[
  {
    "path": ".github/DISCUSSION_TEMPLATE/questions.yml",
    "content": "labels: [question]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for your interest in FastAPI! 🚀\n\n        Please follow these instructions, fill every question, and do every step. 🙏\n\n        I'm asking this because answering questions and solving problems in GitHub is what consumes most of the time.\n\n        I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling questions.\n\n        All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others.\n\n        That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅).\n\n        By asking questions in a structured way (following this) it will be much easier to help you.\n\n        And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎\n\n        As there are too many questions, I'll have to discard and close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓\n  - type: checkboxes\n    id: checks\n    attributes:\n      label: First Check\n      description: Please confirm and check all the following options.\n      options:\n        - label: I added a very descriptive title here.\n          required: true\n        - label: I used the GitHub search to find a similar question and didn't find it.\n          required: true\n        - label: I searched the FastAPI documentation, with the integrated search.\n          required: true\n        - label: I already searched in Google \"How to X in FastAPI\" and didn't find any information.\n          required: true\n        - label: I already read and followed all the tutorial in the docs and didn't find an answer.\n          required: true\n        - label: I already checked if it is not related to FastAPI but to [Pydantic](https://github.com/pydantic/pydantic).\n          required: true\n        - label: I already checked if it is not related to FastAPI but to [Swagger UI](https://github.com/swagger-api/swagger-ui).\n          required: true\n        - label: I already checked if it is not related to FastAPI but to [ReDoc](https://github.com/Redocly/redoc).\n          required: true\n  - type: checkboxes\n    id: help\n    attributes:\n      label: Commit to Help\n      description: |\n        After submitting this, I commit to one of:\n\n          * Read open questions until I find 2 where I can help someone and add a comment to help there.\n          * I already hit the \"watch\" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.\n          * Review one Pull Request by downloading the code and following [all the review process](https://fastapi.tiangolo.com/help-fastapi/#review-pull-requests).\n\n      options:\n        - label: I commit to help with one of those options 👆\n          required: true\n  - type: textarea\n    id: example\n    attributes:\n      label: Example Code\n      description: |\n        Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case.\n\n        If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you.\n\n      placeholder: |\n        from fastapi import FastAPI\n\n        app = FastAPI()\n\n\n        @app.get(\"/\")\n        def read_root():\n            return {\"Hello\": \"World\"}\n      render: python\n    validations:\n      required: true\n  - type: textarea\n    id: description\n    attributes:\n      label: Description\n      description: |\n        What is the problem, question, or error?\n\n        Write a short description telling me what you are doing, what you expect to happen, and what is currently happening.\n      placeholder: |\n        * Open the browser and call the endpoint `/`.\n        * It returns a JSON with `{\"Hello\": \"World\"}`.\n        * But I expected it to return `{\"Hello\": \"Sara\"}`.\n    validations:\n      required: true\n  - type: dropdown\n    id: os\n    attributes:\n      label: Operating System\n      description: What operating system are you on?\n      multiple: true\n      options:\n        - Linux\n        - Windows\n        - macOS\n        - Other\n    validations:\n      required: true\n  - type: textarea\n    id: os-details\n    attributes:\n      label: Operating System Details\n      description: You can add more details about your operating system here, in particular if you chose \"Other\".\n  - type: input\n    id: fastapi-version\n    attributes:\n      label: FastAPI Version\n      description: |\n        What FastAPI version are you using?\n\n        You can find the FastAPI version with:\n\n        ```bash\n        python -c \"import fastapi; print(fastapi.__version__)\"\n        ```\n    validations:\n      required: true\n  - type: input\n    id: pydantic-version\n    attributes:\n      label: Pydantic Version\n      description: |\n        What Pydantic version are you using?\n\n        You can find the Pydantic version with:\n\n        ```bash\n        python -c \"import pydantic; print(pydantic.version.VERSION)\"\n        ```\n    validations:\n      required: true\n  - type: input\n    id: python-version\n    attributes:\n      label: Python Version\n      description: |\n        What Python version are you using?\n\n        You can find the Python version with:\n\n        ```bash\n        python --version\n        ```\n    validations:\n      required: true\n  - type: textarea\n    id: context\n    attributes:\n      label: Additional Context\n      description: Add any additional context information or screenshots you think are useful.\n"
  },
  {
    "path": ".github/DISCUSSION_TEMPLATE/translations.yml",
    "content": "labels: [lang-all]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for your interest in helping translate the FastAPI docs! 🌍\n\n        Please follow these instructions carefully to propose a new language translation. 🙏\n\n        This structured process helps ensure translations can be properly maintained long-term.\n  - type: checkboxes\n    id: checks\n    attributes:\n      label: Initial Checks\n      description: Please confirm and check all the following options.\n      options:\n        - label: I checked that this language is not already being translated in FastAPI docs.\n          required: true\n        - label: I searched existing discussions to ensure no one else proposed this language.\n          required: true\n        - label: I am a native speaker of the language I want to help translate.\n          required: true\n  - type: input\n    id: language\n    attributes:\n      label: Target Language\n      description: What language do you want to translate the FastAPI docs into?\n      placeholder: e.g. Latin\n    validations:\n      required: true\n  - type: textarea\n    id: additional_info\n    attributes:\n      label: Additional Information\n      description: Any other relevant information about your translation proposal\n  - type: markdown\n    attributes:\n      value: |\n        Translations are automatized with AI and then reviewed by native speakers. 🤖 🙋\n\n        This allows us to keep them consistent and up-to-date.\n\n        If there are several native speakers commenting on this discussion and\n        committing to help review new translations, the FastAPI team will review it\n        and potentially make it an official translation. 😎\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: [tiangolo]\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Security Contact\n    about: Please report security vulnerabilities to security@tiangolo.com\n  - name: Question or Problem\n    about: Ask a question or ask about a problem in GitHub Discussions.\n    url: https://github.com/fastapi/fastapi/discussions/categories/questions\n  - name: Feature Request\n    about: To suggest an idea or ask about a feature, please start with a question saying what you would like to achieve. There might be a way to do it already.\n    url: https://github.com/fastapi/fastapi/discussions/categories/questions\n  - name: Show and tell\n    about: Show what you built with FastAPI or to be used with FastAPI.\n    url: https://github.com/fastapi/fastapi/discussions/categories/show-and-tell\n  - name: Translations\n    about: Coordinate translations in GitHub Discussions.\n    url: https://github.com/fastapi/fastapi/discussions/categories/translations\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/privileged.yml",
    "content": "name: Privileged\ndescription: You are @tiangolo or he asked you directly to create an issue here. If not, check the other options. 👇\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for your interest in FastAPI! 🚀\n\n        If you are not @tiangolo or he didn't ask you directly to create an issue here, please start the conversation in a [Question in GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions) instead.\n  - type: checkboxes\n    id: privileged\n    attributes:\n      label: Privileged issue\n      description: Confirm that you are allowed to create an issue here.\n      options:\n        - label: I'm @tiangolo or he asked me directly to create an issue here.\n          required: true\n  - type: textarea\n    id: content\n    attributes:\n      label: Issue Content\n      description: Add the content of the issue here.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  # GitHub Actions\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    cooldown:\n      default-days: 7\n    commit-message:\n      prefix: ⬆\n  # Python\n  - package-ecosystem: \"uv\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    cooldown:\n      default-days: 7\n    commit-message:\n      prefix: ⬆\n  # pre-commit\n  - package-ecosystem: \"pre-commit\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n    cooldown:\n      default-days: 7\n    commit-message:\n      prefix: ⬆\n"
  },
  {
    "path": ".github/labeler.yml",
    "content": "docs:\n  - all:\n    - changed-files:\n      - any-glob-to-any-file:\n        - docs/en/docs/**\n        - docs_src/**\n      - all-globs-to-all-files:\n        - '!fastapi/**'\n        - '!pyproject.toml'\n        - '!docs/en/data/sponsors.yml'\n        - '!docs/en/overrides/main.html'\n\nlang-all:\n  - all:\n    - changed-files:\n      - any-glob-to-any-file:\n        - docs/*/docs/**\n      - all-globs-to-all-files:\n        - '!docs/en/docs/**'\n        - '!docs/*/**/_*.md'\n        - '!fastapi/**'\n        - '!pyproject.toml'\n\ninternal:\n  - all:\n    - changed-files:\n      - any-glob-to-any-file:\n        - .github/**\n        - scripts/**\n        - .gitignore\n        - .pre-commit-config.yaml\n        - uv.lock\n        - docs/en/data/sponsors.yml\n        - docs/en/overrides/main.html\n      - all-globs-to-all-files:\n        - '!docs/*/docs/**'\n        - '!fastapi/**'\n        - '!pyproject.toml'\n"
  },
  {
    "path": ".github/workflows/add-to-project.yml",
    "content": "name: Add to Project\n\non:\n  pull_request_target: # zizmor: ignore[dangerous-triggers]\n  issues:\n    types:\n      - opened\n      - reopened\n\npermissions: {}\n\njobs:\n  add-to-project:\n    name: Add to project\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2.0.0\n        with:\n          project-url: https://github.com/orgs/fastapi/projects/2\n          github-token: ${{ secrets.PROJECTS_TOKEN }} # zizmor: ignore[secrets-outside-env]\n"
  },
  {
    "path": ".github/workflows/build-docs.yml",
    "content": "name: Build Docs\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    types:\n      - opened\n      - synchronize\n\npermissions: {}\n\njobs:\n  changes:\n    runs-on: ubuntu-latest\n    # Required permissions\n    permissions:\n      pull-requests: read\n    # Set job outputs to values from filter step\n    outputs:\n      docs: ${{ steps.filter.outputs.docs }}\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      with:\n        persist-credentials: false\n    # For pull requests it's not necessary to checkout the code but for the main branch it is\n    - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1\n      id: filter\n      with:\n        filters: |\n          docs:\n            - README.md\n            - docs/**\n            - docs_src/**\n            - pyproject.toml\n            - uv.lock\n            - mkdocs.yml\n            - mkdocs.env.yml\n            - .github/workflows/build-docs.yml\n            - .github/workflows/deploy-docs.yml\n            - scripts/mkdocs_hooks.py\n  langs:\n    needs:\n      - changes\n    runs-on: ubuntu-latest\n    outputs:\n      langs: ${{ steps.show-langs.outputs.langs }}\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install docs extras\n        run: uv sync --locked --no-dev --group docs\n      - name: Export Language Codes\n        id: show-langs\n        run: |\n          echo \"langs=$(uv run ./scripts/docs.py langs-json)\" >> $GITHUB_OUTPUT\n\n  build-docs:\n    needs:\n      - changes\n      - langs\n    if: ${{ needs.changes.outputs.docs == 'true' }}\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        lang: ${{ fromJson(needs.langs.outputs.langs) }}\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install docs extras\n        run: uv sync --locked --no-dev --group docs\n      - name: Update Languages\n        run: uv run ./scripts/docs.py update-languages\n      - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5\n        with:\n          key: mkdocs-cards-${{ matrix.lang }}-${{ github.ref }}\n          path: docs/${{ matrix.lang }}/.cache\n      - name: Build Docs\n        run: | # zizmor: ignore[template-injection] - comes from trusted source\n          uv run ./scripts/docs.py build-lang ${{ matrix.lang }}\n      - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n        with:\n          name: docs-site-${{ matrix.lang }}\n          path: ./site/**\n          include-hidden-files: true\n\n  # https://github.com/marketplace/actions/alls-green#why\n  docs-all-green:  # This job does nothing and is only used for the branch protection\n    if: always()\n    needs:\n      - build-docs\n    runs-on: ubuntu-latest\n    steps:\n      - name: Decide whether the needed jobs succeeded or failed\n        uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2\n        with:\n          jobs: ${{ toJSON(needs) }}\n          allowed-skips: build-docs\n"
  },
  {
    "path": ".github/workflows/contributors.yml",
    "content": "name: FastAPI People Contributors\n\non:\n  schedule:\n    - cron: \"0 3 1 * *\"\n  workflow_dispatch:\n    inputs:\n      debug_enabled:\n        description: \"Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)\"\n        required: false\n        default: \"false\"\n\npermissions: {}\n\njobs:\n  job:\n    if: github.repository_owner == 'fastapi'\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: true # Required for `git push` in `contributors.py`\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --locked --no-dev --group github-actions\n      # Allow debugging with tmate\n      - name: Setup tmate session\n        uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23\n        if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}\n        with:\n          limit-access-to-actor: true\n        env:\n          GITHUB_TOKEN: ${{ secrets.FASTAPI_PR_TOKEN }} # zizmor: ignore[secrets-outside-env]\n      - name: FastAPI People Contributors\n        run: uv run ./scripts/contributors.py\n        env:\n          GITHUB_TOKEN: ${{ secrets.FASTAPI_PR_TOKEN }} # zizmor: ignore[secrets-outside-env]\n"
  },
  {
    "path": ".github/workflows/deploy-docs.yml",
    "content": "name: Deploy Docs\non:\n  workflow_run: # zizmor: ignore[dangerous-triggers]\n    workflows:\n      - Build Docs\n    types:\n      - completed\n\npermissions: {}\n\njobs:\n  deploy-docs:\n    runs-on: ubuntu-latest\n    permissions:\n      deployments: write\n      issues: write\n      pull-requests: write\n      statuses: write\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: false\n      - name: Install GitHub Actions dependencies\n        run: uv sync --locked --no-dev --group github-actions\n      - name: Deploy Docs Status Pending\n        run: uv run ./scripts/deploy_docs_status.py\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}\n          RUN_ID: ${{ github.run_id }}\n          STATE: \"pending\"\n      - name: Clean site\n        run: |\n          rm -rf ./site\n          mkdir ./site\n      - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1\n        with:\n          path: ./site/\n          pattern: docs-site-*\n          merge-multiple: true\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          run-id: ${{ github.event.workflow_run.id }}\n      - name: Deploy to Cloudflare Pages\n        # hashFiles returns an empty string if there are no files\n        if: hashFiles('./site/*')\n        id: deploy\n        env:\n          PROJECT_NAME: fastapitiangolo\n          BRANCH: ${{ ( github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'master' && 'main' ) || ( github.event.workflow_run.head_sha ) }}\n        uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3.15.0\n        with:\n          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} # zizmor: ignore[secrets-outside-env]\n          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} # zizmor: ignore[secrets-outside-env]\n          command: pages deploy ./site --project-name=${{ env.PROJECT_NAME }} --branch=${{ env.BRANCH }}\n      - name: Deploy Docs Status Error\n        if: failure()\n        run: uv run ./scripts/deploy_docs_status.py\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}\n          RUN_ID: ${{ github.run_id }}\n          STATE: \"error\"\n      - name: Comment Deploy\n        run: uv run ./scripts/deploy_docs_status.py\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          DEPLOY_URL: ${{ steps.deploy.outputs.deployment-url }}\n          COMMIT_SHA: ${{ github.event.workflow_run.head_sha }}\n          RUN_ID: ${{ github.run_id }}\n          STATE: \"success\"\n"
  },
  {
    "path": ".github/workflows/detect-conflicts.yml",
    "content": "name: \"Conflict detector\"\non:\n  push:\n  pull_request_target: # zizmor: ignore[dangerous-triggers]\n    types: [synchronize]\n\npermissions: {}\n\njobs:\n  main:\n    permissions:\n      contents: read\n      pull-requests: write\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check if PRs have merge conflicts\n        uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 # v3.0.3\n        with:\n          dirtyLabel: \"conflicts\"\n          repoToken: \"${{ secrets.GITHUB_TOKEN }}\"\n          commentOnDirty: \"This pull request has a merge conflict that needs to be resolved.\"\n"
  },
  {
    "path": ".github/workflows/issue-manager.yml",
    "content": "name: Issue Manager\n\non:\n  schedule:\n    - cron: \"13 22 * * *\"\n  issue_comment:\n    types:\n      - created\n  issues:\n    types:\n      - labeled\n  pull_request_target: # zizmor: ignore[dangerous-triggers]\n    types:\n      - labeled\n  workflow_dispatch:\n\npermissions: {}\n\njobs:\n  issue-manager:\n    if: github.repository_owner == 'fastapi'\n    runs-on: ubuntu-latest\n    permissions:\n      issues: write\n      pull-requests: write\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: tiangolo/issue-manager@2fb3484ec9279485df8659e8ec73de262431737d # 0.6.0\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          config: >\n            {\n              \"answered\": {\n                \"delay\": 864000,\n                \"message\": \"Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs.\"\n              },\n              \"waiting\": {\n                \"delay\": 2628000,\n                \"message\": \"As this PR has been waiting for the original user for a while but seems to be inactive, it's now going to be closed. But if there's anyone interested, feel free to create a new PR.\",\n                \"reminder\": {\n                    \"before\": \"P3D\",\n                    \"message\": \"Heads-up: this will be closed in 3 days unless there's new activity.\"\n                }\n              },\n              \"invalid\": {\n                \"delay\": 0,\n                \"message\": \"This was marked as invalid and will be closed now. If this is an error, please provide additional details.\"\n              },\n              \"maybe-ai\": {\n                \"delay\": 0,\n                \"message\": \"This was marked as potentially AI generated and will be closed now. If this is an error, please provide additional details, make sure to read the docs about contributing and AI.\"\n              }\n            }\n"
  },
  {
    "path": ".github/workflows/label-approved.yml",
    "content": "name: Label Approved\n\non:\n  schedule:\n    - cron: \"0 12 * * *\"\n  workflow_dispatch:\n\npermissions: {}\n\njobs:\n  label-approved:\n    if: github.repository_owner == 'fastapi'\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n    - name: Dump GitHub context\n      env:\n        GITHUB_CONTEXT: ${{ toJson(github) }}\n      run: echo \"$GITHUB_CONTEXT\"\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      with:\n        persist-credentials: false\n    - name: Set up Python\n      uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n      with:\n        python-version-file: \".python-version\"\n    - name: Setup uv\n      uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n      with:\n        version: \"0.11.4\"\n        enable-cache: true\n        cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n    - name: Install GitHub Actions dependencies\n      run: uv sync --locked --no-dev --group github-actions\n    - name: Label Approved\n      run: uv run ./scripts/label_approved.py\n      env:\n        TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        CONFIG: >\n          {\n            \"approved-1\":\n              {\n                \"number\": 1,\n                \"await_label\": \"awaiting-review\"\n              }\n          }\n"
  },
  {
    "path": ".github/workflows/labeler.yml",
    "content": "name: Labels\non:\n  pull_request_target: # zizmor: ignore[dangerous-triggers]\n    types:\n      - opened\n      - synchronize\n      - reopened\n      # For label-checker\n      - labeled\n      - unlabeled\n\npermissions: {}\n\njobs:\n  labeler:\n    permissions:\n      contents: read\n      pull-requests: write\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0\n      if: ${{ github.event.action != 'labeled' && github.event.action != 'unlabeled' }}\n    - run: echo \"Done adding labels\"\n  # Run this after labeler applied labels\n  check-labels:\n    needs:\n      - labeler\n    permissions:\n      pull-requests: read\n    runs-on: ubuntu-latest\n    steps:\n      - uses: agilepathway/label-checker@c3d16ad512e7cea5961df85ff2486bb774caf3c5 # v1.6.65\n        with:\n          one_of: breaking,security,feature,bug,refactor,upgrade,docs,lang-all,internal\n          repo_token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/latest-changes.yml",
    "content": "name: Latest Changes\n\non:\n  pull_request_target: # zizmor: ignore[dangerous-triggers]\n    branches:\n      - master\n    types:\n      - closed\n  workflow_dispatch:\n    inputs:\n      number:\n        description: PR number\n        required: true\n      debug_enabled:\n        description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'\n        required: false\n        default: 'false'\n\npermissions: {}\n\njobs:\n  latest-changes:\n    runs-on: ubuntu-latest\n    if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          # To allow latest-changes to commit to the main branch\n          token: ${{ secrets.FASTAPI_LATEST_CHANGES }}  # zizmor: ignore[secrets-outside-env]\n          persist-credentials: true # required by tiangolo/latest-changes\n      # Allow debugging with tmate\n      - name: Setup tmate session\n        uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23\n        if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}\n        with:\n          limit-access-to-actor: true\n      - uses: tiangolo/latest-changes@c9d329cb147f0ddf4fb631214e3f838ff17ccbbd # 0.4.1\n        with:\n          token: ${{ secrets.GITHUB_TOKEN }}\n          latest_changes_file: docs/en/docs/release-notes.md\n          latest_changes_header: '## Latest Changes'\n          end_regex: '^## '\n          debug_logs: true\n          label_header_prefix: '### '\n"
  },
  {
    "path": ".github/workflows/notify-translations.yml",
    "content": "name: Notify Translations\n\non:\n  pull_request_target: # zizmor: ignore[dangerous-triggers]\n    types:\n      - labeled\n      - closed\n    branches:\n      - master\n  workflow_dispatch:\n    inputs:\n      number:\n        description: PR number\n        required: true\n      debug_enabled:\n        description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'\n        required: false\n        default: 'false'\n\npermissions: {}\n\njobs:\n  job:\n    runs-on: ubuntu-latest\n    permissions:\n      discussions: write\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --locked --no-dev --group github-actions\n      # Allow debugging with tmate\n      - name: Setup tmate session\n        uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23\n        if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}\n        with:\n          limit-access-to-actor: true\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      - name: Notify Translations\n        run: uv run ./scripts/notify_translations.py\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          NUMBER: ${{ github.event.inputs.number || null }}\n          DEBUG: ${{ github.event.inputs.debug_enabled || 'false' }}\n"
  },
  {
    "path": ".github/workflows/people.yml",
    "content": "name: FastAPI People\n\non:\n  schedule:\n    - cron: \"0 14 1 * *\"\n  workflow_dispatch:\n    inputs:\n      debug_enabled:\n        description: Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)\n        required: false\n        default: \"false\"\n\npermissions: {}\n\njobs:\n  job:\n    if: github.repository_owner == 'fastapi'\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: true # Required for `git push` in `people.py`\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --locked --no-dev --group github-actions\n      # Allow debugging with tmate\n      - name: Setup tmate session\n        uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23\n        if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}\n        with:\n          limit-access-to-actor: true\n        env:\n          GITHUB_TOKEN: ${{ secrets.FASTAPI_PEOPLE }} # zizmor: ignore[secrets-outside-env]\n      - name: FastAPI People Experts\n        run: uv run ./scripts/people.py\n        env:\n          GITHUB_TOKEN: ${{ secrets.FASTAPI_PEOPLE }} # zizmor: ignore[secrets-outside-env]\n          SLEEP_INTERVAL: ${{ vars.PEOPLE_SLEEP_INTERVAL }}\n"
  },
  {
    "path": ".github/workflows/pre-commit.yml",
    "content": "name: pre-commit\n\non:\n  pull_request:\n    types:\n      - opened\n      - synchronize\n\npermissions: {}\n\nenv:\n  # Forks and Dependabot don't have access to secrets\n  HAS_SECRETS: ${{ secrets.PRE_COMMIT != '' }}\n\njobs:\n  pre-commit:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        name: Checkout PR for own repo\n        if: env.HAS_SECRETS == 'true'\n        with:\n          # To be able to commit it needs to fetch the head of the branch, not the\n          # merge commit\n          ref: ${{ github.head_ref }}\n          # And it needs the full history to be able to compute diffs\n          fetch-depth: 0\n          # A token other than the default GITHUB_TOKEN is needed to be able to trigger CI\n          token: ${{ secrets.PRE_COMMIT }} # zizmor: ignore[secrets-outside-env]\n          persist-credentials: true # Required for `git push` command\n      # pre-commit lite ci needs the default checkout configs to work\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        name: Checkout PR for fork\n        if: env.HAS_SECRETS == 'false'\n        with:\n        # To be able to commit it needs the head branch of the PR, the remote one\n          ref: ${{ github.event.pull_request.head.sha }}\n          fetch-depth: 0\n          persist-credentials: false\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --locked --extra all\n      - name: Run prek - pre-commit\n        id: precommit\n        run: uv run prek run --from-ref origin/${GITHUB_BASE_REF} --to-ref HEAD --show-diff-on-failure\n        continue-on-error: true\n      - name: Commit and push changes\n        if: env.HAS_SECRETS == 'true'\n        run: |\n          git config user.name \"github-actions[bot]\"\n          git config user.email \"github-actions[bot]@users.noreply.github.com\"\n          git add -A\n          if git diff --staged --quiet; then\n            echo \"No changes to commit\"\n          else\n            git commit -m \"🎨 Auto format\"\n            git push\n          fi\n      - uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0\n        if: env.HAS_SECRETS == 'false'\n        with:\n          msg: 🎨 Auto format\n      - name: Error out on pre-commit errors\n        if: steps.precommit.outcome == 'failure'\n        run: exit 1\n\n  # https://github.com/marketplace/actions/alls-green#why\n  pre-commit-alls-green:  # This job does nothing and is only used for the branch protection\n    if: always()\n    needs:\n      - pre-commit\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - name: Decide whether the needed jobs succeeded or failed\n        uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2\n        with:\n          jobs: ${{ toJSON(needs) }}\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish\n\non:\n  release:\n    types:\n      - created\n\npermissions: {}\n\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    permissions:\n      id-token: write\n      contents: read\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Install uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n      - name: Build distribution\n        run: uv build\n      - name: Publish\n        run: uv publish\n"
  },
  {
    "path": ".github/workflows/smokeshow.yml",
    "content": "name: Smokeshow\n\non:\n  workflow_run: # zizmor: ignore[dangerous-triggers]\n    workflows: [Test]\n    types: [completed]\n\npermissions: {}\n\njobs:\n  smokeshow:\n    runs-on: ubuntu-latest\n    permissions:\n      statuses: write\n\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - run: uv sync --locked --no-dev --group github-actions\n      - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1\n        with:\n          name: coverage-html\n          path: htmlcov\n          github-token: ${{ secrets.GITHUB_TOKEN }}\n          run-id: ${{ github.event.workflow_run.id }}\n      # Try 5 times to upload coverage to smokeshow\n      - name: Upload coverage to Smokeshow\n        run: |\n          for i in 1 2 3 4 5; do\n            if uv run smokeshow upload htmlcov; then\n                echo \"Smokeshow upload success!\"\n                break\n            fi\n            echo \"Smokeshow upload error, sleep 1 sec and try again.\"\n            sleep 1\n          done\n        env:\n          SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage}\n          SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 100\n          SMOKESHOW_GITHUB_CONTEXT: coverage\n          SMOKESHOW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          SMOKESHOW_GITHUB_PR_HEAD_SHA: ${{ github.event.workflow_run.head_sha }}\n          SMOKESHOW_AUTH_KEY: ${{ secrets.SMOKESHOW_AUTH_KEY }} # zizmor: ignore[secrets-outside-env]\n"
  },
  {
    "path": ".github/workflows/sponsors.yml",
    "content": "name: FastAPI People Sponsors\n\non:\n  schedule:\n    - cron: \"0 6 1 * *\"\n  workflow_dispatch:\n    inputs:\n      debug_enabled:\n        description: \"Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)\"\n        required: false\n        default: \"false\"\n\npermissions: {}\n\njobs:\n  job:\n    if: github.repository_owner == 'fastapi'\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: true # Required for `git push` in `sponsors.py`\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --locked --no-dev --group github-actions\n      # Allow debugging with tmate\n      - name: Setup tmate session\n        uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23\n        if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}\n        with:\n          limit-access-to-actor: true\n      - name: FastAPI People Sponsors\n        run: uv run ./scripts/sponsors.py\n        env:\n          SPONSORS_TOKEN: ${{ secrets.SPONSORS_TOKEN }} # zizmor: ignore[secrets-outside-env]\n          PR_TOKEN: ${{ secrets.FASTAPI_PR_TOKEN }} # zizmor: ignore[secrets-outside-env]\n"
  },
  {
    "path": ".github/workflows/test-redistribute.yml",
    "content": "name: Test Redistribute\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    types:\n      - opened\n      - synchronize\n\npermissions: {}\n\njobs:\n  test-redistribute:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Install build dependencies\n        run: pip install build\n      - name: Build source distribution\n        run: python -m build --sdist\n      - name: Decompress source distribution\n        run: |\n          cd dist\n          tar xvf fastapi*.tar.gz\n      - name: Install test dependencies\n        run: |\n          cd dist/fastapi*/\n          pip install --group tests --editable .[all]\n      - name: Run source distribution tests\n        run: |\n          cd dist/fastapi*/\n          bash scripts/test.sh\n      - name: Build wheel distribution\n        run: |\n          cd dist\n          pip wheel --no-deps fastapi*.tar.gz\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n\n  # https://github.com/marketplace/actions/alls-green#why\n  test-redistribute-alls-green:  # This job does nothing and is only used for the branch protection\n    if: always()\n    needs:\n      - test-redistribute\n    runs-on: ubuntu-latest\n    steps:\n      - name: Decide whether the needed jobs succeeded or failed\n        uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2\n        with:\n          jobs: ${{ toJSON(needs) }}\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\n\non:\n  push:\n    branches:\n      - master\n  pull_request:\n    types:\n      - opened\n      - synchronize\n  schedule:\n    # cron every week on monday\n    - cron: \"0 0 * * 1\"\n\npermissions: {}\n\nenv:\n  UV_NO_SYNC: true\n  INLINE_SNAPSHOT_DEFAULT_FLAGS: review\n\njobs:\n  changes:\n    runs-on: ubuntu-latest\n    # Required permissions\n    permissions:\n      pull-requests: read\n    # Set job outputs to values from filter step\n    outputs:\n      src: ${{ steps.filter.outputs.src }}\n    steps:\n    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n      with:\n        persist-credentials: false\n    # For pull requests it's not necessary to checkout the code but for the main branch it is\n    - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1\n      id: filter\n      with:\n        filters: |\n          src:\n            - .github/workflows/test.yml\n            - docs_src/**\n            - fastapi/**\n            - scripts/**\n            - tests/**\n            - .python-version\n            - pyproject.toml\n            - uv.lock\n\n  test:\n    needs:\n      - changes\n    if: needs.changes.outputs.src == 'true' || github.ref == 'refs/heads/master'\n    strategy:\n      matrix:\n        os: [ windows-latest, macos-latest ]\n        python-version: [ \"3.14\", \"3.14t\" ]\n        deprecated-tests: [ \"no-deprecation\" ]\n        uv-resolution:\n          - highest\n        starlette-src:\n          - starlette-pypi\n          - starlette-git\n        include:\n          - os: macos-latest\n            python-version: \"3.10\"\n            coverage: coverage\n            uv-resolution: lowest-direct\n            deprecated-tests: \"no-deprecation\"\n          - os: windows-latest\n            python-version: \"3.12\"\n            coverage: coverage\n            uv-resolution: lowest-direct\n            deprecated-tests: \"no-deprecation\"\n          - os: ubuntu-latest\n            python-version: \"3.13\"\n            coverage: coverage\n            uv-resolution: highest\n            deprecated-tests: \"no-deprecation\"\n          - os: ubuntu-latest\n            python-version: \"3.13\"\n            uv-resolution: highest\n            codspeed: codspeed\n            deprecated-tests: \"no-deprecation\"\n          - os: ubuntu-latest\n            python-version: \"3.14\"\n            coverage: coverage\n            uv-resolution: highest\n            starlette-src: starlette-git\n            deprecated-tests: \"test-deprecation\"\n          - os: ubuntu-latest\n            python-version: \"3.14t\"\n            coverage: coverage\n            uv-resolution: highest\n            deprecated-tests: \"no-deprecation\"\n      fail-fast: false\n    runs-on: ${{ matrix.os }}\n    env:\n      UV_PYTHON: ${{ matrix.python-version }}\n      UV_RESOLUTION: ${{ matrix.uv-resolution }}\n      STARLETTE_SRC: ${{ matrix.starlette-src }}\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version: ${{ matrix.python-version }}\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --no-dev --group tests --extra all\n      - name: Ensure that we have the lowest supported Pydantic version\n        if: matrix.uv-resolution == 'lowest-direct'\n        run: uv pip install \"pydantic==2.9.0\"\n      - name: Install Starlette from source\n        if: matrix.starlette-src == 'starlette-git'\n        run: uv pip install \"git+https://github.com/Kludex/starlette@main\"\n      - name: Install deprecated libraries just for testing\n        if: matrix.deprecated-tests == 'test-deprecation'\n        run: uv pip install orjson ujson\n      - name: Reinstall SQLAlchemy without Cython extensions\n        if: matrix.python-version == '3.14t' && matrix.os == 'ubuntu-latest'\n        run: \"DISABLE_SQLALCHEMY_CEXT=1 uv pip install --force-reinstall --no-binary :all: sqlalchemy\"\n      - run: mkdir coverage\n      - name: Test\n        run: uv run --no-sync bash scripts/test-cov.sh\n        env:\n          COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}-${{ matrix.deprecated-tests}}\n          CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}-${{ matrix.deprecated-tests}}\n      # Do not store coverage for all possible combinations to avoid file size max errors in Smokeshow\n      - name: Store coverage files\n        if: matrix.coverage == 'coverage'\n        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n        with:\n          name: coverage-${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.deprecated-tests}}-${{ hashFiles('**/coverage/.coverage.*') }}\n          path: coverage\n          include-hidden-files: true\n\n  benchmark:\n    needs:\n      - changes\n    if: needs.changes.outputs.src == 'true' || github.ref == 'refs/heads/master'\n    runs-on: ubuntu-latest\n    env:\n      UV_PYTHON: \"3.13\"\n      UV_RESOLUTION: highest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version: \"3.13\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --no-dev --group tests --extra all\n      - name: CodSpeed benchmarks\n        uses: CodSpeedHQ/action@658a901452bb54c799643e060733b7afe9121b8d # v4.14.0\n        with:\n          mode: simulation\n          run: uv run --no-sync pytest tests/benchmarks --codspeed\n\n  coverage-combine:\n    needs:\n      - test\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --locked --no-dev --group tests --extra all\n      - name: Get coverage files\n        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1\n        with:\n          pattern: coverage-*\n          path: coverage\n          merge-multiple: true\n      - run: ls -la coverage\n      - run: uv run coverage combine coverage\n      - run: uv run coverage html --title \"Coverage for ${{ github.sha }}\"\n      - name: Store coverage HTML\n        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1\n        with:\n          name: coverage-html\n          path: htmlcov\n          include-hidden-files: true\n      - run: uv run coverage report --fail-under=100\n\n  # https://github.com/marketplace/actions/alls-green#why\n  check:  # This job does nothing and is only used for the branch protection\n    if: always()\n    needs:\n      - coverage-combine\n      - benchmark\n    runs-on: ubuntu-latest\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - name: Decide whether the needed jobs succeeded or failed\n        uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2\n        with:\n          jobs: ${{ toJSON(needs) }}\n          allowed-skips: coverage-combine,test,benchmark\n"
  },
  {
    "path": ".github/workflows/topic-repos.yml",
    "content": "name: Update Topic Repos\n\non:\n  schedule:\n    - cron: \"0 12 1 * *\"\n  workflow_dispatch:\n\npermissions: {}\n\njobs:\n  topic-repos:\n    if: github.repository_owner == 'fastapi'\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: true # Required for `git push` in `topic_repos.py`\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          enable-cache: true\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install GitHub Actions dependencies\n        run: uv sync --locked --no-dev --group github-actions\n      - name: Update Topic Repos\n        run: uv run ./scripts/topic_repos.py\n        env:\n          GITHUB_TOKEN: ${{ secrets.FASTAPI_PR_TOKEN }} # zizmor: ignore[secrets-outside-env]\n"
  },
  {
    "path": ".github/workflows/translate.yml",
    "content": "name: Translate\n\non:\n  schedule:\n    - cron: \"0 5 1,15 * *\"  # Run at 05:00 on the 1st and 15th of every month\n\n  workflow_dispatch:\n    inputs:\n      debug_enabled:\n        description: Run with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)\n        required: false\n        default: \"false\"\n      command:\n        description: Command to run\n        type: choice\n        options:\n          - translate-page\n          - translate-lang\n          - update-outdated\n          - add-missing\n          - update-and-add\n          - remove-removable\n      language:\n        description: Language to translate to as a letter code (e.g. \"es\" for Spanish)\n        type: string\n        required: false\n        default: \"\"\n      en_path:\n        description: File path in English to translate (e.g. docs/en/docs/index.md)\n        type: string\n        required: false\n        default: \"\"\n      commit_in_place:\n        description: Commit changes directly instead of making a PR\n        type: boolean\n        required: false\n        default: false\n      max:\n        description: Maximum number of items to translate (e.g. 10)\n        type: number\n        required: false\n        default: 10\n\npermissions: {}\n\njobs:\n  langs:\n    runs-on: ubuntu-latest\n    outputs:\n      langs: ${{ steps.show-langs.outputs.langs }}\n      commands: ${{ steps.show-langs.outputs.commands }}\n    steps:\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --locked --no-dev --group github-actions --group translations\n      - name: Export Language Codes\n        id: show-langs\n        run: |\n          echo \"langs=$(uv run ./scripts/translate.py llm-translatable-json)\" >> $GITHUB_OUTPUT\n          echo \"commands=$(uv run ./scripts/translate.py commands-json)\" >> $GITHUB_OUTPUT\n        env:\n          LANGUAGE: ${{ github.event.inputs.language }}\n          COMMAND: ${{ github.event.inputs.command }}\n\n  translate:\n    if: github.repository_owner == 'fastapi'\n    needs: langs\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    strategy:\n      matrix:\n        lang: ${{ fromJson(needs.langs.outputs.langs) }}\n        command: ${{ fromJson(needs.langs.outputs.commands) }}\n    steps:\n      - name: Dump GitHub context\n        env:\n          GITHUB_CONTEXT: ${{ toJson(github) }}\n        run: echo \"$GITHUB_CONTEXT\"\n      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          fetch-depth: 0\n          persist-credentials: true # Required for `git push` in `translate.py`\n      - name: Set up Python\n        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0\n        with:\n          python-version-file: \".python-version\"\n      - name: Setup uv\n        uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0\n        with:\n          version: \"0.11.4\"\n          cache-dependency-glob: |\n            pyproject.toml\n            uv.lock\n      - name: Install Dependencies\n        run: uv sync --locked --no-dev --group github-actions --group translations\n      # Allow debugging with tmate\n      - name: Setup tmate session\n        uses: mxschmitt/action-tmate@c0afd6f790e3a5564914980036ebf83216678101 # v3.23\n        if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }}\n        with:\n          limit-access-to-actor: true\n        env:\n          GITHUB_TOKEN: ${{ secrets.FASTAPI_TRANSLATIONS }} # zizmor: ignore[secrets-outside-env]\n          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} # zizmor: ignore[secrets-outside-env]\n      - name: FastAPI Translate\n        run: |\n          uv run ./scripts/translate.py \"$COMMAND\"\n          uv run ./scripts/translate.py make-pr\n        env:\n          GITHUB_TOKEN: ${{ secrets.FASTAPI_TRANSLATIONS }} # zizmor: ignore[secrets-outside-env]\n          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} # zizmor: ignore[secrets-outside-env]\n          LANGUAGE: ${{ matrix.lang }}\n          EN_PATH: ${{ github.event.inputs.en_path }}\n          COMMAND: ${{ matrix.command }}\n          COMMIT_IN_PLACE: ${{ github.event.inputs.commit_in_place == 'true' && 'true' || '' }}\n          MAX: ${{ github.event.inputs.max }}\n"
  },
  {
    "path": ".gitignore",
    "content": ".idea\n.ipynb_checkpoints\n.mypy_cache\n.vscode\n__pycache__\n.pytest_cache\nhtmlcov\ndist\nsite\n.coverage*\ncoverage.xml\n.netlify\ntest.db\nlog.txt\nPipfile.lock\nenv3.*\nenv\ndocs_build\nsite_build\nvenv\ndocs.zip\narchive.zip\n\n# vim temporary files\n*~\n.*.sw?\n.cache\n\n# macOS\n.DS_Store\n\n.codspeed\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "# See https://pre-commit.com for more information\n# See https://pre-commit.com/hooks.html for more hooks\nrepos:\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # v6.0.0\n    hooks:\n      - id: check-added-large-files\n        args: ['--maxkb=750']\n        exclude: ^uv.lock$\n      - id: check-toml\n      - id: check-yaml\n        args:\n        - --unsafe\n      - id: end-of-file-fixer\n      - id: trailing-whitespace\n\n  - repo: https://github.com/crate-ci/typos\n    rev: bbaefadf97b0ec5fdc942684b647f1a6ab250274 # v1.46.0\n    hooks:\n      - id: typos\n        args: [--force-exclude]\n\n  - repo: local\n    hooks:\n      - id: local-ruff-check\n        name: ruff check\n        entry: uv run ruff check --force-exclude --fix --exit-non-zero-on-fix\n        require_serial: true\n        language: unsupported\n        types: [python]\n\n      - id: local-ruff-format\n        name: ruff format\n        entry: uv run ruff format --force-exclude --exit-non-zero-on-format\n        require_serial: true\n        language: unsupported\n        types: [python]\n\n      - id: local-mypy\n        name: mypy check\n        entry: uv run mypy fastapi\n        require_serial: true\n        language: unsupported\n        pass_filenames: false\n\n      - id: local-ty\n        name: ty check\n        entry: uv run ty check fastapi\n        require_serial: true\n        language: unsupported\n        pass_filenames: false\n\n      - id: add-permalinks-pages\n        language: unsupported\n        name: add-permalinks-pages\n        entry: uv run ./scripts/docs.py add-permalinks-pages\n        args:\n          - --update-existing\n        files: ^docs/en/docs/.*\\.md$\n\n      - id: generate-readme\n        language: unsupported\n        name: generate README.md from index.md\n        entry: uv run ./scripts/docs.py generate-readme\n        files: ^docs/en/docs/index\\.md|docs/en/data/sponsors\\.yml|scripts/docs\\.py$\n        pass_filenames: false\n\n      - id: update-languages\n        language: unsupported\n        name: update languages\n        entry: uv run ./scripts/docs.py update-languages\n        files: ^docs/.*|scripts/docs\\.py$\n        pass_filenames: false\n\n      - id: ensure-non-translated\n        language: unsupported\n        name: ensure non-translated files are not modified\n        entry: uv run ./scripts/docs.py ensure-non-translated\n        files: ^docs/(?!en/).*|^scripts/docs\\.py$\n        pass_filenames: false\n\n      - id: fix-translations\n        language: unsupported\n        name: fix translations\n        entry: uv run ./scripts/translation_fixer.py fix-pages\n        files: ^docs/(?!en/).*/docs/.*\\.md$\n\n      - id: add-release-date\n        language: unsupported\n        name: add date to latest release header\n        entry: uv run python scripts/add_latest_release_date.py\n        files: ^docs/en/docs/release-notes\\.md$\n        pass_filenames: false\n\n      - id: zizmor\n        name: zizmor\n        language: python\n        entry: uv run zizmor .\n        files: ^\\.github\\/workflows\\/\n        require_serial: true\n        pass_filenames: false\n"
  },
  {
    "path": ".python-version",
    "content": "3.11\n"
  },
  {
    "path": "CITATION.cff",
    "content": "# This CITATION.cff file was generated with cffinit.\n# Visit https://bit.ly/cffinit to generate yours today!\n\ncff-version: 1.2.0\ntitle: FastAPI\nmessage: >-\n  If you use this software, please cite it using the\n  metadata from this file.\ntype: software\nauthors:\n  - given-names: Sebastián\n    family-names: Ramírez\n    email: tiangolo@gmail.com\nidentifiers:\nrepository-code: 'https://github.com/fastapi/fastapi'\nurl: 'https://fastapi.tiangolo.com'\nabstract: >-\n  FastAPI framework, high performance, easy to learn, fast to code,\n  ready for production\nkeywords:\n  - fastapi\n  - pydantic\n  - starlette\nlicense: MIT\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Please read the [Development - Contributing](https://fastapi.tiangolo.com/contributing/) guidelines in the documentation site.\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018 Sebastián Ramírez\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**Documentation**: [https://fastapi.tiangolo.com](https://fastapi.tiangolo.com)\n\n**Source Code**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints.\n\nThe key features are:\n\n* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).\n* **Fast to code**: Increase the speed to develop features by about 200% to 300%. *\n* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *\n* **Intuitive**: Great editor support. <dfn title=\"also known as auto-complete, autocompletion, IntelliSense\">Completion</dfn> everywhere. Less time debugging.\n* **Easy**: Designed to be easy to use and learn. Less time reading docs.\n* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.\n* **Robust**: Get production-ready code. With automatic interactive documentation.\n* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (previously known as Swagger) and [JSON Schema](https://json-schema.org/).\n\n<small>* estimation based on tests conducted by an internal development team, building production applications.</small>\n\n## Sponsors\n\n<!-- sponsors -->\n### Keystone Sponsor\n\n<a href=\"https://fastapicloud.com\" target=\"_blank\" title=\"FastAPI Cloud. By the same team behind FastAPI. You code. We Cloud.\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/fastapicloud.png\"></a>\n\n### Gold Sponsors\n\n<a href=\"https://blockbee.io?ref=fastapi\" target=\"_blank\" title=\"BlockBee Cryptocurrency Payment Gateway\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/blockbee.png\"></a>\n<a href=\"https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=main-badge\" target=\"_blank\" title=\"Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/scalar.svg\"></a>\n<a href=\"https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=mainbadge\" target=\"_blank\" title=\"Auth, user management and more for your B2B product\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/propelauth.png\"></a>\n<a href=\"https://liblab.com?utm_source=fastapi\" target=\"_blank\" title=\"liblab - Generate SDKs from FastAPI\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/liblab.png\"></a>\n<a href=\"https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi\" target=\"_blank\" title=\"Deploy & scale any full-stack web app on Render. Focus on building apps, not infra.\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/render.svg\"></a>\n<a href=\"https://www.coderabbit.ai/?utm_source=fastapi&utm_medium=badge&utm_campaign=fastapi\" target=\"_blank\" title=\"Cut Code Review Time & Bugs in Half with CodeRabbit\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/coderabbit.png\"></a>\n<a href=\"https://subtotal.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=open-source\" target=\"_blank\" title=\"The Gold Standard in Retail Account Linking\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/subtotal.svg\"></a>\n<a href=\"https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi\" target=\"_blank\" title=\"Deploy enterprise applications at startup speed\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/railway.png\"></a>\n<a href=\"https://serpapi.com/?utm_source=fastapi_website\" target=\"_blank\" title=\"SerpApi: Web Search API\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/serpapi.png\"></a>\n<a href=\"https://www.greptile.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=fastapi_sponsor_page\" target=\"_blank\" title=\"Greptile: The AI Code Reviewer\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/greptile.png\"></a>\n\n### Silver Sponsors\n\n<a href=\"https://databento.com/?utm_source=fastapi&utm_medium=sponsor&utm_content=display\" target=\"_blank\" title=\"Pay as you go for market data\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/databento.svg\"></a>\n<a href=\"https://www.svix.com/\" target=\"_blank\" title=\"Svix - Webhooks as a service\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/svix.svg\"></a>\n<a href=\"https://www.stainlessapi.com/?utm_source=fastapi&utm_medium=referral\" target=\"_blank\" title=\"Stainless | Generate best-in-class SDKs\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/stainless.png\"></a>\n<a href=\"https://www.permit.io/blog/implement-authorization-in-fastapi?utm_source=github&utm_medium=referral&utm_campaign=fastapi\" target=\"_blank\" title=\"Fine-Grained Authorization for FastAPI\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/permit.png\"></a>\n<a href=\"https://www.interviewpal.com/?utm_source=fastapi&utm_medium=open-source&utm_campaign=dev-hiring\" target=\"_blank\" title=\"InterviewPal - AI Interview Coach for Engineers and Devs\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/interviewpal.png\"></a>\n<a href=\"https://dribia.com/en/\" target=\"_blank\" title=\"Dribia - Data Science within your reach\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/dribia.png\"></a>\n<a href=\"https://talordata.com/?campaignid=oh5dVZ3Zc3YGiAI2&utm_source=fastapi&utm_term=fastapi\" target=\"_blank\" title=\"TalorData SERP API - Multi-Engine Search Results Data\"><img src=\"https://fastapi.tiangolo.com/img/sponsors/talordata.png\"></a>\n\n<!-- /sponsors -->\n\n[Other sponsors](https://fastapi.tiangolo.com/fastapi-people/#sponsors)\n\n## Opinions\n\n\n\n<div class=\"only-github\" markdown=\"1\">\n\n\"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n\"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n\"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n\"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our Virtual TAC Engineer._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n</div>\n\n## FastAPI Conf\n\n[**FastAPI Conf '26**](https://fastapiconf.com) is happening on **October 28, 2026** in **Amsterdam, NL**. All about FastAPI, right from the source. 🎤\n\n<a class=\"fastapi-feature-banner\" href=\"https://fastapiconf.com\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-conf.jpeg\" alt=\"FastAPI Conf '26 - October 28, 2026 - Amsterdam, NL\"></a>\n\n## FastAPI mini documentary\n\nThere's a [FastAPI mini documentary](https://www.youtube.com/watch?v=mpR8ngthqiE) released at the end of 2025, you can watch it online:\n\n<a class=\"fastapi-feature-banner\" href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**, the FastAPI of CLIs\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\nIf you are building a <abbr title=\"Command Line Interface\">CLI</abbr> app to be used in the terminal instead of a web API, check out [**Typer**](https://typer.tiangolo.com/).\n\n**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀\n\n## Requirements\n\nFastAPI stands on the shoulders of giants:\n\n* [Starlette](https://www.starlette.dev/) for the web parts.\n* [Pydantic](https://docs.pydantic.dev/) for the data parts.\n\n## Installation\n\nCreate and activate a [virtual environment](https://fastapi.tiangolo.com/virtual-environments/) and then install FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Note**: Make sure you put `\"fastapi[standard]\"` in quotes to ensure it works in all terminals.\n\n## Example\n\n### Create it\n\nCreate a file `main.py` with:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>Or use <code>async def</code>...</summary>\n\nIf your code uses `async` / `await`, use `async def`:\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Note**:\n\nIf you don't know, check the _\"In a hurry?\"_ section about [`async` and `await` in the docs](https://fastapi.tiangolo.com/async/#in-a-hurry).\n\n</details>\n\n### Run it\n\nRun the server with:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary>About the command <code>fastapi dev</code>...</summary>\n\nThe command `fastapi dev` reads your `main.py` file automatically, detects the **FastAPI** app in it, and starts a server using [Uvicorn](https://www.uvicorn.dev).\n\nBy default, `fastapi dev` will start with auto-reload enabled for local development.\n\nYou can read more about it in the [FastAPI CLI docs](https://fastapi.tiangolo.com/fastapi-cli/).\n\n</details>\n\n### Check it\n\nOpen your browser at [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery).\n\nYou will see the JSON response as:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\nYou already created an API that:\n\n* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`.\n* Both _paths_ take `GET` <em>operations</em> (also known as HTTP _methods_).\n* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.\n* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.\n\n### Interactive API docs\n\nNow go to [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nYou will see the automatic interactive API documentation (provided by [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Alternative API docs\n\nAnd now, go to [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nYou will see the alternative automatic documentation (provided by [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Example upgrade\n\nNow modify the file `main.py` to receive a body from a `PUT` request.\n\nDeclare the body using standard Python types, thanks to Pydantic.\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\nThe `fastapi dev` server should reload automatically.\n\n### Interactive API docs upgrade\n\nNow go to [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n* The interactive API documentation will be automatically updated, including the new body:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Click on the button \"Try it out\", it allows you to fill the parameters and directly interact with the API:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* Then click on the \"Execute\" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### Alternative API docs upgrade\n\nAnd now, go to [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\n* The alternative documentation will also reflect the new query parameter and body:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Recap\n\nIn summary, you declare **once** the types of parameters, body, etc. as function parameters.\n\nYou do that with standard modern Python types.\n\nYou don't have to learn a new syntax, the methods or classes of a specific library, etc.\n\nJust standard **Python**.\n\nFor example, for an `int`:\n\n```Python\nitem_id: int\n```\n\nor for a more complex `Item` model:\n\n```Python\nitem: Item\n```\n\n...and with that single declaration you get:\n\n* Editor support, including:\n    * Completion.\n    * Type checks.\n* Validation of data:\n    * Automatic and clear errors when the data is invalid.\n    * Validation even for deeply nested JSON objects.\n* <dfn title=\"also known as: serialization, parsing, marshalling\">Conversion</dfn> of input data: coming from the network to Python data and types. Reading from:\n    * JSON.\n    * Path parameters.\n    * Query parameters.\n    * Cookies.\n    * Headers.\n    * Forms.\n    * Files.\n* <dfn title=\"also known as: serialization, parsing, marshalling\">Conversion</dfn> of output data: converting from Python data and types to network data (as JSON):\n    * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).\n    * `datetime` objects.\n    * `UUID` objects.\n    * Database models.\n    * ...and many more.\n* Automatic interactive API documentation, including 2 alternative user interfaces:\n    * Swagger UI.\n    * ReDoc.\n\n---\n\nComing back to the previous code example, **FastAPI** will:\n\n* Validate that there is an `item_id` in the path for `GET` and `PUT` requests.\n* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests.\n    * If it is not, the client will see a useful, clear error.\n* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.\n    * As the `q` parameter is declared with `= None`, it is optional.\n    * Without the `None` it would be required (as is the body in the case with `PUT`).\n* For `PUT` requests to `/items/{item_id}`, read the body as JSON:\n    * Check that it has a required attribute `name` that should be a `str`.\n    * Check that it has a required attribute `price` that has to be a `float`.\n    * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.\n    * All this would also work for deeply nested JSON objects.\n* Convert from and to JSON automatically.\n* Document everything with OpenAPI, that can be used by:\n    * Interactive documentation systems.\n    * Automatic client code generation systems, for many languages.\n* Provide 2 interactive documentation web interfaces directly.\n\n---\n\nWe just scratched the surface, but you already get the idea of how it all works.\n\nTry changing the line with:\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n...from:\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n...to:\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n...and see how your editor will auto-complete the attributes and know their types:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\nFor a more complete example including more features, see the <a href=\"https://fastapi.tiangolo.com/tutorial/\">Tutorial - User Guide</a>.\n\n**Spoiler alert**: the tutorial - user guide includes:\n\n* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.\n* How to set **validation constraints** as `maximum_length` or `regex`.\n* A very powerful and easy to use **<dfn title=\"also known as components, resources, providers, services, injectables\">Dependency Injection</dfn>** system.\n* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.\n* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).\n* **GraphQL** integration with [Strawberry](https://strawberry.rocks) and other libraries.\n* Many extra features (thanks to Starlette) as:\n    * **WebSockets**\n    * extremely easy tests based on HTTPX and `pytest`\n    * **CORS**\n    * **Cookie Sessions**\n    * ...and more.\n\n### Deploy your app (optional)\n\nYou can optionally deploy your FastAPI app to [FastAPI Cloud](https://fastapicloud.com), go and join the waiting list if you haven't. 🚀\n\nIf you already have a **FastAPI Cloud** account (we invited you from the waiting list 😉), you can deploy your application with one command.\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nThat's it! Now you can access your app at that URL. ✨\n\n#### About FastAPI Cloud\n\n**[FastAPI Cloud](https://fastapicloud.com)** is built by the same author and team behind **FastAPI**.\n\nIt streamlines the process of **building**, **deploying**, and **accessing** an API with minimal effort.\n\nIt brings the same **developer experience** of building apps with FastAPI to **deploying** them to the cloud. 🎉\n\nFastAPI Cloud is the primary sponsor and funding provider for the *FastAPI and friends* open source projects. ✨\n\n#### Deploy to other cloud providers\n\nFastAPI is open source and based on standards. You can deploy FastAPI apps to any cloud provider you choose.\n\nFollow your cloud provider's guides to deploy FastAPI apps with them. 🤓\n\n## Performance\n\nIndependent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as [one of the fastest Python frameworks available](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)\n\nTo understand more about it, see the section [Benchmarks](https://fastapi.tiangolo.com/benchmarks/).\n\n## Dependencies\n\nFastAPI depends on Pydantic and Starlette.\n\n### `standard` Dependencies\n\nWhen you install FastAPI with `pip install \"fastapi[standard]\"` it comes with the `standard` group of optional dependencies:\n\nUsed by Pydantic:\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - for email validation.\n\nUsed by Starlette:\n\n* [`httpx`](https://www.python-httpx.org) - Required if you want to use the `TestClient`.\n* [`jinja2`](https://jinja.palletsprojects.com) - Required if you want to use the default template configuration.\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - Required if you want to support form <dfn title=\"converting the string that comes from an HTTP request into Python data\">\"parsing\"</dfn>, with `request.form()`.\n\nUsed by FastAPI:\n\n* [`uvicorn`](https://www.uvicorn.dev) - for the server that loads and serves your application. This includes `uvicorn[standard]`, which includes some dependencies (e.g. `uvloop`) needed for high performance serving.\n* `fastapi-cli[standard]` - to provide the `fastapi` command.\n    * This includes `fastapi-cloud-cli`, which allows you to deploy your FastAPI application to [FastAPI Cloud](https://fastapicloud.com).\n\n### Without `standard` Dependencies\n\nIf you don't want to include the `standard` optional dependencies, you can install with `pip install fastapi` instead of `pip install \"fastapi[standard]\"`.\n\n### Without `fastapi-cloud-cli`\n\nIf you want to install FastAPI with the standard dependencies but without the `fastapi-cloud-cli`, you can install with `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n### Additional Optional Dependencies\n\nThere are some additional dependencies you might want to install.\n\nAdditional optional Pydantic dependencies:\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - for settings management.\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - for extra types to be used with Pydantic.\n\nAdditional optional FastAPI dependencies:\n\n* [`orjson`](https://github.com/ijl/orjson) - Required if you want to use `ORJSONResponse`.\n* [`ujson`](https://github.com/esnme/ultrajson) - Required if you want to use `UJSONResponse`.\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nSecurity is very important for FastAPI and its community. 🔒\n\nLearn more about it below. 👇\n\n## Versions\n\nThe latest version of FastAPI is supported.\n\nYou are encouraged to [write tests](https://fastapi.tiangolo.com/tutorial/testing/) for your application and update your FastAPI version frequently after ensuring that your tests are passing. This way you will benefit from the latest features, bug fixes, and **security fixes**.\n\nYou can learn more about [FastAPI versions and how to pin and upgrade them](https://fastapi.tiangolo.com/deployment/versions/) for your project in the docs.\n\n## Reporting a Vulnerability\n\nIf you think you found a vulnerability, and even if you are not sure about it, please report it right away by sending an email to: security@tiangolo.com. Please try to be as explicit as possible, describing all the steps and example code to reproduce the security issue.\n\nI (the author, [@tiangolo](https://x.com/tiangolo)) will review it thoroughly and get back to you.\n\n## Public Discussions\n\nPlease restrain from publicly discussing a potential security vulnerability. 🙊\n\nIt's better to discuss privately and try to find a solution first, to limit the potential impact as much as possible.\n\n---\n\nThanks for your help!\n\nThe FastAPI community and I thank you for that. 🙇\n"
  },
  {
    "path": "docs/de/docs/_llm-test.md",
    "content": "# LLM-Testdatei { #llm-test-file }\n\nDieses Dokument testet, ob das <abbr title=\"Large Language Model – Großes Sprachmodell\">LLM</abbr>, das die Dokumentation übersetzt, den <abbr title=\"General Prompt – Allgemeiner Prompt\">`general_prompt`</abbr> in `scripts/translate.py` und den sprachspezifischen Prompt in `docs/{language code}/llm-prompt.md` versteht. Der sprachsspezifische Prompt wird an `general_prompt` angehängt.\n\nHier hinzugefügte Tests werden von allen Erstellern sprachsspezifischer Prompts gesehen.\n\nSo verwenden:\n\n* Einen sprachsspezifischen Prompt haben – `docs/{language code}/llm-prompt.md`.\n* Eine frische Übersetzung dieses Dokuments in die gewünschte Zielsprache durchführen (siehe z. B. das Kommando `translate-page` der `translate.py`). Dadurch wird die Übersetzung unter `docs/{language code}/docs/_llm-test.md` erstellt.\n* Prüfen Sie, ob in der Übersetzung alles in Ordnung ist.\n* Verbessern Sie bei Bedarf Ihren sprachsspezifischen Prompt, den allgemeinen Prompt oder das englische Dokument.\n* Beheben Sie anschließend manuell die verbleibenden Probleme in der Übersetzung, sodass es eine gute Übersetzung ist.\n* Übersetzen Sie erneut, nachdem die gute Übersetzung vorliegt. Das ideale Ergebnis wäre, dass das LLM an der Übersetzung keine Änderungen mehr vornimmt. Das bedeutet, dass der allgemeine Prompt und Ihr sprachsspezifischer Prompt so gut sind, wie sie sein können (Es wird manchmal ein paar scheinbar zufällige Änderungen machen, der Grund ist, dass [LLMs keine deterministischen Algorithmen sind](https://doublespeak.chat/#/handbook#deterministic-output)).\n\nDie Tests:\n\n## Codeschnipsel { #code-snippets }\n\n//// tab | Test\n\nDies ist ein Codeschnipsel: `foo`. Und dies ist ein weiteres Codeschnipsel: `bar`. Und noch eins: `baz quux`.\n\n////\n\n//// tab | Info\n\nDer Inhalt von Codeschnipseln sollte unverändert bleiben.\n\nSiehe Abschnitt `### Content of code snippets` im allgemeinen Prompt in `scripts/translate.py`.\n\n////\n\n## Anführungszeichen { #quotes }\n\n//// tab | Test\n\nGestern schrieb mein Freund: „Wenn man ‚incorrectly‘ korrekt schreibt, hat man es falsch geschrieben“. Worauf ich antwortete: „Korrekt, aber ‚incorrectly‘ ist inkorrekterweise nicht ‚„incorrectly“‘“.\n\n/// note | Hinweis\n\nDas LLM wird dies wahrscheinlich falsch übersetzen. Interessant ist nur, ob es die korrigierte Übersetzung bei einer erneuten Übersetzung beibehält.\n\n///\n\n////\n\n//// tab | Info\n\nDer Promptdesigner kann entscheiden, ob neutrale Anführungszeichen in typografische Anführungszeichen umgewandelt werden sollen. Es ist in Ordnung, sie unverändert zu lassen.\n\nSiehe zum Beispiel den Abschnitt `### Quotes` in `docs/de/llm-prompt.md`.\n\n////\n\n## Anführungszeichen in Codeschnipseln { #quotes-in-code-snippets }\n\n//// tab | Test\n\n`pip install \"foo[bar]\"`\n\nBeispiele für Stringliterale in Codeschnipseln: `\"this\"`, `'that'`.\n\nEin schwieriges Beispiel für Stringliterale in Codeschnipseln: `f\"I like {'oranges' if orange else \"apples\"}\"`\n\nHardcore: `Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | Info\n\n... Allerdings müssen Anführungszeichen in Codeschnipseln unverändert bleiben.\n\n////\n\n## Codeblöcke { #code-blocks }\n\n//// tab | Test\n\nEin Bash-Codebeispiel ...\n\n```bash\n# Eine Begrüßung an das Universum ausgeben\necho \"Hello universe\"\n```\n\n... und ein Konsolen-Codebeispiel ...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n... und noch ein Konsolen-Codebeispiel ...\n\n```console\n// Create a directory \"Code\"\n$ mkdir code\n// In dieses Verzeichnis wechseln\n$ cd code\n```\n\n... und ein Python-Codebeispiel ...\n\n```Python\nwont_work()  # Das wird nicht funktionieren 😱\nworks(foo=\"bar\")  # Das funktioniert 🎉\n```\n\n... und das war's.\n\n////\n\n//// tab | Info\n\nCode in Codeblöcken sollte nicht verändert werden, mit Ausnahme von Kommentaren.\n\nSiehe Abschnitt `### Content of code blocks` im allgemeinen Prompt in `scripts/translate.py`.\n\n////\n\n## Tabs und farbige Boxen { #tabs-and-colored-boxes }\n\n//// tab | Test\n\n/// info | Info\nEtwas Text\n///\n\n/// note | Hinweis\nEtwas Text\n///\n\n/// note | Technische Details\nEtwas Text\n///\n\n/// check | Testen\nEtwas Text\n///\n\n/// tip | Tipp\nEtwas Text\n///\n\n/// warning | Achtung\nEtwas Text\n///\n\n/// danger | Gefahr\nEtwas Text\n///\n\n////\n\n//// tab | Info\n\nTabs und `Info`/`Note`/`Warning`/usw. Blöcke sollten die Übersetzung ihres Titels nach einem vertikalen Strich (`|`) erhalten.\n\nSiehe die Abschnitte `### Special blocks` und `### Tab blocks` im allgemeinen Prompt in `scripts/translate.py`.\n\n////\n\n## Web- und interne Links { #web-and-internal-links }\n\n//// tab | Test\n\nDer Linktext sollte übersetzt werden, die Linkadresse sollte unverändert bleiben:\n\n* [Link zur Überschrift oben](#code-snippets)\n* [Interner Link](index.md#installation)\n* [Externer Link](https://sqlmodel.tiangolo.com/)\n* [Link zu einem Stil](https://fastapi.tiangolo.com/css/styles.css)\n* [Link zu einem Skript](https://fastapi.tiangolo.com/js/logic.js)\n* [Link zu einem Bild](https://fastapi.tiangolo.com/img/foo.jpg)\n\nDer Linktext sollte übersetzt werden, die Linkadresse sollte auf die Übersetzung zeigen:\n\n* [FastAPI-Link](https://fastapi.tiangolo.com/de/)\n\n////\n\n//// tab | Info\n\nLinks sollten übersetzt werden, aber ihre Adresse soll unverändert bleiben. Eine Ausnahme sind absolute Links zu Seiten der FastAPI-Dokumentation. In diesem Fall sollte auf die Übersetzung verlinkt werden.\n\nSiehe Abschnitt `### Links` im allgemeinen Prompt in `scripts/translate.py`.\n\n////\n\n## HTML-„abbr“-Elemente { #html-abbr-elements }\n\n//// tab | Test\n\nHier einige Dinge, die in HTML-„abbr“-Elemente gepackt sind (einige sind erfunden):\n\n### Das abbr gibt eine vollständige Phrase { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done – Dinge erledigt bekommen\">GTD</abbr>\n* <abbr title=\"less than – kleiner als\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token\">XWT</abbr>\n* <abbr title=\"Paralleles Server-Gateway-Interface\">PSGI</abbr>\n\n### Das abbr gibt eine vollständige Phrase und eine Erklärung { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network – Mozilla-Entwicklernetzwerk: Dokumentation für Entwickler, geschrieben von den Firefox-Leuten\">MDN</abbr>\n* <abbr title=\"Input/Output – Eingabe/Ausgabe: Lesen oder Schreiben auf der Festplatte, Netzwerkkommunikation.\">I/O</abbr>.\n\n////\n\n//// tab | Info\n\n„title“-Attribute von „abbr“-Elementen werden nach bestimmten Anweisungen übersetzt.\n\nÜbersetzungen können eigene „abbr“-Elemente hinzufügen, die das LLM nicht entfernen soll. Z. B. um englische Wörter zu erklären.\n\nSiehe Abschnitt `### HTML abbr elements` im allgemeinen Prompt in `scripts/translate.py`.\n\n////\n\n## HTML „dfn“-Elemente { #html-dfn-elements }\n\n* <dfn title=\"Eine Gruppe von Maschinen, die so konfiguriert sind, dass sie verbunden sind und in irgendeiner Weise zusammenarbeiten.\">Cluster</dfn>\n* <dfn title=\"Eine Methode des Machine Learning, die künstliche neuronale Netze mit zahlreichen versteckten Schichten zwischen Eingabe- und Ausgabeschicht verwendet und so eine umfassende interne Struktur entwickelt\">Deep Learning</dfn>\n\n## Überschriften { #headings }\n\n//// tab | Test\n\n### Eine Webapp entwickeln – ein Tutorial { #develop-a-webapp-a-tutorial }\n\nHallo.\n\n### Typhinweise und -annotationen { #type-hints-and-annotations }\n\nHallo wieder.\n\n### Super- und Subklassen { #super-and-subclasses }\n\nHallo wieder.\n\n////\n\n//// tab | Info\n\nDie einzige strenge Regel für Überschriften ist, dass das LLM den Hash-Teil in geschweiften Klammern unverändert lässt, damit Links nicht kaputtgehen.\n\nSiehe Abschnitt `### Headings` im allgemeinen Prompt in `scripts/translate.py`.\n\nFür einige sprachsspezifische Anweisungen, siehe z. B. den Abschnitt `### Headings` in `docs/de/llm-prompt.md`.\n\n////\n\n## In der Dokumentation verwendete Begriffe { #terms-used-in-the-docs }\n\n//// tab | Test\n\n* Sie\n* Ihr\n\n* z. B.\n* usw.\n\n* `foo` vom Typ `int`\n* `bar` vom Typ `str`\n* `baz` vom Typ `list`\n\n* das Tutorial – Benutzerhandbuch\n* das Handbuch für fortgeschrittene Benutzer\n* die SQLModel-Dokumentation\n* die API-Dokumentation\n* die automatische Dokumentation\n\n* Data Science\n* Deep Learning\n* Machine Learning\n* Dependency Injection\n* HTTP Basic-Authentifizierung\n* HTTP Digest\n* ISO-Format\n* der JSON-Schema-Standard\n* das JSON-Schema\n* die Schema-Definition\n* Password Flow\n* Mobile\n\n* deprecatet\n* designt\n* ungültig\n* on the fly\n* Standard\n* Default\n* Groß-/Klein­schrei­bung ist relevant\n* Groß-/Klein­schrei­bung ist nicht relevant\n\n* die Anwendung bereitstellen\n* die Seite ausliefern\n\n* die App\n* die Anwendung\n\n* der Request\n* die Response\n* die Error-Response\n\n* die Pfadoperation\n* der Pfadoperation-Dekorator\n* die Pfadoperation-Funktion\n\n* der Body\n* der Requestbody\n* der Responsebody\n* der JSON-Body\n* der Formularbody\n* der Dateibody\n* der Funktionskörper\n\n* der Parameter\n* der Body-Parameter\n* der Pfad-Parameter\n* der Query-Parameter\n* der Cookie-Parameter\n* der Header-Parameter\n* der Formular-Parameter\n* der Funktionsparameter\n\n* das Event\n* das Startup-Event\n* das Hochfahren des Servers\n* das Shutdown-Event\n* das Lifespan-Event\n\n* der Handler\n* der Eventhandler\n* der Exceptionhandler\n* handhaben\n\n* das Modell\n* das Pydantic-Modell\n* das Datenmodell\n* das Datenbankmodell\n* das Formularmodell\n* das Modellobjekt\n\n* die Klasse\n* die Basisklasse\n* die Elternklasse\n* die Subklasse\n* die Kindklasse\n* die Geschwisterklasse\n* die Klassenmethode\n\n* der Header\n* die Header\n* der Autorisierungsheader\n* der `Authorization`-Header\n* der Forwarded-Header\n\n* das Dependency-Injection-System\n* die Dependency\n* das Dependable\n* der Dependant\n\n* I/O-lastig\n* CPU-lastig\n* Nebenläufigkeit\n* Parallelität\n* Multiprocessing\n\n* die Umgebungsvariable\n* die Umgebungsvariable\n* der `PATH`\n* die `PATH`-Umgebungsvariable\n\n* die Authentifizierung\n* der Authentifizierungsanbieter\n* die Autorisierung\n* das Anmeldeformular\n* der Autorisierungsanbieter\n* der Benutzer authentisiert sich\n* das System authentifiziert den Benutzer\n\n* Das CLI\n* Das Kommandozeileninterface\n\n* der Server\n* der Client\n\n* der Cloudanbieter\n* der Clouddienst\n\n* die Entwicklung\n* die Entwicklungsphasen\n\n* das Dict\n* das Dictionary\n* die Enumeration\n* das Enum\n* das Enum-Member\n\n* der Encoder\n* der Decoder\n* kodieren\n* dekodieren\n\n* die Exception\n* werfen\n\n* der Ausdruck\n* die Anweisung\n\n* das Frontend\n* das Backend\n\n* die GitHub-Diskussion\n* das GitHub-Issue\n\n* die Leistung\n* die Leistungsoptimierung\n\n* der Rückgabetyp\n* der Rückgabewert\n\n* die Sicherheit\n* das Sicherheitsschema\n\n* der Task\n* der Hintergrundtask\n* die Taskfunktion\n\n* das Template\n* die Template-Engine\n\n* die Typannotation\n* der Typhinweis\n\n* der Serverworker\n* der Uvicorn-Worker\n* der Gunicorn-Worker\n* der Workerprozess\n* die Workerklasse\n* die Workload\n\n* das Deployment\n* deployen\n\n* das SDK\n* das Software Development Kit\n\n* der `APIRouter`\n* die `requirements.txt`\n* das Bearer-Token\n* der Breaking Change\n* der Bug\n* der Button\n* das Callable\n* der Code\n* der Commit\n* der Contextmanager\n* die Coroutine\n* die Datenbanksession\n* die Festplatte\n* die Domain\n* die Engine\n* das Fake-X\n* die HTTP-GET-Methode\n* das Item\n* die Bibliothek\n* der Lifespan\n* der Lock\n* die Middleware\n* die Mobile-Anwendung\n* das Modul\n* das Mounten\n* das Netzwerk\n* das Origin\n* Die Überschreibung\n* die Payload\n* der Prozessor\n* die Property\n* der Proxy\n* der Pull Request\n* die Query\n* der RAM\n* der entfernte Rechner\n* der Statuscode\n* der String\n* der Tag\n* das Webframework\n* die Wildcard\n* zurückgeben\n* validieren\n\n////\n\n//// tab | Info\n\nDies ist eine nicht vollständige und nicht normative Liste von (meist) technischen Begriffen, die in der Dokumentation vorkommen. Sie kann dem Promptdesigner helfen herauszufinden, bei welchen Begriffen das LLM Unterstützung braucht. Zum Beispiel, wenn es eine gute Übersetzung immer wieder auf eine suboptimale Übersetzung zurücksetzt. Oder wenn es Probleme hat, einen Begriff in Ihrer Sprache zu konjugieren/deklinieren.\n\nSiehe z. B. den Abschnitt `### List of English terms and their preferred German translations` in `docs/de/llm-prompt.md`.\n\n////\n"
  },
  {
    "path": "docs/de/docs/about/index.md",
    "content": "# Über { #about }\n\nÜber FastAPI, sein Design, seine Inspiration und mehr. 🤓\n"
  },
  {
    "path": "docs/de/docs/advanced/additional-responses.md",
    "content": "# Zusätzliche Responses in OpenAPI { #additional-responses-in-openapi }\n\n/// warning | Achtung\n\nDies ist ein eher fortgeschrittenes Thema.\n\nWenn Sie mit **FastAPI** beginnen, benötigen Sie dies möglicherweise nicht.\n\n///\n\nSie können zusätzliche <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Responses</abbr> mit zusätzlichen Statuscodes, Medientypen, Beschreibungen, usw. deklarieren.\n\nDiese zusätzlichen Responses werden in das OpenAPI-Schema aufgenommen, sodass sie auch in der API-Dokumentation erscheinen.\n\nFür diese zusätzlichen Responses müssen Sie jedoch sicherstellen, dass Sie eine `Response`, wie etwa `JSONResponse`, direkt zurückgeben, mit Ihrem Statuscode und Inhalt.\n\n## Zusätzliche Response mit `model` { #additional-response-with-model }\n\nSie können Ihren *Pfadoperation-Dekoratoren* einen Parameter `responses` übergeben.\n\nDer nimmt ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr> entgegen, die Schlüssel sind Statuscodes für jede Response, wie etwa `200`, und die Werte sind andere `dict`s mit den Informationen für jede Response.\n\nJedes dieser Response-`dict`s kann einen Schlüssel `model` haben, welcher ein Pydantic-Modell enthält, genau wie `response_model`.\n\n**FastAPI** nimmt dieses Modell, generiert dessen JSON-Schema und fügt es an der richtigen Stelle in OpenAPI ein.\n\nUm beispielsweise eine weitere Response mit dem Statuscode `404` und einem Pydantic-Modell `Message` zu deklarieren, können Sie schreiben:\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | Hinweis\n\nBeachten Sie, dass Sie die `JSONResponse` direkt zurückgeben müssen.\n\n///\n\n/// info | Info\n\nDer `model`-Schlüssel ist nicht Teil von OpenAPI.\n\n**FastAPI** nimmt das Pydantic-Modell von dort, generiert das JSON-Schema und fügt es an der richtigen Stelle ein.\n\nDie richtige Stelle ist:\n\n* Im Schlüssel `content`, der als Wert ein weiteres JSON-Objekt (`dict`) hat, welches Folgendes enthält:\n    * Ein Schlüssel mit dem Medientyp, z. B. `application/json`, der als Wert ein weiteres JSON-Objekt hat, welches Folgendes enthält:\n        * Ein Schlüssel `schema`, der als Wert das JSON-Schema aus dem Modell hat, hier ist die richtige Stelle.\n            * **FastAPI** fügt hier eine Referenz auf die globalen JSON-Schemas an einer anderen Stelle in Ihrer OpenAPI hinzu, anstatt es direkt einzubinden. Auf diese Weise können andere Anwendungen und Clients diese JSON-Schemas direkt verwenden, bessere Tools zur Codegenerierung bereitstellen, usw.\n\n///\n\nDie generierten Responses in der OpenAPI für diese *Pfadoperation* lauten:\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nDie Schemas werden von einer anderen Stelle innerhalb des OpenAPI-Schemas referenziert:\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## Zusätzliche Medientypen für die Haupt-Response { #additional-media-types-for-the-main-response }\n\nSie können denselben `responses`-Parameter verwenden, um verschiedene Medientypen für dieselbe Haupt-Response hinzuzufügen.\n\nSie können beispielsweise einen zusätzlichen Medientyp `image/png` hinzufügen und damit deklarieren, dass Ihre *Pfadoperation* ein JSON-Objekt (mit dem Medientyp `application/json`) oder ein PNG-Bild zurückgeben kann:\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | Hinweis\n\nBeachten Sie, dass Sie das Bild direkt mit einer `FileResponse` zurückgeben müssen.\n\n///\n\n/// info | Info\n\nSofern Sie in Ihrem Parameter `responses` nicht explizit einen anderen Medientyp angeben, geht FastAPI davon aus, dass die Response denselben Medientyp wie die Haupt-Response-Klasse hat (Standardmäßig `application/json`).\n\nWenn Sie jedoch eine benutzerdefinierte Response-Klasse mit `None` als Medientyp angegeben haben, verwendet FastAPI `application/json` für jede zusätzliche Response, die über ein zugehöriges Modell verfügt.\n\n///\n\n## Informationen kombinieren { #combining-information }\n\nSie können auch Response-Informationen von mehreren Stellen kombinieren, einschließlich der Parameter `response_model`, `status_code` und `responses`.\n\nSie können ein `response_model` deklarieren, indem Sie den Standardstatuscode `200` (oder bei Bedarf einen benutzerdefinierten) verwenden und dann zusätzliche Informationen für dieselbe Response in `responses` direkt im OpenAPI-Schema deklarieren.\n\n**FastAPI** behält die zusätzlichen Informationen aus `responses` und kombiniert sie mit dem JSON-Schema aus Ihrem Modell.\n\nSie können beispielsweise eine Response mit dem Statuscode `404` deklarieren, die ein Pydantic-Modell verwendet und über eine benutzerdefinierte Beschreibung (`description`) verfügt.\n\nUnd eine Response mit dem Statuscode `200`, die Ihr `response_model` verwendet, aber ein benutzerdefiniertes Beispiel (`example`) enthält:\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\nEs wird alles kombiniert und in Ihre OpenAPI eingebunden und in der API-Dokumentation angezeigt:\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## Vordefinierte und benutzerdefinierte Responses kombinieren { #combine-predefined-responses-and-custom-ones }\n\nMöglicherweise möchten Sie einige vordefinierte Responses haben, die für viele *Pfadoperationen* gelten, Sie möchten diese jedoch mit benutzerdefinierten Responses kombinieren, die für jede *Pfadoperation* erforderlich sind.\n\nIn diesen Fällen können Sie die Python-Technik zum „Entpacken“ eines `dict`s mit `**dict_to_unpack` verwenden:\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\nHier wird `new_dict` alle Schlüssel-Wert-Paare von `old_dict` plus das neue Schlüssel-Wert-Paar enthalten:\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\nMit dieser Technik können Sie einige vordefinierte Responses in Ihren *Pfadoperationen* wiederverwenden und sie mit zusätzlichen benutzerdefinierten Responses kombinieren.\n\nZum Beispiel:\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## Weitere Informationen zu OpenAPI-Responses { #more-information-about-openapi-responses }\n\nUm zu sehen, was genau Sie in die Responses aufnehmen können, können Sie die folgenden Abschnitte in der OpenAPI-Spezifikation überprüfen:\n\n* [OpenAPI Responses Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object), enthält das `Response Object`.\n* [OpenAPI Response Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object), Sie können alles davon direkt in jede Response innerhalb Ihres `responses`-Parameter einfügen. Einschließlich `description`, `headers`, `content` (darin deklarieren Sie verschiedene Medientypen und JSON-Schemas) und `links`.\n"
  },
  {
    "path": "docs/de/docs/advanced/additional-status-codes.md",
    "content": "# Zusätzliche Statuscodes { #additional-status-codes }\n\nStandardmäßig liefert **FastAPI** die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Responses</abbr> als `JSONResponse` zurück und fügt den Inhalt, den Sie aus Ihrer *Pfadoperation* zurückgeben, in diese `JSONResponse` ein.\n\nEs wird der Default-Statuscode oder derjenige verwendet, den Sie in Ihrer *Pfadoperation* festgelegt haben.\n\n## Zusätzliche Statuscodes { #additional-status-codes_1 }\n\nWenn Sie neben dem Hauptstatuscode weitere Statuscodes zurückgeben möchten, können Sie dies tun, indem Sie direkt eine `Response` zurückgeben, wie etwa eine `JSONResponse`, und den zusätzlichen Statuscode direkt festlegen.\n\nAngenommen, Sie möchten eine *Pfadoperation* haben, die das Aktualisieren von Artikeln ermöglicht und bei Erfolg den HTTP-Statuscode 200 „OK“ zurückgibt.\n\nSie möchten aber auch, dass sie neue Artikel akzeptiert. Und wenn die Artikel vorher nicht vorhanden waren, werden diese Artikel erstellt und der HTTP-Statuscode 201 „Created“ zurückgegeben.\n\nUm dies zu erreichen, importieren Sie `JSONResponse`, und geben Sie Ihren Inhalt direkt zurück, indem Sie den gewünschten `status_code` setzen:\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning | Achtung\n\nWenn Sie eine `Response` direkt zurückgeben, wie im obigen Beispiel, wird sie direkt zurückgegeben.\n\nSie wird nicht mit einem Modell usw. serialisiert.\n\nStellen Sie sicher, dass sie die gewünschten Daten enthält und dass die Werte gültiges JSON sind (wenn Sie `JSONResponse` verwenden).\n\n///\n\n/// note | Technische Details\n\nSie können auch `from starlette.responses import JSONResponse` verwenden.\n\n**FastAPI** bietet dieselben `starlette.responses` auch via `fastapi.responses` an, als Annehmlichkeit für Sie, den Entwickler. Die meisten verfügbaren Responses kommen aber direkt von Starlette. Dasselbe gilt für `status`.\n\n///\n\n## OpenAPI- und API-Dokumentation { #openapi-and-api-docs }\n\nWenn Sie zusätzliche Statuscodes und Responses direkt zurückgeben, werden diese nicht in das OpenAPI-Schema (die API-Dokumentation) aufgenommen, da FastAPI keine Möglichkeit hat, im Voraus zu wissen, was Sie zurückgeben werden.\n\nSie können das jedoch in Ihrem Code dokumentieren, indem Sie Folgendes verwenden: [Zusätzliche Responses](additional-responses.md).\n"
  },
  {
    "path": "docs/de/docs/advanced/advanced-dependencies.md",
    "content": "# Fortgeschrittene Abhängigkeiten { #advanced-dependencies }\n\n## Parametrisierte Abhängigkeiten { #parameterized-dependencies }\n\nAlle Abhängigkeiten, die wir bisher gesehen haben, waren festgelegte Funktionen oder Klassen.\n\nEs kann jedoch Fälle geben, in denen Sie Parameter für eine Abhängigkeit festlegen möchten, ohne viele verschiedene Funktionen oder Klassen zu deklarieren.\n\nStellen wir uns vor, wir möchten eine Abhängigkeit haben, die prüft, ob ein Query-Parameter `q` einen vordefinierten Inhalt hat.\n\nAber wir wollen diesen vordefinierten Inhalt per Parameter festlegen können.\n\n## Eine „aufrufbare“ Instanz { #a-callable-instance }\n\nIn Python gibt es eine Möglichkeit, eine Instanz einer Klasse <abbr title=\"Englisch „callable“\">„aufrufbar“</abbr> zu machen.\n\nNicht die Klasse selbst (die bereits aufrufbar ist), sondern eine Instanz dieser Klasse.\n\nDazu deklarieren wir eine Methode `__call__`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\nIn diesem Fall ist dieses `__call__` das, was **FastAPI** verwendet, um nach zusätzlichen Parametern und Unterabhängigkeiten zu suchen, und das ist es auch, was später aufgerufen wird, um einen Wert an den Parameter in Ihrer *Pfadoperation-Funktion* zu übergeben.\n\n## Die Instanz parametrisieren { #parameterize-the-instance }\n\nUnd jetzt können wir `__init__` verwenden, um die Parameter der Instanz zu deklarieren, die wir zum „Parametrisieren“ der Abhängigkeit verwenden können:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\nIn diesem Fall wird **FastAPI** `__init__` nie berühren oder sich darum kümmern, wir werden es direkt in unserem Code verwenden.\n\n## Eine Instanz erstellen { #create-an-instance }\n\nWir könnten eine Instanz dieser Klasse erstellen mit:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\nUnd auf diese Weise können wir unsere Abhängigkeit „parametrisieren“, die jetzt `\"bar\"` enthält, als das Attribut `checker.fixed_content`.\n\n## Die Instanz als Abhängigkeit verwenden { #use-the-instance-as-a-dependency }\n\nDann könnten wir diesen `checker` in einem `Depends(checker)` anstelle von `Depends(FixedContentQueryChecker)` verwenden, da die Abhängigkeit die Instanz `checker` und nicht die Klasse selbst ist.\n\nUnd beim Auflösen der Abhängigkeit ruft **FastAPI** diesen `checker` wie folgt auf:\n\n```Python\nchecker(q=\"somequery\")\n```\n\n... und übergibt, was immer das als Wert dieser Abhängigkeit in unserer *Pfadoperation-Funktion* zurückgibt, als den Parameter `fixed_content_included`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | Tipp\n\nDas alles mag gekünstelt wirken. Und es ist möglicherweise noch nicht ganz klar, welchen Nutzen das hat.\n\nDiese Beispiele sind bewusst einfach gehalten, zeigen aber, wie alles funktioniert.\n\nIn den Kapiteln zum Thema Sicherheit gibt es Hilfsfunktionen, die auf die gleiche Weise implementiert werden.\n\nWenn Sie das hier alles verstanden haben, wissen Sie bereits, wie diese Sicherheits-Hilfswerkzeuge unter der Haube funktionieren.\n\n///\n\n## Abhängigkeiten mit `yield`, `HTTPException`, `except` und Hintergrundtasks { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | Achtung\n\nSie benötigen diese technischen Details höchstwahrscheinlich nicht.\n\nDiese Details sind hauptsächlich nützlich, wenn Sie eine FastAPI-Anwendung haben, die älter als 0.121.0 ist, und Sie auf Probleme mit Abhängigkeiten mit `yield` stoßen.\n\n///\n\nAbhängigkeiten mit `yield` haben sich im Laufe der Zeit weiterentwickelt, um verschiedene Anwendungsfälle abzudecken und einige Probleme zu beheben, hier ist eine Zusammenfassung der Änderungen.\n\n### Abhängigkeiten mit `yield` und `scope` { #dependencies-with-yield-and-scope }\n\nIn Version 0.121.0 hat FastAPI Unterstützung für `Depends(scope=\"function\")` für Abhängigkeiten mit `yield` hinzugefügt.\n\nMit `Depends(scope=\"function\")` wird der Exit-Code nach `yield` direkt nach dem Ende der *Pfadoperation-Funktion* ausgeführt, bevor die Response an den Client gesendet wird.\n\nUnd bei Verwendung von `Depends(scope=\"request\")` (dem Default) wird der Exit-Code nach `yield` ausgeführt, nachdem die Response gesendet wurde.\n\nMehr dazu finden Sie in der Dokumentation zu [Abhängigkeiten mit `yield` – Frühes Beenden und `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope).\n\n### Abhängigkeiten mit `yield` und `StreamingResponse`, Technische Details { #dependencies-with-yield-and-streamingresponse-technical-details }\n\nVor FastAPI 0.118.0 wurde bei Verwendung einer Abhängigkeit mit `yield` der Exit-Code nach der *Pfadoperation-Funktion* ausgeführt, aber unmittelbar bevor die Response gesendet wurde.\n\nDie Absicht war, Ressourcen nicht länger als nötig zu halten, während darauf gewartet wird, dass die Response durchs Netzwerk reist.\n\nDiese Änderung bedeutete auch, dass bei Rückgabe einer `StreamingResponse` der Exit-Code der Abhängigkeit mit `yield` bereits ausgeführt worden wäre.\n\nWenn Sie beispielsweise eine Datenbanksession in einer Abhängigkeit mit `yield` hatten, konnte die `StreamingResponse` diese Session während des Streamens von Daten nicht verwenden, weil die Session im Exit-Code nach `yield` bereits geschlossen worden wäre.\n\nDieses Verhalten wurde in 0.118.0 zurückgenommen, sodass der Exit-Code nach `yield` ausgeführt wird, nachdem die Response gesendet wurde.\n\n/// info | Info\n\nWie Sie unten sehen werden, ähnelt dies sehr dem Verhalten vor Version 0.106.0, jedoch mit mehreren Verbesserungen und Bugfixes für Sonderfälle.\n\n///\n\n#### Anwendungsfälle mit frühem Exit-Code { #use-cases-with-early-exit-code }\n\nEs gibt einige Anwendungsfälle mit spezifischen Bedingungen, die vom alten Verhalten profitieren könnten, den Exit-Code von Abhängigkeiten mit `yield` vor dem Senden der Response auszuführen.\n\nStellen Sie sich zum Beispiel vor, Sie haben Code, der in einer Abhängigkeit mit `yield` eine Datenbanksession verwendet, nur um einen Benutzer zu verifizieren, die Datenbanksession wird aber in der *Pfadoperation-Funktion* nie wieder verwendet, sondern nur in der Abhängigkeit, und die Response benötigt lange, um gesendet zu werden, wie eine `StreamingResponse`, die Daten langsam sendet, aus irgendeinem Grund aber die Datenbank nicht verwendet.\n\nIn diesem Fall würde die Datenbanksession gehalten, bis das Senden der Response abgeschlossen ist, aber wenn Sie sie nicht verwenden, wäre es nicht notwendig, sie zu halten.\n\nSo könnte es aussehen:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\nDer Exit-Code, das automatische Schließen der `Session` in:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n... würde ausgeführt, nachdem die Response das langsame Senden der Daten beendet:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nDa `generate_stream()` die Datenbanksession jedoch nicht verwendet, ist es nicht wirklich notwendig, die Session während des Sendens der Response offen zu halten.\n\nWenn Sie diesen spezifischen Anwendungsfall mit SQLModel (oder SQLAlchemy) haben, könnten Sie die Session explizit schließen, nachdem Sie sie nicht mehr benötigen:\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\nAuf diese Weise würde die Session die Datenbankverbindung freigeben, sodass andere Requests sie verwenden könnten.\n\nWenn Sie einen anderen Anwendungsfall haben, der ein frühes Beenden aus einer Abhängigkeit mit `yield` benötigt, erstellen Sie bitte eine [GitHub-Diskussion-Frage](https://github.com/fastapi/fastapi/discussions/new?category=questions) mit Ihrem spezifischen Anwendungsfall und warum Sie von einem frühen Schließen für Abhängigkeiten mit `yield` profitieren würden.\n\nWenn es überzeugende Anwendungsfälle für ein frühes Schließen bei Abhängigkeiten mit `yield` gibt, würde ich erwägen, eine neue Möglichkeit hinzuzufügen, um ein frühes Schließen optional zu aktivieren.\n\n### Abhängigkeiten mit `yield` und `except`, Technische Details { #dependencies-with-yield-and-except-technical-details }\n\nVor FastAPI 0.110.0 war es so, dass wenn Sie eine Abhängigkeit mit `yield` verwendet und dann in dieser Abhängigkeit mit `except` eine Exception abgefangen haben und die Exception nicht erneut geworfen haben, die Exception automatisch an beliebige Exceptionhandler oder den Handler für interne Serverfehler weitergereicht/weitergeworfen wurde.\n\nDies wurde in Version 0.110.0 geändert, um unbehandelten Speicherverbrauch durch weitergeleitete Exceptions ohne Handler (interne Serverfehler) zu beheben und um es mit dem Verhalten von normalem Python-Code konsistent zu machen.\n\n### Hintergrundtasks und Abhängigkeiten mit `yield`, Technische Details { #background-tasks-and-dependencies-with-yield-technical-details }\n\nVor FastAPI 0.106.0 war das Werfen von Exceptions nach `yield` nicht möglich, der Exit-Code in Abhängigkeiten mit `yield` wurde ausgeführt, nachdem die Response gesendet wurde, sodass [Exceptionhandler](../tutorial/handling-errors.md#install-custom-exception-handlers) bereits ausgeführt worden wären.\n\nDies war so designt, hauptsächlich um die Verwendung derselben von Abhängigkeiten „geyieldeten“ Objekte in Hintergrundtasks zu ermöglichen, da der Exit-Code erst ausgeführt wurde, nachdem die Hintergrundtasks abgeschlossen waren.\n\nDies wurde in FastAPI 0.106.0 geändert mit der Absicht, keine Ressourcen zu halten, während darauf gewartet wird, dass die Response durchs Netzwerk reist.\n\n/// tip | Tipp\n\nZusätzlich ist ein Hintergrundtask normalerweise ein unabhängiger Logikblock, der separat gehandhabt werden sollte, mit eigenen Ressourcen (z. B. eigener Datenbankverbindung).\n\nSo haben Sie wahrscheinlich saubereren Code.\n\n///\n\nWenn Sie sich bisher auf dieses Verhalten verlassen haben, sollten Sie jetzt die Ressourcen für Hintergrundtasks innerhalb des Hintergrundtasks selbst erstellen und intern nur Daten verwenden, die nicht von den Ressourcen von Abhängigkeiten mit `yield` abhängen.\n\nAnstatt beispielsweise dieselbe Datenbanksession zu verwenden, würden Sie innerhalb des Hintergrundtasks eine neue Datenbanksession erstellen und die Objekte aus der Datenbank mithilfe dieser neuen Session beziehen. Und anstatt das Objekt aus der Datenbank als Parameter an die Hintergrundtask-Funktion zu übergeben, würden Sie die ID dieses Objekts übergeben und das Objekt dann innerhalb der Hintergrundtask-Funktion erneut beziehen.\n"
  },
  {
    "path": "docs/de/docs/advanced/advanced-python-types.md",
    "content": "# Fortgeschrittene Python-Typen { #advanced-python-types }\n\nHier sind einige zusätzliche Ideen, die beim Arbeiten mit Python-Typen nützlich sein könnten.\n\n## `Union` oder `Optional` verwenden { #using-union-or-optional }\n\nWenn Ihr Code aus irgendeinem Grund nicht `|` verwenden kann, z. B. wenn es nicht in einer Typannotation ist, sondern in etwas wie `response_model=`, können Sie anstelle des senkrechten Strichs (`|`) `Union` aus `typing` verwenden.\n\nZum Beispiel könnten Sie deklarieren, dass etwas ein `str` oder `None` sein könnte:\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\n`typing` hat außerdem eine Abkürzung, um zu deklarieren, dass etwas `None` sein könnte, mit `Optional`.\n\nHier ist ein Tipp aus meiner sehr **subjektiven** Perspektive:\n\n* 🚨 Vermeiden Sie die Verwendung von `Optional[SomeType]`\n* Verwenden Sie stattdessen ✨ **`Union[SomeType, None]`** ✨.\n\nBeides ist äquivalent und unter der Haube identisch, aber ich würde `Union` statt `Optional` empfehlen, weil das Wort „**optional**“ implizieren könnte, dass der Wert optional ist; tatsächlich bedeutet es jedoch „es kann `None` sein“, selbst wenn es nicht optional ist und weiterhin erforderlich bleibt.\n\nIch finde, `Union[SomeType, None]` ist expliziter in dem, was es bedeutet.\n\nEs geht nur um Wörter und Namen. Aber diese Wörter können beeinflussen, wie Sie und Ihr Team über den Code denken.\n\nAls Beispiel nehmen wir diese Funktion:\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\nDer Parameter `name` ist als `Optional[str]` definiert, aber er ist **nicht optional**, Sie können die Funktion nicht ohne den Parameter aufrufen:\n\n```Python\nsay_hi()  # Oh nein, das löst einen Fehler aus! 😱\n```\n\nDer Parameter `name` ist **weiterhin erforderlich** (nicht *optional*), weil er keinen Defaultwert hat. Dennoch akzeptiert `name` den Wert `None`:\n\n```Python\nsay_hi(name=None)  # Das funktioniert, None ist gültig 🎉\n```\n\nDie gute Nachricht ist: In den meisten Fällen können Sie einfach `|` verwenden, um Unions von Typen zu definieren:\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\nSie müssen sich also normalerweise keine Gedanken über Namen wie `Optional` und `Union` machen. 😎\n"
  },
  {
    "path": "docs/de/docs/advanced/async-tests.md",
    "content": "# Asynchrone Tests { #async-tests }\n\nSie haben bereits gesehen, wie Sie Ihre **FastAPI**-Anwendungen mit dem bereitgestellten `TestClient` testen. Bisher haben Sie nur gesehen, wie man synchrone Tests schreibt, ohne `async`-Funktionen zu verwenden.\n\nDie Möglichkeit, in Ihren Tests asynchrone Funktionen zu verwenden, könnte beispielsweise nützlich sein, wenn Sie Ihre Datenbank asynchron abfragen. Stellen Sie sich vor, Sie möchten das Senden von <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> an Ihre FastAPI-Anwendung testen und dann überprüfen, ob Ihr Backend die richtigen Daten erfolgreich in die Datenbank geschrieben hat, während Sie eine asynchrone Datenbankbibliothek verwenden.\n\nSchauen wir uns an, wie wir das machen können.\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\nWenn wir in unseren Tests asynchrone Funktionen aufrufen möchten, müssen unsere Testfunktionen asynchron sein. AnyIO stellt hierfür ein nettes Plugin zur Verfügung, mit dem wir festlegen können, dass einige Testfunktionen asynchron aufgerufen werden sollen.\n\n## HTTPX { #httpx }\n\nAuch wenn Ihre **FastAPI**-Anwendung normale `def`-Funktionen anstelle von `async def` verwendet, handelt es sich darunter immer noch um eine `async`-Anwendung.\n\nDer `TestClient` betreibt unter der Haube etwas Magie, um die asynchrone FastAPI-Anwendung in Ihren normalen `def`-Testfunktionen, mithilfe von Standard-Pytest aufzurufen. Aber diese Magie funktioniert nicht mehr, wenn wir sie in asynchronen Funktionen verwenden. Durch die asynchrone Ausführung unserer Tests können wir den `TestClient` nicht mehr in unseren Testfunktionen verwenden.\n\nDer `TestClient` basiert auf [HTTPX](https://www.python-httpx.org) und glücklicherweise können wir es direkt verwenden, um die API zu testen.\n\n## Beispiel { #example }\n\nBetrachten wir als einfaches Beispiel eine Dateistruktur ähnlich der in [Größere Anwendungen](../tutorial/bigger-applications.md) und [Testen](../tutorial/testing.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nDie Datei `main.py` hätte als Inhalt:\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\nDie Datei `test_main.py` hätte die Tests für `main.py`, das könnte jetzt so aussehen:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## Es ausführen { #run-it }\n\nSie können Ihre Tests wie gewohnt ausführen mit:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## Im Detail { #in-detail }\n\nDer Marker `@pytest.mark.anyio` teilt pytest mit, dass diese Testfunktion asynchron aufgerufen werden soll:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip | Tipp\n\nBeachten Sie, dass die Testfunktion jetzt `async def` ist und nicht nur `def` wie zuvor, wenn Sie den `TestClient` verwenden.\n\n///\n\nDann können wir einen `AsyncClient` mit der App erstellen und mit `await` asynchrone Requests an ihn senden.\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\nDas ist das Äquivalent zu:\n\n```Python\nresponse = client.get('/')\n```\n\n... welches wir verwendet haben, um unsere Requests mit dem `TestClient` zu machen.\n\n/// tip | Tipp\n\nBeachten Sie, dass wir async/await mit dem neuen `AsyncClient` verwenden – der Request ist asynchron.\n\n///\n\n/// warning | Achtung\n\nFalls Ihre Anwendung auf Lifespan-Events angewiesen ist, der `AsyncClient` löst diese Events nicht aus. Um sicherzustellen, dass sie ausgelöst werden, verwenden Sie `LifespanManager` von [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage).\n\n///\n\n## Andere asynchrone Funktionsaufrufe { #other-asynchronous-function-calls }\n\nDa die Testfunktion jetzt asynchron ist, können Sie in Ihren Tests neben dem Senden von Requests an Ihre FastAPI-Anwendung jetzt auch andere `async`-Funktionen aufrufen (und `await`en), genau so, wie Sie diese an anderer Stelle in Ihrem Code aufrufen würden.\n\n/// tip | Tipp\n\nWenn Sie einen `RuntimeError: Task attached to a different loop` erhalten, wenn Sie asynchrone Funktionsaufrufe in Ihre Tests integrieren (z. B. bei Verwendung von [MongoDBs MotorClient](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop)), dann denken Sie daran, Objekte zu instanziieren, die einen Event Loop nur innerhalb asynchroner Funktionen benötigen, z. B. einen `@app.on_event(\"startup\")`-Callback.\n\n///\n"
  },
  {
    "path": "docs/de/docs/advanced/behind-a-proxy.md",
    "content": "# Hinter einem Proxy { #behind-a-proxy }\n\nIn vielen Situationen würden Sie einen **Proxy** wie Traefik oder Nginx vor Ihrer FastAPI-App verwenden.\n\nDiese Proxys könnten HTTPS-Zertifikate und andere Dinge handhaben.\n\n## Proxy-<abbr title=\"weitergeleitete Header\">Forwarded-Header</abbr> { #proxy-forwarded-headers }\n\nEin **Proxy** vor Ihrer Anwendung würde normalerweise einige Header on-the-fly setzen, bevor er die Requests an den **Server** sendet, um den Server wissen zu lassen, dass der Request vom Proxy **weitergeleitet** wurde, einschließlich der ursprünglichen (öffentlichen) URL, inklusive der Domain, dass HTTPS verwendet wird, usw.\n\nDas **Server**-Programm (z. B. **Uvicorn** via **FastAPI CLI**) ist in der Lage, diese Header zu interpretieren und diese Information dann an Ihre Anwendung weiterzugeben.\n\nAber aus Sicherheitsgründen, da der Server nicht weiß, dass er hinter einem vertrauenswürdigen Proxy läuft, wird er diese Header nicht interpretieren.\n\n/// note | Technische Details\n\nDie Proxy-Header sind:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### Proxy-Forwarded-Header aktivieren { #enable-proxy-forwarded-headers }\n\nSie können FastAPI CLI mit der *CLI-Option* `--forwarded-allow-ips` starten und die IP-Adressen übergeben, denen vertraut werden soll, um diese Forwarded-Header zu lesen.\n\nWenn Sie es auf `--forwarded-allow-ips=\"*\"` setzen, würde es allen eingehenden IPs vertrauen.\n\nWenn Ihr **Server** hinter einem vertrauenswürdigen **Proxy** sitzt und nur der Proxy mit ihm spricht, würde dies dazu führen, dass er die IP dieses **Proxys** akzeptiert, was auch immer sie ist.\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Weiterleitungen mit HTTPS { #redirects-with-https }\n\nAngenommen, Sie definieren eine *Pfadoperation* `/items/`:\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\nWenn der Client versucht, zu `/items` zu gehen, würde er standardmäßig zu `/items/` umgeleitet.\n\nAber bevor Sie die *CLI-Option* `--forwarded-allow-ips` setzen, könnte er zu `http://localhost:8000/items/` umleiten.\n\nAber möglicherweise wird Ihre Anwendung unter `https://mysuperapp.com` gehostet, und die Weiterleitung sollte zu `https://mysuperapp.com/items/` erfolgen.\n\nDurch Setzen von `--proxy-headers` kann FastAPI jetzt an den richtigen Ort umleiten. 😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip | Tipp\n\nWenn Sie mehr über HTTPS erfahren möchten, lesen Sie den Leitfaden [Über HTTPS](../deployment/https.md).\n\n///\n\n### Wie Proxy-Forwarded-Header funktionieren { #how-proxy-forwarded-headers-work }\n\nHier ist eine visuelle Darstellung, wie der **Proxy** weitergeleitete Header zwischen dem Client und dem **Anwendungsserver** hinzufügt:\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Proxy as Proxy/Loadbalancer\n    participant Server as FastAPI Server\n\n    Client->>Proxy: HTTPS-Request<br/>Host: mysuperapp.com<br/>Pfad: /items\n\n    Note over Proxy: Proxy fügt Forwarded-Header hinzu\n\n    Proxy->>Server: HTTP-Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Pfad: /items\n\n    Note over Server: Server interpretiert die Header<br/>(wenn --forwarded-allow-ips gesetzt ist)\n\n    Server->>Proxy: HTTP-Response<br/>mit correkten HTTPS-URLs\n\n    Proxy->>Client: HTTPS-Response\n```\n\nDer **Proxy** fängt den ursprünglichen Client-Request ab und fügt die speziellen *Forwarded*-Header (`X-Forwarded-*`) hinzu, bevor er den Request an den **Anwendungsserver** weitergibt.\n\nDiese Header bewahren Informationen über den ursprünglichen Request, die sonst verloren gingen:\n\n* **X-Forwarded-For**: Die ursprüngliche IP-Adresse des Clients\n* **X-Forwarded-Proto**: Das ursprüngliche Protokoll (`https`)\n* **X-Forwarded-Host**: Der ursprüngliche Host (`mysuperapp.com`)\n\nWenn **FastAPI CLI** mit `--forwarded-allow-ips` konfiguriert ist, vertraut es diesen Headern und verwendet sie, z. B. um die korrekten URLs in Weiterleitungen zu erzeugen.\n\n## Proxy mit einem abgetrennten Pfadpräfix { #proxy-with-a-stripped-path-prefix }\n\nSie könnten einen Proxy haben, der Ihrer Anwendung ein Pfadpräfix hinzufügt.\n\nIn diesen Fällen können Sie <abbr title=\"Wurzelpfad\">`root_path`</abbr> verwenden, um Ihre Anwendung zu konfigurieren.\n\nDer `root_path` ist ein Mechanismus, der von der ASGI-Spezifikation bereitgestellt wird (auf der FastAPI via Starlette aufbaut).\n\nDer `root_path` wird verwendet, um diese speziellen Fälle zu handhaben.\n\nUnd er wird auch intern beim Mounten von Unteranwendungen verwendet.\n\nEin Proxy mit einem abgetrennten Pfadpräfix bedeutet in diesem Fall, dass Sie einen Pfad unter `/app` in Ihrem Code deklarieren könnten, dann aber, eine Ebene darüber, den Proxy hinzufügen, der Ihre **FastAPI**-Anwendung unter einem Pfad wie `/api/v1` platziert.\n\nIn diesem Fall würde der ursprüngliche Pfad `/app` tatsächlich unter `/api/v1/app` bereitgestellt.\n\nAuch wenn Ihr gesamter Code unter der Annahme geschrieben ist, dass es nur `/app` gibt.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\nUnd der Proxy würde das **Pfadpräfix** on-the-fly **„entfernen“**, bevor er den <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> an den Anwendungsserver (wahrscheinlich Uvicorn via FastAPI CLI) übermittelt, dafür sorgend, dass Ihre Anwendung davon überzeugt ist, dass sie unter `/app` bereitgestellt wird, sodass Sie nicht Ihren gesamten Code dahingehend aktualisieren müssen, das Präfix `/api/v1` zu verwenden.\n\nBis hierher würde alles wie gewohnt funktionieren.\n\nWenn Sie dann jedoch die Benutzeroberfläche der integrierten Dokumentation (das Frontend) öffnen, wird angenommen, dass sich das OpenAPI-Schema unter `/openapi.json` anstelle von `/api/v1/openapi.json` befindet.\n\nAlso würde das Frontend (das im Browser läuft) versuchen, `/openapi.json` zu erreichen und wäre nicht in der Lage, das OpenAPI-Schema abzurufen.\n\nDa wir für unsere Anwendung einen Proxy mit dem Pfadpräfix `/api/v1` haben, muss das Frontend das OpenAPI-Schema unter `/api/v1/openapi.json` abrufen.\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy auf http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server auf http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip | Tipp\n\nDie IP `0.0.0.0` wird üblicherweise verwendet, um anzudeuten, dass das Programm alle auf diesem Computer/Server verfügbaren IPs abhört.\n\n///\n\nDie Benutzeroberfläche der Dokumentation würde benötigen, dass das OpenAPI-Schema deklariert, dass sich dieser API-`server` unter `/api/v1` (hinter dem Proxy) befindet. Zum Beispiel:\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // Hier mehr Einstellungen\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // Hier mehr Einstellungen\n    }\n}\n```\n\nIn diesem Beispiel könnte der „Proxy“ etwa **Traefik** sein. Und der Server wäre etwas wie FastAPI CLI mit **Uvicorn**, auf dem Ihre FastAPI-Anwendung ausgeführt wird.\n\n### Bereitstellung des `root_path` { #providing-the-root-path }\n\nUm dies zu erreichen, können Sie die Kommandozeilenoption `--root-path` wie folgt verwenden:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nFalls Sie Hypercorn verwenden, das hat auch die Option `--root-path`.\n\n/// note | Technische Details\n\nDie ASGI-Spezifikation definiert einen `root_path` für diesen Anwendungsfall.\n\nUnd die Kommandozeilenoption `--root-path` stellt diesen `root_path` bereit.\n\n///\n\n### Testen des aktuellen `root_path` { #checking-the-current-root-path }\n\nSie können den aktuellen `root_path` abrufen, der von Ihrer Anwendung für jeden Request verwendet wird. Er ist Teil des `scope`-<abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">Dictionarys</abbr> (das ist Teil der ASGI-Spezifikation).\n\nHier fügen wir ihn, nur zu Demonstrationszwecken, in die Nachricht ein.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\nWenn Sie Uvicorn dann starten mit:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nwäre die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> etwa:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### Festlegen des `root_path` in der FastAPI-Anwendung { #setting-the-root-path-in-the-fastapi-app }\n\nFalls Sie keine Möglichkeit haben, eine Kommandozeilenoption wie `--root-path` oder ähnlich zu übergeben, können Sie, alternativ dazu, beim Erstellen Ihrer FastAPI-Anwendung den Parameter `root_path` setzen:\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\nDie Übergabe des `root_path` an `FastAPI` wäre das Äquivalent zur Übergabe der `--root-path`-Kommandozeilenoption an Uvicorn oder Hypercorn.\n\n### Über `root_path` { #about-root-path }\n\nBeachten Sie, dass der Server (Uvicorn) diesen `root_path` für nichts anderes verwendet als für die Weitergabe an die Anwendung.\n\nAber wenn Sie mit Ihrem Browser auf [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app) gehen, sehen Sie die normale Response:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nEs wird also nicht erwartet, dass unter `http://127.0.0.1:8000/api/v1/app` darauf zugegriffen wird.\n\nUvicorn erwartet, dass der Proxy unter `http://127.0.0.1:8000/app` auf Uvicorn zugreift, und dann liegt es in der Verantwortung des Proxys, das zusätzliche `/api/v1`-Präfix darüber hinzuzufügen.\n\n## Über Proxys mit einem abgetrennten Pfadpräfix { #about-proxies-with-a-stripped-path-prefix }\n\nBedenken Sie, dass ein Proxy mit abgetrenntem Pfadpräfix nur eine von vielen Konfigurationsmöglichkeiten ist.\n\nWahrscheinlich wird in vielen Fällen die Standardeinstellung sein, dass der Proxy kein abgetrenntes Pfadpräfix hat.\n\nIn einem solchen Fall (ohne ein abgetrenntes Pfadpräfix) würde der Proxy auf etwas wie `https://myawesomeapp.com` lauschen, und wenn der Browser dann zu `https://myawesomeapp.com/api/v1/app` wechselt, und Ihr Server (z. B. Uvicorn) auf `http://127.0.0.1:8000` lauscht, würde der Proxy (ohne ein abgetrenntes Pfadpräfix) über denselben Pfad auf Uvicorn zugreifen: `http://127.0.0.1:8000/api/v1/app`.\n\n## Lokal testen mit Traefik { #testing-locally-with-traefik }\n\nSie können das Experiment mit einem abgetrennten Pfadpräfix einfach lokal ausführen, indem Sie [Traefik](https://docs.traefik.io/) verwenden.\n\n[Laden Sie Traefik herunter](https://github.com/containous/traefik/releases), es ist eine einzelne Binärdatei, Sie können die komprimierte Datei extrahieren und sie direkt vom Terminal aus ausführen.\n\nDann erstellen Sie eine Datei `traefik.toml` mit:\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\nDadurch wird Traefik angewiesen, Port 9999 abzuhören und eine andere Datei `routes.toml` zu verwenden.\n\n/// tip | Tipp\n\nWir verwenden Port 9999 anstelle des Standard-HTTP-Ports 80, damit Sie ihn nicht mit Administratorrechten (`sudo`) ausführen müssen.\n\n///\n\nErstellen Sie nun die andere Datei `routes.toml`:\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\nDiese Datei konfiguriert Traefik, das Pfadpräfix `/api/v1` zu verwenden.\n\nUnd dann leitet Traefik seine Requests an Ihren Uvicorn weiter, der unter `http://127.0.0.1:8000` läuft.\n\nStarten Sie nun Traefik:\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\nUnd jetzt starten Sie Ihre Anwendung mit Uvicorn, indem Sie die Option `--root-path` verwenden:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Die Responses testen { #check-the-responses }\n\nWenn Sie nun zur URL mit dem Port für Uvicorn gehen: [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), sehen Sie die normale Response:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip | Tipp\n\nBeachten Sie, dass, obwohl Sie unter `http://127.0.0.1:8000/app` darauf zugreifen, als `root_path` angezeigt wird `/api/v1`, welches aus der Option `--root-path` stammt.\n\n///\n\nÖffnen Sie nun die URL mit dem Port für Traefik, einschließlich des Pfadpräfixes: [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app).\n\nWir bekommen die gleiche Response:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nDiesmal jedoch unter der URL mit dem vom Proxy bereitgestellten Präfixpfad: `/api/v1`.\n\nDie Idee hier ist natürlich, dass jeder über den Proxy auf die Anwendung zugreifen soll, daher ist die Version mit dem Pfadpräfix `/api/v1` die „korrekte“.\n\nUnd die von Uvicorn direkt bereitgestellte Version ohne Pfadpräfix (`http://127.0.0.1:8000/app`) wäre ausschließlich für den Zugriff durch den _Proxy_ (Traefik) bestimmt.\n\nDies demonstriert, wie der Proxy (Traefik) das Pfadpräfix verwendet und wie der Server (Uvicorn) den `root_path` aus der Option `--root-path` verwendet.\n\n### Es in der Dokumentationsoberfläche testen { #check-the-docs-ui }\n\nJetzt folgt der spaßige Teil. ✨\n\nDer „offizielle“ Weg, auf die Anwendung zuzugreifen, wäre über den Proxy mit dem von uns definierten Pfadpräfix. Wenn Sie also die von Uvicorn direkt bereitgestellte Dokumentationsoberfläche ohne das Pfadpräfix in der URL ausprobieren, wird es erwartungsgemäß nicht funktionieren, da erwartet wird, dass der Zugriff über den Proxy erfolgt.\n\nSie können das unter [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) sehen:\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\nWenn wir jedoch unter der „offiziellen“ URL, über den Proxy mit Port `9999`, unter `/api/v1/docs`, auf die Dokumentationsoberfläche zugreifen, funktioniert es ordnungsgemäß! 🎉\n\nSie können das unter [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) testen:\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\nGenau so, wie wir es wollten. ✔️\n\nDies liegt daran, dass FastAPI diesen `root_path` verwendet, um den Default-`server` in OpenAPI mit der von `root_path` bereitgestellten URL zu erstellen.\n\n## Zusätzliche Server { #additional-servers }\n\n/// warning | Achtung\n\nDies ist ein fortgeschrittener Anwendungsfall. Überspringen Sie das gerne.\n\n///\n\nStandardmäßig erstellt **FastAPI** einen `server` im OpenAPI-Schema mit der URL für den `root_path`.\n\nSie können aber auch andere alternative `servers` bereitstellen, beispielsweise wenn Sie möchten, dass *dieselbe* Dokumentationsoberfläche mit einer Staging- und Produktionsumgebung interagiert.\n\nWenn Sie eine benutzerdefinierte Liste von Servern (`servers`) übergeben und es einen `root_path` gibt (da Ihre API hinter einem Proxy läuft), fügt **FastAPI** einen „Server“ mit diesem `root_path` am Anfang der Liste ein.\n\nZum Beispiel:\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\nErzeugt ein OpenAPI-Schema, wie:\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // Hier mehr Einstellungen\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // Hier mehr Einstellungen\n    }\n}\n```\n\n/// tip | Tipp\n\nBeachten Sie den automatisch generierten Server mit dem `URL`-Wert `/api/v1`, welcher vom `root_path` stammt.\n\n///\n\nIn der Dokumentationsoberfläche unter [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) würde es so aussehen:\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip | Tipp\n\nDie Dokumentationsoberfläche interagiert mit dem von Ihnen ausgewählten Server.\n\n///\n\n/// note | Technische Details\n\nDie Eigenschaft `servers` in der OpenAPI-Spezifikation ist optional.\n\nWenn Sie den Parameter `servers` nicht angeben und `root_path` den Wert `/` hat, wird die Eigenschaft `servers` im generierten OpenAPI-Schema standardmäßig vollständig weggelassen, was dem Äquivalent eines einzelnen Servers mit einem `url`-Wert von `/` entspricht.\n\n///\n\n### Den automatischen Server von `root_path` deaktivieren { #disable-automatic-server-from-root-path }\n\nWenn Sie nicht möchten, dass **FastAPI** einen automatischen Server inkludiert, welcher `root_path` verwendet, können Sie den Parameter `root_path_in_servers=False` verwenden:\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\nDann wird er nicht in das OpenAPI-Schema aufgenommen.\n\n## Mounten einer Unteranwendung { #mounting-a-sub-application }\n\nWenn Sie gleichzeitig eine Unteranwendung mounten (wie beschrieben in [Unteranwendungen – Mounts](sub-applications.md)) und einen Proxy mit `root_path` verwenden wollen, können Sie das normal tun, wie Sie es erwarten würden.\n\nFastAPI verwendet intern den `root_path` auf intelligente Weise, sodass es einfach funktioniert. ✨\n"
  },
  {
    "path": "docs/de/docs/advanced/custom-response.md",
    "content": "# Benutzerdefinierte Response – HTML, Stream, Datei, andere { #custom-response-html-stream-file-others }\n\nStandardmäßig gibt **FastAPI** JSON-Responses zurück.\n\nSie können dies überschreiben, indem Sie direkt eine `Response` zurückgeben, wie in [Eine Response direkt zurückgeben](response-directly.md) gezeigt.\n\nWenn Sie jedoch direkt eine `Response` (oder eine Unterklasse wie `JSONResponse`) zurückgeben, werden die Daten nicht automatisch konvertiert (selbst wenn Sie ein `response_model` deklarieren), und die Dokumentation wird nicht automatisch generiert (zum Beispiel einschließlich des spezifischen „Medientyps“ im HTTP-Header `Content-Type` als Teil der generierten OpenAPI).\n\nSie können jedoch auch die `Response`, die Sie verwenden möchten (z. B. jede `Response`-Unterklasse), im *Pfadoperation-Dekorator* mit dem `response_class`-Parameter deklarieren.\n\nDer Inhalt, den Sie von Ihrer *Pfadoperation-Funktion* zurückgeben, wird in diese `Response` eingefügt.\n\n/// note | Hinweis\n\nWenn Sie eine Response-Klasse ohne Medientyp verwenden, erwartet FastAPI, dass Ihre Response keinen Inhalt hat, und dokumentiert daher das Format der Response nicht in deren generierter OpenAPI-Dokumentation.\n\n///\n\n## JSON-Responses { #json-responses }\n\nStandardmäßig gibt FastAPI JSON-Responses zurück.\n\nWenn Sie ein [Responsemodell](../tutorial/response-model.md) deklarieren, verwendet FastAPI Pydantic, um die Daten zu JSON zu serialisieren.\n\nWenn Sie kein Responsemodell deklarieren, verwendet FastAPI den `jsonable_encoder`, wie in [JSON-kompatibler Encoder](../tutorial/encoder.md) erklärt, und packt das Ergebnis in eine `JSONResponse`.\n\nWenn Sie eine `response_class` mit einem JSON-Medientyp (`application/json`) deklarieren, wie es bei `JSONResponse` der Fall ist, werden die von Ihnen zurückgegebenen Daten automatisch mit jedem Pydantic-`response_model` (das Sie im *Pfadoperation-Dekorator* deklariert haben) konvertiert (und gefiltert). Aber die Daten werden nicht mit Pydantic zu JSON-Bytes serialisiert, stattdessen werden sie mit dem `jsonable_encoder` konvertiert und anschließend an die `JSONResponse`-Klasse übergeben, die sie dann mit der Standard-JSON-Bibliothek in Python in Bytes serialisiert.\n\n### JSON-Leistung { #json-performance }\n\nKurz gesagt: Wenn Sie die maximale Leistung möchten, verwenden Sie ein [Responsemodell](../tutorial/response-model.md) und deklarieren Sie keine `response_class` im *Pfadoperation-Dekorator*.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## HTML-Response { #html-response }\n\nUm eine Response mit HTML direkt von **FastAPI** zurückzugeben, verwenden Sie `HTMLResponse`.\n\n* Importieren Sie `HTMLResponse`.\n* Übergeben Sie `HTMLResponse` als den Parameter `response_class` Ihres *Pfadoperation-Dekorators*.\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info | Info\n\nDer Parameter `response_class` wird auch verwendet, um den „Medientyp“ der Response zu definieren.\n\nIn diesem Fall wird der HTTP-Header `Content-Type` auf `text/html` gesetzt.\n\nUnd er wird als solcher in OpenAPI dokumentiert.\n\n///\n\n### Eine `Response` zurückgeben { #return-a-response }\n\nWie in [Eine Response direkt zurückgeben](response-directly.md) gezeigt, können Sie die Response auch direkt in Ihrer *Pfadoperation* überschreiben, indem Sie diese zurückgeben.\n\nDas gleiche Beispiel von oben, das eine `HTMLResponse` zurückgibt, könnte so aussehen:\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning | Achtung\n\nEine `Response`, die direkt von Ihrer *Pfadoperation-Funktion* zurückgegeben wird, wird in OpenAPI nicht dokumentiert (zum Beispiel wird der `Content-Type` nicht dokumentiert) und ist in der automatischen interaktiven Dokumentation nicht sichtbar.\n\n///\n\n/// info | Info\n\nNatürlich stammen der eigentliche `Content-Type`-Header, der Statuscode, usw., aus dem `Response`-Objekt, das Sie zurückgegeben haben.\n\n///\n\n### In OpenAPI dokumentieren und `Response` überschreiben { #document-in-openapi-and-override-response }\n\nWenn Sie die Response innerhalb der Funktion überschreiben und gleichzeitig den „Medientyp“ in OpenAPI dokumentieren möchten, können Sie den `response_class`-Parameter verwenden UND ein `Response`-Objekt zurückgeben.\n\nDie `response_class` wird dann nur zur Dokumentation der OpenAPI-*Pfadoperation* verwendet, Ihre `Response` wird jedoch unverändert verwendet.\n\n#### Eine `HTMLResponse` direkt zurückgeben { #return-an-htmlresponse-directly }\n\nEs könnte zum Beispiel so etwas sein:\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\nIn diesem Beispiel generiert die Funktion `generate_html_response()` bereits eine `Response` und gibt sie zurück, anstatt das HTML in einem `str` zurückzugeben.\n\nIndem Sie das Ergebnis des Aufrufs von `generate_html_response()` zurückgeben, geben Sie bereits eine `Response` zurück, die das Standardverhalten von **FastAPI** überschreibt.\n\nAber da Sie die `HTMLResponse` auch in der `response_class` übergeben haben, weiß **FastAPI**, dass sie in OpenAPI und der interaktiven Dokumentation als HTML mit `text/html` zu dokumentieren ist:\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## Verfügbare Responses { #available-responses }\n\nHier sind einige der verfügbaren Responses.\n\nBedenken Sie, dass Sie `Response` verwenden können, um alles andere zurückzugeben, oder sogar eine benutzerdefinierte Unterklasse zu erstellen.\n\n/// note | Technische Details\n\nSie können auch `from starlette.responses import HTMLResponse` verwenden.\n\n**FastAPI** bietet dieselben `starlette.responses` auch via `fastapi.responses` an, als Annehmlichkeit für Sie, den Entwickler. Die meisten verfügbaren Responses kommen aber direkt von Starlette.\n\n///\n\n### `Response` { #response }\n\nDie Hauptklasse `Response`, alle anderen Responses erben von ihr.\n\nSie können sie direkt zurückgeben.\n\nSie akzeptiert die folgenden Parameter:\n\n* `content` – Ein `str` oder `bytes`.\n* `status_code` – Ein `int`-HTTP-Statuscode.\n* `headers` – Ein `dict` von Strings.\n* `media_type` – Ein `str`, der den Medientyp angibt. Z. B. `\"text/html\"`.\n\nFastAPI (eigentlich Starlette) fügt automatisch einen Content-Length-Header ein. Außerdem wird es einen Content-Type-Header einfügen, der auf dem `media_type` basiert, und für Texttypen einen Zeichensatz (charset) anfügen.\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\nNimmt Text oder Bytes entgegen und gibt eine HTML-Response zurück, wie Sie oben gelesen haben.\n\n### `PlainTextResponse` { #plaintextresponse }\n\nNimmt Text oder Bytes entgegen und gibt eine Plain-Text-Response zurück.\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\nNimmt einige Daten entgegen und gibt eine `application/json`-codierte Response zurück.\n\nDies ist die Standard-Response, die in **FastAPI** verwendet wird, wie Sie oben gelesen haben.\n\n/// note | Technische Details\n\nWenn Sie jedoch ein Responsemodell oder einen Rückgabetyp deklarieren, wird dieser direkt verwendet, um die Daten zu JSON zu serialisieren, und eine Response mit dem richtigen Medientyp für JSON wird direkt zurückgegeben, ohne die `JSONResponse`-Klasse zu verwenden.\n\nDies ist der ideale Weg, um die beste Leistung zu erzielen.\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\nGibt eine HTTP-Weiterleitung (HTTP-Redirect) zurück. Verwendet standardmäßig den Statuscode 307 – Temporäre Weiterleitung (Temporary Redirect).\n\nSie können eine `RedirectResponse` direkt zurückgeben:\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\nOder Sie können sie im Parameter `response_class` verwenden:\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\nWenn Sie das tun, können Sie die URL direkt von Ihrer *Pfadoperation*-Funktion zurückgeben.\n\nIn diesem Fall ist der verwendete `status_code` der Standardcode für die `RedirectResponse`, also `307`.\n\n---\n\nSie können den Parameter `status_code` auch in Kombination mit dem Parameter `response_class` verwenden:\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\nNimmt einen asynchronen Generator oder einen normalen Generator/Iterator (eine Funktion mit `yield`) und streamt den Responsebody.\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | Technische Details\n\nEin `async`-Task kann nur abgebrochen werden, wenn er ein `await` erreicht. Wenn es kein `await` gibt, kann der Generator (Funktion mit `yield`) nicht ordnungsgemäß abgebrochen werden und könnte weiterlaufen, selbst nachdem der Abbruch angefordert wurde.\n\nDa dieses kleine Beispiel keine `await`-Anweisungen benötigt, fügen wir ein `await anyio.sleep(0)` hinzu, um dem Event Loop die Chance zu geben, den Abbruch zu verarbeiten.\n\nDies wäre bei großen oder unendlichen Streams noch wichtiger.\n\n///\n\n/// tip | Tipp\n\nAnstatt eine `StreamingResponse` direkt zurückzugeben, sollten Sie wahrscheinlich dem Stil in [Daten streamen](./stream-data.md) folgen. Das ist wesentlich bequemer und behandelt den Abbruch im Hintergrund für Sie.\n\nWenn Sie JSON Lines streamen, folgen Sie dem Tutorial [JSON Lines streamen](../tutorial/stream-json-lines.md).\n\n///\n\n### `FileResponse` { #fileresponse }\n\nStreamt eine Datei asynchron als Response.\n\nNimmt zur Instanziierung einen anderen Satz von Argumenten entgegen als die anderen Response-Typen:\n\n* `path` – Der Dateipfad zur Datei, die gestreamt werden soll.\n* `headers` – Alle benutzerdefinierten Header, die inkludiert werden sollen, als Dictionary.\n* `media_type` – Ein String, der den Medientyp angibt. Wenn nicht gesetzt, wird der Dateiname oder Pfad verwendet, um auf einen Medientyp zu schließen.\n* `filename` – Wenn gesetzt, wird das in der `Content-Disposition` der Response eingefügt.\n\nDatei-Responses enthalten die entsprechenden `Content-Length`-, `Last-Modified`- und `ETag`-Header.\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\nSie können auch den Parameter `response_class` verwenden:\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\nIn diesem Fall können Sie den Dateipfad direkt von Ihrer *Pfadoperation*-Funktion zurückgeben.\n\n## Benutzerdefinierte Response-Klasse { #custom-response-class }\n\nSie können Ihre eigene benutzerdefinierte Response-Klasse erstellen, die von `Response` erbt und diese verwendet.\n\nNehmen wir zum Beispiel an, dass Sie [`orjson`](https://github.com/ijl/orjson) mit einigen Einstellungen verwenden möchten.\n\nSie möchten etwa, dass Ihre Response eingerücktes und formatiertes JSON zurückgibt. Dafür möchten Sie die orjson-Option `orjson.OPT_INDENT_2` verwenden.\n\nSie könnten eine `CustomORJSONResponse` erstellen. Das Wichtigste, was Sie tun müssen, ist, eine `Response.render(content)`-Methode zu erstellen, die den Inhalt als `bytes` zurückgibt:\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\nAnstatt Folgendes zurückzugeben:\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n... wird diese Response Folgendes zurückgeben:\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\nNatürlich werden Sie wahrscheinlich viel bessere Möglichkeiten finden, Vorteil daraus zu ziehen, als JSON zu formatieren. 😉\n\n### `orjson` oder Responsemodell { #orjson-or-response-model }\n\nWenn es Ihnen um Leistung geht, sind Sie wahrscheinlich mit einem [Responsemodell](../tutorial/response-model.md) besser beraten als mit einer `orjson`-Response.\n\nMit einem Responsemodell verwendet FastAPI Pydantic, um die Daten ohne Zwischenschritte zu JSON zu serialisieren, also ohne sie z. B. erst mit `jsonable_encoder` zu konvertieren, was sonst der Fall wäre.\n\nUnd unter der Haube verwendet Pydantic dieselben Rust-Mechanismen wie `orjson`, um nach JSON zu serialisieren. Sie erhalten mit einem Responsemodell also ohnehin die beste Leistung.\n\n## Standard-Response-Klasse { #default-response-class }\n\nBeim Erstellen einer **FastAPI**-Klasseninstanz oder eines `APIRouter`s können Sie angeben, welche Response-Klasse standardmäßig verwendet werden soll.\n\nDer Parameter, der das definiert, ist `default_response_class`.\n\nIm folgenden Beispiel verwendet **FastAPI** standardmäßig `HTMLResponse` in allen *Pfadoperationen*, anstelle von JSON.\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip | Tipp\n\nSie können dennoch weiterhin `response_class` in *Pfadoperationen* überschreiben, wie bisher.\n\n///\n\n## Zusätzliche Dokumentation { #additional-documentation }\n\nSie können auch den Medientyp und viele andere Details in OpenAPI mit `responses` deklarieren: [Zusätzliche Responses in OpenAPI](additional-responses.md).\n"
  },
  {
    "path": "docs/de/docs/advanced/dataclasses.md",
    "content": "# Datenklassen verwenden { #using-dataclasses }\n\nFastAPI basiert auf **Pydantic**, und ich habe Ihnen gezeigt, wie Sie Pydantic-Modelle verwenden können, um <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> und <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Responses</abbr> zu deklarieren.\n\nAber FastAPI unterstützt auf die gleiche Weise auch die Verwendung von [`dataclasses`](https://docs.python.org/3/library/dataclasses.html):\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\nDas ist dank **Pydantic** ebenfalls möglich, da es [„`dataclasses` intern unterstützt“](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).\n\nAuch wenn im obigen Code Pydantic nicht explizit vorkommt, verwendet FastAPI Pydantic, um diese Standard-Datenklassen in Pydantics eigene Variante von Datenklassen zu konvertieren.\n\nUnd natürlich wird das gleiche unterstützt:\n\n* Datenvalidierung\n* Datenserialisierung\n* Datendokumentation, usw.\n\nDas funktioniert genauso wie mit Pydantic-Modellen. Und tatsächlich wird es unter der Haube mittels Pydantic auf die gleiche Weise bewerkstelligt.\n\n/// info | Info\n\nBedenken Sie, dass Datenklassen nicht alles können, was Pydantic-Modelle können.\n\nDaher müssen Sie möglicherweise weiterhin Pydantic-Modelle verwenden.\n\nWenn Sie jedoch eine Menge Datenklassen herumliegen haben, ist dies ein guter Trick, um sie für eine Web-API mithilfe von FastAPI zu verwenden. 🤓\n\n///\n\n## Datenklassen in `response_model` { #dataclasses-in-response-model }\n\nSie können `dataclasses` auch im Parameter `response_model` verwenden:\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\nDie Datenklasse wird automatisch in eine Pydantic-Datenklasse konvertiert.\n\nAuf diese Weise wird deren Schema in der Benutzeroberfläche der API-Dokumentation angezeigt:\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## Datenklassen in verschachtelten Datenstrukturen { #dataclasses-in-nested-data-structures }\n\nSie können `dataclasses` auch mit anderen Typannotationen kombinieren, um verschachtelte Datenstrukturen zu erstellen.\n\nIn einigen Fällen müssen Sie möglicherweise immer noch Pydantics Version von `dataclasses` verwenden. Zum Beispiel, wenn Sie Fehler in der automatisch generierten API-Dokumentation haben.\n\nIn diesem Fall können Sie einfach die Standard-`dataclasses` durch `pydantic.dataclasses` ersetzen, was einen direkten Ersatz darstellt:\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. Wir importieren `field` weiterhin von Standard-`dataclasses`.\n\n2. `pydantic.dataclasses` ist ein direkter Ersatz für `dataclasses`.\n\n3. Die Datenklasse `Author` enthält eine Liste von `Item`-Datenklassen.\n\n4. Die Datenklasse `Author` wird im `response_model`-Parameter verwendet.\n\n5. Sie können andere Standard-Typannotationen mit Datenklassen als Requestbody verwenden.\n\n    In diesem Fall handelt es sich um eine Liste von `Item`-Datenklassen.\n\n6. Hier geben wir ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">Dictionary</abbr> zurück, das `items` enthält, welches eine Liste von Datenklassen ist.\n\n    FastAPI ist weiterhin in der Lage, die Daten nach JSON zu <dfn title=\"Konvertieren der Daten in ein übertragbares Format\">Serialisieren</dfn>.\n\n7. Hier verwendet das `response_model` als Typannotation eine Liste von `Author`-Datenklassen.\n\n    Auch hier können Sie `dataclasses` mit Standard-Typannotationen kombinieren.\n\n8. Beachten Sie, dass diese *Pfadoperation-Funktion* reguläres `def` anstelle von `async def` verwendet.\n\n    Wie immer können Sie in FastAPI `def` und `async def` beliebig kombinieren.\n\n    Wenn Sie eine Auffrischung darüber benötigen, wann welche Anwendung sinnvoll ist, lesen Sie den Abschnitt „In Eile?“ in der Dokumentation zu [`async` und `await`](../async.md#in-a-hurry).\n\n9. Diese *Pfadoperation-Funktion* gibt keine Datenklassen zurück (obwohl dies möglich wäre), sondern eine Liste von Dictionarys mit internen Daten.\n\n    FastAPI verwendet den Parameter `response_model` (der Datenklassen enthält), um die Response zu konvertieren.\n\nSie können `dataclasses` mit anderen Typannotationen auf vielfältige Weise kombinieren, um komplexe Datenstrukturen zu bilden.\n\nWeitere Einzelheiten finden Sie in den Bemerkungen im Quellcode oben.\n\n## Mehr erfahren { #learn-more }\n\nSie können `dataclasses` auch mit anderen Pydantic-Modellen kombinieren, von ihnen erben, sie in Ihre eigenen Modelle einbinden, usw.\n\nWeitere Informationen finden Sie in der [Pydantic-Dokumentation zu Datenklassen](https://docs.pydantic.dev/latest/concepts/dataclasses/).\n\n## Version { #version }\n\nDies ist verfügbar seit FastAPI-Version `0.67.0`. 🔖\n"
  },
  {
    "path": "docs/de/docs/advanced/events.md",
    "content": "# Lifespan-Events { #lifespan-events }\n\nSie können Logik (Code) definieren, die ausgeführt werden soll, bevor die Anwendung **hochfährt**. Dies bedeutet, dass dieser Code **einmal** ausgeführt wird, **bevor** die Anwendung **beginnt, <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> entgegenzunehmen**.\n\nAuf die gleiche Weise können Sie Logik (Code) definieren, die ausgeführt werden soll, wenn die Anwendung **heruntergefahren** wird. In diesem Fall wird dieser Code **einmal** ausgeführt, **nachdem** möglicherweise **viele Requests** bearbeitet wurden.\n\nDa dieser Code ausgeführt wird, bevor die Anwendung **beginnt**, Requests entgegenzunehmen, und unmittelbar, nachdem sie die Bearbeitung von Requests **abgeschlossen hat**, deckt er den gesamten Anwendungs-<abbr title=\"Lebensdauer\">**Lifespan**</abbr> ab (das Wort „Lifespan“ wird gleich wichtig sein 😉).\n\nDies kann sehr nützlich sein, um **Ressourcen** einzurichten, die Sie in der gesamten App verwenden wollen und die von Requests **gemeinsam genutzt** werden und/oder die Sie anschließend **aufräumen** müssen. Zum Beispiel ein Pool von Datenbankverbindungen oder das Laden eines gemeinsam genutzten Modells für maschinelles Lernen.\n\n## Anwendungsfall { #use-case }\n\nBeginnen wir mit einem Beispiel-**Anwendungsfall** und schauen uns dann an, wie wir ihn mit dieser Methode implementieren können.\n\nStellen wir uns vor, Sie verfügen über einige **Modelle für maschinelles Lernen**, die Sie zur Bearbeitung von Requests verwenden möchten. 🤖\n\nDie gleichen Modelle werden von den Requests gemeinsam genutzt, es handelt sich also nicht um ein Modell pro Request, pro Benutzer, oder ähnliches.\n\nStellen wir uns vor, dass das Laden des Modells **eine ganze Weile dauern** kann, da viele **Daten von der Festplatte** gelesen werden müssen. Sie möchten das also nicht für jeden Request tun.\n\nSie könnten das auf der obersten Ebene des Moduls/der Datei machen, aber das würde auch bedeuten, dass **das Modell geladen wird**, selbst wenn Sie nur einen einfachen automatisierten Test ausführen, dann wäre dieser Test **langsam**, weil er warten müsste, bis das Modell geladen ist, bevor er einen davon unabhängigen Teil des Codes ausführen könnte.\n\nDas wollen wir besser machen: Laden wir das Modell, bevor die Requests bearbeitet werden, aber unmittelbar bevor die Anwendung beginnt, Requests zu empfangen, und nicht, während der Code geladen wird.\n\n## Lifespan { #lifespan }\n\nSie können diese Logik beim <abbr title=\"Hochfahren\">*Startup*</abbr> und <abbr title=\"Herunterfahren\">*Shutdown*</abbr> mithilfe des `lifespan`-Parameters der `FastAPI`-App und eines „Kontextmanagers“ definieren (ich zeige Ihnen gleich, was das ist).\n\nBeginnen wir mit einem Beispiel und sehen es uns dann im Detail an.\n\nWir erstellen eine asynchrone Funktion `lifespan()` mit `yield` wie folgt:\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\nHier simulieren wir den langsamen *Startup*, das Laden des Modells, indem wir die (Fake-)Modellfunktion vor dem `yield` in das <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">Dictionary</abbr> mit Modellen für maschinelles Lernen einfügen. Dieser Code wird ausgeführt, **bevor** die Anwendung **beginnt, Requests entgegenzunehmen**, während des *Startups*.\n\nUnd dann, direkt nach dem `yield`, entladen wir das Modell. Dieser Code wird ausgeführt, **nachdem** die Anwendung **die Bearbeitung von Requests abgeschlossen hat**, direkt vor dem *Shutdown*. Dadurch könnten beispielsweise Ressourcen wie Arbeitsspeicher oder eine GPU freigegeben werden.\n\n/// tip | Tipp\n\nDas `shutdown` würde erfolgen, wenn Sie die Anwendung **stoppen**.\n\nMöglicherweise müssen Sie eine neue Version starten, oder Sie haben es einfach satt, sie auszuführen. 🤷\n\n///\n\n### Lifespan-Funktion { #lifespan-function }\n\nDas Erste, was auffällt, ist, dass wir eine asynchrone Funktion mit `yield` definieren. Das ist sehr ähnlich zu Abhängigkeiten mit `yield`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\nDer erste Teil der Funktion, vor dem `yield`, wird ausgeführt **bevor** die Anwendung startet.\n\nUnd der Teil nach `yield` wird ausgeführt, **nachdem** die Anwendung beendet ist.\n\n### Asynchroner Kontextmanager { #async-context-manager }\n\nWie Sie sehen, ist die Funktion mit einem `@asynccontextmanager` versehen.\n\nDadurch wird die Funktion in einen sogenannten „**asynchronen Kontextmanager**“ umgewandelt.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\nEin **Kontextmanager** in Python ist etwas, das Sie in einer `with`-Anweisung verwenden können, zum Beispiel kann `open()` als Kontextmanager verwendet werden:\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\nIn neueren Versionen von Python gibt es auch einen **asynchronen Kontextmanager**. Sie würden ihn mit `async with` verwenden:\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\nWenn Sie wie oben einen Kontextmanager oder einen asynchronen Kontextmanager erstellen, führt dieser vor dem Betreten des `with`-Blocks den Code vor dem `yield` aus, und nach dem Verlassen des `with`-Blocks wird er den Code nach dem `yield` ausführen.\n\nIn unserem obigen Codebeispiel verwenden wir ihn nicht direkt, sondern übergeben ihn an FastAPI, damit es ihn verwenden kann.\n\nDer Parameter `lifespan` der `FastAPI`-App benötigt einen **asynchronen Kontextmanager**, wir können ihm also unseren neuen asynchronen Kontextmanager `lifespan` übergeben.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## Alternative Events (<abbr title=\"veraltet, obsolet: Es soll nicht mehr verwendet werden\">deprecatet</abbr>) { #alternative-events-deprecated }\n\n/// warning | Achtung\n\nDer empfohlene Weg, den *Startup* und *Shutdown* zu handhaben, ist die Verwendung des `lifespan`-Parameters der `FastAPI`-App, wie oben beschrieben. Wenn Sie einen `lifespan`-Parameter übergeben, werden die `startup`- und `shutdown`-Eventhandler nicht mehr aufgerufen. Es ist entweder alles `lifespan` oder alles Events, nicht beides.\n\nSie können diesen Teil wahrscheinlich überspringen.\n\n///\n\nEs gibt eine alternative Möglichkeit, diese Logik zu definieren, sodass sie beim *Startup* und beim *Shutdown* ausgeführt wird.\n\nSie können <abbr title=\"Eventhandler – Ereignisbehandler: Funktion, die beim Eintreten eines bestimmten Ereignisses ausgeführt wird\">Eventhandler</abbr> (Funktionen) definieren, die ausgeführt werden sollen, bevor die Anwendung hochgefahren wird oder wenn die Anwendung heruntergefahren wird.\n\nDiese Funktionen können mit `async def` oder normalem `def` deklariert werden.\n\n### `startup`-Event { #startup-event }\n\nUm eine Funktion hinzuzufügen, die vor dem Start der Anwendung ausgeführt werden soll, deklarieren Sie diese mit dem Event `startup`:\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\nIn diesem Fall initialisiert die Eventhandler-Funktion `startup` die „Datenbank“ der Items (nur ein `dict`) mit einigen Werten.\n\nSie können mehr als eine Eventhandler-Funktion hinzufügen.\n\nUnd Ihre Anwendung empfängt erst dann Requests, wenn alle `startup`-Eventhandler abgeschlossen sind.\n\n### `shutdown`-Event { #shutdown-event }\n\nUm eine Funktion hinzuzufügen, die beim Shutdown der Anwendung ausgeführt werden soll, deklarieren Sie sie mit dem Event `shutdown`:\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\nHier schreibt die `shutdown`-Eventhandler-Funktion eine Textzeile `\"Application shutdown\"` in eine Datei `log.txt`.\n\n/// info | Info\n\nIn der Funktion `open()` bedeutet `mode=\"a\"` „append“ („anhängen“), sodass die Zeile nach dem, was sich in dieser Datei befindet, hinzugefügt wird, ohne den vorherigen Inhalt zu überschreiben.\n\n///\n\n/// tip | Tipp\n\nBeachten Sie, dass wir in diesem Fall eine Standard-Python-Funktion `open()` verwenden, die mit einer Datei interagiert.\n\nEs handelt sich also um I/O (Input/Output), welches „Warten“ erfordert, bis Dinge auf die Festplatte geschrieben werden.\n\nAber `open()` verwendet nicht `async` und `await`.\n\nDaher deklarieren wir die Eventhandler-Funktion mit Standard-`def` statt mit `async def`.\n\n///\n\n### `startup` und `shutdown` zusammen { #startup-and-shutdown-together }\n\nEs besteht eine hohe Wahrscheinlichkeit, dass die Logik für Ihr *Startup* und *Shutdown* miteinander verknüpft ist. Vielleicht möchten Sie etwas beginnen und es dann beenden, eine Ressource laden und sie dann freigeben usw.\n\nBei getrennten Funktionen, die keine gemeinsame Logik oder Variablen haben, ist dies schwieriger, da Sie Werte in globalen Variablen speichern oder ähnliche Tricks verwenden müssen.\n\nAus diesem Grund wird jetzt empfohlen, stattdessen `lifespan` wie oben erläutert zu verwenden.\n\n## Technische Details { #technical-details }\n\nNur ein technisches Detail für die neugierigen Nerds. 🤓\n\nIn der technischen ASGI-Spezifikation ist dies Teil des [Lifespan Protokolls](https://asgi.readthedocs.io/en/latest/specs/lifespan.html) und definiert Events namens `startup` und `shutdown`.\n\n/// info | Info\n\nWeitere Informationen zu Starlettes `lifespan`-Handlern finden Sie in [Starlettes Lifespan-Dokumentation](https://www.starlette.dev/lifespan/).\n\nEinschließlich, wie man Lifespan-Zustand handhabt, der in anderen Bereichen Ihres Codes verwendet werden kann.\n\n///\n\n## Unteranwendungen { #sub-applications }\n\n🚨 Beachten Sie, dass diese Lifespan-Events (Startup und Shutdown) nur für die Hauptanwendung ausgeführt werden, nicht für [Unteranwendungen – Mounts](sub-applications.md).\n"
  },
  {
    "path": "docs/de/docs/advanced/generate-clients.md",
    "content": "# SDKs generieren { #generating-sdks }\n\nDa **FastAPI** auf der **OpenAPI**-Spezifikation basiert, können dessen APIs in einem standardisierten Format beschrieben werden, das viele Tools verstehen.\n\nDies vereinfacht es, aktuelle **Dokumentation** und Client-Bibliotheken (<abbr title=\"Software Development Kits - Software-Entwicklungspakete\">**SDKs**</abbr>) in verschiedenen Sprachen zu generieren sowie **Test-** oder **Automatisierungs-Workflows**, die mit Ihrem Code synchron bleiben.\n\nIn diesem Leitfaden erfahren Sie, wie Sie ein **TypeScript-SDK** für Ihr FastAPI-Backend generieren.\n\n## Open Source SDK-Generatoren { #open-source-sdk-generators }\n\nEine vielseitige Möglichkeit ist der [OpenAPI Generator](https://openapi-generator.tech/), der **viele Programmiersprachen** unterstützt und SDKs aus Ihrer OpenAPI-Spezifikation generieren kann.\n\nFür **TypeScript-Clients** ist [Hey API](https://heyapi.dev/) eine speziell entwickelte Lösung, die ein optimiertes Erlebnis für das TypeScript-Ökosystem bietet.\n\nWeitere SDK-Generatoren finden Sie auf [OpenAPI.Tools](https://openapi.tools/#sdk).\n\n/// tip | Tipp\n\nFastAPI generiert automatisch **OpenAPI 3.1**-Spezifikationen, daher muss jedes von Ihnen verwendete Tool diese Version unterstützen.\n\n///\n\n## SDK-Generatoren von FastAPI-Sponsoren { #sdk-generators-from-fastapi-sponsors }\n\nDieser Abschnitt hebt **venture-unterstützte** und **firmengestützte** Lösungen hervor, die von Unternehmen entwickelt werden, welche FastAPI sponsern. Diese Produkte bieten **zusätzliche Funktionen** und **Integrationen** zusätzlich zu hochwertig generierten SDKs.\n\nDurch das ✨ [**Sponsoring von FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ helfen diese Unternehmen sicherzustellen, dass das Framework und sein **Ökosystem** gesund und **nachhaltig** bleiben.\n\nIhr Sponsoring zeigt auch ein starkes Engagement für die FastAPI-**Community** (Sie), was bedeutet, dass sie nicht nur einen **großartigen Service** bieten möchten, sondern auch ein **robustes und florierendes Framework**, FastAPI, unterstützen möchten. 🙇\n\nZum Beispiel könnten Sie ausprobieren:\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\nEinige dieser Lösungen sind möglicherweise auch Open Source oder bieten kostenlose Tarife an, sodass Sie diese ohne finanzielle Verpflichtung ausprobieren können. Andere kommerzielle SDK-Generatoren sind online verfügbar und können dort gefunden werden. 🤓\n\n## Ein TypeScript-SDK erstellen { #create-a-typescript-sdk }\n\nBeginnen wir mit einer einfachen FastAPI-Anwendung:\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\nBeachten Sie, dass die *Pfadoperationen* die Modelle definieren, die sie für die <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr>- und <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>-<abbr title=\"Die eigentlichen Nutzdaten, abzüglich der Metadaten\">Payload</abbr> verwenden, indem sie die Modelle `Item` und `ResponseMessage` verwenden.\n\n### API-Dokumentation { #api-docs }\n\nWenn Sie zu `/docs` gehen, sehen Sie, dass es die **Schemas** für die Daten enthält, die in Requests gesendet und in Responses empfangen werden:\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\nSie können diese Schemas sehen, da sie mit den Modellen in der App deklariert wurden.\n\nDiese Informationen sind im **OpenAPI-Schema** der Anwendung verfügbar und werden in der API-Dokumentation angezeigt.\n\nDiese Informationen aus den Modellen, die in OpenAPI enthalten sind, können verwendet werden, um **den Client-Code zu generieren**.\n\n### Hey API { #hey-api }\n\nSobald wir eine FastAPI-App mit den Modellen haben, können wir Hey API verwenden, um einen TypeScript-Client zu generieren. Der schnellste Weg das zu tun, ist über npx.\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\nDies generiert ein TypeScript-SDK in `./src/client`.\n\nSie können lernen, wie man [`@hey-api/openapi-ts` installiert](https://heyapi.dev/openapi-ts/get-started) und über die [erzeugte Ausgabe](https://heyapi.dev/openapi-ts/output) auf deren Website lesen.\n\n### Das SDK verwenden { #using-the-sdk }\n\nJetzt können Sie den Client-Code importieren und verwenden. Er könnte wie folgt aussehen, beachten Sie, dass Sie eine automatische Vervollständigung für die Methoden erhalten:\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\nSie werden auch eine automatische Vervollständigung für die zu sendende Payload erhalten:\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip | Tipp\n\nBeachten Sie die automatische Vervollständigung für `name` und `price`, die in der FastAPI-Anwendung im `Item`-Modell definiert wurden.\n\n///\n\nSie erhalten Inline-Fehlerberichte für die von Ihnen gesendeten Daten:\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\nDas Response-Objekt hat auch automatische Vervollständigung:\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## FastAPI-Anwendung mit Tags { #fastapi-app-with-tags }\n\nIn vielen Fällen wird Ihre FastAPI-App größer sein und Sie werden wahrscheinlich Tags verwenden, um verschiedene Gruppen von *Pfadoperationen* zu separieren.\n\nZum Beispiel könnten Sie einen Abschnitt für **Items** und einen weiteren Abschnitt für **Users** haben, und diese könnten durch Tags getrennt sein:\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### Einen TypeScript-Client mit Tags generieren { #generate-a-typescript-client-with-tags }\n\nWenn Sie einen Client für eine FastAPI-App generieren, die Tags verwendet, wird normalerweise der Client-Code auch anhand der Tags getrennt.\n\nAuf diese Weise können Sie die Dinge für den Client-Code richtig ordnen und gruppieren:\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\nIn diesem Fall haben Sie:\n\n* `ItemsService`\n* `UsersService`\n\n### Client-Methodennamen { #client-method-names }\n\nIm Moment sehen die generierten Methodennamen wie `createItemItemsPost` nicht sehr sauber aus:\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n... das liegt daran, dass der Client-Generator für jede *Pfadoperation* die OpenAPI-interne **Operation-ID** verwendet.\n\nOpenAPI erfordert, dass jede Operation-ID innerhalb aller *Pfadoperationen* einzigartig ist. Daher verwendet FastAPI den **Funktionsnamen**, den **Pfad** und die **HTTP-Methode/-Operation**, um diese Operation-ID zu generieren. Denn so kann sichergestellt werden, dass die Operation-IDs einzigartig sind.\n\nAber ich zeige Ihnen als Nächstes, wie Sie das verbessern können. 🤓\n\n## Benutzerdefinierte Operation-IDs und bessere Methodennamen { #custom-operation-ids-and-better-method-names }\n\nSie können die Art und Weise, wie diese Operation-IDs **generiert** werden, **ändern**, um sie einfacher zu machen und **einfachere Methodennamen** in den Clients zu haben.\n\nIn diesem Fall müssen Sie auf andere Weise sicherstellen, dass jede Operation-ID **einzigartig** ist.\n\nZum Beispiel könnten Sie sicherstellen, dass jede *Pfadoperation* einen Tag hat, und dann die Operation-ID basierend auf dem **Tag** und dem *Pfadoperation*-**Namen** (dem Funktionsnamen) generieren.\n\n### Eine benutzerdefinierte Funktion zur Erzeugung einer eindeutigen ID erstellen { #custom-generate-unique-id-function }\n\nFastAPI verwendet eine **eindeutige ID** für jede *Pfadoperation*, die für die **Operation-ID** und auch für die Namen aller benötigten benutzerdefinierten Modelle für Requests oder Responses verwendet wird.\n\nSie können diese Funktion anpassen. Sie nimmt ein `APIRoute` und gibt einen String zurück.\n\nHier verwendet sie beispielsweise den ersten Tag (Sie werden wahrscheinlich nur einen Tag haben) und den *Pfadoperation*-Namen (den Funktionsnamen).\n\nAnschließend können Sie diese benutzerdefinierte Funktion als `generate_unique_id_function`-Parameter an **FastAPI** übergeben:\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### Einen TypeScript-Client mit benutzerdefinierten Operation-IDs generieren { #generate-a-typescript-client-with-custom-operation-ids }\n\nWenn Sie nun den Client erneut generieren, werden Sie feststellen, dass er über die verbesserten Methodennamen verfügt:\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\nWie Sie sehen, haben die Methodennamen jetzt den Tag und dann den Funktionsnamen, aber keine Informationen aus dem URL-Pfad und der HTTP-Operation.\n\n### Die OpenAPI-Spezifikation für den Client-Generator vorab modifizieren { #preprocess-the-openapi-specification-for-the-client-generator }\n\nDer generierte Code enthält immer noch einige **verdoppelte Informationen**.\n\nWir wissen bereits, dass diese Methode mit den **Items** zusammenhängt, weil dieses Wort in `ItemsService` enthalten ist (vom Tag übernommen), aber wir haben den Tag-Namen dennoch im Methodennamen vorangestellt. 😕\n\nWir werden das wahrscheinlich weiterhin für OpenAPI allgemein beibehalten wollen, da dadurch sichergestellt wird, dass die Operation-IDs **einzigartig** sind.\n\nAber für den generierten Client könnten wir die OpenAPI-Operation-IDs direkt vor der Generierung der Clients **modifizieren**, um diese Methodennamen schöner und **sauberer** zu machen.\n\nWir könnten das OpenAPI-JSON in eine Datei `openapi.json` herunterladen und dann mit einem Skript wie dem folgenden **den präfixierten Tag entfernen**:\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\nDamit würden die Operation-IDs von Dingen wie `items-get_items` in `get_items` umbenannt, sodass der Client-Generator einfachere Methodennamen generieren kann.\n\n### Einen TypeScript-Client mit der vorverarbeiteten OpenAPI generieren { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\nDa das Endergebnis nun in einer `openapi.json`-Datei vorliegt, müssen Sie Ihren Eingabeort aktualisieren:\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\nNach der Generierung des neuen Clients haben Sie jetzt **saubere Methodennamen**, mit allen **Autovervollständigungen**, **Inline-Fehlerberichten**, usw.:\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## Vorteile { #benefits }\n\nWenn Sie die automatisch generierten Clients verwenden, erhalten Sie **Autovervollständigung** für:\n\n* Methoden.\n* Request-Payloads im Body, Query-Parameter, usw.\n* Response-Payloads.\n\nSie erhalten auch **Inline-Fehlerberichte** für alles.\n\nUnd wann immer Sie den Backend-Code aktualisieren und **das Frontend neu generieren**, stehen alle neuen *Pfadoperationen* als Methoden zur Verfügung, die alten werden entfernt und alle anderen Änderungen werden im generierten Code reflektiert. 🤓\n\nDas bedeutet auch, dass, wenn sich etwas ändert, dies automatisch im Client-Code **reflektiert** wird. Und wenn Sie den Client **erstellen**, wird eine Fehlermeldung ausgegeben, wenn die verwendeten Daten **nicht übereinstimmen**.\n\nSie würden also **viele Fehler sehr früh** im Entwicklungszyklus erkennen, anstatt darauf warten zu müssen, dass die Fehler Ihren Endbenutzern in der Produktion angezeigt werden, und dann zu versuchen, zu debuggen, wo das Problem liegt. ✨\n"
  },
  {
    "path": "docs/de/docs/advanced/index.md",
    "content": "# Handbuch für fortgeschrittene Benutzer { #advanced-user-guide }\n\n## Zusatzfunktionen { #additional-features }\n\nDas Haupt-[Tutorial – Benutzerhandbuch](../tutorial/index.md) sollte ausreichen, um Ihnen einen Überblick über alle Hauptfunktionen von **FastAPI** zu geben.\n\nIn den nächsten Abschnitten sehen Sie weitere Optionen, Konfigurationen und zusätzliche Funktionen.\n\n/// tip | Tipp\n\nDie nächsten Abschnitte sind **nicht unbedingt „fortgeschritten“**.\n\nUnd es ist möglich, dass für Ihren Anwendungsfall die Lösung in einem davon liegt.\n\n///\n\n## Das Tutorial zuerst lesen { #read-the-tutorial-first }\n\nSie können immer noch die meisten Funktionen in **FastAPI** mit den Kenntnissen aus dem Haupt-[Tutorial – Benutzerhandbuch](../tutorial/index.md) nutzen.\n\nUnd die nächsten Abschnitte setzen voraus, dass Sie es bereits gelesen haben und dass Sie diese Hauptideen kennen.\n"
  },
  {
    "path": "docs/de/docs/advanced/json-base64-bytes.md",
    "content": "# JSON mit Bytes als base64 { #json-with-bytes-as-base64 }\n\nWenn Ihre App JSON-Daten empfangen und senden muss, Sie darin aber Binärdaten einschließen müssen, können Sie diese als base64 kodieren.\n\n## Base64 vs Dateien { #base64-vs-files }\n\nPrüfen Sie zunächst, ob Sie [Request Files](../tutorial/request-files.md) zum Hochladen von Binärdaten und [Benutzerdefinierte Response – FileResponse](./custom-response.md#fileresponse--fileresponse-) zum Senden von Binärdaten verwenden können, anstatt sie in JSON zu kodieren.\n\nJSON kann nur UTF-8-kodierte Strings enthalten, es kann daher keine rohen Bytes enthalten.\n\nBase64 kann Binärdaten in Strings kodieren, dafür werden jedoch mehr Zeichen benötigt als in den ursprünglichen Binärdaten; es ist daher in der Regel weniger effizient als der Umgang mit normalen Dateien.\n\nVerwenden Sie base64 nur, wenn Sie Binärdaten unbedingt in JSON einbetten müssen und dafür keine Dateien verwenden können.\n\n## Pydantic `bytes` { #pydantic-bytes }\n\nSie können ein Pydantic-Modell mit `bytes`-Feldern deklarieren und dann in der Modellkonfiguration `val_json_bytes` verwenden, um anzugeben, dass zur *Validierung* von eingehenden JSON-Daten base64 genutzt werden soll; im Rahmen dieser Validierung wird der base64-String in Bytes dekodiert.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\nWenn Sie die `/docs` aufrufen, zeigt die Dokumentation, dass das Feld `data` base64-kodierte Bytes erwartet:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\nSie könnten einen Request wie folgt senden:\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip | Tipp\n\n`aGVsbG8=` ist die base64-Kodierung von `hello`.\n\n///\n\nAnschließend dekodiert Pydantic den base64-String und stellt Ihnen die ursprünglichen Bytes im Feld `data` des Modells bereit.\n\nSie erhalten eine Response wie:\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## Pydantic `bytes` für Ausgabedaten { #pydantic-bytes-for-output-data }\n\nSie können in der Modellkonfiguration für Ausgabedaten auch `bytes`-Felder mit `ser_json_bytes` verwenden; Pydantic wird die Bytes bei der Erzeugung der JSON-Response als base64 *serialisieren*.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## Pydantic `bytes` für Eingabe- und Ausgabedaten { #pydantic-bytes-for-input-and-output-data }\n\nUnd selbstverständlich können Sie dasselbe Modell so konfigurieren, dass base64 sowohl für Eingaben (*validieren*) mit `val_json_bytes` als auch für Ausgaben (*serialisieren*) mit `ser_json_bytes` verwendet wird, wenn JSON-Daten empfangen und gesendet werden.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/de/docs/advanced/middleware.md",
    "content": "# Fortgeschrittene Middleware { #advanced-middleware }\n\nIm Haupttutorial haben Sie gelesen, wie Sie Ihrer Anwendung [benutzerdefinierte Middleware](../tutorial/middleware.md) hinzufügen können.\n\nUnd dann auch, wie man [CORS mittels der `CORSMiddleware`](../tutorial/cors.md) handhabt.\n\nIn diesem Abschnitt werden wir sehen, wie man andere Middlewares verwendet.\n\n## ASGI-Middleware hinzufügen { #adding-asgi-middlewares }\n\nDa **FastAPI** auf Starlette basiert und die <abbr title=\"Asynchrones Server-Gateway-Interface\">ASGI</abbr>-Spezifikation implementiert, können Sie jede ASGI-Middleware verwenden.\n\nEine Middleware muss nicht speziell für FastAPI oder Starlette gemacht sein, um zu funktionieren, solange sie der ASGI-Spezifikation genügt.\n\nIm Allgemeinen handelt es sich bei ASGI-Middleware um Klassen, die als erstes Argument eine ASGI-Anwendung erwarten.\n\nIn der Dokumentation für ASGI-Middlewares von Drittanbietern wird Ihnen wahrscheinlich gesagt, dass Sie etwa Folgendes tun sollen:\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\nAber FastAPI (eigentlich Starlette) bietet eine einfachere Möglichkeit, welche sicherstellt, dass die internen Middlewares zur Behandlung von Serverfehlern und benutzerdefinierten Exceptionhandlern ordnungsgemäß funktionieren.\n\nDazu verwenden Sie `app.add_middleware()` (wie schon im Beispiel für CORS gesehen).\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` empfängt eine Middleware-Klasse als erstes Argument und dann alle weiteren Argumente, die an die Middleware übergeben werden sollen.\n\n## Integrierte Middleware { #integrated-middlewares }\n\n**FastAPI** enthält mehrere Middlewares für gängige Anwendungsfälle. Wir werden als Nächstes sehen, wie man sie verwendet.\n\n/// note | Technische Details\n\nFür die nächsten Beispiele könnten Sie auch `from starlette.middleware.something import SomethingMiddleware` verwenden.\n\n**FastAPI** bietet mehrere Middlewares via `fastapi.middleware` an, als Annehmlichkeit für Sie, den Entwickler. Die meisten verfügbaren Middlewares kommen aber direkt von Starlette.\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\nErzwingt, dass alle eingehenden <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> entweder `https` oder `wss` sein müssen.\n\nAlle eingehenden Requests an `http` oder `ws` werden stattdessen an das sichere Schema umgeleitet.\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\nErzwingt, dass alle eingehenden Requests einen korrekt gesetzten `Host`-Header haben, um sich vor HTTP-Host-Header-Angriffen zu schützen.\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\nDie folgenden Argumente werden unterstützt:\n\n* `allowed_hosts` – Eine Liste von Domain-Namen, die als Hostnamen zulässig sein sollten. Wildcard-Domains wie `*.example.com` werden unterstützt, um Subdomains zu matchen. Um jeden Hostnamen zu erlauben, verwenden Sie entweder `allowed_hosts=[\"*\"]` oder lassen Sie diese Middleware weg.\n* `www_redirect` – Wenn auf True gesetzt, werden Requests an Nicht-www-Versionen der erlaubten Hosts zu deren www-Gegenstücken umgeleitet. Der Defaultwert ist `True`.\n\nWenn ein eingehender Request nicht korrekt validiert wird, wird eine `400`-<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> gesendet.\n\n## `GZipMiddleware` { #gzipmiddleware }\n\nVerarbeitet GZip-Responses für alle Requests, die „gzip“ im `Accept-Encoding`-Header enthalten.\n\nDiese Middleware verarbeitet sowohl Standard- als auch Streaming-Responses.\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\nDie folgenden Argumente werden unterstützt:\n\n* `minimum_size` – Responses, die kleiner als diese Mindestgröße in Bytes sind, nicht per GZip komprimieren. Der Defaultwert ist `500`.\n* `compresslevel` – Wird während der GZip-Kompression verwendet. Es ist ein Ganzzahlwert zwischen 1 und 9. Der Defaultwert ist `9`. Ein niedrigerer Wert resultiert in schnellerer Kompression, aber größeren Dateigrößen, während ein höherer Wert langsamere Kompression, aber kleinere Dateigrößen zur Folge hat.\n\n## Andere Middlewares { #other-middlewares }\n\nEs gibt viele andere ASGI-Middlewares.\n\nZum Beispiel:\n\n* [Uvicorns `ProxyHeadersMiddleware`](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n* [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\nUm mehr über weitere verfügbare Middlewares herauszufinden, besuchen Sie [Starlettes Middleware-Dokumentation](https://www.starlette.dev/middleware/) und die [ASGI Awesome List](https://github.com/florimondmanca/awesome-asgi).\n"
  },
  {
    "path": "docs/de/docs/advanced/openapi-callbacks.md",
    "content": "# OpenAPI-Callbacks { #openapi-callbacks }\n\nSie könnten eine API mit einer *Pfadoperation* erstellen, die einen <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> an eine *externe API* auslösen könnte, welche von jemand anderem erstellt wurde (wahrscheinlich derselbe Entwickler, der Ihre API *verwenden* würde).\n\nDer Vorgang, der stattfindet, wenn Ihre API-Anwendung die *externe API* aufruft, wird als <abbr title=\"„Rückruf“\">„Callback“</abbr> bezeichnet. Denn die Software, die der externe Entwickler geschrieben hat, sendet einen Request an Ihre API und dann *ruft Ihre API zurück* (*calls back*) und sendet einen Request an eine *externe API* (die wahrscheinlich vom selben Entwickler erstellt wurde).\n\nIn diesem Fall möchten Sie möglicherweise dokumentieren, wie diese externe API aussehen *sollte*. Welche *Pfadoperation* sie haben sollte, welchen Body sie erwarten sollte, welche <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> sie zurückgeben sollte, usw.\n\n## Eine Anwendung mit Callbacks { #an-app-with-callbacks }\n\nSehen wir uns das alles anhand eines Beispiels an.\n\nStellen Sie sich vor, Sie entwickeln eine Anwendung, mit der Sie Rechnungen erstellen können.\n\nDiese Rechnungen haben eine `id`, einen optionalen `title`, einen `customer` (Kunde) und ein `total` (Gesamtsumme).\n\nDer Benutzer Ihrer API (ein externer Entwickler) erstellt mit einem POST-Request eine Rechnung in Ihrer API.\n\nDann wird Ihre API (stellen wir uns vor):\n\n* die Rechnung an einen Kunden des externen Entwicklers senden.\n* das Geld einsammeln.\n* eine Benachrichtigung an den API-Benutzer (den externen Entwickler) zurücksenden.\n    * Dies erfolgt durch Senden eines POST-Requests (von *Ihrer API*) an eine *externe API*, die von diesem externen Entwickler bereitgestellt wird (das ist der „Callback“).\n\n## Die normale **FastAPI**-Anwendung { #the-normal-fastapi-app }\n\nSehen wir uns zunächst an, wie die normale API-Anwendung aussehen würde, bevor wir den Callback hinzufügen.\n\nSie verfügt über eine *Pfadoperation*, die einen `Invoice`-Body empfängt, und einen Query-Parameter `callback_url`, der die URL für den Callback enthält.\n\nDieser Teil ist ziemlich normal, der größte Teil des Codes ist Ihnen wahrscheinlich bereits bekannt:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip | Tipp\n\nDer Query-Parameter `callback_url` verwendet einen Pydantic-[Url](https://docs.pydantic.dev/latest/api/networks/)-Typ.\n\n///\n\nDas einzig Neue ist `callbacks=invoices_callback_router.routes` als Argument für den *Pfadoperation-Dekorator*. Wir werden als Nächstes sehen, was das ist.\n\n## Dokumentation des Callbacks { #documenting-the-callback }\n\nDer tatsächliche Callback-Code hängt stark von Ihrer eigenen API-Anwendung ab.\n\nUnd er wird wahrscheinlich von Anwendung zu Anwendung sehr unterschiedlich sein.\n\nEs könnten nur eine oder zwei Codezeilen sein, wie zum Beispiel:\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\nDer möglicherweise wichtigste Teil des Callbacks besteht jedoch darin, sicherzustellen, dass Ihr API-Benutzer (der externe Entwickler) die *externe API* korrekt implementiert, gemäß den Daten, die *Ihre API* im Requestbody des Callbacks senden wird, usw.\n\nAls Nächstes fügen wir den Code hinzu, um zu dokumentieren, wie diese *externe API* aussehen sollte, um den Callback von *Ihrer API* zu empfangen.\n\nDiese Dokumentation wird in der Swagger-Oberfläche unter `/docs` in Ihrer API angezeigt und zeigt externen Entwicklern, wie diese die *externe API* erstellen sollten.\n\nIn diesem Beispiel wird nicht der Callback selbst implementiert (das könnte nur eine Codezeile sein), sondern nur der Dokumentationsteil.\n\n/// tip | Tipp\n\nDer eigentliche Callback ist nur ein HTTP-Request.\n\nWenn Sie den Callback selbst implementieren, können Sie beispielsweise [HTTPX](https://www.python-httpx.org) oder [Requests](https://requests.readthedocs.io/) verwenden.\n\n///\n\n## Schreiben des Codes, der den Callback dokumentiert { #write-the-callback-documentation-code }\n\nDieser Code wird nicht in Ihrer Anwendung ausgeführt, wir benötigen ihn nur, um zu *dokumentieren*, wie diese *externe API* aussehen soll.\n\nSie wissen jedoch bereits, wie Sie mit **FastAPI** ganz einfach eine automatische Dokumentation für eine API erstellen.\n\nDaher werden wir dasselbe Wissen nutzen, um zu dokumentieren, wie die *externe API* aussehen sollte ... indem wir die *Pfadoperation(en)* erstellen, welche die externe API implementieren soll (die, welche Ihre API aufruft).\n\n/// tip | Tipp\n\nWenn Sie den Code zum Dokumentieren eines Callbacks schreiben, kann es hilfreich sein, sich vorzustellen, dass Sie dieser *externe Entwickler* sind. Und dass Sie derzeit die *externe API* implementieren, nicht *Ihre API*.\n\nWenn Sie diese Sichtweise (des *externen Entwicklers*) vorübergehend übernehmen, wird es offensichtlicher, wo die Parameter, das Pydantic-Modell für den Body, die Response, usw. für diese *externe API* hingehören.\n\n///\n\n### Einen Callback-`APIRouter` erstellen { #create-a-callback-apirouter }\n\nErstellen Sie zunächst einen neuen `APIRouter`, der einen oder mehrere Callbacks enthält.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### Die Callback-*Pfadoperation* erstellen { #create-the-callback-path-operation }\n\nUm die Callback-*Pfadoperation* zu erstellen, verwenden Sie denselben `APIRouter`, den Sie oben erstellt haben.\n\nSie sollte wie eine normale FastAPI-*Pfadoperation* aussehen:\n\n* Sie sollte wahrscheinlich eine Deklaration des Bodys enthalten, die sie erhalten soll, z. B. `body: InvoiceEvent`.\n* Und sie könnte auch eine Deklaration der Response enthalten, die zurückgegeben werden soll, z. B. `response_model=InvoiceEventReceived`.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\nEs gibt zwei Hauptunterschiede zu einer normalen *Pfadoperation*:\n\n* Es muss kein tatsächlicher Code vorhanden sein, da Ihre Anwendung diesen Code niemals aufruft. Sie wird nur zur Dokumentation der *externen API* verwendet. Die Funktion könnte also einfach `pass` enthalten.\n* Der *Pfad* kann einen [OpenAPI-3-Ausdruck](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) enthalten (mehr dazu weiter unten), wo er Variablen mit Parametern und Teilen des ursprünglichen Requests verwenden kann, der an *Ihre API* gesendet wurde.\n\n### Der Callback-Pfadausdruck { #the-callback-path-expression }\n\nDer Callback-*Pfad* kann einen [OpenAPI-3-Ausdruck](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) enthalten, welcher Teile des ursprünglichen Requests enthalten kann, der an *Ihre API* gesendet wurde.\n\nIn diesem Fall ist es der `str`:\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\nWenn Ihr API-Benutzer (der externe Entwickler) also einen Request an *Ihre API* sendet, via:\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\nmit einem JSON-Körper:\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\ndann verarbeitet *Ihre API* die Rechnung und sendet irgendwann später einen Callback-Request an die `callback_url` (die *externe API*):\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\nmit einem JSON-Body, der etwa Folgendes enthält:\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\nund sie würde eine Response von dieser *externen API* mit einem JSON-Body wie dem folgenden erwarten:\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip | Tipp\n\nBeachten Sie, dass die verwendete Callback-URL die URL enthält, die als Query-Parameter in `callback_url` (`https://www.external.org/events`) empfangen wurde, und auch die Rechnungs-`id` aus dem JSON-Body (`2expen51ve`).\n\n///\n\n### Den Callback-Router hinzufügen { #add-the-callback-router }\n\nAn diesem Punkt haben Sie die benötigte(n) *Callback-Pfadoperation(en)* (diejenige(n), die der *externe Entwickler* in der *externen API* implementieren sollte) im Callback-Router, den Sie oben erstellt haben.\n\nVerwenden Sie nun den Parameter `callbacks` im *Pfadoperation-Dekorator Ihrer API*, um das Attribut `.routes` (das ist eigentlich nur eine `list`e von Routen/*Pfadoperationen*) dieses Callback-Routers zu übergeben:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip | Tipp\n\nBeachten Sie, dass Sie nicht den Router selbst (`invoices_callback_router`) an `callback=` übergeben, sondern das Attribut `.routes`, wie in `invoices_callback_router.routes`.\n\n///\n\n### Es in der Dokumentation testen { #check-the-docs }\n\nJetzt können Sie Ihre Anwendung starten und auf [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) gehen.\n\nSie sehen Ihre Dokumentation, einschließlich eines Abschnitts „Callbacks“ für Ihre *Pfadoperation*, der zeigt, wie die *externe API* aussehen sollte:\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/de/docs/advanced/openapi-webhooks.md",
    "content": "# OpenAPI Webhooks { #openapi-webhooks }\n\nEs gibt Fälle, in denen Sie Ihren API-**Benutzern** mitteilen möchten, dass Ihre App *deren* App mit einigen Daten aufrufen (einen <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> senden) könnte, normalerweise um über ein bestimmtes **Event** zu **benachrichtigen**.\n\nDas bedeutet, dass anstelle des normalen Prozesses, bei dem Ihre Benutzer Requests an Ihre API senden, **Ihre API** (oder Ihre App) **Requests an deren System** (an deren API, deren App) senden könnte.\n\nDas wird normalerweise als **Web<abbr title=\"Haken, Einhängepunkt\">hook</abbr>** bezeichnet.\n\n## Webhooks-Schritte { #webhooks-steps }\n\nDer Prozess besteht normalerweise darin, dass **Sie in Ihrem Code definieren**, welche Nachricht Sie senden möchten, den **Requestbody**.\n\nSie definieren auch auf irgendeine Weise, in welchen **Momenten** Ihre App diese Requests oder Events senden wird.\n\nUnd **Ihre Benutzer** definieren auf irgendeine Weise (zum Beispiel irgendwo in einem Web-<abbr title=\"Benutzeroberfläche für das Visualisieren und Managen von Daten\">Dashboard</abbr>) die **URL**, an die Ihre App diese Requests senden soll.\n\nDie gesamte **Logik** zur Registrierung der URLs für Webhooks und der Code zum tatsächlichen Senden dieser Requests liegt bei Ihnen. Sie schreiben es so, wie Sie möchten, in **Ihrem eigenen Code**.\n\n## Webhooks mit **FastAPI** und OpenAPI dokumentieren { #documenting-webhooks-with-fastapi-and-openapi }\n\nMit **FastAPI**, mithilfe von OpenAPI, können Sie die Namen dieser Webhooks, die Arten von HTTP-Operationen, die Ihre App senden kann (z. B. `POST`, `PUT`, usw.) und die **Requestbodys** definieren, die Ihre App senden würde.\n\nDies kann es Ihren Benutzern viel einfacher machen, **deren APIs zu implementieren**, um Ihre **Webhook**-Requests zu empfangen. Möglicherweise können diese sogar einen Teil ihres eigenen API-Codes automatisch generieren.\n\n/// info | Info\n\nWebhooks sind in OpenAPI 3.1.0 und höher verfügbar und werden von FastAPI `0.99.0` und höher unterstützt.\n\n///\n\n## Eine App mit Webhooks { #an-app-with-webhooks }\n\nWenn Sie eine **FastAPI**-Anwendung erstellen, gibt es ein `webhooks`-Attribut, das Sie verwenden können, um *Webhooks* zu definieren, genauso wie Sie *Pfadoperationen* definieren würden, zum Beispiel mit `@app.webhooks.post()`.\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\nDie von Ihnen definierten Webhooks landen im **OpenAPI**-Schema und der automatischen **Dokumentations-Oberfläche**.\n\n/// info | Info\n\nDas `app.webhooks`-Objekt ist eigentlich nur ein `APIRouter`, derselbe Typ, den Sie verwenden würden, wenn Sie Ihre App mit mehreren Dateien strukturieren.\n\n///\n\nBeachten Sie, dass Sie bei Webhooks tatsächlich keinen *Pfad* (wie `/items/`) deklarieren, der Text, den Sie dort übergeben, ist lediglich eine **Kennzeichnung** des Webhooks (der Name des Events). Zum Beispiel ist in `@app.webhooks.post(\"new-subscription\")` der Webhook-Name `new-subscription`.\n\nDas liegt daran, dass erwartet wird, dass **Ihre Benutzer** den tatsächlichen **URL-Pfad**, an dem sie den Webhook-Request empfangen möchten, auf andere Weise definieren (z. B. über ein Web-Dashboard).\n\n### Die Dokumentation testen { #check-the-docs }\n\nJetzt können Sie Ihre App starten und auf [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) gehen.\n\nSie werden sehen, dass Ihre Dokumentation die normalen *Pfadoperationen* und jetzt auch einige **Webhooks** enthält:\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/de/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# Fortgeschrittene Konfiguration der Pfadoperation { #path-operation-advanced-configuration }\n\n## OpenAPI operationId { #openapi-operationid }\n\n/// warning | Achtung\n\nWenn Sie kein „Experte“ für OpenAPI sind, brauchen Sie dies wahrscheinlich nicht.\n\n///\n\nMit dem Parameter `operation_id` können Sie die OpenAPI `operationId` festlegen, die in Ihrer *Pfadoperation* verwendet werden soll.\n\nSie müssten sicherstellen, dass sie für jede Operation eindeutig ist.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### Verwendung des Namens der *Pfadoperation-Funktion* als operationId { #using-the-path-operation-function-name-as-the-operationid }\n\nWenn Sie die Funktionsnamen Ihrer API als `operationId`s verwenden möchten, können Sie über alle iterieren und die `operation_id` jeder *Pfadoperation* mit deren `APIRoute.name` überschreiben.\n\nSie sollten dies tun, nachdem Sie alle Ihre *Pfadoperationen* hinzugefügt haben.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip | Tipp\n\nWenn Sie `app.openapi()` manuell aufrufen, sollten Sie vorher die `operationId`s aktualisiert haben.\n\n///\n\n/// warning | Achtung\n\nWenn Sie dies tun, müssen Sie sicherstellen, dass jede Ihrer *Pfadoperation-Funktionen* einen eindeutigen Namen hat.\n\nAuch wenn diese sich in unterschiedlichen Modulen (Python-Dateien) befinden.\n\n///\n\n## Von OpenAPI ausschließen { #exclude-from-openapi }\n\nUm eine *Pfadoperation* aus dem generierten OpenAPI-Schema (und damit aus den automatischen Dokumentationssystemen) auszuschließen, verwenden Sie den Parameter `include_in_schema` und setzen Sie ihn auf `False`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## Fortgeschrittene Beschreibung mittels Docstring { #advanced-description-from-docstring }\n\nSie können die verwendeten Zeilen aus dem Docstring einer *Pfadoperation-Funktion* einschränken, die für OpenAPI verwendet werden.\n\nDas Hinzufügen eines `\\f` (ein maskiertes „Form Feed“-Zeichen) führt dazu, dass **FastAPI** die für OpenAPI verwendete Ausgabe an dieser Stelle abschneidet.\n\nSie wird nicht in der Dokumentation angezeigt, aber andere Tools (wie z. B. Sphinx) können den Rest verwenden.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## Zusätzliche Responses { #additional-responses }\n\nSie haben wahrscheinlich gesehen, wie man das `response_model` und den `status_code` für eine *Pfadoperation* deklariert.\n\nDas definiert die Metadaten der Haupt-<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> einer *Pfadoperation*.\n\nSie können auch zusätzliche Responses mit deren Modellen, Statuscodes usw. deklarieren.\n\nEs gibt hier in der Dokumentation ein ganzes Kapitel darüber, Sie können es unter [Zusätzliche Responses in OpenAPI](additional-responses.md) lesen.\n\n## OpenAPI-Extra { #openapi-extra }\n\nWenn Sie in Ihrer Anwendung eine *Pfadoperation* deklarieren, generiert **FastAPI** automatisch die relevanten Metadaten dieser *Pfadoperation*, die in das OpenAPI-Schema aufgenommen werden sollen.\n\n/// note | Technische Details\n\nIn der OpenAPI-Spezifikation wird es das [Operationsobjekt](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object) genannt.\n\n///\n\nEs hat alle Informationen zur *Pfadoperation* und wird zur Erstellung der automatischen Dokumentation verwendet.\n\nEs enthält `tags`, `parameters`, `requestBody`, `responses`, usw.\n\nDieses *Pfadoperation*-spezifische OpenAPI-Schema wird normalerweise automatisch von **FastAPI** generiert, Sie können es aber auch erweitern.\n\n/// tip | Tipp\n\nDies ist ein Low-Level-Erweiterungspunkt.\n\nWenn Sie nur zusätzliche Responses deklarieren müssen, können Sie dies bequemer mit [Zusätzliche Responses in OpenAPI](additional-responses.md) tun.\n\n///\n\nSie können das OpenAPI-Schema für eine *Pfadoperation* erweitern, indem Sie den Parameter `openapi_extra` verwenden.\n\n### OpenAPI-Erweiterungen { #openapi-extensions }\n\nDieses `openapi_extra` kann beispielsweise hilfreich sein, um [OpenAPI-Erweiterungen](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) zu deklarieren:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\nWenn Sie die automatische API-Dokumentation öffnen, wird Ihre Erweiterung am Ende der spezifischen *Pfadoperation* angezeigt.\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\nUnd wenn Sie die resultierende OpenAPI sehen (unter `/openapi.json` in Ihrer API), sehen Sie Ihre Erweiterung auch als Teil der spezifischen *Pfadoperation*:\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### Benutzerdefiniertes OpenAPI-*Pfadoperation*-Schema { #custom-openapi-path-operation-schema }\n\nDas <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">Dictionary</abbr> in `openapi_extra` wird mit dem automatisch generierten OpenAPI-Schema für die *Pfadoperation* zusammengeführt (mittels Deep Merge).\n\nSie können dem automatisch generierten Schema also zusätzliche Daten hinzufügen.\n\nSie könnten sich beispielsweise dafür entscheiden, den <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> mit Ihrem eigenen Code zu lesen und zu validieren, ohne FastAPIs automatische Funktionen mit Pydantic zu verwenden, aber Sie könnten den Request trotzdem im OpenAPI-Schema definieren wollen.\n\nDas könnte man mit `openapi_extra` machen:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\nIn diesem Beispiel haben wir kein Pydantic-Modell deklariert. Tatsächlich wird der Requestbody nicht einmal als JSON <dfn title=\"von einem einfachen Format, wie Bytes, in Python-Objekte konvertiert\">geparst</dfn>, sondern direkt als `bytes` gelesen und die Funktion `magic_data_reader()` wäre dafür verantwortlich, ihn in irgendeiner Weise zu parsen.\n\nDennoch können wir das zu erwartende Schema für den Requestbody deklarieren.\n\n### Benutzerdefinierter OpenAPI-Content-Type { #custom-openapi-content-type }\n\nMit demselben Trick könnten Sie ein Pydantic-Modell verwenden, um das JSON-Schema zu definieren, das dann im benutzerdefinierten Abschnitt des OpenAPI-Schemas für die *Pfadoperation* enthalten ist.\n\nUnd Sie könnten dies auch tun, wenn der Datentyp im Request nicht JSON ist.\n\nIn der folgenden Anwendung verwenden wir beispielsweise weder FastAPIs integrierte Funktionalität zum Extrahieren des JSON-Schemas aus Pydantic-Modellen noch die automatische Validierung für JSON. Tatsächlich deklarieren wir den Request-Content-Type als YAML und nicht als JSON:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\nObwohl wir nicht die standardmäßig integrierte Funktionalität verwenden, verwenden wir dennoch ein Pydantic-Modell, um das JSON-Schema für die Daten, die wir in YAML empfangen möchten, manuell zu generieren.\n\nDann verwenden wir den Request direkt und extrahieren den Body als `bytes`. Das bedeutet, dass FastAPI nicht einmal versucht, die Request-Payload als JSON zu parsen.\n\nUnd dann parsen wir in unserem Code diesen YAML-Inhalt direkt und verwenden dann wieder dasselbe Pydantic-Modell, um den YAML-Inhalt zu validieren:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip | Tipp\n\nHier verwenden wir dasselbe Pydantic-Modell wieder.\n\nAber genauso hätten wir es auch auf andere Weise validieren können.\n\n///\n"
  },
  {
    "path": "docs/de/docs/advanced/response-change-status-code.md",
    "content": "# Response – Statuscode ändern { #response-change-status-code }\n\nSie haben wahrscheinlich schon vorher gelesen, dass Sie einen Default-[Response-Statuscode](../tutorial/response-status-code.md) festlegen können.\n\nIn manchen Fällen müssen Sie jedoch einen anderen als den Default-Statuscode zurückgeben.\n\n## Anwendungsfall { #use-case }\n\nStellen Sie sich zum Beispiel vor, Sie möchten standardmäßig den HTTP-Statuscode „OK“ `200` zurückgeben.\n\nWenn die Daten jedoch nicht vorhanden sind, möchten Sie diese erstellen und den HTTP-Statuscode „CREATED“ `201` zurückgeben.\n\nSie möchten aber dennoch in der Lage sein, die von Ihnen zurückgegebenen Daten mit einem `response_model` zu filtern und zu konvertieren.\n\nIn diesen Fällen können Sie einen `Response`-Parameter verwenden.\n\n## Einen `Response`-Parameter verwenden { #use-a-response-parameter }\n\nSie können einen Parameter vom Typ `Response` in Ihrer *Pfadoperation-Funktion* deklarieren (wie Sie es auch für Cookies und Header tun können).\n\nAnschließend können Sie den `status_code` in diesem *vorübergehenden* <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>-Objekt festlegen.\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\nUnd dann können Sie jedes benötigte Objekt zurückgeben, wie Sie es normalerweise tun würden (ein `dict`, ein Datenbankmodell usw.).\n\nUnd wenn Sie ein `response_model` deklariert haben, wird es weiterhin zum Filtern und Konvertieren des von Ihnen zurückgegebenen Objekts verwendet.\n\n**FastAPI** verwendet diese *vorübergehende* Response, um den Statuscode (auch Cookies und Header) zu extrahieren und fügt diese in die endgültige Response ein, die den von Ihnen zurückgegebenen Wert enthält, gefiltert nach einem beliebigen `response_model`.\n\nSie können den Parameter `Response` auch in Abhängigkeiten deklarieren und den Statuscode darin festlegen. Bedenken Sie jedoch, dass der zuletzt gesetzte gewinnt.\n"
  },
  {
    "path": "docs/de/docs/advanced/response-cookies.md",
    "content": "# Response-Cookies { #response-cookies }\n\n## Einen `Response`-Parameter verwenden { #use-a-response-parameter }\n\nSie können einen Parameter vom Typ `Response` in Ihrer *Pfadoperation-Funktion* deklarieren.\n\nUnd dann können Sie Cookies in diesem *vorübergehenden* <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>-Objekt setzen.\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\nAnschließend können Sie wie gewohnt jedes gewünschte Objekt zurückgeben (ein `dict`, ein Datenbankmodell, usw.).\n\nUnd wenn Sie ein `response_model` deklariert haben, wird es weiterhin zum Filtern und Konvertieren des von Ihnen zurückgegebenen Objekts verwendet.\n\n**FastAPI** verwendet diese *vorübergehende* Response, um die Cookies (auch Header und Statuscode) zu extrahieren und fügt diese in die endgültige Response ein, die den von Ihnen zurückgegebenen Wert enthält, gefiltert nach einem beliebigen `response_model`.\n\nSie können den `Response`-Parameter auch in Abhängigkeiten deklarieren und darin Cookies (und Header) setzen.\n\n## Eine `Response` direkt zurückgeben { #return-a-response-directly }\n\nSie können Cookies auch erstellen, wenn Sie eine `Response` direkt in Ihrem Code zurückgeben.\n\nDazu können Sie eine Response erstellen, wie unter [Eine Response direkt zurückgeben](response-directly.md) beschrieben.\n\nSetzen Sie dann Cookies darin und geben Sie sie dann zurück:\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip | Tipp\n\nBeachten Sie, dass, wenn Sie eine Response direkt zurückgeben, anstatt den `Response`-Parameter zu verwenden, FastAPI diese direkt zurückgibt.\n\nSie müssen also sicherstellen, dass Ihre Daten vom richtigen Typ sind. Z. B. sollten diese mit JSON kompatibel sein, wenn Sie eine `JSONResponse` zurückgeben.\n\nUnd auch, dass Sie keine Daten senden, die durch ein `response_model` hätten gefiltert werden sollen.\n\n///\n\n### Mehr Informationen { #more-info }\n\n/// note | Technische Details\n\nSie können auch `from starlette.responses import Response` oder `from starlette.responses import JSONResponse` verwenden.\n\n**FastAPI** bietet dieselben `starlette.responses` auch via `fastapi.responses` an, als Annehmlichkeit für Sie, den Entwickler. Die meisten verfügbaren Responses kommen aber direkt von Starlette.\n\nUnd da die `Response` häufig zum Setzen von Headern und Cookies verwendet wird, stellt **FastAPI** diese auch unter `fastapi.Response` bereit.\n\n///\n\nUm alle verfügbaren Parameter und Optionen anzuzeigen, sehen Sie sich deren [Dokumentation in Starlette](https://www.starlette.dev/responses/#set-cookie) an.\n"
  },
  {
    "path": "docs/de/docs/advanced/response-directly.md",
    "content": "# Eine Response direkt zurückgeben { #return-a-response-directly }\n\nWenn Sie eine **FastAPI** *Pfadoperation* erstellen, können Sie normalerweise beliebige Daten davon zurückgeben: ein `dict`, eine `list`, ein Pydantic-Modell, ein Datenbankmodell, usw.\n\nWenn Sie ein [Responsemodell](../tutorial/response-model.md) deklarieren, wird FastAPI es verwenden, um die Daten mithilfe von Pydantic nach JSON zu serialisieren.\n\nWenn Sie kein Responsemodell deklarieren, verwendet FastAPI den `jsonable_encoder`, wie in [JSON-kompatibler Encoder](../tutorial/encoder.md) erläutert, und packt die Daten in eine `JSONResponse`.\n\nSie könnten auch direkt eine `JSONResponse` erstellen und zurückgeben.\n\n/// tip | Tipp\n\nNormalerweise erzielen Sie eine deutlich bessere Leistung, wenn Sie ein [Responsemodell](../tutorial/response-model.md) verwenden, als wenn Sie direkt eine `JSONResponse` zurückgeben, da die Serialisierung der Daten dabei mit Pydantic in Rust erfolgt.\n\n///\n\n## Eine `Response` zurückgeben { #return-a-response }\n\nTatsächlich können Sie jede `Response` oder jede Unterklasse davon zurückgeben.\n\n/// info | Info\n\n`JSONResponse` selbst ist eine Unterklasse von `Response`.\n\n///\n\nUnd wenn Sie eine `Response` zurückgeben, wird **FastAPI** diese direkt weiterleiten.\n\nEs wird keine Datenkonvertierung mit Pydantic-Modellen durchführen, es wird den Inhalt nicht in irgendeinen Typ konvertieren, usw.\n\nDadurch haben Sie viel Flexibilität. Sie können jeden Datentyp zurückgeben, jede Datendeklaration oder -validierung überschreiben, usw.\n\nDas bringt Ihnen aber auch viel Verantwortung. Sie müssen sicherstellen, dass die von Ihnen zurückgegebenen Daten korrekt sind, das richtige Format haben, serialisierbar sind, usw.\n\n## Verwendung des `jsonable_encoder` in einer `Response` { #using-the-jsonable-encoder-in-a-response }\n\nDa **FastAPI** keine Änderungen an einer von Ihnen zurückgegebenen `Response` vornimmt, müssen Sie sicherstellen, dass deren Inhalt dafür bereit ist.\n\nSie können beispielsweise kein Pydantic-Modell in eine `JSONResponse` einfügen, ohne es zuvor in ein `dict` zu konvertieren, bei dem alle Datentypen (wie `datetime`, `UUID`, usw.) in JSON-kompatible Typen konvertiert wurden.\n\nIn diesen Fällen können Sie den `jsonable_encoder` verwenden, um Ihre Daten zu konvertieren, bevor Sie sie an eine Response übergeben:\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | Technische Details\n\nSie könnten auch `from starlette.responses import JSONResponse` verwenden.\n\n**FastAPI** bietet dieselben `starlette.responses` auch via `fastapi.responses` an, als Annehmlichkeit für Sie, den Entwickler. Die meisten verfügbaren Responses kommen aber direkt von Starlette.\n\n///\n\n## Eine benutzerdefinierte `Response` zurückgeben { #returning-a-custom-response }\n\nDas obige Beispiel zeigt alle Teile, die Sie benötigen, ist aber noch nicht sehr nützlich, da Sie das `item` einfach direkt hätten zurückgeben können, und **FastAPI** würde es für Sie in eine `JSONResponse` einfügen, es in ein `dict` konvertieren, usw. All das standardmäßig.\n\nSehen wir uns nun an, wie Sie damit eine benutzerdefinierte Response zurückgeben können.\n\nNehmen wir an, Sie möchten eine [XML](https://en.wikipedia.org/wiki/XML)-Response zurückgeben.\n\nSie könnten Ihren XML-Inhalt als String in eine `Response` einfügen und sie zurückgeben:\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## Funktionsweise eines Responsemodells { #how-a-response-model-works }\n\nWenn Sie in einer Pfadoperation ein [Responsemodell - Rückgabetyp](../tutorial/response-model.md) deklarieren, wird **FastAPI** es verwenden, um die Daten mithilfe von Pydantic nach JSON zu serialisieren.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nDa dies auf der Rust-Seite geschieht, ist die Leistung deutlich besser, als wenn es mit normalem Python und der Klasse `JSONResponse` erfolgen würde.\n\nWenn Sie ein `response_model` oder einen Rückgabetyp verwenden, nutzt FastAPI weder den `jsonable_encoder` (was langsamer wäre) zur Konvertierung der Daten noch die Klasse `JSONResponse`.\n\nStattdessen nimmt es die von Pydantic mithilfe des Responsemodells (oder Rückgabetyps) generierten JSON-Bytes und gibt direkt eine `Response` mit dem richtigen Mediatyp für JSON (`application/json`) zurück.\n\n## Anmerkungen { #notes }\n\nWenn Sie eine `Response` direkt zurücksenden, werden deren Daten weder validiert, konvertiert (serialisiert), noch automatisch dokumentiert.\n\nSie können sie aber trotzdem wie unter [Zusätzliche Responses in OpenAPI](additional-responses.md) beschrieben dokumentieren.\n\nIn späteren Abschnitten erfahren Sie, wie Sie diese benutzerdefinierten `Response`s verwenden/deklarieren und gleichzeitig über automatische Datenkonvertierung, Dokumentation, usw. verfügen.\n"
  },
  {
    "path": "docs/de/docs/advanced/response-headers.md",
    "content": "# Response-Header { #response-headers }\n\n## Einen `Response`-Parameter verwenden { #use-a-response-parameter }\n\nSie können einen Parameter vom Typ `Response` in Ihrer *Pfadoperation-Funktion* deklarieren (wie Sie es auch für Cookies tun können).\n\nUnd dann können Sie Header in diesem *vorübergehenden* <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>-Objekt festlegen.\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\nAnschließend können Sie wie gewohnt jedes gewünschte Objekt zurückgeben (ein `dict`, ein Datenbankmodell, usw.).\n\nUnd wenn Sie ein `response_model` deklariert haben, wird es weiterhin zum Filtern und Konvertieren des von Ihnen zurückgegebenen Objekts verwendet.\n\n**FastAPI** verwendet diese *vorübergehende* Response, um die Header (auch Cookies und Statuscode) zu extrahieren und fügt diese in die endgültige Response ein, die den von Ihnen zurückgegebenen Wert enthält, gefiltert nach einem beliebigen `response_model`.\n\nSie können den Parameter `Response` auch in Abhängigkeiten deklarieren und darin Header (und Cookies) festlegen.\n\n## Eine `Response` direkt zurückgeben { #return-a-response-directly }\n\nSie können auch Header hinzufügen, wenn Sie eine `Response` direkt zurückgeben.\n\nErstellen Sie eine Response wie in [Eine Response direkt zurückgeben](response-directly.md) beschrieben und übergeben Sie die Header als zusätzlichen Parameter:\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | Technische Details\n\nSie können auch `from starlette.responses import Response` oder `from starlette.responses import JSONResponse` verwenden.\n\n**FastAPI** bietet dieselben `starlette.responses` auch via `fastapi.responses` an, als Annehmlichkeit für Sie, den Entwickler. Die meisten verfügbaren Responses kommen aber direkt von Starlette.\n\nUnd da die `Response` häufig zum Setzen von Headern und Cookies verwendet wird, stellt **FastAPI** diese auch unter `fastapi.Response` bereit.\n\n///\n\n## Benutzerdefinierte Header { #custom-headers }\n\nBeachten Sie, dass benutzerdefinierte proprietäre Header [mit dem Präfix `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) hinzugefügt werden können.\n\nWenn Sie jedoch benutzerdefinierte Header haben, die ein Client in einem Browser sehen können soll, müssen Sie diese zu Ihrer CORS-Konfiguration hinzufügen (weitere Informationen finden Sie unter [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), unter Verwendung des Parameters `expose_headers`, dokumentiert in [Starlettes CORS-Dokumentation](https://www.starlette.dev/middleware/#corsmiddleware).\n"
  },
  {
    "path": "docs/de/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP Basic Auth { #http-basic-auth }\n\nFür die einfachsten Fälle können Sie <abbr title=\"HTTP-Basisauthentifizierung\">HTTP Basic Auth</abbr> verwenden.\n\nBei HTTP Basic Auth erwartet die Anwendung einen Header, der einen Benutzernamen und ein Passwort enthält.\n\nWenn sie diesen nicht empfängt, gibt sie den HTTP-Error 401 „Unauthorized“ zurück.\n\nUnd gibt einen Header `WWW-Authenticate` mit dem Wert `Basic` und einem optionalen <abbr title=\"Bereich\">`realm`</abbr>-Parameter zurück.\n\nDadurch wird der Browser angewiesen, die integrierte Eingabeaufforderung für einen Benutzernamen und ein Passwort anzuzeigen.\n\nWenn Sie dann den Benutzernamen und das Passwort eingeben, sendet der Browser diese automatisch im Header.\n\n## Einfaches HTTP Basic Auth { #simple-http-basic-auth }\n\n* Importieren Sie `HTTPBasic` und `HTTPBasicCredentials`.\n* Erstellen Sie mit `HTTPBasic` ein „`security`-Schema“.\n* Verwenden Sie dieses `security` mit einer Abhängigkeit in Ihrer *Pfadoperation*.\n* Diese gibt ein Objekt vom Typ `HTTPBasicCredentials` zurück:\n    * Es enthält den gesendeten `username` und das gesendete `password`.\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\nWenn Sie versuchen, die URL zum ersten Mal zu öffnen (oder in der Dokumentation auf den Button „Execute“ zu klicken), wird der Browser Sie nach Ihrem Benutzernamen und Passwort fragen:\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## Den Benutzernamen überprüfen { #check-the-username }\n\nHier ist ein vollständigeres Beispiel.\n\nVerwenden Sie eine Abhängigkeit, um zu überprüfen, ob Benutzername und Passwort korrekt sind.\n\nVerwenden Sie dazu das Python-Standardmodul [`secrets`](https://docs.python.org/3/library/secrets.html), um den Benutzernamen und das Passwort zu überprüfen.\n\n`secrets.compare_digest()` benötigt `bytes` oder einen `str`, welcher nur ASCII-Zeichen (solche der englischen Sprache) enthalten darf, das bedeutet, dass es nicht mit Zeichen wie `á`, wie in `Sebastián`, funktionieren würde.\n\nUm dies zu lösen, konvertieren wir zunächst den `username` und das `password` in UTF-8-codierte `bytes`.\n\nDann können wir `secrets.compare_digest()` verwenden, um sicherzustellen, dass `credentials.username` `\"stanleyjobson\"` und `credentials.password` `\"swordfish\"` ist.\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\nDies wäre das gleiche wie:\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # Einen Error zurückgeben\n    ...\n```\n\nAber durch die Verwendung von `secrets.compare_digest()` ist dieser Code sicher vor einer Art von Angriffen, die „Timing-Angriffe“ genannt werden.\n\n### Timing-Angriffe { #timing-attacks }\n\nAber was ist ein „Timing-Angriff“?\n\nStellen wir uns vor, dass einige Angreifer versuchen, den Benutzernamen und das Passwort zu erraten.\n\nUnd sie senden einen <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> mit dem Benutzernamen `johndoe` und dem Passwort `love123`.\n\nDann würde der Python-Code in Ihrer Anwendung etwa so aussehen:\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nAber genau in dem Moment, in dem Python das erste `j` in `johndoe` mit dem ersten `s` in `stanleyjobson` vergleicht, gibt es `False` zurück, da es bereits weiß, dass diese beiden Strings nicht identisch sind, und denkt, „Es besteht keine Notwendigkeit, weitere Berechnungen mit dem Vergleich der restlichen Buchstaben zu verschwenden“. Und Ihre Anwendung wird zurückgeben „Incorrect username or password“.\n\nDoch dann versuchen es die Angreifer mit dem Benutzernamen `stanleyjobsox` und dem Passwort `love123`.\n\nUnd Ihr Anwendungscode macht etwa Folgendes:\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nPython muss das gesamte `stanleyjobso` in `stanleyjobsox` und `stanleyjobson` vergleichen, bevor es erkennt, dass beide Zeichenfolgen nicht gleich sind. Daher wird es einige zusätzliche Mikrosekunden dauern, bis die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> „Incorrect username or password“ erfolgt.\n\n#### Die Zeit zum Antworten hilft den Angreifern { #the-time-to-answer-helps-the-attackers }\n\nWenn die Angreifer zu diesem Zeitpunkt feststellen, dass der Server einige Mikrosekunden länger braucht, um die Response „Incorrect username or password“ zu senden, wissen sie, dass sie _etwas_ richtig gemacht haben, einige der Anfangsbuchstaben waren richtig.\n\nUnd dann können sie es noch einmal versuchen, wohl wissend, dass es wahrscheinlich eher etwas mit `stanleyjobsox` als mit `johndoe` zu tun hat.\n\n#### Ein „professioneller“ Angriff { #a-professional-attack }\n\nNatürlich würden die Angreifer das alles nicht von Hand versuchen, sondern ein Programm dafür schreiben, möglicherweise mit Tausenden oder Millionen Tests pro Sekunde. Und würden jeweils nur einen zusätzlichen richtigen Buchstaben erhalten.\n\nAber so hätten die Angreifer in wenigen Minuten oder Stunden mit der „Hilfe“ unserer Anwendung den richtigen Benutzernamen und das richtige Passwort erraten, indem sie die Zeitspanne zur Hilfe nehmen, die diese zur Beantwortung benötigt.\n\n#### Das Problem beheben mittels `secrets.compare_digest()` { #fix-it-with-secrets-compare-digest }\n\nAber in unserem Code verwenden wir tatsächlich `secrets.compare_digest()`.\n\nDamit wird, kurz gesagt, der Vergleich von `stanleyjobsox` mit `stanleyjobson` genauso lange dauern wie der Vergleich von `johndoe` mit `stanleyjobson`. Und das Gleiche gilt für das Passwort.\n\nSo ist Ihr Anwendungscode, dank der Verwendung von `secrets.compare_digest()`, vor dieser ganzen Klasse von Sicherheitsangriffen geschützt.\n\n### Den Error zurückgeben { #return-the-error }\n\nNachdem Sie festgestellt haben, dass die Anmeldeinformationen falsch sind, geben Sie eine `HTTPException` mit dem Statuscode 401 zurück (derselbe, der auch zurückgegeben wird, wenn keine Anmeldeinformationen angegeben werden) und fügen den Header `WWW-Authenticate` hinzu, damit der Browser die Anmeldeaufforderung erneut anzeigt:\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/de/docs/advanced/security/index.md",
    "content": "# Fortgeschrittene Sicherheit { #advanced-security }\n\n## Zusatzfunktionen { #additional-features }\n\nNeben den in [Tutorial – Benutzerhandbuch: Sicherheit](../../tutorial/security/index.md) behandelten Funktionen gibt es noch einige zusätzliche Funktionen zur Handhabung der Sicherheit.\n\n/// tip | Tipp\n\nDie nächsten Abschnitte sind **nicht unbedingt „fortgeschritten“**.\n\nUnd es ist möglich, dass für Ihren Anwendungsfall die Lösung in einem davon liegt.\n\n///\n\n## Das Tutorial zuerst lesen { #read-the-tutorial-first }\n\nDie nächsten Abschnitte setzen voraus, dass Sie das Haupt-[Tutorial – Benutzerhandbuch: Sicherheit](../../tutorial/security/index.md) bereits gelesen haben.\n\nSie basieren alle auf den gleichen Konzepten, ermöglichen jedoch einige zusätzliche Funktionalitäten.\n"
  },
  {
    "path": "docs/de/docs/advanced/security/oauth2-scopes.md",
    "content": "# OAuth2-Scopes { #oauth2-scopes }\n\nSie können OAuth2-<abbr title=\"Geltungsbereiche\">Scopes</abbr> direkt in **FastAPI** verwenden, sie sind nahtlos integriert.\n\nDas ermöglicht es Ihnen, ein feingranuliertes Berechtigungssystem nach dem OAuth2-Standard in Ihre OpenAPI-Anwendung (und deren API-Dokumentation) zu integrieren.\n\nOAuth2 mit Scopes ist der Mechanismus, der von vielen großen Authentifizierungsanbietern wie Facebook, Google, GitHub, Microsoft, X (Twitter) usw. verwendet wird. Sie verwenden ihn, um Benutzern und Anwendungen spezifische Berechtigungen zu erteilen.\n\nJedes Mal, wenn Sie sich mit Facebook, Google, GitHub, Microsoft oder X (Twitter) anmelden („log in with“), verwendet die entsprechende Anwendung OAuth2 mit Scopes.\n\nIn diesem Abschnitt erfahren Sie, wie Sie Authentifizierung und Autorisierung mit demselben OAuth2, mit Scopes in Ihrer **FastAPI**-Anwendung verwalten.\n\n/// warning | Achtung\n\nDies ist ein mehr oder weniger fortgeschrittener Abschnitt. Wenn Sie gerade erst anfangen, können Sie ihn überspringen.\n\nSie benötigen nicht unbedingt OAuth2-Scopes, und Sie können die Authentifizierung und Autorisierung handhaben wie Sie möchten.\n\nAber OAuth2 mit Scopes kann bequem in Ihre API (mit OpenAPI) und deren API-Dokumentation integriert werden.\n\nDennoch, verwenden Sie solche Scopes oder andere Sicherheits-/Autorisierungsanforderungen in Ihrem Code so wie Sie es möchten.\n\nIn vielen Fällen kann OAuth2 mit Scopes ein Overkill sein.\n\nAber wenn Sie wissen, dass Sie es brauchen oder neugierig sind, lesen Sie weiter.\n\n///\n\n## OAuth2-Scopes und OpenAPI { #oauth2-scopes-and-openapi }\n\nDie OAuth2-Spezifikation definiert „Scopes“ als eine Liste von durch Leerzeichen getrennten Strings.\n\nDer Inhalt jedes dieser Strings kann ein beliebiges Format haben, sollte jedoch keine Leerzeichen enthalten.\n\nDiese Scopes stellen „Berechtigungen“ dar.\n\nIn OpenAPI (z. B. der API-Dokumentation) können Sie „Sicherheitsschemas“ definieren.\n\nWenn eines dieser Sicherheitsschemas OAuth2 verwendet, können Sie auch Scopes deklarieren und verwenden.\n\nJeder „Scope“ ist nur ein String (ohne Leerzeichen).\n\nEr wird normalerweise verwendet, um bestimmte Sicherheitsberechtigungen zu deklarieren, zum Beispiel:\n\n* `users:read` oder `users:write` sind gängige Beispiele.\n* `instagram_basic` wird von Facebook / Instagram verwendet.\n* `https://www.googleapis.com/auth/drive` wird von Google verwendet.\n\n/// info | Info\n\nIn OAuth2 ist ein „Scope“ nur ein String, der eine bestimmte erforderliche Berechtigung deklariert.\n\nEs spielt keine Rolle, ob er andere Zeichen wie `:` enthält oder ob es eine URL ist.\n\nDiese Details sind implementierungsspezifisch.\n\nFür OAuth2 sind es einfach nur Strings.\n\n///\n\n## Gesamtübersicht { #global-view }\n\nSehen wir uns zunächst kurz die Teile an, die sich gegenüber den Beispielen im Haupt-**Tutorial – Benutzerhandbuch** für [OAuth2 mit Password (und Hashing), Bearer mit JWT-Tokens](../../tutorial/security/oauth2-jwt.md) ändern. Diesmal verwenden wir OAuth2-Scopes:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\nSehen wir uns diese Änderungen nun Schritt für Schritt an.\n\n## OAuth2-Sicherheitsschema { #oauth2-security-scheme }\n\nDie erste Änderung ist, dass wir jetzt das OAuth2-Sicherheitsschema mit zwei verfügbaren Scopes deklarieren: `me` und `items`.\n\nDer `scopes`-Parameter erhält ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr> mit jedem Scope als Schlüssel und dessen Beschreibung als Wert:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\nDa wir diese Scopes jetzt deklarieren, werden sie in der API-Dokumentation angezeigt, wenn Sie sich einloggen/autorisieren.\n\nUnd Sie können auswählen, auf welche Scopes Sie Zugriff haben möchten: `me` und `items`.\n\nDas ist derselbe Mechanismus, der verwendet wird, wenn Sie beim Anmelden mit Facebook, Google, GitHub, usw. Berechtigungen erteilen:\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## JWT-Token mit Scopes { #jwt-token-with-scopes }\n\nÄndern Sie nun die Token-*Pfadoperation*, um die angeforderten Scopes zurückzugeben.\n\nWir verwenden immer noch dasselbe `OAuth2PasswordRequestForm`. Es enthält eine Eigenschaft `scopes` mit einer `list`e von `str`s für jeden Scope, den es im <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> erhalten hat.\n\nUnd wir geben die Scopes als Teil des JWT-Tokens zurück.\n\n/// danger | Gefahr\n\nDer Einfachheit halber fügen wir hier die empfangenen Scopes direkt zum Token hinzu.\n\nAus Sicherheitsgründen sollten Sie jedoch sicherstellen, dass Sie in Ihrer Anwendung nur die Scopes hinzufügen, die der Benutzer tatsächlich haben kann, oder die Sie vordefiniert haben.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## Scopes in *Pfadoperationen* und Abhängigkeiten deklarieren { #declare-scopes-in-path-operations-and-dependencies }\n\nJetzt deklarieren wir, dass die *Pfadoperation* für `/users/me/items/` den Scope `items` erfordert.\n\nDazu importieren und verwenden wir `Security` von `fastapi`.\n\nSie können `Security` verwenden, um Abhängigkeiten zu deklarieren (genau wie `Depends`), aber `Security` erhält auch einen Parameter `scopes` mit einer Liste von Scopes (Strings).\n\nIn diesem Fall übergeben wir eine Abhängigkeitsfunktion `get_current_active_user` an `Security` (genauso wie wir es mit `Depends` tun würden).\n\nWir übergeben aber auch eine `list`e von Scopes, in diesem Fall mit nur einem Scope: `items` (es könnten mehrere sein).\n\nUnd die Abhängigkeitsfunktion `get_current_active_user` kann auch Unterabhängigkeiten deklarieren, nicht nur mit `Depends`, sondern auch mit `Security`. Ihre eigene Unterabhängigkeitsfunktion (`get_current_user`) und weitere Scope-Anforderungen deklarierend.\n\nIn diesem Fall erfordert sie den Scope `me` (sie könnte mehr als einen Scope erfordern).\n\n/// note | Hinweis\n\nSie müssen nicht unbedingt an verschiedenen Stellen verschiedene Scopes hinzufügen.\n\nWir tun dies hier, um zu demonstrieren, wie **FastAPI** auf verschiedenen Ebenen deklarierte Scopes verarbeitet.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | Technische Details\n\n`Security` ist tatsächlich eine Unterklasse von `Depends` und hat nur noch einen zusätzlichen Parameter, den wir später kennenlernen werden.\n\nDurch die Verwendung von `Security` anstelle von `Depends` weiß **FastAPI** jedoch, dass es Sicherheits-Scopes deklarieren, intern verwenden und die API mit OpenAPI dokumentieren kann.\n\nWenn Sie jedoch `Query`, `Path`, `Depends`, `Security` und andere von `fastapi` importieren, handelt es sich tatsächlich um Funktionen, die spezielle Klassen zurückgeben.\n\n///\n\n## `SecurityScopes` verwenden { #use-securityscopes }\n\nAktualisieren Sie nun die Abhängigkeit `get_current_user`.\n\nDas ist diejenige, die von den oben genannten Abhängigkeiten verwendet wird.\n\nHier verwenden wir dasselbe OAuth2-Schema, das wir zuvor erstellt haben, und deklarieren es als Abhängigkeit: `oauth2_scheme`.\n\nDa diese Abhängigkeitsfunktion selbst keine Scope-Anforderungen hat, können wir `Depends` mit `oauth2_scheme` verwenden. Wir müssen `Security` nicht verwenden, wenn wir keine Sicherheits-Scopes angeben müssen.\n\nWir deklarieren auch einen speziellen Parameter vom Typ `SecurityScopes`, der aus `fastapi.security` importiert wird.\n\nDiese `SecurityScopes`-Klasse ähnelt `Request` (`Request` wurde verwendet, um das Request-Objekt direkt zu erhalten).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## Die `scopes` verwenden { #use-the-scopes }\n\nDer Parameter `security_scopes` wird vom Typ `SecurityScopes` sein.\n\nDieses verfügt über ein Attribut `scopes` mit einer Liste, die alle von ihm selbst benötigten Scopes enthält und ferner alle Abhängigkeiten, die dieses als Unterabhängigkeit verwenden. Sprich, alle „Dependanten“ ... das mag verwirrend klingen, wird aber später noch einmal erklärt.\n\nDas `security_scopes`-Objekt (der Klasse `SecurityScopes`) stellt außerdem ein `scope_str`-Attribut mit einem einzelnen String bereit, der die durch Leerzeichen getrennten Scopes enthält (den werden wir verwenden).\n\nWir erstellen eine `HTTPException`, die wir später an mehreren Stellen wiederverwenden (`raise`n) können.\n\nIn diese Exception fügen wir (falls vorhanden) die erforderlichen Scopes als durch Leerzeichen getrennten String ein (unter Verwendung von `scope_str`). Wir fügen diesen String mit den Scopes in den Header `WWW-Authenticate` ein (das ist Teil der Spezifikation).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## Den `username` und das Format der Daten überprüfen { #verify-the-username-and-data-shape }\n\nWir verifizieren, dass wir einen `username` erhalten, und extrahieren die Scopes.\n\nUnd dann validieren wir diese Daten mit dem Pydantic-Modell (wobei wir die `ValidationError`-Exception abfangen), und wenn wir beim Lesen des JWT-Tokens oder beim Validieren der Daten mit Pydantic einen Fehler erhalten, lösen wir die zuvor erstellte `HTTPException` aus.\n\nDazu aktualisieren wir das Pydantic-Modell `TokenData` mit einem neuen Attribut `scopes`.\n\nDurch die Validierung der Daten mit Pydantic können wir sicherstellen, dass wir beispielsweise präzise eine `list`e von `str`s mit den Scopes und einen `str` mit dem `username` haben.\n\nAnstelle beispielsweise eines `dict`s oder etwas anderem, was später in der Anwendung zu Fehlern führen könnte und darum ein Sicherheitsrisiko darstellt.\n\nWir verifizieren auch, dass wir einen Benutzer mit diesem Benutzernamen haben, und wenn nicht, lösen wir dieselbe Exception aus, die wir zuvor erstellt haben.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## Die `scopes` verifizieren { #verify-the-scopes }\n\nWir überprüfen nun, ob das empfangene Token alle Scopes enthält, die von dieser Abhängigkeit und deren Verwendern (einschließlich *Pfadoperationen*) gefordert werden. Andernfalls lösen wir eine `HTTPException` aus.\n\nHierzu verwenden wir `security_scopes.scopes`, das eine `list`e mit allen diesen Scopes als `str` enthält.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## Abhängigkeitsbaum und Scopes { #dependency-tree-and-scopes }\n\nSehen wir uns diesen Abhängigkeitsbaum und die Scopes noch einmal an.\n\nDa die Abhängigkeit `get_current_active_user` von `get_current_user` abhängt, wird der bei `get_current_active_user` deklarierte Scope `\"me\"` in die Liste der erforderlichen Scopes in `security_scopes.scopes` aufgenommen, das an `get_current_user` übergeben wird.\n\nDie *Pfadoperation* selbst deklariert auch einen Scope, `\"items\"`, sodass dieser auch in der Liste der `security_scopes.scopes` enthalten ist, die an `get_current_user` übergeben wird.\n\nSo sieht die Hierarchie der Abhängigkeiten und Scopes aus:\n\n* Die *Pfadoperation* `read_own_items` hat:\n    * Erforderliche Scopes `[\"items\"]` mit der Abhängigkeit:\n    * `get_current_active_user`:\n        * Die Abhängigkeitsfunktion `get_current_active_user` hat:\n            * Erforderliche Scopes `[\"me\"]` mit der Abhängigkeit:\n            * `get_current_user`:\n                * Die Abhängigkeitsfunktion `get_current_user` hat:\n                    * Selbst keine erforderlichen Scopes.\n                    * Eine Abhängigkeit, die `oauth2_scheme` verwendet.\n                    * Einen `security_scopes`-Parameter vom Typ `SecurityScopes`:\n                        * Dieser `security_scopes`-Parameter hat ein Attribut `scopes` mit einer `list`e, die alle oben deklarierten Scopes enthält, sprich:\n                            * `security_scopes.scopes` enthält `[\"me\", \"items\"]` für die *Pfadoperation* `read_own_items`.\n                            * `security_scopes.scopes` enthält `[\"me\"]` für die *Pfadoperation* `read_users_me`, da das in der Abhängigkeit `get_current_active_user` deklariert ist.\n                            * `security_scopes.scopes` wird `[]` (nichts) für die *Pfadoperation* `read_system_status` enthalten, da diese keine `Security` mit `scopes` deklariert hat, und deren Abhängigkeit `get_current_user` ebenfalls keinerlei `scopes` deklariert.\n\n/// tip | Tipp\n\nDas Wichtige und „Magische“ hier ist, dass `get_current_user` für jede *Pfadoperation* eine andere Liste von `scopes` hat, die überprüft werden.\n\nAlles hängt von den „Scopes“ ab, die in jeder *Pfadoperation* und jeder Abhängigkeit im Abhängigkeitsbaum für diese bestimmte *Pfadoperation* deklariert wurden.\n\n///\n\n## Weitere Details zu `SecurityScopes` { #more-details-about-securityscopes }\n\nSie können `SecurityScopes` an jeder Stelle und an mehreren Stellen verwenden, es muss sich nicht in der „Wurzel“-Abhängigkeit befinden.\n\nEs wird immer die Sicherheits-Scopes enthalten, die in den aktuellen `Security`-Abhängigkeiten deklariert sind und in allen Abhängigkeiten für **diese spezifische** *Pfadoperation* und **diesen spezifischen** Abhängigkeitsbaum.\n\nDa die `SecurityScopes` alle von den Verwendern der Abhängigkeiten deklarierten Scopes enthalten, können Sie damit überprüfen, ob ein Token in einer zentralen Abhängigkeitsfunktion über die erforderlichen Scopes verfügt, und dann unterschiedliche Scope-Anforderungen in unterschiedlichen *Pfadoperationen* deklarieren.\n\nDiese werden für jede *Pfadoperation* unabhängig überprüft.\n\n## Es testen { #check-it }\n\nWenn Sie die API-Dokumentation öffnen, können Sie sich authentisieren und angeben, welche Scopes Sie autorisieren möchten.\n\n<img src=\"/img/tutorial/security/image11.png\">\n\nWenn Sie keinen Scope auswählen, werden Sie „authentifiziert“, aber wenn Sie versuchen, auf `/users/me/` oder `/users/me/items/` zuzugreifen, wird eine Fehlermeldung angezeigt, die sagt, dass Sie nicht über genügend Berechtigungen verfügen. Sie können aber auf `/status/` zugreifen.\n\nUnd wenn Sie den Scope `me`, aber nicht den Scope `items` auswählen, können Sie auf `/users/me/` zugreifen, aber nicht auf `/users/me/items/`.\n\nDas würde einer Drittanbieteranwendung passieren, die versucht, auf eine dieser *Pfadoperationen* mit einem Token zuzugreifen, das von einem Benutzer bereitgestellt wurde, abhängig davon, wie viele Berechtigungen der Benutzer dieser Anwendung erteilt hat.\n\n## Über Integrationen von Drittanbietern { #about-third-party-integrations }\n\nIn diesem Beispiel verwenden wir den OAuth2-Flow „Password“.\n\nDas ist angemessen, wenn wir uns bei unserer eigenen Anwendung anmelden, wahrscheinlich mit unserem eigenen Frontend.\n\nWeil wir darauf vertrauen können, dass es den `username` und das `password` erhält, welche wir kontrollieren.\n\nWenn Sie jedoch eine OAuth2-Anwendung erstellen, mit der andere eine Verbindung herstellen würden (d.h. wenn Sie einen Authentifizierungsanbieter erstellen, der Facebook, Google, GitHub usw. entspricht), sollten Sie einen der anderen Flows verwenden.\n\nAm häufigsten ist der „Implicit“-Flow.\n\nAm sichersten ist der „Code“-Flow, die Implementierung ist jedoch komplexer, da mehr Schritte erforderlich sind. Da er komplexer ist, schlagen viele Anbieter letztendlich den „Implicit“-Flow vor.\n\n/// note | Hinweis\n\nEs ist üblich, dass jeder Authentifizierungsanbieter seine Flows anders benennt, um sie zu einem Teil seiner Marke zu machen.\n\nAber am Ende implementieren sie denselben OAuth2-Standard.\n\n///\n\n**FastAPI** enthält Werkzeuge für alle diese OAuth2-Authentifizierungs-Flows in `fastapi.security.oauth2`.\n\n## `Security` in Dekorator-`dependencies` { #security-in-decorator-dependencies }\n\nAuf die gleiche Weise können Sie eine `list`e von `Depends` im Parameter `dependencies` des Dekorators definieren (wie in [Abhängigkeiten in Pfadoperation-Dekoratoren](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md) erläutert), Sie könnten auch dort `Security` mit `scopes` verwenden.\n"
  },
  {
    "path": "docs/de/docs/advanced/settings.md",
    "content": "# Einstellungen und Umgebungsvariablen { #settings-and-environment-variables }\n\nIn vielen Fällen benötigt Ihre Anwendung möglicherweise einige externe Einstellungen oder Konfigurationen, zum Beispiel geheime Schlüssel, Datenbank-Anmeldeinformationen, Anmeldeinformationen für E-Mail-Dienste, usw.\n\nDie meisten dieser Einstellungen sind variabel (können sich ändern), wie z. B. Datenbank-URLs. Und vieles könnten schützenswerte, geheime Daten sein.\n\nAus diesem Grund werden diese üblicherweise in Umgebungsvariablen bereitgestellt, die von der Anwendung gelesen werden.\n\n/// tip | Tipp\n\nUm Umgebungsvariablen zu verstehen, können Sie [Umgebungsvariablen](../environment-variables.md) lesen.\n\n///\n\n## Typen und Validierung { #types-and-validation }\n\nDiese Umgebungsvariablen können nur Text-Zeichenketten verarbeiten, da sie außerhalb von Python liegen und mit anderen Programmen und dem Rest des Systems (und sogar mit verschiedenen Betriebssystemen wie Linux, Windows, macOS) kompatibel sein müssen.\n\nDas bedeutet, dass jeder in Python aus einer Umgebungsvariablen gelesene Wert ein `str` ist und jede Konvertierung in einen anderen Typ oder jede Validierung im Code erfolgen muss.\n\n## Pydantic `Settings` { #pydantic-settings }\n\nGlücklicherweise bietet Pydantic ein großartiges Werkzeug zur Verarbeitung dieser Einstellungen, die von Umgebungsvariablen stammen, mit [Pydantic: Settings Management](https://docs.pydantic.dev/latest/concepts/pydantic_settings/).\n\n### `pydantic-settings` installieren { #install-pydantic-settings }\n\nStellen Sie zunächst sicher, dass Sie Ihre [virtuelle Umgebung](../virtual-environments.md) erstellt und aktiviert haben, und installieren Sie dann das Package `pydantic-settings`:\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\nEs ist bereits enthalten, wenn Sie die `all`-Extras installiert haben, mit:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### Das `Settings`-Objekt erstellen { #create-the-settings-object }\n\nImportieren Sie `BaseSettings` aus Pydantic und erstellen Sie eine Unterklasse, ganz ähnlich wie bei einem Pydantic-Modell.\n\nAuf die gleiche Weise wie bei Pydantic-Modellen deklarieren Sie Klassenattribute mit Typannotationen und möglicherweise Defaultwerten.\n\nSie können dieselben Validierungs-Funktionen und -Tools verwenden, die Sie für Pydantic-Modelle verwenden, z. B. verschiedene Datentypen und zusätzliche Validierungen mit `Field()`.\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip | Tipp\n\nFür ein schnelles Copy-and-paste verwenden Sie nicht dieses Beispiel, sondern das letzte unten.\n\n///\n\nWenn Sie dann eine Instanz dieser `Settings`-Klasse erstellen (in diesem Fall als `settings`-Objekt), liest Pydantic die Umgebungsvariablen ohne Berücksichtigung der Groß- und Kleinschreibung. Eine Variable `APP_NAME` in Großbuchstaben wird also als Attribut `app_name` gelesen.\n\nAls Nächstes werden die Daten konvertiert und validiert. Wenn Sie also dieses `settings`-Objekt verwenden, verfügen Sie über Daten mit den von Ihnen deklarierten Typen (z. B. ist `items_per_user` ein `int`).\n\n### `settings` verwenden { #use-the-settings }\n\nDann können Sie das neue `settings`-Objekt in Ihrer Anwendung verwenden:\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### Den Server ausführen { #run-the-server }\n\nAls Nächstes würden Sie den Server ausführen und die Konfigurationen als Umgebungsvariablen übergeben. Sie könnten beispielsweise `ADMIN_EMAIL` und `APP_NAME` festlegen mit:\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip | Tipp\n\nUm mehrere Umgebungsvariablen für einen einzelnen Befehl festzulegen, trennen Sie diese einfach durch ein Leerzeichen und fügen Sie alle vor dem Befehl ein.\n\n///\n\nUnd dann würde die Einstellung `admin_email` auf „deadpool@example.com“ gesetzt.\n\nDer `app_name` wäre „ChimichangApp“.\n\nUnd `items_per_user` würde seinen Defaultwert von `50` behalten.\n\n## Einstellungen in einem anderen Modul { #settings-in-another-module }\n\nSie könnten diese Einstellungen in eine andere Moduldatei einfügen, wie Sie in [Größere Anwendungen – mehrere Dateien](../tutorial/bigger-applications.md) gesehen haben.\n\nSie könnten beispielsweise eine Datei `config.py` haben mit:\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\nUnd dann verwenden Sie diese in einer Datei `main.py`:\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip | Tipp\n\nSie benötigen außerdem eine Datei `__init__.py`, wie in [Größere Anwendungen – mehrere Dateien](../tutorial/bigger-applications.md) gesehen.\n\n///\n\n## Einstellungen in einer Abhängigkeit { #settings-in-a-dependency }\n\nIn manchen Fällen kann es nützlich sein, die Einstellungen mit einer Abhängigkeit bereitzustellen, anstatt ein globales Objekt `settings` zu haben, das überall verwendet wird.\n\nDies könnte besonders beim Testen nützlich sein, da es sehr einfach ist, eine Abhängigkeit mit Ihren eigenen benutzerdefinierten Einstellungen zu überschreiben.\n\n### Die Konfigurationsdatei { #the-config-file }\n\nAusgehend vom vorherigen Beispiel könnte Ihre Datei `config.py` so aussehen:\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\nBeachten Sie, dass wir jetzt keine Standardinstanz `settings = Settings()` erstellen.\n\n### Die Haupt-Anwendungsdatei { #the-main-app-file }\n\nJetzt erstellen wir eine Abhängigkeit, die ein neues `config.Settings()` zurückgibt.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip | Tipp\n\nWir werden das `@lru_cache` in Kürze besprechen.\n\nIm Moment nehmen Sie an, dass `get_settings()` eine normale Funktion ist.\n\n///\n\nUnd dann können wir das von der *Pfadoperation-Funktion* als Abhängigkeit einfordern und es überall dort verwenden, wo wir es brauchen.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### Einstellungen und Tests { #settings-and-testing }\n\nDann wäre es sehr einfach, beim Testen ein anderes Einstellungsobjekt bereitzustellen, indem man eine Abhängigkeitsüberschreibung für `get_settings` erstellt:\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\nBei der Abhängigkeitsüberschreibung legen wir einen neuen Wert für `admin_email` fest, wenn wir das neue `Settings`-Objekt erstellen, und geben dann dieses neue Objekt zurück.\n\nDann können wir testen, ob das verwendet wird.\n\n## Lesen einer `.env`-Datei { #reading-a-env-file }\n\nWenn Sie viele Einstellungen haben, die sich möglicherweise oft ändern, vielleicht in verschiedenen Umgebungen, kann es nützlich sein, diese in eine Datei zu schreiben und sie dann daraus zu lesen, als wären sie Umgebungsvariablen.\n\nDiese Praxis ist so weit verbreitet, dass sie einen Namen hat. Diese Umgebungsvariablen werden üblicherweise in einer Datei `.env` abgelegt und die Datei wird „dotenv“ genannt.\n\n/// tip | Tipp\n\nEine Datei, die mit einem Punkt (`.`) beginnt, ist eine versteckte Datei in Unix-ähnlichen Systemen wie Linux und macOS.\n\nAber eine dotenv-Datei muss nicht unbedingt genau diesen Dateinamen haben.\n\n///\n\nPydantic unterstützt das Lesen dieser Dateitypen mithilfe einer externen Bibliothek. Weitere Informationen finden Sie unter [Pydantic Settings: Dotenv (.env) support](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support).\n\n/// tip | Tipp\n\nDamit das funktioniert, müssen Sie `pip install python-dotenv` ausführen.\n\n///\n\n### Die `.env`-Datei { #the-env-file }\n\nSie könnten eine `.env`-Datei haben, mit:\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### Einstellungen aus `.env` lesen { #read-settings-from-env }\n\nUnd dann aktualisieren Sie Ihre `config.py` mit:\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip | Tipp\n\nDas Attribut `model_config` wird nur für die Pydantic-Konfiguration verwendet. Weitere Informationen finden Sie unter [Pydantic: Concepts: Configuration](https://docs.pydantic.dev/latest/concepts/config/).\n\n///\n\nHier definieren wir die Konfiguration `env_file` innerhalb Ihrer Pydantic-`Settings`-Klasse und setzen den Wert auf den Dateinamen mit der dotenv-Datei, die wir verwenden möchten.\n\n### Die `Settings` nur einmal laden mittels `lru_cache` { #creating-the-settings-only-once-with-lru-cache }\n\nDas Lesen einer Datei von der Festplatte ist normalerweise ein kostspieliger (langsamer) Vorgang, daher möchten Sie ihn wahrscheinlich nur einmal ausführen und dann dasselbe Einstellungsobjekt erneut verwenden, anstatt es für jeden <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> zu lesen.\n\nAber jedes Mal, wenn wir ausführen:\n\n```Python\nSettings()\n```\n\nwürde ein neues `Settings`-Objekt erstellt und bei der Erstellung würde die `.env`-Datei erneut ausgelesen.\n\nWenn die Abhängigkeitsfunktion wie folgt wäre:\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\nwürden wir dieses Objekt für jeden Request erstellen und die `.env`-Datei für jeden Request lesen. ⚠️\n\nDa wir jedoch den `@lru_cache`-Dekorator oben verwenden, wird das `Settings`-Objekt nur einmal erstellt, nämlich beim ersten Aufruf. ✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\nDann wird bei allen nachfolgenden Aufrufen von `get_settings()`, in den Abhängigkeiten für darauffolgende Requests, dasselbe Objekt zurückgegeben, das beim ersten Aufruf zurückgegeben wurde, anstatt den Code von `get_settings()` erneut auszuführen und ein neues `Settings`-Objekt zu erstellen.\n\n#### Technische Details zu `lru_cache` { #lru-cache-technical-details }\n\n`@lru_cache` ändert die Funktion, die es dekoriert, dahingehend, denselben Wert zurückzugeben, der beim ersten Mal zurückgegeben wurde, anstatt ihn erneut zu berechnen und den Code der Funktion jedes Mal auszuführen.\n\nDie darunter liegende Funktion wird also für jede Argumentkombination einmal ausgeführt. Und dann werden die von jeder dieser Argumentkombinationen zurückgegebenen Werte immer wieder verwendet, wenn die Funktion mit genau derselben Argumentkombination aufgerufen wird.\n\nWenn Sie beispielsweise eine Funktion haben:\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\nkönnte Ihr Programm so ausgeführt werden:\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Funktion ausführen\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: führe Code der Funktion aus\n        execute ->> code: gib das Resultat zurück\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: gib das gespeicherte Resultat zurück\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: führe Code der Funktion aus\n        execute ->> code: gib das Resultat zurück\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: führe Code der Funktion aus\n        execute ->> code: gib das Resultat zurück\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: gib das gespeicherte Resultat zurück\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: gib das gespeicherte Resultat zurück\n    end\n```\n\nIm Fall unserer Abhängigkeit `get_settings()` akzeptiert die Funktion nicht einmal Argumente, sodass sie immer den gleichen Wert zurückgibt.\n\nAuf diese Weise verhält es sich fast so, als wäre es nur eine globale Variable. Da es jedoch eine Abhängigkeitsfunktion verwendet, können wir diese zu Testzwecken problemlos überschreiben.\n\n`@lru_cache` ist Teil von `functools`, welches Teil von Pythons Standardbibliothek ist. Weitere Informationen dazu finden Sie in der [Python Dokumentation für `@lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache).\n\n## Zusammenfassung { #recap }\n\nMit Pydantic Settings können Sie die Einstellungen oder Konfigurationen für Ihre Anwendung verwalten und dabei die gesamte Leistungsfähigkeit der Pydantic-Modelle nutzen.\n\n* Durch die Verwendung einer Abhängigkeit können Sie das Testen vereinfachen.\n* Sie können `.env`-Dateien damit verwenden.\n* Durch die Verwendung von `@lru_cache` können Sie vermeiden, die dotenv-Datei bei jedem Request erneut zu lesen, während Sie sie während des Testens überschreiben können.\n"
  },
  {
    "path": "docs/de/docs/advanced/stream-data.md",
    "content": "# Daten streamen { #stream-data }\n\nWenn Sie Daten streamen möchten, die als JSON strukturiert werden können, sollten Sie [JSON Lines streamen](../tutorial/stream-json-lines.md).\n\nWenn Sie jedoch **reine Binärdaten** oder Strings streamen möchten, so können Sie es machen.\n\n/// info | Info\n\nHinzugefügt in FastAPI 0.134.0.\n\n///\n\n## Anwendungsfälle { #use-cases }\n\nSie könnten dies verwenden, wenn Sie reine Strings streamen möchten, z. B. direkt aus der Ausgabe eines **AI-LLM**-Dienstes.\n\nSie könnten es auch nutzen, um **große Binärdateien** zu streamen, wobei Sie jeden Datenchunk beim Lesen streamen, ohne alles auf einmal in den Speicher laden zu müssen.\n\nSie könnten auf diese Weise auch **Video** oder **Audio** streamen, es könnte sogar beim Verarbeiten erzeugt und gesendet werden.\n\n## Eine `StreamingResponse` mit `yield` { #a-streamingresponse-with-yield }\n\nWenn Sie in Ihrer Pfadoperation-Funktion ein `response_class=StreamingResponse` deklarieren, können Sie `yield` verwenden, um nacheinander jeden Datenchunk zu senden.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI übergibt jeden Datenchunk unverändert an die `StreamingResponse`, es wird nicht versucht, ihn in JSON oder etwas Ähnliches zu konvertieren.\n\n### Nicht-async-Pfadoperation-Funktionen { #non-async-path-operation-functions }\n\nSie können auch reguläre `def`-Funktionen (ohne `async`) verwenden und `yield` auf die gleiche Weise einsetzen.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### Keine Annotation { #no-annotation }\n\nSie müssen den Rückgabetyp für das Streamen von Binärdaten nicht wirklich annotieren.\n\nDa FastAPI die Daten nicht mit Pydantic in JSON umzuwandeln oder sie anderweitig zu serialisieren versucht, ist die Typannotation hier nur für Ihren Editor und Tools relevant, sie wird von FastAPI nicht verwendet.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\nDas bedeutet auch, dass Sie mit `StreamingResponse` die **Freiheit** und **Verantwortung** haben, die Datenbytes genau so zu erzeugen und zu encodieren, wie sie gesendet werden sollen, unabhängig von den Typannotationen. 🤓\n\n### Bytes streamen { #stream-bytes }\n\nEiner der Hauptanwendungsfälle wäre, `bytes` statt Strings zu streamen, das können Sie selbstverständlich tun.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## Eine benutzerdefinierte `PNGStreamingResponse` { #a-custom-pngstreamingresponse }\n\nIn den obigen Beispielen wurden die Datenbytes gestreamt, aber die Response hatte keinen `Content-Type`-Header, sodass der Client nicht wusste, welchen Datentyp er erhielt.\n\nSie können eine benutzerdefinierte Unterklasse von `StreamingResponse` erstellen, die den `Content-Type`-Header auf den Typ der gestreamten Daten setzt.\n\nZum Beispiel können Sie eine `PNGStreamingResponse` erstellen, die den `Content-Type`-Header mit dem Attribut `media_type` auf `image/png` setzt:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\nDann können Sie diese neue Klasse mit `response_class=PNGStreamingResponse` in Ihrer Pfadoperation-Funktion verwenden:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### Eine Datei simulieren { #simulate-a-file }\n\nIn diesem Beispiel simulieren wir eine Datei mit `io.BytesIO`, einem dateiähnlichen Objekt, das nur im Speicher lebt, uns aber dieselbe Schnittstelle nutzen lässt.\n\nWir können z. B. darüber iterieren, um seinen Inhalt zu konsumieren, so wie bei einer Datei.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | Technische Details\n\nDie anderen beiden Variablen, `image_base64` und `binary_image`, sind ein in Base64 encodiertes Bild, dann in Bytes konvertiert, um es anschließend an `io.BytesIO` zu übergeben.\n\nNur damit es in derselben Datei leben kann, für dieses Beispiel, und Sie es unverändert kopieren und ausführen können. 🥚\n\n///\n\nMit einem `with`-Block stellen wir sicher, dass das dateiähnliche Objekt geschlossen wird, nachdem die Generatorfunktion (die Funktion mit `yield`) fertig ist. Also nachdem die Response gesendet wurde.\n\nIn diesem speziellen Beispiel wäre das nicht so wichtig, weil es sich um eine unechte In-Memory-Datei (mit `io.BytesIO`) handelt, aber bei einer echten Datei wäre es wichtig sicherzustellen, dass die Datei nach der Arbeit damit geschlossen wird.\n\n### Dateien und Async { #files-and-async }\n\nIn den meisten Fällen sind dateiähnliche Objekte standardmäßig nicht mit async und await kompatibel.\n\nBeispielsweise haben sie kein `await file.read()` oder `async for chunk in file`.\n\nUnd in vielen Fällen wäre das Lesen eine blockierende Operation (die die Event-Loop blockieren könnte), weil von der Festplatte oder aus dem Netzwerk gelesen wird.\n\n/// info | Info\n\nDas obige Beispiel ist tatsächlich eine Ausnahme, weil sich das `io.BytesIO`-Objekt bereits im Speicher befindet, daher blockiert sein Lesen nichts.\n\nAber in vielen Fällen würde das Lesen einer Datei oder eines dateiähnlichen Objekts blockieren.\n\n///\n\nUm die Event-Loop nicht zu blockieren, können Sie die Pfadoperation-Funktion einfach mit normalem `def` statt `async def` deklarieren, dadurch führt FastAPI sie in einem Threadpool-Worker aus, um die Haupt-Event-Loop nicht zu blockieren.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip | Tipp\n\nWenn Sie blockierenden Code aus einer async-Funktion heraus aufrufen müssen, oder eine async-Funktion aus einer blockierenden Funktion, könnten Sie [Asyncer](https://asyncer.tiangolo.com), eine Schwesterbibliothek zu FastAPI, verwenden.\n\n///\n\n### `yield from` { #yield-from }\n\nWenn Sie über etwas iterieren, z. B. ein dateiähnliches Objekt, und dann für jedes Element `yield` verwenden, könnten Sie auch `yield from` verwenden, um jedes Element direkt weiterzugeben und die `for`-Schleife zu sparen.\n\nDas ist nichts Spezifisches an FastAPI, das ist einfach Python, aber ein netter Trick. 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/de/docs/advanced/strict-content-type.md",
    "content": "# Strikte Content-Type-Prüfung { #strict-content-type-checking }\n\nStandardmäßig verwendet **FastAPI** eine strikte Prüfung des `Content-Type`-Headers für JSON-Requestbodys. Das bedeutet, dass JSON-Requests einen gültigen `Content-Type`-Header (z. B. `application/json`) enthalten MÜSSEN, damit der Body als JSON geparst wird.\n\n## CSRF-Risiko { #csrf-risk }\n\nDieses Standardverhalten schützt vor einer Klasse von **Cross-Site Request Forgery (CSRF)**-Angriffen in einem sehr spezifischen Szenario.\n\nDiese Angriffe nutzen aus, dass Browser Skripte Requests senden lassen, ohne einen CORS-Preflight-Check durchzuführen, wenn sie:\n\n* keinen `Content-Type`-Header haben (z. B. mit `fetch()` und einem `Blob`-Body)\n* und keine Authentifizierungsdaten senden.\n\nDiese Art von Angriff ist vor allem relevant, wenn:\n\n* die Anwendung lokal läuft (z. B. auf `localhost`) oder in einem internen Netzwerk\n* und die Anwendung keine Authentifizierung hat, sondern erwartet, dass jeder Request aus demselben Netzwerk vertrauenswürdig ist.\n\n## Beispielangriff { #example-attack }\n\nStellen Sie sich vor, Sie bauen eine Möglichkeit, lokal einen KI-Agenten auszuführen.\n\nEr stellt eine API bereit unter\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nEs gibt auch ein Frontend unter\n\n```\nhttp://localhost:8000\n```\n\n/// tip | Tipp\n\nBeachten Sie, dass beide denselben Host haben.\n\n///\n\nDann können Sie über das Frontend den KI-Agenten Dinge in Ihrem Namen erledigen lassen.\n\nDa er **lokal** läuft und nicht im offenen Internet, entscheiden Sie sich, **keine Authentifizierung** einzurichten und vertrauen stattdessen einfach auf den Zugriff im lokalen Netzwerk.\n\nDann könnte einer Ihrer Benutzer es installieren und lokal ausführen.\n\nAnschließend könnte er eine bösartige Website öffnen, z. B. so etwas wie\n\n```\nhttps://evilhackers.example.com\n```\n\nUnd diese bösartige Website sendet Requests mit `fetch()` und einem `Blob`-Body an die lokale API unter\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nObwohl der Host der bösartigen Website und der lokalen App unterschiedlich ist, löst der Browser keinen CORS-Preflight-Request aus, weil:\n\n* sie ohne Authentifizierung läuft, es müssen keine Credentials gesendet werden.\n* der Browser annimmt, dass kein JSON gesendet wird (wegen des fehlenden `Content-Type`-Headers).\n\nDann könnte die bösartige Website den lokalen KI-Agenten dazu bringen, wütende Nachrichten an den Ex-Chef des Benutzers zu schicken ... oder Schlimmeres. 😅\n\n## Offenes Internet { #open-internet }\n\nWenn Ihre App im offenen Internet läuft, würden Sie nicht „dem Netzwerk vertrauen“ und jedem erlauben, privilegierte Requests ohne Authentifizierung zu senden.\n\nAngreifer könnten einfach ein Skript ausführen, um Requests an Ihre API zu senden, es ist keine Browserinteraktion nötig. Daher sichern Sie wahrscheinlich schon alle privilegierten Endpunkte.\n\nIn diesem Fall gilt **dieser Angriff / dieses Risiko nicht für Sie**.\n\nDieses Risiko und dieser Angriff sind vor allem relevant, wenn die App im **lokalen Netzwerk** läuft und das die **einzige angenommene Schutzmaßnahme** ist.\n\n## Requests ohne Content-Type erlauben { #allowing-requests-without-content-type }\n\nWenn Sie Clients unterstützen müssen, die keinen `Content-Type`-Header senden, können Sie die strikte Prüfung deaktivieren, indem Sie `strict_content_type=False` setzen:\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\nMit dieser Einstellung werden Requests ohne `Content-Type`-Header im Body als JSON geparst. Das entspricht dem Verhalten älterer FastAPI-Versionen.\n\n/// info | Info\n\nDieses Verhalten und diese Konfiguration wurden in FastAPI 0.132.0 hinzugefügt.\n\n///\n"
  },
  {
    "path": "docs/de/docs/advanced/sub-applications.md",
    "content": "# Unteranwendungen – Mounts { #sub-applications-mounts }\n\nWenn Sie zwei unabhängige FastAPI-Anwendungen mit deren eigenen unabhängigen OpenAPI und deren eigenen Dokumentationsoberflächen benötigen, können Sie eine Hauptanwendung haben und dann eine (oder mehrere) Unteranwendung(en) „mounten“.\n\n## Eine **FastAPI**-Anwendung mounten { #mounting-a-fastapi-application }\n\n„Mounten“ („Einhängen“) bedeutet das Hinzufügen einer völlig „unabhängigen“ Anwendung an einem bestimmten Pfad, die sich dann um die Handhabung aller unter diesem Pfad liegenden _Pfadoperationen_ kümmert, welche in dieser Unteranwendung deklariert sind.\n\n### Hauptanwendung { #top-level-application }\n\nErstellen Sie zunächst die Hauptanwendung **FastAPI** und deren *Pfadoperationen*:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### Unteranwendung { #sub-application }\n\nErstellen Sie dann Ihre Unteranwendung und deren *Pfadoperationen*.\n\nDiese Unteranwendung ist nur eine weitere Standard-FastAPI-Anwendung, aber diese wird „gemountet“:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### Die Unteranwendung mounten { #mount-the-sub-application }\n\nMounten Sie in Ihrer Top-Level-Anwendung `app` die Unteranwendung `subapi`.\n\nIn diesem Fall wird sie im Pfad `/subapi` gemountet:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### Die automatische API-Dokumentation testen { #check-the-automatic-api-docs }\n\nFühren Sie nun den Befehl `fastapi` aus:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nUnd öffnen Sie die Dokumentation unter [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nSie sehen die automatische API-Dokumentation für die Hauptanwendung, welche nur deren eigene _Pfadoperationen_ anzeigt:\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\nÖffnen Sie dann die Dokumentation für die Unteranwendung unter [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs).\n\nSie sehen die automatische API-Dokumentation für die Unteranwendung, welche nur deren eigene _Pfadoperationen_ anzeigt, alle unter dem korrekten Unterpfad-Präfix `/subapi`:\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\nWenn Sie versuchen, mit einer der beiden Benutzeroberflächen zu interagieren, funktionieren diese ordnungsgemäß, da der Browser mit jeder spezifischen Anwendung oder Unteranwendung kommunizieren kann.\n\n### Technische Details: `root_path` { #technical-details-root-path }\n\nWenn Sie eine Unteranwendung wie oben beschrieben mounten, kümmert sich FastAPI darum, den Mount-Pfad für die Unteranwendung zu kommunizieren, mithilfe eines Mechanismus aus der ASGI-Spezifikation namens `root_path`.\n\nAuf diese Weise weiß die Unteranwendung, dass sie dieses Pfadpräfix für die Benutzeroberfläche der Dokumentation verwenden soll.\n\nUnd die Unteranwendung könnte auch ihre eigenen gemounteten Unteranwendungen haben und alles würde korrekt funktionieren, da FastAPI sich um alle diese `root_path`s automatisch kümmert.\n\nMehr über den `root_path` und dessen explizite Verwendung erfahren Sie im Abschnitt [Hinter einem Proxy](behind-a-proxy.md).\n"
  },
  {
    "path": "docs/de/docs/advanced/templates.md",
    "content": "# Templates { #templates }\n\nSie können jede gewünschte Template-Engine mit **FastAPI** verwenden.\n\nEine häufige Wahl ist Jinja2, dasselbe, was auch von Flask und anderen Tools verwendet wird.\n\nEs gibt Werkzeuge zur einfachen Konfiguration, die Sie direkt in Ihrer **FastAPI**-Anwendung verwenden können (bereitgestellt von Starlette).\n\n## Abhängigkeiten installieren { #install-dependencies }\n\nStellen Sie sicher, dass Sie eine [virtuelle Umgebung](../virtual-environments.md) erstellen, sie aktivieren und `jinja2` installieren:\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## `Jinja2Templates` verwenden { #using-jinja2templates }\n\n* Importieren Sie `Jinja2Templates`.\n* Erstellen Sie ein `templates`-Objekt, das Sie später wiederverwenden können.\n* Deklarieren Sie einen `<abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr>`-Parameter in der *Pfadoperation*, welcher ein Template zurückgibt.\n* Verwenden Sie die von Ihnen erstellten `templates`, um eine `TemplateResponse` zu rendern und zurückzugeben, übergeben Sie den Namen des Templates, das Requestobjekt und ein „Kontext“-<abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">Dictionary</abbr> mit Schlüssel-Wert-Paaren, die innerhalb des Jinja2-Templates verwendet werden sollen.\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note | Hinweis\n\nVor FastAPI 0.108.0 und Starlette 0.29.0 war `name` der erste Parameter.\n\nAußerdem wurde in früheren Versionen das `request`-Objekt als Teil der Schlüssel-Wert-Paare im Kontext für Jinja2 übergeben.\n\n///\n\n/// tip | Tipp\n\nDurch die Deklaration von `response_class=HTMLResponse` kann die Dokumentationsoberfläche erkennen, dass die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> HTML sein wird.\n\n///\n\n/// note | Technische Details\n\nSie können auch `from starlette.templating import Jinja2Templates` verwenden.\n\n**FastAPI** bietet dasselbe `starlette.templating` auch via `fastapi.templating` an, als Annehmlichkeit für Sie, den Entwickler. Aber die meisten der verfügbaren Responses kommen direkt von Starlette. Das Gleiche gilt für `Request` und `StaticFiles`.\n\n///\n\n## Templates erstellen { #writing-templates }\n\nDann können Sie unter `templates/item.html` ein Template erstellen, mit z. B. folgendem Inhalt:\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### Template-Kontextwerte { #template-context-values }\n\nIm HTML, welches enthält:\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n... wird die `id` angezeigt, welche dem „Kontext“-`dict` entnommen wird, welches Sie übergeben haben:\n\n```Python\n{\"id\": id}\n```\n\nMit beispielsweise einer ID `42` würde das wie folgt gerendert werden:\n\n```html\nItem ID: 42\n```\n\n### Template-`url_for`-Argumente { #template-url-for-arguments }\n\nSie können `url_for()` auch innerhalb des Templates verwenden, es nimmt als Argumente dieselben Argumente, die von Ihrer *Pfadoperation-Funktion* verwendet werden.\n\nDer Abschnitt mit:\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n... generiert also einen Link zu derselben URL, welche von der *Pfadoperation-Funktion* `read_item(id=id)` gehandhabt werden würde.\n\nMit beispielsweise der ID `42` würde dies Folgendes ergeben:\n\n```html\n<a href=\"/items/42\">\n```\n\n## Templates und statische Dateien { #templates-and-static-files }\n\nSie können `url_for()` innerhalb des Templates auch beispielsweise mit den `StaticFiles` verwenden, die Sie mit `name=\"static\"` gemountet haben.\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\nIn diesem Beispiel würde das zu einer CSS-Datei unter `static/styles.css` verlinken, mit folgendem Inhalt:\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\nUnd da Sie `StaticFiles` verwenden, wird diese CSS-Datei automatisch von Ihrer **FastAPI**-Anwendung unter der URL `/static/styles.css` ausgeliefert.\n\n## Mehr Details { #more-details }\n\nWeitere Informationen, einschließlich, wie man Templates testet, finden Sie in [Starlettes Dokumentation zu Templates](https://www.starlette.dev/templates/).\n"
  },
  {
    "path": "docs/de/docs/advanced/testing-dependencies.md",
    "content": "# Testen mit Überschreibungen für Abhängigkeiten { #testing-dependencies-with-overrides }\n\n## Abhängigkeiten beim Testen überschreiben { #overriding-dependencies-during-testing }\n\nEs gibt einige Szenarien, in denen Sie beim Testen möglicherweise eine Abhängigkeit überschreiben möchten.\n\nSie möchten nicht, dass die ursprüngliche Abhängigkeit ausgeführt wird (und auch keine der möglicherweise vorhandenen Unterabhängigkeiten).\n\nStattdessen möchten Sie eine andere Abhängigkeit bereitstellen, die nur während Tests (möglicherweise nur bei einigen bestimmten Tests) verwendet wird und einen Wert bereitstellt, der dort verwendet werden kann, wo der Wert der ursprünglichen Abhängigkeit verwendet wurde.\n\n### Anwendungsfälle: Externer Service { #use-cases-external-service }\n\nEin Beispiel könnte sein, dass Sie einen externen Authentifizierungsanbieter haben, mit dem Sie sich verbinden müssen.\n\nSie senden ihm ein Token und er gibt einen authentifizierten Benutzer zurück.\n\nDieser Anbieter berechnet Ihnen möglicherweise Gebühren pro <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr>, und der Aufruf könnte etwas länger dauern, als wenn Sie einen vordefinierten <abbr title=\"Platzhalter, vorgetäuscht, zum Schein\">Mock</abbr>-Benutzer für Tests hätten.\n\nSie möchten den externen Anbieter wahrscheinlich einmal testen, ihn aber nicht unbedingt bei jedem weiteren ausgeführten Test aufrufen.\n\nIn diesem Fall können Sie die Abhängigkeit, die diesen Anbieter aufruft, überschreiben und eine benutzerdefinierte Abhängigkeit verwenden, die einen Mock-Benutzer zurückgibt, nur für Ihre Tests.\n\n### Das Attribut `app.dependency_overrides` verwenden { #use-the-app-dependency-overrides-attribute }\n\nFür diese Fälle verfügt Ihre **FastAPI**-Anwendung über das Attribut `app.dependency_overrides`, bei diesem handelt sich um ein einfaches <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr>.\n\nUm eine Abhängigkeit für das Testen zu überschreiben, geben Sie als Schlüssel die ursprüngliche Abhängigkeit (eine Funktion) und als Wert Ihre Überschreibung der Abhängigkeit (eine andere Funktion) ein.\n\nUnd dann ruft **FastAPI** diese Überschreibung anstelle der ursprünglichen Abhängigkeit auf.\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip | Tipp\n\nSie können eine Überschreibung für eine Abhängigkeit festlegen, die an einer beliebigen Stelle in Ihrer **FastAPI**-Anwendung verwendet wird.\n\nDie ursprüngliche Abhängigkeit könnte in einer *Pfadoperation-Funktion*, einem *Pfadoperation-Dekorator* (wenn Sie den Rückgabewert nicht verwenden), einem `.include_router()`-Aufruf, usw. verwendet werden.\n\nFastAPI kann sie in jedem Fall überschreiben.\n\n///\n\nAnschließend können Sie Ihre Überschreibungen zurücksetzen (entfernen), indem Sie `app.dependency_overrides` auf ein leeres `dict` setzen:\n\n```Python\napp.dependency_overrides = {}\n```\n\n\n/// tip | Tipp\n\nWenn Sie eine Abhängigkeit nur während einiger Tests überschreiben möchten, können Sie die Überschreibung zu Beginn des Tests (innerhalb der Testfunktion) festlegen und am Ende (am Ende der Testfunktion) zurücksetzen.\n\n///\n"
  },
  {
    "path": "docs/de/docs/advanced/testing-events.md",
    "content": "# Events testen: Lifespan und Startup – Shutdown { #testing-events-lifespan-and-startup-shutdown }\n\nWenn Sie `lifespan` in Ihren Tests ausführen müssen, können Sie den `TestClient` mit einer `with`-Anweisung verwenden:\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\n\nSie können mehr Details unter [„Lifespan in Tests ausführen in der offiziellen Starlette-Dokumentation.“](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) nachlesen.\n\nFür die deprecateten Events <abbr title=\"Hochfahren\">`startup`</abbr> und <abbr title=\"Herunterfahren\">`shutdown`</abbr> können Sie den `TestClient` wie folgt verwenden:\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/de/docs/advanced/testing-websockets.md",
    "content": "# WebSockets testen { #testing-websockets }\n\nSie können denselben `TestClient` zum Testen von WebSockets verwenden.\n\nDazu verwenden Sie den `TestClient` in einer `with`-Anweisung, eine Verbindung zum WebSocket herstellend:\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note | Hinweis\n\nWeitere Informationen finden Sie in Starlettes Dokumentation zum [Testen von WebSockets](https://www.starlette.dev/testclient/#testing-websocket-sessions).\n\n///\n"
  },
  {
    "path": "docs/de/docs/advanced/using-request-directly.md",
    "content": "# Den Request direkt verwenden { #using-the-request-directly }\n\nBisher haben Sie die Teile des <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr>, die Sie benötigen, mithilfe von deren Typen deklariert.\n\nDaten nehmend von:\n\n* Dem Pfad als Parameter.\n* Headern.\n* Cookies.\n* usw.\n\nUnd indem Sie das tun, validiert **FastAPI** diese Daten, konvertiert sie und generiert automatisch Dokumentation für Ihre API.\n\nEs gibt jedoch Situationen, in denen Sie möglicherweise direkt auf das `Request`-Objekt zugreifen müssen.\n\n## Details zum `Request`-Objekt { #details-about-the-request-object }\n\nDa **FastAPI** unter der Haube eigentlich **Starlette** ist, mit einer Ebene von mehreren Tools darüber, können Sie Starlettes [`Request`](https://www.starlette.dev/requests/)-Objekt direkt verwenden, wenn Sie es benötigen.\n\nDas bedeutet allerdings auch, dass, wenn Sie Daten direkt vom `Request`-Objekt nehmen (z. B. dessen Body lesen), diese von FastAPI nicht validiert, konvertiert oder dokumentiert werden (mit OpenAPI, für die automatische API-Benutzeroberfläche).\n\nObwohl jeder andere normal deklarierte Parameter (z. B. der Body, mit einem Pydantic-Modell) dennoch validiert, konvertiert, annotiert, usw. werden würde.\n\nEs gibt jedoch bestimmte Fälle, in denen es nützlich ist, auf das `Request`-Objekt zuzugreifen.\n\n## Das `Request`-Objekt direkt verwenden { #use-the-request-object-directly }\n\nAngenommen, Sie möchten auf die IP-Adresse/den Host des Clients in Ihrer *Pfadoperation-Funktion* zugreifen.\n\nDazu müssen Sie direkt auf den Request zugreifen.\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\nDurch die Deklaration eines *Pfadoperation-Funktionsparameters*, dessen Typ der `Request` ist, weiß **FastAPI**, dass es den `Request` diesem Parameter übergeben soll.\n\n/// tip | Tipp\n\nBeachten Sie, dass wir in diesem Fall einen Pfad-Parameter zusätzlich zum Request-Parameter deklarieren.\n\nDer Pfad-Parameter wird also extrahiert, validiert, in den spezifizierten Typ konvertiert und mit OpenAPI annotiert.\n\nAuf die gleiche Weise können Sie wie gewohnt jeden anderen Parameter deklarieren und zusätzlich auch den `Request` erhalten.\n\n///\n\n## `Request`-Dokumentation { #request-documentation }\n\nWeitere Details zum [`Request`-Objekt auf der offiziellen Starlette-Dokumentationsseite](https://www.starlette.dev/requests/).\n\n/// note | Technische Details\n\nSie können auch `from starlette.requests import Request` verwenden.\n\n**FastAPI** stellt es direkt zur Verfügung, als Komfort für Sie, den Entwickler. Es kommt aber direkt von Starlette.\n\n///\n"
  },
  {
    "path": "docs/de/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\nSie können [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) mit **FastAPI** verwenden.\n\n## `websockets` installieren { #install-websockets }\n\nStellen Sie sicher, dass Sie eine [virtuelle Umgebung](../virtual-environments.md) erstellen, sie aktivieren und `websockets` installieren (eine Python-Bibliothek, die die Verwendung des „WebSocket“-Protokolls erleichtert):\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## WebSockets-Client { #websockets-client }\n\n### In Produktion { #in-production }\n\nIn Ihrem Produktionssystem haben Sie wahrscheinlich ein Frontend, das mit einem modernen Framework wie React, Vue.js oder Angular erstellt wurde.\n\nUnd um über WebSockets mit Ihrem Backend zu kommunizieren, würden Sie wahrscheinlich die Werkzeuge Ihres Frontends verwenden.\n\nOder Sie verfügen möglicherweise über eine native Mobile-Anwendung, die direkt in nativem Code mit Ihrem WebSocket-Backend kommuniziert.\n\nOder Sie haben andere Möglichkeiten, mit dem WebSocket-Endpunkt zu kommunizieren.\n\n---\n\nFür dieses Beispiel verwenden wir jedoch ein sehr einfaches HTML-Dokument mit etwas JavaScript, alles in einem langen String.\n\nDas ist natürlich nicht optimal und man würde das nicht in der Produktion machen.\n\nIn der Produktion hätten Sie eine der oben genannten Optionen.\n\nAber es ist der einfachste Weg, sich auf die Serverseite von WebSockets zu konzentrieren und ein funktionierendes Beispiel zu haben:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## Einen `websocket` erstellen { #create-a-websocket }\n\nErstellen Sie in Ihrer **FastAPI**-Anwendung einen `websocket`:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | Technische Details\n\nSie könnten auch `from starlette.websockets import WebSocket` verwenden.\n\n**FastAPI** stellt den gleichen `WebSocket` direkt zur Verfügung, als Annehmlichkeit für Sie, den Entwickler. Er kommt aber direkt von Starlette.\n\n///\n\n## Nachrichten erwarten und Nachrichten senden { #await-for-messages-and-send-messages }\n\nIn Ihrer WebSocket-Route können Sie Nachrichten `await`en und Nachrichten senden.\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\nSie können Binär-, Text- und JSON-Daten empfangen und senden.\n\n## Es ausprobieren { #try-it }\n\nLegen Sie Ihren Code in einer Datei `main.py` ab und führen Sie dann Ihre Anwendung aus:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nÖffnen Sie Ihren Browser unter [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nSie sehen eine einfache Seite wie:\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\nSie können Nachrichten in das Eingabefeld tippen und absenden:\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\nUnd Ihre **FastAPI**-Anwendung mit WebSockets antwortet:\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\nSie können viele Nachrichten senden (und empfangen):\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\nUnd alle verwenden dieselbe WebSocket-Verbindung.\n\n## Verwendung von `Depends` und anderen { #using-depends-and-others }\n\nIn WebSocket-Endpunkten können Sie Folgendes aus `fastapi` importieren und verwenden:\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\nDiese funktionieren auf die gleiche Weise wie für andere FastAPI-Endpunkte/*Pfadoperationen*:\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info | Info\n\nDa es sich um einen WebSocket handelt, macht es keinen Sinn, eine `HTTPException` auszulösen, stattdessen lösen wir eine `WebSocketException` aus.\n\nSie können einen „Closing“-Code verwenden, aus den [gültigen Codes, die in der Spezifikation definiert sind](https://tools.ietf.org/html/rfc6455#section-7.4.1).\n\n///\n\n### WebSockets mit Abhängigkeiten ausprobieren { #try-the-websockets-with-dependencies }\n\nFühren Sie Ihre Anwendung aus:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nÖffnen Sie Ihren Browser unter [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nDort können Sie einstellen:\n\n* Die „Item ID“, die im Pfad verwendet wird.\n* Das „Token“, das als Query-Parameter verwendet wird.\n\n/// tip | Tipp\n\nBeachten Sie, dass die Query `token` von einer Abhängigkeit verarbeitet wird.\n\n///\n\nDamit können Sie den WebSocket verbinden und dann Nachrichten senden und empfangen:\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## Verbindungsabbrüche und mehrere Clients handhaben { #handling-disconnections-and-multiple-clients }\n\nWenn eine WebSocket-Verbindung geschlossen wird, löst `await websocket.receive_text()` eine `WebSocketDisconnect`-Exception aus, die Sie dann wie in folgendem Beispiel abfangen und behandeln können.\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\nZum Ausprobieren:\n\n* Öffnen Sie die Anwendung mit mehreren Browser-Tabs.\n* Schreiben Sie Nachrichten in den Tabs.\n* Schließen Sie dann einen der Tabs.\n\nDas wird die Ausnahme `WebSocketDisconnect` auslösen und alle anderen Clients erhalten eine Nachricht wie:\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip | Tipp\n\nDie obige Anwendung ist ein minimales und einfaches Beispiel, das zeigt, wie Nachrichten verarbeitet und an mehrere WebSocket-Verbindungen gesendet werden.\n\nBeachten Sie jedoch, dass, da alles nur im Speicher in einer einzigen Liste verwaltet wird, es nur funktioniert, während der Prozess ausgeführt wird, und nur mit einem einzelnen Prozess.\n\nWenn Sie etwas benötigen, das sich leicht in FastAPI integrieren lässt, aber robuster ist und von Redis, PostgreSQL und anderen unterstützt wird, sehen Sie sich [encode/broadcaster](https://github.com/encode/broadcaster) an.\n\n///\n\n## Mehr Informationen { #more-info }\n\nWeitere Informationen zu Optionen finden Sie in der Dokumentation von Starlette:\n\n* [Die `WebSocket`-Klasse](https://www.starlette.dev/websockets/).\n* [Klassen-basierte Handhabung von WebSockets](https://www.starlette.dev/endpoints/#websocketendpoint).\n"
  },
  {
    "path": "docs/de/docs/advanced/wsgi.md",
    "content": "# WSGI inkludieren – Flask, Django und andere { #including-wsgi-flask-django-others }\n\nSie können WSGI-Anwendungen mounten, wie Sie es in [Unteranwendungen – Mounts](sub-applications.md), [Hinter einem Proxy](behind-a-proxy.md) gesehen haben.\n\nDazu können Sie die `WSGIMiddleware` verwenden und damit Ihre WSGI-Anwendung wrappen, zum Beispiel Flask, Django usw.\n\n## `WSGIMiddleware` verwenden { #using-wsgimiddleware }\n\n/// info | Info\n\nDafür muss `a2wsgi` installiert sein, z. B. mit `pip install a2wsgi`.\n\n///\n\nSie müssen `WSGIMiddleware` aus `a2wsgi` importieren.\n\nWrappen Sie dann die WSGI-Anwendung (z. B. Flask) mit der Middleware.\n\nUnd dann mounten Sie das auf einem Pfad.\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note | Hinweis\n\nFrüher wurde empfohlen, `WSGIMiddleware` aus `fastapi.middleware.wsgi` zu verwenden, dies ist jetzt deprecatet.\n\nStattdessen wird empfohlen, das Paket `a2wsgi` zu verwenden. Die Nutzung bleibt gleich.\n\nStellen Sie lediglich sicher, dass das Paket `a2wsgi` installiert ist und importieren Sie `WSGIMiddleware` korrekt aus `a2wsgi`.\n\n///\n\n## Es testen { #check-it }\n\nJetzt wird jeder <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> unter dem Pfad `/v1/` von der Flask-Anwendung verarbeitet.\n\nUnd der Rest wird von **FastAPI** gehandhabt.\n\nWenn Sie das ausführen und auf [http://localhost:8000/v1/](http://localhost:8000/v1/) gehen, sehen Sie die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> von Flask:\n\n```txt\nHello, World from Flask!\n```\n\nUnd wenn Sie auf [http://localhost:8000/v2](http://localhost:8000/v2) gehen, sehen Sie die Response von FastAPI:\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/de/docs/alternatives.md",
    "content": "# Alternativen, Inspiration und Vergleiche { #alternatives-inspiration-and-comparisons }\n\nWas hat **FastAPI** inspiriert, wie es sich im Vergleich zu Alternativen verhält und was es von ihnen gelernt hat.\n\n## Einführung { #intro }\n\n**FastAPI** würde ohne die frühere Arbeit anderer nicht existieren.\n\nEs wurden zuvor viele Tools entwickelt, die als Inspiration für seine Entwicklung dienten.\n\nIch habe die Schaffung eines neuen Frameworks viele Jahre lang vermieden. Zuerst habe ich versucht, alle von **FastAPI** abgedeckten Funktionen mithilfe vieler verschiedener Frameworks, Plugins und Tools zu lösen.\n\nAber irgendwann gab es keine andere Möglichkeit, als etwas zu schaffen, das all diese Funktionen bereitstellte, die besten Ideen früherer Tools aufnahm und diese auf die bestmögliche Weise kombinierte, wobei Sprachfunktionen verwendet wurden, die vorher noch nicht einmal verfügbar waren (Python 3.6+ Typhinweise).\n\n## Vorherige Tools { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\nEs ist das beliebteste Python-Framework und genießt großes Vertrauen. Es wird zum Aufbau von Systemen wie Instagram verwendet.\n\nEs ist relativ eng mit relationalen Datenbanken (wie MySQL oder PostgreSQL) gekoppelt, daher ist es nicht sehr einfach, eine NoSQL-Datenbank (wie Couchbase, MongoDB, Cassandra, usw.) als Hauptspeicherengine zu verwenden.\n\nEs wurde erstellt, um den HTML-Code im Backend zu generieren, nicht um APIs zu erstellen, die von einem modernen Frontend (wie React, Vue.js und Angular) oder von anderen Systemen (wie <abbr title=\"Internet of Things - Internet der Dinge\">IoT</abbr>-Geräten) verwendet werden, um mit ihm zu kommunizieren.\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nDas Django REST Framework wurde als flexibles Toolkit zum Erstellen von Web-APIs unter Verwendung von Django entwickelt, um dessen API-Möglichkeiten zu verbessern.\n\nEs wird von vielen Unternehmen verwendet, darunter Mozilla, Red Hat und Eventbrite.\n\nEs war eines der ersten Beispiele für **automatische API-Dokumentation**, und dies war insbesondere eine der ersten Ideen, welche „die Suche nach“ **FastAPI** inspirierten.\n\n/// note | Hinweis\n\nDas Django REST Framework wurde von Tom Christie erstellt. Derselbe Schöpfer von Starlette und Uvicorn, auf denen **FastAPI** basiert.\n\n///\n\n/// check | Inspirierte **FastAPI**\n\nEine automatische API-Dokumentationsoberfläche zu haben.\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask ist ein „Mikroframework“, es enthält weder Datenbankintegration noch viele der Dinge, die standardmäßig in Django enthalten sind.\n\nDiese Einfachheit und Flexibilität ermöglichen beispielsweise die Verwendung von NoSQL-Datenbanken als Hauptdatenspeichersystem.\n\nDa es sehr einfach ist, ist es relativ intuitiv zu erlernen, obwohl die Dokumentation an einigen Stellen etwas technisch wird.\n\nEs wird auch häufig für andere Anwendungen verwendet, die nicht unbedingt eine Datenbank, Benutzerverwaltung oder eine der vielen in Django enthaltenen Funktionen benötigen. Obwohl viele dieser Funktionen mit Plugins hinzugefügt werden können.\n\nDiese Entkopplung der Teile und die Tatsache, dass es sich um ein „Mikroframework“ handelt, welches so erweitert werden kann, dass es genau das abdeckt, was benötigt wird, war ein Schlüsselmerkmal, das ich beibehalten wollte.\n\nAngesichts der Einfachheit von Flask schien es eine gute Ergänzung zum Erstellen von APIs zu sein. Als Nächstes musste ein „Django REST Framework“ für Flask gefunden werden.\n\n/// check | Inspirierte **FastAPI**\n\nEin Mikroframework zu sein. Es einfach zu machen, die benötigten Tools und Teile zu kombinieren.\n\nÜber ein einfaches und benutzerfreundliches Routingsystem zu verfügen.\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI** ist eigentlich keine Alternative zu **Requests**. Der Umfang der beiden ist sehr unterschiedlich.\n\nEs wäre tatsächlich üblich, Requests *innerhalb* einer FastAPI-Anwendung zu verwenden.\n\nDennoch erhielt FastAPI von Requests einiges an Inspiration.\n\n**Requests** ist eine Bibliothek zur *Interaktion* mit APIs (als Client), während **FastAPI** eine Bibliothek zum *Erstellen* von APIs (als Server) ist.\n\nDie beiden stehen mehr oder weniger an entgegengesetzten Enden und ergänzen sich.\n\nRequests hat ein sehr einfaches und intuitives Design, ist sehr einfach zu bedienen und verfügt über sinnvolle Standardeinstellungen. Aber gleichzeitig ist es sehr leistungsstark und anpassbar.\n\nAus diesem Grund heißt es auf der offiziellen Website:\n\n> Requests ist eines der am häufigsten heruntergeladenen Python-Packages aller Zeiten\n\nDie Art und Weise, wie Sie es verwenden, ist sehr einfach. Um beispielsweise einen `GET`-<abbr title=\"Request - Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> zu machen, würden Sie schreiben:\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\nDie entsprechende *Pfadoperation* der FastAPI-API könnte wie folgt aussehen:\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\nSehen Sie sich die Ähnlichkeiten in `requests.get(...)` und `@app.get(...)` an.\n\n/// check | Inspirierte **FastAPI**\n\n* Über eine einfache und intuitive API zu verfügen.\n* HTTP-Methodennamen (Operationen) direkt, auf einfache und intuitive Weise zu verwenden.\n* Vernünftige Standardeinstellungen zu haben, aber auch mächtige Einstellungsmöglichkeiten.\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\nDie Hauptfunktion, die ich vom Django REST Framework haben wollte, war die automatische API-Dokumentation.\n\nDann fand ich heraus, dass es einen Standard namens Swagger gab, zur Dokumentation von APIs unter Verwendung von JSON (oder YAML, einer Erweiterung von JSON).\n\nUnd es gab bereits eine Web-Oberfläche für Swagger-APIs. Die Möglichkeit, Swagger-Dokumentation für eine API zu generieren, würde die automatische Nutzung dieser Web-Oberfläche ermöglichen.\n\nIrgendwann wurde Swagger an die Linux Foundation übergeben und in OpenAPI umbenannt.\n\nAus diesem Grund spricht man bei Version 2.0 häufig von „Swagger“ und ab Version 3 von „OpenAPI“.\n\n/// check | Inspirierte **FastAPI**\n\nEinen offenen Standard für API-Spezifikationen zu übernehmen und zu verwenden, anstelle eines benutzerdefinierten Schemas.\n\nUnd Standard-basierte Tools für die Oberfläche zu integrieren:\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\nDiese beiden wurden ausgewählt, weil sie ziemlich beliebt und stabil sind, aber bei einer schnellen Suche könnten Sie Dutzende alternativer Benutzeroberflächen für OpenAPI finden (welche Sie mit **FastAPI** verwenden können).\n\n///\n\n### Flask REST Frameworks { #flask-rest-frameworks }\n\nEs gibt mehrere Flask REST Frameworks, aber nachdem ich die Zeit und Arbeit investiert habe, sie zu untersuchen, habe ich festgestellt, dass viele nicht mehr unterstützt werden oder abgebrochen wurden und dass mehrere fortbestehende Probleme sie unpassend machten.\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nEine der von API-Systemen benötigten Hauptfunktionen ist die Daten-<dfn title=\"auch genannt: Marshalling, Konvertierung\">„Serialisierung“</dfn>, welche Daten aus dem Code (Python) entnimmt und in etwas umwandelt, was durch das Netzwerk gesendet werden kann. Beispielsweise das Konvertieren eines Objekts, welches Daten aus einer Datenbank enthält, in ein JSON-Objekt. Konvertieren von `datetime`-Objekten in Strings, usw.\n\nEine weitere wichtige Funktion, benötigt von APIs, ist die Datenvalidierung, welche sicherstellt, dass die Daten unter gegebenen Umständen gültig sind. Zum Beispiel, dass ein Feld ein `int` ist und kein zufälliger String. Das ist besonders nützlich für hereinkommende Daten.\n\nOhne ein Datenvalidierungssystem müssten Sie alle Prüfungen manuell im Code durchführen.\n\nFür diese Funktionen wurde Marshmallow entwickelt. Es ist eine großartige Bibliothek und ich habe sie schon oft genutzt.\n\nAber sie wurde erstellt, bevor Typhinweise in Python existierten. Um also ein <dfn title=\"die Definition, wie Daten geformt sein sollen\">Schema</dfn> zu definieren, müssen Sie bestimmte Werkzeuge und Klassen verwenden, die von Marshmallow bereitgestellt werden.\n\n/// check | Inspirierte **FastAPI**\n\nCode zu verwenden, um „Schemas“ zu definieren, welche Datentypen und Validierung automatisch bereitstellen.\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nEine weitere wichtige Funktion, die von APIs benötigt wird, ist das <dfn title=\"Lesen und Konvertieren nach Python-Daten\">Parsen</dfn> von Daten aus eingehenden Requests.\n\nWebargs wurde entwickelt, um dieses für mehrere Frameworks, einschließlich Flask, bereitzustellen.\n\nEs verwendet unter der Haube Marshmallow, um die Datenvalidierung durchzuführen. Und es wurde von denselben Entwicklern erstellt.\n\nEs ist ein großartiges Tool und ich habe es auch oft verwendet, bevor ich **FastAPI** hatte.\n\n/// info | Info\n\nWebargs wurde von denselben Marshmallow-Entwicklern erstellt.\n\n///\n\n/// check | Inspirierte **FastAPI**\n\nEingehende Requestdaten automatisch zu validieren.\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow und Webargs bieten Validierung, Parsen und Serialisierung als Plugins.\n\nEs fehlt jedoch noch die Dokumentation. Dann wurde APISpec erstellt.\n\nEs ist ein Plugin für viele Frameworks (und es gibt auch ein Plugin für Starlette).\n\nDie Funktionsweise besteht darin, dass Sie die Definition des Schemas im YAML-Format im Docstring jeder Funktion schreiben, die eine Route verarbeitet.\n\nUnd es generiert OpenAPI-Schemas.\n\nSo funktioniert es in Flask, Starlette, Responder, usw.\n\nAber dann haben wir wieder das Problem einer Mikrosyntax innerhalb eines Python-Strings (eines großen YAML).\n\nDer Texteditor kann dabei nicht viel helfen. Und wenn wir Parameter oder Marshmallow-Schemas ändern und vergessen, auch den YAML-Docstring zu ändern, wäre das generierte Schema veraltet.\n\n/// info | Info\n\nAPISpec wurde von denselben Marshmallow-Entwicklern erstellt.\n\n///\n\n/// check | Inspirierte **FastAPI**\n\nDen offenen Standard für APIs, OpenAPI, zu unterstützen.\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\nHierbei handelt es sich um ein Flask-Plugin, welches Webargs, Marshmallow und APISpec miteinander verbindet.\n\nEs nutzt die Informationen von Webargs und Marshmallow, um mithilfe von APISpec automatisch OpenAPI-Schemas zu generieren.\n\nEin großartiges Tool, sehr unterbewertet. Es sollte weitaus populärer als viele andere Flask-Plugins sein. Möglicherweise liegt es daran, dass die Dokumentation zu kompakt und abstrakt ist.\n\nDas löste das Problem, YAML (eine andere Syntax) in Python-Docstrings schreiben zu müssen.\n\nDiese Kombination aus Flask, Flask-apispec mit Marshmallow und Webargs war bis zur Entwicklung von **FastAPI** mein Lieblings-Backend-Stack.\n\nDie Verwendung führte zur Entwicklung mehrerer Flask-Full-Stack-Generatoren. Dies sind die Hauptstacks, die ich (und mehrere externe Teams) bisher verwendet haben:\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\nUnd dieselben Full-Stack-Generatoren bildeten die Basis der [**FastAPI**-Projektgeneratoren](project-generation.md).\n\n/// info | Info\n\nFlask-apispec wurde von denselben Marshmallow-Entwicklern erstellt.\n\n///\n\n/// check | Inspirierte **FastAPI**\n\nDas OpenAPI-Schema automatisch zu generieren, aus demselben Code, welcher die Serialisierung und Validierung definiert.\n\n///\n\n### [NestJS](https://nestjs.com/) (und [Angular](https://angular.io/)) { #nestjs-and-angular }\n\nDies ist nicht einmal Python, NestJS ist ein von Angular inspiriertes JavaScript (TypeScript) NodeJS Framework.\n\nEs erreicht etwas Ähnliches wie Flask-apispec.\n\nEs verfügt über ein integriertes Dependency Injection System, welches von Angular 2 inspiriert ist. Erfordert ein Vorab-Registrieren der „Injectables“ (wie alle anderen Dependency Injection Systeme, welche ich kenne), sodass der Code ausschweifender wird und es mehr Codeverdoppelung gibt.\n\nDa die Parameter mit TypeScript-Typen beschrieben werden (ähnlich den Python-Typhinweisen), ist die Editorunterstützung ziemlich gut.\n\nDa TypeScript-Daten jedoch nach der Kompilierung nach JavaScript nicht erhalten bleiben, können die Typen nicht gleichzeitig die Validierung, Serialisierung und Dokumentation definieren. Aus diesem Grund und aufgrund einiger Designentscheidungen ist es für die Validierung, Serialisierung und automatische Schemagenerierung erforderlich, an vielen Stellen Dekoratoren hinzuzufügen. Es wird also ziemlich ausführlich.\n\nEs kann nicht sehr gut mit verschachtelten Modellen umgehen. Wenn es sich beim JSON-Body im Request also um ein JSON-Objekt mit inneren Feldern handelt, die wiederum verschachtelte JSON-Objekte sind, kann er nicht richtig dokumentiert und validiert werden.\n\n/// check | Inspirierte **FastAPI**\n\nPython-Typen zu verwenden, um eine hervorragende Editorunterstützung zu erhalten.\n\nÜber ein leistungsstarkes Dependency Injection System zu verfügen. Eine Möglichkeit zu finden, Codeverdoppelung zu minimieren.\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\nEs war eines der ersten extrem schnellen Python-Frameworks, welches auf `asyncio` basierte. Es wurde so gestaltet, dass es Flask sehr ähnlich ist.\n\n/// note | Technische Details\n\nEs verwendete [`uvloop`](https://github.com/MagicStack/uvloop) anstelle der standardmäßigen Python-`asyncio`-Schleife. Das hat es so schnell gemacht.\n\nHat eindeutig Uvicorn und Starlette inspiriert, welche derzeit in offenen Benchmarks schneller als Sanic sind.\n\n///\n\n/// check | Inspirierte **FastAPI**\n\nEinen Weg zu finden, eine hervorragende Performanz zu haben.\n\nAus diesem Grund basiert **FastAPI** auf Starlette, da dieses das schnellste verfügbare Framework ist (getestet in Benchmarks von Dritten).\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon ist ein weiteres leistungsstarkes Python-Framework. Es ist minimalistisch konzipiert und dient als Grundlage für andere Frameworks wie Hug.\n\nEs ist so konzipiert, dass es über Funktionen verfügt, welche zwei Parameter empfangen, einen <abbr title=\"Request - Anfrage: Daten, die der Client zum Server sendet\">„Request“</abbr> und eine <abbr title=\"Response - Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">„Response“</abbr>. Dann „lesen“ Sie Teile des Requests und „schreiben“ Teile der Response. Aufgrund dieses Designs ist es nicht möglich, Request-Parameter und -Bodys mit Standard-Python-Typhinweisen als Funktionsparameter zu deklarieren.\n\nDaher müssen Datenvalidierung, Serialisierung und Dokumentation im Code und nicht automatisch erfolgen. Oder sie müssen als Framework oberhalb von Falcon implementiert werden, so wie Hug. Dieselbe Unterscheidung findet auch in anderen Frameworks statt, die vom Design von Falcon inspiriert sind und ein Requestobjekt und ein Responseobjekt als Parameter haben.\n\n/// check | Inspirierte **FastAPI**\n\nWege zu finden, eine großartige Performanz zu erzielen.\n\nZusammen mit Hug (da Hug auf Falcon basiert), einen `response`-Parameter in Funktionen zu deklarieren.\n\nObwohl er in FastAPI optional ist und hauptsächlich zum Festlegen von Headern, Cookies und alternativen Statuscodes verwendet wird.\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\nIch habe Molten in den ersten Phasen der Entwicklung von **FastAPI** entdeckt. Und es hat ganz ähnliche Ideen:\n\n* Basierend auf Python-Typhinweisen.\n* Validierung und Dokumentation aus diesen Typen.\n* Dependency Injection System.\n\nEs verwendet keine Datenvalidierungs-, Serialisierungs- und Dokumentationsbibliothek eines Dritten wie Pydantic, sondern verfügt über eine eigene. Daher wären diese Datentyp-Definitionen nicht so einfach wiederverwendbar.\n\nEs erfordert eine etwas ausführlichere Konfiguration. Und da es auf WSGI (anstelle von ASGI) basiert, ist es nicht darauf ausgelegt, die hohe Leistung von Tools wie Uvicorn, Starlette und Sanic zu nutzen.\n\nDas Dependency Injection System erfordert eine Vorab-Registrierung der Abhängigkeiten und die Abhängigkeiten werden basierend auf den deklarierten Typen aufgelöst. Daher ist es nicht möglich, mehr als eine „Komponente“ zu deklarieren, welche einen bestimmten Typ bereitstellt.\n\nRouten werden an einer einzigen Stelle deklariert, indem Funktionen verwendet werden, die an anderen Stellen deklariert wurden (anstatt Dekoratoren zu verwenden, welche direkt über der Funktion platziert werden können, welche den Endpunkt verarbeitet). Dies ähnelt eher der Vorgehensweise von Django als der Vorgehensweise von Flask (und Starlette). Es trennt im Code Dinge, die relativ eng miteinander gekoppelt sind.\n\n/// check | Inspirierte **FastAPI**\n\nZusätzliche Validierungen für Datentypen zu definieren, mithilfe des „Default“-Werts von Modellattributen. Dies verbessert die Editorunterstützung und war zuvor in Pydantic nicht verfügbar.\n\nDas hat tatsächlich dazu geführt, dass Teile von Pydantic aktualisiert wurden, um denselben Validierungsdeklarationsstil zu unterstützen (diese gesamte Funktionalität ist jetzt bereits in Pydantic verfügbar).\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug war eines der ersten Frameworks, welches die Deklaration von API-Parametertypen mithilfe von Python-Typhinweisen implementierte. Das war eine großartige Idee, die andere Tools dazu inspirierte, dasselbe zu tun.\n\nEs verwendete benutzerdefinierte Typen in seinen Deklarationen anstelle von Standard-Python-Typen, es war aber dennoch ein großer Fortschritt.\n\nAußerdem war es eines der ersten Frameworks, welches ein benutzerdefiniertes Schema generierte, welches die gesamte API in JSON deklarierte.\n\nEs basierte nicht auf einem Standard wie OpenAPI und JSON Schema. Daher wäre es nicht einfach, es in andere Tools wie Swagger UI zu integrieren. Aber, nochmal, es war eine sehr innovative Idee.\n\nEs verfügt über eine interessante, ungewöhnliche Funktion: Mit demselben Framework ist es möglich, APIs und auch CLIs zu erstellen.\n\nDa es auf dem bisherigen Standard für synchrone Python-Webframeworks (WSGI) basiert, kann es nicht mit Websockets und anderen Dingen umgehen, verfügt aber dennoch über eine hohe Performanz.\n\n/// info | Info\n\nHug wurde von Timothy Crosley erstellt, demselben Schöpfer von [`isort`](https://github.com/timothycrosley/isort), einem großartigen Tool zum automatischen Sortieren von Importen in Python-Dateien.\n\n///\n\n/// check | Ideen, die **FastAPI** inspiriert haben\n\nHug inspirierte Teile von APIStar und war eines der Tools, die ich am vielversprechendsten fand, neben APIStar.\n\nHug hat dazu beigetragen, **FastAPI** dazu zu inspirieren, Python-Typhinweise zum Deklarieren von Parametern zu verwenden und ein Schema zu generieren, das die API automatisch definiert.\n\nHug inspirierte **FastAPI** dazu, einen `response`-Parameter in Funktionen zu deklarieren, um Header und Cookies zu setzen.\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (≦ 0.5) { #apistar-0-5 }\n\nKurz bevor ich mich entschied, **FastAPI** zu erstellen, fand ich den **APIStar**-Server. Er hatte fast alles, was ich suchte, und ein tolles Design.\n\nEr war eine der ersten Implementierungen eines Frameworks, die ich je gesehen hatte (vor NestJS und Molten), welches Python-Typhinweise zur Deklaration von Parametern und Requests verwendeten. Ich habe ihn mehr oder weniger zeitgleich mit Hug gefunden. Aber APIStar nutzte den OpenAPI-Standard.\n\nEr verfügte an mehreren Stellen über automatische Datenvalidierung, Datenserialisierung und OpenAPI-Schemagenerierung, basierend auf denselben Typhinweisen.\n\nBody-Schemadefinitionen verwendeten nicht die gleichen Python-Typhinweise wie Pydantic, er war Marshmallow etwas ähnlicher, sodass die Editorunterstützung nicht so gut war, aber dennoch war APIStar die beste verfügbare Option.\n\nEr hatte zu dieser Zeit die besten Leistungsbenchmarks (nur übertroffen von Starlette).\n\nAnfangs gab es keine Web-Oberfläche für die automatische API-Dokumentation, aber ich wusste, dass ich Swagger UI hinzufügen konnte.\n\nEr verfügte über ein Dependency Injection System. Es erforderte eine Vorab-Registrierung der Komponenten, wie auch bei anderen oben besprochenen Tools. Aber dennoch, es war ein tolles Feature.\n\nIch konnte ihn nie in einem vollständigen Projekt verwenden, da er keine Sicherheitsintegration hatte, sodass ich nicht alle Funktionen, die ich hatte, durch die auf Flask-apispec basierenden Full-Stack-Generatoren ersetzen konnte. Ich hatte in meinem Projekte-Backlog den Eintrag, einen Pull Request zu erstellen, welcher diese Funktionalität hinzufügte.\n\nDoch dann verlagerte sich der Schwerpunkt des Projekts.\n\nEs handelte sich nicht länger um ein API-Webframework, da sich der Entwickler auf Starlette konzentrieren musste.\n\nJetzt handelt es sich bei APIStar um eine Reihe von Tools zur Validierung von OpenAPI-Spezifikationen, nicht um ein Webframework.\n\n/// info | Info\n\nAPIStar wurde von Tom Christie erstellt. Derselbe, welcher Folgendes erstellt hat:\n\n* Django REST Framework\n* Starlette (auf welchem **FastAPI** basiert)\n* Uvicorn (verwendet von Starlette und **FastAPI**)\n\n///\n\n/// check | Inspirierte **FastAPI**\n\nZu existieren.\n\nDie Idee, mehrere Dinge (Datenvalidierung, Serialisierung und Dokumentation) mit denselben Python-Typen zu deklarieren, welche gleichzeitig eine hervorragende Editorunterstützung bieten, hielt ich für eine brillante Idee.\n\nUnd nach einer langen Suche nach einem ähnlichen Framework und dem Testen vieler verschiedener Alternativen, war APIStar die beste verfügbare Option.\n\nDann hörte APIStar auf, als Server zu existieren, und Starlette wurde geschaffen, welches eine neue, bessere Grundlage für ein solches System bildete. Das war die finale Inspiration für die Entwicklung von **FastAPI**.\n\nIch betrachte **FastAPI** als einen „spirituellen Nachfolger“ von APIStar, welcher die Funktionen, das Typsystem und andere Teile verbessert und erweitert, basierend auf den Erkenntnissen aus all diesen früheren Tools.\n\n///\n\n## Verwendet von **FastAPI** { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic ist eine Bibliothek zum Definieren von Datenvalidierung, Serialisierung und Dokumentation (unter Verwendung von JSON Schema) basierend auf Python-Typhinweisen.\n\nDas macht es äußerst intuitiv.\n\nEs ist vergleichbar mit Marshmallow. Obwohl es in Benchmarks schneller als Marshmallow ist. Und da es auf den gleichen Python-Typhinweisen basiert, ist die Editorunterstützung großartig.\n\n/// check | **FastAPI** verwendet es, um\n\nDie gesamte Datenvalidierung, Datenserialisierung und automatische Modelldokumentation (basierend auf JSON Schema) zu erledigen.\n\n**FastAPI** nimmt dann, abgesehen von all den anderen Dingen, die es tut, dieses JSON-Schema und fügt es in OpenAPI ein.\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette ist ein leichtgewichtiges <dfn title=\"Der neue Standard für die Erstellung asynchroner Python-Webanwendungen\">ASGI</dfn>-Framework/Toolkit, welches sich ideal für die Erstellung hochperformanter asynchroner Dienste eignet.\n\nEs ist sehr einfach und intuitiv. Es ist so konzipiert, dass es leicht erweiterbar ist und über modulare Komponenten verfügt.\n\nEs bietet:\n\n* Eine sehr beeindruckende Leistung.\n* WebSocket-Unterstützung.\n* Hintergrundtasks im selben Prozess.\n* Startup- und Shutdown-Events.\n* Testclient basierend auf HTTPX.\n* CORS, GZip, statische Dateien, Responses streamen.\n* Session- und Cookie-Unterstützung.\n* 100 % Testabdeckung.\n* 100 % Typannotierte Codebasis.\n* Wenige starke Abhängigkeiten.\n\nStarlette ist derzeit das schnellste getestete Python-Framework. Nur übertroffen von Uvicorn, welches kein Framework, sondern ein Server ist.\n\nStarlette bietet alle grundlegenden Funktionen eines Web-Microframeworks.\n\nEs bietet jedoch keine automatische Datenvalidierung, Serialisierung oder Dokumentation.\n\nDas ist eines der wichtigsten Dinge, welche **FastAPI** hinzufügt, alles basierend auf Python-Typhinweisen (mit Pydantic). Das, plus, das Dependency Injection System, Sicherheitswerkzeuge, OpenAPI-Schemagenerierung, usw.\n\n/// note | Technische Details\n\nASGI ist ein neuer „Standard“, welcher von Mitgliedern des Django-Kernteams entwickelt wird. Es handelt sich immer noch nicht um einen „Python-Standard“ (ein PEP), obwohl sie gerade dabei sind, das zu tun.\n\nDennoch wird es bereits von mehreren Tools als „Standard“ verwendet. Das verbessert die Interoperabilität erheblich, da Sie Uvicorn mit jeden anderen ASGI-Server (wie Daphne oder Hypercorn) tauschen oder ASGI-kompatible Tools wie `python-socketio` hinzufügen können.\n\n///\n\n/// check | **FastAPI** verwendet es, um\n\nAlle Kern-Webaspekte zu handhaben. Und fügt Funktionen obenauf.\n\nDie Klasse `FastAPI` selbst erbt direkt von der Klasse `Starlette`.\n\nAlles, was Sie also mit Starlette machen können, können Sie direkt mit **FastAPI** machen, da es sich im Grunde um Starlette auf Steroiden handelt.\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn ist ein blitzschneller ASGI-Server, der auf uvloop und httptools basiert.\n\nEs handelt sich nicht um ein Webframework, sondern um einen Server. Beispielsweise werden keine Tools für das Routing von Pfaden bereitgestellt. Das ist etwas, was ein Framework wie Starlette (oder **FastAPI**) zusätzlich bieten würde.\n\nEs ist der empfohlene Server für Starlette und **FastAPI**.\n\n/// check | **FastAPI** empfiehlt es als\n\nHauptwebserver zum Ausführen von **FastAPI**-Anwendungen.\n\nSie können auch die Kommandozeilenoption `--workers` verwenden, um einen asynchronen Multiprozess-Server zu erhalten.\n\nWeitere Details finden Sie im Abschnitt [Deployment](deployment/index.md).\n\n///\n\n## Benchmarks und Geschwindigkeit { #benchmarks-and-speed }\n\nUm den Unterschied zwischen Uvicorn, Starlette und FastAPI zu verstehen, zu vergleichen, und zu sehen, lesen Sie den Abschnitt über [Benchmarks](benchmarks.md).\n"
  },
  {
    "path": "docs/de/docs/async.md",
    "content": "# Nebenläufigkeit und async / await { #concurrency-and-async-await }\n\nDetails zur `async def`-Syntax für *Pfadoperation-Funktionen* und Hintergrundinformationen zu asynchronem Code, Nebenläufigkeit und Parallelität.\n\n## In Eile? { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - Zu lang; nicht gelesen\"><strong>TL;DR:</strong></abbr>\n\nWenn Sie Bibliotheken von Dritten verwenden, die mit `await` aufgerufen werden müssen, wie zum Beispiel:\n\n```Python\nresults = await some_library()\n```\n\nDann deklarieren Sie Ihre *Pfadoperation-Funktionen* mit `async def`, wie in:\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | Hinweis\n\nSie können `await` nur innerhalb von Funktionen verwenden, die mit `async def` erstellt wurden.\n\n///\n\n---\n\nWenn Sie eine Bibliothek eines Dritten verwenden, die mit etwas kommuniziert (einer Datenbank, einer API, dem Dateisystem, usw.) und welche die Verwendung von `await` nicht unterstützt (dies ist derzeit bei den meisten Datenbankbibliotheken der Fall), dann deklarieren Sie Ihre *Pfadoperation-Funktionen* ganz normal nur mit `def`, wie in:\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\nWenn Ihre Anwendung (irgendwie) nicht mit etwas anderem kommunizieren und auf dessen Antwort warten muss, verwenden Sie `async def`, auch wenn Sie `await` im Inneren nicht verwenden müssen.\n\n---\n\nWenn Sie sich unsicher sind, verwenden Sie einfach `def`.\n\n---\n\n**Hinweis**: Sie können `def` und `async def` in Ihren *Pfadoperation-Funktionen* beliebig mischen, so wie Sie es benötigen, und jede einzelne Funktion in der für Sie besten Variante erstellen. FastAPI wird damit das Richtige tun.\n\nWie dem auch sei, in jedem der oben genannten Fälle wird FastAPI immer noch asynchron arbeiten und extrem schnell sein.\n\nWenn Sie jedoch den oben genannten Schritten folgen, können einige Performanz-Optimierungen vorgenommen werden.\n\n## Technische Details { #technical-details }\n\nModerne Versionen von Python unterstützen **„asynchronen Code“** unter Verwendung sogenannter **„Coroutinen“** mithilfe der Syntax **`async` und `await`**.\n\nNehmen wir obigen Satz in den folgenden Abschnitten Schritt für Schritt unter die Lupe:\n\n* **Asynchroner Code**\n* **`async` und `await`**\n* **Coroutinen**\n\n## Asynchroner Code { #asynchronous-code }\n\nAsynchroner Code bedeutet lediglich, dass die Sprache 💬 eine Möglichkeit hat, dem Computer / Programm 🤖 mitzuteilen, dass es 🤖 an einem bestimmten Punkt im Code darauf warten muss, dass *etwas anderes* irgendwo anders fertig wird. Nehmen wir an, *etwas anderes* ist hier „Langsam-Datei“ 📝.\n\nWährend der Zeit, die „Langsam-Datei“ 📝 benötigt, kann das System also andere Aufgaben erledigen.\n\nDann kommt der Computer / das Programm 🤖 bei jeder Gelegenheit zurück, weil es entweder wieder wartet oder wann immer es 🤖 die ganze Arbeit erledigt hat, die zu diesem Zeitpunkt zu tun war. Und es 🤖 wird nachschauen, ob eine der Aufgaben, auf die es gewartet hat, fertig ist.\n\nDann nimmt es 🤖 die erste erledigte Aufgabe (sagen wir, unsere „Langsam-Datei“ 📝) und bearbeitet sie weiter.\n\nDas „Warten auf etwas anderes“ bezieht sich normalerweise auf <abbr title=\"Input and Output - Eingabe und Ausgabe\">I/O</abbr>-Operationen, die relativ „langsam“ sind (im Vergleich zur Geschwindigkeit des Prozessors und des Arbeitsspeichers), wie etwa das Warten darauf, dass:\n\n* die Daten des Clients über das Netzwerk empfangen wurden\n* die von Ihrem Programm gesendeten Daten vom Client über das Netzwerk empfangen wurden\n* der Inhalt einer Datei vom System von der Festplatte gelesen und an Ihr Programm übergeben wurde\n* der Inhalt, den Ihr Programm dem System übergeben hat, auf die Festplatte geschrieben wurde\n* eine Remote-API-Operation beendet wurde\n* Eine Datenbankoperation abgeschlossen wurde\n* eine Datenbankabfrage die Ergebnisse zurückgegeben hat\n* usw.\n\nDa die Ausführungszeit hier hauptsächlich durch das Warten auf <abbr title=\"Input and Output - Eingabe und Ausgabe\">I/O</abbr>-Operationen verbraucht wird, nennt man dies auch „I/O-lastige“ („I/O bound“) Operationen.\n\n„Asynchron“, sagt man, weil der Computer / das Programm nicht mit einer langsamen Aufgabe „synchronisiert“ werden muss und nicht auf den genauen Moment warten muss, in dem die Aufgabe beendet ist, ohne dabei etwas zu tun, um schließlich das Ergebnis der Aufgabe zu übernehmen und die Arbeit fortsetzen zu können.\n\nDa es sich stattdessen um ein „asynchrones“ System handelt, kann die Aufgabe nach Abschluss ein wenig (einige Mikrosekunden) in der Schlange warten, bis der Computer / das Programm seine anderen Dinge erledigt hat und zurückkommt, um die Ergebnisse entgegenzunehmen und mit ihnen weiterzuarbeiten.\n\nFür „synchron“ (im Gegensatz zu „asynchron“) wird auch oft der Begriff „sequentiell“ verwendet, da der Computer / das Programm alle Schritte in einer Sequenz („der Reihe nach“) ausführt, bevor es zu einer anderen Aufgabe wechselt, auch wenn diese Schritte mit Warten verbunden sind.\n\n### Nebenläufigkeit und Hamburger { #concurrency-and-burgers }\n\nDiese oben beschriebene Idee von **asynchronem** Code wird manchmal auch **„Nebenläufigkeit“** genannt. Sie unterscheidet sich von **„Parallelität“**.\n\n**Nebenläufigkeit** und **Parallelität** beziehen sich beide auf „verschiedene Dinge, die mehr oder weniger gleichzeitig passieren“.\n\nAber die Details zwischen *Nebenläufigkeit* und *Parallelität* sind ziemlich unterschiedlich.\n\nUm den Unterschied zu erkennen, stellen Sie sich die folgende Geschichte über Hamburger vor:\n\n### Nebenläufige Hamburger { #concurrent-burgers }\n\nSie gehen mit Ihrem Schwarm Fastfood holen, stehen in der Schlange, während der Kassierer die Bestellungen der Leute vor Ihnen entgegennimmt. 😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\nDann sind Sie an der Reihe und Sie bestellen zwei sehr schmackhafte Burger für Ihren Schwarm und Sie. 🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\nDer Kassierer sagt etwas zum Koch in der Küche, damit dieser weiß, dass er Ihre Burger zubereiten muss (obwohl er gerade die für die vorherigen Kunden zubereitet).\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\nSie bezahlen. 💸\n\nDer Kassierer gibt Ihnen die Nummer Ihrer Bestellung.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\nWährend Sie warten, suchen Sie sich mit Ihrem Schwarm einen Tisch aus, Sie sitzen da und reden lange mit Ihrem Schwarm (da Ihre Burger sehr aufwändig sind und die Zubereitung einige Zeit dauert).\n\nWährend Sie mit Ihrem Schwarm am Tisch sitzen und auf die Burger warten, können Sie die Zeit damit verbringen, zu bewundern, wie großartig, süß und klug Ihr Schwarm ist ✨😍✨.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\nWährend Sie warten und mit Ihrem Schwarm sprechen, überprüfen Sie von Zeit zu Zeit die auf dem Zähler angezeigte Nummer, um zu sehen, ob Sie bereits an der Reihe sind.\n\nDann, irgendwann, sind Sie endlich an der Reihe. Sie gehen zur Theke, holen sich die Burger und kommen zurück an den Tisch.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\nSie und Ihr Schwarm essen die Burger und haben eine schöne Zeit. ✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info | Info\n\nDie wunderschönen Illustrationen stammen von [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nStellen Sie sich vor, Sie wären der Computer / das Programm 🤖 in dieser Geschichte.\n\nWährend Sie an der Schlange stehen, sind Sie einfach untätig 😴, warten darauf, dass Sie an die Reihe kommen, und tun nichts sehr „Produktives“. Aber die Schlange ist schnell abgearbeitet, weil der Kassierer nur die Bestellungen entgegennimmt (und nicht zubereitet), also ist das vertretbar.\n\nWenn Sie dann an der Reihe sind, erledigen Sie tatsächliche „produktive“ Arbeit, Sie gehen das Menü durch, entscheiden sich, was Sie möchten, bekunden Ihre und die Wahl Ihres Schwarms, bezahlen, prüfen, ob Sie die richtige Menge Geld oder die richtige Karte geben, prüfen, ob die Rechnung korrekt ist, prüfen, dass die Bestellung die richtigen Artikel enthält, usw.\n\nAber dann, auch wenn Sie Ihre Burger noch nicht haben, ist Ihre Interaktion mit dem Kassierer erst mal „auf Pause“ ⏸, weil Sie warten müssen 🕙, bis Ihre Burger fertig sind.\n\nAber wenn Sie sich von der Theke entfernt haben und mit der Nummer für die Bestellung an einem Tisch sitzen, können Sie Ihre Aufmerksamkeit auf Ihren Schwarm lenken und an dieser Aufgabe „arbeiten“ ⏯ 🤓. Sie machen wieder etwas sehr „Produktives“ und flirten mit Ihrem Schwarm 😍.\n\nDann sagt der Kassierer 💁 „Ich bin mit dem Burger fertig“, indem er Ihre Nummer auf dem Display über der Theke anzeigt, aber Sie springen nicht sofort wie verrückt auf, wenn das Display auf Ihre Nummer springt. Sie wissen, dass niemand Ihnen Ihre Burger wegnimmt, denn Sie haben die Nummer Ihrer Bestellung, und andere Leute haben andere Nummern.\n\nAlso warten Sie darauf, dass Ihr Schwarm ihre Geschichte zu Ende erzählt (die aktuelle Arbeit ⏯ / bearbeitete Aufgabe beendet 🤓), lächeln sanft und sagen, dass Sie die Burger holen ⏸.\n\nDann gehen Sie zur Theke 🔀, zur ursprünglichen Aufgabe, die nun erledigt ist ⏯, nehmen die Burger auf, sagen Danke, und bringen sie zum Tisch. Damit ist dieser Schritt / diese Aufgabe der Interaktion mit der Theke abgeschlossen ⏹. Das wiederum schafft eine neue Aufgabe, „Burger essen“ 🔀 ⏯, aber die vorherige Aufgabe „Burger holen“ ist erledigt ⏹.\n\n### Parallele Hamburger { #parallel-burgers }\n\nStellen wir uns jetzt vor, dass es sich hierbei nicht um „nebenläufige Hamburger“, sondern um „parallele Hamburger“ handelt.\n\nSie gehen los mit Ihrem Schwarm, um paralleles Fast Food zu bekommen.\n\nSie stehen in der Schlange, während mehrere (sagen wir acht) Kassierer, die gleichzeitig Köche sind, die Bestellungen der Leute vor Ihnen entgegennehmen.\n\nAlle vor Ihnen warten darauf, dass ihre Burger fertig sind, bevor sie die Theke verlassen, denn jeder der 8 Kassierer geht los und bereitet den Burger sofort zu, bevor er die nächste Bestellung entgegennimmt.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\nDann sind Sie endlich an der Reihe und bestellen zwei sehr leckere Burger für Ihren Schwarm und Sie.\n\nSie zahlen 💸.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\nDer Kassierer geht in die Küche.\n\nSie warten, vor der Theke stehend 🕙, damit niemand außer Ihnen Ihre Burger entgegennimmt, da es keine Nummern für die Reihenfolge gibt.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\nDa Sie und Ihr Schwarm damit beschäftigt sind, niemanden vor sich zu lassen, der Ihre Burger nimmt, wenn sie ankommen, können Sie Ihrem Schwarm keine Aufmerksamkeit schenken. 😞\n\nDas ist „synchrone“ Arbeit, Sie sind mit dem Kassierer/Koch „synchronisiert“ 👨‍🍳. Sie müssen warten 🕙 und genau in dem Moment da sein, in dem der Kassierer/Koch 👨‍🍳 die Burger zubereitet hat und Ihnen gibt, sonst könnte jemand anderes sie nehmen.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\nDann kommt Ihr Kassierer/Koch 👨‍🍳 endlich mit Ihren Burgern zurück, nachdem Sie lange vor der Theke gewartet 🕙 haben.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\nSie nehmen Ihre Burger und gehen mit Ihrem Schwarm an den Tisch.\n\nSie essen sie und sind fertig. ⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\nEs wurde nicht viel geredet oder geflirtet, da die meiste Zeit mit Warten 🕙 vor der Theke verbracht wurde. 😞\n\n/// info | Info\n\nDie wunderschönen Illustrationen stammen von [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nIn diesem Szenario der parallelen Hamburger sind Sie ein Computersystem / Programm 🤖 mit zwei Prozessoren (Sie und Ihr Schwarm), die beide warten 🕙 und ihre Aufmerksamkeit darauf verwenden, „lange Zeit vor der Theke zu warten“ 🕙.\n\nDer Fast-Food-Laden verfügt über 8 Prozessoren (Kassierer/Köche). Während der nebenläufige Burger-Laden nur zwei hatte (einen Kassierer und einen Koch).\n\nDennoch ist das schlussendliche Benutzererlebnis nicht das Beste. 😞\n\n---\n\nDies wäre die parallele äquivalente Geschichte für Hamburger. 🍔\n\nFür ein „realeres“ Beispiel hierfür, stellen Sie sich eine Bank vor.\n\nBis vor kurzem hatten die meisten Banken mehrere Kassierer 👨‍💼👨‍💼👨‍💼👨‍💼 und eine große Warteschlange 🕙🕙🕙🕙🕙🕙🕙🕙.\n\nAlle Kassierer erledigen die ganze Arbeit mit einem Kunden nach dem anderen 👨‍💼⏯.\n\nUnd man muss lange in der Schlange warten 🕙 sonst kommt man nicht an die Reihe.\n\nSie würden Ihren Schwarm 😍 wahrscheinlich nicht mitnehmen wollen, um Besorgungen bei der Bank zu erledigen 🏦.\n\n### Hamburger Schlussfolgerung { #burger-conclusion }\n\nIn diesem Szenario „Fastfood-Burger mit Ihrem Schwarm“ ist es viel sinnvoller, ein nebenläufiges System zu haben ⏸🔀⏯, da viel gewartet wird 🕙.\n\nDas ist auch bei den meisten Webanwendungen der Fall.\n\nViele, viele Benutzer, aber Ihr Server wartet 🕙 darauf, dass deren nicht so gute Internetverbindungen die <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> übermitteln.\n\nUnd dann wieder warten 🕙, bis die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Responses</abbr> zurückkommen.\n\nDieses „Warten“ 🕙 wird in Mikrosekunden gemessen, aber zusammenfassend lässt sich sagen, dass am Ende eine Menge gewartet wird.\n\nDeshalb ist es sehr sinnvoll, asynchronen ⏸🔀⏯ Code für Web-APIs zu verwenden.\n\nDiese Art der Asynchronität hat NodeJS populär gemacht (auch wenn NodeJS nicht parallel ist) und darin liegt die Stärke von Go als Programmiersprache.\n\nUnd das ist das gleiche Leistungsniveau, das Sie mit **FastAPI** erhalten.\n\nUnd da Sie Parallelität und Asynchronität gleichzeitig haben können, erzielen Sie eine höhere Performanz als die meisten getesteten NodeJS-Frameworks und sind mit Go auf Augenhöhe, einer kompilierten Sprache, die näher an C liegt [(alles dank Starlette)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).\n\n### Ist Nebenläufigkeit besser als Parallelität? { #is-concurrency-better-than-parallelism }\n\nNein! Das ist nicht die Moral der Geschichte.\n\nNebenläufigkeit unterscheidet sich von Parallelität. Und sie ist besser bei **bestimmten** Szenarien, die viel Warten erfordern. Aus diesem Grund ist sie im Allgemeinen viel besser als Parallelität für die Entwicklung von Webanwendungen. Aber das stimmt nicht für alle Anwendungen.\n\nUm die Dinge auszugleichen, stellen Sie sich die folgende Kurzgeschichte vor:\n\n> Sie müssen ein großes, schmutziges Haus aufräumen.\n\n*Yup, das ist die ganze Geschichte*.\n\n---\n\nEs gibt kein Warten 🕙, nur viel Arbeit an mehreren Stellen im Haus.\n\nSie könnten wie im Hamburger-Beispiel hin- und herspringen, zuerst das Wohnzimmer, dann die Küche, aber da Sie auf nichts warten 🕙, sondern nur putzen und putzen, hätte das Hin- und Herspringen keine Auswirkungen.\n\nEs würde mit oder ohne Hin- und Herspringen (Nebenläufigkeit) die gleiche Zeit in Anspruch nehmen, um fertig zu werden, und Sie hätten die gleiche Menge an Arbeit erledigt.\n\nAber wenn Sie in diesem Fall die acht Ex-Kassierer/Köche/jetzt Reinigungskräfte mitbringen würden und jeder von ihnen (plus Sie) würde einen Bereich des Hauses reinigen, könnten Sie die ganze Arbeit **parallel** erledigen, und würden mit dieser zusätzlichen Hilfe viel schneller fertig werden.\n\nIn diesem Szenario wäre jede einzelne Reinigungskraft (einschließlich Ihnen) ein Prozessor, der seinen Teil der Arbeit erledigt.\n\nUnd da die meiste Ausführungszeit durch tatsächliche Arbeit (anstatt durch Warten) in Anspruch genommen wird und die Arbeit in einem Computer von einer <abbr title=\"Central Processing Unit - Zentrale Recheneinheit\">CPU</abbr> erledigt wird, werden diese Probleme als „CPU-lastig“ („CPU bound“) bezeichnet.\n\n---\n\nTypische Beispiele für CPU-lastige Vorgänge sind Dinge, die komplexe mathematische Berechnungen erfordern.\n\nZum Beispiel:\n\n* **Audio-** oder **Bildbearbeitung**.\n* **Computer Vision**: Ein Bild besteht aus Millionen von Pixeln, jedes Pixel hat 3 Werte / Farben, die Verarbeitung erfordert normalerweise, Berechnungen mit diesen Pixeln durchzuführen, alles zur gleichen Zeit.\n* **Maschinelles Lernen**: Normalerweise sind viele „Matrix“- und „Vektor“-Multiplikationen erforderlich. Stellen Sie sich eine riesige Tabelle mit Zahlen vor, in der Sie alle Zahlen gleichzeitig multiplizieren.\n* **Deep Learning**: Dies ist ein Teilgebiet des maschinellen Lernens, daher gilt das Gleiche. Es ist nur so, dass es nicht eine einzige Tabelle mit Zahlen zum Multiplizieren gibt, sondern eine riesige Menge davon, und in vielen Fällen verwendet man einen speziellen Prozessor, um diese Modelle zu erstellen und / oder zu verwenden.\n\n### Nebenläufigkeit + Parallelität: Web + maschinelles Lernen { #concurrency-parallelism-web-machine-learning }\n\nMit **FastAPI** können Sie die Vorteile der Nebenläufigkeit nutzen, die in der Webentwicklung weit verbreitet ist (derselbe Hauptvorteil von NodeJS).\n\nSie können aber auch die Vorteile von Parallelität und Multiprocessing (mehrere Prozesse werden parallel ausgeführt) für **CPU-lastige** Workloads wie in Systemen für maschinelles Lernen nutzen.\n\nDies und die einfache Tatsache, dass Python die Hauptsprache für **Data Science**, maschinelles Lernen und insbesondere Deep Learning ist, machen FastAPI zu einem sehr passenden Werkzeug für Web-APIs und Anwendungen für Data Science / maschinelles Lernen (neben vielen anderen).\n\nWie Sie diese Parallelität in der Produktion erreichen, erfahren Sie im Abschnitt über [Deployment](deployment/index.md).\n\n## `async` und `await` { #async-and-await }\n\nModerne Versionen von Python verfügen über eine sehr intuitive Möglichkeit, asynchronen Code zu schreiben. Dadurch sieht es wie normaler „sequentieller“ Code aus und übernimmt im richtigen Moment das „Warten“ für Sie.\n\nWenn es einen Vorgang gibt, der erfordert, dass gewartet wird, bevor die Ergebnisse zurückgegeben werden, und der diese neue Python-Funktionalität unterstützt, können Sie ihn wie folgt schreiben:\n\n```Python\nburgers = await get_burgers(2)\n```\n\nDer Schlüssel hier ist das `await`. Es teilt Python mit, dass es warten ⏸ muss, bis `get_burgers(2)` seine Aufgabe erledigt hat 🕙, bevor die Ergebnisse in `burgers` gespeichert werden. Damit weiß Python, dass es in der Zwischenzeit etwas anderes tun kann 🔀 ⏯ (z. B. einen weiteren Request empfangen).\n\nDamit `await` funktioniert, muss es sich in einer Funktion befinden, die diese Asynchronität unterstützt. Dazu deklarieren Sie sie einfach mit `async def`:\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # Mache hier etwas Asynchrones, um die Burger zu erstellen\n    return burgers\n```\n\n... statt mit `def`:\n\n```Python hl_lines=\"2\"\n# Dies ist nicht asynchron\ndef get_sequential_burgers(number: int):\n    # Mache hier etwas Sequentielles, um die Burger zu erstellen\n    return burgers\n```\n\nMit `async def` weiß Python, dass es innerhalb dieser Funktion auf `await`-Ausdrücke achten muss und dass es die Ausführung dieser Funktion „anhalten“ ⏸ und etwas anderes tun kann 🔀, bevor es zurückkommt.\n\nWenn Sie eine `async def`-Funktion aufrufen möchten, müssen Sie sie „erwarten“ („await“). Das folgende wird also nicht funktionieren:\n\n```Python\n# Das funktioniert nicht, weil get_burgers definiert wurde mit: async def\nburgers = get_burgers(2)\n```\n\n---\n\nWenn Sie also eine Bibliothek verwenden, die Ihnen sagt, dass Sie sie mit `await` aufrufen können, müssen Sie die *Pfadoperation-Funktionen*, die diese Bibliothek verwenden, mittels `async def` erstellen, wie in:\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### Weitere technische Details { #more-technical-details }\n\nIhnen ist wahrscheinlich aufgefallen, dass `await` nur innerhalb von Funktionen verwendet werden kann, die mit `async def` definiert sind.\n\nGleichzeitig müssen aber mit `async def` definierte Funktionen „erwartet“ („awaited“) werden. Daher können Funktionen mit `async def` nur innerhalb von Funktionen aufgerufen werden, die auch mit `async def` definiert sind.\n\nDaraus resultiert das Ei-und-Huhn-Problem: Wie ruft man die erste `async` Funktion auf?\n\nWenn Sie mit **FastAPI** arbeiten, müssen Sie sich darüber keine Sorgen machen, da diese „erste“ Funktion Ihre *Pfadoperation-Funktion* sein wird und FastAPI weiß, was zu tun ist.\n\nWenn Sie jedoch `async` / `await` ohne FastAPI verwenden möchten, können Sie dies auch tun.\n\n### Schreiben Sie Ihren eigenen asynchronen Code { #write-your-own-async-code }\n\nStarlette (und **FastAPI**) basieren auf [AnyIO](https://anyio.readthedocs.io/en/stable/), was bedeutet, dass es sowohl kompatibel mit der Python-Standardbibliothek [asyncio](https://docs.python.org/3/library/asyncio-task.html) als auch mit [Trio](https://trio.readthedocs.io/en/stable/) ist.\n\nInsbesondere können Sie [AnyIO](https://anyio.readthedocs.io/en/stable/) direkt verwenden für Ihre fortgeschrittenen nebenläufigen Anwendungsfälle, die fortgeschrittenere Muster in Ihrem eigenen Code erfordern.\n\nUnd auch wenn Sie FastAPI nicht verwenden würden, könnten Sie Ihre eigenen asynchronen Anwendungen mit [AnyIO](https://anyio.readthedocs.io/en/stable/) schreiben, um hochkompatibel zu sein und dessen Vorteile zu nutzen (z. B. *strukturierte Nebenläufigkeit*).\n\nIch habe eine weitere Bibliothek auf Basis von AnyIO erstellt, als dünne Schicht obendrauf, um die Typannotationen etwas zu verbessern und bessere **Autovervollständigung**, **Inline-Fehler** usw. zu erhalten. Sie hat auch eine freundliche Einführung und ein Tutorial, um Ihnen zu helfen, **Ihren eigenen asynchronen Code zu verstehen** und zu schreiben: [Asyncer](https://asyncer.tiangolo.com/). Sie ist insbesondere nützlich, wenn Sie **asynchronen Code mit regulärem** (blockierendem/synchronem) Code kombinieren müssen.\n\n### Andere Formen von asynchronem Code { #other-forms-of-asynchronous-code }\n\nDiese Art der Verwendung von `async` und `await` ist in der Sprache relativ neu.\n\nAber sie erleichtert die Arbeit mit asynchronem Code erheblich.\n\nDie gleiche Syntax (oder fast identisch) wurde kürzlich auch in moderne Versionen von JavaScript (im Browser und in NodeJS) aufgenommen.\n\nDavor war der Umgang mit asynchronem Code jedoch deutlich komplexer und schwieriger.\n\nIn früheren Versionen von Python hätten Sie Threads oder [Gevent](https://www.gevent.org/) verwenden können. Der Code ist jedoch viel komplexer zu verstehen, zu debuggen und nachzuvollziehen.\n\nIn früheren Versionen von NodeJS / Browser JavaScript hätten Sie „Callbacks“ verwendet. Was zur „Callback-Hölle“ führt.\n\n## Coroutinen { #coroutines }\n\n**Coroutine** ist nur ein schicker Begriff für dasjenige, was von einer `async def`-Funktion zurückgegeben wird. Python weiß, dass es so etwas wie eine Funktion ist, die es starten kann und die irgendwann endet, aber auch dass sie pausiert ⏸ werden kann, wann immer darin ein `await` steht.\n\nAber all diese Funktionalität der Verwendung von asynchronem Code mit `async` und `await` wird oft als Verwendung von „Coroutinen“ zusammengefasst. Es ist vergleichbar mit dem Hauptmerkmal von Go, den „Goroutinen“.\n\n## Fazit { #conclusion }\n\nSehen wir uns den gleichen Satz von oben noch mal an:\n\n> Moderne Versionen von Python unterstützen **„asynchronen Code“** unter Verwendung sogenannter **„Coroutinen“** mithilfe der Syntax **`async` und `await`**.\n\nDas sollte jetzt mehr Sinn ergeben. ✨\n\nAll das ist es, was FastAPI (via Starlette) befeuert und es eine so beeindruckende Performanz haben lässt.\n\n## Sehr technische Details { #very-technical-details }\n\n/// warning | Achtung\n\nDas folgende können Sie wahrscheinlich überspringen.\n\nDies sind sehr technische Details darüber, wie **FastAPI** unter der Haube funktioniert.\n\nWenn Sie über gute technische Kenntnisse verfügen (Coroutinen, Threads, Blocking, usw.) und neugierig sind, wie FastAPI mit `async def`s im Vergleich zu normalen `def`s umgeht, fahren Sie fort.\n\n///\n\n### Pfadoperation-Funktionen { #path-operation-functions }\n\nWenn Sie eine *Pfadoperation-Funktion* mit normalem `def` anstelle von `async def` deklarieren, wird sie in einem externen Threadpool ausgeführt, der dann `await`et wird, anstatt direkt aufgerufen zu werden (da dies den Server blockieren würde).\n\nWenn Sie von einem anderen asynchronen Framework kommen, das nicht auf die oben beschriebene Weise funktioniert, und Sie es gewohnt sind, triviale, nur-berechnende *Pfadoperation-Funktionen* mit einfachem `def` zu definieren, um einen geringfügigen Geschwindigkeitsgewinn (etwa 100 Nanosekunden) zu erzielen, beachten Sie bitte, dass der Effekt in **FastAPI** genau gegenteilig wäre. In solchen Fällen ist es besser, `async def` zu verwenden, es sei denn, Ihre *Pfadoperation-Funktionen* verwenden Code, der blockierende <abbr title=\"Input/Output - Eingabe/Ausgabe: Lesen oder Schreiben von/auf Festplatte, Netzwerkkommunikation.\">I/O</abbr>-Operationen durchführt.\n\nDennoch besteht in beiden Fällen eine gute Chance, dass **FastAPI** [immer noch schneller](index.md#performance) als Ihr bisheriges Framework (oder zumindest damit vergleichbar) ist.\n\n### Abhängigkeiten { #dependencies }\n\nDas Gleiche gilt für [Abhängigkeiten](tutorial/dependencies/index.md). Wenn eine Abhängigkeit eine normale `def`-Funktion anstelle einer `async def` ist, wird sie im externen Threadpool ausgeführt.\n\n### Unterabhängigkeiten { #sub-dependencies }\n\nSie können mehrere Abhängigkeiten und [Unterabhängigkeiten](tutorial/dependencies/sub-dependencies.md) haben, die einander bedingen (als Parameter der Funktionsdefinitionen), einige davon könnten erstellt werden mit `async def` und einige mit normalem `def`. Es würde immer noch funktionieren, und diejenigen, die mit normalem `def` erstellt wurden, würden in einem externen Thread (vom Threadpool stammend) aufgerufen werden, anstatt `await`et zu werden.\n\n### Andere Hilfsfunktionen { #other-utility-functions }\n\nJede andere Hilfsfunktion, die Sie direkt aufrufen, kann mit normalem `def` oder `async def` erstellt werden, und FastAPI beeinflusst nicht die Art und Weise, wie Sie sie aufrufen.\n\nDies steht im Gegensatz zu den Funktionen, die FastAPI für Sie aufruft: *Pfadoperation-Funktionen* und Abhängigkeiten.\n\nWenn Ihre Hilfsfunktion eine normale Funktion mit `def` ist, wird sie direkt aufgerufen (so wie Sie es in Ihrem Code schreiben), nicht in einem Threadpool. Wenn die Funktion mit `async def` erstellt wurde, sollten Sie sie `await`en, wenn Sie sie in Ihrem Code aufrufen.\n\n---\n\nNochmal, es handelt sich hier um sehr technische Details, die Ihnen helfen, falls Sie danach gesucht haben.\n\nAndernfalls liegen Sie richtig, wenn Sie sich an die Richtlinien aus dem obigen Abschnitt halten: <a href=\"#in-a-hurry\">In Eile?</a>.\n"
  },
  {
    "path": "docs/de/docs/benchmarks.md",
    "content": "# Benchmarks { #benchmarks }\n\nUnabhängige TechEmpower-Benchmarks zeigen **FastAPI**-Anwendungen, die unter Uvicorn ausgeführt werden, als [eines der schnellsten verfügbaren Python-Frameworks](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), nur unterhalb von Starlette und Uvicorn selbst (die intern von FastAPI verwendet werden).\n\nAber bei der Betrachtung von Benchmarks und Vergleichen sollten Sie Folgendes beachten.\n\n## Benchmarks und Geschwindigkeit { #benchmarks-and-speed }\n\nWenn Sie die Benchmarks ansehen, ist es üblich, dass mehrere Tools unterschiedlichen Typs als gleichwertig verglichen werden.\n\nInsbesondere dass Uvicorn, Starlette und FastAPI zusammen verglichen werden (neben vielen anderen Tools).\n\nJe einfacher das Problem, das durch das Tool gelöst wird, desto besser wird die Performanz sein. Und die meisten Benchmarks testen nicht die zusätzlichen Funktionen, die das Tool bietet.\n\nDie Hierarchie ist wie folgt:\n\n* **Uvicorn**: ein ASGI-Server\n    * **Starlette**: (verwendet Uvicorn) ein Web-Mikroframework\n        * **FastAPI**: (verwendet Starlette) ein API-Mikroframework mit mehreren zusätzlichen Funktionen zum Erstellen von APIs, mit Datenvalidierung, usw.\n\n* **Uvicorn**:\n    * Wird die beste Performanz haben, da außer dem Server selbst nicht viel zusätzlicher Code vorhanden ist.\n    * Sie würden eine Anwendung nicht direkt in Uvicorn schreiben. Das würde bedeuten, dass Ihr Code zumindest mehr oder weniger den gesamten von Starlette (oder **FastAPI**) bereitgestellten Code enthalten müsste. Und wenn Sie das täten, hätte Ihre endgültige Anwendung den gleichen Overhead wie bei der Verwendung eines Frameworks und der Minimierung Ihres Anwendungscodes und der Fehler.\n    * Wenn Sie Uvicorn vergleichen, vergleichen Sie es mit Anwendungsservern wie Daphne, Hypercorn, uWSGI, usw.\n* **Starlette**:\n    * Wird nach Uvicorn die nächstbeste Performanz erbringen. Tatsächlich verwendet Starlette Uvicorn, um zu laufen. Daher kann es wahrscheinlich nur „langsamer“ als Uvicorn werden, weil mehr Code ausgeführt werden muss.\n    * Aber es bietet Ihnen die Werkzeuge, um einfache Webanwendungen zu erstellen, mit Routing basierend auf Pfaden, usw.\n    * Wenn Sie Starlette vergleichen, vergleichen Sie es mit Webframeworks (oder Mikroframeworks) wie Sanic, Flask, Django, usw.\n* **FastAPI**:\n    * So wie Starlette Uvicorn verwendet und nicht schneller als dieses sein kann, verwendet **FastAPI** Starlette, sodass es nicht schneller als dieses sein kann.\n    * FastAPI bietet zusätzliche Funktionen auf Basis von Starlette. Funktionen, die Sie beim Erstellen von APIs fast immer benötigen, wie Datenvalidierung und Serialisierung. Und wenn Sie es verwenden, erhalten Sie kostenlose automatische Dokumentation (die automatische Dokumentation verursacht nicht einmal zusätzlichen Overhead für laufende Anwendungen, sie wird beim Starten generiert).\n    * Wenn Sie FastAPI nicht verwenden und stattdessen Starlette direkt (oder ein anderes Tool wie Sanic, Flask, Responder, usw.) verwenden würden, müssten Sie die gesamte Datenvalidierung und Serialisierung selbst implementieren. Ihre finale Anwendung hätte also immer noch den gleichen Overhead, als ob sie mit FastAPI erstellt worden wäre. Und in vielen Fällen ist diese Datenvalidierung und Serialisierung der größte Teil des in Anwendungen geschriebenen Codes.\n    * Durch die Verwendung von FastAPI sparen Sie also Entwicklungszeit, Fehler und Codezeilen und würden wahrscheinlich die gleiche Performanz (oder eine bessere) erzielen, die Sie hätten, wenn Sie es nicht verwenden würden (da Sie alles in Ihrem Code implementieren müssten).\n    * Wenn Sie FastAPI vergleichen, vergleichen Sie es mit einem Webanwendungs-Framework (oder einer Reihe von Tools), das Datenvalidierung, Serialisierung und Dokumentation bereitstellt, wie Flask-apispec, NestJS, Molten, usw. – Frameworks mit integrierter automatischer Datenvalidierung, Serialisierung und Dokumentation.\n"
  },
  {
    "path": "docs/de/docs/deployment/cloud.md",
    "content": "# FastAPI bei Cloudanbietern deployen { #deploy-fastapi-on-cloud-providers }\n\nSie können praktisch **jeden Cloudanbieter** verwenden, um Ihre FastAPI-Anwendung zu deployen.\n\nIn den meisten Fällen bieten die großen Cloudanbieter Anleitungen zum Deployment von FastAPI an.\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** wurde vom selben Autor und Team hinter **FastAPI** entwickelt.\n\nEs vereinfacht den Prozess des **Erstellens**, **Deployens** und **Zugreifens** auf eine API mit minimalem Aufwand.\n\nEs bringt die gleiche **Developer-Experience** beim Erstellen von Apps mit FastAPI auch zum **Deployment** in der Cloud. 🎉\n\nFastAPI Cloud ist der Hauptsponsor und Finanzierungsgeber für die *FastAPI and friends* Open-Source-Projekte. ✨\n\n## Cloudanbieter – Sponsoren { #cloud-providers-sponsors }\n\nEinige andere Cloudanbieter ✨ [**sponsern FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ ebenfalls. 🙇\n\nSie könnten diese ebenfalls in Betracht ziehen, deren Anleitungen folgen und ihre Dienste ausprobieren:\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/de/docs/deployment/concepts.md",
    "content": "# Deployment-Konzepte { #deployments-concepts }\n\nBei dem Deployment – der Bereitstellung – einer **FastAPI**-Anwendung, oder eigentlich jeder Art von Web-API, gibt es mehrere Konzepte, die Sie wahrscheinlich interessieren, und mithilfe der Sie die **am besten geeignete** Methode zum **Deployment Ihrer Anwendung** finden können.\n\nEinige wichtige Konzepte sind:\n\n* Sicherheit – HTTPS\n* Beim Hochfahren ausführen\n* Neustarts\n* Replikation (die Anzahl der laufenden Prozesse)\n* Arbeitsspeicher\n* Schritte vor dem Start\n\nWir werden sehen, wie diese sich auf das **Deployment** auswirken.\n\nLetztendlich besteht das ultimative Ziel darin, **Ihre API-Clients** auf **sichere** Weise zu versorgen, um **Unterbrechungen** zu vermeiden und die **Rechenressourcen** (z. B. entfernte Server/virtuelle Maschinen) so effizient wie möglich zu nutzen. 🚀\n\nIch erzähle Ihnen hier etwas mehr über diese **Konzepte**, was Ihnen hoffentlich die **Intuition** gibt, die Sie benötigen, um zu entscheiden, wie Sie Ihre API in sehr unterschiedlichen Umgebungen deployen, möglicherweise sogar in **zukünftigen**, die jetzt noch nicht existieren.\n\nDurch die Berücksichtigung dieser Konzepte können Sie die beste Variante des Deployments **Ihrer eigenen APIs** **evaluieren und konzipieren**.\n\nIn den nächsten Kapiteln werde ich Ihnen mehr **konkrete Rezepte** für das Deployment von FastAPI-Anwendungen geben.\n\nAber schauen wir uns zunächst einmal diese grundlegenden **konzeptionellen Ideen** an. Diese Konzepte gelten auch für jede andere Art von Web-API. 💡\n\n## Sicherheit – HTTPS { #security-https }\n\nIm [vorherigen Kapitel über HTTPS](https.md) haben wir erfahren, wie HTTPS Verschlüsselung für Ihre API bereitstellt.\n\nWir haben auch gesehen, dass HTTPS normalerweise von einer Komponente **außerhalb** Ihres Anwendungsservers bereitgestellt wird, einem **TLS-Terminierungsproxy**.\n\nUnd es muss etwas geben, das für die **Erneuerung der HTTPS-Zertifikate** zuständig ist, es könnte sich um dieselbe Komponente handeln oder um etwas anderes.\n\n### Beispieltools für HTTPS { #example-tools-for-https }\n\nEinige der Tools, die Sie als TLS-Terminierungsproxy verwenden können, sind:\n\n* Traefik\n    * Handhabt automatisch Zertifikat-Erneuerungen ✨\n* Caddy\n    * Handhabt automatisch Zertifikat-Erneuerungen ✨\n* Nginx\n    * Mit einer externen Komponente wie Certbot für Zertifikat-Erneuerungen\n* HAProxy\n    * Mit einer externen Komponente wie Certbot für Zertifikat-Erneuerungen\n* Kubernetes mit einem Ingress Controller wie Nginx\n    * Mit einer externen Komponente wie cert-manager für Zertifikat-Erneuerungen\n* Es wird intern von einem Cloudanbieter als Teil seiner Dienste verwaltet (siehe unten 👇)\n\nEine andere Möglichkeit besteht darin, dass Sie einen **Cloud-Dienst** verwenden, der den größten Teil der Arbeit übernimmt, einschließlich der Einrichtung von HTTPS. Er könnte einige Einschränkungen haben oder Ihnen mehr in Rechnung stellen, usw. In diesem Fall müssten Sie jedoch nicht selbst einen TLS-Terminierungsproxy einrichten.\n\nIn den nächsten Kapiteln zeige ich Ihnen einige konkrete Beispiele.\n\n---\n\nDie nächsten zu berücksichtigenden Konzepte drehen sich dann um das Programm, das Ihre eigentliche API ausführt (z. B. Uvicorn).\n\n## Programm und Prozess { #program-and-process }\n\nWir werden viel über den laufenden „**Prozess**“ sprechen, daher ist es nützlich, Klarheit darüber zu haben, was das bedeutet und was der Unterschied zum Wort „**Programm**“ ist.\n\n### Was ist ein Programm { #what-is-a-program }\n\nDas Wort **Programm** wird häufig zur Beschreibung vieler Dinge verwendet:\n\n* Der **Code**, den Sie schreiben, die **Python-Dateien**.\n* Die **Datei**, die vom Betriebssystem **ausgeführt** werden kann, zum Beispiel: `python`, `python.exe` oder `uvicorn`.\n* Ein bestimmtes Programm, während es auf dem Betriebssystem **läuft**, die CPU nutzt und Dinge im Arbeitsspeicher ablegt. Dies wird auch als **Prozess** bezeichnet.\n\n### Was ist ein Prozess { #what-is-a-process }\n\nDas Wort **Prozess** wird normalerweise spezifischer verwendet und bezieht sich nur auf das, was im Betriebssystem ausgeführt wird (wie im letzten Punkt oben):\n\n* Ein bestimmtes Programm, während es auf dem Betriebssystem **ausgeführt** wird.\n    * Dies bezieht sich weder auf die Datei noch auf den Code, sondern **speziell** auf das, was vom Betriebssystem **ausgeführt** und verwaltet wird.\n* Jedes Programm, jeder Code **kann nur dann Dinge tun**, wenn er **ausgeführt** wird, wenn also ein **Prozess läuft**.\n* Der Prozess kann von Ihnen oder vom Betriebssystem **terminiert** („beendet“, „gekillt“) werden. An diesem Punkt hört es auf zu laufen/ausgeführt zu werden und kann **keine Dinge mehr tun**.\n* Hinter jeder Anwendung, die Sie auf Ihrem Computer ausführen, steckt ein Prozess, jedes laufende Programm, jedes Fenster usw. Und normalerweise laufen viele Prozesse **gleichzeitig**, während ein Computer eingeschaltet ist.\n* Es können **mehrere Prozesse** desselben **Programms** gleichzeitig ausgeführt werden.\n\nWenn Sie sich den „Task-Manager“ oder „Systemmonitor“ (oder ähnliche Tools) in Ihrem Betriebssystem ansehen, können Sie viele dieser laufenden Prozesse sehen.\n\nUnd Sie werden beispielsweise wahrscheinlich feststellen, dass mehrere Prozesse dasselbe Browserprogramm ausführen (Firefox, Chrome, Edge, usw.). Normalerweise führen diese einen Prozess pro Browsertab sowie einige andere zusätzliche Prozesse aus.\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\nNachdem wir nun den Unterschied zwischen den Begriffen **Prozess** und **Programm** kennen, sprechen wir weiter über das Deployment.\n\n## Beim Hochfahren ausführen { #running-on-startup }\n\nWenn Sie eine Web-API erstellen, möchten Sie in den meisten Fällen, dass diese **immer läuft**, ununterbrochen, damit Ihre Clients immer darauf zugreifen können. Es sei denn natürlich, Sie haben einen bestimmten Grund, warum Sie möchten, dass diese nur in bestimmten Situationen ausgeführt wird. Meistens möchten Sie jedoch, dass sie ständig ausgeführt wird und **verfügbar** ist.\n\n### Auf einem entfernten Server { #in-a-remote-server }\n\nWenn Sie einen entfernten Server (einen Cloud-Server, eine virtuelle Maschine, usw.) einrichten, können Sie am einfachsten `fastapi run` (welches Uvicorn verwendet) oder etwas Ähnliches manuell ausführen, genau wie bei der lokalen Entwicklung.\n\nUnd es wird funktionieren und **während der Entwicklung** nützlich sein.\n\nWenn Ihre Verbindung zum Server jedoch unterbrochen wird, wird der **laufende Prozess** wahrscheinlich abstürzen.\n\nUnd wenn der Server neu gestartet wird (z. B. nach Updates oder Migrationen vom Cloudanbieter), werden Sie das wahrscheinlich **nicht bemerken**. Und deshalb wissen Sie nicht einmal, dass Sie den Prozess manuell neu starten müssen. Ihre API bleibt also einfach tot. 😱\n\n### Beim Hochfahren automatisch ausführen { #run-automatically-on-startup }\n\nIm Allgemeinen möchten Sie wahrscheinlich, dass das Serverprogramm (z. B. Uvicorn) beim Hochfahren des Servers automatisch gestartet wird und kein **menschliches Eingreifen** erforderlich ist, sodass immer ein Prozess mit Ihrer API ausgeführt wird (z. B. Uvicorn, welches Ihre FastAPI-Anwendung ausführt).\n\n### Separates Programm { #separate-program }\n\nUm dies zu erreichen, haben Sie normalerweise ein **separates Programm**, welches sicherstellt, dass Ihre Anwendung beim Hochfahren ausgeführt wird. Und in vielen Fällen würde es auch sicherstellen, dass auch andere Komponenten oder Anwendungen ausgeführt werden, beispielsweise eine Datenbank.\n\n### Beispieltools zur Ausführung beim Hochfahren { #example-tools-to-run-at-startup }\n\nEinige Beispiele für Tools, die diese Aufgabe übernehmen können, sind:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker im Schwarm-Modus\n* Systemd\n* Supervisor\n* Es wird intern von einem Cloudanbieter im Rahmen seiner Dienste verwaltet\n* Andere ...\n\nIn den nächsten Kapiteln werde ich Ihnen konkretere Beispiele geben.\n\n## Neustart { #restarts }\n\nÄhnlich wie Sie sicherstellen möchten, dass Ihre Anwendung beim Hochfahren ausgeführt wird, möchten Sie wahrscheinlich auch sicherstellen, dass diese nach Fehlern **neu gestartet** wird.\n\n### Wir machen Fehler { #we-make-mistakes }\n\nWir, als Menschen, machen ständig **Fehler**. Software hat fast *immer* **Bugs**, die an verschiedenen Stellen versteckt sind. 🐛\n\nUnd wir als Entwickler verbessern den Code ständig, wenn wir diese Bugs finden und neue Funktionen implementieren (und möglicherweise auch neue Bugs hinzufügen 😅).\n\n### Kleine Fehler automatisch handhaben { #small-errors-automatically-handled }\n\nWenn beim Erstellen von Web-APIs mit FastAPI ein Fehler in unserem Code auftritt, wird FastAPI ihn normalerweise dem einzelnen <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> zurückgeben, der den Fehler ausgelöst hat. 🛡\n\nDer Client erhält für diesen Request einen **500 Internal Server Error**, aber die Anwendung arbeitet bei den nächsten Requests weiter, anstatt einfach komplett abzustürzen.\n\n### Größere Fehler – Abstürze { #bigger-errors-crashes }\n\nDennoch kann es vorkommen, dass wir Code schreiben, der **die gesamte Anwendung zum Absturz bringt** und so zum Absturz von Uvicorn und Python führt. 💥\n\nUnd dennoch möchten Sie wahrscheinlich nicht, dass die Anwendung tot bleibt, weil an einer Stelle ein Fehler aufgetreten ist. Sie möchten wahrscheinlich, dass sie zumindest für die *Pfadoperationen*, die nicht fehlerhaft sind, **weiterläuft**.\n\n### Neustart nach Absturz { #restart-after-crash }\n\nAber in den Fällen mit wirklich schwerwiegenden Fehlern, die den laufenden **Prozess** zum Absturz bringen, benötigen Sie eine externe Komponente, die den Prozess **neu startet**, zumindest ein paar Mal ...\n\n/// tip | Tipp\n\n... Obwohl es wahrscheinlich keinen Sinn macht, sie immer wieder neu zu starten, wenn die gesamte Anwendung einfach **sofort abstürzt**. Aber in diesen Fällen werden Sie es wahrscheinlich während der Entwicklung oder zumindest direkt nach dem Deployment bemerken.\n\nKonzentrieren wir uns also auf die Hauptfälle, in denen die Anwendung in bestimmten Fällen **in der Zukunft** völlig abstürzen könnte und es dann dennoch sinnvoll ist, sie neu zu starten.\n\n///\n\nSie möchten wahrscheinlich, dass eine **externe Komponente** für den Neustart Ihrer Anwendung verantwortlich ist, da zu diesem Zeitpunkt dieselbe Anwendung mit Uvicorn und Python bereits abgestürzt ist und es daher nichts im selben Code derselben Anwendung gibt, was etwas dagegen tun kann.\n\n### Beispieltools zum automatischen Neustart { #example-tools-to-restart-automatically }\n\nIn den meisten Fällen wird dasselbe Tool, das zum **Ausführen des Programms beim Hochfahren** verwendet wird, auch für automatische **Neustarts** verwendet.\n\nDies könnte zum Beispiel erledigt werden durch:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker im Schwarm-Modus\n* Systemd\n* Supervisor\n* Intern von einem Cloudanbieter im Rahmen seiner Dienste\n* Andere ...\n\n## Replikation – Prozesse und Arbeitsspeicher { #replication-processes-and-memory }\n\nWenn Sie eine FastAPI-Anwendung verwenden und ein Serverprogramm wie den `fastapi`-Befehl, der Uvicorn ausführt, kann **ein einzelner Prozess** an mehrere Clients gleichzeitig ausliefern.\n\nIn vielen Fällen möchten Sie jedoch mehrere Workerprozesse gleichzeitig ausführen.\n\n### Mehrere Prozesse – Worker { #multiple-processes-workers }\n\nWenn Sie mehr Clients haben, als ein einzelner Prozess verarbeiten kann (z. B. wenn die virtuelle Maschine nicht sehr groß ist) und die CPU des Servers **mehrere Kerne** hat, dann könnten **mehrere Prozesse** gleichzeitig mit derselben Anwendung laufen und alle Requests unter sich verteilen.\n\nWenn Sie mit **mehreren Prozessen** dasselbe API-Programm ausführen, werden diese üblicherweise als <abbr title=\"Arbeiter\">**Worker**</abbr> bezeichnet.\n\n### Workerprozesse und Ports { #worker-processes-and-ports }\n\nErinnern Sie sich aus der Dokumentation [Über HTTPS](https.md), dass nur ein Prozess auf einer Kombination aus Port und IP-Adresse auf einem Server lauschen kann?\n\nDas ist immer noch wahr.\n\nUm also **mehrere Prozesse** gleichzeitig zu haben, muss es einen **einzelnen Prozess geben, der einen Port überwacht**, welcher dann die Kommunikation auf irgendeine Weise an jeden Workerprozess überträgt.\n\n### Arbeitsspeicher pro Prozess { #memory-per-process }\n\nWenn das Programm nun Dinge in den Arbeitsspeicher lädt, zum Beispiel ein Modell für maschinelles Lernen in einer Variablen oder den Inhalt einer großen Datei in einer Variablen, verbraucht das alles **einen Teil des Arbeitsspeichers (RAM – Random Access Memory)** des Servers.\n\nUnd mehrere Prozesse teilen sich normalerweise keinen Speicher. Das bedeutet, dass jeder laufende Prozess seine eigenen Dinge, eigenen Variablen und eigenen Speicher hat. Und wenn Sie in Ihrem Code viel Speicher verbrauchen, verbraucht **jeder Prozess** die gleiche Menge Speicher.\n\n### Serverspeicher { #server-memory }\n\nWenn Ihr Code beispielsweise ein Machine-Learning-Modell mit **1 GB Größe** lädt und Sie einen Prozess mit Ihrer API ausführen, verbraucht dieser mindestens 1 GB RAM. Und wenn Sie **4 Prozesse** (4 Worker) starten, verbraucht jeder 1 GB RAM. Insgesamt verbraucht Ihre API also **4 GB RAM**.\n\nUnd wenn Ihr entfernter Server oder Ihre virtuelle Maschine nur über 3 GB RAM verfügt, führt der Versuch, mehr als 4 GB RAM zu laden, zu Problemen. 🚨\n\n### Mehrere Prozesse – Ein Beispiel { #multiple-processes-an-example }\n\nIm folgenden Beispiel gibt es einen **Manager-Prozess**, welcher zwei **Workerprozesse** startet und steuert.\n\nDieser Manager-Prozess wäre wahrscheinlich derjenige, welcher der IP am **Port** lauscht. Und er würde die gesamte Kommunikation an die Workerprozesse weiterleiten.\n\nDiese Workerprozesse würden Ihre Anwendung ausführen, sie würden die Hauptberechnungen durchführen, um einen **<abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr>** entgegenzunehmen und eine **<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>** zurückzugeben, und sie würden alles, was Sie in Variablen einfügen, in den RAM laden.\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\nUnd natürlich würden auf derselben Maschine neben Ihrer Anwendung wahrscheinlich **andere Prozesse** laufen.\n\nEin interessantes Detail ist dabei, dass der Prozentsatz der von jedem Prozess verwendeten **CPU** im Laufe der Zeit stark **variieren** kann, der **Arbeitsspeicher (RAM)** jedoch normalerweise mehr oder weniger **stabil** bleibt.\n\nWenn Sie eine API haben, die jedes Mal eine vergleichbare Menge an Berechnungen durchführt, und Sie viele Clients haben, dann wird die **CPU-Auslastung** wahrscheinlich *ebenfalls stabil sein* (anstatt ständig schnell zu steigen und zu fallen).\n\n### Beispiele für Replikation-Tools und -Strategien { #examples-of-replication-tools-and-strategies }\n\nEs gibt mehrere Ansätze, um dies zu erreichen, und ich werde Ihnen in den nächsten Kapiteln mehr über bestimmte Strategien erzählen, beispielsweise wenn es um Docker und Container geht.\n\nDie wichtigste zu berücksichtigende Einschränkung besteht darin, dass es eine **einzelne** Komponente geben muss, welche die **öffentliche IP** auf dem **Port** verwaltet. Und dann muss diese irgendwie die Kommunikation **weiterleiten**, an die replizierten **Prozesse/Worker**.\n\nHier sind einige mögliche Kombinationen und Strategien:\n\n* **Uvicorn** mit `--workers`\n    * Ein Uvicorn-**Prozessmanager** würde der **IP** am **Port** lauschen, und er würde **mehrere Uvicorn-Workerprozesse** starten.\n* **Kubernetes** und andere verteilte **Containersysteme**\n    * Etwas in der **Kubernetes**-Ebene würde die **IP** und den **Port** abhören. Die Replikation hätte **mehrere Container**, in jedem wird jeweils **ein Uvicorn-Prozess** ausgeführt.\n* **Cloud-Dienste**, welche das für Sie erledigen\n    * Der Cloud-Dienst wird wahrscheinlich **die Replikation für Sie übernehmen**. Er würde Sie möglicherweise **einen auszuführenden Prozess** oder ein **zu verwendendes Container-Image** definieren lassen, in jedem Fall wäre es höchstwahrscheinlich **ein einzelner Uvicorn-Prozess**, und der Cloud-Dienst wäre auch verantwortlich für die Replikation.\n\n/// tip | Tipp\n\nMachen Sie sich keine Sorgen, wenn einige dieser Punkte zu **Containern**, Docker oder Kubernetes noch nicht viel Sinn ergeben.\n\nIch werde Ihnen in einem zukünftigen Kapitel mehr über Container-Images, Docker, Kubernetes, usw. erzählen: [FastAPI in Containern – Docker](docker.md).\n\n///\n\n## Schritte vor dem Start { #previous-steps-before-starting }\n\nEs gibt viele Fälle, in denen Sie, **bevor Sie Ihre Anwendung starten**, einige Schritte ausführen möchten.\n\nBeispielsweise möchten Sie möglicherweise **Datenbankmigrationen** ausführen.\n\nIn den meisten Fällen möchten Sie diese Schritte jedoch nur **einmal** ausführen.\n\nSie möchten also einen **einzelnen Prozess** haben, um diese **Vorab-Schritte** auszuführen, bevor Sie die Anwendung starten.\n\nUnd Sie müssen sicherstellen, dass es sich um einen einzelnen Prozess handelt, der die Vorab-Schritte ausführt, *auch* wenn Sie anschließend **mehrere Prozesse** (mehrere Worker) für die Anwendung selbst starten. Wenn diese Schritte von **mehreren Prozessen** ausgeführt würden, würden diese die Arbeit **verdoppeln**, indem sie sie **parallel** ausführen, und wenn es sich bei den Schritten um etwas Delikates wie eine Datenbankmigration handelt, könnte das miteinander Konflikte verursachen.\n\nNatürlich gibt es Fälle, in denen es kein Problem darstellt, die Vorab-Schritte mehrmals auszuführen. In diesem Fall ist die Handhabung viel einfacher.\n\n/// tip | Tipp\n\nBedenken Sie außerdem, dass Sie, abhängig von Ihrer Einrichtung, in manchen Fällen **gar keine Vorab-Schritte** benötigen, bevor Sie die Anwendung starten.\n\nIn diesem Fall müssen Sie sich darüber keine Sorgen machen. 🤷\n\n///\n\n### Beispiele für Strategien für Vorab-Schritte { #examples-of-previous-steps-strategies }\n\nEs hängt **stark** davon ab, wie Sie **Ihr System deployen**, und hängt wahrscheinlich mit der Art und Weise zusammen, wie Sie Programme starten, Neustarts durchführen, usw.\n\nHier sind einige mögliche Ideen:\n\n* Ein „Init-Container“ in Kubernetes, der vor Ihrem Anwendungs-Container ausgeführt wird\n* Ein Bash-Skript, das die Vorab-Schritte ausführt und dann Ihre Anwendung startet\n    * Sie benötigen immer noch eine Möglichkeit, *dieses* Bash-Skript zu starten/neu zu starten, Fehler zu erkennen, usw.\n\n/// tip | Tipp\n\nKonkretere Beispiele hierfür mit Containern gebe ich Ihnen in einem späteren Kapitel: [FastAPI in Containern – Docker](docker.md).\n\n///\n\n## Ressourcennutzung { #resource-utilization }\n\nIhr(e) Server ist (sind) eine **Ressource**, welche Sie mit Ihren Programmen, der Rechenzeit auf den CPUs und dem verfügbaren RAM-Speicher verbrauchen oder **nutzen** können.\n\nWie viele Systemressourcen möchten Sie verbrauchen/nutzen? Sie mögen „nicht viel“ denken, aber in Wirklichkeit möchten Sie tatsächlich **so viel wie möglich ohne Absturz** verwenden.\n\nWenn Sie für drei Server bezahlen, aber nur wenig von deren RAM und CPU nutzen, **verschwenden Sie wahrscheinlich Geld** 💸 und wahrscheinlich **Strom für den Server** 🌎, usw.\n\nIn diesem Fall könnte es besser sein, nur zwei Server zu haben und einen höheren Prozentsatz von deren Ressourcen zu nutzen (CPU, Arbeitsspeicher, Festplatte, Netzwerkbandbreite, usw.).\n\nWenn Sie andererseits über zwei Server verfügen und **100 % ihrer CPU und ihres RAM** nutzen, wird irgendwann ein Prozess nach mehr Speicher fragen und der Server muss die Festplatte als „Speicher“ verwenden (was tausendmal langsamer sein kann) oder er könnte sogar **abstürzen**. Oder ein Prozess muss möglicherweise einige Berechnungen durchführen und müsste warten, bis die CPU wieder frei ist.\n\nIn diesem Fall wäre es besser, **einen zusätzlichen Server** zu besorgen und einige Prozesse darauf auszuführen, damit alle über **genug RAM und CPU-Zeit** verfügen.\n\nEs besteht auch die Möglichkeit, dass es aus irgendeinem Grund zu **Spitzen** in der Nutzung Ihrer API kommt. Vielleicht ist diese viral gegangen, oder vielleicht haben andere Dienste oder Bots damit begonnen, sie zu nutzen. Und vielleicht möchten Sie in solchen Fällen über zusätzliche Ressourcen verfügen, um auf der sicheren Seite zu sein.\n\nSie können eine **beliebige Zahl** festlegen, um beispielsweise eine Ressourcenauslastung zwischen **50 % und 90 %** anzustreben. Der Punkt ist, dass dies wahrscheinlich die wichtigen Dinge sind, die Sie messen und verwenden sollten, um Ihre Deployments zu optimieren.\n\nSie können einfache Tools wie `htop` verwenden, um die in Ihrem Server verwendete CPU und den RAM oder die von jedem Prozess verwendete Menge anzuzeigen. Oder Sie können komplexere Überwachungstools verwenden, die möglicherweise auf mehrere Server usw. verteilt sind.\n\n## Zusammenfassung { #recap }\n\nSie haben hier einige der wichtigsten Konzepte gelesen, die Sie wahrscheinlich berücksichtigen müssen, wenn Sie entscheiden, wie Sie Ihre Anwendung deployen:\n\n* Sicherheit – HTTPS\n* Beim Hochfahren ausführen\n* Neustarts\n* Replikation (die Anzahl der laufenden Prozesse)\n* Arbeitsspeicher\n* Schritte vor dem Start\n\nDas Verständnis dieser Ideen und deren Anwendung sollte Ihnen die nötige Intuition vermitteln, um bei der Konfiguration und Optimierung Ihrer Deployments Entscheidungen zu treffen. 🤓\n\nIn den nächsten Abschnitten gebe ich Ihnen konkretere Beispiele für mögliche Strategien, die Sie verfolgen können. 🚀\n"
  },
  {
    "path": "docs/de/docs/deployment/docker.md",
    "content": "# FastAPI in Containern – Docker { #fastapi-in-containers-docker }\n\nBeim Deployment von FastAPI-Anwendungen besteht ein gängiger Ansatz darin, ein **Linux-Containerimage** zu erstellen. Normalerweise erfolgt dies mit [**Docker**](https://www.docker.com/). Sie können dieses Containerimage dann auf eine von mehreren möglichen Arten deployen.\n\nDie Verwendung von Linux-Containern bietet mehrere Vorteile, darunter **Sicherheit**, **Replizierbarkeit**, **Einfachheit** und andere.\n\n/// tip | Tipp\n\nSie haben es eilig und kennen sich bereits aus? Springen Sie zum [`Dockerfile` unten 👇](#build-a-docker-image-for-fastapi).\n\n///\n\n<details>\n<summary>Dockerfile-Vorschau 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# Wenn Sie hinter einem Proxy wie Nginx oder Traefik sind, fügen Sie --proxy-headers hinzu\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## Was ist ein Container { #what-is-a-container }\n\nContainer (hauptsächlich Linux-Container) sind eine sehr **leichtgewichtige** Möglichkeit, Anwendungen einschließlich aller ihrer Abhängigkeiten und erforderlichen Dateien zu verpacken und sie gleichzeitig von anderen Containern (anderen Anwendungen oder Komponenten) im selben System isoliert zu halten.\n\nLinux-Container werden mit demselben Linux-Kernel des Hosts (Maschine, virtuellen Maschine, Cloud-Servers, usw.) ausgeführt. Das bedeutet einfach, dass sie sehr leichtgewichtig sind (im Vergleich zu vollständigen virtuellen Maschinen, die ein gesamtes Betriebssystem emulieren).\n\nAuf diese Weise verbrauchen Container **wenig Ressourcen**, eine Menge vergleichbar mit der direkten Ausführung der Prozesse (eine virtuelle Maschine würde viel mehr verbrauchen).\n\nContainer verfügen außerdem über ihre eigenen **isoliert** laufenden Prozesse (üblicherweise nur einen Prozess), über ihr eigenes Dateisystem und ihr eigenes Netzwerk, was Deployment, Sicherheit, Entwicklung usw. vereinfacht.\n\n## Was ist ein Containerimage { #what-is-a-container-image }\n\nEin **Container** wird von einem **Containerimage** ausgeführt.\n\nEin Containerimage ist eine **statische** Version aller Dateien, Umgebungsvariablen und des Standardbefehls/-programms, welche in einem Container vorhanden sein sollten. **Statisch** bedeutet hier, dass das Container-**Image** nicht läuft, nicht ausgeführt wird, sondern nur die gepackten Dateien und Metadaten enthält.\n\nIm Gegensatz zu einem „**Containerimage**“, bei dem es sich um den gespeicherten statischen Inhalt handelt, bezieht sich ein „**Container**“ normalerweise auf die laufende Instanz, das Ding, das **ausgeführt** wird.\n\nWenn der **Container** gestartet und ausgeführt wird (gestartet von einem **Containerimage**), kann er Dateien, Umgebungsvariablen usw. erstellen oder ändern. Diese Änderungen sind nur in diesem Container vorhanden, nicht im zugrunde liegenden Containerimage (werden nicht auf der Festplatte gespeichert).\n\nEin Containerimage ist vergleichbar mit der **Programmdatei** und ihrem Inhalt, z. B. `python` und eine Datei `main.py`.\n\nUnd der **Container** selbst (im Gegensatz zum **Containerimage**) ist die tatsächlich laufende Instanz des Images, vergleichbar mit einem **Prozess**. Tatsächlich läuft ein Container nur, wenn er einen **laufenden Prozess** hat (und normalerweise ist es nur ein einzelner Prozess). Der Container stoppt, wenn kein Prozess darin ausgeführt wird.\n\n## Containerimages { #container-images }\n\nDocker ist eines der wichtigsten Tools zum Erstellen und Verwalten von **Containerimages** und **Containern**.\n\nUnd es gibt einen öffentlichen [Docker <abbr title=\"Umschlagplatz\">Hub</abbr>](https://hub.docker.com/) mit vorgefertigten **offiziellen Containerimages** für viele Tools, Umgebungen, Datenbanken und Anwendungen.\n\nBeispielsweise gibt es ein offizielles [Python-Image](https://hub.docker.com/_/python).\n\nUnd es gibt viele andere Images für verschiedene Dinge wie Datenbanken, zum Beispiel für:\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis), usw.\n\nDurch die Verwendung eines vorgefertigten Containerimages ist es sehr einfach, verschiedene Tools zu **kombinieren** und zu verwenden. Zum Beispiel, um eine neue Datenbank auszuprobieren. In den meisten Fällen können Sie die **offiziellen Images** verwenden und diese einfach mit Umgebungsvariablen konfigurieren.\n\nAuf diese Weise können Sie in vielen Fällen etwas über Container und Docker lernen und dieses Wissen mit vielen verschiedenen Tools und Komponenten wiederverwenden.\n\nSie würden also **mehrere Container** mit unterschiedlichen Dingen ausführen, wie einer Datenbank, einer Python-Anwendung, einem Webserver mit einer React-Frontend-Anwendung, und diese über ihr internes Netzwerk miteinander verbinden.\n\nIn alle Containerverwaltungssysteme (wie Docker oder Kubernetes) sind diese Netzwerkfunktionen integriert.\n\n## Container und Prozesse { #containers-and-processes }\n\nEin **Containerimage** enthält normalerweise in seinen Metadaten das Standardprogramm oder den Standardbefehl, der ausgeführt werden soll, wenn der **Container** gestartet wird, sowie die Parameter, die an dieses Programm übergeben werden sollen. Sehr ähnlich zu dem, was wäre, wenn es über die Befehlszeile gestartet werden würde.\n\nWenn ein **Container** gestartet wird, führt er diesen Befehl/dieses Programm aus (Sie können ihn jedoch überschreiben und einen anderen Befehl/ein anderes Programm ausführen lassen).\n\nEin Container läuft, solange der **Hauptprozess** (Befehl oder Programm) läuft.\n\nEin Container hat normalerweise einen **einzelnen Prozess**, aber es ist auch möglich, Unterprozesse vom Hauptprozess aus zu starten, und auf diese Weise haben Sie **mehrere Prozesse** im selben Container.\n\nEs ist jedoch nicht möglich, einen laufenden Container, ohne **mindestens einen laufenden Prozess** zu haben. Wenn der Hauptprozess stoppt, stoppt der Container.\n\n## Ein Docker-Image für FastAPI erstellen { #build-a-docker-image-for-fastapi }\n\nOkay, wollen wir jetzt etwas bauen! 🚀\n\nIch zeige Ihnen, wie Sie ein **Docker-Image** für FastAPI **von Grund auf** erstellen, basierend auf dem **offiziellen Python**-Image.\n\nDas ist, was Sie in **den meisten Fällen** tun möchten, zum Beispiel:\n\n* Bei Verwendung von **Kubernetes** oder ähnlichen Tools\n* Beim Betrieb auf einem **Raspberry Pi**\n* Bei Verwendung eines Cloud-Dienstes, der ein Containerimage für Sie ausführt, usw.\n\n### Paketanforderungen { #package-requirements }\n\nNormalerweise befinden sich die **Paketanforderungen** für Ihre Anwendung in einer Datei.\n\nDies hängt hauptsächlich von dem Tool ab, mit dem Sie diese Anforderungen **installieren**.\n\nDie gebräuchlichste Methode besteht darin, eine Datei `requirements.txt` mit den Namen der Packages und deren Versionen zu erstellen, eine pro Zeile.\n\nSie würden natürlich die gleichen Ideen verwenden, die Sie in [Über FastAPI-Versionen](versions.md) gelesen haben, um die Versionsbereiche festzulegen.\n\nIhre `requirements.txt` könnte beispielsweise so aussehen:\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\nUnd normalerweise würden Sie diese Paketabhängigkeiten mit `pip` installieren, zum Beispiel:\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info | Info\n\nEs gibt andere Formate und Tools zum Definieren und Installieren von Paketabhängigkeiten.\n\n///\n\n### Den **FastAPI**-Code erstellen { #create-the-fastapi-code }\n\n* Erstellen Sie ein `app`-Verzeichnis und betreten Sie es.\n* Erstellen Sie eine leere Datei `__init__.py`.\n* Erstellen Sie eine `main.py`-Datei mit:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\nErstellen Sie nun im selben Projektverzeichnis eine Datei `Dockerfile` mit:\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. Beginne mit dem offiziellen Python-Basisimage.\n\n2. Setze das aktuelle Arbeitsverzeichnis auf `/code`.\n\n    Hier platzieren wir die Datei `requirements.txt` und das Verzeichnis `app`.\n\n3. Kopiere die Datei mit den Paketanforderungen in das Verzeichnis `/code`.\n\n    Kopieren Sie zuerst **nur** die Datei mit den Anforderungen, nicht den Rest des Codes.\n\n    Da sich diese Datei **nicht oft ändert**, erkennt Docker das und verwendet den **Cache** für diesen Schritt, wodurch der Cache auch für den nächsten Schritt aktiviert wird.\n\n4. Installiere die Paketabhängigkeiten aus der Anforderungsdatei.\n\n    Die Option `--no-cache-dir` weist `pip` an, die heruntergeladenen Pakete nicht lokal zu speichern, da dies nur benötigt wird, sollte `pip` erneut ausgeführt werden, um dieselben Pakete zu installieren, aber das ist beim Arbeiten mit Containern nicht der Fall.\n\n    /// note | Hinweis\n\n    Das `--no-cache-dir` bezieht sich nur auf `pip`, es hat nichts mit Docker oder Containern zu tun.\n\n    ///\n\n    Die Option `--upgrade` weist `pip` an, die Packages zu aktualisieren, wenn sie bereits installiert sind.\n\n    Da der vorherige Schritt des Kopierens der Datei vom **Docker-Cache** erkannt werden konnte, wird dieser Schritt auch **den Docker-Cache verwenden**, sofern verfügbar.\n\n    Durch die Verwendung des Caches in diesem Schritt **sparen** Sie viel **Zeit**, wenn Sie das Image während der Entwicklung immer wieder erstellen, anstatt **jedes Mal** alle Abhängigkeiten **herunterzuladen und zu installieren**.\n\n5. Kopiere das Verzeichnis `./app` in das Verzeichnis `/code`.\n\n    Da hier der gesamte Code enthalten ist, der sich **am häufigsten ändert**, wird der Docker-**Cache** nicht ohne weiteres für diesen oder andere **folgende Schritte** verwendet.\n\n    Daher ist es wichtig, dies **nahe dem Ende** des `Dockerfile`s zu platzieren, um die Erstellungszeiten des Containerimages zu optimieren.\n\n6. Lege den **Befehl** fest, um `fastapi run` zu nutzen, welches Uvicorn darunter verwendet.\n\n    `CMD` nimmt eine Liste von Zeichenfolgen entgegen. Jede dieser Zeichenfolgen entspricht dem, was Sie durch Leerzeichen getrennt in die Befehlszeile eingeben würden.\n\n    Dieser Befehl wird aus dem **aktuellen Arbeitsverzeichnis** ausgeführt, dem gleichen `/code`-Verzeichnis, das Sie oben mit `WORKDIR /code` festgelegt haben.\n\n/// tip | Tipp\n\nLernen Sie, was jede Zeile bewirkt, indem Sie auf die Zahlenblasen im Code klicken. 👆\n\n///\n\n/// warning | Achtung\n\nStellen Sie sicher, dass Sie **immer** die **exec form** der Anweisung `CMD` verwenden, wie unten erläutert.\n\n///\n\n#### `CMD` – Exec Form verwenden { #use-cmd-exec-form }\n\nDie [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) Docker-Anweisung kann in zwei Formen geschrieben werden:\n\n✅ **Exec** form:\n\n```Dockerfile\n# ✅ Tun Sie das\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ **Shell** form:\n\n```Dockerfile\n# ⛔️ Tun Sie das nicht\nCMD fastapi run app/main.py --port 80\n```\n\nAchten Sie darauf, stets die **exec** form zu verwenden, um sicherzustellen, dass FastAPI ordnungsgemäß heruntergefahren wird und [Lifespan-Events](../advanced/events.md) ausgelöst werden.\n\nSie können mehr darüber in der [Docker-Dokumentation für Shell und Exec Form lesen](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).\n\nDies kann insbesondere bei der Verwendung von `docker compose` deutlich spürbar sein. Sehen Sie sich diesen Abschnitt in der Docker Compose-FAQ für technische Details an: [Warum benötigen meine Dienste 10 Sekunden, um neu erstellt oder gestoppt zu werden?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).\n\n#### Verzeichnisstruktur { #directory-structure }\n\nSie sollten jetzt eine Verzeichnisstruktur wie diese haben:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### Hinter einem TLS-Terminierungsproxy { #behind-a-tls-termination-proxy }\n\nWenn Sie Ihren Container hinter einem TLS-Terminierungsproxy (Load Balancer) wie Nginx oder Traefik ausführen, fügen Sie die Option `--proxy-headers` hinzu. Das sagt Uvicorn (durch das FastAPI CLI), den von diesem Proxy gesendeten Headern zu vertrauen und dass die Anwendung hinter HTTPS ausgeführt wird, usw.\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Docker-Cache { #docker-cache }\n\nIn diesem `Dockerfile` gibt es einen wichtigen Trick: Wir kopieren zuerst die **Datei nur mit den Abhängigkeiten**, nicht den Rest des Codes. Lassen Sie mich Ihnen erklären, warum.\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker und andere Tools **erstellen** diese Containerimages **inkrementell**, fügen **eine Ebene über der anderen** hinzu, beginnend am Anfang des `Dockerfile`s und fügen alle durch die einzelnen Anweisungen des `Dockerfile`s erstellten Dateien hinzu.\n\nDocker und ähnliche Tools verwenden beim Erstellen des Images auch einen **internen Cache**. Wenn sich eine Datei seit der letzten Erstellung des Containerimages nicht geändert hat, wird **dieselbe Ebene wiederverwendet**, die beim letzten Mal erstellt wurde, anstatt die Datei erneut zu kopieren und eine neue Ebene von Grund auf zu erstellen.\n\nDas bloße Vermeiden des Kopierens von Dateien führt nicht unbedingt zu einer großen Verbesserung, aber da der Cache für diesen Schritt verwendet wurde, kann **der Cache für den nächsten Schritt verwendet werden**. Beispielsweise könnte der Cache verwendet werden für die Anweisung, welche die Abhängigkeiten installiert mit:\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\nDie Datei mit den Paketanforderungen wird sich **nicht häufig ändern**. Wenn Docker also nur diese Datei kopiert, kann es für diesen Schritt **den Cache verwenden**.\n\nUnd dann kann Docker **den Cache für den nächsten Schritt verwenden**, der diese Abhängigkeiten herunterlädt und installiert. Und hier **sparen wir viel Zeit**. ✨ ... und vermeiden die Langeweile beim Warten. 😪😆\n\nDas Herunterladen und Installieren der Paketabhängigkeiten **könnte Minuten dauern**, aber die Verwendung des **Cache** würde höchstens **Sekunden** dauern.\n\nUnd da Sie das Containerimage während der Entwicklung immer wieder erstellen würden, um zu überprüfen, ob Ihre Codeänderungen funktionieren, würde dies viel Zeit sparen.\n\nDann, gegen Ende des `Dockerfile`s, kopieren wir den gesamten Code. Da sich der **am häufigsten ändert**, platzieren wir das am Ende, da fast immer alles nach diesem Schritt nicht mehr in der Lage sein wird, den Cache zu verwenden.\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### Das Docker-Image erstellen { #build-the-docker-image }\n\nNachdem nun alle Dateien vorhanden sind, erstellen wir das Containerimage.\n\n* Gehen Sie zum Projektverzeichnis (dort, wo sich Ihr `Dockerfile` und Ihr `app`-Verzeichnis befindet).\n* Erstellen Sie Ihr FastAPI-Image:\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | Tipp\n\nBeachten Sie das `.` am Ende, es entspricht `./` und teilt Docker mit, welches Verzeichnis zum Erstellen des Containerimages verwendet werden soll.\n\nIn diesem Fall handelt es sich um dasselbe aktuelle Verzeichnis (`.`).\n\n///\n\n### Den Docker-Container starten { #start-the-docker-container }\n\n* Führen Sie einen Container basierend auf Ihrem Image aus:\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## Es testen { #check-it }\n\nSie sollten es in der URL Ihres Docker-Containers überprüfen können, zum Beispiel: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) oder [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (oder gleichwertig, unter Verwendung Ihres Docker-Hosts).\n\nSie werden etwas sehen wie:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## Interaktive API-Dokumentation { #interactive-api-docs }\n\nJetzt können Sie auf [http://192.168.99.100/docs](http://192.168.99.100/docs) oder [http://127.0.0.1/docs](http://127.0.0.1/docs) gehen (oder ähnlich, unter Verwendung Ihres Docker-Hosts).\n\nSie sehen die automatische interaktive API-Dokumentation (bereitgestellt von [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger-Oberfläche](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## Alternative API-Dokumentation { #alternative-api-docs }\n\nSie können auch auf [http://192.168.99.100/redoc](http://192.168.99.100/redoc) oder [http://127.0.0.1/redoc](http://127.0.0.1/redoc) gehen (oder ähnlich, unter Verwendung Ihres Docker-Hosts).\n\nSie sehen die alternative automatische Dokumentation (bereitgestellt von [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Ein Docker-Image mit einem Single-File-FastAPI erstellen { #build-a-docker-image-with-a-single-file-fastapi }\n\nWenn Ihr FastAPI eine einzelne Datei ist, zum Beispiel `main.py` ohne ein `./app`-Verzeichnis, könnte Ihre Dateistruktur wie folgt aussehen:\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\nDann müssten Sie nur noch die entsprechenden Pfade ändern, um die Datei im `Dockerfile` zu kopieren:\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. Kopiere die Datei `main.py` direkt in das Verzeichnis `/code` (ohne ein Verzeichnis `./app`).\n\n2. Verwenden Sie `fastapi run`, um Ihre Anwendung in der einzelnen Datei `main.py` bereitzustellen.\n\nIndem Sie die Datei an `fastapi run` übergeben, wird automatisch erkannt, dass es sich um eine einzelne Datei handelt und nicht um den Teil eines Packages, und es wird wissen, wie es zu importieren ist und Ihre FastAPI-App bereitzustellen. 😎\n\n## Deployment-Konzepte { #deployment-concepts }\n\nLassen Sie uns noch einmal über einige der gleichen [Deployment-Konzepte](concepts.md) in Bezug auf Container sprechen.\n\nContainer sind hauptsächlich ein Werkzeug, um den Prozess des **Erstellens und Deployments** einer Anwendung zu vereinfachen, sie erzwingen jedoch keinen bestimmten Ansatz für die Handhabung dieser **Deployment-Konzepte**, und es gibt mehrere mögliche Strategien.\n\nDie **gute Nachricht** ist, dass es mit jeder unterschiedlichen Strategie eine Möglichkeit gibt, alle Deployment-Konzepte abzudecken. 🎉\n\nSehen wir uns diese **Deployment-Konzepte** im Hinblick auf Container noch einmal an:\n\n* HTTPS\n* Beim Hochfahren ausführen\n* Neustarts\n* Replikation (die Anzahl der laufenden Prozesse)\n* Arbeitsspeicher\n* Schritte vor dem Start\n\n## HTTPS { #https }\n\nWenn wir uns nur auf das **Containerimage** für eine FastAPI-Anwendung (und später auf den laufenden **Container**) konzentrieren, würde HTTPS normalerweise **extern** von einem anderen Tool verarbeitet.\n\nEs könnte sich um einen anderen Container handeln, zum Beispiel mit [Traefik](https://traefik.io/), welcher **HTTPS** und **automatischen** Erwerb von **Zertifikaten** handhabt.\n\n/// tip | Tipp\n\nTraefik verfügt über Integrationen mit Docker, Kubernetes und anderen, sodass Sie damit ganz einfach HTTPS für Ihre Container einrichten und konfigurieren können.\n\n///\n\nAlternativ könnte HTTPS von einem Cloud-Anbieter als einer seiner Dienste gehandhabt werden (während die Anwendung weiterhin in einem Container ausgeführt wird).\n\n## Beim Hochfahren ausführen und Neustarts { #running-on-startup-and-restarts }\n\nNormalerweise gibt es ein anderes Tool, das für das **Starten und Ausführen** Ihres Containers zuständig ist.\n\nEs könnte sich um **Docker** direkt, **Docker Compose**, **Kubernetes**, einen **Cloud-Dienst**, usw. handeln.\n\nIn den meisten (oder allen) Fällen gibt es eine einfache Option, um die Ausführung des Containers beim Hochfahren und Neustarts bei Fehlern zu ermöglichen. In Docker ist es beispielsweise die Befehlszeilenoption `--restart`.\n\nOhne die Verwendung von Containern kann es umständlich und schwierig sein, Anwendungen beim Hochfahren auszuführen und neu zu starten. Bei der **Arbeit mit Containern** ist diese Funktionalität jedoch in den meisten Fällen standardmäßig enthalten. ✨\n\n## Replikation – Anzahl der Prozesse { #replication-number-of-processes }\n\nWenn Sie einen <dfn title=\"Eine Gruppe von Maschinen, die so konfiguriert sind, dass sie verbunden sind und auf irgendeine Weise zusammenarbeiten.\">Cluster</dfn> von Maschinen mit **Kubernetes**, Docker Swarm Mode, Nomad verwenden, oder einem anderen, ähnlich komplexen System zur Verwaltung verteilter Container auf mehreren Maschinen, möchten Sie wahrscheinlich die **Replikation auf Cluster-Ebene abwickeln**, anstatt in jedem Container einen **Prozessmanager** (wie Uvicorn mit Workern) zu verwenden.\n\nDiese verteilten Containerverwaltungssysteme wie Kubernetes verfügen normalerweise über eine integrierte Möglichkeit, die **Replikation von Containern** zu handhaben und gleichzeitig **Load Balancing** für die eingehenden <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> zu unterstützen. Alles auf **Cluster-Ebene**.\n\nIn diesen Fällen möchten Sie wahrscheinlich ein **Docker-Image von Grund auf** erstellen, wie [oben erklärt](#dockerfile), Ihre Abhängigkeiten installieren und **einen einzelnen Uvicorn-Prozess** ausführen, anstatt mehrere Uvicorn-Worker zu verwenden.\n\n### Load Balancer { #load-balancer }\n\nBei der Verwendung von Containern ist normalerweise eine Komponente vorhanden, **die am Hauptport lauscht**. Es könnte sich um einen anderen Container handeln, der auch ein **TLS-Terminierungsproxy** ist, um **HTTPS** zu verarbeiten, oder ein ähnliches Tool.\n\nDa diese Komponente die **Last** an Requests aufnehmen und diese (hoffentlich) **ausgewogen** auf die Worker verteilen würde, wird sie üblicherweise auch <abbr title=\"Lastverteiler\">**Load Balancer**</abbr> genannt.\n\n/// tip | Tipp\n\nDie gleiche **TLS-Terminierungsproxy**-Komponente, die für HTTPS verwendet wird, wäre wahrscheinlich auch ein **Load Balancer**.\n\n///\n\nUnd wenn Sie mit Containern arbeiten, verfügt das gleiche System, mit dem Sie diese starten und verwalten, bereits über interne Tools, um die **Netzwerkkommunikation** (z. B. HTTP-Requests) von diesem **Load Balancer** (das könnte auch ein **TLS-Terminierungsproxy** sein) zu den Containern mit Ihrer Anwendung weiterzuleiten.\n\n### Ein Load Balancer – mehrere Workercontainer { #one-load-balancer-multiple-worker-containers }\n\nBei der Arbeit mit **Kubernetes** oder ähnlichen verteilten Containerverwaltungssystemen würde die Verwendung ihrer internen Netzwerkmechanismen es dem einzelnen **Load Balancer**, der den Haupt-**Port** überwacht, ermöglichen, Kommunikation (Requests) an möglicherweise **mehrere Container** weiterzuleiten, in denen Ihre Anwendung ausgeführt wird.\n\nJeder dieser Container, in denen Ihre Anwendung ausgeführt wird, verfügt normalerweise über **nur einen Prozess** (z. B. einen Uvicorn-Prozess, der Ihre FastAPI-Anwendung ausführt). Es wären alles **identische Container**, die das Gleiche ausführen, welche aber jeweils über einen eigenen Prozess, Speicher, usw. verfügen. Auf diese Weise würden Sie die **Parallelisierung** in **verschiedenen Kernen** der CPU nutzen. Oder sogar in **verschiedenen Maschinen**.\n\nUnd das verteilte Containersystem mit dem **Load Balancer** würde **die Requests abwechselnd** an jeden einzelnen Container mit Ihrer Anwendung verteilen. Jeder Request könnte also von einem der mehreren **replizierten Container** verarbeitet werden, in denen Ihre Anwendung ausgeführt wird.\n\nUnd normalerweise wäre dieser **Load Balancer** in der Lage, Requests zu verarbeiten, die an *andere* Anwendungen in Ihrem Cluster gerichtet sind (z. B. eine andere Domain oder unter einem anderen URL-Pfad-Präfix), und würde diese Kommunikation an die richtigen Container weiterleiten für *diese andere* Anwendung, die in Ihrem Cluster ausgeführt wird.\n\n### Ein Prozess pro Container { #one-process-per-container }\n\nIn einem solchen Szenario möchten Sie wahrscheinlich **einen einzelnen (Uvicorn-)Prozess pro Container** haben, da Sie die Replikation bereits auf Cluster-Ebene durchführen würden.\n\nIn diesem Fall möchten Sie also **nicht** mehrere Worker im Container haben, z. B. mit der `--workers` Befehlszeilenoption. Sie möchten nur einen **einzelnen Uvicorn-Prozess** pro Container haben (wahrscheinlich aber mehrere Container).\n\nEin weiterer Prozessmanager im Container (wie es bei mehreren Workern der Fall wäre) würde nur **unnötige Komplexität** hinzufügen, um welche Sie sich höchstwahrscheinlich bereits mit Ihrem Clustersystem kümmern.\n\n### Container mit mehreren Prozessen und Sonderfälle { #containers-with-multiple-processes-and-special-cases }\n\nNatürlich gibt es **Sonderfälle**, in denen Sie **einen Container** mit mehreren **Uvicorn-Workerprozessen** haben möchten.\n\nIn diesen Fällen können Sie die `--workers` Befehlszeilenoption verwenden, um die Anzahl der zu startenden Worker festzulegen:\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. Hier verwenden wir die `--workers` Befehlszeilenoption, um die Anzahl der Worker auf 4 festzulegen.\n\nHier sind einige Beispiele, wann das sinnvoll sein könnte:\n\n#### Eine einfache Anwendung { #a-simple-app }\n\nSie könnten einen Prozessmanager im Container haben wollen, wenn Ihre Anwendung **einfach genug** ist, sodass Sie es auf einem **einzelnen Server** ausführen können, nicht auf einem Cluster.\n\n#### Docker Compose { #docker-compose }\n\nSie könnten das Deployment auf einem **einzelnen Server** (kein Cluster) mit **Docker Compose** durchführen, sodass Sie keine einfache Möglichkeit hätten, die Replikation von Containern (mit Docker Compose) zu verwalten und gleichzeitig das gemeinsame Netzwerk mit **Load Balancing** zu haben.\n\nDann möchten Sie vielleicht **einen einzelnen Container** mit einem **Prozessmanager** haben, der darin **mehrere Workerprozesse** startet.\n\n---\n\nDer Hauptpunkt ist, dass **keine** dieser Regeln **in Stein gemeißelt** ist, der man blind folgen muss. Sie können diese Ideen verwenden, um **Ihren eigenen Anwendungsfall zu evaluieren**, zu entscheiden, welcher Ansatz für Ihr System am besten geeignet ist und herauszufinden, wie Sie folgende Konzepte verwalten:\n\n* Sicherheit – HTTPS\n* Beim Hochfahren ausführen\n* Neustarts\n* Replikation (die Anzahl der laufenden Prozesse)\n* Arbeitsspeicher\n* Schritte vor dem Start\n\n## Arbeitsspeicher { #memory }\n\nWenn Sie **einen einzelnen Prozess pro Container** ausführen, wird von jedem dieser Container (mehr als einer, wenn sie repliziert werden) eine mehr oder weniger klar definierte, stabile und begrenzte Menge an Arbeitsspeicher verbraucht.\n\nUnd dann können Sie dieselben Speichergrenzen und -anforderungen in Ihren Konfigurationen für Ihr Container-Management-System festlegen (z. B. in **Kubernetes**). Auf diese Weise ist es in der Lage, die Container auf den **verfügbaren Maschinen** zu replizieren, wobei die von diesen benötigte Speichermenge und die auf den Maschinen im Cluster verfügbare Menge berücksichtigt werden.\n\nWenn Ihre Anwendung **einfach** ist, wird dies wahrscheinlich **kein Problem darstellen** und Sie müssen möglicherweise keine festen Speichergrenzen angeben. Wenn Sie jedoch **viel Speicher verbrauchen** (z. B. bei **Modellen für maschinelles Lernen**), sollten Sie überprüfen, wie viel Speicher Sie verbrauchen, und die **Anzahl der Container** anpassen, die in **jeder Maschine** ausgeführt werden (und möglicherweise weitere Maschinen zu Ihrem Cluster hinzufügen).\n\nWenn Sie **mehrere Prozesse pro Container** ausführen, müssen Sie sicherstellen, dass die Anzahl der gestarteten Prozesse nicht **mehr Speicher verbraucht** als verfügbar ist.\n\n## Schritte vor dem Start und Container { #previous-steps-before-starting-and-containers }\n\nWenn Sie Container (z. B. Docker, Kubernetes) verwenden, können Sie hauptsächlich zwei Ansätze verwenden.\n\n### Mehrere Container { #multiple-containers }\n\nWenn Sie **mehrere Container** haben, von denen wahrscheinlich jeder einen **einzelnen Prozess** ausführt (z. B. in einem **Kubernetes**-Cluster), dann möchten Sie wahrscheinlich einen **separaten Container** haben, welcher die Arbeit der **Vorab-Schritte** in einem einzelnen Container, mit einem einzelnen Prozess ausführt, **bevor** die replizierten Workercontainer ausgeführt werden.\n\n/// info | Info\n\nWenn Sie Kubernetes verwenden, wäre dies wahrscheinlich ein [Init-Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).\n\n///\n\nWenn es in Ihrem Anwendungsfall kein Problem darstellt, diese vorherigen Schritte **mehrmals parallel** auszuführen (z. B. wenn Sie keine Datenbankmigrationen ausführen, sondern nur prüfen, ob die Datenbank bereits bereit ist), können Sie sie auch einfach in jedem Container direkt vor dem Start des Hauptprozesses einfügen.\n\n### Einzelner Container { #single-container }\n\nWenn Sie ein einfaches Setup mit einem **einzelnen Container** haben, welcher dann mehrere **Workerprozesse** (oder auch nur einen Prozess) startet, können Sie die Vorab-Schritte im selben Container direkt vor dem Starten des Prozesses mit der Anwendung ausführen.\n\n### Docker-Basisimage { #base-docker-image }\n\nEs gab ein offizielles FastAPI-Docker-Image: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). Dieses ist jedoch jetzt deprecatet. ⛔️\n\nSie sollten wahrscheinlich **nicht** dieses Basis-Docker-Image (oder ein anderes ähnliches) verwenden.\n\nWenn Sie **Kubernetes** (oder andere) verwenden und bereits **Replikation** auf Cluster-Ebene mit mehreren **Containern** eingerichtet haben. In diesen Fällen ist es besser, **ein Image von Grund auf neu zu erstellen**, wie oben beschrieben: [Ein Docker-Image für FastAPI erstellen](#build-a-docker-image-for-fastapi).\n\nUnd wenn Sie mehrere Worker benötigen, können Sie einfach die `--workers` Befehlszeilenoption verwenden.\n\n/// note | Technische Details\n\nDas Docker-Image wurde erstellt, als Uvicorn das Verwalten und Neustarten von ausgefallenen Workern noch nicht unterstützte, weshalb es notwendig war, Gunicorn mit Uvicorn zu verwenden, was zu einer erheblichen Komplexität führte, nur damit Gunicorn die Uvicorn-Workerprozesse verwaltet und neu startet.\n\nAber jetzt, da Uvicorn (und der `fastapi`-Befehl) die Verwendung von `--workers` unterstützen, gibt es keinen Grund, ein Basis-Docker-Image an Stelle eines eigenen (das praktisch denselben Code enthält 😅) zu verwenden.\n\n///\n\n## Deployment des Containerimages { #deploy-the-container-image }\n\nNachdem Sie ein Containerimage (Docker) haben, gibt es mehrere Möglichkeiten, es bereitzustellen.\n\nZum Beispiel:\n\n* Mit **Docker Compose** auf einem einzelnen Server\n* Mit einem **Kubernetes**-Cluster\n* Mit einem Docker Swarm Mode-Cluster\n* Mit einem anderen Tool wie Nomad\n* Mit einem Cloud-Dienst, der Ihr Containerimage nimmt und es deployt\n\n## Docker-Image mit `uv` { #docker-image-with-uv }\n\nWenn Sie [uv](https://github.com/astral-sh/uv) verwenden, um Ihr Projekt zu installieren und zu verwalten, können Sie deren [uv-Docker-Leitfaden](https://docs.astral.sh/uv/guides/integration/docker/) befolgen.\n\n## Zusammenfassung { #recap }\n\nMithilfe von Containersystemen (z. B. mit **Docker** und **Kubernetes**) ist es ziemlich einfach, alle **Deployment-Konzepte** zu handhaben:\n\n* HTTPS\n* Beim Hochfahren ausführen\n* Neustarts\n* Replikation (die Anzahl der laufenden Prozesse)\n* Arbeitsspeicher\n* Schritte vor dem Start\n\nIn den meisten Fällen möchten Sie wahrscheinlich kein Basisimage verwenden und stattdessen **ein Containerimage von Grund auf erstellen**, eines basierend auf dem offiziellen Python-Docker-Image.\n\nIndem Sie auf die **Reihenfolge** der Anweisungen im `Dockerfile` und den **Docker-Cache** achten, können Sie **die Build-Zeiten minimieren**, um Ihre Produktivität zu erhöhen (und Langeweile zu vermeiden). 😎\n"
  },
  {
    "path": "docs/de/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\nSie können Ihre FastAPI-App in der [FastAPI Cloud](https://fastapicloud.com) mit **einem einzigen Befehl** deployen – tragen Sie sich in die Warteliste ein, falls noch nicht geschehen. 🚀\n\n## Anmelden { #login }\n\nStellen Sie sicher, dass Sie bereits ein **FastAPI-Cloud-Konto** haben (wir haben Sie von der Warteliste eingeladen 😉).\n\nMelden Sie sich dann an:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## Deployen { #deploy }\n\nStellen Sie Ihre App jetzt mit **einem einzigen Befehl** bereit:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nDas war’s! Jetzt können Sie Ihre App unter dieser URL aufrufen. ✨\n\n## Über FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** wird vom gleichen Autor und Team hinter **FastAPI** entwickelt.\n\nEs vereinfacht den Prozess des **Erstellens**, **Deployens** und **Nutzens** einer API mit minimalem Aufwand.\n\nEs bringt die gleiche **Developer-Experience** beim Erstellen von Apps mit FastAPI auch zum **Deployment** in der Cloud. 🎉\n\nEs kümmert sich außerdem um das meiste, was beim Deployen einer App nötig ist, zum Beispiel:\n\n* HTTPS\n* Replikation, mit Autoscaling basierend auf Requests\n* usw.\n\nFastAPI Cloud ist Hauptsponsor und Finanzierer der Open-Source-Projekte *FastAPI and friends*. ✨\n\n## Bei anderen Cloudanbietern deployen { #deploy-to-other-cloud-providers }\n\nFastAPI ist Open Source und basiert auf Standards. Sie können FastAPI-Apps bei jedem Cloudanbieter Ihrer Wahl deployen.\n\nFolgen Sie den Anleitungen Ihres Cloudanbieters, um dort FastAPI-Apps zu deployen. 🤓\n\n## Auf den eigenen Server deployen { #deploy-your-own-server }\n\nIch werde Ihnen später in diesem **Deployment-Leitfaden** auch alle Details zeigen, sodass Sie verstehen, was passiert, was geschehen muss und wie Sie FastAPI-Apps selbst deployen können, auch auf Ihre eigenen Server. 🤓\n"
  },
  {
    "path": "docs/de/docs/deployment/https.md",
    "content": "# Über HTTPS { #about-https }\n\nEs ist leicht anzunehmen, dass HTTPS etwas ist, was einfach nur „aktiviert“ wird oder nicht.\n\nAber es ist viel komplexer als das.\n\n/// tip | Tipp\n\nWenn Sie es eilig haben oder es Ihnen egal ist, fahren Sie mit den nächsten Abschnitten fort, um Schritt-für-Schritt-Anleitungen für die Einrichtung der verschiedenen Technologien zu erhalten.\n\n///\n\nUm **die Grundlagen von HTTPS** aus Sicht des Benutzers zu erlernen, schauen Sie sich [https://howhttps.works/](https://howhttps.works/) an.\n\nAus **Sicht des Entwicklers** sollten Sie beim Nachdenken über HTTPS Folgendes beachten:\n\n* Für HTTPS muss **der Server** über von einem **Dritten** generierte **„Zertifikate“** verfügen.\n    * Diese Zertifikate werden tatsächlich vom Dritten **erworben** und nicht „generiert“.\n* Zertifikate haben eine **Lebensdauer**.\n    * Sie **verfallen**.\n    * Und dann müssen sie vom Dritten **erneuert**, **erneut erworben** werden.\n* Die Verschlüsselung der Verbindung erfolgt auf **TCP-Ebene**.\n    * Das ist eine Schicht **unter HTTP**.\n    * Die Handhabung von **Zertifikaten und Verschlüsselung** erfolgt also **vor HTTP**.\n* **TCP weiß nichts über „Domains“**. Nur über IP-Adressen.\n    * Die Informationen über die angeforderte **spezifische Domain** befinden sich in den **HTTP-Daten**.\n* Die **HTTPS-Zertifikate** „zertifizieren“ eine **bestimmte Domain**, aber das Protokoll und die Verschlüsselung erfolgen auf TCP-Ebene, **ohne zu wissen**, um welche Domain es sich handelt.\n* **Standardmäßig** bedeutet das, dass Sie nur **ein HTTPS-Zertifikat pro IP-Adresse** haben können.\n    * Ganz gleich, wie groß Ihr Server ist oder wie klein die einzelnen Anwendungen darauf sind.\n    * Hierfür gibt es jedoch eine **Lösung**.\n* Es gibt eine **Erweiterung** zum **TLS**-Protokoll (dasjenige, das die Verschlüsselung auf TCP-Ebene, vor HTTP, verwaltet) namens **[<abbr title=\"Server Name Indication - Servernamensanzeige\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**.\n    * Mit dieser SNI-Erweiterung kann ein einzelner Server (mit einer **einzelnen IP-Adresse**) über **mehrere HTTPS-Zertifikate** verfügen und **mehrere HTTPS-Domains/Anwendungen bereitstellen**.\n    * Damit das funktioniert, muss eine **einzelne** Komponente (Programm), die auf dem Server ausgeführt wird und welche die **öffentliche IP-Adresse** überwacht, **alle HTTPS-Zertifikate** des Servers haben.\n* **Nachdem** eine sichere Verbindung hergestellt wurde, ist das Kommunikationsprotokoll **immer noch HTTP**.\n    * Die Inhalte sind **verschlüsselt**, auch wenn sie mit dem **HTTP-Protokoll** gesendet werden.\n\nEs ist eine gängige Praxis, **ein Programm/HTTP-Server** auf dem Server (der Maschine, dem Host usw.) laufen zu lassen, welches **alle HTTPS-Aspekte verwaltet**: Empfangen der **verschlüsselten HTTPS-<abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr>**, Senden der **entschlüsselten HTTP-Requests** an die eigentliche HTTP-Anwendung die auf demselben Server läuft (in diesem Fall die **FastAPI**-Anwendung), entgegennehmen der **HTTP-Response** von der Anwendung, **verschlüsseln derselben** mithilfe des entsprechenden **HTTPS-Zertifikats** und Zurücksenden zum Client über **HTTPS**. Dieser Server wird oft als **[TLS-Terminierungsproxy](https://en.wikipedia.org/wiki/TLS_termination_proxy)** bezeichnet.\n\nEinige der Optionen, die Sie als TLS-Terminierungsproxy verwenden können, sind:\n\n* Traefik (kann auch Zertifikat-Erneuerungen durchführen)\n* Caddy (kann auch Zertifikat-Erneuerungen durchführen)\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\nVor Let's Encrypt wurden diese **HTTPS-Zertifikate** von vertrauenswürdigen Dritten verkauft.\n\nDer Prozess zum Erwerb eines dieser Zertifikate war früher umständlich, erforderte viel Papierarbeit und die Zertifikate waren ziemlich teuer.\n\nAber dann wurde **[Let's Encrypt](https://letsencrypt.org/)** geschaffen.\n\nEs ist ein Projekt der Linux Foundation. Es stellt **kostenlose HTTPS-Zertifikate** automatisiert zur Verfügung. Diese Zertifikate nutzen standardmäßig die gesamte kryptografische Sicherheit und sind kurzlebig (circa 3 Monate), sodass die **Sicherheit tatsächlich besser ist**, aufgrund der kürzeren Lebensdauer.\n\nDie Domains werden sicher verifiziert und die Zertifikate werden automatisch generiert. Das ermöglicht auch die automatische Erneuerung dieser Zertifikate.\n\nDie Idee besteht darin, den Erwerb und die Erneuerung der Zertifikate zu automatisieren, sodass Sie **sicheres HTTPS, kostenlos und für immer** haben können.\n\n## HTTPS für Entwickler { #https-for-developers }\n\nHier ist ein Beispiel, wie eine HTTPS-API aussehen könnte, Schritt für Schritt, wobei vor allem die für Entwickler wichtigen Ideen berücksichtigt werden.\n\n### Domainname { #domain-name }\n\nAlles beginnt wahrscheinlich damit, dass Sie einen **Domainnamen erwerben**. Anschließend konfigurieren Sie ihn in einem DNS-Server (wahrscheinlich beim selben Cloudanbieter).\n\nSie würden wahrscheinlich einen Cloud-Server (eine virtuelle Maschine) oder etwas Ähnliches bekommen, und dieser hätte eine <dfn title=\"Ändert sich im Laufe der Zeit nicht. Nicht dynamisch.\">feste</dfn> **öffentliche IP-Adresse**.\n\nIn dem oder den DNS-Server(n) würden Sie einen Eintrag (einen „`A record`“) konfigurieren, um mit **Ihrer Domain** auf die öffentliche **IP-Adresse Ihres Servers** zu verweisen.\n\nSie würden dies wahrscheinlich nur einmal tun, beim ersten Mal, wenn Sie alles einrichten.\n\n/// tip | Tipp\n\nDieser Domainnamen-Aspekt liegt weit vor HTTPS, aber da alles von der Domain und der IP-Adresse abhängt, lohnt es sich, das hier zu erwähnen.\n\n///\n\n### DNS { #dns }\n\nKonzentrieren wir uns nun auf alle tatsächlichen HTTPS-Aspekte.\n\nZuerst würde der Browser mithilfe der **DNS-Server** herausfinden, welches die **IP für die Domain** ist, in diesem Fall `someapp.example.com`.\n\nDie DNS-Server geben dem Browser eine bestimmte **IP-Adresse** zurück. Das wäre die von Ihrem Server verwendete öffentliche IP-Adresse, die Sie in den DNS-Servern konfiguriert haben.\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### TLS-Handshake-Start { #tls-handshake-start }\n\nDer Browser kommuniziert dann mit dieser IP-Adresse über **Port 443** (den HTTPS-Port).\n\nDer erste Teil der Kommunikation besteht lediglich darin, die Verbindung zwischen dem Client und dem Server herzustellen und die zu verwendenden kryptografischen Schlüssel usw. zu vereinbaren.\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\nDiese Interaktion zwischen dem Client und dem Server zum Aufbau der TLS-Verbindung wird als **<abbr title=\"TLS-Handschlag\">TLS-Handshake</abbr>** bezeichnet.\n\n### TLS mit SNI-Erweiterung { #tls-with-sni-extension }\n\n**Nur ein Prozess** im Server kann an einem bestimmten **Port** einer bestimmten **IP-Adresse** lauschen. Möglicherweise gibt es andere Prozesse, die an anderen Ports dieselbe IP-Adresse abhören, jedoch nur einen für jede Kombination aus IP-Adresse und Port.\n\nTLS (HTTPS) verwendet standardmäßig den spezifischen Port `443`. Das ist also der Port, den wir brauchen.\n\nDa an diesem Port nur ein Prozess lauschen kann, wäre der Prozess, der dies tun würde, der **TLS-Terminierungsproxy**.\n\nDer TLS-Terminierungsproxy hätte Zugriff auf ein oder mehrere **TLS-Zertifikate** (HTTPS-Zertifikate).\n\nMithilfe der oben beschriebenen **SNI-Erweiterung** würde der TLS-Terminierungsproxy herausfinden, welches der verfügbaren TLS-Zertifikate (HTTPS) er für diese Verbindung verwenden muss, und zwar das, welches mit der vom Client erwarteten Domain übereinstimmt.\n\nIn diesem Fall würde er das Zertifikat für `someapp.example.com` verwenden.\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\nDer Client **vertraut** bereits der Entität, die das TLS-Zertifikat generiert hat (in diesem Fall Let's Encrypt, aber wir werden später mehr darüber erfahren), sodass er **verifizieren** kann, dass das Zertifikat gültig ist.\n\nMithilfe des Zertifikats entscheiden der Client und der TLS-Terminierungsproxy dann, **wie der Rest der TCP-Kommunikation verschlüsselt werden soll**. Damit ist der **TLS-Handshake** abgeschlossen.\n\nDanach verfügen der Client und der Server über eine **verschlüsselte TCP-Verbindung**, via TLS. Und dann können sie diese Verbindung verwenden, um die eigentliche **HTTP-Kommunikation** zu beginnen.\n\nUnd genau das ist **HTTPS**, es ist einfach **HTTP** innerhalb einer **sicheren TLS-Verbindung**, statt einer puren (unverschlüsselten) TCP-Verbindung.\n\n/// tip | Tipp\n\nBeachten Sie, dass die Verschlüsselung der Kommunikation auf der **TCP-Ebene** und nicht auf der HTTP-Ebene erfolgt.\n\n///\n\n### HTTPS-Request { #https-request }\n\nDa Client und Server (sprich, der Browser und der TLS-Terminierungsproxy) nun über eine **verschlüsselte TCP-Verbindung** verfügen, können sie die **HTTP-Kommunikation** starten.\n\nDer Client sendet also einen **HTTPS-Request**. Das ist einfach ein HTTP-Request über eine verschlüsselte TLS-Verbindung.\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### Den Request entschlüsseln { #decrypt-the-request }\n\nDer TLS-Terminierungsproxy würde die vereinbarte Verschlüsselung zum **Entschlüsseln des Requests** verwenden und den **einfachen (entschlüsselten) HTTP-Request** an den Prozess weiterleiten, der die Anwendung ausführt (z. B. einen Prozess, bei dem Uvicorn die FastAPI-Anwendung ausführt).\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### HTTP-Response { #http-response }\n\nDie Anwendung würde den Request verarbeiten und eine **einfache (unverschlüsselte) HTTP-Response** an den TLS-Terminierungsproxy senden.\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### HTTPS-Response { #https-response }\n\nDer TLS-Terminierungsproxy würde dann die Response mithilfe der zuvor vereinbarten Kryptografie (als das Zertifikat für `someapp.example.com` verhandelt wurde) **verschlüsseln** und sie an den Browser zurücksenden.\n\nAls Nächstes überprüft der Browser, ob die Response gültig und mit dem richtigen kryptografischen Schlüssel usw. verschlüsselt ist. Anschließend **entschlüsselt er die Response** und verarbeitet sie.\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\nDer Client (Browser) weiß, dass die Response vom richtigen Server kommt, da dieser die Kryptografie verwendet, die zuvor mit dem **HTTPS-Zertifikat** vereinbart wurde.\n\n### Mehrere Anwendungen { #multiple-applications }\n\nAuf demselben Server (oder denselben Servern) könnten sich **mehrere Anwendungen** befinden, beispielsweise andere API-Programme oder eine Datenbank.\n\nNur ein Prozess kann diese spezifische IP und den Port verarbeiten (in unserem Beispiel der TLS-Terminierungsproxy), aber die anderen Anwendungen/Prozesse können auch auf dem/den Server(n) ausgeführt werden, solange sie nicht versuchen, dieselbe **Kombination aus öffentlicher IP und Port** zu verwenden.\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\nAuf diese Weise könnte der TLS-Terminierungsproxy HTTPS und Zertifikate für **mehrere Domains**, für mehrere Anwendungen, verarbeiten und die Requests dann jeweils an die richtige Anwendung weiterleiten.\n\n### Verlängerung des Zertifikats { #certificate-renewal }\n\nIrgendwann in der Zukunft würde jedes Zertifikat **ablaufen** (etwa 3 Monate nach dem Erwerb).\n\nUnd dann gäbe es ein anderes Programm (in manchen Fällen ist es ein anderes Programm, in manchen Fällen ist es derselbe TLS-Terminierungsproxy), das mit Let's Encrypt kommuniziert und das/die Zertifikat(e) erneuert.\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\nDie **TLS-Zertifikate** sind **einem Domainnamen zugeordnet**, nicht einer IP-Adresse.\n\nUm die Zertifikate zu erneuern, muss das erneuernde Programm der Behörde (Let's Encrypt) **nachweisen**, dass es diese Domain tatsächlich **besitzt und kontrolliert**.\n\nUm dies zu erreichen und den unterschiedlichen Anwendungsanforderungen gerecht zu werden, gibt es mehrere Möglichkeiten. Einige beliebte Methoden sind:\n\n* **Einige DNS-Einträge ändern**.\n    * Hierfür muss das erneuernde Programm die APIs des DNS-Anbieters unterstützen. Je nachdem, welchen DNS-Anbieter Sie verwenden, kann dies eine Option sein oder auch nicht.\n* **Als Server ausführen** (zumindest während des Zertifikatserwerbsvorgangs), auf der öffentlichen IP-Adresse, die der Domain zugeordnet ist.\n    * Wie oben erwähnt, kann nur ein Prozess eine bestimmte IP und einen bestimmten Port überwachen.\n    * Das ist einer der Gründe, warum es sehr nützlich ist, wenn derselbe TLS-Terminierungsproxy auch den Zertifikats-Erneuerungsprozess übernimmt.\n    * Andernfalls müssen Sie möglicherweise den TLS-Terminierungsproxy vorübergehend stoppen, das Programm starten, welches die neuen Zertifikate beschafft, diese dann mit dem TLS-Terminierungsproxy konfigurieren und dann den TLS-Terminierungsproxy neu starten. Das ist nicht ideal, da Ihre Anwendung(en) während der Zeit, in der der TLS-Terminierungsproxy ausgeschaltet ist, nicht erreichbar ist/sind.\n\nDieser ganze Erneuerungsprozess, während die Anwendung weiterhin bereitgestellt wird, ist einer der Hauptgründe, warum Sie ein **separates System zur Verarbeitung von HTTPS** mit einem TLS-Terminierungsproxy haben möchten, anstatt einfach die TLS-Zertifikate direkt mit dem Anwendungsserver zu verwenden (z. B. Uvicorn).\n\n## Proxy-<abbr title=\"weitergeleitete Header\">Forwarded-Header</abbr> { #proxy-forwarded-headers }\n\nWenn Sie einen Proxy zur Verarbeitung von HTTPS verwenden, weiß Ihr **Anwendungsserver** (z. B. Uvicorn über das FastAPI CLI) nichts über den HTTPS-Prozess, er kommuniziert per einfachem HTTP mit dem **TLS-Terminierungsproxy**.\n\nDieser **Proxy** würde normalerweise unmittelbar vor dem Übermitteln der Anfrage an den **Anwendungsserver** einige HTTP-Header dynamisch setzen, um dem Anwendungsserver mitzuteilen, dass der Request vom Proxy **weitergeleitet** wird.\n\n/// note | Technische Details\n\nDie Proxy-Header sind:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\nTrotzdem, da der **Anwendungsserver** nicht weiß, dass er sich hinter einem vertrauenswürdigen **Proxy** befindet, würde er diesen Headern standardmäßig nicht vertrauen.\n\nSie können den **Anwendungsserver** jedoch so konfigurieren, dass er den vom **Proxy** gesendeten *Forwarded*-Headern vertraut. Wenn Sie das FastAPI CLI verwenden, können Sie die *CLI-Option* `--forwarded-allow-ips` nutzen, um anzugeben, von welchen IPs er diesen *Forwarded*-Headern vertrauen soll.\n\nWenn der **Anwendungsserver** beispielsweise nur Kommunikation vom vertrauenswürdigen **Proxy** empfängt, können Sie `--forwarded-allow-ips=\"*\"` setzen, um allen eingehenden IPs zu vertrauen, da er nur Requests von der vom **Proxy** verwendeten IP erhalten wird.\n\nAuf diese Weise kann die Anwendung ihre eigene öffentliche URL, ob sie HTTPS verwendet, die Domain, usw. erkennen.\n\nDas ist z. B. nützlich, um <abbr title=\"Redirect – Umleitung\">Redirects</abbr> korrekt zu handhaben.\n\n/// tip | Tipp\n\nMehr dazu finden Sie in der Dokumentation zu [Hinter einem Proxy – Proxy-Forwarded-Header aktivieren](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)\n\n///\n\n## Zusammenfassung { #recap }\n\n**HTTPS** zu haben ist sehr wichtig und in den meisten Fällen eine **kritische Anforderung**. Die meiste Arbeit, die Sie als Entwickler in Bezug auf HTTPS aufwenden müssen, besteht lediglich darin, **diese Konzepte zu verstehen** und wie sie funktionieren.\n\nSobald Sie jedoch die grundlegenden Informationen zu **HTTPS für Entwickler** kennen, können Sie verschiedene Tools problemlos kombinieren und konfigurieren, um alles auf einfache Weise zu verwalten.\n\nIn einigen der nächsten Kapitel zeige ich Ihnen einige konkrete Beispiele für die Einrichtung von **HTTPS** für **FastAPI**-Anwendungen. 🔒\n"
  },
  {
    "path": "docs/de/docs/deployment/index.md",
    "content": "# Deployment { #deployment }\n\nDas Deployment einer **FastAPI**-Anwendung ist relativ einfach.\n\n## Was bedeutet Deployment { #what-does-deployment-mean }\n\n<abbr title=\"Bereitstellen der Anwendung\">**Deployment**</abbr> bedeutet, die notwendigen Schritte durchzuführen, um die Anwendung **für die Benutzer verfügbar** zu machen.\n\nBei einer **Web-API** bedeutet das normalerweise, diese auf einem **entfernten Rechner** zu platzieren, mit einem **Serverprogramm**, welches gute Leistung, Stabilität, usw. bietet, damit Ihre **Benutzer** auf die Anwendung effizient und ohne Unterbrechungen oder Probleme **zugreifen** können.\n\nDas steht im Gegensatz zu den **Entwicklungsphasen**, in denen Sie ständig den Code ändern, kaputt machen, reparieren, den Entwicklungsserver stoppen und neu starten, usw.\n\n## Deployment-Strategien { #deployment-strategies }\n\nEs gibt mehrere Möglichkeiten, dies zu tun, abhängig von Ihrem spezifischen Anwendungsfall und den von Ihnen verwendeten Tools.\n\nSie könnten mithilfe einer Kombination von Tools selbst **einen Server deployen**, Sie könnten einen **Cloud-Dienst** nutzen, der einen Teil der Arbeit für Sie erledigt, oder andere mögliche Optionen.\n\nZum Beispiel haben wir, das Team hinter FastAPI, [**FastAPI Cloud**](https://fastapicloud.com) entwickelt, um das Deployment von FastAPI-Apps in der Cloud so reibungslos wie möglich zu gestalten, mit derselben Developer-Experience wie beim Arbeiten mit FastAPI.\n\nIch zeige Ihnen einige der wichtigsten Konzepte, die Sie beim Deployment einer **FastAPI**-Anwendung wahrscheinlich berücksichtigen sollten (obwohl das meiste davon auch für jede andere Art von Webanwendung gilt).\n\nIn den nächsten Abschnitten erfahren Sie mehr über die zu beachtenden Details und über die Techniken, das zu tun. ✨\n"
  },
  {
    "path": "docs/de/docs/deployment/manually.md",
    "content": "# Einen Server manuell ausführen { #run-a-server-manually }\n\n## Den `fastapi run`-Befehl verwenden { #use-the-fastapi-run-command }\n\nKurz gesagt, nutzen Sie `fastapi run`, um Ihre FastAPI-Anwendung bereitzustellen:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\nDas würde in den meisten Fällen funktionieren. 😎\n\nSie könnten diesen Befehl beispielsweise verwenden, um Ihre **FastAPI**-App in einem Container, auf einem Server usw. zu starten.\n\n## ASGI-Server { #asgi-servers }\n\nLassen Sie uns ein wenig tiefer in die Details eintauchen.\n\nFastAPI verwendet einen Standard zum Erstellen von Python-Webframeworks und -Servern, der als <abbr title=\"Asynchrones Server-Gateway-Interface\">ASGI</abbr> bekannt ist. FastAPI ist ein ASGI-Webframework.\n\nDas Wichtigste, was Sie benötigen, um eine **FastAPI**-Anwendung (oder eine andere ASGI-Anwendung) auf einer entfernten Servermaschine auszuführen, ist ein ASGI-Serverprogramm wie **Uvicorn**, der standardmäßig im `fastapi`-Kommando enthalten ist.\n\nEs gibt mehrere Alternativen, einschließlich:\n\n* [Uvicorn](https://www.uvicorn.dev/): ein hochperformanter ASGI-Server.\n* [Hypercorn](https://hypercorn.readthedocs.io/): ein ASGI-Server, der unter anderem kompatibel mit HTTP/2 und Trio ist.\n* [Daphne](https://github.com/django/daphne): der für Django Channels entwickelte ASGI-Server.\n* [Granian](https://github.com/emmett-framework/granian): Ein Rust HTTP-Server für Python-Anwendungen.\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit ist eine leichte und vielseitige Laufzeitumgebung für Webanwendungen.\n\n## Servermaschine und Serverprogramm { #server-machine-and-server-program }\n\nEs gibt ein kleines Detail bei den Namen, das Sie beachten sollten. 💡\n\nDas Wort „**Server**“ wird häufig verwendet, um sowohl den entfernten/Cloud-Computer (die physische oder virtuelle Maschine) als auch das Programm zu bezeichnen, das auf dieser Maschine läuft (z. B. Uvicorn).\n\nDenken Sie einfach daran, dass sich „Server“ im Allgemeinen auf eines dieser beiden Dinge beziehen kann.\n\nWenn man sich auf die entfernte Maschine bezieht, wird sie üblicherweise als **Server**, aber auch als **Maschine**, **VM** (virtuelle Maschine) oder **Knoten** bezeichnet. Diese Begriffe beziehen sich auf irgendeine Art von entfernten Rechner, normalerweise unter Linux, auf dem Sie Programme ausführen.\n\n## Das Serverprogramm installieren { #install-the-server-program }\n\nWenn Sie FastAPI installieren, wird es mit einem Produktionsserver, Uvicorn, geliefert, und Sie können ihn mit dem `fastapi run` Befehl starten.\n\nAber Sie können auch ein ASGI-Serverprogramm manuell installieren.\n\nStellen Sie sicher, dass Sie eine [virtuelle Umgebung](../virtual-environments.md) erstellen, sie aktivieren und dann die Serveranwendung installieren.\n\nZum Beispiel, um Uvicorn zu installieren:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\nEin ähnlicher Prozess würde für jedes andere ASGI-Serverprogramm gelten.\n\n/// tip | Tipp\n\nDurch das Hinzufügen von `standard` installiert und verwendet Uvicorn einige empfohlene zusätzliche Abhängigkeiten.\n\nDazu gehört `uvloop`, der hochperformante Drop-in-Ersatz für `asyncio`, der den großen Nebenläufigkeits-Leistungsschub bietet.\n\nWenn Sie FastAPI mit etwas wie `pip install \"fastapi[standard]\"` installieren, erhalten Sie auch `uvicorn[standard]`.\n\n///\n\n## Das Serverprogramm ausführen { #run-the-server-program }\n\nWenn Sie einen ASGI-Server manuell installiert haben, müssen Sie normalerweise einen Importstring in einem speziellen Format übergeben, damit er Ihre FastAPI-Anwendung importiert:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note | Hinweis\n\nDer Befehl `uvicorn main:app` bezieht sich auf:\n\n* `main`: die Datei `main.py` (das Python-„Modul“).\n* `app`: das Objekt, das innerhalb von `main.py` mit der Zeile `app = FastAPI()` erstellt wurde.\n\nEs ist äquivalent zu:\n\n```Python\nfrom main import app\n```\n\n///\n\nJedes alternative ASGI-Serverprogramm hätte einen ähnlichen Befehl, Sie können in deren jeweiligen Dokumentationen mehr lesen.\n\n/// warning | Achtung\n\nUvicorn und andere Server unterstützen eine `--reload`-Option, die während der Entwicklung nützlich ist.\n\nDie `--reload`-Option verbraucht viel mehr Ressourcen, ist instabiler, usw.\n\nSie hilft während der **Entwicklung**, Sie sollten sie jedoch **nicht** in der **Produktion** verwenden.\n\n///\n\n## Deployment-Konzepte { #deployment-concepts }\n\nDiese Beispiele führen das Serverprogramm (z. B. Uvicorn) aus, starten **einen einzelnen Prozess** und überwachen alle IPs (`0.0.0.0`) an einem vordefinierten Port (z. B. `80`).\n\nDas ist die Grundidee. Aber Sie möchten sich wahrscheinlich um einige zusätzliche Dinge kümmern, wie zum Beispiel:\n\n* Sicherheit – HTTPS\n* Beim Hochfahren ausführen\n* Neustarts\n* Replikation (die Anzahl der laufenden Prozesse)\n* Speicher\n* Schritte vor dem Start\n\nIn den nächsten Kapiteln erzähle ich Ihnen mehr über jedes dieser Konzepte, wie Sie über diese nachdenken, und gebe Ihnen einige konkrete Beispiele mit Strategien für den Umgang damit. 🚀\n"
  },
  {
    "path": "docs/de/docs/deployment/server-workers.md",
    "content": "# Serverworker – Uvicorn mit Workern { #server-workers-uvicorn-with-workers }\n\nSchauen wir uns die Deployment-Konzepte von früher noch einmal an:\n\n* Sicherheit – HTTPS\n* Beim Hochfahren ausführen\n* Neustarts\n* **Replikation (die Anzahl der laufenden Prozesse)**\n* Arbeitsspeicher\n* Schritte vor dem Start\n\nBis zu diesem Punkt, in allen Tutorials in der Dokumentation, haben Sie wahrscheinlich ein **Serverprogramm** ausgeführt, zum Beispiel mit dem `fastapi`-Befehl, der Uvicorn startet, und einen **einzelnen Prozess** ausführt.\n\nWenn Sie Anwendungen deployen, möchten Sie wahrscheinlich eine gewisse **Replikation von Prozessen**, um **mehrere Kerne** zu nutzen und mehr <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> bearbeiten zu können.\n\nWie Sie im vorherigen Kapitel über [Deployment-Konzepte](concepts.md) gesehen haben, gibt es mehrere Strategien, die Sie anwenden können.\n\nHier zeige ich Ihnen, wie Sie **Uvicorn** mit **Workerprozessen** verwenden, indem Sie den `fastapi`-Befehl oder den `uvicorn`-Befehl direkt verwenden.\n\n/// info | Info\n\nWenn Sie Container verwenden, beispielsweise mit Docker oder Kubernetes, erzähle ich Ihnen mehr darüber im nächsten Kapitel: [FastAPI in Containern – Docker](docker.md).\n\nInsbesondere wenn die Anwendung auf **Kubernetes** läuft, werden Sie wahrscheinlich **keine** Worker verwenden wollen, und stattdessen **einen einzelnen Uvicorn-Prozess pro Container** ausführen wollen, aber ich werde Ihnen später in diesem Kapitel mehr darüber erzählen.\n\n///\n\n## Mehrere Worker { #multiple-workers }\n\nSie können mehrere Worker mit der `--workers`-Befehlszeilenoption starten:\n\n//// tab | `fastapi`\n\nWenn Sie den `fastapi`-Befehl verwenden:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\nWenn Sie den `uvicorn`-Befehl direkt verwenden möchten:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\nDie einzige neue Option hier ist `--workers`, die Uvicorn anweist, 4 Workerprozesse zu starten.\n\nSie können auch sehen, dass die **PID** jedes Prozesses angezeigt wird, `27365` für den übergeordneten Prozess (dies ist der **Prozessmanager**) und eine für jeden Workerprozess: `27368`, `27369`, `27370` und `27367`.\n\n## Deployment-Konzepte { #deployment-concepts }\n\nHier haben Sie gesehen, wie Sie mehrere **Worker** verwenden, um die Ausführung der Anwendung zu **parallelisieren**, **mehrere Kerne** der CPU zu nutzen und in der Lage zu sein, **mehr Requests** zu bearbeiten.\n\nIn der Liste der Deployment-Konzepte von oben würde die Verwendung von Workern hauptsächlich bei der **Replikation** und ein wenig bei **Neustarts** helfen, aber Sie müssen sich trotzdem um die anderen kümmern:\n\n* **Sicherheit – HTTPS**\n* **Beim Hochfahren ausführen**\n* ***Neustarts***\n* Replikation (die Anzahl der laufenden Prozesse)\n* **Arbeitsspeicher**\n* **Schritte vor dem Start**\n\n## Container und Docker { #containers-and-docker }\n\nIm nächsten Kapitel über [FastAPI in Containern – Docker](docker.md) werde ich einige Strategien erläutern, die Sie für den Umgang mit den anderen **Deployment-Konzepten** verwenden können.\n\nIch zeige Ihnen, wie Sie **Ihr eigenes Image von Grund auf erstellen**, um einen einzelnen Uvicorn-Prozess auszuführen. Es ist ein einfacher Vorgang und wahrscheinlich das, was Sie tun möchten, wenn Sie ein verteiltes Containerverwaltungssystem wie **Kubernetes** verwenden.\n\n## Zusammenfassung { #recap }\n\nSie können mehrere Workerprozesse mit der `--workers`-CLI-Option über die `fastapi`- oder `uvicorn`-Befehle nutzen, um **Multikern-CPUs** auszunutzen und **mehrere Prozesse parallel** auszuführen.\n\nSie könnten diese Tools und Ideen nutzen, wenn Sie **Ihr eigenes Deployment-System** einrichten und sich dabei selbst um die anderen Deployment-Konzepte kümmern.\n\nSchauen Sie sich das nächste Kapitel an, um mehr über **FastAPI** mit Containern (z. B. Docker und Kubernetes) zu erfahren. Sie werden sehen, dass diese Tools auch einfache Möglichkeiten bieten, die anderen **Deployment-Konzepte** zu lösen. ✨\n"
  },
  {
    "path": "docs/de/docs/deployment/versions.md",
    "content": "# Über FastAPI-Versionen { #about-fastapi-versions }\n\n**FastAPI** wird bereits in vielen Anwendungen und Systemen produktiv eingesetzt. Und die Testabdeckung wird bei 100 % gehalten. Aber seine Entwicklung geht immer noch schnell voran.\n\nEs werden regelmäßig neue Funktionen hinzugefügt, Fehler werden regelmäßig behoben und der Code wird weiterhin kontinuierlich verbessert.\n\nAus diesem Grund sind die aktuellen Versionen immer noch `0.x.x`, was darauf hindeutet, dass jede Version möglicherweise nicht abwärtskompatible Änderungen haben könnte. Dies folgt den Konventionen der [Semantische Versionierung](https://semver.org/).\n\nSie können jetzt Produktionsanwendungen mit **FastAPI** erstellen (und das tun Sie wahrscheinlich schon seit einiger Zeit), Sie müssen nur sicherstellen, dass Sie eine Version verwenden, die korrekt mit dem Rest Ihres Codes funktioniert.\n\n## Ihre `fastapi`-Version pinnen { #pin-your-fastapi-version }\n\nAls Erstes sollten Sie die Version von **FastAPI**, die Sie verwenden, an die höchste Version „pinnen“, von der Sie wissen, dass sie für Ihre Anwendung korrekt funktioniert.\n\nAngenommen, Sie verwenden in Ihrer App die Version `0.112.0`.\n\nWenn Sie eine `requirements.txt`-Datei verwenden, können Sie die Version wie folgt angeben:\n\n```txt\nfastapi[standard]==0.112.0\n```\n\nDas würde bedeuten, dass Sie genau die Version `0.112.0` verwenden.\n\nOder Sie können sie auch anpinnen mit:\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\nDas würde bedeuten, dass Sie eine Version `0.112.0` oder höher verwenden würden, aber kleiner als `0.113.0`, beispielsweise würde eine Version `0.112.2` immer noch akzeptiert.\n\nWenn Sie zum Verwalten Ihrer Installationen andere Tools wie `uv`, Poetry, Pipenv oder andere verwenden, sie verfügen alle über eine Möglichkeit, bestimmte Versionen für Ihre Packages zu definieren.\n\n## Verfügbare Versionen { #available-versions }\n\nDie verfügbaren Versionen können Sie in den [Versionshinweisen](../release-notes.md) einsehen (z. B. um zu überprüfen, welches die neueste Version ist).\n\n## Über Versionen { #about-versions }\n\nGemäß den Konventionen zur semantischen Versionierung könnte jede Version unter `1.0.0` potenziell nicht abwärtskompatible Änderungen hinzufügen.\n\nFastAPI folgt auch der Konvention, dass jede „PATCH“-Versionsänderung für Bugfixes und abwärtskompatible Änderungen gedacht ist.\n\n/// tip | Tipp\n\nDer „PATCH“ ist die letzte Zahl, zum Beispiel ist in `0.2.3` die PATCH-Version `3`.\n\n///\n\nSie sollten also in der Lage sein, eine Version wie folgt anzupinnen:\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\nNicht abwärtskompatible Änderungen und neue Funktionen werden in „MINOR“-Versionen hinzugefügt.\n\n/// tip | Tipp\n\n„MINOR“ ist die Zahl in der Mitte, zum Beispiel ist in `0.2.3` die MINOR-Version `2`.\n\n///\n\n## Upgrade der FastAPI-Versionen { #upgrading-the-fastapi-versions }\n\nSie sollten Tests für Ihre App hinzufügen.\n\nMit **FastAPI** ist das sehr einfach (dank Starlette), schauen Sie sich die Dokumentation an: [Testen](../tutorial/testing.md)\n\nNachdem Sie Tests erstellt haben, können Sie die **FastAPI**-Version auf eine neuere Version aktualisieren und sicherstellen, dass Ihr gesamter Code ordnungsgemäß funktioniert, indem Sie Ihre Tests ausführen.\n\nWenn alles funktioniert oder nachdem Sie die erforderlichen Änderungen vorgenommen haben und alle Ihre Tests bestehen, können Sie Ihr `fastapi` an die neue aktuelle Version pinnen.\n\n## Über Starlette { #about-starlette }\n\nSie sollten die Version von `starlette` nicht pinnen.\n\nVerschiedene Versionen von **FastAPI** verwenden eine bestimmte neuere Version von Starlette.\n\nSie können **FastAPI** also einfach die korrekte Starlette-Version verwenden lassen.\n\n## Über Pydantic { #about-pydantic }\n\nPydantic integriert die Tests für **FastAPI** in seine eigenen Tests, sodass neue Versionen von Pydantic (über `1.0.0`) immer mit FastAPI kompatibel sind.\n\nSie können Pydantic an jede für Sie geeignete Version über `1.0.0` anpinnen.\n\nZum Beispiel:\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/de/docs/editor-support.md",
    "content": "# Editor-Unterstützung { #editor-support }\n\nDie offizielle [FastAPI-Erweiterung](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) verbessert Ihren FastAPI-Entwicklungsworkflow mit Pfadoperation-Erkennung und -Navigation sowie FastAPI-Cloud-Deployment und Live-Logstreaming.\n\nWeitere Details zur Erweiterung finden Sie im README im [GitHub-Repository](https://github.com/fastapi/fastapi-vscode).\n\n## Einrichtung und Installation { #setup-and-installation }\n\nDie **FastAPI-Erweiterung** ist sowohl für [VS Code](https://code.visualstudio.com/) als auch für [Cursor](https://www.cursor.com/) verfügbar. Sie kann direkt über das Erweiterungen-Panel in jedem Editor installiert werden, indem Sie nach „FastAPI“ suchen und die von **FastAPI Labs** veröffentlichte Erweiterung auswählen. Die Erweiterung funktioniert auch in browserbasierten Editoren wie [vscode.dev](https://vscode.dev) und [github.dev](https://github.dev).\n\n### Anwendungserkennung { #application-discovery }\n\nStandardmäßig erkennt die Erweiterung FastAPI-Anwendungen in Ihrem Workspace automatisch, indem sie nach Dateien sucht, die `FastAPI()` instanziieren. Falls die automatische Erkennung mit Ihrer Projektstruktur nicht funktioniert, können Sie einen Entry-Point über `[tool.fastapi]` in `pyproject.toml` oder die VS-Code-Einstellung `fastapi.entryPoint` in Modulnotation angeben (z. B. `myapp.main:app`).\n\n## Funktionen { #features }\n\n- Pfadoperation-Explorer – Eine Baumansicht in der Seitenleiste aller <dfn title=\"Routen, Endpunkte\">*Pfadoperationen*</dfn> in Ihrer Anwendung. Klicken Sie, um zu einer beliebigen Route- oder Router-Definition zu springen.\n- Routensuche – Suchen Sie nach Pfad, Methode oder Namen mit <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (unter macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>).\n- CodeLens-Navigation – Anklickbare Links oberhalb von Testclient-Aufrufen (z. B. `client.get('/items')`), die zur passenden Pfadoperation springen und so eine schnelle Navigation zwischen Tests und Implementierung ermöglichen.\n- Zu FastAPI Cloud deployen – Deployment Ihrer App mit einem Klick auf [FastAPI Cloud](https://fastapicloud.com/).\n- Anwendungslogs streamen – Echtzeit-Logstreaming Ihrer auf FastAPI Cloud deployten Anwendung mit Loglevel-Filterung und Textsuche.\n\nWenn Sie sich mit den Funktionen der Erweiterung vertraut machen möchten, können Sie den Erweiterungs‑Walkthrough aufrufen, indem Sie die Befehlspalette öffnen (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> oder unter macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>) und „Welcome: Open walkthrough …“ auswählen und anschließend den Walkthrough „Get started with FastAPI“ wählen.\n"
  },
  {
    "path": "docs/de/docs/environment-variables.md",
    "content": "# Umgebungsvariablen { #environment-variables }\n\n/// tip | Tipp\n\nWenn Sie bereits wissen, was „Umgebungsvariablen“ sind und wie man sie verwendet, können Sie dies überspringen.\n\n///\n\nEine Umgebungsvariable (auch bekannt als „**env var**“) ist eine Variable, die **außerhalb** des Python-Codes im **Betriebssystem** lebt und von Ihrem Python-Code (oder auch von anderen Programmen) gelesen werden kann.\n\nUmgebungsvariablen können nützlich sein, um **Einstellungen** der Anwendung zu handhaben, als Teil der **Installation** von Python usw.\n\n## Umgebungsvariablen erstellen und verwenden { #create-and-use-env-vars }\n\nSie können Umgebungsvariablen in der **Shell (Terminal)** erstellen und verwenden, ohne Python zu benötigen:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Sie können eine Umgebungsvariable MY_NAME erstellen mit\n$ export MY_NAME=\"Wade Wilson\"\n\n// Dann können Sie sie mit anderen Programmen verwenden, etwa\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Erstellen Sie eine Umgebungsvariable MY_NAME\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Verwenden Sie sie mit anderen Programmen, etwa\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## Umgebungsvariablen in Python lesen { #read-env-vars-in-python }\n\nSie können auch Umgebungsvariablen **außerhalb** von Python erstellen, im Terminal (oder mit jeder anderen Methode) und sie dann **in Python** lesen.\n\nZum Beispiel könnten Sie eine Datei `main.py` haben mit:\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip | Tipp\n\nDas zweite Argument von [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) ist der Defaultwert, der zurückgegeben wird.\n\nWenn er nicht angegeben wird, ist er standardmäßig `None`. Hier geben wir „World“ als den zu verwendenden Defaultwert an.\n\n///\n\nDann könnten Sie das Python-Programm aufrufen:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Hier setzen wir die Umgebungsvariable noch nicht\n$ python main.py\n\n// Da wir die Umgebungsvariable nicht gesetzt haben, erhalten wir den Defaultwert\n\nHello World from Python\n\n// Aber wenn wir zuerst eine Umgebungsvariable erstellen\n$ export MY_NAME=\"Wade Wilson\"\n\n// Und dann das Programm erneut aufrufen\n$ python main.py\n\n// Jetzt kann es die Umgebungsvariable lesen\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Hier setzen wir die Umgebungsvariable noch nicht\n$ python main.py\n\n// Da wir die Umgebungsvariable nicht gesetzt haben, erhalten wir den Defaultwert\n\nHello World from Python\n\n// Aber wenn wir zuerst eine Umgebungsvariable erstellen\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Und dann das Programm erneut aufrufen\n$ python main.py\n\n// Jetzt kann es die Umgebungsvariable lesen\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\nDa Umgebungsvariablen außerhalb des Codes gesetzt werden können, aber vom Code gelesen werden können und nicht mit den restlichen Dateien gespeichert (in `git` committet) werden müssen, werden sie häufig für Konfigurationen oder **Einstellungen** verwendet.\n\nSie können auch eine Umgebungsvariable nur für einen **spezifischen Programmaufruf** erstellen, die nur für dieses Programm und nur für dessen Dauer verfügbar ist.\n\nUm dies zu tun, erstellen Sie sie direkt vor dem Programmaufruf, in derselben Zeile:\n\n<div class=\"termy\">\n\n```console\n// Erstellen Sie eine Umgebungsvariable MY_NAME in der Zeile für diesen Programmaufruf\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// Jetzt kann es die Umgebungsvariable lesen\n\nHello Wade Wilson from Python\n\n// Die Umgebungsvariable existiert danach nicht mehr\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip | Tipp\n\nSie können mehr darüber lesen auf [The Twelve-Factor App: Config](https://12factor.net/config).\n\n///\n\n## Typen und Validierung { #types-and-validation }\n\nDiese Umgebungsvariablen können nur **Textstrings** handhaben, da sie extern zu Python sind und kompatibel mit anderen Programmen und dem Rest des Systems (und sogar mit verschiedenen Betriebssystemen, wie Linux, Windows, macOS) sein müssen.\n\nDas bedeutet, dass **jeder Wert**, der in Python von einer Umgebungsvariablen gelesen wird, **ein `str` sein wird**, und jede Konvertierung in einen anderen Typ oder jede Validierung muss im Code vorgenommen werden.\n\nSie werden mehr darüber lernen, wie man Umgebungsvariablen zur Handhabung von **Anwendungseinstellungen** verwendet, im [Handbuch für fortgeschrittene Benutzer – Einstellungen und Umgebungsvariablen](./advanced/settings.md).\n\n## `PATH`-Umgebungsvariable { #path-environment-variable }\n\nEs gibt eine **spezielle** Umgebungsvariable namens **`PATH`**, die von den Betriebssystemen (Linux, macOS, Windows) verwendet wird, um Programme zu finden, die ausgeführt werden sollen.\n\nDer Wert der Variable `PATH` ist ein langer String, der aus Verzeichnissen besteht, die auf Linux und macOS durch einen Doppelpunkt `:` und auf Windows durch ein Semikolon `;` getrennt sind.\n\nZum Beispiel könnte die `PATH`-Umgebungsvariable so aussehen:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nDas bedeutet, dass das System nach Programmen in den Verzeichnissen suchen sollte:\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\nDas bedeutet, dass das System nach Programmen in den Verzeichnissen suchen sollte:\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\nWenn Sie einen **Befehl** im Terminal eingeben, **sucht** das Betriebssystem nach dem Programm in **jedem dieser Verzeichnisse**, die in der `PATH`-Umgebungsvariablen aufgeführt sind.\n\nZum Beispiel, wenn Sie `python` im Terminal eingeben, sucht das Betriebssystem nach einem Programm namens `python` im **ersten Verzeichnis** in dieser Liste.\n\nWenn es es findet, wird es **benutzt**. Andernfalls sucht es weiter in den **anderen Verzeichnissen**.\n\n### Python installieren und den `PATH` aktualisieren { #installing-python-and-updating-the-path }\n\nWenn Sie Python installieren, könnten Sie gefragt werden, ob Sie die `PATH`-Umgebungsvariable aktualisieren möchten.\n\n//// tab | Linux, macOS\n\nAngenommen, Sie installieren Python und es landet in einem Verzeichnis `/opt/custompython/bin`.\n\nWenn Sie erlauben, die `PATH`-Umgebungsvariable zu aktualisieren, fügt der Installer `/opt/custompython/bin` zur `PATH`-Umgebungsvariable hinzu.\n\nDas könnte so aussehen:\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\nAuf diese Weise, wenn Sie `python` im Terminal eingeben, findet das System das Python-Programm in `/opt/custompython/bin` (das letzte Verzeichnis) und verwendet dieses.\n\n////\n\n//// tab | Windows\n\nAngenommen, Sie installieren Python und es landet in einem Verzeichnis `C:\\opt\\custompython\\bin`.\n\nWenn Sie erlauben, die `PATH`-Umgebungsvariable zu aktualisieren, fügt der Installer `C:\\opt\\custompython\\bin` zur `PATH`-Umgebungsvariable hinzu.\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\nAuf diese Weise, wenn Sie `python` im Terminal eingeben, findet das System das Python-Programm in `C:\\opt\\custompython\\bin` (das letzte Verzeichnis) und verwendet dieses.\n\n////\n\nAlso, wenn Sie tippen:\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\nDas System wird das `python` Programm in `/opt/custompython/bin` **finden** und es ausführen.\n\nEs wäre ungefähr gleichbedeutend mit der Eingabe von:\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\nDas System wird das `python` Programm in `C:\\opt\\custompython\\bin\\python` **finden** und es ausführen.\n\nEs wäre ungefähr gleichbedeutend mit der Eingabe von:\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\nDiese Informationen werden nützlich sein, wenn Sie über [Virtuelle Umgebungen](virtual-environments.md) lernen.\n\n## Fazit { #conclusion }\n\nMit diesem Wissen sollten Sie ein grundlegendes Verständnis davon haben, was **Umgebungsvariablen** sind und wie man sie in Python verwendet.\n\nSie können auch mehr darüber in der [Wikipedia zu Umgebungsvariablen](https://en.wikipedia.org/wiki/Environment_variable) lesen.\n\nIn vielen Fällen ist es nicht sehr offensichtlich, wie Umgebungsvariablen nützlich und sofort anwendbar sein könnten. Aber sie tauchen immer wieder in vielen verschiedenen Szenarien auf, wenn Sie entwickeln, deshalb ist es gut, darüber Bescheid zu wissen.\n\nZum Beispiel werden Sie diese Informationen im nächsten Abschnitt über [Virtuelle Umgebungen](virtual-environments.md) benötigen.\n"
  },
  {
    "path": "docs/de/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - Kommandozeileninterface\">CLI</abbr>** ist ein Kommandozeilenprogramm, mit dem Sie Ihre FastAPI-App bereitstellen, Ihr FastAPI-Projekt verwalten und mehr.\n\nWenn Sie FastAPI installieren (z. B. mit `pip install \"fastapi[standard]\"`), erhalten Sie ein Kommandozeilenprogramm, das Sie im Terminal ausführen können.\n\nUm Ihre FastAPI-App für die Entwicklung auszuführen, können Sie den Befehl `fastapi dev` verwenden:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip | Tipp\n\nFür die Produktion würden Sie statt `fastapi dev` `fastapi run` verwenden. 🚀\n\n///\n\nIntern verwendet das **FastAPI CLI** [Uvicorn](https://www.uvicorn.dev), einen leistungsstarken, produktionsreifen, ASGI-Server. 😎\n\nDas `fastapi`-CLI versucht automatisch, die auszuführende FastAPI-App zu erkennen, und geht davon aus, dass es sich um ein Objekt namens `app` in einer Datei `main.py` handelt (oder ein paar weitere Varianten).\n\nSie können aber auch explizit konfigurieren, welche App verwendet werden soll.\n\n## Den App-`entrypoint` in `pyproject.toml` konfigurieren { #configure-the-app-entrypoint-in-pyproject-toml }\n\nSie können in einer `pyproject.toml`-Datei konfigurieren, wo sich Ihre App befindet, etwa so:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nDieser `entrypoint` teilt dem Befehl `fastapi` mit, dass die App so importiert werden soll:\n\n```python\nfrom main import app\n```\n\nWenn Ihr Code so strukturiert wäre:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nDann würden Sie den `entrypoint` wie folgt setzen:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nwas gleichbedeutend wäre mit:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` mit Pfad { #fastapi-dev-with-path }\n\nSie können auch den Dateipfad an den Befehl `fastapi dev` übergeben, dann wird das zu verwendende FastAPI-App-Objekt erraten:\n\n```console\n$ fastapi dev main.py\n```\n\nAber Sie müssten sich merken, bei jedem Aufruf des `fastapi`-Befehls den korrekten Pfad zu übergeben.\n\nZusätzlich könnten andere Tools sie nicht finden, z. B. die [VS Code Extension](editor-support.md) oder [FastAPI Cloud](https://fastapicloud.com), daher wird empfohlen, den `entrypoint` in `pyproject.toml` zu verwenden.\n\n## `fastapi dev` { #fastapi-dev }\n\nDas Ausführen von `fastapi dev` startet den Entwicklermodus.\n\nStandardmäßig ist **Autoreload** aktiviert, das den Server automatisch neu lädt, wenn Sie Änderungen an Ihrem Code vornehmen. Dies ist ressourcenintensiv und könnte weniger stabil sein als wenn es deaktiviert ist. Sie sollten es nur für die Entwicklung verwenden. Es horcht auch auf der IP-Adresse `127.0.0.1`, die die IP für Ihre Maschine ist, um nur mit sich selbst zu kommunizieren (`localhost`).\n\n## `fastapi run` { #fastapi-run }\n\nDas Ausführen von `fastapi run` startet FastAPI im Produktionsmodus.\n\nStandardmäßig ist **Autoreload** deaktiviert. Es horcht auch auf der IP-Adresse `0.0.0.0`, was alle verfügbaren IP-Adressen bedeutet, so wird es öffentlich zugänglich für jeden, der mit der Maschine kommunizieren kann. So würden Sie es normalerweise in der Produktion ausführen, beispielsweise in einem Container.\n\nIn den meisten Fällen würden (und sollten) Sie einen „Terminierungsproxy“ haben, der HTTPS für Sie verwaltet. Dies hängt davon ab, wie Sie Ihre Anwendung deployen. Ihr Anbieter könnte dies für Sie erledigen, oder Sie müssen es selbst einrichten.\n\n/// tip | Tipp\n\nSie können mehr darüber in der [Deployment-Dokumentation](deployment/index.md) erfahren.\n\n///\n"
  },
  {
    "path": "docs/de/docs/features.md",
    "content": "# Merkmale { #features }\n\n## FastAPI Merkmale { #fastapi-features }\n\n**FastAPI** ermöglicht Ihnen Folgendes:\n\n### Basiert auf offenen Standards { #based-on-open-standards }\n\n* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) für die Erstellung von APIs, inklusive Deklarationen von <dfn title=\"auch bekannt als: Endpunkte, Routen\">Pfad</dfn>-<dfn title=\"auch bekannt als HTTP-Methoden, wie POST, GET, PUT, DELETE\">Operationen</dfn>, Parametern, <abbr title=\"Requestbody\">Requestbodys</abbr>, Sicherheit, usw.\n* Automatische Dokumentation der Datenmodelle mit [**JSON Schema**](https://json-schema.org/) (da OpenAPI selbst auf JSON Schema basiert).\n* Um diese Standards herum entworfen, nach sorgfältigem Studium. Statt einer nachträglichen Schicht darüber.\n* Dies ermöglicht auch automatische **Client-Code-Generierung** in vielen Sprachen.\n\n### Automatische Dokumentation { #automatic-docs }\n\nInteraktive API-Dokumentation und erkundbare Web-Benutzeroberflächen. Da das Framework auf OpenAPI basiert, gibt es mehrere Optionen, zwei sind standardmäßig vorhanden.\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui), bietet interaktive Erkundung, testen und rufen Sie Ihre API direkt im Webbrowser auf.\n\n![Swagger UI Interaktion](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Alternative API-Dokumentation mit [**ReDoc**](https://github.com/Rebilly/ReDoc).\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Nur modernes Python { #just-modern-python }\n\nAlles basiert auf Standard-**Python-Typ**deklarationen (dank Pydantic). Es muss keine neue Syntax gelernt werden, nur standardisiertes modernes Python.\n\nWenn Sie eine zweiminütige Auffrischung benötigen, wie man Python-Typen verwendet (auch wenn Sie FastAPI nicht benutzen), schauen Sie sich das kurze Tutorial an: [Einführung in Python-Typen](python-types.md).\n\nSie schreiben Standard-Python mit Typen:\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# Deklarieren Sie eine Variable als ein str\n# und bekommen Sie Editor-Unterstützung innerhalb der Funktion\ndef main(user_id: str):\n    return user_id\n\n\n# Ein Pydantic-Modell\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\nDas kann nun wie folgt verwendet werden:\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n/// info | Info\n\n`**second_user_data` bedeutet:\n\nNimm die Schlüssel-Wert-Paare des `second_user_data` <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">Dicts</abbr> und übergebe sie direkt als Schlüsselwort-Argumente. Äquivalent zu: `User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### Editor Unterstützung { #editor-support }\n\nDas ganze Framework wurde so entworfen, dass es einfach und intuitiv zu benutzen ist; alle Entscheidungen wurden auf mehreren Editoren getestet, sogar vor der Implementierung, um die bestmögliche Entwicklererfahrung zu gewährleisten.\n\nIn den Python-Entwickler-Umfragen wird klar, [dass die meist genutzte Funktion die „Autovervollständigung“ ist](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).\n\nDas gesamte **FastAPI**-Framework ist darauf ausgelegt, das zu erfüllen. Autovervollständigung funktioniert überall.\n\nSie werden selten noch mal in der Dokumentation nachschauen müssen.\n\nSo kann Ihr Editor Sie unterstützen:\n\n* in [Visual Studio Code](https://code.visualstudio.com/):\n\n![Editor Unterstützung](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* in [PyCharm](https://www.jetbrains.com/pycharm/):\n\n![Editor Unterstützung](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\nSie bekommen sogar Autovervollständigung an Stellen, an denen Sie dies vorher nicht für möglich gehalten hätten. Zum Beispiel der `price` Schlüssel in einem JSON Datensatz (dieser könnte auch verschachtelt sein), der aus einem Request kommt.\n\nNie wieder falsche Schlüsselnamen tippen, Hin und Herhüpfen zwischen der Dokumentation, Hoch- und Runterscrollen, um herauszufinden, ob es `username` oder `user_name` war.\n\n### Kompakt { #short }\n\nEs gibt für alles sensible **Defaultwerte**, mit optionaler Konfiguration überall. Alle Parameter können feinjustiert werden, damit sie tun, was Sie benötigen, und die API definieren, die Sie brauchen.\n\nAber standardmäßig **„funktioniert einfach alles“**.\n\n### Validierung { #validation }\n\n* Validierung für die meisten (oder alle?) Python-**Datentypen**, hierzu gehören:\n    * JSON Objekte (`dict`).\n    * JSON Listen (`list`), die den Typ ihrer Elemente definieren.\n    * Strings (`str`) mit definierter minimaler und maximaler Länge.\n    * Zahlen (`int`, `float`) mit Mindest- und Maximalwerten, usw.\n\n* Validierung für mehr exotische Typen, wie:\n    * URL.\n    * E-Mail.\n    * UUID.\n    * ... und andere.\n\nDie gesamte Validierung übernimmt das gut etablierte und robuste **Pydantic**.\n\n### Sicherheit und Authentifizierung { #security-and-authentication }\n\nSicherheit und Authentifizierung sind integriert. Ohne Kompromisse bei Datenbanken oder Datenmodellen.\n\nAlle in OpenAPI definierten Sicherheitsschemas, inklusive:\n\n* HTTP Basic.\n* **OAuth2** (auch mit **JWT Tokens**). Siehe dazu das Tutorial zu [OAuth2 mit JWT](tutorial/security/oauth2-jwt.md).\n* API Schlüssel in:\n    * Headern.\n    * Query-Parametern.\n    * Cookies, usw.\n\nZusätzlich alle Sicherheitsfunktionen von Starlette (inklusive **Session Cookies**).\n\nAlles als wiederverwendbare Tools und Komponenten gebaut, die einfach in Ihre Systeme, Datenspeicher, relationale und nicht-relationale Datenbanken, usw., integriert werden können.\n\n### Dependency Injection { #dependency-injection }\n\nFastAPI enthält ein extrem einfach zu verwendendes, aber extrem mächtiges <dfn title='auch bekannt als: \"Komponenten\", \"Ressourcen\", \"Dienste\", \"Dienstanbieter\"'><strong>Dependency Injection</strong></dfn> System.\n\n* Selbst Abhängigkeiten können Abhängigkeiten haben, woraus eine Hierarchie oder ein **„Graph“ von Abhängigkeiten** entsteht.\n* Alles **automatisch gehandhabt** durch das Framework.\n* Alle Abhängigkeiten können Daten von Requests anfordern und das Verhalten von **Pfadoperationen** und der automatisierten Dokumentation **modifizieren**.\n* **Automatische Validierung** selbst für solche Parameter von *Pfadoperationen*, welche in Abhängigkeiten definiert sind.\n* Unterstützung für komplexe Authentifizierungssysteme, **Datenbankverbindungen**, usw.\n* **Keine Kompromisse** bei Datenbanken, Frontends, usw., sondern einfache Integration mit allen.\n\n### Unbegrenzte Erweiterungen { #unlimited-plug-ins }\n\nOder mit anderen Worten, sie werden nicht benötigt. Importieren und nutzen Sie den Code, den Sie brauchen.\n\nJede Integration wurde so entworfen, dass sie so einfach zu nutzen ist (mit Abhängigkeiten), dass Sie eine Erweiterung für Ihre Anwendung mit nur zwei Zeilen Code erstellen können. Hierbei nutzen Sie die gleiche Struktur und Syntax, wie bei *Pfadoperationen*.\n\n### Getestet { #tested }\n\n* 100 % <dfn title=\"Der Prozentsatz an Code, der automatisch getestet wird\">Testabdeckung</dfn>.\n* 100 % <dfn title=\"Python-Typannotationen, mit denen Ihr Editor und andere externe Werkzeuge Sie besser unterstützen können\">Typen annotiert</dfn>.\n* Verwendet in Produktionsanwendungen.\n\n## Starlette Merkmale { #starlette-features }\n\n**FastAPI** ist vollkommen kompatibel (und basiert auf) [**Starlette**](https://www.starlette.dev/). Das bedeutet, wenn Sie eigenen Starlette Quellcode haben, funktioniert der.\n\n`FastAPI` ist tatsächlich eine Unterklasse von `Starlette`. Wenn Sie also bereits Starlette kennen oder benutzen, das meiste funktioniert genau so.\n\nMit **FastAPI** bekommen Sie alles von **Starlette** (da FastAPI nur Starlette auf Steroiden ist):\n\n* Schwer beeindruckende Performanz. Es ist [eines der schnellsten Python-Frameworks, auf Augenhöhe mit **NodeJS** und **Go**](https://github.com/encode/starlette#performance).\n* **WebSocket**-Unterstützung.\n* Hintergrundtasks im selben Prozess.\n* Startup- und Shutdown-Events.\n* Testclient basierend auf HTTPX.\n* **CORS**, GZip, statische Dateien, Responses streamen.\n* **Sitzungs- und Cookie**-Unterstützung.\n* 100 % Testabdeckung.\n* 100 % Typen annotierte Codebasis.\n\n## Pydantic Merkmale { #pydantic-features }\n\n**FastAPI** ist vollkommen kompatibel (und basiert auf) [**Pydantic**](https://docs.pydantic.dev/). Das bedeutet, wenn Sie eigenen Pydantic Quellcode haben, funktioniert der.\n\nInklusive externer Bibliotheken, die auf Pydantic basieren, wie <abbr title=\"Object-Relational Mapper - Objektrelationaler Mapper\">ORM</abbr>s, <abbr title=\"Object-Document Mapper - Objekt-Dokument-Mapper\">ODM</abbr>s für Datenbanken.\n\nDaher können Sie in vielen Fällen das Objekt eines Requests **direkt zur Datenbank** schicken, weil alles automatisch validiert wird.\n\nDas gleiche gilt auch für die andere Richtung: Sie können in vielen Fällen das Objekt aus der Datenbank **direkt zum Client** senden.\n\nMit **FastAPI** bekommen Sie alle Funktionen von **Pydantic** (da FastAPI für die gesamte Datenverarbeitung Pydantic nutzt):\n\n* **Kein Kopfzerbrechen**:\n    * Keine neue Schemadefinition-Mikrosprache zu lernen.\n    * Wenn Sie Pythons Typen kennen, wissen Sie, wie man Pydantic verwendet.\n* Gutes Zusammenspiel mit Ihrer/Ihrem **<abbr title=\"Integrated Development Environment - Integrierte Entwicklungsumgebung: Ähnlich einem Code-Editor\">IDE</abbr>/<dfn title=\"Ein Programm, das Fehler im Quellcode sucht\">Linter</dfn>/Gehirn**:\n    * Weil Pydantics Datenstrukturen einfach nur Instanzen ihrer definierten Klassen sind; Autovervollständigung, Linting, mypy und Ihre Intuition sollten alle einwandfrei mit Ihren validierten Daten funktionieren.\n* Validierung von **komplexen Strukturen**:\n    * Benutzung von hierarchischen Pydantic-Modellen, Python-`typing`s `List` und `Dict`, etc.\n    * Die Validierer erlauben es, komplexe Datenschemen klar und einfach zu definieren, überprüft und dokumentiert als JSON Schema.\n    * Sie können tief **verschachtelte JSON** Objekte haben, die alle validiert und annotiert sind.\n* **Erweiterbar**:\n    * Pydantic erlaubt die Definition von eigenen Datentypen oder sie können die Validierung mit einer `validator`-dekorierten Methode im Modell erweitern.\n* 100 % Testabdeckung.\n"
  },
  {
    "path": "docs/de/docs/help-fastapi.md",
    "content": "# FastAPI helfen – Hilfe erhalten { #help-fastapi-get-help }\n\nMögen Sie **FastAPI**?\n\nMöchten Sie FastAPI, anderen Benutzern und dem Autor helfen?\n\nOder möchten Sie Hilfe zu **FastAPI** erhalten?\n\nEs gibt sehr einfache Möglichkeiten zu helfen (einige erfordern nur ein oder zwei Klicks).\n\nUnd es gibt auch mehrere Möglichkeiten, Hilfe zu bekommen.\n\n## Newsletter abonnieren { #subscribe-to-the-newsletter }\n\nSie können den (unregelmäßigen) [**FastAPI and friends**-Newsletter](newsletter.md) abonnieren, um über folgende Themen informiert zu bleiben:\n\n* Neuigkeiten über FastAPI und Freunde 🚀\n* Anleitungen 📝\n* Funktionen ✨\n* Breaking Changes 🚨\n* Tipps und Tricks ✅\n\n## FastAPI auf X (Twitter) folgen { #follow-fastapi-on-x-twitter }\n\n[Folgen Sie @fastapi auf **X (Twitter)**](https://x.com/fastapi), um die neuesten Nachrichten über **FastAPI** zu erhalten. 🐦\n\n## **FastAPI** auf GitHub einen Stern geben { #star-fastapi-in-github }\n\nSie können FastAPI auf GitHub „starren“ (klicken Sie auf den Stern-Button oben rechts): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). ⭐️\n\nDurch das Hinzufügen eines Sterns können andere Benutzer es leichter finden und sehen, dass es für andere bereits nützlich war.\n\n## Das GitHub-Repository auf Releases überwachen { #watch-the-github-repository-for-releases }\n\nSie können FastAPI auf GitHub „beobachten“ (klicken Sie auf den „watch“-Button oben rechts): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nDort können Sie „Releases only“ auswählen.\n\nAuf diese Weise erhalten Sie Benachrichtigungen (per E-Mail), wenn es ein neues Release (eine neue Version) von **FastAPI** mit Bugfixes und neuen Funktionen gibt.\n\n## Mit dem Autor vernetzen { #connect-with-the-author }\n\nSie können sich mit [mir (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com), dem Autor, vernetzen.\n\nSie können:\n\n* [Mir auf **GitHub** folgen](https://github.com/tiangolo).\n    * Andere Open-Source-Projekte sehen, die ich erstellt habe und die Ihnen helfen könnten.\n    * Mir folgen, um zu sehen, wenn ich ein neues Open-Source-Projekt erstelle.\n* [Mir auf **X (Twitter)** folgen](https://x.com/tiangolo) oder [Mastodon](https://fosstodon.org/@tiangolo).\n    * Mir mitteilen, wie Sie FastAPI verwenden (ich höre das gerne).\n    * Mitbekommen, wenn ich Ankündigungen mache oder neue Tools veröffentliche.\n    * Sie können auch [@fastapi auf X (Twitter) folgen](https://x.com/fastapi) (ein separates Konto).\n* [Mir auf **LinkedIn** folgen](https://www.linkedin.com/in/tiangolo/).\n    * Mitbekommen, wenn ich Ankündigungen mache oder neue Tools veröffentliche (obwohl ich X (Twitter) häufiger verwende 🤷‍♂).\n* Lesen, was ich schreibe (oder mir folgen) auf [**Dev.to**](https://dev.to/tiangolo) oder [**Medium**](https://medium.com/@tiangolo).\n    * Andere Ideen, Artikel lesen und mehr über die von mir erstellten Tools erfahren.\n    * Mir folgen, um zu lesen, wenn ich etwas Neues veröffentliche.\n\n## Über **FastAPI** tweeten { #tweet-about-fastapi }\n\n[Tweeten Sie über **FastAPI**](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi) und teilen Sie mir und anderen mit, warum es Ihnen gefällt. 🎉\n\nIch höre gerne, wie **FastAPI** verwendet wird, was Ihnen daran gefallen hat, in welchem Projekt/Unternehmen Sie es verwenden, usw.\n\n## Für FastAPI abstimmen { #vote-for-fastapi }\n\n* [Stimmen Sie für **FastAPI** auf Slant](https://www.slant.co/options/34241/~fastapi-review).\n* [Stimmen Sie für **FastAPI** auf AlternativeTo](https://alternativeto.net/software/fastapi/about/).\n* [Sagen Sie auf StackShare, dass Sie **FastAPI** verwenden](https://stackshare.io/pypi-fastapi).\n\n## Anderen bei Fragen auf GitHub helfen { #help-others-with-questions-in-github }\n\nSie können versuchen, anderen bei ihren Fragen zu helfen:\n\n* [GitHub-Diskussionen](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub-Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\nIn vielen Fällen kennen Sie möglicherweise bereits die Antwort auf diese Fragen. 🤓\n\nWenn Sie vielen Menschen bei ihren Fragen helfen, werden Sie offizieller [FastAPI-Experte](fastapi-people.md#fastapi-experts). 🎉\n\nDenken Sie daran, der wichtigste Punkt ist: Versuchen Sie, freundlich zu sein. Die Leute bringen ihre Frustrationen mit und fragen in vielen Fällen nicht auf die beste Art und Weise, aber versuchen Sie dennoch so gut wie möglich, freundlich zu sein. 🤗\n\nDie **FastAPI**-Community soll freundlich und einladend sein. Akzeptieren Sie gleichzeitig kein Mobbing oder respektloses Verhalten gegenüber anderen. Wir müssen uns umeinander kümmern.\n\n---\n\nSo helfen Sie anderen bei Fragen (in Diskussionen oder Issues):\n\n### Die Frage verstehen { #understand-the-question }\n\n* Prüfen Sie, ob Sie verstehen können, was der **Zweck** und der Anwendungsfall der fragenden Person ist.\n\n* Überprüfen Sie dann, ob die Frage (die überwiegende Mehrheit sind Fragen) **klar** ist.\n\n* In vielen Fällen handelt es sich bei der gestellten Frage um eine Lösung, die der Benutzer sich vorstellt, aber es könnte eine **bessere** Lösung geben. Wenn Sie das Problem und den Anwendungsfall besser verstehen, können Sie eine bessere **Alternativlösung** vorschlagen.\n\n* Wenn Sie die Frage nicht verstehen können, fragen Sie nach weiteren **Details**.\n\n### Das Problem reproduzieren { #reproduce-the-problem }\n\nIn den meisten Fällen und bei den meisten Fragen gibt es etwas in Bezug auf den **originalen Code** der Person.\n\nIn vielen Fällen wird nur ein Fragment des Codes gepostet, aber das reicht nicht aus, um **das Problem zu reproduzieren**.\n\n* Sie können die Person bitten, ein [minimales, reproduzierbares Beispiel](https://stackoverflow.com/help/minimal-reproducible-example) bereitzustellen, welches Sie **kopieren, einfügen** und lokal ausführen können, um den gleichen Fehler oder das gleiche Verhalten zu sehen, das die Person sieht, oder um ihren Anwendungsfall besser zu verstehen.\n\n* Wenn Sie in Geberlaune sind, können Sie ein solches Beispiel selbst erstellen, nur basierend auf der Beschreibung des Problems. Denken Sie jedoch daran, dass dies viel Zeit in Anspruch nehmen kann und dass es besser sein kann, zunächst um eine Klärung des Problems zu bitten.\n\n### Lösungen vorschlagen { #suggest-solutions }\n\n* Nachdem Sie die Frage verstanden haben, können Sie eine mögliche **Antwort** geben.\n\n* In vielen Fällen ist es besser, das **zugrunde liegende Problem oder den Anwendungsfall** zu verstehen, da es möglicherweise einen besseren Weg zur Lösung gibt als das, was die Person versucht.\n\n### Um Schließung bitten { #ask-to-close }\n\nWenn die Person antwortet, besteht eine hohe Chance, dass Sie ihr Problem gelöst haben. Herzlichen Glückwunsch, **Sie sind ein Held**! 🦸\n\n* Wenn es tatsächlich das Problem gelöst hat, können Sie sie darum bitten:\n\n    * In GitHub-Diskussionen: den Kommentar als **Antwort** zu markieren.\n    * In GitHub-Issues: Das Issue zu **schließen**.\n\n## Das GitHub-Repository beobachten { #watch-the-github-repository }\n\nSie können FastAPI auf GitHub „beobachten“ (klicken Sie auf den „watch“-Button oben rechts): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nWenn Sie dann „Watching“ statt „Releases only“ auswählen, erhalten Sie Benachrichtigungen, wenn jemand ein neues Issue eröffnet oder eine neue Frage stellt. Sie können auch spezifizieren, dass Sie nur über neue Issues, Diskussionen, PRs usw. benachrichtigt werden möchten.\n\nDann können Sie versuchen, bei der Lösung solcher Fragen zu helfen.\n\n## Fragen stellen { #ask-questions }\n\nSie können im GitHub-Repository [eine neue Frage erstellen](https://github.com/fastapi/fastapi/discussions/new?category=questions), zum Beispiel:\n\n* Stellen Sie eine **Frage** oder bitten Sie um Hilfe mit einem **Problem**.\n* Schlagen Sie eine neue **Funktionalität** vor.\n\n**Hinweis**: Wenn Sie das tun, bitte ich Sie, auch anderen zu helfen. 😉\n\n## Pull Requests prüfen { #review-pull-requests }\n\nSie können mir helfen, Pull Requests von anderen zu überprüfen.\n\nNoch einmal, bitte versuchen Sie Ihr Bestes, freundlich zu sein. 🤗\n\n---\n\nHier ist, was Sie beachten sollten und wie Sie einen Pull Request überprüfen:\n\n### Das Problem verstehen { #understand-the-problem }\n\n* Stellen Sie zunächst sicher, dass Sie **das Problem verstehen**, welches der Pull Request zu lösen versucht. Möglicherweise gibt es eine längere Diskussion dazu in einer GitHub-Diskussion oder einem GitHub-Issue.\n\n* Es besteht auch eine gute Chance, dass der Pull Request nicht wirklich benötigt wird, da das Problem auf **andere Weise** gelöst werden kann. Dann können Sie das vorschlagen oder danach fragen.\n\n### Keine Panik wegen des Stils { #dont-worry-about-style }\n\n* Machen Sie sich keine Sorgen über Dinge wie den Stil von Commit-Nachrichten. Ich werde den Commit zusammenführen und manuell anpassen.\n\n* Außerdem, keine Sorgen über Stilregeln, es gibt bereits automatisierte Tools, die das überprüfen.\n\nUnd wenn es irgendeinen anderen Stil- oder Konsistenzbedarf gibt, werde ich direkt danach fragen oder zusätzliche Commits mit den erforderlichen Änderungen hinzufügen.\n\n### Den Code testen { #check-the-code }\n\n* Prüfen und lesen Sie den Code, fragen Sie sich, ob er Sinn macht, **führen Sie ihn lokal aus** und testen Sie, ob er das Problem tatsächlich löst.\n\n* Schreiben Sie dann einen **Kommentar** und berichten, dass Sie das getan haben. So weiß ich, dass Sie ihn wirklich überprüft haben.\n\n/// info | Info\n\nLeider kann ich PRs, nur weil sie von mehreren gutgeheißen wurden, nicht einfach vertrauen.\n\nEs ist mehrmals passiert, dass es PRs mit drei, fünf oder mehr Zustimmungen gibt, wahrscheinlich weil die Beschreibung ansprechend ist, aber wenn ich die PRs überprüfe, sind sie tatsächlich fehlerhaft, haben einen Bug, oder lösen das Problem nicht, welches sie behaupten, zu lösen. 😅\n\nDaher ist es wirklich wichtig, dass Sie den Code wirklich lesen und ausführen und mir in den Kommentaren mitteilen, dass Sie dies getan haben. 🤓\n\n///\n\n* Wenn der PR in irgendeiner Weise vereinfacht werden kann, können Sie danach fragen, aber es gibt keinen Grund, zu wählerisch zu sein. Es gibt viele subjektive Standpunkte (und ich habe auch meinen eigenen 🙈), also ist es besser, wenn man sich auf die grundlegenden Dinge konzentriert.\n\n### Tests { #tests }\n\n* Helfen Sie mir zu überprüfen, dass der PR **Tests** hat.\n\n* Überprüfen Sie, dass diese Tests vor dem PR **fehlschlagen**. 🚨\n\n* Überprüfen Sie dann, dass diese Tests nach dem PR **bestanden** werden. ✅\n\n* Viele PRs haben keine Tests. Sie können den Autor daran **erinnern**, Tests hinzuzufügen, oder Sie können sogar selbst einige Tests **vorschlagen**. Das ist eines der Dinge, die am meisten Zeit in Anspruch nehmen, und Sie können dabei viel helfen.\n\n* Kommentieren Sie auch hier anschließend, was Sie versucht haben, sodass ich weiß, dass Sie es überprüft haben. 🤓\n\n## Einen Pull Request erstellen { #create-a-pull-request }\n\nSie können [zum Quellcode mit Pull Requests beitragen](contributing.md), zum Beispiel:\n\n* Um einen Tippfehler zu beheben, den Sie in der Dokumentation gefunden haben.\n* Um einen Artikel, ein Video oder einen Podcast über FastAPI zu teilen, den Sie erstellt oder gefunden haben, indem Sie [diese Datei bearbeiten](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml).\n    * Stellen Sie sicher, dass Sie Ihren Link am Anfang des entsprechenden Abschnitts einfügen.\n* Um zu helfen, [die Dokumentation in Ihre Sprache zu übersetzen](contributing.md#translations).\n    * Sie können auch dabei helfen, die von anderen erstellten Übersetzungen zu überprüfen.\n* Um neue Dokumentationsabschnitte vorzuschlagen.\n* Um ein bestehendes Problem/Bug zu beheben.\n    * Stellen Sie sicher, dass Sie Tests hinzufügen.\n* Um eine neue Funktionalität hinzuzufügen.\n    * Stellen Sie sicher, dass Sie Tests hinzufügen.\n    * Stellen Sie sicher, dass Sie Dokumentation hinzufügen, falls das notwendig ist.\n\n## FastAPI pflegen { #help-maintain-fastapi }\n\nHelfen Sie mir, **FastAPI** zu pflegen! 🤓\n\nEs gibt viel zu tun, und das meiste davon können **SIE** tun.\n\nDie Hauptaufgaben, die Sie jetzt erledigen können, sind:\n\n* [Anderen bei Fragen auf GitHub helfen](#help-others-with-questions-in-github) (siehe Abschnitt oben).\n* [Pull Requests prüfen](#review-pull-requests) (siehe Abschnitt oben).\n\nDiese beiden Aufgaben sind die Dinge, die **am meisten Zeit verbrauchen**. Das ist die Hauptarbeit bei der Wartung von FastAPI.\n\nWenn Sie mir dabei helfen können, **helfen Sie mir, FastAPI zu pflegen** und Sie stellen sicher, dass es weiterhin **schneller und besser voranschreitet**. 🚀\n\n## Am Chat teilnehmen { #join-the-chat }\n\nTreten Sie dem 👥 [Discord-Chatserver](https://discord.gg/VQjSZaeJmf) 👥 bei und treffen Sie sich mit anderen Mitgliedern der FastAPI-Community.\n\n/// tip | Tipp\n\nBei Fragen stellen Sie sie in [GitHub-Diskussionen](https://github.com/fastapi/fastapi/discussions/new?category=questions), dort besteht eine viel größere Chance, dass Sie Hilfe von den [FastAPI-Experten](fastapi-people.md#fastapi-experts) erhalten.\n\nNutzen Sie den Chat nur für andere allgemeine Gespräche.\n\n///\n\n### Den Chat nicht für Fragen verwenden { #dont-use-the-chat-for-questions }\n\nBedenken Sie, dass Sie in Chats, die „freie Konversation“ erlauben, leicht Fragen stellen können, die zu allgemein und schwer zu beantworten sind, sodass Sie möglicherweise keine Antworten erhalten.\n\nAuf GitHub hilft Ihnen die Vorlage dabei, die richtige Frage zu stellen, sodass Sie leichter eine gute Antwort erhalten können, oder sogar das Problem selbst lösen, bevor Sie überhaupt fragen. Und auf GitHub kann ich sicherstellen, dass ich immer alles beantworte, auch wenn es einige Zeit dauert. Persönlich kann ich das mit den Chat-Systemen nicht machen. 😅\n\nUnterhaltungen in den Chat-Systemen sind auch nicht so leicht durchsuchbar wie auf GitHub, sodass Fragen und Antworten möglicherweise im Gespräch verloren gehen. Und nur die auf GitHub machen einen [FastAPI-Experten](fastapi-people.md#fastapi-experts), Sie werden also höchstwahrscheinlich mehr Aufmerksamkeit auf GitHub erhalten.\n\nAuf der anderen Seite gibt es Tausende von Benutzern in den Chat-Systemen, sodass die Wahrscheinlichkeit hoch ist, dass Sie dort fast immer jemanden zum Reden finden. 😄\n\n## Den Autor sponsern { #sponsor-the-author }\n\nWenn Ihr **Produkt/Firma** auf **FastAPI** angewiesen ist oder in Zusammenhang steht und Sie seine Benutzer erreichen möchten, können Sie den Autor (mich) über [GitHub-Sponsoren](https://github.com/sponsors/tiangolo) unterstützen. Je nach Stufe können Sie einige zusätzliche Vorteile erhalten, wie z. B. ein Abzeichen in der Dokumentation. 🎁\n\n---\n\nDanke! 🚀\n"
  },
  {
    "path": "docs/de/docs/history-design-future.md",
    "content": "# Geschichte, Design und Zukunft { #history-design-and-future }\n\nVor einiger Zeit fragte [ein **FastAPI**-Benutzer](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920):\n\n> Was ist die Geschichte dieses Projekts? Es scheint aus dem Nichts in ein paar Wochen zu etwas Großartigem geworden zu sein [...]\n\nHier ist ein wenig über diese Geschichte.\n\n## Alternativen { #alternatives }\n\nIch habe seit mehreren Jahren APIs mit komplexen Anforderungen (maschinelles Lernen, verteilte Systeme, asynchrone Jobs, NoSQL-Datenbanken, usw.) erstellt und leitete mehrere Entwicklerteams.\n\nDabei musste ich viele Alternativen untersuchen, testen und nutzen.\n\nDie Geschichte von **FastAPI** ist zu einem großen Teil die Geschichte seiner Vorgänger.\n\nWie im Abschnitt [Alternativen](alternatives.md) gesagt:\n\n<blockquote markdown=\"1\">\n\n**FastAPI** würde ohne die frühere Arbeit anderer nicht existieren.\n\nEs wurden zuvor viele Tools entwickelt, die als Inspiration für seine Entwicklung dienten.\n\nIch habe die Schaffung eines neuen Frameworks viele Jahre lang vermieden. Zuerst habe ich versucht, alle von **FastAPI** abgedeckten Funktionen mithilfe vieler verschiedener Frameworks, Plugins und Tools zu lösen.\n\nAber irgendwann gab es keine andere Möglichkeit, als etwas zu schaffen, das all diese Funktionen bereitstellte, die besten Ideen früherer Tools aufnahm und diese auf die bestmögliche Weise kombinierte, wobei Sprachfunktionen verwendet wurden, die vorher noch nicht einmal verfügbar waren (Python 3.6+ Typhinweise).\n\n</blockquote>\n\n## Untersuchung { #investigation }\n\nDurch die Nutzung all dieser vorherigen Alternativen hatte ich die Möglichkeit, von allen zu lernen, Ideen aufzunehmen und sie auf die beste Weise zu kombinieren, die ich für mich und die Entwicklerteams, mit denen ich zusammengearbeitet habe, finden konnte.\n\nEs war beispielsweise klar, dass es idealerweise auf Standard-Python-Typhinweisen basieren sollte.\n\nDer beste Ansatz bestand außerdem darin, bereits bestehende Standards zu nutzen.\n\nBevor ich also überhaupt angefangen habe, **FastAPI** zu schreiben, habe ich mehrere Monate damit verbracht, die Spezifikationen für OpenAPI, JSON Schema, OAuth2, usw. zu studieren und deren Beziehungen, Überschneidungen und Unterschiede zu verstehen.\n\n## Design { #design }\n\nDann habe ich einige Zeit damit verbracht, die Entwickler-„API“ zu entwerfen, die ich als Benutzer haben wollte (als Entwickler, welcher FastAPI verwendet).\n\nIch habe mehrere Ideen in den beliebtesten Python-Editoren getestet: PyCharm, VS Code, Jedi-basierte Editoren.\n\nLaut der letzten [Python-Entwickler-Umfrage](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools) deckt das etwa 80 % der Benutzer ab.\n\nDas bedeutet, dass **FastAPI** speziell mit den Editoren getestet wurde, die von 80 % der Python-Entwickler verwendet werden. Und da die meisten anderen Editoren in der Regel ähnlich funktionieren, sollten alle diese Vorteile für praktisch alle Editoren funktionieren.\n\nAuf diese Weise konnte ich die besten Möglichkeiten finden, die Codeverdoppelung so weit wie möglich zu reduzieren, überall Autovervollständigung, Typ- und Fehlerprüfungen, usw. zu gewährleisten.\n\nAlles auf eine Weise, die allen Entwicklern das beste Entwicklungserlebnis bot.\n\n## Anforderungen { #requirements }\n\nNachdem ich mehrere Alternativen getestet hatte, entschied ich, dass ich [**Pydantic**](https://docs.pydantic.dev/) wegen seiner Vorteile verwenden würde.\n\nDann habe ich zu dessen Code beigetragen, um es vollständig mit JSON Schema kompatibel zu machen, und so verschiedene Möglichkeiten zum Definieren von einschränkenden Deklarationen (Constraints) zu unterstützen, und die Editorunterstützung (Typprüfungen, Codevervollständigung) zu verbessern, basierend auf den Tests in mehreren Editoren.\n\nWährend der Entwicklung habe ich auch zu [**Starlette**](https://www.starlette.dev/) beigetragen, die andere Schlüsselanforderung.\n\n## Entwicklung { #development }\n\nAls ich mit der Erstellung von **FastAPI** selbst begann, waren die meisten Teile bereits vorhanden, das Design definiert, die Anforderungen und Tools bereit und das Wissen über die Standards und Spezifikationen klar und frisch.\n\n## Zukunft { #future }\n\nZu diesem Zeitpunkt ist bereits klar, dass **FastAPI** mit seinen Ideen für viele Menschen nützlich ist.\n\nEs wird gegenüber früheren Alternativen gewählt, da es für viele Anwendungsfälle besser geeignet ist.\n\nViele Entwickler und Teams verlassen sich bei ihren Projekten bereits auf **FastAPI** (einschließlich mir und meinem Team).\n\nDennoch stehen uns noch viele Verbesserungen und Funktionen bevor.\n\n**FastAPI** hat eine große Zukunft vor sich.\n\nUnd [Ihre Hilfe](help-fastapi.md) wird sehr geschätzt.\n"
  },
  {
    "path": "docs/de/docs/how-to/authentication-error-status-code.md",
    "content": "# Alte 403-Authentifizierungsfehler-Statuscodes verwenden { #use-old-403-authentication-error-status-codes }\n\nVor FastAPI-Version `0.122.0` verwendeten die integrierten Sicherheits-Utilities den HTTP-Statuscode `403 Forbidden`, wenn sie dem Client nach einer fehlgeschlagenen Authentifizierung einen Fehler zurückgaben.\n\nAb FastAPI-Version `0.122.0` verwenden sie den passenderen HTTP-Statuscode `401 Unauthorized` und geben in der Response einen sinnvollen `WWW-Authenticate`-Header zurück, gemäß den HTTP-Spezifikationen, [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized).\n\nAber falls Ihre Clients aus irgendeinem Grund vom alten Verhalten abhängen, können Sie darauf zurückgreifen, indem Sie in Ihren Sicherheitsklassen die Methode `make_not_authenticated_error` überschreiben.\n\nSie können beispielsweise eine Unterklasse von `HTTPBearer` erstellen, die einen Fehler `403 Forbidden` zurückgibt, statt des Default-`401 Unauthorized`-Fehlers:\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip | Tipp\n\nBeachten Sie, dass die Funktion die Exception-Instanz zurückgibt; sie wirft sie nicht. Das Werfen erfolgt im restlichen internen Code.\n\n///\n"
  },
  {
    "path": "docs/de/docs/how-to/conditional-openapi.md",
    "content": "# Bedingte OpenAPI { #conditional-openapi }\n\nBei Bedarf können Sie OpenAPI mithilfe von Einstellungen und Umgebungsvariablen abhängig von der Umgebung bedingt konfigurieren und sogar vollständig deaktivieren.\n\n## Über Sicherheit, APIs und Dokumentation { #about-security-apis-and-docs }\n\nDas Verstecken Ihrer Dokumentationsoberflächen in der Produktion *sollte nicht* die Methode sein, Ihre API zu schützen.\n\nDadurch wird Ihrer API keine zusätzliche Sicherheit hinzugefügt, die *Pfadoperationen* sind weiterhin dort verfügbar, wo sie sich befinden.\n\nWenn Ihr Code eine Sicherheitslücke aufweist, ist diese weiterhin vorhanden.\n\nDas Verstecken der Dokumentation macht es nur schwieriger zu verstehen, wie mit Ihrer API interagiert werden kann, und könnte es auch schwieriger machen, diese in der Produktion zu debuggen. Man könnte es einfach als eine Form von [Sicherheit durch Verschleierung](https://en.wikipedia.org/wiki/Security_through_obscurity) betrachten.\n\nWenn Sie Ihre API sichern möchten, gibt es mehrere bessere Dinge, die Sie tun können, zum Beispiel:\n\n* Stellen Sie sicher, dass Sie über gut definierte Pydantic-Modelle für Ihre <abbr title=\"Anfragekörper\">Requestbodys</abbr> und <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Responses</abbr> verfügen.\n* Konfigurieren Sie alle erforderlichen Berechtigungen und Rollen mithilfe von Abhängigkeiten.\n* Speichern Sie niemals Klartext-Passwörter, sondern nur Passwort-Hashes.\n* Implementieren und verwenden Sie gängige kryptografische Tools wie pwdlib und JWT-Tokens, usw.\n* Fügen Sie bei Bedarf detailliertere Berechtigungskontrollen mit OAuth2-Scopes hinzu.\n* ... usw.\n\nDennoch kann es sein, dass Sie einen ganz bestimmten Anwendungsfall haben, bei dem Sie die API-Dokumentation für eine bestimmte Umgebung (z. B. für die Produktion) oder abhängig von Konfigurationen aus Umgebungsvariablen wirklich deaktivieren müssen.\n\n## Bedingte OpenAPI aus Einstellungen und Umgebungsvariablen { #conditional-openapi-from-settings-and-env-vars }\n\nSie können problemlos dieselben Pydantic-Einstellungen verwenden, um Ihre generierte OpenAPI und die Dokumentationsoberflächen zu konfigurieren.\n\nZum Beispiel:\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\nHier deklarieren wir die Einstellung `openapi_url` mit dem gleichen Defaultwert `\"/openapi.json\"`.\n\nUnd dann verwenden wir es beim Erstellen der `FastAPI`-App.\n\nDann könnten Sie OpenAPI (einschließlich der Dokumentationsoberflächen) deaktivieren, indem Sie die Umgebungsvariable `OPENAPI_URL` auf einen leeren String setzen, wie zum Beispiel:\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nWenn Sie dann zu den URLs unter `/openapi.json`, `/docs` oder `/redoc` gehen, erhalten Sie lediglich einen `404 Not Found`-Fehler, wie:\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/de/docs/how-to/configure-swagger-ui.md",
    "content": "# Swagger-Oberfläche konfigurieren { #configure-swagger-ui }\n\nSie können einige zusätzliche [Parameter der Swagger-Oberfläche](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/) konfigurieren.\n\nUm diese zu konfigurieren, übergeben Sie das Argument `swagger_ui_parameters` beim Erstellen des `FastAPI()`-App-Objekts oder an die Funktion `get_swagger_ui_html()`.\n\n`swagger_ui_parameters` empfängt ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">Dictionary</abbr> mit den Konfigurationen, die direkt an die Swagger-Oberfläche übergeben werden.\n\nFastAPI konvertiert die Konfigurationen nach **JSON**, um diese mit JavaScript kompatibel zu machen, da die Swagger-Oberfläche das benötigt.\n\n## Syntaxhervorhebung deaktivieren { #disable-syntax-highlighting }\n\nSie könnten beispielsweise die Syntaxhervorhebung in der Swagger-Oberfläche deaktivieren.\n\nOhne Änderung der Einstellungen ist die Syntaxhervorhebung standardmäßig aktiviert:\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\nSie können sie jedoch deaktivieren, indem Sie `syntaxHighlight` auf `False` setzen:\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n... und dann zeigt die Swagger-Oberfläche die Syntaxhervorhebung nicht mehr an:\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## Das Theme ändern { #change-the-theme }\n\nAuf die gleiche Weise könnten Sie das Theme der Syntaxhervorhebung mit dem Schlüssel `\"syntaxHighlight.theme\"` festlegen (beachten Sie, dass er einen Punkt in der Mitte hat):\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\nObige Konfiguration würde das Theme für die Farbe der Syntaxhervorhebung ändern:\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## Defaultparameter der Swagger-Oberfläche ändern { #change-default-swagger-ui-parameters }\n\nFastAPI enthält einige Defaultkonfigurationsparameter, die für die meisten Anwendungsfälle geeignet sind.\n\nEs umfasst die folgenden Defaultkonfigurationen:\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\nSie können jede davon überschreiben, indem Sie im Argument `swagger_ui_parameters` einen anderen Wert festlegen.\n\nUm beispielsweise `deepLinking` zu deaktivieren, könnten Sie folgende Einstellungen an `swagger_ui_parameters` übergeben:\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## Andere Parameter der Swagger-Oberfläche { #other-swagger-ui-parameters }\n\nUm alle anderen möglichen Konfigurationen zu sehen, die Sie verwenden können, lesen Sie die offizielle [Dokumentation für die Parameter der Swagger-Oberfläche](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\n## Nur-JavaScript-Einstellungen { #javascript-only-settings }\n\nDie Swagger-Oberfläche erlaubt, dass andere Konfigurationen auch **Nur-JavaScript**-Objekte sein können (z. B. JavaScript-Funktionen).\n\nFastAPI umfasst auch diese Nur-JavaScript-`presets`-Einstellungen:\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\nDabei handelt es sich um **JavaScript**-Objekte, nicht um Strings, daher können Sie diese nicht direkt vom Python-Code aus übergeben.\n\nWenn Sie solche JavaScript-Konfigurationen verwenden müssen, können Sie einen der früher genannten Wege verwenden. Überschreiben Sie alle *Pfadoperationen* der Swagger-Oberfläche und schreiben Sie manuell jedes benötigte JavaScript.\n"
  },
  {
    "path": "docs/de/docs/how-to/custom-docs-ui-assets.md",
    "content": "# Statische Assets der Dokumentationsoberfläche (Selbst-Hosting) { #custom-docs-ui-static-assets-self-hosting }\n\nDie API-Dokumentation verwendet **Swagger UI** und **ReDoc**, und jede dieser Dokumentationen benötigt einige JavaScript- und CSS-Dateien.\n\nStandardmäßig werden diese Dateien von einem <abbr title=\"Content Delivery Network - Inhalte auslieferndes Netzwerk: Ein Dienst, der normalerweise aus mehreren Servern besteht und statische Dateien wie JavaScript und CSS bereitstellt. Er wird häufig verwendet, um diese Dateien vom Server bereitzustellen, der näher am Client liegt, wodurch die Leistung verbessert wird.\">CDN</abbr> bereitgestellt.\n\nEs ist jedoch möglich, das anzupassen, ein bestimmtes CDN festzulegen oder die Dateien selbst bereitzustellen.\n\n## Benutzerdefiniertes CDN für JavaScript und CSS { #custom-cdn-for-javascript-and-css }\n\nNehmen wir an, Sie möchten ein anderes <abbr title=\"Content Delivery Network - Inhalte auslieferndes Netzwerk\">CDN</abbr> verwenden, zum Beispiel möchten Sie `https://unpkg.com/` verwenden.\n\nDas kann nützlich sein, wenn Sie beispielsweise in einem Land leben, in dem bestimmte URLs eingeschränkt sind.\n\n### Die automatische Dokumentation deaktivieren { #disable-the-automatic-docs }\n\nDer erste Schritt besteht darin, die automatische Dokumentation zu deaktivieren, da sie standardmäßig das Standard-CDN verwendet.\n\nUm sie zu deaktivieren, setzen Sie deren URLs beim Erstellen Ihrer `FastAPI`-App auf `None`:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### Die benutzerdefinierte Dokumentation hinzufügen { #include-the-custom-docs }\n\nJetzt können Sie die *Pfadoperationen* für die benutzerdefinierte Dokumentation erstellen.\n\nSie können die internen Funktionen von FastAPI wiederverwenden, um die HTML-Seiten für die Dokumentation zu erstellen und ihnen die erforderlichen Argumente zu übergeben:\n\n* `openapi_url`: die URL, unter welcher die HTML-Seite für die Dokumentation das OpenAPI-Schema für Ihre API abrufen kann. Sie können hier das Attribut `app.openapi_url` verwenden.\n* `title`: der Titel Ihrer API.\n* `oauth2_redirect_url`: Sie können hier `app.swagger_ui_oauth2_redirect_url` verwenden, um die Standardeinstellung zu verwenden.\n* `swagger_js_url`: die URL, unter welcher der HTML-Code für Ihre Swagger-UI-Dokumentation die **JavaScript**-Datei abrufen kann. Dies ist die benutzerdefinierte CDN-URL.\n* `swagger_css_url`: die URL, unter welcher der HTML-Code für Ihre Swagger-UI-Dokumentation die **CSS**-Datei abrufen kann. Dies ist die benutzerdefinierte CDN-URL.\n\nUnd ähnlich für ReDoc ...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip | Tipp\n\nDie *Pfadoperation* für `swagger_ui_redirect` ist ein Hilfsmittel bei der Verwendung von OAuth2.\n\nWenn Sie Ihre API mit einem OAuth2-Anbieter integrieren, können Sie sich authentifizieren und mit den erworbenen Anmeldeinformationen zur API-Dokumentation zurückkehren. Und mit ihr interagieren, die echte OAuth2-Authentifizierung verwendend.\n\nSwagger UI erledigt das hinter den Kulissen für Sie, benötigt aber diesen „Umleitungs“-Helfer.\n\n///\n\n### Eine *Pfadoperation* erstellen, um es zu testen { #create-a-path-operation-to-test-it }\n\nUm nun testen zu können, ob alles funktioniert, erstellen Sie eine *Pfadoperation*:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### Es testen { #test-it }\n\nJetzt sollten Sie in der Lage sein, zu Ihrer Dokumentation auf [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) zu gehen und die Seite neu zu laden, die Assets werden nun vom neuen CDN geladen.\n\n## JavaScript und CSS für die Dokumentation selbst hosten { #self-hosting-javascript-and-css-for-docs }\n\nDas Selbst-Hosting von JavaScript und CSS kann nützlich sein, wenn Sie beispielsweise möchten, dass Ihre Anwendung auch offline, ohne bestehenden Internetzugang oder in einem lokalen Netzwerk weiter funktioniert.\n\nHier erfahren Sie, wie Sie diese Dateien selbst in derselben FastAPI-App bereitstellen und die Dokumentation für deren Verwendung konfigurieren.\n\n### Projektdateistruktur { #project-file-structure }\n\nNehmen wir an, die Dateistruktur Ihres Projekts sieht folgendermaßen aus:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\nErstellen Sie jetzt ein Verzeichnis zum Speichern dieser statischen Dateien.\n\nIhre neue Dateistruktur könnte so aussehen:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### Die Dateien herunterladen { #download-the-files }\n\nLaden Sie die für die Dokumentation benötigten statischen Dateien herunter und legen Sie diese im Verzeichnis `static/` ab.\n\nSie können wahrscheinlich mit der rechten Maustaste auf jeden Link klicken und eine Option wie etwa „Link speichern unter ...“ auswählen.\n\n**Swagger UI** verwendet folgende Dateien:\n\n* [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n* [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\nUnd **ReDoc** verwendet diese Datei:\n\n* [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\nDanach könnte Ihre Dateistruktur wie folgt aussehen:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### Die statischen Dateien bereitstellen { #serve-the-static-files }\n\n* Importieren Sie `StaticFiles`.\n* „Mounten“ Sie eine `StaticFiles()`-Instanz in einem bestimmten Pfad.\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### Die statischen Dateien testen { #test-the-static-files }\n\nStarten Sie Ihre Anwendung und gehen Sie auf [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js).\n\nSie sollten eine sehr lange JavaScript-Datei für **ReDoc** sehen.\n\nSie könnte beginnen mit etwas wie:\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\nDas zeigt, dass Sie statische Dateien aus Ihrer Anwendung bereitstellen können und dass Sie die statischen Dateien für die Dokumentation an der richtigen Stelle platziert haben.\n\nJetzt können wir die Anwendung so konfigurieren, dass sie diese statischen Dateien für die Dokumentation verwendet.\n\n### Die automatische Dokumentation für statische Dateien deaktivieren { #disable-the-automatic-docs-for-static-files }\n\nWie bei der Verwendung eines benutzerdefinierten CDN besteht der erste Schritt darin, die automatische Dokumentation zu deaktivieren, da sie standardmäßig das CDN verwendet.\n\nUm sie zu deaktivieren, setzen Sie deren URLs beim Erstellen Ihrer `FastAPI`-App auf `None`:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### Die benutzerdefinierte Dokumentation für statische Dateien hinzufügen { #include-the-custom-docs-for-static-files }\n\nUnd genau wie bei einem benutzerdefinierten CDN können Sie jetzt die *Pfadoperationen* für die benutzerdefinierte Dokumentation erstellen.\n\nAuch hier können Sie die internen Funktionen von FastAPI wiederverwenden, um die HTML-Seiten für die Dokumentation zu erstellen und ihnen die erforderlichen Argumente zu übergeben:\n\n* `openapi_url`: die URL, unter der die HTML-Seite für die Dokumentation das OpenAPI-Schema für Ihre API abrufen kann. Sie können hier das Attribut `app.openapi_url` verwenden.\n* `title`: der Titel Ihrer API.\n* `oauth2_redirect_url`: Sie können hier `app.swagger_ui_oauth2_redirect_url` verwenden, um die Standardeinstellung zu verwenden.\n* `swagger_js_url`: die URL, unter welcher der HTML-Code für Ihre Swagger-UI-Dokumentation die **JavaScript**-Datei abrufen kann. **Das ist die, welche jetzt von Ihrer eigenen Anwendung bereitgestellt wird**.\n* `swagger_css_url`: die URL, unter welcher der HTML-Code für Ihre Swagger-UI-Dokumentation die **CSS**-Datei abrufen kann. **Das ist die, welche jetzt von Ihrer eigenen Anwendung bereitgestellt wird**.\n\nUnd ähnlich für ReDoc ...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip | Tipp\n\nDie *Pfadoperation* für `swagger_ui_redirect` ist ein Hilfsmittel bei der Verwendung von OAuth2.\n\nWenn Sie Ihre API mit einem OAuth2-Anbieter integrieren, können Sie sich authentifizieren und mit den erworbenen Anmeldeinformationen zur API-Dokumentation zurückkehren. Und mit ihr interagieren, die echte OAuth2-Authentifizierung verwendend.\n\nSwagger UI erledigt das hinter den Kulissen für Sie, benötigt aber diesen „Umleitungs“-Helfer.\n\n///\n\n### Eine *Pfadoperation* erstellen, um statische Dateien zu testen { #create-a-path-operation-to-test-static-files }\n\nUm nun testen zu können, ob alles funktioniert, erstellen Sie eine *Pfadoperation*:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### Benutzeroberfläche mit statischen Dateien testen { #test-static-files-ui }\n\nJetzt sollten Sie in der Lage sein, Ihr WLAN zu trennen, gehen Sie zu Ihrer Dokumentation unter [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) und laden Sie die Seite neu.\n\nUnd selbst ohne Internet können Sie die Dokumentation für Ihre API sehen und mit ihr interagieren.\n"
  },
  {
    "path": "docs/de/docs/how-to/custom-request-and-route.md",
    "content": "# Benutzerdefinierte Request- und APIRoute-Klasse { #custom-request-and-apiroute-class }\n\nIn einigen Fällen möchten Sie möglicherweise die von den Klassen `Request` und `APIRoute` verwendete Logik überschreiben.\n\nDas kann insbesondere eine gute Alternative zur Logik in einer Middleware sein.\n\nWenn Sie beispielsweise den <abbr title=\"Anfragekörper\">Requestbody</abbr> lesen oder manipulieren möchten, bevor er von Ihrer Anwendung verarbeitet wird.\n\n/// danger | Gefahr\n\nDies ist eine „fortgeschrittene“ Funktion.\n\nWenn Sie gerade erst mit **FastAPI** beginnen, möchten Sie diesen Abschnitt vielleicht überspringen.\n\n///\n\n## Anwendungsfälle { #use-cases }\n\nEinige Anwendungsfälle sind:\n\n* Konvertieren von Nicht-JSON-Requestbodys nach JSON (z. B. [`msgpack`](https://msgpack.org/index.html)).\n* Dekomprimierung gzip-komprimierter Requestbodys.\n* Automatisches Loggen aller Requestbodys.\n\n## Handhaben von benutzerdefinierten Requestbody-Kodierungen { #handling-custom-request-body-encodings }\n\nSehen wir uns an, wie Sie eine benutzerdefinierte `Request`-Unterklasse verwenden, um gzip-Requests zu dekomprimieren.\n\nUnd eine `APIRoute`-Unterklasse zur Verwendung dieser benutzerdefinierten Requestklasse.\n\n### Eine benutzerdefinierte `GzipRequest`-Klasse erstellen { #create-a-custom-gziprequest-class }\n\n/// tip | Tipp\n\nDies ist nur ein einfaches Beispiel, um zu demonstrieren, wie es funktioniert. Wenn Sie Gzip-Unterstützung benötigen, können Sie die bereitgestellte [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware) verwenden.\n\n///\n\nZuerst erstellen wir eine `GzipRequest`-Klasse, welche die Methode `Request.body()` überschreibt, um den Body bei Vorhandensein eines entsprechenden Headers zu dekomprimieren.\n\nWenn der Header kein `gzip` enthält, wird nicht versucht, den Body zu dekomprimieren.\n\nAuf diese Weise kann dieselbe Routenklasse gzip-komprimierte oder unkomprimierte Requests verarbeiten.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### Eine benutzerdefinierte `GzipRoute`-Klasse erstellen { #create-a-custom-gziproute-class }\n\nAls Nächstes erstellen wir eine benutzerdefinierte Unterklasse von `fastapi.routing.APIRoute`, welche `GzipRequest` nutzt.\n\nDieses Mal wird die Methode `APIRoute.get_route_handler()` überschrieben.\n\nDiese Methode gibt eine Funktion zurück. Und diese Funktion empfängt einen <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> und gibt eine <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> zurück.\n\nHier verwenden wir sie, um aus dem ursprünglichen Request einen `GzipRequest` zu erstellen.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | Technische Details\n\nEin `Request` hat ein `request.scope`-Attribut, welches einfach ein Python-<abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr> ist, welches die mit dem Request verbundenen Metadaten enthält.\n\nEin `Request` hat auch ein `request.receive`, welches eine Funktion ist, die den Body des Requests <abbr title=\"Englisch „receive“\">empfängt</abbr>.\n\nDas `scope`-`dict` und die `receive`-Funktion sind beide Teil der ASGI-Spezifikation.\n\nUnd diese beiden Dinge, `scope` und `receive`, werden benötigt, um eine neue `Request`-Instanz zu erstellen.\n\nUm mehr über den `Request` zu erfahren, schauen Sie sich [Starlettes Dokumentation zu Requests](https://www.starlette.dev/requests/) an.\n\n///\n\nDas Einzige, was die von `GzipRequest.get_route_handler` zurückgegebene Funktion anders macht, ist die Konvertierung von `Request` in ein `GzipRequest`.\n\nDabei kümmert sich unser `GzipRequest` um die Dekomprimierung der Daten (falls erforderlich), bevor diese an unsere *Pfadoperationen* weitergegeben werden.\n\nDanach ist die gesamte Verarbeitungslogik dieselbe.\n\nAufgrund unserer Änderungen in `GzipRequest.body` wird der Requestbody jedoch bei Bedarf automatisch dekomprimiert, wenn er von **FastAPI** geladen wird.\n\n## Zugriff auf den Requestbody in einem Exceptionhandler { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip | Tipp\n\nUm dasselbe Problem zu lösen, ist es wahrscheinlich viel einfacher, den `body` in einem benutzerdefinierten Handler für `RequestValidationError` zu verwenden ([Fehlerbehandlung](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)).\n\nDieses Beispiel ist jedoch immer noch gültig und zeigt, wie mit den internen Komponenten interagiert wird.\n\n///\n\nWir können denselben Ansatz auch verwenden, um in einem Exceptionhandler auf den Requestbody zuzugreifen.\n\nAlles, was wir tun müssen, ist, den Request innerhalb eines `try`/`except`-Blocks zu handhaben:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\nWenn eine Exception auftritt, befindet sich die `Request`-Instanz weiterhin im Gültigkeitsbereich, sodass wir den Requestbody lesen und bei der Fehlerbehandlung verwenden können:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## Benutzerdefinierte `APIRoute`-Klasse in einem Router { #custom-apiroute-class-in-a-router }\n\nSie können auch den Parameter `route_class` eines `APIRouter` festlegen:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\nIn diesem Beispiel verwenden die *Pfadoperationen* unter dem `router` die benutzerdefinierte `TimedRoute`-Klasse und haben in der Response einen zusätzlichen `X-Response-Time`-Header mit der Zeit, die zum Generieren der Response benötigt wurde:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/de/docs/how-to/extending-openapi.md",
    "content": "# OpenAPI erweitern { #extending-openapi }\n\nEs gibt einige Fälle, in denen Sie das generierte OpenAPI-Schema ändern müssen.\n\nIn diesem Abschnitt erfahren Sie, wie.\n\n## Der normale Vorgang { #the-normal-process }\n\nDer normale (Standard-)Prozess ist wie folgt.\n\nEine `FastAPI`-Anwendung (Instanz) verfügt über eine `.openapi()`-Methode, von der erwartet wird, dass sie das OpenAPI-Schema zurückgibt.\n\nAls Teil der Erstellung des Anwendungsobjekts wird eine *Pfadoperation* für `/openapi.json` (oder welcher Wert für den Parameter `openapi_url` gesetzt wurde) registriert.\n\nDiese gibt lediglich eine JSON-<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> zurück, mit dem Ergebnis der Methode `.openapi()` der Anwendung.\n\nStandardmäßig überprüft die Methode `.openapi()` die Eigenschaft `.openapi_schema`, um zu sehen, ob diese Inhalt hat, und gibt diesen zurück.\n\nIst das nicht der Fall, wird der Inhalt mithilfe der Hilfsfunktion unter `fastapi.openapi.utils.get_openapi` generiert.\n\nDiese Funktion `get_openapi()` erhält als Parameter:\n\n* `title`: Der OpenAPI-Titel, der in der Dokumentation angezeigt wird.\n* `version`: Die Version Ihrer API, z. B. `2.5.0`.\n* `openapi_version`: Die Version der verwendeten OpenAPI-Spezifikation. Standardmäßig die neueste Version: `3.1.0`.\n* `summary`: Eine kurze Zusammenfassung der API.\n* `description`: Die Beschreibung Ihrer API. Dies kann Markdown enthalten und wird in der Dokumentation angezeigt.\n* `routes`: Eine Liste von Routen, dies sind alle registrierten *Pfadoperationen*. Sie stammen von `app.routes`.\n\n/// info | Info\n\nDer Parameter `summary` ist in OpenAPI 3.1.0 und höher verfügbar und wird von FastAPI 0.99.0 und höher unterstützt.\n\n///\n\n## Überschreiben der Standardeinstellungen { #overriding-the-defaults }\n\nMithilfe der oben genannten Informationen können Sie dieselbe Hilfsfunktion verwenden, um das OpenAPI-Schema zu generieren und jeden benötigten Teil zu überschreiben.\n\nFügen wir beispielsweise [ReDocs OpenAPI-Erweiterung zum Einbinden eines benutzerdefinierten Logos](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo) hinzu.\n\n### Normales **FastAPI** { #normal-fastapi }\n\nSchreiben Sie zunächst wie gewohnt Ihre ganze **FastAPI**-Anwendung:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### Das OpenAPI-Schema generieren { #generate-the-openapi-schema }\n\nVerwenden Sie dann dieselbe Hilfsfunktion, um das OpenAPI-Schema innerhalb einer `custom_openapi()`-Funktion zu generieren:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### Das OpenAPI-Schema ändern { #modify-the-openapi-schema }\n\nJetzt können Sie die ReDoc-Erweiterung hinzufügen und dem `info`-„Objekt“ im OpenAPI-Schema ein benutzerdefiniertes `x-logo` hinzufügen:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### Zwischenspeichern des OpenAPI-Schemas { #cache-the-openapi-schema }\n\nSie können die Eigenschaft `.openapi_schema` als „Cache“ verwenden, um Ihr generiertes Schema zu speichern.\n\nAuf diese Weise muss Ihre Anwendung das Schema nicht jedes Mal generieren, wenn ein Benutzer Ihre API-Dokumentation öffnet.\n\nEs wird nur einmal generiert und dann wird dasselbe zwischengespeicherte Schema für die nächsten <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> verwendet.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### Die Methode überschreiben { #override-the-method }\n\nJetzt können Sie die Methode `.openapi()` durch Ihre neue Funktion ersetzen.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### Es testen { #check-it }\n\nSobald Sie auf [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) gehen, werden Sie sehen, dass Ihr benutzerdefiniertes Logo verwendet wird (in diesem Beispiel das Logo von **FastAPI**):\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/de/docs/how-to/general.md",
    "content": "# Allgemeines – How-To – Rezepte { #general-how-to-recipes }\n\nHier finden Sie mehrere Verweise auf andere Stellen in der Dokumentation, für allgemeine oder häufige Fragen.\n\n## Daten filtern – Sicherheit { #filter-data-security }\n\nUm sicherzustellen, dass Sie nicht mehr Daten zurückgeben, als Sie sollten, lesen Sie die Dokumentation unter [Tutorial – Responsemodell – Rückgabetyp](../tutorial/response-model.md).\n\n## Response-Leistung optimieren – Responsemodell – Rückgabetyp { #optimize-response-performance-response-model-return-type }\n\nUm die Leistung beim Zurückgeben von JSON-Daten zu optimieren, verwenden Sie einen Rückgabetyp oder ein Responsemodell. So übernimmt Pydantic die Serialisierung zu JSON auf der Rust-Seite, ohne den Umweg über Python. Mehr dazu in der Dokumentation unter [Tutorial – Responsemodell – Rückgabetyp](../tutorial/response-model.md).\n\n## Dokumentations-Tags – OpenAPI { #documentation-tags-openapi }\n\nUm Tags zu Ihren *Pfadoperationen* hinzuzufügen und diese in der Oberfläche der Dokumentation zu gruppieren, lesen Sie die Dokumentation unter [Tutorial – Pfadoperation-Konfiguration – Tags](../tutorial/path-operation-configuration.md#tags).\n\n## Zusammenfassung und Beschreibung in der Dokumentation – OpenAPI { #documentation-summary-and-description-openapi }\n\nUm Ihren *Pfadoperationen* eine Zusammenfassung und Beschreibung hinzuzufügen und diese in der Oberfläche der Dokumentation anzuzeigen, lesen Sie die Dokumentation unter [Tutorial – Pfadoperation-Konfiguration – Zusammenfassung und Beschreibung](../tutorial/path-operation-configuration.md#summary-and-description).\n\n## Beschreibung der Response in der Dokumentation – OpenAPI { #documentation-response-description-openapi }\n\nUm die Beschreibung der Response zu definieren, welche in der Oberfläche der Dokumentation angezeigt wird, lesen Sie die Dokumentation unter [Tutorial – Pfadoperation-Konfiguration – Beschreibung der Response](../tutorial/path-operation-configuration.md#response-description).\n\n## *Pfadoperation* in der Dokumentation deprecaten – OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\nUm eine *Pfadoperation* zu <abbr title=\"veraltet, obsolet: Es soll nicht mehr verwendet werden\">deprecaten</abbr> und das in der Oberfläche der Dokumentation anzuzeigen, lesen Sie die Dokumentation unter [Tutorial – Pfadoperation-Konfiguration – Deprecaten](../tutorial/path-operation-configuration.md#deprecate-a-path-operation).\n\n## Daten in etwas JSON-kompatibles konvertieren { #convert-any-data-to-json-compatible }\n\nUm Daten in etwas JSON-kompatibles zu konvertieren, lesen Sie die Dokumentation unter [Tutorial – JSON-kompatibler Encoder](../tutorial/encoder.md).\n\n## OpenAPI-Metadaten – Dokumentation { #openapi-metadata-docs }\n\nUm Metadaten zu Ihrem OpenAPI-Schema hinzuzufügen, einschließlich einer Lizenz, Version, Kontakt, usw., lesen Sie die Dokumentation unter [Tutorial – Metadaten und URLs der Dokumentation](../tutorial/metadata.md).\n\n## Benutzerdefinierte OpenAPI-URL { #openapi-custom-url }\n\nUm die OpenAPI-URL anzupassen (oder zu entfernen), lesen Sie die Dokumentation unter [Tutorial – Metadaten und URLs der Dokumentation](../tutorial/metadata.md#openapi-url).\n\n## URLs der OpenAPI-Dokumentationen { #openapi-docs-urls }\n\nUm die URLs zu aktualisieren, die für die automatisch generierten Dokumentations-Oberflächen verwendet werden, lesen Sie die Dokumentation unter [Tutorial – Metadaten und URLs der Dokumentation](../tutorial/metadata.md#docs-urls).\n"
  },
  {
    "path": "docs/de/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\nDa **FastAPI** auf dem **ASGI**-Standard basiert, ist es sehr einfach, jede **GraphQL**-Bibliothek zu integrieren, die auch mit ASGI kompatibel ist.\n\nSie können normale FastAPI-*Pfadoperationen* mit GraphQL in derselben Anwendung kombinieren.\n\n/// tip | Tipp\n\n**GraphQL** löst einige sehr spezifische Anwendungsfälle.\n\nEs hat **Vorteile** und **Nachteile** im Vergleich zu gängigen **Web-APIs**.\n\nStellen Sie sicher, dass Sie prüfen, ob die **Vorteile** für Ihren Anwendungsfall die **Nachteile** ausgleichen. 🤓\n\n///\n\n## GraphQL-Bibliotheken { #graphql-libraries }\n\nHier sind einige der **GraphQL**-Bibliotheken, die **ASGI**-Unterstützung haben. Sie könnten sie mit **FastAPI** verwenden:\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * Mit [Dokumentation für FastAPI](https://strawberry.rocks/docs/integrations/fastapi)\n* [Ariadne](https://ariadnegraphql.org/)\n    * Mit [Dokumentation für FastAPI](https://ariadnegraphql.org/docs/fastapi-integration)\n* [Tartiflette](https://tartiflette.io/)\n    * Mit [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) für ASGI-Integration\n* [Graphene](https://graphene-python.org/)\n    * Mit [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)\n\n## GraphQL mit Strawberry { #graphql-with-strawberry }\n\nWenn Sie mit **GraphQL** arbeiten möchten oder müssen, ist [**Strawberry**](https://strawberry.rocks/) die **empfohlene** Bibliothek, da deren Design **FastAPIs** Design am nächsten kommt und alles auf **Typannotationen** basiert.\n\nAbhängig von Ihrem Anwendungsfall könnten Sie eine andere Bibliothek vorziehen, aber wenn Sie mich fragen würden, würde ich Ihnen wahrscheinlich empfehlen, **Strawberry** auszuprobieren.\n\nHier ist eine kleine Vorschau, wie Sie Strawberry mit FastAPI integrieren können:\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\nWeitere Informationen zu Strawberry finden Sie in der [Strawberry-Dokumentation](https://strawberry.rocks/).\n\nUnd auch in der Dokumentation zu [Strawberry mit FastAPI](https://strawberry.rocks/docs/integrations/fastapi).\n\n## Ältere `GraphQLApp` von Starlette { #older-graphqlapp-from-starlette }\n\nFrühere Versionen von Starlette enthielten eine `GraphQLApp`-Klasse zur Integration mit [Graphene](https://graphene-python.org/).\n\nDas wurde von Starlette <abbr title=\"veraltet, obsolet: Es soll nicht mehr verwendet werden\">deprecatet</abbr>, aber wenn Sie Code haben, der das verwendet, können Sie einfach zu [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3) **migrieren**, das denselben Anwendungsfall abdeckt und eine **fast identische Schnittstelle** hat.\n\n/// tip | Tipp\n\nWenn Sie GraphQL benötigen, würde ich Ihnen trotzdem empfehlen, sich [Strawberry](https://strawberry.rocks/) anzuschauen, da es auf Typannotationen basiert, statt auf benutzerdefinierten Klassen und Typen.\n\n///\n\n## Mehr darüber lernen { #learn-more }\n\nWeitere Informationen zu **GraphQL** finden Sie in der [offiziellen GraphQL-Dokumentation](https://graphql.org/).\n\nSie können auch mehr über jede der oben beschriebenen Bibliotheken in den jeweiligen Links lesen.\n"
  },
  {
    "path": "docs/de/docs/how-to/index.md",
    "content": "# How-To – Rezepte { #how-to-recipes }\n\nHier finden Sie verschiedene Rezepte und „How-To“-Anleitungen zu **verschiedenen Themen**.\n\nDie meisten dieser Ideen sind mehr oder weniger **unabhängig**, und in den meisten Fällen müssen Sie diese nur studieren, wenn sie direkt auf **Ihr Projekt** anwendbar sind.\n\nWenn etwas für Ihr Projekt interessant und nützlich erscheint, lesen Sie es, andernfalls überspringen Sie es einfach.\n\n/// tip | Tipp\n\nWenn Sie strukturiert **FastAPI lernen** möchten (empfohlen), lesen Sie stattdessen Kapitel für Kapitel das [Tutorial – Benutzerhandbuch](../tutorial/index.md).\n\n///\n"
  },
  {
    "path": "docs/de/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# Von Pydantic v1 zu Pydantic v2 migrieren { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\nWenn Sie eine ältere FastAPI-App haben, nutzen Sie möglicherweise Pydantic Version 1.\n\nFastAPI Version 0.100.0 unterstützte sowohl Pydantic v1 als auch v2. Es verwendete, was auch immer Sie installiert hatten.\n\nFastAPI Version 0.119.0 führte eine teilweise Unterstützung für Pydantic v1 innerhalb von Pydantic v2 (als `pydantic.v1`) ein, um die Migration zu v2 zu erleichtern.\n\nFastAPI 0.126.0 entfernte die Unterstützung für Pydantic v1, während `pydantic.v1` noch eine Weile unterstützt wurde.\n\n/// warning | Achtung\n\nDas Pydantic-Team hat die Unterstützung für Pydantic v1 in den neuesten Python-Versionen eingestellt, beginnend mit **Python 3.14**.\n\nDies schließt `pydantic.v1` ein, das unter Python 3.14 und höher nicht mehr unterstützt wird.\n\nWenn Sie die neuesten Features von Python nutzen möchten, müssen Sie sicherstellen, dass Sie Pydantic v2 verwenden.\n\n///\n\nWenn Sie eine ältere FastAPI-App mit Pydantic v1 haben, zeige ich Ihnen hier, wie Sie sie zu Pydantic v2 migrieren, und die **Features in FastAPI 0.119.0**, die Ihnen bei einer schrittweisen Migration helfen.\n\n## Offizieller Leitfaden { #official-guide }\n\nPydantic hat einen offiziellen [Migrationsleitfaden](https://docs.pydantic.dev/latest/migration/) von v1 zu v2.\n\nEr enthält auch, was sich geändert hat, wie Validierungen nun korrekter und strikter sind, mögliche Stolpersteine, usw.\n\nSie können ihn lesen, um besser zu verstehen, was sich geändert hat.\n\n## Tests { #tests }\n\nStellen Sie sicher, dass Sie [Tests](../tutorial/testing.md) für Ihre App haben und diese in Continuous Integration (CI) ausführen.\n\nAuf diese Weise können Sie das Update durchführen und sicherstellen, dass weiterhin alles wie erwartet funktioniert.\n\n## `bump-pydantic` { #bump-pydantic }\n\nIn vielen Fällen, wenn Sie reguläre Pydantic-Modelle ohne Anpassungen verwenden, können Sie den Großteil des Prozesses der Migration von Pydantic v1 auf Pydantic v2 automatisieren.\n\nSie können [`bump-pydantic`](https://github.com/pydantic/bump-pydantic) vom selben Pydantic-Team verwenden.\n\nDieses Tool hilft Ihnen, den Großteil des zu ändernden Codes automatisch anzupassen.\n\nDanach können Sie die Tests ausführen und prüfen, ob alles funktioniert. Falls ja, sind Sie fertig. 😎\n\n## Pydantic v1 in v2 { #pydantic-v1-in-v2 }\n\nPydantic v2 enthält alles aus Pydantic v1 als Untermodul `pydantic.v1`. Dies wird aber in Versionen oberhalb von Python 3.13 nicht mehr unterstützt.\n\nDas bedeutet, Sie können die neueste Version von Pydantic v2 installieren und die alten Pydantic‑v1‑Komponenten aus diesem Untermodul importieren und verwenden, als hätten Sie das alte Pydantic v1 installiert.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### FastAPI-Unterstützung für Pydantic v1 in v2 { #fastapi-support-for-pydantic-v1-in-v2 }\n\nSeit FastAPI 0.119.0 gibt es außerdem eine teilweise Unterstützung für Pydantic v1 innerhalb von Pydantic v2, um die Migration auf v2 zu erleichtern.\n\nSie könnten also Pydantic auf die neueste Version 2 aktualisieren und die Importe so ändern, dass das Untermodul `pydantic.v1` verwendet wird, und in vielen Fällen würde es einfach funktionieren.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning | Achtung\n\nBeachten Sie, dass, da das Pydantic‑Team Pydantic v1 in neueren Python‑Versionen nicht mehr unterstützt, beginnend mit Python 3.14, auch die Verwendung von `pydantic.v1` unter Python 3.14 und höher nicht unterstützt wird.\n\n///\n\n### Pydantic v1 und v2 in derselben App { #pydantic-v1-and-v2-on-the-same-app }\n\nEs wird von Pydantic **nicht unterstützt**, dass ein Pydantic‑v2‑Modell Felder hat, die als Pydantic‑v1‑Modelle definiert sind, und umgekehrt.\n\n```mermaid\ngraph TB\n    subgraph \"❌ Nicht unterstützt\"\n        direction TB\n        subgraph V2[\"Pydantic-v2-Modell\"]\n            V1Field[\"Pydantic-v1-Modell\"]\n        end\n        subgraph V1[\"Pydantic-v1-Modell\"]\n            V2Field[\"Pydantic-v2-Modell\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n... aber Sie können getrennte Modelle, die Pydantic v1 bzw. v2 nutzen, in derselben App verwenden.\n\n```mermaid\ngraph TB\n    subgraph \"✅ Unterstützt\"\n        direction TB\n        subgraph V2[\"Pydantic-v2-Modell\"]\n            V2Field[\"Pydantic-v2-Modell\"]\n        end\n        subgraph V1[\"Pydantic-v1-Modell\"]\n            V1Field[\"Pydantic-v1-Modell\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\nIn einigen Fällen ist es sogar möglich, sowohl Pydantic‑v1‑ als auch Pydantic‑v2‑Modelle in derselben **Pfadoperation** Ihrer FastAPI‑App zu verwenden:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\nIm obigen Beispiel ist das Eingabemodell ein Pydantic‑v1‑Modell, und das Ausgabemodell (definiert in `response_model=ItemV2`) ist ein Pydantic‑v2‑Modell.\n\n### Pydantic v1 Parameter { #pydantic-v1-parameters }\n\nWenn Sie einige der FastAPI-spezifischen Tools für Parameter wie `Body`, `Query`, `Form`, usw. zusammen mit Pydantic‑v1‑Modellen verwenden müssen, können Sie die aus `fastapi.temp_pydantic_v1_params` importieren, während Sie die Migration zu Pydantic v2 abschließen:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### In Schritten migrieren { #migrate-in-steps }\n\n/// tip | Tipp\n\nProbieren Sie zuerst `bump-pydantic` aus. Wenn Ihre Tests erfolgreich sind und das funktioniert, sind Sie mit einem einzigen Befehl fertig. ✨\n\n///\n\nWenn `bump-pydantic` für Ihren Anwendungsfall nicht funktioniert, können Sie die Unterstützung für Pydantic‑v1‑ und Pydantic‑v2‑Modelle in derselben App nutzen, um die Migration zu Pydantic v2 schrittweise durchzuführen.\n\nSie könnten zuerst Pydantic auf die neueste Version 2 aktualisieren und die Importe so ändern, dass für all Ihre Modelle `pydantic.v1` verwendet wird.\n\nAnschließend können Sie beginnen, Ihre Modelle gruppenweise von Pydantic v1 auf v2 zu migrieren – in kleinen, schrittweisen Etappen. 🚶\n"
  },
  {
    "path": "docs/de/docs/how-to/separate-openapi-schemas.md",
    "content": "# Separate OpenAPI-Schemas für Eingabe und Ausgabe oder nicht { #separate-openapi-schemas-for-input-and-output-or-not }\n\nSeit der Veröffentlichung von **Pydantic v2** ist die generierte OpenAPI etwas genauer und **korrekter** als zuvor. 😎\n\nTatsächlich gibt es in einigen Fällen sogar **zwei JSON-Schemas** in OpenAPI für dasselbe Pydantic-Modell, für Eingabe und Ausgabe, je nachdem, ob sie **Defaultwerte** haben.\n\nSehen wir uns an, wie das funktioniert und wie Sie es bei Bedarf ändern können.\n\n## Pydantic-Modelle für Eingabe und Ausgabe { #pydantic-models-for-input-and-output }\n\nNehmen wir an, Sie haben ein Pydantic-Modell mit Defaultwerten wie dieses:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### Modell für Eingabe { #model-for-input }\n\nWenn Sie dieses Modell wie hier als Eingabe verwenden:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n... dann ist das Feld `description` **nicht erforderlich**. Weil es den Defaultwert `None` hat.\n\n### Eingabemodell in der Dokumentation { #input-model-in-docs }\n\nSie können überprüfen, dass das Feld `description` in der Dokumentation kein **rotes Sternchen** enthält, es ist nicht als erforderlich markiert:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### Modell für die Ausgabe { #model-for-output }\n\nWenn Sie jedoch dasselbe Modell als Ausgabe verwenden, wie hier:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n... dann, weil `description` einen Defaultwert hat, wird es, wenn Sie für dieses Feld **nichts zurückgeben**, immer noch diesen **Defaultwert** haben.\n\n### Modell für Ausgabe-Responsedaten { #model-for-output-response-data }\n\nWenn Sie mit der Dokumentation interagieren und die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> überprüfen, enthält die JSON-Response den Defaultwert (`null`), obwohl der Code nichts in eines der `description`-Felder geschrieben hat:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\nDas bedeutet, dass es **immer einen Wert** hat, der Wert kann jedoch manchmal `None` sein (oder `null` in JSON).\n\nDas bedeutet, dass Clients, die Ihre API verwenden, nicht prüfen müssen, ob der Wert vorhanden ist oder nicht. Sie können davon ausgehen, dass das Feld immer vorhanden ist. In einigen Fällen hat es jedoch nur den Defaultwert `None`.\n\nUm dies in OpenAPI zu kennzeichnen, markieren Sie dieses Feld als **erforderlich**, da es immer vorhanden sein wird.\n\nAus diesem Grund kann das JSON-Schema für ein Modell unterschiedlich sein, je nachdem, ob es für **Eingabe oder Ausgabe** verwendet wird:\n\n* für die **Eingabe** ist `description` **nicht erforderlich**\n* für die **Ausgabe** ist es **erforderlich** (und möglicherweise `None` oder, in JSON-Begriffen, `null`)\n\n### Ausgabemodell in der Dokumentation { #model-for-output-in-docs }\n\nSie können das Ausgabemodell auch in der Dokumentation überprüfen. **Sowohl** `name` **als auch** `description` sind mit einem **roten Sternchen** als **erforderlich** markiert:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### Eingabe- und Ausgabemodell in der Dokumentation { #model-for-input-and-output-in-docs }\n\nUnd wenn Sie alle verfügbaren Schemas (JSON-Schemas) in OpenAPI überprüfen, werden Sie feststellen, dass es zwei gibt, ein `Item-Input` und ein `Item-Output`.\n\nFür `Item-Input` ist `description` **nicht erforderlich**, es hat kein rotes Sternchen.\n\nAber für `Item-Output` ist `description` **erforderlich**, es hat ein rotes Sternchen.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\nMit dieser Funktion von **Pydantic v2** ist Ihre API-Dokumentation **präziser**, und wenn Sie über automatisch generierte Clients und SDKs verfügen, sind diese auch präziser, mit einer besseren **Entwicklererfahrung** und Konsistenz. 🎉\n\n## Schemas nicht trennen { #do-not-separate-schemas }\n\nNun gibt es einige Fälle, in denen Sie möglicherweise **dasselbe Schema für Eingabe und Ausgabe** haben möchten.\n\nDer Hauptanwendungsfall hierfür besteht wahrscheinlich darin, dass Sie das mal tun möchten, wenn Sie bereits über einige automatisch generierte Client-Codes/SDKs verfügen und im Moment nicht alle automatisch generierten Client-Codes/SDKs aktualisieren möchten, möglicherweise später, aber nicht jetzt.\n\nIn diesem Fall können Sie diese Funktion in **FastAPI** mit dem Parameter `separate_input_output_schemas=False` deaktivieren.\n\n/// info | Info\n\nUnterstützung für `separate_input_output_schemas` wurde in FastAPI `0.102.0` hinzugefügt. 🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### Gleiches Schema für Eingabe- und Ausgabemodelle in der Dokumentation { #same-schema-for-input-and-output-models-in-docs }\n\nUnd jetzt wird es ein einziges Schema für die Eingabe und Ausgabe des Modells geben, nur `Item`, und es wird `description` als **nicht erforderlich** kennzeichnen:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/de/docs/how-to/testing-database.md",
    "content": "# Eine Datenbank testen { #testing-a-database }\n\nSie können sich über Datenbanken, SQL und SQLModel in der [SQLModel-Dokumentation](https://sqlmodel.tiangolo.com/) informieren. 🤓\n\nEs gibt ein kurzes [Tutorial zur Verwendung von SQLModel mit FastAPI](https://sqlmodel.tiangolo.com/tutorial/fastapi/). ✨\n\nDieses Tutorial enthält einen Abschnitt über das [Testen von SQL-Datenbanken](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/). 😎\n"
  },
  {
    "path": "docs/de/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/de\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>FastAPI-Framework, hohe Performanz, leicht zu lernen, schnell zu entwickeln, produktionsreif</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Testabdeckung\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package-Version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Unterstützte Python-Versionen\">\n</a>\n</p>\n\n---\n\n**Dokumentation**: [https://fastapi.tiangolo.com/de](https://fastapi.tiangolo.com/de)\n\n**Quellcode**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI ist ein modernes, schnelles (hoch performantes) Webframework zur Erstellung von APIs mit Python auf Basis von Standard-Python-Typhinweisen.\n\nSeine Schlüssel-Merkmale sind:\n\n* **Schnell**: Sehr hohe Performanz, auf Augenhöhe mit **NodeJS** und **Go** (dank Starlette und Pydantic). [Eines der schnellsten verfügbaren Python-Frameworks](#performance).\n* **Schnell zu entwickeln**: Erhöhen Sie die Geschwindigkeit bei der Entwicklung von Features um etwa 200 % bis 300 %. *\n* **Weniger Bugs**: Verringern Sie die von Menschen (Entwicklern) verursachten Fehler um etwa 40 %. *\n* **Intuitiv**: Hervorragende Editor-Unterstützung. <dfn title=\"auch bekannt als Auto-Complete, Autovervollständigung, IntelliSense\">Code-Vervollständigung</dfn> überall. Weniger Zeit mit Debuggen verbringen.\n* **Einfach**: So konzipiert, dass es einfach zu benutzen und zu erlernen ist. Weniger Zeit mit dem Lesen von Dokumentation verbringen.\n* **Kurz**: Minimieren Sie die Verdoppelung von Code. Mehrere Features aus jeder Parameterdeklaration. Weniger Bugs.\n* **Robust**: Erhalten Sie produktionsreifen Code. Mit automatischer, interaktiver Dokumentation.\n* **Standards-basiert**: Basierend auf (und vollständig kompatibel mit) den offenen Standards für APIs: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (früher bekannt als Swagger) und [JSON Schema](https://json-schema.org/).\n\n<small>* Schätzung basierend auf Tests, die von einem internen Entwicklungsteam durchgeführt wurden, das Produktionsanwendungen erstellt.</small>\n\n## Sponsoren { #sponsors }\n\n<!-- sponsors -->\n\n### Keystone-Sponsor { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### Gold- und Silber-Sponsoren { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[Andere Sponsoren](https://fastapi.tiangolo.com/de/fastapi-people/#sponsors)\n\n## Meinungen { #opinions }\n\n„_[...] Ich verwende **FastAPI** heutzutage sehr oft. [...] Ich habe tatsächlich vor, es für alle **ML-Services meines Teams bei Microsoft** zu verwenden. Einige davon werden in das Kernprodukt **Windows** und einige **Office**-Produkte integriert._“\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan – <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(Ref.)</small></a></div>\n\n---\n\n„_Wir haben die **FastAPI**-Bibliothek übernommen, um einen **REST**-Server zu erstellen, der für **Vorhersagen** abgefragt werden kann. [für Ludwig]_“\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, und Sai Sumanth Miryala – <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(Ref.)</small></a></div>\n\n---\n\n„_**Netflix** freut sich, die Open-Source-Veröffentlichung unseres **Krisenmanagement**-Orchestrierung-Frameworks bekannt zu geben: **Dispatch**! [erstellt mit **FastAPI**]_“\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen – <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(Ref.)</small></a></div>\n\n---\n\n„_Ich bin hellauf begeistert von **FastAPI**. Es macht so viel Spaß!_“\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken – <strong>[Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855) Podcast-Host</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(Ref.)</small></a></div>\n\n---\n\n„_Ehrlich, was Du gebaut hast, sieht super solide und poliert aus. In vielerlei Hinsicht ist es so, wie ich **Hug** haben wollte – es ist wirklich inspirierend, jemanden so etwas bauen zu sehen._“\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley – <strong>[Hug](https://github.com/hugapi/hug)-Autor</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(Ref.)</small></a></div>\n\n---\n\n„_Wenn Sie ein **modernes Framework** zum Erstellen von REST-APIs erlernen möchten, schauen Sie sich **FastAPI** an. [...] Es ist schnell, einfach zu verwenden und leicht zu lernen [...]_“\n\n„_Wir haben zu **FastAPI** für unsere **APIs** gewechselt [...] Ich denke, es wird Ihnen gefallen [...]_“\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani – Matthew Honnibal – <strong>[Explosion AI](https://explosion.ai)-Gründer – [spaCy](https://spacy.io)-Autoren</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(Ref.)</small></a> – <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(Ref.)</small></a></div>\n\n---\n\n„_Falls irgendjemand eine Produktions-Python-API erstellen möchte, kann ich **FastAPI** wärmstens empfehlen. Es ist **wunderschön konzipiert**, **einfach zu verwenden** und **hoch skalierbar**; es ist zu einer **Schlüsselkomponente** unserer API-First-Entwicklungsstrategie geworden und treibt viele Automatisierungen und Services an, wie etwa unseren Virtual TAC Engineer._“\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury – <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(Ref.)</small></a></div>\n\n---\n\n## FastAPI Mini-Dokumentarfilm { #fastapi-mini-documentary }\n\nEs gibt einen [FastAPI-Mini-Dokumentarfilm](https://www.youtube.com/watch?v=mpR8ngthqiE), veröffentlicht Ende 2025, Sie können ihn online ansehen:\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini-Dokumentarfilm\"></a>\n\n## **Typer**, das FastAPI der CLIs { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\nWenn Sie eine <abbr title=\"Command Line Interface - Kommandozeilen-Schnittstelle\">CLI</abbr>-Anwendung für das Terminal erstellen, anstelle einer Web-API, schauen Sie sich [**Typer**](https://typer.tiangolo.com/) an.\n\n**Typer** ist die kleine Schwester von FastAPI. Und es soll das **FastAPI der CLIs** sein. ⌨️ 🚀\n\n## Anforderungen { #requirements }\n\nFastAPI steht auf den Schultern von Giganten:\n\n* [Starlette](https://www.starlette.dev/) für die Webanteile.\n* [Pydantic](https://docs.pydantic.dev/) für die Datenanteile.\n\n## Installation { #installation }\n\nErstellen und aktivieren Sie eine [virtuelle Umgebung](https://fastapi.tiangolo.com/de/virtual-environments/) und installieren Sie dann FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Hinweis**: Stellen Sie sicher, dass Sie `\"fastapi[standard]\"` in Anführungszeichen setzen, damit es in allen Terminals funktioniert.\n\n## Beispiel { #example }\n\n### Erstellung { #create-it }\n\nErstellen Sie eine Datei `main.py` mit:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>Oder verwenden Sie <code>async def</code> ...</summary>\n\nWenn Ihr Code `async` / `await` verwendet, benutzen Sie `async def`:\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Hinweis**:\n\nWenn Sie das nicht kennen, schauen Sie sich den Abschnitt _„In Eile?“_ über [`async` und `await` in der Dokumentation](https://fastapi.tiangolo.com/de/async/#in-a-hurry) an.\n\n</details>\n\n### Starten { #run-it }\n\nStarten Sie den Server mit:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary>Über den Befehl <code>fastapi dev</code> ...</summary>\n\nDer Befehl `fastapi dev` liest Ihre `main.py`-Datei, erkennt die **FastAPI**-App darin und startet einen Server mit [Uvicorn](https://www.uvicorn.dev).\n\nStandardmäßig wird `fastapi dev` mit aktiviertem Auto-Reload für die lokale Entwicklung gestartet.\n\nSie können mehr darüber in der [FastAPI CLI Dokumentation](https://fastapi.tiangolo.com/de/fastapi-cli/) lesen.\n\n</details>\n\n### Es testen { #check-it }\n\nÖffnen Sie Ihren Browser unter [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery).\n\nSie sehen die JSON-<abbr title=\"Response - Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> als:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\nSie haben bereits eine API erstellt, welche:\n\n* HTTP-<abbr title=\"Request - Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> auf den _Pfaden_ `/` und `/items/{item_id}` entgegennimmt.\n* Beide _Pfade_ nehmen `GET` <em>Operationen</em> (auch bekannt als HTTP-_Methoden_) entgegen.\n* Der _Pfad_ `/items/{item_id}` hat einen _Pfad-Parameter_ `item_id`, der ein `int` sein sollte.\n* Der _Pfad_ `/items/{item_id}` hat einen optionalen `str`-_Query-Parameter_ `q`.\n\n### Interaktive API-Dokumentation { #interactive-api-docs }\n\nGehen Sie nun auf [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nSie sehen die automatische interaktive API-Dokumentation (bereitgestellt von [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Alternative API-Dokumentation { #alternative-api-docs }\n\nUnd jetzt gehen Sie auf [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nSie sehen die alternative automatische Dokumentation (bereitgestellt von [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Beispielaktualisierung { #example-upgrade }\n\nÄndern Sie jetzt die Datei `main.py`, um den <abbr title=\"Body - Körper, Inhalt: Der eigentliche Inhalt einer Nachricht, nicht die Metadaten\">Body</abbr> eines `PUT`-Requests zu empfangen.\n\nDeklarieren Sie den Body mit Standard-Python-Typen, dank Pydantic.\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\nDer `fastapi dev`-Server sollte automatisch neu laden.\n\n### Interaktive API-Dokumentation aktualisieren { #interactive-api-docs-upgrade }\n\nGehen Sie jetzt auf [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n* Die interaktive API-Dokumentation wird automatisch aktualisiert, einschließlich des neuen Bodys:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Klicken Sie auf den Button „Try it out“, damit können Sie die Parameter ausfüllen und direkt mit der API interagieren:\n\n![Swagger UI Interaktion](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* Klicken Sie dann auf den Button „Execute“, die Benutzeroberfläche wird mit Ihrer API kommunizieren, die Parameter senden, die Ergebnisse erhalten und sie auf dem Bildschirm anzeigen:\n\n![Swagger UI Interaktion](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### Alternative API-Dokumentation aktualisieren { #alternative-api-docs-upgrade }\n\nUnd jetzt gehen Sie auf [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\n* Die alternative Dokumentation wird ebenfalls den neuen Query-Parameter und Body widerspiegeln:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Zusammenfassung { #recap }\n\nZusammengefasst deklarieren Sie **einmal** die Typen von Parametern, Body, usw. als Funktionsparameter.\n\nDas machen Sie mit modernen Standard-Python-Typen.\n\nSie müssen keine neue Syntax, Methoden oder Klassen einer bestimmten Bibliothek usw. lernen.\n\nNur Standard-**Python**.\n\nZum Beispiel für ein `int`:\n\n```Python\nitem_id: int\n```\n\noder für ein komplexeres `Item`-Modell:\n\n```Python\nitem: Item\n```\n\n... und mit dieser einen Deklaration erhalten Sie:\n\n* Editor-Unterstützung, einschließlich:\n    * Vervollständigung.\n    * Typprüfungen.\n* Validierung von Daten:\n    * Automatische und eindeutige Fehler, wenn die Daten ungültig sind.\n    * Validierung sogar für tief verschachtelte JSON-Objekte.\n* <dfn title=\"auch bekannt als: Serialisierung, Parsen, Marshalling\">Konvertierung</dfn> von Eingabedaten: Aus dem Netzwerk kommend, zu Python-Daten und -Typen. Lesen von:\n    * JSON.\n    * Pfad-Parametern.\n    * Query-Parametern.\n    * Cookies.\n    * Headern.\n    * Formularen.\n    * Dateien.\n* <dfn title=\"auch bekannt als: Serialisierung, Parsen, Marshalling\">Konvertierung</dfn> von Ausgabedaten: Konvertierung von Python-Daten und -Typen zu Netzwerkdaten (als JSON):\n    * Konvertieren von Python-Typen (`str`, `int`, `float`, `bool`, `list`, usw.).\n    * `datetime`-Objekte.\n    * `UUID`-Objekte.\n    * Datenbankmodelle.\n    * ... und viele mehr.\n* Automatische interaktive API-Dokumentation, einschließlich zwei alternativer Benutzeroberflächen:\n    * Swagger UI.\n    * ReDoc.\n\n---\n\nUm auf das vorherige Codebeispiel zurückzukommen, **FastAPI** wird:\n\n* Validieren, dass es eine `item_id` im Pfad für `GET`- und `PUT`-Requests gibt.\n* Validieren, ob die `item_id` vom Typ `int` für `GET`- und `PUT`-Requests ist.\n    * Falls nicht, sieht der Client einen hilfreichen, klaren Fehler.\n* Prüfen, ob es einen optionalen Query-Parameter namens `q` (wie in `http://127.0.0.1:8000/items/foo?q=somequery`) für `GET`-Requests gibt.\n    * Da der `q`-Parameter mit `= None` deklariert ist, ist er optional.\n    * Ohne das `None` wäre er erforderlich (wie der Body im Fall von `PUT`).\n* Bei `PUT`-Requests an `/items/{item_id}` den Body als JSON lesen:\n    * Prüfen, ob er ein erforderliches Attribut `name` hat, das ein `str` sein muss.\n    * Prüfen, ob er ein erforderliches Attribut `price` hat, das ein `float` sein muss.\n    * Prüfen, ob er ein optionales Attribut `is_offer` hat, das ein `bool` sein muss, falls vorhanden.\n    * All dies würde auch für tief verschachtelte JSON-Objekte funktionieren.\n* Automatisch von und nach JSON konvertieren.\n* Alles mit OpenAPI dokumentieren, welches verwendet werden kann von:\n    * Interaktiven Dokumentationssystemen.\n    * Automatisch Client-Code generierenden Systemen für viele Sprachen.\n* Zwei interaktive Dokumentations-Weboberflächen direkt bereitstellen.\n\n---\n\nWir haben nur an der Oberfläche gekratzt, aber Sie bekommen schon eine Vorstellung davon, wie das Ganze funktioniert.\n\nVersuchen Sie, diese Zeile zu ändern:\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n... von:\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n... zu:\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n... und sehen Sie, wie Ihr Editor die Attribute automatisch vervollständigt und ihre Typen kennt:\n\n![Editor Unterstützung](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\nFür ein vollständigeres Beispiel, mit weiteren Funktionen, siehe das <a href=\"https://fastapi.tiangolo.com/de/tutorial/\">Tutorial – Benutzerhandbuch</a>.\n\n**Spoiler-Alarm**: Das Tutorial – Benutzerhandbuch enthält:\n\n* Deklaration von **Parametern** von anderen verschiedenen Stellen wie: **Header**, **Cookies**, **Formularfelder** und **Dateien**.\n* Wie man **Validierungs-Constraints** wie `maximum_length` oder `regex` setzt.\n* Ein sehr leistungsfähiges und einfach zu bedienendes System für **<dfn title=\"auch bekannt als Komponenten, Ressourcen, Provider, Services, Injectables\">Dependency Injection</dfn>**.\n* Sicherheit und Authentifizierung, einschließlich Unterstützung für **OAuth2** mit **JWT-Tokens** und **HTTP Basic** Authentifizierung.\n* Fortgeschrittenere (aber ebenso einfache) Techniken zur Deklaration **tief verschachtelter JSON-Modelle** (dank Pydantic).\n* **GraphQL**-Integration mit [Strawberry](https://strawberry.rocks) und anderen Bibliotheken.\n* Viele zusätzliche Features (dank Starlette) wie:\n    * **WebSockets**\n    * extrem einfache Tests auf Basis von HTTPX und `pytest`\n    * **CORS**\n    * **Cookie-Sessions**\n    * ... und mehr.\n\n### Ihre App deployen (optional) { #deploy-your-app-optional }\n\nOptional können Sie Ihre FastAPI-App in die [FastAPI Cloud](https://fastapicloud.com) deployen, gehen Sie und treten Sie der Warteliste bei, falls noch nicht geschehen. 🚀\n\nWenn Sie bereits ein **FastAPI Cloud**-Konto haben (wir haben Sie von der Warteliste eingeladen 😉), können Sie Ihre Anwendung mit einem einzigen Befehl deployen.\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nDas war’s! Jetzt können Sie unter dieser URL auf Ihre App zugreifen. ✨\n\n#### Über FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** wird vom selben Autor und Team hinter **FastAPI** entwickelt.\n\nEs vereinfacht den Prozess des **Erstellens**, **Deployens** und **Zugreifens** auf eine API mit minimalem Aufwand.\n\nEs bringt die gleiche **Developer-Experience** beim Erstellen von Apps mit FastAPI auch zum **Deployment** in der Cloud. 🎉\n\nFastAPI Cloud ist der Hauptsponsor und Finanzierer der *FastAPI and friends* Open-Source-Projekte. ✨\n\n#### Bei anderen Cloudanbietern deployen { #deploy-to-other-cloud-providers }\n\nFastAPI ist Open Source und basiert auf Standards. Sie können FastAPI-Apps bei jedem Cloudanbieter Ihrer Wahl deployen.\n\nFolgen Sie den Anleitungen Ihres Cloudanbieters, um FastAPI-Apps dort bereitzustellen. 🤓\n\n## Performanz { #performance }\n\nUnabhängige TechEmpower-Benchmarks zeigen **FastAPI**-Anwendungen, die unter Uvicorn laufen, als [eines der schnellsten verfügbaren Python-Frameworks](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), nur hinter Starlette und Uvicorn selbst (intern von FastAPI verwendet). (*)\n\nUm mehr darüber zu erfahren, siehe den Abschnitt [Benchmarks](https://fastapi.tiangolo.com/de/benchmarks/).\n\n## Abhängigkeiten { #dependencies }\n\nFastAPI hängt von Pydantic und Starlette ab.\n\n### `standard`-Abhängigkeiten { #standard-dependencies }\n\nWenn Sie FastAPI mit `pip install \"fastapi[standard]\"` installieren, kommt es mit der `standard`-Gruppe optionaler Abhängigkeiten:\n\nVerwendet von Pydantic:\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) – für E-Mail-Validierung.\n\nVerwendet von Starlette:\n\n* [`httpx`](https://www.python-httpx.org) – erforderlich, wenn Sie den `TestClient` verwenden möchten.\n* [`jinja2`](https://jinja.palletsprojects.com) – erforderlich, wenn Sie die Default-Template-Konfiguration verwenden möchten.\n* [`python-multipart`](https://github.com/Kludex/python-multipart) – erforderlich, wenn Sie Formulare mittels `request.form()` <dfn title=\"Konvertieren des Strings, der aus einem HTTP-Request stammt, nach Python-Daten\">„parsen“</dfn> möchten.\n\nVerwendet von FastAPI:\n\n* [`uvicorn`](https://www.uvicorn.dev) – für den Server, der Ihre Anwendung lädt und bereitstellt. Dies umfasst `uvicorn[standard]`, das einige Abhängigkeiten (z. B. `uvloop`) beinhaltet, die für eine Bereitstellung mit hoher Performanz benötigt werden.\n* `fastapi-cli[standard]` – um den `fastapi`-Befehl bereitzustellen.\n    * Dies beinhaltet `fastapi-cloud-cli`, das es Ihnen ermöglicht, Ihre FastAPI-Anwendung auf [FastAPI Cloud](https://fastapicloud.com) bereitzustellen.\n\n### Ohne `standard`-Abhängigkeiten { #without-standard-dependencies }\n\nWenn Sie die `standard` optionalen Abhängigkeiten nicht einschließen möchten, können Sie mit `pip install fastapi` statt `pip install \"fastapi[standard]\"` installieren.\n\n### Ohne `fastapi-cloud-cli` { #without-fastapi-cloud-cli }\n\nWenn Sie FastAPI mit den Standardabhängigkeiten, aber ohne das `fastapi-cloud-cli` installieren möchten, können Sie mit `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"` installieren.\n\n### Zusätzliche optionale Abhängigkeiten { #additional-optional-dependencies }\n\nEs gibt einige zusätzliche Abhängigkeiten, die Sie installieren möchten.\n\nZusätzliche optionale Pydantic-Abhängigkeiten:\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) – für die Verwaltung von Einstellungen.\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) – für zusätzliche Typen zur Verwendung mit Pydantic.\n\nZusätzliche optionale FastAPI-Abhängigkeiten:\n\n* [`orjson`](https://github.com/ijl/orjson) – erforderlich, wenn Sie `ORJSONResponse` verwenden möchten.\n* [`ujson`](https://github.com/esnme/ultrajson) – erforderlich, wenn Sie `UJSONResponse` verwenden möchten.\n\n## Lizenz { #license }\n\nDieses Projekt ist unter den Bedingungen der MIT-Lizenz lizenziert.\n"
  },
  {
    "path": "docs/de/docs/learn/index.md",
    "content": "# Lernen { #learn }\n\nHier sind die einführenden Abschnitte und Tutorials, um **FastAPI** zu lernen.\n\nSie könnten dies als **Buch**, als **Kurs**, als **offizielle** und empfohlene Methode zum Erlernen von FastAPI betrachten. 😎\n"
  },
  {
    "path": "docs/de/docs/project-generation.md",
    "content": "# Full Stack FastAPI Template { #full-stack-fastapi-template }\n\nVorlagen, die normalerweise mit einem bestimmten Setup geliefert werden, sind so konzipiert, dass sie flexibel und anpassbar sind. Dies ermöglicht es Ihnen, sie zu ändern und an die Anforderungen Ihres Projekts anzupassen und sie somit zu einem hervorragenden Ausgangspunkt zu machen. 🏁\n\nSie können diese Vorlage verwenden, um loszulegen, da sie bereits vieles der anfänglichen Einrichtung, Sicherheit, Datenbank und einige API-Endpunkte für Sie eingerichtet hat.\n\nGitHub-Repository: [Full Stack FastAPI Template](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## Full Stack FastAPI Template – Technologiestack und Funktionen { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/de) für die Python-Backend-API.\n  - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) für die Interaktion mit der Python-SQL-Datenbank (ORM).\n  - 🔍 [Pydantic](https://docs.pydantic.dev), verwendet von FastAPI, für die Datenvalidierung und das Einstellungsmanagement.\n  - 💾 [PostgreSQL](https://www.postgresql.org) als SQL-Datenbank.\n- 🚀 [React](https://react.dev) für das Frontend.\n  - 💃 Verwendung von TypeScript, Hooks, Vite und anderen Teilen eines modernen Frontend-Stacks.\n  - 🎨 [Tailwind CSS](https://tailwindcss.com) und [shadcn/ui](https://ui.shadcn.com) für die Frontend-Komponenten.\n  - 🤖 Ein automatisch generierter Frontend-Client.\n  - 🧪 [Playwright](https://playwright.dev) für End-to-End-Tests.\n  - 🦇 „Dark-Mode“-Unterstützung.\n- 🐋 [Docker Compose](https://www.docker.com) für Entwicklung und Produktion.\n- 🔒 Sicheres Passwort-Hashing standardmäßig.\n- 🔑 JWT (JSON Web Token)-Authentifizierung.\n- 📫 E-Mail-basierte Passwortwiederherstellung.\n- ✅ Tests mit [Pytest](https://pytest.org).\n- 📞 [Traefik](https://traefik.io) als Reverse-Proxy / Load Balancer.\n- 🚢 Deployment-Anleitungen unter Verwendung von Docker Compose, einschließlich der Einrichtung eines Frontend-Traefik-Proxys zur Handhabung automatischer HTTPS-Zertifikate.\n- 🏭 CI (kontinuierliche Integration) und CD (kontinuierliches Deployment) basierend auf GitHub Actions.\n"
  },
  {
    "path": "docs/de/docs/python-types.md",
    "content": "# Einführung in Python-Typen { #python-types-intro }\n\nPython hat Unterstützung für optionale „Typhinweise“ (auch „Typannotationen“ genannt).\n\nDiese **„Typhinweise“** oder -Annotationen sind eine spezielle Syntax, die es erlaubt, den <dfn title=\"zum Beispiel: str, int, float, bool\">Typ</dfn> einer Variablen zu deklarieren.\n\nDurch das Deklarieren von Typen für Ihre Variablen können Editoren und Tools bessere Unterstützung bieten.\n\nDies ist lediglich eine **schnelle Anleitung / Auffrischung** über Pythons Typhinweise. Sie deckt nur das Minimum ab, das nötig ist, um diese mit **FastAPI** zu verwenden ... was tatsächlich sehr wenig ist.\n\n**FastAPI** basiert vollständig auf diesen Typhinweisen, sie geben der Anwendung viele Vorteile und Möglichkeiten.\n\nAber selbst wenn Sie **FastAPI** nie verwenden, wird es für Sie nützlich sein, ein wenig darüber zu lernen.\n\n/// note | Hinweis\n\nWenn Sie ein Python-Experte sind und bereits alles über Typhinweise wissen, überspringen Sie dieses Kapitel und fahren Sie mit dem nächsten fort.\n\n///\n\n## Motivation { #motivation }\n\nFangen wir mit einem einfachen Beispiel an:\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\nDieses Programm gibt aus:\n\n```\nJohn Doe\n```\n\nDie Funktion macht Folgendes:\n\n* Nimmt einen `first_name` und `last_name`.\n* Schreibt den ersten Buchstaben eines jeden Wortes groß, mithilfe von `title()`.\n* <dfn title=\"Fügt sie zu einer Einheit zusammen. Mit dem Inhalt des einen nach dem anderen.\">Verkettet</dfn> sie mit einem Leerzeichen in der Mitte.\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### Es bearbeiten { #edit-it }\n\nEs ist ein sehr einfaches Programm.\n\nAber nun stellen Sie sich vor, Sie würden es selbst schreiben.\n\nIrgendwann sind die Funktions-Parameter fertig, Sie starten mit der Definition des Körpers ...\n\nAber dann müssen Sie „diese Methode aufrufen, die den ersten Buchstaben in Großbuchstaben umwandelt“.\n\nWar es `upper`? War es `uppercase`? `first_uppercase`? `capitalize`?\n\nDann versuchen Sie es mit dem langjährigen Freund des Programmierers, der Editor-Autovervollständigung.\n\nSie geben den ersten Parameter der Funktion ein, `first_name`, dann einen Punkt (`.`) und drücken `Strg+Leertaste`, um die Vervollständigung auszulösen.\n\nAber leider erhalten Sie nichts Nützliches:\n\n<img src=\"/img/python-types/image01.png\">\n\n### Typen hinzufügen { #add-types }\n\nLassen Sie uns eine einzelne Zeile aus der vorherigen Version ändern.\n\nWir ändern den folgenden Teil, die Parameter der Funktion, von:\n\n```Python\n    first_name, last_name\n```\n\nzu:\n\n```Python\n    first_name: str, last_name: str\n```\n\nDas war's.\n\nDas sind die „Typhinweise“:\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\nDas ist nicht das gleiche wie das Deklarieren von Defaultwerten, wie es hier der Fall ist:\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\nDas ist eine andere Sache.\n\nWir verwenden Doppelpunkte (`:`), nicht Gleichheitszeichen (`=`).\n\nUnd das Hinzufügen von Typhinweisen ändert normalerweise nichts an dem, was ohne sie passieren würde.\n\nAber jetzt stellen Sie sich vor, Sie sind wieder mitten in der Erstellung dieser Funktion, aber mit Typhinweisen.\n\nAn derselben Stelle versuchen Sie, die Autovervollständigung mit „Strg+Leertaste“ auszulösen, und Sie sehen:\n\n<img src=\"/img/python-types/image02.png\">\n\nHier können Sie durch die Optionen blättern, bis Sie diejenige finden, bei der es „Klick“ macht:\n\n<img src=\"/img/python-types/image03.png\">\n\n## Mehr Motivation { #more-motivation }\n\nSehen Sie sich diese Funktion an, sie hat bereits Typhinweise:\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\nDa der Editor die Typen der Variablen kennt, erhalten Sie nicht nur Code-Vervollständigung, sondern auch eine Fehlerprüfung:\n\n<img src=\"/img/python-types/image04.png\">\n\nJetzt, da Sie wissen, dass Sie das reparieren müssen, konvertieren Sie `age` mittels `str(age)` in einen String:\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## Deklarieren von Typen { #declaring-types }\n\nSie haben gerade den Haupt-Einsatzort für die Deklaration von Typhinweisen gesehen. Als Funktionsparameter.\n\nDas ist auch meistens, wie sie in **FastAPI** verwendet werden.\n\n### Einfache Typen { #simple-types }\n\nSie können alle Standard-Python-Typen deklarieren, nicht nur `str`.\n\nZum Beispiel diese:\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### `typing`-Modul { #typing-module }\n\nFür einige zusätzliche Anwendungsfälle müssen Sie möglicherweise Dinge aus dem Standardmodul `typing` importieren. Zum Beispiel, wenn Sie deklarieren möchten, dass etwas „jeden Typ“ haben kann, können Sie `Any` aus `typing` verwenden:\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### Generische Typen { #generic-types }\n\nEinige Typen können „Typ-Parameter“ in eckigen Klammern annehmen, um ihre inneren Typen zu definieren, z. B. eine „Liste von Strings“ würde als `list[str]` deklariert.\n\nDiese Typen, die Typ-Parameter annehmen können, werden **generische Typen** oder **Generics** genannt.\n\nSie können dieselben eingebauten Typen als Generics verwenden (mit eckigen Klammern und Typen darin):\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### Liste { #list }\n\nDefinieren wir zum Beispiel eine Variable, die eine `list` von `str` – eine Liste von Strings – sein soll.\n\nDeklarieren Sie die Variable mit der gleichen Doppelpunkt-Syntax (`:`).\n\nAls Typ nehmen Sie `list`.\n\nDa die Liste ein Typ ist, welcher innere Typen enthält, werden diese von eckigen Klammern umfasst:\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info | Info\n\nDie inneren Typen in den eckigen Klammern werden als „Typ-Parameter“ bezeichnet.\n\nIn diesem Fall ist `str` der Typ-Parameter, der an `list` übergeben wird.\n\n///\n\nDas bedeutet: Die Variable `items` ist eine Liste – `list` – und jedes der Elemente in dieser Liste ist ein String – `str`.\n\nAuf diese Weise kann Ihr Editor Sie auch bei der Bearbeitung von Einträgen aus der Liste unterstützen:\n\n<img src=\"/img/python-types/image05.png\">\n\nOhne Typen ist das fast unmöglich zu erreichen.\n\nBeachten Sie, dass die Variable `item` eines der Elemente in der Liste `items` ist.\n\nUnd trotzdem weiß der Editor, dass es sich um ein `str` handelt, und bietet entsprechende Unterstützung.\n\n#### Tupel und Menge { #tuple-and-set }\n\nDas Gleiche gilt für die Deklaration eines Tupels – `tuple` – und einer Menge – `set`:\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\nDas bedeutet:\n\n* Die Variable `items_t` ist ein `tuple` mit 3 Elementen, einem `int`, einem weiteren `int` und einem `str`.\n* Die Variable `items_s` ist ein `set`, und jedes seiner Elemente ist vom Typ `bytes`.\n\n#### Dict { #dict }\n\nUm ein `dict` zu definieren, übergeben Sie zwei Typ-Parameter, getrennt durch Kommas.\n\nDer erste Typ-Parameter ist für die Schlüssel des `dict`.\n\nDer zweite Typ-Parameter ist für die Werte des `dict`:\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\nDas bedeutet:\n\n* Die Variable `prices` ist ein `dict`:\n    * Die Schlüssel dieses `dict` sind vom Typ `str` (z. B. die Namen der einzelnen Artikel).\n    * Die Werte dieses `dict` sind vom Typ `float` (z. B. der Preis jedes Artikels).\n\n#### Union { #union }\n\nSie können deklarieren, dass eine Variable einer von **verschiedenen Typen** sein kann, zum Beispiel ein `int` oder ein `str`.\n\nUm das zu definieren, verwenden Sie den <dfn title=\"auch „bitweiser Oder-Operator“ genannt, aber diese Bedeutung ist hier nicht relevant\">vertikalen Balken (`|`)</dfn>, um beide Typen zu trennen.\n\nDas wird „Union“ genannt, weil die Variable etwas aus der Vereinigung dieser beiden Typmengen sein kann.\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\nDas bedeutet, dass `item` ein `int` oder ein `str` sein könnte.\n\n#### Vielleicht `None` { #possibly-none }\n\nSie können deklarieren, dass ein Wert einen Typ haben könnte, wie `str`, dass er aber auch `None` sein könnte.\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\nWenn Sie `str | None` anstelle von nur `str` verwenden, wird Ihr Editor Ihnen dabei helfen, Fehler zu erkennen, bei denen Sie annehmen könnten, dass ein Wert immer ein `str` ist, obwohl er auch `None` sein könnte.\n\n### Klassen als Typen { #classes-as-types }\n\nSie können auch eine Klasse als Typ einer Variablen deklarieren.\n\nNehmen wir an, Sie haben eine Klasse `Person`, mit einem Namen:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\nDann können Sie eine Variable vom Typ `Person` deklarieren:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\nUnd wiederum bekommen Sie die volle Editor-Unterstützung:\n\n<img src=\"/img/python-types/image06.png\">\n\nBeachten Sie, das bedeutet: „`one_person` ist eine **Instanz** der Klasse `Person`“.\n\nEs bedeutet nicht: „`one_person` ist die **Klasse** genannt `Person`“.\n\n## Pydantic-Modelle { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/) ist eine Python-Bibliothek für die Validierung von Daten.\n\nSie deklarieren die „Form“ der Daten als Klassen mit Attributen.\n\nUnd jedes Attribut hat einen Typ.\n\nDann erzeugen Sie eine Instanz dieser Klasse mit einigen Werten, und Pydantic validiert die Werte, konvertiert sie in den passenden Typ (falls notwendig) und gibt Ihnen ein Objekt mit allen Daten.\n\nUnd Sie erhalten volle Editor-Unterstützung für dieses Objekt.\n\nEin Beispiel aus der offiziellen Pydantic Dokumentation:\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info | Info\n\nUm mehr über [Pydantic zu erfahren, schauen Sie sich dessen Dokumentation an](https://docs.pydantic.dev/).\n\n///\n\n**FastAPI** basiert vollständig auf Pydantic.\n\nViel mehr von all dem werden Sie in praktischer Anwendung im [Tutorial – Benutzerhandbuch](tutorial/index.md) sehen.\n\n## Typhinweise mit Metadaten-Annotationen { #type-hints-with-metadata-annotations }\n\nPython bietet auch die Möglichkeit, **zusätzliche <dfn title=\"Daten über die Daten, in diesem Fall Informationen über den Typ, z. B. eine Beschreibung.\">Metadaten</dfn>** in Typhinweisen unterzubringen, mittels `Annotated`.\n\nSie können `Annotated` von `typing` importieren.\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nPython selbst macht nichts mit `Annotated`. Für Editoren und andere Tools ist der Typ immer noch `str`.\n\nAber Sie können `Annotated` nutzen, um **FastAPI** mit Metadaten zu versorgen, die ihm sagen, wie sich Ihre Anwendung verhalten soll.\n\nWichtig ist, dass **der erste *Typ-Parameter***, den Sie `Annotated` übergeben, der **tatsächliche Typ** ist. Der Rest sind Metadaten für andere Tools.\n\nIm Moment müssen Sie nur wissen, dass `Annotated` existiert, und dass es Standard-Python ist. 😎\n\nSpäter werden Sie sehen, wie **mächtig** es sein kann.\n\n/// tip | Tipp\n\nDer Umstand, dass es **Standard-Python** ist, bedeutet, dass Sie immer noch die **bestmögliche Entwickler-Erfahrung** in Ihrem Editor haben, sowie mit den Tools, die Sie nutzen, um Ihren Code zu analysieren, zu refaktorisieren, usw. ✨\n\nUnd ebenfalls, dass Ihr Code sehr kompatibel mit vielen anderen Python-Tools und -Bibliotheken sein wird. 🚀\n\n///\n\n## Typhinweise in **FastAPI** { #type-hints-in-fastapi }\n\n**FastAPI** macht sich diese Typhinweise zunutze, um mehrere Dinge zu tun.\n\nMit **FastAPI** deklarieren Sie Parameter mit Typhinweisen, und Sie erhalten:\n\n* **Editorunterstützung**.\n* **Typ-Prüfungen**.\n\n... und **FastAPI** verwendet dieselben Deklarationen, um:\n\n* **Anforderungen** zu definieren: aus <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr>-Pfadparametern, Query-Parametern, Headern, Bodys, Abhängigkeiten, usw.\n* **Daten umzuwandeln**: aus dem Request in den erforderlichen Typ.\n* **Daten zu validieren**: aus jedem Request:\n    * **Automatische Fehler** generieren, die an den Client zurückgegeben werden, wenn die Daten ungültig sind.\n* Die API mit OpenAPI zu **dokumentieren**:\n    * Die dann von den Benutzeroberflächen der automatisch generierten interaktiven Dokumentation verwendet wird.\n\nDas mag alles abstrakt klingen. Machen Sie sich keine Sorgen. Sie werden all das in Aktion sehen im [Tutorial – Benutzerhandbuch](tutorial/index.md).\n\nDas Wichtigste ist, dass **FastAPI** durch die Verwendung von Standard-Python-Typen an einer einzigen Stelle (anstatt weitere Klassen, Dekoratoren usw. hinzuzufügen) einen Großteil der Arbeit für Sie erledigt.\n\n/// info | Info\n\nWenn Sie bereits das ganze Tutorial durchgearbeitet haben und mehr über Typen erfahren wollen, dann ist eine gute Ressource [der „Cheat Sheet“ von `mypy`](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html).\n\n///\n"
  },
  {
    "path": "docs/de/docs/resources/index.md",
    "content": "# Ressourcen { #resources }\n\nZusätzliche Ressourcen, externe Links und mehr. ✈️\n"
  },
  {
    "path": "docs/de/docs/translation-banner.md",
    "content": "/// details | 🌐 Übersetzung durch KI und Menschen\n\nDiese Übersetzung wurde von KI erstellt, angeleitet von Menschen. 🤝\n\nSie könnte Fehler enthalten, etwa Missverständnisse des ursprünglichen Sinns oder unnatürliche Formulierungen, usw. 🤖\n\nSie können diese Übersetzung verbessern, indem Sie [uns helfen, die KI-LLM besser anzuleiten](https://fastapi.tiangolo.com/de/contributing/#translations).\n\n[Englische Version](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/de/docs/tutorial/background-tasks.md",
    "content": "# Hintergrundtasks { #background-tasks }\n\nSie können <abbr title=\"Hintergrund-Aufgaben\">Hintergrundtasks</abbr> definieren, die *nach* der Rückgabe einer <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> ausgeführt werden sollen.\n\nDas ist nützlich für Vorgänge, die nach einem <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> ausgeführt werden müssen, bei denen der Client jedoch nicht unbedingt auf den Abschluss des Vorgangs warten muss, bevor er die Response erhält.\n\nHierzu zählen beispielsweise:\n\n* E-Mail-Benachrichtigungen, die nach dem Ausführen einer Aktion gesendet werden:\n    * Da die Verbindung zu einem E-Mail-Server und das Senden einer E-Mail in der Regel „langsam“ ist (einige Sekunden), können Sie die Response sofort zurücksenden und die E-Mail-Benachrichtigung im Hintergrund senden.\n* Daten verarbeiten:\n    * Angenommen, Sie erhalten eine Datei, die einen langsamen Prozess durchlaufen muss. Sie können als Response „Accepted“ (HTTP 202) zurückgeben und die Datei im Hintergrund verarbeiten.\n\n## `BackgroundTasks` verwenden { #using-backgroundtasks }\n\nImportieren Sie zunächst `BackgroundTasks` und definieren Sie einen Parameter in Ihrer *Pfadoperation-Funktion* mit der Typdeklaration `BackgroundTasks`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI** erstellt für Sie das Objekt vom Typ `BackgroundTasks` und übergibt es als diesen Parameter.\n\n## Eine Taskfunktion erstellen { #create-a-task-function }\n\nErstellen Sie eine Funktion, die als Hintergrundtask ausgeführt werden soll.\n\nEs handelt sich schlicht um eine Standard-Funktion, die Parameter empfangen kann.\n\nEs kann sich um eine `async def`- oder normale `def`-Funktion handeln. **FastAPI** weiß, wie damit zu verfahren ist.\n\nIn diesem Fall schreibt die Taskfunktion in eine Datei (den Versand einer E-Mail simulierend).\n\nUnd da der Schreibvorgang nicht `async` und `await` verwendet, definieren wir die Funktion mit normalem `def`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## Den Hintergrundtask hinzufügen { #add-the-background-task }\n\nÜbergeben Sie innerhalb Ihrer *Pfadoperation-Funktion* Ihre Taskfunktion mit der Methode `.add_task()` an das *Hintergrundtasks*-Objekt:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()` erhält als Argumente:\n\n* Eine Taskfunktion, die im Hintergrund ausgeführt wird (`write_notification`).\n* Eine beliebige Folge von Argumenten, die der Reihe nach an die Taskfunktion übergeben werden sollen (`email`).\n* Alle Schlüsselwort-Argumente, die an die Taskfunktion übergeben werden sollen (`message=\"some notification\"`).\n\n## Dependency Injection { #dependency-injection }\n\nDie Verwendung von `BackgroundTasks` funktioniert auch mit dem <abbr title=\"Einbringen von Abhängigkeiten\">Dependency Injection</abbr> System. Sie können einen Parameter vom Typ `BackgroundTasks` auf mehreren Ebenen deklarieren: in einer *Pfadoperation-Funktion*, in einer Abhängigkeit (Dependable), in einer Unterabhängigkeit usw.\n\n**FastAPI** weiß, was jeweils zu tun ist und wie dasselbe Objekt wiederverwendet werden kann, sodass alle Hintergrundtasks zusammengeführt und anschließend im Hintergrund ausgeführt werden:\n\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\n\nIn obigem Beispiel werden die Nachrichten, *nachdem* die Response gesendet wurde, in die Datei `log.txt` geschrieben.\n\nWenn im Request ein Query-Parameter enthalten war, wird dieser in einem Hintergrundtask in das Log geschrieben.\n\nUnd dann schreibt ein weiterer Hintergrundtask, der in der *Pfadoperation-Funktion* erstellt wird, eine Nachricht unter Verwendung des Pfad-Parameters `email`.\n\n## Technische Details { #technical-details }\n\nDie Klasse `BackgroundTasks` stammt direkt von [`starlette.background`](https://www.starlette.dev/background/).\n\nSie wird direkt in FastAPI importiert/inkludiert, sodass Sie sie von `fastapi` importieren können und vermeiden, versehentlich das alternative `BackgroundTask` (ohne das `s` am Ende) von `starlette.background` zu importieren.\n\nIndem Sie nur `BackgroundTasks` (und nicht `BackgroundTask`) verwenden, ist es dann möglich, es als *Pfadoperation-Funktion*-Parameter zu verwenden und **FastAPI** den Rest für Sie erledigen zu lassen, genau wie bei der direkten Verwendung des `Request`-Objekts.\n\nEs ist immer noch möglich, `BackgroundTask` allein in FastAPI zu verwenden, aber Sie müssen das Objekt in Ihrem Code erstellen und eine Starlette-`Response` zurückgeben, die es enthält.\n\nWeitere Details finden Sie in [Starlettes offizieller Dokumentation für Hintergrundtasks](https://www.starlette.dev/background/).\n\n## Vorbehalt { #caveat }\n\nWenn Sie umfangreiche Hintergrundberechnungen durchführen müssen und diese nicht unbedingt vom selben Prozess ausgeführt werden müssen (z. B. müssen Sie Speicher, Variablen, usw. nicht gemeinsam nutzen), könnte die Verwendung anderer größerer Tools wie z. B. [Celery](https://docs.celeryq.dev) von Vorteil sein.\n\nSie erfordern in der Regel komplexere Konfigurationen und einen Nachrichten-/Job-Queue-Manager wie RabbitMQ oder Redis, ermöglichen Ihnen jedoch die Ausführung von Hintergrundtasks in mehreren Prozessen und insbesondere auf mehreren Servern.\n\nWenn Sie jedoch über dieselbe **FastAPI**-App auf Variablen und Objekte zugreifen oder kleine Hintergrundtasks ausführen müssen (z. B. das Senden einer E-Mail-Benachrichtigung), können Sie einfach `BackgroundTasks` verwenden.\n\n## Zusammenfassung { #recap }\n\nImportieren und verwenden Sie `BackgroundTasks` mit Parametern in *Pfadoperation-Funktionen* und Abhängigkeiten, um Hintergrundtasks hinzuzufügen.\n"
  },
  {
    "path": "docs/de/docs/tutorial/bigger-applications.md",
    "content": "# Größere Anwendungen – mehrere Dateien { #bigger-applications-multiple-files }\n\nWenn Sie eine Anwendung oder eine Web-API erstellen, ist es selten der Fall, dass Sie alles in einer einzigen Datei unterbringen können.\n\n**FastAPI** bietet ein praktisches Werkzeug zur Strukturierung Ihrer Anwendung bei gleichzeitiger Wahrung der Flexibilität.\n\n/// info | Info\n\nWenn Sie von Flask kommen, wäre dies das Äquivalent zu Flasks Blueprints.\n\n///\n\n## Eine Beispiel-Dateistruktur { #an-example-file-structure }\n\nNehmen wir an, Sie haben eine Dateistruktur wie diese:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | Tipp\n\nEs gibt mehrere `__init__.py`-Dateien: eine in jedem Verzeichnis oder Unterverzeichnis.\n\nDas ermöglicht den Import von Code aus einer Datei in eine andere.\n\nIn `app/main.py` könnten Sie beispielsweise eine Zeile wie diese haben:\n\n```\nfrom app.routers import items\n```\n\n///\n\n* Das Verzeichnis `app` enthält alles. Und es hat eine leere Datei `app/__init__.py`, es handelt sich also um ein „Python-Package“ (eine Sammlung von „Python-Modulen“): `app`.\n* Es enthält eine Datei `app/main.py`. Da sie sich in einem Python-Package (einem Verzeichnis mit einer Datei `__init__.py`) befindet, ist sie ein „Modul“ dieses Packages: `app.main`.\n* Es gibt auch eine Datei `app/dependencies.py`, genau wie `app/main.py` ist sie ein „Modul“: `app.dependencies`.\n* Es gibt ein Unterverzeichnis `app/routers/` mit einer weiteren Datei `__init__.py`, es handelt sich also um ein „Python-Subpackage“: `app.routers`.\n* Die Datei `app/routers/items.py` befindet sich in einem Package, `app/routers/`, also ist sie ein Submodul: `app.routers.items`.\n* Das Gleiche gilt für `app/routers/users.py`, es ist ein weiteres Submodul: `app.routers.users`.\n* Es gibt auch ein Unterverzeichnis `app/internal/` mit einer weiteren Datei `__init__.py`, es handelt sich also um ein weiteres „Python-Subpackage“: `app.internal`.\n* Und die Datei `app/internal/admin.py` ist ein weiteres Submodul: `app.internal.admin`.\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\nDie gleiche Dateistruktur mit Kommentaren:\n\n```bash\n.\n├── app                  # \"app\" ist ein Python-Package\n│   ├── __init__.py      # diese Datei macht \"app\" zu einem \"Python-Package\"\n│   ├── main.py          # \"main\"-Modul, z. B. import app.main\n│   ├── dependencies.py  # \"dependencies\"-Modul, z. B. import app.dependencies\n│   └── routers          # \"routers\" ist ein \"Python-Subpackage\"\n│   │   ├── __init__.py  # macht \"routers\" zu einem \"Python-Subpackage\"\n│   │   ├── items.py     # \"items\"-Submodul, z. B. import app.routers.items\n│   │   └── users.py     # \"users\"-Submodul, z. B. import app.routers.users\n│   └── internal         # \"internal\" ist ein \"Python-Subpackage\"\n│       ├── __init__.py  # macht \"internal\" zu einem \"Python-Subpackage\"\n│       └── admin.py     # \"admin\"-Submodul, z. B. import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\nNehmen wir an, die Datei, die nur für die Verwaltung von Benutzern zuständig ist, ist das Submodul unter `/app/routers/users.py`.\n\nSie möchten die *Pfadoperationen* für Ihre Benutzer vom Rest des Codes trennen, um ihn organisiert zu halten.\n\nAber es ist immer noch Teil derselben **FastAPI**-Anwendung/Web-API (es ist Teil desselben „Python-Packages“).\n\nSie können die *Pfadoperationen* für dieses Modul mit `APIRouter` erstellen.\n\n### `APIRouter` importieren { #import-apirouter }\n\nSie importieren ihn und erstellen eine „Instanz“ auf die gleiche Weise wie mit der Klasse `FastAPI`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### *Pfadoperationen* mit `APIRouter` { #path-operations-with-apirouter }\n\nUnd dann verwenden Sie ihn, um Ihre *Pfadoperationen* zu deklarieren.\n\nVerwenden Sie ihn auf die gleiche Weise wie die Klasse `FastAPI`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\nSie können sich `APIRouter` als eine „Mini-`FastAPI`“-Klasse vorstellen.\n\nAlle die gleichen Optionen werden unterstützt.\n\nAlle die gleichen `parameters`, `responses`, `dependencies`, `tags`, usw.\n\n/// tip | Tipp\n\nIn diesem Beispiel heißt die Variable `router`, aber Sie können ihr einen beliebigen Namen geben.\n\n///\n\nWir werden diesen `APIRouter` in die Hauptanwendung `FastAPI` einbinden, aber zuerst kümmern wir uns um die Abhängigkeiten und einen anderen `APIRouter`.\n\n## Abhängigkeiten { #dependencies }\n\nWir sehen, dass wir einige Abhängigkeiten benötigen, die an mehreren Stellen der Anwendung verwendet werden.\n\nAlso fügen wir sie in ihr eigenes `dependencies`-Modul (`app/dependencies.py`) ein.\n\nWir werden nun eine einfache Abhängigkeit verwenden, um einen benutzerdefinierten `X-Token`-Header zu lesen:\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | Tipp\n\nUm dieses Beispiel zu vereinfachen, verwenden wir einen erfundenen Header.\n\nAber in der Praxis werden Sie mit den integrierten [Sicherheits-Werkzeugen](security/index.md) bessere Ergebnisse erzielen.\n\n///\n\n## Ein weiteres Modul mit `APIRouter` { #another-module-with-apirouter }\n\nNehmen wir an, Sie haben im Modul unter `app/routers/items.py` auch die Endpunkte, die für die Verarbeitung von Artikeln („Items“) aus Ihrer Anwendung vorgesehen sind.\n\nSie haben *Pfadoperationen* für:\n\n* `/items/`\n* `/items/{item_id}`\n\nEs ist alles die gleiche Struktur wie bei `app/routers/users.py`.\n\nAber wir wollen schlauer sein und den Code etwas vereinfachen.\n\nWir wissen, dass alle *Pfadoperationen* in diesem Modul folgendes haben:\n\n* Pfad-`prefix`: `/items`.\n* `tags`: (nur ein Tag: `items`).\n* Zusätzliche `responses`.\n* `dependencies`: Sie alle benötigen die von uns erstellte `X-Token`-Abhängigkeit.\n\nAnstatt also alles zu jeder *Pfadoperation* hinzuzufügen, können wir es dem `APIRouter` hinzufügen.\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\nDa der Pfad jeder *Pfadoperation* mit `/` beginnen muss, wie in:\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n... darf das Präfix kein abschließendes `/` enthalten.\n\nDas Präfix lautet in diesem Fall also `/items`.\n\nWir können auch eine Liste von `tags` und zusätzliche `responses` hinzufügen, die auf alle in diesem Router enthaltenen *Pfadoperationen* angewendet werden.\n\nUnd wir können eine Liste von `dependencies` hinzufügen, die allen *Pfadoperationen* im Router hinzugefügt und für jeden an sie gerichteten <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> ausgeführt/aufgelöst werden.\n\n/// tip | Tipp\n\nBeachten Sie, dass ähnlich wie bei [Abhängigkeiten in *Pfadoperation-Dekoratoren*](dependencies/dependencies-in-path-operation-decorators.md) kein Wert an Ihre *Pfadoperation-Funktion* übergeben wird.\n\n///\n\nDas Endergebnis ist, dass die Pfade für diese Artikel jetzt wie folgt lauten:\n\n* `/items/`\n* `/items/{item_id}`\n\n... wie wir es beabsichtigt hatten.\n\n* Sie werden mit einer Liste von Tags gekennzeichnet, die einen einzelnen String „items“ enthält.\n    * Diese „Tags“ sind besonders nützlich für die automatischen interaktiven Dokumentationssysteme (unter Verwendung von OpenAPI).\n* Alle enthalten die vordefinierten `responses`.\n* Für alle diese *Pfadoperationen* wird die Liste der `dependencies` ausgewertet/ausgeführt, bevor sie selbst ausgeführt werden.\n    * Wenn Sie außerdem Abhängigkeiten in einer bestimmten *Pfadoperation* deklarieren, **werden diese ebenfalls ausgeführt**.\n    * Zuerst werden die Router-Abhängigkeiten ausgeführt, dann die [`dependencies` im Dekorator](dependencies/dependencies-in-path-operation-decorators.md) und dann die normalen Parameterabhängigkeiten.\n    * Sie können auch [`Security`-Abhängigkeiten mit `scopes`](../advanced/security/oauth2-scopes.md) hinzufügen.\n\n/// tip | Tipp\n\n`dependencies` im `APIRouter` können beispielsweise verwendet werden, um eine Authentifizierung für eine ganze Gruppe von *Pfadoperationen* zu erfordern. Selbst wenn die Abhängigkeiten nicht jeder einzeln hinzugefügt werden.\n\n///\n\n/// check | Testen\n\nDie Parameter `prefix`, `tags`, `responses` und `dependencies` sind (wie in vielen anderen Fällen) nur ein Feature von **FastAPI**, um Ihnen dabei zu helfen, Codeverdoppelung zu vermeiden.\n\n///\n\n### Die Abhängigkeiten importieren { #import-the-dependencies }\n\nDer folgende Code befindet sich im Modul `app.routers.items`, also in der Datei `app/routers/items.py`.\n\nUnd wir müssen die Abhängigkeitsfunktion aus dem Modul `app.dependencies` importieren, also aus der Datei `app/dependencies.py`.\n\nDaher verwenden wir einen relativen Import mit `..` für die Abhängigkeiten:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### Wie relative Importe funktionieren { #how-relative-imports-work }\n\n/// tip | Tipp\n\nWenn Sie genau wissen, wie Importe funktionieren, fahren Sie mit dem nächsten Abschnitt unten fort.\n\n///\n\nEin einzelner Punkt `.`, wie in:\n\n```Python\nfrom .dependencies import get_token_header\n```\n\nwürde bedeuten:\n\n* Beginnend im selben Package, in dem sich dieses Modul (die Datei `app/routers/items.py`) befindet (das Verzeichnis `app/routers/`) ...\n* finde das Modul `dependencies` (eine imaginäre Datei unter `app/routers/dependencies.py`) ...\n* und importiere daraus die Funktion `get_token_header`.\n\nAber diese Datei existiert nicht, unsere Abhängigkeiten befinden sich in einer Datei unter `app/dependencies.py`.\n\nErinnern Sie sich, wie unsere Anwendungs-/Dateistruktur aussieht:\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\nDie beiden Punkte `..`, wie in:\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\nbedeuten:\n\n* Beginnend im selben Package, in dem sich dieses Modul (die Datei `app/routers/items.py`) befindet (das Verzeichnis `app/routers/`) ...\n* gehe zum übergeordneten Package (das Verzeichnis `app/`) ...\n* und finde dort das Modul `dependencies` (die Datei unter `app/dependencies.py`) ...\n* und importiere daraus die Funktion `get_token_header`.\n\nDas funktioniert korrekt! 🎉\n\n---\n\nDas Gleiche gilt, wenn wir drei Punkte `...` verwendet hätten, wie in:\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\nDas würde bedeuten:\n\n* Beginnend im selben Package, in dem sich dieses Modul (die Datei `app/routers/items.py`) befindet (das Verzeichnis `app/routers/`) ...\n* gehe zum übergeordneten Package (das Verzeichnis `app/`) ...\n* gehe dann zum übergeordneten Package dieses Packages (es gibt kein übergeordnetes Package, `app` ist die oberste Ebene 😱) ...\n* und finde dort das Modul `dependencies` (die Datei unter `app/dependencies.py`) ...\n* und importiere daraus die Funktion `get_token_header`.\n\nDas würde sich auf ein Paket oberhalb von `app/` beziehen, mit seiner eigenen Datei `__init__.py`, usw. Aber das haben wir nicht. Das würde in unserem Beispiel also einen Fehler auslösen. 🚨\n\nAber jetzt wissen Sie, wie es funktioniert, sodass Sie relative Importe in Ihren eigenen Anwendungen verwenden können, egal wie komplex diese sind. 🤓\n\n### Einige benutzerdefinierte `tags`, `responses`, und `dependencies` hinzufügen { #add-some-custom-tags-responses-and-dependencies }\n\nWir fügen weder das Präfix `/items` noch `tags=[\"items\"]` zu jeder *Pfadoperation* hinzu, da wir sie zum `APIRouter` hinzugefügt haben.\n\nAber wir können immer noch _mehr_ `tags` hinzufügen, die auf eine bestimmte *Pfadoperation* angewendet werden, sowie einige zusätzliche `responses`, die speziell für diese *Pfadoperation* gelten:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | Tipp\n\nDiese letzte Pfadoperation wird eine Kombination von Tags haben: `[\"items\", \"custom\"]`.\n\nUnd sie wird auch beide <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Responses</abbr> in der Dokumentation haben, eine für `404` und eine für `403`.\n\n///\n\n## Das Haupt-`FastAPI` { #the-main-fastapi }\n\nSehen wir uns nun das Modul unter `app/main.py` an.\n\nHier importieren und verwenden Sie die Klasse `FastAPI`.\n\nDies wird die Hauptdatei Ihrer Anwendung sein, die alles zusammenfügt.\n\nUnd da sich der Großteil Ihrer Logik jetzt in seinem eigenen spezifischen Modul befindet, wird die Hauptdatei recht einfach sein.\n\n### `FastAPI` importieren { #import-fastapi }\n\nSie importieren und erstellen wie gewohnt eine `FastAPI`-Klasse.\n\nUnd wir können sogar [globale Abhängigkeiten](dependencies/global-dependencies.md) deklarieren, die mit den Abhängigkeiten für jeden `APIRouter` kombiniert werden:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### Den `APIRouter` importieren { #import-the-apirouter }\n\nJetzt importieren wir die anderen Submodule, die `APIRouter` haben:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\nDa es sich bei den Dateien `app/routers/users.py` und `app/routers/items.py` um Submodule handelt, die Teil desselben Python-Packages `app` sind, können wir einen einzelnen Punkt `.` verwenden, um sie mit „relativen Imports“ zu importieren.\n\n### Wie das Importieren funktioniert { #how-the-importing-works }\n\nDie Sektion:\n\n```Python\nfrom .routers import items, users\n```\n\nbedeutet:\n\n* Beginnend im selben Package, in dem sich dieses Modul (die Datei `app/main.py`) befindet (das Verzeichnis `app/`) ...\n* Suche nach dem Subpackage `routers` (das Verzeichnis unter `app/routers/`) ...\n* und importiere daraus die Submodule `items` (die Datei unter `app/routers/items.py`) und `users` (die Datei unter `app/routers/users.py`) ...\n\nDas Modul `items` verfügt über eine Variable `router` (`items.router`). Das ist dieselbe, die wir in der Datei `app/routers/items.py` erstellt haben, es ist ein `APIRouter`-Objekt.\n\nUnd dann machen wir das gleiche für das Modul `users`.\n\nWir könnten sie auch wie folgt importieren:\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info | Info\n\nDie erste Version ist ein „relativer Import“:\n\n```Python\nfrom .routers import items, users\n```\n\nDie zweite Version ist ein „absoluter Import“:\n\n```Python\nfrom app.routers import items, users\n```\n\nUm mehr über Python-Packages und -Module zu erfahren, lesen Sie [die offizielle Python-Dokumentation über Module](https://docs.python.org/3/tutorial/modules.html).\n\n///\n\n### Namenskollisionen vermeiden { #avoid-name-collisions }\n\nWir importieren das Submodul `items` direkt, anstatt nur seine Variable `router` zu importieren.\n\nDas liegt daran, dass wir im Submodul `users` auch eine weitere Variable namens `router` haben.\n\nWenn wir eine nach der anderen importiert hätten, etwa:\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\nwürde der `router` von `users` den von `items` überschreiben und wir könnten sie nicht gleichzeitig verwenden.\n\nUm also beide in derselben Datei verwenden zu können, importieren wir die Submodule direkt:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### Die `APIRouter` für `users` und `items` inkludieren { #include-the-apirouters-for-users-and-items }\n\nInkludieren wir nun die `router` aus diesen Submodulen `users` und `items`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info | Info\n\n`users.router` enthält den `APIRouter` in der Datei `app/routers/users.py`.\n\nUnd `items.router` enthält den `APIRouter` in der Datei `app/routers/items.py`.\n\n///\n\nMit `app.include_router()` können wir jeden `APIRouter` zur Hauptanwendung `FastAPI` hinzufügen.\n\nEs wird alle Routen von diesem Router als Teil von dieser inkludieren.\n\n/// note | Technische Details\n\nTatsächlich wird intern eine *Pfadoperation* für jede *Pfadoperation* erstellt, die im `APIRouter` deklariert wurde.\n\nHinter den Kulissen wird es also tatsächlich so funktionieren, als ob alles dieselbe einzige Anwendung wäre.\n\n///\n\n/// check | Testen\n\nBei der Einbindung von Routern müssen Sie sich keine Gedanken über die Leistung machen.\n\nDies dauert Mikrosekunden und geschieht nur beim Start.\n\nEs hat also keinen Einfluss auf die Leistung. ⚡\n\n///\n\n### Einen `APIRouter` mit benutzerdefinierten `prefix`, `tags`, `responses` und `dependencies` einfügen { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\nStellen wir uns nun vor, dass Ihre Organisation Ihnen die Datei `app/internal/admin.py` gegeben hat.\n\nSie enthält einen `APIRouter` mit einigen administrativen *Pfadoperationen*, die Ihre Organisation zwischen mehreren Projekten teilt.\n\nIn diesem Beispiel wird es ganz einfach sein. Nehmen wir jedoch an, dass wir, da sie mit anderen Projekten in der Organisation geteilt wird, sie nicht ändern und kein `prefix`, `dependencies`, `tags`, usw. direkt zum `APIRouter` hinzufügen können:\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nAber wir möchten immer noch ein benutzerdefiniertes `prefix` festlegen, wenn wir den `APIRouter` einbinden, sodass alle seine *Pfadoperationen* mit `/admin` beginnen, wir möchten es mit den `dependencies` sichern, die wir bereits für dieses Projekt haben, und wir möchten `tags` und `responses` hinzufügen.\n\nWir können das alles deklarieren, ohne den ursprünglichen `APIRouter` ändern zu müssen, indem wir diese Parameter an `app.include_router()` übergeben:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\nAuf diese Weise bleibt der ursprüngliche `APIRouter` unverändert, sodass wir dieselbe `app/internal/admin.py`-Datei weiterhin mit anderen Projekten in der Organisation teilen können.\n\nDas Ergebnis ist, dass in unserer Anwendung jede der *Pfadoperationen* aus dem Modul `admin` Folgendes haben wird:\n\n* Das Präfix `/admin`.\n* Den Tag `admin`.\n* Die Abhängigkeit `get_token_header`.\n* Die Response `418`. 🍵\n\nDies wirkt sich jedoch nur auf diesen `APIRouter` in unserer Anwendung aus, nicht auf anderen Code, der ihn verwendet.\n\nSo könnten beispielsweise andere Projekte denselben `APIRouter` mit einer anderen Authentifizierungsmethode verwenden.\n\n### Eine *Pfadoperation* hinzufügen { #include-a-path-operation }\n\nWir können *Pfadoperationen* auch direkt zur `FastAPI`-App hinzufügen.\n\nHier machen wir es ... nur um zu zeigen, dass wir es können 🤷:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\nund es wird korrekt funktionieren, zusammen mit allen anderen *Pfadoperationen*, die mit `app.include_router()` hinzugefügt wurden.\n\n/// info | Sehr technische Details\n\n**Hinweis**: Dies ist ein sehr technisches Detail, das Sie wahrscheinlich **einfach überspringen** können.\n\n---\n\nDie `APIRouter` sind nicht „gemountet“, sie sind nicht vom Rest der Anwendung isoliert.\n\nDas liegt daran, dass wir deren *Pfadoperationen* in das OpenAPI-Schema und die Benutzeroberflächen einbinden möchten.\n\nDa wir sie nicht einfach isolieren und unabhängig vom Rest „mounten“ können, werden die *Pfadoperationen* „geklont“ (neu erstellt) und nicht direkt einbezogen.\n\n///\n\n## Den `entrypoint` in `pyproject.toml` konfigurieren { #configure-the-entrypoint-in-pyproject-toml }\n\nDa Ihr FastAPI-`app`-Objekt in `app/main.py` liegt, können Sie den `entrypoint` in Ihrer `pyproject.toml`-Datei so konfigurieren:\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\ndas entspricht einem Import wie:\n\n```python\nfrom app.main import app\n```\n\nAuf diese Weise weiß der `fastapi`-Befehl, wo er Ihre App findet.\n\n/// Note | Hinweis\n\nSie könnten auch den Pfad an den Befehl übergeben, etwa:\n\n```console\n$ fastapi dev app/main.py\n```\n\nAber dann müssten Sie sich jedes Mal, wenn Sie den `fastapi`-Befehl aufrufen, an den korrekten Pfad erinnern.\n\nAußerdem finden andere Tools Ihre App womöglich nicht, zum Beispiel die [VS Code-Erweiterung](../editor-support.md) oder [FastAPI Cloud](https://fastapicloud.com). Daher wird empfohlen, den `entrypoint` in `pyproject.toml` zu verwenden.\n\n///\n\n## Die automatische API-Dokumentation prüfen { #check-the-automatic-api-docs }\n\nFühren Sie nun Ihre App aus:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nUnd öffnen Sie die Dokumentation unter [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nSie sehen die automatische API-Dokumentation, einschließlich der Pfade aller Submodule, mit den richtigen Pfaden (und Präfixen) und den richtigen Tags:\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## Den gleichen Router mehrmals mit unterschiedlichem `prefix` inkludieren { #include-the-same-router-multiple-times-with-different-prefix }\n\nSie können `.include_router()` auch mehrmals mit *demselben* Router und unterschiedlichen Präfixen verwenden.\n\nDies könnte beispielsweise nützlich sein, um dieselbe API unter verschiedenen Präfixen verfügbar zu machen, z. B. `/api/v1` und `/api/latest`.\n\nDies ist eine fortgeschrittene Verwendung, die Sie möglicherweise nicht wirklich benötigen, aber für den Fall, dass Sie sie benötigen, ist sie vorhanden.\n\n## Einen `APIRouter` in einen anderen einfügen { #include-an-apirouter-in-another }\n\nAuf die gleiche Weise, wie Sie einen `APIRouter` in eine `FastAPI`-Anwendung einbinden können, können Sie einen `APIRouter` in einen anderen `APIRouter` einbinden, indem Sie Folgendes verwenden:\n\n```Python\nrouter.include_router(other_router)\n```\n\nStellen Sie sicher, dass Sie dies tun, bevor Sie `router` in die `FastAPI`-App einbinden, damit auch die *Pfadoperationen* von `other_router` inkludiert werden.\n"
  },
  {
    "path": "docs/de/docs/tutorial/body-fields.md",
    "content": "# Body – Felder { #body-fields }\n\nSo wie Sie zusätzliche Validierung und Metadaten in Parametern der *Pfadoperation-Funktion* mittels `Query`, `Path` und `Body` deklarieren, können Sie auch innerhalb von Pydantic-Modellen zusätzliche Validierung und Metadaten deklarieren, mittels Pydantics `Field`.\n\n## `Field` importieren { #import-field }\n\nImportieren Sie es zuerst:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n/// warning | Achtung\n\nBeachten Sie, dass `Field` direkt von `pydantic` importiert wird, nicht von `fastapi`, wie die anderen (`Query`, `Path`, `Body`, usw.)\n\n///\n\n## Modellattribute deklarieren { #declare-model-attributes }\n\nDann können Sie `Field` mit Modellattributen deklarieren:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field` funktioniert genauso wie `Query`, `Path` und `Body`, es hat die gleichen Parameter, usw.\n\n/// note | Technische Details\n\nTatsächlich erstellen `Query`, `Path` und andere, die Sie als nächstes sehen werden, Instanzen von Unterklassen einer allgemeinen Klasse `Param`, welche selbst eine Unterklasse von Pydantics `FieldInfo`-Klasse ist.\n\nUnd Pydantics `Field` gibt ebenfalls eine Instanz von `FieldInfo` zurück.\n\n`Body` gibt auch direkt Instanzen einer Unterklasse von `FieldInfo` zurück. Später werden Sie andere sehen, die Unterklassen der `Body`-Klasse sind.\n\nDenken Sie daran, dass `Query`, `Path` und andere, wenn Sie sie von `fastapi` importieren, tatsächlich Funktionen sind, die spezielle Klassen zurückgeben.\n\n///\n\n/// tip | Tipp\n\nBeachten Sie, wie jedes Attribut eines Modells mit einem Typ, Defaultwert und `Field` die gleiche Struktur hat wie ein Parameter einer *Pfadoperation-Funktion*, nur mit `Field` statt `Path`, `Query`, `Body`.\n\n///\n\n## Zusätzliche Information hinzufügen { #add-extra-information }\n\nSie können zusätzliche Information in `Field`, `Query`, `Body`, usw. deklarieren. Und es wird im generierten JSON-Schema untergebracht.\n\nSie werden später in der Dokumentation mehr darüber lernen, wie man zusätzliche Information unterbringt, wenn Sie lernen, Beispiele zu deklarieren.\n\n/// warning | Achtung\n\nExtra-Schlüssel, die `Field` überreicht werden, werden auch im resultierenden OpenAPI-Schema Ihrer Anwendung gelistet. Da diese Schlüssel möglicherweise nicht Teil der OpenAPI-Spezifikation sind, könnten einige OpenAPI-Tools, wie etwa [der OpenAPI-Validator](https://validator.swagger.io/), nicht mit Ihrem generierten Schema funktionieren.\n\n///\n\n## Zusammenfassung { #recap }\n\nSie können Pydantics `Field` verwenden, um zusätzliche Validierungen und Metadaten für Modellattribute zu deklarieren.\n\nSie können auch die zusätzlichen Schlüsselwortargumente verwenden, um zusätzliche JSON-Schema-Metadaten zu übergeben.\n"
  },
  {
    "path": "docs/de/docs/tutorial/body-multiple-params.md",
    "content": "# Body – Mehrere Parameter { #body-multiple-parameters }\n\nNun, da wir gesehen haben, wie `Path` und `Query` verwendet werden, schauen wir uns fortgeschrittenere Verwendungsmöglichkeiten von <abbr title=\"Requestbody\">Requestbody</abbr>-Deklarationen an.\n\n## `Path`-, `Query`- und Body-Parameter vermischen { #mix-path-query-and-body-parameters }\n\nZuerst einmal, Sie können `Path`-, `Query`- und Requestbody-Parameter-Deklarationen frei mischen und **FastAPI** wird wissen, was zu tun ist.\n\nUnd Sie können auch Body-Parameter als optional kennzeichnen, indem Sie den Defaultwert auf `None` setzen:\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | Hinweis\n\nBeachten Sie, dass in diesem Fall das `item`, welches vom Body genommen wird, optional ist. Da es `None` als Defaultwert hat.\n\n///\n\n## Mehrere Body-Parameter { #multiple-body-parameters }\n\nIm vorherigen Beispiel erwarteten die *Pfadoperationen* einen JSON-Body mit den Attributen eines `Item`s, etwa:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\nAber Sie können auch mehrere Body-Parameter deklarieren, z. B. `item` und `user`:\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\nIn diesem Fall wird **FastAPI** bemerken, dass es mehr als einen Body-Parameter in der Funktion gibt (zwei Parameter, die Pydantic-Modelle sind).\n\nEs wird deshalb die Parameternamen als Schlüssel (Feldnamen) im Body verwenden und erwartet einen Body wie folgt:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | Hinweis\n\nBeachten Sie, dass, obwohl `item` wie zuvor deklariert wurde, es nun unter einem Schlüssel `item` im Body erwartet wird.\n\n///\n\n**FastAPI** wird die automatische Konvertierung des Requests übernehmen, sodass der Parameter `item` seinen spezifischen Inhalt bekommt, und das Gleiche gilt für den Parameter `user`.\n\nEs wird die Validierung dieser zusammengesetzten Daten übernehmen, und diese im OpenAPI-Schema und der automatischen Dokumentation dokumentieren.\n\n## Einzelne Werte im Body { #singular-values-in-body }\n\nSo wie `Query` und `Path` für Query- und Pfad-Parameter, stellt **FastAPI** das Äquivalent `Body` zur Verfügung, um Extra-Daten für Body-Parameter zu definieren.\n\nZum Beispiel, das vorherige Modell erweiternd, könnten Sie entscheiden, dass Sie einen weiteren Schlüssel `importance` im selben Body haben möchten, neben `item` und `user`.\n\nWenn Sie diesen Parameter einfach so hinzufügen, wird **FastAPI** annehmen, dass es ein Query-Parameter ist, da er ein einzelner Wert ist.\n\nAber Sie können **FastAPI** instruieren, ihn als weiteren Body-Schlüssel zu erkennen, indem Sie `Body` verwenden:\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\nIn diesem Fall erwartet **FastAPI** einen Body wie:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\nWiederum wird es die Datentypen konvertieren, validieren, dokumentieren, usw.\n\n## Mehrere Body-Parameter und Query-Parameter { #multiple-body-params-and-query }\n\nNatürlich können Sie auch, wann immer Sie das brauchen, weitere Query-Parameter hinzufügen, zusätzlich zu den Body-Parametern.\n\nDa einfache Werte standardmäßig als Query-Parameter interpretiert werden, müssen Sie `Query` nicht explizit hinzufügen, Sie können einfach schreiben:\n\n```Python\nq: str | None = None\n```\n\nZum Beispiel:\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n/// info | Info\n\n`Body` hat die gleichen zusätzlichen Validierungs- und Metadaten-Parameter wie `Query`, `Path` und andere, die Sie später kennenlernen werden.\n\n///\n\n## Einen einzelnen Body-Parameter einbetten { #embed-a-single-body-parameter }\n\nNehmen wir an, Sie haben nur einen einzelnen `item`-Body-Parameter von einem Pydantic-Modell `Item`.\n\nStandardmäßig wird **FastAPI** dann seinen Body direkt erwarten.\n\nAber wenn Sie möchten, dass es einen JSON-Body mit einem Schlüssel `item` erwartet, und darin den Inhalt des Modells, so wie es das tut, wenn Sie mehrere Body-Parameter deklarieren, dann können Sie den speziellen `Body`-Parameter `embed` setzen:\n\n```Python\nitem: Item = Body(embed=True)\n```\n\nso wie in:\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\nIn diesem Fall erwartet **FastAPI** einen Body wie:\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\nstatt:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## Zusammenfassung { #recap }\n\nSie können mehrere Body-Parameter zu Ihrer *Pfadoperation-Funktion* hinzufügen, obwohl ein Request nur einen einzigen Body enthalten kann.\n\nAber **FastAPI** wird sich darum kümmern, Ihnen korrekte Daten in Ihrer Funktion zu überreichen, und das korrekte Schema in der *Pfadoperation* zu validieren und zu dokumentieren.\n\nSie können auch einzelne Werte deklarieren, die als Teil des Bodys empfangen werden.\n\nUnd Sie können **FastAPI** instruieren, den Body in einem Schlüssel unterzubringen, selbst wenn nur ein einzelner Body-Parameter deklariert ist.\n"
  },
  {
    "path": "docs/de/docs/tutorial/body-nested-models.md",
    "content": "# Body – Verschachtelte Modelle { #body-nested-models }\n\nMit **FastAPI** können Sie (dank Pydantic) beliebig tief verschachtelte Modelle definieren, validieren, dokumentieren und verwenden.\n\n## Listen als Felder { #list-fields }\n\nSie können ein Attribut als Kindtyp definieren, zum Beispiel eine Python-`list`.\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\nDas bewirkt, dass `tags` eine Liste ist, wenngleich es nichts über den Typ der Elemente der Liste aussagt.\n\n## Listen mit Typ-Parametern als Felder { #list-fields-with-type-parameter }\n\nAber Python erlaubt es, Listen mit inneren Typen, auch „Typ-Parameter“ genannt, zu deklarieren.\n\n### Eine `list` mit einem Typ-Parameter deklarieren { #declare-a-list-with-a-type-parameter }\n\nUm Typen zu deklarieren, die Typ-Parameter (innere Typen) haben, wie `list`, `dict`, `tuple`, übergeben Sie den/die inneren Typ(en) als „Typ-Parameter“ in eckigen Klammern: `[` und `]`\n\n```Python\nmy_list: list[str]\n```\n\nDas ist alles Standard-Python-Syntax für Typdeklarationen.\n\nVerwenden Sie dieselbe Standardsyntax für Modellattribute mit inneren Typen.\n\nIn unserem Beispiel können wir also bewirken, dass `tags` spezifisch eine „Liste von Strings“ ist:\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## Set-Typen { #set-types }\n\nAber dann denken wir darüber nach und stellen fest, dass sich die Tags nicht wiederholen sollen, es sollen eindeutige Strings sein.\n\nPython hat einen Datentyp speziell für Mengen eindeutiger Dinge: das <abbr title=\"Menge\">`set`</abbr>.\n\nDeklarieren wir also `tags` als Set von Strings.\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\nJetzt, selbst wenn Sie einen <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> mit duplizierten Daten erhalten, werden diese zu einem Set eindeutiger Dinge konvertiert.\n\nUnd wann immer Sie diese Daten ausgeben, selbst wenn die Quelle Duplikate hatte, wird es als Set von eindeutigen Dingen ausgegeben.\n\nUnd es wird entsprechend annotiert/dokumentiert.\n\n## Verschachtelte Modelle { #nested-models }\n\nJedes Attribut eines Pydantic-Modells hat einen Typ.\n\nAber dieser Typ kann selbst ein anderes Pydantic-Modell sein.\n\nSie können also tief verschachtelte JSON-„Objekte“ deklarieren, mit spezifischen Attributnamen, -typen, und -validierungen.\n\nAlles das beliebig tief verschachtelt.\n\n### Ein Kindmodell definieren { #define-a-submodel }\n\nFür ein Beispiel können wir ein `Image`-Modell definieren.\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### Das Kindmodell als Typ verwenden { #use-the-submodel-as-a-type }\n\nUnd dann können wir es als Typ eines Attributes verwenden:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\nDas würde bedeuten, dass **FastAPI** einen Body wie folgt erwartet:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\nWiederum, nur mit dieser Deklaration erhalten Sie von **FastAPI**:\n\n* Editor-Unterstützung (Codevervollständigung, usw.), selbst für verschachtelte Modelle\n* Datenkonvertierung\n* Datenvalidierung\n* Automatische Dokumentation\n\n## Spezielle Typen und Validierungen { #special-types-and-validation }\n\nAbgesehen von normalen einfachen Typen wie `str`, `int`, `float`, usw. können Sie komplexere einfache Typen verwenden, die von `str` erben.\n\nUm alle Optionen kennenzulernen, die Sie haben, schauen Sie sich [Pydantics Typübersicht](https://docs.pydantic.dev/latest/concepts/types/) an. Sie werden einige Beispiele im nächsten Kapitel kennenlernen.\n\nZum Beispiel, da wir im `Image`-Modell ein Feld `url` haben, können wir deklarieren, dass das eine Instanz von Pydantics `HttpUrl` sein soll, anstelle eines `str`:\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\nEs wird getestet, ob der String eine gültige URL ist, und als solche wird er in JSON Schema / OpenAPI dokumentiert.\n\n## Attribute mit Listen von Kindmodellen { #attributes-with-lists-of-submodels }\n\nSie können Pydantic-Modelle auch als Typen innerhalb von `list`, `set`, usw. verwenden:\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\nDas wird einen JSON-Body erwarten (konvertieren, validieren, dokumentieren, usw.) wie:\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info | Info\n\nBeachten Sie, dass der `images`-Schlüssel jetzt eine Liste von Bild-Objekten hat.\n\n///\n\n## Tief verschachtelte Modelle { #deeply-nested-models }\n\nSie können beliebig tief verschachtelte Modelle definieren:\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info | Info\n\nBeachten Sie, wie `Offer` eine Liste von `Item`s hat, die ihrerseits eine optionale Liste von `Image`s haben.\n\n///\n\n## Bodys aus reinen Listen { #bodies-of-pure-lists }\n\nWenn das äußerste Element des JSON-Bodys, das Sie erwarten, ein JSON-`array` (eine Python-`list`) ist, können Sie den Typ im Funktionsparameter deklarieren, mit der gleichen Syntax wie in Pydantic-Modellen:\n\n```Python\nimages: list[Image]\n```\n\nso wie in:\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## Editor-Unterstützung überall { #editor-support-everywhere }\n\nUnd Sie erhalten Editor-Unterstützung überall.\n\nSelbst für Dinge in Listen:\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\nSie würden diese Editor-Unterstützung nicht erhalten, wenn Sie direkt mit `dict`, statt mit Pydantic-Modellen arbeiten würden.\n\nAber Sie müssen sich auch nicht weiter um die Modelle kümmern, hereinkommende Dicts werden automatisch in sie konvertiert. Und was Sie zurückgeben, wird automatisch nach JSON konvertiert.\n\n## Bodys mit beliebigen `dict`s { #bodies-of-arbitrary-dicts }\n\nSie können einen Body auch als `dict` deklarieren, mit Schlüsseln eines Typs und Werten eines anderen Typs.\n\nSo brauchen Sie vorher nicht zu wissen, wie die Feld-/Attributnamen lauten (wie es bei Pydantic-Modellen der Fall wäre).\n\nDas ist nützlich, wenn Sie Schlüssel empfangen, deren Namen Sie nicht bereits kennen.\n\n---\n\nEin anderer nützlicher Anwendungsfall ist, wenn Sie Schlüssel eines anderen Typs haben wollen, z. B. `int`.\n\nDas schauen wir uns mal an.\n\nIm folgenden Beispiel akzeptieren Sie irgendein `dict`, solange es `int`-Schlüssel und `float`-Werte hat:\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip | Tipp\n\nBedenken Sie, dass JSON nur `str` als Schlüssel unterstützt.\n\nAber Pydantic hat automatische Datenkonvertierung.\n\nDas bedeutet, dass Ihre API-Clients nur Strings senden können, aber solange diese Strings nur Zahlen enthalten, wird Pydantic sie konvertieren und validieren.\n\nUnd das `dict`, welches Sie als `weights` erhalten, wird `int`-Schlüssel und `float`-Werte haben.\n\n///\n\n## Zusammenfassung { #recap }\n\nMit **FastAPI** haben Sie die maximale Flexibilität von Pydantic-Modellen, während Ihr Code einfach, kurz und elegant bleibt.\n\nAber mit all den Vorzügen:\n\n* Editor-Unterstützung (Codevervollständigung überall)\n* Datenkonvertierung (auch bekannt als Parsen, Serialisierung)\n* Datenvalidierung\n* Schema-Dokumentation\n* Automatische Dokumentation\n"
  },
  {
    "path": "docs/de/docs/tutorial/body-updates.md",
    "content": "# Body – Aktualisierungen { #body-updates }\n\n## Ersetzendes Aktualisieren mit `PUT` { #update-replacing-with-put }\n\nUm einen Artikel zu aktualisieren, können Sie die [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) Operation verwenden.\n\nSie können den `jsonable_encoder` verwenden, um die empfangenen Daten in etwas zu konvertieren, das als JSON gespeichert werden kann (z. B. in einer NoSQL-Datenbank). Zum Beispiel, um ein `datetime` in einen `str` zu konvertieren.\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT` wird verwendet, um Daten zu empfangen, die die existierenden Daten ersetzen sollen.\n\n### Warnung bezüglich des Ersetzens { #warning-about-replacing }\n\nDas bedeutet, dass, wenn Sie den Artikel `bar` aktualisieren wollen, mittels `PUT` und folgendem Body:\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\nweil das bereits gespeicherte Attribut `\"tax\": 20.2` nicht enthalten ist, das Eingabemodell den Defaultwert `\"tax\": 10.5` erhalten würde.\n\nUnd die Daten würden mit diesem „neuen“ `tax` von `10.5` gespeichert werden.\n\n## Teil-Aktualisierungen mit `PATCH` { #partial-updates-with-patch }\n\nSie können auch die [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) Operation verwenden, um Daten *teilweise* zu ersetzen.\n\nDas bedeutet, Sie senden nur die Daten, die Sie aktualisieren wollen, der Rest bleibt unverändert.\n\n/// note | Hinweis\n\n`PATCH` wird seltener verwendet und ist weniger bekannt als `PUT`.\n\nUnd viele Teams verwenden ausschließlich `PUT`, selbst für nur Teil-Aktualisierungen.\n\nEs steht Ihnen **frei**, das zu verwenden, was Sie möchten, **FastAPI** legt Ihnen keine Einschränkungen auf.\n\nAber dieser Leitfaden zeigt Ihnen mehr oder weniger, wie die beiden normalerweise verwendet werden.\n\n///\n\n### Pydantics `exclude_unset`-Parameter verwenden { #using-pydantics-exclude-unset-parameter }\n\nWenn Sie Teil-Aktualisierungen entgegennehmen, ist der `exclude_unset`-Parameter in der `.model_dump()`-Methode von Pydantic-Modellen sehr nützlich.\n\nWie in `item.model_dump(exclude_unset=True)`.\n\nDas wird ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr> erstellen, mit nur den Daten, die gesetzt wurden, als das `item`-Modell erstellt wurde, Defaultwerte ausgeschlossen.\n\nSie können das verwenden, um ein `dict` zu erstellen, das nur die (im <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr>) gesendeten Daten enthält, ohne Defaultwerte:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### Pydantics `update`-Parameter verwenden { #using-pydantics-update-parameter }\n\nJetzt können Sie eine Kopie des existierenden Modells mittels `.model_copy()` erstellen, wobei Sie dem `update`-Parameter ein `dict` mit den zu ändernden Daten übergeben.\n\nWie in `stored_item_model.model_copy(update=update_data)`:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### Rekapitulation zu Teil-Aktualisierungen { #partial-updates-recap }\n\nZusammengefasst, um Teil-Aktualisierungen vorzunehmen:\n\n* (Optional) verwenden Sie `PATCH` statt `PUT`.\n* Lesen Sie die bereits gespeicherten Daten aus.\n* Fügen Sie diese in ein Pydantic-Modell ein.\n* Erzeugen Sie aus dem empfangenen Modell ein `dict` ohne Defaultwerte (mittels `exclude_unset`).\n    * So ersetzen Sie nur die tatsächlich vom Benutzer gesetzten Werte, statt dass bereits gespeicherte Werte mit Defaultwerten des Modells überschrieben werden.\n* Erzeugen Sie eine Kopie ihres gespeicherten Modells, wobei Sie die Attribute mit den empfangenen Teil-Ersetzungen aktualisieren (mittels des `update`-Parameters).\n* Konvertieren Sie das kopierte Modell zu etwas, das in Ihrer Datenbank gespeichert werden kann (indem Sie beispielsweise `jsonable_encoder` verwenden).\n    * Das ist vergleichbar dazu, die `.model_dump()`-Methode des Modells erneut aufzurufen, aber es wird sicherstellen, dass die Werte zu Daten konvertiert werden, die ihrerseits zu JSON konvertiert werden können, zum Beispiel `datetime` zu `str`.\n* Speichern Sie die Daten in Ihrer Datenbank.\n* Geben Sie das aktualisierte Modell zurück.\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | Tipp\n\nSie können tatsächlich die gleiche Technik mit einer HTTP `PUT` Operation verwenden.\n\nAber dieses Beispiel verwendet `PATCH`, da dieses für solche Anwendungsfälle geschaffen wurde.\n\n///\n\n/// note | Hinweis\n\nBeachten Sie, dass das hereinkommende Modell immer noch validiert wird.\n\nWenn Sie also Teil-Aktualisierungen empfangen wollen, die alle Attribute auslassen können, müssen Sie ein Modell haben, dessen Attribute alle als optional gekennzeichnet sind (mit Defaultwerten oder `None`).\n\nUm zu unterscheiden zwischen Modellen für **Aktualisierungen**, mit lauter optionalen Werten, und solchen für die **Erzeugung**, mit benötigten Werten, können Sie die Techniken verwenden, die in [Extramodelle](extra-models.md) beschrieben wurden.\n\n///\n"
  },
  {
    "path": "docs/de/docs/tutorial/body.md",
    "content": "# Requestbody { #request-body }\n\nWenn Sie Daten von einem <abbr title=\"Client: Eine Software, die sich mit einem Server verbindet.\">Client</abbr> (sagen wir, einem Browser) zu Ihrer API senden müssen, senden Sie sie als **Requestbody**.\n\nEin <abbr title=\"Anfragekörper\">**Request**body</abbr> sind Daten, die vom Client zu Ihrer API gesendet werden. Ein <abbr title=\"Antwortkörper\">**Response**body</abbr> sind Daten, die Ihre API zum Client sendet.\n\nIhre API muss fast immer einen **Response**body senden. Aber Clients müssen nicht unbedingt immer **Requestbodys** senden, manchmal fordern sie nur einen Pfad an, vielleicht mit einigen Query-Parametern, aber senden keinen Body.\n\nUm einen **Request**body zu deklarieren, verwenden Sie [Pydantic](https://docs.pydantic.dev/)-Modelle mit all deren Fähigkeiten und Vorzügen.\n\n/// info | Info\n\nUm Daten zu senden, sollten Sie eines von: `POST` (meistverwendet), `PUT`, `DELETE` oder `PATCH` verwenden.\n\nDas Senden eines Bodys mit einem `GET`-Request hat ein undefiniertes Verhalten in den Spezifikationen, wird aber dennoch von FastAPI unterstützt, nur für sehr komplexe/extreme Anwendungsfälle.\n\nDa davon abgeraten wird, zeigt die interaktive Dokumentation mit Swagger-Benutzeroberfläche die Dokumentation für den Body nicht an, wenn `GET` verwendet wird, und zwischengeschaltete Proxys unterstützen es möglicherweise nicht.\n\n///\n\n## Pydantics `BaseModel` importieren { #import-pydantics-basemodel }\n\nZuerst müssen Sie `BaseModel` von `pydantic` importieren:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## Ihr Datenmodell erstellen { #create-your-data-model }\n\nDann deklarieren Sie Ihr Datenmodell als eine Klasse, die von `BaseModel` erbt.\n\nVerwenden Sie Standard-Python-Typen für alle Attribute:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\nWie auch bei der Deklaration von Query-Parametern gilt: Wenn ein Modellattribut einen Defaultwert hat, ist das Attribut nicht erforderlich. Andernfalls ist es erforderlich. Verwenden Sie `None`, um es einfach optional zu machen.\n\nZum Beispiel deklariert das obige Modell ein JSON „`object`“ (oder Python-<abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr>) wie dieses:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\nDa `description` und `tax` optional sind (mit `None` als Defaultwert), wäre folgendes JSON „`object`“ auch gültig:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## Als Parameter deklarieren { #declare-it-as-a-parameter }\n\nUm es zu Ihrer *Pfadoperation* hinzuzufügen, deklarieren Sie es auf die gleiche Weise, wie Sie Pfad- und Query-Parameter deklariert haben:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n... und deklarieren Sie dessen Typ als das Modell, welches Sie erstellt haben, `Item`.\n\n## Resultate { #results }\n\nMit nur dieser Python-Typdeklaration wird **FastAPI**:\n\n* Den Requestbody als JSON lesen.\n* Die entsprechenden Typen konvertieren (falls nötig).\n* Diese Daten validieren.\n    * Wenn die Daten ungültig sind, wird ein klar lesbarer Fehler zurückgegeben, der genau anzeigt, wo und was die inkorrekten Daten sind.\n* Ihnen die erhaltenen Daten im Parameter `item` übergeben.\n    * Da Sie ihn in der Funktion als vom Typ `Item` deklariert haben, erhalten Sie auch die volle Unterstützung des Editors (Autovervollständigung, usw.) für alle Attribute und deren Typen.\n* [JSON Schema](https://json-schema.org)-Definitionen für Ihr Modell generieren, die Sie auch überall sonst verwenden können, wenn es für Ihr Projekt Sinn macht.\n* Diese Schemas werden Teil des generierten OpenAPI-Schemas und werden von den <abbr title=\"User Interfaces - Benutzeroberflächen\">UIs</abbr> der automatischen Dokumentation genutzt.\n\n## Automatische Dokumentation { #automatic-docs }\n\nDie JSON-Schemas Ihrer Modelle werden Teil Ihres OpenAPI-generierten Schemas und in der interaktiven API-Dokumentation angezeigt:\n\n<img src=\"/img/tutorial/body/image01.png\">\n\nUnd werden auch in der API-Dokumentation innerhalb jeder *Pfadoperation*, die sie benötigt, verwendet:\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## Editor-Unterstützung { #editor-support }\n\nIn Ihrem Editor erhalten Sie innerhalb Ihrer Funktion Typhinweise und Code-Vervollständigung überall (was nicht der Fall wäre, wenn Sie ein `dict` anstelle eines Pydantic-Modells erhalten hätten):\n\n<img src=\"/img/tutorial/body/image03.png\">\n\nSie bekommen auch Fehlermeldungen für inkorrekte Typoperationen:\n\n<img src=\"/img/tutorial/body/image04.png\">\n\nDas ist nicht zufällig so, das ganze Framework wurde um dieses Design herum aufgebaut.\n\nUnd es wurde in der Designphase gründlich getestet, bevor irgendeine Implementierung stattfand, um sicherzustellen, dass es mit allen Editoren funktioniert.\n\nEs gab sogar einige Änderungen an Pydantic selbst, um dies zu unterstützen.\n\nDie vorherigen Screenshots wurden mit [Visual Studio Code](https://code.visualstudio.com) aufgenommen.\n\nAber Sie würden die gleiche Editor-Unterstützung in [PyCharm](https://www.jetbrains.com/pycharm/) und den meisten anderen Python-Editoren erhalten:\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip | Tipp\n\nWenn Sie [PyCharm](https://www.jetbrains.com/pycharm/) als Ihren Editor verwenden, können Sie das [Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/) ausprobieren.\n\nEs verbessert die Editor-Unterstützung für Pydantic-Modelle, mit:\n\n* Code-Vervollständigung\n* Typüberprüfungen\n* Refaktorisierung\n* Suche\n* Inspektionen\n\n///\n\n## Das Modell verwenden { #use-the-model }\n\nInnerhalb der Funktion können Sie alle Attribute des Modellobjekts direkt verwenden:\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## Requestbody- + Pfad-Parameter { #request-body-path-parameters }\n\nSie können Pfad-Parameter und den Requestbody gleichzeitig deklarieren.\n\n**FastAPI** erkennt, dass Funktionsparameter, die mit Pfad-Parametern übereinstimmen, **vom Pfad genommen** werden sollen, und dass Funktionsparameter, welche Pydantic-Modelle sind, **vom Requestbody genommen** werden sollen.\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n\n## Requestbody- + Pfad- + Query-Parameter { #request-body-path-query-parameters }\n\nSie können auch zur gleichen Zeit **Body-**, **Pfad-** und **Query-Parameter** deklarieren.\n\n**FastAPI** wird jeden von ihnen korrekt erkennen und die Daten vom richtigen Ort holen.\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\nDie Funktionsparameter werden wie folgt erkannt:\n\n* Wenn der Parameter auch im **Pfad** deklariert wurde, wird er als Pfad-Parameter verwendet.\n* Wenn der Parameter ein **einfacher Typ** ist (wie `int`, `float`, `str`, `bool`, usw.), wird er als **Query**-Parameter interpretiert.\n* Wenn der Parameter vom Typ eines **Pydantic-Modells** ist, wird er als Request**body** interpretiert.\n\n/// note | Hinweis\n\nFastAPI weiß, dass der Wert von `q` nicht erforderlich ist, aufgrund des definierten Defaultwertes `= None`.\n\nDas `str | None` wird von FastAPI nicht verwendet, um zu bestimmen, dass der Wert nicht erforderlich ist. FastAPI weiß, dass er nicht erforderlich ist, weil er einen Defaultwert von `= None` hat.\n\nDas Hinzufügen der Typannotationen ermöglicht jedoch Ihrem Editor, Ihnen eine bessere Unterstützung zu bieten und Fehler zu erkennen.\n\n///\n\n## Ohne Pydantic { #without-pydantic }\n\nWenn Sie keine Pydantic-Modelle verwenden möchten, können Sie auch **Body**-Parameter verwenden. Siehe die Dokumentation unter [Body – Mehrere Parameter: Einfache Werte im Body](body-multiple-params.md#singular-values-in-body).\n"
  },
  {
    "path": "docs/de/docs/tutorial/cookie-param-models.md",
    "content": "# Cookie-Parameter-Modelle { #cookie-parameter-models }\n\nWenn Sie eine Gruppe von **Cookies** haben, die zusammengehören, können Sie ein **Pydantic-Modell** erstellen, um diese zu deklarieren. 🍪\n\nDamit können Sie das Modell an **mehreren Stellen wiederverwenden** und auch Validierungen und Metadaten für alle Parameter gleichzeitig deklarieren. 😎\n\n/// note | Hinweis\n\nDies wird seit FastAPI Version `0.115.0` unterstützt. 🤓\n\n///\n\n/// tip | Tipp\n\nDiese gleiche Technik gilt für `Query`, `Cookie` und `Header`. 😎\n\n///\n\n## Cookies mit einem Pydantic-Modell { #cookies-with-a-pydantic-model }\n\nDeklarieren Sie die **Cookie**-Parameter, die Sie benötigen, in einem **Pydantic-Modell**, und deklarieren Sie dann den Parameter als `Cookie`:\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI** wird die Daten für **jedes Feld** aus den im <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> empfangenen **Cookies** **extrahieren** und Ihnen das von Ihnen definierte Pydantic-Modell bereitstellen.\n\n## Die Dokumentation testen { #check-the-docs }\n\nSie können die definierten Cookies in der Dokumentationsoberfläche unter `/docs` sehen:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info | Info\n\nBitte beachten Sie, dass Browser Cookies auf spezielle Weise und im Hintergrund bearbeiten, sodass sie **nicht** leicht **JavaScript** erlauben, diese zu berühren.\n\nWenn Sie zur **API-Dokumentationsoberfläche** unter `/docs` gehen, können Sie die **Dokumentation** für Cookies für Ihre *Pfadoperationen* sehen.\n\nAber selbst wenn Sie die **Daten ausfüllen** und auf „Ausführen“ klicken, werden aufgrund der Tatsache, dass die Dokumentationsoberfläche mit **JavaScript** arbeitet, die Cookies nicht gesendet, und Sie werden eine **Fehlermeldung** sehen, als ob Sie keine Werte eingegeben hätten.\n\n///\n\n## Zusätzliche Cookies verbieten { #forbid-extra-cookies }\n\nIn einigen speziellen Anwendungsfällen (wahrscheinlich nicht sehr häufig) möchten Sie möglicherweise die Cookies, die Sie empfangen möchten, **einschränken**.\n\nIhre API hat jetzt die Macht, ihre eigene <dfn title=\"Das ist ein Scherz, nur für den Fall. Es hat nichts mit Cookie-Einwilligungen zu tun, aber es ist witzig, dass selbst die API jetzt die armen Cookies ablehnen kann. Haben Sie einen Keks. 🍪\">Cookie-Einwilligung</dfn> zu kontrollieren. 🤪🍪\n\nSie können die Modellkonfiguration von Pydantic verwenden, um `extra` Felder zu verbieten (`forbid`):\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\nWenn ein Client versucht, einige **zusätzliche Cookies** zu senden, erhält er eine **Error-<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>**.\n\nArme Cookie-Banner, wie sie sich mühen, Ihre Einwilligung zu erhalten, dass die <dfn title=\"Das ist ein weiterer Scherz. Beachten Sie mich nicht. Trinken Sie einen Kaffee zu Ihrem Keks. ☕\">API sie ablehnen darf</dfn>. 🍪\n\nWenn der Client beispielsweise versucht, ein `santa_tracker`-Cookie mit einem Wert von `good-list-please` zu senden, erhält der Client eine **Error-Response**, die ihm mitteilt, dass das `santa_tracker` <dfn title=\"Santa missbilligt den Mangel an Cookies. 🎅 Okay, keine Cookie-Witze mehr.\">Cookie nicht erlaubt ist</dfn>:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## Zusammenfassung { #summary }\n\nSie können **Pydantic-Modelle** verwenden, um <dfn title=\"Nehmen Sie einen letzten Keks, bevor Sie gehen. 🍪\">**Cookies**</dfn> in **FastAPI** zu deklarieren. 😎\n"
  },
  {
    "path": "docs/de/docs/tutorial/cookie-params.md",
    "content": "# Cookie-Parameter { #cookie-parameters }\n\nSie können Cookie-Parameter auf die gleiche Weise definieren wie `Query`- und `Path`-Parameter.\n\n## `Cookie` importieren { #import-cookie }\n\nImportieren Sie zuerst `Cookie`:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## `Cookie`-Parameter deklarieren { #declare-cookie-parameters }\n\nDeklarieren Sie dann die Cookie-Parameter mit derselben Struktur wie bei `Path` und `Query`.\n\nSie können den Defaultwert sowie alle zusätzlichen Validierungen oder Annotierungsparameter definieren:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Technische Details\n\n`Cookie` ist eine „Schwester“-Klasse von `Path` und `Query`. Sie erbt auch von derselben gemeinsamen `Param`-Klasse.\n\nAber denken Sie daran, dass, wenn Sie `Query`, `Path`, `Cookie` und andere von `fastapi` importieren, diese tatsächlich Funktionen sind, die spezielle Klassen zurückgeben.\n\n///\n\n/// info | Info\n\nUm Cookies zu deklarieren, müssen Sie `Cookie` verwenden, da die Parameter sonst als Query-Parameter interpretiert würden.\n\n///\n\n/// info | Info\n\nBeachten Sie, dass **Browser Cookies auf besondere Weise und hinter den Kulissen handhaben** und **JavaScript** **nicht** ohne Weiteres erlauben, auf sie zuzugreifen.\n\nWenn Sie zur **API-Dokumentations-UI** unter `/docs` gehen, können Sie die **Dokumentation** zu Cookies für Ihre *Pfadoperationen* sehen.\n\nAber selbst wenn Sie die **Daten ausfüllen** und auf „Execute“ klicken, da die Dokumentations-UI mit **JavaScript** arbeitet, werden die Cookies nicht gesendet, und Sie sehen eine **Fehler**-Meldung, als hätten Sie keine Werte eingegeben.\n\n///\n\n## Zusammenfassung { #recap }\n\nDeklarieren Sie Cookies mit `Cookie` und verwenden Sie dabei das gleiche allgemeine Muster wie bei `Query` und `Path`.\n"
  },
  {
    "path": "docs/de/docs/tutorial/cors.md",
    "content": "# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }\n\n[CORS oder <abbr title=\"Ressourcenfreigabe zwischen Ursprüngen\">„Cross-Origin Resource Sharing“</abbr>](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) bezieht sich auf Situationen, in denen ein Frontend, das in einem Browser läuft, JavaScript-Code enthält, der mit einem Backend kommuniziert, und das Backend sich in einem anderen „Origin“ als das Frontend befindet.\n\n## Origin { #origin }\n\nEin <abbr title=\"Ursprung\">Origin</abbr> ist die Kombination aus Protokoll (`http`, `https`), Domain (`myapp.com`, `localhost`, `localhost.tiangolo.com`) und Port (`80`, `443`, `8080`).\n\nAlle folgenden sind also unterschiedliche Origins:\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\nAuch wenn sie alle in `localhost` sind, verwenden sie unterschiedliche Protokolle oder Ports, daher sind sie unterschiedliche „Origins“.\n\n## Schritte { #steps }\n\nAngenommen, Sie haben ein Frontend, das in Ihrem Browser unter `http://localhost:8080` läuft, und dessen JavaScript versucht, mit einem Backend zu kommunizieren, das unter `http://localhost` läuft (da wir keinen Port angegeben haben, geht der Browser vom Default-Port `80` aus).\n\nDann wird der Browser ein HTTP-`OPTIONS`-<abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> an das `:80`-Backend senden, und wenn das Backend die entsprechenden Header sendet, die die Kommunikation von diesem anderen Origin (`http://localhost:8080`) autorisieren, lässt der `:8080`-Browser das JavaScript im Frontend seinen Request an das `:80`-Backend senden.\n\nUm dies zu erreichen, muss das `:80`-Backend eine Liste von „erlaubten Origins“ haben.\n\nIn diesem Fall müsste die Liste `http://localhost:8080` enthalten, damit das `:8080`-Frontend korrekt funktioniert.\n\n## Wildcards { #wildcards }\n\nEs ist auch möglich, die Liste als `\"*\"` (ein „Wildcard“) zu deklarieren, um anzuzeigen, dass alle erlaubt sind.\n\nAber das erlaubt nur bestimmte Arten der Kommunikation und schließt alles aus, was Anmeldeinformationen beinhaltet: Cookies, Autorisierungsheader wie die, die mit Bearer Tokens verwendet werden, usw.\n\nUm sicherzustellen, dass alles korrekt funktioniert, ist es besser, die erlaubten Origins explizit anzugeben.\n\n## `CORSMiddleware` verwenden { #use-corsmiddleware }\n\nSie können das in Ihrer **FastAPI**-Anwendung mit der `CORSMiddleware` konfigurieren.\n\n* Importieren Sie `CORSMiddleware`.\n* Erstellen Sie eine Liste der erlaubten Origins (als Strings).\n* Fügen Sie es als „Middleware“ zu Ihrer **FastAPI**-Anwendung hinzu.\n\nSie können auch angeben, ob Ihr Backend erlaubt:\n\n* Anmeldeinformationen (Autorisierungsheader, Cookies, usw.).\n* Bestimmte HTTP-Methoden (`POST`, `PUT`) oder alle mit der Wildcard `\"*\"`.\n* Bestimmte HTTP-Header oder alle mit der Wildcard `\"*\"`.\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\nDie von der `CORSMiddleware`-Implementierung verwendeten Defaultparameter sind standardmäßig restriktiv, daher müssen Sie bestimmte Origins, Methoden oder Header ausdrücklich aktivieren, damit Browser sie in einem Cross-Domain-Kontext verwenden dürfen.\n\nDie folgenden Argumente werden unterstützt:\n\n* `allow_origins` – Eine Liste von Origins, die Cross-Origin-Requests machen dürfen. z. B. `['https://example.org', 'https://www.example.org']`. Sie können `['*']` verwenden, um jedes Origin zuzulassen.\n* `allow_origin_regex` – Ein Regex-String zum Abgleichen gegen Origins, die Cross-Origin-Requests machen dürfen. z. B. `'https://.*\\.example\\.org'`.\n* `allow_methods` – Eine Liste von HTTP-Methoden, die für Cross-Origin-Requests erlaubt sein sollen. Standardmäßig `['GET']`. Sie können `['*']` verwenden, um alle Standardmethoden zu erlauben.\n* `allow_headers` – Eine Liste von HTTP-Requestheadern, die für Cross-Origin-Requests unterstützt werden sollten. Standardmäßig `[]`. Sie können `['*']` verwenden, um alle Header zu erlauben. Die Header `Accept`, `Accept-Language`, `Content-Language` und `Content-Type` sind immer für [einfache CORS-Requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests) erlaubt.\n* `allow_credentials` – Anzeigen, dass Cookies für Cross-Origin-Requests unterstützt werden sollten. Standardmäßig `False`.\n\n    Keines der `allow_origins`, `allow_methods` und `allow_headers` kann auf `['*']` gesetzt werden, wenn `allow_credentials` auf `True` gesetzt ist. Alle müssen [explizit angegeben](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards) werden.\n\n* `expose_headers` – Angabe der Responseheader, auf die der Browser zugreifen können soll. Standardmäßig `[]`.\n* `max_age` – Legt eine maximale Zeit in Sekunden fest, die Browser CORS-Responses zwischenspeichern dürfen. Standardmäßig `600`.\n\nDie Middleware antwortet auf zwei besondere Arten von HTTP-Requests ...\n\n### CORS-Preflight-Requests { #cors-preflight-requests }\n\nDies sind alle `OPTIONS`-Requests mit `Origin`- und `Access-Control-Request-Method`-Headern.\n\nIn diesem Fall wird die Middleware den eingehenden Request abfangen und mit entsprechenden CORS-Headern, und entweder einer `200`- oder `400`-<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> zu Informationszwecken antworten.\n\n### Einfache Requests { #simple-requests }\n\nJeder Request mit einem `Origin`-Header. In diesem Fall wird die Middleware den Request wie gewohnt durchlassen, aber entsprechende CORS-Header in die Response aufnehmen.\n\n## Weitere Informationen { #more-info }\n\nWeitere Informationen zu <abbr title=\"Cross-Origin Resource Sharing – Ressourcenfreigabe zwischen Ursprüngen\">CORS</abbr> finden Sie in der [Mozilla CORS-Dokumentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).\n\n/// note | Technische Details\n\nSie könnten auch `from starlette.middleware.cors import CORSMiddleware` verwenden.\n\n**FastAPI** bietet mehrere Middlewares in `fastapi.middleware` nur als Komfort für Sie, den Entwickler. Aber die meisten der verfügbaren Middlewares stammen direkt von Starlette.\n\n///\n"
  },
  {
    "path": "docs/de/docs/tutorial/debugging.md",
    "content": "# Debugging { #debugging }\n\nSie können den Debugger in Ihrem Editor verbinden, zum Beispiel mit Visual Studio Code oder PyCharm.\n\n## `uvicorn` aufrufen { #call-uvicorn }\n\nImportieren und führen Sie `uvicorn` direkt in Ihrer FastAPI-Anwendung aus:\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### Über `__name__ == \"__main__\"` { #about-name-main }\n\nDer Hauptzweck von `__name__ == \"__main__\"` ist, dass Code ausgeführt wird, wenn Ihre Datei mit folgendem Befehl aufgerufen wird:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\naber nicht aufgerufen wird, wenn eine andere Datei sie importiert, wie in:\n\n```Python\nfrom myapp import app\n```\n\n#### Weitere Details { #more-details }\n\nAngenommen, Ihre Datei heißt `myapp.py`.\n\nWenn Sie sie mit folgendem Befehl ausführen:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\ndann hat in Ihrer Datei die interne Variable `__name__`, die von Python automatisch erstellt wird, als Wert den String `\"__main__\"`.\n\nDaher wird der Abschnitt:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nausgeführt.\n\n---\n\nDies wird nicht passieren, wenn Sie das Modul (die Datei) importieren.\n\nWenn Sie also eine weitere Datei `importer.py` mit folgendem Inhalt haben:\n\n```Python\nfrom myapp import app\n\n# Hier mehr Code\n```\n\nwird in diesem Fall in `myapp.py` die automatisch erstellte Variable `__name__` nicht den Wert `\"__main__\"` haben.\n\nDaher wird die Zeile:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nnicht ausgeführt.\n\n/// info | Info\n\nFür weitere Informationen besuchen Sie bitte [die offizielle Python-Dokumentation](https://docs.python.org/3/library/__main__.html).\n\n///\n\n## Ihren Code mit Ihrem Debugger ausführen { #run-your-code-with-your-debugger }\n\nDa Sie den Uvicorn-Server direkt aus Ihrem Code ausführen, können Sie Ihr Python-Programm (Ihre FastAPI-Anwendung) direkt aus dem Debugger aufrufen.\n\n---\n\nZum Beispiel können Sie in Visual Studio Code:\n\n* Zum „Debug“-Panel gehen.\n* „Konfiguration hinzufügen ...“ auswählen.\n* „Python“ auswählen.\n* Den Debugger mit der Option „`Python: Current File (Integrated Terminal)`“ ausführen.\n\nDer Server wird dann mit Ihrem **FastAPI**-Code gestartet, an Ihren Haltepunkten angehalten, usw.\n\nSo könnte es aussehen:\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\nWenn Sie Pycharm verwenden, können Sie:\n\n* Das Menü „Run“ öffnen.\n* Die Option „Debug ...“ auswählen.\n* Ein Kontextmenü wird angezeigt.\n* Die zu debuggende Datei auswählen (in diesem Fall `main.py`).\n\nDer Server wird dann mit Ihrem **FastAPI**-Code gestartet, an Ihren Haltepunkten angehalten, usw.\n\nSo könnte es aussehen:\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/de/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# Klassen als Abhängigkeiten { #classes-as-dependencies }\n\nBevor wir tiefer in das **Dependency Injection** System eintauchen, lassen Sie uns das vorherige Beispiel verbessern.\n\n## Ein `dict` aus dem vorherigen Beispiel { #a-dict-from-the-previous-example }\n\nIm vorherigen Beispiel haben wir ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr> von unserer Abhängigkeit („Dependable“) zurückgegeben:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\nAber dann haben wir ein `dict` im Parameter `commons` der *Pfadoperation-Funktion*.\n\nUnd wir wissen, dass Editoren nicht viel Unterstützung (wie etwa Code-Vervollständigung) für `dict`s bieten können, weil sie ihre Schlüssel- und Werttypen nicht kennen.\n\nDas können wir besser machen ...\n\n## Was macht eine Abhängigkeit aus { #what-makes-a-dependency }\n\nBisher haben Sie Abhängigkeiten gesehen, die als Funktionen deklariert wurden.\n\nDas ist jedoch nicht die einzige Möglichkeit, Abhängigkeiten zu deklarieren (obwohl es wahrscheinlich die gebräuchlichste ist).\n\nDer springende Punkt ist, dass eine Abhängigkeit aufrufbar („callable“) sein sollte.\n\nEin „**Callable**“ in Python ist etwas, das wie eine Funktion aufgerufen werden kann („to call“).\n\nWenn Sie also ein Objekt `something` haben (das möglicherweise _keine_ Funktion ist) und Sie es wie folgt aufrufen (ausführen) können:\n\n```Python\nsomething()\n```\n\noder\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\ndann ist das ein „Callable“ (ein „Aufrufbares“).\n\n## Klassen als Abhängigkeiten { #classes-as-dependencies_1 }\n\nMöglicherweise stellen Sie fest, dass Sie zum Erstellen einer Instanz einer Python-Klasse die gleiche Syntax verwenden.\n\nZum Beispiel:\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\nIn diesem Fall ist `fluffy` eine Instanz der Klasse `Cat`.\n\nUnd um `fluffy` zu erzeugen, rufen Sie `Cat` auf.\n\nEine Python-Klasse ist also auch ein **Callable**.\n\nDarum können Sie in **FastAPI** auch eine Python-Klasse als Abhängigkeit verwenden.\n\nWas FastAPI tatsächlich prüft, ist, ob es sich um ein „Callable“ (Funktion, Klasse oder irgendetwas anderes) handelt und ob die Parameter definiert sind.\n\nWenn Sie **FastAPI** ein „Callable“ als Abhängigkeit übergeben, analysiert es die Parameter dieses „Callables“ und verarbeitet sie auf die gleiche Weise wie die Parameter einer *Pfadoperation-Funktion*. Einschließlich Unterabhängigkeiten.\n\nDas gilt auch für Callables ohne Parameter. So wie es auch für *Pfadoperation-Funktionen* ohne Parameter gilt.\n\nDann können wir das „Dependable“ `common_parameters` der Abhängigkeit von oben in die Klasse `CommonQueryParams` ändern:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\nAchten Sie auf die Methode `__init__`, die zum Erstellen der Instanz der Klasse verwendet wird:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n... sie hat die gleichen Parameter wie unsere vorherige `common_parameters`:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\nDiese Parameter werden von **FastAPI** verwendet, um die Abhängigkeit „aufzulösen“.\n\nIn beiden Fällen wird sie haben:\n\n* Einen optionalen `q`-Query-Parameter, der ein `str` ist.\n* Einen `skip`-Query-Parameter, der ein `int` ist, mit einem Defaultwert `0`.\n* Einen `limit`-Query-Parameter, der ein `int` ist, mit einem Defaultwert `100`.\n\nIn beiden Fällen werden die Daten konvertiert, validiert, im OpenAPI-Schema dokumentiert, usw.\n\n## Verwenden { #use-it }\n\nJetzt können Sie Ihre Abhängigkeit mithilfe dieser Klasse deklarieren.\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI** ruft die Klasse `CommonQueryParams` auf. Dadurch wird eine „Instanz“ dieser Klasse erstellt und die Instanz wird als Parameter `commons` an Ihre Funktion überreicht.\n\n## Typannotation vs. `Depends` { #type-annotation-vs-depends }\n\nBeachten Sie, wie wir `CommonQueryParams` im obigen Code zweimal schreiben:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ nicht annotiert\n\n/// tip | Tipp\n\nBevorzugen Sie die `Annotated`-Version, falls möglich.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\nDas letzte `CommonQueryParams`, in:\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n... ist das, was **FastAPI** tatsächlich verwendet, um die Abhängigkeit zu ermitteln.\n\nAus diesem extrahiert FastAPI die deklarierten Parameter, und dieses ist es, was FastAPI auch aufruft.\n\n---\n\nIn diesem Fall hat das erste `CommonQueryParams` in:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ nicht annotiert\n\n/// tip | Tipp\n\nBevorzugen Sie die `Annotated`-Version, falls möglich.\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n... keine besondere Bedeutung für **FastAPI**. FastAPI verwendet es nicht für die Datenkonvertierung, -validierung, usw. (da es dafür `Depends(CommonQueryParams)` verwendet).\n\nSie könnten tatsächlich einfach schreiben:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ nicht annotiert\n\n/// tip | Tipp\n\nBevorzugen Sie die `Annotated`-Version, falls möglich.\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n... wie in:\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\nEs wird jedoch empfohlen, den Typ zu deklarieren, da Ihr Editor so weiß, was als Parameter `commons` übergeben wird, und Ihnen dann bei der Codevervollständigung, Typprüfungen, usw. helfen kann:\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## Abkürzung { #shortcut }\n\nAber Sie sehen, dass wir hier etwas Codeduplizierung haben, indem wir `CommonQueryParams` zweimal schreiben:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ nicht annotiert\n\n/// tip | Tipp\n\nBevorzugen Sie die `Annotated`-Version, falls möglich.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n**FastAPI** bietet eine Abkürzung für diese Fälle, wo die Abhängigkeit *speziell* eine Klasse ist, welche **FastAPI** aufruft, um eine Instanz der Klasse selbst zu erstellen.\n\nIn diesem speziellen Fall können Sie Folgendes tun:\n\nAnstatt zu schreiben:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ nicht annotiert\n\n/// tip | Tipp\n\nBevorzugen Sie die `Annotated`-Version, falls möglich.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n... schreiben Sie:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ nicht annotiert\n\n/// tip | Tipp\n\nBevorzugen Sie die `Annotated`-Version, falls möglich.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\nSie deklarieren die Abhängigkeit als Typ des Parameters und verwenden `Depends()` ohne Parameter, anstatt die vollständige Klasse *erneut* in `Depends(CommonQueryParams)` schreiben zu müssen.\n\nDasselbe Beispiel würde dann so aussehen:\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n... und **FastAPI** wird wissen, was zu tun ist.\n\n/// tip | Tipp\n\nWenn Sie das eher verwirrt, als Ihnen zu helfen, ignorieren Sie es, Sie *brauchen* es nicht.\n\nEs ist nur eine Abkürzung. Es geht **FastAPI** darum, Ihnen dabei zu helfen, Codeverdoppelung zu minimieren.\n\n///\n"
  },
  {
    "path": "docs/de/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# Abhängigkeiten in Pfadoperation-Dekoratoren { #dependencies-in-path-operation-decorators }\n\nManchmal benötigen Sie den Rückgabewert einer Abhängigkeit innerhalb Ihrer *Pfadoperation-Funktion* nicht wirklich.\n\nOder die Abhängigkeit gibt keinen Wert zurück.\n\nAber Sie müssen sie trotzdem ausführen/auflösen.\n\nIn diesen Fällen können Sie, anstatt einen Parameter der *Pfadoperation-Funktion* mit `Depends` zu deklarieren, eine `list` von `dependencies` zum *Pfadoperation-Dekorator* hinzufügen.\n\n## `dependencies` zum *Pfadoperation-Dekorator* hinzufügen { #add-dependencies-to-the-path-operation-decorator }\n\nDer *Pfadoperation-Dekorator* erhält ein optionales Argument `dependencies`.\n\nEs sollte eine `list` von `Depends()` sein:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\nDiese Abhängigkeiten werden auf die gleiche Weise wie normale Abhängigkeiten ausgeführt/aufgelöst. Aber ihr Wert (falls sie einen zurückgeben) wird nicht an Ihre *Pfadoperation-Funktion* übergeben.\n\n/// tip | Tipp\n\nEinige Editoren prüfen, ob Funktionsparameter nicht verwendet werden, und zeigen das als Fehler an.\n\nWenn Sie `dependencies` im *Pfadoperation-Dekorator* verwenden, stellen Sie sicher, dass sie ausgeführt werden, während gleichzeitig Ihr Editor/Ihre Tools keine Fehlermeldungen ausgeben.\n\nDamit wird auch vermieden, neue Entwickler möglicherweise zu verwirren, die einen nicht verwendeten Parameter in Ihrem Code sehen und ihn für unnötig halten könnten.\n\n///\n\n/// info | Info\n\nIn diesem Beispiel verwenden wir zwei erfundene benutzerdefinierte Header `X-Key` und `X-Token`.\n\nAber in realen Fällen würden Sie bei der Implementierung von Sicherheit mehr Vorteile durch die Verwendung der integrierten [Sicherheits-Werkzeuge (siehe nächstes Kapitel)](../security/index.md) erzielen.\n\n///\n\n## Abhängigkeitsfehler und -Rückgabewerte { #dependencies-errors-and-return-values }\n\nSie können dieselben Abhängigkeits-*Funktionen* verwenden, die Sie normalerweise verwenden.\n\n### Abhängigkeitsanforderungen { #dependency-requirements }\n\nSie können Anforderungen für einen <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> (wie Header) oder andere Unterabhängigkeiten deklarieren:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### Exceptions auslösen { #raise-exceptions }\n\nDie Abhängigkeiten können Exceptions `raise`n, genau wie normale Abhängigkeiten:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### Rückgabewerte { #return-values }\n\nUnd sie können Werte zurückgeben oder nicht, die Werte werden nicht verwendet.\n\nSie können also eine normale Abhängigkeit (die einen Wert zurückgibt), die Sie bereits an anderer Stelle verwenden, wiederverwenden, und auch wenn der Wert nicht verwendet wird, wird die Abhängigkeit ausgeführt:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## Abhängigkeiten für eine Gruppe von *Pfadoperationen* { #dependencies-for-a-group-of-path-operations }\n\nWenn Sie später lesen, wie Sie größere Anwendungen strukturieren ([Größere Anwendungen – Mehrere Dateien](../../tutorial/bigger-applications.md)), möglicherweise mit mehreren Dateien, lernen Sie, wie Sie einen einzelnen `dependencies`-Parameter für eine Gruppe von *Pfadoperationen* deklarieren.\n\n## Globale Abhängigkeiten { #global-dependencies }\n\nAls Nächstes werden wir sehen, wie man Abhängigkeiten zur gesamten `FastAPI`-Anwendung hinzufügt, sodass sie für jede *Pfadoperation* gelten.\n"
  },
  {
    "path": "docs/de/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# Abhängigkeiten mit `yield` { #dependencies-with-yield }\n\nFastAPI unterstützt Abhängigkeiten, die einige <dfn title=\"manchmal auch genannt: „Exit Code“, „Cleanup Code“, „Teardown Code“, „Closing Code“, „Kontextmanager Exit Code“, usw.\">zusätzliche Schritte nach Abschluss</dfn> ausführen.\n\nVerwenden Sie dazu `yield` statt `return` und schreiben Sie die zusätzlichen Schritte / den zusätzlichen Code danach.\n\n/// tip | Tipp\n\nStellen Sie sicher, dass Sie `yield` nur einmal pro Abhängigkeit verwenden.\n\n///\n\n/// note | Technische Details\n\nJede Funktion, die dekoriert werden kann mit:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) oder\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nkann auch als gültige **FastAPI**-Abhängigkeit verwendet werden.\n\nTatsächlich verwendet FastAPI diese beiden Dekoratoren intern.\n\n///\n\n## Eine Datenbank-Abhängigkeit mit `yield` { #a-database-dependency-with-yield }\n\nSie könnten damit beispielsweise eine Datenbanksession erstellen und diese nach Abschluss schließen.\n\nNur der Code vor und einschließlich der `yield`-Anweisung wird ausgeführt, bevor eine <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> erzeugt wird:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\nDer ge`yield`ete Wert ist das, was in *Pfadoperationen* und andere Abhängigkeiten eingefügt wird:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\nDer auf die `yield`-Anweisung folgende Code wird nach der Response ausgeführt:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip | Tipp\n\nSie können `async`- oder reguläre Funktionen verwenden.\n\n**FastAPI** wird bei jeder das Richtige tun, so wie auch bei normalen Abhängigkeiten.\n\n///\n\n## Eine Abhängigkeit mit `yield` und `try` { #a-dependency-with-yield-and-try }\n\nWenn Sie einen `try`-Block in einer Abhängigkeit mit `yield` verwenden, empfangen Sie alle Exceptions, die bei Verwendung der Abhängigkeit geworfen wurden.\n\nWenn beispielsweise ein Code irgendwann in der Mitte, in einer anderen Abhängigkeit oder in einer *Pfadoperation*, ein „Rollback“ einer Datenbanktransaktion macht oder eine andere Exception verursacht, empfangen Sie die Exception in Ihrer Abhängigkeit.\n\nSie können also mit `except SomeException` diese bestimmte Exception innerhalb der Abhängigkeit handhaben.\n\nAuf die gleiche Weise können Sie `finally` verwenden, um sicherzustellen, dass die Exit-Schritte ausgeführt werden, unabhängig davon, ob eine Exception geworfen wurde oder nicht.\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## Unterabhängigkeiten mit `yield` { #sub-dependencies-with-yield }\n\nSie können Unterabhängigkeiten und „Bäume“ von Unterabhängigkeiten beliebiger Größe und Form haben, und einige oder alle davon können `yield` verwenden.\n\n**FastAPI** stellt sicher, dass der „Exit-Code“ in jeder Abhängigkeit mit `yield` in der richtigen Reihenfolge ausgeführt wird.\n\nBeispielsweise kann `dependency_c` von `dependency_b` und `dependency_b` von `dependency_a` abhängen:\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\nUnd alle können `yield` verwenden.\n\nIn diesem Fall benötigt `dependency_c` zum Ausführen seines Exit-Codes, dass der Wert von `dependency_b` (hier `dep_b` genannt) verfügbar ist.\n\nUnd wiederum benötigt `dependency_b` den Wert von `dependency_a` (hier `dep_a` genannt) für seinen Exit-Code.\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\nAuf die gleiche Weise könnten Sie einige Abhängigkeiten mit `yield` und einige andere Abhängigkeiten mit `return` haben, und alle können beliebig voneinander abhängen.\n\nUnd Sie könnten eine einzelne Abhängigkeit haben, die auf mehreren ge`yield`eten Abhängigkeiten basiert, usw.\n\nSie können beliebige Kombinationen von Abhängigkeiten haben.\n\n**FastAPI** stellt sicher, dass alles in der richtigen Reihenfolge ausgeführt wird.\n\n/// note | Technische Details\n\nDieses funktioniert dank Pythons [Kontextmanager](https://docs.python.org/3/library/contextlib.html).\n\n**FastAPI** verwendet sie intern, um das zu erreichen.\n\n///\n\n## Abhängigkeiten mit `yield` und `HTTPException` { #dependencies-with-yield-and-httpexception }\n\nSie haben gesehen, dass Sie Abhängigkeiten mit `yield` verwenden und `try`-Blöcke haben können, die versuchen, irgendeinen Code auszuführen und dann, nach `finally`, Exit-Code ausführen.\n\nSie können auch `except` verwenden, um die geworfene Exception abzufangen und damit etwas zu tun.\n\nZum Beispiel können Sie eine andere Exception auslösen, wie `HTTPException`.\n\n/// tip | Tipp\n\nDies ist eine etwas fortgeschrittene Technik, die Sie in den meisten Fällen nicht wirklich benötigen, da Sie Exceptions (einschließlich `HTTPException`) innerhalb des restlichen Anwendungscodes auslösen können, beispielsweise in der *Pfadoperation-Funktion*.\n\nAber es ist für Sie da, wenn Sie es brauchen. 🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\nWenn Sie Exceptions abfangen und darauf basierend eine benutzerdefinierte Response erstellen möchten, erstellen Sie einen [benutzerdefinierten Exceptionhandler](../handling-errors.md#install-custom-exception-handlers).\n\n## Abhängigkeiten mit `yield` und `except` { #dependencies-with-yield-and-except }\n\nWenn Sie eine Exception mit `except` in einer Abhängigkeit mit `yield` abfangen und sie nicht erneut auslösen (oder eine neue Exception auslösen), kann FastAPI nicht feststellen, dass es eine Exception gab, genau so wie es bei normalem Python der Fall wäre:\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\nIn diesem Fall sieht der Client eine *HTTP 500 Internal Server Error*-Response, wie es sein sollte, da wir keine `HTTPException` oder Ähnliches auslösen, aber der Server hat **keine Logs** oder einen anderen Hinweis darauf, was der Fehler war. 😱\n\n### In Abhängigkeiten mit `yield` und `except` immer `raise` verwenden { #always-raise-in-dependencies-with-yield-and-except }\n\nWenn Sie eine Exception in einer Abhängigkeit mit `yield` abfangen, sollten Sie – sofern Sie nicht eine andere `HTTPException` oder Ähnliches auslösen – **die ursprüngliche Exception erneut auslösen**.\n\nSie können dieselbe Exception mit `raise` erneut auslösen:\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\nJetzt erhält der Client dieselbe *HTTP 500 Internal Server Error*-Response, aber der Server enthält unseren benutzerdefinierten `InternalError` in den Logs. 😎\n\n## Ausführung von Abhängigkeiten mit `yield` { #execution-of-dependencies-with-yield }\n\nDie Ausführungsreihenfolge ähnelt mehr oder weniger dem folgenden Diagramm. Die Zeit verläuft von oben nach unten. Und jede Spalte ist einer der interagierenden oder Code-ausführenden Teilnehmer.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exceptionhandler\nparticipant dep as Abhängigkeit mit yield\nparticipant operation as Pfadoperation\nparticipant tasks as Hintergrundtasks\n\n    Note over client,operation: Kann Exceptions auslösen, inklusive HTTPException\n    client ->> dep: Startet den Request\n    Note over dep: Führt den Code bis zum yield aus\n    opt Löst Exception aus\n        dep -->> handler: Löst Exception aus\n        handler -->> client: HTTP-Error-Response\n    end\n    dep ->> operation: Führt Abhängigkeit aus, z. B. DB-Session\n    opt Löst aus\n        operation -->> dep: Löst Exception aus (z. B. HTTPException)\n        opt Handhabt\n            dep -->> dep: Kann Exception abfangen, eine neue HTTPException auslösen, andere Exception auslösen\n        end\n        handler -->> client: HTTP-Error-Response\n    end\n\n    operation ->> client: Sendet Response an Client\n    Note over client,operation: Response wurde bereits gesendet, kann nicht mehr geändert werden\n    opt Tasks\n        operation -->> tasks: Sendet Hintergrundtasks\n    end\n    opt Löst andere Exception aus\n        tasks -->> tasks: Handhabt Exceptions im Hintergrundtask-Code\n    end\n```\n\n/// info | Info\n\nEs wird nur **eine Response** an den Client gesendet. Es kann eine Error-Response oder die Response der *Pfadoperation* sein.\n\nNachdem eine dieser Responses gesendet wurde, kann keine weitere Response gesendet werden.\n\n///\n\n/// tip | Tipp\n\nWenn Sie in dem Code der *Pfadoperation-Funktion* irgendeine Exception auslösen, wird sie an die Abhängigkeiten mit `yield` weitergegeben, einschließlich `HTTPException`. In den meisten Fällen sollten Sie dieselbe Exception oder eine neue aus der Abhängigkeit mit `yield` erneut auslösen, um sicherzustellen, dass sie korrekt gehandhabt wird.\n\n///\n\n## Frühes Beenden und `scope` { #early-exit-and-scope }\n\nNormalerweise wird der Exit-Code von Abhängigkeiten mit `yield` ausgeführt **nachdem die Response** an den Client gesendet wurde.\n\nWenn Sie aber wissen, dass Sie die Abhängigkeit nach der Rückkehr aus der *Pfadoperation-Funktion* nicht mehr benötigen, können Sie `Depends(scope=\"function\")` verwenden, um FastAPI mitzuteilen, dass es die Abhängigkeit nach der Rückkehr aus der *Pfadoperation-Funktion* schließen soll, jedoch **bevor** die **Response gesendet wird**.\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()` erhält einen `scope`-Parameter, der sein kann:\n\n* `\"function\"`: startet die Abhängigkeit vor der *Pfadoperation-Funktion*, die den Request bearbeitet, beendet die Abhängigkeit nach dem Ende der *Pfadoperation-Funktion*, aber **bevor** die Response an den Client zurückgesendet wird. Die Abhängigkeitsfunktion wird also **um** die *Pfadoperation-**Funktion*** **herum** ausgeführt.\n* `\"request\"`: startet die Abhängigkeit vor der *Pfadoperation-Funktion*, die den Request bearbeitet (ähnlich wie bei `\"function\"`), beendet sie jedoch **nachdem** die Response an den Client zurückgesendet wurde. Die Abhängigkeitsfunktion wird also **um** den **Request**- und Response-Zyklus **herum** ausgeführt.\n\nWenn nicht angegeben und die Abhängigkeit `yield` hat, hat sie standardmäßig einen `scope` von `\"request\"`.\n\n### `scope` für Unterabhängigkeiten { #scope-for-sub-dependencies }\n\nWenn Sie eine Abhängigkeit mit `scope=\"request\"` (dem Default) deklarieren, muss jede Unterabhängigkeit ebenfalls einen `scope` von `\"request\"` haben.\n\nEine Abhängigkeit mit `scope` von `\"function\"` kann jedoch Abhängigkeiten mit `scope` von `\"function\"` und `scope` von `\"request\"` haben.\n\nDas liegt daran, dass jede Abhängigkeit in der Lage sein muss, ihren Exit-Code vor den Unterabhängigkeiten auszuführen, da sie diese während ihres Exit-Codes möglicherweise noch verwenden muss.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Abhängigkeit scope=\"request\"\nparticipant dep_func as Abhängigkeit scope=\"function\"\nparticipant operation as Pfadoperation\n\n    client ->> dep_req: Startet den Request\n    Note over dep_req: Führt den Code bis zum yield aus\n    dep_req ->> dep_func: Reicht Abhängigkeit weiter\n    Note over dep_func: Führt den Code bis zum yield aus\n    dep_func ->> operation: Führt Pfadoperation mit Abhängigkeit aus\n    operation ->> dep_func: Kehrt aus Pfadoperation zurück\n    Note over dep_func: Führt Code nach yield aus\n    Note over dep_func: ✅ Abhängigkeit geschlossen\n    dep_func ->> client: Sendet Response an Client\n    Note over client: Response gesendet\n    Note over dep_req: Führt Code nach yield aus\n    Note over dep_req: ✅ Abhängigkeit geschlossen\n```\n\n## Abhängigkeiten mit `yield`, `HTTPException`, `except` und Hintergrundtasks { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\nAbhängigkeiten mit `yield` haben sich im Laufe der Zeit weiterentwickelt, um verschiedene Anwendungsfälle abzudecken und einige Probleme zu beheben.\n\nWenn Sie sehen möchten, was sich in verschiedenen Versionen von FastAPI geändert hat, lesen Sie mehr dazu im fortgeschrittenen Teil, unter [Fortgeschrittene Abhängigkeiten – Abhängigkeiten mit `yield`, `HTTPException`, `except` und Hintergrundtasks](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).\n## Kontextmanager { #context-managers }\n\n### Was sind „Kontextmanager“ { #what-are-context-managers }\n\n„Kontextmanager“ (Englisch „Context Manager“) sind bestimmte Python-Objekte, die Sie in einer `with`-Anweisung verwenden können.\n\nBeispielsweise können Sie [„with“ verwenden, um eine Datei auszulesen](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files):\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\nIm Hintergrund erstellt das `open(\"./somefile.txt\")` ein Objekt, das als „Kontextmanager“ bezeichnet wird.\n\nDieser stellt sicher, dass, wenn der `with`-Block beendet ist, die Datei geschlossen wird, auch wenn Exceptions geworfen wurden.\n\nWenn Sie eine Abhängigkeit mit `yield` erstellen, erstellt **FastAPI** dafür intern einen Kontextmanager und kombiniert ihn mit einigen anderen zugehörigen Tools.\n\n### Kontextmanager in Abhängigkeiten mit `yield` verwenden { #using-context-managers-in-dependencies-with-yield }\n\n/// warning | Achtung\n\nDies ist mehr oder weniger eine „fortgeschrittene“ Idee.\n\nWenn Sie gerade erst mit **FastAPI** beginnen, möchten Sie das vielleicht vorerst überspringen.\n\n///\n\nIn Python können Sie Kontextmanager erstellen, indem Sie [eine Klasse mit zwei Methoden erzeugen: `__enter__()` und `__exit__()`](https://docs.python.org/3/reference/datamodel.html#context-managers).\n\nSie können solche auch innerhalb von **FastAPI**-Abhängigkeiten mit `yield` verwenden, indem Sie `with`- oder `async with`-Anweisungen innerhalb der Abhängigkeits-Funktion verwenden:\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip | Tipp\n\nAndere Möglichkeiten, einen Kontextmanager zu erstellen, sind:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) oder\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nVerwenden Sie diese, um eine Funktion zu dekorieren, die ein einziges `yield` hat.\n\nDas ist es auch, was **FastAPI** intern für Abhängigkeiten mit `yield` verwendet.\n\nAber Sie müssen die Dekoratoren nicht für FastAPI-Abhängigkeiten verwenden (und das sollten Sie auch nicht).\n\nFastAPI erledigt das intern für Sie.\n\n///\n"
  },
  {
    "path": "docs/de/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# Globale Abhängigkeiten { #global-dependencies }\n\nBei einigen Anwendungstypen möchten Sie möglicherweise Abhängigkeiten zur gesamten Anwendung hinzufügen.\n\nÄhnlich wie Sie [`dependencies` zu den *Pfadoperation-Dekoratoren* hinzufügen](dependencies-in-path-operation-decorators.md) können, können Sie sie auch zur `FastAPI`-Anwendung hinzufügen.\n\nIn diesem Fall werden sie auf alle *Pfadoperationen* in der Anwendung angewendet:\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\n\nUnd alle Ideen aus dem Abschnitt über das [Hinzufügen von `dependencies` zu den *Pfadoperation-Dekoratoren*](dependencies-in-path-operation-decorators.md) gelten weiterhin, aber in diesem Fall für alle *Pfadoperationen* in der App.\n\n## Abhängigkeiten für Gruppen von *Pfadoperationen* { #dependencies-for-groups-of-path-operations }\n\nWenn Sie später lesen, wie Sie größere Anwendungen strukturieren ([Größere Anwendungen – mehrere Dateien](../../tutorial/bigger-applications.md)), möglicherweise mit mehreren Dateien, lernen Sie, wie Sie einen einzelnen `dependencies`-Parameter für eine Gruppe von *Pfadoperationen* deklarieren.\n"
  },
  {
    "path": "docs/de/docs/tutorial/dependencies/index.md",
    "content": "# Abhängigkeiten { #dependencies }\n\n**FastAPI** hat ein sehr mächtiges, aber intuitives **<dfn title=\"auch bekannt als Komponenten, Ressourcen, Provider, Services, Injectables\">Abhängigkeitsinjektion</dfn>** System.\n\nEs ist so konzipiert, sehr einfach zu verwenden zu sein und es jedem Entwickler sehr leicht zu machen, andere Komponenten mit **FastAPI** zu integrieren.\n\n## Was ist „Dependency Injection“ { #what-is-dependency-injection }\n\n**„Dependency Injection“** bedeutet in der Programmierung, dass es für Ihren Code (in diesem Fall Ihre *Pfadoperation-Funktionen*) eine Möglichkeit gibt, Dinge zu deklarieren, die er verwenden möchte und die er zum Funktionieren benötigt: „Abhängigkeiten“ – „Dependencies“.\n\nDas System (in diesem Fall **FastAPI**) kümmert sich dann darum, Ihren Code mit den erforderlichen Abhängigkeiten zu versorgen („die Abhängigkeiten einfügen“ – „inject the dependencies“).\n\nDas ist sehr nützlich, wenn Sie:\n\n* Eine gemeinsame Logik haben (die gleiche Code-Logik immer und immer wieder).\n* Datenbankverbindungen teilen.\n* Sicherheit, Authentifizierung, Rollenanforderungen, usw. durchsetzen.\n* Und viele andere Dinge ...\n\nAll dies, während Sie Codeverdoppelung minimieren.\n\n## Erste Schritte { #first-steps }\n\nSehen wir uns ein sehr einfaches Beispiel an. Es ist so einfach, dass es vorerst nicht sehr nützlich ist.\n\nAber so können wir uns besser auf die Funktionsweise des **Dependency Injection** Systems konzentrieren.\n\n### Eine Abhängigkeit erstellen, oder <abbr title=\"Das von dem abhängt, die zu verwendende Abhängigkeit\">„Dependable“</abbr> { #create-a-dependency-or-dependable }\n\nKonzentrieren wir uns zunächst auf die Abhängigkeit – die Dependency.\n\nEs handelt sich einfach um eine Funktion, die die gleichen Parameter entgegennimmt wie eine *Pfadoperation-Funktion*:\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\nDas war's schon.\n\n**Zwei Zeilen**.\n\nUnd sie hat die gleiche Form und Struktur wie alle Ihre *Pfadoperation-Funktionen*.\n\nSie können sie sich als *Pfadoperation-Funktion* ohne den „Dekorator“ (ohne `@app.get(\"/some-path\")`) vorstellen.\n\nUnd sie kann alles zurückgeben, was Sie möchten.\n\nIn diesem Fall erwartet diese Abhängigkeit:\n\n* Einen optionalen Query-Parameter `q`, der ein `str` ist.\n* Einen optionalen Query-Parameter `skip`, der ein `int` ist und standardmäßig `0` ist.\n* Einen optionalen Query-Parameter `limit`, der ein `int` ist und standardmäßig `100` ist.\n\nUnd dann wird einfach ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr> zurückgegeben, welches diese Werte enthält.\n\n/// info | Info\n\nFastAPI unterstützt (und empfiehlt die Verwendung von) `Annotated` seit Version 0.95.0.\n\nWenn Sie eine ältere Version haben, werden Sie Fehler angezeigt bekommen, wenn Sie versuchen, `Annotated` zu verwenden.\n\nBitte [aktualisieren Sie FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions) daher mindestens zu Version 0.95.1, bevor Sie `Annotated` verwenden.\n\n///\n\n### `Depends` importieren { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### Die Abhängigkeit im <abbr title=\"Das Abhängige, der Verwender der Abhängigkeit\">„Dependant“</abbr> deklarieren { #declare-the-dependency-in-the-dependant }\n\nSo wie auch `Body`, `Query`, usw., verwenden Sie `Depends` mit den Parametern Ihrer *Pfadoperation-Funktion*:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\nObwohl Sie `Depends` in den Parametern Ihrer Funktion genauso verwenden wie `Body`, `Query`, usw., funktioniert `Depends` etwas anders.\n\nSie übergeben `Depends` nur einen einzigen Parameter.\n\nDieser Parameter muss so etwas wie eine Funktion sein.\n\nSie **rufen diese nicht direkt auf** (fügen Sie am Ende keine Klammern hinzu), sondern übergeben sie einfach als Parameter an `Depends()`.\n\nUnd diese Funktion akzeptiert Parameter auf die gleiche Weise wie *Pfadoperation-Funktionen*.\n\n/// tip | Tipp\n\nIm nächsten Kapitel erfahren Sie, welche anderen „Dinge“, außer Funktionen, Sie als Abhängigkeiten verwenden können.\n\n///\n\nImmer wenn ein neuer <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> eintrifft, kümmert sich **FastAPI** darum:\n\n* Ihre Abhängigkeitsfunktion („Dependable“) mit den richtigen Parametern aufzurufen.\n* Sich das Ergebnis von dieser Funktion zu holen.\n* Dieses Ergebnis dem Parameter Ihrer *Pfadoperation-Funktion* zuzuweisen.\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\nAuf diese Weise schreiben Sie gemeinsam genutzten Code nur einmal, und **FastAPI** kümmert sich darum, ihn für Ihre *Pfadoperationen* aufzurufen.\n\n/// check | Testen\n\nBeachten Sie, dass Sie keine spezielle Klasse erstellen und diese irgendwo an **FastAPI** übergeben müssen, um sie zu „registrieren“ oder so ähnlich.\n\nSie übergeben es einfach an `Depends` und **FastAPI** weiß, wie der Rest erledigt wird.\n\n///\n\n## `Annotated`-Abhängigkeiten wiederverwenden { #share-annotated-dependencies }\n\nIn den Beispielen oben sehen Sie, dass es ein kleines bisschen **Codeverdoppelung** gibt.\n\nWenn Sie die Abhängigkeit `common_parameters()` verwenden, müssen Sie den gesamten Parameter mit der Typannotation und `Depends()` schreiben:\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\nDa wir jedoch `Annotated` verwenden, können wir diesen `Annotated`-Wert in einer Variablen speichern und an mehreren Stellen verwenden:\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | Tipp\n\nDas ist schlicht Standard-Python, es wird als „Typalias“ bezeichnet und ist eigentlich nicht **FastAPI**-spezifisch.\n\nDa **FastAPI** jedoch auf Standard-Python, einschließlich `Annotated`, basiert, können Sie diesen Trick in Ihrem Code verwenden. 😎\n\n///\n\nDie Abhängigkeiten funktionieren weiterhin wie erwartet, und das **Beste daran** ist, dass die **Typinformationen erhalten bleiben**, was bedeutet, dass Ihr Editor Ihnen weiterhin **automatische Vervollständigung**, **Inline-Fehler**, usw. bieten kann. Das Gleiche gilt für andere Tools wie `mypy`.\n\nDas ist besonders nützlich, wenn Sie es in einer **großen Codebasis** verwenden, in der Sie in **vielen *Pfadoperationen*** immer wieder **dieselben Abhängigkeiten** verwenden.\n\n## `async` oder nicht `async` { #to-async-or-not-to-async }\n\nDa Abhängigkeiten auch von **FastAPI** aufgerufen werden (so wie Ihre *Pfadoperation-Funktionen*), gelten beim Definieren Ihrer Funktionen die gleichen Regeln.\n\nSie können `async def` oder einfach `def` verwenden.\n\nUnd Sie können Abhängigkeiten mit `async def` innerhalb normaler `def`-*Pfadoperation-Funktionen* oder `def`-Abhängigkeiten innerhalb von `async def`-*Pfadoperation-Funktionen*, usw. deklarieren.\n\nEs spielt keine Rolle. **FastAPI** weiß, was zu tun ist.\n\n/// note | Hinweis\n\nWenn Ihnen das nichts sagt, lesen Sie den [Async: *„In Eile?“*](../../async.md#in-a-hurry)-Abschnitt über `async` und `await` in der Dokumentation.\n\n///\n\n## Integriert in OpenAPI { #integrated-with-openapi }\n\nAlle Requestdeklarationen, -validierungen und -anforderungen Ihrer Abhängigkeiten (und Unterabhängigkeiten) werden in dasselbe OpenAPI-Schema integriert.\n\nDie interaktive Dokumentation enthält also auch alle Informationen aus diesen Abhängigkeiten:\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## Einfache Verwendung { #simple-usage }\n\nNäher betrachtet, werden *Pfadoperation-Funktionen* deklariert, um verwendet zu werden, wann immer ein *Pfad* und eine *Operation* übereinstimmen, und dann kümmert sich **FastAPI** darum, die Funktion mit den richtigen Parametern aufzurufen, die Daten aus dem Request extrahierend.\n\nTatsächlich funktionieren alle (oder die meisten) Webframeworks auf die gleiche Weise.\n\nSie rufen diese Funktionen niemals direkt auf. Sie werden von Ihrem Framework aufgerufen (in diesem Fall **FastAPI**).\n\nMit dem Dependency Injection System können Sie **FastAPI** ebenfalls mitteilen, dass Ihre *Pfadoperation-Funktion* von etwas anderem „abhängt“, das vor Ihrer *Pfadoperation-Funktion* ausgeführt werden soll, und **FastAPI** kümmert sich darum, es auszuführen und die Ergebnisse zu „injizieren“.\n\nAndere gebräuchliche Begriffe für dieselbe Idee der „Abhängigkeitsinjektion“ sind:\n\n* Ressourcen\n* Provider\n* Services\n* Injectables\n* Komponenten\n\n## **FastAPI**-Plugins { #fastapi-plug-ins }\n\nIntegrationen und „Plugins“ können mit dem **Dependency Injection** System erstellt werden. Aber tatsächlich besteht **keine Notwendigkeit, „Plugins“ zu erstellen**, da es durch die Verwendung von Abhängigkeiten möglich ist, eine unendliche Anzahl von Integrationen und Interaktionen zu deklarieren, die dann für Ihre *Pfadoperation-Funktionen* verfügbar sind.\n\nUnd Abhängigkeiten können auf sehr einfache und intuitive Weise erstellt werden, sodass Sie einfach die benötigten Python-Packages importieren und sie in wenigen Codezeilen, *im wahrsten Sinne des Wortes*, mit Ihren API-Funktionen integrieren.\n\nBeispiele hierfür finden Sie in den nächsten Kapiteln zu relationalen und NoSQL-Datenbanken, Sicherheit usw.\n\n## **FastAPI**-Kompatibilität { #fastapi-compatibility }\n\nDie Einfachheit des Dependency Injection Systems macht **FastAPI** kompatibel mit:\n\n* allen relationalen Datenbanken\n* NoSQL-Datenbanken\n* externen Packages\n* externen APIs\n* Authentifizierungs- und Autorisierungssystemen\n* API-Nutzungs-Überwachungssystemen\n* <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Responsedaten</abbr>-Injektionssystemen\n* usw.\n\n## Einfach und leistungsstark { #simple-and-powerful }\n\nObwohl das hierarchische Dependency Injection System sehr einfach zu definieren und zu verwenden ist, ist es dennoch sehr mächtig.\n\nSie können Abhängigkeiten definieren, die selbst wiederum Abhängigkeiten definieren können.\n\nAm Ende wird ein hierarchischer Baum von Abhängigkeiten erstellt, und das **Dependency Injection** System kümmert sich darum, alle diese Abhängigkeiten (und deren Unterabhängigkeiten) für Sie aufzulösen und die Ergebnisse bei jedem Schritt einzubinden (zu injizieren).\n\nNehmen wir zum Beispiel an, Sie haben vier API-Endpunkte (*Pfadoperationen*):\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\nDann könnten Sie für jeden davon unterschiedliche Berechtigungsanforderungen hinzufügen, nur mit Abhängigkeiten und Unterabhängigkeiten:\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## Integriert mit **OpenAPI** { #integrated-with-openapi_1 }\n\nAlle diese Abhängigkeiten, während sie ihre Anforderungen deklarieren, fügen auch Parameter, Validierungen, usw. zu Ihren *Pfadoperationen* hinzu.\n\n**FastAPI** kümmert sich darum, alles zum OpenAPI-Schema hinzuzufügen, damit es in den interaktiven Dokumentationssystemen angezeigt wird.\n"
  },
  {
    "path": "docs/de/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# Unterabhängigkeiten { #sub-dependencies }\n\nSie können Abhängigkeiten erstellen, die **Unterabhängigkeiten** haben.\n\nDiese können so **tief** verschachtelt sein, wie nötig.\n\n**FastAPI** kümmert sich darum, sie aufzulösen.\n\n## Erste Abhängigkeit, „Dependable“ { #first-dependency-dependable }\n\nSie könnten eine erste Abhängigkeit („Dependable“) wie folgt erstellen:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\nDiese deklariert einen optionalen Query-Parameter `q` vom Typ `str` und gibt ihn dann einfach zurück.\n\nDas ist recht einfach (nicht sehr nützlich), hilft uns aber dabei, uns auf die Funktionsweise der Unterabhängigkeiten zu konzentrieren.\n\n## Zweite Abhängigkeit, „Dependable“ und „Dependant“ { #second-dependency-dependable-and-dependant }\n\nDann können Sie eine weitere Abhängigkeitsfunktion (ein „Dependable“) erstellen, die gleichzeitig eine eigene Abhängigkeit deklariert (also auch ein „Dependant“ ist):\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\nBetrachten wir die deklarierten Parameter:\n\n* Obwohl diese Funktion selbst eine Abhängigkeit ist („Dependable“, etwas hängt von ihr ab), deklariert sie auch eine andere Abhängigkeit („Dependant“, sie hängt von etwas anderem ab).\n    * Sie hängt von `query_extractor` ab und weist den von diesem zurückgegebenen Wert dem Parameter `q` zu.\n* Sie deklariert außerdem ein optionales `last_query`-Cookie, ein `str`.\n    * Wenn der Benutzer keine Query `q` übermittelt hat, verwenden wir die zuletzt übermittelte Query, die wir zuvor in einem Cookie gespeichert haben.\n\n## Die Abhängigkeit verwenden { #use-the-dependency }\n\nDiese Abhängigkeit verwenden wir nun wie folgt:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info | Info\n\nBeachten Sie, dass wir in der *Pfadoperation-Funktion* nur eine einzige Abhängigkeit deklarieren, den `query_or_cookie_extractor`.\n\nAber **FastAPI** wird wissen, dass es zuerst `query_extractor` auflösen muss, um dessen Resultat an `query_or_cookie_extractor` zu übergeben, wenn dieses aufgerufen wird.\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## Dieselbe Abhängigkeit mehrmals verwenden { #using-the-same-dependency-multiple-times }\n\nWenn eine Ihrer Abhängigkeiten mehrmals für dieselbe *Pfadoperation* deklariert wird, beispielsweise wenn mehrere Abhängigkeiten eine gemeinsame Unterabhängigkeit haben, wird **FastAPI** diese Unterabhängigkeit nur einmal pro <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> aufrufen.\n\nUnd es speichert den zurückgegebenen Wert in einem <dfn title=\"Hilfsprogramm/System zum Speichern berechneter/erzeugter Werte, um sie wiederzuverwenden, anstatt sie erneut zu berechnen.\">„Cache“</dfn> und übergibt diesen gecachten Wert an alle „Dependanten“, die ihn in diesem spezifischen Request benötigen, anstatt die Abhängigkeit mehrmals für denselben Request aufzurufen.\n\nIn einem fortgeschrittenen Szenario, bei dem Sie wissen, dass die Abhängigkeit bei jedem Schritt (möglicherweise mehrmals) in demselben Request aufgerufen werden muss, anstatt den zwischengespeicherten Wert zu verwenden, können Sie den Parameter `use_cache=False` festlegen, wenn Sie `Depends` verwenden:\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ nicht annotiert\n\n/// tip | Tipp\n\nBevorzugen Sie die `Annotated`-Version, falls möglich.\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## Zusammenfassung { #recap }\n\nAbgesehen von all den ausgefallenen Wörtern, die hier verwendet werden, ist das **Dependency Injection**-System recht simpel.\n\nEinfach Funktionen, die genauso aussehen wie *Pfadoperation-Funktionen*.\n\nDennoch ist es sehr mächtig und ermöglicht Ihnen die Deklaration beliebig tief verschachtelter Abhängigkeits-„Graphen“ (Bäume).\n\n/// tip | Tipp\n\nAll dies scheint angesichts dieser einfachen Beispiele möglicherweise nicht so nützlich zu sein.\n\nAber Sie werden in den Kapiteln über **Sicherheit** sehen, wie nützlich das ist.\n\nUnd Sie werden auch sehen, wie viel Code Sie dadurch einsparen.\n\n///\n"
  },
  {
    "path": "docs/de/docs/tutorial/encoder.md",
    "content": "# JSON-kompatibler Encoder { #json-compatible-encoder }\n\nEs gibt Fälle, da möchten Sie einen Datentyp (etwa ein Pydantic-Modell) in etwas konvertieren, das kompatibel mit JSON ist (etwa ein `dict`, eine `list`, usw.).\n\nZum Beispiel, wenn Sie es in einer Datenbank speichern möchten.\n\nDafür bietet **FastAPI** eine Funktion `jsonable_encoder()`.\n\n## `jsonable_encoder` verwenden { #using-the-jsonable-encoder }\n\nStellen wir uns vor, Sie haben eine Datenbank `fake_db`, die nur JSON-kompatible Daten entgegennimmt.\n\nSie akzeptiert zum Beispiel keine `datetime`-Objekte, da die nicht kompatibel mit JSON sind.\n\nEin `datetime`-Objekt müsste also in einen `str` umgewandelt werden, der die Daten im [ISO-Format](https://en.wikipedia.org/wiki/ISO_8601) enthält.\n\nGenauso würde die Datenbank kein Pydantic-Modell (ein Objekt mit Attributen) akzeptieren, sondern nur ein `dict`.\n\nSie können für diese Fälle `jsonable_encoder` verwenden.\n\nEs nimmt ein Objekt entgegen, wie etwa ein Pydantic-Modell, und gibt eine JSON-kompatible Version zurück:\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\nIn diesem Beispiel wird das Pydantic-Modell in ein `dict`, und das `datetime`-Objekt in ein `str` konvertiert.\n\nDas Resultat dieses Aufrufs ist etwas, das mit Pythons Standard-[`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps) kodiert werden kann.\n\nEs wird also kein großer `str` zurückgegeben, der die Daten im JSON-Format (als String) enthält. Es wird eine Python-Standarddatenstruktur (z. B. ein `dict`) zurückgegeben, mit Werten und Unterwerten, die alle mit JSON kompatibel sind.\n\n/// note | Hinweis\n\n`jsonable_encoder` wird tatsächlich von **FastAPI** intern verwendet, um Daten zu konvertieren. Aber es ist in vielen anderen Szenarien hilfreich.\n\n///\n"
  },
  {
    "path": "docs/de/docs/tutorial/extra-data-types.md",
    "content": "# Zusätzliche Datentypen { #extra-data-types }\n\nBisher haben Sie gängige Datentypen verwendet, wie zum Beispiel:\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\nSie können aber auch komplexere Datentypen verwenden.\n\nUnd Sie haben immer noch dieselbe Funktionalität wie bisher gesehen:\n\n* Großartige Editor-Unterstützung.\n* Datenkonvertierung bei eingehenden <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr>.\n* Datenkonvertierung für <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>-Daten.\n* Datenvalidierung.\n* Automatische Annotation und Dokumentation.\n\n## Andere Datentypen { #other-data-types }\n\nHier sind einige der zusätzlichen Datentypen, die Sie verwenden können:\n\n* `UUID`:\n    * Ein standardmäßiger „universell eindeutiger Bezeichner“ („Universally Unique Identifier“), der in vielen Datenbanken und Systemen als ID üblich ist.\n    * Wird in Requests und Responses als `str` dargestellt.\n* `datetime.datetime`:\n    * Ein Python-`datetime.datetime`.\n    * Wird in Requests und Responses als `str` im ISO 8601-Format dargestellt, etwa: `2008-09-15T15:53:00+05:00`.\n* `datetime.date`:\n    * Python-`datetime.date`.\n    * Wird in Requests und Responses als `str` im ISO 8601-Format dargestellt, etwa: `2008-09-15`.\n* `datetime.time`:\n    * Ein Python-`datetime.time`.\n    * Wird in Requests und Responses als `str` im ISO 8601-Format dargestellt, etwa: `14:23:55.003`.\n* `datetime.timedelta`:\n    * Ein Python-`datetime.timedelta`.\n    * Wird in Requests und Responses als `float` der Gesamtsekunden dargestellt.\n    * Pydantic ermöglicht auch die Darstellung als „ISO 8601 Zeitdifferenz-Kodierung“, [siehe die Dokumentation für weitere Informationen](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).\n* `frozenset`:\n    * Wird in Requests und Responses wie ein `set` behandelt:\n        * Bei Requests wird eine Liste gelesen, Duplikate entfernt und in ein `set` umgewandelt.\n        * Bei Responses wird das `set` in eine `list` umgewandelt.\n        * Das generierte Schema zeigt an, dass die `set`-Werte eindeutig sind (unter Verwendung von JSON Schemas `uniqueItems`).\n* `bytes`:\n    * Standard-Python-`bytes`.\n    * In Requests und Responses werden sie als `str` behandelt.\n    * Das generierte Schema wird anzeigen, dass es sich um einen `str` mit `binary` „Format“ handelt.\n* `Decimal`:\n    * Standard-Python-`Decimal`.\n    * In Requests und Responses wird es wie ein `float` behandelt.\n* Sie können alle gültigen Pydantic-Datentypen hier überprüfen: [Pydantic-Datentypen](https://docs.pydantic.dev/latest/usage/types/types/).\n\n## Beispiel { #example }\n\nHier ist ein Beispiel für eine *Pfadoperation* mit Parametern, die einige der oben genannten Typen verwenden.\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\nBeachten Sie, dass die Parameter innerhalb der Funktion ihren natürlichen Datentyp haben und Sie beispielsweise normale Datumsmanipulationen durchführen können, wie zum Beispiel:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/de/docs/tutorial/extra-models.md",
    "content": "# Extramodelle { #extra-models }\n\nIm Anschluss an das vorherige Beispiel ist es üblich, mehr als ein zusammenhängendes Modell zu haben.\n\nDies gilt insbesondere für Benutzermodelle, denn:\n\n* Das **Eingabemodell** muss ein Passwort enthalten können.\n* Das **Ausgabemodell** sollte kein Passwort haben.\n* Das **Datenbankmodell** müsste wahrscheinlich ein gehashtes Passwort haben.\n\n/// danger | Gefahr\n\nSpeichern Sie niemals das Klartextpasswort eines Benutzers. Speichern Sie immer einen „sicheren Hash“, den Sie dann verifizieren können.\n\nWenn Sie nicht wissen, was das ist, werden Sie in den [Sicherheitskapiteln](security/simple-oauth2.md#password-hashing) lernen, was ein „Passworthash“ ist.\n\n///\n\n## Mehrere Modelle { #multiple-models }\n\nHier ist eine allgemeine Idee, wie die Modelle mit ihren Passwortfeldern aussehen könnten und an welchen Stellen sie verwendet werden:\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### Über `**user_in.model_dump()` { #about-user-in-model-dump }\n\n#### Pydantics `.model_dump()` { #pydantics-model-dump }\n\n`user_in` ist ein Pydantic-Modell der Klasse `UserIn`.\n\nPydantic-Modelle haben eine `.model_dump()`-Methode, die ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr> mit den Daten des Modells zurückgibt.\n\nWenn wir also ein Pydantic-Objekt `user_in` erstellen, etwa so:\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\nund dann aufrufen:\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\nhaben wir jetzt ein `dict` mit den Daten in der Variablen `user_dict` (es ist ein `dict` statt eines Pydantic-Modellobjekts).\n\nUnd wenn wir aufrufen:\n\n```Python\nprint(user_dict)\n```\n\nwürden wir ein Python-`dict` erhalten mit:\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### Ein `dict` entpacken { #unpacking-a-dict }\n\nWenn wir ein `dict` wie `user_dict` nehmen und es einer Funktion (oder Klasse) mit `**user_dict` übergeben, wird Python es „entpacken“. Es wird die Schlüssel und Werte von `user_dict` direkt als Schlüsselwort-Argumente übergeben.\n\nSetzen wir also das `user_dict` von oben ein:\n\n```Python\nUserInDB(**user_dict)\n```\n\nso ist das äquivalent zu:\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\nOder genauer gesagt, dazu, `user_dict` direkt zu verwenden, mit welchen Inhalten es auch immer in der Zukunft haben mag:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### Ein Pydantic-Modell aus dem Inhalt eines anderen { #a-pydantic-model-from-the-contents-of-another }\n\nDa wir im obigen Beispiel `user_dict` von `user_in.model_dump()` bekommen haben, wäre dieser Code:\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\ngleichwertig zu:\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n... weil `user_in.model_dump()` ein `dict` ist, und dann lassen wir Python es „entpacken“, indem wir es an `UserInDB` mit vorangestelltem `**` übergeben.\n\nAuf diese Weise erhalten wir ein Pydantic-Modell aus den Daten eines anderen Pydantic-Modells.\n\n#### Ein `dict` entpacken und zusätzliche Schlüsselwort-Argumente { #unpacking-a-dict-and-extra-keywords }\n\nUnd dann fügen wir das zusätzliche Schlüsselwort-Argument `hashed_password=hashed_password` hinzu, wie in:\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n... was so ist wie:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning | Achtung\n\nDie unterstützenden zusätzlichen Funktionen `fake_password_hasher` und `fake_save_user` dienen nur zur Demo eines möglichen Datenflusses, bieten jedoch natürlich keine echte Sicherheit.\n\n///\n\n## Verdopplung vermeiden { #reduce-duplication }\n\nDie Reduzierung von Code-Verdoppelung ist eine der Kernideen von **FastAPI**.\n\nDa die Verdopplung von Code die Wahrscheinlichkeit von Fehlern, Sicherheitsproblemen, Problemen mit der Desynchronisation des Codes (wenn Sie an einer Stelle, aber nicht an der anderen aktualisieren) usw. erhöht.\n\nUnd diese Modelle teilen alle eine Menge der Daten und verdoppeln Attributnamen und -typen.\n\nWir könnten es besser machen.\n\nWir können ein `UserBase`-Modell deklarieren, das als Basis für unsere anderen Modelle dient. Und dann können wir Unterklassen dieses Modells erstellen, die seine Attribute (Typdeklarationen, Validierung usw.) erben.\n\nDie ganze Datenkonvertierung, -validierung, -dokumentation usw. wird immer noch wie gewohnt funktionieren.\n\nAuf diese Weise können wir nur die Unterschiede zwischen den Modellen (mit Klartext-`password`, mit `hashed_password` und ohne Passwort) deklarieren:\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` oder `anyOf` { #union-or-anyof }\n\nSie können deklarieren, dass eine <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> eine <abbr title=\"Union – Verbund, Einheit, Vereinigung: Eines von Mehreren\">`Union`</abbr> mehrerer Typen ist, das bedeutet, dass die Response einer von ihnen ist.\n\nDies wird in OpenAPI mit `anyOf` definiert.\n\nUm das zu tun, verwenden Sie den Standard-Python-Typhinweis [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union):\n\n/// note | Hinweis\n\nWenn Sie eine [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions) definieren, listen Sie den spezifischeren Typ zuerst auf, gefolgt vom weniger spezifischen Typ. Im Beispiel unten steht `PlaneItem` vor `CarItem` in `Union[PlaneItem, CarItem]`.\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### `Union` in Python 3.10 { #union-in-python-3-10 }\n\nIn diesem Beispiel übergeben wir `Union[PlaneItem, CarItem]` als Wert des Arguments `response_model`.\n\nDa wir es als **Wert an ein Argument übergeben**, anstatt es in einer **Typannotation** zu verwenden, müssen wir `Union` verwenden, sogar in Python 3.10.\n\nWäre es eine Typannotation gewesen, hätten wir den vertikalen Strich verwenden können, wie in:\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\nAber wenn wir das in der Zuweisung `response_model=PlaneItem | CarItem` machen, würden wir einen Fehler erhalten, weil Python versuchen würde, eine **ungültige Operation** zwischen `PlaneItem` und `CarItem` auszuführen, anstatt es als Typannotation zu interpretieren.\n\n## Liste von Modellen { #list-of-models }\n\nAuf die gleiche Weise können Sie Responses von Listen von Objekten deklarieren.\n\nDafür verwenden Sie Pythons Standard-`list`:\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## Response mit beliebigem `dict` { #response-with-arbitrary-dict }\n\nSie können auch eine Response deklarieren, die ein beliebiges `dict` zurückgibt, indem Sie nur die Typen der Schlüssel und Werte ohne ein Pydantic-Modell deklarieren.\n\nDies ist nützlich, wenn Sie die gültigen Feld-/Attributnamen nicht im Voraus kennen (die für ein Pydantic-Modell benötigt werden würden).\n\nIn diesem Fall können Sie `dict` verwenden:\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## Zusammenfassung { #recap }\n\nVerwenden Sie gerne mehrere Pydantic-Modelle und vererben Sie je nach Bedarf.\n\nSie brauchen kein einzelnes Datenmodell pro Einheit, wenn diese Einheit in der Lage sein muss, verschiedene „Zustände“ zu haben. Wie im Fall der Benutzer-„Einheit“ mit einem Zustand einschließlich `password`, `password_hash` und ohne Passwort.\n"
  },
  {
    "path": "docs/de/docs/tutorial/first-steps.md",
    "content": "# Erste Schritte { #first-steps }\n\nDie einfachste FastAPI-Datei könnte wie folgt aussehen:\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\nKopieren Sie das in eine Datei `main.py`.\n\nStarten Sie den Live-Server:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nIn der Konsolenausgabe sollte es eine Zeile geben, die ungefähr so aussieht:\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\nDiese Zeile zeigt die URL, unter der Ihre App auf Ihrem lokalen Computer bereitgestellt wird.\n\n### Es testen { #check-it }\n\nÖffnen Sie Ihren Browser unter [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nSie werden die JSON-<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> sehen:\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### Interaktive API-Dokumentation { #interactive-api-docs }\n\nGehen Sie als Nächstes auf [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nSie werden die automatisch erzeugte, interaktive API-Dokumentation sehen (bereitgestellt durch [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Alternative API-Dokumentation { #alternative-api-docs }\n\nGehen Sie nun auf [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nDort sehen Sie die alternative, automatische Dokumentation (bereitgestellt durch [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI** generiert ein „Schema“ mit all Ihren APIs unter Verwendung des **OpenAPI**-Standards zur Definition von APIs.\n\n#### „Schema“ { #schema }\n\nEin „Schema“ ist eine Definition oder Beschreibung von etwas. Nicht der eigentliche Code, der es implementiert, sondern lediglich eine abstrakte Beschreibung.\n\n#### API-„Schema“ { #api-schema }\n\nIn diesem Fall ist [OpenAPI](https://github.com/OAI/OpenAPI-Specification) eine Spezifikation, die vorschreibt, wie ein Schema für Ihre API zu definieren ist.\n\nDiese Schemadefinition enthält Ihre API-Pfade, die möglichen Parameter, welche diese entgegennehmen, usw.\n\n#### Daten-„Schema“ { #data-schema }\n\nDer Begriff „Schema“ kann sich auch auf die Form von Daten beziehen, wie z. B. einen JSON-Inhalt.\n\nIn diesem Fall sind die JSON-Attribute und deren Datentypen, usw. gemeint.\n\n#### OpenAPI und JSON Schema { #openapi-and-json-schema }\n\nOpenAPI definiert ein API-Schema für Ihre API. Dieses Schema enthält Definitionen (oder „Schemas“) der Daten, die von Ihrer API unter Verwendung von **JSON Schema**, dem Standard für JSON-Datenschemata, gesendet und empfangen werden.\n\n#### Die `openapi.json` testen { #check-the-openapi-json }\n\nFalls Sie wissen möchten, wie das rohe OpenAPI-Schema aussieht: FastAPI generiert automatisch ein JSON (Schema) mit den Beschreibungen Ihrer gesamten API.\n\nSie können es direkt einsehen unter: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).\n\nEs wird ein JSON angezeigt, welches ungefähr so aussieht:\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### Wofür OpenAPI gedacht ist { #what-is-openapi-for }\n\nDas OpenAPI-Schema ist die Grundlage für die beiden enthaltenen interaktiven Dokumentationssysteme.\n\nEs gibt dutzende Alternativen, die alle auf OpenAPI basieren. Sie können jede dieser Alternativen problemlos zu Ihrer mit **FastAPI** erstellten Anwendung hinzufügen.\n\nEbenfalls können Sie es verwenden, um automatisch Code für Clients zu generieren, die mit Ihrer API kommunizieren. Zum Beispiel für Frontend-, Mobile- oder IoT-Anwendungen.\n\n### Den App-`entrypoint` in `pyproject.toml` konfigurieren { #configure-the-app-entrypoint-in-pyproject-toml }\n\nSie können in einer `pyproject.toml`-Datei konfigurieren, wo sich Ihre App befindet, z. B.:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nDieser `entrypoint` teilt dem `fastapi`-Befehl mit, dass er die App folgendermaßen importieren soll:\n\n```python\nfrom main import app\n```\n\nWenn Ihr Code so strukturiert wäre:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nDann würden Sie den `entrypoint` so setzen:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nwas äquivalent wäre zu:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` mit Pfad { #fastapi-dev-with-path }\n\nSie können auch den Dateipfad an den Befehl `fastapi dev` übergeben, und er wird das zu verwendende FastAPI-App-Objekt erraten:\n\n```console\n$ fastapi dev main.py\n```\n\nAber Sie müssten sich daran erinnern, bei jedem Aufruf des `fastapi`-Befehls den korrekten Pfad zu übergeben.\n\nZusätzlich könnten andere Tools es nicht finden, z. B. die [VS Code-Erweiterung](../editor-support.md) oder [FastAPI Cloud](https://fastapicloud.com). Daher wird empfohlen, den `entrypoint` in `pyproject.toml` zu verwenden.\n\n### Ihre App deployen (optional) { #deploy-your-app-optional }\n\nSie können optional Ihre FastAPI-App in der [FastAPI Cloud](https://fastapicloud.com) deployen, treten Sie der Warteliste bei, falls Sie es noch nicht getan haben. 🚀\n\nWenn Sie bereits ein **FastAPI Cloud**-Konto haben (wir haben Sie von der Warteliste eingeladen 😉), können Sie Ihre Anwendung mit einem Befehl deployen.\n\nVor dem Deployen, stellen Sie sicher, dass Sie eingeloggt sind:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\nDann stellen Sie Ihre App bereit:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nDas war's! Jetzt können Sie Ihre App unter dieser URL aufrufen. ✨\n\n## Zusammenfassung, Schritt für Schritt { #recap-step-by-step }\n\n### Schritt 1: `FastAPI` importieren { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI` ist eine Python-Klasse, die die gesamte Funktionalität für Ihre API bereitstellt.\n\n/// note | Technische Details\n\n`FastAPI` ist eine Klasse, die direkt von `Starlette` erbt.\n\nSie können alle [Starlette](https://www.starlette.dev/)-Funktionalitäten auch mit `FastAPI` nutzen.\n\n///\n\n### Schritt 2: Erzeugen einer `FastAPI`-„Instanz“ { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\nIn diesem Beispiel ist die Variable `app` eine „Instanz“ der Klasse `FastAPI`.\n\nDies wird der Hauptinteraktionspunkt für die Erstellung all Ihrer APIs sein.\n\n### Schritt 3: Erstellen einer *Pfadoperation* { #step-3-create-a-path-operation }\n\n#### Pfad { #path }\n\n„Pfad“ bezieht sich hier auf den letzten Teil der URL, beginnend mit dem ersten `/`.\n\nIn einer URL wie:\n\n```\nhttps://example.com/items/foo\n```\n\n... wäre der Pfad folglich:\n\n```\n/items/foo\n```\n\n/// info | Info\n\nEin „Pfad“ wird häufig auch als „Endpunkt“ oder „Route“ bezeichnet.\n\n///\n\nBei der Erstellung einer API ist der „Pfad“ die wichtigste Möglichkeit zur Trennung von „Anliegen“ und „Ressourcen“.\n\n#### Operation { #operation }\n\n„Operation“ bezieht sich hier auf eine der HTTP-„Methoden“.\n\nEine von diesen:\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n... und die etwas Exotischeren:\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\nIm HTTP-Protokoll können Sie mit jedem Pfad über eine (oder mehrere) dieser „Methoden“ kommunizieren.\n\n---\n\nBei der Erstellung von APIs verwenden Sie normalerweise diese spezifischen HTTP-Methoden, um eine bestimmte Aktion durchzuführen.\n\nNormalerweise verwenden Sie:\n\n* `POST`: um Daten zu erzeugen (create).\n* `GET`: um Daten zu lesen (read).\n* `PUT`: um Daten zu aktualisieren (update).\n* `DELETE`: um Daten zu löschen (delete).\n\nIn OpenAPI wird folglich jede dieser HTTP-Methoden als „Operation“ bezeichnet.\n\nWir werden sie auch „**Operationen**“ nennen.\n\n#### Definieren eines *Pfadoperation-Dekorators* { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\nDas `@app.get(\"/\")` sagt **FastAPI**, dass die Funktion direkt darunter für die Bearbeitung von <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> zuständig ist, die an:\n\n* den Pfad `/`\n* unter der Verwendung der <dfn title=\"eine HTTP-GET-Methode\"><code>get</code>-Operation</dfn> gehen\n\n/// info | `@decorator` Info\n\nDiese `@something`-Syntax wird in Python „Dekorator“ genannt.\n\nSie platzieren ihn über einer Funktion. Wie ein hübscher, dekorativer Hut (daher kommt wohl der Begriff).\n\nEin „Dekorator“ nimmt die darunter stehende Funktion und macht etwas damit.\n\nIn unserem Fall teilt dieser Dekorator **FastAPI** mit, dass die folgende Funktion mit dem **Pfad** `/` und der **Operation** `get` zusammenhängt.\n\nDies ist der „**Pfadoperation-Dekorator**“.\n\n///\n\nSie können auch die anderen Operationen verwenden:\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\nUnd die exotischeren:\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip | Tipp\n\nEs steht Ihnen frei, jede Operation (HTTP-Methode) so zu verwenden, wie Sie es möchten.\n\n**FastAPI** erzwingt keine bestimmte Bedeutung.\n\nDie hier aufgeführten Informationen dienen als Leitfaden und sind nicht verbindlich.\n\nWenn Sie beispielsweise GraphQL verwenden, führen Sie normalerweise alle Aktionen nur mit „POST“-Operationen durch.\n\n///\n\n### Schritt 4: Definieren der **Pfadoperation-Funktion** { #step-4-define-the-path-operation-function }\n\nDas ist unsere „**Pfadoperation-Funktion**“:\n\n* **Pfad**: ist `/`.\n* **Operation**: ist `get`.\n* **Funktion**: ist die Funktion direkt unter dem „Dekorator“ (unter `@app.get(\"/\")`).\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\nDies ist eine Python-Funktion.\n\nSie wird von **FastAPI** immer dann aufgerufen, wenn sie einen Request an die URL „`/`“ mittels einer `GET`-Operation erhält.\n\nIn diesem Fall handelt es sich um eine `async`-Funktion.\n\n---\n\nSie könnten sie auch als normale Funktion anstelle von `async def` definieren:\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note | Hinweis\n\nWenn Sie den Unterschied nicht kennen, lesen Sie [Async: *„In Eile?“*](../async.md#in-a-hurry).\n\n///\n\n### Schritt 5: den Inhalt zurückgeben { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\nSie können ein `dict`, eine `list`, einzelne Werte wie `str`, `int`, usw. zurückgeben.\n\nSie können auch Pydantic-Modelle zurückgeben (dazu später mehr).\n\nEs gibt viele andere Objekte und Modelle, die automatisch zu JSON konvertiert werden (einschließlich ORMs, usw.). Versuchen Sie, Ihre Lieblingsobjekte zu verwenden. Es ist sehr wahrscheinlich, dass sie bereits unterstützt werden.\n\n### Schritt 6: Deployen { #step-6-deploy-it }\n\nStellen Sie Ihre App in der **[FastAPI Cloud](https://fastapicloud.com)** mit einem Befehl bereit: `fastapi deploy`. 🎉\n\n#### Über FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** wird vom selben Autor und Team hinter **FastAPI** entwickelt.\n\nEs vereinfacht den Prozess des Erstellens, Deployens und des Zugriffs auf eine API mit minimalem Aufwand.\n\nEs bringt die gleiche **Developer-Experience** beim Erstellen von Apps mit FastAPI auch zum **Deployment** in der Cloud. 🎉\n\nFastAPI Cloud ist der Hauptsponsor und Finanzierer der „FastAPI and friends“ Open-Source-Projekte. ✨\n\n#### Zu anderen Cloudanbietern deployen { #deploy-to-other-cloud-providers }\n\nFastAPI ist Open Source und basiert auf Standards. Sie können FastAPI-Apps bei jedem Cloudanbieter Ihrer Wahl deployen.\n\nFolgen Sie den Anleitungen Ihres Cloudanbieters, um dort FastAPI-Apps bereitzustellen. 🤓\n\n## Zusammenfassung { #recap }\n\n* Importieren Sie `FastAPI`.\n* Erstellen Sie eine `app` Instanz.\n* Schreiben Sie einen **Pfadoperation-Dekorator** unter Verwendung von Dekoratoren wie `@app.get(\"/\")`.\n* Definieren Sie eine **Pfadoperation-Funktion**, zum Beispiel `def root(): ...`.\n* Starten Sie den Entwicklungsserver mit dem Befehl `fastapi dev`.\n* Optional: Ihre App mit `fastapi deploy` deployen.\n"
  },
  {
    "path": "docs/de/docs/tutorial/handling-errors.md",
    "content": "# Fehler behandeln { #handling-errors }\n\nEs gibt viele Situationen, in denen Sie einem Client, der Ihre API nutzt, einen Fehler mitteilen müssen.\n\nDieser Client könnte ein Browser mit einem Frontend sein, ein Code von jemand anderem, ein IoT-Gerät usw.\n\nSie könnten dem Client mitteilen müssen, dass:\n\n* Der Client nicht genügend Berechtigungen für diese Operation hat.\n* Der Client keinen Zugriff auf diese Ressource hat.\n* Die Ressource, auf die der Client versucht hat, zuzugreifen, nicht existiert.\n* usw.\n\nIn diesen Fällen würden Sie normalerweise einen **HTTP-Statuscode** im Bereich **400** (von 400 bis 499) zurückgeben.\n\nDies ist vergleichbar mit den HTTP-Statuscodes im Bereich 200 (von 200 bis 299). Diese „200“-Statuscodes bedeuten, dass der <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> in irgendeiner Weise erfolgreich war.\n\nDie Statuscodes im Bereich 400 bedeuten hingegen, dass es einen Fehler seitens des Clients gab.\n\nErinnern Sie sich an all diese **„404 Not Found“** Fehler (und Witze)?\n\n## `HTTPException` verwenden { #use-httpexception }\n\nUm HTTP-<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Responses</abbr> mit Fehlern an den Client zurückzugeben, verwenden Sie `HTTPException`.\n\n### `HTTPException` importieren { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### Eine `HTTPException` in Ihrem Code auslösen { #raise-an-httpexception-in-your-code }\n\n`HTTPException` ist eine normale Python-Exception mit zusätzlichen Daten, die für APIs relevant sind.\n\nWeil es eine Python-Exception ist, geben Sie sie nicht zurück (`return`), sondern lösen sie aus (`raise`).\n\nDas bedeutet auch, wenn Sie sich innerhalb einer Hilfsfunktion befinden, die Sie innerhalb Ihrer *Pfadoperation-Funktion* aufrufen, und Sie die `HTTPException` aus dieser Hilfsfunktion heraus auslösen, wird der restliche Code in der *Pfadoperation-Funktion* nicht ausgeführt. Der Request wird sofort abgebrochen und der HTTP-Error der `HTTPException` wird an den Client gesendet.\n\nDer Vorteil des Auslösens einer Exception gegenüber dem Zurückgeben eines Wertes wird im Abschnitt über Abhängigkeiten und Sicherheit deutlicher werden.\n\nIn diesem Beispiel lösen wir eine Exception mit einem Statuscode von `404` aus, wenn der Client einen Artikel mit einer nicht existierenden ID anfordert:\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### Die resultierende Response { #the-resulting-response }\n\nWenn der Client `http://example.com/items/foo` anfordert (ein `item_id` `\"foo\"`), erhält dieser Client einen HTTP-Statuscode 200 und diese JSON-Response:\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\nAber wenn der Client `http://example.com/items/bar` anfordert (ein nicht-existierendes `item_id` `\"bar\"`), erhält er einen HTTP-Statuscode 404 (der „Not Found“-Error) und eine JSON-Response wie:\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip | Tipp\n\nWenn Sie eine `HTTPException` auslösen, können Sie dem Parameter `detail` jeden Wert übergeben, der in JSON konvertiert werden kann, nicht nur `str`.\n\nSie könnten ein `dict`, eine `list`, usw. übergeben.\n\nDiese werden von **FastAPI** automatisch gehandhabt und in JSON konvertiert.\n\n///\n\n## Benutzerdefinierte Header hinzufügen { #add-custom-headers }\n\nEs gibt Situationen, in denen es nützlich ist, dem HTTP-Error benutzerdefinierte Header hinzuzufügen. Zum Beispiel in einigen Sicherheitsszenarien.\n\nSie werden es wahrscheinlich nicht direkt in Ihrem Code verwenden müssen.\n\nAber falls Sie es für ein fortgeschrittenes Szenario benötigen, können Sie benutzerdefinierte Header hinzufügen:\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## Benutzerdefinierte Exceptionhandler installieren { #install-custom-exception-handlers }\n\nSie können benutzerdefinierte Exceptionhandler mit [denselben Exception-Werkzeugen von Starlette](https://www.starlette.dev/exceptions/) hinzufügen.\n\nAngenommen, Sie haben eine benutzerdefinierte Exception `UnicornException`, die Sie (oder eine Bibliothek, die Sie verwenden) `raise`n könnten.\n\nUnd Sie möchten diese Exception global mit FastAPI handhaben.\n\nSie könnten einen benutzerdefinierten Exceptionhandler mit `@app.exception_handler()` hinzufügen:\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\nHier, wenn Sie `/unicorns/yolo` anfordern, wird die *Pfadoperation* eine `UnicornException` `raise`n.\n\nAber diese wird von `unicorn_exception_handler` gehandhabt.\n\nSie erhalten also einen sauberen Fehler mit einem HTTP-Statuscode von `418` und dem JSON-Inhalt:\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | Technische Details\n\nSie könnten auch `from starlette.requests import Request` und `from starlette.responses import JSONResponse` verwenden.\n\n**FastAPI** bietet dieselben `starlette.responses` auch via `fastapi.responses` an, nur als Annehmlichkeit für Sie, den Entwickler. Aber die meisten verfügbaren Responses kommen direkt von Starlette. Dasselbe gilt für `Request`.\n\n///\n\n## Die Default-Exceptionhandler überschreiben { #override-the-default-exception-handlers }\n\n**FastAPI** hat einige Default-Exceptionhandler.\n\nDiese Handler sind dafür verantwortlich, die Default-JSON-Responses zurückzugeben, wenn Sie eine `HTTPException` `raise`n und wenn der Request ungültige Daten enthält.\n\nSie können diese Exceptionhandler mit Ihren eigenen überschreiben.\n\n### Überschreiben von Request-Validierungs-Exceptions { #override-request-validation-exceptions }\n\nWenn ein Request ungültige Daten enthält, löst **FastAPI** intern einen `RequestValidationError` aus.\n\nUnd es enthält auch einen Default-Exceptionhandler für diesen.\n\nUm diesen zu überschreiben, importieren Sie den `RequestValidationError` und verwenden Sie ihn mit `@app.exception_handler(RequestValidationError)`, um den Exceptionhandler zu dekorieren.\n\nDer Exceptionhandler erhält einen `Request` und die Exception.\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\nWenn Sie nun zu `/items/foo` gehen, erhalten Sie anstelle des standardmäßigen JSON-Fehlers mit:\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\neine Textversion mit:\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### Überschreiben des `HTTPException`-Fehlerhandlers { #override-the-httpexception-error-handler }\n\nAuf die gleiche Weise können Sie den `HTTPException`-Handler überschreiben.\n\nZum Beispiel könnten Sie eine Klartext-Response statt JSON für diese Fehler zurückgeben wollen:\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | Technische Details\n\nSie könnten auch `from starlette.responses import PlainTextResponse` verwenden.\n\n**FastAPI** bietet dieselben `starlette.responses` auch via `fastapi.responses` an, nur als Annehmlichkeit für Sie, den Entwickler. Aber die meisten verfügbaren Responses kommen direkt von Starlette.\n\n///\n\n/// warning | Achtung\n\nBeachten Sie, dass der `RequestValidationError` Informationen über den Dateinamen und die Zeile enthält, in der der Validierungsfehler auftritt, sodass Sie ihn bei Bedarf mit den relevanten Informationen in Ihren Logs anzeigen können.\n\nDas bedeutet aber auch, dass, wenn Sie ihn einfach in einen String umwandeln und diese Informationen direkt zurückgeben, Sie möglicherweise ein paar Informationen über Ihr System preisgeben. Daher extrahiert und zeigt der Code hier jeden Fehler getrennt.\n\n///\n\n### Verwenden des `RequestValidationError`-Bodys { #use-the-requestvalidationerror-body }\n\nDer `RequestValidationError` enthält den empfangenen `body` mit den ungültigen Daten.\n\nSie könnten diesen während der Entwicklung Ihrer Anwendung verwenden, um den Body zu loggen und zu debuggen, ihn an den Benutzer zurückzugeben usw.\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\nVersuchen Sie nun, einen ungültigen Artikel zu senden:\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\nSie erhalten eine Response, die Ihnen sagt, dass die Daten ungültig sind und die den empfangenen Body enthält:\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### FastAPIs `HTTPException` vs. Starlettes `HTTPException` { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI** hat seine eigene `HTTPException`.\n\nUnd die `HTTPException`-Fehlerklasse von **FastAPI** erbt von der `HTTPException`-Fehlerklasse von Starlette.\n\nDer einzige Unterschied besteht darin, dass die `HTTPException` von **FastAPI** beliebige JSON-konvertierbare Daten für das `detail`-Feld akzeptiert, während die `HTTPException` von Starlette nur Strings dafür akzeptiert.\n\nSie können also weiterhin die `HTTPException` von **FastAPI** wie üblich in Ihrem Code auslösen.\n\nAber wenn Sie einen Exceptionhandler registrieren, sollten Sie ihn für die `HTTPException` von Starlette registrieren.\n\nAuf diese Weise, wenn irgendein Teil des internen Codes von Starlette, oder eine Starlette-Erweiterung oder ein Plug-in, eine Starlette `HTTPException` auslöst, wird Ihr Handler in der Lage sein, diese abzufangen und zu handhaben.\n\nUm in diesem Beispiel beide `HTTPException`s im selben Code zu haben, wird die Exception von Starlette zu `StarletteHTTPException` umbenannt:\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### Die Exceptionhandler von **FastAPI** wiederverwenden { #reuse-fastapis-exception-handlers }\n\nWenn Sie die Exception zusammen mit den gleichen Default-Exceptionhandlern von **FastAPI** verwenden möchten, können Sie die Default-Exceptionhandler aus `fastapi.exception_handlers` importieren und wiederverwenden:\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\nIn diesem Beispiel geben Sie nur den Fehler mit einer sehr ausdrucksstarken Nachricht aus, aber Sie verstehen das Prinzip. Sie können die Exception verwenden und dann einfach die Default-Exceptionhandler wiederverwenden.\n"
  },
  {
    "path": "docs/de/docs/tutorial/header-param-models.md",
    "content": "# Header-Parameter-Modelle { #header-parameter-models }\n\nWenn Sie eine Gruppe verwandter **Header-Parameter** haben, können Sie ein **Pydantic-Modell** erstellen, um diese zu deklarieren.\n\nDadurch können Sie das **Modell an mehreren Stellen wiederverwenden** und auch Validierungen und Metadaten für alle Parameter gleichzeitig deklarieren. 😎\n\n/// note | Hinweis\n\nDies wird seit FastAPI Version `0.115.0` unterstützt. 🤓\n\n///\n\n## Header-Parameter mit einem Pydantic-Modell { #header-parameters-with-a-pydantic-model }\n\nDeklarieren Sie die erforderlichen **Header-Parameter** in einem **Pydantic-Modell** und dann den Parameter als `Header`:\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\n**FastAPI** wird die Daten für **jedes Feld** aus den **Headern** des <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> extrahieren und Ihnen das von Ihnen definierte Pydantic-Modell geben.\n\n## Die Dokumentation testen { #check-the-docs }\n\nSie können die erforderlichen Header in der Dokumentationsoberfläche unter `/docs` sehen:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## Zusätzliche Header verbieten { #forbid-extra-headers }\n\nIn einigen speziellen Anwendungsfällen (wahrscheinlich nicht sehr häufig) möchten Sie möglicherweise die **Header einschränken**, die Sie erhalten möchten.\n\nSie können Pydantics Modellkonfiguration verwenden, um `extra` Felder zu verbieten (`forbid`):\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\nWenn ein Client versucht, einige **zusätzliche Header** zu senden, erhält er eine **Error-<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>**.\n\nZum Beispiel, wenn der Client versucht, einen `tool`-Header mit einem Wert von `plumbus` zu senden, erhält er eine **Error-Response**, die ihm mitteilt, dass der Header-Parameter `tool` nicht erlaubt ist:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## Automatische Umwandlung von Unterstrichen deaktivieren { #disable-convert-underscores }\n\nÄhnlich wie bei regulären Header-Parametern werden bei der Verwendung von Unterstrichen in den Parameternamen diese **automatisch in Bindestriche umgewandelt**.\n\nWenn Sie beispielsweise einen Header-Parameter `save_data` im Code haben, wird der erwartete HTTP-Header `save-data` sein, und er wird auch so in der Dokumentation angezeigt.\n\nFalls Sie aus irgendeinem Grund diese automatische Umwandlung deaktivieren müssen, können Sie dies auch für Pydantic-Modelle für Header-Parameter tun.\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | Achtung\n\nBevor Sie `convert_underscores` auf `False` setzen, bedenken Sie, dass einige HTTP-Proxies und -Server die Verwendung von Headern mit Unterstrichen nicht zulassen.\n\n///\n\n## Zusammenfassung { #summary }\n\nSie können **Pydantic-Modelle** verwenden, um **Header** in **FastAPI** zu deklarieren. 😎\n"
  },
  {
    "path": "docs/de/docs/tutorial/header-params.md",
    "content": "# Header-Parameter { #header-parameters }\n\nSie können Header-Parameter genauso definieren, wie Sie `Query`-, `Path`- und `Cookie`-Parameter definieren.\n\n## `Header` importieren { #import-header }\n\nImportieren Sie zuerst `Header`:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## `Header`-Parameter deklarieren { #declare-header-parameters }\n\nDeklarieren Sie dann die Header-Parameter mit derselben Struktur wie bei `Path`, `Query` und `Cookie`.\n\nSie können den Defaultwert sowie alle zusätzlichen Validierungs- oder Annotationsparameter definieren:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Technische Details\n\n`Header` ist eine „Schwester“-Klasse von `Path`, `Query` und `Cookie`. Sie erbt ebenfalls von der gemeinsamen `Param`-Klasse.\n\nAber denken Sie daran, dass bei der Nutzung von `Query`, `Path`, `Header` und anderen Importen aus `fastapi`, diese tatsächlich Funktionen sind, die spezielle Klassen zurückgeben.\n\n///\n\n/// info | Info\n\nUm Header zu deklarieren, müssen Sie `Header` verwenden, da die Parameter sonst als Query-Parameter interpretiert werden würden.\n\n///\n\n## Automatische Konvertierung { #automatic-conversion }\n\n`Header` bietet etwas zusätzliche Funktionalität im Vergleich zu `Path`, `Query` und `Cookie`.\n\nDie meisten Standard-Header sind durch ein „Bindestrich“-Zeichen getrennt, auch bekannt als „Minus-Symbol“ (`-`).\n\nAber eine Variable wie `user-agent` ist in Python ungültig.\n\nDaher wird `Header` standardmäßig die Zeichen des Parameter-Namens von Unterstrich (`_`) zu Bindestrich (`-`) konvertieren, um die Header zu extrahieren und zu dokumentieren.\n\nAußerdem ist Groß-/Klein­schrei­bung in HTTP-Headern nicht relevant, daher können Sie sie im Standard-Python-Stil (auch bekannt als „snake_case“) deklarieren.\n\nSie können also `user_agent` verwenden, wie Sie es normalerweise im Python-Code tun würden, anstatt die Anfangsbuchstaben wie bei `User_Agent` großzuschreiben oder Ähnliches.\n\nWenn Sie aus irgendeinem Grund die automatische Konvertierung von Unterstrichen zu Bindestrichen deaktivieren müssen, setzen Sie den Parameter `convert_underscores` von `Header` auf `False`:\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | Achtung\n\nBevor Sie `convert_underscores` auf `False` setzen, bedenken Sie, dass manche HTTP-Proxys und Server die Verwendung von Headern mit Unterstrichen nicht erlauben.\n\n///\n\n## Doppelte Header { #duplicate-headers }\n\nEs ist möglich, doppelte Header zu empfangen. Damit ist gemeint, denselben Header mit mehreren Werten.\n\nSie können solche Fälle definieren, indem Sie in der Typdeklaration eine Liste verwenden.\n\nSie erhalten dann alle Werte von diesem doppelten Header als Python-`list`.\n\nUm beispielsweise einen `X-Token`-Header zu deklarieren, der mehrmals vorkommen kann, können Sie schreiben:\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\nWenn Sie mit dieser *Pfadoperation* kommunizieren und zwei HTTP-Header senden, wie:\n\n```\nX-Token: foo\nX-Token: bar\n```\n\nDann wäre die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>:\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## Zusammenfassung { #recap }\n\nDeklarieren Sie Header mit `Header`, wobei Sie dasselbe gängige Muster wie bei `Query`, `Path` und `Cookie` verwenden.\n\nUnd machen Sie sich keine Sorgen um Unterstriche in Ihren Variablen, **FastAPI** wird sich darum kümmern, sie zu konvertieren.\n"
  },
  {
    "path": "docs/de/docs/tutorial/index.md",
    "content": "# Tutorial – Benutzerhandbuch { #tutorial-user-guide }\n\nDieses Tutorial zeigt Ihnen Schritt für Schritt, wie Sie **FastAPI** mit den meisten seiner Funktionen verwenden können.\n\nJeder Abschnitt baut schrittweise auf den vorhergehenden auf, ist jedoch in einzelne Themen gegliedert, sodass Sie direkt zu einem bestimmten Thema übergehen können, um Ihre spezifischen API-Anforderungen zu lösen.\n\nEs ist auch so gestaltet, dass es als zukünftige Referenz dient, sodass Sie jederzeit zurückkommen und genau das sehen, was Sie benötigen.\n\n## Den Code ausführen { #run-the-code }\n\nAlle Codeblöcke können kopiert und direkt verwendet werden (es sind tatsächlich getestete Python-Dateien).\n\nUm eines der Beispiele auszuführen, kopieren Sie den Code in eine Datei `main.py`, und starten Sie `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nEs wird **dringend empfohlen**, den Code zu schreiben oder zu kopieren, ihn zu bearbeiten und lokal auszuführen.\n\nDie Verwendung in Ihrem eigenen Editor zeigt Ihnen die Vorteile von FastAPI am besten, wenn Sie sehen, wie wenig Code Sie schreiben müssen, all die Typprüfungen, die automatische Vervollständigung usw.\n\n---\n\n## FastAPI installieren { #install-fastapi }\n\nDer erste Schritt besteht darin, FastAPI zu installieren.\n\nStellen Sie sicher, dass Sie eine [virtuelle Umgebung](../virtual-environments.md) erstellen, sie aktivieren und dann **FastAPI installieren**:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | Hinweis\n\nWenn Sie mit `pip install \"fastapi[standard]\"` installieren, werden einige optionale Standard-Abhängigkeiten mit installiert, einschließlich `fastapi-cloud-cli`, welches Ihnen das Deployment in der [FastAPI Cloud](https://fastapicloud.com) ermöglicht.\n\nWenn Sie diese optionalen Abhängigkeiten nicht haben möchten, können Sie stattdessen `pip install fastapi` installieren.\n\nWenn Sie die Standard-Abhängigkeiten, aber ohne das `fastapi-cloud-cli` installieren möchten, können Sie mit `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"` installieren.\n\n///\n\n/// tip | Tipp\n\nFastAPI hat eine [offizielle Erweiterung für VS Code](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (und Cursor), die viele Funktionen bereitstellt, darunter einen Pfadoperation-Explorer, eine Pfadoperation-Suche, CodeLens-Navigation in Tests (zur Definition aus Tests springen) sowie FastAPI-Cloud-Deployment und Logs – alles direkt aus Ihrem Editor.\n\n///\n\n## Handbuch für fortgeschrittene Benutzer { #advanced-user-guide }\n\nEs gibt auch ein **Handbuch für fortgeschrittene Benutzer**, das Sie nach diesem **Tutorial – Benutzerhandbuch** lesen können.\n\nDas **Handbuch für fortgeschrittene Benutzer** baut hierauf auf, verwendet dieselben Konzepte und bringt Ihnen einige zusätzliche Funktionen bei.\n\nSie sollten jedoch zuerst das **Tutorial – Benutzerhandbuch** lesen (was Sie gerade tun).\n\nEs ist so konzipiert, dass Sie mit dem **Tutorial – Benutzerhandbuch** eine vollständige Anwendung erstellen können und diese dann je nach Bedarf mit einigen der zusätzlichen Ideen aus dem **Handbuch für fortgeschrittene Benutzer** erweitern können.\n"
  },
  {
    "path": "docs/de/docs/tutorial/metadata.md",
    "content": "# Metadaten und Dokumentations-URLs { #metadata-and-docs-urls }\n\nSie können mehrere Metadaten-Konfigurationen in Ihrer **FastAPI**-Anwendung anpassen.\n\n## Metadaten für die API { #metadata-for-api }\n\nSie können die folgenden Felder festlegen, die in der OpenAPI-Spezifikation und in den Benutzeroberflächen der automatischen API-Dokumentation verwendet werden:\n\n| Parameter | Typ | Beschreibung |\n|------------|------|-------------|\n| `title` | `str` | Der Titel der API. |\n| `summary` | `str` | Eine kurze Zusammenfassung der API. <small>Verfügbar seit OpenAPI 3.1.0, FastAPI 0.99.0.</small> |\n| `description` | `str` | Eine kurze Beschreibung der API. Kann Markdown verwenden. |\n| `version` | `string` | Die Version der API. Das ist die Version Ihrer eigenen Anwendung, nicht die von OpenAPI. Zum Beispiel `2.5.0`. |\n| `terms_of_service` | `str` | Eine URL zu den Nutzungsbedingungen für die API. Falls angegeben, muss es sich um eine URL handeln. |\n| `contact` | `dict` | Die Kontaktinformationen für die freigegebene API. Kann mehrere Felder enthalten. <details><summary><code>contact</code>-Felder</summary><table><thead><tr><th>Parameter</th><th>Typ</th><th>Beschreibung</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Der identifizierende Name der Kontaktperson/Organisation.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>Die URL, die auf die Kontaktinformationen verweist. MUSS im Format einer URL vorliegen.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>Die E-Mail-Adresse der Kontaktperson/Organisation. MUSS im Format einer E-Mail-Adresse vorliegen.</td></tr></tbody></table></details> |\n| `license_info` | `dict` | Die Lizenzinformationen für die freigegebene API. Kann mehrere Felder enthalten. <details><summary><code>license_info</code>-Felder</summary><table><thead><tr><th>Parameter</th><th>Typ</th><th>Beschreibung</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ERFORDERLICH</strong> (wenn eine <code>license_info</code> festgelegt ist). Der für die API verwendete Lizenzname.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Ein [SPDX](https://spdx.org/licenses/)-Lizenzausdruck für die API. Das Feld <code>identifier</code> und das Feld <code>url</code> schließen sich gegenseitig aus. <small>Verfügbar seit OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>Eine URL zur Lizenz, die für die API verwendet wird. MUSS im Format einer URL vorliegen.</td></tr></tbody></table></details> |\n\nSie können diese wie folgt setzen:\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | Tipp\n\nSie können Markdown im Feld `description` verwenden, und es wird in der Ausgabe gerendert.\n\n///\n\nMit dieser Konfiguration würde die automatische API-Dokumentation wie folgt aussehen:\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## Lizenzkennung { #license-identifier }\n\nSeit OpenAPI 3.1.0 und FastAPI 0.99.0 können Sie die `license_info` auch mit einem `identifier` anstelle einer `url` festlegen.\n\nZum Beispiel:\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## Metadaten für Tags { #metadata-for-tags }\n\nSie können auch zusätzliche Metadaten für die verschiedenen Tags hinzufügen, die zum Gruppieren Ihrer Pfadoperationen verwendet werden, mit dem Parameter `openapi_tags`.\n\nEr nimmt eine Liste entgegen, die für jeden Tag ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">Dictionary</abbr> enthält.\n\nJedes Dictionary kann Folgendes enthalten:\n\n* `name` (**erforderlich**): ein `str` mit demselben Tag-Namen, den Sie im Parameter `tags` in Ihren *Pfadoperationen* und `APIRouter`n verwenden.\n* `description`: ein `str` mit einer kurzen Beschreibung für das Tag. Sie kann Markdown enthalten und wird in der Benutzeroberfläche der Dokumentation angezeigt.\n* `externalDocs`: ein `dict`, das externe Dokumentation beschreibt mit:\n    * `description`: ein `str` mit einer kurzen Beschreibung für die externe Dokumentation.\n    * `url` (**erforderlich**): ein `str` mit der URL für die externe Dokumentation.\n\n### Metadaten für Tags erstellen { #create-metadata-for-tags }\n\nVersuchen wir es mit einem Beispiel mit Tags für `users` und `items`.\n\nErstellen Sie Metadaten für Ihre Tags und übergeben Sie diese an den Parameter `openapi_tags`:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\nBeachten Sie, dass Sie Markdown innerhalb der Beschreibungen verwenden können. Zum Beispiel wird „login“ in Fettschrift (**login**) und „fancy“ in Kursivschrift (_fancy_) angezeigt.\n\n/// tip | Tipp\n\nSie müssen nicht für alle von Ihnen verwendeten Tags Metadaten hinzufügen.\n\n///\n\n### Ihre Tags verwenden { #use-your-tags }\n\nVerwenden Sie den Parameter `tags` mit Ihren *Pfadoperationen* (und `APIRouter`n), um diese verschiedenen Tags zuzuweisen:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info | Info\n\nLesen Sie mehr zu Tags unter [Pfadoperation-Konfiguration](path-operation-configuration.md#tags).\n\n///\n\n### Die Dokumentation testen { #check-the-docs }\n\nWenn Sie nun die Dokumentation ansehen, werden dort alle zusätzlichen Metadaten angezeigt:\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### Reihenfolge der Tags { #order-of-tags }\n\nDie Reihenfolge der Tag-Metadaten-Dictionarys definiert auch die Reihenfolge, in der diese in der Benutzeroberfläche der Dokumentation angezeigt werden.\n\nAuch wenn beispielsweise `users` im Alphabet nach `items` kommt, wird es vor diesen angezeigt, da wir deren Metadaten als erstes Dictionary der Liste hinzugefügt haben.\n\n## OpenAPI-URL { #openapi-url }\n\nStandardmäßig wird das OpenAPI-Schema unter `/openapi.json` bereitgestellt.\n\nSie können das aber mit dem Parameter `openapi_url` konfigurieren.\n\nUm beispielsweise festzulegen, dass es unter `/api/v1/openapi.json` bereitgestellt wird:\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\nWenn Sie das OpenAPI-Schema vollständig deaktivieren möchten, können Sie `openapi_url=None` festlegen, wodurch auch die Dokumentationsbenutzeroberflächen deaktiviert werden, die es verwenden.\n\n## Dokumentations-URLs { #docs-urls }\n\nSie können die beiden enthaltenen Dokumentationsbenutzeroberflächen konfigurieren:\n\n* **Swagger UI**: bereitgestellt unter `/docs`.\n    * Sie können deren URL mit dem Parameter `docs_url` festlegen.\n    * Sie können sie deaktivieren, indem Sie `docs_url=None` festlegen.\n* **ReDoc**: bereitgestellt unter `/redoc`.\n    * Sie können deren URL mit dem Parameter `redoc_url` festlegen.\n    * Sie können sie deaktivieren, indem Sie `redoc_url=None` festlegen.\n\nUm beispielsweise Swagger UI so einzustellen, dass sie unter `/documentation` bereitgestellt wird, und ReDoc zu deaktivieren:\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/de/docs/tutorial/middleware.md",
    "content": "# Middleware { #middleware }\n\nSie können Middleware zu **FastAPI**-Anwendungen hinzufügen.\n\nEine „Middleware“ ist eine Funktion, die mit jedem **<abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr>** arbeitet, bevor er von einer bestimmten *Pfadoperation* verarbeitet wird. Und auch mit jeder **<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>**, bevor sie zurückgegeben wird.\n\n* Sie nimmt jeden **Request** entgegen, der an Ihre Anwendung gesendet wird.\n* Sie kann dann etwas mit diesem **Request** tun oder beliebigen Code ausführen.\n* Dann gibt sie den **Request** zur Verarbeitung durch den Rest der Anwendung weiter (durch eine bestimmte *Pfadoperation*).\n* Sie nimmt dann die **Response** entgegen, die von der Anwendung generiert wurde (durch eine bestimmte *Pfadoperation*).\n* Sie kann etwas mit dieser **Response** tun oder beliebigen Code ausführen.\n* Dann gibt sie die **Response** zurück.\n\n/// note | Technische Details\n\nWenn Sie Abhängigkeiten mit `yield` haben, wird der Exit-Code *nach* der Middleware ausgeführt.\n\nWenn es Hintergrundtasks gab (dies wird später im [Hintergrundtasks](background-tasks.md)-Abschnitt behandelt), werden sie *nach* allen Middlewares ausgeführt.\n\n///\n\n## Eine Middleware erstellen { #create-a-middleware }\n\nUm eine Middleware zu erstellen, verwenden Sie den Dekorator `@app.middleware(\"http\")` über einer Funktion.\n\nDie Middleware-Funktion erhält:\n\n* Den `request`.\n* Eine Funktion `call_next`, die den `request` als Parameter erhält.\n    * Diese Funktion gibt den `request` an die entsprechende *Pfadoperation* weiter.\n    * Dann gibt es die von der entsprechenden *Pfadoperation* generierte `response` zurück.\n* Sie können die `response` dann weiter modifizieren, bevor Sie sie zurückgeben.\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip | Tipp\n\nBeachten Sie, dass benutzerdefinierte proprietäre Header hinzugefügt werden können [unter Verwendung des `X-`-Präfixes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nWenn Sie jedoch benutzerdefinierte Header haben, die ein Client in einem Browser sehen soll, müssen Sie sie zu Ihrer CORS-Konfiguration ([CORS (Cross-Origin Resource Sharing)](cors.md)) hinzufügen, indem Sie den Parameter `expose_headers` verwenden, der in [Starlettes CORS-Dokumentation](https://www.starlette.dev/middleware/#corsmiddleware) dokumentiert ist.\n\n///\n\n/// note | Technische Details\n\nSie könnten auch `from starlette.requests import Request` verwenden.\n\n**FastAPI** bietet es als Komfort für Sie, den Entwickler, an. Aber es stammt direkt von Starlette.\n\n///\n\n### Vor und nach der `response` { #before-and-after-the-response }\n\nSie können Code hinzufügen, der mit dem `request` ausgeführt wird, bevor dieser von einer beliebigen *Pfadoperation* empfangen wird.\n\nUnd auch nachdem die `response` generiert wurde, bevor sie zurückgegeben wird.\n\nSie könnten beispielsweise einen benutzerdefinierten Header `X-Process-Time` hinzufügen, der die Zeit in Sekunden enthält, die benötigt wurde, um den Request zu verarbeiten und eine Response zu generieren:\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip | Tipp\n\nHier verwenden wir [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) anstelle von `time.time()`, da es für diese Anwendungsfälle präziser sein kann. 🤓\n\n///\n\n## Ausführungsreihenfolge bei mehreren Middlewares { #multiple-middleware-execution-order }\n\nWenn Sie mehrere Middlewares hinzufügen, entweder mit dem `@app.middleware()` Dekorator oder der Methode `app.add_middleware()`, umschließt jede neue Middleware die Anwendung und bildet einen Stapel. Die zuletzt hinzugefügte Middleware ist die *äußerste*, und die erste ist die *innerste*.\n\nAuf dem Requestpfad läuft die *äußerste* Middleware zuerst.\n\nAuf dem Responsepfad läuft sie zuletzt.\n\nZum Beispiel:\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\nDies führt zu folgender Ausführungsreihenfolge:\n\n* **Request**: MiddlewareB → MiddlewareA → Route\n\n* **Response**: Route → MiddlewareA → MiddlewareB\n\nDieses Stapelverhalten stellt sicher, dass Middlewares in einer vorhersehbaren und kontrollierbaren Reihenfolge ausgeführt werden.\n\n## Andere Middlewares { #other-middlewares }\n\nSie können später mehr über andere Middlewares im [Handbuch für fortgeschrittene Benutzer: Fortgeschrittene Middleware](../advanced/middleware.md) lesen.\n\nIn der nächsten Sektion erfahren Sie, wie Sie <abbr title=\"Cross-Origin Resource Sharing – Ressourcenfreigabe zwischen Ursprüngen\">CORS</abbr> mit einer Middleware behandeln können.\n"
  },
  {
    "path": "docs/de/docs/tutorial/path-operation-configuration.md",
    "content": "# Pfadoperation-Konfiguration { #path-operation-configuration }\n\nEs gibt mehrere Parameter, die Sie Ihrem *Pfadoperation-Dekorator* übergeben können, um ihn zu konfigurieren.\n\n/// warning | Achtung\n\nBeachten Sie, dass diese Parameter direkt dem *Pfadoperation-Dekorator* übergeben werden, nicht der *Pfadoperation-Funktion*.\n\n///\n\n## Response-Statuscode { #response-status-code }\n\nSie können den (HTTP-)`status_code` definieren, der in der <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> Ihrer *Pfadoperation* verwendet werden soll.\n\nSie können direkt den `int`-Code übergeben, etwa `404`.\n\nAber falls Sie sich nicht mehr erinnern, wofür jeder Nummerncode steht, können Sie die Abkürzungs-Konstanten in `status` verwenden:\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\nDieser Statuscode wird in der Response verwendet und zum OpenAPI-Schema hinzugefügt.\n\n/// note | Technische Details\n\nSie können auch `from starlette import status` verwenden.\n\n**FastAPI** bietet dieselben `starlette.status`-Codes auch via `fastapi.status` an, als Annehmlichkeit für Sie, den Entwickler. Sie kommen aber direkt von Starlette.\n\n///\n\n## Tags { #tags }\n\nSie können Ihrer *Pfadoperation* Tags hinzufügen, indem Sie dem Parameter `tags` eine `list`e von `str`s übergeben (in der Regel nur ein `str`):\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\nDiese werden zum OpenAPI-Schema hinzugefügt und von den automatischen Dokumentations-Benutzeroberflächen verwendet:\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### Tags mittels Enumeration { #tags-with-enums }\n\nWenn Sie eine große Anwendung haben, können sich am Ende **viele Tags** anhäufen, und Sie möchten sicherstellen, dass Sie für verwandte *Pfadoperationen* immer den **gleichen Tag** verwenden.\n\nIn diesem Fall macht es Sinn, die Tags in einem `Enum` zu speichern.\n\n**FastAPI** unterstützt das auf die gleiche Weise wie einfache Strings:\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## Zusammenfassung und Beschreibung { #summary-and-description }\n\nSie können eine <abbr title=\"Zusammenfassung\">`summary`</abbr> und eine <abbr title=\"Beschreibung\">`description`</abbr> hinzufügen:\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## Beschreibung mittels Docstring { #description-from-docstring }\n\nDa Beschreibungen oft mehrere Zeilen lang sind, können Sie die Beschreibung der *Pfadoperation* im <dfn title=\"Ein mehrzeiliger String (keiner Variable zugewiesen) als erster Ausdruck in einer Funktion, wird für die Dokumentation derselben verwendet\">Docstring</dfn> der Funktion deklarieren, und **FastAPI** wird sie daraus auslesen.\n\nSie können [Markdown](https://en.wikipedia.org/wiki/Markdown) im Docstring schreiben, es wird korrekt interpretiert und angezeigt (unter Berücksichtigung der Einrückung des Docstring).\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\nEs wird in der interaktiven Dokumentation verwendet:\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## Beschreibung der Response { #response-description }\n\nSie können die Response mit dem Parameter `response_description` beschreiben:\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info | Info\n\nBeachten Sie, dass sich `response_description` speziell auf die Response bezieht, während `description` sich generell auf die *Pfadoperation* bezieht.\n\n///\n\n/// check | Testen\n\nOpenAPI verlangt, dass jede *Pfadoperation* über eine Beschreibung der Response verfügt.\n\nDaher, wenn Sie keine vergeben, wird **FastAPI** automatisch eine für „Erfolgreiche Response“ erstellen.\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## Eine *Pfadoperation* deprecaten { #deprecate-a-path-operation }\n\nWenn Sie eine *Pfadoperation* als <dfn title=\"veraltet, obsolet: Es soll nicht mehr verwendet werden\">deprecatet</dfn> kennzeichnen möchten, ohne sie zu entfernen, fügen Sie den Parameter `deprecated` hinzu:\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\nSie wird in der interaktiven Dokumentation gut sichtbar als deprecatet markiert werden:\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\nVergleichen Sie, wie deprecatete und nicht-deprecatete *Pfadoperationen* aussehen:\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## Zusammenfassung { #recap }\n\nSie können auf einfache Weise Metadaten für Ihre *Pfadoperationen* definieren, indem Sie den *Pfadoperation-Dekoratoren* Parameter hinzufügen.\n"
  },
  {
    "path": "docs/de/docs/tutorial/path-params-numeric-validations.md",
    "content": "# Pfad-Parameter und Validierung von Zahlen { #path-parameters-and-numeric-validations }\n\nSo wie Sie mit `Query` für Query-Parameter zusätzliche Validierungen und Metadaten deklarieren können, können Sie mit `Path` die gleichen Validierungen und Metadaten für Pfad-Parameter deklarieren.\n\n## `Path` importieren { #import-path }\n\nImportieren Sie zuerst `Path` von `fastapi`, und importieren Sie `Annotated`:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info | Info\n\nFastAPI hat in Version 0.95.0 Unterstützung für `Annotated` hinzugefügt und es zur Verwendung empfohlen.\n\nWenn Sie eine ältere Version haben, würden Fehler angezeigt werden, wenn Sie versuchen, `Annotated` zu verwenden.\n\nStellen Sie sicher, dass Sie [FastAPI aktualisieren](../deployment/versions.md#upgrading-the-fastapi-versions), auf mindestens Version 0.95.1, bevor Sie `Annotated` verwenden.\n\n///\n\n## Metadaten deklarieren { #declare-metadata }\n\nSie können dieselben Parameter wie für `Query` deklarieren.\n\nUm zum Beispiel einen `title`-Metadaten-Wert für den Pfad-Parameter `item_id` zu deklarieren, können Sie schreiben:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note | Hinweis\n\nEin Pfad-Parameter ist immer erforderlich, da er Teil des Pfads sein muss. Selbst wenn Sie ihn mit `None` deklarieren oder einen Defaultwert setzen, würde das nichts ändern, er wäre dennoch immer erforderlich.\n\n///\n\n## Die Parameter sortieren, wie Sie möchten { #order-the-parameters-as-you-need }\n\n/// tip | Tipp\n\nDas ist wahrscheinlich nicht so wichtig oder notwendig, wenn Sie `Annotated` verwenden.\n\n///\n\nAngenommen, Sie möchten den Query-Parameter `q` als erforderlichen `str` deklarieren.\n\nUnd Sie müssen sonst nichts anderes für diesen Parameter deklarieren, Sie brauchen also `Query` nicht wirklich.\n\nAber Sie müssen dennoch `Path` für den `item_id`-Pfad-Parameter verwenden. Und aus irgendeinem Grund möchten Sie `Annotated` nicht verwenden.\n\nPython wird sich beschweren, wenn Sie einen Wert mit einem „Default“ vor einem Wert ohne „Default“ setzen.\n\nAber Sie können die Reihenfolge ändern und den Wert ohne Default (den Query-Parameter `q`) zuerst setzen.\n\nFür **FastAPI** spielt es keine Rolle. Es erkennt die Parameter anhand ihrer Namen, Typen und Default-Deklarationen (`Query`, `Path`, usw.), es kümmert sich nicht um die Reihenfolge.\n\nSie können Ihre Funktion also so deklarieren:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\nAber bedenken Sie, dass Sie dieses Problem nicht haben, wenn Sie `Annotated` verwenden, da es nicht darauf ankommt, dass Sie keine Funktionsparameter-Defaultwerte für `Query()` oder `Path()` verwenden.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## Die Parameter sortieren, wie Sie möchten: Tricks { #order-the-parameters-as-you-need-tricks }\n\n/// tip | Tipp\n\nDas ist wahrscheinlich nicht so wichtig oder notwendig, wenn Sie `Annotated` verwenden.\n\n///\n\nHier ist ein **kleiner Trick**, der nützlich sein kann, obwohl Sie ihn nicht oft benötigen werden.\n\nWenn Sie:\n\n* den `q`-Query-Parameter sowohl ohne `Query` als auch ohne Defaultwert deklarieren\n* den Pfad-Parameter `item_id` mit `Path` deklarieren\n* sie in einer anderen Reihenfolge haben\n* nicht `Annotated` verwenden\n\n... möchten, dann hat Python eine kleine Spezial-Syntax dafür.\n\nÜbergeben Sie `*`, als den ersten Parameter der Funktion.\n\nPython wird nichts mit diesem `*` machen, aber es wird wissen, dass alle folgenden Parameter als Schlüsselwortargumente (Schlüssel-Wert-Paare) verwendet werden sollen, auch bekannt als <abbr title=\"Von: K-ey W-ord Arg-uments\"><code>kwargs</code></abbr>. Selbst wenn diese keinen Defaultwert haben.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### Besser mit `Annotated` { #better-with-annotated }\n\nBedenken Sie, dass Sie, wenn Sie `Annotated` verwenden, da Sie keine Funktionsparameter-Defaultwerte verwenden, dieses Problem nicht haben werden und wahrscheinlich nicht `*` verwenden müssen.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## Validierung von Zahlen: Größer oder gleich { #number-validations-greater-than-or-equal }\n\nMit `Query` und `Path` (und anderen, die Sie später sehen werden) können Sie Zahlenbeschränkungen deklarieren.\n\nHier, mit `ge=1`, muss `item_id` eine ganze Zahl sein, die „`g`reater than or `e`qual to“ (größer oder gleich) `1` ist.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## Validierung von Zahlen: Größer und kleiner oder gleich { #number-validations-greater-than-and-less-than-or-equal }\n\nDas Gleiche gilt für:\n\n* `gt`: `g`reater `t`han (größer als)\n* `le`: `l`ess than or `e`qual (kleiner oder gleich)\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## Validierung von Zahlen: Floats, größer und kleiner { #number-validations-floats-greater-than-and-less-than }\n\nZahlenvalidierung funktioniert auch für <abbr title=\"Fließkommazahlen\">`float`</abbr>-Werte.\n\nHier wird es wichtig, in der Lage zu sein, <abbr title=\"greater than – größer als\"><code>gt</code></abbr> und nicht nur <abbr title=\"greater than or equal – größer oder gleich\"><code>ge</code></abbr> zu deklarieren. Da Sie mit dieser Option erzwingen können, dass ein Wert größer als `0` sein muss, selbst wenn er kleiner als `1` ist.\n\nAlso wäre `0.5` ein gültiger Wert. Aber `0.0` oder `0` nicht.\n\nUnd das Gleiche gilt für <abbr title=\"less than – kleiner als\"><code>lt</code></abbr>.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## Zusammenfassung { #recap }\n\nMit `Query`, `Path` (und anderen, die Sie noch nicht gesehen haben) können Sie Metadaten und Stringvalidierungen auf die gleichen Weisen deklarieren wie in [Query-Parameter und Stringvalidierungen](query-params-str-validations.md) beschrieben.\n\nUnd Sie können auch Zahlenvalidierungen deklarieren:\n\n* `gt`: `g`reater `t`han (größer als)\n* `ge`: `g`reater than or `e`qual (größer oder gleich)\n* `lt`: `l`ess `t`han (kleiner als)\n* `le`: `l`ess than or `e`qual (kleiner oder gleich)\n\n/// info | Info\n\n`Query`, `Path`, und andere Klassen, die Sie später sehen werden, sind Unterklassen einer gemeinsamen `Param`-Klasse.\n\nAlle von ihnen teilen die gleichen Parameter für zusätzliche Validierung und Metadaten, die Sie gesehen haben.\n\n///\n\n/// note | Technische Details\n\nWenn Sie `Query`, `Path` und andere von `fastapi` importieren, sind sie tatsächlich Funktionen.\n\nDie, wenn sie aufgerufen werden, Instanzen von Klassen mit demselben Namen zurückgeben.\n\nSie importieren also `Query`, was eine Funktion ist. Und wenn Sie sie aufrufen, gibt sie eine Instanz einer Klasse zurück, die auch `Query` genannt wird.\n\nDiese Funktionen existieren (statt die Klassen direkt zu verwenden), damit Ihr Editor keine Fehlermeldungen über ihre Typen ausgibt.\n\nAuf diese Weise können Sie Ihren normalen Editor und Ihre Programmier-Tools verwenden, ohne besondere Einstellungen vornehmen zu müssen, um diese Fehlermeldungen stummzuschalten.\n\n///\n"
  },
  {
    "path": "docs/de/docs/tutorial/path-params.md",
    "content": "# Pfad-Parameter { #path-parameters }\n\nSie können Pfad-„Parameter“ oder -„Variablen“ mit der gleichen Syntax deklarieren, welche in Python-<abbr title=\"Formatstring – Formatierter String: Der String enthält Ausdrücke, die mit geschweiften Klammern umschlossen sind. Solche Stellen werden durch den Wert des Ausdrucks ersetzt\">Formatstrings</abbr> verwendet wird:\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\nDer Wert des Pfad-Parameters `item_id` wird Ihrer Funktion als das Argument `item_id` übergeben.\n\nWenn Sie dieses Beispiel ausführen und auf [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo) gehen, sehen Sie als <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>:\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## Pfad-Parameter mit Typen { #path-parameters-with-types }\n\nSie können den Typ eines Pfad-Parameters in der Argumentliste der Funktion deklarieren, mit Standard-Python-Typannotationen:\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\nIn diesem Fall wird `item_id` als `int` deklariert, also als Ganzzahl.\n\n/// check | Testen\n\nDadurch erhalten Sie Editor-Unterstützung innerhalb Ihrer Funktion, mit Fehlerprüfungen, Codevervollständigung, usw.\n\n///\n\n## Daten-<dfn title=\"auch bekannt als: Serialisierung, Parsen, Marshalling\">Konversion</dfn> { #data-conversion }\n\nWenn Sie dieses Beispiel ausführen und Ihren Browser unter [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3) öffnen, sehen Sie als Response:\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check | Testen\n\nBeachten Sie, dass der Wert, den Ihre Funktion erhält und zurückgibt, die Zahl `3` ist, also ein `int`. Nicht der String „3“, also ein `str`.\n\nSprich, mit dieser Typdeklaration wird **FastAPI** den <dfn title=\"Den String, der von einem HTTP-Request kommt, in Python-Daten konvertieren\">„parsen“</dfn>.\n\n///\n\n## Datenvalidierung { #data-validation }\n\nWenn Sie aber im Browser [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo) besuchen, erhalten Sie eine hübsche HTTP-Fehlermeldung:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\nDer Pfad-Parameter `item_id` hatte den Wert „foo“, was kein `int` ist.\n\nDie gleiche Fehlermeldung würde angezeigt werden, wenn Sie ein `float` (also eine Kommazahl) statt eines `int`s übergeben würden, wie etwa in: [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)\n\n/// check | Testen\n\nSprich, mit der gleichen Python-Typdeklaration gibt Ihnen **FastAPI** Datenvalidierung.\n\nBeachten Sie, dass die Fehlermeldung auch direkt die Stelle anzeigt, wo die Validierung nicht erfolgreich war.\n\nDas ist unglaublich hilfreich, wenn Sie Code entwickeln und debuggen, welcher mit Ihrer API interagiert.\n\n///\n\n## Dokumentation { #documentation }\n\nWenn Sie die Seite [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) in Ihrem Browser öffnen, sehen Sie eine automatische, interaktive API-Dokumentation:\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check | Testen\n\nWiederum, mit dieser gleichen Python-Typdeklaration gibt Ihnen **FastAPI** eine automatische, interaktive Dokumentation (verwendet die Swagger-Benutzeroberfläche).\n\nBeachten Sie, dass der Pfad-Parameter dort als Ganzzahl deklariert ist.\n\n///\n\n## Nützliche Standards, alternative Dokumentation { #standards-based-benefits-alternative-documentation }\n\nUnd weil das generierte Schema vom [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md)-Standard kommt, gibt es viele kompatible Tools.\n\nZum Beispiel bietet **FastAPI** selbst eine alternative API-Dokumentation (verwendet ReDoc), welche Sie unter [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) einsehen können:\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\nUnd viele weitere kompatible Tools. Inklusive Codegenerierung für viele Sprachen.\n\n## Pydantic { #pydantic }\n\nDie ganze Datenvalidierung wird hinter den Kulissen von [Pydantic](https://docs.pydantic.dev/) durchgeführt, Sie profitieren also von dessen Vorteilen. Und Sie wissen, dass Sie in guten Händen sind.\n\nSie können für Typdeklarationen auch `str`, `float`, `bool` und viele andere komplexe Datentypen verwenden.\n\nMehrere davon werden wir in den nächsten Kapiteln erkunden.\n\n## Die Reihenfolge ist wichtig { #order-matters }\n\nWenn Sie *Pfadoperationen* erstellen, haben Sie manchmal einen fixen Pfad.\n\nEtwa `/users/me`, um Daten über den aktuellen Benutzer zu erhalten.\n\nUnd Sie haben auch einen Pfad `/users/{user_id}`, um Daten über einen spezifischen Benutzer zu erhalten, mittels einer Benutzer-ID.\n\nWeil *Pfadoperationen* in ihrer Reihenfolge ausgewertet werden, müssen Sie sicherstellen, dass der Pfad `/users/me` vor `/users/{user_id}` deklariert wurde:\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\nAnsonsten würde der Pfad für `/users/{user_id}` auch `/users/me` auswerten, und annehmen, dass ein Parameter `user_id` mit dem Wert „me“ übergeben wurde.\n\nSie können eine Pfadoperation auch nicht erneut definieren:\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\nDie erste Definition wird immer verwendet werden, da ihr Pfad zuerst übereinstimmt.\n\n## Vordefinierte Parameterwerte { #predefined-values }\n\nWenn Sie eine *Pfadoperation* haben, welche einen *Pfad-Parameter* hat, aber Sie wollen, dass dessen gültige Werte vordefiniert sind, können Sie ein Standard-Python <abbr title=\"Enumeration\">`Enum`</abbr> verwenden.\n\n### Eine `Enum`-Klasse erstellen { #create-an-enum-class }\n\nImportieren Sie `Enum` und erstellen Sie eine Unterklasse, die von `str` und `Enum` erbt.\n\nIndem Sie von `str` erben, weiß die API-Dokumentation, dass die Werte vom Typ `str` sein müssen, und wird in der Lage sein, korrekt zu rendern.\n\nErstellen Sie dann Klassen-Attribute mit festgelegten Werten, welches die erlaubten Werte sein werden:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip | Tipp\n\nFalls Sie sich fragen, was „AlexNet“, „ResNet“ und „LeNet“ ist, das sind Namen von <dfn title=\"Genauer gesagt: Deep-Learning-Modellarchitekturen\">Modellen</dfn> für maschinelles Lernen.\n\n///\n\n### Einen *Pfad-Parameter* deklarieren { #declare-a-path-parameter }\n\nDann erstellen Sie einen *Pfad-Parameter*, der als Typ die gerade erstellte Enum-Klasse hat (`ModelName`):\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### Die API-Dokumentation testen { #check-the-docs }\n\nWeil die erlaubten Werte für den *Pfad-Parameter* nun vordefiniert sind, kann die interaktive Dokumentation sie als Auswahl-Drop-Down anzeigen:\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### Mit Python-*Enumerationen* arbeiten { #working-with-python-enumerations }\n\nDer *Pfad-Parameter* wird ein *<abbr title=\"Member – Mitglied: Einer der möglichen Werte einer Enumeration\">Member</abbr> einer Enumeration* sein.\n\n#### *Enumeration-Member* vergleichen { #compare-enumeration-members }\n\nSie können ihn mit einem Member Ihrer Enumeration `ModelName` vergleichen:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### *Enumerations-Wert* erhalten { #get-the-enumeration-value }\n\nDen tatsächlichen Wert (in diesem Fall ein `str`) erhalten Sie via `model_name.value`, oder generell, `your_enum_member.value`:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip | Tipp\n\nSie können den Wert `\"lenet\"` außerdem mittels `ModelName.lenet.value` abrufen.\n\n///\n\n#### *Enumeration-Member* zurückgeben { #return-enumeration-members }\n\nSie können *Enum-Member* in ihrer *Pfadoperation* zurückgeben, sogar verschachtelt in einem JSON-Body (z. B. als `dict`).\n\nDiese werden zu ihren entsprechenden Werten konvertiert (in diesem Fall Strings), bevor sie zum Client übertragen werden:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\nIn Ihrem Client erhalten Sie eine JSON-Response, wie etwa:\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## Pfad-Parameter, die Pfade enthalten { #path-parameters-containing-paths }\n\nAngenommen, Sie haben eine *Pfadoperation* mit einem Pfad `/files/{file_path}`.\n\nAber `file_path` soll selbst einen *Pfad* enthalten, etwa `home/johndoe/myfile.txt`.\n\nSprich, die URL für diese Datei wäre etwas wie: `/files/home/johndoe/myfile.txt`.\n\n### OpenAPI-Unterstützung { #openapi-support }\n\nOpenAPI bietet nicht die Möglichkeit, dass ein *Pfad-Parameter* seinerseits einen *Pfad* enthalten kann, das würde zu Szenarios führen, die schwierig zu testen und zu definieren sind.\n\nTrotzdem können Sie das in **FastAPI** tun, indem Sie eines der internen Tools von Starlette verwenden.\n\nDie Dokumentation würde weiterhin funktionieren, allerdings wird nicht dokumentiert werden, dass der Parameter ein Pfad sein sollte.\n\n### Pfad-Konverter { #path-convertor }\n\nMittels einer Option direkt von Starlette können Sie einen *Pfad-Parameter* deklarieren, der einen Pfad enthalten soll, indem Sie eine URL wie folgt definieren:\n\n```\n/files/{file_path:path}\n```\n\nIn diesem Fall ist der Name des Parameters `file_path`. Der letzte Teil, `:path`, sagt aus, dass der Parameter ein *Pfad* sein soll.\n\nSie verwenden das also wie folgt:\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip | Tipp\n\nDer Parameter könnte einen führenden Schrägstrich (`/`) haben, wie etwa in `/home/johndoe/myfile.txt`.\n\nIn dem Fall wäre die URL: `/files//home/johndoe/myfile.txt`, mit einem doppelten Schrägstrich (`//`) zwischen `files` und `home`.\n\n///\n\n## Zusammenfassung { #recap }\n\nIn **FastAPI** erhalten Sie mittels kurzer, intuitiver Typdeklarationen:\n\n* Editor-Unterstützung: Fehlerprüfungen, Codevervollständigung, usw.\n* Daten „<dfn title=\"Den String, der von einem HTTP-Request kommt, in Python-Daten konvertieren\">parsen</dfn>“\n* Datenvalidierung\n* API-Annotationen und automatische Dokumentation\n\nUnd Sie müssen sie nur einmal deklarieren.\n\nDas ist wahrscheinlich der sichtbarste Unterschied zwischen **FastAPI** und alternativen Frameworks (abgesehen von der reinen Performanz).\n"
  },
  {
    "path": "docs/de/docs/tutorial/query-param-models.md",
    "content": "# Query-Parameter-Modelle { #query-parameter-models }\n\nWenn Sie eine Gruppe von **Query-Parametern** haben, die miteinander in Beziehung stehen, können Sie ein **Pydantic-Modell** erstellen, um diese zu deklarieren.\n\nDadurch können Sie das **Modell an mehreren Stellen wiederverwenden** und gleichzeitig Validierungen und Metadaten für alle Parameter auf einmal deklarieren. 😎\n\n/// note | Hinweis\n\nDies wird seit FastAPI Version `0.115.0` unterstützt. 🤓\n\n///\n\n## Query-Parameter mit einem Pydantic-Modell { #query-parameters-with-a-pydantic-model }\n\nDeklarieren Sie die benötigten **Query-Parameter** in einem **Pydantic-Modell** und dann den Parameter als `Query`:\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\n**FastAPI** wird die Daten für **jedes Feld** aus den **Query-Parametern** des <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> extrahieren und Ihnen das definierte Pydantic-Modell bereitstellen.\n\n## Die Dokumentation testen { #check-the-docs }\n\nSie können die Query-Parameter in der Dokumentations-Oberfläche unter `/docs` einsehen:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## Zusätzliche Query-Parameter verbieten { #forbid-extra-query-parameters }\n\nIn einigen speziellen Anwendungsfällen (wahrscheinlich nicht sehr häufig) möchten Sie möglicherweise die Query-Parameter, die Sie empfangen möchten, **beschränken**.\n\nSie können die Modellkonfiguration von Pydantic verwenden, um jegliche `extra` Felder zu `verbieten`:\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\nWenn ein Client versucht, einige **zusätzliche** Daten in den **Query-Parametern** zu senden, erhält er eine **Error-<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>**.\n\nWenn der Client beispielsweise versucht, einen `tool` Query-Parameter mit dem Wert `plumbus` zu senden, wie:\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\nerhält er eine **Error-Response**, die ihm mitteilt, dass der Query-Parameter `tool` nicht erlaubt ist:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## Zusammenfassung { #summary }\n\nSie können **Pydantic-Modelle** verwenden, um **Query-Parameter** in **FastAPI** zu deklarieren. 😎\n\n/// tip | Tipp\n\nSpoiler-Alarm: Sie können auch Pydantic-Modelle verwenden, um Cookies und Header zu deklarieren, aber darüber werden Sie später im Tutorial lesen. 🤫\n\n///\n"
  },
  {
    "path": "docs/de/docs/tutorial/query-params-str-validations.md",
    "content": "# Query-Parameter und String-Validierungen { #query-parameters-and-string-validations }\n\n**FastAPI** ermöglicht es Ihnen, zusätzliche Informationen und Validierungen für Ihre Parameter zu deklarieren.\n\nNehmen wir diese Anwendung als Beispiel:\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\nDer Query-Parameter `q` hat den Typ `str | None`, das bedeutet, dass er vom Typ `str` sein kann, aber auch `None`, und tatsächlich ist der Defaultwert `None`, sodass FastAPI weiß, dass er nicht erforderlich ist.\n\n/// note | Hinweis\n\nFastAPI erkennt, dass der Wert von `q` nicht erforderlich ist, aufgrund des Defaultwertes `= None`.\n\nDie Verwendung von `str | None` ermöglicht es Ihrem Editor, Ihnen bessere Unterstützung zu bieten und Fehler zu erkennen.\n\n///\n\n## Zusätzliche Validierung { #additional-validation }\n\nWir werden sicherstellen, dass, obwohl `q` optional ist, wann immer es bereitgestellt wird, **seine Länge 50 Zeichen nicht überschreitet**.\n\n### `Query` und `Annotated` importieren { #import-query-and-annotated }\n\nUm dies zu erreichen, importieren Sie zuerst:\n\n* `Query` von `fastapi`\n* `Annotated` von `typing`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info | Info\n\nFastAPI hat Unterstützung für `Annotated` hinzugefügt (und begonnen, es zu empfehlen) in der Version 0.95.0.\n\nWenn Sie eine ältere Version haben, würden Sie Fehler erhalten, beim Versuch, `Annotated` zu verwenden.\n\nStellen Sie sicher, dass Sie [die FastAPI-Version aktualisieren](../deployment/versions.md#upgrading-the-fastapi-versions), auf mindestens Version 0.95.1, bevor Sie `Annotated` verwenden.\n\n///\n\n## `Annotated` im Typ für den `q`-Parameter verwenden { #use-annotated-in-the-type-for-the-q-parameter }\n\nErinnern Sie sich, dass ich Ihnen zuvor in [Python-Typen-Intro](../python-types.md#type-hints-with-metadata-annotations) gesagt habe, dass `Annotated` verwendet werden kann, um Metadaten zu Ihren Parametern hinzuzufügen?\n\nJetzt ist es soweit, dies mit FastAPI zu verwenden. 🚀\n\nWir hatten diese Typannotation:\n\n```Python\nq: str | None = None\n```\n\nWas wir tun werden, ist, dies mit `Annotated` zu wrappen, sodass es zu:\n\n```Python\nq: Annotated[str | None] = None\n```\n\nBeide dieser Versionen bedeuten dasselbe: `q` ist ein Parameter, der ein `str` oder `None` sein kann, und standardmäßig ist er `None`.\n\nJetzt springen wir zu den spannenden Dingen. 🎉\n\n## `Query` zu `Annotated` im `q`-Parameter hinzufügen { #add-query-to-annotated-in-the-q-parameter }\n\nDa wir nun `Annotated` haben, in das wir mehr Informationen (in diesem Fall einige zusätzliche Validierungen) einfügen können, fügen Sie `Query` innerhalb von `Annotated` hinzu und setzen Sie den Parameter `max_length` auf `50`:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\nBeachten Sie, dass der Defaultwert weiterhin `None` ist, so dass der Parameter weiterhin optional ist.\n\nAber jetzt, mit `Query(max_length=50)` innerhalb von `Annotated`, sagen wir FastAPI, dass wir eine **zusätzliche Validierung** für diesen Wert wünschen, wir wollen, dass er maximal 50 Zeichen hat. 😎\n\n/// tip | Tipp\n\nHier verwenden wir `Query()`, weil dies ein **Query-Parameter** ist. Später werden wir andere wie `Path()`, `Body()`, `Header()`, und `Cookie()` sehen, die auch dieselben Argumente wie `Query()` akzeptieren.\n\n///\n\nFastAPI wird nun:\n\n* Die Daten **validieren**, um sicherzustellen, dass die Länge maximal 50 Zeichen beträgt\n* Einen **klaren Fehler** für den Client anzeigen, wenn die Daten ungültig sind\n* Den Parameter in der OpenAPI-Schema-*Pfadoperation* **dokumentieren** (sodass er in der **automatischen Dokumentation** angezeigt wird)\n\n## Alternative (alt): `Query` als Defaultwert { #alternative-old-query-as-the-default-value }\n\nFrühere Versionen von FastAPI (vor <dfn title=\"vor 2023-03\">0.95.0</dfn>) erforderten, dass Sie `Query` als den Defaultwert Ihres Parameters verwendeten, anstatt es innerhalb von `Annotated` zu platzieren. Es besteht eine hohe Wahrscheinlichkeit, dass Sie Code sehen, der es so verwendet, also werde ich es Ihnen erklären.\n\n/// tip | Tipp\n\nFür neuen Code und wann immer es möglich ist, verwenden Sie `Annotated` wie oben erklärt. Es gibt mehrere Vorteile (unten erläutert) und keine Nachteile. 🍰\n\n///\n\nSo würden Sie `Query()` als den Defaultwert Ihres Funktionsparameters verwenden und den Parameter `max_length` auf 50 setzen:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\nDa wir in diesem Fall (ohne die Verwendung von `Annotated`) den Defaultwert `None` in der Funktion durch `Query()` ersetzen müssen, müssen wir nun den Defaultwert mit dem Parameter `Query(default=None)` setzen, er erfüllt den gleichen Zweck, diesen Defaultwert zu definieren (zumindest für FastAPI).\n\nAlso:\n\n```Python\nq: str | None = Query(default=None)\n```\n\n... macht den Parameter optional mit einem Defaultwert von `None`, genauso wie:\n\n```Python\nq: str | None = None\n```\n\nAber die `Query`-Version deklariert ihn explizit als Query-Parameter.\n\nDann können wir mehr Parameter an `Query` übergeben. In diesem Fall den `max_length`-Parameter, der auf Strings angewendet wird:\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\nDies wird die Daten validieren, einen klaren Fehler anzeigen, wenn die Daten nicht gültig sind, und den Parameter in der OpenAPI-Schema-*Pfadoperation* dokumentieren.\n\n### `Query` als Defaultwert oder in `Annotated` { #query-as-the-default-value-or-in-annotated }\n\nBeachten Sie, dass wenn Sie `Query` innerhalb von `Annotated` verwenden, Sie den `default`-Parameter für `Query` nicht verwenden dürfen.\n\nSetzen Sie stattdessen den tatsächlichen Defaultwert des Funktionsparameters. Andernfalls wäre es inkonsistent.\n\nZum Beispiel ist das nicht erlaubt:\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n... denn es ist nicht klar, ob der Defaultwert „rick“ oder „morty“ sein soll.\n\nSie würden also (bevorzugt) schreiben:\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n... oder in älteren Codebasen finden Sie:\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### Vorzüge von `Annotated` { #advantages-of-annotated }\n\n**Es wird empfohlen, `Annotated` zu verwenden**, anstelle des Defaultwertes in Funktionsparametern, es ist aus mehreren Gründen **besser**. 🤓\n\nDer **Default**wert des **Funktionsparameters** ist der **tatsächliche Default**wert, das ist in der Regel intuitiver mit Python. 😌\n\nSie könnten **diese gleiche Funktion** in **anderen Stellen** ohne FastAPI **aufrufen**, und es würde **wie erwartet funktionieren**. Wenn es einen **erforderlichen** Parameter gibt (ohne Defaultwert), wird Ihr **Editor** Ihnen dies mit einem Fehler mitteilen, außerdem wird **Python** sich beschweren, wenn Sie es ausführen, ohne den erforderlichen Parameter zu übergeben.\n\nWenn Sie `Annotated` nicht verwenden und stattdessen die **(alte) Defaultwert-Stilform** verwenden, müssen Sie sich daran **erinnern**, die Argumente der Funktion zu übergeben, wenn Sie diese Funktion ohne FastAPI in **anderen Stellen** aufrufen. Ansonsten sind die Werte anders als erwartet (z. B. `QueryInfo` oder etwas Ähnliches statt `str`). Ihr Editor kann Ihnen nicht helfen, und Python wird die Funktion ohne Klagen ausführen und sich nur beschweren wenn die Operationen innerhalb auf einen Fehler stoßen.\n\nDa `Annotated` mehr als eine Metadaten-Annotation haben kann, könnten Sie dieselbe Funktion sogar mit anderen Tools verwenden, wie z. B. [Typer](https://typer.tiangolo.com/). 🚀\n\n## Mehr Validierungen hinzufügen { #add-more-validations }\n\nSie können auch einen `min_length`-Parameter hinzufügen:\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## Reguläre Ausdrücke hinzufügen { #add-regular-expressions }\n\nSie können einen <dfn title=\"Ein regulärer Ausdruck, regex oder regexp genannt, ist eine Sequenz von Zeichen, die ein Suchmuster für Strings definiert.\">regulären Ausdruck</dfn> `pattern` definieren, mit dem der Parameter übereinstimmen muss:\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\nDieses spezielle Suchmuster im regulären Ausdruck überprüft, dass der erhaltene Parameterwert:\n\n* `^`: mit den nachfolgenden Zeichen beginnt, keine Zeichen davor hat.\n* `fixedquery`: den exakten Text `fixedquery` hat.\n* `$`: dort endet, keine weiteren Zeichen nach `fixedquery` hat.\n\nWenn Sie sich mit all diesen **„regulärer Ausdruck“**-Ideen verloren fühlen, keine Sorge. Sie sind ein schwieriges Thema für viele Menschen. Sie können noch viele Dinge tun, ohne reguläre Ausdrücke direkt zu benötigen.\n\nAber nun wissen Sie, dass Sie sie in **FastAPI** immer dann verwenden können, wenn Sie sie brauchen.\n\n## Defaultwerte { #default-values }\n\nNatürlich können Sie Defaultwerte verwenden, die nicht `None` sind.\n\nNehmen wir an, Sie möchten, dass der `q` Query-Parameter eine `min_length` von `3` hat und einen Defaultwert von „fixedquery“:\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | Hinweis\n\nEin Defaultwert irgendeines Typs, einschließlich `None`, macht den Parameter optional (nicht erforderlich).\n\n///\n\n## Erforderliche Parameter { #required-parameters }\n\nWenn wir keine weiteren Validierungen oder Metadaten deklarieren müssen, können wir den `q` Query-Parameter erforderlich machen, indem wir einfach keinen Defaultwert deklarieren, wie:\n\n```Python\nq: str\n```\n\nstatt:\n\n```Python\nq: str | None = None\n```\n\nAber jetzt deklarieren wir es mit `Query`, zum Beispiel so:\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\nWenn Sie einen Wert als erforderlich deklarieren müssen, während Sie `Query` verwenden, deklarieren Sie einfach keinen Defaultwert:\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### Erforderlich, kann `None` sein { #required-can-be-none }\n\nSie können deklarieren, dass ein Parameter `None` akzeptieren kann, aber trotzdem erforderlich ist. Dadurch müssten Clients den Wert senden, selbst wenn der Wert `None` ist.\n\nUm das zu tun, können Sie deklarieren, dass `None` ein gültiger Typ ist, einfach indem Sie keinen Defaultwert deklarieren:\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## Query-Parameter-Liste / Mehrere Werte { #query-parameter-list-multiple-values }\n\nWenn Sie einen Query-Parameter explizit mit `Query` definieren, können Sie ihn auch so deklarieren, dass er eine Liste von Werten empfängt, oder anders gesagt, dass er mehrere Werte empfangen kann.\n\nUm zum Beispiel einen Query-Parameter `q` zu deklarieren, der mehrmals in der URL vorkommen kann, schreiben Sie:\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\nDann, mit einer URL wie:\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\nwürden Sie die mehreren `q`-*Query-Parameter*-Werte (`foo` und `bar`) in einer Python-`list` in Ihrer *Pfadoperation-Funktion* im *Funktionsparameter* `q` erhalten.\n\nSo wäre die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> zu dieser URL:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | Tipp\n\nUm einen Query-Parameter mit einem Typ `list` zu deklarieren, wie im obigen Beispiel, müssen Sie explizit `Query` verwenden, da er andernfalls als <abbr title=\"Anfragekörper\">Requestbody</abbr> interpretiert würde.\n\n///\n\nDie interaktive API-Dokumentation wird entsprechend aktualisiert, um mehrere Werte zu erlauben:\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### Query-Parameter-Liste / Mehrere Werte mit Defaults { #query-parameter-list-multiple-values-with-defaults }\n\nSie können auch eine Default-`list` von Werten definieren, wenn keine bereitgestellt werden:\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\nWenn Sie zu:\n\n```\nhttp://localhost:8000/items/\n```\n\ngehen, wird der Default für `q` sein: `[\"foo\", \"bar\"]`, und Ihre Response wird sein:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### Nur `list` verwenden { #using-just-list }\n\nSie können auch `list` direkt verwenden, anstelle von `list[str]`:\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | Hinweis\n\nBeachten Sie, dass FastAPI in diesem Fall den Inhalt der Liste nicht überprüft.\n\nZum Beispiel würde `list[int]` überprüfen (und dokumentieren), dass der Inhalt der Liste Ganzzahlen sind. Aber `list` alleine würde das nicht.\n\n///\n\n## Mehr Metadaten deklarieren { #declare-more-metadata }\n\nSie können mehr Informationen über den Parameter hinzufügen.\n\nDiese Informationen werden in das generierte OpenAPI aufgenommen und von den Dokumentationsoberflächen und externen Tools verwendet.\n\n/// note | Hinweis\n\nBeachten Sie, dass verschiedene Tools möglicherweise unterschiedliche Unterstützungslevels für OpenAPI haben.\n\nEinige davon könnten noch nicht alle zusätzlichen Informationen anzuzeigen, die Sie erklärten, obwohl in den meisten Fällen die fehlende Funktionalität bereits in der Entwicklung geplant ist.\n\n///\n\nSie können einen `title` hinzufügen:\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\nUnd eine `description`:\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## Alias-Parameter { #alias-parameters }\n\nStellen Sie sich vor, Sie möchten, dass der Parameter `item-query` ist.\n\nWie in:\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\nAber `item-query` ist kein gültiger Name für eine Variable in Python.\n\nDer am ähnlichsten wäre `item_query`.\n\nAber Sie benötigen dennoch, dass er genau `item-query` ist ...\n\nDann können Sie ein `alias` deklarieren, und dieser Alias wird verwendet, um den Parameterwert zu finden:\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## Parameter als deprecatet ausweisen { #deprecating-parameters }\n\nNehmen wir an, Ihnen gefällt dieser Parameter nicht mehr.\n\nSie müssen ihn eine Weile dort belassen, da es Clients gibt, die ihn verwenden, aber Sie möchten, dass die Dokumentation ihn klar als <dfn title=\"veraltet, obsolet: Es soll nicht mehr verwendet werden\">deprecatet</dfn> anzeigt.\n\nDann übergeben Sie den Parameter `deprecated=True` an `Query`:\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\nDie Dokumentation wird es so anzeigen:\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## Parameter von OpenAPI ausschließen { #exclude-parameters-from-openapi }\n\nUm einen Query-Parameter aus dem generierten OpenAPI-Schema auszuschließen (und somit aus den automatischen Dokumentationssystemen), setzen Sie den Parameter `include_in_schema` von `Query` auf `False`:\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## Benutzerdefinierte Validierung { #custom-validation }\n\nEs kann Fälle geben, in denen Sie eine **benutzerdefinierte Validierung** durchführen müssen, die nicht mit den oben gezeigten Parametern durchgeführt werden kann.\n\nIn diesen Fällen können Sie eine **benutzerdefinierte Validierungsfunktion** verwenden, die nach der normalen Validierung angewendet wird (z. B. nach der Validierung, dass der Wert ein `str` ist).\n\nSie können dies mit [Pydantics `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) innerhalb von `Annotated` erreichen.\n\n/// tip | Tipp\n\nPydantic unterstützt auch [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) und andere. 🤓\n\n///\n\nZum Beispiel überprüft dieser benutzerdefinierte Validator, ob die Artikel-ID mit `isbn-` für eine <abbr title=\"International Standard Book Number - Internationale Standardbuchnummer\">ISBN</abbr>-Buchnummer oder mit `imdb-` für eine <abbr title=\"Internet Movie Database - Internet-Filmdatenbank: eine Website mit Informationen über Filme\">IMDB</abbr>-Film-URL-ID beginnt:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info | Info\n\nDies ist verfügbar seit Pydantic Version 2 oder höher. 😎\n\n///\n\n/// tip | Tipp\n\nWenn Sie irgendeine Art von Validierung durchführen müssen, die eine Kommunikation mit einer **externen Komponente** erfordert, wie z. B. einer Datenbank oder einer anderen API, sollten Sie stattdessen **FastAPI-Abhängigkeiten** verwenden. Sie werden diese später kennenlernen.\n\nDiese benutzerdefinierten Validatoren sind für Dinge gedacht, die einfach mit denselben **Daten** überprüft werden können, die im Request bereitgestellt werden.\n\n///\n\n### Dieses Codebeispiel verstehen { #understand-that-code }\n\nDer wichtige Punkt ist einfach die Verwendung von **`AfterValidator` mit einer Funktion innerhalb von `Annotated`**. Fühlen Sie sich frei, diesen Teil zu überspringen. 🤸\n\n---\n\nAber wenn Sie neugierig auf dieses spezielle Codebeispiel sind und immer noch Spaß haben, hier sind einige zusätzliche Details.\n\n#### Zeichenkette mit `value.startswith()` { #string-with-value-startswith }\n\nHaben Sie bemerkt? Eine Zeichenkette mit `value.startswith()` kann ein Tuple übernehmen, und es wird jeden Wert im Tuple überprüfen:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### Ein zufälliges Item { #a-random-item }\n\nMit `data.items()` erhalten wir ein <dfn title=\"Etwas, das man mit einer for-Schleife durchlaufen kann, wie eine Liste, Set, usw.\">iterierbares Objekt</dfn> mit Tupeln, die Schlüssel und Wert für jedes <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">Dictionary</abbr>-Element enthalten.\n\nWir konvertieren dieses iterierbare Objekt mit `list(data.items())` in eine richtige `list`.\n\nDann können wir mit `random.choice()` einen **zufälligen Wert** aus der Liste erhalten, also bekommen wir ein Tuple mit `(id, name)`. Es wird etwas wie `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")` sein.\n\nDann **weisen wir diese beiden Werte** des Tupels den Variablen `id` und `name` zu.\n\nWenn der Benutzer also keine Artikel-ID bereitgestellt hat, erhält er trotzdem einen zufälligen Vorschlag.\n\n... wir tun all dies in einer **einzelnen einfachen Zeile**. 🤯 Lieben Sie nicht auch Python? 🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## Zusammenfassung { #recap }\n\nSie können zusätzliche Validierungen und Metadaten für Ihre Parameter deklarieren.\n\nAllgemeine Validierungen und Metadaten:\n\n* `alias`\n* `title`\n* `description`\n* `deprecated`\n\nValidierungen, die spezifisch für Strings sind:\n\n* `min_length`\n* `max_length`\n* `pattern`\n\nBenutzerdefinierte Validierungen mit `AfterValidator`.\n\nIn diesen Beispielen haben Sie gesehen, wie Sie Validierungen für `str`-Werte deklarieren.\n\nSehen Sie sich die nächsten Kapitel an, um zu erfahren, wie Sie Validierungen für andere Typen, wie z. B. Zahlen, deklarieren.\n"
  },
  {
    "path": "docs/de/docs/tutorial/query-params.md",
    "content": "# Query-Parameter { #query-parameters }\n\nWenn Sie in Ihrer Funktion andere Parameter deklarieren, die nicht Teil der Pfad-Parameter sind, dann werden diese automatisch als „Query“-Parameter interpretiert.\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\nDie <abbr title=\"Abfrage\">Query</abbr> ist die Menge von Schlüssel-Wert-Paaren, die nach dem `?` in einer URL folgen und durch `&`-Zeichen getrennt sind.\n\nZum Beispiel sind in der URL:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n... die Query-Parameter:\n\n* `skip`: mit dem Wert `0`\n* `limit`: mit dem Wert `10`\n\nDa sie Teil der URL sind, sind sie „naturgemäß“ Strings.\n\nAber wenn Sie sie mit Python-Typen deklarieren (im obigen Beispiel als `int`), werden sie zu diesem Typ konvertiert und gegen diesen validiert.\n\nDie gleichen Prozesse, die für Pfad-Parameter gelten, werden auch auf Query-Parameter angewendet:\n\n* Editor Unterstützung (natürlich)\n* Daten-<dfn title=\"Konvertieren des Strings, der von einem HTTP-Request kommt, in Python-Daten\">„Parsen“</dfn>\n* Datenvalidierung\n* Automatische Dokumentation\n\n## Defaultwerte { #defaults }\n\nDa Query-Parameter kein fester Teil eines Pfades sind, können sie optional sein und Defaultwerte haben.\n\nIm obigen Beispiel haben sie die Defaultwerte `skip=0` und `limit=10`.\n\nWenn Sie also zur URL:\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\ngehen, so ist das das gleiche wie die URL:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\nAber wenn Sie zum Beispiel zu:\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\ngehen, werden die Parameterwerte Ihrer Funktion sein:\n\n* `skip=20`: da Sie das in der URL gesetzt haben\n* `limit=10`: weil das der Defaultwert ist\n\n## Optionale Parameter { #optional-parameters }\n\nAuf die gleiche Weise können Sie optionale Query-Parameter deklarieren, indem Sie deren Defaultwert auf `None` setzen:\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\nIn diesem Fall wird der Funktionsparameter `q` optional und standardmäßig `None` sein.\n\n/// check | Testen\n\nBeachten Sie auch, dass **FastAPI** intelligent genug ist, um zu erkennen, dass `item_id` ein Pfad-Parameter ist und `q` keiner, daher muss letzteres ein Query-Parameter sein.\n\n///\n\n## Query-Parameter Typkonvertierung { #query-parameter-type-conversion }\n\nSie können auch `bool`-Typen deklarieren, und sie werden konvertiert:\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\nWenn Sie nun zu:\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\noder\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\noder\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\noder\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\noder\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\ngehen, oder zu irgendeiner anderen Variante der Groß-/Kleinschreibung (Alles groß, Anfangsbuchstabe groß, usw.), dann wird Ihre Funktion den Parameter `short` mit dem `bool`-Wert `True` sehen, ansonsten mit dem Wert `False`.\n\n## Mehrere Pfad- und Query-Parameter { #multiple-path-and-query-parameters }\n\nSie können mehrere Pfad-Parameter und Query-Parameter gleichzeitig deklarieren, **FastAPI** weiß, welches welcher ist.\n\nUnd Sie müssen sie auch nicht in einer spezifischen Reihenfolge deklarieren.\n\nParameter werden anhand ihres Namens erkannt:\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## Erforderliche Query-Parameter { #required-query-parameters }\n\nWenn Sie einen Defaultwert für Nicht-Pfad-Parameter deklarieren (Bis jetzt haben wir nur Query-Parameter gesehen), dann ist der Parameter nicht erforderlich.\n\nWenn Sie keinen spezifischen Wert haben wollen, sondern der Parameter einfach optional sein soll, dann setzen Sie den Defaultwert auf `None`.\n\nAber wenn Sie wollen, dass ein Query-Parameter erforderlich ist, vergeben Sie einfach keinen Defaultwert:\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\nHier ist `needy` ein erforderlicher Query-Parameter vom Typ `str`.\n\nWenn Sie in Ihrem Browser eine URL wie:\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n... öffnen, ohne den benötigten Parameter `needy`, dann erhalten Sie einen Fehler wie den folgenden:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\nDa `needy` ein erforderlicher Parameter ist, müssen Sie ihn in der URL setzen:\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n... Das funktioniert:\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\nUnd natürlich können Sie einige Parameter als erforderlich, einige mit Defaultwert, und einige als vollständig optional definieren:\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\nIn diesem Fall gibt es drei Query-Parameter:\n\n* `needy`, ein erforderlicher `str`.\n* `skip`, ein `int` mit einem Defaultwert `0`.\n* `limit`, ein optionales `int`.\n\n/// tip | Tipp\n\nSie können auch `Enum`s verwenden, auf die gleiche Weise wie mit [Pfad-Parametern](path-params.md#predefined-values).\n\n///\n"
  },
  {
    "path": "docs/de/docs/tutorial/request-files.md",
    "content": "# Dateien im Request { #request-files }\n\nSie können Dateien, die vom Client hochgeladen werden, mithilfe von `File` definieren.\n\n/// info | Info\n\nUm hochgeladene Dateien zu empfangen, installieren Sie zuerst [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nStellen Sie sicher, dass Sie eine [virtuelle Umgebung](../virtual-environments.md) erstellen, sie aktivieren und dann das Paket installieren, zum Beispiel:\n\n```console\n$ pip install python-multipart\n```\n\nDas liegt daran, dass hochgeladene Dateien als „Formulardaten“ gesendet werden.\n\n///\n\n## `File` importieren { #import-file }\n\nImportieren Sie `File` und `UploadFile` von `fastapi`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## `File`-Parameter definieren { #define-file-parameters }\n\nErstellen Sie Datei-Parameter, so wie Sie es auch mit `Body` und `Form` machen würden:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info | Info\n\n`File` ist eine Klasse, die direkt von `Form` erbt.\n\nAber erinnern Sie sich, dass, wenn Sie `Query`, `Path`, `File` und andere von `fastapi` importieren, diese tatsächlich Funktionen sind, welche spezielle Klassen zurückgeben.\n\n///\n\n/// tip | Tipp\n\nUm Dateibodys zu deklarieren, müssen Sie `File` verwenden, da diese Parameter sonst als Query-Parameter oder Body (JSON)-Parameter interpretiert werden würden.\n\n///\n\nDie Dateien werden als „Formulardaten“ hochgeladen.\n\nWenn Sie den Typ Ihrer *Pfadoperation-Funktion* als `bytes` deklarieren, wird **FastAPI** die Datei für Sie auslesen, und Sie erhalten den Inhalt als `bytes`.\n\nBedenken Sie, dass das bedeutet, dass sich der gesamte Inhalt der Datei im Arbeitsspeicher befindet. Das wird für kleinere Dateien gut funktionieren.\n\nAber es gibt viele Fälle, in denen Sie davon profitieren, `UploadFile` zu verwenden.\n\n## Datei-Parameter mit `UploadFile` { #file-parameters-with-uploadfile }\n\nDefinieren Sie einen Datei-Parameter mit dem Typ `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\n`UploadFile` zu verwenden, hat mehrere Vorzüge gegenüber `bytes`:\n\n* Sie müssen `File()` nicht als Parameter-Defaultwert verwenden.\n* Es wird eine <abbr title=\"warteschlangenartig\">„gespoolte“</abbr> Datei verwendet:\n    * Eine Datei, die bis zu einem bestimmten Größen-Limit im Arbeitsspeicher behalten wird, und wenn das Limit überschritten wird, auf der Festplatte gespeichert wird.\n* Das bedeutet, es wird für große Dateien wie Bilder, Videos, große Binärdateien, usw. gut funktionieren, ohne den ganzen Arbeitsspeicher aufzubrauchen.\n* Sie können Metadaten aus der hochgeladenen Datei auslesen.\n* Es hat eine [dateiartige](https://docs.python.org/3/glossary.html#term-file-like-object) `async`hrone Schnittstelle.\n* Es stellt ein tatsächliches Python-[`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile)-Objekt bereit, welches Sie direkt anderen Bibliotheken übergeben können, die ein dateiartiges Objekt erwarten.\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` hat die folgenden Attribute:\n\n* `filename`: Ein `str` mit dem ursprünglichen Namen der hochgeladenen Datei (z. B. `meinbild.jpg`).\n* `content_type`: Ein `str` mit dem Inhaltstyp (MIME-Typ / Medientyp) (z. B. `image/jpeg`).\n* `file`: Ein [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (ein [dateiartiges](https://docs.python.org/3/glossary.html#term-file-like-object) Objekt). Das ist das tatsächliche Python-Objekt, das Sie direkt anderen Funktionen oder Bibliotheken übergeben können, welche ein „file-like“-Objekt erwarten.\n\n`UploadFile` hat die folgenden `async`hronen Methoden. Sie alle rufen die entsprechenden Methoden des darunterliegenden Datei-Objekts auf (wobei intern `SpooledTemporaryFile` verwendet wird).\n\n* `write(daten)`: Schreibt `daten` (`str` oder `bytes`) in die Datei.\n* `read(anzahl)`: Liest `anzahl` (`int`) bytes/Zeichen aus der Datei.\n* `seek(versatz)`: Geht zur Position `versatz` (`int`) in der Datei.\n    * z. B. würde `await myfile.seek(0)` zum Anfang der Datei gehen.\n    * Das ist besonders dann nützlich, wenn Sie `await myfile.read()` einmal ausführen und dann diese Inhalte erneut auslesen müssen.\n* `close()`: Schließt die Datei.\n\nDa alle diese Methoden `async`hron sind, müssen Sie sie „await“en („erwarten“).\n\nZum Beispiel können Sie innerhalb einer `async` *Pfadoperation-Funktion* den Inhalt wie folgt auslesen:\n\n```Python\ncontents = await myfile.read()\n```\n\nWenn Sie sich innerhalb einer normalen `def`-*Pfadoperation-Funktion* befinden, können Sie direkt auf `UploadFile.file` zugreifen, zum Beispiel:\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | Technische Details zu `async`\n\nWenn Sie die `async`-Methoden verwenden, führt **FastAPI** die Datei-Methoden in einem <abbr title=\"Mehrere unabhängige Kindprozesse\">Threadpool</abbr> aus und erwartet sie.\n\n///\n\n/// note | Technische Details zu Starlette\n\nFastAPIs `UploadFile` erbt direkt von Starlettes `UploadFile`, fügt aber ein paar notwendige Teile hinzu, um es kompatibel mit **Pydantic** und anderen Teilen von FastAPI zu machen.\n\n///\n\n## Was sind „Formulardaten“ { #what-is-form-data }\n\nDer Weg, wie HTML-Formulare (`<form></form>`) die Daten zum Server senden, verwendet normalerweise eine „spezielle“ Kodierung für diese Daten. Diese unterscheidet sich von JSON.\n\n**FastAPI** stellt sicher, dass diese Daten korrekt ausgelesen werden, statt JSON zu erwarten.\n\n/// note | Technische Details\n\nDaten aus Formularen werden, wenn es keine Dateien sind, normalerweise mit dem <abbr title='Media type – Medientyp, Typ des Mediums'>„media type“</abbr> `application/x-www-form-urlencoded` kodiert.\n\nSollte das Formular aber Dateien enthalten, dann werden diese mit `multipart/form-data` kodiert. Wenn Sie `File` verwenden, wird **FastAPI** wissen, dass es die Dateien vom korrekten Teil des Bodys holen muss.\n\nWenn Sie mehr über diese Kodierungen und Formularfelder lesen möchten, besuchen Sie die [<abbr title=\"Mozilla Developer Network – Mozilla-Entwicklernetzwerk\">MDN</abbr>-Webdokumentation für `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Achtung\n\nSie können mehrere `File`- und `Form`-Parameter in einer *Pfadoperation* deklarieren, aber Sie können nicht gleichzeitig auch `Body`-Felder deklarieren, welche Sie als JSON erwarten, da der <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> den Body mittels `multipart/form-data` statt `application/json` kodiert.\n\nDas ist keine Limitation von **FastAPI**, sondern Teil des HTTP-Protokolls.\n\n///\n\n## Optionaler Datei-Upload { #optional-file-upload }\n\nSie können eine Datei optional machen, indem Sie Standard-Typannotationen verwenden und den Defaultwert auf `None` setzen:\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## `UploadFile` mit zusätzlichen Metadaten { #uploadfile-with-additional-metadata }\n\nSie können auch `File()` mit `UploadFile` verwenden, um zum Beispiel zusätzliche Metadaten zu setzen:\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## Mehrere Datei-Uploads { #multiple-file-uploads }\n\nEs ist auch möglich, mehrere Dateien gleichzeitig hochzuladen.\n\nDiese werden demselben Formularfeld zugeordnet, welches mit den Formulardaten gesendet wird.\n\nUm das zu machen, deklarieren Sie eine Liste von `bytes` oder `UploadFile`s:\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\nSie erhalten, wie deklariert, eine `list` von `bytes` oder `UploadFile`s.\n\n/// note | Technische Details\n\nSie können auch `from starlette.responses import HTMLResponse` verwenden.\n\n**FastAPI** bietet dieselben `starlette.responses` auch via `fastapi.responses` an, als Annehmlichkeit für Sie, den Entwickler. Die meisten verfügbaren <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Responses</abbr> kommen aber direkt von Starlette.\n\n///\n\n### Mehrere Datei-Uploads mit zusätzlichen Metadaten { #multiple-file-uploads-with-additional-metadata }\n\nUnd so wie zuvor können Sie `File()` verwenden, um zusätzliche Parameter zu setzen, sogar für `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## Zusammenfassung { #recap }\n\nVerwenden Sie `File`, `bytes` und `UploadFile`, um hochladbare Dateien im Request zu deklarieren, die als Formulardaten gesendet werden.\n"
  },
  {
    "path": "docs/de/docs/tutorial/request-form-models.md",
    "content": "# Formularmodelle { #form-models }\n\nSie können **Pydantic-Modelle** verwenden, um **Formularfelder** in FastAPI zu deklarieren.\n\n/// info | Info\n\nUm Formulare zu verwenden, installieren Sie zuerst [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nStellen Sie sicher, dass Sie eine [Virtuelle Umgebung](../virtual-environments.md) erstellen, sie aktivieren und es dann installieren, zum Beispiel:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note | Hinweis\n\nDies wird seit FastAPI Version `0.113.0` unterstützt. 🤓\n\n///\n\n## Pydantic-Modelle für Formulare { #pydantic-models-for-forms }\n\nSie müssen nur ein **Pydantic-Modell** mit den Feldern deklarieren, die Sie als **Formularfelder** erhalten möchten, und dann den Parameter als `Form` deklarieren:\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI** wird die Daten für **jedes Feld** aus den **Formulardaten** im <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> **extrahieren** und Ihnen das von Ihnen definierte Pydantic-Modell übergeben.\n\n## Die Dokumentation testen { #check-the-docs }\n\nSie können dies in der Dokumentations-UI unter `/docs` testen:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## Zusätzliche Formularfelder verbieten { #forbid-extra-form-fields }\n\nIn einigen speziellen Anwendungsfällen (wahrscheinlich nicht sehr häufig) möchten Sie möglicherweise die Formularfelder auf nur diejenigen beschränken, die im Pydantic-Modell deklariert sind, und jegliche **zusätzlichen** Felder **verbieten**.\n\n/// note | Hinweis\n\nDies wird seit FastAPI Version `0.114.0` unterstützt. 🤓\n\n///\n\nSie können die Modellkonfiguration von Pydantic verwenden, um jegliche `extra` Felder zu `verbieten`:\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\nWenn ein Client versucht, einige zusätzliche Daten zu senden, erhält er eine **Error-<abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr>**.\n\nZum Beispiel, wenn der Client versucht, folgende Formularfelder zu senden:\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\nerhält er eine Error-Response, die ihm mitteilt, dass das Feld `extra` nicht erlaubt ist:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## Zusammenfassung { #summary }\n\nSie können Pydantic-Modelle verwenden, um Formularfelder in FastAPI zu deklarieren. 😎\n"
  },
  {
    "path": "docs/de/docs/tutorial/request-forms-and-files.md",
    "content": "# Formulardaten und Dateien im Request { #request-forms-and-files }\n\nSie können gleichzeitig Dateien und Formulardaten mit `File` und `Form` definieren.\n\n/// info | Info\n\nUm hochgeladene Dateien und/oder Formulardaten zu empfangen, installieren Sie zuerst [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nStellen Sie sicher, dass Sie eine [virtuelle Umgebung](../virtual-environments.md) erstellen, diese aktivieren und es dann installieren, z. B.:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## `File` und `Form` importieren { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## `File` und `Form`-Parameter definieren { #define-file-and-form-parameters }\n\nErstellen Sie Datei- und Formularparameter, so wie Sie es auch mit `Body` oder `Query` machen würden:\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\nDie Datei- und Formularfelder werden als Formulardaten hochgeladen, und Sie erhalten diese Dateien und Formularfelder.\n\nUnd Sie können einige der Dateien als `bytes` und einige als `UploadFile` deklarieren.\n\n/// warning | Achtung\n\nSie können mehrere `File`- und `Form`-Parameter in einer *Pfadoperation* deklarieren, aber Sie können nicht auch `Body`-Felder deklarieren, die Sie als JSON erwarten, da der Body des <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> mittels `multipart/form-data` statt `application/json` kodiert sein wird.\n\nDas ist keine Limitation von **FastAPI**, sondern Teil des HTTP-Protokolls.\n\n///\n\n## Zusammenfassung { #recap }\n\nVerwenden Sie `File` und `Form` zusammen, wenn Sie Daten und Dateien zusammen im selben Request empfangen müssen.\n"
  },
  {
    "path": "docs/de/docs/tutorial/request-forms.md",
    "content": "# Formulardaten { #form-data }\n\nWenn Sie Felder aus Formularen statt JSON empfangen müssen, können Sie `Form` verwenden.\n\n/// info | Info\n\nUm Formulare zu verwenden, installieren Sie zuerst [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nErstellen Sie unbedingt eine [virtuelle Umgebung](../virtual-environments.md), aktivieren Sie diese und installieren Sie dann das Paket, zum Beispiel:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## `Form` importieren { #import-form }\n\nImportieren Sie `Form` von `fastapi`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## `Form`-Parameter definieren { #define-form-parameters }\n\nErstellen Sie Formular-Parameter, so wie Sie es auch mit `Body` und `Query` machen würden:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\nZum Beispiel stellt eine der Möglichkeiten, die OAuth2-Spezifikation zu verwenden (genannt „password flow“), die Bedingung, einen `username` und ein `password` als Formularfelder zu senden.\n\nDie <dfn title=\"Spezifikation\">Spezifikation</dfn> erfordert, dass die Felder exakt `username` und `password` genannt werden und als Formularfelder, nicht JSON, gesendet werden.\n\nMit `Form` haben Sie die gleichen Konfigurationsmöglichkeiten wie mit `Body` (und `Query`, `Path`, `Cookie`), inklusive Validierung, Beispielen, einem Alias (z. B. `user-name` statt `username`), usw.\n\n/// info | Info\n\n`Form` ist eine Klasse, die direkt von `Body` erbt.\n\n///\n\n/// tip | Tipp\n\nUm Formularbodys zu deklarieren, verwenden Sie explizit `Form`, da diese Parameter sonst als Query-Parameter oder Body (JSON)-Parameter interpretiert werden würden.\n\n///\n\n## Über „Formularfelder“ { #about-form-fields }\n\nHTML-Formulare (`<form></form>`) senden die Daten in einer „speziellen“ Kodierung zum Server, die sich von JSON unterscheidet.\n\n**FastAPI** stellt sicher, dass diese Daten korrekt ausgelesen werden, statt JSON zu erwarten.\n\n/// note | Technische Details\n\nDaten aus Formularen werden normalerweise mit dem <abbr title=\"Medientyp\">„media type“</abbr> `application/x-www-form-urlencoded` kodiert.\n\nWenn das Formular stattdessen Dateien enthält, werden diese mit `multipart/form-data` kodiert. Im nächsten Kapitel erfahren Sie mehr über die Handhabung von Dateien.\n\nWenn Sie mehr über Formularfelder und ihre Kodierungen lesen möchten, besuchen Sie die [<abbr title=\"Mozilla Developer Network – Mozilla-Entwicklernetzwerk\">MDN</abbr>-Webdokumentation für `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Achtung\n\nSie können mehrere `Form`-Parameter in einer *Pfadoperation* deklarieren, aber Sie können nicht gleichzeitig auch `Body`-Felder deklarieren, welche Sie als JSON erwarten, da der <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> den Body mittels `application/x-www-form-urlencoded` statt `application/json` kodiert.\n\nDas ist keine Limitation von **FastAPI**, sondern Teil des HTTP-Protokolls.\n\n///\n\n## Zusammenfassung { #recap }\n\nVerwenden Sie `Form`, um Eingabe-Parameter für Formulardaten zu deklarieren.\n"
  },
  {
    "path": "docs/de/docs/tutorial/response-model.md",
    "content": "# Responsemodell – Rückgabetyp { #response-model-return-type }\n\nSie können den Typ der <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> deklarieren, indem Sie den **Rückgabetyp** der *Pfadoperation* annotieren.\n\nHierbei können Sie **Typannotationen** genauso verwenden, wie Sie es bei Werten von Funktions-**Parametern** machen; verwenden Sie Pydantic-Modelle, Listen, Dicts und skalare Werte wie Nummern, Booleans, usw.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPI wird diesen Rückgabetyp verwenden, um:\n\n* Die zurückzugebenden Daten zu **validieren**.\n    * Wenn die Daten ungültig sind (Sie haben z. B. ein Feld vergessen), bedeutet das, *Ihr* Anwendungscode ist fehlerhaft, er gibt nicht zurück, was er sollte, und daher wird ein <abbr title=\"Server-Fehler\">Server-Error</abbr> ausgegeben, statt falscher Daten. So können Sie und Ihre Clients sicher sein, dass diese die erwarteten Daten, in der richtigen Form erhalten.\n* In der OpenAPI *Pfadoperation* ein **JSON-Schema** für die Response hinzuzufügen.\n    * Dieses wird von der **automatischen Dokumentation** verwendet.\n    * Es wird auch von automatisch Client-Code-generierenden Tools verwendet.\n* Die zurückgegebenen Daten mit Pydantic zu **serialisieren** (zu JSON). Pydantic ist in **Rust** geschrieben und daher **viel schneller**.\n\nAber am wichtigsten:\n\n* Es wird die Ausgabedaten auf das **limitieren und filtern**, was im Rückgabetyp definiert ist.\n    * Das ist insbesondere für die **Sicherheit** wichtig, mehr dazu unten.\n\n## `response_model`-Parameter { #response-model-parameter }\n\nEs gibt Fälle, da möchten oder müssen Sie Daten zurückgeben, die nicht genau dem entsprechen, was der Typ deklariert.\n\nZum Beispiel könnten Sie **ein Dictionary zurückgeben** wollen, oder ein Datenbank-Objekt, aber **es als Pydantic-Modell deklarieren**. Auf diese Weise übernimmt das Pydantic-Modell alle Datendokumentation, -validierung, usw. für das Objekt, welches Sie zurückgeben (z. B. ein Dictionary oder ein Datenbank-Objekt).\n\nWürden Sie eine hierfür eine Rückgabetyp-Annotation verwenden, dann würden Tools und Editoren (korrekterweise) Fehler ausgeben, die Ihnen sagen, dass Ihre Funktion einen Typ zurückgibt (z. B. ein Dict), der sich unterscheidet von dem, was Sie deklariert haben (z. B. ein Pydantic-Modell).\n\nIn solchen Fällen können Sie statt des Rückgabetyps den **Pfadoperation-Dekorator**-Parameter `response_model` verwenden.\n\nSie können `response_model` in jeder möglichen *Pfadoperation* verwenden:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* usw.\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | Hinweis\n\nBeachten Sie, dass `response_model` ein Parameter der „Dekorator“-Methode ist (`get`, `post`, usw.). Nicht der *Pfadoperation-Funktion*, so wie die anderen Parameter und der Body.\n\n///\n\n`response_model` nimmt denselben Typ entgegen, den Sie auch für ein Pydantic-Modellfeld deklarieren würden, also etwa ein Pydantic-Modell, aber es kann auch z. B. eine `list`e von Pydantic-Modellen sein, wie etwa `List[Item]`.\n\nFastAPI wird dieses `response_model` nehmen, um die Daten zu dokumentieren, validieren, usw. und auch, um **die Ausgabedaten** entsprechend der Typdeklaration **zu konvertieren und filtern**.\n\n/// tip | Tipp\n\nWenn Sie in Ihrem Editor strikte Typchecks haben, mypy, usw., können Sie den Funktions-Rückgabetyp als <abbr title=\"„Irgend etwas“\">`Any`</abbr> deklarieren.\n\nSo sagen Sie dem Editor, dass Sie absichtlich *irgendetwas* zurückgeben. Aber FastAPI wird trotzdem die Dokumentation, Validierung, Filterung, usw. der Daten übernehmen, via `response_model`.\n\n///\n\n### `response_model`-Priorität { #response-model-priority }\n\nWenn sowohl Rückgabetyp als auch `response_model` deklariert sind, hat `response_model` die Priorität und wird von FastAPI bevorzugt verwendet.\n\nSo können Sie korrekte Typannotationen zu Ihrer Funktion hinzufügen, die von Ihrem Editor und Tools wie mypy verwendet werden. Und dennoch übernimmt FastAPI die Validierung und Dokumentation, usw., der Daten anhand von `response_model`.\n\nSie können auch `response_model=None` verwenden, um das Erstellen eines Responsemodells für diese *Pfadoperation* zu unterbinden. Sie könnten das tun wollen, wenn Sie Dinge annotieren, die nicht gültige Pydantic-Felder sind. Ein Beispiel dazu werden Sie in einer der Abschnitte unten sehen.\n\n## Dieselben Eingabedaten zurückgeben { #return-the-same-input-data }\n\nIm Folgenden deklarieren wir ein `UserIn`-Modell; es enthält ein Klartext-Passwort:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | Info\n\nUm `EmailStr` zu verwenden, installieren Sie zuerst [`email-validator`](https://github.com/JoshData/python-email-validator).\n\nStellen Sie sicher, dass Sie eine [virtuelle Umgebung](../virtual-environments.md) erstellen, sie aktivieren und es dann installieren, zum Beispiel:\n\n```console\n$ pip install email-validator\n```\n\noder mit:\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\nWir verwenden dieses Modell, um sowohl unsere Eingabe- als auch Ausgabedaten zu deklarieren:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\nImmer wenn jetzt ein Browser einen Benutzer mit Passwort erzeugt, gibt die API dasselbe Passwort in der Response zurück.\n\nHier ist das möglicherweise kein Problem, da es derselbe Benutzer ist, der das Passwort sendet.\n\nAber wenn wir dasselbe Modell für eine andere *Pfadoperation* verwenden, könnten wir das Passwort dieses Benutzers zu jedem Client schicken.\n\n/// danger | Gefahr\n\nSpeichern Sie niemals das Klartext-Passwort eines Benutzers, oder versenden Sie es in einer Response wie dieser, wenn Sie sich nicht der resultierenden Gefahren bewusst sind und nicht wissen, was Sie tun.\n\n///\n\n## Ausgabemodell hinzufügen { #add-an-output-model }\n\nWir können stattdessen ein Eingabemodell mit dem Klartext-Passwort, und ein Ausgabemodell ohne das Passwort erstellen:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\nObwohl unsere *Pfadoperation-Funktion* hier denselben `user` von der Eingabe zurückgibt, der das Passwort enthält:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n... haben wir deklariert, dass `response_model` das Modell `UserOut` ist, welches das Passwort nicht enthält:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\nDarum wird **FastAPI** sich darum kümmern, dass alle Daten, die nicht im Ausgabemodell deklariert sind, herausgefiltert werden (mittels Pydantic).\n\n### `response_model` oder Rückgabewert { #response-model-or-return-type }\n\nDa unsere zwei Modelle in diesem Fall unterschiedlich sind, würde, wenn wir den Rückgabewert der Funktion als `UserOut` deklarieren, der Editor sich beschweren, dass wir einen ungültigen Typ zurückgeben, weil das unterschiedliche Klassen sind.\n\nDarum müssen wir es in diesem Fall im `response_model`-Parameter deklarieren.\n\n... aber lesen Sie weiter, um zu sehen, wie man das anders lösen kann.\n\n## Rückgabewert und Datenfilterung { #return-type-and-data-filtering }\n\nFühren wir unser vorheriges Beispiel fort. Wir wollten **die Funktion mit einem Typ annotieren**, aber wir wollten in der Funktion tatsächlich etwas zurückgeben, das **mehr Daten** enthält.\n\nWir möchten, dass FastAPI die Daten weiterhin mithilfe des Responsemodells **filtert**. Selbst wenn die Funktion mehr Daten zurückgibt, soll die Response nur die Felder enthalten, die im Responsemodell deklariert sind.\n\nIm vorherigen Beispiel mussten wir den `response_model`-Parameter verwenden, weil die Klassen unterschiedlich waren. Das bedeutet aber auch, wir bekommen keine Unterstützung vom Editor und anderen Tools, die den Funktions-Rückgabewert überprüfen.\n\nAber in den meisten Fällen, wenn wir so etwas machen, wollen wir nur, dass das Modell einige der Daten **filtert/entfernt**, so wie in diesem Beispiel.\n\nUnd in solchen Fällen können wir Klassen und Vererbung verwenden, um Vorteil aus den Typannotationen in der Funktion zu ziehen, was vom Editor und von Tools besser unterstützt wird, während wir gleichzeitig FastAPIs **Datenfilterung** behalten.\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\nDamit erhalten wir Tool-Unterstützung, vom Editor und mypy, da dieser Code hinsichtlich der Typen korrekt ist, aber wir erhalten auch die Datenfilterung von FastAPI.\n\nWie funktioniert das? Schauen wir uns das mal an. 🤓\n\n### Typannotationen und Tooling { #type-annotations-and-tooling }\n\nSehen wir uns zunächst an, wie Editor, mypy und andere Tools dies sehen würden.\n\n`BaseUser` verfügt über die Basis-Felder. Dann erbt `UserIn` von `BaseUser` und fügt das Feld `password` hinzu, sodass es nun alle Felder beider Modelle hat.\n\nWir annotieren den Funktionsrückgabetyp als `BaseUser`, geben aber tatsächlich eine `UserIn`-Instanz zurück.\n\nFür den Editor, mypy und andere Tools ist das kein Problem, da `UserIn` eine Unterklasse von `BaseUser` ist (Salopp: `UserIn` ist ein `BaseUser`). Es handelt sich um einen *gültigen* Typ, solange irgendetwas überreicht wird, das ein `BaseUser` ist.\n\n### FastAPI Datenfilterung { #fastapi-data-filtering }\n\nFastAPI seinerseits wird den Rückgabetyp sehen und sicherstellen, dass das, was zurückgegeben wird, **nur** diejenigen Felder enthält, welche im Typ deklariert sind.\n\nFastAPI macht intern mehrere Dinge mit Pydantic, um sicherzustellen, dass obige Ähnlichkeitsregeln der Klassenvererbung nicht auf die Filterung der zurückgegebenen Daten angewendet werden, sonst könnten Sie am Ende mehr Daten zurückgeben als gewollt.\n\nAuf diese Weise erhalten Sie das beste beider Welten: Sowohl Typannotationen mit **Tool-Unterstützung** als auch **Datenfilterung**.\n\n## Anzeige in der Dokumentation { #see-it-in-the-docs }\n\nWenn Sie sich die automatische Dokumentation betrachten, können Sie sehen, dass Eingabe- und Ausgabemodell beide ihr eigenes JSON-Schema haben:\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\nUnd beide Modelle werden auch in der interaktiven API-Dokumentation verwendet:\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## Andere Rückgabetyp-Annotationen { #other-return-type-annotations }\n\nEs kann Fälle geben, bei denen Sie etwas zurückgeben, das kein gültiges Pydantic-Feld ist, und Sie annotieren es in der Funktion nur, um Unterstützung von Tools zu erhalten (Editor, mypy, usw.).\n\n### Eine Response direkt zurückgeben { #return-a-response-directly }\n\nDer häufigste Anwendungsfall ist, wenn Sie [eine Response direkt zurückgeben, wie es später im Handbuch für fortgeschrittene Benutzer erläutert wird](../advanced/response-directly.md).\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\nDieser einfache Anwendungsfall wird automatisch von FastAPI gehandhabt, weil die Annotation des Rückgabetyps die Klasse (oder eine Unterklasse von) `Response` ist.\n\nUnd Tools werden auch glücklich sein, weil sowohl `RedirectResponse` als auch `JSONResponse` Unterklassen von `Response` sind, die Typannotation ist daher korrekt.\n\n### Eine Unterklasse von Response annotieren { #annotate-a-response-subclass }\n\nSie können auch eine Unterklasse von `Response` in der Typannotation verwenden.\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\nDas wird ebenfalls funktionieren, weil `RedirectResponse` eine Unterklasse von `Response` ist, und FastAPI sich um diesen einfachen Anwendungsfall automatisch kümmert.\n\n### Ungültige Rückgabetyp-Annotationen { #invalid-return-type-annotations }\n\nAber wenn Sie ein beliebiges anderes Objekt zurückgeben, das kein gültiger Pydantic-Typ ist (z. B. ein Datenbank-Objekt), und Sie annotieren es so in der Funktion, wird FastAPI versuchen, ein Pydantic-Responsemodell von dieser Typannotation zu erstellen, und scheitern.\n\nDas gleiche wird passieren, wenn Sie eine <dfn title=\"Eine Union mehrerer Typen bedeutet: „Irgendeiner dieser Typen“\">Union</dfn> mehrerer Typen haben, und einer oder mehrere sind nicht gültige Pydantic-Typen. Zum Beispiel funktioniert folgendes nicht 💥:\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n... das scheitert, da die Typannotation kein Pydantic-Typ ist, und auch keine einzelne `Response`-Klasse, oder -Unterklasse, es ist eine Union (eines von beiden) von `Response` und `dict`.\n\n### Responsemodell deaktivieren { #disable-response-model }\n\nBeim Beispiel oben fortsetzend, mögen Sie vielleicht die standardmäßige Datenvalidierung, -Dokumentation, -Filterung, usw., die von FastAPI durchgeführt wird, nicht haben.\n\nAber Sie möchten dennoch den Rückgabetyp in der Funktion annotieren, um Unterstützung von Editoren und Typcheckern (z. B. mypy) zu erhalten.\n\nIn diesem Fall können Sie die Generierung des Responsemodells abschalten, indem Sie `response_model=None` setzen:\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\nDas bewirkt, dass FastAPI die Generierung des Responsemodells unterlässt, und damit können Sie jede gewünschte Rückgabetyp-Annotation haben, ohne dass es Ihre FastAPI-Anwendung beeinflusst. 🤓\n\n## Parameter für die Enkodierung des Responsemodells { #response-model-encoding-parameters }\n\nIhr Responsemodell könnte Defaultwerte haben, wie:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None` (oder `str | None = None` in Python 3.10) hat einen Defaultwert `None`.\n* `tax: float = 10.5` hat einen Defaultwert `10.5`.\n* `tags: List[str] = []` hat eine leere Liste als Defaultwert: `[]`.\n\nAber Sie möchten diese vielleicht vom Resultat ausschließen, wenn Sie gar nicht gesetzt wurden.\n\nWenn Sie zum Beispiel Modelle mit vielen optionalen Attributen in einer NoSQL-Datenbank haben, und Sie möchten nicht ellenlange JSON-Responses voller Defaultwerte senden.\n\n### Den `response_model_exclude_unset`-Parameter verwenden { #use-the-response-model-exclude-unset-parameter }\n\nSie können den *Pfadoperation-Dekorator*-Parameter `response_model_exclude_unset=True` setzen:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\nDie Defaultwerte werden dann nicht in der Response enthalten sein, sondern nur die tatsächlich gesetzten Werte.\n\nWenn Sie also den Artikel mit der ID `foo` bei der *Pfadoperation* anfragen, wird (ohne die Defaultwerte) die Response sein:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | Info\n\nSie können auch:\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\nverwenden, wie in der [Pydantic-Dokumentation](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict) für `exclude_defaults` und `exclude_none` beschrieben.\n\n///\n\n#### Daten mit Werten für Felder mit Defaultwerten { #data-with-values-for-fields-with-defaults }\n\nAber wenn Ihre Daten Werte für Modellfelder mit Defaultwerten haben, wie etwa der Artikel mit der ID `bar`:\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\ndann werden diese Werte in der Response enthalten sein.\n\n#### Daten mit den gleichen Werten wie die Defaultwerte { #data-with-the-same-values-as-the-defaults }\n\nWenn Daten die gleichen Werte haben wie ihre Defaultwerte, wie etwa der Artikel mit der ID `baz`:\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\ndann ist FastAPI klug genug (tatsächlich ist Pydantic klug genug) zu erkennen, dass, obwohl `description`, `tax`, und `tags` die gleichen Werte haben wie ihre Defaultwerte, sie explizit gesetzt wurden (statt dass sie von den Defaultwerten genommen wurden).\n\nDiese Felder werden also in der JSON-Response enthalten sein.\n\n/// tip | Tipp\n\nBeachten Sie, dass Defaultwerte alles Mögliche sein können, nicht nur `None`.\n\nSie können eine Liste (`[]`), ein `float` `10.5`, usw. sein.\n\n///\n\n### `response_model_include` und `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\nSie können auch die Parameter `response_model_include` und `response_model_exclude` im **Pfadoperation-Dekorator** verwenden.\n\nDiese nehmen ein `set` von `str`s entgegen, welches Namen von Attributen sind, die eingeschlossen (ohne die Anderen) oder ausgeschlossen (nur die Anderen) werden sollen.\n\nDas kann als schnelle Abkürzung verwendet werden, wenn Sie nur ein Pydantic-Modell haben und ein paar Daten von der Ausgabe ausschließen wollen.\n\n/// tip | Tipp\n\nEs wird dennoch empfohlen, dass Sie die Ideen von oben verwenden, also mehrere Klassen statt dieser Parameter.\n\nDer Grund ist, dass das das generierte JSON-Schema in der OpenAPI Ihrer Anwendung (und deren Dokumentation) dennoch das komplette Modell abbildet, selbst wenn Sie `response_model_include` oder `response_model_exclude` verwenden, um einige Attribute auszuschließen.\n\nDas trifft auch auf `response_model_by_alias` zu, welches ähnlich funktioniert.\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | Tipp\n\nDie Syntax `{\"name\", \"description\"}` erzeugt ein `set` mit diesen zwei Werten.\n\nÄquivalent zu `set([\"name\", \"description\"])`.\n\n///\n\n#### `list`en statt `set`s verwenden { #using-lists-instead-of-sets }\n\nWenn Sie vergessen, ein `set` zu verwenden, und stattdessen eine `list`e oder ein `tuple` übergeben, wird FastAPI die dennoch in ein `set` konvertieren, und es wird korrekt funktionieren:\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## Zusammenfassung { #recap }\n\nVerwenden Sie den Parameter `response_model` im *Pfadoperation-Dekorator*, um Responsemodelle zu definieren, und besonders, um private Daten herauszufiltern.\n\nVerwenden Sie `response_model_exclude_unset`, um nur explizit gesetzte Werte zurückzugeben.\n"
  },
  {
    "path": "docs/de/docs/tutorial/response-status-code.md",
    "content": "# Response-Statuscode { #response-status-code }\n\nGenauso wie Sie ein Responsemodell angeben können, können Sie auch den HTTP-Statuscode für die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> mit dem Parameter `status_code` in jeder der *Pfadoperationen* deklarieren:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* usw.\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | Hinweis\n\nBeachten Sie, dass `status_code` ein Parameter der „Dekorator“-Methode ist (`get`, `post`, usw.). Nicht der *Pfadoperation-Funktion*, wie alle anderen Parameter und der Body.\n\n///\n\nDem `status_code`-Parameter wird eine Zahl mit dem HTTP-Statuscode übergeben.\n\n/// info | Info\n\nAlternativ kann `status_code` auch ein `IntEnum` erhalten, wie etwa Pythons [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus).\n\n///\n\nDies wird:\n\n* Diesen Statuscode mit der Response zurücksenden.\n* Diesen im OpenAPI-Schema dokumentieren (und somit in den Benutzeroberflächen):\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | Hinweis\n\nEinige Responsecodes (siehe nächsten Abschnitt) kennzeichnen, dass die Response keinen Body hat.\n\nFastAPI erkennt dies und erstellt eine OpenAPI-Dokumentation, die zeigt, dass es keinen Responsebody gibt.\n\n///\n\n## Über HTTP-Statuscodes { #about-http-status-codes }\n\n/// note | Hinweis\n\nWenn Sie bereits wissen, was HTTP-Statuscodes sind, können Sie diesen Abschnitt überspringen und mit dem nächsten fortfahren.\n\n///\n\nIn HTTP senden Sie einen numerischen Statuscode mit 3 Ziffern als Teil der Response.\n\nDiese Statuscodes haben einen zugeordneten Namen, um sie leichter zu erkennen, aber der wichtige Teil ist die Zahl.\n\nKurz gefasst:\n\n* `100 - 199` stehen für „Information“. Sie verwenden diese selten direkt. Responses mit diesen Statuscodes dürfen keinen Body haben.\n* **`200 - 299`** stehen für „Successful“-Responses („Erfolgreich“). Diese werden Sie am häufigsten verwenden.\n    * `200` ist der Default-Statuscode, was bedeutet, alles ist „OK“.\n    * Ein weiteres Beispiel wäre `201`, „Created“ („Erzeugt“). Dieser wird üblicherweise verwendet, nachdem ein neuer Datensatz in der Datenbank erstellt wurde.\n    * Ein spezieller Fall ist `204`, „No Content“ („Kein Inhalt“). Diese Response wird verwendet, wenn es keinen Inhalt gibt, der an den Client zurückgeschickt werden soll, und diese Response darf daher keinen Body haben.\n* **`300 - 399`** stehen für „Redirection“ („Umleitung“). Responses mit diesen Statuscodes können einen Body haben oder nicht, außer bei `304`, „Not Modified“ („Nicht verändert“), die keinen haben darf.\n* **`400 - 499`** stehen für „Client error“-Responses („Client-Fehler“). Diese sind die zweithäufigsten, die Sie vermutlich verwenden werden.\n    * Ein Beispiel ist `404`, für eine „Not Found“-Response („Nicht gefunden“).\n    * Für allgemeine Fehler beim Client können Sie einfach `400` verwenden.\n* `500 - 599` stehen für Server-Fehler. Diese verwenden Sie fast nie direkt. Wenn in Ihrem Anwendungscode oder Server etwas schiefgeht, wird automatisch einer dieser Fehler-Statuscodes zurückgegeben.\n\n/// tip | Tipp\n\nUm mehr über die einzelnen Statuscodes zu erfahren und welcher wofür verwendet wird, sehen Sie sich die [<abbr title=\"Mozilla Developer Network - Mozilla-Entwicklernetzwerk\">MDN</abbr> Dokumentation über HTTP-Statuscodes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) an.\n\n///\n\n## Abkürzung zur Erinnerung an die Namen { #shortcut-to-remember-the-names }\n\nLassen Sie uns das vorherige Beispiel noch einmal anschauen:\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201` ist der Statuscode für „Created“ („Erzeugt“).\n\nAber Sie müssen sich nicht merken, was jeder dieser Codes bedeutet.\n\nSie können die Annehmlichkeit von Variablen aus `fastapi.status` nutzen.\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\nDiese sind nur eine Annehmlichkeit, sie enthalten dieselbe Zahl, aber so können Sie die Autovervollständigung Ihres Editors verwenden, um sie zu finden:\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | Technische Details\n\nSie könnten auch `from starlette import status` verwenden.\n\n**FastAPI** bietet dieselben `starlette.status`-Codes auch via `fastapi.status` an, rein zu Ihrer Annehmlichkeit als Entwickler. Aber sie stammen direkt von Starlette.\n\n///\n\n## Den Defaultwert ändern { #changing-the-default }\n\nSpäter im [Handbuch für fortgeschrittene Benutzer](../advanced/response-change-status-code.md) werden Sie sehen, wie Sie einen anderen Statuscode zurückgeben können, als den Default, den Sie hier deklarieren.\n"
  },
  {
    "path": "docs/de/docs/tutorial/schema-extra-example.md",
    "content": "# Beispiel-Request-Daten deklarieren { #declare-request-example-data }\n\nSie können Beispiele für die Daten deklarieren, die Ihre App empfangen kann.\n\nHier sind mehrere Möglichkeiten, das zu tun.\n\n## Zusätzliche JSON-Schemadaten in Pydantic-Modellen { #extra-json-schema-data-in-pydantic-models }\n\nSie können `examples` („Beispiele“) für ein Pydantic-Modell deklarieren, welche dem generierten JSON-Schema hinzugefügt werden.\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\nDiese zusätzlichen Informationen werden unverändert zum für dieses Modell ausgegebenen **JSON-Schema** hinzugefügt und in der API-Dokumentation verwendet.\n\nSie können das Attribut `model_config` verwenden, das ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr> akzeptiert, wie beschrieben in [Pydantic-Dokumentation: Configuration](https://docs.pydantic.dev/latest/api/config/).\n\nSie können `json_schema_extra` setzen, mit einem `dict`, das alle zusätzlichen Daten enthält, die im generierten JSON-Schema angezeigt werden sollen, einschließlich `examples`.\n\n/// tip | Tipp\n\nMit derselben Technik können Sie das JSON-Schema erweitern und Ihre eigenen benutzerdefinierten Zusatzinformationen hinzufügen.\n\nSie könnten das beispielsweise verwenden, um Metadaten für eine Frontend-Benutzeroberfläche usw. hinzuzufügen.\n\n///\n\n/// info | Info\n\nOpenAPI 3.1.0 (verwendet seit FastAPI 0.99.0) hat Unterstützung für `examples` hinzugefügt, was Teil des **JSON Schema** Standards ist.\n\nZuvor unterstützte es nur das Schlüsselwort `example` mit einem einzigen Beispiel. Dieses wird weiterhin von OpenAPI 3.1.0 unterstützt, ist jedoch <abbr title=\"deprecatet – veraltet, obsolet: Es soll nicht mehr verwendet werden\">deprecatet</abbr> und nicht Teil des JSON Schema Standards. Wir empfehlen Ihnen daher, von `example` nach `examples` zu migrieren. 🤓\n\nMehr erfahren Sie am Ende dieser Seite.\n\n///\n\n## Zusätzliche Argumente für `Field` { #field-additional-arguments }\n\nWenn Sie `Field()` mit Pydantic-Modellen verwenden, können Sie ebenfalls zusätzliche `examples` deklarieren:\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## `examples` im JSON-Schema – OpenAPI { #examples-in-json-schema-openapi }\n\nBei Verwendung von:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nkönnen Sie auch eine Gruppe von `examples` mit zusätzlichen Informationen deklarieren, die zu ihren **JSON-Schemas** innerhalb von **OpenAPI** hinzugefügt werden.\n\n### `Body` mit `examples` { #body-with-examples }\n\nHier übergeben wir `examples`, welches ein einzelnes Beispiel für die in `Body()` erwarteten Daten enthält:\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### Beispiel in der Dokumentations-Benutzeroberfläche { #example-in-the-docs-ui }\n\nMit jeder der oben genannten Methoden würde es in `/docs` so aussehen:\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### `Body` mit mehreren `examples` { #body-with-multiple-examples }\n\nSie können natürlich auch mehrere `examples` übergeben:\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\nWenn Sie das tun, werden die Beispiele Teil des internen **JSON-Schemas** für diese Body-Daten.\n\nNichtsdestotrotz unterstützt Swagger UI, das für die Anzeige der Dokumentations-Benutzeroberfläche zuständige Tool, zum <dfn title=\"2023-08-26\">Zeitpunkt der Erstellung</dfn> nicht die Anzeige mehrerer Beispiele für die Daten in **JSON Schema**. Aber lesen Sie unten für einen Workaround weiter.\n\n### OpenAPI-spezifische `examples` { #openapi-specific-examples }\n\nSchon bevor **JSON Schema** `examples` unterstützte, unterstützte OpenAPI ein anderes Feld, das auch `examples` genannt wurde.\n\nDiese **OpenAPI-spezifischen** `examples` finden sich in einem anderen Abschnitt der OpenAPI-Spezifikation. Sie sind **Details für jede *Pfadoperation***, nicht für jedes JSON-Schema.\n\nUnd Swagger UI unterstützt dieses spezielle Feld `examples` schon seit einiger Zeit. Sie können es also verwenden, um verschiedene **Beispiele in der Benutzeroberfläche der Dokumentation anzuzeigen**.\n\nDas Format dieses OpenAPI-spezifischen Felds `examples` ist ein `dict` mit **mehreren Beispielen** (anstelle einer `list`), jedes mit zusätzlichen Informationen, die auch zu **OpenAPI** hinzugefügt werden.\n\nDies erfolgt nicht innerhalb jedes in OpenAPI enthaltenen JSON-Schemas, sondern außerhalb, in der *Pfadoperation*.\n\n### Verwendung des Parameters `openapi_examples` { #using-the-openapi-examples-parameter }\n\nSie können die OpenAPI-spezifischen `examples` in FastAPI mit dem Parameter `openapi_examples` deklarieren, für:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nDie Schlüssel des `dict` identifizieren jedes Beispiel, und jeder Wert ist ein weiteres `dict`.\n\nJedes spezifische Beispiel-`dict` in den `examples` kann Folgendes enthalten:\n\n* `summary`: Kurze Beschreibung für das Beispiel.\n* `description`: Eine lange Beschreibung, die Markdown-Text enthalten kann.\n* `value`: Dies ist das tatsächlich angezeigte Beispiel, z. B. ein `dict`.\n* `externalValue`: Alternative zu `value`, eine URL, die auf das Beispiel verweist. Allerdings wird dies möglicherweise nicht von so vielen Tools unterstützt wie `value`.\n\nSie können es so verwenden:\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### OpenAPI-Beispiele in der Dokumentations-Benutzeroberfläche { #openapi-examples-in-the-docs-ui }\n\nWenn `openapi_examples` zu `Body()` hinzugefügt wird, würde `/docs` so aussehen:\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## Technische Details { #technical-details }\n\n/// tip | Tipp\n\nWenn Sie bereits **FastAPI** Version **0.99.0 oder höher** verwenden, können Sie diese Details wahrscheinlich **überspringen**.\n\nSie sind für ältere Versionen relevanter, bevor OpenAPI 3.1.0 verfügbar war.\n\nSie können dies als eine kurze **Geschichtsstunde** zu OpenAPI und JSON Schema betrachten. 🤓\n\n///\n\n/// warning | Achtung\n\nDies sind sehr technische Details zu den Standards **JSON Schema** und **OpenAPI**.\n\nWenn die oben genannten Ideen bereits für Sie funktionieren, reicht das möglicherweise aus und Sie benötigen diese Details wahrscheinlich nicht, überspringen Sie sie gerne.\n\n///\n\nVor OpenAPI 3.1.0 verwendete OpenAPI eine ältere und modifizierte Version von **JSON Schema**.\n\nJSON Schema hatte keine `examples`, daher fügte OpenAPI seiner eigenen modifizierten Version ein eigenes `example`-Feld hinzu.\n\nOpenAPI fügte auch die Felder `example` und `examples` zu anderen Teilen der Spezifikation hinzu:\n\n* [`Parameter Object` (in der Spezifikation)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object), das verwendet wurde von FastAPIs:\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object` im Feld `content` des `Media Type Object`s (in der Spezifikation)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object), das verwendet wurde von FastAPIs:\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info | Info\n\nDieser alte, OpenAPI-spezifische `examples`-Parameter heißt seit FastAPI `0.103.0` jetzt `openapi_examples`.\n\n///\n\n### JSON Schemas Feld `examples` { #json-schemas-examples-field }\n\nAber dann fügte JSON Schema ein [`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5)-Feld zu einer neuen Version der Spezifikation hinzu.\n\nUnd dann basierte das neue OpenAPI 3.1.0 auf der neuesten Version (JSON Schema 2020-12), die dieses neue Feld `examples` enthielt.\n\nUnd jetzt hat dieses neue `examples`-Feld Vorrang vor dem alten (und benutzerdefinierten) `example`-Feld, im Singular, das jetzt <abbr title=\"veraltet, obsolet: Es soll nicht mehr verwendet werden\">deprecatet</abbr> ist.\n\nDieses neue `examples`-Feld in JSON Schema ist **nur eine `list`** von Beispielen, kein Dict mit zusätzlichen Metadaten wie an den anderen Stellen in OpenAPI (oben beschrieben).\n\n/// info | Info\n\nSelbst, nachdem OpenAPI 3.1.0 veröffentlicht wurde, mit dieser neuen, einfacheren Integration mit JSON Schema, unterstützte Swagger UI, das Tool, das die automatische Dokumentation bereitstellt, eine Zeit lang OpenAPI 3.1.0 nicht (das tut es seit Version 5.0.0 🎉).\n\nAus diesem Grund verwendeten Versionen von FastAPI vor 0.99.0 immer noch Versionen von OpenAPI vor 3.1.0.\n\n///\n\n### Pydantic- und FastAPI-`examples` { #pydantic-and-fastapi-examples }\n\nWenn Sie `examples` innerhalb eines Pydantic-Modells hinzufügen, indem Sie `schema_extra` oder `Field(examples=[\"something\"])` verwenden, wird dieses Beispiel dem **JSON-Schema** für dieses Pydantic-Modell hinzugefügt.\n\nUnd dieses **JSON-Schema** des Pydantic-Modells ist in der **OpenAPI** Ihrer API enthalten und wird dann in der Benutzeroberfläche der Dokumentation verwendet.\n\nIn Versionen von FastAPI vor 0.99.0 (0.99.0 und höher verwenden das neuere OpenAPI 3.1.0), wenn Sie `example` oder `examples` mit einem der anderen Werkzeuge (`Query()`, `Body()`, usw.) verwendet haben, wurden diese Beispiele nicht zum JSON-Schema hinzugefügt, das diese Daten beschreibt (nicht einmal zur OpenAPI-eigenen Version von JSON Schema), sondern direkt zur *Pfadoperation*-Deklaration in OpenAPI (außerhalb der Teile von OpenAPI, die JSON Schema verwenden).\n\nAber jetzt, da FastAPI 0.99.0 und höher, OpenAPI 3.1.0 verwendet, das JSON Schema 2020-12 verwendet, und Swagger UI 5.0.0 und höher, ist alles konsistenter und die Beispiele sind in JSON Schema enthalten.\n\n### Swagger-Benutzeroberfläche und OpenAPI-spezifische `examples` { #swagger-ui-and-openapi-specific-examples }\n\nDa die Swagger-Benutzeroberfläche derzeit nicht mehrere JSON Schema Beispiele unterstützt (Stand: 26.08.2023), hatten Benutzer keine Möglichkeit, mehrere Beispiele in der Dokumentation anzuzeigen.\n\nUm dieses Problem zu lösen, hat FastAPI `0.103.0` **Unterstützung** für die Deklaration desselben alten **OpenAPI-spezifischen** `examples`-Felds mit dem neuen Parameter `openapi_examples` hinzugefügt. 🤓\n\n### Zusammenfassung { #summary }\n\nIch habe immer gesagt, dass ich Geschichte nicht so sehr mag ... und jetzt schauen Sie mich an, wie ich „Technikgeschichte“-Unterricht gebe. 😅\n\nKurz gesagt: **Aktualisieren Sie auf FastAPI 0.99.0 oder höher**, und die Dinge sind viel **einfacher, konsistenter und intuitiver**, und Sie müssen nicht alle diese historischen Details kennen. 😎\n"
  },
  {
    "path": "docs/de/docs/tutorial/security/first-steps.md",
    "content": "# Sicherheit – Erste Schritte { #security-first-steps }\n\nStellen wir uns vor, dass Sie Ihre **Backend**-API auf einer Domain haben.\n\nUnd Sie haben ein **Frontend** auf einer anderen Domain oder in einem anderen Pfad derselben Domain (oder in einer Mobile-Anwendung).\n\nUnd Sie möchten eine Möglichkeit haben, dass sich das Frontend mithilfe eines **Benutzernamens** und eines **Passworts** beim Backend authentisieren kann.\n\nWir können **OAuth2** verwenden, um das mit **FastAPI** zu erstellen.\n\nAber ersparen wir Ihnen die Zeit, die gesamte lange Spezifikation zu lesen, nur um die kleinen Informationen zu finden, die Sie benötigen.\n\nLassen Sie uns die von **FastAPI** bereitgestellten Tools verwenden, um Sicherheit zu gewährleisten.\n\n## Wie es aussieht { #how-it-looks }\n\nLassen Sie uns zunächst einfach den Code verwenden und sehen, wie er funktioniert, und dann kommen wir zurück, um zu verstehen, was passiert.\n\n## `main.py` erstellen { #create-main-py }\n\nKopieren Sie das Beispiel in eine Datei `main.py`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## Ausführen { #run-it }\n\n/// info | Info\n\nDas Paket [`python-multipart`](https://github.com/Kludex/python-multipart) wird automatisch mit **FastAPI** installiert, wenn Sie den Befehl `pip install \"fastapi[standard]\"` ausführen.\n\nWenn Sie jedoch den Befehl `pip install fastapi` verwenden, ist das Paket `python-multipart` nicht standardmäßig enthalten.\n\nUm es manuell zu installieren, stellen Sie sicher, dass Sie eine [virtuelle Umgebung](../../virtual-environments.md) erstellen, sie aktivieren und es dann mit:\n\n```console\n$ pip install python-multipart\n```\n\ninstallieren.\n\nDas liegt daran, dass **OAuth2** „Formulardaten“ zum Senden von `username` und `password` verwendet.\n\n///\n\nFühren Sie das Beispiel aus mit:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## Es testen { #check-it }\n\nGehen Sie zu der interaktiven Dokumentation unter: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nSie werden etwa Folgendes sehen:\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Authorize-Button!\n\nSie haben bereits einen glänzenden, neuen „Authorize“-Button.\n\nUnd Ihre *Pfadoperation* hat in der oberen rechten Ecke ein kleines Schloss, auf das Sie klicken können.\n\n///\n\nUnd wenn Sie darauf klicken, erhalten Sie ein kleines Anmeldeformular zur Eingabe eines `username` und `password` (und anderer optionaler Felder):\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | Hinweis\n\nEs spielt keine Rolle, was Sie in das Formular eingeben, es wird noch nicht funktionieren. Wir kommen dahin.\n\n///\n\nDies ist natürlich nicht das Frontend für die Endbenutzer, aber es ist ein großartiges automatisches Tool, um Ihre gesamte API interaktiv zu dokumentieren.\n\nEs kann vom Frontend-Team verwendet werden (das auch Sie selbst sein können).\n\nEs kann von Anwendungen und Systemen Dritter verwendet werden.\n\nUnd es kann auch von Ihnen selbst verwendet werden, um dieselbe Anwendung zu debuggen, zu prüfen und zu testen.\n\n## Der `password`-Flow { #the-password-flow }\n\nLassen Sie uns nun etwas zurückgehen und verstehen, was das alles ist.\n\nDer `password`-„Flow“ ist eine der in OAuth2 definierten Wege („Flows“) zur Handhabung von Sicherheit und Authentifizierung.\n\nOAuth2 wurde so konzipiert, dass das Backend oder die API unabhängig vom Server sein kann, der den Benutzer authentifiziert.\n\nIn diesem Fall handhabt jedoch dieselbe **FastAPI**-Anwendung sowohl die API als auch die Authentifizierung.\n\nBetrachten wir es also aus dieser vereinfachten Sicht:\n\n* Der Benutzer gibt den `username` und das `password` im Frontend ein und drückt `Enter`.\n* Das Frontend (das im Browser des Benutzers läuft) sendet diesen `username` und das `password` an eine bestimmte URL in unserer API (deklariert mit `tokenUrl=\"token\"`).\n* Die API überprüft den `username` und das `password` und antwortet mit einem „Token“ (wir haben davon noch nichts implementiert).\n    * Ein „Token“ ist lediglich ein String mit einem Inhalt, den wir später verwenden können, um diesen Benutzer zu verifizieren.\n    * Normalerweise läuft ein Token nach einiger Zeit ab.\n        * Daher muss sich der Benutzer irgendwann später erneut anmelden.\n        * Und wenn der Token gestohlen wird, ist das Risiko geringer. Es handelt sich nicht um einen dauerhaften Schlüssel, der (in den meisten Fällen) für immer funktioniert.\n* Das Frontend speichert diesen Token vorübergehend irgendwo.\n* Der Benutzer klickt im Frontend, um zu einem anderen Abschnitt der Frontend-Web-Anwendung zu gelangen.\n* Das Frontend muss weitere Daten von der API abrufen.\n    * Es benötigt jedoch eine Authentifizierung für diesen bestimmten Endpunkt.\n    * Um sich also bei unserer API zu authentifizieren, sendet es einen `Authorization`-Header mit dem Wert `Bearer ` plus dem Token.\n    * Wenn der Token `foobar` enthielte, wäre der Inhalt des `Authorization`-Headers: `Bearer foobar`.\n\n## **FastAPI**s `OAuth2PasswordBearer` { #fastapis-oauth2passwordbearer }\n\n**FastAPI** bietet mehrere Tools auf unterschiedlichen Abstraktionsebenen zur Implementierung dieser Sicherheitsfunktionen.\n\nIn diesem Beispiel verwenden wir **OAuth2** mit dem **Password**-Flow und einem **Bearer**-Token. Wir machen das mit der Klasse `OAuth2PasswordBearer`.\n\n/// info | Info\n\nEin „Bearer“-Token ist nicht die einzige Option.\n\nAber es ist die beste für unseren Anwendungsfall.\n\nUnd es ist wahrscheinlich auch für die meisten anderen Anwendungsfälle die beste, es sei denn, Sie sind ein OAuth2-Experte und wissen genau, warum es eine andere Option gibt, die Ihren Anforderungen besser entspricht.\n\nIn dem Fall gibt Ihnen **FastAPI** ebenfalls die Tools, die Sie zum Erstellen brauchen.\n\n///\n\nWenn wir eine Instanz der Klasse `OAuth2PasswordBearer` erstellen, übergeben wir den Parameter `tokenUrl`. Dieser Parameter enthält die URL, die der Client (das Frontend, das im Browser des Benutzers ausgeführt wird) verwendet, wenn er den `username` und das `password` sendet, um einen Token zu erhalten.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip | Tipp\n\nHier bezieht sich `tokenUrl=\"token\"` auf eine relative URL `token`, die wir noch nicht erstellt haben. Da es sich um eine relative URL handelt, entspricht sie `./token`.\n\nDa wir eine relative URL verwenden, würde sich das, wenn sich Ihre API unter `https://example.com/` befindet, auf `https://example.com/token` beziehen. Wenn sich Ihre API jedoch unter `https://example.com/api/v1/` befände, würde es sich auf `https://example.com/api/v1/token` beziehen.\n\nDie Verwendung einer relativen URL ist wichtig, um sicherzustellen, dass Ihre Anwendung auch in einem fortgeschrittenen Anwendungsfall, wie [Hinter einem Proxy](../../advanced/behind-a-proxy.md), weiterhin funktioniert.\n\n///\n\nDieser Parameter erstellt nicht diesen Endpunkt / diese *Pfadoperation*, sondern deklariert, dass die URL `/token` diejenige sein wird, die der Client verwenden soll, um den Token abzurufen. Diese Information wird in OpenAPI und dann in den interaktiven API-Dokumentationssystemen verwendet.\n\nWir werden demnächst auch die eigentliche Pfadoperation erstellen.\n\n/// info | Info\n\nWenn Sie ein sehr strenger „Pythonista“ sind, missfällt Ihnen möglicherweise die Schreibweise des Parameternamens `tokenUrl` anstelle von `token_url`.\n\nDas liegt daran, dass FastAPI denselben Namen wie in der OpenAPI-Spezifikation verwendet. Sodass Sie, wenn Sie mehr über eines dieser Sicherheitsschemas herausfinden möchten, den Namen einfach kopieren und einfügen können, um weitere Informationen darüber zu erhalten.\n\n///\n\nDie Variable `oauth2_scheme` ist eine Instanz von `OAuth2PasswordBearer`, aber auch ein „Callable“.\n\nEs könnte wie folgt aufgerufen werden:\n\n```Python\noauth2_scheme(some, parameters)\n```\n\nEs kann also mit `Depends` verwendet werden.\n\n### Verwenden { #use-it }\n\nJetzt können Sie dieses `oauth2_scheme` als Abhängigkeit `Depends` übergeben.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nDiese Abhängigkeit stellt einen `str` bereit, der dem Parameter `token` der *Pfadoperation-Funktion* zugewiesen wird.\n\n**FastAPI** weiß, dass es diese Abhängigkeit verwenden kann, um ein „Sicherheitsschema“ im OpenAPI-Schema (und der automatischen API-Dokumentation) zu definieren.\n\n/// info | Technische Details\n\n**FastAPI** weiß, dass es die Klasse `OAuth2PasswordBearer` (deklariert in einer Abhängigkeit) verwenden kann, um das Sicherheitsschema in OpenAPI zu definieren, da es von `fastapi.security.oauth2.OAuth2` erbt, das wiederum von `fastapi.security.base.SecurityBase` erbt.\n\nAlle Sicherheits-Werkzeuge, die in OpenAPI integriert sind (und die automatische API-Dokumentation), erben von `SecurityBase`, so weiß **FastAPI**, wie es sie in OpenAPI integrieren muss.\n\n///\n\n## Was es macht { #what-it-does }\n\nFastAPI wird im <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> nach diesem `Authorization`-Header suchen, prüfen, ob der Wert `Bearer ` plus ein Token ist, und den Token als `str` zurückgeben.\n\nWenn es keinen `Authorization`-Header sieht, oder der Wert keinen `Bearer `-Token hat, antwortet es direkt mit einem 401-Statuscode-Error (`UNAUTHORIZED`).\n\nSie müssen nicht einmal prüfen, ob der Token existiert, um einen Fehler zurückzugeben. Seien Sie sicher, dass Ihre Funktion, wenn sie ausgeführt wird, ein `str` in diesem Token enthält.\n\nSie können das bereits in der interaktiven Dokumentation ausprobieren:\n\n<img src=\"/img/tutorial/security/image03.png\">\n\nWir überprüfen im Moment noch nicht die Gültigkeit des Tokens, aber das ist bereits ein Anfang.\n\n## Zusammenfassung { #recap }\n\nMit nur drei oder vier zusätzlichen Zeilen haben Sie so bereits eine primitive Form der Sicherheit.\n"
  },
  {
    "path": "docs/de/docs/tutorial/security/get-current-user.md",
    "content": "# Aktuellen Benutzer abrufen { #get-current-user }\n\nIm vorherigen Kapitel hat das Sicherheitssystem (das auf dem Dependency Injection System basiert) der *Pfadoperation-Funktion* einen `token` vom Typ `str` überreicht:\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nAber das ist immer noch nicht so nützlich.\n\nLassen wir es uns den aktuellen Benutzer überreichen.\n\n## Ein Benutzermodell erstellen { #create-a-user-model }\n\nErstellen wir zunächst ein Pydantic-Benutzermodell.\n\nSo wie wir Pydantic zum Deklarieren von Bodys verwenden, können wir es auch überall sonst verwenden:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## Eine `get_current_user`-Abhängigkeit erstellen { #create-a-get-current-user-dependency }\n\nErstellen wir eine Abhängigkeit `get_current_user`.\n\nErinnern Sie sich, dass Abhängigkeiten Unterabhängigkeiten haben können?\n\n`get_current_user` wird seinerseits von `oauth2_scheme` abhängen, das wir zuvor erstellt haben.\n\nSo wie wir es zuvor in der *Pfadoperation* direkt gemacht haben, erhält unsere neue Abhängigkeit `get_current_user` von der Unterabhängigkeit `oauth2_scheme` einen `token` vom Typ `str`:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## Den Benutzer abrufen { #get-the-user }\n\n`get_current_user` wird eine von uns erstellte (gefakte) Hilfsfunktion verwenden, welche einen Token vom Typ `str` entgegennimmt und unser Pydantic-`User`-Modell zurückgibt:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## Den aktuellen Benutzer einfügen { #inject-the-current-user }\n\nUnd jetzt können wir wiederum `Depends` mit unserem `get_current_user` in der *Pfadoperation* verwenden:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\nBeachten Sie, dass wir als Typ von `current_user` das Pydantic-Modell `User` deklarieren.\n\nDas wird uns innerhalb der Funktion bei Codevervollständigung und Typprüfungen helfen.\n\n/// tip | Tipp\n\nSie erinnern sich vielleicht, dass <abbr title=\"Anfragekörper\">Requestbodys</abbr> ebenfalls mit Pydantic-Modellen deklariert werden.\n\nWeil Sie `Depends` verwenden, wird **FastAPI** hier aber nicht verwirrt.\n\n///\n\n/// check | Testen\n\nDie Art und Weise, wie dieses System von Abhängigkeiten konzipiert ist, ermöglicht es uns, verschiedene Abhängigkeiten (verschiedene „Dependables“) zu haben, die alle ein `User`-Modell zurückgeben.\n\nWir sind nicht darauf beschränkt, nur eine Abhängigkeit zu haben, die diesen Typ von Daten zurückgeben kann.\n\n///\n\n## Andere Modelle { #other-models }\n\nSie können jetzt den aktuellen Benutzer direkt in den *Pfadoperation-Funktionen* abrufen und die Sicherheitsmechanismen auf **Dependency Injection** Ebene handhaben, mittels `Depends`.\n\nUnd Sie können alle Modelle und Daten für die Sicherheitsanforderungen verwenden (in diesem Fall ein Pydantic-Modell `User`).\n\nSie sind jedoch nicht auf die Verwendung von bestimmten Datenmodellen, Klassen, oder Typen beschränkt.\n\nMöchten Sie eine `id` und eine `email` und keinen `username` in Ihrem Modell haben? Kein Problem. Sie können dieselben Tools verwenden.\n\nMöchten Sie nur ein `str` haben? Oder nur ein `dict`? Oder direkt eine Instanz eines Modells einer Datenbank-Klasse? Es funktioniert alles auf die gleiche Weise.\n\nSie haben eigentlich keine Benutzer, die sich bei Ihrer Anwendung anmelden, sondern Roboter, Bots oder andere Systeme, die nur über einen Zugriffstoken verfügen? Auch hier funktioniert alles gleich.\n\nVerwenden Sie einfach jede Art von Modell, jede Art von Klasse, jede Art von Datenbank, die Sie für Ihre Anwendung benötigen. **FastAPI** deckt das alles mit seinem Dependency Injection System ab.\n\n## Codegröße { #code-size }\n\nDieses Beispiel mag ausführlich erscheinen. Bedenken Sie, dass wir Sicherheit, Datenmodelle, Hilfsfunktionen und *Pfadoperationen* in derselben Datei vermischen.\n\nAber hier ist der entscheidende Punkt.\n\nDer Code für Sicherheit und Dependency Injection wird einmal geschrieben.\n\nSie können es so komplex gestalten, wie Sie möchten. Und dennoch haben Sie es nur einmal geschrieben, an einer einzigen Stelle. Mit all der Flexibilität.\n\nAber Sie können Tausende von Endpunkten (*Pfadoperationen*) haben, die dasselbe Sicherheitssystem verwenden.\n\nUnd alle (oder beliebige Teile davon) können Vorteil ziehen aus der Wiederverwendung dieser und anderer von Ihnen erstellter Abhängigkeiten.\n\nUnd alle diese Tausenden von *Pfadoperationen* können nur drei Zeilen lang sein:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## Zusammenfassung { #recap }\n\nSie können jetzt den aktuellen Benutzer direkt in Ihrer *Pfadoperation-Funktion* abrufen.\n\nWir haben bereits die Hälfte geschafft.\n\nWir müssen jetzt nur noch eine *Pfadoperation* hinzufügen, mittels der der Benutzer/Client tatsächlich seinen `username` und `password` senden kann.\n\nDas kommt als nächstes.\n"
  },
  {
    "path": "docs/de/docs/tutorial/security/index.md",
    "content": "# Sicherheit { #security }\n\nEs gibt viele Wege, Sicherheit, Authentifizierung und Autorisierung zu handhaben.\n\nUnd normalerweise ist es ein komplexes und „schwieriges“ Thema.\n\nIn vielen Frameworks und Systemen erfordert allein die Handhabung von Sicherheit und Authentifizierung viel Aufwand und Code (in vielen Fällen kann er 50 % oder mehr des gesamten geschriebenen Codes ausmachen).\n\n**FastAPI** bietet mehrere Tools, die Ihnen helfen, schnell und auf standardisierte Weise mit **Sicherheit** umzugehen, ohne alle Sicherheits-Spezifikationen studieren und erlernen zu müssen.\n\nAber schauen wir uns zunächst ein paar kleine Konzepte an.\n\n## In Eile? { #in-a-hurry }\n\nWenn Ihnen diese Begriffe egal sind und Sie einfach *jetzt* Sicherheit mit Authentifizierung basierend auf Benutzername und Passwort hinzufügen müssen, fahren Sie mit den nächsten Kapiteln fort.\n\n## OAuth2 { #oauth2 }\n\nOAuth2 ist eine Spezifikation, die verschiedene Möglichkeiten zur Handhabung von Authentifizierung und Autorisierung definiert.\n\nEs handelt sich um eine recht umfangreiche Spezifikation, und sie deckt mehrere komplexe Anwendungsfälle ab.\n\nSie umfasst Möglichkeiten zur Authentifizierung mithilfe eines „Dritten“.\n\nDas ist es, was alle diese „Login mit Facebook, Google, X (Twitter), GitHub“-Systeme unter der Haube verwenden.\n\n### OAuth 1 { #oauth-1 }\n\nEs gab ein OAuth 1, das sich stark von OAuth2 unterscheidet und komplexer ist, da es direkte Spezifikationen enthält, wie die Kommunikation verschlüsselt wird.\n\nHeutzutage ist es nicht sehr populär und wird kaum verwendet.\n\nOAuth2 spezifiziert nicht, wie die Kommunikation verschlüsselt werden soll, sondern erwartet, dass Ihre Anwendung mit HTTPS bereitgestellt wird.\n\n/// tip | Tipp\n\nIm Abschnitt über **Deployment** erfahren Sie, wie Sie HTTPS mithilfe von Traefik und Let's Encrypt kostenlos einrichten.\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect ist eine weitere Spezifikation, die auf **OAuth2** basiert.\n\nSie erweitert lediglich OAuth2, indem sie einige Dinge spezifiziert, die in OAuth2 relativ mehrdeutig sind, um zu versuchen, es interoperabler zu machen.\n\nBeispielsweise verwendet der Google Login OpenID Connect (welches seinerseits OAuth2 verwendet).\n\nAber der Facebook Login unterstützt OpenID Connect nicht. Es hat seine eigene Variante von OAuth2.\n\n### OpenID (nicht „OpenID Connect“) { #openid-not-openid-connect }\n\nEs gab auch eine „OpenID“-Spezifikation. Sie versuchte das Gleiche zu lösen wie **OpenID Connect**, basierte aber nicht auf OAuth2.\n\nEs handelte sich also um ein komplett zusätzliches System.\n\nHeutzutage ist es nicht sehr populär und wird kaum verwendet.\n\n## OpenAPI { #openapi }\n\nOpenAPI (früher bekannt als Swagger) ist die offene Spezifikation zum Erstellen von APIs (jetzt Teil der Linux Foundation).\n\n**FastAPI** basiert auf **OpenAPI**.\n\nDas ist es, was erlaubt, mehrere automatische interaktive Dokumentations-Oberflächen, Codegenerierung, usw. zu haben.\n\nOpenAPI bietet die Möglichkeit, mehrere Sicherheits„systeme“ zu definieren.\n\nDurch deren Verwendung können Sie alle diese Standards-basierten Tools nutzen, einschließlich dieser interaktiven Dokumentationssysteme.\n\nOpenAPI definiert die folgenden Sicherheitsschemas:\n\n* `apiKey`: ein anwendungsspezifischer Schlüssel, der stammen kann von:\n    * Einem Query-Parameter.\n    * Einem Header.\n    * Einem Cookie.\n* `http`: Standard-HTTP-Authentifizierungssysteme, einschließlich:\n    * `bearer`: ein Header `Authorization` mit dem Wert `Bearer ` plus einem Token. Dies wird von OAuth2 geerbt.\n    * HTTP Basic Authentication.\n    * HTTP Digest, usw.\n* `oauth2`: Alle OAuth2-Methoden zum Umgang mit Sicherheit (genannt „Flows“).\n    * Mehrere dieser Flows eignen sich zum Aufbau eines OAuth 2.0-Authentifizierungsanbieters (wie Google, Facebook, X (Twitter), GitHub usw.):\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * Es gibt jedoch einen bestimmten „Flow“, der perfekt für die direkte Abwicklung der Authentifizierung in derselben Anwendung verwendet werden kann:\n        * `password`: Einige der nächsten Kapitel werden Beispiele dafür behandeln.\n* `openIdConnect`: bietet eine Möglichkeit, zu definieren, wie OAuth2-Authentifizierungsdaten automatisch ermittelt werden können.\n    * Diese automatische Erkennung ist es, die in der OpenID Connect Spezifikation definiert ist.\n\n\n/// tip | Tipp\n\nAuch die Integration anderer Authentifizierungs-/Autorisierungsanbieter wie Google, Facebook, X (Twitter), GitHub, usw. ist möglich und relativ einfach.\n\nDas komplexeste Problem besteht darin, einen Authentifizierungs-/Autorisierungsanbieter wie solche aufzubauen, aber **FastAPI** reicht Ihnen die Tools, das einfach zu erledigen, während Ihnen die schwere Arbeit abgenommen wird.\n\n///\n\n## **FastAPI** Tools { #fastapi-utilities }\n\nFastAPI stellt für jedes dieser Sicherheitsschemas im Modul `fastapi.security` verschiedene Tools bereit, die die Verwendung dieser Sicherheitsmechanismen vereinfachen.\n\nIn den nächsten Kapiteln erfahren Sie, wie Sie mit diesen von **FastAPI** bereitgestellten Tools Sicherheit zu Ihrer API hinzufügen.\n\nUnd Sie werden auch sehen, wie dies automatisch in das interaktive Dokumentationssystem integriert wird.\n"
  },
  {
    "path": "docs/de/docs/tutorial/security/oauth2-jwt.md",
    "content": "# OAuth2 mit Passwort (und Hashing), Bearer mit JWT-Tokens { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\nDa wir nun über den gesamten Sicherheitsablauf verfügen, machen wir die Anwendung tatsächlich sicher, indem wir <abbr title=\"JSON Web Tokens\">JWT</abbr>-Tokens und sicheres Passwort-Hashing verwenden.\n\nDiesen Code können Sie tatsächlich in Ihrer Anwendung verwenden, die Passwort-Hashes in Ihrer Datenbank speichern, usw.\n\nWir bauen auf dem vorherigen Kapitel auf.\n\n## Über JWT { #about-jwt }\n\nJWT bedeutet „JSON Web Tokens“.\n\nEs ist ein Standard, um ein JSON-Objekt in einem langen, kompakten String ohne Leerzeichen zu kodieren. Das sieht so aus:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\nDa er nicht verschlüsselt ist, kann jeder die Informationen aus dem Inhalt wiederherstellen.\n\nAber er ist signiert. Wenn Sie also einen von Ihnen gesendeten Token zurückerhalten, können Sie überprüfen, ob Sie ihn tatsächlich gesendet haben.\n\nAuf diese Weise können Sie einen Token mit einer Gültigkeitsdauer von beispielsweise einer Woche erstellen. Und wenn der Benutzer am nächsten Tag mit dem Token zurückkommt, wissen Sie, dass der Benutzer immer noch bei Ihrem System angemeldet ist.\n\nNach einer Woche läuft der Token ab und der Benutzer wird nicht autorisiert und muss sich erneut anmelden, um einen neuen Token zu erhalten. Und wenn der Benutzer (oder ein Dritter) versuchen würde, den Token zu ändern, um das Ablaufdatum zu ändern, würden Sie das entdecken, weil die Signaturen nicht übereinstimmen würden.\n\nWenn Sie mit JWT-Tokens spielen und sehen möchten, wie sie funktionieren, schauen Sie sich [https://jwt.io](https://jwt.io/) an.\n\n## `PyJWT` installieren { #install-pyjwt }\n\nWir müssen `PyJWT` installieren, um die JWT-Tokens in Python zu generieren und zu verifizieren.\n\nStellen Sie sicher, dass Sie eine [virtuelle Umgebung](../../virtual-environments.md) erstellen, sie aktivieren und dann `pyjwt` installieren:\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info | Info\n\nWenn Sie planen, digitale Signaturalgorithmen wie RSA oder ECDSA zu verwenden, sollten Sie die Kryptografie-Abhängigkeit `pyjwt[crypto]` installieren.\n\nWeitere Informationen finden Sie in der [PyJWT-Installationsdokumentation](https://pyjwt.readthedocs.io/en/latest/installation.html).\n\n///\n\n## Passwort-Hashing { #password-hashing }\n\n„Hashing“ bedeutet: Konvertieren eines Inhalts (in diesem Fall eines Passworts) in eine Folge von Bytes (ein schlichter String), die wie Kauderwelsch aussieht.\n\nImmer wenn Sie genau den gleichen Inhalt (genau das gleiche Passwort) übergeben, erhalten Sie genau den gleichen Kauderwelsch.\n\nSie können jedoch nicht vom Kauderwelsch zurück zum Passwort konvertieren.\n\n### Warum Passwort-Hashing verwenden { #why-use-password-hashing }\n\nWenn Ihre Datenbank gestohlen wird, hat der Dieb nicht die Klartext-Passwörter Ihrer Benutzer, sondern nur die Hashes.\n\nDer Dieb kann also nicht versuchen, die gleichen Passwörter in einem anderen System zu verwenden (da viele Benutzer überall das gleiche Passwort verwenden, wäre dies gefährlich).\n\n## `pwdlib` installieren { #install-pwdlib }\n\npwdlib ist ein großartiges Python-Package, um Passwort-Hashes zu handhaben.\n\nEs unterstützt viele sichere Hashing-Algorithmen und Werkzeuge, um mit diesen zu arbeiten.\n\nDer empfohlene Algorithmus ist „Argon2“.\n\nStellen Sie sicher, dass Sie eine [virtuelle Umgebung](../../virtual-environments.md) erstellen, sie aktivieren, und installieren Sie dann pwdlib mit Argon2:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | Tipp\n\nMit `pwdlib` können Sie sogar konfigurieren, Passwörter zu lesen, die von **Django**, einem **Flask**-Sicherheits-Plugin, oder vielen anderen erstellt wurden.\n\nSo könnten Sie beispielsweise die gleichen Daten aus einer Django-Anwendung in einer Datenbank mit einer FastAPI-Anwendung teilen. Oder schrittweise eine Django-Anwendung migrieren, während Sie dieselbe Datenbank verwenden.\n\nUnd Ihre Benutzer könnten sich gleichzeitig über Ihre Django-Anwendung oder Ihre **FastAPI**-Anwendung anmelden.\n\n///\n\n## Die Passwörter hashen und überprüfen { #hash-and-verify-the-passwords }\n\nImportieren Sie die benötigten Tools aus `pwdlib`.\n\nErstellen Sie eine PasswordHash-Instanz mit empfohlenen Einstellungen – sie wird für das Hashen und Verifizieren von Passwörtern verwendet.\n\n/// tip | Tipp\n\npwdlib unterstützt auch den bcrypt-Hashing-Algorithmus, enthält jedoch keine Legacy-Algorithmen – für die Arbeit mit veralteten Hashes wird die Verwendung der Bibliothek passlib empfohlen.\n\nSie könnten sie beispielsweise verwenden, um von einem anderen System (wie Django) generierte Passwörter zu lesen und zu verifizieren, aber alle neuen Passwörter mit einem anderen Algorithmus wie Argon2 oder Bcrypt zu hashen.\n\nUnd mit allen gleichzeitig kompatibel sein.\n\n///\n\nErstellen Sie eine Hilfsfunktion, um ein vom Benutzer stammendes Passwort zu hashen.\n\nUnd eine weitere, um zu überprüfen, ob ein empfangenes Passwort mit dem gespeicherten Hash übereinstimmt.\n\nUnd noch eine, um einen Benutzer zu authentifizieren und zurückzugeben.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\nWenn `authenticate_user` mit einem Benutzernamen aufgerufen wird, der in der Datenbank nicht existiert, führen wir dennoch `verify_password` gegen einen Dummy-Hash aus.\n\nSo stellt man sicher, dass der Endpunkt ungefähr gleich viel Zeit für die Antwort benötigt, unabhängig davon, ob der Benutzername gültig ist oder nicht. Dadurch werden Timing-Angriffe verhindert, mit denen vorhandene Benutzernamen ermittelt werden könnten.\n\n/// note | Hinweis\n\nWenn Sie sich die neue (gefakte) Datenbank `fake_users_db` anschauen, sehen Sie, wie das gehashte Passwort jetzt aussieht: `\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`.\n\n///\n\n## JWT-Token verarbeiten { #handle-jwt-tokens }\n\nImportieren Sie die installierten Module.\n\nErstellen Sie einen zufälligen geheimen Schlüssel, der zum Signieren der JWT-Tokens verwendet wird.\n\nUm einen sicheren zufälligen geheimen Schlüssel zu generieren, verwenden Sie den folgenden Befehl:\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\nUnd kopieren Sie die Ausgabe in die Variable `SECRET_KEY` (verwenden Sie nicht die im Beispiel).\n\nErstellen Sie eine Variable `ALGORITHM` für den Algorithmus, der zum Signieren des JWT-Tokens verwendet wird, und setzen Sie sie auf `\"HS256\"`.\n\nErstellen Sie eine Variable für das Ablaufdatum des Tokens.\n\nDefinieren Sie ein Pydantic-Modell, das im Token-Endpunkt für die <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> verwendet wird.\n\nErstellen Sie eine Hilfsfunktion, um einen neuen Zugriffstoken zu generieren.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## Die Abhängigkeiten aktualisieren { #update-the-dependencies }\n\nAktualisieren Sie `get_current_user`, um den gleichen Token wie zuvor zu erhalten, dieses Mal jedoch unter Verwendung von JWT-Tokens.\n\nDekodieren Sie den empfangenen Token, validieren Sie ihn und geben Sie den aktuellen Benutzer zurück.\n\nWenn der Token ungültig ist, geben Sie sofort einen HTTP-Fehler zurück.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## Die *Pfadoperation* `/token` aktualisieren { #update-the-token-path-operation }\n\nErstellen Sie ein <abbr title=\"Zeitdifferenz\">`timedelta`</abbr> mit der Ablaufzeit des Tokens.\n\nErstellen Sie einen echten JWT-Zugriffstoken und geben Sie ihn zurück.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### Technische Details zum JWT-„Subjekt“ `sub` { #technical-details-about-the-jwt-subject-sub }\n\nDie JWT-Spezifikation besagt, dass es einen Schlüssel `sub` mit dem Subjekt des Tokens gibt.\n\nDie Verwendung ist optional, aber dort würden Sie die Identifikation des Benutzers speichern, daher verwenden wir das hier.\n\nJWT kann auch für andere Dinge verwendet werden, abgesehen davon, einen Benutzer zu identifizieren und ihm zu erlauben, Operationen direkt auf Ihrer API auszuführen.\n\nSie könnten beispielsweise ein „Auto“ oder einen „Blog-Beitrag“ identifizieren.\n\nAnschließend könnten Sie Berechtigungen für diese Entität hinzufügen, etwa „Fahren“ (für das Auto) oder „Bearbeiten“ (für den Blog).\n\nUnd dann könnten Sie diesen JWT-Token einem Benutzer (oder Bot) geben und dieser könnte ihn verwenden, um diese Aktionen auszuführen (das Auto fahren oder den Blog-Beitrag bearbeiten), ohne dass er überhaupt ein Konto haben müsste, einfach mit dem JWT-Token, den Ihre API dafür generiert hat.\n\nMit diesen Ideen kann JWT für weitaus anspruchsvollere Szenarien verwendet werden.\n\nIn diesen Fällen könnten mehrere dieser Entitäten die gleiche ID haben, sagen wir `foo` (ein Benutzer `foo`, ein Auto `foo` und ein Blog-Beitrag `foo`).\n\nDeshalb, um ID-Kollisionen zu vermeiden, könnten Sie beim Erstellen des JWT-Tokens für den Benutzer, dem Wert des `sub`-Schlüssels ein Präfix, z. B. `username:` voranstellen. In diesem Beispiel hätte der Wert von `sub` also auch `username:johndoe` sein können.\n\nDer wesentliche Punkt ist, dass der `sub`-Schlüssel in der gesamten Anwendung eine eindeutige Kennung haben sollte, und er sollte ein String sein.\n\n## Es testen { #check-it }\n\nFühren Sie den Server aus und gehen Sie zur Dokumentation: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nDie Benutzeroberfläche sieht wie folgt aus:\n\n<img src=\"/img/tutorial/security/image07.png\">\n\nMelden Sie sich bei der Anwendung auf die gleiche Weise wie zuvor an.\n\nVerwenden Sie die Anmeldeinformationen:\n\nBenutzername: `johndoe`\nPasswort: `secret`\n\n/// check | Testen\n\nBeachten Sie, dass im Code nirgendwo das Klartext-Passwort „`secret`“ steht, wir haben nur die gehashte Version.\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\nRufen Sie den Endpunkt `/users/me/` auf, Sie erhalten die Response:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\nWenn Sie die Developer Tools öffnen, können Sie sehen, dass die gesendeten Daten nur den Token enthalten. Das Passwort wird nur beim ersten <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr> gesendet, um den Benutzer zu authentisieren und diesen Zugriffstoken zu erhalten, aber nicht mehr danach:\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | Hinweis\n\nBeachten Sie den Header `Authorization` mit einem Wert, der mit `Bearer ` beginnt.\n\n///\n\n## Fortgeschrittene Verwendung mit `scopes` { #advanced-usage-with-scopes }\n\nOAuth2 hat ein Konzept von <abbr title=\"Geltungsbereiche\">„Scopes“</abbr>.\n\nSie können diese verwenden, um einem JWT-Token einen bestimmten Satz von Berechtigungen zu übergeben.\n\nAnschließend können Sie diesen Token einem Benutzer direkt oder einem Dritten geben, damit diese mit einer Reihe von Einschränkungen mit Ihrer API interagieren können.\n\nWie Sie sie verwenden und wie sie in **FastAPI** integriert sind, erfahren Sie später im **Handbuch für fortgeschrittene Benutzer**.\n\n## Zusammenfassung { #recap }\n\nMit dem, was Sie bis hier gesehen haben, können Sie eine sichere **FastAPI**-Anwendung mithilfe von Standards wie OAuth2 und JWT einrichten.\n\nIn fast jedem Framework wird die Handhabung der Sicherheit recht schnell zu einem ziemlich komplexen Thema.\n\nViele Packages, die es stark vereinfachen, müssen viele Kompromisse beim Datenmodell, der Datenbank und den verfügbaren Funktionen eingehen. Und einige dieser Pakete, die die Dinge zu sehr vereinfachen, weisen tatsächlich Sicherheitslücken auf.\n\n---\n\n**FastAPI** geht bei keiner Datenbank, keinem Datenmodell oder Tool Kompromisse ein.\n\nEs gibt Ihnen die volle Flexibilität, diejenigen auszuwählen, die am besten zu Ihrem Projekt passen.\n\nUnd Sie können viele gut gepflegte und weit verbreitete Packages wie `pwdlib` und `PyJWT` direkt verwenden, da **FastAPI** keine komplexen Mechanismen zur Integration externer Pakete erfordert.\n\nAber es bietet Ihnen die Werkzeuge, um den Prozess so weit wie möglich zu vereinfachen, ohne Kompromisse bei Flexibilität, Robustheit oder Sicherheit einzugehen.\n\nUnd Sie können sichere Standardprotokolle wie OAuth2 auf relativ einfache Weise verwenden und implementieren.\n\nIm **Handbuch für fortgeschrittene Benutzer** erfahren Sie mehr darüber, wie Sie OAuth2-„Scopes“ für ein feingranuliertes Berechtigungssystem verwenden, das denselben Standards folgt. OAuth2 mit Scopes ist der Mechanismus, der von vielen großen Authentifizierungsanbietern wie Facebook, Google, GitHub, Microsoft, X (Twitter), usw. verwendet wird, um Drittanbieteranwendungen zu autorisieren, im Namen ihrer Benutzer mit ihren APIs zu interagieren.\n"
  },
  {
    "path": "docs/de/docs/tutorial/security/simple-oauth2.md",
    "content": "# Einfaches OAuth2 mit Password und Bearer { #simple-oauth2-with-password-and-bearer }\n\nLassen Sie uns nun auf dem vorherigen Kapitel aufbauen und die fehlenden Teile hinzufügen, um einen vollständigen Sicherheits-Flow zu erhalten.\n\n## `username` und `password` entgegennehmen { #get-the-username-and-password }\n\nWir werden **FastAPIs** Sicherheits-Werkzeuge verwenden, um den `username` und das `password` entgegenzunehmen.\n\nOAuth2 spezifiziert, dass der Client/Benutzer bei Verwendung des „Password Flow“ (den wir verwenden) die Felder `username` und `password` als Formulardaten senden muss.\n\nUnd die Spezifikation sagt, dass die Felder so benannt werden müssen. `user-name` oder `email` würde also nicht funktionieren.\n\nAber keine Sorge, Sie können sie Ihren Endbenutzern im Frontend so anzeigen, wie Sie möchten.\n\nUnd Ihre Datenbankmodelle können beliebige andere Namen verwenden.\n\nAber für die Login-*Pfadoperation* müssen wir diese Namen verwenden, um mit der Spezifikation kompatibel zu sein (und beispielsweise das integrierte API-Dokumentationssystem verwenden zu können).\n\nDie Spezifikation besagt auch, dass `username` und `password` als Formulardaten gesendet werden müssen (hier also kein JSON).\n\n### `scope` { #scope }\n\nFerner sagt die Spezifikation, dass der Client ein weiteres Formularfeld \"`scope`\" („Geltungsbereich“) senden kann.\n\nDer Name des Formularfelds lautet `scope` (im Singular), tatsächlich handelt es sich jedoch um einen langen String mit durch Leerzeichen getrennten „Scopes“.\n\nJeder „Scope“ ist nur ein String (ohne Leerzeichen).\n\nDiese werden normalerweise verwendet, um bestimmte Sicherheitsberechtigungen zu deklarieren, zum Beispiel:\n\n* `users:read` oder `users:write` sind gängige Beispiele.\n* `instagram_basic` wird von Facebook / Instagram verwendet.\n* `https://www.googleapis.com/auth/drive` wird von Google verwendet.\n\n/// info | Info\n\nIn OAuth2 ist ein „Scope“ nur ein String, der eine bestimmte erforderliche Berechtigung deklariert.\n\nEs spielt keine Rolle, ob er andere Zeichen wie `:` enthält oder ob es eine URL ist.\n\nDiese Details sind implementierungsspezifisch.\n\nFür OAuth2 sind es einfach nur Strings.\n\n///\n\n## Code, um `username` und `password` entgegenzunehmen { #code-to-get-the-username-and-password }\n\nLassen Sie uns nun die von **FastAPI** bereitgestellten Werkzeuge verwenden, um das zu erledigen.\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\nImportieren Sie zunächst `OAuth2PasswordRequestForm` und verwenden Sie es als Abhängigkeit mit `Depends` in der *Pfadoperation* für `/token`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm` ist eine Klassenabhängigkeit, die einen Formularbody deklariert mit:\n\n* Dem `username`.\n* Dem `password`.\n* Einem optionalen `scope`-Feld als langem String, bestehend aus durch Leerzeichen getrennten Strings.\n* Einem optionalen <abbr title=\"Art der Anmeldung\">`grant_type`</abbr>.\n\n/// tip | Tipp\n\nDie OAuth2-Spezifikation *erfordert* tatsächlich ein Feld `grant_type` mit dem festen Wert `password`, aber `OAuth2PasswordRequestForm` erzwingt dies nicht.\n\nWenn Sie es erzwingen müssen, verwenden Sie `OAuth2PasswordRequestFormStrict` anstelle von `OAuth2PasswordRequestForm`.\n\n///\n\n* Eine optionale `client_id` (benötigen wir für unser Beispiel nicht).\n* Ein optionales `client_secret` (benötigen wir für unser Beispiel nicht).\n\n/// info | Info\n\n`OAuth2PasswordRequestForm` ist keine spezielle Klasse für **FastAPI**, so wie `OAuth2PasswordBearer`.\n\n`OAuth2PasswordBearer` lässt **FastAPI** wissen, dass es sich um ein Sicherheitsschema handelt. Daher wird es auf diese Weise zu OpenAPI hinzugefügt.\n\nAber `OAuth2PasswordRequestForm` ist nur eine Klassenabhängigkeit, die Sie selbst hätten schreiben können, oder Sie hätten `Form`ular-Parameter direkt deklarieren können.\n\nDa es sich jedoch um einen häufigen Anwendungsfall handelt, wird er zur Vereinfachung direkt von **FastAPI** bereitgestellt.\n\n///\n\n### Die Formulardaten verwenden { #use-the-form-data }\n\n/// tip | Tipp\n\nDie Instanz der Klassenabhängigkeit `OAuth2PasswordRequestForm` verfügt, statt eines Attributs `scope` mit dem durch Leerzeichen getrennten langen String, über das Attribut `scopes` mit einer tatsächlichen Liste von Strings, einem für jeden gesendeten Scope.\n\nIn diesem Beispiel verwenden wir keine `scopes`, aber die Funktionalität ist vorhanden, wenn Sie sie benötigen.\n\n///\n\nRufen Sie nun die Benutzerdaten aus der (gefakten) Datenbank ab, für diesen `username` aus dem Formularfeld.\n\nWenn es keinen solchen Benutzer gibt, geben wir die Fehlermeldung „Incorrect username or password“ zurück.\n\nFür den Fehler verwenden wir die Exception `HTTPException`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### Das Passwort überprüfen { #check-the-password }\n\nZu diesem Zeitpunkt liegen uns die Benutzerdaten aus unserer Datenbank vor, das Passwort haben wir jedoch noch nicht überprüft.\n\nLassen Sie uns diese Daten zunächst in das Pydantic-Modell `UserInDB` einfügen.\n\nSie sollten niemals Klartext-Passwörter speichern, daher verwenden wir ein (gefaktes) Passwort-Hashing-System.\n\nWenn die Passwörter nicht übereinstimmen, geben wir denselben Fehler zurück.\n\n#### Passwort-Hashing { #password-hashing }\n\n„Hashing“ bedeutet: Konvertieren eines Inhalts (in diesem Fall eines Passworts) in eine Folge von Bytes (ein schlichter String), die wie Kauderwelsch aussieht.\n\nImmer wenn Sie genau den gleichen Inhalt (genau das gleiche Passwort) übergeben, erhalten Sie genau den gleichen Kauderwelsch.\n\nSie können jedoch nicht vom Kauderwelsch zurück zum Passwort konvertieren.\n\n##### Warum Passwort-Hashing verwenden? { #why-use-password-hashing }\n\nWenn Ihre Datenbank gestohlen wird, hat der Dieb nicht die Klartext-Passwörter Ihrer Benutzer, sondern nur die Hashes.\n\nDer Dieb kann also nicht versuchen, die gleichen Passwörter in einem anderen System zu verwenden (da viele Benutzer überall das gleiche Passwort verwenden, wäre dies gefährlich).\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### Über `**user_dict` { #about-user-dict }\n\n`UserInDB(**user_dict)` bedeutet:\n\n*Übergib die Schlüssel und Werte des `user_dict` direkt als Schlüssel-Wert-Argumente, äquivalent zu:*\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info | Info\n\nEine ausführlichere Erklärung von `**user_dict` finden Sie in [der Dokumentation für **Extra Modelle**](../extra-models.md#about-user-in-dict).\n\n///\n\n## Den Token zurückgeben { #return-the-token }\n\nDie <abbr title=\"Response – Antwort: Daten, die der Server zum anfragenden Client zurücksendet\">Response</abbr> des `token`-Endpunkts muss ein JSON-Objekt sein.\n\nEs sollte einen `token_type` haben. Da wir in unserem Fall „Bearer“-Token verwenden, sollte der Token-Typ „`bearer`“ sein.\n\nUnd es sollte einen `access_token` haben, mit einem String, der unseren Zugriffstoken enthält.\n\nIn diesem einfachen Beispiel gehen wir einfach völlig unsicher vor und geben denselben `username` wie der Token zurück.\n\n/// tip | Tipp\n\nIm nächsten Kapitel sehen Sie eine wirklich sichere Implementierung mit Passwort-Hashing und <abbr title=\"JSON Web Tokens\">JWT</abbr>-Tokens.\n\nAber konzentrieren wir uns zunächst auf die spezifischen Details, die wir benötigen.\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip | Tipp\n\nGemäß der Spezifikation sollten Sie ein JSON mit einem `access_token` und einem `token_type` zurückgeben, genau wie in diesem Beispiel.\n\nDas müssen Sie selbst in Ihrem Code tun und sicherstellen, dass Sie diese JSON-Schlüssel verwenden.\n\nEs ist fast das Einzige, woran Sie denken müssen, es selbst richtigzumachen und die Spezifikationen einzuhalten.\n\nDen Rest erledigt **FastAPI** für Sie.\n\n///\n\n## Die Abhängigkeiten aktualisieren { #update-the-dependencies }\n\nJetzt werden wir unsere Abhängigkeiten aktualisieren.\n\nWir möchten den `current_user` *nur* erhalten, wenn dieser Benutzer aktiv ist.\n\nDaher erstellen wir eine zusätzliche Abhängigkeit `get_current_active_user`, die wiederum `get_current_user` als Abhängigkeit verwendet.\n\nBeide Abhängigkeiten geben nur dann einen HTTP-Error zurück, wenn der Benutzer nicht existiert oder inaktiv ist.\n\nIn unserem Endpunkt erhalten wir also nur dann einen Benutzer, wenn der Benutzer existiert, korrekt authentifiziert wurde und aktiv ist:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info | Info\n\nDer zusätzliche Header `WWW-Authenticate` mit dem Wert `Bearer`, den wir hier zurückgeben, ist ebenfalls Teil der Spezifikation.\n\nJeder HTTP-(Fehler-)Statuscode 401 „UNAUTHORIZED“ soll auch einen `WWW-Authenticate`-Header zurückgeben.\n\nIm Fall von Bearer-Tokens (in unserem Fall) sollte der Wert dieses Headers `Bearer` lauten.\n\nSie können diesen zusätzlichen Header tatsächlich weglassen und es würde trotzdem funktionieren.\n\nAber er wird hier bereitgestellt, um den Spezifikationen zu entsprechen.\n\nAußerdem gibt es möglicherweise Tools, die ihn erwarten und verwenden (jetzt oder in der Zukunft) und das könnte für Sie oder Ihre Benutzer jetzt oder in der Zukunft nützlich sein.\n\nDas ist der Vorteil von Standards ...\n\n///\n\n## Es in Aktion sehen { #see-it-in-action }\n\nÖffnen Sie die interaktive Dokumentation: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n### Authentifizieren { #authenticate }\n\nKlicken Sie auf den Button „Authorize“.\n\nVerwenden Sie die Anmeldedaten:\n\nBenutzer: `johndoe`\n\nPasswort: `secret`.\n\n<img src=\"/img/tutorial/security/image04.png\">\n\nNach der Authentifizierung im System sehen Sie Folgendes:\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### Die eigenen Benutzerdaten ansehen { #get-your-own-user-data }\n\nVerwenden Sie nun die Operation `GET` mit dem Pfad `/users/me`.\n\nSie erhalten Ihre Benutzerdaten:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\nWenn Sie auf das Schlosssymbol klicken und sich abmelden und dann den gleichen Vorgang nochmal versuchen, erhalten Sie einen HTTP 401 Error:\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### Inaktiver Benutzer { #inactive-user }\n\nVersuchen Sie es nun mit einem inaktiven Benutzer und authentisieren Sie sich mit:\n\nBenutzer: `alice`.\n\nPasswort: `secret2`.\n\nUnd versuchen Sie, die Operation `GET` mit dem Pfad `/users/me` zu verwenden.\n\nSie erhalten die Fehlermeldung „Inactive user“:\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## Zusammenfassung { #recap }\n\nSie verfügen jetzt über die Tools, um ein vollständiges Sicherheitssystem basierend auf `username` und `password` für Ihre API zu implementieren.\n\nMit diesen Tools können Sie das Sicherheitssystem mit jeder Datenbank und jedem Benutzer oder Datenmodell kompatibel machen.\n\nDas einzige fehlende Detail ist, dass es noch nicht wirklich „sicher“ ist.\n\nIm nächsten Kapitel erfahren Sie, wie Sie eine sichere Passwort-Hashing-Bibliothek und <abbr title=\"JSON Web Tokens\">JWT</abbr>-Token verwenden.\n"
  },
  {
    "path": "docs/de/docs/tutorial/server-sent-events.md",
    "content": "# Server-Sent Events (SSE) { #server-sent-events-sse }\n\nSie können Daten mithilfe von **Server-Sent Events** (SSE) an den Client streamen.\n\nDas ist ähnlich wie [JSON Lines streamen](stream-json-lines.md), verwendet aber das Format `text/event-stream`, das von Browsern nativ mit der [die `EventSource`-API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) unterstützt wird.\n\n/// info | Info\n\nHinzugefügt in FastAPI 0.135.0.\n\n///\n\n## Was sind Server-Sent Events? { #what-are-server-sent-events }\n\nSSE ist ein Standard zum Streamen von Daten vom Server zum Client über HTTP.\n\nJedes Event ist ein kleiner Textblock mit „Feldern“ wie `data`, `event`, `id` und `retry`, getrennt durch Leerzeilen.\n\nDas sieht so aus:\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE wird häufig für KI-Chat-Streaming, Live-Benachrichtigungen, Logs und Observability sowie andere Fälle verwendet, in denen der Server Updates an den Client pusht.\n\n/// tip | Tipp\n\nWenn Sie Binärdaten streamen wollen, z. B. Video oder Audio, sehen Sie im fortgeschrittenen Handbuch nach: [Daten streamen](../advanced/stream-data.md).\n\n///\n\n## SSE mit FastAPI streamen { #stream-sse-with-fastapi }\n\nUm SSE mit FastAPI zu streamen, verwenden Sie `yield` in Ihrer *Pfadoperation-Funktion* und setzen Sie `response_class=EventSourceResponse`.\n\nImportieren Sie `EventSourceResponse` aus `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\nJedes mit `yield` zurückgegebene Element wird als JSON kodiert und im Feld `data:` eines SSE-Events gesendet.\n\nWenn Sie den Rückgabetyp als `AsyncIterable[Item]` deklarieren, verwendet FastAPI ihn, um die Daten mit Pydantic zu **validieren**, zu **dokumentieren** und zu **serialisieren**.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip | Tipp\n\nDa Pydantic es auf der **Rust**-Seite serialisiert, erhalten Sie eine deutlich höhere **Leistung**, als wenn Sie keinen Rückgabetyp deklarieren.\n\n///\n\n### Nicht-async-*Pfadoperation-Funktionen* { #non-async-path-operation-functions }\n\nSie können auch normale `def`-Funktionen (ohne `async`) verwenden und `yield` genauso einsetzen.\n\nFastAPI stellt sicher, dass sie korrekt ausgeführt wird, sodass sie die Event Loop nicht blockiert.\n\nDa die Funktion in diesem Fall nicht async ist, wäre der passende Rückgabetyp `Iterable[Item]`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### Kein Rückgabetyp { #no-return-type }\n\nSie können den Rückgabetyp auch weglassen. FastAPI verwendet dann den [`jsonable_encoder`](./encoder.md), um die Daten zu konvertieren und zu senden.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\nWenn Sie SSE-Felder wie `event`, `id`, `retry` oder `comment` setzen müssen, können Sie statt reiner Daten `ServerSentEvent`-Objekte yielden.\n\nImportieren Sie `ServerSentEvent` aus `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\nDas Feld `data` wird immer als JSON kodiert. Sie können jeden Wert übergeben, der als JSON serialisierbar ist, einschließlich Pydantic-Modellen.\n\n## Rohdaten { #raw-data }\n\nWenn Sie Daten **ohne** JSON-Kodierung senden müssen, verwenden Sie `raw_data` statt `data`.\n\nDas ist nützlich zum Senden vorformatierter Texte, Logzeilen oder spezieller <dfn title=\"Ein Wert, der verwendet wird, um eine besondere Bedingung oder einen besonderen Zustand anzuzeigen\">„Sentinel“</dfn>-Werte wie `[DONE]`.\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note | Hinweis\n\n`data` und `raw_data` schließen sich gegenseitig aus. Sie können pro `ServerSentEvent` nur eines von beiden setzen.\n\n///\n\n## Mit `Last-Event-ID` fortsetzen { #resuming-with-last-event-id }\n\nWenn ein Browser nach einem Verbindungsabbruch erneut verbindet, sendet er die zuletzt empfangene `id` im Header `Last-Event-ID`.\n\nSie können ihn als Header-Parameter einlesen und verwenden, um den Stream dort fortzusetzen, wo der Client aufgehört hat:\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## SSE mit POST { #sse-with-post }\n\nSSE funktioniert mit **jedem HTTP-Method**, nicht nur mit `GET`.\n\nDas ist nützlich für Protokolle wie [MCP](https://modelcontextprotocol.io), die SSE über `POST` streamen:\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## Technische Details { #technical-details }\n\nFastAPI implementiert einige bewährte SSE-Praktiken direkt out of the box.\n\n- Alle 15 Sekunden, wenn keine Nachricht gesendet wurde, einen **„keep alive“-`ping`-Kommentar** senden, um zu verhindern, dass einige Proxys die Verbindung schließen, wie in der [HTML-Spezifikation: Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes) vorgeschlagen.\n- Den Header `Cache-Control: no-cache` setzen, um **Caching** des Streams zu verhindern.\n- Einen speziellen Header `X-Accel-Buffering: no` setzen, um **Buffering** in einigen Proxys wie Nginx zu verhindern.\n\nSie müssen dafür nichts tun, das funktioniert out of the box. 🤓\n"
  },
  {
    "path": "docs/de/docs/tutorial/sql-databases.md",
    "content": "# SQL (Relationale) Datenbanken { #sql-relational-databases }\n\n**FastAPI** erfordert nicht, dass Sie eine SQL (relationale) Datenbank verwenden. Sondern Sie können **jede beliebige Datenbank** verwenden, die Sie möchten.\n\nHier werden wir ein Beispiel mit [SQLModel](https://sqlmodel.tiangolo.com/) sehen.\n\n**SQLModel** basiert auf [SQLAlchemy](https://www.sqlalchemy.org/) und Pydantic. Es wurde vom selben Autor wie **FastAPI** entwickelt, um die perfekte Ergänzung für FastAPI-Anwendungen zu sein, die **SQL-Datenbanken** verwenden müssen.\n\n/// tip | Tipp\n\nSie könnten jede andere SQL- oder NoSQL-Datenbankbibliothek verwenden, die Sie möchten (in einigen Fällen als <abbr title=\"Object Relational Mapper – Objektrelationaler Mapper: Ein Fachbegriff für eine Bibliothek, in der einige Klassen SQL-Tabellen und Instanzen Zeilen in diesen Tabellen darstellen\">„ORMs“</abbr> bezeichnet), FastAPI zwingt Sie nicht, irgendetwas zu verwenden. 😎\n\n///\n\nDa SQLModel auf SQLAlchemy basiert, können Sie problemlos **jede von SQLAlchemy unterstützte Datenbank** verwenden (was auch bedeutet, dass sie von SQLModel unterstützt werden), wie:\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server, usw.\n\nIn diesem Beispiel verwenden wir **SQLite**, da es eine einzelne Datei verwendet und Python integrierte Unterstützung bietet. Sie können also dieses Beispiel kopieren und direkt ausführen.\n\nSpäter, für Ihre Produktionsanwendung, möchten Sie möglicherweise einen Datenbankserver wie **PostgreSQL** verwenden.\n\n/// tip | Tipp\n\nEs gibt einen offiziellen Projektgenerator mit **FastAPI** und **PostgreSQL**, einschließlich eines Frontends und weiterer Tools: [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\nDies ist ein sehr einfaches und kurzes Tutorial. Wenn Sie mehr über Datenbanken im Allgemeinen, über SQL oder fortgeschrittenere Funktionen erfahren möchten, besuchen Sie die [SQLModel-Dokumentation](https://sqlmodel.tiangolo.com/).\n\n## `SQLModel` installieren { #install-sqlmodel }\n\nStellen Sie zunächst sicher, dass Sie Ihre [virtuelle Umgebung](../virtual-environments.md) erstellen, sie aktivieren und dann `sqlmodel` installieren:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## Die App mit einem einzelnen Modell erstellen { #create-the-app-with-a-single-model }\n\nWir erstellen zuerst die einfachste erste Version der App mit einem einzigen **SQLModel**-Modell.\n\nSpäter werden wir sie verbessern, indem wir unter der Haube **mehrere Modelle** verwenden, um Sicherheit und Vielseitigkeit zu erhöhen. 🤓\n\n### Modelle erstellen { #create-models }\n\nImportieren Sie `SQLModel` und erstellen Sie ein Datenbankmodell:\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\nDie `Hero`-Klasse ist einem Pydantic-Modell sehr ähnlich (faktisch ist sie darunter tatsächlich *ein Pydantic-Modell*).\n\nEs gibt ein paar Unterschiede:\n\n* `table=True` sagt SQLModel, dass dies ein *Tabellenmodell* ist, es soll eine **Tabelle** in der SQL-Datenbank darstellen, es ist nicht nur ein *Datenmodell* (wie es jede andere reguläre Pydantic-Klasse wäre).\n\n* `Field(primary_key=True)` sagt SQLModel, dass die `id` der **Primärschlüssel** in der SQL-Datenbank ist (Sie können mehr über SQL-Primärschlüssel in der SQLModel-Dokumentation erfahren).\n\n    **Hinweis:** Wir verwenden für das Primärschlüsselfeld `int | None`, damit wir im Python-Code *ein Objekt ohne `id` erstellen* können (`id=None`), in der Annahme, dass die Datenbank sie *beim Speichern generiert*. SQLModel versteht, dass die Datenbank die `id` bereitstellt, und *definiert die Spalte im Datenbankschema als ein Nicht-Null-`INTEGER`*. Siehe die [SQLModel-Dokumentation zu Primärschlüsseln](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) für Details.\n\n* `Field(index=True)` sagt SQLModel, dass es einen **SQL-Index** für diese Spalte erstellen soll, was schnelleres Suchen in der Datenbank ermöglicht, wenn Daten mittels dieser Spalte gefiltert werden.\n\n    SQLModel wird verstehen, dass etwas, das als `str` deklariert ist, eine SQL-Spalte des Typs `TEXT` (oder `VARCHAR`, abhängig von der Datenbank) sein wird.\n\n### Eine Engine erstellen { #create-an-engine }\n\nEine SQLModel-`engine` (darunter ist es tatsächlich eine SQLAlchemy-`engine`) ist das, was die **Verbindungen** zur Datenbank hält.\n\nSie hätten **ein einziges `engine`-Objekt** für Ihren gesamten Code, um sich mit derselben Datenbank zu verbinden.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\nDie Verwendung von `check_same_thread=False` erlaubt FastAPI, dieselbe SQLite-Datenbank in verschiedenen Threads zu verwenden. Dies ist notwendig, da **ein einzelner <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Request</abbr>** **mehr als einen Thread** verwenden könnte (zum Beispiel in Abhängigkeiten).\n\nKeine Sorge, so wie der Code strukturiert ist, werden wir später sicherstellen, dass wir **eine einzige SQLModel-*Session* pro Request** verwenden, das ist eigentlich das, was `check_same_thread` erreichen möchte.\n\n### Die Tabellen erstellen { #create-the-tables }\n\nDann fügen wir eine Funktion hinzu, die `SQLModel.metadata.create_all(engine)` verwendet, um die **Tabellen für alle *Tabellenmodelle* zu erstellen**.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### Eine Session-Abhängigkeit erstellen { #create-a-session-dependency }\n\nEine <abbr title=\"Sitzung\">**`Session`**</abbr> speichert die **Objekte im Speicher** und verfolgt alle Änderungen, die an den Daten vorgenommen werden müssen, dann **verwendet sie die `engine`**, um mit der Datenbank zu kommunizieren.\n\nWir werden eine FastAPI **Abhängigkeit** mit `yield` erstellen, die eine neue `Session` für jeden Request bereitstellt. Das ist es, was sicherstellt, dass wir eine einzige Session pro Request verwenden. 🤓\n\nDann erstellen wir eine `Annotated`-Abhängigkeit `SessionDep`, um den Rest des Codes zu vereinfachen, der diese Abhängigkeit nutzen wird.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### Die Datenbanktabellen beim Start erstellen { #create-database-tables-on-startup }\n\nWir werden die Datenbanktabellen erstellen, wenn die Anwendung startet.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\nHier erstellen wir die Tabellen bei einem Anwendungsstart-Event.\n\nFür die Produktion würden Sie wahrscheinlich ein Migrationsskript verwenden, das ausgeführt wird, bevor Sie Ihre App starten. 🤓\n\n/// tip | Tipp\n\nSQLModel wird Migrationstools haben, die Alembic wrappen, aber im Moment können Sie [Alembic](https://alembic.sqlalchemy.org/en/latest/) direkt verwenden.\n\n///\n\n### Einen Helden erstellen { #create-a-hero }\n\nDa jedes SQLModel-Modell auch ein Pydantic-Modell ist, können Sie es in denselben **Typannotationen** verwenden, die Sie für Pydantic-Modelle verwenden könnten.\n\nWenn Sie beispielsweise einen Parameter vom Typ `Hero` deklarieren, wird er aus dem **JSON-Body** gelesen.\n\nAuf die gleiche Weise können Sie es als **Rückgabetyp** der Funktion deklarieren, und dann wird die Form der Daten in der automatischen API-Dokumentation angezeigt.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\nHier verwenden wir die `SessionDep`-Abhängigkeit (eine `Session`), um den neuen `Hero` zur `Session`-Instanz hinzuzufügen, die Änderungen an der Datenbank zu committen, die Daten im `hero` zu aktualisieren und ihn anschließend zurückzugeben.\n\n### Helden lesen { #read-heroes }\n\nWir können `Hero`s aus der Datenbank mit einem `select()` **lesen**. Wir können ein `limit` und `offset` hinzufügen, um die Ergebnisse zu paginieren.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### Einen Helden lesen { #read-one-hero }\n\nWir können einen einzelnen `Hero` **lesen**.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### Einen Helden löschen { #delete-a-hero }\n\nWir können auch einen `Hero` **löschen**.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### Die App ausführen { #run-the-app }\n\nSie können die App ausführen:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nGehen Sie dann zur `/docs`-UI, Sie werden sehen, dass **FastAPI** diese **Modelle** verwendet, um die API zu **dokumentieren**, und es wird sie auch verwenden, um die Daten zu **serialisieren** und zu **validieren**.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## Die App mit mehreren Modellen aktualisieren { #update-the-app-with-multiple-models }\n\nJetzt lassen Sie uns diese App ein wenig **refaktorisieren**, um die **Sicherheit** und **Vielseitigkeit** zu erhöhen.\n\nWenn Sie die vorherige App überprüfen, können Sie in der UI sehen, dass sie bis jetzt dem Client erlaubt, die `id` des zu erstellenden `Hero` zu bestimmen. 😱\n\nDas sollten wir nicht zulassen, sie könnten eine `id` überschreiben, die wir bereits in der DB zugewiesen haben. Die Entscheidung über die `id` sollte vom **Backend** oder der **Datenbank** getroffen werden, **nicht vom Client**.\n\nAußerdem erstellen wir einen `secret_name` für den Helden, aber bisher geben wir ihn überall zurück, das ist nicht sehr **geheim** ... 😅\n\nWir werden diese Dinge beheben, indem wir ein paar **zusätzliche Modelle** hinzufügen. Hier wird SQLModel glänzen. ✨\n\n### Mehrere Modelle erstellen { #create-multiple-models }\n\nIn **SQLModel** ist jede Modellklasse, die `table=True` hat, ein **Tabellenmodell**.\n\nUnd jede Modellklasse, die `table=True` nicht hat, ist ein **Datenmodell**, diese sind tatsächlich nur Pydantic-Modelle (mit ein paar kleinen zusätzlichen Funktionen). 🤓\n\nMit SQLModel können wir **Vererbung** verwenden, um **doppelte Felder** in allen Fällen zu **vermeiden**.\n\n#### `HeroBase` – die Basisklasse { #herobase-the-base-class }\n\nFangen wir mit einem `HeroBase`-Modell an, das alle **Felder hat, die von allen Modellen geteilt werden**:\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` – das *Tabellenmodell* { #hero-the-table-model }\n\nDann erstellen wir `Hero`, das tatsächliche *Tabellenmodell*, mit den **zusätzlichen Feldern**, die nicht immer in den anderen Modellen enthalten sind:\n\n* `id`\n* `secret_name`\n\nDa `Hero` von `HeroBase` erbt, hat es **auch** die **Felder**, die in `HeroBase` deklariert sind, also sind alle Felder von `Hero`:\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` – das öffentliche *Datenmodell* { #heropublic-the-public-data-model }\n\nAls nächstes erstellen wir ein `HeroPublic`-Modell, das an die API-Clients **zurückgegeben** wird.\n\nEs hat dieselben Felder wie `HeroBase`, sodass es `secret_name` nicht enthält.\n\nEndlich ist die Identität unserer Helden geschützt! 🥷\n\nEs deklariert auch `id: int` erneut. Indem wir dies tun, machen wir einen **Vertrag** mit den API-Clients, damit sie immer damit rechnen können, dass die `id` vorhanden ist und ein `int` ist (sie wird niemals `None` sein).\n\n/// tip | Tipp\n\nEs ist sehr nützlich für die API-Clients, wenn das Rückgabemodell sicherstellt, dass ein Wert immer verfügbar und immer `int` (nicht `None`) ist, sie können viel einfacheren Code schreiben, wenn sie diese Sicherheit haben.\n\nAuch **automatisch generierte Clients** werden einfachere Schnittstellen haben, damit die Entwickler, die mit Ihrer API kommunizieren, viel mehr Freude an der Arbeit mit Ihrer API haben können. 😎\n\n///\n\nAlle Felder in `HeroPublic` sind dieselben wie in `HeroBase`, mit `id`, das als `int` (nicht `None`) deklariert ist:\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` – das *Datenmodell* zum Erstellen eines Helden { #herocreate-the-data-model-to-create-a-hero }\n\nNun erstellen wir ein `HeroCreate`-Modell, das die Daten der Clients **validiert**.\n\nEs hat dieselben Felder wie `HeroBase`, und es hat auch `secret_name`.\n\nWenn die Clients **einen neuen Helden erstellen**, senden sie jetzt den `secret_name`, er wird in der Datenbank gespeichert, aber diese geheimen Namen werden den API-Clients nicht zurückgegeben.\n\n/// tip | Tipp\n\nSo würden Sie **Passwörter** handhaben. Empfangen Sie sie, aber geben Sie sie nicht in der API zurück.\n\nSie würden auch die Werte der Passwörter **hashen**, bevor Sie sie speichern, und sie **niemals im Klartext** speichern.\n\n///\n\nDie Felder von `HeroCreate` sind:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` – das *Datenmodell* zum Aktualisieren eines Helden { #heroupdate-the-data-model-to-update-a-hero }\n\nIn der vorherigen Version der App hatten wir keine Möglichkeit, einen Helden **zu aktualisieren**, aber jetzt mit **mehreren Modellen** können wir es. 🎉\n\nDas `HeroUpdate`-*Datenmodell* ist etwas Besonderes, es hat **die selben Felder**, die benötigt werden, um einen neuen Helden zu erstellen, aber alle Felder sind **optional** (sie haben alle einen Defaultwert). Auf diese Weise, wenn Sie einen Helden aktualisieren, können Sie nur die Felder senden, die Sie aktualisieren möchten.\n\nDa sich tatsächlich **alle Felder ändern** (der Typ enthält jetzt `None` und sie haben jetzt einen Standardwert von `None`), müssen wir sie erneut **deklarieren**.\n\nWir müssen wirklich nicht von `HeroBase` erben, weil wir alle Felder neu deklarieren. Ich lasse es aus Konsistenzgründen erben, aber das ist nicht notwendig. Es ist mehr eine Frage des persönlichen Geschmacks. 🤷\n\nDie Felder von `HeroUpdate` sind:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### Mit `HeroCreate` erstellen und ein `HeroPublic` zurückgeben { #create-with-herocreate-and-return-a-heropublic }\n\nNun, da wir **mehrere Modelle** haben, können wir die Teile der App aktualisieren, die sie verwenden.\n\nWir empfangen im Request ein `HeroCreate`-*Datenmodell* und daraus erstellen wir ein `Hero`-*Tabellenmodell*.\n\nDieses neue *Tabellenmodell* `Hero` wird die vom Client gesendeten Felder haben und zusätzlich eine `id`, die von der Datenbank generiert wird.\n\nDann geben wir das gleiche *Tabellenmodell* `Hero` von der Funktion zurück. Aber da wir das `response_model` mit dem `HeroPublic`-*Datenmodell* deklarieren, wird **FastAPI** `HeroPublic` verwenden, um die Daten zu validieren und zu serialisieren.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | Tipp\n\nJetzt verwenden wir `response_model=HeroPublic` anstelle der **Rückgabetyp-Annotation** `-> HeroPublic`, weil der Wert, den wir zurückgeben, tatsächlich *kein* `HeroPublic` ist.\n\nWenn wir `-> HeroPublic` deklariert hätten, würden Ihr Editor und Linter (zu Recht) reklamieren, dass Sie ein `Hero` anstelle eines `HeroPublic` zurückgeben.\n\nDurch die Deklaration in `response_model` sagen wir **FastAPI**, dass es seine Aufgabe erledigen soll, ohne die Typannotationen und die Hilfe von Ihrem Editor und anderen Tools zu beeinträchtigen.\n\n///\n\n### Helden mit `HeroPublic` lesen { #read-heroes-with-heropublic }\n\nWir können dasselbe wie zuvor tun, um `Hero`s zu **lesen**, und erneut verwenden wir `response_model=list[HeroPublic]`, um sicherzustellen, dass die Daten ordnungsgemäß validiert und serialisiert werden.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### Einen einzelnen Helden mit `HeroPublic` lesen { #read-one-hero-with-heropublic }\n\nWir können einen einzelnen Helden **lesen**:\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### Einen Helden mit `HeroUpdate` aktualisieren { #update-a-hero-with-heroupdate }\n\nWir können einen Helden **aktualisieren**. Dafür verwenden wir eine HTTP-`PATCH`-Operation.\n\nUnd im Code erhalten wir ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr> mit allen Daten, die vom Client gesendet wurden, **nur die Daten, die vom Client gesendet wurden**, unter Ausschluss von Werten, die dort nur als Defaultwerte vorhanden wären. Um dies zu tun, verwenden wir `exclude_unset=True`. Das ist der Haupttrick. 🪄\n\nDann verwenden wir `hero_db.sqlmodel_update(hero_data)`, um die `hero_db` mit den Daten aus `hero_data` zu aktualisieren.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### Einen Helden wieder löschen { #delete-a-hero-again }\n\nDas **Löschen** eines Helden bleibt ziemlich gleich.\n\nWir werden dieses Mal nicht dem Wunsch nachgeben, alles zu refaktorisieren. 😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### Die App erneut ausführen { #run-the-app-again }\n\nSie können die App erneut ausführen:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nWenn Sie zur `/docs`-API-UI gehen, werden Sie sehen, dass sie jetzt aktualisiert ist und nicht mehr erwarten wird, die `id` vom Client beim Erstellen eines Helden zu erhalten, usw.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## Zusammenfassung { #recap }\n\nSie können [**SQLModel**](https://sqlmodel.tiangolo.com/) verwenden, um mit einer SQL-Datenbank zu interagieren und den Code mit *Datenmodellen* und *Tabellenmodellen* zu vereinfachen.\n\nSie können viel mehr in der **SQLModel**-Dokumentation lernen, es gibt ein längeres Mini-[Tutorial zur Verwendung von SQLModel mit **FastAPI**](https://sqlmodel.tiangolo.com/tutorial/fastapi/). 🚀\n"
  },
  {
    "path": "docs/de/docs/tutorial/static-files.md",
    "content": "# Statische Dateien { #static-files }\n\nMit `StaticFiles` können Sie statische Dateien aus einem Verzeichnis automatisch bereitstellen.\n\n## `StaticFiles` verwenden { #use-staticfiles }\n\n* Importieren Sie `StaticFiles`.\n* „Mounten“ Sie eine `StaticFiles()`-Instanz in einem bestimmten Pfad.\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | Technische Details\n\nSie könnten auch `from starlette.staticfiles import StaticFiles` verwenden.\n\n**FastAPI** stellt dasselbe `starlette.staticfiles` auch via `fastapi.staticfiles` bereit, als Annehmlichkeit für Sie, den Entwickler. Es kommt aber tatsächlich direkt von Starlette.\n\n///\n\n### Was ist „Mounten“ { #what-is-mounting }\n\n„Mounten“ bedeutet das Hinzufügen einer vollständigen „unabhängigen“ Anwendung an einem bestimmten Pfad, die sich dann um die Handhabung aller Unterpfade kümmert.\n\nDies unterscheidet sich von der Verwendung eines `APIRouter`, da eine gemountete Anwendung völlig unabhängig ist. Die OpenAPI und Dokumentation Ihrer Hauptanwendung enthalten nichts von der gemounteten Anwendung, usw.\n\nWeitere Informationen hierzu finden Sie im [Handbuch für fortgeschrittene Benutzer](../advanced/index.md).\n\n## Einzelheiten { #details }\n\nDas erste `\"/static\"` bezieht sich auf den Unterpfad, auf dem diese „Unteranwendung“ „gemountet“ wird. Daher wird jeder Pfad, der mit `\"/static\"` beginnt, von ihr verarbeitet.\n\nDas `directory=\"static\"` bezieht sich auf den Namen des Verzeichnisses, das Ihre statischen Dateien enthält.\n\nDas `name=\"static\"` gibt dieser Unteranwendung einen Namen, der intern von **FastAPI** verwendet werden kann.\n\nAlle diese Parameter können anders als „`static`“ lauten, passen Sie sie an die Bedürfnisse und spezifischen Details Ihrer eigenen Anwendung an.\n\n## Weitere Informationen { #more-info }\n\nWeitere Details und Optionen finden Sie in [Starlettes Dokumentation zu statischen Dateien](https://www.starlette.dev/staticfiles/).\n"
  },
  {
    "path": "docs/de/docs/tutorial/stream-json-lines.md",
    "content": "# JSON Lines streamen { #stream-json-lines }\n\nSie könnten eine Folge von Daten haben, die Sie in einem „Stream“ senden möchten, das können Sie mit **JSON Lines** tun.\n\n/// info | Info\n\nHinzugefügt in FastAPI 0.134.0.\n\n///\n\n## Was ist ein Stream? { #what-is-a-stream }\n\n„Streaming“ von Daten bedeutet, dass Ihre App damit beginnt, Datenelemente an den Client zu senden, ohne darauf zu warten, dass die gesamte Folge von Elementen fertig ist.\n\nSie sendet also das erste Element, der Client empfängt es und beginnt mit der Verarbeitung, und Sie erzeugen währenddessen möglicherweise bereits das nächste Element.\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\nEs könnte sogar ein unendlicher Stream sein, bei dem Sie kontinuierlich Daten senden.\n\n## JSON Lines { #json-lines }\n\nIn diesen Fällen ist es üblich, „JSON Lines“ zu senden, das ist ein Format, bei dem Sie pro Zeile genau ein JSON-Objekt senden.\n\nEine Response hätte einen Content-Type von `application/jsonl` (anstelle von `application/json`) und der Body sähe etwa so aus:\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\nEs ist einem JSON-Array (entspricht einer Python-Liste) sehr ähnlich, aber anstatt in `[]` eingeschlossen zu sein und `,` zwischen den Elementen zu haben, gibt es hier **ein JSON-Objekt pro Zeile**, sie sind durch ein Zeilenumbruchzeichen getrennt.\n\n/// info | Info\n\nDer wichtige Punkt ist, dass Ihre App in der Lage ist, jede Zeile der Reihe nach zu erzeugen, während der Client die vorherigen Zeilen konsumiert.\n\n///\n\n/// note | Technische Details\n\nDa jedes JSON-Objekt durch einen Zeilenumbruch getrennt wird, können sie keine wörtlichen Zeilenumbrüche in ihrem Inhalt enthalten, aber sie können escapte Zeilenumbrüche (`\\n`) enthalten, das ist Teil des JSON-Standards.\n\nNormalerweise müssen Sie sich darum aber nicht kümmern, das geschieht automatisch, lesen Sie weiter. 🤓\n\n///\n\n## Anwendungsfälle { #use-cases }\n\nSie könnten dies verwenden, um Daten von einem **AI LLM**-Service, aus **Logs** oder **Telemetrie**, oder aus anderen Typen von Daten zu streamen, die sich in **JSON**-Items strukturieren lassen.\n\n/// tip | Tipp\n\nWenn Sie Binärdaten streamen möchten, zum Beispiel Video oder Audio, sehen Sie sich den erweiterten Leitfaden an: [Daten streamen](../advanced/stream-data.md).\n\n///\n\n## JSON Lines mit FastAPI streamen { #stream-json-lines-with-fastapi }\n\nUm JSON Lines mit FastAPI zu streamen, können Sie anstelle von `return` in Ihrer *Pfadoperation-Funktion* `yield` verwenden, um jedes Element der Reihe nach zu erzeugen.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\nWenn jedes JSON-Item, das Sie zurücksenden möchten, vom Typ `Item` ist (ein Pydantic-Modell) und es sich um eine async-Funktion handelt, können Sie den Rückgabetyp als `AsyncIterable[Item]` deklarieren:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\nWenn Sie den Rückgabetyp deklarieren, wird FastAPI ihn verwenden, um die Daten zu **validieren**, sie in OpenAPI zu **dokumentieren**, sie zu **filtern** und sie mit Pydantic zu **serialisieren**.\n\n/// tip | Tipp\n\nDa Pydantic es auf der **Rust**-Seite serialisiert, erhalten Sie eine deutlich höhere **Leistung** als wenn Sie keinen Rückgabetyp deklarieren.\n\n///\n\n### Nicht-async *Pfadoperation-Funktionen* { #non-async-path-operation-functions }\n\nSie können auch normale `def`-Funktionen (ohne `async`) verwenden und `yield` auf die gleiche Weise einsetzen.\n\nFastAPI stellt sicher, dass sie korrekt ausgeführt werden, sodass der Event Loop nicht blockiert wird.\n\nDa die Funktion in diesem Fall nicht async ist, wäre der richtige Rückgabetyp `Iterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### Kein Rückgabetyp { #no-return-type }\n\nSie können den Rückgabetyp auch weglassen. FastAPI verwendet dann den [`jsonable_encoder`](./encoder.md), um die Daten in etwas zu konvertieren, das zu JSON serialisiert werden kann, und sendet sie anschließend als JSON Lines.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## Server-Sent Events (SSE) { #server-sent-events-sse }\n\nFastAPI hat außerdem erstklassige Unterstützung für Server-Sent Events (SSE), die dem sehr ähnlich sind, aber ein paar zusätzliche Details mitbringen. Sie können im nächsten Kapitel mehr darüber lernen: [Server-Sent Events (SSE)](server-sent-events.md). 🤓\n"
  },
  {
    "path": "docs/de/docs/tutorial/testing.md",
    "content": "# Testen { #testing }\n\nDank [Starlette](https://www.starlette.dev/testclient/) ist das Testen von **FastAPI**-Anwendungen einfach und macht Spaß.\n\nEs basiert auf [HTTPX](https://www.python-httpx.org), welches wiederum auf der Grundlage von Requests konzipiert wurde, es ist also sehr vertraut und intuitiv.\n\nDamit können Sie [pytest](https://docs.pytest.org/) direkt mit **FastAPI** verwenden.\n\n## `TestClient` verwenden { #using-testclient }\n\n/// info | Info\n\nUm `TestClient` zu verwenden, installieren Sie zunächst [`httpx`](https://www.python-httpx.org).\n\nErstellen Sie eine [virtuelle Umgebung](../virtual-environments.md), aktivieren Sie sie und installieren Sie es dann, z. B.:\n\n```console\n$ pip install httpx\n```\n\n///\n\nImportieren Sie `TestClient`.\n\nErstellen Sie einen `TestClient`, indem Sie ihm Ihre **FastAPI**-Anwendung übergeben.\n\nErstellen Sie Funktionen mit einem Namen, der mit `test_` beginnt (das sind `pytest`-Konventionen).\n\nVerwenden Sie das `TestClient`-Objekt auf die gleiche Weise wie `httpx`.\n\nSchreiben Sie einfache `assert`-Anweisungen mit den Standard-Python-Ausdrücken, die Sie überprüfen müssen (wiederum, Standard-`pytest`).\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip | Tipp\n\nBeachten Sie, dass die Testfunktionen normal `def` und nicht `async def` sind.\n\nUnd die Anrufe an den Client sind ebenfalls normale Anrufe, die nicht `await` verwenden.\n\nDadurch können Sie `pytest` ohne Komplikationen direkt nutzen.\n\n///\n\n/// note | Technische Details\n\nSie könnten auch `from starlette.testclient import TestClient` verwenden.\n\n**FastAPI** stellt denselben `starlette.testclient` auch via `fastapi.testclient` bereit, als Annehmlichkeit für Sie, den Entwickler. Es kommt aber tatsächlich direkt von Starlette.\n\n///\n\n/// tip | Tipp\n\nWenn Sie in Ihren Tests neben dem Senden von <abbr title=\"Request – Anfrage: Daten, die der Client zum Server sendet\">Requests</abbr> an Ihre FastAPI-Anwendung auch `async`-Funktionen aufrufen möchten (z. B. asynchrone Datenbankfunktionen), werfen Sie einen Blick auf die [Async-Tests](../advanced/async-tests.md) im Handbuch für fortgeschrittene Benutzer.\n\n///\n\n## Tests separieren { #separating-tests }\n\nIn einer echten Anwendung würden Sie Ihre Tests wahrscheinlich in einer anderen Datei haben.\n\nUnd Ihre **FastAPI**-Anwendung könnte auch aus mehreren Dateien/Modulen, usw. bestehen.\n\n### **FastAPI** Anwendungsdatei { #fastapi-app-file }\n\nNehmen wir an, Sie haben eine Dateistruktur wie in [Größere Anwendungen](bigger-applications.md) beschrieben:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\nIn der Datei `main.py` haben Sie Ihre **FastAPI**-Anwendung:\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n\n### Testdatei { #testing-file }\n\nDann könnten Sie eine Datei `test_main.py` mit Ihren Tests haben. Sie könnte sich im selben Python-Package befinden (dasselbe Verzeichnis mit einer `__init__.py`-Datei):\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nDa sich diese Datei im selben Package befindet, können Sie relative Importe verwenden, um das Objekt `app` aus dem `main`-Modul (`main.py`) zu importieren:\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n\n... und haben den Code für die Tests wie zuvor.\n\n## Testen: erweitertes Beispiel { #testing-extended-example }\n\nNun erweitern wir dieses Beispiel und fügen weitere Details hinzu, um zu sehen, wie verschiedene Teile getestet werden.\n\n### Erweiterte **FastAPI**-Anwendungsdatei { #extended-fastapi-app-file }\n\nFahren wir mit der gleichen Dateistruktur wie zuvor fort:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nNehmen wir an, dass die Datei `main.py` mit Ihrer **FastAPI**-Anwendung jetzt einige andere **Pfadoperationen** hat.\n\nSie verfügt über eine `GET`-Operation, die einen Fehler zurückgeben könnte.\n\nSie verfügt über eine `POST`-Operation, die mehrere Fehler zurückgeben könnte.\n\nBeide *Pfadoperationen* erfordern einen `X-Token`-Header.\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### Erweiterte Testdatei { #extended-testing-file }\n\nAnschließend könnten Sie `test_main.py` mit den erweiterten Tests aktualisieren:\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\n\nWenn Sie möchten, dass der Client Informationen im Request übergibt und Sie nicht wissen, wie das geht, können Sie suchen (googeln), wie es mit `httpx` gemacht wird, oder sogar, wie es mit `requests` gemacht wird, da das Design von HTTPX auf dem Design von Requests basiert.\n\nDann machen Sie in Ihren Tests einfach das gleiche.\n\nZ. B.:\n\n* Um einen *Pfad*- oder *Query*-Parameter zu übergeben, fügen Sie ihn der URL selbst hinzu.\n* Um einen JSON-Body zu übergeben, übergeben Sie ein Python-Objekt (z. B. ein <abbr title=\"Dictionary – Zuordnungstabelle: In anderen Sprachen auch Hash, Map, Objekt, Assoziatives Array genannt\">`dict`</abbr>) an den Parameter `json`.\n* Wenn Sie *Formulardaten* anstelle von JSON senden müssen, verwenden Sie stattdessen den `data`-Parameter.\n* Um *Header* zu übergeben, verwenden Sie ein `dict` im `headers`-Parameter.\n* Für *Cookies* ein `dict` im `cookies`-Parameter.\n\nWeitere Informationen zum Übergeben von Daten an das Backend (mithilfe von `httpx` oder dem `TestClient`) finden Sie in der [HTTPX-Dokumentation](https://www.python-httpx.org).\n\n/// info | Info\n\nBeachten Sie, dass der `TestClient` Daten empfängt, die nach JSON konvertiert werden können, keine Pydantic-Modelle.\n\nWenn Sie ein Pydantic-Modell in Ihrem Test haben und dessen Daten während des Testens an die Anwendung senden möchten, können Sie den `jsonable_encoder` verwenden, der in [JSON-kompatibler Encoder](encoder.md) beschrieben wird.\n\n///\n\n## Tests ausführen { #run-it }\n\nDanach müssen Sie nur noch `pytest` installieren.\n\nErstellen Sie eine [virtuelle Umgebung](../virtual-environments.md), aktivieren Sie sie und installieren Sie es dann, z. B.:\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\nEs erkennt die Dateien und Tests automatisch, führt sie aus und berichtet Ihnen die Ergebnisse.\n\nFühren Sie die Tests aus, mit:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/de/docs/virtual-environments.md",
    "content": "# Virtuelle Umgebungen { #virtual-environments }\n\nWenn Sie an Python-Projekten arbeiten, sollten Sie wahrscheinlich eine **virtuelle Umgebung** (oder einen ähnlichen Mechanismus) verwenden, um die <abbr title=\"Python Installationspakete\">Packages</abbr>, die Sie für jedes Projekt installieren, zu isolieren.\n\n/// info | Info\n\nWenn Sie bereits über virtuelle Umgebungen Bescheid wissen, wie man sie erstellt und verwendet, möchten Sie diesen Abschnitt vielleicht überspringen. 🤓\n\n///\n\n/// tip | Tipp\n\nEine **virtuelle Umgebung** unterscheidet sich von einer **Umgebungsvariable**.\n\nEine **Umgebungsvariable** ist eine Variable im System, die von Programmen verwendet werden kann.\n\nEine **virtuelle Umgebung** ist ein Verzeichnis mit einigen Dateien darin.\n\n///\n\n/// info | Info\n\nDiese Seite wird Ihnen beibringen, wie Sie **virtuelle Umgebungen** verwenden und wie sie funktionieren.\n\nWenn Sie bereit sind, ein **Tool zu verwenden, das alles für Sie verwaltet** (einschließlich der Installation von Python), probieren Sie [uv](https://github.com/astral-sh/uv).\n\n///\n\n## Ein Projekt erstellen { #create-a-project }\n\nErstellen Sie zuerst ein Verzeichnis für Ihr Projekt.\n\nWas ich normalerweise mache, ist, dass ich ein Verzeichnis namens `code` in meinem Home/Benutzerverzeichnis erstelle.\n\nUnd darin erstelle ich ein Verzeichnis pro Projekt.\n\n<div class=\"termy\">\n\n```console\n// Gehe zum Home-Verzeichnis\n$ cd\n// Erstelle ein Verzeichnis für alle Ihre Code-Projekte\n$ mkdir code\n// Gehe in dieses Code-Verzeichnis\n$ cd code\n// Erstelle ein Verzeichnis für dieses Projekt\n$ mkdir awesome-project\n// Gehe in dieses Projektverzeichnis\n$ cd awesome-project\n```\n\n</div>\n\n## Eine virtuelle Umgebung erstellen { #create-a-virtual-environment }\n\nWenn Sie zum **ersten Mal** an einem Python-Projekt arbeiten, erstellen Sie eine virtuelle Umgebung **<dfn title=\"es gibt andere Optionen, dies ist eine einfache Richtlinie\">innerhalb Ihres Projekts</dfn>**.\n\n/// tip | Tipp\n\nSie müssen dies nur **einmal pro Projekt** tun, nicht jedes Mal, wenn Sie daran arbeiten.\n\n///\n\n//// tab | `venv`\n\nUm eine virtuelle Umgebung zu erstellen, können Sie das `venv`-Modul verwenden, das mit Python geliefert wird.\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | Was dieser Befehl bedeutet\n\n* `python`: das Programm namens `python` verwenden\n* `-m`: ein Modul als Skript aufrufen, wir geben als nächstes an, welches Modul\n* `venv`: das Modul namens `venv` verwenden, das normalerweise mit Python installiert wird\n* `.venv`: die virtuelle Umgebung im neuen Verzeichnis `.venv` erstellen\n\n///\n\n////\n\n//// tab | `uv`\n\nWenn Sie [`uv`](https://github.com/astral-sh/uv) installiert haben, können Sie es verwenden, um eine virtuelle Umgebung zu erstellen.\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip | Tipp\n\nStandardmäßig erstellt `uv` eine virtuelle Umgebung in einem Verzeichnis namens `.venv`.\n\nAber Sie könnten es anpassen, indem Sie ein zusätzliches Argument mit dem Verzeichnisnamen übergeben.\n\n///\n\n////\n\nDieser Befehl erstellt eine neue virtuelle Umgebung in einem Verzeichnis namens `.venv`.\n\n/// details | `.venv` oder ein anderer Name\n\nSie könnten die virtuelle Umgebung in einem anderen Verzeichnis erstellen, aber es ist eine Konvention, sie `.venv` zu nennen.\n\n///\n\n## Die virtuelle Umgebung aktivieren { #activate-the-virtual-environment }\n\nAktivieren Sie die neue virtuelle Umgebung, damit jeder Python-Befehl, den Sie ausführen oder jedes Paket, das Sie installieren, diese Umgebung verwendet.\n\n/// tip | Tipp\n\nTun Sie dies **jedes Mal**, wenn Sie eine **neue Terminalsitzung** starten, um an dem Projekt zu arbeiten.\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nOder wenn Sie Bash für Windows verwenden (z. B. [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip | Tipp\n\nJedes Mal, wenn Sie ein **neues Paket** in dieser Umgebung installieren, aktivieren Sie die Umgebung erneut.\n\nSo stellen Sie sicher, dass, wenn Sie ein **Terminalprogramm (<abbr title=\"command line interface - Kommandozeileninterface\">CLI</abbr>)** verwenden, das durch dieses Paket installiert wurde, Sie das aus Ihrer virtuellen Umgebung verwenden und nicht eines, das global installiert ist, wahrscheinlich mit einer anderen Version als der, die Sie benötigen.\n\n///\n\n## Testen, ob die virtuelle Umgebung aktiv ist { #check-the-virtual-environment-is-active }\n\nTesten Sie, dass die virtuelle Umgebung aktiv ist (der vorherige Befehl funktioniert hat).\n\n/// tip | Tipp\n\nDies ist **optional**, aber es ist eine gute Möglichkeit, **zu überprüfen**, ob alles wie erwartet funktioniert und Sie die beabsichtigte virtuelle Umgebung verwenden.\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\nWenn es das `python`-Binary in `.venv/bin/python` anzeigt, innerhalb Ihres Projekts (in diesem Fall `awesome-project`), dann hat es funktioniert. 🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\nWenn es das `python`-Binary in `.venv\\Scripts\\python` anzeigt, innerhalb Ihres Projekts (in diesem Fall `awesome-project`), dann hat es funktioniert. 🎉\n\n////\n\n## `pip` aktualisieren { #upgrade-pip }\n\n/// tip | Tipp\n\nWenn Sie [`uv`](https://github.com/astral-sh/uv) verwenden, würden Sie das verwenden, um Dinge zu installieren anstelle von `pip`, sodass Sie `pip` nicht aktualisieren müssen. 😎\n\n///\n\nWenn Sie `pip` verwenden, um Pakete zu installieren (es wird standardmäßig mit Python geliefert), sollten Sie es auf die neueste Version **aktualisieren**.\n\nViele exotische Fehler beim Installieren eines Pakets werden einfach dadurch gelöst, dass zuerst `pip` aktualisiert wird.\n\n/// tip | Tipp\n\nNormalerweise würden Sie dies **einmal** tun, unmittelbar nachdem Sie die virtuelle Umgebung erstellt haben.\n\n///\n\nStellen Sie sicher, dass die virtuelle Umgebung aktiv ist (mit dem obigen Befehl) und führen Sie dann aus:\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip | Tipp\n\nManchmal kann beim Versuch, `pip` zu aktualisieren, der Fehler **`No module named pip`** auftreten.\n\nWenn das passiert, installieren und aktualisieren Sie `pip` mit dem folgenden Befehl:\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\nDieser Befehl installiert `pip`, falls es noch nicht installiert ist, und stellt außerdem sicher, dass die installierte Version von `pip` mindestens so aktuell ist wie die in `ensurepip` verfügbare.\n\n///\n\n## `.gitignore` hinzufügen { #add-gitignore }\n\nWenn Sie **Git** verwenden (was Sie sollten), fügen Sie eine `.gitignore`-Datei hinzu, um alles in Ihrem `.venv` von Git auszuschließen.\n\n/// tip | Tipp\n\nWenn Sie [`uv`](https://github.com/astral-sh/uv) verwendet haben, um die virtuelle Umgebung zu erstellen, hat es dies bereits für Sie getan, Sie können diesen Schritt überspringen. 😎\n\n///\n\n/// tip | Tipp\n\nTun Sie dies **einmal**, unmittelbar nachdem Sie die virtuelle Umgebung erstellt haben.\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | Was dieser Befehl bedeutet\n\n* `echo \"*\"`: wird den Text `*` im Terminal „drucken“ (der nächste Teil ändert das ein wenig)\n* `>`: alles, was durch den Befehl links von `>` im Terminal ausgegeben wird, sollte nicht gedruckt, sondern stattdessen in die Datei geschrieben werden, die rechts von `>` kommt\n* `.gitignore`: der Name der Datei, in die der Text geschrieben werden soll\n\nUnd `*` bedeutet für Git „alles“. Also wird alles im `.venv`-Verzeichnis ignoriert.\n\nDieser Befehl erstellt eine Datei `.gitignore` mit dem Inhalt:\n\n```gitignore\n*\n```\n\n///\n\n## Pakete installieren { #install-packages }\n\nNachdem Sie die Umgebung aktiviert haben, können Sie Pakete darin installieren.\n\n/// tip | Tipp\n\nTun Sie dies **einmal**, wenn Sie die Pakete installieren oder aktualisieren, die Ihr Projekt benötigt.\n\nWenn Sie eine Version aktualisieren oder ein neues Paket hinzufügen müssen, würden Sie **dies erneut tun**.\n\n///\n\n### Pakete direkt installieren { #install-packages-directly }\n\nWenn Sie es eilig haben und keine Datei verwenden möchten, um die Paketanforderungen Ihres Projekts zu deklarieren, können Sie sie direkt installieren.\n\n/// tip | Tipp\n\nEs ist eine (sehr) gute Idee, die Pakete und Versionen, die Ihr Programm benötigt, in einer Datei zu speichern (zum Beispiel `requirements.txt` oder `pyproject.toml`).\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nWenn Sie [`uv`](https://github.com/astral-sh/uv) haben:\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### Installation von `requirements.txt` { #install-from-requirements-txt }\n\nWenn Sie eine `requirements.txt` haben, können Sie diese nun verwenden, um deren Pakete zu installieren.\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nWenn Sie [`uv`](https://github.com/astral-sh/uv) haben:\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\nEine `requirements.txt` mit einigen Paketen könnte folgendermaßen aussehen:\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## Ihr Programm ausführen { #run-your-program }\n\nNachdem Sie die virtuelle Umgebung aktiviert haben, können Sie Ihr Programm ausführen, und es wird das Python innerhalb Ihrer virtuellen Umgebung mit den Paketen verwenden, die Sie dort installiert haben.\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## Ihren Editor konfigurieren { #configure-your-editor }\n\nSie würden wahrscheinlich einen Editor verwenden, stellen Sie sicher, dass Sie ihn so konfigurieren, dass er dieselbe virtuelle Umgebung verwendet, die Sie erstellt haben (er wird sie wahrscheinlich automatisch erkennen), sodass Sie Autovervollständigungen und Inline-Fehler erhalten können.\n\nZum Beispiel:\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip | Tipp\n\nNormalerweise müssen Sie dies nur **einmal** tun, wenn Sie die virtuelle Umgebung erstellen.\n\n///\n\n## Die virtuelle Umgebung deaktivieren { #deactivate-the-virtual-environment }\n\nSobald Sie mit der Arbeit an Ihrem Projekt fertig sind, können Sie die virtuelle Umgebung **deaktivieren**.\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\nAuf diese Weise, wenn Sie `python` ausführen, wird nicht versucht, es aus dieser virtuellen Umgebung mit den dort installierten Paketen auszuführen.\n\n## Bereit zu arbeiten { #ready-to-work }\n\nJetzt sind Sie bereit, mit Ihrem Projekt zu arbeiten.\n\n/// tip | Tipp\n\nMöchten Sie verstehen, was das alles oben bedeutet?\n\nLesen Sie weiter. 👇🤓\n\n///\n\n## Warum virtuelle Umgebungen { #why-virtual-environments }\n\nUm mit FastAPI zu arbeiten, müssen Sie [Python](https://www.python.org/) installieren.\n\nDanach müssen Sie FastAPI und alle anderen Pakete, die Sie verwenden möchten, **installieren**.\n\nUm Pakete zu installieren, würden Sie normalerweise den `pip`-Befehl verwenden, der mit Python geliefert wird (oder ähnliche Alternativen).\n\nWenn Sie jedoch `pip` direkt verwenden, werden die Pakete in Ihrer **globalen Python-Umgebung** (der globalen Installation von Python) installiert.\n\n### Das Problem { #the-problem }\n\nWas ist also das Problem beim Installieren von Paketen in der globalen Python-Umgebung?\n\nIrgendwann werden Sie wahrscheinlich viele verschiedene Programme schreiben, die von **verschiedenen Paketen** abhängen. Und einige dieser Projekte, an denen Sie arbeiten, werden von **verschiedenen Versionen** desselben Pakets abhängen. 😱\n\nZum Beispiel könnten Sie ein Projekt namens `philosophers-stone` erstellen, dieses Programm hängt von einem anderen Paket namens **`harry`, Version `1`** ab. Also müssen Sie `harry` installieren.\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|benötigt| harry-1[harry v1]\n```\n\nDann erstellen Sie zu einem späteren Zeitpunkt ein weiteres Projekt namens `prisoner-of-azkaban`, und dieses Projekt hängt ebenfalls von `harry` ab, aber dieses Projekt benötigt **`harry` Version `3`**.\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |benötigt| harry-3[harry v3]\n```\n\nAber jetzt ist das Problem, wenn Sie die Pakete global (in der globalen Umgebung) installieren anstatt in einer lokalen **virtuellen Umgebung**, müssen Sie wählen, welche Version von `harry` zu installieren ist.\n\nWenn Sie `philosophers-stone` ausführen möchten, müssen Sie zuerst `harry` Version `1` installieren, zum Beispiel mit:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\nUnd dann hätten Sie `harry` Version `1` in Ihrer globalen Python-Umgebung installiert.\n\n```mermaid\nflowchart LR\n    subgraph global[globale Umgebung]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone-Projekt]\n        stone(philosophers-stone) -->|benötigt| harry-1\n    end\n```\n\nAber dann, wenn Sie `prisoner-of-azkaban` ausführen möchten, müssen Sie `harry` Version `1` deinstallieren und `harry` Version `3` installieren (oder einfach die Version `3` installieren, was die Version `1` automatisch deinstallieren würde).\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\nUnd dann hätten Sie `harry` Version `3` in Ihrer globalen Python-Umgebung installiert.\n\nUnd wenn Sie versuchen, `philosophers-stone` erneut auszuführen, besteht die Möglichkeit, dass es **nicht funktioniert**, weil es `harry` Version `1` benötigt.\n\n```mermaid\nflowchart LR\n    subgraph global[globale Umgebung]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone-Projekt]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban-Projekt]\n        azkaban(prisoner-of-azkaban) --> |benötigt| harry-3\n    end\n```\n\n/// tip | Tipp\n\nEs ist sehr üblich in Python-Paketen, alles zu versuchen, **Breaking Changes** in **neuen Versionen** zu vermeiden, aber es ist besser, auf Nummer sicher zu gehen und neue Versionen absichtlich zu installieren und wenn Sie die Tests ausführen können, sicherzustellen, dass alles korrekt funktioniert.\n\n///\n\nStellen Sie sich das jetzt mit **vielen** anderen **Paketen** vor, von denen alle Ihre **Projekte abhängen**. Das ist sehr schwierig zu verwalten. Und Sie würden wahrscheinlich einige Projekte mit einigen **inkompatiblen Versionen** der Pakete ausführen und nicht wissen, warum etwas nicht funktioniert.\n\nDarüber hinaus könnte es je nach Ihrem Betriebssystem (z. B. Linux, Windows, macOS) bereits mit installiertem Python geliefert worden sein. Und in diesem Fall hatte es wahrscheinlich einige Pakete mit bestimmten Versionen **installiert**, die von Ihrem System benötigt werden. Wenn Sie Pakete in der globalen Python-Umgebung installieren, könnten Sie einige der Programme, die mit Ihrem Betriebssystem geliefert wurden, **kaputtmachen**.\n\n## Wo werden Pakete installiert { #where-are-packages-installed }\n\nWenn Sie Python installieren, werden einige Verzeichnisse mit einigen Dateien auf Ihrem Rechner erstellt.\n\nEinige dieser Verzeichnisse sind dafür zuständig, alle Pakete, die Sie installieren, aufzunehmen.\n\nWenn Sie ausführen:\n\n<div class=\"termy\">\n\n```console\n// Führen Sie dies jetzt nicht aus, es ist nur ein Beispiel 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\nDas lädt eine komprimierte Datei mit dem FastAPI-Code herunter, normalerweise von [PyPI](https://pypi.org/project/fastapi/).\n\nEs wird auch Dateien für andere Pakete **herunterladen**, von denen FastAPI abhängt.\n\nDann wird es all diese Dateien **extrahieren** und sie in ein Verzeichnis auf Ihrem Rechner legen.\n\nStandardmäßig werden diese heruntergeladenen und extrahierten Dateien in das Verzeichnis gelegt, das mit Ihrer Python-Installation kommt, das ist die **globale Umgebung**.\n\n## Was sind virtuelle Umgebungen { #what-are-virtual-environments }\n\nDie Lösung für die Probleme, alle Pakete in der globalen Umgebung zu haben, besteht darin, eine **virtuelle Umgebung für jedes Projekt** zu verwenden, an dem Sie arbeiten.\n\nEine virtuelle Umgebung ist ein **Verzeichnis**, sehr ähnlich zu dem globalen, in dem Sie die Pakete für ein Projekt installieren können.\n\nAuf diese Weise hat jedes Projekt seine eigene virtuelle Umgebung (`.venv`-Verzeichnis) mit seinen eigenen Paketen.\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone-Projekt]\n        stone(philosophers-stone) --->|benötigt| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban-Projekt]\n        azkaban(prisoner-of-azkaban) --->|benötigt| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## Was bedeutet das Aktivieren einer virtuellen Umgebung { #what-does-activating-a-virtual-environment-mean }\n\nWenn Sie eine virtuelle Umgebung aktivieren, zum Beispiel mit:\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nOder wenn Sie Bash für Windows verwenden (z. B. [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\nDieser Befehl erstellt oder ändert einige [Umgebungsvariablen](environment-variables.md), die für die nächsten Befehle verfügbar sein werden.\n\nEine dieser Variablen ist die `PATH`-Umgebungsvariable.\n\n/// tip | Tipp\n\nSie können mehr über die `PATH`-Umgebungsvariable im Abschnitt [Umgebungsvariablen](environment-variables.md#path-environment-variable) erfahren.\n\n///\n\nDas Aktivieren einer virtuellen Umgebung fügt deren Pfad `.venv/bin` (auf Linux und macOS) oder `.venv\\Scripts` (auf Windows) zur `PATH`-Umgebungsvariable hinzu.\n\nAngenommen, die `PATH`-Umgebungsvariable sah vor dem Aktivieren der Umgebung so aus:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nDas bedeutet, dass das System nach Programmen sucht in:\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\nDas bedeutet, dass das System nach Programmen sucht in:\n\n* `C:\\Windows\\System32`\n\n////\n\nNach dem Aktivieren der virtuellen Umgebung würde die `PATH`-Umgebungsvariable folgendermaßen aussehen:\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nDas bedeutet, dass das System nun zuerst nach Programmen sucht in:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\nbevor es in den anderen Verzeichnissen sucht.\n\nWenn Sie also `python` im Terminal eingeben, wird das System das Python-Programm in\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\nfinden und dieses verwenden.\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\nDas bedeutet, dass das System nun zuerst nach Programmen sucht in:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\nbevor es in den anderen Verzeichnissen sucht.\n\nWenn Sie also `python` im Terminal eingeben, wird das System das Python-Programm in\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\nfinden und dieses verwenden.\n\n////\n\nEin wichtiger Punkt ist, dass es den Pfad der virtuellen Umgebung am **Anfang** der `PATH`-Umgebungsvariable platziert. Das System wird es **vor** allen anderen verfügbaren Pythons finden. Auf diese Weise, wenn Sie `python` ausführen, wird das Python **aus der virtuellen Umgebung** verwendet anstelle eines anderen `python` (zum Beispiel, einem `python` aus einer globalen Umgebung).\n\nDas Aktivieren einer virtuellen Umgebung ändert auch ein paar andere Dinge, aber dies ist eines der wichtigsten Dinge, die es tut.\n\n## Testen einer virtuellen Umgebung { #checking-a-virtual-environment }\n\nWenn Sie testen, ob eine virtuelle Umgebung aktiv ist, zum Beispiel mit:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\nbedeutet das, dass das `python`-Programm, das verwendet wird, das in der **virtuellen Umgebung** ist.\n\nSie verwenden `which` auf Linux und macOS und `Get-Command` in Windows PowerShell.\n\nSo funktioniert dieser Befehl: Er wird in der `PATH`-Umgebungsvariable nachsehen und **jeden Pfad in der Reihenfolge durchgehen**, um das Programm namens `python` zu finden. Sobald er es findet, wird er Ihnen **den Pfad** zu diesem Programm anzeigen.\n\nDer wichtigste Punkt ist, dass, wenn Sie `python` aufrufen, genau dieses „`python`“ ausgeführt wird.\n\nSo können Sie überprüfen, ob Sie sich in der richtigen virtuellen Umgebung befinden.\n\n/// tip | Tipp\n\nEs ist einfach, eine virtuelle Umgebung zu aktivieren, ein Python zu bekommen und dann **zu einem anderen Projekt zu wechseln**.\n\nUnd das zweite Projekt **würde nicht funktionieren**, weil Sie das **falsche Python** verwenden, aus einer virtuellen Umgebung für ein anderes Projekt.\n\nEs ist nützlich, überprüfen zu können, welches `python` verwendet wird. 🤓\n\n///\n\n## Warum eine virtuelle Umgebung deaktivieren { #why-deactivate-a-virtual-environment }\n\nZum Beispiel könnten Sie an einem Projekt `philosophers-stone` arbeiten, diese virtuelle Umgebung **aktivieren**, Pakete installieren und mit dieser Umgebung arbeiten.\n\nUnd dann möchten Sie an **einem anderen Projekt** `prisoner-of-azkaban` arbeiten.\n\nSie gehen zu diesem Projekt:\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\nWenn Sie die virtuelle Umgebung für `philosophers-stone` nicht deaktivieren, wird beim Ausführen von `python` im Terminal versucht, das Python von `philosophers-stone` zu verwenden.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// Fehler beim Importieren von sirius, es ist nicht installiert 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\nWenn Sie jedoch die virtuelle Umgebung deaktivieren und die neue für `prisoner-of-askaban` aktivieren, wird beim Ausführen von `python` das Python aus der virtuellen Umgebung in `prisoner-of-azkaban` verwendet.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// Sie müssen nicht im alten Verzeichnis sein, um zu deaktivieren, Sie können dies überall tun, sogar nachdem Sie zum anderen Projekt gewechselt haben 😎\n$ deactivate\n\n// Die virtuelle Umgebung in prisoner-of-azkaban/.venv 🚀 aktivieren\n$ source .venv/bin/activate\n\n// Jetzt, wenn Sie python ausführen, wird das Paket sirius in dieser virtuellen Umgebung gefunden ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## Alternativen { #alternatives }\n\nDies ist ein einfacher Leitfaden, um Ihnen den Einstieg zu erleichtern und Ihnen beizubringen, wie alles **unter der Haube** funktioniert.\n\nEs gibt viele **Alternativen** zur Verwaltung von virtuellen Umgebungen, Paketabhängigkeiten (Anforderungen), Projekten.\n\nSobald Sie bereit sind und ein Tool verwenden möchten, das **das gesamte Projekt verwaltet**, Paketabhängigkeiten, virtuelle Umgebungen usw., würde ich Ihnen vorschlagen, [uv](https://github.com/astral-sh/uv) auszuprobieren.\n\n`uv` kann viele Dinge tun, es kann:\n\n* **Python für Sie installieren**, einschließlich verschiedener Versionen\n* Die **virtuelle Umgebung** für Ihre Projekte verwalten\n* **Pakete installieren**\n* Paket**abhängigkeiten und Versionen** für Ihr Projekt verwalten\n* Sicherstellen, dass Sie eine **exakte** Menge an Paketen und Versionen zur Installation haben, einschließlich ihrer Abhängigkeiten, damit Sie sicher sein können, dass Sie Ihr Projekt in der Produktionsumgebung genauso ausführen können wie auf Ihrem Rechner während der Entwicklung, dies wird **Locking** genannt\n* Und viele andere Dinge\n\n## Fazit { #conclusion }\n\nWenn Sie das alles gelesen und verstanden haben, wissen Sie jetzt **viel mehr** über virtuelle Umgebungen als viele Entwickler da draußen. 🤓\n\nDas Wissen über diese Details wird in Zukunft wahrscheinlich nützlich sein, wenn Sie etwas debuggen, das komplex erscheint, aber Sie werden wissen, **wie alles unter der Haube funktioniert**. 😎\n"
  },
  {
    "path": "docs/de/llm-prompt.md",
    "content": "### Target language\n\nTranslate to German (Deutsch).\n\nLanguage code: de.\n\n### Grammar to use when talking to the reader\n\nUse the formal grammar (use `Sie` instead of `Du`).\n\n### Quotes\n\n1) Convert neutral double quotes (`\"`) to German double typographic quotes (`„` and `“`). Convert neutral single quotes (`'`) to German single typographic quotes (`‚` and `‘`).\n\nDo NOT convert quotes in code snippets and code blocks to their German typographic equivalents.\n\nExamples:\n\nSource (English):\n\n```\n\"Hello world\"\n“Hello Universe”\n\"He said: 'Hello'\"\n“my name is ‘Nils’”\n`\"__main__\"`\n`\"items\"`\n```\n\nResult (German):\n\n```\n„Hallo Welt“\n„Hallo Universum“\n„Er sagte: ‚Hallo‘“\n„Mein Name ist ‚Nils‘“\n`\"__main__\"`\n`\"items\"`\n```\n\n### Ellipsis\n\n- Make sure there is a space between an ellipsis and a word following or preceding the ellipsis.\n\nExamples:\n\nSource (English):\n\n```\n...as we intended.\n...this would work:\n...etc.\nothers...\nMore to come...\n```\n\nResult (German):\n\n```\n... wie wir es beabsichtigt hatten.\n... das würde funktionieren:\n... usw.\nAndere ...\nSpäter mehr ...\n```\n\n- This does not apply in URLs, code blocks, and code snippets. Do not remove or add spaces there.\n\n### Headings\n\n- Translate headings using the infinite form.\n\nExamples:\n\nSource (English):\n\n```\n## Create a Project { #create-a-project }\n```\n\nResult (German):\n\n```\n## Ein Projekt erstellen { #create-a-project }\n```\n\nDo NOT translate with (German):\n\n```\n## Erstellen Sie ein Projekt { #create-a-project }\n```\n\nSource (English):\n\n```\n# Install Packages { #install-packages }\n```\n\nTranslate with (German):\n\n```\n# Pakete installieren { #install-packages }\n```\n\nDo NOT translate with (German):\n\n```\n# Installieren Sie Pakete { #install-packages }\n```\n\nSource (English):\n\n```\n### Run Your Program { #run-your-program }\n```\n\nTranslate with (German):\n\n```\n### Ihr Programm ausführen { #run-your-program }\n```\n\nDo NOT translate with (German):\n\n```\n### Führen Sie Ihr Programm aus { #run-your-program }\n```\n\n- Make sure that the translated part of the heading does not end with a period.\n\nExample:\n\nSource (English):\n\n```\n## Another module with `APIRouter` { #another-module-with-apirouter }\n```\n\nTranslate with (German):\n\n```\n## Ein weiteres Modul mit `APIRouter` { #another-module-with-apirouter }\n```\n\nDo NOT translate with (German) – notice the added period:\n\n```\n## Ein weiteres Modul mit `APIRouter`. { #another-module-with-apirouter }\n```\n\n- Replace occurrences of literal ` - ` (a space followed by a hyphen followed by a space) with ` – ` (a space followed by a dash followed by a space) in the translated part of the heading.\n\nExample:\n\nSource (English):\n\n```\n# FastAPI in Containers - Docker { #fastapi-in-containers-docker }\n```\n\nTranslate with (German) – notice the dash:\n\n```\n# FastAPI in Containern – Docker { #fastapi-in-containers-docker }\n```\n\nDo NOT translate with (German) – notice the hyphen:\n\n```\n# FastAPI in Containern - Docker { #fastapi-in-containers-docker }\n```\n\n- Do not apply rule 3 when there is no space before or no space after the hyphen.\n\nExample:\n\nSource (English):\n\n```\n## Type hints and annotations { #type-hints-and-annotations }\n```\n\nTranslate with (German) - notice the hyphen:\n\n```\n## Typhinweise und -annotationen { #type-hints-and-annotations }\n```\n\nDo NOT translate with (German) - notice the dash:\n\n```\n## Typhinweise und –annotationen { #type-hints-and-annotations }\n```\n\n- Do not modify the hyphens in the content in headers inside of curly braces, which you shall not translate.\n\n### German instructions, when to use and when not to use hyphens in words (written in first person, which is you).\n\nIn der Regel versuche ich so weit wie möglich Worte zusammenzuschreiben, also ohne Bindestrich, es sei denn, es ist Konkretesding-Klassevondingen, etwa «Pydantic-Modell» (aber: «Datenbankmodell»), «Python-Modul» (aber: «Standardmodul»). Ich setze auch einen Bindestrich, wenn er die gleichen Buchstaben verbindet, etwa «Enum-Member», «Cloud-Dienst», «Template-Engine». Oder wenn das Wort sonst einfach zu lang wird, etwa, «Performance-Optimierung». Oder um etwas visuell besser zu dokumentieren, etwa «Pfadoperation-Dekorator»,  «Pfadoperation-Funktion».\n\n\n### German instructions about difficult to translate technical terms (written in first person, which is you)\n\nIch versuche nicht, alles einzudeutschen. Das bezieht sich besonders auf Begriffe aus dem Bereich der Programmierung. Ich wandele zwar korrekt in Großschreibung um und setze Bindestriche, wo notwendig, aber ansonsten lasse ich solch ein Wort unverändert. Beispielsweise wird aus dem englischen Wort «string» in der deutschen Übersetzung «String», aber nicht «Zeichenkette». Oder aus dem englischen Wort «request body» wird in der deutschen Übersetzung «Requestbody», aber nicht «Anfragekörper». Oder aus dem englischen «response» wird im Deutschen «Response», aber nicht «Antwort».\n\n### List of English terms and their preferred German translations\n\nBelow is a list of English terms and their preferred German translations, separated by a colon (:). Use these translations, do not use your own. If an existing translation does not use these terms, update it to use them. In the below list, a term or a translation may be followed by an explanation in brackets, which explains when to translate the term this way. If a translation is preceded by `NOT`, then that means: do NOT use this translation for this term. English nouns, starting with the word `the`, have the German genus – `der`, `die`, `das` – prepended to their German translation, to help you to grammatically decline them in the translation. They are given in singular case, unless they have `(plural)` attached, which means they are given in plural case. Verbs are given in the full infinitive – starting with the word `to`.\n\n* /// check: /// check | Testen\n* /// danger: /// danger | Gefahr\n* /// info: /// info | Info\n* /// note | Technical Details: /// note | Technische Details\n* /// note: /// note | Hinweis\n* /// tip: /// tip | Tipp\n* /// warning: /// warning | Achtung\n* you: Sie\n* your: Ihr\n* e.g: z. B.\n* etc.: usw.\n* ref: Ref.\n* the Tutorial - User guide: das Tutorial – Benutzerhandbuch\n* the Advanced User Guide: das Handbuch für fortgeschrittene Benutzer\n* the SQLModel docs: die SQLModel-Dokumentation\n* the docs: die Dokumentation (use singular case)\n* the env var: die Umgebungsvariable\n* the `PATH` environment variable: die `PATH`-Umgebungsvariable\n* the `PATH`: der `PATH`\n* the `requirements.txt`: die `requirements.txt`\n* the API Router: der API-Router\n* the Authorization-Header: der Autorisierungsheader\n* the `Authorization`-Header: der `Authorization`-Header\n* the background task: der Hintergrundtask\n* the button: der Button\n* the cloud provider: der Cloudanbieter\n* the CLI: Das CLI\n* the coverage: Die Testabdeckung\n* the command line interface: Das Kommandozeileninterface\n* the default value: der Defaultwert\n* the default value: NOT der Standardwert\n* the default declaration: die Default-Deklaration\n* the deployment: das Deployment\n* the dict: das Dict\n* the dictionary: das Dictionary\n* the enumeration: die Enumeration\n* the enum: das Enum\n* the engine: die Engine\n* the error response: die Error-Response\n* the event: das Event\n* the exception: die Exception\n* the exception handler: der Exceptionhandler\n* the form model: das Formularmodell\n* the form body: der Formularbody\n* the header: der Header\n* the headers (plural): die Header\n* in headers (plural): in Headern\n* the forwarded header: der Forwarded-Header\n* the lifespan event: das Lifespan-Event\n* the lock: der Lock\n* the locking: das Locking\n* the mobile application: die Mobile-Anwendung\n* the model object: das Modellobjekt\n* the mounting: das Mounten\n* mounted: gemountet\n* the origin: das Origin\n* the override: Die Überschreibung\n* the parameter: der Parameter\n* the parameters (plural): die Parameter\n* the function parameter: der Funktionsparameter\n* the default parameter: der Defaultparameter\n* the body parameter: der Body-Parameter\n* the request body parameter: der Requestbody-Parameter\n* the path parameter: der Pfad-Parameter\n* the query parameter: der Query-Parameter\n* the cookie parameter: der Cookie-Parameter\n* the header parameter: der Header-Parameter\n* the form parameter: der Formular-Parameter\n* the payload: die Payload\n* the performance: NOT die Performance\n* the query: die Query\n* the recap: die Zusammenfassung\n* the request (what the client sends to the server): der Request\n* the request body: der Requestbody\n* the request bodies (plural): die Requestbodys\n* the response (what the server sends back to the client): die Response\n* the return type: der Rückgabetyp\n* the return value: der Rückgabewert\n* the startup (the event of the app): der Startup\n* the shutdown (the event of the app): der Shutdown\n* the startup event: das Startup-Event\n* the shutdown event: das Shutdown-Event\n* the startup (of the server): das Hochfahren\n* the startup (the company): das Startup\n* the SDK: das SDK\n* the tag: der Tag\n* the type annotation: die Typannotation\n* the type hint: der Typhinweis\n* the wildcard: die Wildcard\n* the worker class: die Workerklasse\n* the worker class: NOT die Arbeiterklasse\n* the worker process: der Workerprozess\n* the worker process: NOT der Arbeiterprozess\n* to commit: committen\n* to deploy (in the cloud): deployen\n* to modify: ändern\n* to serve (an application): bereitstellen\n* to serve (a response): ausliefern\n* to serve: NOT bedienen\n* to upgrade: aktualisieren\n* to wrap: wrappen\n* to wrap: NOT hüllen\n* `foo` as a `type`: `foo` vom Typ `type`\n* `foo` as a `type`: `foo`, ein `type`\n* FastAPI's X: FastAPIs X\n* Starlette's Y: Starlettes Y\n* X is case-sensitive: Groß-/Klein­schrei­bung ist relevant in X\n* X is case-insensitive: Groß-/Klein­schrei­bung ist nicht relevant in X\n* standard Python: Standard-Python\n* deprecated: deprecatet\n\n\n### Other rules\n\nPreserve indentation. Keep emojis. Encode in utf-8. Use Linux line breaks (LF).\n"
  },
  {
    "path": "docs/de/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs/en/data/contributors.yml",
    "content": "tiangolo:\n  login: tiangolo\n  count: 942\n  avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4\n  url: https://github.com/tiangolo\ndependabot:\n  login: dependabot\n  count: 189\n  avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4\n  url: https://github.com/apps/dependabot\nYuriiMotov:\n  login: YuriiMotov\n  count: 70\n  avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4\n  url: https://github.com/YuriiMotov\nalejsdev:\n  login: alejsdev\n  count: 56\n  avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=0facffe3abf87f57a1f05fa773d1119cc5c2f6a5&v=4\n  url: https://github.com/alejsdev\npre-commit-ci:\n  login: pre-commit-ci\n  count: 50\n  avatarUrl: https://avatars.githubusercontent.com/in/68672?v=4\n  url: https://github.com/apps/pre-commit-ci\ngithub-actions:\n  login: github-actions\n  count: 26\n  avatarUrl: https://avatars.githubusercontent.com/in/15368?v=4\n  url: https://github.com/apps/github-actions\nKludex:\n  login: Kludex\n  count: 25\n  avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4\n  url: https://github.com/Kludex\nsvlandeg:\n  login: svlandeg\n  count: 23\n  avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4\n  url: https://github.com/svlandeg\ndmontagu:\n  login: dmontagu\n  count: 17\n  avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4\n  url: https://github.com/dmontagu\nnilslindemann:\n  login: nilslindemann\n  count: 15\n  avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4\n  url: https://github.com/nilslindemann\neuri10:\n  login: euri10\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4\n  url: https://github.com/euri10\nkantandane:\n  login: kantandane\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/3978368?u=cccc199291f991a73b1ebba5abc735a948e0bd16&v=4\n  url: https://github.com/kantandane\nzhaohan-dong:\n  login: zhaohan-dong\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/65422392?u=8260f8781f50248410ebfa4c9bf70e143fe5c9f2&v=4\n  url: https://github.com/zhaohan-dong\nmariacamilagl:\n  login: mariacamilagl\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4\n  url: https://github.com/mariacamilagl\nhandabaldeep:\n  login: handabaldeep\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/12239103?u=6c39ef15d14c6d5211f5dd775cc4842f8d7f2f3a&v=4\n  url: https://github.com/handabaldeep\nvishnuvskvkl:\n  login: vishnuvskvkl\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/84698110?u=8af5de0520dd4fa195f53c2850a26f57c0f6bc64&v=4\n  url: https://github.com/vishnuvskvkl\nalissadb:\n  login: alissadb\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/96190409?u=be42d85938c241be781505a5a872575be28b2906&v=4\n  url: https://github.com/alissadb\nalv2017:\n  login: alv2017\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/31544722?v=4\n  url: https://github.com/alv2017\nwshayes:\n  login: wshayes\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4\n  url: https://github.com/wshayes\nsamuelcolvin:\n  login: samuelcolvin\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4\n  url: https://github.com/samuelcolvin\nwaynerv:\n  login: waynerv\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4\n  url: https://github.com/waynerv\nmusicinmybrain:\n  login: musicinmybrain\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/6898909?u=9010312053e7141383b9bdf538036c7f37fbaba0&v=4\n  url: https://github.com/musicinmybrain\nkrishnamadhavan:\n  login: krishnamadhavan\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/31798870?u=950693b28f3ae01105fd545c046e46ca3d31ab06&v=4\n  url: https://github.com/krishnamadhavan\njekirl:\n  login: jekirl\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/2546697?u=a027452387d85bd4a14834e19d716c99255fb3b7&v=4\n  url: https://github.com/jekirl\nhitrust:\n  login: hitrust\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/3360631?u=5fa1f475ad784d64eb9666bdd43cc4d285dcc773&v=4\n  url: https://github.com/hitrust\nShahriyarR:\n  login: ShahriyarR\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/3852029?u=2dc6402d9053ee53f7afc407089cbab21c68f21d&v=4\n  url: https://github.com/ShahriyarR\nadriangb:\n  login: adriangb\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4\n  url: https://github.com/adriangb\niudeen:\n  login: iudeen\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=f09cdd745e5bf16138f29b42732dd57c7f02bee1&v=4\n  url: https://github.com/iudeen\nphilipokiokio:\n  login: philipokiokio\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/55271518?u=d30994d339aaaf1f6bf1b8fc810132016fbd4fdc&v=4\n  url: https://github.com/philipokiokio\nAlexWendland:\n  login: AlexWendland\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/3949212?u=c4c0c615e0ea33d00bfe16b779cf6ebc0f58071c&v=4\n  url: https://github.com/AlexWendland\nvalentinDruzhinin:\n  login: valentinDruzhinin\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4\n  url: https://github.com/valentinDruzhinin\ndivums:\n  login: divums\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/1397556?v=4\n  url: https://github.com/divums\nprostomarkeloff:\n  login: prostomarkeloff\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=6918e39a1224194ba636e897461a02a20126d7ad&v=4\n  url: https://github.com/prostomarkeloff\nfrankie567:\n  login: frankie567\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=f3e79acfe4ed207e15c2145161a8a9759925fcd2&v=4\n  url: https://github.com/frankie567\nnsidnev:\n  login: nsidnev\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4\n  url: https://github.com/nsidnev\npawamoy:\n  login: pawamoy\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4\n  url: https://github.com/pawamoy\npatrickmckenna:\n  login: patrickmckenna\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/3589536?u=53aef07250d226d35e526768e26891964907b41a&v=4\n  url: https://github.com/patrickmckenna\nhukkin:\n  login: hukkin\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/3275109?u=77bb83759127965eacbfe67e2ca983066e964fde&v=4\n  url: https://github.com/hukkin\nmarcosmmb:\n  login: marcosmmb\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/6181089?u=03c50eec631857d84df5232890780d00a3f76903&v=4\n  url: https://github.com/marcosmmb\nSerrones:\n  login: Serrones\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4\n  url: https://github.com/Serrones\nuriyyo:\n  login: uriyyo\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/32038156?u=c26ca9b821fcf6499b84db75f553d4980bf8d023&v=4\n  url: https://github.com/uriyyo\nandrew222651:\n  login: andrew222651\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/889657?u=d70187989940b085bcbfa3bedad8dbc5f3ab1fe7&v=4\n  url: https://github.com/andrew222651\nrkbeatss:\n  login: rkbeatss\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/23391143?u=56ab6bff50be950fa8cae5cf736f2ae66e319ff3&v=4\n  url: https://github.com/rkbeatss\nasheux:\n  login: asheux\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/22955146?u=4553ebf5b5a7c7fe031a46182083aa224faba2e1&v=4\n  url: https://github.com/asheux\nblkst8:\n  login: blkst8\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/49960770?u=7d8a6d5f0a75a5e9a865a2527edfd48895ea27ae&v=4\n  url: https://github.com/blkst8\nghandic:\n  login: ghandic\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4\n  url: https://github.com/ghandic\nTeoZosa:\n  login: TeoZosa\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/13070236?u=96fdae85800ef85dcfcc4b5f8281dc8778c8cb7d&v=4\n  url: https://github.com/TeoZosa\ngraingert:\n  login: graingert\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/413772?v=4\n  url: https://github.com/graingert\njaystone776:\n  login: jaystone776\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4\n  url: https://github.com/jaystone776\nzanieb:\n  login: zanieb\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/2586601?u=e5c86f7ff3b859e7e183187ac2b17fd6ee32b3ab&v=4\n  url: https://github.com/zanieb\nMicaelJarniac:\n  login: MicaelJarniac\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/19514231?u=158c91874ea98d6e9e6f0c6db37ee2ce60c55ff2&v=4\n  url: https://github.com/MicaelJarniac\npapb:\n  login: papb\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/20914054?u=890511fae7ea90d887e2a65ce44a1775abba38d5&v=4\n  url: https://github.com/papb\ntamird:\n  login: tamird\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/1535036?v=4\n  url: https://github.com/tamird\nNimitha-jagadeesha:\n  login: Nimitha-jagadeesha\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/58389915?v=4\n  url: https://github.com/Nimitha-jagadeesha\nlucaromagnoli:\n  login: lucaromagnoli\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/38782977?u=a09a2e916625fa035f9dfa25ebc58e07aac8ec36&v=4\n  url: https://github.com/lucaromagnoli\nsalmantec:\n  login: salmantec\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/41512228?u=443551b893ff2425c59d5d021644f098cf7c68d5&v=4\n  url: https://github.com/salmantec\nOCE1960:\n  login: OCE1960\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/45076670?u=0e9a44712b92ffa89ddfbaa83c112f3f8e1d68e2&v=4\n  url: https://github.com/OCE1960\nhamidrasti:\n  login: hamidrasti\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/43915620?v=4\n  url: https://github.com/hamidrasti\nkkinder:\n  login: kkinder\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1115018?u=c5e90284a9f5c5049eae1bb029e3655c7dc913ed&v=4\n  url: https://github.com/kkinder\nkabirkhan:\n  login: kabirkhan\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/13891834?u=e0eabf792376443ac853e7dca6f550db4166fe35&v=4\n  url: https://github.com/kabirkhan\nzamiramir:\n  login: zamiramir\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/40475662?v=4\n  url: https://github.com/zamiramir\ntrim21:\n  login: trim21\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/13553903?u=3cadf0f02095c9621aa29df6875f53a80ca4fbfb&v=4\n  url: https://github.com/trim21\nkoxudaxi:\n  login: koxudaxi\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4\n  url: https://github.com/koxudaxi\npablogamboa:\n  login: pablogamboa\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/12892536?u=326a57059ee0c40c4eb1b38413957236841c631b&v=4\n  url: https://github.com/pablogamboa\ndconathan:\n  login: dconathan\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/15098095?v=4\n  url: https://github.com/dconathan\nJamim:\n  login: Jamim\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/5607572?u=9ce0b6a6d1a5124e28b3c04d8d26827ca328713a&v=4\n  url: https://github.com/Jamim\nsvalouch:\n  login: svalouch\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/54674660?v=4\n  url: https://github.com/svalouch\nmarier-nico:\n  login: marier-nico\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/30477068?u=c7df6af853c8f4163d1517814f3e9a0715c82713&v=4\n  url: https://github.com/marier-nico\nDustyposa:\n  login: Dustyposa\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4\n  url: https://github.com/Dustyposa\naviramha:\n  login: aviramha\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/41201924?u=ce5d3ea7037c2e6b3f82eff87e2217d4fb63214b&v=4\n  url: https://github.com/aviramha\niwpnd:\n  login: iwpnd\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6152183?u=ec59396e9437fff488791c5ecdf6d23f1f1ebf3a&v=4\n  url: https://github.com/iwpnd\nraphaelauv:\n  login: raphaelauv\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4\n  url: https://github.com/raphaelauv\nwindson:\n  login: windson\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1826682?u=8b28dcd716c46289f191f8828e01d74edd058bef&v=4\n  url: https://github.com/windson\nsm-Fifteen:\n  login: sm-Fifteen\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4\n  url: https://github.com/sm-Fifteen\nsattosan:\n  login: sattosan\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/20574756?u=b0d8474d2938189c6954423ae8d81d91013f80a8&v=4\n  url: https://github.com/sattosan\nmichaeloliverx:\n  login: michaeloliverx\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/55017335?u=efb0cb6e261ff64d862fafb91ee80fc2e1f8a2ed&v=4\n  url: https://github.com/michaeloliverx\nvoegtlel:\n  login: voegtlel\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/5764745?u=db8df3d70d427928ab6d7dbfc395a4a7109c1d1b&v=4\n  url: https://github.com/voegtlel\nHarshaLaxman:\n  login: HarshaLaxman\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/19939186?u=a112f38b0f6b4d4402dc8b51978b5a0b2e5c5970&v=4\n  url: https://github.com/HarshaLaxman\nRunningIkkyu:\n  login: RunningIkkyu\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4\n  url: https://github.com/RunningIkkyu\ncassiobotaro:\n  login: cassiobotaro\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=a08022b191ddbd0a6159b2981d9d878b6d5bb71f&v=4\n  url: https://github.com/cassiobotaro\nchenl:\n  login: chenl\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1677651?u=c618508eaad6d596cea36c8ea784b424288f6857&v=4\n  url: https://github.com/chenl\nretnikt:\n  login: retnikt\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4\n  url: https://github.com/retnikt\nyankeexe:\n  login: yankeexe\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/13623913?u=f970e66421775a8d3cdab89c0c752eaead186f6d&v=4\n  url: https://github.com/yankeexe\npatrickkwang:\n  login: patrickkwang\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1263870?u=4bf74020e15be490f19ef8322a76eec882220b96&v=4\n  url: https://github.com/patrickkwang\nvictorphoenix3:\n  login: victorphoenix3\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/48182195?u=e4875bd088623cb4ddeb7be194ec54b453aff035&v=4\n  url: https://github.com/victorphoenix3\ndavidefiocco:\n  login: davidefiocco\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/4547987?v=4\n  url: https://github.com/davidefiocco\nadriencaccia:\n  login: adriencaccia\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/19605940?u=9a59081f46bfc9d839886a49d5092cf572879049&v=4\n  url: https://github.com/adriencaccia\njamescurtin:\n  login: jamescurtin\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/10189269?u=0b491fc600ca51f41cf1d95b49fa32a3eba1de57&v=4\n  url: https://github.com/jamescurtin\njmriebold:\n  login: jmriebold\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6983392?u=4efdc97bf2422dcc7e9ff65b9ff80087c8eb2a20&v=4\n  url: https://github.com/jmriebold\nnukopy:\n  login: nukopy\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/42367320?u=6061be0bd060506f6d564a8df3ae73fab048cdfe&v=4\n  url: https://github.com/nukopy\nimba-tjd:\n  login: imba-tjd\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/24759802?u=01e901a4fe004b4b126549d3ff1c4000fe3720b5&v=4\n  url: https://github.com/imba-tjd\njohnthagen:\n  login: johnthagen\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/10340167?u=47147fc4e4db1f573bee3fe428deeacb3197bc5f&v=4\n  url: https://github.com/johnthagen\npaxcodes:\n  login: paxcodes\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/13646646?u=e7429cc7ab11211ef762f4cd3efea7db6d9ef036&v=4\n  url: https://github.com/paxcodes\nkaustubhgupta:\n  login: kaustubhgupta\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/43691873?u=8dd738718ac7ffad4ef31e86b5d780a1141c695d&v=4\n  url: https://github.com/kaustubhgupta\nkinuax:\n  login: kinuax\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/13321374?u=22dc9873d6d9f2c7e4fc44c6480c3505efb1531f&v=4\n  url: https://github.com/kinuax\nwakabame:\n  login: wakabame\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/35513518?u=41ef6b0a55076e5c540620d68fb006e386c2ddb0&v=4\n  url: https://github.com/wakabame\nnzig:\n  login: nzig\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/7372858?u=e769add36ed73c778cdb136eb10bf96b1e119671&v=4\n  url: https://github.com/nzig\nkristjanvalur:\n  login: kristjanvalur\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6009543?u=1419f20bbfff8f031be8cb470962e7e62de2595e&v=4\n  url: https://github.com/kristjanvalur\nyezz123:\n  login: yezz123\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=21b53ce4115062b1e20cb513e64ca0000c2ef127&v=4\n  url: https://github.com/yezz123\nsoftwarebloat:\n  login: softwarebloat\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/16540684?v=4\n  url: https://github.com/softwarebloat\nLancetnik:\n  login: Lancetnik\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/44573917?u=6eaa0cdd35259fba40a76b82e4903440cba03fa9&v=4\n  url: https://github.com/Lancetnik\njoakimnordling:\n  login: joakimnordling\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6637576?u=df5d99db9b899b399effd429f4358baaa6f7199c&v=4\n  url: https://github.com/joakimnordling\nAhsanSheraz:\n  login: AhsanSheraz\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/51913596?u=b5aa3c3a004cc0112e56c54f6901941836d8c26b&v=4\n  url: https://github.com/AhsanSheraz\nyogabonito:\n  login: yogabonito\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/7026269?v=4\n  url: https://github.com/yogabonito\ns111d:\n  login: s111d\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/4954856?v=4\n  url: https://github.com/s111d\nestebanx64:\n  login: estebanx64\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/10840422?u=2ca073ee47a625e495a9573bd374ddcd7be5ec91&v=4\n  url: https://github.com/estebanx64\nndimares:\n  login: ndimares\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6267663?u=cfb27efde7a7212be8142abb6c058a1aeadb41b1&v=4\n  url: https://github.com/ndimares\nrabinlamadong:\n  login: rabinlamadong\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/170439781?v=4\n  url: https://github.com/rabinlamadong\nAyushSinghal1794:\n  login: AyushSinghal1794\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/89984761?v=4\n  url: https://github.com/AyushSinghal1794\ngsheni:\n  login: gsheni\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/8726321?u=ee3bd9ff6320f4715d1dd9671a3d55cccb65b984&v=4\n  url: https://github.com/gsheni\nchailandau:\n  login: chailandau\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/112015853?u=2e6aaf2b1647db43834aabeae8d8282b4ec01873&v=4\n  url: https://github.com/chailandau\nDanielKusyDev:\n  login: DanielKusyDev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/36250676?u=411f1f5923596480b896d160e23c908318f39003&v=4\n  url: https://github.com/DanielKusyDev\nViicos:\n  login: Viicos\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/65306057?u=fcd677dc1b9bef12aa103613e5ccb3f8ce305af9&v=4\n  url: https://github.com/Viicos\nDanielYang59:\n  login: DanielYang59\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/80093591?u=63873f701c7c74aac83c906800a1dddc0bc8c92f&v=4\n  url: https://github.com/DanielYang59\nblueswen:\n  login: blueswen\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1564148?u=6d6b8cc8f2b5cef715e68d6175154a8a94d518ee&v=4\n  url: https://github.com/blueswen\nTaoup:\n  login: Taoup\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/22348542?v=4\n  url: https://github.com/Taoup\nsavannahostrowski:\n  login: savannahostrowski\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/8949415?u=e4bb61b9ebaa406274d2f2629cd33179a432a2a7&v=4\n  url: https://github.com/savannahostrowski\njonathan-fulton:\n  login: jonathan-fulton\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/4665111?u=bda1c12e5137bd7771a6aa24d9515b87c11da150&v=4\n  url: https://github.com/jonathan-fulton\n"
  },
  {
    "path": "docs/en/data/github_sponsors.yml",
    "content": "sponsors:\n- - login: renderinc\n    avatarUrl: https://avatars.githubusercontent.com/u/36424661?v=4\n    url: https://github.com/renderinc\n  - login: subtotal\n    avatarUrl: https://avatars.githubusercontent.com/u/176449348?v=4\n    url: https://github.com/subtotal\n  - login: greptileai\n    avatarUrl: https://avatars.githubusercontent.com/u/140149887?v=4\n    url: https://github.com/greptileai\n  - login: coderabbitai\n    avatarUrl: https://avatars.githubusercontent.com/u/132028505?v=4\n    url: https://github.com/coderabbitai\n  - login: zuplo\n    avatarUrl: https://avatars.githubusercontent.com/u/85497839?v=4\n    url: https://github.com/zuplo\n  - login: blockbee-io\n    avatarUrl: https://avatars.githubusercontent.com/u/115143449?u=1b8620c2d6567c4df2111a371b85a51f448f9b85&v=4\n    url: https://github.com/blockbee-io\n  - login: andrew-propelauth\n    avatarUrl: https://avatars.githubusercontent.com/u/89474256?u=c98993dec8553c09d424ede67bbe86e5c35f48c9&v=4\n    url: https://github.com/andrew-propelauth\n  - login: railwayapp\n    avatarUrl: https://avatars.githubusercontent.com/u/66716858?v=4\n    url: https://github.com/railwayapp\n- - login: speakeasy-api\n    avatarUrl: https://avatars.githubusercontent.com/u/91446104?v=4\n    url: https://github.com/speakeasy-api\n  - login: stainless-api\n    avatarUrl: https://avatars.githubusercontent.com/u/88061651?v=4\n    url: https://github.com/stainless-api\n  - login: svix\n    avatarUrl: https://avatars.githubusercontent.com/u/80175132?v=4\n    url: https://github.com/svix\n  - login: permitio\n    avatarUrl: https://avatars.githubusercontent.com/u/71775833?v=4\n    url: https://github.com/permitio\n  - login: databento\n    avatarUrl: https://avatars.githubusercontent.com/u/64141749?v=4\n    url: https://github.com/databento\n- - login: LambdaTest-Inc\n    avatarUrl: https://avatars.githubusercontent.com/u/171592363?u=96606606a45fa170427206199014f2a5a2a4920b&v=4\n    url: https://github.com/LambdaTest-Inc\n  - login: Ponte-Energy-Partners\n    avatarUrl: https://avatars.githubusercontent.com/u/114745848?v=4\n    url: https://github.com/Ponte-Energy-Partners\n  - login: BoostryJP\n    avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4\n    url: https://github.com/BoostryJP\n  - login: acsone\n    avatarUrl: https://avatars.githubusercontent.com/u/7601056?v=4\n    url: https://github.com/acsone\n- - login: scalar\n    avatarUrl: https://avatars.githubusercontent.com/u/301879?v=4\n    url: https://github.com/scalar\n  - login: Trivie\n    avatarUrl: https://avatars.githubusercontent.com/u/8161763?v=4\n    url: https://github.com/Trivie\n- - login: takashi-yoneya\n    avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4\n    url: https://github.com/takashi-yoneya\n  - login: Doist\n    avatarUrl: https://avatars.githubusercontent.com/u/2565372?v=4\n    url: https://github.com/Doist\n- - login: mainframeindustries\n    avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4\n    url: https://github.com/mainframeindustries\n- - login: alixlahuec\n    avatarUrl: https://avatars.githubusercontent.com/u/29543316?u=44357eb2a93bccf30fb9d389b8befe94a3d00985&v=4\n    url: https://github.com/alixlahuec\n- - login: primer-io\n    avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4\n    url: https://github.com/primer-io\n- - login: upciti\n    avatarUrl: https://avatars.githubusercontent.com/u/43346262?v=4\n    url: https://github.com/upciti\n  - login: ChargeStorm\n    avatarUrl: https://avatars.githubusercontent.com/u/26000165?v=4\n    url: https://github.com/ChargeStorm\n  - login: ibrahimpelumi6142\n    avatarUrl: https://avatars.githubusercontent.com/u/113442282?v=4\n    url: https://github.com/ibrahimpelumi6142\n  - login: nilslindemann\n    avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4\n    url: https://github.com/nilslindemann\n- - login: samuelcolvin\n    avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4\n    url: https://github.com/samuelcolvin\n  - login: otosky\n    avatarUrl: https://avatars.githubusercontent.com/u/42260747?u=69d089387c743d89427aa4ad8740cfb34045a9e0&v=4\n    url: https://github.com/otosky\n  - login: ramonalmeidam\n    avatarUrl: https://avatars.githubusercontent.com/u/45269580?u=3358750b3a5854d7c3ed77aaca7dd20a0f529d32&v=4\n    url: https://github.com/ramonalmeidam\n  - login: roboflow\n    avatarUrl: https://avatars.githubusercontent.com/u/53104118?v=4\n    url: https://github.com/roboflow\n  - login: dudikbender\n    avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=3a57542938ebfd57579a0111db2b297e606d9681&v=4\n    url: https://github.com/dudikbender\n  - login: ehaca\n    avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=cec1a3e0643b785288ae8260cc295a85ab344995&v=4\n    url: https://github.com/ehaca\n  - login: raphaellaude\n    avatarUrl: https://avatars.githubusercontent.com/u/28026311?u=91e1c00d9ac4f8045527e13de8050d504531cbc0&v=4\n    url: https://github.com/raphaellaude\n  - login: timlrx\n    avatarUrl: https://avatars.githubusercontent.com/u/28362229?u=9a745ca31372ee324af682715ae88ce8522f9094&v=4\n    url: https://github.com/timlrx\n  - login: Leay15\n    avatarUrl: https://avatars.githubusercontent.com/u/32212558?u=c4aa9c1737e515959382a5515381757b1fd86c53&v=4\n    url: https://github.com/Leay15\n  - login: jugeeem\n    avatarUrl: https://avatars.githubusercontent.com/u/116043716?u=ae590d79c38ac79c91b9c5caa6887d061e865a3d&v=4\n    url: https://github.com/jugeeem\n  - login: Karine-Bauch\n    avatarUrl: https://avatars.githubusercontent.com/u/90465103?u=7feb1018abb1a5631cfd9a91fea723d1ceb5f49b&v=4\n    url: https://github.com/Karine-Bauch\n  - login: kaoru0310\n    avatarUrl: https://avatars.githubusercontent.com/u/80977929?u=1b61d10142b490e56af932ddf08a390fae8ee94f&v=4\n    url: https://github.com/kaoru0310\n  - login: chickenandstats\n    avatarUrl: https://avatars.githubusercontent.com/u/79477966?u=ae2b894aa954070db1d7830dab99b49eba4e4567&v=4\n    url: https://github.com/chickenandstats\n  - login: patricioperezv\n    avatarUrl: https://avatars.githubusercontent.com/u/73832292?u=5f471f156e19ee7920e62ae0f4a47b95580e61cf&v=4\n    url: https://github.com/patricioperezv\n  - login: anthonycepeda\n    avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=60bdf46240cff8fca482ff0fc07d963fd5e1a27c&v=4\n    url: https://github.com/anthonycepeda\n  - login: AalbatrossGuy\n    avatarUrl: https://avatars.githubusercontent.com/u/68378354?u=0bdeea9356d24f638244131f6d8d1e2d2f3601ca&v=4\n    url: https://github.com/AalbatrossGuy\n  - login: patsatsia\n    avatarUrl: https://avatars.githubusercontent.com/u/61111267?u=3271b85f7a37b479c8d0ae0a235182e83c166edf&v=4\n    url: https://github.com/patsatsia\n  - login: oliverxchen\n    avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4\n    url: https://github.com/oliverxchen\n  - login: jaredtrog\n    avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4\n    url: https://github.com/jaredtrog\n  - login: Ryandaydev\n    avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=679ff84cb7b988c5795a5fa583857f574a055763&v=4\n    url: https://github.com/Ryandaydev\n  - login: gorhack\n    avatarUrl: https://avatars.githubusercontent.com/u/4141690?u=ec119ebc4bdf00a7bc84657a71aa17834f4f27f3&v=4\n    url: https://github.com/gorhack\n  - login: mj0331\n    avatarUrl: https://avatars.githubusercontent.com/u/3890353?u=1c627ac1a024515b4871de5c3ebbfaa1a57f65d4&v=4\n    url: https://github.com/mj0331\n  - login: anomaly\n    avatarUrl: https://avatars.githubusercontent.com/u/3654837?v=4\n    url: https://github.com/anomaly\n  - login: aacayaco\n    avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4\n    url: https://github.com/aacayaco\n  - login: kennywakeland\n    avatarUrl: https://avatars.githubusercontent.com/u/3631417?u=7c8f743f1ae325dfadea7c62bbf1abd6a824fc55&v=4\n    url: https://github.com/kennywakeland\n  - login: zsinx6\n    avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4\n    url: https://github.com/zsinx6\n  - login: dblackrun\n    avatarUrl: https://avatars.githubusercontent.com/u/3528486?v=4\n    url: https://github.com/dblackrun\n  - login: knallgelb\n    avatarUrl: https://avatars.githubusercontent.com/u/2358812?u=c48cb6362b309d74cbf144bd6ad3aed3eb443e82&v=4\n    url: https://github.com/knallgelb\n  - login: dodo5522\n    avatarUrl: https://avatars.githubusercontent.com/u/1362607?u=9bf1e0e520cccc547c046610c468ce6115bbcf9f&v=4\n    url: https://github.com/dodo5522\n  - login: mintuhouse\n    avatarUrl: https://avatars.githubusercontent.com/u/769950?u=ecfbd79a97d33177e0d093ddb088283cf7fe8444&v=4\n    url: https://github.com/mintuhouse\n  - login: falkben\n    avatarUrl: https://avatars.githubusercontent.com/u/653031?u=ad9838e089058c9e5a0bab94c0eec7cc181e0cd0&v=4\n    url: https://github.com/falkben\n  - login: koxudaxi\n    avatarUrl: https://avatars.githubusercontent.com/u/630670?u=507d8577b4b3670546b449c4c2ccbc5af40d72f7&v=4\n    url: https://github.com/koxudaxi\n  - login: wshayes\n    avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4\n    url: https://github.com/wshayes\n  - login: pamelafox\n    avatarUrl: https://avatars.githubusercontent.com/u/297042?v=4\n    url: https://github.com/pamelafox\n  - login: robintw\n    avatarUrl: https://avatars.githubusercontent.com/u/296686?v=4\n    url: https://github.com/robintw\n  - login: jstanden\n    avatarUrl: https://avatars.githubusercontent.com/u/63288?u=c3658d57d2862c607a0e19c2101c3c51876e36ad&v=4\n    url: https://github.com/jstanden\n  - login: RaamEEIL\n    avatarUrl: https://avatars.githubusercontent.com/u/20320552?v=4\n    url: https://github.com/RaamEEIL\n  - login: ashi-agrawal\n    avatarUrl: https://avatars.githubusercontent.com/u/17105294?u=99c7a854035e5398d8e7b674f2d42baae6c957f8&v=4\n    url: https://github.com/ashi-agrawal\n  - login: mjohnsey\n    avatarUrl: https://avatars.githubusercontent.com/u/16784016?u=38fad2e6b411244560b3af99c5f5a4751bc81865&v=4\n    url: https://github.com/mjohnsey\n  - login: khadrawy\n    avatarUrl: https://avatars.githubusercontent.com/u/13686061?u=59f25ef42ecf04c22657aac4238ce0e2d3d30304&v=4\n    url: https://github.com/khadrawy\n  - login: dannywade\n    avatarUrl: https://avatars.githubusercontent.com/u/13680237?u=418ee985bd41577b20fde81417fb2d901e875e8a&v=4\n    url: https://github.com/dannywade\n  - login: jsoques\n    avatarUrl: https://avatars.githubusercontent.com/u/12414216?u=620921d94196546cc8b9eae2cc4cbc3f95bab42f&v=4\n    url: https://github.com/jsoques\n  - login: wdwinslow\n    avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=371272f2c69e680e0559a7b0a57385e83a5dc728&v=4\n    url: https://github.com/wdwinslow\n  - login: hiancdtrsnm\n    avatarUrl: https://avatars.githubusercontent.com/u/7343177?v=4\n    url: https://github.com/hiancdtrsnm\n  - login: Rehket\n    avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4\n    url: https://github.com/Rehket\n  - login: FernandoCelmer\n    avatarUrl: https://avatars.githubusercontent.com/u/6262214?u=58ba6d5888fa7f355934e52db19f950e20b38162&v=4\n    url: https://github.com/FernandoCelmer\n  - login: eseglem\n    avatarUrl: https://avatars.githubusercontent.com/u/5920492?u=208d419cf667b8ac594c82a8db01932c7e50d057&v=4\n    url: https://github.com/eseglem\n  - login: ternaus\n    avatarUrl: https://avatars.githubusercontent.com/u/5481618?u=513a26b02a39e7a28d587cd37c6cc877ea368e6e&v=4\n    url: https://github.com/ternaus\n- - login: Artur-Galstyan\n    avatarUrl: https://avatars.githubusercontent.com/u/63471891?u=e8691f386037e51a737cc0ba866cd8c89e5cf109&v=4\n    url: https://github.com/Artur-Galstyan\n  - login: manoelpqueiroz\n    avatarUrl: https://avatars.githubusercontent.com/u/23669137?u=b12e84b28a84369ab5b30bd5a79e5788df5a0756&v=4\n    url: https://github.com/manoelpqueiroz\n- - login: pawamoy\n    avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4\n    url: https://github.com/pawamoy\n  - login: siavashyj\n    avatarUrl: https://avatars.githubusercontent.com/u/43583410?u=562005ddc7901cd27a1219a118a2363817b14977&v=4\n    url: https://github.com/siavashyj\n  - login: mobyw\n    avatarUrl: https://avatars.githubusercontent.com/u/44370805?v=4\n    url: https://github.com/mobyw\n  - login: ArtyomVancyan\n    avatarUrl: https://avatars.githubusercontent.com/u/44609997?v=4\n    url: https://github.com/ArtyomVancyan\n  - login: caviri\n    avatarUrl: https://avatars.githubusercontent.com/u/45425937?u=5f3d66ea5edea94c028c51ebf1c0f3b37e6c3db5&v=4\n    url: https://github.com/caviri\n  - login: hgalytoby\n    avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=6cc9028f3db63f8f60ad21c17b1ce4b88c4e2e60&v=4\n    url: https://github.com/hgalytoby\n  - login: johnl28\n    avatarUrl: https://avatars.githubusercontent.com/u/54412955?u=47dd06082d1c39caa90c752eb55566e4f3813957&v=4\n    url: https://github.com/johnl28\n  - login: danielunderwood\n    avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4\n    url: https://github.com/danielunderwood\n  - login: hoenie-ams\n    avatarUrl: https://avatars.githubusercontent.com/u/25708487?u=cda07434f0509ac728d9edf5e681117c0f6b818b&v=4\n    url: https://github.com/hoenie-ams\n  - login: joerambo\n    avatarUrl: https://avatars.githubusercontent.com/u/26282974?v=4\n    url: https://github.com/joerambo\n  - login: engineerjoe440\n    avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4\n    url: https://github.com/engineerjoe440\n  - login: bnkc\n    avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=4771ac4e64066f0847d40e5b29910adabd9b2372&v=4\n    url: https://github.com/bnkc\n  - login: petercool\n    avatarUrl: https://avatars.githubusercontent.com/u/37613029?u=75aa8c6729e6e8f85a300561c4dbeef9d65c8797&v=4\n    url: https://github.com/petercool\n  - login: PelicanQ\n    avatarUrl: https://avatars.githubusercontent.com/u/77930606?v=4\n    url: https://github.com/PelicanQ\n  - login: PunRabbit\n    avatarUrl: https://avatars.githubusercontent.com/u/70463212?u=1a835cfbc99295a60c8282f6aa6199d1b42241a5&v=4\n    url: https://github.com/PunRabbit\n  - login: my3\n    avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4\n    url: https://github.com/my3\n  - login: WillHogan\n    avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=8a80356e3e7d5a417157aba7ea565dabc8678327&v=4\n    url: https://github.com/WillHogan\n  - login: miguelgr\n    avatarUrl: https://avatars.githubusercontent.com/u/1484589?u=54556072b8136efa12ae3b6902032ea2a39ace4b&v=4\n    url: https://github.com/miguelgr\n  - login: tochikuji\n    avatarUrl: https://avatars.githubusercontent.com/u/851759?v=4\n    url: https://github.com/tochikuji\n  - login: ceb10n\n    avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4\n    url: https://github.com/ceb10n\n  - login: slafs\n    avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4\n    url: https://github.com/slafs\n  - login: bryanculbertson\n    avatarUrl: https://avatars.githubusercontent.com/u/144028?u=defda4f90e93429221cc667500944abde60ebe4a&v=4\n    url: https://github.com/bryanculbertson\n  - login: ddanier\n    avatarUrl: https://avatars.githubusercontent.com/u/113563?u=ed1dc79de72f93bd78581f88ebc6952b62f472da&v=4\n    url: https://github.com/ddanier\n  - login: nisutec\n    avatarUrl: https://avatars.githubusercontent.com/u/25281462?u=e562484c451fdfc59053163f64405f8eb262b8b0&v=4\n    url: https://github.com/nisutec\n  - login: joshuatz\n    avatarUrl: https://avatars.githubusercontent.com/u/17817563?u=f1bf05b690d1fc164218f0b420cdd3acb7913e21&v=4\n    url: https://github.com/joshuatz\n  - login: TheR1D\n    avatarUrl: https://avatars.githubusercontent.com/u/16740832?u=b0dfdbdb27b79729430c71c6128962f77b7b53f7&v=4\n    url: https://github.com/TheR1D\n  - login: Zuzah\n    avatarUrl: https://avatars.githubusercontent.com/u/10934846?u=1ef43e075ddc87bd1178372bf4d95ee6175cae27&v=4\n    url: https://github.com/Zuzah\n  - login: mntolia\n    avatarUrl: https://avatars.githubusercontent.com/u/10390224?v=4\n    url: https://github.com/mntolia\n  - login: hard-coders\n    avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4\n    url: https://github.com/hard-coders\n  - login: DMantis\n    avatarUrl: https://avatars.githubusercontent.com/u/9536869?u=652dd0d49717803c0cbcbf44f7740e53cf2d4892&v=4\n    url: https://github.com/DMantis\n  - login: xncbf\n    avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=a80a7bb349555b277645632ed66639ff43400614&v=4\n    url: https://github.com/xncbf\n  - login: moonape1226\n    avatarUrl: https://avatars.githubusercontent.com/u/8532038?u=d9f8b855a429fff9397c3833c2ff83849ebf989d&v=4\n    url: https://github.com/moonape1226\n  - login: harsh183\n    avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4\n    url: https://github.com/harsh183\n  - login: katnoria\n    avatarUrl: https://avatars.githubusercontent.com/u/7674948?u=09767eb13e07e09496c5fee4e5ce21d9eac34a56&v=4\n    url: https://github.com/katnoria\n  - login: KentShikama\n    avatarUrl: https://avatars.githubusercontent.com/u/6329898?u=8b236810db9b96333230430837e1f021f9246da1&v=4\n    url: https://github.com/KentShikama\n  - login: Baghdady92\n    avatarUrl: https://avatars.githubusercontent.com/u/5708590?v=4\n    url: https://github.com/Baghdady92\n  - login: sdevkota\n    avatarUrl: https://avatars.githubusercontent.com/u/5250987?u=4ed9a120c89805a8aefda1cbdc0cf6512e64d1b4&v=4\n    url: https://github.com/sdevkota\n  - login: rangulvers\n    avatarUrl: https://avatars.githubusercontent.com/u/5235430?u=e254d4af4ace5a05fa58372ae677c7d26f0d5a53&v=4\n    url: https://github.com/rangulvers\n- - login: KOZ39\n    avatarUrl: https://avatars.githubusercontent.com/u/38822500?u=9dfc0a697df1c9628f08e20dc3fb17b1afc4e5a7&v=4\n    url: https://github.com/KOZ39\n  - login: rwxd\n    avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4\n    url: https://github.com/rwxd\n  - login: morzan1001\n    avatarUrl: https://avatars.githubusercontent.com/u/47593005?u=c30ab7230f82a12a9b938dcb54f84a996931409a&v=4\n    url: https://github.com/morzan1001\n  - login: Olegt0rr\n    avatarUrl: https://avatars.githubusercontent.com/u/25399456?u=3e87b5239a2f4600975ba13be73054f8567c6060&v=4\n    url: https://github.com/Olegt0rr\n  - login: larsyngvelundin\n    avatarUrl: https://avatars.githubusercontent.com/u/34173819?u=74958599695bf83ac9f1addd935a51548a10c6b0&v=4\n    url: https://github.com/larsyngvelundin\n  - login: andrecorumba\n    avatarUrl: https://avatars.githubusercontent.com/u/37807517?u=9b9be3b41da9bda60957da9ef37b50dbf65baa61&v=4\n    url: https://github.com/andrecorumba\n  - login: CoderDeltaLAN\n    avatarUrl: https://avatars.githubusercontent.com/u/152043745?u=4ff541efffb7d134e60c5fcf2dd1e343f90bb782&v=4\n    url: https://github.com/CoderDeltaLAN\n  - login: hippoley\n    avatarUrl: https://avatars.githubusercontent.com/u/135493401?u=1164ef48a645a7c12664fabc1638fbb7e1c459b0&v=4\n    url: https://github.com/hippoley\n  - login: nayasinghania\n    avatarUrl: https://avatars.githubusercontent.com/u/74111380?u=752e99a5e139389fdc0a0677122adc08438eb076&v=4\n    url: https://github.com/nayasinghania\n  - login: onestn\n    avatarUrl: https://avatars.githubusercontent.com/u/62360849?u=746dd21c34e7e06eefb11b03e8bb01aaae3c2a4f&v=4\n    url: https://github.com/onestn\n  - login: Toothwitch\n    avatarUrl: https://avatars.githubusercontent.com/u/1710406?u=5eebb23b46cd26e48643b9e5179536cad491c17a&v=4\n    url: https://github.com/Toothwitch\n  - login: andreagrandi\n    avatarUrl: https://avatars.githubusercontent.com/u/636391?u=13d90cb8ec313593a5b71fbd4e33b78d6da736f5&v=4\n    url: https://github.com/andreagrandi\n  - login: msserpa\n    avatarUrl: https://avatars.githubusercontent.com/u/6334934?u=82c4489eb1559d88d2990d60001901b14f722bbb&v=4\n    url: https://github.com/msserpa\n"
  },
  {
    "path": "docs/en/data/members.yml",
    "content": "members:\n- login: tiangolo\n  avatar_url: https://avatars.githubusercontent.com/u/1326112\n  url: https://github.com/tiangolo\n- login: Kludex\n  avatar_url: https://avatars.githubusercontent.com/u/7353520\n  url: https://github.com/Kludex\n- login: alejsdev\n  avatar_url: https://avatars.githubusercontent.com/u/90076947\n  url: https://github.com/alejsdev\n- login: svlandeg\n  avatar_url: https://avatars.githubusercontent.com/u/8796347\n  url: https://github.com/svlandeg\n- login: YuriiMotov\n  avatar_url: https://avatars.githubusercontent.com/u/109919500\n  url: https://github.com/YuriiMotov\n- login: patrick91\n  avatar_url: https://avatars.githubusercontent.com/u/667029\n  url: https://github.com/patrick91\n- login: luzzodev\n  avatar_url: https://avatars.githubusercontent.com/u/27291415\n  url: https://github.com/luzzodev\n"
  },
  {
    "path": "docs/en/data/people.yml",
    "content": "maintainers:\n- login: tiangolo\n  answers: 1927\n  avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4\n  url: https://github.com/tiangolo\nexperts:\n- login: tiangolo\n  count: 1927\n  avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4\n  url: https://github.com/tiangolo\n- login: YuriiMotov\n  count: 1164\n  avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4\n  url: https://github.com/YuriiMotov\n- login: github-actions\n  count: 770\n  avatarUrl: https://avatars.githubusercontent.com/in/15368?v=4\n  url: https://github.com/apps/github-actions\n- login: Kludex\n  count: 657\n  avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4\n  url: https://github.com/Kludex\n- login: jgould22\n  count: 263\n  avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4\n  url: https://github.com/jgould22\n- login: dmontagu\n  count: 240\n  avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4\n  url: https://github.com/dmontagu\n- login: Mause\n  count: 219\n  avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4\n  url: https://github.com/Mause\n- login: ycd\n  count: 216\n  avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=f1e7bae394a315da950912c92dc861a8eaf95d4c&v=4\n  url: https://github.com/ycd\n- login: JarroVGIT\n  count: 192\n  avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4\n  url: https://github.com/JarroVGIT\n- login: euri10\n  count: 153\n  avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4\n  url: https://github.com/euri10\n- login: iudeen\n  count: 128\n  avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=f09cdd745e5bf16138f29b42732dd57c7f02bee1&v=4\n  url: https://github.com/iudeen\n- login: phy25\n  count: 126\n  avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4\n  url: https://github.com/phy25\n- login: JavierSanchezCastro\n  count: 109\n  avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4\n  url: https://github.com/JavierSanchezCastro\n- login: luzzodev\n  count: 107\n  avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4\n  url: https://github.com/luzzodev\n- login: raphaelauv\n  count: 83\n  avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4\n  url: https://github.com/raphaelauv\n- login: ArcLightSlavik\n  count: 71\n  avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4\n  url: https://github.com/ArcLightSlavik\n- login: ghandic\n  count: 71\n  avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4\n  url: https://github.com/ghandic\n- login: n8sty\n  count: 67\n  avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4\n  url: https://github.com/n8sty\n- login: falkben\n  count: 59\n  avatarUrl: https://avatars.githubusercontent.com/u/653031?u=ad9838e089058c9e5a0bab94c0eec7cc181e0cd0&v=4\n  url: https://github.com/falkben\n- login: yinziyan1206\n  count: 55\n  avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4\n  url: https://github.com/yinziyan1206\n- login: acidjunk\n  count: 50\n  avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4\n  url: https://github.com/acidjunk\n- login: sm-Fifteen\n  count: 49\n  avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4\n  url: https://github.com/sm-Fifteen\n- login: adriangb\n  count: 46\n  avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4\n  url: https://github.com/adriangb\n- login: insomnes\n  count: 45\n  avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4\n  url: https://github.com/insomnes\n- login: Dustyposa\n  count: 45\n  avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4\n  url: https://github.com/Dustyposa\n- login: frankie567\n  count: 43\n  avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=f3e79acfe4ed207e15c2145161a8a9759925fcd2&v=4\n  url: https://github.com/frankie567\n- login: odiseo0\n  count: 43\n  avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=75e754b9bd12ce6dfe90ad68e82e6f5255c7ac09&v=4\n  url: https://github.com/odiseo0\n- login: sinisaos\n  count: 41\n  avatarUrl: https://avatars.githubusercontent.com/u/30960668?v=4\n  url: https://github.com/sinisaos\n- login: includeamin\n  count: 40\n  avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4\n  url: https://github.com/includeamin\n- login: chbndrhnns\n  count: 37\n  avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4\n  url: https://github.com/chbndrhnns\n- login: STeveShary\n  count: 37\n  avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4\n  url: https://github.com/STeveShary\n- login: krishnardt\n  count: 35\n  avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4\n  url: https://github.com/krishnardt\n- login: panla\n  count: 32\n  avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4\n  url: https://github.com/panla\n- login: valentinDruzhinin\n  count: 30\n  avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4\n  url: https://github.com/valentinDruzhinin\n- login: prostomarkeloff\n  count: 28\n  avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=6918e39a1224194ba636e897461a02a20126d7ad&v=4\n  url: https://github.com/prostomarkeloff\n- login: alv2017\n  count: 27\n  avatarUrl: https://avatars.githubusercontent.com/u/31544722?v=4\n  url: https://github.com/alv2017\n- login: hasansezertasan\n  count: 27\n  avatarUrl: https://avatars.githubusercontent.com/u/13135006?u=d36995e41a00590da64e6204cfd112e0484ac1ca&v=4\n  url: https://github.com/hasansezertasan\n- login: dbanty\n  count: 26\n  avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9d726785d08e50b1e1cd96505800c8ea8405bce2&v=4\n  url: https://github.com/dbanty\n- login: wshayes\n  count: 25\n  avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4\n  url: https://github.com/wshayes\n- login: SirTelemak\n  count: 23\n  avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4\n  url: https://github.com/SirTelemak\n- login: connebs\n  count: 22\n  avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=e151d5f545a3395136d711c227c22032fda67cfa&v=4\n  url: https://github.com/connebs\n- login: nymous\n  count: 22\n  avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4\n  url: https://github.com/nymous\n- login: chrisK824\n  count: 22\n  avatarUrl: https://avatars.githubusercontent.com/u/79946379?u=03d85b22d696a58a9603e55fbbbe2de6b0f4face&v=4\n  url: https://github.com/chrisK824\n- login: ceb10n\n  count: 21\n  avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4\n  url: https://github.com/ceb10n\n- login: rafsaf\n  count: 21\n  avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=5fe59a56e1f2f9ccd8005d71752a8276f133ae1a&v=4\n  url: https://github.com/rafsaf\n- login: nsidnev\n  count: 20\n  avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4\n  url: https://github.com/nsidnev\n- login: chris-allnutt\n  count: 20\n  avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4\n  url: https://github.com/chris-allnutt\n- login: ebottos94\n  count: 20\n  avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=8b91053b3abe4a9209375e3651e1c1ef192d884b&v=4\n  url: https://github.com/ebottos94\n- login: estebanx64\n  count: 19\n  avatarUrl: https://avatars.githubusercontent.com/u/10840422?u=2ca073ee47a625e495a9573bd374ddcd7be5ec91&v=4\n  url: https://github.com/estebanx64\n- login: sehraramiz\n  count: 18\n  avatarUrl: https://avatars.githubusercontent.com/u/14166324?u=8fac65e84dfff24245d304a5b5b09f7b5bd69dc9&v=4\n  url: https://github.com/sehraramiz\n- login: retnikt\n  count: 18\n  avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4\n  url: https://github.com/retnikt\n- login: zoliknemet\n  count: 18\n  avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4\n  url: https://github.com/zoliknemet\n- login: caeser1996\n  count: 17\n  avatarUrl: https://avatars.githubusercontent.com/u/16540232?u=05d2beb8e034d584d0a374b99d8826327bd7f614&v=4\n  url: https://github.com/caeser1996\n- login: Hultner\n  count: 17\n  avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4\n  url: https://github.com/Hultner\n- login: harunyasar\n  count: 17\n  avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4\n  url: https://github.com/harunyasar\n- login: nkhitrov\n  count: 17\n  avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=e19427d8dc296d6950e9c424adacc92d37496fe9&v=4\n  url: https://github.com/nkhitrov\n- login: dstlny\n  count: 16\n  avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4\n  url: https://github.com/dstlny\n- login: pythonweb2\n  count: 16\n  avatarUrl: https://avatars.githubusercontent.com/u/32141163?v=4\n  url: https://github.com/pythonweb2\n- login: jonatasoli\n  count: 16\n  avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=f601c3f111f2148bd9244c2cb3ebbd57b592e674&v=4\n  url: https://github.com/jonatasoli\n- login: mattmess1221\n  count: 15\n  avatarUrl: https://avatars.githubusercontent.com/u/3409962?u=d22ea18aa8ea688af25a45df306134d593621a44&v=4\n  url: https://github.com/mattmess1221\nlast_month_experts:\n- login: YuriiMotov\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4\n  url: https://github.com/YuriiMotov\n- login: Firatasi\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/112112161?u=3219914a49a4a604b3626007823db7de049b6d66&v=4\n  url: https://github.com/Firatasi\n- login: ericgitangu\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/11472845?u=9d916cf0f5c80e63cb1d753b8b50dcb8ced3b883&v=4\n  url: https://github.com/ericgitangu\n- login: cookesan\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6601329?u=7bfc9b017198a9fa50929ae8ae0a787632424ffd&v=4\n  url: https://github.com/cookesan\n- login: coleifer\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/119974?u=b3a546c94ee1105e792e0acad2c4743d800e7975&v=4\n  url: https://github.com/coleifer\n- login: Bahtya\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/34988899?u=b8e3c0cf26f4bd1faea265d2f5f66f564af63463&v=4\n  url: https://github.com/Bahtya\n- login: luzzodev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4\n  url: https://github.com/luzzodev\n- login: DoctorJohn\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/14076775?u=ec43fe79a98dbc864b428afc7220753e25ca3af2&v=4\n  url: https://github.com/DoctorJohn\nthree_months_experts:\n- login: YuriiMotov\n  count: 74\n  avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4\n  url: https://github.com/YuriiMotov\n- login: Firatasi\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/112112161?u=3219914a49a4a604b3626007823db7de049b6d66&v=4\n  url: https://github.com/Firatasi\n- login: JavierSanchezCastro\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4\n  url: https://github.com/JavierSanchezCastro\n- login: Toygarmetu\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/92878791?u=538530cb6d5554e71f9c28709d794db9a74d23d9&v=4\n  url: https://github.com/Toygarmetu\n- login: tiangolo\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4\n  url: https://github.com/tiangolo\n- login: luzzodev\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4\n  url: https://github.com/luzzodev\n- login: ericgitangu\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/11472845?u=9d916cf0f5c80e63cb1d753b8b50dcb8ced3b883&v=4\n  url: https://github.com/ericgitangu\n- login: cookesan\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6601329?u=7bfc9b017198a9fa50929ae8ae0a787632424ffd&v=4\n  url: https://github.com/cookesan\n- login: coleifer\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/119974?u=b3a546c94ee1105e792e0acad2c4743d800e7975&v=4\n  url: https://github.com/coleifer\n- login: Bahtya\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/34988899?u=b8e3c0cf26f4bd1faea265d2f5f66f564af63463&v=4\n  url: https://github.com/Bahtya\n- login: saitarrun\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/116748905?u=3433afbaf06676a482ebf4ba33b08ddb3fc5c5bf&v=4\n  url: https://github.com/saitarrun\n- login: EmmanuelNiyonshuti\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/142030687?u=ab131d5ad4670280a978f489babe71c9bf9c1097&v=4\n  url: https://github.com/EmmanuelNiyonshuti\n- login: christiansousadev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/103544118?u=690f3f76d1dc4d0929de5020679d5604f860acbc&v=4\n  url: https://github.com/christiansousadev\n- login: DoctorJohn\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/14076775?u=ec43fe79a98dbc864b428afc7220753e25ca3af2&v=4\n  url: https://github.com/DoctorJohn\n- login: gaardhus\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/46934916?u=18d7aacc6ce59f054749209645d11cfe77b52f90&v=4\n  url: https://github.com/gaardhus\n- login: valentinDruzhinin\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4\n  url: https://github.com/valentinDruzhinin\nsix_months_experts:\n- login: YuriiMotov\n  count: 166\n  avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4\n  url: https://github.com/YuriiMotov\n- login: tiangolo\n  count: 23\n  avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4\n  url: https://github.com/tiangolo\n- login: JavierSanchezCastro\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4\n  url: https://github.com/JavierSanchezCastro\n- login: luzzodev\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4\n  url: https://github.com/luzzodev\n- login: Firatasi\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/112112161?u=3219914a49a4a604b3626007823db7de049b6d66&v=4\n  url: https://github.com/Firatasi\n- login: Toygarmetu\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/92878791?u=538530cb6d5554e71f9c28709d794db9a74d23d9&v=4\n  url: https://github.com/Toygarmetu\n- login: ceb10n\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4\n  url: https://github.com/ceb10n\n- login: JunjieAraoXiong\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/167785867?u=b69afe090c8bf5fd73f2d23fc3a887b28f68f192&v=4\n  url: https://github.com/JunjieAraoXiong\n- login: valentinDruzhinin\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4\n  url: https://github.com/valentinDruzhinin\n- login: krylosov-aa\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/242901957?u=4c9c7b468203b09bca64936fb464620e32cdd252&v=4\n  url: https://github.com/krylosov-aa\n- login: ericgitangu\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/11472845?u=9d916cf0f5c80e63cb1d753b8b50dcb8ced3b883&v=4\n  url: https://github.com/ericgitangu\n- login: EmmanuelNiyonshuti\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/142030687?u=ab131d5ad4670280a978f489babe71c9bf9c1097&v=4\n  url: https://github.com/EmmanuelNiyonshuti\n- login: sachinh35\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/21972708?u=8560b97b8b41e175f476270b56de8a493b84f302&v=4\n  url: https://github.com/sachinh35\n- login: RichieB2B\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/1461970?u=edaa57d1077705244ea5c9244f4783d94ff11f12&v=4\n  url: https://github.com/RichieB2B\n- login: cookesan\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6601329?u=7bfc9b017198a9fa50929ae8ae0a787632424ffd&v=4\n  url: https://github.com/cookesan\n- login: coleifer\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/119974?u=b3a546c94ee1105e792e0acad2c4743d800e7975&v=4\n  url: https://github.com/coleifer\n- login: Bahtya\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/34988899?u=b8e3c0cf26f4bd1faea265d2f5f66f564af63463&v=4\n  url: https://github.com/Bahtya\n- login: saitarrun\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/116748905?u=3433afbaf06676a482ebf4ba33b08ddb3fc5c5bf&v=4\n  url: https://github.com/saitarrun\n- login: cepedus\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/26345924?u=38495abbdbb8695dd76478cae5963bf994c498bc&v=4\n  url: https://github.com/cepedus\n- login: christiansousadev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/103544118?u=690f3f76d1dc4d0929de5020679d5604f860acbc&v=4\n  url: https://github.com/christiansousadev\n- login: DoctorJohn\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/14076775?u=ec43fe79a98dbc864b428afc7220753e25ca3af2&v=4\n  url: https://github.com/DoctorJohn\n- login: gaardhus\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/46934916?u=18d7aacc6ce59f054749209645d11cfe77b52f90&v=4\n  url: https://github.com/gaardhus\n- login: Kludex\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4\n  url: https://github.com/Kludex\n- login: y2kbugger\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6101677?u=1d50077e29582dc01fcbdff846f04fe7ec73fe2e&v=4\n  url: https://github.com/y2kbugger\n- login: davidbrochart\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/4711805?u=d39696d995a9e02ec3613ffb2f62b20b14f92f26&v=4\n  url: https://github.com/davidbrochart\n- login: CharlieReitzel\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/20848272?v=4\n  url: https://github.com/CharlieReitzel\n- login: dotmitsu\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/42657211?u=3bccc9a2f386a3f24230ec393080f8904fe2a5b2&v=4\n  url: https://github.com/dotmitsu\n- login: dolfinus\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/4661021?u=ed5ddadcf36d9b943ebe61febe0b96ee34e5425d&v=4\n  url: https://github.com/dolfinus\n- login: florentx\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/142113?u=bf10f10080026346b092633c380977b61cee0d9c&v=4\n  url: https://github.com/florentx\n- login: jc-louis\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/51329768?v=4\n  url: https://github.com/jc-louis\n- login: bughuntr7\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/236391583?u=7f51ff690e3a5711f845a115903c39e21c8af938&v=4\n  url: https://github.com/bughuntr7\n- login: CodeKraken-cmd\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/48470371?u=e7c0e7ec8e35ca5fb3ae40a586ed5e788fd0fe6d&v=4\n  url: https://github.com/CodeKraken-cmd\n- login: svlandeg\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4\n  url: https://github.com/svlandeg\n- login: jymchng\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/27895426?u=fb88c47775147d62a395fdb895d1af4148c7b566&v=4\n  url: https://github.com/jymchng\none_year_experts:\n- login: YuriiMotov\n  count: 951\n  avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4\n  url: https://github.com/YuriiMotov\n- login: luzzodev\n  count: 48\n  avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4\n  url: https://github.com/luzzodev\n- login: tiangolo\n  count: 30\n  avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4\n  url: https://github.com/tiangolo\n- login: valentinDruzhinin\n  count: 30\n  avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4\n  url: https://github.com/valentinDruzhinin\n- login: JavierSanchezCastro\n  count: 18\n  avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4\n  url: https://github.com/JavierSanchezCastro\n- login: sachinh35\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/21972708?u=8560b97b8b41e175f476270b56de8a493b84f302&v=4\n  url: https://github.com/sachinh35\n- login: Firatasi\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/112112161?u=3219914a49a4a604b3626007823db7de049b6d66&v=4\n  url: https://github.com/Firatasi\n- login: DoctorJohn\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/14076775?u=ec43fe79a98dbc864b428afc7220753e25ca3af2&v=4\n  url: https://github.com/DoctorJohn\n- login: raceychan\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/75417963?u=060c62870ec5a791765e63ac20d8885d11143786&v=4\n  url: https://github.com/raceychan\n- login: yinziyan1206\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4\n  url: https://github.com/yinziyan1206\n- login: Toygarmetu\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/92878791?u=538530cb6d5554e71f9c28709d794db9a74d23d9&v=4\n  url: https://github.com/Toygarmetu\n- login: Kludex\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4\n  url: https://github.com/Kludex\n- login: ceb10n\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4\n  url: https://github.com/ceb10n\n- login: RichieB2B\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/1461970?u=edaa57d1077705244ea5c9244f4783d94ff11f12&v=4\n  url: https://github.com/RichieB2B\n- login: JunjieAraoXiong\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/167785867?u=b69afe090c8bf5fd73f2d23fc3a887b28f68f192&v=4\n  url: https://github.com/JunjieAraoXiong\n- login: svlandeg\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4\n  url: https://github.com/svlandeg\n- login: WilliamDEdwards\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/12184311?u=9b29d5d1d71f5f1a7ef9e439963ad3529e3b33a4&v=4\n  url: https://github.com/WilliamDEdwards\n- login: ArmanShirzad\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/68951175?u=1f1efae2fa5d0d17c38a1a8413bedca5e538cedb&v=4\n  url: https://github.com/ArmanShirzad\n- login: CodeKraken-cmd\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/48470371?u=e7c0e7ec8e35ca5fb3ae40a586ed5e788fd0fe6d&v=4\n  url: https://github.com/CodeKraken-cmd\n- login: krylosov-aa\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/242901957?u=4c9c7b468203b09bca64936fb464620e32cdd252&v=4\n  url: https://github.com/krylosov-aa\n- login: isgin01\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=16d6466476cf7dbc55a4cd575b6ea920ebdd81e1&v=4\n  url: https://github.com/isgin01\n- login: ericgitangu\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/11472845?u=9d916cf0f5c80e63cb1d753b8b50dcb8ced3b883&v=4\n  url: https://github.com/ericgitangu\n- login: henrymcl\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/26480299?v=4\n  url: https://github.com/henrymcl\n- login: EmmanuelNiyonshuti\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/142030687?u=ab131d5ad4670280a978f489babe71c9bf9c1097&v=4\n  url: https://github.com/EmmanuelNiyonshuti\n- login: dolfinus\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/4661021?u=ed5ddadcf36d9b943ebe61febe0b96ee34e5425d&v=4\n  url: https://github.com/dolfinus\n- login: jymchng\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/27895426?u=fb88c47775147d62a395fdb895d1af4148c7b566&v=4\n  url: https://github.com/jymchng\n- login: simone-trubian\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/5606840?u=65703af3c605feca61ce49e4009bb4e26495b425&v=4\n  url: https://github.com/simone-trubian\n- login: mahimairaja\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/81288263?u=4eef6b4a36b96e84bd666fc1937aa589036ccb9a&v=4\n  url: https://github.com/mahimairaja\n- login: pankeshpatel\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/1482917?u=666f39197a88cfa38b8bd78d39ef04d95c948b6b&v=4\n  url: https://github.com/pankeshpatel\n- login: Jelle-tenB\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/210023470?u=c25d66addf36a747bd9fab773c4a6e7b238f45d4&v=4\n  url: https://github.com/Jelle-tenB\n- login: cookesan\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6601329?u=7bfc9b017198a9fa50929ae8ae0a787632424ffd&v=4\n  url: https://github.com/cookesan\n- login: coleifer\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/119974?u=b3a546c94ee1105e792e0acad2c4743d800e7975&v=4\n  url: https://github.com/coleifer\n- login: Bahtya\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/34988899?u=b8e3c0cf26f4bd1faea265d2f5f66f564af63463&v=4\n  url: https://github.com/Bahtya\n- login: saitarrun\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/116748905?u=3433afbaf06676a482ebf4ba33b08ddb3fc5c5bf&v=4\n  url: https://github.com/saitarrun\n- login: cepedus\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/26345924?u=38495abbdbb8695dd76478cae5963bf994c498bc&v=4\n  url: https://github.com/cepedus\n- login: christiansousadev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/103544118?u=690f3f76d1dc4d0929de5020679d5604f860acbc&v=4\n  url: https://github.com/christiansousadev\n- login: gaardhus\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/46934916?u=18d7aacc6ce59f054749209645d11cfe77b52f90&v=4\n  url: https://github.com/gaardhus\n- login: y2kbugger\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6101677?u=1d50077e29582dc01fcbdff846f04fe7ec73fe2e&v=4\n  url: https://github.com/y2kbugger\n- login: Garrett-R\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6614695?u=c128fd775002882f6e391bda5a89d1bdc5bdf45f&v=4\n  url: https://github.com/Garrett-R\n- login: TaigoFr\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/17792131?u=372b27056ec82f1ae03d8b3f37ef55b04a7cfdd1&v=4\n  url: https://github.com/TaigoFr\n- login: stan-dot\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/56644812?u=a7dd773084f1c17c5f05019cc25a984e24873691&v=4\n  url: https://github.com/stan-dot\n- login: Damon0603\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/110039208?u=f24bf5c30317bc4959118d1b919587c473a865b6&v=4\n  url: https://github.com/Damon0603\n- login: huynguyengl99\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/49433085?u=7b626115686c5d97a2a32a03119f5300e425cc9f&v=4\n  url: https://github.com/huynguyengl99\n- login: davidbrochart\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/4711805?u=d39696d995a9e02ec3613ffb2f62b20b14f92f26&v=4\n  url: https://github.com/davidbrochart\n- login: CharlieReitzel\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/20848272?v=4\n  url: https://github.com/CharlieReitzel\n- login: kiranzo\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1070878?u=68f78a891c9751dd87571ac712a6309090c4bc01&v=4\n  url: https://github.com/kiranzo\n- login: dotmitsu\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/42657211?u=3bccc9a2f386a3f24230ec393080f8904fe2a5b2&v=4\n  url: https://github.com/dotmitsu\n- login: Brikas\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/80290187?u=2b72e497ca4444ecec1f9dc2d1b8d5437a27b83f&v=4\n  url: https://github.com/Brikas\n- login: BloodyRain2k\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1014362?v=4\n  url: https://github.com/BloodyRain2k\n- login: usiqwerty\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/37992525?u=0c6e91d7b3887aa558755f4225ce74a003cbe852&v=4\n  url: https://github.com/usiqwerty\n- login: skion\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/532192?v=4\n  url: https://github.com/skion\n- login: florentx\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/142113?u=bf10f10080026346b092633c380977b61cee0d9c&v=4\n  url: https://github.com/florentx\n- login: jc-louis\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/51329768?v=4\n  url: https://github.com/jc-louis\n- login: bughuntr7\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/236391583?u=7f51ff690e3a5711f845a115903c39e21c8af938&v=4\n  url: https://github.com/bughuntr7\n- login: purepani\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/7587353?v=4\n  url: https://github.com/purepani\n- login: asmaier\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/3169297?u=84c83cbdb64104331febe16ae232ecf30952d01d&v=4\n  url: https://github.com/asmaier\n- login: davidhuser\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/4357648?u=6ed702f8f6d49a8b2a0ed33cbd8ab59c2d7db7f7&v=4\n  url: https://github.com/davidhuser\n- login: XieJiSS\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/24671280?u=7ea0d9bfe46cf762594d62fd2f3c6d3813c3584c&v=4\n  url: https://github.com/XieJiSS\n- login: profatsky\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/92920843?u=81e54bb0b613c171f7cd0ab3cbb58873782c9c9c&v=4\n  url: https://github.com/profatsky\n- login: pythonweb2\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/32141163?v=4\n  url: https://github.com/pythonweb2\n"
  },
  {
    "path": "docs/en/data/skip_users.yml",
    "content": "- tiangolo\n- codecov\n- github-actions\n- pre-commit-ci\n- dependabot\n"
  },
  {
    "path": "docs/en/data/sponsors.yml",
    "content": "keystone:\n  - url: https://fastapicloud.com\n    title: FastAPI Cloud. By the same team behind FastAPI. You code. We Cloud.\n    img: https://fastapi.tiangolo.com/img/sponsors/fastapicloud.png\ngold:\n  - url: https://blockbee.io?ref=fastapi\n    title: BlockBee Cryptocurrency Payment Gateway\n    img: https://fastapi.tiangolo.com/img/sponsors/blockbee.png\n  - url: https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=main-badge\n    title: \"Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files\"\n    img: https://fastapi.tiangolo.com/img/sponsors/scalar.svg\n  - url: https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=mainbadge\n    title: Auth, user management and more for your B2B product\n    img: https://fastapi.tiangolo.com/img/sponsors/propelauth.png\n  - url: https://liblab.com?utm_source=fastapi\n    title: liblab - Generate SDKs from FastAPI\n    img: https://fastapi.tiangolo.com/img/sponsors/liblab.png\n  - url: https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi\n    title: Deploy & scale any full-stack web app on Render. Focus on building apps, not infra.\n    img: https://fastapi.tiangolo.com/img/sponsors/render.svg\n  - url: https://www.coderabbit.ai/?utm_source=fastapi&utm_medium=badge&utm_campaign=fastapi\n    title: Cut Code Review Time & Bugs in Half with CodeRabbit\n    img: https://fastapi.tiangolo.com/img/sponsors/coderabbit.png\n  - url: https://subtotal.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=open-source\n    title: The Gold Standard in Retail Account Linking\n    img: https://fastapi.tiangolo.com/img/sponsors/subtotal.svg\n  - url: https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi\n    title: Deploy enterprise applications at startup speed\n    img: https://fastapi.tiangolo.com/img/sponsors/railway.png\n  - url: https://serpapi.com/?utm_source=fastapi_website\n    title: \"SerpApi: Web Search API\"\n    img: https://fastapi.tiangolo.com/img/sponsors/serpapi.png\n  - url: https://www.greptile.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=fastapi_sponsor_page\n    title: \"Greptile: The AI Code Reviewer\"\n    img: https://fastapi.tiangolo.com/img/sponsors/greptile.png\nsilver:\n  - url: https://databento.com/?utm_source=fastapi&utm_medium=sponsor&utm_content=display\n    title: Pay as you go for market data\n    img: https://fastapi.tiangolo.com/img/sponsors/databento.svg\n  - url: https://www.svix.com/\n    title: Svix - Webhooks as a service\n    img: https://fastapi.tiangolo.com/img/sponsors/svix.svg\n  - url: https://www.stainlessapi.com/?utm_source=fastapi&utm_medium=referral\n    title: Stainless | Generate best-in-class SDKs\n    img: https://fastapi.tiangolo.com/img/sponsors/stainless.png\n  - url: https://www.permit.io/blog/implement-authorization-in-fastapi?utm_source=github&utm_medium=referral&utm_campaign=fastapi\n    title: Fine-Grained Authorization for FastAPI\n    img: https://fastapi.tiangolo.com/img/sponsors/permit.png\n  - url: https://www.interviewpal.com/?utm_source=fastapi&utm_medium=open-source&utm_campaign=dev-hiring\n    title: InterviewPal - AI Interview Coach for Engineers and Devs\n    img: https://fastapi.tiangolo.com/img/sponsors/interviewpal.png\n  - url: https://dribia.com/en/\n    title: Dribia - Data Science within your reach\n    img: https://fastapi.tiangolo.com/img/sponsors/dribia.png\n  - url: https://talordata.com/?campaignid=oh5dVZ3Zc3YGiAI2&utm_source=fastapi&utm_term=fastapi\n    title: TalorData SERP API - Multi-Engine Search Results Data\n    img: https://fastapi.tiangolo.com/img/sponsors/talordata.png\nbronze:\n  - url: https://www.exoflare.com/open-source/?utm_source=FastAPI&utm_campaign=open_source\n    title: Biosecurity risk assessments made easy.\n    img: https://fastapi.tiangolo.com/img/sponsors/exoflare.png\n  # - url: https://testdriven.io/courses/tdd-fastapi/\n  #   title: Learn to build high-quality web apps with best practices\n  #   img: https://fastapi.tiangolo.com/img/sponsors/testdriven.svg\n  - url: https://www.testmu.ai/?utm_source=fastapi&utm_medium=partner&utm_campaign=sponsor&utm_term=opensource&utm_content=webpage\n    title: TestMu AI. The Native AI-Agentic Cloud Platform to Supercharge Quality Engineering.\n    img: https://fastapi.tiangolo.com/img/sponsors/testmu.png\n"
  },
  {
    "path": "docs/en/data/sponsors_badge.yml",
    "content": "logins:\n  - jina-ai\n  - deta\n  - investsuite\n  - mikeckennedy\n  - deepset-ai\n  - cryptapi\n  - xoflare\n  - DropbaseHQ\n  - VincentParedes\n  - BLUE-DEVIL1134\n  - ObliviousAI\n  - Doist\n  - nihpo\n  - armand-sauzay\n  - databento-bot\n  - databento\n  - nanram22\n  - Flint-company\n  - porter-dev\n  - fern-api\n  - ndimares\n  - svixhq\n  - Alek99\n  - codacy\n  - zanfaruqui\n  - scalar\n  - bump-sh\n  - andrew-propelauth\n  - svix\n  - zuplo-oss\n  - zuplo\n  - Kong\n  - speakeasy-api\n  - jess-render\n  - blockbee-io\n  - liblaber\n  - render-sponsorships\n  - renderinc\n  - stainless-api\n  - snapit-cypher\n  - coderabbitai\n  - permitio\n  - LambdaTest-Inc\n  - dribia\n  - madisonredtfeldt\n  - railwayapp\n  - subtotal\n  - requestly\n  - greptileai\n  - talorelowen\n"
  },
  {
    "path": "docs/en/data/topic_repos.yml",
    "content": "- name: full-stack-fastapi-template\n  html_url: https://github.com/fastapi/full-stack-fastapi-template\n  stars: 42944\n  owner_login: fastapi\n  owner_html_url: https://github.com/fastapi\n- name: Hello-Python\n  html_url: https://github.com/mouredev/Hello-Python\n  stars: 35430\n  owner_login: mouredev\n  owner_html_url: https://github.com/mouredev\n- name: serve\n  html_url: https://github.com/jina-ai/serve\n  stars: 21876\n  owner_login: jina-ai\n  owner_html_url: https://github.com/jina-ai\n- name: HivisionIDPhotos\n  html_url: https://github.com/Zeyi-Lin/HivisionIDPhotos\n  stars: 21054\n  owner_login: Zeyi-Lin\n  owner_html_url: https://github.com/Zeyi-Lin\n- name: sqlmodel\n  html_url: https://github.com/fastapi/sqlmodel\n  stars: 17886\n  owner_login: fastapi\n  owner_html_url: https://github.com/fastapi\n- name: Douyin_TikTok_Download_API\n  html_url: https://github.com/Evil0ctal/Douyin_TikTok_Download_API\n  stars: 17546\n  owner_login: Evil0ctal\n  owner_html_url: https://github.com/Evil0ctal\n- name: fastapi-best-practices\n  html_url: https://github.com/zhanymkanov/fastapi-best-practices\n  stars: 17138\n  owner_login: zhanymkanov\n  owner_html_url: https://github.com/zhanymkanov\n- name: SurfSense\n  html_url: https://github.com/MODSetter/SurfSense\n  stars: 14045\n  owner_login: MODSetter\n  owner_html_url: https://github.com/MODSetter\n- name: machine-learning-zoomcamp\n  html_url: https://github.com/DataTalksClub/machine-learning-zoomcamp\n  stars: 13015\n  owner_login: DataTalksClub\n  owner_html_url: https://github.com/DataTalksClub\n- name: fastapi_mcp\n  html_url: https://github.com/tadata-org/fastapi_mcp\n  stars: 11837\n  owner_login: tadata-org\n  owner_html_url: https://github.com/tadata-org\n- name: awesome-fastapi\n  html_url: https://github.com/mjhea0/awesome-fastapi\n  stars: 11315\n  owner_login: mjhea0\n  owner_html_url: https://github.com/mjhea0\n- name: XHS-Downloader\n  html_url: https://github.com/JoeanAmier/XHS-Downloader\n  stars: 11013\n  owner_login: JoeanAmier\n  owner_html_url: https://github.com/JoeanAmier\n- name: polar\n  html_url: https://github.com/polarsource/polar\n  stars: 9775\n  owner_login: polarsource\n  owner_html_url: https://github.com/polarsource\n- name: pycaret\n  html_url: https://github.com/pycaret/pycaret\n  stars: 9753\n  owner_login: pycaret\n  owner_html_url: https://github.com/pycaret\n- name: FastUI\n  html_url: https://github.com/pydantic/FastUI\n  stars: 8961\n  owner_login: pydantic\n  owner_html_url: https://github.com/pydantic\n- name: FileCodeBox\n  html_url: https://github.com/vastsa/FileCodeBox\n  stars: 8241\n  owner_login: vastsa\n  owner_html_url: https://github.com/vastsa\n- name: nonebot2\n  html_url: https://github.com/nonebot/nonebot2\n  stars: 7488\n  owner_login: nonebot\n  owner_html_url: https://github.com/nonebot\n- name: hatchet\n  html_url: https://github.com/hatchet-dev/hatchet\n  stars: 7044\n  owner_login: hatchet-dev\n  owner_html_url: https://github.com/hatchet-dev\n- name: fastapi-users\n  html_url: https://github.com/fastapi-users/fastapi-users\n  stars: 6107\n  owner_login: fastapi-users\n  owner_html_url: https://github.com/fastapi-users\n- name: serge\n  html_url: https://github.com/serge-chat/serge\n  stars: 5731\n  owner_login: serge-chat\n  owner_html_url: https://github.com/serge-chat\n- name: Yuxi\n  html_url: https://github.com/xerrors/Yuxi\n  stars: 5063\n  owner_login: xerrors\n  owner_html_url: https://github.com/xerrors\n- name: Kokoro-FastAPI\n  html_url: https://github.com/remsky/Kokoro-FastAPI\n  stars: 4785\n  owner_login: remsky\n  owner_html_url: https://github.com/remsky\n- name: strawberry\n  html_url: https://github.com/strawberry-graphql/strawberry\n  stars: 4649\n  owner_login: strawberry-graphql\n  owner_html_url: https://github.com/strawberry-graphql\n- name: devpush\n  html_url: https://github.com/hunvreus/devpush\n  stars: 4641\n  owner_login: hunvreus\n  owner_html_url: https://github.com/hunvreus\n- name: poem\n  html_url: https://github.com/poem-web/poem\n  stars: 4387\n  owner_login: poem-web\n  owner_html_url: https://github.com/poem-web\n- name: dynaconf\n  html_url: https://github.com/dynaconf/dynaconf\n  stars: 4291\n  owner_login: dynaconf\n  owner_html_url: https://github.com/dynaconf\n- name: chatgpt-web-share\n  html_url: https://github.com/chatpire/chatgpt-web-share\n  stars: 4269\n  owner_login: chatpire\n  owner_html_url: https://github.com/chatpire\n- name: logfire\n  html_url: https://github.com/pydantic/logfire\n  stars: 4206\n  owner_login: pydantic\n  owner_html_url: https://github.com/pydantic\n- name: atrilabs-engine\n  html_url: https://github.com/Atri-Labs/atrilabs-engine\n  stars: 4080\n  owner_login: Atri-Labs\n  owner_html_url: https://github.com/Atri-Labs\n- name: huma\n  html_url: https://github.com/danielgtaylor/huma\n  stars: 4043\n  owner_login: danielgtaylor\n  owner_html_url: https://github.com/danielgtaylor\n- name: datamodel-code-generator\n  html_url: https://github.com/koxudaxi/datamodel-code-generator\n  stars: 3882\n  owner_login: koxudaxi\n  owner_html_url: https://github.com/koxudaxi\n- name: LitServe\n  html_url: https://github.com/Lightning-AI/LitServe\n  stars: 3879\n  owner_login: Lightning-AI\n  owner_html_url: https://github.com/Lightning-AI\n- name: fastapi-admin\n  html_url: https://github.com/fastapi-admin/fastapi-admin\n  stars: 3759\n  owner_login: fastapi-admin\n  owner_html_url: https://github.com/fastapi-admin\n- name: mcp-context-forge\n  html_url: https://github.com/IBM/mcp-context-forge\n  stars: 3644\n  owner_login: IBM\n  owner_html_url: https://github.com/IBM\n- name: tracecat\n  html_url: https://github.com/TracecatHQ/tracecat\n  stars: 3564\n  owner_login: TracecatHQ\n  owner_html_url: https://github.com/TracecatHQ\n- name: farfalle\n  html_url: https://github.com/rashadphz/farfalle\n  stars: 3530\n  owner_login: rashadphz\n  owner_html_url: https://github.com/rashadphz\n- name: opyrator\n  html_url: https://github.com/ml-tooling/opyrator\n  stars: 3137\n  owner_login: ml-tooling\n  owner_html_url: https://github.com/ml-tooling\n- name: honcho\n  html_url: https://github.com/plastic-labs/honcho\n  stars: 3135\n  owner_login: plastic-labs\n  owner_html_url: https://github.com/plastic-labs\n- name: docarray\n  html_url: https://github.com/docarray/docarray\n  stars: 3118\n  owner_login: docarray\n  owner_html_url: https://github.com/docarray\n- name: fastapi-realworld-example-app\n  html_url: https://github.com/nsidnev/fastapi-realworld-example-app\n  stars: 3111\n  owner_login: nsidnev\n  owner_html_url: https://github.com/nsidnev\n- name: uvicorn-gunicorn-fastapi-docker\n  html_url: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker\n  stars: 2912\n  owner_login: tiangolo\n  owner_html_url: https://github.com/tiangolo\n- name: FastAPI-template\n  html_url: https://github.com/s3rius/FastAPI-template\n  stars: 2780\n  owner_login: s3rius\n  owner_html_url: https://github.com/s3rius\n- name: sqladmin\n  html_url: https://github.com/smithyhq/sqladmin\n  stars: 2716\n  owner_login: smithyhq\n  owner_html_url: https://github.com/smithyhq\n- name: best-of-web-python\n  html_url: https://github.com/ml-tooling/best-of-web-python\n  stars: 2711\n  owner_login: ml-tooling\n  owner_html_url: https://github.com/ml-tooling\n- name: YC-Killer\n  html_url: https://github.com/sahibzada-allahyar/YC-Killer\n  stars: 2626\n  owner_login: sahibzada-allahyar\n  owner_html_url: https://github.com/sahibzada-allahyar\n- name: fastapi-react\n  html_url: https://github.com/Buuntu/fastapi-react\n  stars: 2581\n  owner_login: Buuntu\n  owner_html_url: https://github.com/Buuntu\n- name: supabase-py\n  html_url: https://github.com/supabase/supabase-py\n  stars: 2499\n  owner_login: supabase\n  owner_html_url: https://github.com/supabase\n- name: RasaGPT\n  html_url: https://github.com/paulpierre/RasaGPT\n  stars: 2466\n  owner_login: paulpierre\n  owner_html_url: https://github.com/paulpierre\n- name: NoteDiscovery\n  html_url: https://github.com/gamosoft/NoteDiscovery\n  stars: 2465\n  owner_login: gamosoft\n  owner_html_url: https://github.com/gamosoft\n- name: 30-Days-of-Python\n  html_url: https://github.com/codingforentrepreneurs/30-Days-of-Python\n  stars: 2459\n  owner_login: codingforentrepreneurs\n  owner_html_url: https://github.com/codingforentrepreneurs\n- name: AIstudioProxyAPI\n  html_url: https://github.com/CJackHwang/AIstudioProxyAPI\n  stars: 2346\n  owner_login: CJackHwang\n  owner_html_url: https://github.com/CJackHwang\n- name: nextpy\n  html_url: https://github.com/dot-agent/nextpy\n  stars: 2336\n  owner_login: dot-agent\n  owner_html_url: https://github.com/dot-agent\n- name: langserve\n  html_url: https://github.com/langchain-ai/langserve\n  stars: 2319\n  owner_login: langchain-ai\n  owner_html_url: https://github.com/langchain-ai\n- name: fastapi-utils\n  html_url: https://github.com/fastapiutils/fastapi-utils\n  stars: 2306\n  owner_login: fastapiutils\n  owner_html_url: https://github.com/fastapiutils\n- name: fastapi-langgraph-agent-production-ready-template\n  html_url: https://github.com/wassim249/fastapi-langgraph-agent-production-ready-template\n  stars: 2218\n  owner_login: wassim249\n  owner_html_url: https://github.com/wassim249\n- name: fastapi-best-architecture\n  html_url: https://github.com/fastapi-practices/fastapi-best-architecture\n  stars: 2206\n  owner_login: fastapi-practices\n  owner_html_url: https://github.com/fastapi-practices\n- name: solara\n  html_url: https://github.com/widgetti/solara\n  stars: 2160\n  owner_login: widgetti\n  owner_html_url: https://github.com/widgetti\n- name: vue-fastapi-admin\n  html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin\n  stars: 2108\n  owner_login: mizhexiaoxiao\n  owner_html_url: https://github.com/mizhexiaoxiao\n- name: mangum\n  html_url: https://github.com/Kludex/mangum\n  stars: 2106\n  owner_login: Kludex\n  owner_html_url: https://github.com/Kludex\n- name: slowapi\n  html_url: https://github.com/laurentS/slowapi\n  stars: 1960\n  owner_login: laurentS\n  owner_html_url: https://github.com/laurentS\n- name: xhs_ai_publisher\n  html_url: https://github.com/BetaStreetOmnis/xhs_ai_publisher\n  stars: 1948\n  owner_login: BetaStreetOmnis\n  owner_html_url: https://github.com/BetaStreetOmnis\n- name: agentkit\n  html_url: https://github.com/BCG-X-Official/agentkit\n  stars: 1944\n  owner_login: BCG-X-Official\n  owner_html_url: https://github.com/BCG-X-Official\n- name: openapi-python-client\n  html_url: https://github.com/openapi-generators/openapi-python-client\n  stars: 1941\n  owner_login: openapi-generators\n  owner_html_url: https://github.com/openapi-generators\n- name: manage-fastapi\n  html_url: https://github.com/ycd/manage-fastapi\n  stars: 1901\n  owner_login: ycd\n  owner_html_url: https://github.com/ycd\n- name: piccolo\n  html_url: https://github.com/piccolo-orm/piccolo\n  stars: 1896\n  owner_login: piccolo-orm\n  owner_html_url: https://github.com/piccolo-orm\n- name: FastAPI-boilerplate\n  html_url: https://github.com/benavlabs/FastAPI-boilerplate\n  stars: 1892\n  owner_login: benavlabs\n  owner_html_url: https://github.com/benavlabs\n- name: fastapi-cache\n  html_url: https://github.com/long2ice/fastapi-cache\n  stars: 1859\n  owner_login: long2ice\n  owner_html_url: https://github.com/long2ice\n- name: any-auto-register\n  html_url: https://github.com/lxf746/any-auto-register\n  stars: 1857\n  owner_login: lxf746\n  owner_html_url: https://github.com/lxf746\n- name: python-week-2022\n  html_url: https://github.com/rochacbruno/python-week-2022\n  stars: 1810\n  owner_login: rochacbruno\n  owner_html_url: https://github.com/rochacbruno\n- name: ormar\n  html_url: https://github.com/ormar-orm/ormar\n  stars: 1806\n  owner_login: ormar-orm\n  owner_html_url: https://github.com/ormar-orm\n- name: termpair\n  html_url: https://github.com/cs01/termpair\n  stars: 1731\n  owner_login: cs01\n  owner_html_url: https://github.com/cs01\n- name: fastapi-crudrouter\n  html_url: https://github.com/awtkns/fastapi-crudrouter\n  stars: 1687\n  owner_login: awtkns\n  owner_html_url: https://github.com/awtkns\n- name: bracket\n  html_url: https://github.com/evroon/bracket\n  stars: 1653\n  owner_login: evroon\n  owner_html_url: https://github.com/evroon\n- name: WebRPA\n  html_url: https://github.com/pmh1314520/WebRPA\n  stars: 1653\n  owner_login: pmh1314520\n  owner_html_url: https://github.com/pmh1314520\n- name: fastapi-pagination\n  html_url: https://github.com/uriyyo/fastapi-pagination\n  stars: 1646\n  owner_login: uriyyo\n  owner_html_url: https://github.com/uriyyo\n- name: langchain-serve\n  html_url: https://github.com/jina-ai/langchain-serve\n  stars: 1640\n  owner_login: jina-ai\n  owner_html_url: https://github.com/jina-ai\n- name: headroom\n  html_url: https://github.com/chopratejas/headroom\n  stars: 1624\n  owner_login: chopratejas\n  owner_html_url: https://github.com/chopratejas\n- name: awesome-fastapi-projects\n  html_url: https://github.com/Kludex/awesome-fastapi-projects\n  stars: 1599\n  owner_login: Kludex\n  owner_html_url: https://github.com/Kludex\n- name: coronavirus-tracker-api\n  html_url: https://github.com/ExpDev07/coronavirus-tracker-api\n  stars: 1567\n  owner_login: ExpDev07\n  owner_html_url: https://github.com/ExpDev07\n- name: fastapi-amis-admin\n  html_url: https://github.com/amisadmin/fastapi-amis-admin\n  stars: 1541\n  owner_login: amisadmin\n  owner_html_url: https://github.com/amisadmin\n- name: fastcrud\n  html_url: https://github.com/benavlabs/fastcrud\n  stars: 1512\n  owner_login: benavlabs\n  owner_html_url: https://github.com/benavlabs\n- name: open-wearables\n  html_url: https://github.com/the-momentum/open-wearables\n  stars: 1496\n  owner_login: the-momentum\n  owner_html_url: https://github.com/the-momentum\n- name: fastapi-boilerplate\n  html_url: https://github.com/teamhide/fastapi-boilerplate\n  stars: 1486\n  owner_login: teamhide\n  owner_html_url: https://github.com/teamhide\n- name: tavily-key-generator\n  html_url: https://github.com/skernelx/tavily-key-generator\n  stars: 1478\n  owner_login: skernelx\n  owner_html_url: https://github.com/skernelx\n- name: prometheus-fastapi-instrumentator\n  html_url: https://github.com/trallnag/prometheus-fastapi-instrumentator\n  stars: 1451\n  owner_login: trallnag\n  owner_html_url: https://github.com/trallnag\n- name: awesome-python-resources\n  html_url: https://github.com/DjangoEx/awesome-python-resources\n  stars: 1449\n  owner_login: DjangoEx\n  owner_html_url: https://github.com/DjangoEx\n- name: fastapi-tutorial\n  html_url: https://github.com/liaogx/fastapi-tutorial\n  stars: 1399\n  owner_login: liaogx\n  owner_html_url: https://github.com/liaogx\n- name: fastapi-code-generator\n  html_url: https://github.com/koxudaxi/fastapi-code-generator\n  stars: 1383\n  owner_login: koxudaxi\n  owner_html_url: https://github.com/koxudaxi\n- name: budgetml\n  html_url: https://github.com/ebhy/budgetml\n  stars: 1345\n  owner_login: ebhy\n  owner_html_url: https://github.com/ebhy\n- name: aktools\n  html_url: https://github.com/akfamily/aktools\n  stars: 1334\n  owner_login: akfamily\n  owner_html_url: https://github.com/akfamily\n- name: RuoYi-Vue3-FastAPI\n  html_url: https://github.com/insistence/RuoYi-Vue3-FastAPI\n  stars: 1302\n  owner_login: insistence\n  owner_html_url: https://github.com/insistence\n- name: bolt-python\n  html_url: https://github.com/slackapi/bolt-python\n  stars: 1296\n  owner_login: slackapi\n  owner_html_url: https://github.com/slackapi\n- name: bedrock-chat\n  html_url: https://github.com/aws-samples/bedrock-chat\n  stars: 1288\n  owner_login: aws-samples\n  owner_html_url: https://github.com/aws-samples\n- name: restish\n  html_url: https://github.com/rest-sh/restish\n  stars: 1279\n  owner_login: rest-sh\n  owner_html_url: https://github.com/rest-sh\n- name: fastapi-alembic-sqlmodel-async\n  html_url: https://github.com/vargasjona/fastapi-alembic-sqlmodel-async\n  stars: 1270\n  owner_login: vargasjona\n  owner_html_url: https://github.com/vargasjona\n- name: fastapi_production_template\n  html_url: https://github.com/zhanymkanov/fastapi_production_template\n  stars: 1243\n  owner_login: zhanymkanov\n  owner_html_url: https://github.com/zhanymkanov\n- name: yubal\n  html_url: https://github.com/guillevc/yubal\n  stars: 1203\n  owner_login: guillevc\n  owner_html_url: https://github.com/guillevc\n- name: langchain-extract\n  html_url: https://github.com/langchain-ai/langchain-extract\n  stars: 1196\n  owner_login: langchain-ai\n  owner_html_url: https://github.com/langchain-ai\n- name: Chatterbox-TTS-Server\n  html_url: https://github.com/devnen/Chatterbox-TTS-Server\n  stars: 1194\n  owner_login: devnen\n  owner_html_url: https://github.com/devnen\n"
  },
  {
    "path": "docs/en/data/translation_reviewers.yml",
    "content": "s111d:\n  login: s111d\n  count: 147\n  avatarUrl: https://avatars.githubusercontent.com/u/4954856?v=4\n  url: https://github.com/s111d\nXewus:\n  login: Xewus\n  count: 140\n  avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4\n  url: https://github.com/Xewus\nsodaMelon:\n  login: sodaMelon\n  count: 128\n  avatarUrl: https://avatars.githubusercontent.com/u/66295123?u=be939db90f1119efee9e6110cc05066ff1f40f00&v=4\n  url: https://github.com/sodaMelon\nceb10n:\n  login: ceb10n\n  count: 119\n  avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4\n  url: https://github.com/ceb10n\ntokusumi:\n  login: tokusumi\n  count: 104\n  avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4\n  url: https://github.com/tokusumi\nhard-coders:\n  login: hard-coders\n  count: 102\n  avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4\n  url: https://github.com/hard-coders\nhasansezertasan:\n  login: hasansezertasan\n  count: 95\n  avatarUrl: https://avatars.githubusercontent.com/u/13135006?u=d36995e41a00590da64e6204cfd112e0484ac1ca&v=4\n  url: https://github.com/hasansezertasan\nalv2017:\n  login: alv2017\n  count: 88\n  avatarUrl: https://avatars.githubusercontent.com/u/31544722?v=4\n  url: https://github.com/alv2017\nnazarepiedady:\n  login: nazarepiedady\n  count: 87\n  avatarUrl: https://avatars.githubusercontent.com/u/31008635?u=f69ddc4ea8bda3bdfac7aa0e2ea38de282e6ee2d&v=4\n  url: https://github.com/nazarepiedady\ntiangolo:\n  login: tiangolo\n  count: 82\n  avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4\n  url: https://github.com/tiangolo\nAlertRED:\n  login: AlertRED\n  count: 81\n  avatarUrl: https://avatars.githubusercontent.com/u/15695000?u=f5a4944c6df443030409c88da7d7fa0b7ead985c&v=4\n  url: https://github.com/AlertRED\nAlexandrhub:\n  login: Alexandrhub\n  count: 68\n  avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4\n  url: https://github.com/Alexandrhub\nnilslindemann:\n  login: nilslindemann\n  count: 67\n  avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4\n  url: https://github.com/nilslindemann\nYuriiMotov:\n  login: YuriiMotov\n  count: 67\n  avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4\n  url: https://github.com/YuriiMotov\ncassiobotaro:\n  login: cassiobotaro\n  count: 64\n  avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=a08022b191ddbd0a6159b2981d9d878b6d5bb71f&v=4\n  url: https://github.com/cassiobotaro\nwaynerv:\n  login: waynerv\n  count: 63\n  avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4\n  url: https://github.com/waynerv\nmattwang44:\n  login: mattwang44\n  count: 61\n  avatarUrl: https://avatars.githubusercontent.com/u/24987826?u=58e37fb3927b9124b458945ac4c97aa0f1062d85&v=4\n  url: https://github.com/mattwang44\nLaineyzhang55:\n  login: Laineyzhang55\n  count: 48\n  avatarUrl: https://avatars.githubusercontent.com/u/59285379?v=4\n  url: https://github.com/Laineyzhang55\nKludex:\n  login: Kludex\n  count: 47\n  avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4\n  url: https://github.com/Kludex\nkomtaki:\n  login: komtaki\n  count: 45\n  avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4\n  url: https://github.com/komtaki\nsvlandeg:\n  login: svlandeg\n  count: 43\n  avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4\n  url: https://github.com/svlandeg\nrostik1410:\n  login: rostik1410\n  count: 42\n  avatarUrl: https://avatars.githubusercontent.com/u/11443899?u=e26a635c2ba220467b308a326a579b8ccf4a8701&v=4\n  url: https://github.com/rostik1410\nalperiox:\n  login: alperiox\n  count: 42\n  avatarUrl: https://avatars.githubusercontent.com/u/34214152?u=2c5acad3461d4dbc2d48371ba86cac56ae9b25cc&v=4\n  url: https://github.com/alperiox\nRishat-F:\n  login: Rishat-F\n  count: 42\n  avatarUrl: https://avatars.githubusercontent.com/u/66554797?v=4\n  url: https://github.com/Rishat-F\nWinand:\n  login: Winand\n  count: 40\n  avatarUrl: https://avatars.githubusercontent.com/u/53390?u=bb0e71a2fc3910a8e0ee66da67c33de40ea695f8&v=4\n  url: https://github.com/Winand\nsolomein-sv:\n  login: solomein-sv\n  count: 38\n  avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=789927ee09cfabd752d3bd554fa6baf4850d2777&v=4\n  url: https://github.com/solomein-sv\nmezgoodle:\n  login: mezgoodle\n  count: 38\n  avatarUrl: https://avatars.githubusercontent.com/u/41520940?u=4a9c765af688389d54296845d18b8f6cd6ddf09a&v=4\n  url: https://github.com/mezgoodle\nJavierSanchezCastro:\n  login: JavierSanchezCastro\n  count: 38\n  avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4\n  url: https://github.com/JavierSanchezCastro\nalejsdev:\n  login: alejsdev\n  count: 37\n  avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=0facffe3abf87f57a1f05fa773d1119cc5c2f6a5&v=4\n  url: https://github.com/alejsdev\nstlucasgarcia:\n  login: stlucasgarcia\n  count: 36\n  avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=c22d8850e9dc396a8820766a59837f967e14f9a0&v=4\n  url: https://github.com/stlucasgarcia\nSwftAlpc:\n  login: SwftAlpc\n  count: 36\n  avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4\n  url: https://github.com/SwftAlpc\ntimothy-jeong:\n  login: timothy-jeong\n  count: 36\n  avatarUrl: https://avatars.githubusercontent.com/u/53824764?u=db3d0cea2f5fab64d810113c5039a369699a2774&v=4\n  url: https://github.com/timothy-jeong\nrjNemo:\n  login: rjNemo\n  count: 34\n  avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4\n  url: https://github.com/rjNemo\nyychanlee:\n  login: yychanlee\n  count: 34\n  avatarUrl: https://avatars.githubusercontent.com/u/103817302?u=3a042740dc0ff58615da0d8679230966fd7693e8&v=4\n  url: https://github.com/yychanlee\nVincy1230:\n  login: Vincy1230\n  count: 34\n  avatarUrl: https://avatars.githubusercontent.com/u/81342412?u=ab5e256a4077a4a91f3f9cd2115ba80780454cbe&v=4\n  url: https://github.com/Vincy1230\nakarev0:\n  login: akarev0\n  count: 33\n  avatarUrl: https://avatars.githubusercontent.com/u/53393089?u=6e528bb4789d56af887ce6fe237bea4010885406&v=4\n  url: https://github.com/akarev0\nromashevchenko:\n  login: romashevchenko\n  count: 32\n  avatarUrl: https://avatars.githubusercontent.com/u/132477732?v=4\n  url: https://github.com/romashevchenko\nLorhanSohaky:\n  login: LorhanSohaky\n  count: 30\n  avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4\n  url: https://github.com/LorhanSohaky\nblack-redoc:\n  login: black-redoc\n  count: 29\n  avatarUrl: https://avatars.githubusercontent.com/u/18581590?u=7b6336166d0797fbbd44ea70c1c3ecadfc89af9e&v=4\n  url: https://github.com/black-redoc\npedabraham:\n  login: pedabraham\n  count: 28\n  avatarUrl: https://avatars.githubusercontent.com/u/16860088?u=abf922a7b920bf8fdb7867d8b43e091f1e796178&v=4\n  url: https://github.com/pedabraham\nSmlep:\n  login: Smlep\n  count: 28\n  avatarUrl: https://avatars.githubusercontent.com/u/16785985?u=ffe99fa954c8e774ef1117e58d34aece92051e27&v=4\n  url: https://github.com/Smlep\ndedkot01:\n  login: dedkot01\n  count: 28\n  avatarUrl: https://avatars.githubusercontent.com/u/26196675?u=e2966887124e67932853df4f10f86cb526edc7b0&v=4\n  url: https://github.com/dedkot01\nhsuanchi:\n  login: hsuanchi\n  count: 28\n  avatarUrl: https://avatars.githubusercontent.com/u/24913710?u=7d25a398e478b6e63503bf6f26c54efa9e0da07b&v=4\n  url: https://github.com/hsuanchi\ndpinezich:\n  login: dpinezich\n  count: 28\n  avatarUrl: https://avatars.githubusercontent.com/u/3204540?u=a2e1465e3ee10d537614d513589607eddefde09f&v=4\n  url: https://github.com/dpinezich\nmaoyibo:\n  login: maoyibo\n  count: 27\n  avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4\n  url: https://github.com/maoyibo\n0417taehyun:\n  login: 0417taehyun\n  count: 27\n  avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4\n  url: https://github.com/0417taehyun\nBilalAlpaslan:\n  login: BilalAlpaslan\n  count: 26\n  avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4\n  url: https://github.com/BilalAlpaslan\njunah201:\n  login: junah201\n  count: 26\n  avatarUrl: https://avatars.githubusercontent.com/u/75025529?u=2451c256e888fa2a06bcfc0646d09b87ddb6a945&v=4\n  url: https://github.com/junah201\nzy7y:\n  login: zy7y\n  count: 25\n  avatarUrl: https://avatars.githubusercontent.com/u/67154681?u=5d634834cc514028ea3f9115f7030b99a1f4d5a4&v=4\n  url: https://github.com/zy7y\nmycaule:\n  login: mycaule\n  count: 25\n  avatarUrl: https://avatars.githubusercontent.com/u/6161385?u=e3cec75bd6d938a0d73fae0dc5534d1ab2ed1b0e&v=4\n  url: https://github.com/mycaule\nAruelius:\n  login: Aruelius\n  count: 25\n  avatarUrl: https://avatars.githubusercontent.com/u/25380989?u=574f8cfcda3ea77a3f81884f6b26a97068e36a9d&v=4\n  url: https://github.com/Aruelius\nwisderfin:\n  login: wisderfin\n  count: 24\n  avatarUrl: https://avatars.githubusercontent.com/u/77553770?u=9a23740d520d65dc0051cdc1ecd87f31cb900313&v=4\n  url: https://github.com/wisderfin\nOzgunCaglarArslan:\n  login: OzgunCaglarArslan\n  count: 24\n  avatarUrl: https://avatars.githubusercontent.com/u/86166426?v=4\n  url: https://github.com/OzgunCaglarArslan\nycd:\n  login: ycd\n  count: 23\n  avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=f1e7bae394a315da950912c92dc861a8eaf95d4c&v=4\n  url: https://github.com/ycd\nsh0nk:\n  login: sh0nk\n  count: 23\n  avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4\n  url: https://github.com/sh0nk\naxel584:\n  login: axel584\n  count: 23\n  avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4\n  url: https://github.com/axel584\nDianaTrufanova:\n  login: DianaTrufanova\n  count: 23\n  avatarUrl: https://avatars.githubusercontent.com/u/119067607?u=1cd55f841b68b4a187fa6d06a7dafa5f070195aa&v=4\n  url: https://github.com/DianaTrufanova\nAGolicyn:\n  login: AGolicyn\n  count: 21\n  avatarUrl: https://avatars.githubusercontent.com/u/86262613?u=3c21606ab8d210a061a1673decff1e7d5592b380&v=4\n  url: https://github.com/AGolicyn\nAttsun1031:\n  login: Attsun1031\n  count: 20\n  avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4\n  url: https://github.com/Attsun1031\ndelhi09:\n  login: delhi09\n  count: 20\n  avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4\n  url: https://github.com/delhi09\nrogerbrinkmann:\n  login: rogerbrinkmann\n  count: 20\n  avatarUrl: https://avatars.githubusercontent.com/u/5690226?u=a1fe0aee927d33ce9db8c455eabc40c1cdf2bb65&v=4\n  url: https://github.com/rogerbrinkmann\nDevDae:\n  login: DevDae\n  count: 20\n  avatarUrl: https://avatars.githubusercontent.com/u/87962045?u=08e10fa516e844934f4b3fc7c38b33c61697e4a1&v=4\n  url: https://github.com/DevDae\nsattosan:\n  login: sattosan\n  count: 19\n  avatarUrl: https://avatars.githubusercontent.com/u/20574756?u=b0d8474d2938189c6954423ae8d81d91013f80a8&v=4\n  url: https://github.com/sattosan\nmaru0123-2004:\n  login: maru0123-2004\n  count: 19\n  avatarUrl: https://avatars.githubusercontent.com/u/43961566?u=16ed8603a4d6a4665cb6c53a7aece6f31379b769&v=4\n  url: https://github.com/maru0123-2004\nyes0ng:\n  login: yes0ng\n  count: 19\n  avatarUrl: https://avatars.githubusercontent.com/u/25501794?u=3aed18b0d491e0220a167a1e9e58bea3638c6707&v=4\n  url: https://github.com/yes0ng\nComicShrimp:\n  login: ComicShrimp\n  count: 18\n  avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=d2fbf412e7730183ce91686ca48d4147e1b7dc74&v=4\n  url: https://github.com/ComicShrimp\nsimatheone:\n  login: simatheone\n  count: 18\n  avatarUrl: https://avatars.githubusercontent.com/u/78508673?u=1b9658d9ee0bde33f56130dd52275493ddd38690&v=4\n  url: https://github.com/simatheone\nivan-abc:\n  login: ivan-abc\n  count: 18\n  avatarUrl: https://avatars.githubusercontent.com/u/36765187?u=c6e0ba571c1ccb6db9d94e62e4b8b5eda811a870&v=4\n  url: https://github.com/ivan-abc\nLimsunoh:\n  login: Limsunoh\n  count: 18\n  avatarUrl: https://avatars.githubusercontent.com/u/90311848?u=f456e0c5709fd50c8cd2898b551558eda14e5f21&v=4\n  url: https://github.com/Limsunoh\nSofiiaTrufanova:\n  login: SofiiaTrufanova\n  count: 18\n  avatarUrl: https://avatars.githubusercontent.com/u/63260929?u=483e0b64fabc76343b3be39b7e1dcb930a95e1bb&v=4\n  url: https://github.com/SofiiaTrufanova\nbezaca:\n  login: bezaca\n  count: 17\n  avatarUrl: https://avatars.githubusercontent.com/u/69092910?u=4ac58eab99bd37d663f3d23551df96d4fbdbf760&v=4\n  url: https://github.com/bezaca\nlbmendes:\n  login: lbmendes\n  count: 17\n  avatarUrl: https://avatars.githubusercontent.com/u/80999926?u=646619e2f07ac5a7c3f65fe7834197461a4fff9f&v=4\n  url: https://github.com/lbmendes\nspacesphere:\n  login: spacesphere\n  count: 17\n  avatarUrl: https://avatars.githubusercontent.com/u/34628304?u=cde91f6002dd33156e1bf8005f11a7a3ed76b790&v=4\n  url: https://github.com/spacesphere\npanko:\n  login: panko\n  count: 17\n  avatarUrl: https://avatars.githubusercontent.com/u/1569515?u=a84a5d255621ed82f8e1ca052f5f2eeb75997da2&v=4\n  url: https://github.com/panko\njeison-araya:\n  login: jeison-araya\n  count: 17\n  avatarUrl: https://avatars.githubusercontent.com/u/57369279?u=17001e68af7d8e5b8c343e5e9df4050f419998d5&v=4\n  url: https://github.com/jeison-araya\nyanever:\n  login: yanever\n  count: 16\n  avatarUrl: https://avatars.githubusercontent.com/u/21978760?v=4\n  url: https://github.com/yanever\nmastizada:\n  login: mastizada\n  count: 16\n  avatarUrl: https://avatars.githubusercontent.com/u/1975818?u=0751a06d7271c8bf17cb73b1b845644ab4d2c6dc&v=4\n  url: https://github.com/mastizada\nJoao-Pedro-P-Holanda:\n  login: Joao-Pedro-P-Holanda\n  count: 16\n  avatarUrl: https://avatars.githubusercontent.com/u/110267046?u=331bd016326dac4cf3df4848f6db2dbbf8b5f978&v=4\n  url: https://github.com/Joao-Pedro-P-Holanda\nJaeHyuckSa:\n  login: JaeHyuckSa\n  count: 16\n  avatarUrl: https://avatars.githubusercontent.com/u/104830931?u=f3b4a2baea550f428a4c602a30ebee6721c1e3df&v=4\n  url: https://github.com/JaeHyuckSa\nJedore:\n  login: Jedore\n  count: 15\n  avatarUrl: https://avatars.githubusercontent.com/u/17944025?u=81d503e1c800eb666b3861ca47a3a773bbc3f539&v=4\n  url: https://github.com/Jedore\nkim-sangah:\n  login: kim-sangah\n  count: 15\n  avatarUrl: https://avatars.githubusercontent.com/u/173775778?v=4\n  url: https://github.com/kim-sangah\nPandaHun:\n  login: PandaHun\n  count: 14\n  avatarUrl: https://avatars.githubusercontent.com/u/13096845?u=646eba44db720e37d0dbe8e98e77ab534ea78a20&v=4\n  url: https://github.com/PandaHun\ndukkee:\n  login: dukkee\n  count: 14\n  avatarUrl: https://avatars.githubusercontent.com/u/36825394?u=ccfd86e6a4f2d093dad6f7544cc875af67fa2df8&v=4\n  url: https://github.com/dukkee\nBORA040126:\n  login: BORA040126\n  count: 14\n  avatarUrl: https://avatars.githubusercontent.com/u/88664069?u=98e382727a485971e04aaa7c873d9a75a17ee3be&v=4\n  url: https://github.com/BORA040126\nmattkoehne:\n  login: mattkoehne\n  count: 14\n  avatarUrl: https://avatars.githubusercontent.com/u/80362153?v=4\n  url: https://github.com/mattkoehne\njovicon:\n  login: jovicon\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4\n  url: https://github.com/jovicon\nizaguerreiro:\n  login: izaguerreiro\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4\n  url: https://github.com/izaguerreiro\njburckel:\n  login: jburckel\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/11768758?u=044462e4130e086a0621f4abb45f0d7a289ab7fa&v=4\n  url: https://github.com/jburckel\npeidrao:\n  login: peidrao\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=979c62398e16ff000cc0faa028e028efd679887c&v=4\n  url: https://github.com/peidrao\nimpocode:\n  login: impocode\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/109408819?u=9cdfc5ccb31a2094c520f41b6087012fa9048982&v=4\n  url: https://github.com/impocode\nwaketzheng:\n  login: waketzheng\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/35413830?u=df19e4fd5bb928e7d086e053ef26a46aad23bf84&v=4\n  url: https://github.com/waketzheng\nwesinalves:\n  login: wesinalves\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/13563128?u=9eb17ed50645dd684bfec47e75dba4e9772ec9c1&v=4\n  url: https://github.com/wesinalves\nandersonrocha0:\n  login: andersonrocha0\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/22346169?u=93a1359c8c5461d894802c0cc65bcd09217e7a02&v=4\n  url: https://github.com/andersonrocha0\nNastasiaSaby:\n  login: NastasiaSaby\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/8245071?u=b3afd005f9e4bf080c219ef61a592b3a8004b764&v=4\n  url: https://github.com/NastasiaSaby\noandersonmagalhaes:\n  login: oandersonmagalhaes\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/83456692?u=daf5f302a59b950efc6d21129314af207e35441f&v=4\n  url: https://github.com/oandersonmagalhaes\nmkdir700:\n  login: mkdir700\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/56359329?u=818e5f4b4dcc1a6ffb3e5aaa08fd827e5a726dfd&v=4\n  url: https://github.com/mkdir700\nbatlopes:\n  login: batlopes\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4\n  url: https://github.com/batlopes\njoonas-yoon:\n  login: joonas-yoon\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/9527681?u=0166d22ef4749e617c6516e79f833cd8d73f1949&v=4\n  url: https://github.com/joonas-yoon\nbaseplate-admin:\n  login: baseplate-admin\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/61817579?u=ce4c268fa949ae9a0290996e7949195302055812&v=4\n  url: https://github.com/baseplate-admin\nKaniKim:\n  login: KaniKim\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/19832624?u=296dbdd490e0eb96e3d45a2608c065603b17dc31&v=4\n  url: https://github.com/KaniKim\ngitgernit:\n  login: gitgernit\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/129539613?u=d04f10143ab32c93f563ea14bf242d1d2bc991b0&v=4\n  url: https://github.com/gitgernit\nkwang1215:\n  login: kwang1215\n  count: 12\n  avatarUrl: https://avatars.githubusercontent.com/u/74170199?u=2a63ff6692119dde3f5e5693365b9fcd6f977b08&v=4\n  url: https://github.com/kwang1215\nAdrianDeAnda:\n  login: AdrianDeAnda\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/1024932?u=b2ea249c6b41ddf98679c8d110d0f67d4a3ebf93&v=4\n  url: https://github.com/AdrianDeAnda\nblt232018:\n  login: blt232018\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4\n  url: https://github.com/blt232018\nNinaHwang:\n  login: NinaHwang\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=241f2cb6d38a2d379536608a8ea5a22ed4b1a3ea&v=4\n  url: https://github.com/NinaHwang\nglsglsgls:\n  login: glsglsgls\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/76133879?v=4\n  url: https://github.com/glsglsgls\nk94-ishi:\n  login: k94-ishi\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/32672580?u=bc7c5c07af0656be9fe4f1784a444af8d81ded89&v=4\n  url: https://github.com/k94-ishi\ncodespearhead:\n  login: codespearhead\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/72931357?u=0fce6b82219b604d58adb614a761556425579cb5&v=4\n  url: https://github.com/codespearhead\nemrhnsyts:\n  login: emrhnsyts\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/42899027?u=ad26798e3f8feed2041c5dd5f87e58933d6c3283&v=4\n  url: https://github.com/emrhnsyts\nLufa1u:\n  login: Lufa1u\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/112495876?u=087658920ed9e74311597bdd921d8d2de939d276&v=4\n  url: https://github.com/Lufa1u\nKNChiu:\n  login: KNChiu\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/36751646?v=4\n  url: https://github.com/KNChiu\nZhongheng-Cheng:\n  login: Zhongheng-Cheng\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/95612344?u=a0f7730a3cc7486827965e01a119ad610bda4b0a&v=4\n  url: https://github.com/Zhongheng-Cheng\nPyth3rEx:\n  login: Pyth3rEx\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/26427764?u=087724f74d813c95925d51e354554bd4b6d6bb60&v=4\n  url: https://github.com/Pyth3rEx\nmariacamilagl:\n  login: mariacamilagl\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4\n  url: https://github.com/mariacamilagl\nryuckel:\n  login: ryuckel\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/36391432?u=094eec0cfddd5013f76f31e55e56147d78b19553&v=4\n  url: https://github.com/ryuckel\numitkaanusta:\n  login: umitkaanusta\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/53405015?v=4\n  url: https://github.com/umitkaanusta\nkty4119:\n  login: kty4119\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/49435654?v=4\n  url: https://github.com/kty4119\nRobotToI:\n  login: RobotToI\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/44951382?u=e41dbc19191ce7abed86694b1a44ea0523e1c60e&v=4\n  url: https://github.com/RobotToI\nvitumenezes:\n  login: vitumenezes\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/9680878?u=05fd25cfafdc09382bf8907c37293a696c205754&v=4\n  url: https://github.com/vitumenezes\nfcrozetta:\n  login: fcrozetta\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/8006246?u=fa2a743e803de2c3a84d3ed8042faefed16c5e43&v=4\n  url: https://github.com/fcrozetta\nsUeharaE4:\n  login: sUeharaE4\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/44468359?v=4\n  url: https://github.com/sUeharaE4\nErnilia:\n  login: Ernilia\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/125735800?u=13bfaac417a53fd5b5cf992efea363ca72598813&v=4\n  url: https://github.com/Ernilia\nsocket-socket:\n  login: socket-socket\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/121552599?u=104df6503242e8d762fe293e7036f7260f245d49&v=4\n  url: https://github.com/socket-socket\nnick-cjyx9:\n  login: nick-cjyx9\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/119087246?u=3d51dcbd79222ecb6538642f31dc7c8bb708d191&v=4\n  url: https://github.com/nick-cjyx9\nmarcelomarkus:\n  login: marcelomarkus\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/20115018?u=dda090ce9160ef0cd2ff69b1e5ea741283425cba&v=4\n  url: https://github.com/marcelomarkus\nlucasbalieiro:\n  login: lucasbalieiro\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/37416577?u=d144221c34c08adac8b20e1833d776ffa1c4b1d0&v=4\n  url: https://github.com/lucasbalieiro\nRunningIkkyu:\n  login: RunningIkkyu\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4\n  url: https://github.com/RunningIkkyu\nJulianMaurin:\n  login: JulianMaurin\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/63545168?u=b7d15ac865268cbefc2d739e2f23d9aeeac1a622&v=4\n  url: https://github.com/JulianMaurin\nJeongHyeongKim:\n  login: JeongHyeongKim\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/26577800?u=77f060f4686f32c248907b81b16ee2b3177ca44c&v=4\n  url: https://github.com/JeongHyeongKim\narthurio:\n  login: arthurio\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/950449?u=76b997138273ce5e1990b971c4f27c9aff979fd5&v=4\n  url: https://github.com/arthurio\nLenclove:\n  login: Lenclove\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/32355298?u=d0065e01650c63c2b2413f42d983634b2ea85481&v=4\n  url: https://github.com/Lenclove\neVery1337:\n  login: eVery1337\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/84917945?u=7af243f05ecfba59191199a70d8ba365c1327768&v=4\n  url: https://github.com/eVery1337\naykhans:\n  login: aykhans\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/88669260?u=798da457cc3276d3c6dd7fd628d0005ad8b298cc&v=4\n  url: https://github.com/aykhans\nriroan:\n  login: riroan\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/33053284?u=2d18e3771506ee874b66d6aa2b3b1107fd95c38f&v=4\n  url: https://github.com/riroan\nMinLee0210:\n  login: MinLee0210\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/57653278?u=e7c4d8d7eeb7bceed1680ef0e5dafec0695f57e0&v=4\n  url: https://github.com/MinLee0210\nyodai-yodai:\n  login: yodai-yodai\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/7031039?u=4f3593f5931892b931a745cfab846eff6e9332e7&v=4\n  url: https://github.com/yodai-yodai\nJoaoGustavoRogel:\n  login: JoaoGustavoRogel\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/29525510?u=a0a91251f5e43e132608d55d28ccb8645c5ea405&v=4\n  url: https://github.com/JoaoGustavoRogel\nvalentinDruzhinin:\n  login: valentinDruzhinin\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4\n  url: https://github.com/valentinDruzhinin\nYarous:\n  login: Yarous\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/61277193?u=5b462347458a373b2d599c6f416d2b75eddbffad&v=4\n  url: https://github.com/Yarous\ndimaqq:\n  login: dimaqq\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/662249?u=15313dec91bae789685e4abb3c2152251de41948&v=4\n  url: https://github.com/dimaqq\njulianofischer:\n  login: julianofischer\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/158303?u=d91662eb949d4cc7368831cf37a5cdfd90b7010c&v=4\n  url: https://github.com/julianofischer\nbnzone:\n  login: bnzone\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/39371503?u=c16f00c41d88479fa2d57b0d7d233b758eacce2d&v=4\n  url: https://github.com/bnzone\nshamosishen:\n  login: shamosishen\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/9498321?u=c83c20c79e019a0b555a125adf20fc4fb7a882c8&v=4\n  url: https://github.com/shamosishen\nmertssmnoglu:\n  login: mertssmnoglu\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/61623638?u=59dd885b68ff1832f9ab3b4a4446896358c23442&v=4\n  url: https://github.com/mertssmnoglu\nmahone3297:\n  login: mahone3297\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/1701379?u=20588ff0e456d13e8017333eb237595d11410234&v=4\n  url: https://github.com/mahone3297\nKimJoonSeo:\n  login: KimJoonSeo\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/17760162?u=a58cdc77ae1c069a64166f7ecc4d42eecfd9a468&v=4\n  url: https://github.com/KimJoonSeo\ncamigomezdev:\n  login: camigomezdev\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/16061815?u=25b5ebc042fff53fa03dc107ded10e36b1b7a5b9&v=4\n  url: https://github.com/camigomezdev\nminaton-ru:\n  login: minaton-ru\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/53541518?u=67336ca11a85493f75031508aade588dad3b9910&v=4\n  url: https://github.com/minaton-ru\nsungchan1:\n  login: sungchan1\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/28076127?u=fadbf24840186aca639d344bb3e0ecf7ff3441cf&v=4\n  url: https://github.com/sungchan1\nroli2py:\n  login: roli2py\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/61126128?u=bcb7a286e435a6b9d6a84b07db1232580ee796d4&v=4\n  url: https://github.com/roli2py\nSerrones:\n  login: Serrones\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4\n  url: https://github.com/Serrones\nisrateneda:\n  login: israteneda\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/20668624?u=67574648f89019d1c73b16a6a009da659557f9e5&v=4\n  url: https://github.com/israteneda\nkrocdort:\n  login: krocdort\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/34248814?v=4\n  url: https://github.com/krocdort\nanthonycepeda:\n  login: anthonycepeda\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=60bdf46240cff8fca482ff0fc07d963fd5e1a27c&v=4\n  url: https://github.com/anthonycepeda\nfabioueno:\n  login: fabioueno\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/14273852?u=a3d546449cdc96621c32bcc26cf74be6e4390209&v=4\n  url: https://github.com/fabioueno\ncfraboulet:\n  login: cfraboulet\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/62244267?u=ed0e286ba48fa1dafd64a08e50f3364b8e12df34&v=4\n  url: https://github.com/cfraboulet\nHiemalBeryl:\n  login: HiemalBeryl\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/63165207?u=276f4af2829baf28b912c718675852bfccb0e7b4&v=4\n  url: https://github.com/HiemalBeryl\npablocm83:\n  login: pablocm83\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/28315068?u=3310fbb05bb8bfc50d2c48b6cb64ac9ee4a14549&v=4\n  url: https://github.com/pablocm83\nd2a-raudenaerde:\n  login: d2a-raudenaerde\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/5213150?u=e6d0ef65c571c7e544fc1c7ec151c7c0a72fb6bb&v=4\n  url: https://github.com/d2a-raudenaerde\nZerohertz:\n  login: Zerohertz\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/42334717?u=5ebf4d33e73b1ad373154f6cdee44f7cab4d05ba&v=4\n  url: https://github.com/Zerohertz\nEdmilsonRodrigues:\n  login: EdmilsonRodrigues\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/62777025?u=217d6f3cd6cc750bb8818a3af7726c8d74eb7c2d&v=4\n  url: https://github.com/EdmilsonRodrigues\ndeniscapeto:\n  login: deniscapeto\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/12864353?u=20c5b2300b264a585a8381acf3cef44bcfcc1ead&v=4\n  url: https://github.com/deniscapeto\nbsab:\n  login: bsab\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/9799799?u=c4a09b1abb794cd8280c4793d43d0e2eb963ecda&v=4\n  url: https://github.com/bsab\nArcLightSlavik:\n  login: ArcLightSlavik\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4\n  url: https://github.com/ArcLightSlavik\nCajuteq:\n  login: Cajuteq\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/26676532?u=8ee0422981810e51480855de1c0d67b6b79cd3f2&v=4\n  url: https://github.com/Cajuteq\nemmrichard:\n  login: emmrichard\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/1328018?u=8114d8fc0e8e42a092e4283013a1c54b792c466b&v=4\n  url: https://github.com/emmrichard\nwakabame:\n  login: wakabame\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/35513518?u=41ef6b0a55076e5c540620d68fb006e386c2ddb0&v=4\n  url: https://github.com/wakabame\nmawassk:\n  login: mawassk\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/84179197?v=4\n  url: https://github.com/mawassk\ndiogoduartec:\n  login: diogoduartec\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/31852339?u=7514a5f05fcbeccc62f8c5dc25879efeb1ef9335&v=4\n  url: https://github.com/diogoduartec\naqcool:\n  login: aqcool\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/52229895?v=4\n  url: https://github.com/aqcool\n'1320555911':\n  login: '1320555911'\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/58590086?u=6d8f4fbf08d5ac72c1c895892c461c5e0b013dc3&v=4\n  url: https://github.com/1320555911\nmcthesw:\n  login: mcthesw\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/61224072?u=82a1b106298348f060c3f4f39817e0cae5ce2b7c&v=4\n  url: https://github.com/mcthesw\nxzmeng:\n  login: xzmeng\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/40202897?v=4\n  url: https://github.com/xzmeng\nnegadive:\n  login: negadive\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/47322392?u=c1be2e9b9b346b4a77d9157da2a5739ab25ce0f8&v=4\n  url: https://github.com/negadive\nmbroton:\n  login: mbroton\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/50829834?u=a48610bf1bffaa9c75d03228926e2eb08a2e24ee&v=4\n  url: https://github.com/mbroton\nKirilex:\n  login: Kirilex\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/100281552?v=4\n  url: https://github.com/Kirilex\narunppsg:\n  login: arunppsg\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/26398753?v=4\n  url: https://github.com/arunppsg\ndimastbk:\n  login: dimastbk\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/3132181?u=66587398d43466a1dc75c238df5f048e0afc77ed&v=4\n  url: https://github.com/dimastbk\ndudyaosuplayer:\n  login: dudyaosuplayer\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/62661898?u=7864cc5f01b1c845ae8ad49acf45dec6faca0c57&v=4\n  url: https://github.com/dudyaosuplayer\ntalhaumer:\n  login: talhaumer\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/46643702?u=5d1fd7057ea9534fb3221931b809a3d750157212&v=4\n  url: https://github.com/talhaumer\nbankofsardine:\n  login: bankofsardine\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/44944207?u=0368e1b698ffab6bf29e202f9fd2dddd352429f1&v=4\n  url: https://github.com/bankofsardine\nRekl0w:\n  login: Rekl0w\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/91488737?u=7d2b7791665e04a12695150776a1d516a6ea7d21&v=4\n  url: https://github.com/Rekl0w\nrsip22:\n  login: rsip22\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/16676222?v=4\n  url: https://github.com/rsip22\njessicapaz:\n  login: jessicapaz\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/20428941?u=6ffdaab5a85bf77a2d8870dade5e53555f34577b&v=4\n  url: https://github.com/jessicapaz\nmohsen-mahmoodi:\n  login: mohsen-mahmoodi\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/2872586?u=3a9fc1aa16a3a0ab93a1f8550de82a940592857d&v=4\n  url: https://github.com/mohsen-mahmoodi\njeesang7:\n  login: jeesang7\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/30719956?u=35fc8bca04d32d3c4ce085956f0636b959ba30f6&v=4\n  url: https://github.com/jeesang7\nTemaSpb:\n  login: TemaSpb\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/20205738?u=d7dce0718720a7107803a573d628d8dd3d5c2fb4&v=4\n  url: https://github.com/TemaSpb\nBugLight:\n  login: BugLight\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/13618366?u=7d733749f80e5f7e66a434cf42aedcfc60340f43&v=4\n  url: https://github.com/BugLight\n0x4Dark:\n  login: 0x4Dark\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/7569289?v=4\n  url: https://github.com/0x4Dark\nWuerike:\n  login: Wuerike\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/35462243?u=80c753dedf4a78db12ef66316dbdebbe6d84a2b9&v=4\n  url: https://github.com/Wuerike\njvmazagao:\n  login: jvmazagao\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/22477816?u=2b57addf5830906bf6ae5f25cd4c8c2fa5c2d68e&v=4\n  url: https://github.com/jvmazagao\ncun3yt:\n  login: cun3yt\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/24409240?u=06abfd77786db859b0602d5369d2ae18c932c17c&v=4\n  url: https://github.com/cun3yt\nMordson:\n  login: Mordson\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/39025897?u=b94ea96ef35bbe43bc85359cfb31d28ac16d470c&v=4\n  url: https://github.com/Mordson\naminkhani:\n  login: aminkhani\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/51851950?u=051896c4933816bc61d11091d887f6e8dfd1d27b&v=4\n  url: https://github.com/aminkhani\nnifadyev:\n  login: nifadyev\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/36514612?u=e101da8641d5a09901d2155255a93f8ab3d9c468&v=4\n  url: https://github.com/nifadyev\nLaurEars:\n  login: LaurEars\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/4914725?v=4\n  url: https://github.com/LaurEars\nChushine:\n  login: Chushine\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/135534400?v=4\n  url: https://github.com/Chushine\nChuyuChoyeon:\n  login: ChuyuChoyeon\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/129537877?u=f0c76f3327817a8b86b422d62e04a34bf2827f2b&v=4\n  url: https://github.com/ChuyuChoyeon\nfrwl404:\n  login: frwl404\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/42642656?u=8395a3d991d9fac86901277d76f0f70857b56ec5&v=4\n  url: https://github.com/frwl404\nesrefzeki:\n  login: esrefzeki\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/54935247?u=193cf5a169ca05fc54995a4dceabc82c7dc6e5ea&v=4\n  url: https://github.com/esrefzeki\ndtleal:\n  login: dtleal\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/31096951?u=704664ec74ab655485e5c909b25de3fa09a922ba&v=4\n  url: https://github.com/dtleal\nart3xa:\n  login: art3xa\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/92092049?v=4\n  url: https://github.com/art3xa\nSamuelBFavarin:\n  login: SamuelBFavarin\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/17628602?u=5aac13ae492fa9a86e397a70803ac723dba2efe7&v=4\n  url: https://github.com/SamuelBFavarin\ntakacs:\n  login: takacs\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/44911031?u=f6c6b70b3ba86ceb93b0f9bcab609bf9328b2305&v=4\n  url: https://github.com/takacs\nanton2yakovlev:\n  login: anton2yakovlev\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/44229180?u=ac245e57bc834ff80f08ca8128000bb650a77a3d&v=4\n  url: https://github.com/anton2yakovlev\nILoveSorasakiHina:\n  login: ILoveSorasakiHina\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/114038930?u=3d3ed8dc3bf57e641d1b26badee5bc79ef34f25b&v=4\n  url: https://github.com/ILoveSorasakiHina\ndevluisrodrigues:\n  login: devluisrodrigues\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/103431660?u=d9674a3249edc4601d2c712cdebf899918503c3a&v=4\n  url: https://github.com/devluisrodrigues\n11kkw:\n  login: 11kkw\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/21125286?v=4\n  url: https://github.com/11kkw\nlpdswing:\n  login: lpdswing\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/20874036?u=7a4fc3e4d0719e37b305deb7af234a7b63200787&v=4\n  url: https://github.com/lpdswing\nSepehrRasouli:\n  login: SepehrRasouli\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/81516241?u=3987e880c77d653dd85963302150e07bb7c0ef99&v=4\n  url: https://github.com/SepehrRasouli\nZxilly:\n  login: Zxilly\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/31370133?u=c5359b8d9d80a7cdc23d5295d179ed90174996c8&v=4\n  url: https://github.com/Zxilly\neavv:\n  login: eavv\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/18273429?u=c05e8b4ea62810ee7889ca049e510cdd0a66fd26&v=4\n  url: https://github.com/eavv\nAlexandreBiguet:\n  login: AlexandreBiguet\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/1483079?u=ff926455cd4cab03c6c49441aa5dc2b21df3e266&v=4\n  url: https://github.com/AlexandreBiguet\nFelipeSilva93:\n  login: FelipeSilva93\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/66804965?u=e7cb4b580e46f2e04ecb4cd4d7a12acdddd3c6c1&v=4\n  url: https://github.com/FelipeSilva93\npeacekimjapan:\n  login: peacekimjapan\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/33534175?u=e4219bcebc3773a7068cc34c3eb268ef77cec31b&v=4\n  url: https://github.com/peacekimjapan\nbas-baskara:\n  login: bas-baskara\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/41407847?u=cdabfaff7481c3323f24a76d9350393b964f2b89&v=4\n  url: https://github.com/bas-baskara\nodiseo0:\n  login: odiseo0\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=75e754b9bd12ce6dfe90ad68e82e6f5255c7ac09&v=4\n  url: https://github.com/odiseo0\neryknn:\n  login: eryknn\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/87120651?v=4\n  url: https://github.com/eryknn\npersonage-hub:\n  login: personage-hub\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/76659786?v=4\n  url: https://github.com/personage-hub\naminalaee:\n  login: aminalaee\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/19784933?v=4\n  url: https://github.com/aminalaee\nerfan-rfmhr:\n  login: erfan-rfmhr\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/98986056?u=0acda1ff1df0989f3f3eb79977baa35da4cb6c8c&v=4\n  url: https://github.com/erfan-rfmhr\nScorpionchiques:\n  login: Scorpionchiques\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/15703294?v=4\n  url: https://github.com/Scorpionchiques\nlordqyxz:\n  login: lordqyxz\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/31722468?u=974553c0ba53526d9be7e9876544283291be3b0d&v=4\n  url: https://github.com/lordqyxz\nheysaeid:\n  login: heysaeid\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/63112273?u=5397ead391319a147a18b70cc04d1a334f235ef3&v=4\n  url: https://github.com/heysaeid\nYois4101:\n  login: Yois4101\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/119609381?v=4\n  url: https://github.com/Yois4101\ntamtam-fitness:\n  login: tamtam-fitness\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/62091034?u=8da19a6bd3d02f5d6ba30c7247d5b46c98dd1403&v=4\n  url: https://github.com/tamtam-fitness\nmpmeleshko:\n  login: mpmeleshko\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/34425664?v=4\n  url: https://github.com/mpmeleshko\nSonnyYou:\n  login: SonnyYou\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/18657569?v=4\n  url: https://github.com/SonnyYou\nmatiasbertani:\n  login: matiasbertani\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/65260383?u=d5edd86a6e2ab4fb1aab7751931fe045a963afd7&v=4\n  url: https://github.com/matiasbertani\nthiennc254:\n  login: thiennc254\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/97406628?u=1b2860679694b9a552764d0fa81dbd7a016322ec&v=4\n  url: https://github.com/thiennc254\njavillegasna:\n  login: javillegasna\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/38879192?u=df9ab0d628f8c1f1c849db7b3c0939337f42c3f1&v=4\n  url: https://github.com/javillegasna\n9zimin9:\n  login: 9zimin9\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/174453744?v=4\n  url: https://github.com/9zimin9\nilhamfadillah:\n  login: ilhamfadillah\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/20577838?u=c56192cf99b55affcaad408b240259c62e633450&v=4\n  url: https://github.com/ilhamfadillah\ngerry-sabar:\n  login: gerry-sabar\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/1120123?v=4\n  url: https://github.com/gerry-sabar\ncookie-byte217:\n  login: cookie-byte217\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/57880178?v=4\n  url: https://github.com/cookie-byte217\nAbolfazlKameli:\n  login: AbolfazlKameli\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/120686133?u=af8f025278cce0d489007071254e4055df60b78c&v=4\n  url: https://github.com/AbolfazlKameli\nSBillion:\n  login: SBillion\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/1070649?u=3ab493dfc88b39da0eb1600e3b8e7df1c90a5dee&v=4\n  url: https://github.com/SBillion\nseuthootDev:\n  login: seuthootDev\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/175179350?u=7c2cbc48ab43b52e0c86592111d92e013d72ea4d&v=4\n  url: https://github.com/seuthootDev\ntyronedamasceno:\n  login: tyronedamasceno\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/12273721?u=913bca6bab96d9416ad8c9874c80de0833782050&v=4\n  url: https://github.com/tyronedamasceno\nLikoIlya:\n  login: LikoIlya\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/15039930?v=4\n  url: https://github.com/LikoIlya\nss-o-furda:\n  login: ss-o-furda\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/56111536?u=d2326baa464a3778c280ed85fd14c00f87eb1080&v=4\n  url: https://github.com/ss-o-furda\nFrans06:\n  login: Frans06\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/5842109?u=77529d5517ae80438249b1a45f2d59372a31a212&v=4\n  url: https://github.com/Frans06\nJefidev:\n  login: Jefidev\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/9964497?u=1da6eee587a8b425ca4afbfdfc6c3a639fe85d02&v=4\n  url: https://github.com/Jefidev\nXaraxx:\n  login: Xaraxx\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/29824698?u=dde2e233e22bb5ca1f8bb0c6e353ccd0d06e6066&v=4\n  url: https://github.com/Xaraxx\nSuyoung789:\n  login: Suyoung789\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/31277231?u=1591aaf651eb860017231a36590050e154c026b6&v=4\n  url: https://github.com/Suyoung789\nakagaeng:\n  login: akagaeng\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/17076841?u=9ada2eb6a33dc705ba96d58f802c787dea3859b8&v=4\n  url: https://github.com/akagaeng\nphamquanganh31101998:\n  login: phamquanganh31101998\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/43257497?u=6b3419ea9e318c356c42a973fb947682590bd8d3&v=4\n  url: https://github.com/phamquanganh31101998\npeebbv6364:\n  login: peebbv6364\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/26784747?u=3bf07017eb4f4fa3639ba8d4ed19980a34bf8f90&v=4\n  url: https://github.com/peebbv6364\nmrparalon:\n  login: mrparalon\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/19637629?u=6339508ceb665717cae862a4d33816ac874cbb8f&v=4\n  url: https://github.com/mrparalon\ncreyD:\n  login: creyD\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/15138480?u=51cd2873cd93807beb578af8e23975856fdbc945&v=4\n  url: https://github.com/creyD\nzhoonit:\n  login: zhoonit\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/17230883?u=698cb26dcce4770374b592aad3b7489e91c07fc6&v=4\n  url: https://github.com/zhoonit\nSefank:\n  login: Sefank\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/12670778?u=ca16995c68a82cabc7435c54ac0564930f62dd59&v=4\n  url: https://github.com/Sefank\nRuslanTer:\n  login: RuslanTer\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/48125303?v=4\n  url: https://github.com/RuslanTer\nFedorGN:\n  login: FedorGN\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/66411909?u=22382380e7d66ee57ffbfc2ae6bd5efd0cdb672e&v=4\n  url: https://github.com/FedorGN\nrafsaf:\n  login: rafsaf\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=5fe59a56e1f2f9ccd8005d71752a8276f133ae1a&v=4\n  url: https://github.com/rafsaf\nfrnsimoes:\n  login: frnsimoes\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/66239468?u=bd788dabd4d9321455db8b8751c1a2676783f50f&v=4\n  url: https://github.com/frnsimoes\nlieryan:\n  login: lieryan\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/1006989?v=4\n  url: https://github.com/lieryan\nValeryVal:\n  login: ValeryVal\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/85856176?v=4\n  url: https://github.com/ValeryVal\nchesstrian:\n  login: chesstrian\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/3923412?u=8ea9bea6cfb5e6c64dc81be65ac2a9aaf23c5d47&v=4\n  url: https://github.com/chesstrian\nPabloEmidio:\n  login: PabloEmidio\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/69937719?u=f4d04cb78da68bb93a641f0b793ff665162e712a&v=4\n  url: https://github.com/PabloEmidio\nPraveenNanda124:\n  login: PraveenNanda124\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/116082827?u=b40c4f23c191692e88f676dc3bf33fc7f315edd4&v=4\n  url: https://github.com/PraveenNanda124\nguites:\n  login: guites\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/71985299?u=5dab5eb82b0a67fe709fc893f47a423df4de5d46&v=4\n  url: https://github.com/guites\nJunhyung21:\n  login: Junhyung21\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/138214497?u=66377988eaad4f57004decb183f396560407a73f&v=4\n  url: https://github.com/Junhyung21\nrinaatt:\n  login: rinaatt\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/6111202?u=9f62ebd2a72879db54d0b51c07c1d1e7203a4813&v=4\n  url: https://github.com/rinaatt\nSlijeff:\n  login: Slijeff\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/31459252?u=083776331690bbcf427766071e33ac28bb8d271d&v=4\n  url: https://github.com/Slijeff\nGeorchW:\n  login: GeorchW\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/8687777?u=ae4160f1d88f32692760003f3be9b5fc40a6e00d&v=4\n  url: https://github.com/GeorchW\nVlad0395:\n  login: Vlad0395\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/37487589?u=57dc6660b9904cc0bc59b73569bbfb1ac871a4a1&v=4\n  url: https://github.com/Vlad0395\nbisibuka:\n  login: bisibuka\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/221887?v=4\n  url: https://github.com/bisibuka\naimasheraz1:\n  login: aimasheraz1\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/132935019?v=4\n  url: https://github.com/aimasheraz1\nwhysage:\n  login: whysage\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/67018871?u=a05d63a1b315dcf56a4c0dda3c0ca84ce3d6c87f&v=4\n  url: https://github.com/whysage\nChake9928:\n  login: Chake9928\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/62596047?u=7aa2c0aad46911934ce3d22f83a895d05fa54e09&v=4\n  url: https://github.com/Chake9928\nqaerial:\n  login: qaerial\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/41595550?v=4\n  url: https://github.com/qaerial\nbluefish6:\n  login: bluefish6\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/3324881?u=d107f6d0017927191644829fb845a8ceb8ac20ee&v=4\n  url: https://github.com/bluefish6\nSion99:\n  login: Sion99\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/82511301?v=4\n  url: https://github.com/Sion99\nnymous:\n  login: nymous\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4\n  url: https://github.com/nymous\nEpsilonRationes:\n  login: EpsilonRationes\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/148639079?u=5dd6c4a3f570dea44d208465fd10b709bcdfa69a&v=4\n  url: https://github.com/EpsilonRationes\nSametEmin:\n  login: SametEmin\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/115692383?u=bda9052f698e50b0df6657fb9436d07e8496fe2f&v=4\n  url: https://github.com/SametEmin\nfhabers21:\n  login: fhabers21\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/58401847?v=4\n  url: https://github.com/fhabers21\nkohiry:\n  login: kohiry\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/57669492?u=f6ab0a062740261e882879269a41a47788c84043&v=4\n  url: https://github.com/kohiry\nptt3199:\n  login: ptt3199\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/51350651?u=2c3d947a80283e32bf616d4c3af139a6be69680f&v=4\n  url: https://github.com/ptt3199\narynoot:\n  login: arynoot\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/73756088?v=4\n  url: https://github.com/arynoot\nGDemay:\n  login: GDemay\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/7033942?u=bbdcb4e2a67df4ec9caa2440362d8cebc44d65e8&v=4\n  url: https://github.com/GDemay\nmaxscheijen:\n  login: maxscheijen\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/47034840?v=4\n  url: https://github.com/maxscheijen\ncelestywang:\n  login: celestywang\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/184830753?v=4\n  url: https://github.com/celestywang\nRyaWcksn:\n  login: RyaWcksn\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/42831964?u=0cb4265faf3e3425a89e59b6fddd3eb2de180af0&v=4\n  url: https://github.com/RyaWcksn\ntienduong-21:\n  login: tienduong-21\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/80129618?v=4\n  url: https://github.com/tienduong-21\nzbellos:\n  login: zbellos\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/204500646?v=4\n  url: https://github.com/zbellos\nMohammad222PR:\n  login: Mohammad222PR\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/116789737?u=25810a5fe049d2f1618e2e7417cea011cc353ce4&v=4\n  url: https://github.com/Mohammad222PR\nblaisep:\n  login: blaisep\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/254456?u=97d584b7c0a6faf583aa59975df4f993f671d121&v=4\n  url: https://github.com/blaisep\nSirTelemak:\n  login: SirTelemak\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4\n  url: https://github.com/SirTelemak\novezovs:\n  login: ovezovs\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/44060682?u=9cb4d738b15e64157cb65afbe2e31bd0c8f3f6e6&v=4\n  url: https://github.com/ovezovs\nneatek:\n  login: neatek\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/3075678?u=3001e778e4aa0bf6d3142d09f0b9d13b2c55066f&v=4\n  url: https://github.com/neatek\nsprytnyk:\n  login: sprytnyk\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/16718258?u=4893ea96bfebfbdbde8abd9e06851eca12b01bc9&v=4\n  url: https://github.com/sprytnyk\nwfpinedar:\n  login: wfpinedar\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/5309214?u=4af7b6b3907b015699a9994d0808137dd68f7658&v=4\n  url: https://github.com/wfpinedar\nitalopenaforte:\n  login: italopenaforte\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/7786881?u=e64a8f24b1ba95eb82f283be8ab90892e40c5465&v=4\n  url: https://github.com/italopenaforte\nhackerneocom:\n  login: hackerneocom\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/67042948?u=ca365045bd261cec5a64059aa23cf80065148c3c&v=4\n  url: https://github.com/hackerneocom\ndmas-at-wiris:\n  login: dmas-at-wiris\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/24917162?u=0df147936a375b4b64232c650de31a227a6b59a0&v=4\n  url: https://github.com/dmas-at-wiris\nTorhamDev:\n  login: TorhamDev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/87639984?u=07e5429fbd9c5d63c5ca55a0f31ef541216f0ce6&v=4\n  url: https://github.com/TorhamDev\njaystone776:\n  login: jaystone776\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4\n  url: https://github.com/jaystone776\nAaronDewes:\n  login: AaronDewes\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/67546953?v=4\n  url: https://github.com/AaronDewes\nkunansy:\n  login: kunansy\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/20476946?u=d8321cd00787d5ee29bfdd8ff6fde23ad783a581&v=4\n  url: https://github.com/kunansy\nTimorChow:\n  login: TimorChow\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/18365403?u=bcbb357be0a447bc682a161932eab5032cede4af&v=4\n  url: https://github.com/TimorChow\nataberkciftlikli:\n  login: ataberkciftlikli\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/64265169?u=ca7c1348242559f70bc1dc027a4be277c464676f&v=4\n  url: https://github.com/ataberkciftlikli\nleandrodesouzadev:\n  login: leandrodesouzadev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/85115541?u=4eb25f43f1fe23727d61e986cf83b73b86e2a95a&v=4\n  url: https://github.com/leandrodesouzadev\ndutkiewicz:\n  login: dutkiewicz\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6649846?u=e941be6e1ab2ffdf41cea227a73f0ffbef20628f&v=4\n  url: https://github.com/dutkiewicz\nmirusu400:\n  login: mirusu400\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/25397908?u=deda776115e4ee6f76fa526bb5127bd1a6c4b231&v=4\n  url: https://github.com/mirusu400\nits0x08:\n  login: its0x08\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/15280042?u=d7c2058f29d4e8fbdae09b194e04c5e410350211&v=4\n  url: https://github.com/its0x08\nlinsein:\n  login: linsein\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/23748021?u=4db169ce262b69aa7292f82b785436544f69fb88&v=4\n  url: https://github.com/linsein\n0xflotus:\n  login: 0xflotus\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/26602940?u=3c52ce6393bb547c97e6380ccdee03e0c64152c6&v=4\n  url: https://github.com/0xflotus\njonatasoli:\n  login: jonatasoli\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=f601c3f111f2148bd9244c2cb3ebbd57b592e674&v=4\n  url: https://github.com/jonatasoli\ntyzh-dev:\n  login: tyzh-dev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/51972581?u=ba3882da7c009918a8e2d6b9ead31c89f09c922d&v=4\n  url: https://github.com/tyzh-dev\nyurkevich-dev:\n  login: yurkevich-dev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/45145188?u=db2de8c186073d95693279dcf085fcebffab57d0&v=4\n  url: https://github.com/yurkevich-dev\nemp7yhead:\n  login: emp7yhead\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/20521260?u=9494c74cb9e1601d734b1f2726e292e257777d98&v=4\n  url: https://github.com/emp7yhead\nBartoszCki:\n  login: BartoszCki\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/17833351?u=40025e1182c32a9664834baec268dadad127703d&v=4\n  url: https://github.com/BartoszCki\nhakancelikdev:\n  login: hakancelikdev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/19157033?u=095ea8e0af1de642edd92e5f806c70359e00c977&v=4\n  url: https://github.com/hakancelikdev\nKaterinaSolovyeva:\n  login: KaterinaSolovyeva\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/85114725?u=1fe81463cb6b1fd01ac047172fa4895e2a3cecaa&v=4\n  url: https://github.com/KaterinaSolovyeva\nzhanymkanov:\n  login: zhanymkanov\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/22341602?u=aa1c47285a4f5692d165ccb2a441c5553f23ef83&v=4\n  url: https://github.com/zhanymkanov\nfelipebpl:\n  login: felipebpl\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/62957465?u=3c05f0f358b9575503c03122daefb115b6ac1414&v=4\n  url: https://github.com/felipebpl\niudeen:\n  login: iudeen\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=f09cdd745e5bf16138f29b42732dd57c7f02bee1&v=4\n  url: https://github.com/iudeen\ndwisulfahnur:\n  login: dwisulfahnur\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/12431528?v=4\n  url: https://github.com/dwisulfahnur\nayr-ton:\n  login: ayr-ton\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1090517?u=5cf70a0e0f0dbf084e074e494aa94d7c91a46ba6&v=4\n  url: https://github.com/ayr-ton\nKadermiyanyedi:\n  login: Kadermiyanyedi\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/48386782?u=08c0f1594c5baf28b6fab7520a848cb9c3806c8e&v=4\n  url: https://github.com/Kadermiyanyedi\nraphaelauv:\n  login: raphaelauv\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4\n  url: https://github.com/raphaelauv\nFahad-Md-Kamal:\n  login: Fahad-Md-Kamal\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/34704464?u=0b1da22a9b88b14d99e7e4368eadde7ecd695366&v=4\n  url: https://github.com/Fahad-Md-Kamal\nzxcq544:\n  login: zxcq544\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/5781268?u=25959ea03803742c3b28220b27fc07923a491dcb&v=4\n  url: https://github.com/zxcq544\nAlexandrMaltsevYDX:\n  login: AlexandrMaltsevYDX\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/109986802?u=ed275d72bfcdb4d15abdd54e7be026adbb9ca098&v=4\n  url: https://github.com/AlexandrMaltsevYDX\nrealFranco:\n  login: realFranco\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/45880759?u=22fea3007d3e2d4c8c82d6ccfbde71454c4c6dd8&v=4\n  url: https://github.com/realFranco\npiaria:\n  login: piaria\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/110835535?u=5af3d56254faa05bbca4258a46c5723489480f90&v=4\n  url: https://github.com/piaria\nmojtabapaso:\n  login: mojtabapaso\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/121169359?u=ced1d5ad673bcd9e949ebf967a4ab50185637443&v=4\n  url: https://github.com/mojtabapaso\neghbalpoorMH:\n  login: eghbalpoorMH\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/36267498?v=4\n  url: https://github.com/eghbalpoorMH\nTiazen:\n  login: Tiazen\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/16170159?u=0ce5e32f76e3f10733c8f25d97db9e31b753838c&v=4\n  url: https://github.com/Tiazen\njfunez:\n  login: jfunez\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/805749?v=4\n  url: https://github.com/jfunez\ns-rigaud:\n  login: s-rigaud\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/46346622?u=eee0adaa9fdff9e312d52526fbd4020dd6860c27&v=4\n  url: https://github.com/s-rigaud\nArtem4es:\n  login: Artem4es\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/110793967?u=0f9d4e80e055adc1aa8b548e951f6b4989fa2e78&v=4\n  url: https://github.com/Artem4es\nsulemanhelp:\n  login: sulemanhelp\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/22400366?u=3e8e68750655c7f5b2e0ba1d54f5779ee526707d&v=4\n  url: https://github.com/sulemanhelp\ntheRealNonso:\n  login: theRealNonso\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/29557286?u=6f062680edccfeb4c802daf3b1d8b2a9e21ae013&v=4\n  url: https://github.com/theRealNonso\nAhsanSheraz:\n  login: AhsanSheraz\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/51913596?u=b5aa3c3a004cc0112e56c54f6901941836d8c26b&v=4\n  url: https://github.com/AhsanSheraz\nHealerNguyen:\n  login: HealerNguyen\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/29653304?u=6ab095689054c63b1f4ceb26dd66847450225c87&v=4\n  url: https://github.com/HealerNguyen\nisulim:\n  login: isulim\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/30448496?u=44c47838defa48a16606b895dce08890fca8482f&v=4\n  url: https://github.com/isulim\nsiavashyj:\n  login: siavashyj\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/43583410?u=562005ddc7901cd27a1219a118a2363817b14977&v=4\n  url: https://github.com/siavashyj\nRamin-RX7:\n  login: Ramin-RX7\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/52785580?u=b3678f779ad0ee9cd9dca9e50ccb804b5eb990a5&v=4\n  url: https://github.com/Ramin-RX7\nDevSpace88:\n  login: DevSpace88\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/102557040?u=103e454f0d4d2d357bd66e9931e57f0bf267526a&v=4\n  url: https://github.com/DevSpace88\nYum-git:\n  login: Yum-git\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/56100888?u=7c6ae21af081488b5fb703ab096fb1926025fd50&v=4\n  url: https://github.com/Yum-git\noubush:\n  login: oubush\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/7489099?u=c86448bc61f5e7f03a1f14a768beeb09c33899d4&v=4\n  url: https://github.com/oubush\nKAZAMA-DREAM:\n  login: KAZAMA-DREAM\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/73453137?u=5108c757a3842733a448d9a16cdc65d82899eee1&v=4\n  url: https://github.com/KAZAMA-DREAM\naprilcoskun:\n  login: aprilcoskun\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/17393603?u=18177d5bdba3a4567b8664587c882fb734e5fa09&v=4\n  url: https://github.com/aprilcoskun\nzhiquanchi:\n  login: zhiquanchi\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/29973289?u=744c74bc2635f839235ec32a0a934c5cef9a156d&v=4\n  url: https://github.com/zhiquanchi\nJamim:\n  login: Jamim\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/5607572?u=9ce0b6a6d1a5124e28b3c04d8d26827ca328713a&v=4\n  url: https://github.com/Jamim\nalvinkhalil:\n  login: alvinkhalil\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/84583022?u=ab0eeb9ce6ffe93fd9bb23daf782b9867b864149&v=4\n  url: https://github.com/alvinkhalil\nleylaeminova:\n  login: leylaeminova\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/100516839?u=0b0dab9e31742076b22812b14a39b4e6d8f6de4a&v=4\n  url: https://github.com/leylaeminova\nUN-9BOT:\n  login: UN-9BOT\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/111110804?u=39e158937ed795972c2d0400fc521c50e9bfb9e7&v=4\n  url: https://github.com/UN-9BOT\nflasonme:\n  login: flasonme\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/30571019?v=4\n  url: https://github.com/flasonme\ngustavoprezoto:\n  login: gustavoprezoto\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/62812585?u=2e936a0c6a2f11ecf3a735ebd33386100bcfebf8&v=4\n  url: https://github.com/gustavoprezoto\njohnny630:\n  login: johnny630\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/2870590?v=4\n  url: https://github.com/johnny630\nJCTrapero:\n  login: JCTrapero\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/109148166?u=bea607a04058176c4c2ae0d7c2e9ec647ccef002&v=4\n  url: https://github.com/JCTrapero\nZhibangYue:\n  login: ZhibangYue\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/93324586?u=20fb23e3718e0364bb217966470d35e0637dd4fe&v=4\n  url: https://github.com/ZhibangYue\nsaeye:\n  login: saeye\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/62229734?u=312d619db2588b60d5d5bde65260a2f44fdc6c76&v=4\n  url: https://github.com/saeye\nHeumhub:\n  login: Heumhub\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/173761521?v=4\n  url: https://github.com/Heumhub\nmanumolina:\n  login: manumolina\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/2404208?u=fdc5502910f8dec814b2477f89587b9e45fac846&v=4\n  url: https://github.com/manumolina\nlogan2d5:\n  login: logan2d5\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/146642263?u=dbd6621f8b0330d6919f6a7131277b92e26fbe87&v=4\n  url: https://github.com/logan2d5\nguspan-tanadi:\n  login: guspan-tanadi\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/36249910?v=4\n  url: https://github.com/guspan-tanadi\ntiaggo16:\n  login: tiaggo16\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/62227573?u=359f4e2c51a4b13c8553ac5af405d635b07bb61f&v=4\n  url: https://github.com/tiaggo16\nkiharito:\n  login: kiharito\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/38311245?v=4\n  url: https://github.com/kiharito\nt4f1d:\n  login: t4f1d\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/4054172?u=463d5ce0ec8ad8582f6e9351bb8c9a5105b39bb7&v=4\n  url: https://github.com/t4f1d\nJ-Fuji:\n  login: J-Fuji\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/101452903?v=4\n  url: https://github.com/J-Fuji\nMrL8199:\n  login: MrL8199\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/39489075?u=3fc4f89c86973e40b5970d838c801bdbc13ac828&v=4\n  url: https://github.com/MrL8199\nivintoiu:\n  login: ivintoiu\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1853336?u=e3de5fd0ab17efc12256b4295285b504ca281440&v=4\n  url: https://github.com/ivintoiu\nTechnoService2:\n  login: TechnoService2\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/142113388?v=4\n  url: https://github.com/TechnoService2\nEgorOnishchuk:\n  login: EgorOnishchuk\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/120256301?v=4\n  url: https://github.com/EgorOnishchuk\niamantonreznik:\n  login: iamantonreznik\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/112612414?u=b9ba8d9b4d3940198bc3a4353dfce70c044a39b1&v=4\n  url: https://github.com/iamantonreznik\nAzazul123:\n  login: Azazul123\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/102759111?u=b48ce6e30a81a23467cc30e0c011bcc57f0326ab&v=4\n  url: https://github.com/Azazul123\nykertytsky:\n  login: ykertytsky\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/83857001?u=1f303eb73189f78cff376c13bd46db65f90ee314&v=4\n  url: https://github.com/ykertytsky\nNavesSapnis:\n  login: NavesSapnis\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/79222417?u=b5b10291b8e9130ca84fd20f0a641e04ed94b6b1&v=4\n  url: https://github.com/NavesSapnis\nisgin01:\n  login: isgin01\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=16d6466476cf7dbc55a4cd575b6ea920ebdd81e1&v=4\n  url: https://github.com/isgin01\nsyedasamina56:\n  login: syedasamina56\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/183273097?v=4\n  url: https://github.com/syedasamina56\n"
  },
  {
    "path": "docs/en/data/translators.yml",
    "content": "nilslindemann:\n  login: nilslindemann\n  count: 130\n  avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4\n  url: https://github.com/nilslindemann\ntiangolo:\n  login: tiangolo\n  count: 67\n  avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4\n  url: https://github.com/tiangolo\njaystone776:\n  login: jaystone776\n  count: 46\n  avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4\n  url: https://github.com/jaystone776\nceb10n:\n  login: ceb10n\n  count: 30\n  avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4\n  url: https://github.com/ceb10n\nvalentinDruzhinin:\n  login: valentinDruzhinin\n  count: 29\n  avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4\n  url: https://github.com/valentinDruzhinin\ntokusumi:\n  login: tokusumi\n  count: 23\n  avatarUrl: https://avatars.githubusercontent.com/u/41147016?u=55010621aece725aa702270b54fed829b6a1fe60&v=4\n  url: https://github.com/tokusumi\nSwftAlpc:\n  login: SwftAlpc\n  count: 23\n  avatarUrl: https://avatars.githubusercontent.com/u/52768429?u=6a3aa15277406520ad37f6236e89466ed44bc5b8&v=4\n  url: https://github.com/SwftAlpc\nYuriiMotov:\n  login: YuriiMotov\n  count: 23\n  avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=bc48be95c429989224786106b027f3c5e40cc354&v=4\n  url: https://github.com/YuriiMotov\nhasansezertasan:\n  login: hasansezertasan\n  count: 22\n  avatarUrl: https://avatars.githubusercontent.com/u/13135006?u=d36995e41a00590da64e6204cfd112e0484ac1ca&v=4\n  url: https://github.com/hasansezertasan\nwaynerv:\n  login: waynerv\n  count: 20\n  avatarUrl: https://avatars.githubusercontent.com/u/39515546?u=ec35139777597cdbbbddda29bf8b9d4396b429a9&v=4\n  url: https://github.com/waynerv\nhard-coders:\n  login: hard-coders\n  count: 16\n  avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=78d12d1acdf853c817700145e73de7fd9e5d068b&v=4\n  url: https://github.com/hard-coders\nAlertRED:\n  login: AlertRED\n  count: 16\n  avatarUrl: https://avatars.githubusercontent.com/u/15695000?u=f5a4944c6df443030409c88da7d7fa0b7ead985c&v=4\n  url: https://github.com/AlertRED\nJoao-Pedro-P-Holanda:\n  login: Joao-Pedro-P-Holanda\n  count: 14\n  avatarUrl: https://avatars.githubusercontent.com/u/110267046?u=331bd016326dac4cf3df4848f6db2dbbf8b5f978&v=4\n  url: https://github.com/Joao-Pedro-P-Holanda\nyychanlee:\n  login: yychanlee\n  count: 14\n  avatarUrl: https://avatars.githubusercontent.com/u/103817302?u=3a042740dc0ff58615da0d8679230966fd7693e8&v=4\n  url: https://github.com/yychanlee\nXewus:\n  login: Xewus\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=f8e2dc7e5104f109cef944af79050ea8d1b8f914&v=4\n  url: https://github.com/Xewus\nZhongheng-Cheng:\n  login: Zhongheng-Cheng\n  count: 13\n  avatarUrl: https://avatars.githubusercontent.com/u/95612344?u=a0f7730a3cc7486827965e01a119ad610bda4b0a&v=4\n  url: https://github.com/Zhongheng-Cheng\nSmlep:\n  login: Smlep\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/16785985?u=ffe99fa954c8e774ef1117e58d34aece92051e27&v=4\n  url: https://github.com/Smlep\nmarcelomarkus:\n  login: marcelomarkus\n  count: 11\n  avatarUrl: https://avatars.githubusercontent.com/u/20115018?u=dda090ce9160ef0cd2ff69b1e5ea741283425cba&v=4\n  url: https://github.com/marcelomarkus\nKaniKim:\n  login: KaniKim\n  count: 10\n  avatarUrl: https://avatars.githubusercontent.com/u/19832624?u=296dbdd490e0eb96e3d45a2608c065603b17dc31&v=4\n  url: https://github.com/KaniKim\nVincy1230:\n  login: Vincy1230\n  count: 9\n  avatarUrl: https://avatars.githubusercontent.com/u/81342412?u=ab5e256a4077a4a91f3f9cd2115ba80780454cbe&v=4\n  url: https://github.com/Vincy1230\nrjNemo:\n  login: rjNemo\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4\n  url: https://github.com/rjNemo\nxzmeng:\n  login: xzmeng\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/40202897?v=4\n  url: https://github.com/xzmeng\npablocm83:\n  login: pablocm83\n  count: 8\n  avatarUrl: https://avatars.githubusercontent.com/u/28315068?u=3310fbb05bb8bfc50d2c48b6cb64ac9ee4a14549&v=4\n  url: https://github.com/pablocm83\nptt3199:\n  login: ptt3199\n  count: 7\n  avatarUrl: https://avatars.githubusercontent.com/u/51350651?u=2c3d947a80283e32bf616d4c3af139a6be69680f&v=4\n  url: https://github.com/ptt3199\nNinaHwang:\n  login: NinaHwang\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=241f2cb6d38a2d379536608a8ea5a22ed4b1a3ea&v=4\n  url: https://github.com/NinaHwang\nbatlopes:\n  login: batlopes\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4\n  url: https://github.com/batlopes\nlucasbalieiro:\n  login: lucasbalieiro\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/37416577?u=d144221c34c08adac8b20e1833d776ffa1c4b1d0&v=4\n  url: https://github.com/lucasbalieiro\nAlexandrhub:\n  login: Alexandrhub\n  count: 6\n  avatarUrl: https://avatars.githubusercontent.com/u/119126536?u=9fc0d48f3307817bafecc5861eb2168401a6cb04&v=4\n  url: https://github.com/Alexandrhub\nSerrones:\n  login: Serrones\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4\n  url: https://github.com/Serrones\nRunningIkkyu:\n  login: RunningIkkyu\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4\n  url: https://github.com/RunningIkkyu\nAttsun1031:\n  login: Attsun1031\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4\n  url: https://github.com/Attsun1031\nrostik1410:\n  login: rostik1410\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/11443899?u=e26a635c2ba220467b308a326a579b8ccf4a8701&v=4\n  url: https://github.com/rostik1410\nalv2017:\n  login: alv2017\n  count: 5\n  avatarUrl: https://avatars.githubusercontent.com/u/31544722?v=4\n  url: https://github.com/alv2017\nkomtaki:\n  login: komtaki\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4\n  url: https://github.com/komtaki\nJulianMaurin:\n  login: JulianMaurin\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/63545168?u=b7d15ac865268cbefc2d739e2f23d9aeeac1a622&v=4\n  url: https://github.com/JulianMaurin\nstlucasgarcia:\n  login: stlucasgarcia\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=c22d8850e9dc396a8820766a59837f967e14f9a0&v=4\n  url: https://github.com/stlucasgarcia\nComicShrimp:\n  login: ComicShrimp\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=d2fbf412e7730183ce91686ca48d4147e1b7dc74&v=4\n  url: https://github.com/ComicShrimp\nBilalAlpaslan:\n  login: BilalAlpaslan\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4\n  url: https://github.com/BilalAlpaslan\naxel584:\n  login: axel584\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4\n  url: https://github.com/axel584\ntamtam-fitness:\n  login: tamtam-fitness\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/62091034?u=8da19a6bd3d02f5d6ba30c7247d5b46c98dd1403&v=4\n  url: https://github.com/tamtam-fitness\nLimsunoh:\n  login: Limsunoh\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/90311848?u=f456e0c5709fd50c8cd2898b551558eda14e5f21&v=4\n  url: https://github.com/Limsunoh\nkwang1215:\n  login: kwang1215\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/74170199?u=2a63ff6692119dde3f5e5693365b9fcd6f977b08&v=4\n  url: https://github.com/kwang1215\nk94-ishi:\n  login: k94-ishi\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/32672580?u=bc7c5c07af0656be9fe4f1784a444af8d81ded89&v=4\n  url: https://github.com/k94-ishi\nMohammad222PR:\n  login: Mohammad222PR\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/116789737?u=25810a5fe049d2f1618e2e7417cea011cc353ce4&v=4\n  url: https://github.com/Mohammad222PR\nNavesSapnis:\n  login: NavesSapnis\n  count: 4\n  avatarUrl: https://avatars.githubusercontent.com/u/79222417?u=b5b10291b8e9130ca84fd20f0a641e04ed94b6b1&v=4\n  url: https://github.com/NavesSapnis\njfunez:\n  login: jfunez\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/805749?v=4\n  url: https://github.com/jfunez\nycd:\n  login: ycd\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=f1e7bae394a315da950912c92dc861a8eaf95d4c&v=4\n  url: https://github.com/ycd\nmariacamilagl:\n  login: mariacamilagl\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4\n  url: https://github.com/mariacamilagl\nmaoyibo:\n  login: maoyibo\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/7887703?v=4\n  url: https://github.com/maoyibo\nblt232018:\n  login: blt232018\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4\n  url: https://github.com/blt232018\nmagiskboy:\n  login: magiskboy\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/13352088?u=18b6d672523f9e9d98401f31dd50e28bb27d826f&v=4\n  url: https://github.com/magiskboy\nluccasmmg:\n  login: luccasmmg\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/11317382?u=65099a5a0d492b89119471f8a7014637cc2e04da&v=4\n  url: https://github.com/luccasmmg\nlbmendes:\n  login: lbmendes\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/80999926?u=646619e2f07ac5a7c3f65fe7834197461a4fff9f&v=4\n  url: https://github.com/lbmendes\nZssaer:\n  login: Zssaer\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/45691504?u=4c0c195f25cb5ac6af32acfb0ab35427682938d2&v=4\n  url: https://github.com/Zssaer\nChuyuChoyeon:\n  login: ChuyuChoyeon\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/129537877?u=f0c76f3327817a8b86b422d62e04a34bf2827f2b&v=4\n  url: https://github.com/ChuyuChoyeon\nivan-abc:\n  login: ivan-abc\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/36765187?u=c6e0ba571c1ccb6db9d94e62e4b8b5eda811a870&v=4\n  url: https://github.com/ivan-abc\nmojtabapaso:\n  login: mojtabapaso\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/121169359?u=ced1d5ad673bcd9e949ebf967a4ab50185637443&v=4\n  url: https://github.com/mojtabapaso\nhsuanchi:\n  login: hsuanchi\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/24913710?u=7d25a398e478b6e63503bf6f26c54efa9e0da07b&v=4\n  url: https://github.com/hsuanchi\nalejsdev:\n  login: alejsdev\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/90076947?u=0facffe3abf87f57a1f05fa773d1119cc5c2f6a5&v=4\n  url: https://github.com/alejsdev\nriroan:\n  login: riroan\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/33053284?u=2d18e3771506ee874b66d6aa2b3b1107fd95c38f&v=4\n  url: https://github.com/riroan\nnayeonkinn:\n  login: nayeonkinn\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/98254573?u=64a75ac99b320d4935eff8d1fceea9680fa07473&v=4\n  url: https://github.com/nayeonkinn\npe-brian:\n  login: pe-brian\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/1783138?u=7e6242eb9e85bcf673fa88bbac9dd6dc3f03b1b5&v=4\n  url: https://github.com/pe-brian\nmaxscheijen:\n  login: maxscheijen\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/47034840?v=4\n  url: https://github.com/maxscheijen\nilacftemp:\n  login: ilacftemp\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/159066669?v=4\n  url: https://github.com/ilacftemp\ndevluisrodrigues:\n  login: devluisrodrigues\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/103431660?u=d9674a3249edc4601d2c712cdebf899918503c3a&v=4\n  url: https://github.com/devluisrodrigues\ndevfernandoa:\n  login: devfernandoa\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/28360583?u=c4308abd62e8847c9e572e1bb9fe6b9dc9ef8e50&v=4\n  url: https://github.com/devfernandoa\nkim-sangah:\n  login: kim-sangah\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/173775778?v=4\n  url: https://github.com/kim-sangah\n9zimin9:\n  login: 9zimin9\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/174453744?v=4\n  url: https://github.com/9zimin9\nnahyunkeem:\n  login: nahyunkeem\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/174440096?u=e12401d492eee58570f8914d0872b52e421a776e&v=4\n  url: https://github.com/nahyunkeem\ntimothy-jeong:\n  login: timothy-jeong\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/53824764?u=db3d0cea2f5fab64d810113c5039a369699a2774&v=4\n  url: https://github.com/timothy-jeong\ngerry-sabar:\n  login: gerry-sabar\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/1120123?v=4\n  url: https://github.com/gerry-sabar\nRishat-F:\n  login: Rishat-F\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/66554797?v=4\n  url: https://github.com/Rishat-F\nruzia:\n  login: ruzia\n  count: 3\n  avatarUrl: https://avatars.githubusercontent.com/u/24503?u=abce66d26c9611818720f11e6ae6773a6e0928f8&v=4\n  url: https://github.com/ruzia\nizaguerreiro:\n  login: izaguerreiro\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/2241504?v=4\n  url: https://github.com/izaguerreiro\nXaraxx:\n  login: Xaraxx\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/29824698?u=dde2e233e22bb5ca1f8bb0c6e353ccd0d06e6066&v=4\n  url: https://github.com/Xaraxx\nsh0nk:\n  login: sh0nk\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4\n  url: https://github.com/sh0nk\ndukkee:\n  login: dukkee\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/36825394?u=ccfd86e6a4f2d093dad6f7544cc875af67fa2df8&v=4\n  url: https://github.com/dukkee\noandersonmagalhaes:\n  login: oandersonmagalhaes\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/83456692?u=daf5f302a59b950efc6d21129314af207e35441f&v=4\n  url: https://github.com/oandersonmagalhaes\nleandrodesouzadev:\n  login: leandrodesouzadev\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/85115541?u=4eb25f43f1fe23727d61e986cf83b73b86e2a95a&v=4\n  url: https://github.com/leandrodesouzadev\nkty4119:\n  login: kty4119\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/49435654?v=4\n  url: https://github.com/kty4119\nASpathfinder:\n  login: ASpathfinder\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/31813636?u=2090bd1b7abb65cfeff0c618f99f11afa82c0548&v=4\n  url: https://github.com/ASpathfinder\njujumilk3:\n  login: jujumilk3\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/41659814?u=538f7dfef03b59f25e43f10d59a31c19ef538a0c&v=4\n  url: https://github.com/jujumilk3\nayr-ton:\n  login: ayr-ton\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1090517?u=5cf70a0e0f0dbf084e074e494aa94d7c91a46ba6&v=4\n  url: https://github.com/ayr-ton\nKadermiyanyedi:\n  login: Kadermiyanyedi\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/48386782?u=08c0f1594c5baf28b6fab7520a848cb9c3806c8e&v=4\n  url: https://github.com/Kadermiyanyedi\nKdHyeon0661:\n  login: KdHyeon0661\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/20253352?u=5ae1aae34b091a39f22cbe60a02b79dcbdbea031&v=4\n  url: https://github.com/KdHyeon0661\nLorhanSohaky:\n  login: LorhanSohaky\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4\n  url: https://github.com/LorhanSohaky\ncfraboulet:\n  login: cfraboulet\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/62244267?u=ed0e286ba48fa1dafd64a08e50f3364b8e12df34&v=4\n  url: https://github.com/cfraboulet\ndedkot01:\n  login: dedkot01\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/26196675?u=e2966887124e67932853df4f10f86cb526edc7b0&v=4\n  url: https://github.com/dedkot01\nAGolicyn:\n  login: AGolicyn\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/86262613?u=3c21606ab8d210a061a1673decff1e7d5592b380&v=4\n  url: https://github.com/AGolicyn\nfhabers21:\n  login: fhabers21\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/58401847?v=4\n  url: https://github.com/fhabers21\nTabarakoAkula:\n  login: TabarakoAkula\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/113298631?u=add801e370dbc502cd94ce6d3484760d7fef5406&v=4\n  url: https://github.com/TabarakoAkula\nAhsanSheraz:\n  login: AhsanSheraz\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/51913596?u=b5aa3c3a004cc0112e56c54f6901941836d8c26b&v=4\n  url: https://github.com/AhsanSheraz\nArtemKhymenko:\n  login: ArtemKhymenko\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/14346625?u=f2fa553d9e5ec5e0f05d66bd649f7be347169631&v=4\n  url: https://github.com/ArtemKhymenko\nhasnatsajid:\n  login: hasnatsajid\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/86589885?u=3712c0362d7a4000d76022339c545cf46aa5903f&v=4\n  url: https://github.com/hasnatsajid\nalperiox:\n  login: alperiox\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/34214152?u=2c5acad3461d4dbc2d48371ba86cac56ae9b25cc&v=4\n  url: https://github.com/alperiox\nemrhnsyts:\n  login: emrhnsyts\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/42899027?u=ad26798e3f8feed2041c5dd5f87e58933d6c3283&v=4\n  url: https://github.com/emrhnsyts\nvusallyv:\n  login: vusallyv\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/85983771?u=620ce103dcdc47953c952bb8d402a9cf8199014d&v=4\n  url: https://github.com/vusallyv\njackleeio:\n  login: jackleeio\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/20477587?u=c5184dab6d021733d10c8f975b20e391856303d6&v=4\n  url: https://github.com/jackleeio\nchoi-haram:\n  login: choi-haram\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/62204475?v=4\n  url: https://github.com/choi-haram\nimtiaz101325:\n  login: imtiaz101325\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/54007087?u=61e79c4c39798cd4d339788045dc44d4c6252bde&v=4\n  url: https://github.com/imtiaz101325\nfabianfalon:\n  login: fabianfalon\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/3700760?u=95f69e31280b17ac22299cdcd345323b142fe0af&v=4\n  url: https://github.com/fabianfalon\nwaketzheng:\n  login: waketzheng\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/35413830?u=df19e4fd5bb928e7d086e053ef26a46aad23bf84&v=4\n  url: https://github.com/waketzheng\nbillzhong:\n  login: billzhong\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/1644011?v=4\n  url: https://github.com/billzhong\nchaoless:\n  login: chaoless\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/64477804?v=4\n  url: https://github.com/chaoless\nlogan2d5:\n  login: logan2d5\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/146642263?u=dbd6621f8b0330d6919f6a7131277b92e26fbe87&v=4\n  url: https://github.com/logan2d5\nandersonrocha0:\n  login: andersonrocha0\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/22346169?u=93a1359c8c5461d894802c0cc65bcd09217e7a02&v=4\n  url: https://github.com/andersonrocha0\nsaeye:\n  login: saeye\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/62229734?u=312d619db2588b60d5d5bde65260a2f44fdc6c76&v=4\n  url: https://github.com/saeye\n11kkw:\n  login: 11kkw\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/21125286?v=4\n  url: https://github.com/11kkw\nyes0ng:\n  login: yes0ng\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/25501794?u=3aed18b0d491e0220a167a1e9e58bea3638c6707&v=4\n  url: https://github.com/yes0ng\nEgorOnishchuk:\n  login: EgorOnishchuk\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/120256301?v=4\n  url: https://github.com/EgorOnishchuk\nEdmilsonRodrigues:\n  login: EdmilsonRodrigues\n  count: 2\n  avatarUrl: https://avatars.githubusercontent.com/u/62777025?u=217d6f3cd6cc750bb8818a3af7726c8d74eb7c2d&v=4\n  url: https://github.com/EdmilsonRodrigues\n"
  },
  {
    "path": "docs/en/docs/_llm-test.md",
    "content": "# LLM test file { #llm-test-file }\n\nThis document tests if the <abbr title=\"Large Language Model\">LLM</abbr>, which translates the documentation, understands the `general_prompt` in `scripts/translate.py` and the language specific prompt in `docs/{language code}/llm-prompt.md`. The language specific prompt is appended to `general_prompt`.\n\nTests added here will be seen by all designers of language specific prompts.\n\nUse as follows:\n\n* Have a language specific prompt - `docs/{language code}/llm-prompt.md`.\n* Do a fresh translation of this document into your desired target language (see e.g. the `translate-page` command of the `translate.py`). This will create the translation under `docs/{language code}/docs/_llm-test.md`.\n* Check if things are okay in the translation.\n* If necessary, improve your language specific prompt, the general prompt, or the English document.\n* Then manually fix the remaining issues in the translation, so that it is a good translation.\n* Retranslate, having the good translation in place. The ideal result would be that the LLM makes no changes anymore to the translation. That means that the general prompt and your language specific prompt are as good as they can be (It will sometimes make a few seemingly random changes, the reason is that [LLMs are not deterministic algorithms](https://doublespeak.chat/#/handbook#deterministic-output)).\n\nThe tests:\n\n## Code snippets { #code-snippets }\n\n//// tab | Test\n\nThis is a code snippet: `foo`. And this is another code snippet: `bar`. And another one: `baz quux`.\n\n////\n\n//// tab | Info\n\nContent of code snippets should be left as is.\n\nSee section `### Content of code snippets` in the general prompt in `scripts/translate.py`.\n\n////\n\n## Quotes { #quotes }\n\n//// tab | Test\n\nYesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\".\n\n/// note\n\nThe LLM will probably translate this wrong. Interesting is only if it keeps the fixed translation when retranslating.\n\n///\n\n////\n\n//// tab | Info\n\nThe prompt designer may choose if they want to convert neutral quotes to typographic quotes. It is okay to leave them as is.\n\nSee for example section `### Quotes` in `docs/de/llm-prompt.md`.\n\n////\n\n## Quotes in code snippets { #quotes-in-code-snippets }\n\n//// tab | Test\n\n`pip install \"foo[bar]\"`\n\nExamples for string literals in code snippets: `\"this\"`, `'that'`.\n\nA difficult example for string literals in code snippets: `f\"I like {'oranges' if orange else \"apples\"}\"`\n\nHardcore: `Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | Info\n\n... However, quotes inside code snippets must stay as is.\n\n////\n\n## code blocks { #code-blocks }\n\n//// tab | Test\n\nA Bash code example...\n\n```bash\n# Print a greeting to the universe\necho \"Hello universe\"\n```\n\n...and a console code example...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n...and another console code example...\n\n```console\n// Create a directory \"Code\"\n$ mkdir code\n// Switch into that directory\n$ cd code\n```\n\n...and a Python code example...\n\n```Python\nwont_work()  # This won't work 😱\nworks(foo=\"bar\")  # This works 🎉\n```\n\n...and that's it.\n\n////\n\n//// tab | Info\n\nCode in code blocks should not be modified, with the exception of comments.\n\nSee section `### Content of code blocks` in the general prompt in `scripts/translate.py`.\n\n////\n\n## Tabs and colored boxes { #tabs-and-colored-boxes }\n\n//// tab | Test\n\n/// info\nSome text\n///\n\n/// note\nSome text\n///\n\n/// note | Technical details\nSome text\n///\n\n/// check\nSome text\n///\n\n/// tip\nSome text\n///\n\n/// warning\nSome text\n///\n\n/// danger\nSome text\n///\n\n////\n\n//// tab | Info\n\nTabs and `Info`/`Note`/`Warning`/etc. blocks should have the translation of their title added after a vertical bar (`|`).\n\nSee sections `### Special blocks` and `### Tab blocks` in the general prompt in `scripts/translate.py`.\n\n////\n\n## Web- and internal links { #web-and-internal-links }\n\n//// tab | Test\n\nThe link text should get translated, the link address should remain unchanged:\n\n* [Link to heading above](#code-snippets)\n* [Internal link](index.md#installation)\n* [External link](https://sqlmodel.tiangolo.com/)\n* [Link to a style](https://fastapi.tiangolo.com/css/styles.css)\n* [Link to a script](https://fastapi.tiangolo.com/js/logic.js)\n* [Link to an image](https://fastapi.tiangolo.com/img/foo.jpg)\n\nThe link text should get translated, the link address should point to the translation:\n\n* [FastAPI link](https://fastapi.tiangolo.com/)\n\n////\n\n//// tab | Info\n\nLinks should be translated, but their address shall remain unchanged. An exception are absolute links to pages of the FastAPI documentation. In that case it should link to the translation.\n\nSee section `### Links` in the general prompt in `scripts/translate.py`.\n\n////\n\n## HTML \"abbr\" elements { #html-abbr-elements }\n\n//// tab | Test\n\nHere some things wrapped in HTML \"abbr\" elements (Some are invented):\n\n### The abbr gives a full phrase { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done\">GTD</abbr>\n* <abbr title=\"less than\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface\">PSGI</abbr>\n\n### The abbr gives a full phrase and an explanation { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network: documentation for developers, written by the Firefox people\">MDN</abbr>\n* <abbr title=\"Input/Output: disk reading or writing, network communications.\">I/O</abbr>.\n\n////\n\n//// tab | Info\n\n\"title\" attributes of \"abbr\" elements are translated following some specific instructions.\n\nTranslations can add their own \"abbr\" elements which the LLM should not remove. E.g. to explain English words.\n\nSee section `### HTML abbr elements` in the general prompt in `scripts/translate.py`.\n\n////\n\n## HTML \"dfn\" elements { #html-dfn-elements }\n\n* <dfn title=\"A group of machines that are configured to be connected and work together in some way.\">cluster</dfn>\n* <dfn title=\"A method of machine learning that uses artificial neural networks with numerous hidden layers between input and output layers, thereby developing a comprehensive internal structure\">Deep Learning</dfn>\n\n## Headings { #headings }\n\n//// tab | Test\n\n### Develop a webapp - a tutorial { #develop-a-webapp-a-tutorial }\n\nHello.\n\n### Type hints and -annotations { #type-hints-and-annotations }\n\nHello again.\n\n### Super- and subclasses { #super-and-subclasses }\n\nHello again.\n\n////\n\n//// tab | Info\n\nThe only hard rule for headings is that the LLM leaves the hash part inside curly brackets unchanged, which ensures that links do not break.\n\nSee section `### Headings` in the general prompt in `scripts/translate.py`.\n\nFor some language specific instructions, see e.g. section `### Headings` in `docs/de/llm-prompt.md`.\n\n////\n\n## Terms used in the docs { #terms-used-in-the-docs }\n\n//// tab | Test\n\n* you\n* your\n\n* e.g.\n* etc.\n\n* `foo` as an `int`\n* `bar` as a `str`\n* `baz` as a `list`\n\n* the Tutorial - User guide\n* the Advanced User Guide\n* the SQLModel docs\n* the API docs\n* the automatic docs\n\n* Data Science\n* Deep Learning\n* Machine Learning\n* Dependency Injection\n* HTTP Basic authentication\n* HTTP Digest\n* ISO format\n* the JSON Schema standard\n* the JSON schema\n* the schema definition\n* Password Flow\n* Mobile\n\n* deprecated\n* designed\n* invalid\n* on the fly\n* standard\n* default\n* case-sensitive\n* case-insensitive\n\n* to serve the application\n* to serve the page\n\n* the app\n* the application\n\n* the request\n* the response\n* the error response\n\n* the path operation\n* the path operation decorator\n* the path operation function\n\n* the body\n* the request body\n* the response body\n* the JSON body\n* the form body\n* the file body\n* the function body\n\n* the parameter\n* the body parameter\n* the path parameter\n* the query parameter\n* the cookie parameter\n* the header parameter\n* the form parameter\n* the function parameter\n\n* the event\n* the startup event\n* the startup of the server\n* the shutdown event\n* the lifespan event\n\n* the handler\n* the event handler\n* the exception handler\n* to handle\n\n* the model\n* the Pydantic model\n* the data model\n* the database model\n* the form model\n* the model object\n\n* the class\n* the base class\n* the parent class\n* the subclass\n* the child class\n* the sibling class\n* the class method\n\n* the header\n* the headers\n* the authorization header\n* the `Authorization` header\n* the forwarded header\n\n* the dependency injection system\n* the dependency\n* the dependable\n* the dependant\n\n* I/O bound\n* CPU bound\n* concurrency\n* parallelism\n* multiprocessing\n\n* the env var\n* the environment variable\n* the `PATH`\n* the `PATH` variable\n\n* the authentication\n* the authentication provider\n* the authorization\n* the authorization form\n* the authorization provider\n* the user authenticates\n* the system authenticates the user\n\n* the CLI\n* the command line interface\n\n* the server\n* the client\n\n* the cloud provider\n* the cloud service\n\n* the development\n* the development stages\n\n* the dict\n* the dictionary\n* the enumeration\n* the enum\n* the enum member\n\n* the encoder\n* the decoder\n* to encode\n* to decode\n\n* the exception\n* to raise\n\n* the expression\n* the statement\n\n* the frontend\n* the backend\n\n* the GitHub discussion\n* the GitHub issue\n\n* the performance\n* the performance optimization\n\n* the return type\n* the return value\n\n* the security\n* the security scheme\n\n* the task\n* the background task\n* the task function\n\n* the template\n* the template engine\n\n* the type annotation\n* the type hint\n\n* the server worker\n* the Uvicorn worker\n* the Gunicorn Worker\n* the worker process\n* the worker class\n* the workload\n\n* the deployment\n* to deploy\n\n* the SDK\n* the software development kit\n\n* the `APIRouter`\n* the `requirements.txt`\n* the Bearer Token\n* the breaking change\n* the bug\n* the button\n* the callable\n* the code\n* the commit\n* the context manager\n* the coroutine\n* the database session\n* the disk\n* the domain\n* the engine\n* the fake X\n* the HTTP GET method\n* the item\n* the library\n* the lifespan\n* the lock\n* the middleware\n* the mobile application\n* the module\n* the mounting\n* the network\n* the origin\n* the override\n* the payload\n* the processor\n* the property\n* the proxy\n* the pull request\n* the query\n* the RAM\n* the remote machine\n* the status code\n* the string\n* the tag\n* the web framework\n* the wildcard\n* to return\n* to validate\n\n////\n\n//// tab | Info\n\nThis is a not complete and not normative list of (mostly) technical terms seen in the docs. It may be helpful for the prompt designer to figure out for which terms the LLM needs a helping hand. For example when it keeps reverting a good translation to a suboptimal translation. Or when it has problems conjugating/declinating a term in your language.\n\nSee e.g. section `### List of English terms and their preferred German translations` in `docs/de/llm-prompt.md`.\n\n////\n"
  },
  {
    "path": "docs/en/docs/about/index.md",
    "content": "# About { #about }\n\nAbout FastAPI, its design, inspiration and more. 🤓\n"
  },
  {
    "path": "docs/en/docs/advanced/additional-responses.md",
    "content": "# Additional Responses in OpenAPI { #additional-responses-in-openapi }\n\n/// warning\n\nThis is a rather advanced topic.\n\nIf you are starting with **FastAPI**, you might not need this.\n\n///\n\nYou can declare additional responses, with additional status codes, media types, descriptions, etc.\n\nThose additional responses will be included in the OpenAPI schema, so they will also appear in the API docs.\n\nBut for those additional responses you have to make sure you return a `Response` like `JSONResponse` directly, with your status code and content.\n\n## Additional Response with `model` { #additional-response-with-model }\n\nYou can pass to your *path operation decorators* a parameter `responses`.\n\nIt receives a `dict`: the keys are status codes for each response (like `200`), and the values are other `dict`s with the information for each of them.\n\nEach of those response `dict`s can have a key `model`, containing a Pydantic model, just like `response_model`.\n\n**FastAPI** will take that model, generate its JSON Schema and include it in the correct place in OpenAPI.\n\nFor example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write:\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note\n\nKeep in mind that you have to return the `JSONResponse` directly.\n\n///\n\n/// info\n\nThe `model` key is not part of OpenAPI.\n\n**FastAPI** will take the Pydantic model from there, generate the JSON Schema, and put it in the correct place.\n\nThe correct place is:\n\n* In the key `content`, that has as value another JSON object (`dict`) that contains:\n    * A key with the media type, e.g. `application/json`, that contains as value another JSON object, that contains:\n        * A key `schema`, that has as the value the JSON Schema from the model, here's the correct place.\n            * **FastAPI** adds a reference here to the global JSON Schemas in another place in your OpenAPI instead of including it directly. This way, other applications and clients can use those JSON Schemas directly, provide better code generation tools, etc.\n\n///\n\nThe generated responses in the OpenAPI for this *path operation* will be:\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nThe schemas are referenced to another place inside the OpenAPI schema:\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## Additional media types for the main response { #additional-media-types-for-the-main-response }\n\nYou can use this same `responses` parameter to add different media types for the same main response.\n\nFor example, you can add an additional media type of `image/png`, declaring that your *path operation* can return a JSON object (with media type `application/json`) or a PNG image:\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note\n\nNotice that you have to return the image using a `FileResponse` directly.\n\n///\n\n/// info\n\nUnless you specify a different media type explicitly in your `responses` parameter, FastAPI will assume the response has the same media type as the main response class (default `application/json`).\n\nBut if you have specified a custom response class with `None` as its media type, FastAPI will use `application/json` for any additional response that has an associated model.\n\n///\n\n## Combining information { #combining-information }\n\nYou can also combine response information from multiple places, including the `response_model`, `status_code`, and `responses` parameters.\n\nYou can declare a `response_model`, using the default status code `200` (or a custom one if you need), and then declare additional information for that same response in `responses`, directly in the OpenAPI schema.\n\n**FastAPI** will keep the additional information from `responses`, and combine it with the JSON Schema from your model.\n\nFor example, you can declare a response with a status code `404` that uses a Pydantic model and has a custom `description`.\n\nAnd a response with a status code `200` that uses your `response_model`, but includes a custom `example`:\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\nIt will all be combined and included in your OpenAPI, and shown in the API docs:\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## Combine predefined responses and custom ones { #combine-predefined-responses-and-custom-ones }\n\nYou might want to have some predefined responses that apply to many *path operations*, but you want to combine them with custom responses needed by each *path operation*.\n\nFor those cases, you can use the Python technique of \"unpacking\" a `dict` with `**dict_to_unpack`:\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\nHere, `new_dict` will contain all the key-value pairs from `old_dict` plus the new key-value pair:\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\nYou can use that technique to reuse some predefined responses in your *path operations* and combine them with additional custom ones.\n\nFor example:\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## More information about OpenAPI responses { #more-information-about-openapi-responses }\n\nTo see what exactly you can include in the responses, you can check these sections in the OpenAPI specification:\n\n* [OpenAPI Responses Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object), it includes the `Response Object`.\n* [OpenAPI Response Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object), you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`.\n"
  },
  {
    "path": "docs/en/docs/advanced/additional-status-codes.md",
    "content": "# Additional Status Codes { #additional-status-codes }\n\nBy default, **FastAPI** will return the responses using a `JSONResponse`, putting the content you return from your *path operation* inside of that `JSONResponse`.\n\nIt will use the default status code or the one you set in your *path operation*.\n\n## Additional status codes { #additional-status-codes_1 }\n\nIf you want to return additional status codes apart from the main one, you can do that by returning a `Response` directly, like a `JSONResponse`, and set the additional status code directly.\n\nFor example, let's say that you want to have a *path operation* that allows to update items, and returns HTTP status codes of 200 \"OK\" when successful.\n\nBut you also want it to accept new items. And when the items didn't exist before, it creates them, and returns an HTTP status code of 201 \"Created\".\n\nTo achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning\n\nWhen you return a `Response` directly, like in the example above, it will be returned directly.\n\nIt won't be serialized with a model, etc.\n\nMake sure it has the data you want it to have, and that the values are valid JSON (if you are using `JSONResponse`).\n\n///\n\n/// note | Technical Details\n\nYou could also use `from starlette.responses import JSONResponse`.\n\n**FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette. The same with `status`.\n\n///\n\n## OpenAPI and API docs { #openapi-and-api-docs }\n\nIf you return additional status codes and responses directly, they won't be included in the OpenAPI schema (the API docs), because FastAPI doesn't have a way to know beforehand what you are going to return.\n\nBut you can document that in your code, using: [Additional Responses](additional-responses.md).\n"
  },
  {
    "path": "docs/en/docs/advanced/advanced-dependencies.md",
    "content": "# Advanced Dependencies { #advanced-dependencies }\n\n## Parameterized dependencies { #parameterized-dependencies }\n\nAll the dependencies we have seen are a fixed function or class.\n\nBut there could be cases where you want to be able to set parameters on the dependency, without having to declare many different functions or classes.\n\nLet's imagine that we want to have a dependency that checks if the query parameter `q` contains some fixed content.\n\nBut we want to be able to parameterize that fixed content.\n\n## A \"callable\" instance { #a-callable-instance }\n\nIn Python there's a way to make an instance of a class a \"callable\".\n\nNot the class itself (which is already a callable), but an instance of that class.\n\nTo do that, we declare a method `__call__`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\nIn this case, this `__call__` is what **FastAPI** will use to check for additional parameters and sub-dependencies, and this is what will be called to pass a value to the parameter in your *path operation function* later.\n\n## Parameterize the instance { #parameterize-the-instance }\n\nAnd now, we can use `__init__` to declare the parameters of the instance that we can use to \"parameterize\" the dependency:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\nIn this case, **FastAPI** won't ever touch or care about `__init__`, we will use it directly in our code.\n\n## Create an instance { #create-an-instance }\n\nWe could create an instance of this class with:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\nAnd that way we are able to \"parameterize\" our dependency, that now has `\"bar\"` inside of it, as the attribute `checker.fixed_content`.\n\n## Use the instance as a dependency { #use-the-instance-as-a-dependency }\n\nThen, we could use this `checker` in a `Depends(checker)`, instead of `Depends(FixedContentQueryChecker)`, because the dependency is the instance, `checker`, not the class itself.\n\nAnd when solving the dependency, **FastAPI** will call this `checker` like:\n\n```Python\nchecker(q=\"somequery\")\n```\n\n...and pass whatever that returns as the value of the dependency in our *path operation function* as the parameter `fixed_content_included`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip\n\nAll this might seem contrived. And it might not be very clear how is it useful yet.\n\nThese examples are intentionally simple, but show how it all works.\n\nIn the chapters about security, there are utility functions that are implemented in this same way.\n\nIf you understood all this, you already know how those utility tools for security work underneath.\n\n///\n\n## Dependencies with `yield`, `HTTPException`, `except` and Background Tasks { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning\n\nYou most probably don't need these technical details.\n\nThese details are useful mainly if you had a FastAPI application older than 0.121.0 and you are facing issues with dependencies with `yield`.\n\n///\n\nDependencies with `yield` have evolved over time to account for the different use cases and to fix some issues, here's a summary of what has changed.\n\n### Dependencies with `yield` and `scope` { #dependencies-with-yield-and-scope }\n\nIn version 0.121.0, FastAPI added support for `Depends(scope=\"function\")` for dependencies with `yield`.\n\nUsing `Depends(scope=\"function\")`, the exit code after `yield` is executed right after the *path operation function* is finished, before the response is sent back to the client.\n\nAnd when using `Depends(scope=\"request\")` (the default), the exit code after `yield` is executed after the response is sent.\n\nYou can read more about it in the docs for [Dependencies with `yield` - Early exit and `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope).\n\n### Dependencies with `yield` and `StreamingResponse`, Technical Details { #dependencies-with-yield-and-streamingresponse-technical-details }\n\nBefore FastAPI 0.118.0, if you used a dependency with `yield`, it would run the exit code after the *path operation function* returned but right before sending the response.\n\nThe intention was to avoid holding resources for longer than necessary, waiting for the response to travel through the network.\n\nThis change also meant that if you returned a `StreamingResponse`, the exit code of the dependency with `yield` would have been already run.\n\nFor example, if you had a database session in a dependency with `yield`, the `StreamingResponse` would not be able to use that session while streaming data because the session would have already been closed in the exit code after `yield`.\n\nThis behavior was reverted in 0.118.0, to make the exit code after `yield` be executed after the response is sent.\n\n/// info\n\nAs you will see below, this is very similar to the behavior before version 0.106.0, but with several improvements and bug fixes for corner cases.\n\n///\n\n#### Use Cases with Early Exit Code { #use-cases-with-early-exit-code }\n\nThere are some use cases with specific conditions that could benefit from the old behavior of running the exit code of dependencies with `yield` before sending the response.\n\nFor example, imagine you have code that uses a database session in a dependency with `yield` only to verify a user, but the database session is never used again in the *path operation function*, only in the dependency, **and** the response takes a long time to be sent, like a `StreamingResponse` that sends data slowly, but for some reason doesn't use the database.\n\nIn this case, the database session would be held until the response is finished being sent, but if you don't use it, then it wouldn't be necessary to hold it.\n\nHere's how it could look like:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\nThe exit code, the automatic closing of the `Session` in:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n...would be run after the response finishes sending the slow data:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nBut as `generate_stream()` doesn't use the database session, it is not really necessary to keep the session open while sending the response.\n\nIf you have this specific use case using SQLModel (or SQLAlchemy), you could explicitly close the session after you don't need it anymore:\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\nThat way the session would release the database connection, so other requests could use it.\n\nIf you have a different use case that needs to exit early from a dependency with `yield`, please create a [GitHub Discussion Question](https://github.com/fastapi/fastapi/discussions/new?category=questions) with your specific use case and why you would benefit from having early closing for dependencies with `yield`.\n\nIf there are compelling use cases for early closing in dependencies with `yield`, I would consider adding a new way to opt in to early closing.\n\n### Dependencies with `yield` and `except`, Technical Details { #dependencies-with-yield-and-except-technical-details }\n\nBefore FastAPI 0.110.0, if you used a dependency with `yield`, and then you captured an exception with `except` in that dependency, and you didn't raise the exception again, the exception would be automatically raised/forwarded to any exception handlers or the internal server error handler.\n\nThis was changed in version 0.110.0 to fix unhandled memory consumption from forwarded exceptions without a handler (internal server errors), and to make it consistent with the behavior of regular Python code.\n\n### Background Tasks and Dependencies with `yield`, Technical Details { #background-tasks-and-dependencies-with-yield-technical-details }\n\nBefore FastAPI 0.106.0, raising exceptions after `yield` was not possible, the exit code in dependencies with `yield` was executed *after* the response was sent, so [Exception Handlers](../tutorial/handling-errors.md#install-custom-exception-handlers) would have already run.\n\nThis was designed this way mainly to allow using the same objects \"yielded\" by dependencies inside of background tasks, because the exit code would be executed after the background tasks were finished.\n\nThis was changed in FastAPI 0.106.0 with the intention to not hold resources while waiting for the response to travel through the network.\n\n/// tip\n\nAdditionally, a background task is normally an independent set of logic that should be handled separately, with its own resources (e.g. its own database connection).\n\nSo, this way you will probably have cleaner code.\n\n///\n\nIf you used to rely on this behavior, now you should create the resources for background tasks inside the background task itself, and use internally only data that doesn't depend on the resources of dependencies with `yield`.\n\nFor example, instead of using the same database session, you would create a new database session inside of the background task, and you would obtain the objects from the database using this new session. And then instead of passing the object from the database as a parameter to the background task function, you would pass the ID of that object and then obtain the object again inside the background task function.\n"
  },
  {
    "path": "docs/en/docs/advanced/advanced-python-types.md",
    "content": "# Advanced Python Types { #advanced-python-types }\n\nHere are some additional ideas that might be useful when working with Python types.\n\n## Using `Union` or `Optional` { #using-union-or-optional }\n\nIf your code for some reason can't use `|`, for example if it's not in a type annotation but in something like `response_model=`, instead of using the vertical bar (`|`) you can use `Union` from `typing`.\n\nFor example, you could declare that something could be a `str` or `None`:\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\n`typing` also has a shortcut to declare that something could be `None`, with `Optional`.\n\nHere's a tip from my very **subjective** point of view:\n\n* 🚨 Avoid using `Optional[SomeType]`\n* Instead ✨ **use `Union[SomeType, None]`** ✨.\n\nBoth are equivalent and underneath they are the same, but I would recommend `Union` instead of `Optional` because the word \"**optional**\" would seem to imply that the value is optional, and it actually means \"it can be `None`\", even if it's not optional and is still required.\n\nI think `Union[SomeType, None]` is more explicit about what it means.\n\nIt's just about the words and names. But those words can affect how you and your teammates think about the code.\n\nAs an example, let's take this function:\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\nThe parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter:\n\n```Python\nsay_hi()  # Oh, no, this throws an error! 😱\n```\n\nThe `name` parameter is **still required** (not *optional*) because it doesn't have a default value. Still, `name` accepts `None` as the value:\n\n```Python\nsay_hi(name=None)  # This works, None is valid 🎉\n```\n\nThe good news is, in most cases, you will be able to simply use `|` to define unions of types:\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\nSo, normally you don't have to worry about names like `Optional` and `Union`. 😎\n"
  },
  {
    "path": "docs/en/docs/advanced/async-tests.md",
    "content": "# Async Tests { #async-tests }\n\nYou have already seen how to test your **FastAPI** applications using the provided `TestClient`. Up to now, you have only seen how to write synchronous tests, without using `async` functions.\n\nBeing able to use asynchronous functions in your tests could be useful, for example, when you're querying your database asynchronously. Imagine you want to test sending requests to your FastAPI application and then verify that your backend successfully wrote the correct data in the database, while using an async database library.\n\nLet's look at how we can make that work.\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\nIf we want to call asynchronous functions in our tests, our test functions have to be asynchronous. AnyIO provides a neat plugin for this, that allows us to specify that some test functions are to be called asynchronously.\n\n## HTTPX { #httpx }\n\nEven if your **FastAPI** application uses normal `def` functions instead of `async def`, it is still an `async` application underneath.\n\nThe `TestClient` does some magic inside to call the asynchronous FastAPI application in your normal `def` test functions, using standard pytest. But that magic doesn't work anymore when we're using it inside asynchronous functions. By running our tests asynchronously, we can no longer use the `TestClient` inside our test functions.\n\nThe `TestClient` is based on [HTTPX](https://www.python-httpx.org), and luckily, we can use it directly to test the API.\n\n## Example { #example }\n\nFor a simple example, let's consider a file structure similar to the one described in [Bigger Applications](../tutorial/bigger-applications.md) and [Testing](../tutorial/testing.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nThe file `main.py` would have:\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\nThe file `test_main.py` would have the tests for `main.py`, it could look like this now:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## Run it { #run-it }\n\nYou can run your tests as usual via:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## In Detail { #in-detail }\n\nThe marker `@pytest.mark.anyio` tells pytest that this test function should be called asynchronously:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip\n\nNote that the test function is now `async def` instead of just `def` as before when using the `TestClient`.\n\n///\n\nThen we can create an `AsyncClient` with the app, and send async requests to it, using `await`.\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\nThis is the equivalent to:\n\n```Python\nresponse = client.get('/')\n```\n\n...that we used to make our requests with the `TestClient`.\n\n/// tip\n\nNote that we're using async/await with the new `AsyncClient` - the request is asynchronous.\n\n///\n\n/// warning\n\nIf your application relies on lifespan events, the `AsyncClient` won't trigger these events. To ensure they are triggered, use `LifespanManager` from [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage).\n\n///\n\n## Other Asynchronous Function Calls { #other-asynchronous-function-calls }\n\nAs the testing function is now asynchronous, you can now also call (and `await`) other `async` functions apart from sending requests to your FastAPI application in your tests, exactly as you would call them anywhere else in your code.\n\n/// tip\n\nIf you encounter a `RuntimeError: Task attached to a different loop` when integrating asynchronous function calls in your tests (e.g. when using [MongoDB's MotorClient](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop)), remember to instantiate objects that need an event loop only within async functions, e.g. an `@app.on_event(\"startup\")` callback.\n\n///\n"
  },
  {
    "path": "docs/en/docs/advanced/behind-a-proxy.md",
    "content": "# Behind a Proxy { #behind-a-proxy }\n\nIn many situations, you would use a **proxy** like Traefik or Nginx in front of your FastAPI app.\n\nThese proxies could handle HTTPS certificates and other things.\n\n## Proxy Forwarded Headers { #proxy-forwarded-headers }\n\nA **proxy** in front of your application would normally set some headers on the fly before sending the requests to your **server** to let the server know that the request was **forwarded** by the proxy, letting it know the original (public) URL, including the domain, that it is using HTTPS, etc.\n\nThe **server** program (for example **Uvicorn** via **FastAPI CLI**) is capable of interpreting these headers, and then passing that information to your application.\n\nBut for security, as the server doesn't know it is behind a trusted proxy, it won't interpret those headers.\n\n/// note | Technical Details\n\nThe proxy headers are:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### Enable Proxy Forwarded Headers { #enable-proxy-forwarded-headers }\n\nYou can start FastAPI CLI with the *CLI Option* `--forwarded-allow-ips` and pass the IP addresses that should be trusted to read those forwarded headers.\n\nIf you set it to `--forwarded-allow-ips=\"*\"` it would trust all the incoming IPs.\n\nIf your **server** is behind a trusted **proxy** and only the proxy talks to it, this would make it accept whatever is the IP of that **proxy**.\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Redirects with HTTPS { #redirects-with-https }\n\nFor example, let's say you define a *path operation* `/items/`:\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\nIf the client tries to go to `/items`, by default, it would be redirected to `/items/`.\n\nBut before setting the *CLI Option* `--forwarded-allow-ips` it could redirect to `http://localhost:8000/items/`.\n\nBut maybe your application is hosted at `https://mysuperapp.com`, and the redirection should be to `https://mysuperapp.com/items/`.\n\nBy setting `--proxy-headers` now FastAPI would be able to redirect to the right location. 😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip\n\nIf you want to learn more about HTTPS, check the guide [About HTTPS](../deployment/https.md).\n\n///\n\n### How Proxy Forwarded Headers Work { #how-proxy-forwarded-headers-work }\n\nHere's a visual representation of how the **proxy** adds forwarded headers between the client and the **application server**:\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Proxy as Proxy/Load Balancer\n    participant Server as FastAPI Server\n\n    Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: Proxy adds forwarded headers\n\n    Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)\n\n    Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs\n\n    Proxy->>Client: HTTPS Response\n```\n\nThe **proxy** intercepts the original client request and adds the special *forwarded* headers (`X-Forwarded-*`) before passing the request to the **application server**.\n\nThese headers preserve information about the original request that would otherwise be lost:\n\n* **X-Forwarded-For**: The original client's IP address\n* **X-Forwarded-Proto**: The original protocol (`https`)\n* **X-Forwarded-Host**: The original host (`mysuperapp.com`)\n\nWhen **FastAPI CLI** is configured with `--forwarded-allow-ips`, it trusts these headers and uses them, for example to generate the correct URLs in redirects.\n\n## Proxy with a stripped path prefix { #proxy-with-a-stripped-path-prefix }\n\nYou could have a proxy that adds a path prefix to your application.\n\nIn these cases you can use `root_path` to configure your application.\n\nThe `root_path` is a mechanism provided by the ASGI specification (that FastAPI is built on, through Starlette).\n\nThe `root_path` is used to handle these specific cases.\n\nAnd it's also used internally when mounting sub-applications.\n\nHaving a proxy with a stripped path prefix, in this case, means that you could declare a path at `/app` in your code, but then, you add a layer on top (the proxy) that would put your **FastAPI** application under a path like `/api/v1`.\n\nIn this case, the original path `/app` would actually be served at `/api/v1/app`.\n\nEven though all your code is written assuming there's just `/app`.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\nAnd the proxy would be **\"stripping\"** the **path prefix** on the fly before transmitting the request to the app server (probably Uvicorn via FastAPI CLI), keeping your application convinced that it is being served at `/app`, so that you don't have to update all your code to include the prefix `/api/v1`.\n\nUp to here, everything would work as normally.\n\nBut then, when you open the integrated docs UI (the frontend), it would expect to get the OpenAPI schema at `/openapi.json`, instead of `/api/v1/openapi.json`.\n\nSo, the frontend (that runs in the browser) would try to reach `/openapi.json` and wouldn't be able to get the OpenAPI schema.\n\nBecause we have a proxy with a path prefix of `/api/v1` for our app, the frontend needs to fetch the OpenAPI schema at `/api/v1/openapi.json`.\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy on http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server on http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip\n\nThe IP `0.0.0.0` is commonly used to mean that the program listens on all the IPs available in that machine/server.\n\n///\n\nThe docs UI would also need the OpenAPI schema to declare that this API `server` is located at `/api/v1` (behind the proxy). For example:\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // More stuff here\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // More stuff here\n    }\n}\n```\n\nIn this example, the \"Proxy\" could be something like **Traefik**. And the server would be something like FastAPI CLI with **Uvicorn**, running your FastAPI application.\n\n### Providing the `root_path` { #providing-the-root-path }\n\nTo achieve this, you can use the command line option `--root-path` like:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nIf you use Hypercorn, it also has the option `--root-path`.\n\n/// note | Technical Details\n\nThe ASGI specification defines a `root_path` for this use case.\n\nAnd the `--root-path` command line option provides that `root_path`.\n\n///\n\n### Checking the current `root_path` { #checking-the-current-root-path }\n\nYou can get the current `root_path` used by your application for each request, it is part of the `scope` dictionary (that's part of the ASGI spec).\n\nHere we are including it in the message just for demonstration purposes.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\nThen, if you start Uvicorn with:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nThe response would be something like:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### Setting the `root_path` in the FastAPI app { #setting-the-root-path-in-the-fastapi-app }\n\nAlternatively, if you don't have a way to provide a command line option like `--root-path` or equivalent, you can set the `root_path` parameter when creating your FastAPI app:\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\nPassing the `root_path` to `FastAPI` would be the equivalent of passing the `--root-path` command line option to Uvicorn or Hypercorn.\n\n### About `root_path` { #about-root-path }\n\nKeep in mind that the server (Uvicorn) won't use that `root_path` for anything else than passing it to the app.\n\nBut if you go with your browser to [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app) you will see the normal response:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nSo, it won't expect to be accessed at `http://127.0.0.1:8000/api/v1/app`.\n\nUvicorn will expect the proxy to access Uvicorn at `http://127.0.0.1:8000/app`, and then it would be the proxy's responsibility to add the extra `/api/v1` prefix on top.\n\n## About proxies with a stripped path prefix { #about-proxies-with-a-stripped-path-prefix }\n\nKeep in mind that a proxy with stripped path prefix is only one of the ways to configure it.\n\nProbably in many cases the default will be that the proxy doesn't have a stripped path prefix.\n\nIn a case like that (without a stripped path prefix), the proxy would listen on something like `https://myawesomeapp.com`, and then if the browser goes to `https://myawesomeapp.com/api/v1/app` and your server (e.g. Uvicorn) listens on `http://127.0.0.1:8000` the proxy (without a stripped path prefix) would access Uvicorn at the same path: `http://127.0.0.1:8000/api/v1/app`.\n\n## Testing locally with Traefik { #testing-locally-with-traefik }\n\nYou can easily run the experiment locally with a stripped path prefix using [Traefik](https://docs.traefik.io/).\n\n[Download Traefik](https://github.com/containous/traefik/releases), it's a single binary, you can extract the compressed file and run it directly from the terminal.\n\nThen create a file `traefik.toml` with:\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\nThis tells Traefik to listen on port 9999 and to use another file `routes.toml`.\n\n/// tip\n\nWe are using port 9999 instead of the standard HTTP port 80 so that you don't have to run it with admin (`sudo`) privileges.\n\n///\n\nNow create that other file `routes.toml`:\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\nThis file configures Traefik to use the path prefix `/api/v1`.\n\nAnd then Traefik will redirect its requests to your Uvicorn running on `http://127.0.0.1:8000`.\n\nNow start Traefik:\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\nAnd now start your app, using the `--root-path` option:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Check the responses { #check-the-responses }\n\nNow, if you go to the URL with the port for Uvicorn: [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), you will see the normal response:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip\n\nNotice that even though you are accessing it at `http://127.0.0.1:8000/app` it shows the `root_path` of `/api/v1`, taken from the option `--root-path`.\n\n///\n\nAnd now open the URL with the port for Traefik, including the path prefix: [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app).\n\nWe get the same response:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nbut this time at the URL with the prefix path provided by the proxy: `/api/v1`.\n\nOf course, the idea here is that everyone would access the app through the proxy, so the version with the path prefix `/api/v1` is the \"correct\" one.\n\nAnd the version without the path prefix (`http://127.0.0.1:8000/app`), provided by Uvicorn directly, would be exclusively for the _proxy_ (Traefik) to access it.\n\nThat demonstrates how the Proxy (Traefik) uses the path prefix and how the server (Uvicorn) uses the `root_path` from the option `--root-path`.\n\n### Check the docs UI { #check-the-docs-ui }\n\nBut here's the fun part. ✨\n\nThe \"official\" way to access the app would be through the proxy with the path prefix that we defined. So, as we would expect, if you try the docs UI served by Uvicorn directly, without the path prefix in the URL, it won't work, because it expects to be accessed through the proxy.\n\nYou can check it at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\nBut if we access the docs UI at the \"official\" URL using the proxy with port `9999`, at `/api/v1/docs`, it works correctly! 🎉\n\nYou can check it at [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\nRight as we wanted it. ✔️\n\nThis is because FastAPI uses this `root_path` to create the default `server` in OpenAPI with the URL provided by `root_path`.\n\n## Additional servers { #additional-servers }\n\n/// warning\n\nThis is a more advanced use case. Feel free to skip it.\n\n///\n\nBy default, **FastAPI** will create a `server` in the OpenAPI schema with the URL for the `root_path`.\n\nBut you can also provide other alternative `servers`, for example if you want *the same* docs UI to interact with both a staging and a production environment.\n\nIf you pass a custom list of `servers` and there's a `root_path` (because your API lives behind a proxy), **FastAPI** will insert a \"server\" with this `root_path` at the beginning of the list.\n\nFor example:\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\nWill generate an OpenAPI schema like:\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // More stuff here\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // More stuff here\n    }\n}\n```\n\n/// tip\n\nNotice the auto-generated server with a `url` value of `/api/v1`, taken from the `root_path`.\n\n///\n\nIn the docs UI at [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) it would look like:\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip\n\nThe docs UI will interact with the server that you select.\n\n///\n\n/// note | Technical Details\n\nThe `servers` property in the OpenAPI specification is optional.\n\nIf you don't specify the `servers` parameter and `root_path` is equal to `/`, the `servers` property in the generated OpenAPI schema will be omitted entirely by default, which is the equivalent of a single server with a `url` value of `/`.\n\n///\n\n### Disable automatic server from `root_path` { #disable-automatic-server-from-root-path }\n\nIf you don't want **FastAPI** to include an automatic server using the `root_path`, you can use the parameter `root_path_in_servers=False`:\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\nand then it won't include it in the OpenAPI schema.\n\n## Mounting a sub-application { #mounting-a-sub-application }\n\nIf you need to mount a sub-application (as described in [Sub Applications - Mounts](sub-applications.md)) while also using a proxy with `root_path`, you can do it normally, as you would expect.\n\nFastAPI will internally use the `root_path` smartly, so it will just work. ✨\n"
  },
  {
    "path": "docs/en/docs/advanced/custom-response.md",
    "content": "# Custom Response - HTML, Stream, File, others { #custom-response-html-stream-file-others }\n\nBy default, **FastAPI** will return JSON responses.\n\nYou can override it by returning a `Response` directly as seen in [Return a Response directly](response-directly.md).\n\nBut if you return a `Response` directly (or any subclass, like `JSONResponse`), the data won't be automatically converted (even if you declare a `response_model`), and the documentation won't be automatically generated (for example, including the specific \"media type\", in the HTTP header `Content-Type` as part of the generated OpenAPI).\n\nBut you can also declare the `Response` that you want to be used (e.g. any `Response` subclass), in the *path operation decorator* using the `response_class` parameter.\n\nThe contents that you return from your *path operation function* will be put inside of that `Response`.\n\n/// note\n\nIf you use a response class with no media type, FastAPI will expect your response to have no content, so it will not document the response format in its generated OpenAPI docs.\n\n///\n\n## JSON Responses { #json-responses }\n\nBy default FastAPI returns JSON responses.\n\nIf you declare a [Response Model](../tutorial/response-model.md) FastAPI will use it to serialize the data to JSON, using Pydantic.\n\nIf you don't declare a response model, FastAPI will use the `jsonable_encoder` explained in [JSON Compatible Encoder](../tutorial/encoder.md) and put it in a `JSONResponse`.\n\nIf you declare a `response_class` with a JSON media type (`application/json`), like is the case with the `JSONResponse`, the data you return will be automatically converted (and filtered) with any Pydantic `response_model` that you declared in the *path operation decorator*. But the data won't be serialized to JSON bytes with Pydantic, instead it will be converted with the `jsonable_encoder` and then passed to the `JSONResponse` class, which will serialize it to bytes using the standard JSON library in Python.\n\n### JSON Performance { #json-performance }\n\nIn short, if you want the maximum performance, use a [Response Model](../tutorial/response-model.md) and don't declare a `response_class` in the *path operation decorator*.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## HTML Response { #html-response }\n\nTo return a response with HTML directly from **FastAPI**, use `HTMLResponse`.\n\n* Import `HTMLResponse`.\n* Pass `HTMLResponse` as the parameter `response_class` of your *path operation decorator*.\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info\n\nThe parameter `response_class` will also be used to define the \"media type\" of the response.\n\nIn this case, the HTTP header `Content-Type` will be set to `text/html`.\n\nAnd it will be documented as such in OpenAPI.\n\n///\n\n### Return a `Response` { #return-a-response }\n\nAs seen in [Return a Response directly](response-directly.md), you can also override the response directly in your *path operation*, by returning it.\n\nThe same example from above, returning an `HTMLResponse`, could look like:\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning\n\nA `Response` returned directly by your *path operation function* won't be documented in OpenAPI (for example, the `Content-Type` won't be documented) and won't be visible in the automatic interactive docs.\n\n///\n\n/// info\n\nOf course, the actual `Content-Type` header, status code, etc, will come from the `Response` object you returned.\n\n///\n\n### Document in OpenAPI and override `Response` { #document-in-openapi-and-override-response }\n\nIf you want to override the response from inside of the function but at the same time document the \"media type\" in OpenAPI, you can use the `response_class` parameter AND return a `Response` object.\n\nThe `response_class` will then be used only to document the OpenAPI *path operation*, but your `Response` will be used as is.\n\n#### Return an `HTMLResponse` directly { #return-an-htmlresponse-directly }\n\nFor example, it could be something like:\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\nIn this example, the function `generate_html_response()` already generates and returns a `Response` instead of returning the HTML in a `str`.\n\nBy returning the result of calling `generate_html_response()`, you are already returning a `Response` that will override the default **FastAPI** behavior.\n\nBut as you passed the `HTMLResponse` in the `response_class` too, **FastAPI** will know how to document it in OpenAPI and the interactive docs as HTML with `text/html`:\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## Available responses { #available-responses }\n\nHere are some of the available responses.\n\nKeep in mind that you can use `Response` to return anything else, or even create a custom sub-class.\n\n/// note | Technical Details\n\nYou could also use `from starlette.responses import HTMLResponse`.\n\n**FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.\n\n///\n\n### `Response` { #response }\n\nThe main `Response` class, all the other responses inherit from it.\n\nYou can return it directly.\n\nIt accepts the following parameters:\n\n* `content` - A `str` or `bytes`.\n* `status_code` - An `int` HTTP status code.\n* `headers` - A `dict` of strings.\n* `media_type` - A `str` giving the media type. E.g. `\"text/html\"`.\n\nFastAPI (actually Starlette) will automatically include a Content-Length header. It will also include a Content-Type header, based on the `media_type` and appending a charset for text types.\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\nTakes some text or bytes and returns an HTML response, as you read above.\n\n### `PlainTextResponse` { #plaintextresponse }\n\nTakes some text or bytes and returns a plain text response.\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\nTakes some data and returns an `application/json` encoded response.\n\nThis is the default response used in **FastAPI**, as you read above.\n\n/// note | Technical Details\n\nBut if you declare a response model or return type, that will be used directly to serialize the data to JSON, and a response with the right media type for JSON will be returned directly, without using the `JSONResponse` class.\n\nThis is the ideal way to get the best performance.\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\nReturns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default.\n\nYou can return a `RedirectResponse` directly:\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\nOr you can use it in the `response_class` parameter:\n\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\nIf you do that, then you can return the URL directly from your *path operation* function.\n\nIn this case, the `status_code` used will be the default one for the `RedirectResponse`, which is `307`.\n\n---\n\nYou can also use the `status_code` parameter combined with the `response_class` parameter:\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\nTakes an async generator or a normal generator/iterator (a function with `yield`) and streams the response body.\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | Technical Details\n\nAn `async` task can only be cancelled when it reaches an `await`. If there is no `await`, the generator (function with `yield`) can not be cancelled properly and may keep running even after cancellation is requested.\n\nSince this small example does not need any `await` statements, we add an `await anyio.sleep(0)` to give the event loop a chance to handle cancellation.\n\nThis would be even more important with large or infinite streams.\n\n///\n\n/// tip\n\nInstead of returning a `StreamingResponse` directly, you should probably follow the style in [Stream Data](./stream-data.md), it's much more convenient and handles cancellation behind the scenes for you.\n\nIf you are streaming JSON Lines, follow the [Stream JSON Lines](../tutorial/stream-json-lines.md) tutorial.\n\n///\n\n### `FileResponse` { #fileresponse }\n\nAsynchronously streams a file as the response.\n\nTakes a different set of arguments to instantiate than the other response types:\n\n* `path` - The file path to the file to stream.\n* `headers` - Any custom headers to include, as a dictionary.\n* `media_type` - A string giving the media type. If unset, the filename or path will be used to infer a media type.\n* `filename` - If set, this will be included in the response `Content-Disposition`.\n\nFile responses will include appropriate `Content-Length`, `Last-Modified` and `ETag` headers.\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\nYou can also use the `response_class` parameter:\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\nIn this case, you can return the file path directly from your *path operation* function.\n\n## Custom response class { #custom-response-class }\n\nYou can create your own custom response class, inheriting from `Response` and using it.\n\nFor example, let's say that you want to use [`orjson`](https://github.com/ijl/orjson) with some settings.\n\nLet's say you want it to return indented and formatted JSON, so you want to use the orjson option `orjson.OPT_INDENT_2`.\n\nYou could create a `CustomORJSONResponse`. The main thing you have to do is create a `Response.render(content)` method that returns the content as `bytes`:\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\nNow instead of returning:\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n...this response will return:\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\nOf course, you will probably find much better ways to take advantage of this than formatting JSON. 😉\n\n### `orjson` or Response Model { #orjson-or-response-model }\n\nIf what you are looking for is performance, you are probably better off using a [Response Model](../tutorial/response-model.md) than an `orjson` response.\n\nWith a response model, FastAPI will use Pydantic to serialize the data to JSON, without using intermediate steps, like converting it with `jsonable_encoder`, which would happen in any other case.\n\nAnd under the hood, Pydantic uses the same underlying Rust mechanisms as `orjson` to serialize to JSON, so you will already get the best performance with a response model.\n\n## Default response class { #default-response-class }\n\nWhen creating a **FastAPI** class instance or an `APIRouter` you can specify which response class to use by default.\n\nThe parameter that defines this is `default_response_class`.\n\nIn the example below, **FastAPI** will use `HTMLResponse` by default, in all *path operations*, instead of JSON.\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip\n\nYou can still override `response_class` in *path operations* as before.\n\n///\n\n## Additional documentation { #additional-documentation }\n\nYou can also declare the media type and many other details in OpenAPI using `responses`: [Additional Responses in OpenAPI](additional-responses.md).\n"
  },
  {
    "path": "docs/en/docs/advanced/dataclasses.md",
    "content": "# Using Dataclasses { #using-dataclasses }\n\nFastAPI is built on top of **Pydantic**, and I have been showing you how to use Pydantic models to declare requests and responses.\n\nBut FastAPI also supports using [`dataclasses`](https://docs.python.org/3/library/dataclasses.html) the same way:\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\nThis is still supported thanks to **Pydantic**, as it has [internal support for `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).\n\nSo, even with the code above that doesn't use Pydantic explicitly, FastAPI is using Pydantic to convert those standard dataclasses to Pydantic's own flavor of dataclasses.\n\nAnd of course, it supports the same:\n\n* data validation\n* data serialization\n* data documentation, etc.\n\nThis works the same way as with Pydantic models. And it is actually achieved in the same way underneath, using Pydantic.\n\n/// info\n\nKeep in mind that dataclasses can't do everything Pydantic models can do.\n\nSo, you might still need to use Pydantic models.\n\nBut if you have a bunch of dataclasses laying around, this is a nice trick to use them to power a web API using FastAPI. 🤓\n\n///\n\n## Dataclasses in `response_model` { #dataclasses-in-response-model }\n\nYou can also use `dataclasses` in the `response_model` parameter:\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\nThe dataclass will be automatically converted to a Pydantic dataclass.\n\nThis way, its schema will show up in the API docs user interface:\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## Dataclasses in Nested Data Structures { #dataclasses-in-nested-data-structures }\n\nYou can also combine `dataclasses` with other type annotations to make nested data structures.\n\nIn some cases, you might still have to use Pydantic's version of `dataclasses`. For example, if you have errors with the automatically generated API documentation.\n\nIn that case, you can simply swap the standard `dataclasses` with `pydantic.dataclasses`, which is a drop-in replacement:\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. We still import `field` from standard `dataclasses`.\n\n2. `pydantic.dataclasses` is a drop-in replacement for `dataclasses`.\n\n3. The `Author` dataclass includes a list of `Item` dataclasses.\n\n4. The `Author` dataclass is used as the `response_model` parameter.\n\n5. You can use other standard type annotations with dataclasses as the request body.\n\n    In this case, it's a list of `Item` dataclasses.\n\n6. Here we are returning a dictionary that contains `items` which is a list of dataclasses.\n\n    FastAPI is still capable of <dfn title=\"converting the data to a format that can be transmitted\">serializing</dfn> the data to JSON.\n\n7. Here the `response_model` is using a type annotation of a list of `Author` dataclasses.\n\n    Again, you can combine `dataclasses` with standard type annotations.\n\n8. Notice that this *path operation function* uses regular `def` instead of `async def`.\n\n    As always, in FastAPI you can combine `def` and `async def` as needed.\n\n    If you need a refresher about when to use which, check out the section _\"In a hurry?\"_ in the docs about [`async` and `await`](../async.md#in-a-hurry).\n\n9. This *path operation function* is not returning dataclasses (although it could), but a list of dictionaries with internal data.\n\n    FastAPI will use the `response_model` parameter (that includes dataclasses) to convert the response.\n\nYou can combine `dataclasses` with other type annotations in many different combinations to form complex data structures.\n\nCheck the in-code annotation tips above to see more specific details.\n\n## Learn More { #learn-more }\n\nYou can also combine `dataclasses` with other Pydantic models, inherit from them, include them in your own models, etc.\n\nTo learn more, check the [Pydantic docs about dataclasses](https://docs.pydantic.dev/latest/concepts/dataclasses/).\n\n## Version { #version }\n\nThis is available since FastAPI version `0.67.0`. 🔖\n"
  },
  {
    "path": "docs/en/docs/advanced/events.md",
    "content": "# Lifespan Events { #lifespan-events }\n\nYou can define logic (code) that should be executed before the application **starts up**. This means that this code will be executed **once**, **before** the application **starts receiving requests**.\n\nThe same way, you can define logic (code) that should be executed when the application is **shutting down**. In this case, this code will be executed **once**, **after** having handled possibly **many requests**.\n\nBecause this code is executed before the application **starts** taking requests, and right after it **finishes** handling requests, it covers the whole application **lifespan** (the word \"lifespan\" will be important in a second 😉).\n\nThis can be very useful for setting up **resources** that you need to use for the whole app, and that are **shared** among requests, and/or that you need to **clean up** afterwards. For example, a database connection pool, or loading a shared machine learning model.\n\n## Use Case { #use-case }\n\nLet's start with an example **use case** and then see how to solve it with this.\n\nLet's imagine that you have some **machine learning models** that you want to use to handle requests. 🤖\n\nThe same models are shared among requests, so, it's not one model per request, or one per user or something similar.\n\nLet's imagine that loading the model can **take quite some time**, because it has to read a lot of **data from disk**. So you don't want to do it for every request.\n\nYou could load it at the top level of the module/file, but that would also mean that it would **load the model** even if you are just running a simple automated test, then that test would be **slow** because it would have to wait for the model to load before being able to run an independent part of the code.\n\nThat's what we'll solve, let's load the model before the requests are handled, but only right before the application starts receiving requests, not while  the code is being loaded.\n\n## Lifespan { #lifespan }\n\nYou can define this *startup* and *shutdown* logic using the `lifespan` parameter of the `FastAPI` app, and a \"context manager\" (I'll show you what that is in a second).\n\nLet's start with an example and then see it in detail.\n\nWe create an async function `lifespan()` with `yield` like this:\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\nHere we are simulating the expensive *startup* operation of loading the model by putting the (fake) model function in the dictionary with machine learning models before the `yield`. This code will be executed **before** the application **starts taking requests**, during the *startup*.\n\nAnd then, right after the `yield`, we unload the model. This code will be executed **after** the application **finishes handling requests**, right before the *shutdown*. This could, for example, release resources like memory or a GPU.\n\n/// tip\n\nThe `shutdown` would happen when you are **stopping** the application.\n\nMaybe you need to start a new version, or you just got tired of running it. 🤷\n\n///\n\n### Lifespan function { #lifespan-function }\n\nThe first thing to notice, is that we are defining an async function with `yield`. This is very similar to Dependencies with `yield`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\nThe first part of the function, before the `yield`, will be executed **before** the application starts.\n\nAnd the part after the `yield` will be executed **after** the application has finished.\n\n### Async Context Manager { #async-context-manager }\n\nIf you check, the function is decorated with an `@asynccontextmanager`.\n\nThat converts the function into something called an \"**async context manager**\".\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\nA **context manager** in Python is something that you can use in a `with` statement, for example, `open()` can be used as a context manager:\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\nIn recent versions of Python, there's also an **async context manager**. You would use it with `async with`:\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\nWhen you create a context manager or an async context manager like above, what it does is that, before entering the `with` block, it will execute the code before the `yield`, and after exiting the `with` block, it will execute the code after the `yield`.\n\nIn our code example above, we don't use it directly, but we pass it to FastAPI for it to use it.\n\nThe `lifespan` parameter of the `FastAPI` app takes an **async context manager**, so we can pass our new `lifespan` async context manager to it.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## Alternative Events (deprecated) { #alternative-events-deprecated }\n\n/// warning\n\nThe recommended way to handle the *startup* and *shutdown* is using the `lifespan` parameter of the `FastAPI` app as described above. If you provide a `lifespan` parameter, `startup` and `shutdown` event handlers will no longer be called. It's all `lifespan` or all events, not both.\n\nYou can probably skip this part.\n\n///\n\nThere's an alternative way to define this logic to be executed during *startup* and during *shutdown*.\n\nYou can define event handlers (functions) that need to be executed before the application starts up, or when the application is shutting down.\n\nThese functions can be declared with `async def` or normal `def`.\n\n### `startup` event { #startup-event }\n\nTo add a function that should be run before the application starts, declare it with the event `\"startup\"`:\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\nIn this case, the `startup` event handler function will initialize the items \"database\" (just a `dict`) with some values.\n\nYou can add more than one event handler function.\n\nAnd your application won't start receiving requests until all the `startup` event handlers have completed.\n\n### `shutdown` event { #shutdown-event }\n\nTo add a function that should be run when the application is shutting down, declare it with the event `\"shutdown\"`:\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\nHere, the `shutdown` event handler function will write a text line `\"Application shutdown\"` to a file `log.txt`.\n\n/// info\n\nIn the `open()` function, the `mode=\"a\"` means \"append\", so, the line will be added after whatever is on that file, without overwriting the previous contents.\n\n///\n\n/// tip\n\nNotice that in this case we are using a standard Python `open()` function that interacts with a file.\n\nSo, it involves I/O (input/output), that requires \"waiting\" for things to be written to disk.\n\nBut `open()` doesn't use `async` and `await`.\n\nSo, we declare the event handler function with standard `def` instead of `async def`.\n\n///\n\n### `startup` and `shutdown` together { #startup-and-shutdown-together }\n\nThere's a high chance that the logic for your *startup* and *shutdown* is connected, you might want to start something and then finish it, acquire a resource and then release it, etc.\n\nDoing that in separated functions that don't share logic or variables together is more difficult as you would need to store values in global variables or similar tricks.\n\nBecause of that, it's now recommended to instead use the `lifespan` as explained above.\n\n## Technical Details { #technical-details }\n\nJust a technical detail for the curious nerds. 🤓\n\nUnderneath, in the ASGI technical specification, this is part of the [Lifespan Protocol](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), and it defines events called `startup` and `shutdown`.\n\n/// info\n\nYou can read more about the Starlette `lifespan` handlers in [Starlette's  Lifespan' docs](https://www.starlette.dev/lifespan/).\n\nIncluding how to handle lifespan state that can be used in other areas of your code.\n\n///\n\n## Sub Applications { #sub-applications }\n\n🚨 Keep in mind that these lifespan events (startup and shutdown) will only be executed for the main application, not for [Sub Applications - Mounts](sub-applications.md).\n"
  },
  {
    "path": "docs/en/docs/advanced/generate-clients.md",
    "content": "# Generating SDKs { #generating-sdks }\n\nBecause **FastAPI** is based on the **OpenAPI** specification, its APIs can be described in a standard format that many tools understand.\n\nThis makes it easy to generate up-to-date **documentation**, client libraries (<abbr title=\"Software Development Kits\">**SDKs**</abbr>) in multiple languages, and **testing** or **automation workflows** that stay in sync with your code.\n\nIn this guide, you'll learn how to generate a **TypeScript SDK** for your FastAPI backend.\n\n## Open Source SDK Generators { #open-source-sdk-generators }\n\nA versatile option is the [OpenAPI Generator](https://openapi-generator.tech/), which supports **many programming languages** and can generate SDKs from your OpenAPI specification.\n\nFor **TypeScript clients**, [Hey API](https://heyapi.dev/) is a purpose-built solution, providing an optimized experience for the TypeScript ecosystem.\n\nYou can discover more SDK generators on [OpenAPI.Tools](https://openapi.tools/#sdk).\n\n/// tip\n\nFastAPI automatically generates **OpenAPI 3.1** specifications, so any tool you use must support this version.\n\n///\n\n## SDK Generators from FastAPI Sponsors { #sdk-generators-from-fastapi-sponsors }\n\nThis section highlights **venture-backed** and **company-supported** solutions from companies that sponsor FastAPI. These products provide **additional features** and **integrations** on top of high-quality generated SDKs.\n\nBy ✨ [**sponsoring FastAPI**](../help-fastapi.md#sponsor-the-author) ✨, these companies help ensure the framework and its **ecosystem** remain healthy and **sustainable**.\n\nTheir sponsorship also demonstrates a strong commitment to the FastAPI **community** (you), showing that they care not only about offering a **great service** but also about supporting a **robust and thriving framework**, FastAPI. 🙇\n\nFor example, you might want to try:\n\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\nSome of these solutions may also be open source or offer free tiers, so you can try them without a financial commitment. Other commercial SDK generators are available and can be found online. 🤓\n\n## Create a TypeScript SDK { #create-a-typescript-sdk }\n\nLet's start with a simple FastAPI application:\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\nNotice that the *path operations* define the models they use for request payload and response payload, using the models `Item` and `ResponseMessage`.\n\n### API Docs { #api-docs }\n\nIf you go to `/docs`, you will see that it has the **schemas** for the data to be sent in requests and received in responses:\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\nYou can see those schemas because they were declared with the models in the app.\n\nThat information is available in the app's **OpenAPI schema**, and then shown in the API docs.\n\nThat same information from the models that is included in OpenAPI is what can be used to **generate the client code**.\n\n### Hey API { #hey-api }\n\nOnce we have a FastAPI app with the models, we can use Hey API to generate a TypeScript client. The fastest way to do that is via npx.\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\nThis will generate a TypeScript SDK in `./src/client`.\n\nYou can learn how to [install `@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started) and read about the [generated output](https://heyapi.dev/openapi-ts/output) on their website.\n\n### Using the SDK { #using-the-sdk }\n\nNow you can import and use the client code. It could look like this, notice that you get autocompletion for the methods:\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\nYou will also get autocompletion for the payload to send:\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip\n\nNotice the autocompletion for `name` and `price`, that was defined in the FastAPI application, in the `Item` model.\n\n///\n\nYou will have inline errors for the data that you send:\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\nThe response object will also have autocompletion:\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## FastAPI App with Tags { #fastapi-app-with-tags }\n\nIn many cases, your FastAPI app will be bigger, and you will probably use tags to separate different groups of *path operations*.\n\nFor example, you could have a section for **items** and another section for **users**, and they could be separated by tags:\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### Generate a TypeScript Client with Tags { #generate-a-typescript-client-with-tags }\n\nIf you generate a client for a FastAPI app using tags, it will normally also separate the client code based on the tags.\n\nThis way, you will be able to have things ordered and grouped correctly for the client code:\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\nIn this case, you have:\n\n* `ItemsService`\n* `UsersService`\n\n### Client Method Names { #client-method-names }\n\nRight now, the generated method names like `createItemItemsPost` don't look very clean:\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n...that's because the client generator uses the OpenAPI internal **operation ID** for each *path operation*.\n\nOpenAPI requires that each operation ID is unique across all the *path operations*, so FastAPI uses the **function name**, the **path**, and the **HTTP method/operation** to generate that operation ID, because that way it can make sure that the operation IDs are unique.\n\nBut I'll show you how to improve that next. 🤓\n\n## Custom Operation IDs and Better Method Names { #custom-operation-ids-and-better-method-names }\n\nYou can **modify** the way these operation IDs are **generated** to make them simpler and have **simpler method names** in the clients.\n\nIn this case, you will have to ensure that each operation ID is **unique** in some other way.\n\nFor example, you could make sure that each *path operation* has a tag, and then generate the operation ID based on the **tag** and the *path operation* **name** (the function name).\n\n### Custom Generate Unique ID Function { #custom-generate-unique-id-function }\n\nFastAPI uses a **unique ID** for each *path operation*, which is used for the **operation ID** and also for the names of any needed custom models, for requests or responses.\n\nYou can customize that function. It takes an `APIRoute` and outputs a string.\n\nFor example, here it is using the first tag (you will probably have only one tag) and the *path operation* name (the function name).\n\nYou can then pass that custom function to **FastAPI** as the `generate_unique_id_function` parameter:\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### Generate a TypeScript Client with Custom Operation IDs { #generate-a-typescript-client-with-custom-operation-ids }\n\nNow, if you generate the client again, you will see that it has the improved method names:\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\nAs you see, the method names now have the tag and then the function name, now they don't include information from the URL path and the HTTP operation.\n\n### Preprocess the OpenAPI Specification for the Client Generator { #preprocess-the-openapi-specification-for-the-client-generator }\n\nThe generated code still has some **duplicated information**.\n\nWe already know that this method is related to the **items** because that word is in the `ItemsService` (taken from the tag), but we still have the tag name prefixed in the method name too. 😕\n\nWe will probably still want to keep it for OpenAPI in general, as that will ensure that the operation IDs are **unique**.\n\nBut for the generated client, we could **modify** the OpenAPI operation IDs right before generating the clients, just to make those method names nicer and **cleaner**.\n\nWe could download the OpenAPI JSON to a file `openapi.json` and then we could **remove that prefixed tag** with a script like this:\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\nWith that, the operation IDs would be renamed from things like `items-get_items` to just `get_items`, that way the client generator can generate simpler method names.\n\n### Generate a TypeScript Client with the Preprocessed OpenAPI { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\nSince the end result is now in an `openapi.json` file, you need to update your input location:\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\nAfter generating the new client, you would now have **clean method names**, with all the **autocompletion**, **inline errors**, etc:\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## Benefits { #benefits }\n\nWhen using the automatically generated clients, you would get **autocompletion** for:\n\n* Methods.\n* Request payloads in the body, query parameters, etc.\n* Response payloads.\n\nYou would also have **inline errors** for everything.\n\nAnd whenever you update the backend code, and **regenerate** the frontend, it would have any new *path operations* available as methods, the old ones removed, and any other change would be reflected on the generated code. 🤓\n\nThis also means that if something changed, it will be **reflected** on the client code automatically. And if you **build** the client, it will error out if you have any **mismatch** in the data used.\n\nSo, you would **detect many errors** very early in the development cycle instead of having to wait for the errors to show up to your final users in production and then trying to debug where the problem is. ✨\n"
  },
  {
    "path": "docs/en/docs/advanced/index.md",
    "content": "# Advanced User Guide { #advanced-user-guide }\n\n## Additional Features { #additional-features }\n\nThe main [Tutorial - User Guide](../tutorial/index.md) should be enough to give you a tour through all the main features of **FastAPI**.\n\nIn the next sections you will see other options, configurations, and additional features.\n\n/// tip\n\nThe next sections are **not necessarily \"advanced\"**.\n\nAnd it's possible that for your use case, the solution is in one of them.\n\n///\n\n## Read the Tutorial first { #read-the-tutorial-first }\n\nYou could still use most of the features in **FastAPI** with the knowledge from the main [Tutorial - User Guide](../tutorial/index.md).\n\nAnd the next sections assume you already read it, and assume that you know those main ideas.\n"
  },
  {
    "path": "docs/en/docs/advanced/json-base64-bytes.md",
    "content": "# JSON with Bytes as Base64 { #json-with-bytes-as-base64 }\n\nIf your app needs to receive and send JSON data, but you need to include binary data in it, you can encode it as base64.\n\n## Base64 vs Files { #base64-vs-files }\n\nConsider first if you can use [Request Files](../tutorial/request-files.md) for uploading binary data and [Custom Response - FileResponse](./custom-response.md#fileresponse--fileresponse-) for sending binary data, instead of encoding it in JSON.\n\nJSON can only contain UTF-8 encoded strings, so it can't contain raw bytes.\n\nBase64 can encode binary data in strings, but to do it, it needs to use more characters than the original binary data, so it would normally be less efficient than regular files.\n\nUse base64 only if you definitely need to include binary data in JSON, and you can't use files for that.\n\n## Pydantic `bytes` { #pydantic-bytes }\n\nYou can declare a Pydantic model with `bytes` fields, and then use `val_json_bytes` in the model config to tell it to use base64 to *validate* input JSON data, as part of that validation it will decode the base64 string into bytes.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\nIf you check the `/docs`, they will show that the field `data` expects base64 encoded bytes:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\nYou could send a request like:\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip\n\n`aGVsbG8=` is the base64 encoding of `hello`.\n\n///\n\nAnd then Pydantic will decode the base64 string and give you the original bytes in the `data` field of the model.\n\nYou will receive a response like:\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## Pydantic `bytes` for Output Data { #pydantic-bytes-for-output-data }\n\nYou can also use `bytes` fields with `ser_json_bytes` in the model config for output data, and Pydantic will *serialize* the bytes as base64 when generating the JSON response.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## Pydantic `bytes` for Input and Output Data { #pydantic-bytes-for-input-and-output-data }\n\nAnd of course, you can use the same model configured to use base64 to handle both input (*validate*) with `val_json_bytes` and output (*serialize*) with `ser_json_bytes` when receiving and sending JSON data.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/en/docs/advanced/middleware.md",
    "content": "# Advanced Middleware { #advanced-middleware }\n\nIn the main tutorial you read how to add [Custom Middleware](../tutorial/middleware.md) to your application.\n\nAnd then you also read how to handle [CORS with the `CORSMiddleware`](../tutorial/cors.md).\n\nIn this section we'll see how to use other middlewares.\n\n## Adding ASGI middlewares { #adding-asgi-middlewares }\n\nAs **FastAPI** is based on Starlette and implements the <abbr title=\"Asynchronous Server Gateway Interface\">ASGI</abbr> specification, you can use any ASGI middleware.\n\nA middleware doesn't have to be made for FastAPI or Starlette to work, as long as it follows the ASGI spec.\n\nIn general, ASGI middlewares are classes that expect to receive an ASGI app as the first argument.\n\nSo, in the documentation for third-party ASGI middlewares they will probably tell you to do something like:\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\nBut FastAPI (actually Starlette) provides a simpler way to do it that makes sure that the internal middlewares handle server errors and custom exception handlers work properly.\n\nFor that, you use `app.add_middleware()` (as in the example for CORS).\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` receives a middleware class as the first argument and any additional arguments to be passed to the middleware.\n\n## Integrated middlewares { #integrated-middlewares }\n\n**FastAPI** includes several middlewares for common use cases, we'll see next how to use them.\n\n/// note | Technical Details\n\nFor the next examples, you could also use `from starlette.middleware.something import SomethingMiddleware`.\n\n**FastAPI** provides several middlewares in `fastapi.middleware` just as a convenience for you, the developer. But most of the available middlewares come directly from Starlette.\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\nEnforces that all incoming requests must either be `https` or `wss`.\n\nAny incoming request to `http` or `ws` will be redirected to the secure scheme instead.\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\nEnforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks.\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\nThe following arguments are supported:\n\n* `allowed_hosts` - A list of domain names that should be allowed as hostnames. Wildcard domains such as `*.example.com` are supported for matching subdomains. To allow any hostname either use `allowed_hosts=[\"*\"]` or omit the middleware.\n* `www_redirect` - If set to True, requests to non-www versions of the allowed hosts will be redirected to their www counterparts. Defaults to `True`.\n\nIf an incoming request does not validate correctly then a `400` response will be sent.\n\n## `GZipMiddleware` { #gzipmiddleware }\n\nHandles GZip responses for any request that includes `\"gzip\"` in the `Accept-Encoding` header.\n\nThe middleware will handle both standard and streaming responses.\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\nThe following arguments are supported:\n\n* `minimum_size` - Do not GZip responses that are smaller than this minimum size in bytes. Defaults to `500`.\n* `compresslevel` - Used during GZip compression. It is an integer ranging from 1 to 9. Defaults to `9`. Lower value results in faster compression but larger file sizes, while higher value results in slower compression but smaller file sizes.\n\n## Other middlewares { #other-middlewares }\n\nThere are many other ASGI middlewares.\n\nFor example:\n\n* [Uvicorn's `ProxyHeadersMiddleware`](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n* [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\nTo see other available middlewares check [Starlette's Middleware docs](https://www.starlette.dev/middleware/) and the [ASGI Awesome List](https://github.com/florimondmanca/awesome-asgi).\n"
  },
  {
    "path": "docs/en/docs/advanced/openapi-callbacks.md",
    "content": "# OpenAPI Callbacks { #openapi-callbacks }\n\nYou could create an API with a *path operation* that could trigger a request to an *external API* created by someone else (probably the same developer that would be *using* your API).\n\nThe process that happens when your API app calls the *external API* is named a \"callback\". Because the software that the external developer wrote sends a request to your API and then your API *calls back*, sending a request to an *external API* (that was probably created by the same developer).\n\nIn this case, you could want to document how that external API *should* look like. What *path operation* it should have, what body it should expect, what response it should return, etc.\n\n## An app with callbacks { #an-app-with-callbacks }\n\nLet's see all this with an example.\n\nImagine you develop an app that allows creating invoices.\n\nThese invoices will have an `id`, `title` (optional), `customer`, and `total`.\n\nThe user of your API (an external developer) will create an invoice in your API with a POST request.\n\nThen your API will (let's imagine):\n\n* Send the invoice to some customer of the external developer.\n* Collect the money.\n* Send a notification back to the API user (the external developer).\n    * This will be done by sending a POST request (from *your API*) to some *external API* provided by that external developer (this is the \"callback\").\n\n## The normal **FastAPI** app { #the-normal-fastapi-app }\n\nLet's first see how the normal API app would look like before adding the callback.\n\nIt will have a *path operation* that will receive an `Invoice` body, and a query parameter `callback_url` that will contain the URL for the callback.\n\nThis part is pretty normal, most of the code is probably already familiar to you:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip\n\nThe `callback_url` query parameter uses a Pydantic [Url](https://docs.pydantic.dev/latest/api/networks/) type.\n\n///\n\nThe only new thing is the `callbacks=invoices_callback_router.routes` as an argument to the *path operation decorator*. We'll see what that is next.\n\n## Documenting the callback { #documenting-the-callback }\n\nThe actual callback code will depend heavily on your own API app.\n\nAnd it will probably vary a lot from one app to the next.\n\nIt could be just one or two lines of code, like:\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\nBut possibly the most important part of the callback is making sure that your API user (the external developer) implements the *external API* correctly, according to the data that *your API* is going to send in the request body of the callback, etc.\n\nSo, what we will do next is add the code to document how that *external API* should look like to receive the callback from *your API*.\n\nThat documentation will show up in the Swagger UI at `/docs` in your API, and it will let external developers know how to build the *external API*.\n\nThis example doesn't implement the callback itself (that could be just a line of code), only the documentation part.\n\n/// tip\n\nThe actual callback is just an HTTP request.\n\nWhen implementing the callback yourself, you could use something like [HTTPX](https://www.python-httpx.org) or [Requests](https://requests.readthedocs.io/).\n\n///\n\n## Write the callback documentation code { #write-the-callback-documentation-code }\n\nThis code won't be executed in your app, we only need it to *document* how that *external API* should look like.\n\nBut, you already know how to easily create automatic documentation for an API with **FastAPI**.\n\nSo we are going to use that same knowledge to document how the *external API* should look like... by creating the *path operation(s)* that the external API should implement (the ones your API will call).\n\n/// tip\n\nWhen writing the code to document a callback, it might be useful to imagine that you are that *external developer*. And that you are currently implementing the *external API*, not *your API*.\n\nTemporarily adopting this point of view (of the *external developer*) can help you feel like it's more obvious where to put the parameters, the Pydantic model for the body, for the response, etc. for that *external API*.\n\n///\n\n### Create a callback `APIRouter` { #create-a-callback-apirouter }\n\nFirst create a new `APIRouter` that will contain one or more callbacks.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### Create the callback *path operation* { #create-the-callback-path-operation }\n\nTo create the callback *path operation* use the same `APIRouter` you created above.\n\nIt should look just like a normal FastAPI *path operation*:\n\n* It should probably have a declaration of the body it should receive, e.g. `body: InvoiceEvent`.\n* And it could also have a declaration of the response it should return, e.g. `response_model=InvoiceEventReceived`.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\nThere are 2 main differences from a normal *path operation*:\n\n* It doesn't need to have any actual code, because your app will never call this code. It's only used to document the *external API*. So, the function could just have `pass`.\n* The *path* can contain an [OpenAPI 3 expression](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (see more below) where it can use variables with parameters and parts of the original request sent to *your API*.\n\n### The callback path expression { #the-callback-path-expression }\n\nThe callback *path* can have an [OpenAPI 3 expression](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) that can contain parts of the original request sent to *your API*.\n\nIn this case, it's the `str`:\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\nSo, if your API user (the external developer) sends a request to *your API* to:\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\nwith a JSON body of:\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\nthen *your API* will process the invoice, and at some point later, send a callback request to the `callback_url` (the *external API*):\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\nwith a JSON body containing something like:\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\nand it would expect a response from that *external API* with a JSON body like:\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip\n\nNotice how the callback URL used contains the URL received as a query parameter in `callback_url` (`https://www.external.org/events`) and also the invoice `id` from inside of the JSON body (`2expen51ve`).\n\n///\n\n### Add the callback router { #add-the-callback-router }\n\nAt this point you have the *callback path operation(s)* needed (the one(s) that the *external developer*  should implement in the *external API*) in the callback router you created above.\n\nNow use the parameter `callbacks` in *your API's path operation decorator* to pass the attribute `.routes` (that's actually just a `list` of routes/*path operations*) from that callback router:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip\n\nNotice that you are not passing the router itself (`invoices_callback_router`) to `callback=`, but the attribute `.routes`, as in `invoices_callback_router.routes`.\n\n///\n\n### Check the docs { #check-the-docs }\n\nNow you can start your app and go to [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nYou will see your docs including a \"Callbacks\" section for your *path operation* that shows how the *external API* should look like:\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/en/docs/advanced/openapi-webhooks.md",
    "content": "# OpenAPI Webhooks { #openapi-webhooks }\n\nThere are cases where you want to tell your API **users** that your app could call *their* app (sending a request) with some data, normally to **notify** of some type of **event**.\n\nThis means that instead of the normal process of your users sending requests to your API, it's **your API** (or your app) that could **send requests to their system** (to their API, their app).\n\nThis is normally called a **webhook**.\n\n## Webhooks steps { #webhooks-steps }\n\nThe process normally is that **you define** in your code what is the message that you will send, the **body of the request**.\n\nYou also define in some way at which **moments** your app will send those requests or events.\n\nAnd **your users** define in some way (for example in a web dashboard somewhere) the **URL** where your app should send those requests.\n\nAll the **logic** about how to register the URLs for webhooks and the code to actually send those requests is up to you. You write it however you want to in **your own code**.\n\n## Documenting webhooks with **FastAPI** and OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }\n\nWith **FastAPI**, using OpenAPI, you can define the names of these webhooks, the types of HTTP operations that your app can send (e.g. `POST`, `PUT`, etc.) and the request **bodies** that your app would send.\n\nThis can make it a lot easier for your users to **implement their APIs** to receive your **webhook** requests, they might even be able to autogenerate some of their own API code.\n\n/// info\n\nWebhooks are available in OpenAPI 3.1.0 and above, supported by FastAPI `0.99.0` and above.\n\n///\n\n## An app with webhooks { #an-app-with-webhooks }\n\nWhen you create a **FastAPI** application, there is a `webhooks` attribute that you can use to define *webhooks*, the same way you would define *path operations*, for example with `@app.webhooks.post()`.\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\nThe webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**.\n\n/// info\n\nThe `app.webhooks` object is actually just an `APIRouter`, the same type you would use when structuring your app with multiple files.\n\n///\n\nNotice that with webhooks you are actually not declaring a *path* (like `/items/`), the text you pass there is just an **identifier** of the webhook (the name of the event), for example in `@app.webhooks.post(\"new-subscription\")`, the webhook name is `new-subscription`.\n\nThis is because it is expected that **your users** would define the actual **URL path** where they want to receive the webhook request in some other way (e.g. a web dashboard).\n\n### Check the docs { #check-the-docs }\n\nNow you can start your app and go to [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nYou will see your docs have the normal *path operations* and now also some **webhooks**:\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/en/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# Path Operation Advanced Configuration { #path-operation-advanced-configuration }\n\n## OpenAPI operationId { #openapi-operationid }\n\n/// warning\n\nIf you are not an \"expert\" in OpenAPI, you probably don't need this.\n\n///\n\nYou can set the OpenAPI `operationId` to be used in your *path operation* with the parameter `operation_id`.\n\nYou would have to make sure that it is unique for each operation.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### Using the *path operation function* name as the operationId { #using-the-path-operation-function-name-as-the-operationid }\n\nIf you want to use your APIs' function names as `operationId`s, you can iterate over all of them and override each *path operation's* `operation_id` using their `APIRoute.name`.\n\nYou should do it after adding all your *path operations*.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip\n\nIf you manually call `app.openapi()`, you should update the `operationId`s before that.\n\n///\n\n/// warning\n\nIf you do this, you have to make sure each one of your *path operation functions* has a unique name.\n\nEven if they are in different modules (Python files).\n\n///\n\n## Exclude from OpenAPI { #exclude-from-openapi }\n\nTo exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## Advanced description from docstring { #advanced-description-from-docstring }\n\nYou can limit the lines used from the docstring of a *path operation function* for OpenAPI.\n\nAdding an `\\f` (an escaped \"form feed\" character) causes **FastAPI** to truncate the output used for OpenAPI at this point.\n\nIt won't show up in the documentation, but other tools (such as Sphinx) will be able to use the rest.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## Additional Responses { #additional-responses }\n\nYou probably have seen how to declare the `response_model` and `status_code` for a *path operation*.\n\nThat defines the metadata about the main response of a *path operation*.\n\nYou can also declare additional responses with their models, status codes, etc.\n\nThere's a whole chapter here in the documentation about it, you can read it at [Additional Responses in OpenAPI](additional-responses.md).\n\n## OpenAPI Extra { #openapi-extra }\n\nWhen you declare a *path operation* in your application, **FastAPI** automatically generates the relevant metadata about that *path operation* to be included in the OpenAPI schema.\n\n/// note | Technical details\n\nIn the OpenAPI specification it is called the [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object).\n\n///\n\nIt has all the information about the *path operation* and is used to generate the automatic documentation.\n\nIt includes the `tags`, `parameters`, `requestBody`, `responses`, etc.\n\nThis *path operation*-specific OpenAPI schema is normally generated automatically by **FastAPI**, but you can also extend it.\n\n/// tip\n\nThis is a low level extension point.\n\nIf you only need to declare additional responses, a more convenient way to do it is with [Additional Responses in OpenAPI](additional-responses.md).\n\n///\n\nYou can extend the OpenAPI schema for a *path operation* using the parameter `openapi_extra`.\n\n### OpenAPI Extensions { #openapi-extensions }\n\nThis `openapi_extra` can be helpful, for example, to declare [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\nIf you open the automatic API docs, your extension will show up at the bottom of the specific *path operation*.\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\nAnd if you see the resulting OpenAPI (at `/openapi.json` in your API), you will see your extension as part of the specific *path operation* too:\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### Custom OpenAPI *path operation* schema { #custom-openapi-path-operation-schema }\n\nThe dictionary in `openapi_extra` will be deeply merged with the automatically generated OpenAPI schema for the *path operation*.\n\nSo, you could add additional data to the automatically generated schema.\n\nFor example, you could decide to read and validate the request with your own code, without using the automatic features of FastAPI with Pydantic, but you could still want to define the request in the OpenAPI schema.\n\nYou could do that with `openapi_extra`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\nIn this example, we didn't declare any Pydantic model. In fact, the request body is not even <dfn title=\"converted from some plain format, like bytes, into Python objects\">parsed</dfn> as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way.\n\nNevertheless, we can declare the expected schema for the request body.\n\n### Custom OpenAPI content type { #custom-openapi-content-type }\n\nUsing this same trick, you could use a Pydantic model to define the JSON Schema that is then included in the custom OpenAPI schema section for the *path operation*.\n\nAnd you could do this even if the data type in the request is not JSON.\n\nFor example, in this application we don't use FastAPI's integrated functionality to extract the JSON Schema from Pydantic models nor the automatic validation for JSON. In fact, we are declaring the request content type as YAML, not JSON:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\nNevertheless, although we are not using the default integrated functionality, we are still using a Pydantic model to manually generate the JSON Schema for the data that we want to receive in YAML.\n\nThen we use the request directly, and extract the body as `bytes`. This means that FastAPI won't even try to parse the request payload as JSON.\n\nAnd then in our code, we parse that YAML content directly, and then we are again using the same Pydantic model to validate the YAML content:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip\n\nHere we reuse the same Pydantic model.\n\nBut the same way, we could have validated it in some other way.\n\n///\n"
  },
  {
    "path": "docs/en/docs/advanced/response-change-status-code.md",
    "content": "# Response - Change Status Code { #response-change-status-code }\n\nYou probably read before that you can set a default [Response Status Code](../tutorial/response-status-code.md).\n\nBut in some cases you need to return a different status code than the default.\n\n## Use case { #use-case }\n\nFor example, imagine that you want to return an HTTP status code of \"OK\" `200` by default.\n\nBut if the data didn't exist, you want to create it, and return an HTTP status code of \"CREATED\" `201`.\n\nBut you still want to be able to filter and convert the data you return with a `response_model`.\n\nFor those cases, you can use a `Response` parameter.\n\n## Use a `Response` parameter { #use-a-response-parameter }\n\nYou can declare a parameter of type `Response` in your *path operation function* (as you can do for cookies and headers).\n\nAnd then you can set the `status_code` in that *temporal* response object.\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\nAnd then you can return any object you need, as you normally would (a `dict`, a database model, etc).\n\nAnd if you declared a `response_model`, it will still be used to filter and convert the object you returned.\n\n**FastAPI** will use that *temporal* response to extract the status code (also cookies and headers), and will put them in the final response that contains the value you returned, filtered by any `response_model`.\n\nYou can also declare the `Response` parameter in dependencies, and set the status code in them. But keep in mind that the last one to be set will win.\n"
  },
  {
    "path": "docs/en/docs/advanced/response-cookies.md",
    "content": "# Response Cookies { #response-cookies }\n\n## Use a `Response` parameter { #use-a-response-parameter }\n\nYou can declare a parameter of type `Response` in your *path operation function*.\n\nAnd then you can set cookies in that *temporal* response object.\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\nAnd then you can return any object you need, as you normally would (a `dict`, a database model, etc).\n\nAnd if you declared a `response_model`, it will still be used to filter and convert the object you returned.\n\n**FastAPI** will use that *temporal* response to extract the cookies (also headers and status code), and will put them in the final response that contains the value you returned, filtered by any `response_model`.\n\nYou can also declare the `Response` parameter in dependencies, and set cookies (and headers) in them.\n\n## Return a `Response` directly { #return-a-response-directly }\n\nYou can also create cookies when returning a `Response` directly in your code.\n\nTo do that, you can create a response as described in [Return a Response Directly](response-directly.md).\n\nThen set Cookies in it, and then return it:\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip\n\nKeep in mind that if you return a response directly instead of using the `Response` parameter, FastAPI will return it directly.\n\nSo, you will have to make sure your data is of the correct type. E.g. it is compatible with JSON, if you are returning a `JSONResponse`.\n\nAnd also that you are not sending any data that should have been filtered by a `response_model`.\n\n///\n\n### More info { #more-info }\n\n/// note | Technical Details\n\nYou could also use `from starlette.responses import Response` or `from starlette.responses import JSONResponse`.\n\n**FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.\n\nAnd as the `Response` can be used frequently to set headers and cookies, **FastAPI** also provides it at `fastapi.Response`.\n\n///\n\nTo see all the available parameters and options, check the [documentation in Starlette](https://www.starlette.dev/responses/#set-cookie).\n"
  },
  {
    "path": "docs/en/docs/advanced/response-directly.md",
    "content": "# Return a Response Directly { #return-a-response-directly }\n\nWhen you create a **FastAPI** *path operation* you can normally return any data from it: a `dict`, a `list`, a Pydantic model, a database model, etc.\n\nIf you declare a [Response Model](../tutorial/response-model.md) FastAPI will use it to serialize the data to JSON, using Pydantic.\n\nIf you don't declare a response model, FastAPI will use the `jsonable_encoder` explained in [JSON Compatible Encoder](../tutorial/encoder.md) and put it in a `JSONResponse`.\n\nYou could also create a `JSONResponse` directly and return it.\n\n/// tip\n\nYou will normally have much better performance using a [Response Model](../tutorial/response-model.md) than returning a `JSONResponse` directly, as that way it serializes the data using Pydantic, in Rust.\n\n///\n\n## Return a `Response` { #return-a-response }\n\nYou can return a `Response` or any sub-class of it.\n\n/// info\n\n`JSONResponse` itself is a sub-class of `Response`.\n\n///\n\nAnd when you return a `Response`, **FastAPI** will pass it directly.\n\nIt won't do any data conversion with Pydantic models, it won't convert the contents to any type, etc.\n\nThis gives you a lot of **flexibility**. You can return any data type, override any data declaration or validation, etc.\n\nIt also gives you a lot of **responsibility**. You have to make sure that the data you return is correct, in the correct format, that it can be serialized, etc.\n\n## Using the `jsonable_encoder` in a `Response` { #using-the-jsonable-encoder-in-a-response }\n\nBecause **FastAPI** doesn't make any changes to a `Response` you return, you have to make sure its contents are ready for it.\n\nFor example, you cannot put a Pydantic model in a `JSONResponse` without first converting it to a `dict` with all the data types (like `datetime`, `UUID`, etc) converted to JSON-compatible types.\n\nFor those cases, you can use the `jsonable_encoder` to convert your data before passing it to a response:\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | Technical Details\n\nYou could also use `from starlette.responses import JSONResponse`.\n\n**FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.\n\n///\n\n## Returning a custom `Response` { #returning-a-custom-response }\n\nThe example above shows all the parts you need, but it's not very useful yet, as you could have just returned the `item` directly, and **FastAPI** would put it in a `JSONResponse` for you, converting it to a `dict`, etc. All that by default.\n\nNow, let's see how you could use that to return a custom response.\n\nLet's say that you want to return an [XML](https://en.wikipedia.org/wiki/XML) response.\n\nYou could put your XML content in a string, put that in a `Response`, and return it:\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## How a Response Model Works { #how-a-response-model-works }\n\nWhen you declare a [Response Model - Return Type](../tutorial/response-model.md) in a path operation, **FastAPI** will use it to serialize the data to JSON, using Pydantic.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nAs that will happen on the Rust side, the performance will be much better than if it was done with regular Python and the `JSONResponse` class.\n\nWhen using a `response_model` or return type, FastAPI won't use the `jsonable_encoder` to convert the data (which would be slower) nor the `JSONResponse` class.\n\nInstead it takes the JSON bytes generated with Pydantic using the response model (or return type) and returns a `Response` with the right media type for JSON directly (`application/json`).\n\n## Notes { #notes }\n\nWhen you return a `Response` directly its data is not validated, converted (serialized), or documented automatically.\n\nBut you can still document it as described in [Additional Responses in OpenAPI](additional-responses.md).\n\nYou can see in later sections how to use/declare these custom `Response`s while still having automatic data conversion, documentation, etc.\n"
  },
  {
    "path": "docs/en/docs/advanced/response-headers.md",
    "content": "# Response Headers { #response-headers }\n\n## Use a `Response` parameter { #use-a-response-parameter }\n\nYou can declare a parameter of type `Response` in your *path operation function* (as you can do for cookies).\n\nAnd then you can set headers in that *temporal* response object.\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\nAnd then you can return any object you need, as you normally would (a `dict`, a database model, etc).\n\nAnd if you declared a `response_model`, it will still be used to filter and convert the object you returned.\n\n**FastAPI** will use that *temporal* response to extract the headers (also cookies and status code), and will put them in the final response that contains the value you returned, filtered by any `response_model`.\n\nYou can also declare the `Response` parameter in dependencies, and set headers (and cookies) in them.\n\n## Return a `Response` directly { #return-a-response-directly }\n\nYou can also add headers when you return a `Response` directly.\n\nCreate a response as described in [Return a Response Directly](response-directly.md) and pass the headers as an additional parameter:\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | Technical Details\n\nYou could also use `from starlette.responses import Response` or `from starlette.responses import JSONResponse`.\n\n**FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.\n\nAnd as the `Response` can be used frequently to set headers and cookies, **FastAPI** also provides it at `fastapi.Response`.\n\n///\n\n## Custom Headers { #custom-headers }\n\nKeep in mind that custom proprietary headers can be added [using the `X-` prefix](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nBut if you have custom headers that you want a client in a browser to be able to see, you need to add them to your CORS configurations (read more in [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), using the parameter `expose_headers` documented in [Starlette's CORS docs](https://www.starlette.dev/middleware/#corsmiddleware).\n"
  },
  {
    "path": "docs/en/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP Basic Auth { #http-basic-auth }\n\nFor the simplest cases, you can use HTTP Basic Auth.\n\nIn HTTP Basic Auth, the application expects a header that contains a username and a password.\n\nIf it doesn't receive it, it returns an HTTP 401 \"Unauthorized\" error.\n\nAnd returns a header `WWW-Authenticate` with a value of `Basic`, and an optional `realm` parameter.\n\nThat tells the browser to show the integrated prompt for a username and password.\n\nThen, when you type that username and password, the browser sends them in the header automatically.\n\n## Simple HTTP Basic Auth { #simple-http-basic-auth }\n\n* Import `HTTPBasic` and `HTTPBasicCredentials`.\n* Create a \"`security` scheme\" using `HTTPBasic`.\n* Use that `security` with a dependency in your *path operation*.\n* It returns an object of type `HTTPBasicCredentials`:\n    * It contains the `username` and `password` sent.\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\nWhen you try to open the URL for the first time (or click the \"Execute\" button in the docs) the browser will ask you for your username and password:\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## Check the username { #check-the-username }\n\nHere's a more complete example.\n\nUse a dependency to check if the username and password are correct.\n\nFor this, use the Python standard module [`secrets`](https://docs.python.org/3/library/secrets.html) to check the username and password.\n\n`secrets.compare_digest()` needs to take `bytes` or a `str` that only contains ASCII characters (the ones in English), this means it wouldn't work with characters like `á`, as in `Sebastián`.\n\nTo handle that, we first convert the `username` and `password` to `bytes` encoding them with UTF-8.\n\nThen we can use `secrets.compare_digest()` to ensure that `credentials.username` is `\"stanleyjobson\"`, and that `credentials.password` is `\"swordfish\"`.\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\nThis would be similar to:\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # Return some error\n    ...\n```\n\nBut by using the `secrets.compare_digest()` it will be secure against a type of attacks called \"timing attacks\".\n\n### Timing Attacks { #timing-attacks }\n\nBut what's a \"timing attack\"?\n\nLet's imagine some attackers are trying to guess the username and password.\n\nAnd they send a request with a username `johndoe` and a password `love123`.\n\nThen the Python code in your application would be equivalent to something like:\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nBut right at the moment Python compares the first `j` in `johndoe` to the first `s` in `stanleyjobson`, it will return `False`, because it already knows that those two strings are not the same, thinking that \"there's no need to waste more computation comparing the rest of the letters\". And your application will say \"Incorrect username or password\".\n\nBut then the attackers try with username `stanleyjobsox` and password `love123`.\n\nAnd your application code does something like:\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nPython will have to compare the whole `stanleyjobso` in both `stanleyjobsox` and `stanleyjobson` before realizing that both strings are not the same. So it will take some extra microseconds to reply back \"Incorrect username or password\".\n\n#### The time to answer helps the attackers { #the-time-to-answer-helps-the-attackers }\n\nAt that point, by noticing that the server took some microseconds longer to send the \"Incorrect username or password\" response, the attackers will know that they got _something_ right, some of the initial letters were right.\n\nAnd then they can try again knowing that it's probably something more similar to `stanleyjobsox` than to `johndoe`.\n\n#### A \"professional\" attack { #a-professional-attack }\n\nOf course, the attackers would not try all this by hand, they would write a program to do it, possibly with thousands or millions of tests per second. And they would get just one extra correct letter at a time.\n\nBut doing that, in some minutes or hours the attackers would have guessed the correct username and password, with the \"help\" of our application, just using the time taken to answer.\n\n#### Fix it with `secrets.compare_digest()` { #fix-it-with-secrets-compare-digest }\n\nBut in our code we are actually using `secrets.compare_digest()`.\n\nIn short, it will take the same time to compare `stanleyjobsox` to `stanleyjobson` than it takes to compare `johndoe` to `stanleyjobson`. And the same for the password.\n\nThat way, using `secrets.compare_digest()` in your application code, it will be safe against this whole range of security attacks.\n\n### Return the error { #return-the-error }\n\nAfter detecting that the credentials are incorrect, return an `HTTPException` with a status code 401 (the same returned when no credentials are provided) and add the header `WWW-Authenticate` to make the browser show the login prompt again:\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/en/docs/advanced/security/index.md",
    "content": "# Advanced Security { #advanced-security }\n\n## Additional Features { #additional-features }\n\nThere are some extra features to handle security apart from the ones covered in the [Tutorial - User Guide: Security](../../tutorial/security/index.md).\n\n/// tip\n\nThe next sections are **not necessarily \"advanced\"**.\n\nAnd it's possible that for your use case, the solution is in one of them.\n\n///\n\n## Read the Tutorial first { #read-the-tutorial-first }\n\nThe next sections assume you already read the main [Tutorial - User Guide: Security](../../tutorial/security/index.md).\n\nThey are all based on the same concepts, but allow some extra functionalities.\n"
  },
  {
    "path": "docs/en/docs/advanced/security/oauth2-scopes.md",
    "content": "# OAuth2 scopes { #oauth2-scopes }\n\nYou can use OAuth2 scopes directly with **FastAPI**, they are integrated to work seamlessly.\n\nThis would allow you to have a more fine-grained permission system, following the OAuth2 standard, integrated into your OpenAPI application (and the API docs).\n\nOAuth2 with scopes is the mechanism used by many big authentication providers, like Facebook, Google, GitHub, Microsoft, X (Twitter), etc. They use it to provide specific permissions to users and applications.\n\nEvery time you \"log in with\" Facebook, Google, GitHub, Microsoft, X (Twitter), that application is using OAuth2 with scopes.\n\nIn this section you will see how to manage authentication and authorization with the same OAuth2 with scopes in your **FastAPI** application.\n\n/// warning\n\nThis is a more or less advanced section. If you are just starting, you can skip it.\n\nYou don't necessarily need OAuth2 scopes, and you can handle authentication and authorization however you want.\n\nBut OAuth2 with scopes can be nicely integrated into your API (with OpenAPI) and your API docs.\n\nNevertheless, you still enforce those scopes, or any other security/authorization requirement, however you need, in your code.\n\nIn many cases, OAuth2 with scopes can be an overkill.\n\nBut if you know you need it, or you are curious, keep reading.\n\n///\n\n## OAuth2 scopes and OpenAPI { #oauth2-scopes-and-openapi }\n\nThe OAuth2 specification defines \"scopes\" as a list of strings separated by spaces.\n\nThe content of each of these strings can have any format, but should not contain spaces.\n\nThese scopes represent \"permissions\".\n\nIn OpenAPI (e.g. the API docs), you can define \"security schemes\".\n\nWhen one of these security schemes uses OAuth2, you can also declare and use scopes.\n\nEach \"scope\" is just a string (without spaces).\n\nThey are normally used to declare specific security permissions, for example:\n\n* `users:read` or `users:write` are common examples.\n* `instagram_basic` is used by Facebook / Instagram.\n* `https://www.googleapis.com/auth/drive` is used by Google.\n\n/// info\n\nIn OAuth2 a \"scope\" is just a string that declares a specific permission required.\n\nIt doesn't matter if it has other characters like `:` or if it is a URL.\n\nThose details are implementation specific.\n\nFor OAuth2 they are just strings.\n\n///\n\n## Global view { #global-view }\n\nFirst, let's quickly see the parts that change from the examples in the main **Tutorial - User Guide** for [OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md). Now using OAuth2 scopes:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\nNow let's review those changes step by step.\n\n## OAuth2 Security scheme { #oauth2-security-scheme }\n\nThe first change is that now we are declaring the OAuth2 security scheme with two available scopes, `me` and `items`.\n\nThe `scopes` parameter receives a `dict` with each scope as a key and the description as the value:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\nBecause we are now declaring those scopes, they will show up in the API docs when you log-in/authorize.\n\nAnd you will be able to select which scopes you want to give access to: `me` and `items`.\n\nThis is the same mechanism used when you give permissions while logging in with Facebook, Google, GitHub, etc:\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## JWT token with scopes { #jwt-token-with-scopes }\n\nNow, modify the token *path operation* to return the scopes requested.\n\nWe are still using the same `OAuth2PasswordRequestForm`. It includes a property `scopes` with a `list` of `str`, with each scope it received in the request.\n\nAnd we return the scopes as part of the JWT token.\n\n/// danger\n\nFor simplicity, here we are just adding the scopes received directly to the token.\n\nBut in your application, for security, you should make sure you only add the scopes that the user is actually able to have, or the ones you have predefined.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## Declare scopes in *path operations* and dependencies { #declare-scopes-in-path-operations-and-dependencies }\n\nNow we declare that the *path operation* for `/users/me/items/` requires the scope `items`.\n\nFor this, we import and use `Security` from `fastapi`.\n\nYou can use `Security` to declare dependencies (just like `Depends`), but `Security` also receives a parameter `scopes` with a list of scopes (strings).\n\nIn this case, we pass a dependency function `get_current_active_user` to `Security` (the same way we would do with `Depends`).\n\nBut we also pass a `list` of scopes, in this case with just one scope: `items` (it could have more).\n\nAnd the dependency function `get_current_active_user` can also declare sub-dependencies, not only with `Depends` but also with `Security`. Declaring its own sub-dependency function (`get_current_user`), and more scope requirements.\n\nIn this case, it requires the scope `me` (it could require more than one scope).\n\n/// note\n\nYou don't necessarily need to add different scopes in different places.\n\nWe are doing it here to demonstrate how **FastAPI** handles scopes declared at different levels.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | Technical Details\n\n`Security` is actually a subclass of `Depends`, and it has just one extra parameter that we'll see later.\n\nBut by using `Security` instead of `Depends`, **FastAPI** will know that it can declare security scopes, use them internally, and document the API with OpenAPI.\n\nBut when you import `Query`, `Path`, `Depends`, `Security` and others from `fastapi`, those are actually functions that return special classes.\n\n///\n\n## Use `SecurityScopes` { #use-securityscopes }\n\nNow update the dependency `get_current_user`.\n\nThis is the one used by the dependencies above.\n\nHere's where we are using the same OAuth2 scheme we created before, declaring it as a dependency: `oauth2_scheme`.\n\nBecause this dependency function doesn't have any scope requirements itself, we can use `Depends` with `oauth2_scheme`, we don't have to use `Security` when we don't need to specify security scopes.\n\nWe also declare a special parameter of type `SecurityScopes`, imported from `fastapi.security`.\n\nThis `SecurityScopes` class is similar to `Request` (`Request` was used to get the request object directly).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## Use the `scopes` { #use-the-scopes }\n\nThe parameter `security_scopes` will be of type `SecurityScopes`.\n\nIt will have a property `scopes` with a list containing all the scopes required by itself and all the dependencies that use this as a sub-dependency. That means, all the \"dependants\"... this might sound confusing, it is explained again later below.\n\nThe `security_scopes` object (of class `SecurityScopes`) also provides a `scope_str` attribute with a single string, containing those scopes separated by spaces (we are going to use it).\n\nWe create an `HTTPException` that we can reuse (`raise`) later at several points.\n\nIn this exception, we include the scopes required (if any) as a string separated by spaces (using `scope_str`). We put that string containing the scopes in the `WWW-Authenticate` header (this is part of the spec).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## Verify the `username` and data shape { #verify-the-username-and-data-shape }\n\nWe verify that we get a `username`, and extract the scopes.\n\nAnd then we validate that data with the Pydantic model (catching the `ValidationError` exception), and if we get an error reading the JWT token or validating the data with Pydantic, we raise the `HTTPException` we created before.\n\nFor that, we update the Pydantic model `TokenData` with a new property `scopes`.\n\nBy validating the data with Pydantic we can make sure that we have, for example, exactly a `list` of `str` with the scopes and a `str` with the `username`.\n\nInstead of, for example, a `dict`, or something else, as it could break the application at some point later, making it a security risk.\n\nWe also verify that we have a user with that username, and if not, we raise that same exception we created before.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## Verify the `scopes` { #verify-the-scopes }\n\nWe now verify that all the scopes required, by this dependency and all the dependants (including *path operations*), are included in the scopes provided in the token received, otherwise raise an `HTTPException`.\n\nFor this, we use `security_scopes.scopes`, that contains a `list` with all these scopes as `str`.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## Dependency tree and scopes { #dependency-tree-and-scopes }\n\nLet's review again this dependency tree and the scopes.\n\nAs the `get_current_active_user` dependency has as a sub-dependency on `get_current_user`, the scope `\"me\"` declared at `get_current_active_user` will be included in the list of required scopes in the `security_scopes.scopes` passed to `get_current_user`.\n\nThe *path operation* itself also declares a scope, `\"items\"`, so this will also be in the list of `security_scopes.scopes` passed to `get_current_user`.\n\nHere's how the hierarchy of dependencies and scopes looks like:\n\n* The *path operation* `read_own_items` has:\n    * Required scopes `[\"items\"]` with the dependency:\n    * `get_current_active_user`:\n        *  The dependency function `get_current_active_user` has:\n            * Required scopes `[\"me\"]` with the dependency:\n            * `get_current_user`:\n                * The dependency function `get_current_user` has:\n                    * No scopes required by itself.\n                    * A dependency using `oauth2_scheme`.\n                    * A `security_scopes` parameter of type `SecurityScopes`:\n                        * This `security_scopes` parameter has a property `scopes` with a `list` containing all these scopes declared above, so:\n                            * `security_scopes.scopes` will contain `[\"me\", \"items\"]` for the *path operation* `read_own_items`.\n                            * `security_scopes.scopes` will contain `[\"me\"]` for the *path operation* `read_users_me`, because it is declared in the dependency `get_current_active_user`.\n                            * `security_scopes.scopes` will contain `[]` (nothing) for the *path operation* `read_system_status`, because it didn't declare any `Security` with `scopes`, and its dependency, `get_current_user`, doesn't declare any `scopes` either.\n\n/// tip\n\nThe important and \"magic\" thing here is that `get_current_user` will have a different list of `scopes` to check for each *path operation*.\n\nAll depending on the `scopes` declared in each *path operation* and each dependency in the dependency tree for that specific *path operation*.\n\n///\n\n## More details about `SecurityScopes` { #more-details-about-securityscopes }\n\nYou can use `SecurityScopes` at any point, and in multiple places, it doesn't have to be at the \"root\" dependency.\n\nIt will always have the security scopes declared in the current `Security` dependencies and all the dependants for **that specific** *path operation* and **that specific** dependency tree.\n\nBecause the `SecurityScopes` will have all the scopes declared by dependants, you can use it to verify that a token has the required scopes in a central dependency function, and then declare different scope requirements in different *path operations*.\n\nThey will be checked independently for each *path operation*.\n\n## Check it { #check-it }\n\nIf you open the API docs, you can authenticate and specify which scopes you want to authorize.\n\n<img src=\"/img/tutorial/security/image11.png\">\n\nIf you don't select any scope, you will be \"authenticated\", but when you try to access `/users/me/` or `/users/me/items/` you will get an error saying that you don't have enough permissions. You will still be able to access `/status/`.\n\nAnd if you select the scope `me` but not the scope `items`, you will be able to access `/users/me/` but not `/users/me/items/`.\n\nThat's what would happen to a third party application that tried to access one of these *path operations* with a token provided by a user, depending on how many permissions the user gave the application.\n\n## About third party integrations { #about-third-party-integrations }\n\nIn this example we are using the OAuth2 \"password\" flow.\n\nThis is appropriate when we are logging in to our own application, probably with our own frontend.\n\nBecause we can trust it to receive the `username` and `password`, as we control it.\n\nBut if you are building an OAuth2 application that others would connect to (i.e., if you are building an authentication provider equivalent to Facebook, Google, GitHub, etc.) you should use one of the other flows.\n\nThe most common is the implicit flow.\n\nThe most secure is the code flow, but it's more complex to implement as it requires more steps. As it is more complex, many providers end up suggesting the implicit flow.\n\n/// note\n\nIt's common that each authentication provider names their flows in a different way, to make it part of their brand.\n\nBut in the end, they are implementing the same OAuth2 standard.\n\n///\n\n**FastAPI** includes utilities for all these OAuth2 authentication flows in `fastapi.security.oauth2`.\n\n## `Security` in decorator `dependencies` { #security-in-decorator-dependencies }\n\nThe same way you can define a `list` of `Depends` in the decorator's `dependencies` parameter (as explained in [Dependencies in path operation decorators](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)), you could also use `Security` with `scopes` there.\n"
  },
  {
    "path": "docs/en/docs/advanced/settings.md",
    "content": "# Settings and Environment Variables { #settings-and-environment-variables }\n\nIn many cases your application could need some external settings or configurations, for example secret keys, database credentials, credentials for email services, etc.\n\nMost of these settings are variable (can change), like database URLs. And many could be sensitive, like secrets.\n\nFor this reason it's common to provide them in environment variables that are read by the application.\n\n/// tip\n\nTo understand environment variables you can read [Environment Variables](../environment-variables.md).\n\n///\n\n## Types and validation { #types-and-validation }\n\nThese environment variables can only handle text strings, as they are external to Python and have to be compatible with other programs and the rest of the system (and even with different operating systems, as Linux, Windows, macOS).\n\nThat means that any value read in Python from an environment variable will be a `str`, and any conversion to a different type or any validation has to be done in code.\n\n## Pydantic `Settings` { #pydantic-settings }\n\nFortunately, Pydantic provides a great utility to handle these settings coming from environment variables with [Pydantic: Settings management](https://docs.pydantic.dev/latest/concepts/pydantic_settings/).\n\n### Install `pydantic-settings` { #install-pydantic-settings }\n\nFirst, make sure you create your [virtual environment](../virtual-environments.md), activate it, and then install the `pydantic-settings` package:\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\nIt also comes included when you install the `all` extras with:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### Create the `Settings` object { #create-the-settings-object }\n\nImport `BaseSettings` from Pydantic and create a sub-class, very much like with a Pydantic model.\n\nThe same way as with Pydantic models, you declare class attributes with type annotations, and possibly default values.\n\nYou can use all the same validation features and tools you use for Pydantic models, like different data types and additional validations with `Field()`.\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip\n\nIf you want something quick to copy and paste, don't use this example, use the last one below.\n\n///\n\nThen, when you create an instance of that `Settings` class (in this case, in the `settings` object), Pydantic will read the environment variables in a case-insensitive way, so, an upper-case variable `APP_NAME` will still be read for the attribute `app_name`.\n\nNext it will convert and validate the data. So, when you use that `settings` object, you will have data of the types you declared (e.g. `items_per_user` will be an `int`).\n\n### Use the `settings` { #use-the-settings }\n\nThen you can use the new `settings` object in your application:\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### Run the server { #run-the-server }\n\nNext, you would run the server passing the configurations as environment variables, for example you could set an `ADMIN_EMAIL` and `APP_NAME` with:\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip\n\nTo set multiple env vars for a single command just separate them with a space, and put them all before the command.\n\n///\n\nAnd then the `admin_email` setting would be set to `\"deadpool@example.com\"`.\n\nThe `app_name` would be `\"ChimichangApp\"`.\n\nAnd the `items_per_user` would keep its default value of `50`.\n\n## Settings in another module { #settings-in-another-module }\n\nYou could put those settings in another module file as you saw in [Bigger Applications - Multiple Files](../tutorial/bigger-applications.md).\n\nFor example, you could have a file `config.py` with:\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\nAnd then use it in a file `main.py`:\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip\n\nYou would also need a file `__init__.py` as you saw in [Bigger Applications - Multiple Files](../tutorial/bigger-applications.md).\n\n///\n\n## Settings in a dependency { #settings-in-a-dependency }\n\nIn some occasions it might be useful to provide the settings from a dependency, instead of having a global object with `settings` that is used everywhere.\n\nThis could be especially useful during testing, as it's very easy to override a dependency with your own custom settings.\n\n### The config file { #the-config-file }\n\nComing from the previous example, your `config.py` file could look like:\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\nNotice that now we don't create a default instance `settings = Settings()`.\n\n### The main app file { #the-main-app-file }\n\nNow we create a dependency that returns a new `config.Settings()`.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip\n\nWe'll discuss the `@lru_cache` in a bit.\n\nFor now you can assume `get_settings()` is a normal function.\n\n///\n\nAnd then we can require it from the *path operation function* as a dependency and use it anywhere we need it.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### Settings and testing { #settings-and-testing }\n\nThen it would be very easy to provide a different settings object during testing by creating a dependency override for `get_settings`:\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\nIn the dependency override we set a new value for the `admin_email` when creating the new `Settings` object, and then we return that new object.\n\nThen we can test that it is used.\n\n## Reading a `.env` file { #reading-a-env-file }\n\nIf you have many settings that possibly change a lot, maybe in different environments, it might be useful to put them on a file and then read them from it as if they were environment variables.\n\nThis practice is common enough that it has a name, these environment variables are commonly placed in a file `.env`, and the file is called a \"dotenv\".\n\n/// tip\n\nA file starting with a dot (`.`) is a hidden file in Unix-like systems, like Linux and macOS.\n\nBut a dotenv file doesn't really have to have that exact filename.\n\n///\n\nPydantic has support for reading from these types of files using an external library. You can read more at [Pydantic Settings: Dotenv (.env) support](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support).\n\n/// tip\n\nFor this to work, you need to `pip install python-dotenv`.\n\n///\n\n### The `.env` file { #the-env-file }\n\nYou could have a `.env` file with:\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### Read settings from `.env` { #read-settings-from-env }\n\nAnd then update your `config.py` with:\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip\n\nThe `model_config` attribute is used just for Pydantic configuration. You can read more at [Pydantic: Concepts: Configuration](https://docs.pydantic.dev/latest/concepts/config/).\n\n///\n\nHere we define the config `env_file` inside of your Pydantic `Settings` class, and set the value to the filename with the dotenv file we want to use.\n\n### Creating the `Settings` only once with `lru_cache` { #creating-the-settings-only-once-with-lru-cache }\n\nReading a file from disk is normally a costly (slow) operation, so you probably want to do it only once and then reuse the same settings object, instead of reading it for each request.\n\nBut every time we do:\n\n```Python\nSettings()\n```\n\na new `Settings` object would be created, and at creation it would read the `.env` file again.\n\nIf the dependency function was just like:\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\nwe would create that object for each request, and we would be reading the `.env` file for each request. ⚠️\n\nBut as we are using the `@lru_cache` decorator on top, the `Settings` object will be created only once, the first time it's called. ✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\nThen for any subsequent call of `get_settings()` in the dependencies for the next requests, instead of executing the internal code of `get_settings()` and creating a new `Settings` object, it will return the same object that was returned on the first call, again and again.\n\n#### `lru_cache` Technical Details { #lru-cache-technical-details }\n\n`@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.\n\nSo, 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.\n\nFor example, if you have a function:\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\nyour program could execute like this:\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Execute function\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n```\n\nIn the case of our dependency `get_settings()`, the function doesn't even take any arguments, so it always returns the same value.\n\nThat 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.\n\n`@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`](https://docs.python.org/3/library/functools.html#functools.lru_cache).\n\n## Recap { #recap }\n\nYou can use Pydantic Settings to handle the settings or configurations for your application, with all the power of Pydantic models.\n\n* By using a dependency you can simplify testing.\n* You can use `.env` files with it.\n* Using `@lru_cache` lets you avoid reading the dotenv file again and again for each request, while allowing you to override it during testing.\n"
  },
  {
    "path": "docs/en/docs/advanced/stream-data.md",
    "content": "# Stream Data { #stream-data }\n\nIf you want to stream data that can be structured as JSON, you should [Stream JSON Lines](../tutorial/stream-json-lines.md).\n\nBut if you want to **stream pure binary data** or strings, here's how you can do it.\n\n/// info\n\nAdded in FastAPI 0.134.0.\n\n///\n\n## Use Cases { #use-cases }\n\nYou could use this if you want to stream pure strings, for example directly from the output of an **AI LLM** service.\n\nYou could also use it to stream **large binary files**, where you stream each chunk of data as you read it, without having to read it all in memory at once.\n\nYou could also stream **video** or **audio** this way, it could even be generated as you process and send it.\n\n## A `StreamingResponse` with `yield` { #a-streamingresponse-with-yield }\n\nIf you declare a `response_class=StreamingResponse` in your *path operation function*, you can use `yield` to send each chunk of data in turn.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI will give each chunk of data to the `StreamingResponse` as is, it won't try to convert it to JSON or anything similar.\n\n### Non-async *path operation functions* { #non-async-path-operation-functions }\n\nYou can also use regular `def` functions (without `async`), and use `yield` the same way.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### No Annotation { #no-annotation }\n\nYou don't really need to declare the return type annotation for streaming binary data.\n\nAs FastAPI will not try to convert the data to JSON with Pydantic or serialize it in any way, in this case, the type annotation is only for your editor and tools to use, it won't be used by FastAPI.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\nThis also means that with `StreamingResponse` you have the **freedom** and **responsibility** to produce and encode the data bytes exactly as you need them to be sent, independent of the type annotations. 🤓\n\n### Stream Bytes { #stream-bytes }\n\nOne of the main use cases would be to stream `bytes` instead of strings, you can of course do it.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## A Custom `PNGStreamingResponse` { #a-custom-pngstreamingresponse }\n\nIn the examples above, the data bytes were streamed, but the response didn't have a `Content-Type` header, so the client didn't know what type of data it was receiving.\n\nYou can create a custom sub-class of `StreamingResponse` that sets the `Content-Type` header to the type of data you're streaming.\n\nFor example, you can create a `PNGStreamingResponse` that sets the `Content-Type` header to `image/png` using the `media_type` attribute:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\nThen you can use this new class in `response_class=PNGStreamingResponse` in your *path operation function*:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### Simulate a File { #simulate-a-file }\n\nIn this example, we are simulating a file with `io.BytesIO`, which is a file-like object that lives only in memory, but lets us use the same interface.\n\nFor example, we can iterate over it to consume its contents, as we could with a file.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | Technical Details\n\nThe other two variables, `image_base64` and `binary_image`, are an image encoded in Base64, and then converted to bytes, to then pass it to `io.BytesIO`.\n\nOnly so that it can live in the same file for this example and you can copy it and run it as is. 🥚\n\n///\n\nBy using a `with` block, we make sure that the file-like object is closed after the generator function (the function with `yield`) is done. So, after it finishes sending the response.\n\nIt wouldn't be that important in this specific example because it's a fake in-memory file (with `io.BytesIO`), but with a real file, it would be important to make sure the file is closed after the work with it is done.\n\n### Files and Async { #files-and-async }\n\nIn most cases, file-like objects are not compatible with async and await by default.\n\nFor example, they don't have an `await file.read()`, or `async for chunk in file`.\n\nAnd in many cases, reading them would be a blocking operation (that could block the event loop), because they are read from disk or from the network.\n\n/// info\n\nThe example above is actually an exception, because the `io.BytesIO` object is already in memory, so reading it won't block anything.\n\nBut in many cases reading a file or a file-like object would block.\n\n///\n\nTo avoid blocking the event loop, you can simply declare the *path operation function* with regular `def` instead of `async def`, that way FastAPI will run it on a threadpool worker, to avoid blocking the main loop.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip\n\nIf you need to call blocking code from inside of an async function, or an async function from inside of a blocking function, you could use [Asyncer](https://asyncer.tiangolo.com), a sibling library to FastAPI.\n\n///\n\n### `yield from` { #yield-from }\n\nWhen you are iterating over something, like a file-like object, and then you are doing `yield` for each item, you could also use `yield from` to yield each item directly and skip the `for` loop.\n\nThis is not particular to FastAPI, it's just Python, but it's a nice trick to know. 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/en/docs/advanced/strict-content-type.md",
    "content": "# Strict Content-Type Checking { #strict-content-type-checking }\n\nBy default, **FastAPI** uses strict `Content-Type` header checking for JSON request bodies, this means that JSON requests **must** include a valid `Content-Type` header (e.g. `application/json`) in order for the body to be parsed as JSON.\n\n## CSRF Risk { #csrf-risk }\n\nThis default behavior provides protection against a class of **Cross-Site Request Forgery (CSRF)** attacks in a very specific scenario.\n\nThese attacks exploit the fact that browsers allow scripts to send requests without doing any CORS preflight check when they:\n\n* don't have a `Content-Type` header (e.g. using `fetch()` with a `Blob` body)\n* and don't send any authentication credentials.\n\nThis type of attack is mainly relevant when:\n\n* the application is running locally (e.g. on `localhost`) or in an internal network\n* and the application doesn't have any authentication, it expects that any request from the same network can be trusted.\n\n## Example Attack { #example-attack }\n\nImagine you build a way to run a local AI agent.\n\nIt provides an API at\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nThere's also a frontend at\n\n```\nhttp://localhost:8000\n```\n\n/// tip\n\nNote that both have the same host.\n\n///\n\nThen using the frontend you can make the AI agent do things on your behalf.\n\nAs it's running **locally**, and not in the open internet, you decide to **not have any authentication** set up, just trusting the access to the local network.\n\nThen one of your users could install it and run it locally.\n\nThen they could open a malicious website, e.g. something like\n\n```\nhttps://evilhackers.example.com\n```\n\nAnd that malicious website sends requests using `fetch()` with a `Blob` body to the local API at\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nEven though the host of the malicious website and the local app is different, the browser won't trigger a CORS preflight request because:\n\n* It's running without any authentication, it doesn't have to send any credentials.\n* The browser thinks it's not sending JSON (because of the missing `Content-Type` header).\n\nThen the malicious website could make the local AI agent send angry messages to the user's ex-boss... or worse. 😅\n\n## Open Internet { #open-internet }\n\nIf your app is in the open internet, you wouldn't \"trust the network\" and let anyone send privileged requests without authentication.\n\nAttackers could simply run a script to send requests to your API, no need for browser interaction, so you are probably already securing any privileged endpoints.\n\nIn that case **this attack / risk doesn't apply to you**.\n\nThis risk and attack is mainly relevant when the app runs on the **local network** and that is the **only assumed protection**.\n\n## Allowing Requests Without Content-Type { #allowing-requests-without-content-type }\n\nIf you need to support clients that don't send a `Content-Type` header, you can disable strict checking by setting `strict_content_type=False`:\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\nWith this setting, requests without a `Content-Type` header will have their body parsed as JSON, which is the same behavior as older versions of FastAPI.\n\n/// info\n\nThis behavior and configuration was added in FastAPI 0.132.0.\n\n///\n"
  },
  {
    "path": "docs/en/docs/advanced/sub-applications.md",
    "content": "# Sub Applications - Mounts { #sub-applications-mounts }\n\nIf you need to have two independent FastAPI applications, with their own independent OpenAPI and their own docs UIs, you can have a main app and \"mount\" one (or more) sub-application(s).\n\n## Mounting a **FastAPI** application { #mounting-a-fastapi-application }\n\n\"Mounting\" means adding a completely \"independent\" application in a specific path, that then takes care of handling everything under that path, with the _path operations_ declared in that sub-application.\n\n### Top-level application { #top-level-application }\n\nFirst, create the main, top-level, **FastAPI** application, and its *path operations*:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### Sub-application { #sub-application }\n\nThen, create your sub-application, and its *path operations*.\n\nThis sub-application is just another standard FastAPI application, but this is the one that will be \"mounted\":\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### Mount the sub-application { #mount-the-sub-application }\n\nIn your top-level application, `app`, mount the sub-application, `subapi`.\n\nIn this case, it will be mounted at the path `/subapi`:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### Check the automatic API docs { #check-the-automatic-api-docs }\n\nNow, run the `fastapi` command:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nAnd open the docs at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nYou will see the automatic API docs for the main app, including only its own _path operations_:\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\nAnd then, open the docs for the sub-application, at [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs).\n\nYou will see the automatic API docs for the sub-application, including only its own _path operations_, all under the correct sub-path prefix `/subapi`:\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\nIf you try interacting with any of the two user interfaces, they will work correctly, because the browser will be able to talk to each specific app or sub-app.\n\n### Technical Details: `root_path` { #technical-details-root-path }\n\nWhen you mount a sub-application as described above, FastAPI will take care of communicating the mount path for the sub-application using a mechanism from the ASGI specification called a `root_path`.\n\nThat way, the sub-application will know to use that path prefix for the docs UI.\n\nAnd the sub-application could also have its own mounted sub-applications and everything would work correctly, because FastAPI handles all these `root_path`s automatically.\n\nYou will learn more about the `root_path` and how to use it explicitly in the section about [Behind a Proxy](behind-a-proxy.md).\n"
  },
  {
    "path": "docs/en/docs/advanced/templates.md",
    "content": "# Templates { #templates }\n\nYou can use any template engine you want with **FastAPI**.\n\nA common choice is Jinja2, the same one used by Flask and other tools.\n\nThere are utilities to configure it easily that you can use directly in your **FastAPI** application (provided by Starlette).\n\n## Install dependencies { #install-dependencies }\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and install `jinja2`:\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## Using `Jinja2Templates` { #using-jinja2templates }\n\n* Import `Jinja2Templates`.\n* Create a `templates` object that you can reuse later.\n* Declare a `Request` parameter in the *path operation* that will return a template.\n* Use the `templates` you created to render and return a `TemplateResponse`, pass the name of the template, the request object, and a \"context\" dictionary with key-value pairs to be used inside of the Jinja2 template.\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note\n\nBefore FastAPI 0.108.0, Starlette 0.29.0, the `name` was the first parameter.\n\nAlso, before that, in previous versions, the `request` object was passed as part of the key-value pairs in the context for Jinja2.\n\n///\n\n/// tip\n\nBy declaring `response_class=HTMLResponse` the docs UI will be able to know that the response will be HTML.\n\n///\n\n/// note | Technical Details\n\nYou could also use `from starlette.templating import Jinja2Templates`.\n\n**FastAPI** provides the same `starlette.templating` as `fastapi.templating` just as a convenience for you, the developer. But most of the available responses come directly from Starlette. The same with `Request` and `StaticFiles`.\n\n///\n\n## Writing templates { #writing-templates }\n\nThen you can write a template at `templates/item.html` with, for example:\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### Template Context Values { #template-context-values }\n\nIn the HTML that contains:\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n...it will show the `id` taken from the \"context\" `dict` you passed:\n\n```Python\n{\"id\": id}\n```\n\nFor example, with an ID of `42`, this would render:\n\n```html\nItem ID: 42\n```\n\n### Template `url_for` Arguments { #template-url-for-arguments }\n\nYou can also use `url_for()` inside of the template, it takes as arguments the same arguments that would be used by your *path operation function*.\n\nSo, the section with:\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n...will generate a link to the same URL that would be handled by the *path operation function* `read_item(id=id)`.\n\nFor example, with an ID of `42`, this would render:\n\n```html\n<a href=\"/items/42\">\n```\n\n## Templates and static files { #templates-and-static-files }\n\nYou can also use `url_for()` inside of the template, and use it, for example, with the `StaticFiles` you mounted with the `name=\"static\"`.\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\nIn this example, it would link to a CSS file at `static/styles.css` with:\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\nAnd because you are using `StaticFiles`, that CSS file would be served automatically by your **FastAPI** application at the URL `/static/styles.css`.\n\n## More details { #more-details }\n\nFor more details, including how to test templates, check [Starlette's docs on templates](https://www.starlette.dev/templates/).\n"
  },
  {
    "path": "docs/en/docs/advanced/testing-dependencies.md",
    "content": "# Testing Dependencies with Overrides { #testing-dependencies-with-overrides }\n\n## Overriding dependencies during testing { #overriding-dependencies-during-testing }\n\nThere are some scenarios where you might want to override a dependency during testing.\n\nYou don't want the original dependency to run (nor any of the sub-dependencies it might have).\n\nInstead, you want to provide a different dependency that will be used only during tests (possibly only some specific tests), and will provide a value that can be used where the value of the original dependency was used.\n\n### Use cases: external service { #use-cases-external-service }\n\nAn example could be that you have an external authentication provider that you need to call.\n\nYou send it a token and it returns an authenticated user.\n\nThis provider might be charging you per request, and calling it might take some extra time than if you had a fixed mock user for tests.\n\nYou probably want to test the external provider once, but not necessarily call it for every test that runs.\n\nIn this case, you can override the dependency that calls that provider, and use a custom dependency that returns a mock user, only for your tests.\n\n### Use the `app.dependency_overrides` attribute { #use-the-app-dependency-overrides-attribute }\n\nFor these cases, your **FastAPI** application has an attribute `app.dependency_overrides`, it is a simple `dict`.\n\nTo override a dependency for testing, you put as a key the original dependency (a function), and as the value, your dependency override (another function).\n\nAnd then **FastAPI** will call that override instead of the original dependency.\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip\n\nYou can set a dependency override for a dependency used anywhere in your **FastAPI** application.\n\nThe original dependency could be used in a *path operation function*, a *path operation decorator* (when you don't use the return value), a `.include_router()` call, etc.\n\nFastAPI will still be able to override it.\n\n///\n\nThen you can reset your overrides (remove them) by setting `app.dependency_overrides` to be an empty `dict`:\n\n```Python\napp.dependency_overrides = {}\n```\n\n/// tip\n\nIf you want to override a dependency only during some tests, you can set the override at the beginning of the test (inside the test function) and reset it at the end (at the end of the test function).\n\n///\n"
  },
  {
    "path": "docs/en/docs/advanced/testing-events.md",
    "content": "# Testing Events: lifespan and startup - shutdown { #testing-events-lifespan-and-startup-shutdown }\n\nWhen you need `lifespan` to run in your tests, you can use the `TestClient` with a `with` statement:\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\n\nYou can read more details about the [\"Running lifespan in tests in the official Starlette documentation site.\"](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)\n\nFor the deprecated `startup` and `shutdown` events, you can use the `TestClient` as follows:\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/en/docs/advanced/testing-websockets.md",
    "content": "# Testing WebSockets { #testing-websockets }\n\nYou can use the same `TestClient` to test WebSockets.\n\nFor this, you use the `TestClient` in a `with` statement, connecting to the WebSocket:\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note\n\nFor more details, check Starlette's documentation for [testing WebSockets](https://www.starlette.dev/testclient/#testing-websocket-sessions).\n\n///\n"
  },
  {
    "path": "docs/en/docs/advanced/using-request-directly.md",
    "content": "# Using the Request Directly { #using-the-request-directly }\n\nUp to now, you have been declaring the parts of the request that you need with their types.\n\nTaking data from:\n\n* The path as parameters.\n* Headers.\n* Cookies.\n* etc.\n\nAnd by doing so, **FastAPI** is validating that data, converting it and generating documentation for your API automatically.\n\nBut there are situations where you might need to access the `Request` object directly.\n\n## Details about the `Request` object { #details-about-the-request-object }\n\nAs **FastAPI** is actually **Starlette** underneath, with a layer of several tools on top, you can use Starlette's [`Request`](https://www.starlette.dev/requests/) object directly when you need to.\n\nIt would also mean that if you get data from the `Request` object directly (for example, read the body) it won't be validated, converted or documented (with OpenAPI, for the automatic API user interface) by FastAPI.\n\nAlthough any other parameter declared normally (for example, the body with a Pydantic model) would still be validated, converted, annotated, etc.\n\nBut there are specific cases where it's useful to get the `Request` object.\n\n## Use the `Request` object directly { #use-the-request-object-directly }\n\nLet's imagine you want to get the client's IP address/host inside of your *path operation function*.\n\nFor that you need to access the request directly.\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\nBy declaring a *path operation function* parameter with the type being the `Request` **FastAPI** will know to pass the `Request` in that parameter.\n\n/// tip\n\nNote that in this case, we are declaring a path parameter beside the request parameter.\n\nSo, the path parameter will be extracted, validated, converted to the specified type and annotated with OpenAPI.\n\nThe same way, you can declare any other parameter as normally, and additionally, get the `Request` too.\n\n///\n\n## `Request` documentation { #request-documentation }\n\nYou can read more details about the [`Request` object in the official Starlette documentation site](https://www.starlette.dev/requests/).\n\n/// note | Technical Details\n\nYou could also use `from starlette.requests import Request`.\n\n**FastAPI** provides it directly just as a convenience for you, the developer. But it comes directly from Starlette.\n\n///\n"
  },
  {
    "path": "docs/en/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\nYou can use [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) with **FastAPI**.\n\n## Install `websockets` { #install-websockets }\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and install `websockets` (a Python library that makes it easy to use the \"WebSocket\" protocol):\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## WebSockets client { #websockets-client }\n\n### In production { #in-production }\n\nIn your production system, you probably have a frontend created with a modern framework like React, Vue.js or Angular.\n\nAnd to communicate using WebSockets with your backend you would probably use your frontend's utilities.\n\nOr you might have a native mobile application that communicates with your WebSocket backend directly, in native code.\n\nOr you might have any other way to communicate with the WebSocket endpoint.\n\n---\n\nBut for this example, we'll use a very simple HTML document with some JavaScript, all inside a long string.\n\nThis, of course, is not optimal and you wouldn't use it for production.\n\nIn production you would have one of the options above.\n\nBut it's the simplest way to focus on the server-side of WebSockets and have a working example:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## Create a `websocket` { #create-a-websocket }\n\nIn your **FastAPI** application, create a `websocket`:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | Technical Details\n\nYou could also use `from starlette.websockets import WebSocket`.\n\n**FastAPI** provides the same `WebSocket` directly just as a convenience for you, the developer. But it comes directly from Starlette.\n\n///\n\n## Await for messages and send messages { #await-for-messages-and-send-messages }\n\nIn your WebSocket route you can `await` for messages and send messages.\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\nYou can receive and send binary, text, and JSON data.\n\n## Try it { #try-it }\n\nPut your code in a file `main.py` and then run your application:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nOpen your browser at [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nYou will see a simple page like:\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\nYou can type messages in the input box, and send them:\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\nAnd your **FastAPI** application with WebSockets will respond back:\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\nYou can send (and receive) many messages:\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\nAnd all of them will use the same WebSocket connection.\n\n## Using `Depends` and others { #using-depends-and-others }\n\nIn WebSocket endpoints you can import from `fastapi` and use:\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\nThey work the same way as for other FastAPI endpoints/*path operations*:\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info\n\nAs this is a WebSocket it doesn't really make sense to raise an `HTTPException`, instead we raise a `WebSocketException`.\n\nYou can use a closing code from the [valid codes defined in the specification](https://tools.ietf.org/html/rfc6455#section-7.4.1).\n\n///\n\n### Try the WebSockets with dependencies { #try-the-websockets-with-dependencies }\n\nRun your application:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nOpen your browser at [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nThere you can set:\n\n* The \"Item ID\", used in the path.\n* The \"Token\" used as a query parameter.\n\n/// tip\n\nNotice that the query `token` will be handled by a dependency.\n\n///\n\nWith that you can connect the WebSocket and then send and receive messages:\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## Handling disconnections and multiple clients { #handling-disconnections-and-multiple-clients }\n\nWhen a WebSocket connection is closed, the `await websocket.receive_text()` will raise a `WebSocketDisconnect` exception, which you can then catch and handle like in this example.\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\nTo try it out:\n\n* Open the app with several browser tabs.\n* Write messages from them.\n* Then close one of the tabs.\n\nThat will raise the `WebSocketDisconnect` exception, and all the other clients will receive a message like:\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip\n\nThe app above is a minimal and simple example to demonstrate how to handle and broadcast messages to several WebSocket connections.\n\nBut keep in mind that, as everything is handled in memory, in a single list, it will only work while the process is running, and will only work with a single process.\n\nIf you need something easy to integrate with FastAPI but that is more robust, supported by Redis, PostgreSQL or others, check [encode/broadcaster](https://github.com/encode/broadcaster).\n\n///\n\n## More info { #more-info }\n\nTo learn more about the options, check Starlette's documentation for:\n\n* [The `WebSocket` class](https://www.starlette.dev/websockets/).\n* [Class-based WebSocket handling](https://www.starlette.dev/endpoints/#websocketendpoint).\n"
  },
  {
    "path": "docs/en/docs/advanced/wsgi.md",
    "content": "# Including WSGI - Flask, Django, others { #including-wsgi-flask-django-others }\n\nYou can mount WSGI applications as you saw with [Sub Applications - Mounts](sub-applications.md), [Behind a Proxy](behind-a-proxy.md).\n\nFor that, you can use the `WSGIMiddleware` and use it to wrap your WSGI application, for example, Flask, Django, etc.\n\n## Using `WSGIMiddleware` { #using-wsgimiddleware }\n\n/// info\n\nThis requires installing `a2wsgi` for example with `pip install a2wsgi`.\n\n///\n\nYou need to import `WSGIMiddleware` from `a2wsgi`.\n\nThen wrap the WSGI (e.g. Flask) app with the middleware.\n\nAnd then mount that under a path.\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note\n\nPreviously, it was recommended to use `WSGIMiddleware` from `fastapi.middleware.wsgi`, but it is now deprecated.\n\nIt’s advised to use the `a2wsgi` package instead. The usage remains the same.\n\nJust ensure that you have the `a2wsgi` package installed and import `WSGIMiddleware` correctly from `a2wsgi`.\n\n///\n\n## Check it { #check-it }\n\nNow, every request under the path `/v1/` will be handled by the Flask application.\n\nAnd the rest will be handled by **FastAPI**.\n\nIf you run it and go to [http://localhost:8000/v1/](http://localhost:8000/v1/) you will see the response from Flask:\n\n```txt\nHello, World from Flask!\n```\n\nAnd if you go to [http://localhost:8000/v2](http://localhost:8000/v2) you will see the response from FastAPI:\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/en/docs/alternatives.md",
    "content": "# Alternatives, Inspiration and Comparisons { #alternatives-inspiration-and-comparisons }\n\nWhat inspired **FastAPI**, how it compares to alternatives and what it learned from them.\n\n## Intro { #intro }\n\n**FastAPI** wouldn't exist if not for the previous work of others.\n\nThere have been many tools created before that have helped inspire its creation.\n\nI have been avoiding the creation of a new framework for several years. First I tried to solve all the features covered by **FastAPI** using many different frameworks, plug-ins, and tools.\n\nBut at some point, there was no other option than creating something that provided all these features, taking the best ideas from previous tools, and combining them in the best way possible, using language features that weren't even available before (Python 3.6+ type hints).\n\n## Previous tools { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\nIt's the most popular Python framework and is widely trusted. It is used to build systems like Instagram.\n\nIt's relatively tightly coupled with relational databases (like MySQL or PostgreSQL), so, having a NoSQL database (like Couchbase, MongoDB, Cassandra, etc) as the main store engine is not very easy.\n\nIt was created to generate the HTML in the backend, not to create APIs used by a modern frontend (like React, Vue.js and Angular) or by other systems (like <abbr title=\"Internet of Things\">IoT</abbr> devices) communicating with it.\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nDjango REST framework was created to be a flexible toolkit for building Web APIs using Django underneath, to improve its API capabilities.\n\nIt is used by many companies including Mozilla, Red Hat and Eventbrite.\n\nIt was one of the first examples of **automatic API documentation**, and this was specifically one of the first ideas that inspired \"the search for\" **FastAPI**.\n\n/// note\n\nDjango REST Framework was created by Tom Christie. The same creator of Starlette and Uvicorn, on which **FastAPI** is based.\n\n///\n\n/// check | Inspired **FastAPI** to\n\nHave an automatic API documentation web user interface.\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask is a \"microframework\", it doesn't include database integrations nor many of the things that come by default in Django.\n\nThis simplicity and flexibility allow doing things like using NoSQL databases as the main data storage system.\n\nAs it is very simple, it's relatively intuitive to learn, although the documentation gets somewhat technical at some points.\n\nIt is also commonly used for other applications that don't necessarily need a database, user management, or any of the many features that come pre-built in Django. Although many of these features can be added with plug-ins.\n\nThis decoupling of parts, and being a \"microframework\" that could be extended to cover exactly what is needed was a key feature that I wanted to keep.\n\nGiven the simplicity of Flask, it seemed like a good match for building APIs. The next thing to find was a \"Django REST Framework\" for Flask.\n\n/// check | Inspired **FastAPI** to\n\nBe a micro-framework. Making it easy to mix and match the tools and parts needed.\n\nHave a simple and easy to use routing system.\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI** is not actually an alternative to **Requests**. Their scope is very different.\n\nIt would actually be common to use Requests *inside* of a FastAPI application.\n\nBut still, FastAPI got quite some inspiration from Requests.\n\n**Requests** is a library to *interact* with APIs (as a client), while **FastAPI** is a library to *build* APIs (as a server).\n\nThey are, more or less, at opposite ends, complementing each other.\n\nRequests has a very simple and intuitive design, it's very easy to use, with sensible defaults. But at the same time, it's very powerful and customizable.\n\nThat's why, as said in the official website:\n\n> Requests is one of the most downloaded Python packages of all time\n\nThe way you use it is very simple. For example, to do a `GET` request, you would write:\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\nThe FastAPI counterpart API *path operation* could look like:\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\nSee the similarities in `requests.get(...)` and `@app.get(...)`.\n\n/// check | Inspired **FastAPI** to\n\n* Have a simple and intuitive API.\n* Use HTTP method names (operations) directly, in a straightforward and intuitive way.\n* Have sensible defaults, but powerful customizations.\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\nThe main feature I wanted from Django REST Framework was the automatic API documentation.\n\nThen I found that there was a standard to document APIs, using JSON (or YAML, an extension of JSON) called Swagger.\n\nAnd there was a web user interface for Swagger APIs already created. So, being able to generate Swagger documentation for an API would allow using this web user interface automatically.\n\nAt some point, Swagger was given to the Linux Foundation, to be renamed OpenAPI.\n\nThat's why when talking about version 2.0 it's common to say \"Swagger\", and for version 3+ \"OpenAPI\".\n\n/// check | Inspired **FastAPI** to\n\nAdopt and use an open standard for API specifications, instead of a custom schema.\n\nAnd integrate standards-based user interface tools:\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\nThese two were chosen for being fairly popular and stable, but doing a quick search, you could find dozens of alternative user interfaces for OpenAPI (that you can use with **FastAPI**).\n\n///\n\n### Flask REST frameworks { #flask-rest-frameworks }\n\nThere 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.\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nOne of the main features needed by API systems is data \"<dfn title=\"also called marshalling, conversion\">serialization</dfn>\" which is taking data from the code (Python) and converting it into something that can be sent through the network. For example, converting an object containing data from a database into a JSON object. Converting `datetime` objects into strings, etc.\n\nAnother big feature needed by APIs is data validation, making sure that the data is valid, given certain parameters. For example, that some field is an `int`, and not some random string. This is especially useful for incoming data.\n\nWithout a data validation system, you would have to do all the checks by hand, in code.\n\nThese features are what Marshmallow was built to provide. It is a great library, and I have used it a lot before.\n\nBut it was created before there existed Python type hints. So, to define every <dfn title=\"the definition of how data should be formed\">schema</dfn> you need to use specific utils and classes provided by Marshmallow.\n\n/// check | Inspired **FastAPI** to\n\nUse code to define \"schemas\" that provide data types and validation, automatically.\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nAnother big feature required by APIs is <dfn title=\"reading and converting to Python data\">parsing</dfn> data from incoming requests.\n\nWebargs is a tool that was made to provide that on top of several frameworks, including Flask.\n\nIt uses Marshmallow underneath to do the data validation. And it was created by the same developers.\n\nIt's a great tool and I have used it a lot too, before having **FastAPI**.\n\n/// info\n\nWebargs was created by the same Marshmallow developers.\n\n///\n\n/// check | Inspired **FastAPI** to\n\nHave automatic validation of incoming request data.\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow and Webargs provide validation, parsing and serialization as plug-ins.\n\nBut documentation is still missing. Then APISpec was created.\n\nIt is a plug-in for many frameworks (and there's a plug-in for Starlette too).\n\nThe way it works is that you write the definition of the schema using YAML format inside the docstring of each function handling a route.\n\nAnd it generates OpenAPI schemas.\n\nThat's how it works in Flask, Starlette, Responder, etc.\n\nBut then, we have again the problem of having a micro-syntax, inside of a Python string (a big YAML).\n\nThe editor can't help much with that. And if we modify parameters or Marshmallow schemas and forget to also modify that YAML docstring, the generated schema would be obsolete.\n\n/// info\n\nAPISpec was created by the same Marshmallow developers.\n\n///\n\n/// check | Inspired **FastAPI** to\n\nSupport the open standard for APIs, OpenAPI.\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\nIt's a Flask plug-in, that ties together Webargs, Marshmallow and APISpec.\n\nIt uses the information from Webargs and Marshmallow to automatically generate OpenAPI schemas, using APISpec.\n\nIt's a great tool, very underrated. It should be way more popular than many Flask plug-ins out there. It might be due to its documentation being too concise and abstract.\n\nThis solved having to write YAML (another syntax) inside of Python docstrings.\n\nThis combination of Flask, Flask-apispec with Marshmallow and Webargs was my favorite backend stack until building **FastAPI**.\n\nUsing it led to the creation of several Flask full-stack generators. These are the main stacks I (and several external teams) have been using up to now:\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\nAnd these same full-stack generators were the base of the [**FastAPI** Project Generators](project-generation.md).\n\n/// info\n\nFlask-apispec was created by the same Marshmallow developers.\n\n///\n\n/// check | Inspired **FastAPI** to\n\nGenerate the OpenAPI schema automatically, from the same code that defines serialization and validation.\n\n///\n\n### [NestJS](https://nestjs.com/) (and [Angular](https://angular.io/)) { #nestjs-and-angular }\n\nThis isn't even Python, NestJS is a JavaScript (TypeScript) NodeJS framework inspired by Angular.\n\nIt achieves something somewhat similar to what can be done with Flask-apispec.\n\nIt has an integrated dependency injection system, inspired by Angular 2. It requires pre-registering the \"injectables\" (like all the other dependency injection systems I know), so, it adds to the verbosity and code repetition.\n\nAs the parameters are described with TypeScript types (similar to Python type hints), editor support is quite good.\n\nBut as TypeScript data is not preserved after compilation to JavaScript, it cannot rely on the types to define validation, serialization and documentation at the same time. Due to this and some design decisions, to get validation, serialization and automatic schema generation, it's needed to add decorators in many places. So, it becomes quite verbose.\n\nIt can't handle nested models very well. So, if the JSON body in the request is a JSON object that has inner fields that in turn are nested JSON objects, it cannot be properly documented and validated.\n\n/// check | Inspired **FastAPI** to\n\nUse Python types to have great editor support.\n\nHave a powerful dependency injection system. Find a way to minimize code repetition.\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\nIt was one of the first extremely fast Python frameworks based on `asyncio`. It was made to be very similar to Flask.\n\n/// note | Technical Details\n\nIt used [`uvloop`](https://github.com/MagicStack/uvloop) instead of the default Python `asyncio` loop. That's what made it so fast.\n\nIt clearly inspired Uvicorn and Starlette, that are currently faster than Sanic in open benchmarks.\n\n///\n\n/// check | Inspired **FastAPI** to\n\nFind a way to have a crazy performance.\n\nThat's why **FastAPI** is based on Starlette, as it is the fastest framework available (tested by third-party benchmarks).\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon is another high performance Python framework, it is designed to be minimal, and work as the foundation of other frameworks like Hug.\n\nIt is designed to have functions that receive two parameters, one \"request\" and one \"response\". Then you \"read\" parts from the request, and \"write\" parts to the response. Because of this design, it is not possible to declare request parameters and bodies with standard Python type hints as function parameters.\n\nSo, data validation, serialization, and documentation, have to be done in code, not automatically. Or they have to be implemented as a framework on top of Falcon, like Hug. This same distinction happens in other frameworks that are inspired by Falcon's design, of having one request object and one response object as parameters.\n\n/// check | Inspired **FastAPI** to\n\nFind ways to get great performance.\n\nAlong with Hug (as Hug is based on Falcon) inspired **FastAPI** to declare a `response` parameter in functions.\n\nAlthough in FastAPI it's optional, and is used mainly to set headers, cookies, and alternative status codes.\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\nI discovered Molten in the first stages of building **FastAPI**. And it has quite similar ideas:\n\n* Based on Python type hints.\n* Validation and documentation from these types.\n* Dependency Injection system.\n\nIt doesn't use a data validation, serialization and documentation third-party library like Pydantic, it has its own. So, these data type definitions would not be reusable as easily.\n\nIt requires a little bit more verbose configurations. And as it is based on WSGI (instead of ASGI), it is not designed to take advantage of the high performance provided by tools like Uvicorn, Starlette and Sanic.\n\nThe dependency injection system requires pre-registration of the dependencies and the dependencies are solved based on the declared types. So, it's not possible to declare more than one \"component\" that provides a certain type.\n\nRoutes are declared in a single place, using functions declared in other places (instead of using decorators that can be placed right on top of the function that handles the endpoint). This is closer to how Django does it than to how Flask (and Starlette) does it. It separates in the code things that are relatively tightly coupled.\n\n/// check | Inspired **FastAPI** to\n\nDefine extra validations for data types using the \"default\" value of model attributes. This improves editor support, and it was not available in Pydantic before.\n\nThis actually inspired updating parts of Pydantic, to support the same validation declaration style (all this functionality is now already available in Pydantic).\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug was one of the first frameworks to implement the declaration of API parameter types using Python type hints. This was a great idea that inspired other tools to do the same.\n\nIt used custom types in its declarations instead of standard Python types, but it was still a huge step forward.\n\nIt also was one of the first frameworks to generate a custom schema declaring the whole API in JSON.\n\nIt was not based on a standard like OpenAPI and JSON Schema. So it wouldn't be straightforward to integrate it with other tools, like Swagger UI. But again, it was a very innovative idea.\n\nIt has an interesting, uncommon feature: using the same framework, it's possible to create APIs and also CLIs.\n\nAs it is based on the previous standard for synchronous Python web frameworks (WSGI), it can't handle Websockets and other things, although it still has high performance too.\n\n/// info\n\nHug was created by Timothy Crosley, the same creator of [`isort`](https://github.com/timothycrosley/isort), a great tool to automatically sort imports in Python files.\n\n///\n\n/// check | Ideas inspiring **FastAPI**\n\nHug inspired parts of APIStar, and was one of the tools I found most promising, alongside APIStar.\n\nHug helped inspiring **FastAPI** to use Python type hints to declare parameters, and to generate a schema defining the API automatically.\n\nHug inspired **FastAPI** to declare a `response` parameter in functions to set headers and cookies.\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0.5) { #apistar-0-5 }\n\nRight before deciding to build **FastAPI** I found **APIStar** server. It had almost everything I was looking for and had a great design.\n\nIt was one of the first implementations of a framework using Python type hints to declare parameters and requests that I ever saw (before NestJS and Molten). I found it more or less at the same time as Hug. But APIStar used the OpenAPI standard.\n\nIt had automatic data validation, data serialization and OpenAPI schema generation based on the same type hints in several places.\n\nBody schema definitions didn't use the same Python type hints like Pydantic, it was a bit more similar to Marshmallow, so, editor support wouldn't be as good, but still, APIStar was the best available option.\n\nIt had the best performance benchmarks at the time (only surpassed by Starlette).\n\nAt first, it didn't have an automatic API documentation web UI, but I knew I could add Swagger UI to it.\n\nIt had a dependency injection system. It required pre-registration of components, as other tools discussed above. But still, it was a great feature.\n\nI was never able to use it in a full project, as it didn't have security integration, so, I couldn't replace all the features I was having with the full-stack generators based on Flask-apispec. I had in my backlog of projects to create a pull request adding that functionality.\n\nBut then, the project's focus shifted.\n\nIt was no longer an API web framework, as the creator needed to focus on Starlette.\n\nNow APIStar is a set of tools to validate OpenAPI specifications, not a web framework.\n\n/// info\n\nAPIStar was created by Tom Christie. The same guy that created:\n\n* Django REST Framework\n* Starlette (in which **FastAPI** is based)\n* Uvicorn (used by Starlette and **FastAPI**)\n\n///\n\n/// check | Inspired **FastAPI** to\n\nExist.\n\nThe idea of declaring multiple things (data validation, serialization and documentation) with the same Python types, that at the same time provided great editor support, was something I considered a brilliant idea.\n\nAnd after searching for a long time for a similar framework and testing many different alternatives, APIStar was the best option available.\n\nThen APIStar stopped to exist as a server and Starlette was created, and was a new better foundation for such a system. That was the final inspiration to build **FastAPI**.\n\nI consider **FastAPI** a \"spiritual successor\" to APIStar, while improving and increasing the features, typing system, and other parts, based on the learnings from all these previous tools.\n\n///\n\n## Used by **FastAPI** { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic is a library to define data validation, serialization and documentation (using JSON Schema) based on Python type hints.\n\nThat makes it extremely intuitive.\n\nIt is comparable to Marshmallow. Although it's faster than Marshmallow in benchmarks. And as it is based on the same Python type hints, the editor support is great.\n\n/// check | **FastAPI** uses it to\n\nHandle all the data validation, data serialization and automatic model documentation (based on JSON Schema).\n\n**FastAPI** then takes that JSON Schema data and puts it in OpenAPI, apart from all the other things it does.\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette is a lightweight <dfn title=\"The new standard for building asynchronous Python web applications\">ASGI</dfn> framework/toolkit, which is ideal for building high-performance asyncio services.\n\nIt is very simple and intuitive. It's designed to be easily extensible, and have modular components.\n\nIt has:\n\n* Seriously impressive performance.\n* WebSocket support.\n* In-process background tasks.\n* Startup and shutdown events.\n* Test client built on HTTPX.\n* CORS, GZip, Static Files, Streaming responses.\n* Session and Cookie support.\n* 100% test coverage.\n* 100% type annotated codebase.\n* Few hard dependencies.\n\nStarlette is currently the fastest Python framework tested. Only surpassed by Uvicorn, which is not a framework, but a server.\n\nStarlette provides all the basic web microframework functionality.\n\nBut it doesn't provide automatic data validation, serialization or documentation.\n\nThat's one of the main things that **FastAPI** adds on top, all based on Python type hints (using Pydantic). That, plus the dependency injection system, security utilities, OpenAPI schema generation, etc.\n\n/// note | Technical Details\n\nASGI is a new \"standard\" being developed by Django core team members. It is still not a \"Python standard\" (a PEP), although they are in the process of doing that.\n\nNevertheless, it is already being used as a \"standard\" by several tools. This greatly improves interoperability, as you could switch Uvicorn for any other ASGI server (like Daphne or Hypercorn), or you could add ASGI compatible tools, like `python-socketio`.\n\n///\n\n/// check | **FastAPI** uses it to\n\nHandle all the core web parts. Adding features on top.\n\nThe class `FastAPI` itself inherits directly from the class `Starlette`.\n\nSo, anything that you can do with Starlette, you can do it directly with **FastAPI**, as it is basically Starlette on steroids.\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn is a lightning-fast ASGI server, built on uvloop and httptools.\n\nIt is not a web framework, but a server. For example, it doesn't provide tools for routing by paths. That's something that a framework like Starlette (or **FastAPI**) would provide on top.\n\nIt is the recommended server for Starlette and **FastAPI**.\n\n/// check | **FastAPI** recommends it as\n\nThe main web server to run **FastAPI** applications.\n\nYou can also use the `--workers` command line option to have an asynchronous multi-process server.\n\nCheck more details in the [Deployment](deployment/index.md) section.\n\n///\n\n## Benchmarks and speed { #benchmarks-and-speed }\n\nTo understand, compare, and see the difference between Uvicorn, Starlette and FastAPI, check the section about [Benchmarks](benchmarks.md).\n"
  },
  {
    "path": "docs/en/docs/async.md",
    "content": "# Concurrency and async / await { #concurrency-and-async-await }\n\nDetails about the `async def` syntax for *path operation functions* and some background about asynchronous code, concurrency, and parallelism.\n\n## In a hurry? { #in-a-hurry }\n\n<abbr title=\"too long; didn't read\"><strong>TL;DR:</strong></abbr>\n\nIf you are using third party libraries that tell you to call them with `await`, like:\n\n```Python\nresults = await some_library()\n```\n\nThen, declare your *path operation functions* with `async def` like:\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note\n\nYou can only use `await` inside of functions created with `async def`.\n\n///\n\n---\n\nIf you are using a third party library that communicates with something (a database, an API, the file system, etc.) and doesn't have support for using `await`, (this is currently the case for most database libraries), then declare your *path operation functions* as normally, with just `def`, like:\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\nIf your application (somehow) doesn't have to communicate with anything else and wait for it to respond, use `async def`, even if you don't need to use `await` inside.\n\n---\n\nIf you just don't know, use normal `def`.\n\n---\n\n**Note**: You can mix `def` and `async def` in your *path operation functions* as much as you need and define each one using the best option for you. FastAPI will do the right thing with them.\n\nAnyway, in any of the cases above, FastAPI will still work asynchronously and be extremely fast.\n\nBut by following the steps above, it will be able to do some performance optimizations.\n\n## Technical Details { #technical-details }\n\nModern versions of Python have support for **\"asynchronous code\"** using something called **\"coroutines\"**, with **`async` and `await`** syntax.\n\nLet's see that phrase by parts in the sections below:\n\n* **Asynchronous Code**\n* **`async` and `await`**\n* **Coroutines**\n\n## Asynchronous Code { #asynchronous-code }\n\nAsynchronous code just means that the language 💬 has a way to tell the computer / program 🤖 that at some point in the code, it 🤖 will have to wait for *something else* to finish somewhere else. Let's say that *something else* is called \"slow-file\" 📝.\n\nSo, during that time, the computer can go and do some other work, while \"slow-file\" 📝 finishes.\n\nThen the computer / program 🤖 will come back every time it has a chance because it's waiting again, or whenever it 🤖 finished all the work it had at that point. And it 🤖 will see if any of the tasks it was waiting for have already finished, doing whatever it had to do.\n\nNext, it 🤖 takes the first task to finish (let's say, our \"slow-file\" 📝) and continues whatever it had to do with it.\n\nThat \"wait for something else\" normally refers to <abbr title=\"Input and Output\">I/O</abbr> operations that are relatively \"slow\" (compared to the speed of the processor and the RAM memory), like waiting for:\n\n* the data from the client to be sent through the network\n* the data sent by your program to be received by the client through the network\n* the contents of a file in the disk to be read by the system and given to your program\n* the contents your program gave to the system to be written to disk\n* a remote API operation\n* a database operation to finish\n* a database query to return the results\n* etc.\n\nAs the execution time is consumed mostly by waiting for <abbr title=\"Input and Output\">I/O</abbr> operations, they call them \"I/O bound\" operations.\n\nIt's called \"asynchronous\" because the computer / program doesn't have to be \"synchronized\" with the slow task, waiting for the exact moment that the task finishes, while doing nothing, to be able to take the task result and continue the work.\n\nInstead of that, by being an \"asynchronous\" system, once finished, the task can wait in line a little bit (some microseconds) for the computer / program to finish whatever it went to do, and then come back to take the results and continue working with them.\n\nFor \"synchronous\" (contrary to \"asynchronous\") they commonly also use the term \"sequential\", because the computer / program follows all the steps in sequence before switching to a different task, even if those steps involve waiting.\n\n### Concurrency and Burgers { #concurrency-and-burgers }\n\nThis idea of **asynchronous** code described above is also sometimes called **\"concurrency\"**. It is different from **\"parallelism\"**.\n\n**Concurrency** and **parallelism** both relate to \"different things happening more or less at the same time\".\n\nBut the details between *concurrency* and *parallelism* are quite different.\n\nTo see the difference, imagine the following story about burgers:\n\n### Concurrent Burgers { #concurrent-burgers }\n\nYou go with your crush to get fast food, you stand in line while the cashier takes the orders from the people in front of you. 😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\nThen it's your turn, you place your order of 2 very fancy burgers for your crush and you. 🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\nThe cashier says something to the cook in the kitchen so they know they have to prepare your burgers (even though they are currently preparing the ones for the previous clients).\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\nYou pay. 💸\n\nThe cashier gives you the number of your turn.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\nWhile you are waiting, you go with your crush and pick a table, you sit and talk with your crush for a long time (as your burgers are very fancy and take some time to prepare).\n\nAs you are sitting at the table with your crush, while you wait for the burgers, you can spend that time admiring how awesome, cute and smart your crush is ✨😍✨.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\nWhile waiting and talking to your crush, from time to time, you check the number displayed on the counter to see if it's your turn already.\n\nThen at some point, it finally is your turn. You go to the counter, get your burgers and come back to the table.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\nYou and your crush eat the burgers and have a nice time. ✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info\n\nBeautiful illustrations by [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nImagine you are the computer / program 🤖 in that story.\n\nWhile you are at the line, you are just idle 😴, waiting for your turn, not doing anything very \"productive\". But the line is fast because the cashier is only taking the orders (not preparing them), so that's fine.\n\nThen, when it's your turn, you do actual \"productive\" work, you process the menu, decide what you want, get your crush's choice, pay, check that you give the correct bill or card, check that you are charged correctly, check that the order has the correct items, etc.\n\nBut then, even though you still don't have your burgers, your work with the cashier is \"on pause\" ⏸, because you have to wait 🕙 for your burgers to be ready.\n\nBut as you go away from the counter and sit at the table with a number for your turn, you can switch 🔀 your attention to your crush, and \"work\" ⏯ 🤓 on that. Then you are again doing something very \"productive\" as is flirting with your crush 😍.\n\nThen the cashier 💁 says \"I'm finished with doing the burgers\" by putting your number on the counter's display, but you don't jump like crazy immediately when the displayed number changes to your turn number. You know no one will steal your burgers because you have the number of your turn, and they have theirs.\n\nSo you wait for your crush to finish the story (finish the current work ⏯ / task being processed 🤓), smile gently and say that you are going for the burgers ⏸.\n\nThen you go to the counter 🔀, to the initial task that is now finished ⏯, pick the burgers, say thanks and take them to the table. That finishes that step / task of interaction with the counter ⏹. That in turn, creates a new task, of \"eating burgers\" 🔀 ⏯, but the previous one of \"getting burgers\" is finished ⏹.\n\n### Parallel Burgers { #parallel-burgers }\n\nNow let's imagine these aren't \"Concurrent Burgers\", but \"Parallel Burgers\".\n\nYou go with your crush to get parallel fast food.\n\nYou stand in line while several (let's say 8) cashiers that at the same time are cooks take the orders from the people in front of you.\n\nEveryone before you is waiting for their burgers to be ready before leaving the counter because each of the 8 cashiers goes and prepares the burger right away before getting the next order.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\nThen it's finally your turn, you place your order of 2 very fancy burgers for your crush and you.\n\nYou pay 💸.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\nThe cashier goes to the kitchen.\n\nYou wait, standing in front of the counter 🕙, so that no one else takes your burgers before you do, as there are no numbers for turns.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\nAs you and your crush are busy not letting anyone get in front of you and take your burgers whenever they arrive, you cannot pay attention to your crush. 😞\n\nThis is \"synchronous\" work, you are \"synchronized\" with the cashier/cook 👨‍🍳. You have to wait 🕙 and be there at the exact moment that the cashier/cook 👨‍🍳 finishes the burgers and gives them to you, or otherwise, someone else might take them.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\nThen your cashier/cook 👨‍🍳 finally comes back with your burgers, after a long time waiting 🕙 there in front of the counter.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\nYou take your burgers and go to the table with your crush.\n\nYou just eat them, and you are done. ⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\nThere was not much talk or flirting as most of the time was spent waiting 🕙 in front of the counter. 😞\n\n/// info\n\nBeautiful illustrations by [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nIn this scenario of the parallel burgers, you are a computer / program 🤖 with two processors (you and your crush), both waiting 🕙 and dedicating their attention ⏯ to be \"waiting on the counter\" 🕙 for a long time.\n\nThe fast food store has 8 processors (cashiers/cooks). While the concurrent burgers store might have had only 2 (one cashier and one cook).\n\nBut still, the final experience is not the best. 😞\n\n---\n\nThis would be the parallel equivalent story for burgers. 🍔\n\nFor a more \"real life\" example of this, imagine a bank.\n\nUp to recently, most of the banks had multiple cashiers 👨‍💼👨‍💼👨‍💼👨‍💼 and a big line 🕙🕙🕙🕙🕙🕙🕙🕙.\n\nAll of the cashiers doing all the work with one client after the other 👨‍💼⏯.\n\nAnd you have to wait 🕙 in the line for a long time or you lose your turn.\n\nYou probably wouldn't want to take your crush 😍 with you to run errands at the bank 🏦.\n\n### Burger Conclusion { #burger-conclusion }\n\nIn this scenario of \"fast food burgers with your crush\", as there is a lot of waiting 🕙, it makes a lot more sense to have a concurrent system ⏸🔀⏯.\n\nThis is the case for most of the web applications.\n\nMany, many users, but your server is waiting 🕙 for their not-so-good connection to send their requests.\n\nAnd then waiting 🕙 again for the responses to come back.\n\nThis \"waiting\" 🕙 is measured in microseconds, but still, summing it all, it's a lot of waiting in the end.\n\nThat's why it makes a lot of sense to use asynchronous ⏸🔀⏯ code for web APIs.\n\nThis kind of asynchronicity is what made NodeJS popular (even though NodeJS is not parallel) and that's the strength of Go as a programming language.\n\nAnd that's the same level of performance you get with **FastAPI**.\n\nAnd as you can have parallelism and asynchronicity at the same time, you get higher performance than most of the tested NodeJS frameworks and on par with Go, which is a compiled language closer to C [(all thanks to Starlette)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).\n\n### Is concurrency better than parallelism? { #is-concurrency-better-than-parallelism }\n\nNope! That's not the moral of the story.\n\nConcurrency is different than parallelism. And it is better on **specific** scenarios that involve a lot of waiting. Because of that, it generally is a lot better than parallelism for web application development. But not for everything.\n\nSo, to balance that out, imagine the following short story:\n\n> You have to clean a big, dirty house.\n\n*Yep, that's the whole story*.\n\n---\n\nThere's no waiting 🕙 anywhere, just a lot of work to be done, on multiple places of the house.\n\nYou could have turns as in the burgers example, first the living room, then the kitchen, but as you are not waiting 🕙 for anything, just cleaning and cleaning, the turns wouldn't affect anything.\n\nIt would take the same amount of time to finish with or without turns (concurrency) and you would have done the same amount of work.\n\nBut in this case, if you could bring the 8 ex-cashier/cooks/now-cleaners, and each one of them (plus you) could take a zone of the house to clean it, you could do all the work in **parallel**, with the extra help, and finish much sooner.\n\nIn this scenario, each one of the cleaners (including you) would be a processor, doing their part of the job.\n\nAnd as most of the execution time is taken by actual work (instead of waiting), and the work in a computer is done by a <abbr title=\"Central Processing Unit\">CPU</abbr>, they call these problems \"CPU bound\".\n\n---\n\nCommon examples of CPU bound operations are things that require complex math processing.\n\nFor example:\n\n* **Audio** or **image processing**.\n* **Computer vision**: an image is composed of millions of pixels, each pixel has 3 values / colors, processing that normally requires computing something on those pixels, all at the same time.\n* **Machine Learning**: it normally requires lots of \"matrix\" and \"vector\" multiplications. Think of a huge spreadsheet with numbers and multiplying all of them together at the same time.\n* **Deep Learning**: this is a sub-field of Machine Learning, so, the same applies. It's just that there is not a single spreadsheet of numbers to multiply, but a huge set of them, and in many cases, you use a special processor to build and / or use those models.\n\n### Concurrency + Parallelism: Web + Machine Learning { #concurrency-parallelism-web-machine-learning }\n\nWith **FastAPI** you can take advantage of concurrency that is very common for web development (the same main attraction of NodeJS).\n\nBut you can also exploit the benefits of parallelism and multiprocessing (having multiple processes running in parallel) for **CPU bound** workloads like those in Machine Learning systems.\n\nThat, plus the simple fact that Python is the main language for **Data Science**, Machine Learning and especially Deep Learning, make FastAPI a very good match for Data Science / Machine Learning web APIs and applications (among many others).\n\nTo see how to achieve this parallelism in production see the section about [Deployment](deployment/index.md).\n\n## `async` and `await` { #async-and-await }\n\nModern versions of Python have a very intuitive way to define asynchronous code. This makes it look just like normal \"sequential\" code and do the \"awaiting\" for you at the right moments.\n\nWhen there is an operation that will require waiting before giving the results and has support for these new Python features, you can code it like:\n\n```Python\nburgers = await get_burgers(2)\n```\n\nThe key here is the `await`. It tells Python that it has to wait ⏸ for `get_burgers(2)` to finish doing its thing 🕙 before storing the results in `burgers`. With that, Python will know that it can go and do something else 🔀 ⏯ in the meanwhile (like receiving another request).\n\nFor `await` to work, it has to be inside a function that supports this asynchronicity. To do that, you just declare it with `async def`:\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # Do some asynchronous stuff to create the burgers\n    return burgers\n```\n\n...instead of `def`:\n\n```Python hl_lines=\"2\"\n# This is not asynchronous\ndef get_sequential_burgers(number: int):\n    # Do some sequential stuff to create the burgers\n    return burgers\n```\n\nWith `async def`, Python knows that, inside that function, it has to be aware of `await` expressions, and that it can \"pause\" ⏸ the execution of that function and go do something else 🔀 before coming back.\n\nWhen you want to call an `async def` function, you have to \"await\" it. So, this won't work:\n\n```Python\n# This won't work, because get_burgers was defined with: async def\nburgers = get_burgers(2)\n```\n\n---\n\nSo, if you are using a library that tells you that you can call it with `await`, you need to create the *path operation functions* that uses it with `async def`, like in:\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### More technical details { #more-technical-details }\n\nYou might have noticed that `await` can only be used inside of functions defined with `async def`.\n\nBut at the same time, functions defined with `async def` have to be \"awaited\". So, functions with `async def` can only be called inside of functions defined with `async def` too.\n\nSo, about the egg and the chicken, how do you call the first `async` function?\n\nIf you are working with **FastAPI** you don't have to worry about that, because that \"first\" function will be your *path operation function*, and FastAPI will know how to do the right thing.\n\nBut if you want to use `async` / `await` without FastAPI, you can do it as well.\n\n### Write your own async code { #write-your-own-async-code }\n\nStarlette (and **FastAPI**) are based on [AnyIO](https://anyio.readthedocs.io/en/stable/), which makes it compatible with both Python's standard library [asyncio](https://docs.python.org/3/library/asyncio-task.html) and [Trio](https://trio.readthedocs.io/en/stable/).\n\nIn particular, you can directly use [AnyIO](https://anyio.readthedocs.io/en/stable/) for your advanced concurrency use cases that require more advanced patterns in your own code.\n\nAnd even if you were not using FastAPI, you could also write your own async applications with [AnyIO](https://anyio.readthedocs.io/en/stable/) to be highly compatible and get its benefits (e.g. *structured concurrency*).\n\nI created another library on top of AnyIO, as a thin layer on top, to improve a bit the type annotations and get better **autocompletion**, **inline errors**, etc. It also has a friendly introduction and tutorial to help you **understand** and write **your own async code**: [Asyncer](https://asyncer.tiangolo.com/). It would be particularly useful if you need to **combine async code with regular** (blocking/synchronous) code.\n\n### Other forms of asynchronous code { #other-forms-of-asynchronous-code }\n\nThis style of using `async` and `await` is relatively new in the language.\n\nBut it makes working with asynchronous code a lot easier.\n\nThis same syntax (or almost identical) was also included recently in modern versions of JavaScript (in Browser and NodeJS).\n\nBut before that, handling asynchronous code was quite more complex and difficult.\n\nIn previous versions of Python, you could have used threads or [Gevent](https://www.gevent.org/). But the code is way more complex to understand, debug, and think about.\n\nIn previous versions of NodeJS / Browser JavaScript, you would have used \"callbacks\". Which leads to \"callback hell\".\n\n## Coroutines { #coroutines }\n\n**Coroutine** is just the very fancy term for the thing returned by an `async def` function. Python knows that it is something like a function, that it can start and that it will end at some point, but that it might be paused ⏸ internally too, whenever there is an `await` inside of it.\n\nBut all this functionality of using asynchronous code with `async` and `await` is many times summarized as using \"coroutines\". It is comparable to the main key feature of Go, the \"Goroutines\".\n\n## Conclusion { #conclusion }\n\nLet's see the same phrase from above:\n\n> Modern versions of Python have support for **\"asynchronous code\"** using something called **\"coroutines\"**, with **`async` and `await`** syntax.\n\nThat should make more sense now. ✨\n\nAll that is what powers FastAPI (through Starlette) and what makes it have such an impressive performance.\n\n## Very Technical Details { #very-technical-details }\n\n/// warning\n\nYou can probably skip this.\n\nThese are very technical details of how **FastAPI** works underneath.\n\nIf you have quite some technical knowledge (coroutines, threads, blocking, etc.) and are curious about how FastAPI handles `async def` vs normal `def`, go ahead.\n\n///\n\n### Path operation functions { #path-operation-functions }\n\nWhen you declare a *path operation function* with normal `def` instead of `async def`, it is run in an external threadpool that is then awaited, instead of being called directly (as it would block the server).\n\nIf you are coming from another async framework that does not work in the way described above and you are used to defining trivial compute-only *path operation functions* with plain `def` for a tiny performance gain (about 100 nanoseconds), please note that in **FastAPI** the effect would be quite opposite. In these cases, it's better to use `async def` unless your *path operation functions* use code that performs blocking <abbr title=\"Input/Output: disk reading or writing, network communications.\">I/O</abbr>.\n\nStill, in both situations, chances are that **FastAPI** will [still be faster](index.md#performance) than (or at least comparable to) your previous framework.\n\n### Dependencies { #dependencies }\n\nThe same applies for [dependencies](tutorial/dependencies/index.md). If a dependency is a standard `def` function instead of `async def`, it is run in the external threadpool.\n\n### Sub-dependencies { #sub-dependencies }\n\nYou can have multiple dependencies and [sub-dependencies](tutorial/dependencies/sub-dependencies.md) 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\".\n\n### Other utility functions { #other-utility-functions }\n\nAny other utility function that you call directly can be created with normal `def` or `async def` and FastAPI won't affect the way you call it.\n\nThis is in contrast to the functions that FastAPI calls for you: *path operation functions* and dependencies.\n\nIf your utility function is a normal function with `def`, it will be called directly (as you write it in your code), not in a threadpool, if the function is created with `async def` then you should `await` for that function when you call it in your code.\n\n---\n\nAgain, these are very technical details that would probably be useful if you came searching for them.\n\nOtherwise, you should be good with the guidelines from the section above: <a href=\"#in-a-hurry\">In a hurry?</a>.\n"
  },
  {
    "path": "docs/en/docs/benchmarks.md",
    "content": "# Benchmarks { #benchmarks }\n\nIndependent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as [one of the fastest Python frameworks available](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), only below Starlette and Uvicorn themselves (used internally by FastAPI).\n\nBut when checking benchmarks and comparisons you should keep the following in mind.\n\n## Benchmarks and speed { #benchmarks-and-speed }\n\nWhen you check the benchmarks, it is common to see several tools of different types compared as equivalent.\n\nSpecifically, to see Uvicorn, Starlette and FastAPI compared together (among many other tools).\n\nThe simpler the problem solved by the tool, the better performance it will get. And most of the benchmarks don't test the additional features provided by the tool.\n\nThe hierarchy is like:\n\n* **Uvicorn**: an ASGI server\n    * **Starlette**: (uses Uvicorn) a web microframework\n        * **FastAPI**: (uses Starlette) an API microframework with several additional features for building APIs, with data validation, etc.\n\n* **Uvicorn**:\n    * Will have the best performance, as it doesn't have much extra code apart from the server itself.\n    * You wouldn't write an application in Uvicorn directly. That would mean that your code would have to include more or less, at least, all the code provided by Starlette (or **FastAPI**). And if you did that, your final application would have the same overhead as having used a framework and minimizing your app code and bugs.\n    * If you are comparing Uvicorn, compare it against Daphne, Hypercorn, uWSGI, etc. Application servers.\n* **Starlette**:\n    * Will have the next best performance, after Uvicorn. In fact, Starlette uses Uvicorn to run. So, it probably can only get \"slower\" than Uvicorn by having to execute more code.\n    * But it provides you the tools to build simple web applications, with routing based on paths, etc.\n    * If you are comparing Starlette, compare it against Sanic, Flask, Django, etc. Web frameworks (or microframeworks).\n* **FastAPI**:\n    * The same way that Starlette uses Uvicorn and cannot be faster than it, **FastAPI** uses Starlette, so it cannot be faster than it.\n    * FastAPI provides more features on top of Starlette. Features that you almost always need when building APIs, like data validation and serialization. And by using it, you get automatic documentation for free (the automatic documentation doesn't even add overhead to running applications, it is generated on startup).\n    * If you didn't use FastAPI and used Starlette directly (or another tool, like Sanic, Flask, Responder, etc) you would have to implement all the data validation and serialization yourself. So, your final application would still have the same overhead as if it was built using FastAPI. And in many cases, this data validation and serialization is the biggest amount of code written in applications.\n    * So, by using FastAPI you are saving development time, bugs, lines of code, and you would probably get the same performance (or better) you would if you didn't use it (as you would have to implement it all in your code).\n    * If you are comparing FastAPI, compare it against a web application framework (or set of tools) that provides data validation, serialization and documentation, like Flask-apispec, NestJS, Molten, etc. Frameworks with integrated automatic data validation, serialization and documentation.\n"
  },
  {
    "path": "docs/en/docs/contributing.md",
    "content": "# Development - Contributing\n\nFirst, you might want to see the basic ways to [help FastAPI and get help](help-fastapi.md).\n\n## Developing\n\nIf you already cloned the [fastapi repository](https://github.com/fastapi/fastapi) and you want to deep dive in the code, here are some guidelines to set up your environment.\n\n### Install requirements\n\nCreate a virtual environment and install the required packages with [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv sync --extra all\n\n---> 100%\n```\n\n</div>\n\nIt will install all the dependencies and your local FastAPI in your local environment.\n\n### Using your local FastAPI\n\nIf you create a Python file that imports and uses FastAPI, and run it with the Python from your local environment, it will use your cloned local FastAPI source code.\n\nAnd if you update that local FastAPI source code when you run that Python file again, it will use the fresh version of FastAPI you just edited.\n\nThat way, you don't have to \"install\" your local version to be able to test every change.\n\n/// note | Technical Details\n\nThis only happens when you install using `uv sync --extra all` instead of running `pip install fastapi` directly.\n\nThat is because `uv sync --extra all` will install the local version of FastAPI in \"editable\" mode by default.\n\n///\n\n### Format the code\n\nThere is a script that you can run that will format and clean all your code:\n\n<div class=\"termy\">\n\n```console\n$ bash scripts/format.sh\n```\n\n</div>\n\nIt will also auto-sort all your imports.\n\n## Tests\n\nThere is a script that you can run locally to test all the code and generate coverage reports in HTML:\n\n<div class=\"termy\">\n\n```console\n$ bash scripts/test-cov-html.sh\n```\n\n</div>\n\nThis command generates a directory `./htmlcov/`, if you open the file `./htmlcov/index.html` in your browser, you can explore interactively the regions of code that are covered by the tests, and notice if there is any region missing.\n\n## Docs\n\nFirst, make sure you set up your environment as described above, that will install all the requirements.\n\n### Docs live\n\nDuring local development, there is a script that builds the site and checks for any changes, live-reloading:\n\n<div class=\"termy\">\n\n```console\n$ python ./scripts/docs.py live\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\n</div>\n\nIt will serve the documentation on `http://127.0.0.1:8008`.\n\nThat way, you can edit the documentation/source files and see the changes live.\n\n/// tip\n\nAlternatively, you can perform the same steps that scripts does manually.\n\nGo into the language directory, for the main docs in English it's at `docs/en/`:\n\n```console\n$ cd docs/en/\n```\n\nThen run `mkdocs` in that directory:\n\n```console\n$ mkdocs serve --dev-addr 127.0.0.1:8008\n```\n\n///\n\n#### Typer CLI (optional)\n\nThe instructions here show you how to use the script at `./scripts/docs.py` with the `python` program directly.\n\nBut you can also use [Typer CLI](https://typer.tiangolo.com/typer-cli/), and you will get autocompletion in your terminal for the commands after installing completion.\n\nIf you install Typer CLI, you can install completion with:\n\n<div class=\"termy\">\n\n```console\n$ typer --install-completion\n\nzsh completion installed in /home/user/.bashrc.\nCompletion will take effect once you restart the terminal.\n```\n\n</div>\n\n### Docs Structure\n\nThe documentation uses [MkDocs](https://www.mkdocs.org/).\n\nAnd there are extra tools/scripts in place to handle translations in `./scripts/docs.py`.\n\n/// tip\n\nYou don't need to see the code in `./scripts/docs.py`, you just use it in the command line.\n\n///\n\nAll the documentation is in Markdown format in the directory `./docs/en/`.\n\nMany of the tutorials have blocks of code.\n\nIn most of the cases, these blocks of code are actual complete applications that can be run as is.\n\nIn fact, those blocks of code are not written inside the Markdown, they are Python files in the `./docs_src/` directory.\n\nAnd those Python files are included/injected in the documentation when generating the site.\n\n### Docs for tests\n\nMost of the tests actually run against the example source files in the documentation.\n\nThis helps to make sure that:\n\n* The documentation is up-to-date.\n* The documentation examples can be run as is.\n* Most of the features are covered by the documentation, ensured by test coverage.\n\n#### Apps and docs at the same time\n\nIf you run the examples with, e.g.:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev tutorial001.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nas Uvicorn by default will use the port `8000`, the documentation on port `8008` won't clash.\n\n### Translations\n\nHelp with translations is VERY MUCH appreciated! And it can't be done without the help from the community. 🌎 🚀\n\nTranslation pull requests are made by LLMs guided with prompts designed by the FastAPI team together with the community of native speakers for each supported language.\n\n#### LLM Prompt per Language\n\nEach language has a directory: [https://github.com/fastapi/fastapi/tree/master/docs](https://github.com/fastapi/fastapi/tree/master/docs), in it you can see a file `llm-prompt.md` with the prompt specific for that language.\n\nFor example, for Spanish, the prompt is at: [`docs/es/llm-prompt.md`](https://github.com/fastapi/fastapi/blob/master/docs/es/llm-prompt.md).\n\nIf you see mistakes in your language, you can make suggestions to the prompt in that file for your language, and request the specific pages you would like to re-generate after the changes.\n\n#### Reviewing Translation PRs\n\nWe don’t require approval from native speakers for translation PRs generated automatically by our translation workflow. However, you can still review them and suggest improvements to the LLM prompt for that language to make the future translations better.\n\nYou can check the currently [existing pull requests](https://github.com/fastapi/fastapi/pulls) for your language. You can filter the pull requests by the ones with the label for your language. For example, for Spanish, the label is [`lang-es`](https://github.com/fastapi/fastapi/pulls?q=is%3Aopen+sort%3Aupdated-desc+label%3Alang-es+label%3Aawaiting-review).\n\nYou can also review already merged translation PRs. To do this, go to the [closed pull requests](https://github.com/fastapi/fastapi/pulls?q=is%3Apr+is%3Aclosed) and filter by your language label. For example, for Spanish, you can use [`lang-es`](https://github.com/fastapi/fastapi/pulls?q=is%3Apr+is%3Aclosed+label%3Alang-es).\n\nWhen reviewing a pull request, it's better not to suggest changes in the same pull request, because it is LLM generated, and it won't be possible to make sure that small individual changes are replicated in other similar sections, or that they are preserved when translating the same content again.\n\nInstead of adding suggestions to the translation PR, make the suggestions to the LLM prompt file for that language, in a new PR. For example, for Spanish, the LLM prompt file is at: [`docs/es/llm-prompt.md`](https://github.com/fastapi/fastapi/blob/master/docs/es/llm-prompt.md).\n\n/// tip\n\nCheck the docs about [adding a pull request review](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-reviews) to approve it or request changes.\n\n///\n\nPRs with suggestions to the language-specific LLM prompt require approval from at least one native speaker. Your help here is very much appreciated!\n\n#### Subscribe to Notifications for Your Language\n\nCheck if there's a [GitHub Discussion](https://github.com/fastapi/fastapi/discussions/categories/translations) to coordinate translations for your language. You can subscribe to it, and when there's a new pull request to review, an automatic comment will be added to the discussion.\n\nTo check the 2-letter code for the language you want to translate, you can use the table [List of ISO 639-1 codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).\n\n#### Request a New Language\n\nLet's say that you want to request translations for a language that is not yet translated, not even some pages. For example, Latin.\n\n* The first step would be for you to find other 2 people that would be willing to be reviewing translation PRs for that language with you.\n* Once there are at least 3 people that would be willing to commit to help maintain that language, you can continue the next steps.\n* Create a new discussion following the template.\n* Tag the other 2 people that will help with the language, and ask them to confirm there they will help.\n\nOnce there are several people in the discussion, the FastAPI team can evaluate it and can make it an official translation.\n\nThen the docs will be automatically translated using LLMs, and the team of native speakers can review the translation, and help tweak the LLM prompts.\n\nOnce there's a new translation, for example if docs are updated or there's a new section, there will be a comment in the same discussion with the link to the new translation to review.\n\n## Automated Code and AI\n\nYou are encouraged to use all the tools you want to do your work and contribute as efficiently as possible, this includes AI (LLM) tools, etc. Nevertheless, contributions should have meaningful human intervention, judgement, context, etc.\n\nIf the **human effort** put in a PR, e.g. writing LLM prompts, is **less** than the **effort we would need to put** to **review it**, please **don't** submit the PR.\n\nThink of it this way: we can already write LLM prompts or run automated tools ourselves, and that would be faster than reviewing external PRs.\n\n### Closing Automated and AI PRs\n\nIf we see PRs that seem AI generated or automated in similar ways, we'll flag them and close them.\n\nThe same applies to comments and descriptions, please don't copy paste the content generated by an LLM.\n\n### Human Effort Denial of Service\n\nUsing automated tools and AI to submit PRs or comments that we have to carefully review and handle would be the equivalent of a [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack) on our human effort.\n\nIt would be very little effort from the person submitting the PR (an LLM prompt) that generates a large amount of effort on our side (carefully reviewing code).\n\nPlease don't do that.\n\nWe'll need to block accounts that spam us with repeated automated PRs or comments.\n\n### Use Tools Wisely\n\nAs Uncle Ben said:\n\n<blockquote>\nWith great <strike>power</strike> <strong>tools</strong> comes great responsibility.\n</blockquote>\n\nAvoid inadvertently doing harm.\n\nYou have amazing tools at hand, use them wisely to help effectively.\n"
  },
  {
    "path": "docs/en/docs/css/custom.css",
    "content": "/* Fira Code, including characters used by Rich output, like the \"heavy right-pointing angle bracket ornament\", not included in Google Fonts */\n@import url(https://cdn.jsdelivr.net/npm/firacode@6.2.0/distr/fira_code.css);\n/* Noto Color Emoji for emoji support with the same font everywhere */\n@import url(https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&display=swap);\n\n/* Override default code font in Material for MkDocs to Fira Code */\n:root {\n    --md-code-font: \"Fira Code\", monospace, \"Noto Color Emoji\";\n}\n\n/* Override default regular font in Material for MkDocs to include Noto Color Emoji */\n:root {\n    --md-text-font: \"Roboto\", \"Noto Color Emoji\";\n}\n\n.termynal-comment {\n  color: #4a968f;\n  font-style: italic;\n  display: block;\n}\n\n.termy {\n  /* For right to left languages */\n  direction: ltr;\n}\n\n.termy [data-termynal] {\n  white-space: pre-wrap;\n}\n\n.termy .linenos {\n  display: none;\n}\n\n/* External links: detected by JS comparing origin to site origin\n   JS sets data-external-link on links pointing outside the site\n   Skip image links, .no-link-icon, and .announce-link */\na[data-external-link]:not(:has(img)):not(.no-link-icon):not(.announce-link) {\n  /* For right to left languages */\n  direction: ltr;\n  display: inline-block;\n}\n\na[data-external-link]:not(:has(img)):not(.no-link-icon):not(.announce-link)::after {\n  content: \"\";\n  display: inline-block;\n  width: 0.75em;\n  height: 0.75em;\n  margin-left: 0.25em;\n  vertical-align: middle;\n  opacity: 0.55;\n  background: currentColor;\n  -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpolyline points='15 3 21 3 21 9'/%3E%3Cline x1='10' y1='14' x2='21' y2='3'/%3E%3C/svg%3E\");\n  -webkit-mask-size: contain;\n  -webkit-mask-repeat: no-repeat;\n  mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpolyline points='15 3 21 3 21 9'/%3E%3Cline x1='10' y1='14' x2='21' y2='3'/%3E%3C/svg%3E\");\n  mask-size: contain;\n  mask-repeat: no-repeat;\n}\n\na[data-external-link]:not(:has(img)):not(.no-link-icon):not(.announce-link):hover::after {\n  opacity: 0.85;\n}\n\n/* Internal links opening in new tab: same-origin links with target=_blank\n   JS sets data-internal-link on links pointing to the same site origin\n   Skip image links, .no-link-icon, and .announce-link */\na[data-internal-link][target=\"_blank\"]:not(:has(img)):not(.no-link-icon):not(.announce-link) {\n  /* For right to left languages */\n  direction: ltr;\n  display: inline-block;\n}\n\na[data-internal-link][target=\"_blank\"]:not(:has(img)):not(.no-link-icon):not(.announce-link)::after {\n  content: \"\";\n  display: inline-block;\n  width: 0.75em;\n  height: 0.75em;\n  margin-left: 0.25em;\n  vertical-align: middle;\n  opacity: 0.55;\n  background: currentColor;\n  -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='7' width='14' height='14' rx='2'/%3E%3Cpath d='M7 3h14v14'/%3E%3C/svg%3E\");\n  -webkit-mask-size: contain;\n  -webkit-mask-repeat: no-repeat;\n  mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='7' width='14' height='14' rx='2'/%3E%3Cpath d='M7 3h14v14'/%3E%3C/svg%3E\");\n  mask-size: contain;\n  mask-repeat: no-repeat;\n}\n\na[data-internal-link][target=\"_blank\"]:not(:has(img)):not(.no-link-icon):not(.announce-link):hover::after {\n  opacity: 0.85;\n}\n\n/* Disable link icons in footer and header nav */\n.md-footer a::after,\n.md-header a::after {\n  content: none !important;\n}\n\n.shadow {\n  box-shadow: 5px 5px 10px #999;\n}\n\n/* Give space to lower icons so Gitter chat doesn't get on top of them */\n.md-footer-meta {\n  padding-bottom: 2em;\n}\n\n.md-footer-meta .md-social {\n  padding-right: 4rem;\n}\n\n.user-list {\n  display: flex;\n  flex-wrap: wrap;\n  margin-bottom: 2rem;\n}\n\n.user-list-center {\n  justify-content: space-evenly;\n}\n\n.user {\n  margin: 1em;\n  min-width: 7em;\n}\n\n.user .avatar-wrapper {\n  width: 80px;\n  height: 80px;\n  margin: 10px auto;\n  overflow: hidden;\n  border-radius: 50%;\n  position: relative;\n}\n\n.user .avatar-wrapper img {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  transform: translate(-50%, -50%);\n}\n\n.user .title {\n  text-align: center;\n}\n\n.user .count {\n  font-size: 80%;\n  text-align: center;\n}\n\na.announce-link:link,\na.announce-link:visited {\n  color: #fff;\n}\n\na.announce-link:hover {\n  color: var(--md-accent-fg-color);\n}\n\n.announce-wrapper {\n  display: flex;\n  justify-content: space-between;\n  flex-wrap: wrap;\n  align-items: center;\n}\n\n.announce-wrapper #announce-left div.item {\n  display: none;\n}\n\n.announce-wrapper #announce-right {\n  display: none;\n}\n\n.announce-wrapper #announce-right div.item {\n  display: none;\n}\n\n.announce-wrapper .sponsor-badge {\n  display: block;\n  position: absolute;\n  top: -10px;\n  right: 0;\n  font-size: 0.5rem;\n  color: #e6e6e6;\n  background-color: #666;\n  border-radius: 10px;\n  padding: 0 10px;\n  z-index: 10;\n}\n\n.announce-wrapper .sponsor-image {\n  display: block;\n  border-radius: 20px;\n}\n\n.announce-wrapper>div {\n  min-height: 40px;\n  display: flex;\n  align-items: center;\n}\n\n.twitter {\n  color: #00acee;\n}\n\n/* Right to left languages */\ncode {\n  direction: ltr;\n  display: inline-block;\n}\n\n.illustration {\n  margin-top: 2em;\n  margin-bottom: 2em;\n}\n\n/* Screenshots */\n/*\nSimulate a browser window frame.\nInspired by Termynal's CSS tricks with modifications\n*/\n\n.screenshot {\n  display: block;\n  background-color: #d3e0de;\n  border-radius: 4px;\n  padding: 45px 5px 5px;\n  position: relative;\n  -webkit-box-sizing: border-box;\n          box-sizing: border-box;\n}\n\n.screenshot img {\n  display: block;\n  border-radius: 2px;\n}\n\n.screenshot:before {\n  content: '';\n  position: absolute;\n  top: 15px;\n  left: 15px;\n  display: inline-block;\n  width: 15px;\n  height: 15px;\n  border-radius: 50%;\n  /* A little hack to display the window buttons in one pseudo element. */\n  background: #d9515d;\n  -webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;\n          box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;\n}\n\n.doc-param-details .highlight {\n  overflow-x: auto;\n  width: 0;\n  min-width: 100%;\n}\n\n.md-typeset dfn {\n  border-bottom: .05rem dotted var(--md-default-fg-color--light);\n  cursor: help;\n}\n\n/* Opinions: interactive logo tabs */\n.fastapi-opinions {\n  margin: 1.5rem 0 2rem;\n}\n.fastapi-opinions__tabs {\n  display: grid;\n  grid-template-columns: repeat(4, 1fr);\n  gap: 0.25rem;\n  margin-bottom: 1.5rem;\n  border-bottom: 1px solid var(--md-default-fg-color--lightest);\n}\n.fastapi-opinions__tab {\n  position: relative;\n  appearance: none;\n  background: none;\n  border: 0;\n  padding: 0.625rem 0.5rem;\n  margin: 0;\n  cursor: pointer;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  color: inherit;\n  font: inherit;\n  min-height: 40px;\n  min-width: 0;\n}\n.fastapi-opinions__tab::after {\n  content: \"\";\n  position: absolute;\n  left: 50%;\n  right: 50%;\n  bottom: -1px;\n  height: 2px;\n  background-color: var(--md-primary-fg-color);\n  opacity: 0;\n  transition: left 0.2s ease, right 0.2s ease, opacity 0.2s ease;\n}\n.fastapi-opinions__tab[aria-selected=\"true\"]::after {\n  left: 12%;\n  right: 12%;\n  opacity: 1;\n}\n.fastapi-opinions__tab:focus-visible {\n  outline: 2px solid var(--md-primary-fg-color);\n  outline-offset: 2px;\n  border-radius: 4px;\n}\n.fastapi-opinions__mark {\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  height: 22px;\n  max-width: 100%;\n  filter: grayscale(1);\n  opacity: 0.5;\n  transition: filter 0.2s, opacity 0.2s;\n}\n.fastapi-opinions__mark img {\n  height: 100%;\n  width: auto;\n  max-width: 100%;\n  object-fit: contain;\n  display: block;\n}\n.fastapi-opinions__tab:hover .fastapi-opinions__mark {\n  filter: grayscale(0.3);\n  opacity: 0.85;\n}\n.fastapi-opinions__tab[aria-selected=\"true\"] .fastapi-opinions__mark {\n  filter: grayscale(0);\n  opacity: 1;\n}\n\n/* Dark mode: brighten dark wordmarks so they read on slate */\n[data-md-color-scheme=\"slate\"] .fastapi-opinions__mark {\n  filter: grayscale(1) invert(0.85);\n}\n[data-md-color-scheme=\"slate\"] .fastapi-opinions__tab:hover .fastapi-opinions__mark {\n  filter: grayscale(0.3) invert(0.4);\n}\n[data-md-color-scheme=\"slate\"] .fastapi-opinions__tab[aria-selected=\"true\"] .fastapi-opinions__mark {\n  filter: none;\n}\n\n.fastapi-opinions__panel {\n  position: relative;\n  padding: 0.5rem 1rem 0.5rem 3rem;\n}\n.fastapi-opinions__panel::before {\n  content: \"\\201C\";\n  position: absolute;\n  top: -0.75rem;\n  left: 0.25rem;\n  font-family: Georgia, \"Times New Roman\", serif;\n  font-size: 4rem;\n  line-height: 1;\n  color: var(--md-primary-fg-color);\n  opacity: 0.18;\n  pointer-events: none;\n}\n.md-typeset blockquote.fastapi-opinions__quote {\n  margin: 0;\n  font-size: 1rem;\n  font-style: italic;\n  line-height: 1.65;\n  color: var(--md-default-fg-color);\n  border-left: 0;\n  padding-left: 0;\n}\n.fastapi-opinions__quote strong { font-style: normal; }\n.fastapi-opinions__attr {\n  margin-top: 0.875rem;\n  font-size: 0.8rem;\n  color: var(--md-default-fg-color--light);\n}\n.fastapi-opinions__attr strong { color: var(--md-default-fg-color); }\n.fastapi-opinions__attr a {\n  color: var(--md-primary-fg-color);\n  text-decoration: none;\n  font-size: 0.75rem;\n  margin-left: 0.25rem;\n}\n.fastapi-opinions__attr a:hover { text-decoration: underline; }\n\n@media (prefers-reduced-motion: reduce) {\n  .fastapi-opinions__tab::after { transition: none; }\n}\n\n@media (max-width: 600px) {\n  .fastapi-opinions__tabs { gap: 0.125rem; }\n  .fastapi-opinions__mark { height: 18px; }\n  .fastapi-opinions__panel { padding-left: 2.25rem; }\n  .fastapi-opinions__panel::before { font-size: 3rem; }\n}\n\n.fastapi-sponsors {\n  display: flex;\n  flex-wrap: wrap;\n  justify-content: center;\n  align-items: center;\n  gap: 1rem 1.25rem;\n  margin: 1rem 0 2rem;\n}\n\n.fastapi-sponsors__card {\n  transition: transform 0.15s ease;\n}\n\n.fastapi-sponsors__card:hover {\n  transform: translateY(-1px);\n}\n\n.fastapi-sponsors__card--keystone {\n  width: 100%;\n  max-width: 560px;\n}\n\n.fastapi-sponsors__banner {\n  display: block;\n  border-radius: 12px;\n}\n\n.fastapi-sponsors__card--keystone .fastapi-sponsors__banner { width: 100%; }\n.fastapi-sponsors__card--gold     .fastapi-sponsors__banner { height: 80px; }\n.fastapi-sponsors__card--silver   .fastapi-sponsors__banner { height: 60px; }\n\n@media (max-width: 600px) {\n  .fastapi-sponsors__card--gold   .fastapi-sponsors__banner { height: 64px; }\n  .fastapi-sponsors__card--silver .fastapi-sponsors__banner { height: 50px; }\n}\n\n.fastapi-feature-banner {\n  display: block;\n  max-width: 680px;\n  margin: 1rem auto 1.5rem;\n}\n.fastapi-feature-banner img {\n  display: block;\n  width: 100%;\n  border-radius: 12px;\n}\n\n/* Hidden in MkDocs; rendered on GitHub (which doesn't load this stylesheet) */\n.only-github { display: none; }\n"
  },
  {
    "path": "docs/en/docs/css/termynal.css",
    "content": "/**\n * termynal.js\n *\n * @author Ines Montani <ines@ines.io>\n * @version 0.0.1\n * @license MIT\n */\n\n:root {\n    --color-bg: #252a33;\n    --color-text: #eee;\n    --color-text-subtle: #a2a2a2;\n}\n\n[data-termynal] {\n    width: 750px;\n    max-width: 100%;\n    background: var(--color-bg);\n    color: var(--color-text);\n    /* font-size: 18px; */\n    font-size: 15px;\n    /* font-family: 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace; */\n    font-family: var(--md-code-font-family), 'Roboto Mono', 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace;\n    border-radius: 4px;\n    padding: 75px 45px 35px;\n    position: relative;\n    -webkit-box-sizing: border-box;\n            box-sizing: border-box;\n    /* Custom line-height */\n    line-height: 1.2;\n}\n\n[data-termynal]:before {\n    content: '';\n    position: absolute;\n    top: 15px;\n    left: 15px;\n    display: inline-block;\n    width: 15px;\n    height: 15px;\n    border-radius: 50%;\n    /* A little hack to display the window buttons in one pseudo element. */\n    background: #d9515d;\n    -webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;\n            box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930;\n}\n\n[data-termynal]:after {\n    content: 'bash';\n    position: absolute;\n    color: var(--color-text-subtle);\n    top: 5px;\n    left: 0;\n    width: 100%;\n    text-align: center;\n}\n\na[data-terminal-control] {\n    text-align: right;\n    display: block;\n    color: #aebbff;\n}\n\n[data-ty] {\n    display: block;\n    line-height: 2;\n}\n\n[data-ty]:before {\n    /* Set up defaults and ensure empty lines are displayed. */\n    content: '';\n    display: inline-block;\n    vertical-align: middle;\n}\n\n[data-ty=\"input\"]:before,\n[data-ty-prompt]:before {\n    margin-right: 0.75em;\n    color: var(--color-text-subtle);\n}\n\n[data-ty=\"input\"]:before {\n    content: '$';\n}\n\n[data-ty][data-ty-prompt]:before {\n    content: attr(data-ty-prompt);\n}\n\n[data-ty-cursor]:after {\n    content: attr(data-ty-cursor);\n    font-family: monospace;\n    margin-left: 0.5em;\n    -webkit-animation: blink 1s infinite;\n            animation: blink 1s infinite;\n}\n\n\n/* Cursor animation */\n\n@-webkit-keyframes blink {\n    50% {\n        opacity: 0;\n    }\n}\n\n@keyframes blink {\n    50% {\n        opacity: 0;\n    }\n}\n"
  },
  {
    "path": "docs/en/docs/deployment/cloud.md",
    "content": "# Deploy FastAPI on Cloud Providers { #deploy-fastapi-on-cloud-providers }\n\nYou can use virtually **any cloud provider** to deploy your FastAPI application.\n\nIn most of the cases, the main cloud providers have guides to deploy FastAPI with them.\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** is built by the same author and team behind **FastAPI**.\n\nIt streamlines the process of **building**, **deploying**, and **accessing** an API with minimal effort.\n\nIt brings the same **developer experience** of building apps with FastAPI to **deploying** them to the cloud. 🎉\n\nFastAPI Cloud is the primary sponsor and funding provider for the *FastAPI and friends* open source projects. ✨\n\n## Cloud Providers - Sponsors { #cloud-providers-sponsors }\n\nSome other cloud providers ✨ [**sponsor FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ too. 🙇\n\nYou might also want to consider them to follow their guides and try their services:\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/en/docs/deployment/concepts.md",
    "content": "# Deployments Concepts { #deployments-concepts }\n\nWhen deploying a **FastAPI** application, or actually, any type of web API, there are several concepts that you probably care about, and using them you can find the **most appropriate** way to **deploy your application**.\n\nSome of the important concepts are:\n\n* Security - HTTPS\n* Running on startup\n* Restarts\n* Replication (the number of processes running)\n* Memory\n* Previous steps before starting\n\nWe'll see how they would affect **deployments**.\n\nIn the end, the ultimate objective is to be able to **serve your API clients** in a way that is **secure**, to **avoid disruptions**, and to use the **compute resources** (for example remote servers/virtual machines) as efficiently as possible. 🚀\n\nI'll tell you a bit more about these **concepts** here, and that would hopefully give you the **intuition** you would need to decide how to deploy your API in very different environments, possibly even in **future** ones that don't exist yet.\n\nBy considering these concepts, you will be able to **evaluate and design** the best way to deploy **your own APIs**.\n\nIn the next chapters, I'll give you more **concrete recipes** to deploy FastAPI applications.\n\nBut for now, let's check these important **conceptual ideas**. These concepts also apply to any other type of web API. 💡\n\n## Security - HTTPS { #security-https }\n\nIn the [previous chapter about HTTPS](https.md) we learned about how HTTPS provides encryption for your API.\n\nWe also saw that HTTPS is normally provided by a component **external** to your application server, a **TLS Termination Proxy**.\n\nAnd there has to be something in charge of **renewing the HTTPS certificates**, it could be the same component or it could be something different.\n\n### Example Tools for HTTPS { #example-tools-for-https }\n\nSome of the tools you could use as a TLS Termination Proxy are:\n\n* Traefik\n    * Automatically handles certificates renewals ✨\n* Caddy\n    * Automatically handles certificates renewals ✨\n* Nginx\n    * With an external component like Certbot for certificate renewals\n* HAProxy\n    * With an external component like Certbot for certificate renewals\n* Kubernetes with an Ingress Controller like Nginx\n    * With an external component like cert-manager for certificate renewals\n* Handled internally by a cloud provider as part of their services (read below 👇)\n\nAnother option is that you could use a **cloud service** that does more of the work including setting up HTTPS. It could have some restrictions or charge you more, etc. But in that case, you wouldn't have to set up a TLS Termination Proxy yourself.\n\nI'll show you some concrete examples in the next chapters.\n\n---\n\nThen the next concepts to consider are all about the program running your actual API (e.g. Uvicorn).\n\n## Program and Process { #program-and-process }\n\nWe will talk a lot about the running \"**process**\", so it's useful to have clarity about what it means, and what's the difference with the word \"**program**\".\n\n### What is a Program { #what-is-a-program }\n\nThe word **program** is commonly used to describe many things:\n\n* The **code** that you write, the **Python files**.\n* The **file** that can be **executed** by the operating system, for example: `python`, `python.exe` or `uvicorn`.\n* A particular program while it is **running** on the operating system, using the CPU, and storing things in memory. This is also called a **process**.\n\n### What is a Process { #what-is-a-process }\n\nThe word **process** is normally used in a more specific way, only referring to the thing that is running in the operating system (like in the last point above):\n\n* A particular program while it is **running** on the operating system.\n    * This doesn't refer to the file, nor to the code, it refers **specifically** to the thing that is being **executed** and managed by the operating system.\n* Any program, any code, **can only do things** when it is being **executed**. So, when there's a **process running**.\n* The process can be **terminated** (or \"killed\") by you, or by the operating system. At that point, it stops running/being executed, and it can **no longer do things**.\n* Each application that you have running on your computer has some process behind it, each running program, each window, etc. And there are normally many processes running **at the same time** while a computer is on.\n* There can be **multiple processes** of the **same program** running at the same time.\n\nIf you check out the \"task manager\" or \"system monitor\" (or similar tools) in your operating system, you will be able to see many of those processes running.\n\nAnd, for example, you will probably see that there are multiple processes running the same browser program (Firefox, Chrome, Edge, etc). They normally run one process per tab, plus some other extra processes.\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\nNow that we know the difference between the terms **process** and **program**, let's continue talking about deployments.\n\n## Running on Startup { #running-on-startup }\n\nIn most cases, when you create a web API, you want it to be **always running**, uninterrupted, so that your clients can always access it. This is of course, unless you have a specific reason why you want it to run only in certain situations, but most of the time you want it constantly running and **available**.\n\n### In a Remote Server { #in-a-remote-server }\n\nWhen you set up a remote server (a cloud server, a virtual machine, etc.) the simplest thing you can do is use `fastapi run` (which uses Uvicorn) or something  similar, manually, the same way you do when developing locally.\n\nAnd it will work and will be useful **during development**.\n\nBut if your connection to the server is lost, the **running process** will probably die.\n\nAnd if the server is restarted (for example after updates, or migrations from the cloud provider) you probably **won't notice it**. And because of that, you won't even know that you have to restart the process manually. So, your API will just stay dead. 😱\n\n### Run Automatically on Startup { #run-automatically-on-startup }\n\nIn general, you will probably want the server program (e.g. Uvicorn) to be started automatically on server startup, and without needing any **human intervention**, to have a process always running with your API (e.g. Uvicorn running your FastAPI app).\n\n### Separate Program { #separate-program }\n\nTo achieve this, you will normally have a **separate program** that would make sure your application is run on startup. And in many cases, it would also make sure other components or applications are also run, for example, a database.\n\n### Example Tools to Run at Startup { #example-tools-to-run-at-startup }\n\nSome examples of the tools that can do this job are:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker in Swarm Mode\n* Systemd\n* Supervisor\n* Handled internally by a cloud provider as part of their services\n* Others...\n\nI'll give you more concrete examples in the next chapters.\n\n## Restarts { #restarts }\n\nSimilar to making sure your application is run on startup, you probably also want to make sure it is **restarted** after failures.\n\n### We Make Mistakes { #we-make-mistakes }\n\nWe, as humans, make **mistakes**, all the time. Software almost *always* has **bugs** hidden in different places. 🐛\n\nAnd we as developers keep improving the code as we find those bugs and as we implement new features (possibly adding new bugs too 😅).\n\n### Small Errors Automatically Handled { #small-errors-automatically-handled }\n\nWhen building web APIs with FastAPI, if there's an error in our code, FastAPI will normally contain it to the single request that triggered the error. 🛡\n\nThe client will get a **500 Internal Server Error** for that request, but the application will continue working for the next requests instead of just crashing completely.\n\n### Bigger Errors - Crashes { #bigger-errors-crashes }\n\nNevertheless, there might be cases where we write some code that **crashes the entire application** making Uvicorn and Python crash. 💥\n\nAnd still, you would probably not want the application to stay dead because there was an error in one place, you probably want it to **continue running** at least for the *path operations* that are not broken.\n\n### Restart After Crash { #restart-after-crash }\n\nBut in those cases with really bad errors that crash the running **process**, you would want an external component that is in charge of **restarting** the process, at least a couple of times...\n\n/// tip\n\n...Although if the whole application is just **crashing immediately** it probably doesn't make sense to keep restarting it forever. But in those cases, you will probably notice it during development, or at least right after deployment.\n\nSo let's focus on the main cases, where it could crash entirely in some particular cases **in the future**, and it still makes sense to restart it.\n\n///\n\nYou would probably want to have the thing in charge of restarting your application as an **external component**, because by that point, the same application with Uvicorn and Python already crashed, so there's nothing in the same code of the same app that could do anything about it.\n\n### Example Tools to Restart Automatically { #example-tools-to-restart-automatically }\n\nIn most cases, the same tool that is used to **run the program on startup** is also used to handle automatic **restarts**.\n\nFor example, this could be handled by:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker in Swarm Mode\n* Systemd\n* Supervisor\n* Handled internally by a cloud provider as part of their services\n* Others...\n\n## Replication - Processes and Memory { #replication-processes-and-memory }\n\nWith a FastAPI application, using a server program like the `fastapi` command that runs Uvicorn, running it once in **one process** can serve multiple clients concurrently.\n\nBut in many cases, you will want to run several worker processes at the same time.\n\n### Multiple Processes - Workers { #multiple-processes-workers }\n\nIf you have more clients than what a single process can handle (for example if the virtual machine is not too big) and you have **multiple cores** in the server's CPU, then you could have **multiple processes** running with the same application at the same time, and distribute all the requests among them.\n\nWhen you run **multiple processes** of the same API program, they are commonly called **workers**.\n\n### Worker Processes and Ports { #worker-processes-and-ports }\n\nRemember from the docs [About HTTPS](https.md) that only one process can be listening on one combination of port and IP address in a server?\n\nThis is still true.\n\nSo, to be able to have **multiple processes** at the same time, there has to be a **single process listening on a port** that then transmits the communication to each worker process in some way.\n\n### Memory per Process { #memory-per-process }\n\nNow, when the program loads things in memory, for example, a machine learning model in a variable, or the contents of a large file in a variable, all that **consumes a bit of the memory (RAM)** of the server.\n\nAnd multiple processes normally **don't share any memory**. This means that each running process has its own things, variables, and memory. And if you are consuming a large amount of memory in your code, **each process** will consume an equivalent amount of memory.\n\n### Server Memory { #server-memory }\n\nFor example, if your code loads a Machine Learning model with **1 GB in size**, when you run one process with your API, it will consume at least 1 GB of RAM. And if you start **4 processes** (4 workers), each will consume 1 GB of RAM. So in total, your API will consume **4 GB of RAM**.\n\nAnd if your remote server or virtual machine only has 3 GB of RAM, trying to load more than 4 GB of RAM will cause problems. 🚨\n\n### Multiple Processes - An Example { #multiple-processes-an-example }\n\nIn this example, there's a **Manager Process** that starts and controls two **Worker Processes**.\n\nThis Manager Process would probably be the one listening on the **port** in the IP. And it would transmit all the communication to the worker processes.\n\nThose worker processes would be the ones running your application, they would perform the main computations to receive a **request** and return a **response**, and they would load anything you put in variables in RAM.\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\nAnd of course, the same machine would probably have **other processes** running as well, apart from your application.\n\nAn interesting detail is that the percentage of the **CPU used** by each process can **vary** a lot over time, but the **memory (RAM)** normally stays more or less **stable**.\n\nIf you have an API that does a comparable amount of computations every time and you have a lot of clients, then the **CPU utilization** will probably *also be stable* (instead of constantly going up and down quickly).\n\n### Examples of Replication Tools and Strategies { #examples-of-replication-tools-and-strategies }\n\nThere can be several approaches to achieve this, and I'll tell you more about specific strategies in the next chapters, for example when talking about Docker and containers.\n\nThe main constraint to consider is that there has to be a **single** component handling the **port** in the **public IP**. And then it has to have a way to **transmit** the communication to the replicated **processes/workers**.\n\nHere are some possible combinations and strategies:\n\n* **Uvicorn** with `--workers`\n    * One Uvicorn **process manager** would listen on the **IP** and **port**, and it would start **multiple Uvicorn worker processes**.\n* **Kubernetes** and other distributed **container systems**\n    * Something in the **Kubernetes** layer would listen on the **IP** and **port**. The replication would be by having **multiple containers**, each with **one Uvicorn process** running.\n* **Cloud services** that handle this for you\n    * The cloud service will probably **handle replication for you**. It would possibly let you define **a process to run**, or a **container image** to use, in any case, it would most probably be **a single Uvicorn process**, and the cloud service would be in charge of replicating it.\n\n/// tip\n\nDon't worry if some of these items about **containers**, Docker, or Kubernetes don't make a lot of sense yet.\n\nI'll tell you more about container images, Docker, Kubernetes, etc. in a future chapter: [FastAPI in Containers - Docker](docker.md).\n\n///\n\n## Previous Steps Before Starting { #previous-steps-before-starting }\n\nThere are many cases where you want to perform some steps **before starting** your application.\n\nFor example, you might want to run **database migrations**.\n\nBut in most cases, you will want to perform these steps only **once**.\n\nSo, you will want to have a **single process** to perform those **previous steps**, before starting the application.\n\nAnd you will have to make sure that it's a single process running those previous steps *even* if afterwards, you start **multiple processes** (multiple workers) for the application itself. If those steps were run by **multiple processes**, they would **duplicate** the work by running it in **parallel**, and if the steps were something delicate like a database migration, they could cause conflicts with each other.\n\nOf course, there are some cases where there's no problem in running the previous steps multiple times, in that case, it's a lot easier to handle.\n\n/// tip\n\nAlso, keep in mind that depending on your setup, in some cases you **might not even need any previous steps** before starting your application.\n\nIn that case, you wouldn't have to worry about any of this. 🤷\n\n///\n\n### Examples of Previous Steps Strategies { #examples-of-previous-steps-strategies }\n\nThis will **depend heavily** on the way you **deploy your system**, and it would probably be connected to the way you start programs, handling restarts, etc.\n\nHere are some possible ideas:\n\n* An \"Init Container\" in Kubernetes that runs before your app container\n* A bash script that runs the previous steps and then starts your application\n    * You would still need a way to start/restart *that* bash script, detect errors, etc.\n\n/// tip\n\nI'll give you more concrete examples for doing this with containers in a future chapter: [FastAPI in Containers - Docker](docker.md).\n\n///\n\n## Resource Utilization { #resource-utilization }\n\nYour server(s) is (are) a **resource**, you can consume or **utilize**, with your programs, the computation time on the CPUs, and the RAM memory available.\n\nHow much of the system resources do you want to be consuming/utilizing? It might be easy to think \"not much\", but in reality, you will probably want to consume **as much as possible without crashing**.\n\nIf you are paying for 3 servers but you are using only a little bit of their RAM and CPU, you are probably **wasting money** 💸, and probably **wasting server electric power** 🌎, etc.\n\nIn that case, it could be better to have only 2 servers and use a higher percentage of their resources (CPU, memory, disk, network bandwidth, etc).\n\nOn the other hand, if you have 2 servers and you are using **100% of their CPU and RAM**, at some point one process will ask for more memory, and the server will have to use the disk as \"memory\" (which can be thousands of times slower), or even **crash**. Or one process might need to do some computation and would have to wait until the CPU is free again.\n\nIn this case, it would be better to get **one extra server** and run some processes on it so that they all have **enough RAM and CPU time**.\n\nThere's also the chance that for some reason you have a **spike** of usage of your API. Maybe it went viral, or maybe some other services or bots start using it. And you might want to have extra resources to be safe in those cases.\n\nYou could put an **arbitrary number** to target, for example, something **between 50% to 90%** of resource utilization. The point is that those are probably the main things you will want to measure and use to tweak your deployments.\n\nYou can use simple tools like `htop` to see the CPU and RAM used in your server or the amount used by each process. Or you can use more complex monitoring tools, which may be distributed across servers, etc.\n\n## Recap { #recap }\n\nYou have been reading here some of the main concepts that you would probably need to keep in mind when deciding how to deploy your application:\n\n* Security - HTTPS\n* Running on startup\n* Restarts\n* Replication (the number of processes running)\n* Memory\n* Previous steps before starting\n\nUnderstanding these ideas and how to apply them should give you the intuition necessary to take any decisions when configuring and tweaking your deployments. 🤓\n\nIn the next sections, I'll give you more concrete examples of possible strategies you can follow. 🚀\n"
  },
  {
    "path": "docs/en/docs/deployment/docker.md",
    "content": "# FastAPI in Containers - Docker { #fastapi-in-containers-docker }\n\nWhen deploying FastAPI applications a common approach is to build a **Linux container image**. It's normally done using [**Docker**](https://www.docker.com/). You can then deploy that container image in one of a few possible ways.\n\nUsing Linux containers has several advantages including **security**, **replicability**, **simplicity**, and others.\n\n/// tip\n\nIn a hurry and already know this stuff? Jump to the [`Dockerfile` below 👇](#build-a-docker-image-for-fastapi).\n\n///\n\n<details>\n<summary>Dockerfile Preview 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# If running behind a proxy like Nginx or Traefik add --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## What is a Container { #what-is-a-container }\n\nContainers (mainly Linux containers) are a very **lightweight** way to package applications including all their dependencies and necessary files while keeping them isolated from other containers (other applications or components) in the same system.\n\nLinux containers run using the same Linux kernel of the host (machine, virtual machine, cloud server, etc). This just means that they are very lightweight (compared to full virtual machines emulating an entire operating system).\n\nThis way, containers consume **little resources**, an amount comparable to running the processes directly (a virtual machine would consume much more).\n\nContainers also have their own **isolated** running processes (commonly just one process), file system, and network, simplifying deployment, security, development, etc.\n\n## What is a Container Image { #what-is-a-container-image }\n\nA **container** is run from a **container image**.\n\nA container image is a **static** version of all the files, environment variables, and the default command/program that should be present in a container. **Static** here means that the container **image** is not running, it's not being executed, it's only the packaged files and metadata.\n\nIn contrast to a \"**container image**\" that is the stored static contents, a \"**container**\" normally refers to the running instance, the thing that is being **executed**.\n\nWhen the **container** is started and running (started from a **container image**) it could create or change files, environment variables, etc. Those changes will exist only in that container, but would not persist in the underlying container image (would not be saved to disk).\n\nA container image is comparable to the **program** file and contents, e.g. `python` and some file `main.py`.\n\nAnd the **container** itself (in contrast to the **container image**) is the actual running instance of the image, comparable to a **process**. In fact, a container is running only when it has a **process running** (and normally it's only a single process). The container stops when there's no process running in it.\n\n## Container Images { #container-images }\n\nDocker has been one of the main tools to create and manage **container images** and **containers**.\n\nAnd there's a public [Docker Hub](https://hub.docker.com/) with pre-made **official container images** for many tools, environments, databases, and applications.\n\nFor example, there's an official [Python Image](https://hub.docker.com/_/python).\n\nAnd there are many other images for different things like databases, for example for:\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis), etc.\n\nBy using a pre-made container image it's very easy to **combine** and use different tools. For example, to try out a new database. In most cases, you can use the **official images**, and just configure them with environment variables.\n\nThat way, in many cases you can learn about containers and Docker and reuse that knowledge with many different tools and components.\n\nSo, you would run **multiple containers** with different things, like a database, a Python application, a web server with a React frontend application, and connect them together via their internal network.\n\nAll the container management systems (like Docker or Kubernetes) have these networking features integrated into them.\n\n## Containers and Processes { #containers-and-processes }\n\nA **container image** normally includes in its metadata the default program or command that should be run when the **container** is started and the parameters to be passed to that program. Very similar to what would be if it was in the command line.\n\nWhen a **container** is started, it will run that command/program (although you can override it and make it run a different command/program).\n\nA container is running as long as the **main process** (command or program) is running.\n\nA container normally has a **single process**, but it's also possible to start subprocesses from the main process, and that way you will have **multiple processes** in the same container.\n\nBut it's not possible to have a running container without **at least one running process**. If the main process stops, the container stops.\n\n## Build a Docker Image for FastAPI { #build-a-docker-image-for-fastapi }\n\nOkay, let's build something now! 🚀\n\nI'll show you how to build a **Docker image** for FastAPI **from scratch**, based on the **official Python** image.\n\nThis is what you would want to do in **most cases**, for example:\n\n* Using **Kubernetes** or similar tools\n* When running on a **Raspberry Pi**\n* Using a cloud service that would run a container image for you, etc.\n\n### Package Requirements { #package-requirements }\n\nYou would normally have the **package requirements** for your application in some file.\n\nIt would depend mainly on the tool you use to **install** those requirements.\n\nThe most common way to do it is to have a file `requirements.txt` with the package names and their versions, one per line.\n\nYou would of course use the same ideas you read in [About FastAPI versions](versions.md) to set the ranges of versions.\n\nFor example, your `requirements.txt` could look like:\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\nAnd you would normally install those package dependencies with `pip`, for example:\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info\n\nThere are other formats and tools to define and install package dependencies.\n\n///\n\n### Create the **FastAPI** Code { #create-the-fastapi-code }\n\n* Create an `app` directory and enter it.\n* Create an empty file `__init__.py`.\n* Create a `main.py` file with:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\nNow in the same project directory create a file `Dockerfile` with:\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. Start from the official Python base image.\n\n2. Set the current working directory to `/code`.\n\n    This is where we'll put the `requirements.txt` file and the `app` directory.\n\n3. Copy the file with the requirements to the `/code` directory.\n\n    Copy **only** the file with the requirements first, not the rest of the code.\n\n    As this file **doesn't change often**, Docker will detect it and use the **cache** for this step, enabling the cache for the next step too.\n\n4. Install the package dependencies in the requirements file.\n\n    The `--no-cache-dir` option tells `pip` to not save the downloaded packages locally, as that is only if `pip` was going to be run again to install the same packages, but that's not the case when working with containers.\n\n    /// note\n\n    The `--no-cache-dir` is only related to `pip`, it has nothing to do with Docker or containers.\n\n    ///\n\n    The `--upgrade` option tells `pip` to upgrade the packages if they are already installed.\n\n    Because the previous step copying the file could be detected by the **Docker cache**, this step will also **use the Docker cache** when available.\n\n    Using the cache in this step will **save** you a lot of **time** when building the image again and again during development, instead of **downloading and installing** all the dependencies **every time**.\n\n5. Copy the `./app` directory inside the `/code` directory.\n\n    As this has all the code which is what **changes most frequently** the Docker **cache** won't be used for this or any **following steps** easily.\n\n    So, it's important to put this **near the end** of the `Dockerfile`, to optimize the container image build times.\n\n6. Set the **command** to use `fastapi run`, which uses Uvicorn underneath.\n\n    `CMD` takes a list of strings, each of these strings is what you would type in the command line separated by spaces.\n\n    This command will be run from the **current working directory**, the same `/code` directory you set above with `WORKDIR /code`.\n\n/// tip\n\nReview what each line does by clicking each number bubble in the code. 👆\n\n///\n\n/// warning\n\nMake sure to **always** use the **exec form** of the `CMD` instruction, as explained below.\n\n///\n\n#### Use `CMD` - Exec Form { #use-cmd-exec-form }\n\nThe [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) Docker instruction can be written using two forms:\n\n✅ **Exec** form:\n\n```Dockerfile\n# ✅ Do this\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ **Shell** form:\n\n```Dockerfile\n# ⛔️ Don't do this\nCMD fastapi run app/main.py --port 80\n```\n\nMake sure to always use the **exec** form to ensure that FastAPI can shutdown gracefully and [lifespan events](../advanced/events.md) are triggered.\n\nYou can read more about it in the [Docker docs for shell and exec form](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).\n\nThis can be quite noticeable when using `docker compose`. See this Docker Compose FAQ section for more technical details: [Why do my services take 10 seconds to recreate or stop?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).\n\n#### Directory Structure { #directory-structure }\n\nYou should now have a directory structure like:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### Behind a TLS Termination Proxy { #behind-a-tls-termination-proxy }\n\nIf you are running your container behind a TLS Termination Proxy (load balancer) like Nginx or Traefik, add the option `--proxy-headers`, this will tell Uvicorn (through the FastAPI CLI) to trust the headers sent by that proxy telling it that the application is running behind HTTPS, etc.\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Docker Cache { #docker-cache }\n\nThere's an important trick in this `Dockerfile`, we first copy the **file with the dependencies alone**, not the rest of the code. Let me tell you why is that.\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker and other tools **build** these container images **incrementally**, adding **one layer on top of the other**, starting from the top of the `Dockerfile` and adding any files created by each of the instructions of the `Dockerfile`.\n\nDocker and similar tools also use an **internal cache** when building the image, if a file hasn't changed since the last time building the container image, then it will **reuse the same layer** created the last time, instead of copying the file again and creating a new layer from scratch.\n\nJust avoiding the copy of files doesn't necessarily improve things too much, but because it used the cache for that step, it can **use the cache for the next step**. For example, it could use the cache for the instruction that installs dependencies with:\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\nThe file with the package requirements **won't change frequently**. So, by copying only that file, Docker will be able to **use the cache** for that step.\n\nAnd then, Docker will be able to **use the cache for the next step** that downloads and install those dependencies. And here's where we **save a lot of time**. ✨ ...and avoid boredom waiting. 😪😆\n\nDownloading and installing the package dependencies **could take minutes**, but using the **cache** would **take seconds** at most.\n\nAnd as you would be building the container image again and again during development to check that your code changes are working, there's a lot of accumulated time this would save.\n\nThen, near the end of the `Dockerfile`, we copy all the code. As this is what **changes most frequently**, we put it near the end, because almost always, anything after this step will not be able to use the cache.\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### Build the Docker Image { #build-the-docker-image }\n\nNow that all the files are in place, let's build the container image.\n\n* Go to the project directory (in where your `Dockerfile` is, containing your `app` directory).\n* Build your FastAPI image:\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip\n\nNotice the `.` at the end, it's equivalent to `./`, it tells Docker the directory to use to build the container image.\n\nIn this case, it's the same current directory (`.`).\n\n///\n\n### Start the Docker Container { #start-the-docker-container }\n\n* Run a container based on your image:\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## Check it { #check-it }\n\nYou should be able to check it in your Docker container's URL, for example: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) or [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (or equivalent, using your Docker host).\n\nYou will see something like:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## Interactive API docs { #interactive-api-docs }\n\nNow you can go to [http://192.168.99.100/docs](http://192.168.99.100/docs) or [http://127.0.0.1/docs](http://127.0.0.1/docs) (or equivalent, using your Docker host).\n\nYou will see the automatic interactive API documentation (provided by [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## Alternative API docs { #alternative-api-docs }\n\nAnd you can also go to [http://192.168.99.100/redoc](http://192.168.99.100/redoc) or [http://127.0.0.1/redoc](http://127.0.0.1/redoc) (or equivalent, using your Docker host).\n\nYou will see the alternative automatic documentation (provided by [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Build a Docker Image with a Single-File FastAPI { #build-a-docker-image-with-a-single-file-fastapi }\n\nIf your FastAPI is a single file, for example, `main.py` without an `./app` directory, your file structure could look like this:\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\nThen you would just have to change the corresponding paths to copy the file inside the `Dockerfile`:\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. Copy the `main.py` file to the `/code` directory directly (without any `./app` directory).\n\n2. Use `fastapi run` to serve your application in the single file `main.py`.\n\nWhen you pass the file to `fastapi run` it will detect automatically that it is a single file and not part of a package and will know how to import it and serve your FastAPI app. 😎\n\n## Deployment Concepts { #deployment-concepts }\n\nLet's talk again about some of the same [Deployment Concepts](concepts.md) in terms of containers.\n\nContainers are mainly a tool to simplify the process of **building and deploying** an application, but they don't enforce a particular approach to handle these **deployment concepts**, and there are several possible strategies.\n\nThe **good news** is that with each different strategy there's a way to cover all of the deployment concepts. 🎉\n\nLet's review these **deployment concepts** in terms of containers:\n\n* HTTPS\n* Running on startup\n* Restarts\n* Replication (the number of processes running)\n* Memory\n* Previous steps before starting\n\n## HTTPS { #https }\n\nIf we focus just on the **container image** for a FastAPI application (and later the running **container**), HTTPS normally would be handled **externally** by another tool.\n\nIt could be another container, for example with [Traefik](https://traefik.io/), handling **HTTPS** and **automatic** acquisition of **certificates**.\n\n/// tip\n\nTraefik has integrations with Docker, Kubernetes, and others, so it's very easy to set up and configure HTTPS for your containers with it.\n\n///\n\nAlternatively, HTTPS could be handled by a cloud provider as one of their services (while still running the application in a container).\n\n## Running on Startup and Restarts { #running-on-startup-and-restarts }\n\nThere is normally another tool in charge of **starting and running** your container.\n\nIt could be **Docker** directly, **Docker Compose**, **Kubernetes**, a **cloud service**, etc.\n\nIn most (or all) cases, there's a simple option to enable running the container on startup and enabling restarts on failures. For example, in Docker, it's the command line option `--restart`.\n\nWithout using containers, making applications run on startup and with restarts can be cumbersome and difficult. But when **working with containers** in most cases that functionality is included by default. ✨\n\n## Replication - Number of Processes { #replication-number-of-processes }\n\nIf you have a <dfn title=\"A group of machines that are configured to be connected and work together in some way.\">cluster</dfn> of machines with **Kubernetes**, Docker Swarm Mode, Nomad, or another similar complex system to manage distributed containers on multiple machines, then you will probably want to **handle replication** at the **cluster level** instead of using a **process manager** (like Uvicorn with workers) in each container.\n\nOne of those distributed container management systems like Kubernetes normally has some integrated way of handling **replication of containers** while still supporting **load balancing** for the incoming requests. All at the **cluster level**.\n\nIn those cases, you would probably want to build a **Docker image from scratch** as [explained above](#dockerfile), installing your dependencies, and running **a single Uvicorn process** instead of using multiple Uvicorn workers.\n\n### Load Balancer { #load-balancer }\n\nWhen using containers, you would normally have some component **listening on the main port**. It could possibly be another container that is also a **TLS Termination Proxy** to handle **HTTPS** or some similar tool.\n\nAs this component would take the **load** of requests and distribute that among the workers in a (hopefully) **balanced** way, it is also commonly called a **Load Balancer**.\n\n/// tip\n\nThe same **TLS Termination Proxy** component used for HTTPS would probably also be a **Load Balancer**.\n\n///\n\nAnd when working with containers, the same system you use to start and manage them would already have internal tools to transmit the **network communication** (e.g. HTTP requests) from that **load balancer** (that could also be a **TLS Termination Proxy**) to the container(s) with your app.\n\n### One Load Balancer - Multiple Worker Containers { #one-load-balancer-multiple-worker-containers }\n\nWhen working with **Kubernetes** or similar distributed container management systems, using their internal networking mechanisms would allow the single **load balancer** that is listening on the main **port** to transmit communication (requests) to possibly **multiple containers** running your app.\n\nEach of these containers running your app would normally have **just one process** (e.g. a Uvicorn process running your FastAPI application). They would all be **identical containers**, running the same thing, but each with its own process, memory, etc. That way you would take advantage of **parallelization** in **different cores** of the CPU, or even in **different machines**.\n\nAnd the distributed container system with the **load balancer** would **distribute the requests** to each one of the containers with your app **in turns**. So, each request could be handled by one of the multiple **replicated containers** running your app.\n\nAnd normally this **load balancer** would be able to handle requests that go to *other* apps in your cluster (e.g. to a different domain, or under a different URL path prefix), and would transmit that communication to the right containers for *that other* application running in your cluster.\n\n### One Process per Container { #one-process-per-container }\n\nIn this type of scenario, you probably would want to have **a single (Uvicorn) process per container**, as you would already be handling replication at the cluster level.\n\nSo, in this case, you **would not** want to have a multiple workers in the container, for example with the `--workers` command line option. You would want to have just a **single Uvicorn process** per container (but probably multiple containers).\n\nHaving another process manager inside the container (as would be with multiple workers) would only add **unnecessary complexity** that you are most probably already taking care of with your cluster system.\n\n### Containers with Multiple Processes and Special Cases { #containers-with-multiple-processes-and-special-cases }\n\nOf course, there are **special cases** where you could want to have **a container** with several **Uvicorn worker processes** inside.\n\nIn those cases, you can use the `--workers` command line option to set the number of workers that you want to run:\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. Here we use the `--workers` command line option to set the number of workers to 4.\n\nHere are some examples of when that could make sense:\n\n#### A Simple App { #a-simple-app }\n\nYou could want a process manager in the container if your application is **simple enough** that can run it on a **single server**, not a cluster.\n\n#### Docker Compose { #docker-compose }\n\nYou could be deploying to a **single server** (not a cluster) with **Docker Compose**, so you wouldn't have an easy way to manage replication of containers (with Docker Compose) while preserving the shared network and **load balancing**.\n\nThen you could want to have **a single container** with a **process manager** starting **several worker processes** inside.\n\n---\n\nThe main point is, **none** of these are **rules written in stone** that you have to blindly follow. You can use these ideas to **evaluate your own use case** and decide what is the best approach for your system, checking out how to manage the concepts of:\n\n* Security - HTTPS\n* Running on startup\n* Restarts\n* Replication (the number of processes running)\n* Memory\n* Previous steps before starting\n\n## Memory { #memory }\n\nIf you run **a single process per container** you will have a more or less well-defined, stable, and limited amount of memory consumed by each of those containers (more than one if they are replicated).\n\nAnd then you can set those same memory limits and requirements in your configurations for your container management system (for example in **Kubernetes**). That way it will be able to **replicate the containers** in the **available machines** taking into account the amount of memory needed by them, and the amount available in the machines in the cluster.\n\nIf your application is **simple**, this will probably **not be a problem**, and you might not need to specify hard memory limits. But if you are **using a lot of memory** (for example with **machine learning** models), you should check how much memory you are consuming and adjust the **number of containers** that runs in **each machine** (and maybe add more machines to your cluster).\n\nIf you run **multiple processes per container** you will have to make sure that the number of processes started doesn't **consume more memory** than what is available.\n\n## Previous Steps Before Starting and Containers { #previous-steps-before-starting-and-containers }\n\nIf you are using containers (e.g. Docker, Kubernetes), then there are two main approaches you can use.\n\n### Multiple Containers { #multiple-containers }\n\nIf you have **multiple containers**, probably each one running a **single process** (for example, in a **Kubernetes** cluster), then you would probably want to have a **separate container** doing the work of the **previous steps** in a single container, running a single process, **before** running the replicated worker containers.\n\n/// info\n\nIf you are using Kubernetes, this would probably be an [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).\n\n///\n\nIf in your use case there's no problem in running those previous steps **multiple times in parallel** (for example if you are not running database migrations, but just checking if the database is ready yet), then you could also just put them in each container right before starting the main process.\n\n### Single Container { #single-container }\n\nIf you have a simple setup, with a **single container** that then starts multiple **worker processes** (or also just one process), then you could run those previous steps in the same container, right before starting the process with the app.\n\n### Base Docker Image { #base-docker-image }\n\nThere used to be an official FastAPI Docker image: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). But it is now deprecated. ⛔️\n\nYou should probably **not** use this base Docker image (or any other similar one).\n\nIf you are using **Kubernetes** (or others) and you are already setting **replication** at the cluster level, with multiple **containers**. In those cases, you are better off **building an image from scratch** as described above: [Build a Docker Image for FastAPI](#build-a-docker-image-for-fastapi).\n\nAnd if you need to have multiple workers, you can simply use the `--workers` command line option.\n\n/// note | Technical Details\n\nThe Docker image was created when Uvicorn didn't support managing and restarting dead workers, so it was needed to use Gunicorn with Uvicorn, which added quite some complexity, just to have Gunicorn manage and restart the Uvicorn worker processes.\n\nBut now that Uvicorn (and the `fastapi` command) support using `--workers`, there's no reason to use a base Docker image instead of building your own (it's pretty much the same amount of code 😅).\n\n///\n\n## Deploy the Container Image { #deploy-the-container-image }\n\nAfter having a Container (Docker) Image there are several ways to deploy it.\n\nFor example:\n\n* With **Docker Compose** in a single server\n* With a **Kubernetes** cluster\n* With a Docker Swarm Mode cluster\n* With another tool like Nomad\n* With a cloud service that takes your container image and deploys it\n\n## Docker Image with `uv` { #docker-image-with-uv }\n\nIf you are using [uv](https://github.com/astral-sh/uv) to install and manage your project, you can follow their [uv Docker guide](https://docs.astral.sh/uv/guides/integration/docker/).\n\n## Recap { #recap }\n\nUsing container systems (e.g. with **Docker** and **Kubernetes**) it becomes fairly straightforward to handle all the **deployment concepts**:\n\n* HTTPS\n* Running on startup\n* Restarts\n* Replication (the number of processes running)\n* Memory\n* Previous steps before starting\n\nIn most cases, you probably won't want to use any base image, and instead **build a container image from scratch** based on the official Python Docker image.\n\nTaking care of the **order** of instructions in the `Dockerfile` and the **Docker cache** you can **minimize build times**, to maximize your productivity (and avoid boredom). 😎\n"
  },
  {
    "path": "docs/en/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\nYou can deploy your FastAPI app to [FastAPI Cloud](https://fastapicloud.com) with **one command**, go and join the waiting list if you haven't. 🚀\n\n## Login { #login }\n\nMake sure you already have a **FastAPI Cloud** account (we invited you from the waiting list 😉).\n\nThen log in:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## Deploy { #deploy }\n\nNow deploy your app, with **one command**:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nThat's it! Now you can access your app at that URL. ✨\n\n## About FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** is built by the same author and team behind **FastAPI**.\n\nIt streamlines the process of **building**, **deploying**, and **accessing** an API with minimal effort.\n\nIt brings the same **developer experience** of building apps with FastAPI to **deploying** them to the cloud. 🎉\n\nIt will also take care of most of the things you would need when deploying an app, like:\n\n* HTTPS\n* Replication, with autoscaling based on requests\n* etc.\n\nFastAPI Cloud is the primary sponsor and funding provider for the *FastAPI and friends* open source projects. ✨\n\n## Deploy to other cloud providers { #deploy-to-other-cloud-providers }\n\nFastAPI is open source and based on standards. You can deploy FastAPI apps to any cloud provider you choose.\n\nFollow your cloud provider's guides to deploy FastAPI apps with them. 🤓\n\n## Deploy your own server { #deploy-your-own-server }\n\nI will also teach you later in this **Deployment** guide all the details, so you can understand what is going on, what needs to happen, or how to deploy FastAPI apps on your own, also with your own servers. 🤓\n"
  },
  {
    "path": "docs/en/docs/deployment/https.md",
    "content": "# About HTTPS { #about-https }\n\nIt is easy to assume that HTTPS is something that is just \"enabled\" or not.\n\nBut it is way more complex than that.\n\n/// tip\n\nIf you are in a hurry or don't care, continue with the next sections for step by step instructions to set everything up with different techniques.\n\n///\n\nTo **learn the basics of HTTPS**, from a consumer perspective, check [https://howhttps.works/](https://howhttps.works/).\n\nNow, from a **developer's perspective**, here are several things to keep in mind while thinking about HTTPS:\n\n* For HTTPS, **the server** needs to **have \"certificates\"** generated by a **third party**.\n    * Those certificates are actually **acquired** from the third party, not \"generated\".\n* Certificates have a **lifetime**.\n    * They **expire**.\n    * And then they need to be **renewed**, **acquired again** from the third party.\n* The encryption of the connection happens at the **TCP level**.\n    * That's one layer **below HTTP**.\n    * So, the **certificate and encryption** handling is done **before HTTP**.\n* **TCP doesn't know about \"domains\"**. Only about IP addresses.\n    * The information about the **specific domain** requested goes in the **HTTP data**.\n* The **HTTPS certificates** \"certify\" a **certain domain**, but the protocol and encryption happen at the TCP level, **before knowing** which domain is being dealt with.\n* **By default**, that would mean that you can only have **one HTTPS certificate per IP address**.\n    * No matter how big your server is or how small each application you have on it might be.\n    * There is a **solution** to this, however.\n* There's an **extension** to the **TLS** protocol (the one handling the encryption at the TCP level, before HTTP) called **[<abbr title=\"Server Name Indication\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**.\n    * This SNI extension allows one single server (with a **single IP address**) to have **several HTTPS certificates** and serve **multiple HTTPS domains/applications**.\n    * For this to work, a **single** component (program) running on the server, listening on the **public IP address**, must have **all the HTTPS certificates** in the server.\n* **After** obtaining a secure connection, the communication protocol is **still HTTP**.\n    * The contents are **encrypted**, even though they are being sent with the **HTTP protocol**.\n\nIt is a common practice to have **one program/HTTP server** running on the server (the machine, host, etc.) and **managing all the HTTPS parts**: receiving the **encrypted HTTPS requests**, sending the **decrypted HTTP requests** to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the **HTTP response** from the application, **encrypt it** using the appropriate **HTTPS certificate** and sending it back to the client using **HTTPS**. This server is often called a **[TLS Termination Proxy](https://en.wikipedia.org/wiki/TLS_termination_proxy)**.\n\nSome of the options you could use as a TLS Termination Proxy are:\n\n* Traefik (that can also handle certificate renewals)\n* Caddy (that can also handle certificate renewals)\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\nBefore Let's Encrypt, these **HTTPS certificates** were sold by trusted third parties.\n\nThe process to acquire one of these certificates used to be cumbersome, require quite some paperwork and the certificates were quite expensive.\n\nBut then **[Let's Encrypt](https://letsencrypt.org/)** was created.\n\nIt is a project from the Linux Foundation. It provides **HTTPS certificates for free**, in an automated way. These certificates use all the standard cryptographic security, and are short-lived (about 3 months), so the **security is actually better** because of their reduced lifespan.\n\nThe domains are securely verified and the certificates are generated automatically. This also allows automating the renewal of these certificates.\n\nThe idea is to automate the acquisition and renewal of these certificates so that you can have **secure HTTPS, for free, forever**.\n\n## HTTPS for Developers { #https-for-developers }\n\nHere's an example of how an HTTPS API could look like, step by step, paying attention mainly to the ideas important for developers.\n\n### Domain Name { #domain-name }\n\nIt would probably all start by you **acquiring** some **domain name**. Then, you would configure it in a DNS server (possibly your same cloud provider).\n\nYou would probably get a cloud server (a virtual machine) or something similar, and it would have a <dfn title=\"Doesn't change over time. Not dynamic.\">fixed</dfn> **public IP address**.\n\nIn the DNS server(s) you would configure a record (an \"`A record`\") to point **your domain** to the public **IP address of your server**.\n\nYou would probably do this just once, the first time, when setting everything up.\n\n/// tip\n\nThis Domain Name part is way before HTTPS, but as everything depends on the domain and the IP address, it's worth mentioning it here.\n\n///\n\n### DNS { #dns }\n\nNow let's focus on all the actual HTTPS parts.\n\nFirst, the browser would check with the **DNS servers** what is the **IP for the domain**, in this case, `someapp.example.com`.\n\nThe DNS servers would tell the browser to use some specific **IP address**. That would be the public IP address used by your server, that you configured in the DNS servers.\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### TLS Handshake Start { #tls-handshake-start }\n\nThe browser would then communicate with that IP address on **port 443** (the HTTPS port).\n\nThe first part of the communication is just to establish the connection between the client and the server and to decide the cryptographic keys they will use, etc.\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\nThis interaction between the client and the server to establish the TLS connection is called the **TLS handshake**.\n\n### TLS with SNI Extension { #tls-with-sni-extension }\n\n**Only one process** in the server can be listening on a specific **port** in a specific **IP address**. There could be other processes listening on other ports in the same IP address, but only one for each combination of IP address and port.\n\nTLS (HTTPS) uses the specific port `443` by default. So that's the port we would need.\n\nAs only one process can be listening on this port, the process that would do it would be the **TLS Termination Proxy**.\n\nThe TLS Termination Proxy would have access to one or more **TLS certificates** (HTTPS certificates).\n\nUsing the **SNI extension** discussed above, the TLS Termination Proxy would check which of the TLS (HTTPS) certificates available it should use for this connection, using the one that matches the domain expected by the client.\n\nIn this case, it would use the certificate for `someapp.example.com`.\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\nThe client already **trusts** the entity that generated that TLS certificate (in this case Let's Encrypt, but we'll see about that later), so it can **verify** that the certificate is valid.\n\nThen, using the certificate, the client and the TLS Termination Proxy **decide how to encrypt** the rest of the **TCP communication**. This completes the **TLS Handshake** part.\n\nAfter this, the client and the server have an **encrypted TCP connection**, this is what TLS provides. And then they can use that connection to start the actual **HTTP communication**.\n\nAnd that's what **HTTPS** is, it's just plain **HTTP** inside a **secure TLS connection** instead of a pure (unencrypted) TCP connection.\n\n/// tip\n\nNotice that the encryption of the communication happens at the **TCP level**, not at the HTTP level.\n\n///\n\n### HTTPS Request { #https-request }\n\nNow that the client and server (specifically the browser and the TLS Termination Proxy) have an **encrypted TCP connection**, they can start the **HTTP communication**.\n\nSo, the client sends an **HTTPS request**. This is just an HTTP request through an encrypted TLS connection.\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### Decrypt the Request { #decrypt-the-request }\n\nThe TLS Termination Proxy would use the encryption agreed to **decrypt the request**, and would transmit the **plain (decrypted) HTTP request** to the process running the application (for example a process with Uvicorn running the FastAPI application).\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### HTTP Response { #http-response }\n\nThe application would process the request and send a **plain (unencrypted) HTTP response** to the TLS Termination Proxy.\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### HTTPS Response { #https-response }\n\nThe TLS Termination Proxy would then **encrypt the response** using the cryptography agreed before (that started with the certificate for `someapp.example.com`), and send it back to the browser.\n\nNext, the browser would verify that the response is valid and encrypted with the right cryptographic key, etc. It would then **decrypt the response** and process it.\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\nThe client (browser) will know that the response comes from the correct server because it is using the cryptography they agreed using the **HTTPS certificate** before.\n\n### Multiple Applications { #multiple-applications }\n\nIn the same server (or servers), there could be **multiple applications**, for example, other API programs or a database.\n\nOnly one process can be handling the specific IP and port (the TLS Termination Proxy in our example) but the other applications/processes can be running on the server(s) too, as long as they don't try to use the same **combination of public IP and port**.\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\nThat way, the TLS Termination Proxy could handle HTTPS and certificates for **multiple domains**, for multiple applications, and then transmit the requests to the right application in each case.\n\n### Certificate Renewal { #certificate-renewal }\n\nAt some point in the future, each certificate would **expire** (about 3 months after acquiring it).\n\nAnd then, there would be another program (in some cases it's another program, in some cases it could be the same TLS Termination Proxy) that would talk to Let's Encrypt, and renew the certificate(s).\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\nThe **TLS certificates** are **associated with a domain name**, not with an IP address.\n\nSo, to renew the certificates, the renewal program needs to **prove** to the authority (Let's Encrypt) that it indeed **\"owns\" and controls that domain**.\n\nTo do that, and to accommodate different application needs, there are several ways it can do it. Some popular ways are:\n\n* **Modify some DNS records**.\n    * For this, the renewal program needs to support the APIs of the DNS provider, so, depending on the DNS provider you are using, this might or might not be an option.\n* **Run as a server** (at least during the certificate acquisition process) on the public IP address associated with the domain.\n    * As we said above, only one process can be listening on a specific IP and port.\n    * This is one of the reasons why it's very useful when the same TLS Termination Proxy also takes care of the certificate renewal process.\n    * Otherwise, you might have to stop the TLS Termination Proxy momentarily, start the renewal program to acquire the certificates, then configure them with the TLS Termination Proxy, and then restart the TLS Termination Proxy. This is not ideal, as your app(s) will not be available during the time that the TLS Termination Proxy is off.\n\nAll this renewal process, while still serving the app, is one of the main reasons why you would want to have a **separate system to handle HTTPS** with a TLS Termination Proxy instead of just using the TLS certificates with the application server directly (e.g. Uvicorn).\n\n## Proxy Forwarded Headers { #proxy-forwarded-headers }\n\nWhen using a proxy to handle HTTPS, your **application server** (for example Uvicorn via FastAPI CLI) doesn't known anything about the HTTPS process, it communicates with plain HTTP with the **TLS Termination Proxy**.\n\nThis **proxy** would normally set some HTTP headers on the fly before transmitting the request to the **application server**, to let the application server know that the request is being **forwarded** by the proxy.\n\n/// note | Technical Details\n\nThe proxy headers are:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\nNevertheless, as the **application server** doesn't know it is behind a trusted **proxy**, by default, it wouldn't trust those headers.\n\nBut you can configure the **application server** to trust the *forwarded* headers sent by the **proxy**. If you are using FastAPI CLI, you can use the *CLI Option* `--forwarded-allow-ips` to tell it from which IPs it should trust those *forwarded* headers.\n\nFor example, if the **application server** is only receiving communication from the trusted **proxy**, you can set it to `--forwarded-allow-ips=\"*\"` to make it trust all incoming IPs, as it will only receive requests from whatever is the IP used by the **proxy**.\n\nThis way the application would be able to know what is its own public URL, if it is using HTTPS, the domain, etc.\n\nThis would be useful for example to properly handle redirects.\n\n/// tip\n\nYou can learn more about this in the documentation for [Behind a Proxy - Enable Proxy Forwarded Headers](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)\n\n///\n\n## Recap { #recap }\n\nHaving **HTTPS** is very important, and quite **critical** in most cases. Most of the effort you as a developer have to put around HTTPS is just about **understanding these concepts** and how they work.\n\nBut once you know the basic information of **HTTPS for developers** you can easily combine and configure different tools to help you manage everything in a simple way.\n\nIn some of the next chapters, I'll show you several concrete examples of how to set up **HTTPS** for **FastAPI** applications. 🔒\n"
  },
  {
    "path": "docs/en/docs/deployment/index.md",
    "content": "# Deployment { #deployment }\n\nDeploying a **FastAPI** application is relatively easy.\n\n## What Does Deployment Mean { #what-does-deployment-mean }\n\nTo **deploy** an application means to perform the necessary steps to make it **available to the users**.\n\nFor a **web API**, it normally involves putting it in a **remote machine**, with a **server program** that provides good performance, stability, etc, so that your **users** can **access** the application efficiently and without interruptions or problems.\n\nThis is in contrast to the **development** stages, where you are constantly changing the code, breaking it and fixing it, stopping and restarting the development server, etc.\n\n## Deployment Strategies { #deployment-strategies }\n\nThere are several ways to do it depending on your specific use case and the tools that you use.\n\nYou could **deploy a server** yourself using a combination of tools, you could use a **cloud service** that does part of the work for you, or other possible options.\n\nFor example, we, the team behind FastAPI, built [**FastAPI Cloud**](https://fastapicloud.com), to make deploying FastAPI apps to the cloud as streamlined as possible, with the same developer experience of working with FastAPI.\n\nI will show you some of the main concepts you should probably keep in mind when deploying a **FastAPI** application (although most of it applies to any other type of web application).\n\nYou will see more details to keep in mind and some of the techniques to do it in the next sections. ✨\n"
  },
  {
    "path": "docs/en/docs/deployment/manually.md",
    "content": "# Run a Server Manually { #run-a-server-manually }\n\n## Use the `fastapi run` Command { #use-the-fastapi-run-command }\n\nIn short, use `fastapi run` to serve your FastAPI application:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\nThat would work for most of the cases. 😎\n\nYou could use that command for example to start your **FastAPI** app in a container, in a server, etc.\n\n## ASGI Servers { #asgi-servers }\n\nLet's go a little deeper into the details.\n\nFastAPI uses a standard for building Python web frameworks and servers called <abbr title=\"Asynchronous Server Gateway Interface\">ASGI</abbr>. FastAPI is an ASGI web framework.\n\nThe main thing you need to run a **FastAPI** application (or any other ASGI application) in a remote server machine is an ASGI server program like **Uvicorn**, this is the one that comes by default in the `fastapi` command.\n\nThere are several alternatives, including:\n\n* [Uvicorn](https://www.uvicorn.dev/): a high performance ASGI server.\n* [Hypercorn](https://hypercorn.readthedocs.io/): an ASGI server compatible with HTTP/2 and Trio among other features.\n* [Daphne](https://github.com/django/daphne): the ASGI server built for Django Channels.\n* [Granian](https://github.com/emmett-framework/granian): A Rust HTTP server for Python applications.\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit is a lightweight and versatile web application runtime.\n\n## Server Machine and Server Program { #server-machine-and-server-program }\n\nThere's a small detail about names to keep in mind. 💡\n\nThe word \"**server**\" is commonly used to refer to both the remote/cloud computer (the physical or virtual machine) and also the program that is running on that machine (e.g. Uvicorn).\n\nJust keep in mind that when you read \"server\" in general, it could refer to one of those two things.\n\nWhen referring to the remote machine, it's common to call it **server**, but also **machine**, **VM** (virtual machine), **node**. Those all refer to some type of remote machine, normally running Linux, where you run programs.\n\n## Install the Server Program { #install-the-server-program }\n\nWhen you install FastAPI, it comes with a production server, Uvicorn, and you can start it with the `fastapi run` command.\n\nBut you can also install an ASGI server manually.\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and then you can install the server application.\n\nFor example, to install Uvicorn:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\nA similar process would apply to any other ASGI server program.\n\n/// tip\n\nBy adding the `standard`, Uvicorn will install and use some recommended extra dependencies.\n\nThat including `uvloop`, the high-performance drop-in replacement for `asyncio`, that provides the big concurrency performance boost.\n\nWhen you install FastAPI with something like `pip install \"fastapi[standard]\"` you already get `uvicorn[standard]` as well.\n\n///\n\n## Run the Server Program { #run-the-server-program }\n\nIf you installed an ASGI server manually, you would normally need to pass an import string in a special format for it to import your FastAPI application:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note\n\nThe command `uvicorn main:app` refers to:\n\n* `main`: the file `main.py` (the Python \"module\").\n* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.\n\nIt is equivalent to:\n\n```Python\nfrom main import app\n```\n\n///\n\nEach alternative ASGI server program would have a similar command, you can read more in their respective documentation.\n\n/// warning\n\nUvicorn and other servers support a `--reload` option that is useful during development.\n\nThe `--reload` option consumes much more resources, is more unstable, etc.\n\nIt helps a lot during **development**, but you **shouldn't** use it in **production**.\n\n///\n\n## Deployment Concepts { #deployment-concepts }\n\nThese examples run the server program (e.g Uvicorn), starting **a single process**, listening on all the IPs (`0.0.0.0`) on a predefined port (e.g. `80`).\n\nThis is the basic idea. But you will probably want to take care of some additional things, like:\n\n* Security - HTTPS\n* Running on startup\n* Restarts\n* Replication (the number of processes running)\n* Memory\n* Previous steps before starting\n\nI'll tell you more about each of these concepts, how to think about them, and some concrete examples with strategies to handle them in the next chapters. 🚀\n"
  },
  {
    "path": "docs/en/docs/deployment/server-workers.md",
    "content": "# Server Workers - Uvicorn with Workers { #server-workers-uvicorn-with-workers }\n\nLet's check back those deployment concepts from before:\n\n* Security - HTTPS\n* Running on startup\n* Restarts\n* **Replication (the number of processes running)**\n* Memory\n* Previous steps before starting\n\nUp to this point, with all the tutorials in the docs, you have probably been running a **server program**, for example, using the `fastapi` command, that runs Uvicorn, running a **single process**.\n\nWhen deploying applications you will probably want to have some **replication of processes** to take advantage of **multiple cores** and to be able to handle more requests.\n\nAs you saw in the previous chapter about [Deployment Concepts](concepts.md), there are multiple strategies you can use.\n\nHere I'll show you how to use **Uvicorn** with **worker processes** using the `fastapi` command or the `uvicorn` command directly.\n\n/// info\n\nIf you are using containers, for example with Docker or Kubernetes, I'll tell you more about that in the next chapter: [FastAPI in Containers - Docker](docker.md).\n\nIn particular, when running on **Kubernetes** you will probably **not** want to use workers and instead run **a single Uvicorn process per container**, but I'll tell you about it later in that chapter.\n\n///\n\n## Multiple Workers { #multiple-workers }\n\nYou can start multiple workers with the `--workers` command line option:\n\n//// tab | `fastapi`\n\nIf you use the `fastapi` command:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\nIf you prefer to use the `uvicorn` command directly:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\nThe only new option here is `--workers` telling Uvicorn to start 4 worker processes.\n\nYou can also see that it shows the **PID** of each process, `27365` for the parent process (this is the **process manager**) and one for each worker process: `27368`, `27369`, `27370`, and `27367`.\n\n## Deployment Concepts { #deployment-concepts }\n\nHere you saw how to use multiple **workers** to **parallelize** the execution of the application, take advantage of **multiple cores** in the CPU, and be able to serve **more requests**.\n\nFrom the list of deployment concepts from above, using workers would mainly help with the **replication** part, and a little bit with the **restarts**, but you still need to take care of the others:\n\n* **Security - HTTPS**\n* **Running on startup**\n* ***Restarts***\n* Replication (the number of processes running)\n* **Memory**\n* **Previous steps before starting**\n\n## Containers and Docker { #containers-and-docker }\n\nIn the next chapter about [FastAPI in Containers - Docker](docker.md) I'll explain some strategies you could use to handle the other **deployment concepts**.\n\nI'll show you how to **build your own image from scratch** to run a single Uvicorn process. It is a simple process and is probably what you would want to do when using a distributed container management system like **Kubernetes**.\n\n## Recap { #recap }\n\nYou can use multiple worker processes with the `--workers` CLI option with the `fastapi` or `uvicorn` commands to take advantage of **multi-core CPUs**, to run **multiple processes in parallel**.\n\nYou could use these tools and ideas if you are setting up **your own deployment system** while taking care of the other deployment concepts yourself.\n\nCheck out the next chapter to learn about **FastAPI** with containers (e.g. Docker and Kubernetes). You will see that those tools have simple ways to solve the other **deployment concepts** as well. ✨\n"
  },
  {
    "path": "docs/en/docs/deployment/versions.md",
    "content": "# About FastAPI versions { #about-fastapi-versions }\n\n**FastAPI** is already being used in production in many applications and systems. And the test coverage is kept at 100%. But its development is still moving quickly.\n\nNew features are added frequently, bugs are fixed regularly, and the code is still continuously improving.\n\nThat's why the current versions are still `0.x.x`, this reflects that each version could potentially have breaking changes. This follows the [Semantic Versioning](https://semver.org/) conventions.\n\nYou can create production applications with **FastAPI** right now (and you have probably been doing it for some time), you just have to make sure that you use a version that works correctly with the rest of your code.\n\n## Pin your `fastapi` version { #pin-your-fastapi-version }\n\nThe first thing you should do is to \"pin\" the version of **FastAPI** you are using to the specific latest version that you know works correctly for your application.\n\nFor example, let's say you are using version `0.112.0` in your app.\n\nIf you use a `requirements.txt` file you could specify the version with:\n\n```txt\nfastapi[standard]==0.112.0\n```\n\nthat would mean that you would use exactly the version `0.112.0`.\n\nOr you could also pin it with:\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\nthat would mean that you would use the versions `0.112.0` or above, but less than `0.113.0`, for example, a version `0.112.2` would still be accepted.\n\nIf you use any other tool to manage your installations, like `uv`, Poetry, Pipenv, or others, they all have a way that you can use to define specific versions for your packages.\n\n## Available versions { #available-versions }\n\nYou can see the available versions (e.g. to check what is the current latest) in the [Release Notes](../release-notes.md).\n\n## About versions { #about-versions }\n\nFollowing the Semantic Versioning conventions, any version below `1.0.0` could potentially add breaking changes.\n\nFastAPI also follows the convention that any \"PATCH\" version change is for bug fixes and non-breaking changes.\n\n/// tip\n\nThe \"PATCH\" is the last number, for example, in `0.2.3`, the PATCH version is `3`.\n\n///\n\nSo, you should be able to pin to a version like:\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\nBreaking changes and new features are added in \"MINOR\" versions.\n\n/// tip\n\nThe \"MINOR\" is the number in the middle, for example, in `0.2.3`, the MINOR version is `2`.\n\n///\n\n## Upgrading the FastAPI versions { #upgrading-the-fastapi-versions }\n\nYou should add tests for your app.\n\nWith **FastAPI** it's very easy (thanks to Starlette), check the docs: [Testing](../tutorial/testing.md)\n\nAfter you have tests, then you can upgrade the **FastAPI** version to a more recent one, and make sure that all your code is working correctly by running your tests.\n\nIf everything is working, or after you make the necessary changes, and all your tests are passing, then you can pin your `fastapi` to that new recent version.\n\n## About Starlette { #about-starlette }\n\nYou shouldn't pin the version of `starlette`.\n\nDifferent versions of **FastAPI** will use a specific newer version of Starlette.\n\nSo, you can just let **FastAPI** use the correct Starlette version.\n\n## About Pydantic { #about-pydantic }\n\nPydantic includes the tests for **FastAPI** with its own tests, so new versions of Pydantic (above `1.0.0`) are always compatible with FastAPI.\n\nYou can pin Pydantic to any version above `1.0.0` that works for you.\n\nFor example:\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/en/docs/editor-support.md",
    "content": "# Editor Support { #editor-support }\n\nThe official [FastAPI Extension](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) enhances your FastAPI development workflow with *path operation* discovery, navigation, as well as FastAPI Cloud deployment, and live log streaming.\n\nFor more details about the extension, refer to the README on the [GitHub repository](https://github.com/fastapi/fastapi-vscode).\n\n## Setup and Installation { #setup-and-installation }\n\nThe **FastAPI Extension** is available for both [VS Code](https://code.visualstudio.com/) and [Cursor](https://www.cursor.com/). It can be installed directly from the Extensions panel in each editor by searching for \"FastAPI\" and selecting the extension published by **FastAPI Labs**. The extension also works in browser-based editors such as [vscode.dev](https://vscode.dev) and [github.dev](https://github.dev).\n\n### Application Discovery { #application-discovery }\n\nBy default, the extension will automatically discover FastAPI applications in your workspace by scanning for files that instantiate `FastAPI()`. If auto-detection doesn't work for your project structure, you can specify an entrypoint via `[tool.fastapi]` in `pyproject.toml` or the `fastapi.entryPoint` VS Code setting using module notation (e.g. `myapp.main:app`).\n\n## Features { #features }\n\n- **Path Operation Explorer** - A sidebar tree view of all <dfn title=\"routes, endpoints\">*path operations*</dfn> in your application. Click to jump to any route or router definition.\n- **Route Search** - Search by path, method, or name with <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (on macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>).\n- **CodeLens Navigation** - Clickable links above test client calls (e.g. `client.get('/items')`) that jump to the matching *path operation* for quick navigation between tests and implementation.\n- **Deploy to FastAPI Cloud** - One-click deployment of your app to [FastAPI Cloud](https://fastapicloud.com/).\n- **Stream Application Logs** - Real-time log streaming from your FastAPI Cloud-deployed application with level filtering and text search.\n\nIf you'd like to familiarize yourself with the extension's features, you can checkout the extension walkthrough by opening the Command Palette (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> or on macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>) and selecting \"Welcome: Open walkthrough...\" and then choosing the \"Get started with FastAPI\" walkthrough.\n"
  },
  {
    "path": "docs/en/docs/environment-variables.md",
    "content": "# Environment Variables { #environment-variables }\n\n/// tip\n\nIf you already know what \"environment variables\" are and how to use them, feel free to skip this.\n\n///\n\nAn environment variable (also known as \"**env var**\") is a variable that lives **outside** of the Python code, in the **operating system**, and could be read by your Python code (or by other programs as well).\n\nEnvironment variables could be useful for handling application **settings**, as part of the **installation** of Python, etc.\n\n## Create and Use Env Vars { #create-and-use-env-vars }\n\nYou can **create** and use environment variables in the **shell (terminal)**, without needing Python:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// You could create an env var MY_NAME with\n$ export MY_NAME=\"Wade Wilson\"\n\n// Then you could use it with other programs, like\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Create an env var MY_NAME\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Use it with other programs, like\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## Read env vars in Python { #read-env-vars-in-python }\n\nYou could also create environment variables **outside** of Python, in the terminal (or with any other method), and then **read them in Python**.\n\nFor example you could have a file `main.py` with:\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip\n\nThe second argument to [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) is the default value to return.\n\nIf not provided, it's `None` by default, here we provide `\"World\"` as the default value to use.\n\n///\n\nThen you could call that Python program:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Here we don't set the env var yet\n$ python main.py\n\n// As we didn't set the env var, we get the default value\n\nHello World from Python\n\n// But if we create an environment variable first\n$ export MY_NAME=\"Wade Wilson\"\n\n// And then call the program again\n$ python main.py\n\n// Now it can read the environment variable\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Here we don't set the env var yet\n$ python main.py\n\n// As we didn't set the env var, we get the default value\n\nHello World from Python\n\n// But if we create an environment variable first\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// And then call the program again\n$ python main.py\n\n// Now it can read the environment variable\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\nAs environment variables can be set outside of the code, but can be read by the code, and don't have to be stored (committed to `git`) with the rest of the files, it's common to use them for configurations or **settings**.\n\nYou can also create an environment variable only for a **specific program invocation**, that is only available to that program, and only for its duration.\n\nTo do that, create it right before the program itself, on the same line:\n\n<div class=\"termy\">\n\n```console\n// Create an env var MY_NAME in line for this program call\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// Now it can read the environment variable\n\nHello Wade Wilson from Python\n\n// The env var no longer exists afterwards\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip\n\nYou can read more about it at [The Twelve-Factor App: Config](https://12factor.net/config).\n\n///\n\n## Types and Validation { #types-and-validation }\n\nThese environment variables can only handle **text strings**, as they are external to Python and have to be compatible with other programs and the rest of the system (and even with different operating systems, as Linux, Windows, macOS).\n\nThat means that **any value** read in Python from an environment variable **will be a `str`**, and any conversion to a different type or any validation has to be done in code.\n\nYou will learn more about using environment variables for handling **application settings** in the [Advanced User Guide - Settings and Environment Variables](./advanced/settings.md).\n\n## `PATH` Environment Variable { #path-environment-variable }\n\nThere is a **special** environment variable called **`PATH`** that is used by the operating systems (Linux, macOS, Windows) to find programs to run.\n\nThe value of the variable `PATH` is a long string that is made of directories separated by a colon `:` on Linux and macOS, and by a semicolon `;` on Windows.\n\nFor example, the `PATH` environment variable could look like this:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nThis means that the system should look for programs in the directories:\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\nThis means that the system should look for programs in the directories:\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\nWhen you type a **command** in the terminal, the operating system **looks for** the program in **each of those directories** listed in the `PATH` environment variable.\n\nFor example, when you type `python` in the terminal, the operating system looks for a program called `python` in the **first directory** in that list.\n\nIf it finds it, then it will **use it**. Otherwise it keeps looking in the **other directories**.\n\n### Installing Python and Updating the `PATH` { #installing-python-and-updating-the-path }\n\nWhen you install Python, you might be asked if you want to update the `PATH` environment variable.\n\n//// tab | Linux, macOS\n\nLet's say you install Python and it ends up in a directory `/opt/custompython/bin`.\n\nIf you say yes to update the `PATH` environment variable, then the installer will add `/opt/custompython/bin` to the `PATH` environment variable.\n\nIt could look like this:\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\nThis way, when you type `python` in the terminal, the system will find the Python program in `/opt/custompython/bin` (the last directory) and use that one.\n\n////\n\n//// tab | Windows\n\nLet's say you install Python and it ends up in a directory `C:\\opt\\custompython\\bin`.\n\nIf you say yes to update the `PATH` environment variable, then the installer will add `C:\\opt\\custompython\\bin` to the `PATH` environment variable.\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\nThis way, when you type `python` in the terminal, the system will find the Python program in `C:\\opt\\custompython\\bin` (the last directory) and use that one.\n\n////\n\nSo, if you type:\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\nThe system will **find** the `python` program in `/opt/custompython/bin` and run it.\n\nIt would be roughly equivalent to typing:\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\nThe system will **find** the `python` program in `C:\\opt\\custompython\\bin\\python` and run it.\n\nIt would be roughly equivalent to typing:\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\nThis information will be useful when learning about [Virtual Environments](virtual-environments.md).\n\n## Conclusion { #conclusion }\n\nWith this you should have a basic understanding of what **environment variables** are and how to use them in Python.\n\nYou can also read more about them in the [Wikipedia for Environment Variable](https://en.wikipedia.org/wiki/Environment_variable).\n\nIn many cases it's not very obvious how environment variables would be useful and applicable right away. But they keep showing up in many different scenarios when you are developing, so it's good to know about them.\n\nFor example, you will need this information in the next section, about [Virtual Environments](virtual-environments.md).\n"
  },
  {
    "path": "docs/en/docs/external-links.md",
    "content": "# External Links\n\n**FastAPI** has a great community constantly growing.\n\nThere are many posts, articles, tools, and projects, related to **FastAPI**.\n\nYou could easily use a search engine or video platform to find many resources related to FastAPI.\n\n/// info\n\nBefore, this page used to list links to external articles.\n\nBut now that FastAPI is the backend framework with the most GitHub stars across languages, and the most starred and used framework in Python, it no longer makes sense to attempt to list all articles written about it.\n\n///\n\n## GitHub Repositories\n\nMost starred [GitHub repositories with the topic `fastapi`](https://github.com/topics/fastapi):\n\n{% for repo in topic_repos %}\n\n<a href={{repo.html_url}} target=\"_blank\">★ {{repo.stars}} - {{repo.name}}</a> by <a href={{repo.owner_html_url}} target=\"_blank\">@{{repo.owner_login}}</a>.\n\n{% endfor %}\n"
  },
  {
    "path": "docs/en/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface\">CLI</abbr>** is a command line program that you can use to serve your FastAPI app, manage your FastAPI project, and more.\n\nWhen you install FastAPI (e.g. with `pip install \"fastapi[standard]\"`), it comes with a command line program you can run in the terminal.\n\nTo run your FastAPI app for development, you can use the `fastapi dev` command:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip\n\nFor production you would use `fastapi run` instead of `fastapi dev`. 🚀\n\n///\n\nInternally, **FastAPI CLI** uses [Uvicorn](https://www.uvicorn.dev), a high-performance, production-ready, ASGI server. 😎\n\nThe `fastapi` CLI will try to detect automatically the FastAPI app to run, assuming it's an object called `app` in a file `main.py` (or a couple other variants).\n\nBut you can configure explicitly the app to use.\n\n## Configure the app `entrypoint` in `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nYou can configure where your app is located in a `pyproject.toml` file like:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nThat `entrypoint` will tell the `fastapi` command that it should import the app like:\n\n```python\nfrom main import app\n```\n\nIf your code was structured like:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nThen you would set the `entrypoint` as:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nwhich would be equivalent to:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` with path { #fastapi-dev-with-path }\n\nYou can also pass the file path to the `fastapi dev` command, and it will guess the FastAPI app object to use:\n\n```console\n$ fastapi dev main.py\n```\n\nBut you would have to remember to pass the correct path every time you call the `fastapi` command.\n\nAdditionally, other tools might not be able to find it, for example the [VS Code Extension](editor-support.md) or [FastAPI Cloud](https://fastapicloud.com), so it is recommended to use the `entrypoint` in `pyproject.toml`.\n\n## `fastapi dev` { #fastapi-dev }\n\nRunning `fastapi dev` initiates development mode.\n\nBy default, **auto-reload** is enabled, automatically reloading the server when you make changes to your code. This is resource-intensive and could be less stable than when it's disabled. You should only use it for development. It also listens on the IP address `127.0.0.1`, which is the IP for your machine to communicate with itself alone (`localhost`).\n\n## `fastapi run` { #fastapi-run }\n\nExecuting `fastapi run` starts FastAPI in production mode.\n\nBy default, **auto-reload** is disabled. It also listens on the IP address `0.0.0.0`, which means all the available IP addresses, this way it will be publicly accessible to anyone that can communicate with the machine. This is how you would normally run it in production, for example, in a container.\n\nIn most cases you would (and should) have a \"termination proxy\" handling HTTPS for you on top, this will depend on how you deploy your application, your provider might do this for you, or you might need to set it up yourself.\n\n/// tip\n\nYou can learn more about it in the [deployment documentation](deployment/index.md).\n\n///\n"
  },
  {
    "path": "docs/en/docs/fastapi-people.md",
    "content": "---\nhide:\n  - navigation\n---\n\n# FastAPI People\n\nFastAPI has an amazing community that welcomes people from all backgrounds.\n\n## Creator\n\nHey! 👋\n\nThis is me:\n\n<div class=\"user-list user-list-center\">\n{% for user in people.maintainers %}\n\n<div class=\"user\"><a href=\"{{ contributors.tiangolo.url }}\"><div class=\"avatar-wrapper\"><img src=\"{{ contributors.tiangolo.avatarUrl }}\"/></div><div class=\"title\">@{{ contributors.tiangolo.login }}</div></a> <div class=\"count\">Answers: {{ user.answers }}</div><div class=\"count\">Pull Requests: {{ contributors.tiangolo.count }}</div></div>\n{% endfor %}\n\n</div>\n\nI'm the creator of **FastAPI**. You can read more about that in [Help FastAPI - Get Help - Connect with the author](help-fastapi.md#connect-with-the-author).\n\n...But here I want to show you the community.\n\n---\n\n**FastAPI** receives a lot of support from the community. And I want to highlight their contributions.\n\nThese are the people that:\n\n* [Help others with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github).\n* [Create Pull Requests](help-fastapi.md#create-a-pull-request).\n* Review Pull Requests, [especially important for translations](contributing.md#translations).\n* Help [manage the repository](management-tasks.md) (team members).\n\nAll these tasks help maintain the repository.\n\nA round of applause to them. 👏 🙇\n\n## Team\n\nThis is the current list of team members. 😎\n\nThey have different levels of involvement and permissions, they can perform [repository management tasks](./management-tasks.md) and together we  [manage the FastAPI repository](./management.md).\n\n<div class=\"user-list user-list-center\">\n\n{% for user in members[\"members\"] %}\n\n<div class=\"user\"><a href=\"{{ user.url }}\"><div class=\"avatar-wrapper\"><img src=\"{{ user.avatar_url }}\"/></div><div class=\"title\">@{{ user.login }}</div></a></div>\n\n{% endfor %}\n\n</div>\n\nAlthough the team members have the permissions to perform privileged tasks, all the [help from others maintaining FastAPI](./help-fastapi.md#help-maintain-fastapi) is very much appreciated! 🙇‍♂️\n\n## FastAPI Experts\n\nThese are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github). 🙇\n\nThey have proven to be **FastAPI Experts** by helping many others. ✨\n\n/// tip\n\nYou could become an official FastAPI Expert too!\n\nJust [help others with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github). 🤓\n\n///\n\nYou can see the **FastAPI Experts** for:\n\n* [Last Month](#fastapi-experts-last-month) 🤓\n* [3 Months](#fastapi-experts-3-months) 😎\n* [6 Months](#fastapi-experts-6-months) 🧐\n* [1 Year](#fastapi-experts-1-year) 🧑‍🔬\n* [**All Time**](#fastapi-experts-all-time) 🧙\n\n### FastAPI Experts - Last Month\n\nThese are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github) during the last month. 🤓\n\n<div class=\"user-list user-list-center\">\n\n{% for user in people.last_month_experts[:10] %}\n\n{% if user.login not in skip_users %}\n\n<div class=\"user\"><a href=\"{{ user.url }}\"><div class=\"avatar-wrapper\"><img src=\"{{ user.avatarUrl }}\"/></div><div class=\"title\">@{{ user.login }}</div></a> <div class=\"count\">Questions replied: {{ user.count }}</div></div>\n\n{% endif %}\n\n{% endfor %}\n\n</div>\n\n### FastAPI Experts - 3 Months\n\nThese are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github) during the last 3 months. 😎\n\n<div class=\"user-list user-list-center\">\n\n{% for user in people.three_months_experts[:10] %}\n\n{% if user.login not in skip_users %}\n\n<div class=\"user\"><a href=\"{{ user.url }}\"><div class=\"avatar-wrapper\"><img src=\"{{ user.avatarUrl }}\"/></div><div class=\"title\">@{{ user.login }}</div></a> <div class=\"count\">Questions replied: {{ user.count }}</div></div>\n\n{% endif %}\n\n{% endfor %}\n\n</div>\n\n### FastAPI Experts - 6 Months\n\nThese are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github) during the last 6 months. 🧐\n\n<div class=\"user-list user-list-center\">\n\n{% for user in people.six_months_experts[:10] %}\n\n{% if user.login not in skip_users %}\n\n<div class=\"user\"><a href=\"{{ user.url }}\"><div class=\"avatar-wrapper\"><img src=\"{{ user.avatarUrl }}\"/></div><div class=\"title\">@{{ user.login }}</div></a> <div class=\"count\">Questions replied: {{ user.count }}</div></div>\n\n{% endif %}\n\n{% endfor %}\n\n</div>\n\n### FastAPI Experts - 1 Year\n\nThese are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github) during the last year. 🧑‍🔬\n\n<div class=\"user-list user-list-center\">\n\n{% for user in people.one_year_experts[:20] %}\n\n{% if user.login not in skip_users %}\n\n<div class=\"user\"><a href=\"{{ user.url }}\"><div class=\"avatar-wrapper\"><img src=\"{{ user.avatarUrl }}\"/></div><div class=\"title\">@{{ user.login }}</div></a> <div class=\"count\">Questions replied: {{ user.count }}</div></div>\n\n{% endif %}\n\n{% endfor %}\n\n</div>\n\n### FastAPI Experts - All Time\n\nHere are the all time **FastAPI Experts**. 🤓🤯\n\nThese are the users that have [helped others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github) through *all time*. 🧙\n\n<div class=\"user-list user-list-center\">\n\n{% for user in people.experts[:50] %}\n\n{% if user.login not in skip_users %}\n\n<div class=\"user\"><a href=\"{{ user.url }}\"><div class=\"avatar-wrapper\"><img src=\"{{ user.avatarUrl }}\"/></div><div class=\"title\">@{{ user.login }}</div></a> <div class=\"count\">Questions replied: {{ user.count }}</div></div>\n\n{% endif %}\n\n{% endfor %}\n\n</div>\n\n## Top Contributors\n\nHere are the **Top Contributors**. 👷\n\nThese users have [created the most Pull Requests](help-fastapi.md#create-a-pull-request) that have been *merged*.\n\nThey have contributed source code, documentation, etc. 📦\n\n<div class=\"user-list user-list-center\">\n\n{% for user in (contributors.values() | list)[:50] %}\n\n{% if user.login not in skip_users %}\n\n<div class=\"user\"><a href=\"{{ user.url }}\"><div class=\"avatar-wrapper\"><img src=\"{{ user.avatarUrl }}\"/></div><div class=\"title\">@{{ user.login }}</div></a> <div class=\"count\">Pull Requests: {{ user.count }}</div></div>\n\n{% endif %}\n\n{% endfor %}\n\n</div>\n\nThere are hundreds of other contributors, you can see them all in the [FastAPI GitHub Contributors page](https://github.com/fastapi/fastapi/graphs/contributors). 👷\n\n## Top Translation Reviewers\n\nThese users are the **Top Translation Reviewers**. 🕵️\n\nTranslation reviewers have the [**power to approve translations**](contributing.md#translations) of the documentation. Without them, there wouldn't be documentation in several other languages.\n\n<div class=\"user-list user-list-center\">\n{% for user in (translation_reviewers.values() | list)[:50] %}\n\n{% if user.login not in skip_users %}\n\n<div class=\"user\"><a href=\"{{ user.url }}\"><div class=\"avatar-wrapper\"><img src=\"{{ user.avatarUrl }}\"/></div><div class=\"title\">@{{ user.login }}</div></a> <div class=\"count\">Reviews: {{ user.count }}</div></div>\n\n{% endif %}\n\n{% endfor %}\n\n</div>\n\n## Sponsors\n\nThese are the **Sponsors**. 😎\n\nThey are supporting my work with **FastAPI** (and others), mainly through [GitHub Sponsors](https://github.com/sponsors/tiangolo).\n\n{% if sponsors %}\n\n{% if sponsors.gold %}\n\n### Gold Sponsors\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n{% endif %}\n\n{% if sponsors.silver %}\n\n### Silver Sponsors\n\n{% for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n{% endif %}\n\n{% if sponsors.bronze %}\n\n### Bronze Sponsors\n\n{% for sponsor in sponsors.bronze -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n{% endif %}\n\n{% endif %}\n\n### Individual Sponsors\n\n{% if github_sponsors %}\n{% for group in github_sponsors.sponsors %}\n\n<div class=\"user-list user-list-center\">\n\n{% for user in group %}\n{% if user.login not in sponsors_badge.logins %}\n\n<div class=\"user\"><a href=\"{{ user.url }}\"><div class=\"avatar-wrapper\"><img src=\"{{ user.avatarUrl }}\"/></div><div class=\"title\">@{{ user.login }}</div></a></div>\n\n{% endif %}\n{% endfor %}\n\n</div>\n\n{% endfor %}\n{% endif %}\n\n## About the data - technical details\n\nThe main intention of this page is to highlight the effort of the community to help others.\n\nEspecially including efforts that are normally less visible, and in many cases more arduous, like helping others with questions and reviewing Pull Requests with translations.\n\nThe data is calculated each month, you can read the [source code here](https://github.com/fastapi/fastapi/blob/master/scripts/).\n\nHere I'm also highlighting contributions from sponsors.\n\nI also reserve the right to update the algorithm, sections, thresholds, etc (just in case 🤷).\n"
  },
  {
    "path": "docs/en/docs/features.md",
    "content": "# Features { #features }\n\n## FastAPI features { #fastapi-features }\n\n**FastAPI** gives you the following:\n\n### Based on open standards { #based-on-open-standards }\n\n* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) for API creation, including declarations of <dfn title=\"also known as: endpoints, routes\">path</dfn> <dfn title=\"also known as HTTP methods, as POST, GET, PUT, DELETE\">operations</dfn>, parameters, request bodies, security, etc.\n* Automatic data model documentation with [**JSON Schema**](https://json-schema.org/) (as OpenAPI itself is based on JSON Schema).\n* Designed around these standards, after a meticulous study. Instead of an afterthought layer on top.\n* This also allows using automatic **client code generation** in many languages.\n\n### Automatic docs { #automatic-docs }\n\nInteractive API documentation and exploration web user interfaces. As the framework is based on OpenAPI, there are multiple options, 2 included by default.\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui), with interactive exploration, call and test your API directly from the browser.\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Alternative API documentation with [**ReDoc**](https://github.com/Rebilly/ReDoc).\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Just Modern Python { #just-modern-python }\n\nIt's all based on standard **Python type** declarations (thanks to Pydantic). No new syntax to learn. Just standard modern Python.\n\nIf you need a 2 minute refresher of how to use Python types (even if you don't use FastAPI), check the short tutorial: [Python Types](python-types.md).\n\nYou write standard Python with types:\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# Declare a variable as a str\n# and get editor support inside the function\ndef main(user_id: str):\n    return user_id\n\n\n# A Pydantic model\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\nThat can then be used like:\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n/// info\n\n`**second_user_data` means:\n\nPass the keys and values of the `second_user_data` dict directly as key-value arguments, equivalent to: `User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### Editor support { #editor-support }\n\nAll the framework was designed to be easy and intuitive to use, all the decisions were tested on multiple editors even before starting development, to ensure the best development experience.\n\nIn the Python developer surveys, it's clear [that one of the most used features is \"autocompletion\"](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).\n\nThe whole **FastAPI** framework is based to satisfy that. Autocompletion works everywhere.\n\nYou will rarely need to come back to the docs.\n\nHere's how your editor might help you:\n\n* in [Visual Studio Code](https://code.visualstudio.com/):\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* in [PyCharm](https://www.jetbrains.com/pycharm/):\n\n![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\nYou will get completion in code you might even consider impossible before. As for example, the `price` key inside a JSON body (that could have been nested) that comes from a request.\n\nNo more typing the wrong key names, coming back and forth between docs, or scrolling up and down to find if you finally used `username` or `user_name`.\n\n### Short { #short }\n\nIt has sensible **defaults** for everything, with optional configurations everywhere. All the parameters can be fine-tuned to do what you need and to define the API you need.\n\nBut by default, it all **\"just works\"**.\n\n### Validation { #validation }\n\n* Validation for most (or all?) Python **data types**, including:\n    * JSON objects (`dict`).\n    * JSON array (`list`) defining item types.\n    * String (`str`) fields, defining min and max lengths.\n    * Numbers (`int`, `float`) with min and max values, etc.\n\n* Validation for more exotic types, like:\n    * URL.\n    * Email.\n    * UUID.\n    * ...and others.\n\nAll the validation is handled by the well-established and robust **Pydantic**.\n\n### Security and authentication { #security-and-authentication }\n\nSecurity and authentication integrated. Without any compromise with databases or data models.\n\nAll the security schemes defined in OpenAPI, including:\n\n* HTTP Basic.\n* **OAuth2** (also with **JWT tokens**). Check the tutorial on [OAuth2 with JWT](tutorial/security/oauth2-jwt.md).\n* API keys in:\n    * Headers.\n    * Query parameters.\n    * Cookies, etc.\n\nPlus all the security features from Starlette (including **session cookies**).\n\nAll built as reusable tools and components that are easy to integrate with your systems, data stores, relational and NoSQL databases, etc.\n\n### Dependency Injection { #dependency-injection }\n\nFastAPI includes an extremely easy to use, but extremely powerful <dfn title='also known as \"components\", \"resources\", \"services\", \"providers\"'><strong>Dependency Injection</strong></dfn> system.\n\n* Even dependencies can have dependencies, creating a hierarchy or **\"graph\" of dependencies**.\n* All **automatically handled** by the framework.\n* All the dependencies can require data from requests and **augment the path operation** constraints and automatic documentation.\n* **Automatic validation** even for *path operation* parameters defined in dependencies.\n* Support for complex user authentication systems, **database connections**, etc.\n* **No compromise** with databases, frontends, etc. But easy integration with all of them.\n\n### Unlimited \"plug-ins\" { #unlimited-plug-ins }\n\nOr in other way, no need for them, import and use the code you need.\n\nAny integration is designed to be so simple to use (with dependencies) that you can create a \"plug-in\" for your application in 2 lines of code using the same structure and syntax used for your *path operations*.\n\n### Tested { #tested }\n\n* 100% <dfn title=\"The amount of code that is automatically tested\">test coverage</dfn>.\n* 100% <dfn title=\"Python type annotations, with this your editor and external tools can give you better support\">type annotated</dfn> code base.\n* Used in production applications.\n\n## Starlette features { #starlette-features }\n\n**FastAPI** is fully compatible with (and based on) [**Starlette**](https://www.starlette.dev/). So, any additional Starlette code you have, will also work.\n\n`FastAPI` is actually a sub-class of `Starlette`. So, if you already know or use Starlette, most of the functionality will work the same way.\n\nWith **FastAPI** you get all of **Starlette**'s features (as FastAPI is just Starlette on steroids):\n\n* Seriously impressive performance. It is [one of the fastest Python frameworks available, on par with **NodeJS** and **Go**](https://github.com/encode/starlette#performance).\n* **WebSocket** support.\n* In-process background tasks.\n* Startup and shutdown events.\n* Test client built on HTTPX.\n* **CORS**, GZip, Static Files, Streaming responses.\n* **Session and Cookie** support.\n* 100% test coverage.\n* 100% type annotated codebase.\n\n## Pydantic features { #pydantic-features }\n\n**FastAPI** is fully compatible with (and based on) [**Pydantic**](https://docs.pydantic.dev/). So, any additional Pydantic code you have, will also work.\n\nIncluding external libraries also based on Pydantic, as <abbr title=\"Object-Relational Mapper\">ORM</abbr>s, <abbr title=\"Object-Document Mapper\">ODM</abbr>s for databases.\n\nThis also means that in many cases you can pass the same object you get from a request **directly to the database**, as everything is validated automatically.\n\nThe same applies the other way around, in many cases you can just pass the object you get from the database **directly to the client**.\n\nWith **FastAPI** you get all of **Pydantic**'s features (as FastAPI is based on Pydantic for all the data handling):\n\n* **No brainfuck**:\n    * No new schema definition micro-language to learn.\n    * If you know Python types you know how to use Pydantic.\n* Plays nicely with your **<abbr title=\"Integrated Development Environment: similar to a code editor\">IDE</abbr>/<dfn title=\"A program that checks for code errors\">linter</dfn>/brain**:\n    * Because pydantic data structures are just instances of classes you define; auto-completion, linting, mypy and your intuition should all work properly with your validated data.\n* Validate **complex structures**:\n    * Use of hierarchical Pydantic models, Python `typing`’s `List` and `Dict`, etc.\n    * And validators allow complex data schemas to be clearly and easily defined, checked and documented as JSON Schema.\n    * You can have deeply **nested JSON** objects and have them all validated and annotated.\n* **Extensible**:\n    * Pydantic allows custom data types to be defined or you can extend validation with methods on a model decorated with the validator decorator.\n* 100% test coverage.\n"
  },
  {
    "path": "docs/en/docs/help-fastapi.md",
    "content": "# Help FastAPI - Get Help { #help-fastapi-get-help }\n\nDo you like **FastAPI**?\n\nWould you like to help FastAPI, other users, and the author?\n\nOr would you like to get help with **FastAPI**?\n\nThere are very simple ways to help (several involve just one or two clicks).\n\nAnd there are several ways to get help too.\n\n## Subscribe to the newsletter { #subscribe-to-the-newsletter }\n\nYou can subscribe to the (infrequent) [**FastAPI and friends** newsletter](newsletter.md) to stay updated about:\n\n* News about FastAPI and friends 🚀\n* Guides 📝\n* Features ✨\n* Breaking changes 🚨\n* Tips and tricks ✅\n\n## Follow FastAPI on X (Twitter) { #follow-fastapi-on-x-twitter }\n\n[Follow @fastapi on **X (Twitter)**](https://x.com/fastapi) to get the latest news about **FastAPI**. 🐦\n\n## Star **FastAPI** in GitHub { #star-fastapi-in-github }\n\nYou can \"star\" FastAPI in GitHub (clicking the star button at the top right): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). ⭐️\n\nBy adding a star, other users will be able to find it more easily and see that it has been already useful for others.\n\n## Watch the GitHub repository for releases { #watch-the-github-repository-for-releases }\n\nYou can \"watch\" FastAPI in GitHub (clicking the \"watch\" button at the top right): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nThere you can select \"Releases only\".\n\nBy doing it, you will receive notifications (in your email) whenever there's a new release (a new version) of **FastAPI** with bug fixes and new features.\n\n## Connect with the author { #connect-with-the-author }\n\nYou can connect with [me (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com), the author.\n\nYou can:\n\n* [Follow me on **GitHub**](https://github.com/tiangolo).\n    * See other Open Source projects I have created that could help you.\n    * Follow me to see when I create a new Open Source project.\n* [Follow me on **X (Twitter)**](https://x.com/tiangolo) or [Mastodon](https://fosstodon.org/@tiangolo).\n    * Tell me how you use FastAPI (I love to hear that).\n    * Hear when I make announcements or release new tools.\n    * You can also [follow @fastapi on X (Twitter)](https://x.com/fastapi) (a separate account).\n* [Follow me on **LinkedIn**](https://www.linkedin.com/in/tiangolo/).\n    * Hear when I make announcements or release new tools (although I use X (Twitter) more often 🤷‍♂).\n* Read what I write (or follow me) on [**Dev.to**](https://dev.to/tiangolo) or [**Medium**](https://medium.com/@tiangolo).\n    * Read other ideas, articles, and read about tools I have created.\n    * Follow me to read when I publish something new.\n\n## Tweet about **FastAPI** { #tweet-about-fastapi }\n\n[Tweet about **FastAPI**](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi) and let me and others know why you like it. 🎉\n\nI love to hear about how **FastAPI** is being used, what you have liked in it, in which project/company are you using it, etc.\n\n## Vote for FastAPI { #vote-for-fastapi }\n\n* [Vote for **FastAPI** in Slant](https://www.slant.co/options/34241/~fastapi-review).\n* [Vote for **FastAPI** in AlternativeTo](https://alternativeto.net/software/fastapi/about/).\n* [Say you use **FastAPI** on StackShare](https://stackshare.io/pypi-fastapi).\n\n## Help others with questions in GitHub { #help-others-with-questions-in-github }\n\nYou can try and help others with their questions in:\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\nIn many cases you might already know the answer for those questions. 🤓\n\nIf you are helping a lot of people with their questions, you will become an official [FastAPI Expert](fastapi-people.md#fastapi-experts). 🎉\n\nJust remember, the most important point is: try to be kind. People come with their frustrations and in many cases don't ask in the best way, but try as best as you can to be kind. 🤗\n\nThe idea is for the **FastAPI** community to be kind and welcoming. At the same time, don't accept bullying or disrespectful behavior towards others. We have to take care of each other.\n\n---\n\nHere's how to help others with questions (in discussions or issues):\n\n### Understand the question { #understand-the-question }\n\n* Check if you can understand what is the **purpose** and use case of the person asking.\n\n* Then check if the question (the vast majority are questions) is **clear**.\n\n* In many cases the question asked is about an imaginary solution from the user, but there might be a **better** one. If you can understand the problem and use case better, you might be able to suggest a better **alternative solution**.\n\n* If you can't understand the question, ask for more **details**.\n\n### Reproduce the problem { #reproduce-the-problem }\n\nFor most of the cases and most of the questions there's something related to the person's **original code**.\n\nIn many cases they will only copy a fragment of the code, but that's not enough to **reproduce the problem**.\n\n* You can ask them to provide a [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example), that you can **copy-paste** and run locally to see the same error or behavior they are seeing, or to understand their use case better.\n\n* If you are feeling too generous, you can try to **create an example** like that yourself, just based on the description of the problem. Just keep in mind that this might take a lot of time and it might be better to ask them to clarify the problem first.\n\n### Suggest solutions { #suggest-solutions }\n\n* After being able to understand the question, you can give them a possible **answer**.\n\n* In many cases, it's better to understand their **underlying problem or use case**, because there might be a better way to solve it than what they are trying to do.\n\n### Ask to close { #ask-to-close }\n\nIf they reply, there's a high chance you would have solved their problem, congrats, **you're a hero**! 🦸\n\n* Now, if that solved their problem, you can ask them to:\n\n    * In GitHub Discussions: mark the comment as the **answer**.\n    * In GitHub Issues: **close** the issue.\n\n## Watch the GitHub repository { #watch-the-github-repository }\n\nYou can \"watch\" FastAPI in GitHub (clicking the \"watch\" button at the top right): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nIf you select \"Watching\" instead of \"Releases only\" you will receive notifications when someone creates a new issue or question. You can also specify that you only want to be notified about new issues, or discussions, or PRs, etc.\n\nThen you can try and help them solve those questions.\n\n## Ask Questions { #ask-questions }\n\nYou can [create a new question](https://github.com/fastapi/fastapi/discussions/new?category=questions) in the GitHub repository, for example to:\n\n* Ask a **question** or ask about a **problem**.\n* Suggest a new **feature**.\n\n**Note**: if you do it, then I'm going to ask you to also help others. 😉\n\n## Review Pull Requests { #review-pull-requests }\n\nYou can help me review pull requests from others.\n\nAgain, please try your best to be kind. 🤗\n\n---\n\nHere's what to keep in mind and how to review a pull request:\n\n### Understand the problem { #understand-the-problem }\n\n* First, make sure you **understand the problem** that the pull request is trying to solve. It might have a longer discussion in a GitHub Discussion or issue.\n\n* There's also a good chance that the pull request is not actually needed because the problem can be solved in a **different way**. Then you can suggest or ask about that.\n\n### Don't worry about style { #dont-worry-about-style }\n\n* Don't worry too much about things like commit message styles, I will squash and merge customizing the commit manually.\n\n* Also don't worry about style rules, there are already automatized tools checking that.\n\nAnd if there's any other style or consistency need, I'll ask directly for that, or I'll add commits on top with the needed changes.\n\n### Check the code { #check-the-code }\n\n* Check and read the code, see if it makes sense, **run it locally** and see if it actually solves the problem.\n\n* Then **comment** saying that you did that, that's how I will know you really checked it.\n\n/// info\n\nUnfortunately, I can't simply trust PRs that just have several approvals.\n\nSeveral times it has happened that there are PRs with 3, 5 or more approvals, probably because the description is appealing, but when I check the PRs, they are actually broken, have a bug, or don't solve the problem they claim to solve. 😅\n\nSo, it's really important that you actually read and run the code, and let me know in the comments that you did. 🤓\n\n///\n\n* If the PR can be simplified in a way, you can ask for that, but there's no need to be too picky, there might be a lot of subjective points of view (and I will have my own as well 🙈), so it's better if you can focus on the fundamental things.\n\n### Tests { #tests }\n\n* Help me check that the PR has **tests**.\n\n* Check that the tests **fail** before the PR. 🚨\n\n* Then check that the tests **pass** after the PR. ✅\n\n* Many PRs don't have tests, you can **remind** them to add tests, or you can even **suggest** some tests yourself. That's one of the things that consume most time and you can help a lot with that.\n\n* Then also comment what you tried, that way I'll know that you checked it. 🤓\n\n## Create a Pull Request { #create-a-pull-request }\n\nYou can [contribute](contributing.md) to the source code with Pull Requests, for example:\n\n* To fix a typo you found on the documentation.\n* To share an article, video, or podcast you created or found about FastAPI by [editing this file](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml).\n    * Make sure you add your link to the start of the corresponding section.\n* To help [translate the documentation](contributing.md#translations) to your language.\n    * You can also help to review the translations created by others.\n* To propose new documentation sections.\n* To fix an existing issue/bug.\n    * Make sure to add tests.\n* To add a new feature.\n    * Make sure to add tests.\n    * Make sure to add documentation if it's relevant.\n\n## Help Maintain FastAPI { #help-maintain-fastapi }\n\nHelp me maintain **FastAPI**! 🤓\n\nThere's a lot of work to do, and for most of it, **YOU** can do it.\n\nThe main tasks that you can do right now are:\n\n* [Help others with questions in GitHub](#help-others-with-questions-in-github) (see the section above).\n* [Review Pull Requests](#review-pull-requests) (see the section above).\n\nThose two tasks are what **consume time the most**. That's the main work of maintaining FastAPI.\n\nIf you can help me with that, **you are helping me maintain FastAPI** and making sure it keeps **advancing faster and better**. 🚀\n\n## Join the chat { #join-the-chat }\n\nJoin the 👥 [Discord chat server](https://discord.gg/VQjSZaeJmf) 👥 and hang out with others in the FastAPI community.\n\n/// tip\n\nFor questions, ask them in [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions), there's a much better chance you will receive help by the [FastAPI Experts](fastapi-people.md#fastapi-experts).\n\nUse the chat only for other general conversations.\n\n///\n\n### Don't use the chat for questions { #dont-use-the-chat-for-questions }\n\nKeep 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.\n\nIn GitHub, the template will guide you to write the right question so that you can more easily get a good answer, or even solve the problem yourself even before asking. And in GitHub I can make sure I always answer everything, even if it takes some time. I can't personally do that with the chat systems. 😅\n\nConversations in the chat systems are also not as easily searchable as in GitHub, so questions and answers might get lost in the conversation. And only the ones in GitHub count to become a [FastAPI Expert](fastapi-people.md#fastapi-experts), so you will most probably receive more attention in GitHub.\n\nOn the other side, there are thousands of users in the chat systems, so there's a high chance you'll find someone to talk to there, almost all the time. 😄\n\n## Sponsor the author { #sponsor-the-author }\n\nIf your **product/company** depends on or is related to **FastAPI** and you want to reach its users, you can sponsor the author (me) through [GitHub sponsors](https://github.com/sponsors/tiangolo). Depending on the tier, you could get some extra benefits, like a badge in the docs. 🎁\n\n---\n\nThanks! 🚀\n"
  },
  {
    "path": "docs/en/docs/history-design-future.md",
    "content": "# History, Design and Future { #history-design-and-future }\n\nSome time ago, [a **FastAPI** user asked](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920):\n\n> What’s the history of this project? It seems to have come from nowhere to awesome in a few weeks [...]\n\nHere's a little bit of that history.\n\n## Alternatives { #alternatives }\n\nI have been creating APIs with complex requirements for several years (Machine Learning, distributed systems, asynchronous jobs, NoSQL databases, etc), leading several teams of developers.\n\nAs part of that, I needed to investigate, test and use many alternatives.\n\nThe history of **FastAPI** is in great part the history of its predecessors.\n\nAs said in the section [Alternatives](alternatives.md):\n\n<blockquote markdown=\"1\">\n\n**FastAPI** wouldn't exist if not for the previous work of others.\n\nThere have been many tools created before that have helped inspire its creation.\n\nI have been avoiding the creation of a new framework for several years. First I tried to solve all the features covered by **FastAPI** using many different frameworks, plug-ins, and tools.\n\nBut at some point, there was no other option than creating something that provided all these features, taking the best ideas from previous tools, and combining them in the best way possible, using language features that weren't even available before (Python 3.6+ type hints).\n\n</blockquote>\n\n## Investigation { #investigation }\n\nBy using all the previous alternatives I had the chance to learn from all of them, take ideas, and combine them in the best way I could find for myself and the teams of developers I have worked with.\n\nFor example, it was clear that ideally it should be based on standard Python type hints.\n\nAlso, the best approach was to use already existing standards.\n\nSo, before even starting to code **FastAPI**, I spent several months studying the specs for OpenAPI, JSON Schema, OAuth2, etc. Understanding their relationship, overlap, and differences.\n\n## Design { #design }\n\nThen I spent some time designing the developer \"API\" I wanted to have as a user (as a developer using FastAPI).\n\nI tested several ideas in the most popular Python editors: PyCharm, VS Code, Jedi based editors.\n\nBy the last [Python Developer Survey](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools), that covers about 80% of the users.\n\nIt means that **FastAPI** was specifically tested with the editors used by 80% of the Python developers. And as most of the other editors tend to work similarly, all its benefits should work for virtually all editors.\n\nThat way I could find the best ways to reduce code duplication as much as possible, to have completion everywhere, type and error checks, etc.\n\nAll in a way that provided the best development experience for all the developers.\n\n## Requirements { #requirements }\n\nAfter testing several alternatives, I decided that I was going to use [**Pydantic**](https://docs.pydantic.dev/) for its advantages.\n\nThen I contributed to it, to make it fully compliant with JSON Schema, to support different ways to define constraint declarations, and to improve editor support (type checks, autocompletion) based on the tests in several editors.\n\nDuring the development, I also contributed to [**Starlette**](https://www.starlette.dev/), the other key requirement.\n\n## Development { #development }\n\nBy the time I started creating **FastAPI** itself, most of the pieces were already in place, the design was defined, the requirements and tools were ready, and the knowledge about the standards and specifications was clear and fresh.\n\n## Future { #future }\n\nBy this point, it's already clear that **FastAPI** with its ideas is being useful for many people.\n\nIt is being chosen over previous alternatives for suiting many use cases better.\n\nMany developers and teams already depend on **FastAPI** for their projects (including me and my team).\n\nBut still, there are many improvements and features to come.\n\n**FastAPI** has a great future ahead.\n\nAnd [your help](help-fastapi.md) is greatly appreciated.\n"
  },
  {
    "path": "docs/en/docs/how-to/authentication-error-status-code.md",
    "content": "# Use Old 403 Authentication Error Status Codes { #use-old-403-authentication-error-status-codes }\n\nBefore FastAPI version `0.122.0`, when the integrated security utilities returned an error to the client after a failed authentication, they used the HTTP status code `403 Forbidden`.\n\nStarting with FastAPI version `0.122.0`, they use the more appropriate HTTP status code `401 Unauthorized`, and return a sensible `WWW-Authenticate` header in the response, following the HTTP specifications, [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized).\n\nBut if for some reason your clients depend on the old behavior, you can revert to it by overriding the method `make_not_authenticated_error` in your security classes.\n\nFor example, you can create a subclass of `HTTPBearer` that returns a `403 Forbidden` error instead of the default `401 Unauthorized` error:\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip\n\nNotice that the function returns the exception instance, it doesn't raise it. The raising is done in the rest of the internal code.\n\n///\n"
  },
  {
    "path": "docs/en/docs/how-to/conditional-openapi.md",
    "content": "# Conditional OpenAPI { #conditional-openapi }\n\nIf you needed to, you could use settings and environment variables to configure OpenAPI conditionally depending on the environment, and even disable it entirely.\n\n## About security, APIs, and docs { #about-security-apis-and-docs }\n\nHiding your documentation user interfaces in production *shouldn't* be the way to protect your API.\n\nThat doesn't add any extra security to your API, the *path operations* will still be available where they are.\n\nIf there's a security flaw in your code, it will still exist.\n\nHiding the documentation just makes it more difficult to understand how to interact with your API, and could make it more difficult for you to debug it in production. It could be considered simply a form of [Security through obscurity](https://en.wikipedia.org/wiki/Security_through_obscurity).\n\nIf you want to secure your API, there are several better things you can do, for example:\n\n* Make sure you have well defined Pydantic models for your request bodies and responses.\n* Configure any required permissions and roles using dependencies.\n* Never store plaintext passwords, only password hashes.\n* Implement and use well-known cryptographic tools, like pwdlib and JWT tokens, etc.\n* Add more granular permission controls with OAuth2 scopes where needed.\n* ...etc.\n\nNevertheless, you might have a very specific use case where you really need to disable the API docs for some environment (e.g. for production) or depending on configurations from environment variables.\n\n## Conditional OpenAPI from settings and env vars { #conditional-openapi-from-settings-and-env-vars }\n\nYou can easily use the same Pydantic settings to configure your generated OpenAPI and the docs UIs.\n\nFor example:\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\nHere we declare the setting `openapi_url` with the same default of `\"/openapi.json\"`.\n\nAnd then we use it when creating the `FastAPI` app.\n\nThen you could disable OpenAPI (including the UI docs) by setting the environment variable `OPENAPI_URL` to the empty string, like:\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nThen if you go to the URLs at `/openapi.json`, `/docs`, or `/redoc` you will just get a `404 Not Found` error like:\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/en/docs/how-to/configure-swagger-ui.md",
    "content": "# Configure Swagger UI { #configure-swagger-ui }\n\nYou can configure some extra [Swagger UI parameters](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\nTo configure them, pass the `swagger_ui_parameters` argument when creating the `FastAPI()` app object or to the `get_swagger_ui_html()` function.\n\n`swagger_ui_parameters` receives a dictionary with the configurations passed to Swagger UI directly.\n\nFastAPI converts the configurations to **JSON** to make them compatible with JavaScript, as that's what Swagger UI needs.\n\n## Disable Syntax Highlighting { #disable-syntax-highlighting }\n\nFor example, you could disable syntax highlighting in Swagger UI.\n\nWithout changing the settings, syntax highlighting is enabled by default:\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\nBut you can disable it by setting `syntaxHighlight` to `False`:\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n...and then Swagger UI won't show the syntax highlighting anymore:\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## Change the Theme { #change-the-theme }\n\nThe same way you could set the syntax highlighting theme with the key `\"syntaxHighlight.theme\"` (notice that it has a dot in the middle):\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\nThat configuration would change the syntax highlighting color theme:\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## Change Default Swagger UI Parameters { #change-default-swagger-ui-parameters }\n\nFastAPI includes some default configuration parameters appropriate for most of the use cases.\n\nIt includes these default configurations:\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\nYou can override any of them by setting a different value in the argument `swagger_ui_parameters`.\n\nFor example, to disable `deepLinking` you could pass these settings to `swagger_ui_parameters`:\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## Other Swagger UI Parameters { #other-swagger-ui-parameters }\n\nTo see all the other possible configurations you can use, read the official [docs for Swagger UI parameters](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\n## JavaScript-only settings { #javascript-only-settings }\n\nSwagger UI also allows other configurations to be **JavaScript-only** objects (for example, JavaScript functions).\n\nFastAPI also includes these JavaScript-only `presets` settings:\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\nThese are **JavaScript** objects, not strings, so you can't pass them from Python code directly.\n\nIf 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.\n"
  },
  {
    "path": "docs/en/docs/how-to/custom-docs-ui-assets.md",
    "content": "# Custom Docs UI Static Assets (Self-Hosting) { #custom-docs-ui-static-assets-self-hosting }\n\nThe API docs use **Swagger UI** and **ReDoc**, and each of those need some JavaScript and CSS files.\n\nBy default, those files are served from a <abbr title=\"Content Delivery Network: A service, normally composed of several servers, that provides static files, like JavaScript and CSS. It's commonly used to serve those files from the server closer to the client, improving performance.\">CDN</abbr>.\n\nBut it's possible to customize it, you can set a specific CDN, or serve the files yourself.\n\n## Custom CDN for JavaScript and CSS { #custom-cdn-for-javascript-and-css }\n\nLet's say that you want to use a different <abbr title=\"Content Delivery Network\">CDN</abbr>, for example you want to use `https://unpkg.com/`.\n\nThis could be useful if for example you live in a country that restricts some URLs.\n\n### Disable the automatic docs { #disable-the-automatic-docs }\n\nThe first step is to disable the automatic docs, as by default, those use the default CDN.\n\nTo disable them, set their URLs to `None` when creating your `FastAPI` app:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### Include the custom docs { #include-the-custom-docs }\n\nNow you can create the *path operations* for the custom docs.\n\nYou can reuse FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments:\n\n* `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`.\n* `title`: the title of your API.\n* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default.\n* `swagger_js_url`: the URL where the HTML for your Swagger UI docs can get the **JavaScript** file. This is the custom CDN URL.\n* `swagger_css_url`: the URL where the HTML for your Swagger UI docs can get the **CSS** file. This is the custom CDN URL.\n\nAnd similarly for ReDoc...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip\n\nThe *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2.\n\nIf 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.\n\nSwagger UI will handle it behind the scenes for you, but it needs this \"redirect\" helper.\n\n///\n\n### Create a *path operation* to test it { #create-a-path-operation-to-test-it }\n\nNow, to be able to test that everything works, create a *path operation*:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### Test it { #test-it }\n\nNow, you should be able to go to your docs at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), and reload the page, it will load those assets from the new CDN.\n\n## Self-hosting JavaScript and CSS for docs { #self-hosting-javascript-and-css-for-docs }\n\nSelf-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.\n\nHere you'll see how to serve those files yourself, in the same FastAPI app, and configure the docs to use them.\n\n### Project file structure { #project-file-structure }\n\nLet's say your project file structure looks like this:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\nNow create a directory to store those static files.\n\nYour new file structure could look like this:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### Download the files { #download-the-files }\n\nDownload the static files needed for the docs and put them on that `static/` directory.\n\nYou can probably right-click each link and select an option similar to \"Save link as...\".\n\n**Swagger UI** uses the files:\n\n* [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n* [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\nAnd **ReDoc** uses the file:\n\n* [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\nAfter that, your file structure could look like:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### Serve the static files { #serve-the-static-files }\n\n* Import `StaticFiles`.\n* \"Mount\" a `StaticFiles()` instance in a specific path.\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### Test the static files { #test-the-static-files }\n\nStart your application and go to [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js).\n\nYou should see a very long JavaScript file for **ReDoc**.\n\nIt could start with something like:\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\nThat 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.\n\nNow we can configure the app to use those static files for the docs.\n\n### Disable the automatic docs for static files { #disable-the-automatic-docs-for-static-files }\n\nThe same as when using a custom CDN, the first step is to disable the automatic docs, as those use the CDN by default.\n\nTo disable them, set their URLs to `None` when creating your `FastAPI` app:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### Include the custom docs for static files { #include-the-custom-docs-for-static-files }\n\nAnd the same way as with a custom CDN, now you can create the *path operations* for the custom docs.\n\nAgain, you can reuse FastAPI's internal functions to create the HTML pages for the docs, and pass them the needed arguments:\n\n* `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`.\n* `title`: the title of your API.\n* `oauth2_redirect_url`: you can use `app.swagger_ui_oauth2_redirect_url` here to use the default.\n* `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**.\n* `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**.\n\nAnd similarly for ReDoc...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip\n\nThe *path operation* for `swagger_ui_redirect` is a helper for when you use OAuth2.\n\nIf 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.\n\nSwagger UI will handle it behind the scenes for you, but it needs this \"redirect\" helper.\n\n///\n\n### Create a *path operation* to test static files { #create-a-path-operation-to-test-static-files }\n\nNow, to be able to test that everything works, create a *path operation*:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### Test Static Files UI { #test-static-files-ui }\n\nNow, you should be able to disconnect your WiFi, go to your docs at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), and reload the page.\n\nAnd even without Internet, you would be able to see the docs for your API and interact with it.\n"
  },
  {
    "path": "docs/en/docs/how-to/custom-request-and-route.md",
    "content": "# Custom Request and APIRoute class { #custom-request-and-apiroute-class }\n\nIn some cases, you may want to override the logic used by the `Request` and `APIRoute` classes.\n\nIn particular, this may be a good alternative to logic in a middleware.\n\nFor example, if you want to read or manipulate the request body before it is processed by your application.\n\n/// danger\n\nThis is an \"advanced\" feature.\n\nIf you are just starting with **FastAPI** you might want to skip this section.\n\n///\n\n## Use cases { #use-cases }\n\nSome use cases include:\n\n* Converting non-JSON request bodies to JSON (e.g. [`msgpack`](https://msgpack.org/index.html)).\n* Decompressing gzip-compressed request bodies.\n* Automatically logging all request bodies.\n\n## Handling custom request body encodings { #handling-custom-request-body-encodings }\n\nLet's see how to make use of a custom `Request` subclass to decompress gzip requests.\n\nAnd an `APIRoute` subclass to use that custom request class.\n\n### Create a custom `GzipRequest` class { #create-a-custom-gziprequest-class }\n\n/// tip\n\nThis is a toy example to demonstrate how it works, if you need Gzip support, you can use the provided [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware).\n\n///\n\nFirst, we create a `GzipRequest` class, which will overwrite the `Request.body()` method to decompress the body in the presence of an appropriate header.\n\nIf there's no `gzip` in the header, it will not try to decompress the body.\n\nThat way, the same route class can handle gzip compressed or uncompressed requests.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### Create a custom `GzipRoute` class { #create-a-custom-gziproute-class }\n\nNext, we create a custom subclass of `fastapi.routing.APIRoute` that will make use of the `GzipRequest`.\n\nThis time, it will overwrite the method `APIRoute.get_route_handler()`.\n\nThis method returns a function. And that function is what will receive a request and return a response.\n\nHere we use it to create a `GzipRequest` from the original request.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | Technical Details\n\nA `Request` has a `request.scope` attribute, that's just a Python `dict` containing the metadata related to the request.\n\nA `Request` also has a `request.receive`, that's a function to \"receive\" the body of the request.\n\nThe `scope` `dict` and `receive` function are both part of the ASGI specification.\n\nAnd those two things, `scope` and `receive`, are what is needed to create a new `Request` instance.\n\nTo learn more about the `Request` check [Starlette's docs about Requests](https://www.starlette.dev/requests/).\n\n///\n\nThe only thing the function returned by `GzipRequest.get_route_handler` does differently is convert the `Request` to a `GzipRequest`.\n\nDoing this, our `GzipRequest` will take care of decompressing the data (if necessary) before passing it to our *path operations*.\n\nAfter that, all of the processing logic is the same.\n\nBut because of our changes in `GzipRequest.body`, the request body will be automatically decompressed when it is loaded by **FastAPI** when needed.\n\n## Accessing the request body in an exception handler { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip\n\nTo solve this same problem, it's probably a lot easier to use the `body` in a custom handler for `RequestValidationError` ([Handling Errors](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)).\n\nBut this example is still valid and it shows how to interact with the internal components.\n\n///\n\nWe can also use this same approach to access the request body in an exception handler.\n\nAll we need to do is handle the request inside a `try`/`except` block:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\nIf an exception occurs, the`Request` instance will still be in scope, so we can read and make use of the request body when handling the error:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## Custom `APIRoute` class in a router { #custom-apiroute-class-in-a-router }\n\nYou can also set the `route_class` parameter of an `APIRouter`:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\nIn this example, the *path operations* under the `router` will use the custom `TimedRoute` class, and will have an extra `X-Response-Time` header in the response with the time it took to generate the response:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/en/docs/how-to/extending-openapi.md",
    "content": "# Extending OpenAPI { #extending-openapi }\n\nThere are some cases where you might need to modify the generated OpenAPI schema.\n\nIn this section you will see how.\n\n## The normal process { #the-normal-process }\n\nThe normal (default) process, is as follows.\n\nA `FastAPI` application (instance) has an `.openapi()` method that is expected to return the OpenAPI schema.\n\nAs part of the application object creation, a *path operation* for `/openapi.json` (or for whatever you set your `openapi_url`) is registered.\n\nIt just returns a JSON response with the result of the application's `.openapi()` method.\n\nBy default, what the method `.openapi()` does is check the property `.openapi_schema` to see if it has contents and return them.\n\nIf it doesn't, it generates them using the utility function at `fastapi.openapi.utils.get_openapi`.\n\nAnd that function `get_openapi()` receives as parameters:\n\n* `title`: The OpenAPI title, shown in the docs.\n* `version`: The version of your API, e.g. `2.5.0`.\n* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.1.0`.\n* `summary`: A short summary of the API.\n* `description`: The description of your API, this can include markdown and will be shown in the docs.\n* `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`.\n\n/// info\n\nThe parameter `summary` is available in OpenAPI 3.1.0 and above, supported by FastAPI 0.99.0 and above.\n\n///\n\n## Overriding the defaults { #overriding-the-defaults }\n\nUsing the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need.\n\nFor example, let's add [ReDoc's OpenAPI extension to include a custom logo](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo).\n\n### Normal **FastAPI** { #normal-fastapi }\n\nFirst, write all your **FastAPI** application as normally:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### Generate the OpenAPI schema { #generate-the-openapi-schema }\n\nThen, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### Modify the OpenAPI schema { #modify-the-openapi-schema }\n\nNow you can add the ReDoc extension, adding a custom `x-logo` to the `info` \"object\" in the OpenAPI schema:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### Cache the OpenAPI schema { #cache-the-openapi-schema }\n\nYou can use the property `.openapi_schema` as a \"cache\", to store your generated schema.\n\nThat way, your application won't have to generate the schema every time a user opens your API docs.\n\nIt will be generated only once, and then the same cached schema will be used for the next requests.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### Override the method { #override-the-method }\n\nNow you can replace the `.openapi()` method with your new function.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### Check it { #check-it }\n\nOnce you go to [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) you will see that you are using your custom logo (in this example, **FastAPI**'s logo):\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/en/docs/how-to/general.md",
    "content": "# General - How To - Recipes { #general-how-to-recipes }\n\nHere are several pointers to other places in the docs, for general or frequent questions.\n\n## Filter Data - Security { #filter-data-security }\n\nTo ensure that you don't return more data than you should, read the docs for [Tutorial - Response Model - Return Type](../tutorial/response-model.md).\n\n## Optimize Response Performance - Response Model - Return Type { #optimize-response-performance-response-model-return-type }\n\nTo optimize performance when returning JSON data, use a return type or response model, that way Pydantic will handle the serialization to JSON on the Rust side, without going through Python. Read more in the docs for [Tutorial - Response Model - Return Type](../tutorial/response-model.md).\n\n## Documentation Tags - OpenAPI { #documentation-tags-openapi }\n\nTo 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).\n\n## Documentation Summary and Description - OpenAPI { #documentation-summary-and-description-openapi }\n\nTo 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).\n\n## Documentation Response description - OpenAPI { #documentation-response-description-openapi }\n\nTo 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).\n\n## Documentation Deprecate a *Path Operation* - OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\nTo 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).\n\n## Convert any Data to JSON-compatible { #convert-any-data-to-json-compatible }\n\nTo convert any data to JSON-compatible, read the docs for [Tutorial - JSON Compatible Encoder](../tutorial/encoder.md).\n\n## OpenAPI Metadata - Docs { #openapi-metadata-docs }\n\nTo add metadata to your OpenAPI schema, including a license, version, contact, etc, read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md).\n\n## OpenAPI Custom URL { #openapi-custom-url }\n\nTo customize the OpenAPI URL (or remove it), read the docs for [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#openapi-url).\n\n## OpenAPI Docs URLs { #openapi-docs-urls }\n\nTo 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).\n"
  },
  {
    "path": "docs/en/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\nAs **FastAPI** is based on the **ASGI** standard, it's very easy to integrate any **GraphQL** library also compatible with ASGI.\n\nYou can combine normal FastAPI *path operations* with GraphQL on the same application.\n\n/// tip\n\n**GraphQL** solves some very specific use cases.\n\nIt has **advantages** and **disadvantages** when compared to common **web APIs**.\n\nMake sure you evaluate if the **benefits** for your use case compensate the **drawbacks**. 🤓\n\n///\n\n## GraphQL Libraries { #graphql-libraries }\n\nHere are some of the **GraphQL** libraries that have **ASGI** support. You could use them with **FastAPI**:\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * With [docs for FastAPI](https://strawberry.rocks/docs/integrations/fastapi)\n* [Ariadne](https://ariadnegraphql.org/)\n    * With [docs for FastAPI](https://ariadnegraphql.org/docs/fastapi-integration)\n* [Tartiflette](https://tartiflette.io/)\n    * With [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) to provide ASGI integration\n* [Graphene](https://graphene-python.org/)\n    * With [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)\n\n## GraphQL with Strawberry { #graphql-with-strawberry }\n\nIf you need or want to work with **GraphQL**, [**Strawberry**](https://strawberry.rocks/) is the **recommended** library as it has the design closest to **FastAPI's** design, it's all based on **type annotations**.\n\nDepending on your use case, you might prefer to use a different library, but if you asked me, I would probably suggest you try **Strawberry**.\n\nHere's a small preview of how you could integrate Strawberry with FastAPI:\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\nYou can learn more about Strawberry in the [Strawberry documentation](https://strawberry.rocks/).\n\nAnd also the docs about [Strawberry with FastAPI](https://strawberry.rocks/docs/integrations/fastapi).\n\n## Older `GraphQLApp` from Starlette { #older-graphqlapp-from-starlette }\n\nPrevious versions of Starlette included a `GraphQLApp` class to integrate with [Graphene](https://graphene-python.org/).\n\nIt was deprecated from Starlette, but if you have code that used it, you can easily **migrate** to [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3), that covers the same use case and has an **almost identical interface**.\n\n/// tip\n\nIf you need GraphQL, I still would recommend you check out [Strawberry](https://strawberry.rocks/), as it's based on type annotations instead of custom classes and types.\n\n///\n\n## Learn More { #learn-more }\n\nYou can learn more about **GraphQL** in the [official GraphQL documentation](https://graphql.org/).\n\nYou can also read more about each those libraries described above in their links.\n"
  },
  {
    "path": "docs/en/docs/how-to/index.md",
    "content": "# How To - Recipes { #how-to-recipes }\n\nHere you will see different recipes or \"how to\" guides for **several topics**.\n\nMost 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**.\n\nIf something seems interesting and useful to your project, go ahead and check it, but otherwise, you might probably just skip them.\n\n/// tip\n\nIf you want to **learn FastAPI** in a structured way (recommended), go and read the [Tutorial - User Guide](../tutorial/index.md) chapter by chapter instead.\n\n///\n"
  },
  {
    "path": "docs/en/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# Migrate from Pydantic v1 to Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\nIf you have an old FastAPI app, you might be using Pydantic version 1.\n\nFastAPI version 0.100.0 had support for either Pydantic v1 or v2. It would use whichever you had installed.\n\nFastAPI version 0.119.0 introduced partial support for Pydantic v1 from inside of Pydantic v2 (as `pydantic.v1`), to facilitate the migration to v2.\n\nFastAPI 0.126.0 dropped support for Pydantic v1, while still supporting `pydantic.v1` for a little while.\n\n/// warning\n\nThe Pydantic team stopped support for Pydantic v1 for the latest versions of Python, starting with **Python 3.14**.\n\nThis includes `pydantic.v1`, which is no longer supported in Python 3.14 and above.\n\nIf you want to use the latest features of Python, you will need to make sure you use Pydantic v2.\n\n///\n\nIf you have an old FastAPI app with Pydantic v1, here I'll show you how to migrate it to Pydantic v2, and the **features in FastAPI 0.119.0** to help you with a gradual migration.\n\n## Official Guide { #official-guide }\n\nPydantic has an official [Migration Guide](https://docs.pydantic.dev/latest/migration/) from v1 to v2.\n\nIt also includes what has changed, how validations are now more correct and strict, possible caveats, etc.\n\nYou can read it to understand better what has changed.\n\n## Tests { #tests }\n\nMake sure you have [tests](../tutorial/testing.md) for your app and you run them on continuous integration (CI).\n\nThis way, you can do the upgrade and make sure everything is still working as expected.\n\n## `bump-pydantic` { #bump-pydantic }\n\nIn many cases, when you use regular Pydantic models without customizations, you will be able to automate most of the process of migrating from Pydantic v1 to Pydantic v2.\n\nYou can use [`bump-pydantic`](https://github.com/pydantic/bump-pydantic) from the same Pydantic team.\n\nThis tool will help you to automatically change most of the code that needs to be changed.\n\nAfter this, you can run the tests and check if everything works. If it does, you are done. 😎\n\n## Pydantic v1 in v2 { #pydantic-v1-in-v2 }\n\nPydantic v2 includes everything from Pydantic v1 as a submodule `pydantic.v1`. But this is no longer supported in versions above Python 3.13.\n\nThis means that you can install the latest version of Pydantic v2 and import and use the old Pydantic v1 components from this submodule, as if you had the old Pydantic v1 installed.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### FastAPI support for Pydantic v1 in v2 { #fastapi-support-for-pydantic-v1-in-v2 }\n\nSince FastAPI 0.119.0, there's also partial support for Pydantic v1 from inside of Pydantic v2, to facilitate the migration to v2.\n\nSo, you could upgrade Pydantic to the latest version 2, and change the imports to use the `pydantic.v1` submodule, and in many cases it would just work.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning\n\nHave in mind that as the Pydantic team no longer supports Pydantic v1 in recent versions of Python, starting from Python 3.14, using `pydantic.v1` is also not supported in Python 3.14 and above.\n\n///\n\n### Pydantic v1 and v2 on the same app { #pydantic-v1-and-v2-on-the-same-app }\n\nIt's **not supported** by Pydantic to have a model of Pydantic v2 with its own fields defined as Pydantic v1 models or vice versa.\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n...but, you can have separated models using Pydantic v1 and v2 in the same app.\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\nIn some cases, it's even possible to have both Pydantic v1 and v2 models in the same **path operation** in your FastAPI app:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\nIn this example above, the input model is a Pydantic v1 model, and the output model (defined in `response_model=ItemV2`) is a Pydantic v2 model.\n\n### Pydantic v1 parameters { #pydantic-v1-parameters }\n\nIf you need to use some of the FastAPI-specific tools for parameters like `Body`, `Query`, `Form`, etc. with Pydantic v1 models, you can import them from `fastapi.temp_pydantic_v1_params` while you finish the migration to Pydantic v2:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### Migrate in steps { #migrate-in-steps }\n\n/// tip\n\nFirst try with `bump-pydantic`, if your tests pass and that works, then you're done in one command. ✨\n\n///\n\nIf `bump-pydantic` doesn't work for your use case, you can use the support for both Pydantic v1 and v2 models in the same app to do the migration to Pydantic v2 gradually.\n\nYou could fist upgrade Pydantic to use the latest version 2, and change the imports to use `pydantic.v1` for all your models.\n\nThen, you can start migrating your models from Pydantic v1 to v2 in groups, in gradual steps. 🚶\n"
  },
  {
    "path": "docs/en/docs/how-to/separate-openapi-schemas.md",
    "content": "# Separate OpenAPI Schemas for Input and Output or Not { #separate-openapi-schemas-for-input-and-output-or-not }\n\nSince **Pydantic v2** was released, the generated OpenAPI is a bit more exact and **correct** than before. 😎\n\nIn 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**.\n\nLet's see how that works and how to change it if you need to do that.\n\n## Pydantic Models for Input and Output { #pydantic-models-for-input-and-output }\n\nLet's say you have a Pydantic model with default values, like this one:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### Model for Input { #model-for-input }\n\nIf you use this model as an input like here:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n...then the `description` field will **not be required**. Because it has a default value of `None`.\n\n### Input Model in Docs { #input-model-in-docs }\n\nYou can confirm that in the docs, the `description` field doesn't have a **red asterisk**, it's not marked as required:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### Model for Output { #model-for-output }\n\nBut if you use the same model as an output, like here:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n...then because `description` has a default value, if you **don't return anything** for that field, it will still have that **default value**.\n\n### Model for Output Response Data { #model-for-output-response-data }\n\nIf 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`):\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\nThis means that it will **always have a value**, it's just that sometimes the value could be `None` (or `null` in JSON).\n\nThat 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`.\n\nThe way to describe this in OpenAPI, is to mark that field as **required**, because it will always be there.\n\nBecause of that, the JSON Schema for a model can be different depending on if it's used for **input or output**:\n\n* for **input** the `description` will **not be required**\n* for **output** it will be **required** (and possibly `None`, or in JSON terms, `null`)\n\n### Model for Output in Docs { #model-for-output-in-docs }\n\nYou can check the output model in the docs too, **both** `name` and `description` are marked as **required** with a **red asterisk**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### Model for Input and Output in Docs { #model-for-input-and-output-in-docs }\n\nAnd 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`.\n\nFor `Item-Input`, `description` is **not required**, it doesn't have a red asterisk.\n\nBut for `Item-Output`, `description` is **required**, it has a red asterisk.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\nWith 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. 🎉\n\n## Do not Separate Schemas { #do-not-separate-schemas }\n\nNow, there are some cases where you might want to have the **same schema for input and output**.\n\nProbably 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.\n\nIn that case, you can disable this feature in **FastAPI**, with the parameter `separate_input_output_schemas=False`.\n\n/// info\n\nSupport for `separate_input_output_schemas` was added in FastAPI `0.102.0`. 🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### Same Schema for Input and Output Models in Docs { #same-schema-for-input-and-output-models-in-docs }\n\nAnd now there will be one single schema for input and output for the model, only `Item`, and it will have `description` as **not required**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/en/docs/how-to/testing-database.md",
    "content": "# Testing a Database { #testing-a-database }\n\nYou can study about databases, SQL, and SQLModel in the [SQLModel docs](https://sqlmodel.tiangolo.com/). 🤓\n\nThere's a mini [tutorial on using SQLModel with FastAPI](https://sqlmodel.tiangolo.com/tutorial/fastapi/). ✨\n\nThat tutorial includes a section about [testing SQL databases](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/). 😎\n"
  },
  {
    "path": "docs/en/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**Documentation**: [https://fastapi.tiangolo.com](https://fastapi.tiangolo.com)\n\n**Source Code**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints.\n\nThe key features are:\n\n* **Fast**: Very high performance, on par with **NodeJS** and **Go** (thanks to Starlette and Pydantic). [One of the fastest Python frameworks available](#performance).\n* **Fast to code**: Increase the speed to develop features by about 200% to 300%. *\n* **Fewer bugs**: Reduce about 40% of human (developer) induced errors. *\n* **Intuitive**: Great editor support. <dfn title=\"also known as auto-complete, autocompletion, IntelliSense\">Completion</dfn> everywhere. Less time debugging.\n* **Easy**: Designed to be easy to use and learn. Less time reading docs.\n* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.\n* **Robust**: Get production-ready code. With automatic interactive documentation.\n* **Standards-based**: Based on (and fully compatible with) the open standards for APIs: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (previously known as Swagger) and [JSON Schema](https://json-schema.org/).\n\n<small>* estimation based on tests conducted by an internal development team, building production applications.</small>\n\n## Sponsors { #sponsors }\n\n<!-- sponsors -->\n\n### Keystone Sponsor { #keystone-sponsor }\n\n<div class=\"fastapi-sponsors fastapi-sponsors--keystone\">\n{% for sponsor in sponsors.keystone -%}\n<a class=\"fastapi-sponsors__card fastapi-sponsors__card--keystone\" href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img class=\"fastapi-sponsors__banner\" src=\"{{ sponsor.img }}\" alt=\"{{ sponsor.title }}\"></a>\n{% endfor -%}\n</div>\n\n### Gold Sponsors { #gold-sponsors }\n\n<div class=\"fastapi-sponsors fastapi-sponsors--gold\">\n{% for sponsor in sponsors.gold -%}\n<a class=\"fastapi-sponsors__card fastapi-sponsors__card--gold\" href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img class=\"fastapi-sponsors__banner\" src=\"{{ sponsor.img }}\" alt=\"{{ sponsor.title }}\" loading=\"lazy\"></a>\n{% endfor -%}\n</div>\n\n### Silver Sponsors { #silver-sponsors }\n\n<div class=\"fastapi-sponsors fastapi-sponsors--silver\">\n{% for sponsor in sponsors.silver -%}\n<a class=\"fastapi-sponsors__card fastapi-sponsors__card--silver\" href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img class=\"fastapi-sponsors__banner\" src=\"{{ sponsor.img }}\" alt=\"{{ sponsor.title }}\" loading=\"lazy\"></a>\n{% endfor %}\n</div>\n\n<!-- /sponsors -->\n\n[Other sponsors](https://fastapi.tiangolo.com/fastapi-people/#sponsors)\n\n## Opinions { #opinions }\n\n<!-- only-mkdocs -->\n<div class=\"fastapi-opinions\" data-fastapi-opinions>\n  <div class=\"fastapi-opinions__tabs\" role=\"tablist\" aria-label=\"Companies using FastAPI\">\n    <button class=\"fastapi-opinions__tab\" role=\"tab\" type=\"button\" id=\"fo-tab-microsoft\" aria-controls=\"fo-panel-microsoft\" aria-selected=\"true\" tabindex=\"0\">\n      <span class=\"fastapi-opinions__mark\"><img src=\"img/logos/microsoft.svg\" alt=\"Microsoft\" loading=\"lazy\"></span>\n    </button>\n    <button class=\"fastapi-opinions__tab\" role=\"tab\" type=\"button\" id=\"fo-tab-uber\" aria-controls=\"fo-panel-uber\" aria-selected=\"false\" tabindex=\"-1\">\n      <span class=\"fastapi-opinions__mark\"><img src=\"img/logos/uber.svg\" alt=\"Uber\" loading=\"lazy\"></span>\n    </button>\n    <button class=\"fastapi-opinions__tab\" role=\"tab\" type=\"button\" id=\"fo-tab-netflix\" aria-controls=\"fo-panel-netflix\" aria-selected=\"false\" tabindex=\"-1\">\n      <span class=\"fastapi-opinions__mark\"><img src=\"img/logos/netflix.svg\" alt=\"Netflix\" loading=\"lazy\"></span>\n    </button>\n    <button class=\"fastapi-opinions__tab\" role=\"tab\" type=\"button\" id=\"fo-tab-cisco\" aria-controls=\"fo-panel-cisco\" aria-selected=\"false\" tabindex=\"-1\">\n      <span class=\"fastapi-opinions__mark\"><img src=\"img/logos/cisco.svg\" alt=\"Cisco\" loading=\"lazy\"></span>\n    </button>\n  </div>\n\n  <div class=\"fastapi-opinions__panel\" id=\"fo-panel-microsoft\" role=\"tabpanel\" aria-labelledby=\"fo-tab-microsoft\" tabindex=\"0\">\n    <blockquote class=\"fastapi-opinions__quote\">\"I'm using <strong>FastAPI</strong> a ton these days. I'm actually planning to use it for all of my team's <strong>ML services at Microsoft</strong>. Some of them are getting integrated into the core <strong>Windows</strong> product and some <strong>Office</strong> products.\"</blockquote>\n    <div class=\"fastapi-opinions__attr\">— Kabir Khan, <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\">(ref)</a></div>\n  </div>\n  <div class=\"fastapi-opinions__panel\" id=\"fo-panel-uber\" role=\"tabpanel\" aria-labelledby=\"fo-tab-uber\" tabindex=\"0\" hidden>\n    <blockquote class=\"fastapi-opinions__quote\">\"We adopted the <strong>FastAPI</strong> library to spawn a <strong>REST</strong> server that can be queried to obtain <strong>predictions</strong>.\" <em>[for Ludwig]</em></blockquote>\n    <div class=\"fastapi-opinions__attr\">— Piero Molino, Yaroslav Dudin, Sai Sumanth Miryala, <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\">(ref)</a></div>\n  </div>\n  <div class=\"fastapi-opinions__panel\" id=\"fo-panel-netflix\" role=\"tabpanel\" aria-labelledby=\"fo-tab-netflix\" tabindex=\"0\" hidden>\n    <blockquote class=\"fastapi-opinions__quote\">\"<strong>Netflix</strong> is pleased to announce the open-source release of our <strong>crisis management</strong> orchestration framework: <strong>Dispatch</strong>!\" <em>[built with FastAPI]</em></blockquote>\n    <div class=\"fastapi-opinions__attr\">— Kevin Glisson, Marc Vilanova, Forest Monsen, <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\">(ref)</a></div>\n  </div>\n  <div class=\"fastapi-opinions__panel\" id=\"fo-panel-cisco\" role=\"tabpanel\" aria-labelledby=\"fo-tab-cisco\" tabindex=\"0\" hidden>\n    <blockquote class=\"fastapi-opinions__quote\">\"If anyone is looking to build a production Python API, I would highly recommend <strong>FastAPI</strong>. It is <strong>beautifully designed</strong>, <strong>simple to use</strong> and <strong>highly scalable</strong> — it has become a <strong>key component</strong> in our API-first development strategy.\"</blockquote>\n    <div class=\"fastapi-opinions__attr\">— Deon Pillsbury, <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\">(ref)</a></div>\n  </div>\n</div>\n<!-- /only-mkdocs -->\n\n<div class=\"only-github\" markdown=\"1\">\n\n\"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n\"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n\"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n\"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our Virtual TAC Engineer._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n</div>\n\n## FastAPI Conf { #fastapi-conf }\n\n[**FastAPI Conf '26**](https://fastapiconf.com) is happening on **October 28, 2026** in **Amsterdam, NL**. All about FastAPI, right from the source. 🎤\n\n<a class=\"fastapi-feature-banner\" href=\"https://fastapiconf.com\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-conf.jpeg\" alt=\"FastAPI Conf '26 - October 28, 2026 - Amsterdam, NL\"></a>\n\n## FastAPI mini documentary { #fastapi-mini-documentary }\n\nThere's a [FastAPI mini documentary](https://www.youtube.com/watch?v=mpR8ngthqiE) released at the end of 2025, you can watch it online:\n\n<a class=\"fastapi-feature-banner\" href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**, the FastAPI of CLIs { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\nIf you are building a <abbr title=\"Command Line Interface\">CLI</abbr> app to be used in the terminal instead of a web API, check out [**Typer**](https://typer.tiangolo.com/).\n\n**Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀\n\n## Requirements { #requirements }\n\nFastAPI stands on the shoulders of giants:\n\n* [Starlette](https://www.starlette.dev/) for the web parts.\n* [Pydantic](https://docs.pydantic.dev/) for the data parts.\n\n## Installation { #installation }\n\nCreate and activate a [virtual environment](https://fastapi.tiangolo.com/virtual-environments/) and then install FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Note**: Make sure you put `\"fastapi[standard]\"` in quotes to ensure it works in all terminals.\n\n## Example { #example }\n\n### Create it { #create-it }\n\nCreate a file `main.py` with:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>Or use <code>async def</code>...</summary>\n\nIf your code uses `async` / `await`, use `async def`:\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Note**:\n\nIf you don't know, check the _\"In a hurry?\"_ section about [`async` and `await` in the docs](https://fastapi.tiangolo.com/async/#in-a-hurry).\n\n</details>\n\n### Run it { #run-it }\n\nRun the server with:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary>About the command <code>fastapi dev</code>...</summary>\n\nThe command `fastapi dev` reads your `main.py` file automatically, detects the **FastAPI** app in it, and starts a server using [Uvicorn](https://www.uvicorn.dev).\n\nBy default, `fastapi dev` will start with auto-reload enabled for local development.\n\nYou can read more about it in the [FastAPI CLI docs](https://fastapi.tiangolo.com/fastapi-cli/).\n\n</details>\n\n### Check it { #check-it }\n\nOpen your browser at [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery).\n\nYou will see the JSON response as:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\nYou already created an API that:\n\n* Receives HTTP requests in the _paths_ `/` and `/items/{item_id}`.\n* Both _paths_ take `GET` <em>operations</em> (also known as HTTP _methods_).\n* The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.\n* The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.\n\n### Interactive API docs { #interactive-api-docs }\n\nNow go to [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nYou will see the automatic interactive API documentation (provided by [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Alternative API docs { #alternative-api-docs }\n\nAnd now, go to [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nYou will see the alternative automatic documentation (provided by [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Example upgrade { #example-upgrade }\n\nNow modify the file `main.py` to receive a body from a `PUT` request.\n\nDeclare the body using standard Python types, thanks to Pydantic.\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\nThe `fastapi dev` server should reload automatically.\n\n### Interactive API docs upgrade { #interactive-api-docs-upgrade }\n\nNow go to [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n* The interactive API documentation will be automatically updated, including the new body:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Click on the button \"Try it out\", it allows you to fill the parameters and directly interact with the API:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* Then click on the \"Execute\" button, the user interface will communicate with your API, send the parameters, get the results and show them on the screen:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### Alternative API docs upgrade { #alternative-api-docs-upgrade }\n\nAnd now, go to [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\n* The alternative documentation will also reflect the new query parameter and body:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Recap { #recap }\n\nIn summary, you declare **once** the types of parameters, body, etc. as function parameters.\n\nYou do that with standard modern Python types.\n\nYou don't have to learn a new syntax, the methods or classes of a specific library, etc.\n\nJust standard **Python**.\n\nFor example, for an `int`:\n\n```Python\nitem_id: int\n```\n\nor for a more complex `Item` model:\n\n```Python\nitem: Item\n```\n\n...and with that single declaration you get:\n\n* Editor support, including:\n    * Completion.\n    * Type checks.\n* Validation of data:\n    * Automatic and clear errors when the data is invalid.\n    * Validation even for deeply nested JSON objects.\n* <dfn title=\"also known as: serialization, parsing, marshalling\">Conversion</dfn> of input data: coming from the network to Python data and types. Reading from:\n    * JSON.\n    * Path parameters.\n    * Query parameters.\n    * Cookies.\n    * Headers.\n    * Forms.\n    * Files.\n* <dfn title=\"also known as: serialization, parsing, marshalling\">Conversion</dfn> of output data: converting from Python data and types to network data (as JSON):\n    * Convert Python types (`str`, `int`, `float`, `bool`, `list`, etc).\n    * `datetime` objects.\n    * `UUID` objects.\n    * Database models.\n    * ...and many more.\n* Automatic interactive API documentation, including 2 alternative user interfaces:\n    * Swagger UI.\n    * ReDoc.\n\n---\n\nComing back to the previous code example, **FastAPI** will:\n\n* Validate that there is an `item_id` in the path for `GET` and `PUT` requests.\n* Validate that the `item_id` is of type `int` for `GET` and `PUT` requests.\n    * If it is not, the client will see a useful, clear error.\n* Check if there is an optional query parameter named `q` (as in `http://127.0.0.1:8000/items/foo?q=somequery`) for `GET` requests.\n    * As the `q` parameter is declared with `= None`, it is optional.\n    * Without the `None` it would be required (as is the body in the case with `PUT`).\n* For `PUT` requests to `/items/{item_id}`, read the body as JSON:\n    * Check that it has a required attribute `name` that should be a `str`.\n    * Check that it has a required attribute `price` that has to be a `float`.\n    * Check that it has an optional attribute `is_offer`, that should be a `bool`, if present.\n    * All this would also work for deeply nested JSON objects.\n* Convert from and to JSON automatically.\n* Document everything with OpenAPI, that can be used by:\n    * Interactive documentation systems.\n    * Automatic client code generation systems, for many languages.\n* Provide 2 interactive documentation web interfaces directly.\n\n---\n\nWe just scratched the surface, but you already get the idea of how it all works.\n\nTry changing the line with:\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n...from:\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n...to:\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n...and see how your editor will auto-complete the attributes and know their types:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\nFor a more complete example including more features, see the <a href=\"https://fastapi.tiangolo.com/tutorial/\">Tutorial - User Guide</a>.\n\n**Spoiler alert**: the tutorial - user guide includes:\n\n* Declaration of **parameters** from other different places as: **headers**, **cookies**, **form fields** and **files**.\n* How to set **validation constraints** as `maximum_length` or `regex`.\n* A very powerful and easy to use **<dfn title=\"also known as components, resources, providers, services, injectables\">Dependency Injection</dfn>** system.\n* Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth.\n* More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic).\n* **GraphQL** integration with [Strawberry](https://strawberry.rocks) and other libraries.\n* Many extra features (thanks to Starlette) as:\n    * **WebSockets**\n    * extremely easy tests based on HTTPX and `pytest`\n    * **CORS**\n    * **Cookie Sessions**\n    * ...and more.\n\n### Deploy your app (optional) { #deploy-your-app-optional }\n\nYou can optionally deploy your FastAPI app to [FastAPI Cloud](https://fastapicloud.com), go and join the waiting list if you haven't. 🚀\n\nIf you already have a **FastAPI Cloud** account (we invited you from the waiting list 😉), you can deploy your application with one command.\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nThat's it! Now you can access your app at that URL. ✨\n\n#### About FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** is built by the same author and team behind **FastAPI**.\n\nIt streamlines the process of **building**, **deploying**, and **accessing** an API with minimal effort.\n\nIt brings the same **developer experience** of building apps with FastAPI to **deploying** them to the cloud. 🎉\n\nFastAPI Cloud is the primary sponsor and funding provider for the *FastAPI and friends* open source projects. ✨\n\n#### Deploy to other cloud providers { #deploy-to-other-cloud-providers }\n\nFastAPI is open source and based on standards. You can deploy FastAPI apps to any cloud provider you choose.\n\nFollow your cloud provider's guides to deploy FastAPI apps with them. 🤓\n\n## Performance { #performance }\n\nIndependent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as [one of the fastest Python frameworks available](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)\n\nTo understand more about it, see the section [Benchmarks](https://fastapi.tiangolo.com/benchmarks/).\n\n## Dependencies { #dependencies }\n\nFastAPI depends on Pydantic and Starlette.\n\n### `standard` Dependencies { #standard-dependencies }\n\nWhen you install FastAPI with `pip install \"fastapi[standard]\"` it comes with the `standard` group of optional dependencies:\n\nUsed by Pydantic:\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - for email validation.\n\nUsed by Starlette:\n\n* [`httpx`](https://www.python-httpx.org) - Required if you want to use the `TestClient`.\n* [`jinja2`](https://jinja.palletsprojects.com) - Required if you want to use the default template configuration.\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - Required if you want to support form <dfn title=\"converting the string that comes from an HTTP request into Python data\">\"parsing\"</dfn>, with `request.form()`.\n\nUsed by FastAPI:\n\n* [`uvicorn`](https://www.uvicorn.dev) - for the server that loads and serves your application. This includes `uvicorn[standard]`, which includes some dependencies (e.g. `uvloop`) needed for high performance serving.\n* `fastapi-cli[standard]` - to provide the `fastapi` command.\n    * This includes `fastapi-cloud-cli`, which allows you to deploy your FastAPI application to [FastAPI Cloud](https://fastapicloud.com).\n\n### Without `standard` Dependencies { #without-standard-dependencies }\n\nIf you don't want to include the `standard` optional dependencies, you can install with `pip install fastapi` instead of `pip install \"fastapi[standard]\"`.\n\n### Without `fastapi-cloud-cli` { #without-fastapi-cloud-cli }\n\nIf you want to install FastAPI with the standard dependencies but without the `fastapi-cloud-cli`, you can install with `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n### Additional Optional Dependencies { #additional-optional-dependencies }\n\nThere are some additional dependencies you might want to install.\n\nAdditional optional Pydantic dependencies:\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - for settings management.\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - for extra types to be used with Pydantic.\n\nAdditional optional FastAPI dependencies:\n\n* [`orjson`](https://github.com/ijl/orjson) - Required if you want to use `ORJSONResponse`.\n* [`ujson`](https://github.com/esnme/ultrajson) - Required if you want to use `UJSONResponse`.\n\n## License { #license }\n\nThis project is licensed under the terms of the MIT license.\n"
  },
  {
    "path": "docs/en/docs/js/custom.js",
    "content": "function setupTermynal() {\n    document.querySelectorAll(\".use-termynal\").forEach(node => {\n        node.style.display = \"block\";\n        new Termynal(node, {\n            lineDelay: 500\n        });\n    });\n    const progressLiteralStart = \"---> 100%\";\n    const promptLiteralStart = \"$ \";\n    const customPromptLiteralStart = \"# \";\n    const termynalActivateClass = \"termy\";\n    let termynals = [];\n\n    function createTermynals() {\n        document\n            .querySelectorAll(`.${termynalActivateClass} .highlight code`)\n            .forEach(node => {\n                const text = node.textContent;\n                const lines = text.split(\"\\n\");\n                const useLines = [];\n                let buffer = [];\n                function saveBuffer() {\n                    if (buffer.length) {\n                        let isBlankSpace = true;\n                        buffer.forEach(line => {\n                            if (line) {\n                                isBlankSpace = false;\n                            }\n                        });\n                        dataValue = {};\n                        if (isBlankSpace) {\n                            dataValue[\"delay\"] = 0;\n                        }\n                        if (buffer[buffer.length - 1] === \"\") {\n                            // A last single <br> won't have effect\n                            // so put an additional one\n                            buffer.push(\"\");\n                        }\n                        const bufferValue = buffer.join(\"<br>\");\n                        dataValue[\"value\"] = bufferValue;\n                        useLines.push(dataValue);\n                        buffer = [];\n                    }\n                }\n                for (let line of lines) {\n                    if (line === progressLiteralStart) {\n                        saveBuffer();\n                        useLines.push({\n                            type: \"progress\"\n                        });\n                    } else if (line.startsWith(promptLiteralStart)) {\n                        saveBuffer();\n                        const value = line.replace(promptLiteralStart, \"\").trimEnd();\n                        useLines.push({\n                            type: \"input\",\n                            value: value\n                        });\n                    } else if (line.startsWith(\"// \")) {\n                        saveBuffer();\n                        const value = \"💬 \" + line.replace(\"// \", \"\").trimEnd();\n                        useLines.push({\n                            value: value,\n                            class: \"termynal-comment\",\n                            delay: 0\n                        });\n                    } else if (line.startsWith(customPromptLiteralStart)) {\n                        saveBuffer();\n                        const promptStart = line.indexOf(promptLiteralStart);\n                        if (promptStart === -1) {\n                            console.error(\"Custom prompt found but no end delimiter\", line)\n                        }\n                        const prompt = line.slice(0, promptStart).replace(customPromptLiteralStart, \"\")\n                        let value = line.slice(promptStart + promptLiteralStart.length);\n                        useLines.push({\n                            type: \"input\",\n                            value: value,\n                            prompt: prompt\n                        });\n                    } else {\n                        buffer.push(line);\n                    }\n                }\n                saveBuffer();\n                const inputCommands = useLines\n                    .filter(line => line.type === \"input\")\n                    .map(line => line.value)\n                    .join(\"\\n\");\n                node.textContent = inputCommands;\n                const div = document.createElement(\"div\");\n                node.style.display = \"none\";\n                node.after(div);\n                const termynal = new Termynal(div, {\n                    lineData: useLines,\n                    noInit: true,\n                    lineDelay: 500\n                });\n                termynals.push(termynal);\n            });\n    }\n\n    function loadVisibleTermynals() {\n        termynals = termynals.filter(termynal => {\n            if (termynal.container.getBoundingClientRect().top - innerHeight <= 0) {\n                termynal.init();\n                return false;\n            }\n            return true;\n        });\n    }\n    window.addEventListener(\"scroll\", loadVisibleTermynals);\n    createTermynals();\n    loadVisibleTermynals();\n}\n\nfunction shuffle(array) {\n    var currentIndex = array.length, temporaryValue, randomIndex;\n    while (0 !== currentIndex) {\n        randomIndex = Math.floor(Math.random() * currentIndex);\n        currentIndex -= 1;\n        temporaryValue = array[currentIndex];\n        array[currentIndex] = array[randomIndex];\n        array[randomIndex] = temporaryValue;\n    }\n    return array;\n}\n\nasync function showRandomAnnouncement(groupId, timeInterval) {\n    const announceFastAPI = document.getElementById(groupId);\n    if (announceFastAPI) {\n        let children = [].slice.call(announceFastAPI.children);\n        children = shuffle(children)\n        let index = 0\n        const announceRandom = () => {\n            children.forEach((el, i) => { el.style.display = \"none\" });\n            children[index].style.display = \"block\"\n            index = (index + 1) % children.length\n        }\n        announceRandom()\n        setInterval(announceRandom, timeInterval\n        )\n    }\n}\n\nfunction handleSponsorImages() {\n    const announceRight = document.getElementById('announce-right');\n    if(!announceRight) return;\n\n    const sponsorImages = document.querySelectorAll('.sponsor-image');\n\n    const imagePromises = Array.from(sponsorImages).map(img => {\n        return new Promise((resolve, reject) => {\n            if (img.complete && img.naturalHeight !== 0) {\n                resolve();\n            } else {\n                img.addEventListener('load', () => {\n                    if (img.naturalHeight !== 0) {\n                        resolve();\n                    } else {\n                        reject();\n                    }\n                });\n                img.addEventListener('error', reject);\n            }\n        });\n    });\n\n    Promise.all(imagePromises)\n        .then(() => {\n            announceRight.style.display = 'block';\n            showRandomAnnouncement('announce-right', 10000);\n        })\n        .catch(() => {\n            // do nothing\n        });\n}\n\nfunction openLinksInNewTab() {\n    const siteUrl = document.querySelector(\"link[rel='canonical']\")?.href\n        || window.location.origin;\n    const siteOrigin = new URL(siteUrl).origin;\n    document.querySelectorAll(\".md-content a[href]\").forEach(a => {\n        if (a.getAttribute(\"target\") === \"_self\") return;\n        const href = a.getAttribute(\"href\");\n        if (!href) return;\n        try {\n            const url = new URL(href, window.location.href);\n            // Skip same-page anchor links (only the hash differs)\n            if (url.origin === window.location.origin\n                && url.pathname === window.location.pathname\n                && url.search === window.location.search) return;\n            if (!a.hasAttribute(\"target\")) {\n                a.setAttribute(\"target\", \"_blank\");\n                a.setAttribute(\"rel\", \"noopener\");\n            }\n            if (url.origin !== siteOrigin) {\n                a.dataset.externalLink = \"\";\n            } else {\n                a.dataset.internalLink = \"\";\n            }\n        } catch (_) {}\n    });\n}\n\nfunction setupOpinionsTabs() {\n    const root = document.querySelector('.fastapi-opinions');\n    if (!root) return;\n    const tabs = Array.from(root.querySelectorAll('[role=\"tab\"]'));\n    const panels = Array.from(root.querySelectorAll('[role=\"tabpanel\"]'));\n    if (!tabs.length) return;\n\n    function activate(tab, focus) {\n        tabs.forEach(t => {\n            const selected = t === tab;\n            t.setAttribute('aria-selected', selected ? 'true' : 'false');\n            t.setAttribute('tabindex', selected ? '0' : '-1');\n        });\n        const targetId = tab.getAttribute('aria-controls');\n        panels.forEach(p => {\n            if (p.id === targetId) p.removeAttribute('hidden');\n            else p.setAttribute('hidden', '');\n        });\n        if (focus) tab.focus();\n    }\n\n    tabs.forEach((tab, i) => {\n        tab.addEventListener('click', () => activate(tab, false));\n        tab.addEventListener('keydown', (e) => {\n            let next = null;\n            if (e.key === 'ArrowRight') next = tabs[(i + 1) % tabs.length];\n            else if (e.key === 'ArrowLeft') next = tabs[(i - 1 + tabs.length) % tabs.length];\n            else if (e.key === 'Home') next = tabs[0];\n            else if (e.key === 'End') next = tabs[tabs.length - 1];\n            if (next) {\n                e.preventDefault();\n                activate(next, true);\n            }\n        });\n    });\n}\n\nasync function main() {\n    setupTermynal();\n    showRandomAnnouncement('announce-left', 5000)\n    handleSponsorImages();\n    openLinksInNewTab();\n    setupOpinionsTabs();\n}\ndocument$.subscribe(() => {\n    main()\n})\n"
  },
  {
    "path": "docs/en/docs/js/init_kapa_widget.js",
    "content": "document.addEventListener(\"DOMContentLoaded\", function () {\n  var script = document.createElement(\"script\");\n  script.src = \"https://widget.kapa.ai/kapa-widget.bundle.js\";\n  script.setAttribute(\"data-website-id\", \"91f47f27-b405-4299-bf5f-a1c0ec07b3cc\");\n  script.setAttribute(\"data-project-name\", \"FastAPI\");\n  script.setAttribute(\"data-project-color\", \"#009485\");\n  script.setAttribute(\"data-project-logo\", \"https://fastapi.tiangolo.com/img/favicon.png\");\n  script.setAttribute(\"data-bot-protection-mechanism\", \"hcaptcha\");\n  script.setAttribute(\"data-button-height\", \"3rem\");\n  script.setAttribute(\"data-button-width\", \"3rem\");\n  script.setAttribute(\"data-button-border-radius\", \"50%\");\n  script.setAttribute(\"data-button-padding\", \"0\");\n  script.setAttribute(\"data-button-image\", \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 8V4H8'/%3E%3Crect width='16' height='12' x='4' y='8' rx='2'/%3E%3Cpath d='M2 14h2'/%3E%3Cpath d='M20 14h2'/%3E%3Cpath d='M15 13v2'/%3E%3Cpath d='M9 13v2'/%3E%3C/svg%3E\");\n  script.setAttribute(\"data-button-image-height\", \"20px\");\n  script.setAttribute(\"data-button-image-width\", \"20px\");\n  script.setAttribute(\"data-button-text\", \"Ask AI\");\n  script.setAttribute(\"data-button-text-font-size\", \"0.5rem\");\n  script.setAttribute(\"data-button-text-font-family\", \"Roboto, sans-serif\");\n  script.setAttribute(\"data-button-text-color\", \"#FFFFFF\");\n  script.setAttribute(\"data-modal-border-radius\", \"0.5rem\");\n  script.setAttribute(\"data-modal-header-bg-color\", \"#009485\");\n  script.setAttribute(\"data-modal-title\", \"FastAPI AI Assistant\");\n  script.setAttribute(\"data-modal-title-color\", \"#FFFFFF\");\n  script.setAttribute(\"data-modal-title-font-family\", \"Roboto, sans-serif\");\n  script.setAttribute(\"data-modal-example-questions\", \"How to define a route?,How to validate models?,How to handle responses?,How to deploy FastAPI?\");\n  script.setAttribute(\"data-modal-disclaimer\", \"AI-generated answers based on FastAPI [documentation](https://fastapi.tiangolo.com/) and [community discussions](https://github.com/fastapi/fastapi/discussions). Always verify important information.\");\n  script.async = true;\n  document.head.appendChild(script);\n});\n"
  },
  {
    "path": "docs/en/docs/js/termynal.js",
    "content": "/**\n * termynal.js\n * A lightweight, modern and extensible animated terminal window, using\n * async/await.\n *\n * @author Ines Montani <ines@ines.io>\n * @version 0.0.1\n * @license MIT\n */\n\n'use strict';\n\n/** Generate a terminal widget. */\nclass Termynal {\n    /**\n     * Construct the widget's settings.\n     * @param {(string|Node)=} container - Query selector or container element.\n     * @param {Object=} options - Custom settings.\n     * @param {string} options.prefix - Prefix to use for data attributes.\n     * @param {number} options.startDelay - Delay before animation, in ms.\n     * @param {number} options.typeDelay - Delay between each typed character, in ms.\n     * @param {number} options.lineDelay - Delay between each line, in ms.\n     * @param {number} options.progressLength - Number of characters displayed as progress bar.\n     * @param {string} options.progressChar – Character to use for progress bar, defaults to █.\n\t * @param {number} options.progressPercent - Max percent of progress.\n     * @param {string} options.cursor – Character to use for cursor, defaults to ▋.\n     * @param {Object[]} lineData - Dynamically loaded line data objects.\n     * @param {boolean} options.noInit - Don't initialise the animation.\n     */\n    constructor(container = '#termynal', options = {}) {\n        this.container = (typeof container === 'string') ? document.querySelector(container) : container;\n        this.pfx = `data-${options.prefix || 'ty'}`;\n        this.originalStartDelay = this.startDelay = options.startDelay\n            || parseFloat(this.container.getAttribute(`${this.pfx}-startDelay`)) || 600;\n        this.originalTypeDelay = this.typeDelay = options.typeDelay\n            || parseFloat(this.container.getAttribute(`${this.pfx}-typeDelay`)) || 90;\n        this.originalLineDelay = this.lineDelay = options.lineDelay\n            || parseFloat(this.container.getAttribute(`${this.pfx}-lineDelay`)) || 1500;\n        this.progressLength = options.progressLength\n            || parseFloat(this.container.getAttribute(`${this.pfx}-progressLength`)) || 40;\n        this.progressChar = options.progressChar\n            || this.container.getAttribute(`${this.pfx}-progressChar`) || '█';\n\t\tthis.progressPercent = options.progressPercent\n            || parseFloat(this.container.getAttribute(`${this.pfx}-progressPercent`)) || 100;\n        this.cursor = options.cursor\n            || this.container.getAttribute(`${this.pfx}-cursor`) || '▋';\n        this.lineData = this.lineDataToElements(options.lineData || []);\n        this.loadLines()\n        if (!options.noInit) this.init()\n    }\n\n    loadLines() {\n        // Load all the lines and create the container so that the size is fixed\n        // Otherwise it would be changing and the user viewport would be constantly\n        // moving as she/he scrolls\n        const finish = this.generateFinish()\n        finish.style.visibility = 'hidden'\n        this.container.appendChild(finish)\n        // Appends dynamically loaded lines to existing line elements.\n        this.lines = [...this.container.querySelectorAll(`[${this.pfx}]`)].concat(this.lineData);\n        for (let line of this.lines) {\n            line.style.visibility = 'hidden'\n            this.container.appendChild(line)\n        }\n        const restart = this.generateRestart()\n        restart.style.visibility = 'hidden'\n        this.container.appendChild(restart)\n        this.container.setAttribute('data-termynal', '');\n    }\n\n    /**\n     * Initialise the widget, get lines, clear container and start animation.\n     */\n    init() {\n        /**\n         * Calculates width and height of Termynal container.\n         * If container is empty and lines are dynamically loaded, defaults to browser `auto` or CSS.\n         */\n        const containerStyle = getComputedStyle(this.container);\n        this.container.style.width = containerStyle.width !== '0px' ?\n            containerStyle.width : undefined;\n        this.container.style.minHeight = containerStyle.height !== '0px' ?\n            containerStyle.height : undefined;\n\n        this.container.setAttribute('data-termynal', '');\n        this.container.innerHTML = '';\n        for (let line of this.lines) {\n            line.style.visibility = 'visible'\n        }\n        this.start();\n    }\n\n    /**\n     * Start the animation and rener the lines depending on their data attributes.\n     */\n    async start() {\n        this.addFinish()\n        await this._wait(this.startDelay);\n\n        for (let line of this.lines) {\n            const type = line.getAttribute(this.pfx);\n            const delay = line.getAttribute(`${this.pfx}-delay`) || this.lineDelay;\n\n            if (type == 'input') {\n                line.setAttribute(`${this.pfx}-cursor`, this.cursor);\n                await this.type(line);\n                await this._wait(delay);\n            }\n\n            else if (type == 'progress') {\n                await this.progress(line);\n                await this._wait(delay);\n            }\n\n            else {\n                this.container.appendChild(line);\n                await this._wait(delay);\n            }\n\n            line.removeAttribute(`${this.pfx}-cursor`);\n        }\n        this.addRestart()\n        this.finishElement.style.visibility = 'hidden'\n        this.lineDelay = this.originalLineDelay\n        this.typeDelay = this.originalTypeDelay\n        this.startDelay = this.originalStartDelay\n    }\n\n    generateRestart() {\n        const restart = document.createElement('a')\n        restart.onclick = (e) => {\n            e.preventDefault()\n            this.container.innerHTML = ''\n            this.init()\n        }\n        restart.href = \"javascript:void(0)\"\n        restart.setAttribute('data-terminal-control', '')\n        restart.innerHTML = \"restart ↻\"\n        return restart\n    }\n\n    generateFinish() {\n        const finish = document.createElement('a')\n        finish.onclick = (e) => {\n            e.preventDefault()\n            this.lineDelay = 0\n            this.typeDelay = 0\n            this.startDelay = 0\n        }\n        finish.href = \"javascript:void(0)\"\n        finish.setAttribute('data-terminal-control', '')\n        finish.innerHTML = \"fast →\"\n        this.finishElement = finish\n        return finish\n    }\n\n    addRestart() {\n        const restart = this.generateRestart()\n        this.container.appendChild(restart)\n    }\n\n    addFinish() {\n        const finish = this.generateFinish()\n        this.container.appendChild(finish)\n    }\n\n    /**\n     * Animate a typed line.\n     * @param {Node} line - The line element to render.\n     */\n    async type(line) {\n        const chars = [...line.textContent];\n        line.textContent = '';\n        this.container.appendChild(line);\n\n        for (let char of chars) {\n            const delay = line.getAttribute(`${this.pfx}-typeDelay`) || this.typeDelay;\n            await this._wait(delay);\n            line.textContent += char;\n        }\n    }\n\n    /**\n     * Animate a progress bar.\n     * @param {Node} line - The line element to render.\n     */\n    async progress(line) {\n        const progressLength = line.getAttribute(`${this.pfx}-progressLength`)\n            || this.progressLength;\n        const progressChar = line.getAttribute(`${this.pfx}-progressChar`)\n            || this.progressChar;\n        const chars = progressChar.repeat(progressLength);\n\t\tconst progressPercent = line.getAttribute(`${this.pfx}-progressPercent`)\n\t\t\t|| this.progressPercent;\n        line.textContent = '';\n        this.container.appendChild(line);\n\n        for (let i = 1; i < chars.length + 1; i++) {\n            await this._wait(this.typeDelay);\n            const percent = Math.round(i / chars.length * 100);\n            line.textContent = `${chars.slice(0, i)} ${percent}%`;\n\t\t\tif (percent>progressPercent) {\n\t\t\t\tbreak;\n\t\t\t}\n        }\n    }\n\n    /**\n     * Helper function for animation delays, called with `await`.\n     * @param {number} time - Timeout, in ms.\n     */\n    _wait(time) {\n        return new Promise(resolve => setTimeout(resolve, time));\n    }\n\n    /**\n     * Converts line data objects into line elements.\n     *\n     * @param {Object[]} lineData - Dynamically loaded lines.\n     * @param {Object} line - Line data object.\n     * @returns {Element[]} - Array of line elements.\n     */\n    lineDataToElements(lineData) {\n        return lineData.map(line => {\n            let div = document.createElement('div');\n            div.innerHTML = `<span ${this._attributes(line)}>${line.value || ''}</span>`;\n\n            return div.firstElementChild;\n        });\n    }\n\n    /**\n     * Helper function for generating attributes string.\n     *\n     * @param {Object} line - Line data object.\n     * @returns {string} - String of attributes.\n     */\n    _attributes(line) {\n        let attrs = '';\n        for (let prop in line) {\n            // Custom add class\n            if (prop === 'class') {\n                attrs += ` class=${line[prop]} `\n                continue\n            }\n            if (prop === 'type') {\n                attrs += `${this.pfx}=\"${line[prop]}\" `\n            } else if (prop !== 'value') {\n                attrs += `${this.pfx}-${prop}=\"${line[prop]}\" `\n            }\n        }\n\n        return attrs;\n    }\n}\n\n/**\n* HTML API: If current script has container(s) specified, initialise Termynal.\n*/\nif (document.currentScript.hasAttribute('data-termynal-container')) {\n    const containers = document.currentScript.getAttribute('data-termynal-container');\n    containers.split('|')\n        .forEach(container => new Termynal(container))\n}\n"
  },
  {
    "path": "docs/en/docs/learn/index.md",
    "content": "# Learn { #learn }\n\nHere are the introductory sections and the tutorials to learn **FastAPI**.\n\nYou could consider this a **book**, a **course**, the **official** and recommended way to learn FastAPI. 😎\n"
  },
  {
    "path": "docs/en/docs/management-tasks.md",
    "content": "# Repository Management Tasks\n\nThese are the tasks that can be performed to manage the FastAPI repository by [team members](./fastapi-people.md#team).\n\n/// tip\n\nThis section is useful only to a handful of people, team members with permissions to manage the repository. You can probably skip it. 😉\n\n///\n\n...so, you are a [team member of FastAPI](./fastapi-people.md#team)? Wow, you are so cool! 😎\n\nYou can help with everything on [Help FastAPI - Get Help](./help-fastapi.md) the same ways as external contributors. But additionally, there are some tasks that only you (as part of the team) can perform.\n\nHere are the general instructions for the tasks you can perform.\n\nThanks a lot for your help. 🙇\n\n## Be Nice\n\nFirst of all, be nice. 😊\n\nYou probably are super nice if you were added to the team, but it's worth mentioning it. 🤓\n\n### When Things are Difficult\n\nWhen things are great, everything is easier, so that doesn't need much instructions. But when things are difficult, here are some guidelines.\n\nTry to find the good side. In general, if people are not being unfriendly, try to thank their effort and interest, even if you disagree with the main subject (discussion, PR), just thank them for being interested in the project, or for having dedicated some time to try to do something.\n\nIt's difficult to convey emotion in text, use emojis to help. 😅\n\nIn discussions and PRs, in many cases, people bring their frustration and show it without filter, in many cases exaggerating, complaining, being entitled, etc. That's really not nice, and when it happens, it lowers our priority to solve their problems. But still, try to breath, and be gentle with your answers.\n\nTry to avoid using bitter sarcasm or potentially passive-aggressive comments. If something is wrong, it's better to be direct (try to be gentle) than sarcastic.\n\nTry to be as specific and objective as possible, avoid generalizations.\n\nFor conversations that are more difficult, for example to reject a PR, you can ask me (@tiangolo) to handle it directly.\n\n## Edit PR Titles\n\n* Edit the PR title to start with an emoji from [gitmoji](https://gitmoji.dev/).\n    * Use the emoji character, not the GitHub code. So, use `🐛` instead of `:bug:`. This is so that it shows up correctly outside of GitHub, for example in the release notes.\n    * For translations use the `🌐` emoji (\"globe with meridians\").\n* Start the title with a verb. For example `Add`, `Refactor`, `Fix`, etc. This way the title will say the action that the PR does. Like `Add support for teleporting`, instead of `Teleporting wasn't working, so this PR fixes it`.\n* Edit the text of the PR title to start in \"imperative\", like giving an order. So, instead of `Adding support for teleporting` use `Add support for teleporting`.\n* Try to make the title descriptive about what it achieves. If it's a feature, try to describe it, for example `Add support for teleporting` instead of `Create TeleportAdapter class`.\n* Do not finish the title with a period (`.`).\n* When the PR is for a translation, start with the `🌐` and then `Add {language} translation for` and then the translated file path. For example:\n\n```Markdown\n🌐 Add Spanish translation for `docs/es/docs/teleporting.md`\n```\n\nOnce the PR is merged, a GitHub Action ([latest-changes](https://github.com/tiangolo/latest-changes)) will use the PR title to update the latest changes automatically.\n\nSo, having a nice PR title will not only look nice in GitHub, but also in the release notes. 📝\n\n## Add Labels to PRs\n\nThe same GitHub Action [latest-changes](https://github.com/tiangolo/latest-changes) uses one label in the PR to decide the section in the release notes to put this PR in.\n\nMake sure you use a supported label from the [latest-changes list of labels](https://github.com/tiangolo/latest-changes#using-labels):\n\n* `breaking`: Breaking Changes\n    * Existing code will break if they update the version without changing their code. This rarely happens, so this label is not frequently used.\n* `security`: Security Fixes\n    * This is for security fixes, like vulnerabilities. It would almost never be used.\n* `feature`: Features\n    * New features, adding support for things that didn't exist before.\n* `bug`: Fixes\n    * Something that was supported didn't work, and this fixes it. There are many PRs that claim to be bug fixes because the user is doing something in an unexpected way that is not supported, but they considered it what should be supported by default. Many of these are actually features or refactors. But in some cases there's an actual bug.\n* `refactor`: Refactors\n    * This is normally for changes to the internal code that don't change the behavior. Normally it improves maintainability, or enables future features, etc.\n* `upgrade`: Upgrades\n    * This is for upgrades to direct dependencies from the project, or extra optional dependencies, normally in `pyproject.toml`. So, things that would affect final users, they would end up receiving the upgrade in their code base once they update. But this is not for upgrades to internal dependencies used for development, testing, docs, etc. Those internal dependencies or GitHub Action versions should be marked as `internal`, not `upgrade`.\n* `docs`: Docs\n    * Changes in docs. This includes updating the docs, fixing typos. But it doesn't include changes to translations.\n    * You can normally quickly detect it by going to the \"Files changed\" tab in the PR and checking if the updated file(s) starts with `docs/en/docs`. The original version of the docs is always in English, so in `docs/en/docs`.\n* `lang-all`: Translations\n    * Use this for translations. You can normally quickly detect it by going to the \"Files changed\" tab in the PR and checking if the updated file(s) starts with `docs/{some lang}/docs` but not `docs/en/docs`. For example, `docs/es/docs`.\n* `internal`: Internal\n    * Use this for changes that only affect how the repo is managed. For example upgrades to internal dependencies, changes in GitHub Actions or scripts, etc.\n\n/// tip\n\nSome tools like Dependabot, will add some labels, like `dependencies`, but have in mind that this label is not used by the `latest-changes` GitHub Action, so it won't be used in the release notes. Please make sure one of the labels above is added.\n\n///\n\n## Add Labels to Translation PRs\n\nWhen there's a PR for a translation, apart from adding the `lang-all` label, also add a label for the language.\n\nThere will be a label for each language using the language code, like `lang-{lang code}`, for example, `lang-es` for Spanish, `lang-fr` for French, etc.\n\n* Add the specific language label.\n* Add the label `awaiting-review`.\n\nThe label `awaiting-review` is special, only used for translations. A GitHub Action will detect it, then it will read the language label, and it will update the GitHub Discussions managing the translations for that language to notify people that there's a new translation to review.\n\nOnce a native speaker comes, reviews the PR, and approves it, the GitHub Action will come and remove the `awaiting-review` label, and add the `approved-1` label.\n\nThis way, we can notice when there are new translations ready, because they have the `approved-1` label.\n\n## Merge Translation PRs\n\nTranslations are generated automatically with LLMs and scripts.\n\nThere's one GitHub Action that can be manually run to add or update translations for a language: [`translate.yml`](https://github.com/fastapi/fastapi/actions/workflows/translate.yml).\n\nFor these language translation PRs, confirm that:\n\n* The PR was automated (authored by @tiangolo), not made by another user.\n* It has the labels `lang-all` and `lang-{lang code}`.\n\nFor PRs that update language-specific LLM prompts, confirm that:\n\n* The PR has the labels `lang-all` and `lang-{lang code}`.\n* It is approved by at least one native speaker.\n* In some cases you might need to translate several pages with new prompt to make sure it works as expected.\n\nIf the PR meets the above conditions, you can merge it. 😎\n\n## Review PRs\n\n* If a PR doesn't explain what it does or why, if it seems like it could be useful, ask for more information. Otherwise, feel free to close it.\n\n* If a PR seems to be spam, meaningless, only to change statistics (to appear as \"contributor\") or similar, you can simply mark it as `invalid`, and it will be automatically closed.\n\n* If a PR seems to be AI generated, and seems like reviewing it would take more time from you than the time it took to write the prompt, mark it as `maybe-ai`, and it will be automatically closed.\n\n* A PR should have a specific use case that it is solving.\n\n* If the PR is for a feature, it should have docs.\n    * Unless it's a feature we want to discourage, like support for a corner case that we don't want users to use.\n* The docs should include a source example file, not write Python directly in Markdown.\n* If the source example(s) file can have different syntax for different Python versions, there should be different versions of the file, and they should be shown in tabs in the docs.\n* There should be tests testing the source example.\n* Before the PR is applied, the new tests should fail.\n* After applying the PR, the new tests should pass.\n* Coverage should stay at 100%.\n* If you see the PR makes sense, or we discussed it and considered it should be accepted, you can add commits on top of the PR to tweak it, to add docs, tests, format, refactor, remove extra files, etc.\n* Feel free to comment in the PR to ask for more information, to suggest changes, etc.\n* Once you think the PR is ready, move it in the internal GitHub project for me to review it.\n\n## FastAPI People PRs\n\nEvery month, a GitHub Action updates the FastAPI People data. Those PRs look like this one: [👥 Update FastAPI People](https://github.com/fastapi/fastapi/pull/11669).\n\nIf the tests are passing, you can merge it right away.\n\n## Dependabot PRs\n\nDependabot will create PRs to update dependencies for several things, and those PRs all look similar, but some are way more delicate than others.\n\n* If the PR is for a direct dependency, so, Dependabot is modifying `pyproject.toml` in the main dependencies, **don't merge it**. 😱 Let me check it first. There's a good chance that some additional tweaks or updates are needed.\n* If the PR updates one of the internal dependencies, for example the group `dev` in `pyproject.toml`, or GitHub Action versions, if the tests are passing, the release notes (shown in a summary in the PR) don't show any obvious potential breaking change, you can merge it. 😎\n\n## Mark GitHub Discussions Answers\n\nWhen a question in GitHub Discussions has been answered, mark the answer by clicking \"Mark as answer\".\n\nYou can filter discussions by [`Questions` that are `Unanswered`](https://github.com/tiangolo/fastapi/discussions/categories/questions?discussions_q=category:Questions+is:open+is:unanswered).\n"
  },
  {
    "path": "docs/en/docs/management.md",
    "content": "# Repository Management\n\nHere's a short description of how the FastAPI repository is managed and maintained.\n\n## Owner\n\nI, [@tiangolo](https://github.com/tiangolo), am the creator and owner of the FastAPI repository. 🤓\n\nI normally give the final review to each PR before merging them. I make the final decisions on the project, I'm the [<abbr title=\"Benevolent Dictator For Life\">BDFL</abbr>](https://en.wikipedia.org/wiki/Benevolent_dictator_for_life). 😅\n\n## Team\n\nThere's a team of people that help manage and maintain the project. 😎\n\nThey have different levels of permissions and [specific instructions](./management-tasks.md).\n\nSome of the tasks they can perform include:\n\n* Adding labels to PRs.\n* Editing PR titles.\n* Adding commits on top of PRs to tweak them.\n* Mark answers in GitHub Discussions questions, etc.\n* Merge some specific types of PRs.\n\nYou can see the current team members in [FastAPI People - Team](./fastapi-people.md#team).\n\nJoining the team is by invitation only, and I could update or remove permissions, instructions, or membership.\n\n## FastAPI Experts\n\nThe people that help others the most in GitHub Discussions can become [**FastAPI Experts**](./fastapi-people.md#fastapi-experts).\n\nThis is normally the best way to contribute to the project.\n\n## External Contributions\n\nExternal contributions are very welcome and appreciated, including answering questions, submitting PRs, etc. 🙇‍♂️\n\nThere are many ways to [help maintain FastAPI](./help-fastapi.md#help-maintain-fastapi).\n"
  },
  {
    "path": "docs/en/docs/newsletter.md",
    "content": "# FastAPI and friends newsletter\n\n<iframe data-w-type=\"embedded\" frameborder=\"0\" scrolling=\"no\" marginheight=\"0\" marginwidth=\"0\" src=\"https://xr4n4.mjt.lu/wgt/xr4n4/hj5/form?c=40a44fa4\" width=\"100%\" style=\"height: 800px;\"></iframe>\n\n<script type=\"text/javascript\" src=\"https://app.mailjet.com/pas-nc-embedded-v1.js\"></script>\n"
  },
  {
    "path": "docs/en/docs/project-generation.md",
    "content": "# Full Stack FastAPI Template { #full-stack-fastapi-template }\n\nTemplates, while typically come with a specific setup, are designed to be flexible and customizable. This allows you to modify and adapt them to your project's requirements, making them an excellent starting point. 🏁\n\nYou can use this template to get started, as it includes a lot of the initial set up, security, database and some API endpoints already done for you.\n\nGitHub Repository: [Full Stack FastAPI Template](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## Full Stack FastAPI Template - Technology Stack and Features { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) for the Python backend API.\n  - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) for the Python SQL database interactions (ORM).\n  - 🔍 [Pydantic](https://docs.pydantic.dev), used by FastAPI, for the data validation and settings management.\n  - 💾 [PostgreSQL](https://www.postgresql.org) as the SQL database.\n- 🚀 [React](https://react.dev) for the frontend.\n  - 💃 Using TypeScript, hooks, Vite, and other parts of a modern frontend stack.\n  - 🎨 [Tailwind CSS](https://tailwindcss.com) and [shadcn/ui](https://ui.shadcn.com) for the frontend components.\n  - 🤖 An automatically generated frontend client.\n  - 🧪 [Playwright](https://playwright.dev) for End-to-End testing.\n  - 🦇 Dark mode support.\n- 🐋 [Docker Compose](https://www.docker.com) for development and production.\n- 🔒 Secure password hashing by default.\n- 🔑 JWT (JSON Web Token) authentication.\n- 📫 Email based password recovery.\n- ✅ Tests with [Pytest](https://pytest.org).\n- 📞 [Traefik](https://traefik.io) as a reverse proxy / load balancer.\n- 🚢 Deployment instructions using Docker Compose, including how to set up a frontend Traefik proxy to handle automatic HTTPS certificates.\n- 🏭 CI (continuous integration) and CD (continuous deployment) based on GitHub Actions.\n"
  },
  {
    "path": "docs/en/docs/python-types.md",
    "content": "# Python Types Intro { #python-types-intro }\n\nPython has support for optional \"type hints\" (also called \"type annotations\").\n\nThese **\"type hints\"** or annotations are a special syntax that allow declaring the <dfn title=\"for example: str, int, float, bool\">type</dfn> of a variable.\n\nBy declaring types for your variables, editors and tools can give you better support.\n\nThis is just a **quick tutorial / refresher** about Python type hints. It covers only the minimum necessary to use them with **FastAPI**... which is actually very little.\n\n**FastAPI** is all based on these type hints, they give it many advantages and benefits.\n\nBut even if you never use **FastAPI**, you would benefit from learning a bit about them.\n\n/// note\n\nIf you are a Python expert, and you already know everything about type hints, skip to the next chapter.\n\n///\n\n## Motivation { #motivation }\n\nLet's start with a simple example:\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\nCalling this program outputs:\n\n```\nJohn Doe\n```\n\nThe function does the following:\n\n* Takes a `first_name` and `last_name`.\n* Converts the first letter of each one to upper case with `title()`.\n* <dfn title=\"Puts them together, as one. With the contents of one after the other.\">Concatenates</dfn> them with a space in the middle.\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### Edit it { #edit-it }\n\nIt's a very simple program.\n\nBut now imagine that you were writing it from scratch.\n\nAt some point you would have started the definition of the function, you had the parameters ready...\n\nBut then you have to call \"that method that converts the first letter to upper case\".\n\nWas it `upper`? Was it `uppercase`? `first_uppercase`? `capitalize`?\n\nThen, you try with the old programmer's friend, editor autocompletion.\n\nYou type the first parameter of the function, `first_name`, then a dot (`.`) and then hit `Ctrl+Space` to trigger the completion.\n\nBut, sadly, you get nothing useful:\n\n<img src=\"/img/python-types/image01.png\">\n\n### Add types { #add-types }\n\nLet's modify a single line from the previous version.\n\nWe will change exactly this fragment, the parameters of the function, from:\n\n```Python\n    first_name, last_name\n```\n\nto:\n\n```Python\n    first_name: str, last_name: str\n```\n\nThat's it.\n\nThose are the \"type hints\":\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\nThat is not the same as declaring default values like would be with:\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\nIt's a different thing.\n\nWe are using colons (`:`), not equals (`=`).\n\nAnd adding type hints normally doesn't change what happens from what would happen without them.\n\nBut now, imagine you are again in the middle of creating that function, but with type hints.\n\nAt the same point, you try to trigger the autocomplete with `Ctrl+Space` and you see:\n\n<img src=\"/img/python-types/image02.png\">\n\nWith that, you can scroll, seeing the options, until you find the one that \"rings a bell\":\n\n<img src=\"/img/python-types/image03.png\">\n\n## More motivation { #more-motivation }\n\nCheck this function, it already has type hints:\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\nBecause the editor knows the types of the variables, you don't only get completion, you also get error checks:\n\n<img src=\"/img/python-types/image04.png\">\n\nNow you know that you have to fix it, convert `age` to a string with `str(age)`:\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## Declaring types { #declaring-types }\n\nYou just saw the main place to declare type hints. As function parameters.\n\nThis is also the main place you would use them with **FastAPI**.\n\n### Simple types { #simple-types }\n\nYou can declare all the standard Python types, not only `str`.\n\nYou can use, for example:\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### `typing` module { #typing-module }\n\nFor some additional use cases, you might need to import some things from the standard library `typing` module, for example when you want to declare that something has \"any type\", you can use `Any` from `typing`:\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### Generic types { #generic-types }\n\nSome types can take \"type parameters\" in square brackets, to define their internal types, for example a \"list of strings\" would be declared `list[str]`.\n\nThese types that can take type parameters are called **Generic types** or **Generics**.\n\nYou can use the same builtin types as generics (with square brackets and types inside):\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### List { #list }\n\nFor example, let's define a variable to be a `list` of `str`.\n\nDeclare the variable, with the same colon (`:`) syntax.\n\nAs the type, put `list`.\n\nAs the list is a type that contains some internal types, you put them in square brackets:\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info\n\nThose internal types in the square brackets are called \"type parameters\".\n\nIn this case, `str` is the type parameter passed to `list`.\n\n///\n\nThat means: \"the variable `items` is a `list`, and each of the items in this list is a `str`\".\n\nBy doing that, your editor can provide support even while processing items from the list:\n\n<img src=\"/img/python-types/image05.png\">\n\nWithout types, that's almost impossible to achieve.\n\nNotice that the variable `item` is one of the elements in the list `items`.\n\nAnd still, the editor knows it is a `str`, and provides support for that.\n\n#### Tuple and Set { #tuple-and-set }\n\nYou would do the same to declare `tuple`s and `set`s:\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\nThis means:\n\n* The variable `items_t` is a `tuple` with 3 items, an `int`, another `int`, and a `str`.\n* The variable `items_s` is a `set`, and each of its items is of type `bytes`.\n\n#### Dict { #dict }\n\nTo define a `dict`, you pass 2 type parameters, separated by commas.\n\nThe first type parameter is for the keys of the `dict`.\n\nThe second type parameter is for the values of the `dict`:\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\nThis means:\n\n* The variable `prices` is a `dict`:\n    * The keys of this `dict` are of type `str` (let's say, the name of each item).\n    * The values of this `dict` are of type `float` (let's say, the price of each item).\n\n#### Union { #union }\n\nYou can declare that a variable can be any of **several types**, for example, an `int` or a `str`.\n\nTo define it you use the <dfn title='also called \"bitwise or operator\", but that meaning is not relevant here'>vertical bar (`|`)</dfn> to separate both types.\n\nThis is called a \"union\", because the variable can be anything in the union of those two sets of types.\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\nThis means that `item` could be an `int` or a `str`.\n\n#### Possibly `None` { #possibly-none }\n\nYou can declare that a value could have a type, like `str`, but that it could also be `None`.\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\nUsing `str | None` instead of just `str` will let the editor help you detect errors where you could be assuming that a value is always a `str`, when it could actually be `None` too.\n\n### Classes as types { #classes-as-types }\n\nYou can also declare a class as the type of a variable.\n\nLet's say you have a class `Person`, with a name:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\nThen you can declare a variable to be of type `Person`:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\nAnd then, again, you get all the editor support:\n\n<img src=\"/img/python-types/image06.png\">\n\nNotice that this means \"`one_person` is an **instance** of the class `Person`\".\n\nIt doesn't mean \"`one_person` is the **class** called `Person`\".\n\n## Pydantic models { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/) is a Python library to perform data validation.\n\nYou declare the \"shape\" of the data as classes with attributes.\n\nAnd each attribute has a type.\n\nThen you create an instance of that class with some values and it will validate the values, convert them to the appropriate type (if that's the case) and give you an object with all the data.\n\nAnd you get all the editor support with that resulting object.\n\nAn example from the official Pydantic docs:\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info\n\nTo learn more about [Pydantic, check its docs](https://docs.pydantic.dev/).\n\n///\n\n**FastAPI** is all based on Pydantic.\n\nYou will see a lot more of all this in practice in the [Tutorial - User Guide](tutorial/index.md).\n\n## Type Hints with Metadata Annotations { #type-hints-with-metadata-annotations }\n\nPython also has a feature that allows putting **additional <dfn title=\"Data about the data, in this case, information about the type, e.g. a description.\">metadata</dfn>** in these type hints using `Annotated`.\n\nYou can import `Annotated` from `typing`.\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nPython itself doesn't do anything with this `Annotated`. And for editors and other tools, the type is still `str`.\n\nBut you can use this space in `Annotated` to provide **FastAPI** with additional metadata about how you want your application to behave.\n\nThe important thing to remember is that **the first *type parameter*** you pass to `Annotated` is the **actual type**. The rest, is just metadata for other tools.\n\nFor now, you just need to know that `Annotated` exists, and that it's standard Python. 😎\n\nLater you will see how **powerful** it can be.\n\n/// tip\n\nThe fact that this is **standard Python** means that you will still get the **best possible developer experience** in your editor, with the tools you use to analyze and refactor your code, etc. ✨\n\nAnd also that your code will be very compatible with many other Python tools and libraries. 🚀\n\n///\n\n## Type hints in **FastAPI** { #type-hints-in-fastapi }\n\n**FastAPI** takes advantage of these type hints to do several things.\n\nWith **FastAPI** you declare parameters with type hints and you get:\n\n* **Editor support**.\n* **Type checks**.\n\n...and **FastAPI** uses the same declarations to:\n\n* **Define requirements**: from request path parameters, query parameters, headers, bodies, dependencies, etc.\n* **Convert data**: from the request to the required type.\n* **Validate data**: coming from each request:\n    * Generating **automatic errors** returned to the client when the data is invalid.\n* **Document** the API using OpenAPI:\n    * which is then used by the automatic interactive documentation user interfaces.\n\nThis might all sound abstract. Don't worry. You'll see all this in action in the [Tutorial - User Guide](tutorial/index.md).\n\nThe important thing is that by using standard Python types, in a single place (instead of adding more classes, decorators, etc), **FastAPI** will do a lot of the work for you.\n\n/// info\n\nIf you already went through all the tutorial and came back to see more about types, a good resource is [the \"cheat sheet\" from `mypy`](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html).\n\n///\n"
  },
  {
    "path": "docs/en/docs/reference/apirouter.md",
    "content": "# `APIRouter` class\n\nHere's the reference information for the `APIRouter` class, with all its parameters, attributes and methods.\n\nYou can import the `APIRouter` class directly from `fastapi`:\n\n```python\nfrom fastapi import APIRouter\n```\n\n::: fastapi.APIRouter\n    options:\n        members:\n            - websocket\n            - include_router\n            - get\n            - put\n            - post\n            - delete\n            - options\n            - head\n            - patch\n            - trace\n            - on_event\n"
  },
  {
    "path": "docs/en/docs/reference/background.md",
    "content": "# Background Tasks - `BackgroundTasks`\n\nYou 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.\n\nYou can import it directly from `fastapi`:\n\n```python\nfrom fastapi import BackgroundTasks\n```\n\n::: fastapi.BackgroundTasks\n"
  },
  {
    "path": "docs/en/docs/reference/dependencies.md",
    "content": "# Dependencies - `Depends()` and `Security()`\n\n## `Depends()`\n\nDependencies are handled mainly with the special function `Depends()` that takes a callable.\n\nHere is the reference for it and its parameters.\n\nYou can import it directly from `fastapi`:\n\n```python\nfrom fastapi import Depends\n```\n\n::: fastapi.Depends\n\n## `Security()`\n\nFor many scenarios, you can handle security (authorization, authentication, etc.) with dependencies, using `Depends()`.\n\nBut when you want to also declare OAuth2 scopes, you can use `Security()` instead of `Depends()`.\n\nYou can import `Security()` directly from `fastapi`:\n\n```python\nfrom fastapi import Security\n```\n\n::: fastapi.Security\n"
  },
  {
    "path": "docs/en/docs/reference/encoders.md",
    "content": "# Encoders - `jsonable_encoder`\n\n::: fastapi.encoders.jsonable_encoder\n"
  },
  {
    "path": "docs/en/docs/reference/exceptions.md",
    "content": "# Exceptions - `HTTPException` and `WebSocketException`\n\nThese are the exceptions that you can raise to show errors to the client.\n\nWhen you raise an exception, as would happen with normal Python, the rest of the execution 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.\n\nYou can use:\n\n* `HTTPException`\n* `WebSocketException`\n\nThese exceptions can be imported directly from `fastapi`:\n\n```python\nfrom fastapi import HTTPException, WebSocketException\n```\n\n::: fastapi.HTTPException\n\n::: fastapi.WebSocketException\n"
  },
  {
    "path": "docs/en/docs/reference/fastapi.md",
    "content": "# `FastAPI` class\n\nHere's the reference information for the `FastAPI` class, with all its parameters, attributes and methods.\n\nYou can import the `FastAPI` class directly from `fastapi`:\n\n```python\nfrom fastapi import FastAPI\n```\n\n::: fastapi.FastAPI\n    options:\n        members:\n            - openapi_version\n            - webhooks\n            - state\n            - dependency_overrides\n            - openapi\n            - websocket\n            - include_router\n            - get\n            - put\n            - post\n            - delete\n            - options\n            - head\n            - patch\n            - trace\n            - on_event\n            - middleware\n            - exception_handler\n"
  },
  {
    "path": "docs/en/docs/reference/httpconnection.md",
    "content": "# `HTTPConnection` class\n\nWhen 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`.\n\nYou can import it from `fastapi.requests`:\n\n```python\nfrom fastapi.requests import HTTPConnection\n```\n\n::: fastapi.requests.HTTPConnection\n"
  },
  {
    "path": "docs/en/docs/reference/index.md",
    "content": "# Reference\n\nHere's the reference or code API, the classes, functions, parameters, attributes, and\nall the FastAPI parts you can use in your applications.\n\nIf you want to **learn FastAPI** you are much better off reading the\n[FastAPI Tutorial](https://fastapi.tiangolo.com/tutorial/).\n"
  },
  {
    "path": "docs/en/docs/reference/middleware.md",
    "content": "# Middleware\n\nThere are several middlewares available provided by Starlette directly.\n\nRead more about them in the [FastAPI docs for Middleware](https://fastapi.tiangolo.com/advanced/middleware/).\n\n::: fastapi.middleware.cors.CORSMiddleware\n\nIt can be imported from `fastapi`:\n\n```python\nfrom fastapi.middleware.cors import CORSMiddleware\n```\n\n::: fastapi.middleware.gzip.GZipMiddleware\n\nIt can be imported from `fastapi`:\n\n```python\nfrom fastapi.middleware.gzip import GZipMiddleware\n```\n\n::: fastapi.middleware.httpsredirect.HTTPSRedirectMiddleware\n\nIt can be imported from `fastapi`:\n\n```python\nfrom fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware\n```\n\n::: fastapi.middleware.trustedhost.TrustedHostMiddleware\n\nIt can be imported from `fastapi`:\n\n```python\nfrom fastapi.middleware.trustedhost import TrustedHostMiddleware\n```\n"
  },
  {
    "path": "docs/en/docs/reference/openapi/docs.md",
    "content": "# OpenAPI `docs`\n\nUtilities to handle OpenAPI automatic UI documentation, including Swagger UI (by default at `/docs`) and ReDoc (by default at `/redoc`).\n\n::: fastapi.openapi.docs.get_swagger_ui_html\n\n::: fastapi.openapi.docs.get_redoc_html\n\n::: fastapi.openapi.docs.get_swagger_ui_oauth2_redirect_html\n\n::: fastapi.openapi.docs.swagger_ui_default_parameters\n"
  },
  {
    "path": "docs/en/docs/reference/openapi/index.md",
    "content": "# OpenAPI\n\nThere are several utilities to handle OpenAPI.\n\nYou normally don't need to use them unless you have a specific advanced use case that requires it.\n"
  },
  {
    "path": "docs/en/docs/reference/openapi/models.md",
    "content": "# OpenAPI `models`\n\nOpenAPI Pydantic models used to generate and validate the generated OpenAPI.\n\n::: fastapi.openapi.models\n"
  },
  {
    "path": "docs/en/docs/reference/parameters.md",
    "content": "# Request Parameters\n\nHere's the reference information for the request parameters.\n\nThese are the special functions that you can put in *path operation function* parameters or dependency functions with `Annotated` to get data from the request.\n\nIt includes:\n\n* `Query()`\n* `Path()`\n* `Body()`\n* `Cookie()`\n* `Header()`\n* `Form()`\n* `File()`\n\nYou can import them all directly from `fastapi`:\n\n```python\nfrom fastapi import Body, Cookie, File, Form, Header, Path, Query\n```\n\n::: fastapi.Query\n\n::: fastapi.Path\n\n::: fastapi.Body\n\n::: fastapi.Cookie\n\n::: fastapi.Header\n\n::: fastapi.Form\n\n::: fastapi.File\n"
  },
  {
    "path": "docs/en/docs/reference/request.md",
    "content": "# `Request` class\n\nYou 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.\n\nRead more about it in the [FastAPI docs about using Request directly](https://fastapi.tiangolo.com/advanced/using-request-directly/)\n\nYou can import it directly from `fastapi`:\n\n```python\nfrom fastapi import Request\n```\n\n/// tip\n\nWhen 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`.\n\n///\n\n::: fastapi.Request\n"
  },
  {
    "path": "docs/en/docs/reference/response.md",
    "content": "# `Response` class\n\nYou 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.\n\nYou can also use it directly to create an instance of it and return it from your *path operations*.\n\nRead more about it in the [FastAPI docs about returning a custom Response](https://fastapi.tiangolo.com/advanced/response-directly/#returning-a-custom-response)\n\nYou can import it directly from `fastapi`:\n\n```python\nfrom fastapi import Response\n```\n\n::: fastapi.Response\n"
  },
  {
    "path": "docs/en/docs/reference/responses.md",
    "content": "# Custom Response Classes - File, HTML, Redirect, Streaming, etc.\n\nThere are several custom response classes you can use to create an instance and return them directly from your *path operations*.\n\nRead more about it in the [FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/).\n\nYou can import them directly from `fastapi.responses`:\n\n```python\nfrom fastapi.responses import (\n    FileResponse,\n    HTMLResponse,\n    JSONResponse,\n    ORJSONResponse,\n    PlainTextResponse,\n    RedirectResponse,\n    Response,\n    StreamingResponse,\n    UJSONResponse,\n)\n```\n\n## FastAPI Responses\n\nThere were a couple of custom FastAPI response classes that were intended to optimize JSON performance.\n\nHowever, they are now deprecated as you will now get better performance by using a [Response Model - Return Type](https://fastapi.tiangolo.com/tutorial/response-model/).\n\nThat way, Pydantic will serialize the data into JSON bytes on the Rust side, which will achieve better performance than these custom JSON responses.\n\nRead more about it in [Custom Response - HTML, Stream, File, others - `orjson` or Response Model](https://fastapi.tiangolo.com/advanced/custom-response/#orjson-or-response-model).\n\n::: fastapi.responses.UJSONResponse\n    options:\n        members:\n            - charset\n            - status_code\n            - media_type\n            - body\n            - background\n            - raw_headers\n            - render\n            - init_headers\n            - headers\n            - set_cookie\n            - delete_cookie\n\n::: fastapi.responses.ORJSONResponse\n    options:\n        members:\n            - charset\n            - status_code\n            - media_type\n            - body\n            - background\n            - raw_headers\n            - render\n            - init_headers\n            - headers\n            - set_cookie\n            - delete_cookie\n\n## Starlette Responses\n\nYou can read more about all of them in the [FastAPI docs for Custom Response](https://fastapi.tiangolo.com/advanced/custom-response/) and in the [Starlette docs about Responses](https://starlette.dev/responses/).\n\n::: fastapi.responses.FileResponse\n    options:\n        members:\n            - chunk_size\n            - charset\n            - status_code\n            - media_type\n            - body\n            - background\n            - raw_headers\n            - render\n            - init_headers\n            - headers\n            - set_cookie\n            - delete_cookie\n\n::: fastapi.responses.HTMLResponse\n    options:\n        members:\n            - charset\n            - status_code\n            - media_type\n            - body\n            - background\n            - raw_headers\n            - render\n            - init_headers\n            - headers\n            - set_cookie\n            - delete_cookie\n\n::: fastapi.responses.JSONResponse\n    options:\n        members:\n            - charset\n            - status_code\n            - media_type\n            - body\n            - background\n            - raw_headers\n            - render\n            - init_headers\n            - headers\n            - set_cookie\n            - delete_cookie\n\n::: fastapi.responses.PlainTextResponse\n    options:\n        members:\n            - charset\n            - status_code\n            - media_type\n            - body\n            - background\n            - raw_headers\n            - render\n            - init_headers\n            - headers\n            - set_cookie\n            - delete_cookie\n\n::: fastapi.responses.RedirectResponse\n    options:\n        members:\n            - charset\n            - status_code\n            - media_type\n            - body\n            - background\n            - raw_headers\n            - render\n            - init_headers\n            - headers\n            - set_cookie\n            - delete_cookie\n\n::: fastapi.responses.Response\n    options:\n        members:\n            - charset\n            - status_code\n            - media_type\n            - body\n            - background\n            - raw_headers\n            - render\n            - init_headers\n            - headers\n            - set_cookie\n            - delete_cookie\n\n::: fastapi.responses.StreamingResponse\n    options:\n        members:\n            - body_iterator\n            - charset\n            - status_code\n            - media_type\n            - body\n            - background\n            - raw_headers\n            - render\n            - init_headers\n            - headers\n            - set_cookie\n            - delete_cookie\n"
  },
  {
    "path": "docs/en/docs/reference/security/index.md",
    "content": "# Security Tools\n\nWhen you need to declare dependencies with OAuth2 scopes you use `Security()`.\n\nBut you still need to define what is the dependable, the callable that you pass as a parameter to `Depends()` or `Security()`.\n\nThere 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.\n\nYou can import them from `fastapi.security`:\n\n```python\nfrom fastapi.security import (\n    APIKeyCookie,\n    APIKeyHeader,\n    APIKeyQuery,\n    HTTPAuthorizationCredentials,\n    HTTPBasic,\n    HTTPBasicCredentials,\n    HTTPBearer,\n    HTTPDigest,\n    OAuth2,\n    OAuth2AuthorizationCodeBearer,\n    OAuth2PasswordBearer,\n    OAuth2PasswordRequestForm,\n    OAuth2PasswordRequestFormStrict,\n    OpenIdConnect,\n    SecurityScopes,\n)\n```\n\nRead more about them in the [FastAPI docs about Security](https://fastapi.tiangolo.com/tutorial/security/).\n\n## API Key Security Schemes\n\n::: fastapi.security.APIKeyCookie\n\n::: fastapi.security.APIKeyHeader\n\n::: fastapi.security.APIKeyQuery\n\n## HTTP Authentication Schemes\n\n::: fastapi.security.HTTPBasic\n\n::: fastapi.security.HTTPBearer\n\n::: fastapi.security.HTTPDigest\n\n## HTTP Credentials\n\n::: fastapi.security.HTTPAuthorizationCredentials\n\n::: fastapi.security.HTTPBasicCredentials\n\n## OAuth2 Authentication\n\n::: fastapi.security.OAuth2\n\n::: fastapi.security.OAuth2AuthorizationCodeBearer\n\n::: fastapi.security.OAuth2PasswordBearer\n\n## OAuth2 Password Form\n\n::: fastapi.security.OAuth2PasswordRequestForm\n\n::: fastapi.security.OAuth2PasswordRequestFormStrict\n\n## OAuth2 Security Scopes in Dependencies\n\n::: fastapi.security.SecurityScopes\n\n## OpenID Connect\n\n::: fastapi.security.OpenIdConnect\n"
  },
  {
    "path": "docs/en/docs/reference/staticfiles.md",
    "content": "# Static Files - `StaticFiles`\n\nYou can use the `StaticFiles` class to serve static files, like JavaScript, CSS, images, etc.\n\nRead more about it in the [FastAPI docs for Static Files](https://fastapi.tiangolo.com/tutorial/static-files/).\n\nYou can import it directly from `fastapi.staticfiles`:\n\n```python\nfrom fastapi.staticfiles import StaticFiles\n```\n\n::: fastapi.staticfiles.StaticFiles\n"
  },
  {
    "path": "docs/en/docs/reference/status.md",
    "content": "# Status Codes\n\nYou can import the `status` module from `fastapi`:\n\n```python\nfrom fastapi import status\n```\n\n`status` is provided directly by Starlette.\n\nIt contains a group of named constants (variables) with integer status codes.\n\nFor example:\n\n* 200: `status.HTTP_200_OK`\n* 403: `status.HTTP_403_FORBIDDEN`\n* etc.\n\nIt 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.\n\nRead more about it in the [FastAPI docs about Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/).\n\n## Example\n\n```python\nfrom fastapi import FastAPI, status\n\napp = FastAPI()\n\n\n@app.get(\"/items/\", status_code=status.HTTP_418_IM_A_TEAPOT)\ndef read_items():\n    return [{\"name\": \"Plumbus\"}, {\"name\": \"Portal Gun\"}]\n```\n\n::: fastapi.status\n"
  },
  {
    "path": "docs/en/docs/reference/templating.md",
    "content": "# Templating - `Jinja2Templates`\n\nYou can use the `Jinja2Templates` class to render Jinja templates.\n\nRead more about it in the [FastAPI docs for Templates](https://fastapi.tiangolo.com/advanced/templates/).\n\nYou can import it directly from `fastapi.templating`:\n\n```python\nfrom fastapi.templating import Jinja2Templates\n```\n\n::: fastapi.templating.Jinja2Templates\n"
  },
  {
    "path": "docs/en/docs/reference/testclient.md",
    "content": "# Test Client - `TestClient`\n\nYou can use the `TestClient` class to test FastAPI applications without creating an actual HTTP and socket connection, just communicating directly with the FastAPI code.\n\nRead more about it in the [FastAPI docs for Testing](https://fastapi.tiangolo.com/tutorial/testing/).\n\nYou can import it directly from `fastapi.testclient`:\n\n```python\nfrom fastapi.testclient import TestClient\n```\n\n::: fastapi.testclient.TestClient\n"
  },
  {
    "path": "docs/en/docs/reference/uploadfile.md",
    "content": "# `UploadFile` class\n\nYou can define *path operation function* parameters to be of the type `UploadFile` to receive files from the request.\n\nYou can import it directly from `fastapi`:\n\n```python\nfrom fastapi import UploadFile\n```\n\n::: fastapi.UploadFile\n    options:\n        members:\n            - file\n            - filename\n            - size\n            - headers\n            - content_type\n            - read\n            - write\n            - seek\n            - close\n"
  },
  {
    "path": "docs/en/docs/reference/websockets.md",
    "content": "# WebSockets\n\nWhen 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.\n\nRead more about it in the [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/)\n\nIt is provided directly by Starlette, but you can import it from `fastapi`:\n\n```python\nfrom fastapi import WebSocket\n```\n\n/// tip\n\nWhen 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`.\n\n///\n\n::: fastapi.WebSocket\n    options:\n        members:\n            - scope\n            - app\n            - url\n            - base_url\n            - headers\n            - query_params\n            - path_params\n            - cookies\n            - client\n            - state\n            - url_for\n            - client_state\n            - application_state\n            - receive\n            - send\n            - accept\n            - receive_text\n            - receive_bytes\n            - receive_json\n            - iter_text\n            - iter_bytes\n            - iter_json\n            - send_text\n            - send_bytes\n            - send_json\n            - close\n\n## WebSockets - additional classes\n\nAdditional classes for handling WebSockets.\n\nProvided directly by Starlette, but you can import it from `fastapi`:\n\n```python\nfrom fastapi.websockets import WebSocketDisconnect, WebSocketState\n```\n\n::: fastapi.websockets.WebSocketDisconnect\n\nWhen a client disconnects, a `WebSocketDisconnect` exception is raised, you can catch it.\n\nYou can import it directly form `fastapi`:\n\n```python\nfrom fastapi import WebSocketDisconnect\n```\n\nRead more about it in the [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/#handling-disconnections-and-multiple-clients)\n\n::: fastapi.websockets.WebSocketState\n\n`WebSocketState` is an enumeration of the possible states of a WebSocket connection.\n"
  },
  {
    "path": "docs/en/docs/resources/index.md",
    "content": "# Resources { #resources }\n\nAdditional resources, external links, and more. ✈️\n"
  },
  {
    "path": "docs/en/docs/translation-banner.md",
    "content": "/// details | 🌐 Translation by AI and humans\n\nThis translation was made by AI guided by humans. 🤝\n\nIt could have mistakes of misunderstanding the original meaning, or looking unnatural, etc. 🤖\n\nYou can improve this translation by [helping us guide the AI LLM better](https://fastapi.tiangolo.com/contributing/#translations).\n\n[English version](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/en/docs/tutorial/background-tasks.md",
    "content": "# Background Tasks { #background-tasks }\n\nYou can define background tasks to be run *after* returning a response.\n\nThis is useful for operations that need to happen after a request, but that the client doesn't really have to be waiting for the operation to complete before receiving the response.\n\nThis includes, for example:\n\n* Email notifications sent after performing an action:\n    * As connecting to an email server and sending an email tends to be \"slow\" (several seconds), you can return the response right away and send the email notification in the background.\n* Processing data:\n    * For example, let's say you receive a file that must go through a slow process, you can return a response of \"Accepted\" (HTTP 202) and process the file in the background.\n\n## Using `BackgroundTasks` { #using-backgroundtasks }\n\nFirst, import `BackgroundTasks` and define a parameter in your *path operation function* with a type declaration of `BackgroundTasks`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI** will create the object of type `BackgroundTasks` for you and pass it as that parameter.\n\n## Create a task function { #create-a-task-function }\n\nCreate a function to be run as the background task.\n\nIt is just a standard function that can receive parameters.\n\nIt can be an `async def` or normal `def` function, **FastAPI** will know how to handle it correctly.\n\nIn this case, the task function will write to a file (simulating sending an email).\n\nAnd as the write operation doesn't use `async` and `await`, we define the function with normal `def`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## Add the background task { #add-the-background-task }\n\nInside of your *path operation function*, pass your task function to the *background tasks* object with the method `.add_task()`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()` receives as arguments:\n\n* A task function to be run in the background (`write_notification`).\n* Any sequence of arguments that should be passed to the task function in order (`email`).\n* Any keyword arguments that should be passed to the task function (`message=\"some notification\"`).\n\n## Dependency Injection { #dependency-injection }\n\nUsing `BackgroundTasks` also works with the dependency injection system, you can declare a parameter of type `BackgroundTasks` at multiple levels: in a *path operation function*, in a dependency (dependable), in a sub-dependency, etc.\n\n**FastAPI** knows what to do in each case and how to reuse the same object, so that all the background tasks are merged together and are run in the background afterwards:\n\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\n\nIn this example, the messages will be written to the `log.txt` file *after* the response is sent.\n\nIf there was a query in the request, it will be written to the log in a background task.\n\nAnd then another background task generated at the *path operation function* will write a message using the `email` path parameter.\n\n## Technical Details { #technical-details }\n\nThe class `BackgroundTasks` comes directly from [`starlette.background`](https://www.starlette.dev/background/).\n\nIt is imported/included directly into FastAPI so that you can import it from `fastapi` and avoid accidentally importing the alternative `BackgroundTask` (without the `s` at the end) from `starlette.background`.\n\nBy only using `BackgroundTasks` (and not `BackgroundTask`), it's then possible to use it as a *path operation function* parameter and have **FastAPI** handle the rest for you, just like when using the `Request` object directly.\n\nIt's still possible to use `BackgroundTask` alone in FastAPI, but you have to create the object in your code and return a Starlette `Response` including it.\n\nYou can see more details in [Starlette's official docs for Background Tasks](https://www.starlette.dev/background/).\n\n## Caveat { #caveat }\n\nIf you need to perform heavy background computation and you don't necessarily need it to be run by the same process (for example, you don't need to share memory, variables, etc), you might benefit from using other bigger tools like [Celery](https://docs.celeryq.dev).\n\nThey tend to require more complex configurations, a message/job queue manager, like RabbitMQ or Redis, but they allow you to run background tasks in multiple processes, and especially, in multiple servers.\n\nBut if you need to access variables and objects from the same **FastAPI** app, or you need to perform small background tasks (like sending an email notification), you can simply just use `BackgroundTasks`.\n\n## Recap { #recap }\n\nImport and use `BackgroundTasks` with parameters in *path operation functions* and dependencies to add background tasks.\n"
  },
  {
    "path": "docs/en/docs/tutorial/bigger-applications.md",
    "content": "# Bigger Applications - Multiple Files { #bigger-applications-multiple-files }\n\nIf you are building an application or a web API, it's rarely the case that you can put everything in a single file.\n\n**FastAPI** provides a convenience tool to structure your application while keeping all the flexibility.\n\n/// info\n\nIf you come from Flask, this would be the equivalent of Flask's Blueprints.\n\n///\n\n## An example file structure { #an-example-file-structure }\n\nLet's say you have a file structure like this:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip\n\nThere are several `__init__.py` files: one in each directory or subdirectory.\n\nThis is what allows importing code from one file into another.\n\nFor example, in `app/main.py` you could have a line like:\n\n```\nfrom app.routers import items\n```\n\n///\n\n* The `app` directory contains everything. And it has an empty file `app/__init__.py`, so it is a \"Python package\" (a collection of \"Python modules\"): `app`.\n* It contains an `app/main.py` file. As it is inside a Python package (a directory with a file `__init__.py`), it is a \"module\" of that package: `app.main`.\n* There's also an `app/dependencies.py` file, just like `app/main.py`, it is a \"module\": `app.dependencies`.\n* There's a subdirectory `app/routers/` with another file `__init__.py`, so it's a \"Python subpackage\": `app.routers`.\n* The file `app/routers/items.py` is inside a package, `app/routers/`, so, it's a submodule: `app.routers.items`.\n* The same with `app/routers/users.py`, it's another submodule: `app.routers.users`.\n* There's also a subdirectory `app/internal/` with another file `__init__.py`, so it's another \"Python subpackage\": `app.internal`.\n* And the file `app/internal/admin.py` is another submodule: `app.internal.admin`.\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\nThe same file structure with comments:\n\n```bash\n.\n├── app                  # \"app\" is a Python package\n│   ├── __init__.py      # this file makes \"app\" a \"Python package\"\n│   ├── main.py          # \"main\" module, e.g. import app.main\n│   ├── dependencies.py  # \"dependencies\" module, e.g. import app.dependencies\n│   └── routers          # \"routers\" is a \"Python subpackage\"\n│   │   ├── __init__.py  # makes \"routers\" a \"Python subpackage\"\n│   │   ├── items.py     # \"items\" submodule, e.g. import app.routers.items\n│   │   └── users.py     # \"users\" submodule, e.g. import app.routers.users\n│   └── internal         # \"internal\" is a \"Python subpackage\"\n│       ├── __init__.py  # makes \"internal\" a \"Python subpackage\"\n│       └── admin.py     # \"admin\" submodule, e.g. import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\nLet's say the file dedicated to handling just users is the submodule at `/app/routers/users.py`.\n\nYou want to have the *path operations* related to your users separated from the rest of the code, to keep it organized.\n\nBut it's still part of the same **FastAPI** application/web API (it's part of the same \"Python Package\").\n\nYou can create the *path operations* for that module using `APIRouter`.\n\n### Import `APIRouter` { #import-apirouter }\n\nYou import it and create an \"instance\" the same way you would with the class `FastAPI`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### *Path operations* with `APIRouter` { #path-operations-with-apirouter }\n\nAnd then you use it to declare your *path operations*.\n\nUse it the same way you would use the `FastAPI` class:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\nYou can think of `APIRouter` as a \"mini `FastAPI`\" class.\n\nAll the same options are supported.\n\nAll the same `parameters`, `responses`, `dependencies`, `tags`, etc.\n\n/// tip\n\nIn this example, the variable is called `router`, but you can name it however you want.\n\n///\n\nWe are going to include this `APIRouter` in the main `FastAPI` app, but first, let's check the dependencies and another `APIRouter`.\n\n## Dependencies { #dependencies }\n\nWe see that we are going to need some dependencies used in several places of the application.\n\nSo we put them in their own `dependencies` module (`app/dependencies.py`).\n\nWe will now use a simple dependency to read a custom `X-Token` header:\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip\n\nWe are using an invented header to simplify this example.\n\nBut in real cases you will get better results using the integrated [Security utilities](security/index.md).\n\n///\n\n## Another module with `APIRouter` { #another-module-with-apirouter }\n\nLet's say you also have the endpoints dedicated to handling \"items\" from your application in the module at `app/routers/items.py`.\n\nYou have *path operations* for:\n\n* `/items/`\n* `/items/{item_id}`\n\nIt's all the same structure as with `app/routers/users.py`.\n\nBut we want to be smarter and simplify the code a bit.\n\nWe know all the *path operations* in this module have the same:\n\n* Path `prefix`: `/items`.\n* `tags`: (just one tag: `items`).\n* Extra `responses`.\n* `dependencies`: they all need that `X-Token` dependency we created.\n\nSo, instead of adding all that to each *path operation*, we can add it to the `APIRouter`.\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\nAs the path of each *path operation* has to start with `/`, like in:\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n...the prefix must not include a final `/`.\n\nSo, the prefix in this case is `/items`.\n\nWe can also add a list of `tags` and extra `responses` that will be applied to all the *path operations* included in this router.\n\nAnd we can add a list of `dependencies` that will be added to all the *path operations* in the router and will be executed/solved for each request made to them.\n\n/// tip\n\nNote that, much like [dependencies in *path operation decorators*](dependencies/dependencies-in-path-operation-decorators.md), no value will be passed to your *path operation function*.\n\n///\n\nThe end result is that the item paths are now:\n\n* `/items/`\n* `/items/{item_id}`\n\n...as we intended.\n\n* They will be marked with a list of tags that contain a single string `\"items\"`.\n    * These \"tags\" are especially useful for the automatic interactive documentation systems (using OpenAPI).\n* All of them will include the predefined `responses`.\n* All these *path operations* will have the list of `dependencies` evaluated/executed before them.\n    * If you also declare dependencies in a specific *path operation*, **they will be executed too**.\n    * The router dependencies are executed first, then the [`dependencies` in the decorator](dependencies/dependencies-in-path-operation-decorators.md), and then the normal parameter dependencies.\n    * You can also add [`Security` dependencies with `scopes`](../advanced/security/oauth2-scopes.md).\n\n/// tip\n\nHaving `dependencies` in the `APIRouter` can be used, for example, to require authentication for a whole group of *path operations*. Even if the dependencies are not added individually to each one of them.\n\n///\n\n/// check\n\nThe `prefix`, `tags`, `responses`, and `dependencies` parameters are (as in many other cases) just a feature from **FastAPI** to help you avoid code duplication.\n\n///\n\n### Import the dependencies { #import-the-dependencies }\n\nThis code lives in the module `app.routers.items`, the file `app/routers/items.py`.\n\nAnd we need to get the dependency function from the module `app.dependencies`, the file `app/dependencies.py`.\n\nSo we use a relative import with `..` for the dependencies:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### How relative imports work { #how-relative-imports-work }\n\n/// tip\n\nIf you know perfectly how imports work, continue to the next section below.\n\n///\n\nA single dot `.`, like in:\n\n```Python\nfrom .dependencies import get_token_header\n```\n\nwould mean:\n\n* Starting in the same package that this module (the file `app/routers/items.py`) lives in (the directory `app/routers/`)...\n* find the module `dependencies` (an imaginary file at `app/routers/dependencies.py`)...\n* and from it, import the function `get_token_header`.\n\nBut that file doesn't exist, our dependencies are in a file at `app/dependencies.py`.\n\nRemember how our app/file structure looks like:\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\nThe two dots `..`, like in:\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\nmean:\n\n* Starting in the same package that this module (the file `app/routers/items.py`) lives in (the directory `app/routers/`)...\n* go to the parent package (the directory `app/`)...\n* and in there, find the module `dependencies` (the file at `app/dependencies.py`)...\n* and from it, import the function `get_token_header`.\n\nThat works correctly! 🎉\n\n---\n\nThe same way, if we had used three dots `...`, like in:\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\nthat would mean:\n\n* Starting in the same package that this module (the file `app/routers/items.py`) lives in (the directory `app/routers/`)...\n* go to the parent package (the directory `app/`)...\n* then go to the parent of that package (there's no parent package, `app` is the top level 😱)...\n* and in there, find the module `dependencies` (the file at `app/dependencies.py`)...\n* and from it, import the function `get_token_header`.\n\nThat would refer to some package above `app/`, with its own file `__init__.py`, etc. But we don't have that. So, that would throw an error in our example. 🚨\n\nBut now you know how it works, so you can use relative imports in your own apps no matter how complex they are. 🤓\n\n### Add some custom `tags`, `responses`, and `dependencies` { #add-some-custom-tags-responses-and-dependencies }\n\nWe are not adding the prefix `/items` nor the `tags=[\"items\"]` to each *path operation* because we added them to the `APIRouter`.\n\nBut we can still add _more_ `tags` that will be applied to a specific *path operation*, and also some extra `responses` specific to that *path operation*:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip\n\nThis last path operation will have the combination of tags: `[\"items\", \"custom\"]`.\n\nAnd it will also have both responses in the documentation, one for `404` and one for `403`.\n\n///\n\n## The main `FastAPI` { #the-main-fastapi }\n\nNow, let's see the module at `app/main.py`.\n\nHere's where you import and use the class `FastAPI`.\n\nThis will be the main file in your application that ties everything together.\n\nAnd as most of your logic will now live in its own specific module, the main file will be quite simple.\n\n### Import `FastAPI` { #import-fastapi }\n\nYou import and create a `FastAPI` class as normally.\n\nAnd we can even declare [global dependencies](dependencies/global-dependencies.md) that will be combined with the dependencies for each `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### Import the `APIRouter` { #import-the-apirouter }\n\nNow we import the other submodules that have `APIRouter`s:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\nAs the files `app/routers/users.py` and `app/routers/items.py` are submodules that are part of the same Python package `app`, we can use a single dot `.` to import them using \"relative imports\".\n\n### How the importing works { #how-the-importing-works }\n\nThe section:\n\n```Python\nfrom .routers import items, users\n```\n\nmeans:\n\n* Starting in the same package that this module (the file `app/main.py`) lives in (the directory `app/`)...\n* look for the subpackage `routers` (the directory at `app/routers/`)...\n* and from it, import the submodule `items` (the file at `app/routers/items.py`) and `users` (the file at `app/routers/users.py`)...\n\nThe module `items` will have a variable `router` (`items.router`). This is the same one we created in the file `app/routers/items.py`, it's an `APIRouter` object.\n\nAnd then we do the same for the module `users`.\n\nWe could also import them like:\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info\n\nThe first version is a \"relative import\":\n\n```Python\nfrom .routers import items, users\n```\n\nThe second version is an \"absolute import\":\n\n```Python\nfrom app.routers import items, users\n```\n\nTo learn more about Python Packages and Modules, read [the official Python documentation about Modules](https://docs.python.org/3/tutorial/modules.html).\n\n///\n\n### Avoid name collisions { #avoid-name-collisions }\n\nWe are importing the submodule `items` directly, instead of importing just its variable `router`.\n\nThis is because we also have another variable named `router` in the submodule `users`.\n\nIf we had imported one after the other, like:\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\nthe `router` from `users` would overwrite the one from `items` and we wouldn't be able to use them at the same time.\n\nSo, to be able to use both of them in the same file, we import the submodules directly:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### Include the `APIRouter`s for `users` and `items` { #include-the-apirouters-for-users-and-items }\n\nNow, let's include the `router`s from the submodules `users` and `items`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info\n\n`users.router` contains the `APIRouter` inside of the file `app/routers/users.py`.\n\nAnd `items.router` contains the `APIRouter` inside of the file `app/routers/items.py`.\n\n///\n\nWith `app.include_router()` we can add each `APIRouter` to the main `FastAPI` application.\n\nIt will include all the routes from that router as part of it.\n\n/// note | Technical Details\n\nIt will actually internally create a *path operation* for each *path operation* that was declared in the `APIRouter`.\n\nSo, behind the scenes, it will actually work as if everything was the same single app.\n\n///\n\n/// check\n\nYou don't have to worry about performance when including routers.\n\nThis will take microseconds and will only happen at startup.\n\nSo it won't affect performance. ⚡\n\n///\n\n### Include an `APIRouter` with a custom `prefix`, `tags`, `responses`, and `dependencies` { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\nNow, let's imagine your organization gave you the `app/internal/admin.py` file.\n\nIt contains an `APIRouter` with some admin *path operations* that your organization shares between several projects.\n\nFor this example it will be super simple. But let's say that because it is shared with other projects in the organization, we cannot modify it and add a `prefix`, `dependencies`, `tags`, etc. directly to the `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nBut we still want to set a custom `prefix` when including the `APIRouter` so that all its *path operations* start with `/admin`, we want to secure it with the `dependencies` we already have for this project, and we want to include `tags` and `responses`.\n\nWe can declare all that without having to modify the original `APIRouter` by passing those parameters to `app.include_router()`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\nThat way, the original `APIRouter` will stay unmodified, so we can still share that same `app/internal/admin.py` file with other projects in the organization.\n\nThe result is that in our app, each of the *path operations* from the `admin` module will have:\n\n* The prefix `/admin`.\n* The tag `admin`.\n* The dependency `get_token_header`.\n* The response `418`. 🍵\n\nBut that will only affect that `APIRouter` in our app, not in any other code that uses it.\n\nSo, for example, other projects could use the same `APIRouter` with a different authentication method.\n\n### Include a *path operation* { #include-a-path-operation }\n\nWe can also add *path operations* directly to the `FastAPI` app.\n\nHere we do it... just to show that we can 🤷:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\nand it will work correctly, together with all the other *path operations* added with `app.include_router()`.\n\n/// info | Very Technical Details\n\n**Note**: this is a very technical detail that you probably can **just skip**.\n\n---\n\nThe `APIRouter`s are not \"mounted\", they are not isolated from the rest of the application.\n\nThis is because we want to include their *path operations* in the OpenAPI schema and the user interfaces.\n\nAs we cannot just isolate them and \"mount\" them independently of the rest, the *path operations* are \"cloned\" (re-created), not included directly.\n\n///\n\n## Configure the `entrypoint` in `pyproject.toml` { #configure-the-entrypoint-in-pyproject-toml }\n\nAs your FastAPI `app` object lives in `app/main.py`, you can configure the `entrypoint` in your `pyproject.toml` file like this:\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\nthat is equivalent to importing like:\n\n```python\nfrom app.main import app\n```\n\nThat way the `fastapi` command will know where to find your app.\n\n/// Note\n\nYou could also pass the path to the command, like:\n\n```console\n$ fastapi dev app/main.py\n```\n\nBut you would have to remember to pass the correct path every time you call the `fastapi` command.\n\nAdditionally, other tools might not be able to find it, for example the [VS Code Extension](../editor-support.md) or [FastAPI Cloud](https://fastapicloud.com), so it is recommended to use the `entrypoint` in `pyproject.toml`.\n\n///\n\n## Check the automatic API docs { #check-the-automatic-api-docs }\n\nNow, run your app:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nAnd open the docs at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nYou will see the automatic API docs, including the paths from all the submodules, using the correct paths (and prefixes) and the correct tags:\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## Include the same router multiple times with different `prefix` { #include-the-same-router-multiple-times-with-different-prefix }\n\nYou can also use `.include_router()` multiple times with the *same* router using different prefixes.\n\nThis could be useful, for example, to expose the same API under different prefixes, e.g. `/api/v1` and `/api/latest`.\n\nThis is an advanced usage that you might not really need, but it's there in case you do.\n\n## Include an `APIRouter` in another { #include-an-apirouter-in-another }\n\nThe same way you can include an `APIRouter` in a `FastAPI` application, you can include an `APIRouter` in another `APIRouter` using:\n\n```Python\nrouter.include_router(other_router)\n```\n\nMake sure you do it before including `router` in the `FastAPI` app, so that the *path operations* from `other_router` are also included.\n"
  },
  {
    "path": "docs/en/docs/tutorial/body-fields.md",
    "content": "# Body - Fields { #body-fields }\n\nThe same way you can declare additional validation and metadata in *path operation function* parameters with `Query`, `Path` and `Body`, you can declare validation and metadata inside of Pydantic models using Pydantic's `Field`.\n\n## Import `Field` { #import-field }\n\nFirst, you have to import it:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n\n/// warning\n\nNotice that `Field` is imported directly from `pydantic`, not from `fastapi` as are all the rest (`Query`, `Path`, `Body`, etc).\n\n///\n\n## Declare model attributes { #declare-model-attributes }\n\nYou can then use `Field` with model attributes:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field` works the same way as `Query`, `Path` and `Body`, it has all the same parameters, etc.\n\n/// note | Technical Details\n\nActually, `Query`, `Path` and others you'll see next create objects of subclasses of a common `Param` class, which is itself a subclass of Pydantic's `FieldInfo` class.\n\nAnd Pydantic's `Field` returns an instance of `FieldInfo` as well.\n\n`Body` also returns objects of a subclass of `FieldInfo` directly. And there are others you will see later that are subclasses of the `Body` class.\n\nRemember that when you import `Query`, `Path`, and others from `fastapi`, those are actually functions that return special classes.\n\n///\n\n/// tip\n\nNotice how each model's attribute with a type, default value and `Field` has the same structure as a *path operation function's* parameter, with `Field` instead of `Path`, `Query` and `Body`.\n\n///\n\n## Add extra information { #add-extra-information }\n\nYou can declare extra information in `Field`, `Query`, `Body`, etc. And it will be included in the generated JSON Schema.\n\nYou will learn more about adding extra information later in the docs, when learning to declare examples.\n\n/// warning\n\nExtra keys passed to `Field` will also be present in the resulting OpenAPI schema for your application.\nAs these keys may not necessarily be part of the OpenAPI specification, some OpenAPI tools, for example [the OpenAPI validator](https://validator.swagger.io/), may not work with your generated schema.\n\n///\n\n## Recap { #recap }\n\nYou can use Pydantic's `Field` to declare extra validations and metadata for model attributes.\n\nYou can also use the extra keyword arguments to pass additional JSON Schema metadata.\n"
  },
  {
    "path": "docs/en/docs/tutorial/body-multiple-params.md",
    "content": "# Body - Multiple Parameters { #body-multiple-parameters }\n\nNow that we have seen how to use `Path` and `Query`, let's see more advanced uses of request body declarations.\n\n## Mix `Path`, `Query` and body parameters { #mix-path-query-and-body-parameters }\n\nFirst, of course, you can mix `Path`, `Query` and request body parameter declarations freely and **FastAPI** will know what to do.\n\nAnd you can also declare body parameters as optional, by setting the default to `None`:\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note\n\nNotice that, in this case, the `item` that would be taken from the body is optional. As it has a `None` default value.\n\n///\n\n## Multiple body parameters { #multiple-body-parameters }\n\nIn the previous example, the *path operations* would expect a JSON body with the attributes of an `Item`, like:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\nBut you can also declare multiple body parameters, e.g. `item` and `user`:\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\n\nIn this case, **FastAPI** will notice that there is more than one body parameter in the function (there are two parameters that are Pydantic models).\n\nSo, it will then use the parameter names as keys (field names) in the body, and expect a body like:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note\n\nNotice that even though the `item` was declared the same way as before, it is now expected to be inside of the body with a key `item`.\n\n///\n\n**FastAPI** will do the automatic conversion from the request, so that the parameter `item` receives its specific content and the same for `user`.\n\nIt will perform the validation of the compound data, and will document it like that for the OpenAPI schema and automatic docs.\n\n## Singular values in body { #singular-values-in-body }\n\nThe same way there is a `Query` and `Path` to define extra data for query and path parameters, **FastAPI** provides an equivalent `Body`.\n\nFor example, extending the previous model, you could decide that you want to have another key `importance` in the same body, besides the `item` and `user`.\n\nIf you declare it as is, because it is a singular value, **FastAPI** will assume that it is a query parameter.\n\nBut you can instruct **FastAPI** to treat it as another body key using `Body`:\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\n\nIn this case, **FastAPI** will expect a body like:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\nAgain, it will convert the data types, validate, document, etc.\n\n## Multiple body params and query { #multiple-body-params-and-query }\n\nOf course, you can also declare additional query parameters whenever you need, additional to any body parameters.\n\nAs, by default, singular values are interpreted as query parameters, you don't have to explicitly add a `Query`, you can just do:\n\n```Python\nq: str | None = None\n```\n\nFor example:\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n\n/// info\n\n`Body` also has all the same extra validation and metadata parameters as `Query`, `Path` and others you will see later.\n\n///\n\n## Embed a single body parameter { #embed-a-single-body-parameter }\n\nLet's say you only have a single `item` body parameter from a Pydantic model `Item`.\n\nBy default, **FastAPI** will then expect its body directly.\n\nBut if you want it to expect a JSON with a key `item` and inside of it the model contents, as it does when you declare extra body parameters, you can use the special `Body` parameter `embed`:\n\n```Python\nitem: Item = Body(embed=True)\n```\n\nas in:\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\n\nIn this case **FastAPI** will expect a body like:\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\ninstead of:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## Recap { #recap }\n\nYou can add multiple body parameters to your *path operation function*, even though a request can only have a single body.\n\nBut **FastAPI** will handle it, give you the correct data in your function, and validate and document the correct schema in the *path operation*.\n\nYou can also declare singular values to be received as part of the body.\n\nAnd you can instruct **FastAPI** to embed the body in a key even when there is only a single parameter declared.\n"
  },
  {
    "path": "docs/en/docs/tutorial/body-nested-models.md",
    "content": "# Body - Nested Models { #body-nested-models }\n\nWith **FastAPI**, you can define, validate, document, and use arbitrarily deeply nested models (thanks to Pydantic).\n\n## List fields { #list-fields }\n\nYou can define an attribute to be a subtype. For example, a Python `list`:\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\nThis will make `tags` be a list, although it doesn't declare the type of the elements of the list.\n\n## List fields with type parameter { #list-fields-with-type-parameter }\n\nBut Python has a specific way to declare lists with internal types, or \"type parameters\":\n\n### Declare a `list` with a type parameter { #declare-a-list-with-a-type-parameter }\n\nTo declare types that have type parameters (internal types), like `list`, `dict`, `tuple`,\npass the internal type(s) as \"type parameters\" using square brackets: `[` and `]`\n\n```Python\nmy_list: list[str]\n```\n\nThat's all standard Python syntax for type declarations.\n\nUse that same standard syntax for model attributes with internal types.\n\nSo, in our example, we can make `tags` be specifically a \"list of strings\":\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## Set types { #set-types }\n\nBut then we think about it, and realize that tags shouldn't repeat, they would probably be unique strings.\n\nAnd Python has a special data type for sets of unique items, the `set`.\n\nThen we can declare `tags` as a set of strings:\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\nWith this, even if you receive a request with duplicate data, it will be converted to a set of unique items.\n\nAnd whenever you output that data, even if the source had duplicates, it will be output as a set of unique items.\n\nAnd it will be annotated / documented accordingly too.\n\n## Nested Models { #nested-models }\n\nEach attribute of a Pydantic model has a type.\n\nBut that type can itself be another Pydantic model.\n\nSo, you can declare deeply nested JSON \"objects\" with specific attribute names, types and validations.\n\nAll that, arbitrarily nested.\n\n### Define a submodel { #define-a-submodel }\n\nFor example, we can define an `Image` model:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### Use the submodel as a type { #use-the-submodel-as-a-type }\n\nAnd then we can use it as the type of an attribute:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\nThis would mean that **FastAPI** would expect a body similar to:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\nAgain, doing just that declaration, with **FastAPI** you get:\n\n* Editor support (completion, etc.), even for nested models\n* Data conversion\n* Data validation\n* Automatic documentation\n\n## Special types and validation { #special-types-and-validation }\n\nApart from normal singular types like `str`, `int`, `float`, etc. you can use more complex singular types that inherit from `str`.\n\nTo see all the options you have, checkout [Pydantic's Type Overview](https://docs.pydantic.dev/latest/concepts/types/). You will see some examples in the next chapter.\n\nFor 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`:\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\nThe string will be checked to be a valid URL, and documented in JSON Schema / OpenAPI as such.\n\n## Attributes with lists of submodels { #attributes-with-lists-of-submodels }\n\nYou can also use Pydantic models as subtypes of `list`, `set`, etc.:\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\nThis will expect (convert, validate, document, etc.) a JSON body like:\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info\n\nNotice how the `images` key now has a list of image objects.\n\n///\n\n## Deeply nested models { #deeply-nested-models }\n\nYou can define arbitrarily deeply nested models:\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info\n\nNotice how `Offer` has a list of `Item`s, which in turn have an optional list of `Image`s\n\n///\n\n## Bodies of pure lists { #bodies-of-pure-lists }\n\nIf the top level value of the JSON body you expect is a JSON `array` (a Python `list`), you can declare the type in the parameter of the function, the same as in Pydantic models:\n\n```Python\nimages: list[Image]\n```\n\nas in:\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## Editor support everywhere { #editor-support-everywhere }\n\nAnd you get editor support everywhere.\n\nEven for items inside of lists:\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\nYou couldn't get this kind of editor support if you were working directly with `dict` instead of Pydantic models.\n\nBut you don't have to worry about them either, incoming dicts are converted automatically and your output is converted automatically to JSON too.\n\n## Bodies of arbitrary `dict`s { #bodies-of-arbitrary-dicts }\n\nYou can also declare a body as a `dict` with keys of some type and values of some other type.\n\nThis way, you don't have to know beforehand what the valid field/attribute names are (as would be the case with Pydantic models).\n\nThis would be useful if you want to receive keys that you don't already know.\n\n---\n\nAnother useful case is when you want to have keys of another type (e.g., `int`).\n\nThat's what we are going to see here.\n\nIn this case, you would accept any `dict` as long as it has `int` keys with `float` values:\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip\n\nKeep in mind that JSON only supports `str` as keys.\n\nBut Pydantic has automatic data conversion.\n\nThis means that, even though your API clients can only send strings as keys, as long as those strings contain pure integers, Pydantic will convert them and validate them.\n\nAnd the `dict` you receive as `weights` will actually have `int` keys and `float` values.\n\n///\n\n## Recap { #recap }\n\nWith **FastAPI** you have the maximum flexibility provided by Pydantic models, while keeping your code simple, short and elegant.\n\nBut with all the benefits:\n\n* Editor support (completion everywhere!)\n* Data conversion (a.k.a. parsing / serialization)\n* Data validation\n* Schema documentation\n* Automatic docs\n"
  },
  {
    "path": "docs/en/docs/tutorial/body-updates.md",
    "content": "# Body - Updates { #body-updates }\n\n## Update replacing with `PUT` { #update-replacing-with-put }\n\nTo update an item you can use the [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) operation.\n\nYou can use the `jsonable_encoder` to convert the input data to data that can be stored as JSON (e.g. with a NoSQL database). For example, converting `datetime` to `str`.\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT` is used to receive data that should replace the existing data.\n\n### Warning about replacing { #warning-about-replacing }\n\nThat means that if you want to update the item `bar` using `PUT` with a body containing:\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\nbecause it doesn't include the already stored attribute `\"tax\": 20.2`, the input model would take the default value of `\"tax\": 10.5`.\n\nAnd the data would be saved with that \"new\" `tax` of `10.5`.\n\n## Partial updates with `PATCH` { #partial-updates-with-patch }\n\nYou can also use the [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) operation to *partially* update data.\n\nThis means that you can send only the data that you want to update, leaving the rest intact.\n\n/// note\n\n`PATCH` is less commonly used and known than `PUT`.\n\nAnd many teams use only `PUT`, even for partial updates.\n\nYou are **free** to use them however you want, **FastAPI** doesn't impose any restrictions.\n\nBut this guide shows you, more or less, how they are intended to be used.\n\n///\n\n### Using Pydantic's `exclude_unset` parameter { #using-pydantics-exclude-unset-parameter }\n\nIf you want to receive partial updates, it's very useful to use the parameter `exclude_unset` in Pydantic's model's `.model_dump()`.\n\nLike `item.model_dump(exclude_unset=True)`.\n\nThat would generate a `dict` with only the data that was set when creating the `item` model, excluding default values.\n\nThen you can use this to generate a `dict` with only the data that was set (sent in the request), omitting default values:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### Using Pydantic's `update` parameter { #using-pydantics-update-parameter }\n\nNow, you can create a copy of the existing model using `.model_copy()`, and pass the `update` parameter with a `dict` containing the data to update.\n\nLike `stored_item_model.model_copy(update=update_data)`:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### Partial updates recap { #partial-updates-recap }\n\nIn summary, to apply partial updates you would:\n\n* (Optionally) use `PATCH` instead of `PUT`.\n* Retrieve the stored data.\n* Put that data in a Pydantic model.\n* Generate a `dict` without default values from the input model (using `exclude_unset`).\n    * This way you can update only the values actually set by the user, instead of overriding values already stored with default values in your model.\n* Create a copy of the stored model, updating its attributes with the received partial updates (using the `update` parameter).\n* Convert the copied model to something that can be stored in your DB (for example, using the `jsonable_encoder`).\n    * This is comparable to using the model's `.model_dump()` method again, but it makes sure (and converts) the values to data types that can be converted to JSON, for example, `datetime` to `str`.\n* Save the data to your DB.\n* Return the updated model.\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip\n\nYou can actually use this same technique with an HTTP `PUT` operation.\n\nBut the example here uses `PATCH` because it was created for these use cases.\n\n///\n\n/// note\n\nNotice that the input model is still validated.\n\nSo, if you want to receive partial updates that can omit all the attributes, you need to have a model with all the attributes marked as optional (with default values or `None`).\n\nTo distinguish from the models with all optional values for **updates** and models with required values for **creation**, you can use the ideas described in [Extra Models](extra-models.md).\n\n///\n"
  },
  {
    "path": "docs/en/docs/tutorial/body.md",
    "content": "# Request Body { #request-body }\n\nWhen you need to send data from a client (let's say, a browser) to your API, you send it as a **request body**.\n\nA **request** body is data sent by the client to your API. A **response** body is the data your API sends to the client.\n\nYour API almost always has to send a **response** body. But clients don't necessarily need to send **request bodies** all the time, sometimes they only request a path, maybe with some query parameters, but don't send a body.\n\nTo declare a **request** body, you use [Pydantic](https://docs.pydantic.dev/) models with all their power and benefits.\n\n/// info\n\nTo send data, you should use one of: `POST` (the more common), `PUT`, `DELETE` or `PATCH`.\n\nSending a body with a `GET` request has an undefined behavior in the specifications, nevertheless, it is supported by FastAPI, only for very complex/extreme use cases.\n\nAs it is discouraged, the interactive docs with Swagger UI won't show the documentation for the body when using `GET`, and proxies in the middle might not support it.\n\n///\n\n## Import Pydantic's `BaseModel` { #import-pydantics-basemodel }\n\nFirst, you need to import `BaseModel` from `pydantic`:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## Create your data model { #create-your-data-model }\n\nThen you declare your data model as a class that inherits from `BaseModel`.\n\nUse standard Python types for all the attributes:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\n\nThe same as when declaring query parameters, when a model attribute has a default value, it is not required. Otherwise, it is required. Use `None` to make it just optional.\n\nFor example, this model above declares a JSON \"`object`\" (or Python `dict`) like:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n...as `description` and `tax` are optional (with a default value of `None`), this JSON \"`object`\" would also be valid:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## Declare it as a parameter { #declare-it-as-a-parameter }\n\nTo add it to your *path operation*, declare it the same way you declared path and query parameters:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n...and declare its type as the model you created, `Item`.\n\n## Results { #results }\n\nWith just that Python type declaration, **FastAPI** will:\n\n* Read the body of the request as JSON.\n* Convert the corresponding types (if needed).\n* Validate the data.\n    * If the data is invalid, it will return a nice and clear error, indicating exactly where and what was the incorrect data.\n* Give you the received data in the parameter `item`.\n    * As you declared it in the function to be of type `Item`, you will also have all the editor support (completion, etc) for all of the attributes and their types.\n* Generate [JSON Schema](https://json-schema.org) definitions for your model, you can also use them anywhere else you like if it makes sense for your project.\n* Those schemas will be part of the generated OpenAPI schema, and used by the automatic documentation <abbr title=\"User Interfaces\">UIs</abbr>.\n\n## Automatic docs { #automatic-docs }\n\nThe JSON Schemas of your models will be part of your OpenAPI generated schema, and will be shown in the interactive API docs:\n\n<img src=\"/img/tutorial/body/image01.png\">\n\nAnd will also be used in the API docs inside each *path operation* that needs them:\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## Editor support { #editor-support }\n\nIn your editor, inside your function you will get type hints and completion everywhere (this wouldn't happen if you received a `dict` instead of a Pydantic model):\n\n<img src=\"/img/tutorial/body/image03.png\">\n\nYou also get error checks for incorrect type operations:\n\n<img src=\"/img/tutorial/body/image04.png\">\n\nThis is not by chance, the whole framework was built around that design.\n\nAnd it was thoroughly tested at the design phase, before any implementation, to ensure it would work with all the editors.\n\nThere were even some changes to Pydantic itself to support this.\n\nThe previous screenshots were taken with [Visual Studio Code](https://code.visualstudio.com).\n\nBut you would get the same editor support with [PyCharm](https://www.jetbrains.com/pycharm/) and most of the other Python editors:\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip\n\nIf you use [PyCharm](https://www.jetbrains.com/pycharm/) as your editor, you can use the [Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/).\n\nIt improves editor support for Pydantic models, with:\n\n* auto-completion\n* type checks\n* refactoring\n* searching\n* inspections\n\n///\n\n## Use the model { #use-the-model }\n\nInside of the function, you can access all the attributes of the model object directly:\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## Request body + path parameters { #request-body-path-parameters }\n\nYou can declare path parameters and request body at the same time.\n\n**FastAPI** will recognize that the function parameters that match path parameters should be **taken from the path**, and that function parameters that are declared to be Pydantic models should be **taken from the request body**.\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n\n## Request body + path + query parameters { #request-body-path-query-parameters }\n\nYou can also declare **body**, **path** and **query** parameters, all at the same time.\n\n**FastAPI** will recognize each of them and take the data from the correct place.\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\nThe function parameters will be recognized as follows:\n\n* If the parameter is also declared in the **path**, it will be used as a path parameter.\n* If the parameter is of a **singular type** (like `int`, `float`, `str`, `bool`, etc) it will be interpreted as a **query** parameter.\n* If the parameter is declared to be of the type of a **Pydantic model**, it will be interpreted as a request **body**.\n\n/// note\n\nFastAPI will know that the value of `q` is not required because of the default value `= None`.\n\nThe `str | None` is not used by FastAPI to determine that the value is not required, it will know it's not required because it has a default value of `= None`.\n\nBut adding the type annotations will allow your editor to give you better support and detect errors.\n\n///\n\n## Without Pydantic { #without-pydantic }\n\nIf you don't want to use Pydantic models, you can also use **Body** parameters. See the docs for [Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body).\n"
  },
  {
    "path": "docs/en/docs/tutorial/cookie-param-models.md",
    "content": "# Cookie Parameter Models { #cookie-parameter-models }\n\nIf you have a group of **cookies** that are related, you can create a **Pydantic model** to declare them. 🍪\n\nThis would allow you to **re-use the model** in **multiple places** and also to declare validations and metadata for all the parameters at once. 😎\n\n/// note\n\nThis is supported since FastAPI version `0.115.0`. 🤓\n\n///\n\n/// tip\n\nThis same technique applies to `Query`, `Cookie`, and `Header`. 😎\n\n///\n\n## Cookies with a Pydantic Model { #cookies-with-a-pydantic-model }\n\nDeclare the **cookie** parameters that you need in a **Pydantic model**, and then declare the parameter as `Cookie`:\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI** will **extract** the data for **each field** from the **cookies** received in the request and give you the Pydantic model you defined.\n\n## Check the Docs { #check-the-docs }\n\nYou can see the defined cookies in the docs UI at `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info\n\nHave in mind that, as **browsers handle cookies** in special ways and behind the scenes, they **don't** easily allow **JavaScript** to touch them.\n\nIf you go to the **API docs UI** at `/docs` you will be able to see the **documentation** for cookies for your *path operations*.\n\nBut even if you **fill the data** and click \"Execute\", because the docs UI works with **JavaScript**, the cookies won't be sent, and you will see an **error** message as if you didn't write any values.\n\n///\n\n## Forbid Extra Cookies { #forbid-extra-cookies }\n\nIn some special use cases (probably not very common), you might want to **restrict** the cookies that you want to receive.\n\nYour API now has the power to control its own <dfn title=\"This is a joke, just in case. It has nothing to do with cookie consents, but it's funny that even the API can now reject the poor cookies. Have a cookie. 🍪\">cookie consent</dfn>. 🤪🍪\n\nYou can use Pydantic's model configuration to `forbid` any `extra` fields:\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\nIf a client tries to send some **extra cookies**, they will receive an **error** response.\n\nPoor cookie banners with all their effort to get your consent for the <dfn title=\"This is another joke. Don't pay attention to me. Have some coffee for your cookie. ☕\">API to reject it</dfn>. 🍪\n\nFor example, if the client tries to send a `santa_tracker` cookie with a value of `good-list-please`, the client will receive an **error** response telling them that the `santa_tracker` <dfn title=\"Santa disapproves the lack of cookies. 🎅 Okay, no more cookie jokes.\">cookie is not allowed</dfn>:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## Summary { #summary }\n\nYou can use **Pydantic models** to declare <dfn title=\"Have a last cookie before you go. 🍪\">**cookies**</dfn> in **FastAPI**. 😎\n"
  },
  {
    "path": "docs/en/docs/tutorial/cookie-params.md",
    "content": "# Cookie Parameters { #cookie-parameters }\n\nYou can define Cookie parameters the same way you define `Query` and `Path` parameters.\n\n## Import `Cookie` { #import-cookie }\n\nFirst import `Cookie`:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## Declare `Cookie` parameters { #declare-cookie-parameters }\n\nThen declare the cookie parameters using the same structure as with `Path` and `Query`.\n\nYou can define the default value as well as all the extra validation or annotation parameters:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Technical Details\n\n`Cookie` is a \"sister\" class of `Path` and `Query`. It also inherits from the same common `Param` class.\n\nBut remember that when you import `Query`, `Path`, `Cookie` and others from `fastapi`, those are actually functions that return special classes.\n\n///\n\n/// info\n\nTo declare cookies, you need to use `Cookie`, because otherwise the parameters would be interpreted as query parameters.\n\n///\n\n/// info\n\nHave in mind that, as **browsers handle cookies** in special ways and behind the scenes, they **don't** easily allow **JavaScript** to touch them.\n\nIf you go to the **API docs UI** at `/docs` you will be able to see the **documentation** for cookies for your *path operations*.\n\nBut even if you **fill the data** and click \"Execute\", because the docs UI works with **JavaScript**, the cookies won't be sent, and you will see an **error** message as if you didn't write any values.\n\n///\n\n## Recap { #recap }\n\nDeclare cookies with `Cookie`, using the same common pattern as `Query` and `Path`.\n"
  },
  {
    "path": "docs/en/docs/tutorial/cors.md",
    "content": "# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }\n\n[CORS or \"Cross-Origin Resource Sharing\"](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) refers to the situations when a frontend running in a browser has JavaScript code that communicates with a backend, and the backend is in a different \"origin\" than the frontend.\n\n## Origin { #origin }\n\nAn origin is the combination of protocol (`http`, `https`), domain (`myapp.com`, `localhost`, `localhost.tiangolo.com`), and port (`80`, `443`, `8080`).\n\nSo, all these are different origins:\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\nEven if they are all in `localhost`, they use different protocols or ports, so, they are different \"origins\".\n\n## Steps { #steps }\n\nSo, let's say you have a frontend running in your browser at `http://localhost:8080`, and its JavaScript is trying to communicate with a backend running at `http://localhost` (because we don't specify a port, the browser will assume the default port `80`).\n\nThen, the browser will send an HTTP `OPTIONS` request to the `:80`-backend, and if the backend sends the appropriate headers authorizing the communication from this different origin (`http://localhost:8080`) then the `:8080`-browser will let the JavaScript in the frontend send its request to the `:80`-backend.\n\nTo achieve this, the `:80`-backend must have a list of \"allowed origins\".\n\nIn this case, the list would have to include `http://localhost:8080` for the `:8080`-frontend to work correctly.\n\n## Wildcards { #wildcards }\n\nIt's also possible to declare the list as `\"*\"` (a \"wildcard\") to say that all are allowed.\n\nBut that will only allow certain types of communication, excluding everything that involves credentials: Cookies, Authorization headers like those used with Bearer Tokens, etc.\n\nSo, for everything to work correctly, it's better to specify explicitly the allowed origins.\n\n## Use `CORSMiddleware` { #use-corsmiddleware }\n\nYou can configure it in your **FastAPI** application using the `CORSMiddleware`.\n\n* Import `CORSMiddleware`.\n* Create a list of allowed origins (as strings).\n* Add it as a \"middleware\" to your **FastAPI** application.\n\nYou can also specify whether your backend allows:\n\n* Credentials (Authorization headers, Cookies, etc).\n* Specific HTTP methods (`POST`, `PUT`) or all of them with the wildcard `\"*\"`.\n* Specific HTTP headers or all of them with the wildcard `\"*\"`.\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\n\nThe default parameters used by the `CORSMiddleware` implementation are restrictive by default, so you'll need to explicitly enable particular origins, methods, or headers, in order for browsers to be permitted to use them in a Cross-Domain context.\n\nThe following arguments are supported:\n\n* `allow_origins` - A list of origins that should be permitted to make cross-origin requests. E.g. `['https://example.org', 'https://www.example.org']`. You can use `['*']` to allow any origin.\n* `allow_origin_regex` - A regex string to match against origins that should be permitted to make cross-origin requests. e.g. `'https://.*\\.example\\.org'`.\n* `allow_methods` - A list of HTTP methods that should be allowed for cross-origin requests. Defaults to `['GET']`. You can use `['*']` to allow all standard methods.\n* `allow_headers` - A list of HTTP request headers that should be supported for cross-origin requests. Defaults to `[]`. You can use `['*']` to allow all headers. The `Accept`, `Accept-Language`, `Content-Language` and `Content-Type` headers are always allowed for [simple CORS requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).\n* `allow_credentials` - Indicate that cookies should be supported for cross-origin requests. Defaults to `False`.\n\n    None of `allow_origins`, `allow_methods` and `allow_headers` can be set to `['*']` if `allow_credentials` is set to `True`. All of them must be [explicitly specified](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards).\n\n* `expose_headers` - Indicate any response headers that should be made accessible to the browser. Defaults to `[]`.\n* `max_age` - Sets a maximum time in seconds for browsers to cache CORS responses. Defaults to `600`.\n\nThe middleware responds to two particular types of HTTP request...\n\n### CORS preflight requests { #cors-preflight-requests }\n\nThese are any `OPTIONS` request with `Origin` and `Access-Control-Request-Method` headers.\n\nIn this case the middleware will intercept the incoming request and respond with appropriate CORS headers, and either a `200` or `400` response for informational purposes.\n\n### Simple requests { #simple-requests }\n\nAny request with an `Origin` header. In this case the middleware will pass the request through as normal, but will include appropriate CORS headers on the response.\n\n## More info { #more-info }\n\nFor more info about <abbr title=\"Cross-Origin Resource Sharing\">CORS</abbr>, check the [Mozilla CORS documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).\n\n/// note | Technical Details\n\nYou could also use `from starlette.middleware.cors import CORSMiddleware`.\n\n**FastAPI** provides several middlewares in `fastapi.middleware` just as a convenience for you, the developer. But most of the available middlewares come directly from Starlette.\n\n///\n"
  },
  {
    "path": "docs/en/docs/tutorial/debugging.md",
    "content": "# Debugging { #debugging }\n\nYou can connect the debugger in your editor, for example with Visual Studio Code or PyCharm.\n\n## Call `uvicorn` { #call-uvicorn }\n\nIn your FastAPI application, import and run `uvicorn` directly:\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### About `__name__ == \"__main__\"` { #about-name-main }\n\nThe main purpose of the `__name__ == \"__main__\"` is to have some code that is executed when your file is called with:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nbut is not called when another file imports it, like in:\n\n```Python\nfrom myapp import app\n```\n\n#### More details { #more-details }\n\nLet's say your file is named `myapp.py`.\n\nIf you run it with:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nthen the internal variable `__name__` in your file, created automatically by Python, will have as value the string `\"__main__\"`.\n\nSo, the section:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nwill run.\n\n---\n\nThis won't happen if you import that module (file).\n\nSo, if you have another file `importer.py` with:\n\n```Python\nfrom myapp import app\n\n# Some more code\n```\n\nin that case, the automatically created variable `__name__` inside of `myapp.py` will not have the value `\"__main__\"`.\n\nSo, the line:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nwill not be executed.\n\n/// info\n\nFor more information, check [the official Python docs](https://docs.python.org/3/library/__main__.html).\n\n///\n\n## Run your code with your debugger { #run-your-code-with-your-debugger }\n\nBecause you are running the Uvicorn server directly from your code, you can call your Python program (your FastAPI application) directly from the debugger.\n\n---\n\nFor example, in Visual Studio Code, you can:\n\n* Go to the \"Debug\" panel.\n* \"Add configuration...\".\n* Select \"Python\"\n* Run the debugger with the option \"`Python: Current File (Integrated Terminal)`\".\n\nIt will then start the server with your **FastAPI** code, stop at your breakpoints, etc.\n\nHere's how it might look:\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\nIf you use Pycharm, you can:\n\n* Open the \"Run\" menu.\n* Select the option \"Debug...\".\n* Then a context menu shows up.\n* Select the file to debug (in this case, `main.py`).\n\nIt will then start the server with your **FastAPI** code, stop at your breakpoints, etc.\n\nHere's how it might look:\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/en/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# Classes as Dependencies { #classes-as-dependencies }\n\nBefore diving deeper into the **Dependency Injection** system, let's upgrade the previous example.\n\n## A `dict` from the previous example { #a-dict-from-the-previous-example }\n\nIn the previous example, we were returning a `dict` from our dependency (\"dependable\"):\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\nBut then we get a `dict` in the parameter `commons` of the *path operation function*.\n\nAnd we know that editors can't provide a lot of support (like completion) for `dict`s, because they can't know their keys and value types.\n\nWe can do better...\n\n## What makes a dependency { #what-makes-a-dependency }\n\nUp to now you have seen dependencies declared as functions.\n\nBut that's not the only way to declare dependencies (although it would probably be the more common).\n\nThe key factor is that a dependency should be a \"callable\".\n\nA \"**callable**\" in Python is anything that Python can \"call\" like a function.\n\nSo, if you have an object `something` (that might _not_ be a function) and you can \"call\" it (execute it) like:\n\n```Python\nsomething()\n```\n\nor\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\nthen it is a \"callable\".\n\n## Classes as dependencies { #classes-as-dependencies_1 }\n\nYou might notice that to create an instance of a Python class, you use that same syntax.\n\nFor example:\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\nIn this case, `fluffy` is an instance of the class `Cat`.\n\nAnd to create `fluffy`, you are \"calling\" `Cat`.\n\nSo, a Python class is also a **callable**.\n\nThen, in **FastAPI**, you could use a Python class as a dependency.\n\nWhat FastAPI actually checks is that it is a \"callable\" (function, class or anything else) and the parameters defined.\n\nIf you pass a \"callable\" as a dependency in **FastAPI**, it will analyze the parameters for that \"callable\", and process them in the same way as the parameters for a *path operation function*. Including sub-dependencies.\n\nThat also applies to callables with no parameters at all. The same as it would be for *path operation functions* with no parameters.\n\nThen, we can change the dependency \"dependable\" `common_parameters` from above to the class `CommonQueryParams`:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\nPay attention to the `__init__` method used to create the instance of the class:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n...it has the same parameters as our previous `common_parameters`:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\nThose parameters are what **FastAPI** will use to \"solve\" the dependency.\n\nIn both cases, it will have:\n\n* An optional `q` query parameter that is a `str`.\n* A `skip` query parameter that is an `int`, with a default of `0`.\n* A `limit` query parameter that is an `int`, with a default of `100`.\n\nIn both cases the data will be converted, validated, documented on the OpenAPI schema, etc.\n\n## Use it { #use-it }\n\nNow you can declare your dependency using this class.\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI** calls the `CommonQueryParams` class. This creates an \"instance\" of that class and the instance will be passed as the parameter `commons` to your function.\n\n## Type annotation vs `Depends` { #type-annotation-vs-depends }\n\nNotice how we write `CommonQueryParams` twice in the above code:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip\n\nPrefer to use the `Annotated` version if possible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\nThe last `CommonQueryParams`, in:\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n...is what **FastAPI** will actually use to know what is the dependency.\n\nIt is from this one that FastAPI will extract the declared parameters and that is what FastAPI will actually call.\n\n---\n\nIn this case, the first `CommonQueryParams`, in:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip\n\nPrefer to use the `Annotated` version if possible.\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n...doesn't have any special meaning for **FastAPI**. FastAPI won't use it for data conversion, validation, etc. (as it is using the `Depends(CommonQueryParams)` for that).\n\nYou could actually write just:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip\n\nPrefer to use the `Annotated` version if possible.\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n...as in:\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\nBut declaring the type is encouraged as that way your editor will know what will be passed as the parameter `commons`, and then it can help you with code completion, type checks, etc:\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## Shortcut { #shortcut }\n\nBut you see that we are having some code repetition here, writing `CommonQueryParams` twice:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip\n\nPrefer to use the `Annotated` version if possible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n**FastAPI** provides a shortcut for these cases, in where the dependency is *specifically* a class that **FastAPI** will \"call\" to create an instance of the class itself.\n\nFor those specific cases, you can do the following:\n\nInstead of writing:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip\n\nPrefer to use the `Annotated` version if possible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n...you write:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip\n\nPrefer to use the `Annotated` version if possible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\nYou declare the dependency as the type of the parameter, and you use `Depends()` without any parameter, instead of having to write the full class *again* inside of `Depends(CommonQueryParams)`.\n\nThe same example would then look like:\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n...and **FastAPI** will know what to do.\n\n/// tip\n\nIf that seems more confusing than helpful, disregard it, you don't *need* it.\n\nIt is just a shortcut. Because **FastAPI** cares about helping you minimize code repetition.\n\n///\n"
  },
  {
    "path": "docs/en/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# Dependencies in path operation decorators { #dependencies-in-path-operation-decorators }\n\nIn some cases you don't really need the return value of a dependency inside your *path operation function*.\n\nOr the dependency doesn't return a value.\n\nBut you still need it to be executed/solved.\n\nFor those cases, instead of declaring a *path operation function* parameter with `Depends`, you can add a `list` of `dependencies` to the *path operation decorator*.\n\n## Add `dependencies` to the *path operation decorator* { #add-dependencies-to-the-path-operation-decorator }\n\nThe *path operation decorator* receives an optional argument `dependencies`.\n\nIt should be a `list` of `Depends()`:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\nThese 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*.\n\n/// tip\n\nSome editors check for unused function parameters, and show them as errors.\n\nUsing these `dependencies` in the *path operation decorator* you can make sure they are executed while avoiding editor/tooling errors.\n\nIt might also help avoid confusion for new developers that see an unused parameter in your code and could think it's unnecessary.\n\n///\n\n/// info\n\nIn this example we use invented custom headers `X-Key` and `X-Token`.\n\nBut in real cases, when implementing security, you would get more benefits from using the integrated [Security utilities (the next chapter)](../security/index.md).\n\n///\n\n## Dependencies errors and return values { #dependencies-errors-and-return-values }\n\nYou can use the same dependency *functions* you use normally.\n\n### Dependency requirements { #dependency-requirements }\n\nThey can declare request requirements (like headers) or other sub-dependencies:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### Raise exceptions { #raise-exceptions }\n\nThese dependencies can `raise` exceptions, the same as normal dependencies:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### Return values { #return-values }\n\nAnd they can return values or not, the values won't be used.\n\nSo, you can reuse a normal dependency (that returns a value) you already use somewhere else, and even though the value won't be used, the dependency will be executed:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## Dependencies for a group of *path operations* { #dependencies-for-a-group-of-path-operations }\n\nLater, when reading about how to structure bigger applications ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md)), possibly with multiple files, you will learn how to declare a single `dependencies` parameter for a group of *path operations*.\n\n## Global Dependencies { #global-dependencies }\n\nNext we will see how to add dependencies to the whole `FastAPI` application, so that they apply to each *path operation*.\n"
  },
  {
    "path": "docs/en/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# Dependencies with yield { #dependencies-with-yield }\n\nFastAPI supports dependencies that do some <dfn title='sometimes also called \"exit code\", \"cleanup code\", \"teardown code\", \"closing code\", \"context manager exit code\", etc.'>extra steps after finishing</dfn>.\n\nTo do this, use `yield` instead of `return`, and write the extra steps (code) after.\n\n/// tip\n\nMake sure to use `yield` one single time per dependency.\n\n///\n\n/// note | Technical Details\n\nAny function that is valid to use with:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) or\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nwould be valid to use as a **FastAPI** dependency.\n\nIn fact, FastAPI uses those two decorators internally.\n\n///\n\n## A database dependency with `yield` { #a-database-dependency-with-yield }\n\nFor example, you could use this to create a database session and close it after finishing.\n\nOnly the code prior to and including the `yield` statement is executed before creating a response:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\nThe yielded value is what is injected into *path operations* and other dependencies:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\nThe code following the `yield` statement is executed after the response:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip\n\nYou can use `async` or regular functions.\n\n**FastAPI** will do the right thing with each, the same as with normal dependencies.\n\n///\n\n## A dependency with `yield` and `try` { #a-dependency-with-yield-and-try }\n\nIf you use a `try` block in a dependency with `yield`, you'll receive any exception that was thrown when using the dependency.\n\nFor example, if some code at some point in the middle, in another dependency or in a *path operation*, made a database transaction \"rollback\" or created any other exception, you would receive the exception in your dependency.\n\nSo, you can look for that specific exception inside the dependency with `except SomeException`.\n\nIn the same way, you can use `finally` to make sure the exit steps are executed, no matter if there was an exception or not.\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## Sub-dependencies with `yield` { #sub-dependencies-with-yield }\n\nYou can have sub-dependencies and \"trees\" of sub-dependencies of any size and shape, and any or all of them can use `yield`.\n\n**FastAPI** will make sure that the \"exit code\" in each dependency with `yield` is run in the correct order.\n\nFor example, `dependency_c` can have a dependency on `dependency_b`, and `dependency_b` on `dependency_a`:\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\nAnd all of them can use `yield`.\n\nIn this case `dependency_c`, to execute its exit code, needs the value from `dependency_b` (here named `dep_b`) to still be available.\n\nAnd, in turn, `dependency_b` needs the value from `dependency_a` (here named `dep_a`) to be available for its exit code.\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\nThe same way, you could have some dependencies with `yield` and some other dependencies with `return`, and have some of those depend on some of the others.\n\nAnd you could have a single dependency that requires several other dependencies with `yield`, etc.\n\nYou can have any combinations of dependencies that you want.\n\n**FastAPI** will make sure everything is run in the correct order.\n\n/// note | Technical Details\n\nThis works thanks to Python's [Context Managers](https://docs.python.org/3/library/contextlib.html).\n\n**FastAPI** uses them internally to achieve this.\n\n///\n\n## Dependencies with `yield` and `HTTPException` { #dependencies-with-yield-and-httpexception }\n\nYou saw that you can use dependencies with `yield` and have `try` blocks that try to execute some code and then run some exit code after `finally`.\n\nYou can also use `except` to catch the exception that was raised and do something with it.\n\nFor example, you can raise a different exception, like `HTTPException`.\n\n/// tip\n\nThis is a somewhat advanced technique, and in most of the cases you won't really need it, as you can raise exceptions (including `HTTPException`) from inside of the rest of your application code, for example, in the *path operation function*.\n\nBut it's there for you if you need it. 🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\nIf you want to catch exceptions and create a custom response based on that, create a [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers).\n\n## Dependencies with `yield` and `except` { #dependencies-with-yield-and-except }\n\nIf you catch an exception using `except` in a dependency with `yield` and you don't raise it again (or raise a new exception), FastAPI won't be able to notice there was an exception, the same way that would happen with regular Python:\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\nIn this case, the client will see an *HTTP 500 Internal Server Error* response as it should, given that we are not raising an `HTTPException` or similar, but the server will **not have any logs** or any other indication of what was the error. 😱\n\n### Always `raise` in Dependencies with `yield` and `except` { #always-raise-in-dependencies-with-yield-and-except }\n\nIf you catch an exception in a dependency with `yield`, unless you are raising another `HTTPException` or similar, **you should re-raise the original exception**.\n\nYou can re-raise the same exception using `raise`:\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\nNow the client will get the same *HTTP 500 Internal Server Error* response, but the server will have our custom `InternalError` in the logs. 😎\n\n## Execution of dependencies with `yield` { #execution-of-dependencies-with-yield }\n\nThe sequence of execution is more or less like this diagram. Time flows from top to bottom. And each column is one of the parts interacting or executing code.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exception handler\nparticipant dep as Dep with yield\nparticipant operation as Path Operation\nparticipant tasks as Background tasks\n\n    Note over client,operation: Can raise exceptions, including HTTPException\n    client ->> dep: Start request\n    Note over dep: Run code up to yield\n    opt raise Exception\n        dep -->> handler: Raise Exception\n        handler -->> client: HTTP error response\n    end\n    dep ->> operation: Run dependency, e.g. DB session\n    opt raise\n        operation -->> dep: Raise Exception (e.g. HTTPException)\n        opt handle\n            dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception\n        end\n        handler -->> client: HTTP error response\n    end\n\n    operation ->> client: Return response to client\n    Note over client,operation: Response is already sent, can't change it anymore\n    opt Tasks\n        operation -->> tasks: Send background tasks\n    end\n    opt Raise other exception\n        tasks -->> tasks: Handle exceptions in the background task code\n    end\n```\n\n/// info\n\nOnly **one response** will be sent to the client. It might be one of the error responses or it will be the response from the *path operation*.\n\nAfter one of those responses is sent, no other response can be sent.\n\n///\n\n/// tip\n\nIf you raise any exception in the code from the *path operation function*, it will be passed to the dependencies with yield, including `HTTPException`. In most cases you will want to re-raise that same exception or a new one from the dependency with `yield` to make sure it's properly handled.\n\n///\n\n## Early exit and `scope` { #early-exit-and-scope }\n\nNormally the exit code of dependencies with `yield` is executed **after the response** is sent to the client.\n\nBut if you know that you won't need to use the dependency after returning from the *path operation function*, you can use `Depends(scope=\"function\")` to tell FastAPI that it should close the dependency after the *path operation function* returns, but **before** the **response is sent**.\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()` receives a `scope` parameter that can be:\n\n* `\"function\"`: start the dependency before the *path operation function* that handles the request, end the dependency after the *path operation function* ends, but **before** the response is sent back to the client. So, the dependency function will be executed **around** the *path operation **function***.\n* `\"request\"`: start the dependency before the *path operation function* that handles the request (similar to when using `\"function\"`), but end **after** the response is sent back to the client. So, the dependency function will be executed **around** the **request** and response cycle.\n\nIf not specified and the dependency has `yield`, it will have a `scope` of `\"request\"` by default.\n\n### `scope` for sub-dependencies { #scope-for-sub-dependencies }\n\nWhen you declare a dependency with a `scope=\"request\"` (the default), any sub-dependency needs to also have a `scope` of `\"request\"`.\n\nBut a dependency with `scope` of `\"function\"` can have dependencies with `scope` of `\"function\"` and `scope` of `\"request\"`.\n\nThis is because any dependency needs to be able to run its exit code before the sub-dependencies, as it might need to still use them during its exit code.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Dep scope=\"request\"\nparticipant dep_func as Dep scope=\"function\"\nparticipant operation as Path Operation\n\n    client ->> dep_req: Start request\n    Note over dep_req: Run code up to yield\n    dep_req ->> dep_func: Pass dependency\n    Note over dep_func: Run code up to yield\n    dep_func ->> operation: Run path operation with dependency\n    operation ->> dep_func: Return from path operation\n    Note over dep_func: Run code after yield\n    Note over dep_func: ✅ Dependency closed\n    dep_func ->> client: Send response to client\n    Note over client: Response sent\n    Note over dep_req: Run code after yield\n    Note over dep_req: ✅ Dependency closed\n```\n\n## Dependencies with `yield`, `HTTPException`, `except` and Background Tasks { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\nDependencies with `yield` have evolved over time to cover different use cases and fix some issues.\n\nIf you want to see what has changed in different versions of FastAPI, you can read more about it in the advanced guide, in [Advanced Dependencies - Dependencies with `yield`, `HTTPException`, `except` and Background Tasks](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).\n## Context Managers { #context-managers }\n\n### What are \"Context Managers\" { #what-are-context-managers }\n\n\"Context Managers\" are any of those Python objects that you can use in a `with` statement.\n\nFor example, [you can use `with` to read a file](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files):\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\nUnderneath, the `open(\"./somefile.txt\")` creates an object that is called a \"Context Manager\".\n\nWhen the `with` block finishes, it makes sure to close the file, even if there were exceptions.\n\nWhen you create a dependency with `yield`, **FastAPI** will internally create a context manager for it, and combine it with some other related tools.\n\n### Using context managers in dependencies with `yield` { #using-context-managers-in-dependencies-with-yield }\n\n/// warning\n\nThis is, more or less, an \"advanced\" idea.\n\nIf you are just starting with **FastAPI** you might want to skip it for now.\n\n///\n\nIn Python, you can create Context Managers by [creating a class with two methods: `__enter__()` and `__exit__()`](https://docs.python.org/3/reference/datamodel.html#context-managers).\n\nYou can also use them inside of **FastAPI** dependencies with `yield` by using\n`with` or `async with` statements inside of the dependency function:\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip\n\nAnother way to create a context manager is with:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) or\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nusing them to decorate a function with a single `yield`.\n\nThat's what **FastAPI** uses internally for dependencies with `yield`.\n\nBut you don't have to use the decorators for FastAPI dependencies (and you shouldn't).\n\nFastAPI will do it for you internally.\n\n///\n"
  },
  {
    "path": "docs/en/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# Global Dependencies { #global-dependencies }\n\nFor some types of applications you might want to add dependencies to the whole application.\n\nSimilar to the way you can [add `dependencies` to the *path operation decorators*](dependencies-in-path-operation-decorators.md), you can add them to the `FastAPI` application.\n\nIn that case, they will be applied to all the *path operations* in the application:\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\n\nAnd all the ideas in the section about [adding `dependencies` to the *path operation decorators*](dependencies-in-path-operation-decorators.md) still apply, but in this case, to all of the *path operations* in the app.\n\n## Dependencies for groups of *path operations* { #dependencies-for-groups-of-path-operations }\n\nLater, when reading about how to structure bigger applications ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md)), possibly with multiple files, you will learn how to declare a single `dependencies` parameter for a group of *path operations*.\n"
  },
  {
    "path": "docs/en/docs/tutorial/dependencies/index.md",
    "content": "# Dependencies { #dependencies }\n\n**FastAPI** has a very powerful but intuitive **<dfn title=\"also known as components, resources, providers, services, injectables\">Dependency Injection</dfn>** system.\n\nIt is designed to be very simple to use, and to make it very easy for any developer to integrate other components with **FastAPI**.\n\n## What is \"Dependency Injection\" { #what-is-dependency-injection }\n\n**\"Dependency Injection\"** means, in programming, that there is a way for your code (in this case, your *path operation functions*) to declare things that it requires to work and use: \"dependencies\".\n\nAnd then, that system (in this case **FastAPI**) will take care of doing whatever is needed to provide your code with those needed dependencies (\"inject\" the dependencies).\n\nThis is very useful when you need to:\n\n* Have shared logic (the same code logic again and again).\n* Share database connections.\n* Enforce security, authentication, role requirements, etc.\n* And many other things...\n\nAll these, while minimizing code repetition.\n\n## First Steps { #first-steps }\n\nLet's see a very simple example. It will be so simple that it is not very useful, for now.\n\nBut this way we can focus on how the **Dependency Injection** system works.\n\n### Create a dependency, or \"dependable\" { #create-a-dependency-or-dependable }\n\nLet's first focus on the dependency.\n\nIt is just a function that can take all the same parameters that a *path operation function* can take:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\nThat's it.\n\n**2 lines**.\n\nAnd it has the same shape and structure that all your *path operation functions* have.\n\nYou can think of it as a *path operation function* without the \"decorator\" (without the `@app.get(\"/some-path\")`).\n\nAnd it can return anything you want.\n\nIn this case, this dependency expects:\n\n* An optional query parameter `q` that is a `str`.\n* An optional query parameter `skip` that is an `int`, and by default is `0`.\n* An optional query parameter `limit` that is an `int`, and by default is `100`.\n\nAnd then it just returns a `dict` containing those values.\n\n/// info\n\nFastAPI added support for `Annotated` (and started recommending it) in version 0.95.0.\n\nIf you have an older version, you would get errors when trying to use `Annotated`.\n\nMake sure you [Upgrade the FastAPI version](../../deployment/versions.md#upgrading-the-fastapi-versions) to at least 0.95.1 before using `Annotated`.\n\n///\n\n### Import `Depends` { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### Declare the dependency, in the \"dependant\" { #declare-the-dependency-in-the-dependant }\n\nThe same way you use `Body`, `Query`, etc. with your *path operation function* parameters, use `Depends` with a new parameter:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\nAlthough you use `Depends` in the parameters of your function the same way you use `Body`, `Query`, etc, `Depends` works a bit differently.\n\nYou only give `Depends` a single parameter.\n\nThis parameter must be something like a function.\n\nYou **don't call it** directly (don't add the parenthesis at the end), you just pass it as a parameter to `Depends()`.\n\nAnd that function takes parameters in the same way that *path operation functions* do.\n\n/// tip\n\nYou'll see what other \"things\", apart from functions, can be used as dependencies in the next chapter.\n\n///\n\nWhenever a new request arrives, **FastAPI** will take care of:\n\n* Calling your dependency (\"dependable\") function with the correct parameters.\n* Get the result from your function.\n* Assign that result to the parameter in your *path operation function*.\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\nThis way you write shared code once and **FastAPI** takes care of calling it for your *path operations*.\n\n/// check\n\nNotice that you don't have to create a special class and pass it somewhere to **FastAPI** to \"register\" it or anything similar.\n\nYou just pass it to `Depends` and **FastAPI** knows how to do the rest.\n\n///\n\n## Share `Annotated` dependencies { #share-annotated-dependencies }\n\nIn the examples above, you see that there's a tiny bit of **code duplication**.\n\nWhen you need to use the `common_parameters()` dependency, you have to write the whole parameter with the type annotation and `Depends()`:\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\nBut because we are using `Annotated`, we can store that `Annotated` value in a variable and use it in multiple places:\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip\n\nThis is just standard Python, it's called a \"type alias\", it's actually not specific to **FastAPI**.\n\nBut because **FastAPI** is based on the Python standards, including `Annotated`, you can use this trick in your code. 😎\n\n///\n\nThe dependencies will keep working as expected, and the **best part** is that the **type information will be preserved**, which means that your editor will be able to keep providing you with **autocompletion**, **inline errors**, etc. The same for other tools like `mypy`.\n\nThis will be especially useful when you use it in a **large code base** where you use **the same dependencies** over and over again in **many *path operations***.\n\n## To `async` or not to `async` { #to-async-or-not-to-async }\n\nAs dependencies will also be called by **FastAPI** (the same as your *path operation functions*), the same rules apply while defining your functions.\n\nYou can use `async def` or normal `def`.\n\nAnd you can declare dependencies with `async def` inside of normal `def` *path operation functions*, or `def` dependencies inside of `async def` *path operation functions*, etc.\n\nIt doesn't matter. **FastAPI** will know what to do.\n\n/// note\n\nIf you don't know, check the [Async: *\"In a hurry?\"*](../../async.md#in-a-hurry) section about `async` and `await` in the docs.\n\n///\n\n## Integrated with OpenAPI { #integrated-with-openapi }\n\nAll the request declarations, validations and requirements of your dependencies (and sub-dependencies) will be integrated in the same OpenAPI schema.\n\nSo, the interactive docs will have all the information from these dependencies too:\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## Simple usage { #simple-usage }\n\nIf you look at it, *path operation functions* are declared to be used whenever a *path* and *operation* matches, and then **FastAPI** takes care of calling the function with the correct parameters, extracting the data from the request.\n\nActually, all (or most) of the web frameworks work in this same way.\n\nYou never call those functions directly. They are called by your framework (in this case, **FastAPI**).\n\nWith the Dependency Injection system, you can also tell **FastAPI** that your *path operation function* also \"depends\" on something else that should be executed before your *path operation function*, and **FastAPI** will take care of executing it and \"injecting\" the results.\n\nOther common terms for this same idea of \"dependency injection\" are:\n\n* resources\n* providers\n* services\n* injectables\n* components\n\n## **FastAPI** plug-ins { #fastapi-plug-ins }\n\nIntegrations and \"plug-ins\" can be built using the **Dependency Injection** system. But in fact, there is actually **no need to create \"plug-ins\"**, as by using dependencies it's possible to declare an infinite number of integrations and interactions that become available to your *path operation functions*.\n\nAnd dependencies can be created in a very simple and intuitive way that allows you to just import the Python packages you need, and integrate them with your API functions in a couple of lines of code, *literally*.\n\nYou will see examples of this in the next chapters, about relational and NoSQL databases, security, etc.\n\n## **FastAPI** compatibility { #fastapi-compatibility }\n\nThe simplicity of the dependency injection system makes **FastAPI** compatible with:\n\n* all the relational databases\n* NoSQL databases\n* external packages\n* external APIs\n* authentication and authorization systems\n* API usage monitoring systems\n* response data injection systems\n* etc.\n\n## Simple and Powerful { #simple-and-powerful }\n\nAlthough the hierarchical dependency injection system is very simple to define and use, it's still very powerful.\n\nYou can define dependencies that in turn can define dependencies themselves.\n\nIn the end, a hierarchical tree of dependencies is built, and the **Dependency Injection** system takes care of solving all these dependencies for you (and their sub-dependencies) and providing (injecting) the results at each step.\n\nFor example, let's say you have 4 API endpoints (*path operations*):\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\nthen you could add different permission requirements for each of them just with dependencies and sub-dependencies:\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## Integrated with **OpenAPI** { #integrated-with-openapi_1 }\n\nAll these dependencies, while declaring their requirements, also add parameters, validations, etc. to your *path operations*.\n\n**FastAPI** will take care of adding it all to the OpenAPI schema, so that it is shown in the interactive documentation systems.\n"
  },
  {
    "path": "docs/en/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# Sub-dependencies { #sub-dependencies }\n\nYou can create dependencies that have **sub-dependencies**.\n\nThey can be as **deep** as you need them to be.\n\n**FastAPI** will take care of solving them.\n\n## First dependency \"dependable\" { #first-dependency-dependable }\n\nYou could create a first dependency (\"dependable\") like:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\nIt declares an optional query parameter `q` as a `str`, and then it just returns it.\n\nThis is quite simple (not very useful), but will help us focus on how the sub-dependencies work.\n\n## Second dependency, \"dependable\" and \"dependant\" { #second-dependency-dependable-and-dependant }\n\nThen you can create another dependency function (a \"dependable\") that at the same time declares a dependency of its own (so it is a \"dependant\" too):\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\nLet's focus on the parameters declared:\n\n* Even though this function is a dependency (\"dependable\") itself, it also declares another dependency (it \"depends\" on something else).\n    * It depends on the `query_extractor`, and assigns the value returned by it to the parameter `q`.\n* It also declares an optional `last_query` cookie, as a `str`.\n    * If the user didn't provide any query `q`, we use the last query used, which we saved to a cookie before.\n\n## Use the dependency { #use-the-dependency }\n\nThen we can use the dependency with:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info\n\nNotice that we are only declaring one dependency in the *path operation function*, the `query_or_cookie_extractor`.\n\nBut **FastAPI** will know that it has to solve `query_extractor` first, to pass the results of that to `query_or_cookie_extractor` while calling it.\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## Using the same dependency multiple times { #using-the-same-dependency-multiple-times }\n\nIf one of your dependencies is declared multiple times for the same *path operation*, for example, multiple dependencies have a common sub-dependency, **FastAPI** will know to call that sub-dependency only once per request.\n\nAnd it will save the returned value in a <dfn title=\"A utility/system to store computed/generated values, to reuse them instead of computing them again.\">\"cache\"</dfn> and pass it to all the \"dependants\" that need it in that specific request, instead of calling the dependency multiple times for the same request.\n\nIn an advanced scenario where you know you need the dependency to be called at every step (possibly multiple times) in the same request instead of using the \"cached\" value, you can set the parameter `use_cache=False` when using `Depends`:\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip\n\nPrefer to use the `Annotated` version if possible.\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## Recap { #recap }\n\nApart from all the fancy words used here, the **Dependency Injection** system is quite simple.\n\nJust functions that look the same as the *path operation functions*.\n\nBut still, it is very powerful, and allows you to declare arbitrarily deeply nested dependency \"graphs\" (trees).\n\n/// tip\n\nAll this might not seem as useful with these simple examples.\n\nBut you will see how useful it is in the chapters about **security**.\n\nAnd you will also see the amounts of code it will save you.\n\n///\n"
  },
  {
    "path": "docs/en/docs/tutorial/encoder.md",
    "content": "# JSON Compatible Encoder { #json-compatible-encoder }\n\nThere are some cases where you might need to convert a data type (like a Pydantic model) to something compatible with JSON (like a `dict`, `list`, etc).\n\nFor example, if you need to store it in a database.\n\nFor that, **FastAPI** provides a `jsonable_encoder()` function.\n\n## Using the `jsonable_encoder` { #using-the-jsonable-encoder }\n\nLet's imagine that you have a database `fake_db` that only receives JSON compatible data.\n\nFor example, it doesn't receive `datetime` objects, as those are not compatible with JSON.\n\nSo, a `datetime` object would have to be converted to a `str` containing the data in [ISO format](https://en.wikipedia.org/wiki/ISO_8601).\n\nThe same way, this database wouldn't receive a Pydantic model (an object with attributes), only a `dict`.\n\nYou can use `jsonable_encoder` for that.\n\nIt receives an object, like a Pydantic model, and returns a JSON compatible version:\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\nIn this example, it would convert the Pydantic model to a `dict`, and the `datetime` to a `str`.\n\nThe result of calling it is something that can be encoded with the Python standard [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps).\n\nIt doesn't return a large `str` containing the data in JSON format (as a string). It returns a Python standard data structure (e.g. a `dict`) with values and sub-values that are all compatible with JSON.\n\n/// note\n\n`jsonable_encoder` is actually used by **FastAPI** internally to convert data. But it is useful in many other scenarios.\n\n///\n"
  },
  {
    "path": "docs/en/docs/tutorial/extra-data-types.md",
    "content": "# Extra Data Types { #extra-data-types }\n\nUp to now, you have been using common data types, like:\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\nBut you can also use more complex data types.\n\nAnd you will still have the same features as seen up to now:\n\n* Great editor support.\n* Data conversion from incoming requests.\n* Data conversion for response data.\n* Data validation.\n* Automatic annotation and documentation.\n\n## Other data types { #other-data-types }\n\nHere are some of the additional data types you can use:\n\n* `UUID`:\n    * A standard \"Universally Unique Identifier\", common as an ID in many databases and systems.\n    * In requests and responses will be represented as a `str`.\n* `datetime.datetime`:\n    * A Python `datetime.datetime`.\n    * In requests and responses will be represented as a `str` in ISO 8601 format, like: `2008-09-15T15:53:00+05:00`.\n* `datetime.date`:\n    * Python `datetime.date`.\n    * In requests and responses will be represented as a `str` in ISO 8601 format, like: `2008-09-15`.\n* `datetime.time`:\n    * A Python `datetime.time`.\n    * In requests and responses will be represented as a `str` in ISO 8601 format, like: `14:23:55.003`.\n* `datetime.timedelta`:\n    * A Python `datetime.timedelta`.\n    * In requests and responses will be represented as a `float` of total seconds.\n    * Pydantic also allows representing it as a \"ISO 8601 time diff encoding\", [see the docs for more info](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).\n* `frozenset`:\n    * In requests and responses, treated the same as a `set`:\n        * In requests, a list will be read, eliminating duplicates and converting it to a `set`.\n        * In responses, the `set` will be converted to a `list`.\n        * The generated schema will specify that the `set` values are unique (using JSON Schema's `uniqueItems`).\n* `bytes`:\n    * Standard Python `bytes`.\n    * In requests and responses will be treated as `str`.\n    * The generated schema will specify that it's a `str` with `binary` \"format\".\n* `Decimal`:\n    * Standard Python `Decimal`.\n    * In requests and responses, handled the same as a `float`.\n* You can check all the valid Pydantic data types here: [Pydantic data types](https://docs.pydantic.dev/latest/usage/types/types/).\n\n## Example { #example }\n\nHere's an example *path operation* with parameters using some of the above types.\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\nNote that the parameters inside the function have their natural data type, and you can, for example, perform normal date manipulations, like:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/en/docs/tutorial/extra-models.md",
    "content": "# Extra Models { #extra-models }\n\nContinuing with the previous example, it will be common to have more than one related model.\n\nThis is especially the case for user models, because:\n\n* The **input model** needs to be able to have a password.\n* The **output model** should not have a password.\n* The **database model** would probably need to have a hashed password.\n\n/// danger\n\nNever store user's plaintext passwords. Always store a \"secure hash\" that you can then verify.\n\nIf you don't know, you will learn what a \"password hash\" is in the [security chapters](security/simple-oauth2.md#password-hashing).\n\n///\n\n## Multiple models { #multiple-models }\n\nHere's a general idea of how the models could look like with their password fields and the places where they are used:\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### About `**user_in.model_dump()` { #about-user-in-model-dump }\n\n#### Pydantic's `.model_dump()` { #pydantics-model-dump }\n\n`user_in` is a Pydantic model of class `UserIn`.\n\nPydantic models have a `.model_dump()` method that returns a `dict` with the model's data.\n\nSo, if we create a Pydantic object `user_in` like:\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\nand then we call:\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\nwe now have a `dict` with the data in the variable `user_dict` (it's a `dict` instead of a Pydantic model object).\n\nAnd if we call:\n\n```Python\nprint(user_dict)\n```\n\nwe would get a Python `dict` with:\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### Unpacking a `dict` { #unpacking-a-dict }\n\nIf we take a `dict` like `user_dict` and pass it to a function (or class) with `**user_dict`, Python will \"unpack\" it. It will pass the keys and values of the `user_dict` directly as key-value arguments.\n\nSo, continuing with the `user_dict` from above, writing:\n\n```Python\nUserInDB(**user_dict)\n```\n\nwould result in something equivalent to:\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\nOr more exactly, using `user_dict` directly, with whatever contents it might have in the future:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### A Pydantic model from the contents of another { #a-pydantic-model-from-the-contents-of-another }\n\nAs in the example above we got `user_dict` from `user_in.model_dump()`, this code:\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\nwould be equivalent to:\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n...because `user_in.model_dump()` is a `dict`, and then we make Python \"unpack\" it by passing it to `UserInDB` prefixed with `**`.\n\nSo, we get a Pydantic model from the data in another Pydantic model.\n\n#### Unpacking a `dict` and extra keywords { #unpacking-a-dict-and-extra-keywords }\n\nAnd then adding the extra keyword argument `hashed_password=hashed_password`, like in:\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n...ends up being like:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning\n\nThe supporting additional functions `fake_password_hasher` and `fake_save_user` are just to demo a possible flow of the data, but they of course are not providing any real security.\n\n///\n\n## Reduce duplication { #reduce-duplication }\n\nReducing code duplication is one of the core ideas in **FastAPI**.\n\nAs code duplication increments the chances of bugs, security issues, code desynchronization issues (when you update in one place but not in the others), etc.\n\nAnd these models are all sharing a lot of the data and duplicating attribute names and types.\n\nWe could do better.\n\nWe can declare a `UserBase` model that serves as a base for our other models. And then we can make subclasses of that model that inherit its attributes (type declarations, validation, etc).\n\nAll the data conversion, validation, documentation, etc. will still work as normally.\n\nThat way, we can declare just the differences between the models (with plaintext `password`, with `hashed_password` and without password):\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` or `anyOf` { #union-or-anyof }\n\nYou can declare a response to be the `Union` of two or more types, that means, that the response would be any of them.\n\nIt will be defined in OpenAPI with `anyOf`.\n\nTo do that, use the standard Python type hint [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union):\n\n/// note\n\nWhen defining a [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions), include the most specific type first, followed by the less specific type. In the example below, the more specific `PlaneItem` comes before `CarItem` in `Union[PlaneItem, CarItem]`.\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### `Union` in Python 3.10 { #union-in-python-3-10 }\n\nIn this example we pass `Union[PlaneItem, CarItem]` as the value of the argument `response_model`.\n\nBecause we are passing it as a **value to an argument** instead of putting it in a **type annotation**, we have to use `Union` even in Python 3.10.\n\nIf it was in a type annotation we could have used the vertical bar, as:\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\nBut if we put that in the assignment `response_model=PlaneItem | CarItem` we would get an error, because Python would try to perform an **invalid operation** between `PlaneItem` and `CarItem` instead of interpreting that as a type annotation.\n\n## List of models { #list-of-models }\n\nThe same way, you can declare responses of lists of objects.\n\nFor that, use the standard Python `list`:\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## Response with arbitrary `dict` { #response-with-arbitrary-dict }\n\nYou can also declare a response using a plain arbitrary `dict`, declaring just the type of the keys and values, without using a Pydantic model.\n\nThis is useful if you don't know the valid field/attribute names (that would be needed for a Pydantic model) beforehand.\n\nIn this case, you can use `dict`:\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## Recap { #recap }\n\nUse multiple Pydantic models and inherit freely for each case.\n\nYou don't need to have a single data model per entity if that entity must be able to have different \"states\". As the case with the user \"entity\" with a state including `password`, `password_hash` and no password.\n"
  },
  {
    "path": "docs/en/docs/tutorial/first-steps.md",
    "content": "# First Steps { #first-steps }\n\nThe simplest FastAPI file could look like this:\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\nCopy that to a file `main.py`.\n\nRun the live server:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nIn the output, there's a line with something like:\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\nThat line shows the URL where your app is being served on your local machine.\n\n### Check it { #check-it }\n\nOpen your browser at [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nYou will see the JSON response as:\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### Interactive API docs { #interactive-api-docs }\n\nNow go to [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nYou will see the automatic interactive API documentation (provided by [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Alternative API docs { #alternative-api-docs }\n\nAnd now, go to [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nYou will see the alternative automatic documentation (provided by [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI** generates a \"schema\" with all your API using the **OpenAPI** standard for defining APIs.\n\n#### \"Schema\" { #schema }\n\nA \"schema\" is a definition or description of something. Not the code that implements it, but just an abstract description.\n\n#### API \"schema\" { #api-schema }\n\nIn this case, [OpenAPI](https://github.com/OAI/OpenAPI-Specification) is a specification that dictates how to define a schema of your API.\n\nThis schema definition includes your API paths, the possible parameters they take, etc.\n\n#### Data \"schema\" { #data-schema }\n\nThe term \"schema\" might also refer to the shape of some data, like a JSON content.\n\nIn that case, it would mean the JSON attributes, and data types they have, etc.\n\n#### OpenAPI and JSON Schema { #openapi-and-json-schema }\n\nOpenAPI defines an API schema for your API. And that schema includes definitions (or \"schemas\") of the data sent and received by your API using **JSON Schema**, the standard for JSON data schemas.\n\n#### Check the `openapi.json` { #check-the-openapi-json }\n\nIf you are curious about how the raw OpenAPI schema looks like, FastAPI automatically generates a JSON (schema) with the descriptions of all your API.\n\nYou can see it directly at: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).\n\nIt will show a JSON starting with something like:\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### What is OpenAPI for { #what-is-openapi-for }\n\nThe OpenAPI schema is what powers the two interactive documentation systems included.\n\nAnd there are dozens of alternatives, all based on OpenAPI. You could easily add any of those alternatives to your application built with **FastAPI**.\n\nYou could also use it to generate code automatically, for clients that communicate with your API. For example, frontend, mobile or IoT applications.\n\n### Configure the app `entrypoint` in `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nYou can configure where your app is located in a `pyproject.toml` file like:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nThat `entrypoint` will tell the `fastapi` command that it should import the app like:\n\n```python\nfrom main import app\n```\n\nIf your code was structured like:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nThen you would set the `entrypoint` as:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nwhich would be equivalent to:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` with path { #fastapi-dev-with-path }\n\nYou can also pass the file path to the `fastapi dev` command, and it will guess the FastAPI app object to use:\n\n```console\n$ fastapi dev main.py\n```\n\nBut you would have to remember to pass the correct path every time you call the `fastapi` command.\n\nAdditionally, other tools might not be able to find it, for example the [VS Code Extension](../editor-support.md) or [FastAPI Cloud](https://fastapicloud.com), so it is recommended to use the `entrypoint` in `pyproject.toml`.\n\n### Deploy your app (optional) { #deploy-your-app-optional }\n\nYou can optionally deploy your FastAPI app to [FastAPI Cloud](https://fastapicloud.com), go and join the waiting list if you haven't. 🚀\n\nIf you already have a **FastAPI Cloud** account (we invited you from the waiting list 😉), you can deploy your application with one command.\n\nBefore deploying, make sure you are logged in:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\nThen deploy your app:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nThat's it! Now you can access your app at that URL. ✨\n\n## Recap, step by step { #recap-step-by-step }\n\n### Step 1: import `FastAPI` { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI` is a Python class that provides all the functionality for your API.\n\n/// note | Technical Details\n\n`FastAPI` is a class that inherits directly from `Starlette`.\n\nYou can use all the [Starlette](https://www.starlette.dev/) functionality with `FastAPI` too.\n\n///\n\n### Step 2: create a `FastAPI` \"instance\" { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\nHere the `app` variable will be an \"instance\" of the class `FastAPI`.\n\nThis will be the main point of interaction to create all your API.\n\n### Step 3: create a *path operation* { #step-3-create-a-path-operation }\n\n#### Path { #path }\n\n\"Path\" here refers to the last part of the URL starting from the first `/`.\n\nSo, in a URL like:\n\n```\nhttps://example.com/items/foo\n```\n\n...the path would be:\n\n```\n/items/foo\n```\n\n/// info\n\nA \"path\" is also commonly called an \"endpoint\" or a \"route\".\n\n///\n\nWhile building an API, the \"path\" is the main way to separate \"concerns\" and \"resources\".\n\n#### Operation { #operation }\n\n\"Operation\" here refers to one of the HTTP \"methods\".\n\nOne of:\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n...and the more exotic ones:\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\nIn the HTTP protocol, you can communicate to each path using one (or more) of these \"methods\".\n\n---\n\nWhen building APIs, you normally use these specific HTTP methods to perform a specific action.\n\nNormally you use:\n\n* `POST`: to create data.\n* `GET`: to read data.\n* `PUT`: to update data.\n* `DELETE`: to delete data.\n\nSo, in OpenAPI, each of the HTTP methods is called an \"operation\".\n\nWe are going to call them \"**operations**\" too.\n\n#### Define a *path operation decorator* { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\nThe `@app.get(\"/\")` tells **FastAPI** that the function right below is in charge of handling requests that go to:\n\n* the path `/`\n* using a <dfn title=\"an HTTP GET method\"><code>get</code> operation</dfn>\n\n/// info | `@decorator` Info\n\nThat `@something` syntax in Python is called a \"decorator\".\n\nYou put it on top of a function. Like a pretty decorative hat (I guess that's where the term came from).\n\nA \"decorator\" takes the function below and does something with it.\n\nIn our case, this decorator tells **FastAPI** that the function below corresponds to the **path** `/` with an **operation** `get`.\n\nIt is the \"**path operation decorator**\".\n\n///\n\nYou can also use the other operations:\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\nAnd the more exotic ones:\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip\n\nYou are free to use each operation (HTTP method) as you wish.\n\n**FastAPI** doesn't enforce any specific meaning.\n\nThe information here is presented as a guideline, not a requirement.\n\nFor example, when using GraphQL you normally perform all the actions using only `POST` operations.\n\n///\n\n### Step 4: define the **path operation function** { #step-4-define-the-path-operation-function }\n\nThis is our \"**path operation function**\":\n\n* **path**: is `/`.\n* **operation**: is `get`.\n* **function**: is the function below the \"decorator\" (below `@app.get(\"/\")`).\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\nThis is a Python function.\n\nIt will be called by **FastAPI** whenever it receives a request to the URL \"`/`\" using a `GET` operation.\n\nIn this case, it is an `async` function.\n\n---\n\nYou could also define it as a normal function instead of `async def`:\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note\n\nIf you don't know the difference, check the [Async: *\"In a hurry?\"*](../async.md#in-a-hurry).\n\n///\n\n### Step 5: return the content { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\nYou can return a `dict`, `list`, singular values as `str`, `int`, etc.\n\nYou can also return Pydantic models (you'll see more about that later).\n\nThere are many other objects and models that will be automatically converted to JSON (including ORMs, etc). Try using your favorite ones, it's highly probable that they are already supported.\n\n### Step 6: Deploy it { #step-6-deploy-it }\n\nDeploy your app to **[FastAPI Cloud](https://fastapicloud.com)** with one command: `fastapi deploy`. 🎉\n\n#### About FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** is built by the same author and team behind **FastAPI**.\n\nIt streamlines the process of **building**, **deploying**, and **accessing** an API with minimal effort.\n\nIt brings the same **developer experience** of building apps with FastAPI to **deploying** them to the cloud. 🎉\n\nFastAPI Cloud is the primary sponsor and funding provider for the *FastAPI and friends* open source projects. ✨\n\n#### Deploy to other cloud providers { #deploy-to-other-cloud-providers }\n\nFastAPI is open source and based on standards. You can deploy FastAPI apps to any cloud provider you choose.\n\nFollow your cloud provider's guides to deploy FastAPI apps with them. 🤓\n\n## Recap { #recap }\n\n* Import `FastAPI`.\n* Create an `app` instance.\n* Write a **path operation decorator** using decorators like `@app.get(\"/\")`.\n* Define a **path operation function**; for example, `def root(): ...`.\n* Run the development server using the command `fastapi dev`.\n* Optionally deploy your app with `fastapi deploy`.\n"
  },
  {
    "path": "docs/en/docs/tutorial/handling-errors.md",
    "content": "# Handling Errors { #handling-errors }\n\nThere are many situations in which you need to notify an error to a client that is using your API.\n\nThis client could be a browser with a frontend, a code from someone else, an IoT device, etc.\n\nYou could need to tell the client that:\n\n* The client doesn't have enough privileges for that operation.\n* The client doesn't have access to that resource.\n* The item the client was trying to access doesn't exist.\n* etc.\n\nIn these cases, you would normally return an **HTTP status code** in the range of **400** (from 400 to 499).\n\nThis is similar to the 200 HTTP status codes (from 200 to 299). Those \"200\" status codes mean that somehow there was a \"success\" in the request.\n\nThe status codes in the 400 range mean that there was an error from the client.\n\nRemember all those **\"404 Not Found\"** errors (and jokes)?\n\n## Use `HTTPException` { #use-httpexception }\n\nTo return HTTP responses with errors to the client you use `HTTPException`.\n\n### Import `HTTPException` { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### Raise an `HTTPException` in your code { #raise-an-httpexception-in-your-code }\n\n`HTTPException` is a normal Python exception with additional data relevant for APIs.\n\nBecause it's a Python exception, you don't `return` it, you `raise` it.\n\nThis also means that if you are inside a utility function that you are calling inside of your *path operation function*, and you raise the `HTTPException` from inside of that utility function, it won't run the rest of the code in the *path operation function*, it will terminate that request right away and send the HTTP error from the `HTTPException` to the client.\n\nThe benefit of raising an exception over returning a value will be more evident in the section about Dependencies and Security.\n\nIn this example, when the client requests an item by an ID that doesn't exist, raise an exception with a status code of `404`:\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### The resulting response { #the-resulting-response }\n\nIf the client requests `http://example.com/items/foo` (an `item_id` `\"foo\"`), that client will receive an HTTP status code of 200, and a JSON response of:\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\nBut if the client requests `http://example.com/items/bar` (a non-existent `item_id` `\"bar\"`), that client will receive an HTTP status code of 404 (the \"not found\" error), and a JSON response of:\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip\n\nWhen raising an `HTTPException`, you can pass any value that can be converted to JSON as the parameter `detail`, not only `str`.\n\nYou could pass a `dict`, a `list`, etc.\n\nThey are handled automatically by **FastAPI** and converted to JSON.\n\n///\n\n## Add custom headers { #add-custom-headers }\n\nThere are some situations in where it's useful to be able to add custom headers to the HTTP error. For example, for some types of security.\n\nYou probably won't need to use it directly in your code.\n\nBut in case you needed it for an advanced scenario, you can add custom headers:\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## Install custom exception handlers { #install-custom-exception-handlers }\n\nYou can add custom exception handlers with [the same exception utilities from Starlette](https://www.starlette.dev/exceptions/).\n\nLet's say you have a custom exception `UnicornException` that you (or a library you use) might `raise`.\n\nAnd you want to handle this exception globally with FastAPI.\n\nYou could add a custom exception handler with `@app.exception_handler()`:\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\nHere, if you request `/unicorns/yolo`, the *path operation* will `raise` a `UnicornException`.\n\nBut it will be handled by the `unicorn_exception_handler`.\n\nSo, you will receive a clean error, with an HTTP status code of `418` and a JSON content of:\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | Technical Details\n\nYou could also use `from starlette.requests import Request` and `from starlette.responses import JSONResponse`.\n\n**FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette. The same with `Request`.\n\n///\n\n## Override the default exception handlers { #override-the-default-exception-handlers }\n\n**FastAPI** has some default exception handlers.\n\nThese handlers are in charge of returning the default JSON responses when you `raise` an `HTTPException` and when the request has invalid data.\n\nYou can override these exception handlers with your own.\n\n### Override request validation exceptions { #override-request-validation-exceptions }\n\nWhen a request contains invalid data, **FastAPI** internally raises a `RequestValidationError`.\n\nAnd it also includes a default exception handler for it.\n\nTo override it, import the `RequestValidationError` and use it with `@app.exception_handler(RequestValidationError)` to decorate the exception handler.\n\nThe exception handler will receive a `Request` and the exception.\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\nNow, if you go to `/items/foo`, instead of getting the default JSON error with:\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\nyou will get a text version, with:\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### Override the `HTTPException` error handler { #override-the-httpexception-error-handler }\n\nThe same way, you can override the `HTTPException` handler.\n\nFor example, you could want to return a plain text response instead of JSON for these errors:\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | Technical Details\n\nYou could also use `from starlette.responses import PlainTextResponse`.\n\n**FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.\n\n///\n\n/// warning\n\nHave in mind that the `RequestValidationError` contains the information of the file name and line where the validation error happens so that you can show it in your logs with the relevant information if you want to.\n\nBut that means that if you just convert it to a string and return that information directly, you could be leaking a bit of information about your system, that's why here the code extracts and shows each error independently.\n\n///\n\n### Use the `RequestValidationError` body { #use-the-requestvalidationerror-body }\n\nThe `RequestValidationError` contains the `body` it received with invalid data.\n\nYou could use it while developing your app to log the body and debug it, return it to the user, etc.\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\nNow try sending an invalid item like:\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\nYou will receive a response telling you that the data is invalid containing the received body:\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### FastAPI's `HTTPException` vs Starlette's `HTTPException` { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI** has its own `HTTPException`.\n\nAnd **FastAPI**'s `HTTPException` error class inherits from Starlette's `HTTPException` error class.\n\nThe only difference is that **FastAPI**'s `HTTPException` accepts any JSON-able data for the `detail` field, while Starlette's `HTTPException` only accepts strings for it.\n\nSo, you can keep raising **FastAPI**'s `HTTPException` as normally in your code.\n\nBut when you register an exception handler, you should register it for Starlette's `HTTPException`.\n\nThis way, if any part of Starlette's internal code, or a Starlette extension or plug-in, raises a Starlette `HTTPException`, your handler will be able to catch and handle it.\n\nIn this example, to be able to have both `HTTPException`s in the same code, Starlette's exceptions is renamed to `StarletteHTTPException`:\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### Reuse **FastAPI**'s exception handlers { #reuse-fastapis-exception-handlers }\n\nIf you want to use the exception along with the same default exception handlers from  **FastAPI**, you can import and reuse the default exception handlers from `fastapi.exception_handlers`:\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\nIn this example you are just printing the error with a very expressive message, but you get the idea. You can use the exception and then just reuse the default exception handlers.\n"
  },
  {
    "path": "docs/en/docs/tutorial/header-param-models.md",
    "content": "# Header Parameter Models { #header-parameter-models }\n\nIf you have a group of related **header parameters**, you can create a **Pydantic model** to declare them.\n\nThis would allow you to **re-use the model** in **multiple places** and also to declare validations and metadata for all the parameters at once. 😎\n\n/// note\n\nThis is supported since FastAPI version `0.115.0`. 🤓\n\n///\n\n## Header Parameters with a Pydantic Model { #header-parameters-with-a-pydantic-model }\n\nDeclare the **header parameters** that you need in a **Pydantic model**, and then declare the parameter as `Header`:\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\n**FastAPI** will **extract** the data for **each field** from the **headers** in the request and give you the Pydantic model you defined.\n\n## Check the Docs { #check-the-docs }\n\nYou can see the required headers in the docs UI at `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## Forbid Extra Headers { #forbid-extra-headers }\n\nIn some special use cases (probably not very common), you might want to **restrict** the headers that you want to receive.\n\nYou can use Pydantic's model configuration to `forbid` any `extra` fields:\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\nIf a client tries to send some **extra headers**, they will receive an **error** response.\n\nFor example, if the client tries to send a `tool` header with a value of `plumbus`, they will receive an **error** response telling them that the header parameter `tool` is not allowed:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## Disable Convert Underscores { #disable-convert-underscores }\n\nThe same way as with regular header parameters, when you have underscore characters in the parameter names, they are **automatically converted to hyphens**.\n\nFor example, if you have a header parameter `save_data` in the code, the expected HTTP header will be `save-data`, and it will show up like that in the docs.\n\nIf for some reason you need to disable this automatic conversion, you can do it as well for Pydantic models for header parameters.\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning\n\nBefore setting `convert_underscores` to `False`, bear in mind that some HTTP proxies and servers disallow the usage of headers with underscores.\n\n///\n\n## Summary { #summary }\n\nYou can use **Pydantic models** to declare **headers** in **FastAPI**. 😎\n"
  },
  {
    "path": "docs/en/docs/tutorial/header-params.md",
    "content": "# Header Parameters { #header-parameters }\n\nYou can define Header parameters the same way you define `Query`, `Path` and `Cookie` parameters.\n\n## Import `Header` { #import-header }\n\nFirst import `Header`:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## Declare `Header` parameters { #declare-header-parameters }\n\nThen declare the header parameters using the same structure as with `Path`, `Query` and `Cookie`.\n\nYou can define the default value as well as all the extra validation or annotation parameters:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Technical Details\n\n`Header` is a \"sister\" class of `Path`, `Query` and `Cookie`. It also inherits from the same common `Param` class.\n\nBut remember that when you import `Query`, `Path`, `Header`, and others from `fastapi`, those are actually functions that return special classes.\n\n///\n\n/// info\n\nTo declare headers, you need to use `Header`, because otherwise the parameters would be interpreted as query parameters.\n\n///\n\n## Automatic conversion { #automatic-conversion }\n\n`Header` has a little extra functionality on top of what `Path`, `Query` and `Cookie` provide.\n\nMost of the standard headers are separated by a \"hyphen\" character, also known as the \"minus symbol\" (`-`).\n\nBut a variable like `user-agent` is invalid in Python.\n\nSo, by default, `Header` will convert the parameter names characters from underscore (`_`) to hyphen (`-`) to extract and document the headers.\n\nAlso, HTTP headers are case-insensitive, so, you can declare them with standard Python style (also known as \"snake_case\").\n\nSo, you can use `user_agent` as you normally would in Python code, instead of needing to capitalize the first letters as `User_Agent` or something similar.\n\nIf for some reason you need to disable automatic conversion of underscores to hyphens, set the parameter `convert_underscores` of `Header` to `False`:\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning\n\nBefore setting `convert_underscores` to `False`, bear in mind that some HTTP proxies and servers disallow the usage of headers with underscores.\n\n///\n\n## Duplicate headers { #duplicate-headers }\n\nIt is possible to receive duplicate headers. That means, the same header with multiple values.\n\nYou can define those cases using a list in the type declaration.\n\nYou will receive all the values from the duplicate header as a Python `list`.\n\nFor example, to declare a header of `X-Token` that can appear more than once, you can write:\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\nIf you communicate with that *path operation* sending two HTTP headers like:\n\n```\nX-Token: foo\nX-Token: bar\n```\n\nThe response would be like:\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## Recap { #recap }\n\nDeclare headers with `Header`, using the same common pattern as `Query`, `Path` and `Cookie`.\n\nAnd don't worry about underscores in your variables, **FastAPI** will take care of converting them.\n"
  },
  {
    "path": "docs/en/docs/tutorial/index.md",
    "content": "# Tutorial - User Guide { #tutorial-user-guide }\n\nThis tutorial shows you how to use **FastAPI** with most of its features, step by step.\n\nEach section gradually builds on the previous ones, but it's structured to separate topics, so that you can go directly to any specific one to solve your specific API needs.\n\nIt is also built to work as a future reference so you can come back and see exactly what you need.\n\n## Run the code { #run-the-code }\n\nAll the code blocks can be copied and used directly (they are actually tested Python files).\n\nTo run any of the examples, copy the code to a file `main.py`, and start `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nIt is **HIGHLY encouraged** that you write or copy the code, edit it and run it locally.\n\nUsing it in your editor is what really shows you the benefits of FastAPI, seeing how little code you have to write, all the type checks, autocompletion, etc.\n\n---\n\n## Install FastAPI { #install-fastapi }\n\nThe first step is to install FastAPI.\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and then **install FastAPI**:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note\n\nWhen you install with `pip install \"fastapi[standard]\"` it comes with some default optional standard dependencies, including `fastapi-cloud-cli`, which allows you to deploy to [FastAPI Cloud](https://fastapicloud.com).\n\nIf you don't want to have those optional dependencies, you can instead install `pip install fastapi`.\n\nIf you want to install the standard dependencies but without the `fastapi-cloud-cli`, you can install with `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n///\n\n/// tip\n\nFastAPI has an [official extension for VS Code](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (and Cursor), which provides a lot of features, including a path operation explorer, path operation search, CodeLens navigation in tests (jump to definition from tests), and FastAPI Cloud deployment and logs, all from your editor.\n\n///\n\n## Advanced User Guide { #advanced-user-guide }\n\nThere is also an **Advanced User Guide** that you can read later after this **Tutorial - User guide**.\n\nThe **Advanced User Guide** builds on this one, uses the same concepts, and teaches you some extra features.\n\nBut you should first read the **Tutorial - User Guide** (what you are reading right now).\n\nIt's designed so that you can build a complete application with just the **Tutorial - User Guide**, and then extend it in different ways, depending on your needs, using some of the additional ideas from the **Advanced User Guide**.\n"
  },
  {
    "path": "docs/en/docs/tutorial/metadata.md",
    "content": "# Metadata and Docs URLs { #metadata-and-docs-urls }\n\nYou can customize several metadata configurations in your **FastAPI** application.\n\n## Metadata for API { #metadata-for-api }\n\nYou can set the following fields that are used in the OpenAPI specification and the automatic API docs UIs:\n\n| Parameter | Type | Description |\n|------------|------|-------------|\n| `title` | `str` | The title of the API. |\n| `summary` | `str` | A short summary of the API. <small>Available since OpenAPI 3.1.0, FastAPI 0.99.0.</small> |\n| `description` | `str` | A short description of the API. It can use Markdown. |\n| `version` | `string` | The version of the API. This is the version of your own application, not of OpenAPI. For example `2.5.0`. |\n| `terms_of_service` | `str` | A URL to the Terms of Service for the API. If provided, this has to be a URL. |\n| `contact` | `dict` | The contact information for the exposed API. It can contain several fields. <details><summary><code>contact</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>The identifying name of the contact person/organization.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>The URL pointing to the contact information. MUST be in the format of a URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>The email address of the contact person/organization. MUST be in the format of an email address.</td></tr></tbody></table></details> |\n| `license_info` | `dict` | The license information for the exposed API. It can contain several fields. <details><summary><code>license_info</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>REQUIRED</strong> (if a <code>license_info</code> is set). The license name used for the API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>An [SPDX](https://spdx.org/licenses/) license expression for the API. The <code>identifier</code> field is mutually exclusive of the <code>url</code> field. <small>Available since OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>A URL to the license used for the API. MUST be in the format of a URL.</td></tr></tbody></table></details> |\n\nYou can set them as follows:\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip\n\nYou can write Markdown in the `description` field and it will be rendered in the output.\n\n///\n\nWith this configuration, the automatic API docs would look like:\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## License identifier { #license-identifier }\n\nSince OpenAPI 3.1.0 and FastAPI 0.99.0, you can also set the `license_info` with an `identifier` instead of a `url`.\n\nFor example:\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## Metadata for tags { #metadata-for-tags }\n\nYou can also add additional metadata for the different tags used to group your path operations with the parameter `openapi_tags`.\n\nIt takes a list containing one dictionary for each tag.\n\nEach dictionary can contain:\n\n* `name` (**required**): a `str` with the same tag name you use in the `tags` parameter in your *path operations* and `APIRouter`s.\n* `description`: a `str` with a short description for the tag. It can have Markdown and will be shown in the docs UI.\n* `externalDocs`: a `dict` describing external documentation with:\n    * `description`: a `str` with a short description for the external docs.\n    * `url` (**required**): a `str` with the URL for the external documentation.\n\n### Create metadata for tags { #create-metadata-for-tags }\n\nLet's try that in an example with tags for `users` and `items`.\n\nCreate metadata for your tags and pass it to the `openapi_tags` parameter:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\nNotice that you can use Markdown inside of the descriptions, for example \"login\" will be shown in bold (**login**) and \"fancy\" will be shown in italics (_fancy_).\n\n/// tip\n\nYou don't have to add metadata for all the tags that you use.\n\n///\n\n### Use your tags { #use-your-tags }\n\nUse the `tags` parameter with your *path operations* (and `APIRouter`s) to assign them to different tags:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info\n\nRead more about tags in [Path Operation Configuration](path-operation-configuration.md#tags).\n\n///\n\n### Check the docs { #check-the-docs }\n\nNow, if you check the docs, they will show all the additional metadata:\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### Order of tags { #order-of-tags }\n\nThe order of each tag metadata dictionary also defines the order shown in the docs UI.\n\nFor example, even though `users` would go after `items` in alphabetical order, it is shown before them, because we added their metadata as the first dictionary in the list.\n\n## OpenAPI URL { #openapi-url }\n\nBy default, the OpenAPI schema is served at `/openapi.json`.\n\nBut you can configure it with the parameter `openapi_url`.\n\nFor example, to set it to be served at `/api/v1/openapi.json`:\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\nIf you want to disable the OpenAPI schema completely you can set `openapi_url=None`, that will also disable the documentation user interfaces that use it.\n\n## Docs URLs { #docs-urls }\n\nYou can configure the two documentation user interfaces included:\n\n* **Swagger UI**: served at `/docs`.\n    * You can set its URL with the parameter `docs_url`.\n    * You can disable it by setting `docs_url=None`.\n* **ReDoc**: served at `/redoc`.\n    * You can set its URL with the parameter `redoc_url`.\n    * You can disable it by setting `redoc_url=None`.\n\nFor example, to set Swagger UI to be served at `/documentation` and disable ReDoc:\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/en/docs/tutorial/middleware.md",
    "content": "# Middleware { #middleware }\n\nYou can add middleware to **FastAPI** applications.\n\nA \"middleware\" is a function that works with every **request** before it is processed by any specific *path operation*. And also with every **response** before returning it.\n\n* It takes each **request** that comes to your application.\n* It can then do something to that **request** or run any needed code.\n* Then it passes the **request** to be processed by the rest of the application (by some *path operation*).\n* It then takes the **response** generated by the application (by some *path operation*).\n* It can do something to that **response** or run any needed code.\n* Then it returns the **response**.\n\n/// note | Technical Details\n\nIf you have dependencies with `yield`, the exit code will run *after* the middleware.\n\nIf there were any background tasks (covered in the [Background Tasks](background-tasks.md) section, you will see it later), they will run *after* all the middleware.\n\n///\n\n## Create a middleware { #create-a-middleware }\n\nTo create a middleware you use the decorator `@app.middleware(\"http\")` on top of a function.\n\nThe middleware function receives:\n\n* The `request`.\n* A function `call_next` that will receive the `request` as a parameter.\n    * This function will pass the `request` to the corresponding *path operation*.\n    * Then it returns the `response` generated by the corresponding *path operation*.\n* You can then further modify the `response` before returning it.\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip\n\nKeep in mind that custom proprietary headers can be added [using the `X-` prefix](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nBut if you have custom headers that you want a client in a browser to be able to see, you need to add them to your CORS configurations ([CORS (Cross-Origin Resource Sharing)](cors.md)) using the parameter `expose_headers` documented in [Starlette's CORS docs](https://www.starlette.dev/middleware/#corsmiddleware).\n\n///\n\n/// note | Technical Details\n\nYou could also use `from starlette.requests import Request`.\n\n**FastAPI** provides it as a convenience for you, the developer. But it comes directly from Starlette.\n\n///\n\n### Before and after the `response` { #before-and-after-the-response }\n\nYou can add code to be run with the `request`,  before any *path operation* receives it.\n\nAnd also after the `response` is generated, before returning it.\n\nFor example, you could add a custom header `X-Process-Time` containing the time in seconds that it took to process the request and generate a response:\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip\n\nHere we use [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) instead of `time.time()` because it can be more precise for these use cases. 🤓\n\n///\n\n## Multiple middleware execution order { #multiple-middleware-execution-order }\n\nWhen you add multiple middlewares using either `@app.middleware()` decorator or `app.add_middleware()` method, each new middleware wraps the application, forming a stack. The last middleware added is the *outermost*, and the first is the *innermost*.\n\nOn the request path, the *outermost* middleware runs first.\n\nOn the response path, it runs last.\n\nFor example:\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\nThis results in the following execution order:\n\n* **Request**: MiddlewareB → MiddlewareA → route\n\n* **Response**: route → MiddlewareA → MiddlewareB\n\nThis stacking behavior ensures that middlewares are executed in a predictable and controllable order.\n\n## Other middlewares { #other-middlewares }\n\nYou can later read more about other middlewares in the [Advanced User Guide: Advanced Middleware](../advanced/middleware.md).\n\nYou will read about how to handle <abbr title=\"Cross-Origin Resource Sharing\">CORS</abbr> with a middleware in the next section.\n"
  },
  {
    "path": "docs/en/docs/tutorial/path-operation-configuration.md",
    "content": "# Path Operation Configuration { #path-operation-configuration }\n\nThere are several parameters that you can pass to your *path operation decorator* to configure it.\n\n/// warning\n\nNotice that these parameters are passed directly to the *path operation decorator*, not to your *path operation function*.\n\n///\n\n## Response Status Code { #response-status-code }\n\nYou can define the (HTTP) `status_code` to be used in the response of your *path operation*.\n\nYou can pass directly the `int` code, like `404`.\n\nBut if you don't remember what each number code is for, you can use the shortcut constants in `status`:\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\nThat status code will be used in the response and will be added to the OpenAPI schema.\n\n/// note | Technical Details\n\nYou could also use `from starlette import status`.\n\n**FastAPI** provides the same `starlette.status` as `fastapi.status` just as a convenience for you, the developer. But it comes directly from Starlette.\n\n///\n\n## Tags { #tags }\n\nYou can add tags to your *path operation*, pass the parameter `tags` with a `list` of `str` (commonly just one `str`):\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\nThey will be added to the OpenAPI schema and used by the automatic documentation interfaces:\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### Tags with Enums { #tags-with-enums }\n\nIf you have a big application, you might end up accumulating **several tags**, and you would want to make sure you always use the **same tag** for related *path operations*.\n\nIn these cases, it could make sense to store the tags in an `Enum`.\n\n**FastAPI** supports that the same way as with plain strings:\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## Summary and description { #summary-and-description }\n\nYou can add a `summary` and `description`:\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## Description from docstring { #description-from-docstring }\n\nAs descriptions tend to be long and cover multiple lines, you can declare the *path operation* description in the function <dfn title=\"a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation\">docstring</dfn> and **FastAPI** will read it from there.\n\nYou can write [Markdown](https://en.wikipedia.org/wiki/Markdown) in the docstring, it will be interpreted and displayed correctly (taking into account docstring indentation).\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\nIt will be used in the interactive docs:\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## Response description { #response-description }\n\nYou can specify the response description with the parameter `response_description`:\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info\n\nNotice that `response_description` refers specifically to the response, the `description` refers to the *path operation* in general.\n\n///\n\n/// check\n\nOpenAPI specifies that each *path operation* requires a response description.\n\nSo, if you don't provide one, **FastAPI** will automatically generate one of \"Successful response\".\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## Deprecate a *path operation* { #deprecate-a-path-operation }\n\nIf you need to mark a *path operation* as <dfn title=\"obsolete, recommended not to use it\">deprecated</dfn>, but without removing it, pass the parameter `deprecated`:\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\nIt will be clearly marked as deprecated in the interactive docs:\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\nCheck how deprecated and non-deprecated *path operations* look like:\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## Recap { #recap }\n\nYou can configure and add metadata for your *path operations* easily by passing parameters to the *path operation decorators*.\n"
  },
  {
    "path": "docs/en/docs/tutorial/path-params-numeric-validations.md",
    "content": "# Path Parameters and Numeric Validations { #path-parameters-and-numeric-validations }\n\nIn the same way that you can declare more validations and metadata for query parameters with `Query`, you can declare the same type of validations and metadata for path parameters with `Path`.\n\n## Import `Path` { #import-path }\n\nFirst, import `Path` from `fastapi`, and import `Annotated`:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info\n\nFastAPI added support for `Annotated` (and started recommending it) in version 0.95.0.\n\nIf you have an older version, you would get errors when trying to use `Annotated`.\n\nMake sure you [Upgrade the FastAPI version](../deployment/versions.md#upgrading-the-fastapi-versions) to at least 0.95.1 before using `Annotated`.\n\n///\n\n## Declare metadata { #declare-metadata }\n\nYou can declare all the same parameters as for `Query`.\n\nFor example, to declare a `title` metadata value for the path parameter `item_id` you can type:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note\n\nA path parameter is always required as it has to be part of the path. Even if you declared it with `None` or set a default value, it would not affect anything, it would still be always required.\n\n///\n\n## Order the parameters as you need { #order-the-parameters-as-you-need }\n\n/// tip\n\nThis is probably not as important or necessary if you use `Annotated`.\n\n///\n\nLet's say that you want to declare the query parameter `q` as a required `str`.\n\nAnd you don't need to declare anything else for that parameter, so you don't really need to use `Query`.\n\nBut you still need to use `Path` for the `item_id` path parameter. And you don't want to use `Annotated` for some reason.\n\nPython will complain if you put a value with a \"default\" before a value that doesn't have a \"default\".\n\nBut you can re-order them, and have the value without a default (the query parameter `q`) first.\n\nIt doesn't matter for **FastAPI**. It will detect the parameters by their names, types and default declarations (`Query`, `Path`, etc), it doesn't care about the order.\n\nSo, you can declare your function as:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\nBut keep in mind that if you use `Annotated`, you won't have this problem, it won't matter as you're not using the function parameter default values for `Query()` or `Path()`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## Order the parameters as you need, tricks { #order-the-parameters-as-you-need-tricks }\n\n/// tip\n\nThis is probably not as important or necessary if you use `Annotated`.\n\n///\n\nHere's a **small trick** that can be handy, but you won't need it often.\n\nIf you want to:\n\n* declare the `q` query parameter without a `Query` nor any default value\n* declare the path parameter `item_id` using `Path`\n* have them in a different order\n* not use `Annotated`\n\n...Python has a little special syntax for that.\n\nPass `*`, as the first parameter of the function.\n\nPython won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as <abbr title=\"From: K-ey W-ord Arg-uments\"><code>kwargs</code></abbr>. Even if they don't have a default value.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### Better with `Annotated` { #better-with-annotated }\n\nKeep in mind that if you use `Annotated`, as you are not using function parameter default values, you won't have this problem, and you probably won't need to use `*`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## Number validations: greater than or equal { #number-validations-greater-than-or-equal }\n\nWith `Query` and `Path` (and others you'll see later) you can declare number constraints.\n\nHere, with `ge=1`, `item_id` will need to be an integer number \"`g`reater than or `e`qual\" to `1`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## Number validations: greater than and less than or equal { #number-validations-greater-than-and-less-than-or-equal }\n\nThe same applies for:\n\n* `gt`: `g`reater `t`han\n* `le`: `l`ess than or `e`qual\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## Number validations: floats, greater than and less than { #number-validations-floats-greater-than-and-less-than }\n\nNumber validations also work for `float` values.\n\nHere's where it becomes important to be able to declare <abbr title=\"greater than\"><code>gt</code></abbr> and not just <abbr title=\"greater than or equal\"><code>ge</code></abbr>. As with it you can require, for example, that a value must be greater than `0`, even if it is less than `1`.\n\nSo, `0.5` would be a valid value. But `0.0` or `0` would not.\n\nAnd the same for <abbr title=\"less than\"><code>lt</code></abbr>.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## Recap { #recap }\n\nWith `Query`, `Path` (and others you haven't seen yet) you can declare metadata and string validations in the same ways as with [Query Parameters and String Validations](query-params-str-validations.md).\n\nAnd you can also declare numeric validations:\n\n* `gt`: `g`reater `t`han\n* `ge`: `g`reater than or `e`qual\n* `lt`: `l`ess `t`han\n* `le`: `l`ess than or `e`qual\n\n/// info\n\n`Query`, `Path`, and other classes you will see later are subclasses of a common `Param` class.\n\nAll of them share the same parameters for additional validation and metadata you have seen.\n\n///\n\n/// note | Technical Details\n\nWhen you import `Query`, `Path` and others from `fastapi`, they are actually functions.\n\nThat when called, return instances of classes of the same name.\n\nSo, you import `Query`, which is a function. And when you call it, it returns an instance of a class also named `Query`.\n\nThese functions are there (instead of just using the classes directly) so that your editor doesn't mark errors about their types.\n\nThat way you can use your normal editor and coding tools without having to add custom configurations to disregard those errors.\n\n///\n"
  },
  {
    "path": "docs/en/docs/tutorial/path-params.md",
    "content": "# Path Parameters { #path-parameters }\n\nYou can declare path \"parameters\" or \"variables\" with the same syntax used by Python format strings:\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\nThe value of the path parameter `item_id` will be passed to your function as the argument `item_id`.\n\nSo, if you run this example and go to [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), you will see a response of:\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## Path parameters with types { #path-parameters-with-types }\n\nYou can declare the type of a path parameter in the function, using standard Python type annotations:\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\nIn this case, `item_id` is declared to be an `int`.\n\n/// check\n\nThis will give you editor support inside of your function, with error checks, completion, etc.\n\n///\n\n## Data <dfn title=\"also known as: serialization, parsing, marshalling\">conversion</dfn> { #data-conversion }\n\nIf you run this example and open your browser at [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3), you will see a response of:\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check\n\nNotice that the value your function received (and returned) is `3`, as a Python `int`, not a string `\"3\"`.\n\nSo, with that type declaration, **FastAPI** gives you automatic request <dfn title=\"converting the string that comes from an HTTP request into Python data\">\"parsing\"</dfn>.\n\n///\n\n## Data validation { #data-validation }\n\nBut if you go to the browser at [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), you will see a nice HTTP error of:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\nbecause the path parameter `item_id` had a value of `\"foo\"`, which is not an `int`.\n\nThe same error would appear if you provided a `float` instead of an `int`, as in: [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)\n\n/// check\n\nSo, with the same Python type declaration, **FastAPI** gives you data validation.\n\nNotice that the error also clearly states exactly the point where the validation didn't pass.\n\nThis is incredibly helpful while developing and debugging code that interacts with your API.\n\n///\n\n## Documentation { #documentation }\n\nAnd when you open your browser at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), you will see an automatic, interactive, API documentation like:\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check\n\nAgain, just with that same Python type declaration, **FastAPI** gives you automatic, interactive documentation (integrating Swagger UI).\n\nNotice that the path parameter is declared to be an integer.\n\n///\n\n## Standards-based benefits, alternative documentation { #standards-based-benefits-alternative-documentation }\n\nAnd because the generated schema is from the [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md) standard, there are many compatible tools.\n\nBecause of this, **FastAPI** itself provides an alternative API documentation (using ReDoc), which you can access at [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc):\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\nThe same way, there are many compatible tools. Including code generation tools for many languages.\n\n## Pydantic { #pydantic }\n\nAll the data validation is performed under the hood by [Pydantic](https://docs.pydantic.dev/), so you get all the benefits from it. And you know you are in good hands.\n\nYou can use the same type declarations with `str`, `float`, `bool` and many other complex data types.\n\nSeveral of these are explored in the next chapters of the tutorial.\n\n## Order matters { #order-matters }\n\nWhen creating *path operations*, you can find situations where you have a fixed path.\n\nLike `/users/me`, let's say that it's to get data about the current user.\n\nAnd then you can also have a path `/users/{user_id}` to get data about a specific user by some user ID.\n\nBecause *path operations* are evaluated in order, you need to make sure that the path for `/users/me` is declared before the one for `/users/{user_id}`:\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\nOtherwise, the path for `/users/{user_id}` would match also for `/users/me`, \"thinking\" that it's receiving a parameter `user_id` with a value of `\"me\"`.\n\nSimilarly, you cannot redefine a path operation:\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\nThe first one will always be used since the path matches first.\n\n## Predefined values { #predefined-values }\n\nIf you have a *path operation* that receives a *path parameter*, but you want the possible valid *path parameter* values to be predefined, you can use a standard Python <abbr title=\"Enumeration\">`Enum`</abbr>.\n\n### Create an `Enum` class { #create-an-enum-class }\n\nImport `Enum` and create a sub-class that inherits from `str` and from `Enum`.\n\nBy inheriting from `str` the API docs will be able to know that the values must be of type `string` and will be able to render correctly.\n\nThen create class attributes with fixed values, which will be the available valid values:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip\n\nIf you are wondering, \"AlexNet\", \"ResNet\", and \"LeNet\" are just names of Machine Learning <dfn title=\"Technically, Deep Learning model architectures\">models</dfn>.\n\n///\n\n### Declare a *path parameter* { #declare-a-path-parameter }\n\nThen create a *path parameter* with a type annotation using the enum class you created (`ModelName`):\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### Check the docs { #check-the-docs }\n\nBecause the available values for the *path parameter* are predefined, the interactive docs can show them nicely:\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### Working with Python *enumerations* { #working-with-python-enumerations }\n\nThe value of the *path parameter* will be an *enumeration member*.\n\n#### Compare *enumeration members* { #compare-enumeration-members }\n\nYou can compare it with the *enumeration member* in your created enum `ModelName`:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### Get the *enumeration value* { #get-the-enumeration-value }\n\nYou can get the actual value (a `str` in this case) using `model_name.value`, or in general, `your_enum_member.value`:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip\n\nYou could also access the value `\"lenet\"` with `ModelName.lenet.value`.\n\n///\n\n#### Return *enumeration members* { #return-enumeration-members }\n\nYou can return *enum members* from your *path operation*, even nested in a JSON body (e.g. a `dict`).\n\nThey will be converted to their corresponding values (strings in this case) before returning them to the client:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\nIn your client you will get a JSON response like:\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## Path parameters containing paths { #path-parameters-containing-paths }\n\nLet's say you have a *path operation* with a path `/files/{file_path}`.\n\nBut you need `file_path` itself to contain a *path*, like `home/johndoe/myfile.txt`.\n\nSo, the URL for that file would be something like: `/files/home/johndoe/myfile.txt`.\n\n### OpenAPI support { #openapi-support }\n\nOpenAPI doesn't support a way to declare a *path parameter* to contain a *path* inside, as that could lead to scenarios that are difficult to test and define.\n\nNevertheless, you can still do it in **FastAPI**, using one of the internal tools from Starlette.\n\nAnd the docs would still work, although not adding any documentation telling that the parameter should contain a path.\n\n### Path convertor { #path-convertor }\n\nUsing an option directly from Starlette you can declare a *path parameter* containing a *path* using a URL like:\n\n```\n/files/{file_path:path}\n```\n\nIn this case, the name of the parameter is `file_path`, and the last part, `:path`, tells it that the parameter should match any *path*.\n\nSo, you can use it with:\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip\n\nYou might need the parameter to contain `/home/johndoe/myfile.txt`, with a leading slash (`/`).\n\nIn that case, the URL would be: `/files//home/johndoe/myfile.txt`, with a double slash (`//`) between `files` and `home`.\n\n///\n\n## Recap { #recap }\n\nWith **FastAPI**, by using short, intuitive and standard Python type declarations, you get:\n\n* Editor support: error checks, autocompletion, etc.\n* Data \"<dfn title=\"converting the string that comes from an HTTP request into Python data\">parsing</dfn>\"\n* Data validation\n* API annotation and automatic documentation\n\nAnd you only have to declare them once.\n\nThat's probably the main visible advantage of **FastAPI** compared to alternative frameworks (apart from the raw performance).\n"
  },
  {
    "path": "docs/en/docs/tutorial/query-param-models.md",
    "content": "# Query Parameter Models { #query-parameter-models }\n\nIf you have a group of **query parameters** that are related, you can create a **Pydantic model** to declare them.\n\nThis would allow you to **re-use the model** in **multiple places** and also to declare validations and metadata for all the parameters at once. 😎\n\n/// note\n\nThis is supported since FastAPI version `0.115.0`. 🤓\n\n///\n\n## Query Parameters with a Pydantic Model { #query-parameters-with-a-pydantic-model }\n\nDeclare the **query parameters** that you need in a **Pydantic model**, and then declare the parameter as `Query`:\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\n**FastAPI** will **extract** the data for **each field** from the **query parameters** in the request and give you the Pydantic model you defined.\n\n## Check the Docs { #check-the-docs }\n\nYou can see the query parameters in the docs UI at `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## Forbid Extra Query Parameters { #forbid-extra-query-parameters }\n\nIn some special use cases (probably not very common), you might want to **restrict** the query parameters that you want to receive.\n\nYou can use Pydantic's model configuration to `forbid` any `extra` fields:\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\nIf a client tries to send some **extra** data in the **query parameters**, they will receive an **error** response.\n\nFor example, if the client tries to send a `tool` query parameter with a value of `plumbus`, like:\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\nThey will receive an **error** response telling them that the query parameter `tool` is not allowed:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## Summary { #summary }\n\nYou can use **Pydantic models** to declare **query parameters** in **FastAPI**. 😎\n\n/// tip\n\nSpoiler alert: you can also use Pydantic models to declare cookies and headers, but you will read about that later in the tutorial. 🤫\n\n///\n"
  },
  {
    "path": "docs/en/docs/tutorial/query-params-str-validations.md",
    "content": "# Query Parameters and String Validations { #query-parameters-and-string-validations }\n\n**FastAPI** allows you to declare additional information and validation for your parameters.\n\nLet's take this application as example:\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\nThe query parameter `q` is of type `str | None`, that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required.\n\n/// note\n\nFastAPI will know that the value of `q` is not required because of the default value `= None`.\n\nHaving `str | None` will allow your editor to give you better support and detect errors.\n\n///\n\n## Additional validation { #additional-validation }\n\nWe are going to enforce that even though `q` is optional, whenever it is provided, **its length doesn't exceed 50 characters**.\n\n### Import `Query` and `Annotated` { #import-query-and-annotated }\n\nTo achieve that, first import:\n\n* `Query` from `fastapi`\n* `Annotated` from `typing`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info\n\nFastAPI added support for `Annotated` (and started recommending it) in version 0.95.0.\n\nIf you have an older version, you would get errors when trying to use `Annotated`.\n\nMake sure you [Upgrade the FastAPI version](../deployment/versions.md#upgrading-the-fastapi-versions) to at least 0.95.1 before using `Annotated`.\n\n///\n\n## Use `Annotated` in the type for the `q` parameter { #use-annotated-in-the-type-for-the-q-parameter }\n\nRemember I told you before that `Annotated` can be used to add metadata to your parameters in the [Python Types Intro](../python-types.md#type-hints-with-metadata-annotations)?\n\nNow it's the time to use it with FastAPI. 🚀\n\nWe had this type annotation:\n\n```Python\nq: str | None = None\n```\n\nWhat we will do is wrap that with `Annotated`, so it becomes:\n\n```Python\nq: Annotated[str | None] = None\n```\n\nBoth of those versions mean the same thing, `q` is a parameter that can be a `str` or `None`, and by default, it is `None`.\n\nNow let's jump to the fun stuff. 🎉\n\n## Add `Query` to `Annotated` in the `q` parameter { #add-query-to-annotated-in-the-q-parameter }\n\nNow that we have this `Annotated` where we can put more information (in this case some additional validation), add `Query` inside of `Annotated`, and set the parameter `max_length` to `50`:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\nNotice that the default value is still `None`, so the parameter is still optional.\n\nBut now, having `Query(max_length=50)` inside of `Annotated`, we are telling FastAPI that we want it to have **additional validation** for this value, we want it to have maximum 50 characters. 😎\n\n/// tip\n\nHere we are using `Query()` because this is a **query parameter**. Later we will see others like `Path()`, `Body()`, `Header()`, and `Cookie()`, that also accept the same arguments as `Query()`.\n\n///\n\nFastAPI will now:\n\n* **Validate** the data making sure that the max length is 50 characters\n* Show a **clear error** for the client when the data is not valid\n* **Document** the parameter in the OpenAPI schema *path operation* (so it will show up in the **automatic docs UI**)\n\n## Alternative (old): `Query` as the default value { #alternative-old-query-as-the-default-value }\n\nPrevious versions of FastAPI (before <dfn title=\"before 2023-03\">0.95.0</dfn>) required you to use `Query` as the default value of your parameter, instead of putting it in `Annotated`, there's a high chance that you will see code using it around, so I'll explain it to you.\n\n/// tip\n\nFor new code and whenever possible, use `Annotated` as explained above. There are multiple advantages (explained below) and no disadvantages. 🍰\n\n///\n\nThis is how you would use `Query()` as the default value of your function parameter, setting the parameter `max_length` to 50:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\nAs in this case (without using `Annotated`) we have to replace the default value `None` in the function with `Query()`, we now need to set the default value with the parameter `Query(default=None)`, it serves the same purpose of defining that default value (at least for FastAPI).\n\nSo:\n\n```Python\nq: str | None = Query(default=None)\n```\n\n...makes the parameter optional, with a default value of `None`, the same as:\n\n\n```Python\nq: str | None = None\n```\n\nBut the `Query` version declares it explicitly as being a query parameter.\n\nThen, we can pass more parameters to `Query`. In this case, the `max_length` parameter that applies to strings:\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\nThis will validate the data, show a clear error when the data is not valid, and document the parameter in the OpenAPI schema *path operation*.\n\n### `Query` as the default value or in `Annotated` { #query-as-the-default-value-or-in-annotated }\n\nKeep in mind that when using `Query` inside of `Annotated` you cannot use the `default` parameter for `Query`.\n\nInstead, use the actual default value of the function parameter. Otherwise, it would be inconsistent.\n\nFor example, this is not allowed:\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n...because it's not clear if the default value should be `\"rick\"` or `\"morty\"`.\n\nSo, you would use (preferably):\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n...or in older code bases you will find:\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### Advantages of `Annotated` { #advantages-of-annotated }\n\n**Using `Annotated` is recommended** instead of the default value in function parameters, it is **better** for multiple reasons. 🤓\n\nThe **default** value of the **function parameter** is the **actual default** value, that's more intuitive with Python in general. 😌\n\nYou could **call** that same function in **other places** without FastAPI, and it would **work as expected**. If there's a **required** parameter (without a default value), your **editor** will let you know with an error, **Python** will also complain if you run it without passing the required parameter.\n\nWhen you don't use `Annotated` and instead use the **(old) default value style**, if you call that function without FastAPI in **other places**, you have to **remember** to pass the arguments to the function for it to work correctly, otherwise the values will be different from what you expect (e.g. `QueryInfo` or something similar instead of `str`). And your editor won't complain, and Python won't complain running that function, only when the operations inside error out.\n\nBecause `Annotated` can have more than one metadata annotation, you could now even use the same function with other tools, like [Typer](https://typer.tiangolo.com/). 🚀\n\n## Add more validations { #add-more-validations }\n\nYou can also add a parameter `min_length`:\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## Add regular expressions { #add-regular-expressions }\n\nYou can define a <dfn title=\"A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.\">regular expression</dfn> `pattern` that the parameter should match:\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\nThis specific regular expression pattern checks that the received parameter value:\n\n* `^`: starts with the following characters, doesn't have characters before.\n* `fixedquery`: has the exact value `fixedquery`.\n* `$`: ends there, doesn't have any more characters after `fixedquery`.\n\nIf you feel lost with all these **\"regular expression\"** ideas, don't worry. They are a hard topic for many people. You can still do a lot of stuff without needing regular expressions yet.\n\nNow you know that whenever you need them you can use them in **FastAPI**.\n\n## Default values { #default-values }\n\nYou can, of course, use default values other than `None`.\n\nLet's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `\"fixedquery\"`:\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note\n\nHaving a default value of any type, including `None`, makes the parameter optional (not required).\n\n///\n\n## Required parameters { #required-parameters }\n\nWhen we don't need to declare more validations or metadata, we can make the `q` query parameter required just by not declaring a default value, like:\n\n```Python\nq: str\n```\n\ninstead of:\n\n```Python\nq: str | None = None\n```\n\nBut we are now declaring it with `Query`, for example like:\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\nSo, when you need to declare a value as required while using `Query`, you can simply not declare a default value:\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### Required, can be `None` { #required-can-be-none }\n\nYou can declare that a parameter can accept `None`, but that it's still required. This would force clients to send a value, even if the value is `None`.\n\nTo do that, you can declare that `None` is a valid type but simply do not declare a default value:\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## Query parameter list / multiple values { #query-parameter-list-multiple-values }\n\nWhen you define a query parameter explicitly with `Query` you can also declare it to receive a list of values, or said in another way, to receive multiple values.\n\nFor example, to declare a query parameter `q` that can appear multiple times in the URL, you can write:\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\nThen, with a URL like:\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\nyou would receive the multiple `q` *query parameters'* values (`foo` and `bar`) in a Python `list` inside your *path operation function*, in the *function parameter* `q`.\n\nSo, the response to that URL would be:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip\n\nTo declare a query parameter with a type of `list`, like in the example above, you need to explicitly use `Query`, otherwise it would be interpreted as a request body.\n\n///\n\nThe interactive API docs will update accordingly, to allow multiple values:\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### Query parameter list / multiple values with defaults { #query-parameter-list-multiple-values-with-defaults }\n\nYou can also define a default `list` of values if none are provided:\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\nIf you go to:\n\n```\nhttp://localhost:8000/items/\n```\n\nthe default of `q` will be: `[\"foo\", \"bar\"]` and your response will be:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### Using just `list` { #using-just-list }\n\nYou can also use `list` directly instead of `list[str]`:\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note\n\nKeep in mind that in this case, FastAPI won't check the contents of the list.\n\nFor example, `list[int]` would check (and document) that the contents of the list are integers. But `list` alone wouldn't.\n\n///\n\n## Declare more metadata { #declare-more-metadata }\n\nYou can add more information about the parameter.\n\nThat information will be included in the generated OpenAPI and used by the documentation user interfaces and external tools.\n\n/// note\n\nKeep in mind that different tools might have different levels of OpenAPI support.\n\nSome of them might not show all the extra information declared yet, although in most of the cases, the missing feature is already planned for development.\n\n///\n\nYou can add a `title`:\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\nAnd a `description`:\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## Alias parameters { #alias-parameters }\n\nImagine that you want the parameter to be `item-query`.\n\nLike in:\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\nBut `item-query` is not a valid Python variable name.\n\nThe closest would be `item_query`.\n\nBut you still need it to be exactly `item-query`...\n\nThen you can declare an `alias`, and that alias is what will be used to find the parameter value:\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## Deprecating parameters { #deprecating-parameters }\n\nNow let's say you don't like this parameter anymore.\n\nYou have to leave it there a while because there are clients using it, but you want the docs to clearly show it as <dfn title=\"obsolete, recommended not to use it\">deprecated</dfn>.\n\nThen pass the parameter `deprecated=True` to `Query`:\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\nThe docs will show it like this:\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## Exclude parameters from OpenAPI { #exclude-parameters-from-openapi }\n\nTo exclude a query parameter from the generated OpenAPI schema (and thus, from the automatic documentation systems), set the parameter `include_in_schema` of `Query` to `False`:\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## Custom Validation { #custom-validation }\n\nThere could be cases where you need to do some **custom validation** that can't be done with the parameters shown above.\n\nIn those cases, you can use a **custom validator function** that is applied after the normal validation (e.g. after validating that the value is a `str`).\n\nYou can achieve that using [Pydantic's `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) inside of `Annotated`.\n\n/// tip\n\nPydantic also has [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) and others. 🤓\n\n///\n\nFor example, this custom validator checks that the item ID starts with `isbn-` for an <abbr title=\"International Standard Book Number\">ISBN</abbr> book number or with `imdb-` for an <abbr title=\"Internet Movie Database: a website with information about movies\">IMDB</abbr> movie URL ID:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info\n\nThis is available with Pydantic version 2 or above. 😎\n\n///\n\n/// tip\n\nIf you need to do any type of validation that requires communicating with any **external component**, like a database or another API, you should instead use **FastAPI Dependencies**, you will learn about them later.\n\nThese custom validators are for things that can be checked with **only** the **same data** provided in the request.\n\n///\n\n### Understand that Code { #understand-that-code }\n\nThe important point is just using **`AfterValidator` with a function inside `Annotated`**. Feel free to skip this part. 🤸\n\n---\n\nBut if you're curious about this specific code example and you're still entertained, here are some extra details.\n\n#### String with `value.startswith()` { #string-with-value-startswith }\n\nDid you notice? a string using `value.startswith()` can take a tuple, and it will check each value in the tuple:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### A Random Item { #a-random-item }\n\nWith `data.items()` we get an <dfn title=\"Something we can iterate on with a for loop, like a list, set, etc.\">iterable object</dfn> with tuples containing the key and value for each dictionary item.\n\nWe convert this iterable object into a proper `list` with `list(data.items())`.\n\nThen with `random.choice()` we can get a **random value** from the list, so, we get a tuple with `(id, name)`. It will be something like `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")`.\n\nThen we **assign those two values** of the tuple to the variables `id` and `name`.\n\nSo, if the user didn't provide an item ID, they will still receive a random suggestion.\n\n...we do all this in a **single simple line**. 🤯 Don't you love Python? 🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## Recap { #recap }\n\nYou can declare additional validations and metadata for your parameters.\n\nGeneric validations and metadata:\n\n* `alias`\n* `title`\n* `description`\n* `deprecated`\n\nValidations specific for strings:\n\n* `min_length`\n* `max_length`\n* `pattern`\n\nCustom validations using `AfterValidator`.\n\nIn these examples you saw how to declare validations for `str` values.\n\nSee the next chapters to learn how to declare validations for other types, like numbers.\n"
  },
  {
    "path": "docs/en/docs/tutorial/query-params.md",
    "content": "# Query Parameters { #query-parameters }\n\nWhen you declare other function parameters that are not part of the path parameters, they are automatically interpreted as \"query\" parameters.\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\nThe query is the set of key-value pairs that go after the `?` in a URL, separated by `&` characters.\n\nFor example, in the URL:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n...the query parameters are:\n\n* `skip`: with a value of `0`\n* `limit`: with a value of `10`\n\nAs they are part of the URL, they are \"naturally\" strings.\n\nBut when you declare them with Python types (in the example above, as `int`), they are converted to that type and validated against it.\n\nAll the same process that applied for path parameters also applies for query parameters:\n\n* Editor support (obviously)\n* Data <dfn title=\"converting the string that comes from an HTTP request into Python data\">\"parsing\"</dfn>\n* Data validation\n* Automatic documentation\n\n## Defaults { #defaults }\n\nAs query parameters are not a fixed part of a path, they can be optional and can have default values.\n\nIn the example above they have default values of `skip=0` and `limit=10`.\n\nSo, going to the URL:\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\nwould be the same as going to:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\nBut if you go to, for example:\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\nThe parameter values in your function will be:\n\n* `skip=20`: because you set it in the URL\n* `limit=10`: because that was the default value\n\n## Optional parameters { #optional-parameters }\n\nThe same way, you can declare optional query parameters, by setting their default to `None`:\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\nIn this case, the function parameter `q` will be optional, and will be `None` by default.\n\n/// check\n\nAlso notice that **FastAPI** is smart enough to notice that the path parameter `item_id` is a path parameter and `q` is not, so, it's a query parameter.\n\n///\n\n## Query parameter type conversion { #query-parameter-type-conversion }\n\nYou can also declare `bool` types, and they will be converted:\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\nIn this case, if you go to:\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\nor\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\nor\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\nor\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\nor\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\nor any other case variation (uppercase, first letter in uppercase, etc), your function will see the parameter `short` with a `bool` value of `True`. Otherwise as `False`.\n\n\n## Multiple path and query parameters { #multiple-path-and-query-parameters }\n\nYou can declare multiple path parameters and query parameters at the same time, **FastAPI** knows which is which.\n\nAnd you don't have to declare them in any specific order.\n\nThey will be detected by name:\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## Required query parameters { #required-query-parameters }\n\nWhen you declare a default value for non-path parameters (for now, we have only seen query parameters), then it is not required.\n\nIf you don't want to add a specific value but just make it optional, set the default as `None`.\n\nBut when you want to make a query parameter required, you can just not declare any default value:\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\nHere the query parameter `needy` is a required query parameter of type `str`.\n\nIf you open in your browser a URL like:\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n...without adding the required parameter `needy`, you will see an error like:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\nAs `needy` is a required parameter, you would need to set it in the URL:\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n...this would work:\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\nAnd of course, you can define some parameters as required, some as having a default value, and some entirely optional:\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\nIn this case, there are 3 query parameters:\n\n* `needy`, a required `str`.\n* `skip`, an `int` with a default value of `0`.\n* `limit`, an optional `int`.\n\n/// tip\n\nYou could also use `Enum`s the same way as with [Path Parameters](path-params.md#predefined-values).\n\n///\n"
  },
  {
    "path": "docs/en/docs/tutorial/request-files.md",
    "content": "# Request Files { #request-files }\n\nYou can define files to be uploaded by the client using `File`.\n\n/// info\n\nTo receive uploaded files, first install [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and then install it, for example:\n\n```console\n$ pip install python-multipart\n```\n\nThis is because uploaded files are sent as \"form data\".\n\n///\n\n## Import `File` { #import-file }\n\nImport `File` and `UploadFile` from `fastapi`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## Define `File` Parameters { #define-file-parameters }\n\nCreate file parameters the same way you would for `Body` or `Form`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info\n\n`File` is a class that inherits directly from `Form`.\n\nBut remember that when you import `Query`, `Path`, `File` and others from `fastapi`, those are actually functions that return special classes.\n\n///\n\n/// tip\n\nTo declare File bodies, you need to use `File`, because otherwise the parameters would be interpreted as query parameters or body (JSON) parameters.\n\n///\n\nThe files will be uploaded as \"form data\".\n\nIf you declare the type of your *path operation function* parameter as `bytes`, **FastAPI** will read the file for you and you will receive the contents as `bytes`.\n\nKeep in mind that this means that the whole contents will be stored in memory. This will work well for small files.\n\nBut there are several cases in which you might benefit from using `UploadFile`.\n\n## File Parameters with `UploadFile` { #file-parameters-with-uploadfile }\n\nDefine a file parameter with a type of `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\nUsing `UploadFile` has several advantages over `bytes`:\n\n* You don't have to use `File()` in the default value of the parameter.\n* It uses a \"spooled\" file:\n    * A file stored in memory up to a maximum size limit, and after passing this limit it will be stored in disk.\n* This means that it will work well for large files like images, videos, large binaries, etc. without consuming all the memory.\n* You can get metadata from the uploaded file.\n* It has a [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) `async` interface.\n* It exposes an actual Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) object that you can pass directly to other libraries that expect a file-like object.\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` has the following attributes:\n\n* `filename`: A `str` with the original file name that was uploaded (e.g. `myimage.jpg`).\n* `content_type`: A `str` with the content type (MIME type / media type) (e.g. `image/jpeg`).\n* `file`: A [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (a [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) object). This is the actual Python file object that you can pass directly to other functions or libraries that expect a \"file-like\" object.\n\n`UploadFile` has the following `async` methods. They all call the corresponding file methods underneath (using the internal `SpooledTemporaryFile`).\n\n* `write(data)`: Writes `data` (`str` or `bytes`) to the file.\n* `read(size)`: Reads `size` (`int`) bytes/characters of the file.\n* `seek(offset)`: Goes to the byte position `offset` (`int`) in the file.\n    * E.g., `await myfile.seek(0)` would go to the start of the file.\n    * This is especially useful if you run `await myfile.read()` once and then need to read the contents again.\n* `close()`: Closes the file.\n\nAs all these methods are `async` methods, you need to \"await\" them.\n\nFor example, inside of an `async` *path operation function* you can get the contents with:\n\n```Python\ncontents = await myfile.read()\n```\n\nIf you are inside of a normal `def` *path operation function*, you can access the `UploadFile.file` directly, for example:\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | `async` Technical Details\n\nWhen you use the `async` methods, **FastAPI** runs the file methods in a threadpool and awaits for them.\n\n///\n\n/// note | Starlette Technical Details\n\n**FastAPI**'s `UploadFile` inherits directly from **Starlette**'s `UploadFile`, but adds some necessary parts to make it compatible with **Pydantic** and the other parts of FastAPI.\n\n///\n\n## What is \"Form Data\" { #what-is-form-data }\n\nThe way HTML forms (`<form></form>`) sends the data to the server normally uses a \"special\" encoding for that data, it's different from JSON.\n\n**FastAPI** will make sure to read that data from the right place instead of JSON.\n\n/// note | Technical Details\n\nData from forms is normally encoded using the \"media type\" `application/x-www-form-urlencoded` when it doesn't include files.\n\nBut when the form includes files, it is encoded as `multipart/form-data`. If you use `File`, **FastAPI** will know it has to get the files from the correct part of the body.\n\nIf you want to read more about these encodings and form fields, head to the [<abbr title=\"Mozilla Developer Network\">MDN</abbr> web docs for `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning\n\nYou can declare multiple `File` and `Form` parameters in a *path operation*, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.\n\nThis is not a limitation of **FastAPI**, it's part of the HTTP protocol.\n\n///\n\n## Optional File Upload { #optional-file-upload }\n\nYou can make a file optional by using standard type annotations and setting a default value of `None`:\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## `UploadFile` with Additional Metadata { #uploadfile-with-additional-metadata }\n\nYou can also use `File()` with `UploadFile`, for example, to set additional metadata:\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## Multiple File Uploads { #multiple-file-uploads }\n\nIt's possible to upload several files at the same time.\n\nThey would be associated to the same \"form field\" sent using \"form data\".\n\nTo use that, declare a list of `bytes` or `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\nYou will receive, as declared, a `list` of `bytes` or `UploadFile`s.\n\n/// note | Technical Details\n\nYou could also use `from starlette.responses import HTMLResponse`.\n\n**FastAPI** provides the same `starlette.responses` as `fastapi.responses` just as a convenience for you, the developer. But most of the available responses come directly from Starlette.\n\n///\n\n### Multiple File Uploads with Additional Metadata { #multiple-file-uploads-with-additional-metadata }\n\nAnd the same way as before, you can use `File()` to set additional parameters, even for `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## Recap { #recap }\n\nUse `File`, `bytes`, and `UploadFile` to declare files to be uploaded in the request, sent as form data.\n"
  },
  {
    "path": "docs/en/docs/tutorial/request-form-models.md",
    "content": "# Form Models { #form-models }\n\nYou can use **Pydantic models** to declare **form fields** in FastAPI.\n\n/// info\n\nTo use forms, first install [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and then install it, for example:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note\n\nThis is supported since FastAPI version `0.113.0`. 🤓\n\n///\n\n## Pydantic Models for Forms { #pydantic-models-for-forms }\n\nYou just need to declare a **Pydantic model** with the fields you want to receive as **form fields**, and then declare the parameter as `Form`:\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI** will **extract** the data for **each field** from the **form data** in the request and give you the Pydantic model you defined.\n\n## Check the Docs { #check-the-docs }\n\nYou can verify it in the docs UI at `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## Forbid Extra Form Fields { #forbid-extra-form-fields }\n\nIn some special use cases (probably not very common), you might want to **restrict** the form fields to only those declared in the Pydantic model. And **forbid** any **extra** fields.\n\n/// note\n\nThis is supported since FastAPI version `0.114.0`. 🤓\n\n///\n\nYou can use Pydantic's model configuration to `forbid` any `extra` fields:\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\nIf a client tries to send some extra data, they will receive an **error** response.\n\nFor example, if the client tries to send the form fields:\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\nThey will receive an error response telling them that the field `extra` is not allowed:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## Summary { #summary }\n\nYou can use Pydantic models to declare form fields in FastAPI. 😎\n"
  },
  {
    "path": "docs/en/docs/tutorial/request-forms-and-files.md",
    "content": "# Request Forms and Files { #request-forms-and-files }\n\nYou can define files and form fields at the same time using `File` and `Form`.\n\n/// info\n\nTo receive uploaded files and/or form data, first install [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and then install it, for example:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Import `File` and `Form` { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## Define `File` and `Form` parameters { #define-file-and-form-parameters }\n\nCreate file and form parameters the same way you would for `Body` or `Query`:\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\nThe files and form fields will be uploaded as form data and you will receive the files and form fields.\n\nAnd you can declare some of the files as `bytes` and some as `UploadFile`.\n\n/// warning\n\nYou can declare multiple `File` and `Form` parameters in a *path operation*, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `multipart/form-data` instead of `application/json`.\n\nThis is not a limitation of **FastAPI**, it's part of the HTTP protocol.\n\n///\n\n## Recap { #recap }\n\nUse `File` and `Form` together when you need to receive data and files in the same request.\n"
  },
  {
    "path": "docs/en/docs/tutorial/request-forms.md",
    "content": "# Form Data { #form-data }\n\nWhen you need to receive form fields instead of JSON, you can use `Form`.\n\n/// info\n\nTo use forms, first install [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and then install it, for example:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Import `Form` { #import-form }\n\nImport `Form` from `fastapi`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## Define `Form` parameters { #define-form-parameters }\n\nCreate form parameters the same way you would for `Body` or `Query`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\nFor example, in one of the ways the OAuth2 specification can be used (called \"password flow\") it is required to send a `username` and `password` as form fields.\n\nThe <dfn title=\"specification\">spec</dfn> requires the fields to be exactly named `username` and `password`, and to be sent as form fields, not JSON.\n\nWith `Form` you can declare the same configurations as with `Body` (and `Query`, `Path`, `Cookie`), including validation, examples, an alias (e.g. `user-name` instead of `username`), etc.\n\n/// info\n\n`Form` is a class that inherits directly from `Body`.\n\n///\n\n/// tip\n\nTo declare form bodies, you need to use `Form` explicitly, because without it the parameters would be interpreted as query parameters or body (JSON) parameters.\n\n///\n\n## About \"Form Fields\" { #about-form-fields }\n\nThe way HTML forms (`<form></form>`) sends the data to the server normally uses a \"special\" encoding for that data, it's different from JSON.\n\n**FastAPI** will make sure to read that data from the right place instead of JSON.\n\n/// note | Technical Details\n\nData from forms is normally encoded using the \"media type\" `application/x-www-form-urlencoded`.\n\nBut when the form includes files, it is encoded as `multipart/form-data`. You'll read about handling files in the next chapter.\n\nIf you want to read more about these encodings and form fields, head to the [<abbr title=\"Mozilla Developer Network\">MDN</abbr> web docs for `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning\n\nYou can declare multiple `Form` parameters in a *path operation*, but you can't also declare `Body` fields that you expect to receive as JSON, as the request will have the body encoded using `application/x-www-form-urlencoded` instead of `application/json`.\n\nThis is not a limitation of **FastAPI**, it's part of the HTTP protocol.\n\n///\n\n## Recap { #recap }\n\nUse `Form` to declare form data input parameters.\n"
  },
  {
    "path": "docs/en/docs/tutorial/response-model.md",
    "content": "# Response Model - Return Type { #response-model-return-type }\n\nYou can declare the type used for the response by annotating the *path operation function* **return type**.\n\nYou can use **type annotations** the same way you would for input data in function **parameters**, you can use Pydantic models, lists, dictionaries, scalar values like integers, booleans, etc.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPI will use this return type to:\n\n* **Validate** the returned data.\n    * If the data is invalid (e.g. you are missing a field), it means that *your* app code is broken, not returning what it should, and it will return a server error instead of returning incorrect data. This way you and your clients can be certain that they will receive the data and the data shape expected.\n* Add a **JSON Schema** for the response, in the OpenAPI *path operation*.\n    * This will be used by the **automatic docs**.\n    * It will also be used by automatic client code generation tools.\n* **Serialize** the returned data to JSON using Pydantic, which is written in **Rust**, so it will be **much faster**.\n\nBut most importantly:\n\n* It will **limit and filter** the output data to what is defined in the return type.\n    * This is particularly important for **security**, we'll see more of that below.\n\n## `response_model` Parameter { #response-model-parameter }\n\nThere are some cases where you need or want to return some data that is not exactly what the type declares.\n\nFor example, you could want to **return a dictionary** or a database object, but **declare it as a Pydantic model**. This way the Pydantic model would do all the data documentation, validation, etc. for the object that you returned (e.g. a dictionary or database object).\n\nIf you added the return type annotation, tools and editors would complain with a (correct) error telling you that your function is returning a type (e.g. a dict) that is different from what you declared (e.g. a Pydantic model).\n\nIn those cases, you can use the *path operation decorator* parameter `response_model` instead of the return type.\n\nYou can use the `response_model` parameter in any of the *path operations*:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* etc.\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note\n\nNotice that `response_model` is a parameter of the \"decorator\" method (`get`, `post`, etc). Not of your *path operation function*, like all the parameters and body.\n\n///\n\n`response_model` receives the same type you would declare for a Pydantic model field, so, it can be a Pydantic model, but it can also be, e.g. a `list` of Pydantic models, like `List[Item]`.\n\nFastAPI will use this `response_model` to do all the data documentation, validation, etc. and also to **convert and filter the output data** to its type declaration.\n\n/// tip\n\nIf you have strict type checks in your editor, mypy, etc, you can declare the function return type as `Any`.\n\nThat way you tell the editor that you are intentionally returning anything. But FastAPI will still do the data documentation, validation, filtering, etc. with the `response_model`.\n\n///\n\n### `response_model` Priority { #response-model-priority }\n\nIf you declare both a return type and a `response_model`, the `response_model` will take priority and be used by FastAPI.\n\nThis way you can add correct type annotations to your functions even when you are returning a type different than the response model, to be used by the editor and tools like mypy. And still you can have FastAPI do the data validation, documentation, etc. using the `response_model`.\n\nYou can also use `response_model=None` to disable creating a response model for that *path operation*, you might need to do it if you are adding type annotations for things that are not valid Pydantic fields, you will see an example of that in one of the sections below.\n\n## Return the same input data { #return-the-same-input-data }\n\nHere we are declaring a `UserIn` model, it will contain a plaintext password:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info\n\nTo use `EmailStr`, first install [`email-validator`](https://github.com/JoshData/python-email-validator).\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and then install it, for example:\n\n```console\n$ pip install email-validator\n```\n\nor with:\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\nAnd we are using this model to declare our input and the same model to declare our output:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\nNow, whenever a browser is creating a user with a password, the API will return the same password in the response.\n\nIn this case, it might not be a problem, because it's the same user sending the password.\n\nBut if we use the same model for another *path operation*, we could be sending our user's passwords to every client.\n\n/// danger\n\nNever store the plain password of a user or send it in a response like this, unless you know all the caveats and you know what you are doing.\n\n///\n\n## Add an output model { #add-an-output-model }\n\nWe can instead create an input model with the plaintext password and an output model without it:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\nHere, even though our *path operation function* is returning the same input user that contains the password:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n...we declared the `response_model` to be our model `UserOut`, that doesn't include the password:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\nSo, **FastAPI** will take care of filtering out all the data that is not declared in the output model (using Pydantic).\n\n### `response_model` or Return Type { #response-model-or-return-type }\n\nIn this case, because the two models are different, if we annotated the function return type as `UserOut`, the editor and tools would complain that we are returning an invalid type, as those are different classes.\n\nThat's why in this example we have to declare it in the `response_model` parameter.\n\n...but continue reading below to see how to overcome that.\n\n## Return Type and Data Filtering { #return-type-and-data-filtering }\n\nLet's continue from the previous example. We wanted to **annotate the function with one type**, but we wanted to be able to return from the function something that actually includes **more data**.\n\nWe want FastAPI to keep **filtering** the data using the response model. So that even though the function returns more data, the response will only include the fields declared in the response model.\n\nIn the previous example, because the classes were different, we had to use the `response_model` parameter. But that also means that we don't get the support from the editor and tools checking the function return type.\n\nBut in most of the cases where we need to do something like this, we want the model just to **filter/remove** some of the data as in this example.\n\nAnd in those cases, we can use classes and inheritance to take advantage of function **type annotations** to get better support in the editor and tools, and still get the FastAPI **data filtering**.\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\nWith this, we get tooling support, from editors and mypy as this code is correct in terms of types, but we also get the data filtering from FastAPI.\n\nHow does this work? Let's check that out. 🤓\n\n### Type Annotations and Tooling { #type-annotations-and-tooling }\n\nFirst let's see how editors, mypy and other tools would see this.\n\n`BaseUser` has the base fields. Then `UserIn` inherits from `BaseUser` and adds the `password` field, so, it will include all the fields from both models.\n\nWe annotate the function return type as `BaseUser`, but we are actually returning a `UserIn` instance.\n\nThe editor, mypy, and other tools won't complain about this because, in typing terms, `UserIn` is a subclass of `BaseUser`, which means it's a *valid* type when what is expected is anything that is a `BaseUser`.\n\n### FastAPI Data Filtering { #fastapi-data-filtering }\n\nNow, for FastAPI, it will see the return type and make sure that what you return includes **only** the fields that are declared in the type.\n\nFastAPI does several things internally with Pydantic to make sure that those same rules of class inheritance are not used for the returned data filtering, otherwise you could end up returning much more data than what you expected.\n\nThis way, you can get the best of both worlds: type annotations with **tooling support** and **data filtering**.\n\n## See it in the docs { #see-it-in-the-docs }\n\nWhen you see the automatic docs, you can check that the input model and output model will both have their own JSON Schema:\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\nAnd both models will be used for the interactive API documentation:\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## Other Return Type Annotations { #other-return-type-annotations }\n\nThere might be cases where you return something that is not a valid Pydantic field and you annotate it in the function, only to get the support provided by tooling (the editor, mypy, etc).\n\n### Return a Response Directly { #return-a-response-directly }\n\nThe most common case would be [returning a Response directly as explained later in the advanced docs](../advanced/response-directly.md).\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\nThis simple case is handled automatically by FastAPI because the return type annotation is the class (or a subclass of) `Response`.\n\nAnd tools will also be happy because both `RedirectResponse` and `JSONResponse` are subclasses of `Response`, so the type annotation is correct.\n\n### Annotate a Response Subclass { #annotate-a-response-subclass }\n\nYou can also use a subclass of `Response` in the type annotation:\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\nThis will also work because `RedirectResponse` is a subclass of `Response`, and FastAPI will automatically handle this simple case.\n\n### Invalid Return Type Annotations { #invalid-return-type-annotations }\n\nBut when you return some other arbitrary object that is not a valid Pydantic type (e.g. a database object) and you annotate it like that in the function, FastAPI will try to create a Pydantic response model from that type annotation, and will fail.\n\nThe same would happen if you had something like a <dfn title='A union between multiple types means \"any of these types\".'>union</dfn> between different types where one or more of them are not valid Pydantic types, for example this would fail 💥:\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n...this fails because the type annotation is not a Pydantic type and is not just a single `Response` class or subclass, it's a union (any of the two) between a `Response` and a `dict`.\n\n### Disable Response Model { #disable-response-model }\n\nContinuing from the example above, you might not want to have the default data validation, documentation, filtering, etc. that is performed by FastAPI.\n\nBut you might want to still keep the return type annotation in the function to get the support from tools like editors and type checkers (e.g. mypy).\n\nIn this case, you can disable the response model generation by setting `response_model=None`:\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\nThis will make FastAPI skip the response model generation and that way you can have any return type annotations you need without it affecting your FastAPI application. 🤓\n\n## Response Model encoding parameters { #response-model-encoding-parameters }\n\nYour response model could have default values, like:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None` (or `str | None = None` in Python 3.10) has a default of `None`.\n* `tax: float = 10.5` has a default of `10.5`.\n* `tags: List[str] = []` has a default of an empty list: `[]`.\n\nbut you might want to omit them from the result if they were not actually stored.\n\nFor example, if you have models with many optional attributes in a NoSQL database, but you don't want to send very long JSON responses full of default values.\n\n### Use the `response_model_exclude_unset` parameter { #use-the-response-model-exclude-unset-parameter }\n\nYou can set the *path operation decorator* parameter `response_model_exclude_unset=True`:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\nand those default values won't be included in the response, only the values actually set.\n\nSo, if you send a request to that *path operation* for the item with ID `foo`, the response (not including default values) will be:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info\n\nYou can also use:\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\nas described in [the Pydantic docs](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict) for `exclude_defaults` and `exclude_none`.\n\n///\n\n#### Data with values for fields with defaults { #data-with-values-for-fields-with-defaults }\n\nBut if your data has values for the model's fields with default values, like the item with ID `bar`:\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\nthey will be included in the response.\n\n#### Data with the same values as the defaults { #data-with-the-same-values-as-the-defaults }\n\nIf the data has the same values as the default ones, like the item with ID `baz`:\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nFastAPI is smart enough (actually, Pydantic is smart enough) to realize that, even though `description`, `tax`, and `tags` have the same values as the defaults, they were set explicitly (instead of taken from the defaults).\n\nSo, they will be included in the JSON response.\n\n/// tip\n\nNotice that the default values can be anything, not only `None`.\n\nThey can be a list (`[]`), a `float` of `10.5`, etc.\n\n///\n\n### `response_model_include` and `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\nYou can also use the *path operation decorator* parameters `response_model_include` and `response_model_exclude`.\n\nThey take a `set` of `str` with the name of the attributes to include (omitting the rest) or to exclude (including the rest).\n\nThis can be used as a quick shortcut if you have only one Pydantic model and want to remove some data from the output.\n\n/// tip\n\nBut it is still recommended to use the ideas above, using multiple classes, instead of these parameters.\n\nThis is because the JSON Schema generated in your app's OpenAPI (and the docs) will still be the one for the complete model, even if you use `response_model_include` or `response_model_exclude` to omit some attributes.\n\nThis also applies to `response_model_by_alias` that works similarly.\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip\n\nThe syntax `{\"name\", \"description\"}` creates a `set` with those two values.\n\nIt is equivalent to `set([\"name\", \"description\"])`.\n\n///\n\n#### Using `list`s instead of `set`s { #using-lists-instead-of-sets }\n\nIf you forget to use a `set` and use a `list` or `tuple` instead, FastAPI will still convert it to a `set` and it will work correctly:\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## Recap { #recap }\n\nUse the *path operation decorator's* parameter `response_model` to define response models and especially to ensure private data is filtered out.\n\nUse `response_model_exclude_unset` to return only the values explicitly set.\n"
  },
  {
    "path": "docs/en/docs/tutorial/response-status-code.md",
    "content": "# Response Status Code { #response-status-code }\n\nThe same way you can specify a response model, you can also declare the HTTP status code used for the response with the parameter `status_code` in any of the *path operations*:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* etc.\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note\n\nNotice that `status_code` is a parameter of the \"decorator\" method (`get`, `post`, etc). Not of your *path operation function*, like all the parameters and body.\n\n///\n\nThe `status_code` parameter receives a number with the HTTP status code.\n\n/// info\n\n`status_code` can alternatively also receive an `IntEnum`, such as Python's [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus).\n\n///\n\nIt will:\n\n* Return that status code in the response.\n* Document it as such in the OpenAPI schema (and so, in the user interfaces):\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note\n\nSome response codes (see the next section) indicate that the response does not have a body.\n\nFastAPI knows this, and will produce OpenAPI docs that state there is no response body.\n\n///\n\n## About HTTP status codes { #about-http-status-codes }\n\n/// note\n\nIf you already know what HTTP status codes are, skip to the next section.\n\n///\n\nIn HTTP, you send a numeric status code of 3 digits as part of the response.\n\nThese status codes have a name associated to recognize them, but the important part is the number.\n\nIn short:\n\n* `100 - 199` are for \"Information\". You rarely use them directly.  Responses with these status codes cannot have a body.\n* **`200 - 299`** are for \"Successful\" responses. These are the ones you would use the most.\n    * `200` is the default status code, which means everything was \"OK\".\n    * Another example would be `201`, \"Created\". It is commonly used after creating a new record in the database.\n    * A special case is `204`, \"No Content\".  This response is used when there is no content to return to the client, and so the response must not have a body.\n* **`300 - 399`** are for \"Redirection\".  Responses with these status codes may or may not have a body, except for `304`, \"Not Modified\", which must not have one.\n* **`400 - 499`** are for \"Client error\" responses. These are the second type you would probably use the most.\n    * An example is `404`, for a \"Not Found\" response.\n    * For generic errors from the client, you can just use `400`.\n* `500 - 599` are for server errors. You almost never use them directly. When something goes wrong at some part in your application code, or server, it will automatically return one of these status codes.\n\n/// tip\n\nTo know more about each status code and which code is for what, check the [<abbr title=\"Mozilla Developer Network\">MDN</abbr> documentation about HTTP status codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).\n\n///\n\n## Shortcut to remember the names { #shortcut-to-remember-the-names }\n\nLet's see the previous example again:\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201` is the status code for \"Created\".\n\nBut you don't have to memorize what each of these codes mean.\n\nYou can use the convenience variables from `fastapi.status`.\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\nThey are just a convenience, they hold the same number, but that way you can use the editor's autocomplete to find them:\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | Technical Details\n\nYou could also use `from starlette import status`.\n\n**FastAPI** provides the same `starlette.status` as `fastapi.status` just as a convenience for you, the developer. But it comes directly from Starlette.\n\n///\n\n## Changing the default { #changing-the-default }\n\nLater, in the [Advanced User Guide](../advanced/response-change-status-code.md), you will see how to return a different status code than the default you are declaring here.\n"
  },
  {
    "path": "docs/en/docs/tutorial/schema-extra-example.md",
    "content": "# Declare Request Example Data { #declare-request-example-data }\n\nYou can declare examples of the data your app can receive.\n\nHere are several ways to do it.\n\n## Extra JSON Schema data in Pydantic models { #extra-json-schema-data-in-pydantic-models }\n\nYou can declare `examples` for a Pydantic model that will be added to the generated JSON Schema.\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\nThat extra info will be added as-is to the output **JSON Schema** for that model, and it will be used in the API docs.\n\nYou can use the attribute `model_config` that takes a `dict` as described in [Pydantic's docs: Configuration](https://docs.pydantic.dev/latest/api/config/).\n\nYou 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`.\n\n/// tip\n\nYou could use the same technique to extend the JSON Schema and add your own custom extra info.\n\nFor example you could use it to add metadata for a frontend user interface, etc.\n\n///\n\n/// info\n\nOpenAPI 3.1.0 (used since FastAPI 0.99.0) added support for `examples`, which is part of the **JSON Schema** standard.\n\nBefore that, it only supported the keyword `example` with a single example. That is still supported by OpenAPI 3.1.0, but is deprecated and is not part of the JSON Schema standard. So you are encouraged to migrate `example` to `examples`. 🤓\n\nYou can read more at the end of this page.\n\n///\n\n## `Field` additional arguments { #field-additional-arguments }\n\nWhen using `Field()` with Pydantic models, you can also declare additional `examples`:\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## `examples` in JSON Schema - OpenAPI { #examples-in-json-schema-openapi }\n\nWhen using any of:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nyou can also declare a group of `examples` with additional information that will be added to their **JSON Schemas** inside of **OpenAPI**.\n\n### `Body` with `examples` { #body-with-examples }\n\nHere we pass `examples` containing one example of the data expected in `Body()`:\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### Example in the docs UI { #example-in-the-docs-ui }\n\nWith any of the methods above it would look like this in the `/docs`:\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### `Body` with multiple `examples` { #body-with-multiple-examples }\n\nYou can of course also pass multiple `examples`:\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\nWhen you do this, the examples will be part of the internal **JSON Schema** for that body data.\n\nNevertheless, at the <dfn title=\"2023-08-26\">time of writing this</dfn>, 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.\n\n### OpenAPI-specific `examples` { #openapi-specific-examples }\n\nSince before **JSON Schema** supported `examples` OpenAPI had support for a different field also called `examples`.\n\nThis **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.\n\nAnd Swagger UI has supported this particular `examples` field for a while. So, you can use it to **show** different **examples in the docs UI**.\n\nThe 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.\n\nThis doesn't go inside of each JSON Schema contained in OpenAPI, this goes outside, in the *path operation* directly.\n\n### Using the `openapi_examples` Parameter { #using-the-openapi-examples-parameter }\n\nYou can declare the OpenAPI-specific `examples` in FastAPI with the parameter `openapi_examples` for:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nThe keys of the `dict` identify each example, and each value is another `dict`.\n\nEach specific example `dict` in the `examples` can contain:\n\n* `summary`: Short description for the example.\n* `description`: A long description that can contain Markdown text.\n* `value`: This is the actual example shown, e.g. a `dict`.\n* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`.\n\nYou can use it like this:\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### OpenAPI Examples in the Docs UI { #openapi-examples-in-the-docs-ui }\n\nWith `openapi_examples` added to `Body()` the `/docs` would look like:\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## Technical Details { #technical-details }\n\n/// tip\n\nIf you are already using **FastAPI** version **0.99.0 or above**, you can probably **skip** these details.\n\nThey are more relevant for older versions, before OpenAPI 3.1.0 was available.\n\nYou can consider this a brief OpenAPI and JSON Schema **history lesson**. 🤓\n\n///\n\n/// warning\n\nThese are very technical details about the standards **JSON Schema** and **OpenAPI**.\n\nIf the ideas above already work for you, that might be enough, and you probably don't need these details, feel free to skip them.\n\n///\n\nBefore OpenAPI 3.1.0, OpenAPI used an older and modified version of **JSON Schema**.\n\nJSON Schema didn't have `examples`, so OpenAPI added its own `example` field to its own modified version.\n\nOpenAPI also added `example` and `examples` fields to other parts of the specification:\n\n* [`Parameter Object` (in the specification)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object) that was used by FastAPI's:\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object`, in the field `content`, on the `Media Type Object` (in the specification)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object) that was used by FastAPI's:\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info\n\nThis old OpenAPI-specific `examples` parameter is now `openapi_examples` since FastAPI `0.103.0`.\n\n///\n\n### JSON Schema's `examples` field { #json-schemas-examples-field }\n\nBut then JSON Schema added an [`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5) field to a new version of the specification.\n\nAnd then the new OpenAPI 3.1.0 was based on the latest version (JSON Schema 2020-12) that included this new field `examples`.\n\nAnd now this new `examples` field takes precedence over the old single (and custom) `example` field, that is now deprecated.\n\nThis new `examples` field in JSON Schema is **just a `list`** of examples, not a dict with extra metadata as in the other places in OpenAPI (described above).\n\n/// info\n\nEven after OpenAPI 3.1.0 was released with this new simpler integration with JSON Schema, for a while, Swagger UI, the tool that provides the automatic docs, didn't support OpenAPI 3.1.0 (it does since version 5.0.0 🎉).\n\nBecause of that, versions of FastAPI previous to 0.99.0 still used versions of OpenAPI lower than 3.1.0.\n\n///\n\n### Pydantic and FastAPI `examples` { #pydantic-and-fastapi-examples }\n\nWhen you add `examples` inside a Pydantic model, using `schema_extra` or `Field(examples=[\"something\"])` that example is added to the **JSON Schema** for that Pydantic model.\n\nAnd that **JSON Schema** of the Pydantic model is included in the **OpenAPI** of your API, and then it's used in the docs UI.\n\nIn versions of FastAPI before 0.99.0 (0.99.0 and above use the newer OpenAPI 3.1.0) when you used `example` or `examples` with any of the other utilities (`Query()`, `Body()`, etc.) those examples were not added to the JSON Schema that describes that data (not even to OpenAPI's own version of JSON Schema), they were added directly to the *path operation* declaration in OpenAPI (outside the parts of OpenAPI that use JSON Schema).\n\nBut 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.\n\n### Swagger UI and OpenAPI-specific `examples` { #swagger-ui-and-openapi-specific-examples }\n\nNow, 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.\n\nTo solve that, FastAPI `0.103.0` **added support** for declaring the same old **OpenAPI-specific** `examples` field with the new parameter `openapi_examples`. 🤓\n\n### Summary { #summary }\n\nI used to say I didn't like history that much... and look at me now giving \"tech history\" lessons. 😅\n\nIn short, **upgrade to FastAPI 0.99.0 or above**, and things are much **simpler, consistent, and intuitive**, and you don't have to know all these historic details. 😎\n"
  },
  {
    "path": "docs/en/docs/tutorial/security/first-steps.md",
    "content": "# Security - First Steps { #security-first-steps }\n\nLet's imagine that you have your **backend** API in some domain.\n\nAnd you have a **frontend** in another domain or in a different path of the same domain (or in a mobile application).\n\nAnd you want to have a way for the frontend to authenticate with the backend, using a **username** and **password**.\n\nWe can use **OAuth2** to build that with **FastAPI**.\n\nBut let's save you the time of reading the full long specification just to find those little pieces of information you need.\n\nLet's use the tools provided by **FastAPI** to handle security.\n\n## How it looks { #how-it-looks }\n\nLet's first just use the code and see how it works, and then we'll come back to understand what's happening.\n\n## Create `main.py` { #create-main-py }\n\nCopy the example in a file `main.py`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## Run it { #run-it }\n\n/// info\n\nThe [`python-multipart`](https://github.com/Kludex/python-multipart) package is automatically installed with **FastAPI** when you run the `pip install \"fastapi[standard]\"` command.\n\nHowever, if you use the `pip install fastapi` command, the `python-multipart` package is not included by default.\n\nTo install it manually, make sure you create a [virtual environment](../../virtual-environments.md), activate it, and then install it with:\n\n```console\n$ pip install python-multipart\n```\n\nThis is because **OAuth2** uses \"form data\" for sending the `username` and `password`.\n\n///\n\nRun the example with:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## Check it { #check-it }\n\nGo to the interactive docs at: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nYou will see something like this:\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Authorize button!\n\nYou already have a shiny new \"Authorize\" button.\n\nAnd your *path operation* has a little lock in the top-right corner that you can click.\n\n///\n\nAnd if you click it, you have a little authorization form to type a `username` and `password` (and other optional fields):\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note\n\nIt doesn't matter what you type in the form, it won't work yet. But we'll get there.\n\n///\n\nThis is of course not the frontend for the final users, but it's a great automatic tool to document interactively all your API.\n\nIt can be used by the frontend team (that can also be yourself).\n\nIt can be used by third party applications and systems.\n\nAnd it can also be used by yourself, to debug, check and test the same application.\n\n## The `password` flow { #the-password-flow }\n\nNow let's go back a bit and understand what is all that.\n\nThe `password` \"flow\" is one of the ways (\"flows\") defined in OAuth2, to handle security and authentication.\n\nOAuth2 was designed so that the backend or API could be independent of the server that authenticates the user.\n\nBut in this case, the same **FastAPI** application will handle the API and the authentication.\n\nSo, let's review it from that simplified point of view:\n\n* The user types the `username` and `password` in the frontend, and hits `Enter`.\n* The frontend (running in the user's browser) sends that `username` and `password` to a specific URL in our API (declared with `tokenUrl=\"token\"`).\n* The API checks that `username` and `password`, and responds with a \"token\" (we haven't implemented any of this yet).\n    * A \"token\" is just a string with some content that we can use later to verify this user.\n    * Normally, a token is set to expire after some time.\n        * So, the user will have to log in again at some point later.\n        * And if the token is stolen, the risk is less. It is not like a permanent key that will work forever (in most of the cases).\n* The frontend stores that token temporarily somewhere.\n* The user clicks in the frontend to go to another section of the frontend web app.\n* The frontend needs to fetch some more data from the API.\n    * But it needs authentication for that specific endpoint.\n    * So, to authenticate with our API, it sends a header `Authorization` with a value of `Bearer ` plus the token.\n    * If the token contains `foobar`, the content of the `Authorization` header would be: `Bearer foobar`.\n\n## **FastAPI**'s `OAuth2PasswordBearer` { #fastapis-oauth2passwordbearer }\n\n**FastAPI** provides several tools, at different levels of abstraction, to implement these security features.\n\nIn this example we are going to use **OAuth2**, with the **Password** flow, using a **Bearer** token. We do that using the `OAuth2PasswordBearer` class.\n\n/// info\n\nA \"bearer\" token is not the only option.\n\nBut it's the best one for our use case.\n\nAnd it might be the best for most use cases, unless you are an OAuth2 expert and know exactly why there's another option that better suits your needs.\n\nIn that case, **FastAPI** also provides you with the tools to build it.\n\n///\n\nWhen we create an instance of the `OAuth2PasswordBearer` class we pass in the `tokenUrl` parameter. This parameter contains the URL that the client (the frontend running in the user's browser) will use to send the `username` and `password` in order to get a token.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip\n\nHere `tokenUrl=\"token\"` refers to a relative URL `token` that we haven't created yet. As it's a relative URL, it's equivalent to `./token`.\n\nBecause we are using a relative URL, if your API was located at `https://example.com/`, then it would refer to `https://example.com/token`. But if your API was located at `https://example.com/api/v1/`, then it would refer to `https://example.com/api/v1/token`.\n\nUsing a relative URL is important to make sure your application keeps working even in an advanced use case like [Behind a Proxy](../../advanced/behind-a-proxy.md).\n\n///\n\nThis parameter doesn't create that endpoint / *path operation*, but declares that the URL `/token` will be the one that the client should use to get the token. That information is used in OpenAPI, and then in the interactive API documentation systems.\n\nWe will soon also create the actual path operation.\n\n/// info\n\nIf you are a very strict \"Pythonista\" you might dislike the style of the parameter name `tokenUrl` instead of `token_url`.\n\nThat's because it is using the same name as in the OpenAPI spec. So that if you need to investigate more about any of these security schemes you can just copy and paste it to find more information about it.\n\n///\n\nThe `oauth2_scheme` variable is an instance of `OAuth2PasswordBearer`, but it is also a \"callable\".\n\nIt could be called as:\n\n```Python\noauth2_scheme(some, parameters)\n```\n\nSo, it can be used with `Depends`.\n\n### Use it { #use-it }\n\nNow you can pass that `oauth2_scheme` in a dependency with `Depends`.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nThis dependency will provide a `str` that is assigned to the parameter `token` of the *path operation function*.\n\n**FastAPI** will know that it can use this dependency to define a \"security scheme\" in the OpenAPI schema (and the automatic API docs).\n\n/// info | Technical Details\n\n**FastAPI** will know that it can use the class `OAuth2PasswordBearer` (declared in a dependency) to define the security scheme in OpenAPI because it inherits from `fastapi.security.oauth2.OAuth2`, which in turn inherits from `fastapi.security.base.SecurityBase`.\n\nAll the security utilities that integrate with OpenAPI (and the automatic API docs) inherit from `SecurityBase`, that's how **FastAPI** can know how to integrate them in OpenAPI.\n\n///\n\n## What it does { #what-it-does }\n\nIt will go and look in the request for that `Authorization` header, check if the value is `Bearer ` plus some token, and will return the token as a `str`.\n\nIf it doesn't see an `Authorization` header, or the value doesn't have a `Bearer ` token, it will respond with a 401 status code error (`UNAUTHORIZED`) directly.\n\nYou don't even have to check if the token exists to return an error. You can be sure that if your function is executed, it will have a `str` in that token.\n\nYou can try it already in the interactive docs:\n\n<img src=\"/img/tutorial/security/image03.png\">\n\nWe are not verifying the validity of the token yet, but that's a start already.\n\n## Recap { #recap }\n\nSo, in just 3 or 4 extra lines, you already have some primitive form of security.\n"
  },
  {
    "path": "docs/en/docs/tutorial/security/get-current-user.md",
    "content": "# Get Current User { #get-current-user }\n\nIn the previous chapter the security system (which is based on the dependency injection system) was giving the *path operation function* a `token` as a `str`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nBut that is still not that useful.\n\nLet's make it give us the current user.\n\n## Create a user model { #create-a-user-model }\n\nFirst, let's create a Pydantic user model.\n\nThe same way we use Pydantic to declare bodies, we can use it anywhere else:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## Create a `get_current_user` dependency { #create-a-get-current-user-dependency }\n\nLet's create a dependency `get_current_user`.\n\nRemember that dependencies can have sub-dependencies?\n\n`get_current_user` will have a dependency with the same `oauth2_scheme` we created before.\n\nThe same as we were doing before in the *path operation* directly, our new dependency `get_current_user` will receive a `token` as a `str` from the sub-dependency `oauth2_scheme`:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## Get the user { #get-the-user }\n\n`get_current_user` will use a (fake) utility function we created, that takes a token as a `str` and returns our Pydantic `User` model:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## Inject the current user { #inject-the-current-user }\n\nSo now we can use the same `Depends` with our `get_current_user` in the *path operation*:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\nNotice that we declare the type of `current_user` as the Pydantic model `User`.\n\nThis will help us inside of the function with all the completion and type checks.\n\n/// tip\n\nYou might remember that request bodies are also declared with Pydantic models.\n\nHere **FastAPI** won't get confused because you are using `Depends`.\n\n///\n\n/// check\n\nThe way this dependency system is designed allows us to have different dependencies (different \"dependables\") that all return a `User` model.\n\nWe are not restricted to having only one dependency that can return that type of data.\n\n///\n\n## Other models { #other-models }\n\nYou can now get the current user directly in the *path operation functions* and deal with the security mechanisms at the **Dependency Injection** level, using `Depends`.\n\nAnd you can use any model or data for the security requirements (in this case, a Pydantic model `User`).\n\nBut you are not restricted to using some specific data model, class or type.\n\nDo you want to have an `id` and `email` and not have any `username` in your model? Sure. You can use these same tools.\n\nDo you want to just have a `str`? Or just a `dict`? Or a database class model instance directly? It all works the same way.\n\nYou actually don't have users that log in to your application but robots, bots, or other systems, that have just an access token? Again, it all works the same.\n\nJust use any kind of model, any kind of class, any kind of database that you need for your application. **FastAPI** has you covered with the dependency injection system.\n\n## Code size { #code-size }\n\nThis example might seem verbose. Keep in mind that we are mixing security, data models, utility functions and *path operations* in the same file.\n\nBut here's the key point.\n\nThe security and dependency injection stuff is written once.\n\nAnd you can make it as complex as you want. And still, have it written only once, in a single place. With all the flexibility.\n\nBut you can have thousands of endpoints (*path operations*) using the same security system.\n\nAnd all of them (or any portion of them that you want) can take advantage of re-using these dependencies or any other dependencies you create.\n\nAnd all these thousands of *path operations* can be as small as 3 lines:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## Recap { #recap }\n\nYou can now get the current user directly in your *path operation function*.\n\nWe are already halfway there.\n\nWe just need to add a *path operation* for the user/client to actually send the `username` and `password`.\n\nThat comes next.\n"
  },
  {
    "path": "docs/en/docs/tutorial/security/index.md",
    "content": "# Security { #security }\n\nThere are many ways to handle security, authentication and authorization.\n\nAnd it normally is a complex and \"difficult\" topic.\n\nIn many frameworks and systems just handling security and authentication takes a big amount of effort and code (in many cases it can be 50% or more of all the code written).\n\n**FastAPI** provides several tools to help you deal with **Security** easily, rapidly, in a standard way, without having to study and learn all the security specifications.\n\nBut first, let's check some small concepts.\n\n## In a hurry? { #in-a-hurry }\n\nIf you don't care about any of these terms and you just need to add security with authentication based on username and password *right now*, skip to the next chapters.\n\n## OAuth2 { #oauth2 }\n\nOAuth2 is a specification that defines several ways to handle authentication and authorization.\n\nIt is quite an extensive specification and covers several complex use cases.\n\nIt includes ways to authenticate using a \"third party\".\n\nThat's what all the systems with \"login with Facebook, Google, X (Twitter), GitHub\" use underneath.\n\n### OAuth 1 { #oauth-1 }\n\nThere was an OAuth 1, which is very different from OAuth2, and more complex, as it included direct specifications on how to encrypt the communication.\n\nIt is not very popular or used nowadays.\n\nOAuth2 doesn't specify how to encrypt the communication, it expects you to have your application served with HTTPS.\n\n/// tip\n\nIn the section about **deployment** you will see how to set up HTTPS for free, using Traefik and Let's Encrypt.\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect is another specification, based on **OAuth2**.\n\nIt just extends OAuth2 specifying some things that are relatively ambiguous in OAuth2, to try to make it more interoperable.\n\nFor example, Google login uses OpenID Connect (which underneath uses OAuth2).\n\nBut Facebook login doesn't support OpenID Connect. It has its own flavor of OAuth2.\n\n### OpenID (not \"OpenID Connect\") { #openid-not-openid-connect }\n\nThere was also an \"OpenID\" specification. That tried to solve the same thing as **OpenID Connect**, but was not based on OAuth2.\n\nSo, it was a complete additional system.\n\nIt is not very popular or used nowadays.\n\n## OpenAPI { #openapi }\n\nOpenAPI (previously known as Swagger) is the open specification for building APIs (now part of the Linux Foundation).\n\n**FastAPI** is based on **OpenAPI**.\n\nThat's what makes it possible to have multiple automatic interactive documentation interfaces, code generation, etc.\n\nOpenAPI has a way to define multiple security \"schemes\".\n\nBy using them, you can take advantage of all these standard-based tools, including these interactive documentation systems.\n\nOpenAPI defines the following security schemes:\n\n* `apiKey`: an application specific key that can come from:\n    * A query parameter.\n    * A header.\n    * A cookie.\n* `http`: standard HTTP authentication systems, including:\n    * `bearer`: a header `Authorization` with a value of `Bearer ` plus a token. This is inherited from OAuth2.\n    * HTTP Basic authentication.\n    * HTTP Digest, etc.\n* `oauth2`: all the OAuth2 ways to handle security (called \"flows\").\n    * Several of these flows are appropriate for building an OAuth 2.0 authentication provider (like Google, Facebook, X (Twitter), GitHub, etc):\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * But there is one specific \"flow\" that can be perfectly used for handling authentication in the same application directly:\n        * `password`: some next chapters will cover examples of this.\n* `openIdConnect`: has a way to define how to discover OAuth2 authentication data automatically.\n    * This automatic discovery is what is defined in the OpenID Connect specification.\n\n\n/// tip\n\nIntegrating other authentication/authorization providers like Google, Facebook, X (Twitter), GitHub, etc. is also possible and relatively easy.\n\nThe most complex problem is building an authentication/authorization provider like those, but **FastAPI** gives you the tools to do it easily, while doing the heavy lifting for you.\n\n///\n\n## **FastAPI** utilities { #fastapi-utilities }\n\nFastAPI provides several tools for each of these security schemes in the `fastapi.security` module that simplify using these security mechanisms.\n\nIn the next chapters you will see how to add security to your API using those tools provided by **FastAPI**.\n\nAnd you will also see how it gets automatically integrated into the interactive documentation system.\n"
  },
  {
    "path": "docs/en/docs/tutorial/security/oauth2-jwt.md",
    "content": "# OAuth2 with Password (and hashing), Bearer with JWT tokens { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\nNow that we have all the security flow, let's make the application actually secure, using <abbr title=\"JSON Web Tokens\">JWT</abbr> tokens and secure password hashing.\n\nThis code is something you can actually use in your application, save the password hashes in your database, etc.\n\nWe are going to start from where we left in the previous chapter and increment it.\n\n## About JWT { #about-jwt }\n\nJWT means \"JSON Web Tokens\".\n\nIt's a standard to codify a JSON object in a long dense string without spaces. It looks like this:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\nIt is not encrypted, so, anyone could recover the information from the contents.\n\nBut it's signed. So, when you receive a token that you emitted, you can verify that you actually emitted it.\n\nThat way, you can create a token with an expiration of, let's say, 1 week. And then when the user comes back the next day with the token, you know that user is still logged in to your system.\n\nAfter a week, the token will be expired and the user will not be authorized and will have to sign in again to get a new token. And if the user (or a third party) tried to modify the token to change the expiration, you would be able to discover it, because the signatures would not match.\n\nIf you want to play with JWT tokens and see how they work, check [https://jwt.io](https://jwt.io/).\n\n## Install `PyJWT` { #install-pyjwt }\n\nWe need to install `PyJWT` to generate and verify the JWT tokens in Python.\n\nMake sure you create a [virtual environment](../../virtual-environments.md), activate it, and then install `pyjwt`:\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info\n\nIf you are planning to use digital signature algorithms like RSA or ECDSA, you should install the cryptography library dependency `pyjwt[crypto]`.\n\nYou can read more about it in the [PyJWT Installation docs](https://pyjwt.readthedocs.io/en/latest/installation.html).\n\n///\n\n## Password hashing { #password-hashing }\n\n\"Hashing\" means converting some content (a password in this case) into a sequence of bytes (just a string) that looks like gibberish.\n\nWhenever you pass exactly the same content (exactly the same password) you get exactly the same gibberish.\n\nBut you cannot convert from the gibberish back to the password.\n\n### Why use password hashing { #why-use-password-hashing }\n\nIf your database is stolen, the thief won't have your users' plaintext passwords, only the hashes.\n\nSo, the thief won't be able to try to use that password in another system (as many users use the same password everywhere, this would be dangerous).\n\n## Install `pwdlib` { #install-pwdlib }\n\npwdlib is a great Python package to handle password hashes.\n\nIt supports many secure hashing algorithms and utilities to work with them.\n\nThe recommended algorithm is \"Argon2\".\n\nMake sure you create a [virtual environment](../../virtual-environments.md), activate it, and then install pwdlib with Argon2:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip\n\nWith `pwdlib`, you could even configure it to be able to read passwords created by **Django**, a **Flask** security plug-in or many others.\n\nSo, you would be able to, for example, share the same data from a Django application in a database with a FastAPI application. Or gradually migrate a Django application using the same database.\n\nAnd your users would be able to login from your Django app or from your **FastAPI** app, at the same time.\n\n///\n\n## Hash and verify the passwords { #hash-and-verify-the-passwords }\n\nImport the tools we need from `pwdlib`.\n\nCreate a PasswordHash instance with recommended settings - it will be used for hashing and verifying passwords.\n\n/// tip\n\npwdlib also supports the bcrypt hashing algorithm but does not include legacy algorithms - for working with outdated hashes, it is recommended to use the passlib library.\n\nFor example, you could use it to read and verify passwords generated by another system (like Django) but hash any new passwords with a different algorithm like Argon2 or Bcrypt.\n\nAnd be compatible with all of them at the same time.\n\n///\n\nCreate a utility function to hash a password coming from the user.\n\nAnd another utility to verify if a received password matches the hash stored.\n\nAnd another one to authenticate and return a user.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\nWhen `authenticate_user` is called with a username that doesn't exist in the database, we still run `verify_password` against a dummy hash.\n\nThis ensures the endpoint takes roughly the same amount of time to respond whether the username is valid or not, preventing **timing attacks** that could be used to enumerate existing usernames.\n\n/// note\n\nIf you check the new (fake) database `fake_users_db`, you will see how the hashed password looks like now: `\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`.\n\n///\n\n## Handle JWT tokens { #handle-jwt-tokens }\n\nImport the modules installed.\n\nCreate a random secret key that will be used to sign the JWT tokens.\n\nTo generate a secure random secret key use the command:\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\nAnd copy the output to the variable `SECRET_KEY` (don't use the one in the example).\n\nCreate a variable `ALGORITHM` with the algorithm used to sign the JWT token and set it to `\"HS256\"`.\n\nCreate a variable for the expiration of the token.\n\nDefine a Pydantic Model that will be used in the token endpoint for the response.\n\nCreate a utility function to generate a new access token.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## Update the dependencies { #update-the-dependencies }\n\nUpdate `get_current_user` to receive the same token as before, but this time, using JWT tokens.\n\nDecode the received token, verify it, and return the current user.\n\nIf the token is invalid, return an HTTP error right away.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## Update the `/token` *path operation* { #update-the-token-path-operation }\n\nCreate a `timedelta` with the expiration time of the token.\n\nCreate a real JWT access token and return it.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### Technical details about the JWT \"subject\" `sub` { #technical-details-about-the-jwt-subject-sub }\n\nThe JWT specification says that there's a key `sub`, with the subject of the token.\n\nIt's optional to use it, but that's where you would put the user's identification, so we are using it here.\n\nJWT might be used for other things apart from identifying a user and allowing them to perform operations directly on your API.\n\nFor example, you could identify a \"car\" or a \"blog post\".\n\nThen you could add permissions about that entity, like \"drive\" (for the car) or \"edit\" (for the blog).\n\nAnd then, you could give that JWT token to a user (or bot), and they could use it to perform those actions (drive the car, or edit the blog post) without even needing to have an account, just with the JWT token your API generated for that.\n\nUsing these ideas, JWT can be used for way more sophisticated scenarios.\n\nIn those cases, several of those entities could have the same ID, let's say `foo` (a user `foo`, a car `foo`, and a blog post `foo`).\n\nSo, to avoid ID collisions, when creating the JWT token for the user, you could prefix the value of the `sub` key, e.g. with `username:`. So, in this example, the value of `sub` could have been: `username:johndoe`.\n\nThe important thing to keep in mind is that the `sub` key should have a unique identifier across the entire application, and it should be a string.\n\n## Check it { #check-it }\n\nRun the server and go to the docs: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nYou'll see the user interface like:\n\n<img src=\"/img/tutorial/security/image07.png\">\n\nAuthorize the application the same way as before.\n\nUsing the credentials:\n\nUsername: `johndoe`\nPassword: `secret`\n\n/// check\n\nNotice that nowhere in the code is the plaintext password \"`secret`\", we only have the hashed version.\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\nCall the endpoint `/users/me/`, you will get the response as:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\nIf you open the developer tools, you could see how the data sent only includes the token, the password is only sent in the first request to authenticate the user and get that access token, but not afterwards:\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note\n\nNotice the header `Authorization`, with a value that starts with `Bearer `.\n\n///\n\n## Advanced usage with `scopes` { #advanced-usage-with-scopes }\n\nOAuth2 has the notion of \"scopes\".\n\nYou can use them to add a specific set of permissions to a JWT token.\n\nThen you can give this token to a user directly or a third party, to interact with your API with a set of restrictions.\n\nYou can learn how to use them and how they are integrated into **FastAPI** later in the **Advanced User Guide**.\n\n## Recap { #recap }\n\nWith what you have seen up to now, you can set up a secure **FastAPI** application using standards like OAuth2 and JWT.\n\nIn almost any framework handling the security becomes a rather complex subject quite quickly.\n\nMany packages that simplify it a lot have to make many compromises with the data model, database, and available features. And some of these packages that simplify things too much actually have security flaws underneath.\n\n---\n\n**FastAPI** doesn't make any compromise with any database, data model or tool.\n\nIt gives you all the flexibility to choose the ones that fit your project the best.\n\nAnd you can use directly many well maintained and widely used packages like `pwdlib` and `PyJWT`, because **FastAPI** doesn't require any complex mechanisms to integrate external packages.\n\nBut it provides you the tools to simplify the process as much as possible without compromising flexibility, robustness, or security.\n\nAnd you can use and implement secure, standard protocols, like OAuth2 in a relatively simple way.\n\nYou can learn more in the **Advanced User Guide** about how to use OAuth2 \"scopes\", for a more fine-grained permission system, following these same standards. OAuth2 with scopes is the mechanism used by many big authentication providers, like Facebook, Google, GitHub, Microsoft, X (Twitter), etc. to authorize third party applications to interact with their APIs on behalf of their users.\n"
  },
  {
    "path": "docs/en/docs/tutorial/security/simple-oauth2.md",
    "content": "# Simple OAuth2 with Password and Bearer { #simple-oauth2-with-password-and-bearer }\n\nNow let's build from the previous chapter and add the missing parts to have a complete security flow.\n\n## Get the `username` and `password` { #get-the-username-and-password }\n\nWe are going to use **FastAPI** security utilities to get the `username` and `password`.\n\nOAuth2 specifies that when using the \"password flow\" (that we are using) the client/user must send a `username` and `password` fields as form data.\n\nAnd the spec says that the fields have to be named like that. So `user-name` or `email` wouldn't work.\n\nBut don't worry, you can show it as you wish to your final users in the frontend.\n\nAnd your database models can use any other names you want.\n\nBut for the login *path operation*, we need to use these names to be compatible with the spec (and be able to, for example, use the integrated API documentation system).\n\nThe spec also states that the `username` and `password` must be sent as form data (so, no JSON here).\n\n### `scope` { #scope }\n\nThe spec also says that the client can send another form field \"`scope`\".\n\nThe form field name is `scope` (in singular), but it is actually a long string with \"scopes\" separated by spaces.\n\nEach \"scope\" is just a string (without spaces).\n\nThey are normally used to declare specific security permissions, for example:\n\n* `users:read` or `users:write` are common examples.\n* `instagram_basic` is used by Facebook / Instagram.\n* `https://www.googleapis.com/auth/drive` is used by Google.\n\n/// info\n\nIn OAuth2 a \"scope\" is just a string that declares a specific permission required.\n\nIt doesn't matter if it has other characters like `:` or if it is a URL.\n\nThose details are implementation specific.\n\nFor OAuth2 they are just strings.\n\n///\n\n## Code to get the `username` and `password` { #code-to-get-the-username-and-password }\n\nNow let's use the utilities provided by **FastAPI** to handle this.\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\nFirst, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` in the *path operation* for `/token`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm` is a class dependency that declares a form body with:\n\n* The `username`.\n* The `password`.\n* An optional `scope` field as a big string, composed of strings separated by spaces.\n* An optional `grant_type`.\n\n/// tip\n\nThe OAuth2 spec actually *requires* a field `grant_type` with a fixed value of `password`, but `OAuth2PasswordRequestForm` doesn't enforce it.\n\nIf you need to enforce it, use `OAuth2PasswordRequestFormStrict` instead of `OAuth2PasswordRequestForm`.\n\n///\n\n* An optional `client_id` (we don't need it for our example).\n* An optional `client_secret` (we don't need it for our example).\n\n/// info\n\nThe `OAuth2PasswordRequestForm` is not a special class for **FastAPI** as is `OAuth2PasswordBearer`.\n\n`OAuth2PasswordBearer` makes **FastAPI** know that it is a security scheme. So it is added that way to OpenAPI.\n\nBut `OAuth2PasswordRequestForm` is just a class dependency that you could have written yourself, or you could have declared `Form` parameters directly.\n\nBut as it's a common use case, it is provided by **FastAPI** directly, just to make it easier.\n\n///\n\n### Use the form data { #use-the-form-data }\n\n/// tip\n\nThe instance of the dependency class `OAuth2PasswordRequestForm` won't have an attribute `scope` with the long string separated by spaces, instead, it will have a `scopes` attribute with the actual list of strings for each scope sent.\n\nWe are not using `scopes` in this example, but the functionality is there if you need it.\n\n///\n\nNow, get the user data from the (fake) database, using the `username` from the form field.\n\nIf there is no such user, we return an error saying \"Incorrect username or password\".\n\nFor the error, we use the exception `HTTPException`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### Check the password { #check-the-password }\n\nAt this point we have the user data from our database, but we haven't checked the password.\n\nLet's put that data in the Pydantic `UserInDB` model first.\n\nYou should never save plaintext passwords, so, we'll use the (fake) password hashing system.\n\nIf the passwords don't match, we return the same error.\n\n#### Password hashing { #password-hashing }\n\n\"Hashing\" means: converting some content (a password in this case) into a sequence of bytes (just a string) that looks like gibberish.\n\nWhenever you pass exactly the same content (exactly the same password) you get exactly the same gibberish.\n\nBut you cannot convert from the gibberish back to the password.\n\n##### Why use password hashing { #why-use-password-hashing }\n\nIf your database is stolen, the thief won't have your users' plaintext passwords, only the hashes.\n\nSo, the thief won't be able to try to use those same passwords in another system (as many users use the same password everywhere, this would be dangerous).\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### About `**user_dict` { #about-user-dict }\n\n`UserInDB(**user_dict)` means:\n\n*Pass the keys and values of the `user_dict` directly as key-value arguments, equivalent to:*\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info\n\nFor a more complete explanation of `**user_dict` check back in [the documentation for **Extra Models**](../extra-models.md#about-user-in-dict).\n\n///\n\n## Return the token { #return-the-token }\n\nThe response of the `token` endpoint must be a JSON object.\n\nIt should have a `token_type`. In our case, as we are using \"Bearer\" tokens, the token type should be \"`bearer`\".\n\nAnd it should have an `access_token`, with a string containing our access token.\n\nFor this simple example, we are going to just be completely insecure and return the same `username` as the token.\n\n/// tip\n\nIn the next chapter, you will see a real secure implementation, with password hashing and <abbr title=\"JSON Web Tokens\">JWT</abbr> tokens.\n\nBut for now, let's focus on the specific details we need.\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip\n\nBy the spec, you should return a JSON with an `access_token` and a `token_type`, the same as in this example.\n\nThis is something that you have to do yourself in your code, and make sure you use those JSON keys.\n\nIt's almost the only thing that you have to remember to do correctly yourself, to be compliant with the specifications.\n\nFor the rest, **FastAPI** handles it for you.\n\n///\n\n## Update the dependencies { #update-the-dependencies }\n\nNow we are going to update our dependencies.\n\nWe want to get the `current_user` *only* if this user is active.\n\nSo, we create an additional dependency `get_current_active_user` that in turn uses `get_current_user` as a dependency.\n\nBoth of these dependencies will just return an HTTP error if the user doesn't exist, or if is inactive.\n\nSo, in our endpoint, we will only get a user if the user exists, was correctly authenticated, and is active:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info\n\nThe additional header `WWW-Authenticate` with value `Bearer` we are returning here is also part of the spec.\n\nAny HTTP (error) status code 401 \"UNAUTHORIZED\" is supposed to also return a `WWW-Authenticate` header.\n\nIn the case of bearer tokens (our case), the value of that header should be `Bearer`.\n\nYou can actually skip that extra header and it would still work.\n\nBut it's provided here to be compliant with the specifications.\n\nAlso, there might be tools that expect and use it (now or in the future) and that might be useful for you or your users, now or in the future.\n\nThat's the benefit of standards...\n\n///\n\n## See it in action { #see-it-in-action }\n\nOpen the interactive docs: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n### Authenticate { #authenticate }\n\nClick the \"Authorize\" button.\n\nUse the credentials:\n\nUser: `johndoe`\n\nPassword: `secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\nAfter authenticating in the system, you will see it like:\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### Get your own user data { #get-your-own-user-data }\n\nNow use the operation `GET` with the path `/users/me`.\n\nYou will get your user's data, like:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\nIf you click the lock icon and logout, and then try the same operation again, you will get an HTTP 401 error of:\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### Inactive user { #inactive-user }\n\nNow try with an inactive user, authenticate with:\n\nUser: `alice`\n\nPassword: `secret2`\n\nAnd try to use the operation `GET` with the path `/users/me`.\n\nYou will get an \"Inactive user\" error, like:\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## Recap { #recap }\n\nYou now have the tools to implement a complete security system based on `username` and `password` for your API.\n\nUsing these tools, you can make the security system compatible with any database and with any user or data model.\n\nThe only detail missing is that it is not actually \"secure\" yet.\n\nIn the next chapter you'll see how to use a secure password hashing library and <abbr title=\"JSON Web Tokens\">JWT</abbr> tokens.\n"
  },
  {
    "path": "docs/en/docs/tutorial/server-sent-events.md",
    "content": "# Server-Sent Events (SSE) { #server-sent-events-sse }\n\nYou can stream data to the client using **Server-Sent Events** (SSE).\n\nThis is similar to [Stream JSON Lines](stream-json-lines.md), but uses the `text/event-stream` format, which is supported natively by browsers with the [`EventSource` API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).\n\n/// info\n\nAdded in FastAPI 0.135.0.\n\n///\n\n## What are Server-Sent Events? { #what-are-server-sent-events }\n\nSSE is a standard for streaming data from the server to the client over HTTP.\n\nEach event is a small text block with \"fields\" like `data`, `event`, `id`, and `retry`, separated by blank lines.\n\nIt looks like this:\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE is commonly used for AI chat streaming, live notifications, logs and observability, and other cases where the server pushes updates to the client.\n\n/// tip\n\nIf you want to stream binary data, for example video or audio, check the advanced guide: [Stream Data](../advanced/stream-data.md).\n\n///\n\n## Stream SSE with FastAPI { #stream-sse-with-fastapi }\n\nTo stream SSE with FastAPI, use `yield` in your *path operation function* and set `response_class=EventSourceResponse`.\n\nImport `EventSourceResponse` from `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\nEach yielded item is encoded as JSON and sent in the `data:` field of an SSE event.\n\nIf you declare the return type as `AsyncIterable[Item]`, FastAPI will use it to **validate**, **document**, and **serialize** the data using Pydantic.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip\n\nAs Pydantic will serialize it in the **Rust** side, you will get much higher **performance** than if you don't declare a return type.\n\n///\n\n### Non-async *path operation functions* { #non-async-path-operation-functions }\n\nYou can also use regular `def` functions (without `async`), and use `yield` the same way.\n\nFastAPI will make sure it's run correctly so that it doesn't block the event loop.\n\nAs in this case the function is not async, the right return type would be `Iterable[Item]`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### No Return Type { #no-return-type }\n\nYou can also omit the return type. FastAPI will use the [`jsonable_encoder`](./encoder.md) to convert the data and send it.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\nIf you need to set SSE fields like `event`, `id`, `retry`, or `comment`, you can yield `ServerSentEvent` objects instead of plain data.\n\nImport `ServerSentEvent` from `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\nThe `data` field is always encoded as JSON. You can pass any value that can be serialized as JSON, including Pydantic models.\n\n## Raw Data { #raw-data }\n\nIf you need to send data **without** JSON encoding, use `raw_data` instead of `data`.\n\nThis is useful for sending pre-formatted text, log lines, or special <dfn title=\"A value used to indicate a special condition or state\">\"sentinel\"</dfn> values like `[DONE]`.\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note\n\n`data` and `raw_data` are mutually exclusive. You can only set one of them on each `ServerSentEvent`.\n\n///\n\n## Resuming with `Last-Event-ID` { #resuming-with-last-event-id }\n\nWhen a browser reconnects after a connection drop, it sends the last received `id` in the `Last-Event-ID` header.\n\nYou can read it as a header parameter and use it to resume the stream from where the client left off:\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## SSE with POST { #sse-with-post }\n\nSSE works with **any HTTP method**, not just `GET`.\n\nThis is useful for protocols like [MCP](https://modelcontextprotocol.io) that stream SSE over `POST`:\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## Technical Details { #technical-details }\n\nFastAPI implements some SSE best practices out of the box.\n\n* Send a **\"keep alive\" `ping` comment** every 15 seconds when there hasn't been any message, to prevent some proxies from closing the connection, as suggested in the [HTML specification: Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes).\n* Set the `Cache-Control: no-cache` header to **prevent caching** of the stream.\n* Set a special header `X-Accel-Buffering: no` to **prevent buffering** in some proxies like Nginx.\n\nYou don't have to do anything about it, it works out of the box. 🤓\n"
  },
  {
    "path": "docs/en/docs/tutorial/sql-databases.md",
    "content": "# SQL (Relational) Databases { #sql-relational-databases }\n\n**FastAPI** doesn't require you to use a SQL (relational) database. But you can use **any database** that you want.\n\nHere we'll see an example using [SQLModel](https://sqlmodel.tiangolo.com/).\n\n**SQLModel** is built on top of [SQLAlchemy](https://www.sqlalchemy.org/) and Pydantic. It was made by the same author of **FastAPI** to be the perfect match for FastAPI applications that need to use **SQL databases**.\n\n/// tip\n\nYou could use any other SQL or NoSQL database library you want (in some cases called <abbr title=\"Object Relational Mapper: a fancy term for a library where some classes represent SQL tables and instances represent rows in those tables\">\"ORMs\"</abbr>), FastAPI doesn't force you to use anything. 😎\n\n///\n\nAs SQLModel is based on SQLAlchemy, you can easily use **any database supported** by SQLAlchemy (which makes them also supported by SQLModel), like:\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server, etc.\n\nIn this example, we'll use **SQLite**, because it uses a single file and Python has integrated support. So, you can copy this example and run it as is.\n\nLater, for your production application, you might want to use a database server like **PostgreSQL**.\n\n/// tip\n\nThere is an official project generator with **FastAPI** and **PostgreSQL** including a frontend and more tools: [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\nThis is a very simple and short tutorial, if you want to learn about databases in general, about SQL, or more advanced features, go to the [SQLModel docs](https://sqlmodel.tiangolo.com/).\n\n## Install `SQLModel` { #install-sqlmodel }\n\nFirst, make sure you create your [virtual environment](../virtual-environments.md), activate it, and then install `sqlmodel`:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## Create the App with a Single Model { #create-the-app-with-a-single-model }\n\nWe'll create the simplest first version of the app with a single **SQLModel** model first.\n\nLater we'll improve it increasing security and versatility with **multiple models** below. 🤓\n\n### Create Models { #create-models }\n\nImport `SQLModel` and create a database model:\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\nThe `Hero` class is very similar to a Pydantic model (in fact, underneath, it actually *is a Pydantic model*).\n\nThere are a few differences:\n\n* `table=True` tells SQLModel that this is a *table model*, it should represent a **table** in the SQL database, it's not just a *data model* (as would be any other regular Pydantic class).\n\n* `Field(primary_key=True)` tells SQLModel that the `id` is the **primary key** in the SQL database (you can learn more about SQL primary keys in the SQLModel docs).\n\n    **Note:** We use `int | None` for the primary key field so that in Python code we can *create an object without an `id`* (`id=None`), assuming the database will *generate it when saving*. SQLModel understands that the database will provide the `id` and *defines the column as a non-null `INTEGER`* in the database schema. See [SQLModel docs on primary keys](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) for details.\n\n* `Field(index=True)` tells SQLModel that it should create a **SQL index** for this column, that would allow faster lookups in the database when reading data filtered by this column.\n\n    SQLModel will know that something declared as `str` will be a SQL column of type `TEXT` (or `VARCHAR`, depending on the database).\n\n### Create an Engine { #create-an-engine }\n\nA SQLModel `engine` (underneath it's actually a SQLAlchemy `engine`) is what **holds the connections** to the database.\n\nYou would have **one single `engine` object** for all your code to connect to the same database.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\nUsing `check_same_thread=False` allows FastAPI to use the same SQLite database in different threads. This is necessary as **one single request** could use **more than one thread** (for example in dependencies).\n\nDon't worry, with the way the code is structured, we'll make sure we use **a single SQLModel *session* per request** later, this is actually what the `check_same_thread` is trying to achieve.\n\n### Create the Tables { #create-the-tables }\n\nWe then add a function that uses `SQLModel.metadata.create_all(engine)` to **create the tables** for all the *table models*.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### Create a Session Dependency { #create-a-session-dependency }\n\nA **`Session`** is what stores the **objects in memory** and keeps track of any changes needed in the data, then it **uses the `engine`** to communicate with the database.\n\nWe will create a FastAPI **dependency** with `yield` that will provide a new `Session` for each request. This is what ensures that we use a single session per request. 🤓\n\nThen we create an `Annotated` dependency `SessionDep` to simplify the rest of the code that will use this dependency.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### Create Database Tables on Startup { #create-database-tables-on-startup }\n\nWe will create the database tables when the application starts.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\nHere we create the tables on an application startup event.\n\nFor production you would probably use a migration script that runs before you start your app. 🤓\n\n/// tip\n\nSQLModel will have migration utilities wrapping Alembic, but for now, you can use [Alembic](https://alembic.sqlalchemy.org/en/latest/) directly.\n\n///\n\n### Create a Hero { #create-a-hero }\n\nBecause each SQLModel model is also a Pydantic model, you can use it in the same **type annotations** that you could use Pydantic models.\n\nFor example, if you declare a parameter of type `Hero`, it will be read from the **JSON body**.\n\nThe same way, you can declare it as the function's **return type**, and then the shape of the data will show up in the automatic API docs UI.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\nHere we use the `SessionDep` dependency (a `Session`) to add the new `Hero` to the `Session` instance, commit the changes to the database, refresh the data in the `hero`, and then return it.\n\n### Read Heroes { #read-heroes }\n\nWe can **read** `Hero`s from the database using a `select()`. We can include a `limit` and `offset` to paginate the results.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### Read One Hero { #read-one-hero }\n\nWe can **read** a single `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### Delete a Hero { #delete-a-hero }\n\nWe can also **delete** a `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### Run the App { #run-the-app }\n\nYou can run the app:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nThen go to the `/docs` UI, you will see that **FastAPI** is using these **models** to **document** the API, and it will use them to **serialize** and **validate** the data too.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## Update the App with Multiple Models { #update-the-app-with-multiple-models }\n\nNow let's **refactor** this app a bit to increase **security** and **versatility**.\n\nIf you check the previous app, in the UI you can see that, up to now, it lets the client decide the `id` of the `Hero` to create. 😱\n\nWe shouldn't let that happen, they could overwrite an `id` we already have assigned in the DB. Deciding the `id` should be done by the **backend** or the **database**, **not by the client**.\n\nAdditionally, we create a `secret_name` for the hero, but so far, we are returning it everywhere, that's not very **secret**... 😅\n\nWe'll fix these things by adding a few **extra models**. Here's where SQLModel will shine. ✨\n\n### Create Multiple Models { #create-multiple-models }\n\nIn **SQLModel**, any model class that has `table=True` is a **table model**.\n\nAnd any model class that doesn't have `table=True` is a **data model**, these ones are actually just Pydantic models (with a couple of small extra features). 🤓\n\nWith SQLModel, we can use **inheritance** to **avoid duplicating** all the fields in all the cases.\n\n#### `HeroBase` - the base class { #herobase-the-base-class }\n\nLet's start with a `HeroBase` model that has all the **fields that are shared** by all the models:\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` - the *table model* { #hero-the-table-model }\n\nThen let's create `Hero`, the actual *table model*, with the **extra fields** that are not always in the other models:\n\n* `id`\n* `secret_name`\n\nBecause `Hero` inherits form `HeroBase`, it **also** has the **fields** declared in `HeroBase`, so all the fields for `Hero` are:\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` - the public *data model* { #heropublic-the-public-data-model }\n\nNext, we create a `HeroPublic` model, this is the one that will be **returned** to the clients of the API.\n\nIt has the same fields as `HeroBase`, so it won't include `secret_name`.\n\nFinally, the identity of our heroes is protected! 🥷\n\nIt also re-declares `id: int`. By doing this, we are making a **contract** with the API clients, so that they can always expect the `id` to be there and to be an `int` (it will never be `None`).\n\n/// tip\n\nHaving the return model ensure that a value is always available and always `int` (not `None`) is very useful for the API clients, they can write much simpler code having this certainty.\n\nAlso, **automatically generated clients** will have simpler interfaces, so that the developers communicating with your API can have a much better time working with your API. 😎\n\n///\n\nAll the fields in `HeroPublic` are the same as in `HeroBase`, with `id` declared as `int` (not `None`):\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` - the *data model* to create a hero { #herocreate-the-data-model-to-create-a-hero }\n\nNow we create a `HeroCreate` model, this is the one that will **validate** the data from the clients.\n\nIt has the same fields as `HeroBase`, and it also has `secret_name`.\n\nNow, when the clients **create a new hero**, they will send the `secret_name`, it will be stored in the database, but those secret names won't be returned in the API to the clients.\n\n/// tip\n\nThis is how you would handle **passwords**. Receive them, but don't return them in the API.\n\nYou would also **hash** the values of the passwords before storing them, **never store them in plain text**.\n\n///\n\nThe fields of `HeroCreate` are:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` - the *data model* to update a hero { #heroupdate-the-data-model-to-update-a-hero }\n\nWe didn't have a way to **update a hero** in the previous version of the app, but now with **multiple models**, we can do it. 🎉\n\nThe `HeroUpdate` *data model* is somewhat special, it has **all the same fields** that would be needed to create a new hero, but all the fields are **optional** (they all have a default value). This way, when you update a hero, you can send just the fields that you want to update.\n\nBecause all the **fields actually change** (the type now includes `None` and they now have a default value of `None`), we need to **re-declare** them.\n\nWe don't really need to inherit from `HeroBase` because we are re-declaring all the fields. I'll leave it inheriting just for consistency, but this is not necessary. It's more a matter of personal taste. 🤷\n\nThe fields of `HeroUpdate` are:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### Create with `HeroCreate` and return a `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }\n\nNow that we have **multiple models**, we can update the parts of the app that use them.\n\nWe receive in the request a `HeroCreate` *data model*, and from it, we create a `Hero` *table model*.\n\nThis new *table model* `Hero` will have the fields sent by the client, and will also have an `id` generated by the database.\n\nThen we return the same *table model* `Hero` as is from the function. But as we declare the `response_model` with the `HeroPublic` *data model*, **FastAPI** will use `HeroPublic` to validate and serialize the data.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip\n\nNow we use `response_model=HeroPublic` instead of the **return type annotation** `-> HeroPublic` because the value that we are returning is actually *not* a `HeroPublic`.\n\nIf we had declared `-> HeroPublic`, your editor and linter would complain (rightfully so) that you are returning a `Hero` instead of a `HeroPublic`.\n\nBy declaring it in `response_model` we are telling **FastAPI** to do its thing, without interfering with the type annotations and the help from your editor and other tools.\n\n///\n\n### Read Heroes with `HeroPublic` { #read-heroes-with-heropublic }\n\nWe can do the same as before to **read** `Hero`s, again, we use `response_model=list[HeroPublic]` to ensure that the data is validated and serialized correctly.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### Read One Hero with `HeroPublic` { #read-one-hero-with-heropublic }\n\nWe can **read** a single hero:\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### Update a Hero with `HeroUpdate` { #update-a-hero-with-heroupdate }\n\nWe can **update a hero**. For this we use an HTTP `PATCH` operation.\n\nAnd in the code, we get a `dict` with all the data sent by the client, **only the data sent by the client**, excluding any values that would be there just for being the default values. To do it we use `exclude_unset=True`. This is the main trick. 🪄\n\nThen we use `hero_db.sqlmodel_update(hero_data)` to update the `hero_db` with the data from `hero_data`.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### Delete a Hero Again { #delete-a-hero-again }\n\n**Deleting** a hero stays pretty much the same.\n\nWe won't satisfy the desire to refactor everything in this one. 😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### Run the App Again { #run-the-app-again }\n\nYou can run the app again:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nIf you go to the `/docs` API UI, you will see that it is now updated, and it won't expect to receive the `id` from the client when creating a hero, etc.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## Recap { #recap }\n\nYou can use [**SQLModel**](https://sqlmodel.tiangolo.com/) to interact with a SQL database and simplify the code with *data models*  and *table models*.\n\nYou can learn a lot more at the **SQLModel** docs, there's a longer mini [tutorial on using SQLModel with **FastAPI**](https://sqlmodel.tiangolo.com/tutorial/fastapi/). 🚀\n"
  },
  {
    "path": "docs/en/docs/tutorial/static-files.md",
    "content": "# Static Files { #static-files }\n\nYou can serve static files automatically from a directory using `StaticFiles`.\n\n## Use `StaticFiles` { #use-staticfiles }\n\n* Import `StaticFiles`.\n* \"Mount\" a `StaticFiles()` instance in a specific path.\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | Technical Details\n\nYou could also use `from starlette.staticfiles import StaticFiles`.\n\n**FastAPI** provides the same `starlette.staticfiles` as `fastapi.staticfiles` just as a convenience for you, the developer. But it actually comes directly from Starlette.\n\n///\n\n### What is \"Mounting\" { #what-is-mounting }\n\n\"Mounting\" means adding a complete \"independent\" application in a specific path, that then takes care of handling all the sub-paths.\n\nThis is different from using an `APIRouter` as a mounted application is completely independent. The OpenAPI and docs from your main application won't include anything from the mounted application, etc.\n\nYou can read more about this in the [Advanced User Guide](../advanced/index.md).\n\n## Details { #details }\n\nThe first `\"/static\"` refers to the sub-path this \"sub-application\" will be \"mounted\" on. So, any path that starts with `\"/static\"` will be handled by it.\n\nThe `directory=\"static\"` refers to the name of the directory that contains your static files.\n\nThe `name=\"static\"` gives it a name that can be used internally by **FastAPI**.\n\nAll these parameters can be different than \"`static`\", adjust them with the needs and specific details of your own application.\n\n## More info { #more-info }\n\nFor more details and options check [Starlette's docs about Static Files](https://www.starlette.dev/staticfiles/).\n"
  },
  {
    "path": "docs/en/docs/tutorial/stream-json-lines.md",
    "content": "# Stream JSON Lines { #stream-json-lines }\n\nYou could have a sequence of data that you would like to send in a \"**stream**\", you could do it with **JSON Lines**.\n\n/// info\n\nAdded in FastAPI 0.134.0.\n\n///\n\n## What is a Stream? { #what-is-a-stream }\n\n\"**Streaming**\" data means that your app will start sending data items to the client without waiting for the entire sequence of items to be ready.\n\nSo, it will send the first item, the client will receive and start processing it, and you might still be producing the next item.\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\nIt could even be an infinite stream, where you keep sending data.\n\n## JSON Lines { #json-lines }\n\nIn these cases, it's common to send \"**JSON Lines**\", which is a format where you send one JSON object per line.\n\nA response would have a content type of `application/jsonl` (instead of `application/json`) and the body would be something like:\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\nIt's very similar to a JSON array (equivalent of a Python list), but instead of being wrapped in `[]` and having `,` between the items, it has **one JSON object per line**, they are separated by a new line character.\n\n/// info\n\nThe important point is that your app will be able to produce each line in turn, while the client consumes the previous lines.\n\n///\n\n/// note | Technical Details\n\nBecause each JSON object will be separated by a new line, they can't contain literal new line characters in their content, but they can contain escaped new lines (`\\n`), which is part of the JSON standard.\n\nBut normally you won't have to worry about it, it's done automatically, continue reading. 🤓\n\n///\n\n## Use Cases { #use-cases }\n\nYou could use this to stream data from an **AI LLM** service, from **logs** or **telemetry**, or from other types of data that can be structured in **JSON** items.\n\n/// tip\n\nIf you want to stream binary data, for example video or audio, check the advanced guide: [Stream Data](../advanced/stream-data.md).\n\n///\n\n## Stream JSON Lines with FastAPI { #stream-json-lines-with-fastapi }\n\nTo stream JSON Lines with FastAPI you can, instead of using `return` in your *path operation function*, use `yield` to produce each item in turn.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\nIf each JSON item you want to send back is of type `Item` (a Pydantic model) and it's an async function, you can declare the return type as `AsyncIterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\nIf you declare the return type, FastAPI will use it to **validate** the data, **document** it in OpenAPI, **filter** it, and **serialize** it using Pydantic.\n\n/// tip\n\nAs Pydantic will serialize it in the **Rust** side, you will get much higher **performance** than if you don't declare a return type.\n\n///\n\n### Non-async *path operation functions* { #non-async-path-operation-functions }\n\nYou can also use regular `def` functions (without `async`), and use `yield` the same way.\n\nFastAPI will make sure it's run correctly so that it doesn't block the event loop.\n\nAs in this case the function is not async, the right return type would be `Iterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### No Return Type { #no-return-type }\n\nYou can also omit the return type. FastAPI will then use the [`jsonable_encoder`](./encoder.md) to convert the data to something that can be serialized to JSON and then send it as JSON Lines.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## Server-Sent Events (SSE) { #server-sent-events-sse }\n\nFastAPI also has first-class support for Server-Sent Events (SSE), which are quite similar but with a couple of extra details. You can learn about them in the next chapter: [Server-Sent Events (SSE)](server-sent-events.md). 🤓\n"
  },
  {
    "path": "docs/en/docs/tutorial/testing.md",
    "content": "# Testing { #testing }\n\nThanks to [Starlette](https://www.starlette.dev/testclient/), testing **FastAPI** applications is easy and enjoyable.\n\nIt is based on [HTTPX](https://www.python-httpx.org), which in turn is designed based on Requests, so it's very familiar and intuitive.\n\nWith it, you can use [pytest](https://docs.pytest.org/) directly with **FastAPI**.\n\n## Using `TestClient` { #using-testclient }\n\n/// info\n\nTo use `TestClient`, first install [`httpx`](https://www.python-httpx.org).\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and then install it, for example:\n\n```console\n$ pip install httpx\n```\n\n///\n\nImport `TestClient`.\n\nCreate a `TestClient` by passing your **FastAPI** application to it.\n\nCreate functions with a name that starts with `test_` (this is standard `pytest` conventions).\n\nUse the `TestClient` object the same way as you do with `httpx`.\n\nWrite simple `assert` statements with the standard Python expressions that you need to check (again, standard `pytest`).\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip\n\nNotice that the testing functions are normal `def`, not `async def`.\n\nAnd the calls to the client are also normal calls, not using `await`.\n\nThis allows you to use `pytest` directly without complications.\n\n///\n\n/// note | Technical Details\n\nYou could also use `from starlette.testclient import TestClient`.\n\n**FastAPI** provides the same `starlette.testclient` as `fastapi.testclient` just as a convenience for you, the developer. But it comes directly from Starlette.\n\n///\n\n/// tip\n\nIf you want to call `async` functions in your tests apart from sending requests to your FastAPI application (e.g. asynchronous database functions), have a look at the [Async Tests](../advanced/async-tests.md) in the advanced tutorial.\n\n///\n\n## Separating tests { #separating-tests }\n\nIn a real application, you probably would have your tests in a different file.\n\nAnd your **FastAPI** application might also be composed of several files/modules, etc.\n\n### **FastAPI** app file { #fastapi-app-file }\n\nLet's say you have a file structure as described in [Bigger Applications](bigger-applications.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\nIn the file `main.py` you have your **FastAPI** app:\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### Testing file { #testing-file }\n\nThen you could have a file `test_main.py` with your tests. It could live on the same Python package (the same directory with a `__init__.py` file):\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nBecause this file is in the same package, you can use relative imports to import the object `app` from the `main` module (`main.py`):\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n\n...and have the code for the tests just like before.\n\n## Testing: extended example { #testing-extended-example }\n\nNow let's extend this example and add more details to see how to test different parts.\n\n### Extended **FastAPI** app file { #extended-fastapi-app-file }\n\nLet's continue with the same file structure as before:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nLet's say that now the file `main.py` with your **FastAPI** app has some other **path operations**.\n\nIt has a `GET` operation that could return an error.\n\nIt has a `POST` operation that could return several errors.\n\nBoth *path operations* require an `X-Token` header.\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### Extended testing file { #extended-testing-file }\n\nYou could then update `test_main.py` with the extended tests:\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\n\nWhenever you need the client to pass information in the request and you don't know how to, you can search (Google) how to do it in `httpx`, or even how to do it with `requests`, as HTTPX's design is based on Requests' design.\n\nThen you just do the same in your tests.\n\nE.g.:\n\n* To pass a *path* or *query* parameter, add it to the URL itself.\n* To pass a JSON body, pass a Python object (e.g. a `dict`) to the parameter `json`.\n* If you need to send *Form Data* instead of JSON, use the `data` parameter instead.\n* To pass *headers*, use a `dict` in the `headers` parameter.\n* For *cookies*, a `dict` in the `cookies` parameter.\n\nFor more information about how to pass data to the backend (using `httpx` or the `TestClient`) check the [HTTPX documentation](https://www.python-httpx.org).\n\n/// info\n\nNote that the `TestClient` receives data that can be converted to JSON, not Pydantic models.\n\nIf you have a Pydantic model in your test and you want to send its data to the application during testing, you can use the `jsonable_encoder` described in [JSON Compatible Encoder](encoder.md).\n\n///\n\n## Run it { #run-it }\n\nAfter that, you just need to install `pytest`.\n\nMake sure you create a [virtual environment](../virtual-environments.md), activate it, and then install it, for example:\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\nIt will detect the files and tests automatically, execute them, and report the results back to you.\n\nRun the tests with:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/en/docs/virtual-environments.md",
    "content": "# Virtual Environments { #virtual-environments }\n\nWhen you work in Python projects you probably should use a **virtual environment** (or a similar mechanism) to isolate the packages you install for each project.\n\n/// info\n\nIf you already know about virtual environments, how to create them and use them, you might want to skip this section. 🤓\n\n///\n\n/// tip\n\nA **virtual environment** is different than an **environment variable**.\n\nAn **environment variable** is a variable in the system that can be used by programs.\n\nA **virtual environment** is a directory with some files in it.\n\n///\n\n/// info\n\nThis page will teach you how to use **virtual environments** and how they work.\n\nIf you are ready to adopt a **tool that manages everything** for you (including installing Python), try [uv](https://github.com/astral-sh/uv).\n\n///\n\n## Create a Project { #create-a-project }\n\nFirst, create a directory for your project.\n\nWhat I normally do is that I create a directory named `code` inside my home/user directory.\n\nAnd inside of that I create one directory per project.\n\n<div class=\"termy\">\n\n```console\n// Go to the home directory\n$ cd\n// Create a directory for all your code projects\n$ mkdir code\n// Enter into that code directory\n$ cd code\n// Create a directory for this project\n$ mkdir awesome-project\n// Enter into that project directory\n$ cd awesome-project\n```\n\n</div>\n\n## Create a Virtual Environment { #create-a-virtual-environment }\n\nWhen you start working on a Python project **for the first time**, create a virtual environment **<dfn title=\"there are other options, this is a simple guideline\">inside your project</dfn>**.\n\n/// tip\n\nYou only need to do this **once per project**, not every time you work.\n\n///\n\n//// tab | `venv`\n\nTo create a virtual environment, you can use the `venv` module that comes with Python.\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | What that command means\n\n* `python`: use the program called `python`\n* `-m`: call a module as a script, we'll tell it which module next\n* `venv`: use the module called `venv` that normally comes installed with Python\n* `.venv`: create the virtual environment in the new directory `.venv`\n\n///\n\n////\n\n//// tab | `uv`\n\nIf you have [`uv`](https://github.com/astral-sh/uv) installed, you can use it to create a virtual environment.\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip\n\nBy default, `uv` will create a virtual environment in a directory called `.venv`.\n\nBut you could customize it passing an additional argument with the directory name.\n\n///\n\n////\n\nThat command creates a new virtual environment in a directory called `.venv`.\n\n/// details | `.venv` or other name\n\nYou could create the virtual environment in a different directory, but there's a convention of calling it `.venv`.\n\n///\n\n## Activate the Virtual Environment { #activate-the-virtual-environment }\n\nActivate the new virtual environment so that any Python command you run or package you install uses it.\n\n/// tip\n\nDo this **every time** you start a **new terminal session** to work on the project.\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nOr if you use Bash for Windows (e.g. [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip\n\nEvery time you install a **new package** in that environment, **activate** the environment again.\n\nThis makes sure that if you use a **terminal (<abbr title=\"command line interface\">CLI</abbr>) program** installed by that package, you use the one from your virtual environment and not any other that could be installed globally, probably with a different version than what you need.\n\n///\n\n## Check the Virtual Environment is Active { #check-the-virtual-environment-is-active }\n\nCheck that the virtual environment is active (the previous command worked).\n\n/// tip\n\nThis is **optional**, but it's a good way to **check** that everything is working as expected and you are using the virtual environment you intended.\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\nIf it shows the `python` binary at `.venv/bin/python`, inside of your project (in this case `awesome-project`), then it worked. 🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\nIf it shows the `python` binary at `.venv\\Scripts\\python`, inside of your project (in this case `awesome-project`), then it worked. 🎉\n\n////\n\n## Upgrade `pip` { #upgrade-pip }\n\n/// tip\n\nIf you use [`uv`](https://github.com/astral-sh/uv) you would use it to install things instead of `pip`, so you don't need to upgrade `pip`. 😎\n\n///\n\nIf you are using `pip` to install packages (it comes by default with Python), you should **upgrade** it to the latest version.\n\nMany exotic errors while installing a package are solved by just upgrading `pip` first.\n\n/// tip\n\nYou would normally do this **once**, right after you create the virtual environment.\n\n///\n\nMake sure the virtual environment is active (with the command above) and then run:\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip\n\nSometimes, you might get a **`No module named pip`** error when trying to upgrade pip.\n\nIf this happens, install and upgrade pip using the command below:\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\nThis command will install pip if it is not already installed and also ensures that the installed version of pip is at least as recent as the one available in `ensurepip`.\n\n///\n\n## Add `.gitignore` { #add-gitignore }\n\nIf you are using **Git** (you should), add a `.gitignore` file to exclude everything in your `.venv` from Git.\n\n/// tip\n\nIf you used [`uv`](https://github.com/astral-sh/uv) to create the virtual environment, it already did this for you, you can skip this step. 😎\n\n///\n\n/// tip\n\nDo this **once**, right after you create the virtual environment.\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | What that command means\n\n* `echo \"*\"`: will \"print\" the text `*` in the terminal (the next part changes that a bit)\n* `>`: anything printed to the terminal by the command to the left of `>` should not be printed but instead written to the file that goes to the right of `>`\n* `.gitignore`: the name of the file where the text should be written\n\nAnd `*` for Git means \"everything\". So, it will ignore everything in the `.venv` directory.\n\nThat command will create a file `.gitignore` with the content:\n\n```gitignore\n*\n```\n\n///\n\n## Install Packages { #install-packages }\n\nAfter activating the environment, you can install packages in it.\n\n/// tip\n\nDo this **once** when installing or upgrading the packages your project needs.\n\nIf you need to upgrade a version or add a new package you would **do this again**.\n\n///\n\n### Install Packages Directly { #install-packages-directly }\n\nIf you're in a hurry and don't want to use a file to declare your project's package requirements, you can install them directly.\n\n/// tip\n\nIt's a (very) good idea to put the packages and versions your program needs in a file (for example `requirements.txt` or `pyproject.toml`).\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nIf you have [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### Install from `requirements.txt` { #install-from-requirements-txt }\n\nIf you have a `requirements.txt`, you can now use it to install its packages.\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nIf you have [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\nA `requirements.txt` with some packages could look like:\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## Run Your Program { #run-your-program }\n\nAfter you activated the virtual environment, you can run your program, and it will use the Python inside of your virtual environment with the packages you installed there.\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## Configure Your Editor { #configure-your-editor }\n\nYou would probably use an editor, make sure you configure it to use the same virtual environment you created (it will probably autodetect it) so that you can get autocompletion and inline errors.\n\nFor example:\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip\n\nYou normally have to do this only **once**, when you create the virtual environment.\n\n///\n\n## Deactivate the Virtual Environment { #deactivate-the-virtual-environment }\n\nOnce you are done working on your project you can **deactivate** the virtual environment.\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\nThis way, when you run `python` it won't try to run it from that virtual environment with the packages installed there.\n\n## Ready to Work { #ready-to-work }\n\nNow you're ready to start working on your project.\n\n\n\n/// tip\n\nDo you want to understand what's all that above?\n\nContinue reading. 👇🤓\n\n///\n\n## Why Virtual Environments { #why-virtual-environments }\n\nTo work with FastAPI you need to install [Python](https://www.python.org/).\n\nAfter that, you would need to **install** FastAPI and any other **packages** you want to use.\n\nTo install packages you would normally use the `pip` command that comes with Python (or similar alternatives).\n\nNevertheless, if you just use `pip` directly, the packages would be installed in your **global Python environment** (the global installation of Python).\n\n### The Problem { #the-problem }\n\nSo, what's the problem with installing packages in the global Python environment?\n\nAt some point, you will probably end up writing many different programs that depend on **different packages**. And some of these projects you work on will depend on **different versions** of the same package. 😱\n\nFor example, you could create a project called `philosophers-stone`, this program depends on another package called **`harry`, using the version `1`**. So, you need to install `harry`.\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n\nThen, at some point later, you create another project called `prisoner-of-azkaban`, and this project also depends on `harry`, but this project needs **`harry` version `3`**.\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]\n```\n\nBut now the problem is, if you install the packages globally (in the global environment) instead of in a local **virtual environment**, you will have to choose which version of `harry` to install.\n\nIf you want to run `philosophers-stone` you will need to first install `harry` version `1`, for example with:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\nAnd then you would end up with `harry` version `1` installed in your global Python environment.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\nBut then if you want to run `prisoner-of-azkaban`, you will need to uninstall `harry` version `1` and install `harry` version `3` (or just installing version `3` would automatically uninstall version `1`).\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\nAnd then you would end up with `harry` version `3` installed in your global Python environment.\n\nAnd if you try to run `philosophers-stone` again, there's a chance it would **not work** because it needs `harry` version `1`.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --> |requires| harry-3\n    end\n```\n\n/// tip\n\nIt's very common in Python packages to try the best to **avoid breaking changes** in **new versions**, but it's better to be safe, and install newer versions intentionally and when you can run the tests to check everything is working correctly.\n\n///\n\nNow, imagine that with **many** other **packages** that all your **projects depend on**. That's very difficult to manage. And you would probably end up running some projects with some **incompatible versions** of the packages, and not knowing why something isn't working.\n\nAlso, depending on your operating system (e.g. Linux, Windows, macOS), it could have come with Python already installed. And in that case it probably had some packages pre-installed with some specific versions **needed by your system**. If you install packages in the global Python environment, you could end up **breaking** some of the programs that came with your operating system.\n\n## Where are Packages Installed { #where-are-packages-installed }\n\nWhen you install Python, it creates some directories with some files in your computer.\n\nSome of these directories are the ones in charge of having all the packages you install.\n\nWhen you run:\n\n<div class=\"termy\">\n\n```console\n// Don't run this now, it's just an example 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\nThat will download a compressed file with the FastAPI code, normally from [PyPI](https://pypi.org/project/fastapi/).\n\nIt will also **download** files for other packages that FastAPI depends on.\n\nThen it will **extract** all those files and put them in a directory in your computer.\n\nBy default, it will put those files downloaded and extracted in the directory that comes with your Python installation, that's the **global environment**.\n\n## What are Virtual Environments { #what-are-virtual-environments }\n\nThe solution to the problems of having all the packages in the global environment is to use a **virtual environment for each project** you work on.\n\nA virtual environment is a **directory**, very similar to the global one, where you can install the packages for a project.\n\nThis way, each project will have its own virtual environment (`.venv` directory) with its own packages.\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) --->|requires| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --->|requires| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## What Does Activating a Virtual Environment Mean { #what-does-activating-a-virtual-environment-mean }\n\nWhen you activate a virtual environment, for example with:\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nOr if you use Bash for Windows (e.g. [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\nThat command will create or modify some [environment variables](environment-variables.md) that will be available for the next commands.\n\nOne of those variables is the `PATH` variable.\n\n/// tip\n\nYou can learn more about the `PATH` environment variable in the [Environment Variables](environment-variables.md#path-environment-variable) section.\n\n///\n\nActivating a virtual environment adds its path `.venv/bin` (on Linux and macOS) or `.venv\\Scripts` (on Windows) to the `PATH` environment variable.\n\nLet's say that before activating the environment, the `PATH` variable looked like this:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nThat means that the system would look for programs in:\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\nThat means that the system would look for programs in:\n\n* `C:\\Windows\\System32`\n\n////\n\nAfter activating the virtual environment, the `PATH` variable would look something like this:\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nThat means that the system will now start looking first for programs in:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\nbefore looking in the other directories.\n\nSo, when you type `python` in the terminal, the system will find the Python program in\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\nand use that one.\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\nThat means that the system will now start looking first for programs in:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\nbefore looking in the other directories.\n\nSo, when you type `python` in the terminal, the system will find the Python program in\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\nand use that one.\n\n////\n\nAn important detail is that it will put the virtual environment path at the **beginning** of the `PATH` variable. The system will find it **before** finding any other Python available. This way, when you run `python`, it will use the Python **from the virtual environment** instead of any other `python` (for example, a `python` from a global environment).\n\nActivating a virtual environment also changes a couple of other things, but this is one of the most important things it does.\n\n## Checking a Virtual Environment { #checking-a-virtual-environment }\n\nWhen you check if a virtual environment is active, for example with:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\nThat means that the `python` program that will be used is the one **in the virtual environment**.\n\nYou use `which` in Linux and macOS and `Get-Command` in Windows PowerShell.\n\nThe way that command works is that it will go and check in the `PATH` environment variable, going through **each path in order**, looking for the program called `python`. Once it finds it, it will **show you the path** to that program.\n\nThe most important part is that when you call `python`, that is the exact \"`python`\" that will be executed.\n\nSo, you can confirm if you are in the correct virtual environment.\n\n/// tip\n\nIt's easy to activate one virtual environment, get one Python, and then **go to another project**.\n\nAnd the second project **wouldn't work** because you are using the **incorrect Python**, from a virtual environment for another project.\n\nIt's useful being able to check what `python` is being used. 🤓\n\n///\n\n## Why Deactivate a Virtual Environment { #why-deactivate-a-virtual-environment }\n\nFor example, you could be working on a project `philosophers-stone`, **activate that virtual environment**, install packages and work with that environment.\n\nAnd then you want to work on **another project** `prisoner-of-azkaban`.\n\nYou go to that project:\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\nIf you don't deactivate the virtual environment for `philosophers-stone`, when you run `python` in the terminal, it will try to use the Python from `philosophers-stone`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// Error importing sirius, it's not installed 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\nBut if you deactivate the virtual environment and activate the new one for `prisoner-of-azkaban` then when you run `python` it will use the Python from the virtual environment in `prisoner-of-azkaban`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// You don't need to be in the old directory to deactivate, you can do it wherever you are, even after going to the other project 😎\n$ deactivate\n\n// Activate the virtual environment in prisoner-of-azkaban/.venv 🚀\n$ source .venv/bin/activate\n\n// Now when you run python, it will find the package sirius installed in this virtual environment ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## Alternatives { #alternatives }\n\nThis is a simple guide to get you started and teach you how everything works **underneath**.\n\nThere are many **alternatives** to managing virtual environments, package dependencies (requirements), projects.\n\nOnce you are ready and want to use a tool to **manage the entire project**, packages dependencies, virtual environments, etc. I would suggest you try [uv](https://github.com/astral-sh/uv).\n\n`uv` can do a lot of things, it can:\n\n* **Install Python** for you, including different versions\n* Manage the **virtual environment** for your projects\n* Install **packages**\n* Manage package **dependencies and versions** for your project\n* Make sure you have an **exact** set of packages and versions to install, including their dependencies, so that you can be sure that you can run your project in production exactly the same as in your computer while developing, this is called **locking**\n* And many other things\n\n## Conclusion { #conclusion }\n\nIf you read and understood all this, now **you know much more** about virtual environments than many developers out there. 🤓\n\nKnowing these details will most probably be useful in a future time when you are debugging something that seems complex, but you will know **how it all works underneath**. 😎\n"
  },
  {
    "path": "docs/en/mkdocs.env.yml",
    "content": "# Define this here and not in the main mkdocs.yml file because that one is auto\n# updated and written, and the script would remove the env var\nmarkdown_extensions:\n  pymdownx.highlight:\n    linenums: !ENV [LINENUMS, false]\n"
  },
  {
    "path": "docs/en/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.env.yml\nsite_name: FastAPI\nsite_description: FastAPI framework, high performance, easy to learn, fast to code, ready for production\nsite_url: https://fastapi.tiangolo.com/\ntheme:\n  name: material\n  custom_dir: ../en/overrides\n  palette:\n  - media: (prefers-color-scheme)\n    toggle:\n      icon: material/lightbulb-auto\n      name: Switch to light mode\n  - media: '(prefers-color-scheme: light)'\n    scheme: default\n    primary: teal\n    accent: amber\n    toggle:\n      icon: material/lightbulb\n      name: Switch to dark mode\n  - media: '(prefers-color-scheme: dark)'\n    scheme: slate\n    primary: teal\n    accent: amber\n    toggle:\n      icon: material/lightbulb-outline\n      name: Switch to system preference\n  features:\n  - content.code.annotate\n  - content.code.copy\n  - content.footnote.tooltips\n  - content.tabs.link\n  - content.tooltips\n  - navigation.footer\n  - navigation.indexes\n  - navigation.instant\n  - navigation.instant.prefetch\n  - navigation.instant.progress\n  - navigation.path\n  - navigation.tabs\n  - navigation.tabs.sticky\n  - navigation.top\n  - navigation.tracking\n  - search.highlight\n  - search.share\n  - search.suggest\n  - toc.follow\n  icon:\n    repo: fontawesome/brands/github-alt\n  logo: img/icon-white.svg\n  favicon: img/favicon.png\n  language: en\nrepo_name: fastapi/fastapi\nrepo_url: https://github.com/fastapi/fastapi\nplugins:\n  social:\n    cards_layout_options:\n      logo: ../en/docs/img/icon-white.svg\n  typeset: null\n  search: null\n  macros:\n    include_yaml:\n    - github_sponsors: ../en/data/github_sponsors.yml\n    - people: ../en/data/people.yml\n    - contributors: ../en/data/contributors.yml\n    - translators: ../en/data/translators.yml\n    - translation_reviewers: ../en/data/translation_reviewers.yml\n    - skip_users: ../en/data/skip_users.yml\n    - members: ../en/data/members.yml\n    - sponsors_badge: ../en/data/sponsors_badge.yml\n    - sponsors: ../en/data/sponsors.yml\n    - topic_repos: ../en/data/topic_repos.yml\n  redirects:\n    redirect_maps:\n      deployment/deta.md: deployment/cloud.md\n      advanced/graphql.md: how-to/graphql.md\n      advanced/custom-request-and-route.md: how-to/custom-request-and-route.md\n      advanced/conditional-openapi.md: how-to/conditional-openapi.md\n      advanced/extending-openapi.md: how-to/extending-openapi.md\n      advanced/testing-database.md: how-to/testing-database.md\n  mkdocstrings:\n    handlers:\n      python:\n        options:\n          extensions:\n          - griffe_typingdoc\n          show_root_heading: true\n          show_if_no_docstring: true\n          preload_modules:\n          - httpx\n          - starlette\n          inherited_members: true\n          members_order: source\n          separate_signature: true\n          unwrap_annotated: true\n          filters:\n          - '!^_'\n          merge_init_into_class: true\n          docstring_section_style: spacy\n          signature_crossrefs: true\n          show_symbol_type_heading: true\n          show_symbol_type_toc: true\nnav:\n- FastAPI: index.md\n- features.md\n- Learn:\n  - learn/index.md\n  - python-types.md\n  - async.md\n  - environment-variables.md\n  - virtual-environments.md\n  - Tutorial - User Guide:\n    - tutorial/index.md\n    - tutorial/first-steps.md\n    - tutorial/path-params.md\n    - tutorial/query-params.md\n    - tutorial/body.md\n    - tutorial/query-params-str-validations.md\n    - tutorial/path-params-numeric-validations.md\n    - tutorial/query-param-models.md\n    - tutorial/body-multiple-params.md\n    - tutorial/body-fields.md\n    - tutorial/body-nested-models.md\n    - tutorial/schema-extra-example.md\n    - tutorial/extra-data-types.md\n    - tutorial/cookie-params.md\n    - tutorial/header-params.md\n    - tutorial/cookie-param-models.md\n    - tutorial/header-param-models.md\n    - tutorial/response-model.md\n    - tutorial/extra-models.md\n    - tutorial/response-status-code.md\n    - tutorial/request-forms.md\n    - tutorial/request-form-models.md\n    - tutorial/request-files.md\n    - tutorial/request-forms-and-files.md\n    - tutorial/handling-errors.md\n    - tutorial/path-operation-configuration.md\n    - tutorial/encoder.md\n    - tutorial/body-updates.md\n    - Dependencies:\n      - tutorial/dependencies/index.md\n      - tutorial/dependencies/classes-as-dependencies.md\n      - tutorial/dependencies/sub-dependencies.md\n      - tutorial/dependencies/dependencies-in-path-operation-decorators.md\n      - tutorial/dependencies/global-dependencies.md\n      - tutorial/dependencies/dependencies-with-yield.md\n    - Security:\n      - tutorial/security/index.md\n      - tutorial/security/first-steps.md\n      - tutorial/security/get-current-user.md\n      - tutorial/security/simple-oauth2.md\n      - tutorial/security/oauth2-jwt.md\n    - tutorial/middleware.md\n    - tutorial/cors.md\n    - tutorial/sql-databases.md\n    - tutorial/bigger-applications.md\n    - tutorial/stream-json-lines.md\n    - tutorial/server-sent-events.md\n    - tutorial/background-tasks.md\n    - tutorial/metadata.md\n    - tutorial/static-files.md\n    - tutorial/testing.md\n    - tutorial/debugging.md\n  - Advanced User Guide:\n    - advanced/index.md\n    - advanced/stream-data.md\n    - advanced/path-operation-advanced-configuration.md\n    - advanced/additional-status-codes.md\n    - advanced/response-directly.md\n    - advanced/custom-response.md\n    - advanced/additional-responses.md\n    - advanced/response-cookies.md\n    - advanced/response-headers.md\n    - advanced/response-change-status-code.md\n    - advanced/advanced-dependencies.md\n    - Advanced Security:\n      - advanced/security/index.md\n      - advanced/security/oauth2-scopes.md\n      - advanced/security/http-basic-auth.md\n    - advanced/using-request-directly.md\n    - advanced/dataclasses.md\n    - advanced/middleware.md\n    - advanced/sub-applications.md\n    - advanced/behind-a-proxy.md\n    - advanced/templates.md\n    - advanced/websockets.md\n    - advanced/events.md\n    - advanced/testing-websockets.md\n    - advanced/testing-events.md\n    - advanced/testing-dependencies.md\n    - advanced/async-tests.md\n    - advanced/settings.md\n    - advanced/openapi-callbacks.md\n    - advanced/openapi-webhooks.md\n    - advanced/wsgi.md\n    - advanced/generate-clients.md\n    - advanced/advanced-python-types.md\n    - advanced/json-base64-bytes.md\n    - advanced/strict-content-type.md\n  - fastapi-cli.md\n  - editor-support.md\n  - Deployment:\n    - deployment/index.md\n    - deployment/versions.md\n    - deployment/fastapicloud.md\n    - deployment/https.md\n    - deployment/manually.md\n    - deployment/concepts.md\n    - deployment/cloud.md\n    - deployment/server-workers.md\n    - deployment/docker.md\n  - How To - Recipes:\n    - how-to/index.md\n    - how-to/general.md\n    - how-to/migrate-from-pydantic-v1-to-pydantic-v2.md\n    - how-to/graphql.md\n    - how-to/custom-request-and-route.md\n    - how-to/conditional-openapi.md\n    - how-to/extending-openapi.md\n    - how-to/separate-openapi-schemas.md\n    - how-to/custom-docs-ui-assets.md\n    - how-to/configure-swagger-ui.md\n    - how-to/testing-database.md\n    - how-to/authentication-error-status-code.md\n- Reference (Code API):\n  - reference/index.md\n  - reference/fastapi.md\n  - reference/parameters.md\n  - reference/status.md\n  - reference/uploadfile.md\n  - reference/exceptions.md\n  - reference/dependencies.md\n  - reference/apirouter.md\n  - reference/background.md\n  - reference/request.md\n  - reference/websockets.md\n  - reference/httpconnection.md\n  - reference/response.md\n  - reference/responses.md\n  - reference/middleware.md\n  - OpenAPI:\n    - reference/openapi/index.md\n    - reference/openapi/docs.md\n    - reference/openapi/models.md\n  - reference/security/index.md\n  - reference/encoders.md\n  - reference/staticfiles.md\n  - reference/templating.md\n  - reference/testclient.md\n- fastapi-people.md\n- Resources:\n  - resources/index.md\n  - help-fastapi.md\n  - contributing.md\n  - project-generation.md\n  - external-links.md\n  - newsletter.md\n  - management-tasks.md\n- About:\n  - about/index.md\n  - alternatives.md\n  - history-design-future.md\n  - benchmarks.md\n  - management.md\n- release-notes.md\nmarkdown_extensions:\n  material.extensions.preview:\n    targets:\n      include:\n      - '*'\n  abbr: null\n  attr_list: null\n  footnotes: null\n  md_in_html: null\n  tables: null\n  toc:\n    permalink: true\n  pymdownx.betterem: null\n  pymdownx.caret: null\n  pymdownx.highlight:\n    line_spans: __span\n    linenums_style: pymdownx-inline\n  pymdownx.inlinehilite: null\n  pymdownx.keys: null\n  pymdownx.mark: null\n  pymdownx.superfences:\n    custom_fences:\n    - name: mermaid\n      class: mermaid\n      format: !!python/name:pymdownx.superfences.fence_code_format ''\n  pymdownx.tilde: null\n  pymdownx.blocks.admonition:\n    types:\n    - note\n    - attention\n    - caution\n    - danger\n    - error\n    - tip\n    - hint\n    - warning\n    - info\n    - check\n  pymdownx.blocks.details: null\n  pymdownx.blocks.tab:\n    alternate_style: true\n  mdx_include: null\n  markdown_include_variants: null\nextra:\n  social:\n  - icon: fontawesome/brands/github-alt\n    link: https://github.com/fastapi/fastapi\n  - icon: fontawesome/brands/discord\n    link: https://discord.gg/VQjSZaeJmf\n  - icon: fontawesome/brands/twitter\n    link: https://x.com/fastapi\n  - icon: fontawesome/brands/linkedin\n    link: https://www.linkedin.com/company/fastapi\n  - icon: fontawesome/solid/globe\n    link: https://tiangolo.com\n  alternate:\n  - link: /\n    name: en - English\n  - link: /de/\n    name: de - Deutsch\n  - link: /es/\n    name: es - español\n  - link: /fr/\n    name: fr - français\n  - link: /ja/\n    name: ja - 日本語\n  - link: /ko/\n    name: ko - 한국어\n  - link: /pt/\n    name: pt - português\n  - link: /ru/\n    name: ru - русский язык\n  - link: /tr/\n    name: tr - Türkçe\n  - link: /uk/\n    name: uk - українська мова\n  - link: /zh/\n    name: zh - 简体中文\n  - link: /zh-hant/\n    name: zh-hant - 繁體中文\nextra_css:\n- css/termynal.css\n- css/custom.css\nextra_javascript:\n- js/termynal.js\n- js/custom.js\n- js/init_kapa_widget.js\nhooks:\n- ../../scripts/mkdocs_hooks.py\n"
  },
  {
    "path": "docs/en/overrides/main.html",
    "content": "{% extends \"base.html\" %}\n\n{% block announce %}\n<div class=\"announce-wrapper\">\n  <div id=\"announce-left\">\n    <div class=\"item\">\n      <a class=\"announce-link\" href=\"https://fastapicloud.com\" target=\"_blank\">\n        <span class=\"twemoji\">\n          {% include \".icons/material/cloud-arrow-up.svg\" %}\n        </span> Join the <strong>FastAPI Cloud</strong> waiting list 🚀\n      </a>\n    </div>\n    <div class=\"item\">\n      <a class=\"announce-link\" href=\"https://fastapiconf.com\" target=\"_blank\">\n        <span class=\"twemoji\">\n          {% include \".icons/material/calendar-star.svg\" %}\n        </span> <strong>FastAPI Conf '26</strong> — Oct 28, 2026, Amsterdam 🎤\n      </a>\n    </div>\n    <div class=\"item\">\n      <a class=\"announce-link\" href=\"https://x.com/fastapi\" target=\"_blank\">\n        <span class=\"twemoji\">\n          {% include \".icons/fontawesome/brands/x-twitter.svg\" %}\n        </span> Follow <strong>@fastapi</strong> on <strong>X (Twitter)</strong> to stay updated\n      </a>\n    </div>\n    <div class=\"item\">\n      <a class=\"announce-link\" href=\"https://www.linkedin.com/company/fastapi\" target=\"_blank\">\n        <span class=\"twemoji linkedin\">\n          {% include \".icons/fontawesome/brands/linkedin.svg\" %}\n        </span> Follow <strong>FastAPI</strong> on <strong>LinkedIn</strong> to stay updated\n      </a>\n    </div>\n    <div class=\"item\">\n      <a class=\"announce-link\" href=\"https://fastapi.tiangolo.com/newsletter/\">\n        <span class=\"twemoji\">\n          {% include \".icons/material/email.svg\" %}\n        </span> Subscribe to the <strong>FastAPI and friends</strong> newsletter 🎉\n      </a>\n    </div>\n  </div>\n  <div id=\"announce-right\" style=\"position: relative;\">\n    <div class=\"item\">\n      <a title=\"BlockBee Cryptocurrency Payment Gateway\" style=\"display: block; position: relative;\" href=\"https://blockbee.io?ref=fastapi\" target=\"_blank\">\n        <span class=\"sponsor-badge\">sponsor</span>\n        <img class=\"sponsor-image\" src=\"/img/sponsors/blockbee-banner.png\" />\n      </a>\n    </div>\n    <div class=\"item\">\n      <a title=\"Scalar: Beautiful Open-Source API References from Swagger/OpenAPI files\" style=\"display: block; position: relative;\" href=\"https://github.com/scalar/scalar/?utm_source=fastapi&utm_medium=website&utm_campaign=top-banner\" target=\"_blank\">\n        <span class=\"sponsor-badge\">sponsor</span>\n        <img class=\"sponsor-image\" src=\"/img/sponsors/scalar-banner.svg\" />\n      </a>\n    </div>\n    <div class=\"item\">\n      <a title=\"Auth, user management and more for your B2B product\" style=\"display: block; position: relative;\" href=\"https://www.propelauth.com/?utm_source=fastapi&utm_campaign=1223&utm_medium=topbanner\" target=\"_blank\">\n        <span class=\"sponsor-badge\">sponsor</span>\n        <img class=\"sponsor-image\" src=\"/img/sponsors/propelauth-banner.png\" />\n      </a>\n    </div>\n    <div class=\"item\">\n      <a title=\"liblab - Generate SDKs from FastAPI\" style=\"display: block; position: relative;\" href=\"https://liblab.com?utm_source=fastapi\" target=\"_blank\">\n        <span class=\"sponsor-badge\">sponsor</span>\n        <img class=\"sponsor-image\" src=\"/img/sponsors/liblab-banner.png\" />\n      </a>\n    </div>\n    <div class=\"item\">\n      <a title=\"Deploy & scale any full-stack web app on Render. Focus on building apps, not infra.\" style=\"display: block; position: relative;\" href=\"https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi\" target=\"_blank\">\n        <span class=\"sponsor-badge\">sponsor</span>\n        <img class=\"sponsor-image\" src=\"/img/sponsors/render-banner.svg\" />\n      </a>\n    </div>\n    <div class=\"item\">\n      <a title=\"Cut Code Review Time & Bugs in Half with CodeRabbit\" style=\"display: block; position: relative;\" href=\"https://www.coderabbit.ai/?utm_source=fastapi&utm_medium=banner&utm_campaign=fastapi\" target=\"_blank\">\n        <span class=\"sponsor-badge\">sponsor</span>\n        <img class=\"sponsor-image\" src=\"/img/sponsors/coderabbit-banner.png\" />\n      </a>\n    </div>\n    <div class=\"item\">\n      <a title=\"Making Retail Purchases Actionable for Brands and Developers\" style=\"display: block; position: relative;\" href=\"https://subtotal.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=open-source\" target=\"_blank\">\n        <span class=\"sponsor-badge\">sponsor</span>\n        <img class=\"sponsor-image\" src=\"/img/sponsors/subtotal-banner.svg\" />\n      </a>\n    </div>\n    <div class=\"item\">\n      <a title=\"Deploy enterprise applications at startup speed\" style=\"display: block; position: relative;\" href=\"https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi\" target=\"_blank\">\n        <span class=\"sponsor-badge\">sponsor</span>\n        <img class=\"sponsor-image\" src=\"/img/sponsors/railway-banner.png\" />\n      </a>\n    </div>\n    <div class=\"item\">\n      <a title=\"SerpApi: Web Search API\" style=\"display: block; position: relative;\" href=\"https://serpapi.com/?utm_source=fastapi_website\" target=\"_blank\">\n        <span class=\"sponsor-badge\">sponsor</span>\n        <img class=\"sponsor-image\" src=\"/img/sponsors/serpapi-banner.png\" />\n      </a>\n    </div>\n    <div class=\"item\">\n      <a title=\"Greptile: The AI Code Reviewer\" style=\"display: block; position: relative;\" href=\"https://www.greptile.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=fastapi_sponsor_page\" target=\"_blank\">\n        <span class=\"sponsor-badge\">sponsor</span>\n        <img class=\"sponsor-image\" src=\"/img/sponsors/greptile-banner.png\" />\n      </a>\n    </div>\n  </div>\n</div>\n{% endblock %}\n"
  },
  {
    "path": "docs/en/overrides/partials/copyright.html",
    "content": "<div class=\"md-copyright\">\n    <div class=\"md-copyright__highlight\">\n        The FastAPI trademark is owned by <a href=\"https://tiangolo.com\" target=\"_blank\">@tiangolo</a> and is registered in the US and across other regions\n    </div>\n    {% if not config.extra.generator == false %}\n    Made with\n    <a href=\"https://squidfunk.github.io/mkdocs-material/\" target=\"_blank\" rel=\"noopener\">\n        Material for MkDocs\n    </a>\n    {% endif %}\n</div>\n"
  },
  {
    "path": "docs/es/docs/_llm-test.md",
    "content": "# Archivo de prueba de LLM { #llm-test-file }\n\nEste documento prueba si el <abbr title=\"Large Language Model - Modelo de lenguaje grande\">LLM</abbr>, que traduce la documentación, entiende el `general_prompt` en `scripts/translate.py` y el prompt específico del idioma en `docs/{language code}/llm-prompt.md`. El prompt específico del idioma se agrega al final de `general_prompt`.\n\nLas pruebas añadidas aquí serán vistas por todas las personas que diseñan prompts específicos del idioma.\n\nÚsalo de la siguiente manera:\n\n* Ten un prompt específico del idioma - `docs/{language code}/llm-prompt.md`.\n* Haz una traducción fresca de este documento a tu idioma destino (mira, por ejemplo, el comando `translate-page` de `translate.py`). Esto creará la traducción en `docs/{language code}/docs/_llm-test.md`.\n* Revisa si las cosas están bien en la traducción.\n* Si es necesario, mejora tu prompt específico del idioma, el prompt general, o el documento en inglés.\n* Luego corrige manualmente los problemas restantes en la traducción para que sea una buena traducción.\n* Vuelve a traducir, teniendo la buena traducción en su lugar. El resultado ideal sería que el LLM ya no hiciera cambios a la traducción. Eso significa que el prompt general y tu prompt específico del idioma están tan bien como pueden estar (A veces hará algunos cambios aparentemente aleatorios; la razón es que [los LLMs no son algoritmos deterministas](https://doublespeak.chat/#/handbook#deterministic-output)).\n\nLas pruebas:\n\n## Fragmentos de código { #code-snippets }\n\n//// tab | Prueba\n\nEste es un fragmento de código: `foo`. Y este es otro fragmento de código: `bar`. Y otro más: `baz quux`.\n\n////\n\n//// tab | Info\n\nEl contenido de los fragmentos de código debe dejarse tal cual.\n\nConsulta la sección `### Content of code snippets` en el prompt general en `scripts/translate.py`.\n\n////\n\n## Comillas { #quotes }\n\n//// tab | Prueba\n\nAyer, mi amigo escribió: \"Si escribes 'incorrectly' correctamente, lo habrás escrito incorrectamente\". A lo que respondí: \"Correcto, pero 'incorrectly' está incorrecto, no '\"incorrectly\"'\".\n\n/// note | Nota\n\nEl LLM probablemente traducirá esto mal. Lo interesante es si mantiene la traducción corregida al volver a traducir.\n\n///\n\n////\n\n//// tab | Info\n\nLa persona que diseña el prompt puede elegir si quiere convertir comillas neutras a comillas tipográficas. También está bien dejarlas como están.\n\nConsulta por ejemplo la sección `### Quotes` en `docs/de/llm-prompt.md`.\n\n////\n\n## Comillas en fragmentos de código { #quotes-in-code-snippets }\n\n//// tab | Prueba\n\n`pip install \"foo[bar]\"`\n\nEjemplos de literales de string en fragmentos de código: `\"this\"`, `'that'`.\n\nUn ejemplo difícil de literales de string en fragmentos de código: `f\"I like {'oranges' if orange else \"apples\"}\"`\n\nHardcore: `Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | Info\n\n... Sin embargo, las comillas dentro de fragmentos de código deben quedarse tal cual.\n\n////\n\n## bloques de código { #code-blocks }\n\n//// tab | Prueba\n\nUn ejemplo de código Bash...\n\n```bash\n# Imprime un saludo al universo\necho \"Hello universe\"\n```\n\n...y un ejemplo de código de consola...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n...y otro ejemplo de código de consola...\n\n```console\n// Crea un directorio \"Code\"\n$ mkdir code\n// Cambia a ese directorio\n$ cd code\n```\n\n...y un ejemplo de código Python...\n\n```Python\nwont_work()  # Esto no va a funcionar 😱\nworks(foo=\"bar\")  # Esto funciona 🎉\n```\n\n...y eso es todo.\n\n////\n\n//// tab | Info\n\nEl código en bloques de código no debe modificarse, con la excepción de los comentarios.\n\nConsulta la sección `### Content of code blocks` en el prompt general en `scripts/translate.py`.\n\n////\n\n## Pestañas y cajas coloreadas { #tabs-and-colored-boxes }\n\n//// tab | Prueba\n\n/// info | Información\nAlgo de texto\n///\n\n/// note | Nota\nAlgo de texto\n///\n\n/// note | Detalles técnicos\nAlgo de texto\n///\n\n/// check | Revisa\nAlgo de texto\n///\n\n/// tip | Consejo\nAlgo de texto\n///\n\n/// warning | Advertencia\nAlgo de texto\n///\n\n/// danger | Peligro\nAlgo de texto\n///\n\n////\n\n//// tab | Info\n\nLas pestañas y los bloques `Info`/`Note`/`Warning`/etc. deben tener la traducción de su título añadida después de una barra vertical (`|`).\n\nConsulta las secciones `### Special blocks` y `### Tab blocks` en el prompt general en `scripts/translate.py`.\n\n////\n\n## Enlaces web e internos { #web-and-internal-links }\n\n//// tab | Prueba\n\nEl texto del enlace debe traducirse, la dirección del enlace debe permanecer sin cambios:\n\n* [Enlace al encabezado de arriba](#code-snippets)\n* [Enlace interno](index.md#installation)\n* [Enlace externo](https://sqlmodel.tiangolo.com/)\n* [Enlace a un estilo](https://fastapi.tiangolo.com/css/styles.css)\n* [Enlace a un script](https://fastapi.tiangolo.com/js/logic.js)\n* [Enlace a una imagen](https://fastapi.tiangolo.com/img/foo.jpg)\n\nEl texto del enlace debe traducirse, la dirección del enlace debe apuntar a la traducción:\n\n* [Enlace a FastAPI](https://fastapi.tiangolo.com/es/)\n\n////\n\n//// tab | Info\n\nLos enlaces deben traducirse, pero su dirección debe permanecer sin cambios. Una excepción son los enlaces absolutos a páginas de la documentación de FastAPI. En ese caso deben enlazar a la traducción.\n\nConsulta la sección `### Links` en el prompt general en `scripts/translate.py`.\n\n////\n\n## Elementos HTML \"abbr\" { #html-abbr-elements }\n\n//// tab | Prueba\n\nAquí algunas cosas envueltas en elementos HTML \"abbr\" (algunas son inventadas):\n\n### El abbr da una frase completa { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done - Hacer las cosas\">GTD</abbr>\n* <abbr title=\"less than - menor que\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token - Token web XML\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface - Interfaz de pasarela de servidor paralela\">PSGI</abbr>\n\n### El abbr da una frase completa y una explicación { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network - Red de Desarrolladores de Mozilla: documentación para desarrolladores, escrita por la gente de Firefox\">MDN</abbr>\n* <abbr title=\"Input/Output - Entrada/Salida: lectura o escritura de disco, comunicaciones de red.\">I/O</abbr>.\n\n////\n\n//// tab | Info\n\nLos atributos \"title\" de los elementos \"abbr\" se traducen siguiendo instrucciones específicas.\n\nLas traducciones pueden añadir sus propios elementos \"abbr\" que el LLM no debe eliminar. P. ej., para explicar palabras en inglés.\n\nConsulta la sección `### HTML abbr elements` en el prompt general en `scripts/translate.py`.\n\n////\n\n## Elementos HTML \"dfn\" { #html-dfn-elements }\n\n* <dfn title=\"Un grupo de máquinas configuradas para estar conectadas y trabajar juntas de alguna manera.\">clúster</dfn>\n* <dfn title=\"Un método de Machine Learning que usa redes neuronales artificiales con numerosas capas ocultas entre las capas de entrada y salida, desarrollando así una estructura interna completa\">Deep Learning</dfn>\n\n## Encabezados { #headings }\n\n//// tab | Prueba\n\n### Desarrolla una webapp - un tutorial { #develop-a-webapp-a-tutorial }\n\nHola.\n\n### Anotaciones de tipos y -anotaciones { #type-hints-and-annotations }\n\nHola de nuevo.\n\n### Superclases y subclases { #super-and-subclasses }\n\nHola de nuevo.\n\n////\n\n//// tab | Info\n\nLa única regla estricta para los encabezados es que el LLM deje la parte del hash dentro de llaves sin cambios, lo que asegura que los enlaces no se rompan.\n\nConsulta la sección `### Headings` en el prompt general en `scripts/translate.py`.\n\nPara instrucciones específicas del idioma, mira p. ej. la sección `### Headings` en `docs/de/llm-prompt.md`.\n\n////\n\n## Términos usados en la documentación { #terms-used-in-the-docs }\n\n//// tab | Prueba\n\n* tú\n* tu\n\n* p. ej.\n* etc.\n\n* `foo` como un `int`\n* `bar` como un `str`\n* `baz` como una `list`\n\n* el Tutorial - Guía de usuario\n* la Guía de usuario avanzada\n* la documentación de SQLModel\n* la documentación de la API\n* la documentación automática\n\n* Ciencia de datos\n* Deep Learning\n* Machine Learning\n* Inyección de dependencias\n* autenticación HTTP Basic\n* HTTP Digest\n* formato ISO\n* el estándar JSON Schema\n* el JSON Schema\n* la definición del esquema\n* Flujo de contraseña\n* Móvil\n\n* obsoleto\n* diseñado\n* inválido\n* sobre la marcha\n* estándar\n* por defecto\n* sensible a mayúsculas/minúsculas\n* insensible a mayúsculas/minúsculas\n\n* servir la aplicación\n* servir la página\n\n* la app\n* la aplicación\n\n* la request\n* la response\n* la response de error\n\n* la path operation\n* el decorador de path operation\n* la path operation function\n\n* el body\n* el request body\n* el response body\n* el body JSON\n* el body del formulario\n* el body de archivo\n* el cuerpo de la función\n\n* el parámetro\n* el parámetro del body\n* el parámetro del path\n* el parámetro de query\n* el parámetro de cookie\n* el parámetro de header\n* el parámetro del formulario\n* el parámetro de la función\n\n* el evento\n* el evento de inicio\n* el inicio del servidor\n* el evento de apagado\n* el evento de lifespan\n\n* el manejador\n* el manejador de eventos\n* el manejador de excepciones\n* manejar\n\n* el modelo\n* el modelo de Pydantic\n* el modelo de datos\n* el modelo de base de datos\n* el modelo de formulario\n* el objeto del modelo\n\n* la clase\n* la clase base\n* la clase padre\n* la subclase\n* la clase hija\n* la clase hermana\n* el método de clase\n\n* el header\n* los headers\n* el header de autorización\n* el header `Authorization`\n* el header forwarded\n\n* el sistema de inyección de dependencias\n* la dependencia\n* el dependable\n* el dependiente\n\n* limitado por I/O\n* limitado por CPU\n* concurrencia\n* paralelismo\n* multiprocesamiento\n\n* la env var\n* la variable de entorno\n* el `PATH`\n* la variable `PATH`\n\n* la autenticación\n* el proveedor de autenticación\n* la autorización\n* el formulario de autorización\n* el proveedor de autorización\n* el usuario se autentica\n* el sistema autentica al usuario\n\n* la CLI\n* la interfaz de línea de comandos\n\n* el servidor\n* el cliente\n\n* el proveedor en la nube\n* el servicio en la nube\n\n* el desarrollo\n* las etapas de desarrollo\n\n* el dict\n* el diccionario\n* la enumeración\n* el enum\n* el miembro del enum\n\n* el codificador\n* el decodificador\n* codificar\n* decodificar\n\n* la excepción\n* lanzar\n\n* la expresión\n* el statement\n\n* el frontend\n* el backend\n\n* la discusión de GitHub\n* el issue de GitHub\n\n* el rendimiento\n* la optimización de rendimiento\n\n* el tipo de retorno\n* el valor de retorno\n\n* la seguridad\n* el esquema de seguridad\n\n* la tarea\n* la tarea en segundo plano\n* la función de tarea\n\n* la plantilla\n* el motor de plantillas\n\n* la anotación de tipos\n* la anotación de tipos\n\n* el worker del servidor\n* el worker de Uvicorn\n* el Gunicorn Worker\n* el worker process\n* la worker class\n* la carga de trabajo\n\n* el despliegue\n* desplegar\n\n* el SDK\n* el kit de desarrollo de software\n\n* el `APIRouter`\n* el `requirements.txt`\n* el Bearer Token\n* el cambio incompatible\n* el bug\n* el botón\n* el invocable\n* el código\n* el commit\n* el context manager\n* la corrutina\n* la sesión de base de datos\n* el disco\n* el dominio\n* el motor\n* el X falso\n* el método HTTP GET\n* el ítem\n* el paquete\n* el lifespan\n* el lock\n* el middleware\n* la aplicación móvil\n* el módulo\n* el montaje\n* la red\n* el origen\n* el override\n* el payload\n* el procesador\n* la propiedad\n* el proxy\n* el pull request\n* la query\n* la RAM\n* la máquina remota\n* el código de estado\n* el string\n* la etiqueta\n* el framework web\n* el comodín\n* devolver\n* validar\n\n////\n\n//// tab | Info\n\nEsta es una lista no completa y no normativa de términos (mayormente) técnicos vistos en la documentación. Puede ayudar a la persona que diseña el prompt a identificar para qué términos el LLM necesita una mano. Por ejemplo cuando sigue revirtiendo una buena traducción a una traducción subóptima. O cuando tiene problemas conjugando/declinando un término en tu idioma.\n\nMira p. ej. la sección `### List of English terms and their preferred German translations` en `docs/de/llm-prompt.md`.\n\n////\n"
  },
  {
    "path": "docs/es/docs/about/index.md",
    "content": "# Acerca de { #about }\n\nAcerca de FastAPI, su diseño, inspiración y más. 🤓\n"
  },
  {
    "path": "docs/es/docs/advanced/additional-responses.md",
    "content": "# Responses Adicionales en OpenAPI { #additional-responses-in-openapi }\n\n/// warning | Advertencia\n\nEste es un tema bastante avanzado.\n\nSi estás comenzando con **FastAPI**, puede que no lo necesites.\n\n///\n\nPuedes declarar responses adicionales, con códigos de estado adicionales, media types, descripciones, etc.\n\nEsos responses adicionales se incluirán en el esquema de OpenAPI, por lo que también aparecerán en la documentación de la API.\n\nPero para esos responses adicionales tienes que asegurarte de devolver un `Response` como `JSONResponse` directamente, con tu código de estado y contenido.\n\n## Response Adicional con `model` { #additional-response-with-model }\n\nPuedes pasar a tus *decoradores de path operation* un parámetro `responses`.\n\nRecibe un `dict`: las claves son los códigos de estado para cada response (como `200`), y los valores son otros `dict`s con la información para cada uno de ellos.\n\nCada uno de esos `dict`s de response puede tener una clave `model`, conteniendo un modelo de Pydantic, así como `response_model`.\n\n**FastAPI** tomará ese modelo, generará su JSON Schema y lo incluirá en el lugar correcto en OpenAPI.\n\nPor ejemplo, para declarar otro response con un código de estado `404` y un modelo Pydantic `Message`, puedes escribir:\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | Nota\n\nTen en cuenta que debes devolver el `JSONResponse` directamente.\n\n///\n\n/// info | Información\n\nLa clave `model` no es parte de OpenAPI.\n\n**FastAPI** tomará el modelo de Pydantic de allí, generará el JSON Schema y lo colocará en el lugar correcto.\n\nEl lugar correcto es:\n\n* En la clave `content`, que tiene como valor otro objeto JSON (`dict`) que contiene:\n  * Una clave con el media type, por ejemplo, `application/json`, que contiene como valor otro objeto JSON, que contiene:\n    * Una clave `schema`, que tiene como valor el JSON Schema del modelo, aquí es el lugar correcto.\n        * **FastAPI** agrega una referencia aquí a los JSON Schemas globales en otro lugar de tu OpenAPI en lugar de incluirlo directamente. De este modo, otras aplicaciones y clientes pueden usar esos JSON Schemas directamente, proporcionar mejores herramientas de generación de código, etc.\n\n///\n\nLos responses generadas en el OpenAPI para esta *path operation* serán:\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nLos esquemas se referencian a otro lugar dentro del esquema de OpenAPI:\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## Media types adicionales para el response principal { #additional-media-types-for-the-main-response }\n\nPuedes usar este mismo parámetro `responses` para agregar diferentes media type para el mismo response principal.\n\nPor ejemplo, puedes agregar un media type adicional de `image/png`, declarando que tu *path operation* puede devolver un objeto JSON (con media type `application/json`) o una imagen PNG:\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | Nota\n\nNota que debes devolver la imagen usando un `FileResponse` directamente.\n\n///\n\n/// info | Información\n\nA menos que especifiques un media type diferente explícitamente en tu parámetro `responses`, FastAPI asumirá que el response tiene el mismo media type que la clase de response principal (por defecto `application/json`).\n\nPero si has especificado una clase de response personalizada con `None` como su media type, FastAPI usará `application/json` para cualquier response adicional que tenga un modelo asociado.\n\n///\n\n## Combinando información { #combining-information }\n\nTambién puedes combinar información de response de múltiples lugares, incluyendo los parámetros `response_model`, `status_code`, y `responses`.\n\nPuedes declarar un `response_model`, usando el código de estado por defecto `200` (o uno personalizado si lo necesitas), y luego declarar información adicional para ese mismo response en `responses`, directamente en el esquema de OpenAPI.\n\n**FastAPI** mantendrá la información adicional de `responses` y la combinará con el JSON Schema de tu modelo.\n\nPor ejemplo, puedes declarar un response con un código de estado `404` que usa un modelo Pydantic y tiene una `description` personalizada.\n\nY un response con un código de estado `200` que usa tu `response_model`, pero incluye un `example` personalizado:\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\nTodo se combinará e incluirá en tu OpenAPI, y se mostrará en la documentación de la API:\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## Combina responses predefinidos y personalizados { #combine-predefined-responses-and-custom-ones }\n\nEs posible que desees tener algunos responses predefinidos que se apliquen a muchas *path operations*, pero que quieras combinarlos con responses personalizados necesarios por cada *path operation*.\n\nPara esos casos, puedes usar la técnica de Python de \"desempaquetar\" un `dict` con `**dict_to_unpack`:\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\nAquí, `new_dict` contendrá todos los pares clave-valor de `old_dict` más el nuevo par clave-valor:\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\nPuedes usar esa técnica para reutilizar algunos responses predefinidos en tus *path operations* y combinarlos con otros personalizados adicionales.\n\nPor ejemplo:\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## Más información sobre responses OpenAPI { #more-information-about-openapi-responses }\n\nPara ver exactamente qué puedes incluir en los responses, puedes revisar estas secciones en la especificación OpenAPI:\n\n* [Objeto de Responses de OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object), incluye el `Response Object`.\n* [Objeto de Response de OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object), puedes incluir cualquier cosa de esto directamente en cada response dentro de tu parámetro `responses`. Incluyendo `description`, `headers`, `content` (dentro de este es que declaras diferentes media types y JSON Schemas), y `links`.\n"
  },
  {
    "path": "docs/es/docs/advanced/additional-status-codes.md",
    "content": "# Códigos de Estado Adicionales { #additional-status-codes }\n\nPor defecto, **FastAPI** devolverá los responses usando un `JSONResponse`, colocando el contenido que devuelves desde tu *path operation* dentro de ese `JSONResponse`.\n\nUsará el código de estado por defecto o el que configures en tu *path operation*.\n\n## Códigos de estado adicionales { #additional-status-codes_1 }\n\nSi quieres devolver códigos de estado adicionales aparte del principal, puedes hacerlo devolviendo un `Response` directamente, como un `JSONResponse`, y configurando el código de estado adicional directamente.\n\nPor ejemplo, supongamos que quieres tener una *path operation* que permita actualizar elementos, y devuelva códigos de estado HTTP de 200 \"OK\" cuando sea exitoso.\n\nPero también quieres que acepte nuevos elementos. Y cuando los elementos no existían antes, los crea y devuelve un código de estado HTTP de 201 \"Created\".\n\nPara lograr eso, importa `JSONResponse`, y devuelve tu contenido allí directamente, configurando el `status_code` que deseas:\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning | Advertencia\n\nCuando devuelves un `Response` directamente, como en el ejemplo anterior, se devuelve directamente.\n\nNo se serializará con un modelo, etc.\n\nAsegúrate de que tenga los datos que deseas que tenga y que los valores sean JSON válidos (si estás usando `JSONResponse`).\n\n///\n\n/// note | Detalles Técnicos\n\nTambién podrías usar `from starlette.responses import JSONResponse`.\n\n**FastAPI** proporciona los mismos `starlette.responses` que `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles provienen directamente de Starlette. Lo mismo con `status`.\n\n///\n\n## OpenAPI y documentación de API { #openapi-and-api-docs }\n\nSi devuelves códigos de estado adicionales y responses directamente, no se incluirán en el esquema de OpenAPI (la documentación de la API), porque FastAPI no tiene una forma de saber de antemano qué vas a devolver.\n\nPero puedes documentarlo en tu código, usando: [Responses Adicionales](additional-responses.md).\n"
  },
  {
    "path": "docs/es/docs/advanced/advanced-dependencies.md",
    "content": "# Dependencias Avanzadas { #advanced-dependencies }\n\n## Dependencias con parámetros { #parameterized-dependencies }\n\nTodas las dependencias que hemos visto son una función o clase fija.\n\nPero podría haber casos en los que quieras poder establecer parámetros en la dependencia, sin tener que declarar muchas funciones o clases diferentes.\n\nImaginemos que queremos tener una dependencia que revise si el parámetro de query `q` contiene algún contenido fijo.\n\nPero queremos poder parametrizar ese contenido fijo.\n\n## Una *instance* \"callable\" { #a-callable-instance }\n\nEn Python hay una forma de hacer que una instance de una clase sea un \"callable\".\n\nNo la clase en sí (que ya es un callable), sino una instance de esa clase.\n\nPara hacer eso, declaramos un método `__call__`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\nEn este caso, este `__call__` es lo que **FastAPI** usará para comprobar parámetros adicionales y sub-dependencias, y es lo que llamará para pasar un valor al parámetro en tu *path operation function* más adelante.\n\n## Parametrizar la instance { #parameterize-the-instance }\n\nY ahora, podemos usar `__init__` para declarar los parámetros de la instance que podemos usar para \"parametrizar\" la dependencia:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\nEn este caso, **FastAPI** nunca tocará ni se preocupará por `__init__`, lo usaremos directamente en nuestro código.\n\n## Crear una instance { #create-an-instance }\n\nPodríamos crear una instance de esta clase con:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\nY de esa manera podemos \"parametrizar\" nuestra dependencia, que ahora tiene `\"bar\"` dentro de ella, como el atributo `checker.fixed_content`.\n\n## Usar la instance como una dependencia { #use-the-instance-as-a-dependency }\n\nLuego, podríamos usar este `checker` en un `Depends(checker)`, en lugar de `Depends(FixedContentQueryChecker)`, porque la dependencia es la instance, `checker`, no la clase en sí.\n\nY al resolver la dependencia, **FastAPI** llamará a este `checker` así:\n\n```Python\nchecker(q=\"somequery\")\n```\n\n...y pasará lo que eso retorne como el valor de la dependencia en nuestra *path operation function* como el parámetro `fixed_content_included`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | Consejo\n\nTodo esto podría parecer complicado. Y puede que no esté muy claro cómo es útil aún.\n\nEstos ejemplos son intencionalmente simples, pero muestran cómo funciona todo.\n\nEn los capítulos sobre seguridad, hay funciones utilitarias que se implementan de esta misma manera.\n\nSi entendiste todo esto, ya sabes cómo funcionan por debajo esas herramientas de utilidad para seguridad.\n\n///\n\n## Dependencias con `yield`, `HTTPException`, `except` y Tareas en segundo plano { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | Advertencia\n\nMuy probablemente no necesites estos detalles técnicos.\n\nEstos detalles son útiles principalmente si tenías una aplicación de FastAPI anterior a la 0.121.0 y estás enfrentando problemas con dependencias con `yield`.\n\n///\n\nLas dependencias con `yield` han evolucionado con el tiempo para cubrir diferentes casos de uso y arreglar algunos problemas; aquí tienes un resumen de lo que ha cambiado.\n\n### Dependencias con `yield` y `scope` { #dependencies-with-yield-and-scope }\n\nEn la versión 0.121.0, FastAPI agregó soporte para `Depends(scope=\"function\")` para dependencias con `yield`.\n\nUsando `Depends(scope=\"function\")`, el código de salida después de `yield` se ejecuta justo después de que la *path operation function* termina, antes de que la response se envíe de vuelta al cliente.\n\nY al usar `Depends(scope=\"request\")` (el valor por defecto), el código de salida después de `yield` se ejecuta después de que la response es enviada.\n\nPuedes leer más al respecto en la documentación de [Dependencias con `yield` - Salida temprana y `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope).\n\n### Dependencias con `yield` y `StreamingResponse`, detalles técnicos { #dependencies-with-yield-and-streamingresponse-technical-details }\n\nAntes de FastAPI 0.118.0, si usabas una dependencia con `yield`, ejecutaba el código de salida después de que la *path operation function* retornaba pero justo antes de enviar la response.\n\nLa intención era evitar retener recursos por más tiempo del necesario, esperando a que la response viajara por la red.\n\nEste cambio también significaba que si retornabas un `StreamingResponse`, el código de salida de la dependencia con `yield` ya se habría ejecutado.\n\nPor ejemplo, si tenías una sesión de base de datos en una dependencia con `yield`, el `StreamingResponse` no podría usar esa sesión mientras hace streaming de datos porque la sesión ya se habría cerrado en el código de salida después de `yield`.\n\nEste comportamiento se revirtió en la 0.118.0, para hacer que el código de salida después de `yield` se ejecute después de que la response sea enviada.\n\n/// info | Información\n\nComo verás abajo, esto es muy similar al comportamiento anterior a la versión 0.106.0, pero con varias mejoras y arreglos de bugs para casos límite.\n\n///\n\n#### Casos de uso con salida temprana del código { #use-cases-with-early-exit-code }\n\nHay algunos casos de uso con condiciones específicas que podrían beneficiarse del comportamiento antiguo de ejecutar el código de salida de dependencias con `yield` antes de enviar la response.\n\nPor ejemplo, imagina que tienes código que usa una sesión de base de datos en una dependencia con `yield` solo para verificar un usuario, pero la sesión de base de datos no se vuelve a usar en la *path operation function*, solo en la dependencia, y la response tarda mucho en enviarse, como un `StreamingResponse` que envía datos lentamente, pero que por alguna razón no usa la base de datos.\n\nEn este caso, la sesión de base de datos se mantendría hasta que la response termine de enviarse, pero si no la usas, entonces no sería necesario mantenerla.\n\nAsí es como se vería:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\nEl código de salida, el cierre automático de la `Session` en:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n...se ejecutaría después de que la response termine de enviar los datos lentos:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nPero como `generate_stream()` no usa la sesión de base de datos, no es realmente necesario mantener la sesión abierta mientras se envía la response.\n\nSi tienes este caso de uso específico usando SQLModel (o SQLAlchemy), podrías cerrar explícitamente la sesión después de que ya no la necesites:\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\nDe esa manera la sesión liberaría la conexión a la base de datos, para que otras requests puedan usarla.\n\nSi tienes un caso de uso diferente que necesite salir temprano desde una dependencia con `yield`, por favor crea una [Pregunta de Discusión en GitHub](https://github.com/fastapi/fastapi/discussions/new?category=questions) con tu caso de uso específico y por qué te beneficiaría tener cierre temprano para dependencias con `yield`.\n\nSi hay casos de uso convincentes para el cierre temprano en dependencias con `yield`, consideraría agregar una nueva forma de optar por el cierre temprano.\n\n### Dependencias con `yield` y `except`, detalles técnicos { #dependencies-with-yield-and-except-technical-details }\n\nAntes de FastAPI 0.110.0, si usabas una dependencia con `yield`, y luego capturabas una excepción con `except` en esa dependencia, y no volvías a elevar la excepción, la excepción se elevaría/remitiría automáticamente a cualquier manejador de excepciones o al manejador de error interno del servidor.\n\nEsto cambió en la versión 0.110.0 para arreglar consumo de memoria no manejado por excepciones reenviadas sin un manejador (errores internos del servidor), y para hacerlo consistente con el comportamiento del código Python normal.\n\n### Tareas en segundo plano y dependencias con `yield`, detalles técnicos { #background-tasks-and-dependencies-with-yield-technical-details }\n\nAntes de FastAPI 0.106.0, elevar excepciones después de `yield` no era posible, el código de salida en dependencias con `yield` se ejecutaba después de que la response era enviada, por lo que [Manejadores de Excepciones](../tutorial/handling-errors.md#install-custom-exception-handlers) ya habrían corrido.\n\nEsto se diseñó así principalmente para permitir usar los mismos objetos devueltos con `yield` por las dependencias dentro de tareas en segundo plano, porque el código de salida se ejecutaría después de que las tareas en segundo plano terminaran.\n\nEsto cambió en FastAPI 0.106.0 con la intención de no retener recursos mientras se espera a que la response viaje por la red.\n\n/// tip | Consejo\n\nAdicionalmente, una tarea en segundo plano normalmente es un conjunto independiente de lógica que debería manejarse por separado, con sus propios recursos (por ejemplo, su propia conexión a la base de datos).\n\nAsí, probablemente tendrás un código más limpio.\n\n///\n\nSi solías depender de este comportamiento, ahora deberías crear los recursos para las tareas en segundo plano dentro de la propia tarea en segundo plano, y usar internamente solo datos que no dependan de los recursos de dependencias con `yield`.\n\nPor ejemplo, en lugar de usar la misma sesión de base de datos, crearías una nueva sesión de base de datos dentro de la tarea en segundo plano, y obtendrías los objetos de la base de datos usando esta nueva sesión. Y entonces, en lugar de pasar el objeto de la base de datos como parámetro a la función de la tarea en segundo plano, pasarías el ID de ese objeto y luego obtendrías el objeto de nuevo dentro de la función de la tarea en segundo plano.\n"
  },
  {
    "path": "docs/es/docs/advanced/advanced-python-types.md",
    "content": "# Tipos avanzados de Python { #advanced-python-types }\n\nAquí tienes algunas ideas adicionales que podrían ser útiles al trabajar con tipos de Python.\n\n## Usar `Union` u `Optional` { #using-union-or-optional }\n\nSi por alguna razón tu código no puede usar `|`, por ejemplo si no está en una anotación de tipos sino en algo como `response_model=`, en lugar de usar la barra vertical (`|`) puedes usar `Union` de `typing`.\n\nPor ejemplo, podrías declarar que algo podría ser un `str` o `None`:\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\n`typing` también tiene un atajo para declarar que algo podría ser `None`, con `Optional`.\n\nAquí va un Consejo desde mi punto de vista muy subjetivo:\n\n* 🚨 Evita usar `Optional[SomeType]`\n* En su lugar ✨ **usa `Union[SomeType, None]`** ✨.\n\nAmbas son equivalentes y por debajo son lo mismo, pero recomendaría `Union` en lugar de `Optional` porque la palabra \"**optional**\" parecería implicar que el valor es opcional, y en realidad significa \"puede ser `None`\", incluso si no es opcional y sigue siendo requerido.\n\nCreo que `Union[SomeType, None]` es más explícito respecto a lo que significa.\n\nSe trata solo de palabras y nombres. Pero esas palabras pueden afectar cómo tú y tu equipo piensan sobre el código.\n\nComo ejemplo, tomemos esta función:\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\nEl parámetro `name` está definido como `Optional[str]`, pero **no es opcional**, no puedes llamar a la función sin el parámetro:\n\n```Python\nsay_hi()  # ¡Oh, no, esto lanza un error! 😱\n```\n\nEl parámetro `name` **sigue siendo requerido** (no es *opcional*) porque no tiene un valor por defecto. Aun así, `name` acepta `None` como valor:\n\n```Python\nsay_hi(name=None)  # Esto funciona, None es válido 🎉\n```\n\nLa buena noticia es que, en la mayoría de los casos, podrás simplemente usar `|` para definir uniones de tipos:\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\nAsí que, normalmente no tienes que preocuparte por nombres como `Optional` y `Union`. 😎\n"
  },
  {
    "path": "docs/es/docs/advanced/async-tests.md",
    "content": "# Tests Asíncronos { #async-tests }\n\nYa has visto cómo probar tus aplicaciones de **FastAPI** usando el `TestClient` proporcionado. Hasta ahora, solo has visto cómo escribir tests sincrónicos, sin usar funciones `async`.\n\nPoder usar funciones asíncronas en tus tests puede ser útil, por ejemplo, cuando consultas tu base de datos de forma asíncrona. Imagina que quieres probar el envío de requests a tu aplicación FastAPI y luego verificar que tu backend escribió exitosamente los datos correctos en la base de datos, mientras usas un paquete de base de datos asíncrono.\n\nVeamos cómo podemos hacer que esto funcione.\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\nSi queremos llamar funciones asíncronas en nuestros tests, nuestras funciones de test tienen que ser asíncronas. AnyIO proporciona un plugin útil para esto, que nos permite especificar que algunas funciones de test deben ser llamadas de manera asíncrona.\n\n## HTTPX { #httpx }\n\nIncluso si tu aplicación de **FastAPI** usa funciones `def` normales en lugar de `async def`, sigue siendo una aplicación `async` por debajo.\n\nEl `TestClient` hace algo de magia interna para llamar a la aplicación FastAPI asíncrona en tus funciones de test `def` normales, usando pytest estándar. Pero esa magia ya no funciona cuando lo usamos dentro de funciones asíncronas. Al ejecutar nuestros tests de manera asíncrona, ya no podemos usar el `TestClient` dentro de nuestras funciones de test.\n\nEl `TestClient` está basado en [HTTPX](https://www.python-httpx.org), y afortunadamente, podemos usarlo directamente para probar la API.\n\n## Ejemplo { #example }\n\nPara un ejemplo simple, consideremos una estructura de archivos similar a la descrita en [Aplicaciones Más Grandes](../tutorial/bigger-applications.md) y [Testing](../tutorial/testing.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nEl archivo `main.py` tendría:\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\nEl archivo `test_main.py` tendría los tests para `main.py`, podría verse así ahora:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## Ejecútalo { #run-it }\n\nPuedes ejecutar tus tests como de costumbre vía:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## En Detalle { #in-detail }\n\nEl marcador `@pytest.mark.anyio` le dice a pytest que esta función de test debe ser llamada asíncronamente:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip | Consejo\n\nNota que la función de test ahora es `async def` en lugar de solo `def` como antes al usar el `TestClient`.\n\n///\n\nLuego podemos crear un `AsyncClient` con la app y enviar requests asíncronos a ella, usando `await`.\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\nEsto es equivalente a:\n\n```Python\nresponse = client.get('/')\n```\n\n...que usábamos para hacer nuestros requests con el `TestClient`.\n\n/// tip | Consejo\n\nNota que estamos usando async/await con el nuevo `AsyncClient`: el request es asíncrono.\n\n///\n\n/// warning | Advertencia\n\nSi tu aplicación depende de eventos de lifespan, el `AsyncClient` no activará estos eventos. Para asegurarte de que se activen, usa `LifespanManager` de [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage).\n\n///\n\n## Otras Llamadas a Funciones Asíncronas { #other-asynchronous-function-calls }\n\nAl ser la función de test asíncrona, ahora también puedes llamar (y `await`) otras funciones `async` además de enviar requests a tu aplicación FastAPI en tus tests, exactamente como las llamarías en cualquier otro lugar de tu código.\n\n/// tip | Consejo\n\nSi encuentras un `RuntimeError: Task attached to a different loop` al integrar llamadas a funciones asíncronas en tus tests (por ejemplo, cuando usas [MotorClient de MongoDB](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop)), recuerda crear instances de objetos que necesiten un loop de eventos solo dentro de funciones async, por ejemplo, en un callback `@app.on_event(\"startup\")`.\n\n///\n"
  },
  {
    "path": "docs/es/docs/advanced/behind-a-proxy.md",
    "content": "# Detrás de un Proxy { #behind-a-proxy }\n\nEn muchas situaciones, usarías un **proxy** como Traefik o Nginx delante de tu app de FastAPI.\n\nEstos proxies podrían manejar certificados HTTPS y otras cosas.\n\n## Headers reenviados por el Proxy { #proxy-forwarded-headers }\n\nUn **proxy** delante de tu aplicación normalmente establecería algunos headers sobre la marcha antes de enviar los requests a tu **server** para que el servidor sepa que el request fue **reenviado** por el proxy, informándole la URL original (pública), incluyendo el dominio, que está usando HTTPS, etc.\n\nEl programa **server** (por ejemplo **Uvicorn** a través de **FastAPI CLI**) es capaz de interpretar esos headers, y luego pasar esa información a tu aplicación.\n\nPero por seguridad, como el server no sabe que está detrás de un proxy confiable, no interpretará esos headers.\n\n/// note | Detalles Técnicos\n\nLos headers del proxy son:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### Habilitar headers reenviados por el Proxy { #enable-proxy-forwarded-headers }\n\nPuedes iniciar FastAPI CLI con la *Opción de CLI* `--forwarded-allow-ips` y pasar las direcciones IP que deberían ser confiables para leer esos headers reenviados.\n\nSi lo estableces a `--forwarded-allow-ips=\"*\"`, confiaría en todas las IPs entrantes.\n\nSi tu **server** está detrás de un **proxy** confiable y solo el proxy le habla, esto haría que acepte cualquiera que sea la IP de ese **proxy**.\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Redirecciones con HTTPS { #redirects-with-https }\n\nPor ejemplo, digamos que defines una *path operation* `/items/`:\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\nSi el cliente intenta ir a `/items`, por defecto, sería redirigido a `/items/`.\n\nPero antes de configurar la *Opción de CLI* `--forwarded-allow-ips` podría redirigir a `http://localhost:8000/items/`.\n\nPero quizá tu aplicación está alojada en `https://mysuperapp.com`, y la redirección debería ser a `https://mysuperapp.com/items/`.\n\nAl configurar `--proxy-headers` ahora FastAPI podrá redirigir a la ubicación correcta. 😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip | Consejo\n\nSi quieres aprender más sobre HTTPS, revisa la guía [Acerca de HTTPS](../deployment/https.md).\n\n///\n\n### Cómo funcionan los headers reenviados por el Proxy { #how-proxy-forwarded-headers-work }\n\nAquí tienes una representación visual de cómo el **proxy** añade headers reenviados entre el cliente y el **application server**:\n\n```mermaid\nsequenceDiagram\n    participant Client as Cliente\n    participant Proxy as Proxy/Load Balancer\n    participant Server as Servidor de FastAPI\n\n    Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: El proxy añade headers reenviados\n\n    Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: El servidor interpreta los headers<br/>(si --forwarded-allow-ips está configurado)\n\n    Server->>Proxy: HTTP Response<br/>con URLs HTTPS correctas\n\n    Proxy->>Client: HTTPS Response\n```\n\nEl **proxy** intercepta el request original del cliente y añade los *headers* especiales de reenvío (`X-Forwarded-*`) antes de pasar el request al **application server**.\n\nEstos headers preservan información sobre el request original que de otro modo se perdería:\n\n* **X-Forwarded-For**: La IP original del cliente\n* **X-Forwarded-Proto**: El protocolo original (`https`)\n* **X-Forwarded-Host**: El host original (`mysuperapp.com`)\n\nCuando **FastAPI CLI** está configurado con `--forwarded-allow-ips`, confía en estos headers y los usa, por ejemplo para generar las URLs correctas en redirecciones.\n\n## Proxy con un prefijo de path eliminado { #proxy-with-a-stripped-path-prefix }\n\nPodrías tener un proxy que añada un prefijo de path a tu aplicación.\n\nEn estos casos, puedes usar `root_path` para configurar tu aplicación.\n\nEl `root_path` es un mecanismo proporcionado por la especificación ASGI (en la que está construido FastAPI, a través de Starlette).\n\nEl `root_path` se usa para manejar estos casos específicos.\n\nY también se usa internamente al montar subaplicaciones.\n\nTener un proxy con un prefijo de path eliminado, en este caso, significa que podrías declarar un path en `/app` en tu código, pero luego añades una capa encima (el proxy) que situaría tu aplicación **FastAPI** bajo un path como `/api/v1`.\n\nEn este caso, el path original `/app` realmente sería servido en `/api/v1/app`.\n\nAunque todo tu código esté escrito asumiendo que solo existe `/app`.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\nY el proxy estaría **\"eliminando\"** el **prefijo del path** sobre la marcha antes de transmitir el request al servidor de aplicaciones (probablemente Uvicorn a través de FastAPI CLI), manteniendo a tu aplicación convencida de que está siendo servida en `/app`, así que no tienes que actualizar todo tu código para incluir el prefijo `/api/v1`.\n\nHasta aquí, todo funcionaría normalmente.\n\nPero luego, cuando abres la UI integrada de los docs (el frontend), esperaría obtener el esquema de OpenAPI en `/openapi.json`, en lugar de `/api/v1/openapi.json`.\n\nEntonces, el frontend (que se ejecuta en el navegador) trataría de alcanzar `/openapi.json` y no podría obtener el esquema de OpenAPI.\n\nPorque tenemos un proxy con un prefijo de path de `/api/v1` para nuestra aplicación, el frontend necesita obtener el esquema de OpenAPI en `/api/v1/openapi.json`.\n\n```mermaid\ngraph LR\n\nbrowser(\"Navegador\")\nproxy[\"Proxy en http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Servidor en http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip | Consejo\n\nLa IP `0.0.0.0` se usa comúnmente para indicar que el programa escucha en todas las IPs disponibles en esa máquina/servidor.\n\n///\n\nLa UI de los docs también necesitaría el esquema de OpenAPI para declarar que este API `servidor` se encuentra en `/api/v1` (detrás del proxy). Por ejemplo:\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // Más cosas aquí\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // Más cosas aquí\n    }\n}\n```\n\nEn este ejemplo, el \"Proxy\" podría ser algo como **Traefik**. Y el servidor sería algo como FastAPI CLI con **Uvicorn**, ejecutando tu aplicación de FastAPI.\n\n### Proporcionando el `root_path` { #providing-the-root-path }\n\nPara lograr esto, puedes usar la opción de línea de comandos `--root-path` como:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nSi usas Hypercorn, también tiene la opción `--root-path`.\n\n/// note | Detalles Técnicos\n\nLa especificación ASGI define un `root_path` para este caso de uso.\n\nY la opción de línea de comandos `--root-path` proporciona ese `root_path`.\n\n///\n\n### Revisar el `root_path` actual { #checking-the-current-root-path }\n\nPuedes obtener el `root_path` actual utilizado por tu aplicación para cada request, es parte del diccionario `scope` (que es parte de la especificación ASGI).\n\nAquí lo estamos incluyendo en el mensaje solo con fines de demostración.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\nLuego, si inicias Uvicorn con:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nEl response sería algo como:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### Configurar el `root_path` en la app de FastAPI { #setting-the-root-path-in-the-fastapi-app }\n\nAlternativamente, si no tienes una forma de proporcionar una opción de línea de comandos como `--root-path` o su equivalente, puedes configurar el parámetro `root_path` al crear tu app de FastAPI:\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\nPasar el `root_path` a `FastAPI` sería el equivalente a pasar la opción de línea de comandos `--root-path` a Uvicorn o Hypercorn.\n\n### Acerca de `root_path` { #about-root-path }\n\nTen en cuenta que el servidor (Uvicorn) no usará ese `root_path` para nada, a excepción de pasárselo a la app.\n\nPero si vas con tu navegador a [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app) verás el response normal:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nAsí que no se esperará que sea accedido en `http://127.0.0.1:8000/api/v1/app`.\n\nUvicorn esperará que el proxy acceda a Uvicorn en `http://127.0.0.1:8000/app`, y luego será responsabilidad del proxy añadir el prefijo extra `/api/v1` encima.\n\n## Sobre proxies con un prefijo de path eliminado { #about-proxies-with-a-stripped-path-prefix }\n\nTen en cuenta que un proxy con prefijo de path eliminado es solo una de las formas de configurarlo.\n\nProbablemente en muchos casos, el valor por defecto será que el proxy no tenga un prefijo de path eliminado.\n\nEn un caso así (sin un prefijo de path eliminado), el proxy escucharía algo como `https://myawesomeapp.com`, y luego si el navegador va a `https://myawesomeapp.com/api/v1/app` y tu servidor (por ejemplo, Uvicorn) escucha en `http://127.0.0.1:8000`, el proxy (sin un prefijo de path eliminado) accedería a Uvicorn en el mismo path: `http://127.0.0.1:8000/api/v1/app`.\n\n## Probando localmente con Traefik { #testing-locally-with-traefik }\n\nPuedes ejecutar fácilmente el experimento localmente con un prefijo de path eliminado usando [Traefik](https://docs.traefik.io/).\n\n[Descarga Traefik](https://github.com/containous/traefik/releases), es un archivo binario único, puedes extraer el archivo comprimido y ejecutarlo directamente desde la terminal.\n\nLuego crea un archivo `traefik.toml` con:\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\nEsto le dice a Traefik que escuche en el puerto 9999 y que use otro archivo `routes.toml`.\n\n/// tip | Consejo\n\nEstamos utilizando el puerto 9999 en lugar del puerto HTTP estándar 80 para que no tengas que ejecutarlo con privilegios de administrador (`sudo`).\n\n///\n\nAhora crea ese otro archivo `routes.toml`:\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\nEste archivo configura Traefik para usar el prefijo de path `/api/v1`.\n\nY luego Traefik redireccionará sus requests a tu Uvicorn ejecutándose en `http://127.0.0.1:8000`.\n\nAhora inicia Traefik:\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\nY ahora inicia tu app, utilizando la opción `--root-path`:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Revisa los responses { #check-the-responses }\n\nAhora, si vas a la URL con el puerto para Uvicorn: [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), verás el response normal:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip | Consejo\n\nNota que incluso aunque estés accediendo en `http://127.0.0.1:8000/app`, muestra el `root_path` de `/api/v1`, tomado de la opción `--root-path`.\n\n///\n\nY ahora abre la URL con el puerto para Traefik, incluyendo el prefijo de path: [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app).\n\nObtenemos el mismo response:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\npero esta vez en la URL con el prefijo de path proporcionado por el proxy: `/api/v1`.\n\nPor supuesto, la idea aquí es que todos accedan a la app a través del proxy, así que la versión con el prefijo de path `/api/v1` es la \"correcta\".\n\nY la versión sin el prefijo de path (`http://127.0.0.1:8000/app`), proporcionada directamente por Uvicorn, sería exclusivamente para que el _proxy_ (Traefik) la acceda.\n\nEso demuestra cómo el Proxy (Traefik) usa el prefijo de path y cómo el servidor (Uvicorn) usa el `root_path` de la opción `--root-path`.\n\n### Revisa la UI de los docs { #check-the-docs-ui }\n\nPero aquí está la parte divertida. ✨\n\nLa forma \"oficial\" de acceder a la app sería a través del proxy con el prefijo de path que definimos. Así que, como esperaríamos, si intentas usar la UI de los docs servida por Uvicorn directamente, sin el prefijo de path en la URL, no funcionará, porque espera ser accedida a través del proxy.\n\nPuedes verificarlo en [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\nPero si accedemos a la UI de los docs en la URL \"oficial\" usando el proxy con puerto `9999`, en `/api/v1/docs`, ¡funciona correctamente! 🎉\n\nPuedes verificarlo en [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\nJusto como queríamos. ✔️\n\nEsto es porque FastAPI usa este `root_path` para crear el `server` por defecto en OpenAPI con la URL proporcionada por `root_path`.\n\n## Servidores adicionales { #additional-servers }\n\n/// warning | Advertencia\n\nEste es un caso de uso más avanzado. Siéntete libre de omitirlo.\n\n///\n\nPor defecto, **FastAPI** creará un `server` en el esquema de OpenAPI con la URL para el `root_path`.\n\nPero también puedes proporcionar otros `servers` alternativos, por ejemplo, si deseas que *la misma* UI de los docs interactúe con un entorno de pruebas y de producción.\n\nSi pasas una lista personalizada de `servers` y hay un `root_path` (porque tu API existe detrás de un proxy), **FastAPI** insertará un \"server\" con este `root_path` al comienzo de la lista.\n\nPor ejemplo:\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\nGenerará un esquema de OpenAPI como:\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // Más cosas aquí\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // Más cosas aquí\n    }\n}\n```\n\n/// tip | Consejo\n\nObserva el server auto-generado con un valor `url` de `/api/v1`, tomado del `root_path`.\n\n///\n\nEn la UI de los docs en [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) se vería como:\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip | Consejo\n\nLa UI de los docs interactuará con el server que selecciones.\n\n///\n\n/// note | Detalles Técnicos\n\nLa propiedad `servers` en la especificación de OpenAPI es opcional.\n\nSi no especificas el parámetro `servers` y `root_path` es igual a `/`, la propiedad `servers` en el esquema de OpenAPI generado se omitirá por completo por defecto, lo cual es equivalente a un único server con un valor `url` de `/`.\n\n///\n\n### Desactivar el server automático de `root_path` { #disable-automatic-server-from-root-path }\n\nSi no quieres que **FastAPI** incluya un server automático usando el `root_path`, puedes usar el parámetro `root_path_in_servers=False`:\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\ny entonces no lo incluirá en el esquema de OpenAPI.\n\n## Montando una sub-aplicación { #mounting-a-sub-application }\n\nSi necesitas montar una sub-aplicación (como se describe en [Aplicaciones secundarias - Monturas](sub-applications.md)) mientras usas un proxy con `root_path`, puedes hacerlo normalmente, como esperarías.\n\nFastAPI usará internamente el `root_path` de manera inteligente, así que simplemente funcionará. ✨\n"
  },
  {
    "path": "docs/es/docs/advanced/custom-response.md",
    "content": "# Response Personalizado - HTML, Stream, Archivo, otros { #custom-response-html-stream-file-others }\n\nPor defecto, **FastAPI** devolverá responses JSON.\n\nPuedes sobrescribirlo devolviendo un `Response` directamente como se ve en [Devolver una Response directamente](response-directly.md).\n\nPero si devuelves un `Response` directamente (o cualquier subclase, como `JSONResponse`), los datos no se convertirán automáticamente (incluso si declaras un `response_model`), y la documentación no se generará automáticamente (por ejemplo, incluyendo el \"media type\" específico, en el HTTP header `Content-Type` como parte del OpenAPI generado).\n\nPero también puedes declarar el `Response` que quieres usar (por ejemplo, cualquier subclase de `Response`), en el *path operation decorator* usando el parámetro `response_class`.\n\nLos contenidos que devuelvas desde tu *path operation function* se colocarán dentro de esa `Response`.\n\n/// note | Nota\n\nSi usas una clase de response sin media type, FastAPI esperará que tu response no tenga contenido, por lo que no documentará el formato del response en su OpenAPI generado.\n\n///\n\n## Responses JSON { #json-responses }\n\nPor defecto FastAPI devuelve responses JSON.\n\nSi declaras un [Response Model](../tutorial/response-model.md) FastAPI lo usará para serializar los datos a JSON, usando Pydantic.\n\nSi no declaras un response model, FastAPI usará el `jsonable_encoder` explicado en [Codificador Compatible con JSON](../tutorial/encoder.md) y lo pondrá en un `JSONResponse`.\n\nSi declaras un `response_class` con un media type JSON (`application/json`), como es el caso con `JSONResponse`, los datos que devuelvas se convertirán automáticamente (y serán filtrados) con cualquier `response_model` de Pydantic que hayas declarado en el *path operation decorator*. Pero los datos no se serializarán a bytes JSON con Pydantic, en su lugar se convertirán con el `jsonable_encoder` y luego se pasarán a la clase `JSONResponse`, que los serializará a bytes usando la librería JSON estándar de Python.\n\n### Rendimiento JSON { #json-performance }\n\nEn resumen, si quieres el máximo rendimiento, usa un [Response Model](../tutorial/response-model.md) y no declares un `response_class` en el *path operation decorator*.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## Response HTML { #html-response }\n\nPara devolver un response con HTML directamente desde **FastAPI**, usa `HTMLResponse`.\n\n* Importa `HTMLResponse`.\n* Pasa `HTMLResponse` como parámetro `response_class` de tu *path operation decorator*.\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info | Información\n\nEl parámetro `response_class` también se utilizará para definir el \"media type\" del response.\n\nEn este caso, el HTTP header `Content-Type` se establecerá en `text/html`.\n\nY se documentará así en OpenAPI.\n\n///\n\n### Devuelve una `Response` { #return-a-response }\n\nComo se ve en [Devolver una Response directamente](response-directly.md), también puedes sobrescribir el response directamente en tu *path operation*, devolviéndolo.\n\nEl mismo ejemplo de arriba, devolviendo una `HTMLResponse`, podría verse así:\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning | Advertencia\n\nUna `Response` devuelta directamente por tu *path operation function* no se documentará en OpenAPI (por ejemplo, el `Content-Type` no se documentará) y no será visible en la documentación interactiva automática.\n\n///\n\n/// info | Información\n\nPor supuesto, el `Content-Type` header real, el código de estado, etc., provendrán del objeto `Response` que devolviste.\n\n///\n\n### Documenta en OpenAPI y sobrescribe `Response` { #document-in-openapi-and-override-response }\n\nSi quieres sobrescribir el response desde dentro de la función pero al mismo tiempo documentar el \"media type\" en OpenAPI, puedes usar el parámetro `response_class` Y devolver un objeto `Response`.\n\nEl `response_class` solo se usará para documentar el OpenAPI *path operation*, pero tu `Response` se usará tal cual.\n\n#### Devuelve un `HTMLResponse` directamente { #return-an-htmlresponse-directly }\n\nPor ejemplo, podría ser algo así:\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\nEn este ejemplo, la función `generate_html_response()` ya genera y devuelve una `Response` en lugar de devolver el HTML en un `str`.\n\nAl devolver el resultado de llamar a `generate_html_response()`, ya estás devolviendo una `Response` que sobrescribirá el comportamiento por defecto de **FastAPI**.\n\nPero como pasaste `HTMLResponse` en el `response_class` también, **FastAPI** sabrá cómo documentarlo en OpenAPI y la documentación interactiva como HTML con `text/html`:\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## Responses disponibles { #available-responses }\n\nAquí hay algunos de los responses disponibles.\n\nTen en cuenta que puedes usar `Response` para devolver cualquier otra cosa, o incluso crear una sub-clase personalizada.\n\n/// note | Nota Técnica\n\nTambién podrías usar `from starlette.responses import HTMLResponse`.\n\n**FastAPI** proporciona los mismos `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.\n\n///\n\n### `Response` { #response }\n\nLa clase principal `Response`, todos los otros responses heredan de ella.\n\nPuedes devolverla directamente.\n\nAcepta los siguientes parámetros:\n\n* `content` - Un `str` o `bytes`.\n* `status_code` - Un código de estado HTTP `int`.\n* `headers` - Un `dict` de strings.\n* `media_type` - Un `str` que da el media type. Por ejemplo, `\"text/html\"`.\n\nFastAPI (de hecho Starlette) incluirá automáticamente un header Content-Length. También incluirá un header Content-Type, basado en el `media_type` y añadiendo un conjunto de caracteres para tipos de texto.\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\nToma algún texto o bytes y devuelve un response HTML, como leíste arriba.\n\n### `PlainTextResponse` { #plaintextresponse }\n\nToma algún texto o bytes y devuelve un response de texto plano.\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\nToma algunos datos y devuelve un response codificado como `application/json`.\n\nEste es el response usado por defecto en **FastAPI**, como leíste arriba.\n\n/// note | Nota Técnica\n\nPero si declaras un response model o un tipo de retorno, eso se usará directamente para serializar los datos a JSON, y se devolverá directamente un response con el media type correcto para JSON, sin usar la clase `JSONResponse`.\n\nEsta es la forma ideal de obtener el mejor rendimiento.\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\nDevuelve una redirección HTTP. Usa un código de estado 307 (Redirección Temporal) por defecto.\n\nPuedes devolver un `RedirectResponse` directamente:\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\nO puedes usarlo en el parámetro `response_class`:\n\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\nSi haces eso, entonces puedes devolver la URL directamente desde tu *path operation* function.\n\nEn este caso, el `status_code` utilizado será el por defecto para `RedirectResponse`, que es `307`.\n\n---\n\nTambién puedes usar el parámetro `status_code` combinado con el parámetro `response_class`:\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\nToma un generador `async` o un generador/iterador normal (una función con `yield`) y transmite el cuerpo del response.\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | Nota Técnica\n\nUna tarea `async` solo puede cancelarse cuando llega a un `await`. Si no hay `await`, el generador (función con `yield`) no se puede cancelar correctamente y puede seguir ejecutándose incluso después de solicitar la cancelación.\n\nComo este pequeño ejemplo no necesita ninguna sentencia `await`, añadimos un `await anyio.sleep(0)` para darle al loop de eventos la oportunidad de manejar la cancelación.\n\nEsto sería aún más importante con streams grandes o infinitos.\n\n///\n\n/// tip | Consejo\n\nEn lugar de devolver un `StreamingResponse` directamente, probablemente deberías seguir el estilo en [Stream Data](./stream-data.md), es mucho más conveniente y maneja la cancelación por detrás de escena por ti.\n\nSi estás transmitiendo JSON Lines, sigue el tutorial [Stream JSON Lines](../tutorial/stream-json-lines.md).\n\n///\n\n### `FileResponse` { #fileresponse }\n\nTransmite un archivo asincrónicamente como response.\n\nToma un conjunto diferente de argumentos para crear un instance que los otros tipos de response:\n\n* `path` - La path del archivo para el archivo a transmitir.\n* `headers` - Cualquier header personalizado para incluir, como un diccionario.\n* `media_type` - Un string que da el media type. Si no se establece, se usará el nombre de archivo o la path para inferir un media type.\n* `filename` - Si se establece, se incluirá en el response `Content-Disposition`.\n\nLos responses de archivos incluirán los headers apropiados `Content-Length`, `Last-Modified` y `ETag`.\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\nTambién puedes usar el parámetro `response_class`:\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\nEn este caso, puedes devolver la path del archivo directamente desde tu *path operation* function.\n\n## Clase de response personalizada { #custom-response-class }\n\nPuedes crear tu propia clase de response personalizada, heredando de `Response` y usándola.\n\nPor ejemplo, digamos que quieres usar [`orjson`](https://github.com/ijl/orjson) con algunas configuraciones.\n\nDigamos que quieres que devuelva JSON con sangría y formato, por lo que quieres usar la opción de orjson `orjson.OPT_INDENT_2`.\n\nPodrías crear un `CustomORJSONResponse`. Lo principal que tienes que hacer es crear un método `Response.render(content)` que devuelva el contenido como `bytes`:\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\nAhora en lugar de devolver:\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n...este response devolverá:\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\nPor supuesto, probablemente encontrarás formas mucho mejores de aprovechar esto que formatear JSON. 😉\n\n### `orjson` o Response Model { #orjson-or-response-model }\n\nSi lo que buscas es rendimiento, probablemente te convenga más usar un [Response Model](../tutorial/response-model.md) que un response con `orjson`.\n\nCon un response model, FastAPI usará Pydantic para serializar los datos a JSON, sin pasos intermedios, como convertirlos con `jsonable_encoder`, que ocurriría en cualquier otro caso.\n\nY por debajo, Pydantic usa los mismos mecanismos en Rust que `orjson` para serializar a JSON, así que ya obtendrás el mejor rendimiento con un response model.\n\n## Clase de response por defecto { #default-response-class }\n\nAl crear una instance de la clase **FastAPI** o un `APIRouter`, puedes especificar qué clase de response usar por defecto.\n\nEl parámetro que define esto es `default_response_class`.\n\nEn el ejemplo a continuación, **FastAPI** usará `HTMLResponse` por defecto, en todas las *path operations*, en lugar de JSON.\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip | Consejo\n\nTodavía puedes sobrescribir `response_class` en *path operations* como antes.\n\n///\n\n## Documentación adicional { #additional-documentation }\n\nTambién puedes declarar el media type y muchos otros detalles en OpenAPI usando `responses`: [Responses Adicionales en OpenAPI](additional-responses.md).\n"
  },
  {
    "path": "docs/es/docs/advanced/dataclasses.md",
    "content": "# Usando Dataclasses { #using-dataclasses }\n\nFastAPI está construido sobre **Pydantic**, y te he estado mostrando cómo usar modelos de Pydantic para declarar requests y responses.\n\nPero FastAPI también soporta el uso de [`dataclasses`](https://docs.python.org/3/library/dataclasses.html) de la misma manera:\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\nEsto sigue siendo soportado gracias a **Pydantic**, ya que tiene [soporte interno para `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).\n\nAsí que, incluso con el código anterior que no usa Pydantic explícitamente, FastAPI está usando Pydantic para convertir esos dataclasses estándar en su propia versión de dataclasses de Pydantic.\n\nY por supuesto, soporta lo mismo:\n\n* validación de datos\n* serialización de datos\n* documentación de datos, etc.\n\nEsto funciona de la misma manera que con los modelos de Pydantic. Y en realidad se logra de la misma manera internamente, utilizando Pydantic.\n\n/// info | Información\n\nTen en cuenta que los dataclasses no pueden hacer todo lo que los modelos de Pydantic pueden hacer.\n\nAsí que, podrías necesitar seguir usando modelos de Pydantic.\n\nPero si tienes un montón de dataclasses por ahí, este es un buen truco para usarlos para potenciar una API web usando FastAPI. 🤓\n\n///\n\n## Dataclasses en `response_model` { #dataclasses-in-response-model }\n\nTambién puedes usar `dataclasses` en el parámetro `response_model`:\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\nEl dataclass será automáticamente convertido a un dataclass de Pydantic.\n\nDe esta manera, su esquema aparecerá en la interfaz de usuario de la documentación de la API:\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## Dataclasses en Estructuras de Datos Anidadas { #dataclasses-in-nested-data-structures }\n\nTambién puedes combinar `dataclasses` con otras anotaciones de tipos para crear estructuras de datos anidadas.\n\nEn algunos casos, todavía podrías tener que usar la versión de `dataclasses` de Pydantic. Por ejemplo, si tienes errores con la documentación de la API generada automáticamente.\n\nEn ese caso, simplemente puedes intercambiar los `dataclasses` estándar con `pydantic.dataclasses`, que es un reemplazo directo:\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. Todavía importamos `field` de los `dataclasses` estándar.\n\n2. `pydantic.dataclasses` es un reemplazo directo para `dataclasses`.\n\n3. El dataclass `Author` incluye una lista de dataclasses `Item`.\n\n4. El dataclass `Author` se usa como el parámetro `response_model`.\n\n5. Puedes usar otras anotaciones de tipos estándar con dataclasses como el request body.\n\n    En este caso, es una lista de dataclasses `Item`.\n\n6. Aquí estamos regresando un diccionario que contiene `items`, que es una lista de dataclasses.\n\n    FastAPI todavía es capaz de <dfn title=\"convertir los datos a un formato que pueda transmitirse\">serializar</dfn> los datos a JSON.\n\n7. Aquí el `response_model` está usando una anotación de tipo de una lista de dataclasses `Author`.\n\n    Nuevamente, puedes combinar `dataclasses` con anotaciones de tipos estándar.\n\n8. Nota que esta *path operation function* usa `def` regular en lugar de `async def`.\n\n    Como siempre, en FastAPI puedes combinar `def` y `async def` según sea necesario.\n\n    Si necesitas un repaso sobre cuándo usar cuál, revisa la sección _\"¿Con prisa?\"_ en la documentación sobre [`async` y `await`](../async.md#in-a-hurry).\n\n9. Esta *path operation function* no está devolviendo dataclasses (aunque podría), sino una lista de diccionarios con datos internos.\n\n    FastAPI usará el parámetro `response_model` (que incluye dataclasses) para convertir el response.\n\nPuedes combinar `dataclasses` con otras anotaciones de tipos en muchas combinaciones diferentes para formar estructuras de datos complejas.\n\nRevisa las anotaciones en el código arriba para ver más detalles específicos.\n\n## Aprende Más { #learn-more }\n\nTambién puedes combinar `dataclasses` con otros modelos de Pydantic, heredar de ellos, incluirlos en tus propios modelos, etc.\n\nPara saber más, revisa la [documentación de Pydantic sobre dataclasses](https://docs.pydantic.dev/latest/concepts/dataclasses/).\n\n## Versión { #version }\n\nEsto está disponible desde la versión `0.67.0` de FastAPI. 🔖\n"
  },
  {
    "path": "docs/es/docs/advanced/events.md",
    "content": "# Eventos de Lifespan { #lifespan-events }\n\nPuedes definir lógica (código) que debería ser ejecutada antes de que la aplicación **inicie**. Esto significa que este código será ejecutado **una vez**, **antes** de que la aplicación **comience a recibir requests**.\n\nDe la misma manera, puedes definir lógica (código) que debería ser ejecutada cuando la aplicación esté **cerrándose**. En este caso, este código será ejecutado **una vez**, **después** de haber manejado posiblemente **muchos requests**.\n\nDebido a que este código se ejecuta antes de que la aplicación **comience** a tomar requests, y justo después de que **termine** de manejarlos, cubre todo el **lifespan** de la aplicación (la palabra \"lifespan\" será importante en un momento 😉).\n\nEsto puede ser muy útil para configurar **recursos** que necesitas usar para toda la app, y que son **compartidos** entre requests, y/o que necesitas **limpiar** después. Por ejemplo, un pool de conexiones a una base de datos, o cargando un modelo de machine learning compartido.\n\n## Caso de Uso { #use-case }\n\nEmpecemos con un ejemplo de **caso de uso** y luego veamos cómo resolverlo con esto.\n\nImaginemos que tienes algunos **modelos de machine learning** que quieres usar para manejar requests. 🤖\n\nLos mismos modelos son compartidos entre requests, por lo que no es un modelo por request, o uno por usuario o algo similar.\n\nImaginemos que cargar el modelo puede **tomar bastante tiempo**, porque tiene que leer muchos **datos del disco**. Entonces no quieres hacerlo para cada request.\n\nPodrías cargarlo en el nivel superior del módulo/archivo, pero eso también significaría que **cargaría el modelo** incluso si solo estás ejecutando una simple prueba automatizada, entonces esa prueba sería **lenta** porque tendría que esperar a que el modelo se cargue antes de poder ejecutar una parte independiente del código.\n\nEso es lo que resolveremos, vamos a cargar el modelo antes de que los requests sean manejados, pero solo justo antes de que la aplicación comience a recibir requests, no mientras el código se está cargando.\n\n## Lifespan { #lifespan }\n\nPuedes definir esta lógica de *startup* y *shutdown* usando el parámetro `lifespan` de la app de `FastAPI`, y un \"context manager\" (te mostraré lo que es en un momento).\n\nComencemos con un ejemplo y luego veámoslo en detalle.\n\nCreamos una función asíncrona `lifespan()` con `yield` así:\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\nAquí estamos simulando la operación costosa de *startup* de cargar el modelo poniendo la función del (falso) modelo en el diccionario con modelos de machine learning antes del `yield`. Este código será ejecutado **antes** de que la aplicación **comience a tomar requests**, durante el *startup*.\n\nY luego, justo después del `yield`, quitaremos el modelo de memoria. Este código será ejecutado **después** de que la aplicación **termine de manejar requests**, justo antes del *shutdown*. Esto podría, por ejemplo, liberar recursos como la memoria o una GPU.\n\n/// tip | Consejo\n\nEl `shutdown` ocurriría cuando estás **deteniendo** la aplicación.\n\nQuizás necesites iniciar una nueva versión, o simplemente te cansaste de ejecutarla. 🤷\n\n///\n\n### Función de Lifespan { #lifespan-function }\n\nLo primero que hay que notar es que estamos definiendo una función asíncrona con `yield`. Esto es muy similar a las Dependencias con `yield`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\nLa primera parte de la función, antes del `yield`, será ejecutada **antes** de que la aplicación comience.\n\nY la parte después del `yield` será ejecutada **después** de que la aplicación haya terminado.\n\n### Async Context Manager { #async-context-manager }\n\nSi revisas, la función está decorada con un `@asynccontextmanager`.\n\nEso convierte a la función en algo llamado un \"**async context manager**\".\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\nUn **context manager** en Python es algo que puedes usar en un statement `with`, por ejemplo, `open()` puede ser usado como un context manager:\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\nEn versiones recientes de Python, también hay un **async context manager**. Lo usarías con `async with`:\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\nCuando creas un context manager o un async context manager como arriba, lo que hace es que, antes de entrar al bloque `with`, ejecutará el código antes del `yield`, y al salir del bloque `with`, ejecutará el código después del `yield`.\n\nEn nuestro ejemplo de código arriba, no lo usamos directamente, pero se lo pasamos a FastAPI para que lo use.\n\nEl parámetro `lifespan` de la app de `FastAPI` toma un **async context manager**, por lo que podemos pasar nuestro nuevo `lifespan` async context manager a él.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## Eventos Alternativos (obsoleto) { #alternative-events-deprecated }\n\n/// warning | Advertencia\n\nLa forma recomendada de manejar el *startup* y el *shutdown* es usando el parámetro `lifespan` de la app de `FastAPI` como se describió arriba. Si proporcionas un parámetro `lifespan`, los manejadores de eventos `startup` y `shutdown` ya no serán llamados. Es solo `lifespan` o solo los eventos, no ambos.\n\nProbablemente puedas saltarte esta parte.\n\n///\n\nHay una forma alternativa de definir esta lógica para ser ejecutada durante el *startup* y durante el *shutdown*.\n\nPuedes definir manejadores de eventos (funciones) que necesitan ser ejecutadas antes de que la aplicación se inicie, o cuando la aplicación se está cerrando.\n\nEstas funciones pueden ser declaradas con `async def` o `def` normal.\n\n### Evento `startup` { #startup-event }\n\nPara añadir una función que debería ejecutarse antes de que la aplicación inicie, declárala con el evento `\"startup\"`:\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\nEn este caso, la función manejadora del evento `startup` inicializará los ítems de la \"base de datos\" (solo un `dict`) con algunos valores.\n\nPuedes añadir más de un manejador de eventos.\n\nY tu aplicación no comenzará a recibir requests hasta que todos los manejadores de eventos `startup` hayan completado.\n\n### Evento `shutdown` { #shutdown-event }\n\nPara añadir una función que debería ejecutarse cuando la aplicación se esté cerrando, declárala con el evento `\"shutdown\"`:\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\nAquí, la función manejadora del evento `shutdown` escribirá una línea de texto `\"Application shutdown\"` a un archivo `log.txt`.\n\n/// info | Información\n\nEn la función `open()`, el `mode=\"a\"` significa \"añadir\", por lo tanto, la línea será añadida después de lo que sea que esté en ese archivo, sin sobrescribir el contenido anterior.\n\n///\n\n/// tip | Consejo\n\nNota que en este caso estamos usando una función estándar de Python `open()` que interactúa con un archivo.\n\nEntonces, involucra I/O (entrada/salida), que requiere \"esperar\" para que las cosas se escriban en el disco.\n\nPero `open()` no usa `async` y `await`.\n\nPor eso, declaramos la función manejadora del evento con `def` estándar en vez de `async def`.\n\n///\n\n### `startup` y `shutdown` juntos { #startup-and-shutdown-together }\n\nHay una gran posibilidad de que la lógica para tu *startup* y *shutdown* esté conectada, podrías querer iniciar algo y luego finalizarlo, adquirir un recurso y luego liberarlo, etc.\n\nHacer eso en funciones separadas que no comparten lógica o variables juntas es más difícil ya que necesitarías almacenar valores en variables globales o trucos similares.\n\nDebido a eso, ahora se recomienda en su lugar usar el `lifespan` como se explicó arriba.\n\n## Detalles Técnicos { #technical-details }\n\nSolo un detalle técnico para los nerds curiosos. 🤓\n\nPor debajo, en la especificación técnica ASGI, esto es parte del [Protocolo de Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), y define eventos llamados `startup` y `shutdown`.\n\n/// info | Información\n\nPuedes leer más sobre los manejadores `lifespan` de Starlette en [la documentación de `Lifespan` de Starlette](https://www.starlette.dev/lifespan/).\n\nIncluyendo cómo manejar el estado de lifespan que puede ser usado en otras áreas de tu código.\n\n///\n\n## Sub Aplicaciones { #sub-applications }\n\n🚨 Ten en cuenta que estos eventos de lifespan (startup y shutdown) solo serán ejecutados para la aplicación principal, no para [Sub Aplicaciones - Mounts](sub-applications.md).\n"
  },
  {
    "path": "docs/es/docs/advanced/generate-clients.md",
    "content": "# Generando SDKs { #generating-sdks }\n\nComo **FastAPI** está basado en la especificación **OpenAPI**, sus APIs se pueden describir en un formato estándar que muchas herramientas entienden.\n\nEsto facilita generar **documentación** actualizada, paquetes de cliente (<abbr title=\"Software Development Kits - Kits de Desarrollo de Software\">**SDKs**</abbr>) en múltiples lenguajes y **escribir pruebas** o **flujos de automatización** que se mantengan sincronizados con tu código.\n\nEn esta guía, aprenderás a generar un **SDK de TypeScript** para tu backend con FastAPI.\n\n## Generadores de SDKs de código abierto { #open-source-sdk-generators }\n\nUna opción versátil es el [OpenAPI Generator](https://openapi-generator.tech/), que soporta **muchos lenguajes de programación** y puede generar SDKs a partir de tu especificación OpenAPI.\n\nPara **clientes de TypeScript**, [Hey API](https://heyapi.dev/) es una solución diseñada específicamente, que ofrece una experiencia optimizada para el ecosistema de TypeScript.\n\nPuedes descubrir más generadores de SDK en [OpenAPI.Tools](https://openapi.tools/#sdk).\n\n/// tip | Consejo\n\nFastAPI genera automáticamente especificaciones **OpenAPI 3.1**, así que cualquier herramienta que uses debe soportar esta versión.\n\n///\n\n## Generadores de SDKs de sponsors de FastAPI { #sdk-generators-from-fastapi-sponsors }\n\nEsta sección destaca soluciones **respaldadas por empresas** y **venture-backed** de compañías que sponsorean FastAPI. Estos productos ofrecen **funcionalidades adicionales** e **integraciones** además de SDKs generados de alta calidad.\n\nAl ✨ [**sponsorear FastAPI**](../help-fastapi.md#sponsor-the-author) ✨, estas compañías ayudan a asegurar que el framework y su **ecosistema** se mantengan saludables y **sustentables**.\n\nSu sponsorship también demuestra un fuerte compromiso con la **comunidad** de FastAPI (tú), mostrando que no solo les importa ofrecer un **gran servicio**, sino también apoyar un **framework robusto y próspero**, FastAPI. 🙇\n\nPor ejemplo, podrías querer probar:\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\nAlgunas de estas soluciones también pueden ser open source u ofrecer niveles gratuitos, así que puedes probarlas sin un compromiso financiero. Hay otros generadores de SDK comerciales disponibles y se pueden encontrar en línea. 🤓\n\n## Crea un SDK de TypeScript { #create-a-typescript-sdk }\n\nEmpecemos con una aplicación simple de FastAPI:\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\nNota que las *path operations* definen los modelos que usan para el payload del request y el payload del response, usando los modelos `Item` y `ResponseMessage`.\n\n### Documentación de la API { #api-docs }\n\nSi vas a `/docs`, verás que tiene los **esquemas** para los datos a enviar en requests y recibir en responses:\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\nPuedes ver esos esquemas porque fueron declarados con los modelos en la app.\n\nEsa información está disponible en el **OpenAPI schema** de la app, y luego se muestra en la documentación de la API.\n\nY esa misma información de los modelos que está incluida en OpenAPI es lo que puede usarse para **generar el código del cliente**.\n\n### Hey API { #hey-api }\n\nUna vez que tenemos una app de FastAPI con los modelos, podemos usar Hey API para generar un cliente de TypeScript. La forma más rápida de hacerlo es con npx.\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\nEsto generará un SDK de TypeScript en `./src/client`.\n\nPuedes aprender cómo [instalar `@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started) y leer sobre el [output generado](https://heyapi.dev/openapi-ts/output) en su sitio web.\n\n### Usar el SDK { #using-the-sdk }\n\nAhora puedes importar y usar el código del cliente. Podría verse así, nota que tienes autocompletado para los métodos:\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\nTambién obtendrás autocompletado para el payload a enviar:\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip | Consejo\n\nNota el autocompletado para `name` y `price`, que fue definido en la aplicación de FastAPI, en el modelo `Item`.\n\n///\n\nTendrás errores en línea para los datos que envíes:\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\nEl objeto de response también tendrá autocompletado:\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## App de FastAPI con tags { #fastapi-app-with-tags }\n\nEn muchos casos tu app de FastAPI será más grande, y probablemente usarás tags para separar diferentes grupos de *path operations*.\n\nPor ejemplo, podrías tener una sección para **items** y otra sección para **users**, y podrían estar separadas por tags:\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### Genera un Cliente TypeScript con tags { #generate-a-typescript-client-with-tags }\n\nSi generas un cliente para una app de FastAPI usando tags, normalmente también separará el código del cliente basándose en los tags.\n\nDe esta manera podrás tener las cosas ordenadas y agrupadas correctamente para el código del cliente:\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\nEn este caso tienes:\n\n* `ItemsService`\n* `UsersService`\n\n### Nombres de los métodos del cliente { #client-method-names }\n\nAhora mismo los nombres de los métodos generados como `createItemItemsPost` no se ven muy limpios:\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n...eso es porque el generador del cliente usa el **operation ID** interno de OpenAPI para cada *path operation*.\n\nOpenAPI requiere que cada operation ID sea único a través de todas las *path operations*, por lo que FastAPI usa el **nombre de la función**, el **path**, y el **método/operación HTTP** para generar ese operation ID, porque de esa manera puede asegurarse de que los operation IDs sean únicos.\n\nPero te mostraré cómo mejorar eso a continuación. 🤓\n\n## Operation IDs personalizados y mejores nombres de métodos { #custom-operation-ids-and-better-method-names }\n\nPuedes **modificar** la forma en que estos operation IDs son **generados** para hacerlos más simples y tener **nombres de métodos más simples** en los clientes.\n\nEn este caso tendrás que asegurarte de que cada operation ID sea **único** de alguna otra manera.\n\nPor ejemplo, podrías asegurarte de que cada *path operation* tenga un tag, y luego generar el operation ID basado en el **tag** y el **name** de la *path operation* (el nombre de la función).\n\n### Función personalizada para generar ID único { #custom-generate-unique-id-function }\n\nFastAPI usa un **ID único** para cada *path operation*, se usa para el **operation ID** y también para los nombres de cualquier modelo personalizado necesario, para requests o responses.\n\nPuedes personalizar esa función. Toma un `APIRoute` y retorna un string.\n\nPor ejemplo, aquí está usando el primer tag (probablemente tendrás solo un tag) y el nombre de la *path operation* (el nombre de la función).\n\nPuedes entonces pasar esa función personalizada a **FastAPI** como el parámetro `generate_unique_id_function`:\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### Genera un Cliente TypeScript con operation IDs personalizados { #generate-a-typescript-client-with-custom-operation-ids }\n\nAhora, si generas el cliente de nuevo, verás que tiene los nombres de métodos mejorados:\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\nComo ves, los nombres de métodos ahora tienen el tag y luego el nombre de la función, ahora no incluyen información del path de la URL y la operación HTTP.\n\n### Preprocesa la especificación OpenAPI para el generador de clientes { #preprocess-the-openapi-specification-for-the-client-generator }\n\nEl código generado aún tiene algo de **información duplicada**.\n\nYa sabemos que este método está relacionado con los **items** porque esa palabra está en el `ItemsService` (tomado del tag), pero aún tenemos el nombre del tag prefijado en el nombre del método también. 😕\n\nProbablemente aún querremos mantenerlo para OpenAPI en general, ya que eso asegurará que los operation IDs sean **únicos**.\n\nPero para el cliente generado podríamos **modificar** los operation IDs de OpenAPI justo antes de generar los clientes, solo para hacer esos nombres de métodos más bonitos y **limpios**.\n\nPodríamos descargar el JSON de OpenAPI a un archivo `openapi.json` y luego podríamos **remover ese tag prefijado** con un script como este:\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\nCon eso, los operation IDs serían renombrados de cosas como `items-get_items` a solo `get_items`, de esa manera el generador del cliente puede generar nombres de métodos más simples.\n\n### Genera un Cliente TypeScript con el OpenAPI preprocesado { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\nComo el resultado final ahora está en un archivo `openapi.json`, necesitas actualizar la ubicación de la entrada:\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\nDespués de generar el nuevo cliente, ahora tendrías nombres de métodos **limpios**, con todo el **autocompletado**, **errores en línea**, etc:\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## Beneficios { #benefits }\n\nCuando uses los clientes generados automáticamente obtendrás **autocompletado** para:\n\n* Métodos.\n* Payloads de request en el body, parámetros de query, etc.\n* Payloads de response.\n\nTambién tendrás **errores en línea** para todo.\n\nY cada vez que actualices el código del backend, y **regeneres** el frontend, tendrás las nuevas *path operations* disponibles como métodos, las antiguas eliminadas, y cualquier otro cambio se reflejará en el código generado. 🤓\n\nEsto también significa que si algo cambió será **reflejado** automáticamente en el código del cliente. Y si haces **build** del cliente, dará error si tienes algún **desajuste** en los datos utilizados.\n\nAsí que, **detectarás muchos errores** muy temprano en el ciclo de desarrollo en lugar de tener que esperar a que los errores se muestren a tus usuarios finales en producción para luego intentar depurar dónde está el problema. ✨\n"
  },
  {
    "path": "docs/es/docs/advanced/index.md",
    "content": "# Guía avanzada del usuario { #advanced-user-guide }\n\n## Funcionalidades adicionales { #additional-features }\n\nEl [Tutorial - Guía del usuario](../tutorial/index.md) principal debería ser suficiente para darte un recorrido por todas las funcionalidades principales de **FastAPI**.\n\nEn las siguientes secciones verás otras opciones, configuraciones y funcionalidades adicionales.\n\n/// tip | Consejo\n\nLas siguientes secciones **no son necesariamente \"avanzadas\"**.\n\nY es posible que para tu caso de uso, la solución esté en una de ellas.\n\n///\n\n## Lee primero el Tutorial { #read-the-tutorial-first }\n\nAún podrías usar la mayoría de las funcionalidades en **FastAPI** con el conocimiento del [Tutorial - Guía del usuario](../tutorial/index.md) principal.\n\nY las siguientes secciones asumen que ya lo leíste y que conoces esas ideas principales.\n"
  },
  {
    "path": "docs/es/docs/advanced/json-base64-bytes.md",
    "content": "# JSON con Bytes como Base64 { #json-with-bytes-as-base64 }\n\nSi tu app necesita recibir y enviar datos JSON, pero necesitas incluir datos binarios en él, puedes codificarlos como base64.\n\n## Base64 vs Archivos { #base64-vs-files }\n\nConsidera primero si puedes usar [Archivos en request](../tutorial/request-files.md) para subir datos binarios y [Response personalizada - FileResponse](./custom-response.md#fileresponse--fileresponse-) para enviar datos binarios, en lugar de codificarlos en JSON.\n\nJSON solo puede contener strings codificados en UTF-8, así que no puede contener bytes crudos.\n\nBase64 puede codificar datos binarios en strings, pero para hacerlo necesita usar más caracteres que los datos binarios originales, así que normalmente sería menos eficiente que los archivos normales.\n\nUsa base64 solo si definitivamente necesitas incluir datos binarios en JSON y no puedes usar archivos para eso.\n\n## Pydantic `bytes` { #pydantic-bytes }\n\nPuedes declarar un modelo de Pydantic con campos `bytes`, y luego usar `val_json_bytes` en la configuración del modelo para indicarle que use base64 para validar datos JSON de entrada; como parte de esa validación decodificará el string base64 en bytes.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\nSi revisas `/docs`, verás que el campo `data` espera bytes codificados en base64:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\nPodrías enviar un request como:\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip | Consejo\n\n`aGVsbG8=` es la codificación base64 de `hello`.\n\n///\n\nY luego Pydantic decodificará el string base64 y te dará los bytes originales en el campo `data` del modelo.\n\nRecibirás una response como:\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## Pydantic `bytes` para datos de salida { #pydantic-bytes-for-output-data }\n\nTambién puedes usar campos `bytes` con `ser_json_bytes` en la configuración del modelo para datos de salida, y Pydantic serializará los bytes como base64 al generar la response JSON.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## Pydantic `bytes` para datos de entrada y salida { #pydantic-bytes-for-input-and-output-data }\n\nY por supuesto, puedes usar el mismo modelo configurado para usar base64 para manejar tanto la entrada (*validate*) con `val_json_bytes` como la salida (*serialize*) con `ser_json_bytes` al recibir y enviar datos JSON.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/es/docs/advanced/middleware.md",
    "content": "# Middleware Avanzado { #advanced-middleware }\n\nEn el tutorial principal leíste cómo agregar [Middleware Personalizado](../tutorial/middleware.md) a tu aplicación.\n\nY luego también leíste cómo manejar [CORS con el `CORSMiddleware`](../tutorial/cors.md).\n\nEn esta sección veremos cómo usar otros middlewares.\n\n## Agregando middlewares ASGI { #adding-asgi-middlewares }\n\nComo **FastAPI** está basado en Starlette e implementa la especificación <abbr title=\"Asynchronous Server Gateway Interface - Interfaz de puerta de enlace de servidor asíncrona\">ASGI</abbr>, puedes usar cualquier middleware ASGI.\n\nUn middleware no tiene que estar hecho para FastAPI o Starlette para funcionar, siempre que siga la especificación ASGI.\n\nEn general, los middlewares ASGI son clases que esperan recibir una aplicación ASGI como primer argumento.\n\nEntonces, en la documentación de middlewares ASGI de terceros probablemente te indicarán que hagas algo como:\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\nPero FastAPI (en realidad Starlette) proporciona una forma más simple de hacerlo que asegura que los middlewares internos manejen errores del servidor y los controladores de excepciones personalizadas funcionen correctamente.\n\nPara eso, usas `app.add_middleware()` (como en el ejemplo para CORS).\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` recibe una clase de middleware como primer argumento y cualquier argumento adicional que se le quiera pasar al middleware.\n\n## Middlewares integrados { #integrated-middlewares }\n\n**FastAPI** incluye varios middlewares para casos de uso común, veremos a continuación cómo usarlos.\n\n/// note | Detalles Técnicos\n\nPara los próximos ejemplos, también podrías usar `from starlette.middleware.something import SomethingMiddleware`.\n\n**FastAPI** proporciona varios middlewares en `fastapi.middleware` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los middlewares disponibles provienen directamente de Starlette.\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\nImpone que todas las requests entrantes deben ser `https` o `wss`.\n\nCualquier request entrante a `http` o `ws` será redirigida al esquema seguro.\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\nImpone que todas las requests entrantes tengan correctamente configurado el header `Host`, para proteger contra ataques de HTTP Host Header.\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\nSe soportan los siguientes argumentos:\n\n* `allowed_hosts` - Una list de nombres de dominio que deberían ser permitidos como nombres de host. Se soportan dominios comodín como `*.example.com` para hacer coincidir subdominios. Para permitir cualquier nombre de host, usa `allowed_hosts=[\"*\"]` u omite el middleware.\n* `www_redirect` - Si se establece en True, las requests a versiones sin www de los hosts permitidos serán redirigidas a sus equivalentes con www. Por defecto es `True`.\n\nSi una request entrante no se valida correctamente, se enviará un response `400`.\n\n## `GZipMiddleware` { #gzipmiddleware }\n\nManeja responses GZip para cualquier request que incluya `\"gzip\"` en el header `Accept-Encoding`.\n\nEl middleware manejará tanto responses estándar como en streaming.\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\nSe soportan los siguientes argumentos:\n\n* `minimum_size` - No comprimir con GZip responses que sean más pequeñas que este tamaño mínimo en bytes. Por defecto es `500`.\n* `compresslevel` - Usado durante la compresión GZip. Es un entero que varía de 1 a 9. Por defecto es `9`. Un valor más bajo resulta en una compresión más rápida pero archivos más grandes, mientras que un valor más alto resulta en una compresión más lenta pero archivos más pequeños.\n\n## Otros middlewares { #other-middlewares }\n\nHay muchos otros middlewares ASGI.\n\nPor ejemplo:\n\n* [`ProxyHeadersMiddleware` de Uvicorn](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n* [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\nPara ver otros middlewares disponibles, revisa [la documentación de Middleware de Starlette](https://www.starlette.dev/middleware/) y la [Lista ASGI Awesome](https://github.com/florimondmanca/awesome-asgi).\n"
  },
  {
    "path": "docs/es/docs/advanced/openapi-callbacks.md",
    "content": "# Callbacks de OpenAPI { #openapi-callbacks }\n\nPodrías crear una API con una *path operation* que podría desencadenar un request a una *API externa* creada por alguien más (probablemente el mismo desarrollador que estaría *usando* tu API).\n\nEl proceso que ocurre cuando tu aplicación API llama a la *API externa* se llama un \"callback\". Porque el software que escribió el desarrollador externo envía un request a tu API y luego tu API hace un *callback*, enviando un request a una *API externa* (que probablemente fue creada por el mismo desarrollador).\n\nEn este caso, podrías querer documentar cómo esa API externa *debería* verse. Qué *path operation* debería tener, qué cuerpo debería esperar, qué response debería devolver, etc.\n\n## Una aplicación con callbacks { #an-app-with-callbacks }\n\nVeamos todo esto con un ejemplo.\n\nImagina que desarrollas una aplicación que permite crear facturas.\n\nEstas facturas tendrán un `id`, `title` (opcional), `customer` y `total`.\n\nEl usuario de tu API (un desarrollador externo) creará una factura en tu API con un request POST.\n\nLuego tu API (imaginemos):\n\n* Enviará la factura a algún cliente del desarrollador externo.\n* Recogerá el dinero.\n* Enviará una notificación de vuelta al usuario de la API (el desarrollador externo).\n    * Esto se hará enviando un request POST (desde *tu API*) a alguna *API externa* proporcionada por ese desarrollador externo (este es el \"callback\").\n\n## La aplicación normal de **FastAPI** { #the-normal-fastapi-app }\n\nPrimero veamos cómo se vería la aplicación API normal antes de agregar el callback.\n\nTendrá una *path operation* que recibirá un cuerpo `Invoice`, y un parámetro de query `callback_url` que contendrá la URL para el callback.\n\nEsta parte es bastante normal, probablemente ya estés familiarizado con la mayor parte del código:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip | Consejo\n\nEl parámetro de query `callback_url` utiliza un tipo [Url](https://docs.pydantic.dev/latest/api/networks/) de Pydantic.\n\n///\n\nLo único nuevo es `callbacks=invoices_callback_router.routes` como un argumento para el *decorador de path operation*. Veremos qué es eso a continuación.\n\n## Documentar el callback { #documenting-the-callback }\n\nEl código real del callback dependerá mucho de tu propia aplicación API.\n\nY probablemente variará mucho de una aplicación a otra.\n\nPodría ser solo una o dos líneas de código, como:\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\nPero posiblemente la parte más importante del callback es asegurarse de que el usuario de tu API (el desarrollador externo) implemente la *API externa* correctamente, de acuerdo con los datos que *tu API* va a enviar en el request body del callback, etc.\n\nAsí que, lo que haremos a continuación es agregar el código para documentar cómo debería verse esa *API externa* para recibir el callback de *tu API*.\n\nEsa documentación aparecerá en la Swagger UI en `/docs` en tu API, y permitirá a los desarrolladores externos saber cómo construir la *API externa*.\n\nEste ejemplo no implementa el callback en sí (eso podría ser solo una línea de código), solo la parte de documentación.\n\n/// tip | Consejo\n\nEl callback real es solo un request HTTP.\n\nCuando implementes el callback tú mismo, podrías usar algo como [HTTPX](https://www.python-httpx.org) o [Requests](https://requests.readthedocs.io/).\n\n///\n\n## Escribe el código de documentación del callback { #write-the-callback-documentation-code }\n\nEste código no se ejecutará en tu aplicación, solo lo necesitamos para *documentar* cómo debería verse esa *API externa*.\n\nPero ya sabes cómo crear fácilmente documentación automática para una API con **FastAPI**.\n\nAsí que vamos a usar ese mismo conocimiento para documentar cómo debería verse la *API externa*... creando la(s) *path operation(s)* que la API externa debería implementar (las que tu API va a llamar).\n\n/// tip | Consejo\n\nCuando escribas el código para documentar un callback, podría ser útil imaginar que eres ese *desarrollador externo*. Y que actualmente estás implementando la *API externa*, no *tu API*.\n\nAdoptar temporalmente este punto de vista (del *desarrollador externo*) puede ayudarte a sentir que es más obvio dónde poner los parámetros, el modelo de Pydantic para el body, para el response, etc. para esa *API externa*.\n\n///\n\n### Crea un `APIRouter` de callback { #create-a-callback-apirouter }\n\nPrimero crea un nuevo `APIRouter` que contendrá uno o más callbacks.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### Crea la *path operation* del callback { #create-the-callback-path-operation }\n\nPara crear la *path operation* del callback usa el mismo `APIRouter` que creaste arriba.\n\nDebería verse como una *path operation* normal de FastAPI:\n\n* Probablemente debería tener una declaración del body que debería recibir, por ejemplo `body: InvoiceEvent`.\n* Y también podría tener una declaración del response que debería devolver, por ejemplo `response_model=InvoiceEventReceived`.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\nHay 2 diferencias principales respecto a una *path operation* normal:\n\n* No necesita tener ningún código real, porque tu aplicación nunca llamará a este código. Solo se usa para documentar la *API externa*. Así que, la función podría simplemente tener `pass`.\n* El *path* puede contener una [expresión OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (ver más abajo) donde puede usar variables con parámetros y partes del request original enviado a *tu API*.\n\n### La expresión del path del callback { #the-callback-path-expression }\n\nEl *path* del callback puede tener una [expresión OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) que puede contener partes del request original enviado a *tu API*.\n\nEn este caso, es el `str`:\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\nEntonces, si el usuario de tu API (el desarrollador externo) envía un request a *tu API* a:\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\ncon un JSON body de:\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\nluego *tu API* procesará la factura y, en algún momento después, enviará un request de callback al `callback_url` (la *API externa*):\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\ncon un JSON body que contiene algo como:\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\ny esperaría un response de esa *API externa* con un JSON body como:\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip | Consejo\n\nObserva cómo la URL del callback utilizada contiene la URL recibida como parámetro de query en `callback_url` (`https://www.external.org/events`) y también el `id` de la factura desde dentro del JSON body (`2expen51ve`).\n\n///\n\n### Agrega el router de callback { #add-the-callback-router }\n\nEn este punto tienes las *path operation(s)* del callback necesarias (las que el *desarrollador externo* debería implementar en la *API externa*) en el router de callback que creaste arriba.\n\nAhora usa el parámetro `callbacks` en el *decorador de path operation de tu API* para pasar el atributo `.routes` (que en realidad es solo un `list` de rutas/*path operations*) de ese router de callback:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip | Consejo\n\nObserva que no estás pasando el router en sí (`invoices_callback_router`) a `callback=`, sino el atributo `.routes`, como en `invoices_callback_router.routes`.\n\n///\n\n### Revisa la documentación { #check-the-docs }\n\nAhora puedes iniciar tu aplicación e ir a [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVerás tu documentación incluyendo una sección de \"Callbacks\" para tu *path operation* que muestra cómo debería verse la *API externa*:\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/es/docs/advanced/openapi-webhooks.md",
    "content": "# Webhooks de OpenAPI { #openapi-webhooks }\n\nHay casos donde quieres decirle a los **usuarios** de tu API que tu aplicación podría llamar a *su* aplicación (enviando una request) con algunos datos, normalmente para **notificar** de algún tipo de **evento**.\n\nEsto significa que en lugar del proceso normal de tus usuarios enviando requests a tu API, es **tu API** (o tu aplicación) la que podría **enviar requests a su sistema** (a su API, su aplicación).\n\nEsto normalmente se llama un **webhook**.\n\n## Pasos de los webhooks { #webhooks-steps }\n\nEl proceso normalmente es que **tú defines** en tu código cuál es el mensaje que enviarás, el **body de la request**.\n\nTambién defines de alguna manera en qué **momentos** tu aplicación enviará esas requests o eventos.\n\nY **tus usuarios** definen de alguna manera (por ejemplo en un panel web en algún lugar) el **URL** donde tu aplicación debería enviar esas requests.\n\nToda la **lógica** sobre cómo registrar los URLs para webhooks y el código para realmente enviar esas requests depende de ti. Lo escribes como quieras en **tu propio código**.\n\n## Documentando webhooks con **FastAPI** y OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }\n\nCon **FastAPI**, usando OpenAPI, puedes definir los nombres de estos webhooks, los tipos de operaciones HTTP que tu aplicación puede enviar (por ejemplo, `POST`, `PUT`, etc.) y los **bodies** de las requests que tu aplicación enviaría.\n\nEsto puede hacer mucho más fácil para tus usuarios **implementar sus APIs** para recibir tus requests de **webhook**, incluso podrían ser capaces de autogenerar algo de su propio código de API.\n\n/// info | Información\n\nLos webhooks están disponibles en OpenAPI 3.1.0 y superiores, soportados por FastAPI `0.99.0` y superiores.\n\n///\n\n## Una aplicación con webhooks { #an-app-with-webhooks }\n\nCuando creas una aplicación de **FastAPI**, hay un atributo `webhooks` que puedes usar para definir *webhooks*, de la misma manera que definirías *path operations*, por ejemplo con `@app.webhooks.post()`.\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\nLos webhooks que defines terminarán en el esquema de **OpenAPI** y en la interfaz automática de **documentación**.\n\n/// info | Información\n\nEl objeto `app.webhooks` es en realidad solo un `APIRouter`, el mismo tipo que usarías al estructurar tu aplicación con múltiples archivos.\n\n///\n\nNota que con los webhooks en realidad no estás declarando un *path* (como `/items/`), el texto que pasas allí es solo un **identificador** del webhook (el nombre del evento), por ejemplo en `@app.webhooks.post(\"new-subscription\")`, el nombre del webhook es `new-subscription`.\n\nEsto es porque se espera que **tus usuarios** definan el actual **URL path** donde quieren recibir la request del webhook de alguna otra manera (por ejemplo, un panel web).\n\n### Revisa la documentación { #check-the-docs }\n\nAhora puedes iniciar tu app e ir a [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVerás que tu documentación tiene las *path operations* normales y ahora también algunos **webhooks**:\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/es/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# Configuración Avanzada de Path Operation { #path-operation-advanced-configuration }\n\n## operationId de OpenAPI { #openapi-operationid }\n\n/// warning | Advertencia\n\nSi no eres un \"experto\" en OpenAPI, probablemente no necesites esto.\n\n///\n\nPuedes establecer el `operationId` de OpenAPI para ser usado en tu *path operation* con el parámetro `operation_id`.\n\nTendrías que asegurarte de que sea único para cada operación.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### Usar el nombre de la *path operation function* como el operationId { #using-the-path-operation-function-name-as-the-operationid }\n\nSi quieres usar los nombres de las funciones de tus APIs como `operationId`s, puedes iterar sobre todas ellas y sobrescribir el `operation_id` de cada *path operation* usando su `APIRoute.name`.\n\nDeberías hacerlo después de agregar todas tus *path operations*.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip | Consejo\n\nSi llamas manualmente a `app.openapi()`, deberías actualizar los `operationId`s antes de eso.\n\n///\n\n/// warning | Advertencia\n\nSi haces esto, tienes que asegurarte de que cada una de tus *path operation functions* tenga un nombre único.\n\nIncluso si están en diferentes módulos (archivos de Python).\n\n///\n\n## Excluir de OpenAPI { #exclude-from-openapi }\n\nPara excluir una *path operation* del esquema OpenAPI generado (y por lo tanto, de los sistemas de documentación automática), utiliza el parámetro `include_in_schema` y configúralo en `False`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## Descripción avanzada desde el docstring { #advanced-description-from-docstring }\n\nPuedes limitar las líneas usadas del docstring de una *path operation function* para OpenAPI.\n\nAñadir un `\\f` (un carácter \"form feed\" escapado) hace que **FastAPI** trunque la salida usada para OpenAPI en este punto.\n\nNo aparecerá en la documentación, pero otras herramientas (como Sphinx) podrán usar el resto.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## Responses Adicionales { #additional-responses }\n\nProbablemente has visto cómo declarar el `response_model` y el `status_code` para una *path operation*.\n\nEso define los metadatos sobre el response principal de una *path operation*.\n\nTambién puedes declarar responses adicionales con sus modelos, códigos de estado, etc.\n\nHay un capítulo entero en la documentación sobre ello, puedes leerlo en [Responses Adicionales en OpenAPI](additional-responses.md).\n\n## OpenAPI Extra { #openapi-extra }\n\nCuando declaras una *path operation* en tu aplicación, **FastAPI** genera automáticamente los metadatos relevantes sobre esa *path operation* para incluirlos en el esquema de OpenAPI.\n\n/// note | Detalles técnicos\n\nEn la especificación de OpenAPI se llama el [Objeto de Operación](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object).\n\n///\n\nTiene toda la información sobre la *path operation* y se usa para generar la documentación automática.\n\nIncluye los `tags`, `parameters`, `requestBody`, `responses`, etc.\n\nEste esquema de OpenAPI específico de *path operation* normalmente se genera automáticamente por **FastAPI**, pero también puedes extenderlo.\n\n/// tip | Consejo\n\nEste es un punto de extensión de bajo nivel.\n\nSi solo necesitas declarar responses adicionales, una forma más conveniente de hacerlo es con [Responses Adicionales en OpenAPI](additional-responses.md).\n\n///\n\nPuedes extender el esquema de OpenAPI para una *path operation* usando el parámetro `openapi_extra`.\n\n### Extensiones de OpenAPI { #openapi-extensions }\n\nEste `openapi_extra` puede ser útil, por ejemplo, para declarar [Extensiones de OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\nSi abres la documentación automática de la API, tu extensión aparecerá en la parte inferior de la *path operation* específica.\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\nY si ves el OpenAPI resultante (en `/openapi.json` en tu API), verás tu extensión como parte de la *path operation* específica también:\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### Esquema de *path operation* personalizada de OpenAPI { #custom-openapi-path-operation-schema }\n\nEl diccionario en `openapi_extra` se combinará profundamente con el esquema de OpenAPI generado automáticamente para la *path operation*.\n\nPor lo tanto, podrías añadir datos adicionales al esquema generado automáticamente.\n\nPor ejemplo, podrías decidir leer y validar el request con tu propio código, sin usar las funcionalidades automáticas de FastAPI con Pydantic, pero aún podrías querer definir el request en el esquema de OpenAPI.\n\nPodrías hacer eso con `openapi_extra`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\nEn este ejemplo, no declaramos ningún modelo Pydantic. De hecho, el request body ni siquiera es <dfn title=\"convertido desde algún formato plano, como bytes, a objetos de Python\">parseado</dfn> como JSON, se lee directamente como `bytes`, y la función `magic_data_reader()` sería la encargada de hacer parse de él de alguna manera.\n\nSin embargo, podemos declarar el esquema esperado para el request body.\n\n### Tipo de contenido personalizado de OpenAPI { #custom-openapi-content-type }\n\nUsando este mismo truco, podrías usar un modelo Pydantic para definir el JSON Schema que luego se incluye en la sección personalizada del esquema OpenAPI para la *path operation*.\n\nY podrías hacer esto incluso si el tipo de datos en el request no es JSON.\n\nPor ejemplo, en esta aplicación no usamos la funcionalidad integrada de FastAPI para extraer el JSON Schema de los modelos Pydantic ni la validación automática para JSON. De hecho, estamos declarando el tipo de contenido del request como YAML, no JSON:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\nSin embargo, aunque no estamos usando la funcionalidad integrada por defecto, aún estamos usando un modelo Pydantic para generar manualmente el JSON Schema para los datos que queremos recibir en YAML.\n\nLuego usamos el request directamente, y extraemos el cuerpo como `bytes`. Esto significa que FastAPI ni siquiera intentará hacer parse de la carga útil del request como JSON.\n\nY luego en nuestro código, hacemos parse de ese contenido YAML directamente, y nuevamente estamos usando el mismo modelo Pydantic para validar el contenido YAML:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip | Consejo\n\nAquí reutilizamos el mismo modelo Pydantic.\n\nPero de la misma manera, podríamos haberlo validado de alguna otra forma.\n\n///\n"
  },
  {
    "path": "docs/es/docs/advanced/response-change-status-code.md",
    "content": "# Response - Cambiar Código de Estado { #response-change-status-code }\n\nProbablemente leíste antes que puedes establecer un [Código de Estado de Response](../tutorial/response-status-code.md) por defecto.\n\nPero en algunos casos necesitas devolver un código de estado diferente al predeterminado.\n\n## Caso de uso { #use-case }\n\nPor ejemplo, imagina que quieres devolver un código de estado HTTP de \"OK\" `200` por defecto.\n\nPero si los datos no existieran, quieres crearlos y devolver un código de estado HTTP de \"CREATED\" `201`.\n\nPero todavía quieres poder filtrar y convertir los datos que devuelves con un `response_model`.\n\nPara esos casos, puedes usar un parámetro `Response`.\n\n## Usa un parámetro `Response` { #use-a-response-parameter }\n\nPuedes declarar un parámetro de tipo `Response` en tu *path operation function* (como puedes hacer para cookies y headers).\n\nY luego puedes establecer el `status_code` en ese objeto de response *temporal*.\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\nY luego puedes devolver cualquier objeto que necesites, como lo harías normalmente (un `dict`, un modelo de base de datos, etc).\n\nY si declaraste un `response_model`, todavía se utilizará para filtrar y convertir el objeto que devolviste.\n\n**FastAPI** usará ese response *temporal* para extraer el código de estado (también cookies y headers), y los pondrá en el response final que contiene el valor que devolviste, filtrado por cualquier `response_model`.\n\nTambién puedes declarar el parámetro `Response` en dependencias y establecer el código de estado en ellas. Pero ten en cuenta que el último establecido prevalecerá.\n"
  },
  {
    "path": "docs/es/docs/advanced/response-cookies.md",
    "content": "# Cookies de Response { #response-cookies }\n\n## Usar un parámetro `Response` { #use-a-response-parameter }\n\nPuedes declarar un parámetro de tipo `Response` en tu *path operation function*.\n\nY luego puedes establecer cookies en ese objeto de response *temporal*.\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\nY entonces puedes devolver cualquier objeto que necesites, como normalmente lo harías (un `dict`, un modelo de base de datos, etc).\n\nY si declaraste un `response_model`, todavía se utilizará para filtrar y convertir el objeto que devolviste.\n\n**FastAPI** utilizará ese response *temporal* para extraer las cookies (también los headers y el código de estado), y las pondrá en el response final que contiene el valor que devolviste, filtrado por cualquier `response_model`.\n\nTambién puedes declarar el parámetro `Response` en las dependencias, y establecer cookies (y headers) en ellas.\n\n## Devolver una `Response` directamente { #return-a-response-directly }\n\nTambién puedes crear cookies al devolver una `Response` directamente en tu código.\n\nPara hacer eso, puedes crear un response como se describe en [Devolver un Response Directamente](response-directly.md).\n\nLuego establece Cookies en ella, y luego devuélvela:\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip | Consejo\n\nTen en cuenta que si devuelves un response directamente en lugar de usar el parámetro `Response`, FastAPI lo devolverá directamente.\n\nAsí que tendrás que asegurarte de que tus datos son del tipo correcto. Por ejemplo, que sea compatible con JSON, si estás devolviendo un `JSONResponse`.\n\nY también que no estés enviando ningún dato que debería haber sido filtrado por un `response_model`.\n\n///\n\n### Más información { #more-info }\n\n/// note | Detalles Técnicos\n\nTambién podrías usar `from starlette.responses import Response` o `from starlette.responses import JSONResponse`.\n\n**FastAPI** proporciona los mismos `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.\n\nY como el `Response` se puede usar frecuentemente para establecer headers y cookies, **FastAPI** también lo proporciona en `fastapi.Response`.\n\n///\n\nPara ver todos los parámetros y opciones disponibles, revisa la [documentación en Starlette](https://www.starlette.dev/responses/#set-cookie).\n"
  },
  {
    "path": "docs/es/docs/advanced/response-directly.md",
    "content": "# Devolver una Response Directamente { #return-a-response-directly }\n\nCuando creas una *path operation* en **FastAPI**, normalmente puedes devolver cualquier dato desde ella: un `dict`, una `list`, un modelo de Pydantic, un modelo de base de datos, etc.\n\nSi declaras un [Response Model](../tutorial/response-model.md) FastAPI lo usará para serializar los datos a JSON, usando Pydantic.\n\nSi no declaras un response model, FastAPI usará el `jsonable_encoder` explicado en [JSON Compatible Encoder](../tutorial/encoder.md) y lo pondrá en un `JSONResponse`.\n\nTambién podrías crear un `JSONResponse` directamente y devolverlo.\n\n/// tip | Consejo\n\nNormalmente tendrás mucho mejor rendimiento usando un [Response Model](../tutorial/response-model.md) que devolviendo un `JSONResponse` directamente, ya que de esa forma serializa los datos usando Pydantic, en Rust.\n\n///\n\n## Devolver una `Response` { #return-a-response }\n\nDe hecho, puedes devolver cualquier `Response` o cualquier subclase de ella.\n\n/// info | Información\n\n`JSONResponse` en sí misma es una subclase de `Response`.\n\n///\n\nY cuando devuelves una `Response`, **FastAPI** la pasará directamente.\n\nNo hará ninguna conversión de datos con los modelos de Pydantic, no convertirá los contenidos a ningún tipo, etc.\n\nEsto te da mucha flexibilidad. Puedes devolver cualquier tipo de datos, sobrescribir cualquier declaración o validación de datos, etc.\n\nTambién te da mucha responsabilidad. Tienes que asegurarte de que los datos que devuelves sean correctos, en el formato correcto, que se puedan serializar, etc.\n\n## Usar el `jsonable_encoder` en una `Response` { #using-the-jsonable-encoder-in-a-response }\n\nComo **FastAPI** no realiza cambios en una `Response` que devuelves, tienes que asegurarte de que sus contenidos estén listos para ello.\n\nPor ejemplo, no puedes poner un modelo de Pydantic en un `JSONResponse` sin primero convertirlo a un `dict` con todos los tipos de datos (como `datetime`, `UUID`, etc.) convertidos a tipos compatibles con JSON.\n\nPara esos casos, puedes usar el `jsonable_encoder` para convertir tus datos antes de pasarlos a un response:\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | Detalles técnicos\n\nTambién podrías usar `from starlette.responses import JSONResponse`.\n\n**FastAPI** proporciona los mismos `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.\n\n///\n\n## Devolver una `Response` personalizada { #returning-a-custom-response }\n\nEl ejemplo anterior muestra todas las partes que necesitas, pero aún no es muy útil, ya que podrías haber devuelto el `item` directamente, y **FastAPI** lo colocaría en un `JSONResponse` por ti, convirtiéndolo a un `dict`, etc. Todo eso por defecto.\n\nAhora, veamos cómo podrías usar eso para devolver un response personalizado.\n\nDigamos que quieres devolver un response en [XML](https://en.wikipedia.org/wiki/XML).\n\nPodrías poner tu contenido XML en un string, poner eso en un `Response`, y devolverlo:\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## Cómo funciona un Response Model { #how-a-response-model-works }\n\nCuando declaras un [Response Model - Return Type](../tutorial/response-model.md) en una *path operation*, **FastAPI** lo usará para serializar los datos a JSON, usando Pydantic.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nComo eso sucederá del lado de Rust, el rendimiento será mucho mejor que si se hiciera con Python normal y la clase `JSONResponse`.\n\nAl usar un `response_model` o tipo de retorno, FastAPI no usará el `jsonable_encoder` para convertir los datos (lo cual sería más lento) ni la clase `JSONResponse`.\n\nEn su lugar, toma los bytes JSON generados con Pydantic usando el response model (o tipo de retorno) y devuelve una `Response` con el media type correcto para JSON directamente (`application/json`).\n\n## Notas { #notes }\n\nCuando devuelves una `Response` directamente, sus datos no son validados, convertidos (serializados), ni documentados automáticamente.\n\nPero aún puedes documentarlo como se describe en [Additional Responses in OpenAPI](additional-responses.md).\n\nPuedes ver en secciones posteriores cómo usar/declarar estas `Response`s personalizadas mientras todavía tienes conversión automática de datos, documentación, etc.\n"
  },
  {
    "path": "docs/es/docs/advanced/response-headers.md",
    "content": "# Headers de Response { #response-headers }\n\n## Usa un parámetro `Response` { #use-a-response-parameter }\n\nPuedes declarar un parámetro de tipo `Response` en tu *path operation function* (como puedes hacer para cookies).\n\nY luego puedes establecer headers en ese objeto de response *temporal*.\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\nY luego puedes devolver cualquier objeto que necesites, como harías normalmente (un `dict`, un modelo de base de datos, etc).\n\nY si declaraste un `response_model`, aún se usará para filtrar y convertir el objeto que devolviste.\n\n**FastAPI** usará ese response *temporal* para extraer los headers (también cookies y el código de estado), y los pondrá en el response final que contiene el valor que devolviste, filtrado por cualquier `response_model`.\n\nTambién puedes declarar el parámetro `Response` en dependencias y establecer headers (y cookies) en ellas.\n\n## Retorna una `Response` directamente { #return-a-response-directly }\n\nTambién puedes agregar headers cuando devuelves un `Response` directamente.\n\nCrea un response como se describe en [Retorna un Response Directamente](response-directly.md) y pasa los headers como un parámetro adicional:\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | Detalles Técnicos\n\nTambién podrías usar `from starlette.responses import Response` o `from starlette.responses import JSONResponse`.\n\n**FastAPI** proporciona las mismas `starlette.responses` como `fastapi.responses` solo por conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles provienen directamente de Starlette.\n\nY como el `Response` se puede usar frecuentemente para establecer headers y cookies, **FastAPI** también lo proporciona en `fastapi.Response`.\n\n///\n\n## Headers Personalizados { #custom-headers }\n\nTen en cuenta que los headers propietarios personalizados se pueden agregar [usando el prefijo `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nPero si tienes headers personalizados que quieres que un cliente en un navegador pueda ver, necesitas agregarlos a tus configuraciones de CORS (leer más en [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), usando el parámetro `expose_headers` documentado en [la documentación CORS de Starlette](https://www.starlette.dev/middleware/#corsmiddleware).\n"
  },
  {
    "path": "docs/es/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP Basic Auth { #http-basic-auth }\n\nPara los casos más simples, puedes usar HTTP Basic Auth.\n\nEn HTTP Basic Auth, la aplicación espera un header que contiene un nombre de usuario y una contraseña.\n\nSi no lo recibe, devuelve un error HTTP 401 \"Unauthorized\".\n\nY devuelve un header `WWW-Authenticate` con un valor de `Basic`, y un parámetro `realm` opcional.\n\nEso le dice al navegador que muestre el prompt integrado para un nombre de usuario y contraseña.\n\nLuego, cuando escribes ese nombre de usuario y contraseña, el navegador los envía automáticamente en el header.\n\n## Simple HTTP Basic Auth { #simple-http-basic-auth }\n\n* Importa `HTTPBasic` y `HTTPBasicCredentials`.\n* Crea un \"esquema de `security`\" usando `HTTPBasic`.\n* Usa ese `security` con una dependencia en tu *path operation*.\n* Devuelve un objeto de tipo `HTTPBasicCredentials`:\n  * Contiene el `username` y `password` enviados.\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\nCuando intentas abrir la URL por primera vez (o haces clic en el botón \"Execute\" en la documentación) el navegador te pedirá tu nombre de usuario y contraseña:\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## Revisa el nombre de usuario { #check-the-username }\n\nAquí hay un ejemplo más completo.\n\nUsa una dependencia para comprobar si el nombre de usuario y la contraseña son correctos.\n\nPara esto, usa el módulo estándar de Python [`secrets`](https://docs.python.org/3/library/secrets.html) para verificar el nombre de usuario y la contraseña.\n\n`secrets.compare_digest()` necesita tomar `bytes` o un `str` que solo contenga caracteres ASCII (los carácteres en inglés), esto significa que no funcionaría con caracteres como `á`, como en `Sebastián`.\n\nPara manejar eso, primero convertimos el `username` y `password` a `bytes` codificándolos con UTF-8.\n\nLuego podemos usar `secrets.compare_digest()` para asegurar que `credentials.username` es `\"stanleyjobson\"`, y que `credentials.password` es `\"swordfish\"`.\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\nEsto sería similar a:\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # Devuelve algún error\n    ...\n```\n\nPero al usar `secrets.compare_digest()` será seguro contra un tipo de ataques llamados \"timing attacks\".\n\n### Timing attacks { #timing-attacks }\n\n¿Pero qué es un \"timing attack\"?\n\nImaginemos que algunos atacantes están tratando de adivinar el nombre de usuario y la contraseña.\n\nY envían un request con un nombre de usuario `johndoe` y una contraseña `love123`.\n\nEntonces el código de Python en tu aplicación equivaldría a algo como:\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nPero justo en el momento en que Python compara la primera `j` en `johndoe` con la primera `s` en `stanleyjobson`, devolverá `False`, porque ya sabe que esas dos strings no son iguales, pensando que \"no hay necesidad de gastar más computación comparando el resto de las letras\". Y tu aplicación dirá \"Nombre de usuario o contraseña incorrectos\".\n\nPero luego los atacantes prueban con el nombre de usuario `stanleyjobsox` y contraseña `love123`.\n\nY el código de tu aplicación hace algo así como:\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nPython tendrá que comparar todo `stanleyjobso` en ambos `stanleyjobsox` y `stanleyjobson` antes de darse cuenta de que ambas strings no son las mismas. Así que tomará algunos microsegundos extra para responder \"Nombre de usuario o contraseña incorrectos\".\n\n#### El tiempo de respuesta ayuda a los atacantes { #the-time-to-answer-helps-the-attackers }\n\nEn ese punto, al notar que el servidor tardó algunos microsegundos más en enviar el response \"Nombre de usuario o contraseña incorrectos\", los atacantes sabrán que acertaron en _algo_, algunas de las letras iniciales eran correctas.\n\nY luego pueden intentar de nuevo sabiendo que probablemente es algo más similar a `stanleyjobsox` que a `johndoe`.\n\n#### Un ataque \"profesional\" { #a-professional-attack }\n\nPor supuesto, los atacantes no intentarían todo esto a mano, escribirían un programa para hacerlo, posiblemente con miles o millones de pruebas por segundo. Y obtendrían solo una letra correcta adicional a la vez.\n\nPero haciendo eso, en algunos minutos u horas, los atacantes habrían adivinado el nombre de usuario y la contraseña correctos, con la \"ayuda\" de nuestra aplicación, solo usando el tiempo tomado para responder.\n\n#### Arréglalo con `secrets.compare_digest()` { #fix-it-with-secrets-compare-digest }\n\nPero en nuestro código estamos usando realmente `secrets.compare_digest()`.\n\nEn resumen, tomará el mismo tiempo comparar `stanleyjobsox` con `stanleyjobson` que comparar `johndoe` con `stanleyjobson`. Y lo mismo para la contraseña.\n\nDe esa manera, usando `secrets.compare_digest()` en el código de tu aplicación, será seguro contra todo este rango de ataques de seguridad.\n\n### Devuelve el error { #return-the-error }\n\nDespués de detectar que las credenciales son incorrectas, regresa un `HTTPException` con un código de estado 401 (el mismo que se devuelve cuando no se proporcionan credenciales) y agrega el header `WWW-Authenticate` para que el navegador muestre el prompt de inicio de sesión nuevamente:\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/es/docs/advanced/security/index.md",
    "content": "# Seguridad Avanzada { #advanced-security }\n\n## Funcionalidades Adicionales { #additional-features }\n\nHay algunas funcionalidades extra para manejar la seguridad aparte de las cubiertas en el [Tutorial - Guía del Usuario: Seguridad](../../tutorial/security/index.md).\n\n/// tip | Consejo\n\nLas siguientes secciones no son necesariamente \"avanzadas\".\n\nY es posible que para tu caso de uso, la solución esté en una de ellas.\n\n///\n\n## Lee primero el Tutorial { #read-the-tutorial-first }\n\nLas siguientes secciones asumen que ya leíste el [Tutorial - Guía del Usuario: Seguridad](../../tutorial/security/index.md) principal.\n\nTodas están basadas en los mismos conceptos, pero permiten algunas funcionalidades adicionales.\n"
  },
  {
    "path": "docs/es/docs/advanced/security/oauth2-scopes.md",
    "content": "# Scopes de OAuth2 { #oauth2-scopes }\n\nPuedes usar scopes de OAuth2 directamente con **FastAPI**, están integrados para funcionar de manera fluida.\n\nEsto te permitiría tener un sistema de permisos más detallado, siguiendo el estándar de OAuth2, integrado en tu aplicación OpenAPI (y la documentación de la API).\n\nOAuth2 con scopes es el mecanismo usado por muchos grandes proveedores de autenticación, como Facebook, Google, GitHub, Microsoft, X (Twitter), etc. Lo usan para proporcionar permisos específicos a usuarios y aplicaciones.\n\nCada vez que te \"logueas con\" Facebook, Google, GitHub, Microsoft, X (Twitter), esa aplicación está usando OAuth2 con scopes.\n\nEn esta sección verás cómo manejar autenticación y autorización con el mismo OAuth2 con scopes en tu aplicación de **FastAPI**.\n\n/// warning | Advertencia\n\nEsta es una sección más o menos avanzada. Si estás comenzando, puedes saltarla.\n\nNo necesariamente necesitas scopes de OAuth2, y puedes manejar autenticación y autorización como quieras.\n\nPero OAuth2 con scopes se puede integrar muy bien en tu API (con OpenAPI) y en la documentación de tu API.\n\nNo obstante, tú aún impones esos scopes, o cualquier otro requisito de seguridad/autorización, como necesites, en tu código.\n\nEn muchos casos, OAuth2 con scopes puede ser un exceso.\n\nPero si sabes que lo necesitas, o tienes curiosidad, sigue leyendo.\n\n///\n\n## Scopes de OAuth2 y OpenAPI { #oauth2-scopes-and-openapi }\n\nLa especificación de OAuth2 define \"scopes\" como una lista de strings separados por espacios.\n\nEl contenido de cada uno de estos strings puede tener cualquier formato, pero no debe contener espacios.\n\nEstos scopes representan \"permisos\".\n\nEn OpenAPI (por ejemplo, en la documentación de la API), puedes definir \"esquemas de seguridad\".\n\nCuando uno de estos esquemas de seguridad usa OAuth2, también puedes declarar y usar scopes.\n\nCada \"scope\" es solo un string (sin espacios).\n\nNormalmente se utilizan para declarar permisos de seguridad específicos, por ejemplo:\n\n* `users:read` o `users:write` son ejemplos comunes.\n* `instagram_basic` es usado por Facebook / Instagram.\n* `https://www.googleapis.com/auth/drive` es usado por Google.\n\n/// info | Información\n\nEn OAuth2 un \"scope\" es solo un string que declara un permiso específico requerido.\n\nNo importa si tiene otros caracteres como `:` o si es una URL.\n\nEsos detalles son específicos de la implementación.\n\nPara OAuth2 son solo strings.\n\n///\n\n## Vista global { #global-view }\n\nPrimero, echemos un vistazo rápido a las partes que cambian desde los ejemplos en el **Tutorial - User Guide** principal para [OAuth2 con Password (y hashing), Bearer con tokens JWT](../../tutorial/security/oauth2-jwt.md). Ahora usando scopes de OAuth2:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\nAhora revisemos esos cambios paso a paso.\n\n## Esquema de seguridad OAuth2 { #oauth2-security-scheme }\n\nEl primer cambio es que ahora estamos declarando el esquema de seguridad OAuth2 con dos scopes disponibles, `me` y `items`.\n\nEl parámetro `scopes` recibe un `dict` con cada scope como clave y la descripción como valor:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\nComo ahora estamos declarando esos scopes, aparecerán en la documentación de la API cuando inicies sesión/autorices.\n\nY podrás seleccionar cuáles scopes quieres dar de acceso: `me` y `items`.\n\nEste es el mismo mecanismo utilizado cuando das permisos al iniciar sesión con Facebook, Google, GitHub, etc:\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## Token JWT con scopes { #jwt-token-with-scopes }\n\nAhora, modifica la *path operation* del token para devolver los scopes solicitados.\n\nTodavía estamos usando el mismo `OAuth2PasswordRequestForm`. Incluye una propiedad `scopes` con una `list` de `str`, con cada scope que recibió en el request.\n\nY devolvemos los scopes como parte del token JWT.\n\n/// danger | Peligro\n\nPara simplificar, aquí solo estamos añadiendo los scopes recibidos directamente al token.\n\nPero en tu aplicación, por seguridad, deberías asegurarte de añadir solo los scopes que el usuario realmente puede tener, o los que has predefinido.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## Declarar scopes en *path operations* y dependencias { #declare-scopes-in-path-operations-and-dependencies }\n\nAhora declaramos que la *path operation* para `/users/me/items/` requiere el scope `items`.\n\nPara esto, importamos y usamos `Security` de `fastapi`.\n\nPuedes usar `Security` para declarar dependencias (igual que `Depends`), pero `Security` también recibe un parámetro `scopes` con una lista de scopes (strings).\n\nEn este caso, pasamos una función de dependencia `get_current_active_user` a `Security` (de la misma manera que haríamos con `Depends`).\n\nPero también pasamos una `list` de scopes, en este caso con solo un scope: `items` (podría tener más).\n\nY la función de dependencia `get_current_active_user` también puede declarar sub-dependencias, no solo con `Depends` sino también con `Security`. Declarando su propia función de sub-dependencia (`get_current_user`), y más requisitos de scope.\n\nEn este caso, requiere el scope `me` (podría requerir más de un scope).\n\n/// note | Nota\n\nNo necesariamente necesitas añadir diferentes scopes en diferentes lugares.\n\nLo estamos haciendo aquí para demostrar cómo **FastAPI** maneja scopes declarados en diferentes niveles.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | Información Técnica\n\n`Security` es en realidad una subclase de `Depends`, y tiene solo un parámetro extra que veremos más adelante.\n\nPero al usar `Security` en lugar de `Depends`, **FastAPI** sabrá que puede declarar scopes de seguridad, usarlos internamente y documentar la API con OpenAPI.\n\nPero cuando importas `Query`, `Path`, `Depends`, `Security` y otros de `fastapi`, en realidad son funciones que devuelven clases especiales.\n\n///\n\n## Usar `SecurityScopes` { #use-securityscopes }\n\nAhora actualiza la dependencia `get_current_user`.\n\nEsta es la que usan las dependencias anteriores.\n\nAquí es donde estamos usando el mismo esquema de OAuth2 que creamos antes, declarándolo como una dependencia: `oauth2_scheme`.\n\nPorque esta función de dependencia no tiene ningún requisito de scope en sí, podemos usar `Depends` con `oauth2_scheme`, no tenemos que usar `Security` cuando no necesitamos especificar scopes de seguridad.\n\nTambién declaramos un parámetro especial de tipo `SecurityScopes`, importado de `fastapi.security`.\n\nEsta clase `SecurityScopes` es similar a `Request` (`Request` se usó para obtener el objeto request directamente).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## Usar los `scopes` { #use-the-scopes }\n\nEl parámetro `security_scopes` será del tipo `SecurityScopes`.\n\nTendrá una propiedad `scopes` con una lista que contiene todos los scopes requeridos por sí mismo y por todas las dependencias que lo usan como sub-dependencia. Eso significa, todos los \"dependientes\"... esto podría sonar confuso, se explica de nuevo más abajo.\n\nEl objeto `security_scopes` (de la clase `SecurityScopes`) también proporciona un atributo `scope_str` con un único string, que contiene esos scopes separados por espacios (lo vamos a usar).\n\nCreamos una `HTTPException` que podemos reutilizar (`raise`) más tarde en varios puntos.\n\nEn esta excepción, incluimos los scopes requeridos (si los hay) como un string separado por espacios (usando `scope_str`). Ponemos ese string que contiene los scopes en el header `WWW-Authenticate` (esto es parte de la especificación).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## Verificar el `username` y la forma de los datos { #verify-the-username-and-data-shape }\n\nVerificamos que obtenemos un `username`, y extraemos los scopes.\n\nY luego validamos esos datos con el modelo de Pydantic (capturando la excepción `ValidationError`), y si obtenemos un error leyendo el token JWT o validando los datos con Pydantic, lanzamos la `HTTPException` que creamos antes.\n\nPara eso, actualizamos el modelo de Pydantic `TokenData` con una nueva propiedad `scopes`.\n\nAl validar los datos con Pydantic podemos asegurarnos de que tenemos, por ejemplo, exactamente una `list` de `str` con los scopes y un `str` con el `username`.\n\nEn lugar de, por ejemplo, un `dict`, o algo más, ya que podría romper la aplicación en algún punto posterior, haciéndolo un riesgo de seguridad.\n\nTambién verificamos que tenemos un usuario con ese username, y si no, lanzamos esa misma excepción que creamos antes.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## Verificar los `scopes` { #verify-the-scopes }\n\nAhora verificamos que todos los scopes requeridos, por esta dependencia y todos los dependientes (incluyendo *path operations*), estén incluidos en los scopes proporcionados en el token recibido, de lo contrario, lanzamos una `HTTPException`.\n\nPara esto, usamos `security_scopes.scopes`, que contiene una `list` con todos estos scopes como `str`.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## Árbol de dependencias y scopes { #dependency-tree-and-scopes }\n\nRevisemos de nuevo este árbol de dependencias y los scopes.\n\nComo la dependencia `get_current_active_user` tiene como sub-dependencia a `get_current_user`, el scope `\"me\"` declarado en `get_current_active_user` se incluirá en la lista de scopes requeridos en el `security_scopes.scopes` pasado a `get_current_user`.\n\nLa *path operation* en sí también declara un scope, `\"items\"`, por lo que esto también estará en la lista de `security_scopes.scopes` pasado a `get_current_user`.\n\nAsí es como se ve la jerarquía de dependencias y scopes:\n\n* La *path operation* `read_own_items` tiene:\n    * Scopes requeridos `[\"items\"]` con la dependencia:\n    * `get_current_active_user`:\n        * La función de dependencia `get_current_active_user` tiene:\n            * Scopes requeridos `[\"me\"]` con la dependencia:\n            * `get_current_user`:\n                * La función de dependencia `get_current_user` tiene:\n                    * No requiere scopes por sí misma.\n                    * Una dependencia usando `oauth2_scheme`.\n                    * Un parámetro `security_scopes` de tipo `SecurityScopes`:\n                        * Este parámetro `security_scopes` tiene una propiedad `scopes` con una `list` que contiene todos estos scopes declarados arriba, por lo que:\n                            * `security_scopes.scopes` contendrá `[\"me\", \"items\"]` para la *path operation* `read_own_items`.\n                            * `security_scopes.scopes` contendrá `[\"me\"]` para la *path operation* `read_users_me`, porque está declarado en la dependencia `get_current_active_user`.\n                            * `security_scopes.scopes` contendrá `[]` (nada) para la *path operation* `read_system_status`, porque no declaró ningún `Security` con `scopes`, y su dependencia, `get_current_user`, tampoco declara ningún `scopes`.\n\n/// tip | Consejo\n\nLo importante y \"mágico\" aquí es que `get_current_user` tendrá una lista diferente de `scopes` para verificar para cada *path operation*.\n\nTodo depende de los `scopes` declarados en cada *path operation* y cada dependencia en el árbol de dependencias para esa *path operation* específica.\n\n///\n\n## Más detalles sobre `SecurityScopes` { #more-details-about-securityscopes }\n\nPuedes usar `SecurityScopes` en cualquier punto, y en múltiples lugares, no tiene que ser en la dependencia \"raíz\".\n\nSiempre tendrá los scopes de seguridad declarados en las dependencias `Security` actuales y todos los dependientes para **esa específica** *path operation* y **ese específico** árbol de dependencias.\n\nDebido a que `SecurityScopes` tendrá todos los scopes declarados por dependientes, puedes usarlo para verificar que un token tiene los scopes requeridos en una función de dependencia central, y luego declarar diferentes requisitos de scope en diferentes *path operations*.\n\nSerán verificados independientemente para cada *path operation*.\n\n## Revisa { #check-it }\n\nSi abres la documentación de la API, puedes autenticarte y especificar qué scopes deseas autorizar.\n\n<img src=\"/img/tutorial/security/image11.png\">\n\nSi no seleccionas ningún scope, estarás \"autenticado\", pero cuando intentes acceder a `/users/me/` o `/users/me/items/` obtendrás un error diciendo que no tienes suficientes permisos. Aún podrás acceder a `/status/`.\n\nY si seleccionas el scope `me` pero no el scope `items`, podrás acceder a `/users/me/` pero no a `/users/me/items/`.\n\nEso es lo que pasaría a una aplicación de terceros que intentara acceder a una de estas *path operations* con un token proporcionado por un usuario, dependiendo de cuántos permisos el usuario otorgó a la aplicación.\n\n## Acerca de las integraciones de terceros { #about-third-party-integrations }\n\nEn este ejemplo estamos usando el flujo de OAuth2 \"password\".\n\nEsto es apropiado cuando estamos iniciando sesión en nuestra propia aplicación, probablemente con nuestro propio frontend.\n\nPorque podemos confiar en ella para recibir el `username` y `password`, ya que la controlamos.\n\nPero si estás construyendo una aplicación OAuth2 a la que otros se conectarían (es decir, si estás construyendo un proveedor de autenticación equivalente a Facebook, Google, GitHub, etc.) deberías usar uno de los otros flujos.\n\nEl más común es el flujo implícito.\n\nEl más seguro es el flujo de código, pero es más complejo de implementar ya que requiere más pasos. Como es más complejo, muchos proveedores terminan sugiriendo el flujo implícito.\n\n/// note | Nota\n\nEs común que cada proveedor de autenticación nombre sus flujos de una manera diferente, para hacerlos parte de su marca.\n\nPero al final, están implementando el mismo estándar OAuth2.\n\n///\n\n**FastAPI** incluye utilidades para todos estos flujos de autenticación OAuth2 en `fastapi.security.oauth2`.\n\n## `Security` en `dependencies` del decorador { #security-in-decorator-dependencies }\n\nDe la misma manera que puedes definir una `list` de `Depends` en el parámetro `dependencies` del decorador (como se explica en [Dependencias en decoradores de path operation](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)), también podrías usar `Security` con `scopes` allí.\n"
  },
  {
    "path": "docs/es/docs/advanced/settings.md",
    "content": "# Configuraciones y Variables de Entorno { #settings-and-environment-variables }\n\nEn muchos casos, tu aplicación podría necesitar algunas configuraciones o ajustes externos, por ejemplo, claves secretas, credenciales de base de datos, credenciales para servicios de correo electrónico, etc.\n\nLa mayoría de estas configuraciones son variables (pueden cambiar), como las URLs de bases de datos. Y muchas podrían ser sensibles, como los secretos.\n\nPor esta razón, es común proporcionarlas en variables de entorno que son leídas por la aplicación.\n\n/// tip | Consejo\n\nPara entender las variables de entorno, puedes leer [Variables de Entorno](../environment-variables.md).\n\n///\n\n## Tipos y validación { #types-and-validation }\n\nEstas variables de entorno solo pueden manejar strings de texto, ya que son externas a Python y tienen que ser compatibles con otros programas y el resto del sistema (e incluso con diferentes sistemas operativos, como Linux, Windows, macOS).\n\nEso significa que cualquier valor leído en Python desde una variable de entorno será un `str`, y cualquier conversión a un tipo diferente o cualquier validación tiene que hacerse en código.\n\n## Pydantic `Settings` { #pydantic-settings }\n\nAfortunadamente, Pydantic proporciona una gran utilidad para manejar estas configuraciones provenientes de variables de entorno con [Pydantic: Settings management](https://docs.pydantic.dev/latest/concepts/pydantic_settings/).\n\n### Instalar `pydantic-settings` { #install-pydantic-settings }\n\nPrimero, asegúrate de crear tu [entorno virtual](../virtual-environments.md), actívalo y luego instala el paquete `pydantic-settings`:\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\nTambién viene incluido cuando instalas los extras `all` con:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### Crear el objeto `Settings` { #create-the-settings-object }\n\nImporta `BaseSettings` de Pydantic y crea una sub-clase, muy similar a un modelo de Pydantic.\n\nDe la misma forma que con los modelos de Pydantic, declaras atributos de clase con anotaciones de tipos, y posiblemente, valores por defecto.\n\nPuedes usar todas las mismas funcionalidades de validación y herramientas que usas para los modelos de Pydantic, como diferentes tipos de datos y validaciones adicionales con `Field()`.\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip | Consejo\n\nSi quieres algo rápido para copiar y pegar, no uses este ejemplo, usa el último más abajo.\n\n///\n\nLuego, cuando creas un instance de esa clase `Settings` (en este caso, en el objeto `settings`), Pydantic leerá las variables de entorno de una manera indiferente a mayúsculas y minúsculas, por lo que una variable en mayúsculas `APP_NAME` aún será leída para el atributo `app_name`.\n\nLuego convertirá y validará los datos. Así que, cuando uses ese objeto `settings`, tendrás datos de los tipos que declaraste (por ejemplo, `items_per_user` será un `int`).\n\n### Usar el `settings` { #use-the-settings }\n\nLuego puedes usar el nuevo objeto `settings` en tu aplicación:\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### Ejecutar el servidor { #run-the-server }\n\nLuego, ejecutarías el servidor pasando las configuraciones como variables de entorno, por ejemplo, podrías establecer un `ADMIN_EMAIL` y `APP_NAME` con:\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip | Consejo\n\nPara establecer múltiples env vars para un solo comando, simplemente sepáralas con un espacio y ponlas todas antes del comando.\n\n///\n\nY luego la configuración `admin_email` se establecería en `\"deadpool@example.com\"`.\n\nEl `app_name` sería `\"ChimichangApp\"`.\n\nY el `items_per_user` mantendría su valor por defecto de `50`.\n\n## Configuraciones en otro módulo { #settings-in-another-module }\n\nPodrías poner esas configuraciones en otro archivo de módulo como viste en [Aplicaciones Más Grandes - Múltiples Archivos](../tutorial/bigger-applications.md).\n\nPor ejemplo, podrías tener un archivo `config.py` con:\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\nY luego usarlo en un archivo `main.py`:\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip | Consejo\n\nTambién necesitarías un archivo `__init__.py` como viste en [Aplicaciones Más Grandes - Múltiples Archivos](../tutorial/bigger-applications.md).\n\n///\n\n## Configuraciones en una dependencia { #settings-in-a-dependency }\n\nEn algunas ocasiones podría ser útil proporcionar las configuraciones desde una dependencia, en lugar de tener un objeto global con `settings` que se use en todas partes.\n\nEsto podría ser especialmente útil durante las pruebas, ya que es muy fácil sobrescribir una dependencia con tus propias configuraciones personalizadas.\n\n### El archivo de configuración { #the-config-file }\n\nProveniente del ejemplo anterior, tu archivo `config.py` podría verse como:\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\nNota que ahora no creamos un instance por defecto `settings = Settings()`.\n\n### El archivo principal de la app { #the-main-app-file }\n\nAhora creamos una dependencia que devuelve un nuevo `config.Settings()`.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip | Consejo\n\nHablaremos del `@lru_cache` en un momento.\n\nPor ahora puedes asumir que `get_settings()` es una función normal.\n\n///\n\nY luego podemos requerirlo desde la *path operation function* como una dependencia y usarlo donde lo necesitemos.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### Configuraciones y pruebas { #settings-and-testing }\n\nLuego sería muy fácil proporcionar un objeto de configuraciones diferente durante las pruebas al crear una sobrescritura de dependencia para `get_settings`:\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\nEn la sobrescritura de dependencia establecemos un nuevo valor para el `admin_email` al crear el nuevo objeto `Settings`, y luego devolvemos ese nuevo objeto.\n\nLuego podemos probar que se está usando.\n\n## Leer un archivo `.env` { #reading-a-env-file }\n\nSi tienes muchas configuraciones que posiblemente cambien mucho, tal vez en diferentes entornos, podría ser útil ponerlos en un archivo y luego leerlos desde allí como si fueran variables de entorno.\n\nEsta práctica es lo suficientemente común que tiene un nombre, estas variables de entorno generalmente se colocan en un archivo `.env`, y el archivo se llama un \"dotenv\".\n\n/// tip | Consejo\n\nUn archivo que comienza con un punto (`.`) es un archivo oculto en sistemas tipo Unix, como Linux y macOS.\n\nPero un archivo dotenv realmente no tiene que tener ese nombre exacto.\n\n///\n\nPydantic tiene soporte para leer desde estos tipos de archivos usando un paquete externo. Puedes leer más en [Pydantic Settings: Dotenv (.env) support](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support).\n\n/// tip | Consejo\n\nPara que esto funcione, necesitas `pip install python-dotenv`.\n\n///\n\n### El archivo `.env` { #the-env-file }\n\nPodrías tener un archivo `.env` con:\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### Leer configuraciones desde `.env` { #read-settings-from-env }\n\nY luego actualizar tu `config.py` con:\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip | Consejo\n\nEl atributo `model_config` se usa solo para configuración de Pydantic. Puedes leer más en [Pydantic: Concepts: Configuration](https://docs.pydantic.dev/latest/concepts/config/).\n\n///\n\nAquí definimos la configuración `env_file` dentro de tu clase Pydantic `Settings`, y establecemos el valor en el nombre del archivo con el archivo dotenv que queremos usar.\n\n### Creando el `Settings` solo una vez con `lru_cache` { #creating-the-settings-only-once-with-lru-cache }\n\nLeer un archivo desde el disco es normalmente una operación costosa (lenta), por lo que probablemente quieras hacerlo solo una vez y luego reutilizar el mismo objeto de configuraciones, en lugar de leerlo para cada request.\n\nPero cada vez que hacemos:\n\n```Python\nSettings()\n```\n\nse crearía un nuevo objeto `Settings`, y al crearse leería el archivo `.env` nuevamente.\n\nSi la función de dependencia fuera simplemente así:\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\ncrearíamos ese objeto para cada request, y estaríamos leyendo el archivo `.env` para cada request. ⚠️\n\nPero como estamos usando el decorador `@lru_cache` encima, el objeto `Settings` se creará solo una vez, la primera vez que se llame. ✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\nEntonces, para cualquier llamada subsiguiente de `get_settings()` en las dependencias de los próximos requests, en lugar de ejecutar el código interno de `get_settings()` y crear un nuevo objeto `Settings`, devolverá el mismo objeto que fue devuelto en la primera llamada, una y otra vez.\n\n#### Detalles Técnicos de `lru_cache` { #lru-cache-technical-details }\n\n`@lru_cache` modifica la función que decora para devolver el mismo valor que se devolvió la primera vez, en lugar de calcularlo nuevamente, ejecutando el código de la función cada vez.\n\nAsí que la función debajo se ejecutará una vez por cada combinación de argumentos. Y luego, los valores devueltos por cada una de esas combinaciones de argumentos se utilizarán una y otra vez cada vez que la función sea llamada con exactamente la misma combinación de argumentos.\n\nPor ejemplo, si tienes una función:\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\ntu programa podría ejecutarse así:\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Código\nparticipant function as say_hi()\nparticipant execute as Ejecutar función\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: ejecutar código de la función\n        execute ->> code: devolver el resultado\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: devolver resultado almacenado\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: ejecutar código de la función\n        execute ->> code: devolver el resultado\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: ejecutar código de la función\n        execute ->> code: devolver el resultado\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: devolver resultado almacenado\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: devolver resultado almacenado\n    end\n```\n\nEn el caso de nuestra dependencia `get_settings()`, la función ni siquiera toma argumentos, por lo que siempre devuelve el mismo valor.\n\nDe esa manera, se comporta casi como si fuera solo una variable global. Pero como usa una función de dependencia, entonces podemos sobrescribirla fácilmente para las pruebas.\n\n`@lru_cache` es parte de `functools`, que es parte del paquete estándar de Python, puedes leer más sobre él en las [docs de Python para `@lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache).\n\n## Resumen { #recap }\n\nPuedes usar Pydantic Settings para manejar las configuraciones o ajustes de tu aplicación, con todo el poder de los modelos de Pydantic.\n\n* Al usar una dependencia, puedes simplificar las pruebas.\n* Puedes usar archivos `.env` con él.\n* Usar `@lru_cache` te permite evitar leer el archivo dotenv una y otra vez para cada request, mientras te permite sobrescribirlo durante las pruebas.\n"
  },
  {
    "path": "docs/es/docs/advanced/stream-data.md",
    "content": "# Transmitir datos { #stream-data }\n\nSi quieres transmitir datos que se puedan estructurar como JSON, deberías [Transmitir JSON Lines](../tutorial/stream-json-lines.md).\n\nPero si quieres transmitir datos binarios puros o strings, aquí tienes cómo hacerlo.\n\n/// info | Información\n\nAñadido en FastAPI 0.134.0.\n\n///\n\n## Casos de uso { #use-cases }\n\nPodrías usar esto si quieres transmitir strings puros, por ejemplo directamente de la salida de un servicio de AI LLM.\n\nTambién podrías usarlo para transmitir archivos binarios grandes, donde transmites cada bloque de datos a medida que lo lees, sin tener que leerlo todo en memoria de una sola vez.\n\nTambién podrías transmitir video o audio de esta manera; incluso podría generarse mientras lo procesas y lo envías.\n\n## Un `StreamingResponse` con `yield` { #a-streamingresponse-with-yield }\n\nSi declaras un `response_class=StreamingResponse` en tu *path operation function*, puedes usar `yield` para enviar cada bloque de datos a su vez.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI entregará cada bloque de datos a `StreamingResponse` tal cual, no intentará convertirlo a JSON ni nada parecido.\n\n### *path operation functions* no async { #non-async-path-operation-functions }\n\nTambién puedes usar funciones `def` normales (sin `async`) y usar `yield` de la misma manera.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### Sin anotación { #no-annotation }\n\nRealmente no necesitas declarar la anotación de tipo de retorno para transmitir datos binarios.\n\nComo FastAPI no intentará convertir los datos a JSON con Pydantic ni serializarlos de ninguna manera, en este caso la anotación de tipos es solo para que la use tu editor y tus herramientas; FastAPI no la usará.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\nEsto también significa que con `StreamingResponse` tienes la libertad y la responsabilidad de producir y codificar los bytes de datos exactamente como necesites enviarlos, independientemente de las anotaciones de tipos. 🤓\n\n### Transmitir bytes { #stream-bytes }\n\nUno de los casos de uso principales sería transmitir `bytes` en lugar de strings; por supuesto puedes hacerlo.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## Un `PNGStreamingResponse` personalizado { #a-custom-pngstreamingresponse }\n\nEn los ejemplos anteriores, se transmitieron los bytes de datos, pero la response no tenía un header `Content-Type`, así que el cliente no sabía qué tipo de datos estaba recibiendo.\n\nPuedes crear una subclase personalizada de `StreamingResponse` que establezca el header `Content-Type` al tipo de datos que estás transmitiendo.\n\nPor ejemplo, puedes crear un `PNGStreamingResponse` que establezca el header `Content-Type` a `image/png` usando el atributo `media_type`:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\nLuego puedes usar esta nueva clase en `response_class=PNGStreamingResponse` en tu *path operation function*:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### Simular un archivo { #simulate-a-file }\n\nEn este ejemplo estamos simulando un archivo con `io.BytesIO`, que es un objeto tipo archivo que vive solo en memoria, pero nos permite usar la misma interfaz.\n\nPor ejemplo, podemos iterarlo para consumir su contenido, como podríamos con un archivo.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | Detalles técnicos\n\nLas otras dos variables, `image_base64` y `binary_image`, son una imagen codificada en Base64 y luego convertida a bytes, para después pasarla a `io.BytesIO`.\n\nSolo para que pueda vivir en el mismo archivo para este ejemplo y puedas copiarlo y ejecutarlo tal cual. 🥚\n\n///\n\nAl usar un bloque `with`, nos aseguramos de que el objeto tipo archivo se cierre cuando termine la función generadora (la función con `yield`). Es decir, después de que termine de enviar la response.\n\nNo sería tan importante en este ejemplo específico porque es un archivo falso en memoria (con `io.BytesIO`), pero con un archivo real sí sería importante asegurarse de que el archivo se cierre al terminar de trabajar con él.\n\n### Archivos y async { #files-and-async }\n\nEn la mayoría de los casos, los objetos tipo archivo no son compatibles con `async` y `await` por defecto.\n\nPor ejemplo, no tienen un `await file.read()`, ni un `async for chunk in file`.\n\nY en muchos casos leerlos sería una operación bloqueante (que podría bloquear el event loop), porque se leen desde disco o desde la red.\n\n/// info | Información\n\nEl ejemplo anterior es en realidad una excepción, porque el objeto `io.BytesIO` ya está en memoria, así que leerlo no bloqueará nada.\n\nPero en muchos casos leer un archivo u objeto tipo archivo sí bloquearía.\n\n///\n\nPara evitar bloquear el event loop, puedes simplemente declarar la *path operation function* con un `def` normal en lugar de `async def`; de esa forma FastAPI la ejecutará en un worker de threadpool para evitar bloquear el loop principal.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip | Consejo\n\nSi necesitas llamar código bloqueante desde dentro de una función async, o una función async desde dentro de una función bloqueante, podrías usar [Asyncer](https://asyncer.tiangolo.com), un paquete hermano de FastAPI.\n\n///\n\n### `yield from` { #yield-from }\n\nCuando estés iterando sobre algo, como un objeto tipo archivo, y estés haciendo `yield` para cada elemento, también podrías usar `yield from` para hacer `yield` de cada elemento directamente y saltarte el `for`.\n\nEsto no es particular de FastAPI, es simplemente Python, pero es un truco útil que conviene conocer. 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/es/docs/advanced/strict-content-type.md",
    "content": "# Chequeo estricto de Content-Type { #strict-content-type-checking }\n\nPor defecto, **FastAPI** usa un chequeo estricto del header `Content-Type` para request bodies JSON, esto significa que las requests JSON deben incluir un header `Content-Type` válido (p. ej. `application/json`) para que el request body se parse como JSON.\n\n## Riesgo de CSRF { #csrf-risk }\n\nEste comportamiento por defecto provee protección contra una clase de ataques de **Cross-Site Request Forgery (CSRF)** en un escenario muy específico.\n\nEstos ataques aprovechan que los navegadores permiten que los scripts envíen requests sin hacer un preflight de CORS cuando:\n\n* no tienen un header `Content-Type` (p. ej. usando `fetch()` con un body `Blob`)\n* y no envían credenciales de autenticación.\n\nEste tipo de ataque es relevante principalmente cuando:\n\n* la aplicación corre localmente (p. ej. en `localhost`) o en una red interna\n* y la aplicación no tiene ninguna autenticación, espera que cualquier request de la misma red sea confiable.\n\n## Ejemplo de ataque { #example-attack }\n\nImagina que construyes una forma de ejecutar un agente de IA local.\n\nProvee un API en\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nTambién hay un frontend en\n\n```\nhttp://localhost:8000\n```\n\n/// tip | Consejo\n\nTen en cuenta que ambos tienen el mismo host.\n\n///\n\nLuego, usando el frontend, puedes hacer que el agente de IA haga cosas en tu nombre.\n\nComo está corriendo localmente y no en Internet abierta, decides no tener ninguna autenticación configurada, confiando simplemente en el acceso a la red local.\n\nEntonces, uno de tus usuarios podría instalarlo y ejecutarlo localmente.\n\nDespués podría abrir un sitio web malicioso, por ejemplo algo como\n\n```\nhttps://evilhackers.example.com\n```\n\nY ese sitio malicioso envía requests usando `fetch()` con un body `Blob` al API local en\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nAunque el host del sitio malicioso y el de la app local sea diferente, el navegador no disparará un preflight de CORS porque:\n\n* Está corriendo sin ninguna autenticación, no tiene que enviar credenciales.\n* El navegador cree que no está enviando JSON (por la falta del header `Content-Type`).\n\nEntonces el sitio malicioso podría hacer que el agente de IA local envíe mensajes agresivos al exjefe del usuario... o peor. 😅\n\n## Internet abierta { #open-internet }\n\nSi tu app está en Internet abierta, no “confiarías en la red” ni permitirías que cualquiera envíe requests privilegiadas sin autenticación.\n\nLos atacantes podrían simplemente ejecutar un script para enviar requests a tu API, sin necesidad de interacción del navegador, así que probablemente ya estás asegurando cualquier endpoint privilegiado.\n\nEn ese caso, este ataque/riesgo no aplica a ti.\n\nEste riesgo y ataque es relevante principalmente cuando la app corre en la red local y esa es la única protección asumida.\n\n## Permitir requests sin Content-Type { #allowing-requests-without-content-type }\n\nSi necesitas soportar clientes que no envían un header `Content-Type`, puedes desactivar el chequeo estricto configurando `strict_content_type=False`:\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\nCon esta configuración, las requests sin un header `Content-Type` tendrán su body parseado como JSON, que es el mismo comportamiento de versiones anteriores de FastAPI.\n\n/// info | Información\n\nEste comportamiento y configuración se añadieron en FastAPI 0.132.0.\n\n///\n"
  },
  {
    "path": "docs/es/docs/advanced/sub-applications.md",
    "content": "# Sub Aplicaciones - Mounts { #sub-applications-mounts }\n\nSi necesitas tener dos aplicaciones de **FastAPI** independientes, cada una con su propio OpenAPI independiente y su propia interfaz de docs, puedes tener una aplicación principal y \"montar\" una (o más) sub-aplicación(es).\n\n## Montar una aplicación **FastAPI** { #mounting-a-fastapi-application }\n\n\"Montar\" significa añadir una aplicación completamente \"independiente\" en un path específico, que luego se encarga de manejar todo bajo ese path, con las _path operations_ declaradas en esa sub-aplicación.\n\n### Aplicación de nivel superior { #top-level-application }\n\nPrimero, crea la aplicación principal de nivel superior de **FastAPI**, y sus *path operations*:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### Sub-aplicación { #sub-application }\n\nLuego, crea tu sub-aplicación, y sus *path operations*.\n\nEsta sub-aplicación es solo otra aplicación estándar de FastAPI, pero es la que se \"montará\":\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### Montar la sub-aplicación { #mount-the-sub-application }\n\nEn tu aplicación de nivel superior, `app`, monta la sub-aplicación, `subapi`.\n\nEn este caso, se montará en el path `/subapi`:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### Revisa la documentación automática de la API { #check-the-automatic-api-docs }\n\nAhora, ejecuta el comando `fastapi`:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nY abre la documentación en [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVerás la documentación automática de la API para la aplicación principal, incluyendo solo sus propias _path operations_:\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\nY luego, abre la documentación para la sub-aplicación, en [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs).\n\nVerás la documentación automática de la API para la sub-aplicación, incluyendo solo sus propias _path operations_, todas bajo el prefijo correcto del sub-path `/subapi`:\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\nSi intentas interactuar con cualquiera de las dos interfaces de usuario, funcionarán correctamente, porque el navegador podrá comunicarse con cada aplicación o sub-aplicación específica.\n\n### Detalles Técnicos: `root_path` { #technical-details-root-path }\n\nCuando montas una sub-aplicación como se describe arriba, FastAPI se encargará de comunicar el path de montaje para la sub-aplicación usando un mecanismo de la especificación ASGI llamado `root_path`.\n\nDe esa manera, la sub-aplicación sabrá usar ese prefijo de path para la interfaz de documentación.\n\nY la sub-aplicación también podría tener sus propias sub-aplicaciones montadas y todo funcionaría correctamente, porque FastAPI maneja todos estos `root_path`s automáticamente.\n\nAprenderás más sobre el `root_path` y cómo usarlo explícitamente en la sección sobre [Detrás de un Proxy](behind-a-proxy.md).\n"
  },
  {
    "path": "docs/es/docs/advanced/templates.md",
    "content": "# Plantillas { #templates }\n\nPuedes usar cualquier motor de plantillas que desees con **FastAPI**.\n\nUna elección común es Jinja2, el mismo que usa Flask y otras herramientas.\n\nHay utilidades para configurarlo fácilmente que puedes usar directamente en tu aplicación de **FastAPI** (proporcionadas por Starlette).\n\n## Instala dependencias { #install-dependencies }\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo e instalar `jinja2`:\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## Usando `Jinja2Templates` { #using-jinja2templates }\n\n* Importa `Jinja2Templates`.\n* Crea un objeto `templates` que puedas reutilizar más tarde.\n* Declara un parámetro `Request` en la *path operation* que devolverá una plantilla.\n* Usa los `templates` que creaste para renderizar y devolver un `TemplateResponse`, pasa el nombre de la plantilla, el objeto de request, y un diccionario \"context\" con pares clave-valor que se usarán dentro de la plantilla Jinja2.\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note | Nota\n\nAntes de FastAPI 0.108.0, Starlette 0.29.0, el `name` era el primer parámetro.\n\nAdemás, antes de eso, en versiones anteriores, el objeto `request` se pasaba como parte de los pares clave-valor en el contexto para Jinja2.\n\n///\n\n/// tip | Consejo\n\nAl declarar `response_class=HTMLResponse`, la interfaz de usuario de la documentación podrá saber que el response será HTML.\n\n///\n\n/// note | Detalles técnicos\n\nTambién podrías usar `from starlette.templating import Jinja2Templates`.\n\n**FastAPI** proporciona el mismo `starlette.templating` como `fastapi.templating`, solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette. Lo mismo con `Request` y `StaticFiles`.\n\n///\n\n## Escribiendo plantillas { #writing-templates }\n\nLuego puedes escribir una plantilla en `templates/item.html` con, por ejemplo:\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### Valores de Contexto de la Plantilla { #template-context-values }\n\nEn el HTML que contiene:\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n...mostrará el `id` tomado del `dict` de \"contexto\" que pasaste:\n\n```Python\n{\"id\": id}\n```\n\nPor ejemplo, con un ID de `42`, esto se renderizaría como:\n\n```html\nItem ID: 42\n```\n\n### Argumentos de la Plantilla `url_for` { #template-url-for-arguments }\n\nTambién puedes usar `url_for()` dentro de la plantilla, toma como argumentos los mismos que usaría tu *path operation function*.\n\nEntonces, la sección con:\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n...generará un enlace hacia la misma URL que manejaría la *path operation function* `read_item(id=id)`.\n\nPor ejemplo, con un ID de `42`, esto se renderizaría como:\n\n```html\n<a href=\"/items/42\">\n```\n\n## Plantillas y archivos estáticos { #templates-and-static-files }\n\nTambién puedes usar `url_for()` dentro de la plantilla, y usarlo, por ejemplo, con los `StaticFiles` que montaste con el `name=\"static\"`.\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\nEn este ejemplo, enlazaría a un archivo CSS en `static/styles.css` con:\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\nY porque estás usando `StaticFiles`, ese archivo CSS sería servido automáticamente por tu aplicación de **FastAPI** en la URL `/static/styles.css`.\n\n## Más detalles { #more-details }\n\nPara más detalles, incluyendo cómo testear plantillas, revisa [la documentación de Starlette sobre plantillas](https://www.starlette.dev/templates/).\n"
  },
  {
    "path": "docs/es/docs/advanced/testing-dependencies.md",
    "content": "# Probando Dependencias con Overrides { #testing-dependencies-with-overrides }\n\n## Sobrescribir dependencias durante las pruebas { #overriding-dependencies-during-testing }\n\nHay algunos escenarios donde podrías querer sobrescribir una dependencia durante las pruebas.\n\nNo quieres que la dependencia original se ejecute (ni ninguna de las sub-dependencias que pueda tener).\n\nEn cambio, quieres proporcionar una dependencia diferente que se usará solo durante las pruebas (posiblemente solo algunas pruebas específicas), y que proporcionará un valor que pueda ser usado donde se usó el valor de la dependencia original.\n\n### Casos de uso: servicio externo { #use-cases-external-service }\n\nUn ejemplo podría ser que tienes un proveedor de autenticación externo al que necesitas llamar.\n\nLe envías un token y te devuelve un usuario autenticado.\n\nEste proveedor podría estar cobrándote por cada request, y llamarlo podría tomar más tiempo adicional que si tuvieras un usuario mock fijo para los tests.\n\nProbablemente quieras probar el proveedor externo una vez, pero no necesariamente llamarlo para cada test que se realice.\n\nEn este caso, puedes sobrescribir la dependencia que llama a ese proveedor y usar una dependencia personalizada que devuelva un usuario mock, solo para tus tests.\n\n### Usa el atributo `app.dependency_overrides` { #use-the-app-dependency-overrides-attribute }\n\nPara estos casos, tu aplicación **FastAPI** tiene un atributo `app.dependency_overrides`, es un simple `dict`.\n\nPara sobrescribir una dependencia para las pruebas, colocas como clave la dependencia original (una función), y como valor, tu dependencia para sobreescribir (otra función).\n\nY entonces **FastAPI** llamará a esa dependencia para sobreescribir en lugar de la dependencia original.\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip | Consejo\n\nPuedes sobreescribir una dependencia utilizada en cualquier lugar de tu aplicación **FastAPI**.\n\nLa dependencia original podría ser utilizada en una *path operation function*, un *path operation decorator* (cuando no usas el valor de retorno), una llamada a `.include_router()`, etc.\n\nFastAPI todavía podrá sobrescribirla.\n\n///\n\nEntonces puedes restablecer las dependencias sobreescritas (eliminarlas) configurando `app.dependency_overrides` para que sea un `dict` vacío:\n\n```Python\napp.dependency_overrides = {}\n```\n\n/// tip | Consejo\n\nSi quieres sobrescribir una dependencia solo durante algunos tests, puedes establecer la sobrescritura al inicio del test (dentro de la función del test) y restablecerla al final (al final de la función del test).\n\n///\n"
  },
  {
    "path": "docs/es/docs/advanced/testing-events.md",
    "content": "# Eventos de testing: lifespan y startup - shutdown { #testing-events-lifespan-and-startup-shutdown }\n\nCuando necesitas que `lifespan` se ejecute en tus tests, puedes usar el `TestClient` con un statement `with`:\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\n\nPuedes leer más detalles sobre [\"Ejecutar lifespan en tests en el sitio oficial de documentación de Starlette.\"](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)\n\nPara los eventos obsoletos `startup` y `shutdown`, puedes usar el `TestClient` así:\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/es/docs/advanced/testing-websockets.md",
    "content": "# Probando WebSockets { #testing-websockets }\n\nPuedes usar el mismo `TestClient` para probar WebSockets.\n\nPara esto, usas el `TestClient` en un statement `with`, conectándote al WebSocket:\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note | Nota\n\nPara más detalles, revisa la documentación de Starlette sobre [probar WebSockets](https://www.starlette.dev/testclient/#testing-websocket-sessions).\n\n///\n"
  },
  {
    "path": "docs/es/docs/advanced/using-request-directly.md",
    "content": "# Usar el Request Directamente { #using-the-request-directly }\n\nHasta ahora, has estado declarando las partes del request que necesitas con sus tipos.\n\nTomando datos de:\n\n* El path como parámetros.\n* Headers.\n* Cookies.\n* etc.\n\nY al hacerlo, **FastAPI** está validando esos datos, convirtiéndolos y generando documentación para tu API automáticamente.\n\nPero hay situaciones donde podrías necesitar acceder al objeto `Request` directamente.\n\n## Detalles sobre el objeto `Request` { #details-about-the-request-object }\n\nComo **FastAPI** es en realidad **Starlette** por debajo, con una capa de varias herramientas encima, puedes usar el objeto de Starlette [`Request`](https://www.starlette.dev/requests/) directamente cuando lo necesites.\n\nTambién significa que si obtienes datos del objeto `Request` directamente (por ejemplo, leyendo el cuerpo) no serán validados, convertidos o documentados (con OpenAPI, para la interfaz automática de usuario de la API) por FastAPI.\n\nAunque cualquier otro parámetro declarado normalmente (por ejemplo, el cuerpo con un modelo de Pydantic) seguiría siendo validado, convertido, anotado, etc.\n\nPero hay casos específicos donde es útil obtener el objeto `Request`.\n\n## Usa el objeto `Request` directamente { #use-the-request-object-directly }\n\nImaginemos que quieres obtener la dirección IP/host del cliente dentro de tu *path operation function*.\n\nPara eso necesitas acceder al request directamente.\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\nAl declarar un parámetro de *path operation function* con el tipo siendo `Request`, **FastAPI** sabrá pasar el `Request` en ese parámetro.\n\n/// tip | Consejo\n\nNota que en este caso, estamos declarando un parámetro de path además del parámetro del request.\n\nAsí que, el parámetro de path será extraído, validado, convertido al tipo especificado y anotado con OpenAPI.\n\nDe la misma manera, puedes declarar cualquier otro parámetro como normalmente, y adicionalmente, obtener también el `Request`.\n\n///\n\n## Documentación de `Request` { #request-documentation }\n\nPuedes leer más detalles sobre el [objeto `Request` en el sitio de documentación oficial de Starlette](https://www.starlette.dev/requests/).\n\n/// note | Detalles Técnicos\n\nPodrías también usar `from starlette.requests import Request`.\n\n**FastAPI** lo proporciona directamente solo como conveniencia para ti, el desarrollador. Pero viene directamente de Starlette.\n\n///\n"
  },
  {
    "path": "docs/es/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\nPuedes usar [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) con **FastAPI**.\n\n## Instalar `websockets` { #install-websockets }\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo e instalar `websockets` (un paquete de Python que facilita usar el protocolo \"WebSocket\"):\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## Cliente WebSockets { #websockets-client }\n\n### En producción { #in-production }\n\nEn tu sistema de producción, probablemente tengas un frontend creado con un framework moderno como React, Vue.js o Angular.\n\nY para comunicarte usando WebSockets con tu backend probablemente usarías las utilidades de tu frontend.\n\nO podrías tener una aplicación móvil nativa que se comunica con tu backend de WebSocket directamente, en código nativo.\n\nO podrías tener alguna otra forma de comunicarte con el endpoint de WebSocket.\n\n---\n\nPero para este ejemplo, usaremos un documento HTML muy simple con algo de JavaScript, todo dentro de un string largo.\n\nEsto, por supuesto, no es lo ideal y no lo usarías para producción.\n\nEn producción tendrías una de las opciones anteriores.\n\nPero es la forma más sencilla de enfocarse en el lado del servidor de WebSockets y tener un ejemplo funcional:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## Crear un `websocket` { #create-a-websocket }\n\nEn tu aplicación de **FastAPI**, crea un `websocket`:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | Detalles Técnicos\n\nTambién podrías usar `from starlette.websockets import WebSocket`.\n\n**FastAPI** proporciona el mismo `WebSocket` directamente solo como una conveniencia para ti, el desarrollador. Pero viene directamente de Starlette.\n\n///\n\n## Esperar mensajes y enviar mensajes { #await-for-messages-and-send-messages }\n\nEn tu ruta de WebSocket puedes `await` para recibir mensajes y enviar mensajes.\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\nPuedes recibir y enviar datos binarios, de texto y JSON.\n\n## Pruébalo { #try-it }\n\nPon tu código en un archivo `main.py` y luego ejecuta tu aplicación:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nAbre tu navegador en [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nVerás una página simple como:\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\nPuedes escribir mensajes en el cuadro de entrada y enviarlos:\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\nY tu aplicación **FastAPI** con WebSockets responderá de vuelta:\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\nPuedes enviar (y recibir) muchos mensajes:\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\nY todos usarán la misma conexión WebSocket.\n\n## Usando `Depends` y otros { #using-depends-and-others }\n\nEn endpoints de WebSocket puedes importar desde `fastapi` y usar:\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\nFuncionan de la misma manera que para otros endpoints de FastAPI/*path operations*:\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info | Información\n\nComo esto es un WebSocket no tiene mucho sentido lanzar un `HTTPException`, en su lugar lanzamos un `WebSocketException`.\n\nPuedes usar un código de cierre de los [códigos válidos definidos en la especificación](https://tools.ietf.org/html/rfc6455#section-7.4.1).\n\n///\n\n### Prueba los WebSockets con dependencias { #try-the-websockets-with-dependencies }\n\nEjecuta tu aplicación:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nAbre tu navegador en [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nAhí puedes establecer:\n\n* El \"ID del Ítem\", usado en el path.\n* El \"Token\" usado como un parámetro query.\n\n/// tip | Consejo\n\nNota que el query `token` será manejado por una dependencia.\n\n///\n\nCon eso puedes conectar el WebSocket y luego enviar y recibir mensajes:\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## Manejar desconexiones y múltiples clientes { #handling-disconnections-and-multiple-clients }\n\nCuando una conexión de WebSocket se cierra, el `await websocket.receive_text()` lanzará una excepción `WebSocketDisconnect`, que puedes capturar y manejar como en este ejemplo.\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\nPara probarlo:\n\n* Abre la aplicación con varias pestañas del navegador.\n* Escribe mensajes desde ellas.\n* Luego cierra una de las pestañas.\n\nEso lanzará la excepción `WebSocketDisconnect`, y todos los otros clientes recibirán un mensaje como:\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip | Consejo\n\nLa aplicación anterior es un ejemplo mínimo y simple para demostrar cómo manejar y transmitir mensajes a varias conexiones WebSocket.\n\nPero ten en cuenta que, como todo se maneja en memoria, en una sola lista, solo funcionará mientras el proceso esté en ejecución, y solo funcionará con un solo proceso.\n\nSi necesitas algo fácil de integrar con FastAPI pero que sea más robusto, soportado por Redis, PostgreSQL u otros, revisa [encode/broadcaster](https://github.com/encode/broadcaster).\n\n///\n\n## Más información { #more-info }\n\nPara aprender más sobre las opciones, revisa la documentación de Starlette para:\n\n* [La clase `WebSocket`](https://www.starlette.dev/websockets/).\n* [Manejo de WebSocket basado en clases](https://www.starlette.dev/endpoints/#websocketendpoint).\n"
  },
  {
    "path": "docs/es/docs/advanced/wsgi.md",
    "content": "# Incluyendo WSGI - Flask, Django, otros { #including-wsgi-flask-django-others }\n\nPuedes montar aplicaciones WSGI como viste con [Sub Aplicaciones - Mounts](sub-applications.md), [Detrás de un Proxy](behind-a-proxy.md).\n\nPara eso, puedes usar el `WSGIMiddleware` y usarlo para envolver tu aplicación WSGI, por ejemplo, Flask, Django, etc.\n\n## Usando `WSGIMiddleware` { #using-wsgimiddleware }\n\n/// info | Información\n\nEsto requiere instalar `a2wsgi`, por ejemplo con `pip install a2wsgi`.\n\n///\n\nNecesitas importar `WSGIMiddleware` de `a2wsgi`.\n\nLuego envuelve la aplicación WSGI (p. ej., Flask) con el middleware.\n\nY luego móntala bajo un path.\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note | Nota\n\nAnteriormente, se recomendaba usar `WSGIMiddleware` de `fastapi.middleware.wsgi`, pero ahora está deprecado.\n\nSe aconseja usar el paquete `a2wsgi` en su lugar. El uso sigue siendo el mismo.\n\nSolo asegúrate de tener instalado el paquete `a2wsgi` e importar `WSGIMiddleware` correctamente desde `a2wsgi`.\n\n///\n\n## Revisa { #check-it }\n\nAhora, cada request bajo el path `/v1/` será manejado por la aplicación Flask.\n\nY el resto será manejado por **FastAPI**.\n\nSi lo ejecutas y vas a [http://localhost:8000/v1/](http://localhost:8000/v1/) verás el response de Flask:\n\n```txt\nHello, World from Flask!\n```\n\nY si vas a [http://localhost:8000/v2](http://localhost:8000/v2) verás el response de FastAPI:\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/es/docs/alternatives.md",
    "content": "# Alternativas, Inspiración y Comparaciones { #alternatives-inspiration-and-comparisons }\n\nLo que inspiró a **FastAPI**, cómo se compara con las alternativas y lo que aprendió de ellas.\n\n## Introducción { #intro }\n\n**FastAPI** no existiría si no fuera por el trabajo previo de otros.\n\nSe han creado muchas herramientas antes que han ayudado a inspirar su creación.\n\nHe estado evitando la creación de un nuevo framework durante varios años. Primero intenté resolver todas las funcionalidades cubiertas por **FastAPI** usando muchos frameworks diferentes, plug-ins y herramientas.\n\nPero en algún punto, no hubo otra opción que crear algo que proporcionara todas estas funcionalidades, tomando las mejores ideas de herramientas previas y combinándolas de la mejor manera posible, usando funcionalidades del lenguaje que ni siquiera estaban disponibles antes (anotaciones de tipos de Python 3.6+).\n\n## Herramientas previas { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\nEs el framework más popular de Python y es ampliamente confiable. Se utiliza para construir sistemas como Instagram.\n\nEstá relativamente acoplado con bases de datos relacionales (como MySQL o PostgreSQL), por lo que tener una base de datos NoSQL (como Couchbase, MongoDB, Cassandra, etc) como motor de almacenamiento principal no es muy fácil.\n\nFue creado para generar el HTML en el backend, no para crear APIs utilizadas por un frontend moderno (como React, Vue.js y Angular) o por otros sistemas (como dispositivos del <abbr title=\"Internet of Things - Internet de las cosas\">IoT</abbr>) comunicándose con él.\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nEl framework Django REST fue creado para ser un kit de herramientas flexible para construir APIs Web utilizando Django, mejorando sus capacidades API.\n\nEs utilizado por muchas empresas, incluidas Mozilla, Red Hat y Eventbrite.\n\nFue uno de los primeros ejemplos de **documentación automática de APIs**, y esto fue específicamente una de las primeras ideas que inspiraron \"la búsqueda de\" **FastAPI**.\n\n/// note | Nota\n\nDjango REST Framework fue creado por Tom Christie. El mismo creador de Starlette y Uvicorn, en los cuales **FastAPI** está basado.\n\n///\n\n/// check | Inspiró a **FastAPI** a\n\nTener una interfaz de usuario web de documentación automática de APIs.\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask es un \"microframework\", no incluye integraciones de bases de datos ni muchas de las cosas que vienen por defecto en Django.\n\nEsta simplicidad y flexibilidad permiten hacer cosas como usar bases de datos NoSQL como el sistema de almacenamiento de datos principal.\n\nComo es muy simple, es relativamente intuitivo de aprender, aunque la documentación se vuelve algo técnica en algunos puntos.\n\nTambién se utiliza comúnmente para otras aplicaciones que no necesariamente necesitan una base de datos, gestión de usuarios, o cualquiera de las muchas funcionalidades que vienen preconstruidas en Django. Aunque muchas de estas funcionalidades se pueden añadir con plug-ins.\n\nEsta separación de partes, y ser un \"microframework\" que podría extenderse para cubrir exactamente lo que se necesita, fue una funcionalidad clave que quise mantener.\n\nDada la simplicidad de Flask, parecía una buena opción para construir APIs. Lo siguiente a encontrar era un \"Django REST Framework\" para Flask.\n\n/// check | Inspiró a **FastAPI** a\n\nSer un micro-framework. Haciendo fácil mezclar y combinar las herramientas y partes necesarias.\n\nTener un sistema de routing simple y fácil de usar.\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI** no es en realidad una alternativa a **Requests**. Su ámbito es muy diferente.\n\nDe hecho, sería común usar Requests *dentro* de una aplicación FastAPI.\n\nAun así, FastAPI se inspiró bastante en Requests.\n\n**Requests** es un paquete para *interactuar* con APIs (como cliente), mientras que **FastAPI** es un paquete para *construir* APIs (como servidor).\n\nEstán, más o menos, en extremos opuestos, complementándose entre sí.\n\nRequests tiene un diseño muy simple e intuitivo, es muy fácil de usar, con valores por defecto sensatos. Pero al mismo tiempo, es muy poderoso y personalizable.\n\nPor eso, como se dice en el sitio web oficial:\n\n> Requests es uno de los paquetes Python más descargados de todos los tiempos\n\nLa forma en que lo usas es muy sencilla. Por ejemplo, para hacer un `GET` request, escribirías:\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\nLa operación de path equivalente en FastAPI podría verse como:\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\nMira las similitudes entre `requests.get(...)` y `@app.get(...)`.\n\n/// check | Inspiró a **FastAPI** a\n\n* Tener un API simple e intuitivo.\n* Usar nombres de métodos HTTP (operaciones) directamente, de una manera sencilla e intuitiva.\n* Tener valores por defecto sensatos, pero personalizaciones poderosas.\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\nLa principal funcionalidad que quería de Django REST Framework era la documentación automática de la API.\n\nLuego descubrí que había un estándar para documentar APIs, usando JSON (o YAML, una extensión de JSON) llamado Swagger.\n\nY ya existía una interfaz de usuario web para las APIs Swagger. Por lo tanto, ser capaz de generar documentación Swagger para una API permitiría usar esta interfaz de usuario web automáticamente.\n\nEn algún punto, Swagger fue entregado a la Linux Foundation, para ser renombrado OpenAPI.\n\nEs por eso que cuando se habla de la versión 2.0 es común decir \"Swagger\", y para la versión 3+ \"OpenAPI\".\n\n/// check | Inspiró a **FastAPI** a\n\nAdoptar y usar un estándar abierto para especificaciones de API, en lugar de usar un esquema personalizado.\n\nY a integrar herramientas de interfaz de usuario basadas en estándares:\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\nEstas dos fueron elegidas por ser bastante populares y estables, pero haciendo una búsqueda rápida, podrías encontrar docenas de interfaces de usuario alternativas para OpenAPI (que puedes usar con **FastAPI**).\n\n///\n\n### Frameworks REST para Flask { #flask-rest-frameworks }\n\nExisten varios frameworks REST para Flask, pero después de invertir tiempo y trabajo investigándolos, encontré que muchos son descontinuados o abandonados, con varios problemas existentes que los hacían inadecuados.\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nUna de las principales funcionalidades necesitadas por los sistemas API es la \"<dfn title=\"también llamado marshalling, conversión\">serialización</dfn>\" de datos, que consiste en tomar datos del código (Python) y convertirlos en algo que pueda ser enviado a través de la red. Por ejemplo, convertir un objeto que contiene datos de una base de datos en un objeto JSON. Convertir objetos `datetime` en strings, etc.\n\nOtra gran funcionalidad necesaria por las APIs es la validación de datos, asegurarse de que los datos sean válidos, dados ciertos parámetros. Por ejemplo, que algún campo sea un `int`, y no algún string aleatorio. Esto es especialmente útil para los datos entrantes.\n\nSin un sistema de validación de datos, tendrías que hacer todas las comprobaciones a mano, en código.\n\nEstas funcionalidades son para lo que fue creado Marshmallow. Es un gran paquete, y lo he usado mucho antes.\n\nPero fue creado antes de que existieran las anotaciones de tipos en Python. Así que, para definir cada <dfn title=\"la definición de cómo deberían formarse los datos\">esquema</dfn> necesitas usar utilidades y clases específicas proporcionadas por Marshmallow.\n\n/// check | Inspiró a **FastAPI** a\n\nUsar código para definir \"esquemas\" que proporcionen tipos de datos y validación automáticamente.\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nOtra gran funcionalidad requerida por las APIs es el <dfn title=\"lectura y conversión a datos de Python\">parsing</dfn> de datos de las requests entrantes.\n\nWebargs es una herramienta que fue creada para proporcionar esa funcionalidad sobre varios frameworks, incluido Flask.\n\nUsa Marshmallow por debajo para hacer la validación de datos. Y fue creada por los mismos desarrolladores.\n\nEs una gran herramienta y la he usado mucho también, antes de tener **FastAPI**.\n\n/// info | Información\n\nWebargs fue creada por los mismos desarrolladores de Marshmallow.\n\n///\n\n/// check | Inspiró a **FastAPI** a\n\nTener validación automática de datos entrantes en una request.\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow y Webargs proporcionan validación, parsing y serialización como plug-ins.\n\nPero la documentación todavía falta. Entonces APISpec fue creado.\n\nEs un plug-in para muchos frameworks (y hay un plug-in para Starlette también).\n\nLa manera en que funciona es que escribes la definición del esquema usando el formato YAML dentro del docstring de cada función que maneja una ruta.\n\nY genera esquemas OpenAPI.\n\nAsí es como funciona en Flask, Starlette, Responder, etc.\n\nPero luego, tenemos otra vez el problema de tener una micro-sintaxis, dentro de un string de Python (un gran YAML).\n\nEl editor no puede ayudar mucho con eso. Y si modificamos parámetros o esquemas de Marshmallow y olvidamos también modificar ese docstring YAML, el esquema generado estaría obsoleto.\n\n/// info | Información\n\nAPISpec fue creado por los mismos desarrolladores de Marshmallow.\n\n///\n\n/// check | Inspiró a **FastAPI** a\n\nSoportar el estándar abierto para APIs, OpenAPI.\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\nEs un plug-in de Flask, que conecta juntos Webargs, Marshmallow y APISpec.\n\nUsa la información de Webargs y Marshmallow para generar automáticamente esquemas OpenAPI, usando APISpec.\n\nEs una gran herramienta, muy subestimada. Debería ser mucho más popular que muchos plug-ins de Flask por ahí. Puede que se deba a que su documentación es demasiado concisa y abstracta.\n\nEsto resolvió tener que escribir YAML (otra sintaxis) dentro de docstrings de Python.\n\nEsta combinación de Flask, Flask-apispec con Marshmallow y Webargs fue mi stack de backend favorito hasta construir **FastAPI**.\n\nUsarlo llevó a la creación de varios generadores de full-stack para Flask. Estos son los principales stacks que yo (y varios equipos externos) hemos estado usando hasta ahora:\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\nY estos mismos generadores de full-stack fueron la base de los [Generadores de Proyectos **FastAPI**](project-generation.md).\n\n/// info | Información\n\nFlask-apispec fue creado por los mismos desarrolladores de Marshmallow.\n\n///\n\n/// check | Inspiró a **FastAPI** a\n\nGenerar el esquema OpenAPI automáticamente, desde el mismo código que define la serialización y validación.\n\n///\n\n### [NestJS](https://nestjs.com/) (y [Angular](https://angular.io/)) { #nestjs-and-angular }\n\nEsto ni siquiera es Python, NestJS es un framework de JavaScript (TypeScript) NodeJS inspirado por Angular.\n\nLogra algo algo similar a lo que se puede hacer con Flask-apispec.\n\nTiene un sistema de inyección de dependencias integrado, inspirado por Angular 2. Requiere pre-registrar los \"inyectables\" (como todos los otros sistemas de inyección de dependencias que conozco), por lo que añade a la verbosidad y repetición de código.\n\nComo los parámetros se describen con tipos de TypeScript (similar a las anotaciones de tipos en Python), el soporte editorial es bastante bueno.\n\nPero como los datos de TypeScript no se preservan después de la compilación a JavaScript, no puede depender de los tipos para definir validación, serialización y documentación al mismo tiempo. Debido a esto y algunas decisiones de diseño, para obtener validación, serialización y generación automática del esquema, es necesario agregar decoradores en muchos lugares. Por lo tanto, se vuelve bastante verboso.\n\nNo puede manejar muy bien modelos anidados. Entonces, si el cuerpo JSON en la request es un objeto JSON que tiene campos internos que a su vez son objetos JSON anidados, no puede ser documentado y validado apropiadamente.\n\n/// check | Inspiró a **FastAPI** a\n\nUsar tipos de Python para tener un gran soporte del editor.\n\nTener un poderoso sistema de inyección de dependencias. Encontrar una forma de minimizar la repetición de código.\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\nFue uno de los primeros frameworks de Python extremadamente rápidos basados en `asyncio`. Fue hecho para ser muy similar a Flask.\n\n/// note | Detalles Técnicos\n\nUsó [`uvloop`](https://github.com/MagicStack/uvloop) en lugar del loop `asyncio` por defecto de Python. Eso fue lo que lo hizo tan rápido.\n\nClaramente inspiró a Uvicorn y Starlette, que actualmente son más rápidos que Sanic en benchmarks abiertos.\n\n///\n\n/// check | Inspiró a **FastAPI** a\n\nEncontrar una manera de tener un rendimiento impresionante.\n\nPor eso **FastAPI** se basa en Starlette, ya que es el framework más rápido disponible (probado por benchmarks de terceros).\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon es otro framework de Python de alto rendimiento, está diseñado para ser minimalista y funcionar como la base de otros frameworks como Hug.\n\nEstá diseñado para tener funciones que reciben dos parámetros, un \"request\" y un \"response\". Luego \"lees\" partes del request y \"escribes\" partes en el response. Debido a este diseño, no es posible declarar parámetros de request y cuerpos con las anotaciones de tipos estándar de Python como parámetros de función.\n\nPor lo tanto, la validación de datos, la serialización y la documentación, tienen que hacerse en código, no automáticamente. O tienen que implementarse como un framework sobre Falcon, como Hug. Esta misma distinción ocurre en otros frameworks que se inspiran en el diseño de Falcon, de tener un objeto request y un objeto response como parámetros.\n\n/// check | Inspiró a **FastAPI** a\n\nBuscar maneras de obtener un gran rendimiento.\n\nJunto con Hug (ya que Hug se basa en Falcon), inspiraron a **FastAPI** a declarar un parámetro `response` en las funciones.\n\nAunque en FastAPI es opcional, y se utiliza principalmente para configurar headers, cookies y códigos de estado alternativos.\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\nDescubrí Molten en las primeras etapas de construcción de **FastAPI**. Y tiene ideas bastante similares:\n\n* Basado en las anotaciones de tipos de Python.\n* Validación y documentación a partir de estos tipos.\n* Sistema de Inyección de Dependencias.\n\nNo utiliza un paquete de validación de datos, serialización y documentación de terceros como Pydantic, tiene el suyo propio. Por lo tanto, estas definiciones de tipos de datos no serían reutilizables tan fácilmente.\n\nRequiere configuraciones un poquito más verbosas. Y dado que se basa en WSGI (en lugar de ASGI), no está diseñado para aprovechar el alto rendimiento proporcionado por herramientas como Uvicorn, Starlette y Sanic.\n\nEl sistema de inyección de dependencias requiere pre-registrar las dependencias y las dependencias se resuelven en base a los tipos declarados. Por lo tanto, no es posible declarar más de un \"componente\" que proporcione cierto tipo.\n\nLas rutas se declaran en un solo lugar, usando funciones declaradas en otros lugares (en lugar de usar decoradores que pueden colocarse justo encima de la función que maneja el endpoint). Esto se acerca más a cómo lo hace Django que a cómo lo hace Flask (y Starlette). Separa en el código cosas que están relativamente acopladas.\n\n/// check | Inspiró a **FastAPI** a\n\nDefinir validaciones extra para tipos de datos usando el valor \"default\" de los atributos del modelo. Esto mejora el soporte del editor y no estaba disponible en Pydantic antes.\n\nEsto en realidad inspiró la actualización de partes de Pydantic, para soportar el mismo estilo de declaración de validación (toda esta funcionalidad ya está disponible en Pydantic).\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug fue uno de los primeros frameworks en implementar la declaración de tipos de parámetros API usando las anotaciones de tipos de Python. Esta fue una gran idea que inspiró a otras herramientas a hacer lo mismo.\n\nUsaba tipos personalizados en sus declaraciones en lugar de tipos estándar de Python, pero aún así fue un gran avance.\n\nTambién fue uno de los primeros frameworks en generar un esquema personalizado declarando toda la API en JSON.\n\nNo se basaba en un estándar como OpenAPI y JSON Schema. Por lo que no sería sencillo integrarlo con otras herramientas, como Swagger UI. Pero, nuevamente, fue una idea muy innovadora.\n\nTiene una funcionalidad interesante e inusual: usando el mismo framework, es posible crear APIs y también CLIs.\n\nDado que se basa en el estándar previo para frameworks web Python sincrónicos (WSGI), no puede manejar Websockets y otras cosas, aunque aún así tiene un alto rendimiento también.\n\n/// info | Información\n\nHug fue creado por Timothy Crosley, el mismo creador de [`isort`](https://github.com/timothycrosley/isort), una gran herramienta para ordenar automáticamente imports en archivos Python.\n\n///\n\n/// check | Ideas que inspiraron a **FastAPI**\n\nHug inspiró partes de APIStar, y fue una de las herramientas que encontré más prometedoras, junto a APIStar.\n\nHug ayudó a inspirar a **FastAPI** a usar anotaciones de tipos de Python para declarar parámetros, y a generar un esquema definiendo la API automáticamente.\n\nHug inspiró a **FastAPI** a declarar un parámetro `response` en funciones para configurar headers y cookies.\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0.5) { #apistar-0-5 }\n\nJusto antes de decidir construir **FastAPI** encontré **APIStar** server. Tenía casi todo lo que estaba buscando y tenía un gran diseño.\n\nEra una de las primeras implementaciones de un framework utilizando las anotaciones de tipos de Python para declarar parámetros y requests que jamás vi (antes de NestJS y Molten). Lo encontré más o menos al mismo tiempo que Hug. Pero APIStar usaba el estándar OpenAPI.\n\nTenía validación de datos automática, serialización de datos y generación del esquema OpenAPI basada en las mismas anotaciones de tipos en varios lugares.\n\nLas definiciones de esquema de cuerpo no usaban las mismas anotaciones de tipos de Python como Pydantic, era un poco más similar a Marshmallow, por lo que el soporte del editor no sería tan bueno, pero aún así, APIStar era la mejor opción disponible.\n\nTenía los mejores benchmarks de rendimiento en ese momento (solo superado por Starlette).\n\nAl principio, no tenía una interfaz de usuario web de documentación de API automática, pero sabía que podía agregar Swagger UI a él.\n\nTenía un sistema de inyección de dependencias. Requería pre-registrar componentes, como otras herramientas discutidas anteriormente. Pero aún así, era una gran funcionalidad.\n\nNunca pude usarlo en un proyecto completo, ya que no tenía integración de seguridad, por lo que no podía reemplazar todas las funcionalidades que tenía con los generadores de full-stack basados en Flask-apispec. Tenía en mi lista de tareas pendientes de proyectos crear un pull request agregando esa funcionalidad.\n\nPero luego, el enfoque del proyecto cambió.\n\nYa no era un framework web API, ya que el creador necesitaba enfocarse en Starlette.\n\nAhora APIStar es un conjunto de herramientas para validar especificaciones OpenAPI, no un framework web.\n\n/// info | Información\n\nAPIStar fue creado por Tom Christie. El mismo que creó:\n\n* Django REST Framework\n* Starlette (en la cual **FastAPI** está basado)\n* Uvicorn (usado por Starlette y **FastAPI**)\n\n///\n\n/// check | Inspiró a **FastAPI** a\n\nExistir.\n\nLa idea de declarar múltiples cosas (validación de datos, serialización y documentación) con los mismos tipos de Python, que al mismo tiempo proporcionaban un gran soporte del editor, era algo que consideré una idea brillante.\n\nY después de buscar durante mucho tiempo un framework similar y probar muchas alternativas diferentes, APIStar fue la mejor opción disponible.\n\nLuego APIStar dejó de existir como servidor y Starlette fue creado, y fue una nueva y mejor base para tal sistema. Esa fue la inspiración final para construir **FastAPI**.\n\nConsidero a **FastAPI** un \"sucesor espiritual\" de APIStar, mientras mejora y aumenta las funcionalidades, el sistema de tipos y otras partes, basándose en los aprendizajes de todas estas herramientas previas.\n\n///\n\n## Usado por **FastAPI** { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic es un paquete para definir validación de datos, serialización y documentación (usando JSON Schema) basándose en las anotaciones de tipos de Python.\n\nEso lo hace extremadamente intuitivo.\n\nEs comparable a Marshmallow. Aunque es más rápido que Marshmallow en benchmarks. Y como está basado en las mismas anotaciones de tipos de Python, el soporte del editor es estupendo.\n\n/// check | **FastAPI** lo usa para\n\nManejar toda la validación de datos, serialización de datos y documentación automática de modelos (basada en JSON Schema).\n\n**FastAPI** luego toma esos datos JSON Schema y los coloca en OpenAPI, aparte de todas las otras cosas que hace.\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette es un framework/toolkit <dfn title=\"El nuevo estándar para construir aplicaciones web asíncronas en Python\">ASGI</dfn> liviano, ideal para construir servicios asyncio de alto rendimiento.\n\nEs muy simple e intuitivo. Está diseñado para ser fácilmente extensible y tener componentes modulares.\n\nTiene:\n\n* Un rendimiento seriamente impresionante.\n* Soporte para WebSocket.\n* Tareas en segundo plano dentro del proceso.\n* Eventos de inicio y apagado.\n* Cliente de pruebas basado en HTTPX.\n* CORS, GZip, Archivos estáticos, Responses en streaming.\n* Soporte para sesiones y cookies.\n* Cobertura de tests del 100%.\n* code base 100% tipada.\n* Pocas dependencias obligatorias.\n\nStarlette es actualmente el framework de Python más rápido probado. Solo superado por Uvicorn, que no es un framework, sino un servidor.\n\nStarlette proporciona toda la funcionalidad básica de un microframework web.\n\nPero no proporciona validación de datos automática, serialización o documentación.\n\nEsa es una de las principales cosas que **FastAPI** agrega, todo basado en las anotaciones de tipos de Python (usando Pydantic). Eso, además del sistema de inyección de dependencias, utilidades de seguridad, generación de esquemas OpenAPI, etc.\n\n/// note | Detalles Técnicos\n\nASGI es un nuevo \"estándar\" que está siendo desarrollado por miembros del equipo central de Django. Todavía no es un \"estándar de Python\" (un PEP), aunque están en proceso de hacerlo.\n\nNo obstante, ya está siendo usado como un \"estándar\" por varias herramientas. Esto mejora enormemente la interoperabilidad, ya que podrías cambiar Uvicorn por cualquier otro servidor ASGI (como Daphne o Hypercorn), o podrías añadir herramientas compatibles con ASGI, como `python-socketio`.\n\n///\n\n/// check | **FastAPI** lo usa para\n\nManejar todas las partes web centrales. Añadiendo funcionalidades encima.\n\nLa clase `FastAPI` en sí misma hereda directamente de la clase `Starlette`.\n\nPor lo tanto, cualquier cosa que puedas hacer con Starlette, puedes hacerlo directamente con **FastAPI**, ya que es básicamente Starlette potenciado.\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn es un servidor ASGI extremadamente rápido, construido sobre uvloop y httptools.\n\nNo es un framework web, sino un servidor. Por ejemplo, no proporciona herramientas para el enrutamiento por paths. Eso es algo que un framework como Starlette (o **FastAPI**) proporcionaría encima.\n\nEs el servidor recomendado para Starlette y **FastAPI**.\n\n/// check | **FastAPI** lo recomienda como\n\nEl servidor web principal para ejecutar aplicaciones **FastAPI**.\n\nTambién puedes usar la opción de línea de comandos `--workers` para tener un servidor multiproceso asíncrono.\n\nRevisa más detalles en la sección [Despliegue](deployment/index.md).\n\n///\n\n## Benchmarks y velocidad { #benchmarks-and-speed }\n\nPara entender, comparar, y ver la diferencia entre Uvicorn, Starlette y FastAPI, revisa la sección sobre [Benchmarks](benchmarks.md).\n"
  },
  {
    "path": "docs/es/docs/async.md",
    "content": "# Concurrencia y async / await { #concurrency-and-async-await }\n\nDetalles sobre la sintaxis `async def` para *path operation functions* y algunos antecedentes sobre el código asíncrono, la concurrencia y el paralelismo.\n\n## ¿Con prisa? { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - demasiado largo; no lo leí\"><strong>TL;DR:</strong></abbr>\n\nSi estás usando paquetes de terceros que te dicen que los llames con `await`, como:\n\n```Python\nresults = await some_library()\n```\n\nEntonces, declara tus *path operation functions* con `async def` así:\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | Nota\n\nSolo puedes usar `await` dentro de funciones creadas con `async def`.\n\n///\n\n---\n\nSi estás usando un paquete de terceros que se comunica con algo (una base de datos, una API, el sistema de archivos, etc.) y no tiene soporte para usar `await` (este es actualmente el caso para la mayoría de los paquetes de base de datos), entonces declara tus *path operation functions* como normalmente, usando simplemente `def`, así:\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\nSi tu aplicación (de alguna manera) no tiene que comunicarse con nada más y esperar a que responda, usa `async def`, incluso si no necesitas usar `await` dentro.\n\n---\n\nSi simplemente no lo sabes, usa `def` normal.\n\n---\n\n**Nota**: Puedes mezclar `def` y `async def` en tus *path operation functions* tanto como necesites y definir cada una utilizando la mejor opción para ti. FastAPI hará lo correcto con ellas.\n\nDe todos modos, en cualquiera de los casos anteriores, FastAPI seguirá funcionando de forma asíncrona y será extremadamente rápido.\n\nPero al seguir los pasos anteriores, podrá hacer algunas optimizaciones de rendimiento.\n\n## Detalles Técnicos { #technical-details }\n\nLas versiones modernas de Python tienen soporte para **\"código asíncrono\"** utilizando algo llamado **\"coroutines\"**, con la sintaxis **`async` y `await`**.\n\nVeamos esa frase por partes en las secciones a continuación:\n\n* **Código Asíncrono**\n* **`async` y `await`**\n* **Coroutines**\n\n## Código Asíncrono { #asynchronous-code }\n\nEl código asíncrono simplemente significa que el lenguaje 💬 tiene una forma de decirle a la computadora / programa 🤖 que en algún momento del código, tendrá que esperar que *otra cosa* termine en otro lugar. Digamos que esa *otra cosa* se llama \"archivo-lento\" 📝.\n\nEntonces, durante ese tiempo, la computadora puede ir y hacer algún otro trabajo, mientras \"archivo-lento\" 📝 termina.\n\nLuego la computadora / programa 🤖 volverá cada vez que tenga una oportunidad porque está esperando nuevamente, o siempre que 🤖 haya terminado todo el trabajo que tenía en ese punto. Y 🤖 comprobará si alguna de las tareas que estaba esperando ya se han completado, haciendo lo que tenía que hacer.\n\nDespués, 🤖 toma la primera tarea que termine (digamos, nuestro \"archivo-lento\" 📝) y continúa con lo que tenía que hacer con ella.\n\nEse \"esperar otra cosa\" normalmente se refiere a las operaciones de <abbr title=\"Input and Output - Entrada y salida\">I/O</abbr> que son relativamente \"lentas\" (comparadas con la velocidad del procesador y la memoria RAM), como esperar:\n\n* que los datos del cliente se envíen a través de la red\n* que los datos enviados por tu programa sean recibidos por el cliente a través de la red\n* que el contenido de un archivo en el disco sea leído por el sistema y entregado a tu programa\n* que el contenido que tu programa entregó al sistema sea escrito en el disco\n* una operación de API remota\n* que una operación de base de datos termine\n* que una query de base de datos devuelva los resultados\n* etc.\n\nComo el tiempo de ejecución se consume principalmente esperando operaciones de <abbr title=\"Input and Output - Entrada y salida\">I/O</abbr>, las llaman operaciones \"I/O bound\".\n\nSe llama \"asíncrono\" porque la computadora / programa no tiene que estar \"sincronizado\" con la tarea lenta, esperando el momento exacto en que la tarea termine, sin hacer nada, para poder tomar el resultado de la tarea y continuar el trabajo.\n\nEn lugar de eso, al ser un sistema \"asíncrono\", una vez terminado, la tarea puede esperar un poco en la cola (algunos microsegundos) para que la computadora / programa termine lo que salió a hacer, y luego regrese para tomar los resultados y continuar trabajando con ellos.\n\nPara el \"sincrónico\" (contrario al \"asíncrono\") comúnmente también usan el término \"secuencial\", porque la computadora / programa sigue todos los pasos en secuencia antes de cambiar a una tarea diferente, incluso si esos pasos implican esperar.\n\n### Concurrencia y Hamburguesas { #concurrency-and-burgers }\n\nEsta idea de código **asíncrono** descrita anteriormente a veces también se llama **\"concurrencia\"**. Es diferente del **\"paralelismo\"**.\n\n**Concurrencia** y **paralelismo** ambos se relacionan con \"diferentes cosas sucediendo más o menos al mismo tiempo\".\n\nPero los detalles entre *concurrencia* y *paralelismo* son bastante diferentes.\n\nPara ver la diferencia, imagina la siguiente historia sobre hamburguesas:\n\n### Hamburguesas Concurrentes { #concurrent-burgers }\n\nVas con tu crush a conseguir comida rápida, te pones en fila mientras el cajero toma los pedidos de las personas frente a ti. 😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\nLuego es tu turno, haces tu pedido de 2 hamburguesas muy sofisticadas para tu crush y para ti. 🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\nEl cajero dice algo al cocinero en la cocina para que sepan que tienen que preparar tus hamburguesas (aunque actualmente están preparando las de los clientes anteriores).\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\nPagas. 💸\n\nEl cajero te da el número de tu turno.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\nMientras esperas, vas con tu crush y eliges una mesa, te sientas y hablas con tu crush por un largo rato (ya que tus hamburguesas son muy sofisticadas y toman un tiempo en prepararse).\n\nMientras estás sentado en la mesa con tu crush, mientras esperas las hamburguesas, puedes pasar ese tiempo admirando lo increíble, lindo e inteligente que es tu crush ✨😍✨.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\nMientras esperas y hablas con tu crush, de vez en cuando revisas el número mostrado en el mostrador para ver si ya es tu turno.\n\nLuego, en algún momento, finalmente es tu turno. Vas al mostrador, obtienes tus hamburguesas y vuelves a la mesa.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\nTú y tu crush comen las hamburguesas y pasan un buen rato. ✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info | Información\n\nHermosas ilustraciones de [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nImagina que eres la computadora / programa 🤖 en esa historia.\n\nMientras estás en la fila, estás inactivo 😴, esperando tu turno, sin hacer nada muy \"productivo\". Pero la fila es rápida porque el cajero solo está tomando los pedidos (no preparándolos), así que está bien.\n\nLuego, cuando es tu turno, haces un trabajo realmente \"productivo\", procesas el menú, decides lo que quieres, obtienes la elección de tu crush, pagas, verificas que das el billete o tarjeta correctos, verificas que te cobren correctamente, verificas que el pedido tenga los artículos correctos, etc.\n\nPero luego, aunque todavía no tienes tus hamburguesas, tu trabajo con el cajero está \"en pausa\" ⏸, porque tienes que esperar 🕙 a que tus hamburguesas estén listas.\n\nPero como te alejas del mostrador y te sientas en la mesa con un número para tu turno, puedes cambiar 🔀 tu atención a tu crush, y \"trabajar\" ⏯ 🤓 en eso. Luego, nuevamente estás haciendo algo muy \"productivo\" como es coquetear con tu crush 😍.\n\nLuego el cajero 💁 dice \"he terminado de hacer las hamburguesas\" al poner tu número en el mostrador, pero no saltas como loco inmediatamente cuando el número mostrado cambia a tu número de turno. Sabes que nadie robará tus hamburguesas porque tienes el número de tu turno, y ellos tienen el suyo.\n\nAsí que esperas a que tu crush termine la historia (termine el trabajo ⏯ / tarea actual que se está procesando 🤓), sonríes amablemente y dices que vas por las hamburguesas ⏸.\n\nLuego vas al mostrador 🔀, a la tarea inicial que ahora está terminada ⏯, recoges las hamburguesas, das las gracias y las llevas a la mesa. Eso termina ese paso / tarea de interacción con el mostrador ⏹. Eso a su vez, crea una nueva tarea, de \"comer hamburguesas\" 🔀 ⏯, pero la anterior de \"obtener hamburguesas\" ha terminado ⏹.\n\n### Hamburguesas Paralelas { #parallel-burgers }\n\nAhora imaginemos que estas no son \"Hamburguesas Concurrentes\", sino \"Hamburguesas Paralelas\".\n\nVas con tu crush a obtener comida rápida paralela.\n\nTe pones en fila mientras varios (digamos 8) cajeros que al mismo tiempo son cocineros toman los pedidos de las personas frente a ti.\n\nTodos antes que tú están esperando a que sus hamburguesas estén listas antes de dejar el mostrador porque cada uno de los 8 cajeros va y prepara la hamburguesa de inmediato antes de obtener el siguiente pedido.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\nLuego, finalmente es tu turno, haces tu pedido de 2 hamburguesas muy sofisticadas para tu crush y para ti.\n\nPagas 💸.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\nEl cajero va a la cocina.\n\nEsperas, de pie frente al mostrador 🕙, para que nadie más tome tus hamburguesas antes que tú, ya que no hay números para los turnos.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\nComo tú y tu crush están ocupados no dejando que nadie se interponga y tome tus hamburguesas cuando lleguen, no puedes prestar atención a tu crush. 😞\n\nEste es un trabajo \"sincrónico\", estás \"sincronizado\" con el cajero/cocinero 👨‍🍳. Tienes que esperar 🕙 y estar allí en el momento exacto en que el cajero/cocinero 👨‍🍳 termine las hamburguesas y te las entregue, o de lo contrario, alguien más podría tomarlas.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\nLuego tu cajero/cocinero 👨‍🍳 finalmente regresa con tus hamburguesas, después de mucho tiempo esperando 🕙 allí frente al mostrador.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\nTomas tus hamburguesas y vas a la mesa con tu crush.\n\nSimplemente las comes, y has terminado. ⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\nNo hubo mucho hablar o coquetear ya que la mayor parte del tiempo se dedicó a esperar 🕙 frente al mostrador. 😞\n\n/// info | Información\n\nHermosas ilustraciones de [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nEn este escenario de las hamburguesas paralelas, eres una computadora / programa 🤖 con dos procesadores (tú y tu crush), ambos esperando 🕙 y dedicando su atención ⏯ a estar \"esperando en el mostrador\" 🕙 por mucho tiempo.\n\nLa tienda de comida rápida tiene 8 procesadores (cajeros/cocineros). Mientras que la tienda de hamburguesas concurrentes podría haber tenido solo 2 (un cajero y un cocinero).\n\nPero aún así, la experiencia final no es la mejor. 😞\n\n---\n\nEsta sería la historia equivalente de las hamburguesas paralelas. 🍔\n\nPara un ejemplo más \"de la vida real\" de esto, imagina un banco.\n\nHasta hace poco, la mayoría de los bancos tenían múltiples cajeros 👨‍💼👨‍💼👨‍💼👨‍💼 y una gran fila 🕙🕙🕙🕙🕙🕙🕙🕙.\n\nTodos los cajeros haciendo todo el trabajo con un cliente tras otro 👨‍💼⏯.\n\nY tienes que esperar 🕙 en la fila por mucho tiempo o pierdes tu turno.\n\nProbablemente no querrías llevar a tu crush 😍 contigo a hacer trámites en el banco 🏦.\n\n### Conclusión de las Hamburguesas { #burger-conclusion }\n\nEn este escenario de \"hamburguesas de comida rápida con tu crush\", como hay mucha espera 🕙, tiene mucho más sentido tener un sistema concurrente ⏸🔀⏯.\n\nEste es el caso para la mayoría de las aplicaciones web.\n\nMuchos, muchos usuarios, pero tu servidor está esperando 🕙 su conexión no tan buena para enviar sus requests.\n\nY luego esperar 🕙 nuevamente a que los responses retornen.\n\nEsta \"espera\" 🕙 se mide en microsegundos, pero aún así, sumándolo todo, es mucha espera al final.\n\nPor eso tiene mucho sentido usar código asíncrono ⏸🔀⏯ para las APIs web.\n\nEste tipo de asincronía es lo que hizo popular a NodeJS (aunque NodeJS no es paralelo) y esa es la fortaleza de Go como lenguaje de programación.\n\nY ese es el mismo nivel de rendimiento que obtienes con **FastAPI**.\n\nY como puedes tener paralelismo y asincronía al mismo tiempo, obtienes un mayor rendimiento que la mayoría de los frameworks de NodeJS probados y a la par con Go, que es un lenguaje compilado más cercano a C [(todo gracias a Starlette)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).\n\n### ¿Es la concurrencia mejor que el paralelismo? { #is-concurrency-better-than-parallelism }\n\n¡No! Esa no es la moraleja de la historia.\n\nLa concurrencia es diferente del paralelismo. Y es mejor en escenarios **específicos** que implican mucha espera. Debido a eso, generalmente es mucho mejor que el paralelismo para el desarrollo de aplicaciones web. Pero no para todo.\n\nAsí que, para equilibrar eso, imagina la siguiente historia corta:\n\n> Tienes que limpiar una casa grande y sucia.\n\n*Sí, esa es toda la historia*.\n\n---\n\nNo hay esperas 🕙 en ninguna parte, solo mucho trabajo por hacer, en múltiples lugares de la casa.\n\nPodrías tener turnos como en el ejemplo de las hamburguesas, primero la sala de estar, luego la cocina, pero como no estás esperando 🕙 nada, solo limpiando y limpiando, los turnos no afectarían nada.\n\nTomaría la misma cantidad de tiempo terminar con o sin turnos (concurrencia) y habrías hecho la misma cantidad de trabajo.\n\nPero en este caso, si pudieras traer a los 8 ex-cajeros/cocineros/ahora-limpiadores, y cada uno de ellos (más tú) pudiera tomar una zona de la casa para limpiarla, podrías hacer todo el trabajo en **paralelo**, con la ayuda extra, y terminar mucho antes.\n\nEn este escenario, cada uno de los limpiadores (incluyéndote) sería un procesador, haciendo su parte del trabajo.\n\nY como la mayor parte del tiempo de ejecución se dedica al trabajo real (en lugar de esperar), y el trabajo en una computadora lo realiza una <abbr title=\"Central Processing Unit - Unidad Central de Procesamiento\">CPU</abbr>, llaman a estos problemas \"CPU bound\".\n\n---\n\nEjemplos comunes de operaciones limitadas por la CPU son cosas que requieren procesamiento matemático complejo.\n\nPor ejemplo:\n\n* **Procesamiento de audio** o **imágenes**.\n* **Visión por computadora**: una imagen está compuesta de millones de píxeles, cada píxel tiene 3 valores / colores, procesar eso normalmente requiere calcular algo en esos píxeles, todos al mismo tiempo.\n* **Machine Learning**: normalmente requiere muchas multiplicaciones de \"matrices\" y \"vectores\". Piensa en una enorme hoja de cálculo con números y multiplicando todos juntos al mismo tiempo.\n* **Deep Learning**: este es un subcampo de Machine Learning, por lo tanto, se aplica lo mismo. Es solo que no hay una sola hoja de cálculo de números para multiplicar, sino un enorme conjunto de ellas, y en muchos casos, usas un procesador especial para construir y / o usar esos modelos.\n\n### Concurrencia + Paralelismo: Web + Machine Learning { #concurrency-parallelism-web-machine-learning }\n\nCon **FastAPI** puedes aprovechar la concurrencia que es muy común para el desarrollo web (la misma atracción principal de NodeJS).\n\nPero también puedes explotar los beneficios del paralelismo y la multiprocesamiento (tener múltiples procesos ejecutándose en paralelo) para cargas de trabajo **CPU bound** como las de los sistemas de Machine Learning.\n\nEso, más el simple hecho de que Python es el lenguaje principal para **Data Science**, Machine Learning y especialmente Deep Learning, hacen de FastAPI una muy buena opción para APIs web de Data Science / Machine Learning y aplicaciones (entre muchas otras).\n\nPara ver cómo lograr este paralelismo en producción, consulta la sección sobre [Despliegue](deployment/index.md).\n\n## `async` y `await` { #async-and-await }\n\nLas versiones modernas de Python tienen una forma muy intuitiva de definir código asíncrono. Esto hace que se vea igual que el código \"secuencial\" normal y hace el \"wait\" por ti en los momentos adecuados.\n\nCuando hay una operación que requerirá esperar antes de dar los resultados y tiene soporte para estas nuevas funcionalidades de Python, puedes programarlo así:\n\n```Python\nburgers = await get_burgers(2)\n```\n\nLa clave aquí es el `await`. Dice a Python que tiene que esperar ⏸ a que `get_burgers(2)` termine de hacer su cosa 🕙 antes de almacenar los resultados en `burgers`. Con eso, Python sabrá que puede ir y hacer algo más 🔀 ⏯ mientras tanto (como recibir otro request).\n\nPara que `await` funcione, tiene que estar dentro de una función que soporte esta asincronía. Para hacer eso, solo declara la función con `async def`:\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # Hacer algunas cosas asíncronas para crear las hamburguesas\n    return burgers\n```\n\n...en lugar de `def`:\n\n```Python hl_lines=\"2\"\n# Esto no es asíncrono\ndef get_sequential_burgers(number: int):\n    # Hacer algunas cosas secuenciales para crear las hamburguesas\n    return burgers\n```\n\nCon `async def`, Python sabe que, dentro de esa función, tiene que estar atento a las expresiones `await`, y que puede \"pausar\" ⏸ la ejecución de esa función e ir a hacer algo más 🔀 antes de regresar.\n\nCuando deseas llamar a una función `async def`, tienes que \"await\" dicha función. Así que, esto no funcionará:\n\n```Python\n# Esto no funcionará, porque get_burgers fue definido con: async def\nburgers = get_burgers(2)\n```\n\n---\n\nAsí que, si estás usando un paquete que te dice que puedes llamarlo con `await`, necesitas crear las *path operation functions* que lo usen con `async def`, como en:\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### Más detalles técnicos { #more-technical-details }\n\nPodrías haber notado que `await` solo se puede usar dentro de funciones definidas con `async def`.\n\nPero al mismo tiempo, las funciones definidas con `async def` deben ser \"awaited\". Por lo tanto, las funciones con `async def` solo se pueden llamar dentro de funciones definidas con `async def` también.\n\nEntonces, sobre el huevo y la gallina, ¿cómo llamas a la primera función `async`?\n\nSi estás trabajando con **FastAPI** no tienes que preocuparte por eso, porque esa \"primera\" función será tu *path operation function*, y FastAPI sabrá cómo hacer lo correcto.\n\nPero si deseas usar `async` / `await` sin FastAPI, también puedes hacerlo.\n\n### Escribe tu propio código async { #write-your-own-async-code }\n\nStarlette (y **FastAPI**) están basados en [AnyIO](https://anyio.readthedocs.io/en/stable/), lo que lo hace compatible tanto con el [asyncio](https://docs.python.org/3/library/asyncio-task.html) del paquete estándar de Python como con [Trio](https://trio.readthedocs.io/en/stable/).\n\nEn particular, puedes usar directamente [AnyIO](https://anyio.readthedocs.io/en/stable/) para tus casos de uso avanzados de concurrencia que requieran patrones más avanzados en tu propio código.\n\nE incluso si no estuvieras usando FastAPI, también podrías escribir tus propias aplicaciones asíncronas con [AnyIO](https://anyio.readthedocs.io/en/stable/) para ser altamente compatibles y obtener sus beneficios (p.ej. *concurrencia estructurada*).\n\nCreé otro paquete sobre AnyIO, como una capa delgada, para mejorar un poco las anotaciones de tipos y obtener mejor **autocompletado**, **errores en línea**, etc. También tiene una introducción amigable y tutorial para ayudarte a **entender** y escribir **tu propio código async**: [Asyncer](https://asyncer.tiangolo.com/). Sería particularmente útil si necesitas **combinar código async con regular** (bloqueante/sincrónico).\n\n### Otras formas de código asíncrono { #other-forms-of-asynchronous-code }\n\nEste estilo de usar `async` y `await` es relativamente nuevo en el lenguaje.\n\nPero hace que trabajar con código asíncrono sea mucho más fácil.\n\nEsta misma sintaxis (o casi idéntica) también se incluyó recientemente en las versiones modernas de JavaScript (en el Navegador y NodeJS).\n\nPero antes de eso, manejar el código asíncrono era mucho más complejo y difícil.\n\nEn versiones previas de Python, podrías haber usado hilos o [Gevent](https://www.gevent.org/). Pero el código es mucho más complejo de entender, depurar y razonar.\n\nEn versiones previas de NodeJS / JavaScript en el Navegador, habrías usado \"callbacks\". Lo que lleva al \"callback hell\".\n\n## Coroutines { #coroutines }\n\n**Coroutines** es simplemente el término muy elegante para la cosa que devuelve una función `async def`. Python sabe que es algo parecido a una función, que puede comenzar y que terminará en algún momento, pero que podría pausar ⏸ internamente también, siempre que haya un `await` dentro de él.\n\nPero toda esta funcionalidad de usar código asíncrono con `async` y `await` a menudo se resume como utilizar \"coroutines\". Es comparable a la funcionalidad clave principal de Go, las \"Goroutines\".\n\n## Conclusión { #conclusion }\n\nVeamos la misma frase de arriba:\n\n> Las versiones modernas de Python tienen soporte para **\"código asíncrono\"** utilizando algo llamado **\"coroutines\"**, con la sintaxis **`async` y `await`**.\n\nEso debería tener más sentido ahora. ✨\n\nTodo eso es lo que impulsa FastAPI (a través de Starlette) y lo que hace que tenga un rendimiento tan impresionante.\n\n## Detalles Muy Técnicos { #very-technical-details }\n\n/// warning | Advertencia\n\nProbablemente puedas saltarte esto.\n\nEstos son detalles muy técnicos de cómo **FastAPI** funciona en su interior.\n\nSi tienes bastante conocimiento técnico (coroutines, hilos, bloqueo, etc.) y tienes curiosidad sobre cómo FastAPI maneja `async def` vs `def` normal, adelante.\n\n///\n\n### Funciones de *path operation* { #path-operation-functions }\n\nCuando declaras una *path operation function* con `def` normal en lugar de `async def`, se ejecuta en un threadpool externo que luego es esperado, en lugar de ser llamado directamente (ya que bloquearía el servidor).\n\nSi vienes de otro framework async que no funciona de la manera descrita anteriormente y estás acostumbrado a definir funciones de *path operation* solo de cómputo trivial con `def` normal para una pequeña ganancia de rendimiento (alrededor de 100 nanosegundos), ten en cuenta que en **FastAPI** el efecto sería bastante opuesto. En estos casos, es mejor usar `async def` a menos que tus *path operation functions* usen código que realice <abbr title=\"Input/Output - Entrada/Salida: lectura o escritura en disco, comunicaciones de red.\">I/O</abbr> de bloqueo.\n\nAun así, en ambas situaciones, es probable que **FastAPI** [siga siendo más rápida](index.md#performance) que (o al menos comparable a) tu framework anterior.\n\n### Dependencias { #dependencies }\n\nLo mismo aplica para las [dependencias](tutorial/dependencies/index.md). Si una dependencia es una función estándar `def` en lugar de `async def`, se ejecuta en el threadpool externo.\n\n### Sub-dependencias { #sub-dependencies }\n\nPuedes tener múltiples dependencias y [sub-dependencias](tutorial/dependencies/sub-dependencies.md) requiriéndose mutuamente (como parámetros de las definiciones de funciones), algunas de ellas podrían ser creadas con `async def` y algunas con `def` normal. Aun funcionará, y las que fueron creadas con `def` normal serían llamadas en un hilo externo (del threadpool) en lugar de ser \"awaited\".\n\n### Otras funciones de utilidad { #other-utility-functions }\n\nCualquier otra función de utilidad que llames directamente puede ser creada con `def` normal o `async def` y FastAPI no afectará la forma en que la llames.\n\nEsto contrasta con las funciones que FastAPI llama por ti: *path operation functions* y dependencias.\n\nSi tu función de utilidad es una función normal con `def`, será llamada directamente (como la escribas en tu código), no en un threadpool; si la función es creada con `async def` entonces deberías \"await\" por esa función cuando la llames en tu código.\n\n---\n\nNuevamente, estos son detalles muy técnicos que probablemente serían útiles si los buscaste.\n\nDe lo contrario, deberías estar bien con las pautas de la sección anterior: <a href=\"#in-a-hurry\">¿Con prisa?</a>.\n"
  },
  {
    "path": "docs/es/docs/benchmarks.md",
    "content": "# Benchmarks { #benchmarks }\n\nLos benchmarks independientes de TechEmpower muestran aplicaciones de **FastAPI** ejecutándose bajo Uvicorn como [uno de los frameworks de Python más rápidos disponibles](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), solo por debajo de Starlette y Uvicorn en sí mismos (utilizados internamente por FastAPI).\n\nPero al revisar benchmarks y comparaciones, debes tener en cuenta lo siguiente.\n\n## Benchmarks y velocidad { #benchmarks-and-speed }\n\nCuando ves los benchmarks, es común ver varias herramientas de diferentes tipos comparadas como equivalentes.\n\nEspecíficamente, ver Uvicorn, Starlette y FastAPI comparados juntos (entre muchas otras herramientas).\n\nCuanto más simple sea el problema resuelto por la herramienta, mejor rendimiento tendrá. Y la mayoría de los benchmarks no prueban las funcionalidades adicionales proporcionadas por la herramienta.\n\nLa jerarquía es como:\n\n* **Uvicorn**: un servidor ASGI\n    * **Starlette**: (usa Uvicorn) un microframework web\n        * **FastAPI**: (usa Starlette) un microframework para APIs con varias funcionalidades adicionales para construir APIs, con validación de datos, etc.\n\n* **Uvicorn**:\n    * Tendrá el mejor rendimiento, ya que no tiene mucho código extra aparte del propio servidor.\n    * No escribirías una aplicación directamente en Uvicorn. Eso significaría que tu código tendría que incluir, más o menos, al menos, todo el código proporcionado por Starlette (o **FastAPI**). Y si hicieras eso, tu aplicación final tendría la misma carga que si hubieras usado un framework, minimizando el código de tu aplicación y los bugs.\n    * Si estás comparando Uvicorn, compáralo con Daphne, Hypercorn, uWSGI, etc. Servidores de aplicaciones.\n* **Starlette**:\n    * Tendrá el siguiente mejor rendimiento, después de Uvicorn. De hecho, Starlette usa Uvicorn para ejecutarse. Así que probablemente solo pueda ser \"más lento\" que Uvicorn por tener que ejecutar más código.\n    * Pero te proporciona las herramientas para construir aplicaciones web sencillas, con enrutamiento basado en paths, etc.\n    * Si estás comparando Starlette, compáralo con Sanic, Flask, Django, etc. Frameworks web (o microframeworks).\n* **FastAPI**:\n    * De la misma forma en que Starlette usa Uvicorn y no puede ser más rápido que él, **FastAPI** usa Starlette, por lo que no puede ser más rápido que él.\n    * FastAPI ofrece más funcionalidades además de las de Starlette. Funcionalidades que casi siempre necesitas al construir APIs, como la validación y serialización de datos. Y al utilizarlo, obtienes documentación automática gratis (la documentación automática ni siquiera añade carga a las aplicaciones en ejecución, se genera al inicio).\n    * Si no usabas FastAPI y utilizabas Starlette directamente (u otra herramienta, como Sanic, Flask, Responder, etc.) tendrías que implementar toda la validación y serialización de datos por ti mismo. Entonces, tu aplicación final aún tendría la misma carga que si hubiera sido construida usando FastAPI. Y en muchos casos, esta validación y serialización de datos es la mayor cantidad de código escrito en las aplicaciones.\n    * Entonces, al usar FastAPI estás ahorrando tiempo de desarrollo, bugs, líneas de código, y probablemente obtendrías el mismo rendimiento (o mejor) que si no lo usaras (ya que tendrías que implementarlo todo en tu código).\n    * Si estás comparando FastAPI, compáralo con un framework de aplicación web (o conjunto de herramientas) que proporcione validación de datos, serialización y documentación, como Flask-apispec, NestJS, Molten, etc. Frameworks con validación de datos, serialización y documentación automáticas integradas.\n"
  },
  {
    "path": "docs/es/docs/deployment/cloud.md",
    "content": "# Despliega FastAPI en Proveedores de Nube { #deploy-fastapi-on-cloud-providers }\n\nPuedes usar prácticamente **cualquier proveedor de nube** para desplegar tu aplicación FastAPI.\n\nEn la mayoría de los casos, los principales proveedores de nube tienen guías para desplegar FastAPI con ellos.\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** está construido por el mismo autor y equipo detrás de **FastAPI**.\n\nSimplifica el proceso de **construir**, **desplegar** y **acceder** a una API con un esfuerzo mínimo.\n\nTrae la misma **experiencia de desarrollador** de construir aplicaciones con FastAPI a **desplegarlas** en la nube. 🎉\n\nFastAPI Cloud es el sponsor principal y proveedor de financiamiento de los proyectos open source *FastAPI and friends*. ✨\n\n## Proveedores de Nube - Sponsors { #cloud-providers-sponsors }\n\nOtros proveedores de nube ✨ [**son sponsors de FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ también. 🙇\n\nTambién podrías considerarlos para seguir sus guías y probar sus servicios:\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/es/docs/deployment/concepts.md",
    "content": "# Conceptos de Implementación { #deployments-concepts }\n\nCuando implementas una aplicación **FastAPI**, o en realidad, cualquier tipo de API web, hay varios conceptos que probablemente te importen, y al entenderlos, puedes encontrar la **forma más adecuada** de **implementar tu aplicación**.\n\nAlgunos de los conceptos importantes son:\n\n* Seguridad - HTTPS\n* Ejecución al iniciar\n* Reinicios\n* Replicación (la cantidad de procesos en ejecución)\n* Memoria\n* Pasos previos antes de iniciar\n\nVeremos cómo afectan estas **implementaciones**.\n\nAl final, el objetivo principal es poder **servir a tus clientes de API** de una manera que sea **segura**, para **evitar interrupciones**, y usar los **recursos de cómputo** (por ejemplo, servidores remotos/máquinas virtuales) de la manera más eficiente posible. 🚀\n\nTe contaré un poquito más sobre estos **conceptos** aquí, y eso, con suerte, te dará la **intuición** que necesitarías para decidir cómo implementar tu API en diferentes entornos, posiblemente incluso en aquellos **futuros** que aún no existen.\n\nAl considerar estos conceptos, podrás **evaluar y diseñar** la mejor manera de implementar **tus propias APIs**.\n\nEn los próximos capítulos, te daré más **recetas concretas** para implementar aplicaciones de FastAPI.\n\nPero por ahora, revisemos estas importantes **ideas conceptuales**. Estos conceptos también se aplican a cualquier otro tipo de API web. 💡\n\n## Seguridad - HTTPS { #security-https }\n\nEn el [capítulo anterior sobre HTTPS](https.md) aprendimos sobre cómo HTTPS proporciona cifrado para tu API.\n\nTambién vimos que HTTPS es normalmente proporcionado por un componente **externo** a tu servidor de aplicaciones, un **Proxy de Terminación TLS**.\n\nY debe haber algo encargado de **renovar los certificados HTTPS**, podría ser el mismo componente o algo diferente.\n\n### Herramientas de Ejemplo para HTTPS { #example-tools-for-https }\n\nAlgunas de las herramientas que podrías usar como Proxy de Terminación TLS son:\n\n* Traefik\n    * Maneja automáticamente las renovaciones de certificados ✨\n* Caddy\n    * Maneja automáticamente las renovaciones de certificados ✨\n* Nginx\n    * Con un componente externo como Certbot para las renovaciones de certificados\n* HAProxy\n    * Con un componente externo como Certbot para las renovaciones de certificados\n* Kubernetes con un Controlador de Ingress como Nginx\n    * Con un componente externo como cert-manager para las renovaciones de certificados\n* Manejado internamente por un proveedor de nube como parte de sus servicios (lee abajo 👇)\n\nOtra opción es que podrías usar un **servicio de nube** que haga más del trabajo, incluyendo configurar HTTPS. Podría tener algunas restricciones o cobrarte más, etc. Pero en ese caso, no tendrías que configurar un Proxy de Terminación TLS tú mismo.\n\nTe mostraré algunos ejemplos concretos en los próximos capítulos.\n\n---\n\nLuego, los siguientes conceptos a considerar son todos acerca del programa que ejecuta tu API real (por ejemplo, Uvicorn).\n\n## Programa y Proceso { #program-and-process }\n\nHablaremos mucho sobre el \"**proceso**\" en ejecución, así que es útil tener claridad sobre lo que significa y cuál es la diferencia con la palabra \"**programa**\".\n\n### Qué es un Programa { #what-is-a-program }\n\nLa palabra **programa** se usa comúnmente para describir muchas cosas:\n\n* El **código** que escribes, los **archivos Python**.\n* El **archivo** que puede ser **ejecutado** por el sistema operativo, por ejemplo: `python`, `python.exe` o `uvicorn`.\n* Un programa específico mientras está siendo **ejecutado** en el sistema operativo, usando la CPU y almacenando cosas en la memoria. Esto también se llama **proceso**.\n\n### Qué es un Proceso { #what-is-a-process }\n\nLa palabra **proceso** se usa normalmente de una manera más específica, refiriéndose solo a lo que está ejecutándose en el sistema operativo (como en el último punto anterior):\n\n* Un programa específico mientras está siendo **ejecutado** en el sistema operativo.\n    * Esto no se refiere al archivo, ni al código, se refiere **específicamente** a lo que está siendo **ejecutado** y gestionado por el sistema operativo.\n* Cualquier programa, cualquier código, **solo puede hacer cosas** cuando está siendo **ejecutado**. Así que, cuando hay un **proceso en ejecución**.\n* El proceso puede ser **terminado** (o \"matado\") por ti, o por el sistema operativo. En ese punto, deja de ejecutarse/ser ejecutado, y ya no puede **hacer cosas**.\n* Cada aplicación que tienes en ejecución en tu computadora tiene algún proceso detrás, cada programa en ejecución, cada ventana, etc. Y normalmente hay muchos procesos ejecutándose **al mismo tiempo** mientras una computadora está encendida.\n* Puede haber **múltiples procesos** del **mismo programa** ejecutándose al mismo tiempo.\n\nSi revisas el \"administrador de tareas\" o \"monitor del sistema\" (o herramientas similares) en tu sistema operativo, podrás ver muchos de esos procesos en ejecución.\n\nY, por ejemplo, probablemente verás que hay múltiples procesos ejecutando el mismo programa del navegador (Firefox, Chrome, Edge, etc.). Normalmente ejecutan un proceso por pestaña, además de algunos otros procesos extra.\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\nAhora que conocemos la diferencia entre los términos **proceso** y **programa**, sigamos hablando sobre implementaciones.\n\n## Ejecución al Iniciar { #running-on-startup }\n\nEn la mayoría de los casos, cuando creas una API web, quieres que esté **siempre en ejecución**, ininterrumpida, para que tus clientes puedan acceder a ella en cualquier momento. Esto, por supuesto, a menos que tengas una razón específica para que se ejecute solo en ciertas situaciones, pero la mayoría de las veces quieres que esté constantemente en ejecución y **disponible**.\n\n### En un Servidor Remoto { #in-a-remote-server }\n\nCuando configuras un servidor remoto (un servidor en la nube, una máquina virtual, etc.) lo más sencillo que puedes hacer es usar `fastapi run` (que utiliza Uvicorn) o algo similar, manualmente, de la misma manera que lo haces al desarrollar localmente.\n\nY funcionará y será útil **durante el desarrollo**.\n\nPero si pierdes la conexión con el servidor, el **proceso en ejecución** probablemente morirá.\n\nY si el servidor se reinicia (por ejemplo, después de actualizaciones o migraciones del proveedor de la nube) probablemente **no lo notarás**. Y debido a eso, ni siquiera sabrás que tienes que reiniciar el proceso manualmente. Así, tu API simplemente quedará muerta. 😱\n\n### Ejecutar Automáticamente al Iniciar { #run-automatically-on-startup }\n\nEn general, probablemente querrás que el programa del servidor (por ejemplo, Uvicorn) se inicie automáticamente al arrancar el servidor, y sin necesidad de ninguna **intervención humana**, para tener siempre un proceso en ejecución con tu API (por ejemplo, Uvicorn ejecutando tu aplicación FastAPI).\n\n### Programa Separado { #separate-program }\n\nPara lograr esto, normalmente tendrás un **programa separado** que se asegurará de que tu aplicación se ejecute al iniciarse. Y en muchos casos, también se asegurará de que otros componentes o aplicaciones se ejecuten, por ejemplo, una base de datos.\n\n### Herramientas de Ejemplo para Ejecutar al Iniciar { #example-tools-to-run-at-startup }\n\nAlgunos ejemplos de las herramientas que pueden hacer este trabajo son:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker en Modo Swarm\n* Systemd\n* Supervisor\n* Manejado internamente por un proveedor de nube como parte de sus servicios\n* Otros...\n\nTe daré más ejemplos concretos en los próximos capítulos.\n\n## Reinicios { #restarts }\n\nDe manera similar a asegurarte de que tu aplicación se ejecute al iniciar, probablemente también quieras asegurarte de que se **reinicie** después de fallos.\n\n### Cometemos Errores { #we-make-mistakes }\n\nNosotros, como humanos, cometemos **errores**, todo el tiempo. El software casi *siempre* tiene **bugs** ocultos en diferentes lugares. 🐛\n\nY nosotros, como desarrolladores, seguimos mejorando el código a medida que encontramos esos bugs y a medida que implementamos nuevas funcionalidades (posiblemente agregando nuevos bugs también 😅).\n\n### Errores Pequeños Manejados Automáticamente { #small-errors-automatically-handled }\n\nAl construir APIs web con FastAPI, si hay un error en nuestro código, FastAPI normalmente lo contiene al request único que desencadenó el error. 🛡\n\nEl cliente obtendrá un **500 Internal Server Error** para ese request, pero la aplicación continuará funcionando para los siguientes requests en lugar de simplemente colapsar por completo.\n\n### Errores Mayores - Colapsos { #bigger-errors-crashes }\n\nSin embargo, puede haber casos en los que escribamos algún código que **colapse toda la aplicación** haciendo que Uvicorn y Python colapsen. 💥\n\nY aún así, probablemente no querrías que la aplicación quede muerta porque hubo un error en un lugar, probablemente querrás que **siga ejecutándose** al menos para las *path operations* que no estén rotas.\n\n### Reiniciar Después del Colapso { #restart-after-crash }\n\nPero en esos casos con errores realmente malos que colapsan el **proceso en ejecución**, querrías un componente externo encargado de **reiniciar** el proceso, al menos un par de veces...\n\n/// tip | Consejo\n\n...Aunque si la aplicación completa **colapsa inmediatamente**, probablemente no tenga sentido seguir reiniciándola eternamente. Pero en esos casos, probablemente lo notarás durante el desarrollo, o al menos justo después de la implementación.\n\nAsí que enfoquémonos en los casos principales, donde podría colapsar por completo en algunos casos particulares **en el futuro**, y aún así tenga sentido reiniciarla.\n\n///\n\nProbablemente querrías que la cosa encargada de reiniciar tu aplicación sea un **componente externo**, porque para ese punto, la misma aplicación con Uvicorn y Python ya colapsó, así que no hay nada en el mismo código de la misma aplicación que pueda hacer algo al respecto.\n\n### Herramientas de Ejemplo para Reiniciar Automáticamente { #example-tools-to-restart-automatically }\n\nEn la mayoría de los casos, la misma herramienta que se utiliza para **ejecutar el programa al iniciar** también se utiliza para manejar reinicios automáticos.\n\nPor ejemplo, esto podría ser manejado por:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker en Modo Swarm\n* Systemd\n* Supervisor\n* Manejado internamente por un proveedor de nube como parte de sus servicios\n* Otros...\n\n## Replicación - Procesos y Memoria { #replication-processes-and-memory }\n\nCon una aplicación FastAPI, usando un programa servidor como el comando `fastapi` que ejecuta Uvicorn, ejecutarlo una vez en **un proceso** puede servir a múltiples clientes concurrentemente.\n\nPero en muchos casos, querrás ejecutar varios worker processes al mismo tiempo.\n\n### Múltiples Procesos - Workers { #multiple-processes-workers }\n\nSi tienes más clientes de los que un solo proceso puede manejar (por ejemplo, si la máquina virtual no es muy grande) y tienes **múltiples núcleos** en la CPU del servidor, entonces podrías tener **múltiples procesos** ejecutando la misma aplicación al mismo tiempo, y distribuir todas las requests entre ellos.\n\nCuando ejecutas **múltiples procesos** del mismo programa de API, comúnmente se les llama **workers**.\n\n### Worker Processes y Puertos { #worker-processes-and-ports }\n\nRecuerda de la documentación [Sobre HTTPS](https.md) que solo un proceso puede estar escuchando en una combinación de puerto y dirección IP en un servidor.\n\nEsto sigue siendo cierto.\n\nAsí que, para poder tener **múltiples procesos** al mismo tiempo, tiene que haber un **solo proceso escuchando en un puerto** que luego transmita la comunicación a cada worker process de alguna forma.\n\n### Memoria por Proceso { #memory-per-process }\n\nAhora, cuando el programa carga cosas en memoria, por ejemplo, un modelo de Machine Learning en una variable, o el contenido de un archivo grande en una variable, todo eso **consume un poco de la memoria (RAM)** del servidor.\n\nY múltiples procesos normalmente **no comparten ninguna memoria**. Esto significa que cada proceso en ejecución tiene sus propias cosas, variables y memoria. Y si estás consumiendo una gran cantidad de memoria en tu código, **cada proceso** consumirá una cantidad equivalente de memoria.\n\n### Memoria del Servidor { #server-memory }\n\nPor ejemplo, si tu código carga un modelo de Machine Learning con **1 GB de tamaño**, cuando ejecutas un proceso con tu API, consumirá al menos 1 GB de RAM. Y si inicias **4 procesos** (4 workers), cada uno consumirá 1 GB de RAM. Así que, en total, tu API consumirá **4 GB de RAM**.\n\nY si tu servidor remoto o máquina virtual solo tiene 3 GB de RAM, intentar cargar más de 4 GB de RAM causará problemas. 🚨\n\n### Múltiples Procesos - Un Ejemplo { #multiple-processes-an-example }\n\nEn este ejemplo, hay un **Proceso Administrador** que inicia y controla dos **Worker Processes**.\n\nEste Proceso Administrador probablemente sería el que escuche en el **puerto** en la IP. Y transmitirá toda la comunicación a los worker processes.\n\nEsos worker processes serían los que ejecutan tu aplicación, realizarían los cálculos principales para recibir un **request** y devolver un **response**, y cargarían cualquier cosa que pongas en variables en RAM.\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\nY por supuesto, la misma máquina probablemente tendría **otros procesos** ejecutándose también, aparte de tu aplicación.\n\nUn detalle interesante es que el porcentaje de **CPU utilizado** por cada proceso puede **variar** mucho con el tiempo, pero la **memoria (RAM)** normalmente permanece más o menos **estable**.\n\nSi tienes una API que hace una cantidad comparable de cálculos cada vez y tienes muchos clientes, entonces la **utilización de CPU** probablemente *también sea estable* (en lugar de constantemente subir y bajar rápidamente).\n\n### Ejemplos de Herramientas y Estrategias de Replicación { #examples-of-replication-tools-and-strategies }\n\nPuede haber varios enfoques para lograr esto, y te contaré más sobre estrategias específicas en los próximos capítulos, por ejemplo, al hablar sobre Docker y contenedores.\n\nLa principal restricción a considerar es que tiene que haber un **componente único** manejando el **puerto** en la **IP pública**. Y luego debe tener una forma de **transmitir** la comunicación a los **procesos/workers** replicados.\n\nAquí hay algunas combinaciones y estrategias posibles:\n\n* **Uvicorn** con `--workers`\n    * Un administrador de procesos de Uvicorn **escucharía** en la **IP** y **puerto**, y iniciaría **múltiples worker processes de Uvicorn**.\n* **Kubernetes** y otros sistemas de **contenedor distribuidos**\n    * Algo en la capa de **Kubernetes** escucharía en la **IP** y **puerto**. La replicación sería al tener **múltiples contenedores**, cada uno con **un proceso de Uvicorn** ejecutándose.\n* **Servicios en la Nube** que manejan esto por ti\n    * El servicio en la nube probablemente **manejará la replicación por ti**. Posiblemente te permitiría definir **un proceso para ejecutar**, o una **imagen de contenedor** para usar, en cualquier caso, lo más probable es que sería **un solo proceso de Uvicorn**, y el servicio en la nube se encargaría de replicarlo.\n\n/// tip | Consejo\n\nNo te preocupes si algunos de estos elementos sobre **contenedores**, Docker, o Kubernetes no tienen mucho sentido todavía.\n\nTe contaré más sobre imágenes de contenedores, Docker, Kubernetes, etc. en un capítulo futuro: [FastAPI en Contenedores - Docker](docker.md).\n\n///\n\n## Pasos Previos Antes de Iniciar { #previous-steps-before-starting }\n\nHay muchos casos en los que quieres realizar algunos pasos **antes de iniciar** tu aplicación.\n\nPor ejemplo, podrías querer ejecutar **migraciones de base de datos**.\n\nPero en la mayoría de los casos, querrás realizar estos pasos solo **una vez**.\n\nAsí que, querrás tener un **único proceso** para realizar esos **pasos previos**, antes de iniciar la aplicación.\n\nY tendrás que asegurarte de que sea un único proceso ejecutando esos pasos previos incluso si después, inicias **múltiples procesos** (múltiples workers) para la propia aplicación. Si esos pasos fueran ejecutados por **múltiples procesos**, **duplicarían** el trabajo al ejecutarlo en **paralelo**, y si los pasos fueran algo delicado como una migración de base de datos, podrían causar conflictos entre sí.\n\nPor supuesto, hay algunos casos en los que no hay problema en ejecutar los pasos previos múltiples veces, en ese caso, es mucho más fácil de manejar.\n\n/// tip | Consejo\n\nTambién, ten en cuenta que dependiendo de tu configuración, en algunos casos **quizás ni siquiera necesites realizar pasos previos** antes de iniciar tu aplicación.\n\nEn ese caso, no tendrías que preocuparte por nada de esto. 🤷\n\n///\n\n### Ejemplos de Estrategias para Pasos Previos { #examples-of-previous-steps-strategies }\n\nEsto **dependerá mucho** de la forma en que **implementarás tu sistema**, y probablemente estará conectado con la forma en que inicias programas, manejas reinicios, etc.\n\nAquí hay algunas ideas posibles:\n\n* Un \"Contenedor de Inicio\" en Kubernetes que se ejecuta antes de tu contenedor de aplicación\n* Un script de bash que ejecuta los pasos previos y luego inicia tu aplicación\n    * Aún necesitarías una forma de iniciar/reiniciar *ese* script de bash, detectar errores, etc.\n\n/// tip | Consejo\n\nTe daré más ejemplos concretos para hacer esto con contenedores en un capítulo futuro: [FastAPI en Contenedores - Docker](docker.md).\n\n///\n\n## Utilización de Recursos { #resource-utilization }\n\nTu(s) servidor(es) es(son) un **recurso** que puedes consumir o **utilizar**, con tus programas, el tiempo de cómputo en las CPUs y la memoria RAM disponible.\n\n¿Cuánto de los recursos del sistema quieres consumir/utilizar? Podría ser fácil pensar \"no mucho\", pero en realidad, probablemente querrás consumir **lo más posible sin colapsar**.\n\nSi estás pagando por 3 servidores pero solo estás usando un poquito de su RAM y CPU, probablemente estés **desperdiciando dinero** 💸, y probablemente **desperdiciando la energía eléctrica del servidor** 🌎, etc.\n\nEn ese caso, podría ser mejor tener solo 2 servidores y usar un mayor porcentaje de sus recursos (CPU, memoria, disco, ancho de banda de red, etc.).\n\nPor otro lado, si tienes 2 servidores y estás usando **100% de su CPU y RAM**, en algún momento un proceso pedirá más memoria y el servidor tendrá que usar el disco como \"memoria\" (lo cual puede ser miles de veces más lento), o incluso **colapsar**. O un proceso podría necesitar hacer algún cálculo y tendría que esperar hasta que la CPU esté libre de nuevo.\n\nEn este caso, sería mejor obtener **un servidor extra** y ejecutar algunos procesos en él para que todos tengan **suficiente RAM y tiempo de CPU**.\n\nTambién existe la posibilidad de que, por alguna razón, tengas un **pico** de uso de tu API. Tal vez se volvió viral, o tal vez otros servicios o bots comienzan a usarla. Y podrías querer tener recursos extra para estar a salvo en esos casos.\n\nPodrías establecer un **número arbitrario** para alcanzar, por ejemplo, algo **entre 50% a 90%** de utilización de recursos. El punto es que esas son probablemente las principales cosas que querrás medir y usar para ajustar tus implementaciones.\n\nPuedes usar herramientas simples como `htop` para ver la CPU y RAM utilizadas en tu servidor o la cantidad utilizada por cada proceso. O puedes usar herramientas de monitoreo más complejas, que pueden estar distribuidas a través de servidores, etc.\n\n## Resumen { #recap }\n\nHas estado leyendo aquí algunos de los conceptos principales que probablemente necesitarás tener en mente al decidir cómo implementar tu aplicación:\n\n* Seguridad - HTTPS\n* Ejecución al iniciar\n* Reinicios\n* Replicación (la cantidad de procesos en ejecución)\n* Memoria\n* Pasos previos antes de iniciar\n\nComprender estas ideas y cómo aplicarlas debería darte la intuición necesaria para tomar decisiones al configurar y ajustar tus implementaciones. 🤓\n\nEn las próximas secciones, te daré más ejemplos concretos de posibles estrategias que puedes seguir. 🚀\n"
  },
  {
    "path": "docs/es/docs/deployment/docker.md",
    "content": "# FastAPI en Contenedores - Docker { #fastapi-in-containers-docker }\n\nAl desplegar aplicaciones de FastAPI, un enfoque común es construir una **imagen de contenedor de Linux**. Normalmente se realiza usando [**Docker**](https://www.docker.com/). Luego puedes desplegar esa imagen de contenedor de varias formas.\n\nUsar contenedores de Linux tiene varias ventajas, incluyendo **seguridad**, **replicabilidad**, **simplicidad**, y otras.\n\n/// tip | Consejo\n\n¿Tienes prisa y ya conoces esto? Salta al [`Dockerfile` más abajo 👇](#build-a-docker-image-for-fastapi).\n\n///\n\n<details>\n<summary>Vista previa del Dockerfile 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# Si estás detrás de un proxy como Nginx o Traefik añade --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## Qué es un Contenedor { #what-is-a-container }\n\nLos contenedores (principalmente contenedores de Linux) son una forma muy **ligera** de empaquetar aplicaciones incluyendo todas sus dependencias y archivos necesarios, manteniéndolos aislados de otros contenedores (otras aplicaciones o componentes) en el mismo sistema.\n\nLos contenedores de Linux se ejecutan utilizando el mismo núcleo de Linux del host (máquina, máquina virtual, servidor en la nube, etc.). Esto significa que son muy ligeros (en comparación con las máquinas virtuales completas que emulan un sistema operativo completo).\n\nDe esta forma, los contenedores consumen **pocos recursos**, una cantidad comparable a ejecutar los procesos directamente (una máquina virtual consumiría mucho más).\n\nLos contenedores también tienen sus propios procesos de ejecución **aislados** (normalmente solo un proceso), sistema de archivos y red, simplificando el despliegue, la seguridad, el desarrollo, etc.\n\n## Qué es una Imagen de Contenedor { #what-is-a-container-image }\n\nUn **contenedor** se ejecuta desde una **imagen de contenedor**.\n\nUna imagen de contenedor es una versión **estática** de todos los archivos, variables de entorno y el comando/programa por defecto que debería estar presente en un contenedor. **Estático** aquí significa que la **imagen** de contenedor no se está ejecutando, no está siendo ejecutada, son solo los archivos empaquetados y los metadatos.\n\nEn contraste con una \"**imagen de contenedor**\" que son los contenidos estáticos almacenados, un \"**contenedor**\" normalmente se refiere a la instance en ejecución, lo que está siendo **ejecutado**.\n\nCuando el **contenedor** se inicia y está en funcionamiento (iniciado a partir de una **imagen de contenedor**), puede crear o cambiar archivos, variables de entorno, etc. Esos cambios existirán solo en ese contenedor, pero no persistirán en la imagen de contenedor subyacente (no se guardarán en disco).\n\nUna imagen de contenedor es comparable al archivo de **programa** y sus contenidos, por ejemplo, `python` y algún archivo `main.py`.\n\nY el **contenedor** en sí (en contraste con la **imagen de contenedor**) es la instance real en ejecución de la imagen, comparable a un **proceso**. De hecho, un contenedor solo se está ejecutando cuando tiene un **proceso en ejecución** (y normalmente es solo un proceso). El contenedor se detiene cuando no hay un proceso en ejecución en él.\n\n## Imágenes de Contenedor { #container-images }\n\nDocker ha sido una de las herramientas principales para crear y gestionar **imágenes de contenedor** y **contenedores**.\n\nY hay un [Docker Hub](https://hub.docker.com/) público con **imágenes de contenedores oficiales** pre-hechas para muchas herramientas, entornos, bases de datos y aplicaciones.\n\nPor ejemplo, hay una [Imagen de Python](https://hub.docker.com/_/python) oficial.\n\nY hay muchas otras imágenes para diferentes cosas como bases de datos, por ejemplo para:\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis), etc.\n\nUsando una imagen de contenedor pre-hecha es muy fácil **combinar** y utilizar diferentes herramientas. Por ejemplo, para probar una nueva base de datos. En la mayoría de los casos, puedes usar las **imágenes oficiales**, y simplemente configurarlas con variables de entorno.\n\nDe esta manera, en muchos casos puedes aprender sobre contenedores y Docker y reutilizar ese conocimiento con muchas herramientas y componentes diferentes.\n\nAsí, ejecutarías **múltiples contenedores** con diferentes cosas, como una base de datos, una aplicación de Python, un servidor web con una aplicación frontend en React, y conectarlos entre sí a través de su red interna.\n\nTodos los sistemas de gestión de contenedores (como Docker o Kubernetes) tienen estas funcionalidades de redes integradas.\n\n## Contenedores y Procesos { #containers-and-processes }\n\nUna **imagen de contenedor** normalmente incluye en sus metadatos el programa o comando por defecto que debería ser ejecutado cuando el **contenedor** se inicie y los parámetros que deben pasar a ese programa. Muy similar a lo que sería si estuviera en la línea de comandos.\n\nCuando un **contenedor** se inicia, ejecutará ese comando/programa (aunque puedes sobrescribirlo y hacer que ejecute un comando/programa diferente).\n\nUn contenedor está en ejecución mientras el **proceso principal** (comando o programa) esté en ejecución.\n\nUn contenedor normalmente tiene un **proceso único**, pero también es posible iniciar subprocesos desde el proceso principal, y de esa manera tendrás **múltiples procesos** en el mismo contenedor.\n\nPero no es posible tener un contenedor en ejecución sin **al menos un proceso en ejecución**. Si el proceso principal se detiene, el contenedor se detiene.\n\n## Construir una Imagen de Docker para FastAPI { #build-a-docker-image-for-fastapi }\n\n¡Bien, construyamos algo ahora! 🚀\n\nTe mostraré cómo construir una **imagen de Docker** para FastAPI **desde cero**, basada en la imagen **oficial de Python**.\n\nEsto es lo que querrías hacer en **la mayoría de los casos**, por ejemplo:\n\n* Usando **Kubernetes** o herramientas similares\n* Al ejecutar en un **Raspberry Pi**\n* Usando un servicio en la nube que ejecutaría una imagen de contenedor por ti, etc.\n\n### Requisitos del Paquete { #package-requirements }\n\nNormalmente tendrías los **requisitos del paquete** para tu aplicación en algún archivo.\n\nDependería principalmente de la herramienta que uses para **instalar** esos requisitos.\n\nLa forma más común de hacerlo es tener un archivo `requirements.txt` con los nombres de los paquetes y sus versiones, uno por línea.\n\nPor supuesto, usarías las mismas ideas que leíste en [Acerca de las versiones de FastAPI](versions.md) para establecer los rangos de versiones.\n\nPor ejemplo, tu `requirements.txt` podría verse así:\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\nY normalmente instalarías esas dependencias de los paquetes con `pip`, por ejemplo:\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info | Información\n\nExisten otros formatos y herramientas para definir e instalar dependencias de paquetes.\n\n///\n\n### Crear el Código de **FastAPI** { #create-the-fastapi-code }\n\n* Crea un directorio `app` y entra en él.\n* Crea un archivo vacío `__init__.py`.\n* Crea un archivo `main.py` con:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\nAhora, en el mismo directorio del proyecto, crea un archivo `Dockerfile` con:\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. Comenzar desde la imagen base oficial de Python.\n\n2. Establecer el directorio de trabajo actual a `/code`.\n\n    Aquí es donde pondremos el archivo `requirements.txt` y el directorio `app`.\n\n3. Copiar el archivo con los requisitos al directorio `/code`.\n\n    Copiar **solo** el archivo con los requisitos primero, no el resto del código.\n\n    Como este archivo **no cambia a menudo**, Docker lo detectará y usará la **caché** para este paso, habilitando la caché para el siguiente paso también.\n\n4. Instalar las dependencias de los paquetes en el archivo de requisitos.\n\n    La opción `--no-cache-dir` le dice a `pip` que no guarde los paquetes descargados localmente, ya que eso solo sería si `pip` fuese a ejecutarse de nuevo para instalar los mismos paquetes, pero ese no es el caso al trabajar con contenedores.\n\n    /// note | Nota\n\n    El `--no-cache-dir` está relacionado solo con `pip`, no tiene nada que ver con Docker o contenedores.\n\n    ///\n\n    La opción `--upgrade` le dice a `pip` que actualice los paquetes si ya están instalados.\n\n    Debido a que el paso anterior de copiar el archivo podría ser detectado por la **caché de Docker**, este paso también **usará la caché de Docker** cuando esté disponible.\n\n    Usar la caché en este paso te **ahorrará** mucho **tiempo** al construir la imagen una y otra vez durante el desarrollo, en lugar de **descargar e instalar** todas las dependencias **cada vez**.\n\n5. Copiar el directorio `./app` dentro del directorio `/code`.\n\n    Como esto contiene todo el código, que es lo que **cambia con más frecuencia**, la **caché de Docker** no se utilizará para este u otros **pasos siguientes** fácilmente.\n\n    Así que es importante poner esto **cerca del final** del `Dockerfile`, para optimizar los tiempos de construcción de la imagen del contenedor.\n\n6. Establecer el **comando** para usar `fastapi run`, que utiliza Uvicorn debajo.\n\n    `CMD` toma una lista de cadenas, cada una de estas cadenas es lo que escribirías en la línea de comandos separado por espacios.\n\n    Este comando se ejecutará desde el **directorio de trabajo actual**, el mismo directorio `/code` que estableciste antes con `WORKDIR /code`.\n\n/// tip | Consejo\n\nRevisa qué hace cada línea haciendo clic en cada número en la burbuja del código. 👆\n\n///\n\n/// warning | Advertencia\n\nAsegúrate de **siempre** usar la **forma exec** de la instrucción `CMD`, como se explica a continuación.\n\n///\n\n#### Usar `CMD` - Forma Exec { #use-cmd-exec-form }\n\nLa instrucción Docker [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) se puede escribir usando dos formas:\n\n✅ **Forma Exec**:\n\n```Dockerfile\n# ✅ Haz esto\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ **Forma Shell**:\n\n```Dockerfile\n# ⛔️ No hagas esto\nCMD fastapi run app/main.py --port 80\n```\n\nAsegúrate de siempre usar la **forma exec** para garantizar que FastAPI pueda cerrarse de manera adecuada y que [los eventos de lifespan](../advanced/events.md) sean disparados.\n\nPuedes leer más sobre esto en la [documentación de Docker para formas de shell y exec](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).\n\nEsto puede ser bastante notorio al usar `docker compose`. Consulta esta sección de preguntas frecuentes de Docker Compose para más detalles técnicos: [¿Por qué mis servicios tardan 10 segundos en recrearse o detenerse?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).\n\n#### Estructura de Directorios { #directory-structure }\n\nAhora deberías tener una estructura de directorios como:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### Detrás de un Proxy de Terminación TLS { #behind-a-tls-termination-proxy }\n\nSi estás ejecutando tu contenedor detrás de un Proxy de Terminación TLS (load balancer) como Nginx o Traefik, añade la opción `--proxy-headers`, esto le dirá a Uvicorn (a través de la CLI de FastAPI) que confíe en los headers enviados por ese proxy indicando que la aplicación se está ejecutando detrás de HTTPS, etc.\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Caché de Docker { #docker-cache }\n\nHay un truco importante en este `Dockerfile`, primero copiamos **el archivo con las dependencias solo**, no el resto del código. Déjame decirte por qué es así.\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker y otras herramientas **construyen** estas imágenes de contenedor **incrementalmente**, añadiendo **una capa sobre la otra**, empezando desde la parte superior del `Dockerfile` y añadiendo cualquier archivo creado por cada una de las instrucciones del `Dockerfile`.\n\nDocker y herramientas similares también usan una **caché interna** al construir la imagen, si un archivo no ha cambiado desde la última vez que se construyó la imagen del contenedor, entonces reutilizará la misma capa creada la última vez, en lugar de copiar el archivo de nuevo y crear una nueva capa desde cero.\n\nSolo evitar copiar archivos no mejora necesariamente las cosas mucho, pero porque se usó la caché para ese paso, puede **usar la caché para el siguiente paso**. Por ejemplo, podría usar la caché para la instrucción que instala las dependencias con:\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\nEl archivo con los requisitos de los paquetes **no cambiará con frecuencia**. Así que, al copiar solo ese archivo, Docker podrá **usar la caché** para ese paso.\n\nY luego, Docker podrá **usar la caché para el siguiente paso** que descarga e instala esas dependencias. Y aquí es donde **ahorramos mucho tiempo**. ✨ ...y evitamos el aburrimiento de esperar. 😪😆\n\nDescargar e instalar las dependencias de los paquetes **podría llevar minutos**, pero usando la **caché** tomaría **segundos** como máximo.\n\nY como estarías construyendo la imagen del contenedor una y otra vez durante el desarrollo para comprobar que los cambios en tu código funcionan, hay una gran cantidad de tiempo acumulado que te ahorrarías.\n\nLuego, cerca del final del `Dockerfile`, copiamos todo el código. Como esto es lo que **cambia con más frecuencia**, lo ponemos cerca del final, porque casi siempre, cualquier cosa después de este paso no podrá usar la caché.\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### Construir la Imagen de Docker { #build-the-docker-image }\n\nAhora que todos los archivos están en su lugar, vamos a construir la imagen del contenedor.\n\n* Ve al directorio del proyecto (donde está tu `Dockerfile`, conteniendo tu directorio `app`).\n* Construye tu imagen de FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | Consejo\n\nFíjate en el `.` al final, es equivalente a `./`, le indica a Docker el directorio a usar para construir la imagen del contenedor.\n\nEn este caso, es el mismo directorio actual (`.`).\n\n///\n\n### Iniciar el Contenedor Docker { #start-the-docker-container }\n\n* Ejecuta un contenedor basado en tu imagen:\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## Revísalo { #check-it }\n\nDeberías poder revisarlo en la URL de tu contenedor de Docker, por ejemplo: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) o [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (o equivalente, usando tu host de Docker).\n\nVerás algo como:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## Documentación Interactiva de la API { #interactive-api-docs }\n\nAhora puedes ir a [http://192.168.99.100/docs](http://192.168.99.100/docs) o [http://127.0.0.1/docs](http://127.0.0.1/docs) (o equivalente, usando tu host de Docker).\n\nVerás la documentación interactiva automática de la API (proporcionada por [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## Documentación Alternativa de la API { #alternative-api-docs }\n\nY también puedes ir a [http://192.168.99.100/redoc](http://192.168.99.100/redoc) o [http://127.0.0.1/redoc](http://127.0.0.1/redoc) (o equivalente, usando tu host de Docker).\n\nVerás la documentación alternativa automática (proporcionada por [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Construir una Imagen de Docker con un FastAPI de Un Solo Archivo { #build-a-docker-image-with-a-single-file-fastapi }\n\nSi tu FastAPI es un solo archivo, por ejemplo, `main.py` sin un directorio `./app`, tu estructura de archivos podría verse así:\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\nEntonces solo tendrías que cambiar las rutas correspondientes para copiar el archivo dentro del `Dockerfile`:\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. Copia el archivo `main.py` directamente al directorio `/code` (sin ningún directorio `./app`).\n\n2. Usa `fastapi run` para servir tu aplicación en el archivo único `main.py`.\n\nCuando pasas el archivo a `fastapi run`, detectará automáticamente que es un archivo único y no parte de un paquete y sabrá cómo importarlo y servir tu aplicación FastAPI. 😎\n\n## Conceptos de Despliegue { #deployment-concepts }\n\nHablemos nuevamente de algunos de los mismos [Conceptos de Despliegue](concepts.md) en términos de contenedores.\n\nLos contenedores son principalmente una herramienta para simplificar el proceso de **construcción y despliegue** de una aplicación, pero no imponen un enfoque particular para manejar estos **conceptos de despliegue**, y hay varias estrategias posibles.\n\nLa **buena noticia** es que con cada estrategia diferente hay una forma de cubrir todos los conceptos de despliegue. 🎉\n\nRevisemos estos **conceptos de despliegue** en términos de contenedores:\n\n* HTTPS\n* Ejecutar en el inicio\n* Reinicios\n* Replicación (el número de procesos en ejecución)\n* Memoria\n* Pasos previos antes de comenzar\n\n## HTTPS { #https }\n\nSi nos enfocamos solo en la **imagen de contenedor** para una aplicación FastAPI (y luego el **contenedor** en ejecución), HTTPS normalmente sería manejado **externamente** por otra herramienta.\n\nPodría ser otro contenedor, por ejemplo, con [Traefik](https://traefik.io/), manejando **HTTPS** y la adquisición **automática** de **certificados**.\n\n/// tip | Consejo\n\nTraefik tiene integraciones con Docker, Kubernetes, y otros, por lo que es muy fácil configurar y configurar HTTPS para tus contenedores con él.\n\n///\n\nAlternativamente, HTTPS podría ser manejado por un proveedor de la nube como uno de sus servicios (mientras que la aplicación aún se ejecuta en un contenedor).\n\n## Ejecutar en el Inicio y Reinicios { #running-on-startup-and-restarts }\n\nNormalmente hay otra herramienta encargada de **iniciar y ejecutar** tu contenedor.\n\nPodría ser **Docker** directamente, **Docker Compose**, **Kubernetes**, un **servicio en la nube**, etc.\n\nEn la mayoría (o todas) de las casos, hay una opción sencilla para habilitar la ejecución del contenedor al inicio y habilitar los reinicios en caso de fallos. Por ejemplo, en Docker, es la opción de línea de comandos `--restart`.\n\nSin usar contenedores, hacer que las aplicaciones se ejecuten al inicio y con reinicios puede ser engorroso y difícil. Pero al **trabajar con contenedores** en la mayoría de los casos, esa funcionalidad se incluye por defecto. ✨\n\n## Replicación - Número de Procesos { #replication-number-of-processes }\n\nSi tienes un <dfn title=\"Un grupo de máquinas que están configuradas para estar conectadas y trabajar juntas de alguna manera.\">clúster</dfn> de máquinas con **Kubernetes**, Docker Swarm Mode, Nomad, u otro sistema complejo similar para gestionar contenedores distribuidos en varias máquinas, entonces probablemente querrás manejar la **replicación** a nivel de **cluster** en lugar de usar un **gestor de procesos** (como Uvicorn con workers) en cada contenedor.\n\nUno de esos sistemas de gestión de contenedores distribuidos como Kubernetes normalmente tiene alguna forma integrada de manejar la **replicación de contenedores** mientras aún soporta el **load balancing** para las requests entrantes. Todo a nivel de **cluster**.\n\nEn esos casos, probablemente desearías construir una **imagen de Docker desde cero** como se [explica arriba](#dockerfile), instalando tus dependencias, y ejecutando **un solo proceso de Uvicorn** en lugar de usar múltiples workers de Uvicorn.\n\n### Load Balancer { #load-balancer }\n\nAl usar contenedores, normalmente tendrías algún componente **escuchando en el puerto principal**. Podría posiblemente ser otro contenedor que es también un **Proxy de Terminación TLS** para manejar **HTTPS** o alguna herramienta similar.\n\nComo este componente tomaría la **carga** de las requests y las distribuiría entre los workers de una manera (esperablemente) **balanceada**, también se le llama comúnmente **Load Balancer**.\n\n/// tip | Consejo\n\nEl mismo componente **Proxy de Terminación TLS** usado para HTTPS probablemente también sería un **Load Balancer**.\n\n///\n\nY al trabajar con contenedores, el mismo sistema que usas para iniciarlos y gestionarlos ya tendría herramientas internas para transmitir la **comunicación en red** (e.g., requests HTTP) desde ese **load balancer** (que también podría ser un **Proxy de Terminación TLS**) a los contenedores con tu aplicación.\n\n### Un Load Balancer - Múltiples Contenedores Worker { #one-load-balancer-multiple-worker-containers }\n\nAl trabajar con **Kubernetes** u otros sistemas de gestión de contenedores distribuidos similares, usar sus mecanismos de red internos permitiría que el único **load balancer** que está escuchando en el **puerto** principal transmita la comunicación (requests) a posiblemente **múltiples contenedores** ejecutando tu aplicación.\n\nCada uno de estos contenedores ejecutando tu aplicación normalmente tendría **solo un proceso** (e.g., un proceso Uvicorn ejecutando tu aplicación FastAPI). Todos serían **contenedores idénticos**, ejecutando lo mismo, pero cada uno con su propio proceso, memoria, etc. De esa forma, aprovecharías la **paralelización** en **diferentes núcleos** de la CPU, o incluso en **diferentes máquinas**.\n\nY el sistema de contenedores distribuido con el **load balancer** **distribuiría las requests** a cada uno de los contenedores con tu aplicación **en turnos**. Así, cada request podría ser manejada por uno de los múltiples **contenedores replicados** ejecutando tu aplicación.\n\nY normalmente este **load balancer** podría manejar requests que vayan a *otras* aplicaciones en tu cluster (p. ej., a un dominio diferente, o bajo un prefijo de path de URL diferente), y transmitiría esa comunicación a los contenedores correctos para *esa otra* aplicación ejecutándose en tu cluster.\n\n### Un Proceso por Contenedor { #one-process-per-container }\n\nEn este tipo de escenario, probablemente querrías tener **un solo proceso (Uvicorn) por contenedor**, ya que ya estarías manejando la replicación a nivel de cluster.\n\nAsí que, en este caso, **no** querrías tener múltiples workers en el contenedor, por ejemplo, con la opción de línea de comandos `--workers`. Querrías tener solo un **proceso Uvicorn por contenedor** (pero probablemente múltiples contenedores).\n\nTener otro gestor de procesos dentro del contenedor (como sería con múltiples workers) solo añadiría **complejidad innecesaria** que probablemente ya estés manejando con tu sistema de cluster.\n\n### Contenedores con Múltiples Procesos y Casos Especiales { #containers-with-multiple-processes-and-special-cases }\n\nPor supuesto, hay **casos especiales** donde podrías querer tener **un contenedor** con varios **worker processes de Uvicorn** dentro.\n\nEn esos casos, puedes usar la opción de línea de comandos `--workers` para establecer el número de workers que deseas ejecutar:\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. Aquí usamos la opción de línea de comandos `--workers` para establecer el número de workers a 4.\n\nAquí hay algunos ejemplos de cuándo eso podría tener sentido:\n\n#### Una Aplicación Simple { #a-simple-app }\n\nPodrías querer un gestor de procesos en el contenedor si tu aplicación es **lo suficientemente simple** que pueda ejecutarse en un **servidor único**, no un cluster.\n\n#### Docker Compose { #docker-compose }\n\nPodrías estar desplegando en un **servidor único** (no un cluster) con **Docker Compose**, por lo que no tendrías una forma fácil de gestionar la replicación de contenedores (con Docker Compose) mientras se preserva la red compartida y el **load balancing**.\n\nEntonces podrías querer tener **un solo contenedor** con un **gestor de procesos** iniciando **varios worker processes** dentro.\n\n---\n\nEl punto principal es que, **ninguna** de estas son **reglas escritas en piedra** que debas seguir a ciegas. Puedes usar estas ideas para **evaluar tu propio caso de uso** y decidir cuál es el mejor enfoque para tu sistema, verificando cómo gestionar los conceptos de:\n\n* Seguridad - HTTPS\n* Ejecutar en el inicio\n* Reinicios\n* Replicación (el número de procesos en ejecución)\n* Memoria\n* Pasos previos antes de comenzar\n\n## Memoria { #memory }\n\nSi ejecutas **un solo proceso por contenedor**, tendrás una cantidad de memoria más o menos bien definida, estable y limitada consumida por cada uno de esos contenedores (más de uno si están replicados).\n\nY luego puedes establecer esos mismos límites de memoria y requisitos en tus configuraciones para tu sistema de gestión de contenedores (por ejemplo, en **Kubernetes**). De esa manera, podrá **replicar los contenedores** en las **máquinas disponibles** teniendo en cuenta la cantidad de memoria necesaria por ellos, y la cantidad disponible en las máquinas en el cluster.\n\nSi tu aplicación es **simple**, probablemente esto **no será un problema**, y puede que no necesites especificar límites de memoria estrictos. Pero si estás **usando mucha memoria** (por ejemplo, con modelos de **Machine Learning**), deberías verificar cuánta memoria estás consumiendo y ajustar el **número de contenedores** que se ejecutan en **cada máquina** (y tal vez agregar más máquinas a tu cluster).\n\nSi ejecutas **múltiples procesos por contenedor**, tendrás que asegurarte de que el número de procesos iniciados no **consuma más memoria** de la que está disponible.\n\n## Pasos Previos Antes de Comenzar y Contenedores { #previous-steps-before-starting-and-containers }\n\nSi estás usando contenedores (por ejemplo, Docker, Kubernetes), entonces hay dos enfoques principales que puedes usar.\n\n### Múltiples Contenedores { #multiple-containers }\n\nSi tienes **múltiples contenedores**, probablemente cada uno ejecutando un **proceso único** (por ejemplo, en un cluster de **Kubernetes**), entonces probablemente querrías tener un **contenedor separado** realizando el trabajo de los **pasos previos** en un solo contenedor, ejecutando un solo proceso, **antes** de ejecutar los contenedores worker replicados.\n\n/// info | Información\n\nSi estás usando Kubernetes, probablemente sería un [Contenedor de Inicialización](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).\n\n///\n\nSi en tu caso de uso no hay problema en ejecutar esos pasos previos **múltiples veces en paralelo** (por ejemplo, si no estás ejecutando migraciones de base de datos, sino simplemente verificando si la base de datos está lista), entonces también podrías simplemente ponerlos en cada contenedor justo antes de iniciar el proceso principal.\n\n### Un Contenedor Único { #single-container }\n\nSi tienes una configuración simple, con un **contenedor único** que luego inicia múltiples **worker processes** (o también solo un proceso), entonces podrías ejecutar esos pasos previos en el mismo contenedor, justo antes de iniciar el proceso con la aplicación.\n\n### Imagen Base de Docker { #base-docker-image }\n\nSolía haber una imagen oficial de Docker de FastAPI: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). Pero ahora está obsoleta. ⛔️\n\nProbablemente **no** deberías usar esta imagen base de Docker (o cualquier otra similar).\n\nSi estás usando **Kubernetes** (u otros) y ya estás configurando la **replicación** a nivel de cluster, con múltiples **contenedores**. En esos casos, es mejor que **construyas una imagen desde cero** como se describe arriba: [Construir una Imagen de Docker para FastAPI](#build-a-docker-image-for-fastapi).\n\nY si necesitas tener múltiples workers, puedes simplemente utilizar la opción de línea de comandos `--workers`.\n\n/// note | Detalles Técnicos\n\nLa imagen de Docker se creó cuando Uvicorn no soportaba gestionar y reiniciar workers muertos, por lo que era necesario usar Gunicorn con Uvicorn, lo que añadía bastante complejidad, solo para que Gunicorn gestionara y reiniciara los worker processes de Uvicorn.\n\nPero ahora que Uvicorn (y el comando `fastapi`) soportan el uso de `--workers`, no hay razón para utilizar una imagen base de Docker en lugar de construir la tuya propia (es prácticamente la misma cantidad de código 😅).\n\n///\n\n## Desplegar la Imagen del Contenedor { #deploy-the-container-image }\n\nDespués de tener una Imagen de Contenedor (Docker) hay varias maneras de desplegarla.\n\nPor ejemplo:\n\n* Con **Docker Compose** en un servidor único\n* Con un cluster de **Kubernetes**\n* Con un cluster de Docker Swarm Mode\n* Con otra herramienta como Nomad\n* Con un servicio en la nube que tome tu imagen de contenedor y la despliegue\n\n## Imagen de Docker con `uv` { #docker-image-with-uv }\n\nSi estás usando [uv](https://github.com/astral-sh/uv) para instalar y gestionar tu proyecto, puedes seguir su [guía de Docker de uv](https://docs.astral.sh/uv/guides/integration/docker/).\n\n## Resumen { #recap }\n\nUsando sistemas de contenedores (por ejemplo, con **Docker** y **Kubernetes**) se vuelve bastante sencillo manejar todos los **conceptos de despliegue**:\n\n* HTTPS\n* Ejecutar en el inicio\n* Reinicios\n* Replicación (el número de procesos en ejecución)\n* Memoria\n* Pasos previos antes de comenzar\n\nEn la mayoría de los casos, probablemente no querrás usar ninguna imagen base, y en su lugar **construir una imagen de contenedor desde cero** basada en la imagen oficial de Docker de Python.\n\nTeniendo en cuenta el **orden** de las instrucciones en el `Dockerfile` y la **caché de Docker** puedes **minimizar los tiempos de construcción**, para maximizar tu productividad (y evitar el aburrimiento). 😎\n"
  },
  {
    "path": "docs/es/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\nPuedes desplegar tu app de FastAPI en [FastAPI Cloud](https://fastapicloud.com) con **un solo comando**; ve y únete a la lista de espera si aún no lo has hecho. 🚀\n\n## Iniciar sesión { #login }\n\nAsegúrate de que ya tienes una cuenta de **FastAPI Cloud** (te invitamos desde la lista de espera 😉).\n\nLuego inicia sesión:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## Desplegar { #deploy }\n\nAhora despliega tu app, con **un solo comando**:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n¡Eso es todo! Ahora puedes acceder a tu app en esa URL. ✨\n\n## Acerca de FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** está creado por el mismo autor y equipo detrás de **FastAPI**.\n\nAgiliza el proceso de **crear**, **desplegar** y **acceder** a una API con el mínimo esfuerzo.\n\nAporta la misma **experiencia de desarrollador** de crear apps con FastAPI al **desplegarlas** en la nube. 🎉\n\nTambién se encargará de la mayoría de las cosas que necesitas al desplegar una app, como:\n\n* HTTPS\n* Replicación, con autoescalado basado en requests\n* etc.\n\nFastAPI Cloud es el sponsor principal y proveedor de financiación de los proyectos open source de *FastAPI and friends*. ✨\n\n## Desplegar en otros proveedores de la nube { #deploy-to-other-cloud-providers }\n\nFastAPI es open source y está basado en estándares. Puedes desplegar apps de FastAPI en cualquier proveedor de la nube que elijas.\n\nSigue las guías de tu proveedor de la nube para desplegar apps de FastAPI con ellos. 🤓\n\n## Despliega tu propio servidor { #deploy-your-own-server }\n\nTambién te enseñaré más adelante en esta guía de **Despliegue** todos los detalles, para que puedas entender qué está pasando, qué tiene que ocurrir o cómo desplegar apps de FastAPI por tu cuenta, también con tus propios servidores. 🤓\n"
  },
  {
    "path": "docs/es/docs/deployment/https.md",
    "content": "# Sobre HTTPS { #about-https }\n\nEs fácil asumir que HTTPS es algo que simplemente está \"activado\" o no.\n\nPero es mucho más complejo que eso.\n\n/// tip | Consejo\n\nSi tienes prisa o no te importa, continúa con las siguientes secciones para ver instrucciones paso a paso para configurar todo con diferentes técnicas.\n\n///\n\nPara **aprender los conceptos básicos de HTTPS**, desde una perspectiva de consumidor, revisa [https://howhttps.works/](https://howhttps.works/).\n\nAhora, desde una **perspectiva de desarrollador**, aquí hay varias cosas a tener en cuenta al pensar en HTTPS:\n\n* Para HTTPS, **el servidor** necesita **tener \"certificados\"** generados por un **tercero**.\n    * Esos certificados en realidad son **adquiridos** del tercero, no \"generados\".\n* Los certificados tienen una **vida útil**.\n    * Ellos **expiran**.\n    * Y luego necesitan ser **renovados**, **adquiridos nuevamente** del tercero.\n* La encriptación de la conexión ocurre a nivel de **TCP**.\n    * Esa es una capa **debajo de HTTP**.\n    * Por lo tanto, el manejo de **certificados y encriptación** se realiza **antes de HTTP**.\n* **TCP no sabe acerca de \"dominios\"**. Solo sobre direcciones IP.\n    * La información sobre el **dominio específico** solicitado va en los **datos HTTP**.\n* Los **certificados HTTPS** \"certifican\" un **cierto dominio**, pero el protocolo y la encriptación ocurren a nivel de TCP, **antes de saber** con cuál dominio se está tratando.\n* **Por defecto**, eso significaría que solo puedes tener **un certificado HTTPS por dirección IP**.\n    * No importa cuán grande sea tu servidor o qué tan pequeña pueda ser cada aplicación que tengas en él.\n    * Sin embargo, hay una **solución** para esto.\n* Hay una **extensión** para el protocolo **TLS** (el que maneja la encriptación a nivel de TCP, antes de HTTP) llamada **[<abbr title=\"Server Name Indication - Indicación del nombre del servidor\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**.\n    * Esta extensión SNI permite que un solo servidor (con una **sola dirección IP**) tenga **varios certificados HTTPS** y sirva **múltiples dominios/aplicaciones HTTPS**.\n    * Para que esto funcione, un componente (programa) **único** que se ejecute en el servidor, escuchando en la **dirección IP pública**, debe tener **todos los certificados HTTPS** en el servidor.\n* **Después** de obtener una conexión segura, el protocolo de comunicación sigue siendo **HTTP**.\n    * Los contenidos están **encriptados**, aunque se envién con el **protocolo HTTP**.\n\nEs una práctica común tener **un programa/servidor HTTP** ejecutándose en el servidor (la máquina, host, etc.) y **gestionando todas las partes de HTTPS**: recibiendo los **requests HTTPS encriptados**, enviando los **requests HTTP desencriptados** a la aplicación HTTP real que se ejecuta en el mismo servidor (la aplicación **FastAPI**, en este caso), tomando el **response HTTP** de la aplicación, **encriptándolo** usando el **certificado HTTPS** adecuado y enviándolo de vuelta al cliente usando **HTTPS**. Este servidor a menudo se llama un **[TLS Termination Proxy](https://en.wikipedia.org/wiki/TLS_termination_proxy)**.\n\nAlgunas de las opciones que podrías usar como un TLS Termination Proxy son:\n\n* Traefik (que también puede manejar la renovación de certificados)\n* Caddy (que también puede manejar la renovación de certificados)\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\nAntes de Let's Encrypt, estos **certificados HTTPS** eran vendidos por terceros.\n\nEl proceso para adquirir uno de estos certificados solía ser complicado, requerir bastante papeleo y los certificados eran bastante costosos.\n\nPero luego se creó **[Let's Encrypt](https://letsencrypt.org/)**.\n\nEs un proyecto de la Linux Foundation. Proporciona **certificados HTTPS de forma gratuita**, de manera automatizada. Estos certificados usan toda la seguridad criptográfica estándar, y tienen una corta duración (aproximadamente 3 meses), por lo que la **seguridad es en realidad mejor** debido a su lifespan reducida.\n\nLos dominios son verificados de manera segura y los certificados se generan automáticamente. Esto también permite automatizar la renovación de estos certificados.\n\nLa idea es automatizar la adquisición y renovación de estos certificados para que puedas tener **HTTPS seguro, gratuito, para siempre**.\n\n## HTTPS para Desarrolladores { #https-for-developers }\n\nAquí tienes un ejemplo de cómo podría ser una API HTTPS, paso a paso, prestando atención principalmente a las ideas importantes para los desarrolladores.\n\n### Nombre de Dominio { #domain-name }\n\nProbablemente todo comenzaría adquiriendo un **nombre de dominio**. Luego, lo configurarías en un servidor DNS (posiblemente tu mismo proveedor de la nube).\n\nProbablemente conseguirías un servidor en la nube (una máquina virtual) o algo similar, y tendría una **dirección IP pública** <dfn title=\"No cambia con el tiempo. No dinámica.\">fija</dfn>.\n\nEn el/los servidor(es) DNS configurarías un registro (un \"`A record`\") para apuntar **tu dominio** a la **dirección IP pública de tu servidor**.\n\nProbablemente harías esto solo una vez, la primera vez, al configurar todo.\n\n/// tip | Consejo\n\nEsta parte del Nombre de Dominio es mucho antes de HTTPS, pero como todo depende del dominio y la dirección IP, vale la pena mencionarlo aquí.\n\n///\n\n### DNS { #dns }\n\nAhora centrémonos en todas las partes realmente de HTTPS.\n\nPrimero, el navegador consultaría con los **servidores DNS** cuál es la **IP del dominio**, en este caso, `someapp.example.com`.\n\nLos servidores DNS le dirían al navegador que use una **dirección IP** específica. Esa sería la dirección IP pública utilizada por tu servidor, que configuraste en los servidores DNS.\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### Inicio del Handshake TLS { #tls-handshake-start }\n\nEl navegador luego se comunicaría con esa dirección IP en el **puerto 443** (el puerto HTTPS).\n\nLa primera parte de la comunicación es solo para establecer la conexión entre el cliente y el servidor y decidir las claves criptográficas que usarán, etc.\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\nEsta interacción entre el cliente y el servidor para establecer la conexión TLS se llama **handshake TLS**.\n\n### TLS con Extensión SNI { #tls-with-sni-extension }\n\n**Solo un proceso** en el servidor puede estar escuchando en un **puerto** específico en una **dirección IP** específica. Podría haber otros procesos escuchando en otros puertos en la misma dirección IP, pero solo uno para cada combinación de dirección IP y puerto.\n\nTLS (HTTPS) utiliza el puerto específico `443` por defecto. Así que ese es el puerto que necesitaríamos.\n\nComo solo un proceso puede estar escuchando en este puerto, el proceso que lo haría sería el **TLS Termination Proxy**.\n\nEl TLS Termination Proxy tendría acceso a uno o más **certificados TLS** (certificados HTTPS).\n\nUsando la **extensión SNI** discutida anteriormente, el TLS Termination Proxy verificaría cuál de los certificados TLS (HTTPS) disponibles debería usar para esta conexión, usando el que coincida con el dominio esperado por el cliente.\n\nEn este caso, usaría el certificado para `someapp.example.com`.\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\nEl cliente ya **confía** en la entidad que generó ese certificado TLS (en este caso Let's Encrypt, pero lo veremos más adelante), por lo que puede **verificar** que el certificado sea válido.\n\nLuego, usando el certificado, el cliente y el TLS Termination Proxy **deciden cómo encriptar** el resto de la **comunicación TCP**. Esto completa la parte de **Handshake TLS**.\n\nDespués de esto, el cliente y el servidor tienen una **conexión TCP encriptada**, esto es lo que proporciona TLS. Y luego pueden usar esa conexión para iniciar la comunicación **HTTP real**.\n\nY eso es lo que es **HTTPS**, es simplemente HTTP simple **dentro de una conexión TLS segura** en lugar de una conexión TCP pura (sin encriptar).\n\n/// tip | Consejo\n\nTen en cuenta que la encriptación de la comunicación ocurre a nivel de **TCP**, no a nivel de HTTP.\n\n///\n\n### Request HTTPS { #https-request }\n\nAhora que el cliente y el servidor (específicamente el navegador y el TLS Termination Proxy) tienen una **conexión TCP encriptada**, pueden iniciar la **comunicación HTTP**.\n\nAsí que, el cliente envía un **request HTTPS**. Esto es simplemente un request HTTP a través de una conexión TLS encriptada.\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### Desencriptar el Request { #decrypt-the-request }\n\nEl TLS Termination Proxy usaría la encriptación acordada para **desencriptar el request**, y transmitiría el **request HTTP simple (desencriptado)** al proceso que ejecuta la aplicación (por ejemplo, un proceso con Uvicorn ejecutando la aplicación FastAPI).\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### Response HTTP { #http-response }\n\nLa aplicación procesaría el request y enviaría un **response HTTP simple (sin encriptar)** al TLS Termination Proxy.\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### Response HTTPS { #https-response }\n\nEl TLS Termination Proxy entonces **encriptaría el response** usando la criptografía acordada antes (que comenzó con el certificado para `someapp.example.com`), y lo enviaría de vuelta al navegador.\n\nLuego, el navegador verificaría que el response sea válido y encriptado con la clave criptográfica correcta, etc. Entonces **desencriptaría el response** y lo procesaría.\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\nEl cliente (navegador) sabrá que el response proviene del servidor correcto porque está utilizando la criptografía que acordaron usando el **certificado HTTPS** anteriormente.\n\n### Múltiples Aplicaciones { #multiple-applications }\n\nEn el mismo servidor (o servidores), podrían haber **múltiples aplicaciones**, por ejemplo, otros programas API o una base de datos.\n\nSolo un proceso puede estar gestionando la IP y puerto específica (el TLS Termination Proxy en nuestro ejemplo) pero las otras aplicaciones/procesos pueden estar ejecutándose en el/los servidor(es) también, siempre y cuando no intenten usar la misma **combinación de IP pública y puerto**.\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\nDe esa manera, el TLS Termination Proxy podría gestionar HTTPS y certificados para **múltiples dominios**, para múltiples aplicaciones, y luego transmitir los requests a la aplicación correcta en cada caso.\n\n### Renovación de Certificados { #certificate-renewal }\n\nEn algún momento en el futuro, cada certificado **expiraría** (alrededor de 3 meses después de haberlo adquirido).\n\nY entonces, habría otro programa (en algunos casos es otro programa, en algunos casos podría ser el mismo TLS Termination Proxy) que hablaría con Let's Encrypt y renovaría el/los certificado(s).\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\nLos **certificados TLS** están **asociados con un nombre de dominio**, no con una dirección IP.\n\nEntonces, para renovar los certificados, el programa de renovación necesita **probar** a la autoridad (Let's Encrypt) que de hecho **\"posee\" y controla ese dominio**.\n\nPara hacer eso, y para acomodar diferentes necesidades de aplicaciones, hay varias formas en que puede hacerlo. Algunas formas populares son:\n\n* **Modificar algunos registros DNS**.\n    * Para esto, el programa de renovación necesita soportar las API del proveedor de DNS, por lo que, dependiendo del proveedor de DNS que estés utilizando, esto podría o no ser una opción.\n* **Ejecutarse como un servidor** (al menos durante el proceso de adquisición del certificado) en la dirección IP pública asociada con el dominio.\n    * Como dijimos anteriormente, solo un proceso puede estar escuchando en una IP y puerto específicos.\n    * Esta es una de las razones por las que es muy útil cuando el mismo TLS Termination Proxy también se encarga del proceso de renovación del certificado.\n    * De lo contrario, podrías tener que detener momentáneamente el TLS Termination Proxy, iniciar el programa de renovación para adquirir los certificados, luego configurarlos con el TLS Termination Proxy, y luego reiniciar el TLS Termination Proxy. Esto no es ideal, ya que tus aplicaciones no estarán disponibles durante el tiempo que el TLS Termination Proxy esté apagado.\n\nTodo este proceso de renovación, mientras aún se sirve la aplicación, es una de las principales razones por las que querrías tener un **sistema separado para gestionar el HTTPS** con un TLS Termination Proxy en lugar de simplemente usar los certificados TLS con el servidor de aplicaciones directamente (por ejemplo, Uvicorn).\n\n## Headers reenviados por el proxy { #proxy-forwarded-headers }\n\nAl usar un proxy para gestionar HTTPS, tu **servidor de aplicaciones** (por ejemplo Uvicorn vía FastAPI CLI) no sabe nada sobre el proceso HTTPS, se comunica con HTTP simple con el **TLS Termination Proxy**.\n\nEste **proxy** normalmente configuraría algunos headers HTTP sobre la marcha antes de transmitir el request al **servidor de aplicaciones**, para hacerle saber al servidor de aplicaciones que el request está siendo **reenviado** por el proxy.\n\n/// note | Detalles técnicos\n\nLos headers del proxy son:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\nAun así, como el **servidor de aplicaciones** no sabe que está detrás de un **proxy** de confianza, por defecto, no confiaría en esos headers.\n\nPero puedes configurar el **servidor de aplicaciones** para confiar en los headers reenviados enviados por el **proxy**. Si estás usando FastAPI CLI, puedes usar la *Opción de la CLI* `--forwarded-allow-ips` para indicarle desde qué IPs debería confiar en esos headers reenviados.\n\nPor ejemplo, si el **servidor de aplicaciones** solo está recibiendo comunicación del **proxy** de confianza, puedes establecerlo en `--forwarded-allow-ips=\"*\"` para hacer que confíe en todas las IPs entrantes, ya que solo recibirá requests desde la IP que sea utilizada por el **proxy**.\n\nDe esta manera la aplicación podrá saber cuál es su propia URL pública, si está usando HTTPS, el dominio, etc.\n\nEsto sería útil, por ejemplo, para manejar correctamente redirecciones.\n\n/// tip | Consejo\n\nPuedes aprender más sobre esto en la documentación de [Detrás de un proxy - Habilitar headers reenviados por el proxy](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)\n\n///\n\n## Resumen { #recap }\n\nTener **HTTPS** es muy importante y bastante **crítico** en la mayoría de los casos. La mayor parte del esfuerzo que como desarrollador tienes que poner en torno a HTTPS es solo sobre **entender estos conceptos** y cómo funcionan.\n\nPero una vez que conoces la información básica de **HTTPS para desarrolladores** puedes combinar y configurar fácilmente diferentes herramientas para ayudarte a gestionar todo de una manera sencilla.\n\nEn algunos de los siguientes capítulos, te mostraré varios ejemplos concretos de cómo configurar **HTTPS** para aplicaciones **FastAPI**. 🔒\n"
  },
  {
    "path": "docs/es/docs/deployment/index.md",
    "content": "# Despliegue { #deployment }\n\nDesplegar una aplicación **FastAPI** es relativamente fácil.\n\n## Qué Significa Despliegue { #what-does-deployment-mean }\n\n**Desplegar** una aplicación significa realizar los pasos necesarios para hacerla **disponible para los usuarios**.\n\nPara una **API web**, normalmente implica ponerla en una **máquina remota**, con un **programa de servidor** que proporcione buen rendimiento, estabilidad, etc., para que tus **usuarios** puedan **acceder** a la aplicación de manera eficiente y sin interrupciones o problemas.\n\nEsto contrasta con las etapas de **desarrollo**, donde estás constantemente cambiando el código, rompiéndolo y arreglándolo, deteniendo y reiniciando el servidor de desarrollo, etc.\n\n## Estrategias de Despliegue { #deployment-strategies }\n\nHay varias maneras de hacerlo dependiendo de tu caso de uso específico y las herramientas que utilices.\n\nPodrías **desplegar un servidor** tú mismo utilizando una combinación de herramientas, podrías usar un **servicio en la nube** que hace parte del trabajo por ti, u otras opciones posibles.\n\nPor ejemplo, nosotros, el equipo detrás de FastAPI, construimos [**FastAPI Cloud**](https://fastapicloud.com), para hacer que desplegar aplicaciones de FastAPI en la nube sea lo más ágil posible, con la misma experiencia de desarrollador de trabajar con FastAPI.\n\nTe mostraré algunos de los conceptos principales que probablemente deberías tener en cuenta al desplegar una aplicación **FastAPI** (aunque la mayoría se aplica a cualquier otro tipo de aplicación web).\n\nVerás más detalles a tener en cuenta y algunas de las técnicas para hacerlo en las siguientes secciones. ✨\n"
  },
  {
    "path": "docs/es/docs/deployment/manually.md",
    "content": "# Ejecutar un Servidor Manualmente { #run-a-server-manually }\n\n## Usa el Comando `fastapi run` { #use-the-fastapi-run-command }\n\nEn resumen, usa `fastapi run` para servir tu aplicación FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\nEso funcionaría para la mayoría de los casos. 😎\n\nPodrías usar ese comando, por ejemplo, para iniciar tu app **FastAPI** en un contenedor, en un servidor, etc.\n\n## Servidores ASGI { #asgi-servers }\n\nVamos a profundizar un poquito en los detalles.\n\nFastAPI usa un estándar para construir frameworks de web y servidores de Python llamado <abbr title=\"Asynchronous Server Gateway Interface - Interfaz de puerta de enlace de servidor asíncrona\">ASGI</abbr>. FastAPI es un framework web ASGI.\n\nLo principal que necesitas para ejecutar una aplicación **FastAPI** (o cualquier otra aplicación ASGI) en una máquina de servidor remota es un programa de servidor ASGI como **Uvicorn**, que es el que viene por defecto en el comando `fastapi`.\n\nHay varias alternativas, incluyendo:\n\n* [Uvicorn](https://www.uvicorn.dev/): un servidor ASGI de alto rendimiento.\n* [Hypercorn](https://hypercorn.readthedocs.io/): un servidor ASGI compatible con HTTP/2 y Trio entre otras funcionalidades.\n* [Daphne](https://github.com/django/daphne): el servidor ASGI construido para Django Channels.\n* [Granian](https://github.com/emmett-framework/granian): Un servidor HTTP Rust para aplicaciones en Python.\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit es un runtime para aplicaciones web ligero y versátil.\n\n## Máquina Servidor y Programa Servidor { #server-machine-and-server-program }\n\nHay un pequeño detalle sobre los nombres que hay que tener en cuenta. 💡\n\nLa palabra \"**servidor**\" se utiliza comúnmente para referirse tanto al computador remoto/en la nube (la máquina física o virtual) como al programa que se está ejecutando en esa máquina (por ejemplo, Uvicorn).\n\nSolo ten en cuenta que cuando leas \"servidor\" en general, podría referirse a una de esas dos cosas.\n\nAl referirse a la máquina remota, es común llamarla **servidor**, pero también **máquina**, **VM** (máquina virtual), **nodo**. Todos esos se refieren a algún tipo de máquina remota, generalmente con Linux, donde ejecutas programas.\n\n## Instala el Programa del Servidor { #install-the-server-program }\n\nCuando instalas FastAPI, viene con un servidor de producción, Uvicorn, y puedes iniciarlo con el comando `fastapi run`.\n\nPero también puedes instalar un servidor ASGI manualmente.\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), actívalo, y luego puedes instalar la aplicación del servidor.\n\nPor ejemplo, para instalar Uvicorn:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\nUn proceso similar se aplicaría a cualquier otro programa de servidor ASGI.\n\n/// tip | Consejo\n\nAl añadir `standard`, Uvicorn instalará y usará algunas dependencias adicionales recomendadas.\n\nEso incluye `uvloop`, el reemplazo de alto rendimiento para `asyncio`, que proporciona un gran impulso de rendimiento en concurrencia.\n\nCuando instalas FastAPI con algo como `pip install \"fastapi[standard]\"` ya obtienes `uvicorn[standard]` también.\n\n///\n\n## Ejecuta el Programa del Servidor { #run-the-server-program }\n\nSi instalaste un servidor ASGI manualmente, normalmente necesitarías pasar una cadena de import en un formato especial para que importe tu aplicación FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note | Nota\n\nEl comando `uvicorn main:app` se refiere a:\n\n* `main`: el archivo `main.py` (el \"módulo\" de Python).\n* `app`: el objeto creado dentro de `main.py` con la línea `app = FastAPI()`.\n\nEs equivalente a:\n\n```Python\nfrom main import app\n```\n\n///\n\nCada programa alternativo de servidor ASGI tendría un comando similar, puedes leer más en su respectiva documentación.\n\n/// warning | Advertencia\n\nUvicorn y otros servidores soportan una opción `--reload` que es útil durante el desarrollo.\n\nLa opción `--reload` consume muchos más recursos, es más inestable, etc.\n\nAyuda mucho durante el **desarrollo**, pero **no** deberías usarla en **producción**.\n\n///\n\n## Conceptos de Despliegue { #deployment-concepts }\n\nEstos ejemplos ejecutan el programa del servidor (por ejemplo, Uvicorn), iniciando **un solo proceso**, escuchando en todas las IPs (`0.0.0.0`) en un puerto predefinido (por ejemplo, `80`).\n\nEsta es la idea básica. Pero probablemente querrás encargarte de algunas cosas adicionales, como:\n\n* Seguridad - HTTPS\n* Ejecución en el arranque\n* Reinicios\n* Replicación (el número de procesos ejecutándose)\n* Memoria\n* Pasos previos antes de comenzar\n\nTe contaré más sobre cada uno de estos conceptos, cómo pensarlos, y algunos ejemplos concretos con estrategias para manejarlos en los próximos capítulos. 🚀\n"
  },
  {
    "path": "docs/es/docs/deployment/server-workers.md",
    "content": "# Servidores Workers - Uvicorn con Workers { #server-workers-uvicorn-with-workers }\n\nVamos a revisar esos conceptos de despliegue de antes:\n\n* Seguridad - HTTPS\n* Ejecución al inicio\n* Reinicios\n* **Replicación (el número de procesos en ejecución)**\n* Memoria\n* Pasos previos antes de empezar\n\nHasta este punto, con todos los tutoriales en la documentación, probablemente has estado ejecutando un **programa de servidor**, por ejemplo, usando el comando `fastapi`, que ejecuta Uvicorn, corriendo un **solo proceso**.\n\nAl desplegar aplicaciones probablemente querrás tener algo de **replicación de procesos** para aprovechar **múltiples núcleos** y poder manejar más requests.\n\nComo viste en el capítulo anterior sobre [Conceptos de Despliegue](concepts.md), hay múltiples estrategias que puedes usar.\n\nAquí te mostraré cómo usar **Uvicorn** con **worker processes** usando el comando `fastapi` o el comando `uvicorn` directamente.\n\n/// info | Información\n\nSi estás usando contenedores, por ejemplo con Docker o Kubernetes, te contaré más sobre eso en el próximo capítulo: [FastAPI en Contenedores - Docker](docker.md).\n\nEn particular, cuando corras en **Kubernetes** probablemente **no** querrás usar workers y en cambio correr **un solo proceso de Uvicorn por contenedor**, pero te contaré sobre eso más adelante en ese capítulo.\n\n///\n\n## Múltiples Workers { #multiple-workers }\n\nPuedes iniciar múltiples workers con la opción de línea de comando `--workers`:\n\n//// tab | `fastapi`\n\nSi usas el comando `fastapi`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\nSi prefieres usar el comando `uvicorn` directamente:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\nLa única opción nueva aquí es `--workers` indicando a Uvicorn que inicie 4 worker processes.\n\nTambién puedes ver que muestra el **PID** de cada proceso, `27365` para el proceso padre (este es el **gestor de procesos**) y uno para cada worker process: `27368`, `27369`, `27370`, y `27367`.\n\n## Conceptos de Despliegue { #deployment-concepts }\n\nAquí viste cómo usar múltiples **workers** para **paralelizar** la ejecución de la aplicación, aprovechar los **múltiples núcleos** del CPU, y poder servir **más requests**.\n\nDe la lista de conceptos de despliegue de antes, usar workers ayudaría principalmente con la parte de **replicación**, y un poquito con los **reinicios**, pero aún necesitas encargarte de los otros:\n\n* **Seguridad - HTTPS**\n* **Ejecución al inicio**\n* ***Reinicios***\n* Replicación (el número de procesos en ejecución)\n* **Memoria**\n* **Pasos previos antes de empezar**\n\n## Contenedores y Docker { #containers-and-docker }\n\nEn el próximo capítulo sobre [FastAPI en Contenedores - Docker](docker.md) te explicaré algunas estrategias que podrías usar para manejar los otros **conceptos de despliegue**.\n\nTe mostraré cómo **construir tu propia imagen desde cero** para ejecutar un solo proceso de Uvicorn. Es un proceso sencillo y probablemente es lo que querrías hacer al usar un sistema de gestión de contenedores distribuido como **Kubernetes**.\n\n## Resumen { #recap }\n\nPuedes usar múltiples worker processes con la opción CLI `--workers` con los comandos `fastapi` o `uvicorn` para aprovechar los **CPUs de múltiples núcleos**, para ejecutar **múltiples procesos en paralelo**.\n\nPodrías usar estas herramientas e ideas si estás instalando **tu propio sistema de despliegue** mientras te encargas tú mismo de los otros conceptos de despliegue.\n\nRevisa el próximo capítulo para aprender sobre **FastAPI** con contenedores (por ejemplo, Docker y Kubernetes). Verás que esas herramientas tienen formas sencillas de resolver los otros **conceptos de despliegue** también. ✨\n"
  },
  {
    "path": "docs/es/docs/deployment/versions.md",
    "content": "# Sobre las versiones de FastAPI { #about-fastapi-versions }\n\n**FastAPI** ya se está utilizando en producción en muchas aplicaciones y sistemas. Y la cobertura de tests se mantiene al 100%. Pero su desarrollo sigue avanzando rápidamente.\n\nSe añaden nuevas funcionalidades con frecuencia, se corrigen bugs regularmente, y el código sigue mejorando continuamente.\n\nPor eso las versiones actuales siguen siendo `0.x.x`, esto refleja que cada versión podría tener potencialmente cambios incompatibles. Esto sigue las convenciones de [Semantic Versioning](https://semver.org/).\n\nPuedes crear aplicaciones de producción con **FastAPI** ahora mismo (y probablemente ya lo has estado haciendo desde hace algún tiempo), solo debes asegurarte de que utilizas una versión que funciona correctamente con el resto de tu código.\n\n## Fija tu versión de `fastapi` { #pin-your-fastapi-version }\n\nLo primero que debes hacer es \"fijar\" la versión de **FastAPI** que estás usando a la versión específica más reciente que sabes que funciona correctamente para tu aplicación.\n\nPor ejemplo, digamos que estás utilizando la versión `0.112.0` en tu aplicación.\n\nSi usas un archivo `requirements.txt` podrías especificar la versión con:\n\n```txt\nfastapi[standard]==0.112.0\n```\n\neso significaría que usarías exactamente la versión `0.112.0`.\n\nO también podrías fijarla con:\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\neso significaría que usarías las versiones `0.112.0` o superiores, pero menores que `0.113.0`, por ejemplo, una versión `0.112.2` todavía sería aceptada.\n\nSi utilizas cualquier otra herramienta para gestionar tus instalaciones, como `uv`, Poetry, Pipenv, u otras, todas tienen una forma que puedes usar para definir versiones específicas para tus paquetes.\n\n## Versiones disponibles { #available-versions }\n\nPuedes ver las versiones disponibles (por ejemplo, para revisar cuál es la más reciente) en las [Release Notes](../release-notes.md).\n\n## Sobre las versiones { #about-versions }\n\nSiguiendo las convenciones del Semantic Versioning, cualquier versión por debajo de `1.0.0` podría potencialmente añadir cambios incompatibles.\n\nFastAPI también sigue la convención de que cualquier cambio de versión \"PATCH\" es para corrección de bugs y cambios no incompatibles.\n\n/// tip | Consejo\n\nEl \"PATCH\" es el último número, por ejemplo, en `0.2.3`, la versión PATCH es `3`.\n\n///\n\nAsí que deberías poder fijar a una versión como:\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\nLos cambios incompatibles y nuevas funcionalidades se añaden en versiones \"MINOR\".\n\n/// tip | Consejo\n\nEl \"MINOR\" es el número en el medio, por ejemplo, en `0.2.3`, la versión MINOR es `2`.\n\n///\n\n## Actualizando las versiones de FastAPI { #upgrading-the-fastapi-versions }\n\nDeberías añadir tests para tu aplicación.\n\nCon **FastAPI** es muy fácil (gracias a Starlette), revisa la documentación: [Escribir pruebas](../tutorial/testing.md)\n\nDespués de tener tests, puedes actualizar la versión de **FastAPI** a una más reciente, y asegurarte de que todo tu código está funcionando correctamente ejecutando tus tests.\n\nSi todo está funcionando, o después de hacer los cambios necesarios, y todos tus tests pasan, entonces puedes fijar tu `fastapi` a esa nueva versión más reciente.\n\n## Sobre Starlette { #about-starlette }\n\nNo deberías fijar la versión de `starlette`.\n\nDiferentes versiones de **FastAPI** utilizarán una versión más reciente específica de Starlette.\n\nAsí que, puedes simplemente dejar que **FastAPI** use la versión correcta de Starlette.\n\n## Sobre Pydantic { #about-pydantic }\n\nPydantic incluye los tests para **FastAPI** con sus propios tests, así que nuevas versiones de Pydantic (por encima de `1.0.0`) siempre son compatibles con FastAPI.\n\nPuedes fijar Pydantic a cualquier versión por encima de `1.0.0` que funcione para ti.\n\nPor ejemplo:\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/es/docs/editor-support.md",
    "content": "# Soporte del editor { #editor-support }\n\nLa [Extensión de FastAPI](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) oficial mejora tu flujo de trabajo de desarrollo con FastAPI con descubrimiento de *path operation*, navegación, además de deployment a FastAPI Cloud y streaming en vivo de logs.\n\nPara más detalles sobre la extensión, consulta el README en el [repositorio de GitHub](https://github.com/fastapi/fastapi-vscode).\n\n## Configuración e instalación { #setup-and-installation }\n\nLa **Extensión de FastAPI** está disponible tanto para [VS Code](https://code.visualstudio.com/) como para [Cursor](https://www.cursor.com/). Se puede instalar directamente desde el panel de Extensiones en cada editor buscando \"FastAPI\" y seleccionando la extensión publicada por **FastAPI Labs**. La extensión también funciona en editores basados en navegador como [vscode.dev](https://vscode.dev) y [github.dev](https://github.dev).\n\n### Descubrimiento de la aplicación { #application-discovery }\n\nPor defecto, la extensión descubrirá automáticamente aplicaciones FastAPI en tu espacio de trabajo escaneando archivos que creen un instance de `FastAPI()`. Si la detección automática no funciona con la estructura de tu proyecto, puedes especificar un punto de entrada mediante `[tool.fastapi]` en `pyproject.toml` o la configuración de VS Code `fastapi.entryPoint` usando notación de módulo (p. ej. `myapp.main:app`).\n\n## Funcionalidades { #features }\n\n- **Explorador de Path Operations** - Una vista en árbol en la barra lateral de todas las <dfn title=\"rutas, endpoints\">*path operations*</dfn> de tu aplicación. Haz clic para saltar a cualquier definición de ruta o de router.\n- **Búsqueda de rutas** - Busca por path, método o nombre con <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (en macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>).\n- **Navegación con CodeLens** - Enlaces clicables encima de llamadas del cliente de tests (p. ej. `client.get('/items')`) que saltan a la *path operation* correspondiente para navegar rápidamente entre tests e implementación.\n- **Desplegar en FastAPI Cloud** - Deployment con un clic de tu app a [FastAPI Cloud](https://fastapicloud.com/).\n- **Streaming de logs de la aplicación** - Streaming en tiempo real de logs desde tu aplicación desplegada en FastAPI Cloud, con filtrado por nivel y búsqueda de texto.\n\nSi quieres familiarizarte con las funcionalidades de la extensión, puedes revisar el recorrido guiado de la extensión abriendo la Paleta de Comandos (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> o en macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>) y seleccionando \"Welcome: Open walkthrough...\" y luego eligiendo el recorrido \"Get started with FastAPI\".\n"
  },
  {
    "path": "docs/es/docs/environment-variables.md",
    "content": "# Variables de Entorno { #environment-variables }\n\n/// tip | Consejo\n\nSi ya sabes qué son las \"variables de entorno\" y cómo usarlas, siéntete libre de saltarte esto.\n\n///\n\nUna variable de entorno (también conocida como \"**env var**\") es una variable que vive **fuera** del código de Python, en el **sistema operativo**, y podría ser leída por tu código de Python (o por otros programas también).\n\nLas variables de entorno pueden ser útiles para manejar **configuraciones** de aplicaciones, como parte de la **instalación** de Python, etc.\n\n## Crear y Usar Variables de Entorno { #create-and-use-env-vars }\n\nPuedes **crear** y usar variables de entorno en la **shell (terminal)**, sin necesidad de Python:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Podrías crear una env var MY_NAME con\n$ export MY_NAME=\"Wade Wilson\"\n\n// Luego podrías usarla con otros programas, como\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Crea una env var MY_NAME\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Úsala con otros programas, como\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## Leer Variables de Entorno en Python { #read-env-vars-in-python }\n\nTambién podrías crear variables de entorno **fuera** de Python, en la terminal (o con cualquier otro método), y luego **leerlas en Python**.\n\nPor ejemplo, podrías tener un archivo `main.py` con:\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip | Consejo\n\nEl segundo argumento de [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) es el valor por defecto a retornar.\n\nSi no se proporciona, es `None` por defecto; aquí proporcionamos `\"World\"` como el valor por defecto para usar.\n\n///\n\nLuego podrías llamar a ese programa Python:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Aquí todavía no configuramos la env var\n$ python main.py\n\n// Como no configuramos la env var, obtenemos el valor por defecto\n\nHello World from Python\n\n// Pero si creamos una variable de entorno primero\n$ export MY_NAME=\"Wade Wilson\"\n\n// Y luego llamamos al programa nuevamente\n$ python main.py\n\n// Ahora puede leer la variable de entorno\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Aquí todavía no configuramos la env var\n$ python main.py\n\n// Como no configuramos la env var, obtenemos el valor por defecto\n\nHello World from Python\n\n// Pero si creamos una variable de entorno primero\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Y luego llamamos al programa nuevamente\n$ python main.py\n\n// Ahora puede leer la variable de entorno\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\nDado que las variables de entorno pueden configurarse fuera del código, pero pueden ser leídas por el código, y no tienen que ser almacenadas (committed en `git`) con el resto de los archivos, es común usarlas para configuraciones o **ajustes**.\n\nTambién puedes crear una variable de entorno solo para una **invocación específica de un programa**, que está disponible solo para ese programa, y solo durante su duración.\n\nPara hacer eso, créala justo antes del programa en sí, en la misma línea:\n\n<div class=\"termy\">\n\n```console\n// Crea una env var MY_NAME en línea para esta llamada del programa\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// Ahora puede leer la variable de entorno\n\nHello Wade Wilson from Python\n\n// La env var ya no existe después\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip | Consejo\n\nPuedes leer más al respecto en [The Twelve-Factor App: Config](https://12factor.net/config).\n\n///\n\n## Tipos y Validación { #types-and-validation }\n\nEstas variables de entorno solo pueden manejar **strings de texto**, ya que son externas a Python y deben ser compatibles con otros programas y el resto del sistema (e incluso con diferentes sistemas operativos, como Linux, Windows, macOS).\n\nEsto significa que **cualquier valor** leído en Python desde una variable de entorno **será un `str`**, y cualquier conversión a un tipo diferente o cualquier validación tiene que hacerse en el código.\n\nAprenderás más sobre cómo usar variables de entorno para manejar **configuraciones de aplicación** en la [Guía del Usuario Avanzado - Ajustes y Variables de Entorno](./advanced/settings.md).\n\n## Variable de Entorno `PATH` { #path-environment-variable }\n\nHay una variable de entorno **especial** llamada **`PATH`** que es utilizada por los sistemas operativos (Linux, macOS, Windows) para encontrar programas a ejecutar.\n\nEl valor de la variable `PATH` es un string largo que consiste en directorios separados por dos puntos `:` en Linux y macOS, y por punto y coma `;` en Windows.\n\nPor ejemplo, la variable de entorno `PATH` podría verse así:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nEsto significa que el sistema debería buscar programas en los directorios:\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\nEsto significa que el sistema debería buscar programas en los directorios:\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\nCuando escribes un **comando** en la terminal, el sistema operativo **busca** el programa en **cada uno de esos directorios** listados en la variable de entorno `PATH`.\n\nPor ejemplo, cuando escribes `python` en la terminal, el sistema operativo busca un programa llamado `python` en el **primer directorio** de esa lista.\n\nSi lo encuentra, entonces lo **utilizará**. De lo contrario, continúa buscando en los **otros directorios**.\n\n### Instalando Python y Actualizando el `PATH` { #installing-python-and-updating-the-path }\n\nCuando instalas Python, se te podría preguntar si deseas actualizar la variable de entorno `PATH`.\n\n//// tab | Linux, macOS\n\nDigamos que instalas Python y termina en un directorio `/opt/custompython/bin`.\n\nSi dices que sí para actualizar la variable de entorno `PATH`, entonces el instalador añadirá `/opt/custompython/bin` a la variable de entorno `PATH`.\n\nPodría verse así:\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\nDe esta manera, cuando escribes `python` en la terminal, el sistema encontrará el programa Python en `/opt/custompython/bin` (el último directorio) y usará ese.\n\n////\n\n//// tab | Windows\n\nDigamos que instalas Python y termina en un directorio `C:\\opt\\custompython\\bin`.\n\nSi dices que sí para actualizar la variable de entorno `PATH`, entonces el instalador añadirá `C:\\opt\\custompython\\bin` a la variable de entorno `PATH`.\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\nDe esta manera, cuando escribes `python` en la terminal, el sistema encontrará el programa Python en `C:\\opt\\custompython\\bin` (el último directorio) y usará ese.\n\n////\n\nEntonces, si escribes:\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\nEl sistema **encontrará** el programa `python` en `/opt/custompython/bin` y lo ejecutará.\n\nEsto sería más o menos equivalente a escribir:\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\nEl sistema **encontrará** el programa `python` en `C:\\opt\\custompython\\bin\\python` y lo ejecutará.\n\nEsto sería más o menos equivalente a escribir:\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\nEsta información será útil al aprender sobre [Entornos Virtuales](virtual-environments.md).\n\n## Conclusión { #conclusion }\n\nCon esto deberías tener una comprensión básica de qué son las **variables de entorno** y cómo usarlas en Python.\n\nTambién puedes leer más sobre ellas en la [Wikipedia para Variable de Entorno](https://en.wikipedia.org/wiki/Environment_variable).\n\nEn muchos casos no es muy obvio cómo las variables de entorno serían útiles y aplicables de inmediato. Pero siguen apareciendo en muchos escenarios diferentes cuando estás desarrollando, así que es bueno conocerlas.\n\nPor ejemplo, necesitarás esta información en la siguiente sección, sobre [Entornos Virtuales](virtual-environments.md).\n"
  },
  {
    "path": "docs/es/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - interfaz de línea de comandos\">CLI</abbr>** es un programa de línea de comandos que puedes usar para servir tu aplicación FastAPI, gestionar tu proyecto FastAPI, y más.\n\nCuando instalas FastAPI (por ejemplo, con `pip install \"fastapi[standard]\"`), viene con un programa de línea de comandos que puedes ejecutar en la terminal.\n\nPara ejecutar tu aplicación FastAPI en modo de desarrollo, puedes usar el comando `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip | Consejo\n\nPara producción usarías `fastapi run` en lugar de `fastapi dev`. 🚀\n\n///\n\nInternamente, **FastAPI CLI** usa [Uvicorn](https://www.uvicorn.dev), un servidor ASGI de alto rendimiento y listo para producción. 😎\n\nEl CLI `fastapi` intentará detectar automáticamente la app de FastAPI que debe ejecutar, asumiendo que es un objeto llamado `app` en un archivo `main.py` (o un par de variantes más).\n\nPero puedes configurar explícitamente la app a usar.\n\n## Configura el `entrypoint` de la app en `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nPuedes configurar dónde está tu app en un archivo `pyproject.toml` así:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nEse `entrypoint` le dirá al comando `fastapi` que debe importar la app así:\n\n```python\nfrom main import app\n```\n\nSi tu código estuviera estructurado así:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nEntonces establecerías el `entrypoint` como:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nlo cual sería equivalente a:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` con path { #fastapi-dev-with-path }\n\nTambién puedes pasar el path del archivo al comando `fastapi dev`, y adivinará el objeto app de FastAPI a usar:\n\n```console\n$ fastapi dev main.py\n```\n\nPero tendrías que recordar pasar el path correcto cada vez que llames al comando `fastapi`.\n\nAdicionalmente, otras herramientas podrían no ser capaces de encontrarla, por ejemplo la [Extensión de VS Code](editor-support.md) o [FastAPI Cloud](https://fastapicloud.com), así que se recomienda usar el `entrypoint` en `pyproject.toml`.\n\n## `fastapi dev` { #fastapi-dev }\n\nEjecutar `fastapi dev` inicia el modo de desarrollo.\n\nPor defecto, **auto-reload** está habilitado, recargando automáticamente el servidor cuando realizas cambios en tu código. Esto consume muchos recursos y podría ser menos estable que cuando está deshabilitado. Deberías usarlo solo para desarrollo. También escucha en la dirección IP `127.0.0.1`, que es la IP para que tu máquina se comunique solo consigo misma (`localhost`).\n\n## `fastapi run` { #fastapi-run }\n\nEjecutar `fastapi run` inicia FastAPI en modo de producción por defecto.\n\nPor defecto, **auto-reload** está deshabilitado. También escucha en la dirección IP `0.0.0.0`, lo que significa todas las direcciones IP disponibles, de esta manera será accesible públicamente por cualquiera que pueda comunicarse con la máquina. Esta es la manera en la que normalmente lo ejecutarías en producción, por ejemplo, en un contenedor.\n\nEn la mayoría de los casos tendrías (y deberías) tener un \"proxy de terminación\" manejando HTTPS por ti, esto dependerá de cómo despliegues tu aplicación, tu proveedor podría hacer esto por ti, o podrías necesitar configurarlo tú mismo.\n\n/// tip | Consejo\n\nPuedes aprender más al respecto en la [documentación de despliegue](deployment/index.md).\n\n///\n"
  },
  {
    "path": "docs/es/docs/features.md",
    "content": "# Funcionalidades { #features }\n\n## Funcionalidades de FastAPI { #fastapi-features }\n\n**FastAPI** te ofrece lo siguiente:\n\n### Basado en estándares abiertos { #based-on-open-standards }\n\n* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) para la creación de APIs, incluyendo declaraciones de <dfn title=\"también conocido como: endpoints, rutas\">path</dfn> <dfn title=\"también conocido como métodos HTTP, como POST, GET, PUT, DELETE\">operations</dfn>, parámetros, request bodies, seguridad, etc.\n* Documentación automática de modelos de datos con [**JSON Schema**](https://json-schema.org/) (ya que OpenAPI en sí mismo está basado en JSON Schema).\n* Diseñado alrededor de estos estándares, tras un estudio meticuloso. En lugar de ser una capa adicional.\n* Esto también permite el uso de **generación de código cliente automática** en muchos idiomas.\n\n### Documentación automática { #automatic-docs }\n\nInterfaces web de documentación y exploración de APIs interactivas. Como el framework está basado en OpenAPI, hay múltiples opciones, 2 incluidas por defecto.\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui), con exploración interactiva, llama y prueba tu API directamente desde el navegador.\n\n![Interacción Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Documentación alternativa de API con [**ReDoc**](https://github.com/Rebilly/ReDoc).\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Solo Python moderno { #just-modern-python }\n\nTodo está basado en declaraciones estándar de **tipos en Python** (gracias a Pydantic). Sin nueva sintaxis que aprender. Solo Python moderno estándar.\n\nSi necesitas un repaso de 2 minutos sobre cómo usar tipos en Python (aunque no uses FastAPI), revisa el tutorial corto: [Tipos en Python](python-types.md).\n\nEscribes Python estándar con tipos:\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# Declara una variable como un str\n# y obtiene soporte del editor dentro de la función\ndef main(user_id: str):\n    return user_id\n\n\n# Un modelo de Pydantic\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\nQue luego puede ser usado como:\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n/// info | Información\n\n`**second_user_data` significa:\n\nPasa las claves y valores del dict `second_user_data` directamente como argumentos de clave-valor, equivalente a: `User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### Soporte del editor { #editor-support }\n\nTodo el framework fue diseñado para ser fácil e intuitivo de usar, todas las decisiones fueron probadas en múltiples editores incluso antes de comenzar el desarrollo, para asegurar la mejor experiencia de desarrollo.\n\nEn las encuestas a desarrolladores de Python, es claro [que una de las funcionalidades más usadas es el \"autocompletado\"](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).\n\nTodo el framework **FastAPI** está basado para satisfacer eso. El autocompletado funciona en todas partes.\n\nRara vez necesitarás regresar a la documentación.\n\nAquí está cómo tu editor podría ayudarte:\n\n* en [Visual Studio Code](https://code.visualstudio.com/):\n\n![soporte del editor](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* en [PyCharm](https://www.jetbrains.com/pycharm/):\n\n![soporte del editor](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\nObtendrás autocompletado en código que podrías considerar imposible antes. Por ejemplo, la clave `price` dentro de un cuerpo JSON (que podría haber estado anidado) que proviene de un request.\n\nNo más escribir nombres de claves incorrectos, yendo de un lado a otro entre la documentación, o desplazándote hacia arriba y abajo para encontrar si finalmente usaste `username` o `user_name`.\n\n### Breve { #short }\n\nTiene **valores por defecto** sensatos para todo, con configuraciones opcionales en todas partes. Todos los parámetros se pueden ajustar finamente para hacer lo que necesitas y para definir el API que necesitas.\n\nPero por defecto, todo **\"simplemente funciona\"**.\n\n### Validación { #validation }\n\n* Validación para la mayoría (¿o todas?) de los **tipos de datos** de Python, incluyendo:\n    * Objetos JSON (`dict`).\n    * array JSON (`list`) definiendo tipos de elementos.\n    * Campos de string (`str`), definiendo longitudes mínimas y máximas.\n    * Números (`int`, `float`) con valores mínimos y máximos, etc.\n\n* Validación para tipos más exóticos, como:\n    * URL.\n    * Email.\n    * UUID.\n    * ...y otros.\n\nToda la validación es manejada por **Pydantic**, una herramienta bien establecida y robusta.\n\n### Seguridad y autenticación { #security-and-authentication }\n\nSeguridad y autenticación integradas. Sin ningún compromiso con bases de datos o modelos de datos.\n\nTodos los esquemas de seguridad definidos en OpenAPI, incluyendo:\n\n* HTTP Básico.\n* **OAuth2** (también con **tokens JWT**). Revisa el tutorial sobre [OAuth2 con JWT](tutorial/security/oauth2-jwt.md).\n* API keys en:\n    * Headers.\n    * Parámetros de query.\n    * Cookies, etc.\n\nAdemás de todas las características de seguridad de Starlette (incluyendo **cookies de sesión**).\n\nTodo construido como herramientas y componentes reutilizables que son fáciles de integrar con tus sistemas, almacenes de datos, bases de datos relacionales y NoSQL, etc.\n\n### Inyección de dependencias { #dependency-injection }\n\nFastAPI incluye un sistema de <dfn title='también conocido como \"componentes\", \"recursos\", \"servicios\", \"proveedores\"'><strong>Inyección de Dependencias</strong></dfn> extremadamente fácil de usar, pero extremadamente potente.\n\n* Incluso las dependencias pueden tener dependencias, creando una jerarquía o **\"grafo de dependencias\"**.\n* Todo **manejado automáticamente** por el framework.\n* Todas las dependencias pueden requerir datos de los requests y **aumentar las restricciones de la path operation** y la documentación automática.\n* **Validación automática** incluso para los parámetros de *path operation* definidos en las dependencias.\n* Soporte para sistemas de autenticación de usuario complejos, **conexiones a bases de datos**, etc.\n* **Sin compromisos** con bases de datos, frontends, etc. Pero fácil integración con todos ellos.\n\n### \"Plug-ins\" ilimitados { #unlimited-plug-ins }\n\nO de otra manera, no hay necesidad de ellos, importa y usa el código que necesitas.\n\nCualquier integración está diseñada para ser tan simple de usar (con dependencias) que puedes crear un \"plug-in\" para tu aplicación en 2 líneas de código usando la misma estructura y sintaxis utilizada para tus *path operations*.\n\n### Probado { #tested }\n\n* 100% de <dfn title=\"La cantidad de código que se prueba automáticamente\">cobertura de tests</dfn>.\n* 100% <dfn title=\"Anotaciones de tipos en Python, con esto tu editor y herramientas externas pueden ofrecerte mejor soporte\">anotada con tipos</dfn> code base.\n* Usado en aplicaciones en producción.\n\n## Funcionalidades de Starlette { #starlette-features }\n\n**FastAPI** es totalmente compatible con (y está basado en) [**Starlette**](https://www.starlette.dev/). Así que, cualquier código adicional de Starlette que tengas, también funcionará.\n\n`FastAPI` es en realidad una subclase de `Starlette`. Así que, si ya conoces o usas Starlette, la mayoría de las funcionalidades funcionarán de la misma manera.\n\nCon **FastAPI** obtienes todas las funcionalidades de **Starlette** (ya que FastAPI es simplemente Starlette potenciado):\n\n* Rendimiento seriamente impresionante. Es [uno de los frameworks de Python más rápidos disponibles, a la par de **NodeJS** y **Go**](https://github.com/encode/starlette#performance).\n* Soporte para **WebSocket**.\n* Tareas en segundo plano en el mismo proceso.\n* Eventos de inicio y apagado.\n* Cliente de prueba basado en HTTPX.\n* **CORS**, GZip, archivos estáticos, responses en streaming.\n* Soporte para **Session y Cookie**.\n* Cobertura de tests del 100%.\n* code base 100% anotada con tipos.\n\n## Funcionalidades de Pydantic { #pydantic-features }\n\n**FastAPI** es totalmente compatible con (y está basado en) [**Pydantic**](https://docs.pydantic.dev/). Por lo tanto, cualquier código adicional de Pydantic que tengas, también funcionará.\n\nIncluyendo paquetes externos también basados en Pydantic, como <abbr title=\"Object-Relational Mapper – Mapeador Objeto-Relacional\">ORM</abbr>s, <abbr title=\"Object-Document Mapper – Mapeador Objeto-Documento\">ODM</abbr>s para bases de datos.\n\nEsto también significa que, en muchos casos, puedes pasar el mismo objeto que obtienes de un request **directamente a la base de datos**, ya que todo se valida automáticamente.\n\nLo mismo aplica al revés, en muchos casos puedes simplemente pasar el objeto que obtienes de la base de datos **directamente al cliente**.\n\nCon **FastAPI** obtienes todas las funcionalidades de **Pydantic** (ya que FastAPI está basado en Pydantic para todo el manejo de datos):\n\n* **Sin complicaciones**:\n    * Sin micro-lenguaje de definición de esquemas nuevo que aprender.\n    * Si conoces los tipos en Python sabes cómo usar Pydantic.\n* Se lleva bien con tu **<abbr title=\"Integrated Development Environment – Entorno de Desarrollo Integrado: similar a un editor de código\">IDE</abbr>/<dfn title=\"Un programa que verifica errores de código\">linter</dfn>/cerebro**:\n    * Porque las estructuras de datos de pydantic son solo instances de clases que defines; autocompletado, linting, mypy y tu intuición deberían funcionar correctamente con tus datos validados.\n* Valida **estructuras complejas**:\n    * Uso de modelos jerárquicos de Pydantic, `List` y `Dict` de `typing` de Python, etc.\n    * Y los validadores permiten definir, verificar y documentar de manera clara y fácil esquemas de datos complejos como JSON Schema.\n    * Puedes tener objetos JSON profundamente **anidados** y validarlos todos y anotarlos.\n* **Extensible**:\n    * Pydantic permite definir tipos de datos personalizados o puedes extender la validación con métodos en un modelo decorados con el decorador validator.\n* Cobertura de tests del 100%.\n"
  },
  {
    "path": "docs/es/docs/help-fastapi.md",
    "content": "# Ayuda a FastAPI - Consigue Ayuda { #help-fastapi-get-help }\n\n¿Te gusta **FastAPI**?\n\n¿Te gustaría ayudar a FastAPI, a otros usuarios y al autor?\n\n¿O te gustaría conseguir ayuda con **FastAPI**?\n\nHay formas muy sencillas de ayudar (varias implican solo uno o dos clics).\n\nY también hay varias formas de conseguir ayuda.\n\n## Suscríbete al boletín { #subscribe-to-the-newsletter }\n\nPuedes suscribirte al (esporádico) [boletín **FastAPI and friends**](newsletter.md) para mantenerte al día sobre:\n\n* Noticias sobre FastAPI y amigos 🚀\n* Guías 📝\n* Funcionalidades ✨\n* Cambios importantes 🚨\n* Consejos y trucos ✅\n\n## Sigue a FastAPI en X (Twitter) { #follow-fastapi-on-x-twitter }\n\n[Sigue a @fastapi en **X (Twitter)**](https://x.com/fastapi) para obtener las últimas noticias sobre **FastAPI**. 🐦\n\n## Dale una estrella a **FastAPI** en GitHub { #star-fastapi-in-github }\n\nPuedes \"darle una estrella\" a FastAPI en GitHub (haciendo clic en el botón de estrella en la parte superior derecha): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). ⭐️\n\nAl agregar una estrella, otros usuarios podrán encontrarlo más fácilmente y ver que ya ha sido útil para otros.\n\n## Observa el repositorio de GitHub para lanzamientos { #watch-the-github-repository-for-releases }\n\nPuedes \"observar\" FastAPI en GitHub (haciendo clic en el botón \"watch\" en la parte superior derecha): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nAllí puedes seleccionar \"Releases only\".\n\nAl hacerlo, recibirás notificaciones (en tu email) cada vez que haya un nuevo lanzamiento (una nueva versión) de **FastAPI** con correcciones de bugs y nuevas funcionalidades.\n\n## Conéctate con el autor { #connect-with-the-author }\n\nPuedes conectar [conmigo (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com), el autor.\n\nPuedes:\n\n* [Seguirme en **GitHub**](https://github.com/tiangolo).\n    * Ver otros proyectos de Código Abierto que he creado y que podrían ayudarte.\n    * Seguirme para ver cuándo creo un nuevo proyecto de Código Abierto.\n* [Seguirme en **X (Twitter)**](https://x.com/tiangolo) o [Mastodon](https://fosstodon.org/@tiangolo).\n    * Contarme cómo usas FastAPI (me encanta oír eso).\n    * Enterarte cuando hago anuncios o lanzo nuevas herramientas.\n    * También puedes [seguir @fastapi en X (Twitter)](https://x.com/fastapi) (una cuenta aparte).\n* [Seguirme en **LinkedIn**](https://www.linkedin.com/in/tiangolo/).\n    * Enterarte cuando hago anuncios o lanzo nuevas herramientas (aunque uso X (Twitter) más a menudo 🤷‍♂).\n* Leer lo que escribo (o seguirme) en [**Dev.to**](https://dev.to/tiangolo) o [**Medium**](https://medium.com/@tiangolo).\n    * Leer otras ideas, artículos, y leer sobre las herramientas que he creado.\n    * Seguirme para leer lo que publico nuevo.\n\n## Twittea sobre **FastAPI** { #tweet-about-fastapi }\n\n[Twittea sobre **FastAPI**](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi) y dime a mí y a otros por qué te gusta. 🎉\n\nMe encanta escuchar cómo se está utilizando **FastAPI**, qué te ha gustado, en qué proyecto/empresa lo estás usando, etc.\n\n## Vota por FastAPI { #vote-for-fastapi }\n\n* [Vota por **FastAPI** en Slant](https://www.slant.co/options/34241/~fastapi-review).\n* [Vota por **FastAPI** en AlternativeTo](https://alternativeto.net/software/fastapi/about/).\n* [Di que usas **FastAPI** en StackShare](https://stackshare.io/pypi-fastapi).\n\n## Ayuda a otros con preguntas en GitHub { #help-others-with-questions-in-github }\n\nPuedes intentar ayudar a otros con sus preguntas en:\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\nEn muchos casos, probablemente ya conozcas la respuesta a esas preguntas. 🤓\n\nSi estás ayudando mucho a la gente con sus preguntas, te convertirás en un [FastAPI Expert](fastapi-people.md#fastapi-experts) oficial. 🎉\n\nSolo recuerda, el punto más importante es: trata de ser amable. La gente llega con sus frustraciones y, en muchos casos, no pregunta de la mejor manera, pero haz todo lo posible por ser amable. 🤗\n\nLa idea es que la comunidad de **FastAPI** sea amable y acogedora. Al mismo tiempo, no aceptes acoso o comportamiento irrespetuoso hacia los demás. Tenemos que cuidarnos unos a otros.\n\n---\n\nAquí te explico cómo ayudar a otros con preguntas (en discusiones o issues):\n\n### Entiende la pregunta { #understand-the-question }\n\n* Revisa si puedes entender cuál es el **propósito** y el caso de uso de la persona que pregunta.\n\n* Luego revisa si la pregunta (la gran mayoría son preguntas) es **clara**.\n\n* En muchos casos, la pregunta planteada es sobre una solución imaginaria del usuario, pero podría haber una **mejor**. Si puedes entender mejor el problema y el caso de uso, podrías sugerir una mejor **solución alternativa**.\n\n* Si no puedes entender la pregunta, pide más **detalles**.\n\n### Reproduce el problema { #reproduce-the-problem }\n\nEn la mayoría de los casos y preguntas hay algo relacionado con el **código original** de la persona.\n\nEn muchos casos solo copiarán un fragmento del código, pero eso no es suficiente para **reproducir el problema**.\n\n* Puedes pedirles que proporcionen un [ejemplo mínimo, reproducible](https://stackoverflow.com/help/minimal-reproducible-example), que puedas **copiar-pegar** y ejecutar localmente para ver el mismo error o comportamiento que están viendo, o para entender mejor su caso de uso.\n\n* Si te sientes muy generoso, puedes intentar **crear un ejemplo** así tú mismo, solo basado en la descripción del problema. Solo ten en cuenta que esto podría llevar mucho tiempo y podría ser mejor pedirles que aclaren el problema primero.\n\n### Sugerir soluciones { #suggest-solutions }\n\n* Después de poder entender la pregunta, puedes darles una posible **respuesta**.\n\n* En muchos casos, es mejor entender su **problema subyacente o caso de uso**, porque podría haber una mejor manera de resolverlo que lo que están intentando hacer.\n\n### Pide cerrar { #ask-to-close }\n\nSi responden, hay una alta probabilidad de que hayas resuelto su problema, felicidades, ¡**eres un héroe**! 🦸\n\n* Ahora, si eso resolvió su problema, puedes pedirles que:\n\n    * En GitHub Discussions: marquen el comentario como la **respuesta**.\n    * En GitHub Issues: **cierren** el issue.\n\n## Observa el repositorio de GitHub { #watch-the-github-repository }\n\nPuedes \"observar\" FastAPI en GitHub (haciendo clic en el botón \"watch\" en la parte superior derecha): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nSi seleccionas \"Watching\" en lugar de \"Releases only\", recibirás notificaciones cuando alguien cree un nuevo issue o pregunta. También puedes especificar que solo deseas que te notifiquen sobre nuevos issues, discusiones, PRs, etc.\n\nLuego puedes intentar ayudarlos a resolver esas preguntas.\n\n## Haz preguntas { #ask-questions }\n\nPuedes [crear una nueva pregunta](https://github.com/fastapi/fastapi/discussions/new?category=questions) en el repositorio de GitHub, por ejemplo, para:\n\n* Hacer una **pregunta** o preguntar sobre un **problema**.\n* Sugerir una nueva **funcionalidad**.\n\n**Nota**: si lo haces, entonces te voy a pedir que también ayudes a otros. 😉\n\n## Revisa Pull Requests { #review-pull-requests }\n\nPuedes ayudarme a revisar pull requests de otros.\n\nDe nuevo, por favor, haz tu mejor esfuerzo por ser amable. 🤗\n\n---\n\nAquí está lo que debes tener en cuenta y cómo revisar un pull request:\n\n### Entiende el problema { #understand-the-problem }\n\n* Primero, asegúrate de **entender el problema** que el pull request está intentando resolver. Podría tener una discusión más larga en una GitHub Discussion o issue.\n\n* También hay una buena posibilidad de que el pull request no sea realmente necesario porque el problema se puede resolver de una manera **diferente**. Entonces puedes sugerir o preguntar sobre eso.\n\n### No te preocupes por el estilo { #dont-worry-about-style }\n\n* No te preocupes demasiado por cosas como los estilos de los mensajes de commit, yo haré squash y merge personalizando el commit manualmente.\n\n* Tampoco te preocupes por las reglas de estilo, hay herramientas automatizadas verificando eso.\n\nY si hay alguna otra necesidad de estilo o consistencia, pediré directamente eso, o agregaré commits encima con los cambios necesarios.\n\n### Revisa el código { #check-the-code }\n\n* Revisa y lee el código, ve si tiene sentido, **ejecútalo localmente** y ve si realmente resuelve el problema.\n\n* Luego **comenta** diciendo que hiciste eso, así sabré que realmente lo revisaste.\n\n/// info | Información\n\nDesafortunadamente, no puedo simplemente confiar en PRs que solo tienen varias aprobaciones.\n\nVarias veces ha sucedido que hay PRs con 3, 5 o más aprobaciones, probablemente porque la descripción es atractiva, pero cuando reviso los PRs, en realidad están rotos, tienen un bug, o no resuelven el problema que dicen resolver. 😅\n\nAsí que, es realmente importante que realmente leas y ejecutes el código, y me hagas saber en los comentarios que lo hiciste. 🤓\n\n///\n\n* Si el PR se puede simplificar de alguna manera, puedes pedir eso, pero no hay necesidad de ser demasiado exigente, podría haber muchos puntos de vista subjetivos (y yo tendré el mío también 🙈), así que es mejor si puedes centrarte en las cosas fundamentales.\n\n### Tests { #tests }\n\n* Ayúdame a verificar que el PR tenga **tests**.\n\n* Verifica que los tests **fallen** antes del PR. 🚨\n\n* Luego verifica que los tests **pasen** después del PR. ✅\n\n* Muchos PRs no tienen tests, puedes **recordarles** que agreguen tests, o incluso puedes **sugerir** algunos tests tú mismo. Eso es una de las cosas que consume más tiempo y puedes ayudar mucho con eso.\n\n* Luego también comenta lo que intentaste, de esa manera sabré que lo revisaste. 🤓\n\n## Crea un Pull Request { #create-a-pull-request }\n\nPuedes [contribuir](contributing.md) al código fuente con Pull Requests, por ejemplo:\n\n* Para corregir un error tipográfico que encontraste en la documentación.\n* Para compartir un artículo, video o podcast que creaste o encontraste sobre FastAPI [editando este archivo](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml).\n    * Asegúrate de agregar tu enlace al inicio de la sección correspondiente.\n* Para ayudar a [traducir la documentación](contributing.md#translations) a tu idioma.\n    * También puedes ayudar a revisar las traducciones creadas por otros.\n* Para proponer nuevas secciones de documentación.\n* Para corregir un issue/bug existente.\n    * Asegúrate de agregar tests.\n* Para agregar una nueva funcionalidad.\n    * Asegúrate de agregar tests.\n    * Asegúrate de agregar documentación si es relevante.\n\n## Ayuda a Mantener FastAPI { #help-maintain-fastapi }\n\n¡Ayúdame a mantener **FastAPI**! 🤓\n\nHay mucho trabajo por hacer, y para la mayoría de ello, **TÚ** puedes hacerlo.\n\nLas tareas principales que puedes hacer ahora son:\n\n* [Ayudar a otros con preguntas en GitHub](#help-others-with-questions-in-github) (ver la sección arriba).\n* [Revisar Pull Requests](#review-pull-requests) (ver la sección arriba).\n\nEsas dos tareas son las que **consumen más tiempo**. Ese es el trabajo principal de mantener FastAPI.\n\nSi puedes ayudarme con eso, **me estás ayudando a mantener FastAPI** y asegurando que siga **avanzando más rápido y mejor**. 🚀\n\n## Únete al chat { #join-the-chat }\n\nÚnete al servidor de chat 👥 [Discord](https://discord.gg/VQjSZaeJmf) 👥 y charla con otros en la comunidad de FastAPI.\n\n/// tip | Consejo\n\nPara preguntas, házlas en [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions), hay muchas más probabilidades de que recibas ayuda de parte de los [FastAPI Experts](fastapi-people.md#fastapi-experts).\n\nUsa el chat solo para otras conversaciones generales.\n\n///\n\n### No uses el chat para preguntas { #dont-use-the-chat-for-questions }\n\nTen en cuenta que dado que los chats permiten una \"conversación más libre\", es fácil hacer preguntas que son demasiado generales y más difíciles de responder, por lo que es posible que no recibas respuestas.\n\nEn GitHub, la plantilla te guiará para escribir la pregunta correcta para que puedas obtener más fácilmente una buena respuesta, o incluso resolver el problema por ti mismo antes de preguntar. Y en GitHub puedo asegurarme de responder siempre todo, incluso si lleva tiempo. No puedo hacer eso personalmente con los sistemas de chat. 😅\n\nLas conversaciones en los sistemas de chat tampoco son tan fácilmente buscables como en GitHub, por lo que las preguntas y respuestas podrían perderse en la conversación. Y solo las que están en GitHub cuentan para convertirse en un [FastAPI Expert](fastapi-people.md#fastapi-experts), por lo que probablemente recibirás más atención en GitHub.\n\nPor otro lado, hay miles de usuarios en los sistemas de chat, por lo que hay muchas posibilidades de que encuentres a alguien con quien hablar allí, casi todo el tiempo. 😄\n\n## Hazte sponsor del autor { #sponsor-the-author }\n\nSi tu **producto/empresa** depende de o está relacionado con **FastAPI** y quieres llegar a sus usuarios, puedes hacerte sponsor del autor (de mí) a través de [GitHub sponsors](https://github.com/sponsors/tiangolo). Según el nivel, podrías obtener algunos beneficios extra, como una insignia en la documentación. 🎁\n\n---\n\n¡Gracias! 🚀\n"
  },
  {
    "path": "docs/es/docs/history-design-future.md",
    "content": "# Historia, Diseño y Futuro { #history-design-and-future }\n\nHace algún tiempo, [un usuario de **FastAPI** preguntó](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920):\n\n> ¿Cuál es la historia de este proyecto? Parece haber surgido de la nada y ser increíble en pocas semanas [...]\n\nAquí hay un poquito de esa historia.\n\n## Alternativas { #alternatives }\n\nHe estado creando APIs con requisitos complejos durante varios años (Machine Learning, sistemas distribuidos, trabajos asíncronos, bases de datos NoSQL, etc.), liderando varios equipos de desarrolladores.\n\nComo parte de eso, necesitaba investigar, probar y usar muchas alternativas.\n\nLa historia de **FastAPI** es en gran parte la historia de sus predecesores.\n\nComo se dice en la sección [Alternativas](alternatives.md):\n\n<blockquote markdown=\"1\">\n\n**FastAPI** no existiría si no fuera por el trabajo previo de otros.\n\nHa habido muchas herramientas creadas antes que han ayudado a inspirar su creación.\n\nHe estado evitando la creación de un nuevo framework durante varios años. Primero traté de resolver todas las funcionalidades cubiertas por **FastAPI** usando varios frameworks, plug-ins y herramientas diferentes.\n\nPero en algún momento, no había otra opción que crear algo que proporcionara todas estas funcionalidades, tomando las mejores ideas de herramientas anteriores y combinándolas de la mejor manera posible, usando funcionalidades del lenguaje que ni siquiera estaban disponibles antes (anotaciones de tipos de Python 3.6+).\n\n</blockquote>\n\n## Investigación { #investigation }\n\nAl usar todas las alternativas anteriores, tuve la oportunidad de aprender de todas ellas, tomar ideas y combinarlas de la mejor manera que pude encontrar para mí y los equipos de desarrolladores con los que he trabajado.\n\nPor ejemplo, estaba claro que idealmente debería estar basado en las anotaciones de tipos estándar de Python.\n\nTambién, el mejor enfoque era usar estándares ya existentes.\n\nEntonces, antes de siquiera empezar a programar **FastAPI**, pasé varios meses estudiando las especificaciones de OpenAPI, JSON Schema, OAuth2, etc. Entendiendo su relación, superposición y diferencias.\n\n## Diseño { #design }\n\nLuego pasé algún tiempo diseñando la \"API\" de desarrollador que quería tener como usuario (como desarrollador usando FastAPI).\n\nProbé varias ideas en los editores de Python más populares: PyCharm, VS Code, editores basados en Jedi.\n\nSegún la última [Encuesta de Desarrolladores de Python](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools), estos editores cubren alrededor del 80% de los usuarios.\n\nEsto significa que **FastAPI** fue específicamente probado con los editores usados por el 80% de los desarrolladores de Python. Y como la mayoría de los otros editores tienden a funcionar de manera similar, todos sus beneficios deberían funcionar prácticamente para todos los editores.\n\nDe esa manera, pude encontrar las mejores maneras de reducir la duplicación de código tanto como fuera posible, para tener autocompletado en todas partes, chequeos de tipos y errores, etc.\n\nTodo de una manera que proporcionara la mejor experiencia de desarrollo para todos los desarrolladores.\n\n## Requisitos { #requirements }\n\nDespués de probar varias alternativas, decidí que iba a usar [**Pydantic**](https://docs.pydantic.dev/) por sus ventajas.\n\nLuego contribuí a este, para hacerlo totalmente compatible con JSON Schema, para soportar diferentes maneras de definir declaraciones de restricciones, y para mejorar el soporte de los editores (chequeo de tipos, autocompletado) basado en las pruebas en varios editores.\n\nDurante el desarrollo, también contribuí a [**Starlette**](https://www.starlette.dev/), el otro requisito clave.\n\n## Desarrollo { #development }\n\nPara cuando comencé a crear el propio **FastAPI**, la mayoría de las piezas ya estaban en su lugar, el diseño estaba definido, los requisitos y herramientas estaban listos, y el conocimiento sobre los estándares y especificaciones estaba claro y fresco.\n\n## Futuro { #future }\n\nA este punto, ya está claro que **FastAPI** con sus ideas está siendo útil para muchas personas.\n\nEstá siendo elegido sobre alternativas anteriores por adaptarse mejor a muchos casos de uso.\n\nMuchos desarrolladores y equipos ya dependen de **FastAPI** para sus proyectos (incluyéndome a mí y a mi equipo).\n\nPero aún así, hay muchas mejoras y funcionalidades por venir.\n\n**FastAPI** tiene un gran futuro por delante.\n\nY [tu ayuda](help-fastapi.md) es muy apreciada.\n"
  },
  {
    "path": "docs/es/docs/how-to/authentication-error-status-code.md",
    "content": "# Usar los códigos de estado antiguos 403 para errores de autenticación { #use-old-403-authentication-error-status-codes }\n\nAntes de FastAPI versión `0.122.0`, cuando las utilidades de seguridad integradas devolvían un error al cliente después de una autenticación fallida, usaban el código de estado HTTP `403 Forbidden`.\n\nA partir de FastAPI versión `0.122.0`, usan el código de estado HTTP `401 Unauthorized`, más apropiado, y devuelven un `WWW-Authenticate` header adecuado en la response, siguiendo las especificaciones HTTP, [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized).\n\nPero si por alguna razón tus clientes dependen del comportamiento anterior, puedes volver a él sobrescribiendo el método `make_not_authenticated_error` en tus clases de seguridad.\n\nPor ejemplo, puedes crear una subclase de `HTTPBearer` que devuelva un error `403 Forbidden` en lugar del `401 Unauthorized` por defecto:\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip | Consejo\n\nTen en cuenta que la función devuelve la instance de la excepción, no la lanza. El lanzamiento se hace en el resto del código interno.\n\n///\n"
  },
  {
    "path": "docs/es/docs/how-to/conditional-openapi.md",
    "content": "# OpenAPI condicional { #conditional-openapi }\n\nSi lo necesitaras, podrías usar configuraciones y variables de entorno para configurar OpenAPI condicionalmente según el entorno, e incluso desactivarlo por completo.\n\n## Sobre seguridad, APIs y documentación { #about-security-apis-and-docs }\n\nOcultar las interfaces de usuario de la documentación en producción *no debería* ser la forma de proteger tu API.\n\nEso no añade ninguna seguridad extra a tu API, las *path operations* seguirán estando disponibles donde están.\n\nSi hay una falla de seguridad en tu código, seguirá existiendo.\n\nOcultar la documentación solo hace que sea más difícil entender cómo interactuar con tu API y podría dificultar más depurarla en producción. Podría considerarse simplemente una forma de [Seguridad mediante oscuridad](https://en.wikipedia.org/wiki/Security_through_obscurity).\n\nSi quieres asegurar tu API, hay varias cosas mejores que puedes hacer, por ejemplo:\n\n* Asegúrate de tener modelos Pydantic bien definidos para tus request bodies y responses.\n* Configura los permisos y roles necesarios usando dependencias.\n* Nunca guardes contraseñas en texto plano, solo hashes de contraseñas.\n* Implementa y utiliza herramientas criptográficas bien conocidas, como pwdlib y JWT tokens, etc.\n* Añade controles de permisos más detallados con Scopes de OAuth2 donde sea necesario.\n* ...etc.\n\nNo obstante, podrías tener un caso de uso muy específico donde realmente necesites desactivar la documentación de la API para algún entorno (por ejemplo, para producción) o dependiendo de configuraciones de variables de entorno.\n\n## OpenAPI condicional desde configuraciones y variables de entorno { #conditional-openapi-from-settings-and-env-vars }\n\nPuedes usar fácilmente las mismas configuraciones de Pydantic para configurar tu OpenAPI generado y las interfaces de usuario de la documentación.\n\nPor ejemplo:\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\nAquí declaramos la configuración `openapi_url` con el mismo valor por defecto de `\"/openapi.json\"`.\n\nY luego la usamos al crear la app de `FastAPI`.\n\nEntonces podrías desactivar OpenAPI (incluyendo las UI de documentación) configurando la variable de entorno `OPENAPI_URL` a una string vacía, así:\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nLuego, si vas a las URLs en `/openapi.json`, `/docs`, o `/redoc`, solo obtendrás un error `404 Not Found` como:\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/es/docs/how-to/configure-swagger-ui.md",
    "content": "# Configurar Swagger UI { #configure-swagger-ui }\n\nPuedes configurar algunos [parámetros adicionales de Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\nPara configurarlos, pasa el argumento `swagger_ui_parameters` al crear el objeto de la app `FastAPI()` o a la función `get_swagger_ui_html()`.\n\n`swagger_ui_parameters` recibe un diccionario con las configuraciones pasadas directamente a Swagger UI.\n\nFastAPI convierte las configuraciones a **JSON** para hacerlas compatibles con JavaScript, ya que eso es lo que Swagger UI necesita.\n\n## Desactivar el resaltado de sintaxis { #disable-syntax-highlighting }\n\nPor ejemplo, podrías desactivar el resaltado de sintaxis en Swagger UI.\n\nSin cambiar la configuración, el resaltado de sintaxis está activado por defecto:\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\nPero puedes desactivarlo estableciendo `syntaxHighlight` en `False`:\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n...y entonces Swagger UI ya no mostrará el resaltado de sintaxis:\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## Cambiar el tema { #change-the-theme }\n\nDe la misma manera, podrías configurar el tema del resaltado de sintaxis con la clave `\"syntaxHighlight.theme\"` (ten en cuenta que tiene un punto en el medio):\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\nEsa configuración cambiaría el tema de color del resaltado de sintaxis:\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## Cambiar los parámetros por defecto de Swagger UI { #change-default-swagger-ui-parameters }\n\nFastAPI incluye algunos parámetros de configuración por defecto apropiados para la mayoría de los casos de uso.\n\nIncluye estas configuraciones por defecto:\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\nPuedes sobrescribir cualquiera de ellos estableciendo un valor diferente en el argumento `swagger_ui_parameters`.\n\nPor ejemplo, para desactivar `deepLinking` podrías pasar estas configuraciones a `swagger_ui_parameters`:\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## Otros parámetros de Swagger UI { #other-swagger-ui-parameters }\n\nPara ver todas las demás configuraciones posibles que puedes usar, lee la [documentación oficial de los parámetros de Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\n## Configuraciones solo de JavaScript { #javascript-only-settings }\n\nSwagger UI también permite otras configuraciones que son objetos **solo de JavaScript** (por ejemplo, funciones de JavaScript).\n\nFastAPI también incluye estas configuraciones `presets` solo de JavaScript:\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\nEstos son objetos de **JavaScript**, no strings, por lo que no puedes pasarlos directamente desde código de Python.\n\nSi necesitas usar configuraciones solo de JavaScript como esas, puedes usar uno de los métodos anteriores. Sobrescribe toda la *path operation* de Swagger UI y escribe manualmente cualquier JavaScript que necesites.\n"
  },
  {
    "path": "docs/es/docs/how-to/custom-docs-ui-assets.md",
    "content": "# Recursos Estáticos Personalizados para la Docs UI (self hosting) { #custom-docs-ui-static-assets-self-hosting }\n\nLa documentación de la API utiliza **Swagger UI** y **ReDoc**, y cada uno de estos necesita algunos archivos JavaScript y CSS.\n\nPor defecto, esos archivos se sirven desde un <abbr title=\"Content Delivery Network - Red de entrega de contenidos: Un servicio, normalmente compuesto de varios servidores, que proporciona archivos estáticos, como JavaScript y CSS. Se usa comúnmente para servir esos archivos desde el servidor más cercano al cliente, mejorando el rendimiento.\">CDN</abbr>.\n\nPero es posible personalizarlo, puedes establecer un CDN específico, o servir los archivos tú mismo.\n\n## CDN Personalizado para JavaScript y CSS { #custom-cdn-for-javascript-and-css }\n\nDigamos que quieres usar un <abbr title=\"Content Delivery Network - Red de entrega de contenidos\">CDN</abbr> diferente, por ejemplo, quieres usar `https://unpkg.com/`.\n\nEsto podría ser útil si, por ejemplo, vives en un país que restringe algunas URLs.\n\n### Desactiva la documentación automática { #disable-the-automatic-docs }\n\nEl primer paso es desactivar la documentación automática, ya que por defecto, esos usan el CDN por defecto.\n\nPara desactivarlos, establece sus URLs en `None` cuando crees tu aplicación de `FastAPI`:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### Incluye la documentación personalizada { #include-the-custom-docs }\n\nAhora puedes crear las *path operations* para la documentación personalizada.\n\nPuedes reutilizar las funciones internas de FastAPI para crear las páginas HTML para la documentación, y pasarles los argumentos necesarios:\n\n* `openapi_url`: la URL donde la página HTML para la documentación puede obtener el OpenAPI esquema de tu API. Puedes usar aquí el atributo `app.openapi_url`.\n* `title`: el título de tu API.\n* `oauth2_redirect_url`: puedes usar `app.swagger_ui_oauth2_redirect_url` aquí para usar el valor por defecto.\n* `swagger_js_url`: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo **JavaScript**. Esta es la URL personalizada del CDN.\n* `swagger_css_url`: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo **CSS**. Esta es la URL personalizada del CDN.\n\nY de manera similar para ReDoc...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip | Consejo\n\nLa *path operation* para `swagger_ui_redirect` es una herramienta cuando utilizas OAuth2.\n\nSi integras tu API con un proveedor OAuth2, podrás autenticarte y regresar a la documentación de la API con las credenciales adquiridas. E interactuar con ella usando la autenticación real de OAuth2.\n\nSwagger UI lo manejará detrás de escena para ti, pero necesita este auxiliar de \"redirección\".\n\n///\n\n### Crea una *path operation* para probarlo { #create-a-path-operation-to-test-it }\n\nAhora, para poder probar que todo funciona, crea una *path operation*:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### Pruébalo { #test-it }\n\nAhora, deberías poder ir a tu documentación en [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), y recargar la página, cargará esos recursos desde el nuevo CDN.\n\n## self hosting de JavaScript y CSS para la documentación { #self-hosting-javascript-and-css-for-docs }\n\nEl self hosting de JavaScript y CSS podría ser útil si, por ejemplo, necesitas que tu aplicación siga funcionando incluso offline, sin acceso a Internet, o en una red local.\n\nAquí verás cómo servir esos archivos tú mismo, en la misma aplicación de FastAPI, y configurar la documentación para usarla.\n\n### Estructura de archivos del proyecto { #project-file-structure }\n\nSupongamos que la estructura de archivos de tu proyecto se ve así:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\nAhora crea un directorio para almacenar esos archivos estáticos.\n\nTu nueva estructura de archivos podría verse así:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### Descarga los archivos { #download-the-files }\n\nDescarga los archivos estáticos necesarios para la documentación y ponlos en ese directorio `static/`.\n\nProbablemente puedas hacer clic derecho en cada enlace y seleccionar una opción similar a `Guardar enlace como...`.\n\n**Swagger UI** utiliza los archivos:\n\n* [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n* [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\nY **ReDoc** utiliza el archivo:\n\n* [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\nDespués de eso, tu estructura de archivos podría verse así:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### Sirve los archivos estáticos { #serve-the-static-files }\n\n* Importa `StaticFiles`.\n* \"Monta\" una instance de `StaticFiles()` en un path específico.\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### Prueba los archivos estáticos { #test-the-static-files }\n\nInicia tu aplicación y ve a [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js).\n\nDeberías ver un archivo JavaScript muy largo de **ReDoc**.\n\nPodría comenzar con algo como:\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\nEso confirma que puedes servir archivos estáticos desde tu aplicación, y que colocaste los archivos estáticos para la documentación en el lugar correcto.\n\nAhora podemos configurar la aplicación para usar esos archivos estáticos para la documentación.\n\n### Desactiva la documentación automática para archivos estáticos { #disable-the-automatic-docs-for-static-files }\n\nIgual que cuando usas un CDN personalizado, el primer paso es desactivar la documentación automática, ya que esos usan el CDN por defecto.\n\nPara desactivarlos, establece sus URLs en `None` cuando crees tu aplicación de `FastAPI`:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### Incluye la documentación personalizada para archivos estáticos { #include-the-custom-docs-for-static-files }\n\nY de la misma manera que con un CDN personalizado, ahora puedes crear las *path operations* para la documentación personalizada.\n\nNuevamente, puedes reutilizar las funciones internas de FastAPI para crear las páginas HTML para la documentación, y pasarles los argumentos necesarios:\n\n* `openapi_url`: la URL donde la página HTML para la documentación puede obtener el OpenAPI esquema de tu API. Puedes usar aquí el atributo `app.openapi_url`.\n* `title`: el título de tu API.\n* `oauth2_redirect_url`: puedes usar `app.swagger_ui_oauth2_redirect_url` aquí para usar el valor por defecto.\n* `swagger_js_url`: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo **JavaScript**. **Este es el que tu propia aplicación está sirviendo ahora**.\n* `swagger_css_url`: la URL donde el HTML para tu documentación de Swagger UI puede obtener el archivo **CSS**. **Este es el que tu propia aplicación está sirviendo ahora**.\n\nY de manera similar para ReDoc...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip | Consejo\n\nLa *path operation* para `swagger_ui_redirect` es una herramienta cuando utilizas OAuth2.\n\nSi integras tu API con un proveedor OAuth2, podrás autenticarte y regresar a la documentación de la API con las credenciales adquiridas. Y interactuar con ella usando la autenticación real de OAuth2.\n\nSwagger UI lo manejará detrás de escena para ti, pero necesita este auxiliar de \"redirección\".\n\n///\n\n### Crea una *path operation* para probar archivos estáticos { #create-a-path-operation-to-test-static-files }\n\nAhora, para poder probar que todo funciona, crea una *path operation*:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### Prueba la UI de Archivos Estáticos { #test-static-files-ui }\n\nAhora, deberías poder desconectar tu WiFi, ir a tu documentación en [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), y recargar la página.\n\nE incluso sin Internet, podrás ver la documentación de tu API e interactuar con ella.\n"
  },
  {
    "path": "docs/es/docs/how-to/custom-request-and-route.md",
    "content": "# Clase personalizada de Request y APIRoute { #custom-request-and-apiroute-class }\n\nEn algunos casos, puede que quieras sobrescribir la lógica utilizada por las clases `Request` y `APIRoute`.\n\nEn particular, esta puede ser una buena alternativa a la lógica en un middleware.\n\nPor ejemplo, si quieres leer o manipular el request body antes de que sea procesado por tu aplicación.\n\n/// danger | Advertencia\n\nEsta es una funcionalidad \"avanzada\".\n\nSi apenas estás comenzando con **FastAPI**, quizás quieras saltar esta sección.\n\n///\n\n## Casos de uso { #use-cases }\n\nAlgunos casos de uso incluyen:\n\n* Convertir cuerpos de requests no-JSON a JSON (por ejemplo, [`msgpack`](https://msgpack.org/index.html)).\n* Descomprimir cuerpos de requests comprimidos con gzip.\n* Registrar automáticamente todos los request bodies.\n\n## Manejo de codificaciones personalizadas de request body { #handling-custom-request-body-encodings }\n\nVeamos cómo hacer uso de una subclase personalizada de `Request` para descomprimir requests gzip.\n\nY una subclase de `APIRoute` para usar esa clase de request personalizada.\n\n### Crear una clase personalizada `GzipRequest` { #create-a-custom-gziprequest-class }\n\n/// tip | Consejo\n\nEste es un ejemplo sencillo para demostrar cómo funciona. Si necesitas soporte para Gzip, puedes usar el [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware) proporcionado.\n\n///\n\nPrimero, creamos una clase `GzipRequest`, que sobrescribirá el método `Request.body()` para descomprimir el request body si hay un header apropiado.\n\nSi no hay `gzip` en el header, no intentará descomprimir el request body.\n\nDe esa manera, la misma clase de ruta puede manejar requests comprimidos con gzip o no comprimidos.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### Crear una clase personalizada `GzipRoute` { #create-a-custom-gziproute-class }\n\nA continuación, creamos una subclase personalizada de `fastapi.routing.APIRoute` que hará uso de `GzipRequest`.\n\nEsta vez, sobrescribirá el método `APIRoute.get_route_handler()`.\n\nEste método devuelve una función. Y esa función es la que recibirá un request y devolverá un response.\n\nAquí lo usamos para crear un `GzipRequest` a partir del request original.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | Detalles técnicos\n\nUn `Request` tiene un atributo `request.scope`, que es simplemente un `dict` de Python que contiene los metadatos relacionados con el request.\n\nUn `Request` también tiene un `request.receive`, que es una función para \"recibir\" el request body.\n\nEl `dict` `scope` y la función `receive` son ambos parte de la especificación ASGI.\n\nY esas dos cosas, `scope` y `receive`, son lo que se necesita para crear una nueva *Request instance*.\n\nPara aprender más sobre el `Request`, revisa [la documentación de Starlette sobre Requests](https://www.starlette.dev/requests/).\n\n///\n\nLa única cosa que la función devuelta por `GzipRequest.get_route_handler` hace diferente es convertir el `Request` en un `GzipRequest`.\n\nHaciendo esto, nuestro `GzipRequest` se encargará de descomprimir los datos (si es necesario) antes de pasarlos a nuestras *path operations*.\n\nDespués de eso, toda la lógica de procesamiento es la misma.\n\nPero debido a nuestros cambios en `GzipRequest.body`, el request body se descomprimirá automáticamente cuando sea cargado por **FastAPI** si es necesario.\n\n## Accediendo al request body en un manejador de excepciones { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip | Consejo\n\nPara resolver este mismo problema, probablemente sea mucho más fácil usar el `body` en un manejador personalizado para `RequestValidationError` ([Manejo de Errores](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)).\n\nPero este ejemplo sigue siendo válido y muestra cómo interactuar con los componentes internos.\n\n///\n\nTambién podemos usar este mismo enfoque para acceder al request body en un manejador de excepciones.\n\nTodo lo que necesitamos hacer es manejar el request dentro de un bloque `try`/`except`:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\nSi ocurre una excepción, la `Request instance` aún estará en el alcance, así que podemos leer y hacer uso del request body cuando manejamos el error:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## Clase personalizada `APIRoute` en un router { #custom-apiroute-class-in-a-router }\n\nTambién puedes establecer el parámetro `route_class` de un `APIRouter`:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\nEn este ejemplo, las *path operations* bajo el `router` usarán la clase personalizada `TimedRoute`, y tendrán un header `X-Response-Time` extra en el response con el tiempo que tomó generar el response:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/es/docs/how-to/extending-openapi.md",
    "content": "# Extender OpenAPI { #extending-openapi }\n\nHay algunos casos en los que podrías necesitar modificar el esquema de OpenAPI generado.\n\nEn esta sección verás cómo hacerlo.\n\n## El proceso normal { #the-normal-process }\n\nEl proceso normal (por defecto) es el siguiente.\n\nUna aplicación (instance) de `FastAPI` tiene un método `.openapi()` que se espera que devuelva el esquema de OpenAPI.\n\nComo parte de la creación del objeto de la aplicación, se registra una *path operation* para `/openapi.json` (o para lo que sea que configures tu `openapi_url`).\n\nSimplemente devuelve un response JSON con el resultado del método `.openapi()` de la aplicación.\n\nPor defecto, lo que hace el método `.openapi()` es revisar la propiedad `.openapi_schema` para ver si tiene contenido y devolverlo.\n\nSi no lo tiene, lo genera usando la función de utilidad en `fastapi.openapi.utils.get_openapi`.\n\nY esa función `get_openapi()` recibe como parámetros:\n\n* `title`: El título de OpenAPI, mostrado en la documentación.\n* `version`: La versión de tu API, por ejemplo `2.5.0`.\n* `openapi_version`: La versión de la especificación OpenAPI utilizada. Por defecto, la más reciente: `3.1.0`.\n* `summary`: Un breve resumen de la API.\n* `description`: La descripción de tu API, esta puede incluir markdown y se mostrará en la documentación.\n* `routes`: Una list de rutas, estas son cada una de las *path operations* registradas. Se toman de `app.routes`.\n\n/// info | Información\n\nEl parámetro `summary` está disponible en OpenAPI 3.1.0 y versiones superiores, soportado por FastAPI 0.99.0 y superiores.\n\n///\n\n## Sobrescribir los valores por defecto { #overriding-the-defaults }\n\nUsando la información anterior, puedes usar la misma función de utilidad para generar el esquema de OpenAPI y sobrescribir cada parte que necesites.\n\nPor ejemplo, vamos a añadir [la extensión OpenAPI de ReDoc para incluir un logo personalizado](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo).\n\n### **FastAPI** normal { #normal-fastapi }\n\nPrimero, escribe toda tu aplicación **FastAPI** como normalmente:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### Generar el esquema de OpenAPI { #generate-the-openapi-schema }\n\nLuego, usa la misma función de utilidad para generar el esquema de OpenAPI, dentro de una función `custom_openapi()`:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### Modificar el esquema de OpenAPI { #modify-the-openapi-schema }\n\nAhora puedes añadir la extensión de ReDoc, agregando un `x-logo` personalizado al \"objeto\" `info` en el esquema de OpenAPI:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### Cachear el esquema de OpenAPI { #cache-the-openapi-schema }\n\nPuedes usar la propiedad `.openapi_schema` como un \"cache\", para almacenar tu esquema generado.\n\nDe esa forma, tu aplicación no tendrá que generar el esquema cada vez que un usuario abra la documentación de tu API.\n\nSe generará solo una vez, y luego se usará el mismo esquema cacheado para las siguientes requests.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### Sobrescribir el método { #override-the-method }\n\nAhora puedes reemplazar el método `.openapi()` por tu nueva función.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### Revisa { #check-it }\n\nUna vez que vayas a [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) verás que estás usando tu logo personalizado (en este ejemplo, el logo de **FastAPI**):\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/es/docs/how-to/general.md",
    "content": "# General - Cómo Hacer - Recetas { #general-how-to-recipes }\n\nAquí tienes varias indicaciones hacia otros lugares en la documentación, para preguntas generales o frecuentes.\n\n## Filtrar Datos - Seguridad { #filter-data-security }\n\nPara asegurarte de que no devuelves más datos de los que deberías, lee la documentación para [Tutorial - Modelo de Response - Tipo de Retorno](../tutorial/response-model.md).\n\n## Optimizar el Rendimiento del Response - Modelo de Response - Tipo de Retorno { #optimize-response-performance-response-model-return-type }\n\nPara optimizar el rendimiento al devolver datos JSON, usa un tipo de retorno o un modelo de Response; de esa manera Pydantic se encargará de la serialización a JSON del lado de Rust, sin pasar por Python. Lee más en la documentación para [Tutorial - Modelo de Response - Tipo de Retorno](../tutorial/response-model.md).\n\n## Etiquetas de Documentación - OpenAPI { #documentation-tags-openapi }\n\nPara agregar etiquetas a tus *path operations*, y agruparlas en la interfaz de usuario de la documentación, lee la documentación para [Tutorial - Configuraciones de Path Operation - Etiquetas](../tutorial/path-operation-configuration.md#tags).\n\n## Resumen y Descripción de Documentación - OpenAPI { #documentation-summary-and-description-openapi }\n\nPara agregar un resumen y descripción a tus *path operations*, y mostrarlos en la interfaz de usuario de la documentación, lee la documentación para [Tutorial - Configuraciones de Path Operation - Resumen y Descripción](../tutorial/path-operation-configuration.md#summary-and-description).\n\n## Documentación de Descripción de Response - OpenAPI { #documentation-response-description-openapi }\n\nPara definir la descripción del response, mostrada en la interfaz de usuario de la documentación, lee la documentación para [Tutorial - Configuraciones de Path Operation - Descripción del Response](../tutorial/path-operation-configuration.md#response-description).\n\n## Documentar la Deprecación de una *Path Operation* - OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\nPara deprecar una *path operation*, y mostrarla en la interfaz de usuario de la documentación, lee la documentación para [Tutorial - Configuraciones de Path Operation - Deprecación](../tutorial/path-operation-configuration.md#deprecate-a-path-operation).\n\n## Convertir cualquier Dato a Compatible con JSON { #convert-any-data-to-json-compatible }\n\nPara convertir cualquier dato a compatible con JSON, lee la documentación para [Tutorial - Codificador Compatible con JSON](../tutorial/encoder.md).\n\n## Metadatos OpenAPI - Documentación { #openapi-metadata-docs }\n\nPara agregar metadatos a tu esquema de OpenAPI, incluyendo una licencia, versión, contacto, etc, lee la documentación para [Tutorial - Metadatos y URLs de Documentación](../tutorial/metadata.md).\n\n## URL Personalizada de OpenAPI { #openapi-custom-url }\n\nPara personalizar la URL de OpenAPI (o eliminarla), lee la documentación para [Tutorial - Metadatos y URLs de Documentación](../tutorial/metadata.md#openapi-url).\n\n## URLs de Documentación de OpenAPI { #openapi-docs-urls }\n\nPara actualizar las URLs usadas para las interfaces de usuario de documentación generadas automáticamente, lee la documentación para [Tutorial - Metadatos y URLs de Documentación](../tutorial/metadata.md#docs-urls).\n"
  },
  {
    "path": "docs/es/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\nComo **FastAPI** se basa en el estándar **ASGI**, es muy fácil integrar cualquier paquete de **GraphQL** que también sea compatible con ASGI.\n\nPuedes combinar las *path operations* normales de FastAPI con GraphQL en la misma aplicación.\n\n/// tip | Consejo\n\n**GraphQL** resuelve algunos casos de uso muy específicos.\n\nTiene **ventajas** y **desventajas** en comparación con las **APIs web** comunes.\n\nAsegúrate de evaluar si los **beneficios** para tu caso de uso compensan los **inconvenientes**. 🤓\n\n///\n\n## Paquetes de GraphQL { #graphql-libraries }\n\nAquí algunos de los paquetes de **GraphQL** que tienen soporte **ASGI**. Podrías usarlos con **FastAPI**:\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * Con [documentación para FastAPI](https://strawberry.rocks/docs/integrations/fastapi)\n* [Ariadne](https://ariadnegraphql.org/)\n    * Con [documentación para FastAPI](https://ariadnegraphql.org/docs/fastapi-integration)\n* [Tartiflette](https://tartiflette.io/)\n    * Con [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) para proporcionar integración con ASGI\n* [Graphene](https://graphene-python.org/)\n    * Con [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)\n\n## GraphQL con Strawberry { #graphql-with-strawberry }\n\nSi necesitas o quieres trabajar con **GraphQL**, [**Strawberry**](https://strawberry.rocks/) es el paquete **recomendado** ya que tiene un diseño muy similar al diseño de **FastAPI**, todo basado en **anotaciones de tipos**.\n\nDependiendo de tu caso de uso, podrías preferir usar un paquete diferente, pero si me preguntas, probablemente te sugeriría probar **Strawberry**.\n\nAquí tienes una pequeña vista previa de cómo podrías integrar Strawberry con FastAPI:\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\nPuedes aprender más sobre Strawberry en la [documentación de Strawberry](https://strawberry.rocks/).\n\nY también la documentación sobre [Strawberry con FastAPI](https://strawberry.rocks/docs/integrations/fastapi).\n\n## `GraphQLApp` viejo de Starlette { #older-graphqlapp-from-starlette }\n\nLas versiones anteriores de Starlette incluían una clase `GraphQLApp` para integrar con [Graphene](https://graphene-python.org/).\n\nFue deprecada de Starlette, pero si tienes código que lo usaba, puedes fácilmente **migrar** a [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3), que cubre el mismo caso de uso y tiene una **interfaz casi idéntica**.\n\n/// tip | Consejo\n\nSi necesitas GraphQL, aún te recomendaría revisar [Strawberry](https://strawberry.rocks/), ya que se basa en anotaciones de tipos en lugar de clases y tipos personalizados.\n\n///\n\n## Aprende Más { #learn-more }\n\nPuedes aprender más sobre **GraphQL** en la [documentación oficial de GraphQL](https://graphql.org/).\n\nTambién puedes leer más sobre cada uno de esos paquetes descritos arriba en sus enlaces.\n"
  },
  {
    "path": "docs/es/docs/how-to/index.md",
    "content": "# Cómo hacer - Recetas { #how-to-recipes }\n\nAquí verás diferentes recetas o guías de \"cómo hacer\" para **varios temas**.\n\nLa mayoría de estas ideas serían más o menos **independientes**, y en la mayoría de los casos solo deberías estudiarlas si aplican directamente a **tu proyecto**.\n\nSi algo parece interesante y útil para tu proyecto, adelante y revísalo, pero de lo contrario, probablemente puedas simplemente omitirlas.\n\n/// tip | Consejo\n\nSi quieres **aprender FastAPI** de una manera estructurada (recomendado), ve y lee el [Tutorial - Guía de Usuario](../tutorial/index.md) capítulo por capítulo en su lugar.\n\n///\n"
  },
  {
    "path": "docs/es/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# Migra de Pydantic v1 a Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\nSi tienes una app de FastAPI antigua, podrías estar usando Pydantic versión 1.\n\nFastAPI versión 0.100.0 tenía compatibilidad con Pydantic v1 o v2. Usaba la que tuvieras instalada.\n\nFastAPI versión 0.119.0 introdujo compatibilidad parcial con Pydantic v1 desde dentro de Pydantic v2 (como `pydantic.v1`), para facilitar la migración a v2.\n\nFastAPI 0.126.0 eliminó la compatibilidad con Pydantic v1, aunque siguió soportando `pydantic.v1` por un poquito más de tiempo.\n\n/// warning | Advertencia\n\nEl equipo de Pydantic dejó de dar soporte a Pydantic v1 para las versiones más recientes de Python, comenzando con **Python 3.14**.\n\nEsto incluye `pydantic.v1`, que ya no está soportado en Python 3.14 y superiores.\n\nSi quieres usar las funcionalidades más recientes de Python, tendrás que asegurarte de usar Pydantic v2.\n\n///\n\nSi tienes una app de FastAPI antigua con Pydantic v1, aquí te muestro cómo migrarla a Pydantic v2, y las **funcionalidades en FastAPI 0.119.0** para ayudarte con una migración gradual.\n\n## Guía oficial { #official-guide }\n\nPydantic tiene una [Guía de migración](https://docs.pydantic.dev/latest/migration/) oficial de v1 a v2.\n\nTambién incluye qué cambió, cómo las validaciones ahora son más correctas y estrictas, posibles consideraciones, etc.\n\nPuedes leerla para entender mejor qué cambió.\n\n## Tests { #tests }\n\nAsegúrate de tener [tests](../tutorial/testing.md) para tu app y de ejecutarlos en integración continua (CI).\n\nAsí podrás hacer la actualización y asegurarte de que todo sigue funcionando como esperas.\n\n## `bump-pydantic` { #bump-pydantic }\n\nEn muchos casos, cuando usas modelos de Pydantic normales sin personalizaciones, podrás automatizar gran parte del proceso de migración de Pydantic v1 a Pydantic v2.\n\nPuedes usar [`bump-pydantic`](https://github.com/pydantic/bump-pydantic) del mismo equipo de Pydantic.\n\nEsta herramienta te ayudará a cambiar automáticamente la mayor parte del código que necesita cambiarse.\n\nDespués de esto, puedes ejecutar los tests y revisa si todo funciona. Si es así, ya terminaste. 😎\n\n## Pydantic v1 en v2 { #pydantic-v1-in-v2 }\n\nPydantic v2 incluye todo lo de Pydantic v1 como un submódulo `pydantic.v1`. Pero esto ya no está soportado en versiones por encima de Python 3.13.\n\nEsto significa que puedes instalar la versión más reciente de Pydantic v2 e importar y usar los componentes viejos de Pydantic v1 desde este submódulo, como si tuvieras instalado el Pydantic v1 antiguo.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### Compatibilidad de FastAPI con Pydantic v1 en v2 { #fastapi-support-for-pydantic-v1-in-v2 }\n\nDesde FastAPI 0.119.0, también hay compatibilidad parcial para Pydantic v1 desde dentro de Pydantic v2, para facilitar la migración a v2.\n\nAsí que podrías actualizar Pydantic a la última versión 2 y cambiar los imports para usar el submódulo `pydantic.v1`, y en muchos casos simplemente funcionaría.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning | Advertencia\n\nTen en cuenta que, como el equipo de Pydantic ya no da soporte a Pydantic v1 en versiones recientes de Python, empezando por Python 3.14, usar `pydantic.v1` tampoco está soportado en Python 3.14 y superiores.\n\n///\n\n### Pydantic v1 y v2 en la misma app { #pydantic-v1-and-v2-on-the-same-app }\n\n**No está soportado** por Pydantic tener un modelo de Pydantic v2 con sus propios campos definidos como modelos de Pydantic v1 o viceversa.\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n...pero puedes tener modelos separados usando Pydantic v1 y v2 en la misma app.\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\nEn algunos casos, incluso es posible tener modelos de Pydantic v1 y v2 en la misma **path operation** de tu app de FastAPI:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\nEn el ejemplo anterior, el modelo de entrada es un modelo de Pydantic v1 y el modelo de salida (definido en `response_model=ItemV2`) es un modelo de Pydantic v2.\n\n### Parámetros de Pydantic v1 { #pydantic-v1-parameters }\n\nSi necesitas usar algunas de las herramientas específicas de FastAPI para parámetros como `Body`, `Query`, `Form`, etc. con modelos de Pydantic v1, puedes importarlas de `fastapi.temp_pydantic_v1_params` mientras terminas la migración a Pydantic v2:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### Migra por pasos { #migrate-in-steps }\n\n/// tip | Consejo\n\nPrimero prueba con `bump-pydantic`, si tus tests pasan y eso funciona, entonces terminaste con un solo comando. ✨\n\n///\n\nSi `bump-pydantic` no funciona para tu caso de uso, puedes usar la compatibilidad de modelos Pydantic v1 y v2 en la misma app para hacer la migración a Pydantic v2 de forma gradual.\n\nPodrías primero actualizar Pydantic para usar la última versión 2, y cambiar los imports para usar `pydantic.v1` para todos tus modelos.\n\nLuego puedes empezar a migrar tus modelos de Pydantic v1 a v2 por grupos, en pasos graduales. 🚶\n"
  },
  {
    "path": "docs/es/docs/how-to/separate-openapi-schemas.md",
    "content": "# Separación de Esquemas OpenAPI para Entrada y Salida o No { #separate-openapi-schemas-for-input-and-output-or-not }\n\nDesde que se lanzó **Pydantic v2**, el OpenAPI generado es un poco más exacto y **correcto** que antes. 😎\n\nDe hecho, en algunos casos, incluso tendrá **dos JSON Schemas** en OpenAPI para el mismo modelo Pydantic, para entrada y salida, dependiendo de si tienen **valores por defecto**.\n\nVeamos cómo funciona eso y cómo cambiarlo si necesitas hacerlo.\n\n## Modelos Pydantic para Entrada y Salida { #pydantic-models-for-input-and-output }\n\nDigamos que tienes un modelo Pydantic con valores por defecto, como este:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### Modelo para Entrada { #model-for-input }\n\nSi usas este modelo como entrada, como aquí:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n...entonces el campo `description` **no será requerido**. Porque tiene un valor por defecto de `None`.\n\n### Modelo de Entrada en la Documentación { #input-model-in-docs }\n\nPuedes confirmar eso en la documentación, el campo `description` no tiene un **asterisco rojo**, no está marcado como requerido:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### Modelo para Salida { #model-for-output }\n\nPero si usas el mismo modelo como salida, como aquí:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n...entonces, porque `description` tiene un valor por defecto, si **no devuelves nada** para ese campo, aún tendrá ese **valor por defecto**.\n\n### Modelo para Datos de Response de Salida { #model-for-output-response-data }\n\nSi interactúas con la documentación y revisas el response, aunque el código no agregó nada en uno de los campos `description`, el response JSON contiene el valor por defecto (`null`):\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\nEsto significa que **siempre tendrá un valor**, solo que a veces el valor podría ser `None` (o `null` en JSON).\n\nEso significa que, los clientes que usan tu API no tienen que revisar si el valor existe o no, pueden **asumir que el campo siempre estará allí**, pero solo que en algunos casos tendrá el valor por defecto de `None`.\n\nLa forma de describir esto en OpenAPI es marcar ese campo como **requerido**, porque siempre estará allí.\n\nDebido a eso, el JSON Schema para un modelo puede ser diferente dependiendo de si se usa para **entrada o salida**:\n\n* para **entrada** el `description` **no será requerido**\n* para **salida** será **requerido** (y posiblemente `None`, o en términos de JSON, `null`)\n\n### Modelo para Salida en la Documentación { #model-for-output-in-docs }\n\nTambién puedes revisar el modelo de salida en la documentación, **ambos** `name` y `description` están marcados como **requeridos** con un **asterisco rojo**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### Modelo para Entrada y Salida en la Documentación { #model-for-input-and-output-in-docs }\n\nY si revisas todos los esquemas disponibles (JSON Schemas) en OpenAPI, verás que hay dos, uno `Item-Input` y uno `Item-Output`.\n\nPara `Item-Input`, `description` **no es requerido**, no tiene un asterisco rojo.\n\nPero para `Item-Output`, `description` **es requerido**, tiene un asterisco rojo.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\nCon esta funcionalidad de **Pydantic v2**, la documentación de tu API es más **precisa**, y si tienes clientes y SDKs autogenerados, también serán más precisos, con una mejor **experiencia para desarrolladores** y consistencia. 🎉\n\n## No Separar Esquemas { #do-not-separate-schemas }\n\nAhora, hay algunos casos donde podrías querer tener el **mismo esquema para entrada y salida**.\n\nProbablemente el caso principal para esto es si ya tienes algún código cliente/SDKs autogenerado y no quieres actualizar todo el código cliente/SDKs autogenerado aún, probablemente querrás hacerlo en algún momento, pero tal vez no ahora.\n\nEn ese caso, puedes desactivar esta funcionalidad en **FastAPI**, con el parámetro `separate_input_output_schemas=False`.\n\n/// info | Información\n\nEl soporte para `separate_input_output_schemas` fue agregado en FastAPI `0.102.0`. 🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### Mismo Esquema para Modelos de Entrada y Salida en la Documentación { #same-schema-for-input-and-output-models-in-docs }\n\nY ahora habrá un único esquema para entrada y salida para el modelo, solo `Item`, y tendrá `description` como **no requerido**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/es/docs/how-to/testing-database.md",
    "content": "# Escribir pruebas para una base de datos { #testing-a-database }\n\nPuedes estudiar sobre bases de datos, SQL y SQLModel en la [documentación de SQLModel](https://sqlmodel.tiangolo.com/). 🤓\n\nHay un mini [tutorial sobre el uso de SQLModel con FastAPI](https://sqlmodel.tiangolo.com/tutorial/fastapi/). ✨\n\nEse tutorial incluye una sección sobre [escribir pruebas para bases de datos SQL](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/). 😎\n"
  },
  {
    "path": "docs/es/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/es\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>FastAPI framework, alto rendimiento, fácil de aprender, rápido de programar, listo para producción</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**Documentación**: [https://fastapi.tiangolo.com](https://fastapi.tiangolo.com/es)\n\n**Código Fuente**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI es un framework web moderno, rápido (de alto rendimiento), para construir APIs con Python basado en las anotaciones de tipos estándar de Python.\n\nLas funcionalidades clave son:\n\n* **Rápido**: Muy alto rendimiento, a la par con **NodeJS** y **Go** (gracias a Starlette y Pydantic). [Uno de los frameworks Python más rápidos disponibles](#performance).\n* **Rápido de programar**: Aumenta la velocidad para desarrollar funcionalidades en aproximadamente un 200% a 300%. *\n* **Menos bugs**: Reduce en aproximadamente un 40% los errores inducidos por humanos (desarrolladores). *\n* **Intuitivo**: Gran soporte para editores. <dfn title=\"también conocido como: auto-complete, autocompletado, IntelliSense\">Autocompletado</dfn> en todas partes. Menos tiempo depurando.\n* **Fácil**: Diseñado para ser fácil de usar y aprender. Menos tiempo leyendo documentación.\n* **Corto**: Minimiza la duplicación de código. Múltiples funcionalidades desde cada declaración de parámetro. Menos bugs.\n* **Robusto**: Obtén código listo para producción. Con documentación interactiva automática.\n* **Basado en estándares**: Basado (y completamente compatible) con los estándares abiertos para APIs: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (anteriormente conocido como Swagger) y [JSON Schema](https://json-schema.org/).\n\n<small>* estimación basada en pruebas con un equipo de desarrollo interno, construyendo aplicaciones de producción.</small>\n\n## Sponsors { #sponsors }\n\n<!-- sponsors -->\n\n### Sponsor Keystone { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### Sponsors Oro y Plata { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[Otros sponsors](https://fastapi.tiangolo.com/es/fastapi-people/#sponsors)\n\n## Opiniones { #opinions }\n\n\"_[...] Estoy usando **FastAPI** un montón estos días. [...] De hecho, estoy planeando usarlo para todos los servicios de **ML de mi equipo en Microsoft**. Algunos de ellos se están integrando en el núcleo del producto **Windows** y algunos productos de **Office**._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n\"_Adoptamos el paquete **FastAPI** para crear un servidor **REST** que pueda ser consultado para obtener **predicciones**. [para Ludwig]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, y Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n\"_**Netflix** se complace en anunciar el lanzamiento de código abierto de nuestro framework de orquestación de **gestión de crisis**: **Dispatch**! [construido con **FastAPI**]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n\"_Estoy súper emocionado con **FastAPI**. ¡Es tan divertido!_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken - <strong>[Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855) host del podcast</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(ref)</small></a></div>\n\n---\n\n\"_Honestamente, lo que has construido parece súper sólido y pulido. En muchos aspectos, es lo que quería que **Hug** fuera; es realmente inspirador ver a alguien construir eso._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley - <strong>[Hug](https://github.com/hugapi/hug) creador</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(ref)</small></a></div>\n\n---\n\n\"_Si estás buscando aprender un **framework moderno** para construir APIs REST, échale un vistazo a **FastAPI** [...] Es rápido, fácil de usar y fácil de aprender [...]_\"\n\n\"_Nos hemos cambiado a **FastAPI** para nuestras **APIs** [...] Creo que te gustará [...]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani - Matthew Honnibal - <strong>[fundadores de Explosion AI](https://explosion.ai) - [creadores de spaCy](https://spacy.io)</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(ref)</small></a> - <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(ref)</small></a></div>\n\n---\n\n\"_Si alguien está buscando construir una API de Python para producción, altamente recomendaría **FastAPI**. Está **hermosamente diseñado**, es **simple de usar** y **altamente escalable**, se ha convertido en un **componente clave** en nuestra estrategia de desarrollo API primero y está impulsando muchas automatizaciones y servicios como nuestro Ingeniero Virtual TAC._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n## Mini documental de FastAPI { #fastapi-mini-documentary }\n\nHay un [mini documental de FastAPI](https://www.youtube.com/watch?v=mpR8ngthqiE) lanzado a finales de 2025, puedes verlo online:\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**, el FastAPI de las CLIs { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\nSi estás construyendo una aplicación de <abbr title=\"Command Line Interface - Interfaz de Línea de Comandos\">CLI</abbr> para ser usada en la terminal en lugar de una API web, revisa [**Typer**](https://typer.tiangolo.com/).\n\n**Typer** es el hermano pequeño de FastAPI. Y está destinado a ser el **FastAPI de las CLIs**. ⌨️ 🚀\n\n## Requisitos { #requirements }\n\nFastAPI se apoya en hombros de gigantes:\n\n* [Starlette](https://www.starlette.dev/) para las partes web.\n* [Pydantic](https://docs.pydantic.dev/) para las partes de datos.\n\n## Instalación { #installation }\n\nCrea y activa un [entorno virtual](https://fastapi.tiangolo.com/es/virtual-environments/) y luego instala FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Nota**: Asegúrate de poner `\"fastapi[standard]\"` entre comillas para asegurar que funcione en todas las terminales.\n\n## Ejemplo { #example }\n\n### Créalo { #create-it }\n\nCrea un archivo `main.py` con:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>O usa <code>async def</code>...</summary>\n\nSi tu código usa `async` / `await`, usa `async def`:\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Nota**:\n\nSi no lo sabes, revisa la sección _\"¿Con prisa?\"_ sobre [`async` y `await` en la documentación](https://fastapi.tiangolo.com/es/async/#in-a-hurry).\n\n</details>\n\n### Córrelo { #run-it }\n\nCorre el servidor con:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary>Acerca del comando <code>fastapi dev</code>...</summary>\n\nEl comando `fastapi dev` lee tu archivo `main.py` automáticamente, detecta la app **FastAPI** en él y arranca un servidor usando [Uvicorn](https://www.uvicorn.dev).\n\nPor defecto, `fastapi dev` comenzará con auto-recarga habilitada para el desarrollo local.\n\nPuedes leer más sobre esto en la [documentación del CLI de FastAPI](https://fastapi.tiangolo.com/es/fastapi-cli/).\n\n</details>\n\n### Revísalo { #check-it }\n\nAbre tu navegador en [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery).\n\nVerás el response JSON como:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\nYa creaste una API que:\n\n* Recibe requests HTTP en los _paths_ `/` y `/items/{item_id}`.\n* Ambos _paths_ toman _operaciones_ `GET` (también conocidas como métodos HTTP).\n* El _path_ `/items/{item_id}` tiene un _parámetro de path_ `item_id` que debe ser un `int`.\n* El _path_ `/items/{item_id}` tiene un _parámetro de query_ `q` opcional que es un `str`.\n\n### Documentación interactiva de la API { #interactive-api-docs }\n\nAhora ve a [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVerás la documentación interactiva automática de la API (proporcionada por [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Documentación alternativa de la API { #alternative-api-docs }\n\nY ahora, ve a [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nVerás la documentación alternativa automática (proporcionada por [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Actualización del ejemplo { #example-upgrade }\n\nAhora modifica el archivo `main.py` para recibir un body desde un request `PUT`.\n\nDeclara el body usando tipos estándar de Python, gracias a Pydantic.\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\nEl servidor `fastapi dev` debería recargarse automáticamente.\n\n### Actualización de la documentación interactiva de la API { #interactive-api-docs-upgrade }\n\nAhora ve a [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n* La documentación interactiva de la API se actualizará automáticamente, incluyendo el nuevo body:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Haz clic en el botón \"Try it out\", te permite llenar los parámetros e interactuar directamente con la API:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* Luego haz clic en el botón \"Execute\", la interfaz de usuario se comunicará con tu API, enviará los parámetros, obtendrá los resultados y los mostrará en la pantalla:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### Actualización de la documentación alternativa de la API { #alternative-api-docs-upgrade }\n\nY ahora, ve a [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\n* La documentación alternativa también reflejará el nuevo parámetro de query y body:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Resumen { #recap }\n\nEn resumen, declaras **una vez** los tipos de parámetros, body, etc. como parámetros de función.\n\nLo haces con tipos estándar modernos de Python.\n\nNo tienes que aprender una nueva sintaxis, los métodos o clases de un paquete específico, etc.\n\nSolo **Python** estándar.\n\nPor ejemplo, para un `int`:\n\n```Python\nitem_id: int\n```\n\no para un modelo `Item` más complejo:\n\n```Python\nitem: Item\n```\n\n...y con esa única declaración obtienes:\n\n* Soporte para editores, incluyendo:\n    * Autocompletado.\n    * Chequeo de tipos.\n* Validación de datos:\n    * Errores automáticos y claros cuando los datos son inválidos.\n    * Validación incluso para objetos JSON profundamente anidados.\n* <dfn title=\"también conocido como: serialización, parsing, marshalling\">Conversión</dfn> de datos de entrada: de la red a los datos y tipos de Python. Leyendo desde:\n    * JSON.\n    * Parámetros de path.\n    * Parámetros de query.\n    * Cookies.\n    * Headers.\n    * Formularios.\n    * Archivos.\n* <dfn title=\"también conocido como: serialización, parsing, marshalling\">Conversión</dfn> de datos de salida: convirtiendo de datos y tipos de Python a datos de red (como JSON):\n    * Convertir tipos de Python (`str`, `int`, `float`, `bool`, `list`, etc).\n    * Objetos `datetime`.\n    * Objetos `UUID`.\n    * Modelos de base de datos.\n    * ...y muchos más.\n* Documentación interactiva automática de la API, incluyendo 2 interfaces de usuario alternativas:\n    * Swagger UI.\n    * ReDoc.\n\n---\n\nVolviendo al ejemplo de código anterior, **FastAPI**:\n\n* Validará que haya un `item_id` en el path para requests `GET` y `PUT`.\n* Validará que el `item_id` sea del tipo `int` para requests `GET` y `PUT`.\n    * Si no lo es, el cliente verá un error útil y claro.\n* Revisa si hay un parámetro de query opcional llamado `q` (como en `http://127.0.0.1:8000/items/foo?q=somequery`) para requests `GET`.\n    * Como el parámetro `q` está declarado con `= None`, es opcional.\n    * Sin el `None` sería requerido (como lo es el body en el caso con `PUT`).\n* Para requests `PUT` a `/items/{item_id}`, leerá el body como JSON:\n    * Revisa que tiene un atributo requerido `name` que debe ser un `str`.\n    * Revisa que tiene un atributo requerido `price` que debe ser un `float`.\n    * Revisa que tiene un atributo opcional `is_offer`, que debe ser un `bool`, si está presente.\n    * Todo esto también funcionaría para objetos JSON profundamente anidados.\n* Convertirá de y a JSON automáticamente.\n* Documentará todo con OpenAPI, que puede ser usado por:\n    * Sistemas de documentación interactiva.\n    * Sistemas de generación automática de código cliente, para muchos lenguajes.\n* Proporcionará 2 interfaces web de documentación interactiva directamente.\n\n---\n\nSolo tocamos los conceptos básicos, pero ya te haces una idea de cómo funciona todo.\n\nIntenta cambiar la línea con:\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n...desde:\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n...a:\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n...y observa cómo tu editor autocompleta los atributos y conoce sus tipos:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\nPara un ejemplo más completo incluyendo más funcionalidades, ve al <a href=\"https://fastapi.tiangolo.com/es/tutorial/\">Tutorial - Guía del Usuario</a>.\n\n**Alerta de spoilers**: el tutorial - guía del usuario incluye:\n\n* Declaración de **parámetros** desde otros lugares diferentes como: **headers**, **cookies**, **campos de formulario** y **archivos**.\n* Cómo establecer **restricciones de validación** como `maximum_length` o `regex`.\n* Un sistema de **<dfn title=\"también conocido como: componentes, recursos, proveedores, servicios, inyectables\">Inyección de Dependencias</dfn>** muy poderoso y fácil de usar.\n* Seguridad y autenticación, incluyendo soporte para **OAuth2** con **tokens JWT** y autenticación **HTTP Basic**.\n* Técnicas más avanzadas (pero igualmente fáciles) para declarar **modelos JSON profundamente anidados** (gracias a Pydantic).\n* Integración con **GraphQL** usando [Strawberry](https://strawberry.rocks) y otros paquetes.\n* Muchas funcionalidades extra (gracias a Starlette) como:\n    * **WebSockets**\n    * pruebas extremadamente fáciles basadas en HTTPX y `pytest`\n    * **CORS**\n    * **Sesiones de Cookies**\n    * ...y más.\n\n### Despliega tu app (opcional) { #deploy-your-app-optional }\n\nOpcionalmente puedes desplegar tu app de FastAPI en [FastAPI Cloud](https://fastapicloud.com), ve y únete a la lista de espera si no lo has hecho. 🚀\n\nSi ya tienes una cuenta de **FastAPI Cloud** (te invitamos desde la lista de espera 😉), puedes desplegar tu aplicación con un solo comando.\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n¡Eso es todo! Ahora puedes acceder a tu app en esa URL. ✨\n\n#### Acerca de FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** está construido por el mismo autor y equipo detrás de **FastAPI**.\n\nOptimiza el proceso de **construir**, **desplegar** y **acceder** a una API con un esfuerzo mínimo.\n\nTrae la misma **experiencia de desarrollador** de construir apps con FastAPI a **desplegarlas** en la nube. 🎉\n\nFastAPI Cloud es el sponsor principal y proveedor de financiamiento para los proyectos open source *FastAPI and friends*. ✨\n\n#### Despliega en otros proveedores de cloud { #deploy-to-other-cloud-providers }\n\nFastAPI es open source y está basado en estándares. Puedes desplegar apps de FastAPI en cualquier proveedor de cloud que elijas.\n\nSigue las guías de tu proveedor de cloud para desplegar apps de FastAPI con ellos. 🤓\n\n## Rendimiento { #performance }\n\nBenchmarks independientes de TechEmpower muestran aplicaciones **FastAPI** ejecutándose bajo Uvicorn como [uno de los frameworks Python más rápidos disponibles](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), solo por debajo de Starlette y Uvicorn (usados internamente por FastAPI). (*)\n\nPara entender más sobre esto, ve la sección [Benchmarks](https://fastapi.tiangolo.com/es/benchmarks/).\n\n## Dependencias { #dependencies }\n\nFastAPI depende de Pydantic y Starlette.\n\n### Dependencias `standard` { #standard-dependencies }\n\nCuando instalas FastAPI con `pip install \"fastapi[standard]\"` viene con el grupo `standard` de dependencias opcionales:\n\nUsadas por Pydantic:\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - para validación de correos electrónicos.\n\nUsadas por Starlette:\n\n* [`httpx`](https://www.python-httpx.org) - Requerido si deseas usar el `TestClient`.\n* [`jinja2`](https://jinja.palletsprojects.com) - Requerido si deseas usar la configuración de plantilla por defecto.\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - Requerido si deseas soportar form <dfn title=\"convertir el string que viene de un request HTTP en datos de Python\">\"parsing\"</dfn>, con `request.form()`.\n\nUsadas por FastAPI:\n\n* [`uvicorn`](https://www.uvicorn.dev) - para el servidor que carga y sirve tu aplicación. Esto incluye `uvicorn[standard]`, que incluye algunas dependencias (por ejemplo, `uvloop`) necesarias para servir con alto rendimiento.\n* `fastapi-cli[standard]` - para proporcionar el comando `fastapi`.\n    * Esto incluye `fastapi-cloud-cli`, que te permite desplegar tu aplicación de FastAPI en [FastAPI Cloud](https://fastapicloud.com).\n\n### Sin Dependencias `standard` { #without-standard-dependencies }\n\nSi no deseas incluir las dependencias opcionales `standard`, puedes instalar con `pip install fastapi` en lugar de `pip install \"fastapi[standard]\"`.\n\n### Sin `fastapi-cloud-cli` { #without-fastapi-cloud-cli }\n\nSi quieres instalar FastAPI con las dependencias standard pero sin `fastapi-cloud-cli`, puedes instalar con `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n### Dependencias Opcionales Adicionales { #additional-optional-dependencies }\n\nExisten algunas dependencias adicionales que podrías querer instalar.\n\nDependencias opcionales adicionales de Pydantic:\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - para la gestión de configuraciones.\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - para tipos extra para ser usados con Pydantic.\n\nDependencias opcionales adicionales de FastAPI:\n\n* [`orjson`](https://github.com/ijl/orjson) - Requerido si deseas usar `ORJSONResponse`.\n* [`ujson`](https://github.com/esnme/ultrajson) - Requerido si deseas usar `UJSONResponse`.\n\n## Licencia { #license }\n\nEste proyecto tiene licencia bajo los términos de la licencia MIT.\n"
  },
  {
    "path": "docs/es/docs/learn/index.md",
    "content": "# Aprende { #learn }\n\nAquí están las secciones introductorias y los tutoriales para aprender **FastAPI**.\n\nPodrías considerar esto un **libro**, un **curso**, la forma **oficial** y recomendada de aprender FastAPI. 😎\n"
  },
  {
    "path": "docs/es/docs/project-generation.md",
    "content": "# Plantilla Full Stack FastAPI { #full-stack-fastapi-template }\n\nLas plantillas, aunque normalmente vienen con una configuración específica, están diseñadas para ser flexibles y personalizables. Esto te permite modificarlas y adaptarlas a los requisitos de tu proyecto, haciéndolas un excelente punto de partida. 🏁\n\nPuedes usar esta plantilla para comenzar, ya que incluye gran parte de la configuración inicial, seguridad, base de datos y algunos endpoints de API ya hechos para ti.\n\nRepositorio de GitHub: [Plantilla Full Stack FastAPI](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## Plantilla Full Stack FastAPI - Stack de tecnología y funcionalidades { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/es) para la API del backend en Python.\n    - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para las interacciones con bases de datos SQL en Python (ORM).\n    - 🔍 [Pydantic](https://docs.pydantic.dev), utilizado por FastAPI, para la validación de datos y gestión de configuraciones.\n    - 💾 [PostgreSQL](https://www.postgresql.org) como base de datos SQL.\n- 🚀 [React](https://react.dev) para el frontend.\n    - 💃 Usando TypeScript, hooks, Vite, y otras partes de una stack moderna de frontend.\n    - 🎨 [Tailwind CSS](https://tailwindcss.com) y [shadcn/ui](https://ui.shadcn.com) para los componentes del frontend.\n    - 🤖 Un cliente de frontend generado automáticamente.\n    - 🧪 [Playwright](https://playwright.dev) para escribir pruebas End-to-End.\n    - 🦇 Soporte para modo oscuro.\n- 🐋 [Docker Compose](https://www.docker.com) para desarrollo y producción.\n- 🔒 Hashing seguro de contraseñas por defecto.\n- 🔑 Autenticación con tokens JWT.\n- 📫 Recuperación de contraseñas basada en email.\n- ✅ Pruebas con [Pytest](https://pytest.org).\n- 📞 [Traefik](https://traefik.io) como proxy inverso / load balancer.\n- 🚢 Instrucciones de despliegue usando Docker Compose, incluyendo cómo configurar un proxy Traefik frontend para manejar certificados HTTPS automáticos.\n- 🏭 CI (integración continua) y CD (despliegue continuo) basados en GitHub Actions.\n"
  },
  {
    "path": "docs/es/docs/python-types.md",
    "content": "# Introducción a Tipos en Python { #python-types-intro }\n\nPython tiene soporte para \"anotaciones de tipos\" opcionales (también llamadas \"type hints\").\n\nEstas **\"anotaciones de tipos\"** o type hints son una sintaxis especial que permite declarar el <dfn title=\"por ejemplo: str, int, float, bool\">tipo</dfn> de una variable.\n\nAl declarar tipos para tus variables, los editores y herramientas te pueden proporcionar un mejor soporte.\n\nEste es solo un **tutorial rápido / recordatorio** sobre las anotaciones de tipos en Python. Cubre solo lo mínimo necesario para usarlas con **FastAPI**... que en realidad es muy poco.\n\n**FastAPI** se basa completamente en estas anotaciones de tipos, dándole muchas ventajas y beneficios.\n\nPero incluso si nunca usas **FastAPI**, te beneficiaría aprender un poco sobre ellas.\n\n/// note | Nota\n\nSi eres un experto en Python, y ya sabes todo sobre las anotaciones de tipos, salta al siguiente capítulo.\n\n///\n\n## Motivación { #motivation }\n\nComencemos con un ejemplo simple:\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\nLlamar a este programa genera:\n\n```\nJohn Doe\n```\n\nLa función hace lo siguiente:\n\n* Toma un `first_name` y `last_name`.\n* Convierte la primera letra de cada uno a mayúsculas con `title()`.\n* <dfn title=\"Los une, como uno. Con el contenido de uno después del otro.\">Concatena</dfn> ambos con un espacio en el medio.\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### Edítalo { #edit-it }\n\nEs un programa muy simple.\n\nPero ahora imagina que lo escribieras desde cero.\n\nEn algún momento habrías empezado la definición de la función, tenías los parámetros listos...\n\nPero luego tienes que llamar \"ese método que convierte la primera letra a mayúscula\".\n\n¿Era `upper`? ¿Era `uppercase`? `first_uppercase`? `capitalize`?\n\nEntonces, pruebas con el amigo del viejo programador, el autocompletado del editor.\n\nEscribes el primer parámetro de la función, `first_name`, luego un punto (`.`) y luego presionas `Ctrl+Espacio` para activar el autocompletado.\n\nPero, tristemente, no obtienes nada útil:\n\n<img src=\"/img/python-types/image01.png\">\n\n### Añadir tipos { #add-types }\n\nModifiquemos una sola línea de la versión anterior.\n\nCambiaremos exactamente este fragmento, los parámetros de la función, de:\n\n```Python\n    first_name, last_name\n```\n\na:\n\n```Python\n    first_name: str, last_name: str\n```\n\nEso es todo.\n\nEsas son las \"anotaciones de tipos\":\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\nEso no es lo mismo que declarar valores por defecto como sería con:\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\nEs una cosa diferente.\n\nEstamos usando dos puntos (`:`), no igualdades (`=`).\n\nY agregar anotaciones de tipos normalmente no cambia lo que sucede de lo que ocurriría sin ellas.\n\nPero ahora, imagina que nuevamente estás en medio de la creación de esa función, pero con anotaciones de tipos.\n\nEn el mismo punto, intentas activar el autocompletado con `Ctrl+Espacio` y ves:\n\n<img src=\"/img/python-types/image02.png\">\n\nCon eso, puedes desplazarte, viendo las opciones, hasta que encuentres la que \"te suene\":\n\n<img src=\"/img/python-types/image03.png\">\n\n## Más motivación { #more-motivation }\n\nRevisa esta función, ya tiene anotaciones de tipos:\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\nPorque el editor conoce los tipos de las variables, no solo obtienes autocompletado, también obtienes chequeo de errores:\n\n<img src=\"/img/python-types/image04.png\">\n\nAhora sabes que debes corregirlo, convertir `age` a un string con `str(age)`:\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## Declaración de tipos { #declaring-types }\n\nAcabas de ver el lugar principal para declarar anotaciones de tipos. Como parámetros de función.\n\nEste también es el lugar principal donde los utilizarías con **FastAPI**.\n\n### Tipos simples { #simple-types }\n\nPuedes declarar todos los tipos estándar de Python, no solo `str`.\n\nPuedes usar, por ejemplo:\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### Módulo `typing` { #typing-module }\n\nPara algunos casos adicionales, podrías necesitar importar algunas cosas del módulo `typing` de la standard library, por ejemplo cuando quieres declarar que algo tiene \"cualquier tipo\", puedes usar `Any` de `typing`:\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### Tipos genéricos { #generic-types }\n\nAlgunos tipos pueden tomar \"parámetros de tipo\" entre corchetes, para definir sus tipos internos, por ejemplo una \"lista de strings\" se declararía `list[str]`.\n\nEstos tipos que pueden tomar parámetros de tipo se llaman **Tipos Genéricos** o **Genéricos**.\n\nPuedes usar los mismos tipos integrados como genéricos (con corchetes y tipos dentro):\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### Lista { #list }\n\nPor ejemplo, vamos a definir una variable para ser una `list` de `str`.\n\nDeclara la variable, con la misma sintaxis de dos puntos (`:`).\n\nComo tipo, pon `list`.\n\nComo la lista es un tipo que contiene algunos tipos internos, los pones entre corchetes:\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info | Información\n\nEsos tipos internos en los corchetes se denominan \"parámetros de tipo\".\n\nEn este caso, `str` es el parámetro de tipo pasado a `list`.\n\n///\n\nEso significa: \"la variable `items` es una `list`, y cada uno de los ítems en esta lista es un `str`\".\n\nAl hacer eso, tu editor puede proporcionar soporte incluso mientras procesa elementos de la lista:\n\n<img src=\"/img/python-types/image05.png\">\n\nSin tipos, eso es casi imposible de lograr.\n\nNota que la variable `item` es uno de los elementos en la lista `items`.\n\nY aún así, el editor sabe que es un `str` y proporciona soporte para eso.\n\n#### Tuple y Set { #tuple-and-set }\n\nHarías lo mismo para declarar `tuple`s y `set`s:\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\nEsto significa:\n\n* La variable `items_t` es un `tuple` con 3 ítems, un `int`, otro `int`, y un `str`.\n* La variable `items_s` es un `set`, y cada uno de sus ítems es del tipo `bytes`.\n\n#### Dict { #dict }\n\nPara definir un `dict`, pasas 2 parámetros de tipo, separados por comas.\n\nEl primer parámetro de tipo es para las claves del `dict`.\n\nEl segundo parámetro de tipo es para los valores del `dict`:\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\nEsto significa:\n\n* La variable `prices` es un `dict`:\n    * Las claves de este `dict` son del tipo `str` (digamos, el nombre de cada ítem).\n    * Los valores de este `dict` son del tipo `float` (digamos, el precio de cada ítem).\n\n#### Union { #union }\n\nPuedes declarar que una variable puede ser cualquiera de **varios tipos**, por ejemplo, un `int` o un `str`.\n\nPara definirlo usas la <dfn title='también llamado \"operador OR a nivel de bits\", pero ese significado no es relevante aquí'>barra vertical (`|`)</dfn> para separar ambos tipos.\n\nEsto se llama una \"unión\", porque la variable puede ser cualquiera en la unión de esos dos conjuntos de tipos.\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\nEsto significa que `item` podría ser un `int` o un `str`.\n\n#### Posiblemente `None` { #possibly-none }\n\nPuedes declarar que un valor podría tener un tipo, como `str`, pero que también podría ser `None`.\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\nUsar `str | None` en lugar de solo `str` te permitirá al editor ayudarte a detectar errores donde podrías estar asumiendo que un valor siempre es un `str`, cuando en realidad también podría ser `None`.\n\n### Clases como tipos { #classes-as-types }\n\nTambién puedes declarar una clase como el tipo de una variable.\n\nDigamos que tienes una clase `Person`, con un nombre:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\nLuego puedes declarar una variable para que sea de tipo `Person`:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\nY luego, nuevamente, obtienes todo el soporte del editor:\n\n<img src=\"/img/python-types/image06.png\">\n\nNota que esto significa \"`one_person` es una **instance** de la clase `Person`\".\n\nNo significa \"`one_person` es la **clase** llamada `Person`\".\n\n## Modelos Pydantic { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/) es un paquete de Python para realizar la validación de datos.\n\nDeclaras la \"forma\" de los datos como clases con atributos.\n\nY cada atributo tiene un tipo.\n\nEntonces creas un instance de esa clase con algunos valores y validará los valores, los convertirá al tipo adecuado (si es el caso) y te dará un objeto con todos los datos.\n\nY obtienes todo el soporte del editor con ese objeto resultante.\n\nUn ejemplo de la documentación oficial de Pydantic:\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info | Información\n\nPara saber más sobre [Pydantic, revisa su documentación](https://docs.pydantic.dev/).\n\n///\n\n**FastAPI** está completamente basado en Pydantic.\n\nVerás mucho más de todo esto en práctica en el [Tutorial - Guía del Usuario](tutorial/index.md).\n\n## Anotaciones de tipos con metadata { #type-hints-with-metadata-annotations }\n\nPython también tiene una funcionalidad que permite poner **<dfn title=\"Datos sobre los datos, en este caso, información sobre el tipo, por ejemplo, una descripción.\">metadata</dfn> adicional** en estas anotaciones de tipos usando `Annotated`.\n\nPuedes importar `Annotated` desde `typing`.\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nPython en sí no hace nada con este `Annotated`. Y para los editores y otras herramientas, el tipo sigue siendo `str`.\n\nPero puedes usar este espacio en `Annotated` para proporcionar a **FastAPI** metadata adicional sobre cómo quieres que se comporte tu aplicación.\n\nLo importante a recordar es que **el primer *parámetro de tipo*** que pasas a `Annotated` es el **tipo real**. El resto es solo metadata para otras herramientas.\n\nPor ahora, solo necesitas saber que `Annotated` existe, y que es Python estándar. 😎\n\nLuego verás lo **poderoso** que puede ser.\n\n/// tip | Consejo\n\nEl hecho de que esto sea **Python estándar** significa que seguirás obteniendo la **mejor experiencia de desarrollador posible** en tu editor, con las herramientas que usas para analizar y refactorizar tu código, etc. ✨\n\nY también que tu código será muy compatible con muchas otras herramientas y paquetes de Python. 🚀\n\n///\n\n## Anotaciones de tipos en **FastAPI** { #type-hints-in-fastapi }\n\n**FastAPI** aprovecha estas anotaciones de tipos para hacer varias cosas.\n\nCon **FastAPI** declaras parámetros con anotaciones de tipos y obtienes:\n\n* **Soporte del editor**.\n* **Chequeo de tipos**.\n\n...y **FastAPI** usa las mismas declaraciones para:\n\n* **Definir requerimientos**: de parámetros de path de la request, parámetros de query, headers, bodies, dependencias, etc.\n* **Convertir datos**: de la request al tipo requerido.\n* **Validar datos**: provenientes de cada request:\n    * Generando **errores automáticos** devueltos al cliente cuando los datos son inválidos.\n* **Documentar** la API usando OpenAPI:\n    * Que luego es usada por las interfaces de documentación interactiva automática.\n\nTodo esto puede sonar abstracto. No te preocupes. Verás todo esto en acción en el [Tutorial - Guía del Usuario](tutorial/index.md).\n\nLo importante es que al usar tipos estándar de Python, en un solo lugar (en lugar de agregar más clases, decoradores, etc.), **FastAPI** hará gran parte del trabajo por ti.\n\n/// info | Información\n\nSi ya revisaste todo el tutorial y volviste para ver más sobre tipos, un buen recurso es [la \"cheat sheet\" de `mypy`](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html).\n\n///\n"
  },
  {
    "path": "docs/es/docs/resources/index.md",
    "content": "# Recursos { #resources }\n\nRecursos adicionales, enlaces externos y más. ✈️\n"
  },
  {
    "path": "docs/es/docs/translation-banner.md",
    "content": "/// details | 🌐 Traducción por IA y humanos\n\nEsta traducción fue hecha por IA guiada por humanos. 🤝\n\nPodría tener errores al interpretar el significado original, o sonar poco natural, etc. 🤖\n\nPuedes mejorar esta traducción [ayudándonos a guiar mejor al LLM de IA](https://fastapi.tiangolo.com/es/contributing/#translations).\n\n[Versión en inglés](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/es/docs/tutorial/background-tasks.md",
    "content": "# Tareas en Segundo Plano { #background-tasks }\n\nPuedes definir tareas en segundo plano para que se ejecuten *después* de devolver un response.\n\nEsto es útil para operaciones que necesitan ocurrir después de un request, pero para las que el cliente realmente no necesita esperar a que la operación termine antes de recibir el response.\n\nEsto incluye, por ejemplo:\n\n* Notificaciones por email enviadas después de realizar una acción:\n  * Como conectarse a un servidor de email y enviar un email tiende a ser \"lento\" (varios segundos), puedes devolver el response de inmediato y enviar la notificación por email en segundo plano.\n* Procesamiento de datos:\n  * Por ejemplo, supongamos que recibes un archivo que debe pasar por un proceso lento, puedes devolver un response de \"Accepted\" (HTTP 202) y procesar el archivo en segundo plano.\n\n## Usando `BackgroundTasks` { #using-backgroundtasks }\n\nPrimero, importa `BackgroundTasks` y define un parámetro en tu *path operation function* con una declaración de tipo de `BackgroundTasks`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI** creará el objeto de tipo `BackgroundTasks` por ti y lo pasará como ese parámetro.\n\n## Crear una función de tarea { #create-a-task-function }\n\nCrea una función para que se ejecute como la tarea en segundo plano.\n\nEs solo una función estándar que puede recibir parámetros.\n\nPuede ser una función `async def` o una función normal `def`, **FastAPI** sabrá cómo manejarla correctamente.\n\nEn este caso, la función de tarea escribirá en un archivo (simulando el envío de un email).\n\nY como la operación de escritura no usa `async` y `await`, definimos la función con un `def` normal:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## Agregar la tarea en segundo plano { #add-the-background-task }\n\nDentro de tu *path operation function*, pasa tu función de tarea al objeto de *background tasks* con el método `.add_task()`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()` recibe como argumentos:\n\n* Una función de tarea para ejecutar en segundo plano (`write_notification`).\n* Cualquier secuencia de argumentos que deba pasarse a la función de tarea en orden (`email`).\n* Cualquier argumento de palabras clave que deba pasarse a la función de tarea (`message=\"some notification\"`).\n\n## Inyección de Dependencias { #dependency-injection }\n\nUsar `BackgroundTasks` también funciona con el sistema de inyección de dependencias, puedes declarar un parámetro de tipo `BackgroundTasks` en varios niveles: en una *path operation function*, en una dependencia (dependable), en una sub-dependencia, etc.\n\n**FastAPI** sabe qué hacer en cada caso y cómo reutilizar el mismo objeto, de modo que todas las tareas en segundo plano se combinan y ejecutan en segundo plano después:\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\nEn este ejemplo, los mensajes se escribirán en el archivo `log.txt` *después* de que se envíe el response.\n\nSi hay un query en el request, se escribirá en el log en una tarea en segundo plano.\n\nY luego otra tarea en segundo plano generada en la *path operation function* escribirá un mensaje usando el parámetro de path `email`.\n\n## Detalles Técnicos { #technical-details }\n\nLa clase `BackgroundTasks` proviene directamente de [`starlette.background`](https://www.starlette.dev/background/).\n\nSe importa/incluye directamente en FastAPI para que puedas importarla desde `fastapi` y evitar importar accidentalmente la alternativa `BackgroundTask` (sin la `s` al final) de `starlette.background`.\n\nAl usar solo `BackgroundTasks` (y no `BackgroundTask`), es posible usarla como un parámetro de *path operation function* y dejar que **FastAPI** maneje el resto por ti, tal como cuando usas el objeto `Request` directamente.\n\nTodavía es posible usar `BackgroundTask` solo en FastAPI, pero debes crear el objeto en tu código y devolver una `Response` de Starlette incluyéndolo.\n\nPuedes ver más detalles en [la documentación oficial de Starlette sobre Background Tasks](https://www.starlette.dev/background/).\n\n## Advertencia { #caveat }\n\nSi necesitas realizar una computación intensa en segundo plano y no necesariamente necesitas que se ejecute por el mismo proceso (por ejemplo, no necesitas compartir memoria, variables, etc.), podrías beneficiarte del uso de otras herramientas más grandes como [Celery](https://docs.celeryq.dev).\n\nTienden a requerir configuraciones más complejas, un gestor de cola de mensajes/trabajos, como RabbitMQ o Redis, pero te permiten ejecutar tareas en segundo plano en múltiples procesos, y especialmente, en múltiples servidores.\n\nPero si necesitas acceder a variables y objetos de la misma app de **FastAPI**, o necesitas realizar pequeñas tareas en segundo plano (como enviar una notificación por email), simplemente puedes usar `BackgroundTasks`.\n\n## Resumen { #recap }\n\nImporta y usa `BackgroundTasks` con parámetros en *path operation functions* y dependencias para agregar tareas en segundo plano.\n"
  },
  {
    "path": "docs/es/docs/tutorial/bigger-applications.md",
    "content": "# Aplicaciones más grandes - Múltiples archivos { #bigger-applications-multiple-files }\n\nSi estás construyendo una aplicación o una API web, rara vez podrás poner todo en un solo archivo.\n\n**FastAPI** proporciona una herramienta conveniente para estructurar tu aplicación manteniendo toda la flexibilidad.\n\n/// info | Información\n\nSi vienes de Flask, esto sería el equivalente a los Blueprints de Flask.\n\n///\n\n## Un ejemplo de estructura de archivos { #an-example-file-structure }\n\nDigamos que tienes una estructura de archivos como esta:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | Consejo\n\nHay varios archivos `__init__.py`: uno en cada directorio o subdirectorio.\n\nEsto es lo que permite importar código de un archivo a otro.\n\nPor ejemplo, en `app/main.py` podrías tener una línea como:\n\n```\nfrom app.routers import items\n```\n\n///\n\n* El directorio `app` contiene todo. Y tiene un archivo vacío `app/__init__.py`, por lo que es un \"paquete de Python\" (una colección de \"módulos de Python\"): `app`.\n* Contiene un archivo `app/main.py`. Como está dentro de un paquete de Python (un directorio con un archivo `__init__.py`), es un \"módulo\" de ese paquete: `app.main`.\n* También hay un archivo `app/dependencies.py`, al igual que `app/main.py`, es un \"módulo\": `app.dependencies`.\n* Hay un subdirectorio `app/routers/` con otro archivo `__init__.py`, por lo que es un \"subpaquete de Python\": `app.routers`.\n* El archivo `app/routers/items.py` está dentro de un paquete, `app/routers/`, por lo que es un submódulo: `app.routers.items`.\n* Lo mismo con `app/routers/users.py`, es otro submódulo: `app.routers.users`.\n* También hay un subdirectorio `app/internal/` con otro archivo `__init__.py`, por lo que es otro \"subpaquete de Python\": `app.internal`.\n* Y el archivo `app/internal/admin.py` es otro submódulo: `app.internal.admin`.\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\nLa misma estructura de archivos con comentarios:\n\n```bash\n.\n├── app                  # \"app\" es un paquete de Python\n│   ├── __init__.py      # este archivo hace que \"app\" sea un \"paquete de Python\"\n│   ├── main.py          # módulo \"main\", por ejemplo import app.main\n│   ├── dependencies.py  # módulo \"dependencies\", por ejemplo import app.dependencies\n│   └── routers          # \"routers\" es un \"subpaquete de Python\"\n│   │   ├── __init__.py  # hace que \"routers\" sea un \"subpaquete de Python\"\n│   │   ├── items.py     # submódulo \"items\", por ejemplo import app.routers.items\n│   │   └── users.py     # submódulo \"users\", por ejemplo import app.routers.users\n│   └── internal         # \"internal\" es un \"subpaquete de Python\"\n│       ├── __init__.py  # hace que \"internal\" sea un \"subpaquete de Python\"\n│       └── admin.py     # submódulo \"admin\", por ejemplo import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\nDigamos que el archivo dedicado solo a manejar usuarios es el submódulo en `/app/routers/users.py`.\n\nQuieres tener las *path operations* relacionadas con tus usuarios separadas del resto del código, para mantenerlo organizado.\n\nPero todavía es parte de la misma aplicación/web API de **FastAPI** (es parte del mismo \"paquete de Python\").\n\nPuedes crear las *path operations* para ese módulo usando `APIRouter`.\n\n### Importar `APIRouter` { #import-apirouter }\n\nLo importas y creas una \"instance\" de la misma manera que lo harías con la clase `FastAPI`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### *Path operations* con `APIRouter` { #path-operations-with-apirouter }\n\nY luego lo usas para declarar tus *path operations*.\n\nÚsalo de la misma manera que usarías la clase `FastAPI`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\nPuedes pensar en `APIRouter` como una clase \"mini `FastAPI`\".\n\nSe soportan todas las mismas opciones.\n\nTodos los mismos `parameters`, `responses`, `dependencies`, `tags`, etc.\n\n/// tip | Consejo\n\nEn este ejemplo, la variable se llama `router`, pero puedes nombrarla como quieras.\n\n///\n\nVamos a incluir este `APIRouter` en la aplicación principal de `FastAPI`, pero primero, revisemos las dependencias y otro `APIRouter`.\n\n## Dependencias { #dependencies }\n\nVemos que vamos a necesitar algunas dependencias usadas en varios lugares de la aplicación.\n\nAsí que las ponemos en su propio módulo `dependencies` (`app/dependencies.py`).\n\nAhora utilizaremos una dependencia simple para leer un header `X-Token` personalizado:\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | Consejo\n\nEstamos usando un header inventado para simplificar este ejemplo.\n\nPero en casos reales obtendrás mejores resultados usando las [utilidades de Seguridad](security/index.md) integradas.\n\n///\n\n## Otro módulo con `APIRouter` { #another-module-with-apirouter }\n\nDigamos que también tienes los endpoints dedicados a manejar \"items\" de tu aplicación en el módulo `app/routers/items.py`.\n\nTienes *path operations* para:\n\n* `/items/`\n* `/items/{item_id}`\n\nEs toda la misma estructura que con `app/routers/users.py`.\n\nPero queremos ser más inteligentes y simplificar un poco el código.\n\nSabemos que todas las *path operations* en este módulo tienen el mismo:\n\n* Prefijo de path: `/items`.\n* `tags`: (solo una etiqueta: `items`).\n* `responses` extra.\n* `dependencies`: todas necesitan esa dependencia `X-Token` que creamos.\n\nEntonces, en lugar de agregar todo eso a cada *path operation*, podemos agregarlo al `APIRouter`.\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\nComo el path de cada *path operation* tiene que empezar con `/`, como en:\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n...el prefijo no debe incluir un `/` final.\n\nAsí que, el prefijo en este caso es `/items`.\n\nTambién podemos agregar una lista de `tags` y `responses` extra que se aplicarán a todas las *path operations* incluidas en este router.\n\nY podemos agregar una lista de `dependencies` que se añadirá a todas las *path operations* en el router y se ejecutarán/solucionarán por cada request que les haga.\n\n/// tip | Consejo\n\nNota que, al igual que [dependencias en decoradores de *path operations*](dependencies/dependencies-in-path-operation-decorators.md), ningún valor será pasado a tu *path operation function*.\n\n///\n\nEl resultado final es que los paths de item son ahora:\n\n* `/items/`\n* `/items/{item_id}`\n\n...como pretendíamos.\n\n* Serán marcados con una lista de tags que contiene un solo string `\"items\"`.\n  * Estos \"tags\" son especialmente útiles para los sistemas de documentación interactiva automática (usando OpenAPI).\n* Todos incluirán las `responses` predefinidas.\n* Todas estas *path operations* tendrán la lista de `dependencies` evaluadas/ejecutadas antes de ellas.\n  * Si también declaras dependencias en una *path operation* específica, **también se ejecutarán**.\n  * Las dependencias del router se ejecutan primero, luego las [`dependencies` en el decorador](dependencies/dependencies-in-path-operation-decorators.md), y luego las dependencias de parámetros normales.\n  * También puedes agregar [dependencias de `Security` con `scopes`](../advanced/security/oauth2-scopes.md).\n\n/// tip | Consejo\n\nTener `dependencies` en el `APIRouter` puede ser usado, por ejemplo, para requerir autenticación para un grupo completo de *path operations*. Incluso si las dependencias no son añadidas individualmente a cada una de ellas.\n\n///\n\n/// check | Revisa\n\nLos parámetros `prefix`, `tags`, `responses`, y `dependencies` son (como en muchos otros casos) solo una funcionalidad de **FastAPI** para ayudarte a evitar la duplicación de código.\n\n///\n\n### Importar las dependencias { #import-the-dependencies }\n\nEste código vive en el módulo `app.routers.items`, el archivo `app/routers/items.py`.\n\nY necesitamos obtener la función de dependencia del módulo `app.dependencies`, el archivo `app/dependencies.py`.\n\nAsí que usamos un import relativo con `..` para las dependencias:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### Cómo funcionan los imports relativos { #how-relative-imports-work }\n\n/// tip | Consejo\n\nSi sabes perfectamente cómo funcionan los imports, continúa a la siguiente sección abajo.\n\n///\n\nUn solo punto `.`, como en:\n\n```Python\nfrom .dependencies import get_token_header\n```\n\nsignificaría:\n\n* Partiendo en el mismo paquete en el que este módulo (el archivo `app/routers/items.py`) habita (el directorio `app/routers/`)...\n* busca el módulo `dependencies` (un archivo imaginario en `app/routers/dependencies.py`)...\n* y de él, importa la función `get_token_header`.\n\nPero ese archivo no existe, nuestras dependencias están en un archivo en `app/dependencies.py`.\n\nRecuerda cómo se ve nuestra estructura de aplicación/archivo:\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\nLos dos puntos `..`, como en:\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\nsignifican:\n\n* Partiendo en el mismo paquete en el que este módulo (el archivo `app/routers/items.py`) habita (el directorio `app/routers/`)...\n* ve al paquete padre (el directorio `app/`)...\n* y allí, busca el módulo `dependencies` (el archivo en `app/dependencies.py`)...\n* y de él, importa la función `get_token_header`.\n\n¡Eso funciona correctamente! 🎉\n\n---\n\nDe la misma manera, si hubiéramos usado tres puntos `...`, como en:\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\neso significaría:\n\n* Partiendo en el mismo paquete en el que este módulo (el archivo `app/routers/items.py`) habita (el directorio `app/routers/`)...\n* ve al paquete padre (el directorio `app/`)...\n* luego ve al paquete padre de ese paquete (no hay paquete padre, `app` es el nivel superior 😱)...\n* y allí, busca el módulo `dependencies` (el archivo en `app/dependencies.py`)...\n* y de él, importa la función `get_token_header`.\n\nEso se referiría a algún paquete arriba de `app/`, con su propio archivo `__init__.py`, etc. Pero no tenemos eso. Así que, eso lanzaría un error en nuestro ejemplo. 🚨\n\nPero ahora sabes cómo funciona, para que puedas usar imports relativos en tus propias apps sin importar cuán complejas sean. 🤓\n\n### Agregar algunos `tags`, `responses`, y `dependencies` personalizados { #add-some-custom-tags-responses-and-dependencies }\n\nNo estamos agregando el prefijo `/items` ni los `tags=[\"items\"]` a cada *path operation* porque los hemos añadido al `APIRouter`.\n\nPero aún podemos agregar _más_ `tags` que se aplicarán a una *path operation* específica, y también algunas `responses` extra específicas para esa *path operation*:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | Consejo\n\nEsta última path operation tendrá la combinación de tags: `[\"items\", \"custom\"]`.\n\nY también tendrá ambas responses en la documentación, una para `404` y otra para `403`.\n\n///\n\n## El `FastAPI` principal { #the-main-fastapi }\n\nAhora, veamos el módulo en `app/main.py`.\n\nAquí es donde importas y usas la clase `FastAPI`.\n\nEste será el archivo principal en tu aplicación que conecta todo.\n\nY como la mayor parte de tu lógica ahora vivirá en su propio módulo específico, el archivo principal será bastante simple.\n\n### Importar `FastAPI` { #import-fastapi }\n\nImportas y creas una clase `FastAPI` como normalmente.\n\nY podemos incluso declarar [dependencias globales](dependencies/global-dependencies.md) que se combinarán con las dependencias para cada `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### Importar el `APIRouter` { #import-the-apirouter }\n\nAhora importamos los otros submódulos que tienen `APIRouter`s:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\nComo los archivos `app/routers/users.py` y `app/routers/items.py` son submódulos que son parte del mismo paquete de Python `app`, podemos usar un solo punto `.` para importarlos usando \"imports relativos\".\n\n### Cómo funciona la importación { #how-the-importing-works }\n\nLa sección:\n\n```Python\nfrom .routers import items, users\n```\n\nsignifica:\n\n* Partiendo en el mismo paquete en el que este módulo (el archivo `app/main.py`) habita (el directorio `app/`)...\n* busca el subpaquete `routers` (el directorio en `app/routers/`)...\n* y de él, importa el submódulo `items` (el archivo en `app/routers/items.py`) y `users` (el archivo en `app/routers/users.py`)...\n\nEl módulo `items` tendrá una variable `router` (`items.router`). Este es el mismo que creamos en el archivo `app/routers/items.py`, es un objeto `APIRouter`.\n\nY luego hacemos lo mismo para el módulo `users`.\n\nTambién podríamos importarlos así:\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info | Información\n\nLa primera versión es un \"import relativo\":\n\n```Python\nfrom .routers import items, users\n```\n\nLa segunda versión es un \"import absoluto\":\n\n```Python\nfrom app.routers import items, users\n```\n\nPara aprender más sobre Paquetes y Módulos de Python, lee [la documentación oficial de Python sobre Módulos](https://docs.python.org/3/tutorial/modules.html).\n\n///\n\n### Evitar colisiones de nombres { #avoid-name-collisions }\n\nEstamos importando el submódulo `items` directamente, en lugar de importar solo su variable `router`.\n\nEsto se debe a que también tenemos otra variable llamada `router` en el submódulo `users`.\n\nSi hubiéramos importado uno después del otro, como:\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\nel `router` de `users` sobrescribiría el de `items` y no podríamos usarlos al mismo tiempo.\n\nAsí que, para poder usar ambos en el mismo archivo, importamos los submódulos directamente:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### Incluir los `APIRouter`s para `users` y `items` { #include-the-apirouters-for-users-and-items }\n\nAhora, incluyamos los `router`s de los submódulos `users` y `items`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info | Información\n\n`users.router` contiene el `APIRouter` dentro del archivo `app/routers/users.py`.\n\nY `items.router` contiene el `APIRouter` dentro del archivo `app/routers/items.py`.\n\n///\n\nCon `app.include_router()` podemos agregar cada `APIRouter` a la aplicación principal de `FastAPI`.\n\nIncluirá todas las rutas de ese router como parte de ella.\n\n/// note | Detalles Técnicos\n\nEn realidad creará internamente una *path operation* para cada *path operation* que fue declarada en el `APIRouter`.\n\nAsí, detrás de escena, funcionará como si todo fuera la misma única app.\n\n///\n\n/// check | Revisa\n\nNo tienes que preocuparte por el rendimiento al incluir routers.\n\nEsto tomará microsegundos y solo sucederá al inicio.\n\nAsí que no afectará el rendimiento. ⚡\n\n///\n\n### Incluir un `APIRouter` con un `prefix`, `tags`, `responses`, y `dependencies` personalizados { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\nAhora, imaginemos que tu organización te dio el archivo `app/internal/admin.py`.\n\nContiene un `APIRouter` con algunas *path operations* de administración que tu organización comparte entre varios proyectos.\n\nPara este ejemplo será súper simple. Pero digamos que porque está compartido con otros proyectos en la organización, no podemos modificarlo y agregar un `prefix`, `dependencies`, `tags`, etc. directamente al `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nPero aún queremos configurar un `prefix` personalizado al incluir el `APIRouter` para que todas sus *path operations* comiencen con `/admin`, queremos asegurarlo con las `dependencies` que ya tenemos para este proyecto, y queremos incluir `tags` y `responses`.\n\nPodemos declarar todo eso sin tener que modificar el `APIRouter` original pasando esos parámetros a `app.include_router()`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\nDe esa manera, el `APIRouter` original permanecerá sin modificar, por lo que aún podemos compartir ese mismo archivo `app/internal/admin.py` con otros proyectos en la organización.\n\nEl resultado es que, en nuestra app, cada una de las *path operations* del módulo `admin` tendrá:\n\n* El prefix `/admin`.\n* El tag `admin`.\n* La dependencia `get_token_header`.\n* La response `418`. 🍵\n\nPero eso solo afectará a ese `APIRouter` en nuestra app, no en ningún otro código que lo utilice.\n\nAsí, por ejemplo, otros proyectos podrían usar el mismo `APIRouter` con un método de autenticación diferente.\n\n### Incluir una *path operation* { #include-a-path-operation }\n\nTambién podemos agregar *path operations* directamente a la app de `FastAPI`.\n\nAquí lo hacemos... solo para mostrar que podemos 🤷:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\ny funcionará correctamente, junto con todas las otras *path operations* añadidas con `app.include_router()`.\n\n/// info | Detalles Muy Técnicos\n\n**Nota**: este es un detalle muy técnico que probablemente puedes **simplemente omitir**.\n\n---\n\nLos `APIRouter`s no están \"montados\", no están aislados del resto de la aplicación.\n\nEsto se debe a que queremos incluir sus *path operations* en el esquema de OpenAPI y las interfaces de usuario.\n\nComo no podemos simplemente aislarlos y \"montarlos\" independientemente del resto, las *path operations* se \"clonan\" (se vuelven a crear), no se incluyen directamente.\n\n///\n\n## Configurar el `entrypoint` en `pyproject.toml` { #configure-the-entrypoint-in-pyproject-toml }\n\nComo tu objeto `app` de FastAPI vive en `app/main.py`, puedes configurar el `entrypoint` en tu archivo `pyproject.toml` así:\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\nque es equivalente a importar como:\n\n```python\nfrom app.main import app\n```\n\nDe esa manera el comando `fastapi` sabrá dónde encontrar tu app.\n\n/// Note | Nota\n\nTambién podrías pasar la ruta al comando, como:\n\n```console\n$ fastapi dev app/main.py\n```\n\nPero tendrías que recordar pasar la ruta correcta cada vez que llames al comando `fastapi`.\n\nAdemás, otras herramientas podrían no ser capaces de encontrarla, por ejemplo la [Extensión de VS Code](../editor-support.md) o [FastAPI Cloud](https://fastapicloud.com), así que se recomienda usar el `entrypoint` en `pyproject.toml`.\n\n///\n\n## Revisa la documentación automática de la API { #check-the-automatic-api-docs }\n\nAhora, ejecuta tu app:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nY abre la documentación en [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVerás la documentación automática de la API, incluyendo los paths de todos los submódulos, usando los paths correctos (y prefijos) y los tags correctos:\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## Incluir el mismo router múltiples veces con diferentes `prefix` { #include-the-same-router-multiple-times-with-different-prefix }\n\nTambién puedes usar `.include_router()` múltiples veces con el *mismo* router usando diferentes prefijos.\n\nEsto podría ser útil, por ejemplo, para exponer la misma API bajo diferentes prefijos, por ejemplo, `/api/v1` y `/api/latest`.\n\nEste es un uso avanzado que quizás no necesites realmente, pero está allí en caso de que lo necesites.\n\n## Incluir un `APIRouter` en otro { #include-an-apirouter-in-another }\n\nDe la misma manera que puedes incluir un `APIRouter` en una aplicación `FastAPI`, puedes incluir un `APIRouter` en otro `APIRouter` usando:\n\n```Python\nrouter.include_router(other_router)\n```\n\nAsegúrate de hacerlo antes de incluir `router` en la app de `FastAPI`, para que las *path operations* de `other_router` también se incluyan.\n"
  },
  {
    "path": "docs/es/docs/tutorial/body-fields.md",
    "content": "# Body - Campos { #body-fields }\n\nDe la misma manera que puedes declarar validaciones adicionales y metadatos en los parámetros de las *path operation function* con `Query`, `Path` y `Body`, puedes declarar validaciones y metadatos dentro de los modelos de Pydantic usando `Field` de Pydantic.\n\n## Importar `Field` { #import-field }\n\nPrimero, tienes que importarlo:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n/// warning | Advertencia\n\nFíjate que `Field` se importa directamente desde `pydantic`, no desde `fastapi` como el resto (`Query`, `Path`, `Body`, etc).\n\n///\n\n## Declarar atributos del modelo { #declare-model-attributes }\n\nDespués puedes utilizar `Field` con los atributos del modelo:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field` funciona de la misma manera que `Query`, `Path` y `Body`, tiene todos los mismos parámetros, etc.\n\n/// note | Detalles técnicos\n\nEn realidad, `Query`, `Path` y otros que verás a continuación crean objetos de subclases de una clase común `Param`, que es a su vez una subclase de la clase `FieldInfo` de Pydantic.\n\nY `Field` de Pydantic también regresa una instance de `FieldInfo`.\n\n`Body` también devuelve objetos de una subclase de `FieldInfo` directamente. Y hay otros que verás más adelante que son subclases de la clase `Body`.\n\nRecuerda que cuando importas `Query`, `Path`, y otros desde `fastapi`, en realidad son funciones que devuelven clases especiales.\n\n///\n\n/// tip | Consejo\n\nObserva cómo cada atributo del modelo con un tipo, un valor por defecto y `Field` tiene la misma estructura que un parámetro de una *path operation function*, con `Field` en lugar de `Path`, `Query` y `Body`.\n\n///\n\n## Agregar información extra { #add-extra-information }\n\nPuedes declarar información extra en `Field`, `Query`, `Body`, etc. Y será incluida en el JSON Schema generado.\n\nAprenderás más sobre cómo agregar información extra más adelante en la documentación, cuando aprendamos a declarar ejemplos.\n\n/// warning | Advertencia\n\nLas claves extra pasadas a `Field` también estarán presentes en el esquema de OpenAPI resultante para tu aplicación.\nComo estas claves no necesariamente tienen que ser parte de la especificación de OpenAPI, algunas herramientas de OpenAPI, por ejemplo [el validador de OpenAPI](https://validator.swagger.io/), podrían no funcionar con tu esquema generado.\n\n///\n\n## Resumen { #recap }\n\nPuedes utilizar `Field` de Pydantic para declarar validaciones adicionales y metadatos para los atributos del modelo.\n\nTambién puedes usar los argumentos de palabra clave extra para pasar metadatos adicionales del JSON Schema.\n"
  },
  {
    "path": "docs/es/docs/tutorial/body-multiple-params.md",
    "content": "# Cuerpo - Múltiples Parámetros { #body-multiple-parameters }\n\nAhora que hemos visto cómo usar `Path` y `Query`, veamos usos más avanzados de las declaraciones del request body.\n\n## Mezclar `Path`, `Query` y parámetros del cuerpo { #mix-path-query-and-body-parameters }\n\nPrimero, por supuesto, puedes mezclar las declaraciones de parámetros de `Path`, `Query` y del request body libremente y **FastAPI** sabrá qué hacer.\n\nY también puedes declarar parámetros del cuerpo como opcionales, estableciendo el valor por defecto a `None`:\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | Nota\n\nTen en cuenta que, en este caso, el `item` que se tomaría del cuerpo es opcional. Ya que tiene un valor por defecto de `None`.\n\n///\n\n## Múltiples parámetros del cuerpo { #multiple-body-parameters }\n\nEn el ejemplo anterior, las *path operations* esperarían un cuerpo JSON con los atributos de un `Item`, como:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\nPero también puedes declarar múltiples parámetros del cuerpo, por ejemplo `item` y `user`:\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\nEn este caso, **FastAPI** notará que hay más de un parámetro del cuerpo en la función (hay dos parámetros que son modelos de Pydantic).\n\nEntonces, usará los nombres de los parámetros como claves (nombres de campo) en el cuerpo, y esperará un cuerpo como:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | Nota\n\nTen en cuenta que aunque el `item` se declaró de la misma manera que antes, ahora se espera que esté dentro del cuerpo con una clave `item`.\n\n///\n\n**FastAPI** hará la conversión automática del request, de modo que el parámetro `item` reciba su contenido específico y lo mismo para `user`.\n\nRealizará la validación de los datos compuestos, y los documentará así para el esquema de OpenAPI y la documentación automática.\n\n## Valores singulares en el cuerpo { #singular-values-in-body }\n\nDe la misma manera que hay un `Query` y `Path` para definir datos extra para parámetros de query y path, **FastAPI** proporciona un equivalente `Body`.\n\nPor ejemplo, ampliando el modelo anterior, podrías decidir que deseas tener otra clave `importance` en el mismo cuerpo, además de `item` y `user`.\n\nSi lo declaras tal cual, debido a que es un valor singular, **FastAPI** asumirá que es un parámetro de query.\n\nPero puedes instruir a **FastAPI** para que lo trate como otra clave del cuerpo usando `Body`:\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\nEn este caso, **FastAPI** esperará un cuerpo como:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\nNuevamente, convertirá los tipos de datos, validará, documentará, etc.\n\n## Múltiples parámetros de cuerpo y query { #multiple-body-params-and-query }\n\nPor supuesto, también puedes declarar parámetros adicionales de query siempre que lo necesites, además de cualquier parámetro del cuerpo.\n\nComo, por defecto, los valores singulares se interpretan como parámetros de query, no tienes que añadir explícitamente un `Query`, solo puedes hacer:\n\n```Python\nq: str | None = None\n```\n\nPor ejemplo:\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n/// info | Información\n\n`Body` también tiene todos los mismos parámetros de validación y metadatos extras que `Query`, `Path` y otros que verás luego.\n\n///\n\n## Embeber un solo parámetro de cuerpo { #embed-a-single-body-parameter }\n\nSupongamos que solo tienes un único parámetro de cuerpo `item` de un modelo Pydantic `Item`.\n\nPor defecto, **FastAPI** esperará su cuerpo directamente.\n\nPero si deseas que espere un JSON con una clave `item` y dentro de ella los contenidos del modelo, como lo hace cuando declaras parámetros de cuerpo extra, puedes usar el parámetro especial `Body` `embed`:\n\n```Python\nitem: Item = Body(embed=True)\n```\n\ncomo en:\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\nEn este caso, **FastAPI** esperará un cuerpo como:\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\nen lugar de:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## Resumen { #recap }\n\nPuedes añadir múltiples parámetros de cuerpo a tu *path operation function*, aunque un request solo puede tener un único cuerpo.\n\nPero **FastAPI** lo manejará, te dará los datos correctos en tu función, y validará y documentará el esquema correcto en la *path operation*.\n\nTambién puedes declarar valores singulares para ser recibidos como parte del cuerpo.\n\nY puedes instruir a **FastAPI** para embeber el cuerpo en una clave incluso cuando solo hay un único parámetro declarado.\n"
  },
  {
    "path": "docs/es/docs/tutorial/body-nested-models.md",
    "content": "# Cuerpo - Modelos Anidados { #body-nested-models }\n\nCon **FastAPI**, puedes definir, validar, documentar y usar modelos profundamente anidados de manera arbitraria (gracias a Pydantic).\n\n## Campos de lista { #list-fields }\n\nPuedes definir un atributo como un subtipo. Por ejemplo, una `list` en Python:\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\nEsto hará que `tags` sea una lista, aunque no declare el tipo de los elementos de la lista.\n\n## Campos de lista con parámetro de tipo { #list-fields-with-type-parameter }\n\nPero Python tiene una forma específica de declarar listas con tipos internos, o \"parámetros de tipo\":\n\n### Declarar una `list` con un parámetro de tipo { #declare-a-list-with-a-type-parameter }\n\nPara declarar tipos que tienen parámetros de tipo (tipos internos), como `list`, `dict`, `tuple`,\npasa el/los tipo(s) interno(s) como \"parámetros de tipo\" usando corchetes: `[` y `]`\n\n```Python\nmy_list: list[str]\n```\n\nEso es toda la sintaxis estándar de Python para declaraciones de tipo.\n\nUsa esa misma sintaxis estándar para atributos de modelos con tipos internos.\n\nAsí, en nuestro ejemplo, podemos hacer que `tags` sea específicamente una \"lista de strings\":\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## Tipos de conjunto { #set-types }\n\nPero luego pensamos en ello, y nos damos cuenta de que los tags no deberían repetirse, probablemente serían strings únicos.\n\nY Python tiene un tipo de datos especial para conjuntos de elementos únicos, el `set`.\n\nEntonces podemos declarar `tags` como un conjunto de strings:\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\nCon esto, incluso si recibes un request con datos duplicados, se convertirá en un conjunto de elementos únicos.\n\nY siempre que emitas esos datos, incluso si la fuente tenía duplicados, se emitirá como un conjunto de elementos únicos.\n\nY también se anotará/documentará en consecuencia.\n\n## Modelos Anidados { #nested-models }\n\nCada atributo de un modelo Pydantic tiene un tipo.\n\nPero ese tipo puede ser en sí mismo otro modelo Pydantic.\n\nAsí que, puedes declarar \"objetos\" JSON anidados profundamente con nombres de atributos específicos, tipos y validaciones.\n\nTodo eso, de manera arbitraria.\n\n### Definir un submodelo { #define-a-submodel }\n\nPor ejemplo, podemos definir un modelo `Image`:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### Usar el submodelo como tipo { #use-the-submodel-as-a-type }\n\nY luego podemos usarlo como el tipo de un atributo:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\nEsto significaría que **FastAPI** esperaría un cuerpo similar a:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\nNuevamente, haciendo solo esa declaración, con **FastAPI** obtienes:\n\n* Soporte de editor (autocompletado, etc.), incluso para modelos anidados\n* Conversión de datos\n* Validación de datos\n* Documentación automática\n\n## Tipos especiales y validación { #special-types-and-validation }\n\nAdemás de tipos singulares normales como `str`, `int`, `float`, etc., puedes usar tipos singulares más complejos que heredan de `str`.\n\nPara ver todas las opciones que tienes, Revisa [Resumen de tipos de Pydantic](https://docs.pydantic.dev/latest/concepts/types/). Verás algunos ejemplos en el siguiente capítulo.\n\nPor ejemplo, como en el modelo `Image` tenemos un campo `url`, podemos declararlo como una instance de `HttpUrl` de Pydantic en lugar de un `str`:\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\nEl string será verificado para ser una URL válida, y documentado en JSON Schema / OpenAPI como tal.\n\n## Atributos con listas de submodelos { #attributes-with-lists-of-submodels }\n\nTambién puedes usar modelos Pydantic como subtipos de `list`, `set`, etc.:\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\nEsto esperará (convertirá, validará, documentará, etc.) un cuerpo JSON como:\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info | Información\n\nNota cómo la clave `images` ahora tiene una lista de objetos de imagen.\n\n///\n\n## Modelos anidados profundamente { #deeply-nested-models }\n\nPuedes definir modelos anidados tan profundamente como desees:\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info | Información\n\nObserva cómo `Offer` tiene una lista de `Item`s, que a su vez tienen una lista opcional de `Image`s\n\n///\n\n## Cuerpos de listas puras { #bodies-of-pure-lists }\n\nSi el valor superior del cuerpo JSON que esperas es un `array` JSON (una `list` en Python), puedes declarar el tipo en el parámetro de la función, al igual que en los modelos Pydantic:\n\n```Python\nimages: list[Image]\n```\n\ncomo en:\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## Soporte de editor en todas partes { #editor-support-everywhere }\n\nY obtienes soporte de editor en todas partes.\n\nIncluso para elementos dentro de listas:\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\nNo podrías obtener este tipo de soporte de editor si estuvieras trabajando directamente con `dict` en lugar de modelos Pydantic.\n\nPero tampoco tienes que preocuparte por ellos, los `dicts` entrantes se convierten automáticamente y tu salida se convierte automáticamente a JSON también.\n\n## Cuerpos de `dict`s arbitrarios { #bodies-of-arbitrary-dicts }\n\nTambién puedes declarar un cuerpo como un `dict` con claves de algún tipo y valores de algún otro tipo.\n\nDe esta manera, no tienes que saber de antemano cuáles son los nombres válidos de campo/atributo (como sería el caso con modelos Pydantic).\n\nEsto sería útil si deseas recibir claves que aún no conoces.\n\n---\n\nOtro caso útil es cuando deseas tener claves de otro tipo (por ejemplo, `int`).\n\nEso es lo que vamos a ver aquí.\n\nEn este caso, aceptarías cualquier `dict` siempre que tenga claves `int` con valores `float`:\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip | Consejo\n\nTen en cuenta que JSON solo admite `str` como claves.\n\nPero Pydantic tiene conversión automática de datos.\n\nEsto significa que, aunque tus clientes de API solo pueden enviar strings como claves, mientras esos strings contengan enteros puros, Pydantic los convertirá y validará.\n\nY el `dict` que recibas como `weights` tendrá realmente claves `int` y valores `float`.\n\n///\n\n## Resumen { #recap }\n\nCon **FastAPI** tienes la máxima flexibilidad proporcionada por los modelos Pydantic, manteniendo tu código simple, corto y elegante.\n\nPero con todos los beneficios:\n\n* Soporte de editor (¡autocompletado en todas partes!)\n* Conversión de datos (también conocido como parsing/serialización)\n* Validación de datos\n* Documentación del esquema\n* Documentación automática\n"
  },
  {
    "path": "docs/es/docs/tutorial/body-updates.md",
    "content": "# Body - Actualizaciones { #body-updates }\n\n## Actualización reemplazando con `PUT` { #update-replacing-with-put }\n\nPara actualizar un ítem puedes utilizar la operación de [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT).\n\nPuedes usar el `jsonable_encoder` para convertir los datos de entrada en datos que se puedan almacenar como JSON (por ejemplo, con una base de datos NoSQL). Por ejemplo, convirtiendo `datetime` a `str`.\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT` se usa para recibir datos que deben reemplazar los datos existentes.\n\n### Advertencia sobre el reemplazo { #warning-about-replacing }\n\nEsto significa que si quieres actualizar el ítem `bar` usando `PUT` con un body que contenga:\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\ndebido a que no incluye el atributo ya almacenado `\"tax\": 20.2`, el modelo de entrada tomaría el valor por defecto de `\"tax\": 10.5`.\n\nY los datos se guardarían con ese \"nuevo\" `tax` de `10.5`.\n\n## Actualizaciones parciales con `PATCH` { #partial-updates-with-patch }\n\nTambién puedes usar la operación de [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) para actualizar *parcialmente* datos.\n\nEsto significa que puedes enviar solo los datos que deseas actualizar, dejando el resto intacto.\n\n/// note | Nota\n\n`PATCH` es menos usado y conocido que `PUT`.\n\nY muchos equipos utilizan solo `PUT`, incluso para actualizaciones parciales.\n\nEres **libre** de usarlos como desees, **FastAPI** no impone ninguna restricción.\n\nPero esta guía te muestra, más o menos, cómo se pretende que se usen.\n\n///\n\n### Uso del parámetro `exclude_unset` de Pydantic { #using-pydantics-exclude-unset-parameter }\n\nSi quieres recibir actualizaciones parciales, es muy útil usar el parámetro `exclude_unset` en el `.model_dump()` del modelo de Pydantic.\n\nComo `item.model_dump(exclude_unset=True)`.\n\nEso generaría un `dict` solo con los datos que se establecieron al crear el modelo `item`, excluyendo los valores por defecto.\n\nLuego puedes usar esto para generar un `dict` solo con los datos que se establecieron (enviados en el request), omitiendo los valores por defecto:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### Uso del parámetro `update` de Pydantic { #using-pydantics-update-parameter }\n\nAhora, puedes crear una copia del modelo existente usando `.model_copy()`, y pasar el parámetro `update` con un `dict` que contenga los datos a actualizar.\n\nComo `stored_item_model.model_copy(update=update_data)`:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### Resumen de actualizaciones parciales { #partial-updates-recap }\n\nEn resumen, para aplicar actualizaciones parciales deberías:\n\n* (Opcionalmente) usar `PATCH` en lugar de `PUT`.\n* Recuperar los datos almacenados.\n* Poner esos datos en un modelo de Pydantic.\n* Generar un `dict` sin valores por defecto del modelo de entrada (usando `exclude_unset`).\n    * De esta manera puedes actualizar solo los valores realmente establecidos por el usuario, en lugar de sobrescribir valores ya almacenados con valores por defecto en tu modelo.\n* Crear una copia del modelo almacenado, actualizando sus atributos con las actualizaciones parciales recibidas (usando el parámetro `update`).\n* Convertir el modelo copiado en algo que pueda almacenarse en tu DB (por ejemplo, usando el `jsonable_encoder`).\n    * Esto es comparable a usar el método `.model_dump()` del modelo de nuevo, pero asegura (y convierte) los valores a tipos de datos que pueden convertirse a JSON, por ejemplo, `datetime` a `str`.\n* Guardar los datos en tu DB.\n* Devolver el modelo actualizado.\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | Consejo\n\nPuedes realmente usar esta misma técnica con una operación HTTP `PUT`.\n\nPero el ejemplo aquí usa `PATCH` porque fue creado para estos casos de uso.\n\n///\n\n/// note | Nota\n\nObserva que el modelo de entrada sigue siendo validado.\n\nEntonces, si deseas recibir actualizaciones parciales que puedan omitir todos los atributos, necesitas tener un modelo con todos los atributos marcados como opcionales (con valores por defecto o `None`).\n\nPara distinguir entre los modelos con todos los valores opcionales para **actualizaciones** y modelos con valores requeridos para **creación**, puedes utilizar las ideas descritas en [Modelos Extra](extra-models.md).\n\n///\n"
  },
  {
    "path": "docs/es/docs/tutorial/body.md",
    "content": "# Request Body { #request-body }\n\nCuando necesitas enviar datos desde un cliente (digamos, un navegador) a tu API, los envías como un **request body**.\n\nUn **request** body es un dato enviado por el cliente a tu API. Un **response** body es el dato que tu API envía al cliente.\n\nTu API casi siempre tiene que enviar un **response** body. Pero los clientes no necesariamente necesitan enviar **request bodies** todo el tiempo, a veces solo solicitan un path, quizás con algunos parámetros de query, pero no envían un body.\n\nPara declarar un **request** body, usas modelos de [Pydantic](https://docs.pydantic.dev/) con todo su poder y beneficios.\n\n/// info | Información\n\nPara enviar datos, deberías usar uno de estos métodos: `POST` (el más común), `PUT`, `DELETE` o `PATCH`.\n\nEnviar un body con un request `GET` tiene un comportamiento indefinido en las especificaciones, no obstante, es soportado por FastAPI, solo para casos de uso muy complejos/extremos.\n\nComo no se recomienda, la documentación interactiva con Swagger UI no mostrará la documentación para el body cuando se usa `GET`, y los proxies intermedios podrían no soportarlo.\n\n///\n\n## Importar `BaseModel` de Pydantic { #import-pydantics-basemodel }\n\nPrimero, necesitas importar `BaseModel` de `pydantic`:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## Crea tu modelo de datos { #create-your-data-model }\n\nLuego, declaras tu modelo de datos como una clase que hereda de `BaseModel`.\n\nUsa tipos estándar de Python para todos los atributos:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\n\nAl igual que al declarar parámetros de query, cuando un atributo del modelo tiene un valor por defecto, no es obligatorio. De lo contrario, es obligatorio. Usa `None` para hacerlo solo opcional.\n\nPor ejemplo, el modelo anterior declara un “`object`” JSON (o `dict` en Python) como:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n...dado que `description` y `tax` son opcionales (con un valor por defecto de `None`), este “`object`” JSON también sería válido:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## Decláralo como un parámetro { #declare-it-as-a-parameter }\n\nPara añadirlo a tu *path operation*, decláralo de la misma manera que declaraste parámetros de path y query:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n...y declara su tipo como el modelo que creaste, `Item`.\n\n## Resultados { #results }\n\nCon solo esa declaración de tipo en Python, **FastAPI** hará lo siguiente:\n\n* Leer el body del request como JSON.\n* Convertir los tipos correspondientes (si es necesario).\n* Validar los datos.\n    * Si los datos son inválidos, devolverá un error claro e indicado, señalando exactamente dónde y qué fue lo incorrecto.\n* Proporcionar los datos recibidos en el parámetro `item`.\n    * Como lo declaraste en la función como de tipo `Item`, también tendrás todo el soporte del editor (autocompletado, etc.) para todos los atributos y sus tipos.\n* Generar definiciones de [JSON Schema](https://json-schema.org) para tu modelo, que también puedes usar en cualquier otro lugar si tiene sentido para tu proyecto.\n* Esos esquemas serán parte del esquema de OpenAPI generado y usados por las <abbr title=\"User Interfaces - Interfaces de usuario\">UIs</abbr> de documentación automática.\n\n## Documentación automática { #automatic-docs }\n\nLos JSON Schemas de tus modelos serán parte del esquema OpenAPI generado y se mostrarán en la documentación API interactiva:\n\n<img src=\"/img/tutorial/body/image01.png\">\n\nY también se utilizarán en la documentación API dentro de cada *path operation* que los necesite:\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## Soporte del editor { #editor-support }\n\nEn tu editor, dentro de tu función, obtendrás anotaciones de tipos y autocompletado en todas partes (esto no sucedería si recibieras un `dict` en lugar de un modelo de Pydantic):\n\n<img src=\"/img/tutorial/body/image03.png\">\n\nTambién recibirás chequeos de errores para operaciones de tipo incorrecto:\n\n<img src=\"/img/tutorial/body/image04.png\">\n\nNo es por casualidad, todo el framework fue construido alrededor de ese diseño.\n\nY fue rigurosamente probado en la fase de diseño, antes de cualquier implementación, para garantizar que funcionaría con todos los editores.\n\nIncluso se hicieron algunos cambios en Pydantic para admitir esto.\n\nLas capturas de pantalla anteriores se tomaron con [Visual Studio Code](https://code.visualstudio.com).\n\nPero obtendrías el mismo soporte en el editor con [PyCharm](https://www.jetbrains.com/pycharm/) y la mayoría de los otros editores de Python:\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip | Consejo\n\nSi usas [PyCharm](https://www.jetbrains.com/pycharm/) como tu editor, puedes usar el [Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/).\n\nMejora el soporte del editor para modelos de Pydantic, con:\n\n* autocompletado\n* chequeo de tipos\n* refactorización\n* búsqueda\n* inspecciones\n\n///\n\n## Usa el modelo { #use-the-model }\n\nDentro de la función, puedes acceder a todos los atributos del objeto modelo directamente:\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## Request body + parámetros de path { #request-body-path-parameters }\n\nPuedes declarar parámetros de path y request body al mismo tiempo.\n\n**FastAPI** reconocerá que los parámetros de función que coinciden con los parámetros de path deben ser **tomados del path**, y que los parámetros de función que se declaran como modelos de Pydantic deben ser **tomados del request body**.\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n\n## Request body + path + parámetros de query { #request-body-path-query-parameters }\n\nTambién puedes declarar parámetros de **body**, **path** y **query**, todos al mismo tiempo.\n\n**FastAPI** reconocerá cada uno de ellos y tomará los datos del lugar correcto.\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\nLos parámetros de la función se reconocerán de la siguiente manera:\n\n* Si el parámetro también se declara en el **path**, se utilizará como un parámetro de path.\n* Si el parámetro es de un **tipo singular** (como `int`, `float`, `str`, `bool`, etc.), se interpretará como un parámetro de **query**.\n* Si el parámetro se declara como del tipo de un **modelo de Pydantic**, se interpretará como un **body** de request.\n\n/// note | Nota\n\nFastAPI sabrá que el valor de `q` no es requerido debido al valor por defecto `= None`.\n\nEl `str | None` no es utilizado por FastAPI para determinar que el valor no es requerido, sabrá que no es requerido porque tiene un valor por defecto de `= None`.\n\nPero agregar las anotaciones de tipos permitirá que tu editor te brinde un mejor soporte y detecte errores.\n\n///\n\n## Sin Pydantic { #without-pydantic }\n\nSi no quieres usar modelos de Pydantic, también puedes usar parámetros **Body**. Consulta la documentación para [Body - Múltiples parámetros: Valores singulares en el body](body-multiple-params.md#singular-values-in-body).\n"
  },
  {
    "path": "docs/es/docs/tutorial/cookie-param-models.md",
    "content": "# Modelos de Cookies { #cookie-parameter-models }\n\nSi tienes un grupo de **cookies** que están relacionadas, puedes crear un **modelo de Pydantic** para declararlas. 🍪\n\nEsto te permitirá **reutilizar el modelo** en **múltiples lugares** y también declarar validaciones y metadatos para todos los parámetros a la vez. 😎\n\n/// note | Nota\n\nEsto es compatible desde la versión `0.115.0` de FastAPI. 🤓\n\n///\n\n/// tip | Consejo\n\nEsta misma técnica se aplica a `Query`, `Cookie`, y `Header`. 😎\n\n///\n\n## Cookies con un Modelo de Pydantic { #cookies-with-a-pydantic-model }\n\nDeclara los parámetros de **cookie** que necesites en un **modelo de Pydantic**, y luego declara el parámetro como `Cookie`:\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI** **extraerá** los datos para **cada campo** de las **cookies** recibidas en el request y te entregará el modelo de Pydantic que definiste.\n\n## Revisa la Documentación { #check-the-docs }\n\nPuedes ver las cookies definidas en la UI de la documentación en `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info | Información\n\nTen en cuenta que, como los **navegadores manejan las cookies** de maneras especiales y detrás de escenas, **no** permiten fácilmente que **JavaScript** las toque.\n\nSi vas a la **UI de la documentación de la API** en `/docs` podrás ver la **documentación** de las cookies para tus *path operations*.\n\nPero incluso si **rellenas los datos** y haces clic en \"Execute\", como la UI de la documentación funciona con **JavaScript**, las cookies no serán enviadas y verás un **mensaje de error** como si no hubieras escrito ningún valor.\n\n///\n\n## Prohibir Cookies Extra { #forbid-extra-cookies }\n\nEn algunos casos de uso especiales (probablemente no muy comunes), podrías querer **restringir** las cookies que deseas recibir.\n\nTu API ahora tiene el poder de controlar su propio <dfn title=\"Esto es una broma, por si acaso. No tiene nada que ver con los consentimientos de cookies, pero es gracioso que incluso la API ahora pueda rechazar las pobres cookies. Toma una cookie. 🍪\">consentimiento de cookies</dfn>. 🤪🍪\n\nPuedes usar la configuración del modelo de Pydantic para `prohibir` cualquier campo `extra`:\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\nSi un cliente intenta enviar algunas **cookies extra**, recibirán un response de **error**.\n\nPobres banners de cookies con todo su esfuerzo para obtener tu consentimiento para que la <dfn title=\"Esta es otra broma. No me prestes atención. Toma un café para tu cookie. ☕\">API lo rechace</dfn>. 🍪\n\nPor ejemplo, si el cliente intenta enviar una cookie `santa_tracker` con un valor de `good-list-please`, el cliente recibirá un response de **error** que le informa que la `santa_tracker` <dfn title=\"Santa desaprueba la falta de cookies. 🎅 Está bien, no más bromas de cookies.\">cookie no está permitida</dfn>:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## Resumen { #summary }\n\nPuedes usar **modelos de Pydantic** para declarar <dfn title=\"Toma una última cookie antes de irte. 🍪\">**cookies**</dfn> en **FastAPI**. 😎\n"
  },
  {
    "path": "docs/es/docs/tutorial/cookie-params.md",
    "content": "# Parámetros de Cookie { #cookie-parameters }\n\nPuedes definir parámetros de Cookie de la misma manera que defines los parámetros `Query` y `Path`.\n\n## Importar `Cookie` { #import-cookie }\n\nPrimero importa `Cookie`:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## Declarar parámetros de `Cookie` { #declare-cookie-parameters }\n\nLuego declara los parámetros de cookie usando la misma estructura que con `Path` y `Query`.\n\nPuedes definir el valor por defecto así como toda la validación extra o los parámetros de anotación:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Detalles Técnicos\n\n`Cookie` es una clase \"hermana\" de `Path` y `Query`. También hereda de la misma clase común `Param`.\n\nPero recuerda que cuando importas `Query`, `Path`, `Cookie` y otros desde `fastapi`, en realidad son funciones que devuelven clases especiales.\n\n///\n\n/// info | Información\n\nPara declarar cookies, necesitas usar `Cookie`, porque de lo contrario los parámetros serían interpretados como parámetros de query.\n\n///\n\n/// info | Información\n\nTen en cuenta que, como **los navegadores manejan las cookies** de formas especiales y por detrás, **no** permiten fácilmente que **JavaScript** las toque.\n\nSi vas a la **UI de la documentación de la API** en `/docs` podrás ver la **documentación** de cookies para tus *path operations*.\n\nPero incluso si **rellenas los datos** y haces clic en \"Execute\", como la UI de la documentación funciona con **JavaScript**, las cookies no se enviarán y verás un mensaje de **error** como si no hubieras escrito ningún valor.\n\n///\n\n## Resumen { #recap }\n\nDeclara cookies con `Cookie`, usando el mismo patrón común que `Query` y `Path`.\n"
  },
  {
    "path": "docs/es/docs/tutorial/cors.md",
    "content": "# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }\n\n[CORS o \"Cross-Origin Resource Sharing\"](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) se refiere a situaciones en las que un frontend que se ejecuta en un navegador tiene código JavaScript que se comunica con un backend, y el backend está en un \"origen\" diferente al frontend.\n\n## Origen { #origin }\n\nUn origen es la combinación de protocolo (`http`, `https`), dominio (`myapp.com`, `localhost`, `localhost.tiangolo.com`) y puerto (`80`, `443`, `8080`).\n\nAsí que, todos estos son orígenes diferentes:\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\nAunque todos están en `localhost`, usan protocolos o puertos diferentes, por lo tanto, son \"orígenes\" diferentes.\n\n## Pasos { #steps }\n\nEntonces, digamos que tienes un frontend corriendo en tu navegador en `http://localhost:8080`, y su JavaScript está tratando de comunicarse con un backend corriendo en `http://localhost` (porque no especificamos un puerto, el navegador asumirá el puerto por defecto `80`).\n\nEntonces, el navegador enviará un request HTTP `OPTIONS` al backend `:80`, y si el backend envía los headers apropiados autorizando la comunicación desde este origen diferente (`http://localhost:8080`), entonces el navegador `:8080` permitirá que el JavaScript en el frontend envíe su request al backend `:80`.\n\nPara lograr esto, el backend `:80` debe tener una lista de \"orígenes permitidos\".\n\nEn este caso, la lista tendría que incluir `http://localhost:8080` para que el frontend `:8080` funcione correctamente.\n\n## Comodines { #wildcards }\n\nTambién es posible declarar la lista como `\"*\"` (un \"comodín\") para decir que todos están permitidos.\n\nPero eso solo permitirá ciertos tipos de comunicación, excluyendo todo lo que implique credenciales: Cookies, headers de autorización como los utilizados con Bearer Tokens, etc.\n\nAsí que, para que todo funcione correctamente, es mejor especificar explícitamente los orígenes permitidos.\n\n## Usa `CORSMiddleware` { #use-corsmiddleware }\n\nPuedes configurarlo en tu aplicación **FastAPI** usando el `CORSMiddleware`.\n\n* Importa `CORSMiddleware`.\n* Crea una lista de orígenes permitidos (como strings).\n* Agrégalo como un \"middleware\" a tu aplicación **FastAPI**.\n\nTambién puedes especificar si tu backend permite:\n\n* Credenciales (headers de autorización, cookies, etc).\n* Métodos HTTP específicos (`POST`, `PUT`) o todos ellos con el comodín `\"*\"`.\n* Headers HTTP específicos o todos ellos con el comodín `\"*\"`.\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\n\nLos parámetros predeterminados utilizados por la implementación de `CORSMiddleware` son restrictivos por defecto, por lo que necesitarás habilitar explícitamente orígenes, métodos o headers particulares para que los navegadores estén permitidos de usarlos en un contexto de Cross-Domain.\n\nSe admiten los siguientes argumentos:\n\n* `allow_origins` - Una lista de orígenes que deberían estar permitidos para hacer requests cross-origin. Por ejemplo, `['https://example.org', 'https://www.example.org']`. Puedes usar `['*']` para permitir cualquier origen.\n* `allow_origin_regex` - Una cadena regex para coincidir con orígenes que deberían estar permitidos para hacer requests cross-origin. por ejemplo, `'https://.*\\.example\\.org'`.\n* `allow_methods` - Una lista de métodos HTTP que deberían estar permitidos para requests cross-origin. Por defecto es `['GET']`. Puedes usar `['*']` para permitir todos los métodos estándar.\n* `allow_headers` - Una lista de headers de request HTTP que deberían estar soportados para requests cross-origin. Por defecto es `[]`. Puedes usar `['*']` para permitir todos los headers. Los headers `Accept`, `Accept-Language`, `Content-Language` y `Content-Type` siempre están permitidos para [requests CORS simples](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).\n* `allow_credentials` - Indica que las cookies deberían estar soportadas para requests cross-origin. Por defecto es `False`.\n\n    Ninguno de `allow_origins`, `allow_methods` y `allow_headers` puede establecerse a `['*']` si `allow_credentials` está configurado a `True`. Todos deben ser [especificados explícitamente](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards).\n\n* `expose_headers` - Indica cualquier header de response que debería ser accesible para el navegador. Por defecto es `[]`.\n* `max_age` - Establece un tiempo máximo en segundos para que los navegadores almacenen en caché los responses CORS. Por defecto es `600`.\n\nEl middleware responde a dos tipos particulares de request HTTP...\n\n### Requests de preflight CORS { #cors-preflight-requests }\n\nEstos son cualquier request `OPTIONS` con headers `Origin` y `Access-Control-Request-Method`.\n\nEn este caso, el middleware interceptará el request entrante y responderá con los headers CORS adecuados, y un response `200` o `400` con fines informativos.\n\n### Requests simples { #simple-requests }\n\nCualquier request con un header `Origin`. En este caso, el middleware pasará el request a través de lo normal, pero incluirá los headers CORS adecuados en el response.\n\n## Más info { #more-info }\n\nPara más información sobre <abbr title=\"Cross-Origin Resource Sharing\">CORS</abbr>, revisa la [documentación de CORS de Mozilla](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).\n\n/// note | Detalles Técnicos\n\nTambién podrías usar `from starlette.middleware.cors import CORSMiddleware`.\n\n**FastAPI** proporciona varios middlewares en `fastapi.middleware` como una conveniencia para ti, el desarrollador. Pero la mayoría de los middlewares disponibles provienen directamente de Starlette.\n\n///\n"
  },
  {
    "path": "docs/es/docs/tutorial/debugging.md",
    "content": "# Depuración { #debugging }\n\nPuedes conectar el depurador en tu editor, por ejemplo con Visual Studio Code o PyCharm.\n\n## Llama a `uvicorn` { #call-uvicorn }\n\nEn tu aplicación de FastAPI, importa y ejecuta `uvicorn` directamente:\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### Acerca de `__name__ == \"__main__\"` { #about-name-main }\n\nEl objetivo principal de `__name__ == \"__main__\"` es tener algo de código que se ejecute cuando tu archivo es llamado con:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\npero no es llamado cuando otro archivo lo importa, como en:\n\n```Python\nfrom myapp import app\n```\n\n#### Más detalles { #more-details }\n\nSupongamos que tu archivo se llama `myapp.py`.\n\nSi lo ejecutas con:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nentonces la variable interna `__name__` en tu archivo, creada automáticamente por Python, tendrá como valor el string `\"__main__\"`.\n\nAsí que, la sección:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nse ejecutará.\n\n---\n\nEsto no ocurrirá si importas ese módulo (archivo).\n\nEntonces, si tienes otro archivo `importer.py` con:\n\n```Python\nfrom myapp import app\n\n# Algún código adicional\n```\n\nen ese caso, la variable creada automáticamente dentro de `myapp.py` no tendrá la variable `__name__` con un valor de `\"__main__\"`.\n\nAsí que, la línea:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nno se ejecutará.\n\n/// info | Información\n\nPara más información, revisa [la documentación oficial de Python](https://docs.python.org/3/library/__main__.html).\n\n///\n\n## Ejecuta tu código con tu depurador { #run-your-code-with-your-debugger }\n\nDado que estás ejecutando el servidor Uvicorn directamente desde tu código, puedes llamar a tu programa de Python (tu aplicación FastAPI) directamente desde el depurador.\n\n---\n\nPor ejemplo, en Visual Studio Code, puedes:\n\n* Ir al panel de \"Debug\".\n* \"Add configuration...\".\n* Seleccionar \"Python\".\n* Ejecutar el depurador con la opción \"`Python: Current File (Integrated Terminal)`\".\n\nLuego, iniciará el servidor con tu código **FastAPI**, deteniéndose en tus puntos de interrupción, etc.\n\nAsí es como podría verse:\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\nSi usas PyCharm, puedes:\n\n* Abrir el menú \"Run\".\n* Seleccionar la opción \"Debug...\".\n* Luego aparece un menú contextual.\n* Selecciona el archivo para depurar (en este caso, `main.py`).\n\nLuego, iniciará el servidor con tu código **FastAPI**, deteniéndose en tus puntos de interrupción, etc.\n\nAsí es como podría verse:\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/es/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# Clases como dependencias { #classes-as-dependencies }\n\nAntes de profundizar en el sistema de **Inyección de Dependencias**, vamos a mejorar el ejemplo anterior.\n\n## Un `dict` del ejemplo anterior { #a-dict-from-the-previous-example }\n\nEn el ejemplo anterior, estábamos devolviendo un `dict` de nuestra dependencia (\"dependable\"):\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\nPero luego obtenemos un `dict` en el parámetro `commons` de la *path operation function*.\n\nY sabemos que los editores no pueden proporcionar mucho soporte (como autocompletado) para `dict`s, porque no pueden conocer sus claves y tipos de valor.\n\nPodemos hacerlo mejor...\n\n## Qué hace a una dependencia { #what-makes-a-dependency }\n\nHasta ahora has visto dependencias declaradas como funciones.\n\nPero esa no es la única forma de declarar dependencias (aunque probablemente sea la más común).\n\nEl factor clave es que una dependencia debe ser un \"callable\".\n\nUn \"**callable**\" en Python es cualquier cosa que Python pueda \"llamar\" como una función.\n\nEntonces, si tienes un objeto `something` (que podría _no_ ser una función) y puedes \"llamarlo\" (ejecutarlo) como:\n\n```Python\nsomething()\n```\n\no\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\nentonces es un \"callable\".\n\n## Clases como dependencias { #classes-as-dependencies_1 }\n\nPuedes notar que para crear una instance de una clase en Python, utilizas esa misma sintaxis.\n\nPor ejemplo:\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\nEn este caso, `fluffy` es una instance de la clase `Cat`.\n\nY para crear `fluffy`, estás \"llamando\" a `Cat`.\n\nEntonces, una clase en Python también es un **callable**.\n\nEntonces, en **FastAPI**, podrías usar una clase de Python como una dependencia.\n\nLo que **FastAPI** realmente comprueba es que sea un \"callable\" (función, clase o cualquier otra cosa) y los parámetros definidos.\n\nSi pasas un \"callable\" como dependencia en **FastAPI**, analizará los parámetros de ese \"callable\", y los procesará de la misma manera que los parámetros de una *path operation function*. Incluyendo sub-dependencias.\n\nEso también se aplica a los callables sin parámetros. Igual que sería para *path operation functions* sin parámetros.\n\nEntonces, podemos cambiar la dependencia \"dependable\" `common_parameters` de arriba a la clase `CommonQueryParams`:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\nPresta atención al método `__init__` usado para crear la instance de la clase:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n...tiene los mismos parámetros que nuestros `common_parameters` anteriores:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\nEsos parámetros son los que **FastAPI** usará para \"resolver\" la dependencia.\n\nEn ambos casos, tendrá:\n\n* Un parámetro de query `q` opcional que es un `str`.\n* Un parámetro de query `skip` que es un `int`, con un valor por defecto de `0`.\n* Un parámetro de query `limit` que es un `int`, con un valor por defecto de `100`.\n\nEn ambos casos, los datos serán convertidos, validados, documentados en el esquema de OpenAPI, etc.\n\n## Úsalo { #use-it }\n\nAhora puedes declarar tu dependencia usando esta clase.\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI** llama a la clase `CommonQueryParams`. Esto crea una \"instance\" de esa clase y la instance será pasada como el parámetro `commons` a tu función.\n\n## Anotación de tipos vs `Depends` { #type-annotation-vs-depends }\n\nNota cómo escribimos `CommonQueryParams` dos veces en el código anterior:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ sin `Annotated`\n\n/// tip | Consejo\n\nPrefiere usar la versión `Annotated` si es posible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\nEl último `CommonQueryParams`, en:\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n...es lo que **FastAPI** utilizará realmente para saber cuál es la dependencia.\n\nEs a partir de este que **FastAPI** extraerá los parámetros declarados y es lo que **FastAPI** realmente llamará.\n\n---\n\nEn este caso, el primer `CommonQueryParams`, en:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ sin `Annotated`\n\n/// tip | Consejo\n\nPrefiere usar la versión `Annotated` si es posible.\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n...no tiene ningún significado especial para **FastAPI**. **FastAPI** no lo usará para la conversión de datos, validación, etc. (ya que está usando `Depends(CommonQueryParams)` para eso).\n\nDe hecho, podrías escribir simplemente:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ sin `Annotated`\n\n/// tip | Consejo\n\nPrefiere usar la versión `Annotated` si es posible.\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n...como en:\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\nPero declarar el tipo es recomendable, ya que de esa manera tu editor sabrá lo que se pasará como el parámetro `commons`, y entonces podrá ayudarte con el autocompletado, chequeo de tipos, etc:\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## Atajo { #shortcut }\n\nPero ves que estamos teniendo algo de repetición de código aquí, escribiendo `CommonQueryParams` dos veces:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ sin `Annotated`\n\n/// tip | Consejo\n\nPrefiere usar la versión `Annotated` si es posible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n**FastAPI** proporciona un atajo para estos casos, en donde la dependencia es *específicamente* una clase que **FastAPI** \"llamará\" para crear una instance de la clase misma.\n\nPara esos casos específicos, puedes hacer lo siguiente:\n\nEn lugar de escribir:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ sin `Annotated`\n\n/// tip | Consejo\n\nPrefiere usar la versión `Annotated` si es posible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n...escribes:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ sin `Annotated`\n\n/// tip | Consejo\n\nPrefiere usar la versión `Annotated` si es posible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\nDeclaras la dependencia como el tipo del parámetro, y usas `Depends()` sin ningún parámetro, en lugar de tener que escribir la clase completa *otra vez* dentro de `Depends(CommonQueryParams)`.\n\nEl mismo ejemplo se vería entonces así:\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n...y **FastAPI** sabrá qué hacer.\n\n/// tip | Consejo\n\nSi eso parece más confuso que útil, ignóralo, no lo *necesitas*.\n\nEs solo un atajo. Porque a **FastAPI** le importa ayudarte a minimizar la repetición de código.\n\n///\n"
  },
  {
    "path": "docs/es/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# Dependencias en decoradores de *path operation* { #dependencies-in-path-operation-decorators }\n\nEn algunos casos realmente no necesitas el valor de retorno de una dependencia dentro de tu *path operation function*.\n\nO la dependencia no devuelve un valor.\n\nPero aún necesitas que sea ejecutada/resuelta.\n\nPara esos casos, en lugar de declarar un parámetro de *path operation function* con `Depends`, puedes añadir una `list` de `dependencies` al decorador de *path operation*.\n\n## Agregar `dependencies` al decorador de *path operation* { #add-dependencies-to-the-path-operation-decorator }\n\nEl decorador de *path operation* recibe un argumento opcional `dependencies`.\n\nDebe ser una `list` de `Depends()`:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\nEstas dependencias serán ejecutadas/resueltas de la misma manera que las dependencias normales. Pero su valor (si devuelven alguno) no será pasado a tu *path operation function*.\n\n/// tip | Consejo\n\nAlgunos editores revisan los parámetros de función no usados y los muestran como errores.\n\nUsando estas `dependencies` en el decorador de *path operation* puedes asegurarte de que se ejecutan mientras evitas errores en editores/herramientas.\n\nTambién puede ayudar a evitar confusiones para nuevos desarrolladores que vean un parámetro no usado en tu código y puedan pensar que es innecesario.\n\n///\n\n/// info | Información\n\nEn este ejemplo usamos headers personalizados inventados `X-Key` y `X-Token`.\n\nPero en casos reales, al implementar seguridad, obtendrías más beneficios usando las [Utilidades de Seguridad integradas (el próximo capítulo)](../security/index.md).\n\n///\n\n## Errores de dependencias y valores de retorno { #dependencies-errors-and-return-values }\n\nPuedes usar las mismas *funciones* de dependencia que usas normalmente.\n\n### Requisitos de dependencia { #dependency-requirements }\n\nPueden declarar requisitos de request (como headers) u otras sub-dependencias:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### Lanzar excepciones { #raise-exceptions }\n\nEstas dependencias pueden `raise` excepciones, igual que las dependencias normales:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### Valores de retorno { #return-values }\n\nY pueden devolver valores o no, los valores no serán usados.\n\nAsí que, puedes reutilizar una dependencia normal (que devuelve un valor) que ya uses en otro lugar, y aunque el valor no se use, la dependencia será ejecutada:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## Dependencias para un grupo de *path operations* { #dependencies-for-a-group-of-path-operations }\n\nMás adelante, cuando leas sobre cómo estructurar aplicaciones más grandes ([Aplicaciones Más Grandes - Múltiples Archivos](../../tutorial/bigger-applications.md)), posiblemente con múltiples archivos, aprenderás cómo declarar un único parámetro `dependencies` para un grupo de *path operations*.\n\n## Dependencias Globales { #global-dependencies }\n\nA continuación veremos cómo añadir dependencias a toda la aplicación `FastAPI`, de modo que se apliquen a cada *path operation*.\n"
  },
  {
    "path": "docs/es/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# Dependencias con yield { #dependencies-with-yield }\n\nFastAPI admite dependencias que realizan algunos <dfn title='a veces también llamado \"código de salida\", \"código de limpieza\", \"código de teardown\", \"código de cierre\", \"código de salida del context manager\", etc.'>pasos adicionales después de finalizar</dfn>.\n\nPara hacer esto, usa `yield` en lugar de `return`, y escribe los pasos adicionales (código) después.\n\n/// tip | Consejo\n\nAsegúrate de usar `yield` una sola vez por dependencia.\n\n///\n\n/// note | Detalles técnicos\n\nCualquier función que sea válida para usar con:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) o\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nsería válida para usar como una dependencia en **FastAPI**.\n\nDe hecho, FastAPI usa esos dos decoradores internamente.\n\n///\n\n## Una dependencia de base de datos con `yield` { #a-database-dependency-with-yield }\n\nPor ejemplo, podrías usar esto para crear una sesión de base de datos y cerrarla después de finalizar.\n\nSolo el código anterior e incluyendo el `yield` statement se ejecuta antes de crear un response:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\nEl valor generado es lo que se inyecta en *path operations* y otras dependencias:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\nEl código posterior al `yield` statement se ejecuta después del response:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip | Consejo\n\nPuedes usar funciones `async` o regulares.\n\n**FastAPI** hará lo correcto con cada una, igual que con dependencias normales.\n\n///\n\n## Una dependencia con `yield` y `try` { #a-dependency-with-yield-and-try }\n\nSi usas un bloque `try` en una dependencia con `yield`, recibirás cualquier excepción que se haya lanzado al usar la dependencia.\n\nPor ejemplo, si algún código en algún punto intermedio, en otra dependencia o en una *path operation*, realiza un \"rollback\" en una transacción de base de datos o crea cualquier otro error, recibirás la excepción en tu dependencia.\n\nPor lo tanto, puedes buscar esa excepción específica dentro de la dependencia con `except SomeException`.\n\nDel mismo modo, puedes usar `finally` para asegurarte de que los pasos de salida se ejecuten, sin importar si hubo una excepción o no.\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## Sub-dependencias con `yield` { #sub-dependencies-with-yield }\n\nPuedes tener sub-dependencias y \"árboles\" de sub-dependencias de cualquier tamaño y forma, y cualquiera o todas ellas pueden usar `yield`.\n\n**FastAPI** se asegurará de que el \"código de salida\" en cada dependencia con `yield` se ejecute en el orden correcto.\n\nPor ejemplo, `dependency_c` puede tener una dependencia de `dependency_b`, y `dependency_b` de `dependency_a`:\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\nY todas ellas pueden usar `yield`.\n\nEn este caso, `dependency_c`, para ejecutar su código de salida, necesita que el valor de `dependency_b` (aquí llamado `dep_b`) todavía esté disponible.\n\nY, a su vez, `dependency_b` necesita que el valor de `dependency_a` (aquí llamado `dep_a`) esté disponible para su código de salida.\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\nDe la misma manera, podrías tener algunas dependencias con `yield` y otras dependencias con `return`, y hacer que algunas de esas dependan de algunas de las otras.\n\nY podrías tener una sola dependencia que requiera varias otras dependencias con `yield`, etc.\n\nPuedes tener cualquier combinación de dependencias que quieras.\n\n**FastAPI** se asegurará de que todo se ejecute en el orden correcto.\n\n/// note | Detalles técnicos\n\nEsto funciona gracias a los [Context Managers](https://docs.python.org/3/library/contextlib.html) de Python.\n\n**FastAPI** los utiliza internamente para lograr esto.\n\n///\n\n## Dependencias con `yield` y `HTTPException` { #dependencies-with-yield-and-httpexception }\n\nViste que puedes usar dependencias con `yield` y tener bloques `try` que intentan ejecutar algo de código y luego ejecutar código de salida después de `finally`.\n\nTambién puedes usar `except` para capturar la excepción que se lanzó y hacer algo con ella.\n\nPor ejemplo, puedes lanzar una excepción diferente, como `HTTPException`.\n\n/// tip | Consejo\n\nEsta es una técnica algo avanzada, y en la mayoría de los casos realmente no la necesitarás, ya que puedes lanzar excepciones (incluyendo `HTTPException`) desde dentro del resto del código de tu aplicación, por ejemplo, en la *path operation function*.\n\nPero está ahí para ti si la necesitas. 🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\nSi quieres capturar excepciones y crear un response personalizado en base a eso, crea un [Manejador de Excepciones Personalizado](../handling-errors.md#install-custom-exception-handlers).\n\n## Dependencias con `yield` y `except` { #dependencies-with-yield-and-except }\n\nSi capturas una excepción usando `except` en una dependencia con `yield` y no la lanzas nuevamente (o lanzas una nueva excepción), FastAPI no podrá notar que hubo una excepción, al igual que sucedería con Python normal:\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\nEn este caso, el cliente verá un response *HTTP 500 Internal Server Error* como debería, dado que no estamos lanzando una `HTTPException` o similar, pero el servidor **no tendrá ningún registro** ni ninguna otra indicación de cuál fue el error. 😱\n\n### Siempre `raise` en Dependencias con `yield` y `except` { #always-raise-in-dependencies-with-yield-and-except }\n\nSi capturas una excepción en una dependencia con `yield`, a menos que estés lanzando otra `HTTPException` o similar, **deberías volver a lanzar la excepción original**.\n\nPuedes volver a lanzar la misma excepción usando `raise`:\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\nAhora el cliente obtendrá el mismo response *HTTP 500 Internal Server Error*, pero el servidor tendrá nuestro `InternalError` personalizado en los registros. 😎\n\n## Ejecución de dependencias con `yield` { #execution-of-dependencies-with-yield }\n\nLa secuencia de ejecución es más o menos como este diagrama. El tiempo fluye de arriba a abajo. Y cada columna es una de las partes que interactúa o ejecuta código.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exception handler\nparticipant dep as Dep with yield\nparticipant operation as Path Operation\nparticipant tasks as Background tasks\n\n    Note over client,operation: Puede lanzar excepciones, incluyendo HTTPException\n    client ->> dep: Iniciar request\n    Note over dep: Ejecutar código hasta yield\n    opt raise Exception\n        dep -->> handler: Lanzar Exception\n        handler -->> client: Response HTTP de error\n    end\n    dep ->> operation: Ejecutar dependencia, por ejemplo, sesión de BD\n    opt raise\n        operation -->> dep: Lanzar Exception (por ejemplo, HTTPException)\n        opt handle\n            dep -->> dep: Puede capturar excepción, lanzar una nueva HTTPException, lanzar otra excepción\n        end\n        handler -->> client: Response HTTP de error\n    end\n\n    operation ->> client: Devolver response al cliente\n    Note over client,operation: El response ya fue enviado, no se puede cambiar\n    opt Tasks\n        operation -->> tasks: Enviar tareas en background\n    end\n    opt Lanzar otra excepción\n        tasks -->> tasks: Manejar excepciones en el código de la tarea en background\n    end\n```\n\n/// info | Información\n\nSolo **un response** será enviado al cliente. Podría ser uno de los responses de error o será el response de la *path operation*.\n\nDespués de que se envíe uno de esos responses, no se podrá enviar ningún otro response.\n\n///\n\n/// tip | Consejo\n\nSi lanzas cualquier excepción en el código de la *path operation function*, se pasará a las dependencias con `yield`, incluyendo `HTTPException`. En la mayoría de los casos querrás volver a lanzar esa misma excepción o una nueva desde la dependencia con `yield` para asegurarte de que se maneje correctamente.\n\n///\n\n## Salida temprana y `scope` { #early-exit-and-scope }\n\nNormalmente, el código de salida de las dependencias con `yield` se ejecuta **después de que el response** se envía al cliente.\n\nPero si sabes que no necesitarás usar la dependencia después de regresar de la *path operation function*, puedes usar `Depends(scope=\"function\")` para decirle a FastAPI que debe cerrar la dependencia después de que la *path operation function* regrese, pero **antes** de que se envíe el **response**.\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()` recibe un parámetro `scope` que puede ser:\n\n* `\"function\"`: iniciar la dependencia antes de la *path operation function* que maneja el request, terminar la dependencia después de que termine la *path operation function*, pero **antes** de que el response se envíe de vuelta al cliente. Entonces, la función de dependencia se ejecutará **alrededor** de la *path operation **function***.\n* `\"request\"`: iniciar la dependencia antes de la *path operation function* que maneja el request (similar a cuando se usa `\"function\"`), pero terminar **después** de que el response se envíe de vuelta al cliente. Entonces, la función de dependencia se ejecutará **alrededor** del **request** y del ciclo del response.\n\nSi no se especifica y la dependencia tiene `yield`, tendrá un `scope` de `\"request\"` por defecto.\n\n### `scope` para sub-dependencias { #scope-for-sub-dependencies }\n\nCuando declaras una dependencia con `scope=\"request\"` (el valor por defecto), cualquier sub-dependencia también necesita tener un `scope` de `\"request\"`.\n\nPero una dependencia con `scope` de `\"function\"` puede tener dependencias con `scope` de `\"function\"` y `scope` de `\"request\"`.\n\nEsto es porque cualquier dependencia necesita poder ejecutar su código de salida antes que las sub-dependencias, ya que podría necesitar seguir usándolas durante su código de salida.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Dep scope=\"request\"\nparticipant dep_func as Dep scope=\"function\"\nparticipant operation as Path Operation\n\n    client ->> dep_req: Start request\n    Note over dep_req: Run code up to yield\n    dep_req ->> dep_func: Pass dependency\n    Note over dep_func: Run code up to yield\n    dep_func ->> operation: Run path operation with dependency\n    operation ->> dep_func: Return from path operation\n    Note over dep_func: Run code after yield\n    Note over dep_func: ✅ Dependency closed\n    dep_func ->> client: Send response to client\n    Note over client: Response sent\n    Note over dep_req: Run code after yield\n    Note over dep_req: ✅ Dependency closed\n```\n\n## Dependencias con `yield`, `HTTPException`, `except` y Tareas en Background { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\nLas dependencias con `yield` han evolucionado con el tiempo para cubrir diferentes casos de uso y corregir algunos problemas.\n\nSi quieres ver qué ha cambiado en diferentes versiones de FastAPI, puedes leer más al respecto en la guía avanzada, en [Dependencias avanzadas - Dependencias con `yield`, `HTTPException`, `except` y Tareas en Background](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).\n## Context Managers { #context-managers }\n\n### Qué son los \"Context Managers\" { #what-are-context-managers }\n\nLos \"Context Managers\" son aquellos objetos de Python que puedes usar en un `with` statement.\n\nPor ejemplo, [puedes usar `with` para leer un archivo](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files):\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\nInternamente, `open(\"./somefile.txt\")` crea un objeto llamado \"Context Manager\".\n\nCuando el bloque `with` termina, se asegura de cerrar el archivo, incluso si hubo excepciones.\n\nCuando creas una dependencia con `yield`, **FastAPI** creará internamente un context manager para ella y lo combinará con algunas otras herramientas relacionadas.\n\n### Usando context managers en dependencias con `yield` { #using-context-managers-in-dependencies-with-yield }\n\n/// warning | Advertencia\n\nEsto es, más o menos, una idea \"avanzada\".\n\nSi apenas estás comenzando con **FastAPI**, podrías querer omitirlo por ahora.\n\n///\n\nEn Python, puedes crear Context Managers [creando una clase con dos métodos: `__enter__()` y `__exit__()`](https://docs.python.org/3/reference/datamodel.html#context-managers).\n\nTambién puedes usarlos dentro de las dependencias de **FastAPI** con `yield` usando\n`with` o `async with` en la función de dependencia:\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip | Consejo\n\nOtra manera de crear un context manager es con:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) o\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nusándolos para decorar una función con un solo `yield`.\n\nEso es lo que **FastAPI** usa internamente para dependencias con `yield`.\n\nPero no tienes que usar los decoradores para las dependencias de FastAPI (y no deberías).\n\nFastAPI lo hará por ti internamente.\n\n///\n"
  },
  {
    "path": "docs/es/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# Dependencias Globales { #global-dependencies }\n\nPara algunos tipos de aplicaciones, podrías querer agregar dependencias a toda la aplicación.\n\nSimilar a como puedes [agregar `dependencies` a los *path operation decorators*](dependencies-in-path-operation-decorators.md), puedes agregarlos a la aplicación de `FastAPI`.\n\nEn ese caso, se aplicarán a todas las *path operations* en la aplicación:\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\nY todas las ideas en la sección sobre [agregar `dependencies` a los *path operation decorators*](dependencies-in-path-operation-decorators.md) siguen aplicándose, pero en este caso, a todas las *path operations* en la app.\n\n## Dependencias para grupos de *path operations* { #dependencies-for-groups-of-path-operations }\n\nMás adelante, al leer sobre cómo estructurar aplicaciones más grandes ([Aplicaciones Más Grandes - Múltiples Archivos](../../tutorial/bigger-applications.md)), posiblemente con múltiples archivos, aprenderás cómo declarar un solo parámetro de `dependencies` para un grupo de *path operations*.\n"
  },
  {
    "path": "docs/es/docs/tutorial/dependencies/index.md",
    "content": "# Dependencias { #dependencies }\n\n**FastAPI** tiene un sistema de **<dfn title=\"también conocido como componentes, recursos, proveedores, servicios, inyectables\">Inyección de Dependencias</dfn>** muy poderoso pero intuitivo.\n\nEstá diseñado para ser muy simple de usar, y para hacer que cualquier desarrollador integre otros componentes con **FastAPI** de forma muy sencilla.\n\n## Qué es la \"Inyección de Dependencias\" { #what-is-dependency-injection }\n\n**\"Inyección de Dependencias\"** significa, en programación, que hay una manera para que tu código (en este caso, tus *path operation functions*) declare las cosas que necesita para funcionar y utilizar: \"dependencias\".\n\nY luego, ese sistema (en este caso **FastAPI**) se encargará de hacer lo que sea necesario para proporcionar a tu código esas dependencias necesarias (\"inyectar\" las dependencias).\n\nEsto es muy útil cuando necesitas:\n\n* Tener lógica compartida (la misma lógica de código una y otra vez).\n* Compartir conexiones a bases de datos.\n* Imponer seguridad, autenticación, requisitos de roles, etc.\n* Y muchas otras cosas...\n\nTodo esto, mientras minimizas la repetición de código.\n\n## Primeros Pasos { #first-steps }\n\nVeamos un ejemplo muy simple. Será tan simple que no es muy útil, por ahora.\n\nPero de esta manera podemos enfocarnos en cómo funciona el sistema de **Inyección de Dependencias**.\n\n### Crear una dependencia, o \"dependable\" { #create-a-dependency-or-dependable }\n\nPrimero enfoquémonos en la dependencia.\n\nEs solo una función que puede tomar todos los mismos parámetros que una *path operation function* puede tomar:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\nEso es todo.\n\n**2 líneas**.\n\nY tiene la misma forma y estructura que todas tus *path operation functions*.\n\nPuedes pensar en ella como una *path operation function* sin el \"decorador\" (sin el `@app.get(\"/some-path\")`).\n\nY puede devolver lo que quieras.\n\nEn este caso, esta dependencia espera:\n\n* Un parámetro de query opcional `q` que es un `str`.\n* Un parámetro de query opcional `skip` que es un `int`, y por defecto es `0`.\n* Un parámetro de query opcional `limit` que es un `int`, y por defecto es `100`.\n\nY luego solo devuelve un `dict` que contiene esos valores.\n\n/// info | Información\n\nFastAPI agregó soporte para `Annotated` (y comenzó a recomendarlo) en la versión 0.95.0.\n\nSi tienes una versión anterior, obtendrás errores al intentar usar `Annotated`.\n\nAsegúrate de [Actualizar la versión de FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions) al menos a la 0.95.1 antes de usar `Annotated`.\n\n///\n\n### Importar `Depends` { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### Declarar la dependencia, en el \"dependant\" { #declare-the-dependency-in-the-dependant }\n\nDe la misma forma en que usas `Body`, `Query`, etc. con los parámetros de tu *path operation function*, usa `Depends` con un nuevo parámetro:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\nAunque usas `Depends` en los parámetros de tu función de la misma manera que usas `Body`, `Query`, etc., `Depends` funciona un poco diferente.\n\nLe das a `Depends` un solo parámetro.\n\nEste parámetro debe ser algo como una función.\n\n**No la llames** directamente (no agregues los paréntesis al final), solo pásala como un parámetro a `Depends()`.\n\nY esa función toma parámetros de la misma manera que las *path operation functions*.\n\n/// tip | Consejo\n\nVerás qué otras \"cosas\", además de funciones, pueden usarse como dependencias en el próximo capítulo.\n\n///\n\nCada vez que llega un nuevo request, **FastAPI** se encargará de:\n\n* Llamar a tu función de dependencia (\"dependable\") con los parámetros correctos.\n* Obtener el resultado de tu función.\n* Asignar ese resultado al parámetro en tu *path operation function*.\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\nDe esta manera escribes código compartido una vez y **FastAPI** se encarga de llamarlo para tus *path operations*.\n\n/// check | Revisa\n\nNota que no tienes que crear una clase especial y pasarla en algún lugar a **FastAPI** para \"registrarla\" o algo similar.\n\nSolo la pasas a `Depends` y **FastAPI** sabe cómo hacer el resto.\n\n///\n\n## Compartir dependencias `Annotated` { #share-annotated-dependencies }\n\nEn los ejemplos anteriores, ves que hay un poquito de **duplicación de código**.\n\nCuando necesitas usar la dependencia `common_parameters()`, tienes que escribir todo el parámetro con la anotación de tipo y `Depends()`:\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\nPero como estamos usando `Annotated`, podemos almacenar ese valor `Annotated` en una variable y usarlo en múltiples lugares:\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | Consejo\n\nEsto es solo Python estándar, se llama un \"alias de tipo\", en realidad no es específico de **FastAPI**.\n\nPero porque **FastAPI** está basado en los estándares de Python, incluido `Annotated`, puedes usar este truco en tu código. 😎\n\n///\n\nLas dependencias seguirán funcionando como se esperaba, y la **mejor parte** es que la **información de tipo se preservará**, lo que significa que tu editor podrá seguir proporcionándote **autocompletado**, **errores en línea**, etc. Lo mismo para otras herramientas como `mypy`.\n\nEsto será especialmente útil cuando lo uses en una **gran code base** donde uses **las mismas dependencias** una y otra vez en **muchas *path operations***.\n\n## Usar `async` o no usar `async` { #to-async-or-not-to-async }\n\nComo las dependencias también serán llamadas por **FastAPI** (lo mismo que tus *path operation functions*), las mismas reglas aplican al definir tus funciones.\n\nPuedes usar `async def` o `def` normal.\n\nY puedes declarar dependencias con `async def` dentro de *path operation functions* normales `def`, o dependencias `def` dentro de *path operation functions* `async def`, etc.\n\nNo importa. **FastAPI** sabrá qué hacer.\n\n/// note | Nota\n\nSi no lo sabes, revisa la sección [Async: *\"¿Con prisa?\"*](../../async.md#in-a-hurry) sobre `async` y `await` en la documentación.\n\n///\n\n## Integración con OpenAPI { #integrated-with-openapi }\n\nTodas las declaraciones de request, validaciones y requisitos de tus dependencias (y sub-dependencias) se integrarán en el mismo esquema de OpenAPI.\n\nAsí, la documentación interactiva tendrá toda la información de estas dependencias también:\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## Uso simple { #simple-usage }\n\nSi lo ves, las *path operation functions* se declaran para ser usadas siempre que un *path* y una *operación* coincidan, y luego **FastAPI** se encarga de llamar la función con los parámetros correctos, extrayendo los datos del request.\n\nEn realidad, todos (o la mayoría) de los frameworks web funcionan de esta misma manera.\n\nNunca llamas directamente a esas funciones. Son llamadas por tu framework (en este caso, **FastAPI**).\n\nCon el sistema de Inyección de Dependencias, también puedes decirle a **FastAPI** que tu *path operation function* también \"depende\" de algo más que debe ejecutarse antes que tu *path operation function*, y **FastAPI** se encargará de ejecutarlo e \"inyectar\" los resultados.\n\nOtros términos comunes para esta misma idea de \"inyección de dependencias\" son:\n\n* recursos\n* proveedores\n* servicios\n* inyectables\n* componentes\n\n## Plug-ins de **FastAPI** { #fastapi-plug-ins }\n\nLas integraciones y \"plug-ins\" pueden construirse usando el sistema de **Inyección de Dependencias**. Pero, de hecho, en realidad **no hay necesidad de crear \"plug-ins\"**, ya que al usar dependencias es posible declarar una cantidad infinita de integraciones e interacciones que se vuelven disponibles para tus *path operation functions*.\n\nY las dependencias se pueden crear de una manera muy simple e intuitiva que te permite simplemente importar los paquetes de Python que necesitas, e integrarlos con tus funciones de API en un par de líneas de código, *literalmente*.\n\nVerás ejemplos de esto en los próximos capítulos, sobre bases de datos relacionales y NoSQL, seguridad, etc.\n\n## Compatibilidad de **FastAPI** { #fastapi-compatibility }\n\nLa simplicidad del sistema de inyección de dependencias hace que **FastAPI** sea compatible con:\n\n* todas las bases de datos relacionales\n* bases de datos NoSQL\n* paquetes externos\n* APIs externas\n* sistemas de autenticación y autorización\n* sistemas de monitoreo de uso de la API\n* sistemas de inyección de datos de response\n* etc.\n\n## Simple y Poderoso { #simple-and-powerful }\n\nAunque el sistema de inyección de dependencias jerárquico es muy simple de definir y usar, sigue siendo muy poderoso.\n\nPuedes definir dependencias que a su vez pueden definir dependencias ellas mismas.\n\nAl final, se construye un árbol jerárquico de dependencias, y el sistema de **Inyección de Dependencias** se encarga de resolver todas estas dependencias por ti (y sus sub-dependencias) y proporcionar (inyectar) los resultados en cada paso.\n\nPor ejemplo, digamos que tienes 4 endpoints de API (*path operations*):\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\nentonces podrías agregar diferentes requisitos de permiso para cada uno de ellos solo con dependencias y sub-dependencias:\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## Integrado con **OpenAPI** { #integrated-with-openapi_1 }\n\nTodas estas dependencias, al declarar sus requisitos, también añaden parámetros, validaciones, etc. a tus *path operations*.\n\n**FastAPI** se encargará de agregar todo al esquema de OpenAPI, para que se muestre en los sistemas de documentación interactiva.\n"
  },
  {
    "path": "docs/es/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# Sub-dependencias { #sub-dependencies }\n\nPuedes crear dependencias que tengan **sub-dependencias**.\n\nPueden ser tan **profundas** como necesites.\n\n**FastAPI** se encargará de resolverlas.\n\n## Primera dependencia \"dependable\" { #first-dependency-dependable }\n\nPodrías crear una primera dependencia (\"dependable\") así:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\nDeclara un parámetro de query opcional `q` como un `str`, y luego simplemente lo devuelve.\n\nEsto es bastante simple (no muy útil), pero nos ayudará a centrarnos en cómo funcionan las sub-dependencias.\n\n## Segunda dependencia, \"dependable\" y \"dependant\" { #second-dependency-dependable-and-dependant }\n\nLuego puedes crear otra función de dependencia (un \"dependable\") que al mismo tiempo declare una dependencia propia (por lo que también es un \"dependant\"):\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\nCentrémonos en los parámetros declarados:\n\n* Aunque esta función es una dependencia (\"dependable\") en sí misma, también declara otra dependencia (depende de algo más).\n    * Depende del `query_extractor`, y asigna el valor que devuelve al parámetro `q`.\n* También declara una `last_query` cookie opcional, como un `str`.\n    * Si el usuario no proporcionó ningún query `q`, usamos el último query utilizado, que guardamos previamente en una cookie.\n\n## Usa la dependencia { #use-the-dependency }\n\nEntonces podemos usar la dependencia con:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info | Información\n\nFíjate que solo estamos declarando una dependencia en la *path operation function*, `query_or_cookie_extractor`.\n\nPero **FastAPI** sabrá que tiene que resolver `query_extractor` primero, para pasar los resultados de eso a `query_or_cookie_extractor` al llamarlo.\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## Usando la misma dependencia múltiples veces { #using-the-same-dependency-multiple-times }\n\nSi una de tus dependencias se declara varias veces para la misma *path operation*, por ejemplo, múltiples dependencias tienen una sub-dependencia común, **FastAPI** sabrá llamar a esa sub-dependencia solo una vez por request.\n\nY guardará el valor devuelto en un <dfn title=\"Una utilidad/sistema para almacenar valores calculados/generados, para reutilizarlos en lugar de calcularlos nuevamente.\">\"caché\"</dfn> y lo pasará a todos los \"dependants\" que lo necesiten en ese request específico, en lugar de llamar a la dependencia varias veces para el mismo request.\n\nEn un escenario avanzado donde sabes que necesitas que la dependencia se llame en cada paso (posiblemente varias veces) en el mismo request en lugar de usar el valor \"en caché\", puedes establecer el parámetro `use_cache=False` al usar `Depends`:\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ sin Anotaciones\n\n/// tip | Consejo\n\nPrefiere usar la versión `Annotated` si es posible.\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## Resumen { #recap }\n\nAparte de todas las palabras rimbombantes usadas aquí, el sistema de **Inyección de Dependencias** es bastante simple.\n\nSolo son funciones que se ven igual que las *path operation functions*.\n\nPero aun así, es muy potente y te permite declarar \"grafos\" de dependencia anidados arbitrariamente profundos (árboles).\n\n/// tip | Consejo\n\nTodo esto podría no parecer tan útil con estos ejemplos simples.\n\nPero verás lo útil que es en los capítulos sobre **seguridad**.\n\nY también verás la cantidad de código que te ahorrará.\n\n///\n"
  },
  {
    "path": "docs/es/docs/tutorial/encoder.md",
    "content": "# Codificador compatible con JSON { #json-compatible-encoder }\n\nHay algunos casos en los que podrías necesitar convertir un tipo de dato (como un modelo de Pydantic) a algo compatible con JSON (como un `dict`, `list`, etc).\n\nPor ejemplo, si necesitas almacenarlo en una base de datos.\n\nPara eso, **FastAPI** proporciona una función `jsonable_encoder()`.\n\n## Usando el `jsonable_encoder` { #using-the-jsonable-encoder }\n\nImaginemos que tienes una base de datos `fake_db` que solo recibe datos compatibles con JSON.\n\nPor ejemplo, no recibe objetos `datetime`, ya que no son compatibles con JSON.\n\nEntonces, un objeto `datetime` tendría que ser convertido a un `str` que contenga los datos en [formato ISO](https://en.wikipedia.org/wiki/ISO_8601).\n\nDe la misma manera, esta base de datos no recibiría un modelo de Pydantic (un objeto con atributos), solo un `dict`.\n\nPuedes usar `jsonable_encoder` para eso.\n\nRecibe un objeto, como un modelo de Pydantic, y devuelve una versión compatible con JSON:\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\nEn este ejemplo, convertiría el modelo de Pydantic a un `dict`, y el `datetime` a un `str`.\n\nEl resultado de llamarlo es algo que puede ser codificado con la función estándar de Python [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps).\n\nNo devuelve un gran `str` que contenga los datos en formato JSON (como un string). Devuelve una estructura de datos estándar de Python (por ejemplo, un `dict`) con valores y sub-valores que son todos compatibles con JSON.\n\n/// note | Nota\n\n`jsonable_encoder` es utilizado internamente por **FastAPI** para convertir datos. Pero es útil en muchos otros escenarios.\n\n///\n"
  },
  {
    "path": "docs/es/docs/tutorial/extra-data-types.md",
    "content": "# Tipos de Datos Extra { #extra-data-types }\n\nHasta ahora, has estado usando tipos de datos comunes, como:\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\nPero también puedes usar tipos de datos más complejos.\n\nY seguirás teniendo las mismas funcionalidades como hasta ahora:\n\n* Gran soporte de editor.\n* Conversión de datos de requests entrantes.\n* Conversión de datos para datos de response.\n* Validación de datos.\n* Anotación y documentación automática.\n\n## Otros tipos de datos { #other-data-types }\n\nAquí hay algunos de los tipos de datos adicionales que puedes usar:\n\n* `UUID`:\n    * Un \"Identificador Universalmente Único\" estándar, común como un ID en muchas bases de datos y sistemas.\n    * En requests y responses se representará como un `str`.\n* `datetime.datetime`:\n    * Un `datetime.datetime` de Python.\n    * En requests y responses se representará como un `str` en formato ISO 8601, como: `2008-09-15T15:53:00+05:00`.\n* `datetime.date`:\n    * `datetime.date` de Python.\n    * En requests y responses se representará como un `str` en formato ISO 8601, como: `2008-09-15`.\n* `datetime.time`:\n    * Un `datetime.time` de Python.\n    * En requests y responses se representará como un `str` en formato ISO 8601, como: `14:23:55.003`.\n* `datetime.timedelta`:\n    * Un `datetime.timedelta` de Python.\n    * En requests y responses se representará como un `float` de segundos totales.\n    * Pydantic también permite representarlo como una \"codificación de diferencia horaria ISO 8601\", [consulta la documentación para más información](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).\n* `frozenset`:\n    * En requests y responses, tratado igual que un `set`:\n        * En requests, se leerá una list, eliminando duplicados y convirtiéndola en un `set`.\n        * En responses, el `set` se convertirá en una `list`.\n        * El esquema generado especificará que los valores del `set` son únicos (usando `uniqueItems` de JSON Schema).\n* `bytes`:\n    * `bytes` estándar de Python.\n    * En requests y responses se tratará como `str`.\n    * El esquema generado especificará que es un `str` con `binary` como \"format\".\n* `Decimal`:\n    * `Decimal` estándar de Python.\n    * En requests y responses, manejado igual que un `float`.\n* Puedes revisar todos los tipos de datos válidos de Pydantic aquí: [Tipos de datos de Pydantic](https://docs.pydantic.dev/latest/usage/types/types/).\n\n## Ejemplo { #example }\n\nAquí tienes un ejemplo de una *path operation* con parámetros usando algunos de los tipos anteriores.\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\nNota que los parámetros dentro de la función tienen su tipo de dato natural, y puedes, por ejemplo, realizar manipulaciones de fechas normales, como:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/es/docs/tutorial/extra-models.md",
    "content": "# Modelos Extra { #extra-models }\n\nContinuando con el ejemplo anterior, será común tener más de un modelo relacionado.\n\nEsto es especialmente el caso para los modelos de usuario, porque:\n\n* El **modelo de entrada** necesita poder tener una contraseña.\n* El **modelo de salida** no debería tener una contraseña.\n* El **modelo de base de datos** probablemente necesitaría tener una contraseña hasheada.\n\n/// danger | Peligro\n\nNunca almacenes contraseñas de usuarios en texto plano. Siempre almacena un \"hash seguro\" que puedas verificar luego.\n\nSi no lo sabes, aprenderás qué es un \"hash de contraseña\" en los [capítulos de seguridad](security/simple-oauth2.md#password-hashing).\n\n///\n\n## Múltiples modelos { #multiple-models }\n\nAquí tienes una idea general de cómo podrían ser los modelos con sus campos de contraseña y los lugares donde se utilizan:\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### Acerca de `**user_in.model_dump()` { #about-user-in-model-dump }\n\n#### `.model_dump()` de Pydantic { #pydantics-model-dump }\n\n`user_in` es un modelo Pydantic de la clase `UserIn`.\n\nLos modelos Pydantic tienen un método `.model_dump()` que devuelve un `dict` con los datos del modelo.\n\nAsí que, si creamos un objeto Pydantic `user_in` como:\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\ny luego llamamos a:\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\nahora tenemos un `dict` con los datos en la variable `user_dict` (es un `dict` en lugar de un objeto modelo Pydantic).\n\nY si llamamos a:\n\n```Python\nprint(user_dict)\n```\n\nobtendríamos un `dict` de Python con:\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### Desempaquetando un `dict` { #unpacking-a-dict }\n\nSi tomamos un `dict` como `user_dict` y lo pasamos a una función (o clase) con `**user_dict`, Python lo \"desempaquetará\". Pasará las claves y valores del `user_dict` directamente como argumentos clave-valor.\n\nAsí que, continuando con el `user_dict` anterior, escribir:\n\n```Python\nUserInDB(**user_dict)\n```\n\nsería equivalente a algo como:\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\nO más exactamente, usando `user_dict` directamente, con cualquier contenido que pueda tener en el futuro:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### Un modelo Pydantic a partir del contenido de otro { #a-pydantic-model-from-the-contents-of-another }\n\nComo en el ejemplo anterior obtuvimos `user_dict` de `user_in.model_dump()`, este código:\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\nsería equivalente a:\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n...porque `user_in.model_dump()` es un `dict`, y luego hacemos que Python lo \"desempaquete\" al pasarlo a `UserInDB` con el prefijo `**`.\n\nAsí, obtenemos un modelo Pydantic a partir de los datos en otro modelo Pydantic.\n\n#### Desempaquetando un `dict` y palabras clave adicionales { #unpacking-a-dict-and-extra-keywords }\n\nY luego agregando el argumento de palabra clave adicional `hashed_password=hashed_password`, como en:\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n...termina siendo como:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning | Advertencia\n\nLas funciones adicionales de soporte `fake_password_hasher` y `fake_save_user` son solo para demostrar un posible flujo de datos, pero por supuesto no proporcionan ninguna seguridad real.\n\n///\n\n## Reducir duplicación { #reduce-duplication }\n\nReducir la duplicación de código es una de las ideas centrales en **FastAPI**.\n\nYa que la duplicación de código incrementa las posibilidades de bugs, problemas de seguridad, problemas de desincronización de código (cuando actualizas en un lugar pero no en los otros), etc.\n\nY estos modelos están compartiendo muchos de los datos y duplicando nombres y tipos de atributos.\n\nPodríamos hacerlo mejor.\n\nPodemos declarar un modelo `UserBase` que sirva como base para nuestros otros modelos. Y luego podemos hacer subclases de ese modelo que heredan sus atributos (declaraciones de tipos, validación, etc).\n\nToda la conversión de datos, validación, documentación, etc. seguirá funcionando normalmente.\n\nDe esa manera, podemos declarar solo las diferencias entre los modelos (con `password` en texto plano, con `hashed_password` y sin contraseña):\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` o `anyOf` { #union-or-anyof }\n\nPuedes declarar un response que sea la `Union` de dos o más tipos, eso significa que el response sería cualquiera de ellos.\n\nSe definirá en OpenAPI con `anyOf`.\n\nPara hacerlo, usa la anotación de tipos estándar de Python [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union):\n\n/// note | Nota\n\nAl definir una [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions), incluye el tipo más específico primero, seguido por el tipo menos específico. En el ejemplo a continuación, el más específico `PlaneItem` viene antes de `CarItem` en `Union[PlaneItem, CarItem]`.\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### `Union` en Python 3.10 { #union-in-python-3-10 }\n\nEn este ejemplo pasamos `Union[PlaneItem, CarItem]` como el valor del argumento `response_model`.\n\nPorque lo estamos pasando como un **valor a un argumento** en lugar de ponerlo en una **anotación de tipos**, tenemos que usar `Union` incluso en Python 3.10.\n\nSi estuviera en una anotación de tipos podríamos haber usado la barra vertical, como:\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\nPero si ponemos eso en la asignación `response_model=PlaneItem | CarItem` obtendríamos un error, porque Python intentaría realizar una **operación inválida** entre `PlaneItem` y `CarItem` en lugar de interpretar eso como una anotación de tipos.\n\n## Lista de modelos { #list-of-models }\n\nDe la misma manera, puedes declarar responses de listas de objetos.\n\nPara eso, usa la `list` estándar de Python:\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## Response con `dict` arbitrario { #response-with-arbitrary-dict }\n\nTambién puedes declarar un response usando un `dict` arbitrario plano, declarando solo el tipo de las claves y valores, sin usar un modelo Pydantic.\n\nEsto es útil si no conoces los nombres de los campos/atributos válidos (que serían necesarios para un modelo Pydantic) de antemano.\n\nEn este caso, puedes usar `dict`:\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## Recapitulación { #recap }\n\nUsa múltiples modelos Pydantic y hereda libremente para cada caso.\n\nNo necesitas tener un solo modelo de datos por entidad si esa entidad debe poder tener diferentes \"estados\". Como el caso con la \"entidad\" usuario con un estado que incluye `password`, `password_hash` y sin contraseña.\n"
  },
  {
    "path": "docs/es/docs/tutorial/first-steps.md",
    "content": "# Primeros Pasos { #first-steps }\n\nEl archivo FastAPI más simple podría verse así:\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\nCopia eso en un archivo `main.py`.\n\nEjecuta el servidor en vivo:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nEn el resultado, hay una línea con algo como:\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\nEsa línea muestra la URL donde tu aplicación está siendo servida, en tu máquina local.\n\n### Revisa { #check-it }\n\nAbre tu navegador en [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nVerás el response JSON como:\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### Documentación interactiva de la API { #interactive-api-docs }\n\nAhora ve a [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVerás la documentación interactiva automática de la API (proporcionada por [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Documentación alternativa de la API { #alternative-api-docs }\n\nY ahora, ve a [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nVerás la documentación alternativa automática (proporcionada por [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI** genera un \"esquema\" con toda tu API utilizando el estándar **OpenAPI** para definir APIs.\n\n#### \"Esquema\" { #schema }\n\nUn \"esquema\" es una definición o descripción de algo. No el código que lo implementa, sino solo una descripción abstracta.\n\n#### Esquema de la API { #api-schema }\n\nEn este caso, [OpenAPI](https://github.com/OAI/OpenAPI-Specification) es una especificación que dicta cómo definir un esquema de tu API.\n\nEsta definición de esquema incluye los paths de tu API, los posibles parámetros que toman, etc.\n\n#### Esquema de Datos { #data-schema }\n\nEl término \"esquema\" también podría referirse a la forma de algunos datos, como el contenido JSON.\n\nEn ese caso, significaría los atributos del JSON, los tipos de datos que tienen, etc.\n\n#### OpenAPI y JSON Schema { #openapi-and-json-schema }\n\nOpenAPI define un esquema de API para tu API. Y ese esquema incluye definiciones (o \"esquemas\") de los datos enviados y recibidos por tu API utilizando **JSON Schema**, el estándar para esquemas de datos JSON.\n\n#### Revisa el `openapi.json` { #check-the-openapi-json }\n\nSi tienes curiosidad por cómo se ve el esquema OpenAPI en bruto, FastAPI automáticamente genera un JSON (esquema) con las descripciones de toda tu API.\n\nPuedes verlo directamente en: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).\n\nMostrará un JSON que empieza con algo como:\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### Para qué sirve OpenAPI { #what-is-openapi-for }\n\nEl esquema OpenAPI es lo que impulsa los dos sistemas de documentación interactiva incluidos.\n\nY hay docenas de alternativas, todas basadas en OpenAPI. Podrías añadir fácilmente cualquiera de esas alternativas a tu aplicación construida con **FastAPI**.\n\nTambién podrías usarlo para generar código automáticamente, para clientes que se comuniquen con tu API. Por ejemplo, aplicaciones frontend, móviles o IoT.\n\n### Configura el `entrypoint` de la app en `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nPuedes configurar dónde está tu app en un archivo `pyproject.toml` así:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nEse `entrypoint` le dirá al comando `fastapi` que debe hacer el import de la app así:\n\n```python\nfrom main import app\n```\n\nSi tu código estuviera estructurado así:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nEntonces pondrías el `entrypoint` como:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nlo cual sería equivalente a:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` con path { #fastapi-dev-with-path }\n\nTambién puedes pasar el path del archivo al comando `fastapi dev`, y adivinará el objeto app de FastAPI que debe usar:\n\n```console\n$ fastapi dev main.py\n```\n\nPero tendrías que recordar pasar el path correcto cada vez que llames al comando `fastapi`.\n\nAdemás, otras herramientas podrían no ser capaces de encontrarlo, por ejemplo la [Extensión de VS Code](../editor-support.md) o [FastAPI Cloud](https://fastapicloud.com), así que se recomienda usar el `entrypoint` en `pyproject.toml`.\n\n### Despliega tu app (opcional) { #deploy-your-app-optional }\n\nOpcionalmente puedes desplegar tu app de FastAPI en [FastAPI Cloud](https://fastapicloud.com), ve y únete a la lista de espera si aún no lo has hecho. 🚀\n\nSi ya tienes una cuenta de **FastAPI Cloud** (te invitamos desde la lista de espera 😉), puedes desplegar tu aplicación con un solo comando.\n\nAntes de desplegar, asegúrate de haber iniciado sesión:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\nLuego despliega tu app:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n¡Eso es todo! Ahora puedes acceder a tu app en esa URL. ✨\n\n## Recapitulación, paso a paso { #recap-step-by-step }\n\n### Paso 1: importa `FastAPI` { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI` es una clase de Python que proporciona toda la funcionalidad para tu API.\n\n/// note | Detalles técnicos\n\n`FastAPI` es una clase que hereda directamente de `Starlette`.\n\nPuedes usar toda la funcionalidad de [Starlette](https://www.starlette.dev/) con `FastAPI` también.\n\n///\n\n### Paso 2: crea una \"instance\" de `FastAPI` { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\nAquí la variable `app` será una \"instance\" de la clase `FastAPI`.\n\nEste será el punto principal de interacción para crear toda tu API.\n\n### Paso 3: crea una *path operation* { #step-3-create-a-path-operation }\n\n#### Path { #path }\n\n\"Path\" aquí se refiere a la última parte de la URL empezando desde la primera `/`.\n\nAsí que, en una URL como:\n\n```\nhttps://example.com/items/foo\n```\n\n...el path sería:\n\n```\n/items/foo\n```\n\n/// info | Información\n\nUn \"path\" también es comúnmente llamado \"endpoint\" o \"ruta\".\n\n///\n\nMientras construyes una API, el \"path\" es la forma principal de separar \"concerns\" y \"resources\".\n\n#### Operación { #operation }\n\n\"Operación\" aquí se refiere a uno de los \"métodos\" HTTP.\n\nUno de:\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n...y los más exóticos:\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\nEn el protocolo HTTP, puedes comunicarte con cada path usando uno (o más) de estos \"métodos\".\n\n---\n\nAl construir APIs, normalmente usas estos métodos HTTP específicos para realizar una acción específica.\n\nNormalmente usas:\n\n* `POST`: para crear datos.\n* `GET`: para leer datos.\n* `PUT`: para actualizar datos.\n* `DELETE`: para eliminar datos.\n\nAsí que, en OpenAPI, cada uno de los métodos HTTP se llama una \"operation\".\n\nVamos a llamarlas \"**operaciones**\" también.\n\n#### Define un *path operation decorator* { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\nEl `@app.get(\"/\")` le dice a **FastAPI** que la función justo debajo se encarga de manejar requests que vayan a:\n\n* el path `/`\n* usando una <dfn title=\"un método HTTP GET\"><code>get</code> operación</dfn>\n\n/// info | Información sobre `@decorator`\n\nEsa sintaxis `@algo` en Python se llama un \"decorador\".\n\nLo pones encima de una función. Como un bonito sombrero decorativo (supongo que de ahí viene el término).\n\nUn \"decorador\" toma la función de abajo y hace algo con ella.\n\nEn nuestro caso, este decorador le dice a **FastAPI** que la función de abajo corresponde al **path** `/` con una **operation** `get`.\n\nEs el \"**path operation decorator**\".\n\n///\n\nTambién puedes usar las otras operaciones:\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\nY los más exóticos:\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip | Consejo\n\nEres libre de usar cada operación (método HTTP) como quieras.\n\n**FastAPI** no fuerza ningún significado específico.\n\nLa información aquí se presenta como una guía, no un requisito.\n\nPor ejemplo, cuando usas GraphQL normalmente realizas todas las acciones usando solo operaciones `POST`.\n\n///\n\n### Paso 4: define la **path operation function** { #step-4-define-the-path-operation-function }\n\nEsta es nuestra \"**path operation function**\":\n\n* **path**: es `/`.\n* **operation**: es `get`.\n* **function**: es la función debajo del \"decorador\" (debajo de `@app.get(\"/\")`).\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\nEsta es una función de Python.\n\nSerá llamada por **FastAPI** cuando reciba un request en la URL \"`/`\" usando una operación `GET`.\n\nEn este caso, es una función `async`.\n\n---\n\nTambién podrías definirla como una función normal en lugar de `async def`:\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note | Nota\n\nSi no sabes la diferencia, Revisa la sección [Async: *\"¿Tienes prisa?\"*](../async.md#in-a-hurry).\n\n///\n\n### Paso 5: retorna el contenido { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\nPuedes retornar un `dict`, `list`, valores singulares como `str`, `int`, etc.\n\nTambién puedes retornar modelos de Pydantic (verás más sobre eso más adelante).\n\nHay muchos otros objetos y modelos que serán automáticamente convertidos a JSON (incluyendo ORMs, etc). Intenta usar tus favoritos, es altamente probable que ya sean compatibles.\n\n### Paso 6: Despliégalo { #step-6-deploy-it }\n\nDespliega tu app en **[FastAPI Cloud](https://fastapicloud.com)** con un solo comando: `fastapi deploy`. 🎉\n\n#### Sobre FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** está construido por el mismo autor y equipo detrás de **FastAPI**.\n\nAgiliza el proceso de **construir**, **desplegar** y **acceder** a una API con el mínimo esfuerzo.\n\nTrae la misma **experiencia de desarrollador** de construir apps con FastAPI a **desplegarlas** en la nube. 🎉\n\nFastAPI Cloud es el sponsor principal y proveedor de financiación para los proyectos open source de *FastAPI and friends*. ✨\n\n#### Despliega en otros proveedores cloud { #deploy-to-other-cloud-providers }\n\nFastAPI es open source y basado en estándares. Puedes desplegar apps de FastAPI en cualquier proveedor cloud que elijas.\n\nSigue las guías de tu proveedor cloud para desplegar apps de FastAPI con ellos. 🤓\n\n## Recapitulación { #recap }\n\n* Importa `FastAPI`.\n* Crea una instance `app`.\n* Escribe un **path operation decorator** usando decoradores como `@app.get(\"/\")`.\n* Define una **path operation function**; por ejemplo, `def root(): ...`.\n* Ejecuta el servidor de desarrollo usando el comando `fastapi dev`.\n* Opcionalmente, despliega tu app con `fastapi deploy`.\n"
  },
  {
    "path": "docs/es/docs/tutorial/handling-errors.md",
    "content": "# Manejo de Errores { #handling-errors }\n\nExisten muchas situaciones en las que necesitas notificar un error a un cliente que está usando tu API.\n\nEste cliente podría ser un navegador con un frontend, un código de otra persona, un dispositivo IoT, etc.\n\nPodrías necesitar decirle al cliente que:\n\n* El cliente no tiene suficientes privilegios para esa operación.\n* El cliente no tiene acceso a ese recurso.\n* El ítem al que el cliente intentaba acceder no existe.\n* etc.\n\nEn estos casos, normalmente devolverías un **código de estado HTTP** en el rango de **400** (de 400 a 499).\n\nEsto es similar a los códigos de estado HTTP 200 (de 200 a 299). Esos códigos de estado \"200\" significan que de alguna manera hubo un \"éxito\" en el request.\n\nLos códigos de estado en el rango de 400 significan que hubo un error por parte del cliente.\n\n¿Recuerdas todos esos errores de **\"404 Not Found\"** (y chistes)?\n\n## Usa `HTTPException` { #use-httpexception }\n\nPara devolver responses HTTP con errores al cliente, usa `HTTPException`.\n\n### Importa `HTTPException` { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### Lanza un `HTTPException` en tu código { #raise-an-httpexception-in-your-code }\n\n`HTTPException` es una excepción de Python normal con datos adicionales relevantes para APIs.\n\nDebido a que es una excepción de Python, no la `return`, sino que la `raise`.\n\nEsto también significa que si estás dentro de una función de utilidad que estás llamando dentro de tu *path operation function*, y lanzas el `HTTPException` desde dentro de esa función de utilidad, no se ejecutará el resto del código en la *path operation function*, terminará ese request de inmediato y enviará el error HTTP del `HTTPException` al cliente.\n\nEl beneficio de lanzar una excepción en lugar de `return`ar un valor será más evidente en la sección sobre Dependencias y Seguridad.\n\nEn este ejemplo, cuando el cliente solicita un ítem por un ID que no existe, lanza una excepción con un código de estado de `404`:\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### El response resultante { #the-resulting-response }\n\nSi el cliente solicita `http://example.com/items/foo` (un `item_id` `\"foo\"`), ese cliente recibirá un código de estado HTTP de 200, y un response JSON de:\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\nPero si el cliente solicita `http://example.com/items/bar` (un `item_id` inexistente `\"bar\"`), ese cliente recibirá un código de estado HTTP de 404 (el error \"no encontrado\"), y un response JSON de:\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip | Consejo\n\nCuando lanzas un `HTTPException`, puedes pasar cualquier valor que pueda convertirse a JSON como el parámetro `detail`, no solo `str`.\n\nPodrías pasar un `dict`, un `list`, etc.\n\nSon manejados automáticamente por **FastAPI** y convertidos a JSON.\n\n///\n\n## Agrega headers personalizados { #add-custom-headers }\n\nExisten algunas situaciones en las que es útil poder agregar headers personalizados al error HTTP. Por ejemplo, para algunos tipos de seguridad.\n\nProbablemente no necesitarás usarlos directamente en tu código.\n\nPero en caso de que los necesites para un escenario avanzado, puedes agregar headers personalizados:\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## Instalar manejadores de excepciones personalizados { #install-custom-exception-handlers }\n\nPuedes agregar manejadores de excepciones personalizados con [las mismas utilidades de excepciones de Starlette](https://www.starlette.dev/exceptions/).\n\nSupongamos que tienes una excepción personalizada `UnicornException` que tú (o un paquete que usas) podrías lanzar.\n\nY quieres manejar esta excepción globalmente con FastAPI.\n\nPodrías agregar un manejador de excepciones personalizado con `@app.exception_handler()`:\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\nAquí, si solicitas `/unicorns/yolo`, la *path operation* lanzará un `UnicornException`.\n\nPero será manejado por el `unicorn_exception_handler`.\n\nAsí que recibirás un error limpio, con un código de estado HTTP de `418` y un contenido JSON de:\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | Nota Técnica\n\nTambién podrías usar `from starlette.requests import Request` y `from starlette.responses import JSONResponse`.\n\n**FastAPI** ofrece las mismas `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette. Lo mismo con `Request`.\n\n///\n\n## Sobrescribir los manejadores de excepciones predeterminados { #override-the-default-exception-handlers }\n\n**FastAPI** tiene algunos manejadores de excepciones predeterminados.\n\nEstos manejadores se encargan de devolver los responses JSON predeterminadas cuando lanzas un `HTTPException` y cuando el request tiene datos inválidos.\n\nPuedes sobrescribir estos manejadores de excepciones con los tuyos propios.\n\n### Sobrescribir excepciones de validación de request { #override-request-validation-exceptions }\n\nCuando un request contiene datos inválidos, **FastAPI** lanza internamente un `RequestValidationError`.\n\nY también incluye un manejador de excepciones predeterminado para ello.\n\nPara sobrescribirlo, importa el `RequestValidationError` y úsalo con `@app.exception_handler(RequestValidationError)` para decorar el manejador de excepciones.\n\nEl manejador de excepciones recibirá un `Request` y la excepción.\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\nAhora, si vas a `/items/foo`, en lugar de obtener el error JSON por defecto con:\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\nobtendrás una versión en texto, con:\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### Sobrescribir el manejador de errores de `HTTPException` { #override-the-httpexception-error-handler }\n\nDe la misma manera, puedes sobrescribir el manejador de `HTTPException`.\n\nPor ejemplo, podrías querer devolver un response de texto plano en lugar de JSON para estos errores:\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | Nota Técnica\n\nTambién podrías usar `from starlette.responses import PlainTextResponse`.\n\n**FastAPI** ofrece las mismas `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.\n\n///\n\n/// warning | Advertencia\n\nTen en cuenta que `RequestValidationError` contiene la información del nombre de archivo y la línea donde ocurre el error de validación, para que puedas mostrarla en tus logs con la información relevante si quieres.\n\nPero eso significa que si simplemente lo conviertes a un string y devuelves esa información directamente, podrías estar filtrando un poquito de información sobre tu sistema, por eso aquí el código extrae y muestra cada error de forma independiente.\n\n///\n\n### Usar el body de `RequestValidationError` { #use-the-requestvalidationerror-body }\n\nEl `RequestValidationError` contiene el `body` que recibió con datos inválidos.\n\nPodrías usarlo mientras desarrollas tu aplicación para registrar el body y depurarlo, devolverlo al usuario, etc.\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\nAhora intenta enviar un ítem inválido como:\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\nRecibirás un response que te dirá que los datos son inválidos conteniendo el body recibido:\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### `HTTPException` de FastAPI vs `HTTPException` de Starlette { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI** tiene su propio `HTTPException`.\n\nY la clase de error `HTTPException` de **FastAPI** hereda de la clase de error `HTTPException` de Starlette.\n\nLa única diferencia es que el `HTTPException` de **FastAPI** acepta cualquier dato JSON-able para el campo `detail`, mientras que el `HTTPException` de Starlette solo acepta strings para ello.\n\nAsí que puedes seguir lanzando un `HTTPException` de **FastAPI** como de costumbre en tu código.\n\nPero cuando registras un manejador de excepciones, deberías registrarlo para el `HTTPException` de Starlette.\n\nDe esta manera, si alguna parte del código interno de Starlette, o una extensión o plug-in de Starlette, lanza un `HTTPException` de Starlette, tu manejador podrá capturarlo y manejarlo.\n\nEn este ejemplo, para poder tener ambos `HTTPException` en el mismo código, las excepciones de Starlette son renombradas a `StarletteHTTPException`:\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### Reutilizar los manejadores de excepciones de **FastAPI** { #reuse-fastapis-exception-handlers }\n\nSi quieres usar la excepción junto con los mismos manejadores de excepciones predeterminados de **FastAPI**, puedes importar y reutilizar los manejadores de excepciones predeterminados de `fastapi.exception_handlers`:\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\nEn este ejemplo solo estás `print`eando el error con un mensaje muy expresivo, pero te haces una idea. Puedes usar la excepción y luego simplemente reutilizar los manejadores de excepciones predeterminados.\n"
  },
  {
    "path": "docs/es/docs/tutorial/header-param-models.md",
    "content": "# Modelos de Parámetros de Header { #header-parameter-models }\n\nSi tienes un grupo de **parámetros de header** relacionados, puedes crear un **modelo Pydantic** para declararlos.\n\nEsto te permitirá **reutilizar el modelo** en **múltiples lugares** y también declarar validaciones y metadatos para todos los parámetros al mismo tiempo. 😎\n\n/// note | Nota\n\nEsto es compatible desde la versión `0.115.0` de FastAPI. 🤓\n\n///\n\n## Parámetros de Header con un Modelo Pydantic { #header-parameters-with-a-pydantic-model }\n\nDeclara los **parámetros de header** que necesitas en un **modelo Pydantic**, y luego declara el parámetro como `Header`:\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\n**FastAPI** **extraerá** los datos para **cada campo** de los **headers** en el request y te dará el modelo Pydantic que definiste.\n\n## Revisa la Documentación { #check-the-docs }\n\nPuedes ver los headers requeridos en la interfaz de documentación en `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## Prohibir Headers Extra { #forbid-extra-headers }\n\nEn algunos casos de uso especiales (probablemente no muy comunes), podrías querer **restringir** los headers que deseas recibir.\n\nPuedes usar la configuración del modelo de Pydantic para `prohibir` cualquier campo `extra`:\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\nSi un cliente intenta enviar algunos **headers extra**, recibirán un response de **error**.\n\nPor ejemplo, si el cliente intenta enviar un header `tool` con un valor de `plumbus`, recibirán un response de **error** indicando que el parámetro de header `tool` no está permitido:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## Desactivar la conversión de guiones bajos { #disable-convert-underscores }\n\nDe la misma forma que con los parámetros de header normales, cuando tienes caracteres de guion bajo en los nombres de los parámetros, se **convierten automáticamente en guiones**.\n\nPor ejemplo, si tienes un parámetro de header `save_data` en el código, el header HTTP esperado será `save-data`, y aparecerá así en la documentación.\n\nSi por alguna razón necesitas desactivar esta conversión automática, también puedes hacerlo para los modelos Pydantic de parámetros de header.\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | Advertencia\n\nAntes de establecer `convert_underscores` a `False`, ten en cuenta que algunos proxies y servidores HTTP no permiten el uso de headers con guiones bajos.\n\n///\n\n## Resumen { #summary }\n\nPuedes usar **modelos Pydantic** para declarar **headers** en **FastAPI**. 😎\n"
  },
  {
    "path": "docs/es/docs/tutorial/header-params.md",
    "content": "# Parámetros de Header { #header-parameters }\n\nPuedes definir los parámetros de Header de la misma manera que defines los parámetros de `Query`, `Path` y `Cookie`.\n\n## Importar `Header` { #import-header }\n\nPrimero importa `Header`:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## Declarar parámetros de `Header` { #declare-header-parameters }\n\nLuego declara los parámetros de header usando la misma estructura que con `Path`, `Query` y `Cookie`.\n\nPuedes definir el valor por defecto así como toda la validación extra o los parámetros de anotaciones:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Detalles Técnicos\n\n`Header` es una clase \"hermana\" de `Path`, `Query` y `Cookie`. También hereda de la misma clase común `Param`.\n\nPero recuerda que cuando importas `Query`, `Path`, `Header`, y otros de `fastapi`, en realidad son funciones que retornan clases especiales.\n\n///\n\n/// info | Información\n\nPara declarar headers, necesitas usar `Header`, porque de otra forma los parámetros serían interpretados como parámetros de query.\n\n///\n\n## Conversión automática { #automatic-conversion }\n\n`Header` tiene un poquito de funcionalidad extra además de lo que proporcionan `Path`, `Query` y `Cookie`.\n\nLa mayoría de los headers estándar están separados por un carácter \"guion\", también conocido como el \"símbolo menos\" (`-`).\n\nPero una variable como `user-agent` es inválida en Python.\n\nAsí que, por defecto, `Header` convertirá los caracteres de los nombres de los parámetros de guion bajo (`_`) a guion (`-`) para extraer y documentar los headers.\n\nAdemás, los headers HTTP no diferencian entre mayúsculas y minúsculas, por lo que los puedes declarar con el estilo estándar de Python (también conocido como \"snake_case\").\n\nAsí que, puedes usar `user_agent` como normalmente lo harías en código Python, en lugar de necesitar capitalizar las primeras letras como `User_Agent` o algo similar.\n\nSi por alguna razón necesitas desactivar la conversión automática de guiones bajos a guiones, establece el parámetro `convert_underscores` de `Header` a `False`:\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | Advertencia\n\nAntes de establecer `convert_underscores` a `False`, ten en cuenta que algunos proxies y servidores HTTP no permiten el uso de headers con guiones bajos.\n\n///\n\n## Headers duplicados { #duplicate-headers }\n\nEs posible recibir headers duplicados. Eso significa, el mismo header con múltiples valores.\n\nPuedes definir esos casos usando una lista en la declaración del tipo.\n\nRecibirás todos los valores del header duplicado como una `list` de Python.\n\nPor ejemplo, para declarar un header de `X-Token` que puede aparecer más de una vez, puedes escribir:\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\nSi te comunicas con esa *path operation* enviando dos headers HTTP como:\n\n```\nX-Token: foo\nX-Token: bar\n```\n\nEl response sería como:\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## Recapitulación { #recap }\n\nDeclara headers con `Header`, usando el mismo patrón común que `Query`, `Path` y `Cookie`.\n\nY no te preocupes por los guiones bajos en tus variables, **FastAPI** se encargará de convertirlos.\n"
  },
  {
    "path": "docs/es/docs/tutorial/index.md",
    "content": "# Tutorial - Guía del Usuario { #tutorial-user-guide }\n\nEste tutorial te muestra cómo usar **FastAPI** con la mayoría de sus funcionalidades, paso a paso.\n\nCada sección se basa gradualmente en las anteriores, pero está estructurada para separar temas, de manera que puedas ir directamente a cualquier sección específica para resolver tus necesidades específicas de API.\n\nTambién está diseñado para funcionar como una referencia futura para que puedas volver y ver exactamente lo que necesitas.\n\n## Ejecuta el código { #run-the-code }\n\nTodos los bloques de código pueden ser copiados y usados directamente (de hecho, son archivos Python probados).\n\nPara ejecutar cualquiera de los ejemplos, copia el código a un archivo `main.py`, y comienza `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nEs **ALTAMENTE recomendable** que escribas o copies el código, lo edites y lo ejecutes localmente.\n\nUsarlo en tu editor es lo que realmente te muestra los beneficios de FastAPI, al ver cuán poco código tienes que escribir, todos los chequeos de tipos, autocompletado, etc.\n\n---\n\n## Instalar FastAPI { #install-fastapi }\n\nEl primer paso es instalar FastAPI.\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), actívalo, y luego **instala FastAPI**:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | Nota\n\nCuando instalas con `pip install \"fastapi[standard]\"` viene con algunas dependencias opcionales estándar por defecto, incluyendo `fastapi-cloud-cli`, que te permite hacer deploy a [FastAPI Cloud](https://fastapicloud.com).\n\nSi no quieres tener esas dependencias opcionales, en su lugar puedes instalar `pip install fastapi`.\n\nSi quieres instalar las dependencias estándar pero sin `fastapi-cloud-cli`, puedes instalar con `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n///\n\n/// tip | Consejo\n\nFastAPI tiene una [extensión oficial para VS Code](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (y Cursor), que ofrece muchas funcionalidades, incluyendo un explorador de path operation, búsqueda de path operation, navegación de CodeLens en tests (saltar a la definición desde tests), y deploy y logs de FastAPI Cloud, todo desde tu editor.\n\n///\n\n## Guía Avanzada del Usuario { #advanced-user-guide }\n\nTambién hay una **Guía Avanzada del Usuario** que puedes leer después de esta **Tutorial - Guía del Usuario**.\n\nLa **Guía Avanzada del Usuario** se basa en esta, utiliza los mismos conceptos y te enseña algunas funcionalidades adicionales.\n\nPero primero deberías leer la **Tutorial - Guía del Usuario** (lo que estás leyendo ahora mismo).\n\nEstá diseñada para que puedas construir una aplicación completa solo con la **Tutorial - Guía del Usuario**, y luego extenderla de diferentes maneras, dependiendo de tus necesidades, utilizando algunas de las ideas adicionales de la **Guía Avanzada del Usuario**.\n"
  },
  {
    "path": "docs/es/docs/tutorial/metadata.md",
    "content": "# Metadata y URLs de Docs { #metadata-and-docs-urls }\n\nPuedes personalizar varias configuraciones de metadata en tu aplicación **FastAPI**.\n\n## Metadata para la API { #metadata-for-api }\n\nPuedes establecer los siguientes campos que se usan en la especificación OpenAPI y en las interfaces automáticas de documentación de la API:\n\n| Parámetro | Tipo | Descripción |\n|------------|------|-------------|\n| `title` | `str` | El título de la API. |\n| `summary` | `str` | Un resumen corto de la API. <small>Disponible desde OpenAPI 3.1.0, FastAPI 0.99.0.</small> |\n| `description` | `str` | Una breve descripción de la API. Puede usar Markdown. |\n| `version` | `string` | La versión de la API. Esta es la versión de tu propia aplicación, no de OpenAPI. Por ejemplo, `2.5.0`. |\n| `terms_of_service` | `str` | Una URL a los Términos de Servicio para la API. Si se proporciona, debe ser una URL. |\n| `contact` | `dict` | La información de contacto para la API expuesta. Puede contener varios campos. <details><summary><code>contact</code> fields</summary><table><thead><tr><th>Parámetro</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>El nombre identificativo de la persona/organización de contacto.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>La URL que apunta a la información de contacto. DEBE tener el formato de una URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>La dirección de correo electrónico de la persona/organización de contacto. DEBE tener el formato de una dirección de correo.</td></tr></tbody></table></details> |\n| `license_info` | `dict` | La información de la licencia para la API expuesta. Puede contener varios campos. <details><summary><code>license_info</code> fields</summary><table><thead><tr><th>Parámetro</th><th>Tipo</th><th>Descripción</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>REQUERIDO</strong> (si se establece un <code>license_info</code>). El nombre de la licencia utilizada para la API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Una expresión de licencia [SPDX](https://spdx.org/licenses/) para la API. El campo <code>identifier</code> es mutuamente excluyente del campo <code>url</code>. <small>Disponible desde OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>Una URL a la licencia utilizada para la API. DEBE tener el formato de una URL.</td></tr></tbody></table></details> |\n\nPuedes configurarlos de la siguiente manera:\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | Consejo\n\nPuedes escribir Markdown en el campo `description` y se mostrará en el resultado.\n\n///\n\nCon esta configuración, la documentación automática de la API se vería así:\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## Identificador de licencia { #license-identifier }\n\nDesde OpenAPI 3.1.0 y FastAPI 0.99.0, también puedes establecer la `license_info` con un `identifier` en lugar de una `url`.\n\nPor ejemplo:\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## Metadata para etiquetas { #metadata-for-tags }\n\nTambién puedes agregar metadata adicional para las diferentes etiquetas usadas para agrupar tus path operations con el parámetro `openapi_tags`.\n\nEste toma una list que contiene un diccionario para cada etiqueta.\n\nCada diccionario puede contener:\n\n* `name` (**requerido**): un `str` con el mismo nombre de etiqueta que usas en el parámetro `tags` en tus *path operations* y `APIRouter`s.\n* `description`: un `str` con una breve descripción de la etiqueta. Puede tener Markdown y se mostrará en la interfaz de documentación.\n* `externalDocs`: un `dict` que describe documentación externa con:\n    * `description`: un `str` con una breve descripción para la documentación externa.\n    * `url` (**requerido**): un `str` con la URL para la documentación externa.\n\n### Crear metadata para etiquetas { #create-metadata-for-tags }\n\nProbemos eso en un ejemplo con etiquetas para `users` y `items`.\n\nCrea metadata para tus etiquetas y pásala al parámetro `openapi_tags`:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\nNota que puedes utilizar Markdown dentro de las descripciones, por ejemplo \"login\" se mostrará en negrita (**login**) y \"fancy\" se mostrará en cursiva (_fancy_).\n\n/// tip | Consejo\n\nNo tienes que agregar metadata para todas las etiquetas que uses.\n\n///\n\n### Usar tus etiquetas { #use-your-tags }\n\nUsa el parámetro `tags` con tus *path operations* (y `APIRouter`s) para asignarlas a diferentes etiquetas:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info | Información\n\nLee más sobre etiquetas en [Configuración de Path Operation](path-operation-configuration.md#tags).\n\n///\n\n### Revisa la documentación { #check-the-docs }\n\nAhora, si revisas la documentación, mostrará toda la metadata adicional:\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### Orden de las etiquetas { #order-of-tags }\n\nEl orden de cada diccionario de metadata de etiqueta también define el orden mostrado en la interfaz de documentación.\n\nPor ejemplo, aunque `users` iría después de `items` en orden alfabético, se muestra antes porque agregamos su metadata como el primer diccionario en la list.\n\n## URL de OpenAPI { #openapi-url }\n\nPor defecto, el esquema OpenAPI se sirve en `/openapi.json`.\n\nPero puedes configurarlo con el parámetro `openapi_url`.\n\nPor ejemplo, para configurarlo para que se sirva en `/api/v1/openapi.json`:\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\nSi quieres deshabilitar el esquema OpenAPI completamente, puedes establecer `openapi_url=None`, eso también deshabilitará las interfaces de usuario de documentación que lo usan.\n\n## URLs de Docs { #docs-urls }\n\nPuedes configurar las dos interfaces de usuario de documentación incluidas:\n\n* **Swagger UI**: servida en `/docs`.\n    * Puedes establecer su URL con el parámetro `docs_url`.\n    * Puedes deshabilitarla estableciendo `docs_url=None`.\n* **ReDoc**: servida en `/redoc`.\n    * Puedes establecer su URL con el parámetro `redoc_url`.\n    * Puedes deshabilitarla estableciendo `redoc_url=None`.\n\nPor ejemplo, para configurar Swagger UI para que se sirva en `/documentation` y deshabilitar ReDoc:\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/es/docs/tutorial/middleware.md",
    "content": "# Middleware { #middleware }\n\nPuedes añadir middleware a las aplicaciones de **FastAPI**.\n\nUn \"middleware\" es una función que trabaja con cada **request** antes de que sea procesada por cualquier *path operation* específica. Y también con cada **response** antes de devolverla.\n\n* Toma cada **request** que llega a tu aplicación.\n* Puede entonces hacer algo a esa **request** o ejecutar cualquier código necesario.\n* Luego pasa la **request** para que sea procesada por el resto de la aplicación (por alguna *path operation*).\n* Después toma la **response** generada por la aplicación (por alguna *path operation*).\n* Puede hacer algo a esa **response** o ejecutar cualquier código necesario.\n* Luego devuelve la **response**.\n\n/// note | Detalles Técnicos\n\nSi tienes dependencias con `yield`, el código de salida se ejecutará *después* del middleware.\n\nSi hubiera tareas en segundo plano (cubiertas en la sección [Tareas en segundo plano](background-tasks.md), lo verás más adelante), se ejecutarán *después* de todo el middleware.\n\n///\n\n## Crear un middleware { #create-a-middleware }\n\nPara crear un middleware usas el decorador `@app.middleware(\"http\")` encima de una función.\n\nLa función middleware recibe:\n\n* La `request`.\n* Una función `call_next` que recibirá la `request` como parámetro.\n    * Esta función pasará la `request` a la correspondiente *path operation*.\n    * Luego devuelve la `response` generada por la correspondiente *path operation*.\n* Puedes entonces modificar aún más la `response` antes de devolverla.\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip | Consejo\n\nTen en cuenta que los custom proprietary headers se pueden añadir [usando el prefijo `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nPero si tienes custom headers que deseas que un cliente en un navegador pueda ver, necesitas añadirlos a tus configuraciones de CORS ([CORS (Cross-Origin Resource Sharing)](cors.md)) usando el parámetro `expose_headers` documentado en [la documentación de CORS de Starlette](https://www.starlette.dev/middleware/#corsmiddleware).\n\n///\n\n/// note | Detalles Técnicos\n\nTambién podrías usar `from starlette.requests import Request`.\n\n**FastAPI** lo proporciona como una conveniencia para ti, el desarrollador. Pero viene directamente de Starlette.\n\n///\n\n### Antes y después de la `response` { #before-and-after-the-response }\n\nPuedes añadir código que se ejecute con la `request`, antes de que cualquier *path operation* la reciba.\n\nY también después de que se genere la `response`, antes de devolverla.\n\nPor ejemplo, podrías añadir un custom header `X-Process-Time` que contenga el tiempo en segundos que tomó procesar la request y generar una response:\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip | Consejo\n\nAquí usamos [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) en lugar de `time.time()` porque puede ser más preciso para estos casos de uso. 🤓\n\n///\n\n## Orden de ejecución con múltiples middlewares { #multiple-middleware-execution-order }\n\nCuando añades múltiples middlewares usando ya sea el decorador `@app.middleware()` o el método `app.add_middleware()`, cada nuevo middleware envuelve la aplicación, formando un stack. El último middleware añadido es el más externo, y el primero es el más interno.\n\nEn el camino de la request, el middleware más externo se ejecuta primero.\n\nEn el camino de la response, se ejecuta al final.\n\nPor ejemplo:\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\nEsto da como resultado el siguiente orden de ejecución:\n\n* **Request**: MiddlewareB → MiddlewareA → ruta\n\n* **Response**: ruta → MiddlewareA → MiddlewareB\n\nEste comportamiento de apilamiento asegura que los middlewares se ejecuten en un orden predecible y controlable.\n\n## Otros middlewares { #other-middlewares }\n\nMás adelante puedes leer sobre otros middlewares en la [Guía del Usuario Avanzado: Middleware Avanzado](../advanced/middleware.md).\n\nLeerás sobre cómo manejar <abbr title=\"Cross-Origin Resource Sharing\">CORS</abbr> con un middleware en la siguiente sección.\n"
  },
  {
    "path": "docs/es/docs/tutorial/path-operation-configuration.md",
    "content": "# Configuración de Path Operation { #path-operation-configuration }\n\nHay varios parámetros que puedes pasar a tu *path operation decorator* para configurarlo.\n\n/// warning | Advertencia\n\nTen en cuenta que estos parámetros se pasan directamente al *path operation decorator*, no a tu *path operation function*.\n\n///\n\n## Código de Estado del Response { #response-status-code }\n\nPuedes definir el `status_code` (HTTP) que se utilizará en el response de tu *path operation*.\n\nPuedes pasar directamente el código `int`, como `404`.\n\nPero si no recuerdas para qué es cada código numérico, puedes usar las constantes atajo en `status`:\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\nEse código de estado se usará en el response y se añadirá al esquema de OpenAPI.\n\n/// note | Detalles Técnicos\n\nTambién podrías usar `from starlette import status`.\n\n**FastAPI** ofrece el mismo `starlette.status` como `fastapi.status` solo por conveniencia para ti, el desarrollador. Pero viene directamente de Starlette.\n\n///\n\n## Tags { #tags }\n\nPuedes añadir tags a tu *path operation*, pasando el parámetro `tags` con un `list` de `str` (comúnmente solo una `str`):\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\nSerán añadidas al esquema de OpenAPI y usadas por las interfaces de documentación automática:\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### Tags con Enums { #tags-with-enums }\n\nSi tienes una gran aplicación, podrías terminar acumulando **varias tags**, y querrías asegurarte de que siempre uses la **misma tag** para *path operations* relacionadas.\n\nEn estos casos, podría tener sentido almacenar las tags en un `Enum`.\n\n**FastAPI** soporta eso de la misma manera que con strings normales:\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## Resumen y Descripción { #summary-and-description }\n\nPuedes añadir un `summary` y `description`:\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## Descripción desde docstring { #description-from-docstring }\n\nComo las descripciones tienden a ser largas y cubrir múltiples líneas, puedes declarar la descripción de la *path operation* en la <dfn title=\"un string de múltiples líneas como la primera expresión dentro de una función (no asignada a ninguna variable) usada para documentación\">docstring</dfn> de la función y **FastAPI** la leerá desde allí.\n\nPuedes escribir [Markdown](https://en.wikipedia.org/wiki/Markdown) en el docstring, se interpretará y mostrará correctamente (teniendo en cuenta la indentación del docstring).\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\nSerá usado en la documentación interactiva:\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## Descripción del Response { #response-description }\n\nPuedes especificar la descripción del response con el parámetro `response_description`:\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info | Información\n\nTen en cuenta que `response_description` se refiere específicamente al response, mientras que `description` se refiere a la *path operation* en general.\n\n///\n\n/// check | Revisa\n\nOpenAPI especifica que cada *path operation* requiere una descripción de response.\n\nEntonces, si no proporcionas una, **FastAPI** generará automáticamente una de \"Response exitoso\".\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## Deprecar una *path operation* { #deprecate-a-path-operation }\n\nSi necesitas marcar una *path operation* como <dfn title=\"obsoleta, se recomienda no usarla\">deprecated</dfn>, pero sin eliminarla, pasa el parámetro `deprecated`:\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\nSe marcará claramente como deprecado en la documentación interactiva:\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\nRevisa cómo lucen las *path operations* deprecadas y no deprecadas:\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## Resumen { #recap }\n\nPuedes configurar y añadir metadatos a tus *path operations* fácilmente pasando parámetros a los *path operation decorators*.\n"
  },
  {
    "path": "docs/es/docs/tutorial/path-params-numeric-validations.md",
    "content": "# Parámetros de Path y Validaciones Numéricas { #path-parameters-and-numeric-validations }\n\nDe la misma manera que puedes declarar más validaciones y metadatos para los parámetros de query con `Query`, puedes declarar el mismo tipo de validaciones y metadatos para los parámetros de path con `Path`.\n\n## Importar `Path` { #import-path }\n\nPrimero, importa `Path` de `fastapi`, e importa `Annotated`:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info | Información\n\nFastAPI agregó soporte para `Annotated` (y comenzó a recomendar su uso) en la versión 0.95.0.\n\nSi tienes una versión anterior, obtendrás errores al intentar usar `Annotated`.\n\nAsegúrate de [Actualizar la versión de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) a al menos la 0.95.1 antes de usar `Annotated`.\n\n///\n\n## Declarar metadatos { #declare-metadata }\n\nPuedes declarar todos los mismos parámetros que para `Query`.\n\nPor ejemplo, para declarar un valor de metadato `title` para el parámetro de path `item_id` puedes escribir:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note | Nota\n\nUn parámetro de path siempre es requerido ya que tiene que formar parte del path. Incluso si lo declaras con `None` o le asignas un valor por defecto, no afectará en nada, siempre será requerido.\n\n///\n\n## Ordena los parámetros como necesites { #order-the-parameters-as-you-need }\n\n/// tip | Consejo\n\nEsto probablemente no es tan importante o necesario si usas `Annotated`.\n\n///\n\nSupongamos que quieres declarar el parámetro de query `q` como un `str` requerido.\n\nY no necesitas declarar nada más para ese parámetro, así que realmente no necesitas usar `Query`.\n\nPero aún necesitas usar `Path` para el parámetro de path `item_id`. Y no quieres usar `Annotated` por alguna razón.\n\nPython se quejará si pones un valor con \"por defecto\" antes de un valor que no tenga \"por defecto\".\n\nPero puedes reordenarlos y poner el valor sin un valor por defecto (el parámetro de query `q`) primero.\n\nNo importa para **FastAPI**. Detectará los parámetros por sus nombres, tipos y declaraciones por defecto (`Query`, `Path`, etc), no le importa el orden.\n\nAsí que puedes declarar tu función como:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\nPero ten en cuenta que si usas `Annotated`, no tendrás este problema, no importará ya que no estás usando los valores por defecto de los parámetros de la función para `Query()` o `Path()`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## Ordena los parámetros como necesites, trucos { #order-the-parameters-as-you-need-tricks }\n\n/// tip | Consejo\n\nEsto probablemente no es tan importante o necesario si usas `Annotated`.\n\n///\n\nAquí hay un **pequeño truco** que puede ser útil, pero no lo necesitarás a menudo.\n\nSi quieres:\n\n* declarar el parámetro de query `q` sin un `Query` ni ningún valor por defecto\n* declarar el parámetro de path `item_id` usando `Path`\n* tenerlos en un orden diferente\n* no usar `Annotated`\n\n...Python tiene una sintaxis especial para eso.\n\nPasa `*`, como el primer parámetro de la función.\n\nPython no hará nada con ese `*`, pero sabrá que todos los parámetros siguientes deben ser llamados como argumentos de palabras clave (parejas key-value), también conocidos como <abbr title=\"De: K-ey W-ord Arg-uments\"><code>kwargs</code></abbr>. Incluso si no tienen un valor por defecto.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### Mejor con `Annotated` { #better-with-annotated }\n\nTen en cuenta que si usas `Annotated`, como no estás usando valores por defecto de los parámetros de la función, no tendrás este problema y probablemente no necesitarás usar `*`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## Validaciones numéricas: mayor o igual { #number-validations-greater-than-or-equal }\n\nCon `Query` y `Path` (y otros que verás más adelante) puedes declarar restricciones numéricas.\n\nAquí, con `ge=1`, `item_id` necesitará ser un número entero \"`g`reater than or `e`qual\" a `1`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## Validaciones numéricas: mayor que y menor o igual { #number-validations-greater-than-and-less-than-or-equal }\n\nLo mismo aplica para:\n\n* `gt`: `g`reater `t`han\n* `le`: `l`ess than or `e`qual\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## Validaciones numéricas: flotantes, mayor y menor { #number-validations-floats-greater-than-and-less-than }\n\nLas validaciones numéricas también funcionan para valores `float`.\n\nAquí es donde se convierte en importante poder declarar <abbr title=\"greater than - mayor que\"><code>gt</code></abbr> y no solo <abbr title=\"greater than or equal - mayor o igual que\"><code>ge</code></abbr>. Ya que con esto puedes requerir, por ejemplo, que un valor sea mayor que `0`, incluso si es menor que `1`.\n\nAsí, `0.5` sería un valor válido. Pero `0.0` o `0` no lo serían.\n\nY lo mismo para <abbr title=\"less than - menor que\"><code>lt</code></abbr>.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## Resumen { #recap }\n\nCon `Query`, `Path` (y otros que aún no has visto) puedes declarar metadatos y validaciones de string de las mismas maneras que con [Parámetros de Query y Validaciones de String](query-params-str-validations.md).\n\nY también puedes declarar validaciones numéricas:\n\n* `gt`: `g`reater `t`han\n* `ge`: `g`reater than or `e`qual\n* `lt`: `l`ess `t`han\n* `le`: `l`ess than or `e`qual\n\n/// info | Información\n\n`Query`, `Path` y otras clases que verás más adelante son subclases de una clase común `Param`.\n\nTodas ellas comparten los mismos parámetros para validación adicional y metadatos que has visto.\n\n///\n\n/// note | Detalles técnicos\n\nCuando importas `Query`, `Path` y otros de `fastapi`, en realidad son funciones.\n\nQue cuando se llaman, retornan instances de clases con el mismo nombre.\n\nAsí que importas `Query`, que es una función. Y cuando la llamas, retorna una instance de una clase también llamada `Query`.\n\nEstas funciones están allí (en lugar de usar simplemente las clases directamente) para que tu editor no marque errores sobre sus tipos.\n\nDe esa forma puedes usar tu editor y herramientas de programación normales sin tener que agregar configuraciones personalizadas para omitir esos errores.\n\n///\n"
  },
  {
    "path": "docs/es/docs/tutorial/path-params.md",
    "content": "# Parámetros de Path { #path-parameters }\n\nPuedes declarar \"parámetros\" o \"variables\" de path con la misma sintaxis que se usa en los format strings de Python:\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\nEl valor del parámetro de path `item_id` se pasará a tu función como el argumento `item_id`.\n\nAsí que, si ejecutas este ejemplo y vas a [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), verás un response de:\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## Parámetros de path con tipos { #path-parameters-with-types }\n\nPuedes declarar el tipo de un parámetro de path en la función, usando anotaciones de tipos estándar de Python:\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\nEn este caso, `item_id` se declara como un `int`.\n\n/// check | Revisa\n\nEsto te dará soporte del editor dentro de tu función, con chequeo de errores, autocompletado, etc.\n\n///\n\n## <dfn title=\"también conocido como: serialización, parsing, marshalling\">Conversión</dfn> de datos { #data-conversion }\n\nSi ejecutas este ejemplo y abres tu navegador en [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3), verás un response de:\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check | Revisa\n\nNota que el valor que tu función recibió (y devolvió) es `3`, como un `int` de Python, no un string `\"3\"`.\n\nEntonces, con esa declaración de tipo, **FastAPI** te ofrece <dfn title=\"convertir el string que viene de un request HTTP en datos de Python\">\"parsing\"</dfn> automático de request.\n\n///\n\n## Validación de datos { #data-validation }\n\nPero si vas al navegador en [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), verás un bonito error HTTP de:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\nporque el parámetro de path `item_id` tenía un valor de `\"foo\"`, que no es un `int`.\n\nEl mismo error aparecería si proporcionaras un `float` en lugar de un `int`, como en: [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)\n\n/// check | Revisa\n\nEntonces, con la misma declaración de tipo de Python, **FastAPI** te ofrece validación de datos.\n\nNota que el error también indica claramente el punto exacto donde la validación falló.\n\nEsto es increíblemente útil mientras desarrollas y depuras código que interactúa con tu API.\n\n///\n\n## Documentación { #documentation }\n\nY cuando abras tu navegador en [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), verás una documentación de API automática e interactiva como:\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check | Revisa\n\nNuevamente, solo con esa misma declaración de tipo de Python, **FastAPI** te ofrece documentación automática e interactiva (integrando Swagger UI).\n\nNota que el parámetro de path está declarado como un entero.\n\n///\n\n## Beneficios basados en estándares, documentación alternativa { #standards-based-benefits-alternative-documentation }\n\nY porque el esquema generado es del estándar [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md), hay muchas herramientas compatibles.\n\nDebido a esto, el propio **FastAPI** proporciona una documentación de API alternativa (usando ReDoc), a la cual puedes acceder en [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc):\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\nDe la misma manera, hay muchas herramientas compatibles. Incluyendo herramientas de generación de código para muchos lenguajes.\n\n## Pydantic { #pydantic }\n\nToda la validación de datos se realiza internamente con [Pydantic](https://docs.pydantic.dev/), así que obtienes todos los beneficios de esta. Y sabes que estás en buenas manos.\n\nPuedes usar las mismas declaraciones de tipo con `str`, `float`, `bool` y muchos otros tipos de datos complejos.\n\nVarios de estos se exploran en los siguientes capítulos del tutorial.\n\n## El orden importa { #order-matters }\n\nAl crear *path operations*, puedes encontrarte en situaciones donde tienes un path fijo.\n\nComo `/users/me`, imaginemos que es para obtener datos sobre el usuario actual.\n\nY luego también puedes tener un path `/users/{user_id}` para obtener datos sobre un usuario específico por algún ID de usuario.\n\nDebido a que las *path operations* se evalúan en orden, necesitas asegurarte de que el path para `/users/me` se declara antes que el de `/users/{user_id}`:\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\nDe lo contrario, el path para `/users/{user_id}` también coincidiría para `/users/me`, \"pensando\" que está recibiendo un parámetro `user_id` con un valor de `\"me\"`.\n\nDe manera similar, no puedes redefinir una path operation:\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\nLa primera siempre será utilizada ya que el path coincide primero.\n\n## Valores predefinidos { #predefined-values }\n\nSi tienes una *path operation* que recibe un *path parameter*, pero quieres que los valores posibles válidos del *path parameter* estén predefinidos, puedes usar un <abbr title=\"Enumeration – Enumeración\">`Enum`</abbr> estándar de Python.\n\n### Crear una clase `Enum` { #create-an-enum-class }\n\nImporta `Enum` y crea una subclase que herede de `str` y de `Enum`.\n\nAl heredar de `str`, la documentación de la API podrá saber que los valores deben ser de tipo `string` y podrá representarlos correctamente.\n\nLuego crea atributos de clase con valores fijos, que serán los valores válidos disponibles:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip | Consejo\n\nSi te estás preguntando, \"AlexNet\", \"ResNet\" y \"LeNet\" son solo nombres de <dfn title=\"Técnicamente, arquitecturas de modelos de Deep Learning\">modelos</dfn> de Machine Learning.\n\n///\n\n### Declarar un *path parameter* { #declare-a-path-parameter }\n\nLuego crea un *path parameter* con una anotación de tipo usando la clase enum que creaste (`ModelName`):\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### Revisa la documentación { #check-the-docs }\n\nComo los valores disponibles para el *path parameter* están predefinidos, la documentación interactiva puede mostrarlos de manera ordenada:\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### Trabajando con *enumeraciones* de Python { #working-with-python-enumerations }\n\nEl valor del *path parameter* será un *miembro* de enumeración.\n\n#### Comparar *miembros* de enumeraciones { #compare-enumeration-members }\n\nPuedes compararlo con el *miembro* de enumeración en tu enum creada `ModelName`:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### Obtener el valor de *enumeración* { #get-the-enumeration-value }\n\nPuedes obtener el valor actual (un `str` en este caso) usando `model_name.value`, o en general, `your_enum_member.value`:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip | Consejo\n\nTambién podrías acceder al valor `\"lenet\"` con `ModelName.lenet.value`.\n\n///\n\n#### Devolver *miembros* de enumeración { #return-enumeration-members }\n\nPuedes devolver *miembros de enum* desde tu *path operation*, incluso anidados en un cuerpo JSON (por ejemplo, un `dict`).\n\nSerán convertidos a sus valores correspondientes (cadenas en este caso) antes de devolverlos al cliente:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\nEn tu cliente recibirás un response JSON como:\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## Parámetros de path conteniendo paths { #path-parameters-containing-paths }\n\nImaginemos que tienes una *path operation* con un path `/files/{file_path}`.\n\nPero necesitas que `file_path` en sí mismo contenga un *path*, como `home/johndoe/myfile.txt`.\n\nEntonces, la URL para ese archivo sería algo como: `/files/home/johndoe/myfile.txt`.\n\n### Soporte de OpenAPI { #openapi-support }\n\nOpenAPI no soporta una manera de declarar un *path parameter* para que contenga un *path* dentro, ya que eso podría llevar a escenarios que son difíciles de probar y definir.\n\nSin embargo, todavía puedes hacerlo en **FastAPI**, usando una de las herramientas internas de Starlette.\n\nY la documentación seguiría funcionando, aunque no agregue ninguna documentación indicando que el parámetro debe contener un path.\n\n### Convertidor de Path { #path-convertor }\n\nUsando una opción directamente de Starlette puedes declarar un *path parameter* conteniendo un *path* usando una URL como:\n\n```\n/files/{file_path:path}\n```\n\nEn este caso, el nombre del parámetro es `file_path`, y la última parte, `:path`, indica que el parámetro debería coincidir con cualquier *path*.\n\nAsí que, puedes usarlo con:\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip | Consejo\n\nPodrías necesitar que el parámetro contenga `/home/johndoe/myfile.txt`, con una barra inclinada (`/`) inicial.\n\nEn ese caso, la URL sería: `/files//home/johndoe/myfile.txt`, con una doble barra inclinada (`//`) entre `files` y `home`.\n\n///\n\n## Resumen { #recap }\n\nCon **FastAPI**, al usar declaraciones de tipo estándar de Python, cortas e intuitivas, obtienes:\n\n* Soporte del editor: chequeo de errores, autocompletado, etc.\n* \" <dfn title=\"convertir el string que viene de un request HTTP en datos de Python\">parsing</dfn> \" de datos\n* Validación de datos\n* Anotación de API y documentación automática\n\nY solo tienes que declararlos una vez.\n\nProbablemente esa sea la principal ventaja visible de **FastAPI** en comparación con otros frameworks alternativos (aparte del rendimiento bruto).\n"
  },
  {
    "path": "docs/es/docs/tutorial/query-param-models.md",
    "content": "# Modelos de Parámetros Query { #query-parameter-models }\n\nSi tienes un grupo de **parámetros query** que están relacionados, puedes crear un **modelo de Pydantic** para declararlos.\n\nEsto te permitiría **reutilizar el modelo** en **múltiples lugares** y también declarar validaciones y metadatos para todos los parámetros de una vez. 😎\n\n/// note | Nota\n\nEsto es compatible desde la versión `0.115.0` de FastAPI. 🤓\n\n///\n\n## Parámetros Query con un Modelo Pydantic { #query-parameters-with-a-pydantic-model }\n\nDeclara los **parámetros query** que necesitas en un **modelo de Pydantic**, y luego declara el parámetro como `Query`:\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\n**FastAPI** **extraerá** los datos para **cada campo** de los **parámetros query** en el request y te proporcionará el modelo de Pydantic que definiste.\n\n## Revisa la Documentación { #check-the-docs }\n\nPuedes ver los parámetros query en la UI de documentación en `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## Prohibir Parámetros Query Extras { #forbid-extra-query-parameters }\n\nEn algunos casos de uso especiales (probablemente no muy comunes), podrías querer **restringir** los parámetros query que deseas recibir.\n\nPuedes usar la configuración del modelo de Pydantic para `forbid` cualquier campo `extra`:\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\nSi un cliente intenta enviar algunos datos **extra** en los **parámetros query**, recibirán un response de **error**.\n\nPor ejemplo, si el cliente intenta enviar un parámetro query `tool` con un valor de `plumbus`, como:\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\nRecibirán un response de **error** que les indica que el parámetro query `tool` no está permitido:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## Resumen { #summary }\n\nPuedes usar **modelos de Pydantic** para declarar **parámetros query** en **FastAPI**. 😎\n\n/// tip | Consejo\n\nAlerta de spoiler: también puedes usar modelos de Pydantic para declarar cookies y headers, pero leerás sobre eso más adelante en el tutorial. 🤫\n\n///\n"
  },
  {
    "path": "docs/es/docs/tutorial/query-params-str-validations.md",
    "content": "# Parámetros de Query y Validaciones de String { #query-parameters-and-string-validations }\n\n**FastAPI** te permite declarar información adicional y validación para tus parámetros.\n\nTomemos esta aplicación como ejemplo:\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\nEl parámetro de query `q` es de tipo `str | None`, lo que significa que es de tipo `str` pero también podría ser `None`, y de hecho, el valor por defecto es `None`, así que FastAPI sabrá que no es requerido.\n\n/// note | Nota\n\nFastAPI sabrá que el valor de `q` no es requerido por el valor por defecto `= None`.\n\nTener `str | None` permitirá que tu editor te dé un mejor soporte y detecte errores.\n\n///\n\n## Validaciones adicionales { #additional-validation }\n\nVamos a hacer que, aunque `q` sea opcional, siempre que se proporcione, su longitud no exceda los 50 caracteres.\n\n### Importar `Query` y `Annotated` { #import-query-and-annotated }\n\nPara lograr eso, primero importa:\n\n* `Query` desde `fastapi`\n* `Annotated` desde `typing`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info | Información\n\nFastAPI añadió soporte para `Annotated` (y empezó a recomendarlo) en la versión 0.95.0.\n\nSi tienes una versión más antigua, obtendrás errores al intentar usar `Annotated`.\n\nAsegúrate de [Actualizar la versión de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) a al menos 0.95.1 antes de usar `Annotated`.\n\n///\n\n## Usar `Annotated` en el tipo del parámetro `q` { #use-annotated-in-the-type-for-the-q-parameter }\n\n¿Recuerdas que te dije antes que `Annotated` puede usarse para agregar metadatos a tus parámetros en la [Introducción a Tipos de Python](../python-types.md#type-hints-with-metadata-annotations)?\n\nAhora es el momento de usarlo con FastAPI. 🚀\n\nTeníamos esta anotación de tipo:\n\n```Python\nq: str | None = None\n```\n\nLo que haremos es envolver eso con `Annotated`, para que se convierta en:\n\n```Python\nq: Annotated[str | None] = None\n```\n\nAmbas versiones significan lo mismo, `q` es un parámetro que puede ser un `str` o `None`, y por defecto, es `None`.\n\nAhora vamos a lo divertido. 🎉\n\n## Agregar `Query` a `Annotated` en el parámetro `q` { #add-query-to-annotated-in-the-q-parameter }\n\nAhora que tenemos este `Annotated` donde podemos poner más información (en este caso algunas validaciones adicionales), agrega `Query` dentro de `Annotated`, y establece el parámetro `max_length` a `50`:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\nNota que el valor por defecto sigue siendo `None`, por lo que el parámetro sigue siendo opcional.\n\nPero ahora, al tener `Query(max_length=50)` dentro de `Annotated`, le estamos diciendo a FastAPI que queremos que tenga validación adicional para este valor, queremos que tenga un máximo de 50 caracteres. 😎\n\n/// tip | Consejo\n\nAquí estamos usando `Query()` porque este es un **parámetro de query**. Más adelante veremos otros como `Path()`, `Body()`, `Header()`, y `Cookie()`, que también aceptan los mismos argumentos que `Query()`.\n\n///\n\nFastAPI ahora:\n\n* Validará los datos asegurándose de que la longitud máxima sea de 50 caracteres\n* Mostrará un error claro para el cliente cuando los datos no sean válidos\n* Documentará el parámetro en el OpenAPI esquema *path operation* (así aparecerá en la UI de documentación automática)\n\n## Alternativa (antigua): `Query` como valor por defecto { #alternative-old-query-as-the-default-value }\n\nVersiones anteriores de FastAPI (antes de <dfn title=\"antes de 2023-03\">0.95.0</dfn>) requerían que usaras `Query` como el valor por defecto de tu parámetro, en lugar de ponerlo en `Annotated`, hay una alta probabilidad de que veas código usándolo alrededor, así que te lo explicaré.\n\n/// tip | Consejo\n\nPara nuevo código y siempre que sea posible, usa `Annotated` como se explicó arriba. Hay múltiples ventajas (explicadas a continuación) y no hay desventajas. 🍰\n\n///\n\nAsí es como usarías `Query()` como el valor por defecto de tu parámetro de función, estableciendo el parámetro `max_length` a 50:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\nComo en este caso (sin usar `Annotated`) debemos reemplazar el valor por defecto `None` en la función con `Query()`, ahora necesitamos establecer el valor por defecto con el parámetro `Query(default=None)`, esto sirve al mismo propósito de definir ese valor por defecto (al menos para FastAPI).\n\nEntonces:\n\n```Python\nq: str | None = Query(default=None)\n```\n\n...hace que el parámetro sea opcional, con un valor por defecto de `None`, lo mismo que:\n\n\n```Python\nq: str | None = None\n```\n\nPero la versión con `Query` lo declara explícitamente como un parámetro de query.\n\nLuego, podemos pasar más parámetros a `Query`. En este caso, el parámetro `max_length` que se aplica a los strings:\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\nEsto validará los datos, mostrará un error claro cuando los datos no sean válidos, y documentará el parámetro en el esquema del *path operation* de OpenAPI.\n\n### `Query` como valor por defecto o en `Annotated` { #query-as-the-default-value-or-in-annotated }\n\nTen en cuenta que cuando uses `Query` dentro de `Annotated` no puedes usar el parámetro `default` para `Query`.\n\nEn su lugar utiliza el valor por defecto real del parámetro de la función. De lo contrario, sería inconsistente.\n\nPor ejemplo, esto no está permitido:\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n...porque no está claro si el valor por defecto debería ser `\"rick\"` o `\"morty\"`.\n\nAsí que utilizarías (preferentemente):\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n...o en code bases más antiguas encontrarás:\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### Ventajas de `Annotated` { #advantages-of-annotated }\n\nUsar `Annotated` es recomendado en lugar del valor por defecto en los parámetros de función, es mejor por múltiples razones. 🤓\n\nEl valor por defecto del parámetro de función es el valor real por defecto, eso es más intuitivo con Python en general. 😌\n\nPodrías llamar a esa misma función en otros lugares sin FastAPI, y funcionaría como se espera. Si hay un parámetro requerido (sin un valor por defecto), tu editor te avisará con un error, Python también se quejará si lo ejecutas sin pasar el parámetro requerido.\n\nCuando no usas `Annotated` y en su lugar usas el estilo de valor por defecto (antiguo), si llamas a esa función sin FastAPI en otros lugares, tienes que recordar pasar los argumentos a la función para que funcione correctamente, de lo contrario, los valores serán diferentes de lo que esperas (por ejemplo, `QueryInfo` o algo similar en lugar de `str`). Y tu editor no se quejará, y Python no se quejará al ejecutar esa función, solo cuando los errores dentro de las operaciones hagan que funcione incorrectamente.\n\nDado que `Annotated` puede tener más de una anotación de metadato, ahora podrías incluso usar la misma función con otras herramientas, como [Typer](https://typer.tiangolo.com/). 🚀\n\n## Agregar más validaciones { #add-more-validations }\n\nTambién puedes agregar un parámetro `min_length`:\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## Agregar expresiones regulares { #add-regular-expressions }\n\nPuedes definir una <dfn title=\"Una expresión regular, regex o regexp es una secuencia de caracteres que define un patrón de búsqueda para strings.\">expresión regular</dfn> `pattern` que el parámetro debe coincidir:\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\nEste patrón específico de expresión regular comprueba que el valor recibido del parámetro:\n\n* `^`: comienza con los siguientes caracteres, no tiene caracteres antes.\n* `fixedquery`: tiene el valor exacto `fixedquery`.\n* `$`: termina allí, no tiene más caracteres después de `fixedquery`.\n\nSi te sientes perdido con todas estas ideas de \"expresión regular\", no te preocupes. Son un tema difícil para muchas personas. Aún puedes hacer muchas cosas sin necesitar expresiones regulares todavía.\n\nAhora sabes que cuando las necesites puedes usarlas en **FastAPI**.\n\n## Valores por defecto { #default-values }\n\nPuedes, por supuesto, usar valores por defecto diferentes de `None`.\n\nDigamos que quieres declarar el parámetro de query `q` para que tenga un `min_length` de `3`, y para que tenga un valor por defecto de `\"fixedquery\"`:\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | Nota\n\nTener un valor por defecto de cualquier tipo, incluyendo `None`, hace que el parámetro sea opcional (no requerido).\n\n///\n\n## Parámetros requeridos { #required-parameters }\n\nCuando no necesitamos declarar más validaciones o metadatos, podemos hacer que el parámetro de query `q` sea requerido simplemente no declarando un valor por defecto, como:\n\n```Python\nq: str\n```\n\nen lugar de:\n\n```Python\nq: str | None = None\n```\n\nPero ahora lo estamos declarando con `Query`, por ejemplo, como:\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\nAsí que, cuando necesites declarar un valor como requerido mientras usas `Query`, simplemente puedes no declarar un valor por defecto:\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### Requerido, puede ser `None` { #required-can-be-none }\n\nPuedes declarar que un parámetro puede aceptar `None`, pero que aún así es requerido. Esto obligaría a los clientes a enviar un valor, incluso si el valor es `None`.\n\nPara hacer eso, puedes declarar que `None` es un tipo válido pero simplemente no declarar un valor por defecto:\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## Lista de parámetros de Query / múltiples valores { #query-parameter-list-multiple-values }\n\nCuando defines un parámetro de query explícitamente con `Query` también puedes declararlo para recibir una lista de valores, o dicho de otra manera, para recibir múltiples valores.\n\nPor ejemplo, para declarar un parámetro de query `q` que puede aparecer varias veces en la URL, puedes escribir:\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\nEntonces, con una URL como:\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\nrecibirías los múltiples valores de los *query parameters* `q` (`foo` y `bar`) en una `list` de Python dentro de tu *path operation function*, en el *parámetro de función* `q`.\n\nEntonces, el response a esa URL sería:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | Consejo\n\nPara declarar un parámetro de query con un tipo de `list`, como en el ejemplo anterior, necesitas usar explícitamente `Query`, de lo contrario sería interpretado como un request body.\n\n///\n\nLa documentación interactiva de API se actualizará en consecuencia, para permitir múltiples valores:\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### Lista de parámetros de Query / múltiples valores con valores por defecto { #query-parameter-list-multiple-values-with-defaults }\n\nTambién puedes definir un valor por defecto `list` de valores si no se proporciona ninguno:\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\nSi vas a:\n\n```\nhttp://localhost:8000/items/\n```\n\nel valor por defecto de `q` será: `[\"foo\", \"bar\"]` y tu response será:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### Usando solo `list` { #using-just-list }\n\nTambién puedes usar `list` directamente en lugar de `list[str]`:\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | Nota\n\nTen en cuenta que en este caso, FastAPI no comprobará el contenido de la list.\n\nPor ejemplo, `list[int]` comprobaría (y documentaría) que el contenido de la list son enteros. Pero `list` sola no lo haría.\n\n///\n\n## Declarar más metadatos { #declare-more-metadata }\n\nPuedes agregar más información sobre el parámetro.\n\nEsa información se incluirá en el OpenAPI generado y será utilizada por las interfaces de usuario de documentación y herramientas externas.\n\n/// note | Nota\n\nTen en cuenta que diferentes herramientas podrían tener diferentes niveles de soporte de OpenAPI.\n\nAlgunas de ellas podrían no mostrar toda la información extra declarada todavía, aunque en la mayoría de los casos, la funcionalidad faltante ya está planificada para desarrollo.\n\n///\n\nPuedes agregar un `title`:\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\nY una `description`:\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## Alias para parámetros { #alias-parameters }\n\nImagina que quieres que el parámetro sea `item-query`.\n\nComo en:\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\nPero `item-query` no es un nombre de variable válido en Python.\n\nLo más cercano sería `item_query`.\n\nPero aún necesitas que sea exactamente `item-query`...\n\nEntonces puedes declarar un `alias`, y ese alias será usado para encontrar el valor del parámetro:\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## Declarar parámetros obsoletos { #deprecating-parameters }\n\nAhora digamos que ya no te gusta este parámetro.\n\nTienes que dejarlo allí por un tiempo porque hay clientes usándolo, pero quieres que la documentación lo muestre claramente como <dfn title=\"obsoleto, se recomienda no usarlo\">obsoleto</dfn>.\n\nLuego pasa el parámetro `deprecated=True` a `Query`:\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\nLa documentación lo mostrará así:\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## Excluir parámetros de OpenAPI { #exclude-parameters-from-openapi }\n\nPara excluir un parámetro de query del esquema de OpenAPI generado (y por lo tanto, de los sistemas de documentación automática), establece el parámetro `include_in_schema` de `Query` a `False`:\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## Validación personalizada { #custom-validation }\n\nPodría haber casos donde necesites hacer alguna validación personalizada que no puede hacerse con los parámetros mostrados arriba.\n\nEn esos casos, puedes usar una función validadora personalizada que se aplique después de la validación normal (por ejemplo, después de validar que el valor es un `str`).\n\nPuedes lograr eso usando [`AfterValidator` de Pydantic](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) dentro de `Annotated`.\n\n/// tip | Consejo\n\nPydantic también tiene [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) y otros. 🤓\n\n///\n\nPor ejemplo, este validador personalizado comprueba que el ID del ítem empiece con `isbn-` para un número de libro <abbr title=\"International Standard Book Number - Número Estándar Internacional de Libros\">ISBN</abbr> o con `imdb-` para un ID de URL de película de <abbr title=\"Internet Movie Database - Base de datos de películas en Internet: un sitio web con información sobre películas\">IMDB</abbr>:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info | Información\n\nEsto está disponible con Pydantic versión 2 o superior. 😎\n\n///\n\n/// tip | Consejo\n\nSi necesitas hacer cualquier tipo de validación que requiera comunicarte con algún componente externo, como una base de datos u otra API, deberías usar Dependencias de FastAPI, las aprenderás más adelante.\n\nEstos validadores personalizados son para cosas que pueden comprobarse solo con los mismos datos provistos en el request.\n\n///\n\n### Entiende ese código { #understand-that-code }\n\nEl punto importante es solo usar `AfterValidator` con una función dentro de `Annotated`. Si quieres, sáltate esta parte. 🤸\n\n---\n\nPero si te da curiosidad este ejemplo de código específico y sigues entretenido, aquí tienes algunos detalles extra.\n\n#### String con `value.startswith()` { #string-with-value-startswith }\n\n¿Lo notaste? un string usando `value.startswith()` puede recibir una tupla, y comprobará cada valor en la tupla:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### Un ítem aleatorio { #a-random-item }\n\nCon `data.items()` obtenemos un <dfn title=\"Algo que podemos iterar con un for loop, como una list, set, etc.\">objeto iterable</dfn> con tuplas que contienen la clave y el valor para cada elemento del diccionario.\n\nConvertimos este objeto iterable en una `list` propiamente dicha con `list(data.items())`.\n\nLuego con `random.choice()` podemos obtener un valor aleatorio de la lista, así que obtenemos una tupla con `(id, name)`. Será algo como `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")`.\n\nLuego asignamos esos dos valores de la tupla a las variables `id` y `name`.\n\nAsí, si el usuario no proporcionó un ID de ítem, aún recibirá una sugerencia aleatoria.\n\n...hacemos todo esto en una sola línea simple. 🤯 ¿No te encanta Python? 🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## Recapitulación { #recap }\n\nPuedes declarar validaciones y metadatos adicionales para tus parámetros.\n\nValidaciones genéricas y metadatos:\n\n* `alias`\n* `title`\n* `description`\n* `deprecated`\n\nValidaciones específicas para strings:\n\n* `min_length`\n* `max_length`\n* `pattern`\n\nValidaciones personalizadas usando `AfterValidator`.\n\nEn estos ejemplos viste cómo declarar validaciones para valores de tipo `str`.\n\nMira los siguientes capítulos para aprender cómo declarar validaciones para otros tipos, como números.\n"
  },
  {
    "path": "docs/es/docs/tutorial/query-params.md",
    "content": "# Parámetros de Query { #query-parameters }\n\nCuando declaras otros parámetros de función que no son parte de los parámetros de path, son automáticamente interpretados como parámetros de \"query\".\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\nLa query es el conjunto de pares clave-valor que van después del `?` en una URL, separados por caracteres `&`.\n\nPor ejemplo, en la URL:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n...los parámetros de query son:\n\n* `skip`: con un valor de `0`\n* `limit`: con un valor de `10`\n\nComo son parte de la URL, son \"naturalmente\" strings.\n\nPero cuando los declaras con tipos de Python (en el ejemplo anterior, como `int`), son convertidos a ese tipo y validados respecto a él.\n\nTodo el mismo proceso que se aplica para los parámetros de path también se aplica para los parámetros de query:\n\n* Soporte del editor (obviamente)\n* <dfn title=\"convirtiendo el string que viene de un request HTTP en datos de Python\">\"parsing\"</dfn> de datos\n* Validación de datos\n* Documentación automática\n\n## Valores por defecto { #defaults }\n\nComo los parámetros de query no son una parte fija de un path, pueden ser opcionales y pueden tener valores por defecto.\n\nEn el ejemplo anterior, tienen valores por defecto de `skip=0` y `limit=10`.\n\nEntonces, ir a la URL:\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\nsería lo mismo que ir a:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\nPero si vas a, por ejemplo:\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\nLos valores de los parámetros en tu función serán:\n\n* `skip=20`: porque lo configuraste en la URL\n* `limit=10`: porque ese era el valor por defecto\n\n## Parámetros opcionales { #optional-parameters }\n\nDe la misma manera, puedes declarar parámetros de query opcionales, estableciendo su valor por defecto en `None`:\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\nEn este caso, el parámetro de función `q` será opcional y será `None` por defecto.\n\n/// check | Revisa\n\nAdemás, nota que **FastAPI** es lo suficientemente inteligente para notar que el parámetro de path `item_id` es un parámetro de path y `q` no lo es, por lo tanto, es un parámetro de query.\n\n///\n\n## Conversión de tipos en parámetros de query { #query-parameter-type-conversion }\n\nTambién puedes declarar tipos `bool`, y serán convertidos:\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\nEn este caso, si vas a:\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\no\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\no\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\no\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\no\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\no cualquier otra variación (mayúsculas, primera letra en mayúscula, etc.), tu función verá el parámetro `short` con un valor `bool` de `True`. De lo contrario, será `False`.\n\n## Múltiples parámetros de path y de query { #multiple-path-and-query-parameters }\n\nPuedes declarar múltiples parámetros de path y de query al mismo tiempo, **FastAPI** sabe cuál es cuál.\n\nY no tienes que declararlos en un orden específico.\n\nSerán detectados por nombre:\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## Parámetros de query requeridos { #required-query-parameters }\n\nCuando declaras un valor por defecto para parámetros que no son de path (por ahora, solo hemos visto parámetros de query), entonces no es requerido.\n\nSi no quieres agregar un valor específico pero solo hacer que sea opcional, establece el valor por defecto como `None`.\n\nPero cuando quieres hacer un parámetro de query requerido, simplemente no declares ningún valor por defecto:\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\nAquí el parámetro de query `needy` es un parámetro de query requerido de tipo `str`.\n\nSi abres en tu navegador una URL como:\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n...sin agregar el parámetro requerido `needy`, verás un error como:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\nComo `needy` es un parámetro requerido, necesitarías establecerlo en la URL:\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n...esto funcionaría:\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\nY por supuesto, puedes definir algunos parámetros como requeridos, algunos con un valor por defecto, y algunos enteramente opcionales:\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\nEn este caso, hay 3 parámetros de query:\n\n* `needy`, un `str` requerido.\n* `skip`, un `int` con un valor por defecto de `0`.\n* `limit`, un `int` opcional.\n\n/// tip | Consejo\n\nTambién podrías usar `Enum`s de la misma manera que con [Parámetros de Path](path-params.md#predefined-values).\n\n///\n"
  },
  {
    "path": "docs/es/docs/tutorial/request-files.md",
    "content": "# Archivos de Request { #request-files }\n\nPuedes definir archivos que serán subidos por el cliente utilizando `File`.\n\n/// info | Información\n\nPara recibir archivos subidos, primero instala [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo y luego instalarlo, por ejemplo:\n\n```console\n$ pip install python-multipart\n```\n\nEsto es porque los archivos subidos se envían como \"form data\".\n\n///\n\n## Importar `File` { #import-file }\n\nImporta `File` y `UploadFile` desde `fastapi`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## Definir Parámetros `File` { #define-file-parameters }\n\nCrea parámetros de archivo de la misma manera que lo harías para `Body` o `Form`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info | Información\n\n`File` es una clase que hereda directamente de `Form`.\n\nPero recuerda que cuando importas `Query`, `Path`, `File` y otros desde `fastapi`, esos son en realidad funciones que devuelven clases especiales.\n\n///\n\n/// tip | Consejo\n\nPara declarar cuerpos de File, necesitas usar `File`, porque de otra manera los parámetros serían interpretados como parámetros query o parámetros de cuerpo (JSON).\n\n///\n\nLos archivos se subirán como \"form data\".\n\nSi declaras el tipo de tu parámetro de *path operation function* como `bytes`, **FastAPI** leerá el archivo por ti y recibirás el contenido como `bytes`.\n\nTen en cuenta que esto significa que todo el contenido se almacenará en memoria. Esto funcionará bien para archivos pequeños.\n\nPero hay varios casos en los que podrías beneficiarte de usar `UploadFile`.\n\n## Parámetros de Archivo con `UploadFile` { #file-parameters-with-uploadfile }\n\nDefine un parámetro de archivo con un tipo de `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\nUsar `UploadFile` tiene varias ventajas sobre `bytes`:\n\n* No tienes que usar `File()` en el valor por defecto del parámetro.\n* Usa un archivo \"spooled\":\n    * Un archivo almacenado en memoria hasta un límite de tamaño máximo, y después de superar este límite, se almacenará en el disco.\n* Esto significa que funcionará bien para archivos grandes como imágenes, videos, binarios grandes, etc. sin consumir toda la memoria.\n* Puedes obtener metadatos del archivo subido.\n* Tiene una interfaz `async` [parecida a un archivo](https://docs.python.org/3/glossary.html#term-file-like-object).\n* Expone un objeto Python real [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) que puedes pasar directamente a otros paquetes que esperan un objeto parecido a un archivo.\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` tiene los siguientes atributos:\n\n* `filename`: Un `str` con el nombre original del archivo que fue subido (por ejemplo, `myimage.jpg`).\n* `content_type`: Un `str` con el tipo de contenido (MIME type / media type) (por ejemplo, `image/jpeg`).\n* `file`: Un [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (un objeto [parecido a un archivo](https://docs.python.org/3/glossary.html#term-file-like-object)). Este es el objeto de archivo Python real que puedes pasar directamente a otras funciones o paquetes que esperan un objeto \"parecido a un archivo\".\n\n`UploadFile` tiene los siguientes métodos `async`. Todos ellos llaman a los métodos correspondientes del archivo por debajo (usando el `SpooledTemporaryFile` interno).\n\n* `write(data)`: Escribe `data` (`str` o `bytes`) en el archivo.\n* `read(size)`: Lee `size` (`int`) bytes/caracteres del archivo.\n* `seek(offset)`: Va a la posición de bytes `offset` (`int`) en el archivo.\n    * Por ejemplo, `await myfile.seek(0)` iría al inicio del archivo.\n    * Esto es especialmente útil si ejecutas `await myfile.read()` una vez y luego necesitas leer el contenido nuevamente.\n* `close()`: Cierra el archivo.\n\nComo todos estos métodos son métodos `async`, necesitas \"await\" para ellos.\n\nPor ejemplo, dentro de una *path operation function* `async` puedes obtener los contenidos con:\n\n```Python\ncontents = await myfile.read()\n```\n\nSi estás dentro de una *path operation function* normal `def`, puedes acceder al `UploadFile.file` directamente, por ejemplo:\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | Detalles Técnicos de `async`\n\nCuando usas los métodos `async`, **FastAPI** ejecuta los métodos del archivo en un threadpool y los espera.\n\n///\n\n/// note | Detalles Técnicos de Starlette\n\nEl `UploadFile` de **FastAPI** hereda directamente del `UploadFile` de **Starlette**, pero añade algunas partes necesarias para hacerlo compatible con **Pydantic** y las otras partes de FastAPI.\n\n///\n\n## Qué es \"Form Data\" { #what-is-form-data }\n\nLa manera en que los formularios de HTML (`<form></form>`) envían los datos al servidor normalmente utiliza una codificación \"especial\" para esos datos, es diferente de JSON.\n\n**FastAPI** se asegurará de leer esos datos del lugar correcto en lugar de JSON.\n\n/// note | Detalles Técnicos\n\nLos datos de los forms normalmente se codifican usando el \"media type\" `application/x-www-form-urlencoded` cuando no incluyen archivos.\n\nPero cuando el formulario incluye archivos, se codifica como `multipart/form-data`. Si usas `File`, **FastAPI** sabrá que tiene que obtener los archivos de la parte correcta del cuerpo.\n\nSi deseas leer más sobre estas codificaciones y campos de formularios, dirígete a la [<abbr title=\"Mozilla Developer Network - Red de Desarrolladores de Mozilla\">MDN</abbr> web docs para `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Advertencia\n\nPuedes declarar múltiples parámetros `File` y `Form` en una *path operation*, pero no puedes declarar campos `Body` que esperas recibir como JSON, ya que el request tendrá el cuerpo codificado usando `multipart/form-data` en lugar de `application/json`.\n\nEsto no es una limitación de **FastAPI**, es parte del protocolo HTTP.\n\n///\n\n## Subida de Archivos Opcional { #optional-file-upload }\n\nPuedes hacer un archivo opcional utilizando anotaciones de tipos estándar y estableciendo un valor por defecto de `None`:\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## `UploadFile` con Metadatos Adicionales { #uploadfile-with-additional-metadata }\n\nTambién puedes usar `File()` con `UploadFile`, por ejemplo, para establecer metadatos adicionales:\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## Subidas de Múltiples Archivos { #multiple-file-uploads }\n\nEs posible subir varios archivos al mismo tiempo.\n\nEstarían asociados al mismo \"campo de formulario\" enviado usando \"form data\".\n\nPara usar eso, declara una `list` de `bytes` o `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\nRecibirás, como se declaró, una `list` de `bytes` o `UploadFile`s.\n\n/// note | Detalles Técnicos\n\nTambién podrías usar `from starlette.responses import HTMLResponse`.\n\n**FastAPI** proporciona las mismas `starlette.responses` como `fastapi.responses` solo como una conveniencia para ti, el desarrollador. Pero la mayoría de los responses disponibles vienen directamente de Starlette.\n\n///\n\n### Subidas de Múltiples Archivos con Metadatos Adicionales { #multiple-file-uploads-with-additional-metadata }\n\nY de la misma manera que antes, puedes usar `File()` para establecer parámetros adicionales, incluso para `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## Recapitulación { #recap }\n\nUsa `File`, `bytes` y `UploadFile` para declarar archivos que se subirán en el request, enviados como form data.\n"
  },
  {
    "path": "docs/es/docs/tutorial/request-form-models.md",
    "content": "# Modelos de Formulario { #form-models }\n\nPuedes usar **modelos de Pydantic** para declarar **campos de formulario** en FastAPI.\n\n/// info | Información\n\nPara usar formularios, primero instala [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo, y luego instalarlo, por ejemplo:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note | Nota\n\nEsto es compatible desde la versión `0.113.0` de FastAPI. 🤓\n\n///\n\n## Modelos de Pydantic para Formularios { #pydantic-models-for-forms }\n\nSolo necesitas declarar un **modelo de Pydantic** con los campos que quieres recibir como **campos de formulario**, y luego declarar el parámetro como `Form`:\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI** **extraerá** los datos de **cada campo** de los **form data** en el request y te dará el modelo de Pydantic que definiste.\n\n## Revisa la Documentación { #check-the-docs }\n\nPuedes verificarlo en la interfaz de documentación en `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## Prohibir Campos de Formulario Extra { #forbid-extra-form-fields }\n\nEn algunos casos de uso especiales (probablemente no muy comunes), podrías querer **restringir** los campos de formulario a solo aquellos declarados en el modelo de Pydantic. Y **prohibir** cualquier campo **extra**.\n\n/// note | Nota\n\nEsto es compatible desde la versión `0.114.0` de FastAPI. 🤓\n\n///\n\nPuedes usar la configuración del modelo de Pydantic para `forbid` cualquier campo `extra`:\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\nSi un cliente intenta enviar datos extra, recibirá un response de **error**.\n\nPor ejemplo, si el cliente intenta enviar los campos de formulario:\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\nRecibirá un response de error indicando que el campo `extra` no está permitido:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## Resumen { #summary }\n\nPuedes usar modelos de Pydantic para declarar campos de formulario en FastAPI. 😎\n"
  },
  {
    "path": "docs/es/docs/tutorial/request-forms-and-files.md",
    "content": "# Formularios y archivos del request { #request-forms-and-files }\n\nPuedes definir archivos y campos de formulario al mismo tiempo usando `File` y `Form`.\n\n/// info | Información\n\nPara recibir archivos subidos y/o form data, primero instala [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), actívalo y luego instálalo, por ejemplo:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Importa `File` y `Form` { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## Define parámetros `File` y `Form` { #define-file-and-form-parameters }\n\nCrea parámetros de archivo y formulario de la misma manera que lo harías para `Body` o `Query`:\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\nLos archivos y campos de formulario se subirán como form data y recibirás los archivos y campos de formulario.\n\nY puedes declarar algunos de los archivos como `bytes` y algunos como `UploadFile`.\n\n/// warning | Advertencia\n\nPuedes declarar múltiples parámetros `File` y `Form` en una *path operation*, pero no puedes también declarar campos `Body` que esperas recibir como JSON, ya que el request tendrá el body codificado usando `multipart/form-data` en lugar de `application/json`.\n\nEsto no es una limitación de **FastAPI**, es parte del protocolo HTTP.\n\n///\n\n## Resumen { #recap }\n\nUsa `File` y `Form` juntos cuando necesites recibir datos y archivos en el mismo request.\n"
  },
  {
    "path": "docs/es/docs/tutorial/request-forms.md",
    "content": "# Datos de formulario { #form-data }\n\nCuando necesitas recibir campos de formulario en lugar de JSON, puedes usar `Form`.\n\n/// info | Información\n\nPara usar formularios, primero instala [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo, y luego instalarlo, por ejemplo:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Importar `Form` { #import-form }\n\nImportar `Form` desde `fastapi`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## Definir parámetros de `Form` { #define-form-parameters }\n\nCrea parámetros de formulario de la misma manera que lo harías para `Body` o `Query`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\nPor ejemplo, en una de las formas en las que se puede usar la especificación OAuth2 (llamada \"password flow\") se requiere enviar un `username` y `password` como campos de formulario.\n\nLa <dfn title=\"especificación\">especificación</dfn> requiere que los campos se llamen exactamente `username` y `password`, y que se envíen como campos de formulario, no JSON.\n\nCon `Form` puedes declarar las mismas configuraciones que con `Body` (y `Query`, `Path`, `Cookie`), incluyendo validación, ejemplos, un alias (por ejemplo, `user-name` en lugar de `username`), etc.\n\n/// info | Información\n\n`Form` es una clase que hereda directamente de `Body`.\n\n///\n\n/// tip | Consejo\n\nPara declarar bodies de formularios, necesitas usar `Form` explícitamente, porque sin él, los parámetros se interpretarían como parámetros de query o como parámetros de body (JSON).\n\n///\n\n## Sobre \"Campos de formulario\" { #about-form-fields }\n\nLa manera en que los formularios HTML (`<form></form>`) envían los datos al servidor normalmente usa una codificación \"especial\" para esos datos, es diferente de JSON.\n\n**FastAPI** se encargará de leer esos datos del lugar correcto en lugar de JSON.\n\n/// note | Detalles técnicos\n\nLos datos de formularios normalmente se codifican usando el \"media type\" `application/x-www-form-urlencoded`.\n\nPero cuando el formulario incluye archivos, se codifica como `multipart/form-data`. Leerás sobre la gestión de archivos en el próximo capítulo.\n\nSi quieres leer más sobre estas codificaciones y campos de formulario, dirígete a las [<abbr title=\"Mozilla Developer Network - Red de Desarrolladores de Mozilla\">MDN</abbr> web docs para `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Advertencia\n\nPuedes declarar múltiples parámetros `Form` en una *path operation*, pero no puedes también declarar campos `Body` que esperas recibir como JSON, ya que el request tendrá el body codificado usando `application/x-www-form-urlencoded` en lugar de `application/json`.\n\nEsto no es una limitación de **FastAPI**, es parte del protocolo HTTP.\n\n///\n\n## Recapitulación { #recap }\n\nUsa `Form` para declarar parámetros de entrada de datos de formulario.\n"
  },
  {
    "path": "docs/es/docs/tutorial/response-model.md",
    "content": "# Modelo de Response - Tipo de Retorno { #response-model-return-type }\n\nPuedes declarar el tipo utilizado para el response anotando el **tipo de retorno** de la *path operation function*.\n\nPuedes utilizar **anotaciones de tipos** de la misma manera que lo harías para datos de entrada en **parámetros** de función, puedes utilizar modelos de Pydantic, lists, diccionarios, valores escalares como enteros, booleanos, etc.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPI usará este tipo de retorno para:\n\n* **Validar** los datos devueltos.\n    * Si los datos son inválidos (por ejemplo, falta un campo), significa que el código de *tu* aplicación está defectuoso, no devolviendo lo que debería, y retornará un error del servidor en lugar de devolver datos incorrectos. De esta manera, tú y tus clientes pueden estar seguros de que recibirán los datos y la forma de los datos esperada.\n* Agregar un **JSON Schema** para el response, en la *path operation* de OpenAPI.\n    * Esto será utilizado por la **documentación automática**.\n    * También será utilizado por herramientas de generación automática de código de cliente.\n* **Serializar** los datos devueltos a JSON usando Pydantic, que está escrito en **Rust**, por lo que será **mucho más rápido**.\n\nPero lo más importante:\n\n* **Limitará y filtrará** los datos de salida a lo que se define en el tipo de retorno.\n    * Esto es particularmente importante para la **seguridad**, veremos más sobre eso a continuación.\n\n## Parámetro `response_model` { #response-model-parameter }\n\nHay algunos casos en los que necesitas o quieres devolver algunos datos que no son exactamente lo que declara el tipo.\n\nPor ejemplo, podrías querer **devolver un diccionario** u objeto de base de datos, pero **declararlo como un modelo de Pydantic**. De esta manera el modelo de Pydantic haría toda la documentación de datos, validación, etc. para el objeto que devolviste (por ejemplo, un diccionario u objeto de base de datos).\n\nSi añadiste la anotación del tipo de retorno, las herramientas y editores se quejarían con un error (correcto) diciéndote que tu función está devolviendo un tipo (por ejemplo, un dict) que es diferente de lo que declaraste (por ejemplo, un modelo de Pydantic).\n\nEn esos casos, puedes usar el parámetro del *decorador de path operation* `response_model` en lugar del tipo de retorno.\n\nPuedes usar el parámetro `response_model` en cualquiera de las *path operations*:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* etc.\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | Nota\n\nObserva que `response_model` es un parámetro del método \"decorador\" (`get`, `post`, etc). No de tu *path operation function*, como todos los parámetros y el cuerpo.\n\n///\n\n`response_model` recibe el mismo tipo que declararías para un campo de modelo Pydantic, por lo que puede ser un modelo de Pydantic, pero también puede ser, por ejemplo, un `list` de modelos de Pydantic, como `List[Item]`.\n\nFastAPI usará este `response_model` para hacer toda la documentación de datos, validación, etc. y también para **convertir y filtrar los datos de salida** a su declaración de tipo.\n\n/// tip | Consejo\n\nSi tienes chequeo de tipos estricto en tu editor, mypy, etc., puedes declarar el tipo de retorno de la función como `Any`.\n\nDe esa manera le dices al editor que intencionalmente estás devolviendo cualquier cosa. Pero FastAPI todavía hará la documentación de datos, validación, filtrado, etc. con `response_model`.\n\n///\n\n### Prioridad del `response_model` { #response-model-priority }\n\nSi declaras tanto un tipo de retorno como un `response_model`, el `response_model` tomará prioridad y será utilizado por FastAPI.\n\nDe esta manera puedes añadir anotaciones de tipos correctas a tus funciones incluso cuando estás devolviendo un tipo diferente al modelo de response, para ser utilizado por el editor y herramientas como mypy. Y aún así puedes hacer que FastAPI realice la validación de datos, documentación, etc. usando el `response_model`.\n\nTambién puedes usar `response_model=None` para desactivar la creación de un modelo de response para esa *path operation*, podrías necesitar hacerlo si estás añadiendo anotaciones de tipos para cosas que no son campos válidos de Pydantic, verás un ejemplo de eso en una de las secciones a continuación.\n\n## Devolver los mismos datos de entrada { #return-the-same-input-data }\n\nAquí estamos declarando un modelo `UserIn`, contendrá una contraseña en texto plano:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | Información\n\nPara usar `EmailStr`, primero instala [`email-validator`](https://github.com/JoshData/python-email-validator).\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo, y luego instalarlo, por ejemplo:\n\n```console\n$ pip install email-validator\n```\n\no con:\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\nY estamos usando este modelo para declarar nuestra entrada y el mismo modelo para declarar nuestra salida:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\nAhora, cada vez que un navegador esté creando un usuario con una contraseña, la API devolverá la misma contraseña en el response.\n\nEn este caso, podría no ser un problema, porque es el mismo usuario que envía la contraseña.\n\nPero si usamos el mismo modelo para otra *path operation*, podríamos estar enviando las contraseñas de nuestros usuarios a cada cliente.\n\n/// danger | Peligro\n\nNunca almacenes la contraseña en texto plano de un usuario ni la envíes en un response como esta, a menos que conozcas todas las advertencias y sepas lo que estás haciendo.\n\n///\n\n## Añadir un modelo de salida { #add-an-output-model }\n\nPodemos en cambio crear un modelo de entrada con la contraseña en texto plano y un modelo de salida sin ella:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\nAquí, aunque nuestra *path operation function* está devolviendo el mismo usuario de entrada que contiene la contraseña:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n...hemos declarado el `response_model` para ser nuestro modelo `UserOut`, que no incluye la contraseña:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\nEntonces, **FastAPI** se encargará de filtrar todos los datos que no estén declarados en el modelo de salida (usando Pydantic).\n\n### `response_model` o Tipo de Retorno { #response-model-or-return-type }\n\nEn este caso, como los dos modelos son diferentes, si anotáramos el tipo de retorno de la función como `UserOut`, el editor y las herramientas se quejarían de que estamos devolviendo un tipo inválido, ya que son clases diferentes.\n\nPor eso en este ejemplo tenemos que declararlo en el parámetro `response_model`.\n\n...pero sigue leyendo abajo para ver cómo superar eso.\n\n## Tipo de Retorno y Filtrado de Datos { #return-type-and-data-filtering }\n\nContinuemos con el ejemplo anterior. Queríamos **anotar la función con un tipo**, pero queríamos poder devolver desde la función algo que en realidad incluya **más datos**.\n\nQueremos que FastAPI continúe **filtrando** los datos usando el modelo de response. Para que, incluso cuando la función devuelva más datos, el response solo incluya los campos declarados en el modelo de response.\n\nEn el ejemplo anterior, debido a que las clases eran diferentes, tuvimos que usar el parámetro `response_model`. Pero eso también significa que no obtenemos el soporte del editor y las herramientas verificando el tipo de retorno de la función.\n\nPero en la mayoría de los casos en los que necesitamos hacer algo como esto, queremos que el modelo solo **filtre/elimine** algunos de los datos como en este ejemplo.\n\nY en esos casos, podemos usar clases y herencia para aprovechar las **anotaciones de tipos** de funciones para obtener mejor soporte en el editor y herramientas, y aún así obtener el **filtrado de datos** de FastAPI.\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\nCon esto, obtenemos soporte de las herramientas, de los editores y mypy ya que este código es correcto en términos de tipos, pero también obtenemos el filtrado de datos de FastAPI.\n\n¿Cómo funciona esto? Vamos a echarle un vistazo. 🤓\n\n### Anotaciones de Tipos y Herramientas { #type-annotations-and-tooling }\n\nPrimero vamos a ver cómo los editores, mypy y otras herramientas verían esto.\n\n`BaseUser` tiene los campos base. Luego `UserIn` hereda de `BaseUser` y añade el campo `password`, por lo que incluirá todos los campos de ambos modelos.\n\nAnotamos el tipo de retorno de la función como `BaseUser`, pero en realidad estamos devolviendo un `UserIn` instance.\n\nEl editor, mypy y otras herramientas no se quejarán de esto porque, en términos de tipificación, `UserIn` es una subclase de `BaseUser`, lo que significa que es un tipo *válido* cuando se espera algo que es un `BaseUser`.\n\n### Filtrado de Datos en FastAPI { #fastapi-data-filtering }\n\nAhora, para FastAPI, verá el tipo de retorno y se asegurará de que lo que devuelves incluya **solo** los campos que están declarados en el tipo.\n\nFastAPI realiza varias cosas internamente con Pydantic para asegurarse de que esas mismas reglas de herencia de clases no se utilicen para el filtrado de datos devueltos, de lo contrario, podrías terminar devolviendo muchos más datos de los que esperabas.\n\nDe esta manera, puedes obtener lo mejor de ambos mundos: anotaciones de tipos con **soporte de herramientas** y **filtrado de datos**.\n\n## Verlo en la documentación { #see-it-in-the-docs }\n\nCuando veas la documentación automática, puedes verificar que el modelo de entrada y el modelo de salida tendrán cada uno su propio JSON Schema:\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\nY ambos modelos se utilizarán para la documentación interactiva de la API:\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## Otras Anotaciones de Tipos de Retorno { #other-return-type-annotations }\n\nPodría haber casos en los que devuelvas algo que no es un campo válido de Pydantic y lo anotes en la función, solo para obtener el soporte proporcionado por las herramientas (el editor, mypy, etc).\n\n### Devolver un Response Directamente { #return-a-response-directly }\n\nEl caso más común sería [devolver un Response directamente como se explica más adelante en la documentación avanzada](../advanced/response-directly.md).\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\nEste caso simple es manejado automáticamente por FastAPI porque la anotación del tipo de retorno es la clase (o una subclase de) `Response`.\n\nY las herramientas también estarán felices porque tanto `RedirectResponse` como `JSONResponse` son subclases de `Response`, por lo que la anotación del tipo es correcta.\n\n### Anotar una Subclase de Response { #annotate-a-response-subclass }\n\nTambién puedes usar una subclase de `Response` en la anotación del tipo:\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\nEsto también funcionará porque `RedirectResponse` es una subclase de `Response`, y FastAPI manejará automáticamente este caso simple.\n\n### Anotaciones de Tipos de Retorno Inválidas { #invalid-return-type-annotations }\n\nPero cuando devuelves algún otro objeto arbitrario que no es un tipo válido de Pydantic (por ejemplo, un objeto de base de datos) y lo anotas así en la función, FastAPI intentará crear un modelo de response de Pydantic a partir de esa anotación de tipo, y fallará.\n\nLo mismo sucedería si tuvieras algo como una <dfn title='una unión entre múltiples tipos significa \"cualquiera de estos tipos\".'>unión</dfn> entre diferentes tipos donde uno o más de ellos no son tipos válidos de Pydantic, por ejemplo esto fallaría 💥:\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n...esto falla porque la anotación de tipo no es un tipo de Pydantic y no es solo una sola clase `Response` o subclase, es una unión (cualquiera de los dos) entre una `Response` y un `dict`.\n\n### Desactivar el Modelo de Response { #disable-response-model }\n\nContinuando con el ejemplo anterior, puede que no quieras tener la validación de datos por defecto, documentación, filtrado, etc. que realiza FastAPI.\n\nPero puedes querer mantener la anotación del tipo de retorno en la función para obtener el soporte de herramientas como editores y verificadores de tipos (por ejemplo, mypy).\n\nEn este caso, puedes desactivar la generación del modelo de response configurando `response_model=None`:\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\nEsto hará que FastAPI omita la generación del modelo de response y de esa manera puedes tener cualquier anotación de tipo de retorno que necesites sin que afecte a tu aplicación FastAPI. 🤓\n\n## Parámetros de codificación del Modelo de Response { #response-model-encoding-parameters }\n\nTu modelo de response podría tener valores por defecto, como:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None` (o `str | None = None` en Python 3.10) tiene un valor por defecto de `None`.\n* `tax: float = 10.5` tiene un valor por defecto de `10.5`.\n* `tags: List[str] = []` tiene un valor por defecto de una list vacía: `[]`.\n\npero podrías querer omitirlos del resultado si no fueron en realidad almacenados.\n\nPor ejemplo, si tienes modelos con muchos atributos opcionales en una base de datos NoSQL, pero no quieres enviar responses JSON muy largos llenos de valores por defecto.\n\n### Usa el parámetro `response_model_exclude_unset` { #use-the-response-model-exclude-unset-parameter }\n\nPuedes configurar el parámetro del decorador de path operation `response_model_exclude_unset=True`:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\ny esos valores por defecto no serán incluidos en el response, solo los valores realmente establecidos.\n\nEntonces, si envías un request a esa *path operation* para el ítem con ID `foo`, el response (no incluyendo valores por defecto) será:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | Información\n\nTambién puedes usar:\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\ncomo se describe en [la documentación de Pydantic](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict) para `exclude_defaults` y `exclude_none`.\n\n///\n\n#### Datos con valores para campos con valores por defecto { #data-with-values-for-fields-with-defaults }\n\nPero si tus datos tienen valores para los campos del modelo con valores por defecto, como el artículo con ID `bar`:\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\nserán incluidos en el response.\n\n#### Datos con los mismos valores que los valores por defecto { #data-with-the-same-values-as-the-defaults }\n\nSi los datos tienen los mismos valores que los valores por defecto, como el artículo con ID `baz`:\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nFastAPI es lo suficientemente inteligente (de hecho, Pydantic es lo suficientemente inteligente) para darse cuenta de que, a pesar de que `description`, `tax` y `tags` tienen los mismos valores que los valores por defecto, fueron establecidos explícitamente (en lugar de tomados de los valores por defecto).\n\nPor lo tanto, se incluirán en el response JSON.\n\n/// tip | Consejo\n\nTen en cuenta que los valores por defecto pueden ser cualquier cosa, no solo `None`.\n\nPueden ser una list (`[]`), un `float` de `10.5`, etc.\n\n///\n\n### `response_model_include` y `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\nTambién puedes usar los parámetros del decorador de path operation `response_model_include` y `response_model_exclude`.\n\nAceptan un `set` de `str` con el nombre de los atributos a incluir (omitiendo el resto) o excluir (incluyendo el resto).\n\nEsto se puede usar como un atajo rápido si solo tienes un modelo de Pydantic y quieres eliminar algunos datos de la salida.\n\n/// tip | Consejo\n\nPero todavía se recomienda usar las ideas anteriores, usando múltiples clases, en lugar de estos parámetros.\n\nEsto se debe a que el JSON Schema generado en el OpenAPI de tu aplicación (y la documentación) aún será el del modelo completo, incluso si usas `response_model_include` o `response_model_exclude` para omitir algunos atributos.\n\nEsto también se aplica a `response_model_by_alias` que funciona de manera similar.\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | Consejo\n\nLa sintaxis `{\"name\", \"description\"}` crea un `set` con esos dos valores.\n\nEs equivalente a `set([\"name\", \"description\"])`.\n\n///\n\n#### Usar `list`s en lugar de `set`s { #using-lists-instead-of-sets }\n\nSi olvidas usar un `set` y usas un `list` o `tuple` en su lugar, FastAPI todavía lo convertirá a un `set` y funcionará correctamente:\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## Resumen { #recap }\n\nUsa el parámetro `response_model` del *decorador de path operation* para definir modelos de response y especialmente para asegurarte de que los datos privados sean filtrados.\n\nUsa `response_model_exclude_unset` para devolver solo los valores establecidos explícitamente.\n"
  },
  {
    "path": "docs/es/docs/tutorial/response-status-code.md",
    "content": "# Código de Estado del Response { #response-status-code }\n\nDe la misma manera que puedes especificar un modelo de response, también puedes declarar el código de estado HTTP usado para el response con el parámetro `status_code` en cualquiera de las *path operations*:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* etc.\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | Nota\n\nObserva que `status_code` es un parámetro del método \"decorador\" (`get`, `post`, etc). No de tu *path operation function*, como todos los parámetros y body.\n\n///\n\nEl parámetro `status_code` recibe un número con el código de estado HTTP.\n\n/// info | Información\n\n`status_code` también puede recibir un `IntEnum`, como por ejemplo el [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus) de Python.\n\n///\n\nEsto hará:\n\n* Devolver ese código de estado en el response.\n* Documentarlo como tal en el esquema de OpenAPI (y por lo tanto, en las interfaces de usuario):\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | Nota\n\nAlgunos códigos de response (ver la siguiente sección) indican que el response no tiene un body.\n\nFastAPI sabe esto, y producirá documentación OpenAPI que establece que no hay un response body.\n\n///\n\n## Acerca de los códigos de estado HTTP { #about-http-status-codes }\n\n/// note | Nota\n\nSi ya sabes qué son los códigos de estado HTTP, salta a la siguiente sección.\n\n///\n\nEn HTTP, envías un código de estado numérico de 3 dígitos como parte del response.\n\nEstos códigos de estado tienen un nombre asociado para reconocerlos, pero la parte importante es el número.\n\nEn breve:\n\n* `100 - 199` son para \"Información\". Rara vez los usas directamente. Los responses con estos códigos de estado no pueden tener un body.\n* **`200 - 299`** son para responses \"Exitosos\". Estos son los que usarías más.\n    * `200` es el código de estado por defecto, lo que significa que todo estaba \"OK\".\n    * Otro ejemplo sería `201`, \"Created\". Comúnmente se usa después de crear un nuevo registro en la base de datos.\n    * Un caso especial es `204`, \"No Content\". Este response se usa cuando no hay contenido para devolver al cliente, por lo tanto, el response no debe tener un body.\n* **`300 - 399`** son para \"Redirección\". Los responses con estos códigos de estado pueden o no tener un body, excepto `304`, \"Not Modified\", que no debe tener uno.\n* **`400 - 499`** son para responses de \"Error del Cliente\". Este es el segundo tipo que probablemente más usarías.\n    * Un ejemplo es `404`, para un response \"Not Found\".\n    * Para errores genéricos del cliente, puedes usar simplemente `400`.\n* `500 - 599` son para errores del servidor. Casi nunca los usas directamente. Cuando algo sale mal en alguna parte de tu código de aplicación, o del servidor, automáticamente devolverá uno de estos códigos de estado.\n\n/// tip | Consejo\n\nPara saber más sobre cada código de estado y qué código es para qué, revisa la [documentación de <abbr title=\"Mozilla Developer Network - Red de Desarrolladores de Mozilla\">MDN</abbr> sobre códigos de estado HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).\n\n///\n\n## Atajo para recordar los nombres { #shortcut-to-remember-the-names }\n\nVeamos de nuevo el ejemplo anterior:\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201` es el código de estado para \"Created\".\n\nPero no tienes que memorizar lo que significa cada uno de estos códigos.\n\nPuedes usar las variables de conveniencia de `fastapi.status`.\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\nSon solo una conveniencia, mantienen el mismo número, pero de esa manera puedes usar el autocompletado del editor para encontrarlos:\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | Detalles técnicos\n\nTambién podrías usar `from starlette import status`.\n\n**FastAPI** proporciona el mismo `starlette.status` como `fastapi.status` solo como una conveniencia para ti, el desarrollador. Pero proviene directamente de Starlette.\n\n///\n\n## Cambiando el valor por defecto { #changing-the-default }\n\nMás adelante, en la [Guía de Usuario Avanzada](../advanced/response-change-status-code.md), verás cómo devolver un código de estado diferente al valor por defecto que estás declarando aquí.\n"
  },
  {
    "path": "docs/es/docs/tutorial/schema-extra-example.md",
    "content": "# Declarar Datos de Ejemplo de Request { #declare-request-example-data }\n\nPuedes declarar ejemplos de los datos que tu aplicación puede recibir.\n\nAquí tienes varias formas de hacerlo.\n\n## Datos extra de JSON Schema en modelos de Pydantic { #extra-json-schema-data-in-pydantic-models }\n\nPuedes declarar `examples` para un modelo de Pydantic que se añadirá al JSON Schema generado.\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\nEsa información extra se añadirá tal cual al **JSON Schema** resultante para ese modelo, y se usará en la documentación de la API.\n\nPuedes usar el atributo `model_config` que toma un `dict` como se describe en [Documentación de Pydantic: Configuración](https://docs.pydantic.dev/latest/api/config/).\n\nPuedes establecer `\"json_schema_extra\"` con un `dict` que contenga cualquier dato adicional que te gustaría que aparezca en el JSON Schema generado, incluyendo `examples`.\n\n/// tip | Consejo\n\nPodrías usar la misma técnica para extender el JSON Schema y añadir tu propia información extra personalizada.\n\nPor ejemplo, podrías usarlo para añadir metadatos para una interfaz de usuario frontend, etc.\n\n///\n\n/// info | Información\n\nOpenAPI 3.1.0 (usado desde FastAPI 0.99.0) añadió soporte para `examples`, que es parte del estándar de **JSON Schema**.\n\nAntes de eso, solo soportaba la palabra clave `example` con un solo ejemplo. Eso aún es soportado por OpenAPI 3.1.0, pero está obsoleto y no es parte del estándar de JSON Schema. Así que se te anima a migrar `example` a `examples`. 🤓\n\nPuedes leer más al final de esta página.\n\n///\n\n## Argumentos adicionales en `Field` { #field-additional-arguments }\n\nCuando usas `Field()` con modelos de Pydantic, también puedes declarar `examples` adicionales:\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## `examples` en JSON Schema - OpenAPI { #examples-in-json-schema-openapi }\n\nCuando usas cualquiera de:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\ntambién puedes declarar un grupo de `examples` con información adicional que se añadirá a sus **JSON Schemas** dentro de **OpenAPI**.\n\n### `Body` con `examples` { #body-with-examples }\n\nAquí pasamos `examples` que contiene un ejemplo de los datos esperados en `Body()`:\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### Ejemplo en la interfaz de documentación { #example-in-the-docs-ui }\n\nCon cualquiera de los métodos anteriores se vería así en los `/docs`:\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### `Body` con múltiples `examples` { #body-with-multiple-examples }\n\nPor supuesto, también puedes pasar múltiples `examples`:\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\nCuando haces esto, los ejemplos serán parte del **JSON Schema** interno para esos datos del body.\n\nSin embargo, al <dfn title=\"2023-08-26\">momento de escribir esto</dfn>, Swagger UI, la herramienta encargada de mostrar la interfaz de documentación, no soporta mostrar múltiples ejemplos para los datos en **JSON Schema**. Pero lee más abajo para una solución alternativa.\n\n### `examples` específicos de OpenAPI { #openapi-specific-examples }\n\nDesde antes de que **JSON Schema** soportara `examples`, OpenAPI tenía soporte para un campo diferente también llamado `examples`.\n\nEstos `examples` específicos de **OpenAPI** van en otra sección en la especificación de OpenAPI. Van en los **detalles para cada *path operation***, no dentro de cada JSON Schema.\n\nY Swagger UI ha soportado este campo particular de `examples` por un tiempo. Así que, puedes usarlo para **mostrar** diferentes **ejemplos en la interfaz de documentación**.\n\nLa forma de este campo específico de OpenAPI `examples` es un `dict` con **múltiples ejemplos** (en lugar de una `list`), cada uno con información adicional que también se añadirá a **OpenAPI**.\n\nEsto no va dentro de cada JSON Schema contenido en OpenAPI, esto va afuera, directamente en la *path operation*.\n\n### Usando el Parámetro `openapi_examples` { #using-the-openapi-examples-parameter }\n\nPuedes declarar los `examples` específicos de OpenAPI en FastAPI con el parámetro `openapi_examples` para:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nLas claves del `dict` identifican cada ejemplo, y cada valor es otro `dict`.\n\nCada `dict` específico del ejemplo en los `examples` puede contener:\n\n* `summary`: Descripción corta del ejemplo.\n* `description`: Una descripción larga que puede contener texto Markdown.\n* `value`: Este es el ejemplo real mostrado, e.g. un `dict`.\n* `externalValue`: alternativa a `value`, una URL que apunta al ejemplo. Aunque esto puede no ser soportado por tantas herramientas como `value`.\n\nPuedes usarlo así:\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### Ejemplos de OpenAPI en la Interfaz de Documentación { #openapi-examples-in-the-docs-ui }\n\nCon `openapi_examples` añadido a `Body()`, los `/docs` se verían así:\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## Detalles Técnicos { #technical-details }\n\n/// tip | Consejo\n\nSi ya estás usando la versión **0.99.0 o superior** de **FastAPI**, probablemente puedes **omitir** estos detalles.\n\nSon más relevantes para versiones más antiguas, antes de que OpenAPI 3.1.0 estuviera disponible.\n\nPuedes considerar esto una breve lección de **historia** de OpenAPI y JSON Schema. 🤓\n\n///\n\n/// warning | Advertencia\n\nEstos son detalles muy técnicos sobre los estándares **JSON Schema** y **OpenAPI**.\n\nSi las ideas anteriores ya funcionan para ti, eso podría ser suficiente, y probablemente no necesites estos detalles, siéntete libre de omitirlos.\n\n///\n\nAntes de OpenAPI 3.1.0, OpenAPI usaba una versión más antigua y modificada de **JSON Schema**.\n\nJSON Schema no tenía `examples`, así que OpenAPI añadió su propio campo `example` a su versión modificada.\n\nOpenAPI también añadió los campos `example` y `examples` a otras partes de la especificación:\n\n* [`Parameter Object` (en la especificación)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object) que era usado por FastAPI:\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object`, en el campo `content`, sobre el `Media Type Object` (en la especificación)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object) que era usado por FastAPI:\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info | Información\n\nEste viejo parámetro `examples` específico de OpenAPI ahora es `openapi_examples` desde FastAPI `0.103.0`.\n\n///\n\n### Campo `examples` de JSON Schema { #json-schemas-examples-field }\n\nPero luego JSON Schema añadió un [campo `examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5) a una nueva versión de la especificación.\n\nY entonces el nuevo OpenAPI 3.1.0 se basó en la última versión (JSON Schema 2020-12) que incluía este nuevo campo `examples`.\n\nY ahora este nuevo campo `examples` tiene precedencia sobre el viejo campo único (y personalizado) `example`, que ahora está obsoleto.\n\nEste nuevo campo `examples` en JSON Schema es **solo una `list`** de ejemplos, no un dict con metadatos adicionales como en los otros lugares en OpenAPI (descritos arriba).\n\n/// info | Información\n\nIncluso después de que OpenAPI 3.1.0 fue lanzado con esta nueva integración más sencilla con JSON Schema, por un tiempo, Swagger UI, la herramienta que proporciona la documentación automática, no soportaba OpenAPI 3.1.0 (lo hace desde la versión 5.0.0 🎉).\n\nDebido a eso, las versiones de FastAPI anteriores a 0.99.0 todavía usaban versiones de OpenAPI menores a 3.1.0.\n\n///\n\n### `examples` de Pydantic y FastAPI { #pydantic-and-fastapi-examples }\n\nCuando añades `examples` dentro de un modelo de Pydantic, usando `schema_extra` o `Field(examples=[\"something\"])`, ese ejemplo se añade al **JSON Schema** para ese modelo de Pydantic.\n\nY ese **JSON Schema** del modelo de Pydantic se incluye en el **OpenAPI** de tu API, y luego se usa en la interfaz de documentación.\n\nEn las versiones de FastAPI antes de 0.99.0 (0.99.0 y superiores usan el nuevo OpenAPI 3.1.0) cuando usabas `example` o `examples` con cualquiera de las otras utilidades (`Query()`, `Body()`, etc.) esos ejemplos no se añadían al JSON Schema que describe esos datos (ni siquiera a la propia versión de JSON Schema de OpenAPI), se añadían directamente a la declaración de la *path operation* en OpenAPI (fuera de las partes de OpenAPI que usan JSON Schema).\n\nPero ahora que FastAPI 0.99.0 y superiores usa OpenAPI 3.1.0, que usa JSON Schema 2020-12, y Swagger UI 5.0.0 y superiores, todo es más consistente y los ejemplos se incluyen en JSON Schema.\n\n### Swagger UI y `examples` específicos de OpenAPI { #swagger-ui-and-openapi-specific-examples }\n\nAhora, como Swagger UI no soportaba múltiples ejemplos de JSON Schema (a fecha de 2023-08-26), los usuarios no tenían una forma de mostrar múltiples ejemplos en la documentación.\n\nPara resolver eso, FastAPI `0.103.0` **añadió soporte** para declarar el mismo viejo campo **específico de OpenAPI** `examples` con el nuevo parámetro `openapi_examples`. 🤓\n\n### Resumen { #summary }\n\nSolía decir que no me gustaba mucho la historia... y mírame ahora dando lecciones de \"historia tecnológica\". 😅\n\nEn resumen, **actualiza a FastAPI 0.99.0 o superior**, y las cosas son mucho **más simples, consistentes e intuitivas**, y no necesitas conocer todos estos detalles históricos. 😎\n"
  },
  {
    "path": "docs/es/docs/tutorial/security/first-steps.md",
    "content": "# Seguridad - Primeros pasos { #security-first-steps }\n\nImaginemos que tienes tu API de **backend** en algún dominio.\n\nY tienes un **frontend** en otro dominio o en un path diferente del mismo dominio (o en una aplicación móvil).\n\nY quieres tener una forma para que el frontend se autentique con el backend, usando un **username** y **password**.\n\nPodemos usar **OAuth2** para construir eso con **FastAPI**.\n\nPero vamos a ahorrarte el tiempo de leer la larga especificación completa solo para encontrar esos pequeños fragmentos de información que necesitas.\n\nUsemos las herramientas proporcionadas por **FastAPI** para manejar la seguridad.\n\n## Cómo se ve { #how-it-looks }\n\nPrimero solo usemos el código y veamos cómo funciona, y luego volveremos para entender qué está sucediendo.\n\n## Crea `main.py` { #create-main-py }\n\nCopia el ejemplo en un archivo `main.py`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## Ejecútalo { #run-it }\n\n/// info | Información\n\nEl paquete [`python-multipart`](https://github.com/Kludex/python-multipart) se instala automáticamente con **FastAPI** cuando ejecutas el comando `pip install \"fastapi[standard]\"`.\n\nSin embargo, si usas el comando `pip install fastapi`, el paquete `python-multipart` no se incluye por defecto.\n\nPara instalarlo manualmente, asegúrate de crear un [entorno virtual](../../virtual-environments.md), activarlo, y luego instalarlo con:\n\n```console\n$ pip install python-multipart\n```\n\nEsto se debe a que **OAuth2** utiliza \"form data\" para enviar el `username` y `password`.\n\n///\n\nEjecuta el ejemplo con:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## Revisa { #check-it }\n\nVe a la documentación interactiva en: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVerás algo así:\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | ¡Botón de autorización!\n\nYa tienes un nuevo y brillante botón de \"Authorize\".\n\nY tu *path operation* tiene un pequeño candado en la esquina superior derecha que puedes pulsar.\n\n///\n\nY si lo haces, tendrás un pequeño formulario de autorización para escribir un `username` y `password` (y otros campos opcionales):\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | Nota\n\nNo importa lo que escribas en el formulario, aún no funcionará. Pero llegaremos allí.\n\n///\n\nEsto por supuesto no es el frontend para los usuarios finales, pero es una gran herramienta automática para documentar interactivamente toda tu API.\n\nPuede ser utilizada por el equipo de frontend (que también puedes ser tú mismo).\n\nPuede ser utilizada por aplicaciones y sistemas de terceros.\n\nY también puede ser utilizada por ti mismo, para depurar, revisar y probar la misma aplicación.\n\n## El flujo `password` { #the-password-flow }\n\nAhora retrocedamos un poco y entendamos qué es todo eso.\n\nEl \"flujo\" `password` es una de las formas (\"flujos\") definidas en OAuth2, para manejar la seguridad y la autenticación.\n\nOAuth2 fue diseñado para que el backend o la API pudieran ser independientes del servidor que autentica al usuario.\n\nPero en este caso, la misma aplicación de **FastAPI** manejará la API y la autenticación.\n\nAsí que, revisémoslo desde ese punto de vista simplificado:\n\n* El usuario escribe el `username` y `password` en el frontend, y presiona `Enter`.\n* El frontend (ejecutándose en el navegador del usuario) envía ese `username` y `password` a una URL específica en nuestra API (declarada con `tokenUrl=\"token\"`).\n* La API verifica ese `username` y `password`, y responde con un \"token\" (no hemos implementado nada de esto aún).\n    * Un \"token\" es solo un string con algún contenido que podemos usar luego para verificar a este usuario.\n    * Normalmente, un token se establece para que expire después de algún tiempo.\n        * Así que, el usuario tendrá que volver a iniciar sesión más adelante.\n        * Y si el token es robado, el riesgo es menor. No es como una llave permanente que funcionará para siempre (en la mayoría de los casos).\n* El frontend almacena temporalmente ese token en algún lugar.\n* El usuario hace clic en el frontend para ir a otra sección de la aplicación web frontend.\n* El frontend necesita obtener más datos de la API.\n    * Pero necesita autenticación para ese endpoint específico.\n    * Así que, para autenticarse con nuestra API, envía un `header` `Authorization` con un valor de `Bearer ` más el token.\n    * Si el token contiene `foobar`, el contenido del `header` `Authorization` sería: `Bearer foobar`.\n\n## `OAuth2PasswordBearer` de **FastAPI** { #fastapis-oauth2passwordbearer }\n\n**FastAPI** proporciona varias herramientas, en diferentes niveles de abstracción, para implementar estas funcionalidades de seguridad.\n\nEn este ejemplo vamos a usar **OAuth2**, con el flujo **Password**, usando un token **Bearer**. Hacemos eso utilizando la clase `OAuth2PasswordBearer`.\n\n/// info | Información\n\nUn token \"bearer\" no es la única opción.\n\nPero es la mejor para nuestro caso de uso.\n\nY podría ser la mejor para la mayoría de los casos de uso, a menos que seas un experto en OAuth2 y sepas exactamente por qué hay otra opción que se adapta mejor a tus necesidades.\n\nEn ese caso, **FastAPI** también te proporciona las herramientas para construirlo.\n\n///\n\nCuando creamos una instance de la clase `OAuth2PasswordBearer` pasamos el parámetro `tokenUrl`. Este parámetro contiene la URL que el cliente (el frontend corriendo en el navegador del usuario) usará para enviar el `username` y `password` a fin de obtener un token.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip | Consejo\n\nAquí `tokenUrl=\"token\"` se refiere a una URL relativa `token` que aún no hemos creado. Como es una URL relativa, es equivalente a `./token`.\n\nPorque estamos usando una URL relativa, si tu API estuviera ubicada en `https://example.com/`, entonces se referiría a `https://example.com/token`. Pero si tu API estuviera ubicada en `https://example.com/api/v1/`, entonces se referiría a `https://example.com/api/v1/token`.\n\nUsar una URL relativa es importante para asegurarse de que tu aplicación siga funcionando incluso en un caso de uso avanzado como [Detrás de un Proxy](../../advanced/behind-a-proxy.md).\n\n///\n\nEste parámetro no crea ese endpoint / *path operation*, pero declara que la URL `/token` será la que el cliente deberá usar para obtener el token. Esa información se usa en OpenAPI, y luego en los sistemas de documentación interactiva del API.\n\nPronto también crearemos la verdadera *path operation*.\n\n/// info | Información\n\nSi eres un \"Pythonista\" muy estricto, tal vez no te guste el estilo del nombre del parámetro `tokenUrl` en lugar de `token_url`.\n\nEso es porque está usando el mismo nombre que en la especificación de OpenAPI. Para que si necesitas investigar más sobre cualquiera de estos esquemas de seguridad, puedas simplemente copiarlo y pegarlo para encontrar más información al respecto.\n\n///\n\nLa variable `oauth2_scheme` es una instance de `OAuth2PasswordBearer`, pero también es un \"callable\".\n\nPodría ser llamada como:\n\n```Python\noauth2_scheme(some, parameters)\n```\n\nAsí que, puede usarse con `Depends`.\n\n### Úsalo { #use-it }\n\nAhora puedes pasar ese `oauth2_scheme` en una dependencia con `Depends`.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nEsta dependencia proporcionará un `str` que se asigna al parámetro `token` de la *path operation function*.\n\n**FastAPI** sabrá que puede usar esta dependencia para definir un \"security scheme\" en el esquema OpenAPI (y en los docs automáticos del API).\n\n/// info | Detalles técnicos\n\n**FastAPI** sabrá que puede usar la clase `OAuth2PasswordBearer` (declarada en una dependencia) para definir el esquema de seguridad en OpenAPI porque hereda de `fastapi.security.oauth2.OAuth2`, que a su vez hereda de `fastapi.security.base.SecurityBase`.\n\nTodas las utilidades de seguridad que se integran con OpenAPI (y los docs automáticos del API) heredan de `SecurityBase`, así es como **FastAPI** puede saber cómo integrarlas en OpenAPI.\n\n///\n\n## Lo que hace { #what-it-does }\n\nIrá y buscará en el request ese header `Authorization`, verificará si el valor es `Bearer ` más algún token, y devolverá el token como un `str`.\n\nSi no ve un header `Authorization`, o el valor no tiene un token `Bearer `, responderá directamente con un error de código de estado 401 (`UNAUTHORIZED`).\n\nNi siquiera tienes que verificar si el token existe para devolver un error. Puedes estar seguro de que si tu función se ejecuta, tendrá un `str` en ese token.\n\nPuedes probarlo ya en los docs interactivos:\n\n<img src=\"/img/tutorial/security/image03.png\">\n\nTodavía no estamos verificando la validez del token, pero ya es un comienzo.\n\n## Resumen { #recap }\n\nAsí que, en solo 3 o 4 líneas adicionales, ya tienes alguna forma primitiva de seguridad.\n"
  },
  {
    "path": "docs/es/docs/tutorial/security/get-current-user.md",
    "content": "# Obtener Usuario Actual { #get-current-user }\n\nEn el capítulo anterior, el sistema de seguridad (que se basa en el sistema de inyección de dependencias) le estaba dando a la *path operation function* un `token` como un `str`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nPero eso aún no es tan útil. Vamos a hacer que nos dé el usuario actual.\n\n## Crear un modelo de usuario { #create-a-user-model }\n\nPrimero, vamos a crear un modelo de usuario con Pydantic.\n\nDe la misma manera que usamos Pydantic para declarar cuerpos, podemos usarlo en cualquier otra parte:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## Crear una dependencia `get_current_user` { #create-a-get-current-user-dependency }\n\nVamos a crear una dependencia `get_current_user`.\n\n¿Recuerdas que las dependencias pueden tener sub-dependencias?\n\n`get_current_user` tendrá una dependencia con el mismo `oauth2_scheme` que creamos antes.\n\nDe la misma manera que estábamos haciendo antes en la *path operation* directamente, nuestra nueva dependencia `get_current_user` recibirá un `token` como un `str` de la sub-dependencia `oauth2_scheme`:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## Obtener el usuario { #get-the-user }\n\n`get_current_user` usará una función de utilidad (falsa) que creamos, que toma un token como un `str` y devuelve nuestro modelo de Pydantic `User`:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## Inyectar al usuario actual { #inject-the-current-user }\n\nEntonces ahora podemos usar el mismo `Depends` con nuestro `get_current_user` en la *path operation*:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\nTen en cuenta que declaramos el tipo de `current_user` como el modelo de Pydantic `User`.\n\nEsto nos ayudará dentro de la función con todo el autocompletado y chequeo de tipos.\n\n/// tip | Consejo\n\nTal vez recuerdes que los request bodies también se declaran con modelos de Pydantic.\n\nAquí **FastAPI** no se confundirá porque estás usando `Depends`.\n\n///\n\n/// check | Revisa\n\nEl modo en que este sistema de dependencias está diseñado nos permite tener diferentes dependencias (diferentes \"dependables\") que todas devuelven un modelo `User`.\n\nNo estamos restringidos a tener solo una dependencia que pueda devolver ese tipo de datos.\n\n///\n\n## Otros modelos { #other-models }\n\nAhora puedes obtener el usuario actual directamente en las *path operation functions* y manejar los mecanismos de seguridad a nivel de **Dependency Injection**, usando `Depends`.\n\nY puedes usar cualquier modelo o datos para los requisitos de seguridad (en este caso, un modelo de Pydantic `User`).\n\nPero no estás limitado a usar algún modelo de datos, clase o tipo específico.\n\n¿Quieres tener un `id` y `email` y no tener un `username` en tu modelo? Claro. Puedes usar estas mismas herramientas.\n\n¿Quieres solo tener un `str`? ¿O solo un `dict`? ¿O un instance de clase modelo de base de datos directamente? Todo funciona de la misma manera.\n\n¿En realidad no tienes usuarios que inicien sesión en tu aplicación sino robots, bots u otros sistemas, que solo tienen un token de acceso? Una vez más, todo funciona igual.\n\nUsa cualquier tipo de modelo, cualquier tipo de clase, cualquier tipo de base de datos que necesites para tu aplicación. **FastAPI** te cubre con el sistema de inyección de dependencias.\n\n## Tamaño del código { #code-size }\n\nEste ejemplo podría parecer extenso. Ten en cuenta que estamos mezclando seguridad, modelos de datos, funciones de utilidad y *path operations* en el mismo archivo.\n\nPero aquí está el punto clave.\n\nEl tema de seguridad e inyección de dependencias se escribe una vez.\n\nY puedes hacerlo tan complejo como desees. Y aún así, tenerlo escrito solo una vez, en un solo lugar. Con toda la flexibilidad.\n\nPero puedes tener miles de endpoints (*path operations*) usando el mismo sistema de seguridad.\n\nY todos ellos (o cualquier porción de ellos que quieras) pueden aprovechar la reutilización de estas dependencias o cualquier otra dependencia que crees.\n\nY todas estas miles de *path operations* pueden ser tan pequeñas como 3 líneas:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## Resumen { #recap }\n\nAhora puedes obtener el usuario actual directamente en tu *path operation function*.\n\nYa estamos a mitad de camino.\n\nSolo necesitamos agregar una *path operation* para que el usuario/cliente envíe realmente el `username` y `password`.\n\nEso es lo que viene a continuación.\n"
  },
  {
    "path": "docs/es/docs/tutorial/security/index.md",
    "content": "# Seguridad { #security }\n\nHay muchas formas de manejar la seguridad, autenticación y autorización.\n\nY normalmente es un tema complejo y \"difícil\".\n\nEn muchos frameworks y sistemas, solo manejar la seguridad y autenticación requiere una gran cantidad de esfuerzo y código (en muchos casos puede ser el 50% o más de todo el código escrito).\n\n**FastAPI** proporciona varias herramientas para ayudarte a manejar la **Seguridad** de manera fácil, rápida y estándar, sin tener que estudiar y aprender todas las especificaciones de seguridad.\n\nPero primero, vamos a revisar algunos pequeños conceptos.\n\n## ¿Con prisa? { #in-a-hurry }\n\nSi no te importan ninguno de estos términos y solo necesitas agregar seguridad con autenticación basada en nombre de usuario y contraseña *ahora mismo*, salta a los siguientes capítulos.\n\n## OAuth2 { #oauth2 }\n\nOAuth2 es una especificación que define varias maneras de manejar la autenticación y autorización.\n\nEs una especificación bastante extensa y cubre varios casos de uso complejos.\n\nIncluye formas de autenticarse usando un \"tercero\".\n\nEso es lo que todos los sistemas con \"iniciar sesión con Facebook, Google, X (Twitter), GitHub\" utilizan internamente.\n\n### OAuth 1 { #oauth-1 }\n\nHubo un OAuth 1, que es muy diferente de OAuth2, y más complejo, ya que incluía especificaciones directas sobre cómo encriptar la comunicación.\n\nNo es muy popular o usado hoy en día.\n\nOAuth2 no especifica cómo encriptar la comunicación, espera que tengas tu aplicación servida con HTTPS.\n\n/// tip | Consejo\n\nEn la sección sobre **deployment** verás cómo configurar HTTPS de forma gratuita, usando Traefik y Let's Encrypt.\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect es otra especificación, basada en **OAuth2**.\n\nSolo extiende OAuth2 especificando algunas cosas que son relativamente ambiguas en OAuth2, para intentar hacerla más interoperable.\n\nPor ejemplo, el login de Google usa OpenID Connect (que internamente usa OAuth2).\n\nPero el login de Facebook no soporta OpenID Connect. Tiene su propia versión de OAuth2.\n\n### OpenID (no \"OpenID Connect\") { #openid-not-openid-connect }\n\nHubo también una especificación \"OpenID\". Que intentaba resolver lo mismo que **OpenID Connect**, pero no estaba basada en OAuth2.\n\nEntonces, era un sistema completo adicional.\n\nNo es muy popular o usado hoy en día.\n\n## OpenAPI { #openapi }\n\nOpenAPI (anteriormente conocido como Swagger) es la especificación abierta para construir APIs (ahora parte de la Linux Foundation).\n\n**FastAPI** se basa en **OpenAPI**.\n\nEso es lo que hace posible tener múltiples interfaces de documentación interactiva automática, generación de código, etc.\n\nOpenAPI tiene una forma de definir múltiples \"esquemas\" de seguridad.\n\nAl usarlos, puedes aprovechar todas estas herramientas basadas en estándares, incluidos estos sistemas de documentación interactiva.\n\nOpenAPI define los siguientes esquemas de seguridad:\n\n* `apiKey`: una clave específica de la aplicación que puede provenir de:\n  * Un parámetro de query.\n  * Un header.\n  * Una cookie.\n* `http`: sistemas de autenticación HTTP estándar, incluyendo:\n  * `bearer`: un header `Authorization` con un valor de `Bearer ` más un token. Esto se hereda de OAuth2.\n  * Autenticación básica HTTP.\n  * Digest HTTP, etc.\n* `oauth2`: todas las formas de OAuth2 para manejar la seguridad (llamadas \"flujos\").\n  * Varios de estos flujos son apropiados para construir un proveedor de autenticación OAuth 2.0 (como Google, Facebook, X (Twitter), GitHub, etc.):\n    * `implicit`\n    * `clientCredentials`\n    * `authorizationCode`\n  * Pero hay un \"flujo\" específico que puede usarse perfectamente para manejar la autenticación directamente en la misma aplicación:\n    * `password`: algunos de los próximos capítulos cubrirán ejemplos de esto.\n* `openIdConnect`: tiene una forma de definir cómo descubrir automáticamente los datos de autenticación OAuth2.\n  * Este descubrimiento automático es lo que se define en la especificación de OpenID Connect.\n\n/// tip | Consejo\n\nIntegrar otros proveedores de autenticación/autorización como Google, Facebook, X (Twitter), GitHub, etc. también es posible y relativamente fácil.\n\nEl problema más complejo es construir un proveedor de autenticación/autorización como esos, pero **FastAPI** te da las herramientas para hacerlo fácilmente, mientras hace el trabajo pesado por ti.\n\n///\n\n## Utilidades de **FastAPI** { #fastapi-utilities }\n\nFastAPI proporciona varias herramientas para cada uno de estos esquemas de seguridad en el módulo `fastapi.security` que simplifican el uso de estos mecanismos de seguridad.\n\nEn los siguientes capítulos verás cómo agregar seguridad a tu API usando esas herramientas proporcionadas por **FastAPI**.\n\nY también verás cómo se integra automáticamente en el sistema de documentación interactiva.\n"
  },
  {
    "path": "docs/es/docs/tutorial/security/oauth2-jwt.md",
    "content": "# OAuth2 con Password (y hashing), Bearer con tokens JWT { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\nAhora que tenemos todo el flujo de seguridad, hagamos que la aplicación sea realmente segura, usando tokens <abbr title=\"JSON Web Tokens\">JWT</abbr> y hashing de contraseñas seguras.\n\nEste código es algo que puedes usar realmente en tu aplicación, guardar los hashes de las contraseñas en tu base de datos, etc.\n\nVamos a empezar desde donde lo dejamos en el capítulo anterior e incrementarlo.\n\n## Acerca de JWT { #about-jwt }\n\nJWT significa \"JSON Web Tokens\".\n\nEs un estándar para codificar un objeto JSON en un string largo y denso sin espacios. Se ve así:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\nNo está encriptado, por lo que cualquiera podría recuperar la información de los contenidos.\n\nPero está firmado. Así que, cuando recibes un token que has emitido, puedes verificar que realmente lo emitiste.\n\nDe esta manera, puedes crear un token con una expiración de, digamos, 1 semana. Y luego, cuando el usuario regresa al día siguiente con el token, sabes que el usuario todavía está registrado en tu sistema.\n\nDespués de una semana, el token estará expirado y el usuario no estará autorizado y tendrá que iniciar sesión nuevamente para obtener un nuevo token. Y si el usuario (o un tercero) intenta modificar el token para cambiar la expiración, podrás descubrirlo, porque las firmas no coincidirían.\n\nSi quieres jugar con tokens JWT y ver cómo funcionan, revisa [https://jwt.io](https://jwt.io/).\n\n## Instalar `PyJWT` { #install-pyjwt }\n\nNecesitamos instalar `PyJWT` para generar y verificar los tokens JWT en Python.\n\nAsegúrate de crear un [entorno virtual](../../virtual-environments.md), activarlo y luego instalar `pyjwt`:\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info | Información\n\nSi planeas usar algoritmos de firma digital como RSA o ECDSA, deberías instalar la dependencia del paquete de criptografía `pyjwt[crypto]`.\n\nPuedes leer más al respecto en la [documentación de instalación de PyJWT](https://pyjwt.readthedocs.io/en/latest/installation.html).\n\n///\n\n## Hashing de contraseñas { #password-hashing }\n\n\"Hacer hashing\" significa convertir algún contenido (una contraseña en este caso) en una secuencia de bytes (solo un string) que parece un galimatías.\n\nSiempre que pases exactamente el mismo contenido (exactamente la misma contraseña) obtienes exactamente el mismo galimatías.\n\nPero no puedes convertir del galimatías de nuevo a la contraseña.\n\n### Por qué usar hashing de contraseñas { #why-use-password-hashing }\n\nSi tu base de datos es robada, el ladrón no tendrá las contraseñas en texto claro de tus usuarios, solo los hashes.\n\nPor lo tanto, el ladrón no podrá intentar usar esa contraseña en otro sistema (como muchos usuarios usan la misma contraseña en todas partes, esto sería peligroso).\n\n## Instalar `pwdlib` { #install-pwdlib }\n\npwdlib es un gran paquete de Python para manejar hashes de contraseñas.\n\nSoporta muchos algoritmos de hashing seguros y utilidades para trabajar con ellos.\n\nEl algoritmo recomendado es \"Argon2\".\n\nAsegúrate de crear un [entorno virtual](../../virtual-environments.md), activarlo y luego instalar pwdlib con Argon2:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | Consejo\n\nCon `pwdlib`, incluso podrías configurarlo para poder leer contraseñas creadas por **Django**, un plug-in de seguridad de **Flask** u otros muchos.\n\nAsí, podrías, por ejemplo, compartir los mismos datos de una aplicación de Django en una base de datos con una aplicación de FastAPI. O migrar gradualmente una aplicación de Django usando la misma base de datos.\n\nY tus usuarios podrían iniciar sesión desde tu aplicación Django o desde tu aplicación **FastAPI**, al mismo tiempo.\n\n///\n\n## Hash y verificación de contraseñas { #hash-and-verify-the-passwords }\n\nImporta las herramientas que necesitamos de `pwdlib`.\n\nCrea un instance PasswordHash con configuraciones recomendadas: se usará para hacer el hash y verificar las contraseñas.\n\n/// tip | Consejo\n\npwdlib también soporta el algoritmo de hashing bcrypt pero no incluye algoritmos legacy; para trabajar con hashes desactualizados, se recomienda usar el paquete passlib.\n\nPor ejemplo, podrías usarlo para leer y verificar contraseñas generadas por otro sistema (como Django) pero hacer hash de cualquier contraseña nueva con un algoritmo diferente como Argon2 o Bcrypt.\n\nY ser compatible con todos ellos al mismo tiempo.\n\n///\n\nCrea una función de utilidad para hacer el hash de una contraseña que venga del usuario.\n\nY otra utilidad para verificar si una contraseña recibida coincide con el hash almacenado.\n\nY otra más para autenticar y devolver un usuario.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\nCuando `authenticate_user` se llama con un nombre de usuario que no existe en la base de datos, aun así ejecutamos `verify_password` contra un hash ficticio.\n\nEsto asegura que el endpoint tarda aproximadamente la misma cantidad de tiempo en responder tanto si el nombre de usuario es válido como si no, previniendo los **timing attacks** que podrían usarse para enumerar nombres de usuario existentes.\n\n/// note | Nota\n\nSi revisas la nueva (falsa) base de datos `fake_users_db`, verás cómo se ve ahora la contraseña con hash: `\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`.\n\n///\n\n## Manejo de tokens JWT { #handle-jwt-tokens }\n\nImporta los módulos instalados.\n\nCrea una clave secreta aleatoria que se usará para firmar los tokens JWT.\n\nPara generar una clave secreta segura al azar usa el comando:\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\nY copia el resultado a la variable `SECRET_KEY` (no uses la del ejemplo).\n\nCrea una variable `ALGORITHM` con el algoritmo usado para firmar el token JWT y configúralo a `\"HS256\"`.\n\nCrea una variable para la expiración del token.\n\nDefine un Modelo de Pydantic que se usará en el endpoint de token para el response.\n\nCrea una función de utilidad para generar un nuevo token de acceso.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## Actualizar las dependencias { #update-the-dependencies }\n\nActualiza `get_current_user` para recibir el mismo token que antes, pero esta vez, usando tokens JWT.\n\nDecodifica el token recibido, verifícalo y devuelve el usuario actual.\n\nSi el token es inválido, devuelve un error HTTP de inmediato.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## Actualizar la *path operation* `/token` { #update-the-token-path-operation }\n\nCrea un `timedelta` con el tiempo de expiración del token.\n\nCrea un verdadero token de acceso JWT y devuélvelo.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### Detalles técnicos sobre el \"sujeto\" `sub` de JWT { #technical-details-about-the-jwt-subject-sub }\n\nLa especificación de JWT dice que hay una clave `sub`, con el sujeto del token.\n\nEs opcional usarlo, pero ahí es donde pondrías la identificación del usuario, por lo que lo estamos usando aquí.\n\nJWT podría ser usado para otras cosas aparte de identificar un usuario y permitirle realizar operaciones directamente en tu API.\n\nPor ejemplo, podrías identificar un \"coche\" o un \"artículo de blog\".\n\nLuego, podrías agregar permisos sobre esa entidad, como \"conducir\" (para el coche) o \"editar\" (para el blog).\n\nY luego, podrías darle ese token JWT a un usuario (o bot), y ellos podrían usarlo para realizar esas acciones (conducir el coche, o editar el artículo del blog) sin siquiera necesitar tener una cuenta, solo con el token JWT que tu API generó para eso.\n\nUsando estas ideas, JWT puede ser utilizado para escenarios mucho más sofisticados.\n\nEn esos casos, varias de esas entidades podrían tener el mismo ID, digamos `foo` (un usuario `foo`, un coche `foo`, y un artículo del blog `foo`).\n\nEntonces, para evitar colisiones de ID, cuando crees el token JWT para el usuario, podrías prefijar el valor de la clave `sub`, por ejemplo, con `username:`. Así, en este ejemplo, el valor de `sub` podría haber sido: `username:johndoe`.\n\nLo importante a tener en cuenta es que la clave `sub` debería tener un identificador único a lo largo de toda la aplicación, y debería ser un string.\n\n## Revisa { #check-it }\n\nEjecuta el servidor y ve a la documentación: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVerás la interfaz de usuario como:\n\n<img src=\"/img/tutorial/security/image07.png\">\n\nAutoriza la aplicación de la misma manera que antes.\n\nUsando las credenciales:\n\nUsuario: `johndoe`\nContraseña: `secret`\n\n/// check | Revisa\n\nObserva que en ninguna parte del código está la contraseña en texto claro \"`secret`\", solo tenemos la versión con hash.\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\nLlama al endpoint `/users/me/`, obtendrás el response como:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\nSi abres las herramientas de desarrollador, podrías ver cómo los datos enviados solo incluyen el token, la contraseña solo se envía en la primera request para autenticar al usuario y obtener ese token de acceso, pero no después:\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | Nota\n\nObserva el header `Authorization`, con un valor que comienza con `Bearer `.\n\n///\n\n## Uso avanzado con `scopes` { #advanced-usage-with-scopes }\n\nOAuth2 tiene la noción de \"scopes\".\n\nPuedes usarlos para agregar un conjunto específico de permisos a un token JWT.\n\nLuego, puedes darle este token directamente a un usuario o a un tercero, para interactuar con tu API con un conjunto de restricciones.\n\nPuedes aprender cómo usarlos y cómo están integrados en **FastAPI** más adelante en la **Guía de Usuario Avanzada**.\n\n## Resumen { #recap }\n\nCon lo que has visto hasta ahora, puedes configurar una aplicación **FastAPI** segura usando estándares como OAuth2 y JWT.\n\nEn casi cualquier framework el manejo de la seguridad se convierte en un tema bastante complejo rápidamente.\n\nMuchos paquetes que lo simplifican tienen que hacer muchos compromisos con el modelo de datos, la base de datos y las funcionalidades disponibles. Y algunos de estos paquetes que simplifican las cosas demasiado en realidad tienen fallos de seguridad en el fondo.\n\n---\n\n**FastAPI** no hace ningún compromiso con ninguna base de datos, modelo de datos o herramienta.\n\nTe da toda la flexibilidad para elegir aquellas que se ajusten mejor a tu proyecto.\n\nY puedes usar directamente muchos paquetes bien mantenidos y ampliamente usados como `pwdlib` y `PyJWT`, porque **FastAPI** no requiere mecanismos complejos para integrar paquetes externos.\n\nPero te proporciona las herramientas para simplificar el proceso tanto como sea posible sin comprometer la flexibilidad, la robustez o la seguridad.\n\nY puedes usar e implementar protocolos seguros y estándar, como OAuth2 de una manera relativamente simple.\n\nPuedes aprender más en la **Guía de Usuario Avanzada** sobre cómo usar \"scopes\" de OAuth2, para un sistema de permisos más detallado, siguiendo estos mismos estándares. OAuth2 con scopes es el mecanismo utilizado por muchos grandes proveedores de autenticación, como Facebook, Google, GitHub, Microsoft, X (Twitter), etc. para autorizar aplicaciones de terceros para interactuar con sus APIs en nombre de sus usuarios.\n"
  },
  {
    "path": "docs/es/docs/tutorial/security/simple-oauth2.md",
    "content": "# Simple OAuth2 con Password y Bearer { #simple-oauth2-with-password-and-bearer }\n\nAhora vamos a construir a partir del capítulo anterior y agregar las partes faltantes para tener un flujo de seguridad completo.\n\n## Obtener el `username` y `password` { #get-the-username-and-password }\n\nVamos a usar las utilidades de seguridad de **FastAPI** para obtener el `username` y `password`.\n\nOAuth2 especifica que cuando se utiliza el \"password flow\" (que estamos usando), el cliente/usuario debe enviar campos `username` y `password` como form data.\n\nY la especificación dice que los campos deben llamarse así. Por lo que `user-name` o `email` no funcionarían.\n\nPero no te preocupes, puedes mostrarlo como quieras a tus usuarios finales en el frontend.\n\nY tus modelos de base de datos pueden usar cualquier otro nombre que desees.\n\nPero para la *path operation* de inicio de sesión, necesitamos usar estos nombres para ser compatibles con la especificación (y poder, por ejemplo, utilizar el sistema de documentación integrada de la API).\n\nLa especificación también establece que el `username` y `password` deben enviarse como form data (por lo que no hay JSON aquí).\n\n### `scope` { #scope }\n\nLa especificación también indica que el cliente puede enviar otro campo del formulario llamado \"`scope`\".\n\nEl nombre del campo del formulario es `scope` (en singular), pero en realidad es un string largo con \"scopes\" separados por espacios.\n\nCada \"scope\" es simplemente un string (sin espacios).\n\nNormalmente se utilizan para declarar permisos de seguridad específicos, por ejemplo:\n\n* `users:read` o `users:write` son ejemplos comunes.\n* `instagram_basic` es usado por Facebook / Instagram.\n* `https://www.googleapis.com/auth/drive` es usado por Google.\n\n/// info | Información\n\nEn OAuth2 un \"scope\" es solo un string que declara un permiso específico requerido.\n\nNo importa si tiene otros caracteres como `:` o si es una URL.\n\nEsos detalles son específicos de la implementación.\n\nPara OAuth2 son solo strings.\n\n///\n\n## Código para obtener el `username` y `password` { #code-to-get-the-username-and-password }\n\nAhora vamos a usar las utilidades proporcionadas por **FastAPI** para manejar esto.\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\nPrimero, importa `OAuth2PasswordRequestForm`, y úsalo como una dependencia con `Depends` en la *path operation* para `/token`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm` es una dependencia de clase que declara un body de formulario con:\n\n* El `username`.\n* El `password`.\n* Un campo opcional `scope` como un string grande, compuesto por strings separados por espacios.\n* Un `grant_type` opcional.\n\n/// tip | Consejo\n\nLa especificación de OAuth2 en realidad *requiere* un campo `grant_type` con un valor fijo de `password`, pero `OAuth2PasswordRequestForm` no lo obliga.\n\nSi necesitas imponerlo, utiliza `OAuth2PasswordRequestFormStrict` en lugar de `OAuth2PasswordRequestForm`.\n\n///\n\n* Un `client_id` opcional (no lo necesitamos para nuestro ejemplo).\n* Un `client_secret` opcional (no lo necesitamos para nuestro ejemplo).\n\n/// info | Información\n\n`OAuth2PasswordRequestForm` no es una clase especial para **FastAPI** como lo es `OAuth2PasswordBearer`.\n\n`OAuth2PasswordBearer` hace que **FastAPI** sepa que es un esquema de seguridad. Así que se añade de esa manera a OpenAPI.\n\nPero `OAuth2PasswordRequestForm` es solo una dependencia de clase que podrías haber escrito tú mismo, o podrías haber declarado parámetros de `Form` directamente.\n\nPero como es un caso de uso común, se proporciona directamente por **FastAPI**, solo para facilitarlo.\n\n///\n\n### Usa el form data { #use-the-form-data }\n\n/// tip | Consejo\n\nLa instance de la clase de dependencia `OAuth2PasswordRequestForm` no tendrá un atributo `scope` con el string largo separado por espacios, en su lugar, tendrá un atributo `scopes` con la lista real de strings para cada scope enviado.\n\nNo estamos usando `scopes` en este ejemplo, pero la funcionalidad está ahí si la necesitas.\n\n///\n\nAhora, obtén los datos del usuario desde la base de datos (falsa), usando el `username` del campo del form.\n\nSi no existe tal usuario, devolvemos un error diciendo \"Incorrect username or password\".\n\nPara el error, usamos la excepción `HTTPException`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### Revisa el password { #check-the-password }\n\nEn este punto tenemos los datos del usuario de nuestra base de datos, pero no hemos revisado el password.\n\nPrimero pongamos esos datos en el modelo `UserInDB` de Pydantic.\n\nNunca deberías guardar passwords en texto plano, así que, usaremos el sistema de hash de passwords (falso).\n\nSi los passwords no coinciden, devolvemos el mismo error.\n\n#### Hashing de passwords { #password-hashing }\n\n\"Hacer hash\" significa: convertir algún contenido (un password en este caso) en una secuencia de bytes (solo un string) que parece un galimatías.\n\nSiempre que pases exactamente el mismo contenido (exactamente el mismo password) obtienes exactamente el mismo galimatías.\n\nPero no puedes convertir del galimatías al password.\n\n##### Por qué usar hashing de passwords { #why-use-password-hashing }\n\nSi tu base de datos es robada, el ladrón no tendrá los passwords en texto plano de tus usuarios, solo los hashes.\n\nEntonces, el ladrón no podrá intentar usar esos mismos passwords en otro sistema (como muchos usuarios usan el mismo password en todas partes, esto sería peligroso).\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### Sobre `**user_dict` { #about-user-dict }\n\n`UserInDB(**user_dict)` significa:\n\n*Pasa las claves y valores de `user_dict` directamente como argumentos clave-valor, equivalente a:*\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info | Información\n\nPara una explicación más completa de `**user_dict` revisa en [la documentación para **Extra Models**](../extra-models.md#about-user-in-dict).\n\n///\n\n## Devolver el token { #return-the-token }\n\nEl response del endpoint `token` debe ser un objeto JSON.\n\nDebe tener un `token_type`. En nuestro caso, como estamos usando tokens \"Bearer\", el tipo de token debe ser \"`bearer`\".\n\nY debe tener un `access_token`, con un string que contenga nuestro token de acceso.\n\nPara este ejemplo simple, vamos a ser completamente inseguros y devolver el mismo `username` como el token.\n\n/// tip | Consejo\n\nEn el próximo capítulo, verás una implementación segura real, con hashing de passwords y tokens <abbr title=\"JSON Web Tokens\">JWT</abbr>.\n\nPero por ahora, enfoquémonos en los detalles específicos que necesitamos.\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip | Consejo\n\nDe acuerdo con la especificación, deberías devolver un JSON con un `access_token` y un `token_type`, igual que en este ejemplo.\n\nEsto es algo que tienes que hacer tú mismo en tu código, y asegurarte de usar esas claves JSON.\n\nEs casi lo único que tienes que recordar hacer correctamente tú mismo, para ser compatible con las especificaciones.\n\nPara el resto, **FastAPI** lo maneja por ti.\n\n///\n\n## Actualizar las dependencias { #update-the-dependencies }\n\nAhora vamos a actualizar nuestras dependencias.\n\nQueremos obtener el `current_user` *solo* si este usuario está activo.\n\nEntonces, creamos una dependencia adicional `get_current_active_user` que a su vez utiliza `get_current_user` como dependencia.\n\nAmbas dependencias solo devolverán un error HTTP si el usuario no existe, o si está inactivo.\n\nAsí que, en nuestro endpoint, solo obtendremos un usuario si el usuario existe, fue autenticado correctamente, y está activo:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info | Información\n\nEl header adicional `WWW-Authenticate` con el valor `Bearer` que estamos devolviendo aquí también es parte de la especificación.\n\nCualquier código de estado HTTP (error) 401 \"UNAUTHORIZED\" se supone que también debe devolver un header `WWW-Authenticate`.\n\nEn el caso de tokens bearer (nuestro caso), el valor de ese header debe ser `Bearer`.\n\nDe hecho, puedes omitir ese header extra y aún funcionaría.\n\nPero se proporciona aquí para cumplir con las especificaciones.\n\nAdemás, podría haber herramientas que lo esperen y lo usen (ahora o en el futuro) y eso podría ser útil para ti o tus usuarios, ahora o en el futuro.\n\nEse es el beneficio de los estándares...\n\n///\n\n## Verlo en acción { #see-it-in-action }\n\nAbre la documentación interactiva: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n### Autenticar { #authenticate }\n\nHaz clic en el botón \"Authorize\".\n\nUsa las credenciales:\n\nUsuario: `johndoe`\n\nContraseña: `secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\nDespués de autenticarte en el sistema, lo verás así:\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### Obtener tus propios datos de usuario { #get-your-own-user-data }\n\nAhora usa la operación `GET` con la path `/users/me`.\n\nObtendrás los datos de tu usuario, como:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\nSi haces clic en el icono de candado y cierras sesión, y luego intentas la misma operación nuevamente, obtendrás un error HTTP 401 de:\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### Usuario inactivo { #inactive-user }\n\nAhora prueba con un usuario inactivo, autentícate con:\n\nUsuario: `alice`\n\nContraseña: `secret2`\n\nY trata de usar la operación `GET` con la path `/users/me`.\n\nObtendrás un error de \"Usuario inactivo\", como:\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## Recapitulación { #recap }\n\nAhora tienes las herramientas para implementar un sistema de seguridad completo basado en `username` y `password` para tu API.\n\nUsando estas herramientas, puedes hacer que el sistema de seguridad sea compatible con cualquier base de datos y con cualquier modelo de usuario o de datos.\n\nEl único detalle que falta es que en realidad no es \"seguro\" aún.\n\nEn el próximo capítulo verás cómo usar un paquete de hashing de passwords seguro y tokens <abbr title=\"JSON Web Tokens\">JWT</abbr>.\n"
  },
  {
    "path": "docs/es/docs/tutorial/server-sent-events.md",
    "content": "# Server-Sent Events (SSE) { #server-sent-events-sse }\n\nPuedes enviar datos en streaming al cliente usando **Server-Sent Events** (SSE).\n\nEsto es similar a [Stream JSON Lines](stream-json-lines.md), pero usa el formato `text/event-stream`, que los navegadores soportan de forma nativa con la [`EventSource` API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).\n\n/// info | Información\n\nAñadido en FastAPI 0.135.0.\n\n///\n\n## ¿Qué son los Server-Sent Events? { #what-are-server-sent-events }\n\nSSE es un estándar para hacer streaming de datos desde el servidor al cliente sobre HTTP.\n\nCada evento es un pequeño bloque de texto con “campos” como `data`, `event`, `id` y `retry`, separados por líneas en blanco.\n\nSe ve así:\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE se usa comúnmente para streaming de chat de IA, notificaciones en vivo, logs y observabilidad, y otros casos donde el servidor envía actualizaciones al cliente.\n\n/// tip | Consejo\n\nSi quieres hacer streaming de datos binarios, por ejemplo video o audio, Revisa la guía avanzada: [Stream Data](../advanced/stream-data.md).\n\n///\n\n## Streaming de SSE con FastAPI { #stream-sse-with-fastapi }\n\nPara hacer streaming de SSE con FastAPI, usa `yield` en tu path operation function y establece `response_class=EventSourceResponse`.\n\nimport `EventSourceResponse` de `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\nCada ítem producido con `yield` se codifica como JSON y se envía en el campo `data:` de un evento SSE.\n\nSi declaras el tipo de retorno como `AsyncIterable[Item]`, FastAPI lo usará para **validar**, **documentar** y **serializar** los datos usando Pydantic.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip | Consejo\n\nComo Pydantic lo serializará en el lado de **Rust**, obtendrás un **rendimiento** mucho mayor que si no declaras un tipo de retorno.\n\n///\n\n### No async *path operation functions* { #non-async-path-operation-functions }\n\nTambién puedes usar funciones `def` normales (sin `async`), y usar `yield` de la misma manera.\n\nFastAPI se asegurará de ejecutarlo correctamente para que no bloquee el event loop.\n\nComo en este caso la función no es async, el tipo de retorno correcto sería `Iterable[Item]`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### Sin tipo de retorno { #no-return-type }\n\nTambién puedes omitir el tipo de retorno. FastAPI usará el [`jsonable_encoder`](./encoder.md) para convertir los datos y enviarlos.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\nSi necesitas configurar campos SSE como `event`, `id`, `retry` o `comment`, puedes hacer `yield` de objetos `ServerSentEvent` en lugar de datos simples.\n\nimport `ServerSentEvent` de `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\nEl campo `data` siempre se codifica como JSON. Puedes pasar cualquier valor que pueda serializarse como JSON, incluidos modelos de Pydantic.\n\n## Datos sin procesar { #raw-data }\n\nSi necesitas enviar datos **sin** codificarlos a JSON, usa `raw_data` en lugar de `data`.\n\nEsto es útil para enviar texto preformateado, líneas de log, o valores especiales de <dfn title=\"Un valor usado para indicar una condición o estado especial\">\"centinela\"</dfn> como `[DONE]`.\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note | Nota\n\n`data` y `raw_data` son mutuamente excluyentes. Solo puedes establecer uno de ellos en cada `ServerSentEvent`.\n\n///\n\n## Reanudar con `Last-Event-ID` { #resuming-with-last-event-id }\n\nCuando un navegador se reconecta después de una caída de la conexión, envía el último `id` recibido en el header `Last-Event-ID`.\n\nPuedes leerlo como un parámetro de header y usarlo para reanudar el stream desde donde el cliente se quedó:\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## SSE con `POST` { #sse-with-post }\n\nSSE funciona con **cualquier método HTTP**, no solo con `GET`.\n\nEsto es útil para protocolos como [MCP](https://modelcontextprotocol.io) que hacen streaming de SSE sobre `POST`:\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## Detalles técnicos { #technical-details }\n\nFastAPI implementa algunas mejores prácticas de SSE desde el primer momento.\n\n- Enviar un comentario de **\"keep alive\" `ping`** cada 15 segundos cuando no ha habido ningún mensaje, para evitar que algunos proxies cierren la conexión, como se sugiere en la [Especificación HTML: Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes).\n- Configurar el header `Cache-Control: no-cache` para **evitar el almacenamiento en caché** del stream.\n- Configurar un header especial `X-Accel-Buffering: no` para **evitar el buffering** en algunos proxies como Nginx.\n\nNo tienes que hacer nada, funciona tal cual viene. 🤓\n"
  },
  {
    "path": "docs/es/docs/tutorial/sql-databases.md",
    "content": "# Bases de Datos SQL (Relacionales) { #sql-relational-databases }\n\n**FastAPI** no requiere que uses una base de datos SQL (relacional). Pero puedes utilizar **cualquier base de datos** que desees.\n\nAquí veremos un ejemplo usando [SQLModel](https://sqlmodel.tiangolo.com/).\n\n**SQLModel** está construido sobre [SQLAlchemy](https://www.sqlalchemy.org/) y Pydantic. Fue creado por el mismo autor de **FastAPI** para ser la combinación perfecta para aplicaciones de FastAPI que necesiten usar **bases de datos SQL**.\n\n/// tip | Consejo\n\nPuedes usar cualquier otro paquete de bases de datos SQL o NoSQL que quieras (en algunos casos llamadas <abbr title=\"Object Relational Mapper - Mapeador Objeto-Relacional: un término elegante para un paquete donde algunas clases representan tablas SQL y las instances representan filas en esas tablas\">\"ORMs\"</abbr>), FastAPI no te obliga a usar nada. 😎\n\n///\n\nComo SQLModel se basa en SQLAlchemy, puedes usar fácilmente **cualquier base de datos soportada** por SQLAlchemy (lo que las hace también soportadas por SQLModel), como:\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server, etc.\n\nEn este ejemplo, usaremos **SQLite**, porque utiliza un solo archivo y Python tiene soporte integrado. Así que puedes copiar este ejemplo y ejecutarlo tal cual.\n\nMás adelante, para tu aplicación en producción, es posible que desees usar un servidor de base de datos como **PostgreSQL**.\n\n/// tip | Consejo\n\nHay un generador de proyectos oficial con **FastAPI** y **PostgreSQL** que incluye un frontend y más herramientas: [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\nEste es un tutorial muy simple y corto, si deseas aprender sobre bases de datos en general, sobre SQL o más funcionalidades avanzadas, ve a la [documentación de SQLModel](https://sqlmodel.tiangolo.com/).\n\n## Instalar `SQLModel` { #install-sqlmodel }\n\nPrimero, asegúrate de crear tu [entorno virtual](../virtual-environments.md), actívalo, y luego instala `sqlmodel`:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## Crear la App con un Solo Modelo { #create-the-app-with-a-single-model }\n\nPrimero crearemos la versión más simple de la aplicación con un solo modelo de **SQLModel**.\n\nMás adelante la mejoraremos aumentando la seguridad y versatilidad con **múltiples modelos** a continuación. 🤓\n\n### Crear Modelos { #create-models }\n\nImporta `SQLModel` y crea un modelo de base de datos:\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\nLa clase `Hero` es muy similar a un modelo de Pydantic (de hecho, en el fondo, realmente *es un modelo de Pydantic*).\n\nHay algunas diferencias:\n\n* `table=True` le dice a SQLModel que este es un *modelo de tabla*, que debe representar una **tabla** en la base de datos SQL, no es solo un *modelo de datos* (como lo sería cualquier otra clase regular de Pydantic).\n\n* `Field(primary_key=True)` le dice a SQLModel que `id` es la **clave primaria** en la base de datos SQL (puedes aprender más sobre claves primarias de SQL en la documentación de SQLModel).\n\n    Nota: Usamos `int | None` para el campo de clave primaria para que en el código Python podamos *crear un objeto sin un `id`* (`id=None`), asumiendo que la base de datos lo *generará al guardar*. SQLModel entiende que la base de datos proporcionará el `id` y *define la columna como un `INTEGER` no nulo* en el esquema de la base de datos. Consulta la [documentación de SQLModel sobre claves primarias](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) para más detalles.\n\n* `Field(index=True)` le dice a SQLModel que debe crear un **índice SQL** para esta columna, lo que permitirá búsquedas más rápidas en la base de datos cuando se lean datos filtrados por esta columna.\n\n    SQLModel sabrá que algo declarado como `str` será una columna SQL de tipo `TEXT` (o `VARCHAR`, dependiendo de la base de datos).\n\n### Crear un Engine { #create-an-engine }\n\nUn `engine` de SQLModel (en el fondo, realmente es un `engine` de SQLAlchemy) es lo que **mantiene las conexiones** a la base de datos.\n\nTendrías **un solo objeto `engine`** para todo tu código para conectar a la misma base de datos.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\nUsar `check_same_thread=False` permite a FastAPI usar la misma base de datos SQLite en diferentes hilos. Esto es necesario ya que **una sola request** podría usar **más de un hilo** (por ejemplo, en dependencias).\n\nNo te preocupes, con la forma en que está estructurado el código, nos aseguraremos de usar **una sola *session* de SQLModel por request** más adelante, esto es realmente lo que intenta lograr el `check_same_thread`.\n\n### Crear las Tablas { #create-the-tables }\n\nLuego añadimos una función que usa `SQLModel.metadata.create_all(engine)` para **crear las tablas** para todos los *modelos de tabla*.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### Crear una Dependencia de Session { #create-a-session-dependency }\n\nUna **`Session`** es lo que almacena los **objetos en memoria** y lleva un seguimiento de cualquier cambio necesario en los datos, luego **usa el `engine`** para comunicarse con la base de datos.\n\nCrearemos una **dependencia de FastAPI** con `yield` que proporcionará una nueva `Session` para cada request. Esto es lo que asegura que usemos una sola session por request. 🤓\n\nLuego creamos una dependencia `Annotated` `SessionDep` para simplificar el resto del código que usará esta dependencia.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### Crear Tablas de Base de Datos al Arrancar { #create-database-tables-on-startup }\n\nCrearemos las tablas de la base de datos cuando arranque la aplicación.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\nAquí creamos las tablas en un evento de inicio de la aplicación.\n\nPara producción probablemente usarías un script de migración que se ejecuta antes de iniciar tu aplicación. 🤓\n\n/// tip | Consejo\n\nSQLModel tendrá utilidades de migración envolviendo Alembic, pero por ahora, puedes usar [Alembic](https://alembic.sqlalchemy.org/en/latest/) directamente.\n\n///\n\n### Crear un Hero { #create-a-hero }\n\nDebido a que cada modelo de SQLModel también es un modelo de Pydantic, puedes usarlo en las mismas **anotaciones de tipos** que podrías usar en modelos de Pydantic.\n\nPor ejemplo, si declaras un parámetro de tipo `Hero`, será leído desde el **JSON body**.\n\nDe la misma manera, puedes declararlo como el **tipo de retorno** de la función, y luego la forma de los datos aparecerá en la interfaz automática de documentación de la API.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\nAquí usamos la dependencia `SessionDep` (una `Session`) para añadir el nuevo `Hero` a la instance `Session`, comiteamos los cambios a la base de datos, refrescamos los datos en el `hero` y luego lo devolvemos.\n\n### Leer Heroes { #read-heroes }\n\nPodemos **leer** `Hero`s de la base de datos usando un `select()`. Podemos incluir un `limit` y `offset` para paginar los resultados.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### Leer Un Hero { #read-one-hero }\n\nPodemos **leer** un único `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### Eliminar un Hero { #delete-a-hero }\n\nTambién podemos **eliminar** un `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### Ejecutar la App { #run-the-app }\n\nPuedes ejecutar la aplicación:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nLuego dirígete a la interfaz de `/docs`, verás que **FastAPI** está usando estos **modelos** para **documentar** la API, y los usará para **serializar** y **validar** los datos también.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## Actualizar la App con Múltiples Modelos { #update-the-app-with-multiple-models }\n\nAhora vamos a **refactorizar** un poco esta aplicación para aumentar la **seguridad** y la **versatilidad**.\n\nSi revisas la aplicación anterior, en la interfaz verás que, hasta ahora, permite al cliente decidir el `id` del `Hero` a crear. 😱\n\nNo deberíamos permitir que eso suceda, podrían sobrescribir un `id` que ya tenemos asignado en la base de datos. Decidir el `id` debería ser tarea del **backend** o la **base de datos**, **no del cliente**.\n\nAdemás, creamos un `secret_name` para el héroe, pero hasta ahora, lo estamos devolviendo en todas partes, eso no es muy **secreto**... 😅\n\nArreglaremos estas cosas añadiendo unos **modelos extra**. Aquí es donde SQLModel brillará. ✨\n\n### Crear Múltiples Modelos { #create-multiple-models }\n\nEn **SQLModel**, cualquier clase de modelo que tenga `table=True` es un **modelo de tabla**.\n\nY cualquier clase de modelo que no tenga `table=True` es un **modelo de datos**, estos son en realidad solo modelos de Pydantic (con un par de características extra pequeñas). 🤓\n\nCon SQLModel, podemos usar **herencia** para **evitar duplicar** todos los campos en todos los casos.\n\n#### `HeroBase` - la clase base { #herobase-the-base-class }\n\nComencemos con un modelo `HeroBase` que tiene todos los **campos que son compartidos** por todos los modelos:\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` - el *modelo de tabla* { #hero-the-table-model }\n\nLuego, crearemos `Hero`, el *modelo de tabla* real, con los **campos extra** que no siempre están en los otros modelos:\n\n* `id`\n* `secret_name`\n\nDebido a que `Hero` hereda de `HeroBase`, **también** tiene los **campos** declarados en `HeroBase`, por lo que todos los campos para `Hero` son:\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` - el *modelo de datos* público { #heropublic-the-public-data-model }\n\nA continuación, creamos un modelo `HeroPublic`, este es el que será **devuelto** a los clientes de la API.\n\nTiene los mismos campos que `HeroBase`, por lo que no incluirá `secret_name`.\n\nPor fin, la identidad de nuestros héroes está protegida! 🥷\n\nTambién vuelve a declarar `id: int`. Al hacer esto, estamos haciendo un **contrato** con los clientes de la API, para que siempre puedan esperar que el `id` esté allí y sea un `int` (nunca será `None`).\n\n/// tip | Consejo\n\nTener el modelo de retorno asegurando que un valor siempre esté disponible y siempre sea `int` (no `None`) es muy útil para los clientes de la API, pueden escribir código mucho más simple teniendo esta certeza.\n\nAdemás, los **clientes generados automáticamente** tendrán interfaces más simples, para que los desarrolladores que se comuniquen con tu API puedan tener una experiencia mucho mejor trabajando con tu API. 😎\n\n///\n\nTodos los campos en `HeroPublic` son los mismos que en `HeroBase`, con `id` declarado como `int` (no `None`):\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` - el *modelo de datos* para crear un héroe { #herocreate-the-data-model-to-create-a-hero }\n\nAhora creamos un modelo `HeroCreate`, este es el que **validará** los datos de los clientes.\n\nTiene los mismos campos que `HeroBase`, y también tiene `secret_name`.\n\nAhora, cuando los clientes **crean un nuevo héroe**, enviarán el `secret_name`, se almacenará en la base de datos, pero esos nombres secretos no se devolverán en la API a los clientes.\n\n/// tip | Consejo\n\nEsta es la forma en la que manejarías **contraseñas**. Recíbelas, pero no las devuelvas en la API.\n\nTambién **hashea** los valores de las contraseñas antes de almacenarlos, **nunca los almacenes en texto plano**.\n\n///\n\nLos campos de `HeroCreate` son:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` - el *modelo de datos* para actualizar un héroe { #heroupdate-the-data-model-to-update-a-hero }\n\nNo teníamos una forma de **actualizar un héroe** en la versión anterior de la aplicación, pero ahora con **múltiples modelos**, podemos hacerlo. 🎉\n\nEl *modelo de datos* `HeroUpdate` es algo especial, tiene **todos los mismos campos** que serían necesarios para crear un nuevo héroe, pero todos los campos son **opcionales** (todos tienen un valor por defecto). De esta forma, cuando actualices un héroe, puedes enviar solo los campos que deseas actualizar.\n\nDebido a que todos los **campos realmente cambian** (el tipo ahora incluye `None` y ahora tienen un valor por defecto de `None`), necesitamos **volver a declararlos**.\n\nRealmente no necesitamos heredar de `HeroBase` porque estamos volviendo a declarar todos los campos. Lo dejaré heredando solo por consistencia, pero esto no es necesario. Es más una cuestión de gusto personal. 🤷\n\nLos campos de `HeroUpdate` son:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### Crear con `HeroCreate` y devolver un `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }\n\nAhora que tenemos **múltiples modelos**, podemos actualizar las partes de la aplicación que los usan.\n\nRecibimos en la request un *modelo de datos* `HeroCreate`, y a partir de él, creamos un *modelo de tabla* `Hero`.\n\nEste nuevo *modelo de tabla* `Hero` tendrá los campos enviados por el cliente, y también tendrá un `id` generado por la base de datos.\n\nLuego devolvemos el mismo *modelo de tabla* `Hero` tal cual desde la función. Pero como declaramos el `response_model` con el *modelo de datos* `HeroPublic`, **FastAPI** usará `HeroPublic` para validar y serializar los datos.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | Consejo\n\nAhora usamos `response_model=HeroPublic` en lugar de la **anotación de tipo de retorno** `-> HeroPublic` porque el valor que estamos devolviendo en realidad *no* es un `HeroPublic`.\n\nSi hubiéramos declarado `-> HeroPublic`, tu editor y linter se quejarían (con razón) de que estás devolviendo un `Hero` en lugar de un `HeroPublic`.\n\nAl declararlo en `response_model` le estamos diciendo a **FastAPI** que haga lo suyo, sin interferir con las anotaciones de tipo y la ayuda de tu editor y otras herramientas.\n\n///\n\n### Leer Heroes con `HeroPublic` { #read-heroes-with-heropublic }\n\nPodemos hacer lo mismo que antes para **leer** `Hero`s, nuevamente, usamos `response_model=list[HeroPublic]` para asegurar que los datos se validen y serialicen correctamente.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### Leer Un Hero con `HeroPublic` { #read-one-hero-with-heropublic }\n\nPodemos **leer** un único héroe:\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### Actualizar un Hero con `HeroUpdate` { #update-a-hero-with-heroupdate }\n\nPodemos **actualizar un héroe**. Para esto usamos una operación HTTP `PATCH`.\n\nY en el código, obtenemos un `dict` con todos los datos enviados por el cliente, **solo los datos enviados por el cliente**, excluyendo cualquier valor que estaría allí solo por ser valores por defecto. Para hacerlo usamos `exclude_unset=True`. Este es el truco principal. 🪄\n\nLuego usamos `hero_db.sqlmodel_update(hero_data)` para actualizar el `hero_db` con los datos de `hero_data`.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### Eliminar un Hero de Nuevo { #delete-a-hero-again }\n\n**Eliminar** un héroe se mantiene prácticamente igual.\n\nNo satisfaremos el deseo de refactorizar todo en este punto. 😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### Ejecutar la App de Nuevo { #run-the-app-again }\n\nPuedes ejecutar la aplicación de nuevo:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nSi vas a la interfaz de `/docs` de la API, verás que ahora está actualizada, y no esperará recibir el `id` del cliente al crear un héroe, etc.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## Resumen { #recap }\n\nPuedes usar [**SQLModel**](https://sqlmodel.tiangolo.com/) para interactuar con una base de datos SQL y simplificar el código con *modelos de datos* y *modelos de tablas*.\n\nPuedes aprender mucho más en la documentación de **SQLModel**, hay un mini [tutorial más largo sobre el uso de SQLModel con **FastAPI**](https://sqlmodel.tiangolo.com/tutorial/fastapi/). 🚀\n"
  },
  {
    "path": "docs/es/docs/tutorial/static-files.md",
    "content": "# Archivos Estáticos { #static-files }\n\nPuedes servir archivos estáticos automáticamente desde un directorio utilizando `StaticFiles`.\n\n## Usa `StaticFiles` { #use-staticfiles }\n\n* Importa `StaticFiles`.\n* \"Monta\" una instance de `StaticFiles()` en un path específico.\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | Detalles Técnicos\n\nTambién podrías usar `from starlette.staticfiles import StaticFiles`.\n\n**FastAPI** proporciona el mismo `starlette.staticfiles` como `fastapi.staticfiles` solo como una conveniencia para ti, el desarrollador. Pero en realidad viene directamente de Starlette.\n\n///\n\n### Qué es \"Montar\" { #what-is-mounting }\n\n\"Montar\" significa agregar una aplicación completa \"independiente\" en un path específico, que luego se encargará de manejar todos los sub-paths.\n\nEsto es diferente a usar un `APIRouter`, ya que una aplicación montada es completamente independiente. El OpenAPI y la documentación de tu aplicación principal no incluirán nada de la aplicación montada, etc.\n\nPuedes leer más sobre esto en la [Guía de Usuario Avanzada](../advanced/index.md).\n\n## Detalles { #details }\n\nEl primer `\"/static\"` se refiere al sub-path en el que esta \"sub-aplicación\" será \"montada\". Por lo tanto, cualquier path que comience con `\"/static\"` será manejado por ella.\n\nEl `directory=\"static\"` se refiere al nombre del directorio que contiene tus archivos estáticos.\n\nEl `name=\"static\"` le da un nombre que puede ser utilizado internamente por **FastAPI**.\n\nTodos estos parámetros pueden ser diferentes a \"`static`\", ajústalos según las necesidades y detalles específicos de tu propia aplicación.\n\n## Más info { #more-info }\n\nPara más detalles y opciones revisa [la documentación de Starlette sobre Archivos Estáticos](https://www.starlette.dev/staticfiles/).\n"
  },
  {
    "path": "docs/es/docs/tutorial/stream-json-lines.md",
    "content": "# Transmitir JSON Lines { #stream-json-lines }\n\nPodrías tener una secuencia de datos que quieras enviar en un \"**stream**\", podrías hacerlo con **JSON Lines**.\n\n/// info | Información\n\nAñadido en FastAPI 0.134.0.\n\n///\n\n## ¿Qué es un Stream? { #what-is-a-stream }\n\nHacer \"**Streaming**\" de datos significa que tu app empezará a enviar ítems de datos al cliente sin esperar a que toda la secuencia de ítems esté lista.\n\nEntonces, enviará el primer ítem, el cliente lo recibirá y empezará a procesarlo, y tú podrías seguir produciendo el siguiente ítem.\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\nIncluso podría ser un stream infinito, donde sigues enviando datos.\n\n## JSON Lines { #json-lines }\n\nEn estos casos, es común enviar \"**JSON Lines**\", que es un formato donde envías un objeto JSON por línea.\n\nUna response tendría un tipo de contenido `application/jsonl` (en lugar de `application/json`) y el response body sería algo como:\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\nEs muy similar a un array JSON (equivalente de una list de Python), pero en lugar de estar envuelto en `[]` y tener `,` entre los ítems, tiene **un objeto JSON por línea**, separados por un carácter de nueva línea.\n\n/// info | Información\n\nEl punto importante es que tu app podrá producir cada línea a su turno, mientras el cliente consume las líneas anteriores.\n\n///\n\n/// note | Detalles técnicos\n\nComo cada objeto JSON estará separado por una nueva línea, no pueden contener caracteres de nueva línea literales en su contenido, pero sí pueden contener nuevas líneas escapadas (`\\n`), lo cual es parte del estándar JSON.\n\nPero normalmente no tendrás que preocuparte por eso, se hace automáticamente, sigue leyendo. 🤓\n\n///\n\n## Casos de uso { #use-cases }\n\nPodrías usar esto para hacer stream de datos desde un servicio de **AI LLM**, desde **logs** o **telemetry**, o desde otros tipos de datos que puedan estructurarse en ítems **JSON**.\n\n/// tip | Consejo\n\nSi quieres hacer stream de datos binarios, por ejemplo video o audio, Revisa la guía avanzada: [Transmitir datos](../advanced/stream-data.md).\n\n///\n\n## Transmitir JSON Lines con FastAPI { #stream-json-lines-with-fastapi }\n\nPara transmitir JSON Lines con FastAPI puedes, en lugar de usar `return` en tu *path operation function*, usar `yield` para producir cada ítem a su turno.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\nSi cada ítem JSON que quieres enviar de vuelta es de tipo `Item` (un modelo de Pydantic) y es una función async, puedes declarar el tipo de retorno como `AsyncIterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\nSi declaras el tipo de retorno, FastAPI lo usará para **validar** los datos, **documentarlos** en OpenAPI, **filtrarlos** y **serializarlos** usando Pydantic.\n\n/// tip | Consejo\n\nComo Pydantic lo serializará en el lado de **Rust**, obtendrás un **rendimiento** mucho mayor que si no declaras un tipo de retorno.\n\n///\n\n### *path operation functions* no-async { #non-async-path-operation-functions }\n\nTambién puedes usar funciones `def` regulares (sin `async`), y usar `yield` de la misma forma.\n\nFastAPI se asegurará de que se ejecute correctamente para que no bloquee el event loop.\n\nComo en este caso la función no es async, el tipo de retorno correcto sería `Iterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### Sin tipo de retorno { #no-return-type }\n\nTambién puedes omitir el tipo de retorno. Entonces FastAPI usará [`jsonable_encoder`](./encoder.md) para convertir los datos a algo que se pueda serializar a JSON y luego enviarlo como JSON Lines.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## Server-Sent Events (SSE) { #server-sent-events-sse }\n\nFastAPI también tiene soporte de primera clase para Server-Sent Events (SSE), que son bastante similares pero con un par de detalles extra. Puedes aprender sobre ellos en el siguiente capítulo: [Eventos enviados por el servidor (SSE)](server-sent-events.md). 🤓\n"
  },
  {
    "path": "docs/es/docs/tutorial/testing.md",
    "content": "# Testing { #testing }\n\nGracias a [Starlette](https://www.starlette.dev/testclient/), escribir pruebas para aplicaciones de **FastAPI** es fácil y agradable.\n\nEstá basado en [HTTPX](https://www.python-httpx.org), que a su vez está diseñado basado en Requests, por lo que es muy familiar e intuitivo.\n\nCon él, puedes usar [pytest](https://docs.pytest.org/) directamente con **FastAPI**.\n\n## Usando `TestClient` { #using-testclient }\n\n/// info | Información\n\nPara usar `TestClient`, primero instala [`httpx`](https://www.python-httpx.org).\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo y luego instalarlo, por ejemplo:\n\n```console\n$ pip install httpx\n```\n\n///\n\nImporta `TestClient`.\n\nCrea un `TestClient` pasándole tu aplicación de **FastAPI**.\n\nCrea funciones con un nombre que comience con `test_` (esta es la convención estándar de `pytest`).\n\nUsa el objeto `TestClient` de la misma manera que con `httpx`.\n\nEscribe declaraciones `assert` simples con las expresiones estándar de Python que necesites revisar (otra vez, estándar de `pytest`).\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip | Consejo\n\nNota que las funciones de prueba son `def` normales, no `async def`.\n\nY las llamadas al cliente también son llamadas normales, sin usar `await`.\n\nEsto te permite usar `pytest` directamente sin complicaciones.\n\n///\n\n/// note | Detalles técnicos\n\nTambién podrías usar `from starlette.testclient import TestClient`.\n\n**FastAPI** proporciona el mismo `starlette.testclient` como `fastapi.testclient` solo por conveniencia para ti, el desarrollador. Pero proviene directamente de Starlette.\n\n///\n\n/// tip | Consejo\n\nSi quieres llamar a funciones `async` en tus pruebas además de enviar requests a tu aplicación FastAPI (por ejemplo, funciones asincrónicas de bases de datos), echa un vistazo a las [Pruebas Asincrónicas](../advanced/async-tests.md) en el tutorial avanzado.\n\n///\n\n## Separando pruebas { #separating-tests }\n\nEn una aplicación real, probablemente tendrías tus pruebas en un archivo diferente.\n\nY tu aplicación de **FastAPI** también podría estar compuesta de varios archivos/módulos, etc.\n\n### Archivo de aplicación **FastAPI** { #fastapi-app-file }\n\nDigamos que tienes una estructura de archivos como se describe en [Aplicaciones Más Grandes](bigger-applications.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\nEn el archivo `main.py` tienes tu aplicación de **FastAPI**:\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### Archivo de prueba { #testing-file }\n\nEntonces podrías tener un archivo `test_main.py` con tus pruebas. Podría estar en el mismo paquete de Python (el mismo directorio con un archivo `__init__.py`):\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nDebido a que este archivo está en el mismo paquete, puedes usar importaciones relativas para importar el objeto `app` desde el módulo `main` (`main.py`):\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n...y tener el código para las pruebas tal como antes.\n\n## Pruebas: ejemplo extendido { #testing-extended-example }\n\nAhora extiende este ejemplo y añade más detalles para ver cómo escribir pruebas para diferentes partes.\n\n### Archivo de aplicación **FastAPI** extendido { #extended-fastapi-app-file }\n\nContinuemos con la misma estructura de archivos que antes:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nDigamos que ahora el archivo `main.py` con tu aplicación de **FastAPI** tiene algunas otras **path operations**.\n\nTiene una operación `GET` que podría devolver un error.\n\nTiene una operación `POST` que podría devolver varios errores.\n\nAmbas *path operations* requieren un `X-Token` header.\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### Archivo de prueba extendido { #extended-testing-file }\n\nPodrías entonces actualizar `test_main.py` con las pruebas extendidas:\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\nCada vez que necesites que el cliente pase información en el request y no sepas cómo, puedes buscar (Googlear) cómo hacerlo en `httpx`, o incluso cómo hacerlo con `requests`, dado que el diseño de HTTPX está basado en el diseño de Requests.\n\nLuego simplemente haces lo mismo en tus pruebas.\n\nPor ejemplo:\n\n* Para pasar un parámetro de *path* o *query*, añádelo a la URL misma.\n* Para pasar un cuerpo JSON, pasa un objeto de Python (por ejemplo, un `dict`) al parámetro `json`.\n* Si necesitas enviar *Form Data* en lugar de JSON, usa el parámetro `data` en su lugar.\n* Para pasar *headers*, usa un `dict` en el parámetro `headers`.\n* Para *cookies*, un `dict` en el parámetro `cookies`.\n\nPara más información sobre cómo pasar datos al backend (usando `httpx` o el `TestClient`) revisa la [documentación de HTTPX](https://www.python-httpx.org).\n\n/// info | Información\n\nTen en cuenta que el `TestClient` recibe datos que pueden ser convertidos a JSON, no modelos de Pydantic.\n\nSi tienes un modelo de Pydantic en tu prueba y quieres enviar sus datos a la aplicación durante las pruebas, puedes usar el `jsonable_encoder` descrito en [Codificador Compatible con JSON](encoder.md).\n\n///\n\n## Ejecútalo { #run-it }\n\nDespués de eso, solo necesitas instalar `pytest`.\n\nAsegúrate de crear un [entorno virtual](../virtual-environments.md), activarlo y luego instalarlo, por ejemplo:\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\nDetectará los archivos y pruebas automáticamente, ejecutará las mismas y te reportará los resultados.\n\nEjecuta las pruebas con:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/es/docs/virtual-environments.md",
    "content": "# Entornos Virtuales { #virtual-environments }\n\nCuando trabajas en proyectos de Python probablemente deberías usar un **entorno virtual** (o un mecanismo similar) para aislar los paquetes que instalas para cada proyecto.\n\n/// info | Información\n\nSi ya sabes sobre entornos virtuales, cómo crearlos y usarlos, podrías querer saltar esta sección. 🤓\n\n///\n\n/// tip | Consejo\n\nUn **entorno virtual** es diferente de una **variable de entorno**.\n\nUna **variable de entorno** es una variable en el sistema que puede ser usada por programas.\n\nUn **entorno virtual** es un directorio con algunos archivos en él.\n\n///\n\n/// info | Información\n\nEsta página te enseñará cómo usar **entornos virtuales** y cómo funcionan.\n\nSi estás listo para adoptar una **herramienta que gestiona todo** por ti (incluyendo la instalación de Python), prueba [uv](https://github.com/astral-sh/uv).\n\n///\n\n## Crea un Proyecto { #create-a-project }\n\nPrimero, crea un directorio para tu proyecto.\n\nLo que normalmente hago es crear un directorio llamado `code` dentro de mi directorio de usuario.\n\nY dentro de eso creo un directorio por proyecto.\n\n<div class=\"termy\">\n\n```console\n// Ve al directorio principal\n$ cd\n// Crea un directorio para todos tus proyectos de código\n$ mkdir code\n// Entra en ese directorio de código\n$ cd code\n// Crea un directorio para este proyecto\n$ mkdir awesome-project\n// Entra en ese directorio del proyecto\n$ cd awesome-project\n```\n\n</div>\n\n## Crea un Entorno Virtual { #create-a-virtual-environment }\n\nCuando empiezas a trabajar en un proyecto de Python **por primera vez**, crea un entorno virtual **<dfn title=\"hay otras opciones, esto es solo una guía sencilla\">dentro de tu proyecto</dfn>**.\n\n/// tip | Consejo\n\nSolo necesitas hacer esto **una vez por proyecto**, no cada vez que trabajas.\n\n///\n\n//// tab | `venv`\n\nPara crear un entorno virtual, puedes usar el módulo `venv` que viene con Python.\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | Qué significa ese comando\n\n* `python`: usa el programa llamado `python`\n* `-m`: llama a un módulo como un script, indicaremos cuál módulo a continuación\n* `venv`: usa el módulo llamado `venv` que normalmente viene instalado con Python\n* `.venv`: crea el entorno virtual en el nuevo directorio `.venv`\n\n///\n\n////\n\n//// tab | `uv`\n\nSi tienes instalado [`uv`](https://github.com/astral-sh/uv), puedes usarlo para crear un entorno virtual.\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip | Consejo\n\nPor defecto, `uv` creará un entorno virtual en un directorio llamado `.venv`.\n\nPero podrías personalizarlo pasando un argumento adicional con el nombre del directorio.\n\n///\n\n////\n\nEse comando crea un nuevo entorno virtual en un directorio llamado `.venv`.\n\n/// details | `.venv` u otro nombre\n\nPodrías crear el entorno virtual en un directorio diferente, pero hay una convención de llamarlo `.venv`.\n\n///\n\n## Activa el Entorno Virtual { #activate-the-virtual-environment }\n\nActiva el nuevo entorno virtual para que cualquier comando de Python que ejecutes o paquete que instales lo utilicen.\n\n/// tip | Consejo\n\nHaz esto **cada vez** que inicies una **nueva sesión de terminal** para trabajar en el proyecto.\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nO si usas Bash para Windows (por ejemplo, [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip | Consejo\n\nCada vez que instales un **nuevo paquete** en ese entorno, **activa** el entorno de nuevo.\n\nEsto asegura que si usas un programa de **terminal (<abbr title=\"command line interface – interfaz de línea de comandos\">CLI</abbr>)** instalado por ese paquete, uses el de tu entorno virtual y no cualquier otro que podría estar instalado globalmente, probablemente con una versión diferente a la que necesitas.\n\n///\n\n## Revisa que el Entorno Virtual esté Activo { #check-the-virtual-environment-is-active }\n\nRevisa que el entorno virtual esté activo (el comando anterior funcionó).\n\n/// tip | Consejo\n\nEsto es **opcional**, pero es una buena forma de **revisar** que todo está funcionando como se esperaba y estás usando el entorno virtual que pretendes.\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\nSi muestra el binario de `python` en `.venv/bin/python`, dentro de tu proyecto (en este caso `awesome-project`), entonces funcionó. 🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\nSi muestra el binario de `python` en `.venv\\Scripts\\python`, dentro de tu proyecto (en este caso `awesome-project`), entonces funcionó. 🎉\n\n////\n\n## Actualiza `pip` { #upgrade-pip }\n\n/// tip | Consejo\n\nSi usas [`uv`](https://github.com/astral-sh/uv) usarías eso para instalar cosas en lugar de `pip`, por lo que no necesitas actualizar `pip`. 😎\n\n///\n\nSi estás usando `pip` para instalar paquetes (viene por defecto con Python), deberías **actualizarlo** a la última versión.\n\nMuchos errores exóticos al instalar un paquete se resuelven simplemente actualizando `pip` primero.\n\n/// tip | Consejo\n\nNormalmente harías esto **una vez**, justo después de crear el entorno virtual.\n\n///\n\nAsegúrate de que el entorno virtual esté activo (con el comando anterior) y luego ejecuta:\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip | Consejo\n\nA veces, podrías obtener un error **`No module named pip`** al intentar actualizar pip.\n\nSi esto pasa, instala y actualiza pip usando el siguiente comando:\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\nEste comando instalará pip si aún no está instalado y también se asegura de que la versión instalada de pip sea al menos tan reciente como la disponible en `ensurepip`.\n\n///\n\n## Añade `.gitignore` { #add-gitignore }\n\nSi estás usando **Git** (deberías), añade un archivo `.gitignore` para excluir todo en tu `.venv` de Git.\n\n/// tip | Consejo\n\nSi usaste [`uv`](https://github.com/astral-sh/uv) para crear el entorno virtual, ya lo hizo por ti, puedes saltarte este paso. 😎\n\n///\n\n/// tip | Consejo\n\nHaz esto **una vez**, justo después de crear el entorno virtual.\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | Qué significa ese comando\n\n* `echo \"*\"`: \"imprimirá\" el texto `*` en el terminal (la siguiente parte cambia eso un poco)\n* `>`: cualquier cosa impresa en el terminal por el comando a la izquierda de `>` no debería imprimirse, sino escribirse en el archivo que va a la derecha de `>`\n* `.gitignore`: el nombre del archivo donde debería escribirse el texto\n\nY `*` para Git significa \"todo\". Así que, ignorará todo en el directorio `.venv`.\n\nEse comando creará un archivo `.gitignore` con el contenido:\n\n```gitignore\n*\n```\n\n///\n\n## Instala Paquetes { #install-packages }\n\nDespués de activar el entorno, puedes instalar paquetes en él.\n\n/// tip | Consejo\n\nHaz esto **una vez** al instalar o actualizar los paquetes que necesita tu proyecto.\n\nSi necesitas actualizar una versión o agregar un nuevo paquete, **harías esto de nuevo**.\n\n///\n\n### Instala Paquetes Directamente { #install-packages-directly }\n\nSi tienes prisa y no quieres usar un archivo para declarar los requisitos de paquetes de tu proyecto, puedes instalarlos directamente.\n\n/// tip | Consejo\n\nEs una (muy) buena idea poner los paquetes y las versiones que necesita tu programa en un archivo (por ejemplo, `requirements.txt` o `pyproject.toml`).\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nSi tienes [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### Instala desde `requirements.txt` { #install-from-requirements-txt }\n\nSi tienes un `requirements.txt`, ahora puedes usarlo para instalar sus paquetes.\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nSi tienes [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\nUn `requirements.txt` con algunos paquetes podría verse así:\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## Ejecuta Tu Programa { #run-your-program }\n\nDespués de activar el entorno virtual, puedes ejecutar tu programa, y usará el Python dentro de tu entorno virtual con los paquetes que instalaste allí.\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## Configura Tu Editor { #configure-your-editor }\n\nProbablemente usarías un editor, asegúrate de configurarlo para que use el mismo entorno virtual que creaste (probablemente lo autodetectará) para que puedas obtener autocompletado y errores en línea.\n\nPor ejemplo:\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip | Consejo\n\nNormalmente solo tendrías que hacer esto **una vez**, cuando crees el entorno virtual.\n\n///\n\n## Desactiva el Entorno Virtual { #deactivate-the-virtual-environment }\n\nUna vez que hayas terminado de trabajar en tu proyecto, puedes **desactivar** el entorno virtual.\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\nDe esta manera, cuando ejecutes `python` no intentará ejecutarse desde ese entorno virtual con los paquetes instalados allí.\n\n## Listo para Trabajar { #ready-to-work }\n\nAhora estás listo para empezar a trabajar en tu proyecto.\n\n/// tip | Consejo\n\n¿Quieres entender todo lo anterior?\n\nContinúa leyendo. 👇🤓\n\n///\n\n## Por qué Entornos Virtuales { #why-virtual-environments }\n\nPara trabajar con FastAPI necesitas instalar [Python](https://www.python.org/).\n\nDespués de eso, necesitarías **instalar** FastAPI y cualquier otro **paquete** que desees usar.\n\nPara instalar paquetes normalmente usarías el comando `pip` que viene con Python (o alternativas similares).\n\nSin embargo, si solo usas `pip` directamente, los paquetes se instalarían en tu **entorno global de Python** (la instalación global de Python).\n\n### El Problema { #the-problem }\n\nEntonces, ¿cuál es el problema de instalar paquetes en el entorno global de Python?\n\nEn algún momento, probablemente terminarás escribiendo muchos programas diferentes que dependen de **diferentes paquetes**. Y algunos de estos proyectos en los que trabajas dependerán de **diferentes versiones** del mismo paquete. 😱\n\nPor ejemplo, podrías crear un proyecto llamado `philosophers-stone`, este programa depende de otro paquete llamado **`harry`, usando la versión `1`**. Así que, necesitas instalar `harry`.\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n\nLuego, en algún momento después, creas otro proyecto llamado `prisoner-of-azkaban`, y este proyecto también depende de `harry`, pero este proyecto necesita **`harry` versión `3`**.\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]\n```\n\nPero ahora el problema es, si instalas los paquetes globalmente (en el entorno global) en lugar de en un **entorno virtual local**, tendrás que elegir qué versión de `harry` instalar.\n\nSi deseas ejecutar `philosophers-stone` necesitarás primero instalar `harry` versión `1`, por ejemplo con:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\nY entonces terminarías con `harry` versión `1` instalada en tu entorno global de Python.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\nPero luego si deseas ejecutar `prisoner-of-azkaban`, necesitarás desinstalar `harry` versión `1` e instalar `harry` versión `3` (o simplemente instalar la versión `3` automáticamente desinstalaría la versión `1`).\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\nY entonces terminarías con `harry` versión `3` instalada en tu entorno global de Python.\n\nY si intentas ejecutar `philosophers-stone` de nuevo, hay una posibilidad de que **no funcione** porque necesita `harry` versión `1`.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --> |requires| harry-3\n    end\n```\n\n/// tip | Consejo\n\nEs muy común en los paquetes de Python intentar lo mejor para **evitar romper cambios** en **nuevas versiones**, pero es mejor estar seguro e instalar nuevas versiones intencionalmente y cuando puedas ejecutar las pruebas para verificar que todo está funcionando correctamente.\n\n///\n\nAhora, imagina eso con **muchos** otros **paquetes** de los que dependen todos tus **proyectos**. Eso es muy difícil de manejar. Y probablemente terminarías ejecutando algunos proyectos con algunas **versiones incompatibles** de los paquetes, y sin saber por qué algo no está funcionando.\n\nAdemás, dependiendo de tu sistema operativo (por ejemplo, Linux, Windows, macOS), podría haber venido con Python ya instalado. Y en ese caso probablemente tenía algunos paquetes preinstalados con algunas versiones específicas **necesitadas por tu sistema**. Si instalas paquetes en el entorno global de Python, podrías terminar **rompiendo** algunos de los programas que vinieron con tu sistema operativo.\n\n## Dónde se Instalan los Paquetes { #where-are-packages-installed }\n\nCuando instalas Python, crea algunos directorios con algunos archivos en tu computadora.\n\nAlgunos de estos directorios son los encargados de tener todos los paquetes que instalas.\n\nCuando ejecutas:\n\n<div class=\"termy\">\n\n```console\n// No ejecutes esto ahora, solo es un ejemplo 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\nEso descargará un archivo comprimido con el código de FastAPI, normalmente desde [PyPI](https://pypi.org/project/fastapi/).\n\nTambién **descargará** archivos para otros paquetes de los que depende FastAPI.\n\nLuego, **extraerá** todos esos archivos y los pondrá en un directorio en tu computadora.\n\nPor defecto, pondrá esos archivos descargados y extraídos en el directorio que viene con tu instalación de Python, eso es el **entorno global**.\n\n## Qué son los Entornos Virtuales { #what-are-virtual-environments }\n\nLa solución a los problemas de tener todos los paquetes en el entorno global es usar un **entorno virtual para cada proyecto** en el que trabajas.\n\nUn entorno virtual es un **directorio**, muy similar al global, donde puedes instalar los paquetes para un proyecto.\n\nDe esta manera, cada proyecto tendrá su propio entorno virtual (directorio `.venv`) con sus propios paquetes.\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) --->|requires| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --->|requires| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## Qué Significa Activar un Entorno Virtual { #what-does-activating-a-virtual-environment-mean }\n\nCuando activas un entorno virtual, por ejemplo con:\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nO si usas Bash para Windows (por ejemplo, [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\nEse comando creará o modificará algunas [variables de entorno](environment-variables.md) que estarán disponibles para los siguientes comandos.\n\nUna de esas variables es la variable `PATH`.\n\n/// tip | Consejo\n\nPuedes aprender más sobre la variable de entorno `PATH` en la sección [Variables de Entorno](environment-variables.md#path-environment-variable).\n\n///\n\nActivar un entorno virtual agrega su path `.venv/bin` (en Linux y macOS) o `.venv\\Scripts` (en Windows) a la variable de entorno `PATH`.\n\nDigamos que antes de activar el entorno, la variable `PATH` se veía así:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nEso significa que el sistema buscaría programas en:\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\nEso significa que el sistema buscaría programas en:\n\n* `C:\\Windows\\System32`\n\n////\n\nDespués de activar el entorno virtual, la variable `PATH` se vería algo así:\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nEso significa que el sistema ahora comenzará a buscar primero los programas en:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\nantes de buscar en los otros directorios.\n\nAsí que, cuando escribas `python` en el terminal, el sistema encontrará el programa Python en\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\ny utilizará ese.\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\nEso significa que el sistema ahora comenzará a buscar primero los programas en:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\nantes de buscar en los otros directorios.\n\nAsí que, cuando escribas `python` en el terminal, el sistema encontrará el programa Python en\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\ny utilizará ese.\n\n////\n\nUn detalle importante es que pondrá el path del entorno virtual al **comienzo** de la variable `PATH`. El sistema lo encontrará **antes** que cualquier otro Python disponible. De esta manera, cuando ejecutes `python`, utilizará el Python **del entorno virtual** en lugar de cualquier otro `python` (por ejemplo, un `python` de un entorno global).\n\nActivar un entorno virtual también cambia un par de otras cosas, pero esta es una de las cosas más importantes que hace.\n\n## Revisando un Entorno Virtual { #checking-a-virtual-environment }\n\nCuando revisas si un entorno virtual está activo, por ejemplo con:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\nEso significa que el programa `python` que se utilizará es el que está **en el entorno virtual**.\n\nUsas `which` en Linux y macOS y `Get-Command` en Windows PowerShell.\n\nLa forma en que funciona ese comando es que irá y revisará la variable de entorno `PATH`, pasando por **cada path en orden**, buscando el programa llamado `python`. Una vez que lo encuentre, te **mostrará el path** a ese programa.\n\nLa parte más importante es que cuando llamas a `python`, ese es el exacto \"`python`\" que será ejecutado.\n\nAsí que, puedes confirmar si estás en el entorno virtual correcto.\n\n/// tip | Consejo\n\nEs fácil activar un entorno virtual, obtener un Python, y luego **ir a otro proyecto**.\n\nY el segundo proyecto **no funcionaría** porque estás usando el **Python incorrecto**, de un entorno virtual para otro proyecto.\n\nEs útil poder revisar qué `python` se está usando. 🤓\n\n///\n\n## Por qué Desactivar un Entorno Virtual { #why-deactivate-a-virtual-environment }\n\nPor ejemplo, podrías estar trabajando en un proyecto `philosophers-stone`, **activar ese entorno virtual**, instalar paquetes y trabajar con ese entorno.\n\nY luego quieres trabajar en **otro proyecto** `prisoner-of-azkaban`.\n\nVas a ese proyecto:\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\nSi no desactivas el entorno virtual para `philosophers-stone`, cuando ejecutes `python` en el terminal, intentará usar el Python de `philosophers-stone`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// Error importando sirius, no está instalado 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\nPero si desactivas el entorno virtual y activas el nuevo para `prisoner-of-askaban` entonces cuando ejecutes `python` utilizará el Python del entorno virtual en `prisoner-of-azkaban`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// No necesitas estar en el directorio antiguo para desactivar, puedes hacerlo donde sea que estés, incluso después de ir al otro proyecto 😎\n$ deactivate\n\n// Activa el entorno virtual en prisoner-of-azkaban/.venv 🚀\n$ source .venv/bin/activate\n\n// Ahora cuando ejecutes python, encontrará el paquete sirius instalado en este entorno virtual ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## Alternativas { #alternatives }\n\nEsta es una guía simple para comenzar y enseñarte cómo funciona todo **por debajo**.\n\nHay muchas **alternativas** para gestionar entornos virtuales, dependencias de paquetes (requisitos), proyectos.\n\nUna vez que estés listo y quieras usar una herramienta para **gestionar todo el proyecto**, dependencias de paquetes, entornos virtuales, etc. Te sugeriría probar [uv](https://github.com/astral-sh/uv).\n\n`uv` puede hacer muchas cosas, puede:\n\n* **Instalar Python** por ti, incluyendo diferentes versiones\n* Gestionar el **entorno virtual** para tus proyectos\n* Instalar **paquetes**\n* Gestionar **dependencias y versiones** de paquetes para tu proyecto\n* Asegurarse de que tengas un conjunto **exacto** de paquetes y versiones para instalar, incluidas sus dependencias, para que puedas estar seguro de que puedes ejecutar tu proyecto en producción exactamente igual que en tu computadora mientras desarrollas, esto se llama **locking**\n* Y muchas otras cosas\n\n## Conclusión { #conclusion }\n\nSi leíste y comprendiste todo esto, ahora **sabes mucho más** sobre entornos virtuales que muchos desarrolladores por ahí. 🤓\n\nConocer estos detalles probablemente te será útil en el futuro cuando estés depurando algo que parece complejo, pero sabrás **cómo funciona todo por debajo**. 😎\n"
  },
  {
    "path": "docs/es/llm-prompt.md",
    "content": "Translate to Spanish (español).\n\nUse the informal grammar (use \"tú\" instead of \"usted\").\n\nFor instructions or titles in imperative, keep them in imperative, for example \"Edit it\" to \"Edítalo\".\n\n---\n\nFor the next terms, use the following translations:\n\n* framework: framework (do not translate to \"marco\")\n* performance: rendimiento\n* program (verb): programar\n* code (verb): programar\n* type hints: anotaciones de tipos\n* type annotations: anotaciones de tipos\n* autocomplete: autocompletado\n* completion (in the context of autocompletion): autocompletado\n* feature: funcionalidad\n* sponsor: sponsor\n* host (in a podcast): host\n* request (as in HTTP request): request\n* response (as in HTTP response): response\n* path operation function: path operation function (do not translate to \"función de operación de ruta\")\n* path operation: path operation (do not translate to \"operación de ruta\")\n* path (as in URL path): path (do not translate to \"ruta\")\n* query (as in URL query): query (do not translate to \"consulta\")\n* cookie (as in HTTP cookie): cookie\n* header (as in HTTP header): header\n* form (as in HTML form): formulario\n* type checks: chequeo de tipos\n* parse: parse\n* parsing: parsing\n* marshall: marshall\n* library: paquete (do not translate to \"biblioteca\" or \"librería\")\n* instance: instance (do not translate to \"instancia\")\n* scratch the surface: tocar los conceptos básicos\n* string: string\n* bug: bug\n* docs: documentación (do not translate to \"documentos\")\n* cheat sheet: cheat sheet (do not translate to \"chuleta\")\n* key (as in key-value pair, dictionary key): clave\n* array (as in JSON array): array\n* API key: API key (do not translate to \"clave API\")\n* 100% test coverage: cobertura de tests del 100%\n* back and forth: de un lado a otro\n* I/O (as in \"input and output\"): I/O (do not translate to \"E/S\")\n* Machine Learning: Machine Learning (do not translate to \"Aprendizaje Automático\")\n* Deep Learning: Deep Learning (do not translate to \"Aprendizaje Profundo\")\n* callback hell: callback hell (do not translate to \"infierno de callbacks\")\n* tip: Consejo (do not translate to \"tip\")\n* check: Revisa (do not translate to \"chequea\" or \"comprobación\")\n* Cross-Origin Resource Sharing: Cross-Origin Resource Sharing (do not translate to \"Compartición de Recursos de Origen Cruzado\")\n* Release Notes: Release Notes (do not translate to \"Notas de la Versión\")\n* Semantic Versioning: Semantic Versioning (do not translate to \"Versionado Semántico\")\n* dependable: dependable (do not translate to \"confiable\" or \"fiable\")\n* list (as in Python list): list\n* context manager: context manager (do not translate to \"gestor de contexto\" or \"administrador de contexto\")\n* a little bit: un poquito\n* graph (data structure, as in \"dependency graph\"): grafo (do not translate to \"gráfico\")\n* form data: form data (do not translate to \"datos de formulario\" or \"datos de form\")\n* import (as in code import): import (do not translate to \"importación\")\n* JSON Schema: JSON Schema (do not translate to \"Esquema JSON\")\n* embed: embeber (do not translate to \"incrustar\")\n* request body: request body (do not translate to \"cuerpo de la petición\")\n* response body: response body (do not translate to \"cuerpo de la respuesta\")\n* cross domain: cross domain (do not translate to \"dominio cruzado\")\n* cross origin: cross origin (do not translate to \"origen cruzado\")\n* plugin: plugin (do not translate to \"complemento\" or \"extensión\")\n* plug-in: plug-in (do not translate to \"complemento\" or \"extensión\")\n* plug-ins: plug-ins (do not translate to \"complementos\" or \"extensiones\")\n* full stack: full stack (do not translate to \"pila completa\")\n* full-stack: full-stack (do not translate to \"de pila completa\")\n* stack: stack (do not translate to \"pila\")\n* loop (as in async loop): loop (do not translate to \"bucle\" or \"ciclo\")\n* hard dependencies: dependencias obligatorias (do not translate to \"dependencias duras\")\n* locking: locking (do not translate to \"bloqueo\")\n* testing (as in software testing): escribir pruebas (do not translate to \"probar\")\n* code base: code base (do not translate to \"base de código\")\n* default: por defecto (do not translate to \"predeterminado\")\n* default values: valores por defecto (do not translate to \"valores predeterminados\")\n* media type: media type (do not translate to \"tipo de medio\")\n* instantiate: crear un instance (do not translate to \"instanciar\")\n* OAuth2 Scopes: Scopes de OAuth2 (do not translate to \"Alcances de OAuth2\")\n* on the fly: sobre la marcha (do not translate to \"al vuelo\")\n* terminal: terminal (feminine, as in \"la terminal\")\n* terminals: terminales (plural feminine, as in \"las terminales\")\n* lifespan: lifespan (do not translate to \"vida útil\" or \"tiempo de vida\")\n* unload: quitar de memoria (do not translate to \"descargar\")\n* mount (noun): mount (do not translate to \"montura\")\n* mount (verb): montar\n* statement (as in code statement): statement (do not translate to \"declaración\" or \"sentencia\")\n* worker process: worker process (do not translate to \"proceso trabajador\" or \"proceso de trabajo\")\n* worker processes: worker processes (do not translate to \"procesos trabajadores\" or \"procesos de trabajo\")\n* worker: worker (do not translate to \"trabajador\")\n* load balancer: load balancer (do not translate to \"balanceador de carga\")\n* load balance: load balance (do not translate to \"balancear carga\")\n* self hosting: self hosting (do not translate to \"auto alojamiento\")\n* timing attack: timing attack (do not translate to \"ataque de temporización\")\n"
  },
  {
    "path": "docs/es/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs/fr/docs/_llm-test.md",
    "content": "# Fichier de test LLM { #llm-test-file }\n\nCe document teste si le <abbr title=\"Large Language Model - Grand modèle de langage\">LLM</abbr>, qui traduit la documentation, comprend le `general_prompt` dans `scripts/translate.py` et l’invite spécifique à la langue dans `docs/{language code}/llm-prompt.md`. L’invite spécifique à la langue est ajoutée à la fin de `general_prompt`.\n\nLes tests ajoutés ici seront visibles par tous les concepteurs d’invites spécifiques à chaque langue.\n\nUtiliser comme suit :\n\n* Avoir une invite spécifique à la langue - `docs/{language code}/llm-prompt.md`.\n* Effectuer une nouvelle traduction de ce document dans votre langue cible souhaitée (voir par exemple la commande `translate-page` de `translate.py`). Cela créera la traduction sous `docs/{language code}/docs/_llm-test.md`.\n* Vérifier si tout est correct dans la traduction.\n* Si nécessaire, améliorer votre invite spécifique à la langue, l’invite générale, ou le document anglais.\n* Corriger ensuite manuellement les problèmes restants dans la traduction, afin que ce soit une bonne traduction.\n* Retraduire, en ayant la bonne traduction en place. Le résultat idéal serait que le LLM ne fasse plus aucun changement à la traduction. Cela signifie que l’invite générale et votre invite spécifique à la langue sont aussi bonnes que possible (il fera parfois quelques changements apparemment aléatoires, la raison étant que [les LLM ne sont pas des algorithmes déterministes](https://doublespeak.chat/#/handbook#deterministic-output)).\n\nLes tests :\n\n## Extraits de code { #code-snippets }\n\n//// tab | Test\n\nCeci est un extrait de code : `foo`. Et ceci est un autre extrait de code : `bar`. Et encore un autre : `baz quux`.\n\n////\n\n//// tab | Info\n\nLe contenu des extraits de code doit être laissé tel quel.\n\nVoir la section `### Content of code snippets` dans l’invite générale dans `scripts/translate.py`.\n\n////\n\n## Guillemets { #quotes }\n\n//// tab | Test\n\nHier, mon ami a écrit : « Si vous écrivez « incorrectly » correctement, vous l’avez écrit de façon incorrecte ». À quoi j’ai répondu : « Correct, mais ‘incorrectly’ est incorrectement non pas ‘« incorrectly »’ ».\n\n/// note | Remarque\n\nLe LLM traduira probablement ceci de manière erronée. Il est seulement intéressant de voir s’il conserve la traduction corrigée lors d’une retraduction.\n\n///\n\n////\n\n//// tab | Info\n\nLe concepteur de l’invite peut choisir s’il souhaite convertir les guillemets neutres en guillemets typographiques. Il est acceptable de les laisser tels quels.\n\nVoir par exemple la section `### Quotes` dans `docs/de/llm-prompt.md`.\n\n////\n\n## Guillemets dans les extraits de code { #quotes-in-code-snippets }\n\n//// tab | Test\n\n`pip install \"foo[bar]\"`\n\nExemples de littéraux de chaîne dans des extraits de code : `\"this\"`, `'that'`.\n\nUn exemple difficile de littéraux de chaîne dans des extraits de code : `f\"I like {'oranges' if orange else \"apples\"}\"`\n\nHardcore: `Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | Info\n\n... Cependant, les guillemets à l’intérieur des extraits de code doivent rester tels quels.\n\n////\n\n## Blocs de code { #code-blocks }\n\n//// tab | Test\n\nUn exemple de code Bash ...\n\n```bash\n# Afficher un message de bienvenue à l'univers\necho \"Hello universe\"\n```\n\n... et un exemple de code console ...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n... et un autre exemple de code console ...\n\n```console\n// Créer un répertoire \"Code\"\n$ mkdir code\n// Aller dans ce répertoire\n$ cd code\n```\n\n... et un exemple de code Python ...\n\n```Python\nwont_work()  # Cela ne fonctionnera pas 😱\nworks(foo=\"bar\")  # Cela fonctionne 🎉\n```\n\n... et c’est tout.\n\n////\n\n//// tab | Info\n\nLe code dans les blocs de code ne doit pas être modifié, à l’exception des commentaires.\n\nVoir la section `### Content of code blocks` dans l’invite générale dans `scripts/translate.py`.\n\n////\n\n## Onglets et encadrés colorés { #tabs-and-colored-boxes }\n\n//// tab | Test\n\n/// info | Info\nDu texte\n///\n\n/// note | Remarque\nDu texte\n///\n\n/// note | Détails techniques\nDu texte\n///\n\n/// check | Vérifications\nDu texte\n///\n\n/// tip | Astuce\nDu texte\n///\n\n/// warning | Alertes\nDu texte\n///\n\n/// danger | Danger\nDu texte\n///\n\n////\n\n//// tab | Info\n\nLes onglets et les blocs « Info »/« Note »/« Warning »/etc. doivent avoir la traduction de leur titre ajoutée après une barre verticale (« | »).\n\nVoir les sections `### Special blocks` et `### Tab blocks` dans l’invite générale dans `scripts/translate.py`.\n\n////\n\n## Liens Web et internes { #web-and-internal-links }\n\n//// tab | Test\n\nLe texte du lien doit être traduit, l’adresse du lien doit rester inchangée :\n\n* [Lien vers le titre ci-dessus](#code-snippets)\n* [Lien interne](index.md#installation)\n* [Lien externe](https://sqlmodel.tiangolo.com/)\n* [Lien vers une feuille de style](https://fastapi.tiangolo.com/css/styles.css)\n* [Lien vers un script](https://fastapi.tiangolo.com/js/logic.js)\n* [Lien vers une image](https://fastapi.tiangolo.com/img/foo.jpg)\n\nLe texte du lien doit être traduit, l’adresse du lien doit pointer vers la traduction :\n\n* [Lien FastAPI](https://fastapi.tiangolo.com/fr/)\n\n////\n\n//// tab | Info\n\nLes liens doivent être traduits, mais leur adresse doit rester inchangée. Exception faite des liens absolus vers des pages de la documentation FastAPI. Dans ce cas, il faut pointer vers la traduction.\n\nVoir la section `### Links` dans l’invite générale dans `scripts/translate.py`.\n\n////\n\n## Éléments HTML « abbr » { #html-abbr-elements }\n\n//// tab | Test\n\nVoici quelques éléments entourés d’un élément HTML « abbr » (certains sont inventés) :\n\n### L’abbr fournit une expression complète { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done - S'organiser pour réussir\">GTD</abbr>\n* <abbr title=\"less than - inférieur à\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token - Jeton Web XML\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface - Interface passerelle serveur parallèle\">PSGI</abbr>\n\n### L’abbr donne une expression complète et une explication { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network - Réseau des développeurs Mozilla: documentation pour les développeurs, écrite par l’équipe Firefox\">MDN</abbr>\n* <abbr title=\"Input/Output - Entrée/Sortie: lecture ou écriture sur le disque, communications réseau.\">I/O</abbr>.\n\n////\n\n//// tab | Info\n\nLes attributs « title » des éléments « abbr » sont traduits en suivant des consignes spécifiques.\n\nLes traductions peuvent ajouter leurs propres éléments « abbr » que le LLM ne doit pas supprimer. Par exemple pour expliquer des mots anglais.\n\nVoir la section `### HTML abbr elements` dans l’invite générale dans `scripts/translate.py`.\n\n////\n\n## Éléments HTML « dfn » { #html-dfn-elements }\n\n* <dfn title=\"Un groupe de machines configurées pour être connectées et travailler ensemble d’une certaine manière.\">grappe</dfn>\n* <dfn title=\"Une méthode d’apprentissage automatique qui utilise des réseaux de neurones artificiels avec de nombreuses couches cachées entre les couches d’entrée et de sortie, développant ainsi une structure interne complète\">Apprentissage profond</dfn>\n\n## Titres { #headings }\n\n//// tab | Test\n\n### Créer une application Web - un tutoriel { #develop-a-webapp-a-tutorial }\n\nBonjour.\n\n### Annotations de type et annotations de type { #type-hints-and-annotations }\n\nRebonjour.\n\n### Superclasses et sous-classes { #super-and-subclasses }\n\nRebonjour.\n\n////\n\n//// tab | Info\n\nLa seule règle stricte pour les titres est que le LLM laisse la partie hachage entre accolades inchangée, ce qui garantit que les liens ne se rompent pas.\n\nVoir la section `### Headings` dans l’invite générale dans `scripts/translate.py`.\n\nPour certaines consignes spécifiques à la langue, voir par exemple la section `### Headings` dans `docs/de/llm-prompt.md`.\n\n////\n\n## Termes utilisés dans les documents { #terms-used-in-the-docs }\n\n//// tab | Test\n\n* vous\n* votre\n\n* p. ex.\n* etc.\n\n* `foo` en tant que `int`\n* `bar` en tant que `str`\n* `baz` en tant que `list`\n\n* le Tutoriel - Guide utilisateur\n* le Guide utilisateur avancé\n* la documentation SQLModel\n* la documentation de l’API\n* la documentation automatique\n\n* Data Science\n* Apprentissage profond\n* Apprentissage automatique\n* Injection de dépendances\n* authentification HTTP Basic\n* HTTP Digest\n* format ISO\n* la norme JSON Schema\n* le schéma JSON\n* la définition de schéma\n* Flux Password\n* Mobile\n\n* déprécié\n* conçu\n* invalide\n* à la volée\n* standard\n* par défaut\n* sensible à la casse\n* insensible à la casse\n\n* servir l’application\n* servir la page\n\n* l’app\n* l’application\n\n* la requête\n* la réponse\n* la réponse d’erreur\n\n* le chemin d’accès\n* le décorateur de chemin d’accès\n* la fonction de chemin d’accès\n\n* le corps\n* le corps de la requête\n* le corps de la réponse\n* le corps JSON\n* le corps de formulaire\n* le corps de fichier\n* le corps de la fonction\n\n* le paramètre\n* le paramètre de corps\n* le paramètre de chemin\n* le paramètre de requête\n* le paramètre de cookie\n* le paramètre d’en-tête\n* le paramètre de formulaire\n* le paramètre de fonction\n\n* l’événement\n* l’événement de démarrage\n* le démarrage du serveur\n* l’événement d’arrêt\n* l’événement de cycle de vie\n\n* le gestionnaire\n* le gestionnaire d’événements\n* le gestionnaire d’exceptions\n* gérer\n\n* le modèle\n* le modèle Pydantic\n* le modèle de données\n* le modèle de base de données\n* le modèle de formulaire\n* l’objet modèle\n\n* la classe\n* la classe de base\n* la classe parente\n* la sous-classe\n* la classe enfant\n* la classe sœur\n* la méthode de classe\n\n* l’en-tête\n* les en-têtes\n* l’en-tête d’autorisation\n* l’en-tête `Authorization`\n* l’en-tête transféré\n\n* le système d’injection de dépendances\n* la dépendance\n* l’élément dépendable\n* le dépendant\n\n* lié aux E/S\n* lié au processeur\n* concurrence\n* parallélisme\n* multi-traitement\n\n* la variable d’env\n* la variable d’environnement\n* le `PATH`\n* la variable `PATH`\n\n* l’authentification\n* le fournisseur d’authentification\n* l’autorisation\n* le formulaire d’autorisation\n* le fournisseur d’autorisation\n* l’utilisateur s’authentifie\n* le système authentifie l’utilisateur\n\n* la CLI\n* l’interface en ligne de commande\n\n* le serveur\n* le client\n\n* le fournisseur cloud\n* le service cloud\n\n* le développement\n* les étapes de développement\n\n* le dict\n* le dictionnaire\n* l’énumération\n* l’enum\n* le membre d’enum\n\n* l’encodeur\n* le décodeur\n* encoder\n* décoder\n\n* l’exception\n* lever\n\n* l’expression\n* l’instruction\n\n* le frontend\n* le backend\n\n* la discussion GitHub\n* le ticket GitHub\n\n* la performance\n* l’optimisation des performances\n\n* le type de retour\n* la valeur de retour\n\n* la sécurité\n* le schéma de sécurité\n\n* la tâche\n* la tâche d’arrière-plan\n* la fonction de tâche\n\n* le template\n* le moteur de templates\n\n* l’annotation de type\n* l’annotation de type\n\n* le worker du serveur\n* le worker Uvicorn\n* le Worker Gunicorn\n* le processus worker\n* la classe de worker\n* la charge de travail\n\n* le déploiement\n* déployer\n\n* le SDK\n* le kit de développement logiciel\n\n* le `APIRouter`\n* le `requirements.txt`\n* le jeton Bearer\n* le changement majeur incompatible\n* le bogue\n* le bouton\n* l’appelable\n* le code\n* le commit\n* le gestionnaire de contexte\n* la coroutine\n* la session de base de données\n* le disque\n* le domaine\n* le moteur\n* le faux X\n* la méthode HTTP GET\n* l’élément\n* la bibliothèque\n* le cycle de vie\n* le verrou\n* le middleware\n* l’application mobile\n* le module\n* le montage\n* le réseau\n* l’origine\n* la surcharge\n* le payload\n* le processeur\n* la propriété\n* le proxy\n* la pull request\n* la requête\n* la RAM\n* la machine distante\n* le code d’état\n* la chaîne\n* l’étiquette\n* le framework Web\n* le joker\n* retourner\n* valider\n\n////\n\n//// tab | Info\n\nIl s’agit d’une liste non exhaustive et non normative de termes (principalement) techniques présents dans les documents. Elle peut aider le concepteur de l’invite à déterminer pour quels termes le LLM a besoin d’un coup de main. Par exemple, lorsqu’il continue de remplacer une bonne traduction par une traduction sous-optimale. Ou lorsqu’il a des difficultés à conjuguer/décliner un terme dans votre langue.\n\nVoir par exemple la section `### List of English terms and their preferred German translations` dans `docs/de/llm-prompt.md`.\n\n////\n"
  },
  {
    "path": "docs/fr/docs/about/index.md",
    "content": "# À propos { #about }\n\nÀ propos de FastAPI, de sa conception, de ses sources d'inspiration et plus encore. 🤓\n"
  },
  {
    "path": "docs/fr/docs/advanced/additional-responses.md",
    "content": "# Réponses supplémentaires dans OpenAPI { #additional-responses-in-openapi }\n\n/// warning | Alertes\n\nCeci concerne un sujet plutôt avancé.\n\nSi vous débutez avec **FastAPI**, vous n'en aurez peut-être pas besoin.\n\n///\n\nVous pouvez déclarer des réponses supplémentaires, avec des codes d'état supplémentaires, des types de médias, des descriptions, etc.\n\nCes réponses supplémentaires seront incluses dans le schéma OpenAPI, elles apparaîtront donc également dans la documentation de l'API.\n\nMais pour ces réponses supplémentaires, vous devez vous assurer de renvoyer directement une `Response` comme `JSONResponse`, avec votre code HTTP et votre contenu.\n\n## Réponse supplémentaire avec `model` { #additional-response-with-model }\n\nVous pouvez passer à vos décorateurs de *chemin d'accès* un paramètre `responses`.\n\nIl prend comme valeur un `dict` dont les clés sont des codes HTTP pour chaque réponse, comme `200`, et la valeur de ces clés sont d'autres `dict` avec des informations pour chacun d'eux.\n\nChacun de ces `dict` de réponse peut avoir une clé `model`, contenant un modèle Pydantic, tout comme `response_model`.\n\n**FastAPI** prendra ce modèle, générera son schéma JSON et l'inclura au bon endroit dans OpenAPI.\n\nPar exemple, pour déclarer une autre réponse avec un code HTTP `404` et un modèle Pydantic `Message`, vous pouvez écrire :\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | Remarque\n\nGardez à l'esprit que vous devez renvoyer directement `JSONResponse`.\n\n///\n\n/// info\n\nLa clé `model` ne fait pas partie d'OpenAPI.\n\n**FastAPI** prendra le modèle Pydantic à partir de là, générera le `JSON Schema` et le placera au bon endroit.\n\nLe bon endroit est :\n\n* Dans la clé `content`, qui a pour valeur un autre objet JSON (`dict`) qui contient :\n    * Une clé avec le type de support, par ex. `application/json`, qui contient comme valeur un autre objet JSON, qui contient :\n        * Une clé `schema`, qui a pour valeur le schéma JSON du modèle, voici le bon endroit.\n            * **FastAPI** ajoute ici une référence aux schémas JSON globaux à un autre endroit de votre OpenAPI au lieu de l'inclure directement. De cette façon, d'autres applications et clients peuvent utiliser ces schémas JSON directement, fournir de meilleurs outils de génération de code, etc.\n\n///\n\nLes réponses générées au format OpenAPI pour ce *chemin d'accès* seront :\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nLes schémas sont référencés à un autre endroit du modèle OpenAPI :\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## Types de médias supplémentaires pour la réponse principale { #additional-media-types-for-the-main-response }\n\nVous pouvez utiliser ce même paramètre `responses` pour ajouter différents types de médias pour la même réponse principale.\n\nPar exemple, vous pouvez ajouter un type de média supplémentaire `image/png`, en déclarant que votre *chemin d'accès* peut renvoyer un objet JSON (avec le type de média `application/json`) ou une image PNG :\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | Remarque\n\nNotez que vous devez retourner l'image en utilisant directement un `FileResponse`.\n\n///\n\n/// info\n\nÀ moins que vous ne spécifiiez explicitement un type de média différent dans votre paramètre `responses`, FastAPI supposera que la réponse a le même type de média que la classe de réponse principale (par défaut `application/json`).\n\nMais si vous avez spécifié une classe de réponse personnalisée avec `None` comme type de média, FastAPI utilisera `application/json` pour toute réponse supplémentaire associée à un modèle.\n\n///\n\n## Combiner les informations { #combining-information }\n\nVous pouvez également combiner des informations de réponse provenant de plusieurs endroits, y compris les paramètres `response_model`, `status_code` et `responses`.\n\nVous pouvez déclarer un `response_model`, en utilisant le code HTTP par défaut `200` (ou un code personnalisé si vous en avez besoin), puis déclarer des informations supplémentaires pour cette même réponse dans `responses`, directement dans le schéma OpenAPI.\n\n**FastAPI** conservera les informations supplémentaires des `responses` et les combinera avec le schéma JSON de votre modèle.\n\nPar exemple, vous pouvez déclarer une réponse avec un code HTTP `404` qui utilise un modèle Pydantic et a une `description` personnalisée.\n\nEt une réponse avec un code HTTP `200` qui utilise votre `response_model`, mais inclut un `example` personnalisé :\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\nTout sera combiné et inclus dans votre OpenAPI, et affiché dans la documentation de l'API :\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## Combinez les réponses prédéfinies et les réponses personnalisées { #combine-predefined-responses-and-custom-ones }\n\nVous voulez peut-être avoir des réponses prédéfinies qui s'appliquent à de nombreux *chemins d'accès*, mais vous souhaitez les combiner avec des réponses personnalisées nécessaires à chaque *chemin d'accès*.\n\nDans ces cas, vous pouvez utiliser la technique Python « unpacking » d'un `dict` avec `**dict_to_unpack` :\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\nIci, `new_dict` contiendra toutes les paires clé-valeur de `old_dict` plus la nouvelle paire clé-valeur :\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\nVous pouvez utiliser cette technique pour réutiliser certaines réponses prédéfinies dans vos *chemins d'accès* et les combiner avec des réponses personnalisées supplémentaires.\n\nPar exemple:\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## Plus d'informations sur les réponses OpenAPI { #more-information-about-openapi-responses }\n\nPour voir exactement ce que vous pouvez inclure dans les réponses, vous pouvez consulter ces sections dans la spécification OpenAPI :\n\n* [Objet Responses de OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object), il inclut le `Response Object`.\n* [Objet Response de OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object), vous pouvez inclure n'importe quoi directement dans chaque réponse à l'intérieur de votre paramètre `responses`. Y compris `description`, `headers`, `content` (à l'intérieur de cela, vous déclarez différents types de médias et schémas JSON) et `links`.\n"
  },
  {
    "path": "docs/fr/docs/advanced/additional-status-codes.md",
    "content": "# Codes HTTP supplémentaires { #additional-status-codes }\n\nPar défaut, **FastAPI** renverra les réponses à l'aide d'une structure de données `JSONResponse`, en plaçant la réponse de votre  *chemin d'accès* à l'intérieur de cette `JSONResponse`.\n\nIl utilisera le code HTTP par défaut ou celui que vous avez défini dans votre *chemin d'accès*.\n\n## Codes HTTP supplémentaires { #additional-status-codes_1 }\n\nSi vous souhaitez renvoyer des codes HTTP supplémentaires en plus du code principal, vous pouvez le faire en renvoyant directement une `Response`, comme une `JSONResponse`, et en définissant directement le code HTTP supplémentaire.\n\nPar exemple, disons que vous voulez avoir un *chemin d'accès* qui permet de mettre à jour les éléments et renvoie les codes HTTP 200 « OK » en cas de succès.\n\nMais vous voulez aussi qu'il accepte de nouveaux éléments. Et lorsque les éléments n'existaient pas auparavant, il les crée et renvoie un code HTTP de 201 « Créé ».\n\nPour y parvenir, importez `JSONResponse` et renvoyez-y directement votre contenu, en définissant le `status_code` que vous souhaitez :\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning | Alertes\n\nLorsque vous renvoyez une `Response` directement, comme dans l'exemple ci-dessus, elle sera renvoyée directement.\n\nElle ne sera pas sérialisée avec un modèle, etc.\n\nVous devez vous assurer qu'elle contient les données souhaitées et que les valeurs sont dans un format JSON valide (si vous utilisez une `JSONResponse`).\n\n///\n\n/// note | Détails techniques\n\nVous pouvez également utiliser `from starlette.responses import JSONResponse`.\n\nPar commodité pour vous, le développeur, **FastAPI** fournit les mêmes `starlette.responses` sous la forme de `fastapi.responses`. Mais la plupart des réponses disponibles proviennent directement de Starlette. Il en est de même avec `status`.\n\n///\n\n## Documents OpenAPI et API { #openapi-and-api-docs }\n\nSi vous renvoyez directement des codes HTTP et des réponses supplémentaires, ils ne seront pas inclus dans le schéma OpenAPI (les documents de l'API), car FastAPI n'a aucun moyen de savoir à l'avance ce que vous allez renvoyer.\n\nMais vous pouvez documenter cela dans votre code, en utilisant : [Réponses supplémentaires](additional-responses.md).\n"
  },
  {
    "path": "docs/fr/docs/advanced/advanced-dependencies.md",
    "content": "# Dépendances avancées { #advanced-dependencies }\n\n## Dépendances paramétrées { #parameterized-dependencies }\n\nToutes les dépendances que nous avons vues étaient des fonctions ou des classes fixes.\n\nMais il peut y avoir des cas où vous souhaitez pouvoir définir des paramètres sur la dépendance, sans devoir déclarer de nombreuses fonctions ou classes différentes.\n\nImaginons que nous voulions avoir une dépendance qui vérifie si le paramètre de requête `q` contient un contenu fixe.\n\nMais nous voulons pouvoir paramétrer ce contenu fixe.\n\n## Une instance « callable » { #a-callable-instance }\n\nEn Python, il existe un moyen de rendre une instance de classe « callable ».\n\nPas la classe elle‑même (qui est déjà un callable), mais une instance de cette classe.\n\nPour cela, nous déclarons une méthode `__call__` :\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\nDans ce cas, ce `__call__` est ce que **FastAPI** utilisera pour détecter des paramètres supplémentaires et des sous‑dépendances, et c’est ce qui sera appelé pour transmettre ensuite une valeur au paramètre dans votre *fonction de chemin d'accès*.\n\n## Paramétrer l'instance { #parameterize-the-instance }\n\nEt maintenant, nous pouvons utiliser `__init__` pour déclarer les paramètres de l’instance, que nous utiliserons pour « paramétrer » la dépendance :\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\nDans ce cas, **FastAPI** n’accèdera pas à `__init__` et ne s’en souciera pas ; nous l’utiliserons directement dans notre code.\n\n## Créer une instance { #create-an-instance }\n\nNous pouvons créer une instance de cette classe avec :\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\nEt de cette façon, nous pouvons « paramétrer » notre dépendance, qui contient maintenant « bar », en tant qu’attribut `checker.fixed_content`.\n\n## Utiliser l'instance comme dépendance { #use-the-instance-as-a-dependency }\n\nEnsuite, nous pourrions utiliser ce `checker` dans un `Depends(checker)`, au lieu de `Depends(FixedContentQueryChecker)`, car la dépendance est l’instance, `checker`, et non la classe elle‑même.\n\nEt lors de la résolution de la dépendance, **FastAPI** appellera ce `checker` comme ceci :\n\n```Python\nchecker(q=\"somequery\")\n```\n\n... et passera ce que cela renvoie comme valeur de la dépendance à notre *fonction de chemin d'accès*, en tant que paramètre `fixed_content_included` :\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | Astuce\n\nTout cela peut sembler artificiel. Et il n’est peut‑être pas encore très clair en quoi c’est utile.\n\nCes exemples sont volontairement simples, mais ils montrent comment tout cela fonctionne.\n\nDans les chapitres sur la sécurité, il existe des fonctions utilitaires implémentées de la même manière.\n\nSi vous avez compris tout cela, vous savez déjà comment ces outils utilitaires pour la sécurité fonctionnent en interne.\n\n///\n\n## Dépendances avec `yield`, `HTTPException`, `except` et tâches d'arrière‑plan { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | Alertes\n\nVous n’avez très probablement pas besoin de ces détails techniques.\n\nCes détails sont utiles principalement si vous aviez une application FastAPI antérieure à la version 0.121.0 et que vous rencontrez des problèmes avec des dépendances utilisant `yield`.\n\n///\n\nLes dépendances avec `yield` ont évolué au fil du temps pour couvrir différents cas d’utilisation et corriger certains problèmes ; voici un résumé de ce qui a changé.\n\n### Dépendances avec `yield` et `scope` { #dependencies-with-yield-and-scope }\n\nDans la version 0.121.0, **FastAPI** a ajouté la prise en charge de `Depends(scope=\"function\")` pour les dépendances avec `yield`.\n\nAvec `Depends(scope=\"function\")`, le code d’arrêt après `yield` s’exécute immédiatement après la fin de la *fonction de chemin d'accès*, avant que la réponse ne soit renvoyée au client.\n\nEt lorsque vous utilisez `Depends(scope=\"request\")` (valeur par défaut), le code d’arrêt après `yield` s’exécute après l’envoi de la réponse.\n\nVous pouvez en lire davantage dans les documents pour [Dépendances avec `yield` - Sortie anticipée et `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope).\n\n### Dépendances avec `yield` et `StreamingResponse`, Détails techniques { #dependencies-with-yield-and-streamingresponse-technical-details }\n\nAvant FastAPI 0.118.0, si vous utilisiez une dépendance avec `yield`, elle exécutait le code d’arrêt après que la *fonction de chemin d'accès* a retourné, mais juste avant d’envoyer la réponse.\n\nL’objectif était d’éviter de conserver des ressources plus longtemps que nécessaire pendant que la réponse transitait sur le réseau.\n\nCe changement impliquait aussi que si vous retourniez une `StreamingResponse`, le code d’arrêt de la dépendance avec `yield` aurait déjà été exécuté.\n\nPar exemple, si vous aviez une session de base de données dans une dépendance avec `yield`, la `StreamingResponse` ne pourrait pas utiliser cette session pendant le streaming des données, car la session aurait déjà été fermée dans le code d’arrêt après `yield`.\n\nCe comportement a été annulé en 0.118.0, afin que le code d’arrêt après `yield` s’exécute après l’envoi de la réponse.\n\n/// info\n\nComme vous le verrez ci‑dessous, c’est très similaire au comportement avant la version 0.106.0, mais avec plusieurs améliorations et corrections de bogues pour des cas limites.\n\n///\n\n#### Cas d’utilisation avec sortie anticipée du code { #use-cases-with-early-exit-code }\n\nIl existe certains cas d’utilisation avec des conditions spécifiques qui pourraient bénéficier de l’ancien comportement, où le code d’arrêt des dépendances avec `yield` s’exécute avant l’envoi de la réponse.\n\nPar exemple, imaginez que vous ayez du code qui utilise une session de base de données dans une dépendance avec `yield` uniquement pour vérifier un utilisateur, mais que la session de base de données ne soit plus jamais utilisée dans la *fonction de chemin d'accès*, seulement dans la dépendance, et que la réponse mette longtemps à être envoyée, comme une `StreamingResponse` qui envoie les données lentement mais qui, pour une raison quelconque, n’utilise pas la base de données.\n\nDans ce cas, la session de base de données serait conservée jusqu’à la fin de l’envoi de la réponse, mais si vous ne l’utilisez pas, il ne serait pas nécessaire de la conserver.\n\nVoici à quoi cela pourrait ressembler :\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\nLe code d’arrêt, la fermeture automatique de la `Session` dans :\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n... serait exécuté après que la réponse a fini d’envoyer les données lentes :\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nMais comme `generate_stream()` n’utilise pas la session de base de données, il n’est pas vraiment nécessaire de garder la session ouverte pendant l’envoi de la réponse.\n\nSi vous avez ce cas d’utilisation spécifique avec SQLModel (ou SQLAlchemy), vous pouvez fermer explicitement la session dès que vous n’en avez plus besoin :\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\nDe cette manière, la session libérera la connexion à la base de données, afin que d’autres requêtes puissent l’utiliser.\n\nSi vous avez un autre cas d’utilisation qui nécessite une sortie anticipée depuis une dépendance avec `yield`, veuillez créer une [Question de discussion GitHub](https://github.com/fastapi/fastapi/discussions/new?category=questions) avec votre cas spécifique et pourquoi vous bénéficieriez d’une fermeture anticipée pour les dépendances avec `yield`.\n\nS’il existe des cas d’utilisation convaincants pour une fermeture anticipée dans les dépendances avec `yield`, j’envisagerai d’ajouter une nouvelle façon d’y opter.\n\n### Dépendances avec `yield` et `except`, Détails techniques { #dependencies-with-yield-and-except-technical-details }\n\nAvant FastAPI 0.110.0, si vous utilisiez une dépendance avec `yield`, puis capturiez une exception avec `except` dans cette dépendance, et que vous ne relanciez pas l’exception, l’exception était automatiquement levée/transmise à tout gestionnaire d’exceptions ou au gestionnaire d’erreur interne du serveur.\n\nCela a été modifié dans la version 0.110.0 pour corriger une consommation de mémoire non gérée due aux exceptions transmises sans gestionnaire (erreurs internes du serveur), et pour rendre le comportement cohérent avec celui du code Python classique.\n\n### Tâches d'arrière‑plan et dépendances avec `yield`, Détails techniques { #background-tasks-and-dependencies-with-yield-technical-details }\n\nAvant FastAPI 0.106.0, lever des exceptions après `yield` n’était pas possible, le code d’arrêt dans les dépendances avec `yield` s’exécutait après l’envoi de la réponse, donc les [Gestionnaires d'exceptions](../tutorial/handling-errors.md#install-custom-exception-handlers) avaient déjà été exécutés.\n\nCela avait été conçu ainsi principalement pour permettre d’utiliser les mêmes objets « générés par yield » par les dépendances à l’intérieur de tâches d’arrière‑plan, car le code d’arrêt s’exécutait après la fin des tâches d’arrière‑plan.\n\nCela a été modifié dans FastAPI 0.106.0 afin de ne pas conserver des ressources pendant l’attente de la transmission de la réponse sur le réseau.\n\n/// tip | Astuce\n\nDe plus, une tâche d’arrière‑plan est normalement un ensemble de logique indépendant qui devrait être géré séparément, avec ses propres ressources (par ex. sa propre connexion à la base de données).\n\nAinsi, vous aurez probablement un code plus propre.\n\n///\n\nSi vous comptiez sur ce comportement, vous devez désormais créer les ressources pour les tâches d’arrière‑plan à l’intérieur de la tâche elle‑même, et n’utiliser en interne que des données qui ne dépendent pas des ressources des dépendances avec `yield`.\n\nPar exemple, au lieu d’utiliser la même session de base de données, vous créeriez une nouvelle session de base de données à l’intérieur de la tâche d’arrière‑plan, et vous obtiendriez les objets depuis la base de données en utilisant cette nouvelle session. Puis, au lieu de passer l’objet obtenu depuis la base de données en paramètre à la fonction de tâche d’arrière‑plan, vous passeriez l’identifiant (ID) de cet objet et vous obtiendriez à nouveau l’objet à l’intérieur de la fonction de la tâche d’arrière‑plan.\n"
  },
  {
    "path": "docs/fr/docs/advanced/advanced-python-types.md",
    "content": "# Types Python avancés { #advanced-python-types }\n\nVoici quelques idées supplémentaires qui peuvent être utiles lorsque vous travaillez avec les types Python.\n\n## Utiliser `Union` ou `Optional` { #using-union-or-optional }\n\nSi votre code ne peut pas utiliser `|` pour une raison quelconque, par exemple si ce n'est pas dans une annotation de type mais dans quelque chose comme `response_model=`, au lieu d'utiliser la barre verticale (`|`) vous pouvez utiliser `Union` de `typing`.\n\nPar exemple, vous pourriez déclarer que quelque chose peut être un `str` ou `None` :\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\n`typing` propose également un raccourci pour déclarer que quelque chose peut être `None`, avec `Optional`.\n\nVoici un conseil issu de mon point de vue très subjectif :\n\n- 🚨 Évitez d'utiliser `Optional[SomeType]`\n- À la place ✨ **utilisez `Union[SomeType, None]`** ✨.\n\nLes deux sont équivalents et, en interne, identiques, mais je recommande `Union` plutôt que `Optional` parce que le mot « optional » semble impliquer que la valeur est facultative, alors qu'il signifie en réalité « elle peut être `None` », même si elle n'est pas facultative et reste requise.\n\nJe pense que `Union[SomeType, None]` est plus explicite quant à sa signification.\n\nIl ne s'agit que des mots et des noms. Mais ces mots peuvent influencer la manière dont vous et vos coéquipiers pensez au code.\n\nÀ titre d'exemple, prenons cette fonction :\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\nLe paramètre `name` est défini comme `Optional[str]`, mais il n'est pas facultatif, vous ne pouvez pas appeler la fonction sans le paramètre :\n\n```Python\nsay_hi()  # Oh non, cela lève une erreur ! 😱\n```\n\nLe paramètre `name` est toujours requis (pas facultatif) car il n'a pas de valeur par défaut. En revanche, `name` accepte `None` comme valeur :\n\n```Python\nsay_hi(name=None)  # Ceci fonctionne, None est valide 🎉\n```\n\nLa bonne nouvelle, c'est que, dans la plupart des cas, vous pourrez simplement utiliser `|` pour définir des unions de types :\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\nAinsi, normalement, vous n'avez pas à vous préoccuper de noms comme `Optional` et `Union`. 😎\n"
  },
  {
    "path": "docs/fr/docs/advanced/async-tests.md",
    "content": "# Tests asynchrones { #async-tests }\n\nVous avez déjà vu comment tester vos applications **FastAPI** en utilisant le `TestClient` fourni. Jusqu'à présent, vous n'avez vu que comment écrire des tests synchrones, sans utiliser de fonctions `async`.\n\nPouvoir utiliser des fonctions asynchrones dans vos tests peut être utile, par exemple lorsque vous interrogez votre base de données de manière asynchrone. Imaginez que vous vouliez tester l'envoi de requêtes à votre application FastAPI puis vérifier que votre backend a bien écrit les bonnes données dans la base, tout en utilisant une bibliothèque de base de données asynchrone.\n\nVoyons comment procéder.\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\nSi nous voulons appeler des fonctions asynchrones dans nos tests, nos fonctions de test doivent être asynchrones. AnyIO fournit un plug-in pratique qui nous permet d'indiquer que certaines fonctions de test doivent être appelées de manière asynchrone.\n\n## HTTPX { #httpx }\n\nMême si votre application **FastAPI** utilise des fonctions `def` normales au lieu de `async def`, c'est toujours une application `async` en interne.\n\nLe `TestClient` fait un peu de magie pour appeler l'application FastAPI asynchrone depuis vos fonctions de test `def` normales, en utilisant pytest standard. Mais cette magie ne fonctionne plus lorsque nous l'utilisons dans des fonctions asynchrones. En exécutant nos tests de manière asynchrone, nous ne pouvons plus utiliser le `TestClient` dans nos fonctions de test.\n\nLe `TestClient` est basé sur [HTTPX](https://www.python-httpx.org) et, heureusement, nous pouvons l'utiliser directement pour tester l'API.\n\n## Exemple { #example }\n\nPour un exemple simple, considérons une structure de fichiers similaire à celle décrite dans [Applications plus grandes](../tutorial/bigger-applications.md) et [Tests](../tutorial/testing.md) :\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nLe fichier `main.py` contiendrait :\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\nLe fichier `test_main.py` contiendrait les tests pour `main.py`, il pourrait maintenant ressembler à ceci :\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## Exécuter { #run-it }\n\nVous pouvez lancer vos tests comme d'habitude via :\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## En détail { #in-detail }\n\nLe marqueur `@pytest.mark.anyio` indique à pytest que cette fonction de test doit être appelée de manière asynchrone :\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip | Astuce\n\nNotez que la fonction de test est maintenant `async def` au lieu de simplement `def` comme auparavant avec le `TestClient`.\n\n///\n\nNous pouvons ensuite créer un `AsyncClient` avec l'application et lui envoyer des requêtes asynchrones en utilisant `await`.\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\nC'est l'équivalent de :\n\n```Python\nresponse = client.get('/')\n```\n\n... que nous utilisions pour faire nos requêtes avec le `TestClient`.\n\n/// tip | Astuce\n\nNotez que nous utilisons async/await avec le nouveau `AsyncClient` — la requête est asynchrone.\n\n///\n\n/// warning | Alertes\n\nSi votre application s'appuie sur des événements de cycle de vie, l'`AsyncClient` ne déclenchera pas ces événements. Pour vous assurer qu'ils sont déclenchés, utilisez `LifespanManager` depuis [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage).\n\n///\n\n## Autres appels de fonctions asynchrones { #other-asynchronous-function-calls }\n\nComme la fonction de test est désormais asynchrone, vous pouvez également appeler (et `await`) d'autres fonctions `async` en plus d'envoyer des requêtes à votre application FastAPI dans vos tests, exactement comme vous le feriez ailleurs dans votre code.\n\n/// tip | Astuce\n\nSi vous rencontrez une erreur `RuntimeError: Task attached to a different loop` lors de l'intégration d'appels de fonctions asynchrones dans vos tests (par exemple en utilisant [MotorClient de MongoDB](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop)), n'oubliez pas d'instancier les objets qui ont besoin d'une boucle d'événements uniquement dans des fonctions async, par exemple dans un callback `@app.on_event(\"startup\")`.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/advanced/behind-a-proxy.md",
    "content": "# Être derrière un proxy { #behind-a-proxy }\n\nDans de nombreuses situations, vous utiliserez un **proxy** comme Traefik ou Nginx devant votre application FastAPI.\n\nCes proxies peuvent gérer les certificats HTTPS et d'autres aspects.\n\n## En-têtes transférés par le proxy { #proxy-forwarded-headers }\n\nUn **proxy** placé devant votre application définit normalement certains en-têtes à la volée avant d'envoyer les requêtes à votre **serveur**, afin d'indiquer au serveur que la requête a été **transférée** par le proxy, en lui donnant l'URL d'origine (publique), y compris le domaine, le fait qu'elle utilise HTTPS, etc.\n\nLe programme **serveur** (par exemple **Uvicorn** via **FastAPI CLI**) est capable d'interpréter ces en‑têtes, puis de transmettre ces informations à votre application.\n\nMais, par sécurité, comme le serveur ne sait pas qu'il se trouve derrière un proxy de confiance, il n'interprétera pas ces en‑têtes.\n\n/// note | Détails techniques\n\nLes en-têtes du proxy sont :\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### Activer les en-têtes transférés par le proxy { #enable-proxy-forwarded-headers }\n\nVous pouvez démarrer FastAPI CLI avec l'option de CLI `--forwarded-allow-ips` et fournir les adresses IP à considérer comme fiables pour lire ces en‑têtes transférés.\n\nSi vous la définissez à `--forwarded-allow-ips=\"*\"`, elle fera confiance à toutes les IP entrantes.\n\nSi votre **serveur** est derrière un **proxy** de confiance et que seul le proxy lui parle, cela fera accepter l'IP de ce **proxy**, quelle qu'elle soit.\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Redirections avec HTTPS { #redirects-with-https }\n\nPar exemple, disons que vous définissez un *chemin d'accès* `/items/` :\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\nSi le client essaie d'aller à `/items`, par défaut, il sera redirigé vers `/items/`.\n\nMais avant de définir l'option de CLI `--forwarded-allow-ips`, il pourrait rediriger vers `http://localhost:8000/items/`.\n\nMais peut‑être que votre application est hébergée à `https://mysuperapp.com`, et la redirection devrait être vers `https://mysuperapp.com/items/`.\n\nEn définissant `--proxy-headers`, FastAPI pourra désormais rediriger vers l'emplacement correct. 😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip | Astuce\n\nSi vous voulez en savoir plus sur HTTPS, consultez le guide [À propos de HTTPS](../deployment/https.md).\n\n///\n\n### Comment fonctionnent les en‑têtes transférés par le proxy { #how-proxy-forwarded-headers-work }\n\nVoici une représentation visuelle de la façon dont le **proxy** ajoute des en‑têtes transférés entre le client et le **serveur d'application** :\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Proxy as Proxy/Load Balancer\n    participant Server as FastAPI Server\n\n    Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: Proxy adds forwarded headers\n\n    Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)\n\n    Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs\n\n    Proxy->>Client: HTTPS Response\n```\n\nLe **proxy** intercepte la requête client d'origine et ajoute les en-têtes spéciaux *forwarded* (`X-Forwarded-*`) avant de transmettre la requête au **serveur d'application**.\n\nCes en‑têtes conservent des informations sur la requête d'origine qui seraient autrement perdues :\n\n* **X-Forwarded-For** : l'adresse IP du client d'origine\n* **X-Forwarded-Proto** : le protocole d'origine (`https`)\n* **X-Forwarded-Host** : l'hôte d'origine (`mysuperapp.com`)\n\nLorsque **FastAPI CLI** est configurée avec `--forwarded-allow-ips`, elle fait confiance à ces en‑têtes et les utilise, par exemple pour générer les bonnes URL dans les redirections.\n\n## Proxy avec un préfixe de chemin supprimé { #proxy-with-a-stripped-path-prefix }\n\nVous pouvez avoir un proxy qui ajoute un préfixe de chemin à votre application.\n\nDans ces cas, vous pouvez utiliser `root_path` pour configurer votre application.\n\nLe `root_path` est un mécanisme fourni par la spécification ASGI (sur laquelle FastAPI est construit, via Starlette).\n\nLe `root_path` est utilisé pour gérer ces cas spécifiques.\n\nEt il est également utilisé en interne lors du montage de sous‑applications.\n\nAvoir un proxy avec un préfixe de chemin supprimé, dans ce cas, signifie que vous pourriez déclarer un chemin à `/app` dans votre code, mais ensuite, vous ajoutez une couche au‑dessus (le proxy) qui place votre application **FastAPI** sous un chemin comme `/api/v1`.\n\nDans ce cas, le chemin original `/app` serait en réalité servi à `/api/v1/app`.\n\nMême si tout votre code est écrit en supposant qu'il n'y a que `/app`.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\nEt le proxy **« stripping »** le **préfixe de chemin** à la volée avant de transmettre la requête au serveur de l'application (probablement Uvicorn via FastAPI CLI), en gardant votre application convaincue qu'elle est servie à `/app`, afin que vous n'ayez pas à mettre à jour tout votre code pour inclure le préfixe `/api/v1`.\n\nJusqu'ici, tout fonctionnerait normalement.\n\nMais ensuite, lorsque vous ouvrez l'interface de documentation intégrée (le frontend), elle s'attendra à obtenir le schéma OpenAPI à `/openapi.json`, au lieu de `/api/v1/openapi.json`.\n\nAinsi, le frontend (qui s'exécute dans le navigateur) essaiera d'atteindre `/openapi.json` et ne pourra pas obtenir le schéma OpenAPI.\n\nParce que nous avons un proxy avec un préfixe de chemin `/api/v1` pour notre application, le frontend doit récupérer le schéma OpenAPI à `/api/v1/openapi.json`.\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy on http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server on http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip | Astuce\n\nL'IP `0.0.0.0` est couramment utilisée pour signifier que le programme écoute sur toutes les IP disponibles de cette machine/serveur.\n\n///\n\nL'interface de documents doit également indiquer dans le schéma OpenAPI que ce `server` d'API se trouve à `/api/v1` (derrière le proxy). Par exemple :\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // Plus d'éléments ici\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // Plus d'éléments ici\n    }\n}\n```\n\nDans cet exemple, le « Proxy » pourrait être quelque chose comme **Traefik**. Et le serveur serait quelque chose comme FastAPI CLI avec **Uvicorn**, exécutant votre application FastAPI.\n\n### Fournir le `root_path` { #providing-the-root-path }\n\nPour y parvenir, vous pouvez utiliser l'option de ligne de commande `--root-path` comme suit :\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nSi vous utilisez Hypercorn, il dispose également de l'option `--root-path`.\n\n/// note | Détails techniques\n\nLa spécification ASGI définit un `root_path` pour ce cas d'usage.\n\nEt l'option de ligne de commande `--root-path` fournit ce `root_path`.\n\n///\n\n### Vérifier le `root_path` actuel { #checking-the-current-root-path }\n\nVous pouvez obtenir le `root_path` actuel utilisé par votre application pour chaque requête, il fait partie du dictionnaire `scope` (qui fait partie de la spécification ASGI).\n\nIci, nous l'incluons dans le message uniquement à des fins de démonstration.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\nEnsuite, si vous démarrez Uvicorn avec :\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nLa réponse sera semblable à :\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### Définir le `root_path` dans l'application FastAPI { #setting-the-root-path-in-the-fastapi-app }\n\nAutrement, si vous n'avez pas la possibilité de fournir une option de ligne de commande comme `--root-path` ou équivalent, vous pouvez définir le paramètre `root_path` lors de la création de votre application FastAPI :\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\nPasser le `root_path` à `FastAPI` équivaut à passer l'option de ligne de commande `--root-path` à Uvicorn ou Hypercorn.\n\n### À propos de `root_path` { #about-root-path }\n\nGardez à l'esprit que le serveur (Uvicorn) n'utilisera ce `root_path` que pour le transmettre à l'application.\n\nMais si vous allez avec votre navigateur sur [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), vous verrez la réponse normale :\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nDonc, il ne s'attendra pas à être accessible à `http://127.0.0.1:8000/api/v1/app`.\n\nUvicorn s'attendra à ce que le proxy accède à Uvicorn sur `http://127.0.0.1:8000/app`, et ce sera ensuite la responsabilité du proxy d'ajouter le préfixe supplémentaire `/api/v1` au‑dessus.\n\n## À propos des proxies avec un préfixe de chemin supprimé { #about-proxies-with-a-stripped-path-prefix }\n\nGardez à l'esprit qu'un proxy avec préfixe de chemin supprimé n'est qu'une des façons de le configurer.\n\nDans de nombreux cas, la valeur par défaut sera probablement que le proxy n'a pas de préfixe de chemin supprimé.\n\nDans un cas comme celui‑ci (sans préfixe de chemin supprimé), le proxy écoutera sur quelque chose comme `https://myawesomeapp.com`, puis si le navigateur va sur `https://myawesomeapp.com/api/v1/app` et que votre serveur (par ex. Uvicorn) écoute sur `http://127.0.0.1:8000`, le proxy (sans préfixe de chemin supprimé) accédera à Uvicorn au même chemin : `http://127.0.0.1:8000/api/v1/app`.\n\n## Tester localement avec Traefik { #testing-locally-with-traefik }\n\nVous pouvez facilement faire l'expérience en local avec un préfixe de chemin supprimé en utilisant [Traefik](https://docs.traefik.io/).\n\n[Téléchargez Traefik](https://github.com/containous/traefik/releases) ; c'est un binaire unique, vous pouvez extraire le fichier compressé et l'exécuter directement depuis le terminal.\n\nCréez ensuite un fichier `traefik.toml` avec :\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\nCela indique à Traefik d'écouter sur le port 9999 et d'utiliser un autre fichier `routes.toml`.\n\n/// tip | Astuce\n\nNous utilisons le port 9999 au lieu du port HTTP standard 80 afin que vous n'ayez pas à l'exécuter avec des privilèges administrateur (`sudo`).\n\n///\n\nCréez maintenant cet autre fichier `routes.toml` :\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\nCe fichier configure Traefik pour utiliser le préfixe de chemin `/api/v1`.\n\nPuis Traefik redirigera ses requêtes vers votre Uvicorn tournant sur `http://127.0.0.1:8000`.\n\nDémarrez maintenant Traefik :\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\nEt démarrez maintenant votre application, en utilisant l'option `--root-path` :\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Vérifier les réponses { #check-the-responses }\n\nMaintenant, si vous allez à l'URL avec le port pour Uvicorn : [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), vous verrez la réponse normale :\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip | Astuce\n\nRemarquez que même si vous y accédez via `http://127.0.0.1:8000/app`, il affiche le `root_path` de `/api/v1`, repris depuis l'option `--root-path`.\n\n///\n\nEt maintenant ouvrez l'URL avec le port pour Traefik, en incluant le préfixe de chemin : [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app).\n\nNous obtenons la même réponse :\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nmais cette fois à l'URL avec le préfixe fourni par le proxy : `/api/v1`.\n\nBien sûr, l'idée ici est que tout le monde accède à l'application via le proxy ; la version avec le préfixe de chemin `/api/v1` est donc la « correcte ».\n\nEt la version sans préfixe de chemin (`http://127.0.0.1:8000/app`), fournie directement par Uvicorn, serait exclusivement destinée au _proxy_ (Traefik) pour y accéder.\n\nCela montre comment le Proxy (Traefik) utilise le préfixe de chemin et comment le serveur (Uvicorn) utilise le `root_path` fourni par l'option `--root-path`.\n\n### Vérifier l'interface de documentation { #check-the-docs-ui }\n\nMais voici la partie intéressante. ✨\n\nLa manière « officielle » d'accéder à l'application serait via le proxy avec le préfixe de chemin que nous avons défini. Donc, comme on s'y attend, si vous essayez l'interface de documentation servie directement par Uvicorn, sans le préfixe de chemin dans l'URL, cela ne fonctionne pas, car elle s'attend à être accédée via le proxy.\n\nVous pouvez le vérifier sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) :\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\nMais si nous accédons à l'interface de documents à l'URL « officielle » en utilisant le proxy avec le port `9999`, à `/api/v1/docs`, cela fonctionne correctement ! 🎉\n\nVous pouvez le vérifier sur [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) :\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\nExactement comme nous le voulions. ✔️\n\nC'est parce que FastAPI utilise ce `root_path` pour créer le `server` par défaut dans OpenAPI avec l'URL fournie par `root_path`.\n\n## Serveurs supplémentaires { #additional-servers }\n\n/// warning | Alertes\n\nCeci est un cas d'utilisation plus avancé. N'hésitez pas à l'ignorer.\n\n///\n\nPar défaut, **FastAPI** créera un `server` dans le schéma OpenAPI avec l'URL correspondant au `root_path`.\n\nMais vous pouvez aussi fournir d'autres `servers` alternatifs, par exemple si vous voulez que la même interface de documents interagisse avec un environnement de staging et un environnement de production.\n\nSi vous passez une liste personnalisée de `servers` et qu'il y a un `root_path` (parce que votre API vit derrière un proxy), **FastAPI** insérera un « server » avec ce `root_path` au début de la liste.\n\nPar exemple :\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\nGénérera un schéma OpenAPI comme :\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // Plus d'éléments ici\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // Plus d'éléments ici\n    }\n}\n```\n\n/// tip | Astuce\n\nRemarquez le serveur généré automatiquement avec une valeur `url` de `/api/v1`, repris depuis le `root_path`.\n\n///\n\nDans l'interface de documents sur [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs), cela ressemblera à ceci :\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip | Astuce\n\nL'interface de documents interagit avec le serveur que vous sélectionnez.\n\n///\n\n/// note | Détails techniques\n\nLa propriété `servers` dans la spécification OpenAPI est facultative.\n\nSi vous ne spécifiez pas le paramètre `servers` et que `root_path` est égal à `/`, la propriété `servers` dans le schéma OpenAPI généré sera entièrement omise par défaut, ce qui équivaut à un seul serveur avec une valeur `url` de `/`.\n\n///\n\n### Désactiver le serveur automatique issu de `root_path` { #disable-automatic-server-from-root-path }\n\nSi vous ne voulez pas que **FastAPI** inclue un serveur automatique utilisant le `root_path`, vous pouvez utiliser le paramètre `root_path_in_servers=False` :\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\net il ne l'inclura alors pas dans le schéma OpenAPI.\n\n## Monter une sous-application { #mounting-a-sub-application }\n\nSi vous avez besoin de monter une sous‑application (comme décrit dans [Sous‑applications - montages](sub-applications.md)) tout en utilisant un proxy avec `root_path`, vous pouvez le faire normalement, comme vous vous y attendez.\n\nFastAPI utilisera intelligemment le `root_path` en interne, donc cela fonctionnera simplement. ✨\n"
  },
  {
    "path": "docs/fr/docs/advanced/custom-response.md",
    "content": "# Réponse personnalisée - HTML, flux, fichier, autres { #custom-response-html-stream-file-others }\n\nPar défaut, **FastAPI** renvoie des réponses JSON.\n\nVous pouvez le remplacer en renvoyant une `Response` directement comme vu dans [Renvoyer une Response directement](response-directly.md).\n\nMais si vous renvoyez directement une `Response` (ou n'importe quelle sous-classe, comme `JSONResponse`), les données ne seront pas automatiquement converties (même si vous déclarez un `response_model`), et la documentation ne sera pas générée automatiquement (par exemple, l'inclusion du « media type », dans l'en-tête HTTP `Content-Type` comme partie de l'OpenAPI généré).\n\nVous pouvez aussi déclarer la `Response` que vous voulez utiliser (par ex. toute sous-classe de `Response`), dans le décorateur de *chemin d'accès* en utilisant le paramètre `response_class`.\n\nLe contenu que vous renvoyez depuis votre *fonction de chemin d'accès* sera placé à l'intérieur de cette `Response`.\n\n/// note | Remarque\n\nSi vous utilisez une classe de réponse sans media type, FastAPI s'attendra à ce que votre réponse n'ait pas de contenu ; il ne documentera donc pas le format de la réponse dans la documentation OpenAPI générée.\n\n///\n\n## Réponses JSON { #json-responses }\n\nPar défaut, FastAPI renvoie des réponses JSON.\n\nSi vous déclarez un [Modèle de réponse](../tutorial/response-model.md), FastAPI l'utilisera pour sérialiser les données en JSON, en utilisant Pydantic.\n\nSi vous ne déclarez pas de modèle de réponse, FastAPI utilisera le `jsonable_encoder` expliqué dans [Encodeur compatible JSON](../tutorial/encoder.md) et le placera dans une `JSONResponse`.\n\nSi vous déclarez une `response_class` avec un media type JSON (`application/json`), comme c'est le cas avec `JSONResponse`, les données que vous renvoyez seront automatiquement converties (et filtrées) avec tout `response_model` Pydantic que vous avez déclaré dans le décorateur de *chemin d'accès*. Mais les données ne seront pas sérialisées en octets JSON avec Pydantic, elles seront converties avec le `jsonable_encoder` puis passées à la classe `JSONResponse`, qui les sérialisera en octets en utilisant la bibliothèque JSON standard de Python.\n\n### Performance JSON { #json-performance }\n\nEn bref, si vous voulez la performance maximale, utilisez un [Modèle de réponse](../tutorial/response-model.md) et ne déclarez pas de `response_class` dans le décorateur de *chemin d'accès*.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## Réponse HTML { #html-response }\n\nPour renvoyer une réponse avec du HTML directement depuis **FastAPI**, utilisez `HTMLResponse`.\n\n- Importez `HTMLResponse`.\n- Passez `HTMLResponse` comme paramètre `response_class` de votre *décorateur de chemin d'accès*.\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info\n\nLe paramètre `response_class` sera aussi utilisé pour définir le « media type » de la réponse.\n\nDans ce cas, l'en-tête HTTP `Content-Type` sera défini à `text/html`.\n\nEt il sera documenté comme tel dans OpenAPI.\n\n///\n\n### Renvoyer une `Response` { #return-a-response }\n\nComme vu dans [Renvoyer une Response directement](response-directly.md), vous pouvez aussi remplacer la réponse directement dans votre *chemin d'accès*, en la renvoyant.\n\nLe même exemple ci-dessus, renvoyant une `HTMLResponse`, pourrait ressembler à :\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning | Alertes\n\nUne `Response` renvoyée directement par votre *fonction de chemin d'accès* ne sera pas documentée dans OpenAPI (par exemple, le `Content-Type` ne sera pas documenté) et ne sera pas visible dans les documents interactifs automatiques.\n\n///\n\n/// info\n\nBien sûr, l'en-tête `Content-Type` réel, le code d'état, etc., proviendront de l'objet `Response` que vous avez renvoyé.\n\n///\n\n### Documenter dans OpenAPI et remplacer `Response` { #document-in-openapi-and-override-response }\n\nSi vous voulez remplacer la réponse depuis l'intérieur de la fonction mais en même temps documenter le « media type » dans OpenAPI, vous pouvez utiliser le paramètre `response_class` ET renvoyer un objet `Response`.\n\n`response_class` sera alors utilisé uniquement pour documenter l’*opération de chemin d'accès* OpenAPI, mais votre `Response` sera utilisée telle quelle.\n\n#### Renvoyer directement une `HTMLResponse` { #return-an-htmlresponse-directly }\n\nPar exemple, cela pourrait être quelque chose comme :\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\nDans cet exemple, la fonction `generate_html_response()` génère déjà et renvoie une `Response` au lieu de renvoyer le HTML dans une `str`.\n\nEn renvoyant le résultat de l'appel à `generate_html_response()`, vous renvoyez déjà une `Response` qui remplacera le comportement par défaut de **FastAPI**.\n\nMais comme vous avez aussi passé `HTMLResponse` dans `response_class`, **FastAPI** saura comment la documenter dans OpenAPI et les documents interactifs comme HTML avec `text/html` :\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## Réponses disponibles { #available-responses }\n\nVoici certaines des réponses disponibles.\n\nGardez à l'esprit que vous pouvez utiliser `Response` pour renvoyer autre chose, ou même créer une sous-classe personnalisée.\n\n/// note | Détails techniques\n\nVous pourriez aussi utiliser `from starlette.responses import HTMLResponse`.\n\n**FastAPI** fournit les mêmes `starlette.responses` sous `fastapi.responses` simplement pour votre confort de développement. Mais la plupart des réponses disponibles viennent directement de Starlette.\n\n///\n\n### `Response` { #response }\n\nLa classe principale `Response`, toutes les autres réponses en héritent.\n\nVous pouvez la renvoyer directement.\n\nElle accepte les paramètres suivants :\n\n- `content` - Une `str` ou des `bytes`.\n- `status_code` - Un code d'état HTTP de type `int`.\n- `headers` - Un `dict` de chaînes.\n- `media_type` - Une `str` donnant le media type. Par exemple « text/html ».\n\nFastAPI (en fait Starlette) inclura automatiquement un en-tête Content-Length. Il inclura aussi un en-tête Content-Type, basé sur `media_type` et en ajoutant un charset pour les types textuels.\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\nPrend du texte ou des octets et renvoie une réponse HTML, comme vous l'avez vu ci-dessus.\n\n### `PlainTextResponse` { #plaintextresponse }\n\nPrend du texte ou des octets et renvoie une réponse en texte brut.\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\nPrend des données et renvoie une réponse encodée en `application/json`.\n\nC'est la réponse par défaut utilisée dans **FastAPI**, comme vous l'avez lu ci-dessus.\n\n/// note | Détails techniques\n\nMais si vous déclarez un modèle de réponse ou un type de retour, il sera utilisé directement pour sérialiser les données en JSON, et une réponse avec le bon media type pour JSON sera renvoyée directement, sans utiliser la classe `JSONResponse`.\n\nC'est la manière idéale d'obtenir la meilleure performance.\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\nRenvoie une redirection HTTP. Utilise par défaut un code d'état 307 (Temporary Redirect).\n\nVous pouvez renvoyer directement une `RedirectResponse` :\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\nOu vous pouvez l'utiliser dans le paramètre `response_class` :\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\nSi vous faites cela, vous pouvez alors renvoyer directement l'URL depuis votre *fonction de chemin d'accès*.\n\nDans ce cas, le `status_code` utilisé sera celui par défaut pour `RedirectResponse`, c'est-à-dire `307`.\n\n---\n\nVous pouvez aussi utiliser le paramètre `status_code` combiné avec le paramètre `response_class` :\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\nPrend un générateur async ou un générateur/itérateur normal (une fonction avec `yield`) et diffuse le corps de la réponse.\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | Détails techniques\n\nUne tâche `async` ne peut être annulée que lorsqu'elle atteint un `await`. S'il n'y a pas de `await`, le générateur (fonction avec `yield`) ne peut pas être annulé correctement et peut continuer à s'exécuter même après la demande d'annulation.\n\nComme ce petit exemple n'a besoin d'aucune instruction `await`, nous ajoutons un `await anyio.sleep(0)` pour donner une chance à la boucle d'événements de gérer l'annulation.\n\nCela serait encore plus important avec des flux volumineux ou infinis.\n\n///\n\n/// tip | Astuce\n\nAu lieu de renvoyer une `StreamingResponse` directement, vous devriez probablement suivre le style de [Diffuser des données](./stream-data.md), c'est beaucoup plus pratique et gère l'annulation en arrière-plan pour vous.\n\nSi vous diffusez des JSON Lines, suivez le didacticiel [Diffuser des JSON Lines](../tutorial/stream-json-lines.md).\n\n///\n\n### `FileResponse` { #fileresponse }\n\nDiffuse de façon asynchrone un fichier comme réponse.\n\nPrend un ensemble de paramètres différent à l'instanciation par rapport aux autres types de réponse :\n\n- `path` - Le chemin du fichier à diffuser.\n- `headers` - D'éventuels en-têtes personnalisés à inclure, sous forme de dictionnaire.\n- `media_type` - Une chaîne donnant le media type. Si non défini, le nom du fichier ou le chemin sera utilisé pour en déduire un media type.\n- `filename` - Si défini, sera inclus dans l'en-tête `Content-Disposition` de la réponse.\n\nLes réponses de type fichier incluront les en-têtes appropriés `Content-Length`, `Last-Modified` et `ETag`.\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\nVous pouvez aussi utiliser le paramètre `response_class` :\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\nDans ce cas, vous pouvez renvoyer directement le chemin du fichier depuis votre *fonction de chemin d'accès*.\n\n## Classe de réponse personnalisée { #custom-response-class }\n\nVous pouvez créer votre propre classe de réponse personnalisée, héritant de `Response`, et l'utiliser.\n\nPar exemple, disons que vous voulez utiliser [`orjson`](https://github.com/ijl/orjson) avec certains réglages.\n\nDisons que vous voulez renvoyer du JSON indenté et formaté, donc vous voulez utiliser l'option orjson `orjson.OPT_INDENT_2`.\n\nVous pourriez créer une `CustomORJSONResponse`. L'essentiel est de créer une méthode `Response.render(content)` qui renvoie le contenu en `bytes` :\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\nMaintenant, au lieu de renvoyer :\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n... cette réponse renverra :\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\nBien sûr, vous trouverez probablement des moyens bien meilleurs de tirer parti de cela que de formater du JSON. 😉\n\n### `orjson` ou Modèle de réponse { #orjson-or-response-model }\n\nSi ce que vous recherchez est la performance, vous aurez probablement de meilleurs résultats en utilisant un [Modèle de réponse](../tutorial/response-model.md) qu'une réponse `orjson`.\n\nAvec un modèle de réponse, FastAPI utilisera Pydantic pour sérialiser les données en JSON, sans étapes intermédiaires, comme la conversion avec `jsonable_encoder`, qui se produirait dans tout autre cas.\n\nEt en interne, Pydantic utilise les mêmes mécanismes Rust sous-jacents que `orjson` pour sérialiser en JSON, vous obtiendrez donc déjà la meilleure performance avec un modèle de réponse.\n\n## Classe de réponse par défaut { #default-response-class }\n\nLors de la création d'une instance de classe **FastAPI** ou d'un `APIRouter`, vous pouvez spécifier quelle classe de réponse utiliser par défaut.\n\nLe paramètre qui le définit est `default_response_class`.\n\nDans l'exemple ci-dessous, **FastAPI** utilisera `HTMLResponse` par défaut, dans tous les *chemins d'accès*, au lieu de JSON.\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip | Astuce\n\nVous pouvez toujours remplacer `response_class` dans les *chemins d'accès* comme auparavant.\n\n///\n\n## Documentation supplémentaire { #additional-documentation }\n\nVous pouvez aussi déclarer le media type et de nombreux autres détails dans OpenAPI en utilisant `responses` : [Réponses supplémentaires dans OpenAPI](additional-responses.md).\n"
  },
  {
    "path": "docs/fr/docs/advanced/dataclasses.md",
    "content": "# Utiliser des dataclasses { #using-dataclasses }\n\nFastAPI est construit au‑dessus de **Pydantic**, et je vous ai montré comment utiliser des modèles Pydantic pour déclarer les requêtes et les réponses.\n\nMais FastAPI prend aussi en charge l'utilisation de [`dataclasses`](https://docs.python.org/3/library/dataclasses.html) de la même manière :\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\nCela fonctionne grâce à **Pydantic**, qui offre une [prise en charge interne des `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).\n\nAinsi, même avec le code ci‑dessus qui n'emploie pas explicitement Pydantic, FastAPI utilise Pydantic pour convertir ces dataclasses standard en la variante de dataclasses de Pydantic.\n\nEt bien sûr, cela prend en charge la même chose :\n\n* validation des données\n* sérialisation des données\n* documentation des données, etc.\n\nCela fonctionne de la même manière qu'avec les modèles Pydantic. Et, en réalité, c'est mis en œuvre de la même façon en interne, en utilisant Pydantic.\n\n/// info\n\nGardez à l'esprit que les dataclasses ne peuvent pas tout ce que peuvent faire les modèles Pydantic.\n\nVous pourriez donc avoir encore besoin d'utiliser des modèles Pydantic.\n\nMais si vous avez déjà un ensemble de dataclasses sous la main, c'est une astuce pratique pour les utiliser afin d'alimenter une API Web avec FastAPI. 🤓\n\n///\n\n## Utiliser des dataclasses dans `response_model` { #dataclasses-in-response-model }\n\nVous pouvez aussi utiliser `dataclasses` dans le paramètre `response_model` :\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\nLa dataclass sera automatiquement convertie en dataclass Pydantic.\n\nAinsi, son schéma apparaîtra dans l'interface utilisateur de la documentation de l'API :\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## Utiliser des dataclasses dans des structures de données imbriquées { #dataclasses-in-nested-data-structures }\n\nVous pouvez aussi combiner `dataclasses` avec d'autres annotations de type pour créer des structures de données imbriquées.\n\nDans certains cas, vous devrez peut‑être encore utiliser la version `dataclasses` de Pydantic. Par exemple, si vous rencontrez des erreurs avec la documentation d'API générée automatiquement.\n\nDans ce cas, vous pouvez simplement remplacer les `dataclasses` standard par `pydantic.dataclasses`, qui est un remplacement drop‑in :\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. Nous continuons à importer `field` depuis les `dataclasses` standard.\n\n2. `pydantic.dataclasses` est un remplacement drop‑in pour `dataclasses`.\n\n3. La dataclass `Author` inclut une liste de dataclasses `Item`.\n\n4. La dataclass `Author` est utilisée comme paramètre `response_model`.\n\n5. Vous pouvez utiliser d'autres annotations de type standard avec des dataclasses comme corps de la requête.\n\n    Dans ce cas, il s'agit d'une liste de dataclasses `Item`.\n\n6. Ici, nous renvoyons un dictionnaire qui contient `items`, qui est une liste de dataclasses.\n\n    FastAPI est toujours capable de <dfn title=\"convertir les données dans un format pouvant être transmis\">sérialiser</dfn> les données en JSON.\n\n7. Ici, `response_model` utilise une annotation de type correspondant à une liste de dataclasses `Author`.\n\n    Là encore, vous pouvez combiner `dataclasses` avec des annotations de type standard.\n\n8. Notez que cette *fonction de chemin d'accès* utilise un `def` classique au lieu de `async def`.\n\n    Comme toujours, avec FastAPI vous pouvez combiner `def` et `async def` selon vos besoins.\n\n    Si vous avez besoin d'un rappel sur quand utiliser l'un ou l'autre, consultez la section _« In a hurry? »_ dans la documentation à propos de [`async` et `await`](../async.md#in-a-hurry).\n\n9. Cette *fonction de chemin d'accès* ne renvoie pas des dataclasses (même si elle le pourrait), mais une liste de dictionnaires contenant des données internes.\n\n    FastAPI utilisera le paramètre `response_model` (qui inclut des dataclasses) pour convertir la réponse.\n\nVous pouvez combiner `dataclasses` avec d'autres annotations de type, selon de nombreuses combinaisons, pour former des structures de données complexes.\n\nReportez‑vous aux annotations dans le code ci‑dessus pour voir plus de détails spécifiques.\n\n## En savoir plus { #learn-more }\n\nVous pouvez aussi combiner `dataclasses` avec d'autres modèles Pydantic, en hériter, les inclure dans vos propres modèles, etc.\n\nPour en savoir plus, consultez la [documentation Pydantic sur les dataclasses](https://docs.pydantic.dev/latest/concepts/dataclasses/).\n\n## Version { #version }\n\nC'est disponible depuis FastAPI version `0.67.0`. 🔖\n"
  },
  {
    "path": "docs/fr/docs/advanced/events.md",
    "content": "# Événements de cycle de vie { #lifespan-events }\n\nVous pouvez définir une logique (du code) qui doit être exécutée avant que l'application ne **démarre**. Cela signifie que ce code sera exécuté **une seule fois**, **avant** que l'application ne **commence à recevoir des requêtes**.\n\nDe la même manière, vous pouvez définir une logique (du code) qui doit être exécutée lorsque l'application **s'arrête**. Dans ce cas, ce code sera exécuté **une seule fois**, **après** avoir traité potentiellement **de nombreuses requêtes**.\n\nComme ce code est exécuté avant que l'application ne **commence** à recevoir des requêtes, et juste après qu'elle **termine** de les traiter, il couvre tout le **cycle de vie** de l'application (le mot « lifespan » va être important dans un instant 😉).\n\nCela peut être très utile pour configurer des **ressources** dont vous avez besoin pour l'ensemble de l'application, qui sont **partagées** entre les requêtes, et/ou que vous devez **nettoyer** ensuite. Par exemple, un pool de connexions à une base de données, ou le chargement d'un modèle d'apprentissage automatique partagé.\n\n## Cas d'utilisation { #use-case }\n\nCommençons par un exemple de **cas d'utilisation**, puis voyons comment le résoudre avec ceci.\n\nImaginons que vous ayez des **modèles d'apprentissage automatique** que vous souhaitez utiliser pour traiter des requêtes. 🤖\n\nLes mêmes modèles sont partagés entre les requêtes, ce n'est donc pas un modèle par requête, ni un par utilisateur, ou quelque chose de similaire.\n\nImaginons que le chargement du modèle puisse **prendre pas mal de temps**, car il doit lire beaucoup de **données depuis le disque**. Vous ne voulez donc pas le faire pour chaque requête.\n\nVous pourriez le charger au niveau supérieur du module/fichier, mais cela signifierait aussi qu'il **chargerait le modèle** même si vous exécutez simplement un test automatisé simple ; ce test serait alors **lent** car il devrait attendre le chargement du modèle avant de pouvoir exécuter une partie indépendante du code.\n\nC'est ce que nous allons résoudre : chargeons le modèle avant que les requêtes ne soient traitées, mais seulement juste avant que l'application ne commence à recevoir des requêtes, pas pendant le chargement du code.\n\n## Cycle de vie { #lifespan }\n\nVous pouvez définir cette logique de *démarrage* et d'*arrêt* en utilisant le paramètre `lifespan` de l'application `FastAPI`, et un « gestionnaire de contexte » (je vais vous montrer ce que c'est dans un instant).\n\nCommençons par un exemple, puis voyons-le en détail.\n\nNous créons une fonction async `lifespan()` avec `yield` comme ceci :\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\nIci, nous simulons l'opération de *démarrage* coûteuse de chargement du modèle en plaçant la fonction (factice) du modèle dans le dictionnaire avec les modèles d'apprentissage automatique avant le `yield`. Ce code sera exécuté **avant** que l'application ne **commence à recevoir des requêtes**, pendant le *démarrage*.\n\nPuis, juste après le `yield`, nous déchargeons le modèle. Ce code sera exécuté **après** que l'application **a fini de traiter les requêtes**, juste avant l'*arrêt*. Cela pourrait, par exemple, libérer des ressources comme la mémoire ou un GPU.\n\n/// tip | Astuce\n\nLe `shutdown` se produit lorsque vous **arrêtez** l'application.\n\nPeut-être devez-vous démarrer une nouvelle version, ou vous en avez simplement assez de l'exécuter. 🤷\n\n///\n\n### Fonction de cycle de vie { #lifespan-function }\n\nLa première chose à remarquer est que nous définissons une fonction async avec `yield`. C'est très similaire aux Dépendances avec `yield`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\nLa première partie de la fonction, avant le `yield`, sera exécutée **avant** le démarrage de l'application.\n\nEt la partie après le `yield` sera exécutée **après** que l'application a terminé.\n\n### Gestionnaire de contexte asynchrone { #async-context-manager }\n\nSi vous regardez, la fonction est décorée avec `@asynccontextmanager`.\n\nCela convertit la fonction en quelque chose appelé un « **gestionnaire de contexte asynchrone** ».\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\nUn **gestionnaire de contexte** en Python est quelque chose que vous pouvez utiliser dans une instruction `with`. Par exemple, `open()` peut être utilisé comme gestionnaire de contexte :\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\nDans les versions récentes de Python, il existe aussi un **gestionnaire de contexte asynchrone**. Vous l'utiliseriez avec `async with` :\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\nQuand vous créez un gestionnaire de contexte ou un gestionnaire de contexte asynchrone comme ci-dessus, ce qu'il fait, c'est qu'avant d'entrer dans le bloc `with`, il exécute le code avant le `yield`, et après être sorti du bloc `with`, il exécute le code après le `yield`.\n\nDans notre exemple de code ci-dessus, nous ne l'utilisons pas directement, mais nous le transmettons à FastAPI pour qu'il l'utilise.\n\nLe paramètre `lifespan` de l'application `FastAPI` accepte un **gestionnaire de contexte asynchrone**, nous pouvons donc lui passer notre nouveau gestionnaire de contexte asynchrone `lifespan`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## Événements alternatifs (déprécié) { #alternative-events-deprecated }\n\n/// warning | Alertes\n\nLa méthode recommandée pour gérer le *démarrage* et l'*arrêt* est d'utiliser le paramètre `lifespan` de l'application `FastAPI` comme décrit ci-dessus. Si vous fournissez un paramètre `lifespan`, les gestionnaires d'événements `startup` et `shutdown` ne seront plus appelés. C'est soit tout en `lifespan`, soit tout en événements, pas les deux.\n\nVous pouvez probablement passer cette partie.\n\n///\n\nIl existe une autre manière de définir cette logique à exécuter au *démarrage* et à l'*arrêt*.\n\nVous pouvez définir des gestionnaires d'événements (fonctions) qui doivent être exécutés avant le démarrage de l'application, ou lorsque l'application s'arrête.\n\nCes fonctions peuvent être déclarées avec `async def` ou un `def` normal.\n\n### Événement `startup` { #startup-event }\n\nPour ajouter une fonction qui doit être exécutée avant le démarrage de l'application, déclarez-la avec l'événement « startup » :\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\nDans ce cas, la fonction gestionnaire de l'événement `startup` initialisera la « base de données » des items (juste un `dict`) avec quelques valeurs.\n\nVous pouvez ajouter plusieurs fonctions de gestion d'événements.\n\nEt votre application ne commencera pas à recevoir des requêtes avant que tous les gestionnaires de l'événement `startup` aient terminé.\n\n### Événement `shutdown` { #shutdown-event }\n\nPour ajouter une fonction qui doit être exécutée lorsque l'application s'arrête, déclarez-la avec l'événement « shutdown » :\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\nIci, la fonction gestionnaire de l'événement `shutdown` écrira une ligne de texte « Application shutdown » dans un fichier `log.txt`.\n\n/// info\n\nDans la fonction `open()`, le `mode=\"a\"` signifie « append » (ajouter) ; la ligne sera donc ajoutée après ce qui se trouve déjà dans ce fichier, sans écraser le contenu précédent.\n\n///\n\n/// tip | Astuce\n\nNotez que dans ce cas, nous utilisons une fonction Python standard `open()` qui interagit avec un fichier.\n\nCela implique des E/S (input/output), qui nécessitent « d'attendre » que des choses soient écrites sur le disque.\n\nMais `open()` n'utilise pas `async` et `await`.\n\nNous déclarons donc la fonction gestionnaire d'événement avec un `def` standard plutôt qu'avec `async def`.\n\n///\n\n### `startup` et `shutdown` ensemble { #startup-and-shutdown-together }\n\nIl y a de fortes chances que la logique de votre *démarrage* et de votre *arrêt* soit liée : vous pourriez vouloir démarrer quelque chose puis le terminer, acquérir une ressource puis la libérer, etc.\n\nFaire cela dans des fonctions séparées qui ne partagent pas de logique ni de variables est plus difficile, car vous devriez stocker des valeurs dans des variables globales ou recourir à des astuces similaires.\n\nPour cette raison, il est désormais recommandé d'utiliser plutôt le `lifespan` comme expliqué ci-dessus.\n\n## Détails techniques { #technical-details }\n\nJuste un détail technique pour les nerds curieux. 🤓\n\nSous le capot, dans la spécification technique ASGI, cela fait partie du [protocole Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), et il y définit des événements appelés `startup` et `shutdown`.\n\n/// info\n\nVous pouvez en lire plus sur les gestionnaires `lifespan` de Starlette dans la [documentation « Lifespan » de Starlette](https://www.starlette.dev/lifespan/).\n\nY compris comment gérer l'état de cycle de vie qui peut être utilisé dans d'autres parties de votre code.\n\n///\n\n## Sous-applications { #sub-applications }\n\n🚨 Gardez à l'esprit que ces événements de cycle de vie (démarrage et arrêt) ne seront exécutés que pour l'application principale, pas pour [Sous-applications - Montages](sub-applications.md).\n"
  },
  {
    "path": "docs/fr/docs/advanced/generate-clients.md",
    "content": "# Générer des SDK { #generating-sdks }\n\nParce que **FastAPI** est basé sur la spécification **OpenAPI**, ses API peuvent être décrites dans un format standard compris par de nombreux outils.\n\nCela facilite la génération de **documentation** à jour, de bibliothèques clientes (<abbr title=\"Software Development Kits - Kits de développement logiciel\">**SDKs**</abbr>) dans plusieurs langages, ainsi que de **tests** ou de **workflows d’automatisation** qui restent synchronisés avec votre code.\n\nDans ce guide, vous apprendrez à générer un **SDK TypeScript** pour votre backend FastAPI.\n\n## Générateurs de SDK open source { #open-source-sdk-generators }\n\nUne option polyvalente est le [OpenAPI Generator](https://openapi-generator.tech/), qui prend en charge **de nombreux langages de programmation** et peut générer des SDK à partir de votre spécification OpenAPI.\n\nPour les **clients TypeScript**, [Hey API](https://heyapi.dev/) est une solution dédiée, offrant une expérience optimisée pour l’écosystème TypeScript.\n\nVous pouvez découvrir davantage de générateurs de SDK sur [OpenAPI.Tools](https://openapi.tools/#sdk).\n\n/// tip | Astuce\n\nFastAPI génère automatiquement des spécifications **OpenAPI 3.1**, donc tout outil que vous utilisez doit prendre en charge cette version.\n\n///\n\n## Générateurs de SDK par les sponsors de FastAPI { #sdk-generators-from-fastapi-sponsors }\n\nCette section met en avant des solutions **soutenues par des fonds** et **par des entreprises** qui sponsorisent FastAPI. Ces produits offrent **des fonctionnalités supplémentaires** et **des intégrations** en plus de SDK de haute qualité générés.\n\nEn ✨ [**sponsorisant FastAPI**](../help-fastapi.md#sponsor-the-author) ✨, ces entreprises contribuent à garantir que le framework et son **écosystème** restent sains et **durables**.\n\nLeur sponsoring démontre également un fort engagement envers la **communauté** FastAPI (vous), montrant qu’elles se soucient non seulement d’offrir un **excellent service**, mais aussi de soutenir un **framework robuste et florissant**, FastAPI. 🙇\n\nPar exemple, vous pourriez essayer :\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\nCertaines de ces solutions peuvent aussi être open source ou proposer des niveaux gratuits, afin que vous puissiez les essayer sans engagement financier. D’autres générateurs de SDK commerciaux existent et peuvent être trouvés en ligne. 🤓\n\n## Créer un SDK TypeScript { #create-a-typescript-sdk }\n\nCommençons par une application FastAPI simple :\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\nRemarquez que les *chemins d'accès* définissent les modèles qu’ils utilisent pour le payload de requête et le payload de réponse, en utilisant les modèles `Item` et `ResponseMessage`.\n\n### Documentation de l’API { #api-docs }\n\nSi vous allez sur `/docs`, vous verrez qu’elle contient les **schémas** pour les données à envoyer dans les requêtes et reçues dans les réponses :\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\nVous voyez ces schémas parce qu’ils ont été déclarés avec les modèles dans l’application.\n\nCes informations sont disponibles dans le **schéma OpenAPI** de l’application, puis affichées dans la documentation de l’API.\n\nCes mêmes informations issues des modèles, incluses dans OpenAPI, peuvent être utilisées pour **générer le code client**.\n\n### Hey API { #hey-api }\n\nUne fois que vous avez une application FastAPI avec les modèles, vous pouvez utiliser Hey API pour générer un client TypeScript. Le moyen le plus rapide de le faire est via npx.\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\nCela générera un SDK TypeScript dans `./src/client`.\n\nVous pouvez apprendre à [installer `@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started) et lire à propos du [résultat généré](https://heyapi.dev/openapi-ts/output) sur leur site.\n\n### Utiliser le SDK { #using-the-sdk }\n\nVous pouvez maintenant importer et utiliser le code client. Cela pourrait ressembler à ceci, remarquez que vous obtenez l’autocomplétion pour les méthodes :\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\nVous obtiendrez également l’autocomplétion pour le payload à envoyer :\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip | Astuce\n\nRemarquez l’autocomplétion pour `name` et `price`, qui a été définie dans l’application FastAPI, dans le modèle `Item`.\n\n///\n\nVous aurez des erreurs en ligne pour les données que vous envoyez :\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\nL’objet de réponse aura également l’autocomplétion :\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## Application FastAPI avec des tags { #fastapi-app-with-tags }\n\nDans de nombreux cas, votre application FastAPI sera plus grande, et vous utiliserez probablement des tags pour séparer différents groupes de *chemins d'accès*.\n\nPar exemple, vous pourriez avoir une section pour les **items** et une autre section pour les **users**, et elles pourraient être séparées par des tags :\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### Générer un client TypeScript avec des tags { #generate-a-typescript-client-with-tags }\n\nSi vous générez un client pour une application FastAPI utilisant des tags, il séparera normalement aussi le code client en fonction des tags.\n\nDe cette façon, vous pourrez avoir les éléments ordonnés et correctement groupés côté client :\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\nDans ce cas, vous avez :\n\n* `ItemsService`\n* `UsersService`\n\n### Noms des méthodes du client { #client-method-names }\n\nÀ l’heure actuelle, les noms de méthodes générés comme `createItemItemsPost` ne sont pas très propres :\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n... c’est parce que le générateur de client utilise l’**operation ID** interne OpenAPI pour chaque *chemin d'accès*.\n\nOpenAPI exige que chaque operation ID soit unique parmi tous les *chemins d'accès*, donc FastAPI utilise le **nom de la fonction**, le **chemin**, et la **méthode/opération HTTP** pour générer cet operation ID, car de cette façon il peut s’assurer que les operation IDs sont uniques.\n\nMais je vais vous montrer comment améliorer cela ensuite. 🤓\n\n## IDs d’opération personnalisés et meilleurs noms de méthodes { #custom-operation-ids-and-better-method-names }\n\nVous pouvez **modifier** la façon dont ces operation IDs sont **générés** pour les simplifier et obtenir des **noms de méthodes plus simples** dans les clients.\n\nDans ce cas, vous devez vous assurer que chaque operation ID est **unique** d’une autre manière.\n\nPar exemple, vous pouvez vous assurer que chaque *chemin d'accès* a un tag, puis générer l’operation ID à partir du **tag** et du **nom** du *chemin d'accès* (le nom de la fonction).\n\n### Fonction personnalisée de génération d’ID unique { #custom-generate-unique-id-function }\n\nFastAPI utilise un **ID unique** pour chaque *chemin d'accès*, qui est utilisé pour l’**operation ID** et également pour les noms des modèles personnalisés nécessaires, pour les requêtes ou les réponses.\n\nVous pouvez personnaliser cette fonction. Elle prend un `APIRoute` et retourne une chaîne.\n\nPar exemple, ici elle utilise le premier tag (vous n’en aurez probablement qu’un) et le nom du *chemin d'accès* (le nom de la fonction).\n\nVous pouvez ensuite passer cette fonction personnalisée à **FastAPI** via le paramètre `generate_unique_id_function` :\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### Générer un client TypeScript avec des IDs d’opération personnalisés { #generate-a-typescript-client-with-custom-operation-ids }\n\nMaintenant, si vous régénérez le client, vous verrez qu’il possède des noms de méthodes améliorés :\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\nComme vous le voyez, les noms de méthodes contiennent maintenant le tag puis le nom de la fonction ; ils n’incluent plus d’informations provenant du chemin d’URL et de l’opération HTTP.\n\n### Prétraiter la spécification OpenAPI pour le générateur de client { #preprocess-the-openapi-specification-for-the-client-generator }\n\nLe code généré contient encore des **informations dupliquées**.\n\nNous savons déjà que cette méthode est liée aux **items** parce que ce mot figure dans `ItemsService` (issu du tag), mais nous avons encore le nom du tag préfixé dans le nom de la méthode. 😕\n\nNous voudrons probablement le conserver pour OpenAPI en général, car cela garantira que les operation IDs sont **uniques**.\n\nMais pour le client généré, nous pourrions **modifier** les operation IDs d’OpenAPI juste avant de générer les clients, simplement pour rendre ces noms de méthodes plus agréables et **plus clairs**.\n\nNous pourrions télécharger le JSON OpenAPI dans un fichier `openapi.json` puis **supprimer ce tag préfixé** avec un script comme celui-ci :\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\nAvec cela, les operation IDs seraient renommés de `items-get_items` en simplement `get_items`, de sorte que le générateur de client puisse produire des noms de méthodes plus simples.\n\n### Générer un client TypeScript avec l’OpenAPI prétraité { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\nPuisque le résultat final se trouve maintenant dans un fichier `openapi.json`, vous devez mettre à jour l’emplacement d’entrée :\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\nAprès avoir généré le nouveau client, vous aurez désormais des **noms de méthodes propres**, avec toute l’**autocomplétion**, les **erreurs en ligne**, etc. :\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## Avantages { #benefits }\n\nEn utilisant les clients générés automatiquement, vous obtiendrez de l’**autocomplétion** pour :\n\n* Méthodes.\n* Payloads de requête dans le corps, paramètres de requête, etc.\n* Payloads de réponse.\n\nVous auriez également des **erreurs en ligne** pour tout.\n\nEt chaque fois que vous mettez à jour le code du backend et **régénérez** le frontend, il inclura les nouveaux *chemins d'accès* disponibles en tant que méthodes, supprimera les anciens, et tout autre changement sera reflété dans le code généré. 🤓\n\nCela signifie aussi que si quelque chose change, cela sera **reflété** automatiquement dans le code client. Et si vous **bâtissez** le client, il échouera en cas de **discordance** dans les données utilisées.\n\nAinsi, vous **détecterez de nombreuses erreurs** très tôt dans le cycle de développement au lieu d’attendre qu’elles apparaissent pour vos utilisateurs finaux en production puis de tenter de déboguer l’origine du problème. ✨\n"
  },
  {
    "path": "docs/fr/docs/advanced/index.md",
    "content": "# Guide de l'utilisateur avancé { #advanced-user-guide }\n\n## Caractéristiques supplémentaires { #additional-features }\n\nLe [Tutoriel - Guide de l'utilisateur](../tutorial/index.md) devrait suffire à vous faire découvrir toutes les fonctionnalités principales de **FastAPI**.\n\nDans les sections suivantes, vous verrez des options, configurations et fonctionnalités supplémentaires.\n\n/// tip | Astuce\n\nLes sections suivantes ne sont **pas nécessairement « avancées »**.\n\nEt il est possible que, pour votre cas d'utilisation, la solution se trouve dans l'une d'entre elles.\n\n///\n\n## Lire d'abord le tutoriel { #read-the-tutorial-first }\n\nVous pouvez utiliser la plupart des fonctionnalités de **FastAPI** grâce aux connaissances du [Tutoriel - Guide de l'utilisateur](../tutorial/index.md).\n\nEt les sections suivantes supposent que vous l'avez lu et que vous en connaissez les idées principales.\n"
  },
  {
    "path": "docs/fr/docs/advanced/json-base64-bytes.md",
    "content": "# JSON avec des octets en Base64 { #json-with-bytes-as-base64 }\n\nSi votre application doit recevoir et envoyer des données JSON, mais que vous devez y inclure des données binaires, vous pouvez les encoder en base64.\n\n## Base64 vs fichiers { #base64-vs-files }\n\nEnvisagez d'abord d'utiliser [Fichiers de requête](../tutorial/request-files.md) pour téléverser des données binaires et [Réponse personnalisée - FileResponse](./custom-response.md#fileresponse--fileresponse-) pour envoyer des données binaires, plutôt que de les encoder dans du JSON.\n\nJSON ne peut contenir que des chaînes encodées en UTF-8, il ne peut donc pas contenir d'octets bruts.\n\nBase64 peut encoder des données binaires en chaînes, mais pour cela il doit utiliser plus de caractères que les données binaires originales ; c'est donc en général moins efficace que des fichiers classiques.\n\nN'utilisez base64 que si vous devez absolument inclure des données binaires dans du JSON et que vous ne pouvez pas utiliser des fichiers pour cela.\n\n## Pydantic `bytes` { #pydantic-bytes }\n\nVous pouvez déclarer un modèle Pydantic avec des champs `bytes`, puis utiliser `val_json_bytes` dans la configuration du modèle pour lui indiquer d'utiliser base64 pour valider les données JSON en entrée ; dans le cadre de cette validation, il décodera la chaîne base64 en octets.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\nSi vous allez sur les `/docs`, vous verrez que le champ `data` attend des octets encodés en base64 :\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\nVous pourriez envoyer une requête comme :\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip | Astuce\n\n`aGVsbG8=` est l'encodage base64 de `hello`.\n\n///\n\nPydantic décodera ensuite la chaîne base64 et vous fournira les octets originaux dans le champ `data` du modèle.\n\nVous recevrez une réponse comme :\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## Pydantic `bytes` pour les données de sortie { #pydantic-bytes-for-output-data }\n\nVous pouvez également utiliser des champs `bytes` avec `ser_json_bytes` dans la configuration du modèle pour les données de sortie ; Pydantic sérialisera alors les octets en base64 lors de la génération de la réponse JSON.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## Pydantic `bytes` pour les données d'entrée et de sortie { #pydantic-bytes-for-input-and-output-data }\n\nEt bien sûr, vous pouvez utiliser le même modèle configuré pour utiliser base64 afin de gérer à la fois l'entrée (valider) avec `val_json_bytes` et la sortie (sérialiser) avec `ser_json_bytes` lors de la réception et de l'envoi de données JSON.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/fr/docs/advanced/middleware.md",
    "content": "# Utiliser des middlewares avancés { #advanced-middleware }\n\nDans le tutoriel principal, vous avez vu comment ajouter des [middlewares personnalisés](../tutorial/middleware.md) à votre application.\n\nVous avez également vu comment gérer [CORS avec le `CORSMiddleware`](../tutorial/cors.md).\n\nDans cette section, nous allons voir comment utiliser d'autres middlewares.\n\n## Ajouter des middlewares ASGI { #adding-asgi-middlewares }\n\nComme **FastAPI** est basé sur Starlette et implémente la spécification <abbr title=\"Asynchronous Server Gateway Interface - Interface passerelle serveur asynchrone\">ASGI</abbr>, vous pouvez utiliser n'importe quel middleware ASGI.\n\nUn middleware n'a pas besoin d'être conçu pour FastAPI ou Starlette pour fonctionner, tant qu'il suit la spécification ASGI.\n\nEn général, les middlewares ASGI sont des classes qui s'attendent à recevoir une application ASGI en premier argument.\n\nAinsi, dans la documentation de middlewares ASGI tiers, on vous indiquera probablement de faire quelque chose comme :\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\nMais FastAPI (en fait Starlette) fournit une manière plus simple de le faire, qui garantit que les middlewares internes gèrent les erreurs serveur et que les gestionnaires d'exceptions personnalisés fonctionnent correctement.\n\nPour cela, vous utilisez `app.add_middleware()` (comme dans l'exemple pour CORS).\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` reçoit une classe de middleware en premier argument, ainsi que tout argument supplémentaire à transmettre au middleware.\n\n## Utiliser les middlewares intégrés { #integrated-middlewares }\n\n**FastAPI** inclut plusieurs middlewares pour des cas d'usage courants ; voyons comment les utiliser.\n\n/// note | Détails techniques\n\nPour les prochains exemples, vous pourriez aussi utiliser `from starlette.middleware.something import SomethingMiddleware`.\n\n**FastAPI** fournit plusieurs middlewares dans `fastapi.middleware` simplement pour vous faciliter la vie, en tant que développeur. Mais la plupart des middlewares disponibles viennent directement de Starlette.\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\nImpose que toutes les requêtes entrantes soient soit `https`, soit `wss`.\n\nToute requête entrante en `http` ou `ws` sera redirigée vers le schéma sécurisé correspondant.\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\nImpose que toutes les requêtes entrantes aient un en-tête `Host` correctement défini, afin de se prémunir contre les attaques de type HTTP Host Header.\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\nLes arguments suivants sont pris en charge :\n\n- `allowed_hosts` - Une liste de noms de domaine autorisés comme noms d'hôte. Les domaines génériques tels que `*.example.com` sont pris en charge pour faire correspondre les sous-domaines. Pour autoriser n'importe quel nom d'hôte, utilisez `allowed_hosts=[\"*\"]` ou omettez le middleware.\n- `www_redirect` - Si défini à `True`, les requêtes vers les versions sans www des hôtes autorisés seront redirigées vers leurs équivalents avec www. Valeur par défaut : `True`.\n\nSi une requête entrante n'est pas valide, une réponse `400` sera envoyée.\n\n## `GZipMiddleware` { #gzipmiddleware }\n\nGère les réponses GZip pour toute requête qui inclut « gzip » dans l'en-tête `Accept-Encoding`.\n\nLe middleware gérera les réponses standard et en streaming.\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\nLes arguments suivants sont pris en charge :\n\n- `minimum_size` - Ne pas compresser en GZip les réponses dont la taille est inférieure à ce minimum en octets. Valeur par défaut : `500`.\n- `compresslevel` - Utilisé pendant la compression GZip. Entier compris entre 1 et 9. Valeur par défaut : `9`. Une valeur plus faible entraîne une compression plus rapide mais des fichiers plus volumineux, tandis qu'une valeur plus élevée entraîne une compression plus lente mais des fichiers plus petits.\n\n## Autres middlewares { #other-middlewares }\n\nIl existe de nombreux autres middlewares ASGI.\n\nPar exemple :\n\n- [Le `ProxyHeadersMiddleware` d'Uvicorn](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n- [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\nPour voir d'autres middlewares disponibles, consultez la [documentation des middlewares de Starlette](https://www.starlette.dev/middleware/) et la [liste ASGI Awesome](https://github.com/florimondmanca/awesome-asgi).\n"
  },
  {
    "path": "docs/fr/docs/advanced/openapi-callbacks.md",
    "content": "# Callbacks OpenAPI { #openapi-callbacks }\n\nVous pourriez créer une API avec un *chemin d'accès* qui déclenche une requête vers une *API externe* créée par quelqu'un d'autre (probablement la même personne développeuse qui utiliserait votre API).\n\nLe processus qui se produit lorsque votre application API appelle l’*API externe* s’appelle un « callback ». Parce que le logiciel écrit par la personne développeuse externe envoie une requête à votre API puis votre API « rappelle », en envoyant une requête à une *API externe* (probablement créée par la même personne développeuse).\n\nDans ce cas, vous pourriez vouloir documenter à quoi cette API externe devrait ressembler. Quel *chemin d'accès* elle devrait avoir, quel corps elle devrait attendre, quelle réponse elle devrait renvoyer, etc.\n\n## Une application avec des callbacks { #an-app-with-callbacks }\n\nVoyons tout cela avec un exemple.\n\nImaginez que vous développiez une application qui permet de créer des factures.\n\nCes factures auront un `id`, un `title` (facultatif), un `customer` et un `total`.\n\nL’utilisateur de votre API (une personne développeuse externe) créera une facture dans votre API avec une requête POST.\n\nEnsuite votre API va (imaginons) :\n\n* Envoyer la facture à un client de la personne développeuse externe.\n* Encaisser l’argent.\n* Renvoyer une notification à l’utilisateur de l’API (la personne développeuse externe).\n    * Cela sera fait en envoyant une requête POST (depuis *votre API*) vers une *API externe* fournie par cette personne développeuse externe (c’est le « callback »).\n\n## L’application **FastAPI** normale { #the-normal-fastapi-app }\n\nVoyons d’abord à quoi ressemble l’application API normale avant d’ajouter le callback.\n\nElle aura un *chemin d'accès* qui recevra un corps `Invoice`, et un paramètre de requête `callback_url` qui contiendra l’URL pour le callback.\n\nCette partie est assez normale, la plupart du code vous est probablement déjà familier :\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip | Astuce\n\nLe paramètre de requête `callback_url` utilise un type Pydantic [Url](https://docs.pydantic.dev/latest/api/networks/).\n\n///\n\nLa seule nouveauté est `callbacks=invoices_callback_router.routes` comme argument du *décorateur de chemin d'accès*. Nous allons voir ce que c’est ensuite.\n\n## Documenter le callback { #documenting-the-callback }\n\nLe code réel du callback dépendra fortement de votre application API.\n\nEt il variera probablement beaucoup d’une application à l’autre.\n\nCela pourrait être seulement une ou deux lignes de code, comme :\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\nMais la partie la plus importante du callback est sans doute de vous assurer que l’utilisateur de votre API (la personne développeuse externe) implémente correctement l’*API externe*, conformément aux données que *votre API* va envoyer dans le corps de la requête du callback, etc.\n\nAinsi, ce que nous allons faire ensuite, c’est ajouter le code pour documenter à quoi cette *API externe* devrait ressembler pour recevoir le callback de *votre API*.\n\nCette documentation apparaîtra dans Swagger UI à `/docs` dans votre API, et permettra aux personnes développeuses externes de savoir comment construire l’*API externe*.\n\nCet exemple n’implémente pas le callback lui-même (qui pourrait être une simple ligne de code), uniquement la partie documentation.\n\n/// tip | Astuce\n\nLe callback réel n’est qu’une requête HTTP.\n\nEn implémentant vous-même le callback, vous pourriez utiliser quelque chose comme [HTTPX](https://www.python-httpx.org) ou [Requests](https://requests.readthedocs.io/).\n\n///\n\n## Écrire le code de documentation du callback { #write-the-callback-documentation-code }\n\nCe code ne sera pas exécuté dans votre application, nous en avons seulement besoin pour *documenter* à quoi devrait ressembler cette *API externe*.\n\nMais vous savez déjà comment créer facilement une documentation automatique pour une API avec **FastAPI**.\n\nNous allons donc utiliser ce même savoir pour documenter à quoi l’*API externe* devrait ressembler ... en créant le(s) *chemin(s) d'accès* que l’API externe devrait implémenter (ceux que votre API appellera).\n\n/// tip | Astuce\n\nLorsque vous écrivez le code pour documenter un callback, il peut être utile d’imaginer que vous êtes cette *personne développeuse externe*. Et que vous implémentez actuellement l’*API externe*, pas *votre API*.\n\nAdopter temporairement ce point de vue (celui de la *personne développeuse externe*) peut vous aider à trouver plus évident où placer les paramètres, le modèle Pydantic pour le corps, pour la réponse, etc., pour cette *API externe*.\n\n///\n\n### Créer un `APIRouter` de callback { #create-a-callback-apirouter }\n\nCommencez par créer un nouveau `APIRouter` qui contiendra un ou plusieurs callbacks.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### Créer le *chemin d'accès* du callback { #create-the-callback-path-operation }\n\nPour créer le *chemin d'accès* du callback, utilisez le même `APIRouter` que vous avez créé ci-dessus.\n\nIl devrait ressembler exactement à un *chemin d'accès* FastAPI normal :\n\n* Il devrait probablement déclarer le corps qu’il doit recevoir, par exemple `body: InvoiceEvent`.\n* Et il pourrait aussi déclarer la réponse qu’il doit renvoyer, par exemple `response_model=InvoiceEventReceived`.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\nIl y a 2 principales différences par rapport à un *chemin d'accès* normal :\n\n* Il n’a pas besoin d’avoir de code réel, car votre application n’appellera jamais ce code. Il sert uniquement à documenter l’*API externe*. La fonction peut donc simplement contenir `pass`.\n* Le *chemin* peut contenir une [expression OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (voir plus bas) où il peut utiliser des variables avec des paramètres et des parties de la requête originale envoyée à *votre API*.\n\n### L’expression du chemin de callback { #the-callback-path-expression }\n\nLe *chemin* du callback peut contenir une [expression OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) qui peut inclure des parties de la requête originale envoyée à *votre API*.\n\nDans ce cas, c’est la `str` :\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\nAinsi, si l’utilisateur de votre API (la personne développeuse externe) envoie une requête à *votre API* vers :\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\navec un corps JSON :\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\nalors *votre API* traitera la facture et, à un moment ultérieur, enverra une requête de callback à `callback_url` (l’*API externe*) :\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\navec un corps JSON contenant quelque chose comme :\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\net elle s’attendra à une réponse de cette *API externe* avec un corps JSON comme :\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip | Astuce\n\nRemarquez que l’URL de callback utilisée contient l’URL reçue en paramètre de requête dans `callback_url` (`https://www.external.org/events`) et aussi l’`id` de la facture à l’intérieur du corps JSON (`2expen51ve`).\n\n///\n\n### Ajouter le routeur de callback { #add-the-callback-router }\n\nÀ ce stade, vous avez le(s) *chemin(s) d'accès de callback* nécessaire(s) (celui/ceux que la *personne développeuse externe* doit implémenter dans l’*API externe*) dans le routeur de callback que vous avez créé ci-dessus.\n\nUtilisez maintenant le paramètre `callbacks` dans *le décorateur de chemin d'accès de votre API* pour passer l’attribut `.routes` (qui est en fait juste une `list` de routes/*chemins d'accès*) depuis ce routeur de callback :\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip | Astuce\n\nRemarquez que vous ne passez pas le routeur lui-même (`invoices_callback_router`) à `callback=`, mais l’attribut `.routes`, comme dans `invoices_callback_router.routes`.\n\n///\n\n### Vérifier la documentation { #check-the-docs }\n\nVous pouvez maintenant démarrer votre application et aller sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVous verrez votre documentation incluant une section « Callbacks » pour votre *chemin d'accès* qui montre à quoi l’*API externe* devrait ressembler :\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/fr/docs/advanced/openapi-webhooks.md",
    "content": "# Webhooks OpenAPI { #openapi-webhooks }\n\nIl existe des cas où vous voulez informer les utilisateurs de votre API que votre application peut appeler leur application (en envoyant une requête) avec des données, généralement pour notifier un type d'événement.\n\nCela signifie qu'au lieu du processus habituel où vos utilisateurs envoient des requêtes à votre API, c'est votre API (ou votre application) qui peut envoyer des requêtes vers leur système (vers leur API, leur application).\n\nOn appelle généralement cela un webhook.\n\n## Étapes des webhooks { #webhooks-steps }\n\nLe processus consiste généralement à définir dans votre code le message que vous enverrez, c'est-à-dire le corps de la requête.\n\nVous définissez également, d'une manière ou d'une autre, à quels moments votre application enverra ces requêtes ou événements.\n\nEt vos utilisateurs définissent aussi, d'une manière ou d'une autre (par exemple dans un tableau de bord Web), l'URL à laquelle votre application doit envoyer ces requêtes.\n\nToute la logique de gestion des URL des webhooks et le code qui envoie effectivement ces requêtes vous incombent. Vous l'implémentez comme vous le souhaitez dans votre propre code.\n\n## Documenter des webhooks avec FastAPI et OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }\n\nAvec FastAPI, en utilisant OpenAPI, vous pouvez définir les noms de ces webhooks, les types d'opérations HTTP que votre application peut envoyer (par exemple `POST`, `PUT`, etc.) et les corps des requêtes que votre application enverra.\n\nCela peut grandement faciliter la tâche de vos utilisateurs pour implémenter leurs API afin de recevoir vos requêtes de webhook ; ils pourront même peut-être générer automatiquement une partie de leur propre code d'API.\n\n/// info\n\nLes webhooks sont disponibles dans OpenAPI 3.1.0 et versions ultérieures, pris en charge par FastAPI `0.99.0` et versions ultérieures.\n\n///\n\n## Créer une application avec des webhooks { #an-app-with-webhooks }\n\nLorsque vous créez une application FastAPI, il existe un attribut `webhooks` que vous pouvez utiliser pour définir des webhooks, de la même manière que vous définiriez des chemins d'accès, par exemple avec `@app.webhooks.post()`.\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\nLes webhooks que vous définissez apparaîtront dans le schéma OpenAPI et dans l'interface de documentation automatique.\n\n/// info\n\nL'objet `app.webhooks` est en fait simplement un `APIRouter`, le même type que vous utiliseriez pour structurer votre application en plusieurs fichiers.\n\n///\n\nNotez qu'avec les webhooks, vous ne déclarez pas réellement un chemin (comme `/items/`), le texte que vous y passez est simplement un identifiant du webhook (le nom de l'événement). Par exemple, dans `@app.webhooks.post(\"new-subscription\")`, le nom du webhook est `new-subscription`.\n\nC'est parce qu'on s'attend à ce que vos utilisateurs définissent, par un autre moyen (par exemple un tableau de bord Web), le véritable chemin d'URL où ils souhaitent recevoir la requête de webhook.\n\n### Consulter la documentation { #check-the-docs }\n\nVous pouvez maintenant démarrer votre application et aller sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVous verrez que votre documentation contient les chemins d'accès habituels et désormais aussi des webhooks :\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/fr/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# Configuration avancée des chemins d'accès { #path-operation-advanced-configuration }\n\n## ID d’opération OpenAPI { #openapi-operationid }\n\n/// warning | Alertes\n\nSi vous n’êtes pas un « expert » d’OpenAPI, vous n’en avez probablement pas besoin.\n\n///\n\nVous pouvez définir l’OpenAPI `operationId` à utiliser dans votre chemin d’accès avec le paramètre `operation_id`.\n\nVous devez vous assurer qu’il est unique pour chaque opération.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### Utiliser le nom de la fonction de chemin d’accès comme operationId { #using-the-path-operation-function-name-as-the-operationid }\n\nSi vous souhaitez utiliser les noms de fonction de vos API comme `operationId`, vous pouvez les parcourir tous et remplacer l’`operation_id` de chaque chemin d’accès en utilisant leur `APIRoute.name`.\n\nVous devez le faire après avoir ajouté tous vos chemins d’accès.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip | Astuce\n\nSi vous appelez manuellement `app.openapi()`, vous devez mettre à jour les `operationId` avant cela.\n\n///\n\n/// warning | Alertes\n\nSi vous faites cela, vous devez vous assurer que chacune de vos fonctions de chemin d’accès a un nom unique.\n\nMême si elles se trouvent dans des modules différents (fichiers Python).\n\n///\n\n## Exclusion d’OpenAPI { #exclude-from-openapi }\n\nPour exclure un chemin d’accès du schéma OpenAPI généré (et donc des systèmes de documentation automatiques), utilisez le paramètre `include_in_schema` et définissez-le à `False` :\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## Description avancée depuis la docstring { #advanced-description-from-docstring }\n\nVous pouvez limiter les lignes utilisées de la docstring d’une fonction de chemin d’accès pour OpenAPI.\n\nL’ajout d’un `\\f` (un caractère « form feed » échappé) amène **FastAPI** à tronquer la sortie utilisée pour OpenAPI à cet endroit.\n\nCela n’apparaîtra pas dans la documentation, mais d’autres outils (comme Sphinx) pourront utiliser le reste.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## Réponses supplémentaires { #additional-responses }\n\nVous avez probablement vu comment déclarer le `response_model` et le `status_code` pour un chemin d’accès.\n\nCela définit les métadonnées sur la réponse principale d’un chemin d’accès.\n\nVous pouvez également déclarer des réponses supplémentaires avec leurs modèles, codes de statut, etc.\n\nIl y a un chapitre entier dans la documentation à ce sujet, vous pouvez le lire dans [Réponses supplémentaires dans OpenAPI](additional-responses.md).\n\n## OpenAPI supplémentaire { #openapi-extra }\n\nLorsque vous déclarez un chemin d’accès dans votre application, **FastAPI** génère automatiquement les métadonnées pertinentes à propos de ce chemin d’accès à inclure dans le schéma OpenAPI.\n\n/// note | Détails techniques\n\nDans la spécification OpenAPI, cela s’appelle l’[objet Operation](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object).\n\n///\n\nIl contient toutes les informations sur le chemin d’accès et est utilisé pour générer la documentation automatique.\n\nIl inclut les `tags`, `parameters`, `requestBody`, `responses`, etc.\n\nCe schéma OpenAPI spécifique à un chemin d’accès est normalement généré automatiquement par **FastAPI**, mais vous pouvez également l’étendre.\n\n/// tip | Astuce\n\nCeci est un point d’extension de bas niveau.\n\nSi vous avez seulement besoin de déclarer des réponses supplémentaires, un moyen plus pratique de le faire est d’utiliser [Réponses supplémentaires dans OpenAPI](additional-responses.md).\n\n///\n\nVous pouvez étendre le schéma OpenAPI pour un chemin d’accès en utilisant le paramètre `openapi_extra`.\n\n### Extensions OpenAPI { #openapi-extensions }\n\nCet `openapi_extra` peut être utile, par exemple, pour déclarer des [Extensions OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) :\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\nSi vous ouvrez la documentation automatique de l’API, votre extension apparaîtra en bas du chemin d’accès spécifique.\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\nEt si vous consultez l’OpenAPI résultant (à `/openapi.json` dans votre API), vous verrez également votre extension comme partie du chemin d’accès spécifique :\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### Personnaliser le schéma OpenAPI d’un chemin d’accès { #custom-openapi-path-operation-schema }\n\nLe dictionnaire dans `openapi_extra` sera fusionné en profondeur avec le schéma OpenAPI généré automatiquement pour le chemin d’accès.\n\nAinsi, vous pouvez ajouter des données supplémentaires au schéma généré automatiquement.\n\nPar exemple, vous pourriez décider de lire et de valider la requête avec votre propre code, sans utiliser les fonctionnalités automatiques de FastAPI avec Pydantic, mais vous pourriez tout de même vouloir définir la requête dans le schéma OpenAPI.\n\nVous pourriez le faire avec `openapi_extra` :\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\nDans cet exemple, nous n’avons déclaré aucun modèle Pydantic. En fait, le corps de la requête n’est même pas <dfn title=\"converti d'un format simple, comme des octets, en objets Python\">parsé</dfn> en JSON, il est lu directement en tant que `bytes`, et la fonction `magic_data_reader()` serait chargée de l’analyser d’une manière ou d’une autre.\n\nNéanmoins, nous pouvons déclarer le schéma attendu pour le corps de la requête.\n\n### Type de contenu OpenAPI personnalisé { #custom-openapi-content-type }\n\nEn utilisant cette même astuce, vous pourriez utiliser un modèle Pydantic pour définir le JSON Schema qui est ensuite inclus dans la section de schéma OpenAPI personnalisée pour le chemin d’accès.\n\nEt vous pourriez le faire même si le type de données dans la requête n’est pas du JSON.\n\nPar exemple, dans cette application nous n’utilisons pas la fonctionnalité intégrée de FastAPI pour extraire le JSON Schema des modèles Pydantic ni la validation automatique pour le JSON. En fait, nous déclarons le type de contenu de la requête comme YAML, pas JSON :\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\nNéanmoins, bien que nous n’utilisions pas la fonctionnalité intégrée par défaut, nous utilisons toujours un modèle Pydantic pour générer manuellement le JSON Schema pour les données que nous souhaitons recevoir en YAML.\n\nEnsuite, nous utilisons directement la requête et extrayons le corps en tant que `bytes`. Cela signifie que FastAPI n’essaiera même pas d’analyser le payload de la requête en JSON.\n\nEnsuite, dans notre code, nous analysons directement ce contenu YAML, puis nous utilisons à nouveau le même modèle Pydantic pour valider le contenu YAML :\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip | Astuce\n\nIci, nous réutilisons le même modèle Pydantic.\n\nMais de la même manière, nous aurions pu le valider autrement.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/advanced/response-change-status-code.md",
    "content": "# Réponse - Modifier le code d'état { #response-change-status-code }\n\nVous avez probablement déjà lu que vous pouvez définir un [Code d'état de la réponse](../tutorial/response-status-code.md) par défaut.\n\nMais dans certains cas, vous devez renvoyer un code d'état différent de celui par défaut.\n\n## Cas d'utilisation { #use-case }\n\nPar exemple, imaginez que vous vouliez renvoyer par défaut un code d'état HTTP « OK » `200`.\n\nMais si les données n'existent pas, vous voulez les créer et renvoyer un code d'état HTTP « CREATED » `201`.\n\nMais vous souhaitez toujours pouvoir filtrer et convertir les données que vous renvoyez avec un `response_model`.\n\nPour ces cas, vous pouvez utiliser un paramètre `Response`.\n\n## Utiliser un paramètre `Response` { #use-a-response-parameter }\n\nVous pouvez déclarer un paramètre de type `Response` dans votre fonction de chemin d'accès (comme vous pouvez le faire pour les cookies et les en-têtes).\n\nVous pouvez ensuite définir le `status_code` dans cet objet de réponse *temporaire*.\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\nVous pouvez ensuite renvoyer n'importe quel objet nécessaire, comme d'habitude (un `dict`, un modèle de base de données, etc.).\n\nEt si vous avez déclaré un `response_model`, il sera toujours utilisé pour filtrer et convertir l'objet que vous avez renvoyé.\n\n**FastAPI** utilisera cette réponse *temporaire* pour extraire le code d'état (ainsi que les cookies et les en-têtes), et les placera dans la réponse finale qui contient la valeur que vous avez renvoyée, filtrée par tout `response_model`.\n\nVous pouvez également déclarer le paramètre `Response` dans des dépendances et y définir le code d'état. Mais gardez à l'esprit que la dernière valeur définie prévaut.\n"
  },
  {
    "path": "docs/fr/docs/advanced/response-cookies.md",
    "content": "# Cookies de réponse { #response-cookies }\n\n## Utiliser un paramètre `Response` { #use-a-response-parameter }\n\nVous pouvez déclarer un paramètre de type `Response` dans votre *fonction de chemin d'accès*.\n\nVous pouvez ensuite définir des cookies dans cet objet de réponse *temporaire*.\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\nVous pouvez ensuite renvoyer n'importe quel objet dont vous avez besoin, comme d'habitude (un `dict`, un modèle de base de données, etc.).\n\nEt si vous avez déclaré un `response_model`, il sera toujours utilisé pour filtrer et convertir l'objet que vous avez renvoyé.\n\n**FastAPI** utilisera cette réponse *temporaire* pour extraire les cookies (ainsi que les en-têtes et le code d'état), et les placera dans la réponse finale qui contient la valeur que vous avez renvoyée, filtrée par tout `response_model`.\n\nVous pouvez également déclarer le paramètre `Response` dans des dépendances, et y définir des cookies (et des en-têtes).\n\n## Renvoyer une `Response` directement { #return-a-response-directly }\n\nVous pouvez également créer des cookies en renvoyant une `Response` directement dans votre code.\n\nPour ce faire, vous pouvez créer une réponse comme décrit dans [Renvoyer une Response directement](response-directly.md).\n\nDéfinissez ensuite des cookies dessus, puis renvoyez-la :\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip | Astuce\n\nGardez à l'esprit que si vous renvoyez une réponse directement au lieu d'utiliser le paramètre `Response`, FastAPI la renverra telle quelle.\n\nVous devez donc vous assurer que vos données sont du type correct. Par exemple, qu'elles sont compatibles avec JSON si vous renvoyez une `JSONResponse`.\n\nEt également que vous n'envoyez pas de données qui auraient dû être filtrées par un `response_model`.\n\n///\n\n### En savoir plus { #more-info }\n\n/// note | Détails techniques\n\nVous pouvez également utiliser `from starlette.responses import Response` ou `from starlette.responses import JSONResponse`.\n\n**FastAPI** fournit les mêmes `starlette.responses` que `fastapi.responses` simplement pour votre commodité, en tant que développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.\n\nEt comme `Response` peut être utilisé fréquemment pour définir des en-têtes et des cookies, **FastAPI** la met également à disposition via `fastapi.Response`.\n\n///\n\nPour voir tous les paramètres et options disponibles, consultez la [documentation de Starlette](https://www.starlette.dev/responses/#set-cookie).\n"
  },
  {
    "path": "docs/fr/docs/advanced/response-directly.md",
    "content": "# Renvoyer directement une réponse { #return-a-response-directly }\n\nLorsque vous créez un *chemin d'accès* **FastAPI**, vous pouvez normalement renvoyer n'importe quelle donnée : un `dict`, une `list`, un modèle Pydantic, un modèle de base de données, etc.\n\nSi vous déclarez un [Modèle de réponse](../tutorial/response-model.md), FastAPI l'utilise pour sérialiser les données en JSON, en utilisant Pydantic.\n\nSi vous ne déclarez pas de modèle de réponse, FastAPI utilise le `jsonable_encoder` expliqué dans [Encodeur compatible JSON](../tutorial/encoder.md) et le place dans une `JSONResponse`.\n\nVous pouvez également créer directement une `JSONResponse` et la renvoyer.\n\n/// tip | Astuce\n\nVous aurez normalement une bien meilleure performance en utilisant un [Modèle de réponse](../tutorial/response-model.md) qu'en renvoyant directement une `JSONResponse`, car de cette façon la sérialisation des données est effectuée par Pydantic, en Rust.\n\n///\n\n## Renvoyer une `Response` { #return-a-response }\n\nVous pouvez renvoyer une `Response` ou n'importe laquelle de ses sous-classes.\n\n/// info\n\n`JSONResponse` est elle-même une sous-classe de `Response`.\n\n///\n\nEt lorsque vous renvoyez une `Response`, **FastAPI** la transmet directement.\n\nIl n'effectue aucune conversion de données avec les modèles Pydantic, il ne convertit pas le contenu en un autre type, etc.\n\nCela vous donne beaucoup de flexibilité. Vous pouvez renvoyer n'importe quel type de données, surcharger toute déclaration ou validation de données, etc.\n\nCela vous donne aussi beaucoup de responsabilité. Vous devez vous assurer que les données que vous renvoyez sont correctes, dans le bon format, qu'elles peuvent être sérialisées, etc.\n\n## Utiliser le `jsonable_encoder` dans une `Response` { #using-the-jsonable-encoder-in-a-response }\n\nComme **FastAPI** n'apporte aucune modification à une `Response` que vous renvoyez, vous devez vous assurer que son contenu est prêt pour cela.\n\nPar exemple, vous ne pouvez pas mettre un modèle Pydantic dans une `JSONResponse` sans d'abord le convertir en un `dict` avec tous les types de données (comme `datetime`, `UUID`, etc.) convertis en types compatibles JSON.\n\nPour ces cas, vous pouvez utiliser le `jsonable_encoder` pour convertir vos données avant de les passer à une réponse :\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | Détails techniques\n\nVous pouvez aussi utiliser `from starlette.responses import JSONResponse`.\n\n**FastAPI** fournit le même `starlette.responses` que `fastapi.responses` uniquement par commodité pour vous, développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.\n\n///\n\n## Renvoyer une `Response` personnalisée { #returning-a-custom-response }\n\nL'exemple ci-dessus montre toutes les parties dont vous avez besoin, mais il n'est pas encore très utile, car vous auriez pu renvoyer l'`item` directement, et **FastAPI** l'aurait placé dans une `JSONResponse` pour vous, en le convertissant en `dict`, etc. Tout cela par défaut.\n\nVoyons maintenant comment vous pourriez utiliser cela pour renvoyer une réponse personnalisée.\n\nDisons que vous voulez renvoyer une [réponse XML](https://en.wikipedia.org/wiki/XML).\n\nVous pouvez placer votre contenu XML dans une chaîne de caractères, le mettre dans une `Response` et le renvoyer :\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## Comprendre le fonctionnement d'un Modèle de réponse { #how-a-response-model-works }\n\nLorsque vous déclarez un [Modèle de réponse - Type de retour](../tutorial/response-model.md) dans un chemin d'accès, **FastAPI** l'utilise pour sérialiser les données en JSON, en utilisant Pydantic.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nComme cela se passe côté Rust, la performance sera bien meilleure que si cela était fait avec le Python classique et la classe `JSONResponse`.\n\nLorsque vous utilisez un `response_model` ou un type de retour, FastAPI n'utilise ni le `jsonable_encoder` pour convertir les données (ce qui serait plus lent) ni la classe `JSONResponse`.\n\nÀ la place, il prend les octets JSON générés avec Pydantic en utilisant le modèle de réponse (ou le type de retour) et renvoie directement une `Response` avec le type de média approprié pour JSON (`application/json`).\n\n## Notes { #notes }\n\nLorsque vous renvoyez une `Response` directement, ses données ne sont pas validées, converties (sérialisées), ni documentées automatiquement.\n\nMais vous pouvez toujours les documenter comme décrit dans [Réponses supplémentaires dans OpenAPI](additional-responses.md).\n\nVous pouvez voir dans les sections suivantes comment utiliser/déclarer ces `Response` personnalisées tout en conservant la conversion automatique des données, la documentation, etc.\n"
  },
  {
    "path": "docs/fr/docs/advanced/response-headers.md",
    "content": "# En-têtes de réponse { #response-headers }\n\n## Utiliser un paramètre `Response` { #use-a-response-parameter }\n\nVous pouvez déclarer un paramètre de type `Response` dans votre fonction de chemin d'accès (comme vous pouvez le faire pour les cookies).\n\nVous pouvez ensuite définir des en-têtes dans cet objet de réponse temporaire.\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\nEnsuite, vous pouvez renvoyer n'importe quel objet dont vous avez besoin, comme d'habitude (un `dict`, un modèle de base de données, etc.).\n\nEt si vous avez déclaré un `response_model`, il sera toujours utilisé pour filtrer et convertir l'objet que vous avez renvoyé.\n\n**FastAPI** utilisera cette réponse temporaire pour extraire les en-têtes (ainsi que les cookies et le code de statut), et les placera dans la réponse finale qui contient la valeur que vous avez renvoyée, filtrée par tout `response_model`.\n\nVous pouvez également déclarer le paramètre `Response` dans des dépendances, et y définir des en-têtes (et des cookies).\n\n## Renvoyer une `Response` directement { #return-a-response-directly }\n\nVous pouvez également ajouter des en-têtes lorsque vous renvoyez une `Response` directement.\n\nCréez une réponse comme décrit dans [Renvoyer une Response directement](response-directly.md) et passez les en-têtes comme paramètre supplémentaire :\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | Détails techniques\n\nVous pouvez également utiliser `from starlette.responses import Response` ou `from starlette.responses import JSONResponse`.\n\n**FastAPI** fournit les mêmes `starlette.responses` sous `fastapi.responses` simplement pour votre commodité, en tant que développeur. Mais la plupart des réponses disponibles viennent directement de Starlette.\n\nEt comme `Response` peut être utilisée fréquemment pour définir des en-têtes et des cookies, **FastAPI** la fournit aussi via `fastapi.Response`.\n\n///\n\n## En-têtes personnalisés { #custom-headers }\n\nGardez à l'esprit que des en-têtes propriétaires personnalisés peuvent être ajoutés [en utilisant le préfixe `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nMais si vous avez des en-têtes personnalisés que vous voulez qu'un client dans un navigateur puisse voir, vous devez les ajouter à vos configurations CORS (en savoir plus dans [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), en utilisant le paramètre `expose_headers` documenté dans [la documentation CORS de Starlette](https://www.starlette.dev/middleware/#corsmiddleware).\n"
  },
  {
    "path": "docs/fr/docs/advanced/security/http-basic-auth.md",
    "content": "# Authentification HTTP Basic { #http-basic-auth }\n\nPour les cas les plus simples, vous pouvez utiliser l'authentification HTTP Basic.\n\nAvec l'authentification HTTP Basic, l'application attend un en-tête contenant un nom d'utilisateur et un mot de passe.\n\nSi elle ne le reçoit pas, elle renvoie une erreur HTTP 401 « Unauthorized ».\n\nEt elle renvoie un en-tête `WWW-Authenticate` avec la valeur `Basic`, et un paramètre optionnel `realm`.\n\nCela indique au navigateur d'afficher l'invite intégrée pour saisir un nom d'utilisateur et un mot de passe.\n\nEnsuite, lorsque vous saisissez ce nom d'utilisateur et ce mot de passe, le navigateur les envoie automatiquement dans l'en-tête.\n\n## Authentification HTTP Basic simple { #simple-http-basic-auth }\n\n- Importer `HTTPBasic` et `HTTPBasicCredentials`.\n- Créer un « schéma de sécurité » en utilisant `HTTPBasic`.\n- Utiliser ce `security` avec une dépendance dans votre chemin d'accès.\n- Cela renvoie un objet de type `HTTPBasicCredentials` :\n    - Il contient le `username` et le `password` envoyés.\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\nLorsque vous essayez d'ouvrir l'URL pour la première fois (ou cliquez sur le bouton « Execute » dans les documents) le navigateur vous demandera votre nom d'utilisateur et votre mot de passe :\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## Vérifier le nom d'utilisateur { #check-the-username }\n\nVoici un exemple plus complet.\n\nUtilisez une dépendance pour vérifier si le nom d'utilisateur et le mot de passe sont corrects.\n\nPour cela, utilisez le module standard Python [`secrets`](https://docs.python.org/3/library/secrets.html) pour vérifier le nom d'utilisateur et le mot de passe.\n\n`secrets.compare_digest()` doit recevoir des `bytes` ou une `str` ne contenant que des caractères ASCII (ceux de l'anglais), ce qui signifie qu'elle ne fonctionnerait pas avec des caractères comme `á`, comme dans `Sebastián`.\n\nPour gérer cela, nous convertissons d'abord `username` et `password` en `bytes` en les encodant en UTF-8.\n\nNous pouvons ensuite utiliser `secrets.compare_digest()` pour vérifier que `credentials.username` est « stanleyjobson » et que `credentials.password` est « swordfish ».\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\nCela serait équivalent à :\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # Renvoyer une erreur\n    ...\n```\n\nMais en utilisant `secrets.compare_digest()`, cela sera sécurisé contre un type d'attaques appelé « attaques par chronométrage ».\n\n### Attaques par chronométrage { #timing-attacks }\n\nMais qu'est-ce qu'une « attaque par chronométrage » ?\n\nImaginons que des attaquants essaient de deviner le nom d'utilisateur et le mot de passe.\n\nIls envoient alors une requête avec un nom d'utilisateur `johndoe` et un mot de passe `love123`.\n\nLe code Python de votre application serait alors équivalent à quelque chose comme :\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nMais au moment où Python compare le premier `j` de `johndoe` au premier `s` de `stanleyjobson`, il retournera `False`, car il sait déjà que ces deux chaînes ne sont pas identiques, en se disant qu'« il n'est pas nécessaire de gaspiller plus de calcul pour comparer le reste des lettres ». Et votre application dira « Nom d'utilisateur ou mot de passe incorrect ».\n\nMais ensuite, les attaquants essaient avec le nom d'utilisateur `stanleyjobsox` et le mot de passe `love123`.\n\nEt le code de votre application fait quelque chose comme :\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nPython devra comparer tout `stanleyjobso` dans `stanleyjobsox` et `stanleyjobson` avant de réaliser que les deux chaînes ne sont pas identiques. Cela prendra donc quelques microsecondes supplémentaires pour répondre « Nom d'utilisateur ou mot de passe incorrect ».\n\n#### Le temps de réponse aide les attaquants { #the-time-to-answer-helps-the-attackers }\n\nÀ ce stade, en remarquant que le serveur a mis quelques microsecondes de plus à envoyer la réponse « Nom d'utilisateur ou mot de passe incorrect », les attaquants sauront qu'ils ont trouvé quelque chose de juste : certaines des premières lettres étaient correctes.\n\nIls peuvent alors réessayer en sachant que c'est probablement quelque chose de plus proche de `stanleyjobsox` que de `johndoe`.\n\n#### Une attaque « professionnelle » { #a-professional-attack }\n\nBien sûr, les attaquants n'essaieraient pas tout cela à la main ; ils écriraient un programme pour le faire, avec éventuellement des milliers ou des millions de tests par seconde. Ils obtiendraient une lettre correcte supplémentaire à la fois.\n\nCe faisant, en quelques minutes ou heures, les attaquants devineraient le nom d'utilisateur et le mot de passe corrects, avec « l'aide » de notre application, simplement en se basant sur le temps de réponse.\n\n#### Corrigez-le avec `secrets.compare_digest()` { #fix-it-with-secrets-compare-digest }\n\nMais dans notre code nous utilisons justement `secrets.compare_digest()`.\n\nEn bref, il faudra le même temps pour comparer `stanleyjobsox` à `stanleyjobson` que pour comparer `johndoe` à `stanleyjobson`. Il en va de même pour le mot de passe.\n\nAinsi, en utilisant `secrets.compare_digest()` dans le code de votre application, votre application sera protégée contre toute cette gamme d'attaques de sécurité.\n\n### Renvoyer l'erreur { #return-the-error }\n\nAprès avoir détecté que les identifiants sont incorrects, renvoyez une `HTTPException` avec un code d'état 401 (le même que lorsque aucun identifiant n'est fourni) et ajoutez l'en-tête `WWW-Authenticate` pour que le navigateur affiche à nouveau l'invite de connexion :\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/fr/docs/advanced/security/index.md",
    "content": "# Sécurité avancée { #advanced-security }\n\n## Fonctionnalités supplémentaires { #additional-features }\n\nIl existe des fonctionnalités supplémentaires pour gérer la sécurité en plus de celles couvertes dans le [Tutoriel - Guide utilisateur : Sécurité](../../tutorial/security/index.md).\n\n/// tip | Astuce\n\nLes sections suivantes **ne sont pas nécessairement « advanced »**.\n\nEt il est possible que, pour votre cas d’utilisation, la solution se trouve dans l’une d’entre elles.\n\n///\n\n## Lire d’abord le tutoriel { #read-the-tutorial-first }\n\nLes sections suivantes partent du principe que vous avez déjà lu le [Tutoriel - Guide utilisateur : Sécurité](../../tutorial/security/index.md) principal.\n\nElles s’appuient toutes sur les mêmes concepts, mais permettent des fonctionnalités supplémentaires.\n"
  },
  {
    "path": "docs/fr/docs/advanced/security/oauth2-scopes.md",
    "content": "# Scopes OAuth2 { #oauth2-scopes }\n\nVous pouvez utiliser des scopes OAuth2 directement avec **FastAPI**, ils sont intégrés pour fonctionner de manière transparente.\n\nCela vous permettrait d’avoir un système d’autorisations plus fin, conforme au standard OAuth2, intégré à votre application OpenAPI (et à la documentation de l’API).\n\nOAuth2 avec scopes est le mécanisme utilisé par de nombreux grands fournisseurs d’authentification, comme Facebook, Google, GitHub, Microsoft, X (Twitter), etc. Ils l’utilisent pour fournir des permissions spécifiques aux utilisateurs et aux applications.\n\nChaque fois que vous « log in with » Facebook, Google, GitHub, Microsoft, X (Twitter), cette application utilise OAuth2 avec scopes.\n\nDans cette section, vous verrez comment gérer l’authentification et l’autorisation avec le même OAuth2 avec scopes dans votre application **FastAPI**.\n\n/// warning | Alertes\n\nC’est une section plus ou moins avancée. Si vous débutez, vous pouvez la passer.\n\nVous n’avez pas nécessairement besoin des scopes OAuth2, et vous pouvez gérer l’authentification et l’autorisation comme vous le souhaitez.\n\nMais OAuth2 avec scopes peut s’intégrer élégamment à votre API (avec OpenAPI) et à votre documentation d’API.\n\nNéanmoins, c’est toujours à vous de faire appliquer ces scopes, ou toute autre exigence de sécurité/autorisation, selon vos besoins, dans votre code.\n\nDans de nombreux cas, OAuth2 avec scopes peut être excessif.\n\nMais si vous savez que vous en avez besoin, ou si vous êtes curieux, continuez à lire.\n\n///\n\n## Scopes OAuth2 et OpenAPI { #oauth2-scopes-and-openapi }\n\nLa spécification OAuth2 définit des « scopes » comme une liste de chaînes séparées par des espaces.\n\nLe contenu de chacune de ces chaînes peut avoir n’importe quel format, mais ne doit pas contenir d’espaces.\n\nCes scopes représentent des « permissions ».\n\nDans OpenAPI (par ex. la documentation de l’API), vous pouvez définir des « schémas de sécurité ».\n\nLorsqu’un de ces schémas de sécurité utilise OAuth2, vous pouvez aussi déclarer et utiliser des scopes.\n\nChaque « scope » est juste une chaîne (sans espaces).\n\nIls sont généralement utilisés pour déclarer des permissions de sécurité spécifiques, par exemple :\n\n* `users:read` ou `users:write` sont des exemples courants.\n* `instagram_basic` est utilisé par Facebook / Instagram.\n* `https://www.googleapis.com/auth/drive` est utilisé par Google.\n\n/// info\n\nDans OAuth2, un « scope » est simplement une chaîne qui déclare une permission spécifique requise.\n\nPeu importe s’il contient d’autres caractères comme `:` ou si c’est une URL.\n\nCes détails dépendent de l’implémentation.\n\nPour OAuth2, ce ne sont que des chaînes.\n\n///\n\n## Vue d’ensemble { #global-view }\n\nVoyons d’abord rapidement les parties qui changent par rapport aux exemples du **Tutoriel - Guide utilisateur** pour [OAuth2 avec mot de passe (et hachage), Bearer avec jetons JWT](../../tutorial/security/oauth2-jwt.md). Cette fois, en utilisant des scopes OAuth2 :\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\nPassons maintenant en revue ces changements étape par étape.\n\n## Déclarer le schéma de sécurité OAuth2 { #oauth2-security-scheme }\n\nLe premier changement est que nous déclarons maintenant le schéma de sécurité OAuth2 avec deux scopes disponibles, `me` et `items`.\n\nLe paramètre `scopes` reçoit un `dict` avec chaque scope en clé et la description en valeur :\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\nComme nous déclarons maintenant ces scopes, ils apparaîtront dans la documentation de l’API lorsque vous vous authentifiez/autorisez.\n\nEt vous pourrez sélectionner à quels scopes vous souhaitez accorder l’accès : `me` et `items`.\n\nC’est le même mécanisme utilisé lorsque vous donnez des permissions en vous connectant avec Facebook, Google, GitHub, etc. :\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## Jeton JWT avec scopes { #jwt-token-with-scopes }\n\nModifiez maintenant le *chemin d’accès* du jeton pour renvoyer les scopes demandés.\n\nNous utilisons toujours le même `OAuth2PasswordRequestForm`. Il inclut une propriété `scopes` avec une `list` de `str`, contenant chaque scope reçu dans la requête.\n\nEt nous renvoyons les scopes comme partie du jeton JWT.\n\n/// danger | Danger\n\nPour simplifier, ici nous ajoutons directement au jeton les scopes reçus.\n\nMais dans votre application, pour la sécurité, vous devez vous assurer de n’ajouter que les scopes que l’utilisateur est réellement autorisé à avoir, ou ceux que vous avez prédéfinis.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## Déclarer des scopes dans les chemins d’accès et les dépendances { #declare-scopes-in-path-operations-and-dependencies }\n\nNous déclarons maintenant que le *chemin d’accès* `/users/me/items/` nécessite le scope `items`.\n\nPour cela, nous importons et utilisons `Security` depuis `fastapi`.\n\nVous pouvez utiliser `Security` pour déclarer des dépendances (comme `Depends`), mais `Security` reçoit aussi un paramètre `scopes` avec une liste de scopes (chaînes).\n\nDans ce cas, nous passons une fonction de dépendance `get_current_active_user` à `Security` (de la même manière que nous le ferions avec `Depends`).\n\nMais nous passons aussi une `list` de scopes, ici avec un seul scope : `items` (il pourrait y en avoir plus).\n\nEt la fonction de dépendance `get_current_active_user` peut également déclarer des sous-dépendances, non seulement avec `Depends` mais aussi avec `Security`. En déclarant sa propre fonction de sous-dépendance (`get_current_user`), et davantage d’exigences de scopes.\n\nDans ce cas, elle nécessite le scope `me` (elle pourrait en exiger plusieurs).\n\n/// note | Remarque\n\nVous n’avez pas nécessairement besoin d’ajouter des scopes différents à différents endroits.\n\nNous le faisons ici pour montrer comment **FastAPI** gère des scopes déclarés à différents niveaux.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | Détails techniques\n\n`Security` est en réalité une sous-classe de `Depends`, et elle n’a qu’un paramètre supplémentaire que nous verrons plus tard.\n\nMais en utilisant `Security` au lieu de `Depends`, **FastAPI** saura qu’il peut déclarer des scopes de sécurité, les utiliser en interne et documenter l’API avec OpenAPI.\n\nCependant, lorsque vous importez `Query`, `Path`, `Depends`, `Security` et d’autres depuis `fastapi`, ce sont en fait des fonctions qui renvoient des classes spéciales.\n\n///\n\n## Utiliser `SecurityScopes` { #use-securityscopes }\n\nMettez maintenant à jour la dépendance `get_current_user`.\n\nC’est celle utilisée par les dépendances ci-dessus.\n\nC’est ici que nous utilisons le même schéma OAuth2 que nous avons créé auparavant, en le déclarant comme dépendance : `oauth2_scheme`.\n\nComme cette fonction de dépendance n’a pas elle-même d’exigences de scope, nous pouvons utiliser `Depends` avec `oauth2_scheme`, nous n’avons pas à utiliser `Security` quand nous n’avons pas besoin de spécifier des scopes de sécurité.\n\nNous déclarons également un paramètre spécial de type `SecurityScopes`, importé de `fastapi.security`.\n\nCette classe `SecurityScopes` est similaire à `Request` (`Request` servait à obtenir directement l’objet requête).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## Utiliser les `scopes` { #use-the-scopes }\n\nLe paramètre `security_scopes` sera de type `SecurityScopes`.\n\nIl aura une propriété `scopes` avec une liste contenant tous les scopes requis par lui-même et par toutes les dépendances qui l’utilisent comme sous-dépendance. Cela signifie, tous les « dépendants » ... cela peut paraître déroutant, c’est expliqué à nouveau plus bas.\n\nL’objet `security_scopes` (de classe `SecurityScopes`) fournit aussi un attribut `scope_str` avec une chaîne unique, contenant ces scopes séparés par des espaces (nous allons l’utiliser).\n\nNous créons une `HTTPException` que nous pouvons réutiliser (`raise`) plus tard à plusieurs endroits.\n\nDans cette exception, nous incluons les scopes requis (le cas échéant) sous forme de chaîne séparée par des espaces (en utilisant `scope_str`). Nous plaçons cette chaîne contenant les scopes dans l’en-tête `WWW-Authenticate` (cela fait partie de la spécification).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## Vérifier le `username` et la structure des données { #verify-the-username-and-data-shape }\n\nNous vérifions que nous obtenons un `username`, et extrayons les scopes.\n\nNous validons ensuite ces données avec le modèle Pydantic (en capturant l’exception `ValidationError`), et si nous obtenons une erreur lors de la lecture du jeton JWT ou de la validation des données avec Pydantic, nous levons la `HTTPException` que nous avons créée auparavant.\n\nPour cela, nous mettons à jour le modèle Pydantic `TokenData` avec une nouvelle propriété `scopes`.\n\nEn validant les données avec Pydantic, nous pouvons nous assurer que nous avons, par exemple, exactement une `list` de `str` pour les scopes et un `str` pour le `username`.\n\nAu lieu, par exemple, d’un `dict`, ou autre chose, ce qui pourrait casser l’application plus tard et constituer un risque de sécurité.\n\nNous vérifions également que nous avons un utilisateur avec ce nom d’utilisateur, et sinon, nous levons la même exception que précédemment.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## Vérifier les `scopes` { #verify-the-scopes }\n\nNous vérifions maintenant que tous les scopes requis, par cette dépendance et tous les dépendants (y compris les *chemins d’accès*), sont inclus dans les scopes fournis dans le jeton reçu, sinon nous levons une `HTTPException`.\n\nPour cela, nous utilisons `security_scopes.scopes`, qui contient une `list` avec tous ces scopes en `str`.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## Arbre de dépendances et scopes { #dependency-tree-and-scopes }\n\nRevoyons encore cet arbre de dépendances et les scopes.\n\nComme la dépendance `get_current_active_user` a une sous-dépendance `get_current_user`, le scope « me » déclaré dans `get_current_active_user` sera inclus dans la liste des scopes requis dans `security_scopes.scopes` passé à `get_current_user`.\n\nLe *chemin d’accès* lui-même déclare également un scope, « items », il sera donc aussi présent dans la liste `security_scopes.scopes` passée à `get_current_user`.\n\nVoici à quoi ressemble la hiérarchie des dépendances et des scopes :\n\n* Le *chemin d’accès* `read_own_items` a :\n    * Des scopes requis `[\"items\"]` avec la dépendance :\n    * `get_current_active_user` :\n        * La fonction de dépendance `get_current_active_user` a :\n            * Des scopes requis `[\"me\"]` avec la dépendance :\n            * `get_current_user` :\n                * La fonction de dépendance `get_current_user` a :\n                    * Aucun scope requis par elle-même.\n                    * Une dépendance utilisant `oauth2_scheme`.\n                    * Un paramètre `security_scopes` de type `SecurityScopes` :\n                        * Ce paramètre `security_scopes` a une propriété `scopes` avec une `list` contenant tous les scopes déclarés ci-dessus, donc :\n                            * `security_scopes.scopes` contiendra `[\"me\", \"items\"]` pour le *chemin d’accès* `read_own_items`.\n                            * `security_scopes.scopes` contiendra `[\"me\"]` pour le *chemin d’accès* `read_users_me`, car il est déclaré dans la dépendance `get_current_active_user`.\n                            * `security_scopes.scopes` contiendra `[]` (rien) pour le *chemin d’accès* `read_system_status`, car il n’a déclaré aucun `Security` avec des `scopes`, et sa dépendance, `get_current_user`, ne déclare pas non plus de `scopes`.\n\n/// tip | Astuce\n\nL’élément important et « magique » ici est que `get_current_user` aura une liste différente de `scopes` à vérifier pour chaque *chemin d’accès*.\n\nTout dépend des `scopes` déclarés dans chaque *chemin d’accès* et chaque dépendance dans l’arbre de dépendances pour ce *chemin d’accès* spécifique.\n\n///\n\n## Détails supplémentaires sur `SecurityScopes` { #more-details-about-securityscopes }\n\nVous pouvez utiliser `SecurityScopes` à n’importe quel endroit, et à de multiples endroits, il n’a pas besoin d’être dans la dépendance « root ».\n\nIl aura toujours les scopes de sécurité déclarés dans les dépendances `Security` actuelles et tous les dépendants pour **ce** *chemin d’accès* spécifique et **cet** arbre de dépendances spécifique.\n\nComme `SecurityScopes` contient tous les scopes déclarés par les dépendants, vous pouvez l’utiliser pour vérifier qu’un jeton possède les scopes requis dans une fonction de dépendance centrale, puis déclarer des exigences de scopes différentes dans différents *chemins d’accès*.\n\nElles seront vérifiées indépendamment pour chaque *chemin d’accès*.\n\n## Tester { #check-it }\n\nSi vous ouvrez la documentation de l’API, vous pouvez vous authentifier et spécifier quels scopes vous voulez autoriser.\n\n<img src=\"/img/tutorial/security/image11.png\">\n\nSi vous ne sélectionnez aucun scope, vous serez « authenticated », mais lorsque vous essayerez d’accéder à `/users/me/` ou `/users/me/items/`, vous obtiendrez une erreur indiquant que vous n’avez pas suffisamment de permissions. Vous pourrez toujours accéder à `/status/`.\n\nEt si vous sélectionnez le scope `me` mais pas le scope `items`, vous pourrez accéder à `/users/me/` mais pas à `/users/me/items/`.\n\nC’est ce qui arriverait à une application tierce qui tenterait d’accéder à l’un de ces *chemins d’accès* avec un jeton fourni par un utilisateur, selon le nombre de permissions que l’utilisateur a accordées à l’application.\n\n## À propos des intégrations tierces { #about-third-party-integrations }\n\nDans cet exemple, nous utilisons le flux OAuth2 « password ».\n\nC’est approprié lorsque nous nous connectons à notre propre application, probablement avec notre propre frontend.\n\nParce que nous pouvons lui faire confiance pour recevoir le `username` et le `password`, puisque nous le contrôlons.\n\nMais si vous construisez une application OAuth2 à laquelle d’autres se connecteraient (c.-à-d., si vous construisez un fournisseur d’authentification équivalent à Facebook, Google, GitHub, etc.), vous devez utiliser l’un des autres flux.\n\nLe plus courant est le flux implicite.\n\nLe plus sûr est le flux « code », mais il est plus complexe à implémenter car il nécessite plus d’étapes. Comme il est plus complexe, de nombreux fournisseurs finissent par recommander le flux implicite.\n\n/// note | Remarque\n\nIl est courant que chaque fournisseur d’authentification nomme ses flux différemment, pour en faire une partie de sa marque.\n\nMais au final, ils implémentent le même standard OAuth2.\n\n///\n\n**FastAPI** inclut des utilitaires pour tous ces flux d’authentification OAuth2 dans `fastapi.security.oauth2`.\n\n## `Security` dans les dépendances du décorateur `dependencies` { #security-in-decorator-dependencies }\n\nDe la même manière que vous pouvez définir une `list` de `Depends` dans le paramètre `dependencies` du décorateur (comme expliqué dans [Dépendances dans les décorateurs de chemins d’accès](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)), vous pouvez aussi utiliser `Security` avec des `scopes` à cet endroit.\n"
  },
  {
    "path": "docs/fr/docs/advanced/settings.md",
    "content": "# Paramètres et variables d'environnement { #settings-and-environment-variables }\n\nDans de nombreux cas, votre application peut avoir besoin de paramètres ou de configurations externes, par exemple des clés secrètes, des identifiants de base de données, des identifiants pour des services d'e-mail, etc.\n\nLa plupart de ces paramètres sont variables (peuvent changer), comme les URL de base de données. Et beaucoup peuvent être sensibles, comme les secrets.\n\nC'est pourquoi il est courant de les fournir via des variables d'environnement lues par l'application.\n\n/// tip | Astuce\n\nPour comprendre les variables d'environnement, vous pouvez lire [Variables d'environnement](../environment-variables.md).\n\n///\n\n## Types et validation { #types-and-validation }\n\nCes variables d'environnement ne gèrent que des chaînes de texte, car elles sont externes à Python et doivent être compatibles avec d'autres programmes et le reste du système (et même avec différents systèmes d'exploitation, comme Linux, Windows, macOS).\n\nCela signifie que toute valeur lue en Python depuis une variable d'environnement sera une `str`, et toute conversion vers un autre type ou toute validation doit être effectuée dans le code.\n\n## Pydantic `Settings` { #pydantic-settings }\n\nHeureusement, Pydantic fournit un excellent utilitaire pour gérer ces paramètres provenant des variables d'environnement avec [Pydantic : gestion des paramètres](https://docs.pydantic.dev/latest/concepts/pydantic_settings/).\n\n### Installer `pydantic-settings` { #install-pydantic-settings }\n\nD'abord, vous devez créer votre [environnement virtuel](../virtual-environments.md), l'activer, puis installer le paquet `pydantic-settings` :\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\nIl est également inclus lorsque vous installez les extras `all` avec :\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### Créer l'objet `Settings` { #create-the-settings-object }\n\nImportez `BaseSettings` depuis Pydantic et créez une sous-classe, comme pour un modèle Pydantic.\n\nDe la même manière qu'avec les modèles Pydantic, vous déclarez des attributs de classe avec des annotations de type, et éventuellement des valeurs par défaut.\n\nVous pouvez utiliser toutes les mêmes fonctionnalités et outils de validation que pour les modèles Pydantic, comme différents types de données et des validations supplémentaires avec `Field()`.\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip | Astuce\n\nSi vous voulez quelque chose à copier-coller rapidement, n'utilisez pas cet exemple, utilisez le dernier ci-dessous.\n\n///\n\nEnsuite, lorsque vous créez une instance de cette classe `Settings` (dans ce cas, l'objet `settings`), Pydantic lira les variables d'environnement de manière insensible à la casse, donc une variable en majuscules `APP_NAME` sera tout de même lue pour l'attribut `app_name`.\n\nIl convertira ensuite et validera les données. Ainsi, lorsque vous utilisez cet objet `settings`, vous aurez des données des types que vous avez déclarés (par exemple, `items_per_user` sera un `int`).\n\n### Utiliser `settings` { #use-the-settings }\n\nVous pouvez ensuite utiliser le nouvel objet `settings` dans votre application :\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### Exécuter le serveur { #run-the-server }\n\nEnsuite, vous exécutez le serveur en passant les configurations comme variables d'environnement ; par exemple, vous pouvez définir un `ADMIN_EMAIL` et `APP_NAME` avec :\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip | Astuce\n\nPour définir plusieurs variables d'environnement pour une seule commande, séparez-les simplement par un espace et placez-les toutes avant la commande.\n\n///\n\nAinsi, le paramètre `admin_email` sera défini sur « deadpool@example.com ».\n\nLe `app_name` sera « ChimichangApp ».\n\nEt `items_per_user` conservera sa valeur par défaut de `50`.\n\n## Paramètres dans un autre module { #settings-in-another-module }\n\nVous pouvez placer ces paramètres dans un autre module comme vous l'avez vu dans [Applications plus grandes - Plusieurs fichiers](../tutorial/bigger-applications.md).\n\nPar exemple, vous pourriez avoir un fichier `config.py` avec :\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\nPuis l'utiliser dans un fichier `main.py` :\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip | Astuce\n\nVous aurez également besoin d'un fichier `__init__.py` comme vous l'avez vu dans [Applications plus grandes - Plusieurs fichiers](../tutorial/bigger-applications.md).\n\n///\n\n## Paramètres dans une dépendance { #settings-in-a-dependency }\n\nDans certains cas, il peut être utile de fournir les paramètres via une dépendance, au lieu d'avoir un objet global `settings` utilisé partout.\n\nCela peut être particulièrement utile pendant les tests, car il est très facile de surcharger une dépendance avec vos propres paramètres personnalisés.\n\n### Le fichier de configuration { #the-config-file }\n\nEn repartant de l'exemple précédent, votre fichier `config.py` pourrait ressembler à :\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\nNotez que maintenant, nous ne créons pas d'instance par défaut `settings = Settings()`.\n\n### Le fichier principal de l'application { #the-main-app-file }\n\nNous créons maintenant une dépendance qui renvoie un nouveau `config.Settings()`.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip | Astuce\n\nNous parlerons de `@lru_cache` dans un instant.\n\nPour l'instant, vous pouvez supposer que `get_settings()` est une fonction normale.\n\n///\n\nNous pouvons ensuite l'exiger depuis la fonction de chemin d'accès comme dépendance et l'utiliser où nous en avons besoin.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### Paramètres et tests { #settings-and-testing }\n\nIl devient alors très simple de fournir un autre objet de paramètres pendant les tests en créant une surcharge de dépendance pour `get_settings` :\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\nDans la surcharge de dépendance, nous définissons une nouvelle valeur pour `admin_email` lors de la création du nouvel objet `Settings`, puis nous renvoyons ce nouvel objet.\n\nNous pouvons ensuite tester qu'il est bien utilisé.\n\n## Lire un fichier `.env` { #reading-a-env-file }\n\nSi vous avez de nombreux paramètres susceptibles de beaucoup changer, peut-être selon les environnements, il peut être utile de les placer dans un fichier, puis de les lire comme s'il s'agissait de variables d'environnement.\n\nCette pratique est suffisamment courante pour avoir un nom ; ces variables d'environnement sont fréquemment placées dans un fichier `.env`, et le fichier est appelé un « dotenv ».\n\n/// tip | Astuce\n\nUn fichier commençant par un point (`.`) est un fichier caché dans les systèmes de type Unix, comme Linux et macOS.\n\nMais un fichier dotenv n'a pas forcément exactement ce nom de fichier.\n\n///\n\nPydantic prend en charge la lecture depuis ce type de fichiers en utilisant une bibliothèque externe. Vous pouvez en lire davantage ici : [Pydantic Settings : prise en charge de Dotenv (.env)](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support).\n\n/// tip | Astuce\n\nPour que cela fonctionne, vous devez exécuter `pip install python-dotenv`.\n\n///\n\n### Le fichier `.env` { #the-env-file }\n\nVous pouvez avoir un fichier `.env` avec :\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### Lire les paramètres depuis `.env` { #read-settings-from-env }\n\nPuis mettre à jour votre `config.py` avec :\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip | Astuce\n\nL'attribut `model_config` est utilisé uniquement pour la configuration Pydantic. Vous pouvez en lire davantage ici : [Pydantic : Concepts : Configuration](https://docs.pydantic.dev/latest/concepts/config/).\n\n///\n\nIci, nous définissons la configuration `env_file` à l'intérieur de votre classe Pydantic `Settings` et lui attribuons le nom du fichier dotenv que nous voulons utiliser.\n\n### Créer `Settings` une seule fois avec `lru_cache` { #creating-the-settings-only-once-with-lru-cache }\n\nLire un fichier depuis le disque est normalement une opération coûteuse (lente), vous voudrez donc probablement le faire une seule fois puis réutiliser le même objet de paramètres, au lieu de le lire à chaque requête.\n\nMais chaque fois que nous faisons :\n\n```Python\nSettings()\n```\n\nun nouvel objet `Settings` serait créé, et à sa création il lirait à nouveau le fichier `.env`.\n\nSi la fonction de dépendance était simplement :\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\nnous créerions cet objet pour chaque requête, et nous lirions le fichier `.env` pour chaque requête. ⚠️\n\nMais comme nous utilisons le décorateur `@lru_cache` au-dessus, l'objet `Settings` sera créé une seule fois, la première fois qu'il est appelé. ✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\nEnsuite, pour tout appel ultérieur de `get_settings()` dans les dépendances pour les requêtes suivantes, au lieu d'exécuter le code interne de `get_settings()` et de créer un nouvel objet `Settings`, il renverra le même objet que celui retourné au premier appel, encore et encore.\n\n#### Détails techniques de `lru_cache` { #lru-cache-technical-details }\n\n`@lru_cache` modifie la fonction qu'il décore pour renvoyer la même valeur que celle qui a été retournée la première fois, au lieu de la recalculer en exécutant le code de la fonction à chaque fois.\n\nAinsi, la fonction située en dessous sera exécutée une fois pour chaque combinaison d'arguments. Ensuite, les valeurs renvoyées par chacune de ces combinaisons d'arguments seront réutilisées à chaque fois que la fonction sera appelée avec exactement la même combinaison d'arguments.\n\nPar exemple, si vous avez une fonction :\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\nvotre programme pourrait s'exécuter comme ceci :\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Execute function\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n```\n\nDans le cas de notre dépendance `get_settings()`, la fonction ne prend même aucun argument, elle renvoie donc toujours la même valeur.\n\nDe cette façon, elle se comporte presque comme s'il s'agissait simplement d'une variable globale. Mais comme elle utilise une fonction de dépendance, nous pouvons alors la surcharger facilement pour les tests.\n\n`@lru_cache` fait partie de `functools` qui fait partie de la bibliothèque standard de Python, vous pouvez en lire davantage dans la [documentation Python pour `@lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache).\n\n## Récapitulatif { #recap }\n\nVous pouvez utiliser Pydantic Settings pour gérer les paramètres ou configurations de votre application, avec toute la puissance des modèles Pydantic.\n\n* En utilisant une dépendance, vous pouvez simplifier les tests.\n* Vous pouvez utiliser des fichiers `.env`.\n* Utiliser `@lru_cache` vous permet d'éviter de relire le fichier dotenv à chaque requête, tout en vous permettant de le surcharger pendant les tests.\n"
  },
  {
    "path": "docs/fr/docs/advanced/stream-data.md",
    "content": "# Diffuser des données { #stream-data }\n\nSi vous voulez diffuser des données pouvant être structurées en JSON, vous devez [Diffuser des JSON Lines](../tutorial/stream-json-lines.md).\n\nMais si vous voulez diffuser des données binaires pures ou des chaînes, voici comment procéder.\n\n/// info\n\nAjouté dans FastAPI 0.134.0.\n\n///\n\n## Cas d'utilisation { #use-cases }\n\nVous pouvez l'utiliser si vous souhaitez diffuser des chaînes pures, par exemple directement depuis la sortie d'un service d'**IA LLM**.\n\nVous pouvez également l'utiliser pour diffuser de gros fichiers binaires, en envoyant chaque bloc de données au fur et à mesure de la lecture, sans tout charger en mémoire d'un coup.\n\nVous pouvez aussi diffuser de la **vidéo** ou de l'**audio** de cette manière ; cela peut même être généré au fil du traitement et de l'envoi.\n\n## Utiliser une `StreamingResponse` avec `yield` { #a-streamingresponse-with-yield }\n\nSi vous déclarez un `response_class=StreamingResponse` dans votre *fonction de chemin d'accès*, vous pouvez utiliser `yield` pour envoyer chaque bloc de données à son tour.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI transmettra chaque bloc de données à la `StreamingResponse` tel quel ; il n'essaiera pas de le convertir en JSON ni autre chose similaire.\n\n### Fonctions de chemin d'accès non async { #non-async-path-operation-functions }\n\nVous pouvez également utiliser des fonctions `def` classiques (sans `async`), et utiliser `yield` de la même manière.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### Sans annotation { #no-annotation }\n\nVous n'avez pas vraiment besoin de déclarer l'annotation de type de retour pour diffuser des données binaires.\n\nComme FastAPI n'essaiera pas de convertir les données en JSON avec Pydantic ni de les sérialiser, dans ce cas l'annotation de type ne sert qu'à votre éditeur et à vos outils ; elle ne sera pas utilisée par FastAPI.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\nCela signifie aussi qu'avec `StreamingResponse` vous avez la liberté — et la responsabilité — de produire et d'encoder les octets de données exactement comme vous avez besoin de les envoyer, indépendamment des annotations de type. 🤓\n\n### Diffuser des bytes { #stream-bytes }\n\nL'un des principaux cas d'usage consiste à diffuser des `bytes` au lieu de chaînes ; vous pouvez bien sûr le faire.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## Créer une `PNGStreamingResponse` personnalisée { #a-custom-pngstreamingresponse }\n\nDans les exemples ci-dessus, les octets de données étaient diffusés, mais la réponse n'avait pas d'en-tête `Content-Type`, le client ne savait donc pas quel type de données il recevait.\n\nVous pouvez créer une sous-classe personnalisée de `StreamingResponse` qui définit l'en-tête `Content-Type` sur le type de données que vous diffusez.\n\nPar exemple, vous pouvez créer une `PNGStreamingResponse` qui définit l'en-tête `Content-Type` à `image/png` en utilisant l'attribut `media_type` :\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\nVous pouvez ensuite utiliser cette nouvelle classe dans `response_class=PNGStreamingResponse` dans votre *fonction de chemin d'accès* :\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### Simuler un fichier { #simulate-a-file }\n\nDans cet exemple, nous simulons un fichier avec `io.BytesIO`, qui est un objet de type fichier résidant uniquement en mémoire, mais qui permet d'utiliser la même interface.\n\nPar exemple, nous pouvons itérer dessus pour en consommer le contenu, comme nous le ferions avec un fichier.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | Détails techniques\n\nLes deux autres variables, `image_base64` et `binary_image`, correspondent à une image encodée en Base64, puis convertie en bytes, afin de la passer à `io.BytesIO`.\n\nC'est uniquement pour que tout tienne dans le même fichier pour cet exemple, et que vous puissiez le copier et l'exécuter tel quel. 🥚\n\n///\n\nEn utilisant un bloc `with`, nous nous assurons que l'objet de type fichier est fermé après l'exécution de la fonction génératrice (la fonction avec `yield`). Donc, après la fin de l'envoi de la réponse.\n\nCe ne serait pas si important dans cet exemple précis, car il s'agit d'un faux fichier en mémoire (avec `io.BytesIO`), mais avec un vrai fichier, il est important de s'assurer qu'il est fermé une fois le travail terminé.\n\n### Gérer les fichiers et async { #files-and-async }\n\nDans la plupart des cas, les objets de type fichier ne sont pas compatibles avec `async` et `await` par défaut.\n\nPar exemple, ils n'ont pas de `await file.read()`, ni de `async for chunk in file`.\n\nEt dans de nombreux cas, leur lecture serait une opération bloquante (pouvant bloquer la boucle d'événements), car ils sont lus depuis le disque ou le réseau.\n\n/// info\n\nL'exemple ci-dessus est en réalité une exception, car l'objet `io.BytesIO` est déjà en mémoire ; sa lecture ne bloquera donc rien.\n\nMais dans de nombreux cas, la lecture d'un fichier ou d'un objet de type fichier bloquera.\n\n///\n\nPour éviter de bloquer la boucle d'événements, vous pouvez simplement déclarer la *fonction de chemin d'accès* avec un `def` classique au lieu de `async def`. Ainsi, FastAPI l'exécutera dans un worker de pool de threads, afin d'éviter de bloquer la boucle principale.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip | Astuce\n\nSi vous devez appeler du code bloquant depuis une fonction async, ou une fonction async depuis une fonction bloquante, vous pouvez utiliser [Asyncer](https://asyncer.tiangolo.com), une bibliothèque sœur de FastAPI.\n\n///\n\n### `yield from` { #yield-from }\n\nLorsque vous itérez sur quelque chose, comme un objet de type fichier, et que vous faites un `yield` pour chaque élément, vous pouvez aussi utiliser `yield from` pour émettre chaque élément directement et éviter la boucle `for`.\n\nCe n'est pas spécifique à FastAPI, c'est simplement Python, mais c'est une astuce utile à connaître. 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/fr/docs/advanced/strict-content-type.md",
    "content": "# Vérifier strictement le Content-Type { #strict-content-type-checking }\n\nPar défaut, FastAPI applique une vérification stricte de l’en-tête `Content-Type` pour les corps de requêtes JSON ; cela signifie que les requêtes JSON doivent inclure un en-tête `Content-Type` valide (par ex. `application/json`) pour que le corps soit analysé comme JSON.\n\n## Risque CSRF { #csrf-risk }\n\nCe comportement par défaut offre une protection contre une catégorie d’attaques de Cross-Site Request Forgery (CSRF) dans un scénario très spécifique.\n\nCes attaques exploitent le fait que les navigateurs permettent à des scripts d’envoyer des requêtes sans effectuer de pré-vérification CORS (preflight) lorsqu’ils :\n\n* n’ont pas d’en-tête `Content-Type` (par ex. en utilisant `fetch()` avec un corps `Blob`)\n* et n’envoient aucune information d’authentification.\n\nCe type d’attaque est surtout pertinent lorsque :\n\n* l’application s’exécute localement (par ex. sur `localhost`) ou sur un réseau interne\n* et l’application n’a aucun mécanisme d’authentification, elle part du principe que toute requête provenant du même réseau est fiable.\n\n## Exemple d’attaque { #example-attack }\n\nImaginez que vous mettiez au point un moyen d’exécuter un agent IA local.\n\nIl expose une API à l’adresse\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nIl y a aussi un frontend à l’adresse\n\n```\nhttp://localhost:8000\n```\n\n/// tip | Astuce\n\nNotez qu’ils ont le même hôte.\n\n///\n\nVous pouvez alors, via le frontend, amener l’agent IA à effectuer des actions en votre nom.\n\nComme il s’exécute localement, et non sur l’Internet ouvert, vous décidez de ne mettre en place aucun mécanisme d’authentification, en vous fiant simplement à l’accès au réseau local.\n\nUn de vos utilisateurs pourrait alors l’installer et l’exécuter localement.\n\nIl pourrait ensuite ouvrir un site malveillant, par exemple quelque chose comme\n\n```\nhttps://evilhackers.example.com\n```\n\nEt ce site malveillant enverrait des requêtes en utilisant `fetch()` avec un corps `Blob` vers l’API locale à l’adresse\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nMême si l’hôte du site malveillant et celui de l’application locale sont différents, le navigateur ne déclenchera pas de pré-vérification CORS (preflight) parce que :\n\n* Elle s’exécute sans aucune authentification, il n’y a pas à envoyer d’informations d’authentification.\n* Le navigateur pense qu’il n’envoie pas de JSON (faute d’en-tête `Content-Type`).\n\nLe site malveillant pourrait alors amener l’agent IA local à envoyer des messages en colère à l’ancien patron de l’utilisateur ... ou pire. 😅\n\n## Internet ouvert { #open-internet }\n\nSi votre application est exposée sur l’Internet ouvert, vous ne « ferez pas confiance au réseau » et ne laisserez pas n’importe qui envoyer des requêtes privilégiées sans authentification.\n\nDes attaquants pourraient simplement exécuter un script pour envoyer des requêtes à votre API, sans interaction avec le navigateur ; vous sécurisez donc probablement déjà tout endpoint privilégié.\n\nDans ce cas, cette attaque / ce risque ne vous concerne pas.\n\nCe risque et cette attaque sont surtout pertinents lorsque l’application s’exécute sur le réseau local et que c’est la seule protection supposée.\n\n## Autoriser les requêtes sans Content-Type { #allowing-requests-without-content-type }\n\nSi vous devez prendre en charge des clients qui n’envoient pas d’en-tête `Content-Type`, vous pouvez désactiver la vérification stricte en définissant `strict_content_type=False` :\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\nAvec ce paramètre, les requêtes sans en-tête `Content-Type` verront leur corps analysé comme JSON, ce qui correspond au comportement des anciennes versions de FastAPI.\n\n/// info\n\nCe comportement et cette configuration ont été ajoutés dans FastAPI 0.132.0.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/advanced/sub-applications.md",
    "content": "# Sous-applications - Montage { #sub-applications-mounts }\n\nSi vous avez besoin de deux applications FastAPI indépendantes, avec leur propre OpenAPI et leurs propres interfaces de la documentation, vous pouvez avoir une application principale et « monter » une (ou plusieurs) sous‑application(s).\n\n## Monter une application **FastAPI** { #mounting-a-fastapi-application }\n\n« Monter » signifie ajouter une application entièrement « indépendante » à un chemin spécifique, qui se chargera ensuite de tout gérer sous ce chemin, avec les _chemins d'accès_ déclarés dans cette sous‑application.\n\n### Application de premier niveau { #top-level-application }\n\nCréez d'abord l'application **FastAPI** principale (de premier niveau) et ses *chemins d'accès* :\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### Sous-application { #sub-application }\n\nEnsuite, créez votre sous‑application et ses *chemins d'accès*.\n\nCette sous‑application est simplement une autre application FastAPI standard, mais c'est celle qui sera « montée » :\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### Monter la sous-application { #mount-the-sub-application }\n\nDans votre application de premier niveau, `app`, montez la sous‑application, `subapi`.\n\nDans ce cas, elle sera montée au chemin `/subapi` :\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### Vérifier la documentation API automatique { #check-the-automatic-api-docs }\n\nExécutez maintenant la commande `fastapi` :\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nEt ouvrez la documentation à [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVous verrez la documentation API automatique pour l'application principale, n'incluant que ses propres _chemins d'accès_ :\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\nEnsuite, ouvrez la documentation de la sous‑application à [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs).\n\nVous verrez la documentation API automatique pour la sous‑application, n'incluant que ses propres _chemins d'accès_, tous sous le préfixe de sous‑chemin correct `/subapi` :\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\nSi vous essayez d'interagir avec l'une ou l'autre des deux interfaces, elles fonctionneront correctement, car le navigateur pourra communiquer avec chaque application ou sous‑application spécifique.\n\n### Détails techniques : `root_path` { #technical-details-root-path }\n\nLorsque vous montez une sous‑application comme ci‑dessus, FastAPI se charge de communiquer le chemin de montage à la sous‑application au moyen d'un mécanisme de la spécification ASGI appelé `root_path`.\n\nDe cette manière, la sous‑application saura utiliser ce préfixe de chemin pour l'interface de documentation.\n\nLa sous‑application peut également avoir ses propres sous‑applications montées et tout fonctionnera correctement, car FastAPI gère automatiquement tous ces `root_path`.\n\nVous en apprendrez davantage sur `root_path` et sur la façon de l'utiliser explicitement dans la section [Derrière un proxy](behind-a-proxy.md).\n"
  },
  {
    "path": "docs/fr/docs/advanced/templates.md",
    "content": "# Templates { #templates }\n\nVous pouvez utiliser n'importe quel moteur de templates avec **FastAPI**.\n\nUn choix courant est Jinja2, le même que celui utilisé par Flask et d'autres outils.\n\nIl existe des utilitaires pour le configurer facilement que vous pouvez utiliser directement dans votre application **FastAPI** (fournis par Starlette).\n\n## Installer les dépendances { #install-dependencies }\n\nVous devez créer un [environnement virtuel](../virtual-environments.md), l'activer, puis installer `jinja2` :\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## Utiliser `Jinja2Templates` { #using-jinja2templates }\n\n- Importez `Jinja2Templates`.\n- Créez un objet `templates` que vous pourrez réutiliser par la suite.\n- Déclarez un paramètre `Request` dans le *chemin d'accès* qui renverra un template.\n- Utilisez l'objet `templates` que vous avez créé pour rendre et retourner une `TemplateResponse`, en transmettant le nom du template, l'objet de requête et un dictionnaire de « context » avec des paires clé-valeur à utiliser dans le template Jinja2.\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note | Remarque\n\nAvant FastAPI 0.108.0 et Starlette 0.29.0, `name` était le premier paramètre.\n\nDe plus, auparavant, dans les versions précédentes, l'objet `request` faisait partie des paires clé-valeur du contexte pour Jinja2.\n\n///\n\n/// tip | Astuce\n\nEn déclarant `response_class=HTMLResponse`, l'interface de la documentation saura que la réponse sera en HTML.\n\n///\n\n/// note | Détails techniques\n\nVous pouvez aussi utiliser `from starlette.templating import Jinja2Templates`.\n\n**FastAPI** expose le même `starlette.templating` sous `fastapi.templating` par simple commodité pour vous, développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette. C'est également le cas pour `Request` et `StaticFiles`.\n\n///\n\n## Écrire des templates { #writing-templates }\n\nVous pouvez ensuite écrire un template dans `templates/item.html`, par exemple :\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### Valeurs de contexte du template { #template-context-values }\n\nDans le HTML qui contient :\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n... il affichera l’`id` récupéré à partir du `dict` « context » que vous avez passé :\n\n```Python\n{\"id\": id}\n```\n\nPar exemple, avec un ID de `42`, cela rendrait :\n\n```html\nItem ID: 42\n```\n\n### Arguments de `url_for` dans le template { #template-url-for-arguments }\n\nVous pouvez aussi utiliser `url_for()` dans le template ; elle prend en paramètres les mêmes arguments que ceux utilisés par votre *fonction de chemin d'accès*.\n\nAinsi, la section suivante :\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n... générera un lien vers la même URL que celle gérée par la *fonction de chemin d'accès* `read_item(id=id)`.\n\nPar exemple, avec un ID de `42`, cela rendrait :\n\n```html\n<a href=\"/items/42\">\n```\n\n## Templates et fichiers statiques { #templates-and-static-files }\n\nVous pouvez aussi utiliser `url_for()` dans le template, par exemple avec les `StaticFiles` que vous avez montés avec `name=\"static\"`.\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\nDans cet exemple, cela créera un lien vers un fichier CSS `static/styles.css` avec :\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\nEt comme vous utilisez `StaticFiles`, ce fichier CSS est servi automatiquement par votre application **FastAPI** à l’URL `/static/styles.css`.\n\n## En savoir plus { #more-details }\n\nPour plus de détails, y compris sur la façon de tester des templates, consultez [la documentation de Starlette sur les templates](https://www.starlette.dev/templates/).\n"
  },
  {
    "path": "docs/fr/docs/advanced/testing-dependencies.md",
    "content": "# Tester des dépendances avec des surcharges { #testing-dependencies-with-overrides }\n\n## Surcharger des dépendances pendant les tests { #overriding-dependencies-during-testing }\n\nIl existe des cas où vous souhaiterez surcharger une dépendance pendant les tests.\n\nVous ne voulez pas exécuter la dépendance originale (ni ses éventuelles sous‑dépendances).\n\nÀ la place, vous souhaitez fournir une dépendance différente, utilisée uniquement pendant les tests (éventuellement seulement pour certains tests), et qui fournira une valeur utilisable partout où l’on utilisait celle de la dépendance originale.\n\n### Cas d’usage : service externe { #use-cases-external-service }\n\nPar exemple, vous avez un fournisseur d’authentification externe à appeler.\n\nVous lui envoyez un token et il renvoie un utilisateur authentifié.\n\nCe fournisseur peut vous facturer à la requête, et l’appeler peut prendre plus de temps que si vous aviez un utilisateur factice fixe pour les tests.\n\nVous voudrez probablement tester le fournisseur externe une fois, mais pas nécessairement l’appeler pour chaque test exécuté.\n\nDans ce cas, vous pouvez surcharger la dépendance qui appelle ce fournisseur et utiliser une dépendance personnalisée qui renvoie un utilisateur factice, uniquement pour vos tests.\n\n### Utiliser l’attribut `app.dependency_overrides` { #use-the-app-dependency-overrides-attribute }\n\nPour ces cas, votre **FastAPI** application possède un attribut `app.dependency_overrides` ; c’est un simple `dict`.\n\nPour surcharger une dépendance lors des tests, vous mettez comme clé la dépendance originale (une fonction) et comme valeur votre surcharge de dépendance (une autre fonction).\n\nEnsuite, **FastAPI** appellera cette surcharge au lieu de la dépendance originale.\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip | Astuce\n\nVous pouvez définir une surcharge de dépendance pour une dépendance utilisée n’importe où dans votre application **FastAPI**.\n\nLa dépendance originale peut être utilisée dans une fonction de chemin d'accès, un décorateur de chemin d'accès (quand vous n’utilisez pas la valeur de retour), un appel à `.include_router()`, etc.\n\nFastAPI pourra toujours la surcharger.\n\n///\n\nVous pouvez ensuite réinitialiser vos surcharges (les supprimer) en affectant à `app.dependency_overrides` un `dict` vide :\n\n```Python\napp.dependency_overrides = {}\n```\n/// tip | Astuce\n\nSi vous souhaitez surcharger une dépendance uniquement pendant certains tests, vous pouvez définir la surcharge au début du test (dans la fonction de test) et la réinitialiser à la fin (à la fin de la fonction de test).\n\n///\n"
  },
  {
    "path": "docs/fr/docs/advanced/testing-events.md",
    "content": "# Tester les événements : lifespan et startup - shutdown { #testing-events-lifespan-and-startup-shutdown }\n\nLorsque vous avez besoin d'exécuter `lifespan` dans vos tests, vous pouvez utiliser `TestClient` avec une instruction `with` :\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\nVous pouvez lire plus de détails dans [« Exécuter lifespan dans les tests sur le site de documentation officiel de Starlette. »](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)\n\nPour les événements dépréciés `startup` et `shutdown`, vous pouvez utiliser le `TestClient` comme suit :\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/fr/docs/advanced/testing-websockets.md",
    "content": "# Tester les WebSockets { #testing-websockets }\n\nVous pouvez utiliser le même `TestClient` pour tester les WebSockets.\n\nPour cela, vous utilisez `TestClient` dans une instruction `with`, en vous connectant au WebSocket :\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note | Remarque\n\nPour plus de détails, consultez la documentation de Starlette sur le [test des WebSockets](https://www.starlette.dev/testclient/#testing-websocket-sessions).\n\n///\n"
  },
  {
    "path": "docs/fr/docs/advanced/using-request-directly.md",
    "content": "# Utiliser Request directement { #using-the-request-directly }\n\nJusqu'à présent, vous avez déclaré les parties de la requête dont vous avez besoin, avec leurs types.\n\nEn récupérant des données depuis :\n\n* Le chemin, sous forme de paramètres.\n* En-têtes.\n* Cookies.\n* etc.\n\nEt ce faisant, **FastAPI** valide ces données, les convertit et génère automatiquement la documentation de votre API.\n\nMais il existe des situations où vous pouvez avoir besoin d'accéder directement à l'objet `Request`.\n\n## Détails sur l'objet `Request` { #details-about-the-request-object }\n\nComme **FastAPI** est en fait **Starlette** en dessous, avec une couche de plusieurs outils au-dessus, vous pouvez utiliser directement l'objet [`Request`](https://www.starlette.dev/requests/) de Starlette lorsque vous en avez besoin.\n\nCela signifie aussi que si vous récupérez des données directement à partir de l'objet `Request` (par exemple, lire le corps), elles ne seront pas validées, converties ni documentées (avec OpenAPI, pour l'interface utilisateur automatique de l'API) par FastAPI.\n\nEn revanche, tout autre paramètre déclaré normalement (par exemple, le corps avec un modèle Pydantic) sera toujours validé, converti, annoté, etc.\n\nMais il existe des cas spécifiques où il est utile d'obtenir l'objet `Request`.\n\n## Utiliser l'objet `Request` directement { #use-the-request-object-directly }\n\nImaginons que vous souhaitiez obtenir l'adresse IP/l'hôte du client dans votre fonction de chemin d'accès.\n\nPour cela, vous devez accéder directement à la requête.\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\nEn déclarant un paramètre de fonction de chemin d'accès de type `Request`, **FastAPI** saura passer la `Request` dans ce paramètre.\n\n/// tip | Astuce\n\nNotez que, dans ce cas, nous déclarons un paramètre de chemin en plus du paramètre de requête.\n\nAinsi, le paramètre de chemin sera extrait, validé, converti vers le type spécifié et annoté avec OpenAPI.\n\nDe la même façon, vous pouvez déclarer tout autre paramètre normalement, et en plus, obtenir aussi la `Request`.\n\n///\n\n## Documentation de `Request` { #request-documentation }\n\nVous pouvez lire plus de détails sur [l'objet `Request` sur le site de documentation officiel de Starlette](https://www.starlette.dev/requests/).\n\n/// note | Détails techniques\n\nVous pouvez également utiliser `from starlette.requests import Request`.\n\n**FastAPI** le fournit directement pour votre commodité, en tant que développeur. Mais il provient directement de Starlette.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\nVous pouvez utiliser [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) avec **FastAPI**.\n\n## Installer `websockets` { #install-websockets }\n\nVous devez créer un [environnement virtuel](../virtual-environments.md), l'activer, et installer `websockets` (une bibliothèque Python qui facilite l'utilisation du protocole « WebSocket ») :\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## Client WebSocket { #websockets-client }\n\n### En production { #in-production }\n\nDans votre système de production, vous avez probablement un frontend créé avec un framework moderne comme React, Vue.js ou Angular.\n\nEt pour communiquer en utilisant WebSockets avec votre backend, vous utiliseriez probablement les outils fournis par votre frontend.\n\nOu vous pouvez avoir une application mobile native qui communique directement avec votre backend WebSocket, en code natif.\n\nOu vous pouvez avoir toute autre façon de communiquer avec l'endpoint WebSocket.\n\n---\n\nMais pour cet exemple, nous utiliserons un document HTML très simple avec un peu de JavaScript, le tout dans une longue chaîne.\n\nCela, bien entendu, n'est pas optimal et vous ne l'utiliseriez pas en production.\n\nEn production, vous auriez l'une des options ci-dessus.\n\nMais c'est la façon la plus simple de se concentrer sur la partie serveur des WebSockets et d'avoir un exemple fonctionnel :\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## Créer un `websocket` { #create-a-websocket }\n\nDans votre application **FastAPI**, créez un `websocket` :\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | Détails techniques\n\nVous pourriez aussi utiliser `from starlette.websockets import WebSocket`.\n\n**FastAPI** fournit le même `WebSocket` directement, simplement pour vous faciliter la vie en tant que développeur. Mais il provient directement de Starlette.\n\n///\n\n## Attendre des messages et envoyer des messages { #await-for-messages-and-send-messages }\n\nDans votre route WebSocket, vous pouvez `await` des messages et envoyer des messages.\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\nVous pouvez recevoir et envoyer des données binaires, texte et JSON.\n\n## Essayer { #try-it }\n\nMettez votre code dans un fichier `main.py` puis exécutez votre application :\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nOuvrez votre navigateur à l'adresse [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nVous verrez une page simple comme :\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\nVous pouvez saisir des messages dans le champ de saisie et les envoyer :\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\nEt votre application **FastAPI** avec WebSockets vous répondra :\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\nVous pouvez envoyer (et recevoir) de nombreux messages :\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\nEt tous utiliseront la même connexion WebSocket.\n\n## Utiliser `Depends` et autres { #using-depends-and-others }\n\nDans les endpoints WebSocket, vous pouvez importer depuis `fastapi` et utiliser :\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\nIls fonctionnent de la même manière que pour les autres endpoints/*chemins d'accès* FastAPI :\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info\n\nComme il s'agit d'un WebSocket, il n'est pas vraiment logique de lever une `HTTPException`, nous levons plutôt une `WebSocketException`.\n\nVous pouvez utiliser un code de fermeture parmi les [codes valides définis dans la spécification](https://tools.ietf.org/html/rfc6455#section-7.4.1).\n\n///\n\n### Essayez les WebSockets avec des dépendances { #try-the-websockets-with-dependencies }\n\nExécutez votre application :\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nOuvrez votre navigateur à l'adresse [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nLà, vous pouvez définir :\n\n* « Item ID », utilisé dans le chemin.\n* « Token » utilisé comme paramètre de requête.\n\n/// tip | Astuce\n\nNotez que le `token` de requête sera géré par une dépendance.\n\n///\n\nAvec cela, vous pouvez connecter le WebSocket puis envoyer et recevoir des messages :\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## Gérer les déconnexions et plusieurs clients { #handling-disconnections-and-multiple-clients }\n\nLorsqu'une connexion WebSocket est fermée, l'instruction `await websocket.receive_text()` lèvera une exception `WebSocketDisconnect`, que vous pouvez ensuite intercepter et gérer comme dans cet exemple.\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\nPour l'essayer :\n\n* Ouvrez l'application dans plusieurs onglets du navigateur.\n* Écrivez des messages depuis ceux-ci.\n* Puis fermez l'un des onglets.\n\nCela lèvera l'exception `WebSocketDisconnect`, et tous les autres clients recevront un message comme :\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip | Astuce\n\nL'application ci-dessus est un exemple minimal et simple pour montrer comment gérer et diffuser des messages à plusieurs connexions WebSocket.\n\nMais gardez à l'esprit que, comme tout est géré en mémoire, dans une seule liste, cela ne fonctionnera que tant que le processus s'exécute et uniquement avec un seul processus.\n\nSi vous avez besoin de quelque chose de facile à intégrer avec FastAPI mais plus robuste, pris en charge par Redis, PostgreSQL ou autres, consultez [encode/broadcaster](https://github.com/encode/broadcaster).\n\n///\n\n## Plus d'informations { #more-info }\n\nPour en savoir plus sur les options, consultez la documentation de Starlette concernant :\n\n* [La classe `WebSocket`](https://www.starlette.dev/websockets/).\n* [Gestion des WebSocket basée sur des classes](https://www.starlette.dev/endpoints/#websocketendpoint).\n"
  },
  {
    "path": "docs/fr/docs/advanced/wsgi.md",
    "content": "# Inclure WSGI - Flask, Django, autres { #including-wsgi-flask-django-others }\n\nVous pouvez monter des applications WSGI comme vous l'avez vu avec [Sous-applications - Montages](sub-applications.md), [Derrière un proxy](behind-a-proxy.md).\n\nPour cela, vous pouvez utiliser `WSGIMiddleware` et l'utiliser pour envelopper votre application WSGI, par exemple Flask, Django, etc.\n\n## Utiliser `WSGIMiddleware` { #using-wsgimiddleware }\n\n/// info\n\nCela nécessite l'installation de `a2wsgi`, par exemple avec `pip install a2wsgi`.\n\n///\n\nVous devez importer `WSGIMiddleware` depuis `a2wsgi`.\n\nEnsuite, enveloppez l'application WSGI (par ex. Flask) avec le middleware.\n\nPuis, montez-la sous un chemin.\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note | Remarque\n\nAuparavant, il était recommandé d'utiliser `WSGIMiddleware` depuis `fastapi.middleware.wsgi`, mais il est désormais déprécié.\n\nIl est conseillé d'utiliser le package `a2wsgi` à la place. L'utilisation reste la même.\n\nAssurez-vous simplement que le package `a2wsgi` est installé et importez `WSGIMiddleware` correctement depuis `a2wsgi`.\n\n///\n\n## Vérifiez { #check-it }\n\nDésormais, chaque requête sous le chemin `/v1/` sera gérée par l'application Flask.\n\nEt le reste sera géré par **FastAPI**.\n\nSi vous l'exécutez et allez à [http://localhost:8000/v1/](http://localhost:8000/v1/) vous verrez la réponse de Flask :\n\n```txt\nHello, World from Flask!\n```\n\nEt si vous allez à [http://localhost:8000/v2](http://localhost:8000/v2) vous verrez la réponse de FastAPI :\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/fr/docs/alternatives.md",
    "content": "# Alternatives, inspiration et comparaisons { #alternatives-inspiration-and-comparisons }\n\nCe qui a inspiré **FastAPI**, comment il se compare à d'autres solutions et ce qu'il en a appris.\n\n## Intro { #intro }\n\n**FastAPI** n'existerait pas sans les précédentes contributions d'autres projets.\n\nDe nombreux outils ont été créés auparavant et ont contribué à inspirer sa création.\n\nJ'ai évité la création d'un nouveau framework pendant plusieurs années. J'ai d'abord essayé de combler toutes les\nfonctionnalités couvertes par **FastAPI** en utilisant de nombreux frameworks, plug-ins et outils différents.\n\nMais à un moment donné il n'y avait pas d'autre option que de créer quelque chose qui offrait toutes ces\nfonctionnalités, en reprenant et en combinant de la meilleure façon possible les meilleures idées des outils\nprécédents, en utilisant des fonctionnalités du langage qui n'étaient même pas disponibles auparavant (annotations de type depuis Python 3.6+).\n\n## Outils précédents { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\nC'est le framework Python le plus populaire et il bénéficie d'une grande confiance. Il est utilisé pour construire\ndes systèmes tel qu'Instagram.\n\nIl est relativement fortement couplé aux bases de données relationnelles (comme MySQL ou PostgreSQL), de sorte qu'il\nn'est pas très facile d'utiliser une base de données NoSQL (comme Couchbase, MongoDB, Cassandra, etc.) comme principal moyen de\nstockage.\n\nIl a été créé pour générer le HTML en backend, pas pour créer des API consommées par un frontend moderne (comme React, Vue.js et Angular) ou par d'autres systèmes (comme les appareils <abbr title=\"Internet of Things - Internet des objets\">IoT</abbr>) communiquant avec lui.\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nDjango REST Framework a été conçu comme une boîte à outils flexible permettant de construire des API Web à partir de Django, afin d'améliorer ses capacités en matière d'API.\n\nIl est utilisé par de nombreuses entreprises, dont Mozilla, Red Hat et Eventbrite.\n\nIl s'agissait de l'un des premiers exemples de **documentation automatique pour API**, et c'est précisément l'une des\npremières idées qui a inspiré « la recherche de » **FastAPI**.\n\n/// note | Remarque\n\nDjango REST Framework a été créé par Tom Christie. Le créateur de Starlette et Uvicorn, sur lesquels **FastAPI** est basé.\n\n///\n\n/// check | A inspiré **FastAPI** à\n\nAvoir une interface de documentation automatique de l'API.\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask est un « micro‑framework », il ne comprend pas d'intégrations de bases de données ni beaucoup de choses qui sont fournies par défaut dans Django.\n\nCette simplicité et cette flexibilité permettent d'utiliser des bases de données NoSQL comme principal système de stockage de données.\n\nComme il est très simple, son apprentissage est relativement intuitif, bien que la documentation soit quelque peu\ntechnique par moments.\n\nIl est aussi couramment utilisé pour d'autres applications qui n'ont pas nécessairement besoin d'une base de données, de gestion des utilisateurs ou de l'une des nombreuses fonctionnalités préinstallées dans Django. Bien que beaucoup de ces fonctionnalités puissent être ajoutées avec des plug-ins.\n\nCe découplage des parties, et le fait d'être un « micro‑framework » qui puisse être étendu pour couvrir exactement ce\nqui est nécessaire, était une caractéristique clé que je voulais conserver.\n\nCompte tenu de la simplicité de Flask, il semblait bien adapté à la création d'API. La prochaine chose à trouver était un « Django REST Framework » pour Flask.\n\n/// check | A inspiré **FastAPI** à\n\nÊtre un micro‑framework. Il est donc facile de combiner les outils et les pièces nécessaires.\n\nProposer un système de routage simple et facile à utiliser.\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI** n'est pas réellement une alternative à **Requests**. Leur cadre est très différent.\n\nIl serait en fait plus courant d'utiliser Requests _à l'intérieur_ d'une application FastAPI.\n\nMais quand même, FastAPI s'est inspiré de Requests.\n\n**Requests** est une bibliothèque pour _interagir_ avec les API (en tant que client), tandis que **FastAPI** est une bibliothèque pour _créer_ des API (en tant que serveur).\n\nIls sont, plus ou moins, aux extrémités opposées, se complétant l'un l'autre.\n\nRequests a un design très simple et intuitif, il est très facile à utiliser, avec des valeurs par défaut raisonnables, tout en étant très puissant et personnalisable.\n\nC'est pourquoi, comme le dit le site officiel :\n\n> Requests est l'un des packages Python les plus téléchargés de tous les temps\n\nLa façon dont vous l'utilisez est très simple. Par exemple, pour faire une requête `GET`, vous devez écrire :\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\nL’opération de chemin d'accès correspondante dans **FastAPI** pourrait ressembler à ceci :\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\nNotez les similitudes entre `requests.get(...)` et `@app.get(...)`.\n\n/// check | A inspiré **FastAPI** à\n\n* Avoir une API simple et intuitive.\n* Utiliser les noms de méthodes HTTP (opérations) directement, de manière simple et intuitive.\n* Avoir des valeurs par défaut raisonnables, mais des personnalisations puissantes.\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\nLa principale fonctionnalité que j'ai emprunté à Django REST Framework était la documentation automatique des API.\n\nPuis j'ai découvert qu'il existait une norme pour documenter les API, en utilisant JSON (ou YAML, une extension de JSON) appelée Swagger.\n\nIl existait déjà une interface utilisateur Web pour les API Swagger. Donc, être capable de générer une documentation\nSwagger pour une API permettrait d'utiliser cette interface utilisateur web automatiquement.\n\nÀ un moment donné, Swagger a été cédé à la Fondation Linux, puis a été rebaptisé OpenAPI.\n\nC'est pourquoi, lorsqu'on parle de la version 2.0, il est courant de dire « Swagger », et pour la version 3+ « OpenAPI ».\n\n/// check | A inspiré **FastAPI** à\n\nAdopter et utiliser une norme ouverte pour les spécifications des API, au lieu d'un schéma personnalisé.\n\nIntégrer des outils d'interface utilisateur basés sur des normes :\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\nCes deux-là ont été choisis parce qu'ils sont populaires et stables, mais en faisant une recherche rapide, vous pourriez trouver des dizaines d'alternatives supplémentaires pour OpenAPI (que vous pouvez utiliser avec **FastAPI**).\n\n///\n\n### Frameworks REST pour Flask { #flask-rest-frameworks }\n\nIl y a plusieurs frameworks REST pour Flask, mais après avoir investi du temps et du travail pour les étudier, j'ai\ndécouvert que le développement de beaucoup d'entre eux sont suspendus ou abandonnés, avec plusieurs problèmes\npermanents qui les rendent inadaptés.\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nL'une des principales fonctionnalités nécessaires aux systèmes API est la « <dfn title=\"aussi appelé : marshalling, conversion\">sérialisation</dfn> » des données, qui consiste à prendre les données du code (Python) et à\nles convertir en quelque chose qui peut être envoyé sur le réseau. Par exemple, convertir un objet contenant des\ndonnées provenant d'une base de données en un objet JSON. Convertir des objets `datetime` en strings, etc.\n\nLa validation des données est une autre fonctionnalité importante dont ont besoin les API. Elle permet de s'assurer\nque les données sont valides, compte tenu de certains paramètres. Par exemple, qu'un champ est un `int`, et non un\nstring.\nCeci est particulièrement utile pour les données entrantes.\n\nSans un système de validation des données, vous devriez effectuer toutes les vérifications à la main, dans le code.\n\nCes fonctionnalités sont ce pourquoi Marshmallow a été construit. C'est une excellente bibliothèque, et je l'ai déjà beaucoup utilisée.\n\nMais elle a été créée avant que les annotations de type n'existent en Python. Ainsi, pour définir chaque <dfn title=\"la définition de la façon dont les données doivent être formées\">schéma</dfn>, vous devez utiliser des utilitaires et des classes spécifiques fournies par Marshmallow.\n\n/// check | A inspiré **FastAPI** à\n\nUtiliser du code pour définir des « schémas » qui fournissent automatiquement les types de données et la validation.\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nUne autre grande fonctionnalité requise par les API est l’<dfn title=\"lecture et conversion en données Python\">analyse</dfn> des données provenant des requêtes entrantes.\n\nWebargs est un outil qui a été créé pour fournir cela par-dessus plusieurs frameworks, dont Flask.\n\nIl utilise Marshmallow pour effectuer la validation des données. Et il a été créé par les mêmes développeurs.\n\nC'est un outil formidable et je l'ai beaucoup utilisé aussi, avant d'avoir **FastAPI**.\n\n/// info\n\nWebargs a été créé par les développeurs de Marshmallow.\n\n///\n\n/// check | A inspiré **FastAPI** à\n\nDisposer d'une validation automatique des données des requêtes entrantes.\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow et Webargs fournissent la validation, l'analyse et la sérialisation en tant que plug-ins.\n\nMais la documentation fait toujours défaut. C'est alors qu'APISpec a été créé.\n\nIl s'agit d'un plug-in pour de nombreux frameworks (et il existe également un plug-in pour Starlette).\n\nLe principe est le suivant : vous écrivez la définition du schéma au format YAML dans la docstring de chaque fonction gérant une route.\n\nEt il génère des schémas OpenAPI.\n\nC'est ainsi que cela fonctionne dans Flask, Starlette, Responder, etc.\n\nMais alors, nous avons à nouveau le problème d'avoir une micro-syntaxe, dans une docstring Python (un gros morceau de YAML).\n\nL'éditeur ne peut guère aider en la matière. Et si nous modifions les paramètres ou les schémas Marshmallow et que nous oublions de modifier également cette docstring YAML, le schéma généré deviendrait obsolète.\n\n/// info\n\nAPISpec a été créé par les développeurs de Marshmallow.\n\n///\n\n/// check | A inspiré **FastAPI** à\n\nSupporter la norme ouverte pour les API, OpenAPI.\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\nC'est un plug-in pour Flask, qui relie Webargs, Marshmallow et APISpec.\n\nIl utilise les informations de Webargs et Marshmallow pour générer automatiquement des schémas OpenAPI, en utilisant APISpec.\n\nC'est un excellent outil, très sous-estimé. Il devrait être beaucoup plus populaire que de nombreux plug-ins Flask. C'est peut-être dû au fait que sa documentation est trop concise et abstraite.\n\nCela a permis de ne pas avoir à écrire YAML (une autre syntaxe) à l'intérieur des docstrings Python.\n\nCette combinaison de Flask, Flask-apispec avec Marshmallow et Webargs était ma stack backend préférée jusqu'à la création de **FastAPI**.\n\nSon utilisation a conduit à la création de plusieurs générateurs Flask full-stack. Ce sont les principales stacks que\nj'ai (ainsi que plusieurs équipes externes) utilisées jusqu'à présent :\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\nCes mêmes générateurs full-stack ont servi de base aux [Générateurs de projets pour **FastAPI**](project-generation.md).\n\n/// info\n\nFlask-apispec a été créé par les développeurs de Marshmallow.\n\n///\n\n/// check | A inspiré **FastAPI** à\n\nGénérer le schéma OpenAPI automatiquement, à partir du même code qui définit la sérialisation et la validation.\n\n///\n\n### [NestJS](https://nestjs.com/) (et [Angular](https://angular.io/)) { #nestjs-and-angular }\n\nCe n'est même pas du Python, NestJS est un framework JavaScript (TypeScript) NodeJS inspiré d'Angular.\n\nIl réalise quelque chose de similaire à ce qui peut être fait avec Flask-apispec.\n\nIl possède un système d'injection de dépendances intégré, inspiré d'Angular 2. Il nécessite de pré-enregistrer les « injectables » (comme tous les autres systèmes d'injection de dépendances que je connais), donc, cela ajoute à la verbosité et à la répétition du code.\n\nComme les paramètres sont décrits avec des types TypeScript (similaires aux annotations de type de Python), la prise en charge\npar l'éditeur est assez bonne.\n\nMais comme les données TypeScript ne sont pas préservées après la compilation en JavaScript, il ne peut pas compter sur les types pour définir la validation, la sérialisation et la documentation en même temps. En raison de cela et de certaines décisions de conception, pour obtenir la validation, la sérialisation et la génération automatique de schémas, il est nécessaire d'ajouter des décorateurs à de nombreux endroits. Cela devient donc assez verbeux.\n\nIl ne peut pas très bien gérer les modèles imbriqués. Ainsi, si le corps JSON de la requête est un objet JSON comportant des champs internes qui sont à leur tour des objets JSON imbriqués, il ne peut pas être correctement documenté et validé.\n\n/// check | A inspiré **FastAPI** à\n\nUtiliser les types Python pour bénéficier d'un excellent support de l'éditeur.\n\nDisposer d'un puissant système d'injection de dépendances. Trouver un moyen de minimiser la répétition du code.\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\nC'était l'un des premiers frameworks Python extrêmement rapides basés sur `asyncio`. Il a été conçu pour être très similaire à Flask.\n\n/// note | Détails techniques\n\nIl utilisait [`uvloop`](https://github.com/MagicStack/uvloop) au lieu du système par défaut de Python `asyncio`. C'est ce qui l'a rendu si rapide.\n\nIl a clairement inspiré Uvicorn et Starlette, qui sont actuellement plus rapides que Sanic dans les benchmarks.\n\n///\n\n/// check | A inspiré **FastAPI** à\n\nTrouver un moyen d'avoir une performance folle.\n\nC'est pourquoi **FastAPI** est basé sur Starlette, car il s'agit du framework le plus rapide disponible (testé par des benchmarks tiers).\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon est un autre framework Python haute performance, il est conçu pour être minimal, et est utilisé comme fondation pour d'autres frameworks comme Hug.\n\nIl est conçu pour avoir des fonctions qui reçoivent deux paramètres, une « requête » et une « réponse ». Ensuite, vous\n« lisez » des parties de la requête et « écrivez » des parties dans la réponse. En raison de cette conception, il n'est\npas possible de déclarer des paramètres de requête et des corps avec des indications de type Python standard comme paramètres de fonction.\n\nAinsi, la validation, la sérialisation et la documentation des données doivent être effectuées dans le code, et non pas automatiquement. Ou bien elles doivent être implémentées comme un framework au-dessus de Falcon, comme Hug. Cette même distinction se retrouve dans d'autres frameworks qui s'inspirent de la conception de Falcon, qui consiste à avoir un objet de requête et un objet de réponse comme paramètres.\n\n/// check | A inspiré **FastAPI** à\n\nTrouver des moyens d'obtenir de bonnes performances.\n\nAvec Hug (puisque Hug est basé sur Falcon), cela a inspiré **FastAPI** à déclarer un paramètre `response` dans les fonctions.\n\nBien que dans FastAPI, il est facultatif, et est utilisé principalement pour définir les en-têtes, les cookies, et les codes de statut alternatifs.\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\nJ'ai découvert Molten lors des premières étapes de développement de **FastAPI**. Et il a des idées assez similaires :\n\n* Basé sur les annotations de type Python.\n* Validation et documentation via ces types.\n* Système d'injection de dépendances.\n\nIl n'utilise pas une librairie tiers de validation, sérialisation et de documentation tel que Pydantic, il utilise son propre système. Ainsi, ces définitions de types de données ne sont pas réutilisables aussi facilement.\n\nIl nécessite une configuration un peu plus verbeuse. Et comme il est basé sur WSGI (au lieu d'ASGI), il n'est pas\nconçu pour profiter des hautes performances fournies par des outils comme Uvicorn, Starlette et Sanic.\n\nLe système d'injection de dépendances exige le pré-enregistrement des dépendances et les dépendances sont résolues sur la base des types déclarés. Ainsi, il n'est pas possible de déclarer plus d'un « composant » qui fournit un certain type.\n\nLes routes sont déclarées à un seul endroit, en utilisant des fonctions déclarées à d'autres endroits (au lieu\nd'utiliser des décorateurs qui peuvent être placés juste au-dessus de la fonction qui gère l'endpoint). Cette\nméthode est plus proche de celle de Django que de celle de Flask (et Starlette). Il sépare dans le code des choses\nqui sont relativement fortement couplées.\n\n/// check | A inspiré **FastAPI** à\n\nDéfinir des validations supplémentaires pour les types de données utilisant la valeur « par défaut » des attributs du modèle. Ceci améliore le support de l'éditeur, et n'était pas disponible dans Pydantic auparavant.\n\nCela a en fait inspiré la mise à jour de certaines parties de Pydantic, afin de supporter le même style de déclaration de validation (toute cette fonctionnalité est maintenant déjà disponible dans Pydantic).\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug a été l'un des premiers frameworks à implémenter la déclaration des types de paramètres d'API en utilisant les annotations de type Python. C'était une excellente idée qui a inspiré d'autres outils à faire de même.\n\nIl utilisait des types personnalisés dans ses déclarations au lieu des types Python standard, mais c'était tout de même un énorme pas en avant.\n\nIl a également été l'un des premiers frameworks à générer un schéma personnalisé déclarant l'ensemble de l'API en JSON.\n\nIl n'était pas basé sur une norme comme OpenAPI et JSON Schema. Il ne serait donc pas simple de l'intégrer à d'autres outils, comme Swagger UI. Mais encore une fois, c'était une idée très innovante.\n\nIl présente une caractéristique intéressante et peu commune : à l'aide du même framework, il est possible de créer des\nAPI et des CLI.\n\nComme il est basé sur l'ancienne norme pour les frameworks web Python synchrones (WSGI), il ne peut pas gérer les Websockets et autres, bien qu'il soit également très performant.\n\n/// info\n\nHug a été créé par Timothy Crosley, le créateur de [`isort`](https://github.com/timothycrosley/isort), un excellent outil pour trier automatiquement les imports dans les fichiers Python.\n\n///\n\n/// check | Idées ayant inspiré **FastAPI**\n\nHug a inspiré certaines parties d'APIStar, et était l'un des outils que je trouvais les plus prometteurs, à côté d'APIStar.\n\nHug a contribué à inspirer **FastAPI** pour utiliser les annotations de type Python\npour déclarer les paramètres, et pour générer automatiquement un schéma définissant l'API.\n\nHug a inspiré **FastAPI** pour déclarer un paramètre `response` dans les fonctions pour définir les en-têtes et les cookies.\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0.5) { #apistar-0-5 }\n\nJuste avant de décider de développer **FastAPI**, j'ai trouvé le serveur **APIStar**. Il contenait presque tout ce\nque je recherchais et avait un beau design.\n\nC'était l'une des premières implémentations d'un framework utilisant les annotations de type Python pour déclarer les paramètres\net les requêtes que j'ai vues (avant NestJS et Molten). Je l'ai trouvé plus ou moins en même temps que Hug. Mais APIStar utilisait le standard OpenAPI.\n\nIl disposait de la validation automatique, sérialisation des données et d'une génération de schéma OpenAPI basée sur les mêmes annotations de type à plusieurs endroits.\n\nLa définition du schéma de corps de requête n'utilisait pas les mêmes annotations de type Python que Pydantic, il était un peu plus proche de Marshmallow, donc le support de l'éditeur n'était pas aussi bon, mais APIStar était quand même la meilleure option disponible.\n\nIl avait les meilleures performances d'après les benchmarks de l'époque (seulement surpassé par Starlette).\n\nAu départ, il ne disposait pas d'une interface web de documentation automatique de l'API, mais je savais que je pouvais lui ajouter une interface Swagger.\n\nIl avait un système d'injection de dépendances. Il nécessitait un pré-enregistrement des composants, comme d'autres outils discutés ci-dessus. Mais c'était quand même une excellente fonctionnalité.\n\nJe n'ai jamais pu l'utiliser dans un projet complet, car il n'avait pas d'intégration de sécurité, et je ne pouvais donc pas remplacer toutes les fonctionnalités que j'avais avec les générateurs complets basés sur Flask-apispec. J'avais dans mon backlog de projets de créer une pull request pour ajouter cette fonctionnalité.\n\nMais ensuite, le projet a changé d'orientation.\n\nIl ne s'agissait plus d'un framework web API, le créateur devant se concentrer sur Starlette.\n\nMaintenant, APIStar est un ensemble d'outils pour valider les spécifications OpenAPI, et non un framework web.\n\n/// info\n\nAPIStar a été créé par Tom Christie. Le même gars qui a créé :\n\n* Django REST Framework\n* Starlette (sur lequel **FastAPI** est basé)\n* Uvicorn (utilisé par Starlette et **FastAPI**)\n\n///\n\n/// check | A inspiré **FastAPI** à\n\nExister.\n\nL'idée de déclarer plusieurs choses (validation des données, sérialisation et documentation) avec les mêmes types Python, tout en offrant un excellent support pour les éditeurs, était pour moi une idée brillante.\n\nEt après avoir longtemps cherché un framework similaire et testé de nombreuses alternatives, APIStar était la meilleure option disponible.\n\nPuis APIStar a cessé d'exister en tant que serveur et Starlette a été créé, et a constitué une meilleure base pour un tel système. Ce fut l'inspiration finale pour construire **FastAPI**.\n\nJe considère **FastAPI** comme un « successeur spirituel » d'APIStar, tout en améliorant et en augmentant les fonctionnalités, le système de typage et d'autres parties, sur la base des enseignements tirés de tous ces outils précédents.\n\n///\n\n## Utilisés par **FastAPI** { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic est une bibliothèque permettant de définir la validation, la sérialisation et la documentation des données (à l'aide de JSON Schema) en se basant sur les annotations de type Python.\n\nCela le rend extrêmement intuitif.\n\nIl est comparable à Marshmallow. Bien qu'il soit plus rapide que Marshmallow dans les benchmarks. Et comme il est\nbasé sur les mêmes annotations de type Python, le support de l'éditeur est grand.\n\n/// check | **FastAPI** l'utilise pour\n\nGérer toute la validation des données, leur sérialisation et la documentation automatique du modèle (basée sur le schéma JSON).\n\n**FastAPI** prend ensuite ces données JSON Schema et les place dans OpenAPI, en plus de toutes les autres choses qu'il fait.\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette est un framework/toolkit léger <dfn title=\"La nouvelle norme pour créer des applications web Python asynchrones\">ASGI</dfn>, qui est idéal pour construire des services asyncio performants.\n\nIl est très simple et intuitif. Il est conçu pour être facilement extensible et avoir des composants modulaires.\n\nIl offre :\n\n- Des performances vraiment impressionnantes.\n- Le support des WebSockets.\n- Les tâches d'arrière-plan.\n- Les événements de démarrage et d'arrêt.\n- Un client de test basé sur HTTPX.\n- CORS, GZip, fichiers statiques, streaming des réponses.\n- Le support des sessions et des cookies.\n- Une couverture de test à 100 %.\n- 100 % de la base de code avec des annotations de type.\n- Peu de dépendances strictes.\n\nStarlette est actuellement le framework Python le plus rapide testé. Seulement dépassé par Uvicorn, qui n'est pas un framework, mais un serveur.\n\nStarlette fournit toutes les fonctionnalités de base d'un micro‑framework web.\n\nMais il ne fournit pas de validation automatique des données, de sérialisation ou de documentation.\n\nC'est l'une des principales choses que **FastAPI** ajoute par-dessus, le tout basé sur les annotations de type Python (en utilisant Pydantic). Cela, plus le système d'injection de dépendances, les utilitaires de sécurité, la génération de schémas OpenAPI, etc.\n\n/// note | Détails techniques\n\nASGI est une nouvelle « norme » développée par les membres de l'équipe principale de Django. Il ne s'agit pas encore d'une « norme Python » (un PEP), bien qu'ils soient en train de le faire.\n\nNéanmoins, il est déjà utilisé comme « standard » par plusieurs outils. Cela améliore grandement l'interopérabilité, puisque vous pouvez remplacer Uvicorn par n'importe quel autre serveur ASGI (comme Daphne ou Hypercorn), ou vous pouvez ajouter des outils compatibles ASGI, comme `python-socketio`.\n\n///\n\n/// check | **FastAPI** l'utilise pour\n\nGérer toutes les parties web de base. Ajouter des fonctionnalités par-dessus.\n\nLa classe `FastAPI` elle-même hérite directement de la classe `Starlette`.\n\nAinsi, tout ce que vous pouvez faire avec Starlette, vous pouvez le faire directement avec **FastAPI**, car il s'agit en fait de Starlette sous stéroïdes.\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn est un serveur ASGI rapide comme l'éclair, basé sur uvloop et httptools.\n\nIl ne s'agit pas d'un framework web, mais d'un serveur. Par exemple, il ne fournit pas d'outils pour le routing. C'est\nquelque chose qu'un framework comme Starlette (ou **FastAPI**) fournirait par-dessus.\n\nC'est le serveur recommandé pour Starlette et **FastAPI**.\n\n/// check | **FastAPI** le recommande comme\n\nLe serveur web principal pour exécuter les applications **FastAPI**.\n\nVous pouvez également utiliser l'option de ligne de commande `--workers` pour avoir un serveur multi‑processus asynchrone.\n\nPour plus de détails, consultez la section [Déploiement](deployment/index.md).\n\n///\n\n## Benchmarks et vitesse { #benchmarks-and-speed }\n\nPour comprendre, comparer et voir la différence entre Uvicorn, Starlette et FastAPI, consultez la section sur les [Benchmarks](benchmarks.md).\n"
  },
  {
    "path": "docs/fr/docs/async.md",
    "content": "# Concurrence et async / await { #concurrency-and-async-await }\n\nDétails sur la syntaxe `async def` pour les *fonctions de chemin d'accès* et quelques rappels sur le code asynchrone, la concurrence et le parallélisme.\n\n## Vous êtes pressés ? { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - trop long ; pas lu\"><strong>TL;DR :</strong></abbr>\n\nSi vous utilisez des bibliothèques tierces qui nécessitent d'être appelées avec `await`, telles que :\n\n```Python\nresults = await some_library()\n```\n\nAlors, déclarez vos *fonctions de chemin d'accès* avec `async def` comme ceci :\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | Remarque\n\nVous pouvez uniquement utiliser `await` dans les fonctions créées avec `async def`.\n\n///\n\n---\n\nSi vous utilisez une bibliothèque externe qui communique avec quelque chose (une base de données, une API, le système de fichiers, etc.) et qui ne supporte pas l'utilisation d'`await` (ce qui est actuellement le cas pour la majorité des bibliothèques de base de données), alors déclarez vos *fonctions de chemin d'accès* normalement, avec le classique `def`, comme ceci :\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\nSi votre application (d'une certaine manière) n'a pas à communiquer avec une autre chose et à attendre sa réponse, utilisez `async def`, même si vous n'avez pas besoin d'utiliser `await` à l'intérieur.\n\n---\n\nSi vous ne savez pas, utilisez seulement `def`.\n\n---\n\nNote : vous pouvez mélanger `def` et `async def` dans vos *fonctions de chemin d'accès* autant que nécessaire, et définir chacune avec l’option la plus adaptée pour vous. FastAPI fera ce qu'il faut avec elles.\n\nAu final, peu importe le cas parmi ceux ci-dessus, FastAPI fonctionnera de manière asynchrone et sera extrêmement rapide.\n\nMais si vous suivez bien les instructions ci-dessus, il pourra effectuer quelques optimisations et ainsi améliorer les performances.\n\n## Détails techniques { #technical-details }\n\nLes versions modernes de Python supportent le **code asynchrone** grâce aux **« coroutines »** avec les syntaxes **`async` et `await`**.\n\nAnalysons les différentes parties de cette phrase dans les sections suivantes :\n\n* **Code asynchrone**\n* **`async` et `await`**\n* **Coroutines**\n\n## Code asynchrone { #asynchronous-code }\n\nFaire du code asynchrone signifie que le langage 💬 est capable de dire à l'ordinateur / au programme 🤖 qu'à un moment du code, il 🤖 devra attendre que *quelque chose d'autre* se termine autre part. Disons que ce *quelque chose d'autre* est appelé « slow-file » 📝.\n\nDonc, pendant ce temps, l'ordinateur pourra effectuer d'autres tâches, pendant que « slow-file » 📝 se termine.\n\nEnsuite l'ordinateur / le programme 🤖 reviendra à chaque fois qu'il en a la chance que ce soit parce qu'il attend à nouveau, ou car il 🤖 a fini tout le travail qu'il avait à faire. Il 🤖 regardera donc si les tâches qu'il attend ont terminé d'être effectuées.\n\nEnsuite, il 🤖 prendra la première tâche à finir (disons, notre « slow-file » 📝) et continuera à faire avec cette dernière ce qu'il était censé.\n\nCe « attendre quelque chose d'autre » fait généralement référence à des opérations <abbr title=\"Input and Output - Entrées et sorties\">I/O</abbr> qui sont relativement « lentes » (comparées à la vitesse du processeur et de la mémoire RAM) telles qu'attendre que :\n\n* de la donnée soit envoyée par le client à travers le réseau\n* de la donnée envoyée depuis votre programme soit reçue par le client à travers le réseau\n* le contenu d'un fichier sur le disque soit lu par le système et passé à votre programme\n* le contenu que votre programme a passé au système soit écrit sur le disque\n* une opération effectuée à distance par une API se termine\n* une opération en base de données se termine\n* une requête à une base de données renvoie un résultat\n* etc.\n\nLe temps d'exécution étant consommé majoritairement par l'attente d'opérations <abbr title=\"Input and Output - Entrées et sorties\">I/O</abbr>, on appelle ceci des opérations « I/O bound ».\n\nCe concept se nomme « asynchrone » car l'ordinateur / le programme n'a pas besoin d'être « synchronisé » avec la tâche, attendant le moment exact où cette dernière se terminera en ne faisant rien, pour être capable de récupérer le résultat de la tâche et l'utiliser dans la suite des opérations.\n\nÀ la place, en étant « asynchrone », une fois terminée, une tâche peut légèrement attendre (quelques microsecondes) que l'ordinateur / le programme finisse ce qu'il était en train de faire, et revienne récupérer le résultat.\n\nPour parler de tâches « synchrones » (en opposition à « asynchrones »), on utilise souvent le terme « séquentiel », car l'ordinateur / le programme va effectuer toutes les étapes d'une tâche séquentiellement avant de passer à une autre tâche, même si ces étapes impliquent de l'attente.\n\n### Concurrence et Burgers { #concurrency-and-burgers }\n\nL'idée de code **asynchrone** décrite ci-dessus est parfois aussi appelée **« concurrence »**. Ce qui est différent du **« parallélisme »**.\n\nLa **concurrence** et le **parallélisme** sont tous deux liés à l'idée de « différentes choses arrivant plus ou moins au même moment ».\n\nMais les détails entre la **concurrence** et le **parallélisme** diffèrent sur de nombreux points.\n\nPour expliquer la différence, voici une histoire de burgers :\n\n### Burgers concurrents { #concurrent-burgers }\n\nVous amenez votre crush 😍 dans votre fast food 🍔 favori, et faites la queue pendant que le serveur 💁 prend les commandes des personnes devant vous.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\nPuis vient votre tour, vous commandez alors 2 magnifiques burgers 🍔 pour votre crush 😍 et vous.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\nLe serveur 💁 dit quelque chose à son collègue dans la cuisine 👨‍🍳 pour qu'il sache qu'il doit préparer vos burgers 🍔 (bien qu'il soit déjà en train de préparer ceux des clients précédents).\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\nVous payez 💸.\n\nLe serveur 💁 vous donne le numéro assigné à votre commande.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\nPendant que vous attendez, vous allez choisir une table avec votre crush 😍, vous discutez avec votre crush 😍 pendant un long moment (les burgers étant « magnifiques » ils sont très longs à préparer ✨🍔✨).\n\nPendant que vous êtes assis à table, en attendant que les burgers 🍔 soient prêts, vous pouvez passer ce temps à admirer à quel point votre crush 😍 est géniale, mignonne et intelligente ✨😍✨.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\nPendant que vous discutez avec votre crush 😍, de temps en temps vous jetez un coup d’œil au nombre affiché au-dessus du comptoir pour savoir si c'est à votre tour d'être servis.\n\nJusqu'au moment où c'est (enfin) votre tour. Vous allez au comptoir, récupérez vos burgers 🍔 et revenez à votre table.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\nVous et votre crush 😍 mangez les burgers 🍔 et passez un bon moment ✨.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info\n\nIllustrations proposées par [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nImaginez que vous êtes l'ordinateur / le programme 🤖 dans cette histoire.\n\nPendant que vous faites la queue, vous être simplement inactif 😴, attendant votre tour, ne faisant rien de « productif ». Mais la queue est rapide car le serveur 💁 prend seulement les commandes (et ne les prépare pas), donc tout va bien.\n\nEnsuite, quand c'est votre tour, vous faites des actions « productives » 🤓, vous étudiez le menu, décidez ce que vous voulez, demandez à votre crush 😍 son choix, payez 💸, vérifiez que vous utilisez la bonne carte de crédit, vérifiez que le montant débité sur la carte est correct, vérifiez que la commande contient les bons produits, etc.\n\nMais ensuite, même si vous n'avez pas encore vos burgers 🍔, votre travail avec le serveur 💁 est « en pause » ⏸, car vous devez attendre 🕙 que vos burgers soient prêts.\n\nAprès vous être écarté du comptoir et vous être assis à votre table avec le numéro de votre commande, vous pouvez tourner 🔀 votre attention vers votre crush 😍, et « travailler » ⏯ 🤓 là-dessus. Vous êtes donc à nouveau en train de faire quelque chose de « productif » 🤓, vous flirtez avec votre crush 😍.\n\nPuis le serveur 💁 dit « J'ai fini de préparer les burgers » 🍔 en mettant votre numéro sur l'affichage du comptoir, mais vous ne courez pas immédiatement au moment où votre numéro s'affiche. Vous savez que personne ne volera vos burgers 🍔 car vous avez votre numéro et les autres clients ont le leur.\n\nVous attendez donc que votre crush 😍 finisse son histoire, souriez gentiment et dites que vous allez chercher les burgers ⏸.\n\nPour finir vous allez au comptoir 🔀, vers la tâche initiale qui est désormais terminée ⏯, récupérez les burgers 🍔, remerciez le serveur et ramenez les burgers 🍔 à votre table. Ceci termine l'étape / la tâche d'interaction avec le comptoir ⏹. Ce qui ensuite, crée une nouvelle tâche de « manger les burgers » 🔀 ⏯, mais la précédente, « récupérer les burgers » est terminée ⏹.\n\n### Burgers parallèles { #parallel-burgers }\n\nImaginons désormais que ce ne sont pas des « burgers concurrents » mais des « burgers parallèles ».\n\nVous allez avec votre crush 😍 dans un fast food 🍔 parallélisé.\n\nVous attendez pendant que plusieurs (disons 8) serveurs qui sont aussi des cuisiniers 👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳 prennent les commandes des personnes devant vous.\n\nChaque personne devant vous attend 🕙 que son burger 🍔 soit prêt avant de quitter le comptoir car chacun des 8 serveurs va lui-même préparer le burger directement avant de prendre la commande suivante.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\nPuis c'est enfin votre tour, vous commandez 2 magnifiques burgers 🍔 pour vous et votre crush 😍.\n\nVous payez 💸.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\nLe serveur va dans la cuisine 👨‍🍳.\n\nVous attendez devant le comptoir afin que personne ne prenne vos burgers 🍔 avant vous, vu qu'il n'y a pas de numéro de commande.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\nVous et votre crush 😍 étant occupés à vérifier que personne ne passe devant vous prendre vos burgers au moment où ils arriveront 🕙, vous ne pouvez pas vous préoccuper de votre crush 😞.\n\nC'est du travail « synchrone », vous être « synchronisés » avec le serveur/cuisinier 👨‍🍳. Vous devez attendre 🕙 et être présent au moment exact où le serveur/cuisinier 👨‍🍳 finira les burgers 🍔 et vous les donnera, sinon quelqu'un risque de vous les prendre.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\nPuis le serveur/cuisinier 👨‍🍳 revient enfin avec vos burgers 🍔, après un long moment d'attente 🕙 devant le comptoir.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\nVous prenez vos burgers 🍔 et allez à une table avec votre crush 😍\n\nVous les mangez, et vous avez terminé 🍔 ⏹.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\nDurant tout ce processus, il n'y a presque pas eu de discussions ou de flirts car la plupart de votre temps à été passé à attendre 🕙 devant le comptoir 😞.\n\n/// info\n\nIllustrations proposées par [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nDans ce scénario de burgers parallèles, vous êtes un ordinateur / programme 🤖 avec deux processeurs (vous et votre crush 😍) attendant 🕙 à deux et dédiant votre attention ⏯ à « attendre devant le comptoir » 🕙 pour une longue durée.\n\nLe fast-food a 8 processeurs (serveurs/cuisiniers) 👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳. Alors que le fast-food de burgers concurrents en avait 2 (un serveur et un cuisinier).\n\nEt pourtant l'expérience finale n'est pas meilleure 😞.\n\n---\n\nC'est donc l'histoire équivalente parallèle pour les burgers 🍔.\n\nPour un exemple plus courant dans la « vie réelle », imaginez une banque.\n\nJusqu'à récemment, la plupart des banques avaient plusieurs caisses (et banquiers) 👨‍💼👨‍💼👨‍💼👨‍💼 et une unique file d'attente 🕙🕙🕙🕙🕙🕙🕙🕙.\n\nTous les banquiers faisaient l'intégralité du travail avec chaque client avant de passer au suivant 👨‍💼⏯.\n\nEt vous deviez attendre 🕙 dans la file pendant un long moment ou vous perdiez votre place.\n\nVous n'auriez donc probablement pas envie d'amener votre crush 😍 avec vous à la banque 🏦.\n\n### Conclusion sur les burgers { #burger-conclusion }\n\nDans ce scénario des « burgers du fast-food avec votre crush », comme il y a beaucoup d'attente 🕙, il est très logique d'avoir un système concurrent ⏸🔀⏯.\n\nEt c'est le cas pour la plupart des applications web.\n\nVous aurez de nombreux, nombreux utilisateurs, mais votre serveur attendra 🕙 que leur connexion peu performante envoie des requêtes.\n\nPuis vous attendrez 🕙 de nouveau que leurs réponses reviennent.\n\nCette « attente » 🕙 se mesure en microsecondes, mais tout de même, en cumulé cela fait beaucoup d'attente.\n\nC'est pourquoi il est logique d'utiliser du code asynchrone ⏸🔀⏯ pour des APIs web.\n\nCe type d'asynchronicité est ce qui a rendu NodeJS populaire (bien que NodeJS ne soit pas parallèle) et c'est la force de Go en tant que langage de programmation.\n\nEt c'est le même niveau de performance que celui obtenu avec **FastAPI**.\n\nEt comme on peut avoir du parallélisme et de l'asynchronicité en même temps, on obtient des performances plus hautes que la plupart des frameworks NodeJS testés et égales à celles du Go, qui est un langage compilé plus proche du C [(tout ça grâce à Starlette)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).\n\n### Est-ce que la concurrence est mieux que le parallélisme ? { #is-concurrency-better-than-parallelism }\n\nNope ! C'est ça la morale de l'histoire.\n\nLa concurrence est différente du parallélisme. C'est mieux sur des scénarios **spécifiques** qui impliquent beaucoup d'attente. À cause de ça, c'est généralement bien meilleur que le parallélisme pour le développement d'applications web. Mais pas pour tout.\n\nDonc pour équilibrer tout ça, imaginez l'histoire suivante :\n\n> Vous devez nettoyer une grande et sale maison.\n\n*Oui, c'est toute l'histoire*.\n\n---\n\nIl n'y a plus d'attente 🕙 nulle part, juste beaucoup de travail à effectuer, dans différentes pièces de la maison.\n\nVous pourriez diviser en différentes sections comme avec les burgers, d'abord le salon, puis la cuisine, etc. Mais vous n'attendez 🕙 rien, vous ne faites que nettoyer et nettoyer, la séparation en sections ne changerait rien au final.\n\nCela prendrait autant de temps pour finir avec ou sans sections (concurrence) et vous auriez effectué la même quantité de travail.\n\nMais dans ce cas, si pouviez amener 8 ex-serveurs/cuisiniers/devenus-nettoyeurs 👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳👨‍🍳, et que chacun d'eux (plus vous) pouvait prendre une zone de la maison pour la nettoyer, vous pourriez faire tout le travail en parallèle, et finir plus tôt.\n\nDans ce scénario, chacun des nettoyeurs (vous y compris) serait un processeur, faisant sa partie du travail.\n\nEt comme la plupart du temps d'exécution est pris par du « vrai » travail (et non de l'attente), et que le travail dans un ordinateur est fait par un <abbr title=\"Central Processing Unit - Unité centrale de traitement\">CPU</abbr>, ce sont des problèmes dits « CPU bound ».\n\n---\n\nDes exemples communs d'opérations « CPU bound » sont les procédés qui requièrent des traitements mathématiques complexes.\n\nPar exemple :\n\n* Traitements d'**audio** et d'**images**.\n* La **vision par ordinateur** : une image est composée de millions de pixels, chaque pixel ayant 3 valeurs / couleurs, les traiter tous va nécessiter d'effectuer des traitements sur chaque pixel, et de préférence tous en même temps.\n* L'apprentissage automatique (ou **Machine Learning**) : cela nécessite de nombreuses multiplications de matrices et vecteurs. Imaginez une énorme feuille de calcul remplie de nombres que vous multiplierez entre eux tous au même moment.\n* L'apprentissage profond (ou **Deep Learning**) : est un sous-domaine du **Machine Learning**, donc les mêmes raisons s'appliquent. Avec la différence qu'il n'y a pas une unique feuille de calcul de nombres à multiplier, mais une énorme quantité d'entre elles, et dans de nombreux cas, on utilise un processeur spécial pour construire et / ou utiliser ces modèles.\n\n### Concurrence + Parallélisme : Web + Machine Learning { #concurrency-parallelism-web-machine-learning }\n\nAvec **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).\n\nMais vous pouvez aussi profiter du parallélisme et du multiprocessing (plusieurs processus s'exécutant en parallèle) afin de gérer des charges **CPU bound** qui sont récurrentes dans les systèmes de *Machine Learning*.\n\nÇa, ajouté au fait que Python soit le langage le plus populaire pour la **Data Science**, le **Machine Learning** et surtout le **Deep Learning**, font de **FastAPI** un très bon choix pour les APIs et applications de **Data Science** / **Machine Learning**.\n\nPour comprendre comment mettre en place ce parallélisme en production, allez lire la section [Déploiement](deployment/index.md).\n\n## `async` et `await` { #async-and-await }\n\nLes versions modernes de Python ont une manière très intuitive de définir le code asynchrone, tout en gardant une apparence de code « séquentiel » classique en laissant Python faire l'attente pour vous au bon moment.\n\nPour une opération qui nécessite de l'attente avant de donner un résultat et qui supporte ces nouvelles fonctionnalités Python, vous pouvez l'utiliser comme tel :\n\n```Python\nburgers = await get_burgers(2)\n```\n\nLe mot-clé important ici est `await`. Il informe Python qu'il faut attendre ⏸ que `get_burgers(2)` finisse d'effectuer ses opérations 🕙 avant de stocker les résultats dans la variable `burgers`. Grâce à cela, Python saura qu'il peut aller effectuer d'autres opérations 🔀 ⏯ pendant ce temps (comme par exemple recevoir une autre requête).\n\nPour que `await` fonctionne, il doit être placé dans une fonction qui supporte l'asynchronicité. Pour que ça soit le cas, il faut déclarer cette dernière avec `async def` :\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # Opérations asynchrones pour créer les burgers\n    return burgers\n```\n\n... et non `def` :\n\n```Python hl_lines=\"2\"\n# Ceci n'est pas asynchrone\ndef get_sequential_burgers(number: int):\n    # Opérations séquentielles pour créer les burgers\n    return burgers\n```\n\nAvec `async def`, Python sait que dans cette fonction il doit prendre en compte les expressions `await`, et qu'il peut mettre en pause ⏸ l'exécution de la fonction pour aller faire autre chose 🔀 avant de revenir.\n\nPour appeler une fonction définie avec `async def`, vous devez utiliser `await`. Donc ceci ne marche pas :\n\n```Python\n# Ceci ne fonctionne pas, car get_burgers a été défini avec async def\nburgers = get_burgers(2)\n```\n\n---\n\nDonc, si vous utilisez une bibliothèque qui nécessite que ses fonctions soient appelées avec `await`, vous devez définir la *fonction de chemin d'accès* en utilisant `async def` comme dans :\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### Plus de détails techniques { #more-technical-details }\n\nVous avez donc compris que `await` peut seulement être utilisé dans des fonctions définies avec `async def`.\n\nMais en même temps, les fonctions définies avec `async def` doivent être appelées avec `await` et donc dans des fonctions définies elles aussi avec `async def`.\n\nVous avez donc remarqué ce paradoxe d'œuf et de la poule, comment appelle-t-on la première fonction `async` ?\n\nSi vous utilisez **FastAPI**, pas besoin de vous en inquiéter, car cette « première » fonction sera votre *fonction de chemin d'accès* ; et **FastAPI** saura comment arriver au résultat attendu.\n\nMais si vous souhaitez utiliser `async` / `await` sans FastAPI, vous pouvez également le faire.\n\n### Écrire votre propre code async { #write-your-own-async-code }\n\nStarlette (et **FastAPI**) s’appuie sur [AnyIO](https://anyio.readthedocs.io/en/stable/), ce qui le rend compatible à la fois avec la bibliothèque standard [asyncio](https://docs.python.org/3/library/asyncio-task.html) de Python et avec [Trio](https://trio.readthedocs.io/en/stable/).\n\nEn particulier, vous pouvez utiliser directement [AnyIO](https://anyio.readthedocs.io/en/stable/) pour vos cas d’usage de concurrence avancés qui nécessitent des schémas plus élaborés dans votre propre code.\n\nEt même si vous n’utilisiez pas FastAPI, vous pourriez aussi écrire vos propres applications async avec [AnyIO](https://anyio.readthedocs.io/en/stable/) pour une grande compatibilité et pour bénéficier de ses avantages (par ex. la « structured concurrency »).\n\nJ’ai créé une autre bibliothèque au-dessus d’AnyIO, comme une fine surcouche, pour améliorer un peu les annotations de type et obtenir une meilleure **autocomplétion**, des **erreurs en ligne**, etc. Elle propose également une introduction et un tutoriel accessibles pour vous aider à **comprendre** et écrire **votre propre code async** : [Asyncer](https://asyncer.tiangolo.com/). Elle sera particulièrement utile si vous devez **combiner du code async avec du code classique** (bloquant/synchrone).\n\n### Autres formes de code asynchrone { #other-forms-of-asynchronous-code }\n\nL'utilisation d'`async` et `await` est relativement nouvelle dans ce langage.\n\nMais cela rend la programmation asynchrone bien plus simple.\n\nCette même syntaxe (ou presque) a aussi été incluse récemment dans les versions modernes de JavaScript (dans les navigateurs et NodeJS).\n\nMais avant ça, gérer du code asynchrone était bien plus complexe et difficile.\n\nDans les versions précédentes de Python, vous auriez utilisé des threads ou [Gevent](https://www.gevent.org/).  Mais le code aurait été bien plus difficile à comprendre, débugger, et concevoir.\n\nDans les versions précédentes de JavaScript côté navigateur / NodeJS, vous auriez utilisé des « callbacks ». Menant potentiellement à ce que l'on appelle le « callback hell ».\n\n## Coroutines { #coroutines }\n\n« Coroutine » est juste un terme élaboré pour désigner ce qui est retourné par une fonction définie avec `async def`. Python sait que c'est comme une fonction classique qui va démarrer à un moment et terminer à un autre, mais qu'elle peut aussi être mise en pause ⏸, du moment qu'il y a un `await` dans son contenu.\n\nMais toutes ces fonctionnalités d'utilisation de code asynchrone avec `async` et `await` sont souvent résumées comme l'utilisation des « coroutines ». On peut comparer cela à la principale fonctionnalité clé de Go, les « Goroutines ».\n\n## Conclusion { #conclusion }\n\nReprenons la phrase du début de la page :\n\n> Les versions modernes de Python supportent le **code asynchrone** grâce aux **« coroutines »** avec les syntaxes **`async` et `await`**.\n\nCeci devrait être plus compréhensible désormais. ✨\n\nTout ceci est donc ce qui donne sa force à FastAPI (à travers Starlette) et lui permet d'avoir une performance aussi impressionnante.\n\n## Détails très techniques { #very-technical-details }\n\n/// warning | Alertes\n\nVous pouvez probablement ignorer cela.\n\nCe sont des détails très poussés sur comment **FastAPI** fonctionne en arrière-plan.\n\nSi vous avez de bonnes connaissances techniques (coroutines, threads, code bloquant, etc.) et êtes curieux de comment **FastAPI** gère `async def` versus le `def` classique, cette partie est faite pour vous.\n\n///\n\n### Fonctions de chemin d'accès { #path-operation-functions }\n\nQuand vous déclarez une *fonction de chemin d'accès* avec un `def` normal et non `async def`, elle est exécutée dans un groupe de threads (threadpool) externe qui est ensuite attendu, plutôt que d'être appelée directement (car cela bloquerait le serveur).\n\nSi vous venez d'un autre framework asynchrone qui ne fonctionne pas comme de la façon décrite ci-dessus et que vous êtes habitué à définir des *fonctions de chemin d'accès* basiques et purement calculatoires avec un simple `def` pour un faible gain de performance (environ 100 nanosecondes), veuillez noter que dans **FastAPI**, l'effet serait plutôt contraire. Dans ces cas-là, il vaut mieux utiliser `async def` à moins que votre *fonction de chemin d'accès* utilise du code qui effectue des opérations <abbr title=\"Input/Output - Entrées/Sorties: lecture ou écriture sur le disque, communications réseau.\">I/O</abbr> bloquantes.\n\nAu final, dans les deux situations, il est fort probable que **FastAPI** soit tout de même [plus rapide](index.md#performance) que (ou au moins de vitesse égale à) votre framework précédent.\n\n### Dépendances { #dependencies }\n\nLa même chose s'applique aux [dépendances](tutorial/dependencies/index.md). Si une dépendance est définie avec `def` plutôt que `async def`, elle est exécutée dans la threadpool externe.\n\n### Sous-dépendances { #sub-dependencies }\n\nVous pouvez avoir de multiples dépendances et [sous-dépendances](tutorial/dependencies/sub-dependencies.md) dépendant les unes des autres (en tant que paramètres de la définition de la *fonction de chemin d'accès*), certaines créées avec `async def` et d'autres avec `def`. Cela fonctionnerait aussi, et celles définies avec un simple `def` seraient exécutées sur un thread externe (venant de la threadpool) plutôt que d'être « attendues ».\n\n### Autres fonctions utilitaires { #other-utility-functions }\n\nToute autre fonction utilitaire que vous appelez directement peut être créée avec un classique `def` ou avec `async def` et FastAPI n'aura pas d'impact sur la façon dont vous l'appelez.\n\nContrairement aux fonctions que FastAPI appelle pour vous : les *fonctions de chemin d'accès* et dépendances.\n\nSi votre fonction utilitaire est une fonction classique définie avec `def`, elle sera appelée directement (telle qu'écrite dans votre code), pas dans une threadpool ; si la fonction est définie avec `async def` alors vous devrez attendre (avec `await`) que cette fonction se termine avant de passer à la suite du code.\n\n---\n\nEncore une fois, ce sont des détails très techniques qui peuvent être utiles si vous venez ici les chercher.\n\nSinon, les instructions de la section <a href=\"#in-a-hurry\">Vous êtes pressés ?</a> ci-dessus sont largement suffisantes.\n"
  },
  {
    "path": "docs/fr/docs/benchmarks.md",
    "content": "# Tests de performance { #benchmarks }\n\nLes benchmarks indépendants de TechEmpower montrent que les applications **FastAPI** s’exécutant avec Uvicorn sont [parmi les frameworks Python les plus rapides disponibles](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), seulement en dessous de Starlette et Uvicorn eux‑mêmes (tous deux utilisés en interne par FastAPI).\n\nMais en prêtant attention aux tests de performance et aux comparaisons, vous devez tenir compte de ce qui suit.\n\n## Tests de performance et rapidité { #benchmarks-and-speed }\n\nLorsque vous vérifiez les tests de performance, il est commun de voir plusieurs outils de différents types comparés comme équivalents.\n\nEn particulier, on voit Uvicorn, Starlette et FastAPI comparés (parmi de nombreux autres outils).\n\nPlus le problème résolu par un outil est simple, meilleures seront les performances obtenues. Et la plupart des tests de performance ne prennent pas en compte les fonctionnalités additionnelles fournies par les outils.\n\nLa hiérarchie est la suivante :\n\n* **Uvicorn** : un serveur ASGI\n    * **Starlette** : (utilise Uvicorn) un microframework web\n        * **FastAPI**: (utilise Starlette) un microframework pour API disposant de fonctionnalités additionnelles pour la création d'API, avec la validation des données, etc.\n\n* **Uvicorn** :\n    * A les meilleures performances, étant donné qu'il n'a pas beaucoup de code mis à part le serveur en lui‑même.\n    * On n'écrit pas une application directement avec Uvicorn. Cela signifie que le code devrait inclure, au minimum, plus ou moins tout le code offert par Starlette (ou **FastAPI**). Et si on fait cela, l'application finale aura la même surcharge que si on avait utilisé un framework, tout en minimisant la quantité de code et les bugs.\n    * Si on compare Uvicorn, il faut le comparer à d'autres serveurs d'applications comme Daphne, Hypercorn, uWSGI, etc.\n* **Starlette** :\n    * A les secondes meilleures performances après Uvicorn. En réalité, Starlette utilise Uvicorn. De ce fait, il ne peut qu’être plus « lent » qu'Uvicorn car il requiert l'exécution de plus de code.\n    * Cependant, il apporte les outils pour construire une application web simple, avec un routage basé sur des chemins, etc.\n    * Si on compare Starlette, il faut le comparer à d'autres frameworks web (ou microframeworks) comme Sanic, Flask, Django, etc.\n* **FastAPI** :\n    * Comme Starlette utilise Uvicorn et ne peut donc pas être plus rapide que lui, **FastAPI** utilise Starlette et ne peut donc pas être plus rapide que lui.\n    * FastAPI apporte des fonctionnalités supplémentaires à Starlette. Des fonctionnalités dont vous avez presque toujours besoin lors de la création d'une API, comme la validation des données et la sérialisation. En l'utilisant, vous obtenez une documentation automatique « gratuitement » (la documentation automatique n'ajoute même pas de surcharge à l’exécution, elle est générée au démarrage).\n    * Si on n'utilisait pas FastAPI mais directement Starlette (ou un autre outil comme Sanic, Flask, Responder, etc.), il faudrait implémenter toute la validation des données et la sérialisation soi‑même. L'application finale aurait donc la même surcharge que si elle avait été construite avec FastAPI. Et dans de nombreux cas, cette validation des données et cette sérialisation représentent la plus grande quantité de code écrite dans les applications.\n    * De ce fait, en utilisant FastAPI on minimise le temps de développement, les bugs, le nombre de lignes de code, et on obtient probablement les mêmes performances (voire de meilleures performances) que l'on aurait pu avoir sans ce framework (car il aurait fallu tout implémenter dans votre code).\n    * Si on compare FastAPI, il faut le comparer à d'autres frameworks d’application web (ou ensembles d'outils) qui fournissent la validation des données, la sérialisation et la documentation, comme Flask-apispec, NestJS, Molten, etc. Des frameworks avec validation des données, sérialisation et documentation automatiques intégrées.\n"
  },
  {
    "path": "docs/fr/docs/deployment/cloud.md",
    "content": "# Déployer FastAPI sur des fournisseurs cloud { #deploy-fastapi-on-cloud-providers }\n\nVous pouvez utiliser pratiquement n'importe quel fournisseur cloud pour déployer votre application FastAPI.\n\nDans la plupart des cas, les principaux fournisseurs cloud proposent des guides pour déployer FastAPI avec leurs services.\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** est créée par le même auteur et l'équipe à l'origine de **FastAPI**.\n\nElle simplifie le processus de **création**, de **déploiement** et **d'accès** à une API avec un effort minimal.\n\nElle apporte la même **expérience développeur** que celle de la création d'applications avec FastAPI au **déploiement** de celles-ci dans le cloud. 🎉\n\nFastAPI Cloud est le sponsor principal et le financeur des projets open source *FastAPI and friends*. ✨\n\n## Fournisseurs cloud - Sponsors { #cloud-providers-sponsors }\n\nD'autres fournisseurs cloud ✨ [**parrainent FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ également. 🙇\n\nVous pouvez également envisager ces fournisseurs pour suivre leurs guides et essayer leurs services :\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/fr/docs/deployment/concepts.md",
    "content": "# Concepts de déploiement { #deployments-concepts }\n\nLorsque vous déployez une application **FastAPI**, ou en fait n'importe quel type de web API, il existe plusieurs concepts qui vous importent probablement, et en les utilisant vous pouvez trouver la manière la **plus appropriée** de **déployer votre application**.\n\nParmi les concepts importants, on trouve :\n\n* Sécurité - HTTPS\n* Exécuter au démarrage\n* Redémarrages\n* Réplication (le nombre de processus en cours d'exécution)\n* Mémoire\n* Étapes préalables avant de démarrer\n\nNous allons voir comment ils affectent les **déploiements**.\n\nAu final, l'objectif ultime est de pouvoir **servir vos clients d'API** de manière **sécurisée**, d'**éviter les interruptions**, et d'utiliser les **ressources de calcul** (par exemple des serveurs/VM distants) aussi efficacement que possible. 🚀\n\nJe vais vous en dire un peu plus ici sur ces **concepts**, ce qui devrait vous donner l'**intuition** nécessaire pour décider comment déployer votre API dans des environnements très différents, voire même dans des environnements **futurs** qui n'existent pas encore.\n\nEn tenant compte de ces concepts, vous serez en mesure **d'évaluer et de concevoir** la meilleure façon de déployer **vos propres API**.\n\nDans les chapitres suivants, je vous donnerai des **recettes concrètes** pour déployer des applications FastAPI.\n\nMais pour l'instant, voyons ces **idées conceptuelles** importantes. Ces concepts s'appliquent aussi à tout autre type de web API. 💡\n\n## Sécurité - HTTPS { #security-https }\n\nDans le [chapitre précédent à propos de HTTPS](https.md), nous avons vu comment HTTPS fournit le chiffrement pour votre API.\n\nNous avons également vu que HTTPS est normalement fourni par un composant **externe** à votre serveur d'application, un **TLS Termination Proxy**.\n\nEt il doit y avoir quelque chose chargé de **renouveler les certificats HTTPS** ; cela peut être le même composant ou quelque chose de différent.\n\n### Exemples d’outils pour HTTPS { #example-tools-for-https }\n\nParmi les outils que vous pourriez utiliser comme TLS Termination Proxy :\n\n* Traefik\n    * Gère automatiquement le renouvellement des certificats ✨\n* Caddy\n    * Gère automatiquement le renouvellement des certificats ✨\n* Nginx\n    * Avec un composant externe comme Certbot pour le renouvellement des certificats\n* HAProxy\n    * Avec un composant externe comme Certbot pour le renouvellement des certificats\n* Kubernetes avec un Ingress Controller comme Nginx\n    * Avec un composant externe comme cert-manager pour le renouvellement des certificats\n* Pris en charge en interne par un fournisseur cloud dans le cadre de ses services (lisez ci-dessous 👇)\n\nUne autre option consiste à utiliser un **service cloud** qui fait davantage de travail, y compris la mise en place de HTTPS. Il peut avoir certaines restrictions ou vous facturer davantage, etc. Mais dans ce cas, vous n'auriez pas à configurer vous‑même un TLS Termination Proxy.\n\nJe vous montrerai des exemples concrets dans les prochains chapitres.\n\n---\n\nLes concepts suivants à considérer concernent tous le programme qui exécute votre API réelle (par ex. Uvicorn).\n\n## Programme et processus { #program-and-process }\n\nNous allons beaucoup parler du « **processus** » en cours d'exécution, il est donc utile d'être clair sur ce que cela signifie, et sur la différence avec le mot « **programme** ».\n\n### Qu'est-ce qu'un programme { #what-is-a-program }\n\nLe mot **programme** est couramment utilisé pour décrire plusieurs choses :\n\n* Le **code** que vous écrivez, les **fichiers Python**.\n* Le **fichier** qui peut être **exécuté** par le système d'exploitation, par exemple : `python`, `python.exe` ou `uvicorn`.\n* Un programme particulier lorsqu'il **s'exécute** sur le système d'exploitation, utilisant le CPU et stockant des choses en mémoire. On appelle aussi cela un **processus**.\n\n### Qu'est-ce qu'un processus { #what-is-a-process }\n\nLe mot **processus** est normalement utilisé de manière plus spécifique, en ne se référant qu'à l'élément qui s'exécute dans le système d'exploitation (comme dans le dernier point ci‑dessus) :\n\n* Un programme particulier lorsqu'il **s'exécute** sur le système d'exploitation.\n    * Cela ne se réfère ni au fichier, ni au code ; cela se réfère **spécifiquement** à l'élément qui est **exécuté** et géré par le système d'exploitation.\n* N'importe quel programme, n'importe quel code, **ne peut faire des choses** que lorsqu'il est **exécuté**. Donc, lorsqu'il y a un **processus en cours**.\n* Le processus peut être **arrêté** (ou « tué ») par vous ou par le système d'exploitation. À ce moment‑là, il cesse de s'exécuter/d'être exécuté, et il **ne peut plus rien faire**.\n* Chaque application que vous avez en cours d'exécution sur votre ordinateur a un processus derrière elle, chaque programme lancé, chaque fenêtre, etc. Et il y a normalement de nombreux processus exécutés **en même temps** tant qu'un ordinateur est allumé.\n* Il peut y avoir **plusieurs processus** du **même programme** exécutés simultanément.\n\nSi vous ouvrez le « gestionnaire des tâches » ou le « moniteur système » (ou des outils similaires) de votre système d'exploitation, vous verrez nombre de ces processus en cours d'exécution.\n\nEt, par exemple, vous verrez probablement qu'il y a plusieurs processus exécutant le même navigateur (Firefox, Chrome, Edge, etc.). Ils exécutent normalement un processus par onglet, plus quelques processus supplémentaires.\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\nMaintenant que nous connaissons la différence entre les termes **processus** et **programme**, continuons à parler des déploiements.\n\n## Exécuter au démarrage { #running-on-startup }\n\nDans la plupart des cas, lorsque vous créez une web API, vous voulez qu'elle **tourne en permanence**, sans interruption, afin que vos clients puissent toujours y accéder. Bien sûr, sauf si vous avez une raison spécifique de ne vouloir l'exécuter que dans certaines situations, mais la plupart du temps vous la voulez constamment en cours et **disponible**.\n\n### Sur un serveur distant { #in-a-remote-server }\n\nLorsque vous configurez un serveur distant (un serveur cloud, une machine virtuelle, etc.), la chose la plus simple à faire est d'utiliser `fastapi run` (qui utilise Uvicorn) ou quelque chose de similaire, manuellement, de la même manière que lorsque vous développez en local.\n\nEt cela fonctionnera et sera utile **pendant le développement**.\n\nMais si votre connexion au serveur est coupée, le **processus en cours** va probablement s'arrêter.\n\nEt si le serveur est redémarré (par exemple après des mises à jour, ou des migrations chez le fournisseur cloud) vous **ne le remarquerez probablement pas**. Et à cause de cela, vous ne saurez même pas que vous devez redémarrer le processus manuellement. Ainsi, votre API restera tout simplement à l'arrêt. 😱\n\n### Lancer automatiquement au démarrage { #run-automatically-on-startup }\n\nEn général, vous voudrez probablement que le programme serveur (par ex. Uvicorn) soit démarré automatiquement au démarrage du serveur, et sans aucune **intervention humaine**, afin d'avoir en permanence un processus exécutant votre API (par ex. Uvicorn exécutant votre app FastAPI).\n\n### Programme séparé { #separate-program }\n\nPour y parvenir, vous aurez normalement un **programme séparé** qui s'assure que votre application est lancée au démarrage. Et dans de nombreux cas, il s'assurera également que d'autres composants ou applications sont également lancés, par exemple une base de données.\n\n### Exemples d’outils pour lancer au démarrage { #example-tools-to-run-at-startup }\n\nVoici quelques exemples d'outils capables de faire ce travail :\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker en mode Swarm\n* Systemd\n* Supervisor\n* Pris en charge en interne par un fournisseur cloud dans le cadre de ses services\n* Autres ...\n\nJe vous donnerai des exemples plus concrets dans les prochains chapitres.\n\n## Redémarrages { #restarts }\n\nDe la même manière que vous voulez vous assurer que votre application est lancée au démarrage, vous voulez probablement aussi vous assurer qu'elle est **redémarrée** après des échecs.\n\n### Nous faisons des erreurs { #we-make-mistakes }\n\nNous, humains, faisons des **erreurs**, tout le temps. Les logiciels ont presque *toujours* des **bugs** cachés à différents endroits. 🐛\n\nEt nous, développeurs, continuons à améliorer le code au fur et à mesure que nous trouvons ces bugs et que nous implémentons de nouvelles fonctionnalités (en ajoutant éventuellement de nouveaux bugs aussi 😅).\n\n### Petites erreurs gérées automatiquement { #small-errors-automatically-handled }\n\nLors de la création de web API avec FastAPI, s'il y a une erreur dans notre code, FastAPI la contiendra normalement à la seule requête qui a déclenché l'erreur. 🛡\n\nLe client recevra un **500 Internal Server Error** pour cette requête, mais l'application continuera de fonctionner pour les requêtes suivantes au lieu de simplement s'effondrer complètement.\n\n### Erreurs plus importantes - plantages { #bigger-errors-crashes }\n\nNéanmoins, il peut y avoir des cas où nous écrivons du code qui **fait planter l'application entière**, faisant planter Uvicorn et Python. 💥\n\nEt malgré cela, vous ne voudrez probablement pas que l'application reste à l'arrêt parce qu'il y a eu une erreur à un endroit ; vous voudrez probablement qu'elle **continue de tourner**, au moins pour les *chemins d'accès* qui ne sont pas cassés.\n\n### Redémarrer après un plantage { #restart-after-crash }\n\nMais dans ces cas avec de très mauvaises erreurs qui font planter le **processus** en cours, vous voudrez un composant externe chargé de **redémarrer** le processus, au moins quelques fois ...\n\n/// tip | Astuce\n\n... Bien que si l'application entière **plante immédiatement**, il n'est probablement pas logique de continuer à la redémarrer indéfiniment. Mais dans ces cas, vous le remarquerez probablement pendant le développement, ou au moins juste après le déploiement.\n\nConcentrons‑nous donc sur les cas principaux, où elle pourrait planter entièrement dans certaines situations particulières **à l'avenir**, et où il est toujours logique de la redémarrer.\n\n///\n\nVous voudrez probablement que l'élément chargé de redémarrer votre application soit un **composant externe**, car à ce stade, l'application elle‑même avec Uvicorn et Python a déjà planté, donc il n'y a rien dans le même code de la même app qui pourrait y faire quoi que ce soit.\n\n### Exemples d’outils pour redémarrer automatiquement { #example-tools-to-restart-automatically }\n\nDans la plupart des cas, le même outil qui est utilisé pour **lancer le programme au démarrage** est également utilisé pour gérer les **redémarrages** automatiques.\n\nPar exemple, cela peut être géré par :\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker en mode Swarm\n* Systemd\n* Supervisor\n* Pris en charge en interne par un fournisseur cloud dans le cadre de ses services\n* Autres ...\n\n## Réplication - Processus et mémoire { #replication-processes-and-memory }\n\nAvec une application FastAPI, en utilisant un programme serveur comme la commande `fastapi` qui exécute Uvicorn, l'exécuter une fois dans **un processus** peut servir plusieurs clients simultanément.\n\nMais dans de nombreux cas, vous voudrez exécuter plusieurs processus de travail en même temps.\n\n### Multiples processus - Workers { #multiple-processes-workers }\n\nSi vous avez plus de clients que ce qu'un seul processus peut gérer (par exemple si la machine virtuelle n'est pas très grande) et que vous avez **plusieurs cœurs** dans le CPU du serveur, alors vous pouvez avoir **plusieurs processus** exécutant la même application simultanément, et distribuer toutes les requêtes entre eux.\n\nQuand vous exécutez **plusieurs processus** du même programme d'API, on les appelle couramment des **workers**.\n\n### Processus workers et ports { #worker-processes-and-ports }\n\nRappelez‑vous, d'après les documents [À propos de HTTPS](https.md), qu'un seul processus peut écouter une combinaison de port et d'adresse IP sur un serveur ?\n\nC'est toujours vrai.\n\nDonc, pour pouvoir avoir **plusieurs processus** en même temps, il doit y avoir un **seul processus à l'écoute sur un port** qui transmet ensuite la communication à chaque processus worker d'une manière ou d'une autre.\n\n### Mémoire par processus { #memory-per-process }\n\nMaintenant, lorsque le programme charge des choses en mémoire, par exemple, un modèle de machine learning dans une variable, ou le contenu d'un gros fichier dans une variable, tout cela **consomme une partie de la mémoire (RAM)** du serveur.\n\nEt plusieurs processus **ne partagent normalement pas de mémoire**. Cela signifie que chaque processus en cours a ses propres éléments, variables et mémoire. Et si vous consommez une grande quantité de mémoire dans votre code, **chaque processus** consommera une quantité équivalente de mémoire.\n\n### Mémoire du serveur { #server-memory }\n\nPar exemple, si votre code charge un modèle de Machine Learning de **1 Go**, lorsque vous exécutez un processus avec votre API, il consommera au moins 1 Go de RAM. Et si vous démarrez **4 processus** (4 workers), chacun consommera 1 Go de RAM. Donc au total, votre API consommera **4 Go de RAM**.\n\nEt si votre serveur distant ou votre machine virtuelle n'a que 3 Go de RAM, essayer de charger plus de 4 Go de RAM posera problème. 🚨\n\n### Multiples processus - Un exemple { #multiple-processes-an-example }\n\nDans cet exemple, il y a un **processus gestionnaire** qui démarre et contrôle deux **processus workers**.\n\nCe processus gestionnaire serait probablement celui qui écoute sur le **port** de l'IP. Et il transmettrait toute la communication aux processus workers.\n\nCes processus workers seraient ceux qui exécutent votre application, ils effectueraient les calculs principaux pour recevoir une **requête** et renvoyer une **réponse**, et ils chargeraient tout ce que vous mettez dans des variables en RAM.\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\nEt bien sûr, la même machine aurait probablement **d'autres processus** en cours d'exécution également, en plus de votre application.\n\nUn détail intéressant est que le pourcentage de **CPU utilisé** par chaque processus peut **varier** fortement dans le temps, mais la **mémoire (RAM)** reste normalement plus ou moins **stable**.\n\nSi vous avez une API qui effectue une quantité comparable de calculs à chaque fois et que vous avez beaucoup de clients, alors l'**utilisation du CPU** sera probablement *également stable* (au lieu de monter et descendre rapidement en permanence).\n\n### Exemples d’outils et de stratégies de réplication { #examples-of-replication-tools-and-strategies }\n\nIl peut y avoir plusieurs approches pour y parvenir, et je vous en dirai plus sur des stratégies spécifiques dans les prochains chapitres, par exemple en parlant de Docker et des conteneurs.\n\nLa principale contrainte à considérer est qu'il doit y avoir un **seul** composant gérant le **port** sur l'**IP publique**. Et il doit ensuite avoir un moyen de **transmettre** la communication aux **processus/workers** répliqués.\n\nVoici quelques combinaisons et stratégies possibles :\n\n* **Uvicorn** avec `--workers`\n    * Un **gestionnaire de processus** Uvicorn écouterait sur l'**IP** et le **port**, et il démarrerait **plusieurs processus workers Uvicorn**.\n* **Kubernetes** et autres systèmes **de conteneurs** distribués\n    * Quelque chose dans la couche **Kubernetes** écouterait sur l'**IP** et le **port**. La réplication se ferait en ayant **plusieurs conteneurs**, chacun avec **un processus Uvicorn** en cours.\n* **Services cloud** qui s'en chargent pour vous\n    * Le service cloud **gérera probablement la réplication pour vous**. Il vous permettra éventuellement de définir **un processus à exécuter**, ou une **image de conteneur** à utiliser ; dans tous les cas, ce sera très probablement **un seul processus Uvicorn**, et le service cloud sera chargé de le répliquer.\n\n/// tip | Astuce\n\nNe vous inquiétez pas si certains de ces éléments concernant les **conteneurs**, Docker ou Kubernetes ne sont pas encore très clairs.\n\nJe vous en dirai plus sur les images de conteneurs, Docker, Kubernetes, etc. dans un chapitre à venir : [FastAPI dans des conteneurs - Docker](docker.md).\n\n///\n\n## Étapes préalables avant de démarrer { #previous-steps-before-starting }\n\nIl existe de nombreux cas où vous souhaitez effectuer certaines étapes **avant de démarrer** votre application.\n\nPar exemple, vous pourriez vouloir exécuter des **migrations de base de données**.\n\nMais dans la plupart des cas, vous voudrez effectuer ces étapes **une seule fois**.\n\nVous voudrez donc avoir un **processus unique** pour effectuer ces **étapes préalables**, avant de démarrer l'application.\n\nEt vous devez vous assurer que c'est un processus unique qui exécute ces étapes préalables *même si*, ensuite, vous démarrez **plusieurs processus** (plusieurs workers) pour l'application elle‑même. Si ces étapes étaient exécutées par **plusieurs processus**, ils **dupliqueraient** le travail en l'exécutant **en parallèle**, et si les étapes étaient délicates comme une migration de base de données, elles pourraient entrer en conflit les unes avec les autres.\n\nBien sûr, il y a des cas où il n'y a aucun problème à exécuter les étapes préalables plusieurs fois ; dans ce cas, c'est beaucoup plus simple à gérer.\n\n/// tip | Astuce\n\nGardez aussi à l'esprit que selon votre configuration, dans certains cas vous **n'aurez peut‑être même pas besoin d'étapes préalables** avant de démarrer votre application.\n\nDans ce cas, vous n'auriez pas à vous soucier de tout cela. 🤷\n\n///\n\n### Exemples de stratégies pour les étapes préalables { #examples-of-previous-steps-strategies }\n\nCela **dépendra fortement** de la manière dont vous **déployez votre système**, et sera probablement lié à votre manière de démarrer les programmes, de gérer les redémarrages, etc.\n\nVoici quelques idées possibles :\n\n* Un « Init Container » dans Kubernetes qui s'exécute avant votre conteneur d'application\n* Un script bash qui exécute les étapes préalables puis démarre votre application\n    * Vous aurez toujours besoin d'un moyen de démarrer/redémarrer *ce* script bash, de détecter les erreurs, etc.\n\n/// tip | Astuce\n\nJe vous donnerai des exemples plus concrets pour faire cela avec des conteneurs dans un chapitre à venir : [FastAPI dans des conteneurs - Docker](docker.md).\n\n///\n\n## Utilisation des ressources { #resource-utilization }\n\nVotre ou vos serveurs constituent une **ressource** que vos programmes peuvent consommer ou **utiliser** : le temps de calcul des CPU et la mémoire RAM disponible.\n\nQuelle quantité des ressources système voulez‑vous consommer/utiliser ? Il peut être facile de penser « pas beaucoup », mais en réalité, vous voudrez probablement consommer **le plus possible sans planter**.\n\nSi vous payez pour 3 serveurs mais que vous n'utilisez qu'un petit peu de leur RAM et CPU, vous **gaspillez probablement de l'argent** 💸, et **gaspillez probablement l'électricité des serveurs** 🌎, etc.\n\nDans ce cas, il pourrait être préférable de n'avoir que 2 serveurs et d'utiliser un pourcentage plus élevé de leurs ressources (CPU, mémoire, disque, bande passante réseau, etc.).\n\nÀ l'inverse, si vous avez 2 serveurs et que vous utilisez **100 % de leur CPU et de leur RAM**, à un moment donné un processus demandera plus de mémoire, et le serveur devra utiliser le disque comme « mémoire » (ce qui peut être des milliers de fois plus lent), voire **planter**. Ou un processus pourrait avoir besoin de faire un calcul et devrait attendre que le CPU soit à nouveau libre.\n\nDans ce cas, il serait préférable d'obtenir **un serveur supplémentaire** et d'y exécuter certains processus afin qu'ils aient tous **suffisamment de RAM et de temps CPU**.\n\nIl est également possible que, pour une raison quelconque, vous ayez un **pic** d'utilisation de votre API. Peut‑être qu'elle devient virale, ou peut‑être que d'autres services ou bots commencent à l'utiliser. Et vous voudrez peut‑être disposer de ressources supplémentaires pour être en sécurité dans ces cas.\n\nVous pouvez définir un **chiffre arbitraire** comme cible, par exemple **entre 50 % et 90 %** d'utilisation des ressources. L'idée est que ce sont probablement les principaux éléments que vous voudrez mesurer et utiliser pour ajuster vos déploiements.\n\nVous pouvez utiliser des outils simples comme `htop` pour voir le CPU et la RAM utilisés sur votre serveur ou la quantité utilisée par chaque processus. Ou vous pouvez utiliser des outils de supervision plus complexes, éventuellement distribués sur plusieurs serveurs, etc.\n\n## Récapitulatif { #recap }\n\nVous venez de lire ici certains des principaux concepts que vous devrez probablement garder à l'esprit lorsque vous décidez comment déployer votre application :\n\n* Sécurité - HTTPS\n* Exécuter au démarrage\n* Redémarrages\n* Réplication (le nombre de processus en cours d'exécution)\n* Mémoire\n* Étapes préalables avant de démarrer\n\nComprendre ces idées et comment les appliquer devrait vous donner l'intuition nécessaire pour prendre toutes les décisions lors de la configuration et de l'ajustement de vos déploiements. 🤓\n\nDans les sections suivantes, je vous donnerai des exemples plus concrets de stratégies possibles à suivre. 🚀\n"
  },
  {
    "path": "docs/fr/docs/deployment/docker.md",
    "content": "# FastAPI dans des conteneurs - Docker { #fastapi-in-containers-docker }\n\nLors du déploiement d'applications FastAPI, une approche courante consiste à construire une **image de conteneur Linux**. C'est généralement fait avec [**Docker**](https://www.docker.com/). Vous pouvez ensuite déployer cette image de conteneur de plusieurs façons possibles.\n\nL'utilisation de conteneurs Linux présente plusieurs avantages, notamment la **sécurité**, la **réplicabilité**, la **simplicité**, entre autres.\n\n/// tip | Astuce\n\nVous êtes pressé et vous connaissez déjà tout ça ? Allez directement au [`Dockerfile` ci-dessous 👇](#build-a-docker-image-for-fastapi).\n\n///\n\n<details>\n<summary>Aperçu du Dockerfile 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# Si vous exécutez derrière un proxy comme Nginx ou Traefik, ajoutez --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## Qu'est-ce qu'un conteneur { #what-is-a-container }\n\nLes conteneurs (principalement les conteneurs Linux) sont un moyen très **léger** d'empaqueter des applications, y compris toutes leurs dépendances et les fichiers nécessaires, tout en les isolant des autres conteneurs (autres applications ou composants) dans le même système.\n\nLes conteneurs Linux s'exécutent en utilisant le même noyau Linux que l'hôte (machine, machine virtuelle, serveur cloud, etc.). Cela signifie simplement qu'ils sont très légers (comparés à des machines virtuelles complètes émulant un système d'exploitation entier).\n\nAinsi, les conteneurs consomment **peu de ressources**, une quantité comparable à l'exécution directe des processus (alors qu'une machine virtuelle consommerait beaucoup plus).\n\nLes conteneurs ont également leurs propres processus d'exécution **isolés** (généralement un seul processus), leur système de fichiers et leur réseau, ce qui simplifie le déploiement, la sécurité, le développement, etc.\n\n## Qu'est-ce qu'une image de conteneur { #what-is-a-container-image }\n\nUn **conteneur** s'exécute à partir d'une **image de conteneur**.\n\nUne image de conteneur est une version **statique** de tous les fichiers, des variables d'environnement et de la commande/le programme par défaut devant être présents dans un conteneur. Ici, **statique** signifie que l'**image** du conteneur ne s'exécute pas, elle n'est pas en cours d'exécution, ce ne sont que les fichiers et métadonnées empaquetés.\n\nPar opposition à une « **image de conteneur** » qui correspond aux contenus statiques stockés, un « **conteneur** » fait normalement référence à l'instance en cours d'exécution, la chose qui est **exécutée**.\n\nLorsque le **conteneur** est démarré et en cours d'exécution (démarré à partir d'une **image de conteneur**), il peut créer ou modifier des fichiers, des variables d'environnement, etc. Ces changements n'existeront que dans ce conteneur, mais ne persisteront pas dans l'image de conteneur sous-jacente (ils ne seront pas enregistrés sur le disque).\n\nUne image de conteneur est comparable au **programme** et à ses contenus, par exemple `python` et un fichier `main.py`.\n\nEt le **conteneur** lui-même (par opposition à l'**image de conteneur**) est l'instance en cours d'exécution réelle de l'image, comparable à un **processus**. En fait, un conteneur ne fonctionne que lorsqu'il a un **processus en cours d'exécution** (et normalement, il s'agit d'un seul processus). Le conteneur s'arrête lorsqu'aucun processus n'y est en cours d'exécution.\n\n## Images de conteneur { #container-images }\n\nDocker a été l'un des principaux outils pour créer et gérer des **images de conteneur** et des **conteneurs**.\n\nEt il existe un [Docker Hub](https://hub.docker.com/) public avec des **images de conteneur officielles** pré-construites pour de nombreux outils, environnements, bases de données et applications.\n\nPar exemple, il existe une [image Python officielle](https://hub.docker.com/_/python).\n\nEt il existe beaucoup d'autres images pour différentes choses comme des bases de données, par exemple :\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis), etc.\n\nEn utilisant une image de conteneur pré-construite, il est très facile de **combiner** et d'utiliser différents outils. Par exemple, pour essayer une nouvelle base de données. Dans la plupart des cas, vous pouvez utiliser les **images officielles** et simplement les configurer avec des variables d'environnement.\n\nAinsi, dans de nombreux cas, vous pouvez apprendre les conteneurs et Docker et réutiliser ces connaissances avec de nombreux outils et composants différents.\n\nVous exécuteriez donc **plusieurs conteneurs** avec des éléments différents, comme une base de données, une application Python, un serveur web avec une application frontend React, et les connecter entre eux via leur réseau interne.\n\nTous les systèmes de gestion de conteneurs (comme Docker ou Kubernetes) disposent de ces fonctionnalités réseau intégrées.\n\n## Conteneurs et processus { #containers-and-processes }\n\nUne **image de conteneur** inclut normalement dans ses métadonnées le programme/la commande par défaut à exécuter lorsque le **conteneur** est démarré et les paramètres à transmettre à ce programme. Très similaire à ce que vous utiliseriez en ligne de commande.\n\nLorsqu'un **conteneur** est démarré, il exécutera cette commande/ce programme (bien que vous puissiez la/le remplacer et faire exécuter une autre commande/un autre programme).\n\nUn conteneur fonctionne tant que le **processus principal** (commande ou programme) est en cours d'exécution.\n\nUn conteneur a normalement un **seul processus**, mais il est aussi possible de démarrer des sous-processus à partir du processus principal, et ainsi vous aurez **plusieurs processus** dans le même conteneur.\n\nMais il n'est pas possible d'avoir un conteneur en cours d'exécution sans **au moins un processus en cours**. Si le processus principal s'arrête, le conteneur s'arrête.\n\n## Construire une image Docker pour FastAPI { #build-a-docker-image-for-fastapi }\n\nTrès bien, construisons quelque chose maintenant ! 🚀\n\nJe vais vous montrer comment construire une **image Docker** pour FastAPI **à partir de zéro**, basée sur l'image **officielle Python**.\n\nC'est ce que vous voudrez faire dans **la plupart des cas**, par exemple :\n\n* Utiliser **Kubernetes** ou des outils similaires\n* Exécuter sur un **Raspberry Pi**\n* Utiliser un service cloud qui exécuterait une image de conteneur pour vous, etc.\n\n### Dépendances des paquets { #package-requirements }\n\nVous aurez normalement les **dépendances des paquets** de votre application dans un fichier.\n\nCela dépendra principalement de l'outil que vous utilisez pour **installer** ces dépendances.\n\nLa manière la plus courante consiste à avoir un fichier `requirements.txt` avec les noms des paquets et leurs versions, un par ligne.\n\nVous utiliserez bien sûr les mêmes idées que vous avez lues dans [À propos des versions de FastAPI](versions.md) pour définir les plages de versions.\n\nPar exemple, votre `requirements.txt` pourrait ressembler à :\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\nEt vous installerez normalement ces dépendances de paquets avec `pip`, par exemple :\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info\n\nIl existe d'autres formats et outils pour définir et installer des dépendances de paquets.\n\n///\n\n### Créer le code **FastAPI** { #create-the-fastapi-code }\n\n* Créez un répertoire `app` et entrez dedans.\n* Créez un fichier vide `__init__.py`.\n* Créez un fichier `main.py` avec :\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\nMaintenant, dans le même répertoire de projet, créez un fichier `Dockerfile` avec :\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. Démarrer à partir de l'image de base Python officielle.\n\n2. Définir le répertoire de travail courant sur `/code`.\n\n    C'est là que nous placerons le fichier `requirements.txt` et le répertoire `app`.\n\n3. Copier le fichier des dépendances vers le répertoire `/code`.\n\n    Copier **uniquement** le fichier des dépendances en premier, pas le reste du code.\n\n    Comme ce fichier **ne change pas souvent**, Docker le détectera et utilisera le **cache** pour cette étape, ce qui activera le cache pour l'étape suivante aussi.\n\n4. Installer les dépendances listées dans le fichier des dépendances.\n\n    L'option `--no-cache-dir` indique à `pip` de ne pas enregistrer localement les paquets téléchargés, car cela ne sert que si `pip` devait être relancé pour installer les mêmes paquets, mais ce n'est pas le cas lorsque l'on travaille avec des conteneurs.\n\n    /// note | Remarque\n\n    Le `--no-cache-dir` concerne uniquement `pip`, cela n'a rien à voir avec Docker ou les conteneurs.\n\n    ///\n\n    L'option `--upgrade` indique à `pip` de mettre à niveau les paquets s'ils sont déjà installés.\n\n    Comme l'étape précédente de copie du fichier peut être détectée par le **cache Docker**, cette étape **utilisera également le cache Docker** lorsqu'il est disponible.\n\n    L'utilisation du cache à cette étape vous **fera gagner** beaucoup de **temps** lors de la reconstruction de l'image encore et encore pendant le développement, au lieu de **télécharger et installer** toutes les dépendances **à chaque fois**.\n\n5. Copier le répertoire `./app` dans le répertoire `/code`.\n\n    Comme cela contient tout le code qui est ce qui **change le plus fréquemment**, le **cache** Docker ne sera pas facilement utilisé pour cette étape ou pour les **étapes suivantes**.\n\n    Il est donc important de placer cela **vers la fin** du `Dockerfile`, pour optimiser les temps de construction de l'image de conteneur.\n\n6. Définir la **commande** pour utiliser `fastapi run`, qui utilise Uvicorn sous le capot.\n\n    `CMD` prend une liste de chaînes, chacune de ces chaînes correspond à ce que vous taperiez en ligne de commande séparé par des espaces.\n\n    Cette commande sera exécutée à partir du **répertoire de travail courant**, le même répertoire `/code` que vous avez défini plus haut avec `WORKDIR /code`.\n\n/// tip | Astuce\n\nPassez en revue ce que fait chaque ligne en cliquant sur chaque bulle numérotée dans le code. 👆\n\n///\n\n/// warning | Alertes\n\nVous devez vous assurer d'utiliser **toujours** la **forme exec** de l'instruction `CMD`, comme expliqué ci-dessous.\n\n///\n\n#### Utiliser `CMD` - Forme Exec { #use-cmd-exec-form }\n\nL'instruction Docker [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) peut être écrite sous deux formes :\n\n✅ Forme **Exec** :\n\n```Dockerfile\n# ✅ À faire\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ Forme **Shell** :\n\n```Dockerfile\n# ⛔️ À ne pas faire\nCMD fastapi run app/main.py --port 80\n```\n\nAssurez-vous d'utiliser toujours la forme **exec** pour garantir que FastAPI peut s'arrêter proprement et que les [événements de cycle de vie](../advanced/events.md) sont déclenchés.\n\nVous pouvez en lire davantage dans la [documentation Docker sur les formes shell et exec](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).\n\nCela peut être très visible lors de l'utilisation de `docker compose`. Voir cette section de la FAQ Docker Compose pour plus de détails techniques : [Pourquoi mes services mettent-ils 10 secondes à se recréer ou à s'arrêter ?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).\n\n#### Structure du répertoire { #directory-structure }\n\nVous devriez maintenant avoir une structure de répertoire comme :\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### Derrière un proxy de terminaison TLS { #behind-a-tls-termination-proxy }\n\nSi vous exécutez votre conteneur derrière un proxy de terminaison TLS (load balancer) comme Nginx ou Traefik, ajoutez l'option `--proxy-headers`, cela indiquera à Uvicorn (via la CLI FastAPI) de faire confiance aux en-têtes envoyés par ce proxy lui indiquant que l'application s'exécute derrière HTTPS, etc.\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Cache Docker { #docker-cache }\n\nIl y a une astuce importante dans ce `Dockerfile`, nous copions d'abord **le fichier des dépendances seul**, pas le reste du code. Laissez-moi vous expliquer pourquoi.\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker et d'autres outils **construisent** ces images de conteneur **de manière incrémentale**, en ajoutant **une couche au-dessus de l'autre**, en commençant par le haut du `Dockerfile` et en ajoutant tous les fichiers créés par chacune des instructions du `Dockerfile`.\n\nDocker et des outils similaires utilisent également un **cache interne** lors de la construction de l'image : si un fichier n'a pas changé depuis la dernière construction de l'image de conteneur, alors il va **réutiliser la même couche** créée la dernière fois, au lieu de recopier le fichier et créer une nouvelle couche à partir de zéro.\n\nÉviter simplement la copie des fichiers n'améliore pas nécessairement les choses de manière significative, mais comme il a utilisé le cache pour cette étape, il peut **utiliser le cache pour l'étape suivante**. Par exemple, il peut utiliser le cache pour l'instruction qui installe les dépendances avec :\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\nLe fichier des dépendances **ne changera pas fréquemment**. Ainsi, en copiant uniquement ce fichier, Docker pourra **utiliser le cache** pour cette étape.\n\nEt ensuite, Docker pourra **utiliser le cache pour l'étape suivante** qui télécharge et installe ces dépendances. Et c'est là que nous **gagnons beaucoup de temps**. ✨ ... et évitons l'ennui en attendant. 😪😆\n\nTélécharger et installer les dépendances de paquets **peut prendre des minutes**, mais utiliser le **cache** ne **prendra que quelques secondes** au plus.\n\nEt comme vous reconstruirez l'image de conteneur encore et encore pendant le développement pour vérifier que vos modifications de code fonctionnent, cela vous fera gagner beaucoup de temps cumulé.\n\nEnsuite, vers la fin du `Dockerfile`, nous copions tout le code. Comme c'est ce qui **change le plus fréquemment**, nous le plaçons vers la fin, car presque toujours, tout ce qui suit cette étape ne pourra pas utiliser le cache.\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### Construire l'image Docker { #build-the-docker-image }\n\nMaintenant que tous les fichiers sont en place, construisons l'image de conteneur.\n\n* Allez dans le répertoire du projet (là où se trouve votre `Dockerfile`, contenant votre répertoire `app`).\n* Construisez votre image FastAPI :\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | Astuce\n\nRemarquez le `.` à la fin, équivalent à `./`, il indique à Docker le répertoire à utiliser pour construire l'image de conteneur.\n\nDans ce cas, c'est le même répertoire courant (`.`).\n\n///\n\n### Démarrer le conteneur Docker { #start-the-docker-container }\n\n* Exécutez un conteneur basé sur votre image :\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## Vérifier { #check-it }\n\nVous devriez pouvoir le vérifier via l'URL de votre conteneur Docker, par exemple : [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) ou [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (ou équivalent, en utilisant votre hôte Docker).\n\nVous verrez quelque chose comme :\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## Documentation interactive de l'API { #interactive-api-docs }\n\nVous pouvez maintenant aller sur [http://192.168.99.100/docs](http://192.168.99.100/docs) ou [http://127.0.0.1/docs](http://127.0.0.1/docs) (ou équivalent, en utilisant votre hôte Docker).\n\nVous verrez la documentation interactive automatique de l'API (fournie par [Swagger UI](https://github.com/swagger-api/swagger-ui)) :\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## Documentation alternative de l'API { #alternative-api-docs }\n\nEt vous pouvez aussi aller sur [http://192.168.99.100/redoc](http://192.168.99.100/redoc) ou [http://127.0.0.1/redoc](http://127.0.0.1/redoc) (ou équivalent, en utilisant votre hôte Docker).\n\nVous verrez la documentation automatique alternative (fournie par [ReDoc](https://github.com/Rebilly/ReDoc)) :\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Construire une image Docker avec un FastAPI mono-fichier { #build-a-docker-image-with-a-single-file-fastapi }\n\nSi votre FastAPI est un seul fichier, par exemple `main.py` sans répertoire `./app`, votre structure de fichiers pourrait ressembler à ceci :\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\nVous n'auriez alors qu'à changer les chemins correspondants pour copier le fichier dans le `Dockerfile` :\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. Copier le fichier `main.py` directement dans le répertoire `/code` (sans répertoire `./app`).\n\n2. Utiliser `fastapi run` pour servir votre application dans le fichier unique `main.py`.\n\nLorsque vous passez le fichier à `fastapi run`, il détectera automatiquement qu'il s'agit d'un fichier unique et non d'un package et saura comment l'importer et servir votre application FastAPI. 😎\n\n## Concepts de déploiement { #deployment-concepts }\n\nParlons à nouveau de certains des mêmes [Concepts de déploiement](concepts.md) en termes de conteneurs.\n\nLes conteneurs sont principalement un outil pour simplifier le processus de **construction et de déploiement** d'une application, mais ils n'imposent pas une approche particulière pour gérer ces **concepts de déploiement**, et il existe plusieurs stratégies possibles.\n\nLa **bonne nouvelle**, c'est qu'avec chaque stratégie différente, il existe un moyen de couvrir tous les concepts de déploiement. 🎉\n\nPassons en revue ces **concepts de déploiement** en termes de conteneurs :\n\n* HTTPS\n* Exécution au démarrage\n* Redémarrages\n* Réplication (le nombre de processus en cours d'exécution)\n* Mémoire\n* Étapes préalables au démarrage\n\n## HTTPS { #https }\n\nSi l'on se concentre uniquement sur l'**image de conteneur** pour une application FastAPI (et plus tard sur le **conteneur** en cours d'exécution), HTTPS serait normalement géré **à l'extérieur** par un autre outil.\n\nCela pourrait être un autre conteneur, par exemple avec [Traefik](https://traefik.io/), gérant **HTTPS** et l'acquisition **automatique** des **certificats**.\n\n/// tip | Astuce\n\nTraefik s'intègre avec Docker, Kubernetes, et d'autres, donc il est très facile de configurer HTTPS pour vos conteneurs avec lui.\n\n///\n\nAlternativement, HTTPS pourrait être géré par un fournisseur cloud comme l'un de leurs services (tout en exécutant l'application dans un conteneur).\n\n## Exécution au démarrage et redémarrages { #running-on-startup-and-restarts }\n\nIl y a normalement un autre outil chargé de **démarrer et exécuter** votre conteneur.\n\nCela pourrait être **Docker** directement, **Docker Compose**, **Kubernetes**, un **service cloud**, etc.\n\nDans la plupart (ou toutes) des situations, il existe une option simple pour activer l'exécution du conteneur au démarrage et activer les redémarrages en cas d'échec. Par exemple, dans Docker, c'est l'option de ligne de commande `--restart`.\n\nSans utiliser de conteneurs, faire en sorte que les applications s'exécutent au démarrage et avec redémarrages peut être fastidieux et difficile. Mais en **travaillant avec des conteneurs**, dans la plupart des cas, cette fonctionnalité est incluse par défaut. ✨\n\n## Réplication - Nombre de processus { #replication-number-of-processes }\n\nSi vous avez un <dfn title=\"Groupe de machines configurées pour être connectées et fonctionner ensemble d'une certaine manière.\">cluster</dfn> de machines avec **Kubernetes**, Docker Swarm Mode, Nomad, ou un autre système complexe similaire pour gérer des conteneurs distribués sur plusieurs machines, alors vous voudrez probablement **gérer la réplication** au **niveau du cluster** plutôt que d'utiliser un **gestionnaire de processus** (comme Uvicorn avec workers) dans chaque conteneur.\n\nL'un de ces systèmes de gestion de conteneurs distribués comme Kubernetes dispose normalement d'une manière intégrée de gérer la **réplication des conteneurs** tout en supportant l'**équilibrage de charge** des requêtes entrantes. Le tout au **niveau du cluster**.\n\nDans ces cas, vous voudrez probablement construire une **image Docker à partir de zéro** comme [expliqué ci-dessus](#dockerfile), en installant vos dépendances et en exécutant **un seul processus Uvicorn** au lieu d'utiliser plusieurs workers Uvicorn.\n\n### Équilibreur de charge { #load-balancer }\n\nLors de l'utilisation de conteneurs, vous aurez normalement un composant **à l'écoute sur le port principal**. Cela pourrait être un autre conteneur qui est également un **proxy de terminaison TLS** pour gérer **HTTPS** ou un outil similaire.\n\nComme ce composant prend la **charge** des requêtes et la distribue entre les workers de façon (espérons-le) **équilibrée**, on l'appelle également communément un **équilibreur de charge**.\n\n/// tip | Astuce\n\nLe même composant de **proxy de terminaison TLS** utilisé pour HTTPS sera probablement aussi un **équilibreur de charge**.\n\n///\n\nEt en travaillant avec des conteneurs, le même système que vous utilisez pour les démarrer et les gérer dispose déjà d'outils internes pour transmettre la **communication réseau** (par ex. les requêtes HTTP) depuis cet **équilibreur de charge** (qui peut aussi être un **proxy de terminaison TLS**) vers le ou les conteneurs avec votre application.\n\n### Un équilibreur de charge - Plusieurs conteneurs worker { #one-load-balancer-multiple-worker-containers }\n\nLorsque vous travaillez avec **Kubernetes** ou des systèmes de gestion de conteneurs distribués similaires, l'utilisation de leurs mécanismes réseau internes permet au **seul équilibreur de charge** à l'écoute sur le **port** principal de transmettre la communication (les requêtes) vers potentiellement **plusieurs conteneurs** exécutant votre application.\n\nChacun de ces conteneurs exécutant votre application aura normalement **un seul processus** (par ex. un processus Uvicorn exécutant votre application FastAPI). Ils seront tous des **conteneurs identiques**, exécutant la même chose, mais chacun avec son propre processus, sa mémoire, etc. De cette façon, vous profiterez de la **parallélisation** sur **différents cœurs** du CPU, voire sur **différentes machines**.\n\nEt le système de conteneurs distribués avec l'**équilibreur de charge** **distribuera les requêtes** à chacun des conteneurs exécutant votre application **à tour de rôle**. Ainsi, chaque requête pourrait être traitée par l'un des multiples **conteneurs répliqués** exécutant votre application.\n\nEt normalement cet **équilibreur de charge** pourra gérer des requêtes qui vont vers *d'autres* applications dans votre cluster (par ex. vers un autre domaine, ou sous un autre préfixe de chemin d'URL), et transmettra cette communication aux bons conteneurs pour *cette autre* application s'exécutant dans votre cluster.\n\n### Un processus par conteneur { #one-process-per-container }\n\nDans ce type de scénario, vous voudrez probablement avoir **un seul processus (Uvicorn) par conteneur**, puisque vous gérez déjà la réplication au niveau du cluster.\n\nDonc, dans ce cas, vous **ne voudrez pas** avoir plusieurs workers dans le conteneur, par exemple avec l'option de ligne de commande `--workers`. Vous voudrez avoir **un seul processus Uvicorn** par conteneur (mais probablement plusieurs conteneurs).\n\nAvoir un autre gestionnaire de processus à l'intérieur du conteneur (comme ce serait le cas avec plusieurs workers) n'ajouterait que de la **complexité inutile** que vous gérez très probablement déjà avec votre système de cluster.\n\n### Conteneurs avec plusieurs processus et cas particuliers { #containers-with-multiple-processes-and-special-cases }\n\nBien sûr, il existe des **cas particuliers** où vous pourriez vouloir avoir **un conteneur** avec plusieurs **processus worker Uvicorn** à l'intérieur.\n\nDans ces cas, vous pouvez utiliser l'option de ligne de commande `--workers` pour définir le nombre de workers que vous souhaitez exécuter :\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. Ici, nous utilisons l'option de ligne de commande `--workers` pour définir le nombre de workers à 4.\n\nVoici quelques exemples où cela pourrait avoir du sens :\n\n#### Une application simple { #a-simple-app }\n\nVous pourriez vouloir un gestionnaire de processus dans le conteneur si votre application est **suffisamment simple** pour s'exécuter sur un **seul serveur**, pas un cluster.\n\n#### Docker Compose { #docker-compose }\n\nVous pourriez déployer sur un **seul serveur** (pas un cluster) avec **Docker Compose**, donc vous n'auriez pas un moyen simple de gérer la réplication des conteneurs (avec Docker Compose) tout en préservant le réseau partagé et l'**équilibrage de charge**.\n\nVous pourriez alors vouloir avoir **un seul conteneur** avec un **gestionnaire de processus** qui démarre **plusieurs processus worker** à l'intérieur.\n\n---\n\nL'idée principale est que **rien** de tout cela ne sont des **règles gravées dans la pierre** que vous devez suivre aveuglément. Vous pouvez utiliser ces idées pour **évaluer votre propre cas d'usage** et décider de la meilleure approche pour votre système, en vérifiant comment gérer les concepts suivants :\n\n* Sécurité - HTTPS\n* Exécution au démarrage\n* Redémarrages\n* Réplication (le nombre de processus en cours d'exécution)\n* Mémoire\n* Étapes préalables au démarrage\n\n## Mémoire { #memory }\n\nSi vous exécutez **un seul processus par conteneur**, vous aurez une quantité de mémoire consommée plus ou moins bien définie, stable et limitée par chacun de ces conteneurs (plus d'un s'ils sont répliqués).\n\nVous pouvez alors définir ces mêmes limites et exigences de mémoire dans vos configurations pour votre système de gestion de conteneurs (par exemple dans **Kubernetes**). De cette façon, il pourra **répliquer les conteneurs** sur les **machines disponibles** en tenant compte de la quantité de mémoire dont ils ont besoin et de la quantité disponible sur les machines du cluster.\n\nSi votre application est **simple**, cela ne sera probablement **pas un problème**, et vous n'aurez peut-être pas besoin de spécifier des limites de mémoire strictes. Mais si vous **utilisez beaucoup de mémoire** (par exemple avec des modèles de **machine learning**), vous devez vérifier combien de mémoire vous consommez et ajuster le **nombre de conteneurs** qui s'exécutent sur **chaque machine** (et peut-être ajouter plus de machines à votre cluster).\n\nSi vous exécutez **plusieurs processus par conteneur**, vous devez vous assurer que le nombre de processus démarrés ne **consomme pas plus de mémoire** que ce qui est disponible.\n\n## Étapes préalables au démarrage et conteneurs { #previous-steps-before-starting-and-containers }\n\nSi vous utilisez des conteneurs (par ex. Docker, Kubernetes), alors il existe deux approches principales que vous pouvez utiliser.\n\n### Plusieurs conteneurs { #multiple-containers }\n\nSi vous avez **plusieurs conteneurs**, probablement chacun exécutant un **seul processus** (par exemple, dans un cluster **Kubernetes**), alors vous voudrez probablement avoir un **conteneur séparé** effectuant le travail des **étapes préalables** dans un seul conteneur, exécutant un seul processus, **avant** d'exécuter les conteneurs worker répliqués.\n\n/// info\n\nSi vous utilisez Kubernetes, ce sera probablement un [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).\n\n///\n\nSi, dans votre cas d'usage, il n'y a pas de problème à exécuter ces étapes préalables **plusieurs fois en parallèle** (par exemple si vous n'exécutez pas de migrations de base de données, mais vérifiez simplement si la base de données est prête), alors vous pourriez aussi simplement les mettre dans chaque conteneur juste avant de démarrer le processus principal.\n\n### Un seul conteneur { #single-container }\n\nSi vous avez une configuration simple, avec **un seul conteneur** qui démarre ensuite plusieurs **processus worker** (ou un seul processus aussi), vous pouvez alors exécuter ces étapes préalables dans le même conteneur, juste avant de démarrer le processus avec l'application.\n\n### Image Docker de base { #base-docker-image }\n\nIl existait une image Docker officielle FastAPI : [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). Mais elle est désormais dépréciée. ⛔️\n\nVous ne devriez probablement **pas** utiliser cette image Docker de base (ni aucune autre similaire).\n\nSi vous utilisez **Kubernetes** (ou autres) et que vous définissez déjà la **réplication** au niveau du cluster, avec plusieurs **conteneurs**. Dans ces cas, il est préférable de **construire une image à partir de zéro** comme décrit ci-dessus : [Construire une image Docker pour FastAPI](#build-a-docker-image-for-fastapi).\n\nEt si vous devez avoir plusieurs workers, vous pouvez simplement utiliser l'option de ligne de commande `--workers`.\n\n/// note | Détails techniques\n\nL'image Docker a été créée à une époque où Uvicorn ne supportait pas la gestion et le redémarrage des workers morts, il fallait donc utiliser Gunicorn avec Uvicorn, ce qui ajoutait pas mal de complexité, uniquement pour que Gunicorn gère et redémarre les processus worker Uvicorn.\n\nMais maintenant qu'Uvicorn (et la commande `fastapi`) supporte l'usage de `--workers`, il n'y a plus de raison d'utiliser une image Docker de base au lieu de construire la vôtre (c'est à peu près la même quantité de code 😅).\n\n///\n\n## Déployer l'image de conteneur { #deploy-the-container-image }\n\nAprès avoir une image de conteneur (Docker), il existe plusieurs façons de la déployer.\n\nPar exemple :\n\n* Avec **Docker Compose** sur un seul serveur\n* Avec un cluster **Kubernetes**\n* Avec un cluster Docker Swarm Mode\n* Avec un autre outil comme Nomad\n* Avec un service cloud qui prend votre image de conteneur et la déploie\n\n## Image Docker avec `uv` { #docker-image-with-uv }\n\nSi vous utilisez [uv](https://github.com/astral-sh/uv) pour installer et gérer votre projet, vous pouvez suivre leur [guide Docker pour uv](https://docs.astral.sh/uv/guides/integration/docker/).\n\n## Récapitulatif { #recap }\n\nAvec les systèmes de conteneurs (par ex. avec **Docker** et **Kubernetes**), il devient assez simple de gérer tous les **concepts de déploiement** :\n\n* HTTPS\n* Exécution au démarrage\n* Redémarrages\n* Réplication (le nombre de processus en cours d'exécution)\n* Mémoire\n* Étapes préalables au démarrage\n\nDans la plupart des cas, vous ne voudrez probablement pas utiliser d'image de base, et au contraire **construire une image de conteneur à partir de zéro** basée sur l'image Docker Python officielle.\n\nEn prenant soin de l'**ordre** des instructions dans le `Dockerfile` et du **cache Docker**, vous pouvez **minimiser les temps de construction**, maximiser votre productivité (et éviter l'ennui). 😎\n"
  },
  {
    "path": "docs/fr/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\nVous pouvez déployer votre application FastAPI sur [FastAPI Cloud](https://fastapicloud.com) avec une **seule commande**, allez vous inscrire sur la liste d’attente si ce n’est pas déjà fait. 🚀\n\n## Se connecter { #login }\n\nVous devez vous assurer que vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d’attente 😉).\n\nConnectez-vous ensuite :\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## Déployer { #deploy }\n\nDéployez maintenant votre application, avec une **seule commande** :\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nC’est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨\n\n## À propos de FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** est développé par le même auteur et la même équipe à l’origine de **FastAPI**.\n\nCela simplifie le processus de **création**, de **déploiement** et **d’accès** à une API avec un effort minimal.\n\nCela apporte la même **expérience développeur** que pour créer des applications avec FastAPI au **déploiement** dans le cloud. 🎉\n\nCela prend également en charge la plupart des éléments nécessaires lors du déploiement d’une application, notamment :\n\n* HTTPS\n* Réplication, avec mise à l’échelle automatique basée sur les requêtes\n* etc.\n\nFastAPI Cloud est le sponsor principal et le financeur des projets open source *FastAPI and friends*. ✨\n\n## Déployer sur d’autres fournisseurs cloud { #deploy-to-other-cloud-providers }\n\nFastAPI est open source et basé sur des standards. Vous pouvez déployer des applications FastAPI sur n’importe quel fournisseur cloud de votre choix.\n\nSuivez les guides de votre fournisseur cloud pour déployer des applications FastAPI avec eux. 🤓\n\n## Déployer votre propre serveur { #deploy-your-own-server }\n\nJe vous expliquerai également plus loin dans ce guide de **Déploiement** tous les détails, afin que vous compreniez ce qui se passe, ce qui doit être fait, et comment déployer des applications FastAPI par vous-même, y compris sur vos propres serveurs. 🤓\n"
  },
  {
    "path": "docs/fr/docs/deployment/https.md",
    "content": "# À propos de HTTPS { #about-https }\n\nIl est facile de supposer que HTTPS est quelque chose qui est simplement « activé » ou non.\n\nMais c'est beaucoup plus complexe que cela.\n\n/// tip | Astuce\n\nSi vous êtes pressé ou si cela ne vous intéresse pas, continuez avec les sections suivantes pour obtenir des instructions étape par étape afin de tout configurer avec différentes techniques.\n\n///\n\nPour apprendre les bases du HTTPS, du point de vue d'un utilisateur, consultez [https://howhttps.works/](https://howhttps.works/).\n\nMaintenant, du point de vue d'un développeur, voici plusieurs choses à avoir en tête en pensant au HTTPS :\n\n* Pour le HTTPS, **le serveur** doit **disposer de « certificats »** générés par une **tierce partie**.\n    * Ces certificats sont en réalité **acquis** auprès de la tierce partie, et non « générés ».\n* Les certificats ont une **durée de vie**.\n    * Ils **expirent**.\n    * Puis ils doivent être **renouvelés**, **acquis à nouveau** auprès de la tierce partie.\n* Le cryptage de la connexion se fait au **niveau TCP**.\n    * C'est une couche **en dessous de HTTP**.\n    * Donc, la gestion du **certificat et du cryptage** est effectuée **avant HTTP**.\n* **TCP ne connaît pas les « domaines »**. Il ne connaît que les adresses IP.\n    * L'information sur le **domaine spécifique** demandé se trouve dans les **données HTTP**.\n* Les **certificats HTTPS** « certifient » un **certain domaine**, mais le protocole et le cryptage se font au niveau TCP, **avant de savoir** quel domaine est traité.\n* **Par défaut**, cela signifie que vous ne pouvez avoir qu'**un seul certificat HTTPS par adresse IP**.\n    * Quelle que soit la taille de votre serveur ou la petitesse de chacune des applications qu'il contient.\n    * Il existe cependant une **solution** à ce problème.\n* Il existe une **extension** du protocole **TLS** (celui qui gère le cryptage au niveau TCP, avant HTTP) appelée **[<abbr title=\"Server Name Indication - Indication du nom du serveur\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**.\n    * Cette extension SNI permet à un seul serveur (avec une **seule adresse IP**) d'avoir **plusieurs certificats HTTPS** et de servir **plusieurs domaines/applications HTTPS**.\n    * Pour que cela fonctionne, un **seul** composant (programme) fonctionnant sur le serveur, écoutant sur l'**adresse IP publique**, doit avoir **tous les certificats HTTPS** du serveur.\n* **Après** l'établissement d'une connexion sécurisée, le protocole de communication est **toujours HTTP**.\n    * Le contenu est **crypté**, même s'il est envoyé avec le **protocole HTTP**.\n\nIl est courant d'avoir **un seul programme/serveur HTTP** fonctionnant sur le serveur (la machine, l'hôte, etc.) et **gérant toutes les parties HTTPS** : recevoir les **requêtes HTTPS chiffrées**, envoyer les **requêtes HTTP déchiffrées** à l'application HTTP réelle fonctionnant sur le même serveur (l'application **FastAPI**, dans ce cas), prendre la **réponse HTTP** de l'application, la **chiffrer** en utilisant le **certificat HTTPS** approprié et la renvoyer au client en utilisant **HTTPS**. Ce serveur est souvent appelé un **[Proxy de terminaison TLS](https://en.wikipedia.org/wiki/TLS_termination_proxy)**.\n\nParmi les options que vous pourriez utiliser comme Proxy de terminaison TLS :\n\n* Traefik (qui peut également gérer les renouvellements de certificats)\n* Caddy (qui peut également gérer les renouvellements de certificats)\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\nAvant Let's Encrypt, ces **certificats HTTPS** étaient vendus par des tiers de confiance.\n\nLe processus d'acquisition de l'un de ces certificats était auparavant lourd, nécessitait pas mal de paperasses et les certificats étaient assez chers.\n\nMais ensuite, **[Let's Encrypt](https://letsencrypt.org/)** a été créé.\n\nIl s'agit d'un projet de la Fondation Linux. Il fournit **des certificats HTTPS gratuitement**, de manière automatisée. Ces certificats utilisent toutes les sécurités cryptographiques standard et ont une durée de vie courte (environ 3 mois), de sorte que la **sécurité est en fait meilleure** en raison de leur durée de vie réduite.\n\nLes domaines sont vérifiés de manière sécurisée et les certificats sont générés automatiquement. Cela permet également d'automatiser le renouvellement de ces certificats.\n\nL'idée est d'automatiser l'acquisition et le renouvellement de ces certificats, afin que vous puissiez disposer d'un **HTTPS sécurisé, gratuitement et pour toujours**.\n\n## HTTPS pour les développeurs { #https-for-developers }\n\nVoici un exemple de ce à quoi pourrait ressembler une API HTTPS, étape par étape, en portant principalement attention aux idées importantes pour les développeurs.\n\n### Nom de domaine { #domain-name }\n\nTout commencerait probablement par le fait que vous **acquériez** un **nom de domaine**. Ensuite, vous le configureriez dans un serveur DNS (possiblement le même que votre fournisseur cloud).\n\nVous obtiendriez probablement un serveur cloud (une machine virtuelle) ou quelque chose de similaire, et il aurait une adresse IP publique <dfn title=\"Ne change pas dans le temps. Pas dynamique.\">fixe</dfn>.\n\nDans le ou les serveurs DNS, vous configureriez un enregistrement (un « `A record` ») pour faire pointer **votre domaine** vers l'**adresse IP publique de votre serveur**.\n\nVous feriez probablement cela une seule fois, la première fois, lors de la mise en place de l'ensemble.\n\n/// tip | Astuce\n\nCette partie relative au nom de domaine intervient bien avant HTTPS, mais comme tout dépend du domaine et de l'adresse IP, il vaut la peine de la mentionner ici.\n\n///\n\n### DNS { #dns }\n\nConcentrons-nous maintenant sur toutes les parties réellement liées à HTTPS.\n\nD'abord, le navigateur vérifierait auprès des **serveurs DNS** quelle est l'**IP du domaine**, dans ce cas, `someapp.example.com`.\n\nLes serveurs DNS indiqueraient au navigateur d'utiliser une **adresse IP** spécifique. Ce serait l'adresse IP publique utilisée par votre serveur, celle que vous avez configurée dans les serveurs DNS.\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### Début de la négociation TLS (Handshake) { #tls-handshake-start }\n\nLe navigateur communiquerait ensuite avec cette adresse IP sur le **port 443** (le port HTTPS).\n\nLa première partie de la communication consiste simplement à établir la connexion entre le client et le serveur et à décider des clés cryptographiques qu'ils utiliseront, etc.\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\nCette interaction entre le client et le serveur pour établir la connexion TLS s'appelle la **négociation TLS (TLS handshake)**.\n\n### TLS avec l'extension SNI { #tls-with-sni-extension }\n\n**Un seul processus** sur le serveur peut écouter sur un **port** spécifique d'une **adresse IP** spécifique. Il pourrait y avoir d'autres processus écoutant sur d'autres ports de la même adresse IP, mais un seul pour chaque combinaison d'adresse IP et de port.\n\nTLS (HTTPS) utilise par défaut le port spécifique `443`. C'est donc le port dont nous aurions besoin.\n\nComme un seul processus peut écouter sur ce port, le processus qui le ferait serait le **Proxy de terminaison TLS**.\n\nLe Proxy de terminaison TLS aurait accès à un ou plusieurs **certificats TLS** (certificats HTTPS).\n\nEn utilisant l'**extension SNI** mentionnée plus haut, le Proxy de terminaison TLS vérifierait lequel des certificats TLS (HTTPS) disponibles il devrait utiliser pour cette connexion, en choisissant celui qui correspond au domaine attendu par le client.\n\nDans ce cas, il utiliserait le certificat pour `someapp.example.com`.\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\nLe client **fait déjà confiance** à l'entité qui a généré ce certificat TLS (dans ce cas Let's Encrypt, mais nous y reviendrons plus tard), il peut donc **vérifier** que le certificat est valide.\n\nEnsuite, en utilisant le certificat, le client et le Proxy de terminaison TLS **décident comment chiffrer** le reste de la **communication TCP**. Cela termine la partie **négociation TLS**.\n\nAprès cela, le client et le serveur disposent d'une **connexion TCP chiffrée**, c'est ce que fournit TLS. Ils peuvent alors utiliser cette connexion pour démarrer la **communication HTTP** proprement dite.\n\nEt c'est ce qu'est **HTTPS** : c'est simplement du **HTTP** à l'intérieur d'une **connexion TLS sécurisée** au lieu d'une connexion TCP pure (non chiffrée).\n\n/// tip | Astuce\n\nRemarquez que le cryptage de la communication se produit au **niveau TCP**, pas au niveau HTTP.\n\n///\n\n### Requête HTTPS { #https-request }\n\nMaintenant que le client et le serveur (spécifiquement le navigateur et le Proxy de terminaison TLS) ont une **connexion TCP chiffrée**, ils peuvent démarrer la **communication HTTP**.\n\nAinsi, le client envoie une **requête HTTPS**. Ce n'est qu'une requête HTTP à travers une connexion TLS chiffrée.\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### Déchiffrer la requête { #decrypt-the-request }\n\nLe Proxy de terminaison TLS utiliserait le chiffrement convenu pour **déchiffrer la requête**, et transmettrait la **requête HTTP en clair (déchiffrée)** au processus exécutant l'application (par exemple un processus avec Uvicorn exécutant l'application FastAPI).\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### Réponse HTTP { #http-response }\n\nL'application traiterait la requête et enverrait une **réponse HTTP en clair (non chiffrée)** au Proxy de terminaison TLS.\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### Réponse HTTPS { #https-response }\n\nLe Proxy de terminaison TLS **chiffrerait ensuite la réponse** en utilisant la cryptographie convenue auparavant (qui a commencé avec le certificat pour `someapp.example.com`), et la renverrait au navigateur.\n\nEnsuite, le navigateur vérifierait que la réponse est valide et chiffrée avec la bonne clé cryptographique, etc. Il **déchiffrerait la réponse** et la traiterait.\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\nLe client (navigateur) saura que la réponse provient du bon serveur parce qu'elle utilise la cryptographie convenue auparavant à l'aide du **certificat HTTPS**.\n\n### Applications multiples { #multiple-applications }\n\nSur le même serveur (ou les mêmes serveurs), il pourrait y avoir **plusieurs applications**, par exemple d'autres programmes d'API ou une base de données.\n\nUn seul processus peut gérer l'adresse IP et le port spécifiques (le Proxy de terminaison TLS dans notre exemple), mais les autres applications/processus peuvent également s'exécuter sur le ou les serveurs, tant qu'ils n'essaient pas d'utiliser la même **combinaison d'adresse IP publique et de port**.\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\nDe cette façon, le Proxy de terminaison TLS pourrait gérer HTTPS et les certificats pour **plusieurs domaines**, pour plusieurs applications, puis transmettre les requêtes à la bonne application dans chaque cas.\n\n### Renouvellement des certificats { #certificate-renewal }\n\nÀ un moment donné dans le futur, chaque certificat **expirerait** (environ 3 mois après son acquisition).\n\nEnsuite, il y aurait un autre programme (dans certains cas c'est un autre programme, dans d'autres cas cela pourrait être le même Proxy de terminaison TLS) qui communiquerait avec Let's Encrypt et renouvellerait le ou les certificats.\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\nLes **certificats TLS** sont **associés à un nom de domaine**, pas à une adresse IP.\n\nAinsi, pour renouveler les certificats, le programme de renouvellement doit **prouver** à l'autorité (Let's Encrypt) qu'il **« possède » et contrôle ce domaine**.\n\nPour ce faire, et pour s'adapter aux différents besoins des applications, il existe plusieurs façons de procéder. Parmi les plus courantes :\n\n* **Modifier certains enregistrements DNS**.\n    * Pour cela, le programme de renouvellement doit prendre en charge les API du fournisseur DNS ; ainsi, selon le fournisseur DNS que vous utilisez, cela peut être ou non une option.\n* **S'exécuter comme un serveur** (au moins pendant le processus d'acquisition du certificat) sur l'adresse IP publique associée au domaine.\n    * Comme nous l'avons dit plus haut, un seul processus peut écouter sur une adresse IP et un port spécifiques.\n    * C'est l'une des raisons pour lesquelles il est très utile que le même Proxy de terminaison TLS prenne également en charge le processus de renouvellement des certificats.\n    * Sinon, vous pourriez avoir à arrêter le Proxy de terminaison TLS momentanément, démarrer le programme de renouvellement pour acquérir les certificats, puis les configurer avec le Proxy de terminaison TLS, et ensuite redémarrer le Proxy de terminaison TLS. Ce n'est pas idéal, car votre/vos application(s) ne seront pas disponibles pendant le temps où le Proxy de terminaison TLS est arrêté.\n\nTout ce processus de renouvellement, tout en continuant à servir l'application, est l'une des principales raisons pour lesquelles vous voudriez avoir un **système séparé pour gérer HTTPS** avec un Proxy de terminaison TLS, au lieu d'utiliser directement les certificats TLS avec le serveur d'application (par exemple Uvicorn).\n\n## En-têtes Proxy Forwarded { #proxy-forwarded-headers }\n\nLorsque vous utilisez un proxy pour gérer HTTPS, votre **serveur d'application** (par exemple Uvicorn via FastAPI CLI) ne connaît rien du processus HTTPS, il communique en HTTP en clair avec le **Proxy de terminaison TLS**.\n\nCe **proxy** définirait normalement certains en-têtes HTTP à la volée avant de transmettre la requête au **serveur d'application**, pour informer le serveur d'application que la requête est **transmise** par le proxy.\n\n/// note | Détails techniques\n\nLes en-têtes du proxy sont :\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\nNéanmoins, comme le **serveur d'application** ne sait pas qu'il se trouve derrière un **proxy** de confiance, par défaut, il ne ferait pas confiance à ces en-têtes.\n\nMais vous pouvez configurer le **serveur d'application** pour qu'il fasse confiance aux en-têtes transmis (*forwarded*) envoyés par le **proxy**. Si vous utilisez FastAPI CLI, vous pouvez utiliser l'*option CLI* `--forwarded-allow-ips` pour lui indiquer à partir de quelles IP il doit faire confiance à ces en-têtes transmis.\n\nPar exemple, si le **serveur d'application** ne reçoit des communications que du **proxy** de confiance, vous pouvez définir `--forwarded-allow-ips=\"*\"` pour lui faire faire confiance à toutes les IP entrantes, puisqu'il ne recevra des requêtes que depuis l'IP utilisée par le **proxy**.\n\nDe cette façon, l'application sera en mesure de savoir quelle est sa propre URL publique, si elle utilise HTTPS, le domaine, etc.\n\nCela serait utile, par exemple, pour gérer correctement les redirections.\n\n/// tip | Astuce\n\nVous pouvez en savoir plus dans la documentation [Derrière un proxy - Activer les en-têtes transmis par le proxy](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)\n\n///\n\n## Récapitulatif { #recap }\n\nDisposer de **HTTPS** est très important, et assez **critique** dans la plupart des cas. La majeure partie de l'effort que vous, en tant que développeur, devez fournir autour de HTTPS consiste simplement à **comprendre ces concepts** et leur fonctionnement.\n\nMais une fois que vous connaissez les informations de base sur **HTTPS pour les développeurs**, vous pouvez facilement combiner et configurer différents outils pour vous aider à tout gérer simplement.\n\nDans certains des prochains chapitres, je vous montrerai plusieurs exemples concrets de configuration de **HTTPS** pour des applications **FastAPI**. 🔒\n"
  },
  {
    "path": "docs/fr/docs/deployment/index.md",
    "content": "# Déploiement { #deployment }\n\nLe déploiement d'une application **FastAPI** est relativement simple.\n\n## Que signifie le déploiement { #what-does-deployment-mean }\n\n**Déployer** une application signifie effectuer les étapes nécessaires pour la rendre **disponible pour les\nutilisateurs**.\n\nPour une **API Web**, cela implique normalement de la placer sur une **machine distante**, avec un **programme serveur**\nqui offre de bonnes performances, une bonne stabilité, _etc._, afin que vos **utilisateurs** puissent **accéder** à\nl'application efficacement et sans interruption ni problème.\n\nCeci contraste avec les étapes de **développement**, où vous êtes constamment en train de modifier le code, de le casser\net de le réparer, d'arrêter et de redémarrer le serveur de développement, _etc._\n\n## Stratégies de déploiement { #deployment-strategies }\n\nIl existe plusieurs façons de procéder, en fonction de votre cas d'utilisation spécifique et des outils que vous\nutilisez.\n\nVous pouvez **déployer un serveur** vous-même en utilisant une combinaison d'outils, vous pouvez utiliser un **service\ncloud** qui fait une partie du travail pour vous, ou encore d'autres options possibles.\n\nPar exemple, nous, l'équipe derrière FastAPI, avons créé [**FastAPI Cloud**](https://fastapicloud.com), pour rendre le déploiement d'applications FastAPI dans le cloud aussi fluide que possible, avec la même expérience développeur que lorsque vous travaillez avec FastAPI.\n\nJe vais vous montrer certains des principaux concepts que vous devriez probablement avoir à l'esprit lors du déploiement\nd'une application **FastAPI** (bien que la plupart de ces concepts s'appliquent à tout autre type d'application web).\n\nVous verrez plus de détails à avoir en tête et certaines des techniques pour le faire dans les sections suivantes. ✨\n"
  },
  {
    "path": "docs/fr/docs/deployment/manually.md",
    "content": "# Exécuter un serveur manuellement { #run-a-server-manually }\n\n## Utiliser la commande `fastapi run` { #use-the-fastapi-run-command }\n\nEn bref, utilisez `fastapi run` pour servir votre application FastAPI :\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\nCela fonctionnerait pour la plupart des cas. 😎\n\nVous pourriez utiliser cette commande par exemple pour démarrer votre application **FastAPI** dans un conteneur, sur un serveur, etc.\n\n## Serveurs ASGI { #asgi-servers }\n\nAllons un peu plus en détail.\n\nFastAPI utilise un standard pour construire des frameworks web Python et des serveurs appelé <abbr title=\"Asynchronous Server Gateway Interface - Interface passerelle serveur asynchrone\">ASGI</abbr>. FastAPI est un framework web ASGI.\n\nLa principale chose dont vous avez besoin pour exécuter une application **FastAPI** (ou toute autre application ASGI) sur une machine serveur distante est un programme serveur ASGI comme **Uvicorn**, c'est celui utilisé par défaut par la commande `fastapi`.\n\nIl existe plusieurs alternatives, notamment :\n\n* [Uvicorn](https://www.uvicorn.dev/) : un serveur ASGI haute performance.\n* [Hypercorn](https://hypercorn.readthedocs.io/) : un serveur ASGI compatible avec HTTP/2 et Trio entre autres fonctionnalités.\n* [Daphne](https://github.com/django/daphne) : le serveur ASGI conçu pour Django Channels.\n* [Granian](https://github.com/emmett-framework/granian) : un serveur HTTP Rust pour les applications Python.\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/) : NGINX Unit est un environnement d'exécution d'applications web léger et polyvalent.\n\n## Machine serveur et programme serveur { #server-machine-and-server-program }\n\nIl y a un petit détail sur les noms à garder à l'esprit. 💡\n\nLe mot « serveur » est couramment utilisé pour désigner à la fois l'ordinateur distant/cloud (la machine physique ou virtuelle) et également le programme qui s'exécute sur cette machine (par exemple, Uvicorn).\n\nGardez cela à l'esprit lorsque vous lisez « serveur » en général, cela pourrait faire référence à l'une de ces deux choses.\n\nLorsqu'on se réfère à la machine distante, il est courant de l'appeler **serveur**, mais aussi **machine**, **VM** (machine virtuelle), **nœud**. Tout cela fait référence à un type de machine distante, exécutant normalement Linux, sur laquelle vous exécutez des programmes.\n\n## Installer le programme serveur { #install-the-server-program }\n\nLorsque vous installez FastAPI, il est fourni avec un serveur de production, Uvicorn, et vous pouvez le démarrer avec la commande `fastapi run`.\n\nMais vous pouvez également installer un serveur ASGI manuellement.\n\nVous devez créer un [environnement virtuel](../virtual-environments.md), l'activer, puis vous pouvez installer l'application serveur.\n\nPar exemple, pour installer Uvicorn :\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\nUn processus similaire s'appliquerait à tout autre programme de serveur ASGI.\n\n/// tip | Astuce\n\nEn ajoutant `standard`, Uvicorn va installer et utiliser quelques dépendances supplémentaires recommandées.\n\nCela inclut `uvloop`, le remplaçant hautes performances de `asyncio`, qui fournit le gros gain de performance en matière de concurrence.\n\nLorsque vous installez FastAPI avec quelque chose comme `pip install \"fastapi[standard]\"`, vous obtenez déjà `uvicorn[standard]` aussi.\n\n///\n\n## Exécuter le programme serveur { #run-the-server-program }\n\nSi vous avez installé un serveur ASGI manuellement, vous devrez normalement passer une chaîne d'import dans un format spécial pour qu'il importe votre application FastAPI :\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note | Remarque\n\nLa commande `uvicorn main:app` fait référence à :\n\n* `main` : le fichier `main.py` (le « module » Python).\n* `app` : l'objet créé dans `main.py` avec la ligne `app = FastAPI()`.\n\nC'est équivalent à :\n\n```Python\nfrom main import app\n```\n\n///\n\nChaque programme de serveur ASGI alternatif aurait une commande similaire, vous pouvez en lire plus dans leur documentation respective.\n\n/// warning | Alertes\n\nUvicorn et d'autres serveurs prennent en charge une option `--reload` utile pendant le développement.\n\nL'option `--reload` consomme beaucoup plus de ressources, est plus instable, etc.\n\nCela aide beaucoup pendant le **développement**, mais vous **ne devriez pas** l'utiliser en **production**.\n\n///\n\n## Concepts de déploiement { #deployment-concepts }\n\nCes exemples exécutent le programme serveur (par exemple Uvicorn), en démarrant **un seul processus**, à l'écoute sur toutes les IP (`0.0.0.0`) sur un port prédéfini (par exemple `80`).\n\nC'est l'idée de base. Mais vous voudrez probablement vous occuper de certaines choses supplémentaires, comme :\n\n* Sécurité - HTTPS\n* Exécution au démarrage\n* Redémarrages\n* Réplication (le nombre de processus en cours d'exécution)\n* Mémoire\n* Étapes précédant le démarrage\n\nJe vous en dirai plus sur chacun de ces concepts, sur la manière d'y réfléchir, et donnerai quelques exemples concrets avec des stratégies pour les gérer dans les prochains chapitres. 🚀\n"
  },
  {
    "path": "docs/fr/docs/deployment/server-workers.md",
    "content": "# Workers du serveur - Uvicorn avec workers { #server-workers-uvicorn-with-workers }\n\nReprenons ces concepts de déploiement vus précédemment :\n\n* Sécurité - HTTPS\n* Exécution au démarrage\n* Redémarrages\n* **Réplication (le nombre de processus en cours d'exécution)**\n* Mémoire\n* Étapes préalables avant le démarrage\n\nJusqu'à présent, avec tous les tutoriels dans les documents, vous avez probablement exécuté un programme serveur, par exemple avec la commande `fastapi`, qui lance Uvicorn en exécutant un seul processus.\n\nLors du déploiement d'applications, vous voudrez probablement avoir une réplication de processus pour tirer parti de plusieurs cœurs et pouvoir gérer davantage de requêtes.\n\nComme vous l'avez vu dans le chapitre précédent sur les [Concepts de déploiement](concepts.md), il existe plusieurs stratégies possibles.\n\nIci, je vais vous montrer comment utiliser Uvicorn avec des processus workers en utilisant la commande `fastapi` ou directement la commande `uvicorn`.\n\n/// info | Info\n\nSi vous utilisez des conteneurs, par exemple avec Docker ou Kubernetes, je vous en dirai plus à ce sujet dans le prochain chapitre : [FastAPI dans des conteneurs - Docker](docker.md).\n\nEn particulier, lorsque vous exécutez sur **Kubernetes**, vous ne voudrez probablement **pas** utiliser de workers et plutôt exécuter **un seul processus Uvicorn par conteneur**, mais je vous en parlerai plus en détail dans ce chapitre.\n\n///\n\n## Utiliser plusieurs workers { #multiple-workers }\n\nVous pouvez démarrer plusieurs workers avec l'option de ligne de commande `--workers` :\n\n//// tab | `fastapi`\n\nSi vous utilisez la commande `fastapi` :\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\nSi vous préférez utiliser directement la commande `uvicorn` :\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\nLa seule option nouvelle ici est `--workers` qui indique à Uvicorn de démarrer 4 processus workers.\n\nVous pouvez aussi voir qu'il affiche le **PID** de chaque processus, `27365` pour le processus parent (c'est le **gestionnaire de processus**) et un pour chaque processus worker : `27368`, `27369`, `27370` et `27367`.\n\n## Concepts de déploiement { #deployment-concepts }\n\nIci, vous avez vu comment utiliser plusieurs workers pour paralléliser l'exécution de l'application, tirer parti de plusieurs cœurs du CPU et être en mesure de servir davantage de requêtes.\n\nDans la liste des concepts de déploiement ci-dessus, l'utilisation de workers aide principalement à la partie réplication, et un peu aux redémarrages, mais vous devez toujours vous occuper des autres :\n\n* **Sécurité - HTTPS**\n* **Exécution au démarrage**\n* ***Redémarrages***\n* Réplication (le nombre de processus en cours d'exécution)\n* **Mémoire**\n* **Étapes préalables avant le démarrage**\n\n## Conteneurs et Docker { #containers-and-docker }\n\nDans le prochain chapitre sur [FastAPI dans des conteneurs - Docker](docker.md), j'expliquerai quelques stratégies que vous pourriez utiliser pour gérer les autres **concepts de déploiement**.\n\nJe vous montrerai comment créer votre propre image à partir de zéro pour exécuter un seul processus Uvicorn. C'est un processus simple et c'est probablement ce que vous voudrez faire lorsque vous utilisez un système distribué de gestion de conteneurs comme **Kubernetes**.\n\n## Récapitulatif { #recap }\n\nVous pouvez utiliser plusieurs processus workers avec l'option CLI `--workers` des commandes `fastapi` ou `uvicorn` pour tirer parti des **CPU multicœurs**, et exécuter **plusieurs processus en parallèle**.\n\nVous pourriez utiliser ces outils et idées si vous mettez en place votre propre système de déploiement tout en prenant vous-même en charge les autres concepts de déploiement.\n\nConsultez le prochain chapitre pour en savoir plus sur **FastAPI** avec des conteneurs (par exemple Docker et Kubernetes). Vous verrez que ces outils offrent aussi des moyens simples de résoudre les autres **concepts de déploiement**. ✨\n"
  },
  {
    "path": "docs/fr/docs/deployment/versions.md",
    "content": "# À propos des versions de FastAPI { #about-fastapi-versions }\n\n**FastAPI** est déjà utilisé en production dans de nombreuses applications et de nombreux systèmes. Et la couverture de tests est maintenue à 100 %. Mais son développement avance toujours rapidement.\n\nDe nouvelles fonctionnalités sont ajoutées fréquemment, des bogues sont corrigés régulièrement et le code s'améliore continuellement.\n\nC'est pourquoi les versions actuelles sont toujours `0.x.x`, cela reflète que chaque version pourrait potentiellement comporter des changements non rétrocompatibles. Cela suit les conventions de [versionnage sémantique](https://semver.org/).\n\nVous pouvez créer des applications de production avec **FastAPI** dès maintenant (et vous le faites probablement depuis un certain temps), vous devez juste vous assurer que vous utilisez une version qui fonctionne correctement avec le reste de votre code.\n\n## Épingler votre version de `fastapi` { #pin-your-fastapi-version }\n\nLa première chose que vous devez faire est « épingler » la version de **FastAPI** que vous utilisez à la dernière version spécifique dont vous savez qu’elle fonctionne correctement pour votre application.\n\nPar exemple, disons que vous utilisez la version `0.112.0` dans votre application.\n\nSi vous utilisez un fichier `requirements.txt`, vous pouvez spécifier la version avec :\n\n```txt\nfastapi[standard]==0.112.0\n```\n\nce qui signifierait que vous utiliseriez exactement la version `0.112.0`.\n\nOu vous pourriez aussi l'épingler avec :\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\ncela signifierait que vous utiliseriez les versions `0.112.0` ou supérieures, mais inférieures à `0.113.0`, par exemple, une version `0.112.2` serait toujours acceptée.\n\nSi vous utilisez un autre outil pour gérer vos installations, comme `uv`, Poetry, Pipenv, ou autres, ils ont tous un moyen que vous pouvez utiliser pour définir des versions spécifiques pour vos paquets.\n\n## Versions disponibles { #available-versions }\n\nVous pouvez consulter les versions disponibles (par exemple, pour vérifier quelle est la dernière version en date) dans les [Notes de version](../release-notes.md).\n\n## À propos des versions { #about-versions }\n\nSuivant les conventions de versionnage sémantique, toute version inférieure à `1.0.0` peut potentiellement ajouter des changements non rétrocompatibles.\n\nFastAPI suit également la convention selon laquelle tout changement de version « PATCH » concerne des corrections de bogues et des changements rétrocompatibles.\n\n/// tip | Astuce\n\nLe « PATCH » est le dernier chiffre, par exemple, dans `0.2.3`, la version PATCH est `3`.\n\n///\n\nDonc, vous devriez être en mesure d'épingler une version comme suit :\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\nLes changements non rétrocompatibles et les nouvelles fonctionnalités sont ajoutés dans les versions « MINOR ».\n\n/// tip | Astuce\n\nLe « MINOR » est le numéro au milieu, par exemple, dans `0.2.3`, la version MINOR est `2`.\n\n///\n\n## Mettre à niveau les versions de FastAPI { #upgrading-the-fastapi-versions }\n\nVous devez ajouter des tests pour votre application.\n\nAvec **FastAPI** c'est très facile (merci à Starlette), consultez les documents : [Tests](../tutorial/testing.md)\n\nAprès avoir des tests, vous pouvez mettre à niveau la version de **FastAPI** vers une version plus récente et vous assurer que tout votre code fonctionne correctement en exécutant vos tests.\n\nSi tout fonctionne, ou après avoir effectué les changements nécessaires, et que tous vos tests passent, vous pouvez alors épingler votre `fastapi` à cette nouvelle version récente.\n\n## À propos de Starlette { #about-starlette }\n\nVous ne devez pas épingler la version de `starlette`.\n\nDifférentes versions de **FastAPI** utiliseront une version spécifique plus récente de Starlette.\n\nAinsi, vous pouvez simplement laisser **FastAPI** utiliser la bonne version de Starlette.\n\n## À propos de Pydantic { #about-pydantic }\n\nPydantic inclut les tests pour **FastAPI** avec ses propres tests, ainsi les nouvelles versions de Pydantic (au-dessus de `1.0.0`) sont toujours compatibles avec FastAPI.\n\nVous pouvez épingler Pydantic à toute version supérieure à `1.0.0` qui fonctionne pour vous.\n\nPar exemple :\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/fr/docs/editor-support.md",
    "content": "# Prise en charge des éditeurs { #editor-support }\n\nL’extension officielle [Extension FastAPI](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) améliore votre flux de développement FastAPI grâce à la découverte des chemins d'accès, à la navigation, ainsi qu’au déploiement sur FastAPI Cloud et à la diffusion en direct des journaux.\n\nPour plus de détails sur l’extension, reportez-vous au README sur le [référentiel GitHub](https://github.com/fastapi/fastapi-vscode).\n\n## Configurer et installer { #setup-and-installation }\n\nL’**Extension FastAPI** est disponible pour [VS Code](https://code.visualstudio.com/) et [Cursor](https://www.cursor.com/). Vous pouvez l’installer directement depuis le panneau Extensions de chaque éditeur en recherchant « FastAPI » et en sélectionnant l’extension publiée par **FastAPI Labs**. L’extension fonctionne également dans les éditeurs basés sur le navigateur tels que [vscode.dev](https://vscode.dev) et [github.dev](https://github.dev).\n\n### Découvrir l’application { #application-discovery }\n\nPar défaut, l’extension détecte automatiquement les applications FastAPI dans votre espace de travail en recherchant les fichiers qui instancient `FastAPI()`. Si la détection automatique ne convient pas à la structure de votre projet, vous pouvez spécifier un point d’entrée via `[tool.fastapi]` dans `pyproject.toml` ou le paramètre VS Code `fastapi.entryPoint`, en utilisant la notation de module (par ex. `myapp.main:app`).\n\n## Fonctionnalités { #features }\n\n- **Explorateur des chemins d'accès** — Une vue arborescente latérale de tous les <dfn title=\"routes, endpoints\">*chemins d'accès*</dfn> de votre application. Cliquez pour accéder à n’importe quelle définition de route ou de routeur.\n- **Recherche de routes** — Recherchez par chemin, méthode ou nom avec <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (sur macOS : <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>).\n- **Navigation CodeLens** — Liens cliquables au-dessus des appels du client de test (par ex. `client.get('/items')`) menant au *chemin d'accès* correspondant, pour naviguer rapidement entre les tests et l’implémentation.\n- **Déployer sur FastAPI Cloud** — Déploiement en un clic de votre application sur [FastAPI Cloud](https://fastapicloud.com/).\n- **Diffuser les journaux de l’application** — Diffusion en temps réel des journaux de votre application déployée sur FastAPI Cloud, avec filtrage par niveau et recherche textuelle.\n\nSi vous souhaitez vous familiariser avec les fonctionnalités de l’extension, vous pouvez consulter le guide pas à pas de l’extension en ouvrant la palette de commandes (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> ou sur macOS : <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>) et en sélectionnant « Welcome: Open walkthrough ... » puis en choisissant le guide « Get started with FastAPI ».\n"
  },
  {
    "path": "docs/fr/docs/environment-variables.md",
    "content": "# Variables d'environnement { #environment-variables }\n\n/// tip | Astuce\n\nSi vous savez déjà ce que sont les « variables d'environnement » et comment les utiliser, vous pouvez passer cette section.\n\n///\n\nUne variable d'environnement (également appelée « env var ») est une variable qui vit en dehors du code Python, dans le système d'exploitation, et qui peut être lue par votre code Python (ou par d'autres programmes également).\n\nLes variables d'environnement peuvent être utiles pour gérer des **paramètres** d'application, dans le cadre de l'**installation** de Python, etc.\n\n## Créer et utiliser des variables d'environnement { #create-and-use-env-vars }\n\nVous pouvez créer et utiliser des variables d'environnement dans le **shell (terminal)**, sans avoir besoin de Python :\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Vous pouvez créer une variable d'environnement MY_NAME avec\n$ export MY_NAME=\"Wade Wilson\"\n\n// Vous pouvez ensuite l'utiliser avec d'autres programmes, par exemple\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Créer une variable d'environnement MY_NAME\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// L'utiliser avec d'autres programmes, par exemple\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## Lire des variables d'environnement en Python { #read-env-vars-in-python }\n\nVous pouvez également créer des variables d'environnement **en dehors** de Python, dans le terminal (ou par tout autre moyen), puis les **lire en Python**.\n\nPar exemple, vous pouvez avoir un fichier `main.py` contenant :\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip | Astuce\n\nLe deuxième argument de [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) est la valeur par défaut à retourner.\n\nS'il n'est pas fourni, c'est `None` par défaut ; ici, nous fournissons `\"World\"` comme valeur par défaut à utiliser.\n\n///\n\nVous pouvez ensuite exécuter ce programme Python :\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Ici, nous ne définissons pas encore la variable d'environnement\n$ python main.py\n\n// Comme nous ne l'avons pas définie, nous obtenons la valeur par défaut\n\nHello World from Python\n\n// Mais si nous créons d'abord une variable d'environnement\n$ export MY_NAME=\"Wade Wilson\"\n\n// Puis que nous relançons le programme\n$ python main.py\n\n// Il peut maintenant lire la variable d'environnement\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Ici, nous ne définissons pas encore la variable d'environnement\n$ python main.py\n\n// Comme nous ne l'avons pas définie, nous obtenons la valeur par défaut\n\nHello World from Python\n\n// Mais si nous créons d'abord une variable d'environnement\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Puis que nous relançons le programme\n$ python main.py\n\n// Il peut maintenant lire la variable d'environnement\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\nComme les variables d'environnement peuvent être définies en dehors du code, mais lues par le code, et qu'elles n'ont pas besoin d'être stockées (validées dans `git`) avec le reste des fichiers, il est courant de les utiliser pour les configurations ou les **paramètres**.\n\nVous pouvez également créer une variable d'environnement uniquement pour l'**invocation d'un programme spécifique**, qui ne sera disponible que pour ce programme et uniquement pendant sa durée d'exécution.\n\nPour cela, créez-la juste avant le programme, sur la même ligne :\n\n<div class=\"termy\">\n\n```console\n// Créer en ligne une variable d'environnement MY_NAME pour cet appel de programme\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// Il peut maintenant lire la variable d'environnement\n\nHello Wade Wilson from Python\n\n// La variable d'environnement n'existe plus ensuite\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip | Astuce\n\nVous pouvez en lire davantage sur [The Twelve-Factor App : Config](https://12factor.net/config).\n\n///\n\n## Gérer les types et la validation { #types-and-validation }\n\nCes variables d'environnement ne peuvent gérer que des **chaînes de texte**, car elles sont externes à Python et doivent être compatibles avec les autres programmes et le reste du système (et même avec différents systèmes d'exploitation, comme Linux, Windows, macOS).\n\nCela signifie que **toute valeur** lue en Python à partir d'une variable d'environnement **sera une `str`**, et que toute conversion vers un autre type ou toute validation doit être effectuée dans le code.\n\nVous en apprendrez davantage sur l'utilisation des variables d'environnement pour gérer les **paramètres d'application** dans le [Guide utilisateur avancé - Paramètres et variables d'environnement](./advanced/settings.md).\n\n## Variable d'environnement `PATH` { #path-environment-variable }\n\nIl existe une **variable d'environnement spéciale** appelée **`PATH`** qui est utilisée par les systèmes d'exploitation (Linux, macOS, Windows) pour trouver les programmes à exécuter.\n\nLa valeur de la variable `PATH` est une longue chaîne composée de répertoires séparés par deux-points `:` sous Linux et macOS, et par point-virgule `;` sous Windows.\n\nPar exemple, la variable d'environnement `PATH` peut ressembler à ceci :\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nCela signifie que le système doit rechercher les programmes dans les répertoires :\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\nCela signifie que le système doit rechercher les programmes dans les répertoires :\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\nLorsque vous tapez une **commande** dans le terminal, le système d'exploitation **cherche** le programme dans **chacun de ces répertoires** listés dans la variable d'environnement `PATH`.\n\nPar exemple, lorsque vous tapez `python` dans le terminal, le système d'exploitation cherche un programme nommé `python` dans le **premier répertoire** de cette liste.\n\nS'il le trouve, alors il **l'utilise**. Sinon, il continue à chercher dans les **autres répertoires**.\n\n### Installer Python et mettre à jour `PATH` { #installing-python-and-updating-the-path }\n\nLorsque vous installez Python, il est possible que l'on vous demande si vous souhaitez mettre à jour la variable d'environnement `PATH`.\n\n//// tab | Linux, macOS\n\nSupposons que vous installiez Python et qu'il se retrouve dans un répertoire `/opt/custompython/bin`.\n\nSi vous acceptez de mettre à jour la variable d'environnement `PATH`, l'installateur ajoutera `/opt/custompython/bin` à la variable d'environnement `PATH`.\n\nCela pourrait ressembler à ceci :\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\nAinsi, lorsque vous tapez `python` dans le terminal, le système trouvera le programme Python dans `/opt/custompython/bin` (le dernier répertoire) et utilisera celui-là.\n\n////\n\n//// tab | Windows\n\nSupposons que vous installiez Python et qu'il se retrouve dans un répertoire `C:\\opt\\custompython\\bin`.\n\nSi vous acceptez de mettre à jour la variable d'environnement `PATH`, l'installateur ajoutera `C:\\opt\\custompython\\bin` à la variable d'environnement `PATH`.\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\nAinsi, lorsque vous tapez `python` dans le terminal, le système trouvera le programme Python dans `C:\\opt\\custompython\\bin` (le dernier répertoire) et utilisera celui-là.\n\n////\n\nAinsi, si vous tapez :\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\nLe système va **trouver** le programme `python` dans `/opt/custompython/bin` et l'exécuter.\n\nCela reviendrait à peu près à taper :\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\nLe système va **trouver** le programme `python` dans `C:\\opt\\custompython\\bin\\python` et l'exécuter.\n\nCela reviendrait à peu près à taper :\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\nCes informations vous seront utiles lors de l'apprentissage des [Environnements virtuels](virtual-environments.md).\n\n## Conclusion { #conclusion }\n\nAvec cela, vous devriez avoir une compréhension de base de ce que sont les **variables d'environnement** et de la façon de les utiliser en Python.\n\nVous pouvez également en lire davantage sur la [page Wikipédia dédiée aux variables d'environnement](https://en.wikipedia.org/wiki/Environment_variable).\n\nDans de nombreux cas, il n'est pas évident de voir immédiatement en quoi les variables d'environnement seraient utiles et applicables. Mais elles réapparaissent dans de nombreux scénarios lorsque vous développez, il est donc bon de les connaître.\n\nPar exemple, vous aurez besoin de ces informations dans la section suivante, sur les [Environnements virtuels](virtual-environments.md).\n"
  },
  {
    "path": "docs/fr/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - interface en ligne de commande\">CLI</abbr>** est un programme en ligne de commande que vous pouvez utiliser pour servir votre application FastAPI, gérer votre projet FastAPI, et plus encore.\n\nLorsque vous installez FastAPI (par exemple avec `pip install \"fastapi[standard]\"`), il est fourni avec un programme en ligne de commande que vous pouvez exécuter dans le terminal.\n\nPour exécuter votre application FastAPI en développement, vous pouvez utiliser la commande `fastapi dev` :\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip | Astuce\n\nPour la production, utilisez `fastapi run` plutôt que `fastapi dev`. 🚀\n\n///\n\nEn interne, **FastAPI CLI** utilise [Uvicorn](https://www.uvicorn.dev), un serveur ASGI haute performance, prêt pour la production. 😎\n\nLa CLI `fastapi` tentera de détecter automatiquement l’application FastAPI à exécuter, en supposant qu’il s’agit d’un objet nommé `app` dans un fichier `main.py` (ou quelques autres variantes).\n\nMais vous pouvez configurer explicitement l’application à utiliser.\n\n## Configurer le `entrypoint` de l’application dans `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nVous pouvez configurer l’endroit où se trouve votre application dans un fichier `pyproject.toml` comme suit :\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nCet `entrypoint` indiquera à la commande `fastapi` qu’elle doit importer l’application comme ceci :\n\n```python\nfrom main import app\n```\n\nSi votre code était structuré comme ceci :\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nVous définiriez alors le `entrypoint` comme suit :\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nce qui serait équivalent à :\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` avec un chemin { #fastapi-dev-with-path }\n\nVous pouvez également passer le chemin du fichier à la commande `fastapi dev`, et elle devinera l’objet d’application FastAPI à utiliser :\n\n```console\n$ fastapi dev main.py\n```\n\nMais vous devez vous rappeler de passer le bon chemin à chaque fois que vous appelez la commande `fastapi`.\n\nDe plus, d’autres outils pourraient ne pas pouvoir le trouver, par exemple l’[extension VS Code](editor-support.md) ou [FastAPI Cloud](https://fastapicloud.com), il est donc recommandé d’utiliser le `entrypoint` dans `pyproject.toml`.\n\n## `fastapi dev` { #fastapi-dev }\n\nL’exécution de `fastapi dev` lance le mode développement.\n\nPar défaut, l’**auto-reload** est activé et recharge automatiquement le serveur lorsque vous modifiez votre code. Cela consomme des ressources et peut être moins stable que lorsqu’il est désactivé. Vous devez l’utiliser uniquement pour le développement. Il écoute aussi sur l’adresse IP `127.0.0.1`, qui est l’adresse IP permettant à votre machine de communiquer uniquement avec elle‑même (`localhost`).\n\n## `fastapi run` { #fastapi-run }\n\nExécuter `fastapi run` démarre FastAPI en mode production par défaut.\n\nPar défaut, l’**auto-reload** est désactivé. Il écoute aussi sur l’adresse IP `0.0.0.0`, ce qui signifie toutes les adresses IP disponibles ; de cette manière, il sera accessible publiquement à toute personne pouvant communiquer avec la machine. C’est ainsi que vous l’exécutez normalement en production, par exemple dans un conteneur.\n\nDans la plupart des cas, vous avez (et devez avoir) un « termination proxy » au‑dessus qui gère le HTTPS pour vous ; cela dépend de la façon dont vous déployez votre application : votre fournisseur peut le faire pour vous, ou vous devrez le configurer vous‑même.\n\n/// tip | Astuce\n\nVous pouvez en savoir plus à ce sujet dans la [documentation de déploiement](deployment/index.md).\n\n///\n"
  },
  {
    "path": "docs/fr/docs/features.md",
    "content": "# Fonctionnalités { #features }\n\n## Fonctionnalités de FastAPI { #fastapi-features }\n\n**FastAPI** vous offre les éléments suivants :\n\n### Basé sur des standards ouverts { #based-on-open-standards }\n\n* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) pour la création d'API, incluant la déclaration de <dfn title=\"aussi connu comme : endpoints, routes\">chemin</dfn> <dfn title=\"aussi connu comme méthodes HTTP, comme POST, GET, PUT, DELETE\">opérations</dfn>, paramètres, corps de requêtes, sécurité, etc.\n* Documentation automatique des modèles de données avec [**JSON Schema**](https://json-schema.org/) (puisque OpenAPI est lui-même basé sur JSON Schema).\n* Conçu autour de ces standards, après une étude méticuleuse. Plutôt qu'une couche ajoutée après coup.\n* Cela permet également d'utiliser la **génération automatique de code client** dans de nombreux langages.\n\n### Documentation automatique { #automatic-docs }\n\nDocumentation d'API interactive et interfaces web d'exploration. Comme le framework est basé sur OpenAPI, plusieurs options existent, 2 incluses par défaut.\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui), avec exploration interactive, appelez et testez votre API directement depuis le navigateur.\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Documentation d'API alternative avec [**ReDoc**](https://github.com/Rebilly/ReDoc).\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Uniquement du Python moderne { #just-modern-python }\n\nTout est basé sur les déclarations de **types Python** standard (grâce à Pydantic). Aucune nouvelle syntaxe à apprendre. Juste du Python moderne standard.\n\nSi vous avez besoin d'un rappel de 2 minutes sur l'utilisation des types en Python (même si vous n'utilisez pas FastAPI), consultez le court tutoriel : [Types Python](python-types.md).\n\nVous écrivez du Python standard avec des types :\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# Déclarez une variable comme étant une str\n# et profitez de l'aide de l'éditeur dans cette fonction\ndef main(user_id: str):\n    return user_id\n\n\n# Un modèle Pydantic\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\nQui peuvent ensuite être utilisés comme ceci :\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n/// info\n\n`**second_user_data` signifie :\n\nPassez les clés et valeurs du dictionnaire `second_user_data` directement comme arguments clé-valeur, équivalent à : `User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### Support des éditeurs { #editor-support }\n\nTout le framework a été conçu pour être facile et intuitif à utiliser, toutes les décisions ont été testées sur plusieurs éditeurs avant même de commencer le développement, pour assurer la meilleure expérience de développement.\n\nDans les enquêtes auprès des développeurs Python, il est clair [que l’une des fonctionnalités les plus utilisées est « autocomplétion »](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).\n\nL'ensemble du framework **FastAPI** est conçu pour satisfaire cela. L'autocomplétion fonctionne partout.\n\nVous aurez rarement besoin de revenir aux documents.\n\nVoici comment votre éditeur peut vous aider :\n\n* dans [Visual Studio Code](https://code.visualstudio.com/) :\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* dans [PyCharm](https://www.jetbrains.com/pycharm/) :\n\n![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\nVous obtiendrez de l'autocomplétion dans du code que vous auriez pu considérer impossible auparavant. Par exemple, la clé `price` à l'intérieur d'un corps JSON (qui aurait pu être imbriqué) provenant d'une requête.\n\nFini de taper des noms de clés erronés, de faire des allers-retours entre les documents, ou de faire défiler vers le haut et vers le bas pour savoir si vous avez finalement utilisé `username` ou `user_name`.\n\n### Court { #short }\n\nDes **valeurs par défaut** sensées pour tout, avec des configurations optionnelles partout. Tous les paramètres peuvent être ajustés finement pour faire ce dont vous avez besoin et définir l'API dont vous avez besoin.\n\nMais par défaut, tout **« just works »**.\n\n### Validation { #validation }\n\n* Validation pour la plupart (ou tous ?) des **types de données** Python, y compris :\n    * objets JSON (`dict`).\n    * tableaux JSON (`list`) définissant les types d'éléments.\n    * champs String (`str`), définition des longueurs minimale et maximale.\n    * nombres (`int`, `float`) avec valeurs minimale et maximale, etc.\n\n* Validation pour des types plus exotiques, comme :\n    * URL.\n    * Email.\n    * UUID.\n    * ... et autres.\n\nToutes les validations sont gérées par le **Pydantic** bien établi et robuste.\n\n### Sécurité et authentification { #security-and-authentication }\n\nSécurité et authentification intégrées. Sans aucun compromis avec les bases de données ou les modèles de données.\n\nTous les schémas de sécurité définis dans OpenAPI, y compris :\n\n* HTTP Basic.\n* **OAuth2** (également avec des **tokens JWT**). Consultez le tutoriel [OAuth2 avec JWT](tutorial/security/oauth2-jwt.md).\n* Clés d'API dans :\n    * les en-têtes.\n    * les paramètres de requête.\n    * les cookies, etc.\n\nPlus toutes les fonctionnalités de sécurité de Starlette (y compris les **cookies de session**).\n\nLe tout construit comme des outils et composants réutilisables, faciles à intégrer à vos systèmes, magasins de données, bases de données relationnelles et NoSQL, etc.\n\n### Injection de dépendances { #dependency-injection }\n\nFastAPI inclut un système d’<dfn title='aussi connu sous le nom de « composants », « ressources », « services », « fournisseurs »'><strong>Injection de dépendances</strong></dfn> extrêmement simple à utiliser, mais extrêmement puissant.\n\n* Même les dépendances peuvent avoir des dépendances, créant une hiérarchie ou un **« graphe » de dépendances**.\n* Le tout **géré automatiquement** par le framework.\n* Toutes les dépendances peuvent exiger des données des requêtes et **augmenter les contraintes du chemin d'accès** ainsi que la documentation automatique.\n* **Validation automatique** même pour les paramètres de *chemin d'accès* définis dans les dépendances.\n* Prise en charge des systèmes d'authentification d'utilisateurs complexes, des **connexions de base de données**, etc.\n* **Aucun compromis** avec les bases de données, les frontends, etc. Mais une intégration facile avec tous.\n\n### « Plug-ins » illimités { #unlimited-plug-ins }\n\nOu, autrement dit, pas besoin d'eux, importez et utilisez le code dont vous avez besoin.\n\nToute intégration est conçue pour être si simple à utiliser (avec des dépendances) que vous pouvez créer un « plug-in » pour votre application en 2 lignes de code en utilisant la même structure et la même syntaxe que pour vos *chemins d'accès*.\n\n### Testé { #tested }\n\n* 100 % de <dfn title=\"La quantité de code testée automatiquement\">couverture de test</dfn>.\n* 100 % de base de code <dfn title=\"Annotations de type Python ; avec cela votre éditeur et les outils externes peuvent vous offrir un meilleur support\">annotée avec des types</dfn>.\n* Utilisé dans des applications en production.\n\n## Fonctionnalités de Starlette { #starlette-features }\n\n**FastAPI** est entièrement compatible avec (et basé sur) [**Starlette**](https://www.starlette.dev/). Donc, tout code Starlette additionnel que vous avez fonctionnera aussi.\n\n`FastAPI` est en fait une sous-classe de `Starlette`. Ainsi, si vous connaissez ou utilisez déjà Starlette, la plupart des fonctionnalités fonctionneront de la même manière.\n\nAvec **FastAPI** vous obtenez toutes les fonctionnalités de **Starlette** (puisque FastAPI est juste Starlette sous stéroïdes) :\n\n* Des performances vraiment impressionnantes. C'est [l’un des frameworks Python les plus rapides disponibles, à l’égal de **NodeJS** et **Go**](https://github.com/encode/starlette#performance).\n* Prise en charge des **WebSocket**.\n* Tâches d'arrière-plan dans le processus.\n* Évènements de démarrage et d'arrêt.\n* Client de test basé sur HTTPX.\n* **CORS**, GZip, fichiers statiques, réponses en streaming.\n* Prise en charge des **Sessions et Cookies**.\n* Couverture de test à 100 %.\n* Base de code annotée à 100 % avec des types.\n\n## Fonctionnalités de Pydantic { #pydantic-features }\n\n**FastAPI** est entièrement compatible avec (et basé sur) [**Pydantic**](https://docs.pydantic.dev/). Donc, tout code Pydantic additionnel que vous avez fonctionnera aussi.\n\nY compris des bibliothèques externes également basées sur Pydantic, servant d’<abbr title=\"Object-Relational Mapper - Mappeur objet-relationnel\">ORM</abbr>, d’<abbr title=\"Object-Document Mapper - Mappeur objet-document\">ODM</abbr> pour les bases de données.\n\nCela signifie également que, dans de nombreux cas, vous pouvez passer l'objet que vous recevez d'une requête **directement à la base de données**, puisque tout est validé automatiquement.\n\nL’inverse est également vrai, dans de nombreux cas, vous pouvez simplement passer l'objet que vous récupérez de la base de données **directement au client**.\n\nAvec **FastAPI** vous obtenez toutes les fonctionnalités de **Pydantic** (puisque FastAPI est basé sur Pydantic pour toute la gestion des données) :\n\n* **Pas de prise de tête** :\n    * Pas de micro-langage de définition de schéma à apprendre.\n    * Si vous connaissez les types Python vous savez utiliser Pydantic.\n* Fonctionne bien avec votre **<abbr title=\"Integrated Development Environment - Environnement de développement intégré: similaire à un éditeur de code\">IDE</abbr>/<dfn title=\"Programme qui vérifie les erreurs de code\">linter</dfn>/cerveau** :\n    * Parce que les structures de données de Pydantic sont simplement des instances de classes que vous définissez ; l'autocomplétion, le linting, mypy et votre intuition devraient tous bien fonctionner avec vos données validées.\n* Valider des **structures complexes** :\n    * Utilisation de modèles Pydantic hiérarchiques, de `List` et `Dict` du `typing` Python, etc.\n    * Et les validateurs permettent de définir, vérifier et documenter clairement et facilement des schémas de données complexes en tant que JSON Schema.\n    * Vous pouvez avoir des objets **JSON fortement imbriqués** et les faire tous valider et annoter.\n* **Extensible** :\n    * Pydantic permet de définir des types de données personnalisés ou vous pouvez étendre la validation avec des méthodes sur un modèle décoré avec le décorateur de validation.\n* Couverture de test à 100 %.\n"
  },
  {
    "path": "docs/fr/docs/help-fastapi.md",
    "content": "# Aider FastAPI - Obtenir de l'aide { #help-fastapi-get-help }\n\nAimez-vous **FastAPI** ?\n\nSouhaitez-vous aider FastAPI, les autres utilisateurs et l'auteur ?\n\nOu souhaitez-vous obtenir de l'aide avec **FastAPI** ?\n\nIl existe des moyens très simples d'aider (plusieurs ne nécessitent qu'un ou deux clics).\n\nEt il existe aussi plusieurs façons d'obtenir de l'aide.\n\n## S'abonner à la newsletter { #subscribe-to-the-newsletter }\n\nVous pouvez vous abonner à la (peu fréquente) [newsletter **FastAPI and friends**](newsletter.md) pour rester informé à propos :\n\n* Nouvelles sur FastAPI et ses amis 🚀\n* Guides 📝\n* Fonctionnalités ✨\n* Changements majeurs 🚨\n* Astuces et conseils ✅\n\n## Suivre FastAPI sur X (Twitter) { #follow-fastapi-on-x-twitter }\n\n[Suivez @fastapi sur **X (Twitter)**](https://x.com/fastapi) pour obtenir les dernières nouvelles sur **FastAPI**. 🐦\n\n## Mettre une étoile à **FastAPI** sur GitHub { #star-fastapi-in-github }\n\nVous pouvez « star » FastAPI sur GitHub (en cliquant sur le bouton étoile en haut à droite) : [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). ⭐️\n\nEn ajoutant une étoile, les autres utilisateurs pourront le trouver plus facilement et voir qu'il a déjà été utile à d'autres.\n\n## Suivre le dépôt GitHub pour les releases { #watch-the-github-repository-for-releases }\n\nVous pouvez « watch » FastAPI sur GitHub (en cliquant sur le bouton « watch » en haut à droite) : [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nVous pouvez y sélectionner « Releases only ».\n\nAinsi, vous recevrez des notifications (par e‑mail) chaque fois qu'il y aura une nouvelle release (une nouvelle version) de **FastAPI** avec des corrections de bugs et de nouvelles fonctionnalités.\n\n## Entrer en contact avec l'auteur { #connect-with-the-author }\n\nVous pouvez entrer en contact avec [moi (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com), l'auteur.\n\nVous pouvez :\n\n* [Me suivre sur **GitHub**](https://github.com/tiangolo).\n    * Voir d'autres projets Open Source que j'ai créés et qui pourraient vous aider.\n    * Me suivre pour voir quand je crée un nouveau projet Open Source.\n* [Me suivre sur **X (Twitter)**](https://x.com/tiangolo) ou sur [Mastodon](https://fosstodon.org/@tiangolo).\n    * Me dire comment vous utilisez FastAPI (j'adore l'entendre).\n    * Être informé quand je fais des annonces ou publie de nouveaux outils.\n    * Vous pouvez aussi [suivre @fastapi sur X (Twitter)](https://x.com/fastapi) (un compte séparé).\n* [Me suivre sur **LinkedIn**](https://www.linkedin.com/in/tiangolo/).\n    * Être informé quand je fais des annonces ou publie de nouveaux outils (même si j'utilise plus souvent X (Twitter) 🤷‍♂).\n* Lire ce que j'écris (ou me suivre) sur [**Dev.to**](https://dev.to/tiangolo) ou [**Medium**](https://medium.com/@tiangolo).\n    * Lire d'autres idées, des articles, et découvrir des outils que j'ai créés.\n    * Me suivre pour lire quand je publie quelque chose de nouveau.\n\n## Tweeter à propos de **FastAPI** { #tweet-about-fastapi }\n\n[Tweetez à propos de **FastAPI**](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi) et faites savoir à moi et aux autres pourquoi vous l'appréciez. 🎉\n\nJ'adore entendre comment **FastAPI** est utilisé, ce que vous avez aimé, dans quel projet/quelle entreprise vous l'utilisez, etc.\n\n## Voter pour FastAPI { #vote-for-fastapi }\n\n* [Votez pour **FastAPI** sur Slant](https://www.slant.co/options/34241/~fastapi-review).\n* [Votez pour **FastAPI** sur AlternativeTo](https://alternativeto.net/software/fastapi/about/).\n* [Indiquez que vous utilisez **FastAPI** sur StackShare](https://stackshare.io/pypi-fastapi).\n\n## Aider les autres avec des questions sur GitHub { #help-others-with-questions-in-github }\n\nVous pouvez essayer d'aider les autres avec leurs questions dans :\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\nDans de nombreux cas, vous connaissez peut-être déjà la réponse à ces questions. 🤓\n\nSi vous aidez beaucoup de personnes avec leurs questions, vous deviendrez un [Expert FastAPI](fastapi-people.md#fastapi-experts) officiel. 🎉\n\nN'oubliez pas, le point le plus important est : essayez d'être aimable. Les gens viennent avec leurs frustrations et, dans bien des cas, ne posent pas la question de la meilleure façon, mais faites de votre mieux pour rester aimable. 🤗\n\nL'idée est que la communauté **FastAPI** soit bienveillante et accueillante. En même temps, n'acceptez pas l'intimidation ni les comportements irrespectueux envers les autres. Nous devons prendre soin les uns des autres.\n\n---\n\nVoici comment aider les autres avec des questions (dans les discussions ou les issues) :\n\n### Comprendre la question { #understand-the-question }\n\n* Vérifiez si vous comprenez quel est l’**objectif** et le cas d'utilisation de la personne qui pose la question.\n\n* Ensuite, vérifiez si la question (la grande majorité sont des questions) est **claire**.\n\n* Dans de nombreux cas, la question porte sur une solution imaginaire de l'utilisateur, mais il pourrait y en avoir une **meilleure**. Si vous comprenez mieux le problème et le cas d'utilisation, vous pourriez suggérer une **solution alternative** plus adaptée.\n\n* Si vous ne comprenez pas la question, demandez plus de **détails**.\n\n### Reproduire le problème { #reproduce-the-problem }\n\nDans la plupart des cas et pour la plupart des questions, il y a quelque chose lié au **code original** de la personne.\n\nDans de nombreux cas, elle ne copiera qu'un fragment de code, mais ce n'est pas suffisant pour **reproduire le problème**.\n\n* Vous pouvez leur demander de fournir un [exemple minimal, complet et vérifiable](https://stackoverflow.com/help/minimal-reproducible-example), que vous pouvez **copier‑coller** et exécuter localement pour voir la même erreur ou le même comportement qu'ils observent, ou pour mieux comprendre leur cas d'utilisation.\n\n* Si vous vous sentez très généreux, vous pouvez essayer de **créer un tel exemple** vous‑même, simplement à partir de la description du problème. Gardez simplement à l'esprit que cela peut prendre beaucoup de temps et qu'il peut être préférable de leur demander d'abord de clarifier le problème.\n\n### Suggérer des solutions { #suggest-solutions }\n\n* Après avoir compris la question, vous pouvez leur donner une **réponse** possible.\n\n* Dans de nombreux cas, il est préférable de comprendre leur **problème sous‑jacent ou cas d'utilisation**, car il pourrait exister une meilleure façon de le résoudre que ce qu'ils essaient de faire.\n\n### Demander la clôture { #ask-to-close }\n\nS'ils répondent, il y a de fortes chances que vous ayez résolu leur problème, bravo, **vous êtes un héros** ! 🦸\n\n* Maintenant, si cela a résolu leur problème, vous pouvez leur demander de :\n\n    * Dans GitHub Discussions : marquer le commentaire comme **réponse**.\n    * Dans GitHub Issues : **fermer** l'issue.\n\n## Suivre le dépôt GitHub { #watch-the-github-repository }\n\nVous pouvez « watch » FastAPI sur GitHub (en cliquant sur le bouton « watch » en haut à droite) : [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nSi vous sélectionnez « Watching » au lieu de « Releases only », vous recevrez des notifications lorsque quelqu'un crée une nouvelle issue ou question. Vous pouvez aussi préciser que vous ne souhaitez être notifié que pour les nouvelles issues, ou les discussions, ou les PR, etc.\n\nVous pouvez alors essayer de les aider à résoudre ces questions.\n\n## Poser des questions { #ask-questions }\n\nVous pouvez [créer une nouvelle question](https://github.com/fastapi/fastapi/discussions/new?category=questions) dans le dépôt GitHub, par exemple pour :\n\n* Poser une **question** ou demander à propos d'un **problème**.\n* Suggérer une nouvelle **fonctionnalité**.\n\n**Remarque** : si vous le faites, je vais vous demander d'aider aussi les autres. 😉\n\n## Relire des Pull Requests { #review-pull-requests }\n\nVous pouvez m'aider à relire les pull requests des autres.\n\nEncore une fois, essayez autant que possible d'être aimable. 🤗\n\n---\n\nVoici ce à garder à l'esprit et comment relire une pull request :\n\n### Comprendre le problème { #understand-the-problem }\n\n* D'abord, assurez‑vous de **comprendre le problème** que la pull request essaie de résoudre. Il peut y avoir une discussion plus longue dans une GitHub Discussion ou une issue.\n\n* Il y a aussi de bonnes chances que la pull request ne soit pas réellement nécessaire parce que le problème peut être résolu d'une **autre manière**. Vous pouvez alors le suggérer ou poser la question.\n\n### Ne pas s'inquiéter du style { #dont-worry-about-style }\n\n* Ne vous souciez pas trop des choses comme les styles de messages de commit, je ferai un squash and merge en personnalisant le commit manuellement.\n\n* Ne vous inquiétez pas non plus des règles de style, il existe déjà des outils automatisés qui vérifient cela.\n\nEt s'il y a d'autres besoins de style ou de cohérence, je le demanderai directement, ou j'ajouterai des commits par‑dessus avec les changements nécessaires.\n\n### Vérifier le code { #check-the-code }\n\n* Vérifiez et lisez le code, voyez s'il a du sens, **exécutez‑le localement** et voyez s'il résout effectivement le problème.\n\n* Ensuite, **commentez** en disant que vous l'avez fait, c'est ainsi que je saurai que vous l'avez vraiment vérifié.\n\n/// info\n\nMalheureusement, je ne peux pas simplement faire confiance aux PR qui ont juste plusieurs approbations.\n\nPlusieurs fois, il est arrivé qu'il y ait des PR avec 3, 5 ou plus approbations, probablement parce que la description est attrayante, mais lorsque je vérifie les PR, elles sont en fait cassées, ont un bug, ou ne résolvent pas le problème qu'elles prétendent résoudre. 😅\n\nDonc, il est vraiment important que vous lisiez et exécutiez le code, et que vous me le disiez dans les commentaires. 🤓\n\n///\n\n* Si la PR peut être simplifiée d'une certaine manière, vous pouvez le demander, mais il n'est pas nécessaire d'être trop pointilleux, il peut y avoir beaucoup de points de vue subjectifs (et j'aurai les miens aussi 🙈), donc il est préférable de vous concentrer sur les choses fondamentales.\n\n### Tests { #tests }\n\n* Aidez‑moi à vérifier que la PR a des **tests**.\n\n* Vérifiez que les tests **échouent** avant la PR. 🚨\n\n* Puis vérifiez que les tests **réussissent** après la PR. ✅\n\n* Beaucoup de PR n'ont pas de tests, vous pouvez leur **rappeler** d'ajouter des tests, ou même **suggérer** des tests vous‑même. C'est l'une des choses qui consomment le plus de temps et vous pouvez beaucoup aider.\n\n* Commentez aussi ce que vous avez essayé, ainsi je saurai que vous l'avez vérifié. 🤓\n\n## Créer une Pull Request { #create-a-pull-request }\n\nVous pouvez [contribuer](contributing.md) au code source avec des Pull Requests, par exemple :\n\n* Corriger une coquille que vous avez trouvée dans la documentation.\n* Partager un article, une vidéo ou un podcast que vous avez créé ou trouvé à propos de FastAPI en [modifiant ce fichier](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml).\n    * Vous devez vous assurer d'ajouter votre lien au début de la section correspondante.\n* Aider à [traduire la documentation](contributing.md#translations) dans votre langue.\n    * Vous pouvez aussi aider à relire les traductions créées par d'autres.\n* Proposer de nouvelles sections de documentation.\n* Corriger une issue/un bug existant.\n    * Vous devez ajouter des tests.\n* Ajouter une nouvelle fonctionnalité.\n    * Vous devez ajouter des tests.\n    * Vous devez ajouter de la documentation si c'est pertinent.\n\n## Aider à maintenir FastAPI { #help-maintain-fastapi }\n\nAidez‑moi à maintenir **FastAPI** ! 🤓\n\nIl y a beaucoup de travail à faire, et pour la plupart, **VOUS** pouvez le faire.\n\nLes principales tâches que vous pouvez faire dès maintenant sont :\n\n* [Aider les autres avec des questions sur GitHub](#help-others-with-questions-in-github) (voir la section ci‑dessus).\n* [Relire des Pull Requests](#review-pull-requests) (voir la section ci‑dessus).\n\nCes deux tâches sont celles qui **consomment le plus de temps**. C'est le travail principal de la maintenance de FastAPI.\n\nSi vous pouvez m'aider avec cela, **vous m'aidez à maintenir FastAPI** et à vous assurer qu'il continue **d'avancer plus vite et mieux**. 🚀\n\n## Rejoindre le chat { #join-the-chat }\n\nRejoignez le 👥 [serveur Discord](https://discord.gg/VQjSZaeJmf) 👥 et échangez avec d'autres membres de la communauté FastAPI.\n\n/// tip | Astuce\n\nPour les questions, posez‑les dans [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions), vous avez bien plus de chances de recevoir de l'aide par les [Experts FastAPI](fastapi-people.md#fastapi-experts).\n\nUtilisez le chat uniquement pour d'autres conversations générales.\n\n///\n\n### N'utilisez pas le chat pour les questions { #dont-use-the-chat-for-questions }\n\nGardez à l'esprit que, comme les chats permettent une « conversation libre », il est facile de poser des questions trop générales et plus difficiles à répondre ; vous pourriez donc ne pas recevoir de réponses.\n\nSur GitHub, le modèle vous guidera pour rédiger 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 de demander. Et sur GitHub, je peux m'assurer de toujours tout répondre, même si cela prend du temps. Je ne peux pas personnellement faire cela avec les systèmes de chat. 😅\n\nLes conversations dans les systèmes de chat ne sont pas non plus aussi facilement recherchables que sur GitHub, donc les questions et réponses peuvent se perdre dans la conversation. Et seules celles sur GitHub comptent pour devenir un [Expert FastAPI](fastapi-people.md#fastapi-experts), vous aurez donc très probablement plus d'attention sur GitHub.\n\nD'un autre côté, il y a des milliers d'utilisateurs dans les systèmes de chat, il y a donc de fortes chances que vous trouviez presque toujours quelqu'un avec qui parler. 😄\n\n## Sponsoriser l'auteur { #sponsor-the-author }\n\nSi votre **produit/entreprise** dépend de **FastAPI** ou y est lié et que vous souhaitez atteindre ses utilisateurs, vous pouvez sponsoriser l'auteur (moi) via [GitHub sponsors](https://github.com/sponsors/tiangolo). Selon le niveau, vous pourriez obtenir des avantages supplémentaires, comme un badge dans les documents. 🎁\n\n---\n\nMerci ! 🚀\n"
  },
  {
    "path": "docs/fr/docs/history-design-future.md",
    "content": "# Histoire, conception et avenir { #history-design-and-future }\n\nIl y a quelque temps, [un utilisateur de **FastAPI** a demandé](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920) :\n\n> Quelle est l'histoire de ce projet ? Il semble être sorti de nulle part et est devenu génial en quelques semaines [...].\n\nVoici un petit bout de cette histoire.\n\n## Alternatives { #alternatives }\n\nJe crée des API avec des exigences complexes depuis plusieurs années (Machine Learning, systèmes distribués, jobs asynchrones, bases de données NoSQL, etc), en dirigeant plusieurs équipes de développeurs.\n\nDans ce cadre, j'ai dû étudier, tester et utiliser de nombreuses alternatives.\n\nL'histoire de **FastAPI** est en grande partie l'histoire de ses prédécesseurs.\n\nComme dit dans la section [Alternatives](alternatives.md) :\n\n<blockquote markdown=\"1\">\n\n**FastAPI** n'existerait pas sans le travail antérieur d'autres personnes.\n\nIl y a eu de nombreux outils créés auparavant qui ont contribué à inspirer sa création.\n\nJ'ai évité la création d'un nouveau framework pendant plusieurs années. J'ai d'abord essayé de résoudre toutes les fonctionnalités couvertes par **FastAPI** en utilisant de nombreux frameworks, plug-ins et outils différents.\n\nMais à un moment donné, il n'y avait pas d'autre option que de créer quelque chose qui offre toutes ces fonctionnalités, en prenant les meilleures idées des outils précédents, et en les combinant de la meilleure façon possible, en utilisant des fonctionnalités du langage qui n'étaient même pas disponibles auparavant (annotations de type pour Python 3.6+).\n\n</blockquote>\n\n## Recherche { #investigation }\n\nEn utilisant toutes les alternatives précédentes, j'ai eu la chance d'apprendre de toutes, de prendre des idées, et de les combiner de la meilleure façon que j'ai pu trouver pour moi-même et les équipes de développeurs avec lesquelles j'ai travaillé.\n\nPar exemple, il était clair que l'idéal était de se baser sur les annotations de type Python standard.\n\nDe plus, la meilleure approche était d'utiliser des normes déjà existantes.\n\nAinsi, avant même de commencer à coder **FastAPI**, j'ai passé plusieurs mois à étudier les spécifications d'OpenAPI, JSON Schema, OAuth2, etc. Comprendre leurs relations, leurs similarités et leurs différences.\n\n## Conception { #design }\n\nEnsuite, j'ai passé du temps à concevoir l'« API » de développeur que je voulais avoir en tant qu'utilisateur (en tant que développeur utilisant FastAPI).\n\nJ'ai testé plusieurs idées dans les éditeurs Python les plus populaires : PyCharm, VS Code, les éditeurs basés sur Jedi.\n\nD'après la dernière [Enquête Développeurs Python](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools), cela couvre environ 80% des utilisateurs.\n\nCela signifie que **FastAPI** a été spécifiquement testé avec les éditeurs utilisés par 80% des développeurs Python. Et comme la plupart des autres éditeurs ont tendance à fonctionner de façon similaire, tous ses avantages devraient fonctionner pour pratiquement tous les éditeurs.\n\nAinsi, j'ai pu trouver les meilleurs moyens de réduire autant que possible la duplication du code, d'avoir l'autocomplétion partout, les contrôles de type et d'erreur, etc.\n\nLe tout de manière à offrir la meilleure expérience de développement à tous les développeurs.\n\n## Exigences { #requirements }\n\nAprès avoir testé plusieurs alternatives, j'ai décidé que j'allais utiliser [**Pydantic**](https://docs.pydantic.dev/) pour ses avantages.\n\nJ'y ai ensuite contribué, pour le rendre entièrement compatible avec JSON Schema, pour supporter différentes manières de définir les déclarations de contraintes, et pour améliorer le support des éditeurs (vérifications de type, autocomplétion) sur la base des tests effectués dans plusieurs éditeurs.\n\nPendant le développement, j'ai également contribué à [**Starlette**](https://www.starlette.dev/), l'autre exigence clé.\n\n## Développement { #development }\n\nAu moment où j'ai commencé à créer **FastAPI** lui-même, la plupart des pièces étaient déjà en place, la conception était définie, les exigences et les outils étaient prêts, et la connaissance des normes et des spécifications était claire et fraîche.\n\n## Futur { #future }\n\nÀ ce stade, il est déjà clair que **FastAPI** et ses idées sont utiles pour de nombreuses personnes.\n\nElle a été préférée aux solutions précédentes parce qu'elle convient mieux à de nombreux cas d'utilisation.\n\nDe nombreux développeurs et équipes dépendent déjà de **FastAPI** pour leurs projets (y compris moi et mon équipe).\n\nMais il y a encore de nombreuses améliorations et fonctionnalités à venir.\n\n**FastAPI** a un grand avenir devant lui.\n\nEt [votre aide](help-fastapi.md) est grandement appréciée.\n"
  },
  {
    "path": "docs/fr/docs/how-to/authentication-error-status-code.md",
    "content": "# Utiliser les anciens codes d'erreur d'authentification 403 { #use-old-403-authentication-error-status-codes }\n\nAvant FastAPI version `0.122.0`, lorsque les utilitaires de sécurité intégrés renvoyaient une erreur au client après un échec d'authentification, ils utilisaient le code d'état HTTP `403 Forbidden`.\n\nÀ partir de FastAPI version `0.122.0`, ils utilisent le code d'état HTTP plus approprié `401 Unauthorized`, et renvoient un en-tête `WWW-Authenticate` pertinent dans la réponse, conformément aux spécifications HTTP, [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized).\n\nMais si, pour une raison quelconque, vos clients dépendent de l'ancien comportement, vous pouvez y revenir en surchargeant la méthode `make_not_authenticated_error` dans vos classes de sécurité.\n\nPar exemple, vous pouvez créer une sous-classe de `HTTPBearer` qui renvoie une erreur `403 Forbidden` au lieu de l'erreur par défaut `401 Unauthorized` :\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip | Astuce\n\nRemarquez que la fonction renvoie l'instance de l'exception, elle ne la lève pas. La levée est effectuée dans le reste du code interne.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/how-to/conditional-openapi.md",
    "content": "# Configurer OpenAPI de manière conditionnelle { #conditional-openapi }\n\nSi nécessaire, vous pouvez utiliser des paramètres et des variables d'environnement pour configurer OpenAPI de manière conditionnelle selon l'environnement, et même le désactiver complètement.\n\n## À propos de la sécurité, des API et des documents { #about-security-apis-and-docs }\n\nMasquer vos interfaces utilisateur des documents en production ne devrait pas être la manière de protéger votre API.\n\nCela n'ajoute aucune sécurité supplémentaire à votre API, les *chemins d'accès* resteront disponibles là où ils se trouvent.\n\nS'il y a une faille de sécurité dans votre code, elle existera toujours.\n\nMasquer les documents rend simplement plus difficile la compréhension de la manière d'interagir avec votre API et pourrait aussi rendre son débogage en production plus difficile. Cela pourrait être considéré simplement comme une forme de [Sécurité par l'obscurité](https://en.wikipedia.org/wiki/Security_through_obscurity).\n\nSi vous voulez sécuriser votre API, il y a plusieurs meilleures approches possibles, par exemple :\n\n* Vous devez vous assurer d'avoir des modèles Pydantic bien définis pour le corps de la requête et la réponse.\n* Configurez toutes les autorisations et tous les rôles nécessaires à l'aide de dépendances.\n* Ne stockez jamais de mots de passe en clair, seulement des hachages de mots de passe.\n* Implémentez et utilisez des outils cryptographiques reconnus, comme pwdlib et des jetons JWT, ... etc.\n* Ajoutez des contrôles d'autorisation plus granulaires avec des scopes OAuth2 lorsque nécessaire.\n* ... etc.\n\nNéanmoins, vous pourriez avoir un cas d'utilisation très spécifique où vous devez vraiment désactiver les documents de l'API pour un certain environnement (par exemple pour la production) ou selon des configurations provenant de variables d'environnement.\n\n## Configurer OpenAPI de manière conditionnelle avec des paramètres et des variables d'environnement { #conditional-openapi-from-settings-and-env-vars }\n\nVous pouvez facilement utiliser les mêmes paramètres Pydantic pour configurer votre OpenAPI généré et les interfaces utilisateur des documents.\n\nPar exemple :\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\nIci nous déclarons le paramètre `openapi_url` avec la même valeur par défaut `\"/openapi.json\"`.\n\nNous l'utilisons ensuite lors de la création de l'application `FastAPI`.\n\nVous pouvez alors désactiver OpenAPI (y compris les interfaces utilisateur des documents) en définissant la variable d'environnement `OPENAPI_URL` sur la chaîne vide, comme ceci :\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nEnsuite, si vous allez aux URL `/openapi.json`, `/docs` ou `/redoc`, vous obtiendrez simplement une erreur `404 Not Found` comme :\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/fr/docs/how-to/configure-swagger-ui.md",
    "content": "# Configurer Swagger UI { #configure-swagger-ui }\n\nVous pouvez configurer des [paramètres supplémentaires de Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\nPour les configurer, passez l'argument `swagger_ui_parameters` lors de la création de l'objet d'application `FastAPI()` ou à la fonction `get_swagger_ui_html()`.\n\n`swagger_ui_parameters` reçoit un dictionnaire avec les configurations passées directement à Swagger UI.\n\nFastAPI convertit les configurations en **JSON** pour les rendre compatibles avec JavaScript, car c'est ce dont Swagger UI a besoin.\n\n## Désactiver la coloration syntaxique { #disable-syntax-highlighting }\n\nPar exemple, vous pourriez désactiver la coloration syntaxique dans Swagger UI.\n\nSans modifier les paramètres, la coloration syntaxique est activée par défaut :\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\nMais vous pouvez la désactiver en définissant `syntaxHighlight` à `False` :\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n... et ensuite Swagger UI n'affichera plus la coloration syntaxique :\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## Modifier le thème { #change-the-theme }\n\nDe la même manière, vous pouvez définir le thème de la coloration syntaxique avec la clé « syntaxHighlight.theme » (remarquez le point au milieu) :\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\nCette configuration modifierait le thème de couleurs de la coloration syntaxique :\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## Modifier les paramètres Swagger UI par défaut { #change-default-swagger-ui-parameters }\n\nFastAPI inclut des paramètres de configuration par défaut adaptés à la plupart des cas d'utilisation.\n\nIl inclut ces configurations par défaut :\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\nVous pouvez remplacer n'importe lequel d'entre eux en définissant une valeur différente dans l'argument `swagger_ui_parameters`.\n\nPar exemple, pour désactiver `deepLinking`, vous pourriez passer ces paramètres à `swagger_ui_parameters` :\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## Autres paramètres de Swagger UI { #other-swagger-ui-parameters }\n\nPour voir toutes les autres configurations possibles que vous pouvez utiliser, lisez les [documents officiels pour les paramètres de Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\n## Paramètres JavaScript uniquement { #javascript-only-settings }\n\nSwagger UI permet également d'autres configurations qui sont des objets réservés à JavaScript (par exemple, des fonctions JavaScript).\n\nFastAPI inclut aussi ces paramètres `presets` réservés à JavaScript :\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\nCe sont des objets **JavaScript**, pas des chaînes, vous ne pouvez donc pas les passer directement depuis du code Python.\n\nSi vous devez utiliser des configurations réservées à JavaScript comme celles-ci, vous pouvez utiliser l'une des méthodes ci-dessus. Surchargez entièrement le *chemin d'accès* Swagger UI et écrivez manuellement tout JavaScript nécessaire.\n"
  },
  {
    "path": "docs/fr/docs/how-to/custom-docs-ui-assets.md",
    "content": "# Héberger en propre les ressources statiques de l’UI des docs personnalisées { #custom-docs-ui-static-assets-self-hosting }\n\nLes documents de l’API utilisent **Swagger UI** et **ReDoc**, et chacune nécessite des fichiers JavaScript et CSS.\n\nPar défaut, ces fichiers sont servis depuis un <abbr title=\"Content Delivery Network - Réseau de diffusion de contenu: Un service, normalement composé de plusieurs serveurs, qui fournit des fichiers statiques, comme JavaScript et CSS. Il est couramment utilisé pour servir ces fichiers depuis le serveur le plus proche du client, améliorant la performance.\">CDN</abbr>.\n\nMais il est possible de le personnaliser : vous pouvez définir un CDN spécifique, ou servir vous‑même les fichiers.\n\n## Configurer un CDN personnalisé pour JavaScript et CSS { #custom-cdn-for-javascript-and-css }\n\nSupposons que vous souhaitiez utiliser un autre <abbr title=\"Content Delivery Network - Réseau de diffusion de contenu\">CDN</abbr>, par exemple vous voulez utiliser `https://unpkg.com/`.\n\nCela peut être utile si, par exemple, vous vivez dans un pays qui restreint certaines URL.\n\n### Désactiver les docs automatiques { #disable-the-automatic-docs }\n\nLa première étape consiste à désactiver les docs automatiques, car par défaut elles utilisent le CDN par défaut.\n\nPour les désactiver, définissez leurs URL sur `None` lors de la création de votre application `FastAPI` :\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### Inclure les docs personnalisées { #include-the-custom-docs }\n\nVous pouvez maintenant créer les chemins d'accès pour les docs personnalisées.\n\nVous pouvez réutiliser les fonctions internes de FastAPI pour créer les pages HTML de la documentation et leur passer les arguments nécessaires :\n\n- `openapi_url` : l’URL où la page HTML des docs peut récupérer le schéma OpenAPI de votre API. Vous pouvez utiliser ici l’attribut `app.openapi_url`.\n- `title` : le titre de votre API.\n- `oauth2_redirect_url` : vous pouvez utiliser `app.swagger_ui_oauth2_redirect_url` ici pour utiliser la valeur par défaut.\n- `swagger_js_url` : l’URL où la page HTML de Swagger UI peut récupérer le fichier **JavaScript**. C’est l’URL du CDN personnalisé.\n- `swagger_css_url` : l’URL où la page HTML de Swagger UI peut récupérer le fichier **CSS**. C’est l’URL du CDN personnalisé.\n\nEt de même pour ReDoc ...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip | Astuce\n\nLe chemin d'accès pour `swagger_ui_redirect` est un assistant lorsque vous utilisez OAuth2.\n\nSi vous intégrez votre API à un fournisseur OAuth2, vous pourrez vous authentifier et revenir aux docs de l’API avec les identifiants acquis. Et interagir avec elle en utilisant la véritable authentification OAuth2.\n\nSwagger UI s’en chargera en arrière‑plan pour vous, mais il a besoin de cet assistant « redirect ».\n\n///\n\n### Créer un chemin d'accès pour tester { #create-a-path-operation-to-test-it }\n\nMaintenant, pour pouvoir vérifier que tout fonctionne, créez un chemin d'accès :\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### Tester { #test-it }\n\nVous devriez maintenant pouvoir aller à vos docs sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), puis recharger la page : elle chargera ces ressources depuis le nouveau CDN.\n\n## Héberger en propre JavaScript et CSS pour les docs { #self-hosting-javascript-and-css-for-docs }\n\nHéberger vous‑même le JavaScript et le CSS peut être utile si, par exemple, votre application doit continuer de fonctionner même hors ligne, sans accès Internet ouvert, ou sur un réseau local.\n\nVous verrez ici comment servir ces fichiers vous‑même, dans la même application FastAPI, et configurer les docs pour les utiliser.\n\n### Structure des fichiers du projet { #project-file-structure }\n\nSupposons que la structure de vos fichiers de projet ressemble à ceci :\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\nCréez maintenant un répertoire pour stocker ces fichiers statiques.\n\nVotre nouvelle structure de fichiers pourrait ressembler à ceci :\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### Télécharger les fichiers { #download-the-files }\n\nTéléchargez les fichiers statiques nécessaires aux docs et placez‑les dans ce répertoire `static/`.\n\nVous pouvez probablement cliquer avec le bouton droit sur chaque lien et choisir une option similaire à « Enregistrer le lien sous ... ».\n\n**Swagger UI** utilise les fichiers :\n\n- [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n- [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\nEt **ReDoc** utilise le fichier :\n\n- [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\nAprès cela, votre structure de fichiers pourrait ressembler à :\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### Servir les fichiers statiques { #serve-the-static-files }\n\n- Importer `StaticFiles`.\n- « Monter » une instance `StaticFiles()` sur un chemin spécifique.\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### Tester les fichiers statiques { #test-the-static-files }\n\nDémarrez votre application et rendez‑vous sur [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js).\n\nVous devriez voir un très long fichier JavaScript pour **ReDoc**.\n\nIl pourrait commencer par quelque chose comme :\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\nCela confirme que vous parvenez à servir des fichiers statiques depuis votre application et que vous avez placé les fichiers statiques des docs au bon endroit.\n\nNous pouvons maintenant configurer l’application pour utiliser ces fichiers statiques pour les docs.\n\n### Désactiver les docs automatiques pour les fichiers statiques { #disable-the-automatic-docs-for-static-files }\n\nComme lors de l’utilisation d’un CDN personnalisé, la première étape consiste à désactiver les docs automatiques, car elles utilisent un CDN par défaut.\n\nPour les désactiver, définissez leurs URL sur `None` lors de la création de votre application `FastAPI` :\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### Inclure les docs personnalisées pour les fichiers statiques { #include-the-custom-docs-for-static-files }\n\nEt comme avec un CDN personnalisé, vous pouvez maintenant créer les chemins d'accès pour les docs personnalisées.\n\nLà encore, vous pouvez réutiliser les fonctions internes de FastAPI pour créer les pages HTML de la documentation et leur passer les arguments nécessaires :\n\n- `openapi_url` : l’URL où la page HTML des docs peut récupérer le schéma OpenAPI de votre API. Vous pouvez utiliser ici l’attribut `app.openapi_url`.\n- `title` : le titre de votre API.\n- `oauth2_redirect_url` : vous pouvez utiliser `app.swagger_ui_oauth2_redirect_url` ici pour utiliser la valeur par défaut.\n- `swagger_js_url` : l’URL où la page HTML de Swagger UI peut récupérer le fichier **JavaScript**. **C’est celui que votre propre application sert désormais**.\n- `swagger_css_url` : l’URL où la page HTML de Swagger UI peut récupérer le fichier **CSS**. **C’est celui que votre propre application sert désormais**.\n\nEt de même pour ReDoc ...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip | Astuce\n\nLe chemin d'accès pour `swagger_ui_redirect` est un assistant lorsque vous utilisez OAuth2.\n\nSi vous intégrez votre API à un fournisseur OAuth2, vous pourrez vous authentifier et revenir aux docs de l’API avec les identifiants acquis. Et interagir avec elle en utilisant la véritable authentification OAuth2.\n\nSwagger UI s’en chargera en arrière‑plan pour vous, mais il a besoin de cet assistant « redirect ».\n\n///\n\n### Créer un chemin d'accès pour tester les fichiers statiques { #create-a-path-operation-to-test-static-files }\n\nMaintenant, pour pouvoir vérifier que tout fonctionne, créez un chemin d'accès :\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### Tester l’UI avec des fichiers statiques { #test-static-files-ui }\n\nVous devriez maintenant pouvoir couper votre Wi‑Fi, aller à vos docs sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) et recharger la page.\n\nEt même sans Internet, vous pourrez voir la documentation de votre API et interagir avec elle.\n"
  },
  {
    "path": "docs/fr/docs/how-to/custom-request-and-route.md",
    "content": "# Personnaliser les classes Request et APIRoute { #custom-request-and-apiroute-class }\n\nDans certains cas, vous pouvez vouloir surcharger la logique utilisée par les classes `Request` et `APIRoute`.\n\nEn particulier, cela peut être une bonne alternative à une logique dans un middleware.\n\nPar exemple, si vous voulez lire ou manipuler le corps de la requête avant qu'il ne soit traité par votre application.\n\n/// danger | Danger\n\nCeci est une fonctionnalité « avancée ».\n\nSi vous débutez avec **FastAPI**, vous pouvez ignorer cette section.\n\n///\n\n## Cas d'utilisation { #use-cases }\n\nVoici quelques cas d'utilisation :\n\n* Convertir des corps de requête non JSON en JSON (par exemple [`msgpack`](https://msgpack.org/index.html)).\n* Décompresser des corps de requête compressés en gzip.\n* Journaliser automatiquement tous les corps de requête.\n\n## Gérer les encodages personnalisés du corps de la requête { #handling-custom-request-body-encodings }\n\nVoyons comment utiliser une sous-classe personnalisée de `Request` pour décompresser des requêtes gzip.\n\nEt une sous-classe d'`APIRoute` pour utiliser cette classe de requête personnalisée.\n\n### Créer une classe `GzipRequest` personnalisée { #create-a-custom-gziprequest-class }\n\n/// tip | Astuce\n\nIl s'agit d'un exemple simplifié pour montrer le fonctionnement ; si vous avez besoin de la prise en charge de Gzip, vous pouvez utiliser le [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware) fourni.\n\n///\n\nCommencez par créer une classe `GzipRequest`, qui va surcharger la méthode `Request.body()` pour décompresser le corps en présence d'un en-tête approprié.\n\nS'il n'y a pas `gzip` dans l'en-tête, elle n'essaiera pas de décompresser le corps.\n\nDe cette manière, la même classe de route peut gérer des requêtes gzip compressées ou non compressées.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### Créer une classe `GzipRoute` personnalisée { #create-a-custom-gziproute-class }\n\nEnsuite, nous créons une sous-classe personnalisée de `fastapi.routing.APIRoute` qui utilisera `GzipRequest`.\n\nCette fois, elle va surcharger la méthode `APIRoute.get_route_handler()`.\n\nCette méthode renvoie une fonction. Et c'est cette fonction qui recevra une requête et retournera une réponse.\n\nIci, nous l'utilisons pour créer une `GzipRequest` à partir de la requête originale.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | Détails techniques\n\nUn `Request` possède un attribut `request.scope`, qui n'est qu'un `dict` Python contenant les métadonnées liées à la requête.\n\nUn `Request` a également un `request.receive`, qui est une fonction pour « recevoir » le corps de la requête.\n\nLe `dict` `scope` et la fonction `receive` font tous deux partie de la spécification ASGI.\n\nEt ces deux éléments, `scope` et `receive`, sont ce dont on a besoin pour créer une nouvelle instance de `Request`.\n\nPour en savoir plus sur `Request`, consultez [la documentation de Starlette sur les requêtes](https://www.starlette.dev/requests/).\n\n///\n\nLa seule chose que fait différemment la fonction renvoyée par `GzipRequest.get_route_handler`, c'est de convertir la `Request` en `GzipRequest`.\n\nCe faisant, notre `GzipRequest` se chargera de décompresser les données (si nécessaire) avant de les transmettre à nos *chemins d'accès*.\n\nAprès cela, toute la logique de traitement est identique.\n\nMais grâce à nos modifications dans `GzipRequest.body`, le corps de la requête sera automatiquement décompressé lorsque **FastAPI** le chargera, si nécessaire.\n\n## Accéder au corps de la requête dans un gestionnaire d'exceptions { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip | Astuce\n\nPour résoudre ce même problème, il est probablement beaucoup plus simple d'utiliser `body` dans un gestionnaire personnalisé pour `RequestValidationError` ([Gérer les erreurs](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)).\n\nMais cet exemple reste valable et montre comment interagir avec les composants internes.\n\n///\n\nNous pouvons également utiliser cette même approche pour accéder au corps de la requête dans un gestionnaire d'exceptions.\n\nIl suffit de traiter la requête dans un bloc `try`/`except` :\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\nSi une exception se produit, l'instance de `Request` sera toujours dans la portée, ce qui nous permet de lire et d'utiliser le corps de la requête lors du traitement de l'erreur :\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## Utiliser une classe `APIRoute` personnalisée dans un routeur { #custom-apiroute-class-in-a-router }\n\nVous pouvez également définir le paramètre `route_class` d'un `APIRouter` :\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\nDans cet exemple, les *chemins d'accès* sous le `router` utiliseront la classe personnalisée `TimedRoute`, et auront un en-tête supplémentaire `X-Response-Time` dans la réponse avec le temps nécessaire pour générer la réponse :\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/fr/docs/how-to/extending-openapi.md",
    "content": "# Étendre OpenAPI { #extending-openapi }\n\nIl existe des cas où vous pouvez avoir besoin de modifier le schéma OpenAPI généré.\n\nDans cette section, vous verrez comment faire.\n\n## Le processus normal { #the-normal-process }\n\nLe processus normal (par défaut) est le suivant.\n\nUne application (instance) `FastAPI` a une méthode `.openapi()` censée retourner le schéma OpenAPI.\n\nLors de la création de l'objet application, un *chemin d'accès* pour `/openapi.json` (ou pour l'URL que vous avez définie dans votre `openapi_url`) est enregistré.\n\nIl renvoie simplement une réponse JSON avec le résultat de la méthode `.openapi()` de l'application.\n\nPar défaut, la méthode `.openapi()` vérifie la propriété `.openapi_schema` pour voir si elle contient des données et les renvoie.\n\nSinon, elle les génère à l'aide de la fonction utilitaire `fastapi.openapi.utils.get_openapi`.\n\nEt cette fonction `get_openapi()` reçoit comme paramètres :\n\n* `title` : Le titre OpenAPI, affiché dans les documents.\n* `version` : La version de votre API, p. ex. `2.5.0`.\n* `openapi_version` : La version de la spécification OpenAPI utilisée. Par défaut, la plus récente : `3.1.0`.\n* `summary` : Un court résumé de l'API.\n* `description` : La description de votre API ; elle peut inclure du markdown et sera affichée dans la documentation.\n* `routes` : Une liste de routes ; chacune correspond à un *chemin d'accès* enregistré. Elles sont extraites de `app.routes`.\n\n/// info\n\nLe paramètre `summary` est disponible à partir d'OpenAPI 3.1.0, pris en charge par FastAPI 0.99.0 et versions ultérieures.\n\n///\n\n## Remplacer les valeurs par défaut { #overriding-the-defaults }\n\nEn vous appuyant sur les informations ci-dessus, vous pouvez utiliser la même fonction utilitaire pour générer le schéma OpenAPI et remplacer chaque partie dont vous avez besoin.\n\nPar exemple, ajoutons [l’extension OpenAPI de ReDoc pour inclure un logo personnalisé](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo).\n\n### **FastAPI** normal { #normal-fastapi }\n\nTout d’abord, écrivez votre application **FastAPI** comme d’habitude :\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### Générer le schéma OpenAPI { #generate-the-openapi-schema }\n\nEnsuite, utilisez la même fonction utilitaire pour générer le schéma OpenAPI, dans une fonction `custom_openapi()` :\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### Modifier le schéma OpenAPI { #modify-the-openapi-schema }\n\nVous pouvez maintenant ajouter l’extension ReDoc, en ajoutant un `x-logo` personnalisé à l’« objet » `info` dans le schéma OpenAPI :\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### Mettre en cache le schéma OpenAPI { #cache-the-openapi-schema }\n\nVous pouvez utiliser la propriété `.openapi_schema` comme « cache » pour stocker votre schéma généré.\n\nAinsi, votre application n’aura pas à générer le schéma à chaque fois qu’un utilisateur ouvre les documents de votre API.\n\nIl ne sera généré qu’une seule fois, puis le même schéma en cache sera utilisé pour les requêtes suivantes.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### Remplacer la méthode { #override-the-method }\n\nVous pouvez maintenant remplacer la méthode `.openapi()` par votre nouvelle fonction.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### Vérifier { #check-it }\n\nUne fois que vous allez sur [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc), vous verrez que vous utilisez votre logo personnalisé (dans cet exemple, le logo de **FastAPI**) :\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/fr/docs/how-to/general.md",
    "content": "# Général - Guides pratiques - Recettes { #general-how-to-recipes }\n\nVoici plusieurs renvois vers d'autres endroits dans les documents, pour des questions générales ou fréquentes.\n\n## Filtrer des données - Sécurité { #filter-data-security }\n\nPour vous assurer que vous ne renvoyez pas plus de données que nécessaire, lisez les documents [Tutoriel - Modèle de réponse - Type de retour](../tutorial/response-model.md).\n\n## Optimiser la performance des réponses - Modèle de réponse - Type de retour { #optimize-response-performance-response-model-return-type }\n\nPour optimiser la performance lors du renvoi de données JSON, utilisez un type de retour ou un modèle de réponse ; de cette façon, Pydantic prendra en charge la sérialisation en JSON côté Rust, sans passer par Python. Pour en savoir plus, lisez les documents [Tutoriel - Modèle de réponse - Type de retour](../tutorial/response-model.md).\n\n## Étiquettes de documentation - OpenAPI { #documentation-tags-openapi }\n\nPour ajouter des étiquettes à vos *chemins d'accès* et les regrouper dans l'interface utilisateur de la documentation, lisez les documents [Tutoriel - Configurations de chemin d'accès - Tags](../tutorial/path-operation-configuration.md#tags).\n\n## Résumé et description de la documentation - OpenAPI { #documentation-summary-and-description-openapi }\n\nPour ajouter un résumé et une description à vos *chemins d'accès* et les afficher dans l'interface utilisateur de la documentation, lisez les documents [Tutoriel - Configurations de chemin d'accès - Résumé et description](../tutorial/path-operation-configuration.md#summary-and-description).\n\n## Description de la réponse dans la documentation - OpenAPI { #documentation-response-description-openapi }\n\nPour définir la description de la réponse, affichée dans l'interface utilisateur de la documentation, lisez les documents [Tutoriel - Configurations de chemin d'accès - Description de la réponse](../tutorial/path-operation-configuration.md#response-description).\n\n## Déprécier un *chemin d'accès* dans la documentation - OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\nPour déprécier un *chemin d'accès* et l'indiquer dans l'interface utilisateur de la documentation, lisez les documents [Tutoriel - Configurations de chemin d'accès - Dépréciation](../tutorial/path-operation-configuration.md#deprecate-a-path-operation).\n\n## Convertir n'importe quelles données au format compatible JSON { #convert-any-data-to-json-compatible }\n\nPour convertir des données vers un format compatible JSON, lisez les documents [Tutoriel - Encodeur compatible JSON](../tutorial/encoder.md).\n\n## Métadonnées OpenAPI - Documentation { #openapi-metadata-docs }\n\nPour ajouter des métadonnées à votre schéma OpenAPI, y compris une licence, une version, un contact, etc., lisez les documents [Tutoriel - Métadonnées et URLs de la documentation](../tutorial/metadata.md).\n\n## URL OpenAPI personnalisée { #openapi-custom-url }\n\nPour personnaliser l'URL OpenAPI (ou la supprimer), lisez les documents [Tutoriel - Métadonnées et URLs de la documentation](../tutorial/metadata.md#openapi-url).\n\n## URL de la documentation OpenAPI { #openapi-docs-urls }\n\nPour mettre à jour les URL utilisées pour les interfaces utilisateur de documentation générées automatiquement, lisez les documents [Tutoriel - Métadonnées et URLs de la documentation](../tutorial/metadata.md#docs-urls).\n"
  },
  {
    "path": "docs/fr/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\nComme **FastAPI** est basé sur la norme **ASGI**, il est très facile d'intégrer toute bibliothèque **GraphQL** également compatible avec ASGI.\n\nVous pouvez combiner des *chemins d'accès* FastAPI classiques avec GraphQL dans la même application.\n\n/// tip | Astuce\n\n**GraphQL** résout des cas d'utilisation très spécifiques.\n\nIl présente des **avantages** et des **inconvénients** par rapport aux **API web** classiques.\n\nAssurez-vous d'évaluer si les **bénéfices** pour votre cas d'utilisation compensent les **inconvénients**. 🤓\n\n///\n\n## Bibliothèques GraphQL { #graphql-libraries }\n\nVoici quelques bibliothèques **GraphQL** qui prennent en charge **ASGI**. Vous pouvez les utiliser avec **FastAPI** :\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * Avec [la documentation pour FastAPI](https://strawberry.rocks/docs/integrations/fastapi)\n* [Ariadne](https://ariadnegraphql.org/)\n    * Avec [la documentation pour FastAPI](https://ariadnegraphql.org/docs/fastapi-integration)\n* [Tartiflette](https://tartiflette.io/)\n    * Avec [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) pour fournir l'intégration ASGI\n* [Graphene](https://graphene-python.org/)\n    * Avec [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)\n\n## GraphQL avec Strawberry { #graphql-with-strawberry }\n\nSi vous avez besoin ou souhaitez travailler avec **GraphQL**, [**Strawberry**](https://strawberry.rocks/) est la bibliothèque **recommandée** car sa conception est la plus proche de celle de **FastAPI**, tout est basé sur des **annotations de type**.\n\nSelon votre cas d'utilisation, vous pourriez préférer une autre bibliothèque, mais si vous me le demandiez, je vous suggérerais probablement d'essayer **Strawberry**.\n\nVoici un petit aperçu de la manière dont vous pouvez intégrer Strawberry avec FastAPI :\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\nVous pouvez en apprendre davantage sur Strawberry dans la [documentation de Strawberry](https://strawberry.rocks/).\n\nEt également la documentation sur [Strawberry avec FastAPI](https://strawberry.rocks/docs/integrations/fastapi).\n\n## Ancien `GraphQLApp` de Starlette { #older-graphqlapp-from-starlette }\n\nLes versions précédentes de Starlette incluaient une classe `GraphQLApp` pour s'intégrer à [Graphene](https://graphene-python.org/).\n\nElle a été dépréciée dans Starlette, mais si vous avez du code qui l'utilisait, vous pouvez facilement **migrer** vers [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3), qui couvre le même cas d'utilisation et propose une **interface presque identique**.\n\n/// tip | Astuce\n\nSi vous avez besoin de GraphQL, je vous recommande tout de même de regarder [Strawberry](https://strawberry.rocks/), car il est basé sur des annotations de type plutôt que sur des classes et types personnalisés.\n\n///\n\n## En savoir plus { #learn-more }\n\nVous pouvez en apprendre davantage sur **GraphQL** dans la [documentation officielle de GraphQL](https://graphql.org/).\n\nVous pouvez également en lire davantage sur chacune des bibliothèques décrites ci-dessus via leurs liens.\n"
  },
  {
    "path": "docs/fr/docs/how-to/index.md",
    "content": "# Comment faire - Recettes { #how-to-recipes }\n\nVous trouverez ici différentes recettes ou des guides « comment faire » pour **plusieurs sujets**.\n\nLa plupart de ces idées sont plus ou moins **indépendantes**, et dans la plupart des cas vous n'avez besoin de les étudier que si elles s'appliquent directement à **votre projet**.\n\nSi quelque chose vous paraît intéressant et utile pour votre projet, allez-y et consultez-le ; sinon, vous pouvez probablement simplement les ignorer.\n\n/// tip | Astuce\n\nSi vous voulez **apprendre FastAPI** de façon structurée (recommandé), allez lire le [Tutoriel - Guide utilisateur](../tutorial/index.md) chapitre par chapitre à la place.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# Migrer de Pydantic v1 à Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\nSi vous avez une ancienne application FastAPI, vous utilisez peut-être Pydantic version 1.\n\nFastAPI version 0.100.0 prenait en charge soit Pydantic v1 soit v2. Il utilisait celle que vous aviez installée.\n\nFastAPI version 0.119.0 a introduit une prise en charge partielle de Pydantic v1 depuis l'intérieur de Pydantic v2 (comme `pydantic.v1`), pour faciliter la migration vers v2.\n\nFastAPI 0.126.0 a supprimé la prise en charge de Pydantic v1, tout en continuant à prendre en charge `pydantic.v1` pendant un certain temps.\n\n/// warning | Alertes\n\nL'équipe Pydantic a arrêté la prise en charge de Pydantic v1 pour les dernières versions de Python, à partir de **Python 3.14**.\n\nCela inclut `pydantic.v1`, qui n'est plus pris en charge en Python 3.14 et versions ultérieures.\n\nSi vous souhaitez utiliser les dernières fonctionnalités de Python, vous devez vous assurer que vous utilisez Pydantic v2.\n\n///\n\nSi vous avez une ancienne application FastAPI avec Pydantic v1, je vais vous montrer comment la migrer vers Pydantic v2, et les **fonctionnalités de FastAPI 0.119.0** pour vous aider à une migration progressive.\n\n## Guide officiel { #official-guide }\n\nPydantic propose un [Guide de migration](https://docs.pydantic.dev/latest/migration/) officiel de la v1 à la v2.\n\nIl inclut aussi ce qui a changé, comment les validations sont désormais plus correctes et strictes, les pièges possibles, etc.\n\nVous pouvez le lire pour mieux comprendre ce qui a changé.\n\n## Tests { #tests }\n\nVous devez vous assurer d'avoir des [tests](../tutorial/testing.md) pour votre application et de les exécuter en intégration continue (CI).\n\nDe cette façon, vous pouvez effectuer la mise à niveau et vous assurer que tout fonctionne toujours comme prévu.\n\n## `bump-pydantic` { #bump-pydantic }\n\nDans de nombreux cas, lorsque vous utilisez des modèles Pydantic classiques sans personnalisations, vous pourrez automatiser la majeure partie du processus de migration de Pydantic v1 à Pydantic v2.\n\nVous pouvez utiliser [`bump-pydantic`](https://github.com/pydantic/bump-pydantic) de la même équipe Pydantic.\n\nCet outil vous aidera à modifier automatiquement la majeure partie du code à adapter.\n\nAprès cela, vous pouvez exécuter les tests et vérifier que tout fonctionne. Si c'est le cas, vous avez terminé. 😎\n\n## Pydantic v1 dans v2 { #pydantic-v1-in-v2 }\n\nPydantic v2 inclut tout Pydantic v1 sous la forme du sous-module `pydantic.v1`. Mais cela n'est plus pris en charge dans les versions au-delà de Python 3.13.\n\nCela signifie que vous pouvez installer la dernière version de Pydantic v2 et importer/utiliser les anciens composants de Pydantic v1 depuis ce sous-module, comme si vous aviez l'ancien Pydantic v1 installé.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### Prise en charge de FastAPI pour Pydantic v1 dans v2 { #fastapi-support-for-pydantic-v1-in-v2 }\n\nDepuis FastAPI 0.119.0, il existe également une prise en charge partielle de Pydantic v1 depuis l'intérieur de Pydantic v2, pour faciliter la migration vers v2.\n\nVous pouvez donc mettre à niveau Pydantic vers la dernière version 2 et modifier les imports pour utiliser le sous-module `pydantic.v1`, et dans de nombreux cas cela fonctionnera tel quel.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning | Alertes\n\nGardez à l'esprit que, puisque l'équipe Pydantic ne prend plus en charge Pydantic v1 dans les versions récentes de Python à partir de Python 3.14, l'utilisation de `pydantic.v1` n'est pas non plus prise en charge en Python 3.14 et versions ultérieures.\n\n///\n\n### Pydantic v1 et v2 dans la même application { #pydantic-v1-and-v2-on-the-same-app }\n\nPydantic ne prend pas en charge le fait d'avoir un modèle Pydantic v2 contenant des champs eux-mêmes définis comme des modèles Pydantic v1, et inversement.\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n... mais vous pouvez avoir des modèles séparés utilisant Pydantic v1 et v2 dans la même application.\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\nDans certains cas, il est même possible d'avoir des modèles Pydantic v1 et v2 dans le même **chemin d'accès** de votre application FastAPI :\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\nDans l'exemple ci-dessus, le modèle d'entrée est un modèle Pydantic v1 et le modèle de sortie (défini dans `response_model=ItemV2`) est un modèle Pydantic v2.\n\n### Paramètres Pydantic v1 { #pydantic-v1-parameters }\n\nSi vous devez utiliser certains des outils spécifiques à FastAPI pour les paramètres comme `Body`, `Query`, `Form`, etc., avec des modèles Pydantic v1, vous pouvez les importer depuis `fastapi.temp_pydantic_v1_params` le temps de terminer la migration vers Pydantic v2 :\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### Migrer par étapes { #migrate-in-steps }\n\n/// tip | Astuce\n\nEssayez d'abord avec `bump-pydantic` ; si vos tests passent et que cela fonctionne, vous avez tout terminé en une seule commande. ✨\n\n///\n\nSi `bump-pydantic` ne fonctionne pas pour votre cas d'usage, vous pouvez utiliser la prise en charge des modèles Pydantic v1 et v2 dans la même application pour effectuer la migration vers Pydantic v2 progressivement.\n\nVous pouvez d'abord mettre à niveau Pydantic pour utiliser la dernière version 2 et modifier les imports pour utiliser `pydantic.v1` pour tous vos modèles.\n\nEnsuite, vous pouvez commencer à migrer vos modèles de Pydantic v1 vers v2 par groupes, par étapes progressives. 🚶\n"
  },
  {
    "path": "docs/fr/docs/how-to/separate-openapi-schemas.md",
    "content": "# Séparer les schémas OpenAPI pour l'entrée et la sortie ou non { #separate-openapi-schemas-for-input-and-output-or-not }\n\nDepuis la sortie de **Pydantic v2**, l'OpenAPI généré est un peu plus précis et **correct** qu'avant. 😎\n\nEn fait, dans certains cas, il y aura même **deux schémas JSON** dans OpenAPI pour le même modèle Pydantic, pour l'entrée et pour la sortie, selon s'ils ont des **valeurs par défaut**.\n\nVoyons comment cela fonctionne et comment le modifier si vous devez le faire.\n\n## Utiliser des modèles Pydantic pour l'entrée et la sortie { #pydantic-models-for-input-and-output }\n\nSupposons que vous ayez un modèle Pydantic avec des valeurs par défaut, comme celui‑ci :\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### Modèle pour l'entrée { #model-for-input }\n\nSi vous utilisez ce modèle en entrée comme ici :\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n... alors, le champ `description` ne sera **pas requis**. Parce qu'il a une valeur par défaut de `None`.\n\n### Modèle d'entrée dans les documents { #input-model-in-docs }\n\nVous pouvez le confirmer dans les documents, le champ `description` n'a pas d'**astérisque rouge**, il n'est pas indiqué comme requis :\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### Modèle pour la sortie { #model-for-output }\n\nMais si vous utilisez le même modèle en sortie, comme ici :\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n... alors, comme `description` a une valeur par défaut, si vous ne retournez rien pour ce champ, il aura tout de même cette **valeur par défaut**.\n\n### Modèle pour les données de réponse en sortie { #model-for-output-response-data }\n\nSi vous interagissez avec les documents et vérifiez la réponse, même si le code n'a rien ajouté dans l'un des champs `description`, la réponse JSON contient la valeur par défaut (`null`) :\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\nCela signifie qu'il aura **toujours une valeur**, simplement, parfois la valeur pourra être `None` (ou `null` en JSON).\n\nCela signifie que les clients utilisant votre API n'ont pas à vérifier si la valeur existe ou non, ils peuvent **supposer que le champ sera toujours présent**, mais que, dans certains cas, il aura la valeur par défaut `None`.\n\nLa manière de décrire cela dans OpenAPI est de marquer ce champ comme **requis**, car il sera toujours présent.\n\nPour cette raison, le schéma JSON d'un modèle peut être différent selon qu'il est utilisé pour **l'entrée ou la sortie** :\n\n- pour **l'entrée**, `description` ne sera **pas requis**\n- pour **la sortie**, il sera **requis** (et éventuellement `None`, ou en termes JSON, `null`)\n\n### Modèle de sortie dans les documents { #model-for-output-in-docs }\n\nVous pouvez également vérifier le modèle de sortie dans les documents, **à la fois** `name` et `description` sont marqués comme **requis** avec un **astérisque rouge** :\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### Modèle pour l'entrée et la sortie dans les documents { #model-for-input-and-output-in-docs }\n\nEt si vous consultez tous les schémas disponibles (schémas JSON) dans OpenAPI, vous verrez qu'il y en a deux, un `Item-Input` et un `Item-Output`.\n\nPour `Item-Input`, `description` n'est **pas requis**, il n'a pas d'astérisque rouge.\n\nMais pour `Item-Output`, `description` est **requis**, il a un astérisque rouge.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\nAvec cette fonctionnalité de **Pydantic v2**, la documentation de votre API est plus **précise**, et si vous avez des clients et SDKs générés automatiquement, ils seront eux aussi plus précis, avec une meilleure **expérience développeur** et davantage de cohérence. 🎉\n\n## Ne pas séparer les schémas { #do-not-separate-schemas }\n\nIl existe des cas où vous pourriez vouloir avoir le **même schéma pour l'entrée et la sortie**.\n\nLe cas d'usage principal est probablement que vous avez déjà du code client/SDKs générés automatiquement et que vous ne souhaitez pas encore mettre à jour tout ce code client/ces SDKs générés automatiquement ; vous le ferez sans doute à un moment donné, mais peut‑être pas tout de suite.\n\nDans ce cas, vous pouvez désactiver cette fonctionnalité dans **FastAPI**, avec le paramètre `separate_input_output_schemas=False`.\n\n/// info | info\n\nLa prise en charge de `separate_input_output_schemas` a été ajoutée dans FastAPI `0.102.0`. 🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### Utiliser le même schéma pour les modèles d'entrée et de sortie dans les documents { #same-schema-for-input-and-output-models-in-docs }\n\nDésormais, il n'y aura qu'un seul schéma pour l'entrée et la sortie du modèle, uniquement `Item`, et `description` ne sera pas requis :\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/fr/docs/how-to/testing-database.md",
    "content": "# Tester une base de données { #testing-a-database }\n\nVous pouvez étudier les bases de données, SQL et SQLModel dans les [documents SQLModel](https://sqlmodel.tiangolo.com/). 🤓\n\nIl existe un mini [tutoriel sur l'utilisation de SQLModel avec FastAPI](https://sqlmodel.tiangolo.com/tutorial/fastapi/). ✨\n\nCe tutoriel comprend une section sur les [tests des bases de données SQL](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/). 😎\n"
  },
  {
    "path": "docs/fr/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/fr\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>Framework FastAPI, haute performance, facile à apprendre, rapide à coder, prêt pour la production</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**Documentation** : [https://fastapi.tiangolo.com/fr](https://fastapi.tiangolo.com/fr)\n\n**Code Source** : [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI est un framework web moderne et rapide (haute performance) pour la création d'API avec Python, basé sur les annotations de type standard de Python.\n\nLes principales fonctionnalités sont :\n\n* **Rapide** : très hautes performances, au niveau de **NodeJS** et **Go** (grâce à Starlette et Pydantic). [L'un des frameworks Python les plus rapides](#performance).\n* **Rapide à coder** : augmente la vitesse de développement des fonctionnalités d'environ 200 % à 300 %. *\n* **Moins de bugs** : réduit d'environ 40 % les erreurs induites par le développeur. *\n* **Intuitif** : excellente compatibilité avec les éditeurs. <dfn title=\"également connu sous le nom de : auto-complétion, autocomplétion, IntelliSense\">Autocomplétion</dfn> partout. Moins de temps passé à déboguer.\n* **Facile** : conçu pour être facile à utiliser et à apprendre. Moins de temps passé à lire les documents.\n* **Concis** : diminue la duplication de code. Plusieurs fonctionnalités à partir de chaque déclaration de paramètre. Moins de bugs.\n* **Robuste** : obtenez un code prêt pour la production. Avec une documentation interactive automatique.\n* **Basé sur des normes** : basé sur (et entièrement compatible avec) les standards ouverts pour les APIs : [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (précédemment connu sous le nom de Swagger) et [JSON Schema](https://json-schema.org/).\n\n<small>* estimation basée sur des tests d'une équipe de développement interne, construisant des applications de production.</small>\n\n## Sponsors { #sponsors }\n\n<!-- sponsors -->\n\n### Sponsor clé de voûte { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### Sponsors Or et Argent { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[Autres sponsors](https://fastapi.tiangolo.com/fr/fastapi-people/#sponsors)\n\n## Opinions { #opinions }\n\n« _[...] J'utilise beaucoup **FastAPI** ces derniers temps. [...] Je prévois de l'utiliser dans mon équipe pour tous les **services de ML chez Microsoft**. Certains d'entre eux sont intégrés au cœur de **Windows** et à certains produits **Office**._ »\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n« _Nous avons adopté la bibliothèque **FastAPI** pour créer un serveur **REST** qui peut être interrogé pour obtenir des **prédictions**. [pour Ludwig]_ »\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, et Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n« _**Netflix** est heureux d'annoncer la publication en open source de notre framework d'orchestration de **gestion de crise** : **Dispatch** ! [construit avec **FastAPI**]_ »\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n« _Je suis plus qu'enthousiaste à propos de **FastAPI**. C'est tellement fun !_ »\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken - <strong>Animateur du podcast [Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855)</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(ref)</small></a></div>\n\n---\n\n« _Honnêtement, ce que vous avez construit a l'air super solide et soigné. À bien des égards, c'est ce que je voulais que **Hug** soit — c'est vraiment inspirant de voir quelqu'un construire ça._ »\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley - <strong>Créateur de [Hug](https://github.com/hugapi/hug)</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(ref)</small></a></div>\n\n---\n\n« _Si vous cherchez à apprendre un **framework moderne** pour créer des APIs REST, regardez **FastAPI** [...] C'est rapide, facile à utiliser et facile à apprendre [...]_ »\n\n« _Nous sommes passés à **FastAPI** pour nos **APIs** [...] Je pense que vous l'aimerez [...]_ »\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani - Matthew Honnibal - <strong>Fondateurs de [Explosion AI](https://explosion.ai) - Créateurs de [spaCy](https://spacy.io)</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(ref)</small></a> - <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(ref)</small></a></div>\n\n---\n\n« _Si quelqu'un cherche à construire une API Python de production, je recommande vivement **FastAPI**. Il est **magnifiquement conçu**, **simple à utiliser** et **hautement scalable**. Il est devenu un **composant clé** de notre stratégie de développement API-first et alimente de nombreuses automatisations et services tels que notre ingénieur TAC virtuel._ »\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n## Mini documentaire FastAPI { #fastapi-mini-documentary }\n\nUn [mini documentaire FastAPI](https://www.youtube.com/watch?v=mpR8ngthqiE) est sorti fin 2025, vous pouvez le regarder en ligne :\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**, le FastAPI des CLIs { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\nSi vous construisez une application <abbr title=\"Command Line Interface - Interface en ligne de commande\">CLI</abbr> à utiliser dans un terminal au lieu d'une API web, regardez [**Typer**](https://typer.tiangolo.com/).\n\n**Typer** est le petit frère de FastAPI. Et il est destiné à être le **FastAPI des CLIs**. ⌨️ 🚀\n\n## Prérequis { #requirements }\n\nFastAPI repose sur les épaules de géants :\n\n* [Starlette](https://www.starlette.dev/) pour les parties web.\n* [Pydantic](https://docs.pydantic.dev/) pour les parties données.\n\n## Installation { #installation }\n\nCréez et activez un [environnement virtuel](https://fastapi.tiangolo.com/fr/virtual-environments/) puis installez FastAPI :\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Remarque** : Vous devez vous assurer de mettre « fastapi[standard] » entre guillemets pour garantir que cela fonctionne dans tous les terminaux.\n\n## Exemple { #example }\n\n### Créer { #create-it }\n\nCréez un fichier `main.py` avec :\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>Ou utilisez <code>async def</code>...</summary>\n\nSi votre code utilise `async` / `await`, utilisez `async def` :\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Remarque** :\n\nSi vous ne savez pas, consultez la section « Vous êtes pressés ? » à propos de [`async` et `await` dans la documentation](https://fastapi.tiangolo.com/fr/async/#in-a-hurry).\n\n</details>\n\n### Lancer { #run-it }\n\nLancez le serveur avec :\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary>À propos de la commande <code>fastapi dev</code>...</summary>\n\nLa commande `fastapi dev` lit automatiquement votre fichier `main.py`, détecte l'application **FastAPI** qu'il contient et lance un serveur avec [Uvicorn](https://www.uvicorn.dev).\n\nPar défaut, `fastapi dev` démarre avec le rechargement automatique activé pour le développement local.\n\nVous pouvez en savoir plus dans la [documentation de la CLI FastAPI](https://fastapi.tiangolo.com/fr/fastapi-cli/).\n\n</details>\n\n### Vérifier { #check-it }\n\nOuvrez votre navigateur à l'adresse [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery).\n\nVous verrez la réponse JSON :\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\nVous avez déjà créé une API qui :\n\n* Reçoit des requêtes HTTP sur les _chemins_ `/` et `/items/{item_id}`.\n* Les deux _chemins_ acceptent des <em>opérations</em> `GET` (également connues sous le nom de _méthodes_ HTTP).\n* Le _chemin_ `/items/{item_id}` a un _paramètre de chemin_ `item_id` qui doit être un `int`.\n* Le _chemin_ `/items/{item_id}` a un _paramètre de requête_ optionnel `q` de type `str`.\n\n### Documentation API interactive { #interactive-api-docs }\n\nMaintenant, rendez-vous sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVous verrez la documentation interactive automatique de l'API (fournie par [Swagger UI](https://github.com/swagger-api/swagger-ui)) :\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Documentation API alternative { #alternative-api-docs }\n\nEt maintenant, rendez-vous sur [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nVous verrez la documentation alternative automatique (fournie par [ReDoc](https://github.com/Rebilly/ReDoc)) :\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Mettre à niveau l'exemple { #example-upgrade }\n\nModifiez maintenant le fichier `main.py` pour recevoir un corps depuis une requête `PUT`.\n\nDéclarez le corps en utilisant les types Python standard, grâce à Pydantic.\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\nLe serveur `fastapi dev` devrait se recharger automatiquement.\n\n### Mettre à niveau la documentation API interactive { #interactive-api-docs-upgrade }\n\nMaintenant, rendez-vous sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n* La documentation interactive de l'API sera automatiquement mise à jour, y compris le nouveau corps :\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Cliquez sur le bouton « Try it out », il vous permet de renseigner les paramètres et d'interagir directement avec l'API :\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* Cliquez ensuite sur le bouton « Execute », l'interface utilisateur communiquera avec votre API, enverra les paramètres, obtiendra les résultats et les affichera à l'écran :\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### Mettre à niveau la documentation API alternative { #alternative-api-docs-upgrade }\n\nEt maintenant, rendez-vous sur [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\n* La documentation alternative reflètera également le nouveau paramètre de requête et le nouveau corps :\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### En résumé { #recap }\n\nEn résumé, vous déclarez **une fois** les types de paramètres, le corps, etc. en tant que paramètres de fonction.\n\nVous faites cela avec les types Python standard modernes.\n\nVous n'avez pas à apprendre une nouvelle syntaxe, les méthodes ou les classes d'une bibliothèque spécifique, etc.\n\nJuste du **Python** standard.\n\nPar exemple, pour un `int` :\n\n```Python\nitem_id: int\n```\n\nou pour un modèle `Item` plus complexe :\n\n```Python\nitem: Item\n```\n\n... et avec cette déclaration unique, vous obtenez :\n\n* Une assistance dans l'éditeur, notamment :\n    * l'autocomplétion.\n    * la vérification des types.\n* La validation des données :\n    * des erreurs automatiques et claires lorsque les données ne sont pas valides.\n    * une validation même pour les objets JSON profondément imbriqués.\n* <dfn title=\"également connu sous le nom de : sérialisation, parsing, marshalling\">Conversion</dfn> des données d'entrée : venant du réseau vers les données et types Python. Lecture depuis :\n    * JSON.\n    * Paramètres de chemin.\n    * Paramètres de requête.\n    * Cookies.\n    * En-têtes.\n    * Formulaires.\n    * Fichiers.\n* <dfn title=\"également connu sous le nom de : sérialisation, parsing, marshalling\">Conversion</dfn> des données de sortie : conversion des données et types Python en données réseau (au format JSON) :\n    * Conversion des types Python (`str`, `int`, `float`, `bool`, `list`, etc).\n    * Objets `datetime`.\n    * Objets `UUID`.\n    * Modèles de base de données.\n    * ... et bien plus.\n* Documentation API interactive automatique, avec 2 interfaces utilisateur au choix :\n    * Swagger UI.\n    * ReDoc.\n\n---\n\nPour revenir à l'exemple de code précédent, **FastAPI** va :\n\n* Valider la présence d'un `item_id` dans le chemin pour les requêtes `GET` et `PUT`.\n* Valider que `item_id` est de type `int` pour les requêtes `GET` et `PUT`.\n    * Si ce n'est pas le cas, le client verra une erreur utile et claire.\n* Vérifier s'il existe un paramètre de requête optionnel nommé `q` (comme dans `http://127.0.0.1:8000/items/foo?q=somequery`) pour les requêtes `GET`.\n    * Comme le paramètre `q` est déclaré avec `= None`, il est optionnel.\n    * Sans le `None`, il serait requis (comme l'est le corps dans le cas de `PUT`).\n* Pour les requêtes `PUT` vers `/items/{item_id}`, lire le corps au format JSON :\n    * Vérifier qu'il a un attribut obligatoire `name` qui doit être un `str`.\n    * Vérifier qu'il a un attribut obligatoire `price` qui doit être un `float`.\n    * Vérifier qu'il a un attribut optionnel `is_offer`, qui doit être un `bool`, s'il est présent.\n    * Tout cela fonctionne également pour les objets JSON profondément imbriqués.\n* Convertir automatiquement depuis et vers JSON.\n* Tout documenter avec OpenAPI, qui peut être utilisé par :\n    * des systèmes de documentation interactive.\n    * des systèmes de génération automatique de clients, pour de nombreux langages.\n* Fournir directement 2 interfaces web de documentation interactive.\n\n---\n\nNous n'avons fait qu'effleurer la surface, mais vous avez déjà une idée de la façon dont tout fonctionne.\n\nEssayez de changer la ligne contenant :\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n... de :\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n... à :\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n... et voyez comment votre éditeur complète automatiquement les attributs et connaît leurs types :\n\n![compatibilité éditeur](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\nPour un exemple plus complet comprenant plus de fonctionnalités, voir le <a href=\"https://fastapi.tiangolo.com/fr/tutorial/\">Tutoriel - Guide utilisateur</a>.\n\n**Alerte spoiler** : le tutoriel - guide utilisateur inclut :\n\n* Déclaration de **paramètres** provenant d'autres emplacements comme : **en-têtes**, **cookies**, **champs de formulaire** et **fichiers**.\n* Comment définir des **contraintes de validation** comme `maximum_length` ou `regex`.\n* Un système **<dfn title=\"également connu sous le nom de : composants, ressources, fournisseurs, services, injectables\">d'injection de dépendances</dfn>** très puissant et facile à utiliser.\n* Sécurité et authentification, y compris la prise en charge de **OAuth2** avec des **JWT tokens** et l'authentification **HTTP Basic**.\n* Des techniques plus avancées (mais tout aussi faciles) pour déclarer des **modèles JSON profondément imbriqués** (grâce à Pydantic).\n* Intégration **GraphQL** avec [Strawberry](https://strawberry.rocks) et d'autres bibliothèques.\n* De nombreuses fonctionnalités supplémentaires (grâce à Starlette) comme :\n    * **WebSockets**\n    * des tests extrêmement faciles basés sur HTTPX et `pytest`\n    * **CORS**\n    * **Cookie Sessions**\n    * ... et plus encore.\n\n### Déployer votre application (optionnel) { #deploy-your-app-optional }\n\nVous pouvez, si vous le souhaitez, déployer votre application FastAPI sur [FastAPI Cloud](https://fastapicloud.com), allez vous inscrire sur la liste d'attente si ce n'est pas déjà fait. 🚀\n\nSi vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d'attente 😉), vous pouvez déployer votre application avec une seule commande.\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nC'est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨\n\n#### À propos de FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** est construit par le même auteur et la même équipe derrière **FastAPI**.\n\nIl simplifie le processus de **construction**, de **déploiement** et **d'accès** à une API avec un effort minimal.\n\nIl apporte la même **expérience développeur** de la création d'applications avec FastAPI au **déploiement** dans le cloud. 🎉\n\nFastAPI Cloud est le principal sponsor et financeur des projets open source *FastAPI and friends*. ✨\n\n#### Déployer sur d'autres fournisseurs cloud { #deploy-to-other-cloud-providers }\n\nFastAPI est open source et basé sur des standards. Vous pouvez déployer des applications FastAPI sur n'importe quel fournisseur cloud de votre choix.\n\nSuivez les guides de votre fournisseur cloud pour y déployer des applications FastAPI. 🤓\n\n## Performance { #performance }\n\nLes benchmarks TechEmpower indépendants montrent que les applications **FastAPI** s'exécutant sous Uvicorn sont [parmi les frameworks Python les plus rapides](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), juste derrière Starlette et Uvicorn eux-mêmes (utilisés en interne par FastAPI). (*)\n\nPour en savoir plus, consultez la section [Benchmarks](https://fastapi.tiangolo.com/fr/benchmarks/).\n\n## Dépendances { #dependencies }\n\nFastAPI dépend de Pydantic et Starlette.\n\n### Dépendances `standard` { #standard-dependencies }\n\nLorsque vous installez FastAPI avec `pip install \"fastapi[standard]\"`, il inclut le groupe `standard` de dépendances optionnelles :\n\nUtilisées par Pydantic :\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - pour la validation des adresses e-mail.\n\nUtilisées par Starlette :\n\n* [`httpx`](https://www.python-httpx.org) - Obligatoire si vous souhaitez utiliser le `TestClient`.\n* [`jinja2`](https://jinja.palletsprojects.com) - Obligatoire si vous souhaitez utiliser la configuration de template par défaut.\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - Obligatoire si vous souhaitez prendre en charge l’<dfn title=\"convertir la chaîne issue d'une requête HTTP en données Python\">« parsing »</dfn> de formulaires avec `request.form()`.\n\nUtilisées par FastAPI :\n\n* [`uvicorn`](https://www.uvicorn.dev) - pour le serveur qui charge et sert votre application. Cela inclut `uvicorn[standard]`, qui comprend certaines dépendances (par ex. `uvloop`) nécessaires pour une haute performance.\n* `fastapi-cli[standard]` - pour fournir la commande `fastapi`.\n    * Cela inclut `fastapi-cloud-cli`, qui vous permet de déployer votre application FastAPI sur [FastAPI Cloud](https://fastapicloud.com).\n\n### Sans les dépendances `standard` { #without-standard-dependencies }\n\nSi vous ne souhaitez pas inclure les dépendances optionnelles `standard`, vous pouvez installer avec `pip install fastapi` au lieu de `pip install \"fastapi[standard]\"`.\n\n### Sans `fastapi-cloud-cli` { #without-fastapi-cloud-cli }\n\nSi vous souhaitez installer FastAPI avec les dépendances standard mais sans `fastapi-cloud-cli`, vous pouvez installer avec `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n### Dépendances optionnelles supplémentaires { #additional-optional-dependencies }\n\nIl existe des dépendances supplémentaires que vous pourriez vouloir installer.\n\nDépendances optionnelles supplémentaires pour Pydantic :\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - pour la gestion des paramètres.\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - pour des types supplémentaires à utiliser avec Pydantic.\n\nDépendances optionnelles supplémentaires pour FastAPI :\n\n* [`orjson`](https://github.com/ijl/orjson) - Obligatoire si vous souhaitez utiliser `ORJSONResponse`.\n* [`ujson`](https://github.com/esnme/ultrajson) - Obligatoire si vous souhaitez utiliser `UJSONResponse`.\n\n## Licence { #license }\n\nCe projet est soumis aux termes de la licence MIT.\n"
  },
  {
    "path": "docs/fr/docs/learn/index.md",
    "content": "# Apprendre { #learn }\n\nVoici les sections introductives et les tutoriels pour apprendre **FastAPI**.\n\nVous pouvez considérer ceci comme un **livre**, un **cours**, la méthode **officielle** et recommandée pour apprendre FastAPI. 😎\n"
  },
  {
    "path": "docs/fr/docs/project-generation.md",
    "content": "# Modèle Full Stack FastAPI { #full-stack-fastapi-template }\n\nLes modèles, bien qu'ils soient généralement livrés avec une configuration spécifique, sont conçus pour être flexibles et personnalisables. Cela vous permet de les modifier et de les adapter aux exigences de votre projet, ce qui en fait un excellent point de départ. 🏁\n\nVous pouvez utiliser ce modèle pour démarrer, car il inclut une grande partie de la configuration initiale, la sécurité, la base de données et quelques endpoints d'API déjà prêts pour vous.\n\nDépôt GitHub : [Modèle Full Stack FastAPI](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## Modèle Full Stack FastAPI - Pile technologique et fonctionnalités { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/fr) pour l'API backend Python.\n  - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) pour les interactions avec la base de données SQL en Python (ORM).\n  - 🔍 [Pydantic](https://docs.pydantic.dev), utilisé par FastAPI, pour la validation des données et la gestion des paramètres.\n  - 💾 [PostgreSQL](https://www.postgresql.org) comme base de données SQL.\n- 🚀 [React](https://react.dev) pour le frontend.\n  - 💃 Utilisation de TypeScript, des hooks, de Vite et d'autres éléments d'un stack frontend moderne.\n  - 🎨 [Tailwind CSS](https://tailwindcss.com) et [shadcn/ui](https://ui.shadcn.com) pour les composants frontend.\n  - 🤖 Un client frontend généré automatiquement.\n  - 🧪 [Playwright](https://playwright.dev) pour les tests de bout en bout.\n  - 🦇 Prise en charge du mode sombre.\n- 🐋 [Docker Compose](https://www.docker.com) pour le développement et la production.\n- 🔒 Hachage sécurisé des mots de passe par défaut.\n- 🔑 Authentification JWT (JSON Web Token).\n- 📫 Récupération de mot de passe par e-mail.\n- ✅ Tests avec [Pytest](https://pytest.org).\n- 📞 [Traefik](https://traefik.io) comme proxy inverse / répartiteur de charge.\n- 🚢 Instructions de déploiement avec Docker Compose, y compris la configuration d'un proxy Traefik frontal pour gérer les certificats HTTPS automatiques.\n- 🏭 CI (intégration continue) et CD (déploiement continu) basés sur GitHub Actions.\n"
  },
  {
    "path": "docs/fr/docs/python-types.md",
    "content": "# Introduction aux types Python { #python-types-intro }\n\nPython prend en charge des « annotations de type » (aussi appelées « type hints ») facultatives.\n\nCes **« annotations de type »** sont une syntaxe spéciale qui permet de déclarer le <dfn title=\"par exemple : str, int, float, bool\">type</dfn> d'une variable.\n\nEn déclarant les types de vos variables, les éditeurs et outils peuvent vous offrir un meilleur support.\n\nCeci est un **tutoriel rapide / rappel** à propos des annotations de type Python. Il couvre uniquement le minimum nécessaire pour les utiliser avec **FastAPI** ... ce qui est en réalité très peu.\n\n**FastAPI** est totalement basé sur ces annotations de type, elles lui donnent de nombreux avantages et bénéfices.\n\nMais même si vous n'utilisez jamais **FastAPI**, vous auriez intérêt à en apprendre un peu à leur sujet.\n\n/// note | Remarque\n\nSi vous êtes un expert Python, et que vous savez déjà tout sur les annotations de type, passez au chapitre suivant.\n\n///\n\n## Motivation { #motivation }\n\nCommençons par un exemple simple :\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\nExécuter ce programme affiche :\n\n```\nJohn Doe\n```\n\nLa fonction fait ce qui suit :\n\n* Prend un `first_name` et un `last_name`.\n* Convertit la première lettre de chacun en majuscule avec `title()`.\n* <dfn title=\"Les met ensemble, en un seul. Avec le contenu de l'un après l'autre.\">Concatène</dfn> ces deux valeurs avec un espace au milieu.\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### Modifier le code { #edit-it }\n\nC'est un programme très simple.\n\nMais maintenant imaginez que vous l'écriviez de zéro.\n\nÀ un certain moment, vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts ...\n\nMais ensuite vous devez appeler « cette méthode qui convertit la première lettre en majuscule ».\n\nÉtait-ce `upper` ? Était-ce `uppercase` ? `first_uppercase` ? `capitalize` ?\n\nVous essayez alors avec l'ami de toujours des programmeurs, l'autocomplétion de l'éditeur.\n\nVous tapez le premier paramètre de la fonction, `first_name`, puis un point (`.`) et appuyez sur `Ctrl+Espace` pour déclencher l'autocomplétion.\n\nMais, malheureusement, vous n'obtenez rien d'utile :\n\n<img src=\"/img/python-types/image01.png\">\n\n### Ajouter des types { #add-types }\n\nModifions une seule ligne de la version précédente.\n\nNous allons changer exactement ce fragment, les paramètres de la fonction, de :\n\n```Python\n    first_name, last_name\n```\n\nà :\n\n```Python\n    first_name: str, last_name: str\n```\n\nC'est tout.\n\nCe sont les « annotations de type » :\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\nCe n'est pas la même chose que de déclarer des valeurs par défaut, ce qui serait :\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\nC'est différent.\n\nNous utilisons des deux-points (`:`), pas des signes égal (`=`).\n\nEt ajouter des annotations de type ne change normalement pas ce qui se passe par rapport à ce qui se passerait sans elles.\n\nMais maintenant, imaginez que vous êtes à nouveau en train de créer cette fonction, mais avec des annotations de type.\n\nAu même moment, vous essayez de déclencher l'autocomplétion avec `Ctrl+Espace` et vous voyez :\n\n<img src=\"/img/python-types/image02.png\">\n\nAvec cela, vous pouvez faire défiler en voyant les options, jusqu'à trouver celle qui « vous dit quelque chose » :\n\n<img src=\"/img/python-types/image03.png\">\n\n## Plus de motivation { #more-motivation }\n\nRegardez cette fonction, elle a déjà des annotations de type :\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\nComme l'éditeur connaît les types des variables, vous n'obtenez pas seulement l'autocomplétion, vous obtenez aussi des vérifications d'erreurs :\n\n<img src=\"/img/python-types/image04.png\">\n\nVous savez maintenant qu'il faut corriger, convertir `age` en chaîne avec `str(age)` :\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## Déclarer des types { #declaring-types }\n\nVous venez de voir l'endroit principal pour déclarer des annotations de type : dans les paramètres des fonctions.\n\nC'est aussi l'endroit principal où vous les utiliserez avec **FastAPI**.\n\n### Types simples { #simple-types }\n\nVous pouvez déclarer tous les types standards de Python, pas seulement `str`.\n\nVous pouvez utiliser, par exemple :\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### Module `typing` { #typing-module }\n\nPour certains cas d'utilisation supplémentaires, vous pourriez avoir besoin d'importer certains éléments depuis le module standard `typing`, par exemple lorsque vous voulez déclarer que quelque chose a « n'importe quel type », vous pouvez utiliser `Any` depuis `typing` :\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### Types génériques { #generic-types }\n\nCertains types peuvent prendre des « paramètres de type » entre crochets, pour définir leurs types internes, par exemple une « liste de chaînes » se déclarerait `list[str]`.\n\nCes types qui peuvent prendre des paramètres de type sont appelés des **types génériques** ou **Generics**.\n\nVous pouvez utiliser les mêmes types intégrés comme génériques (avec des crochets et des types à l'intérieur) :\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### Liste { #list }\n\nPar exemple, définissons une variable comme une `list` de `str`.\n\nDéclarez la variable, en utilisant la même syntaxe avec deux-points (`:`).\n\nComme type, mettez `list`.\n\nComme la liste est un type qui contient des types internes, mettez-les entre crochets :\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info\n\nCes types internes entre crochets sont appelés « paramètres de type ».\n\nDans ce cas, `str` est le paramètre de type passé à `list`.\n\n///\n\nCela signifie : « la variable `items` est une `list`, et chacun des éléments de cette liste est un `str` ».\n\nEn faisant cela, votre éditeur peut vous fournir de l'aide même pendant le traitement des éléments de la liste :\n\n<img src=\"/img/python-types/image05.png\">\n\nSans types, c'est presque impossible à réaliser.\n\nRemarquez que la variable `item` est l'un des éléments de la liste `items`.\n\nEt pourtant, l'éditeur sait que c'est un `str` et fournit le support approprié.\n\n#### Tuple et Set { #tuple-and-set }\n\nVous feriez la même chose pour déclarer des `tuple` et des `set` :\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\nCela signifie :\n\n* La variable `items_t` est un `tuple` avec 3 éléments, un `int`, un autre `int`, et un `str`.\n* La variable `items_s` est un `set`, et chacun de ses éléments est de type `bytes`.\n\n#### Dict { #dict }\n\nPour définir un `dict`, vous passez 2 paramètres de type, séparés par des virgules.\n\nLe premier paramètre de type est pour les clés du `dict`.\n\nLe second paramètre de type est pour les valeurs du `dict` :\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\nCela signifie :\n\n* La variable `prices` est un `dict` :\n    * Les clés de ce `dict` sont de type `str` (disons, le nom de chaque article).\n    * Les valeurs de ce `dict` sont de type `float` (disons, le prix de chaque article).\n\n#### Union { #union }\n\nVous pouvez déclarer qu'une variable peut être **plusieurs types**, par exemple, un `int` ou un `str`.\n\nPour le définir, vous utilisez la <dfn title='aussi appelé « opérateur OU bit à bit », mais ce sens n’est pas pertinent ici'>barre verticale (`|`)</dfn> pour séparer les deux types.\n\nC'est ce qu'on appelle une « union », car la variable peut être n'importe quoi dans l'union de ces deux ensembles de types.\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\nCela signifie que `item` peut être un `int` ou un `str`.\n\n#### Possiblement `None` { #possibly-none }\n\nVous pouvez déclarer qu'une valeur peut avoir un type, comme `str`, mais qu'elle peut aussi être `None`.\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\nUtiliser `str | None` au lieu de simplement `str` permettra à l'éditeur de vous aider à détecter des erreurs où vous supposeriez qu'une valeur est toujours un `str`, alors qu'elle pourrait en fait aussi être `None`.\n\n### Classes en tant que types { #classes-as-types }\n\nVous pouvez aussi déclarer une classe comme type d'une variable.\n\nDisons que vous avez une classe `Person`, avec un nom :\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\nVous pouvez ensuite déclarer une variable de type `Person` :\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\nEt là encore, vous obtenez tout le support de l'éditeur :\n\n<img src=\"/img/python-types/image06.png\">\n\nRemarquez que cela signifie « `one_person` est une **instance** de la classe `Person` ».\n\nCela ne signifie pas « `one_person` est la **classe** appelée `Person` ».\n\n## Modèles Pydantic { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/) est une bibliothèque Python pour effectuer de la validation de données.\n\nVous déclarez la « forme » de la donnée sous forme de classes avec des attributs.\n\nEt chaque attribut a un type.\n\nEnsuite, vous créez une instance de cette classe avec certaines valeurs et elle validera les valeurs, les convertira dans le type approprié (le cas échéant) et vous donnera un objet avec toutes les données.\n\nEt vous obtenez tout le support de l'éditeur avec cet objet résultant.\n\nUn exemple tiré de la documentation officielle de Pydantic :\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info\n\nPour en savoir plus à propos de [Pydantic, consultez sa documentation](https://docs.pydantic.dev/).\n\n///\n\n**FastAPI** est entièrement basé sur Pydantic.\n\nVous verrez beaucoup plus de tout cela en pratique dans le [Tutoriel - Guide utilisateur](tutorial/index.md).\n\n## Annotations de type avec métadonnées { #type-hints-with-metadata-annotations }\n\nPython dispose également d'une fonctionnalité qui permet de mettre des **<dfn title=\"Données sur les données, dans ce cas, des informations sur le type, p. ex. une description.\">métadonnées</dfn> supplémentaires** dans ces annotations de type en utilisant `Annotated`.\n\nVous pouvez importer `Annotated` depuis `typing`.\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nPython lui-même ne fait rien avec ce `Annotated`. Et pour les éditeurs et autres outils, le type est toujours `str`.\n\nMais vous pouvez utiliser cet espace dans `Annotated` pour fournir à **FastAPI** des métadonnées supplémentaires sur la façon dont vous voulez que votre application se comporte.\n\nL'important à retenir est que **le premier « paramètre de type »** que vous passez à `Annotated` est le **type réel**. Le reste n'est que des métadonnées pour d'autres outils.\n\nPour l'instant, vous avez juste besoin de savoir que `Annotated` existe, et que c'est du Python standard. 😎\n\nPlus tard, vous verrez à quel point cela peut être **puissant**.\n\n/// tip | Astuce\n\nLe fait que ce soit du **Python standard** signifie que vous bénéficierez toujours de la **meilleure expérience développeur possible** dans votre éditeur, avec les outils que vous utilisez pour analyser et refactoriser votre code, etc. ✨\n\nEt aussi que votre code sera très compatible avec de nombreux autres outils et bibliothèques Python. 🚀\n\n///\n\n## Annotations de type dans **FastAPI** { #type-hints-in-fastapi }\n\n**FastAPI** tire parti de ces annotations de type pour faire plusieurs choses.\n\nAvec **FastAPI**, vous déclarez des paramètres avec des annotations de type et vous obtenez :\n\n* **Du support de l'éditeur**.\n* **Des vérifications de types**.\n\n... et **FastAPI** utilise les mêmes déclarations pour :\n\n* **Définir des prérequis** : à partir des paramètres de chemin de la requête, des paramètres de requête, des en-têtes, des corps, des dépendances, etc.\n* **Convertir des données** : de la requête vers le type requis.\n* **Valider des données** : provenant de chaque requête :\n    * En générant des **erreurs automatiques** renvoyées au client lorsque la donnée est invalide.\n* **Documenter** l'API avec OpenAPI :\n    * ce qui est ensuite utilisé par les interfaces utilisateur de documentation interactive automatiques.\n\nTout cela peut sembler abstrait. Ne vous inquiétez pas. Vous verrez tout cela en action dans le [Tutoriel - Guide utilisateur](tutorial/index.md).\n\nL'important est qu'en utilisant les types standards de Python, en un seul endroit (au lieu d'ajouter plus de classes, de décorateurs, etc.), **FastAPI** fera une grande partie du travail pour vous.\n\n/// info\n\nSi vous avez déjà parcouru tout le tutoriel et êtes revenu pour en voir plus sur les types, une bonne ressource est [l'« aide-mémoire » de `mypy`](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html).\n\n///\n"
  },
  {
    "path": "docs/fr/docs/resources/index.md",
    "content": "# Ressources { #resources }\n\nRessources supplémentaires, liens externes et plus encore. ✈️\n"
  },
  {
    "path": "docs/fr/docs/translation-banner.md",
    "content": "/// details | 🌐 Traduction par IA et humains\n\nCette traduction a été réalisée par une IA guidée par des humains. 🤝\n\nElle peut contenir des erreurs d'interprétation du sens original, ou paraître peu naturelle, etc. 🤖\n\nVous pouvez améliorer cette traduction en [nous aidant à mieux guider le LLM d'IA](https://fastapi.tiangolo.com/fr/contributing/#translations).\n\n[Version anglaise](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/fr/docs/tutorial/background-tasks.md",
    "content": "# Tâches d'arrière-plan { #background-tasks }\n\nVous pouvez définir des tâches d'arrière-plan qui seront exécutées après avoir retourné une réponse.\n\nCeci est utile pour les opérations qui doivent avoir lieu après une requête, mais où le client n'a pas réellement besoin d'attendre que l'opération soit terminée pour recevoir une réponse.\n\nCela comprend, par exemple :\n\n* Les notifications par email envoyées après l'exécution d'une action :\n    * Étant donné que se connecter à un serveur et envoyer un email a tendance à être « lent » (plusieurs secondes), vous pouvez retourner la réponse directement et envoyer la notification en arrière-plan.\n* Traiter des données :\n    * Par exemple, si vous recevez un fichier qui doit passer par un traitement lent, vous pouvez retourner une réponse « Accepted » (HTTP 202) puis faire le traitement en arrière-plan.\n\n## Utiliser `BackgroundTasks` { #using-backgroundtasks }\n\nPour commencer, importez `BackgroundTasks` et définissez un paramètre dans votre *fonction de chemin d'accès* avec `BackgroundTasks` comme type déclaré.\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI** créera l'objet de type `BackgroundTasks` pour vous et le passera comme paramètre.\n\n## Créer une fonction de tâche { #create-a-task-function }\n\nCréez une fonction à exécuter comme tâche d'arrière-plan.\n\nUne fonction à exécuter comme tâche d'arrière-plan est juste une fonction standard qui peut recevoir des paramètres.\n\nElle peut être une fonction asynchrone (`async def`) ou une fonction normale (`def`), **FastAPI** saura la gérer correctement.\n\nDans cet exemple, la fonction de tâche écrira dans un fichier (afin de simuler un envoi d'email).\n\nL'opération d'écriture n'utilisant ni `async` ni `await`, on définit la fonction avec un `def` normal.\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## Ajouter une tâche d'arrière-plan { #add-the-background-task }\n\nDans votre *fonction de chemin d'accès*, passez votre fonction de tâche à l'objet de type `BackgroundTasks` (`background_tasks` ici) grâce à la méthode `.add_task()` :\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()` reçoit comme arguments :\n\n* Une fonction de tâche à exécuter en arrière-plan (`write_notification`).\n* Les arguments positionnels à passer à la fonction de tâche dans l'ordre (`email`).\n* Les arguments nommés à passer à la fonction de tâche (`message=\"some notification\"`).\n\n## Injection de dépendances { #dependency-injection }\n\nUtiliser `BackgroundTasks` fonctionne aussi avec le système d'injection de dépendances. Vous pouvez déclarer un paramètre de type `BackgroundTasks` à différents niveaux : dans une *fonction de chemin d'accès*, dans une dépendance (dependable), dans une sous-dépendance, etc.\n\n**FastAPI** sait quoi faire dans chaque cas et comment réutiliser le même objet, afin que toutes les tâches d'arrière-plan soient fusionnées et que les tâches soient ensuite exécutées en arrière-plan :\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\nDans cet exemple, les messages seront écrits dans le fichier `log.txt` après que la réponse soit envoyée.\n\nS'il y avait un paramètre de requête dans la requête, alors il sera écrit dans le journal via une tâche d'arrière-plan.\n\nEt ensuite une autre tâche d'arrière-plan (générée dans la *fonction de chemin d'accès*) écrira un message comprenant le paramètre de chemin `email`.\n\n## Détails techniques { #technical-details }\n\nLa classe `BackgroundTasks` provient directement de [`starlette.background`](https://www.starlette.dev/background/).\n\nElle est importée/incluse directement dans **FastAPI** pour que vous puissiez l'importer depuis `fastapi` et éviter d'importer accidentellement `BackgroundTask` (sans `s` à la fin) depuis `starlette.background`.\n\nEn utilisant seulement `BackgroundTasks` (et non `BackgroundTask`), il est possible de l'utiliser en tant que paramètre de *fonction de chemin d'accès* et de laisser **FastAPI** gérer le reste pour vous, comme en utilisant l'objet `Request` directement.\n\nIl est tout de même possible d'utiliser `BackgroundTask` seul dans **FastAPI**, mais dans ce cas il faut créer l'objet dans le code et renvoyer une `Response` Starlette l'incluant.\n\nPlus de détails sont disponibles dans [la documentation officielle de Starlette sur les tâches d'arrière-plan](https://www.starlette.dev/background/).\n\n## Avertissement { #caveat }\n\nSi vous avez besoin de réaliser des traitements lourds en tâche d'arrière-plan et que vous n'avez pas besoin que ces traitements aient lieu dans le même process (par exemple, pas besoin de partager la mémoire, les variables, etc.), il peut s'avérer profitable d'utiliser des outils plus importants tels que [Celery](https://docs.celeryq.dev).\n\nCes outils nécessitent généralement des configurations plus complexes ainsi qu'un gestionnaire de queue de message, comme RabbitMQ ou Redis, mais ils permettent d'exécuter des tâches d'arrière-plan dans différents process, et surtout, sur plusieurs serveurs.\n\nMais si vous avez besoin d'accéder aux variables et objets de la même application **FastAPI**, ou si vous avez besoin d'effectuer de petites tâches d'arrière-plan (comme envoyer des notifications par email), vous pouvez simplement vous contenter d'utiliser `BackgroundTasks`.\n\n## Résumé { #recap }\n\nImportez et utilisez `BackgroundTasks` grâce aux paramètres de *fonction de chemin d'accès* et les dépendances pour ajouter des tâches d'arrière-plan.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/bigger-applications.md",
    "content": "# Créer des applications plus grandes - Plusieurs fichiers { #bigger-applications-multiple-files }\n\nSi vous créez une application ou une API web, il est rare que vous puissiez tout mettre dans un seul fichier.\n\n**FastAPI** fournit un outil pratique pour structurer votre application tout en conservant toute la flexibilité.\n\n/// info\n\nSi vous venez de Flask, cela équivaut aux Blueprints de Flask.\n\n///\n\n## Exemple de structure de fichiers { #an-example-file-structure }\n\nSupposons que vous ayez une structure de fichiers comme ceci :\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | Astuce\n\nIl y a plusieurs fichiers `__init__.py` : un dans chaque répertoire ou sous-répertoire.\n\nC'est cela qui permet d'importer du code d'un fichier dans un autre.\n\nPar exemple, dans `app/main.py` vous pourriez avoir une ligne comme :\n\n```\nfrom app.routers import items\n```\n\n///\n\n* Le répertoire `app` contient tout. Et il a un fichier vide `app/__init__.py`, c'est donc un « package Python » (une collection de « modules Python ») : `app`.\n* Il contient un fichier `app/main.py`. Comme il se trouve dans un package Python (un répertoire avec un fichier `__init__.py`), c'est un « module » de ce package : `app.main`.\n* Il y a aussi un fichier `app/dependencies.py`, tout comme `app/main.py`, c'est un « module » : `app.dependencies`.\n* Il y a un sous-répertoire `app/routers/` avec un autre fichier `__init__.py`, c'est donc un « sous-package Python » : `app.routers`.\n* Le fichier `app/routers/items.py` est dans un package, `app/routers/`, c'est donc un sous-module : `app.routers.items`.\n* De même pour `app/routers/users.py`, c'est un autre sous-module : `app.routers.users`.\n* Il y a aussi un sous-répertoire `app/internal/` avec un autre fichier `__init__.py`, c'est donc un autre « sous-package Python » : `app.internal`.\n* Et le fichier `app/internal/admin.py` est un autre sous-module : `app.internal.admin`.\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\nLa même structure de fichiers avec des commentaires :\n\n```bash\n.\n├── app                  # \"app\" est un package Python\n│   ├── __init__.py      # ce fichier fait de \"app\" un \"package Python\"\n│   ├── main.py          # module \"main\", ex. import app.main\n│   ├── dependencies.py  # module \"dependencies\", ex. import app.dependencies\n│   └── routers          # \"routers\" est un \"sous-package Python\"\n│   │   ├── __init__.py  # fait de \"routers\" un \"sous-package Python\"\n│   │   ├── items.py     # sous-module \"items\", ex. import app.routers.items\n│   │   └── users.py     # sous-module \"users\", ex. import app.routers.users\n│   └── internal         # \"internal\" est un \"sous-package Python\"\n│       ├── __init__.py  # fait de \"internal\" un \"sous-package Python\"\n│       └── admin.py     # sous-module \"admin\", ex. import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\nSupposons que le fichier dédié à la gestion des utilisateurs soit le sous-module `/app/routers/users.py`.\n\nVous voulez séparer les *chemins d'accès* liés à vos utilisateurs du reste du code pour le garder organisé.\n\nMais cela fait toujours partie de la même application/API web **FastAPI** (cela fait partie du même « package Python »).\n\nVous pouvez créer les *chemins d'accès* pour ce module à l'aide de `APIRouter`.\n\n### Importer `APIRouter` { #import-apirouter }\n\nVous l'importez et créez une « instance » de la même manière que vous le feriez avec la classe `FastAPI` :\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### Déclarer des *chemins d'accès* avec `APIRouter` { #path-operations-with-apirouter }\n\nPuis vous l'utilisez pour déclarer vos *chemins d'accès*.\n\nUtilisez-le de la même manière que vous utiliseriez la classe `FastAPI` :\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\nVous pouvez considérer `APIRouter` comme une « mini `FastAPI` ».\n\nToutes les mêmes options sont prises en charge.\n\nTous les mêmes `parameters`, `responses`, `dependencies`, `tags`, etc.\n\n/// tip | Astuce\n\nDans cet exemple, la variable s'appelle `router`, mais vous pouvez la nommer comme vous le souhaitez.\n\n///\n\nNous allons inclure ce `APIRouter` dans l'application principale `FastAPI`, mais d'abord, examinons les dépendances et un autre `APIRouter`.\n\n## Gérer les dépendances { #dependencies }\n\nNous voyons que nous allons avoir besoin de certaines dépendances utilisées à plusieurs endroits de l'application.\n\nNous les mettons donc dans leur propre module `dependencies` (`app/dependencies.py`).\n\nNous allons maintenant utiliser une dépendance simple pour lire un en-tête personnalisé `X-Token` :\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | Astuce\n\nNous utilisons un en-tête inventé pour simplifier cet exemple.\n\nMais dans les cas réels, vous obtiendrez de meilleurs résultats en utilisant les [utilitaires de sécurité](security/index.md) intégrés.\n\n///\n\n## Créer un autre module avec `APIRouter` { #another-module-with-apirouter }\n\nSupposons que vous ayez également les endpoints dédiés à la gestion des « items » de votre application dans le module `app/routers/items.py`.\n\nVous avez des *chemins d'accès* pour :\n\n* `/items/`\n* `/items/{item_id}`\n\nC'est exactement la même structure que pour `app/routers/users.py`.\n\nMais nous voulons être plus malins et simplifier un peu le code.\n\nNous savons que tous les *chemins d'accès* de ce module ont les mêmes éléments :\n\n* Préfixe de chemin `prefix` : `/items`.\n* `tags` : (un seul tag : `items`).\n* `responses` supplémentaires.\n* `dependencies` : ils ont tous besoin de la dépendance `X-Token` que nous avons créée.\n\nDonc, au lieu d'ajouter tout cela à chaque *chemin d'accès*, nous pouvons l'ajouter au `APIRouter`.\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\nComme le chemin de chaque *chemin d'accès* doit commencer par `/`, comme dans :\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n... le préfixe ne doit pas inclure un `/` final.\n\nAinsi, le préfixe dans ce cas est `/items`.\n\nNous pouvons également ajouter une liste de `tags` et des `responses` supplémentaires qui seront appliqués à tous les *chemins d'accès* inclus dans ce routeur.\n\nEt nous pouvons ajouter une liste de `dependencies` qui seront ajoutées à tous les *chemins d'accès* du routeur et seront exécutées/résolues pour chaque requête qui leur est faite.\n\n/// tip | Astuce\n\nNotez que, tout comme pour les [dépendances dans les décorateurs de *chemin d'accès*](dependencies/dependencies-in-path-operation-decorators.md), aucune valeur ne sera transmise à votre *fonction de chemin d'accès*.\n\n///\n\nLe résultat final est que les chemins d'item sont désormais :\n\n* `/items/`\n* `/items/{item_id}`\n\n... comme prévu.\n\n* Ils seront marqués avec une liste de tags qui contient une seule chaîne « items ».\n    * Ces « tags » sont particulièrement utiles pour les systèmes de documentation interactive automatique (utilisant OpenAPI).\n* Ils incluront tous les `responses` prédéfinies.\n* Tous ces *chemins d'accès* auront la liste des `dependencies` évaluées/exécutées avant eux.\n    * Si vous déclarez également des dépendances dans un *chemin d'accès* spécifique, **elles seront aussi exécutées**.\n    * Les dépendances du routeur sont exécutées en premier, puis les [`dependencies` dans le décorateur](dependencies/dependencies-in-path-operation-decorators.md), puis les dépendances des paramètres normaux.\n    * Vous pouvez également ajouter des [`Security` dependencies avec des `scopes`](../advanced/security/oauth2-scopes.md).\n\n/// tip | Astuce\n\nAvoir des `dependencies` dans le `APIRouter` peut servir, par exemple, à exiger une authentification pour tout un groupe de *chemins d'accès*. Même si les dépendances ne sont pas ajoutées individuellement à chacun d'eux.\n\n///\n\n/// check | Vérifications\n\nLes paramètres `prefix`, `tags`, `responses` et `dependencies` sont (comme dans de nombreux autres cas) simplement une fonctionnalité de **FastAPI** pour vous aider à éviter la duplication de code.\n\n///\n\n### Importer les dépendances { #import-the-dependencies }\n\nCe code se trouve dans le module `app.routers.items`, le fichier `app/routers/items.py`.\n\nEt nous devons récupérer la fonction de dépendance depuis le module `app.dependencies`, le fichier `app/dependencies.py`.\n\nNous utilisons donc un import relatif avec `..` pour les dépendances :\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### Comprendre le fonctionnement des imports relatifs { #how-relative-imports-work }\n\n/// tip | Astuce\n\nSi vous savez parfaitement comment fonctionnent les imports, passez à la section suivante ci-dessous.\n\n///\n\nUn seul point `.`, comme dans :\n\n```Python\nfrom .dependencies import get_token_header\n```\n\nsignifierait :\n\n* En partant du même package dans lequel vit ce module (le fichier `app/routers/items.py`) (le répertoire `app/routers/`)...\n* trouver le module `dependencies` (un fichier imaginaire `app/routers/dependencies.py`)...\n* et en importer la fonction `get_token_header`.\n\nMais ce fichier n'existe pas, nos dépendances sont dans un fichier `app/dependencies.py`.\n\nRappelez-vous à quoi ressemble la structure de notre app/fichiers :\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\nLes deux points `..`, comme dans :\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\nveulent dire :\n\n* En partant du même package dans lequel vit ce module (le fichier `app/routers/items.py`) (le répertoire `app/routers/`)...\n* aller au package parent (le répertoire `app/`)...\n* et là, trouver le module `dependencies` (le fichier `app/dependencies.py`)...\n* et en importer la fonction `get_token_header`.\n\nCela fonctionne correctement ! 🎉\n\n---\n\nDe la même manière, si nous avions utilisé trois points `...`, comme dans :\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\ncela voudrait dire :\n\n* En partant du même package dans lequel vit ce module (le fichier `app/routers/items.py`) (le répertoire `app/routers/`)...\n* aller au package parent (le répertoire `app/`)...\n* puis aller au parent de ce package (il n'y a pas de package parent, `app` est le niveau supérieur 😱)...\n* et là, trouver le module `dependencies` (le fichier `app/dependencies.py`)...\n* et en importer la fonction `get_token_header`.\n\nCela ferait référence à un package au-dessus de `app/`, avec son propre fichier `__init__.py`, etc. Mais nous n'avons pas cela. Donc, cela lèverait une erreur dans notre exemple. 🚨\n\nMais maintenant vous savez comment cela fonctionne, vous pouvez donc utiliser des imports relatifs dans vos propres applications, aussi complexes soient-elles. 🤓\n\n### Ajouter des `tags`, `responses` et `dependencies` personnalisés { #add-some-custom-tags-responses-and-dependencies }\n\nNous n'ajoutons pas le préfixe `/items` ni `tags=[\"items\"]` à chaque *chemin d'accès* parce que nous les avons ajoutés au `APIRouter`.\n\nMais nous pouvons toujours ajouter _davantage_ de `tags` qui seront appliqués à un *chemin d'accès* spécifique, ainsi que des `responses` supplémentaires propres à ce *chemin d'accès* :\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | Astuce\n\nCe dernier *chemin d'accès* aura la combinaison de tags : `[\"items\", \"custom\"]`.\n\nEt il aura également les deux réponses dans la documentation, une pour `404` et une pour `403`.\n\n///\n\n## Créer l'application `FastAPI` principale { #the-main-fastapi }\n\nVoyons maintenant le module `app/main.py`.\n\nC'est ici que vous importez et utilisez la classe `FastAPI`.\n\nCe sera le fichier principal de votre application qui reliera tout ensemble.\n\nEt comme la plupart de votre logique vivra désormais dans son propre module, le fichier principal sera assez simple.\n\n### Importer `FastAPI` { #import-fastapi }\n\nVous importez et créez une classe `FastAPI` comme d'habitude.\n\nEt nous pouvons même déclarer des [dépendances globales](dependencies/global-dependencies.md) qui seront combinées avec les dépendances de chaque `APIRouter` :\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### Importer les `APIRouter` { #import-the-apirouter }\n\nNous importons maintenant les autres sous-modules qui ont des `APIRouter` :\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\nComme les fichiers `app/routers/users.py` et `app/routers/items.py` sont des sous-modules qui font partie du même package Python `app`, nous pouvons utiliser un seul point `.` pour les importer en utilisant des « imports relatifs ».\n\n### Comprendre le fonctionnement de l'import { #how-the-importing-works }\n\nLa section :\n\n```Python\nfrom .routers import items, users\n```\n\nsignifie :\n\n* En partant du même package dans lequel vit ce module (le fichier `app/main.py`) (le répertoire `app/`)...\n* chercher le sous-package `routers` (le répertoire `app/routers/`)...\n* et en importer le sous-module `items` (le fichier `app/routers/items.py`) et `users` (le fichier `app/routers/users.py`)...\n\nLe module `items` aura une variable `router` (`items.router`). C'est celle que nous avons créée dans le fichier `app/routers/items.py`, c'est un objet `APIRouter`.\n\nNous faisons ensuite la même chose pour le module `users`.\n\nNous pourrions aussi les importer ainsi :\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info\n\nLa première version est un « import relatif » :\n\n```Python\nfrom .routers import items, users\n```\n\nLa deuxième version est un « import absolu » :\n\n```Python\nfrom app.routers import items, users\n```\n\nPour en savoir plus sur les Packages et Modules Python, lisez [la documentation officielle de Python sur les modules](https://docs.python.org/3/tutorial/modules.html).\n\n///\n\n### Éviter les collisions de noms { #avoid-name-collisions }\n\nNous importons le sous-module `items` directement, au lieu d'importer uniquement sa variable `router`.\n\nC'est parce que nous avons également une autre variable nommée `router` dans le sous-module `users`.\n\nSi nous les avions importées l'une après l'autre, comme :\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\nle `router` de `users` écraserait celui de `items` et nous ne pourrions pas les utiliser en même temps.\n\nDonc, pour pouvoir utiliser les deux dans le même fichier, nous importons directement les sous-modules :\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### Inclure les `APIRouter` pour `users` et `items` { #include-the-apirouters-for-users-and-items }\n\nIncluons maintenant les `router` des sous-modules `users` et `items` :\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info\n\n`users.router` contient le `APIRouter` à l'intérieur du fichier `app/routers/users.py`.\n\nEt `items.router` contient le `APIRouter` à l'intérieur du fichier `app/routers/items.py`.\n\n///\n\nAvec `app.include_router()`, nous pouvons ajouter chaque `APIRouter` à l'application principale `FastAPI`.\n\nCela inclura toutes les routes de ce routeur comme faisant partie de l'application.\n\n/// note | Détails techniques\n\nEn interne, cela créera en fait un *chemin d'accès* pour chaque *chemin d'accès* qui a été déclaré dans le `APIRouter`.\n\nDonc, en coulisses, cela fonctionnera comme si tout faisait partie d'une seule et même application.\n\n///\n\n/// check | Vérifications\n\nVous n'avez pas à vous soucier de la performance lors de l'inclusion de routeurs.\n\nCela prendra des microsecondes et ne se produira qu'au démarrage.\n\nDonc cela n'affectera pas la performance. ⚡\n\n///\n\n### Inclure un `APIRouter` avec un `prefix`, des `tags`, des `responses` et des `dependencies` personnalisés { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\nImaginons maintenant que votre organisation vous ait fourni le fichier `app/internal/admin.py`.\n\nIl contient un `APIRouter` avec quelques *chemins d'accès* d'administration que votre organisation partage entre plusieurs projets.\n\nPour cet exemple, il sera très simple. Mais supposons que, parce qu'il est partagé avec d'autres projets de l'organisation, nous ne puissions pas le modifier et ajouter un `prefix`, des `dependencies`, des `tags`, etc. directement au `APIRouter` :\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nMais nous voulons quand même définir un `prefix` personnalisé lors de l'inclusion du `APIRouter` afin que tous ses *chemins d'accès* commencent par `/admin`, nous voulons le sécuriser avec les `dependencies` que nous avons déjà pour ce projet, et nous voulons inclure des `tags` et des `responses`.\n\nNous pouvons déclarer tout cela sans avoir à modifier le `APIRouter` d'origine en passant ces paramètres à `app.include_router()` :\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\nDe cette façon, le `APIRouter` original restera inchangé, afin que nous puissions toujours partager ce même fichier `app/internal/admin.py` avec d'autres projets de l'organisation.\n\nLe résultat est que, dans notre application, chacun des *chemins d'accès* du module `admin` aura :\n\n* Le préfixe `/admin`.\n* Le tag `admin`.\n* La dépendance `get_token_header`.\n* La réponse `418`. 🍵\n\nMais cela n'affectera que ce `APIRouter` dans notre application, pas dans tout autre code qui l'utilise.\n\nAinsi, par exemple, d'autres projets pourraient utiliser le même `APIRouter` avec une méthode d'authentification différente.\n\n### Inclure un *chemin d'accès* { #include-a-path-operation }\n\nNous pouvons également ajouter des *chemins d'accès* directement à l'application `FastAPI`.\n\nIci, nous le faisons ... juste pour montrer que nous le pouvons 🤷 :\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\net cela fonctionnera correctement, avec tous les autres *chemins d'accès* ajoutés avec `app.include_router()`.\n\n/// info | Détails très techniques\n\nNote : c'est un détail très technique que vous pouvez probablement **simplement ignorer**.\n\n---\n\nLes `APIRouter` ne sont pas « montés », ils ne sont pas isolés du reste de l'application.\n\nC'est parce que nous voulons inclure leurs *chemins d'accès* dans le schéma OpenAPI et les interfaces utilisateur.\n\nComme nous ne pouvons pas simplement les isoler et les « monter » indépendamment du reste, les *chemins d'accès* sont « clonés » (recréés), pas inclus directement.\n\n///\n\n## Configurer l'`entrypoint` dans `pyproject.toml` { #configure-the-entrypoint-in-pyproject-toml }\n\nComme votre objet FastAPI `app` vit dans `app/main.py`, vous pouvez configurer l'`entrypoint` dans votre fichier `pyproject.toml` comme ceci :\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\nce qui équivaut à importer ainsi :\n\n```python\nfrom app.main import app\n```\n\nDe cette façon, la commande `fastapi` saura où trouver votre app.\n\n/// Note | Remarque\n\nVous pourriez aussi passer le chemin à la commande, comme :\n\n```console\n$ fastapi dev app/main.py\n```\n\nMais vous devriez vous rappeler de passer le bon chemin à chaque fois que vous appelez la commande `fastapi`.\n\nEn outre, d'autres outils pourraient ne pas être en mesure de la trouver, par exemple l'[Extension VS Code](../editor-support.md) ou [FastAPI Cloud](https://fastapicloud.com), il est donc recommandé d'utiliser l'`entrypoint` dans `pyproject.toml`.\n\n///\n\n## Consulter la documentation API automatique { #check-the-automatic-api-docs }\n\nMaintenant, exécutez votre application :\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nEt ouvrez les documents à [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVous verrez la documentation API automatique, incluant les chemins de tous les sous-modules, utilisant les bons chemins (et préfixes) et les bons tags :\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## Inclure le même routeur plusieurs fois avec des `prefix` différents { #include-the-same-router-multiple-times-with-different-prefix }\n\nVous pouvez aussi utiliser `.include_router()` plusieurs fois avec le même routeur en utilisant des préfixes différents.\n\nCela peut être utile, par exemple, pour exposer la même API sous des préfixes différents, p. ex. `/api/v1` et `/api/latest`.\n\nC'est un usage avancé dont vous n'aurez peut-être pas vraiment besoin, mais il est là au cas où.\n\n## Inclure un `APIRouter` dans un autre { #include-an-apirouter-in-another }\n\nDe la même manière que vous pouvez inclure un `APIRouter` dans une application `FastAPI`, vous pouvez inclure un `APIRouter` dans un autre `APIRouter` en utilisant :\n\n```Python\nrouter.include_router(other_router)\n```\n\nVous devez vous assurer de le faire avant d'inclure `router` dans l'application `FastAPI`, afin que les *chemins d'accès* de `other_router` soient également inclus.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/body-fields.md",
    "content": "# Corps - Champs { #body-fields }\n\nDe la même manière que vous pouvez déclarer des validations supplémentaires et des métadonnées dans les paramètres d'une fonction de chemin d'accès avec `Query`, `Path` et `Body`, vous pouvez déclarer des validations et des métadonnées à l'intérieur des modèles Pydantic en utilisant `Field` de Pydantic.\n\n## Importer `Field` { #import-field }\n\nD'abord, vous devez l'importer :\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n\n/// warning | Alertes\n\nNotez que `Field` est importé directement depuis `pydantic`, et non depuis `fastapi` comme le sont les autres (`Query`, `Path`, `Body`, etc.).\n\n///\n\n## Déclarer les attributs du modèle { #declare-model-attributes }\n\nVous pouvez ensuite utiliser `Field` avec des attributs de modèle :\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field` fonctionne de la même manière que `Query`, `Path` et `Body`, il dispose des mêmes paramètres, etc.\n\n/// note | Détails techniques\n\nEn réalité, `Query`, `Path` et d'autres que vous verrez ensuite créent des objets de sous-classes d'une classe commune `Param`, qui est elle-même une sous-classe de la classe `FieldInfo` de Pydantic.\n\nEt `Field` de Pydantic renvoie également une instance de `FieldInfo`.\n\n`Body` renvoie aussi directement des objets d'une sous-classe de `FieldInfo`. Et il y en a d'autres que vous verrez plus tard qui sont des sous-classes de la classe `Body`.\n\nRappelez-vous que lorsque vous importez `Query`, `Path` et d'autres depuis `fastapi`, ce sont en réalité des fonctions qui renvoient des classes spéciales.\n\n///\n\n/// tip | Astuce\n\nRemarquez comment chaque attribut de modèle avec un type, une valeur par défaut et `Field` a la même structure qu'un paramètre de fonction de chemin d'accès, avec `Field` au lieu de `Path`, `Query` et `Body`.\n\n///\n\n## Ajouter des informations supplémentaires { #add-extra-information }\n\nVous pouvez déclarer des informations supplémentaires dans `Field`, `Query`, `Body`, etc. Elles seront incluses dans le JSON Schema généré.\n\nVous en apprendrez davantage sur l'ajout d'informations supplémentaires plus loin dans les documents, lorsque vous apprendrez à déclarer des exemples.\n\n/// warning | Alertes\n\nLes clés supplémentaires passées à `Field` seront également présentes dans le schéma OpenAPI résultant pour votre application.\nComme ces clés ne font pas nécessairement partie de la spécification OpenAPI, certains outils OpenAPI, par exemple [le validateur OpenAPI](https://validator.swagger.io/), peuvent ne pas fonctionner avec votre schéma généré.\n\n///\n\n## Récapitulatif { #recap }\n\nVous pouvez utiliser `Field` de Pydantic pour déclarer des validations supplémentaires et des métadonnées pour les attributs de modèle.\n\nVous pouvez également utiliser des arguments nommés supplémentaires pour transmettre des métadonnées JSON Schema additionnelles.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/body-multiple-params.md",
    "content": "# Body - Paramètres multiples { #body-multiple-parameters }\n\nMaintenant que nous avons vu comment utiliser `Path` et `Query`, voyons des usages plus avancés des déclarations de paramètres du corps de la requête.\n\n## Mélanger les paramètres `Path`, `Query` et du corps de la requête { #mix-path-query-and-body-parameters }\n\nTout d'abord, sachez que vous pouvez mélanger librement les déclarations des paramètres `Path`, `Query` et du corps de la requête, **FastAPI** saura quoi faire.\n\nEt vous pouvez également déclarer des paramètres du corps de la requête comme étant optionnels, en leur assignant une valeur par défaut à `None` :\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | Remarque\n\nNotez que, dans ce cas, l'élément `item` récupéré depuis le corps de la requête est optionnel. Comme sa valeur par défaut est `None`.\n\n///\n\n## Paramètres multiples du corps de la requête { #multiple-body-parameters }\n\nDans l'exemple précédent, les chemins d'accès attendraient un corps de la requête JSON avec les attributs d'un `Item`, par exemple :\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\nMais vous pouvez également déclarer plusieurs paramètres provenant du corps de la requête, par exemple `item` et `user` :\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\nDans ce cas, **FastAPI** détectera qu'il y a plus d'un paramètre du corps de la requête dans la fonction (il y a deux paramètres qui sont des modèles Pydantic).\n\nIl utilisera alors les noms des paramètres comme clés (noms de champs) dans le corps de la requête, et s'attendra à recevoir un corps de la requête semblable à :\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | Remarque\n\nNotez que, bien que `item` ait été déclaré de la même manière qu'auparavant, il est désormais attendu à l'intérieur du corps de la requête sous la clé `item`.\n\n///\n\n**FastAPI** effectuera la conversion automatique depuis la requête, de sorte que le paramètre `item` reçoive son contenu spécifique, et de même pour `user`.\n\nIl effectuera la validation des données composées, et les documentera ainsi pour le schéma OpenAPI et la documentation automatique.\n\n## Valeurs singulières dans le corps de la requête { #singular-values-in-body }\n\nDe la même façon qu'il existe `Query` et `Path` pour définir des données supplémentaires pour les paramètres de requête et de chemin, **FastAPI** fournit un équivalent `Body`.\n\nPar exemple, en étendant le modèle précédent, vous pourriez décider d'avoir une autre clé `importance` dans le même corps de la requête, en plus de `item` et `user`.\n\nSi vous le déclarez tel quel, comme c'est une valeur singulière, **FastAPI** supposera qu'il s'agit d'un paramètre de requête.\n\nMais vous pouvez indiquer à **FastAPI** de la traiter comme une autre clé du corps de la requête en utilisant `Body` :\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\nDans ce cas, **FastAPI** s'attendra à un corps de la requête semblable à :\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\nEncore une fois, il convertira les types de données, validera, documentera, etc.\n\n## Paramètres multiples du corps de la requête et paramètres de requête { #multiple-body-params-and-query }\n\nBien entendu, vous pouvez également déclarer des paramètres de requête supplémentaires quand vous en avez besoin, en plus de tout paramètre du corps de la requête.\n\nComme, par défaut, les valeurs singulières sont interprétées comme des paramètres de requête, vous n'avez pas besoin d'ajouter explicitement `Query`, vous pouvez simplement écrire :\n\n```Python\nq: str | None = None\n```\n\nPar exemple :\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n/// info\n\n`Body` possède également les mêmes paramètres supplémentaires de validation et de métadonnées que `Query`, `Path` et d'autres que vous verrez plus tard.\n\n///\n\n## Intégrer un seul paramètre du corps de la requête { #embed-a-single-body-parameter }\n\nSupposons que vous n'ayez qu'un seul paramètre `item` dans le corps de la requête, provenant d'un modèle Pydantic `Item`.\n\nPar défaut, **FastAPI** attendra alors son contenu directement.\n\nMais si vous voulez qu'il attende un JSON avec une clé `item` contenant le contenu du modèle, comme lorsqu'on déclare des paramètres supplémentaires du corps de la requête, vous pouvez utiliser le paramètre spécial `embed` de `Body` :\n\n```Python\nitem: Item = Body(embed=True)\n```\n\ncomme dans :\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\nDans ce cas **FastAPI** s'attendra à un corps de la requête semblable à :\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\nau lieu de :\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## Récapitulatif { #recap }\n\nVous pouvez ajouter plusieurs paramètres du corps de la requête à votre fonction de chemin d'accès, même si une requête ne peut avoir qu'un seul corps de la requête.\n\nMais **FastAPI** s'en chargera, vous fournira les bonnes données dans votre fonction, et validera et documentera le schéma correct dans le chemin d'accès.\n\nVous pouvez également déclarer des valeurs singulières à recevoir dans le corps de la requête.\n\nEt vous pouvez indiquer à **FastAPI** d'intégrer le corps de la requête sous une clé même lorsqu'un seul paramètre est déclaré.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/body-nested-models.md",
    "content": "# Corps - Modèles imbriqués { #body-nested-models }\n\nAvec FastAPI, vous pouvez définir, valider, documenter et utiliser des modèles imbriqués à n'importe quelle profondeur (grâce à Pydantic).\n\n## Déclarer des champs de liste { #list-fields }\n\nVous pouvez définir un attribut comme étant un sous-type. Par exemple, une `list` Python :\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\nCela fera de `tags` une liste, bien que le type des éléments de la liste ne soit pas déclaré.\n\n## Champs de liste avec paramètre de type { #list-fields-with-type-parameter }\n\nMais Python a une manière spécifique de déclarer des listes avec des types internes, ou « paramètres de type » :\n\n### Déclarer une `list` avec un paramètre de type { #declare-a-list-with-a-type-parameter }\n\nPour déclarer des types qui ont des paramètres de type (types internes), comme `list`, `dict`, `tuple`,\npassez le(s) type(s) interne(s) comme « paramètres de type » à l'aide de crochets : `[` et `]`\n\n```Python\nmy_list: list[str]\n```\n\nC'est simplement la syntaxe Python standard pour les déclarations de type.\n\nUtilisez cette même syntaxe standard pour les attributs de modèles avec des types internes.\n\nAinsi, dans notre exemple, nous pouvons faire de `tags` spécifiquement une « liste de chaînes » :\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## Types set { #set-types }\n\nMais en y réfléchissant, nous réalisons que les tags ne devraient pas se répéter, ce seraient probablement des chaînes uniques.\n\nEt Python dispose d'un type de données spécial pour les ensembles d'éléments uniques, le `set`.\n\nNous pouvons alors déclarer `tags` comme un set de chaînes :\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\nAvec cela, même si vous recevez une requête contenant des doublons, elle sera convertie en un set d'éléments uniques.\n\nEt chaque fois que vous renverrez ces données, même si la source contenait des doublons, elles seront renvoyées sous la forme d'un set d'éléments uniques.\n\nElles seront également annotées / documentées en conséquence.\n\n## Modèles imbriqués { #nested-models }\n\nChaque attribut d'un modèle Pydantic a un type.\n\nMais ce type peut lui-même être un autre modèle Pydantic.\n\nAinsi, vous pouvez déclarer des « objets » JSON profondément imbriqués avec des noms d'attributs, des types et des validations spécifiques.\n\nTout cela, de manière arbitrairement imbriquée.\n\n### Définir un sous-modèle { #define-a-submodel }\n\nPar exemple, nous pouvons définir un modèle `Image` :\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### Utiliser le sous-modèle comme type { #use-the-submodel-as-a-type }\n\nNous pouvons ensuite l'utiliser comme type d'un attribut :\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\nCela signifie que FastAPI attendrait un corps similaire à :\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\nLà encore, avec cette simple déclaration, avec FastAPI vous obtenez :\n\n- Prise en charge par l'éditeur (autocomplétion, etc.), même pour les modèles imbriqués\n- Conversion des données\n- Validation des données\n- Documentation automatique\n\n## Types spéciaux et validation { #special-types-and-validation }\n\nOutre les types singuliers normaux comme `str`, `int`, `float`, etc. vous pouvez utiliser des types singuliers plus complexes qui héritent de `str`.\n\nPour voir toutes les options dont vous disposez, consultez [l’aperçu des types de Pydantic](https://docs.pydantic.dev/latest/concepts/types/). Vous verrez quelques exemples au chapitre suivant.\n\nPar exemple, comme dans le modèle `Image` nous avons un champ `url`, nous pouvons le déclarer comme instance de `HttpUrl` de Pydantic au lieu de `str` :\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\nLa chaîne sera vérifiée comme URL valide et documentée comme telle dans JSON Schema / OpenAPI.\n\n## Attributs avec des listes de sous-modèles { #attributes-with-lists-of-submodels }\n\nVous pouvez également utiliser des modèles Pydantic comme sous-types de `list`, `set`, etc. :\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\nCela attendra (convertira, validera, documentera, etc.) un corps JSON comme :\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n/// info\n\nRemarquez que la clé `images` contient maintenant une liste d'objets image.\n\n///\n\n## Modèles profondément imbriqués { #deeply-nested-models }\n\nVous pouvez définir des modèles imbriqués à une profondeur arbitraire :\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info\n\nRemarquez que `Offer` a une liste d’`Item`, qui à leur tour ont une liste optionnelle d’`Image`.\n\n///\n\n## Corps de listes pures { #bodies-of-pure-lists }\n\nSi la valeur de premier niveau du corps JSON attendu est un `array` JSON (une `list` Python), vous pouvez déclarer le type dans le paramètre de la fonction, de la même manière que dans les modèles Pydantic :\n\n```Python\nimages: list[Image]\n```\n\ncomme :\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## Bénéficier de la prise en charge de l'éditeur partout { #editor-support-everywhere }\n\nEt vous bénéficiez de la prise en charge de l'éditeur partout.\n\nMême pour les éléments à l'intérieur des listes :\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\nVous ne pourriez pas obtenir ce type de prise en charge de l'éditeur si vous travailliez directement avec des `dict` au lieu de modèles Pydantic.\n\nMais vous n'avez pas à vous en soucier non plus, les `dict` entrants sont convertis automatiquement et votre sortie est également convertie automatiquement en JSON.\n\n## Corps de `dict` arbitraires { #bodies-of-arbitrary-dicts }\n\nVous pouvez également déclarer un corps comme un `dict` avec des clés d’un certain type et des valeurs d’un autre type.\n\nDe cette façon, vous n'avez pas besoin de savoir à l'avance quels sont les noms de champs/attributs valides (comme ce serait le cas avec des modèles Pydantic).\n\nCela serait utile si vous voulez recevoir des clés que vous ne connaissez pas à l'avance.\n\n---\n\nUn autre cas utile est lorsque vous souhaitez avoir des clés d'un autre type (par exemple `int`).\n\nC'est ce que nous allons voir ici.\n\nDans ce cas, vous accepteriez n'importe quel `dict` tant qu'il a des clés `int` avec des valeurs `float` :\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip | Astuce\n\nGardez à l'esprit que JSON ne prend en charge que des `str` comme clés.\n\nMais Pydantic dispose d'une conversion automatique des données.\n\nCela signifie que, même si vos clients d'API ne peuvent envoyer que des chaînes comme clés, tant que ces chaînes contiennent des entiers purs, Pydantic les convertira et les validera.\n\nEt le `dict` que vous recevez dans `weights` aura en réalité des clés `int` et des valeurs `float`.\n\n///\n\n## Récapitulatif { #recap }\n\nAvec FastAPI, vous bénéficiez de la flexibilité maximale fournie par les modèles Pydantic, tout en gardant votre code simple, concis et élégant.\n\nMais avec tous les avantages :\n\n- Prise en charge par l'éditeur (autocomplétion partout !)\n- Conversion des données (a.k.a. parsing / sérialisation)\n- Validation des données\n- Documentation des schémas\n- Documentation automatique\n"
  },
  {
    "path": "docs/fr/docs/tutorial/body-updates.md",
    "content": "# Corps - Mises à jour { #body-updates }\n\n## Mettre à jour en remplaçant avec `PUT` { #update-replacing-with-put }\n\nPour mettre à jour un élément, vous pouvez utiliser l’opération [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT).\n\nVous pouvez utiliser le `jsonable_encoder` pour convertir les données d’entrée en données pouvant être stockées au format JSON (par exemple, avec une base de données NoSQL). Par exemple, convertir `datetime` en `str`.\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\nOn utilise `PUT` pour recevoir des données qui doivent remplacer les données existantes.\n\n### Avertissement concernant le remplacement { #warning-about-replacing }\n\nCela signifie que si vous souhaitez mettre à jour l’élément `bar` avec `PUT` et un corps contenant :\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\ncomme il n’inclut pas l’attribut déjà enregistré « tax »: 20.2, le modèle d’entrée prendrait la valeur par défaut « tax »: 10.5.\n\nEt les données seraient enregistrées avec cette « nouvelle » « tax » de 10.5.\n\n## Effectuer des mises à jour partielles avec `PATCH` { #partial-updates-with-patch }\n\nVous pouvez également utiliser l’opération [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) pour mettre à jour des données de manière partielle.\n\nCela signifie que vous pouvez n’envoyer que les données que vous souhaitez mettre à jour, en laissant le reste intact.\n\n/// note | Remarque\n\n`PATCH` est moins utilisé et moins connu que `PUT`.\n\nEt de nombreuses équipes n’utilisent que `PUT`, même pour les mises à jour partielles.\n\nVous êtes libre de les utiliser comme vous le souhaitez, **FastAPI** n’impose aucune restriction.\n\nMais ce guide vous montre, plus ou moins, la façon dont ils sont censés être utilisés.\n\n///\n\n### Utiliser le paramètre `exclude_unset` de Pydantic { #using-pydantics-exclude-unset-parameter }\n\nSi vous souhaitez recevoir des mises à jour partielles, il est très utile d’utiliser le paramètre `exclude_unset` dans la méthode `.model_dump()` du modèle Pydantic.\n\nComme `item.model_dump(exclude_unset=True)`.\n\nCela génère un `dict` ne contenant que les données définies lors de la création du modèle `item`, en excluant les valeurs par défaut.\n\nVous pouvez ensuite l’utiliser pour produire un `dict` avec uniquement les données définies (envoyées dans la requête), en omettant les valeurs par défaut :\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### Utiliser le paramètre `update` de Pydantic { #using-pydantics-update-parameter }\n\nVous pouvez maintenant créer une copie du modèle existant avec `.model_copy()`, et passer le paramètre `update` avec un `dict` contenant les données à mettre à jour.\n\nComme `stored_item_model.model_copy(update=update_data)` :\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### Récapitulatif des mises à jour partielles { #partial-updates-recap }\n\nEn résumé, pour appliquer des mises à jour partielles, vous procédez ainsi :\n\n* (Optionnel) utilisez `PATCH` au lieu de `PUT`.\n* Récupérez les données stockées.\n* Placez ces données dans un modèle Pydantic.\n* Générez un `dict` sans valeurs par défaut à partir du modèle d’entrée (en utilisant `exclude_unset`).\n    * De cette façon, vous mettez à jour uniquement les valeurs effectivement définies par l’utilisateur, au lieu d’écraser des valeurs déjà stockées par des valeurs par défaut de votre modèle.\n* Créez une copie du modèle stocké, en mettant à jour ses attributs avec les mises à jour partielles reçues (en utilisant le paramètre `update`).\n* Convertissez le modèle copié en quelque chose qui peut être stocké dans votre base de données (par exemple en utilisant le `jsonable_encoder`).\n    * Cela est comparable à l’utilisation à nouveau de la méthode `.model_dump()` du modèle, mais cela vérifie (et convertit) les valeurs vers des types pouvant être convertis en JSON, par exemple `datetime` en `str`.\n* Enregistrez les données dans votre base de données.\n* Retournez le modèle mis à jour.\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | Astuce\n\nVous pouvez en réalité utiliser cette même technique avec une opération HTTP `PUT`.\n\nMais l’exemple ici utilise `PATCH` car il a été créé pour ces cas d’usage.\n\n///\n\n/// note | Remarque\n\nRemarquez que le modèle d’entrée est toujours validé.\n\nAinsi, si vous souhaitez recevoir des mises à jour partielles pouvant omettre tous les attributs, vous devez disposer d’un modèle avec tous les attributs marqués comme optionnels (avec des valeurs par défaut ou `None`).\n\nPour distinguer les modèles avec toutes les valeurs optionnelles pour les mises à jour et les modèles avec des valeurs requises pour la création, vous pouvez utiliser les idées décrites dans [Modèles supplémentaires](extra-models.md).\n\n///\n"
  },
  {
    "path": "docs/fr/docs/tutorial/body.md",
    "content": "# Corps de la requête { #request-body }\n\nQuand vous avez besoin d'envoyer de la donnée depuis un client (comme un navigateur) vers votre API, vous l'envoyez en tant que **corps de requête**.\n\nLe corps d'une **requête** est de la donnée envoyée par le client à votre API. Le corps d'une **réponse** est la donnée envoyée par votre API au client.\n\nVotre API aura presque toujours à envoyer un corps de **réponse**. Mais un client n'a pas toujours à envoyer un **corps de requête** : parfois il demande seulement un chemin, peut-être avec quelques paramètres de requête, mais n'envoie pas de corps.\n\nPour déclarer un corps de **requête**, on utilise les modèles de [Pydantic](https://docs.pydantic.dev/) en profitant de tous leurs avantages et fonctionnalités.\n\n/// info\n\nPour envoyer de la donnée, vous devez utiliser : `POST` (le plus populaire), `PUT`, `DELETE` ou `PATCH`.\n\nEnvoyer un corps dans une requête `GET` a un comportement non défini dans les spécifications, cela est néanmoins supporté par **FastAPI**, seulement pour des cas d'utilisation très complexes/extrêmes.\n\nCeci étant découragé, la documentation interactive générée par Swagger UI ne montrera pas de documentation pour le corps d'une requête `GET`, et les proxys intermédiaires risquent de ne pas le supporter.\n\n///\n\n## Importer le `BaseModel` de Pydantic { #import-pydantics-basemodel }\n\nCommencez par importer la classe `BaseModel` du module `pydantic` :\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## Créer votre modèle de données { #create-your-data-model }\n\nDéclarez ensuite votre modèle de données en tant que classe qui hérite de `BaseModel`.\n\nUtilisez les types Python standard pour tous les attributs :\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\nTout comme pour la déclaration de paramètres de requête, quand un attribut de modèle a une valeur par défaut, il n'est pas nécessaire. Sinon, il est requis. Utilisez `None` pour le rendre simplement optionnel.\n\nPar exemple, le modèle ci-dessus déclare un JSON « `object` » (ou `dict` Python) tel que :\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n... `description` et `tax` étant des attributs optionnels (avec `None` comme valeur par défaut), ce JSON « `object` » serait aussi valide :\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## Le déclarer comme paramètre { #declare-it-as-a-parameter }\n\nPour l'ajouter à votre *chemin d'accès*, déclarez-le comme vous déclareriez des paramètres de chemin ou de requête :\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n... et déclarez que son type est le modèle que vous avez créé : `Item`.\n\n## Résultats { #results }\n\nEn utilisant uniquement les déclarations de type Python, **FastAPI** réussit à :\n\n* Lire le contenu de la requête en tant que JSON.\n* Convertir les types correspondants (si nécessaire).\n* Valider la donnée.\n    * Si la donnée est invalide, une erreur propre et claire sera renvoyée, indiquant exactement où et quelle était la donnée incorrecte.\n* Passer la donnée reçue dans le paramètre `item`.\n    * Ce paramètre ayant été déclaré dans la fonction comme étant de type `Item`, vous aurez aussi tout le support offert par l'éditeur (autocomplétion, etc.) pour tous les attributs de ce paramètre et les types de ces attributs.\n* Générer des définitions [JSON Schema](https://json-schema.org) pour votre modèle ; vous pouvez également les utiliser partout ailleurs si cela a du sens pour votre projet.\n* Ces schémas participeront à la constitution du schéma généré OpenAPI, et seront utilisés par les documentations automatiques <abbr title=\"User Interfaces - Interfaces utilisateur\">UIs</abbr>.\n\n## Documentation automatique { #automatic-docs }\n\nLes schémas JSON de vos modèles seront intégrés au schéma OpenAPI global de votre application, et seront donc affichés dans la documentation interactive de l'API :\n\n<img src=\"/img/tutorial/body/image01.png\">\n\nEt seront aussi utilisés dans chaque *chemin d'accès* de la documentation utilisant ces modèles :\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## Support de l'éditeur { #editor-support }\n\nDans votre éditeur, vous aurez des annotations de type et de l'autocomplétion partout dans votre fonction (ce qui n'aurait pas été le cas si vous aviez reçu un `dict` plutôt qu'un modèle Pydantic) :\n\n<img src=\"/img/tutorial/body/image03.png\">\n\nEt vous obtenez aussi des vérifications d'erreurs pour les opérations de types incorrectes :\n\n<img src=\"/img/tutorial/body/image04.png\">\n\nCe n'est pas un hasard, ce framework entier a été bâti avec ce design comme objectif.\n\nEt cela a été rigoureusement testé durant la phase de design, avant toute implémentation, pour vous assurer que cela fonctionnerait avec tous les éditeurs.\n\nDes changements sur Pydantic ont même été faits pour supporter cela.\n\nLes captures d'écran précédentes ont été prises sur [Visual Studio Code](https://code.visualstudio.com).\n\nMais vous auriez le même support de l'éditeur avec [PyCharm](https://www.jetbrains.com/pycharm/) et la majorité des autres éditeurs de code Python :\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip | Astuce\n\nSi vous utilisez [PyCharm](https://www.jetbrains.com/pycharm/) comme éditeur, vous pouvez utiliser le plug-in [Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/).\n\nCe qui améliore le support pour les modèles Pydantic avec :\n\n* de l'autocomplétion\n* des vérifications de type\n* du « refactoring »\n* de la recherche\n* des inspections\n\n///\n\n## Utiliser le modèle { #use-the-model }\n\nDans la fonction, vous pouvez accéder à tous les attributs de l'objet du modèle directement :\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## Corps de la requête + paramètres de chemin { #request-body-path-parameters }\n\nVous pouvez déclarer des paramètres de chemin et un corps de requête pour la même *chemin d'accès*.\n\n**FastAPI** est capable de reconnaître que les paramètres de la fonction qui correspondent aux paramètres de chemin doivent être **récupérés depuis le chemin**, et que les paramètres de fonctions déclarés comme modèles Pydantic devraient être **récupérés depuis le corps de la requête**.\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n## Corps de la requête + paramètres de chemin et de requête { #request-body-path-query-parameters }\n\nVous pouvez aussi déclarer un **corps**, et des paramètres de **chemin** et de **requête** dans la même *chemin d'accès*.\n\n**FastAPI** saura reconnaître chacun d'entre eux et récupérer la bonne donnée au bon endroit.\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\nLes paramètres de la fonction seront reconnus comme tel :\n\n* Si le paramètre est aussi déclaré dans le **chemin**, il sera utilisé comme paramètre de chemin.\n* Si le paramètre est d'un **type singulier** (comme `int`, `float`, `str`, `bool`, etc.), il sera interprété comme un paramètre de **requête**.\n* Si le paramètre est déclaré comme ayant pour type un **modèle Pydantic**, il sera interprété comme faisant partie du **corps** de la requête.\n\n/// note | Remarque\n\n**FastAPI** saura que la valeur de `q` n'est pas requise grâce à la valeur par défaut `= None`.\n\nL'annotation de type `str | None` n'est pas utilisée par **FastAPI** pour déterminer que la valeur n'est pas requise, il le saura parce qu'elle a une valeur par défaut `= None`.\n\nMais ajouter ces annotations de type permettra à votre éditeur de vous offrir un meilleur support et de détecter des erreurs.\n\n///\n\n## Sans Pydantic { #without-pydantic }\n\nSi vous ne voulez pas utiliser des modèles Pydantic, vous pouvez aussi utiliser des paramètres de **Body**. Pour cela, allez voir la documentation sur [Corps de la requête - Paramètres multiples : Valeurs singulières dans le corps](body-multiple-params.md#singular-values-in-body).\n"
  },
  {
    "path": "docs/fr/docs/tutorial/cookie-param-models.md",
    "content": "# Modèles de paramètres de cookies { #cookie-parameter-models }\n\nSi vous avez un groupe de **cookies** liés, vous pouvez créer un **modèle Pydantic** pour les déclarer. 🍪\n\nCela vous permet de **réutiliser le modèle** à **plusieurs endroits** et aussi de déclarer des validations et des métadonnées pour tous les paramètres en une seule fois. 😎\n\n/// note | Remarque\n\nCeci est pris en charge depuis la version `0.115.0` de FastAPI. 🤓\n\n///\n\n/// tip | Astuce\n\nCette même technique s'applique à `Query`, `Cookie` et `Header`. 😎\n\n///\n\n## Déclarer des cookies avec un modèle Pydantic { #cookies-with-a-pydantic-model }\n\nDéclarez les paramètres de **cookie** dont vous avez besoin dans un **modèle Pydantic**, puis déclarez le paramètre comme `Cookie` :\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI** va **extraire** les données pour **chaque champ** à partir des **cookies** reçus dans la requête et vous fournir le modèle Pydantic que vous avez défini.\n\n## Consulter la documentation { #check-the-docs }\n\nVous pouvez voir les cookies définis dans l'interface de la documentation à `/docs` :\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info\n\nGardez à l'esprit que, comme les **navigateurs gèrent les cookies** de manière particulière et en arrière-plan, ils **n'autorisent pas** facilement **JavaScript** à y accéder.\n\nSi vous allez dans **l'interface de la documentation de l'API** à `/docs`, vous pourrez voir la **documentation** des cookies pour vos *chemins d'accès*.\n\nMais même si vous **remplissez les données** et cliquez sur « Execute », comme l'interface de la documentation fonctionne avec **JavaScript**, les cookies ne seront pas envoyés et vous verrez un **message d'erreur** comme si vous n'aviez saisi aucune valeur.\n\n///\n\n## Interdire les cookies supplémentaires { #forbid-extra-cookies }\n\nDans certains cas d'utilisation particuliers (probablement peu courants), vous pourriez vouloir **restreindre** les cookies que vous souhaitez recevoir.\n\nVotre API a désormais le pouvoir de contrôler son propre <dfn title=\"C'est une blague, au cas où. Cela n'a rien à voir avec les consentements aux cookies, mais c'est amusant que même l'API puisse maintenant rejeter les pauvres cookies. Prenez un cookie. 🍪\">consentement aux cookies</dfn>. 🤪🍪\n\nVous pouvez utiliser la configuration du modèle de Pydantic pour `forbid` tout champ `extra` :\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\nSi un client tente d'envoyer des **cookies supplémentaires**, il recevra une **réponse d'erreur**.\n\nPauvres bannières de cookies, avec tous leurs efforts pour obtenir votre consentement pour que l'<dfn title=\"C'est encore une blague. Ne faites pas attention à moi. Prenez un café avec votre cookie. ☕\">API pour le rejeter</dfn>. 🍪\n\nPar exemple, si le client tente d'envoyer un cookie `santa_tracker` avec la valeur `good-list-please`, il recevra une **réponse d'erreur** lui indiquant que le `santa_tracker` <dfn title=\"Le Père Noël désapprouve le manque de cookies. 🎅 D'accord, plus de blagues de cookies.\">le cookie n'est pas autorisé</dfn> :\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## Récapitulatif { #summary }\n\nVous pouvez utiliser des **modèles Pydantic** pour déclarer des <dfn title=\"Prenez un dernier cookie avant de partir. 🍪\">**cookies**</dfn> dans **FastAPI**. 😎\n"
  },
  {
    "path": "docs/fr/docs/tutorial/cookie-params.md",
    "content": "# Paramètres de cookie { #cookie-parameters }\n\nVous pouvez définir des paramètres de cookie de la même manière que vous définissez les paramètres `Query` et `Path`.\n\n## Importer `Cookie` { #import-cookie }\n\nCommencez par importer `Cookie` :\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## Déclarer des paramètres `Cookie` { #declare-cookie-parameters }\n\nDéclarez ensuite les paramètres de cookie en utilisant la même structure qu'avec `Path` et `Query`.\n\nVous pouvez définir la valeur par défaut ainsi que tous les paramètres supplémentaires de validation ou d'annotation :\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Détails techniques\n\n`Cookie` est une classe « sœur » de `Path` et `Query`. Elle hérite également de la même classe commune `Param`.\n\nMais rappelez-vous que lorsque vous importez `Query`, `Path`, `Cookie` et d'autres depuis `fastapi`, il s'agit en réalité de fonctions qui renvoient des classes spéciales.\n\n///\n\n/// info\n\nPour déclarer des cookies, vous devez utiliser `Cookie`, sinon les paramètres seraient interprétés comme des paramètres de requête.\n\n///\n\n/// info\n\nGardez à l'esprit que, comme **les navigateurs gèrent les cookies** de manière particulière et en coulisses, ils **n'autorisent pas** facilement **JavaScript** à y accéder.\n\nSi vous allez dans l'**interface de la documentation de l'API** à `/docs`, vous pourrez voir la **documentation** des cookies pour vos *chemins d'accès*.\n\nMais même si vous **renseignez les données** et cliquez sur « Execute », comme l'interface de documentation fonctionne avec **JavaScript**, les cookies ne seront pas envoyés et vous verrez un message **d'erreur** comme si vous n'aviez saisi aucune valeur.\n\n///\n\n## Récapitulatif { #recap }\n\nDéclarez les cookies avec `Cookie`, en utilisant le même schéma commun que `Query` et `Path`.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/cors.md",
    "content": "# CORS (Partage des ressources entre origines) { #cors-cross-origin-resource-sharing }\n\n[CORS ou « Cross-Origin Resource Sharing »](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) fait référence aux situations où un frontend exécuté dans un navigateur contient du code JavaScript qui communique avec un backend, et où le backend se trouve dans une « origine » différente de celle du frontend.\n\n## Origine { #origin }\n\nUne origine est la combinaison du protocole (`http`, `https`), du domaine (`myapp.com`, `localhost`, `localhost.tiangolo.com`) et du port (`80`, `443`, `8080`).\n\nAinsi, toutes celles-ci sont des origines différentes :\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\nMême si elles sont toutes sur `localhost`, elles utilisent des protocoles ou des ports différents, ce sont donc des « origines » différentes.\n\n## Étapes { #steps }\n\nDisons donc que vous avez un frontend exécuté dans votre navigateur à `http://localhost:8080`, et que son JavaScript essaie de communiquer avec un backend exécuté à `http://localhost` (comme nous ne spécifions pas de port, le navigateur supposera le port par défaut `80`).\n\nLe navigateur enverra alors une requête HTTP `OPTIONS` au backend `:80`, et si le backend envoie les en-têtes appropriés autorisant la communication depuis cette origine différente (`http://localhost:8080`), alors le navigateur `:8080` permettra au JavaScript du frontend d’envoyer sa requête au backend `:80`.\n\nPour y parvenir, le backend `:80` doit disposer d’une liste « d’origines autorisées ».\n\nDans ce cas, la liste devrait inclure `http://localhost:8080` pour que le frontend `:8080` fonctionne correctement.\n\n## Caractères génériques { #wildcards }\n\nIl est également possible de déclarer la liste comme « * » (un « wildcard ») pour indiquer que toutes sont autorisées.\n\nMais cela n’autorisera que certains types de communication, en excluant tout ce qui implique des informations d’identification : cookies, en-têtes Authorization comme ceux utilisés avec les Bearer Tokens, etc.\n\nAinsi, pour que tout fonctionne correctement, il est préférable d’indiquer explicitement les origines autorisées.\n\n## Utiliser `CORSMiddleware` { #use-corsmiddleware }\n\nVous pouvez le configurer dans votre application **FastAPI** à l’aide de `CORSMiddleware`.\n\n* Importer `CORSMiddleware`.\n* Créer une liste d’origines autorisées (sous forme de chaînes).\n* L’ajouter comme « middleware » à votre application **FastAPI**.\n\nVous pouvez également spécifier si votre backend autorise :\n\n* Les informations d’identification (en-têtes Authorization, cookies, etc.).\n* Des méthodes HTTP spécifiques (`POST`, `PUT`) ou toutes avec le caractère générique « * ».\n* Des en-têtes HTTP spécifiques ou tous avec le caractère générique « * ».\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\nLes paramètres utilisés par défaut par l’implémentation de `CORSMiddleware` sont restrictifs, vous devez donc activer explicitement des origines, méthodes ou en-têtes particuliers afin que les navigateurs soient autorisés à les utiliser dans un contexte inter‑domaine.\n\nLes arguments suivants sont pris en charge :\n\n* `allow_origins` - Une liste d’origines autorisées à effectuer des requêtes cross-origin. Par ex. `['https://example.org', 'https://www.example.org']`. Vous pouvez utiliser `['*']` pour autoriser n’importe quelle origine.\n* `allow_origin_regex` - Une chaîne regex pour faire correspondre les origines autorisées à effectuer des requêtes cross-origin. Par ex. `'https://.*\\.example\\.org'`.\n* `allow_methods` - Une liste de méthodes HTTP qui doivent être autorisées pour les requêtes cross-origin. Par défaut `['GET']`. Vous pouvez utiliser `['*']` pour autoriser toutes les méthodes standard.\n* `allow_headers` - Une liste d’en-têtes HTTP de requête qui doivent être pris en charge pour les requêtes cross-origin. Par défaut `[]`. Vous pouvez utiliser `['*']` pour autoriser tous les en-têtes. Les en-têtes `Accept`, `Accept-Language`, `Content-Language` et `Content-Type` sont toujours autorisés pour les [requêtes CORS simples](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).\n* `allow_credentials` - Indique que les cookies doivent être pris en charge pour les requêtes cross-origin. Par défaut `False`.\n\n    Aucun de `allow_origins`, `allow_methods` et `allow_headers` ne peut être défini à `['*']` si `allow_credentials` est défini à `True`. Ils doivent tous être [spécifiés explicitement](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards).\n\n* `expose_headers` - Indique les en-têtes de réponse qui doivent être accessibles au navigateur. Par défaut `[]`.\n* `max_age` - Définit un temps maximum (en secondes) pendant lequel les navigateurs peuvent mettre en cache les réponses CORS. Par défaut `600`.\n\nLe middleware répond à deux types particuliers de requêtes HTTP ...\n\n### Requêtes CORS de pré‑vérification { #cors-preflight-requests }\n\nIl s’agit de toute requête `OPTIONS` avec les en-têtes `Origin` et `Access-Control-Request-Method`.\n\nDans ce cas, le middleware interceptera la requête entrante et répondra avec les en-têtes CORS appropriés, et soit une réponse `200`, soit `400` à titre informatif.\n\n### Requêtes simples { #simple-requests }\n\nToute requête avec un en-tête `Origin`. Dans ce cas, le middleware laissera passer la requête normalement, mais inclura les en-têtes CORS appropriés dans la réponse.\n\n## En savoir plus { #more-info }\n\nPour plus d’informations sur <abbr title=\"Cross-Origin Resource Sharing - Partage des ressources entre origines\">CORS</abbr>, consultez la [documentation CORS de Mozilla](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).\n\n/// note | Détails techniques\n\nVous pouvez également utiliser `from starlette.middleware.cors import CORSMiddleware`.\n\n**FastAPI** fournit plusieurs middlewares dans `fastapi.middleware` uniquement pour votre confort, en tant que développeur. Mais la plupart des middlewares disponibles proviennent directement de Starlette.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/tutorial/debugging.md",
    "content": "# <abbr title=\"En anglais: Debugging\">Débogage</abbr> { #debugging }\n\nVous pouvez connecter le <abbr title=\"En anglais: debugger\">débogueur</abbr> dans votre éditeur, par exemple avec Visual Studio Code ou PyCharm.\n\n## Appeler `uvicorn` { #call-uvicorn }\n\nDans votre application FastAPI, importez et exécutez directement `uvicorn` :\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### À propos de `__name__ == \"__main__\"` { #about-name-main }\n\nLe but principal de `__name__ == \"__main__\"` est d'avoir du code qui est exécuté lorsque votre fichier est appelé avec :\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nmais qui n'est pas appelé lorsqu'un autre fichier l'importe, comme dans :\n\n```Python\nfrom myapp import app\n```\n\n#### Pour davantage de détails { #more-details }\n\nImaginons que votre fichier s'appelle `myapp.py`.\n\nSi vous l'exécutez avec :\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nalors la variable interne `__name__` de votre fichier, créée automatiquement par Python, aura pour valeur la chaîne de caractères `\"__main__\"`.\n\nAinsi, la section :\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nva s'exécuter.\n\n---\n\nCela ne se produira pas si vous importez ce module (fichier).\n\nPar exemple, si vous avez un autre fichier `importer.py` qui contient :\n\n```Python\nfrom myapp import app\n\n# Code supplémentaire\n```\n\ndans ce cas, la variable automatique `__name__` à l'intérieur de `myapp.py` n'aura pas la valeur `\"__main__\"`.\n\nAinsi, la ligne :\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nne sera pas exécutée.\n\n/// info\n\nPour plus d'informations, consultez [la documentation officielle de Python](https://docs.python.org/3/library/__main__.html).\n\n///\n\n## Exécuter votre code avec votre <abbr title=\"En anglais: debugger\">débogueur</abbr> { #run-your-code-with-your-debugger }\n\nParce que vous exécutez le serveur Uvicorn directement depuis votre code, vous pouvez appeler votre programme Python (votre application FastAPI) directement depuis le <abbr title=\"En anglais: debugger\">débogueur</abbr>.\n\n---\n\nPar exemple, dans Visual Studio Code, vous pouvez :\n\n- Allez dans le panneau « Debug ».\n- « Add configuration ... ».\n- Sélectionnez « Python ».\n- Lancez le <abbr title=\"En anglais: debugger\">débogueur</abbr> avec l'option « Python: Current File (Integrated Terminal) ».\n\nIl démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.\n\nVoici à quoi cela pourrait ressembler :\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\nSi vous utilisez Pycharm, vous pouvez :\n\n- Ouvrez le menu « Run ».\n- Sélectionnez l'option « Debug ... ».\n- Un menu contextuel s'affiche alors.\n- Sélectionnez le fichier à déboguer (dans ce cas, `main.py`).\n\nIl démarrera alors le serveur avec votre code **FastAPI**, s'arrêtera à vos points d'arrêt, etc.\n\nVoici à quoi cela pourrait ressembler :\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/fr/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# Utiliser des classes comme dépendances { #classes-as-dependencies }\n\nAvant d'aller plus loin dans le système d'**Injection de dépendances**, mettons à niveau l'exemple précédent.\n\n## Un `dict` de l'exemple précédent { #a-dict-from-the-previous-example }\n\nDans l'exemple précédent, nous renvoyions un `dict` depuis notre dépendance (« dependable ») :\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\nMais nous recevons alors un `dict` dans le paramètre `commons` de la fonction de chemin d'accès.\n\nEt les éditeurs ne peuvent pas apporter beaucoup d'assistance (comme l'autocomplétion) pour les `dict`, car ils ne peuvent pas connaître leurs clés ni les types de valeurs.\n\nNous pouvons faire mieux ...\n\n## Ce qui fait d'un objet une dépendance { #what-makes-a-dependency }\n\nJusqu'à présent, vous avez vu des dépendances déclarées sous forme de fonctions.\n\nMais ce n'est pas la seule manière de déclarer des dépendances (même si c'est probablement la plus courante).\n\nL'élément clé est qu'une dépendance doit être un « callable ».\n\nUn « callable » en Python est tout ce que Python peut « appeler » comme une fonction.\n\nAinsi, si vous avez un objet `something` (qui n'est peut‑être pas une fonction) et que vous pouvez « l'appeler » (l'exécuter) comme :\n\n```Python\nsomething()\n```\n\nou\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\nalors c'est un « callable ».\n\n## Utiliser des classes comme dépendances { #classes-as-dependencies_1 }\n\nVous remarquerez que pour créer une instance d'une classe Python, vous utilisez la même syntaxe.\n\nPar exemple :\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\nDans ce cas, `fluffy` est une instance de la classe `Cat`.\n\nEt pour créer `fluffy`, vous « appelez » `Cat`.\n\nDonc, une classe Python est aussi un « callable ».\n\nAinsi, avec **FastAPI**, vous pouvez utiliser une classe Python comme dépendance.\n\nCe que **FastAPI** vérifie réellement, c'est qu'il s'agit d'un « callable » (fonction, classe ou autre) et des paramètres qui y sont définis.\n\nSi vous passez un « callable » comme dépendance dans **FastAPI**, il en analysera les paramètres et les traitera de la même manière que les paramètres d'une fonction de chemin d'accès. Y compris les sous‑dépendances.\n\nCela s'applique également aux callables sans aucun paramètre. Comme ce serait le cas pour des fonctions de chemin d'accès sans paramètres.\n\nNous pouvons alors remplacer la dépendance « dependable » `common_parameters` ci‑dessus par la classe `CommonQueryParams` :\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\nFaites attention à la méthode `__init__` utilisée pour créer l'instance de la classe :\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n... il a les mêmes paramètres que notre précédent `common_parameters` :\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\nCe sont ces paramètres que **FastAPI** utilisera pour « résoudre » la dépendance.\n\nDans les deux cas, il y aura :\n\n- Un paramètre de requête optionnel `q` qui est un `str`.\n- Un paramètre de requête `skip` qui est un `int`, avec une valeur par défaut de `0`.\n- Un paramètre de requête `limit` qui est un `int`, avec une valeur par défaut de `100`.\n\nDans les deux cas, les données seront converties, validées, documentées dans le schéma OpenAPI, etc.\n\n## Utiliser { #use-it }\n\nVous pouvez maintenant déclarer votre dépendance en utilisant cette classe.\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI** appelle la classe `CommonQueryParams`. Cela crée une « instance » de cette classe et l'instance sera passée comme paramètre `commons` à votre fonction.\n\n## Annotation de type vs `Depends` { #type-annotation-vs-depends }\n\nRemarquez que nous écrivons `CommonQueryParams` deux fois dans le code ci‑dessus :\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ sans Annotated\n\n/// tip | Astuce\n\nPrivilégiez la version avec `Annotated` si possible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\nLe dernier `CommonQueryParams`, dans :\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n... est ce que **FastAPI** utilisera réellement pour savoir quelle est la dépendance.\n\nC'est à partir de celui‑ci que FastAPI extraira les paramètres déclarés et c'est ce que FastAPI appellera effectivement.\n\n---\n\nDans ce cas, le premier `CommonQueryParams`, dans :\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ sans Annotated\n\n/// tip | Astuce\n\nPrivilégiez la version avec `Annotated` si possible.\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n... n'a aucune signification particulière pour **FastAPI**. FastAPI ne l'utilisera pas pour la conversion des données, la validation, etc. (car il utilise `Depends(CommonQueryParams)` pour cela).\n\nVous pourriez en fait écrire simplement :\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ sans Annotated\n\n/// tip | Astuce\n\nPrivilégiez la version avec `Annotated` si possible.\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n... comme dans :\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\nMais il est recommandé de déclarer le type ; ainsi, votre éditeur saura ce qui sera passé comme paramètre `commons`, et pourra vous aider avec l'autocomplétion, les vérifications de type, etc. :\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## Raccourci { #shortcut }\n\nMais vous voyez qu'il y a ici de la duplication de code : nous écrivons `CommonQueryParams` deux fois :\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ sans Annotated\n\n/// tip | Astuce\n\nPrivilégiez la version avec `Annotated` si possible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n**FastAPI** fournit un raccourci pour ces cas, lorsque la dépendance est spécifiquement une classe que **FastAPI** va « appeler » pour créer une instance de la classe elle‑même.\n\nPour ces cas précis, vous pouvez faire ce qui suit :\n\nAu lieu d'écrire :\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ sans Annotated\n\n/// tip | Astuce\n\nPrivilégiez la version avec `Annotated` si possible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n... vous écrivez :\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ sans Annotated\n\n/// tip | Astuce\n\nPrivilégiez la version avec `Annotated` si possible.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\nVous déclarez la dépendance comme type du paramètre et vous utilisez `Depends()` sans aucun paramètre, au lieu d'avoir à réécrire la classe entière à l'intérieur de `Depends(CommonQueryParams)`.\n\nLe même exemple ressemblerait alors à ceci :\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n... et **FastAPI** saura quoi faire.\n\n/// tip | Astuce\n\nSi cela vous semble plus déroutant qu'utile, ignorez‑le, vous n'en avez pas besoin.\n\nCe n'est qu'un raccourci. Parce que **FastAPI** tient à vous aider à minimiser la duplication de code.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# Gérer les dépendances dans les décorateurs de chemins d'accès { #dependencies-in-path-operation-decorators }\n\nDans certains cas, vous n'avez pas vraiment besoin de la valeur de retour d'une dépendance dans votre *fonction de chemin d'accès*.\n\nOu la dépendance ne retourne aucune valeur.\n\nMais vous avez quand même besoin qu'elle soit exécutée/résolue.\n\nDans ces cas, au lieu de déclarer un paramètre de *fonction de chemin d'accès* avec `Depends`, vous pouvez ajouter une `list` de `dependencies` au *décorateur de chemin d'accès*.\n\n## Ajouter `dependencies` au *décorateur de chemin d'accès* { #add-dependencies-to-the-path-operation-decorator }\n\nLe *décorateur de chemin d'accès* accepte un argument optionnel `dependencies`.\n\nIl doit s'agir d'une `list` de `Depends()` :\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\nCes dépendances seront exécutées/résolues de la même manière que des dépendances normales. Mais leur valeur (si elles en retournent une) ne sera pas transmise à votre *fonction de chemin d'accès*.\n\n/// tip | Astuce\n\nCertains éditeurs vérifient les paramètres de fonction non utilisés et les signalent comme des erreurs.\n\nEn utilisant ces `dependencies` dans le *décorateur de chemin d'accès*, vous pouvez vous assurer qu'elles sont exécutées tout en évitant des erreurs de l'éditeur/des outils.\n\nCela peut également éviter toute confusion pour les nouveaux développeurs qui voient un paramètre inutilisé dans votre code et pourraient penser qu'il est superflu.\n\n///\n\n/// info | Info\n\nDans cet exemple, nous utilisons des en-têtes personnalisés fictifs `X-Key` et `X-Token`.\n\nMais dans des cas réels, lors de l'implémentation de la sécurité, vous tirerez davantage d'avantages en utilisant les [utilitaires de sécurité (chapitre suivant)](../security/index.md) intégrés.\n\n///\n\n## Gérer les erreurs et les valeurs de retour des dépendances { #dependencies-errors-and-return-values }\n\nVous pouvez utiliser les mêmes *fonctions* de dépendance que d'habitude.\n\n### Définir les exigences des dépendances { #dependency-requirements }\n\nElles peuvent déclarer des exigences pour la requête (comme des en-têtes) ou d'autres sous-dépendances :\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### Lever des exceptions { #raise-exceptions }\n\nCes dépendances peuvent `raise` des exceptions, comme des dépendances normales :\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### Gérer les valeurs de retour { #return-values }\n\nElles peuvent retourner des valeurs ou non, ces valeurs ne seront pas utilisées.\n\nVous pouvez donc réutiliser une dépendance normale (qui retourne une valeur) que vous utilisez déjà ailleurs ; même si la valeur n'est pas utilisée, la dépendance sera exécutée :\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## Définir des dépendances pour un groupe de chemins d'accès { #dependencies-for-a-group-of-path-operations }\n\nPlus tard, en lisant comment structurer des applications plus grandes ([Applications plus grandes - Plusieurs fichiers](../../tutorial/bigger-applications.md)), éventuellement avec plusieurs fichiers, vous apprendrez à déclarer un unique paramètre `dependencies` pour un groupe de *chemins d'accès*.\n\n## Définir des dépendances globales { #global-dependencies }\n\nEnsuite, nous verrons comment ajouter des dépendances à l'application `FastAPI` entière, afin qu'elles s'appliquent à chaque *chemin d'accès*.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# Utiliser des dépendances avec `yield` { #dependencies-with-yield }\n\nFastAPI prend en charge des dépendances qui effectuent des <dfn title='parfois aussi appelées « exit code », « cleanup code », « teardown code », « closing code », « context manager exit code », etc.'>étapes supplémentaires après l'exécution</dfn>.\n\nPour cela, utilisez `yield` au lieu de `return`, et écrivez les étapes supplémentaires (code) après.\n\n/// tip | Astuce\n\nVous devez vous assurer d'utiliser `yield` une seule fois par dépendance.\n\n///\n\n/// note | Détails techniques\n\nToute fonction valide à utiliser avec :\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) ou\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nsera valide comme dépendance **FastAPI**.\n\nEn fait, FastAPI utilise ces deux décorateurs en interne.\n\n///\n\n## Créer une dépendance de base de données avec `yield` { #a-database-dependency-with-yield }\n\nPar exemple, vous pouvez l'utiliser pour créer une session de base de données et la fermer après la fin.\n\nSeul le code précédant et incluant l'instruction `yield` est exécuté avant la création de la réponse :\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\nLa valeur transmise par `yield` est celle qui est injectée dans les *chemins d'accès* et autres dépendances :\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\nLe code suivant l'instruction `yield` est exécuté après la réponse :\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip | Astuce\n\nVous pouvez utiliser des fonctions `async` ou des fonctions classiques.\n\n**FastAPI** fera ce qu'il faut dans chaque cas, comme avec des dépendances normales.\n\n///\n\n## Créer une dépendance avec `yield` et `try` { #a-dependency-with-yield-and-try }\n\nSi vous utilisez un bloc `try` dans une dépendance avec `yield`, vous recevrez toute exception qui a été levée lors de l'utilisation de la dépendance.\n\nPar exemple, si à un moment donné, dans une autre dépendance ou dans un *chemin d'accès*, un code a effectué un « rollback » de transaction de base de données ou a créé une autre exception, vous recevrez l'exception dans votre dépendance.\n\nVous pouvez donc rechercher cette exception spécifique dans la dépendance avec `except SomeException`.\n\nDe la même manière, vous pouvez utiliser `finally` pour vous assurer que les étapes de sortie sont exécutées, qu'il y ait eu une exception ou non.\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## Utiliser des sous-dépendances avec `yield` { #sub-dependencies-with-yield }\n\nVous pouvez avoir des sous-dépendances et des « arbres » de sous-dépendances de toute taille et forme, et certaines ou toutes peuvent utiliser `yield`.\n\n**FastAPI** s'assurera que le « code de sortie » dans chaque dépendance avec `yield` est exécuté dans le bon ordre.\n\nPar exemple, `dependency_c` peut dépendre de `dependency_b`, et `dependency_b` de `dependency_a` :\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\nEt elles peuvent toutes utiliser `yield`.\n\nDans ce cas, `dependency_c`, pour exécuter son code de sortie, a besoin que la valeur de `dependency_b` (appelée ici `dep_b`) soit toujours disponible.\n\nEt, à son tour, `dependency_b` a besoin que la valeur de `dependency_a` (appelée ici `dep_a`) soit disponible pour son code de sortie.\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\nDe la même manière, vous pouvez avoir certaines dépendances avec `yield` et d'autres avec `return`, et faire en sorte que certaines dépendent des autres.\n\nEt vous pouvez avoir une seule dépendance qui exige plusieurs autres dépendances avec `yield`, etc.\n\nVous pouvez combiner les dépendances comme vous le souhaitez.\n\n**FastAPI** s'assurera que tout est exécuté dans le bon ordre.\n\n/// note | Détails techniques\n\nCela fonctionne grâce aux [gestionnaires de contexte](https://docs.python.org/3/library/contextlib.html) de Python.\n\n**FastAPI** les utilise en interne pour y parvenir.\n\n///\n\n## Utiliser des dépendances avec `yield` et `HTTPException` { #dependencies-with-yield-and-httpexception }\n\nVous avez vu que vous pouvez utiliser des dépendances avec `yield` et avoir des blocs `try` qui tentent d'exécuter du code puis exécutent du code de sortie après `finally`.\n\nVous pouvez également utiliser `except` pour intercepter l'exception qui a été levée et faire quelque chose avec.\n\nPar exemple, vous pouvez lever une autre exception, comme `HTTPException`.\n\n/// tip | Astuce\n\nC'est une technique plutôt avancée, et dans la plupart des cas vous n'en aurez pas vraiment besoin, car vous pouvez lever des exceptions (y compris `HTTPException`) depuis le reste de votre code applicatif, par exemple, dans la *fonction de chemin d'accès*.\n\nMais elle est à votre disposition si vous en avez besoin. 🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\nSi vous souhaitez intercepter des exceptions et créer une réponse personnalisée en fonction de cela, créez un [Gestionnaire d'exceptions personnalisé](../handling-errors.md#install-custom-exception-handlers).\n\n## Utiliser des dépendances avec `yield` et `except` { #dependencies-with-yield-and-except }\n\nSi vous interceptez une exception avec `except` dans une dépendance avec `yield` et que vous ne la relancez pas (ou que vous ne levez pas une nouvelle exception), FastAPI ne pourra pas remarquer qu'il y a eu une exception, de la même manière que cela se produirait avec Python classique :\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\nDans ce cas, le client verra une réponse *HTTP 500 Internal Server Error* comme il se doit, étant donné que nous ne levons pas de `HTTPException` ou similaire, mais le serveur **n'aura aucun logs** ni aucune autre indication de l'erreur. 😱\n\n### Toujours `raise` dans les dépendances avec `yield` et `except` { #always-raise-in-dependencies-with-yield-and-except }\n\nSi vous interceptez une exception dans une dépendance avec `yield`, à moins de lever une autre `HTTPException` ou similaire, **vous devez relancer l'exception d'origine**.\n\nVous pouvez relancer la même exception avec `raise` :\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\nÀ présent, le client recevra la même réponse *HTTP 500 Internal Server Error*, mais le serveur aura notre `InternalError` personnalisé dans les logs. 😎\n\n## Comprendre l'exécution des dépendances avec `yield` { #execution-of-dependencies-with-yield }\n\nLa séquence d'exécution ressemble plus ou moins à ce diagramme. Le temps s'écoule de haut en bas. Et chaque colonne représente une des parties qui interagit ou exécute du code.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exception handler\nparticipant dep as Dep with yield\nparticipant operation as Path Operation\nparticipant tasks as Background tasks\n\n    Note over client,operation: Can raise exceptions, including HTTPException\n    client ->> dep: Start request\n    Note over dep: Run code up to yield\n    opt raise Exception\n        dep -->> handler: Raise Exception\n        handler -->> client: HTTP error response\n    end\n    dep ->> operation: Run dependency, e.g. DB session\n    opt raise\n        operation -->> dep: Raise Exception (e.g. HTTPException)\n        opt handle\n            dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception\n        end\n        handler -->> client: HTTP error response\n    end\n\n    operation ->> client: Return response to client\n    Note over client,operation: Response is already sent, can't change it anymore\n    opt Tasks\n        operation -->> tasks: Send background tasks\n    end\n    opt Raise other exception\n        tasks -->> tasks: Handle exceptions in the background task code\n    end\n```\n\n/// info\n\nUne **seule réponse** sera envoyée au client. Il peut s'agir d'une des réponses d'erreur ou de la réponse provenant du *chemin d'accès*.\n\nAprès l'envoi de l'une de ces réponses, aucune autre réponse ne peut être envoyée.\n\n///\n\n/// tip | Astuce\n\nSi vous levez une exception dans le code de la *fonction de chemin d'accès*, elle sera transmise aux dépendances avec `yield`, y compris `HTTPException`. Dans la plupart des cas, vous voudrez relancer cette même exception ou en lever une nouvelle depuis la dépendance avec `yield` pour vous assurer qu'elle est correctement gérée.\n\n///\n\n## Utiliser la sortie anticipée et `scope` { #early-exit-and-scope }\n\nNormalement, le code de sortie des dépendances avec `yield` est exécuté **après la réponse** envoyée au client.\n\nMais si vous savez que vous n'aurez pas besoin d'utiliser la dépendance après être revenu de la *fonction de chemin d'accès*, vous pouvez utiliser `Depends(scope=\"function\")` pour indiquer à FastAPI qu'il doit fermer la dépendance après le retour de la *fonction de chemin d'accès*, mais **avant** que la **réponse ne soit envoyée**.\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()` reçoit un paramètre `scope` qui peut être :\n\n* « function » : démarrer la dépendance avant la *fonction de chemin d'accès* qui gère la requête, terminer la dépendance après la fin de la *fonction de chemin d'accès*, mais **avant** que la réponse ne soit renvoyée au client. Ainsi, la fonction de dépendance sera exécutée **autour** de la *fonction de chemin d'accès*.\n* « request » : démarrer la dépendance avant la *fonction de chemin d'accès* qui gère la requête (similaire à l'utilisation de « function »), mais terminer **après** que la réponse a été renvoyée au client. Ainsi, la fonction de dépendance sera exécutée **autour** du cycle **requête** et réponse.\n\nS'il n'est pas spécifié et que la dépendance utilise `yield`, le `scope` sera par défaut « request ».\n\n### Définir `scope` pour les sous-dépendances { #scope-for-sub-dependencies }\n\nLorsque vous déclarez une dépendance avec un `scope=\"request\"` (par défaut), toute sous-dépendance doit également avoir un `scope` de « request ».\n\nMais une dépendance avec un `scope` de « function » peut avoir des dépendances avec un `scope` de « function » et un `scope` de « request ».\n\nCela vient du fait que toute dépendance doit pouvoir exécuter son code de sortie avant ses sous-dépendances, car elle pourrait encore avoir besoin de les utiliser pendant son code de sortie.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Dep scope=\"request\"\nparticipant dep_func as Dep scope=\"function\"\nparticipant operation as Path Operation\n\n    client ->> dep_req: Start request\n    Note over dep_req: Run code up to yield\n    dep_req ->> dep_func: Pass dependency\n    Note over dep_func: Run code up to yield\n    dep_func ->> operation: Run path operation with dependency\n    operation ->> dep_func: Return from path operation\n    Note over dep_func: Run code after yield\n    Note over dep_func: ✅ Dependency closed\n    dep_func ->> client: Send response to client\n    Note over client: Response sent\n    Note over dep_req: Run code after yield\n    Note over dep_req: ✅ Dependency closed\n```\n\n## Utiliser des dépendances avec `yield`, `HTTPException`, `except` et Background Tasks { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\nLes dépendances avec `yield` ont évolué au fil du temps pour couvrir différents cas d'utilisation et corriger certains problèmes.\n\nSi vous souhaitez voir ce qui a changé dans différentes versions de FastAPI, vous pouvez en savoir plus dans le guide avancé, dans [Dépendances avancées - Dépendances avec `yield`, `HTTPException`, `except` et Background Tasks](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).\n## Gestionnaires de contexte { #context-managers }\n\n### Que sont les « Context Managers » { #what-are-context-managers }\n\nLes « Context Managers » sont des objets Python que vous pouvez utiliser dans une instruction `with`.\n\nPar exemple, [vous pouvez utiliser `with` pour lire un fichier](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files) :\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\nEn coulisse, `open(\"./somefile.txt\")` crée un objet appelé « Context Manager ».\n\nLorsque le bloc `with` se termine, il s'assure de fermer le fichier, même s'il y a eu des exceptions.\n\nLorsque vous créez une dépendance avec `yield`, **FastAPI** créera en interne un gestionnaire de contexte pour celle-ci et le combinera avec d'autres outils associés.\n\n### Utiliser des gestionnaires de contexte dans des dépendances avec `yield` { #using-context-managers-in-dependencies-with-yield }\n\n/// warning | Alertes\n\nC'est, plus ou moins, une idée « avancée ».\n\nSi vous débutez avec **FastAPI**, vous voudrez peut-être l'ignorer pour le moment.\n\n///\n\nEn Python, vous pouvez créer des gestionnaires de contexte en [créant une classe avec deux méthodes : `__enter__()` et `__exit__()`](https://docs.python.org/3/reference/datamodel.html#context-managers).\n\nVous pouvez également les utiliser dans des dépendances **FastAPI** avec `yield` en utilisant\ndes instructions `with` ou `async with` à l'intérieur de la fonction de dépendance :\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip | Astuce\n\nUne autre façon de créer un gestionnaire de contexte consiste à utiliser :\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) ou\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\npour décorer une fonction avec un unique `yield`.\n\nC'est ce que **FastAPI** utilise en interne pour les dépendances avec `yield`.\n\nMais vous n'avez pas à utiliser ces décorateurs pour les dépendances FastAPI (et vous ne devriez pas).\n\nFastAPI le fera pour vous en interne.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# Dépendances globales { #global-dependencies }\n\nPour certains types d'applications, vous pourriez vouloir ajouter des dépendances à l'application entière.\n\nComme vous pouvez [ajouter des `dependencies` aux *décorateurs de chemin d'accès*](dependencies-in-path-operation-decorators.md), vous pouvez les ajouter à l'application `FastAPI`.\n\nDans ce cas, elles seront appliquées à tous les *chemins d'accès* de l'application :\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\nEt toutes les idées de la section sur [l'ajout de `dependencies` aux *décorateurs de chemin d'accès*](dependencies-in-path-operation-decorators.md) s'appliquent toujours, mais dans ce cas à tous les *chemins d'accès* de l'application.\n\n## Dépendances pour des groupes de *chemins d'accès* { #dependencies-for-groups-of-path-operations }\n\nPlus tard, en lisant comment structurer des applications plus grandes ([Applications plus grandes - Plusieurs fichiers](../../tutorial/bigger-applications.md)), éventuellement avec plusieurs fichiers, vous apprendrez comment déclarer un unique paramètre `dependencies` pour un groupe de *chemins d'accès*.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/dependencies/index.md",
    "content": "# Dépendances { #dependencies }\n\n**FastAPI** dispose d’un système d’**<dfn title=\"aussi connu sous le nom de : composants, ressources, fournisseurs, services, injectables\">Injection de dépendances</dfn>** très puissant mais intuitif.\n\nIl est conçu pour être très simple à utiliser, et pour faciliter l’intégration d’autres composants à **FastAPI** pour n’importe quel développeur.\n\n## Qu’est-ce que « l’injection de dépendances » { #what-is-dependency-injection }\n\nL’**« injection de dépendances »** signifie, en programmation, qu’il existe un moyen pour votre code (dans ce cas, vos fonctions de chemins d’accès) de déclarer ce dont il a besoin pour fonctionner et utiliser : « dépendances ».\n\nEnsuite, ce système (dans ce cas **FastAPI**) se charge de faire tout le nécessaire pour fournir à votre code ces dépendances requises (« injecter » les dépendances).\n\nC’est très utile lorsque vous avez besoin de :\n\n* Avoir de la logique partagée (la même logique de code encore et encore).\n* Partager des connexions à la base de données.\n* Imposer la sécurité, l’authentification, des exigences de rôles, etc.\n* Et bien d’autres choses ...\n\nTout cela, en minimisant la répétition de code.\n\n## Premiers pas { #first-steps }\n\nVoyons un exemple très simple. Il sera tellement simple qu’il n’est pas très utile, pour l’instant.\n\nMais de cette façon nous pouvons nous concentrer sur le fonctionnement du système d’**injection de dépendances**.\n\n### Créer une dépendance, ou « dependable » { #create-a-dependency-or-dependable }\n\nConcentrons-nous d’abord sur la dépendance.\n\nC’est simplement une fonction qui peut prendre tous les mêmes paramètres qu’une fonction de chemin d’accès peut prendre :\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\nC’est tout.\n\n**2 lignes**.\n\nEt elle a la même forme et structure que toutes vos fonctions de chemins d’accès.\n\nVous pouvez la considérer comme une fonction de chemin d’accès sans le « décorateur » (sans le `@app.get(\"/some-path\")`).\n\nEt elle peut retourner tout ce que vous voulez.\n\nDans ce cas, cette dépendance attend :\n\n* Un paramètre de requête optionnel `q` qui est une `str`.\n* Un paramètre de requête optionnel `skip` qui est un `int`, et vaut `0` par défaut.\n* Un paramètre de requête optionnel `limit` qui est un `int`, et vaut `100` par défaut.\n\nPuis elle retourne simplement un `dict` contenant ces valeurs.\n\n/// info\n\nFastAPI a ajouté la prise en charge de `Annotated` (et a commencé à le recommander) dans la version 0.95.0.\n\nSi vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d’utiliser `Annotated`.\n\nVous devez vous assurer de [mettre à niveau la version de FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions) vers au moins la 0.95.1 avant d’utiliser `Annotated`.\n\n///\n\n### Importer `Depends` { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### Déclarer la dépendance, dans le « dependant » { #declare-the-dependency-in-the-dependant }\n\nDe la même manière que vous utilisez `Body`, `Query`, etc. avec les paramètres de votre fonction de chemin d’accès, utilisez `Depends` avec un nouveau paramètre :\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\nMême si vous utilisez `Depends` dans les paramètres de votre fonction de la même façon que `Body`, `Query`, etc., `Depends` fonctionne un peu différemment.\n\nVous ne donnez à `Depends` qu’un seul paramètre.\n\nCe paramètre doit être quelque chose comme une fonction.\n\nVous ne l’appelez pas directement (n’ajoutez pas de parenthèses à la fin), vous le passez simplement en paramètre à `Depends()`.\n\nEt cette fonction prend des paramètres de la même manière que les fonctions de chemins d’accès.\n\n/// tip | Astuce\n\nVous verrez quelles autres « choses », en plus des fonctions, peuvent être utilisées comme dépendances dans le prochain chapitre.\n\n///\n\nChaque fois qu’une nouvelle requête arrive, **FastAPI** se charge de :\n\n* Appeler votre fonction de dépendance (« dependable ») avec les bons paramètres.\n* Récupérer le résultat de votre fonction.\n* Affecter ce résultat au paramètre dans votre fonction de chemin d’accès.\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\nDe cette façon vous écrivez le code partagé une seule fois et **FastAPI** se charge de l’appeler pour vos chemins d’accès.\n\n/// check | Vérifications\n\nNotez que vous n’avez pas à créer une classe spéciale et à la passer quelque part à **FastAPI** pour l’« enregistrer » ou quoi que ce soit de similaire.\n\nVous la passez simplement à `Depends` et **FastAPI** sait faire le reste.\n\n///\n\n## Partager des dépendances `Annotated` { #share-annotated-dependencies }\n\nDans les exemples ci-dessus, vous voyez qu’il y a un tout petit peu de **duplication de code**.\n\nLorsque vous devez utiliser la dépendance `common_parameters()`, vous devez écrire tout le paramètre avec l’annotation de type et `Depends()` :\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\nMais comme nous utilisons `Annotated`, nous pouvons stocker cette valeur `Annotated` dans une variable et l’utiliser à plusieurs endroits :\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | Astuce\n\nC’est simplement du Python standard, cela s’appelle un « alias de type », ce n’est en fait pas spécifique à **FastAPI**.\n\nMais comme **FastAPI** est basé sur les standards Python, y compris `Annotated`, vous pouvez utiliser cette astuce dans votre code. 😎\n\n///\n\nLes dépendances continueront de fonctionner comme prévu, et la **meilleure partie** est que **l’information de type sera conservée**, ce qui signifie que votre éditeur pourra continuer à vous fournir **l’autocomplétion**, **des erreurs en ligne**, etc. Idem pour d’autres outils comme `mypy`.\n\nCela sera particulièrement utile lorsque vous l’utiliserez dans une **grande base de code** où vous utilisez **les mêmes dépendances** encore et encore dans **de nombreux chemins d’accès**.\n\n## Utiliser `async` ou non { #to-async-or-not-to-async }\n\nComme les dépendances seront aussi appelées par **FastAPI** (tout comme vos fonctions de chemins d’accès), les mêmes règles s’appliquent lors de la définition de vos fonctions.\n\nVous pouvez utiliser `async def` ou un `def` normal.\n\nEt vous pouvez déclarer des dépendances avec `async def` à l’intérieur de fonctions de chemins d’accès `def` normales, ou des dépendances `def` à l’intérieur de fonctions de chemins d’accès `async def`, etc.\n\nPeu importe. **FastAPI** saura quoi faire.\n\n/// note | Remarque\n\nSi vous ne savez pas, consultez la section [Async : *« Pressé ? »*](../../async.md#in-a-hurry) à propos de `async` et `await` dans la documentation.\n\n///\n\n## Intégrer à OpenAPI { #integrated-with-openapi }\n\nToutes les déclarations de requête, validations et exigences de vos dépendances (et sous-dépendances) seront intégrées dans le même schéma OpenAPI.\n\nAinsi, la documentation interactive contiendra aussi toutes les informations issues de ces dépendances :\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## Utilisation simple { #simple-usage }\n\nSi vous y regardez de près, les fonctions de chemins d’accès sont déclarées pour être utilisées chaque fois qu’un « chemin » et une « opération » correspondent, puis **FastAPI** se charge d’appeler la fonction avec les bons paramètres, en extrayant les données de la requête.\n\nEn réalité, tous (ou la plupart) des frameworks web fonctionnent de cette manière.\n\nVous n’appelez jamais ces fonctions directement. Elles sont appelées par votre framework (dans ce cas, **FastAPI**).\n\nAvec le système d’injection de dépendances, vous pouvez aussi indiquer à **FastAPI** que votre fonction de chemin d’accès « dépend » également d’autre chose qui doit être exécuté avant votre fonction de chemin d’accès, et **FastAPI** se chargera de l’exécuter et d’« injecter » les résultats.\n\nD’autres termes courants pour cette même idée « d’injection de dépendances » sont :\n\n* ressources\n* fournisseurs\n* services\n* injectables\n* composants\n\n## Plug-ins **FastAPI** { #fastapi-plug-ins }\n\nLes intégrations et « plug-ins » peuvent être construits en utilisant le système d’**injection de dépendances**. Mais en réalité, il n’y a **pas besoin de créer des « plug-ins »**, car en utilisant des dépendances il est possible de déclarer un nombre infini d’intégrations et d’interactions qui deviennent disponibles pour vos fonctions de chemins d’accès.\n\nEt les dépendances peuvent être créées de manière très simple et intuitive, ce qui vous permet d’importer juste les packages Python dont vous avez besoin, et de les intégrer à vos fonctions d’API en quelques lignes de code, *littéralement*.\n\nVous verrez des exemples de cela dans les prochains chapitres, à propos des bases de données relationnelles et NoSQL, de la sécurité, etc.\n\n## Compatibilité **FastAPI** { #fastapi-compatibility }\n\nLa simplicité du système d’injection de dépendances rend **FastAPI** compatible avec :\n\n* toutes les bases de données relationnelles\n* les bases de données NoSQL\n* les packages externes\n* les API externes\n* les systèmes d’authentification et d’autorisation\n* les systèmes de supervision d’usage d’API\n* les systèmes d’injection de données de réponse\n* etc.\n\n## Simple et puissant { #simple-and-powerful }\n\nBien que le système hiérarchique d’injection de dépendances soit très simple à définir et à utiliser, il reste très puissant.\n\nVous pouvez définir des dépendances qui, à leur tour, peuvent définir leurs propres dépendances.\n\nAu final, un arbre hiérarchique de dépendances est construit, et le système d’**injection de dépendances** se charge de résoudre toutes ces dépendances pour vous (et leurs sous-dépendances) et de fournir (injecter) les résultats à chaque étape.\n\nPar exemple, supposons que vous ayez 4 endpoints d’API (chemins d’accès) :\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\nalors vous pourriez ajouter différentes exigences d’autorisations pour chacun d’eux uniquement avec des dépendances et des sous-dépendances :\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## Intégrer à **OpenAPI** { #integrated-with-openapi_1 }\n\nToutes ces dépendances, tout en déclarant leurs exigences, ajoutent également des paramètres, des validations, etc. à vos chemins d’accès.\n\n**FastAPI** se chargera d’ajouter le tout au schéma OpenAPI, afin que cela apparaisse dans les systèmes de documentation interactive.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# Sous-dépendances { #sub-dependencies }\n\nVous pouvez créer des dépendances qui ont des sous-dépendances.\n\nElles peuvent être aussi profondes que nécessaire.\n\n**FastAPI** se chargera de les résoudre.\n\n## Créer une première dépendance « dependable » { #first-dependency-dependable }\n\nVous pouvez créer une première dépendance (« dependable ») comme :\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\nElle déclare un paramètre de requête optionnel `q` de type `str`, puis le retourne simplement.\n\nC'est assez simple (pas très utile), mais cela nous aidera à nous concentrer sur le fonctionnement des sous-dépendances.\n\n## Créer une seconde dépendance, « dependable » et « dependant » { #second-dependency-dependable-and-dependant }\n\nVous pouvez ensuite créer une autre fonction de dépendance (un « dependable ») qui, en même temps, déclare sa propre dépendance (elle est donc aussi un « dependant ») :\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\nConcentrons-nous sur les paramètres déclarés :\n\n- Même si cette fonction est elle‑même une dépendance (« dependable »), elle déclare aussi une autre dépendance (elle « dépend » d'autre chose).\n    - Elle dépend de `query_extractor` et affecte la valeur renvoyée au paramètre `q`.\n- Elle déclare également un cookie `last_query` optionnel, de type `str`.\n    - Si l'utilisateur n'a fourni aucune requête `q`, nous utilisons la dernière requête utilisée, que nous avons enregistrée auparavant dans un cookie.\n\n## Utiliser la dépendance { #use-the-dependency }\n\nNous pouvons ensuite utiliser la dépendance avec :\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info\n\nNotez que nous ne déclarons qu'une seule dépendance dans la *fonction de chemin d'accès*, `query_or_cookie_extractor`.\n\nMais **FastAPI** saura qu'il doit d'abord résoudre `query_extractor`, pour passer ses résultats à `query_or_cookie_extractor` lors de son appel.\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## Utiliser la même dépendance plusieurs fois { #using-the-same-dependency-multiple-times }\n\nSi l'une de vos dépendances est déclarée plusieurs fois pour le même *chemin d'accès*, par exemple si plusieurs dépendances ont une sous-dépendance commune, **FastAPI** saura n'appeler cette sous-dépendance qu'une seule fois par requête.\n\nEt il enregistrera la valeur renvoyée dans un <dfn title=\"Un utilitaire/système pour stocker des valeurs calculées/générées, afin de les réutiliser au lieu de les recalculer.\">« cache »</dfn> et la transmettra à tous les « dependants » qui en ont besoin dans cette requête spécifique, au lieu d'appeler la dépendance plusieurs fois pour la même requête.\n\nDans un scénario avancé où vous savez que vous avez besoin que la dépendance soit appelée à chaque étape (éventuellement plusieurs fois) dans la même requête au lieu d'utiliser la valeur « mise en cache », vous pouvez définir le paramètre `use_cache=False` lors de l'utilisation de `Depends` :\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ non annoté\n\n/// tip | Astuce\n\nPrivilégiez la version `Annotated` si possible.\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## Récapituler { #recap }\n\nEn dehors de tout le jargon utilisé ici, le système d'**injection de dépendances** est assez simple.\n\nCe ne sont que des fonctions qui ressemblent aux *fonctions de chemin d'accès*.\n\nMais il est très puissant et vous permet de déclarer des « graphes » (arbres) de dépendances imbriquées aussi profondément que vous le souhaitez.\n\n/// tip | Astuce\n\nTout cela peut ne pas sembler très utile avec ces exemples simples.\n\nMais vous verrez à quel point c'est utile dans les chapitres sur la **sécurité**.\n\nEt vous verrez aussi la quantité de code que cela vous fera économiser.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/tutorial/encoder.md",
    "content": "# Encodeur compatible JSON { #json-compatible-encoder }\n\nIl existe des cas où vous pourriez avoir besoin de convertir un type de données (comme un modèle Pydantic) en quelque chose de compatible avec JSON (comme un `dict`, `list`, etc.).\n\nPar exemple, si vous devez le stocker dans une base de données.\n\nPour cela, **FastAPI** fournit une fonction `jsonable_encoder()`.\n\n## Utiliser `jsonable_encoder` { #using-the-jsonable-encoder }\n\nImaginons que vous ayez une base de données `fake_db` qui ne reçoit que des données compatibles JSON.\n\nPar exemple, elle ne reçoit pas d'objets `datetime`, car ceux-ci ne sont pas compatibles avec JSON.\n\nAinsi, un objet `datetime` doit être converti en une `str` contenant les données au [format ISO](https://en.wikipedia.org/wiki/ISO_8601).\n\nDe la même manière, cette base de données n'accepterait pas un modèle Pydantic (un objet avec des attributs), seulement un `dict`.\n\nVous pouvez utiliser `jsonable_encoder` pour cela.\n\nElle reçoit un objet, comme un modèle Pydantic, et renvoie une version compatible JSON :\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\nDans cet exemple, elle convertirait le modèle Pydantic en `dict`, et le `datetime` en `str`.\n\nLe résultat de son appel est quelque chose qui peut être encodé avec la fonction standard de Python [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps).\n\nElle ne renvoie pas une grande `str` contenant les données au format JSON (sous forme de chaîne). Elle renvoie une structure de données standard de Python (par ex. un `dict`) avec des valeurs et sous-valeurs toutes compatibles avec JSON.\n\n/// note | Remarque\n\n`jsonable_encoder` est en fait utilisée par **FastAPI** en interne pour convertir des données. Mais elle est utile dans de nombreux autres scénarios.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/tutorial/extra-data-types.md",
    "content": "# Types de données supplémentaires { #extra-data-types }\n\nJusqu'à présent, vous avez utilisé des types de données courants, comme :\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\nMais vous pouvez aussi utiliser des types de données plus complexes.\n\nEt vous bénéficierez toujours des mêmes fonctionnalités que jusqu'à présent :\n\n* Excellente prise en charge dans l'éditeur.\n* Conversion des données à partir des requêtes entrantes.\n* Conversion des données pour les données de réponse.\n* Validation des données.\n* Annotations et documentation automatiques.\n\n## Autres types de données { #other-data-types }\n\nVoici quelques types de données supplémentaires que vous pouvez utiliser :\n\n* `UUID` :\n    * Un « identifiant universel unique » standard, couramment utilisé comme ID dans de nombreuses bases de données et systèmes.\n    * Dans les requêtes et les réponses, il sera représenté sous forme de `str`.\n* `datetime.datetime` :\n    * Un `datetime.datetime` Python.\n    * Dans les requêtes et les réponses, il sera représenté sous forme de `str` au format ISO 8601, par exemple : `2008-09-15T15:53:00+05:00`.\n* `datetime.date` :\n    * `datetime.date` Python.\n    * Dans les requêtes et les réponses, il sera représenté sous forme de `str` au format ISO 8601, par exemple : `2008-09-15`.\n* `datetime.time` :\n    * Un `datetime.time` Python.\n    * Dans les requêtes et les réponses, il sera représenté sous forme de `str` au format ISO 8601, par exemple : `14:23:55.003`.\n* `datetime.timedelta` :\n    * Un `datetime.timedelta` Python.\n    * Dans les requêtes et les réponses, il sera représenté sous forme de `float` de secondes totales.\n    * Pydantic permet aussi de le représenter sous la forme d'un « encodage de différence de temps ISO 8601 », [voir la documentation pour plus d'informations](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).\n* `frozenset` :\n    * Dans les requêtes et les réponses, traité de la même manière qu'un `set` :\n        * Dans les requêtes, une liste sera lue, les doublons éliminés, puis convertie en `set`.\n        * Dans les réponses, le `set` sera converti en `list`.\n        * Le schéma généré indiquera que les valeurs du `set` sont uniques (en utilisant `uniqueItems` de JSON Schema).\n* `bytes` :\n    * `bytes` Python standard.\n    * Dans les requêtes et les réponses, traité comme une `str`.\n    * Le schéma généré indiquera qu'il s'agit d'une `str` avec le « format » `binary`.\n* `Decimal` :\n    * `Decimal` Python standard.\n    * Dans les requêtes et les réponses, géré de la même manière qu'un `float`.\n* Vous pouvez consulter tous les types de données Pydantic valides ici : [Types de données Pydantic](https://docs.pydantic.dev/latest/usage/types/types/).\n\n## Exemple { #example }\n\nVoici un exemple de *chemin d'accès* avec des paramètres utilisant certains des types ci-dessus.\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\nNotez que les paramètres à l'intérieur de la fonction ont leur type de données naturel et que vous pouvez, par exemple, effectuer des manipulations de dates normales, comme :\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/fr/docs/tutorial/extra-models.md",
    "content": "# Modèles supplémentaires { #extra-models }\n\nEn poursuivant l'exemple précédent, il est courant d'avoir plusieurs modèles liés.\n\nC'est particulièrement vrai pour les modèles d'utilisateur, car :\n\n* Le modèle d'entrée doit pouvoir contenir un mot de passe.\n* Le modèle de sortie ne doit pas avoir de mot de passe.\n* Le modèle de base de données devra probablement avoir un mot de passe haché.\n\n/// danger | Danger\n\nNe stockez jamais les mots de passe des utilisateurs en clair. Stockez toujours un « hachage sécurisé » que vous pourrez ensuite vérifier.\n\nSi vous ne savez pas ce que c'est, vous apprendrez ce qu'est un « hachage de mot de passe » dans les [chapitres sur la sécurité](security/simple-oauth2.md#password-hashing).\n\n///\n\n## Utiliser plusieurs modèles { #multiple-models }\n\nVoici une idée générale de l'apparence des modèles avec leurs champs de mot de passe et les endroits où ils sont utilisés :\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### À propos de `**user_in.model_dump()` { #about-user-in-model-dump }\n\n#### La méthode `.model_dump()` de Pydantic { #pydantics-model-dump }\n\n`user_in` est un modèle Pydantic de classe `UserIn`.\n\nLes modèles Pydantic ont une méthode `.model_dump()` qui renvoie un `dict` avec les données du modèle.\n\nAinsi, si nous créons un objet Pydantic `user_in` comme :\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\net que nous appelons ensuite :\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\nnous avons maintenant un `dict` avec les données dans la variable `user_dict` (c'est un `dict` au lieu d'un objet modèle Pydantic).\n\nEt si nous appelons :\n\n```Python\nprint(user_dict)\n```\n\nnous obtiendrions un `dict` Python contenant :\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### Déballer un `dict` { #unpacking-a-dict }\n\nSi nous prenons un `dict` comme `user_dict` et que nous le passons à une fonction (ou une classe) avec `**user_dict`, Python va « déballer » ce `dict`. Il passera les clés et valeurs de `user_dict` directement comme arguments nommés.\n\nAinsi, en reprenant `user_dict` ci-dessus, écrire :\n\n```Python\nUserInDB(**user_dict)\n```\n\naurait pour résultat quelque chose d'équivalent à :\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\nOu plus exactement, en utilisant `user_dict` directement, quels que soient ses contenus futurs :\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### Créer un modèle Pydantic à partir du contenu d'un autre { #a-pydantic-model-from-the-contents-of-another }\n\nComme dans l'exemple ci-dessus nous avons obtenu `user_dict` depuis `user_in.model_dump()`, ce code :\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\nserait équivalent à :\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n... parce que `user_in.model_dump()` est un `dict`, et nous demandons ensuite à Python de « déballer » ce `dict` en le passant à `UserInDB` précédé de `**`.\n\nAinsi, nous obtenons un modèle Pydantic à partir des données d'un autre modèle Pydantic.\n\n#### Déballer un `dict` et ajouter des mots-clés supplémentaires { #unpacking-a-dict-and-extra-keywords }\n\nEt en ajoutant ensuite l'argument nommé supplémentaire `hashed_password=hashed_password`, comme ici :\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n... revient à :\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning | Alertes\n\nLes fonctions auxiliaires `fake_password_hasher` et `fake_save_user` ne servent qu'à démontrer un flux de données possible, mais elles n'offrent évidemment aucune sécurité réelle.\n\n///\n\n## Réduire la duplication { #reduce-duplication }\n\nRéduire la duplication de code est l'une des idées centrales de **FastAPI**.\n\nLa duplication de code augmente les risques de bogues, de problèmes de sécurité, de désynchronisation du code (lorsque vous mettez à jour un endroit mais pas les autres), etc.\n\nEt ces modèles partagent beaucoup de données et dupliquent des noms et types d'attributs.\n\nNous pouvons faire mieux.\n\nNous pouvons déclarer un modèle `UserBase` qui sert de base à nos autres modèles. Ensuite, nous pouvons créer des sous-classes de ce modèle qui héritent de ses attributs (déclarations de type, validation, etc.).\n\nToutes les conversions de données, validations, documentation, etc., fonctionneront comme d'habitude.\n\nDe cette façon, nous pouvons ne déclarer que les différences entre les modèles (avec `password` en clair, avec `hashed_password` et sans mot de passe) :\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` ou `anyOf` { #union-or-anyof }\n\nVous pouvez déclarer qu'une réponse est l'`Union` de deux types ou plus, ce qui signifie que la réponse peut être n'importe lequel d'entre eux.\n\nCela sera défini dans OpenAPI avec `anyOf`.\n\nPour ce faire, utilisez l'annotation de type Python standard [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union) :\n\n/// note | Remarque\n\nLors de la définition d'une [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions), incluez d'abord le type le plus spécifique, suivi du type le moins spécifique. Dans l'exemple ci-dessous, le type le plus spécifique `PlaneItem` précède `CarItem` dans `Union[PlaneItem, CarItem]`.\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### `Union` en Python 3.10 { #union-in-python-3-10 }\n\nDans cet exemple, nous passons `Union[PlaneItem, CarItem]` comme valeur de l'argument `response_model`.\n\nComme nous le passons comme valeur d'un argument au lieu de l'utiliser dans une annotation de type, nous devons utiliser `Union` même en Python 3.10.\n\nS'il s'agissait d'une annotation de type, nous pourrions utiliser la barre verticale, comme :\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\nMais si nous écrivons cela dans l'affectation `response_model=PlaneItem | CarItem`, nous obtiendrons une erreur, car Python essaierait d'effectuer une « opération invalide » entre `PlaneItem` et `CarItem` au lieu de l'interpréter comme une annotation de type.\n\n## Liste de modèles { #list-of-models }\n\nDe la même manière, vous pouvez déclarer des réponses contenant des listes d'objets.\n\nPour cela, utilisez le `list` Python standard :\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## Réponse avec un `dict` arbitraire { #response-with-arbitrary-dict }\n\nVous pouvez également déclarer une réponse en utilisant un simple `dict` arbitraire, en déclarant uniquement le type des clés et des valeurs, sans utiliser de modèle Pydantic.\n\nC'est utile si vous ne connaissez pas à l'avance les noms de champs/attributs valides (qui seraient nécessaires pour un modèle Pydantic).\n\nDans ce cas, vous pouvez utiliser `dict` :\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## Récapitulatif { #recap }\n\nUtilisez plusieurs modèles Pydantic et héritez librement selon chaque cas.\n\nVous n'avez pas besoin d'avoir un seul modèle de données par entité si cette entité doit pouvoir avoir différents « états ». Comme pour l'« entité » utilisateur, avec un état incluant `password`, `password_hash` et sans mot de passe.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/first-steps.md",
    "content": "# Démarrer { #first-steps }\n\nLe fichier **FastAPI** le plus simple possible pourrait ressembler à ceci :\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\nCopiez cela dans un fichier `main.py`.\n\nDémarrez le serveur en direct :\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nDans la sortie, il y a une ligne semblable à :\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\nCette ligne montre l’URL où votre application est servie, sur votre machine locale.\n\n### Vérifier { #check-it }\n\nOuvrez votre navigateur à l’adresse [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nVous verrez la réponse JSON suivante :\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### Documentation interactive de l’API { #interactive-api-docs }\n\nAllez maintenant sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVous verrez la documentation interactive de l’API générée automatiquement (fournie par [Swagger UI](https://github.com/swagger-api/swagger-ui)) :\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Documentation alternative de l’API { #alternative-api-docs }\n\nEt maintenant, allez sur [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nVous verrez la documentation automatique alternative (fournie par [ReDoc](https://github.com/Rebilly/ReDoc)) :\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI** génère un « schéma » contenant toute votre API en utilisant le standard **OpenAPI** pour définir des API.\n\n#### « Schéma » { #schema }\n\nUn « schéma » est une définition ou une description de quelque chose. Pas le code qui l’implémente, mais uniquement une description abstraite.\n\n#### « Schéma » d’API { #api-schema }\n\nIci, [OpenAPI](https://github.com/OAI/OpenAPI-Specification) est une spécification qui dicte comment définir le schéma de votre API.\n\nCette définition de schéma inclut les chemins de votre API, les paramètres possibles qu’ils prennent, etc.\n\n#### « Schéma » de données { #data-schema }\n\nLe terme « schéma » peut également faire référence à la forme d’une donnée, comme un contenu JSON.\n\nDans ce cas, cela désignerait les attributs JSON, ainsi que leurs types, etc.\n\n#### OpenAPI et JSON Schema { #openapi-and-json-schema }\n\nOpenAPI définit un schéma d’API pour votre API. Et ce schéma inclut des définitions (ou « schémas ») des données envoyées et reçues par votre API en utilisant **JSON Schema**, le standard pour les schémas de données JSON.\n\n#### Voir le `openapi.json` { #check-the-openapi-json }\n\nSi vous êtes curieux de voir à quoi ressemble le schéma OpenAPI brut, FastAPI génère automatiquement un JSON (schéma) avec les descriptions de toute votre API.\n\nVous pouvez le voir directement à l’adresse : [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).\n\nIl affichera un JSON commençant par quelque chose comme :\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### À quoi sert OpenAPI { #what-is-openapi-for }\n\nLe schéma OpenAPI est ce qui alimente les deux systèmes de documentation interactive inclus.\n\nEt il existe des dizaines d’alternatives, toutes basées sur OpenAPI. Vous pourriez facilement ajouter n’importe laquelle de ces alternatives à votre application construite avec **FastAPI**.\n\nVous pourriez également l’utiliser pour générer du code automatiquement, pour les clients qui communiquent avec votre API. Par exemple, des applications frontend, mobiles ou IoT.\n\n### Configurer le `entrypoint` de l’application dans `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nVous pouvez configurer l’emplacement de votre application dans un fichier `pyproject.toml` comme :\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nCe `entrypoint` indiquera à la commande `fastapi` qu’elle doit importer l’application comme :\n\n```python\nfrom main import app\n```\n\nSi votre code est structuré comme :\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nAlors vous définiriez le `entrypoint` comme :\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nce qui équivaudrait à :\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` avec un chemin { #fastapi-dev-with-path }\n\nVous pouvez également passer le chemin du fichier à la commande `fastapi dev`, et elle devinera l’objet d’application FastAPI à utiliser :\n\n```console\n$ fastapi dev main.py\n```\n\nMais vous devrez vous souvenir de passer le chemin correct à chaque exécution de la commande `fastapi`.\n\nDe plus, d’autres outils pourraient ne pas être capables de le trouver, par exemple l’[Extension VS Code](../editor-support.md) ou [FastAPI Cloud](https://fastapicloud.com), il est donc recommandé d’utiliser le `entrypoint` dans `pyproject.toml`.\n\n### Déployer votre application (optionnel) { #deploy-your-app-optional }\n\nVous pouvez, si vous le souhaitez, déployer votre application FastAPI sur [FastAPI Cloud](https://fastapicloud.com), allez rejoindre la liste d’attente si ce n’est pas déjà fait. 🚀\n\nSi vous avez déjà un compte **FastAPI Cloud** (nous vous avons invité depuis la liste d’attente 😉), vous pouvez déployer votre application avec une seule commande.\n\nAvant de déployer, vous devez vous assurer que vous êtes connecté :\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\nPuis déployez votre application :\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nC’est tout ! Vous pouvez maintenant accéder à votre application à cette URL. ✨\n\n## Récapitulatif, étape par étape { #recap-step-by-step }\n\n### Étape 1 : importer `FastAPI` { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI` est une classe Python qui fournit toutes les fonctionnalités nécessaires à votre API.\n\n/// note | Détails techniques\n\n`FastAPI` est une classe qui hérite directement de `Starlette`.\n\nVous pouvez donc aussi utiliser toutes les fonctionnalités de [Starlette](https://www.starlette.dev/) avec `FastAPI`.\n\n///\n\n### Étape 2 : créer une « instance » `FastAPI` { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\nIci, la variable `app` sera une « instance » de la classe `FastAPI`.\n\nCe sera le point principal d’interaction pour créer toute votre API.\n\n### Étape 3 : créer un « chemin d’accès » { #step-3-create-a-path-operation }\n\n#### Chemin { #path }\n\n« Chemin » fait ici référence à la dernière partie de l’URL à partir du premier `/`.\n\nDonc, dans une URL telle que :\n\n```\nhttps://example.com/items/foo\n```\n\n... le chemin serait :\n\n```\n/items/foo\n```\n\n/// info\n\nUn « chemin » est aussi couramment appelé « endpoint » ou « route ».\n\n///\n\nLors de la création d’une API, le « chemin » est la manière principale de séparer les « préoccupations » et les « ressources ».\n\n#### Opération { #operation }\n\n« Opération » fait ici référence à l’une des « méthodes » HTTP.\n\nL’une de :\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n... et les plus exotiques :\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\nDans le protocole HTTP, vous pouvez communiquer avec chaque chemin en utilisant une (ou plusieurs) de ces « méthodes ».\n\n---\n\nEn construisant des APIs, vous utilisez normalement ces méthodes HTTP spécifiques pour effectuer une action précise.\n\nEn général, vous utilisez :\n\n* `POST` : pour créer des données.\n* `GET` : pour lire des données.\n* `PUT` : pour mettre à jour des données.\n* `DELETE` : pour supprimer des données.\n\nDonc, dans OpenAPI, chacune des méthodes HTTP est appelée une « opération ».\n\nNous allons donc aussi les appeler « opérations ».\n\n#### Définir un « décorateur de chemin d’accès » { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\nLe `@app.get(\"/\")` indique à **FastAPI** que la fonction juste en dessous est chargée de gérer les requêtes qui vont vers :\n\n* le chemin `/`\n* en utilisant une <dfn title=\"une méthode HTTP GET\"><code>get</code> opération</dfn>\n\n/// info | `@decorator` Info\n\nCette syntaxe `@something` en Python est appelée un « décorateur ».\n\nVous la mettez au-dessus d’une fonction. Comme un joli chapeau décoratif (j’imagine que c’est de là que vient le terme 🤷🏻‍♂).\n\nUn « décorateur » prend la fonction en dessous et fait quelque chose avec.\n\nDans notre cas, ce décorateur indique à **FastAPI** que la fonction en dessous correspond au **chemin** `/` avec une **opération** `get`.\n\nC’est le « décorateur de chemin d’accès ».\n\n///\n\nVous pouvez aussi utiliser les autres opérations :\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\nAinsi que les plus exotiques :\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip | Astuce\n\nVous êtes libre d’utiliser chaque opération (méthode HTTP) comme vous le souhaitez.\n\n**FastAPI** n’impose aucune signification spécifique.\n\nLes informations ici sont présentées comme des lignes directrices, pas comme une obligation.\n\nPar exemple, lorsque vous utilisez GraphQL, vous effectuez normalement toutes les actions en utilisant uniquement des opérations `POST`.\n\n///\n\n### Étape 4 : définir la **fonction de chemin d’accès** { #step-4-define-the-path-operation-function }\n\nVoici notre « fonction de chemin d’accès » :\n\n* **chemin** : `/`.\n* **opération** : `get`.\n* **fonction** : la fonction sous le « décorateur » (sous `@app.get(\"/\")`).\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\nC’est une fonction Python.\n\nElle sera appelée par **FastAPI** chaque fois qu’il recevra une requête vers l’URL « / » en utilisant une opération `GET`.\n\nDans ce cas, c’est une fonction `async`.\n\n---\n\nVous pouvez aussi la définir comme une fonction normale au lieu de `async def` :\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note | Remarque\n\nSi vous ne connaissez pas la différence, consultez [Asynchrone : « Pressé ? »](../async.md#in-a-hurry).\n\n///\n\n### Étape 5 : retourner le contenu { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\nVous pouvez retourner un `dict`, une `list`, des valeurs uniques comme `str`, `int`, etc.\n\nVous pouvez également retourner des modèles Pydantic (vous en verrez plus à ce sujet plus tard).\n\nIl existe de nombreux autres objets et modèles qui seront automatiquement convertis en JSON (y compris des ORM, etc.). Essayez d’utiliser vos favoris, il est fort probable qu’ils soient déjà pris en charge.\n\n### Étape 6 : le déployer { #step-6-deploy-it }\n\nDéployez votre application sur **[FastAPI Cloud](https://fastapicloud.com)** avec une seule commande : `fastapi deploy`. 🎉\n\n#### À propos de FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** est construit par le même auteur et l’équipe derrière **FastAPI**.\n\nIl simplifie le processus de **construction**, de **déploiement** et d’**accès** à une API avec un minimum d’effort.\n\nIl apporte la même **expérience développeur** de création d’applications avec FastAPI au **déploiement** dans le cloud. 🎉\n\nFastAPI Cloud est le sponsor principal et le financeur des projets open source *FastAPI and friends*. ✨\n\n#### Déployer sur d’autres fournisseurs cloud { #deploy-to-other-cloud-providers }\n\nFastAPI est open source et basé sur des standards. Vous pouvez déployer des applications FastAPI chez n’importe quel fournisseur cloud de votre choix.\n\nSuivez les guides de votre fournisseur cloud pour y déployer des applications FastAPI. 🤓\n\n## Récapitulatif { #recap }\n\n* Importez `FastAPI`.\n* Créez une instance `app`.\n* Écrivez un **décorateur de chemin d’accès** avec des décorateurs comme `@app.get(\"/\")`.\n* Définissez une **fonction de chemin d’accès** ; par exemple, `def root(): ...`.\n* Exécutez le serveur de développement avec la commande `fastapi dev`.\n* Déployez éventuellement votre application avec `fastapi deploy`.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/handling-errors.md",
    "content": "# Gérer les erreurs { #handling-errors }\n\nIl existe de nombreuses situations où vous devez signaler une erreur à un client qui utilise votre API.\n\nCe client peut être un navigateur avec un frontend, un code d'un tiers, un appareil IoT, etc.\n\nVous pourriez avoir besoin d'indiquer au client que :\n\n* Le client n'a pas les privilèges suffisants pour cette opération.\n* Le client n'a pas accès à cette ressource.\n* L'élément auquel le client tentait d'accéder n'existe pas.\n* etc.\n\nDans ces cas, vous retournez normalement un **code d'état HTTP** dans la plage de **400** (de 400 à 499).\n\nC'est similaire aux codes d'état HTTP 200 (de 200 à 299). Ces codes « 200 » signifient que, d'une certaine manière, la requête a été un « succès ».\n\nLes codes d'état dans la plage des 400 signifient qu'il y a eu une erreur côté client.\n\nVous souvenez-vous de toutes ces erreurs **« 404 Not Found »** (et des blagues) ?\n\n## Utiliser `HTTPException` { #use-httpexception }\n\nPour renvoyer au client des réponses HTTP avec des erreurs, vous utilisez `HTTPException`.\n\n### Importer `HTTPException` { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### Lever une `HTTPException` dans votre code { #raise-an-httpexception-in-your-code }\n\n`HTTPException` est une exception Python normale avec des données supplémentaires pertinentes pour les API.\n\nComme il s'agit d'une exception Python, vous ne la `return` pas, vous la `raise`.\n\nCela signifie aussi que si vous êtes dans une fonction utilitaire appelée depuis votre fonction de chemin d'accès, et que vous levez la `HTTPException` à l'intérieur de cette fonction utilitaire, le reste du code de la fonction de chemin d'accès ne s'exécutera pas : la requête sera immédiatement interrompue et l'erreur HTTP issue de la `HTTPException` sera envoyée au client.\n\nL'avantage de lever une exception plutôt que de retourner une valeur apparaîtra plus clairement dans la section sur les Dépendances et la Sécurité.\n\nDans cet exemple, lorsque le client demande un élément par un ID qui n'existe pas, levez une exception avec un code d'état `404` :\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### Réponse résultante { #the-resulting-response }\n\nSi le client demande `http://example.com/items/foo` (un `item_id` « foo »), il recevra un code d'état HTTP 200 et une réponse JSON :\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\nMais si le client demande `http://example.com/items/bar` (un `item_id` inexistant « bar »), il recevra un code d'état HTTP 404 (l'erreur « not found ») et une réponse JSON :\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip | Astuce\n\nLorsque vous levez une `HTTPException`, vous pouvez passer n'importe quelle valeur convertible en JSON comme paramètre `detail`, pas uniquement un `str`.\n\nVous pouvez passer un `dict`, une `list`, etc.\n\nElles sont gérées automatiquement par **FastAPI** et converties en JSON.\n\n///\n\n## Ajouter des en-têtes personnalisés { #add-custom-headers }\n\nDans certaines situations, il est utile de pouvoir ajouter des en-têtes personnalisés à l'erreur HTTP. Par exemple, pour certains types de sécurité.\n\nVous n'aurez probablement pas besoin de l'utiliser directement dans votre code.\n\nMais si vous en aviez besoin pour un scénario avancé, vous pouvez ajouter des en-têtes personnalisés :\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## Installer des gestionnaires d'exception personnalisés { #install-custom-exception-handlers }\n\nVous pouvez ajouter des gestionnaires d'exception personnalisés avec [les mêmes utilitaires d'exception de Starlette](https://www.starlette.dev/exceptions/).\n\nSupposons que vous ayez une exception personnalisée `UnicornException` que vous (ou une bibliothèque que vous utilisez) pourriez `raise`.\n\nEt vous souhaitez gérer cette exception globalement avec FastAPI.\n\nVous pouvez ajouter un gestionnaire d'exception personnalisé avec `@app.exception_handler()` :\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\nIci, si vous appelez `/unicorns/yolo`, le chemin d'accès va `raise` une `UnicornException`.\n\nMais elle sera gérée par `unicorn_exception_handler`.\n\nAinsi, vous recevrez une erreur propre, avec un code d'état HTTP `418` et un contenu JSON :\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | Détails techniques\n\nVous pourriez aussi utiliser `from starlette.requests import Request` et `from starlette.responses import JSONResponse`.\n\n**FastAPI** fournit les mêmes `starlette.responses` sous `fastapi.responses` par simple commodité pour vous, développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette. Il en va de même pour `Request`.\n\n///\n\n## Remplacer les gestionnaires d'exception par défaut { #override-the-default-exception-handlers }\n\n**FastAPI** fournit des gestionnaires d'exception par défaut.\n\nCes gestionnaires se chargent de renvoyer les réponses JSON par défaut lorsque vous `raise` une `HTTPException` et lorsque la requête contient des données invalides.\n\nVous pouvez remplacer ces gestionnaires d'exception par les vôtres.\n\n### Remplacer les exceptions de validation de la requête { #override-request-validation-exceptions }\n\nLorsqu'une requête contient des données invalides, **FastAPI** lève en interne une `RequestValidationError`.\n\nEt il inclut également un gestionnaire d'exception par défaut pour cela.\n\nPour la remplacer, importez `RequestValidationError` et utilisez-la avec `@app.exception_handler(RequestValidationError)` pour décorer le gestionnaire d'exception.\n\nLe gestionnaire d'exception recevra une `Request` et l'exception.\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\nÀ présent, si vous allez sur `/items/foo`, au lieu d'obtenir l'erreur JSON par défaut suivante :\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\nvous obtiendrez une version texte, avec :\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### Remplacer le gestionnaire d'erreurs `HTTPException` { #override-the-httpexception-error-handler }\n\nDe la même manière, vous pouvez remplacer le gestionnaire de `HTTPException`.\n\nPar exemple, vous pourriez vouloir renvoyer une réponse en texte brut au lieu de JSON pour ces erreurs :\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | Détails techniques\n\nVous pourriez aussi utiliser `from starlette.responses import PlainTextResponse`.\n\n**FastAPI** fournit les mêmes `starlette.responses` sous `fastapi.responses` par simple commodité pour vous, le développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.\n\n///\n\n/// warning | Alertes\n\nGardez à l'esprit que la `RequestValidationError` contient l'information du nom de fichier et de la ligne où l'erreur de validation se produit, afin que vous puissiez l'afficher dans vos journaux avec les informations pertinentes si vous le souhaitez.\n\nMais cela signifie que si vous vous contentez de la convertir en chaîne et de renvoyer cette information directement, vous pourriez divulguer un peu d'information sur votre système. C'est pourquoi, ici, le code extrait et affiche chaque erreur indépendamment.\n\n///\n\n### Utiliser le corps de `RequestValidationError` { #use-the-requestvalidationerror-body }\n\nLa `RequestValidationError` contient le `body` qu'elle a reçu avec des données invalides.\n\nVous pouvez l'utiliser pendant le développement de votre application pour journaliser le corps et le déboguer, le renvoyer à l'utilisateur, etc.\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\nEssayez maintenant d'envoyer un élément invalide comme :\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\nVous recevrez une réponse vous indiquant que les données sont invalides et contenant le corps reçu :\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### `HTTPException` de FastAPI vs `HTTPException` de Starlette { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI** a sa propre `HTTPException`.\n\nEt la classe d'erreur `HTTPException` de **FastAPI** hérite de la classe d'erreur `HTTPException` de Starlette.\n\nLa seule différence est que la `HTTPException` de **FastAPI** accepte toute donnée sérialisable en JSON pour le champ `detail`, tandis que la `HTTPException` de Starlette n'accepte que des chaînes.\n\nAinsi, vous pouvez continuer à lever la `HTTPException` de **FastAPI** normalement dans votre code.\n\nMais lorsque vous enregistrez un gestionnaire d'exception, vous devez l'enregistrer pour la `HTTPException` de Starlette.\n\nDe cette façon, si une partie du code interne de Starlette, ou une extension ou un plug-in Starlette, lève une `HTTPException` de Starlette, votre gestionnaire pourra l'intercepter et la traiter.\n\nDans cet exemple, afin de pouvoir avoir les deux `HTTPException` dans le même code, les exceptions de Starlette sont renommées en `StarletteHTTPException` :\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### Réutiliser les gestionnaires d'exception de **FastAPI** { #reuse-fastapis-exception-handlers }\n\nSi vous souhaitez utiliser l'exception avec les mêmes gestionnaires d'exception par défaut de **FastAPI**, vous pouvez importer et réutiliser les gestionnaires d'exception par défaut depuis `fastapi.exception_handlers` :\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\nDans cet exemple, vous vous contentez d'afficher l'erreur avec un message très expressif, mais vous voyez l'idée. Vous pouvez utiliser l'exception puis simplement réutiliser les gestionnaires d'exception par défaut.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/header-param-models.md",
    "content": "# Modèles de paramètres d'en-tête { #header-parameter-models }\n\nSi vous avez un groupe de **paramètres d'en-tête** liés, vous pouvez créer un **modèle Pydantic** pour les déclarer.\n\nCela vous permet de **réutiliser le modèle** à **plusieurs endroits** et aussi de déclarer des validations et des métadonnées pour tous les paramètres en une seule fois. 😎\n\n/// note | Remarque\n\nCela est pris en charge depuis la version `0.115.0` de FastAPI. 🤓\n\n///\n\n## Paramètres d'en-tête avec un modèle Pydantic { #header-parameters-with-a-pydantic-model }\n\nDéclarez les **paramètres d'en-tête** dont vous avez besoin dans un **modèle Pydantic**, puis déclarez le paramètre comme `Header` :\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\n**FastAPI** extrait les données de **chaque champ** depuis les **en-têtes** de la requête et vous fournit le modèle Pydantic que vous avez défini.\n\n## Consulter la documentation { #check-the-docs }\n\nVous pouvez voir les en-têtes requis dans l'interface de la documentation à `/docs` :\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## Interdire les en-têtes supplémentaires { #forbid-extra-headers }\n\nDans certains cas d'utilisation particuliers (probablement pas très courants), vous pourriez vouloir **restreindre** les en-têtes que vous souhaitez recevoir.\n\nVous pouvez utiliser la configuration du modèle de Pydantic pour `forbid` tout champ `extra` :\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\nSi un client essaie d'envoyer des **en-têtes supplémentaires**, il recevra une **réponse d'erreur**.\n\nPar exemple, si le client essaie d'envoyer un en-tête `tool` avec la valeur `plumbus`, il recevra une **réponse d'erreur** lui indiquant que le paramètre d'en-tête `tool` n'est pas autorisé :\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## Désactiver convert_underscores { #disable-convert-underscores }\n\nComme pour les paramètres d'en-tête classiques, lorsque vous avez des caractères de soulignement dans les noms de paramètres, ils sont **automatiquement convertis en tirets**.\n\nPar exemple, si vous avez un paramètre d'en-tête `save_data` dans le code, l'en-tête HTTP attendu sera `save-data`, et il apparaîtra ainsi dans la documentation.\n\nSi, pour une raison quelconque, vous devez désactiver cette conversion automatique, vous pouvez aussi le faire pour les modèles Pydantic de paramètres d'en-tête.\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | Alertes\n\nAvant de définir `convert_underscores` à `False`, gardez à l'esprit que certains proxys et serveurs HTTP interdisent l'utilisation d'en-têtes contenant des underscores.\n\n///\n\n## Résumé { #summary }\n\nVous pouvez utiliser des **modèles Pydantic** pour déclarer des **en-têtes** dans **FastAPI**. 😎\n"
  },
  {
    "path": "docs/fr/docs/tutorial/header-params.md",
    "content": "# Paramètres d'en-tête { #header-parameters }\n\nVous pouvez définir des paramètres `Header` de la même manière que vous définissez des paramètres `Query`, `Path` et `Cookie`.\n\n## Importer `Header` { #import-header }\n\nCommencez par importer `Header` :\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## Déclarer des paramètres `Header` { #declare-header-parameters }\n\nDéclarez ensuite les paramètres d'en-tête en utilisant la même structure qu'avec `Path`, `Query` et `Cookie`.\n\nVous pouvez définir la valeur par défaut ainsi que tous les paramètres supplémentaires de validation ou d'annotation :\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Détails techniques\n\n`Header` est une classe « sœur » de `Path`, `Query` et `Cookie`. Elle hérite également de la même classe commune `Param`.\n\nMais rappelez-vous que lorsque vous importez `Query`, `Path`, `Header` et d'autres depuis `fastapi`, ce sont en réalité des fonctions qui renvoient des classes spéciales.\n\n///\n\n/// info\n\nPour déclarer des en-têtes, vous devez utiliser `Header`, sinon les paramètres seraient interprétés comme des paramètres de requête.\n\n///\n\n## Conversion automatique { #automatic-conversion }\n\n`Header` offre un peu de fonctionnalité supplémentaire par rapport à `Path`, `Query` et `Cookie`.\n\nLa plupart des en-têtes standards sont séparés par un caractère « trait d'union », également appelé « signe moins » (`-`).\n\nMais une variable comme `user-agent` est invalide en Python.\n\nAinsi, par défaut, `Header` convertit les caractères des noms de paramètres du tiret bas (`_`) en trait d'union (`-`) pour extraire et documenter les en-têtes.\n\nDe plus, les en-têtes HTTP ne sont pas sensibles à la casse, vous pouvez donc les déclarer avec le style Python standard (aussi appelé « snake_case »).\n\nVous pouvez donc utiliser `user_agent` comme vous le feriez normalement dans du code Python, au lieu d'avoir à mettre des majuscules aux premières lettres comme `User_Agent` ou quelque chose de similaire.\n\nSi, pour une raison quelconque, vous devez désactiver la conversion automatique des traits bas en traits d'union, définissez le paramètre `convert_underscores` de `Header` sur `False` :\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | Alertes\n\nAvant de définir `convert_underscores` sur `False`, gardez à l'esprit que certains proxies et serveurs HTTP interdisent l'utilisation d'en-têtes contenant des traits bas.\n\n///\n\n## Gérer les en-têtes dupliqués { #duplicate-headers }\n\nIl est possible de recevoir des en-têtes en double. Autrement dit, le même en-tête avec plusieurs valeurs.\n\nVous pouvez définir ces cas à l'aide d'une liste dans la déclaration de type.\n\nVous recevrez toutes les valeurs de l'en-tête dupliqué sous forme de `list` Python.\n\nPar exemple, pour déclarer un en-tête `X-Token` qui peut apparaître plusieurs fois, vous pouvez écrire :\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\nSi vous communiquez avec ce *chemin d'accès* en envoyant deux en-têtes HTTP comme :\n\n```\nX-Token: foo\nX-Token: bar\n```\n\nLa réponse ressemblerait à ceci :\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## Récapitulatif { #recap }\n\nDéclarez les en-têtes avec `Header`, en suivant le même modèle que pour `Query`, `Path` et `Cookie`.\n\nEt ne vous souciez pas des traits bas dans vos variables, **FastAPI** s'occupe de les convertir.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/index.md",
    "content": "# Tutoriel - Guide utilisateur { #tutorial-user-guide }\n\nCe tutoriel vous montre comment utiliser **FastAPI** avec la plupart de ses fonctionnalités, étape par étape.\n\nChaque section s'appuie progressivement sur les précédentes, mais elle est structurée de manière à séparer les sujets, afin que vous puissiez aller directement à l'un d'entre eux pour répondre à vos besoins spécifiques d'API.\n\nIl est également conçu pour servir de référence ultérieure, afin que vous puissiez revenir voir exactement ce dont vous avez besoin.\n\n## Exécuter le code { #run-the-code }\n\nTous les blocs de code peuvent être copiés et utilisés directement (il s'agit en fait de fichiers Python testés).\n\nPour exécuter l'un de ces exemples, copiez le code dans un fichier `main.py`, et démarrez `fastapi dev` :\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nIl est **FORTEMENT encouragé** que vous écriviez ou copiez le code, l'éditiez et l'exécutiez localement.\n\nL'utiliser dans votre éditeur est ce qui vous montre vraiment les avantages de FastAPI, en voyant le peu de code que vous avez à écrire, toutes les vérifications de type, l'autocomplétion, etc.\n\n---\n\n## Installer FastAPI { #install-fastapi }\n\nLa première étape consiste à installer FastAPI.\n\nAssurez-vous de créer un [environnement virtuel](../virtual-environments.md), de l'activer, puis **d'installer FastAPI** :\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | Remarque\n\nLorsque vous installez avec `pip install \"fastapi[standard]\"`, cela inclut des dépendances standards optionnelles par défaut, y compris `fastapi-cloud-cli`, qui vous permet de déployer sur [FastAPI Cloud](https://fastapicloud.com).\n\nSi vous ne souhaitez pas avoir ces dépendances optionnelles, vous pouvez à la place installer `pip install fastapi`.\n\nSi vous souhaitez installer les dépendances standard mais sans `fastapi-cloud-cli`, vous pouvez installer avec `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n///\n\n/// tip | Astuce\n\nFastAPI dispose d'une [extension officielle pour VS Code](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (et Cursor), qui fournit de nombreuses fonctionnalités, notamment un explorateur de chemins d'accès, une recherche de chemins d'accès, la navigation CodeLens dans les tests (aller à la définition depuis les tests), ainsi que le déploiement et les journaux FastAPI Cloud, le tout depuis votre éditeur.\n\n///\n\n## Guide d'utilisation avancé { #advanced-user-guide }\n\nIl existe également un **Guide d'utilisation avancé** que vous pouvez lire plus tard après ce **Tutoriel - Guide d'utilisation**.\n\nLe **Guide d'utilisation avancé**, qui s'appuie sur cette base, utilise les mêmes concepts et vous apprend quelques fonctionnalités supplémentaires.\n\nMais vous devez d'abord lire le **Tutoriel - Guide d'utilisation** (ce que vous êtes en train de lire en ce moment).\n\nIl est conçu pour que vous puissiez construire une application complète avec seulement le **Tutoriel - Guide d'utilisation**, puis l'étendre de différentes manières, en fonction de vos besoins, en utilisant certaines des idées supplémentaires du **Guide d'utilisation avancé**.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/metadata.md",
    "content": "# Métadonnées et URL des documents { #metadata-and-docs-urls }\n\nVous pouvez personnaliser plusieurs configurations de métadonnées dans votre application **FastAPI**.\n\n## Métadonnées pour l'API { #metadata-for-api }\n\nVous pouvez définir les champs suivants qui sont utilisés dans la spécification OpenAPI et les interfaces utilisateur de documentation automatique de l’API :\n\n| Paramètre | Type | Description |\n|------------|------|-------------|\n| `title` | `str` | Le titre de l’API. |\n| `summary` | `str` | Un court résumé de l’API. <small>Disponible depuis OpenAPI 3.1.0, FastAPI 0.99.0.</small> |\n| `description` | `str` | Une brève description de l’API. Elle peut utiliser Markdown. |\n| `version` | `string` | La version de l’API. C’est la version de votre propre application, pas d’OpenAPI. Par exemple `2.5.0`. |\n| `terms_of_service` | `str` | Une URL vers les Conditions d’utilisation de l’API. Le cas échéant, il doit s’agir d’une URL. |\n| `contact` | `dict` | Les informations de contact pour l’API exposée. Cela peut contenir plusieurs champs. <details><summary>champs de <code>contact</code></summary><table><thead><tr><th>Paramètre</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Le nom identifiant de la personne/organisation de contact.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>L’URL pointant vers les informations de contact. DOIT être au format d’une URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>L’adresse e-mail de la personne/organisation de contact. DOIT être au format d’une adresse e-mail.</td></tr></tbody></table></details> |\n| `license_info` | `dict` | Les informations de licence pour l’API exposée. Cela peut contenir plusieurs champs. <details><summary>champs de <code>license_info</code></summary><table><thead><tr><th>Paramètre</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>OBLIGATOIRE</strong> (si un <code>license_info</code> est défini). Le nom de la licence utilisée pour l’API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Une expression de licence [SPDX](https://spdx.org/licenses/) pour l’API. Le champ <code>identifier</code> est mutuellement exclusif du champ <code>url</code>. <small>Disponible depuis OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>Une URL vers la licence utilisée pour l’API. DOIT être au format d’une URL.</td></tr></tbody></table></details> |\n\nVous pouvez les définir comme suit :\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | Astuce\n\nVous pouvez écrire du Markdown dans le champ `description` et il sera rendu dans la sortie.\n\n///\n\nAvec cette configuration, les documents API automatiques ressembleraient à :\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## Identifiant de licence { #license-identifier }\n\nDepuis OpenAPI 3.1.0 et FastAPI 0.99.0, vous pouvez également définir `license_info` avec un `identifier` au lieu d’une `url`.\n\nPar exemple :\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## Métadonnées pour les tags { #metadata-for-tags }\n\nVous pouvez également ajouter des métadonnées supplémentaires pour les différents tags utilisés pour regrouper vos chemins d'accès avec le paramètre `openapi_tags`.\n\nIl prend une liste contenant un dictionnaire pour chaque tag.\n\nChaque dictionnaire peut contenir :\n\n* `name` (**requis**) : un `str` avec le même nom de tag que vous utilisez dans le paramètre `tags` de vos *chemins d'accès* et `APIRouter`s.\n* `description` : un `str` avec une courte description pour le tag. Il peut contenir du Markdown et sera affiché dans l’interface utilisateur de la documentation.\n* `externalDocs` : un `dict` décrivant une documentation externe avec :\n    * `description` : un `str` avec une courte description pour la documentation externe.\n    * `url` (**requis**) : un `str` avec l’URL de la documentation externe.\n\n### Créer des métadonnées pour les tags { #create-metadata-for-tags }\n\nEssayons cela avec un exemple de tags pour `users` et `items`.\n\nCréez des métadonnées pour vos tags et transmettez-les au paramètre `openapi_tags` :\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\nNotez que vous pouvez utiliser Markdown à l’intérieur des descriptions, par exemple « login » sera affiché en gras (**login**) et « fancy » sera affiché en italique (_fancy_).\n\n/// tip | Astuce\n\nVous n’avez pas à ajouter des métadonnées pour tous les tags que vous utilisez.\n\n///\n\n### Utiliser vos tags { #use-your-tags }\n\nUtilisez le paramètre `tags` avec vos *chemins d'accès* (et `APIRouter`s) pour les affecter à différents tags :\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info\n\nEn savoir plus sur les tags dans [Configuration de chemins d'accès](path-operation-configuration.md#tags).\n\n///\n\n### Consultez les documents { #check-the-docs }\n\nDésormais, si vous consultez les documents, ils afficheront toutes les métadonnées supplémentaires :\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### Définir l’ordre des tags { #order-of-tags }\n\nL’ordre de chaque dictionnaire de métadonnées de tag définit également l’ordre affiché dans l’interface utilisateur de la documentation.\n\nPar exemple, même si `users` viendrait après `items` par ordre alphabétique, il est affiché avant, car nous avons ajouté ses métadonnées comme premier dictionnaire de la liste.\n\n## URL OpenAPI { #openapi-url }\n\nPar défaut, le schéma OpenAPI est servi à `/openapi.json`.\n\nMais vous pouvez le configurer avec le paramètre `openapi_url`.\n\nPar exemple, pour qu’il soit servi à `/api/v1/openapi.json` :\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\nSi vous souhaitez désactiver complètement le schéma OpenAPI, vous pouvez définir `openapi_url=None`, cela désactivera également les interfaces utilisateur de la documentation qui l’utilisent.\n\n## URL des documents { #docs-urls }\n\nVous pouvez configurer les deux interfaces utilisateur de documentation incluses :\n\n* **Swagger UI** : servie à `/docs`.\n    * Vous pouvez définir son URL avec le paramètre `docs_url`.\n    * Vous pouvez la désactiver en définissant `docs_url=None`.\n* **ReDoc** : servie à `/redoc`.\n    * Vous pouvez définir son URL avec le paramètre `redoc_url`.\n    * Vous pouvez la désactiver en définissant `redoc_url=None`.\n\nPar exemple, pour que Swagger UI soit servi à `/documentation` et désactiver ReDoc :\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/fr/docs/tutorial/middleware.md",
    "content": "# Middleware { #middleware }\n\nVous pouvez ajouter des middlewares aux applications **FastAPI**.\n\nUn « middleware » est une fonction qui agit sur chaque **requête** avant qu’elle ne soit traitée par un *chemin d'accès* spécifique. Et aussi sur chaque **réponse** avant son renvoi.\n\n* Il intercepte chaque **requête** qui parvient à votre application.\n* Il peut alors faire quelque chose avec cette **requête** ou exécuter tout code nécessaire.\n* Ensuite, il transmet la **requête** pour qu’elle soit traitée par le reste de l’application (par un *chemin d'accès*).\n* Puis il récupère la **réponse** générée par l’application (par un *chemin d'accès*).\n* Il peut faire quelque chose avec cette **réponse** ou exécuter tout code nécessaire.\n* Enfin, il renvoie la **réponse**.\n\n/// note | Détails techniques\n\nSi vous avez des dépendances avec `yield`, le code de sortie s’exécutera après le middleware.\n\nS’il y avait des tâches d’arrière-plan (présentées dans la section [Tâches d’arrière-plan](background-tasks.md), que vous verrez plus tard), elles s’exécuteront après tous les middlewares.\n\n///\n\n## Créer un middleware { #create-a-middleware }\n\nPour créer un middleware, utilisez le décorateur `@app.middleware(\"http\")` au-dessus d’une fonction.\n\nLa fonction de middleware reçoit :\n\n* La `request`.\n* Une fonction `call_next` qui recevra la `request` en paramètre.\n    * Cette fonction transmettra la `request` au *chemin d'accès* correspondant.\n    * Puis elle renverra la `response` générée par le *chemin d'accès* correspondant.\n* Vous pouvez ensuite modifier la `response` avant de la renvoyer.\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip | Astuce\n\nGardez à l’esprit que des en-têtes propriétaires personnalisés peuvent être ajoutés [en utilisant le préfixe `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nMais si vous avez des en-têtes personnalisés que vous voulez rendre visibles pour un client dans un navigateur, vous devez les ajouter à votre configuration CORS ([CORS (Partage des ressources entre origines)](cors.md)) en utilisant le paramètre `expose_headers` documenté dans [la documentation CORS de Starlette](https://www.starlette.dev/middleware/#corsmiddleware).\n\n///\n\n/// note | Détails techniques\n\nVous pourriez aussi utiliser `from starlette.requests import Request`.\n\n**FastAPI** le fournit pour votre confort de développeur. Mais cela provient directement de Starlette.\n\n///\n\n### Avant et après la `response` { #before-and-after-the-response }\n\nVous pouvez ajouter du code à exécuter avec la `request`, avant que tout *chemin d'accès* ne la reçoive.\n\nEt aussi après que la `response` a été générée, avant de la renvoyer.\n\nPar exemple, vous pourriez ajouter un en-tête personnalisé `X-Process-Time` contenant le temps en secondes nécessaire pour traiter la requête et générer une réponse :\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip | Astuce\n\nIci, nous utilisons [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) au lieu de `time.time()` car cela peut être plus précis pour ces cas d’usage. 🤓\n\n///\n\n## Ordre d’exécution de plusieurs middlewares { #multiple-middleware-execution-order }\n\nQuand vous ajoutez plusieurs middlewares en utilisant soit le décorateur `@app.middleware()`, soit la méthode `app.add_middleware()`, chaque nouveau middleware enveloppe l’application, formant une pile. Le dernier middleware ajouté est le plus externe, et le premier est le plus interne.\n\nSur le chemin de la requête, le plus externe s’exécute en premier.\n\nSur le chemin de la réponse, il s’exécute en dernier.\n\nPar exemple :\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\nCela aboutit à l’ordre d’exécution suivant :\n\n* **Requête** : MiddlewareB → MiddlewareA → route\n\n* **Réponse** : route → MiddlewareA → MiddlewareB\n\nCe comportement d’empilement garantit que les middlewares s’exécutent dans un ordre prévisible et contrôlable.\n\n## Autres middlewares { #other-middlewares }\n\nVous pouvez en lire davantage sur d’autres middlewares dans le [Guide de l’utilisateur avancé : Middleware avancé](../advanced/middleware.md).\n\nVous verrez comment gérer <abbr title=\"Cross-Origin Resource Sharing - Partage des ressources entre origines\">CORS</abbr> avec un middleware dans la section suivante.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/path-operation-configuration.md",
    "content": "# Configurer les chemins d'accès { #path-operation-configuration }\n\nVous pouvez passer plusieurs paramètres à votre *décorateur de chemin d'accès* pour le configurer.\n\n/// warning | Alertes\n\nNotez que ces paramètres sont passés directement au *décorateur de chemin d'accès*, et non à votre *fonction de chemin d'accès*.\n\n///\n\n## Définir le code d'état de la réponse { #response-status-code }\n\nVous pouvez définir le `status_code` (HTTP) à utiliser dans la réponse de votre *chemin d'accès*.\n\nVous pouvez passer directement le code `int`, comme `404`.\n\nMais si vous ne vous souvenez pas à quoi correspond chaque code numérique, vous pouvez utiliser les constantes abrégées dans `status` :\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\nCe code d'état sera utilisé dans la réponse et ajouté au schéma OpenAPI.\n\n/// note | Détails techniques\n\nVous pouvez également utiliser `from starlette import status`.\n\n**FastAPI** fournit le même `starlette.status` sous le nom `fastapi.status` pour votre commodité, en tant que développeur. Mais cela provient directement de Starlette.\n\n///\n\n## Ajouter des tags { #tags }\n\nVous pouvez ajouter des tags à votre *chemin d'accès*, en passant le paramètre `tags` avec une `list` de `str` (généralement un seul `str`) :\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\nIls seront ajoutés au schéma OpenAPI et utilisés par les interfaces de documentation automatiques :\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### Utiliser des tags avec Enum { #tags-with-enums }\n\nSi vous avez une grande application, vous pourriez finir par accumuler **plusieurs tags**, et vous voudrez vous assurer d'utiliser toujours le **même tag** pour les *chemins d'accès* associés.\n\nDans ces cas, il peut être judicieux de stocker les tags dans un `Enum`.\n\n**FastAPI** le prend en charge de la même manière qu'avec des chaînes simples :\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## Ajouter un résumé et une description { #summary-and-description }\n\nVous pouvez ajouter un `summary` et une `description` :\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## Utiliser la description depuis la docstring { #description-from-docstring }\n\nComme les descriptions ont tendance à être longues et à couvrir plusieurs lignes, vous pouvez déclarer la description du *chemin d'accès* dans la <dfn title=\"une chaîne multilignes comme première expression à l'intérieur d'une fonction (non assignée à une variable) utilisée pour la documentation\">docstring</dfn> de la fonction et **FastAPI** la lira à partir de là.\n\nVous pouvez écrire [Markdown](https://en.wikipedia.org/wiki/Markdown) dans la docstring, il sera interprété et affiché correctement (en tenant compte de l'indentation de la docstring).\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\nElle sera utilisée dans les documents interactifs :\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## Définir la description de la réponse { #response-description }\n\nVous pouvez spécifier la description de la réponse avec le paramètre `response_description` :\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info\n\nNotez que `response_description` se réfère spécifiquement à la réponse, tandis que `description` se réfère au *chemin d'accès* en général.\n\n///\n\n/// check | Vérifications\n\nOpenAPI spécifie que chaque *chemin d'accès* requiert une description de réponse.\n\nDonc, si vous n'en fournissez pas, **FastAPI** en générera automatiquement une « Réponse réussie ».\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## Déprécier un *chemin d'accès* { #deprecate-a-path-operation }\n\nSi vous devez marquer un *chemin d'accès* comme <dfn title=\"obsolète, il est recommandé de ne pas l'utiliser\">déprécié</dfn>, sans pour autant le supprimer, passez le paramètre `deprecated` :\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\nIl sera clairement marqué comme déprécié dans les documents interactifs :\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\nVoyez à quoi ressemblent les *chemins d'accès* dépréciés et non dépréciés :\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## Récapitulatif { #recap }\n\nVous pouvez facilement configurer et ajouter des métadonnées à vos *chemins d'accès* en passant des paramètres aux *décorateurs de chemin d'accès*.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/path-params-numeric-validations.md",
    "content": "# Paramètres de chemin et validations numériques { #path-parameters-and-numeric-validations }\n\nDe la même façon que vous pouvez déclarer plus de validations et de métadonnées pour les paramètres de requête avec `Query`, vous pouvez déclarer le même type de validations et de métadonnées pour les paramètres de chemin avec `Path`.\n\n## Importer `Path` { #import-path }\n\nTout d'abord, importez `Path` de `fastapi`, et importez `Annotated` :\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info\n\nFastAPI a ajouté le support pour `Annotated` (et a commencé à le recommander) dans la version 0.95.0.\n\nSi vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d'utiliser `Annotated`.\n\nAssurez-vous de [Mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) à la version 0.95.1 à minima avant d'utiliser `Annotated`.\n\n///\n\n## Déclarer des métadonnées { #declare-metadata }\n\nVous pouvez déclarer les mêmes paramètres que pour `Query`.\n\nPar exemple, pour déclarer une valeur de métadonnée `title` pour le paramètre de chemin `item_id`, vous pouvez écrire :\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note | Remarque\n\nUn paramètre de chemin est toujours requis car il doit faire partie du chemin. Même si vous l'avez déclaré avec `None` ou défini une valeur par défaut, cela ne changerait rien, il serait toujours requis.\n\n///\n\n## Ordonner les paramètres comme vous le souhaitez { #order-the-parameters-as-you-need }\n\n/// tip | Astuce\n\nCe n'est probablement pas aussi important ou nécessaire si vous utilisez `Annotated`.\n\n///\n\nDisons que vous voulez déclarer le paramètre de requête `q` comme un `str` requis.\n\nEt vous n'avez pas besoin de déclarer autre chose pour ce paramètre, donc vous n'avez pas vraiment besoin d'utiliser `Query`.\n\nMais vous avez toujours besoin d'utiliser `Path` pour le paramètre de chemin `item_id`. Et vous ne voulez pas utiliser `Annotated` pour une raison quelconque.\n\nPython se plaindra si vous mettez une valeur avec une « valeur par défaut » avant une valeur qui n'a pas de « valeur par défaut ».\n\nMais vous pouvez les réorganiser, et avoir la valeur sans défaut (le paramètre de requête `q`) en premier.\n\nCela n'a pas d'importance pour **FastAPI**. Il détectera les paramètres par leurs noms, types et déclarations par défaut (`Query`, `Path`, etc), il ne se soucie pas de l'ordre.\n\nAinsi, vous pouvez déclarer votre fonction comme suit :\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\nMais gardez à l'esprit que si vous utilisez `Annotated`, vous n'aurez pas ce problème, cela n'aura pas d'importance car vous n'utilisez pas les valeurs par défaut des paramètres de fonction pour `Query()` ou `Path()`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## Ordonner les paramètres comme vous le souhaitez, astuces { #order-the-parameters-as-you-need-tricks }\n\n/// tip | Astuce\n\nCe n'est probablement pas aussi important ou nécessaire si vous utilisez `Annotated`.\n\n///\n\nVoici une **petite astuce** qui peut être pratique, mais vous n'en aurez pas souvent besoin.\n\nSi vous voulez :\n\n* déclarer le paramètre de requête `q` sans `Query` ni valeur par défaut\n* déclarer le paramètre de chemin `item_id` en utilisant `Path`\n* les avoir dans un ordre différent\n* ne pas utiliser `Annotated`\n\n... Python a une petite syntaxe spéciale pour cela.\n\nPassez `*`, comme premier paramètre de la fonction.\n\nPython ne fera rien avec ce `*`, mais il saura que tous les paramètres suivants doivent être appelés comme arguments « mots-clés » (paires clé-valeur), également connus sous le nom de <abbr title=\"De : K-ey W-ord Arg-uments\"><code>kwargs</code></abbr>. Même s'ils n'ont pas de valeur par défaut.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### Mieux avec `Annotated` { #better-with-annotated }\n\nGardez à l'esprit que si vous utilisez `Annotated`, comme vous n'utilisez pas les valeurs par défaut des paramètres de fonction, vous n'aurez pas ce problème, et vous n'aurez probablement pas besoin d'utiliser `*`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## Validations numériques : supérieur ou égal { #number-validations-greater-than-or-equal }\n\nAvec `Query` et `Path` (et d'autres que vous verrez plus tard) vous pouvez déclarer des contraintes numériques.\n\nIci, avec `ge=1`, `item_id` devra être un nombre entier « `g`reater than or `e`qual » à `1`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## Validations numériques : supérieur et inférieur ou égal { #number-validations-greater-than-and-less-than-or-equal }\n\nLa même chose s'applique pour :\n\n* `gt` : `g`reater `t`han\n* `le` : `l`ess than or `e`qual\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## Validations numériques : flottants, supérieur et inférieur { #number-validations-floats-greater-than-and-less-than }\n\nLes validations numériques fonctionnent également pour les valeurs `float`.\n\nC'est ici qu'il devient important de pouvoir déclarer <abbr title=\"greater than - supérieur à\"><code>gt</code></abbr> et pas seulement <abbr title=\"greater than or equal - supérieur ou égal\"><code>ge</code></abbr>. Avec cela, vous pouvez exiger, par exemple, qu'une valeur doit être supérieure à `0`, même si elle est inférieure à `1`.\n\nAinsi, `0.5` serait une valeur valide. Mais `0.0` ou `0` ne le serait pas.\n\nEt la même chose pour <abbr title=\"less than - inférieur à\"><code>lt</code></abbr>.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## Pour résumer { #recap }\n\nAvec `Query`, `Path` (et d'autres que vous verrez plus tard) vous pouvez déclarer des métadonnées et des validations de chaînes de la même manière qu'avec les [Paramètres de requête et validations de chaînes](query-params-str-validations.md).\n\nEt vous pouvez également déclarer des validations numériques :\n\n* `gt` : `g`reater `t`han\n* `ge` : `g`reater than or `e`qual\n* `lt` : `l`ess `t`han\n* `le` : `l`ess than or `e`qual\n\n/// info\n\n`Query`, `Path`, et d'autres classes que vous verrez plus tard sont des sous-classes d'une classe commune `Param`.\n\nTous partagent les mêmes paramètres pour des validations supplémentaires et des métadonnées que vous avez vu précédemment.\n\n///\n\n/// note | Détails techniques\n\nLorsque vous importez `Query`, `Path` et d'autres de `fastapi`, ce sont en fait des fonctions.\n\nCes dernières, lorsqu'elles sont appelées, renvoient des instances de classes du même nom.\n\nAinsi, vous importez `Query`, qui est une fonction. Et lorsque vous l'appelez, elle renvoie une instance d'une classe également nommée `Query`.\n\nCes fonctions sont là (au lieu d'utiliser simplement les classes directement) pour que votre éditeur ne marque pas d'erreurs sur leurs types.\n\nDe cette façon, vous pouvez utiliser votre éditeur et vos outils de codage habituels sans avoir à ajouter des configurations personnalisées pour ignorer ces erreurs.\n\n///\n"
  },
  {
    "path": "docs/fr/docs/tutorial/path-params.md",
    "content": "# Paramètres de chemin { #path-parameters }\n\nVous pouvez déclarer des « paramètres » ou « variables » de chemin avec la même syntaxe utilisée par les chaînes de format Python :\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\nLa valeur du paramètre de chemin `item_id` sera transmise à votre fonction dans l'argument `item_id`.\n\nDonc, si vous exécutez cet exemple et allez sur [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), vous verrez comme réponse :\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## Paramètres de chemin typés { #path-parameters-with-types }\n\nVous pouvez déclarer le type d'un paramètre de chemin dans la fonction, en utilisant les annotations de type Python standard :\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\nIci, `item_id` est déclaré comme `int`.\n\n/// check | Vérifications\n\nCela vous apporte la prise en charge par l'éditeur dans votre fonction, avec vérifications d'erreurs, autocomplétion, etc.\n\n///\n\n## <dfn title=\"également appelé : sérialisation, parsing, marshalling\">Conversion</dfn> de données { #data-conversion }\n\nSi vous exécutez cet exemple et ouvrez votre navigateur sur [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3), vous verrez comme réponse :\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check | Vérifications\n\nRemarquez que la valeur reçue par votre fonction (et renvoyée) est `3`, en tant qu'entier (`int`) Python, pas la chaîne de caractères « 3 ».\n\nAinsi, avec cette déclaration de type, **FastAPI** vous fournit automatiquement le <dfn title=\"conversion de la chaîne de caractères provenant d'une requête HTTP en données Python\">« parsing »</dfn> de la requête.\n\n///\n\n## Validation de données { #data-validation }\n\nMais si vous allez dans le navigateur sur [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), vous verrez une belle erreur HTTP :\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\ncar le paramètre de chemin `item_id` a pour valeur « foo », qui n'est pas un `int`.\n\nLa même erreur apparaîtrait si vous fournissiez un `float` au lieu d'un `int`, comme ici : [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)\n\n/// check | Vérifications\n\nAinsi, avec la même déclaration de type Python, **FastAPI** vous fournit la validation de données.\n\nRemarquez que l'erreur indique clairement l'endroit exact où la validation n'a pas réussi.\n\nC'est incroyablement utile lors du développement et du débogage du code qui interagit avec votre API.\n\n///\n\n## Documentation { #documentation }\n\nEt lorsque vous ouvrez votre navigateur sur [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), vous verrez une documentation d'API automatique et interactive comme :\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check | Vérifications\n\nÀ nouveau, simplement avec cette même déclaration de type Python, **FastAPI** vous fournit une documentation interactive automatique (intégrant Swagger UI).\n\nRemarquez que le paramètre de chemin est déclaré comme entier.\n\n///\n\n## Les avantages d'une norme, documentation alternative { #standards-based-benefits-alternative-documentation }\n\nEt comme le schéma généré suit la norme [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md), il existe de nombreux outils compatibles.\n\nGrâce à cela, **FastAPI** fournit lui-même une documentation d'API alternative (utilisant ReDoc), accessible sur [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) :\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\nDe la même façon, il existe de nombreux outils compatibles, y compris des outils de génération de code pour de nombreux langages.\n\n## Pydantic { #pydantic }\n\nToute la validation de données est effectuée sous le capot par [Pydantic](https://docs.pydantic.dev/), vous en bénéficiez donc pleinement. Vous savez ainsi que vous êtes entre de bonnes mains.\n\nVous pouvez utiliser les mêmes déclarations de type avec `str`, `float`, `bool` et de nombreux autres types de données complexes.\n\nPlusieurs d'entre eux sont explorés dans les prochains chapitres du tutoriel.\n\n## L'ordre importe { #order-matters }\n\nQuand vous créez des *chemins d'accès*, vous pouvez vous retrouver dans une situation avec un chemin fixe.\n\nPar exemple `/users/me`, disons pour récupérer les données de l'utilisateur actuel.\n\nEt vous pouvez aussi avoir un chemin `/users/{user_id}` pour récupérer des données sur un utilisateur spécifique grâce à un identifiant d'utilisateur.\n\nComme les *chemins d'accès* sont évalués dans l'ordre, vous devez vous assurer que le chemin `/users/me` est déclaré avant celui de `/users/{user_id}` :\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\nSinon, le chemin `/users/{user_id}` correspondrait aussi à `/users/me`, « pensant » qu'il reçoit un paramètre `user_id` avec la valeur « me ».\n\nDe même, vous ne pouvez pas redéfinir un chemin d'accès :\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\nLe premier sera toujours utilisé puisque le chemin correspond en premier.\n\n## Valeurs prédéfinies { #predefined-values }\n\nSi vous avez un *chemin d'accès* qui reçoit un *paramètre de chemin*, mais que vous voulez que les valeurs possibles de ce *paramètre de chemin* soient prédéfinies, vous pouvez utiliser une <abbr title=\"Énumération\">`Enum`</abbr> Python standard.\n\n### Créer une classe `Enum` { #create-an-enum-class }\n\nImportez `Enum` et créez une sous-classe qui hérite de `str` et de `Enum`.\n\nEn héritant de `str`, la documentation de l'API saura que les valeurs doivent être de type `string` et pourra donc s'afficher correctement.\n\nCréez ensuite des attributs de classe avec des valeurs fixes, qui seront les valeurs valides disponibles :\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip | Astuce\n\nSi vous vous demandez, « AlexNet », « ResNet » et « LeNet » sont juste des noms de <dfn title=\"Techniquement, architectures de modèles de Deep Learning\">modèles</dfn> de Machine Learning.\n\n///\n\n### Déclarer un paramètre de chemin { #declare-a-path-parameter }\n\nCréez ensuite un *paramètre de chemin* avec une annotation de type utilisant la classe d'énumération que vous avez créée (`ModelName`) :\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### Consulter la documentation { #check-the-docs }\n\nComme les valeurs disponibles pour le *paramètre de chemin* sont prédéfinies, la documentation interactive peut les afficher clairement :\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### Travailler avec les *énumérations* Python { #working-with-python-enumerations }\n\nLa valeur du *paramètre de chemin* sera un *membre d'énumération*.\n\n#### Comparer des *membres d'énumération* { #compare-enumeration-members }\n\nVous pouvez le comparer avec le *membre d'énumération* dans votre enum `ModelName` :\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### Obtenir la *valeur de l'énumération* { #get-the-enumeration-value }\n\nVous pouvez obtenir la valeur réelle (une `str` dans ce cas) avec `model_name.value`, ou en général, `votre_membre_d_enum.value` :\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip | Astuce\n\nVous pouvez aussi accéder à la valeur « lenet » avec `ModelName.lenet.value`.\n\n///\n\n#### Retourner des *membres d'énumération* { #return-enumeration-members }\n\nVous pouvez retourner des *membres d'énumération* depuis votre *chemin d'accès*, même imbriqués dans un corps JSON (par ex. un `dict`).\n\nIls seront convertis vers leurs valeurs correspondantes (des chaînes de caractères ici) avant d'être renvoyés au client :\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\nDans votre client, vous recevrez une réponse JSON comme :\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## Paramètres de chemin contenant des chemins { #path-parameters-containing-paths }\n\nDisons que vous avez un *chemin d'accès* avec un chemin `/files/{file_path}`.\n\nMais vous avez besoin que `file_path` lui-même contienne un *chemin*, comme `home/johndoe/myfile.txt`.\n\nAinsi, l'URL pour ce fichier serait : `/files/home/johndoe/myfile.txt`.\n\n### Support d'OpenAPI { #openapi-support }\n\nOpenAPI ne prend pas en charge une manière de déclarer un *paramètre de chemin* contenant un *chemin* à l'intérieur, car cela peut conduire à des scénarios difficiles à tester et à définir.\n\nNéanmoins, vous pouvez toujours le faire dans **FastAPI**, en utilisant l'un des outils internes de Starlette.\n\nEt la documentation fonctionnera quand même, même si aucune indication supplémentaire ne sera ajoutée pour dire que le paramètre doit contenir un chemin.\n\n### Convertisseur de chemin { #path-convertor }\n\nEn utilisant une option directement depuis Starlette, vous pouvez déclarer un *paramètre de chemin* contenant un *chemin* avec une URL comme :\n\n```\n/files/{file_path:path}\n```\n\nDans ce cas, le nom du paramètre est `file_path`, et la dernière partie, `:path`, indique que le paramètre doit correspondre à n'importe quel *chemin*.\n\nVous pouvez donc l'utiliser ainsi :\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip | Astuce\n\nVous pourriez avoir besoin que le paramètre contienne `/home/johndoe/myfile.txt`, avec un slash initial (`/`).\n\nDans ce cas, l'URL serait : `/files//home/johndoe/myfile.txt`, avec un double slash (`//`) entre `files` et `home`.\n\n///\n\n## Récapitulatif { #recap }\n\nAvec **FastAPI**, en utilisant des déclarations de type Python courtes, intuitives et standard, vous obtenez :\n\n* Support de l'éditeur : vérifications d'erreurs, autocomplétion, etc.\n* Données « <dfn title=\"conversion de la chaîne de caractères provenant d'une requête HTTP en données Python\">parsing</dfn> »\n* Validation de données\n* Annotations d'API et documentation automatique\n\nEt vous n'avez besoin de les déclarer qu'une seule fois.\n\nC'est probablement l'avantage visible principal de **FastAPI** comparé aux autres frameworks (outre les performances pures).\n"
  },
  {
    "path": "docs/fr/docs/tutorial/query-param-models.md",
    "content": "# Modèles de paramètres de requête { #query-parameter-models }\n\nSi vous avez un groupe de paramètres de requête liés, vous pouvez créer un modèle Pydantic pour les déclarer.\n\nCela vous permet de réutiliser le modèle à plusieurs endroits et aussi de déclarer des validations et des métadonnées pour tous les paramètres en une seule fois. 😎\n\n/// note | Remarque\n\nPris en charge depuis FastAPI version `0.115.0`. 🤓\n\n///\n\n## Déclarer des paramètres de requête avec un modèle Pydantic { #query-parameters-with-a-pydantic-model }\n\nDéclarez les paramètres de requête dont vous avez besoin dans un modèle Pydantic, puis déclarez le paramètre en tant que `Query` :\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\nFastAPI extrait les données pour chaque champ à partir des paramètres de requête de la requête et vous fournit le modèle Pydantic que vous avez défini.\n\n## Consulter les documents { #check-the-docs }\n\nVous pouvez voir les paramètres de requête dans l'interface des documents à `/docs` :\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## Interdire des paramètres de requête supplémentaires { #forbid-extra-query-parameters }\n\nDans certains cas d'utilisation particuliers (probablement peu courants), vous pouvez vouloir restreindre les paramètres de requête que vous souhaitez recevoir.\n\nVous pouvez utiliser la configuration du modèle Pydantic pour `forbid` tout champ `extra` :\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\nSi un client tente d'envoyer des données supplémentaires dans les paramètres de requête, il recevra une réponse d'erreur.\n\nPar exemple, si le client tente d'envoyer un paramètre de requête `tool` avec la valeur `plumbus`, comme :\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\nIl recevra une réponse d'erreur lui indiquant que le paramètre de requête `tool` n'est pas autorisé :\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## Résumé { #summary }\n\nVous pouvez utiliser des modèles Pydantic pour déclarer des paramètres de requête dans FastAPI. 😎\n\n/// tip | Astuce\n\nAlerte spoiler : vous pouvez aussi utiliser des modèles Pydantic pour déclarer des cookies et des en-têtes, mais vous lirez cela plus tard dans le tutoriel. 🤫\n\n///\n"
  },
  {
    "path": "docs/fr/docs/tutorial/query-params-str-validations.md",
    "content": "# Paramètres de requête et validations de chaînes de caractères { #query-parameters-and-string-validations }\n\n**FastAPI** vous permet de déclarer des informations et des validations supplémentaires pour vos paramètres.\n\nPrenons cette application comme exemple :\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\nLe paramètre de requête `q` est de type `str | None`, cela signifie qu’il est de type `str` mais peut aussi être `None`, et en effet, la valeur par défaut est `None`, donc FastAPI saura qu’il n’est pas requis.\n\n/// note | Remarque\n\nFastAPI saura que la valeur de `q` n’est pas requise grâce à la valeur par défaut `= None`.\n\nAvoir `str | None` permettra à votre éditeur de vous offrir un meilleur support et de détecter les erreurs.\n\n///\n\n## Validation additionnelle { #additional-validation }\n\nNous allons imposer que, même si `q` est optionnel, dès qu’il est fourni, **sa longueur n’excède pas 50 caractères**.\n\n### Importer `Query` et `Annotated` { #import-query-and-annotated }\n\nPour ce faire, importez d’abord :\n\n- `Query` depuis `fastapi`\n- `Annotated` depuis `typing`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info\n\nFastAPI a ajouté la prise en charge de `Annotated` (et a commencé à le recommander) dans la version 0.95.0.\n\nSi vous avez une version plus ancienne, vous obtiendrez des erreurs en essayant d’utiliser `Annotated`.\n\nAssurez-vous de [mettre à niveau la version de FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) vers au moins 0.95.1 avant d’utiliser `Annotated`.\n\n///\n\n## Utiliser `Annotated` dans le type pour le paramètre `q` { #use-annotated-in-the-type-for-the-q-parameter }\n\nVous vous souvenez que je vous ai dit plus tôt que `Annotated` peut être utilisé pour ajouter des métadonnées à vos paramètres dans l’[Introduction aux types Python](../python-types.md#type-hints-with-metadata-annotations) ?\n\nC’est le moment de l’utiliser avec FastAPI. 🚀\n\nNous avions cette annotation de type :\n\n```Python\nq: str | None = None\n```\n\nCe que nous allons faire, c’est l’englober avec `Annotated`, de sorte que cela devienne :\n\n```Python\nq: Annotated[str | None] = None\n```\n\nLes deux versions signifient la même chose, `q` est un paramètre qui peut être une `str` ou `None`, et par défaut, c’est `None`.\n\nPassons maintenant aux choses amusantes. 🎉\n\n## Ajouter `Query` à `Annotated` dans le paramètre `q` { #add-query-to-annotated-in-the-q-parameter }\n\nMaintenant que nous avons cet `Annotated` dans lequel nous pouvons mettre plus d’informations (dans ce cas une validation supplémentaire), ajoutez `Query` à l’intérieur de `Annotated`, et définissez le paramètre `max_length` à `50` :\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\nRemarquez que la valeur par défaut est toujours `None`, donc le paramètre est toujours optionnel.\n\nMais maintenant, avec `Query(max_length=50)` à l’intérieur de `Annotated`, nous indiquons à FastAPI que nous voulons **une validation supplémentaire** pour cette valeur, nous voulons qu’elle ait au maximum 50 caractères. 😎\n\n/// tip | Astuce\n\nIci nous utilisons `Query()` parce qu’il s’agit d’un **paramètre de requête**. Plus tard nous verrons d’autres comme `Path()`, `Body()`, `Header()` et `Cookie()`, qui acceptent également les mêmes arguments que `Query()`.\n\n///\n\nFastAPI va maintenant :\n\n- **Valider** les données en s’assurant que la longueur maximale est de 50 caractères\n- Afficher une **erreur claire** au client quand les données ne sont pas valides\n- **Documenter** le paramètre dans la *chemin d'accès* du schéma OpenAPI (il apparaîtra donc dans l’**interface de documentation automatique**)\n\n## Alternative (ancienne) : `Query` comme valeur par défaut { #alternative-old-query-as-the-default-value }\n\nLes versions précédentes de FastAPI (avant <dfn title=\"avant 2023-03\">0.95.0</dfn>) exigeaient d’utiliser `Query` comme valeur par défaut de votre paramètre, au lieu de le mettre dans `Annotated`. Il y a de fortes chances que vous voyiez du code qui l’utilise encore, je vais donc vous l’expliquer.\n\n/// tip | Astuce\n\nPour du nouveau code et dès que possible, utilisez `Annotated` comme expliqué ci-dessus. Il y a de multiples avantages (expliqués ci-dessous) et aucun inconvénient. 🍰\n\n///\n\nVoici comment vous utiliseriez `Query()` comme valeur par défaut du paramètre de votre fonction, en définissant le paramètre `max_length` à 50 :\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\nComme, dans ce cas (sans utiliser `Annotated`), nous devons remplacer la valeur par défaut `None` dans la fonction par `Query()`, nous devons maintenant définir la valeur par défaut avec le paramètre `Query(default=None)`, cela sert le même objectif de définir cette valeur par défaut (au moins pour FastAPI).\n\nDonc :\n\n```Python\nq: str | None = Query(default=None)\n```\n\n... rend le paramètre optionnel, avec une valeur par défaut de `None`, comme :\n\n```Python\nq: str | None = None\n```\n\nMais la version avec `Query` le déclare explicitement comme étant un paramètre de requête.\n\nEnsuite, nous pouvons passer plus de paramètres à `Query`. Dans ce cas, le paramètre `max_length` qui s’applique aux chaînes de caractères :\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\nCela validera les données, affichera une erreur claire lorsque les données ne sont pas valides et documentera le paramètre dans la *chemin d'accès* du schéma OpenAPI.\n\n### `Query` comme valeur par défaut ou dans `Annotated` { #query-as-the-default-value-or-in-annotated }\n\nGardez à l’esprit qu’en utilisant `Query` à l’intérieur de `Annotated`, vous ne pouvez pas utiliser le paramètre `default` de `Query`.\n\nUtilisez à la place la valeur par défaut réelle du paramètre de fonction. Sinon, ce serait incohérent.\n\nPar exemple, ceci n’est pas autorisé :\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n... parce qu’il n’est pas clair si la valeur par défaut doit être « rick » ou « morty ».\n\nDonc, vous utiliseriez (de préférence) :\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n... ou dans des bases de code plus anciennes, vous trouverez :\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### Avantages de `Annotated` { #advantages-of-annotated }\n\n**L’utilisation de `Annotated` est recommandée** plutôt que la valeur par défaut dans les paramètres de fonction, c’est **mieux** pour plusieurs raisons. 🤓\n\nLa valeur **par défaut** du **paramètre de fonction** est la **vraie valeur par défaut**, c’est plus intuitif en Python en général. 😌\n\nVous pouvez **appeler** cette même fonction dans **d’autres endroits** sans FastAPI, et elle **fonctionnera comme prévu**. S’il y a un paramètre **requis** (sans valeur par défaut), votre **éditeur** vous le signalera avec une erreur, **Python** se plaindra aussi si vous l’exécutez sans passer le paramètre requis.\n\nQuand vous n’utilisez pas `Annotated` et utilisez à la place l’**ancienne** méthode avec la **valeur par défaut**, si vous appelez cette fonction sans FastAPI dans **d’autres endroits**, vous devez **penser** à passer les arguments à la fonction pour qu’elle fonctionne correctement, sinon les valeurs seront différentes de ce que vous attendez (par ex. `QueryInfo` ou quelque chose de similaire au lieu d’une `str`). Et votre éditeur ne se plaindra pas, et Python ne se plaindra pas en exécutant cette fonction, seulement quand les opérations internes échoueront.\n\nComme `Annotated` peut avoir plus d’une annotation de métadonnées, vous pouvez maintenant même utiliser la même fonction avec d’autres outils, comme [Typer](https://typer.tiangolo.com/). 🚀\n\n## Ajouter plus de validations { #add-more-validations }\n\nVous pouvez également ajouter un paramètre `min_length` :\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## Ajouter des expressions régulières { #add-regular-expressions }\n\nVous pouvez définir un `pattern` d’<dfn title=\"Une expression régulière, regex ou regexp, est une suite de caractères qui définit un motif de recherche pour les chaînes de caractères.\">expression régulière</dfn> auquel le paramètre doit correspondre :\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\nCe pattern d’expression régulière spécifique vérifie que la valeur reçue pour le paramètre :\n\n- `^` : commence avec les caractères qui suivent, n’a pas de caractères avant.\n- `fixedquery` : a exactement la valeur `fixedquery`.\n- `$` : se termine là, n’a pas d’autres caractères après `fixedquery`.\n\nSi vous vous sentez perdu avec toutes ces idées d’**« expression régulière »**, pas d’inquiétude. C’est un sujet difficile pour beaucoup. Vous pouvez déjà faire beaucoup de choses sans avoir besoin d’expressions régulières.\n\nDésormais, vous savez que, lorsque vous en aurez besoin, vous pourrez les utiliser dans **FastAPI**.\n\n## Valeurs par défaut { #default-values }\n\nVous pouvez, bien sûr, utiliser des valeurs par défaut autres que `None`.\n\nDisons que vous voulez déclarer le paramètre de requête `q` avec un `min_length` de `3`, et avec une valeur par défaut de « fixedquery » :\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | Remarque\n\nAvoir une valeur par défaut de n’importe quel type, y compris `None`, rend le paramètre optionnel (non requis).\n\n///\n\n## Paramètres requis { #required-parameters }\n\nQuand nous n’avons pas besoin de déclarer plus de validations ou de métadonnées, nous pouvons rendre le paramètre de requête `q` requis en n’indiquant simplement pas de valeur par défaut, comme :\n\n```Python\nq: str\n```\n\nau lieu de :\n\n```Python\nq: str | None = None\n```\n\nMais maintenant nous le déclarons avec `Query`, par exemple ainsi :\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\nDonc, lorsque vous avez besoin de déclarer une valeur comme requise tout en utilisant `Query`, vous pouvez simplement ne pas déclarer de valeur par défaut :\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### Requis, peut valoir `None` { #required-can-be-none }\n\nVous pouvez déclarer qu’un paramètre accepte `None`, mais qu’il est tout de même requis. Cela obligerait les clients à envoyer une valeur, même si la valeur est `None`.\n\nPour ce faire, vous pouvez déclarer que `None` est un type valide tout en ne déclarant pas de valeur par défaut :\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## Liste de paramètres de requête / valeurs multiples { #query-parameter-list-multiple-values }\n\nQuand vous définissez un paramètre de requête explicitement avec `Query`, vous pouvez aussi déclarer qu’il reçoit une liste de valeurs, autrement dit, qu’il reçoit des valeurs multiples.\n\nPar exemple, pour déclarer un paramètre de requête `q` qui peut apparaître plusieurs fois dans l’URL, vous pouvez écrire :\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\nEnsuite, avec une URL comme :\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\nvous recevriez les valeurs des multiples paramètres de requête `q` (`foo` et `bar`) dans une `list` Python à l’intérieur de votre fonction de *chemin d'accès*, dans le *paramètre de fonction* `q`.\n\nDonc, la réponse pour cette URL serait :\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | Astuce\n\nPour déclarer un paramètre de requête avec un type `list`, comme dans l’exemple ci-dessus, vous devez explicitement utiliser `Query`, sinon il serait interprété comme faisant partie du corps de la requête.\n\n///\n\nL’interface de documentation interactive de l’API sera mise à jour en conséquence, pour autoriser plusieurs valeurs :\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### Liste de paramètres de requête / valeurs multiples avec valeurs par défaut { #query-parameter-list-multiple-values-with-defaults }\n\nVous pouvez également définir une `list` de valeurs par défaut si aucune n’est fournie :\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\nSi vous allez à :\n\n```\nhttp://localhost:8000/items/\n```\n\nla valeur par défaut de `q` sera : `[\"foo\", \"bar\"]` et votre réponse sera :\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### Utiliser simplement `list` { #using-just-list }\n\nVous pouvez aussi utiliser `list` directement au lieu de `list[str]` :\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | Remarque\n\nGardez à l’esprit que dans ce cas, FastAPI ne vérifiera pas le contenu de la liste.\n\nPar exemple, `list[int]` vérifierait (et documenterait) que le contenu de la liste est composé d’entiers. Mais un simple `list` ne le ferait pas.\n\n///\n\n## Déclarer plus de métadonnées { #declare-more-metadata }\n\nVous pouvez ajouter plus d’informations à propos du paramètre.\n\nCes informations seront incluses dans l’OpenAPI généré et utilisées par les interfaces de documentation et les outils externes.\n\n/// note | Remarque\n\nGardez à l’esprit que différents outils peuvent avoir des niveaux de prise en charge d’OpenAPI différents.\n\nCertains d’entre eux pourraient ne pas encore afficher toutes les informations supplémentaires déclarées, bien que, dans la plupart des cas, la fonctionnalité manquante soit déjà prévue au développement.\n\n///\n\nVous pouvez ajouter un `title` :\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\nEt une `description` :\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## Paramètres avec alias { #alias-parameters }\n\nImaginez que vous vouliez que le paramètre soit `item-query`.\n\nComme dans :\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\nMais `item-query` n’est pas un nom de variable Python valide.\n\nLe plus proche serait `item_query`.\n\nMais vous avez quand même besoin que ce soit exactement `item-query` ...\n\nVous pouvez alors déclarer un `alias`, et cet alias sera utilisé pour trouver la valeur du paramètre :\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## Déprécier des paramètres { #deprecating-parameters }\n\nDisons que vous n’aimez plus ce paramètre.\n\nVous devez le laisser là quelque temps car des clients l’utilisent, mais vous voulez que les documents l’affichent clairement comme <dfn title=\"obsolète, il est recommandé de ne pas l’utiliser\">déprécié</dfn>.\n\nPassez alors le paramètre `deprecated=True` à `Query` :\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\nLes documents l’afficheront ainsi :\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## Exclure des paramètres d’OpenAPI { #exclude-parameters-from-openapi }\n\nPour exclure un paramètre de requête du schéma OpenAPI généré (et donc, des systèmes de documentation automatiques), définissez le paramètre `include_in_schema` de `Query` à `False` :\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## Validation personnalisée { #custom-validation }\n\nIl peut y avoir des cas où vous devez faire une **validation personnalisée** qui ne peut pas être réalisée avec les paramètres montrés ci-dessus.\n\nDans ces cas, vous pouvez utiliser une **fonction de validation personnalisée** qui est appliquée après la validation normale (par ex. après avoir validé que la valeur est une `str`).\n\nVous pouvez y parvenir en utilisant [`AfterValidator` de Pydantic](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) à l’intérieur de `Annotated`.\n\n/// tip | Astuce\n\nPydantic a aussi [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) et d’autres. 🤓\n\n///\n\nPar exemple, ce validateur personnalisé vérifie que l’ID d’item commence par `isbn-` pour un numéro de livre <abbr title=\"International Standard Book Number - Numéro international normalisé du livre\">ISBN</abbr> ou par `imdb-` pour un ID d’URL de film <abbr title=\"Internet Movie Database - Base de données de films sur Internet: un site web contenant des informations sur les films\">IMDB</abbr> :\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info\n\nC’est disponible avec Pydantic version 2 ou supérieure. 😎\n\n///\n\n/// tip | Astuce\n\nSi vous devez faire un type de validation qui nécessite de communiquer avec un **composant externe**, comme une base de données ou une autre API, vous devez plutôt utiliser les **Dépendances de FastAPI**, vous en apprendrez davantage plus tard.\n\nCes validateurs personnalisés sont destinés aux éléments qui peuvent être vérifiés **uniquement** avec les **mêmes données** fournies dans la requête.\n\n///\n\n### Comprendre ce code { #understand-that-code }\n\nLe point important est simplement d’utiliser **`AfterValidator` avec une fonction à l’intérieur de `Annotated`**. N’hésitez pas à passer cette partie. 🤸\n\n---\n\nMais si vous êtes curieux de cet exemple de code spécifique et que vous êtes toujours partant, voici quelques détails supplémentaires.\n\n#### Chaîne avec `value.startswith()` { #string-with-value-startswith }\n\nAvez-vous remarqué ? Une chaîne utilisant `value.startswith()` peut prendre un tuple, et elle vérifiera chaque valeur du tuple :\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### Un élément aléatoire { #a-random-item }\n\nAvec `data.items()` nous obtenons un <dfn title=\"Quelque chose que l’on peut itérer avec une boucle for, comme une liste, un set, etc.\">objet itérable</dfn> avec des tuples contenant la clé et la valeur pour chaque élément du dictionnaire.\n\nNous convertissons cet objet itérable en une `list` propre avec `list(data.items())`.\n\nEnsuite, avec `random.choice()` nous pouvons obtenir une **valeur aléatoire** depuis la liste, nous obtenons donc un tuple `(id, name)`. Ce sera quelque chose comme `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")`.\n\nPuis nous **affectons ces deux valeurs** du tuple aux variables `id` et `name`.\n\nAinsi, si l’utilisateur n’a pas fourni d’ID d’item, il recevra quand même une suggestion aléatoire.\n\n... nous faisons tout cela en **une seule ligne simple**. 🤯 Vous n’adorez pas Python ? 🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## Récapitulatif { #recap }\n\nVous pouvez déclarer des validations et des métadonnées supplémentaires pour vos paramètres.\n\nValidations et métadonnées génériques :\n\n- `alias`\n- `title`\n- `description`\n- `deprecated`\n\nValidations spécifiques aux chaînes :\n\n- `min_length`\n- `max_length`\n- `pattern`\n\nValidations personnalisées avec `AfterValidator`.\n\nDans ces exemples, vous avez vu comment déclarer des validations pour des valeurs `str`.\n\nVoyez les prochains chapitres pour apprendre à déclarer des validations pour d’autres types, comme les nombres.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/query-params.md",
    "content": "# Paramètres de requête { #query-parameters }\n\nQuand vous déclarez d'autres paramètres de fonction qui ne font pas partie des paramètres de chemin, ils sont automatiquement interprétés comme des paramètres de « query ».\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\nLa query est l'ensemble des paires clé-valeur placées après le `?` dans une URL, séparées par des caractères `&`.\n\nPar exemple, dans l'URL :\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n... les paramètres de requête sont :\n\n* `skip` : avec une valeur de `0`\n* `limit` : avec une valeur de `10`\n\nComme ils font partie de l'URL, ce sont « naturellement » des chaînes de caractères.\n\nMais lorsque vous les déclarez avec des types Python (dans l'exemple ci-dessus, en tant que `int`), ils sont convertis vers ce type et validés par rapport à celui-ci.\n\nTous les mêmes processus qui s'appliquaient aux paramètres de chemin s'appliquent aussi aux paramètres de requête :\n\n* Prise en charge de l'éditeur (évidemment)\n* <dfn title=\"conversion de la chaîne provenant d'une requête HTTP en données Python\">« parsing »</dfn> des données\n* Validation des données\n* Documentation automatique\n\n## Valeurs par défaut { #defaults }\n\nComme les paramètres de requête ne sont pas une partie fixe d'un chemin, ils peuvent être optionnels et avoir des valeurs par défaut.\n\nDans l'exemple ci-dessus, ils ont des valeurs par défaut `skip=0` et `limit=10`.\n\nDonc, accéder à l'URL :\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\nserait équivalent à accéder à :\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\nMais si vous accédez, par exemple, à :\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\nLes valeurs des paramètres dans votre fonction seront :\n\n* `skip=20` : car vous l'avez défini dans l'URL\n* `limit=10` : car c'était la valeur par défaut\n\n## Paramètres optionnels { #optional-parameters }\n\nDe la même façon, vous pouvez déclarer des paramètres de requête optionnels, en définissant leur valeur par défaut à `None` :\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\nDans ce cas, le paramètre de fonction `q` sera optionnel et vaudra `None` par défaut.\n\n/// check | Vérifications\n\nNotez également que **FastAPI** est suffisamment intelligent pour remarquer que le paramètre de chemin `item_id` est un paramètre de chemin et que `q` ne l'est pas, c'est donc un paramètre de requête.\n\n///\n\n## Conversion des types des paramètres de requête { #query-parameter-type-conversion }\n\nVous pouvez aussi déclarer des types `bool`, ils seront convertis :\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\nDans ce cas, si vous allez sur :\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\nou\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\nou\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\nou\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\nou\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\nou n'importe quelle autre variation de casse (tout en majuscules, uniquement la première lettre en majuscule, etc.), votre fonction verra le paramètre `short` avec une valeur `bool` à `True`. Sinon la valeur sera à `False`.\n\n## Multiples paramètres de chemin et de requête { #multiple-path-and-query-parameters }\n\nVous pouvez déclarer plusieurs paramètres de chemin et paramètres de requête en même temps, **FastAPI** sait lequel est lequel.\n\nEt vous n'avez pas besoin de les déclarer dans un ordre spécifique.\n\nIls seront détectés par leur nom :\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## Paramètres de requête requis { #required-query-parameters }\n\nQuand vous déclarez une valeur par défaut pour des paramètres qui ne sont pas des paramètres de chemin (pour l'instant, nous n'avons vu que les paramètres de requête), alors ils ne sont pas requis.\n\nSi vous ne voulez pas leur donner de valeur spécifique mais simplement les rendre optionnels, définissez la valeur par défaut à `None`.\n\nMais si vous voulez rendre un paramètre de requête obligatoire, vous pouvez simplement ne déclarer aucune valeur par défaut :\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\nIci, le paramètre de requête `needy` est un paramètre de requête requis de type `str`.\n\nSi vous ouvrez dans votre navigateur une URL comme :\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n... sans ajouter le paramètre requis `needy`, vous verrez une erreur comme :\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\nComme `needy` est un paramètre requis, vous devez le définir dans l'URL :\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n... cela fonctionnerait :\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\nEt bien sûr, vous pouvez définir certains paramètres comme requis, certains avec une valeur par défaut et certains entièrement optionnels :\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\nDans ce cas, il y a 3 paramètres de requête :\n\n* `needy`, un `str` requis.\n* `skip`, un `int` avec une valeur par défaut de `0`.\n* `limit`, un `int` optionnel.\n\n/// tip | Astuce\n\nVous pourriez aussi utiliser des `Enum`s de la même façon qu'avec les [Paramètres de chemin](path-params.md#predefined-values).\n\n///\n"
  },
  {
    "path": "docs/fr/docs/tutorial/request-files.md",
    "content": "# Envoyer des fichiers { #request-files }\n\nVous pouvez définir des fichiers à téléverser par le client en utilisant `File`.\n\n/// info\n\nPour recevoir des fichiers téléversés, installez d'abord [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nAssurez-vous de créer un [environnement virtuel](../virtual-environments.md), de l'activer, puis d'installer le paquet, par exemple :\n\n```console\n$ pip install python-multipart\n```\n\nC'est parce que les fichiers téléversés sont envoyés en « données de formulaire ».\n\n///\n\n## Importer `File` { #import-file }\n\nImportez `File` et `UploadFile` depuis `fastapi` :\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## Définir des paramètres `File` { #define-file-parameters }\n\nCréez des paramètres de fichier de la même manière que pour `Body` ou `Form` :\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info\n\n`File` est une classe qui hérite directement de `Form`.\n\nMais souvenez-vous que lorsque vous importez `Query`, `Path`, `File` et d'autres depuis `fastapi`, ce sont en réalité des fonctions qui renvoient des classes spéciales.\n\n///\n\n/// tip | Astuce\n\nPour déclarer des fichiers dans le corps de la requête, vous devez utiliser `File`, sinon les paramètres seraient interprétés comme des paramètres de requête ou des paramètres de corps (JSON).\n\n///\n\nLes fichiers seront téléversés en « données de formulaire ».\n\nSi vous déclarez le type de votre paramètre de *fonction de chemin d'accès* comme `bytes`, **FastAPI** lira le fichier pour vous et vous recevrez le contenu sous forme de `bytes`.\n\nGardez à l'esprit que cela signifie que tout le contenu sera stocké en mémoire. Cela fonctionnera bien pour de petits fichiers.\n\nMais dans plusieurs cas, vous pourriez bénéficier de l'utilisation d'`UploadFile`.\n\n## Paramètres de fichier avec `UploadFile` { #file-parameters-with-uploadfile }\n\nDéfinissez un paramètre de fichier de type `UploadFile` :\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\nUtiliser `UploadFile` présente plusieurs avantages par rapport à `bytes` :\n\n- Vous n'avez pas besoin d'utiliser `File()` comme valeur par défaut du paramètre.\n- Il utilise un fichier « spooled » :\n    - Un fichier stocké en mémoire jusqu'à une taille maximale, puis, au-delà de cette limite, stocké sur le disque.\n- Cela fonctionne donc bien pour des fichiers volumineux comme des images, des vidéos, de gros binaires, etc., sans consommer toute la mémoire.\n- Vous pouvez obtenir des métadonnées à partir du fichier téléversé.\n- Il offre une interface `async` de type [file-like](https://docs.python.org/3/glossary.html#term-file-like-object).\n- Il expose un véritable objet Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) que vous pouvez passer directement à d'autres bibliothèques qui attendent un objet « file-like ».\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` a les attributs suivants :\n\n- `filename` : une `str` contenant le nom de fichier original téléversé (par ex. `myimage.jpg`).\n- `content_type` : une `str` avec le type de contenu (type MIME / type média) (par ex. `image/jpeg`).\n- `file` : un [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (un objet [file-like](https://docs.python.org/3/glossary.html#term-file-like-object)). C'est l'objet fichier Python réel que vous pouvez passer directement à d'autres fonctions ou bibliothèques qui attendent un objet « file-like ».\n\n`UploadFile` a les méthodes `async` suivantes. Elles appellent toutes les méthodes correspondantes du fichier sous-jacent (en utilisant le `SpooledTemporaryFile` interne).\n\n- `write(data)` : écrit `data` (`str` ou `bytes`) dans le fichier.\n- `read(size)` : lit `size` (`int`) octets/caractères du fichier.\n- `seek(offset)` : se déplace à la position d'octet `offset` (`int`) dans le fichier.\n    - Par ex., `await myfile.seek(0)` irait au début du fichier.\n    - C'est particulièrement utile si vous exécutez `await myfile.read()` une fois puis devez relire le contenu.\n- `close()` : ferme le fichier.\n\nComme toutes ces méthodes sont `async`, vous devez les « await ».\n\nPar exemple, à l'intérieur d'une *fonction de chemin d'accès* `async`, vous pouvez obtenir le contenu avec :\n\n```Python\ncontents = await myfile.read()\n```\n\nSi vous êtes dans une *fonction de chemin d'accès* `def` normale, vous pouvez accéder directement à `UploadFile.file`, par exemple :\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | Détails techniques `async`\n\nLorsque vous utilisez les méthodes `async`, **FastAPI** exécute les méthodes de fichier dans un pool de threads et les attend.\n\n///\n\n/// note | Détails techniques Starlette\n\nL'`UploadFile` de **FastAPI** hérite directement de l'`UploadFile` de **Starlette**, mais ajoute certaines parties nécessaires pour le rendre compatible avec **Pydantic** et les autres parties de FastAPI.\n\n///\n\n## Qu'est-ce que les « données de formulaire » { #what-is-form-data }\n\nLa façon dont les formulaires HTML (`<form></form>`) envoient les données au serveur utilise normalement un encodage « spécial » pour ces données, différent de JSON.\n\n**FastAPI** s'assure de lire ces données au bon endroit plutôt que depuis JSON.\n\n/// note | Détails techniques\n\nLes données des formulaires sont normalement encodées avec le « type de média » `application/x-www-form-urlencoded` lorsqu'elles n'incluent pas de fichiers.\n\nMais lorsque le formulaire inclut des fichiers, il est encodé en `multipart/form-data`. Si vous utilisez `File`, **FastAPI** saura qu'il doit récupérer les fichiers depuis la partie appropriée du corps.\n\nSi vous souhaitez en savoir plus sur ces encodages et les champs de formulaire, consultez la [<abbr title=\"Mozilla Developer Network - Réseau des développeurs Mozilla\">MDN</abbr> Web Docs pour `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Alertes\n\nVous pouvez déclarer plusieurs paramètres `File` et `Form` dans un *chemin d'accès*, mais vous ne pouvez pas également déclarer des champs `Body` que vous vous attendez à recevoir en JSON, car la requête aura le corps encodé en `multipart/form-data` au lieu de `application/json`.\n\nCe n'est pas une limitation de **FastAPI**, cela fait partie du protocole HTTP.\n\n///\n\n## Téléversement de fichier facultatif { #optional-file-upload }\n\nVous pouvez rendre un fichier facultatif en utilisant des annotations de type standard et en définissant une valeur par défaut à `None` :\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## `UploadFile` avec des métadonnées supplémentaires { #uploadfile-with-additional-metadata }\n\nVous pouvez aussi utiliser `File()` avec `UploadFile`, par exemple pour définir des métadonnées supplémentaires :\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## Téléverser plusieurs fichiers { #multiple-file-uploads }\n\nIl est possible de téléverser plusieurs fichiers en même temps.\n\nIls seraient associés au même « champ de formulaire » envoyé en « données de formulaire ».\n\nPour cela, déclarez une `list` de `bytes` ou d'`UploadFile` :\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\nVous recevrez, comme déclaré, une `list` de `bytes` ou d'`UploadFile`.\n\n/// note | Détails techniques\n\nVous pourriez aussi utiliser `from starlette.responses import HTMLResponse`.\n\n**FastAPI** fournit les mêmes `starlette.responses` sous `fastapi.responses` simplement pour votre convenance en tant que développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.\n\n///\n\n### Téléversements multiples avec métadonnées supplémentaires { #multiple-file-uploads-with-additional-metadata }\n\nEt de la même manière que précédemment, vous pouvez utiliser `File()` pour définir des paramètres supplémentaires, même pour `UploadFile` :\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## Récapitulatif { #recap }\n\nUtilisez `File`, `bytes` et `UploadFile` pour déclarer des fichiers à téléverser dans la requête, envoyés en « données de formulaire ».\n"
  },
  {
    "path": "docs/fr/docs/tutorial/request-form-models.md",
    "content": "# Modèles de formulaire { #form-models }\n\nVous pouvez utiliser des **modèles Pydantic** pour déclarer des **champs de formulaire** dans FastAPI.\n\n/// info\n\nPour utiliser les formulaires, installez d'abord [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nAssurez-vous de créer un [environnement virtuel](../virtual-environments.md), de l'activer, puis d'installer le paquet, par exemple :\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note | Remarque\n\nCeci est pris en charge depuis la version `0.113.0` de FastAPI. 🤓\n\n///\n\n## Modèles Pydantic pour les formulaires { #pydantic-models-for-forms }\n\nVous avez simplement besoin de déclarer un **modèle Pydantic** avec les champs que vous souhaitez recevoir comme **champs de formulaire**, puis de déclarer le paramètre comme `Form` :\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI** va **extraire** les données pour **chaque champ** à partir des **données de formulaire** de la requête et vous fournir le modèle Pydantic que vous avez défini.\n\n## Consulter les documents { #check-the-docs }\n\nVous pouvez le vérifier dans l'interface des documents à `/docs` :\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## Interdire les champs de formulaire supplémentaires { #forbid-extra-form-fields }\n\nDans certains cas d'utilisation particuliers (probablement peu courants), vous pourriez vouloir **restreindre** les champs de formulaire à ceux déclarés dans le modèle Pydantic, et **interdire** tout champ **supplémentaire**.\n\n/// note | Remarque\n\nCeci est pris en charge depuis la version `0.114.0` de FastAPI. 🤓\n\n///\n\nVous pouvez utiliser la configuration du modèle Pydantic pour `forbid` tout champ `extra` :\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\nSi un client tente d'envoyer des données supplémentaires, il recevra une **réponse d'erreur**.\n\nPar exemple, si le client essaie d'envoyer les champs de formulaire :\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\nIl recevra une réponse d'erreur lui indiquant que le champ `extra` n'est pas autorisé :\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## Résumer { #summary }\n\nVous pouvez utiliser des modèles Pydantic pour déclarer des champs de formulaire dans FastAPI. 😎\n"
  },
  {
    "path": "docs/fr/docs/tutorial/request-forms-and-files.md",
    "content": "# Utiliser des formulaires et des fichiers de requête { #request-forms-and-files }\n\nVous pouvez définir des fichiers et des champs de formulaire en même temps à l'aide de `File` et `Form`.\n\n/// info\n\nPour recevoir des fichiers téléversés et/ou des données de formulaire, installez d'abord [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nVous devez créer un [environnement virtuel](../virtual-environments.md), l'activer, puis installer ce paquet, par exemple :\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Importer `File` et `Form` { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## Définir des paramètres `File` et `Form` { #define-file-and-form-parameters }\n\nCréez des paramètres de fichier et de formulaire de la même manière que pour `Body` ou `Query` :\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\nLes fichiers et les champs de formulaire seront téléversés en tant que données de formulaire et vous les recevrez.\n\nEt vous pouvez déclarer certains fichiers comme `bytes` et d'autres comme `UploadFile`.\n\n/// warning | Alertes\n\nVous pouvez déclarer plusieurs paramètres `File` et `Form` dans un *chemin d'accès*, mais vous ne pouvez pas aussi déclarer des champs `Body` que vous vous attendez à recevoir en JSON, car la requête aura le corps encodé en `multipart/form-data` au lieu de `application/json`.\n\nCe n'est pas une limitation de **FastAPI**, cela fait partie du protocole HTTP.\n\n///\n\n## Récapitulatif { #recap }\n\nUtilisez `File` et `Form` ensemble lorsque vous devez recevoir des données et des fichiers dans la même requête.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/request-forms.md",
    "content": "# Données de formulaire { #form-data }\n\nLorsque vous devez recevoir des champs de formulaire au lieu de JSON, vous pouvez utiliser `Form`.\n\n/// info\n\nPour utiliser les formulaires, installez d'abord [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nAssurez-vous de créer un [environnement virtuel](../virtual-environments.md), de l'activer, puis installez-le, par exemple :\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Importer `Form` { #import-form }\n\nImportez `Form` depuis `fastapi` :\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## Définir les paramètres `Form` { #define-form-parameters }\n\nCréez des paramètres de formulaire comme vous le feriez pour `Body` ou `Query` :\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\nPar exemple, dans l'une des manières dont la spécification OAuth2 peut être utilisée (appelée « password flow »), il est requis d'envoyer un `username` et un `password` comme champs de formulaire.\n\nLa <dfn title=\"spécification\">spécification</dfn> exige que les champs soient exactement nommés `username` et `password`, et qu'ils soient envoyés en tant que champs de formulaire, pas en JSON.\n\nAvec `Form`, vous pouvez déclarer les mêmes configurations que pour `Body` (ainsi que `Query`, `Path`, `Cookie`), y compris la validation, des exemples, un alias (p. ex. `user-name` au lieu de `username`), etc.\n\n/// info\n\n`Form` est une classe qui hérite directement de `Body`.\n\n///\n\n/// tip | Astuce\n\nPour déclarer des corps de formulaire, vous devez utiliser `Form` explicitement, car sinon les paramètres seraient interprétés comme des paramètres de requête ou des paramètres de corps (JSON).\n\n///\n\n## À propos des « champs de formulaire » { #about-form-fields }\n\nLa manière dont les formulaires HTML (`<form></form>`) envoient les données au serveur utilise normalement un encodage « spécial » pour ces données, différent de JSON.\n\n**FastAPI** s'assure de lire ces données au bon endroit au lieu de JSON.\n\n/// note | Détails techniques\n\nLes données issues des formulaires sont normalement encodées avec le « type de média » `application/x-www-form-urlencoded`.\n\nMais lorsque le formulaire inclut des fichiers, il est encodé en `multipart/form-data`. Vous lirez la gestion des fichiers dans le chapitre suivant.\n\nSi vous voulez en savoir plus sur ces encodages et les champs de formulaire, consultez la [<abbr title=\"Mozilla Developer Network - Réseau des développeurs Mozilla\">MDN</abbr> web docs pour `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Alertes\n\nVous pouvez déclarer plusieurs paramètres `Form` dans un chemin d'accès, mais vous ne pouvez pas aussi déclarer des champs `Body` que vous vous attendez à recevoir en JSON, car la requête aura le corps encodé en `application/x-www-form-urlencoded` au lieu de `application/json`.\n\nCe n'est pas une limitation de **FastAPI**, cela fait partie du protocole HTTP.\n\n///\n\n## Récapitulatif { #recap }\n\nUtilisez `Form` pour déclarer les paramètres d'entrée des données de formulaire.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/response-model.md",
    "content": "# Modèle de réponse - Type de retour { #response-model-return-type }\n\nVous pouvez déclarer le type utilisé pour la réponse en annotant le **type de retour** de la *fonction de chemin d'accès*.\n\nVous pouvez utiliser des **annotations de type** de la même manière que pour les données d'entrée dans les **paramètres** de fonction. Vous pouvez utiliser des modèles Pydantic, des listes, des dictionnaires, des valeurs scalaires comme des entiers, des booléens, etc.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPI utilisera ce type de retour pour :\n\n* **Valider** les données renvoyées.\n    * Si les données sont invalides (par exemple, il manque un champ), cela signifie que le code de *votre* application est défectueux, qu'il ne renvoie pas ce qu'il devrait, et un erreur serveur sera renvoyée au lieu de renvoyer des données incorrectes. De cette façon, vous et vos clients pouvez être certains de recevoir les données attendues et avec la structure attendue.\n* Ajouter un **JSON Schema** pour la réponse, dans l’OpenAPI du *chemin d'accès*.\n    * Ceci sera utilisé par la **documentation automatique**.\n    * Ceci sera également utilisé par les outils de génération automatique de code client.\n* **Sérialiser** les données renvoyées en JSON en utilisant Pydantic, qui est écrit en **Rust**, ce qui sera **beaucoup plus rapide**.\n\nMais surtout :\n\n* Il **limitera et filtrera** les données de sortie à ce qui est défini dans le type de retour.\n    * C'est particulièrement important pour la **sécurité**, nous verrons cela plus bas.\n\n## Paramètre `response_model` { #response-model-parameter }\n\nIl existe des cas où vous devez ou souhaitez renvoyer des données qui ne correspondent pas exactement à ce que déclare le type.\n\nPar exemple, vous pourriez vouloir **renvoyer un dictionnaire** ou un objet de base de données, mais **le déclarer comme un modèle Pydantic**. Ainsi, le modèle Pydantic ferait toute la documentation des données, la validation, etc. pour l'objet que vous avez renvoyé (par exemple un dictionnaire ou un objet de base de données).\n\nSi vous ajoutez l'annotation du type de retour, les outils et éditeurs se plaindront avec une (juste) erreur vous indiquant que votre fonction renvoie un type (par exemple un dict) différent de ce que vous avez déclaré (par exemple un modèle Pydantic).\n\nDans ces cas, vous pouvez utiliser le paramètre `response_model` du *décorateur de chemin d'accès* au lieu du type de retour.\n\nVous pouvez utiliser le paramètre `response_model` dans n'importe lequel des *chemins d'accès* :\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* etc.\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | Remarque\n\nNotez que `response_model` est un paramètre de la méthode « decorator » (`get`, `post`, etc.). Pas de votre *fonction de chemin d'accès*, comme tous les paramètres et le corps.\n\n///\n\n`response_model` reçoit le même type que vous déclareriez pour un champ de modèle Pydantic, il peut donc s'agir d'un modèle Pydantic, mais il peut aussi être, par exemple, une `list` de modèles Pydantic, comme `List[Item]`.\n\nFastAPI utilisera ce `response_model` pour toute la documentation des données, la validation, etc. et aussi pour **convertir et filtrer les données de sortie** selon sa déclaration de type.\n\n/// tip | Astuce\n\nSi vous avez des vérifications de type strictes dans votre éditeur, mypy, etc., vous pouvez déclarer le type de retour de la fonction en `Any`.\n\nAinsi, vous indiquez à l'éditeur que vous renvoyez intentionnellement n'importe quoi. Mais FastAPI effectuera quand même la documentation, la validation, le filtrage, etc. des données avec `response_model`.\n\n///\n\n### Priorité de `response_model` { #response-model-priority }\n\nSi vous déclarez à la fois un type de retour et un `response_model`, c'est `response_model` qui aura la priorité et sera utilisé par FastAPI.\n\nDe cette manière, vous pouvez ajouter des annotations de type correctes à vos fonctions même si vous renvoyez un type différent du modèle de réponse, pour qu'il soit utilisé par l'éditeur et des outils comme mypy. Et vous pouvez toujours laisser FastAPI faire la validation des données, la documentation, etc. avec `response_model`.\n\nVous pouvez également utiliser `response_model=None` pour désactiver la création d’un modèle de réponse pour ce *chemin d'accès* ; vous pourriez en avoir besoin si vous ajoutez des annotations de type pour des choses qui ne sont pas des champs valides Pydantic, vous verrez un exemple de cela dans une des sections ci-dessous.\n\n## Renvoyer les mêmes données d'entrée { #return-the-same-input-data }\n\nIci, nous déclarons un modèle `UserIn`, il contiendra un mot de passe en clair :\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | Info\n\nPour utiliser `EmailStr`, installez d'abord [`email-validator`](https://github.com/JoshData/python-email-validator).\n\nAssurez-vous de créer un [environnement virtuel](../virtual-environments.md), de l'activer, puis de l'installer, par exemple :\n\n```console\n$ pip install email-validator\n```\n\nou avec :\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\nEt nous utilisons ce modèle pour déclarer notre entrée et le même modèle pour déclarer notre sortie :\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\nDésormais, chaque fois qu'un navigateur crée un utilisateur avec un mot de passe, l'API renverra le même mot de passe dans la réponse.\n\nDans ce cas, cela peut ne pas poser de problème, car c'est le même utilisateur qui envoie le mot de passe.\n\nMais si nous utilisons le même modèle pour un autre *chemin d'accès*, nous pourrions envoyer les mots de passe de nos utilisateurs à tous les clients.\n\n/// danger | Danger\n\nNe stockez jamais le mot de passe en clair d'un utilisateur et ne l'envoyez pas dans une réponse de cette manière, à moins de connaître tous les écueils et de savoir exactement ce que vous faites.\n\n///\n\n## Ajouter un modèle de sortie { #add-an-output-model }\n\nNous pouvons à la place créer un modèle d'entrée avec le mot de passe en clair et un modèle de sortie sans celui-ci :\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\nIci, même si notre *fonction de chemin d'accès* renvoie le même utilisateur d'entrée qui contient le mot de passe :\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n... nous avons déclaré `response_model` comme étant notre modèle `UserOut`, qui n'inclut pas le mot de passe :\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\nAinsi, **FastAPI** se chargera de filtrer toutes les données qui ne sont pas déclarées dans le modèle de sortie (en utilisant Pydantic).\n\n### `response_model` ou type de retour { #response-model-or-return-type }\n\nDans ce cas, comme les deux modèles sont différents, si nous annotions le type de retour de la fonction en `UserOut`, l’éditeur et les outils se plaindraient que nous renvoyons un type invalide, car ce sont des classes différentes.\n\nC'est pourquoi, dans cet exemple, nous devons le déclarer dans le paramètre `response_model`.\n\n... mais continuez à lire ci-dessous pour voir comment contourner cela.\n\n## Type de retour et filtrage des données { #return-type-and-data-filtering }\n\nContinuons l'exemple précédent. Nous voulions **annoter la fonction avec un type**, mais nous voulions pouvoir renvoyer depuis la fonction quelque chose qui inclut **plus de données**.\n\nNous voulons que FastAPI continue de **filtrer** les données à l’aide du modèle de réponse. Ainsi, même si la fonction renvoie plus de données, la réponse n’inclura que les champs déclarés dans le modèle de réponse.\n\nDans l'exemple précédent, comme les classes étaient différentes, nous avons dû utiliser le paramètre `response_model`. Mais cela signifie aussi que nous ne bénéficions pas de la prise en charge de l'éditeur et des outils pour la vérification du type de retour de la fonction.\n\nMais dans la plupart des cas où nous avons besoin de quelque chose comme cela, nous voulons que le modèle **filtre/supprime** simplement une partie des données comme dans cet exemple.\n\nEt dans ces cas, nous pouvons utiliser des classes et l'héritage pour tirer parti des **annotations de type** de fonction afin d'obtenir une meilleure prise en charge dans l'éditeur et les outils, tout en bénéficiant du **filtrage de données** de FastAPI.\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\nAvec cela, nous obtenons la prise en charge des outils, des éditeurs et de mypy car ce code est correct en termes de types, et nous bénéficions également du filtrage des données par FastAPI.\n\nComment cela fonctionne-t-il ? Voyons cela. 🤓\n\n### Annotations de type et outils { #type-annotations-and-tooling }\n\nVoyons d'abord comment les éditeurs, mypy et autres outils considèreraient cela.\n\n`BaseUser` a les champs de base. Puis `UserIn` hérite de `BaseUser` et ajoute le champ `password`, il inclura donc tous les champs des deux modèles.\n\nNous annotons le type de retour de la fonction en `BaseUser`, mais nous renvoyons en réalité une instance de `UserIn`.\n\nL’éditeur, mypy et d'autres outils ne s’en plaindront pas car, en termes de typage, `UserIn` est une sous-classe de `BaseUser`, ce qui signifie que c’est un type *valide* lorsque ce qui est attendu est n'importe quoi de type `BaseUser`.\n\n### Filtrage des données par FastAPI { #fastapi-data-filtering }\n\nMaintenant, pour FastAPI, il verra le type de retour et s'assurera que ce que vous renvoyez inclut **uniquement** les champs qui sont déclarés dans le type.\n\nFastAPI fait plusieurs choses en interne avec Pydantic pour s'assurer que ces mêmes règles d'héritage de classes ne sont pas utilisées pour le filtrage des données renvoyées, sinon vous pourriez finir par renvoyer beaucoup plus de données que prévu.\n\nDe cette façon, vous obtenez le meilleur des deux mondes : annotations de type avec **prise en charge par les outils** et **filtrage des données**.\n\n## Le voir dans la documentation { #see-it-in-the-docs }\n\nDans la documentation automatique, vous pouvez vérifier que le modèle d'entrée et le modèle de sortie auront chacun leur propre JSON Schema :\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\nEt les deux modèles seront utilisés pour la documentation API interactive :\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## Autres annotations de type de retour { #other-return-type-annotations }\n\nIl peut y avoir des cas où vous renvoyez quelque chose qui n'est pas un champ Pydantic valide et vous l'annotez dans la fonction, uniquement pour obtenir la prise en charge fournie par les outils (l’éditeur, mypy, etc.).\n\n### Renvoyer directement une Response { #return-a-response-directly }\n\nLe cas le plus courant serait [de renvoyer directement une Response comme expliqué plus loin dans la documentation avancée](../advanced/response-directly.md).\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\nCe cas simple est géré automatiquement par FastAPI car l'annotation du type de retour est la classe (ou une sous-classe de) `Response`.\n\nEt les outils seront également satisfaits car `RedirectResponse` et `JSONResponse` sont des sous-classes de `Response`, donc l'annotation de type est correcte.\n\n### Annoter une sous-classe de Response { #annotate-a-response-subclass }\n\nVous pouvez aussi utiliser une sous-classe de `Response` dans l'annotation de type :\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\nCela fonctionnera également car `RedirectResponse` est une sous-classe de `Response`, et FastAPI gérera automatiquement ce cas simple.\n\n### Annotations de type de retour invalides { #invalid-return-type-annotations }\n\nMais lorsque vous renvoyez un autre objet arbitraire qui n'est pas un type Pydantic valide (par exemple un objet de base de données) et que vous l'annotez ainsi dans la fonction, FastAPI essaiera de créer un modèle de réponse Pydantic à partir de cette annotation de type, et échouera.\n\nIl en serait de même si vous aviez quelque chose comme une <dfn title=\"Une union entre plusieurs types signifie « n'importe lequel de ces types ».\">union</dfn> entre différents types dont un ou plusieurs ne sont pas des types Pydantic valides, par exemple ceci échouerait 💥 :\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n... cela échoue parce que l'annotation de type n'est pas un type Pydantic et n'est pas juste une unique classe `Response` ou une sous-classe, c'est une union (l'un des deux) entre une `Response` et un `dict`.\n\n### Désactiver le modèle de réponse { #disable-response-model }\n\nEn reprenant l'exemple ci-dessus, vous pourriez ne pas vouloir avoir la validation par défaut des données, la documentation, le filtrage, etc. effectués par FastAPI.\n\nMais vous pourriez vouloir tout de même conserver l’annotation du type de retour dans la fonction pour bénéficier de la prise en charge des outils comme les éditeurs et les vérificateurs de type (par exemple mypy).\n\nDans ce cas, vous pouvez désactiver la génération du modèle de réponse en définissant `response_model=None` :\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\nCela fera en sorte que FastAPI ignore la génération du modèle de réponse et vous permettra ainsi d’avoir toutes les annotations de type de retour dont vous avez besoin sans que cela n’affecte votre application FastAPI. 🤓\n\n## Paramètres d'encodage du modèle de réponse { #response-model-encoding-parameters }\n\nVotre modèle de réponse peut avoir des valeurs par défaut, par exemple :\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None` (ou `str | None = None` en Python 3.10) a une valeur par défaut `None`.\n* `tax: float = 10.5` a une valeur par défaut `10.5`.\n* `tags: List[str] = []` a une valeur par défaut de liste vide : `[]`.\n\nmais vous pourriez vouloir les omettre du résultat si elles n'ont pas été réellement stockées.\n\nPar exemple, si vous avez des modèles avec de nombreux attributs optionnels dans une base NoSQL, mais que vous ne voulez pas envoyer de très longues réponses JSON remplies de valeurs par défaut.\n\n### Utiliser le paramètre `response_model_exclude_unset` { #use-the-response-model-exclude-unset-parameter }\n\nVous pouvez définir le paramètre du *décorateur de chemin d'accès* `response_model_exclude_unset=True` :\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\net ces valeurs par défaut ne seront pas incluses dans la réponse, uniquement les valeurs effectivement définies.\n\nAinsi, si vous envoyez une requête à ce *chemin d'accès* pour l'article avec l'ID `foo`, la réponse (sans les valeurs par défaut) sera :\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | Info\n\nVous pouvez également utiliser :\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\ncomme décrit dans [la documentation Pydantic](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict) pour `exclude_defaults` et `exclude_none`.\n\n///\n\n#### Données avec des valeurs pour des champs avec des valeurs par défaut { #data-with-values-for-fields-with-defaults }\n\nMais si vos données ont des valeurs pour les champs du modèle avec des valeurs par défaut, comme l'article avec l'ID `bar` :\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\nelles seront incluses dans la réponse.\n\n#### Données avec les mêmes valeurs que les valeurs par défaut { #data-with-the-same-values-as-the-defaults }\n\nSi les données ont les mêmes valeurs que les valeurs par défaut, comme l'article avec l'ID `baz` :\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nFastAPI est suffisamment intelligent (en fait, Pydantic l’est) pour comprendre que, même si `description`, `tax` et `tags` ont les mêmes valeurs que les valeurs par défaut, elles ont été définies explicitement (au lieu d'être prises depuis les valeurs par défaut).\n\nElles seront donc incluses dans la réponse JSON.\n\n/// tip | Astuce\n\nNotez que les valeurs par défaut peuvent être n'importe quoi, pas seulement `None`.\n\nElles peuvent être une liste (`[]`), un `float` de `10.5`, etc.\n\n///\n\n### `response_model_include` et `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\nVous pouvez également utiliser les paramètres du *décorateur de chemin d'accès* `response_model_include` et `response_model_exclude`.\n\nIls prennent un `set` de `str` avec les noms des attributs à inclure (en omettant le reste) ou à exclure (en incluant le reste).\n\nCela peut être utilisé comme un raccourci rapide si vous n'avez qu'un seul modèle Pydantic et que vous souhaitez supprimer certaines données de la sortie.\n\n/// tip | Astuce\n\nMais il est toujours recommandé d'utiliser les idées ci-dessus, en utilisant plusieurs classes, plutôt que ces paramètres.\n\nEn effet, le JSON Schema généré dans l’OpenAPI de votre application (et la documentation) restera celui du modèle complet, même si vous utilisez `response_model_include` ou `response_model_exclude` pour omettre certains attributs.\n\nCela s'applique également à `response_model_by_alias` qui fonctionne de manière similaire.\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | Astuce\n\nLa syntaxe `{\"name\", \"description\"}` crée un `set` avec ces deux valeurs.\n\nElle est équivalente à `set([\"name\", \"description\"])`.\n\n///\n\n#### Utiliser des `list` au lieu de `set` { #using-lists-instead-of-sets }\n\nSi vous oubliez d'utiliser un `set` et utilisez une `list` ou un `tuple` à la place, FastAPI le convertira quand même en `set` et cela fonctionnera correctement :\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## Récapitulatif { #recap }\n\nUtilisez le paramètre du *décorateur de chemin d'accès* `response_model` pour définir les modèles de réponse et surtout pour garantir que les données privées sont filtrées.\n\nUtilisez `response_model_exclude_unset` pour ne renvoyer que les valeurs définies explicitement.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/response-status-code.md",
    "content": "# Code d'état de la réponse { #response-status-code }\n\nDe la même manière que vous pouvez spécifier un modèle de réponse, vous pouvez également déclarer le code d'état HTTP utilisé pour la réponse avec le paramètre `status_code` dans n'importe lequel des chemins d'accès :\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* etc.\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | Remarque\n\nRemarquez que `status_code` est un paramètre de la méthode « decorator » (`get`, `post`, etc.). Pas de votre fonction de chemin d'accès, comme tous les paramètres et le corps.\n\n///\n\nLe paramètre `status_code` reçoit un nombre correspondant au code d'état HTTP.\n\n/// info\n\n`status_code` peut aussi recevoir un `IntEnum`, comme le [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus) de Python.\n\n///\n\nIl va :\n\n* Renvoyer ce code d'état dans la réponse.\n* Le documenter comme tel dans le schéma OpenAPI (et donc dans les interfaces utilisateur) :\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | Remarque\n\nCertains codes de réponse (voir la section suivante) indiquent que la réponse n'a pas de corps.\n\nFastAPI le sait et produira une documentation OpenAPI indiquant qu'il n'y a pas de corps de réponse.\n\n///\n\n## À propos des codes d'état HTTP { #about-http-status-codes }\n\n/// note | Remarque\n\nSi vous savez déjà ce que sont les codes d'état HTTP, passez à la section suivante.\n\n///\n\nEn HTTP, vous envoyez un code d'état numérique de 3 chiffres dans la réponse.\n\nCes codes d'état ont un nom associé pour les reconnaître, mais la partie importante est le nombre.\n\nEn bref :\n\n* `100 - 199` sont pour « Information ». Vous les utilisez rarement directement. Les réponses avec ces codes d'état ne peuvent pas avoir de corps.\n* **`200 - 299`** sont pour les réponses de « Succès ». Ce sont celles que vous utiliserez le plus.\n    * `200` est le code d'état par défaut, ce qui signifie que tout était « OK ».\n    * Un autre exemple est `201`, « Créé ». Il est couramment utilisé après la création d'un nouvel enregistrement dans la base de données.\n    * Un cas particulier est `204`, « Aucun contenu ». Cette réponse est utilisée lorsqu'il n'y a aucun contenu à renvoyer au client ; la réponse ne doit donc pas avoir de corps.\n* **`300 - 399`** sont pour la « Redirection ». Les réponses avec ces codes d'état peuvent avoir ou non un corps, sauf `304`, « Non modifié », qui ne doit pas en avoir.\n* **`400 - 499`** sont pour les réponses d'« Erreur côté client ». C'est probablement le deuxième type que vous utiliserez le plus.\n    * Un exemple est `404`, pour une réponse « Non trouvé ».\n    * Pour des erreurs génériques du client, vous pouvez simplement utiliser `400`.\n* `500 - 599` sont pour les erreurs côté serveur. Vous ne les utilisez presque jamais directement. Lorsqu'un problème survient quelque part dans le code de votre application ou sur le serveur, il renverra automatiquement l'un de ces codes d'état.\n\n/// tip | Astuce\n\nPour en savoir plus sur chaque code d'état et à quoi il correspond, consultez la [<abbr title=\"Mozilla Developer Network - Réseau des développeurs Mozilla\">MDN</abbr> documentation sur les codes d'état HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).\n\n///\n\n## Raccourci pour se souvenir des noms { #shortcut-to-remember-the-names }\n\nReprenons l'exemple précédent :\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201` est le code d'état pour « Créé ».\n\nMais vous n'avez pas à mémoriser la signification de chacun de ces codes.\n\nVous pouvez utiliser les variables pratiques de `fastapi.status`.\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\nElles ne sont qu'une commodité, elles contiennent le même nombre, mais de cette façon vous pouvez utiliser l'autocomplétion de l'éditeur pour les trouver :\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | Détails techniques\n\nVous pourriez aussi utiliser `from starlette import status`.\n\n**FastAPI** fournit le même `starlette.status` que `fastapi.status`, uniquement pour votre commodité de développeur. Mais cela vient directement de Starlette.\n\n///\n\n## Modifier la valeur par défaut { #changing-the-default }\n\nPlus tard, dans le [Guide utilisateur avancé](../advanced/response-change-status-code.md), vous verrez comment renvoyer un code d'état différent de celui par défaut que vous déclarez ici.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/schema-extra-example.md",
    "content": "# Déclarer des exemples de données de requête { #declare-request-example-data }\n\nVous pouvez déclarer des exemples des données que votre application peut recevoir.\n\nVoici plusieurs façons de le faire.\n\n## Ajouter des données JSON Schema supplémentaires dans les modèles Pydantic { #extra-json-schema-data-in-pydantic-models }\n\nVous pouvez déclarer `examples` pour un modèle Pydantic qui seront ajoutés au JSON Schema généré.\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\nCes informations supplémentaires seront ajoutées telles quelles au **JSON Schema** de sortie pour ce modèle, et elles seront utilisées dans la documentation de l'API.\n\nVous pouvez utiliser l'attribut `model_config` qui accepte un `dict` comme décrit dans [Documentation de Pydantic : Configuration](https://docs.pydantic.dev/latest/api/config/).\n\nVous pouvez définir `\"json_schema_extra\"` avec un `dict` contenant toutes les données supplémentaires que vous souhaitez voir apparaître dans le JSON Schema généré, y compris `examples`.\n\n/// tip | Astuce\n\nVous pouvez utiliser la même technique pour étendre le JSON Schema et ajouter vos propres informations supplémentaires personnalisées.\n\nPar exemple, vous pourriez l'utiliser pour ajouter des métadonnées pour une interface utilisateur frontend, etc.\n\n///\n\n/// info\n\nOpenAPI 3.1.0 (utilisé depuis FastAPI 0.99.0) a ajouté la prise en charge de `examples`, qui fait partie du standard **JSON Schema**.\n\nAvant cela, seule la clé `example` avec un exemple unique était prise en charge. Elle l'est toujours par OpenAPI 3.1.0, mais elle est dépréciée et ne fait pas partie du standard JSON Schema. Vous êtes donc encouragé à migrer de `example` vers `examples`. 🤓\n\nVous pouvez en lire davantage à la fin de cette page.\n\n///\n\n## Arguments supplémentaires de `Field` { #field-additional-arguments }\n\nLorsque vous utilisez `Field()` avec des modèles Pydantic, vous pouvez également déclarer des `examples` supplémentaires :\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## `examples` dans JSON Schema - OpenAPI { #examples-in-json-schema-openapi }\n\nEn utilisant l'un des éléments suivants :\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nvous pouvez également déclarer un groupe de `examples` avec des informations supplémentaires qui seront ajoutées à leurs **JSON Schemas** à l'intérieur d'**OpenAPI**.\n\n### `Body` avec `examples` { #body-with-examples }\n\nIci, nous passons `examples` contenant un exemple des données attendues dans `Body()` :\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### Exemple dans l'interface des documents { #example-in-the-docs-ui }\n\nAvec l'une des méthodes ci-dessus, cela ressemblerait à ceci dans le `/docs` :\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### `Body` avec plusieurs `examples` { #body-with-multiple-examples }\n\nVous pouvez bien sûr aussi passer plusieurs `examples` :\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\nLorsque vous faites cela, les exemples feront partie du **JSON Schema** interne pour ces données de corps.\n\nNéanmoins, <dfn title=\"2023-08-26\">au moment de la rédaction</dfn>, Swagger UI, l'outil chargé d'afficher l'interface des documents, ne prend pas en charge l'affichage de plusieurs exemples pour les données dans **JSON Schema**. Mais lisez ci-dessous pour un contournement.\n\n### `examples` spécifiques à OpenAPI { #openapi-specific-examples }\n\nAvant que **JSON Schema** ne prenne en charge `examples`, OpenAPI prenait déjà en charge un autre champ également appelé `examples`.\n\nCe `examples` **spécifique à OpenAPI** se trouve dans une autre section de la spécification OpenAPI. Il se trouve dans les **détails de chaque *chemin d'accès***, et non à l'intérieur de chaque JSON Schema.\n\nEt Swagger UI prend en charge ce champ particulier `examples` depuis un certain temps. Vous pouvez donc l'utiliser pour **afficher** différents **exemples dans l'interface des documents**.\n\nLa forme de ce champ `examples` spécifique à OpenAPI est un `dict` avec **plusieurs exemples** (au lieu d'une `list`), chacun avec des informations supplémentaires qui seront également ajoutées à **OpenAPI**.\n\nCela ne va pas à l'intérieur de chaque JSON Schema contenu dans OpenAPI, cela se place à l'extérieur, directement dans le *chemin d'accès*.\n\n### Utiliser le paramètre `openapi_examples` { #using-the-openapi-examples-parameter }\n\nVous pouvez déclarer le `examples` spécifique à OpenAPI dans FastAPI avec le paramètre `openapi_examples` pour :\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nLes clés du `dict` identifient chaque exemple, et chaque valeur est un autre `dict`.\n\nChaque `dict` d'exemple spécifique dans `examples` peut contenir :\n\n* `summary` : une courte description de l'exemple.\n* `description` : une description longue qui peut contenir du texte Markdown.\n* `value` : c'est l'exemple réel affiché, par ex. un `dict`.\n* `externalValue` : alternative à `value`, une URL pointant vers l'exemple. Cependant, cela pourrait ne pas être pris en charge par autant d'outils que `value`.\n\nVous pouvez l'utiliser ainsi :\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### Exemples OpenAPI dans l'interface des documents { #openapi-examples-in-the-docs-ui }\n\nAvec `openapi_examples` ajouté à `Body()`, le `/docs` ressemblerait à :\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## Détails techniques { #technical-details }\n\n/// tip | Astuce\n\nSi vous utilisez déjà **FastAPI** en version **0.99.0 ou supérieure**, vous pouvez probablement **passer** ces détails.\n\nIls sont plus pertinents pour les versions plus anciennes, avant que OpenAPI 3.1.0 ne soit disponible.\n\nVous pouvez considérer ceci comme une courte leçon d'histoire d'OpenAPI et de JSON Schema. 🤓\n\n///\n\n/// warning | Alertes\n\nCe sont des détails très techniques au sujet des standards **JSON Schema** et **OpenAPI**.\n\nSi les idées ci-dessus fonctionnent déjà pour vous, cela pourrait suffire, et vous n'avez probablement pas besoin de ces détails, n'hésitez pas à les ignorer.\n\n///\n\nAvant OpenAPI 3.1.0, OpenAPI utilisait une version plus ancienne et modifiée de **JSON Schema**.\n\nJSON Schema n'avait pas `examples`, donc OpenAPI a ajouté son propre champ `example` à sa version modifiée.\n\nOpenAPI a également ajouté les champs `example` et `examples` à d'autres parties de la spécification :\n\n* [`Parameter Object` (dans la spécification)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object) qui était utilisé par les éléments FastAPI :\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object`, dans le champ `content`, sur le `Media Type Object` (dans la spécification)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object) qui était utilisé par les éléments FastAPI :\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info\n\nCe paramètre `examples` ancien et spécifique à OpenAPI est désormais `openapi_examples` depuis FastAPI `0.103.0`.\n\n///\n\n### Le champ `examples` de JSON Schema { #json-schemas-examples-field }\n\nEnsuite, JSON Schema a ajouté un champ [`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5) dans une nouvelle version de la spécification.\n\nPuis le nouveau OpenAPI 3.1.0 s'est basé sur la dernière version (JSON Schema 2020-12) qui incluait ce nouveau champ `examples`.\n\nEt désormais, ce nouveau champ `examples` a priorité sur l'ancien champ unique (et personnalisé) `example`, qui est maintenant déprécié.\n\nCe nouveau champ `examples` dans JSON Schema est **juste une `list`** d'exemples, et non pas un dict avec des métadonnées supplémentaires comme dans les autres endroits d'OpenAPI (décrits ci-dessus).\n\n/// info\n\nMême après la sortie d'OpenAPI 3.1.0 avec cette nouvelle intégration plus simple avec JSON Schema, pendant un temps, Swagger UI, l'outil qui fournit la documentation automatique, ne prenait pas en charge OpenAPI 3.1.0 (il le fait depuis la version 5.0.0 🎉).\n\nÀ cause de cela, les versions de FastAPI antérieures à 0.99.0 utilisaient encore des versions d'OpenAPI inférieures à 3.1.0.\n\n///\n\n### `examples` avec Pydantic et FastAPI { #pydantic-and-fastapi-examples }\n\nLorsque vous ajoutez `examples` dans un modèle Pydantic, en utilisant `schema_extra` ou `Field(examples=[\"something\"])`, cet exemple est ajouté au **JSON Schema** de ce modèle Pydantic.\n\nEt ce **JSON Schema** du modèle Pydantic est inclus dans l'**OpenAPI** de votre API, puis il est utilisé dans l'interface de la documentation.\n\nDans les versions de FastAPI antérieures à 0.99.0 (0.99.0 et supérieures utilisent le nouveau OpenAPI 3.1.0), lorsque vous utilisiez `example` ou `examples` avec l'une des autres utilitaires (`Query()`, `Body()`, etc.), ces exemples n'étaient pas ajoutés au JSON Schema qui décrit ces données (pas même à la version de JSON Schema propre à OpenAPI), ils étaient ajoutés directement à la déclaration du *chemin d'accès* dans OpenAPI (en dehors des parties d'OpenAPI qui utilisent JSON Schema).\n\nMais maintenant que FastAPI 0.99.0 et supérieures utilisent OpenAPI 3.1.0, qui utilise JSON Schema 2020-12, et Swagger UI 5.0.0 et supérieures, tout est plus cohérent et les exemples sont inclus dans JSON Schema.\n\n### Swagger UI et `examples` spécifiques à OpenAPI { #swagger-ui-and-openapi-specific-examples }\n\nComme Swagger UI ne prenait pas en charge plusieurs exemples JSON Schema (au 2023-08-26), les utilisateurs n'avaient pas de moyen d'afficher plusieurs exemples dans les documents.\n\nPour résoudre cela, FastAPI `0.103.0` a **ajouté la prise en charge** de la déclaration du même ancien champ `examples` **spécifique à OpenAPI** avec le nouveau paramètre `openapi_examples`. 🤓\n\n### Résumé { #summary }\n\nJe disais que je n'aimais pas trop l'histoire ... et me voilà maintenant à donner des leçons d'« tech history ». 😅\n\nEn bref, **mettez à niveau vers FastAPI 0.99.0 ou supérieur**, et les choses sont bien plus **simples, cohérentes et intuitives**, et vous n'avez pas besoin de connaître tous ces détails historiques. 😎\n"
  },
  {
    "path": "docs/fr/docs/tutorial/security/first-steps.md",
    "content": "# Sécurité - Premiers pas { #security-first-steps }\n\nImaginons que vous ayez votre API de **backend** sur un certain domaine.\n\nEt vous avez un **frontend** sur un autre domaine ou dans un chemin différent du même domaine (ou dans une application mobile).\n\nEt vous voulez que le **frontend** puisse s'authentifier auprès du **backend**, en utilisant un **username** et un **password**.\n\nNous pouvons utiliser **OAuth2** pour construire cela avec **FastAPI**.\n\nMais épargnons-vous le temps de lire toute la spécification complète juste pour trouver les petites informations dont vous avez besoin.\n\nUtilisons les outils fournis par **FastAPI** pour gérer la sécurité.\n\n## Voir à quoi cela ressemble { #how-it-looks }\n\nCommençons par utiliser le code et voir comment cela fonctionne, puis nous reviendrons pour comprendre ce qui se passe.\n\n## Créer `main.py` { #create-main-py }\n\nCopiez l'exemple dans un fichier `main.py` :\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## Exécuter { #run-it }\n\n/// info\n\nLe package [`python-multipart`](https://github.com/Kludex/python-multipart) est installé automatiquement avec **FastAPI** lorsque vous exécutez la commande `pip install \"fastapi[standard]\"`.\n\nCependant, si vous utilisez la commande `pip install fastapi`, le package `python-multipart` n'est pas inclus par défaut.\n\nPour l'installer manuellement, vous devez vous assurer de créer un [environnement virtuel](../../virtual-environments.md), de l'activer, puis de l'installer avec :\n\n```console\n$ pip install python-multipart\n```\n\nCela est dû au fait que **OAuth2** utilise des « form data » pour envoyer le `username` et le `password`.\n\n///\n\nExécutez l'exemple avec :\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## Vérifier { #check-it }\n\nAllez à la documentation interactive à l'adresse : [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVous verrez quelque chose comme ceci :\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Bouton « Authorize » !\n\nVous avez déjà un tout nouveau bouton « Authorize ».\n\nEt votre *chemin d'accès* a un petit cadenas dans le coin supérieur droit sur lequel vous pouvez cliquer.\n\n///\n\nEt si vous cliquez dessus, vous obtenez un petit formulaire d'autorisation pour saisir un `username` et un `password` (et d'autres champs optionnels) :\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | Remarque\n\nPeu importe ce que vous saisissez dans le formulaire, cela ne fonctionnera pas encore. Mais nous y viendrons.\n\n///\n\nCe n'est bien sûr pas le frontend pour les utilisateurs finaux, mais c'est un excellent outil automatique pour documenter de manière interactive toute votre API.\n\nIl peut être utilisé par l'équipe frontend (qui peut aussi être vous-même).\n\nIl peut être utilisé par des applications et des systèmes tiers.\n\nEt il peut aussi être utilisé par vous-même, pour déboguer, vérifier et tester la même application.\n\n## Le flux `password` { #the-password-flow }\n\nRevenons un peu en arrière et comprenons de quoi il s'agit.\n\nLe « flux » `password` est l'une des manières (« flows ») définies dans OAuth2 pour gérer la sécurité et l'authentification.\n\nOAuth2 a été conçu pour que le backend ou l'API puisse être indépendant du serveur qui authentifie l'utilisateur.\n\nMais dans ce cas, la même application **FastAPI** gérera l'API et l'authentification.\n\nVoyons cela selon ce point de vue simplifié :\n\n- L'utilisateur saisit le `username` et le `password` dans le frontend, puis appuie sur Entrée.\n- Le frontend (exécuté dans le navigateur de l'utilisateur) envoie ce `username` et ce `password` vers une URL spécifique de notre API (déclarée avec `tokenUrl=\"token\"`).\n- L'API vérifie ce `username` et ce `password`, et répond avec un « token » (nous n'avons encore rien implémenté de tout cela).\n    - Un « token » n'est qu'une chaîne contenant des informations que nous pouvons utiliser plus tard pour vérifier cet utilisateur.\n    - Normalement, un token est configuré pour expirer après un certain temps.\n        - Ainsi, l'utilisateur devra se reconnecter à un moment donné.\n        - Et si le token est volé, le risque est moindre. Ce n'est pas une clé permanente qui fonctionnerait indéfiniment (dans la plupart des cas).\n- Le frontend stocke ce token temporairement quelque part.\n- L'utilisateur clique dans le frontend pour aller vers une autre section de l'application web frontend.\n- Le frontend doit récupérer d'autres données depuis l'API.\n    - Mais cela nécessite une authentification pour cet endpoint spécifique.\n    - Donc, pour s'authentifier auprès de notre API, il envoie un en-tête `Authorization` avec une valeur `Bearer ` suivie du token.\n    - Si le token contient `foobar`, le contenu de l'en-tête `Authorization` serait : `Bearer foobar`.\n\n## Le `OAuth2PasswordBearer` de **FastAPI** { #fastapis-oauth2passwordbearer }\n\n**FastAPI** fournit plusieurs outils, à différents niveaux d'abstraction, pour implémenter ces fonctionnalités de sécurité.\n\nDans cet exemple, nous allons utiliser **OAuth2**, avec le flux **Password**, en utilisant un token **Bearer**. Nous le faisons avec la classe `OAuth2PasswordBearer`.\n\n/// info\n\nUn token « bearer » n'est pas la seule option.\n\nMais c'est la meilleure pour notre cas d'utilisation.\n\nEt cela pourrait être la meilleure pour la plupart des cas, sauf si vous êtes expert en OAuth2 et savez exactement pourquoi une autre option convient mieux à vos besoins.\n\nDans ce cas, **FastAPI** vous fournit aussi les outils pour la construire.\n\n///\n\nLorsque nous créons une instance de la classe `OAuth2PasswordBearer`, nous passons le paramètre `tokenUrl`. Ce paramètre contient l'URL que le client (le frontend s'exécutant dans le navigateur de l'utilisateur) utilisera pour envoyer le `username` et le `password` afin d'obtenir un token.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip | Astuce\n\nIci `tokenUrl=\"token\"` fait référence à une URL relative `token` que nous n'avons pas encore créée. Comme c'est une URL relative, elle est équivalente à `./token`.\n\nParce que nous utilisons une URL relative, si votre API se trouvait à `https://example.com/`, alors elle ferait référence à `https://example.com/token`. Mais si votre API se trouvait à `https://example.com/api/v1/`, alors elle ferait référence à `https://example.com/api/v1/token`.\n\nUtiliser une URL relative est important pour vous assurer que votre application continue de fonctionner même dans un cas d'usage avancé comme [Derrière un proxy](../../advanced/behind-a-proxy.md).\n\n///\n\nCe paramètre ne crée pas cet endpoint / *chemin d'accès*, mais déclare que l'URL `/token` sera celle que le client doit utiliser pour obtenir le token. Cette information est utilisée dans OpenAPI, puis dans les systèmes de documentation API interactifs.\n\nNous créerons bientôt aussi le véritable chemin d'accès.\n\n/// info\n\nSi vous êtes un « Pythonista » très strict, vous pourriez ne pas apprécier le style du nom de paramètre `tokenUrl` au lieu de `token_url`.\n\nC'est parce qu'il utilise le même nom que dans la spécification OpenAPI. Ainsi, si vous devez approfondir l'un de ces schémas de sécurité, vous pouvez simplement copier-coller pour trouver plus d'informations à ce sujet.\n\n///\n\nLa variable `oauth2_scheme` est une instance de `OAuth2PasswordBearer`, mais c'est aussi un « callable ».\n\nElle pourrait être appelée ainsi :\n\n```Python\noauth2_scheme(some, parameters)\n```\n\nAinsi, elle peut être utilisée avec `Depends`.\n\n### Utiliser { #use-it }\n\nVous pouvez maintenant passer ce `oauth2_scheme` en dépendance avec `Depends`.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nCette dépendance fournira une `str` qui est affectée au paramètre `token` de la fonction de *chemin d'accès*.\n\n**FastAPI** saura qu'il peut utiliser cette dépendance pour définir un « schéma de sécurité » dans le schéma OpenAPI (et la documentation API automatique).\n\n/// info | Détails techniques\n\n**FastAPI** saura qu'il peut utiliser la classe `OAuth2PasswordBearer` (déclarée dans une dépendance) pour définir le schéma de sécurité dans OpenAPI parce qu'elle hérite de `fastapi.security.oauth2.OAuth2`, qui hérite à son tour de `fastapi.security.base.SecurityBase`.\n\nTous les utilitaires de sécurité qui s'intègrent à OpenAPI (et à la documentation API automatique) héritent de `SecurityBase`, c'est ainsi que **FastAPI** sait comment les intégrer dans OpenAPI.\n\n///\n\n## Ce que cela fait { #what-it-does }\n\nIl va chercher dans la requête cet en-tête `Authorization`, vérifier si la valeur est `Bearer ` plus un token, et renverra le token en tant que `str`.\n\nS'il ne voit pas d'en-tête `Authorization`, ou si la valeur n'a pas de token `Bearer `, il répondra directement avec une erreur de code d'état 401 (`UNAUTHORIZED`).\n\nVous n'avez même pas à vérifier si le token existe pour renvoyer une erreur. Vous pouvez être sûr que si votre fonction est exécutée, elle aura une `str` dans ce token.\n\nVous pouvez déjà l'essayer dans la documentation interactive :\n\n<img src=\"/img/tutorial/security/image03.png\">\n\nNous ne vérifions pas encore la validité du token, mais c'est déjà un début.\n\n## Récapitulatif { #recap }\n\nAinsi, en seulement 3 ou 4 lignes supplémentaires, vous disposez déjà d'une forme primitive de sécurité.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/security/get-current-user.md",
    "content": "# Obtenir l'utilisateur actuel { #get-current-user }\n\nDans le chapitre précédent, le système de sécurité (basé sur le système d'injection de dépendances) fournissait à la *fonction de chemin d'accès* un `token` en tant que `str` :\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nMais ce n'est pas encore très utile.\n\nFaisons en sorte qu'il nous fournisse l'utilisateur actuel.\n\n## Créer un modèle d'utilisateur { #create-a-user-model }\n\nCommençons par créer un modèle d'utilisateur Pydantic.\n\nDe la même manière que nous utilisons Pydantic pour déclarer des corps de requête, nous pouvons l'utiliser ailleurs :\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## Créer une dépendance `get_current_user` { #create-a-get-current-user-dependency }\n\nCréons une dépendance `get_current_user`.\n\nRappelez-vous que les dépendances peuvent avoir des sous-dépendances ?\n\n`get_current_user` aura une dépendance avec le même `oauth2_scheme` que nous avons créé précédemment.\n\nComme nous le faisions auparavant directement dans le *chemin d'accès*, notre nouvelle dépendance `get_current_user` recevra un `token` en tant que `str` de la sous-dépendance `oauth2_scheme` :\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## Récupérer l'utilisateur { #get-the-user }\n\n`get_current_user` utilisera une fonction utilitaire (factice) que nous avons créée, qui prend un token en `str` et retourne notre modèle Pydantic `User` :\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## Injecter l'utilisateur actuel { #inject-the-current-user }\n\nNous pouvons donc utiliser le même `Depends` avec notre `get_current_user` dans le *chemin d'accès* :\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\nRemarquez que nous déclarons le type de `current_user` comme le modèle Pydantic `User`.\n\nCela nous aidera dans la fonction avec toute l'autocomplétion et les vérifications de type.\n\n/// tip | Astuce\n\nVous vous souvenez peut-être que les corps de requête sont également déclarés avec des modèles Pydantic.\n\nIci, **FastAPI** ne s'y trompera pas car vous utilisez `Depends`.\n\n///\n\n/// check | Vérifications\n\nLa manière dont ce système de dépendances est conçu nous permet d'avoir différentes dépendances (différents « dependables ») qui retournent toutes un modèle `User`.\n\nNous ne sommes pas limités à une seule dépendance pouvant retourner ce type de données.\n\n///\n\n## Autres modèles { #other-models }\n\nVous pouvez maintenant obtenir l'utilisateur actuel directement dans les *fonctions de chemin d'accès* et gérer les mécanismes de sécurité au niveau de l'**Injection de dépendances**, en utilisant `Depends`.\n\nEt vous pouvez utiliser n'importe quel modèle ou données pour les exigences de sécurité (dans ce cas, un modèle Pydantic `User`).\n\nMais vous n'êtes pas limité à un modèle, une classe ou un type de données spécifique.\n\nVoulez-vous avoir un `id` et `email` et ne pas avoir de `username` dans votre modèle ? Bien sûr. Vous pouvez utiliser ces mêmes outils.\n\nVoulez-vous simplement avoir un `str` ? Ou juste un `dict` ? Ou directement une instance d'un modèle de classe de base de données ? Tout fonctionne de la même manière.\n\nVous n'avez en fait pas d'utilisateurs qui se connectent à votre application, mais des robots, bots ou d'autres systèmes, qui n'ont qu'un jeton d'accès ? Là encore, tout fonctionne de la même façon.\n\nUtilisez simplement tout type de modèle, toute sorte de classe, tout type de base de données dont vous avez besoin pour votre application. **FastAPI** vous couvre avec le système d'injection de dépendances.\n\n## Taille du code { #code-size }\n\nCet exemple peut sembler verbeux. Gardez à l'esprit que nous mélangeons sécurité, modèles de données, fonctions utilitaires et *chemins d'accès* dans le même fichier.\n\nMais voici le point clé.\n\nLa partie sécurité et injection de dépendances est écrite une seule fois.\n\nEt vous pouvez la rendre aussi complexe que vous le souhaitez. Et malgré tout, ne l'écrire qu'une seule fois, en un seul endroit. Avec toute la flexibilité.\n\nMais vous pouvez avoir des milliers d'endpoints (*chemins d'accès*) utilisant le même système de sécurité.\n\nEt tous (ou seulement une partie d'entre eux, si vous le souhaitez) peuvent profiter de la réutilisation de ces dépendances ou de toute autre dépendance que vous créez.\n\nEt tous ces milliers de *chemins d'accès* peuvent tenir en seulement 3 lignes :\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## Récapitulatif { #recap }\n\nVous pouvez désormais obtenir l'utilisateur actuel directement dans votre *fonction de chemin d'accès*.\n\nNous avons déjà fait la moitié du chemin.\n\nIl nous suffit d'ajouter un *chemin d'accès* pour que l'utilisateur/client envoie effectivement le `username` et le `password`.\n\nC'est pour la suite.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/security/index.md",
    "content": "# Sécurité { #security }\n\nIl existe de nombreuses façons de gérer la sécurité, l'authentification et l'autorisation.\n\nEt c'est normalement un sujet complexe et « difficile ».\n\nDans de nombreux frameworks et systèmes, le simple fait de gérer la sécurité et l'authentification demande beaucoup d'efforts et de code (dans de nombreux cas, cela peut représenter 50 % ou plus de tout le code écrit).\n\n**FastAPI** fournit plusieurs outils pour vous aider à gérer la **Sécurité** facilement, rapidement, de manière standard, sans avoir à étudier et apprendre toutes les spécifications de sécurité.\n\nMais d'abord, voyons quelques notions.\n\n## Pressé ? { #in-a-hurry }\n\nSi ces termes ne vous intéressent pas et que vous avez simplement besoin d'ajouter une sécurité avec une authentification basée sur un nom d'utilisateur et un mot de passe immédiatement, passez aux chapitres suivants.\n\n## OAuth2 { #oauth2 }\n\nOAuth2 est une spécification qui définit plusieurs façons de gérer l'authentification et l'autorisation.\n\nC'est une spécification assez vaste qui couvre plusieurs cas d'utilisation complexes.\n\nElle inclut des moyens de s'authentifier en utilisant un « tiers ».\n\nC'est ce que tous les systèmes avec « connexion avec Facebook, Google, X (Twitter), GitHub » utilisent en arrière-plan.\n\n### OAuth 1 { #oauth-1 }\n\nIl y a eu un OAuth 1, très différent d'OAuth2, et plus complexe, car il incluait des spécifications directes sur la manière de chiffrer la communication.\n\nIl n'est plus très populaire ni utilisé de nos jours.\n\nOAuth2 ne spécifie pas comment chiffrer la communication ; il suppose que votre application est servie en HTTPS.\n\n/// tip | Astuce\n\nDans la section sur le déploiement, vous verrez comment configurer HTTPS gratuitement, en utilisant Traefik et Let's Encrypt.\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect est une autre spécification, basée sur **OAuth2**.\n\nElle étend simplement OAuth2 en précisant certains points relativement ambigus dans OAuth2, afin d'essayer de la rendre plus interopérable.\n\nPar exemple, la connexion Google utilise OpenID Connect (qui, en arrière-plan, utilise OAuth2).\n\nMais la connexion Facebook ne prend pas en charge OpenID Connect. Elle a sa propre variante d'OAuth2.\n\n### OpenID (pas « OpenID Connect ») { #openid-not-openid-connect }\n\nIl y avait aussi une spécification « OpenID ». Elle essayait de résoudre la même chose qu'**OpenID Connect**, mais n'était pas basée sur OAuth2.\n\nC'était donc un système totalement distinct.\n\nIl n'est plus très populaire ni utilisé de nos jours.\n\n## OpenAPI { #openapi }\n\nOpenAPI (précédemment connu sous le nom de Swagger) est la spécification ouverte pour construire des API (désormais partie de la Linux Foundation).\n\n**FastAPI** est basé sur **OpenAPI**.\n\nC'est ce qui rend possibles plusieurs interfaces de documentation interactive automatiques, la génération de code, etc.\n\nOpenAPI propose une manière de définir plusieurs « schémas » de sécurité.\n\nEn les utilisant, vous pouvez tirer parti de tous ces outils basés sur des standards, y compris ces systèmes de documentation interactive.\n\nOpenAPI définit les schémas de sécurité suivants :\n\n* `apiKey` : une clé spécifique à l'application qui peut provenir :\n    * D'un paramètre de requête.\n    * D'un en-tête.\n    * D'un cookie.\n* `http` : des systèmes d'authentification HTTP standards, notamment :\n    * `bearer` : un en-tête `Authorization` avec une valeur `Bearer ` plus un jeton. Hérité d'OAuth2.\n    * Authentification HTTP Basic.\n    * HTTP Digest, etc.\n* `oauth2` : toutes les méthodes OAuth2 pour gérer la sécurité (appelées « flows »).\n    * Plusieurs de ces flows conviennent pour construire un fournisseur d'authentification OAuth 2.0 (comme Google, Facebook, X (Twitter), GitHub, etc.) :\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * Mais il existe un « flow » spécifique qui peut parfaitement être utilisé pour gérer l'authentification directement dans la même application :\n        * `password` : certains des prochains chapitres couvriront des exemples à ce sujet.\n* `openIdConnect` : propose un moyen de définir comment découvrir automatiquement les données d'authentification OAuth2.\n    * Cette découverte automatique est ce qui est défini dans la spécification OpenID Connect.\n\n\n/// tip | Astuce\n\nIntégrer d'autres fournisseurs d'authentification/autorisation comme Google, Facebook, X (Twitter), GitHub, etc. est également possible et relativement facile.\n\nLe problème le plus complexe est de construire un fournisseur d'authentification/autorisation comme ceux-là, mais **FastAPI** vous donne les outils pour le faire facilement, tout en effectuant le gros du travail pour vous.\n\n///\n\n## Outils **FastAPI** { #fastapi-utilities }\n\nFastAPI propose plusieurs outils pour chacun de ces schémas de sécurité dans le module fastapi.security qui simplifient l'utilisation de ces mécanismes de sécurité.\n\nDans les prochains chapitres, vous verrez comment ajouter de la sécurité à votre API en utilisant ces outils fournis par **FastAPI**.\n\nEt vous verrez aussi comment cela s'intègre automatiquement au système de documentation interactive.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/security/oauth2-jwt.md",
    "content": "# OAuth2 avec mot de passe (et hachage), Bearer avec des jetons JWT { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\nMaintenant que nous avons tout le flux de sécurité, rendons réellement l'application sécurisée, en utilisant des jetons <abbr title=\"JSON Web Tokens\">JWT</abbr> et un hachage de mot de passe sécurisé.\n\nCe code est utilisable dans votre application, enregistrez les hachages de mots de passe dans votre base de données, etc.\n\nNous allons repartir d'où nous nous sommes arrêtés dans le chapitre précédent et l'enrichir.\n\n## À propos de JWT { #about-jwt }\n\nJWT signifie « JSON Web Tokens ».\n\nC'est une norme pour coder un objet JSON dans une longue chaîne compacte sans espaces. Cela ressemble à ceci :\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\nIl n'est pas chiffré ; ainsi, n'importe qui peut récupérer les informations à partir de son contenu.\n\nMais il est signé. Ainsi, quand vous recevez un jeton que vous avez émis, vous pouvez vérifier que vous l'avez bien émis.\n\nDe cette façon, vous pouvez créer un jeton avec une expiration d'une semaine, par exemple. Et quand l'utilisateur revient le lendemain avec ce jeton, vous savez qu'il est toujours connecté à votre système.\n\nAprès une semaine, le jeton aura expiré et l'utilisateur ne sera pas autorisé et devra se reconnecter pour obtenir un nouveau jeton. Et si l'utilisateur (ou un tiers) essayait de modifier le jeton pour changer l'expiration, vous pourriez le détecter, car les signatures ne correspondraient pas.\n\nSi vous voulez expérimenter avec des jetons JWT et voir comment ils fonctionnent, consultez [https://jwt.io](https://jwt.io/).\n\n## Installer `PyJWT` { #install-pyjwt }\n\nNous devons installer `PyJWT` pour générer et vérifier les jetons JWT en Python.\n\nAssurez-vous de créer un [environnement virtuel](../../virtual-environments.md), de l'activer, puis d'installer `pyjwt` :\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info\n\nSi vous prévoyez d'utiliser des algorithmes de signature numérique comme RSA ou ECDSA, vous devez installer la dépendance de bibliothèque de cryptographie `pyjwt[crypto]`.\n\nVous pouvez en lire davantage dans la [documentation d'installation de PyJWT](https://pyjwt.readthedocs.io/en/latest/installation.html).\n\n///\n\n## Hachage de mot de passe { #password-hashing }\n\n« Hachage » signifie convertir un contenu (un mot de passe dans ce cas) en une séquence d'octets (juste une chaîne) qui ressemble à du charabia.\n\nChaque fois que vous fournissez exactement le même contenu (exactement le même mot de passe), vous obtenez exactement le même charabia.\n\nMais vous ne pouvez pas convertir le charabia en sens inverse vers le mot de passe.\n\n### Pourquoi utiliser le hachage de mot passe { #why-use-password-hashing }\n\nSi votre base de données est volée, le voleur n'aura pas les mots de passe en clair de vos utilisateurs, seulement les hachages.\n\nAinsi, le voleur ne pourra pas essayer d'utiliser ce mot de passe dans un autre système (comme beaucoup d'utilisateurs utilisent le même mot de passe partout, ce serait dangereux).\n\n## Installer `pwdlib` { #install-pwdlib }\n\npwdlib est un excellent package Python pour gérer les hachages de mots de passe.\n\nIl prend en charge de nombreux algorithmes de hachage sécurisés et des utilitaires pour travailler avec eux.\n\nL'algorithme recommandé est « Argon2 ».\n\nAssurez-vous de créer un [environnement virtuel](../../virtual-environments.md), de l'activer, puis d'installer pwdlib avec Argon2 :\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | Astuce\n\nAvec `pwdlib`, vous pouvez même le configurer pour pouvoir lire des mots de passe créés par **Django**, un plug-in de sécurité **Flask** ou bien d'autres.\n\nAinsi, vous seriez par exemple en mesure de partager les mêmes données d'une application Django dans une base de données avec une application FastAPI. Ou de migrer progressivement une application Django en utilisant la même base de données.\n\nEt vos utilisateurs pourraient se connecter depuis votre application Django ou depuis votre application **FastAPI**, en même temps.\n\n///\n\n## Hacher et vérifier les mots de passe { #hash-and-verify-the-passwords }\n\nImportez les outils nécessaires depuis `pwdlib`.\n\nCréez une instance PasswordHash avec les réglages recommandés ; elle sera utilisée pour hacher et vérifier les mots de passe.\n\n/// tip | Astuce\n\npwdlib prend également en charge l'algorithme de hachage bcrypt, mais n'inclut pas les algorithmes hérités. Pour travailler avec des hachages obsolètes, il est recommandé d'utiliser la bibliothèque passlib.\n\nPar exemple, vous pourriez l'utiliser pour lire et vérifier des mots de passe générés par un autre système (comme Django), mais hacher tous les nouveaux mots de passe avec un autre algorithme comme Argon2 ou Bcrypt.\n\nEt rester compatible avec tous en même temps.\n\n///\n\nCréez une fonction utilitaire pour hacher un mot de passe fourni par l'utilisateur.\n\nEt une autre pour vérifier si un mot de passe reçu correspond au hachage stocké.\n\nEt une autre pour authentifier et renvoyer un utilisateur.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\nLorsque `authenticate_user` est appelée avec un nom d'utilisateur qui n'existe pas dans la base de données, nous exécutons tout de même `verify_password` contre un hachage factice.\n\nCela garantit que le point de terminaison met approximativement le même temps à répondre que le nom d'utilisateur soit valide ou non, empêchant des **attaques temporelles** qui pourraient être utilisées pour énumérer les noms d'utilisateur existants.\n\n/// note | Remarque\n\nSi vous consultez la nouvelle (fausse) base de données `fake_users_db`, vous verrez à quoi ressemble maintenant le mot de passe haché : `\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`.\n\n///\n\n## Gérer les jetons JWT { #handle-jwt-tokens }\n\nImportez les modules installés.\n\nCréez une clé secrète aléatoire qui sera utilisée pour signer les jetons JWT.\n\nPour générer une clé secrète aléatoire sécurisée, utilisez la commande :\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\nEt copiez la sortie dans la variable `SECRET_KEY` (n'utilisez pas celle de l'exemple).\n\nCréez une variable `ALGORITHM` avec l'algorithme utilisé pour signer le jeton JWT, et définissez-la à `\"HS256\"`.\n\nCréez une variable pour l'expiration du jeton.\n\nDéfinissez un modèle Pydantic qui sera utilisé dans le point de terminaison du jeton pour la réponse.\n\nCréez une fonction utilitaire pour générer un nouveau jeton d'accès.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## Mettre à jour les dépendances { #update-the-dependencies }\n\nMettez à jour `get_current_user` pour recevoir le même jeton qu'auparavant, mais cette fois en utilisant des jetons JWT.\n\nDécodez le jeton reçu, vérifiez-le, et renvoyez l'utilisateur courant.\n\nSi le jeton est invalide, renvoyez immédiatement une erreur HTTP.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## Mettre à jour le *chemin d'accès* `/token` { #update-the-token-path-operation }\n\nCréez un `timedelta` avec la durée d'expiration du jeton.\n\nCréez un véritable jeton d'accès JWT et renvoyez-le.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### Détails techniques au sujet du « subject » JWT `sub` { #technical-details-about-the-jwt-subject-sub }\n\nLa spécification JWT indique qu'il existe une clé `sub`, contenant le sujet du jeton.\n\nSon utilisation est facultative, mais c'est là que vous placeriez l'identifiant de l'utilisateur ; nous l'utilisons donc ici.\n\nLes JWT peuvent être utilisés pour d'autres choses que l'identification d'un utilisateur et l'autorisation d'effectuer des opérations directement sur votre API.\n\nPar exemple, vous pourriez identifier une « voiture » ou un « article de blog ».\n\nVous pourriez ensuite ajouter des permissions sur cette entité, comme « conduire » (pour la voiture) ou « modifier » (pour le blog).\n\nVous pourriez alors donner ce jeton JWT à un utilisateur (ou un bot), et il pourrait l'utiliser pour effectuer ces actions (conduire la voiture, ou modifier l'article de blog) sans même avoir besoin d'avoir un compte, uniquement avec le jeton JWT que votre API a généré pour cela.\n\nEn utilisant ces idées, les JWT peuvent servir à des scénarios bien plus sophistiqués.\n\nDans ces cas, plusieurs de ces entités peuvent avoir le même identifiant, disons `foo` (un utilisateur `foo`, une voiture `foo`, et un article de blog `foo`).\n\nDonc, pour éviter les collisions d'identifiants, lors de la création du jeton JWT pour l'utilisateur, vous pouvez préfixer la valeur de la clé `sub`, par exemple avec `username:`. Ainsi, dans cet exemple, la valeur de `sub` aurait pu être : `username:johndoe`.\n\nL'important à garder à l'esprit est que la clé `sub` doit contenir un identifiant unique dans toute l'application, et ce doit être une chaîne de caractères.\n\n## Vérifier { #check-it }\n\nLancez le serveur et allez à la documentation : [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVous verrez l'interface utilisateur suivante :\n\n<img src=\"/img/tutorial/security/image07.png\">\n\nAutorisez l'application de la même manière qu'auparavant.\n\nEn utilisant les identifiants :\n\nNom d'utilisateur : `johndoe`\nMot de passe : `secret`\n\n/// check | Vérifications\n\nRemarquez qu'à aucun endroit du code le mot de passe en clair « secret » n'apparaît, nous n'avons que la version hachée.\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\nAppelez le point de terminaison `/users/me/`, vous obtiendrez la réponse suivante :\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\nSi vous ouvrez les outils de développement, vous pouvez voir que les données envoyées n'incluent que le jeton ; le mot de passe n'est envoyé que dans la première requête pour authentifier l'utilisateur et obtenir ce jeton d'accès, mais plus ensuite :\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | Remarque\n\nRemarquez l'en-tête `Authorization`, avec une valeur qui commence par `Bearer `.\n\n///\n\n## Utilisation avancée avec `scopes` { #advanced-usage-with-scopes }\n\nOAuth2 comporte la notion de « scopes ».\n\nVous pouvez les utiliser pour ajouter un ensemble spécifique d'autorisations à un jeton JWT.\n\nVous pouvez ensuite donner ce jeton directement à un utilisateur ou à un tiers, pour interagir avec votre API avec un ensemble de restrictions.\n\nVous pouvez apprendre à les utiliser et comment ils sont intégrés à **FastAPI** plus tard dans le **Guide de l'utilisateur avancé**.\n\n## Récapitulatif { #recap }\n\nAvec ce que vous avez vu jusqu'à présent, vous pouvez configurer une application **FastAPI** sécurisée en utilisant des standards comme OAuth2 et JWT.\n\nDans presque n'importe quel framework, la gestion de la sécurité devient assez rapidement un sujet plutôt complexe.\n\nDe nombreux packages qui la simplifient beaucoup doivent faire de nombreux compromis avec le modèle de données, la base de données et les fonctionnalités disponibles. Et certains de ces packages qui simplifient trop les choses comportent en fait des failles de sécurité sous-jacentes.\n\n---\n\n**FastAPI** ne fait aucun compromis avec une base de données, un modèle de données ni un outil.\n\nIl vous donne toute la flexibilité pour choisir ceux qui conviennent le mieux à votre projet.\n\nEt vous pouvez utiliser directement de nombreux packages bien maintenus et largement utilisés comme `pwdlib` et `PyJWT`, car **FastAPI** n'exige aucun mécanisme complexe pour intégrer des packages externes.\n\nMais il vous fournit les outils pour simplifier le processus autant que possible sans compromettre la flexibilité, la robustesse ou la sécurité.\n\nEt vous pouvez utiliser et implémenter des protocoles sécurisés et standard, comme OAuth2, de manière relativement simple.\n\nVous pouvez en apprendre davantage dans le **Guide de l'utilisateur avancé** sur la façon d'utiliser les « scopes » OAuth2, pour un système d'autorisations plus fin, en suivant ces mêmes standards. OAuth2 avec scopes est le mécanisme utilisé par de nombreux grands fournisseurs d'authentification, comme Facebook, Google, GitHub, Microsoft, X (Twitter), etc., pour autoriser des applications tierces à interagir avec leurs API au nom de leurs utilisateurs.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/security/simple-oauth2.md",
    "content": "# OAuth2 simple avec Password et Bearer { #simple-oauth2-with-password-and-bearer }\n\nConstruisons maintenant à partir du chapitre précédent et ajoutons les éléments manquants pour avoir un flux de sécurité complet.\n\n## Obtenir `username` et `password` { #get-the-username-and-password }\n\nNous allons utiliser les utilités de sécurité de **FastAPI** pour obtenir `username` et `password`.\n\nOAuth2 spécifie que lorsqu'on utilise le « password flow » (ce que nous utilisons), le client/utilisateur doit envoyer des champs `username` et `password` en tant que données de formulaire.\n\nEt la spécification indique que les champs doivent porter exactement ces noms. Ainsi, `user-name` ou `email` ne fonctionneraient pas.\n\nMais ne vous inquiétez pas, vous pouvez l'afficher comme vous le souhaitez à vos utilisateurs finaux dans le frontend.\n\nEt vos modèles de base de données peuvent utiliser les noms que vous voulez.\n\nMais pour le chemin d'accès de connexion, nous devons utiliser ces noms pour être compatibles avec la spécification (et pouvoir, par exemple, utiliser le système de documentation API intégré).\n\nLa spécification précise également que `username` et `password` doivent être envoyés en données de formulaire (donc pas de JSON ici).\n\n### `scope` { #scope }\n\nLa spécification indique aussi que le client peut envoyer un autre champ de formulaire « scope ».\n\nLe nom du champ de formulaire est `scope` (au singulier), mais il s'agit en fait d'une longue chaîne contenant des « scopes » séparés par des espaces.\n\nChaque « scope » n'est qu'une chaîne (sans espaces).\n\nIls sont normalement utilisés pour déclarer des permissions de sécurité spécifiques, par exemple :\n\n* `users:read` ou `users:write` sont des exemples courants.\n* `instagram_basic` est utilisé par Facebook / Instagram.\n* `https://www.googleapis.com/auth/drive` est utilisé par Google.\n\n/// info\n\nEn OAuth2, un « scope » est simplement une chaîne qui déclare une permission spécifique requise.\n\nPeu importe s'il contient d'autres caractères comme `:` ou si c'est une URL.\n\nCes détails dépendent de l'implémentation.\n\nPour OAuth2, ce ne sont que des chaînes.\n\n///\n\n## Écrire le code pour obtenir `username` et `password` { #code-to-get-the-username-and-password }\n\nUtilisons maintenant les utilités fournies par **FastAPI** pour gérer cela.\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\nTout d'abord, importez `OAuth2PasswordRequestForm`, et utilisez-la en tant que dépendance avec `Depends` dans le chemin d'accès pour `/token` :\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm` est une dépendance de classe qui déclare un corps de formulaire avec :\n\n* Le `username`.\n* Le `password`.\n* Un champ optionnel `scope` sous forme d'une grande chaîne, composée de chaînes séparées par des espaces.\n* Un `grant_type` optionnel.\n\n/// tip | Astuce\n\nLa spécification OAuth2 exige en réalité un champ `grant_type` avec la valeur fixe `password`, mais `OAuth2PasswordRequestForm` ne l'impose pas.\n\nSi vous avez besoin de l'imposer, utilisez `OAuth2PasswordRequestFormStrict` au lieu de `OAuth2PasswordRequestForm`.\n\n///\n\n* Un `client_id` optionnel (nous n'en avons pas besoin pour notre exemple).\n* Un `client_secret` optionnel (nous n'en avons pas besoin pour notre exemple).\n\n/// info\n\nLa classe `OAuth2PasswordRequestForm` n'est pas une classe spéciale pour **FastAPI** comme l'est `OAuth2PasswordBearer`.\n\n`OAuth2PasswordBearer` indique à **FastAPI** qu'il s'agit d'un schéma de sécurité. Il est donc ajouté de cette façon à OpenAPI.\n\nMais `OAuth2PasswordRequestForm` est simplement une dépendance de classe que vous auriez pu écrire vous‑même, ou vous auriez pu déclarer des paramètres `Form` directement.\n\nMais comme c'est un cas d'usage courant, elle est fournie directement par **FastAPI**, simplement pour vous faciliter la vie.\n\n///\n\n### Utiliser les données du formulaire { #use-the-form-data }\n\n/// tip | Astuce\n\nL'instance de la classe de dépendance `OAuth2PasswordRequestForm` n'aura pas d'attribut `scope` contenant la longue chaîne séparée par des espaces ; elle aura plutôt un attribut `scopes` avec la liste réelle des chaînes pour chaque scope envoyé.\n\nNous n'utilisons pas `scopes` dans cet exemple, mais la fonctionnalité est disponible si vous en avez besoin.\n\n///\n\nRécupérez maintenant les données utilisateur depuis la (fausse) base de données, en utilisant le `username` du champ de formulaire.\n\nS'il n'existe pas d'utilisateur, nous renvoyons une erreur indiquant « Incorrect username or password ».\n\nPour l'erreur, nous utilisons l'exception `HTTPException` :\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### Vérifier le mot de passe { #check-the-password }\n\nÀ ce stade, nous avons les données utilisateur depuis notre base, mais nous n'avons pas encore vérifié le mot de passe.\n\nMettons d'abord ces données dans le modèle Pydantic `UserInDB`.\n\nVous ne devez jamais enregistrer des mots de passe en clair ; nous allons donc utiliser le système (factice) de hachage de mot de passe.\n\nSi les mots de passe ne correspondent pas, nous renvoyons la même erreur.\n\n#### Hachage de mot de passe { #password-hashing }\n\nLe « hachage » signifie : convertir un contenu (un mot de passe, dans ce cas) en une séquence d'octets (juste une chaîne) qui ressemble à du charabia.\n\nChaque fois que vous fournissez exactement le même contenu (exactement le même mot de passe), vous obtenez exactement le même charabia.\n\nMais vous ne pouvez pas convertir ce charabia pour retrouver le mot de passe.\n\n##### Pourquoi utiliser le hachage de mot de passe { #why-use-password-hashing }\n\nSi votre base de données est volée, le voleur n'aura pas les mots de passe en clair de vos utilisateurs, seulement les hachages.\n\nAinsi, il ne pourra pas essayer d'utiliser ces mêmes mots de passe dans un autre système (comme beaucoup d'utilisateurs utilisent le même mot de passe partout, ce serait dangereux).\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### À propos de `**user_dict` { #about-user-dict }\n\n`UserInDB(**user_dict)` signifie :\n\nPassez les clés et valeurs de `user_dict` directement comme arguments clé‑valeur, équivalent à :\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info\n\nPour une explication plus complète de `**user_dict`, consultez [la documentation pour **Modèles supplémentaires**](../extra-models.md#about-user-in-dict).\n\n///\n\n## Renvoyer le jeton { #return-the-token }\n\nLa réponse de l'endpoint `token` doit être un objet JSON.\n\nIl doit contenir un `token_type`. Dans notre cas, comme nous utilisons des jetons « Bearer », le type de jeton doit être « bearer ».\n\nEt il doit contenir un `access_token`, avec une chaîne contenant notre jeton d'accès.\n\nPour cet exemple simple, nous allons faire quelque chose de complètement non sécurisé et renvoyer le même `username` comme jeton.\n\n/// tip | Astuce\n\nDans le prochain chapitre, vous verrez une véritable implémentation sécurisée, avec du hachage de mot de passe et des jetons <abbr title=\"JSON Web Tokens\">JWT</abbr>.\n\nMais pour l'instant, concentrons‑nous sur les détails spécifiques dont nous avons besoin.\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip | Astuce\n\nD'après la spécification, vous devez renvoyer un JSON avec un `access_token` et un `token_type`, comme dans cet exemple.\n\nC'est quelque chose que vous devez faire vous‑même dans votre code, et vous devez vous assurer d'utiliser ces clés JSON.\n\nC'est presque la seule chose que vous devez vous rappeler de faire correctement vous‑même pour être conforme aux spécifications.\n\nPour le reste, **FastAPI** s'en charge pour vous.\n\n///\n\n## Mettre à jour les dépendances { #update-the-dependencies }\n\nNous allons maintenant mettre à jour nos dépendances.\n\nNous voulons obtenir `current_user` uniquement si cet utilisateur est actif.\n\nNous créons donc une dépendance supplémentaire `get_current_active_user` qui utilise à son tour `get_current_user` comme dépendance.\n\nCes deux dépendances renverront simplement une erreur HTTP si l'utilisateur n'existe pas, ou s'il est inactif.\n\nAinsi, dans notre endpoint, nous n'obtiendrons un utilisateur que si l'utilisateur existe, a été correctement authentifié et est actif :\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info\n\nL'en‑tête supplémentaire `WWW-Authenticate` avec la valeur `Bearer` que nous renvoyons ici fait également partie de la spécification.\n\nIl est prévu qu'un code d'état HTTP (d'erreur) 401 « UNAUTHORIZED » renvoie également un en‑tête `WWW-Authenticate`.\n\nDans le cas des jetons bearer (notre cas), la valeur de cet en‑tête doit être `Bearer`.\n\nVous pouvez en réalité omettre cet en‑tête supplémentaire et cela fonctionnerait quand même.\n\nMais il est fourni ici pour être conforme aux spécifications.\n\nDe plus, il peut exister des outils qui l'attendent et l'utilisent (maintenant ou à l'avenir) et cela pourrait vous être utile, à vous ou à vos utilisateurs, maintenant ou à l'avenir.\n\nC'est l'avantage des standards ...\n\n///\n\n## Voir en action { #see-it-in-action }\n\nOuvrez la documentation interactive : [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n### S'authentifier { #authenticate }\n\nCliquez sur le bouton « Authorize ».\n\nUtilisez les identifiants :\n\nUtilisateur : `johndoe`\n\nMot de passe : `secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\nAprès vous être authentifié dans le système, vous verrez ceci :\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### Obtenir vos propres données utilisateur { #get-your-own-user-data }\n\nUtilisez maintenant l'opération `GET` avec le chemin `/users/me`.\n\nVous obtiendrez les données de votre utilisateur, par exemple :\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\nSi vous cliquez sur l'icône de cadenas et vous vous déconnectez, puis réessayez la même opération, vous obtiendrez une erreur HTTP 401 :\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### Utilisateur inactif { #inactive-user }\n\nEssayez maintenant avec un utilisateur inactif, authentifiez‑vous avec :\n\nUtilisateur : `alice`\n\nMot de passe : `secret2`\n\nEt essayez d'utiliser l'opération `GET` avec le chemin `/users/me`.\n\nVous obtiendrez une erreur « Inactive user », par exemple :\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## Récapitulatif { #recap }\n\nVous avez maintenant les outils pour implémenter un système de sécurité complet basé sur `username` et `password` pour votre API.\n\nEn utilisant ces outils, vous pouvez rendre le système de sécurité compatible avec n'importe quelle base de données et avec n'importe quel modèle d'utilisateur ou de données.\n\nLe seul détail manquant est qu'il n'est pas encore réellement « sécurisé ».\n\nDans le prochain chapitre, vous verrez comment utiliser une bibliothèque de hachage de mot de passe sécurisée et des jetons <abbr title=\"JSON Web Tokens\">JWT</abbr>.\n"
  },
  {
    "path": "docs/fr/docs/tutorial/server-sent-events.md",
    "content": "# Événements envoyés par le serveur (SSE) { #server-sent-events-sse }\n\nVous pouvez diffuser des données vers le client en utilisant les **Server-Sent Events** (SSE).\n\nC'est similaire à [Diffuser des JSON Lines](stream-json-lines.md), mais cela utilise le format `text/event-stream`, pris en charge nativement par les navigateurs via l’API [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).\n\n/// info | Info\n\nAjouté dans FastAPI 0.135.0.\n\n///\n\n## Que sont les Server-Sent Events ? { #what-are-server-sent-events }\n\nSSE est un standard pour diffuser des données du serveur au client via HTTP.\n\nChaque événement est un petit bloc de texte avec des « champs » comme `data`, `event`, `id` et `retry`, séparés par des lignes vides.\n\nCela ressemble à ceci :\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nLes SSE sont couramment utilisés pour le streaming de chat IA, les notifications en direct, les journaux et l’observabilité, et d’autres cas où le serveur envoie des mises à jour au client.\n\n/// tip | Astuce\n\nSi vous souhaitez diffuser des données binaires, par exemple de la vidéo ou de l’audio, consultez le guide avancé : [Diffuser des données](../advanced/stream-data.md).\n\n///\n\n## Diffuser des SSE avec FastAPI { #stream-sse-with-fastapi }\n\nPour diffuser des SSE avec FastAPI, utilisez `yield` dans votre *fonction de chemin d'accès* et définissez `response_class=EventSourceResponse`.\n\nImportez `EventSourceResponse` depuis `fastapi.sse` :\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\nChaque élément produit avec `yield` est encodé en JSON et envoyé dans le champ `data:` d’un événement SSE.\n\nSi vous déclarez le type de retour comme `AsyncIterable[Item]`, FastAPI l’utilisera pour **valider**, **documenter** et **sérialiser** les données avec Pydantic.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip | Astuce\n\nComme Pydantic le sérialisera du côté **Rust**, vous obtiendrez une **performance** bien supérieure que si vous ne déclarez pas de type de retour.\n\n///\n\n### Fonctions de chemin d'accès non async { #non-async-path-operation-functions }\n\nVous pouvez aussi utiliser des fonctions `def` normales (sans `async`), et utiliser `yield` de la même façon.\n\nFastAPI s’assure qu’elles s’exécutent correctement pour ne pas bloquer la boucle d’événements.\n\nDans ce cas la fonction n’est pas async, le type de retour approprié serait `Iterable[Item]` :\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### Sans type de retour { #no-return-type }\n\nVous pouvez aussi omettre le type de retour. FastAPI utilisera le [`jsonable_encoder`](./encoder.md) pour convertir les données et les envoyer.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\nSi vous devez définir des champs SSE comme `event`, `id`, `retry` ou `comment`, vous pouvez produire des objets `ServerSentEvent` au lieu de données brutes.\n\nImportez `ServerSentEvent` depuis `fastapi.sse` :\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\nLe champ `data` est toujours encodé en JSON. Vous pouvez passer toute valeur sérialisable en JSON, y compris des modèles Pydantic.\n\n## Données brutes { #raw-data }\n\nSi vous devez envoyer des données **sans** encodage JSON, utilisez `raw_data` au lieu de `data`.\n\nC’est utile pour envoyer du texte préformaté, des lignes de log, ou des valeurs <dfn title=\"Une valeur utilisée pour indiquer une condition ou un état particulier\">« sentinelle »</dfn> spéciales comme `[DONE]`.\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note | Remarque\n\n`data` et `raw_data` s’excluent mutuellement. Vous ne pouvez en définir qu’un seul par `ServerSentEvent`.\n\n///\n\n## Reprendre avec `Last-Event-ID` { #resuming-with-last-event-id }\n\nQuand un navigateur se reconnecte après une coupure, il envoie le dernier `id` reçu dans l’en-tête `Last-Event-ID`.\n\nVous pouvez le lire comme paramètre d’en-tête et l’utiliser pour reprendre le flux là où le client s’était arrêté :\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## SSE avec POST { #sse-with-post }\n\nSSE fonctionne avec **n’importe quelle méthode HTTP**, pas seulement `GET`.\n\nC’est utile pour des protocoles comme [MCP](https://modelcontextprotocol.io) qui diffusent des SSE via `POST` :\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## Détails techniques { #technical-details }\n\nFastAPI met en œuvre certaines bonnes pratiques SSE prêtes à l’emploi.\n\n- Envoyer un commentaire **« keep alive » `ping`** toutes les 15 secondes quand aucun message n’a été émis, pour éviter que certains proxys ne ferment la connexion, comme suggéré dans la [Spécification HTML : Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes).\n- Définir l’en-tête `Cache-Control: no-cache` pour **empêcher la mise en cache** du flux.\n- Définir un en-tête spécial `X-Accel-Buffering: no` pour **empêcher le buffering** dans certains proxys comme Nginx.\n\nVous n’avez rien à faire, cela fonctionne prêt à l’emploi. 🤓\n"
  },
  {
    "path": "docs/fr/docs/tutorial/sql-databases.md",
    "content": "# Bases de données SQL (relationnelles) { #sql-relational-databases }\n\n**FastAPI** ne vous oblige pas à utiliser une base de données SQL (relationnelle). Mais vous pouvez utiliser **n'importe quelle base de données** que vous voulez.\n\nIci, nous allons voir un exemple utilisant [SQLModel](https://sqlmodel.tiangolo.com/).\n\n**SQLModel** est construit au-dessus de [SQLAlchemy](https://www.sqlalchemy.org/) et de Pydantic. Il a été créé par le même auteur que **FastAPI** pour être l'accord parfait pour les applications FastAPI qui ont besoin d'utiliser des **bases de données SQL**.\n\n/// tip | Astuce\n\nVous pouvez utiliser toute autre bibliothèque SQL ou NoSQL que vous voulez (dans certains cas appelées <abbr title=\"Object Relational Mapper - Mappeur objet-relationnel: un terme sophistiqué pour une bibliothèque où certaines classes représentent des tables SQL et les instances représentent des lignes dans ces tables\">« ORMs »</abbr>), FastAPI ne vous impose rien. 😎\n\n///\n\nComme SQLModel est basé sur SQLAlchemy, vous pouvez facilement utiliser **toute base prise en charge** par SQLAlchemy (ce qui les rend également prises en charge par SQLModel), comme :\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server, etc.\n\nDans cet exemple, nous utiliserons **SQLite**, car il utilise un seul fichier et Python a un support intégré. Ainsi, vous pouvez copier cet exemple et l'exécuter tel quel.\n\nPlus tard, pour votre application de production, vous voudrez peut-être utiliser un serveur de base de données comme **PostgreSQL**.\n\n/// tip | Astuce\n\nIl existe un générateur de projet officiel avec **FastAPI** et **PostgreSQL**, incluant un frontend et plus d'outils : [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\nIl s'agit d'un tutoriel très simple et court ; si vous souhaitez apprendre sur les bases de données en général, sur SQL, ou des fonctionnalités plus avancées, allez voir la [documentation SQLModel](https://sqlmodel.tiangolo.com/).\n\n## Installer `SQLModel` { #install-sqlmodel }\n\nD'abord, assurez-vous de créer votre [environnement virtuel](../virtual-environments.md), de l'activer, puis d'installer `sqlmodel` :\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## Créer l'application avec un modèle unique { #create-the-app-with-a-single-model }\n\nNous allons d'abord créer la première version la plus simple de l'application avec un seul modèle **SQLModel**.\n\nEnsuite, nous l'améliorerons en augmentant la sécurité et la polyvalence avec **plusieurs modèles** ci-dessous. 🤓\n\n### Créer les modèles { #create-models }\n\nImportez `SQLModel` et créez un modèle de base de données :\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\nLa classe `Hero` est très similaire à un modèle Pydantic (en fait, en dessous, c'est réellement un modèle Pydantic).\n\nIl y a quelques différences :\n\n* `table=True` indique à SQLModel qu'il s'agit d'un *modèle de table*, il doit représenter une **table** dans la base SQL, ce n'est pas seulement un *modèle de données* (comme le serait n'importe quelle autre classe Pydantic classique).\n\n* `Field(primary_key=True)` indique à SQLModel que `id` est la **clé primaire** dans la base SQL (vous pouvez en savoir plus sur les clés primaires SQL dans la documentation SQLModel).\n\n    Remarque : nous utilisons `int | None` pour le champ clé primaire afin qu'en Python nous puissions *créer un objet sans `id`* (`id=None`), en supposant que la base *le génère à l'enregistrement*. SQLModel comprend que la base fournira l'`id` et *définit la colonne comme un `INTEGER` non nul* dans le schéma de base. Voir la [documentation SQLModel sur les clés primaires](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) pour plus de détails.\n\n* `Field(index=True)` indique à SQLModel qu'il doit créer un **index SQL** pour cette colonne, ce qui permettra des recherches plus rapides dans la base lors de la lecture de données filtrées par cette colonne.\n\n    SQLModel saura que quelque chose déclaré comme `str` sera une colonne SQL de type `TEXT` (ou `VARCHAR`, selon la base).\n\n### Créer un engine { #create-an-engine }\n\nUn `engine` SQLModel (en dessous c'est en fait un `engine` SQLAlchemy) est ce qui **détient les connexions** à la base de données.\n\nVous devez avoir **un seul objet `engine`** pour tout votre code afin de se connecter à la même base.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\nL'utilisation de `check_same_thread=False` permet à FastAPI d'utiliser la même base SQLite dans différents threads. C'est nécessaire car **une seule requête** peut utiliser **plus d'un thread** (par exemple dans des dépendances).\n\nNe vous inquiétez pas, avec la structure du code, nous nous assurerons d'utiliser **une seule *session* SQLModel par requête** plus loin, c'est en fait ce que `check_same_thread` essaie d'assurer.\n\n### Créer les tables { #create-the-tables }\n\nNous ajoutons ensuite une fonction qui utilise `SQLModel.metadata.create_all(engine)` pour **créer les tables** pour tous les *modèles de table*.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### Créer une dépendance de session { #create-a-session-dependency }\n\nUne **`Session`** est ce qui stocke les **objets en mémoire** et suit les modifications nécessaires des données, puis **utilise l'`engine`** pour communiquer avec la base.\n\nNous allons créer une **dépendance** FastAPI avec `yield` qui fournira une nouvelle `Session` pour chaque requête. C'est ce qui garantit que nous utilisons une seule session par requête. 🤓\n\nPuis nous créons une dépendance `Annotated` `SessionDep` pour simplifier le reste du code qui utilisera cette dépendance.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### Créer les tables de base au démarrage { #create-database-tables-on-startup }\n\nNous allons créer les tables de base de données au démarrage de l'application.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\nIci, nous créons les tables lors d'un événement de démarrage de l'application.\n\nEn production, vous utiliseriez probablement un script de migration qui s'exécute avant de démarrer votre application. 🤓\n\n/// tip | Astuce\n\nSQLModel aura des utilitaires de migration enveloppant Alembic, mais pour l'instant, vous pouvez utiliser [Alembic](https://alembic.sqlalchemy.org/en/latest/) directement.\n\n///\n\n### Créer un héros { #create-a-hero }\n\nComme chaque modèle SQLModel est aussi un modèle Pydantic, vous pouvez l'utiliser dans les mêmes **annotations de type** que vous utiliseriez pour des modèles Pydantic.\n\nPar exemple, si vous déclarez un paramètre de type `Hero`, il sera lu depuis le **corps JSON**.\n\nDe la même manière, vous pouvez le déclarer comme **type de retour** de la fonction, et alors la forme des données apparaîtra dans l'UI automatique de documentation de l'API.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\nIci, nous utilisons la dépendance `SessionDep` (une `Session`) pour ajouter le nouveau `Hero` à l'instance de `Session`, valider les changements dans la base, rafraîchir les données dans `hero`, puis le retourner.\n\n### Lire les héros { #read-heroes }\n\nNous pouvons **lire** des `Hero` depuis la base en utilisant un `select()`. Nous pouvons inclure une `limit` et un `offset` pour paginer les résultats.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### Lire un héros { #read-one-hero }\n\nNous pouvons **lire** un seul `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### Supprimer un héros { #delete-a-hero }\n\nNous pouvons aussi **supprimer** un `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### Exécuter l'application { #run-the-app }\n\nVous pouvez exécuter l'application :\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nEnsuite, allez sur l'UI `/docs`, vous verrez que **FastAPI** utilise ces **modèles** pour **documenter** l'API, et les utilisera aussi pour **sérialiser** et **valider** les données.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## Mettre à jour l'application avec plusieurs modèles { #update-the-app-with-multiple-models }\n\nMaintenant, **refactorisons** un peu cette application pour augmenter la **sécurité** et la **polyvalence**.\n\nSi vous vérifiez l'application précédente, dans l'UI vous pouvez voir que, jusqu'à présent, elle laisse le client décider de l'`id` du `Hero` à créer. 😱\n\nNous ne devrions pas laisser cela se produire, ils pourraient écraser un `id` que nous avons déjà attribué dans la base. Décider de l'`id` doit être fait par le **backend** ou la **base**, **pas par le client**.\n\nDe plus, nous créons un `secret_name` pour le héros, mais jusqu'ici, nous le renvoyons partout, ce n'est pas très « secret » ... 😅\n\nNous allons corriger ces choses en ajoutant quelques **modèles supplémentaires**. C'est là que SQLModel brille. ✨\n\n### Créer plusieurs modèles { #create-multiple-models }\n\nDans **SQLModel**, toute classe de modèle qui a `table=True` est un **modèle de table**.\n\nEt toute classe de modèle qui n'a pas `table=True` est un **modèle de données**, ceux-ci sont en réalité juste des modèles Pydantic (avec deux petites fonctionnalités en plus). 🤓\n\nAvec SQLModel, nous pouvons utiliser **l'héritage** pour **éviter de dupliquer** tous les champs dans tous les cas.\n\n#### `HeroBase` - la classe de base { #herobase-the-base-class }\n\nCommençons avec un modèle `HeroBase` qui a tous les **champs partagés** par tous les modèles :\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` - le *modèle de table* { #hero-the-table-model }\n\nCréons ensuite `Hero`, le *modèle de table* proprement dit, avec les **champs supplémentaires** qui ne sont pas toujours dans les autres modèles :\n\n* `id`\n* `secret_name`\n\nComme `Hero` hérite de `HeroBase`, il **a aussi** les **champs** déclarés dans `HeroBase`, donc tous les champs de `Hero` sont :\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` - le *modèle de données* public { #heropublic-the-public-data-model }\n\nEnsuite, nous créons un modèle `HeroPublic`, c'est celui qui sera **retourné** aux clients de l'API.\n\nIl a les mêmes champs que `HeroBase`, il n'inclura donc pas `secret_name`.\n\nEnfin, l'identité de nos héros est protégée ! 🥷\n\nIl redéclare aussi `id: int`. Ce faisant, nous faisons un **contrat** avec les clients de l'API, afin qu'ils puissent toujours s'attendre à ce que `id` soit présent et soit un `int` (il ne sera jamais `None`).\n\n/// tip | Astuce\n\nAvoir le modèle de retour qui garantit qu'une valeur est toujours disponible et toujours `int` (pas `None`) est très utile pour les clients de l'API, ils peuvent écrire un code beaucoup plus simple avec cette certitude.\n\nDe plus, les **clients générés automatiquement** auront des interfaces plus simples, afin que les développeurs qui communiquent avec votre API puissent travailler bien plus facilement avec votre API. 😎\n\n///\n\nTous les champs de `HeroPublic` sont les mêmes que dans `HeroBase`, avec `id` déclaré comme `int` (pas `None`) :\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` - le *modèle de données* pour créer un héros { #herocreate-the-data-model-to-create-a-hero }\n\nNous créons maintenant un modèle `HeroCreate`, c'est celui qui **validera** les données provenant des clients.\n\nIl a les mêmes champs que `HeroBase`, et il a aussi `secret_name`.\n\nMaintenant, lorsque les clients **créent un nouveau héros**, ils enverront `secret_name`, il sera stocké dans la base, mais ces noms secrets ne seront pas renvoyés dans l'API aux clients.\n\n/// tip | Astuce\n\nC'est ainsi que vous géreriez les **mots de passe**. Les recevoir, mais ne pas les renvoyer dans l'API.\n\nVous **hacherez** aussi les valeurs des mots de passe avant de les stocker, **ne les stockez jamais en texte en clair**.\n\n///\n\nLes champs de `HeroCreate` sont :\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` - le *modèle de données* pour mettre à jour un héros { #heroupdate-the-data-model-to-update-a-hero }\n\nNous n'avions pas de moyen de **mettre à jour un héros** dans la version précédente de l'application, mais maintenant avec **plusieurs modèles**, nous pouvons le faire. 🎉\n\nLe *modèle de données* `HeroUpdate` est un peu spécial, il a **tous les mêmes champs** qui seraient nécessaires pour créer un nouveau héros, mais tous les champs sont **optionnels** (ils ont tous une valeur par défaut). Ainsi, lorsque vous mettez à jour un héros, vous pouvez n'envoyer que les champs que vous souhaitez mettre à jour.\n\nComme tous les **champs changent réellement** (le type inclut désormais `None` et ils ont maintenant une valeur par défaut de `None`), nous devons les **redéclarer**.\n\nNous n'avons pas vraiment besoin d'hériter de `HeroBase` puisque nous redéclarons tous les champs. Je le laisse hériter juste pour la cohérence, mais ce n'est pas nécessaire. C'est plutôt une question de goût personnel. 🤷\n\nLes champs de `HeroUpdate` sont :\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### Créer avec `HeroCreate` et retourner un `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }\n\nMaintenant que nous avons **plusieurs modèles**, nous pouvons mettre à jour les parties de l'application qui les utilisent.\n\nNous recevons dans la requête un *modèle de données* `HeroCreate`, et à partir de celui-ci, nous créons un *modèle de table* `Hero`.\n\nCe nouveau *modèle de table* `Hero` aura les champs envoyés par le client, et aura aussi un `id` généré par la base.\n\nNous retournons ensuite le même *modèle de table* `Hero` tel quel depuis la fonction. Mais comme nous déclarons le `response_model` avec le *modèle de données* `HeroPublic`, **FastAPI** utilisera `HeroPublic` pour valider et sérialiser les données.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | Astuce\n\nNous utilisons maintenant `response_model=HeroPublic` au lieu de l'**annotation de type de retour** `-> HeroPublic` car la valeur que nous renvoyons n'est en réalité *pas* un `HeroPublic`.\n\nSi nous avions déclaré `-> HeroPublic`, votre éditeur et votre linter se plaindraient (à juste titre) que vous retournez un `Hero` au lieu d'un `HeroPublic`.\n\nEn le déclarant dans `response_model`, nous disons à **FastAPI** de faire son travail, sans interférer avec les annotations de type et l'aide de votre éditeur et d'autres outils.\n\n///\n\n### Lire des héros avec `HeroPublic` { #read-heroes-with-heropublic }\n\nNous pouvons faire la même chose qu'avant pour **lire** des `Hero`, à nouveau, nous utilisons `response_model=list[HeroPublic]` pour garantir que les données sont correctement validées et sérialisées.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### Lire un héros avec `HeroPublic` { #read-one-hero-with-heropublic }\n\nNous pouvons **lire** un héros unique :\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### Mettre à jour un héros avec `HeroUpdate` { #update-a-hero-with-heroupdate }\n\nNous pouvons **mettre à jour un héros**. Pour cela, nous utilisons une opération HTTP `PATCH`.\n\nEt dans le code, nous obtenons un `dict` avec toutes les données envoyées par le client, **uniquement les données envoyées par le client**, en excluant toute valeur qui serait là simplement parce que c'est la valeur par défaut. Pour ce faire, nous utilisons `exclude_unset=True`. C'est l'astuce principale. 🪄\n\nNous utilisons ensuite `hero_db.sqlmodel_update(hero_data)` pour mettre à jour `hero_db` avec les données de `hero_data`.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### Supprimer un héros (bis) { #delete-a-hero-again }\n\n**Supprimer** un héros reste pratiquement identique.\n\nNous n'allons pas céder à l'envie de tout refactoriser pour celui-ci. 😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### Exécuter l'application à nouveau { #run-the-app-again }\n\nVous pouvez exécuter l'application à nouveau :\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nSi vous allez sur l'UI `/docs` de l'API, vous verrez qu'elle est maintenant à jour, et qu'elle n'attendra plus de recevoir l'`id` du client lors de la création d'un héros, etc.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## Récapitulatif { #recap }\n\nVous pouvez utiliser [**SQLModel**](https://sqlmodel.tiangolo.com/) pour interagir avec une base SQL et simplifier le code avec des *modèles de données* et des *modèles de table*.\n\nVous pouvez en apprendre beaucoup plus dans la documentation **SQLModel**, il y a un mini [tutoriel plus long sur l'utilisation de SQLModel avec **FastAPI**](https://sqlmodel.tiangolo.com/tutorial/fastapi/). 🚀\n"
  },
  {
    "path": "docs/fr/docs/tutorial/static-files.md",
    "content": "# Fichiers statiques { #static-files }\n\nVous pouvez servir des fichiers statiques automatiquement à partir d'un répertoire en utilisant `StaticFiles`.\n\n## Utiliser `StaticFiles` { #use-staticfiles }\n\n- Importer `StaticFiles`.\n- « Mount » une instance `StaticFiles()` sur un chemin spécifique.\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | Détails techniques\n\nVous pouvez également utiliser `from starlette.staticfiles import StaticFiles`.\n\n**FastAPI** fournit le même `starlette.staticfiles` sous le nom `fastapi.staticfiles` uniquement pour votre commodité, en tant que développeur. Mais cela provient en réalité directement de Starlette.\n\n///\n\n### Qu'est-ce que « Mounting » { #what-is-mounting }\n\n« Mounting » signifie ajouter une application complète « indépendante » sur un chemin spécifique, qui se chargera ensuite de gérer tous les sous-chemins.\n\nCela diffère de l'utilisation d'un `APIRouter`, car une application montée est complètement indépendante. L'OpenAPI et les documents de votre application principale n'incluront rien provenant de l'application montée, etc.\n\nVous pouvez en lire davantage à ce sujet dans le [Guide utilisateur avancé](../advanced/index.md).\n\n## Détails { #details }\n\nLe premier `\"/static\"` fait référence au sous-chemin sur lequel cette « sous-application » sera « montée ». Ainsi, tout chemin qui commence par `\"/static\"` sera géré par elle.\n\nLe `directory=\"static\"` fait référence au nom du répertoire qui contient vos fichiers statiques.\n\nLe `name=\"static\"` lui donne un nom utilisable en interne par **FastAPI**.\n\nTous ces paramètres peuvent être différents de « `static` », adaptez-les aux besoins et aux détails spécifiques de votre propre application.\n\n## Plus d'informations { #more-info }\n\nPour plus de détails et d'options, consultez la [documentation de Starlette sur les fichiers statiques](https://www.starlette.dev/staticfiles/).\n"
  },
  {
    "path": "docs/fr/docs/tutorial/stream-json-lines.md",
    "content": "# Diffuser des JSON Lines { #stream-json-lines }\n\nVous pouvez avoir une séquence de données que vous souhaitez envoyer en « flux » ; vous pouvez le faire avec « JSON Lines ».\n\n/// info\n\nAjouté dans FastAPI 0.134.0.\n\n///\n\n## Qu'est-ce qu'un flux ? { #what-is-a-stream }\n\nLa « diffusion en continu » de données signifie que votre application commence à envoyer des éléments de données au client sans attendre que l'ensemble de la séquence soit prêt.\n\nAinsi, elle enverra le premier élément, le client le recevra et commencera à le traiter, et vous pourriez être encore en train de produire l'élément suivant.\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\nCela peut même être un flux infini, où vous continuez à envoyer des données.\n\n## JSON Lines { #json-lines }\n\nDans ces cas, il est courant d'envoyer des « JSON Lines », qui est un format où vous envoyez un objet JSON par ligne.\n\nUne réponse aurait un type de contenu `application/jsonl` (au lieu de `application/json`) et le corps ressemblerait à ceci :\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\nC'est très similaire à un tableau JSON (équivalent d'une liste Python), mais au lieu d'être entouré de `[]` et d'avoir des `,` entre les éléments, il y a un objet JSON par ligne, ils sont séparés par un caractère de saut de ligne.\n\n/// info\n\nLe point important est que votre application pourra produire chaque ligne à son tour, tandis que le client consomme les lignes précédentes.\n\n///\n\n/// note | Détails techniques\n\nComme chaque objet JSON sera séparé par un saut de ligne, ils ne peuvent pas contenir de caractères de saut de ligne littéraux dans leur contenu, mais ils peuvent contenir des sauts de ligne échappés (`\\n`), ce qui fait partie du standard JSON.\n\nMais normalement, vous n'avez pas à vous en soucier, c'est fait automatiquement, continuez la lecture. 🤓\n\n///\n\n## Cas d'utilisation { #use-cases }\n\nVous pouvez utiliser cela pour diffuser des données depuis un service **AI LLM**, depuis des **journaux** ou de la **télémétrie**, ou depuis d'autres types de données pouvant être structurées en éléments **JSON**.\n\n/// tip | Astuce\n\nSi vous voulez diffuser des données binaires, par exemple de la vidéo ou de l'audio, consultez le guide avancé : [Diffuser des données](../advanced/stream-data.md).\n\n///\n\n## Diffuser des JSON Lines avec FastAPI { #stream-json-lines-with-fastapi }\n\nPour diffuser des JSON Lines avec FastAPI, au lieu d'utiliser `return` dans votre fonction de chemin d'accès, utilisez `yield` pour produire chaque élément à tour de rôle.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\nSi chaque élément JSON que vous voulez renvoyer est de type `Item` (un modèle Pydantic) et que c'est une fonction async, vous pouvez déclarer le type de retour comme `AsyncIterable[Item]` :\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\nSi vous déclarez le type de retour, FastAPI l'utilisera pour **valider** les données, les **documenter** dans OpenAPI, les **filtrer**, et les **sérialiser** avec Pydantic.\n\n/// tip | Astuce\n\nComme Pydantic les sérialisera côté **Rust**, vous obtiendrez une **performance** bien supérieure que si vous ne déclarez pas de type de retour.\n\n///\n\n### Fonctions de chemin d'accès non asynchrones { #non-async-path-operation-functions }\n\nVous pouvez aussi utiliser des fonctions `def` classiques (sans `async`), et utiliser `yield` de la même manière.\n\nFastAPI s'assure qu'elle s'exécute correctement afin de ne pas bloquer la boucle d'événements.\n\nComme dans ce cas la fonction n'est pas async, le bon type de retour serait `Iterable[Item]` :\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### Sans type de retour { #no-return-type }\n\nVous pouvez également omettre le type de retour. FastAPI utilisera alors [`jsonable_encoder`](./encoder.md) pour convertir les données en quelque chose qui peut être sérialisé en JSON, puis les enverra en JSON Lines.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## Événements envoyés par le serveur (SSE) { #server-sent-events-sse }\n\nFastAPI propose également une prise en charge native des Server-Sent Events (SSE), qui sont assez proches mais avec quelques détails supplémentaires. Vous pouvez en apprendre davantage dans le chapitre suivant : [Événements envoyés par le serveur (SSE)](server-sent-events.md). 🤓\n"
  },
  {
    "path": "docs/fr/docs/tutorial/testing.md",
    "content": "# Tester { #testing }\n\nGrâce à [Starlette](https://www.starlette.dev/testclient/), tester des applications **FastAPI** est simple et agréable.\n\nC’est basé sur [HTTPX](https://www.python-httpx.org), dont la conception s’inspire de Requests, ce qui le rend très familier et intuitif.\n\nAvec cela, vous pouvez utiliser [pytest](https://docs.pytest.org/) directement avec **FastAPI**.\n\n## Utiliser `TestClient` { #using-testclient }\n\n/// info\n\nPour utiliser `TestClient`, installez d’abord [`httpx`](https://www.python-httpx.org).\n\nVous devez créer un [environnement virtuel](../virtual-environments.md), l’activer, puis y installer le paquet, par exemple :\n\n```console\n$ pip install httpx\n```\n\n///\n\nImportez `TestClient`.\n\nCréez un `TestClient` en lui passant votre application **FastAPI**.\n\nCréez des fonctions dont le nom commence par `test_` (c’est la convention standard de `pytest`).\n\nUtilisez l’objet `TestClient` de la même manière que vous utilisez `httpx`.\n\nÉcrivez de simples instructions `assert` avec les expressions Python standard que vous devez vérifier (là encore, standard `pytest`).\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip | Astuce\n\nRemarquez que les fonctions de test sont des `def` normales, pas des `async def`.\n\nEt les appels au client sont aussi des appels normaux, sans utiliser `await`.\n\nCela vous permet d’utiliser `pytest` directement sans complications.\n\n///\n\n/// note | Détails techniques\n\nVous pouvez aussi utiliser `from starlette.testclient import TestClient`.\n\n**FastAPI** fournit le même `starlette.testclient` sous le nom `fastapi.testclient` uniquement pour votre commodité, en tant que développeur. Mais cela vient directement de Starlette.\n\n///\n\n/// tip | Astuce\n\nSi vous souhaitez appeler des fonctions `async` dans vos tests en dehors de l’envoi de requêtes à votre application FastAPI (par exemple des fonctions de base de données asynchrones), consultez les [Tests asynchrones](../advanced/async-tests.md) dans le tutoriel avancé.\n\n///\n\n## Séparer les tests { #separating-tests }\n\nDans une application réelle, vous auriez probablement vos tests dans un fichier différent.\n\nEt votre application **FastAPI** pourrait aussi être composée de plusieurs fichiers/modules, etc.\n\n### Fichier d’application **FastAPI** { #fastapi-app-file }\n\nSupposons que vous ayez une structure de fichiers comme décrit dans [Applications plus grandes](bigger-applications.md) :\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\nDans le fichier `main.py`, vous avez votre application **FastAPI** :\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### Fichier de test { #testing-file }\n\nVous pourriez alors avoir un fichier `test_main.py` avec vos tests. Il pourrait vivre dans le même package Python (le même répertoire avec un fichier `__init__.py`) :\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nComme ce fichier se trouve dans le même package, vous pouvez utiliser des imports relatifs pour importer l’objet `app` depuis le module `main` (`main.py`) :\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n\n… et avoir le code des tests comme précédemment.\n\n## Tester : exemple étendu { #testing-extended-example }\n\nÉtendons maintenant cet exemple et ajoutons plus de détails pour voir comment tester différentes parties.\n\n### Fichier d’application **FastAPI** étendu { #extended-fastapi-app-file }\n\nContinuons avec la même structure de fichiers qu’auparavant :\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nSupposons que désormais le fichier `main.py` avec votre application **FastAPI** contienne d’autres **chemins d’accès**.\n\nIl a une opération `GET` qui pourrait renvoyer une erreur.\n\nIl a une opération `POST` qui pourrait renvoyer plusieurs erreurs.\n\nLes deux chemins d’accès requièrent un en-tête `X-Token`.\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### Fichier de test étendu { #extended-testing-file }\n\nVous pourriez ensuite mettre à jour `test_main.py` avec les tests étendus :\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\n\nChaque fois que vous avez besoin que le client transmette des informations dans la requête et que vous ne savez pas comment faire, vous pouvez chercher (Google) comment le faire avec `httpx`, ou même comment le faire avec `requests`, puisque la conception de HTTPX est basée sur celle de Requests.\n\nEnsuite, vous faites simplement la même chose dans vos tests.\n\nPar exemple :\n\n* Pour passer un paramètre de chemin ou un paramètre de requête, ajoutez-le directement à l’URL.\n* Pour passer un corps JSON, passez un objet Python (par exemple un `dict`) au paramètre `json`.\n* Si vous devez envoyer des *Form Data* au lieu de JSON, utilisez le paramètre `data` à la place.\n* Pour passer des en-têtes, utilisez un `dict` dans le paramètre `headers`.\n* Pour les cookies, un `dict` dans le paramètre `cookies`.\n\nPour plus d’informations sur la manière de transmettre des données au backend (en utilisant `httpx` ou le `TestClient`), consultez la [documentation HTTPX](https://www.python-httpx.org).\n\n/// info\n\nNotez que le `TestClient` reçoit des données qui peuvent être converties en JSON, pas des modèles Pydantic.\n\nSi vous avez un modèle Pydantic dans votre test et que vous souhaitez envoyer ses données à l’application pendant les tests, vous pouvez utiliser le `jsonable_encoder` décrit dans [Encodeur compatible JSON](encoder.md).\n\n///\n\n## Exécuter { #run-it }\n\nAprès cela, vous avez simplement besoin d’installer `pytest`.\n\nVous devez créer un [environnement virtuel](../virtual-environments.md), l’activer, puis y installer le paquet, par exemple :\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\nIl détectera automatiquement les fichiers et les tests, les exécutera et vous communiquera les résultats.\n\nExécutez les tests avec :\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/fr/docs/virtual-environments.md",
    "content": "# Environnements virtuels { #virtual-environments }\n\nLorsque vous travaillez sur des projets Python, vous devriez probablement utiliser un environnement virtuel (ou un mécanisme similaire) pour isoler les packages que vous installez pour chaque projet.\n\n/// info\n\nSi vous connaissez déjà les environnements virtuels, comment les créer et les utiliser, vous pouvez passer cette section. 🤓\n\n///\n\n/// tip | Astuce\n\nUn environnement virtuel est différent d’une variable d’environnement.\n\nUne variable d’environnement est une variable du système qui peut être utilisée par des programmes.\n\nUn environnement virtuel est un répertoire contenant certains fichiers.\n\n///\n\n/// info\n\nCette page vous apprendra à utiliser les environnements virtuels et à comprendre leur fonctionnement.\n\nSi vous êtes prêt à adopter un outil qui gère tout pour vous (y compris l’installation de Python), essayez [uv](https://github.com/astral-sh/uv).\n\n///\n\n## Créer un projet { #create-a-project }\n\nCommencez par créer un répertoire pour votre projet.\n\nCe que je fais généralement, c’est créer un répertoire nommé `code` dans mon répertoire personnel/utilisateur.\n\nEt à l’intérieur, je crée un répertoire par projet.\n\n<div class=\"termy\">\n\n```console\n// Aller au répertoire personnel\n$ cd\n// Créer un répertoire pour tous vos projets de code\n$ mkdir code\n// Entrer dans ce répertoire code\n$ cd code\n// Créer un répertoire pour ce projet\n$ mkdir awesome-project\n// Entrer dans ce répertoire de projet\n$ cd awesome-project\n```\n\n</div>\n\n## Créer un environnement virtuel { #create-a-virtual-environment }\n\nLorsque vous commencez à travailler sur un projet Python pour la première fois, créez un environnement virtuel <strong><dfn title=\"il existe d'autres options, il s'agit d'une simple recommandation\">dans votre projet</dfn></strong>.\n\n/// tip | Astuce\n\nVous n’avez besoin de faire cela qu’une seule fois par projet, pas à chaque fois que vous travaillez.\n\n///\n\n//// tab | `venv`\n\nPour créer un environnement virtuel, vous pouvez utiliser le module `venv` fourni avec Python.\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | Que signifie cette commande\n\n* `python` : utiliser le programme nommé `python`\n* `-m` : appeler un module comme un script, nous préciserons ensuite quel module\n* `venv` : utiliser le module nommé `venv` qui est normalement installé avec Python\n* `.venv` : créer l’environnement virtuel dans le nouveau répertoire `.venv`\n\n///\n\n////\n\n//// tab | `uv`\n\nSi vous avez installé [`uv`](https://github.com/astral-sh/uv), vous pouvez l’utiliser pour créer un environnement virtuel.\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip | Astuce\n\nPar défaut, `uv` créera un environnement virtuel dans un répertoire appelé `.venv`.\n\nMais vous pouvez le personnaliser en passant un argument supplémentaire avec le nom du répertoire.\n\n///\n\n////\n\nCette commande crée un nouvel environnement virtuel dans un répertoire appelé `.venv`.\n\n/// details | `.venv` ou autre nom\n\nVous pourriez créer l’environnement virtuel dans un autre répertoire, mais il est d’usage de l’appeler `.venv`.\n\n///\n\n## Activer l’environnement virtuel { #activate-the-virtual-environment }\n\nActivez le nouvel environnement virtuel afin que toute commande Python que vous exécutez ou tout package que vous installez l’utilise.\n\n/// tip | Astuce\n\nFaites cela à chaque fois que vous démarrez une nouvelle session de terminal pour travailler sur le projet.\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nOu si vous utilisez Bash pour Windows (par exemple [Git Bash](https://gitforwindows.org/)) :\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip | Astuce\n\nChaque fois que vous installez un nouveau package dans cet environnement, activez de nouveau l’environnement.\n\nVous vous assurez ainsi que si vous utilisez un programme de terminal (<abbr title=\"command line interface - interface en ligne de commande\">CLI</abbr>) installé par ce package, vous utilisez celui de votre environnement virtuel et non un autre qui pourrait être installé globalement, probablement avec une version différente de celle dont vous avez besoin.\n\n///\n\n## Vérifier que l’environnement virtuel est actif { #check-the-virtual-environment-is-active }\n\nVérifiez que l’environnement virtuel est actif (la commande précédente a fonctionné).\n\n/// tip | Astuce\n\nC’est facultatif, mais c’est une bonne manière de vérifier que tout fonctionne comme prévu et que vous utilisez l’environnement virtuel voulu.\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\nS’il affiche le binaire `python` à `.venv/bin/python`, dans votre projet (dans cet exemple `awesome-project`), alors cela a fonctionné. 🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\nS’il affiche le binaire `python` à `.venv\\Scripts\\python`, dans votre projet (dans cet exemple `awesome-project`), alors cela a fonctionné. 🎉\n\n////\n\n## Mettre à niveau `pip` { #upgrade-pip }\n\n/// tip | Astuce\n\nSi vous utilisez [`uv`](https://github.com/astral-sh/uv), vous l’utiliserez pour installer des éléments à la place de `pip`, vous n’avez donc pas besoin de mettre `pip` à niveau. 😎\n\n///\n\nSi vous utilisez `pip` pour installer des packages (il est fourni par défaut avec Python), vous devez le mettre à niveau vers la dernière version.\n\nBeaucoup d’erreurs exotiques lors de l’installation d’un package se résolvent simplement en mettant d’abord `pip` à niveau.\n\n/// tip | Astuce\n\nVous feriez normalement cela une seule fois, juste après avoir créé l’environnement virtuel.\n\n///\n\nVous devez vous assurer que l’environnement virtuel est actif (avec la commande ci-dessus), puis exécuter :\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip | Astuce\n\nParfois, vous pourriez obtenir une erreur **`No module named pip`** en essayant de mettre à niveau pip.\n\nSi cela arrive, installez et mettez à niveau pip avec la commande ci-dessous :\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\nCette commande installera pip s’il n’est pas déjà installé et garantit aussi que la version de pip installée est au moins aussi récente que celle disponible dans `ensurepip`.\n\n///\n\n## Ajouter `.gitignore` { #add-gitignore }\n\nSi vous utilisez Git (vous devriez), ajoutez un fichier `.gitignore` pour exclure tout ce qui se trouve dans votre `.venv` de Git.\n\n/// tip | Astuce\n\nSi vous avez utilisé [`uv`](https://github.com/astral-sh/uv) pour créer l’environnement virtuel, il l’a déjà fait pour vous, vous pouvez passer cette étape. 😎\n\n///\n\n/// tip | Astuce\n\nFaites cela une seule fois, juste après avoir créé l’environnement virtuel.\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | Que signifie cette commande\n\n* `echo \"*\"` : va « afficher » le texte `*` dans le terminal (la partie suivante change un peu cela)\n* `>` : tout ce qui est affiché dans le terminal par la commande à gauche de `>` ne doit pas être affiché mais écrit dans le fichier à droite de `>`\n* `.gitignore` : le nom du fichier dans lequel le texte doit être écrit\n\nEt `*` signifie pour Git « tout ». Ainsi, il ignorera tout dans le répertoire `.venv`.\n\nCette commande créera un fichier `.gitignore` avec le contenu :\n\n```gitignore\n*\n```\n\n///\n\n## Installer des packages { #install-packages }\n\nAprès avoir activé l’environnement, vous pouvez y installer des packages.\n\n/// tip | Astuce\n\nFaites cela une seule fois lorsque vous installez ou mettez à niveau les packages nécessaires à votre projet.\n\nSi vous devez mettre à niveau une version ou ajouter un nouveau package, vous le referez.\n\n///\n\n### Installer des packages directement { #install-packages-directly }\n\nSi vous êtes pressé et ne souhaitez pas utiliser un fichier pour déclarer les dépendances de votre projet, vous pouvez les installer directement.\n\n/// tip | Astuce\n\nC’est une très bonne idée de placer les packages et leurs versions nécessaires à votre programme dans un fichier (par exemple `requirements.txt` ou `pyproject.toml`).\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nSi vous avez [`uv`](https://github.com/astral-sh/uv) :\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### Installer depuis `requirements.txt` { #install-from-requirements-txt }\n\nSi vous avez un `requirements.txt`, vous pouvez maintenant l’utiliser pour installer ses packages.\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nSi vous avez [`uv`](https://github.com/astral-sh/uv) :\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\nUn `requirements.txt` avec quelques packages pourrait ressembler à :\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## Exécuter votre programme { #run-your-program }\n\nAprès avoir activé l’environnement virtuel, vous pouvez exécuter votre programme, et il utilisera le Python de votre environnement virtuel avec les packages que vous y avez installés.\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## Configurer votre éditeur { #configure-your-editor }\n\nVous utiliserez probablement un éditeur, assurez-vous de le configurer pour utiliser le même environnement virtuel que vous avez créé (il le détectera probablement automatiquement) afin d’avoir l’autocomplétion et les erreurs inline.\n\nPar exemple :\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip | Astuce\n\nVous devez normalement faire cela une seule fois, lorsque vous créez l’environnement virtuel.\n\n///\n\n## Désactiver l’environnement virtuel { #deactivate-the-virtual-environment }\n\nUne fois que vous avez fini de travailler sur votre projet, vous pouvez désactiver l’environnement virtuel.\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\nAinsi, lorsque vous exécutez `python`, il n’essaiera pas de l’exécuter depuis cet environnement virtuel avec les packages qui y sont installés.\n\n## Prêt à travailler { #ready-to-work }\n\nVous êtes maintenant prêt à commencer à travailler sur votre projet.\n\n\n\n/// tip | Astuce\n\nVoulez-vous comprendre tout ce qui précède ?\n\nContinuez la lecture. 👇🤓\n\n///\n\n## Pourquoi des environnements virtuels { #why-virtual-environments }\n\nPour travailler avec FastAPI, vous devez installer [Python](https://www.python.org/).\n\nEnsuite, vous devrez installer FastAPI et tout autre package que vous souhaitez utiliser.\n\nPour installer des packages, vous utiliseriez normalement la commande `pip` fournie avec Python (ou des alternatives similaires).\n\nNéanmoins, si vous utilisez simplement `pip` directement, les packages seraient installés dans votre environnement Python global (l’installation globale de Python).\n\n### Le problème { #the-problem }\n\nAlors, quel est le problème d’installer des packages dans l’environnement Python global ?\n\nÀ un moment donné, vous finirez probablement par écrire de nombreux programmes différents qui dépendent de packages différents. Et certains de ces projets sur lesquels vous travaillez dépendront de versions différentes du même package. 😱\n\nPar exemple, vous pourriez créer un projet appelé `philosophers-stone`, ce programme dépend d’un autre package appelé **`harry`, en version `1`**. Vous devez donc installer `harry`.\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n\nPuis, plus tard, vous créez un autre projet appelé `prisoner-of-azkaban`, et ce projet dépend aussi de `harry`, mais il a besoin de **`harry` en version `3`**.\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]\n```\n\nMais maintenant, le problème est que, si vous installez les packages globalement (dans l’environnement global) au lieu de dans un environnement virtuel local, vous devrez choisir quelle version de `harry` installer.\n\nSi vous voulez exécuter `philosophers-stone`, vous devrez d’abord installer `harry` en version `1`, par exemple avec :\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\nEt vous vous retrouverez avec `harry` en version `1` installé dans votre environnement Python global.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\nMais si vous voulez ensuite exécuter `prisoner-of-azkaban`, vous devrez désinstaller `harry` version `1` et installer `harry` version `3` (ou bien installer la version `3` désinstallerait automatiquement la version `1`).\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\nEt vous vous retrouverez alors avec `harry` version `3` installé dans votre environnement Python global.\n\nEt si vous essayez d’exécuter à nouveau `philosophers-stone`, il y a une chance que cela ne fonctionne pas car il a besoin de `harry` version `1`.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --> |requires| harry-3\n    end\n```\n\n/// tip | Astuce\n\nIl est très courant que les packages Python fassent de leur mieux pour éviter les changements cassants dans les nouvelles versions, mais il vaut mieux jouer la sécurité et installer de nouvelles versions intentionnellement et lorsque vous pouvez exécuter les tests pour vérifier que tout fonctionne correctement.\n\n///\n\nMaintenant, imaginez cela avec beaucoup d’autres packages dont tous vos projets dépendent. C’est très difficile à gérer. Et vous finiriez probablement par exécuter certains projets avec des versions incompatibles des packages, sans savoir pourquoi quelque chose ne fonctionne pas.\n\nDe plus, selon votre système d’exploitation (par exemple Linux, Windows, macOS), il se peut qu’il soit livré avec Python déjà installé. Et dans ce cas, il avait probablement des packages préinstallés avec des versions spécifiques nécessaires à votre système. Si vous installez des packages dans l’environnement Python global, vous pourriez finir par casser certains des programmes fournis avec votre système d’exploitation.\n\n## Où les packages sont-ils installés { #where-are-packages-installed }\n\nLorsque vous installez Python, il crée des répertoires avec des fichiers sur votre ordinateur.\n\nCertains de ces répertoires sont chargés de contenir tous les packages que vous installez.\n\nLorsque vous exécutez :\n\n<div class=\"termy\">\n\n```console\n// Ne l’exécutez pas maintenant, c’est juste un exemple 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\nCela téléchargera un fichier compressé avec le code de FastAPI, normalement depuis [PyPI](https://pypi.org/project/fastapi/).\n\nIl téléchargera également des fichiers pour d’autres packages dont FastAPI dépend.\n\nEnsuite, il extraira tous ces fichiers et les placera dans un répertoire de votre ordinateur.\n\nPar défaut, il placera ces fichiers téléchargés et extraits dans le répertoire fourni avec votre installation de Python, c’est l’environnement global.\n\n## Qu’est-ce qu’un environnement virtuel { #what-are-virtual-environments }\n\nLa solution aux problèmes posés par le fait d’avoir tous les packages dans l’environnement global est d’utiliser un environnement virtuel pour chaque projet sur lequel vous travaillez.\n\nUn environnement virtuel est un répertoire, très similaire à celui global, où vous pouvez installer les packages pour un projet.\n\nDe cette manière, chaque projet aura son propre environnement virtuel (répertoire `.venv`) avec ses propres packages.\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) --->|requires| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --->|requires| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## Que signifie activer un environnement virtuel { #what-does-activating-a-virtual-environment-mean }\n\nLorsque vous activez un environnement virtuel, par exemple avec :\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nOu si vous utilisez Bash pour Windows (par exemple [Git Bash](https://gitforwindows.org/)) :\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\nCette commande créera ou modifiera certaines [variables d’environnement](environment-variables.md) qui seront disponibles pour les prochaines commandes.\n\nL’une de ces variables est la variable `PATH`.\n\n/// tip | Astuce\n\nVous pouvez en savoir plus sur la variable d’environnement `PATH` dans la section [Variables d’environnement](environment-variables.md#path-environment-variable).\n\n///\n\nActiver un environnement virtuel ajoute son chemin `.venv/bin` (sur Linux et macOS) ou `.venv\\Scripts` (sur Windows) à la variable d’environnement `PATH`.\n\nDisons qu’avant d’activer l’environnement, la variable `PATH` ressemblait à ceci :\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nCela signifie que le système chercherait des programmes dans :\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\nCela signifie que le système chercherait des programmes dans :\n\n* `C:\\Windows\\System32`\n\n////\n\nAprès avoir activé l’environnement virtuel, la variable `PATH` ressemblerait à quelque chose comme ceci :\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nCela signifie que le système commencera maintenant par chercher des programmes dans :\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\navant de chercher dans les autres répertoires.\n\nAinsi, lorsque vous tapez `python` dans le terminal, le système trouvera le programme Python dans\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\net utilisera celui-ci.\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\nCela signifie que le système commencera maintenant par chercher des programmes dans :\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\navant de chercher dans les autres répertoires.\n\nAinsi, lorsque vous tapez `python` dans le terminal, le système trouvera le programme Python dans\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\net utilisera celui-ci.\n\n////\n\nUn détail important est qu’il placera le chemin de l’environnement virtuel au début de la variable `PATH`. Le système le trouvera avant de trouver tout autre Python disponible. Ainsi, lorsque vous exécutez `python`, il utilisera le Python de l’environnement virtuel au lieu de tout autre `python` (par exemple, un `python` d’un environnement global).\n\nActiver un environnement virtuel change aussi deux ou trois autres choses, mais c’est l’un des points les plus importants.\n\n## Vérifier un environnement virtuel { #checking-a-virtual-environment }\n\nLorsque vous vérifiez si un environnement virtuel est actif, par exemple avec :\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\nCela signifie que le programme `python` qui sera utilisé est celui dans l’environnement virtuel.\n\nVous utilisez `which` sous Linux et macOS et `Get-Command` sous Windows PowerShell.\n\nLa façon dont cette commande fonctionne est qu’elle va vérifier la variable d’environnement `PATH`, en parcourant chaque chemin dans l’ordre, à la recherche du programme nommé `python`. Une fois trouvé, elle vous affichera le chemin vers ce programme.\n\nLa partie la plus importante est que lorsque vous appelez `python`, c’est exactement « `python` » qui sera exécuté.\n\nAinsi, vous pouvez confirmer si vous êtes dans le bon environnement virtuel.\n\n/// tip | Astuce\n\nIl est facile d’activer un environnement virtuel, d’obtenir un Python, puis d’aller vers un autre projet.\n\nEt le second projet ne fonctionnerait pas parce que vous utilisez le Python incorrect, provenant d’un environnement virtuel d’un autre projet.\n\nIl est utile de pouvoir vérifier quel `python` est utilisé. 🤓\n\n///\n\n## Pourquoi désactiver un environnement virtuel { #why-deactivate-a-virtual-environment }\n\nPar exemple, vous pourriez travailler sur un projet `philosophers-stone`, activer cet environnement virtuel, installer des packages et travailler avec cet environnement.\n\nPuis vous souhaitez travailler sur un autre projet `prisoner-of-azkaban`.\n\nVous allez vers ce projet :\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\nSi vous ne désactivez pas l’environnement virtuel de `philosophers-stone`, lorsque vous exécutez `python` dans le terminal, il essaiera d’utiliser le Python de `philosophers-stone`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// Erreur lors de l'import de sirius, il n'est pas installé 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\nMais si vous désactivez l’environnement virtuel et activez le nouveau pour `prisoner-of-askaban`, alors lorsque vous exécuterez `python`, il utilisera le Python de l’environnement virtuel de `prisoner-of-azkaban`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// Vous n’avez pas besoin d’être dans l’ancien répertoire pour désactiver, vous pouvez le faire où que vous soyez, même après être allé dans l’autre projet 😎\n$ deactivate\n\n// Activer l’environnement virtuel dans prisoner-of-azkaban/.venv 🚀\n$ source .venv/bin/activate\n\n// Maintenant, lorsque vous exécutez python, il trouvera le package sirius installé dans cet environnement virtuel ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## Alternatives { #alternatives }\n\nCeci est un guide simple pour vous lancer et vous montrer comment tout fonctionne en dessous.\n\nIl existe de nombreuses alternatives pour gérer les environnements virtuels, les dépendances de packages (requirements), les projets.\n\nLorsque vous êtes prêt et souhaitez utiliser un outil pour gérer l’ensemble du projet, les dépendances, les environnements virtuels, etc., je vous suggère d’essayer [uv](https://github.com/astral-sh/uv).\n\n`uv` peut faire beaucoup de choses, il peut :\n\n* Installer Python pour vous, y compris différentes versions\n* Gérer l’environnement virtuel pour vos projets\n* Installer des packages\n* Gérer les dépendances de packages et leurs versions pour votre projet\n* Vous assurer d’avoir un ensemble exact de packages et de versions à installer, y compris leurs dépendances, afin que vous puissiez être certain d’exécuter votre projet en production exactement comme sur votre ordinateur pendant le développement, cela s’appelle le locking\n* Et bien d’autres choses\n\n## Conclusion { #conclusion }\n\nSi vous avez lu et compris tout cela, vous en savez maintenant bien plus sur les environnements virtuels que beaucoup de développeurs. 🤓\n\nConnaître ces détails vous sera très probablement utile à l’avenir lorsque vous déboguerez quelque chose qui semble complexe, mais vous saurez comment tout fonctionne en dessous. 😎\n"
  },
  {
    "path": "docs/fr/llm-prompt.md",
    "content": "### Target language\n\nTranslate to French (français).\n\nLanguage code: fr.\n\n### Grammar to use when talking to the reader\n\nUse the formal grammar (use `vous` instead of `tu`).\n\nAdditionally, in instructional sentences, prefer the present tense for obligations:\n\n- Prefer `vous devez …` over `vous devrez …`, unless the English source explicitly refers to a future requirement.\n\n- When translating “make sure (that) … is …”, prefer the indicative after `vous assurer que` (e.g. `Vous devez vous assurer qu'il est …`) instead of the subjunctive (e.g. `qu'il soit …`).\n\n### Quotes\n\n- Convert neutral double quotes (`\"`) to French guillemets (`«` and `»`).\n\n- Do not convert quotes inside code blocks, inline code, paths, URLs, or anything wrapped in backticks.\n\nExamples:\n\nSource (English):\n\n```\n\"Hello world\"\n“Hello Universe”\n\"He said: 'Hello'\"\n\"The module is `__main__`\"\n```\n\nResult (French):\n\n```\n\"Hello world\"\n“Hello Universe”\n\"He said: 'Hello'\"\n\"The module is `__main__`\"\n```\n\n### Ellipsis\n\n- Make sure there is a space between an ellipsis and a word following or preceding the ellipsis.\n\nExamples:\n\nSource (English):\n\n```\n...as we intended.\n...this would work:\n...etc.\nothers...\nMore to come...\n```\n\nResult (French):\n\n```\n... comme prévu.\n... cela fonctionnerait :\n... etc.\nD'autres ...\nLa suite ...\n```\n\n- This does not apply in URLs, code blocks, and code snippets. Do not remove or add spaces there.\n\n### Headings\n\n- Prefer translating headings using the infinitive form (as is common in the existing French docs): `Créer…`, `Utiliser…`, `Ajouter…`.\n\n- For headings that are instructions written in imperative in English (e.g. `Go check …`), keep them in imperative in French, using the formal grammar (e.g. `Allez voir …`).\n\n### French instructions about technical terms\n\nDo not try to translate everything. In particular, keep common programming terms (e.g. `framework`, `endpoint`, `plug-in`, `payload`).\n\nKeep class names, function names, modules, file names, and CLI commands unchanged.\n\n### List of English terms and their preferred French translations\n\nBelow is a list of English terms and their preferred French translations, separated by a colon (:). Use these translations, do not use your own. If an existing translation does not use these terms, update it to use them.\n\n- /// note | Technical Details»: /// note | Détails techniques\n- /// note: /// note | Remarque\n- /// tip: /// tip | Astuce\n- /// warning: /// warning | Alertes\n- /// check: /// check | Vérifications\n- /// info: /// info\n\n- the docs: les documents\n- the documentation: la documentation\n\n- Exclude from OpenAPI: Exclusion d'OpenAPI\n\n- framework: framework (do not translate to cadre)\n- performance: performance\n\n- type hints: annotations de type\n- type annotations: annotations de type\n\n- autocomplete: autocomplétion\n- autocompletion: autocomplétion\n\n- the request (what the client sends to the server): la requête\n- the response (what the server sends back to the client): la réponse\n\n- the request body: le corps de la requête\n- the response body: le corps de la réponse\n\n- path operation: chemin d'accès\n- path operations (plural): chemins d'accès\n- path operation function: fonction de chemin d'accès\n- path operation decorator: décorateur de chemin d'accès\n\n- path parameter: paramètre de chemin\n- query parameter: paramètre de requête\n\n- the `Request`: `Request` (keep as code identifier)\n- the `Response`: `Response` (keep as code identifier)\n\n- deployment: déploiement\n- to upgrade: mettre à niveau\n\n- deprecated: déprécié\n- to deprecate: déprécier\n\n- cheat sheet: aide-mémoire\n- plug-in: plug-in\n"
  },
  {
    "path": "docs/fr/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs/ja/docs/_llm-test.md",
    "content": "# LLM テストファイル { #llm-test-file }\n\nこのドキュメントは、ドキュメントを翻訳する <abbr title=\"Large Language Model - 大規模言語モデル\">LLM</abbr> が、`scripts/translate.py` の `general_prompt` と、`docs/{language code}/llm-prompt.md` の言語固有プロンプトを理解しているかをテストします。言語固有プロンプトは `general_prompt` の末尾に追加されます。\n\nここに追加したテストは、すべての言語固有プロンプトの設計者が参照します。\n\n使い方:\n\n* 言語固有プロンプトを用意します - `docs/{language code}/llm-prompt.md`。\n* この文書を希望するターゲット言語に新規で翻訳します（例: `translate.py` の `translate-page` コマンド）。これにより `docs/{language code}/docs/_llm-test.md` に翻訳が作成されます。\n* 翻訳が問題ないか確認します。\n* 必要であれば、言語固有プロンプト、general プロンプト、または英語ドキュメントを改善します。\n* その後、翻訳に残っている問題を手動で修正し、良い翻訳にします。\n* 良い翻訳を用意した状態でもう一度翻訳します。理想的な結果は、LLM が翻訳に一切変更を加えないことです。つまり general プロンプトと言語固有プロンプトが最良であることを意味します（時々いくつかランダムに見える変更を行うことがあります。理由は [LLM は決定論的アルゴリズムではない](https://doublespeak.chat/#/handbook#deterministic-output) ためです）。\n\nテスト内容:\n\n## コードスニペット { #code-snippets }\n\n//// tab | テスト\n\nこれはコードスニペットです: `foo`。そしてこれもコードスニペットです: `bar`。さらにもう一つ: `baz quux`。\n\n////\n\n//// tab | 情報\n\nコードスニペットの内容はそのままにしておく必要があります。\n\n`scripts/translate.py` の general プロンプト内「### Content of code snippets」の節を参照してください。\n\n////\n\n## 引用 { #quotes }\n\n//// tab | テスト\n\n昨日、友人はこう書きました。「incorrectly を正しく綴れば、あなたはそれを間違って綴ったことになる」。それに対して私はこう答えました。「そのとおり。ただし『incorrectly』は誤りで、『\"incorrectly\"』ではありません」。\n\n/// note | 備考\n\nLLM はおそらくここを誤って翻訳します。重要なのは、再翻訳時に修正済みの翻訳を維持できるかどうかだけです。\n\n///\n\n////\n\n//// tab | 情報\n\nプロンプト設計者は、ストレートクォートをタイポグラフィックな引用符に変換するかどうかを選べます。そのままでも問題ありません。\n\n例として `docs/de/llm-prompt.md` の「### Quotes」の節を参照してください。\n\n////\n\n## コードスニペット内の引用 { #quotes-in-code-snippets }\n\n//// tab | テスト\n\n`pip install \"foo[bar]\"`\n\nコードスニペット中の文字列リテラルの例: `\"this\"`, `'that'`.\n\n難しい文字列リテラルの例: `f\"I like {'oranges' if orange else \"apples\"}\"`\n\nハードコア: `Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | 情報\n\n... ただし、コードスニペット内の引用符はそのままにしておく必要があります。\n\n////\n\n## コードブロック { #code-blocks }\n\n//// tab | テスト\n\nBash のコード例です...\n\n```bash\n# 宇宙にあいさつを表示\necho \"Hello universe\"\n```\n\n...そしてコンソールのコード例です...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n...さらに別のコンソールのコード例です...\n\n```console\n// ディレクトリ \"Code\" を作成\n$ mkdir code\n// そのディレクトリに移動\n$ cd code\n```\n\n...そして Python のコード例です...\n\n```Python\nwont_work()  # これは動作しません 😱\nworks(foo=\"bar\")  # これは動作します 🎉\n```\n\n...以上です。\n\n////\n\n//// tab | 情報\n\nコードブロック内のコードは、コメントを除き、変更してはいけません。\n\n`scripts/translate.py` の general プロンプト内「### Content of code blocks」の節を参照してください。\n\n////\n\n## タブと色付きボックス { #tabs-and-colored-boxes }\n\n//// tab | テスト\n\n/// info | 情報\nいくつかのテキスト\n///\n\n/// note | 備考\nいくつかのテキスト\n///\n\n/// note | 技術詳細\nいくつかのテキスト\n///\n\n/// check | 確認\nいくつかのテキスト\n///\n\n/// tip | 豆知識\nいくつかのテキスト\n///\n\n/// warning | 注意\nいくつかのテキスト\n///\n\n/// danger | 警告\nいくつかのテキスト\n///\n\n////\n\n//// tab | 情報\n\nタブおよび `Info`/`Note`/`Warning` などのブロックには、タイトルの翻訳を縦棒（`|`）の後ろに追加します。\n\n`scripts/translate.py` の general プロンプト内「### Special blocks」と「### Tab blocks」の節を参照してください。\n\n////\n\n## Web リンクと内部リンク { #web-and-internal-links }\n\n//// tab | テスト\n\nリンクのテキストは翻訳し、リンク先のアドレスは変更しないでください:\n\n* [上の見出しへのリンク](#code-snippets)\n* [内部リンク](index.md#installation)\n* [外部リンク](https://sqlmodel.tiangolo.com/)\n* [スタイルへのリンク](https://fastapi.tiangolo.com/css/styles.css)\n* [スクリプトへのリンク](https://fastapi.tiangolo.com/js/logic.js)\n* [画像へのリンク](https://fastapi.tiangolo.com/img/foo.jpg)\n\nリンクのテキストは翻訳し、リンク先のアドレスは翻訳版を指すようにしてください:\n\n* [FastAPI リンク](https://fastapi.tiangolo.com/ja/)\n\n////\n\n//// tab | 情報\n\nリンクのテキストは翻訳し、アドレスは変更しないでください。例外は、FastAPI ドキュメントのページへの絶対 URL です。その場合は翻訳版へのリンクにします。\n\n`scripts/translate.py` の general プロンプト内「### Links」の節を参照してください。\n\n////\n\n## HTML \"abbr\" 要素 { #html-abbr-elements }\n\n//// tab | テスト\n\nここでは HTML の \"abbr\" 要素で包まれたものをいくつか示します（いくつかは架空です）:\n\n### abbr が完全な語句を示す { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done - 仕事を成し遂げること\">GTD</abbr>\n* <abbr title=\"less than - より小さい\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token - XML ウェブトークン\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface - 並列サーバーゲートウェイインターフェース\">PSGI</abbr>\n\n### abbr が完全な語句と説明を示す { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network - Mozilla 開発者ネットワーク: 開発者向けドキュメント、Firefox の開発元が執筆\">MDN</abbr>\n* <abbr title=\"Input/Output - 入出力: ディスクの読み書き、ネットワーク通信。\">I/O</abbr>.\n\n////\n\n//// tab | 情報\n\n\"abbr\" 要素の \"title\" 属性は特定の指示に従って翻訳します。\n\n翻訳は、英語の語を説明するために独自の \"abbr\" 要素を追加してもよく、LLM はそれらを削除してはいけません。\n\n`scripts/translate.py` の general プロンプト内「### HTML abbr elements」の節を参照してください。\n\n////\n\n## HTML \"dfn\" 要素 { #html-dfn-elements }\n\n* <dfn title=\"ある方法で接続・連携して動作するよう構成された複数のマシンの集合\">クラスター</dfn>\n* <dfn title=\"入力層と出力層の間に多数の隠れ層を持つ人工ニューラルネットワークを用いる機械学習の手法で、その内部構造を包括的に形成する\">ディープラーニング</dfn>\n\n## 見出し { #headings }\n\n//// tab | テスト\n\n### Web アプリを開発する - チュートリアル { #develop-a-webapp-a-tutorial }\n\nこんにちは。\n\n### 型ヒントとアノテーション { #type-hints-and-annotations }\n\nまたこんにちは。\n\n### スーパークラスとサブクラス { #super-and-subclasses }\n\nまたこんにちは。\n\n////\n\n//// tab | 情報\n\n見出しに関する唯一の厳格なルールは、リンクが壊れないように、LLM が中括弧内のハッシュ部分を変更しないことです。\n\n`scripts/translate.py` の general プロンプト内「### Headings」の節を参照してください。\n\n言語固有の指示については、例として `docs/de/llm-prompt.md` の「### Headings」の節を参照してください。\n\n////\n\n## ドキュメントで使う用語 { #terms-used-in-the-docs }\n\n//// tab | テスト\n\n* you\n* your\n\n* e.g.\n* etc.\n\n* `foo` を `int` として\n* `bar` を `str` として\n* `baz` を `list` として\n\n* チュートリアル - ユーザーガイド\n* 上級ユーザーガイド\n* SQLModel ドキュメント\n* API ドキュメント\n* 自動生成ドキュメント\n\n* データサイエンス\n* ディープラーニング\n* 機械学習\n* 依存性注入\n* HTTP Basic 認証\n* HTTP Digest\n* ISO 形式\n* JSON Schema 規格\n* JSON スキーマ\n* スキーマ定義\n* Password Flow\n* モバイル\n\n* 非推奨\n* 設計された\n* 無効\n* オンザフライ\n* 標準\n* デフォルト\n* 大文字小文字を区別\n* 大文字小文字を区別しない\n\n* アプリケーションを提供する\n* ページを配信する\n\n* アプリ\n* アプリケーション\n\n* リクエスト\n* レスポンス\n* エラーレスポンス\n\n* path operation\n* path operation デコレータ\n* path operation 関数\n\n* ボディ\n* リクエストボディ\n* レスポンスボディ\n* JSON ボディ\n* フォームボディ\n* ファイルボディ\n* 関数本体\n\n* パラメータ\n* ボディパラメータ\n* パスパラメータ\n* クエリパラメータ\n* Cookie パラメータ\n* ヘッダーパラメータ\n* フォームパラメータ\n* 関数パラメータ\n\n* イベント\n* 起動イベント\n* サーバーの起動\n* シャットダウンイベント\n* lifespan イベント\n\n* ハンドラ\n* イベントハンドラ\n* 例外ハンドラ\n* 処理する\n\n* モデル\n* Pydantic モデル\n* データモデル\n* データベースモデル\n* フォームモデル\n* モデルオブジェクト\n\n* クラス\n* 基底クラス\n* 親クラス\n* サブクラス\n* 子クラス\n* 兄弟クラス\n* クラスメソッド\n\n* ヘッダー\n* ヘッダー（複数）\n* 認可ヘッダー\n* `Authorization` ヘッダー\n* Forwarded ヘッダー\n\n* 依存性注入システム\n* 依存関係\n* dependable\n* dependant\n\n* I/O バウンド\n* CPU バウンド\n* 同時実行性\n* 並列性\n* マルチプロセッシング\n\n* env var\n* 環境変数\n* `PATH`\n* `PATH` 環境変数\n\n* 認証\n* 認証プロバイダ\n* 認可\n* 認可フォーム\n* 認可プロバイダ\n* ユーザーが認証する\n* システムがユーザーを認証する\n\n* CLI\n* コマンドラインインターフェース\n\n* サーバー\n* クライアント\n\n* クラウドプロバイダ\n* クラウドサービス\n\n* 開発\n* 開発段階\n\n* dict\n* 辞書\n* 列挙型\n* Enum\n* 列挙メンバー\n\n* エンコーダー\n* デコーダー\n* エンコードする\n* デコードする\n\n* 例外\n* 送出する\n\n* 式\n* 文\n\n* フロントエンド\n* バックエンド\n\n* GitHub ディスカッション\n* GitHub Issue\n\n* パフォーマンス\n* パフォーマンス最適化\n\n* 戻り値の型\n* 戻り値\n\n* セキュリティ\n* セキュリティスキーム\n\n* タスク\n* バックグラウンドタスク\n* タスク関数\n\n* テンプレート\n* テンプレートエンジン\n\n* 型アノテーション\n* 型ヒント\n\n* サーバーワーカー\n* Uvicorn ワーカー\n* Gunicorn ワーカー\n* ワーカープロセス\n* ワーカークラス\n* ワークロード\n\n* デプロイ\n* デプロイする\n\n* SDK\n* ソフトウェア開発キット\n\n* `APIRouter`\n* `requirements.txt`\n* Bearer Token\n* 破壊的変更\n* バグ\n* ボタン\n* 呼び出し可能\n* コード\n* コミット\n* コンテキストマネージャ\n* コルーチン\n* データベースセッション\n* ディスク\n* ドメイン\n* エンジン\n* フェイクの X\n* HTTP GET メソッド\n* アイテム\n* ライブラリ\n* ライフスパン\n* ロック\n* ミドルウェア\n* モバイルアプリケーション\n* モジュール\n* マウント\n* ネットワーク\n* オリジン\n* オーバーライド\n* ペイロード\n* プロセッサ\n* プロパティ\n* プロキシ\n* プルリクエスト\n* クエリ\n* RAM\n* リモートマシン\n* ステータスコード\n* 文字列\n* タグ\n* Web フレームワーク\n* ワイルドカード\n* 返す\n* 検証する\n\n////\n\n//// tab | 情報\n\nこれはドキュメントで見られる（主に）技術用語の不完全かつ規範的でない一覧です。プロンプト設計者が、LLM がどの用語で手助けを必要としているかを把握するのに役立つかもしれません。例えば、良い翻訳を最適でない翻訳に戻してしまう場合や、あなたの言語での活用・格変化に問題がある場合などです。\n\n`docs/de/llm-prompt.md` の「### List of English terms and their preferred German translations」の節を参照してください。\n\n////\n"
  },
  {
    "path": "docs/ja/docs/about/index.md",
    "content": "# 概要 { #about }\n\nFastAPI の概要、その設計やインスピレーションなどについて解説します。🤓\n"
  },
  {
    "path": "docs/ja/docs/advanced/additional-responses.md",
    "content": "# OpenAPI の追加レスポンス { #additional-responses-in-openapi }\n\n/// warning | 注意\n\nこれは比較的高度なトピックです。\n\nFastAPI を使い始めたばかりであれば、これは不要かもしれません。\n\n///\n\n追加のステータスコード、メディアタイプ、説明などを伴う追加レスポンスを宣言できます。\n\nそれらの追加レスポンスは OpenAPI スキーマに含まれ、API ドキュメントにも表示されます。\n\nただし、それらの追加レスポンスについては、ステータスコードとコンテンツを指定して `JSONResponse` などの `Response` を直接返す必要があります。\n\n## `model` を使った追加レスポンス { #additional-response-with-model }\n\n*path operation デコレータ*に `responses` パラメータを渡せます。\n\nこれは `dict` を受け取り、キーは各レスポンスのステータスコード（例: `200`）、値は各レスポンスの情報を含む別の `dict` です。\n\nそれぞれのレスポンス `dict` には、`response_model` と同様に Pydantic モデルを格納する `model` キーを含められます。\n\nFastAPI はそのモデルから JSON Schema を生成し、OpenAPI の適切な場所に含めます。\n\n例えば、ステータスコード `404` と Pydantic モデル `Message` を持つ別のレスポンスを宣言するには、次のように書けます:\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | 備考\n\n`JSONResponse` を直接返す必要がある点に注意してください。\n\n///\n\n/// info | 情報\n\n`model` キーは OpenAPI の一部ではありません。\n\nFastAPI はそこから Pydantic モデルを取得して JSON Schema を生成し、適切な場所に配置します。\n\n適切な場所は次のとおりです:\n\n- `content` キーの中。これは値として別の JSON オブジェクト（`dict`）を持ち、その中に次が含まれます:\n    - メディアタイプ（例: `application/json`）をキーとし、値としてさらに別の JSON オブジェクトを持ち、その中に次が含まれます:\n        - `schema` キー。値としてモデル由来の JSON Schema を持ち、ここが正しい配置場所です。\n            - FastAPI はここに、スキーマを直接埋め込む代わりに OpenAPI 内のグローバルな JSON Schema への参照を追加します。これにより、他のアプリケーションやクライアントがそれらの JSON Schema を直接利用し、より良いコード生成ツール等を提供できます。\n\n///\n\nこの *path operation* のために OpenAPI に生成されるレスポンスは次のとおりです:\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nスキーマは OpenAPI スキーマ内の別の場所への参照になります:\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## メインのレスポンスに追加のメディアタイプ { #additional-media-types-for-the-main-response }\n\n同じ `responses` パラメータを使って、同一のメインレスポンスに別のメディアタイプを追加できます。\n\n例えば、`image/png` の追加メディアタイプを加え、あなたの *path operation* が JSON オブジェクト（メディアタイプ `application/json`）または PNG 画像を返せることを宣言できます:\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | 備考\n\n画像は `FileResponse` を使って直接返す必要がある点に注意してください。\n\n///\n\n/// info | 情報\n\n`responses` パラメータで明示的に別のメディアタイプを指定しない限り、FastAPI はレスポンスがメインのレスポンスクラスと同じメディアタイプ（デフォルトは `application/json`）であるとみなします。\n\nただし、メディアタイプが `None` のカスタムレスポンスクラスを指定している場合、モデルが関連付けられた追加レスポンスには FastAPI は `application/json` を使用します。\n\n///\n\n## 情報の結合 { #combining-information }\n\n`response_model`、`status_code`、`responses` パラメータなど、複数の場所からのレスポンス情報を組み合わせることもできます。\n\n`response_model` を宣言し、デフォルトのステータスコード `200`（必要なら任意のコード）を使い、その同じレスポンスに対する追加情報を `responses` で OpenAPI スキーマに直接記述できます。\n\nFastAPI は `responses` にある追加情報を保持し、モデルの JSON Schema と結合します。\n\n例えば、Pydantic モデルを用い、独自の `description` を持つステータスコード `404` のレスポンスを宣言できます。\n\nさらに、`response_model` を使うステータスコード `200` のレスポンスに独自の `example` を含めることもできます:\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\nこれらはすべて結合されて OpenAPI に含まれ、API ドキュメントに表示されます:\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## 事前定義レスポンスとカスタムの組み合わせ { #combine-predefined-responses-and-custom-ones }\n\n多くの *path operations* に適用できる事前定義のレスポンスを用意しつつ、各 *path operation* ごとに必要なカスタムレスポンスと組み合わせたい場合があります。\n\nそのような場合、Python の `**dict_to_unpack` による `dict` の「アンパック」テクニックを使えます:\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\nここでは、`new_dict` には `old_dict` のすべてのキーと値に加え、新しいキーと値が含まれます:\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\nこのテクニックを使うと、*path operations* で事前定義レスポンスを再利用し、さらにカスタムのレスポンスを組み合わせられます。\n\n例えば:\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## OpenAPI レスポンスの詳細 { #more-information-about-openapi-responses }\n\nレスポンスに正確に何を含められるかは、OpenAPI 仕様の次のセクションを参照してください:\n\n- [OpenAPI の Responses Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object)、ここには `Response Object` が含まれます。\n- [OpenAPI の Response Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object)、`responses` パラメータ内の各レスポンスに、ここで定義されている要素を直接含められます。`description`、`headers`、`content`（ここで異なるメディアタイプや JSON Schema を宣言します）、`links` など。\n"
  },
  {
    "path": "docs/ja/docs/advanced/additional-status-codes.md",
    "content": "# 追加のステータスコード { #additional-status-codes }\n\nデフォルトでは、 **FastAPI** は `JSONResponse` を使ってレスポンスを返し、*path operation* から返した内容をその `JSONResponse` の中に入れます。\n\nデフォルトのステータスコード、または *path operation* で設定したステータスコードが使用されます。\n\n## 追加のステータスコード { #additional-status-codes_1 }\n\nメインのステータスコードとは別に追加のステータスコードを返したい場合は、`JSONResponse` のような `Response` を直接返し、追加のステータスコードを直接設定できます。\n\nたとえば、item を更新でき、成功時に HTTP ステータスコード 200 \"OK\" を返す *path operation* を作りたいとします。\n\nしかし、新しい item も受け付けたいとします。そして、item が以前存在しなかった場合には作成し、HTTP ステータスコード 201「Created」を返します。\n\nこれを実現するには、`JSONResponse` をインポートし、望む `status_code` を設定して、そこで内容を直接返します。\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning\n\n上の例のように `Response` を直接返すと、それはそのまま返されます。\n\nモデルなどによってシリアライズされません。\n\n必要なデータが含まれていること、そして（`JSONResponse` を使用している場合）値が有効な JSON であることを確認してください。\n\n///\n\n/// note | 技術詳細\n\n`from starlette.responses import JSONResponse` を使うこともできます。\n\n**FastAPI** は開発者の利便性のために、`fastapi.responses` と同じ `starlette.responses` を提供しています。しかし、利用可能なレスポンスのほとんどは Starlette から直接提供されています。`status` も同様です。\n\n///\n\n## OpenAPI と API ドキュメント { #openapi-and-api-docs }\n\n追加のステータスコードとレスポンスを直接返す場合、それらは OpenAPI スキーマ（API ドキュメント）には含まれません。FastAPI には、事前に何が返されるかを知る方法がないからです。\n\nしかし、[追加のレスポンス](additional-responses.md) を使ってコード内にドキュメント化できます。\n"
  },
  {
    "path": "docs/ja/docs/advanced/advanced-dependencies.md",
    "content": "# 高度な依存関係 { #advanced-dependencies }\n\n## パラメータ化された依存関係 { #parameterized-dependencies }\n\nこれまで見てきた依存関係は、固定の関数またはクラスでした。\n\nしかし、多くの異なる関数やクラスを宣言せずに、その依存関係にパラメータを設定したい場合があります。\n\nたとえば、クエリパラメータ `q` に、ある固定の内容が含まれているかを検査する依存関係が欲しいとします。\n\nただし、その固定の内容はパラメータ化できるようにしたいです。\n\n## \"callable\" なインスタンス { #a-callable-instance }\n\nPython には、クラスのインスタンスを \"callable\" にする方法があります。\n\nクラス自体（これはすでに callable です）ではなく、そのクラスのインスタンスです。\n\nそのためには、`__call__` メソッドを宣言します:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\nこの場合、この `__call__` が、**FastAPI** が追加のパラメータやサブ依存関係を確認するために使うものになり、後であなたの *path operation 関数* のパラメータに値を渡すために呼び出されるものになります。\n\n## インスタンスのパラメータ化 { #parameterize-the-instance }\n\nそして、`__init__` を使って、依存関係を「パラメータ化」するために利用できるインスタンスのパラメータを宣言できます:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\nこの場合、**FastAPI** は `__init__` に触れたり気にかけたりすることはありません。私たちがコード内で直接使います。\n\n## インスタンスの作成 { #create-an-instance }\n\nこのクラスのインスタンスは次のように作成できます:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\nこのようにして依存関係を「パラメータ化」できます。いまや `\"bar\"` が属性 `checker.fixed_content` として中に保持されています。\n\n## インスタンスを依存関係として使う { #use-the-instance-as-a-dependency }\n\nその後、`Depends(FixedContentQueryChecker)` の代わりに `Depends(checker)` でこの `checker` を使えます。依存関係はクラスそのものではなく、インスタンスである `checker` だからです。\n\n依存関係を解決するとき、**FastAPI** はこの `checker` を次のように呼び出します:\n\n```Python\nchecker(q=\"somequery\")\n```\n\n...そして、その戻り値を *path operation 関数* 内の依存関係の値として、パラメータ `fixed_content_included` に渡します:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | 豆知識\n\nここまでの内容は回りくどく感じられるかもしれません。まだどのように役立つかが明確でないかもしれません。\n\nこれらの例は意図的に単純ですが、仕組みを示しています。\n\nセキュリティの章では、同じやり方で実装されたユーティリティ関数があります。\n\nここまでを理解できていれば、そうしたセキュリティ用ユーティリティが内部でどのように動いているかも理解できています。\n\n///\n\n## `yield`、`HTTPException`、`except` とバックグラウンドタスクを伴う依存関係 { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | 注意\n\nこれらの技術的詳細は、ほとんどの場合は不要です。\n\n主に、0.121.0 より前の FastAPI アプリケーションがあり、`yield` を使う依存関係で問題が発生している場合に有用です。\n\n///\n\n`yield` を使う依存関係は、さまざまなユースケースに対応し、いくつかの問題を修正するために時間とともに進化してきました。ここでは変更点の概要を説明します。\n\n### `yield` と `scope` を伴う依存関係 { #dependencies-with-yield-and-scope }\n\nバージョン 0.121.0 で、`yield` を使う依存関係に対して `Depends(scope=\"function\")` がサポートされました。\n\n`Depends(scope=\"function\")` を使うと、`yield` の後の終了コードは、クライアントへレスポンスが返される前、*path operation 関数* が終了した直後に実行されます。\n\nそして、`Depends(scope=\"request\")`（デフォルト）を使う場合、`yield` の後の終了コードはレスポンス送信後に実行されます。\n\n詳しくはドキュメント「[`yield` を使う依存関係 - 早期終了と `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope)」を参照してください。\n\n### `yield` と `StreamingResponse` を伴う依存関係、技術詳細 { #dependencies-with-yield-and-streamingresponse-technical-details }\n\nFastAPI 0.118.0 より前では、`yield` を使う依存関係を使用すると、*path operation 関数* が戻ってからレスポンス送信直前に終了コードが実行されていました。\n\nこれは、レスポンスがネットワーク上を移動するのを待っている間に、不要にリソースを保持しないようにする意図でした。\n\nこの変更により、`StreamingResponse` を返す場合、`yield` を持つ依存関係の終了コードはすでに実行されていることになりました。\n\nたとえば、`yield` を持つ依存関係の中でデータベースセッションを持っていた場合、`StreamingResponse` はデータをストリーミングしている間にそのセッションを使えません。というのも、`yield` の後の終了コードでそのセッションがすでにクローズされているからです。\n\nこの挙動は 0.118.0 で元に戻され、`yield` の後の終了コードはレスポンス送信後に実行されるようになりました。\n\n/// info | 情報\n\n以下で見るように、これはバージョン 0.106.0 より前の挙動ととても似ていますが、いくつかのコーナーケースに対する改良とバグ修正が含まれています。\n\n///\n\n#### 早期終了コードのユースケース { #use-cases-with-early-exit-code }\n\n特定の条件では、レスポンス送信前に `yield` を持つ依存関係の終了コードを実行する、古い挙動の恩恵を受けられるユースケースがあります。\n\n例えば、`yield` を持つ依存関係でデータベースセッションを使ってユーザ検証だけを行い、その後は *path operation 関数* 内ではそのデータベースセッションを一切使わない、かつレスポンス送信に長い時間がかかる（例えばデータをゆっくり送る `StreamingResponse`）が、何らかの理由でデータベースは使わない、というケースです。\n\nこの場合、レスポンスの送信が終わるまでデータベースセッションが保持されますが、使わないのであれば保持する必要はありません。\n\n次のようになります:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\n終了コード、すなわち `Session` の自動クローズは:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n...の部分で定義されており、遅いデータ送信が終わった後に実行されます:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nしかし、`generate_stream()` はデータベースセッションを使わないため、レスポンス送信中にセッションを開いたままにしておく必要は実際にはありません。\n\nSQLModel（または SQLAlchemy）でこの特定のユースケースがある場合は、不要になった時点でセッションを明示的にクローズできます:\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\nこのようにすると、セッションはデータベース接続を解放するため、他のリクエストがそれを使えるようになります。\n\n`yield` を持つ依存関係で早期終了が必要な別のユースケースがある場合は、あなたの具体的なユースケースと、なぜ `yield` を持つ依存関係の早期クローズが有益かを説明して、[GitHub Discussion の質問](https://github.com/fastapi/fastapi/discussions/new?category=questions)を作成してください。\n\n`yield` を持つ依存関係の早期クローズに納得できるユースケースがある場合は、早期クローズにオプトインする新しい方法を追加することを検討します。\n\n### `yield` と `except` を伴う依存関係、技術詳細 { #dependencies-with-yield-and-except-technical-details }\n\nFastAPI 0.110.0 より前では、`yield` を持つ依存関係を使い、その依存関係内で `except` によって例外を捕捉し、再度その例外を送出しなかった場合でも、その例外は自動的に送出（フォワード）され、任意の例外ハンドラまたは内部サーバエラーハンドラに渡されていました。\n\nこれは、ハンドラのないフォワードされた例外（内部サーバエラー）による未処理のメモリ消費を修正し、通常の Python コードの挙動と一貫性を持たせるため、バージョン 0.110.0 で変更されました。\n\n### バックグラウンドタスクと `yield` を伴う依存関係、技術詳細 { #background-tasks-and-dependencies-with-yield-technical-details }\n\nFastAPI 0.106.0 より前では、`yield` の後で例外を送出することはできませんでした。`yield` を持つ依存関係の終了コードはレスポンス送信「後」に実行されるため、[例外ハンドラ](../tutorial/handling-errors.md#install-custom-exception-handlers)はすでに実行済みでした。\n\nこれは主に、依存関係が \"yield\" した同じオブジェクトをバックグラウンドタスク内で利用できるようにするための設計でした。終了コードはバックグラウンドタスク完了後に実行されるからです。\n\nこれは、レスポンスがネットワーク上を移動するのを待っている間にリソースを保持しないようにする意図で、FastAPI 0.106.0 で変更されました。\n\n/// tip | 豆知識\n\n加えて、バックグラウンドタスクは通常、独立したロジックの集合であり、（例えば専用のデータベース接続など）それ自身のリソースで個別に扱うべきです。\n\nそのため、このやり方の方がコードはおそらくよりクリーンになります。\n\n///\n\nこの挙動に依存していた場合は、バックグラウンドタスク用のリソースをバックグラウンドタスク内部で作成し、`yield` を持つ依存関係のリソースに依存しないデータだけを内部で使用するようにしてください。\n\n例えば、同じデータベースセッションを使うのではなく、バックグラウンドタスク内で新しいデータベースセッションを作成し、この新しいセッションでデータベースからオブジェクトを取得します。そして、バックグラウンドタスク関数の引数としてデータベースのオブジェクト自体を渡すのではなく、そのオブジェクトの ID を渡し、バックグラウンドタスク関数内でもう一度そのオブジェクトを取得します。\n"
  },
  {
    "path": "docs/ja/docs/advanced/advanced-python-types.md",
    "content": "# 高度な Python の型 { #advanced-python-types }\n\nPython の型を扱うときに役立つ追加のアイデアをいくつか紹介します。\n\n## `Union` または `Optional` の利用 { #using-union-or-optional }\n\n何らかの理由で `|` が使えない場合、たとえば型アノテーションではなく `response_model=` のような場所では、縦棒（`|`）の代わりに `typing` の `Union` を使えます。\n\n例えば、`str` または `None` になり得ることを宣言できます:\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\n`typing` には、`None` を取り得ることを宣言するための短縮形として `Optional` もあります。\n\nここからは私のとても主観的な提案です:\n\n- 🚨 `Optional[SomeType]` の使用は避けましょう\n- 代わりに ✨ **`Union[SomeType, None]` を使いましょう** ✨。\n\nどちらも等価で内部的には同一ですが、「optional（任意）」という語が値が任意だと誤解させやすく、実際の意味は「`None` を取り得る」であり、任意ではなく依然として必須である場合でもそうです。そのため `Optional` より `Union` を勧めます。\n\n`Union[SomeType, None]` の方が意味がより明確だと思います。\n\nこれは用語や名前付けの話に過ぎませんが、その言葉があなたやチームメイトのコードの捉え方に影響します。\n\n例として次の関数を見てみましょう:\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\nパラメータ `name` は `Optional[str]` と定義されていますが、任意ではありません。このパラメータなしで関数を呼び出すことはできません:\n\n```Python\nsay_hi()  # あっ、これはエラーになります！😱\n```\n\n`name` パラメータにはデフォルト値がないため、依然として必須（任意ではない）です。ただし、`name` は値として `None` を受け付けます:\n\n```Python\nsay_hi(name=None)  # これは動作します。None は有効です 🎉\n```\n\n朗報として、多くの場合は単純に `|` を使って型の Union を定義できます:\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\nしたがって、通常は `Optional` や `Union` といった名前を気にする必要はありません。😎\n"
  },
  {
    "path": "docs/ja/docs/advanced/async-tests.md",
    "content": "# 非同期テスト { #async-tests }\n\nこれまでに、提供されている `TestClient` を使って **FastAPI** アプリケーションをテストする方法を見てきました。ここまでは、`async` 関数を使わない同期テストのみでした。\n\nテストで非同期関数を使えると、たとえばデータベースへ非同期にクエリする場合などに便利です。非同期データベースライブラリを使いながら、FastAPI アプリにリクエストを送り、その後バックエンドが正しいデータをデータベースに書き込めたかを検証したい、といったケースを想像してください。\n\nその方法を見ていきます。\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\nテスト内で非同期関数を呼び出したい場合、テスト関数自体も非同期である必要があります。AnyIO はこれを実現するための便利なプラグインを提供しており、特定のテスト関数を非同期で呼び出すことを指定できます。\n\n## HTTPX { #httpx }\n\n**FastAPI** アプリケーションが通常の `def` 関数を使っていても、その内側は依然として `async` アプリケーションです。\n\n`TestClient` は、標準の pytest を使って通常の `def` のテスト関数から非同期の FastAPI アプリを呼び出すための「おまじない」を内部で行います。しかし、その「おまじない」はテスト関数自体が非同期の場合には機能しません。テストを非同期で実行すると、テスト関数内で `TestClient` は使えなくなります。\n\n`TestClient` は [HTTPX](https://www.python-httpx.org) を基に作られており、幸いなことに API のテストには HTTPX を直接利用できます。\n\n## 例 { #example }\n\n簡単な例として、[大きなアプリケーション](../tutorial/bigger-applications.md) と [テスト](../tutorial/testing.md) で説明したものに似たファイル構成を考えます:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n`main.py` は次のようになります:\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\n`test_main.py` は `main.py` のテストを持ち、次のようになります:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## 実行 { #run-it }\n\nテストはいつも通り次で実行できます:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## 詳細 { #in-detail }\n\nマーカー `@pytest.mark.anyio` は、このテスト関数を非同期で呼び出すべきであることを pytest に伝えます:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip | 豆知識\n\n`TestClient` を使っていたときと異なり、テスト関数は `async def` ではなく `def` になっている点に注意してください。\n\n///\n\n次に、アプリを渡して `AsyncClient` を作成し、`await` を使って非同期リクエストを送信できます。\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\nこれは次と同等です:\n\n```Python\nresponse = client.get('/')\n```\n\n...これまでは `TestClient` でリクエストを送っていました。\n\n/// tip | 豆知識\n\n新しい `AsyncClient` では async/await を使っている点に注意してください。リクエストは非同期です。\n\n///\n\n/// warning | 注意\n\nアプリケーションが lifespan イベントに依存している場合、`AsyncClient` はそれらのイベントをトリガーしません。確実にトリガーするには、[florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage) の `LifespanManager` を使用してください。\n\n///\n\n## その他の非同期関数呼び出し { #other-asynchronous-function-calls }\n\nテスト関数が非同期になったので、FastAPI アプリへのリクエスト送信以外の `async` 関数も、コードの他の場所と同様に呼び出して（`await` して）使えます。\n\n/// tip | 豆知識\n\nテストに非同期関数呼び出しを統合した際に（例: [MongoDB の MotorClient](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop) 使用時）、`RuntimeError: Task attached to a different loop` に遭遇した場合は、イベントループを必要とするオブジェクトは非同期関数内でのみインスタンス化するようにしてください。例えば `@app.on_event(\"startup\")` コールバック内で行います。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/advanced/behind-a-proxy.md",
    "content": "# プロキシの背後 { #behind-a-proxy }\n\n多くの状況で、FastAPI アプリの前段に **Traefik** や **Nginx** のような**プロキシ**を置きます。\n\nこれらのプロキシは HTTPS 証明書などの処理を担います。\n\n## プロキシの転送ヘッダー { #proxy-forwarded-headers }\n\nアプリケーションの前段にある **プロキシ** は通常、リクエストを **サーバー** に送る前に、そのリクエストがプロキシによって転送されたことを知らせるためのヘッダーを動的に付与し、使用中の元の（公開）URL（ドメインを含む）や HTTPS 使用などの情報を伝えます。\n\n**サーバー** プログラム（例えば **FastAPI CLI** 経由の **Uvicorn**）はこれらのヘッダーを解釈し、その情報をアプリケーションに渡すことができます。\n\nしかしセキュリティ上、サーバーは自分が信頼できるプロキシの背後にあると分からないため、これらのヘッダーを解釈しません。\n\n/// note | 技術詳細\n\nプロキシのヘッダーは次のとおりです:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### プロキシ転送ヘッダーを有効化 { #enable-proxy-forwarded-headers }\n\nFastAPI CLI を *CLI オプション* `--forwarded-allow-ips` 付きで起動し、転送ヘッダーを信頼して読んでよい IP アドレスを指定できます。\n\n`--forwarded-allow-ips=\"*\"` とすると、すべての送信元 IP を信頼します。\n\n**サーバー** が信頼できる **プロキシ** の背後にあり、そのプロキシからのみ接続される場合、プロキシの IP を受け入れるようになります。\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### HTTPS を伴うリダイレクト { #redirects-with-https }\n\n例えば、*path operation* `/items/` を定義しているとします:\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\nクライアントが `/items` にアクセスすると、既定では `/items/` にリダイレクトされます。\n\nしかし、*CLI オプション* `--forwarded-allow-ips` を設定する前は、`http://localhost:8000/items/` にリダイレクトされる場合があります。\n\nですが、アプリケーションは `https://mysuperapp.com` で公開されており、`https://mysuperapp.com/items/` にリダイレクトされるべきかもしれません。\n\n`--proxy-headers` を設定すると、FastAPI は正しい場所にリダイレクトできるようになります。😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip | 豆知識\n\nHTTPS について詳しく知りたい場合は、[HTTPS について](../deployment/https.md) を参照してください。\n\n///\n\n### プロキシ転送ヘッダーの仕組み { #how-proxy-forwarded-headers-work }\n\nクライアントと **アプリケーションサーバー** の間で、**プロキシ** がどのように転送ヘッダーを追加するかを図示します:\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Proxy as Proxy/Load Balancer\n    participant Server as FastAPI Server\n\n    Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: Proxy adds forwarded headers\n\n    Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)\n\n    Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs\n\n    Proxy->>Client: HTTPS Response\n```\n\n**プロキシ** は元のクライアントリクエストを受け取り、**アプリケーションサーバー** に渡す前に特別な「転送」ヘッダー（`X-Forwarded-*`）を追加します。\n\nこれらのヘッダーは、通常は失われる元のリクエストの情報を保持します:\n\n* **X-Forwarded-For**: 元のクライアントの IP アドレス\n* **X-Forwarded-Proto**: 元のプロトコル（`https`）\n* **X-Forwarded-Host**: 元のホスト（`mysuperapp.com`）\n\n**FastAPI CLI** を `--forwarded-allow-ips` で設定すると、これらのヘッダーを信頼して使用し、たとえばリダイレクトで正しい URL を生成します。\n\n## パスプレフィックスを削除するプロキシ { #proxy-with-a-stripped-path-prefix }\n\nアプリケーションにパスプレフィックスを付与するプロキシを使う場合があります。\n\nそのような場合は `root_path` でアプリケーションを設定できます。\n\n`root_path` は（FastAPI が Starlette を通して基づいている）ASGI 仕様で提供されている仕組みです。\n\n`root_path` はこの種のケースを扱うために使われます。\n\nこれはサブアプリケーションをマウントする際にも内部的に使用されます。\n\nここでいう「パスプレフィックスを削除するプロキシ」とは、コード上では `/app` というパスを宣言していても、その上にプロキシ層を追加して **FastAPI** アプリケーションを `/api/v1` のようなパスの下に配置することを指します。\n\nこの場合、元のパス `/app` は実際には `/api/v1/app` で提供されます。\n\nすべてのコードは `/app` だけを前提に書かれているにもかかわらず、です。\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\nそしてプロキシは、アプリサーバー（おそらく FastAPI CLI 経由の Uvicorn）に転送する前に、その場で **パスプレフィックス** を**「削除」**し、アプリケーション側には自分が `/app` で提供されているように見せかけます。これにより、コードのすべてを `/api/v1` のプレフィックス付きに書き換える必要がありません。\n\nここまでは通常どおりに動作します。\n\nしかし、統合ドキュメント UI（フロントエンド）を開くと、OpenAPI スキーマを `/api/v1/openapi.json` ではなく `/openapi.json` から取得しようとします。\n\nそのため、フロントエンド（ブラウザで動作）は `/openapi.json` にアクセスしようとして、OpenAPI スキーマを取得できません。\n\nこのアプリには `/api/v1` のパスプレフィックスを付与するプロキシがあるため、フロントエンドは `/api/v1/openapi.json` から取得する必要があります。\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy on http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server on http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip | 豆知識\n\nIP `0.0.0.0` は、そのマシン/サーバーで利用可能なすべての IP で待ち受けることを意味する表現として一般的に使われます。\n\n///\n\nドキュメント UI では、この API の `server` が（プロキシの背後で）`/api/v1` にあることを宣言する OpenAPI スキーマも必要です。例えば:\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // ほかの項目\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // ほかの項目\n    }\n}\n```\n\nこの例では「Proxy」は **Traefik** のようなもの、サーバーは **Uvicorn** と FastAPI CLI で FastAPI アプリケーションを実行しているものを想定しています。\n\n### `root_path` の指定 { #providing-the-root-path }\n\nこれを実現するには、次のようにコマンドラインオプション `--root-path` を使用します:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nHypercorn を使う場合も、同様に `--root-path` オプションがあります。\n\n/// note | 技術詳細\n\nこのユースケース向けに、ASGI 仕様は `root_path` を定義しています。\n\nそして `--root-path` コマンドラインオプションは、その `root_path` を提供します。\n\n///\n\n### 現在の `root_path` の確認 { #checking-the-current-root-path }\n\n各リクエストでアプリケーションが使用している現在の `root_path` は取得できます。これは（ASGI 仕様の一部である）`scope` 辞書に含まれます。\n\nここではデモのため、メッセージに含めています。\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\nそのうえで、次のように Uvicorn を起動すると:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nレスポンスは次のようになります:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### FastAPI アプリでの `root_path` 設定 { #setting-the-root-path-in-the-fastapi-app }\n\nあるいは、`--root-path` のようなコマンドラインオプションを渡せない場合は、FastAPI アプリ作成時にパラメータ `root_path` を設定できます:\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\n`FastAPI` に `root_path` を渡すのは、Uvicorn や Hypercorn にコマンドラインオプション `--root-path` を渡すのと同等です。\n\n### `root_path` について { #about-root-path }\n\nサーバー（Uvicorn）は、その `root_path` をアプリに渡す以外の用途では使用しない点に注意してください。\n\nしかし、ブラウザで [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app) にアクセスすると、通常どおりのレスポンスが表示されます:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nつまり、`http://127.0.0.1:8000/api/v1/app` でアクセスされることは想定していません。\n\nUvicorn は、プロキシが `http://127.0.0.1:8000/app` にアクセスしてくることを想定しており、その上に追加の `/api/v1` プレフィックスを付けるのはプロキシの責務です。\n\n## パスプレフィックスを削除するプロキシについて { #about-proxies-with-a-stripped-path-prefix }\n\nパスプレフィックスを削除するプロキシは、設定方法の一例にすぎない点に注意してください。\n\n多くの場合、プロキシはパスプレフィックスを削除しない設定が既定でしょう。\n\nそのような場合（パスプレフィックスを削除しない場合）は、プロキシは `https://myawesomeapp.com` のようなアドレスで待ち受け、ブラウザが `https://myawesomeapp.com/api/v1/app` にアクセスし、サーバー（例: Uvicorn）が `http://127.0.0.1:8000` で待ち受けているなら、プロキシ（プレフィックスを削除しない）は同じパス `http://127.0.0.1:8000/api/v1/app` で Uvicorn にアクセスします。\n\n## Traefik を使ったローカル検証 { #testing-locally-with-traefik }\n\n[Traefik](https://docs.traefik.io/) を使えば、パスプレフィックスを削除する構成をローカルで簡単に試せます。\n\n[Traefik をダウンロード](https://github.com/containous/traefik/releases) してください。単一バイナリなので、圧縮ファイルを展開して端末から直接実行できます。\n\n次の内容で `traefik.toml` というファイルを作成します:\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\nこれは Traefik にポート 9999 で待ち受け、別のファイル `routes.toml` を使用するよう指示します。\n\n/// tip | 豆知識\n\n標準の HTTP ポート 80 ではなく 9999 を使うのは、管理者（`sudo`）権限で実行する必要をなくすためです。\n\n///\n\n次に、その `routes.toml` ファイルを作成します:\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\nこのファイルは Traefik に `/api/v1` のパスプレフィックスを使うよう設定します。\n\nそして Traefik は、`http://127.0.0.1:8000` で動作している Uvicorn へリクエストを転送します。\n\nでは Traefik を起動します:\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\n次に、`--root-path` オプションを指定してアプリを起動します:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### レスポンスの確認 { #check-the-responses }\n\nここで、Uvicorn のポートの URL [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app) にアクセスすると、通常どおりのレスポンスが表示されます:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip | 豆知識\n\n`http://127.0.0.1:8000/app` にアクセスしているにもかかわらず、オプション `--root-path` から取得した `root_path` が `/api/v1` と表示されている点に注目してください。\n\n///\n\n次に、Traefik のポートでプレフィックス付きの URL [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app) を開きます。\n\n同じレスポンスが得られます:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nただし今回は、プロキシが付与したプレフィックス `/api/v1` の付いた URL です。\n\nもちろん、ここでの想定は全員がプロキシ経由でアプリにアクセスすることです。したがって、パスプレフィックス `/api/v1` のある版が「正しい」アクセス方法になります。\n\n一方、プレフィックスのない版（`http://127.0.0.1:8000/app`。Uvicorn が直接提供）は、_プロキシ_（Traefik）専用の接続先になります。\n\nこれにより、プロキシ（Traefik）がパスプレフィックスをどのように用い、サーバー（Uvicorn）が `--root-path` の `root_path` をどのように利用するかが分かります。\n\n### ドキュメント UI の確認 { #check-the-docs-ui }\n\nここがポイントです。✨\n\n「公式な」アクセス方法は、定義したパスプレフィックス付きのプロキシ経由です。したがって想定どおり、プレフィックスなしの URL で Uvicorn が直接提供するドキュメント UI にアクセスすると動作しません。プロキシ経由でアクセスされることを前提としているためです。\n\n[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) を確認してください:\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\nしかし、プロキシ（ポート `9999`）を使った「公式」URL `/api/v1/docs` でドキュメント UI にアクセスすると、正しく動作します！🎉\n\n[http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) を確認してください:\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\nねらいどおりです。✔️\n\nこれは、FastAPI が `root_path` を使って、OpenAPI の既定の `server` を `root_path` の URL で生成するためです。\n\n## 追加のサーバー { #additional-servers }\n\n/// warning | 注意\n\nこれは高度なユースケースです。読み飛ばしても構いません。\n\n///\n\n既定では、**FastAPI** は OpenAPI スキーマ内に `root_path` の URL を持つ `server` を作成します。\n\nしかし、ステージングと本番の両方と同じドキュメント UI で対話させたい場合など、別の `servers` を指定することもできます。\n\nカスタムの `servers` リストを渡していて、かつ `root_path`（API がプロキシの背後にあるため）が設定されている場合、**FastAPI** はこの `root_path` を用いた「server」をリストの先頭に挿入します。\n\n例えば:\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\n次のような OpenAPI スキーマが生成されます:\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // ほかの項目\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // ほかの項目\n    }\n}\n```\n\n/// tip | 豆知識\n\n`root_path` から取得した `url` 値 `/api/v1` を持つ server が自動生成されている点に注目してください。\n\n///\n\nドキュメント UI（[http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs)）では次のように表示されます:\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip | 豆知識\n\nドキュメント UI は、選択した server と対話します。\n\n///\n\n/// note | 技術詳細\n\nOpenAPI 仕様の `servers` プロパティは任意です。\n\n`servers` パラメータを指定せず、かつ `root_path` が `/` の場合、生成される OpenAPI スキーマからは `servers` プロパティが既定で完全に省略されます。これは、`url` が `/` の server が 1 つあるのと同等です。\n\n///\n\n### `root_path` 由来の自動 server を無効化 { #disable-automatic-server-from-root-path }\n\n`root_path` を用いた自動的な server を **FastAPI** に含めてほしくない場合は、パラメータ `root_path_in_servers=False` を使用します:\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\nすると、OpenAPI スキーマには含まれません。\n\n## サブアプリケーションのマウント { #mounting-a-sub-application }\n\n`root_path` を伴うプロキシを使用しつつサブアプリケーションをマウントする必要がある場合でも（[サブアプリケーション - マウント](sub-applications.md) 参照）、通常どおりに行えます。\n\nFastAPI は内部で `root_path` を適切に扱うため、そのまま動作します。✨\n"
  },
  {
    "path": "docs/ja/docs/advanced/custom-response.md",
    "content": "# カスタムレスポンス - HTML、ストリーム、ファイル、その他 { #custom-response-html-stream-file-others }\n\nデフォルトでは、**FastAPI** はJSONレスポンスを返します。\n\n[レスポンスを直接返す](response-directly.md)で見たように、`Response` を直接返してこの挙動を上書きできます。\n\nしかし、`Response`（または `JSONResponse` のような任意のサブクラス）を直接返す場合、（`response_model` を宣言していても）データは自動的に変換されず、ドキュメントも自動生成されません（例えば、生成されるOpenAPIの一部としてHTTPヘッダー `Content-Type` に特定の「メディアタイプ」を含めるなど）。\n\n一方で、*path operation デコレータ* の `response_class` パラメータを使って、使用したい `Response`（`Response` の任意のサブクラス）を宣言することもできます。\n\n*path operation 関数* から返したコンテンツは、その `Response` に格納されます。\n\n/// note | 備考\n\nメディアタイプを持たないレスポンスクラスを使用すると、FastAPIはレスポンスにコンテンツがないものと見なします。そのため、生成されるOpenAPIドキュメントにレスポンスフォーマットは記載されません。\n\n///\n\n## JSONレスポンス { #json-responses }\n\nFastAPI はデフォルトでJSONレスポンスを返します。\n\n[レスポンスモデル](../tutorial/response-model.md) を宣言すると、FastAPI は Pydantic を使ってデータをJSONにシリアライズします。\n\nレスポンスモデルを宣言しない場合、FastAPI は [JSON Compatible Encoder](../tutorial/encoder.md) で説明した `jsonable_encoder` を使い、その結果を `JSONResponse` に入れます。\n\n`JSONResponse` のようにJSONメディアタイプ（`application/json`）を持つ `response_class` を宣言した場合、*path operation デコレータ* に宣言した任意のPydanticの `response_model` に従って、返すデータは自動的に変換（およびフィルタ）されます。ただし、そのデータは Pydantic でJSONのバイト列にシリアライズされるわけではなく、まず `jsonable_encoder` で変換された後に `JSONResponse` クラスへ渡され、Pythonの標準JSONライブラリでバイト列にシリアライズされます。\n\n### JSONのパフォーマンス { #json-performance }\n\n結論として、最大のパフォーマンスを得たい場合は、[レスポンスモデル](../tutorial/response-model.md) を使い、*path operation デコレータ* で `response_class` は宣言しないでください。\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## HTMLレスポンス { #html-response }\n\n**FastAPI** からHTMLを直接返すには、`HTMLResponse` を使います。\n\n* `HTMLResponse` をインポートする\n* *path operation デコレータ* のパラメータ `response_class` に `HTMLResponse` を渡す\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info | 情報\n\nパラメータ `response_class` は、レスポンスの「メディアタイプ」を定義するためにも使用されます。\n\nこの場合、HTTPヘッダー `Content-Type` には `text/html` が設定されます。\n\nそして、OpenAPIにもそのようにドキュメント化されます。\n\n///\n\n### `Response` を返す { #return-a-response }\n\n[レスポンスを直接返す](response-directly.md)で見たように、*path operation* の中でレスポンスを直接返して上書きすることもできます。\n\n上記と同じ例で、`HTMLResponse` を返すと次のようになります:\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning | 注意\n\n*path operation 関数* から直接返される `Response` は、OpenAPIにドキュメント化されず（例えば `Content-Type` がドキュメント化されない）、自動生成の対話的ドキュメントにも表示されません。\n\n///\n\n/// info | 情報\n\nもちろん、実際の `Content-Type` ヘッダーやステータスコードなどは、返した `Response` オブジェクトに由来します。\n\n///\n\n### OpenAPIにドキュメント化しつつ `Response` を上書き { #document-in-openapi-and-override-response }\n\n関数の中からレスポンスを上書きしつつ、同時にOpenAPIで「メディアタイプ」をドキュメント化したい場合は、`response_class` パラメータを使用し、かつ `Response` オブジェクトを返します。\n\nこの場合、`response_class` はOpenAPIの *path operation* をドキュメント化するためだけに使われ、実際には返した `Response` がそのまま使用されます。\n\n#### `HTMLResponse` を直接返す { #return-an-htmlresponse-directly }\n\n例えば、次のようになります:\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\nこの例では、関数 `generate_html_response()` はHTMLの `str` を返すのではなく、すでに `Response` を生成して返しています。\n\n`generate_html_response()` の呼び出し結果を返すことで、デフォルトの **FastAPI** の挙動を上書きする `Response` をすでに返しています。\n\nしかし、`response_class` にも `HTMLResponse` を渡しているため、**FastAPI** はOpenAPIおよび対話的ドキュメントで、それが `text/html` のHTMLであると正しくドキュメント化できます:\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## 利用可能なレスポンス { #available-responses }\n\n以下は利用可能なレスポンスの一部です。\n\n`Response` を使って他のものを返したり、カスタムサブクラスを作成することもできます。\n\n/// note | 技術詳細\n\n`from starlette.responses import HTMLResponse` を使うこともできます。\n\n**FastAPI** は開発者の利便性のために、`starlette.responses` と同じものを `fastapi.responses` として提供しています。ただし、利用可能なレスポンスの多くはStarletteから直接提供されています。\n\n///\n\n### `Response` { #response }\n\nメインの `Response` クラスで、他のすべてのレスポンスはこれを継承しています。\n\n直接返すことができます。\n\n以下のパラメータを受け付けます。\n\n* `content` - `str` または `bytes`\n* `status_code` - `int` のHTTPステータスコード\n* `headers` - 文字列の `dict`\n* `media_type` - メディアタイプを示す `str`。例: `\"text/html\"`\n\nFastAPI（実際にはStarlette）は自動的に Content-Length ヘッダーを含めます。また、`media_type` に基づいた Content-Type ヘッダーを含め、テキストタイプには charset を追加します。\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\n上で読んだように、テキストやバイト列を受け取り、HTMLレスポンスを返します。\n\n### `PlainTextResponse` { #plaintextresponse }\n\nテキストやバイト列を受け取り、プレーンテキストのレスポンスを返します。\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\nデータを受け取り、`application/json` としてエンコードされたレスポンスを返します。\n\nこれは、上で述べたように **FastAPI** のデフォルトのレスポンスです。\n\n/// note | 技術詳細\n\nただし、レスポンスモデルや返却型を宣言した場合は、それが直接データのJSONシリアライズに使われ、適切なJSONのメディアタイプを持つレスポンスが `JSONResponse` クラスを使わずに直接返されます。\n\nこれが最適なパフォーマンスを得る理想的な方法です。\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\nHTTPリダイレクトを返します。デフォルトでは307ステータスコード（Temporary Redirect）を使用します。\n\n`RedirectResponse` を直接返せます:\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\nまたは、`response_class` パラメータで使用できます:\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\nその場合、*path operation* 関数からURLを直接返せます。\n\nこの場合に使用される `status_code` は、`RedirectResponse` のデフォルトである `307` になります。\n\n---\n\nさらに、`status_code` パラメータを `response_class` パラメータと組み合わせて使うこともできます:\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\n非同期ジェネレータ、または通常のジェネレータ/イテレータ（`yield` を持つ関数）を受け取り、レスポンスボディをストリームします。\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | 技術詳細\n\n`async` タスクは `await` に到達したときにのみキャンセルできます。`await` がない場合、ジェネレータ（`yield` を持つ関数）は適切にキャンセルできず、キャンセル要求後も実行が続く可能性があります。\n\nこの小さな例では `await` が不要なため、イベントループにキャンセルを処理する機会を与えるために `await anyio.sleep(0)` を追加しています。\n\nこれは大きなストリームや無限ストリームではさらに重要になります。\n\n///\n\n/// tip | 豆知識\n\n`StreamingResponse` を直接返す代わりに、[データをストリームする](./stream-data.md) スタイルに従うことをおすすめします。こちらのほうがはるかに便利で、裏側でキャンセル処理も行ってくれます。\n\nJSON Lines をストリームする場合は、[JSON Lines をストリームする](../tutorial/stream-json-lines.md) チュートリアルを参照してください。\n\n///\n\n### `FileResponse` { #fileresponse }\n\nファイルをレスポンスとして非同期にストリームします。\n\n他のレスポンスタイプとは異なる引数セットでインスタンス化します:\n\n* `path` - ストリームするファイルのファイルパス\n* `headers` - 含めたい任意のカスタムヘッダー（辞書）\n* `media_type` - メディアタイプを示す文字列。未設定の場合、ファイル名やパスから推測されます\n* `filename` - 設定した場合、レスポンスの `Content-Disposition` に含まれます\n\nファイルレスポンスには、適切な `Content-Length`、`Last-Modified`、`ETag` ヘッダーが含まれます。\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\n`response_class` パラメータを使うこともできます:\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\nこの場合、*path operation* 関数からファイルパスを直接返せます。\n\n## カスタムレスポンスクラス { #custom-response-class }\n\n`Response` を継承して、独自のカスタムレスポンスクラスを作成し、使用できます。\n\n例えば、[`orjson`](https://github.com/ijl/orjson) を特定の設定で使いたいとします。\n\nインデントされた整形済みJSONを返したいので、orjson のオプション `orjson.OPT_INDENT_2` を使いたいとします。\n\n`CustomORJSONResponse` を作成できます。主に必要なのは、`bytes` を返す `Response.render(content)` メソッドを作ることです:\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\nこれまでは次のように返していたものが:\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n...このレスポンスでは次のように返されます:\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\nもちろん、JSONの整形以外にも、これを活用するもっと良い方法が見つかるはずです。 😉\n\n### `orjson` か レスポンスモデルか { #orjson-or-response-model }\n\nもし求めているのがパフォーマンスであれば、`orjson` レスポンスを使うより、[レスポンスモデル](../tutorial/response-model.md) を使うほうが良い場合が多いです。\n\nレスポンスモデルがあると、FastAPI は中間ステップ（他の場合に行われる `jsonable_encoder` による変換など）を介さずに、Pydantic を使ってデータをJSONにシリアライズします。\n\n内部的には、Pydantic はJSONシリアライズに `orjson` と同じRust由来の仕組みを用いているため、レスポンスモデルを使うだけで最良のパフォーマンスが得られます。\n\n## デフォルトレスポンスクラス { #default-response-class }\n\n**FastAPI** クラスのインスタンスや `APIRouter` を作成する際に、デフォルトで使用するレスポンスクラスを指定できます。\n\nこれを定義するパラメータは `default_response_class` です。\n\n以下の例では、**FastAPI** はすべての *path operation* で、JSONの代わりにデフォルトで `HTMLResponse` を使用します。\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip | 豆知識\n\nこれまでと同様に、*path operation* ごとに `response_class` をオーバーライドできます。\n\n///\n\n## その他のドキュメント { #additional-documentation }\n\nOpenAPIでは `responses` を使ってメディアタイプやその他の詳細を宣言することもできます: [OpenAPI の追加レスポンス](additional-responses.md)。\n"
  },
  {
    "path": "docs/ja/docs/advanced/dataclasses.md",
    "content": "# Dataclasses の使用 { #using-dataclasses }\n\nFastAPI は **Pydantic** の上に構築されており、これまでにリクエストやレスポンスを宣言するために Pydantic モデルを使う方法を紹介してきました。\n\nしかし FastAPI は、同様の方法で [`dataclasses`](https://docs.python.org/3/library/dataclasses.html) もサポートします:\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\nこれは **Pydantic** によって引き続きサポートされています。Pydantic には [`dataclasses` の内部サポート](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel) があるためです。\n\nそのため、上記のように明示的に Pydantic を使っていないコードでも、FastAPI は標準の dataclass を Pydantic 独自の dataclass に変換するために Pydantic を使用しています。\n\nそして当然ながら、次の点も同様にサポートされます:\n\n- データ検証\n- データのシリアライズ\n- データのドキュメント化 など\n\nこれは Pydantic モデルの場合と同じように動作します。内部的にも同様に Pydantic を使って実現されています。\n\n/// info | 情報\n\ndataclasses は、Pydantic モデルができることをすべては行えない点に留意してください。\n\nそのため、Pydantic モデルを使う必要がある場合もあります。\n\nしかし既存の dataclass が多数あるなら、FastAPI で Web API を構築する際にそれらを活用するちょっとしたテクニックになります。🤓\n\n///\n\n## `response_model` での dataclasses { #dataclasses-in-response-model }\n\n`response_model` パラメータでも `dataclasses` を使用できます:\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\ndataclass は自動的に Pydantic の dataclass に変換されます。\n\nこのため、そのスキーマは API ドキュメントの UI に表示されます:\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## ネストしたデータ構造での dataclasses { #dataclasses-in-nested-data-structures }\n\n`dataclasses` を他の型注釈と組み合わせて、ネストしたデータ構造を作成できます。\n\n場合によっては、自動生成された API ドキュメントでエラーが発生するなどの理由で、Pydantic 版の `dataclasses` を使う必要があるかもしれません。\n\nその場合は、標準の `dataclasses` を `pydantic.dataclasses` に置き換えるだけで済みます。これはドロップイン置換です:\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. 依然として標準の `dataclasses` から `field` をインポートします。\n\n2. `pydantic.dataclasses` は `dataclasses` のドロップイン置換です。\n\n3. `Author` dataclass は `Item` dataclass のリストを含みます。\n\n4. `Author` dataclass を `response_model` パラメータとして使用しています。\n\n5. リクエストボディとしての dataclass と併せて、他の標準の型注釈を使用できます。\n\n    この例では、`Item` dataclass のリストです。\n\n6. ここでは、dataclass のリストである `items` を含む辞書を返しています。\n\n    FastAPI はデータを JSON に <dfn title=\"送信可能な形式にデータを変換すること\">シリアライズ</dfn> できます。\n\n7. ここでは `response_model` に `Author` dataclass のリストという型注釈を使用しています。\n\n    このように、`dataclasses` は標準の型注釈と組み合わせられます。\n\n8. この *path operation 関数* は、`async def` ではなく通常の `def` を使用しています。\n\n    いつもどおり、FastAPI では必要に応じて `def` と `async def` を組み合わせられます。\n\n    どちらをいつ使うかの復習が必要な場合は、[`async` と `await`](../async.md#in-a-hurry) に関するドキュメントの _\"In a hurry?\"_ セクションを参照してください。\n\n9. この *path operation 関数* は（可能ではありますが）dataclass 自体は返さず、内部データを持つ辞書のリストを返しています。\n\n    FastAPI は dataclass を含む `response_model` パラメータを使ってレスポンスを変換します。\n\n`dataclasses` は他の型注釈と多様な組み合わせが可能で、複雑なデータ構造を構成できます。\n\n上記のコード内コメントのヒントを参照して、より具体的な詳細を確認してください。\n\n## さらに学ぶ { #learn-more }\n\n`dataclasses` を他の Pydantic モデルと組み合わせたり、継承したり、自分のモデルに含めたりもできます。\n\n詳しくは、[dataclasses に関する Pydantic ドキュメント](https://docs.pydantic.dev/latest/concepts/dataclasses/) を参照してください。\n\n## バージョン { #version }\n\nこれは FastAPI バージョン `0.67.0` 以降で利用可能です。🔖\n"
  },
  {
    "path": "docs/ja/docs/advanced/events.md",
    "content": "# Lifespan イベント { #lifespan-events }\n\nアプリケーションが起動する前に一度だけ実行すべきロジック（コード）を定義できます。これは、アプリケーションがリクエストを受け取り始める前に、そのコードが一度だけ実行される、という意味です。\n\n同様に、アプリケーションがシャットダウンするときに実行すべきロジック（コード）も定義できます。この場合、そのコードは、（多くのリクエストを処理した）後に一度だけ実行されます。\n\nこのコードは、アプリケーションがリクエストの受け付けを「開始」する前、そして処理を「終了」した直後に実行されるため、アプリケーションの全体の「Lifespan」（この「lifespan」という言葉はすぐ後で重要になります 😉）をカバーします。\n\nこれは、アプリ全体で使用し、リクエスト間で「共有」し、かつ後で「クリーンアップ」する必要があるような「リソース」をセットアップするのにとても便利です。たとえば、データベース接続プールや、共有の機械学習モデルの読み込みなどです。\n\n## ユースケース { #use-case }\n\nまずはユースケースの例から始めて、これをどのように解決するかを見ていきます。\n\nリクエストを処理するために使用したい「機械学習モデル」がいくつかあると想像してください。🤖\n\n同じモデルをリクエスト間で共有するので、リクエストごとやユーザーごとに別々のモデルを使うわけではありません。\n\nモデルの読み込みにはディスクから大量のデータを読む必要があり、かなり時間がかかるかもしれません。したがって、リクエストごとに読み込みたくはありません。\n\nモジュール/ファイルのトップレベルで読み込むこともできますが、その場合は、たとえ簡単な自動テストを実行するだけでも「モデルを読み込む」ことになり、そのモデルの読み込みを待つ必要があるため、独立したコード部分を走らせるだけのテストでも「遅く」なってしまいます。\n\nこれを解決しましょう。リクエストを処理する前にモデルを読み込みますが、コードがロードされている最中ではなく、アプリケーションがリクエストの受け付けを開始する直前だけにします。\n\n## Lifespan { #lifespan }\n\nこの「起動時」と「シャットダウン時」のロジックは、`FastAPI` アプリの `lifespan` パラメータと「コンテキストマネージャ」（これが何かはすぐに示します）を使って定義できます。\n\nまずは例を見てから、詳細を説明します。\n\n次のように、`yield` を使う非同期関数 `lifespan()` を作成します:\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\nここでは、`yield` の前で機械学習モデルの辞書に（ダミーの）モデル関数を入れることで、高コストな「起動時」のモデル読み込みをシミュレーションしています。このコードは、アプリケーションがリクエストを「受け付け始める前」に、すなわち起動時に実行されます。\n\nそして `yield` の直後でモデルをアンロードします。このコードは、アプリケーションがリクエスト処理を「終了」した後、シャットダウン直前に実行されます。たとえばメモリや GPU のようなリソースを解放できます。\n\n/// tip | 豆知識\n\n`shutdown` は、アプリケーションを「停止」するときに発生します。\n\n新しいバージョンを開始する必要があるか、単に実行をやめたくなったのかもしれません。🤷\n\n///\n\n### Lifespan 関数 { #lifespan-function }\n\nまず注目すべきは、`yield` を使う非同期関数を定義していることです。これは「yield を使う依存関係（Dependencies）」にとてもよく似ています。\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\n`yield` の前の前半は、アプリケーションが開始される「前」に実行されます。\n\n`yield` の後半は、アプリケーションの処理が「終了」した「後」に実行されます。\n\n### 非同期コンテキストマネージャ { #async-context-manager }\n\nこの関数には `@asynccontextmanager` がデコレートされています。\n\nこれにより、この関数は「非同期コンテキストマネージャ」になります。\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\nPython の「コンテキストマネージャ」は、`with` 文で使えるものです。たとえば、`open()` はコンテキストマネージャとして使えます:\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\n最近の Python には「非同期コンテキストマネージャ」もあります。`async with` で使います:\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\nこのようにコンテキストマネージャ（または非同期コンテキストマネージャ）を作ると、`with` ブロックに入る前に `yield` より前のコードが実行され、`with` ブロックを出た後に `yield` より後ろのコードが実行されます。\n\n上のコード例では直接それを使ってはいませんが、FastAPI に渡して内部で使ってもらいます。\n\n`FastAPI` アプリの `lifespan` パラメータは「非同期コンテキストマネージャ」を受け取るので、新しく作った `lifespan` 非同期コンテキストマネージャを渡せます。\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## 代替のイベント（非推奨） { #alternative-events-deprecated }\n\n/// warning | 注意\n\n推奨される方法は、上で説明したとおり `FastAPI` アプリの `lifespan` パラメータを使って「起動」と「シャットダウン」を扱うことです。`lifespan` パラメータを指定すると、`startup` と `shutdown` のイベントハンドラは呼び出されなくなります。`lifespan` かイベントか、どちらか一方であり、両方同時ではありません。\n\nこの節は読み飛ばしてもかまいません。\n\n///\n\n起動時とシャットダウン時に実行されるロジックを定義する別の方法もあります。\n\nアプリケーションが起動する前、またはシャットダウンするときに実行する必要があるイベントハンドラ（関数）を定義できます。\n\nこれらの関数は `async def` でも、通常の `def` でも構いません。\n\n### `startup` イベント { #startup-event }\n\nアプリケーションが開始される前に実行すべき関数を追加するには、イベント `\"startup\"` で宣言します:\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\nこの場合、`startup` のイベントハンドラ関数は items の「データベース」（単なる `dict`）をいくつかの値で初期化します。\n\nイベントハンドラ関数は複数追加できます。\n\nすべての `startup` イベントハンドラが完了するまで、アプリケーションはリクエストの受け付けを開始しません。\n\n### `shutdown` イベント { #shutdown-event }\n\nアプリケーションがシャットダウンするときに実行すべき関数を追加するには、イベント `\"shutdown\"` で宣言します:\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\nここでは、`shutdown` のイベントハンドラ関数が、テキスト行 `\"Application shutdown\"` をファイル `log.txt` に書き込みます。\n\n/// info | 情報\n\n`open()` 関数の `mode=\"a\"` は「追加」（append）を意味します。つまり、そのファイルに既にある内容を上書きせず、行が後ろに追記されます。\n\n///\n\n/// tip | 豆知識\n\nこの例では、ファイルを扱う標準の Python 関数 `open()` を使っています。\n\nそのため、ディスクへの書き込みを「待つ」必要がある I/O（入力/出力）が関わります。\n\nしかし `open()` 自体は `async` や `await` を使いません。\n\nしたがって、イベントハンドラ関数は `async def` ではなく通常の `def` で宣言しています。\n\n///\n\n### `startup` と `shutdown` をまとめて { #startup-and-shutdown-together }\n\n起動時とシャットダウン時のロジックは関連していることが多いです。何かを開始してから終了したい、リソースを獲得してから解放したい、などです.\n\n共有するロジックや変数のない別々の関数でそれを行うのは難しく、グローバル変数などに値を保存する必要が出てきます。\n\nそのため、現在は上で説明したとおり `lifespan` を使うことが推奨されています。\n\n## 技術詳細 { #technical-details }\n\n技術が気になる方への細かな詳細です。🤓\n\n内部的には、ASGI の技術仕様において、これは [Lifespan プロトコル](https://asgi.readthedocs.io/en/latest/specs/lifespan.html) の一部であり、`startup` と `shutdown` というイベントが定義されています。\n\n/// info | 情報\n\nStarlette の `lifespan` ハンドラについては、[Starlette の Lifespan ドキュメント](https://www.starlette.dev/lifespan/)で詳しく読むことができます。\n\nコードの他の領域で使える lifespan の状態をどのように扱うかも含まれています。\n\n///\n\n## サブアプリケーション { #sub-applications }\n\n🚨 これらの lifespan イベント（startup と shutdown）はメインのアプリケーションに対してのみ実行され、[サブアプリケーション - マウント](sub-applications.md) には実行されないことに注意してください。\n"
  },
  {
    "path": "docs/ja/docs/advanced/generate-clients.md",
    "content": "# SDK の生成 { #generating-sdks }\n\n**FastAPI** は **OpenAPI** 仕様に基づいているため、その API は多くのツールが理解できる標準形式で記述できます。\n\nこれにより、最新の**ドキュメント**、複数言語のクライアントライブラリ（<abbr title=\"Software Development Kits - ソフトウェア開発キット\">**SDKs**</abbr>）、そしてコードと同期し続ける**テスト**や**自動化ワークフロー**を容易に生成できます。\n\n本ガイドでは、FastAPI バックエンド向けの **TypeScript SDK** を生成する方法を説明します。\n\n## オープンソースの SDK ジェネレータ { #open-source-sdk-generators }\n\n多用途な選択肢として [OpenAPI Generator](https://openapi-generator.tech/) があります。これは**多数のプログラミング言語**をサポートし、OpenAPI 仕様から SDK を生成できます。\n\n**TypeScript クライアント**向けには、[Hey API](https://heyapi.dev/) が目的特化のソリューションで、TypeScript エコシステムに最適化された体験を提供します。\n\n他の SDK ジェネレータは [OpenAPI.Tools](https://openapi.tools/#sdk) でも見つけられます。\n\n/// tip | 豆知識\n\nFastAPI は自動的に **OpenAPI 3.1** の仕様を生成します。したがって、使用するツールはこのバージョンをサポートしている必要があります。\n\n///\n\n## FastAPI スポンサーによる SDK ジェネレータ { #sdk-generators-from-fastapi-sponsors }\n\nこのセクションでは、FastAPI をスポンサーしている企業による、**ベンチャー支援**および**企業支援**のソリューションを紹介します。これらの製品は、高品質な生成 SDK に加えて、**追加機能**や**統合**を提供します。\n\n✨ [**FastAPI をスポンサーする**](../help-fastapi.md#sponsor-the-author) ✨ ことで、これらの企業はフレームワークとその**エコシステム**の健全性と**持続可能性**を支援しています。\n\nこの支援は、FastAPI の**コミュニティ**（皆さん）への強いコミットメントの表明でもあり、**優れたサービス**の提供だけでなく、堅牢で発展するフレームワーク FastAPI を支える姿勢を示しています。🙇\n\n例えば、次のようなものがあります:\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\nこれらのソリューションの中にはオープンソースや無料枠を提供するものもあり、金銭的コミットメントなしで試すことができます。他の商用 SDK ジェネレータも存在し、オンラインで見つけられます。🤓\n\n## TypeScript SDK を作成する { #create-a-typescript-sdk }\n\nまずは簡単な FastAPI アプリから始めます:\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\nここで、*path operation* はリクエストとレスポンスのペイロードに使用するモデルを定義しており、`Item` と `ResponseMessage` を使っています。\n\n### API ドキュメント { #api-docs }\n\n`/docs` に移動すると、リクエストで送信・レスポンスで受信するデータの**スキーマ**が表示されます:\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\nこれらのスキーマは、アプリ内でモデルとして宣言されているため表示されます。\n\nその情報はアプリの **OpenAPI スキーマ**に含まれ、API ドキュメントに表示されます。\n\nOpenAPI に含まれるこれらのモデル情報を使って、**クライアントコードを生成**できます。\n\n### Hey API { #hey-api }\n\nモデルを備えた FastAPI アプリがあれば、Hey API で TypeScript クライアントを生成できます。最も手早い方法は npx を使うことです。\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\nこれで TypeScript SDK が `./src/client` に生成されます。\n\n[`@hey-api/openapi-ts` のインストール方法](https://heyapi.dev/openapi-ts/get-started)や、[生成物の詳細](https://heyapi.dev/openapi-ts/output)は公式サイトを参照してください。\n\n### SDK の利用 { #using-the-sdk }\n\nこれでクライアントコードを import して利用できます。例えば次のようになり、メソッドに対して補完が効きます:\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\n送信するペイロードにも補完が適用されます:\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip | 豆知識\n\nFastAPI アプリの `Item` モデルで定義した `name` と `price` に補完が効いている点に注目してください。\n\n///\n\n送信データに対するインラインエラーも表示されます:\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\nレスポンスオブジェクトにも補完があります:\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## タグ付きの FastAPI アプリ { #fastapi-app-with-tags }\n\n実運用ではアプリは大きくなり、*path operation* のグループ分けにタグを使うことが多いでしょう。\n\n例えば **items** 用と **users** 用のセクションがあり、タグで分けられます:\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### タグ付き TypeScript クライアントの生成 { #generate-a-typescript-client-with-tags }\n\nタグを用いた FastAPI アプリからクライアントを生成すると、通常クライアント側のコードもタグごとに分割されます。\n\nこれにより、クライアントコードも正しく整理・グルーピングされます:\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\nこの例では次のようになります:\n\n* `ItemsService`\n* `UsersService`\n\n### クライアントのメソッド名 { #client-method-names }\n\n現状では、生成されるメソッド名（`createItemItemsPost` など）はあまりきれいではありません:\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\nこれは、クライアントジェネレータが各 *path operation* の OpenAPI 内部の **operation ID** を用いるためです。\n\nOpenAPI では operation ID は全ての *path operation* を通して一意である必要があります。そのため FastAPI は**関数名**、**パス**、**HTTP メソッド/オペレーション**を組み合わせて operation ID を生成し、一意性を保証します。\n\n次にこれを改善する方法を示します。🤓\n\n## カスタム operation ID とより良いメソッド名 { #custom-operation-ids-and-better-method-names }\n\noperation ID の**生成方法**を**変更**して簡潔にし、クライアント側の**メソッド名をシンプル**にできます。\n\nこの場合でも各 operation ID が**一意**であることは別の方法で保証する必要があります。\n\n例えば、各 *path operation* にタグを付け、**タグ**と *path operation* の**名前**（関数名）から operation ID を生成できます。\n\n### 一意 ID 生成関数のカスタマイズ { #custom-generate-unique-id-function }\n\nFastAPI は各 *path operation* に**一意 ID**を用いており、これは **operation ID** のほか、必要に応じてリクエストやレスポンスのカスタムモデル名にも使われます。\n\nこの関数はカスタマイズ可能です。`APIRoute` を受け取り、文字列を返します。\n\n例えばここでは、最初のタグ（通常は 1 つ）と *path operation* 名（関数名）を使います。\n\nそのカスタム関数を **FastAPI** の `generate_unique_id_function` パラメータに渡します:\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### カスタム operation ID で TypeScript クライアントを生成 { #generate-a-typescript-client-with-custom-operation-ids }\n\nこの状態でクライアントを再生成すると、メソッド名が改善されています:\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\nご覧のとおり、メソッド名はタグ名と関数名のみになり、URL パスや HTTP オペレーションの情報は含まれません。\n\n### クライアント生成向けの OpenAPI 仕様の前処理 { #preprocess-the-openapi-specification-for-the-client-generator }\n\nそれでも生成コードには**重複情報**が残っています。\n\n`ItemsService`（タグ由来）から items 関連であることはすでに分かるのに、メソッド名にもタグ名が前置されています。😕\n\nOpenAPI 全体としては operation ID の**一意性**のために、このプレフィックスを維持したい場合があるでしょう。\n\nしかし生成クライアント用には、クライアントを生成する直前に OpenAPI の operation ID を**加工**して、メソッド名をより**見やすく**、**クリーン**にできます。\n\nOpenAPI の JSON を `openapi.json` として保存し、次のようなスクリプトで**そのタグのプレフィックスを除去**できます:\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\nこれにより operation ID は `items-get_items` のような形から単なる `get_items` に置き換わり、クライアントジェネレータはより簡潔なメソッド名を生成できます。\n\n### 前処理済み OpenAPI から TypeScript クライアントを生成 { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\n生成元が `openapi.json` になったので、入力の場所を更新します:\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\n新しいクライアントを生成すると、**クリーンなメソッド名**になり、**補完**や**インラインエラー**などもそのまま利用できます:\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## 利点 { #benefits }\n\n自動生成されたクライアントを使うと、次のような対象で**補完**が得られます:\n\n* メソッド\n* 本体のリクエストペイロード、クエリパラメータ等\n* レスポンスのペイロード\n\nまた、あらゆる箇所で**インラインエラー**も得られます。\n\nバックエンドコードを更新してフロントエンドを**再生成**すれば、新しい *path operation* はメソッドとして追加され、古いものは削除され、その他の変更も生成コードに反映されます。🤓\n\nつまり、変更があれば自動的にクライアントコードに**反映**されます。クライアントを**ビルド**すれば、使用データに**不整合**があればエラーになります。\n\nその結果、多くのエラーを開発の初期段階で**早期発見**でき、本番で最終ユーザーに不具合が現れてから原因をデバッグする必要がなくなります。✨\n"
  },
  {
    "path": "docs/ja/docs/advanced/index.md",
    "content": "# 高度なユーザーガイド { #advanced-user-guide }\n\n## さらなる機能 { #additional-features }\n\nメインの[チュートリアル - ユーザーガイド](../tutorial/index.md)だけで、**FastAPI**の主要な機能を一通り把握するには十分なはずです。\n\n以降のセクションでは、その他のオプション、設定、追加機能を見ていきます。\n\n/// tip | 豆知識\n\n以降のセクションは、**必ずしも「高度」ではありません**。\n\nまた、あなたのユースケースに対する解決策が、その中のどれかにある可能性もあります。\n\n///\n\n## 先にチュートリアルを読む { #read-the-tutorial-first }\n\nメインの[チュートリアル - ユーザーガイド](../tutorial/index.md)で得た知識があれば、**FastAPI**の機能の多くは引き続き利用できます。\n\nまた、以降のセクションでは、すでにそれを読んでいて、主要な考え方を理解していることを前提としています。\n"
  },
  {
    "path": "docs/ja/docs/advanced/json-base64-bytes.md",
    "content": "# Base64 にしたバイトを含む JSON { #json-with-bytes-as-base64 }\n\nアプリで JSON データの受信・送信が必要だが、その中にバイナリデータを含める必要がある場合は、base64 にエンコードできます。\n\n## Base64 とファイル { #base64-vs-files }\n\nバイナリデータのアップロードにはまず、JSON にエンコードする代わりに [Request Files](../tutorial/request-files.md) を、バイナリデータの送信には [カスタムレスポンス - FileResponse](./custom-response.md#fileresponse--fileresponse-) を使えるか検討してください。\n\nJSON は UTF-8 でエンコードされた文字列のみを含められるため、生のバイト列は含められません。\n\nBase64 はバイナリデータを文字列にエンコードできますが、そのために元のバイナリより多くの文字を使用する必要があり、通常は通常のファイルより非効率です。\n\nJSON にバイナリデータをどうしても含める必要があり、ファイルを使えない場合にのみ base64 を使用してください。\n\n## Pydantic `bytes` { #pydantic-bytes }\n\nPydantic モデルで `bytes` 型のフィールドを宣言し、モデル設定で `val_json_bytes` を使うと、入力 JSON データの検証時に base64 を用いるよう指示できます。この検証の一環として、base64 文字列はバイト列へデコードされます。\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\n「/docs」を確認すると、`data` フィールドが base64 でエンコードされたバイト列を期待していることが表示されます。\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\n次のようなリクエストを送れます:\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip | 豆知識\n\n`aGVsbG8=` は `hello` の base64 エンコードです。\n\n///\n\nその後、Pydantic は base64 文字列をデコードし、モデルの `data` フィールドに元のバイト列を渡します。\n\n次のようなレスポンスを受け取ります:\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## 出力データ向けの Pydantic `bytes` { #pydantic-bytes-for-output-data }\n\n出力データ用にモデル設定で `ser_json_bytes` とともに `bytes` フィールドを使用することもでき、Pydantic は JSON レスポンスを生成するときにバイト列を base64 でシリアライズします。\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## 入力・出力データ向けの Pydantic `bytes` { #pydantic-bytes-for-input-and-output-data }\n\nもちろん、同じモデルを base64 を使うように設定しておけば、JSON データの受信時は `val_json_bytes` で入力を「検証」し、送信時は `ser_json_bytes` で出力を「シリアライズ」する、といった具合に、入力と出力の両方を扱えます。\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/ja/docs/advanced/middleware.md",
    "content": "# 高度なミドルウェア { #advanced-middleware }\n\nメインのチュートリアルでは、アプリケーションに[カスタムミドルウェア](../tutorial/middleware.md)を追加する方法を学びました。\n\nそして、[`CORSMiddleware` を使った CORS の扱い方](../tutorial/cors.md)も学びました。\n\nこのセクションでは、その他のミドルウェアの使い方を見ていきます。\n\n## ASGI ミドルウェアの追加 { #adding-asgi-middlewares }\n\n**FastAPI** は Starlette を基盤としており、<abbr title=\"Asynchronous Server Gateway Interface - 非同期サーバーゲートウェイインターフェース\">ASGI</abbr> 仕様を実装しているため、任意の ASGI ミドルウェアを利用できます。\n\nミドルウェアは ASGI 仕様に従っていれば、FastAPI や Starlette 専用に作られていなくても動作します。\n\n一般に、ASGI ミドルウェアは最初の引数として ASGI アプリを受け取るクラスです。\n\nそのため、サードパーティの ASGI ミドルウェアのドキュメントでは、おそらく次のように書かれているでしょう:\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\nしかし FastAPI（正確には Starlette）は、内部ミドルウェアがサーバーエラーを処理し、カスタム例外ハンドラが正しく動作することを保証する、より簡単な方法を提供しています。\n\nそのためには（CORS の例と同様に）`app.add_middleware()` を使います。\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` は、最初の引数にミドルウェアのクラスを取り、それ以外の追加引数はミドルウェアに渡されます。\n\n## 組み込みミドルウェア { #integrated-middlewares }\n\n**FastAPI** は一般的なユースケースに対応するいくつかのミドルウェアを含んでいます。以下でその使い方を見ていきます。\n\n/// note | 技術詳細\n\n以下の例では、`from starlette.middleware.something import SomethingMiddleware` を使うこともできます。\n\n**FastAPI** は開発者であるあなたの便宜のために `fastapi.middleware` にいくつかのミドルウェアを提供しています。しかし、利用可能なミドルウェアの多くは Starlette から直接提供されています。\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\nすべての受信リクエストが `https` または `wss` でなければならないように強制します。\n\n`http` または `ws` への受信リクエストは、安全なスキームにリダイレクトされます。\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\nHTTP Host Header 攻撃を防ぐため、すべての受信リクエストに正しく設定された `Host` ヘッダーを強制します。\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\nサポートされる引数は次のとおりです:\n\n- `allowed_hosts` - 許可するホスト名のドメイン名リスト。`*.example.com` のようなワイルドカードドメインでサブドメインのマッチングもサポートします。任意のホスト名を許可するには、`allowed_hosts=[\"*\"]` を使うか、このミドルウェアを省略します。\n- `www_redirect` - True に設定すると、許可されたホストの非 www 版へのリクエストを www 版へリダイレクトします。デフォルトは `True` です。\n\n受信リクエストが正しく検証されない場合、`400` のレスポンスが返されます。\n\n## `GZipMiddleware` { #gzipmiddleware }\n\n`Accept-Encoding` ヘッダーに \"gzip\" を含むリクエストに対して GZip レスポンスを処理します。\n\nこのミドルウェアは、通常のレスポンスとストリーミングレスポンスの両方を処理します。\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\nサポートされる引数は次のとおりです:\n\n- `minimum_size` - このバイト数の最小サイズ未満のレスポンスは GZip 圧縮しません。デフォルトは `500` です。\n- `compresslevel` - GZip 圧縮時に使用します。1 から 9 までの整数です。デフォルトは `9`。値が小さいほど圧縮は速くなりますがファイルサイズは大きくなり、値が大きいほど圧縮は遅くなりますがファイルサイズは小さくなります。\n\n## その他のミドルウェア { #other-middlewares }\n\n他にも多くの ASGI ミドルウェアがあります。\n\n例えば:\n\n- [Uvicorn の `ProxyHeadersMiddleware`](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n- [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\n他に利用可能なミドルウェアについては、[Starlette のミドルウェアドキュメント](https://www.starlette.dev/middleware/)や [ASGI Awesome List](https://github.com/florimondmanca/awesome-asgi) を参照してください。\n"
  },
  {
    "path": "docs/ja/docs/advanced/openapi-callbacks.md",
    "content": "# OpenAPI コールバック { #openapi-callbacks }\n\nあなたは、*path operation* を持つ API を作成し、他者（多くの場合、あなたの API を「利用する」同一の開発者）が作成した *外部 API* へリクエストをトリガーできるようにできます。\n\nあなたの API アプリが *外部 API* を呼び出すときに起きる処理は「コールバック」と呼ばれます。なぜなら、外部開発者が作成したソフトウェアがあなたの API にリクエストを送り、その後であなたの API が「呼び返し」、*外部 API*（おそらく同じ開発者が作成）へリクエストを送るためです。\n\nこの場合、その *外部 API* がどのようである「べき」かをドキュメント化したくなるでしょう。どんな *path operation* を持ち、どんなボディを受け取り、どんなレスポンスを返すか、などです。\n\n## コールバックのあるアプリ { #an-app-with-callbacks }\n\n例で見ていきます。\n\nあなたが請求書を作成できるアプリを開発していると想像してください。\n\nこれらの請求書は `id`、`title`（任意）、`customer`、`total` を持ちます。\n\nあなたの API の利用者（外部開発者）は、POST リクエストであなたの API に請求書を作成します。\n\nその後、あなたの API は（仮にこうしましょう）:\n\n* 外部開発者の顧客に請求書を送ります。\n* 代金を回収します。\n* API 利用者（外部開発者）に通知を送り返します。\n    * これは（あなたの API から）外部開発者が提供する *外部 API* に POST リクエストを送ることで行われます（これが「コールバック」です）。\n\n## 通常の FastAPI アプリ { #the-normal-fastapi-app }\n\nまず、コールバックを追加する前の通常の API アプリがどうなるか見てみましょう。\n\n`Invoice` ボディを受け取り、クエリパラメータ `callback_url` にコールバック用の URL を含める *path operation* を持ちます。\n\nこの部分はとても普通で、ほとんどのコードはすでに見覚えがあるはずです:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip | 豆知識\n\n`callback_url` クエリパラメータは、Pydantic の [Url](https://docs.pydantic.dev/latest/api/networks/) 型を使用します。\n\n///\n\n唯一の新しい点は、*path operation デコレータ*の引数として `callbacks=invoices_callback_router.routes` を渡すことです。これが何かは次で見ます。\n\n## コールバックのドキュメント化 { #documenting-the-callback }\n\n実際のコールバックのコードは、あなた自身の API アプリに大きく依存します。\n\nそしてアプリごとに大きく異なるでしょう。\n\nそれは次のように 1、2 行のコードかもしれません:\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\nしかし、おそらくコールバックで最も重要な点は、あなたの API 利用者（外部開発者）が、*あなたの API* がコールバックのリクエストボディなどで送るデータに従って、*外部 API* を正しく実装することを確実にすることです。\n\nそこで次に行うのは、*あなたの API* からのコールバックを受け取るために、その *外部 API* がどうあるべきかをドキュメント化するコードを追加することです。\n\nそのドキュメントはあなたの API の `/docs` の Swagger UI に表示され、外部開発者に *外部 API* の作り方を知らせます。\n\nこの例ではコールバック自体は実装しません（それは 1 行のコードでもよいでしょう）。ドキュメント部分のみです。\n\n/// tip | 豆知識\n\n実際のコールバックは単なる HTTP リクエストです。\n\n自分でコールバックを実装する場合は、[HTTPX](https://www.python-httpx.org) や [Requests](https://requests.readthedocs.io/) のようなものを使えます。\n\n///\n\n## コールバックのドキュメント用コードを書く { #write-the-callback-documentation-code }\n\nこのコードはあなたのアプリで実行されません。*外部 API* がどうあるべきかをドキュメント化するためだけに必要です。\n\nしかし、あなたはすでに **FastAPI** で API の自動ドキュメントを簡単に作る方法を知っています。\n\nその知識を使って、*外部 API* がどうあるべきかをドキュメント化します……つまり、外部 API が実装すべき *path operation(s)*（あなたの API が呼び出すもの）を作成します。\n\n/// tip | 豆知識\n\nコールバックをドキュメント化するコードを書くときは、あなたがその「外部開発者」だと想像するのが役に立つかもしれません。いま実装しているのは「あなたの API」ではなく、*外部 API* です。\n\nこの（外部開発者の）視点を一時的に採用すると、その *外部 API* に対してパラメータ、ボディ用の Pydantic モデル、レスポンスなどをどこに置くのが自然かがより明確に感じられるでしょう。\n\n///\n\n### コールバック用 APIRouter を作成 { #create-a-callback-apirouter }\n\nまず、1 つ以上のコールバックを含む新しい `APIRouter` を作成します。\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### コールバックの path operation を作成 { #create-the-callback-path-operation }\n\n上で作成したのと同じ `APIRouter` を使って、コールバックの *path operation* を作成します。\n\n見た目は通常の FastAPI の *path operation* と同じです:\n\n* 受け取るボディの宣言（例: `body: InvoiceEvent`）が必要でしょう。\n* 返すレスポンスの宣言（例: `response_model=InvoiceEventReceived`）も持てます。\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\n通常の *path operation* と異なる主な点が 2 つあります:\n\n* 実際のコードは不要です。あなたのアプリはこのコードを決して呼びません。これは *外部 API* をドキュメント化するためだけに使われます。したがって、関数本体は `pass` で構いません。\n* *パス* には、*あなたの API* に送られた元のリクエストのパラメータや一部を変数として使える [OpenAPI 3 の式](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression)（後述）を含められます。\n\n### コールバックのパス式 { #the-callback-path-expression }\n\nコールバックの *パス* には、*あなたの API* に送られた元のリクエストの一部を含められる [OpenAPI 3 の式](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression)を使用できます。\n\nこの例では、`str` は次のとおりです:\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\nつまり、あなたの API 利用者（外部開発者）が *あなたの API* に次のようにリクエストを送った場合:\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\nJSON ボディは:\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\nその後 *あなたの API* は請求書を処理し、のちほど `callback_url`（*外部 API*）へコールバックのリクエストを送ります:\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\nJSON ボディは次のような内容です:\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\nそして *外部 API* からは次のような JSON ボディのレスポンスを期待します:\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip | 豆知識\n\n使用されるコールバック URL には、クエリパラメータ `callback_url`（`https://www.external.org/events`）で受け取った URL と、JSON ボディ内の請求書 `id`（`2expen51ve`）が含まれている点に注目してください。\n\n///\n\n### コールバック用ルーターを追加 { #add-the-callback-router }\n\nこれで、上で作成したコールバック用ルーター内に、必要なコールバックの *path operation(s)*（*外部開発者* が *外部 API* に実装すべきもの）が用意できました。\n\n次に、*あなたの API の path operation デコレータ*の `callbacks` パラメータに、そのコールバック用ルーターの属性 `.routes`（実体はルート/*path operations* の `list`）を渡します:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip | 豆知識\n\n`callback=` に渡すのはルーター本体（`invoices_callback_router`）ではなく、属性 `.routes`（`invoices_callback_router.routes`）である点に注意してください。\n\n///\n\n### ドキュメントを確認 { #check-the-docs }\n\nアプリを起動して [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) にアクセスします。\n\nあなたの *path operation* に「Callbacks」セクションが含まれ、*外部 API* がどうあるべきかが表示されているのが確認できます:\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/ja/docs/advanced/openapi-webhooks.md",
    "content": "# OpenAPI の Webhook { #openapi-webhooks }\n\nアプリがある種の**イベント**を**通知**するために、データ付きで相手のアプリ（リクエスト送信）を呼び出す可能性があることを、API の**ユーザー**に伝えたい場合があります。\n\nこれは、通常のようにユーザーがあなたの API にリクエストを送るのではなく、**あなたの API（あなたのアプリ）**が**相手のシステム**（相手の API、アプリ）にリクエストを送る、ということです。\n\nこれは一般に**Webhook**と呼ばれます。\n\n## Webhook の手順 { #webhooks-steps }\n\n通常の流れとして、まずあなたのコード内で、送信するメッセージ、すなわちリクエストの**本文（ボディ）**を**定義**します。\n\n加えて、アプリがそれらのリクエスト（イベント）を送信する**タイミング**も何らかの形で定義します。\n\nそして**ユーザー**は、アプリがそのリクエストを送るべき**URL**を（たとえばどこかの Web ダッシュボードで）定義します。\n\nWebhook の URL を登録する方法や実際にリクエストを送るコードなど、これらの**ロジック**はすべてあなた次第です。**あなた自身のコード**で好きなように実装します。\n\n## FastAPI と OpenAPI による Webhook のドキュメント化 { #documenting-webhooks-with-fastapi-and-openapi }\n\n**FastAPI** と OpenAPI を使うと、Webhook の名前、アプリが送信できる HTTP の操作（例: `POST`, `PUT` など）、アプリが送るリクエストの**ボディ**を定義できます。\n\nこれにより、ユーザーがあなたの **Webhook** リクエストを受け取るための**API を実装**するのが大幅に簡単になります。場合によっては、ユーザーが自分たちの API コードを自動生成できるかもしれません。\n\n/// info | 情報\n\nWebhook は OpenAPI 3.1.0 以上で利用可能で、FastAPI `0.99.0` 以上が対応しています。\n\n///\n\n## Webhook を持つアプリ { #an-app-with-webhooks }\n\n**FastAPI** アプリケーションを作成すると、`webhooks` という属性があり、ここで *path operations* と同様に（例: `@app.webhooks.post()`）*webhook* を定義できます。\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\n定義した webhook は **OpenAPI** スキーマおよび自動生成される **ドキュメント UI** に反映されます。\n\n/// info | 情報\n\n`app.webhooks` オブジェクトは実際には単なる `APIRouter` で、複数ファイルでアプリを構成する際に使うものと同じ型です。\n\n///\n\nWebhook では（`/items/` のような）*パス*を宣言しているわけではない点に注意してください。ここで渡す文字列は webhook の**識別子**（イベント名）です。たとえば `@app.webhooks.post(\"new-subscription\")` での webhook 名は `new-subscription` です。\n\nこれは、**ユーザー**が実際に Webhook リクエストを受け取りたい**URL パス**を、別の方法（例: Web ダッシュボード）で定義することを想定しているためです。\n\n### ドキュメントの確認 { #check-the-docs }\n\nアプリを起動し、[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) にアクセスします。\n\nドキュメントには通常の *path operations* に加えて、**webhooks** も表示されます:\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/ja/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# Path Operationの高度な設定 { #path-operation-advanced-configuration }\n\n## OpenAPI operationId { #openapi-operationid }\n\n/// warning | 注意\n\nOpenAPIの「エキスパート」でなければ、これはおそらく必要ありません。\n\n///\n\n*path operation* で `operation_id` パラメータを利用することで、OpenAPIの `operationId` を設定できます。\n\n各オペレーションで一意になるようにする必要があります。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### *path operation関数* の名前をoperationIdとして使用する { #using-the-path-operation-function-name-as-the-operationid }\n\nAPIの関数名を `operationId` として利用したい場合、すべてのAPI関数をイテレーションし、各 *path operation* の `operation_id` を `APIRoute.name` で上書きすれば可能です。\n\nすべての *path operation* を追加した後に行うべきです。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip | 豆知識\n\n`app.openapi()` を手動で呼び出す場合、その前に `operationId` を更新するべきです。\n\n///\n\n/// warning | 注意\n\nこの方法をとる場合、各 *path operation関数* が一意な名前である必要があります。\n\n異なるモジュール（Pythonファイル）にある場合でも同様です。\n\n///\n\n## OpenAPIから除外する { #exclude-from-openapi }\n\n生成されるOpenAPIスキーマ（つまり、自動ドキュメント生成の仕組み）から *path operation* を除外するには、`include_in_schema` パラメータを使用して `False` に設定します。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## docstringによる説明の高度な設定 { #advanced-description-from-docstring }\n\n*path operation関数* のdocstringからOpenAPIに使用する行を制限できます。\n\n`\\f`（エスケープされた「書式送り（form feed）」文字）を追加すると、**FastAPI** はその地点でOpenAPIに使用される出力を切り詰めます。\n\nドキュメントには表示されませんが、他のツール（Sphinxなど）は残りの部分を利用できます。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## 追加レスポンス { #additional-responses }\n\n*path operation* に対して `response_model` と `status_code` を宣言する方法はすでに見たことがあるでしょう。\n\nそれにより、*path operation* のメインのレスポンスに関するメタデータが定義されます。\n\n追加のレスポンスについても、モデルやステータスコードなどとともに宣言できます。\n\nこれについてはドキュメントに章全体があります。 [OpenAPIの追加レスポンス](additional-responses.md) で読めます。\n\n## OpenAPI Extra { #openapi-extra }\n\nアプリケーションで *path operation* を宣言すると、**FastAPI** はOpenAPIスキーマに含めるために、その *path operation* に関連するメタデータを自動的に生成します。\n\n/// note | 技術詳細\n\nOpenAPI仕様では [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object) と呼ばれています。\n\n///\n\nこれには *path operation* に関するすべての情報が含まれ、自動ドキュメントを生成するために使われます。\n\n`tags`、`parameters`、`requestBody`、`responses` などが含まれます。\n\nこの *path operation* 固有のOpenAPIスキーマは通常 **FastAPI** により自動生成されますが、拡張することもできます。\n\n/// tip | 豆知識\n\nこれは低レベルな拡張ポイントです。\n\n追加レスポンスを宣言するだけなら、より便利な方法として [OpenAPIの追加レスポンス](additional-responses.md) を使うことができます。\n\n///\n\n`openapi_extra` パラメータを使って、*path operation* のOpenAPIスキーマを拡張できます。\n\n### OpenAPI Extensions { #openapi-extensions }\n\nこの `openapi_extra` は、例えば [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) を宣言するのに役立ちます。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\n自動APIドキュメントを開くと、その拡張は特定の *path operation* の下部に表示されます。\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\nそして（APIの `/openapi.json` にある）生成されたOpenAPIを見ると、その拡張も特定の *path operation* の一部として確認できます。\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### カスタムOpenAPI *path operation* スキーマ { #custom-openapi-path-operation-schema }\n\n`openapi_extra` 内の辞書は、*path operation* 用に自動生成されたOpenAPIスキーマと深くマージされます。\n\nそのため、自動生成されたスキーマに追加データを加えることができます。\n\n例えば、Pydanticを使ったFastAPIの自動機能を使わずに独自のコードでリクエストを読み取り・検証することを選べますが、それでもOpenAPIスキーマでリクエストを定義したい場合があります。\n\nそれは `openapi_extra` で行えます。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\nこの例では、Pydanticモデルを一切宣言していません。実際、リクエストボディはJSONとして <dfn title=\"bytes などのプレーンな形式から Python オブジェクトに変換される\">パース</dfn> されず、直接 `bytes` として読み取られます。そして `magic_data_reader()` 関数が、何らかの方法でそれをパースする責務を担います。\n\nそれでも、リクエストボディに期待されるスキーマを宣言できます。\n\n### カスタムOpenAPI content type { #custom-openapi-content-type }\n\n同じトリックを使って、PydanticモデルでJSON Schemaを定義し、それを *path operation* 用のカスタムOpenAPIスキーマセクションに含めることができます。\n\nまた、リクエスト内のデータ型がJSONでない場合でもこれを行えます。\n\n例えばこのアプリケーションでは、PydanticモデルからJSON Schemaを抽出するFastAPIの統合機能や、JSONの自動バリデーションを使っていません。実際、リクエストのcontent typeをJSONではなくYAMLとして宣言しています。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\nそれでも、デフォルトの統合機能を使っていないにもかかわらず、YAMLで受け取りたいデータのために、Pydanticモデルを使って手動でJSON Schemaを生成しています。\n\nそしてリクエストを直接使い、ボディを `bytes` として抽出します。これは、FastAPIがリクエストペイロードをJSONとしてパースしようとすらしないことを意味します。\n\nその後、コード内でそのYAMLコンテンツを直接パースし、さらに同じPydanticモデルを使ってYAMLコンテンツを検証しています。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip | 豆知識\n\nここでは同じPydanticモデルを再利用しています。\n\nただし同様に、別の方法で検証することもできます。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/advanced/response-change-status-code.md",
    "content": "# レスポンス - ステータスコードの変更 { #response-change-status-code }\n\nすでに、デフォルトの[レスポンスのステータスコード](../tutorial/response-status-code.md)を設定できることをご存知かもしれません。\n\nしかし場合によっては、デフォルトとは異なるステータスコードを返す必要があります。\n\n## ユースケース { #use-case }\n\nたとえば、デフォルトでは HTTP ステータスコード \"OK\" `200` を返したいとします。\n\nしかし、データが存在しなければそれを作成し、HTTP ステータスコード \"CREATED\" `201` を返したい。\n\nそれでも、返すデータは `response_model` でフィルタ・変換できるようにしておきたい。\n\nそのような場合は `Response` パラメータを使えます。\n\n## `Response` パラメータを使う { #use-a-response-parameter }\n\n*path operation* 関数で `Response` 型のパラメータを宣言できます（Cookie やヘッダーと同様です）。\n\nそして、その*一時的な*レスポンスオブジェクトに `status_code` を設定できます。\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\nその後は通常どおり、必要な任意のオブジェクト（`dict`、データベースモデルなど）を返せます。\n\nそして `response_model` を宣言していれば、返したオブジェクトのフィルタと変換には引き続きそれが使われます。\n\n**FastAPI** はその*一時的な*レスポンスからステータスコード（および Cookie とヘッダー）を取り出し、`response_model` によってフィルタ済みの返却値を含む最終的なレスポンスに反映します。\n\nまた、`Response` パラメータは依存関係内に宣言してステータスコードを設定することもできます。ただし、最後に設定されたものが優先される点に注意してください。\n"
  },
  {
    "path": "docs/ja/docs/advanced/response-cookies.md",
    "content": "# レスポンスの Cookie { #response-cookies }\n\n## `Response` パラメータを使う { #use-a-response-parameter }\n\n*path operation 関数*で `Response` 型のパラメータを宣言できます。\n\nそして、その*一時的*なレスポンスオブジェクトに Cookie を設定できます。\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\nその後は通常どおり、必要な任意のオブジェクト（`dict`、データベースモデルなど）を返せます。\n\n`response_model` を宣言している場合でも、返したオブジェクトは引き続きフィルタおよび変換されます。\n\n**FastAPI** はその*一時的*なレスポンスから Cookie（およびヘッダーやステータスコード）を取り出し、`response_model` によってフィルタされた返却値を含む最終的なレスポンスに設定します。\n\n`Response` パラメータは依存関係でも宣言でき、そこで Cookie（やヘッダー）を設定することも可能です。\n\n## `Response` を直接返す { #return-a-response-directly }\n\nコードで `Response` を直接返すときに、Cookie を作成することもできます。\n\nそのためには、[Response を直接返す](response-directly.md) で説明されているとおりにレスポンスを作成します。\n\nそのレスポンスに Cookie を設定してから返します:\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip | 豆知識\n\n`Response` パラメータを使わずにレスポンスを直接返す場合、FastAPI はそのレスポンスをそのまま返します。\n\nそのため、データの型が正しいことを確認する必要があります。例えば、`JSONResponse` を返すなら、JSON と互換性がある必要があります。\n\nまた、`response_model` によってフィルタされるべきデータを送っていないことも確認してください。\n\n///\n\n### 詳細情報 { #more-info }\n\n/// note | 技術詳細\n\n`from starlette.responses import Response` や `from starlette.responses import JSONResponse` を使うこともできます。\n\n**FastAPI** は開発者の利便性のために、`starlette.responses` と同じものを `fastapi.responses` として提供しています。ただし、利用可能なレスポンスの大半は Starlette から直接提供されています。\n\nまた、`Response` はヘッダーや Cookie の設定に頻繁に使われるため、`fastapi.Response` としても提供されています。\n\n///\n\n利用可能なすべてのパラメータやオプションについては、[Starlette のドキュメント](https://www.starlette.dev/responses/#set-cookie)を参照してください。\n"
  },
  {
    "path": "docs/ja/docs/advanced/response-directly.md",
    "content": "# レスポンスを直接返す { #return-a-response-directly }\n\n**FastAPI** の *path operation* では、通常は任意のデータを返すことができます: 例えば、`dict`、`list`、Pydanticモデル、データベースモデルなどです。\n\n[レスポンスモデル](../tutorial/response-model.md) を宣言した場合、FastAPI は Pydantic を使ってデータをJSONにシリアライズします。\n\nレスポンスモデルを宣言しない場合、FastAPI は [JSON互換エンコーダ](../tutorial/encoder.md) で説明されている `jsonable_encoder` を使用し、その結果を `JSONResponse` に入れます。\n\nまた、`JSONResponse` を直接作成して返すこともできます。\n\n/// tip\n\n通常は、`JSONResponse` を直接返すよりも、[レスポンスモデル](../tutorial/response-model.md) を使うほうがパフォーマンスが大幅に良くなります。これは、Pydantic によるシリアライズが Rust で実行されるためです。\n\n///\n\n## `Response` を返す { #return-a-response }\n\n実際は、`Response` やそのサブクラスを返すことができます。\n\n/// info\n\n`JSONResponse` それ自体は、`Response` のサブクラスです。\n\n///\n\n`Response` を返した場合は、**FastAPI** は直接それを返します。\n\nそれは、Pydanticモデルのデータ変換や、コンテンツを任意の型に変換したりなどはしません。\n\nこれは多くの柔軟性を提供します。任意のデータ型を返したり、任意のデータ宣言やバリデーションをオーバーライドできます。\n\n同時に多くの責任も伴います。返すデータが正しく、正しいフォーマットであり、シリアライズ可能であることなどを、あなたが保証しなければなりません。\n\n## `jsonable_encoder` を `Response` の中で使う { #using-the-jsonable-encoder-in-a-response }\n\n**FastAPI** はあなたが返す `Response` に対して何も変更を加えないので、コンテンツが準備できていることを保証しなければなりません。\n\n例えば、Pydanticモデルを `JSONResponse` に含めるには、すべてのデータ型 (`datetime` や `UUID` など) をJSON互換の型に変換された `dict` に変換しなければなりません。\n\nこのようなケースでは、レスポンスにデータを含める前に `jsonable_encoder` を使ってデータを変換できます。\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | 技術詳細\n\nまた、`from starlette.responses import JSONResponse` も利用できます。\n\n**FastAPI** は開発者の利便性のために `fastapi.responses` という `starlette.responses` と同じものを提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。\n\n///\n\n## カスタム `Response` を返す { #returning-a-custom-response }\n\n上記の例では必要な部分を全て示していますが、あまり便利ではありません。`item` を直接返すことができるし、**FastAPI** はそれを `dict` に変換して `JSONResponse` に含めてくれるなど。すべて、デフォルトの動作です。\n\nでは、これを使ってカスタムレスポンスをどう返すか見てみましょう。\n\n[XML](https://en.wikipedia.org/wiki/XML)レスポンスを返したいとしましょう。\n\nXMLを文字列にし、`Response` に含め、それを返します。\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## Response Model の仕組み { #how-a-response-model-works }\n\npath operation で [Response Model - 戻り値の型](../tutorial/response-model.md) を宣言すると、**FastAPI** はそれを使って Pydantic によりデータをJSONにシリアライズします。\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nこれは Rust 側で行われるため、通常の Python と `JSONResponse` クラスで行う場合より、パフォーマンスははるかに良くなります。\n\n`response_model` や戻り値の型を使用する場合、FastAPI はデータ変換に（低速になりうる）`jsonable_encoder` も `JSONResponse` クラスも使いません。\n\n代わりに、response model（または戻り値の型）を使って Pydantic が生成した JSON のバイト列をそのまま用い、JSON 用の正しいメディアタイプ（`application/json`）を持つ `Response` を直接返します。\n\n## 備考 { #notes }\n\n`Response` を直接返す場合、バリデーションや、変換 (シリアライズ) や、自動ドキュメントは行われません。\n\nしかし、[Additional Responses in OpenAPI](additional-responses.md)に記載されたようにドキュメントを書くこともできます。\n\n後のセクションで、カスタム `Response` を使用・宣言しながら、自動的なデータ変換やドキュメンテーションを行う方法を説明します。\n"
  },
  {
    "path": "docs/ja/docs/advanced/response-headers.md",
    "content": "# レスポンスヘッダー { #response-headers }\n\n## `Response` パラメータを使う { #use-a-response-parameter }\n\n（Cookie と同様に）*path operation 関数*で `Response` 型のパラメータを宣言できます。\n\nそして、その*一時的*なレスポンスオブジェクトにヘッダーを設定できます。\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\nその後は通常どおり、必要な任意のオブジェクト（`dict`、データベースモデルなど）を返せます。\n\n`response_model` を宣言している場合は、返したオブジェクトのフィルタと変換に引き続き使用されます。\n\n**FastAPI** はその*一時的*なレスポンスからヘッダー（Cookie やステータスコードも含む）を取り出し、`response_model` によってフィルタされた返却値を含む最終的なレスポンスに反映します。\n\nまた、依存関係の中で `Response` パラメータを宣言し、その中でヘッダー（や Cookie）を設定することもできます。\n\n## `Response` を直接返す { #return-a-response-directly }\n\n`Response` を直接返す場合にもヘッダーを追加できます。\n\n[Response を直接返す](response-directly.md) で説明したようにレスポンスを作成し、ヘッダーを追加のパラメータとして渡します:\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | 技術詳細\n\n`from starlette.responses import Response` や `from starlette.responses import JSONResponse` を使うこともできます。\n\n**FastAPI** は、開発者であるあなたへの便宜として、`starlette.responses` と同じものを `fastapi.responses` として提供しています。しかし、利用可能なレスポンスの大半は直接 Starlette から来ています。\n\nまた、`Response` はヘッダーや Cookie を設定するのによく使われるため、**FastAPI** は `fastapi.Response` でも提供しています。\n\n///\n\n## カスタムヘッダー { #custom-headers }\n\n独自のカスタムヘッダーは、[`X-` プレフィックスを使って](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)追加できることに注意してください。\n\nただし、ブラウザのクライアントに見えるようにしたいカスタムヘッダーがある場合は、CORS 設定にそれらを追加する必要があります（[CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md) を参照）。このとき、[Starlette の CORS ドキュメント](https://www.starlette.dev/middleware/#corsmiddleware)に記載の `expose_headers` パラメータを使用します。\n"
  },
  {
    "path": "docs/ja/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP Basic 認証 { #http-basic-auth }\n\n最もシンプルなケースでは、HTTP Basic 認証を利用できます。\n\nHTTP Basic 認証では、アプリケーションはユーザー名とパスワードを含むヘッダーを期待します。\n\nそれを受け取れない場合、HTTP 401 \"Unauthorized\" エラーを返します。\n\nそして、値が `Basic` のヘッダー `WWW-Authenticate` を、任意の `realm` パラメータとともに返します。\n\nこれにより、ブラウザは組み込みのユーザー名とパスワード入力プロンプトを表示します。\n\nその後、そのユーザー名とパスワードを入力すると、ブラウザはそれらをヘッダーに自動的に付与して送信します。\n\n## シンプルな HTTP Basic 認証 { #simple-http-basic-auth }\n\n- `HTTPBasic` と `HTTPBasicCredentials` をインポートします。\n- `HTTPBasic` を使って「`security` スキーム」を作成します。\n- その `security` を依存関係として path operation に使用します。\n- `HTTPBasicCredentials` 型のオブジェクトが返ります:\n    - 送信された `username` と `password` を含みます。\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\nURL を最初に開こうとしたとき（またはドキュメントで「Execute」ボタンをクリックしたとき）、ブラウザはユーザー名とパスワードの入力を求めます:\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## ユーザー名の確認 { #check-the-username }\n\nより完全な例です。\n\n依存関係を使ってユーザー名とパスワードが正しいかを確認します。\n\nこれには、Python 標準モジュール [`secrets`](https://docs.python.org/3/library/secrets.html) を用いてユーザー名とパスワードを検証します。\n\n`secrets.compare_digest()` は `bytes` か、ASCII 文字（英語の文字）のみを含む `str` を受け取る必要があります。つまり、`Sebastián` のように `á` を含む文字ではそのままでは動作しません。\n\nこれに対処するため、まず `username` と `password` を UTF-8 でエンコードして `bytes` に変換します。\n\nそのうえで、`secrets.compare_digest()` を使って、`credentials.username` が `\"stanleyjobson\"` であり、`credentials.password` が `\"swordfish\"` であることを確認します。\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\nこれは次のようなコードに相当します:\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # 何らかのエラーを返す\n    ...\n```\n\nしかし `secrets.compare_digest()` を使うことで、「タイミング攻撃」と呼ばれる種類の攻撃に対して安全になります。\n\n### タイミング攻撃 { #timing-attacks }\n\n「タイミング攻撃」とは何でしょうか？\n\n攻撃者がユーザー名とパスワードを推測しようとしていると想像してください。\n\nそして、ユーザー名 `johndoe`、パスワード `love123` を使ってリクエストを送ります。\n\nその場合、アプリケーション内の Python コードは次のようなものと等価になります:\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nしかし、Python は `johndoe` の最初の `j` と `stanleyjobson` の最初の `s` を比較した時点で、両者の文字列が同じでないと判断してすぐに `False` を返します。つまり「残りの文字を比較して計算資源を無駄にする必要はない」と考えるわけです。そしてアプリケーションは「ユーザー名またはパスワードが正しくありません」と返します。\n\n次に、攻撃者がユーザー名 `stanleyjobsox`、パスワード `love123` で試すとします。\n\nアプリケーションのコードは次のようになります:\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nこの場合、Python は `stanleyjobsox` と `stanleyjobson` の両方で `stanleyjobso` 全体を比較してから、文字列が同じでないと気づきます。したがって、「ユーザー名またはパスワードが正しくありません」と応答するまでに余分に数マイクロ秒かかります。\n\n#### 応答時間が攻撃者を助ける { #the-time-to-answer-helps-the-attackers }\n\nここで、サーバーが「ユーザー名またはパスワードが正しくありません」というレスポンスを返すまでに、わずかに長い時間がかかったことに気づけば、攻撃者は何かしら正解に近づいた、すなわち先頭のいくつかの文字が正しかったことを知ることができます。\n\nすると、`johndoe` よりも `stanleyjobsox` に近いものを狙って再試行できます。\n\n#### 「プロ」レベルの攻撃 { #a-professional-attack }\n\nもちろん、攻撃者はこれらを手作業では行わず、プログラムを書いて、1 秒間に数千〜数百万回のテストを行うでしょう。そして 1 回に 1 文字ずつ正しい文字を見つけていきます。\n\nそうすることで、数分から数時間のうちに、攻撃者は私たちのアプリケーションの「助け」（応答にかかった時間）だけを利用して、正しいユーザー名とパスワードを推測できてしまいます。\n\n#### `secrets.compare_digest()` で対策 { #fix-it-with-secrets-compare-digest }\n\nしかし、私たちのコードでは実際に `secrets.compare_digest()` を使用しています。\n\n要するに、`stanleyjobsox` と `stanleyjobson` を比較するのにかかる時間は、`johndoe` と `stanleyjobson` を比較するのにかかる時間と同じになります。パスワードでも同様です。\n\nこのように、アプリケーションコードで `secrets.compare_digest()` を使うと、この種の一連のセキュリティ攻撃に対して安全になります。\n\n### エラーを返す { #return-the-error }\n\n認証情報が不正であることを検出したら、ステータスコード 401（認証情報が提供されない場合と同じ）で `HTTPException` を返し、ブラウザに再度ログインプロンプトを表示させるためにヘッダー `WWW-Authenticate` を追加します:\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/ja/docs/advanced/security/index.md",
    "content": "# 高度なセキュリティ { #advanced-security }\n\n## 追加機能 { #additional-features }\n\n[チュートリアル - ユーザーガイド: セキュリティ](../../tutorial/security/index.md)で扱ったもの以外にも、セキュリティを扱うための追加機能がいくつかあります。\n\n/// tip | 豆知識\n\n次の節は**必ずしも「高度」ではありません**。\n\nあなたのユースケースでは、その中のいずれかに解決策があるかもしれません。\n\n///\n\n## まずチュートリアルを読む { #read-the-tutorial-first }\n\n以下の節は、すでにメインの[チュートリアル - ユーザーガイド: セキュリティ](../../tutorial/security/index.md)を読んでいることを前提とします。\n\nいずれも同じ概念に基づいていますが、いくつかの追加機能を利用できます。\n"
  },
  {
    "path": "docs/ja/docs/advanced/security/oauth2-scopes.md",
    "content": "# OAuth2 のスコープ { #oauth2-scopes }\n\nOAuth2 のスコープは **FastAPI** で直接利用でき、シームレスに統合されています。\n\nこれにより、OAuth2 標準に従った、よりきめ細かな権限システムを、OpenAPI 対応アプリケーション（および API ドキュメント）に統合できます。\n\nスコープ付きの OAuth2 は、Facebook、Google、GitHub、Microsoft、X (Twitter) など、多くの大手認証プロバイダで使われている仕組みです。ユーザーやアプリケーションに特定の権限を付与するために利用されます。\n\n「Facebook でログイン」「Google でログイン」「GitHub でログイン」「Microsoft でログイン」「X (Twitter) でログイン」するたびに、そのアプリケーションはスコープ付きの OAuth2 を使っています。\n\nこの節では、同じスコープ付き OAuth2 を使って、**FastAPI** アプリケーションで認証と認可を管理する方法を見ていきます。\n\n/// warning | 注意\n\nこれはやや高度な内容です。はじめたばかりであれば読み飛ばしても構いません。\n\nOAuth2 のスコープは必ずしも必要ではなく、認証と認可は好きなやり方で実装できます。\n\nただし、スコープ付きの OAuth2 は、API（OpenAPI）や API ドキュメントにきれいに統合できます。\n\nとはいえ、これらのスコープやその他のセキュリティ／認可要件の適用は、必要に応じてコードの中で行う必要があります。\n\n多くの場合、スコープ付き OAuth2 はオーバースペックになりえます。\n\nそれでも必要だと分かっている場合や、興味がある場合は、このまま読み進めてください。\n\n///\n\n## OAuth2 のスコープと OpenAPI { #oauth2-scopes-and-openapi }\n\nOAuth2 仕様では、「スコープ」は空白で区切られた文字列の一覧として定義されています。\n\n各文字列の内容は任意ですが、空白は含められません。\n\nこれらのスコープは「権限」を表します。\n\nOpenAPI（例: API ドキュメント）では、「セキュリティスキーム」を定義できます。\n\nこれらのセキュリティスキームの一つが OAuth2 を使う場合、スコープを宣言して利用できます。\n\n各「スコープ」は、ただの文字列（空白なし）です。\n\n通常、特定のセキュリティ権限を宣言するために使われます。例えば:\n\n- `users:read` や `users:write` は一般的な例です。\n- `instagram_basic` は Facebook / Instagram で使われています。\n- `https://www.googleapis.com/auth/drive` は Google で使われています。\n\n/// info | 情報\n\nOAuth2 において「スコープ」は、必要な特定の権限を宣言する単なる文字列です。\n\n`:` のような他の文字が含まれていても、URL であっても問題ありません。\n\nそれらの詳細は実装依存です。\n\nOAuth2 にとっては、単に文字列に過ぎません。\n\n///\n\n## 全体像 { #global-view }\n\nまず、メインの**チュートリアル - ユーザーガイド**にある [OAuth2（パスワード［ハッシュ化あり］）、Bearer と JWT トークン](../../tutorial/security/oauth2-jwt.md) の例から変更される部分を、スコープ付き OAuth2 を使って手早く見てみましょう。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\nでは、これらの変更を一つずつ確認していきます。\n\n## OAuth2 のセキュリティスキーム { #oauth2-security-scheme }\n\n最初の変更点は、`me` と `items` の 2 つのスコープを持つ OAuth2 セキュリティスキームを宣言していることです。\n\n`scopes` パラメータは、各スコープをキー、その説明を値とする `dict` を受け取ります:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\nこれらのスコープを宣言しているため、ログイン／認可時に API ドキュメントに表示されます。\n\nそして、付与するスコープ（`me`、`items`）を選択できます。\n\nこれは、Facebook、Google、GitHub などでログイン時に権限を付与する際と同じ仕組みです:\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## スコープ付きの JWT トークン { #jwt-token-with-scopes }\n\n次に、トークンの path operation を修正して、要求されたスコープを返すようにします。\n\n引き続き同じ `OAuth2PasswordRequestForm` を使用します。これには、リクエストで受け取った各スコープを含む、`str` の `list` である `scopes` プロパティが含まれます。\n\nそして、そのスコープを JWT トークンの一部として返します。\n\n/// danger | 警告\n\n簡単のため、ここでは受け取ったスコープをそのままトークンに追加しています。\n\nしかし、本番アプリケーションではセキュリティのため、ユーザーが実際に持つことができるスコープ、または事前に定義したスコープだけを追加するようにしてください。\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## path operation と依存関係でスコープを宣言 { #declare-scopes-in-path-operations-and-dependencies }\n\nここでは、`/users/me/items/` の path operation が `items` スコープを必要とするように宣言します。\n\nそのために、`fastapi` から `Security` をインポートして使います。\n\n`Security` は（`Depends` と同様に）依存関係を宣言できますが、さらにスコープ（文字列）のリストを受け取る `scopes` パラメータも持ちます。\n\nこの場合、`Security` に依存関数 `get_current_active_user` を渡します（`Depends` と同様です）。\n\n加えて、`items` という 1 つのスコープ（複数でも可）を含む `list` も渡します。\n\n依存関数 `get_current_active_user` は、`Depends` だけでなく `Security` でもサブ依存関係を宣言できます。自身のサブ依存関数（`get_current_user`）を宣言し、さらにスコープ要件を追加します。\n\nこの場合、`me` スコープを要求します（複数のスコープも可）。\n\n/// note | 備考\n\n異なる場所で異なるスコープを追加する必要は必ずしもありません。\n\nここでは、**FastAPI** が異なるレベルで宣言されたスコープをどのように扱うかを示すためにそうしています。\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | 技術詳細\n\n`Security` は実際には `Depends` のサブクラスで、後述する追加パラメータが 1 つあるだけです。\n\nしかし `Depends` の代わりに `Security` を使うことで、**FastAPI** はセキュリティスコープを宣言・内部利用でき、OpenAPI で API をドキュメント化できると判断します。\n\nなお、`fastapi` から `Query`、`Path`、`Depends`、`Security` などをインポートする際、それらは実際には特殊なクラスを返す関数です。\n\n///\n\n## `SecurityScopes` を使う { #use-securityscopes }\n\n次に、依存関数 `get_current_user` を更新します。\n\nこれは上記の依存関係から使用されます。\n\nここで、先ほど作成した同じ OAuth2 スキームを依存関係（`oauth2_scheme`）として宣言して使います。\n\nこの依存関数自体はスコープ要件を持たないため、`oauth2_scheme` には `Depends` を使えます。セキュリティスコープを指定する必要がない場合は `Security` を使う必要はありません。\n\nさらに、`fastapi.security` からインポートする特別な型 `SecurityScopes` のパラメータを宣言します。\n\nこの `SecurityScopes` クラスは `Request` に似ています（`Request` はリクエストオブジェクトを直接取得するために使いました）。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## `scopes` を使う { #use-the-scopes }\n\nパラメータ `security_scopes` は `SecurityScopes` 型になります。\n\nこのオブジェクトは、自身およびこれをサブ依存として使うすべての依存関係で要求されるスコープを含む `scopes` プロパティ（リスト）を持ちます。つまり、すべての「依存元」... 少し分かりにくいかもしれませんが、後で再度説明します。\n\n`security_scopes`（`SecurityScopes` クラスのインスタンス）は、要求されたスコープを空白で連結した 1 つの文字列を返す `scope_str` も提供します（これを使います）。\n\n後で複数箇所で再利用（raise）できるように、`HTTPException` を 1 つ作成します。\n\nこの例外には、要求されたスコープがあればそれらを空白区切りの文字列（`scope_str` を使用）として含めます。このスコープ文字列は `WWW-Authenticate` ヘッダに入れます（仕様の一部です）。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## `username` とデータ構造の検証 { #verify-the-username-and-data-shape }\n\n`username` を取得できていることを確認し、スコープを取り出します。\n\nそして、そのデータを Pydantic モデルで検証します（`ValidationError` 例外を捕捉）。JWT トークンの読み取りや Pydantic によるデータ検証でエラーが発生した場合は、先ほど作成した `HTTPException` を送出します。\n\nそのために、Pydantic モデル `TokenData` に新しいプロパティ `scopes` を追加します。\n\nPydantic でデータを検証することで、例えばスコープは `str` の `list`、`username` は `str` といった、正確な型になっていることを保証できます。\n\nそうしておけば、例えば誤って `dict` などが入って後でアプリケーションを破壊してしまい、セキュリティリスクになる、といった事態を避けられます。\n\nまた、その `username` を持つユーザーが存在することも確認し、存在しなければ、やはり先ほどの例外を送出します。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## `scopes` の検証 { #verify-the-scopes }\n\nこの依存関数およびすべての依存元（path operation を含む）が要求するすべてのスコープが、受け取ったトークンに含まれていることを検証し、含まれていなければ `HTTPException` を送出します。\n\nそのために、これらすべてのスコープを `str` の `list` として含む `security_scopes.scopes` を使います。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## 依存関係ツリーとスコープ { #dependency-tree-and-scopes }\n\n依存関係ツリーとスコープをもう一度見てみましょう。\n\n`get_current_active_user` 依存関係は `get_current_user` をサブ依存として持つため、`get_current_active_user` で宣言された `\"me\"` スコープは、`get_current_user` に渡される `security_scopes.scopes` の必須スコープ一覧に含まれます。\n\npath operation 自体も `\"items\"` スコープを宣言するため、これも `get_current_user` に渡される `security_scopes.scopes` に含まれます。\n\n依存関係とスコープの階層は次のようになります:\n\n- *path operation* `read_own_items` には:\n    - 依存関係に対して必須スコープ `[\"items\"]` がある:\n    - `get_current_active_user`:\n        - 依存関数 `get_current_active_user` には:\n            - 依存関係に対して必須スコープ `[\"me\"]` がある:\n            - `get_current_user`:\n                - 依存関数 `get_current_user` には:\n                    - 自身に必須スコープはない。\n                    - `oauth2_scheme` を使う依存関係がある。\n                    - `SecurityScopes` 型の `security_scopes` パラメータがある:\n                        - この `security_scopes` パラメータは、上で宣言されたすべてのスコープを含む `list` を持つ `scopes` プロパティを持つ。したがって:\n                            - *path operation* `read_own_items` では、`security_scopes.scopes` は `[\"me\", \"items\"]` を含む。\n                            - *path operation* `read_users_me` では、`security_scopes.scopes` は `[\"me\"]` を含む。これは依存関係 `get_current_active_user` に宣言されているため。\n                            - *path operation* `read_system_status` では、`security_scopes.scopes` は `[]`（空）になる。`scopes` を持つ `Security` を宣言しておらず、その依存関係 `get_current_user` も `scopes` を宣言していないため。\n\n/// tip | 豆知識\n\n重要で「魔法のよう」な点は、`get_current_user` が path operation ごとに異なる `scopes` のリストをチェックすることになる、ということです。\n\nそれは、それぞれの path operation と、その path operation の依存関係ツリー内の各依存関係で宣言された `scopes` によって決まります。\n\n///\n\n## `SecurityScopes` の詳細 { #more-details-about-securityscopes }\n\n`SecurityScopes` はどの地点でも、複数箇所でも使えます。「ルート」の依存関係である必要はありません。\n\n常に、その時点の `Security` 依存関係と、**その特定の** path operation と **その特定の** 依存関係ツリーにおける、すべての依存元で宣言されたセキュリティスコープを持ちます。\n\n`SecurityScopes` には依存元で宣言されたすべてのスコープが入るため、トークンが必要なスコープを持っているかどうかを中央の依存関数で検証し、path operation ごとに異なるスコープ要件を宣言する、といった使い方ができます。\n\nこれらは path operation ごとに独立して検証されます。\n\n## チェック { #check-it }\n\nAPI ドキュメントを開くと、認証して、許可するスコープを指定できます。\n\n<img src=\"/img/tutorial/security/image11.png\">\n\nどのスコープも選択しない場合は「認証済み」にはなりますが、`/users/me/` や `/users/me/items/` にアクセスしようとすると、権限が不足しているというエラーになります。`/status/` には引き続きアクセスできます。\n\n`me` スコープだけを選択し、`items` スコープを選択しない場合は、`/users/me/` にはアクセスできますが、`/users/me/items/` にはアクセスできません。\n\nこれは、ユーザーがアプリケーションに与えた権限の範囲に応じて、サードパーティアプリケーションがこれらの path operation のいずれかに、ユーザーから提供されたトークンでアクセスしようとしたときに起こる動作です。\n\n## サードパーティ統合について { #about-third-party-integrations }\n\nこの例では、OAuth2 の「password」フローを使用しています。\n\nこれは、（おそらく自前のフロントエンドで）自分たちのアプリケーションにログインする場合に適しています。\n\n自分たちで管理しているため、`username` と `password` を受け取る相手を信頼できるからです。\n\nしかし、他者が接続する OAuth2 アプリケーション（Facebook、Google、GitHub などに相当する認証プロバイダ）を構築する場合は、他のいずれかのフローを使用すべきです。\n\n最も一般的なのは implicit フローです。\n\n最も安全なのは code フローですが、手順が多く実装がより複雑です。複雑なため、多くのプロバイダは結局 implicit フローを推奨することがあります。\n\n/// note | 備考\n\n各認証プロバイダがフローに独自の名称を付け、自社のブランドの一部にするのは一般的です。\n\nしかし、最終的には同じ OAuth2 標準を実装しています。\n\n///\n\n**FastAPI** には、これらすべての OAuth2 認証フロー向けのユーティリティが `fastapi.security.oauth2` に含まれています。\n\n## デコレータ `dependencies` での `Security` { #security-in-decorator-dependencies }\n\nデコレータの `dependencies` パラメータに `Depends` の `list` を定義できるのと同様（[path operation デコレータでの依存関係](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md) 参照）、ここで `scopes` を指定した `Security` も使用できます。\n"
  },
  {
    "path": "docs/ja/docs/advanced/settings.md",
    "content": "# 設定と環境変数 { #settings-and-environment-variables }\n\n多くの場合、アプリケーションは外部の設定や構成を必要とします。たとえば、シークレットキー、データベース認証情報、メールサービスの認証情報などです。\n\nこれらの設定の多くは可変（変更されうる）で、データベースのURLのようなものがあります。また、多くはシークレットのように機微な情報です。\n\nそのため、アプリケーションが読み取る環境変数で提供するのが一般的です。\n\n/// tip | 豆知識\n\n環境変数について理解するには、[環境変数](../environment-variables.md)を参照してください。\n\n///\n\n## 型とバリデーション { #types-and-validation }\n\nこれらの環境変数は Python の外部にあり、他のプログラムやシステム全体（Linux、Windows、macOS といった異なるOSを含む）と互換性が必要なため、文字列テキストのみを扱えます。\n\nつまり、Python で環境変数から読み取られる値はすべて `str` になり、他の型への変換やバリデーションはコードで行う必要があります。\n\n## Pydantic の `Settings` { #pydantic-settings }\n\n幸いなことに、Pydantic には環境変数から来る設定を扱うための優れたユーティリティがあり、[Pydantic: Settings management](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) で提供されています。\n\n### `pydantic-settings` のインストール { #install-pydantic-settings }\n\nまず、[仮想環境](../virtual-environments.md)を作成して有効化し、`pydantic-settings` パッケージをインストールします:\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\nまた、次のように `all` エクストラをインストールすると付属します:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### `Settings` オブジェクトを作成 { #create-the-settings-object }\n\nPydantic から `BaseSettings` をインポートして、そのサブクラスを作成します。これは Pydantic モデルとほぼ同じです。\n\nPydantic モデルと同様に、型アノテーションと（必要なら）デフォルト値を持つクラス属性を宣言します。\n\n`Field()` による追加バリデーションなど、Pydantic モデルで使えるのと同じバリデーション機能をすべて利用できます。\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip | 豆知識\n\nコピペ用に手早く使いたい場合は、この例ではなく、下の最後の例を使ってください。\n\n///\n\nその後、その `Settings` クラスのインスタンス（この例では `settings` オブジェクト）を作成すると、Pydantic は環境変数を大文字小文字を区別せずに読み取ります。つまり、大文字の `APP_NAME` という変数は、属性 `app_name` に対しても読み取られます。\n\n次に、データが変換・バリデーションされます。したがって、`settings` オブジェクトを使うと、宣言した型のデータ（例: `items_per_user` は `int`）が得られます。\n\n### `settings` の使用 { #use-the-settings }\n\n次に、アプリケーションで新しい `settings` オブジェクトを使用できます:\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### サーバーを実行 { #run-the-server }\n\n次に、設定を環境変数として渡してサーバーを実行します。たとえば、`ADMIN_EMAIL` と `APP_NAME` を次のように設定できます:\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip | 豆知識\n\n1つのコマンドに複数の環境変数を設定するには、スペースで区切ってコマンドの前に並べます。\n\n///\n\nすると、`admin_email` の設定は `\"deadpool@example.com\"` に設定されます。\n\n`app_name` は `\"ChimichangApp\"` になります。\n\n`items_per_user` はデフォルト値の `50` のままです。\n\n## 別モジュールでの設定 { #settings-in-another-module }\n\n[大規模アプリケーション - 複数ファイル](../tutorial/bigger-applications.md) で見たように、これらの設定を別のモジュールファイルに置くこともできます。\n\nたとえば、`config.py` というファイルに次のように書けます:\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\nそして、`main.py` というファイルでそれを使います:\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip | 豆知識\n\n[大規模アプリケーション - 複数ファイル](../tutorial/bigger-applications.md) で見たように、`__init__.py` ファイルも必要です。\n\n///\n\n## 依存関係での設定 { #settings-in-a-dependency }\n\n場合によっては、どこでも使うグローバルな `settings` オブジェクトを持つ代わりに、依存関係から設定を提供すると便利なことがあります。\n\nこれは特にテスト時に有用で、依存関係を独自のカスタム設定で簡単にオーバーライドできるからです。\n\n### 設定ファイル { #the-config-file }\n\n前の例から続けると、`config.py` ファイルは次のようになります:\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\nここでは、デフォルトのインスタンス `settings = Settings()` を作成していないことに注意してください。\n\n### メインアプリファイル { #the-main-app-file }\n\nここでは、新しい `config.Settings()` を返す依存関係を作成します。\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip | 豆知識\n\n`@lru_cache` については後で説明します。\n\n今は `get_settings()` が普通の関数だと考えてください。\n\n///\n\nそして、*path operation 関数*から依存関係として要求し、必要な場所でどこでも使えます。\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### 設定とテスト { #settings-and-testing }\n\n次に、`get_settings` の依存関係オーバーライドを作ることで、テスト中に別の設定オブジェクトを提供するのがとても簡単になります:\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\n依存関係オーバーライドでは、新しい `Settings` オブジェクトを作る際に `admin_email` に新しい値を設定し、その新しいオブジェクトを返します。\n\nそして、それが使用されていることをテストできます。\n\n## `.env` ファイルの読み込み { #reading-a-env-file }\n\n変更が多くなりそうな設定が多数ある場合、環境ごとにファイルに入れて、環境変数としてそこから読み込むと便利なことがあります。\n\nこのプラクティスは十分に一般的で名前もあり、これらの環境変数は通常 `.env` というファイルに置かれ、そのファイルは「dotenv」と呼ばれます。\n\n/// tip | 豆知識\n\nドット（`.`）で始まるファイルは、Linux や macOS のような Unix 系システムでは隠しファイルです。\n\nただし、dotenv ファイルは必ずしもその正確なファイル名である必要はありません。\n\n///\n\nPydantic は外部ライブラリを使ってこの種のファイルからの読み込みをサポートしています。詳細は [Pydantic Settings: Dotenv (.env) support](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support) を参照してください。\n\n/// tip | 豆知識\n\nこれを機能させるには、`pip install python-dotenv` が必要です。\n\n///\n\n### `.env` ファイル { #the-env-file }\n\n次のような `.env` ファイルを用意できます:\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### `.env` から設定を読む { #read-settings-from-env }\n\nそして、`config.py` を次のように更新します:\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip | 豆知識\n\n`model_config` 属性は Pydantic の設定専用です。詳しくは [Pydantic: Concepts: Configuration](https://docs.pydantic.dev/latest/concepts/config/) を参照してください。\n\n///\n\nここでは、Pydantic の `Settings` クラス内で設定 `env_file` を定義し、使用したい dotenv ファイルのファイル名を指定しています。\n\n### `lru_cache` で `Settings` を一度だけ作成 { #creating-the-settings-only-once-with-lru-cache }\n\nディスクからファイルを読むのは通常コスト（遅延）が高い処理なので、1回だけ実行して同じ設定オブジェクトを再利用し、各リクエストごとに読み直さないのが望ましいです。\n\nしかし、次のようにするたびに:\n\n```Python\nSettings()\n```\n\n新しい `Settings` オブジェクトが作成され、その作成時に `.env` ファイルが再度読み込まれます。\n\n依存関数が次のようであれば:\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\n各リクエストごとにそのオブジェクトを作成し、各リクエストごとに `.env` ファイルを読み込むことになります。⚠️\n\nしかし、上に `@lru_cache` デコレータを使っているので、`Settings` オブジェクトは最初に呼び出されたときに一度だけ作成されます。✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\nその後のリクエスト用の依存関係で `get_settings()` が呼ばれるたびに、`get_settings()` の内部コードを実行して新しい `Settings` オブジェクトを作るのではなく、最初の呼び出しで返されたのと同じオブジェクトを何度でも返します。\n\n#### `lru_cache` の技術詳細 { #lru-cache-technical-details }\n\n`@lru_cache` は、毎回関数のコードを実行して再計算するのではなく、最初に返した値を返すように、修飾する関数を変更します。\n\nしたがって、その下の関数は引数の組み合わせごとに一度だけ実行されます。そして、その各引数の組み合わせで返された値は、まったく同じ引数の組み合わせで呼び出されたときに何度でも再利用されます。\n\nたとえば、次のような関数があるとします:\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\nプログラムは次のように実行されます:\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Execute function\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n```\n\n今回の依存関数 `get_settings()` の場合、関数は引数を一切取りません。そのため、常に同じ値を返します。\n\nこの方法は、ほとんどグローバル変数のように振る舞います。しかし、依存関数を使っているので、テストのために簡単にオーバーライドできます。\n\n`@lru_cache` は Python 標準ライブラリの `functools` の一部です。詳細は [Python の `@lru_cache` ドキュメント](https://docs.python.org/3/library/functools.html#functools.lru_cache)を参照してください。\n\n## まとめ { #recap }\n\nPydantic Settings を使うことで、アプリケーションの設定や構成を、Pydantic モデルの力を活かして扱えます。\n\n* 依存関係を使うことで、テストを簡素化できます。\n* `.env` ファイルを利用できます。\n* `@lru_cache` を使うと、各リクエストごとに dotenv ファイルを繰り返し読み込むのを避けつつ、テスト時にはオーバーライドできます。\n"
  },
  {
    "path": "docs/ja/docs/advanced/stream-data.md",
    "content": "# データのストリーミング { #stream-data }\n\nJSON として構造化できるデータをストリームしたい場合は、[JSON Lines をストリームする](../tutorial/stream-json-lines.md) を参照してください。\n\nしかし、純粋なバイナリデータや文字列をストリームしたい場合は、次のようにできます。\n\n/// info | 情報\n\nFastAPI 0.134.0 で追加されました。\n\n///\n\n## ユースケース { #use-cases }\n\n例えば、AI LLM サービスの出力をそのまま、純粋な文字列としてストリームしたい場合に使えます。\n\nメモリに一度に全て読み込むことなく、読み込みながらチャンクごとに送ることで、巨大なバイナリファイルをストリームすることにも使えます。\n\n同様に、動画や音声をストリームすることもできます。処理しながら生成し、そのまま送信することも可能です。\n\n## `yield` を使った `StreamingResponse` { #a-streamingresponse-with-yield }\n\npath operation 関数で `response_class=StreamingResponse` を宣言すると、`yield` を使ってデータをチャンクごとに順次送信できます。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI は各データチャンクをそのまま `StreamingResponse` に渡し、JSON などに変換しようとはしません。\n\n### 非 async な path operation 関数 { #non-async-path-operation-functions }\n\n`async` なしの通常の `def` 関数でも同様に `yield` を使えます。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### アノテーションなし { #no-annotation }\n\nバイナリデータをストリームする場合、戻り値の型アノテーションを宣言する必要は実際にはありません。\n\nこの場合、FastAPI はデータを Pydantic で JSON 化したり、何らかの方法でシリアライズしようとしないため、型アノテーションはエディタやツール向けの補助にすぎず、FastAPI 自体では使用されません。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\nつまり、`StreamingResponse` では型アノテーションに依存せず、送信したい形式に合わせてバイト列を生成・エンコードする「自由」と「責任」があなたにあります。 🤓\n\n### バイト列をストリームする { #stream-bytes }\n\n主なユースケースの一つは、文字列ではなく `bytes` をストリームすることです。もちろん可能です。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## カスタム `PNGStreamingResponse` { #a-custom-pngstreamingresponse }\n\n上記の例ではバイト列をストリームしましたが、レスポンスに `Content-Type` ヘッダがないため、クライアントは受け取るデータの種類を認識できませんでした。\n\n`StreamingResponse` を継承したカスタムクラスを作成し、ストリームするデータに応じて `Content-Type` ヘッダを設定できます。\n\n例えば、`media_type` 属性で `Content-Type` を `image/png` に設定する `PNGStreamingResponse` を作成できます:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\nその後、path operation 関数で `response_class=PNGStreamingResponse` としてこの新しいクラスを使用できます:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### ファイルを模擬する { #simulate-a-file }\n\nこの例では `io.BytesIO` でファイルを模擬しています。これはメモリ上だけに存在するファイルライクオブジェクトですが、通常のファイルと同じインターフェースを提供します。\n\n例えば、ファイルと同様にイテレートして内容を読み出せます。\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | 技術詳細\n\n他の2つの変数 `image_base64` と `binary_image` は、画像を Base64 でエンコードし、それを `bytes` に変換してから `io.BytesIO` に渡したものです。\n\nこの例では1つのファイル内に完結させ、コピーしてそのまま実行できるようにするためだけのものです。 🥚\n\n///\n\n`with` ブロックを使うことで、ジェネレータ関数（`yield` を持つ関数）が終了した後、つまりレスポンス送信が完了した後に、そのファイルライクオブジェクトが確実にクローズされます。\n\nこの例では `io.BytesIO` によるメモリ内の疑似ファイルなので重要度は高くありませんが、実ファイルの場合は処理後に確実にクローズすることが重要です。\n\n### ファイルと非同期 { #files-and-async }\n\n多くの場合、ファイルライクオブジェクトはデフォルトでは async/await と互換性がありません。\n\n例えば、`await file.read()` や `async for chunk in file` のような操作は提供されていません。\n\nまた、多くの場合、ディスクやネットワークから読み出すため、読み取りはブロッキング（イベントループをブロックし得る）処理になります。\n\n/// info | 情報\n\n上記の例は例外で、`io.BytesIO` は既にメモリ上にあるため、読み取りが何かをブロックすることはありません。\n\nしかし多くの場合、ファイルやファイルライクオブジェクトの読み取りはブロッキングになります。\n\n///\n\nイベントループのブロッキングを避けるには、path operation 関数を `async def` ではなく通常の `def` で宣言してください。そうすると FastAPI はその関数をスレッドプールワーカー上で実行し、メインループのブロッキングを避けます。\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip | 豆知識\n\nasync 関数内からブロッキングなコードを呼び出す必要がある場合、あるいはブロッキングな関数内から async 関数を呼び出す必要がある場合は、FastAPI の兄弟ライブラリである [Asyncer](https://asyncer.tiangolo.com) を利用できます。\n\n///\n\n### `yield from` { #yield-from }\n\nファイルライクオブジェクトのようなものをイテレートして各要素に対して `yield` している場合、`for` ループを省略して、`yield from` で各要素をそのまま送ることもできます。\n\nこれは FastAPI 固有ではなく単なる Python の機能ですが、知っておくと便利な小ワザです。 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/ja/docs/advanced/strict-content-type.md",
    "content": "# Content-Type の厳格チェック { #strict-content-type-checking }\n\n既定では、FastAPI は JSON リクエストボディに対して厳格な `Content-Type` ヘッダーのチェックを行います。つまり、JSON のリクエストを JSON として解析するには、有効な `Content-Type` ヘッダー（例: `application/json`）を必ず含める必要があります。\n\n## CSRF のリスク { #csrf-risk }\n\nこの既定の挙動は、ある特定の状況における Cross-Site Request Forgery（CSRF）攻撃の一種に対する保護を提供します。\n\nこれらの攻撃は、次の条件を満たすときにブラウザが CORS のプリフライトチェックを行わずにスクリプトからリクエストを送信できる事実を悪用します。\n\n- `Content-Type` ヘッダーがない（例: `Blob` をボディにして `fetch()` を使う）\n- かつ、いかなる認証情報も送信しない\n\nこの種の攻撃は主に次のような場合に関係します。\n\n- アプリケーションがローカル（例: `localhost`）または社内ネットワークで動作している\n- かつ、アプリに認証がなく、同一ネットワークからのリクエストは信頼できると想定している\n\n## 攻撃例 { #example-attack }\n\nローカルで AI エージェントを実行できる仕組みを構築したとします。\n\nそれは次の API を提供します。\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nフロントエンドもあります。\n\n```\nhttp://localhost:8000\n```\n\n/// tip | 豆知識\n\n両方とも同じホストであることに注意してください。\n\n///\n\nそのフロントエンドを使って、AI エージェントに自分の代わりに作業をさせられます。\n\nそれが「公開インターネット」ではなくローカルで動作しているため、ローカルネットワークへのアクセスを信頼し、認証を一切設定しないことにしたとします。\n\nすると、ユーザーの一人がそれをインストールしてローカルで実行できます。\n\nその後、例えば次のような悪意のあるサイトを開く可能性があります。\n\n```\nhttps://evilhackers.example.com\n```\n\nそしてその悪意のあるサイトが、`Blob` をボディにした `fetch()` を使ってローカルの API にリクエストを送信します。\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\n悪意のあるサイトとローカルアプリのホストは異なるにもかかわらず、ブラウザは次の理由で CORS のプリフライトリクエストを発行しません。\n\n- 認証なしで動作しており、認証情報を送る必要がないため\n- ブラウザは（`Content-Type` ヘッダーがないため）JSON を送っていないと判断するため\n\nその結果、悪意のあるサイトがローカルの AI エージェントに、ユーザーの元上司に怒りのメッセージを送らせることができてしまいます... あるいは、もっと悪いことも。 😅\n\n## 公開インターネット { #open-internet }\n\nアプリが公開インターネット上にある場合、「ネットワークを信頼」して認証なしで誰にでも特権的なリクエストを送らせることはしないはずです。\n\n攻撃者は単にスクリプトを実行して API にリクエストを送れます。ブラウザを介する必要がないため、すでに特権エンドポイントは保護しているでしょう。\n\nその場合、これはあなたには当てはまらない攻撃／リスクです。\n\nこのリスクと攻撃が主に問題になるのは、アプリがローカルネットワークで動作し、それだけが前提の保護となっている場合です。\n\n## Content-Type なしのリクエストを許可する { #allowing-requests-without-content-type }\n\n`Content-Type` ヘッダーを送らないクライアントをサポートする必要がある場合は、`strict_content_type=False` を設定して厳格チェックを無効化できます。\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\nこの設定では、`Content-Type` ヘッダーがないリクエストでもボディが JSON として解析されます。これは古いバージョンの FastAPI と同じ挙動です。\n\n/// info | 情報\n\nこの挙動と設定は FastAPI 0.132.0 で追加されました。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/advanced/sub-applications.md",
    "content": "# サブアプリケーション - マウント { #sub-applications-mounts }\n\nそれぞれ独立した OpenAPI とドキュメント UI を持つ2つの独立した FastAPI アプリケーションが必要な場合、メインアプリに1つ（以上）のサブアプリケーションを「マウント」できます。\n\n## FastAPI アプリケーションのマウント { #mounting-a-fastapi-application }\n\n「マウント」とは、特定のパスに完全に「独立した」アプリケーションを追加し、そのサブアプリケーションで宣言された path operation によって、そのパス以下のすべてを処理させることを意味します。\n\n### トップレベルアプリケーション { #top-level-application }\n\nまず、メインのトップレベル **FastAPI** アプリケーションと、その path operation を作成します:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### サブアプリケーション { #sub-application }\n\n次に、サブアプリケーションとその path operation を作成します。\n\nこのサブアプリケーションは通常の FastAPI アプリケーションですが、これを「マウント」します:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### サブアプリケーションをマウント { #mount-the-sub-application }\n\nトップレベルのアプリケーション `app` に、サブアプリケーション `subapi` をマウントします。\n\nこの例では、パス `/subapi` にマウントされます:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### 自動 API ドキュメントの確認 { #check-the-automatic-api-docs }\n\nでは、`fastapi` コマンドを実行します:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nそして、[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) を開きます。\n\nメインアプリ用の自動 API ドキュメントが表示され、そのアプリ自身の path operation のみが含まれます:\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\n次に、サブアプリケーションのドキュメント [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs) を開きます。\n\nサブアプリケーション用の自動 API ドキュメントが表示され、そのアプリ自身の path operation のみが、正しいサブパス接頭辞 `/subapi` の下で表示されます:\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\nどちらの UI でも操作すれば正しく動作します。ブラウザがそれぞれのアプリ／サブアプリと通信できるためです。\n\n### 技術詳細: `root_path` { #technical-details-root-path }\n\n上記のようにサブアプリケーションをマウントすると、FastAPI は ASGI 仕様の `root_path` と呼ばれる仕組みを使って、そのサブアプリケーションへのマウントパスを伝播します。\n\nこのため、サブアプリケーションはドキュメント UI でそのパス接頭辞を使用すべきことを認識できます。\n\nさらに、サブアプリケーション自身が別のサブアプリケーションをマウントしていても問題ありません。FastAPI がこれらの `root_path` をすべて自動的に処理するためです。\n\n`root_path` の詳細や明示的な指定方法については、[プロキシの背後で](behind-a-proxy.md) の節で学べます。\n"
  },
  {
    "path": "docs/ja/docs/advanced/templates.md",
    "content": "# テンプレート { #templates }\n\n**FastAPI** では任意のテンプレートエンジンを使用できます。\n\nFlask などでも使われている Jinja2 が一般的な選択肢です。\n\nStarlette によって提供され、**FastAPI** アプリで直接使える、簡単に設定できるユーティリティがあります。\n\n## 依存関係のインストール { #install-dependencies }\n\n[仮想環境](../virtual-environments.md) を作成して有効化し、`jinja2` をインストールします:\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## `Jinja2Templates` の使用 { #using-jinja2templates }\n\n* `Jinja2Templates` をインポートします。\n* 後で再利用できる `templates` オブジェクトを作成します。\n* テンプレートを返す path operation に `Request` パラメータを宣言します。\n* 作成した `templates` を使って `TemplateResponse` をレンダリングして返します。テンプレート名、リクエストオブジェクト、Jinja2 テンプレート内で使用するキーと値のペアからなる \"context\" の辞書を渡します。\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note | 備考\n\nFastAPI 0.108.0、Starlette 0.29.0 以前では、`name` は最初のパラメータでした。\n\nまたそれ以前のバージョンでは、`request` オブジェクトは Jinja2 用のコンテキスト内のキーと値のペアの一部として渡されていました。\n\n///\n\n/// tip | 豆知識\n\n`response_class=HTMLResponse` を宣言すると、ドキュメント UI がレスポンスが HTML であることを認識できます。\n\n///\n\n/// note | 技術詳細\n\n`from starlette.templating import Jinja2Templates` を使うこともできます。\n\n**FastAPI** は、開発者であるあなたの利便性のために、`starlette.templating` と同じものを `fastapi.templating` として提供しています。しかし、利用可能なレスポンスのほとんどは Starlette から直接提供されています。`Request` や `StaticFiles` も同様です。\n\n///\n\n## テンプレートの作成 { #writing-templates }\n\n例えば、`templates/item.html` に次のようなテンプレートを書きます:\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### テンプレートのコンテキスト値 { #template-context-values }\n\n次のような HTML 内で:\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n...渡した \"context\" の `dict` から取得した `id` が表示されます:\n\n```Python\n{\"id\": id}\n```\n\n例えば、ID が `42` の場合は次のようにレンダリングされます:\n\n```html\nItem ID: 42\n```\n\n### テンプレートの `url_for` の引数 { #template-url-for-arguments }\n\nテンプレート内でも `url_for()` を使用できます。引数には、対応する path operation 関数で使われるのと同じ引数を取ります。\n\nしたがって、次の部分は:\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n...path operation 関数 `read_item(id=id)` が処理するのと同じ URL へのリンクを生成します。\n\n例えば、ID が `42` の場合は次のようにレンダリングされます:\n\n```html\n<a href=\"/items/42\">\n```\n\n## テンプレートと静的ファイル { #templates-and-static-files }\n\nテンプレート内で `url_for()` を使用し、例えば `name=\"static\"` でマウントした `StaticFiles` に対して利用できます。\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\nこの例では、`static/styles.css` の CSS ファイルにリンクします:\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\nまた、`StaticFiles` を使用しているため、その CSS ファイルは **FastAPI** アプリケーションから URL `/static/styles.css` で自動的に配信されます。\n\n## さらに詳しく { #more-details }\n\nより詳しい内容（テンプレートのテスト方法など）については、[Starlette のテンプレートに関するドキュメント](https://www.starlette.dev/templates/)を参照してください。\n"
  },
  {
    "path": "docs/ja/docs/advanced/testing-dependencies.md",
    "content": "# 依存関係のオーバーライドによるテスト { #testing-dependencies-with-overrides }\n\n## テスト時の依存関係のオーバーライド { #overriding-dependencies-during-testing }\n\nテスト中に依存関係をオーバーライドしたい場面がいくつかあります。\n\n元の依存関係（およびそれにぶら下がるサブ依存関係）を実行したくない場合です。\n\n代わりに、テストの間だけ（特定のテストだけでも）使われる別の依存関係を提供し、元の依存関係の値が使われていた箇所で利用できる値を返したいのです。\n\n### ユースケース: 外部サービス { #use-cases-external-service }\n\n例として、呼び出す必要がある外部の認証プロバイダがあるとします。\n\nトークンを送ると、認証済みユーザーが返ってきます。\n\nこのプロバイダはリクエストごとに課金されるかもしれず、テスト用に固定のモックユーザーを使う場合に比べて呼び出しに余分な時間がかかるかもしれません。\n\n外部プロバイダ自体の動作は一度はテストしたいでしょうが、実行されるすべてのテストで毎回呼び出す必要はありません。\n\nこの場合、そのプロバイダを呼び出す依存関係をオーバーライドし、テストのときだけモックユーザーを返すカスタムの依存関係を使えます。\n\n### app.dependency_overrides 属性を使う { #use-the-app-dependency-overrides-attribute }\n\nこのような場合のために、**FastAPI** アプリケーションには `app.dependency_overrides` という属性があり、これは単純な `dict` です。\n\nテスト用に依存関係をオーバーライドするには、キーに元の依存関係（関数）を、値にオーバーライドする依存関係（別の関数）を設定します。\n\nすると **FastAPI** は元の依存関係の代わりにそのオーバーライドを呼び出します。\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip | 豆知識\n\nアプリケーション内のどこで使われている依存関係に対しても、依存関係のオーバーライドを設定できます。\n\n元の依存関係は、*path operation 関数*、*path operation デコレータ*（戻り値を使わない場合）、`.include_router()` の呼び出しなど、さまざまな場所で使われていてもかまいません。\n\nFastAPI はそれでもオーバーライドできます。\n\n///\n\nその後、`app.dependency_overrides` を空の `dict` に設定することで、オーバーライドをリセット（削除）できます:\n\n```Python\napp.dependency_overrides = {}\n```\n\n/// tip | 豆知識\n\n一部のテストの間だけ依存関係をオーバーライドしたい場合は、テストの開始時（テスト関数内）にオーバーライドを設定し、終了時（テスト関数の末尾）にリセットするとよいです。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/advanced/testing-events.md",
    "content": "# イベントのテスト: lifespan と startup - shutdown { #testing-events-lifespan-and-startup-shutdown }\n\nテストで `lifespan` を実行する必要がある場合は、`with` 文と併用して `TestClient` を使用できます:\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\nより詳しい内容は、[公式 Starlette ドキュメントの「テストでの lifespan の実行」](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) を参照してください。\n\n非推奨の `startup` および `shutdown` イベントについては、次のように `TestClient` を使用できます:\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/ja/docs/advanced/testing-websockets.md",
    "content": "# WebSocket のテスト { #testing-websockets }\n\nWebSocket をテストするのにも同じ `TestClient` を使用できます。\n\nそのために、`with` 文の中で `TestClient` を使用し、WebSocket に接続します:\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note | 備考\n\n詳細については、Starlette のドキュメント「[WebSocket のテスト](https://www.starlette.dev/testclient/#testing-websocket-sessions)」を参照してください。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/advanced/using-request-directly.md",
    "content": "# Request を直接使う { #using-the-request-directly }\n\nこれまで、必要なリクエストの各部分を、その型とともに宣言してきました。\n\n次の場所からデータを取得します:\n\n- パスのパラメータ\n- ヘッダー\n- クッキー\n- など\n\nこうすることで、**FastAPI** はそのデータを検証し、変換し、API のドキュメントを自動生成します。\n\nしかし、`Request` オブジェクトに直接アクセスする必要がある場面もあります。\n\n## `Request` オブジェクトの詳細 { #details-about-the-request-object }\n\n**FastAPI** は内部的には **Starlette** の上にいくつかのツール層を載せたものなので、必要に応じて Starlette の [`Request`](https://www.starlette.dev/requests/) オブジェクトを直接使えます。\n\nまた、`Request` オブジェクトから直接データ（例: ボディ）を取得する場合、そのデータは FastAPI によって検証・変換・ドキュメント化（OpenAPI による自動 API ユーザーインターフェース向け）されません。\n\nただし、通常どおりに宣言された他のパラメータ（例: Pydantic モデルのボディ）は引き続き検証・変換・注釈付けなどが行われます。\n\nそれでも、`Request` オブジェクトを取得するのが有用な特定のケースがあります。\n\n## `Request` オブジェクトを直接使う { #use-the-request-object-directly }\n\nたとえば、path operation 関数内でクライアントの IP アドレス／ホストを取得したいとします。\n\nそのためには、リクエストに直接アクセスする必要があります。\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\npath operation 関数の引数として `Request` 型のパラメータを宣言すると、**FastAPI** はその引数に `Request` を渡します。\n\n/// tip | 豆知識\n\nこの例では、`Request` 型の引数に加えて、パスパラメータも宣言しています。\n\nそのため、パスパラメータは取り出され、検証され、指定した型に変換され、OpenAPI で注釈（ドキュメント化）されます。\n\n同様に、通常どおり任意の他のパラメータを宣言しつつ、追加で `Request` も受け取れます。\n\n///\n\n## `Request` のドキュメント { #request-documentation }\n\nより詳しくは、[公式 Starlette ドキュメントサイトの `Request` オブジェクト](https://www.starlette.dev/requests/)を参照してください。\n\n/// note | 技術詳細\n\n`from starlette.requests import Request` を使うこともできます。\n\n**FastAPI** は開発者である皆さんの便宜のために直接提供していますが、これは Starlette からそのまま提供されているものです。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\n**FastAPI**で[WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)が使用できます。\n\n## `websockets`のインストール { #install-websockets }\n\n[仮想環境](../virtual-environments.md)を作成し、それを有効化してから、「WebSocket」プロトコルを簡単に使えるようにするPythonライブラリの`websockets`をインストールしてください。\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## WebSockets クライアント { #websockets-client }\n\n### 本番環境 { #in-production }\n\n本番環境では、React、Vue.js、Angularなどの最新のフレームワークで作成されたフロントエンドを使用しているでしょう。\n\nそして、バックエンドとWebSocketsを使用して通信するために、おそらくフロントエンドのユーティリティを使用することになるでしょう。\n\nまたは、ネイティブコードでWebSocketバックエンドと直接通信するネイティブモバイルアプリケーションがあるかもしれません。\n\n他にも、WebSocketのエンドポイントと通信する方法があるかもしれません。\n\n---\n\nただし、この例では非常にシンプルなHTML文書といくつかのJavaScriptを、すべて長い文字列の中に入れて使用することにします。\n\nもちろん、これは最適な方法ではありませんし、本番環境で使うことはないでしょう。\n\n本番環境では、上記の方法のいずれかの選択肢を採用することになるでしょう。\n\nしかし、これはWebSocketsのサーバーサイドに焦点を当て、動作する例を示す最も簡単な方法です。\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## `websocket` を作成する { #create-a-websocket }\n\n**FastAPI** アプリケーションで、`websocket` を作成します。\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | 技術詳細\n\n`from starlette.websockets import WebSocket` を使用しても構いません.\n\n**FastAPI** は開発者の利便性のために、同じ `WebSocket` を提供します。しかし、こちらはStarletteから直接提供されるものです。\n\n///\n\n## メッセージを待機して送信する { #await-for-messages-and-send-messages }\n\nWebSocketルートでは、メッセージを待機して送信するために `await` を使用できます。\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\nバイナリやテキストデータ、JSONデータを送受信できます。\n\n## 試してみる { #try-it }\n\nコードを `main.py` に入れて、アプリケーションを実行します。\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nブラウザで [http://127.0.0.1:8000](http://127.0.0.1:8000) を開きます。\n\n次のようなシンプルなページが表示されます。\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\n入力ボックスにメッセージを入力して送信できます。\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\nそして、 WebSocketsを使用した**FastAPI**アプリケーションが応答します。\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\n複数のメッセージを送信（および受信）できます。\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\nそして、これらの通信はすべて同じWebSocket接続を使用します。\n\n## `Depends` などの使用 { #using-depends-and-others }\n\nWebSocketエンドポイントでは、`fastapi` から以下をインポートして使用できます。\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\nこれらは、他のFastAPI エンドポイント/*path operations* の場合と同じように機能します。\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info | 情報\n\nこれはWebSocketであるため、`HTTPException` を発生させることはあまり意味がありません。代わりに `WebSocketException` を発生させます。\n\nクロージングコードは、[仕様で定義された有効なコード](https://tools.ietf.org/html/rfc6455#section-7.4.1)の中から使用することができます。\n\n///\n\n### 依存関係を用いてWebSocketsを試してみる { #try-the-websockets-with-dependencies }\n\nアプリケーションを実行します。\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nブラウザで [http://127.0.0.1:8000](http://127.0.0.1:8000) を開きます。\n\nそこで、以下を設定できます。\n\n* パスで使用される「Item ID」\n* クエリパラメータとして使用される「Token」\n\n/// tip | 豆知識\n\nクエリ `token` は依存関係によって処理されることに注意してください。\n\n///\n\nこれにより、WebSocketに接続してメッセージを送受信できます。\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## 切断や複数クライアントの処理 { #handling-disconnections-and-multiple-clients }\n\nWebSocket接続が閉じられると、 `await websocket.receive_text()` は例外 `WebSocketDisconnect` を発生させ、この例のようにキャッチして処理することができます。\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\n試してみるには、\n\n* いくつかのブラウザタブでアプリを開きます。\n* それらのタブでメッセージを記入してください。\n* そして、タブのうち1つを閉じてください。\n\nこれにより例外 `WebSocketDisconnect` が発生し、他のすべてのクライアントは次のようなメッセージを受信します。\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip | 豆知識\n\n上記のアプリは、複数の WebSocket 接続に対してメッセージを処理し、ブロードキャストする方法を示すための最小限のシンプルな例です。\n\nしかし、すべてがメモリ内の単一のリストで処理されるため、プロセスの実行中にのみ機能し、単一のプロセスでのみ機能することに注意してください。\n\nFastAPIと簡単に統合できて、RedisやPostgreSQLなどでサポートされている、より堅牢なものが必要なら、[encode/broadcaster](https://github.com/encode/broadcaster) を確認してください。\n\n///\n\n## 詳細情報 { #more-info }\n\nオプションの詳細については、Starletteのドキュメントを確認してください。\n\n* [`WebSocket` クラス](https://www.starlette.dev/websockets/)。\n* [クラスベースのWebSocket処理](https://www.starlette.dev/endpoints/#websocketendpoint)。\n"
  },
  {
    "path": "docs/ja/docs/advanced/wsgi.md",
    "content": "# WSGI の組み込み - Flask、Django など { #including-wsgi-flask-django-others }\n\n[サブアプリケーション - マウント](sub-applications.md)、[プロキシの背後](behind-a-proxy.md) で見たように、WSGI アプリケーションをマウントできます。\n\nそのために `WSGIMiddleware` を使用して、Flask や Django などの WSGI アプリをラップできます。\n\n## `WSGIMiddleware` の使用 { #using-wsgimiddleware }\n\n/// info | 情報\n\nこれには `a2wsgi` のインストールが必要です。例: `pip install a2wsgi`。\n\n///\n\n`a2wsgi` から `WSGIMiddleware` をインポートします。\n\n次に、そのミドルウェアで WSGI（例: Flask）アプリをラップします。\n\nそして、それをあるパスの下にマウントします。\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note | 備考\n\n以前は `fastapi.middleware.wsgi` の `WSGIMiddleware` を使用することが推奨されていましたが、現在は非推奨です。\n\n代わりに `a2wsgi` パッケージを使用することを推奨します。使い方は同じです。\n\n`a2wsgi` パッケージがインストールされていることを確認し、`a2wsgi` から `WSGIMiddleware` を正しくインポートしてください。\n\n///\n\n## チェック { #check-it }\n\nこれで、パス `/v1/` 配下へのすべてのリクエストは Flask アプリケーションが処理します。\n\nそれ以外は **FastAPI** が処理します。\n\n実行して [http://localhost:8000/v1/](http://localhost:8000/v1/) にアクセスすると、Flask からのレスポンスが表示されます:\n\n```txt\nHello, World from Flask!\n```\n\nさらに [http://localhost:8000/v2](http://localhost:8000/v2) にアクセスすると、FastAPI からのレスポンスが表示されます:\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/ja/docs/alternatives.md",
    "content": "# 代替ツールから受けたインスピレーションと比較 { #alternatives-inspiration-and-comparisons }\n\n何が**FastAPI**にインスピレーションを与えたのか、他の代替ツールと比較してどうか、そしてそこから何を学んだのかについて。\n\n## はじめに { #intro }\n\n**FastAPI**は、代替ツールのこれまでの働きがなければ存在しなかったでしょう。\n\n以前に作られた多くのツールが、作成における刺激として役立ってきました。\n\n私は数年前から新しいフレームワークの作成を避けてきました。まず、**FastAPI**でカバーされているすべての機能を、さまざまなフレームワーク、プラグイン、ツールを使って解決しようとしました。\n\nしかし、その時点では、これらの機能をすべて提供し、以前のツールから優れたアイデアを取り入れ、可能な限り最高の方法でそれらを組み合わせ、それまで利用できなかった言語機能 (Python 3.6以降の型ヒント) を利用したものを作る以外に選択肢はありませんでした。\n\n## 以前のツール { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\nPythonのフレームワークの中で最もポピュラーで、広く信頼されています。Instagramのようなシステムの構築に使われています。\n\nリレーショナルデータベース (MySQLやPostgreSQLなど) と比較的強固に結合されているので、NoSQLデータベース (Couchbase、MongoDB、Cassandraなど) をメインに利用することは簡単ではありません。\n\nバックエンドでHTMLを生成するために作られたものであり、現代的なフロントエンド (ReactやVue.js、Angularなど) や、他のシステム (<abbr title=\"Internet of Things - モノのインターネット\">IoT</abbr>デバイスなど) と通信するAPIを構築するために作られたものではありません。\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nDjango REST Frameworkは、Djangoを下敷きにしてWeb APIを構築する柔軟なツールキットとして、APIの機能を向上させるために作られました。\n\nMozilla、Red Hat、Eventbrite など多くの企業で利用されています。\n\nこれは**自動的なAPIドキュメント生成**の最初の例であり、これは**FastAPI**に向けた「調査」を触発した最初のアイデアの一つでした。\n\n/// note | 備考\n\nDjango REST Framework は Tom Christie によって作成されました。StarletteとUvicornの生みの親であり、**FastAPI**のベースとなっています。\n\n///\n\n/// check | **FastAPI**へ与えたインスピレーション\n\n自動でAPIドキュメントを生成するWebユーザーインターフェースを持っている点。\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask は「マイクロフレームワーク」であり、データベースとの統合のようなDjangoがデフォルトで持つ多くの機能は含まれていません。\n\nこのシンプルさと柔軟性により、メインのデータストレージシステムとしてNoSQLデータベースを使用するといったようなことが可能になります。\n\n非常にシンプルなので、ドキュメントはいくつかの点でやや技術的でありますが、比較的直感的に学ぶことができます。\n\nまた、データベースやユーザ管理、あるいはDjangoにあらかじめ組み込まれている多くの機能を必ずしも必要としないアプリケーションにもよく使われています。これらの機能の多くはプラグインで追加することができます。\n\nこのようにパーツを分離し、必要なものを正確にカバーするために拡張できる「マイクロフレームワーク」であることは、私が残しておきたかった重要な機能でした。\n\nFlaskのシンプルさを考えると、APIを構築するのに適しているように思えました。次に見つけるべきは、Flask 用の「Django REST Framework」でした。\n\n/// check | **FastAPI**へ与えたインスピレーション\n\nマイクロフレームワークであること。ツールやパーツを目的に合うように簡単に組み合わせられる点。\n\nシンプルで簡単なルーティングの仕組みを持っている点。\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI**は実際には**Requests**の代替ではありません。それらのスコープは大きく異なります。\n\n実際にはFastAPIアプリケーションの*内部*でRequestsを使用するのが一般的です。\n\nしかし、FastAPIはRequestsからかなりのインスピレーションを得ています。\n\n**Requests**は (クライアントとして) APIと*通信*するためのライブラリであり、**FastAPI**は (サーバーとして) APIを*構築*するためのライブラリです。\n\nこれらは多かれ少なかれ両端にあり、お互いを補完し合っています。\n\nRequestsは非常にシンプルかつ直感的なデザインで使いやすく、適切なデフォルト値を設定しています。しかし同時に、非常に強力でカスタマイズも可能です。\n\n公式サイトで以下のように言われているのは、それが理由です。\n\n> Requestsは史上最もダウンロードされたPythonパッケージのひとつです\n\n使い方はとても簡単です。例えば、`GET`リクエストを実行するには、このように書けば良いです:\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\n対応するFastAPIのAPIのpath operationはこのようになります:\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\n `requests.get(...)` と`@app.get(...)` には類似点が見受けられます。\n\n/// check | **FastAPI**へ与えたインスピレーション\n\n* シンプルで直感的なAPIを持っている点。\n* HTTPメソッド名を直接利用し、単純で直感的である。\n* 適切なデフォルト値を持ちつつ、強力なカスタマイズ性を持っている。\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\n私がDjango REST Frameworkに求めていた主な機能は、APIの自動的なドキュメント生成でした。\n\nそして、Swaggerと呼ばれる、 JSON (またはYAML、JSONの拡張版) を使ってAPIをドキュメント化するための標準があることを知りました。\n\nそして、Swagger API用のWebユーザーインターフェースが既に作成されていました。つまり、API用のSwaggerドキュメントを生成することができれば、このWebユーザーインターフェースを自動的に使用することができるようになります。\n\nある時点で、SwaggerはLinux Foundationに寄贈され、OpenAPIに改名されました。\n\nそのため、バージョン2.0では「Swagger」、バージョン3以上では「OpenAPI」と表記するのが一般的です。\n\n/// check | **FastAPI**へ与えたインスピレーション\n\n独自のスキーマの代わりに、API仕様のオープンな標準を採用しました。\n\nそして、標準に基づくユーザーインターフェースツールを統合しています。\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\nこの二つは人気で安定したものとして選択されましたが、少し検索してみると、 (**FastAPI**と同時に使用できる) OpenAPIのための多くの代替となるツールを見つけることができます。\n\n///\n\n### Flask REST フレームワーク { #flask-rest-frameworks }\n\nいくつかのFlask RESTフレームワークがありますが、それらを調査してみたところ、多くのものが不適切な問題が残ったまま、中断されたり放置されていることがわかりました。\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nAPIシステムで必要とされる主な機能の一つに、コード (Python) からデータを取り出して、ネットワークを介して送れるものに変換するデータの「<dfn title=\"別名: marshalling、変換\">シリアライゼーション</dfn>」があります。例えば、データベースのデータを含むオブジェクトをJSONオブジェクトに変換したり、`datetime` オブジェクトを文字列に変換するなどです。\n\nAPIが必要とするもう一つの大きな機能はデータのバリデーションであり、特定のパラメータが与えられた場合にデータが有効であることを確認することです。例えば、あるフィールドがランダムな文字列ではなく `int` であることなどです。これは特に受信するデータに対して便利です。\n\nデータバリデーションの仕組みがなければ、すべてのチェックを手作業でコードに実装しなければなりません。\n\nこれらの機能は、Marshmallowが提供するものです。Marshmallowは素晴らしいライブラリで、私も以前に何度も使ったことがあります。\n\nしかし、それはPythonの型ヒントが存在する前に作られたものです。そのため、すべての<dfn title=\"データがどのように構成されるべきかの定義\">スキーマ</dfn>を定義するためには、Marshmallowが提供する特定のユーティリティやクラスを使用する必要があります。\n\n/// check | **FastAPI**へ与えたインスピレーション\n\nコードで「スキーマ」を定義し、データの型やバリデーションを自動で提供する点。\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nAPIに求められる他の大きな機能として、<dfn title=\"Pythonデータへの読み込みと変換\">受信したリクエストデータのパース</dfn>があります。\n\nWebargsはFlaskをはじめとするいくつかのフレームワークの上にそれを提供するために作られたツールです。\n\nデータのバリデーションを行うために内部ではMarshmallowを使用しており、同じ開発者によって作られました。\n\n素晴らしいツールで、私も**FastAPI**を持つ前はよく使っていました。\n\n/// info | 情報\n\nWebargsは、Marshmallowと同じ開発者により作られました。\n\n///\n\n/// check | **FastAPI**へ与えたインスピレーション\n\n受信したデータに対する自動的なバリデーションを持っている点。\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallowとWebargsはバリデーション、パース、シリアライゼーションをプラグインとして提供しています。\n\nしかし、ドキュメントはまだ不足しています。そこでAPISpecが作られました。\n\nこれは多くのフレームワーク用のプラグインです (Starlette用のプラグインもあります) 。\n\n仕組みとしては、各ルーティング関数のdocstringにYAML形式でスキーマの定義を記述します。\n\nそして、OpenAPIスキーマを生成してくれます。\n\nFlask, Starlette, Responderなどにおいてはそのように動作します。\n\nしかし、Pythonの文字列 (大きなYAML) の中に、小さな構文があるという問題があります。\n\nエディタでは、この問題を解決することはできません。また、パラメータやMarshmallowスキーマを変更したときに、YAMLのdocstringを変更するのを忘れてしまうと、生成されたスキーマが古くなってしまいます。\n\n/// info | 情報\n\nAPISpecは、Marshmallowと同じ開発者により作成されました。\n\n///\n\n/// check | **FastAPI**へ与えたインスピレーション\n\nOpenAPIという、APIについてのオープンな標準をサポートしている点。\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\nWebargs、Marshmallow、APISpecを連携させたFlaskプラグインです。\n\nWebargsとMarshmallowの情報から、APISpecを使用してOpenAPIスキーマを自動的に生成します。\n\nこれは素晴らしいツールで、非常に過小評価されています。多くの Flask プラグインよりもずっと人気があるべきです。ドキュメントがあまりにも簡潔で抽象的であるからかもしれません。\n\nこれにより、PythonのdocstringにYAML (別の構文) を書く必要がなくなりました。\n\nFlask、Flask-apispec、Marshmallow、Webargsの組み合わせは、**FastAPI**を構築するまで私のお気に入りのバックエンドスタックでした。\n\nこれを使うことで、いくつかのFlaskフルスタックジェネレータを作成することになりました。これらは私 (といくつかの外部のチーム) が今まで使ってきたメインのスタックです。\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\nそして、これらのフルスタックジェネレーターは、[**FastAPI** Project Generators](project-generation.md)の元となっていました。\n\n/// info | 情報\n\nFlask-apispecはMarshmallowと同じ開発者により作成されました。\n\n///\n\n/// check | **FastAPI**へ与えたインスピレーション\n\nシリアライゼーションとバリデーションを定義したコードから、OpenAPIスキーマを自動的に生成する点。\n\n///\n\n### [NestJS](https://nestjs.com/) (と[Angular](https://angular.io/)) { #nestjs-and-angular }\n\nNestJSはAngularにインスパイアされたJavaScript (TypeScript) NodeJSフレームワークで、Pythonですらありません。\n\nFlask-apispecでできることと多少似たようなことを実現しています。\n\nAngular 2にインスピレーションを受けた、統合された依存性注入の仕組みを持っています。(私が知っている他の依存性注入の仕組みと同様に) 「injectable」を事前に登録しておく必要があるため、冗長性とコードの繰り返しが発生します。\n\nパラメータはTypeScriptの型で記述されるので (Pythonの型ヒントに似ています) 、エディタのサポートはとても良いです。\n\nしかし、TypeScriptのデータはJavaScriptへのコンパイル後には残されないため、バリデーション、シリアライゼーション、ドキュメント化を同時に定義するのに型に頼ることはできません。そのため、バリデーション、シリアライゼーション、スキーマの自動生成を行うためには、多くの場所でデコレータを追加する必要があり、非常に冗長になります。\n\n入れ子になったモデルをうまく扱えません。そのため、リクエストのJSONボディが内部フィールドを持つJSONオブジェクトで、それが順番にネストされたJSONオブジェクトになっている場合、適切にドキュメント化やバリデーションをすることができません。\n\n/// check | **FastAPI**へ与えたインスピレーション\n\n素晴らしいエディターの補助を得るために、Pythonの型ヒントを利用している点。\n\n強力な依存性注入の仕組みを持ち、コードの繰り返しを最小化する方法を見つけた点。\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\n`asyncio`に基づいた、Pythonのフレームワークの中でも非常に高速なものの一つです。Flaskと非常に似た作りになっています。\n\n/// note | 技術詳細\n\nPythonの`asyncio`ループの代わりに、[`uvloop`](https://github.com/MagicStack/uvloop)が利用されています。それにより、非常に高速です。\n\n`Uvicorn`と`Starlette`に明らかなインスピレーションを与えており、それらは現在オープンなベンチマークにおいてSanicより高速です。\n\n///\n\n/// check | **FastAPI**へ与えたインスピレーション\n\n物凄い性能を出す方法を見つけた点。\n\n**FastAPI**が、(サードパーティのベンチマークによりテストされた) 最も高速なフレームワークであるStarletteに基づいている理由です。\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalconはもう一つの高性能Pythonフレームワークで、ミニマムに設計されており、Hugのような他のフレームワークの基盤として動作します。\n\nこれは、「リクエスト」と「レスポンス」の2つのパラメータを受け取る関数を持つように設計されています。そして、リクエストからデータを「読み込み」、レスポンスにデータを「書き込み」ます。この設計のため、Python標準の型ヒントでリクエストのパラメータやボディを関数の引数として宣言することはできません。\n\nそのため、データのバリデーション、シリアライゼーション、ドキュメント化は、自動的にできずコードの中で行わなければなりません。あるいは、HugのようにFalconの上にフレームワークとして実装されなければなりません。このような分断は、パラメータとして1つのリクエストオブジェクトと1つのレスポンスオブジェクトを持つというFalconのデザインにインスピレーションを受けた他のフレームワークでも起こります。\n\n/// check | **FastAPI**へ与えたインスピレーション\n\n素晴らしい性能を得るための方法を見つけた点。\n\nHug (HugはFalconをベースにしています) と一緒に、**FastAPI**が`response`引数を関数に持つことにインスピレーションを与えました。\n\n**FastAPI**では任意ですが、ヘッダーやCookieやステータスコードを設定するために利用されています。\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\n**FastAPI**を構築する最初の段階でMoltenを発見しました。そして、それは非常に似たようなアイデアを持っています。\n\n* Pythonの型ヒントに基づいている\n* これらの型から行われるバリデーションとドキュメント化\n* 依存性注入の仕組み\n\nPydanticのようなデータのバリデーション、シリアライゼーション、ドキュメント化をするサードパーティライブラリを使用せず、独自のものを持っています。そのため、これらのデータ型の定義は簡単には再利用できません。\n\nもう少し冗長な設定が必要になります。また、 (ASGIではなく) WSGIに基づいているので、UvicornやStarletteやSanicのようなツールが提供する高性能を得られるようには設計されていません。\n\n依存性注入の仕組みは依存性の事前登録が必要で、宣言された型に基づいて依存性が解決されます。そのため、特定の型を提供する「コンポーネント」を複数宣言することはできません。\n\nルーティングは一つの場所で宣言され、他の場所で宣言された関数を使用します (エンドポイントを扱う関数のすぐ上に配置できるデコレータを使用するのではなく) 。これはFlask (やStarlette) よりも、Djangoに近いです。これは、比較的緊密に結合されているものをコードの中で分離しています。\n\n/// check | **FastAPI**へ与えたインスピレーション\n\nモデルの属性の「デフォルト」値を使用したデータ型の追加バリデーションを定義します。これはエディタの補助を改善するもので、以前はPydanticでは利用できませんでした。\n\n同様の方法でのバリデーションの宣言をサポートするよう、Pydanticを部分的にアップデートするインスピーレションを与えました。(現在はこれらの機能は全てPydanticで可能となっています。)\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHugは、Pythonの型ヒントを利用してAPIパラメータの型宣言を実装した最初のフレームワークの1つです。これは素晴らしいアイデアで、他のツールが同じことをするきっかけとなりました。\n\nHugは標準のPython型の代わりにカスタム型を宣言に使用していましたが、それでも大きな進歩でした。\n\nまた、JSONでAPI全体を宣言するカスタムスキーマを生成した最初のフレームワークの1つでもあります。\n\nOpenAPIやJSON Schemaのような標準に基づいたものではありませんでした。そのため、Swagger UIのような他のツールと統合するのは簡単ではありませんでした。しかし、繰り返しになりますが、これは非常に革新的なアイデアでした。\n\n同じフレームワークを使ってAPIとCLIを作成できる、面白く珍しい機能を持っています。\n\n以前のPythonの同期型Webフレームワーク標準 (WSGI) をベースにしているため、Websocketなどは扱えませんが、それでも高性能です。\n\n/// info | 情報\n\nHugはTimothy Crosleyにより作成されました。彼は[`isort`](https://github.com/timothycrosley/isort)など、Pythonのファイル内のインポートの並び替えを自動的におこうなう素晴らしいツールの開発者です。\n\n///\n\n/// check | **FastAPI**へ与えたインスピレーション\n\nHugはAPIStarに部分的なインスピレーションを与えており、私が発見した中ではAPIStarと同様に最も期待の持てるツールの一つでした。\n\nHugは、**FastAPI**がPythonの型ヒントを用いてパラメータを宣言し自動的にAPIを定義するスキーマを生成することを触発しました。\n\nHugは、**FastAPI**がヘッダーやクッキーを設定するために関数に `response`引数を宣言することにインスピレーションを与えました。\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0.5) { #apistar-0-5 }\n\n**FastAPI**を構築することを決める直前に、**APIStar**サーバーを見つけました。それは私が探していたものがほぼすべて含まれており、素晴らしいデザインでした。\n\nこれは、私がこれまでに見た中で (NestJSやMoltenの前に) Pythonの型ヒントを使ってパラメータやリクエストを宣言するフレームワークの最初の実装の一つでした。Hugと多かれ少なかれ同時期に見つけました。ただ、APIStarはOpenAPI標準を使っていました。\n\nいくつかの場所で同じ型ヒントを元に、データの自動バリデーション、データのシリアライゼーション、OpenAPIスキーマの生成を行っていました。\n\nボディのスキーマ定義にはPydanticのようなPythonの型ヒントは使われておらず、もう少しMarshmallowに似ていたので、エディタの補助はあまり良くないかもしれませんが、それでもAPIStarは利用可能な最良の選択肢でした。\n\n当時のベンチマークでは最高のパフォーマンスを発揮していました (Starletteのみが上回っていました) 。\n\n最初は自動的なAPIのドキュメント化のWeb UIを持っていませんでしたが、Swagger UIを追加できることはわかっていました。\n\n依存性注入の仕組みを持っていました。上記で説明した他のツールのようにコンポーネントの事前登録が必要でした。しかし、それでも素晴らしい機能でした。\n\nセキュリティの統合がなかったので、Flask-apispecを元にしたフルスタックジェネレータにあるすべての機能を置き換えることはできませんでした。私はその機能を追加するプルリクエストを作成するというプロジェクトのバックログを持っていました。\n\nしかし、その後、プロジェクトの焦点が変わりました。\n\n制作者はStarletteに集中する必要があったため、APIウェブフレームワークではなくなりました。\n\n今ではAPIStarはOpenAPI仕様を検証するためのツールセットであり、ウェブフレームワークではありません。\n\n/// info | 情報\n\nAPIStarはTom Christieにより開発されました。以下の開発者でもあります:\n\n* Django REST Framework\n* Starlette (**FastAPI**のベースになっています)\n* Uvicorn (Starletteや**FastAPI**で利用されています)\n\n///\n\n/// check | **FastAPI**へ与えたインスピレーション\n\n存在そのもの。\n\n複数の機能 (データのバリデーション、シリアライゼーション、ドキュメント化) を同じPython型で宣言し、同時に優れたエディタの補助を提供するというアイデアは、私にとって素晴らしいアイデアでした。\n\nそして、長い間同じようなフレームワークを探し、多くの異なる代替ツールをテストした結果、APIStarが最良の選択肢となりました。\n\nその後、APIStarはサーバーとして存在しなくなり、Starletteが作られ、そのようなシステムのための新しくより良い基盤となりました。これが**FastAPI**を構築するための最終的なインスピレーションでした。\n\n私は、これまでのツールから学んだことをもとに、機能や型システムなどの部分を改善・拡充しながら、**FastAPI**をAPIStarの「精神的な後継者」と考えています。\n\n///\n\n## **FastAPI**が利用しているもの { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydanticは、Pythonの型ヒントを元にデータのバリデーション、シリアライゼーション、 (JSON Schemaを使用した) ドキュメントを定義するライブラリです。\n\nそのため、非常に直感的です。\n\nMarshmallowに匹敵しますが、ベンチマークではMarshmallowよりも高速です。また、Pythonの型ヒントを元にしているので、エディタの補助が素晴らしいです。\n\n/// check | **FastAPI**での使用用途\n\nデータのバリデーション、データのシリアライゼーション、自動的なモデルの (JSON Schemaに基づいた) ドキュメント化の全てを扱えます。\n\n**FastAPI**はそのJSON SchemaデータをOpenAPIに取り込みます (それ以外にも多くのことを行います)。\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarletteは、軽量な<dfn title=\"非同期Python Webアプリケーションを構築するための新しい標準\">ASGI</dfn>フレームワーク/ツールキットで、高性能な非同期サービスの構築に最適です。\n\n非常にシンプルで直感的です。簡単に拡張できるように設計されており、モジュール化されたコンポーネントを持っています。\n\n以下のような特徴があります。\n\n* 非常に感動的な性能。\n* WebSocketのサポート。\n* インプロセスのバックグラウンドタスク。\n* 起動およびシャットダウンイベント。\n* HTTPXに基づいて構築されたテストクライアント。\n* CORS、GZip、静的ファイル、ストリーミング応答。\n* セッションとクッキーのサポート。\n* 100%のテストカバレッジ。\n* 100%の型注釈付きコードベース。\n* ハードな依存関係は少ない。\n\nStarletteは、現在テストされているPythonフレームワークの中で最も速いフレームワークです。フレームワークではなくサーバーであるUvicornだけが上回っています。\n\nStarletteは基本的なWebマイクロフレームワークの機能をすべて提供します。\n\nしかし、自動的なデータバリデーション、シリアライゼーション、ドキュメント化は提供していません。\n\nこれは **FastAPI** が追加する主な機能の一つで、すべての機能は Pythonの型ヒントに基づいています (Pydanticを使用しています) 。これに加えて、依存性注入の仕組み、セキュリティユーティリティ、OpenAPIスキーマ生成などがあります。\n\n/// note | 技術詳細\n\nASGIはDjangoのコアチームメンバーにより開発された新しい「標準」です。まだ「Pythonの標準 (PEP) 」ではありませんが、現在そうなるように進めています。\n\nしかしながら、いくつかのツールにおいてすでに「標準」として利用されています。このことは互換性を大きく改善するもので、Uvicornから他のASGIサーバー (DaphneやHypercorn) に乗り換えることができたり、あなたが`python-socketio`のようなASGI互換のツールを追加することもできます。\n\n///\n\n/// check | **FastAPI**での使用用途\n\nwebに関するコアな部分を全て扱います。その上に機能を追加します。\n\n`FastAPI`クラスそのものは、`Starlette`クラスを直接継承しています。\n\n基本的にはStarletteの強化版であるため、Starletteで可能なことは**FastAPI**で直接可能です。\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicornは非常に高速なASGIサーバーで、uvloopとhttptoolsにより構成されています。\n\nウェブフレームワークではなくサーバーです。例えば、パスルーティングのツールは提供していません。それらは、Starlette (や**FastAPI**) のようなフレームワークがその上で提供するものです。\n\nStarletteや**FastAPI**のサーバーとして推奨されています。\n\n/// check | **FastAPI**が推奨する理由\n\n**FastAPI**アプリケーションを実行するメインのウェブサーバーである点。\n\nコマンドラインオプション `--workers` を使って、非同期のマルチプロセスサーバーにできます。\n\n詳細は[デプロイ](deployment/index.md)の項目で確認してください。\n\n///\n\n## ベンチマーク と スピード { #benchmarks-and-speed }\n\nUvicorn、Starlette、FastAPIの違いを理解、比較、確認するには、[ベンチマーク](benchmarks.md)を確認してください。\n"
  },
  {
    "path": "docs/ja/docs/async.md",
    "content": "# 並行処理と async / await { #concurrency-and-async-await }\n\n*path operation 関数*のための `async def` 構文に関する詳細と、非同期コード、並行処理、並列処理の背景についてです。\n\n## 急いでいますか？ { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - 長すぎて読まなかった\"><strong>TL;DR:</strong></abbr>\n\n次のように `await` で呼び出すよう指示されているサードパーティライブラリを使っているなら:\n\n```Python\nresults = await some_library()\n```\n\n*path operation 関数*は次のように `async def` で宣言します:\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | 備考\n\n`await` は `async def` で作られた関数の内部でしか使えません。\n\n///\n\n---\n\nデータベース、API、ファイルシステムなどと通信しつつ `await` の使用をサポートしていないサードパーティライブラリ (現在のところ多くのデータベースライブラリが該当します) を使っている場合、*path operation 関数*は通常どおり `def` で宣言してください:\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\nアプリケーションが (何らかの理由で) ほかの何とも通信せず応答を待つ必要がないなら、`await` を内部で使わなくても `async def` を使ってください。\n\n---\n\nよく分からない場合は、通常の `def` を使ってください。\n\n---\n\n**備考**: 必要に応じて *path operation 関数* では `def` と `async def` を混在させ、それぞれに最適な選択肢で定義できます。FastAPI は適切に処理します。\n\nいずれの場合でも、FastAPI は非同期で動作し非常に高速です。\n\nただし上記の手順に従うことで、さらにパフォーマンス最適化が可能になります。\n\n## 技術詳細 { #technical-details }\n\nモダンな Python は **「非同期コード」** を **「コルーチン」** と呼ばれる仕組みでサポートしており、構文は **`async` と `await`** です。\n\n以下のセクションで、このフレーズをパーツごとに見ていきます:\n\n* **非同期コード**\n* **`async` と `await`**\n* **コルーチン**\n\n## 非同期コード { #asynchronous-code }\n\n非同期コードとは、言語 💬 がコードのどこかの時点で、コンピュータ/プログラム 🤖 に「どこか別のところで終わるまで、別の何か」を待つ必要があると伝える手段を持っている、ということです。その「別の何か」を「遅いファイル」📝 と呼ぶことにしましょう。\n\nその間、コンピュータは「遅いファイル」📝 が終わるまで、他の作業を進められます。\n\nその後、コンピュータ/プログラム 🤖 は、また待つ機会が来たときや、その時点で抱えていた作業をすべて終えたときに戻ってきます。そして、待っていたタスクのどれかが終わっていないか確認し、必要な処理を実行します。\n\n次に、最初に終わったタスク (たとえば「遅いファイル」📝) を取り、続きの処理を行います。\n\nこの「別の何かを待つ」は、通常 <abbr title=\"Input and Output - 入出力\">I/O</abbr> 操作を指し、(プロセッサや RAM の速度に比べて) 相対的に「遅い」待機を伴います。例えば次のようなものです:\n\n* クライアントからネットワーク経由でデータが送られてくるのを待つ\n* プログラムが送信したデータをクライアントがネットワーク経由で受け取るのを待つ\n* ディスク上のファイル内容がシステムにより読み取られ、プログラムに渡されるのを待つ\n* プログラムがシステムに渡した内容がディスクに書き込まれるのを待つ\n* リモート API 操作\n* データベース操作の完了\n* データベースクエリが結果を返すのを待つ\n* など\n\n実行時間の大半が <abbr title=\"Input and Output - 入出力\">I/O</abbr> 操作の待ち時間に費やされるため、これらは「I/O バウンド」な操作と呼ばれます。\n\n「非同期」と呼ばれるのは、コンピュータ/プログラムがその遅いタスクと「同期」(タスクがちょうど終わる瞬間を、何もせずに待つ) する必要がないからです。結果を受け取って処理を続けるために、空待ちする必要がありません。\n\n代わりに「非同期」システムでは、タスクが終わったら、コンピュータ/プログラムが取りかかっている作業が終わるまで (数マイクロ秒ほど) 少し待ち、結果を受け取りに戻って処理を続けられます。\n\n「非同期」と対になる「同期」は、「シーケンシャル」と呼ばれることもあります。待機が含まれていても、別のタスクに切り替える前にコンピュータ/プログラムが手順を順番に実行するためです。\n\n### 並行処理とハンバーガー { #concurrency-and-burgers }\n\n上で説明した**非同期**コードの考え方は、**「並行処理」** と呼ばれることもあります。これは **「並列処理」** とは異なります。\n\n**並行処理** も **並列処理** も、「複数のことがだいたい同時に起きる」ことに関係します。\n\nただし、*並行処理* と *並列処理* の詳細はかなり異なります。\n\n違いを見るために、ハンバーガーに関する次の物語を想像してみてください。\n\n### 並行ハンバーガー { #concurrent-burgers }\n\nあなたは好きな人とファストフードを買いに行き、前の人たちの注文をレジ係が受ける間、列に並びます。😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\nやがてあなたの番になり、好きな人と自分のために、とても豪華なハンバーガーを2つ注文します。🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\nレジ係はキッチンの料理人に、あなたのハンバーガーを用意するよう声をかけます (料理人はいま前のお客さんの分を作っています)。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\n支払いをします。💸\n\nレジ係はあなたに番号札を渡します。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\n待っている間、好きな人とテーブルに移動して座り、(豪華なハンバーガーは時間がかかるので) しばらく話します。\n\nテーブルで待っている間、好きな人がどれだけ素敵で、かわいくて、頭が良いかを眺めて時間を過ごせます ✨😍✨。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\n時々カウンターの表示を見て、自分の番号になっているか確認します。\n\nやがてあなたの番になります。カウンターに行き、ハンバーガーを受け取り、テーブルに戻ります。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\nあなたと好きな人はハンバーガーを食べて、楽しい時間を過ごします。✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info | 情報\n\n美しいイラストは [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot) によるものです。🎨\n\n///\n\n---\n\nこの物語で、あなた自身がコンピュータ/プログラム 🤖 だと想像してみてください。\n\n列にいる間は、何も「生産的」なことをせず、自分の番を待つだけのアイドル状態 😴 です。ただしレジ係は注文を取るだけ (作りはしない) なので列は速く進み、問題ありません。\n\nあなたの番になると、実際に「生産的」な作業をします。メニューを見て注文を決め、好きな人の分も確認し、支払い、正しい紙幣/カードを渡したか、正しく決済されたか、注文内容が正しいかなどを確認します。\n\nしかし、ハンバーガーはまだ出来上がっていないので、レジ係とのやり取りは「一時停止」⏸ になります。ハンバーガーができるまで待つ 🕙 必要があるからです。\n\nただし、番号札を持ってカウンターから離れテーブルに座れば、注意を好きな人に切り替え 🔀、「その作業」⏯ 🤓 に取り組めます。好きな人といちゃつくという、とても「生産的」🤓 なことがまたできます。\n\nレジ係 💁 がカウンターの表示にあなたの番号を出して「ハンバーガーができました」と知らせても、あなたは表示が切り替わった瞬間に飛び跳ねたりしません。自分の番号札があり、他の人にもそれぞれ番号札があるので、ハンバーガーを盗られることはないと知っているからです。\n\nだから、好きな人の話が終わるのを待ち (現在の作業 ⏯ / 処理中のタスクを完了し 🤓)、微笑んで「ハンバーガー取ってくるね」と言います ⏸。\n\nそれからカウンターへ行き 🔀、いま完了した初期のタスク ⏯ に戻って、ハンバーガーを受け取り、礼を言ってテーブルに持っていきます。これでカウンターとのやり取りというステップ/タスクは完了 ⏹ です。その結果として「ハンバーガーを食べる」🔀 ⏯ という新しいタスクが生まれますが、先の「ハンバーガーを受け取る」タスクは完了 ⏹ しています。\n\n### 並列ハンバーガー { #parallel-burgers }\n\n今度は、これが「並行ハンバーガー」ではなく「並列ハンバーガー」だと想像しましょう。\n\nあなたは好きな人と「並列」ファストフードを買いに行きます。\n\n複数のレジ係 (例えば 8 人) が同時に料理人でもあり、前の人たちの注文を受けています。\n\n8 人のレジ係はそれぞれ、次の注文を取る前にすぐに調理に取りかかるため、あなたの前の人たちはカウンターを離れず、ハンバーガーができるのを待っています。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\nようやくあなたの番になり、好きな人と自分のために豪華なハンバーガーを 2 つ注文します。\n\n支払いをします 💸。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\nレジ係はキッチンに向かいます。\n\n番号札がないため、他の誰かに先に取られないよう、カウンターの前で立って待ちます 🕙。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\nあなたと好きな人は、誰にも割り込まれずハンバーガーが来たらすぐ受け取れるよう見張っているので、好きな人に注意を向けられません。😞\n\nこれは「同期」的な作業です。レジ係/料理人 👨‍🍳 と「同期」しています。レジ係/料理人 👨‍🍳 がハンバーガーを作り終えて手渡すその瞬間に、待って 🕙 その場にいなければなりません。そうでないと他の誰かに取られるかもしれません。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\n長い時間 🕙 カウンター前で待った後、ようやくレジ係/料理人 👨‍🍳 がハンバーガーを持って戻ってきます。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\nハンバーガーを受け取り、好きな人とテーブルに行きます。\n\n食べて、おしまいです。⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\nほとんどの時間をカウンター前で待つ 🕙 のに費やしたため、あまり話したり、いちゃついたりできませんでした。😞\n\n/// info | 情報\n\n美しいイラストは [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot) によるものです。🎨\n\n///\n\n---\n\nこの「並列ハンバーガー」のシナリオでは、あなたは 2 つのプロセッサ (あなたと好きな人) を持つコンピュータ/プログラム 🤖 で、どちらも長い間 🕙「カウンターでの待機」に注意 ⏯ を専念しています。\n\nファストフード店には 8 個のプロセッサ (レジ係/料理人) があります。一方、並行ハンバーガーの店には (レジ係 1、人、料理人 1 人の) 2 個しかなかったかもしれません。\n\nそれでも、最終的な体験は最良とは言えません。😞\n\n---\n\nこれはハンバーガーにおける並列版の物語です。🍔\n\nより「現実的な」例として、銀行を想像してみてください。\n\nつい最近まで、ほとんどの銀行には複数の窓口係 👨‍💼👨‍💼👨‍💼👨‍💼 と長い行列 🕙🕙🕙🕙🕙🕙🕙🕙 がありました。\n\n各窓口係が、一人ずつ、すべての作業を順番に行います 👨‍💼⏯。\n\nそして、長時間 🕙 行列で待たなければ順番を失います。\n\n銀行の用事 🏦 に、好きな人 😍 を連れて行きたいとは思わないでしょう。\n\n### ハンバーガーのまとめ { #burger-conclusion }\n\nこの「好きな人とファストフード」のシナリオでは、待ち時間 🕙 が多いため、並行システム ⏸🔀⏯ を使う方がはるかに理にかなっています。\n\nこれは、ほとんどの Web アプリケーションにも当てはまります。\n\nとても多くのユーザーがいますが、サーバは彼らのあまり速くない回線からリクエストが届くのを待ち 🕙、\n\nその後、レスポンスが戻ってくるのをまた待ちます 🕙。\n\nこの「待ち」🕙 はマイクロ秒単位で測られますが、すべてを合計すると、結局かなりの待ちになります。\n\nだからこそ、Web API には非同期 ⏸🔀⏯ コードを使うのが理にかなっています。\n\nこれが、NodeJS を人気にした要因 (NodeJS 自体は並列ではありません) であり、プログラミング言語としての Go の強みでもあります。\n\nそして、それが **FastAPI** で得られるパフォーマンスの水準です。\n\nさらに、並列性と非同期性を同時に活用できるため、テストされた多くの NodeJS フレームワークより高い性能を発揮し、C に近いコンパイル言語である Go と同等の性能になります [(すべて Starlette のおかげです)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1)。\n\n### 並行処理は並列処理より優れている？ { #is-concurrency-better-than-parallelism }\n\nいいえ！それがこの話の教訓ではありません。\n\n並行処理は並列処理とは異なります。そして多くの待ち時間を伴う**特定の**シナリオでは優れています。そのため、一般に Web アプリ開発では並列処理よりはるかに適しています。しかし、すべてに対して最良というわけではありません。\n\nバランスを取るために、次の短い物語を想像してください。\n\n> 大きくて汚れた家を掃除しなければならない。\n\n*はい、これで物語は全部です*。\n\n---\n\nどこにも待ち 🕙 はなく、家の複数箇所で大量の作業があるだけです。\n\nハンバーガーの例のように順番を決めて、まずリビング、次にキッチン、と進めてもよいのですが、何かを待つ 🕙 わけではなく、ひたすら掃除するだけなので、順番は何も影響しません。\n\n順番の有無 (並行性の有無) に関係なく、終了までに同じ時間がかかり、同じ作業量をこなすことになります。\n\nしかしこの場合、8 人の元レジ係/料理人/現清掃員を連れてきて、それぞれ (あなたも加えて) 家の別々のエリアを掃除できれば、**並列** に作業でき、より早く終えられます。\n\nこのシナリオでは、各清掃員 (あなたを含む) がプロセッサであり、それぞれが自分の役割を果たします。\n\nそして実行時間の大半は (待ちではなく) 実作業が占め、コンピュータでの作業は <abbr title=\"Central Processing Unit - 中央処理装置\">CPU</abbr> によって行われます。これらの問題は「CPU バウンド」と呼ばれます。\n\n---\n\nCPU バウンドな操作の一般的な例は、複雑な数値処理が必要なものです。\n\n例えば:\n\n* **オーディオ** や **画像処理**。\n* **コンピュータビジョン**: 画像は数百万のピクセルで構成され、各ピクセルには 3 つの値/色があり、通常、それらのピクセル上で同時に何かを計算する必要があります。\n* **機械学習**: 多くの「行列」や「ベクトル」の乗算が必要になります。巨大なスプレッドシートに数字が入っていて、それらを同時にすべて掛け合わせることを想像してください。\n* **ディープラーニング**: 機械学習のサブフィールドなので同様です。掛け合わせる数字が 1 つのスプレッドシートではなく膨大な集合であり、多くの場合、それらのモデルを構築/利用するための特別なプロセッサを使います。\n\n### 並行処理 + 並列処理: Web + 機械学習 { #concurrency-parallelism-web-machine-learning }\n\n**FastAPI** では、Web 開発で非常に一般的な並行処理 (NodeJS の主な魅力と同じ) を活用できます。\n\n同時に、機械学習システムのような **CPU バウンド** なワークロードに対して、並列処理やマルチプロセッシング (複数プロセスの並列実行) の利点も活用できます。\n\nさらに、Python が **データサイエンス**、機械学習、特にディープラーニングの主要言語であるという事実も相まって、FastAPI はデータサイエンス/機械学習の Web API やアプリケーション (ほか多数) に非常に適しています。\n\n本番環境でこの並列性を実現する方法は、[デプロイ](deployment/index.md) のセクションを参照してください。\n\n## `async` と `await` { #async-and-await }\n\nモダンな Python には、非同期コードをとても直感的に定義する方法があります。これにより、通常の「シーケンシャル」なコードのように書けて、適切なタイミングで「待ち」を行ってくれます。\n\n結果を返す前に待ちが必要で、これらの新しい Python 機能をサポートしている操作がある場合、次のように書けます。\n\n```Python\nburgers = await get_burgers(2)\n```\n\nここでの鍵は `await` です。`burgers` に結果を保存する前に、`get_burgers(2)` がやるべきことを終えるのを ⏸ 待つ 🕙 ように Python に伝えます。これにより Python は、その間に (別のリクエストを受け取るなど) ほかのことを 🔀 ⏯ できると分かります。\n\n`await` が機能するには、この非同期性をサポートする関数の内部でなければなりません。そのためには `async def` で宣言します:\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # ハンバーガーを作るために非同期の処理を行う\n    return burgers\n```\n\n...`def` の代わりに:\n\n```Python hl_lines=\"2\"\n# これは非同期ではない\ndef get_sequential_burgers(number: int):\n    # ハンバーガーを作るためにシーケンシャルな処理を行う\n    return burgers\n```\n\n`async def` を使うと、Python はその関数内で `await` 式に注意し、関数の実行を「一時停止」⏸ してほかのことをしに行き 🔀、戻ってくることができると分かります。\n\n`async def` な関数を呼ぶときは「await」しなければなりません。したがって、次は動きません:\n\n```Python\n# 動きません。get_burgers は async def で定義されています\nburgers = get_burgers(2)\n```\n\n---\n\nそのため、`await` で呼べると謳っているライブラリを使っている場合は、それを使う *path operation 関数* を `async def` で作る必要があります。例えば:\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### より発展的な技術詳細 { #more-technical-details }\n\n`await` は `async def` で定義された関数の内部でしか使えないことに気づいたかもしれません。\n\n同時に、`async def` で定義された関数は「await」される必要があります。つまり、`async def` を持つ関数は、やはり `async def` で定義された関数の内部からしか呼べません。\n\nでは、ニワトリと卵の話のように、最初の `async` 関数はどう呼ぶのでしょうか？\n\n**FastAPI** を使っている場合は心配ありません。その「最初の」関数は *path operation 関数* で、FastAPI が適切に実行してくれます。\n\nしかし、FastAPI を使わずに `async` / `await` を使いたい場合もあります。\n\n### 自分で async コードを書く { #write-your-own-async-code }\n\nStarlette (**FastAPI** も) は [AnyIO](https://anyio.readthedocs.io/en/stable/) の上に構築されており、標準ライブラリの [asyncio](https://docs.python.org/3/library/asyncio-task.html) と [Trio](https://trio.readthedocs.io/en/stable/) の両方に対応しています。\n\n特に、あなた自身のコード内で、より高度なパターンを必要とする発展的な並行処理のユースケースに対して、[AnyIO](https://anyio.readthedocs.io/en/stable/) を直接使えます。\n\n仮に FastAPI を使っていなくても、[AnyIO](https://anyio.readthedocs.io/en/stable/) で独自の async アプリケーションを書けば、高い互換性と利点 (例: 構造化並行性) を得られます。\n\n私は AnyIO の上に薄い層として、型注釈を少し改善し、より良い**補完**や**インラインエラー**などを得るための別ライブラリも作りました。また、**理解**して**自分で async コードを書く**のに役立つフレンドリーなイントロ/チュートリアルもあります: [Asyncer](https://asyncer.tiangolo.com/)。特に、**async コードと通常の** (ブロッキング/同期) **コードを組み合わせる**必要がある場合に有用です。\n\n### 非同期コードの他の形式 { #other-forms-of-asynchronous-code }\n\n`async` と `await` を使うこのスタイルは、言語としては比較的新しいものです。\n\nしかし、これにより非同期コードの取り扱いは大幅に簡単になります。\n\n同等 (ほぼ同一) の構文が最近の JavaScript (ブラウザと NodeJS) にも導入されました。\n\nそれ以前は、非同期コードの扱いはかなり複雑で難解でした。\n\n以前の Python ではスレッドや [Gevent](https://www.gevent.org/) を使えましたが、コードの理解・デバッグ・思考がはるかに難しくなります。\n\n以前の NodeJS / ブラウザ JavaScript では「コールバック」を使っており、「コールバック地獄」を招きました。\n\n## コルーチン { #coroutines }\n\n**コルーチン**は、`async def` 関数が返すものを指す、ちょっと洒落た用語です。Python はそれを、開始できていつか終了する関数のようなものとして扱いますが、内部に `await` があるたびに内部的に一時停止 ⏸ するかもしれないものとして認識します。\n\n`async` と `await` を用いた非同期コードの機能全体は、しばしば「コルーチンを使う」と要約されます。これは Go の主要機能「Goroutines」に相当します。\n\n## まとめ { #conclusion }\n\n上のフレーズをもう一度見てみましょう:\n\n> モダンな Python は **「非同期コード」** を **「コルーチン」** と呼ばれる仕組みでサポートしており、構文は **`async` と `await`** です。\n\n今なら、より意味が分かるはずです。✨\n\nこれらすべてが (Starlette を通じて) FastAPI を支え、印象的なパフォーマンスを実現しています。\n\n## 非常に発展的な技術的詳細 { #very-technical-details }\n\n/// warning | 注意\n\nおそらく読み飛ばしても大丈夫です。\n\nこれは **FastAPI** の内部動作に関する、とても技術的な詳細です。\n\n(コルーチン、スレッド、ブロッキング等の) 技術知識があり、FastAPI が `async def` と通常の `def` をどう扱うかに興味がある場合は、読み進めてください。\n\n///\n\n### Path operation 関数 { #path-operation-functions }\n\n*path operation 関数* を `async def` ではなく通常の `def` で宣言した場合、(サーバをブロックしてしまうため) 直接呼び出されるのではなく、外部のスレッドプールで実行され、それを待機します。\n\n上記とは異なる動作の別の非同期フレームワークから来ており、ほんのわずかなパフォーマンス向上 (約 100 ナノ秒) を狙って、計算のみの些細な *path operation 関数* を素の `def` で定義することに慣れている場合、**FastAPI** では効果がまったく逆になる点に注意してください。これらの場合、*path operation 関数* がブロッキングな <abbr title=\"Input/Output - 入出力: ディスクの読み取りまたは書き込み、ネットワーク通信。\">I/O</abbr> を行うコードを使っていない限り、`async def` を使った方が良いです。\n\nそれでも、どちらの状況でも、**FastAPI** はあなたが以前使っていたフレームワークよりも (少なくとも同等に) [高速である](index.md#performance) 可能性が高いです。\n\n### 依存関係 { #dependencies }\n\n[依存関係](tutorial/dependencies/index.md) についても同様です。依存関係が `async def` ではなく標準の `def` 関数である場合、外部のスレッドプールで実行されます。\n\n### サブ依存関係 { #sub-dependencies }\n\n複数の依存関係や [サブ依存関係](tutorial/dependencies/sub-dependencies.md) を (関数定義のパラメータとして) 相互に要求させられます。その一部は `async def`、他は通常の `def` で作られていても動作します。通常の `def` で作られたものは「await」される代わりに、外部スレッドプールからスレッド上で呼び出されます。\n\n### その他のユーティリティ関数 { #other-utility-functions }\n\nあなたが直接呼び出すユーティリティ関数は、通常の `def` でも `async def` でも構いません。FastAPI はその呼び出し方に影響を与えません。\n\nこれは、FastAPI があなたの代わりに呼び出す関数 (すなわち *path operation 関数* と依存関係) とは対照的です。\n\nユーティリティ関数が `def` の通常関数であれば、(あなたのコードに書いたとおりに) 直接呼び出され、スレッドプールでは実行されません。関数が `async def` で作られている場合は、その関数を呼ぶときに `await` すべきです。\n\n---\n\n繰り返しになりますが、これらは非常に技術的な詳細で、該当事項を検索してここにたどり着いた場合には役立つでしょう。\n\nそれ以外の場合は、上のセクションのガイドラインに従えば十分です: <a href=\"#in-a-hurry\">急いでいますか？</a>。\n"
  },
  {
    "path": "docs/ja/docs/benchmarks.md",
    "content": "# ベンチマーク { #benchmarks }\n\nTechEmpowerの独立したベンチマークでは、Uvicornの下で動作する**FastAPI**アプリケーションは、[利用可能な最速のPythonフレームワークの1つ](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7)であり、下回っているのはStarletteとUvicorn自体（FastAPIによって内部で使用される）のみだと示されています。\n\nただし、ベンチマークを確認し、比較する際には下記の内容に気を付けてください。\n\n## ベンチマークと速度 { #benchmarks-and-speed }\n\nベンチマークを確認する時、異なるタイプの複数のツールが同等のものとして比較されているのを目にするのが一般的です。\n\n具体的には、Uvicorn、Starlette、FastAPIを（他の多くのツールの中で）まとめて比較しているのを目にすることがあります。\n\nツールで解決する問題がシンプルなほど、パフォーマンスが向上します。また、ほとんどのベンチマークは、ツールから提供される追加機能をテストしていません。\n\n階層関係はこのようになります。\n\n* **Uvicorn**: ASGIサーバー\n    * **Starlette**: （Uvicornを使用）webマイクロフレームワーク\n        * **FastAPI**: （Starletteを使用）データバリデーションなど、APIを構築するためのいくつかの追加機能を備えたAPIマイクロフレームワーク\n\n* **Uvicorn**:\n    * サーバー自体以外に余分なコードがあまりないため、最高のパフォーマンスになります。\n    * Uvicornにアプリケーションを直接書くことはないでしょう。それは、あなたのコードに、Starlette（または**FastAPI**）が提供するコードを、少なくとも多かれ少なかれ含める必要があるということです。そして、もしそうした場合、最終的なアプリケーションは、フレームワークを使用してアプリのコードとバグを最小限に抑えた場合と同じオーバーヘッドになります。\n    * Uvicornを比較する場合は、Daphne、Hypercorn、uWSGIなどのアプリケーションサーバーと比較してください。\n* **Starlette**:\n    * Uvicornに次ぐ性能になるでしょう。実際、Starletteは実行にUvicornを使用しています。そのため、おそらく、より多くのコードを実行しなければならない分だけ、Uvicornより「遅く」なるだけです。\n    * しかし、パスに基づくルーティングなどを使って、シンプルなwebアプリケーションを構築するためのツールを提供します。\n    * Starletteを比較する場合は、Sanic、Flask、Djangoなどのwebフレームワーク（またはマイクロフレームワーク）と比較してください。\n* **FastAPI**:\n    * StarletteがUvicornを使用しており、それより速くできないのと同じように、**FastAPI**はStarletteを使用しているため、それより速くできません。\n    * FastAPIはStarletteの上に、より多くの機能を提供します。データバリデーションやシリアライゼーションのように、APIを構築する際にほとんど常に必要な機能です。また、それを使用することで、自動ドキュメント化を無料で利用できます（自動ドキュメントは実行中のアプリケーションにオーバーヘッドを追加せず、起動時に生成されます）。\n    * FastAPIを使用せず、Starletteを直接（またはSanic、Flask、Responderなど別のツールを）使用した場合、データバリデーションとシリアライゼーションをすべて自分で実装する必要があります。そのため、最終的なアプリケーションはFastAPIを使用して構築した場合と同じオーバーヘッドが発生します。そして多くの場合、このデータバリデーションとシリアライゼーションは、アプリケーションで書かれるコードの大部分になります。\n    * そのため、FastAPIを使用することで、開発時間、バグ、コード行数を節約でき、使用しない場合（あなたがそれをすべて自分のコードで実装する必要があるため）と比べて、同じパフォーマンス（またはそれ以上）を得られる可能性があります。\n    * FastAPIを比較する場合は、Flask-apispec、NestJS、Moltenなど、データバリデーション、シリアライゼーション、ドキュメント化を提供するwebアプリケーションフレームワーク（またはツール群）と比較してください。自動データバリデーション、シリアライゼーション、ドキュメント化が統合されたフレームワークです。\n"
  },
  {
    "path": "docs/ja/docs/deployment/cloud.md",
    "content": "# クラウドプロバイダへの FastAPI デプロイ { #deploy-fastapi-on-cloud-providers }\n\nFastAPI アプリケーションは、実質的にどのようなクラウドプロバイダでもデプロイできます。\n\n多くの場合、主要なクラウドプロバイダは FastAPI をデプロイするためのガイドを提供しています。\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** は、**FastAPI** の作者と同じチームによって作られています。\n\nAPI の**構築**、**デプロイ**、**アクセス**までのプロセスを、最小限の手間で効率化します。\n\nFastAPI でアプリを開発するときと同じ**開発者体験**を、クラウドへの**デプロイ**にももたらします。🎉\n\nFastAPI Cloud は、*FastAPI and friends* オープンソースプロジェクトの主要なスポンサーかつ資金提供元です。✨\n\n## クラウドプロバイダ - スポンサー { #cloud-providers-sponsors }\n\n他にもいくつかのクラウドプロバイダが ✨ [**FastAPI をスポンサーしています**](../help-fastapi.md#sponsor-the-author) ✨。🙇\n\nそれらのガイドを参考にし、サービスを試してみるのもよいでしょう:\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/ja/docs/deployment/concepts.md",
    "content": "# デプロイメントのコンセプト { #deployments-concepts }\n\n**FastAPI**を用いたアプリケーションをデプロイするとき、もしくはどのようなタイプのWeb APIであっても、おそらく気になるコンセプトがいくつかあります。\n\nそれらを活用することでアプリケーションを**デプロイするための最適な方法**を見つけることができます。\n\n重要なコンセプトのいくつかを紹介します:\n\n* セキュリティ - HTTPS\n* 起動時の実行\n* 再起動\n* レプリケーション（実行中のプロセス数）\n* メモリ\n* 開始前の事前のステップ\n\nこれらが**デプロイメント**にどのような影響を与えるかを見ていきましょう。\n\n最終的な目的は、**安全な方法で**APIクライアントに**サービスを提供**し、**中断を回避**するだけでなく、**計算リソース**（例えばリモートサーバー/仮想マシン）を可能な限り効率的に使用することです。 🚀\n\nこの章では前述した**コンセプト**についてそれぞれ説明します。\n\nこの説明を通して、普段とは非常に異なる環境や存在しないであろう**将来の**環境に対し、デプロイの方法を決める上で必要な**直感**を与えてくれることを願っています。\n\nこれらのコンセプトを意識することにより、**あなた自身のAPI**をデプロイするための最適な方法を**評価**し、**設計**することができるようになるでしょう。\n\n次の章では、FastAPIアプリケーションをデプロイするための**具体的なレシピ**を紹介します。\n\nしかし、今はこれらの重要な**コンセプトに基づくアイデア**を確認しましょう。これらのコンセプトは、他のどのタイプのWeb APIにも当てはまります。💡\n\n## セキュリティ - HTTPS { #security-https }\n\n[前チャプターのHTTPSについて](https.md)では、HTTPSがどのようにAPIを暗号化するのかについて学びました。\n\n通常、アプリケーションサーバにとって**外部の**コンポーネントである**TLS Termination Proxy**によって提供されることが一般的です。このプロキシは通信の暗号化を担当します。\n\nさらに、HTTPS証明書の更新を担当するものが必要で、同じコンポーネントが担当することもあれば、別のコンポーネントが担当することもあります。\n\n### HTTPS 用ツールの例 { #example-tools-for-https }\nTLS Termination Proxyとして使用できるツールには以下のようなものがあります：\n\n* Traefik\n    * 証明書の更新を自動的に処理 ✨\n* Caddy\n    * 証明書の更新を自動的に処理 ✨\n* Nginx\n    * 証明書更新のために Certbot のような外部コンポーネントを使用\n* HAProxy\n    * 証明書更新のために Certbot のような外部コンポーネントを使用\n* Nginx のような Ingress Controller を持つ Kubernetes\n    * 証明書の更新に cert-manager のような外部コンポーネントを使用\n* クラウド・プロバイダーがサービスの一部として内部的に処理（下記を参照👇）\n\nもう1つの選択肢は、HTTPSのセットアップを含んだより多くの作業を行う**クラウド・サービス**を利用することです。 このサービスには制限があったり、料金が高くなったりする可能性があります。しかしその場合、TLS Termination Proxyを自分でセットアップする必要はないです。\n\n次の章で具体例をいくつか紹介します。\n\n---\n\n次に考慮すべきコンセプトは、実際のAPIを実行するプログラム（例：Uvicorn）に関連するものすべてです。\n\n## プログラム と プロセス { #program-and-process }\n\n私たちは「**プロセス**」という言葉についてたくさん話すので、その意味や「**プログラム**」という言葉との違いを明確にしておくと便利です。\n\n### プログラムとは何か { #what-is-a-program }\n\n**プログラム**という言葉は、一般的にいろいろなものを表現するのに使われます：\n\n* プログラマが書く**コード**、**Pythonファイル**\n* OSによって実行することができるファイル（例: `python`, `python.exe` or `uvicorn`）\n* OS上で**実行**している間、CPUを使用し、メモリ上に何かを保存する特定のプログラム（**プロセス**とも呼ばれる）\n\n### プロセスとは何か { #what-is-a-process }\n\n**プロセス**という言葉は通常、より具体的な意味で使われ、OSで実行されているものだけを指します（先ほどの最後の説明のように）：\n\n* OS上で**実行**している特定のプログラム\n    * これはファイルやコードを指すのではなく、OSによって**実行**され、管理されているものを指します。\n* どんなプログラムやコードも、それが**実行されているときにだけ機能**します。つまり、**プロセスとして実行されているときだけ**です。\n* プロセスは、ユーザーにあるいはOSによって、 **終了**（あるいは \"kill\"）させることができます。その時点で、プロセスは実行/実行されることを停止し、それ以降は**何もできなくなります**。\n* コンピュータで実行されている各アプリケーションは、実行中のプログラムや各ウィンドウなど、その背後にいくつかのプロセスを持っています。そして通常、コンピュータが起動している間、**多くのプロセスが**同時に実行されています。\n* **同じプログラム**の**複数のプロセス**が同時に実行されていることがあります。\n\nOSの「タスク・マネージャー」や「システム・モニター」（または同様のツール）を確認すれば、これらのプロセスの多くが実行されているの見ることができるでしょう。\n\n例えば、同じブラウザプログラム（Firefox、Chrome、Edgeなど）を実行しているプロセスが複数あることがわかります。通常、1つのタブにつき1つのプロセスが実行され、さらに他のプロセスも実行されます。\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\nさて、**プロセス**と**プログラム**という用語の違いを確認したところで、デプロイメントについて話を続けます。\n\n## 起動時の実行 { #running-on-startup }\n\nほとんどの場合、Web APIを作成するときは、クライアントがいつでもアクセスできるように、**常に**中断されることなく**実行される**ことを望みます。もちろん、特定の状況でのみ実行させたい特別な理由がある場合は別ですが、その時間のほとんどは、常に実行され、**利用可能**であることを望みます。\n\n### リモートサーバー上での実行 { #in-a-remote-server }\n\nリモートサーバー（クラウドサーバー、仮想マシンなど）をセットアップするときにできる最も簡単なことは、ローカルで開発するときと同じように、`fastapi run`（Uvicornを使用します）や同様のものを手動で実行することです。\n\nそしてこれは動作し、**開発中**には役に立つでしょう。\n\nしかし、サーバーへの接続が切れた場合、**実行中のプロセス**はおそらくダウンしてしまうでしょう。\n\nそしてサーバーが再起動された場合（アップデートやクラウドプロバイダーからのマイグレーションの後など）、おそらくあなたはそれに**気づかないでしょう**。そのため、プロセスを手動で再起動しなければならないことすら気づかないでしょう。つまり、APIはダウンしたままなのです。😱\n\n### 起動時に自動的に実行 { #run-automatically-on-startup }\n\n一般的に、サーバープログラム（Uvicornなど）はサーバー起動時に自動的に開始され、**人の介入**を必要とせずに、APIと一緒にプロセスが常に実行されるようにしたいと思われます（UvicornがFastAPIアプリを実行するなど）。\n\n### 別のプログラムの用意 { #separate-program }\n\nこれを実現するために、通常は**別のプログラム**を用意し、起動時にアプリケーションが実行されるようにします。そして多くの場合、他のコンポーネントやアプリケーション、例えばデータベースも実行されるようにします。\n\n### 起動時に実行するツールの例 { #example-tools-to-run-at-startup }\n\n実行するツールの例をいくつか挙げます:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Swarm モードによる Docker\n* Systemd\n* Supervisor\n* クラウドプロバイダーがサービスの一部として内部的に処理\n* そのほか...\n\n次の章で、より具体的な例を挙げていきます。\n\n## 再起動 { #restarts }\n\n起動時にアプリケーションが実行されることを確認するのと同様に、失敗後にアプリケーションが**再起動**されることも確認したいと思われます。\n\n### 我々は間違いを犯す { #we-make-mistakes }\n\n私たち人間は常に**間違い**を犯します。ソフトウェアには、ほとんど常に**バグ**があらゆる箇所に隠されています。🐛\n\nそして私たち開発者は、それらのバグを見つけたり新しい機能を実装したりしながらコードを改善し続けます（新しいバグも追加してしまうかもしれません😅）。\n\n### 小さなエラーは自動的に処理される { #small-errors-automatically-handled }\n\nFastAPIでWeb APIを構築する際に、コードにエラーがある場合、FastAPIは通常、エラーを引き起こした単一のリクエストにエラーを含めます。🛡\n\nクライアントはそのリクエストに対して**500 Internal Server Error**を受け取りますが、アプリケーションは完全にクラッシュするのではなく、次のリクエストのために動作を続けます。\n\n### 重大なエラー - クラッシュ { #bigger-errors-crashes }\n\nしかしながら、**アプリケーション全体をクラッシュさせるようなコードを書いて**UvicornとPythonをクラッシュさせるようなケースもあるかもしれません。💥\n\nそれでも、ある箇所でエラーが発生したからといって、アプリケーションを停止させたままにしたくないでしょう。 少なくとも壊れていない*path operation*については、**実行し続けたい**はずです。\n\n### クラッシュ後の再起動 { #restart-after-crash }\n\nしかし、実行中の**プロセス**をクラッシュさせるような本当にひどいエラーの場合、少なくとも2〜3回ほどプロセスを**再起動**させる外部コンポーネントが必要でしょう。\n\n/// tip | 豆知識\n\n...とはいえ、アプリケーション全体が**すぐにクラッシュする**のであれば、いつまでも再起動し続けるのは意味がないでしょう。しかし、その場合はおそらく開発中か少なくともデプロイ直後に気づくと思われます。\n\nそこで、**将来**クラッシュする可能性があり、それでも再スタートさせることに意味があるような、主なケースに焦点を当ててみます。\n\n///\n\nあなたはおそらく**外部コンポーネント**がアプリケーションの再起動を担当することを望むと考えます。 なぜなら、その時点でUvicornとPythonを使った同じアプリケーションはすでにクラッシュしており、同じアプリケーションの同じコードに対して何もできないためです。\n\n### 自動的に再起動するツールの例 { #example-tools-to-restart-automatically }\n\nほとんどの場合、前述した**起動時にプログラムを実行する**ために使用されるツールは、自動で**再起動**することにも利用されます。\n\n例えば、次のようなものがあります：\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Swarm モードによる Docker\n* Systemd\n* Supervisor\n* クラウドプロバイダーがサービスの一部として内部的に処理\n* そのほか...\n\n## レプリケーション - プロセスとメモリ { #replication-processes-and-memory }\n\nFastAPI アプリケーションでは、Uvicorn を実行する `fastapi` コマンドのようなサーバープログラムを使用し、**1つのプロセス**で1度に複数のクライアントに同時に対応できます。\n\nしかし、多くの場合、複数のワーカー・プロセスを同時に実行したいと考えるでしょう。\n\n### 複数のプロセス - Worker { #multiple-processes-workers }\n\nクライアントの数が単一のプロセスで処理できる数を超えており（たとえば仮想マシンがそれほど大きくない場合）、かつサーバーの CPU に**複数のコア**がある場合、同じアプリケーションで同時に**複数のプロセス**を実行させ、すべてのリクエストを分散させることができます。\n\n同じAPIプログラムの**複数のプロセス**を実行する場合、それらは一般的に**Worker／ワーカー**と呼ばれます。\n\n### ワーカー・プロセス と ポート { #worker-processes-and-ports }\n\n[HTTPSについて](https.md)のドキュメントで、1つのサーバーで1つのポートとIPアドレスの組み合わせでリッスンできるのは1つのプロセスだけであることを覚えていますでしょうか？\n\nこれはいまだに同じです。\n\nそのため、**複数のプロセス**を同時に持つには**ポートでリッスンしている単一のプロセス**が必要であり、それが何らかの方法で各ワーカー・プロセスに通信を送信することが求められます。\n\n### プロセスあたりのメモリ { #memory-per-process }\n\nさて、プログラムがメモリにロードする際には、例えば機械学習モデルや大きなファイルの内容を変数に入れたりする場合では、**サーバーのメモリ（RAM）**を少し消費します。\n\nそして複数のプロセスは通常、**メモリを共有しません**。これは、実行中の各プロセスがそれぞれ独自の変数やメモリ等を持っていることを意味します。つまり、コード内で大量のメモリを消費している場合、**各プロセス**は同等の量のメモリを消費することになります。\n\n### サーバーメモリ { #server-memory }\n\n例えば、あなたのコードが **1GBのサイズの機械学習モデル**をロードする場合、APIで1つのプロセスを実行すると、少なくとも1GBのRAMを消費します。\n\nまた、**4つのプロセス**（4つのワーカー）を起動すると、それぞれが1GBのRAMを消費します。つまり、合計でAPIは**4GBのRAM**を消費することになります。\n\nリモートサーバーや仮想マシンのRAMが3GBしかない場合、4GB以上のRAMをロードしようとすると問題が発生します。🚨\n\n### 複数プロセス - 例 { #multiple-processes-an-example }\n\nこの例では、2つの**ワーカー・プロセス**を起動し制御する**マネージャー・ プロセス**があります。\n\nこのマネージャー・ プロセスは、おそらくIPの**ポート**でリッスンしているものです。そして、すべての通信をワーカー・プロセスに転送します。\n\nこれらのワーカー・プロセスは、アプリケーションを実行するものであり、**リクエスト**を受けて**レスポンス**を返すための主要な計算を行い、あなたが変数に入れたものは何でもRAMにロードします。\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\nそしてもちろん、同じマシンでは、あなたのアプリケーションとは別に、**他のプロセス**も実行されているでしょう。\n\n興味深いことに、各プロセスが使用する**CPU**の割合は時間とともに大きく**変動**する可能性がありますが、**メモリ（RAM）**は通常、多かれ少なかれ**安定**します。\n\n毎回同程度の計算を行うAPIがあり、多くのクライアントがいるのであれば、**CPU使用率**もおそらく**安定**するでしょう（常に急激に上下するのではなく）。\n\n### レプリケーション・ツールと戦略の例 { #examples-of-replication-tools-and-strategies }\n\nこれを実現するにはいくつかのアプローチがありますが、具体的な戦略については次の章(Dockerやコンテナの章など)で詳しく説明します。\n\n考慮すべき主な制約は、**パブリックIP**の**ポート**を処理する**単一の**コンポーネントが存在しなければならないということです。\n\nそして、レプリケートされた**プロセス/ワーカー**に通信を**送信**する方法を持つ必要があります。\n\n考えられる組み合わせと戦略をいくつか紹介します：\n\n* `--workers` を指定した **Uvicorn**\n    * 1つのUvicornの**プロセスマネージャー**が**IP**と**ポート**をリッスンし、**複数のUvicornワーカー・プロセス**を起動する。\n* **Kubernetes**やその他の分散**コンテナ・システム**\n    * **Kubernetes**レイヤーの何かが**IP**と**ポート**をリッスンする。レプリケーションは、**複数のコンテナ**にそれぞれ**1つのUvicornプロセス**を実行させることで行われる。\n* **クラウド・サービス**によるレプリケーション\n    * クラウド・サービスはおそらく**あなたのためにレプリケーションを処理**します。**実行するプロセス**や使用する**コンテナイメージ**を定義できるかもしれませんが、いずれにせよ、それはおそらく**単一のUvicornプロセス**であり、クラウドサービスはそのレプリケーションを担当するでしょう。\n\n/// tip | 豆知識\n\nこれらの**コンテナ**やDockerそしてKubernetesに関する項目が、まだあまり意味をなしていなくても心配しないでください。\n\nコンテナ・イメージ、Docker、Kubernetesなどについては、将来の章で詳しく説明します: [コンテナ内のFastAPI - Docker](docker.md).\n\n///\n\n## 開始前の事前のステップ { #previous-steps-before-starting }\n\nアプリケーションを**開始する前**に、いくつかのステップを実行したい場合が多くあります。\n\n例えば、**データベース・マイグレーション** を実行したいかもしれません。\n\nしかしほとんどの場合、これらの手順を**1度**に実行したいと考えるでしょう。\n\nそのため、アプリケーションを開始する前の**事前のステップ**を実行する**単一のプロセス**を用意したいと思われます。\n\nそして、それらの事前のステップを実行しているのが単一のプロセスであることを確認する必要があります。このことはその後アプリケーション自体のために**複数のプロセス**（複数のワーカー）を起動した場合も同様です。\n\nこれらのステップが**複数のプロセス**によって実行された場合、**並列**に実行されることによって作業が**重複**することになります。そして、もしそのステップがデータベースのマイグレーションのような繊細なものであった場合、互いに競合を引き起こす可能性があります。\n\nもちろん、事前のステップを何度も実行しても問題がない場合もあり、その際は対処がかなり楽になります。\n\n/// tip | 豆知識\n\nまた、セットアップによっては、アプリケーションを開始する前の**事前のステップ**が必要ない場合もあることを覚えておいてください。\n\nその場合は、このようなことを心配する必要はないです。🤷\n\n///\n\n### 事前ステップの戦略例 { #examples-of-previous-steps-strategies }\n\nこれは**システムを**デプロイする方法に**大きく依存**するだろうし、おそらくプログラムの起動方法や再起動の処理などにも関係してくるでしょう。\n\n考えられるアイデアをいくつか挙げてみます：\n\n* アプリコンテナの前に実行されるKubernetesのInitコンテナ\n* 事前のステップを実行し、アプリケーションを起動するbashスクリプト\n    * 利用するbashスクリプトを起動／再起動したり、エラーを検出したりする方法は以前として必要になるでしょう。\n\n/// tip | 豆知識\n\nコンテナを使った具体的な例については、将来の章で紹介します: [コンテナ内のFastAPI - Docker](docker.md).\n\n///\n\n## リソースの利用 { #resource-utilization }\n\nあなたのサーバーは**リソース**であり、プログラムを実行しCPUの計算時間や利用可能なRAMメモリを消費または**利用**することができます。\n\nシステムリソースをどれくらい消費／利用したいですか？ 「少ない方が良い」と考えるのは簡単かもしれないですが、実際には、**クラッシュせずに可能な限り**最大限に活用したいでしょう。\n\n3台のサーバーにお金を払っているにも関わらず、そのRAMとCPUを少ししか使っていないとしたら、おそらく**お金を無駄にしている** 💸、おそらく**サーバーの電力を無駄にしている** 🌎ことになるでしょう。\n\nその場合は、サーバーを2台だけにして、そのリソース（CPU、メモリ、ディスク、ネットワーク帯域幅など）をより高い割合で使用する方がよいでしょう。\n\n一方、2台のサーバーがあり、そのCPUとRAMの**100%を使用している**場合、ある時点で1つのプロセスがより多くのメモリを要求し、サーバーはディスクを「メモリ」として使用しないといけません。（何千倍も遅くなる可能性があります。）\nもしくは**クラッシュ**することもあれば、あるいはあるプロセスが何らかの計算をする必要があり、そしてCPUが再び空くまで待たなければならないかもしれません。\n\nこの場合、**1つ余分なサーバー**を用意し、その上でいくつかのプロセスを実行し、すべてのサーバーが**十分なRAMとCPU時間を持つようにする**のがよいでしょう。\n\nまた、何らかの理由でAPIの利用が急増する可能性もあります。もしかしたらそれが流行ったのかもしれないし、他のサービスやボットが使い始めたのかもしれないです。そのような場合に備えて、余分なリソースを用意しておくと安心でしょう。\n\n例えば、リソース使用率の**50%から90%の範囲**で**任意の数字**をターゲットとすることができます。\n\n重要なのは、デプロイメントを微調整するためにターゲットを設定し測定することが、おそらく使用したい主要な要素であることです。\n\n`htop`のような単純なツールを使って、サーバーで使用されているCPUやRAM、あるいは各プロセスで使用されている量を見ることができます。あるいは、より複雑な監視ツールを使って、サーバに分散して使用することもできます。\n\n## まとめ { #recap }\n\nアプリケーションのデプロイ方法を決定する際に、考慮すべきであろう主要なコンセプトのいくつかを紹介していきました：\n\n* セキュリティ - HTTPS\n* 起動時の実行\n* 再起動\n* レプリケーション（実行中のプロセス数）\n* メモリ\n* 開始前の事前ステップ\n\nこれらの考え方とその適用方法を理解することで、デプロイメントを設定したり調整したりする際に必要な直感的な判断ができるようになるはずです。🤓\n\n次のセクションでは、あなたが取り得る戦略について、より具体的な例を挙げます。🚀\n"
  },
  {
    "path": "docs/ja/docs/deployment/docker.md",
    "content": "# コンテナ内のFastAPI - Docker { #fastapi-in-containers-docker }\n\nFastAPIアプリケーションをデプロイする場合、一般的なアプローチは**Linuxコンテナ・イメージ**をビルドすることです。基本的には [**Docker**](https://www.docker.com/) を用いて行われます。生成されたコンテナ・イメージは、いくつかの方法のいずれかでデプロイできます。\n\nLinuxコンテナの使用には、**セキュリティ**、**反復可能性（レプリカビリティ）**、**シンプリシティ**など、いくつかの利点があります。\n\n/// tip | 豆知識\n\nお急ぎで、すでにこれらの情報をご存じですか？ [以下の`Dockerfile`の箇所👇](#build-a-docker-image-for-fastapi)へジャンプしてください。\n\n///\n\n<details>\n<summary>Dockerfile Preview 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# If running behind a proxy like Nginx or Traefik add --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## コンテナとは何か { #what-is-a-container }\n\nコンテナ（主にLinuxコンテナ）は、同じシステム内の他のコンテナ（他のアプリケーションやコンポーネント）から隔離された状態を保ちながら、すべての依存関係や必要なファイルを含むアプリケーションをパッケージ化する非常に**軽量**な方法です。\n\nLinuxコンテナは、ホスト（マシン、仮想マシン、クラウドサーバーなど）の同じLinuxカーネルを使用して実行されます。これは、（OS全体をエミュレートする完全な仮想マシンと比べて）非常に軽量であることを意味します。\n\nこのように、コンテナは**リソースをほとんど消費しません**が、プロセスを直接実行するのに匹敵する量です（仮想マシンはもっと消費します）。\n\nコンテナはまた、独自の**分離された**実行プロセス（通常は1つのプロセスのみ）や、ファイルシステム、ネットワークを持ちます。 このことはデプロイ、セキュリティ、開発などを簡素化させます。\n\n## コンテナ・イメージとは何か { #what-is-a-container-image }\n\n**コンテナ**は、**コンテナ・イメージ**から実行されます。\n\nコンテナ・イメージは、コンテナ内に存在すべきすべてのファイルや環境変数、そしてデフォルトのコマンド/プログラムを**静的に**バージョン化したものです。 ここでの**静的**とは、コンテナ**イメージ**は実行されておらず、パッケージ化されたファイルとメタデータのみであることを意味します。\n\n保存された静的コンテンツである「**コンテナイメージ**」とは対照的に、「**コンテナ**」は通常、実行中のインスタンス、つまり**実行**されているものを指します。\n\n**コンテナ**が起動され実行されるとき（**コンテナイメージ**から起動されるとき）、ファイルや環境変数などが作成されたり変更されたりする可能性があります。これらの変更はそのコンテナ内にのみ存在しますが、基盤となるコンテナ・イメージには残りません（ディスクに保存されません）。\n\nコンテナイメージは **プログラム** ファイルやその内容、例えば `python` と `main.py` ファイルに匹敵します。\n\nそして、**コンテナ**自体は（**コンテナイメージ**とは対照的に）イメージをもとにした実際の実行中のインスタンスであり、**プロセス**に匹敵します。実際、コンテナが実行されているのは、**プロセスが実行されている**ときだけです（通常は単一のプロセスだけです）。 コンテナ内で実行中のプロセスがない場合、コンテナは停止します。\n\n## コンテナ・イメージ { #container-images }\n\nDockerは、**コンテナ・イメージ**と**コンテナ**を作成・管理するための主要なツールの1つです。\n\nそして、多くのツールや環境、データベース、アプリケーションに対応している予め作成された**公式のコンテナ・イメージ**をパブリックに提供している [Docker Hub](https://hub.docker.com/) というものがあります。\n\n例えば、公式イメージの1つに [Python Image](https://hub.docker.com/_/python) があります。\n\nその他にも、データベースなどさまざまなイメージがあります：\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis), etc.\n\n予め作成されたコンテナ・イメージを使用することで、異なるツールを**組み合わせて**使用することが非常に簡単になります。例えば、新しいデータベースを試す場合に特に便利です。ほとんどの場合、**公式イメージ**を使い、環境変数で設定するだけで良いです。\n\nそうすれば多くの場合、コンテナとDockerについて学び、その知識をさまざまなツールやコンポーネントによって再利用することができます。\n\nつまり、データベース、Pythonアプリケーション、Reactフロントエンド・アプリケーションを備えたウェブ・サーバーなど、さまざまなものを**複数のコンテナ**で実行し、それらを内部ネットワーク経由で接続します。\n\nすべてのコンテナ管理システム（DockerやKubernetesなど）には、こうしたネットワーキング機能が統合されています。\n\n## コンテナとプロセス { #containers-and-processes }\n\n通常、**コンテナ・イメージ**はそのメタデータに**コンテナ**の起動時に実行されるデフォルトのプログラムまたはコマンドと、そのプログラムに渡されるパラメータを含みます。コマンドラインでの操作とよく似ています。\n\n**コンテナ**が起動されると、そのコマンド/プログラムが実行されます（ただし、別のコマンド/プログラムをオーバーライドして実行させることもできます）。\n\nコンテナは、**メイン・プロセス**（コマンドまたはプログラム）が実行されている限り実行されます。\n\nコンテナは通常**1つのプロセス**を持ちますが、メイン・プロセスからサブ・プロセスを起動することも可能で、そうすれば同じコンテナ内に**複数のプロセス**を持つことになります。\n\nしかし、**少なくとも1つの実行中のプロセス**がなければ、実行中のコンテナを持つことはできないです。メイン・プロセスが停止すれば、コンテナも停止します。\n\n## FastAPI用のDockerイメージをビルドする { #build-a-docker-image-for-fastapi }\n\nということで、何か作りましょう！🚀\n\nFastAPI用の**Dockerイメージ**を、**公式Python**イメージに基づいて**ゼロから**ビルドする方法をお見せします。\n\nこれは**ほとんどの場合**にやりたいことです。例えば：\n\n* **Kubernetes**または同様のツールを使用する場合\n* **Raspberry Pi**で実行する場合\n* コンテナ・イメージを実行してくれるクラウド・サービスなどを利用する場合\n\n### パッケージ要件 { #package-requirements }\n\nアプリケーションの**パッケージ要件**は通常、何らかのファイルに記述されているはずです。\n\nパッケージ要件は主に**インストール**するために使用するツールに依存するでしょう。\n\n最も一般的な方法は、`requirements.txt` ファイルにパッケージ名とそのバージョンを 1 行ずつ書くことです。\n\nもちろん、[FastAPI バージョンについて](versions.md)で読んだのと同じアイデアを使用して、バージョンの範囲を設定します。\n\n例えば、`requirements.txt` は次のようになります：\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\nそして通常、例えば `pip` を使ってこれらのパッケージの依存関係をインストールします：\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info | 情報\n\nパッケージの依存関係を定義しインストールするためのフォーマットやツールは他にもあります。\n\n///\n\n### **FastAPI**コードを作成する { #create-the-fastapi-code }\n\n* `app` ディレクトリを作成し、その中に入ります。\n* 空のファイル `__init__.py` を作成します。\n* 次の内容で `main.py` ファイルを作成します：\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\n同じプロジェクト・ディレクトリに`Dockerfile`というファイルを作成します：\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. 公式のPythonベースイメージから始めます\n\n2. 現在の作業ディレクトリを `/code` に設定します\n\n    ここに `requirements.txt` ファイルと `app` ディレクトリを置きます。\n\n3. 要件が書かれたファイルを `/code` ディレクトリにコピーします\n\n    残りのコードではなく、最初に必要なファイルだけをコピーしてください。\n\n    このファイルは**頻繁には変更されない**ので、Dockerはこのステップではそれを検知し**キャッシュ**を使用し、次のステップでもキャッシュを有効にします。\n\n4. 要件ファイルにあるパッケージの依存関係をインストールします\n\n    `--no-cache-dir` オプションはダウンロードしたパッケージをローカルに保存しないように `pip` に指示します。これは、同じパッケージをインストールするために `pip` を再度実行する場合にのみ有効ですが、コンテナで作業する場合はそうではないです。\n\n    /// note | 備考\n\n    `--no-cache-dir`は`pip`に関連しているだけで、Dockerやコンテナとは何の関係もないです。\n\n    ///\n\n    `--upgrade` オプションは、パッケージが既にインストールされている場合、`pip` にアップグレードするように指示します。\n\n    何故ならファイルをコピーする前のステップは**Dockerキャッシュ**によって検出される可能性があるためであり、このステップも利用可能な場合は**Dockerキャッシュ**を使用します。\n\n    このステップでキャッシュを使用すると、開発中にイメージを何度もビルドする際に、**毎回**すべての依存関係を**ダウンロードしてインストールする**代わりに多くの**時間**を**節約**できます。\n\n5. `./app` ディレクトリを `/code` ディレクトリの中にコピーする。\n\n    これには**最も頻繁に変更される**すべてのコードが含まれているため、Dockerの**キャッシュ**は**これ以降のステップ**に簡単に使用されることはありません。\n\n    そのため、コンテナイメージのビルド時間を最適化するために、`Dockerfile`の **最後** にこれを置くことが重要です。\n\n6. 内部でUvicornを使用する `fastapi run` を使うための**コマンド**を設定します\n\n    `CMD` は文字列のリストを取り、それぞれの文字列はスペースで区切られたコマンドラインに入力するものです。\n\n    このコマンドは **現在の作業ディレクトリ**から実行され、上記の `WORKDIR /code` にて設定した `/code` ディレクトリと同じです。\n\n/// tip | 豆知識\n\nコード内の各番号バブルをクリックして、各行が何をするのかをレビューしてください。👆\n\n///\n\n/// warning | 注意\n\n以下で説明する通り、`CMD` 命令は**常に** **exec形式**を使用してください。\n\n///\n\n#### `CMD` を使う - Exec形式 { #use-cmd-exec-form }\n\nDocker命令 [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) は2つの形式で書けます：\n\n✅ **Exec** 形式：\n\n```Dockerfile\n# ✅ Do this\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ **Shell** 形式：\n\n```Dockerfile\n# ⛔️ Don't do this\nCMD fastapi run app/main.py --port 80\n```\n\nFastAPIが正常にシャットダウンでき、[lifespan events](../advanced/events.md)がトリガーされるように、常に **exec** 形式を使用してください。\n\n詳しくは、[shell形式とexec形式に関するDockerドキュメント](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form)をご覧ください。\n\nこれは `docker compose` を使用する場合にかなり目立つことがあります。より技術的な詳細は、このDocker ComposeのFAQセクションをご覧ください：[Why do my services take 10 seconds to recreate or stop?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop)。\n\n#### ディレクトリ構造 { #directory-structure }\n\nこれで、次のようなディレクトリ構造になるはずです：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### TLS Termination Proxyの裏側 { #behind-a-tls-termination-proxy }\n\nNginx や Traefik のような TLS Termination Proxy (ロードバランサ) の後ろでコンテナを動かしている場合は、`--proxy-headers`オプションを追加します。これにより、（FastAPI CLI経由で）Uvicornに対して、そのプロキシから送信されるヘッダを信頼し、アプリケーションがHTTPSの裏で実行されていることなどを示すよう指示します。\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Dockerキャッシュ { #docker-cache }\n\nこの`Dockerfile`には重要なトリックがあり、まず**依存関係だけのファイル**をコピーします。その理由を説明します。\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDockerや他のツールは、これらのコンテナイメージを**段階的に**ビルドし、**1つのレイヤーを他のレイヤーの上に**追加します。`Dockerfile`の先頭から開始し、`Dockerfile`の各命令によって作成されたファイルを追加していきます。\n\nDockerや同様のツールは、イメージをビルドする際に**内部キャッシュ**も使用します。前回コンテナイメージを構築したときからファイルが変更されていない場合、ファイルを再度コピーしてゼロから新しいレイヤーを作成する代わりに、**前回作成した同じレイヤーを再利用**します。\n\nただファイルのコピーを避けるだけではあまり改善されませんが、そのステップでキャッシュを利用したため、**次のステップ**でキャッシュを使うことができます。\n\n例えば、依存関係をインストールする命令のためにキャッシュを使うことができます：\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\nパッケージ要件のファイルは**頻繁に変更されることはありません**。そのため、そのファイルだけをコピーすることで、Dockerはそのステップでは**キャッシュ**を使用することができます。\n\nそして、Dockerは**次のステップのためにキャッシュ**を使用し、それらの依存関係をダウンロードしてインストールすることができます。そして、ここで**多くの時間を節約**します。✨ ...そして退屈な待ち時間を避けることができます。😪😆\n\nパッケージの依存関係をダウンロードしてインストールするには**数分**かかりますが、**キャッシュ**を使えば**せいぜい数秒**です。\n\n加えて、開発中にコンテナ・イメージを何度もビルドして、コードの変更が機能しているかどうかをチェックすることになるため、多くの時間を節約することができます。\n\nそして`Dockerfile`の最終行の近くですべてのコードをコピーします。この理由は、**最も頻繁に**変更されるものなので、このステップの後にあるものはほとんどキャッシュを使用することができないのためです。\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### Dockerイメージをビルドする { #build-the-docker-image }\n\nすべてのファイルが揃ったので、コンテナ・イメージをビルドしましょう。\n\n* プロジェクトディレクトリに移動します（`Dockerfile`がある場所で、`app`ディレクトリがあります）。\n* FastAPI イメージをビルドします：\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | 豆知識\n\n末尾の `.` に注目してほしいです。これは `./` と同じ意味です。 これはDockerにコンテナイメージのビルドに使用するディレクトリを指示します。\n\nこの場合、同じカレント・ディレクトリ(`.`)です。\n\n///\n\n### Dockerコンテナの起動する { #start-the-docker-container }\n\n* イメージに基づいてコンテナを実行します：\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## 確認する { #check-it }\n\nDockerコンテナの[http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) や [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (またはそれに相当するDockerホストを使用したもの）といったURLで確認できるはずです。\n\nアクセスすると以下のようなものが表示されます：\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## インタラクティブなAPIドキュメント { #interactive-api-docs }\n\nこれらのURLにもアクセスできます:  [http://192.168.99.100/docs](http://192.168.99.100/docs) や [http://127.0.0.1/docs](http://127.0.0.1/docs) (またはそれに相当するDockerホストを使用したもの）\n\nアクセスすると、自動対話型APIドキュメント（[Swagger UI](https://github.com/swagger-api/swagger-ui)が提供）が表示されます：\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## 代替のAPIドキュメント { #alternative-api-docs }\n\nまた、[http://192.168.99.100/redoc](http://192.168.99.100/redoc) や [http://127.0.0.1/redoc](http://127.0.0.1/redoc) (またはそれに相当するDockerホストを使用したもの）にもアクセスできます。\n\n代替の自動ドキュメント（[ReDoc](https://github.com/Rebilly/ReDoc)によって提供される）が表示されます：\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## 単一ファイルのFastAPIでDockerイメージをビルドする { #build-a-docker-image-with-a-single-file-fastapi }\n\nFastAPI が単一のファイル、例えば `./app` ディレクトリのない `main.py` の場合、ファイル構造は次のようになります：\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\nそうすれば、`Dockerfile`の中にファイルをコピーするために、対応するパスを変更するだけでよいです：\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. `main.py`ファイルを `/code` ディレクトリに直接コピーします（`./app` ディレクトリなし）。\n\n2. 単一ファイル `main.py` 内のアプリケーションを配信するために `fastapi run` を使用します。\n\n`fastapi run` にファイルを渡すと、それがパッケージの一部ではなく単一ファイルであることを自動的に検出し、インポートしてFastAPIアプリを配信する方法を判断します。😎\n\n## デプロイメントのコンセプト { #deployment-concepts }\n\nコンテナという観点から、[デプロイのコンセプト](concepts.md)に共通するいくつかについて、もう一度説明しましょう。\n\nコンテナは主に、アプリケーションの**ビルドとデプロイ**のプロセスを簡素化するためのツールですが、これらの**デプロイのコンセプト**を扱うための特定のアプローチを強制するものではなく、いくつかの戦略があります。\n\n**良いニュース**は、それぞれの異なる戦略には、すべてのデプロイメントのコンセプトをカバーする方法があるということです。🎉\n\nこれらの**デプロイメントのコンセプト**をコンテナの観点から見直してみましょう：\n\n* HTTPS\n* 起動時の実行\n* 再起動\n* レプリケーション（実行中のプロセス数）\n* メモリ\n* 開始前の事前ステップ\n\n## HTTPS { #https }\n\nFastAPI アプリケーションの **コンテナ・イメージ**（および後で実行中の **コンテナ**）だけに焦点を当てると、通常、HTTPSは別のツールを用いて**外部で**処理されます。\n\n例えば [Traefik](https://traefik.io/) のように、**HTTPS**と**証明書**の**自動**取得を扱う別のコンテナである可能性もあります。\n\n/// tip | 豆知識\n\nTraefikはDockerやKubernetesなどと統合されているので、コンテナ用のHTTPSの設定や構成はとても簡単です。\n\n///\n\nあるいは、（コンテナ内でアプリケーションを実行しながら）クラウド・プロバイダーがサービスの1つとしてHTTPSを処理することもできます。\n\n## 起動時および再起動時の実行 { #running-on-startup-and-restarts }\n\n通常、コンテナの**起動と実行**を担当する別のツールがあります。\n\nそれは直接**Docker**であったり、**Docker Compose**であったり、**Kubernetes**であったり、**クラウドサービス**であったりします。\n\nほとんどの場合（またはすべての場合）、起動時にコンテナを実行し、失敗時に再起動を有効にする簡単なオプションがあります。例えばDockerでは、コマンドラインオプションの`--restart`が該当します。\n\nコンテナを使わなければ、アプリケーションを起動時や再起動時に実行させるのは面倒で難しいかもしれません。しかし、**コンテナ**で作業する場合、ほとんどのケースでその機能はデフォルトで含まれています。✨\n\n## レプリケーション - プロセス数 { #replication-number-of-processes }\n\n**Kubernetes** や Docker Swarm モード、Nomad、あるいは複数のマシン上で分散コンテナを管理するための同様の複雑なシステムを使ってマシンの<dfn title=\"ある方法で接続され、連携して動作するように構成されたマシンの集まり\">クラスタ</dfn>を構成している場合、 各コンテナで（Workerを持つUvicornのような）**プロセスマネージャ**を使用する代わりに、**クラスター・レベル**で**レプリケーション**を処理したいと思うでしょう。\n\nKubernetesのような分散コンテナ管理システムの1つは通常、入ってくるリクエストの**ロードバランシング**をサポートしながら、**コンテナのレプリケーション**を処理する統合された方法を持っています。このことはすべて**クラスタレベル**にてです。\n\nそのような場合、[上記の説明](#dockerfile)のように**Dockerイメージをゼロから**ビルドし、依存関係をインストールして、**単一のUvicornプロセス**を実行したいでしょう。複数のUvicornワーカーを使う代わりにです。\n\n### ロードバランサー { #load-balancer }\n\nコンテナを使用する場合、通常はメイン・ポート**でリスニング**しているコンポーネントがあるはずです。それはおそらく、**HTTPS**を処理するための**TLS Termination Proxy**でもある別のコンテナであったり、同様のツールであったりするでしょう。\n\nこのコンポーネントはリクエストの **負荷** を受け、 (うまくいけば) その負荷を**バランスよく** ワーカーに分配するので、一般に **ロードバランサ** とも呼ばれます。\n\n/// tip | 豆知識\n\nHTTPSに使われるものと同じ**TLS Termination Proxy**コンポーネントは、おそらく**ロードバランサー**にもなるでしょう。\n\n///\n\nそしてコンテナで作業する場合、コンテナの起動と管理に使用する同じシステムには、**ロードバランサー**（**TLS Termination Proxy**の可能性もある）から**ネットワーク通信**（HTTPリクエストなど）をアプリのあるコンテナ（複数可）に送信するための内部ツールが既にあるはずです。\n\n### 1つのロードバランサー - 複数のワーカーコンテナー { #one-load-balancer-multiple-worker-containers }\n\n**Kubernetes**や同様の分散コンテナ管理システムで作業する場合、その内部のネットワーキングのメカニズムを使用することで、メインの**ポート**でリッスンしている単一の**ロードバランサー**が、アプリを実行している可能性のある**複数のコンテナ**に通信（リクエスト）を送信できるようになります。\n\nアプリを実行するこれらのコンテナには、通常**1つのプロセス**（たとえば、FastAPIアプリケーションを実行するUvicornプロセス）があります。これらはすべて**同一のコンテナ**であり同じものを実行しますが、それぞれが独自のプロセスやメモリなどを持ちます。そうすることで、CPUの**異なるコア**、あるいは**異なるマシン**での**並列化**を利用できます。\n\nそして、**ロードバランサー**を備えた分散コンテナシステムは、**順番に**あなたのアプリを含む各コンテナに**リクエストを分配**します。つまり、各リクエストは、あなたのアプリを実行している複数の**レプリケートされたコンテナ**の1つによって処理されます。\n\nそして通常、この**ロードバランサー**は、クラスタ内の*他の*アプリケーション（例えば、異なるドメインや異なるURLパスのプレフィックスの配下）へのリクエストを処理することができ、その通信をクラスタ内で実行されている*他の*アプリケーションのための適切なコンテナに送信します。\n\n### 1コンテナにつき1プロセス { #one-process-per-container }\n\nこの種のシナリオでは、すでにクラスタ・レベルでレプリケーションを処理しているため、おそらくコンテナごとに**単一の（Uvicorn）プロセス**を持ちたいでしょう。\n\nこの場合、例えばコマンドラインオプションの `--workers` で、コンテナ内に複数のワーカーを持つことは**避けたい**でしょう。**コンテナごとにUvicornのプロセスは1つだけ**にしたいでしょう（おそらく複数のコンテナが必要でしょう）。\n\n（複数のワーカーの場合のように）コンテナ内に別のプロセスマネージャーを持つことは、クラスターシステムですでに対処しているであろう**不要な複雑さ**を追加するだけです。\n\n### 複数プロセスのコンテナと特殊なケース { #containers-with-multiple-processes-and-special-cases }\n\nもちろん、**特殊なケース**として、**コンテナ**内で複数の**Uvicornワーカープロセス**を起動させたい場合があります。\n\nそのような場合、`--workers` コマンドラインオプションを使って、実行したいワーカー数を設定できます：\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. ここでは `--workers` コマンドラインオプションを使って、ワーカー数を4に設定しています。\n\n以下は、それが理にかなっている場合の例です：\n\n#### シンプルなアプリ { #a-simple-app }\n\nアプリケーションが、クラスタではなく**単一サーバ**で実行できるほど**シンプル**である場合、コンテナ内にプロセスマネージャが欲しくなることがあります。\n\n#### Docker Compose { #docker-compose }\n\nDocker Composeで**単一サーバ**（クラスタではない）にデプロイすることもできますので、共有ネットワークと**ロードバランシング**を維持しながら（Docker Composeで）コンテナのレプリケーションを管理する簡単な方法はないでしょう。\n\nその場合、**単一のコンテナ**で、**プロセスマネージャ**が内部で**複数のワーカープロセス**を起動するようにします。\n\n---\n\n重要なのは、これらのどれも、盲目的に従わなければならない「**絶対的なルール**」ではないということです。これらのアイデアは、**あなた自身のユースケース**を評価し、あなたのシステムに最適なアプローチを決定するために使用できます。次の概念をどう管理するかを確認してください：\n\n* セキュリティ - HTTPS\n* 起動時の実行\n* 再起動\n* レプリケーション（実行中のプロセス数）\n* メモリ\n* 開始前の事前ステップ\n\n## メモリ { #memory }\n\nコンテナごとに**単一のプロセスを実行する**と、それらのコンテナ（レプリケートされている場合は1つ以上）によって消費される多かれ少なかれ明確に定義された、安定し制限された量のメモリを持つことになります。\n\nそして、コンテナ管理システム（**Kubernetes**など）の設定で、同じメモリ制限と要件を設定することができます。\n\nそうすれば、コンテナが必要とするメモリ量とクラスタ内のマシンで利用可能なメモリ量を考慮して、**利用可能なマシン**に**コンテナ**をレプリケートできるようになります。\n\nアプリケーションが**シンプル**なものであれば、これはおそらく**問題にはならない**でしょうし、ハードなメモリ制限を指定する必要はないかもしれないです。\n\nしかし、**多くのメモリを使用**している場合（たとえば**機械学習**モデルなど）、どれだけのメモリを消費しているかを確認し、**各マシンで実行するコンテナの数**を調整する必要があります（そしておそらくクラスタにマシンを追加します）。\n\n**コンテナごとに複数のプロセス**を実行する場合、起動するプロセスの数が**利用可能なメモリ以上に消費しない**ようにする必要があります。\n\n## 開始前の事前ステップとコンテナ { #previous-steps-before-starting-and-containers }\n\nコンテナ（DockerやKubernetesなど）を使っている場合、主に2つのアプローチがあります。\n\n### 複数のコンテナ { #multiple-containers }\n\n複数の**コンテナ**があり、おそらくそれぞれが**単一のプロセス**を実行している場合（例えば、**Kubernetes**クラスタなど）、レプリケートされたワーカーコンテナを実行する**前に**、単一のコンテナで**事前のステップ**の作業を行う**別のコンテナ**を持ちたいと思うでしょう。\n\n/// info | 情報\n\nもしKubernetesを使用している場合, これはおそらく[Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)でしょう。\n\n///\n\nユースケースが事前のステップを**並列で複数回**実行するのに問題がない場合（例：データベースマイグレーションを実行するのではなく、データベースの準備ができたかをチェックするだけの場合）、メインプロセスを開始する直前に、それらのステップを各コンテナに入れることも可能です。\n\n### 単一コンテナ { #single-container }\n\n単純なセットアップで、**単一のコンテナ**で複数の**ワーカープロセス**（または1つのプロセスのみ）を起動する場合、アプリでプロセスを開始する直前に、同じコンテナで事前のステップを実行できます。\n\n### ベースDockerイメージ { #base-docker-image }\n\n以前は、公式のFastAPI Dockerイメージがありました：[tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker)。しかし、現在は非推奨です。⛔️\n\nおそらく、このベースDockerイメージ（またはその他の類似のもの）は**使用しない**方がよいでしょう。\n\nすでに**Kubernetes**（または他のもの）を使用していて、複数の**コンテナ**で、クラスタレベルで**レプリケーション**を設定している場合。そのような場合は、上記で説明したように**ゼロから**イメージを構築する方がよいでしょう：[FastAPI用のDockerイメージをビルドする](#build-a-docker-image-for-fastapi)。\n\nまた、複数のワーカーが必要な場合は、単純に `--workers` コマンドラインオプションを使用できます。\n\n/// note | 技術詳細\n\nこのDockerイメージは、Uvicornが停止したワーカーの管理と再起動をサポートしていなかった頃に作成されたため、Uvicornと一緒にGunicornを使う必要がありました。これは、GunicornにUvicornワーカープロセスの管理と再起動をさせるだけのために、かなりの複雑さを追加していました。\n\nしかし現在は、Uvicorn（および `fastapi` コマンド）が `--workers` をサポートしているため、自分でビルドする代わりにベースDockerイメージを使う理由はありません（コード量もだいたい同じです 😅）。\n\n///\n\n## コンテナ・イメージのデプロイ { #deploy-the-container-image }\n\nコンテナ（Docker）イメージを手に入れた後、それをデプロイするにはいくつかの方法があります。\n\n例えば以下のリストの方法です:\n\n* 単一サーバーの**Docker Compose**\n* **Kubernetes**クラスタ\n* Docker Swarmモードのクラスター\n* Nomadのような別のツール\n* コンテナ・イメージをデプロイするクラウド・サービス\n\n## `uv` を使ったDockerイメージ { #docker-image-with-uv }\n\n[uv](https://github.com/astral-sh/uv) を使ってプロジェクトのインストールと管理をしている場合は、[uv Docker guide](https://docs.astral.sh/uv/guides/integration/docker/)に従ってください。\n\n## まとめ { #recap }\n\nコンテナ・システム（例えば**Docker**や**Kubernetes**など）を使えば、すべての**デプロイメントのコンセプト**を扱うのがかなり簡単になります：\n\n* HTTPS\n* 起動時の実行\n* 再起動\n* レプリケーション（実行中のプロセス数）\n* メモリ\n* 開始前の事前ステップ\n\nほとんどの場合、ベースとなるイメージは使用せず、公式のPython Dockerイメージをベースにした**コンテナイメージをゼロからビルド**します。\n\n`Dockerfile`と**Dockerキャッシュ**内の命令の**順番**に注意することで、**ビルド時間を最小化**し、生産性を最大化できます（そして退屈を避けることができます）。😎\n"
  },
  {
    "path": "docs/ja/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\n[FastAPI Cloud](https://fastapicloud.com) に **コマンド1つ** でデプロイできます。まだならウェイティングリストにご登録ください。🚀\n\n## ログイン { #login }\n\nすでに **FastAPI Cloud** アカウントをお持ちであることを確認してください（ウェイティングリストからご招待しています 😉）。\n\n次にログインします:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## デプロイ { #deploy }\n\nでは、**コマンド1つ** でアプリをデプロイします:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n以上です！その URL からアプリにアクセスできます。✨\n\n## FastAPI Cloud について { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** は、**FastAPI** の作者とチームによって開発されています。\n\n最小限の手間で API を**構築**・**デプロイ**・**利用**できるように工程を簡素化します。\n\nFastAPI での開発と同じ**開発者体験**を、クラウドへの**デプロイ**にももたらします。🎉\n\nさらに、アプリのデプロイ時に必要となる多くの事項も任せられます。例えば:\n\n* HTTPS\n* レプリケーション（リクエストに基づくオートスケーリング付き）\n* など\n\nFastAPI Cloud は、*FastAPI and friends* のオープンソースプロジェクトに対する主要スポンサーかつ資金提供元です。✨\n\n## 他のクラウドプロバイダーへのデプロイ { #deploy-to-other-cloud-providers }\n\nFastAPI はオープンソースで標準に基づいています。お好みの任意のクラウドプロバイダーに FastAPI アプリをデプロイできます。\n\n各クラウドプロバイダーのガイドに従って FastAPI アプリをデプロイしてください。🤓\n\n## 自分のサーバーへのデプロイ { #deploy-your-own-server }\n\nこの**デプロイ**ガイドの後半では詳細も解説します。何が起きているのか、何が必要なのか、そして自分のサーバーを含めて FastAPI アプリを自力でデプロイする方法が分かるようになります。🤓\n"
  },
  {
    "path": "docs/ja/docs/deployment/https.md",
    "content": "# HTTPS について { #about-https }\n\nHTTPSは単に「有効」か「無効」かで決まるものだと思いがちです。\n\nしかし、それよりもはるかに複雑です。\n\n/// tip | 豆知識\n\nもし急いでいたり、HTTPSの仕組みについて気にしないのであれば、次のセクションに進み、さまざまなテクニックを使ってすべてをセットアップするステップ・バイ・ステップの手順をご覧ください。\n\n///\n\n利用者の視点から **HTTPS の基本を学ぶ**に当たっては、次のリソースをオススメします: [https://howhttps.works/](https://howhttps.works/).\n\nさて、**開発者の視点**から、HTTPSについて考える際に念頭に置くべきことをいくつかみていきましょう：\n\n* HTTPSの場合、**サーバ**は**第三者**によって生成された**「証明書」を持つ**必要があります。\n    * これらの証明書は「生成」されたものではなく、実際には第三者から**取得**されたものです。\n* 証明書には**有効期限**があります。\n    * つまりいずれ失効します。\n    * そのため**更新**をし、第三者から**再度取得**する必要があります。\n* 接続の暗号化は**TCPレベル**で行われます。\n    * それは**HTTPの1つ下**のレイヤーです。\n    * つまり、**証明書と暗号化**の処理は、**HTTPの前**に行われます。\n* **TCPは「ドメイン」について知りません**。IPアドレスについてのみ知っています。\n    * 要求された**特定のドメイン**に関する情報は、**HTTPデータ**に入ります。\n* **HTTPS証明書**は、**特定のドメイン**を「証明」しますが、プロトコルと暗号化はTCPレベルで行われ、どのドメインが扱われているかを**知る前**に行われます。\n* **デフォルトでは**、**IPアドレスごとに1つのHTTPS証明書**しか持てないことになります。\n    * これは、サーバーの規模やアプリケーションの規模に寄りません。\n    * しかし、これには**解決策**があります。\n* **TLS**プロトコル(HTTPの前に、TCPレベルで暗号化を処理するもの)には、**[<abbr title=\"Server Name Indication - サーバー名表示\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**と呼ばれる**拡張**があります。\n    * このSNI拡張機能により、1つのサーバー（**単一のIPアドレス**を持つ）が**複数のHTTPS証明書**を持ち、**複数のHTTPSドメイン/アプリケーション**にサービスを提供できるようになります。\n    * これが機能するためには、**パブリックIPアドレス**でリッスンしている、サーバー上で動作している**単一の**コンポーネント(プログラム)が、サーバー内の**すべてのHTTPS証明書**を持っている必要があります。\n* セキュアな接続を取得した**後**でも、通信プロトコルは**HTTPのまま**です。\n    * コンテンツは**HTTPプロトコル**で送信されているにもかかわらず、**暗号化**されています。\n\nサーバー（マシン、ホストなど）上で**1つのプログラム/HTTPサーバー**を実行させ、**HTTPSに関する全てのこと**を管理するのが一般的です。**暗号化された HTTPS リクエスト** を受信し、**復号化された HTTP リクエスト** を同じサーバーで実行されている実際の HTTP アプリケーション（この場合は **FastAPI** アプリケーション）に送信し、アプリケーションから **HTTP レスポンス** を受け取り、適切な **HTTPS 証明書** を使用して **暗号化** し、そして**HTTPS** を使用してクライアントに送り返します。このサーバーはしばしば **[TLS Termination Proxy](https://en.wikipedia.org/wiki/TLS_termination_proxy)**と呼ばれます。\n\nTLS Termination Proxyとして使えるオプションには、以下のようなものがあります：\n\n* Traefik（証明書の更新も対応）\n* Caddy (証明書の更新も対応)\n* Nginx\n* HAProxy\n\n\n## Let's Encrypt { #lets-encrypt }\n\nLet's Encrypt以前は、これらの**HTTPS証明書**は信頼できる第三者によって販売されていました。\n\nこれらの証明書を取得するための手続きは面倒で、かなりの書類を必要とし、証明書はかなり高価なものでした。\n\nしかしその後、**[Let's Encrypt](https://letsencrypt.org/)** が作られました。\n\nこれはLinux Foundationのプロジェクトから生まれたものです。 自動化された方法で、**HTTPS証明書を無料で**提供します。これらの証明書は、すべての標準的な暗号化セキュリティを使用し、また短命（約3ヶ月）ですが、こういった寿命の短さによって、**セキュリティは実際に優れています**。\n\nドメインは安全に検証され、証明書は自動的に生成されます。また、証明書の更新も自動化されます。\n\nこのアイデアは、これらの証明書の取得と更新を自動化することで、**安全なHTTPSを、無料で、永遠に**利用できるようにすることです。\n\n## 開発者のための HTTPS { #https-for-developers }\n\nここでは、HTTPS APIがどのように見えるかの例を、主に開発者にとって重要なアイデアに注意を払いながら、ステップ・バイ・ステップで説明します。\n\n### ドメイン名 { #domain-name }\n\nステップの初めは、**ドメイン名**を**取得すること**から始まるでしょう。その後、DNSサーバー（おそらく同じクラウドプロバイダー）に設定します。\n\nおそらくクラウドサーバー（仮想マシン）かそれに類するものを手に入れ、<dfn title=\"時間とともに変化しない。動的ではない。\">固定の</dfn> **パブリックIPアドレス**を持つことになるでしょう。\n\nDNSサーバーでは、**取得したドメイン**をあなたのサーバーのパブリック**IPアドレス**に向けるレコード（「`A record`」）を設定します。\n\nこれはおそらく、最初の1回だけあり、すべてをセットアップするときに行うでしょう。\n\n/// tip | 豆知識\n\nドメイン名の話はHTTPSに関する話のはるか前にありますが、すべてがドメインとIPアドレスに依存するため、ここで言及する価値があります。\n\n///\n\n### DNS { #dns }\n\nでは、実際のHTTPSの部分に注目してみましょう。\n\nまず、ブラウザは**DNSサーバー**に**ドメインに対するIP**が何であるかを確認します。今回は、`someapp.example.com`とします。\n\nDNSサーバーは、ブラウザに特定の**IPアドレス**を使用するように指示します。このIPアドレスは、DNSサーバーで設定した、あなたのサーバーが使用するパブリックIPアドレスになります。\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### TLS Handshake の開始 { #tls-handshake-start }\n\nブラウザはIPアドレスと**ポート443**（HTTPSポート）で通信します。\n\n通信の最初の部分は、クライアントとサーバー間の接続を確立し、使用する暗号鍵などを決めるだけです。\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\nTLS接続を確立するためのクライアントとサーバー間のこのやりとりは、**TLSハンドシェイク**と呼ばれます。\n\n### SNI拡張機能付きのTLS { #tls-with-sni-extension }\n\nサーバー内の**1つのプロセス**だけが、特定の**IPアドレス**の特定の**ポート**で待ち受けることができます。\n\n同じIPアドレスの他のポートで他のプロセスがリッスンしている可能性もありますが、IPアドレスとポートの組み合わせごとに1つだけです。\n\nTLS（HTTPS）はデフォルトで`443`という特定のポートを使用する。つまり、これが必要なポートです。\n\nこのポートをリクエストできるのは1つのプロセスだけなので、これを実行するプロセスは**TLS Termination Proxy**となります。\n\nTLS Termination Proxyは、1つ以上の**TLS証明書**（HTTPS証明書）にアクセスできます。\n\n前述した**SNI拡張機能**を使用して、TLS Termination Proxy は、利用可能なTLS (HTTPS)証明書のどれを接続先として使用すべきかをチェックし、クライアントが期待するドメインに一致するものを使用します。\n\n今回は、`someapp.example.com`の証明書を使うことになります。\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\nクライアントは、そのTLS証明書を生成したエンティティ（この場合はLet's Encryptですが、これについては後述します）をすでに**信頼**しているため、その証明書が有効であることを**検証**することができます。\n\n次に証明書を使用して、クライアントとTLS Termination Proxy は、 **TCP通信**の残りを**どのように暗号化するかを決定**します。これで**TLSハンドシェイク**の部分が完了します。\n\nこの後、クライアントとサーバーは**暗号化されたTCP接続**を持ちます。そして、その接続を使って実際の**HTTP通信**を開始することができます。\n\nこれが**HTTPS**であり、純粋な（暗号化されていない）TCP接続ではなく、**セキュアなTLS接続**の中に**HTTP**があるだけです。\n\n/// tip | 豆知識\n\n通信の暗号化は、HTTPレベルではなく、**TCPレベル**で行われることに注意してください。\n\n///\n\n### HTTPS リクエスト { #https-request }\n\nこれでクライアントとサーバー（具体的にはブラウザとTLS Termination Proxy）は**暗号化されたTCP接続**を持つことになり、**HTTP通信**を開始することができます。\n\nそこで、クライアントは**HTTPSリクエスト**を送信します。これは、暗号化されたTLSコネクションを介した単なるHTTPリクエストです。\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### リクエストの復号化 { #decrypt-the-request }\n\nTLS Termination Proxy は、合意が取れている暗号化を使用して、**リクエストを復号化**し、**プレーン (復号化された) HTTP リクエスト** をアプリケーションを実行しているプロセス (例えば、FastAPI アプリケーションを実行している Uvicorn を持つプロセス) に送信します。\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### HTTP レスポンス { #http-response }\n\nアプリケーションはリクエストを処理し、**プレーン(暗号化されていない)HTTPレスポンス** をTLS Termination Proxyに送信します。\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### HTTPS レスポンス { #https-response }\n\nTLS Termination Proxyは次に、事前に合意が取れている暗号(`someapp.example.com`の証明書から始まる)を使って**レスポンスを暗号化し**、ブラウザに送り返す。\n\nその後ブラウザでは、レスポンスが有効で正しい暗号キーで暗号化されていることなどを検証します。そして、ブラウザはレスポンスを**復号化**して処理します。\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\nクライアント（ブラウザ）は、レスポンスが正しいサーバーから来たことを知ることができます。 なぜなら、そのサーバーは、以前に**HTTPS証明書**を使って合意した暗号を使っているからです。\n\n### 複数のアプリケーション { #multiple-applications }\n\n同じサーバー（または複数のサーバー）に、例えば他のAPIプログラムやデータベースなど、**複数のアプリケーション**が存在する可能性があります。\n\n特定のIPとポート（この例ではTLS Termination Proxy）を扱うことができるのは1つのプロセスだけですが、他のアプリケーション/プロセスも、同じ**パブリックIPとポート**の組み合わせを使用しようとしない限り、サーバー上で実行することができます。\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\nそうすれば、TLS Termination Proxy は、**複数のドメイン**や複数のアプリケーションのHTTPSと証明書を処理し、それぞれのケースで適切なアプリケーションにリクエストを送信することができます。\n\n### 証明書の更新 { #certificate-renewal }\n\n将来のある時点で、各証明書は（取得後約3ヶ月で）**失効**します。\n\nその後、Let's Encryptと通信する別のプログラム（別のプログラムである場合もあれば、同じTLS Termination Proxyである場合もある）によって、証明書を更新します。\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\n**TLS証明書**は、IPアドレスではなく、**ドメイン名に関連付けられて**います。\n\nしたがって、証明書を更新するために、更新プログラムは、認証局（Let's Encrypt）に対して、**そのドメインが本当に「所有」し、管理している**ことを**証明**する必要があります。\n\nそのために、またさまざまなアプリケーションのニーズに対応するために、いくつかの方法があります。よく使われる方法としては:\n\n* **いくつかのDNSレコードを修正します。**\n    * これをするためには、更新プログラムはDNSプロバイダーのAPIをサポートする必要があります。したがって、使用しているDNSプロバイダーによっては、このオプションが使える場合もあれば、使えない場合もあります。\n* ドメインに関連付けられたパブリックIPアドレス上で、（少なくとも証明書取得プロセス中は）**サーバー**として実行します。\n    * 上で述べたように、特定のIPとポートでリッスンできるプロセスは1つだけです。\n    * これは、同じTLS Termination Proxyが証明書の更新処理も行う場合に非常に便利な理由の1つです。\n    * そうでなければ、TLS Termination Proxyを一時的に停止し、証明書を取得するために更新プログラムを起動し、TLS Termination Proxyで証明書を設定し、TLS Termination Proxyを再起動しなければならないかもしれません。TLS Termination Proxyが停止している間はアプリが利用できなくなるため、これは理想的ではありません。\n\n\nアプリを提供しながらこのような更新処理を行うことは、アプリケーション・サーバー（Uvicornなど）でTLS証明書を直接使用するのではなく、TLS Termination Proxyを使用して**HTTPSを処理する別のシステム**を用意したくなる主な理由の1つです。\n\n## プロキシ転送ヘッダー { #proxy-forwarded-headers }\n\nプロキシを使ってHTTPSを処理する場合、**アプリケーションサーバー**（たとえばFastAPI CLI経由のUvicorn）はHTTPS処理について何も知らず、**TLS Termination Proxy**とはプレーンなHTTPで通信します。\n\nこの**プロキシ**は通常、リクエストを**アプリケーションサーバー**に転送する前に、その場でいくつかのHTTPヘッダーを設定し、リクエストがプロキシによって**転送**されていることをアプリケーションサーバーに知らせます。\n\n/// note | 技術詳細\n\nプロキシヘッダーは次のとおりです：\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\nそれでも、**アプリケーションサーバー**は信頼できる**プロキシ**の背後にあることを知らないため、デフォルトではそれらのヘッダーを信頼しません。\n\nしかし、**アプリケーションサーバー**が**プロキシ**から送信される*forwarded*ヘッダーを信頼するように設定できます。FastAPI CLIを使用している場合は、*CLI Option* `--forwarded-allow-ips` を使って、どのIPからの*forwarded*ヘッダーを信頼すべきかを指定できます。\n\nたとえば、**アプリケーションサーバー**が信頼できる**プロキシ**からの通信のみを受け取っている場合、`--forwarded-allow-ips=\"*\"` に設定して、受信するすべてのIPを信頼するようにできます。受け取るリクエストは、**プロキシ**が使用するIPからのものだけになるためです。\n\nこうすることで、アプリケーションは、HTTPSを使用しているかどうか、ドメインなど、自身のパブリックURLが何であるかを把握できるようになります。\n\nこれは、たとえばリダイレクトを適切に処理するのに便利です。\n\n/// tip | 豆知識\n\nこれについては、[Behind a Proxy - Enable Proxy Forwarded Headers](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers) のドキュメントで詳しく学べます。\n\n///\n\n## まとめ { #recap }\n\n**HTTPS**を持つことは非常に重要であり、ほとんどの場合、かなり**クリティカル**です。開発者として HTTPS に関わる労力のほとんどは、これらの**概念とその仕組みを理解する**ことです。\n\nしかし、ひとたび**開発者向けHTTPS**の基本的な情報を知れば、簡単な方法ですべてを管理するために、さまざまなツールを組み合わせて設定することができます。\n\n次の章のいくつかでは、**FastAPI** アプリケーションのために **HTTPS** をセットアップする方法について、いくつかの具体例を紹介します。🔒\n"
  },
  {
    "path": "docs/ja/docs/deployment/index.md",
    "content": "# デプロイ { #deployment }\n\n**FastAPI** アプリケーションのデプロイは比較的簡単です。\n\n## デプロイとは { #what-does-deployment-mean }\n\nアプリケーションを**デプロイ**するとは、**ユーザーが利用できるようにする**ために必要な手順を実行することを意味します。\n\n**Web API** の場合、通常は **リモートマシン** 上に配置し、優れたパフォーマンス、安定性などを提供する **サーバープログラム** と組み合わせて、**ユーザー** が中断や問題なく効率的にアプリケーションへ**アクセス**できるようにします。\n\nこれは **開発** 段階とは対照的です。開発では、コードを常に変更し、壊しては直し、開発サーバーを停止したり再起動したりします。\n\n## デプロイ戦略 { #deployment-strategies }\n\n具体的なユースケースや使用するツールによって、いくつかの方法があります。\n\n複数のツールを組み合わせて自分で**サーバーをデプロイ**することもできますし、作業の一部を代行してくれる **クラウドサービス** を使うこともできます。ほかにも選択肢があります。\n\nたとえば、FastAPI の開発チームである私たちは、クラウドへの FastAPI アプリのデプロイを可能な限り合理化し、FastAPI を使って開発するのと同じ開発者体験を提供するために、[**FastAPI Cloud**](https://fastapicloud.com) を構築しました。\n\n**FastAPI** アプリケーションをデプロイする際に、おそらく念頭に置くべき主要な概念をいくつか紹介します（ただし、そのほとんどは他の種類の Web アプリケーションにも当てはまります）。\n\n次のセクションでは、留意すべき点の詳細や、それを実現するためのいくつかの手法を確認します。 ✨\n"
  },
  {
    "path": "docs/ja/docs/deployment/manually.md",
    "content": "# サーバーを手動で実行する { #run-a-server-manually }\n\n## fastapi run コマンドを使う { #use-the-fastapi-run-command }\n\n結論として、FastAPI アプリケーションを提供するには `fastapi run` を使います:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\nこれでほとんどのケースは動作します。😎\n\nこのコマンドは、たとえばコンテナやサーバー内で **FastAPI** アプリを起動するのに使えます。\n\n## ASGIサーバー { #asgi-servers }\n\n少し詳しく見ていきます。\n\nFastAPI は、Python の Web フレームワークとサーバーのための標準である <abbr title=\"Asynchronous Server Gateway Interface - 非同期サーバーゲートウェイインターフェース\">ASGI</abbr> を使います。FastAPI は ASGI Web フレームワークです。\n\nリモートのサーバーマシンで **FastAPI** アプリケーション（や他の ASGI アプリケーション）を実行するのに主に必要なのは **Uvicorn** のような ASGI サーバープログラムです。これは `fastapi` コマンドにデフォルトで含まれています。\n\n他にもいくつかの選択肢があります:\n\n* [Uvicorn](https://www.uvicorn.dev/): 高性能な ASGI サーバー。\n* [Hypercorn](https://hypercorn.readthedocs.io/): HTTP/2 や Trio に対応する ASGI サーバーなど。\n* [Daphne](https://github.com/django/daphne): Django Channels のために作られた ASGI サーバー。\n* [Granian](https://github.com/emmett-framework/granian): Python アプリケーション向けの Rust 製 HTTP サーバー。\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): 軽量で多用途な Web アプリケーションランタイム。\n\n## サーバーマシンとサーバープログラム { #server-machine-and-server-program }\n\n名称に関する小さな注意点があります。💡\n\n「サーバー」という言葉は、リモート/クラウド上のコンピュータ（物理/仮想マシン）と、そのマシン上で動作しているプログラム（例: Uvicorn）の両方を指すのに一般的に使われます。\n\n一般に「サーバー」と書かれているときは、そのどちらかを指している可能性があることを覚えておいてください。\n\nリモートマシンを指す場合、「サーバー」のほか「マシン」「VM（仮想マシン）」「ノード」などとも呼ばれます。いずれも通常 Linux を実行し、そこでプログラムを動かすリモートマシンを指します。\n\n## サーバープログラムをインストール { #install-the-server-program }\n\nFastAPI をインストールすると、本番サーバーの Uvicorn が同梱されており、`fastapi run` コマンドで起動できます。\n\nただし、ASGI サーバーを手動でインストールすることもできます。\n\n[仮想環境](../virtual-environments.md)を作成して有効化し、サーバーアプリケーションをインストールしてください。\n\n例として、Uvicorn をインストールするには:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\n他の ASGI サーバープログラムでも同様の手順です。\n\n/// tip | 豆知識\n\n`standard` を付けると、Uvicorn は推奨の追加依存関係もインストールして使用します。\n\nその中には、`uvloop` も含まれます。これは `asyncio` の高性能なドロップイン代替で、大きな並行実行性能の向上をもたらします。\n\n`pip install \"fastapi[standard]\"` のように FastAPI をインストールした場合は、すでに `uvicorn[standard]` も含まれます。\n\n///\n\n## サーバープログラムを起動 { #run-the-server-program }\n\nASGI サーバーを手動でインストールした場合、通常は FastAPI アプリケーションをインポートさせるために、特別な形式のインポート文字列を渡す必要があります:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note | 備考\n\n`uvicorn main:app` というコマンドは次を指します:\n\n* `main`: ファイル `main.py`（Python の「モジュール」）。\n* `app`: `main.py` 内で `app = FastAPI()` により作成されたオブジェクト。\n\nこれは次と等価です:\n\n```Python\nfrom main import app\n```\n\n///\n\n他の ASGI サーバープログラムでも同様のコマンドがあり、詳細はそれぞれのドキュメントを参照してください。\n\n/// warning | 注意\n\nUvicorn などのサーバーは、開発時に便利な `--reload` オプションをサポートしています。\n\nしかし `--reload` は多くのリソースを消費し、不安定になるなどの性質があります。\n\n開発中には非常に役立ちますが、 本番環境では使用すべきではありません。\n\n///\n\n## デプロイの概念 { #deployment-concepts }\n\nこれらの例は、サーバープログラム（例: Uvicorn）を実行し、事前に決めたポート（例: `80`）で、すべての IP（`0.0.0.0`）をリッスンする「単一プロセス」を起動します。\n\nこれが基本的な考え方です。ただし、次のような追加事項にも対応したくなるでしょう:\n\n* セキュリティ - HTTPS\n* 起動時に実行\n* 再起動\n* レプリケーション（実行プロセス数）\n* メモリ\n* 起動前の事前ステップ\n\nこれらの各概念についての考え方や、対処するための具体例・戦略を次の章で説明します。🚀\n"
  },
  {
    "path": "docs/ja/docs/deployment/server-workers.md",
    "content": "# Server Workers - ワーカー付きUvicorn { #server-workers-uvicorn-with-workers }\n\n前回のデプロイメントのコンセプトを振り返ってみましょう：\n\n* セキュリティ - HTTPS\n* 起動時の実行\n* 再起動\n* **レプリケーション（実行中のプロセス数）**\n* メモリ\n* 開始前の事前ステップ\n\nここまでのドキュメントのチュートリアルでは、おそらく `fastapi` コマンドなど（Uvicornを実行するもの）を使って、**単一のプロセス**として動作する**サーバープログラム**を実行してきたはずです。\n\nアプリケーションをデプロイする際には、**複数のコア**を利用し、そしてより多くのリクエストを処理できるようにするために、プロセスの**レプリケーション**を持つことを望むでしょう。\n\n前のチャプターである[デプロイメントのコンセプト](concepts.md)にて見てきたように、有効な戦略がいくつかあります。\n\nここでは、`fastapi` コマンド、または `uvicorn` コマンドを直接使って、**ワーカープロセス**付きの **Uvicorn** を使う方法を紹介します。\n\n/// info | 情報\n\nDockerやKubernetesなどのコンテナを使用している場合は、次の章で詳しく説明します： [コンテナ内のFastAPI - Docker](docker.md)。\n\n特に**Kubernetes**上で実行する場合は、おそらくワーカーは使わず、代わりに**コンテナごとに単一のUvicornプロセス**を実行したいはずですが、それについてはその章の後半で説明します。\n\n///\n\n## 複数ワーカー { #multiple-workers }\n\n`--workers` コマンドラインオプションで複数のワーカーを起動できます。\n\n//// tab | `fastapi`\n\n`fastapi` コマンドを使う場合：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\n`uvicorn` コマンドを直接使いたい場合：\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\nここで唯一の新しいオプションは `--workers` で、Uvicornに4つのワーカープロセスを起動するように指示しています。\n\n各プロセスの **PID** も表示されていて、親プロセス（これは**プロセスマネージャー**）が `27365`、各ワーカープロセスがそれぞれ `27368`、`27369`、`27370`、`27367` です。\n\n## デプロイメントのコンセプト { #deployment-concepts }\n\nここでは、複数の **ワーカー** を使ってアプリケーションの実行を**並列化**し、CPUの**複数コア**を活用して、**より多くのリクエスト**を処理できるようにする方法を見てきました。\n\n上のデプロイメントのコンセプトのリストから、ワーカーを使うことは主に**レプリケーション**の部分と、**再起動**を少し助けてくれますが、それ以外については引き続き対処が必要です：\n\n* **セキュリティ - HTTPS**\n* **起動時の実行**\n* ***再起動***\n* レプリケーション（実行中のプロセス数）\n* **メモリ**\n* **開始前の事前ステップ**\n\n## コンテナとDocker { #containers-and-docker }\n\n次章の[コンテナ内のFastAPI - Docker](docker.md)では、その他の**デプロイメントのコンセプト**を扱うために使える戦略をいくつか説明します。\n\n単一のUvicornプロセスを実行するために、**ゼロから独自のイメージを構築する**方法も紹介します。これは簡単なプロセスで、**Kubernetes**のような分散コンテナ管理システムを使う場合に、おそらくやりたいことでしょう。\n\n## まとめ { #recap }\n\n`fastapi` または `uvicorn` コマンドで `--workers` CLIオプションを使うことで、**マルチコアCPU**を活用し、**複数のプロセスを並列実行**できるように複数のワーカープロセスを利用できます。\n\n他のデプロイメントのコンセプトを自分で対応しながら、**独自のデプロイシステム**を構築している場合にも、これらのツールやアイデアを使えます。\n\n次の章で、コンテナ（例：DockerやKubernetes）を使った **FastAPI** について学びましょう。これらのツールにも、他の**デプロイメントのコンセプト**を解決する簡単な方法があることがわかります。✨\n"
  },
  {
    "path": "docs/ja/docs/deployment/versions.md",
    "content": "# FastAPIのバージョンについて { #about-fastapi-versions }\n\n**FastAPI** はすでに多くのアプリケーションやシステムで本番環境にて使われています。また、テストカバレッジは 100% に維持されています。しかし、開発は依然として急速に進んでいます。\n\n新機能が高頻度で追加され、定期的にバグが修正され、コードは継続的に改善されています。\n\nこれが現在のバージョンがいまだに `0.x.x` な理由であり、それぞれのバージョンは破壊的な変更がなされる可能性があります。これは、[セマンティック バージョニング](https://semver.org/)の規則に則っています。\n\n**FastAPI** を使用すると本番用アプリケーションを今すぐ作成できます（そして、おそらくあなたはしばらく前からそうしているはずです）。必要なのは、残りのコードと正しく動作するバージョンを使用していることを確認することだけです。\n\n## `fastapi` のバージョンを固定 { #pin-your-fastapi-version }\n\n最初にすべきことは、使用している **FastAPI** のバージョンを、アプリケーションで正しく動作することが分かっている特定の最新バージョンに「固定（pin）」することです。\n\n例えば、アプリでバージョン `0.112.0` を使っているとしましょう。\n\n`requirements.txt` ファイルを使う場合は、以下のようにバージョンを指定できます:\n\n```txt\nfastapi[standard]==0.112.0\n```\n\nこれは、厳密にバージョン `0.112.0` だけを使うことを意味します。\n\nまたは、以下のように固定することもできます:\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\nこれは `0.112.0` 以上、`0.113.0` 未満のバージョンを使うことを意味します。例えば、バージョン `0.112.2` は使用可能です。\n\n`uv`、Poetry、Pipenv など、他のインストール管理ツールを使用している場合でも、いずれもパッケージの特定バージョンを定義する方法があります。\n\n## 利用可能なバージョン { #available-versions }\n\n利用可能なバージョン（例: 現在の最新が何かを確認するため）は、[Release Notes](../release-notes.md) で確認できます。\n\n## バージョンについて { #about-versions }\n\nセマンティック バージョニングの規約に従って、`1.0.0` 未満のバージョンは破壊的な変更が加わる可能性があります。\n\nFastAPI では「PATCH」バージョンの変更はバグ修正と非破壊的な変更に使う、という規約にも従っています。\n\n/// tip | 豆知識\n\n「PATCH」は最後の数字です。例えば、`0.2.3` では PATCH バージョンは `3` です。\n\n///\n\n従って、以下のようなバージョンの固定ができるはずです:\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\n破壊的な変更と新機能は「MINOR」バージョンで追加されます。\n\n/// tip | 豆知識\n\n「MINOR」は真ん中の数字です。例えば、`0.2.3` では MINOR バージョンは `2` です。\n\n///\n\n## FastAPIのバージョンのアップグレード { #upgrading-the-fastapi-versions }\n\nアプリケーションにテストを追加すべきです。\n\n**FastAPI** では非常に簡単に実現できます（Starlette のおかげです）。ドキュメントを確認して下さい: [テスト](../tutorial/testing.md)\n\nテストを追加したら、**FastAPI** のバージョンをより新しいものにアップグレードし、テストを実行することで全てのコードが正しく動作するか確認できます。\n\n全てが動作する、または必要な変更を行った後に全てのテストが通るなら、その新しいバージョンに `fastapi` を固定できます。\n\n## Starletteについて { #about-starlette }\n\n`starlette` のバージョンは固定すべきではありません。\n\n**FastAPI** のバージョンが異なれば、Starlette の特定のより新しいバージョンが使われます。\n\nそのため、正しい Starlette バージョンを **FastAPI** に任せればよいです。\n\n## Pydanticについて { #about-pydantic }\n\nPydantic は自身のテストに **FastAPI** のテストも含んでいるため、Pydantic の新しいバージョン（`1.0.0` より上）は常に FastAPI と互換性があります。\n\nPydantic は、自分にとって動作する `1.0.0` より上の任意のバージョンに固定できます。\n\n例えば:\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/ja/docs/editor-support.md",
    "content": "# エディタ対応 { #editor-support }\n\n公式の[FastAPI Extension](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode)は、*path operation* の検出・ナビゲーションに加え、FastAPI Cloud へのデプロイやライブログストリーミングなど、FastAPI の開発ワークフローを強化します。\n\n拡張機能の詳細は、[GitHub リポジトリ](https://github.com/fastapi/fastapi-vscode)の README を参照してください。\n\n## セットアップとインストール { #setup-and-installation }\n\n**FastAPI Extension** は [VS Code](https://code.visualstudio.com/) と [Cursor](https://www.cursor.com/) の両方で利用できます。各エディタの拡張機能パネルから「FastAPI」を検索し、**FastAPI Labs** が公開している拡張機能を選択して直接インストールできます。 [vscode.dev](https://vscode.dev) や [github.dev](https://github.dev) などのブラウザベースのエディタでも動作します。\n\n### アプリケーション検出 { #application-discovery }\n\n既定では、ワークスペース内で `FastAPI()` を生成しているファイルを走査し、FastAPI アプリケーションを自動検出します。プロジェクト構成の都合で自動検出が機能しない場合は、`pyproject.toml` の `[tool.fastapi]`、または VS Code 設定の `fastapi.entryPoint` にモジュール記法（例: `myapp.main:app`）でエントリポイントを指定できます。\n\n## 機能 { #features }\n\n- **Path Operation エクスプローラー** - アプリケーション内のすべての <dfn title=\"ルート、エンドポイント\">*path operations*</dfn> をサイドバーのツリービューで表示します。クリックして任意のルートまたはルーター定義へジャンプできます。\n- **ルート検索** - <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>（macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>）で、パス・メソッド・名前で検索できます。\n- **CodeLens ナビゲーション** - テストクライアント呼び出し（例: `client.get('/items')`）の上に表示されるクリック可能なリンクから、対応する *path operation* にジャンプし、テストと実装の行き来をすばやく行えます。\n- **FastAPI Cloud へデプロイ** - [FastAPI Cloud](https://fastapicloud.com/) にワンクリックでアプリをデプロイできます。\n- **アプリケーションログのストリーミング** - FastAPI Cloud にデプロイしたアプリから、レベルフィルタやテキスト検索付きでリアルタイムにログをストリーミングできます。\n\n拡張機能の機能に慣れるには、コマンドパレット（<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>、macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>）を開き、\"Welcome: Open walkthrough...\" を選択してから、\"Get started with FastAPI\" のウォークスルーを選んでください。\n"
  },
  {
    "path": "docs/ja/docs/environment-variables.md",
    "content": "# 環境変数 { #environment-variables }\n\n/// tip | 豆知識\n\nもし「環境変数」とは何か、それをどう使うかを既に知っている場合は、このセクションをスキップして構いません。\n\n///\n\n環境変数（「**env var**」とも呼ばれます）とは、Pythonコードの**外側**、つまり**オペレーティングシステム**に存在する変数で、Pythonコード（または他のプログラム）から読み取れます。\n\n環境変数は、アプリケーションの**設定**の扱い、Pythonの**インストール**の一部などで役立ちます。\n\n## 環境変数の作成と使用 { #create-and-use-env-vars }\n\n環境変数は、Pythonを必要とせず、**シェル（ターミナル）**で**作成**して使用できます。\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// 環境変数 MY_NAME を作成する例\n$ export MY_NAME=\"Wade Wilson\"\n\n// その後、他のプログラムで利用できます。例えば\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// 環境変数 MY_NAME を作成\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// 他のプログラムで利用、例えば\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## Pythonで環境変数を読み取る { #read-env-vars-in-python }\n\n環境変数はPythonの**外側**（ターミナル、またはその他の方法）で作成し、その後に**Pythonで読み取る**こともできます。\n\n例えば、以下のような`main.py`ファイルを用意します:\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip | 豆知識\n\n[`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) の第2引数は、返されるデフォルト値です。\n\n指定しない場合、デフォルトは`None`ですが、ここでは使用するデフォルト値として`\"World\"`を指定しています。\n\n///\n\n次に、このPythonプログラムを呼び出します。\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// ここではまだ環境変数を設定していません\n$ python main.py\n\n// 環境変数を設定していないため、デフォルト値が使われます\n\nHello World from Python\n\n// しかし、先に環境変数を作成すると\n$ export MY_NAME=\"Wade Wilson\"\n\n// それからもう一度プログラムを実行すると\n$ python main.py\n\n// すると環境変数を読み取れます\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// ここではまだ環境変数を設定していません\n$ python main.py\n\n// 環境変数を設定していないため、デフォルト値が使われます\n\nHello World from Python\n\n// しかし、先に環境変数を作成すると\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// それからもう一度プログラムを実行すると\n$ python main.py\n\n// すると環境変数を読み取れます\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n環境変数はコードの外側で設定でき、コードから読み取れ、他のファイルと一緒に（`git`に）保存（コミット）する必要がないため、設定や**settings**に使うのが一般的です。\n\nまた、**特定のプログラムの呼び出し**のためだけに、そのプログラムでのみ、実行中の間だけ利用できる環境変数を作成することもできます。\n\nそのためには、同じ行で、プログラム自体の直前に作成してください。\n\n<div class=\"termy\">\n\n```console\n// このプログラム呼び出し用に同じ行で環境変数 MY_NAME を作成\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// これで環境変数を読み取れます\n\nHello Wade Wilson from Python\n\n// その後は環境変数は存在しません\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip | 豆知識\n\n詳しくは [The Twelve-Factor App: 設定](https://12factor.net/config) を参照してください。\n\n///\n\n## 型とバリデーション { #types-and-validation }\n\nこれらの環境変数が扱えるのは**テキスト文字列**のみです。環境変数はPythonの外部にあり、他のプログラムやシステム全体（Linux、Windows、macOSなど異なるオペレーティングシステム間も）との互換性が必要になるためです。\n\nつまり、環境変数からPythonで読み取る**あらゆる値**は **`str`になり**、他の型への変換やバリデーションはコード内で行う必要があります。\n\n環境変数を使って**アプリケーション設定**を扱う方法については、[高度なユーザーガイド - Settings and Environment Variables](./advanced/settings.md)で詳しく学べます。\n\n## `PATH`環境変数 { #path-environment-variable }\n\n**`PATH`**という**特別な**環境変数があります。これはオペレーティングシステム（Linux、macOS、Windows）が実行するプログラムを見つけるために使用されます。\n\n変数`PATH`の値は長い文字列で、LinuxとmacOSではコロン`:`、Windowsではセミコロン`;`で区切られたディレクトリで構成されます。\n\n例えば、`PATH`環境変数は次のような文字列かもしれません:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nこれは、システムが次のディレクトリでプログラムを探すことを意味します:\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\nこれは、システムが次のディレクトリでプログラムを探すことを意味します:\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\nターミナル上で**コマンド**を入力すると、オペレーティングシステムは`PATH`環境変数に記載された**それぞれのディレクトリ**の中からプログラムを**探し**ます。\n\n例えば、ターミナルで`python`と入力すると、オペレーティングシステムはそのリストの**最初のディレクトリ**で`python`というプログラムを探します。\n\n見つかればそれを**使用**します。見つからなければ、**他のディレクトリ**を探し続けます。\n\n### Pythonのインストールと`PATH`の更新 { #installing-python-and-updating-the-path }\n\nPythonのインストール時に、`PATH`環境変数を更新するかどうかを尋ねられるかもしれません。\n\n//// tab | Linux, macOS\n\nPythonをインストールして、その結果`/opt/custompython/bin`というディレクトリに配置されたとします。\n\n`PATH`環境変数を更新することに同意すると、インストーラーは`PATH`環境変数に`/opt/custompython/bin`を追加します。\n\n例えば次のようになります:\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\nこのようにして、ターミナルで`python`と入力すると、システムは`/opt/custompython/bin`（最後のディレクトリ）にあるPythonプログラムを見つけ、それを使用します。\n\n////\n\n//// tab | Windows\n\nPythonをインストールして、その結果`C:\\opt\\custompython\\bin`というディレクトリに配置されたとします。\n\n`PATH`環境変数を更新することに同意すると、インストーラーは`PATH`環境変数に`C:\\opt\\custompython\\bin`を追加します。\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\nこのようにして、ターミナルで`python`と入力すると、システムは`C:\\opt\\custompython\\bin`（最後のディレクトリ）にあるPythonプログラムを見つけ、それを使用します。\n\n////\n\nつまり、ターミナルで次のように入力すると:\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\nシステムは`/opt/custompython/bin`にある`python`プログラムを**見つけ**て実行します。\n\nこれは、次のように入力するのとおおむね同等です:\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\nシステムは`C:\\opt\\custompython\\bin\\python`にある`python`プログラムを**見つけ**て実行します。\n\nこれは、次のように入力するのとおおむね同等です:\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\nこの情報は、[Virtual Environments](virtual-environments.md)について学ぶ際にも役立ちます。\n\n## まとめ { #conclusion }\n\nこれで、**環境変数**とは何か、Pythonでどのように使用するかについて、基本的な理解が得られたはずです。\n\n環境変数についての詳細は、[Wikipedia の環境変数](https://en.wikipedia.org/wiki/Environment_variable)も参照してください。\n\n多くの場合、環境変数がどのように役立ち、すぐに適用できるのかはあまり明確ではありません。しかし、開発中のさまざまなシナリオで何度も登場するため、知っておくとよいでしょう。\n\n例えば、次のセクションの[Virtual Environments](virtual-environments.md)でこの情報が必要になります。\n"
  },
  {
    "path": "docs/ja/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - コマンドラインインターフェース\">CLI</abbr>** は、FastAPI アプリの提供、FastAPI プロジェクトの管理などに使用できるコマンドラインプログラムです。\n\nFastAPI をインストールすると（例: `pip install \"fastapi[standard]\"`）、ターミナルで実行できるコマンドラインプログラムが付属します。\n\n開発用に FastAPI アプリを起動するには、`fastapi dev` コマンドを使用できます:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip\n\n本番では `fastapi dev` の代わりに `fastapi run` を使用します。🚀\n\n///\n\n内部的には、**FastAPI CLI** は [Uvicorn](https://www.uvicorn.dev)（高性能で本番運用向けの ASGI サーバー）を使用します。😎\n\n`fastapi` CLI は、実行する FastAPI アプリを自動検出しようとします。既定では、`main.py` の中にある `app` という名前のオブジェクト（ほかにもいくつかの変種）であると仮定します。\n\nただし、使用するアプリを明示的に設定することもできます。\n\n## `pyproject.toml` でアプリの `entrypoint` を設定 { #configure-the-app-entrypoint-in-pyproject-toml }\n\n`pyproject.toml` に次のように、アプリの場所を設定できます:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nこの `entrypoint` により、`fastapi` コマンドは次のようにアプリを import する必要があると認識します:\n\n```python\nfrom main import app\n```\n\nもしコード構成が次のような場合:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\n`entrypoint` は次のように設定します:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nこれは次と同等です:\n\n```python\nfrom backend.main import app\n```\n\n### パス指定での `fastapi dev` { #fastapi-dev-with-path }\n\n`fastapi dev` コマンドにファイルパスを渡すこともでき、使用する FastAPI アプリオブジェクトを推測します:\n\n```console\n$ fastapi dev main.py\n```\n\nただし、そのたびに `fastapi` コマンドを呼び出す際に正しいパスを渡す必要があります。\n\nさらに、[VS Code 拡張機能](editor-support.md) や [FastAPI Cloud](https://fastapicloud.com) など、ほかのツールがそれを見つけられない場合があります。そのため、`pyproject.toml` の `entrypoint` を使用することを推奨します。\n\n## `fastapi dev` { #fastapi-dev }\n\n`fastapi dev` を実行すると、開発モードが有効になります。\n\nデフォルトでは、**auto-reload** が有効です。コードを変更するとサーバーが自動で再読み込みされます。これはリソースを多く消費し、無効時より安定性が低くなる可能性があります。開発時のみに使用してください。また、IP アドレス `127.0.0.1`（マシン自身のみと通信するための IP、`localhost`）で待ち受けます。\n\n## `fastapi run` { #fastapi-run }\n\n`fastapi run` を実行すると、デフォルトで本番モードで起動します。\n\nデフォルトでは、**auto-reload** は無効です。また、IP アドレス `0.0.0.0`（利用可能なすべての IP アドレスを意味します）で待ち受けるため、そのマシンと通信できる任意のクライアントから公開アクセスが可能になります。これは、たとえばコンテナ内など、本番環境で一般的な実行方法です。\n\n多くの場合（そして推奨されるのは）、上位に HTTPS を終端する「termination proxy」を置きます。これはアプリのデプロイ方法に依存し、プロバイダが代行する場合もあれば、自分で設定する必要がある場合もあります。\n\n/// tip\n\n詳しくは、[デプロイのドキュメント](deployment/index.md)を参照してください。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/features.md",
    "content": "# 機能 { #features }\n\n## FastAPIの機能 { #fastapi-features }\n\n**FastAPI** は次のものを提供します:\n\n### オープンスタンダード準拠 { #based-on-open-standards }\n\n* API 作成のための [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification)。<dfn title=\"別名: エンドポイント、ルート\">パス</dfn> <dfn title=\"別名: HTTP メソッド（POST、GET、PUT、DELETE など）\">オペレーション</dfn>、パラメータ、リクエストボディ、セキュリティなどの宣言を含みます。\n* [**JSON Schema**](https://json-schema.org/) によるデータモデルの自動ドキュメント化（OpenAPI 自体が JSON Schema に基づいています）。\n* 入念な調査のうえ、これらの標準を中心に設計されています。後付けのレイヤーではありません。\n* これにより、多くの言語で自動 **クライアントコード生成** が可能です。\n\n### 自動ドキュメント { #automatic-docs }\n\n対話的な API ドキュメントと探索的な Web ユーザーインターフェース。フレームワークは OpenAPI に基づいているため、複数のオプションがあり、デフォルトで 2 つ含まれます。\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui)。インタラクティブに探索しつつ、ブラウザから直接 API を呼び出してテストできます。\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* [**ReDoc**](https://github.com/Rebilly/ReDoc) による代替の API ドキュメント。\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### 現代的なPythonのみ { #just-modern-python }\n\nすべて標準の **Python の型** 宣言（Pydantic に感謝）に基づいています。新しい構文を学ぶ必要はありません。標準的でモダンな Python だけです。\n\n（FastAPI を使わない場合でも）Python の型の使い方を 2 分で復習したい場合は、短いチュートリアル [Python の型](python-types.md) を参照してください。\n\n型を使った標準的な Python を記述します:\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# Declare a variable as a str\n# and get editor support inside the function\ndef main(user_id: str):\n    return user_id\n\n\n# A Pydantic model\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\nこれは次のように使えます:\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n/// info\n\n`**second_user_data` は次の意味です:\n\n`second_user_data` 辞書のキーと値を、そのままキーバリュー引数として渡します。これは `User(id=4, name=\"Mary\", joined=\"2018-11-30\")` と同等です。\n\n///\n\n### エディタのサポート { #editor-support }\n\nフレームワーク全体が使いやすく直感的になるよう設計されており、最高の開発体験を確保するため、開発開始前から複数のエディタであらゆる判断が検証されています。\n\nPython 開発者調査では、[最もよく使われる機能の 1 つが「オートコンプリート」であることが明らかです](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features)。\n\n**FastAPI** はその要求を満たすことを基盤にしています。オートコンプリートはどこでも機能します。\n\nドキュメントに戻る必要はほとんどありません。\n\nエディタがどのように役立つかの例です:\n\n* [Visual Studio Code](https://code.visualstudio.com/) の場合:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* [PyCharm](https://www.jetbrains.com/pycharm/) の場合:\n\n![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\n以前は不可能だと思っていたコードでも補完が得られます。例えば、リクエストから届く（ネストされている可能性のある）JSON ボディ内の `price` キーなどです。\n\nもう間違ったキー名を入力したり、ドキュメントを行き来したり、上下にスクロールして最終的に `username` と `user_name` のどちらを使ったのか探す必要はありません。\n\n### 簡潔 { #short }\n\nすべてに妥当な **デフォルト** があり、どこでもオプションで構成できます。必要に応じてすべてのパラメータを微調整して、求める API を定義できます。\n\nしかしデフォルトのままでも、すべて **うまく動きます**。\n\n### 検証 { #validation }\n\n* ほとんど（あるいはすべて？）の Python の **データ型** に対する検証:\n    * JSON オブジェクト（`dict`）。\n    * 項目の型を定義する JSON 配列（`list`）。\n    * 文字列（`str`）フィールドの最小/最大長。\n    * 数値（`int`、`float`）の最小/最大値、など。\n\n* よりエキゾチックな型の検証:\n    * URL。\n    * Email。\n    * UUID。\n    * ...その他。\n\nすべての検証は、確立され堅牢な **Pydantic** によって処理されます。\n\n### セキュリティと認証 { #security-and-authentication }\n\nセキュリティと認証が統合されています。データベースやデータモデルとの妥協はありません。\n\nOpenAPI で定義されたすべてのセキュリティスキームをサポートします:\n\n* HTTP Basic。\n* **OAuth2**（**JWT トークン** も可）。チュートリアル [JWT を用いた OAuth2](tutorial/security/oauth2-jwt.md) を確認してください。\n* API キー（以下の場所）:\n    * ヘッダー。\n    * クエリパラメータ。\n    * クッキー、など。\n\nさらに、Starlette のすべてのセキュリティ機能（**セッション Cookie** を含む）も利用できます。\n\nこれらはすべて再利用可能なツールやコンポーネントとして構築されており、システム、データストア、リレーショナル/NoSQL データベース等と容易に統合できます。\n\n### 依存性の注入 { #dependency-injection }\n\nFastAPI には、非常に使いやすく、かつ非常に強力な <dfn title='別名: コンポーネント、リソース、サービス、プロバイダー'><strong>依存性の注入</strong></dfn> システムがあります。\n\n* 依存関係は依存関係を持つこともでき、階層または **依存関係の「グラフ」** を作成できます。\n* すべてフレームワークによって**自動的に処理**されます。\n* すべての依存関係はリクエストからデータを要求でき、*path operation* の制約と自動ドキュメントを**拡張**できます。\n* 依存関係で定義された *path operation* のパラメータについても**自動検証**されます。\n* 複雑なユーザー認証システム、**データベース接続** などのサポート。\n* **データベースやフロントエンド等との妥協は不要**。すべてと簡単に統合できます。\n\n### 無制限の「プラグイン」 { #unlimited-plug-ins }\n\n別の言い方をすれば、プラグインは不要で、必要なコードをインポートして使うだけです。\n\nあらゆる統合は（依存関係を用いて）非常に簡単に使えるよう設計されており、*path operation* で使うのと同じ構造と構文で、2 行のコードでアプリケーション用の「プラグイン」を作れます。\n\n### テスト済み { #tested }\n\n* 100% の <dfn title=\"自動的にテストされるコードの量\">テストカバレッジ</dfn>。\n* 100% <dfn title=\"Python の型アノテーション。これにより、エディタや外部ツールからより良い支援が受けられます\">型アノテーション付き</dfn>のコードベース。\n* 本番アプリケーションで使用されています。\n\n## Starletteの機能 { #starlette-features }\n\n**FastAPI** は [**Starlette**](https://www.starlette.dev/) と完全に互換性があり（かつそれに基づいています）。そのため、手元の Starlette の追加コードも動作します。\n\n`FastAPI` は実際には `Starlette` のサブクラスです。すでに Starlette を知っている、あるいは使っているなら、ほとんどの機能は同じように動作します。\n\n**FastAPI** では **Starlette** のすべての機能が利用できます（FastAPI は強化された Starlette にすぎません）:\n\n* 圧倒的なパフォーマンス。[利用可能な最速クラスの Python フレームワークの 1 つで、**NodeJS** や **Go** と同等です](https://github.com/encode/starlette#performance)。\n* **WebSocket** のサポート。\n* プロセス内バックグラウンドタスク。\n* 起動およびシャットダウンイベント。\n* HTTPX に基づくテストクライアント。\n* **CORS**、GZip、静的ファイル、ストリーミングレスポンス。\n* **セッションと Cookie** のサポート。\n* テストカバレッジ 100%。\n* 型アノテーション 100% のコードベース。\n\n## Pydanticの機能 { #pydantic-features }\n\n**FastAPI** は [**Pydantic**](https://docs.pydantic.dev/) と完全に互換性があり（かつそれに基づいています）。そのため、手元の Pydantic の追加コードも動作します。\n\nPydantic に基づく外部ライブラリ（データベース用の <abbr title=\"Object-Relational Mapper - オブジェクト関係マッパー\">ORM</abbr>、<abbr title=\"Object-Document Mapper - オブジェクトドキュメントマッパー\">ODM</abbr> など）も含まれます。\n\nこれは、すべてが自動的に検証されるため、多くの場合、リクエストから取得したオブジェクトを **そのままデータベースに** 渡せることを意味します。\n\n逆方向も同様で、多くの場合、データベースから取得したオブジェクトを **そのままクライアントに** 渡せます。\n\n**FastAPI** では **Pydantic** のすべての機能が利用できます（FastAPI はデータ処理のすべてで Pydantic に基づいています）:\n\n* **brainfuck なし**：\n    * スキーマ定義のための新しいマイクロ言語を学ぶ必要はありません。\n    * Python の型を知っていれば、Pydantic の使い方もわかります。\n* **<abbr title=\"Integrated Development Environment - 統合開発環境: コードエディタに類似\">IDE</abbr>/<dfn title=\"コードのエラーを検査するプログラム\">リンター</dfn>/思考** と気持ちよく連携します：\n    * Pydantic のデータ構造は、あなたが定義するクラスの単なるインスタンスなので、オートコンプリート、リンティング、mypy、そしてあなたの直感が、検証済みデータに対して適切に機能します。\n* **複雑な構造** を検証：\n    * 階層的な Pydantic モデルや、Python の `typing` にある `List` や `Dict` などを利用できます。\n    * さらにバリデータにより、複雑なデータスキーマを明確かつ容易に定義・検査でき、JSON Schema として文書化できます。\n    * 深く **ネストされた JSON** オブジェクトを扱え、それらすべてを検証してアノテーションを付与できます。\n* **拡張可能**：\n    * Pydantic ではカスタムデータ型を定義できますし、バリデータデコレーターで装飾したモデルメソッドで検証を拡張できます。\n* テストカバレッジ 100%。\n"
  },
  {
    "path": "docs/ja/docs/help-fastapi.md",
    "content": "# FastAPIを応援 - ヘルプの入手 { #help-fastapi-get-help }\n\n**FastAPI** は気に入りましたか？\n\nFastAPIや他のユーザー、作者を応援したいですか？\n\nそれとも **FastAPI** についてヘルプが必要ですか？\n\nとても簡単に応援できる方法があります（1、2回クリックするだけのものもあります）。\n\nヘルプを得る方法もいくつかあります。\n\n## ニュースレターを購読 { #subscribe-to-the-newsletter }\n\n[**FastAPI and friends** ニュースレター](newsletter.md)（配信はまれです）を購読すると、次の情報をキャッチアップできます:\n\n* FastAPI と関連プロジェクトのニュース 🚀\n* ガイド 📝\n* 機能 ✨\n* 互換性に影響する変更 🚨\n* ヒントやコツ ✅\n\n## X (Twitter) で FastAPI をフォロー { #follow-fastapi-on-x-twitter }\n\n[**X (Twitter)** で @fastapi をフォロー](https://x.com/fastapi)して、**FastAPI** の最新情報を受け取りましょう。🐦\n\n## GitHubで **FastAPI** にStar { #star-fastapi-in-github }\n\nGitHubでFastAPIに「Star」をつけることができます（右上部のStarボタンをクリック）: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)。⭐️\n\nスターを増やすことで、他のユーザーの目につきやすくなり、すでに多くの人の役に立っていることが伝わります。\n\n## GitHubレポジトリのリリースをWatch { #watch-the-github-repository-for-releases }\n\nGitHubでFastAPIを「Watch」できます（右上部の「Watch」ボタンをクリック）: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)。👀\n\nそこで「Releases only」を選択できます。\n\nこれを行うと、バグ修正や新機能を含む **FastAPI** の新しいリリース（新バージョン）があるたびに、（メールで）通知を受け取れます。\n\n## 開発者とつながる { #connect-with-the-author }\n\n作者である[私（Sebastián Ramírez / `tiangolo`）](https://tiangolo.com)とつながれます。\n\nできること:\n\n* [**GitHub** でフォロー](https://github.com/tiangolo)。\n    * 役に立つかもしれない、私が作成した他のオープンソースプロジェクトを見られます。\n    * 新しいオープンソースプロジェクトを作成したときにわかります。\n* [**X (Twitter)** でフォロー](https://x.com/tiangolo) または [Mastodon](https://fosstodon.org/@tiangolo)。\n    * あなたがどのようにFastAPIを使っているか教えてください（聞けると嬉しいです）。\n    * 新しいツールの告知やリリースを聞けます。\n    * さらに、[X (Twitter) の @fastapi](https://x.com/fastapi)（別アカウント）もフォローできます。\n* [**LinkedIn** でフォロー](https://www.linkedin.com/in/tiangolo/)。\n    * 新しいツールの告知やリリースを聞けます（ただしX (Twitter) の方をよく使っています 🤷‍♂）。\n* [**Dev.to**](https://dev.to/tiangolo) や [**Medium**](https://medium.com/@tiangolo) で執筆内容を読む（またはフォロー）。\n    * 私のアイデアや、作成したツールに関する記事を読めます。\n    * 新しい記事を公開したときに読めます。\n\n## **FastAPI** についてツイート { #tweet-about-fastapi }\n\n[**FastAPI** についてツイート](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi)して、なぜ気に入っているのかを私や他の人に教えてください。🎉\n\n**FastAPI** がどのように使われているか、どこを気に入っているか、どのプロジェクト/会社で使っているか等、聞けると嬉しいです。\n\n## FastAPIに投票 { #vote-for-fastapi }\n\n* [Slantで **FastAPI** に投票](https://www.slant.co/options/34241/~fastapi-review)。\n* [AlternativeToで **FastAPI** に投票](https://alternativeto.net/software/fastapi/about/)。\n* [StackShare で **FastAPI** を使っていると宣言](https://stackshare.io/pypi-fastapi)。\n\n## GitHubで質問に困っている人を助ける { #help-others-with-questions-in-github }\n\n次の場所で、他の人の質問を手助けできます:\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\n多くの場合、その質問の答えをすでに知っているかもしれません。🤓\n\nもし多くの人の質問に答えて助けてくれたなら、あなたは公式の[FastAPI Expert](fastapi-people.md#fastapi-experts)になります。🎉\n\n最も大事なポイントは「親切であること」を心がけることです。人はフラストレーションを抱えてやって来るので、必ずしも最良の聞き方をしているとは限りませんが、できる限り親切に対応しましょう。🤗\n\n**FastAPI** コミュニティは親切で歓迎的であることを目指しています。同時に、いじめや他者への無礼な振る舞いは受け入れないでください。お互いを大事にしましょう。\n\n---\n\n以下は（Discussions や Issues で）他の人の質問を手助けする方法です:\n\n### 質問を理解する { #understand-the-question }\n\n* 質問者の「目的」やユースケースを理解できるか確認します。\n\n* 次に、質問（大半は質問です）が「明確」か確認します。\n\n* 多くの場合、ユーザーが想像した解決策についての質問になっていますが、もっと「良い」方法があるかもしれません。問題やユースケースをよりよく理解できれば、より良い「代替解決策」を提案できるかもしれません。\n\n* 質問が理解できない場合は、さらに「詳細」を尋ねます。\n\n### 问題を再現する { #reproduce-the-problem }\n\n多くのケースや質問は、その人の「元のコード」に関係しています。\n\nしばしばコードの断片だけが共有されますが、それでは問題を「再現」するには不十分です。\n\n* ローカルで同じエラーや挙動を確認できるように、またはユースケースをよりよく理解できるように、**コピー&ペースト**して実行できる[最小の再現可能な例](https://stackoverflow.com/help/minimal-reproducible-example)の提供を依頼できます。\n\n* とても寛大な気分なら、問題の説明だけをもとに、あなた自身でそのような**例を作成**してみることもできます。ただし時間がかかる可能性が高いので、まずは問題の明確化を依頼した方が良い場合もあります。\n\n### 解決策を提案する { #suggest-solutions }\n\n* 質問を理解できたら、可能な**回答**を提示できます。\n\n* 多くの場合、相手の「根本的な問題やユースケース」を理解することが重要です。相手が試している方法より良い解決方法があるかもしれないからです。\n\n### クローズを依頼する { #ask-to-close }\n\nもし相手が返信してきて、あなたが問題を解決できたなら、おめでとう、**あなたはヒーロー**です！🦸\n\n* その場合、次のように依頼できます:\n\n    * GitHub Discussions: コメントを**回答**としてマークしてもらう。\n    * GitHub Issues: issue を**クローズ**してもらう。\n\n## GitHubレポジトリをWatch { #watch-the-github-repository }\n\nGitHubでFastAPIを「Watch」できます（右上部の「Watch」ボタンをクリック）: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)。👀\n\n「Releases only」ではなく「Watching」を選択すると、新しい issue や質問が作成されたときに通知を受け取れます。新しい issue のみ、Discussions のみ、PR のみ、など通知対象を絞ることもできます。\n\nその上で、そうした質問の解決を手助けできます。\n\n## 質問する { #ask-questions }\n\nGitHubレポジトリで[新しい質問](https://github.com/fastapi/fastapi/discussions/new?category=questions)を作成できます。例えば:\n\n* **質問**をする、または**問題**について尋ねる。\n* 新しい**機能**を提案する。\n\n**Note**: もしそうするなら、他の人の手助けもお願いします。😉\n\n## プルリクエストをレビュー { #review-pull-requests }\n\n他の人からのプルリクエストのレビューを手伝ってもらえます。\n\nここでも、できる限り親切であるようにしてください。🤗\n\n---\n\nプルリクエストをレビューするときのポイントです:\n\n### 問題を理解する { #understand-the-problem }\n\n* まず、そのプルリクエストが解決しようとしている**問題を理解**してください。長めの議論が GitHub Discussion や issue にあるかもしれません。\n\n* その問題は実は**別の方法**で解決でき、プルリクエスト自体が不要な場合もあります。その場合は、その提案や質問をしても良いでしょう。\n\n### スタイルは気にしすぎない { #dont-worry-about-style }\n\n* コミットメッセージのスタイルなどはあまり気にしなくて大丈夫です。私は squash and merge を使い、コミットを手動で調整します。\n\n* スタイルルールについても心配無用です。自動化ツールがすでにチェックしています。\n\nほかにスタイルや一貫性の要件があれば、私から直接依頼しますし、必要な変更を上に積む形でコミットを追加します。\n\n### コードを確認 { #check-the-code }\n\n* コードを確認して読み、妥当かどうかを見て、**ローカルで実行**し、本当に問題を解決しているか確かめてください。\n\n* そのうえで、それを行ったことを**コメント**で伝えてください。そうすれば、実際に確認してくれたとわかります。\n\n/// info | 情報\n\n残念ながら、承認が複数ついただけのPRを、そのまま信頼することはできません。\n\n説明が魅力的なためか、3件、5件以上の承認がついていても、実際にPRを確認すると壊れていたり、バグがあったり、主張する問題を解決していなかったりすることが何度もありました。😅\n\nですので、実際にコードを読み、実行して確認し、それをコメントで知らせてもらえることが本当に重要です。🤓\n\n///\n\n* もしPRを簡素化できそうなら、その依頼をしても構いませんが、細かい点にこだわり過ぎる必要はありません。主観的な見方が多く（私にもあります 🙈）、基本的な点に集中できるとより良いでしょう。\n\n### テスト { #tests }\n\n* PRに**テスト**があるか確認を手伝ってください。\n\n* PR前はテストが**失敗**することを確認します。🚨\n\n* そしてPR後にテストが**成功**することを確認します。✅\n\n* 多くのPRにはテストがありません。テストの追加を**リマインド**したり、テストを**提案**したりできます。これは最も時間を消費する部分の一つで、大いに助けになります。\n\n* 何を試したかもコメントしてください。そうすれば、確認してくれたことがわかります。🤓\n\n## プルリクエストを作成 { #create-a-pull-request }\n\n[貢献](contributing.md)として、次のようにプルリクエストでソースコードに貢献できます:\n\n* ドキュメントで見つけたタイポの修正。\n* 自分が作成/発見した FastAPI に関する記事・動画・ポッドキャストを、[このファイルを編集](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml)して共有。\n    * 該当セクションの先頭にリンクを追加してください。\n* 自分の言語への[ドキュメント翻訳を手伝う](contributing.md#translations)。\n    * 他の人が作成した翻訳のレビューも手伝えます。\n* 新しいドキュメントセクションの提案。\n* 既存のissue/バグの修正。\n    * テストを追加してください。\n* 新機能の追加。\n    * テストを追加してください。\n    * 関連があればドキュメントも追加してください。\n\n## FastAPIのメンテナンスを手伝う { #help-maintain-fastapi }\n\n**FastAPI** のメンテナンスを手伝ってください！🤓\n\nやることはたくさんあり、その多くは**あなた**にもできます。\n\n今すぐできる主なタスクは次のとおりです:\n\n* [GitHubで質問に困っている人を助ける](#help-others-with-questions-in-github)（上のセクションを参照）。\n* [プルリクエストをレビュー](#review-pull-requests)（上のセクションを参照）。\n\nこの2つが**最も時間を消費**します。FastAPI のメンテナンス作業の中心です。\n\nこれを手伝ってもらえると、**FastAPIのメンテナンスに貢献**し、**より速く・より良く前進**できるようになります。🚀\n\n## チャットに参加 { #join-the-chat }\n\n👥 [Discord チャットサーバー](https://discord.gg/VQjSZaeJmf) 👥 に参加し、FastAPI コミュニティのみんなと交流しましょう。\n\n/// tip | 豆知識\n\n質問は [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions) に投稿してください。そこなら[FastAPI Experts](fastapi-people.md#fastapi-experts)から助けてもらえる可能性がずっと高いです。\n\nチャットは一般的な会話のみに使いましょう。\n\n///\n\n### 質問でチャットを使わない { #dont-use-the-chat-for-questions }\n\nチャットは「自由な会話」がしやすいため、一般的すぎて答えにくい質問になりがちです。そのため、回答が得られない可能性があります。\n\nGitHub では、テンプレートが正しい形で質問を書くのを助けてくれるため、良い回答を得やすくなりますし、質問する前に自分で問題を解決できることもあります。さらにGitHubなら、時間がかかっても私が必ずすべてに回答できるようにできます。チャットでは私個人にはそれができません。😅\n\nチャットでの会話はGitHubほど検索しやすくないため、質問と回答が会話に埋もれがちです。そして、[FastAPI Expert](fastapi-people.md#fastapi-experts)になるためにカウントされるのはGitHub上の活動だけです。ですから、GitHubの方が注目を集めやすいでしょう。\n\n一方で、チャットには数千人のユーザーがいるため、ほぼ常に誰かと会話できる可能性が高いです。😄\n\n## 作者をスポンサー { #sponsor-the-author }\n\nあなたの**製品/会社**が **FastAPI** に依存している、または関連しており、そのユーザーにリーチしたい場合は、[GitHub sponsors](https://github.com/sponsors/tiangolo) を通じて作者（私）を支援できます。プランに応じて、ドキュメントにバッジが表示されるなどの特典がある場合があります。🎁\n\n---\n\nThanks! 🚀\n"
  },
  {
    "path": "docs/ja/docs/history-design-future.md",
    "content": "# 歴史、設計、そしてこれから { #history-design-and-future }\n\nしばらく前に、[ある **FastAPI** ユーザーが質問しました](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920):\n\n> このプロジェクトの歴史は？何もないところから、数週間ですごいものができているようです。 [...]\n\nこれがその歴史のほんの一部です。\n\n## 代替手段 { #alternatives }\n\n数年前から、私は複雑な要件を持つAPI (機械学習、分散システム、非同期ジョブ、NoSQLデータベースなど) を作成しており、いくつかの開発者チームを率いています。\n\nその一環で、多くの方法を調査し、テストし、利用する必要がありました。\n\n**FastAPI** の歴史は、その前身の歴史が大部分を占めています。\n\n[代替手段](alternatives.md)のセクションでこう述べています:\n\n<blockquote markdown=\"1\">\n\n**FastAPI**は、他の人々のこれまでの働きがなければ存在しなかったでしょう。\n\n以前に作られた多くのツールが、作成における刺激として役立ってきました。\n\n私は数年前から新しいフレームワークの作成を避けてきました。まず、**FastAPI**でカバーされているすべての機能を、さまざまなフレームワーク、プラグイン、ツールを使って解決しようとしました。\n\nしかし、その時点では、これらの機能をすべて提供し、以前のツールから優れたアイデアを取り入れ、可能な限り最高の方法でそれらを組み合わせ、それまで利用できなかった言語機能 (Python 3.6以降の型ヒント) を利用したものを作る以外に選択肢はありませんでした。\n\n</blockquote>\n\n## 調査 { #investigation }\n\nすべて既存の代替手段を使うことで、そのすべてを学び、アイデアを得て、自分や一緒に仕事をしてきた開発者のチームにとって最良の方法で組み合わせる機会を得ました。\n\nたとえば、理想的にはPythonの標準的な型ヒントに基づくべきであることが明らかになりました。\n\nまた、すでにある規格を利用するのがベストな方法でした。\n\nそこで、**FastAPI**のコードを書き始める前に、OpenAPI、JSON Schema、OAuth2などの仕様を数ヶ月かけて勉強し、それらの関係、重複する箇所、相違点を理解しました。\n\n## 設計 { #design }\n\nその後、 (FastAPIを使う開発者として) ユーザーが欲しい「API」の設計に時間を費やしました。\n\nもっとも人気のあるPythonエディターでいくつかのアイデアをテストしました。PyCharm、VS Code、Jediベースのエディターです。\n\n最新の [Python開発者調査](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools)で、それらのエディターがユーザーの80%をカバーしていました。\n\nこれは、**FastAPI**がPython開発者の80%が使用しているエディターで特別にテストされたことを意味します。また、ほとんどの他のエディターも同様に動作する傾向があるため、この恩恵は事実上すべてのエディターでうけられるはずです。\n\nそうすることで、コードの重複を可能な限り減らし、どこでも補完があるようにし、タイプチェックやエラーチェックなどを実現する最善の方法を見つけました。\n\nすべての箇所で、すべての開発者に最高の開発体験を提供しました。\n\n## 要件 { #requirements }\n\nいくつかの代替手法を試したあと、私は[**Pydantic**](https://docs.pydantic.dev/)の強みを利用することを決めました。\n\nそして、JSON Schemaに完全に準拠するようにしたり、制約宣言を定義するさまざまな方法をサポートしたり、いくつかのエディターでのテストに基づいてエディターのサポート (型チェック、自動補完) を改善するために貢献しました。\n\n開発中、もう1つの重要な鍵となる[**Starlette**](https://www.starlette.dev/)にも貢献しました。\n\n## 開発 { #development }\n\n私が**FastAPI**自体の作成を開始した時には、ほとんどの部分がすでに準備されており、設計が定義され、必要な条件とツールの準備ができていました。そして規格や仕様に関する知識が、明確になり、更新されていました。\n\n## これから { #future }\n\nこの時点ですでに、これらのアイデアを持った**FastAPI**が多くの人の役に立っていることは明らかです。\n\n多くのユースケースに適しているため、既存の方法よりも選ばれています。\n\n多くの開発者やチームが、すでに **FastAPI** にプロジェクトを依存しています (私と私のチームも含めて) 。\n\nしかし、まだまだ多くの改善点や機能があります。\n\n**FastAPI**には大きな未来が待っています。\n\nそして、[あなたの助け](help-fastapi.md)を大いに歓迎します。\n"
  },
  {
    "path": "docs/ja/docs/how-to/authentication-error-status-code.md",
    "content": "# 古い 403 認証エラーのステータスコードを使う { #use-old-403-authentication-error-status-codes }\n\nFastAPI バージョン `0.122.0` より前は、統合されたセキュリティユーティリティが認証に失敗してクライアントへエラーを返す際、HTTP ステータスコード `403 Forbidden` を使用していました。\n\nFastAPI バージョン `0.122.0` 以降では、より適切な HTTP ステータスコード `401 Unauthorized` を使用し、HTTP 仕様に従ってレスポンスに妥当な `WWW-Authenticate` ヘッダーを含めます。[RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized)。\n\nしかし、何らかの理由でクライアントが従来の挙動に依存している場合は、セキュリティクラスでメソッド `make_not_authenticated_error` をオーバーライドすることで、その挙動に戻せます。\n\nたとえば、既定の `401 Unauthorized` エラーの代わりに `403 Forbidden` エラーを返す `HTTPBearer` のサブクラスを作成できます:\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip | 豆知識\n\nこの関数は例外インスタンスを返す点に注意してください。ここでは例外を送出しません。送出は内部の他のコードで行われます。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/how-to/conditional-openapi.md",
    "content": "# 条件付き OpenAPI { #conditional-openapi }\n\n必要であれば、設定と環境変数を利用して、環境に応じて条件付きでOpenAPIを構成することが可能です。また、完全にOpenAPIを無効にすることもできます。\n\n## セキュリティとAPI、およびドキュメントについて { #about-security-apis-and-docs }\n\n本番環境においてドキュメントのUIを非表示にすることによって、APIを保護しようと *すべきではありません*。\n\nそれは、APIのセキュリティの強化にはならず、*path operations* は依然として利用可能です。\n\nもしセキュリティ上の欠陥がソースコードにあるならば、それは存在したままです。\n\nドキュメンテーションを非表示にするのは、単にあなたのAPIへのアクセス方法を難解にするだけでなく、同時にあなた自身の本番環境でのAPIのデバッグを困難にしてしまう可能性があります。単純に、[秘匿によるセキュリティ](https://en.wikipedia.org/wiki/Security_through_obscurity) の一つの形態として考えられるでしょう。\n\nもしあなたのAPIのセキュリティを強化したいなら、いくつかのよりよい方法があります。例を示すと、\n\n* リクエストボディとレスポンスのためのPydanticモデルの定義を見直す。\n* 依存関係に基づきすべての必要なパーミッションとロールを設定する。\n* パスワードを絶対に平文で保存しない。パスワードハッシュのみを保存する。\n* pwdlibやJWTトークンに代表される、よく知られた暗号化ツールを使って実装する。\n* そして必要なところでは、もっと細かいパーミッション制御をOAuth2スコープを使って行う。\n* ...など\n\nそれでも、例えば本番環境のような特定の環境のみで、あるいは環境変数の設定によってAPIドキュメントをどうしても無効にしたいという、非常に特殊なユースケースがあるかもしれません。\n\n## 設定と環境変数による条件付き OpenAPI { #conditional-openapi-from-settings-and-env-vars }\n\n生成するOpenAPIとドキュメントUIの構成は、共通のPydanticの設定を使用して簡単に切り替えられます。\n\n例えば、\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\nここでは `openapi_url` の設定を、デフォルトの `\"/openapi.json\"` のまま宣言しています。\n\nそして、これを `FastAPI` appを作る際に使います。\n\nそれから、以下のように `OPENAPI_URL` という環境変数を空文字列に設定することによってOpenAPI (UIドキュメントを含む) を無効化することができます。\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nすると、以下のように `/openapi.json`, `/docs`, `/redoc` のどのURLにアクセスしても、 `404 Not Found` エラーが返ってくるようになります。\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/ja/docs/how-to/configure-swagger-ui.md",
    "content": "# Swagger UI の設定 { #configure-swagger-ui }\n\nいくつかの追加の [Swagger UI パラメータ](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)を設定できます。\n\n設定するには、`FastAPI()` のアプリオブジェクトを作成するとき、または `get_swagger_ui_html()` 関数に `swagger_ui_parameters` 引数を渡します。\n\n`swagger_ui_parameters` は、Swagger UI に直接渡される設定を含む辞書を受け取ります。\n\nFastAPI はそれらの設定を **JSON** に変換し、JavaScript と互換にします。Swagger UI が必要とするのはこの形式です。\n\n## シンタックスハイライトを無効化 { #disable-syntax-highlighting }\n\n例えば、Swagger UI のシンタックスハイライトを無効化できます。\n\n設定を変更しなければ、シンタックスハイライトはデフォルトで有効です:\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\nしかし、`syntaxHighlight` を `False` に設定すると無効化できます:\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n...その場合、Swagger UI ではシンタックスハイライトが表示されなくなります:\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## テーマの変更 { #change-the-theme }\n\n同様に、キー `\"syntaxHighlight.theme\"`（途中にドットが含まれている点に注意）でシンタックスハイライトのテーマを設定できます:\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\nこの設定により、シンタックスハイライトの配色テーマが変わります:\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## 既定の Swagger UI パラメータの変更 { #change-default-swagger-ui-parameters }\n\nFastAPI には、多くのユースケースに適した既定の設定パラメータが含まれています。\n\n既定では次の設定が含まれます:\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\n引数 `swagger_ui_parameters` に別の値を指定することで、これらを上書きできます。\n\n例えば、`deepLinking` を無効化するには、次の設定を `swagger_ui_parameters` に渡します:\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## その他の Swagger UI パラメータ { #other-swagger-ui-parameters }\n\n利用可能な他のすべての設定については、公式の [Swagger UI パラメータのドキュメント](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)を参照してください。\n\n## JavaScript 専用の設定 { #javascript-only-settings }\n\nSwagger UI では、他にも **JavaScript 専用** のオブジェクト（例: JavaScript の関数）による設定が可能です。\n\nFastAPI には、次の JavaScript 専用の `presets` 設定も含まれています:\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\nこれらは文字列ではなく **JavaScript** のオブジェクトであるため、Python のコードから直接渡すことはできません。\n\nそのような JavaScript 専用の設定を使う必要がある場合は、上記のいずれかの方法を使用し、Swagger UI の path operation をオーバーライドして、必要な JavaScript を手動で記述してください。\n"
  },
  {
    "path": "docs/ja/docs/how-to/custom-docs-ui-assets.md",
    "content": "# カスタムドキュメント UI の静的アセット（セルフホスティング） { #custom-docs-ui-static-assets-self-hosting }\n\nAPI ドキュメントは **Swagger UI** と **ReDoc** を使用しており、それぞれにいくつかの JavaScript と CSS ファイルが必要です。\n\n既定では、これらのファイルは <abbr title=\"Content Delivery Network - コンテンツ配信ネットワーク: 通常は複数のサーバーで構成され、JavaScript や CSS などの静的ファイルを提供するサービス。クライアントに近いサーバーからそれらのファイルを配信することで、パフォーマンスを改善するためによく使われます。\">CDN</abbr> から配信されます。\n\nしかし、カスタマイズすることも可能で、特定の CDN を指定したり、自分でファイルを配信したりできます。\n\n## JavaScript と CSS のカスタム CDN { #custom-cdn-for-javascript-and-css }\n\n別の <abbr title=\"Content Delivery Network - コンテンツ配信ネットワーク\">CDN</abbr> を使いたいとします。例えば `https://unpkg.com/` を使いたい場合です。\n\n例えば、一部の URL が制限されている国に住んでいる場合に役立ちます。\n\n### 自動ドキュメントの無効化 { #disable-the-automatic-docs }\n\n最初の手順は自動ドキュメントを無効化することです。デフォルトではそれらは既定の CDN を使用します。\n\n無効化するには、`FastAPI` アプリ作成時にそれらの URL を `None` に設定します:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### カスタムドキュメントの追加 { #include-the-custom-docs }\n\nこれで、カスタムドキュメント用の *path operations* を作成できます。\n\nFastAPI の内部関数を再利用してドキュメント用の HTML ページを生成し、必要な引数を渡せます:\n\n- `openapi_url`: ドキュメントの HTML ページが API の OpenAPI スキーマを取得する URL。ここでは属性 `app.openapi_url` を使用できます。\n- `title`: API のタイトル。\n- `oauth2_redirect_url`: 既定値を使うにはここで `app.swagger_ui_oauth2_redirect_url` を使用できます。\n- `swagger_js_url`: Swagger UI ドキュメント用の HTML が取得する JavaScript ファイルの URL。これはカスタム CDN の URL です。\n- `swagger_css_url`: Swagger UI ドキュメント用の HTML が取得する CSS ファイルの URL。これはカスタム CDN の URL です。\n\nReDoc についても同様です...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip | 豆知識\n\n`swagger_ui_redirect` 用の *path operation* は、OAuth2 を使用する場合の補助です。\n\nAPI を OAuth2 プロバイダと統合すると、認証を実行して取得したクレデンシャルを持った状態で API ドキュメントに戻れます。そして実際の OAuth2 認証を用いてドキュメント上から API と対話できます。\n\nSwagger UI がこの処理を裏側で行いますが、そのためにこの「redirect」の補助が必要です。\n\n///\n\n### テスト用の *path operation* を作成 { #create-a-path-operation-to-test-it }\n\nすべてが動作するかをテストできるように、*path operation* を作成します:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### テスト { #test-it }\n\nこれで、[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) にアクセスしてページを再読み込みすると、新しい CDN からそれらのアセットが読み込まれるはずです。\n\n## ドキュメント用 JavaScript と CSS のセルフホスティング { #self-hosting-javascript-and-css-for-docs }\n\nオフライン（インターネット非接続）でも、あるいはローカルネットワークで、アプリを動作させたい場合などには、JavaScript と CSS をセルフホストするのが有用です。\n\nここでは、同じ FastAPI アプリ内でそれらのファイルを配信し、ドキュメントでそれらを使用するように設定する方法を示します。\n\n### プロジェクトのファイル構成 { #project-file-structure }\n\nプロジェクトのファイル構成が次のようになっているとします:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\nこれらの静的ファイルを保存するためのディレクトリを作成します。\n\n新しいファイル構成は次のようになります:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### ファイルのダウンロード { #download-the-files }\n\nドキュメントに必要な静的ファイルをダウンロードし、`static/` ディレクトリに配置します。\n\n各リンクを右クリックして「リンク先を別名で保存...」のようなオプションを選べます。\n\n**Swagger UI** では次のファイルを使用します:\n\n- [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n- [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\nそして **ReDoc** では次のファイルを使用します:\n\n- [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\nその後、ファイル構成は次のようになります:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### 静的ファイルの配信 { #serve-the-static-files }\n\n- `StaticFiles` をインポートします。\n- 特定のパスに `StaticFiles()` インスタンスを「マウント」します。\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### 静的ファイルのテスト { #test-the-static-files }\n\nアプリケーションを起動し、[http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js) にアクセスします。\n\n**ReDoc** 用の非常に長い JavaScript ファイルが表示されるはずです。\n\n先頭は次のようになっているかもしれません:\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\nこれで、アプリから静的ファイルを配信できていること、そしてドキュメント用の静的ファイルを正しい場所に配置できていることが確認できます。\n\n次に、ドキュメントでそれらの静的ファイルを使用するようにアプリを設定します。\n\n### 静的ファイル用に自動ドキュメントを無効化 { #disable-the-automatic-docs-for-static-files }\n\nカスタム CDN を使う場合と同様、最初の手順は自動ドキュメントを無効化することです。既定では CDN を使用します。\n\n無効化するには、`FastAPI` アプリ作成時にそれらの URL を `None` に設定します:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### 静的ファイル用のカスタムドキュメントを追加 { #include-the-custom-docs-for-static-files }\n\nカスタム CDN と同様の方法で、カスタムドキュメント用の *path operations* を作成できます。\n\n再び、FastAPI の内部関数を再利用してドキュメント用の HTML ページを生成し、必要な引数を渡します:\n\n- `openapi_url`: ドキュメントの HTML ページが API の OpenAPI スキーマを取得する URL。ここでは属性 `app.openapi_url` を使用できます。\n- `title`: API のタイトル。\n- `oauth2_redirect_url`: 既定値を使うにはここで `app.swagger_ui_oauth2_redirect_url` を使用できます。\n- `swagger_js_url`: Swagger UI ドキュメント用の HTML が取得する **JavaScript** ファイルの URL。**これはあなたのアプリ自身がいま配信しているものです**。\n- `swagger_css_url`: Swagger UI ドキュメント用の HTML が取得する **CSS** ファイルの URL。**これはあなたのアプリ自身がいま配信しているものです**。\n\nReDoc についても同様です...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip | 豆知識\n\n`swagger_ui_redirect` 用の *path operation* は、OAuth2 を使用する場合の補助です。\n\nAPI を OAuth2 プロバイダと統合すると、認証を実行して取得したクレデンシャルを持った状態で API ドキュメントに戻れます。そして実際の OAuth2 認証を用いてドキュメント上から API と対話できます。\n\nSwagger UI がこの処理を裏側で行いますが、そのためにこの「redirect」の補助が必要です。\n\n///\n\n### 静的ファイルをテストするための *path operation* を作成 { #create-a-path-operation-to-test-static-files }\n\nすべてが動作するかをテストできるように、*path operation* を作成します:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### 静的ファイル UI のテスト { #test-static-files-ui }\n\nこれで、WiFi を切断して [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) にアクセスし、ページを再読み込みできるはずです。\n\nインターネットに接続していなくても、API のドキュメントを表示し、API と対話できます。\n"
  },
  {
    "path": "docs/ja/docs/how-to/custom-request-and-route.md",
    "content": "# カスタム Request と APIRoute クラス { #custom-request-and-apiroute-class }\n\n場合によっては、`Request` や `APIRoute` クラスで使われるロジックを上書きしたいことがあります。\n\n特に、ミドルウェアでのロジックの代替として有効な場合があります。\n\nたとえば、アプリケーションで処理される前にリクエストボディを読み取ったり操作したりしたい場合です。\n\n/// danger | 警告\n\nこれは「上級」機能です。\n\nFastAPI を始めたばかりの場合は、このセクションは読み飛ばしてもよいでしょう。\n\n///\n\n## ユースケース { #use-cases }\n\nユースケースの例:\n\n* JSON ではないリクエストボディを JSON に変換する（例: [`msgpack`](https://msgpack.org/index.html)）。\n* gzip 圧縮されたリクエストボディの解凍。\n* すべてのリクエストボディの自動ロギング。\n\n## カスタムリクエストボディのエンコーディングの処理 { #handling-custom-request-body-encodings }\n\ngzip のリクエストを解凍するために、カスタムの `Request` サブクラスを使う方法を見ていきます。\n\nそして、そのカスタムリクエストクラスを使うための `APIRoute` サブクラスを用意します。\n\n### カスタム `GzipRequest` クラスの作成 { #create-a-custom-gziprequest-class }\n\n/// tip | 豆知識\n\nこれは仕組みを示すためのサンプルです。Gzip 対応が必要な場合は、用意されている [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware) を使用できます。\n\n///\n\nまず、`GzipRequest` クラスを作成します。これは適切なヘッダーがある場合に本体を解凍するよう、`Request.body()` メソッドを上書きします。\n\nヘッダーに `gzip` がなければ、解凍は試みません。\n\nこの方法により、同じルートクラスで gzip 圧縮済み／未圧縮のリクエストの両方を扱えます。\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### カスタム `GzipRoute` クラスの作成 { #create-a-custom-gziproute-class }\n\n次に、`GzipRequest` を利用する `fastapi.routing.APIRoute` のカスタムサブクラスを作成します。\n\nここでは `APIRoute.get_route_handler()` メソッドを上書きします。\n\nこのメソッドは関数を返します。そしてその関数がリクエストを受け取り、レスポンスを返します。\n\nここでは、元のリクエストから `GzipRequest` を作成するために利用します。\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | 技術詳細\n\n`Request` には `request.scope` 属性があり、これはリクエストに関するメタデータを含む Python の `dict` です。\n\n`Request` には `request.receive` もあり、これはリクエストの本体を「受信」するための関数です。\n\n`scope` の `dict` と `receive` 関数はいずれも ASGI 仕様の一部です。\n\nそしてこの 2 つ（`scope` と `receive`）が、新しい `Request` インスタンスを作成するために必要なものです。\n\n`Request` について詳しくは、[Starlette の Requests に関するドキュメント](https://www.starlette.dev/requests/) を参照してください。\n\n///\n\n`GzipRequest.get_route_handler` が返す関数が異なるのは、`Request` を `GzipRequest` に変換する点だけです。\n\nこれにより、`GzipRequest` は必要に応じてデータを解凍してから *path operations* に渡します。\n\nそれ以降の処理ロジックはすべて同じです。\n\nただし、`GzipRequest.body` を変更しているため、必要に応じて **FastAPI** によって読み込まれる際にリクエストボディが自動的に解凍されます。\n\n## 例外ハンドラでのリクエストボディへのアクセス { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip | 豆知識\n\n同じ問題を解決するには、`RequestValidationError` 用のカスタムハンドラで `body` を使う方がずっと簡単でしょう（[エラー処理](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)）。\n\nただし、この例も有効で、内部コンポーネントとどのようにやり取りするかを示しています。\n\n///\n\n同じアプローチを使って、例外ハンドラ内でリクエストボディにアクセスすることもできます。\n\nやることは、`try`/`except` ブロックの中でリクエストを処理するだけです：\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\n例外が発生しても、`Request` インスタンスはスコープ内に残るため、エラー処理時にリクエストボディを読み取り、活用できます：\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## ルーターでのカスタム `APIRoute` クラス { #custom-apiroute-class-in-a-router }\n\n`APIRouter` の `route_class` パラメータを設定することもできます：\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\nこの例では、`router` 配下の *path operations* はカスタムの `TimedRoute` クラスを使用し、レスポンスの生成にかかった時間を示す追加の `X-Response-Time` ヘッダーがレスポンスに含まれます：\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/ja/docs/how-to/extending-openapi.md",
    "content": "# OpenAPI の拡張 { #extending-openapi }\n\n生成された OpenAPI スキーマを変更する必要がある場合があります。\n\nこのセクションではその方法を説明します。\n\n## 通常のプロセス { #the-normal-process }\n\n通常（デフォルト）のプロセスは次のとおりです。\n\n`FastAPI` アプリケーション（インスタンス）には、OpenAPI スキーマを返すことが期待される `.openapi()` メソッドがあります。\n\nアプリケーションオブジェクトの作成時に、`/openapi.json`（または `openapi_url` に設定したパス）への path operation が登録されます。\n\nこれは単に、アプリケーションの `.openapi()` メソッドの結果を含む JSON レスポンスを返します。\n\nデフォルトでは、`.openapi()` メソッドはプロパティ `.openapi_schema` に内容があるかを確認し、あればそれを返します。\n\nなければ、`fastapi.openapi.utils.get_openapi` にあるユーティリティ関数を使って生成します。\n\nこの関数 `get_openapi()` は次の引数を受け取ります:\n\n- `title`: ドキュメントに表示される OpenAPI のタイトル。\n- `version`: API のバージョン。例: `2.5.0`。\n- `openapi_version`: 使用する OpenAPI 仕様のバージョン。デフォルトは最新の `3.1.0`。\n- `summary`: API の短い概要。\n- `description`: API の説明。Markdown を含めることができ、ドキュメントに表示されます。\n- `routes`: ルートのリスト。登録済みの各 path operation です。`app.routes` から取得されます。\n\n/// info | 情報\n\nパラメータ `summary` は OpenAPI 3.1.0 以降で利用可能で、FastAPI 0.99.0 以降が対応しています。\n\n///\n\n## デフォルトの上書き { #overriding-the-defaults }\n\n上記の情報を使って、同じユーティリティ関数で OpenAPI スキーマを生成し、必要な部分を上書きできます。\n\nたとえば、[カスタムロゴを含めるための ReDoc の OpenAPI 拡張](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo)を追加してみましょう。\n\n### 通常の **FastAPI** { #normal-fastapi }\n\nまず、通常どおりに **FastAPI** アプリケーションを実装します:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### OpenAPI スキーマの生成 { #generate-the-openapi-schema }\n\n次に、`custom_openapi()` 関数内で同じユーティリティ関数を使って OpenAPI スキーマを生成します:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### OpenAPI スキーマの変更 { #modify-the-openapi-schema }\n\nOpenAPI スキーマの `info`「オブジェクト」にカスタムの `x-logo` を追加して、ReDoc 拡張を加えます:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### OpenAPI スキーマのキャッシュ { #cache-the-openapi-schema }\n\n生成したスキーマを保持する「キャッシュ」として `.openapi_schema` プロパティを利用できます。\n\nこうすることで、ユーザーが API ドキュメントを開くたびにスキーマを生成する必要がなくなります。\n\n最初の1回だけ生成され、その後は同じキャッシュ済みスキーマが以降のリクエストで使われます。\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### メソッドの上書き { #override-the-method }\n\nこれで、`.openapi()` メソッドを新しい関数に置き換えられます。\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### 確認 { #check-it }\n\n[http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) にアクセスすると、カスタムロゴ（この例では **FastAPI** のロゴ）が使われていることが確認できます:\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/ja/docs/how-to/general.md",
    "content": "# 一般 - ハウツー - レシピ { #general-how-to-recipes }\n\nここでは、一般的またはよくある質問に対して、ドキュメント内の他の箇所への参照をいくつか示します。\n\n## データのフィルタリング - セキュリティ { #filter-data-security }\n\n返すべき以上のデータを返さないようにするには、[チュートリアル - レスポンスモデル - 戻り値の型](../tutorial/response-model.md) を参照してください。\n\n## レスポンス性能の最適化 - レスポンスモデル - 戻り値の型 { #optimize-response-performance-response-model-return-type }\n\nJSON データを返す際の性能を最適化するには、戻り値の型またはレスポンスモデルを使用してください。そうすることで、Pydantic が Python を経由せずに Rust 側で JSON へのシリアライズを処理します。詳細は [チュートリアル - レスポンスモデル - 戻り値の型](../tutorial/response-model.md) を参照してください。\n\n## ドキュメントのタグ - OpenAPI { #documentation-tags-openapi }\n\n*path operations* にタグを追加し、ドキュメント UI でグループ化するには、[チュートリアル - path operation の設定 - タグ](../tutorial/path-operation-configuration.md#tags) を参照してください。\n\n## ドキュメントの概要と説明 - OpenAPI { #documentation-summary-and-description-openapi }\n\n*path operations* に概要と説明を追加し、ドキュメント UI に表示するには、[チュートリアル - path operation の設定 - 概要と説明](../tutorial/path-operation-configuration.md#summary-and-description) を参照してください。\n\n## ドキュメントのレスポンス説明 - OpenAPI { #documentation-response-description-openapi }\n\nドキュメント UI に表示されるレスポンスの説明を定義するには、[チュートリアル - path operation の設定 - レスポンスの説明](../tutorial/path-operation-configuration.md#response-description) を参照してください。\n\n## *Path Operation* の非推奨化 - OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\n*path operation* を非推奨にし、ドキュメント UI に表示するには、[チュートリアル - path operation の設定 - 非推奨](../tutorial/path-operation-configuration.md#deprecate-a-path-operation) を参照してください。\n\n## 任意のデータを JSON 互換に変換 { #convert-any-data-to-json-compatible }\n\n任意のデータを JSON 互換に変換するには、[チュートリアル - JSON 互換エンコーダ](../tutorial/encoder.md) を参照してください。\n\n## OpenAPI メタデータ - ドキュメント { #openapi-metadata-docs }\n\nライセンス、バージョン、連絡先などを含むメタデータを OpenAPI スキーマに追加するには、[チュートリアル - メタデータとドキュメントの URL](../tutorial/metadata.md) を参照してください。\n\n## OpenAPI のカスタム URL { #openapi-custom-url }\n\nOpenAPI の URL をカスタマイズ（または削除）するには、[チュートリアル - メタデータとドキュメントの URL](../tutorial/metadata.md#openapi-url) を参照してください。\n\n## OpenAPI ドキュメントの URL { #openapi-docs-urls }\n\n自動生成されるドキュメント UI が使用する URL を変更するには、[チュートリアル - メタデータとドキュメントの URL](../tutorial/metadata.md#docs-urls) を参照してください。\n"
  },
  {
    "path": "docs/ja/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\n**FastAPI** は **ASGI** 標準に基づいているため、ASGI に対応した任意の **GraphQL** ライブラリを簡単に統合できます。\n\n同じアプリケーション内で通常の FastAPI の *path operation* と GraphQL を組み合わせて使えます。\n\n/// tip | 豆知識\n\n**GraphQL** は非常に特定のユースケースを解決します。\n\n一般的な **Web API** と比べると、**長所** と **短所** があります。\n\nご自身のユースケースで得られる **利点** が **欠点** を補うかどうかを評価してください。 🤓\n\n///\n\n## GraphQL ライブラリ { #graphql-libraries }\n\n**ASGI** をサポートする **GraphQL** ライブラリの一部を以下に示します。**FastAPI** と組み合わせて使用できます:\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * [FastAPI 向けドキュメント](https://strawberry.rocks/docs/integrations/fastapi)あり\n* [Ariadne](https://ariadnegraphql.org/)\n    * [FastAPI 向けドキュメント](https://ariadnegraphql.org/docs/fastapi-integration)あり\n* [Tartiflette](https://tartiflette.io/)\n    * ASGI 連携用の [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) あり\n* [Graphene](https://graphene-python.org/)\n    * [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3) あり\n\n## Strawberry で GraphQL { #graphql-with-strawberry }\n\n**GraphQL** が必要、または利用したい場合は、[**Strawberry**](https://strawberry.rocks/) を**推奨**します。**FastAPI** の設計に最も近く、すべてが**型アノテーション**に基づいています。\n\nユースケースによっては他のライブラリを選ぶ方がよい場合もありますが、私に尋ねられれば、おそらく **Strawberry** を試すことを勧めるでしょう。\n\nFastAPI と Strawberry を統合する方法の簡単なプレビューです:\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\n詳細は [Strawberry のドキュメント](https://strawberry.rocks/)をご覧ください。\n\nまた、[Strawberry と FastAPI](https://strawberry.rocks/docs/integrations/fastapi) の連携に関するドキュメントもあります。\n\n## Starlette の旧 `GraphQLApp` { #older-graphqlapp-from-starlette }\n\n以前の Starlette には、[Graphene](https://graphene-python.org/) と統合するための `GraphQLApp` クラスが含まれていました。\n\nこれは Starlette からは非推奨になりましたが、もしそれを使用しているコードがある場合は、同じユースケースをカバーし、**ほぼ同一のインターフェース**を持つ [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3) へ容易に**移行**できます。\n\n/// tip | 豆知識\n\nGraphQL が必要であれば、依然として [Strawberry](https://strawberry.rocks/) の利用を推奨します。独自のクラスや型ではなく、型アノテーションに基づいているためです。\n\n///\n\n## さらに学ぶ { #learn-more }\n\n**GraphQL** については、[公式 GraphQL ドキュメント](https://graphql.org/)でさらに学べます。\n\n上記の各ライブラリについては、リンク先のドキュメントをご参照ください。\n"
  },
  {
    "path": "docs/ja/docs/how-to/index.md",
    "content": "# ハウツー - レシピ { #how-to-recipes }\n\nここでは、**複数のトピック**に関するさまざまなレシピや「ハウツー」ガイドを紹介します。\n\nこれらのアイデアの多くはおおむね**独立**しており、ほとんどの場合、**あなたのプロジェクト**に直接当てはまるものだけを読めば十分です。\n\nプロジェクトにとって興味深く有用だと思うものがあれば、ぜひ確認してください。そうでなければ、読み飛ばしても問題ありません。\n\n/// tip | 豆知識\n\n**FastAPI を学ぶ**ことを体系的に進めたい場合（推奨）、代わりに [チュートリアル - ユーザーガイド](../tutorial/index.md) を章ごとに読んでください。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# Pydantic v1 から Pydantic v2 への移行 { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\n古い FastAPI アプリがある場合、Pydantic v1 を使っているかもしれません。\n\nFastAPI 0.100.0 は Pydantic v1 / v2 のどちらにも対応しており、インストールされている方を使用しました。\n\nFastAPI 0.119.0 では、Pydantic v2 内からの Pydantic v1 の部分的サポート（`pydantic.v1`）が導入され、v2 への移行が容易になりました。\n\nFastAPI 0.126.0 で Pydantic v1 のサポートは終了しましたが、しばらくの間は `pydantic.v1` は利用可能でした。\n\n/// warning | 注意\n\nPydantic チームは Python の最新バージョン、つまり **Python 3.14** から、Pydantic v1 のサポートを終了しました。\n\nこれには `pydantic.v1` も含まれ、Python 3.14 以上ではサポートされません。\n\nPython の最新機能を使いたい場合は、Pydantic v2 を使用していることを確認する必要があります。\n\n///\n\n古い FastAPI アプリで Pydantic v1 を使っている場合、ここでは Pydantic v2 への移行方法と、段階的移行を助ける **FastAPI 0.119.0 の機能** を紹介します。\n\n## 公式ガイド { #official-guide }\n\nPydantic には v1 から v2 への公式の [移行ガイド](https://docs.pydantic.dev/latest/migration/) があります。\n\n変更点、検証がより正確で厳密になった点、注意事項などが含まれます。\n\n何が変わったかをよりよく理解するために参照してください。\n\n## テスト { #tests }\n\nアプリに対する[テスト](../tutorial/testing.md)を用意し、継続的インテグレーション（CI）で実行するようにしてください。\n\nこれにより、アップグレード後も期待どおり動作していることを確認できます。\n\n## `bump-pydantic` { #bump-pydantic }\n\n多くの場合、カスタマイズのない通常の Pydantic モデルを使っていれば、v1 から v2 への移行作業の大半を自動化できます。\n\n同じ Pydantic チームが提供する [`bump-pydantic`](https://github.com/pydantic/bump-pydantic) を使用できます。\n\nこのツールは必要なコード変更のほとんどを自動で行います。\n\nその後テストを実行し、問題なければ完了です。😎\n\n## v2 における Pydantic v1 { #pydantic-v1-in-v2 }\n\nPydantic v2 には、Pydantic v1 がサブモジュール `pydantic.v1` として同梱されています。ただし、これは Python 3.13 を超えるバージョンではサポートされません。\n\nつまり、Pydantic v2 の最新バージョンをインストールし、このサブモジュールから旧 Pydantic v1 のコンポーネントをインポートして、あたかも v1 をインストールしているかのように使用できます。\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### v2 内の Pydantic v1 に対する FastAPI のサポート { #fastapi-support-for-pydantic-v1-in-v2 }\n\nFastAPI 0.119.0 以降では、移行を容易にするため、Pydantic v2 内の Pydantic v1 に対する部分的サポートもあります。\n\nそのため、Pydantic を v2 の最新に上げ、インポートを `pydantic.v1` サブモジュールに切り替えるだけで、多くの場合そのまま動作します。\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning | 注意\n\n前述のとおり、Python の最近のバージョン（Python 3.14 以降）では Pydantic v1 がサポートされないため、`pydantic.v1` の使用も Python 3.14 以上ではサポートされません。\n\n///\n\n### 同一アプリでの Pydantic v1 と v2 { #pydantic-v1-and-v2-on-the-same-app }\n\nPydantic v2 のモデルのフィールドに Pydantic v1 のモデルを（またはその逆を）埋め込むことは、Pydantic では「サポートされていません」。\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n...しかし、同じアプリ内で Pydantic v1 と v2 を別々のモデルとして分けて使うことは可能です。\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n場合によっては、同じ FastAPI の path operation 内で、Pydantic v1 と v2 の両方のモデルを扱うことも可能です:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\n上の例では、入力モデルは Pydantic v1、出力モデル（`response_model=ItemV2` で定義）は Pydantic v2 です。\n\n### Pydantic v1 のパラメータ { #pydantic-v1-parameters }\n\nPydantic v1 のモデルで `Body`、`Query`、`Form` などの FastAPI 固有のパラメータユーティリティを使う必要がある場合、v2 への移行が完了するまでの間は `fastapi.temp_pydantic_v1_params` からインポートできます:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### 段階的に移行 { #migrate-in-steps }\n\n/// tip | 豆知識\n\nまずは `bump-pydantic` を試してください。テストが通り、問題なければコマンド一発で完了です。✨\n\n///\n\n`bump-pydantic` が適用できない場合は、同一アプリで v1 と v2 のモデルを併用できるサポートを利用して、徐々に v2 へ移行できます。\n\nまず Pydantic を v2 の最新にアップグレードし、すべてのモデルのインポートを `pydantic.v1` に切り替えます。\n\nその後、モデルをグループごとに少しずつ Pydantic v1 から v2 へ移行していきます。🚶\n"
  },
  {
    "path": "docs/ja/docs/how-to/separate-openapi-schemas.md",
    "content": "# 入力と出力でOpenAPIのスキーマを分けるかどうか { #separate-openapi-schemas-for-input-and-output-or-not }\n\n**Pydantic v2** のリリース以降、生成される OpenAPI は以前より少し正確で、より正しいものになりました。😎\n\n実際には、場合によっては同じ Pydantic モデルに対して、入力用と出力用で OpenAPI に **2 つの JSON Schema** が含まれることがあります。これは **デフォルト値** の有無に依存します。\n\nその動作と、必要に応じての変更方法を見ていきます。\n\n## 入出力のPydanticモデル { #pydantic-models-for-input-and-output }\n\n次のようにデフォルト値を持つ Pydantic モデルがあるとします。\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### 入力用モデル { #model-for-input }\n\nこのモデルを次のように入力として使うと:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n...`description` フィールドは **必須ではありません**。デフォルト値が `None` だからです。\n\n### ドキュメントでの入力モデル { #input-model-in-docs }\n\nドキュメントで確認すると、`description` フィールドには **赤いアスタリスク** が付いておらず、必須としてはマークされていません:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### 出力用モデル { #model-for-output }\n\nしかし同じモデルを次のように出力として使う場合:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n...`description` にデフォルト値があるため、そのフィールドに何も返さなくても、その **デフォルト値** が入ります。\n\n### 出力のレスポンスデータ { #model-for-output-response-data }\n\nドキュメントから試してレスポンスを確認すると、コードでは一方の `description` フィールドに何も追加していないにもかかわらず、JSON レスポンスにはデフォルト値（`null`）が含まれています:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\nつまりそのフィールドには **常に値があります**。値が `None`（JSON では `null`）になることがあるだけです。\n\nしたがって、この API を使うクライアントは値の有無を確認する必要がなく、フィールドが **常に存在する** と仮定できます。場合によってはデフォルト値の `None` になるだけです。\n\nこれを OpenAPI で表現するには、そのフィールドを **必須** としてマークします。常に存在するためです。\n\nこのため、モデルの JSON Schema は、**入力か出力か** によって異なる場合があります:\n\n- **入力** では `description` は **必須ではない**\n- **出力** では **必須**（値は `None`、JSON では `null` の可能性あり）\n\n### ドキュメントでの出力モデル { #model-for-output-in-docs }\n\nドキュメントで出力モデルを見ると、`name` と `description` の **両方** が **赤いアスタリスク** で **必須** としてマークされています:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### ドキュメントでの入力・出力モデル { #model-for-input-and-output-in-docs }\n\nさらに、OpenAPI に含まれる利用可能なスキーマ（JSON Schema）を確認すると、`Item-Input` と `Item-Output` の 2 つがあることが分かります。\n\n`Item-Input` では、`description` は **必須ではありません**（赤いアスタリスクなし）。\n\n一方、`Item-Output` では、`description` は **必須**（赤いアスタリスクあり）です。\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\nこの **Pydantic v2** の機能により、API ドキュメントはより **正確** になり、自動生成されたクライアントや SDK もより正確になります。これにより、より良い **開発者エクスペリエンス** と一貫性が得られます。🎉\n\n## スキーマを分けない { #do-not-separate-schemas }\n\n一方で、**入力と出力で同じスキーマ** にしたい場合もあります。\n\n主なユースケースは、すでに自動生成されたクライアントコードや SDK があり、まだそれらをすべて更新したくない場合です。いずれは更新したいとしても、今ではないかもしれません。\n\nその場合は、**FastAPI** のパラメータ `separate_input_output_schemas=False` でこの機能を無効化できます。\n\n/// info | 情報\n\n`separate_input_output_schemas` のサポートは FastAPI `0.102.0` で追加されました。🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### ドキュメントで入力・出力に同一スキーマを使用 { #same-schema-for-input-and-output-models-in-docs }\n\nこれでモデルの入力と出力は単一のスキーマ、`Item` のみになり、`description` は **必須ではありません**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/ja/docs/how-to/testing-database.md",
    "content": "# データベースのテスト { #testing-a-database }\n\nデータベース、SQL、SQLModel については、[SQLModel ドキュメント](https://sqlmodel.tiangolo.com/)で学べます。🤓\n\nFastAPI と一緒に SQLModel を使うためのミニ [チュートリアル](https://sqlmodel.tiangolo.com/tutorial/fastapi/)があります。✨\n\nそのチュートリアルには、[SQL データベースのテスト](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/)に関するセクションも含まれています。😎\n"
  },
  {
    "path": "docs/ja/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/ja\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>FastAPI フレームワーク、高パフォーマンス、学びやすい、素早くコーディングできる、本番運用に対応</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**ドキュメント**: [https://fastapi.tiangolo.com/ja](https://fastapi.tiangolo.com/ja)\n\n**ソースコード**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI は、Python の標準である型ヒントに基づいて Python で API を構築するための、モダンで、高速（高パフォーマンス）な Web フレームワークです。\n\n主な特徴:\n\n* **高速**: **NodeJS** や **Go** 並みのとても高いパフォーマンス（Starlette と Pydantic のおかげです）。 [利用可能な最も高速な Python フレームワークの一つです](#performance)。\n* **高速なコーディング**: 開発速度を約 200%〜300% 向上させます。*\n* **少ないバグ**: 開発者起因のヒューマンエラーを約 40% 削減します。*\n* **直感的**: 素晴らしいエディタサポート。<dfn title=\"別名: auto-complete、autocompletion、IntelliSense\">補完</dfn> があらゆる場所で使えます。デバッグ時間を削減します。\n* **簡単**: 簡単に利用・習得できるようにデザインされています。ドキュメントを読む時間を削減します。\n* **短い**: コードの重複を最小限にします。各パラメータ宣言から複数の機能を得られます。バグも減ります。\n* **堅牢性**: 自動対話型ドキュメントにより、本番環境向けのコードが得られます。\n* **Standards-based**: API のオープンスタンダードに基づいており（そして完全に互換性があります）、[OpenAPI](https://github.com/OAI/OpenAPI-Specification)（以前は Swagger として知られていました）や [JSON Schema](https://json-schema.org/) をサポートします。\n\n<small>* 本番アプリケーションを構築している社内開発チームのテストに基づく見積もりです。</small>\n\n## Sponsors { #sponsors }\n\n<!-- sponsors -->\n\n### Keystone Sponsor { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### Gold and Silver Sponsors { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[その他のスポンサー](https://fastapi.tiangolo.com/ja/fastapi-people/#sponsors)\n\n## 評価 { #opinions }\n\n\"_[...] 最近 **FastAPI** を使っています。 [...] 実際に私のチームの全ての **Microsoft の機械学習サービス** で使用する予定です。 そのうちのいくつかのコアな **Windows** 製品と **Office** 製品に統合されつつあります。_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n\"_FastAPIライブラリを採用し、クエリで **予測値** を取得できる **REST** サーバを構築しました。 [for Ludwig]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n\"_**Netflix** は、**危機管理**オーケストレーションフレームワーク、**Dispatch** のオープンソースリリースを発表できることをうれしく思います。 [built with **FastAPI**]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n\"_私は **FastAPI** にワクワクしています。 めちゃくちゃ楽しいです！_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken - <strong>[Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855) podcast host</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(ref)</small></a></div>\n\n---\n\n\"_正直、あなたが作ったものは超堅実で洗練されているように見えます。いろんな意味で、それは私が **Hug** にそうなってほしかったものです。誰かがそれを作るのを見るのは本当に刺激的です。_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley - <strong>[Hug](https://github.com/hugapi/hug) creator</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(ref)</small></a></div>\n\n---\n\n\"_REST API を構築するための **モダンなフレームワーク** を学びたい方は、**FastAPI** [...] をチェックしてみてください。 [...] 高速で、使用・習得が簡単です [...]_\"\n\n\"_私たちの **API** は **FastAPI** に切り替えました [...] きっと気に入ると思います [...]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani - Matthew Honnibal - <strong>[Explosion AI](https://explosion.ai) founders - [spaCy](https://spacy.io) creators</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(ref)</small></a> - <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(ref)</small></a></div>\n\n---\n\n\"_本番運用の Python API を構築したい方には、**FastAPI** を強くおすすめします。**美しく設計**されており、**使いやすく**、**高いスケーラビリティ**があります。私たちの API ファースト開発戦略の **主要コンポーネント** となり、Virtual TAC Engineer などの多くの自動化やサービスを推進しています。_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n## FastAPI ミニドキュメンタリー { #fastapi-mini-documentary }\n\n2025 年末に公開された [FastAPI ミニドキュメンタリー](https://www.youtube.com/watch?v=mpR8ngthqiE)があります。オンラインで視聴できます:\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**、CLI 版 FastAPI { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\nWeb API の代わりにターミナルで使用する <abbr title=\"Command Line Interface - コマンドラインインターフェイス\">CLI</abbr> アプリを構築する場合は、[**Typer**](https://typer.tiangolo.com/) を確認してください。\n\n**Typer** は FastAPI の弟分です。そして、**CLI 版 FastAPI** を意図しています。 ⌨️ 🚀\n\n## 必要条件 { #requirements }\n\nFastAPI は巨人の肩の上に立っています。\n\n* [Starlette](https://www.starlette.dev/)（Web 部分）\n* [Pydantic](https://docs.pydantic.dev/)（データ部分）\n\n## インストール { #installation }\n\n[仮想環境](https://fastapi.tiangolo.com/ja/virtual-environments/) を作成して有効化し、それから FastAPI をインストールします。\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**注**: すべてのターミナルで動作するように、`\"fastapi[standard]\"` は必ずクォートで囲んでください。\n\n## アプリケーション例 { #example }\n\n### 作成 { #create-it }\n\n`main.py` ファイルを作成し、以下のコードを入力します。\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>または <code>async def</code> を使います...</summary>\n\nコードで `async` / `await` を使用する場合は、`async def` を使います。\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**注**:\n\nわからない場合は、_「In a hurry?」_ セクションの [ドキュメントの `async` と `await`](https://fastapi.tiangolo.com/ja/async/#in-a-hurry) を確認してください。\n\n</details>\n\n### 実行 { #run-it }\n\n以下のコマンドでサーバーを起動します。\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary><code>fastapi dev</code> コマンドについて</summary>\n\n`fastapi dev` コマンドは `main.py` ファイルを自動的に読み取り、その中の **FastAPI** アプリを検出し、[Uvicorn](https://www.uvicorn.dev) を使用してサーバーを起動します。\n\nデフォルトでは、`fastapi dev` はローカル開発向けに自動リロードを有効にして起動します。\n\n詳しくは [FastAPI CLI docs](https://fastapi.tiangolo.com/ja/fastapi-cli/) を参照してください。\n\n</details>\n\n### 動作確認 { #check-it }\n\nブラウザで [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery) を開きます。\n\n以下の JSON のレスポンスが確認できます。\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\nすでに以下の API が作成されています。\n\n* _パス_ `/` と `/items/{item_id}` で HTTP リクエストを受け取ります。\n* 両方の _パス_ は `GET` <em>操作</em>（HTTP _メソッド_ としても知られています）を取ります。\n* _パス_ `/items/{item_id}` は `int` であるべき _パスパラメータ_ `item_id` を持ちます。\n* _パス_ `/items/{item_id}` はオプションの `str` _クエリパラメータ_ `q` を持ちます。\n\n### 自動対話型 API ドキュメント { #interactive-api-docs }\n\n次に、[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) にアクセスします。\n\n自動対話型 API ドキュメントが表示されます（[Swagger UI](https://github.com/swagger-api/swagger-ui) が提供しています）。\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### 代替 API ドキュメント { #alternative-api-docs }\n\n次に、[http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) にアクセスします。\n\n代替の自動ドキュメントが表示されます（[ReDoc](https://github.com/Rebilly/ReDoc) が提供しています）。\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## アップグレード例 { #example-upgrade }\n\n次に、`PUT` リクエストからボディを受け取るために `main.py` ファイルを修正しましょう。\n\nPydantic によって、標準的な Python の型を使ってボディを宣言します。\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n`fastapi dev` サーバーは自動でリロードされるはずです。\n\n### 自動対話型 API ドキュメントのアップグレード { #interactive-api-docs-upgrade }\n\n次に、[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) にアクセスします。\n\n* 自動対話型 API ドキュメントは新しいボディも含めて自動でアップデートされます。\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* 「Try it out」ボタンをクリックします。パラメータを入力して API と直接やりとりできます。\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* 次に、「Execute」ボタンをクリックします。ユーザーインターフェースは API と通信し、パラメータを送信し、結果を取得して画面に表示します。\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### 代替 API ドキュメントのアップグレード { #alternative-api-docs-upgrade }\n\n次に、[http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) にアクセスします。\n\n* 代替のドキュメントにも新しいクエリパラメータやボディが反映されます。\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### まとめ { #recap }\n\n要約すると、関数のパラメータとして、パラメータやボディなどの型を **一度だけ** 宣言します。\n\n標準的な最新の Python の型を使います。\n\n新しい構文や特定のライブラリのメソッドやクラスなどを覚える必要はありません。\n\n単なる標準的な **Python** です。\n\n例えば、`int` の場合:\n\n```Python\nitem_id: int\n```\n\nまたは、より複雑な `Item` モデルの場合:\n\n```Python\nitem: Item\n```\n\n...そして、この一度の宣言で、以下のようになります。\n\n* 以下を含むエディタサポート:\n    * 補完。\n    * 型チェック。\n* データの検証:\n    * データが無効な場合に自動で明確なエラーを返します。\n    * 深い入れ子になった JSON オブジェクトでも検証が可能です。\n* 入力データの <dfn title=\"別名: serialization、parsing、marshalling\">変換</dfn>: ネットワークから Python のデータや型へ。以下から読み取ります:\n    * JSON。\n    * パスパラメータ。\n    * クエリパラメータ。\n    * Cookie。\n    * ヘッダー。\n    * フォーム。\n    * ファイル。\n* 出力データの <dfn title=\"別名: serialization、parsing、marshalling\">変換</dfn>: Python のデータや型からネットワークデータへ（JSON として）変換します:\n    * Python の型（`str`、`int`、`float`、`bool`、`list` など）の変換。\n    * `datetime` オブジェクト。\n    * `UUID` オブジェクト。\n    * データベースモデル。\n    * ...などなど。\n* 2 つの代替ユーザーインターフェースを含む自動対話型 API ドキュメント:\n    * Swagger UI。\n    * ReDoc。\n\n---\n\n前のコード例に戻ると、**FastAPI** は次のように動作します。\n\n* `GET` および `PUT` リクエストのパスに `item_id` があることを検証します。\n* `GET` および `PUT` リクエストに対して `item_id` が `int` 型であることを検証します。\n    * そうでない場合、クライアントは有用で明確なエラーを受け取ります。\n* `GET` リクエストに対して、`q` という名前のオプションのクエリパラメータ（`http://127.0.0.1:8000/items/foo?q=somequery` のような）が存在するかどうかを調べます。\n    * `q` パラメータは `= None` で宣言されているため、オプションです。\n    * `None` がなければ必須になります（`PUT` の場合のボディと同様です）。\n* `PUT` リクエストを `/items/{item_id}` に送信する場合、ボディを JSON として読み込みます:\n    * 必須の属性 `name` があり、`str` であるべきことを確認します。\n    * 必須の属性 `price` があり、`float` でなければならないことを確認します。\n    * オプションの属性 `is_offer` があり、存在する場合は `bool` であるべきことを確認します。\n    * これらはすべて、深くネストされた JSON オブジェクトに対しても動作します。\n* JSON への/からの変換を自動的に行います。\n* OpenAPI ですべてを文書化し、以下で利用できます:\n    * 対話型ドキュメントシステム。\n    * 多くの言語に対応した自動クライアントコード生成システム。\n* 2 つの対話型ドキュメント Web インターフェースを直接提供します。\n\n---\n\nまだ表面的な部分に触れただけですが、仕組みはすでにイメージできているはずです。\n\n以下の行を変更してみてください。\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n...以下の:\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n...を:\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n...に変更し、エディタが属性を自動補完し、その型を知ることを確認してください。\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\nより多くの機能を含む、より完全な例については、<a href=\"https://fastapi.tiangolo.com/ja/tutorial/\">Tutorial - User Guide</a> を参照してください。\n\n**ネタバレ注意**: tutorial - user guide には以下が含まれます。\n\n* **ヘッダー**、**Cookie**、**フォームフィールド**、**ファイル**など、他のさまざまな場所からの **パラメータ** 宣言。\n* `maximum_length` や `regex` のような **検証制約** を設定する方法。\n* 非常に強力で使いやすい **<dfn title=\"別名: components、resources、providers、services、injectables\">依存性注入</dfn>** システム。\n* **JWT トークン**を用いた **OAuth2** や **HTTP Basic** 認証のサポートを含む、セキュリティと認証。\n* **深くネストされた JSON モデル**を宣言するための、より高度な（しかし同様に簡単な）手法（Pydantic のおかげです）。\n* [Strawberry](https://strawberry.rocks) および他のライブラリによる **GraphQL** 統合。\n* 以下のようなたくさんのおまけ機能（Starlette のおかげです）:\n    * **WebSockets**\n    * HTTPX と `pytest` に基づく極めて簡単なテスト\n    * **CORS**\n    * **Cookie Sessions**\n    * ...などなど。\n\n### アプリをデプロイ（任意） { #deploy-your-app-optional }\n\n必要に応じて FastAPI アプリを [FastAPI Cloud](https://fastapicloud.com) にデプロイできます。まだの場合はウェイティングリストに参加してください。 🚀\n\nすでに **FastAPI Cloud** アカウント（ウェイティングリストから招待されました 😉）がある場合は、1 コマンドでアプリケーションをデプロイできます。\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nこれで完了です！その URL でアプリにアクセスできます。 ✨\n\n#### FastAPI Cloud について { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** は **FastAPI** の作者と同じチームによって作られています。\n\n最小限の労力で API を **構築**、**デプロイ**、**アクセス** するためのプロセスを効率化します。\n\nFastAPI でアプリを構築するのと同じ **開発者体験** を、クラウドへの **デプロイ** にももたらします。 🎉\n\nFastAPI Cloud は *FastAPI and friends* オープンソースプロジェクトの主要スポンサーであり、資金提供元です。 ✨\n\n#### 他のクラウドプロバイダにデプロイ { #deploy-to-other-cloud-providers }\n\nFastAPI はオープンソースであり、標準に基づいています。選択した任意のクラウドプロバイダに FastAPI アプリをデプロイできます。\n\n各クラウドプロバイダのガイドに従って、FastAPI アプリをデプロイしてください。 🤓\n\n## パフォーマンス { #performance }\n\n独立した TechEmpower のベンチマークでは、Uvicorn で動作する **FastAPI** アプリケーションが、[利用可能な最も高速な Python フレームワークの一つ](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7)であり、Starlette と Uvicorn（FastAPI で内部的に使用されています）にのみ下回っていると示されています。（*）\n\n詳細は [Benchmarks](https://fastapi.tiangolo.com/ja/benchmarks/) セクションをご覧ください。\n\n## 依存関係 { #dependencies }\n\nFastAPI は Pydantic と Starlette に依存しています。\n\n### `standard` 依存関係 { #standard-dependencies }\n\nFastAPI を `pip install \"fastapi[standard]\"` でインストールすると、`standard` グループのオプション依存関係が含まれます。\n\nPydantic によって使用されるもの:\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - メール検証のため。\n\nStarlette によって使用されるもの:\n\n* [`httpx`](https://www.python-httpx.org) - `TestClient` を使用したい場合に必要です。\n* [`jinja2`](https://jinja.palletsprojects.com) - デフォルトのテンプレート設定を使用したい場合に必要です。\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - `request.form()` とともに、フォームの <dfn title=\"HTTP リクエストから届く文字列を Python データに変換すること\">「parsing」</dfn> をサポートしたい場合に必要です。\n\nFastAPI によって使用されるもの:\n\n* [`uvicorn`](https://www.uvicorn.dev) - アプリケーションをロードして提供するサーバーのため。これには `uvicorn[standard]` も含まれ、高性能なサービングに必要な依存関係（例: `uvloop`）が含まれます。\n* `fastapi-cli[standard]` - `fastapi` コマンドを提供します。\n    * これには `fastapi-cloud-cli` が含まれ、FastAPI アプリケーションを [FastAPI Cloud](https://fastapicloud.com) にデプロイできます。\n\n### `standard` 依存関係なし { #without-standard-dependencies }\n\n`standard` のオプション依存関係を含めたくない場合は、`pip install \"fastapi[standard]\"` の代わりに `pip install fastapi` でインストールできます。\n\n### `fastapi-cloud-cli` なし { #without-fastapi-cloud-cli }\n\n標準の依存関係を含めつつ `fastapi-cloud-cli` を除外して FastAPI をインストールしたい場合は、`pip install \"fastapi[standard-no-fastapi-cloud-cli]\"` でインストールできます。\n\n### 追加のオプション依存関係 { #additional-optional-dependencies }\n\n追加でインストールしたい依存関係があります。\n\n追加のオプション Pydantic 依存関係:\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - 設定管理のため。\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - Pydantic で使用する追加の型のため。\n\n追加のオプション FastAPI 依存関係:\n\n* [`orjson`](https://github.com/ijl/orjson) - `ORJSONResponse` を使用したい場合に必要です。\n* [`ujson`](https://github.com/esnme/ultrajson) - `UJSONResponse` を使用したい場合に必要です。\n\n## ライセンス { #license }\n\nこのプロジェクトは MIT ライセンスの条項の下でライセンスされています。\n"
  },
  {
    "path": "docs/ja/docs/learn/index.md",
    "content": "# 学習 { #learn }\n\nここでは、**FastAPI** を学習するための入門セクションとチュートリアルを紹介します。\n\nこれは、**書籍**や**コース**、FastAPIを学習するための**公式**かつ推奨される方法とみなすことができます。😎\n"
  },
  {
    "path": "docs/ja/docs/project-generation.md",
    "content": "# Full Stack FastAPI テンプレート { #full-stack-fastapi-template }\n\nテンプレートは通常、特定のセットアップが含まれていますが、柔軟でカスタマイズできるように設計されています。これにより、プロジェクトの要件に合わせて変更・適応でき、優れた出発点になります。🏁\n\nこのテンプレートを使って開始できます。初期セットアップ、セキュリティ、データベース、いくつかのAPIエンドポイントがすでに用意されています。\n\nGitHubリポジトリ: [Full Stack FastAPI Template](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## Full Stack FastAPI テンプレート - 技術スタックと機能 { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ PythonバックエンドAPI向けの [**FastAPI**](https://fastapi.tiangolo.com/ja)。\n  - 🧰 PythonのSQLデータベース操作（ORM）向けの [SQLModel](https://sqlmodel.tiangolo.com)。\n  - 🔍 FastAPIで使用される、データバリデーションと設定管理向けの [Pydantic](https://docs.pydantic.dev)。\n  - 💾 SQLデータベースとしての [PostgreSQL](https://www.postgresql.org)。\n- 🚀 フロントエンド向けの [React](https://react.dev)。\n  - 💃 TypeScript、hooks、Vite、その他のモダンなフロントエンドスタックの各要素を使用。\n  - 🎨 フロントエンドコンポーネント向けの [Tailwind CSS](https://tailwindcss.com) と [shadcn/ui](https://ui.shadcn.com)。\n  - 🤖 自動生成されたフロントエンドクライアント。\n  - 🧪 End-to-Endテスト向けの [Playwright](https://playwright.dev)。\n  - 🦇 ダークモードのサポート。\n- 🐋 開発および本番向けの [Docker Compose](https://www.docker.com)。\n- 🔒 デフォルトでの安全なパスワードハッシュ化。\n- 🔑 JWT（JSON Web Token）認証。\n- 📫 メールベースのパスワードリカバリ。\n- ✅ [Pytest](https://pytest.org) によるテスト。\n- 📞 リバースプロキシ / ロードバランサとしての [Traefik](https://traefik.io)。\n- 🚢 Docker Composeを使用したデプロイ手順（自動HTTPS証明書を処理するフロントエンドTraefikプロキシのセットアップ方法を含む）。\n- 🏭 GitHub Actionsに基づくCI（continuous integration）とCD（continuous deployment）。\n"
  },
  {
    "path": "docs/ja/docs/python-types.md",
    "content": "# Pythonの型の紹介 { #python-types-intro }\n\nPython にはオプションの「型ヒント」（「型アノテーション」とも呼ばれます）がサポートされています。\n\nこれらの **「型ヒント」** やアノテーションは、変数の<dfn title=\"例えば: str、int、float、bool\">型</dfn>を宣言できる特別な構文です。\n\n変数に型を宣言することで、エディターやツールがより良いサポートを提供できます。\n\nこれは Python の型ヒントについての **クイックチュートリアル/リフレッシュ** にすぎません。**FastAPI** で使うために必要な最低限のことだけをカバーしています。...実際には本当に少ないです。\n\n**FastAPI** はすべてこれらの型ヒントに基づいており、多くの強みと利点を与えてくれます。\n\nしかし、たとえ **FastAPI** をまったく使用しない場合でも、それらについて少し学ぶことで利点を得られます。\n\n/// note | 備考\n\nもしあなたが Python の専門家で、すでに型ヒントについてすべて知っているのであれば、次の章まで読み飛ばしてください。\n\n///\n\n## 動機 { #motivation }\n\n簡単な例から始めてみましょう:\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\nこのプログラムを呼び出すと、以下が出力されます:\n\n```\nJohn Doe\n```\n\nこの関数は以下のようなことを行います:\n\n* `first_name` と `last_name` を取得します。\n* `title()` を用いて、それぞれの最初の文字を大文字に変換します。\n* 真ん中にスペースを入れて<dfn title=\"1つにまとめます。片方の内容をもう片方の後ろに続けます。\">連結</dfn>します。\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### 編集 { #edit-it }\n\nこれはとても簡単なプログラムです。\n\nしかし、今、あなたがそれを一から書いていたと想像してみてください。\n\nパラメータの準備ができていたら、そのとき、関数の定義を始めていたことでしょう...\n\nしかし、そうすると「最初の文字を大文字に変換するあのメソッド」を呼び出す必要があります。\n\nそれは `upper` でしたか？`uppercase` でしたか？`first_uppercase`？`capitalize`？\n\nそして、古くからプログラマーの友人であるエディタで自動補完を試してみます。\n\n関数の最初のパラメータ `first_name` を入力し、ドット（`.`）を入力してから、`Ctrl+Space` を押すと補完が実行されます。\n\nしかし、悲しいことに、これはなんの役にも立ちません:\n\n<img src=\"/img/python-types/image01.png\">\n\n### 型の追加 { #add-types }\n\n先ほどのコードから一行変更してみましょう。\n\n関数のパラメータである次の断片を、以下から:\n\n```Python\n    first_name, last_name\n```\n\n以下へ変更します:\n\n```Python\n    first_name: str, last_name: str\n```\n\nこれだけです。\n\nそれが「型ヒント」です:\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\nこれは、以下のようにデフォルト値を宣言するのと同じではありません:\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\nそれとは別物です。\n\nイコール（`=`）ではなく、コロン（`:`）を使用します。\n\nそして、通常、型ヒントを追加しても、それらがない状態と起こることは何も変わりません。\n\nしかし今、あなたが再びその関数を作成している最中に、型ヒントを使っていると想像してみてください。\n\n同じタイミングで `Ctrl+Space` で自動補完を実行すると、以下のようになります:\n\n<img src=\"/img/python-types/image02.png\">\n\nこれであれば、あなたは「ベルを鳴らす」ものを見つけるまで、オプションを見てスクロールできます:\n\n<img src=\"/img/python-types/image03.png\">\n\n## より強い動機 { #more-motivation }\n\nこの関数を見てください。すでに型ヒントを持っています:\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\nエディタは変数の型を知っているので、補完だけでなく、エラーチェックをすることもできます:\n\n<img src=\"/img/python-types/image04.png\">\n\nこれで `age` を `str(age)` で文字列に変換して修正する必要があることがわかります:\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## 型の宣言 { #declaring-types }\n\n型ヒントを宣言する主な場所を見てきました。関数のパラメータです。\n\nこれは **FastAPI** で使用する主な場所でもあります。\n\n### 単純な型 { #simple-types }\n\n`str` だけでなく、Python の標準的な型すべてを宣言できます。\n\n例えば、以下を使用可能です:\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### `typing` モジュール { #typing-module }\n\nいくつかの追加のユースケースでは、標準ライブラリの `typing` モジュールから何かをインポートする必要があるかもしれません。例えば「任意の型」を受け付けることを宣言したい場合、`typing` の `Any` を使えます:\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### ジェネリック型 { #generic-types }\n\n一部の型は、角括弧内で「型パラメータ」を受け取り、内部の型を定義できます。例えば「文字列のリスト」は `list[str]` として宣言します。\n\nこのように型パラメータを取れる型は **Generic types**（ジェネリクス）と呼ばれます。\n\n次の組み込み型をジェネリクスとして（角括弧と内部の型で）使えます:\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### List { #list }\n\n例えば、`str` の `list` の変数を定義してみましょう。\n\n同じコロン（`:`）の構文で変数を宣言します。\n\n型として、`list` を指定します。\n\nリストはいくつかの内部の型を含む型なので、それらを角括弧で囲みます:\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info | 情報\n\n角括弧内の内部の型は「型パラメータ」と呼ばれています。\n\nこの場合、`str` は `list` に渡される型パラメータです。\n\n///\n\nつまり: 変数 `items` は `list` であり、このリストの各項目は `str` です。\n\nそうすることで、エディタはリストの項目を処理している間にもサポートを提供できます。\n\n<img src=\"/img/python-types/image05.png\">\n\n型がなければ、それはほぼ不可能です。\n\n変数 `item` はリスト `items` の要素の一つであることに注意してください。\n\nそれでも、エディタはそれが `str` であることを知っていて、そのためのサポートを提供しています。\n\n#### Tuple と Set { #tuple-and-set }\n\n`tuple` と `set` の宣言も同様です:\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\nつまり:\n\n* 変数 `items_t` は `int`、別の `int`、`str` の 3 つの項目を持つ `tuple` です。\n* 変数 `items_s` は `set` であり、その各項目は `bytes` 型です。\n\n#### Dict { #dict }\n\n`dict` を定義するには、カンマ区切りで 2 つの型パラメータを渡します。\n\n最初の型パラメータは `dict` のキーです。\n\n2 番目の型パラメータは `dict` の値です:\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\nつまり:\n\n* 変数 `prices` は `dict` です:\n    * この `dict` のキーは `str` 型です（例えば、各項目の名前）。\n    * この `dict` の値は `float` 型です（例えば、各項目の価格）。\n\n#### Union { #union }\n\n変数が **複数の型のいずれか** になり得ることを宣言できます。例えば、`int` または `str` です。\n\nそれを定義するには、両方の型を区切るために <dfn title=\"「ビット単位の OR 演算子」とも呼ばれますが、ここでの意味とは関係ありません。\">縦棒（`|`）</dfn> を使います。\n\nこれは「ユニオン（union）」と呼ばれます。変数がそれら 2 つの型の集合の和集合のいずれかになり得るからです。\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\nこれは `item` が `int` または `str` になり得ることを意味します。\n\n#### `None` の可能性 { #possibly-none }\n\n値が `str` のような型を持つ可能性がある一方で、`None` にもなり得ることを宣言できます。\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\nただの `str` の代わりに `str | None` を使用することで、値が常に `str` であると仮定しているときに、実際には `None` である可能性もあるというエラーをエディタが検出するのに役立ちます。\n\n### 型としてのクラス { #classes-as-types }\n\n変数の型としてクラスを宣言することもできます。\n\n名前を持つ `Person` クラスがあるとしましょう:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\n変数を `Person` 型として宣言できます:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\nそして、再び、すべてのエディタのサポートを得ることができます:\n\n<img src=\"/img/python-types/image06.png\">\n\nこれは「`one_person` はクラス `Person` の **インスタンス** である」ことを意味します。\n\n「`one_person` は `Person` という名前の **クラス** である」という意味ではありません。\n\n## Pydantic のモデル { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/) はデータ検証を行うための Python ライブラリです。\n\nデータの「形」を属性付きのクラスとして宣言します。\n\nそして、それぞれの属性は型を持ちます。\n\nさらに、いくつかの値を持つクラスのインスタンスを作成すると、その値を検証し、適切な型に変換して（もしそうであれば）すべてのデータを持つオブジェクトを提供してくれます。\n\nまた、その結果のオブジェクトですべてのエディタのサポートを受けることができます。\n\nPydantic の公式ドキュメントからの例:\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info | 情報\n\n[ Pydantic の詳細はドキュメントを参照してください](https://docs.pydantic.dev/)。\n\n///\n\n**FastAPI** はすべて Pydantic をベースにしています。\n\nすべてのことは [チュートリアル - ユーザーガイド](tutorial/index.md) で実際に見ることができます。\n\n## メタデータアノテーション付き型ヒント { #type-hints-with-metadata-annotations }\n\nPython には、`Annotated` を使って型ヒントに **追加の <dfn title=\"データに関するデータ。この場合は型に関する情報（例えば説明）。\">メタデータ</dfn>** を付与できる機能もあります。\n\n`Annotated` は `typing` からインポートできます。\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nPython 自体は、この `Annotated` で何かをするわけではありません。また、エディタや他のツールにとっても、型は依然として `str` です。\n\nしかし、`Annotated` 内のこのスペースを使って、アプリケーションをどのように動作させたいかについての追加メタデータを **FastAPI** に提供できます。\n\n覚えておくべき重要な点は、`Annotated` に渡す **最初の「型パラメータ」** が **実際の型** であることです。残りは、他のツール向けのメタデータにすぎません。\n\n今のところは、`Annotated` が存在し、それが標準の Python であることを知っておけば十分です。😎\n\n後で、これがどれほど **強力** になり得るかを見ることになります。\n\n/// tip | 豆知識\n\nこれが **標準の Python** であるという事実は、エディタで、使用しているツール（コードの解析やリファクタリングなど）とともに、**可能な限り最高の開発体験** が得られることを意味します。 ✨\n\nまた、あなたのコードが他の多くの Python ツールやライブラリとも非常に互換性が高いことも意味します。 🚀\n\n///\n\n## **FastAPI** での型ヒント { #type-hints-in-fastapi }\n\n**FastAPI** はこれらの型ヒントを利用していくつかのことを行います。\n\n**FastAPI** では型ヒントを使ってパラメータを宣言すると以下のものが得られます:\n\n* **エディタサポート**。\n* **型チェック**。\n\n...そして **FastAPI** は同じ宣言を使って、以下のことを行います:\n\n* **要件の定義**: リクエストのパスパラメータ、クエリパラメータ、ヘッダー、ボディ、依存関係などから要件を定義します。\n* **データの変換**: リクエストから必要な型にデータを変換します。\n* **データの検証**: 各リクエストから来るデータについて:\n    * データが無効な場合にクライアントに返される **自動エラー** を生成します。\n* OpenAPI を使用して API を **ドキュメント化** します:\n    * これは自動の対話型ドキュメントのユーザーインターフェイスで使われます。\n\nすべてが抽象的に聞こえるかもしれません。心配しないでください。 この全ての動作は [チュートリアル - ユーザーガイド](tutorial/index.md) で見ることができます。\n\n重要なのは、Python の標準的な型を使うことで、（クラスやデコレータなどを追加するのではなく）1 つの場所で **FastAPI** が多くの作業を代わりにやってくれているということです。\n\n/// info | 情報\n\nすでにすべてのチュートリアルを終えて、型についての詳細を見るためにこのページに戻ってきた場合は、良いリソースとして [`mypy` の「チートシート`](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html) があります。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/resources/index.md",
    "content": "# リソース { #resources }\n\n追加リソース、外部リンクなど。✈️\n"
  },
  {
    "path": "docs/ja/docs/translation-banner.md",
    "content": "/// details | 🌐 AI と人間による翻訳\n\nこの翻訳は、人間のガイドに基づいて AI によって作成されました。🤝\n\n原文の意図を取り違えていたり、不自然な表現になっている可能性があります。🤖\n\n[AI LLM をより適切に誘導するのを手伝う](https://fastapi.tiangolo.com/ja/contributing/#translations) ことで、この翻訳を改善できます。\n\n[英語版](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/ja/docs/tutorial/background-tasks.md",
    "content": "# バックグラウンドタスク { #background-tasks }\n\nレスポンスを返した *後に* 実行されるバックグラウンドタスクを定義できます。\n\nこれは、リクエスト後に処理を開始する必要があるが、クライアントがレスポンスを受け取る前に処理を終える必要のない操作に役立ちます。\n\nこれには、たとえば次のものが含まれます。\n\n* 作業実行後のメール通知:\n    * メールサーバーへの接続とメールの送信は「遅い」(数秒) 傾向があるため、すぐにレスポンスを返し、バックグラウンドでメール通知ができます。\n* データ処理:\n    * たとえば、時間のかかる処理を必要とするファイル受信時には、「Accepted」(HTTP 202) のレスポンスを返し、バックグラウンドで処理できます。\n\n## `BackgroundTasks` の使用 { #using-backgroundtasks }\n\nまず初めに、`BackgroundTasks` をインポートし、`BackgroundTasks` の型宣言と共に、*path operation function* のパラメーターを定義します:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI** は、`BackgroundTasks` 型のオブジェクトを作成し、そのパラメーターに渡します。\n\n## タスク関数の作成 { #create-a-task-function }\n\nバックグラウンドタスクとして実行される関数を作成します。\n\nこれは、パラメーターを受け取ることができる単なる標準的な関数です。\n\nこれは `async def` または通常の `def` 関数であり、**FastAPI** はこれを正しく処理します。\n\nここで、タスク関数はファイル書き込みを実行します (メール送信のシミュレーション)。\n\nまた、書き込み操作では `async` と `await` を使用しないため、通常の `def` で関数を定義します。\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## バックグラウンドタスクの追加 { #add-the-background-task }\n\n*path operation function* 内で、`.add_task()` メソッドを使用してタスク関数を *background tasks* オブジェクトに渡します。\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()` は以下の引数を受け取ります:\n\n* バックグラウンドで実行されるタスク関数 (`write_notification`)。\n* タスク関数に順番に渡す必要のある引数の列 (`email`)。\n* タスク関数に渡す必要のあるキーワード引数 (`message=\"some notification\"`)。\n\n## 依存性注入 { #dependency-injection }\n\n`BackgroundTasks` の使用は依存性注入システムでも機能し、様々な階層 (*path operation function*、依存性 (dependable)、サブ依存性など) で `BackgroundTasks` 型のパラメーターを宣言できます。\n\n**FastAPI** は、それぞれの場合の処理​​方法と同じオブジェクトの再利用方法を知っているため、すべてのバックグラウンドタスクがマージされ、バックグラウンドで後で実行されます:\n\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\n\nこの例では、レスポンスが送信された *後* にメッセージが `log.txt` ファイルに書き込まれます。\n\nリクエストにクエリがあった場合、バックグラウンドタスクでログに書き込まれます。\n\nそして、*path operation function* で生成された別のバックグラウンドタスクは、`email` パスパラメータを使用してメッセージを書き込みます。\n\n## 技術的な詳細 { #technical-details }\n\n`BackgroundTasks` クラスは、[`starlette.background`](https://www.starlette.dev/background/) から直接取得されます。\n\nこれは、FastAPI に直接インポート/インクルードされるため、`fastapi` からインポートできる上に、`starlette.background`から別の `BackgroundTask` (末尾に `s` がない) を誤ってインポートすることを回避できます。\n\n`BackgroundTasks`のみを使用することで (`BackgroundTask` ではなく)、`Request` オブジェクトを直接使用する場合と同様に、それを *path operation function* パラメーターとして使用し、**FastAPI** に残りの処理を任せることができます。\n\nそれでも、FastAPI で `BackgroundTask` を単独で使用することは可能ですが、コード内でオブジェクトを作成し、それを含むStarlette `Response` を返す必要があります。\n\n詳細については、[Starlette のバックグラウンドタスクに関する公式ドキュメント](https://www.starlette.dev/background/)を参照して下さい。\n\n## 注意 { #caveat }\n\n大量のバックグラウンド計算が必要であり、必ずしも同じプロセスで実行する必要がない場合 (たとえば、メモリや変数などを共有する必要がない場合)、[Celery](https://docs.celeryq.dev) のようなより大きな他のツールを使用するとメリットがあるかもしれません。\n\nこれらは、より複雑な構成、RabbitMQ や Redis などのメッセージ/ジョブキューマネージャーを必要とする傾向がありますが、複数のプロセス、特に複数のサーバーでバックグラウンドタスクを実行できます。\n\nただし、同じ **FastAPI** アプリから変数とオブジェクトにアクセスする必要がある場合、または小さなバックグラウンドタスク (電子メール通知の送信など) を実行する必要がある場合は、単に `BackgroundTasks` を使用できます。\n\n## まとめ { #recap }\n\n*path operation functions* と依存性のパラメータで `BackgroundTasks`をインポートして使用し、バックグラウンドタスクを追加して下さい。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/bigger-applications.md",
    "content": "# 大規模アプリケーション - 複数ファイル { #bigger-applications-multiple-files }\n\nアプリケーションや Web API を作る場合、すべてを1つのファイルに収められることはほとんどありません。\n\n**FastAPI** は、柔軟性を保ったままアプリケーションを構造化できる便利なツールを提供します。\n\n/// info | 情報\n\nFlask 出身であれば、Flask の Blueprint に相当します。\n\n///\n\n## 例のファイル構成 { #an-example-file-structure }\n\n次のようなファイル構成があるとします:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | 豆知識\n\n複数の `__init__.py` ファイルがあります: 各ディレクトリやサブディレクトリに1つずつです。\n\nこれにより、あるファイルから別のファイルへコードをインポートできます。\n\n例えば、`app/main.py` では次のように書けます:\n\n```\nfrom app.routers import items\n```\n\n///\n\n* `app` ディレクトリはすべてを含みます。そして空のファイル `app/__init__.py` があり、「Python パッケージ」（「Python モジュール」の集合）: `app` です。\n* `app/main.py` ファイルがあります。Python パッケージ（`__init__.py` のあるディレクトリ）の中にあるため、そのパッケージの「モジュール」: `app.main` です。\n* `app/dependencies.py` ファイルもあり、`app/main.py` と同様に「モジュール」: `app.dependencies` です。\n* `app/routers/` サブディレクトリに別の `__init__.py` があるので、「Python サブパッケージ」: `app.routers` です。\n* `app/routers/items.py` はパッケージ `app/routers/` 内のファイルなので、サブモジュール: `app.routers.items` です。\n* `app/routers/users.py` も同様で、別のサブモジュール: `app.routers.users` です。\n* `app/internal/` サブディレクトリにも `__init__.py` があるので、別の「Python サブパッケージ」: `app.internal` です。\n* `app/internal/admin.py` は別のサブモジュール: `app.internal.admin` です。\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n同じファイル構成にコメントを付けると次のとおりです:\n\n```bash\n.\n├── app                  # \"app\" は Python パッケージ\n│   ├── __init__.py      # このファイルにより \"app\" は「Python パッケージ」になる\n│   ├── main.py          # \"main\" モジュール（例: import app.main）\n│   ├── dependencies.py  # \"dependencies\" モジュール（例: import app.dependencies）\n│   └── routers          # \"routers\" は「Python サブパッケージ」\n│   │   ├── __init__.py  # このファイルにより \"routers\" は「Python サブパッケージ」になる\n│   │   ├── items.py     # \"items\" サブモジュール（例: import app.routers.items）\n│   │   └── users.py     # \"users\" サブモジュール（例: import app.routers.users）\n│   └── internal         # \"internal\" は「Python サブパッケージ」\n│       ├── __init__.py  # このファイルにより \"internal\" は「Python サブパッケージ」になる\n│       └── admin.py     # \"admin\" サブモジュール（例: import app.internal.admin）\n```\n\n## `APIRouter` { #apirouter }\n\nユーザーだけを扱うファイルが `/app/routers/users.py` のサブモジュールだとします。\n\nユーザーに関連する *path operations* をほかのコードから分離して整理したいはずです。\n\nただし、同じ **FastAPI** アプリケーション / Web API（同じ「Python パッケージ」の一部）である点は変わりません。\n\nそのモジュールで `APIRouter` を使って *path operations* を作成できます。\n\n### `APIRouter` のインポート { #import-apirouter }\n\nクラス `FastAPI` と同様にインポートし、「インスタンス」を作成します:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### `APIRouter` での *path operations* { #path-operations-with-apirouter }\n\nこれを使って *path operations* を宣言します。\n\n使い方は `FastAPI` クラスと同じです:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\n`APIRouter` は「ミニ `FastAPI`」のようなクラスと考えられます。\n\n同じオプションがすべてサポートされています。\n\n同じ `parameters`、`responses`、`dependencies`、`tags` などが使えます。\n\n/// tip | 豆知識\n\nこの例では変数名は `router` ですが、任意の名前を付けられます。\n\n///\n\nこの `APIRouter` をメインの `FastAPI` アプリに取り込みますが、その前に依存関係と別の `APIRouter` を確認します。\n\n## 依存関係 { #dependencies }\n\nアプリケーションの複数箇所で使う依存関係が必要になります。\n\nそのため、専用の `dependencies` モジュール（`app/dependencies.py`）に置きます。\n\nここではカスタムヘッダー `X-Token` を読む簡単な依存関係を使います:\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | 豆知識\n\nこの例を簡単にするために架空のヘッダーを使っています。\n\nしかし実際には、組み込みの [Security utilities](security/index.md) を使う方が良い結果になります。\n\n///\n\n## 別モジュールでの `APIRouter` { #another-module-with-apirouter }\n\nアプリケーションの「items」を扱うエンドポイントが `app/routers/items.py` のモジュールにあるとします。\n\n次の *path operations* があります:\n\n* `/items/`\n* `/items/{item_id}`\n\n構造は `app/routers/users.py` と同じです。\n\nしかし、もう少し賢くしてコードを少し簡潔にしたいところです。\n\nこのモジュールのすべての *path operations* には同じものがあると分かっています:\n\n* パスの `prefix`: `/items`\n* `tags`（1つのタグ: `items`）\n* 追加の `responses`\n* `dependencies`: 先ほど作成した `X-Token` の依存関係が必要\n\nそこで、各 *path operation* に個別に追加する代わりに、これらを `APIRouter` に追加できます。\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\n各 *path operation* のパスは次のように `/` で始める必要があるため:\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n...prefix の末尾に `/` を含めてはいけません。\n\nこの場合の prefix は `/items` です。\n\nまた、`tags` のリストや追加の `responses` を、このルーターに含まれるすべての *path operations* に適用するよう追加できます。\n\nさらに `dependencies` のリストを追加できます。これはこのルーター内のすべての *path operations* に追加され、それらへの各リクエストごとに実行・解決されます。\n\n/// tip | 豆知識\n\n[*path operation デコレータ*の依存関係](dependencies/dependencies-in-path-operation-decorators.md) と同様に、*path operation 関数*には値は渡されない点に注意してください。\n\n///\n\n最終的に、item のパスは次のとおりになります:\n\n* `/items/`\n* `/items/{item_id}`\n\n...意図したとおりです。\n\n* これらには、文字列 `\"items\"` を1つ含むタグのリストが付きます。\n    * これらの「タグ」は、（OpenAPI を使う）自動インタラクティブドキュメントで特に有用です。\n* すべてに事前定義した `responses` が含まれます。\n* これらすべての *path operations* では、実行前に `dependencies` のリストが評価・実行されます。\n    * 特定の *path operation* に依存関係を宣言した場合は、**それらも実行されます**。\n    * ルーターの依存関係が先に実行され、その後に[デコレータ内の `dependencies`](dependencies/dependencies-in-path-operation-decorators.md)、次に通常のパラメータ依存関係が続きます。\n    * [`scopes` を伴う `Security` 依存関係](../advanced/security/oauth2-scopes.md) を追加することもできます。\n\n/// tip | 豆知識\n\n`APIRouter` に `dependencies` を置くことで、*path operations* のグループ全体に認証を要求する、といった用途に使えます。個々の *path operation* に依存関係を追加していなくても構いません。\n\n///\n\n/// check | 確認\n\n`prefix`、`tags`、`responses`、`dependencies` の各パラメータは（ほかの多くのケースと同様に）コード重複を避けるための **FastAPI** の機能です。\n\n///\n\n### 依存関係をインポート { #import-the-dependencies }\n\nこのコードはモジュール `app.routers.items`（ファイル `app/routers/items.py`）内にあります。\n\nそして依存関係の関数はモジュール `app.dependencies`（ファイル `app/dependencies.py`）から取得する必要があります。\n\nそこで、依存関係には `..` を使った相対インポートを使います:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### 相対インポートの仕組み { #how-relative-imports-work }\n\n/// tip | 豆知識\n\nインポートの仕組みを十分理解している場合は、次の節に進んでください。\n\n///\n\nドット1つ `.` を使うと、次のような意味になります:\n\n```Python\nfrom .dependencies import get_token_header\n```\n\n意味:\n\n* このモジュール（`app/routers/items.py`）が存在する同じパッケージ（ディレクトリ `app/routers/`）から開始し...\n* モジュール `dependencies`（仮想的には `app/routers/dependencies.py`）を探し...\n* そこから関数 `get_token_header` をインポートする。\n\nしかしそのファイルは存在せず、実際の依存関係は `app/dependencies.py` にあります。\n\nアプリ／ファイル構成がどうなっていたかを思い出してください:\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\nドット2つ `..` を使うと、次のようになります:\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\n意味:\n\n* このモジュール（`app/routers/items.py`）が存在する同じパッケージ（ディレクトリ `app/routers/`）から開始し...\n* 親パッケージ（ディレクトリ `app/`）に移動し...\n* そこでモジュール `dependencies`（ファイル `app/dependencies.py`）を探し...\n* そこから関数 `get_token_header` をインポートする。\n\nこれは正しく動作します！ 🎉\n\n---\n\n同様に、ドット3つ `...` を使うと:\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\n意味:\n\n* このモジュール（`app/routers/items.py`）が存在する同じパッケージ（ディレクトリ `app/routers/`）から開始し...\n* 親パッケージ（ディレクトリ `app/`）に移動し...\n* さらにその親パッケージに移動しようとします（`app` は最上位なので親パッケージはありません 😱）...\n* そこでモジュール `dependencies`（ファイル `app/dependencies.py`）を探し...\n* そこから関数 `get_token_header` をインポートする。\n\nこれは `app/` より上位のパッケージ（独自の `__init__.py` を持つ）を参照することになります。しかしそのようなものはありません。そのため、この例ではエラーになります。🚨\n\nこれで仕組みが分かったので、どれほど複雑でも自分のアプリで相対インポートを使えます。🤓\n\n### カスタムの `tags`、`responses`、`dependencies` を追加 { #add-some-custom-tags-responses-and-dependencies }\n\n`APIRouter` に追加済みなので、各 *path operation* に `/items` の prefix や `tags=[\"items\"]` を付けていません。\n\nしかし、特定の *path operation* に適用される _追加の_ `tags` や、その *path operation* 固有の追加の `responses` を加えることはできます:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | 豆知識\n\nこの最後の *path operation* は、`[\"items\", \"custom\"]` のタグの組み合わせを持ちます。\n\nまたドキュメントには `404` と `403` の両方のレスポンスが表示されます。\n\n///\n\n## メインの `FastAPI` { #the-main-fastapi }\n\n次に、`app/main.py` のモジュールを見ていきます。\n\nここでクラス `FastAPI` をインポートして使用します。\n\nこれはすべてをまとめるアプリケーションのメインファイルになります。\n\nそして大部分のロジックはそれぞれの専用モジュールに置かれるため、メインファイルはかなりシンプルになります。\n\n### `FastAPI` のインポート { #import-fastapi }\n\n通常どおり `FastAPI` クラスをインポートして作成します。\n\nさらに、各 `APIRouter` の依存関係と組み合わされる[グローバル依存関係](dependencies/global-dependencies.md)も宣言できます:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### `APIRouter` のインポート { #import-the-apirouter }\n\n次に、`APIRouter` を持つ他のサブモジュールをインポートします:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\n`app/routers/users.py` と `app/routers/items.py` は同じ Python パッケージ `app` のサブモジュールなので、1つのドット `.` を使った「相対インポート」でインポートできます。\n\n### インポートの動作 { #how-the-importing-works }\n\n次の部分:\n\n```Python\nfrom .routers import items, users\n```\n\nは次の意味です:\n\n* このモジュール（`app/main.py`）が存在する同じパッケージ（ディレクトリ `app/`）から開始し...\n* サブパッケージ `routers`（ディレクトリ `app/routers/`）を探し...\n* そこからサブモジュール `items`（ファイル `app/routers/items.py`）と `users`（ファイル `app/routers/users.py`）をインポートする...\n\nモジュール `items` には変数 `router`（`items.router`）があります。これは `app/routers/items.py` で作成した `APIRouter` オブジェクトと同じものです。\n\nモジュール `users` についても同様です。\n\n次のようにインポートすることもできます:\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info | 情報\n\n最初のバージョンは「相対インポート」です:\n\n```Python\nfrom .routers import items, users\n```\n\n2つ目のバージョンは「絶対インポート」です:\n\n```Python\nfrom app.routers import items, users\n```\n\nPython のパッケージとモジュールについて詳しくは、[公式の Python モジュールに関するドキュメント](https://docs.python.org/3/tutorial/modules.html)をご覧ください。\n\n///\n\n### 名前衝突の回避 { #avoid-name-collisions }\n\nサブモジュール `items` の変数 `router` だけをインポートするのではなく、サブモジュール自体を直接インポートしています。\n\nこれは、サブモジュール `users` にも `router` という変数があるためです。\n\nもし次のように続けてインポートした場合:\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\n`users` の `router` が `items` のものを上書きしてしまい、同時に両方を使えなくなります。\n\n同じファイルで両方を使えるようにするため、サブモジュールを直接インポートします:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### `users` と `items` の `APIRouter` を取り込む { #include-the-apirouters-for-users-and-items }\n\nでは、サブモジュール `users` と `items` から `router` を取り込みます:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info | 情報\n\n`users.router` は、ファイル `app/routers/users.py` 内の `APIRouter` を含みます。\n\n`items.router` は、ファイル `app/routers/items.py` 内の `APIRouter` を含みます。\n\n///\n\n`app.include_router()` を使って、各 `APIRouter` をメインの `FastAPI` アプリケーションに追加できます。\n\nそのルーターのすべてのルートがアプリに含まれます。\n\n/// note | 技術詳細\n\n実際には、`APIRouter` で宣言された各 *path operation* ごとに内部的に *path operation* が作成されます。\n\nつまり裏側では、すべてが同じ単一のアプリであるかのように動作します。\n\n///\n\n/// check | 確認\n\nルーターを取り込んでもパフォーマンスを心配する必要はありません。\n\nこれは起動時にマイクロ秒で行われます。\n\nしたがってパフォーマンスには影響しません。⚡\n\n///\n\n### カスタムの `prefix`、`tags`、`responses`、`dependencies` 付きで `APIRouter` を取り込む { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\nあなたの組織から `app/internal/admin.py` ファイルが提供されたとしましょう。\n\nそこには、組織が複数プロジェクトで共有している管理用の *path operations* を持つ `APIRouter` が含まれています。\n\nこの例ではとてもシンプルですが、組織内の他プロジェクトと共有しているため、`APIRouter` 自体を直接変更して `prefix`、`dependencies`、`tags` などを追加できないとします:\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nそれでも、`APIRouter` を取り込む際にカスタムの `prefix` を設定してすべての *path operations* を `/admin` で始めたい、既存の `dependencies` で保護したい、さらに `tags` と `responses` も含めたいとします。\n\n元の `APIRouter` を変更することなく、`app.include_router()` にこれらのパラメータを渡すことで宣言できます:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\nこのようにすると、元の `APIRouter` は未変更のままなので、同じ `app/internal/admin.py` ファイルを組織内の他プロジェクトとも引き続き共有できます。\n\n結果として、このアプリ内では `admin` モジュールの各 *path operation* が次のようになります:\n\n* prefix は `/admin`\n* タグは `admin`\n* 依存関係は `get_token_header`\n* レスポンスは `418` 🍵\n\nただし、これはこのアプリ内のその `APIRouter` にのみ影響し、それを使用する他のコードには影響しません。\n\n例えば、他のプロジェクトでは同じ `APIRouter` を別の認証方式で使うこともできます。\n\n### *path operation* を追加 { #include-a-path-operation }\n\n`FastAPI` アプリに *path operations* を直接追加することもできます。\n\nここでは（できることを示すためだけに）追加します 🤷:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\nそして、`app.include_router()` で追加したほかの *path operations* と一緒に正しく動作します。\n\n/// info | 非常に技術的な詳細\n\n注記: これは非常に技術的な詳細で、**読み飛ばして構いません**。\n\n---\n\n`APIRouter` は「マウント」されておらず、アプリケーションの他部分から分離されていません。\n\nこれは、それらの *path operations* を OpenAPI スキーマやユーザーインターフェースに含めたいからです。\n\n完全に分離して独立に「マウント」できないため、*path operations* は直接取り込まれるのではなく「クローン（再作成）」されます。\n\n///\n\n## `pyproject.toml` の `entrypoint` を設定 { #configure-the-entrypoint-in-pyproject-toml }\n\nFastAPI の `app` オブジェクトは `app/main.py` にあるので、`pyproject.toml` で `entrypoint` を次のように設定できます:\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\nこれは次のようにインポートするのと同等です:\n\n```python\nfrom app.main import app\n```\n\nこのようにすると、`fastapi` コマンドがアプリの場所を把握できます。\n\n/// Note | 備考\n\nコマンドにパスを渡すこともできます。例えば:\n\n```console\n$ fastapi dev app/main.py\n```\n\nしかし、そのたびに `fastapi` コマンドを呼ぶ際、正しいパスを渡すのを忘れないようにする必要があります。\n\nさらに、[VS Code Extension](../editor-support.md) や [FastAPI Cloud](https://fastapicloud.com) など、他のツールが見つけられない場合があります。そのため、`pyproject.toml` の `entrypoint` を使うことを推奨します。\n\n///\n\n## 自動APIドキュメントの確認 { #check-the-automatic-api-docs }\n\nアプリを実行します:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nそして [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) を開きます。\n\nすべてのサブモジュール由来のパスを含む自動 API ドキュメントが表示され、正しいパス（および prefix）と正しいタグが使われているのが分かります:\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## 同じルーターを異なる `prefix` で複数回取り込む { #include-the-same-router-multiple-times-with-different-prefix }\n\n同じルーターに対して、異なる prefix で `.include_router()` を複数回使うこともできます。\n\n例えば、同じ API を `/api/v1` と `/api/latest` のように異なる prefix で公開する場合に役立ちます。\n\n高度な使い方なので不要かもしれませんが、必要な場合に備えて用意されています。\n\n## `APIRouter` を別の `APIRouter` に取り込む { #include-an-apirouter-in-another }\n\n`APIRouter` を `FastAPI` アプリケーションに取り込めるのと同じように、`APIRouter` を別の `APIRouter` に取り込むこともできます:\n\n```Python\nrouter.include_router(other_router)\n```\n\n`router` を `FastAPI` アプリに取り込む前にこれを実行して、`other_router` の *path operations* も含まれるようにしてください。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/body-fields.md",
    "content": "# ボディ - フィールド { #body-fields }\n\n`Query`や`Path`、`Body`を使って *path operation関数* のパラメータに追加のバリデーションやメタデータを宣言するのと同じように、Pydanticの`Field`を使ってPydanticモデルの内部でバリデーションやメタデータを宣言することができます。\n\n## `Field`のインポート { #import-field }\n\nまず、以下のようにインポートします:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n\n/// warning | 注意\n\n`Field`は他の全てのもの（`Query`、`Path`、`Body`など）とは違い、`fastapi`からではなく、`pydantic`から直接インポートされていることに注意してください。\n\n///\n\n## モデルの属性の宣言 { #declare-model-attributes }\n\n以下のように`Field`をモデルの属性として使用することができます:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field`は`Query`や`Path`、`Body`と同じように動作し、全く同様のパラメータなどを持ちます。\n\n/// note | 技術詳細\n\n実際には次に見る`Query`や`Path`などは、共通の`Param`クラスのサブクラスのオブジェクトを作成しますが、それ自体はPydanticの`FieldInfo`クラスのサブクラスです。\n\nまた、Pydanticの`Field`は`FieldInfo`のインスタンスも返します。\n\n`Body`は`FieldInfo`のサブクラスのオブジェクトを直接返すこともできます。そして、他にも`Body`クラスのサブクラスであるものがあります。\n\n`fastapi`から`Query`や`Path`などをインポートする場合、これらは実際には特殊なクラスを返す関数であることに注意してください。\n\n///\n\n/// tip | 豆知識\n\n型、デフォルト値、`Field`を持つ各モデルの属性が、`Path`や`Query`、`Body`の代わりに`Field`を持つ、*path operation 関数の*パラメータと同じ構造になっていることに注目してください。\n\n///\n\n## 追加情報の追加 { #add-extra-information }\n\n追加情報は`Field`や`Query`、`Body`などで宣言することができます。そしてそれは生成されたJSONスキーマに含まれます。\n\n後に例を用いて宣言を学ぶ際に、追加情報を追加する方法を学べます。\n\n/// warning | 注意\n\n`Field`に渡された追加のキーは、結果として生成されるアプリケーションのOpenAPIスキーマにも含まれます。\nこれらのキーは必ずしもOpenAPI仕様の一部であるとは限らないため、例えば[OpenAPI validator](https://validator.swagger.io/)などの一部のOpenAPIツールは、生成されたスキーマでは動作しない場合があります。\n\n///\n\n## まとめ { #recap }\n\nPydanticの`Field`を使用して、モデルの属性に追加のバリデーションやメタデータを宣言することができます。\n\n追加のキーワード引数を使用して、追加のJSONスキーマのメタデータを渡すこともできます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/body-multiple-params.md",
    "content": "# ボディ - 複数のパラメータ { #body-multiple-parameters }\n\nこれまで`Path`と`Query`をどう使うかを見てきましたが、リクエストボディ宣言のより高度な使い方を見てみましょう。\n\n## `Path`、`Query`とボディパラメータを混ぜる { #mix-path-query-and-body-parameters }\n\nまず、もちろん、`Path`と`Query`とリクエストボディのパラメータ宣言は自由に混ぜることができ、 **FastAPI** は何をするべきかを知っています。\n\nまた、デフォルトを`None`に設定することで、ボディパラメータをオプションとして宣言することもできます:\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | 備考\n\nこの場合、ボディから取得する`item`はオプションであることに注意してください。デフォルト値が`None`になっているためです。\n\n///\n\n## 複数のボディパラメータ { #multiple-body-parameters }\n\n上述の例では、*path operations*は`Item`の属性を持つ以下のようなJSONボディを期待していました:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\nしかし、`item`と`user`のように複数のボディパラメータを宣言することもできます:\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\n\nこの場合、**FastAPI**は関数内に複数のボディパラメータがあることに気付きます（Pydanticモデルである2つのパラメータがあります）。\n\nそのため、パラメータ名をボディのキー（フィールド名）として使用し、以下のようなボディを期待します:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | 備考\n\n以前と同じように`item`が宣言されていたにもかかわらず、`item`はキー`item`を持つボディの内部にあることが期待されていることに注意してください。\n\n///\n\n**FastAPI** はリクエストから自動で変換を行い、パラメータ`item`が特定の内容を受け取り、`user`も同じように特定の内容を受け取ります。\n\n複合データの検証を行い、OpenAPIスキーマや自動ドキュメントのように文書化してくれます。\n\n## ボディ内の単数値 { #singular-values-in-body }\n\nクエリとパスパラメータの追加データを定義するための `Query` と `Path` があるのと同じように、 **FastAPI** は同等の `Body` を提供します。\n\n例えば、前のモデルを拡張して、同じボディに `item` と `user` の他にもう一つのキー `importance` を入れたいと決めることができます。\n\n単数値なのでそのまま宣言すると、**FastAPI** はそれがクエリパラメータであるとみなします。\n\nしかし、`Body`を使用して、**FastAPI** に別のボディキーとして扱うように指示することができます:\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\n\nこの場合、**FastAPI** は以下のようなボディを期待します:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\n繰り返しになりますが、データ型の変換、検証、文書化などを行います。\n\n## 複数のボディパラメータとクエリ { #multiple-body-params-and-query }\n\nもちろん、ボディパラメータに加えて、必要に応じて追加のクエリパラメータを宣言することもできます。\n\nデフォルトでは、単数値はクエリパラメータとして解釈されるので、明示的に `Query` を追加する必要はなく、次のようにできます:\n\n```Python\nq: str | None = None\n```\n\n例えば:\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n/// info | 情報\n\n`Body`もまた、後述する `Query` や `Path` などと同様に、すべての追加検証パラメータとメタデータパラメータを持っています。\n\n///\n\n## 単一のボディパラメータの埋め込み { #embed-a-single-body-parameter }\n\nPydanticモデル`Item`の単一の`item`ボディパラメータしかないとしましょう。\n\nデフォルトでは、**FastAPI**はそのボディを直接期待します。\n\nしかし、追加のボディパラメータを宣言したときのように、キー `item` を持つ JSON と、その中のモデル内容を期待したい場合は、特別な `Body` パラメータ `embed` を使うことができます:\n\n```Python\nitem: Item = Body(embed=True)\n```\n\n以下において:\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\n\nこの場合、**FastAPI** は以下のようなボディを期待します:\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\n以下の代わりに:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## まとめ { #recap }\n\nリクエストが単一のボディしか持てない場合でも、*path operation function*に複数のボディパラメータを追加することができます。\n\nしかし、**FastAPI** はそれを処理し、関数内の正しいデータを与え、*path operation*内の正しいスキーマを検証し、文書化します。\n\nまた、ボディの一部として受け取る単数値を宣言することもできます。\n\nまた、単一のパラメータしか宣言されていない場合でも、ボディをキーに埋め込むように **FastAPI** に指示することができます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/body-nested-models.md",
    "content": "# ボディ - ネストされたモデル { #body-nested-models }\n\n**FastAPI** を使用すると、深くネストされた任意のモデルを定義、検証、文書化、使用することができます（Pydanticのおかげです）。\n\n## リストのフィールド { #list-fields }\n\n属性をサブタイプとして定義することができます。例えば、Pythonの`list`:\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\nこれにより、各項目の型は宣言されていませんが、`tags`はリストになります。\n\n## タイプパラメータを持つリストのフィールド { #list-fields-with-type-parameter }\n\nしかし、Pythonには内部の型、または「タイプパラメータ」を使ってリストを宣言するための特定の方法があります:\n\n### タイプパラメータを持つ`list`の宣言 { #declare-a-list-with-a-type-parameter }\n\n`list`、`dict`、`tuple`のようにタイプパラメータ（内部の型）を持つ型を宣言するには、\n角括弧（`[`と`]`）を使って内部の型を「タイプパラメータ」として渡します。\n\n```Python\nmy_list: list[str]\n```\n\n型宣言の標準的なPythonの構文はこれだけです。\n\n内部の型を持つモデルの属性にも同じ標準の構文を使用してください。\n\nそのため、以下の例では`tags`を具体的な「文字列のリスト」にすることができます:\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## セット型 { #set-types }\n\nしかし、よく考えてみると、タグは繰り返すべきではなく、おそらくユニークな文字列になるのではないかと気付いたとします。\n\nそして、Pythonにはユニークな項目のセットのための特別なデータ型`set`があります。\n\nそして、`tags`を文字列のセットとして宣言できます:\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\nこれを使えば、データが重複しているリクエストを受けた場合でも、ユニークな項目のセットに変換されます。\n\nそして、そのデータを出力すると、たとえソースに重複があったとしても、固有の項目のセットとして出力されます。\n\nまた、それに応じて注釈をつけたり、文書化したりします。\n\n## ネストされたモデル { #nested-models }\n\nPydanticモデルの各属性には型があります。\n\nしかし、その型はそれ自体が別のPydanticモデルである可能性があります。\n\nそのため、特定の属性名、型、バリデーションを指定して、深くネストしたJSON「オブジェクト」を宣言することができます。\n\nすべては、任意のネストにされています。\n\n### サブモデルの定義 { #define-a-submodel }\n\n例えば、`Image`モデルを定義することができます:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### サブモデルを型として使用 { #use-the-submodel-as-a-type }\n\nそして、それを属性の型として使用することができます:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\nこれは **FastAPI** が以下のようなボディを期待することを意味します:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\n繰り返しになりますが、**FastAPI** を使用して、その宣言を行うだけで以下のような恩恵を受けられます:\n\n* ネストされたモデルでも対応可能なエディタのサポート（補完など）\n* データ変換\n* データの検証\n* 自動文書化\n\n## 特殊な型とバリデーション { #special-types-and-validation }\n\n`str`や`int`、`float`などの通常の単数型の他にも、`str`を継承したより複雑な単数型を使うこともできます。\n\nすべてのオプションをみるには、[Pydantic の型の概要](https://docs.pydantic.dev/latest/concepts/types/)を確認してください。次の章でいくつかの例をみることができます。\n\n例えば、`Image`モデルのように`url`フィールドがある場合、`str`の代わりにPydanticの`HttpUrl`のインスタンスとして宣言することができます:\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\n文字列は有効なURLであることが確認され、そのようにJSON Schema / OpenAPIで文書化されます。\n\n## サブモデルのリストを持つ属性 { #attributes-with-lists-of-submodels }\n\nPydanticモデルを`list`や`set`などのサブタイプとして使用することもできます:\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\nこれは、次のようなJSONボディを期待します（変換、検証、ドキュメントなど）:\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info | 情報\n\n`images`キーが画像オブジェクトのリストを持つようになったことに注目してください。\n\n///\n\n## 深くネストされたモデル { #deeply-nested-models }\n\n深くネストされた任意のモデルを定義することができます:\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info | 情報\n\n`Offer`は`Item`のリストであり、それらがさらにオプションの`Image`のリストを持っていることに注目してください。\n\n///\n\n## 純粋なリストのボディ { #bodies-of-pure-lists }\n\n期待するJSONボディのトップレベルの値がJSON`array`（Pythonの`list`）であれば、Pydanticモデルと同じように、関数のパラメータで型を宣言することができます:\n\n```Python\nimages: list[Image]\n```\n\n以下のように:\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## あらゆる場所でのエディタサポート { #editor-support-everywhere }\n\nそして、あらゆる場所でエディタサポートを得られます。\n\n以下のようにリストの中の項目でも:\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\nPydanticモデルではなく、`dict`を直接使用している場合はこのようなエディタのサポートは得られません。\n\nしかし、それらについて心配する必要はありません。入力されたdictは自動的に変換され、出力も自動的にJSONに変換されます。\n\n## 任意の`dict`のボディ { #bodies-of-arbitrary-dicts }\n\nまた、ある型のキーと別の型の値を持つ`dict`としてボディを宣言することもできます。\n\nこの方法で、有効なフィールド/属性名を事前に知る必要がありません（Pydanticモデルの場合のように）。\n\nこれは、まだ知らないキーを受け取りたいときに便利です。\n\n---\n\nもうひとつ便利なケースは、別の型（例: `int`）のキーを持ちたい場合です。\n\nそれをここで見ていきます。\n\nこの場合、`int`のキーと`float`の値を持つものであれば、どんな`dict`でも受け入れることができます:\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip | 豆知識\n\nJSONはキーとして`str`しかサポートしていないことに注意してください。\n\nしかしPydanticには自動データ変換機能があります。\n\nこれは、APIクライアントがキーとして文字列しか送信できなくても、それらの文字列に純粋な整数が含まれている限り、Pydanticが変換して検証することを意味します。\n\nそして、`weights`として受け取る`dict`は、実際には`int`のキーと`float`の値を持つことになります。\n\n///\n\n## まとめ { #recap }\n\n**FastAPI** を使用すると、Pydanticモデルが提供する最大限の柔軟性を持ちながら、コードをシンプルに短く、エレガントに保つことができます。\n\nしかし、以下のような利点があります:\n\n* エディタのサポート（どこでも補完！）\n* データ変換（別名：構文解析 / シリアライズ）\n* データの検証\n* スキーマ文書\n* 自動ドキュメント\n"
  },
  {
    "path": "docs/ja/docs/tutorial/body-updates.md",
    "content": "# ボディ - 更新 { #body-updates }\n\n## `PUT`による置換での更新 { #update-replacing-with-put }\n\n項目を更新するには[HTTPの`PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT)操作を使用することができます。\n\n`jsonable_encoder`を用いて、入力データをJSONとして保存できるデータに変換することができます（例：NoSQLデータベース）。例えば、`datetime`を`str`に変換します。\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT`は、既存のデータを置き換えるべきデータを受け取るために使用されます。\n\n### 置換についての注意 { #warning-about-replacing }\n\nつまり、`PUT`を使用して以下のボディで項目`bar`を更新したい場合は:\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\nすでに格納されている属性`\"tax\": 20.2`を含まないため、入力モデルは`\"tax\": 10.5`のデフォルト値を取ります。\n\nそして、データはその「新しい」`10.5`の`tax`と共に保存されます。\n\n## `PATCH`による部分的な更新 { #partial-updates-with-patch }\n\nまた、[HTTPの`PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH)操作でデータを*部分的に*更新することもできます。\n\nつまり、更新したいデータだけを送信して、残りはそのままにしておくことができます。\n\n/// note | 備考\n\n`PATCH`は`PUT`よりもあまり使われておらず、知られていません。\n\nまた、多くのチームは部分的な更新であっても`PUT`だけを使用しています。\n\n**FastAPI** はどんな制限も課けていないので、それらを使うのは **自由** です。\n\nしかし、このガイドでは、それらがどのように使用されることを意図しているかを多かれ少なかれ、示しています。\n\n///\n\n### Pydanticの`exclude_unset`パラメータの使用 { #using-pydantics-exclude-unset-parameter }\n\n部分的な更新を受け取りたい場合は、Pydanticモデルの`.model_dump()`の`exclude_unset`パラメータを使用すると非常に便利です。\n\n`item.model_dump(exclude_unset=True)`のように。\n\nこれにより、`item`モデルの作成時に設定されたデータのみを持つ`dict`が生成され、デフォルト値は除外されます。\n\nこれを使うことで、デフォルト値を省略して、設定された（リクエストで送られた）データのみを含む`dict`を生成することができます:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### Pydanticの`update`パラメータの使用 { #using-pydantics-update-parameter }\n\nここで、`.model_copy()`を用いて既存のモデルのコピーを作成し、`update`パラメータに更新するデータを含む`dict`を渡すことができます。\n\n`stored_item_model.model_copy(update=update_data)`のように:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### 部分的更新のまとめ { #partial-updates-recap }\n\nまとめると、部分的な更新を適用するには、次のようにします:\n\n* (オプションで)`PUT`の代わりに`PATCH`を使用します。\n* 保存されているデータを取得します。\n* そのデータをPydanticモデルにいれます。\n* 入力モデルからデフォルト値を含まない`dict`を生成します（`exclude_unset`を使用します）。\n    * この方法では、モデル内のデフォルト値ですでに保存されている値を上書きするのではなく、ユーザーが実際に設定した値のみを更新することができます。\n* 保存されているモデルのコピーを作成し、受け取った部分的な更新で属性を更新します（`update`パラメータを使用します）。\n* コピーしたモデルをDBに保存できるものに変換します（例えば、`jsonable_encoder`を使用します）。\n    * これはモデルの`.model_dump()`メソッドを再度利用することに匹敵しますが、値をJSONに変換できるデータ型になるようにし（変換し）、例えば`datetime`を`str`に変換します。\n* データをDBに保存します。\n* 更新されたモデルを返します。\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | 豆知識\n\n実際には、HTTPの`PUT`操作でも同じテクニックを使用することができます。\n\nしかし、これらのユースケースのために作成されたので、ここでの例では`PATCH`を使用しています。\n\n///\n\n/// note | 備考\n\n入力モデルがまだ検証されていることに注目してください。\n\nそのため、すべての属性を省略できる部分的な変更を受け取りたい場合は、すべての属性をオプションとしてマークしたモデルを用意する必要があります（デフォルト値または`None`を使用して）。\n\n**更新** のためのオプション値がすべて設定されているモデルと、**作成** のための必須値が設定されているモデルを区別するには、[追加モデル](extra-models.md)で説明されている考え方を利用することができます。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/tutorial/body.md",
    "content": "# リクエストボディ { #request-body }\n\nクライアント（例えばブラウザ）からAPIにデータを送信する必要がある場合、**リクエストボディ**として送信します。\n\n**リクエスト**ボディは、クライアントからAPIへ送信されるデータです。**レスポンス**ボディは、APIがクライアントに送信するデータです。\n\nAPIはほとんどの場合 **レスポンス** ボディを送信する必要があります。しかしクライアントは、常に **リクエストボディ** を送信する必要があるとは限りません。場合によっては、クエリパラメータ付きのパスだけをリクエストして、ボディを送信しないこともあります。\n\n**リクエスト**ボディを宣言するには、[Pydantic](https://docs.pydantic.dev/) モデルを使用し、その強力な機能とメリットをすべて利用します。\n\n/// info | 情報\n\nデータを送信するには、`POST`（より一般的）、`PUT`、`DELETE`、`PATCH` のいずれかを使用すべきです。\n\n`GET` リクエストでボディを送信することは仕様上は未定義の動作ですが、それでもFastAPIではサポートされています。ただし、非常に複雑／極端なユースケースのためだけです。\n\n推奨されないため、Swagger UIによる対話的ドキュメントでは `GET` 使用時のボディのドキュメントは表示されず、途中のプロキシが対応していない可能性もあります。\n\n///\n\n## Pydanticの `BaseModel` をインポート { #import-pydantics-basemodel }\n\nまず、`pydantic` から `BaseModel` をインポートする必要があります:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## データモデルの作成 { #create-your-data-model }\n\n次に、`BaseModel` を継承するクラスとしてデータモデルを宣言します。\n\nすべての属性に標準のPython型を使用します:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\n\nクエリパラメータの宣言と同様に、モデル属性がデフォルト値を持つ場合は必須ではありません。そうでなければ必須です。単にオプションにするには `None` を使用してください。\n\n例えば、上記のモデルは次のようなJSON「`object`」（またはPythonの `dict`）を宣言します:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n...`description` と `tax` はオプション（デフォルト値が `None`）なので、このJSON「`object`」も有効です:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## パラメータとして宣言 { #declare-it-as-a-parameter }\n\n*path operation* に追加するには、パスパラメータやクエリパラメータを宣言したのと同じ方法で宣言します:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n...そして、作成したモデル `Item` を型として宣言します。\n\n## 結果 { #results }\n\nそのPythonの型宣言だけで **FastAPI** は以下を行います:\n\n* リクエストのボディをJSONとして読み取ります。\n* 対応する型に変換します（必要な場合）。\n* データを検証します。\n    * データが無効な場合は、どこで何が不正なデータだったのかを正確に示す、分かりやすい明確なエラーを返します。\n* 受け取ったデータをパラメータ `item` に渡します。\n    * 関数内で `Item` 型として宣言したため、すべての属性とその型について、エディタサポート（補完など）も利用できます。\n* モデル向けの [JSON Schema](https://json-schema.org) 定義を生成します。プロジェクトにとって意味があるなら、他の場所でも好きなように利用できます。\n* それらのスキーマは生成されるOpenAPIスキーマの一部となり、自動ドキュメントの <abbr title=\"User Interfaces - ユーザーインターフェース\">UIs</abbr> で使用されます。\n\n## 自動ドキュメント { #automatic-docs }\n\nモデルのJSON Schemaは、OpenAPIで生成されたスキーマの一部になり、対話的なAPIドキュメントに表示されます:\n\n<img src=\"/img/tutorial/body/image01.png\">\n\nまた、それらが必要な各 *path operation* 内のAPIドキュメントでも使用されます:\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## エディタサポート { #editor-support }\n\nエディタ上で、関数内のあらゆる場所で型ヒントと補完が得られます（Pydanticモデルの代わりに `dict` を受け取った場合は起きません）:\n\n<img src=\"/img/tutorial/body/image03.png\">\n\n不正な型操作に対するエラーチェックも得られます:\n\n<img src=\"/img/tutorial/body/image04.png\">\n\nこれは偶然ではなく、フレームワーク全体がその設計を中心に構築されています。\n\nそして、すべてのエディタで動作することを確実にするために、実装前の設計フェーズで徹底的にテストされました。\n\nこれをサポートするために、Pydantic自体にもいくつかの変更が加えられました。\n\n前述のスクリーンショットは [Visual Studio Code](https://code.visualstudio.com) で撮影されたものです。\n\nただし、[PyCharm](https://www.jetbrains.com/pycharm/) や、他のほとんどのPythonエディタでも同じエディタサポートを得られます:\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip | 豆知識\n\nエディタとして [PyCharm](https://www.jetbrains.com/pycharm/) を使用している場合、[Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/) を使用できます。\n\n以下により、Pydanticモデルに対するエディタサポートが改善されます:\n\n* auto-completion\n* type checks\n* refactoring\n* searching\n* inspections\n\n///\n\n## モデルを使用する { #use-the-model }\n\n関数内では、モデルオブジェクトのすべての属性に直接アクセスできます:\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## リクエストボディ + パスパラメータ { #request-body-path-parameters }\n\nパスパラメータとリクエストボディを同時に宣言できます。\n\n**FastAPI** は、パスパラメータに一致する関数パラメータは **パスから取得** し、Pydanticモデルとして宣言された関数パラメータは **リクエストボディから取得** すべきだと認識します。\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n\n## リクエストボディ + パス + クエリパラメータ { #request-body-path-query-parameters }\n\n**body**、**path**、**query** パラメータもすべて同時に宣言できます。\n\n**FastAPI** はそれぞれを認識し、正しい場所からデータを取得します。\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\n関数パラメータは以下のように認識されます:\n\n* パラメータが **path** でも宣言されている場合、パスパラメータとして使用されます。\n* パラメータが **単数型**（`int`、`float`、`str`、`bool` など）の場合、**query** パラメータとして解釈されます。\n* パラメータが **Pydanticモデル** の型として宣言されている場合、リクエスト **body** として解釈されます。\n\n/// note | 備考\n\nFastAPIは、デフォルト値 `= None` があるため、`q` の値が必須ではないことを認識します。\n\n`str | None` は、値が必須ではないことを判断するためにFastAPIでは使用されません。`= None` というデフォルト値があるため、必須ではないことを認識します。\n\nしかし、型アノテーションを追加すると、エディタがより良いサポートを提供し、エラーを検出できるようになります。\n\n///\n\n## Pydanticを使わない方法 { #without-pydantic }\n\nPydanticモデルを使いたくない場合は、**Body** パラメータも使用できます。[Body - 複数のパラメータ: ボディ内の単一値](body-multiple-params.md#singular-values-in-body) のドキュメントを参照してください。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/cookie-param-models.md",
    "content": "# クッキーパラメータモデル { #cookie-parameter-models }\n\nもし関連する**複数のクッキー**から成るグループがあるなら、それらを宣言するために、**Pydanticモデル**を作成できます。🍪\n\nこうすることで、**複数の場所**で**そのPydanticモデルを再利用**でき、バリデーションやメタデータを、すべてのパラメータに対して一度に宣言できます。😎\n\n/// note | 備考\n\nこの機能は、FastAPIのバージョン `0.115.0` からサポートされています。🤓\n\n///\n\n/// tip | 豆知識\n\nこれと同じテクニックは `Query` 、 `Cookie` 、 `Header` にも適用できます。 😎\n\n///\n\n## Pydanticモデルを使用したクッキー { #cookies-with-a-pydantic-model }\n\n必要な複数の**クッキー**パラメータを**Pydanticモデル**で宣言し、さらに、パラメータを `Cookie` として宣言しましょう:\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI**は、リクエストで受け取った**クッキー**から**それぞれのフィールド**のデータを**抽出**し、定義したPydanticモデルを提供します。\n\n## ドキュメントの確認 { #check-the-docs }\n\n対話的APIドキュメントUI `/docs` で、定義されているクッキーを確認できます:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info | 情報\n\n**ブラウザがクッキーを処理し**ていますが、特別な方法で内部的に処理を行っているために、**JavaScript**からは簡単に操作**できない**ことに留意してください。\n\n**APIドキュメントUI** `/docs` にアクセスすれば、*path operation*に関するクッキーの**ドキュメンテーション**を確認できます。\n\nしかし、たとえ**データを入力して**「Execute」をクリックしても、ドキュメントUIは**JavaScript**で動作しているためクッキーは送信されず、まるで値を入力しなかったかのような**エラー**メッセージが表示されます。\n\n///\n\n## 余分なクッキーを禁止する { #forbid-extra-cookies }\n\n特定の（あまり一般的ではないかもしれない）ケースで、受け付けるクッキーを**制限**する必要があるかもしれません。\n\nあなたのAPIは独自の <dfn title=\"念のためですが、これはジョークです。クッキー同意とは関係ありませんが、APIでさえ今やかわいそうなクッキーを拒否できるのは面白いですね。クッキーでもどうぞ。🍪\">クッキー同意</dfn> を管理する能力を持っています。 🤪🍪\n\nPydanticのモデルの Configuration を利用して、 `extra` フィールドを `forbid` とすることができます。\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\nもしクライアントが**余分なクッキー**を送ろうとすると、**エラー**レスポンスが返されます。\n\n<dfn title=\"これもジョークです。気にしないでください。クッキーのお供にコーヒーでもどうぞ。☕\">どうせAPIに拒否されるのに</dfn>あなたの同意を得ようと精一杯努力する可哀想なクッキーバナーたち... 🍪\n\n例えば、クライアントがクッキー `santa_tracker` を `good-list-please` という値で送ろうとすると、`santa_tracker` という <dfn title=\"サンタはクッキー不足を良しとしません。🎅 はい、クッキージョークはこれでおしまい。\">クッキーが許可されていない</dfn> ことを通知する**エラー**レスポンスが返されます:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## まとめ { #summary }\n\n**FastAPI**では、<dfn title=\"帰る前に最後のクッキーをどうぞ。🍪\">**クッキー**</dfn>を宣言するために、**Pydanticモデル**を使用できます。😎\n"
  },
  {
    "path": "docs/ja/docs/tutorial/cookie-params.md",
    "content": "# クッキーのパラメータ { #cookie-parameters }\n\nクッキーのパラメータは、`Query`や`Path`のパラメータを定義するのと同じ方法で定義できます。\n\n## `Cookie`をインポート { #import-cookie }\n\nまず、`Cookie`をインポートします:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## `Cookie`のパラメータを宣言 { #declare-cookie-parameters }\n\n次に、`Path`や`Query`と同じ構造を使ってクッキーのパラメータを宣言します。\n\n最初の値がデフォルト値で、追加の検証パラメータや注釈パラメータをすべて渡すことができます:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | 技術詳細\n\n`Cookie`は`Path`と`Query`の「姉妹」クラスです。また、同じ共通の`Param`クラスを継承しています。\n\nしかし、`fastapi`から`Query`や`Path`、`Cookie`などをインポートする場合、それらは実際には特殊なクラスを返す関数であることを覚えておいてください。\n\n///\n\n/// info | 情報\n\nクッキーを宣言するには、`Cookie`を使う必要があります。なぜなら、そうしないとパラメータがクエリのパラメータとして解釈されてしまうからです。\n\n///\n\n/// info | 情報\n\n**ブラウザがクッキーを**特殊な方法で裏側で扱うため、**JavaScript** から簡単には触れられないことを念頭に置いてください。\n\n`/docs` の **API docs UI** に移動すると、*path operation* のクッキーに関する **documentation** を確認できます。\n\nしかし、データを **入力** して「Execute」をクリックしても、docs UI は **JavaScript** で動作するためクッキーは送信されず、値を何も書かなかったかのような **error** メッセージが表示されます。\n\n///\n\n## まとめ { #recap }\n\nクッキーは`Cookie`を使って宣言し、`Query`や`Path`と同じ共通のパターンを使用する。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/cors.md",
    "content": "# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }\n\n[CORSまたは「Cross-Origin Resource Sharing」](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) は、ブラウザで実行されているフロントエンドにバックエンドと通信するJavaScriptコードがあり、そのバックエンドがフロントエンドとは異なる「オリジン」にある状況を指します。\n\n## オリジン { #origin }\n\nオリジンはプロトコル (`http`、`https`) とドメイン (`myapp.com`、`localhost`、`localhost.tiangolo.com`) とポート (`80`、`443`、`8080`) の組み合わせです。\n\nしたがって、以下はすべて異なるオリジンです:\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\nすべて `localhost` であっても、異なるプロトコルやポートを使用するので、異なる「オリジン」です。\n\n## ステップ { #steps }\n\nそして、ブラウザ上で実行されているフロントエンド (`http://localhost:8080`) があり、そのJavaScriptが `http://localhost` で実行されているバックエンドと通信するとします。(ポートを指定していないので、ブラウザはデフォルトの`80`ポートを使用します)\n\n次に、ブラウザはHTTPの `OPTIONS` リクエストを `:80` のバックエンドに送信します。そして、バックエンドがこの異なるオリジン (`http://localhost:8080`) からの通信を許可する適切なヘッダーを送信すると、`:8080` のブラウザはフロントエンドのJavaScriptに `:80` のバックエンドへのリクエストを送信させます。\n\nこれを実現するには、`:80` のバックエンドに「許可されたオリジン」のリストがなければなりません。\n\nこの場合、`:8080` のフロントエンドを正しく機能させるには、そのリストに `http://localhost:8080` を含める必要があります。\n\n## ワイルドカード { #wildcards }\n\nリストを `\"*\"` (「ワイルドカード」) と宣言して、すべてを許可することもできます。\n\nただし、クレデンシャル情報に関するもの、つまりCookie、Bearer Tokenで使用されるようなAuthorizationヘッダーなどを含むものは除外され、特定の種類の通信のみが許可されます。\n\nしたがって、すべてを正しく機能させるために、許可されたオリジンの明示的な指定をお勧めします。\n\n## `CORSMiddleware` の使用 { #use-corsmiddleware }\n\n**FastAPI** アプリケーションでは `CORSMiddleware` を使用して、CORSに関する設定ができます。\n\n* `CORSMiddleware`をインポートします。\n* 許可されたオリジンのリストを (文字列として) 作成します。\n* これを「ミドルウェア」として **FastAPI** アプリケーションに追加します。\n\n以下も、バックエンドに許可させるかどうか指定できます:\n\n* クレデンシャル情報 (Authorizationヘッダー、Cookieなど) 。\n* 特定のHTTPメソッド (`POST`、`PUT`) またはワイルドカード `\"*\"` を使用してすべて許可。\n* 特定のHTTPヘッダー、またはワイルドカード `\"*\"`を使用してすべて許可。\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\n\n`CORSMiddleware` 実装で使用されるデフォルトのパラメータはデフォルトで制限が厳しいため、ブラウザがクロスドメインのコンテキストでそれらを使用できるようにするには、特定のオリジン、メソッド、またはヘッダーを明示的に有効にする必要があります。\n\n以下の引数がサポートされています:\n\n* `allow_origins` - オリジン間リクエストを許可するオリジンのリスト。例えば、`['https://example.org', 'https://www.example.org']`。`['*']`を使用して任意のオリジンを許可できます。\n* `allow_origin_regex` - オリジン間リクエストを許可するオリジンの正規表現文字列。例えば、`'https://.*\\.example\\.org'`。\n* `allow_methods` - オリジン間リクエストで許可するHTTPメソッドのリスト。デフォルトは `['GET']` です。`['*']`を使用してすべての標準メソッドを許可できます。\n* `allow_headers` - オリジン間リクエストでサポートするHTTPリクエストヘッダーのリスト。デフォルトは `[]` です。`['*']`を使用して、すべてのヘッダーを許可できます。[シンプルなCORSリクエスト](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests)では、 `Accept` 、 `Accept-Language` 、 `Content-Language` 、 `Content-Type` ヘッダーが常に許可されます。\n* `allow_credentials` - オリジン間リクエストでCookieをサポートする必要があることを示します。デフォルトは `False` です。\n\n    `allow_credentials` が `True` に設定されている場合、`allow_origins`、`allow_methods`、`allow_headers` のいずれも `['*']` に設定できません。これらはすべて[明示的に指定](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards)する必要があります。\n\n* `expose_headers` - ブラウザからアクセスできるようにするレスポンスヘッダーを示します。デフォルトは `[]` です。\n* `max_age` - ブラウザがCORSレスポンスをキャッシュする最大時間を秒単位で設定します。デフォルトは `600` です。\n\nこのミドルウェアは2種類のHTTPリクエストに応答します...\n\n### CORSプリフライトリクエスト { #cors-preflight-requests }\n\nこれらは、 `Origin` ヘッダーと `Access-Control-Request-Method` ヘッダーを持つ `OPTIONS` リクエストです。\n\nこの場合、ミドルウェアはリクエストを横取りし、適切なCORSヘッダーと共に情報提供のために `200` または `400` のレスポンスを返します。\n\n### シンプルなリクエスト { #simple-requests }\n\n`Origin` ヘッダーのあるリクエスト。この場合、ミドルウェアは通常どおりリクエストに何もしないですが、レスポンスに適切なCORSヘッダーを加えます。\n\n## より詳しい情報 { #more-info }\n\n<abbr title=\"Cross-Origin Resource Sharing - オリジン間リソース共有\">CORS</abbr>についてより詳しい情報は、[Mozilla CORS documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) を参照して下さい。\n\n/// note | 技術詳細\n\n`from starlette.middleware.cors import CORSMiddleware` も使用できます。\n\n**FastAPI** は、開発者の利便性を高めるために、`fastapi.middleware` でいくつかのミドルウェアを提供します。利用可能なミドルウェアのほとんどは、Starletteから直接提供されています。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/tutorial/debugging.md",
    "content": "# デバッグ { #debugging }\n\nVisual Studio CodeやPyCharmなどを使用して、エディター上でデバッガーと連携できます。\n\n## `uvicorn` を呼び出す { #call-uvicorn }\n\nFastAPIアプリケーション上で、`uvicorn` を直接インポートして実行します:\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### `__name__ == \"__main__\"` について { #about-name-main }\n\n`__name__ == \"__main__\"` の主な目的は、ファイルが次のコマンドで呼び出されたときに実行されるコードを用意することです:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nただし、次のように、別のファイルからインポートされるときには呼び出されません:\n\n```Python\nfrom myapp import app\n```\n\n#### より詳しい説明 { #more-details }\n\nファイルの名前が `myapp.py` だとします。\n\n以下の様に実行する場合:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nPythonによって自動的に作成されたファイル内の内部変数 `__name__` は、値として文字列 `\"__main__\"` を持ちます。\n\nなので、以下:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nは実行されます。\n\n---\n\nそのモジュール (ファイル) をインポートした場合は、こうはなりません。\n\nしたがって、次のようなもう一つのファイル `importer.py` がある場合:\n\n```Python\nfrom myapp import app\n\n# その他のコード\n```\n\nその場合、`myapp.py` 内の自動的に作成された変数 `__name__` は、値として `\"__main__\"` を持ちません。\n\nしたがって、以下の行:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nは実行されません。\n\n/// info | 情報\n\nより詳しい情報は、[公式Pythonドキュメント](https://docs.python.org/3/library/__main__.html)を参照してください。\n\n///\n\n## デバッガーでコードを実行 { #run-your-code-with-your-debugger }\n\nコードから直接Uvicornサーバーを実行しているため、デバッガーから直接Pythonプログラム (FastAPIアプリケーション) を呼び出せます。\n\n---\n\n例えば、Visual Studio Codeでは、次のことが可能です:\n\n* 「デバッグ」パネルに移動。\n* 「構成の追加...」\n* 「Python」を選択。\n* オプション「`Python: Current File (Integrated Terminal)`」を指定してデバッガーを実行。\n\nすると、**FastAPI** コードでサーバーが起動され、ブレークポイントで停止したりするでしょう。\n\n以下の様な画面になります:\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\nPycharmを使用する場合、次のことが可能です:\n\n* 「実行」メニューをオープン。\n* オプション「デバッグ...」を選択。\n* 次にコンテキストメニューが表示される。\n* デバッグするファイル (ここでは `main.py`) を選択。\n\nすると、**FastAPI** コードでサーバーが起動され、ブレークポイントで停止したりするでしょう。\n\n以下の様な画面になります:\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/ja/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# 依存関係としてのクラス { #classes-as-dependencies }\n\n**依存性注入** システムを深く掘り下げる前に、先ほどの例をアップグレードしてみましょう。\n\n## 前の例の`dict` { #a-dict-from-the-previous-example }\n\n前の例では、依存関係（\"dependable\"）から`dict`を返していました:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\nしかし、*path operation関数*のパラメータ`commons`に`dict`が含まれています。\n\nまた、エディタは`dict`のキーと値の型を知ることができないため、多くのサポート（補完のような）を提供することができません。\n\nもっとうまくやれるはずです...。\n\n## 依存関係を作るもの { #what-makes-a-dependency }\n\nこれまでは、依存関係が関数として宣言されているのを見てきました。\n\nしかし、依存関係を定義する方法はそれだけではありません（その方が一般的かもしれませんが）。\n\n重要なのは、依存関係が「呼び出し可能」なものであることです。\n\nPythonにおける「**呼び出し可能**」とは、Pythonが関数のように「呼び出す」ことができるものを指します。\n\nそのため、`something`オブジェクト（関数ではないかもしれませんが）を持っていて、それを次のように「呼び出す」（実行する）ことができるとします:\n\n```Python\nsomething()\n```\n\nまたは\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\nこれを「呼び出し可能」なものと呼びます。\n\n## 依存関係としてのクラス { #classes-as-dependencies_1 }\n\nPythonのクラスのインスタンスを作成する際に、同じ構文を使用していることに気づくかもしれません。\n\n例えば:\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\nこの場合、`fluffy`は`Cat`クラスのインスタンスです。\n\nそして`fluffy`を作成するために、`Cat`を「呼び出している」ことになります。\n\nそのため、Pythonのクラスもまた「呼び出し可能」です。\n\nそして、**FastAPI** では、Pythonのクラスを依存関係として使用することができます。\n\nFastAPIが実際にチェックしているのは、それが「呼び出し可能」（関数、クラス、その他なんでも）であり、パラメータが定義されているかどうかということです。\n\n**FastAPI** の依存関係として「呼び出し可能なもの」を渡すと、その「呼び出し可能なもの」のパラメータを解析し、サブ依存関係も含めて、*path operation関数*のパラメータと同じように処理します。\n\nそれは、パラメータが全くない呼び出し可能なものにも適用されます。パラメータのない*path operation関数*と同じように。\n\nそこで、上で紹介した依存関係の\"dependable\" `common_parameters`を`CommonQueryParams`クラスに変更します:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\nクラスのインスタンスを作成するために使用される`__init__`メソッドに注目してください:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n...以前の`common_parameters`と同じパラメータを持っています:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\nこれらのパラメータは **FastAPI** が依存関係を「解決」するために使用するものです。\n\nどちらの場合も以下を持っています:\n\n* `str`であるオプショナルの`q`クエリパラメータ。\n* デフォルトが`0`である`int`の`skip`クエリパラメータ。\n* デフォルトが`100`である`int`の`limit`クエリパラメータ。\n\nどちらの場合も、データは変換され、検証され、OpenAPIスキーマなどで文書化されます。\n\n## 使用 { #use-it }\n\nこれで、このクラスを使用して依存関係を宣言することができます。\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI** は`CommonQueryParams`クラスを呼び出します。これにより、そのクラスの「インスタンス」が作成され、インスタンスはパラメータ`commons`として関数に渡されます。\n\n## 型注釈と`Depends` { #type-annotation-vs-depends }\n\n上のコードでは`CommonQueryParams`を２回書いていることに注目してください:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 注釈なし\n\n/// tip | 豆知識\n\n可能であれば`Annotated`バージョンを使用することを推奨します。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n以下にある最後の`CommonQueryParams`:\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n...は、**FastAPI** が依存関係を知るために実際に使用するものです。\n\nそこからFastAPIが宣言されたパラメータを抽出し、それが実際にFastAPIが呼び出すものです。\n\n---\n\nこの場合、以下にある最初の`CommonQueryParams`:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ 注釈なし\n\n/// tip | 豆知識\n\n可能であれば`Annotated`バージョンを使用することを推奨します。\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n...は **FastAPI** に対して特別な意味をもちません。FastAPIはデータ変換や検証などには使用しません（それらのためには`Depends(CommonQueryParams)`を使用しています）。\n\n実際には以下のように書けばいいだけです:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 注釈なし\n\n/// tip | 豆知識\n\n可能であれば`Annotated`バージョンを使用することを推奨します。\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n以下にあるように:\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\nしかし、型を宣言することは推奨されています。そうすれば、エディタは`commons`のパラメータとして何が渡されるかを知ることができ、コードの補完や型チェックなどを行うのに役立ちます:\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## ショートカット { #shortcut }\n\nしかし、ここでは`CommonQueryParams`を２回書くというコードの繰り返しが発生していることがわかります:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 注釈なし\n\n/// tip | 豆知識\n\n可能であれば`Annotated`バージョンを使用することを推奨します。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n依存関係が、クラス自体のインスタンスを作成するために**FastAPI**が「呼び出す」*特定の*クラスである場合、**FastAPI** はこれらのケースのショートカットを提供しています。\n\nそれらの具体的なケースについては以下のようにします:\n\n以下のように書く代わりに:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 注釈なし\n\n/// tip | 豆知識\n\n可能であれば`Annotated`バージョンを使用することを推奨します。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n...以下のように書きます:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ 注釈なし\n\n/// tip | 豆知識\n\n可能であれば`Annotated`バージョンを使用することを推奨します。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\nパラメータの型として依存関係を宣言し、`Depends()`の中でパラメータを指定せず、`Depends()`をその関数のパラメータの「デフォルト」値（`=`のあとの値）として使用することで、`Depends(CommonQueryParams)`の中でクラス全体を*もう一度*書かなくてもよくなります。\n\n同じ例では以下のようになります:\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n...そして **FastAPI** は何をすべきか知っています。\n\n/// tip | 豆知識\n\n役に立つというよりも、混乱するようであれば無視してください。それをする*必要*はありません。\n\nそれは単なるショートカットです。なぜなら **FastAPI** はコードの繰り返しを最小限に抑えることに気を使っているからです。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# path operation デコレータの依存関係 { #dependencies-in-path-operation-decorators }\n\n場合によっては、*path operation 関数*の中で依存関係の戻り値を実際には必要としないことがあります。\n\nまたは、依存関係が値を返さない場合もあります。\n\nしかし、それでも実行・解決される必要があります。\n\nそのような場合、`Depends` で *path operation 関数* のパラメータを宣言する代わりに、*path operation デコレータ*に `dependencies` の `list` を追加できます。\n\n## *path operation デコレータ*に`dependencies`を追加 { #add-dependencies-to-the-path-operation-decorator }\n\n*path operation デコレータ*はオプション引数`dependencies`を受け取ります。\n\nそれは`Depends()`の`list`であるべきです:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\nこれらの依存関係は、通常の依存関係と同様に実行・解決されます。しかし、それらの値（何かを返す場合）は*path operation 関数*には渡されません。\n\n/// tip | 豆知識\n\n一部のエディタは、未使用の関数パラメータをチェックしてエラーとして表示します。\n\nこれらの`dependencies`を*path operation デコレータ*で使用することで、エディタ/ツールのエラーを回避しつつ、確実に実行されるようにできます。\n\nまた、コード内の未使用のパラメータを見た新しい開発者が、それを不要だと思って混乱するのを避ける助けにもなるかもしれません。\n\n///\n\n/// info | 情報\n\nこの例では、架空のカスタムヘッダー `X-Key` と `X-Token` を使用しています。\n\nしかし実際のケースでセキュリティを実装する際は、統合された[Security utilities（次の章）](../security/index.md)を使うことで、より多くの利点を得られます。\n\n///\n\n## 依存関係のエラーと戻り値 { #dependencies-errors-and-return-values }\n\n通常使用している依存関係の*関数*と同じものを使用できます。\n\n### 依存関係の要件 { #dependency-requirements }\n\nこれらはリクエストの要件（ヘッダーのようなもの）やその他のサブ依存関係を宣言できます:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### 例外の発生 { #raise-exceptions }\n\nこれらの依存関係は、通常の依存関係と同じように例外を`raise`できます:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### 戻り値 { #return-values }\n\nそして、値を返すことも返さないこともできますが、値は使われません。\n\nつまり、すでにどこかで使っている通常の依存関係（値を返すもの）を再利用でき、値は使われなくても依存関係は実行されます:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## *path operation*のグループに対する依存関係 { #dependencies-for-a-group-of-path-operations }\n\n後で、より大きなアプリケーションを（おそらく複数ファイルで）構造化する方法（[Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md)）について読むときに、*path operation*のグループに対して単一の`dependencies`パラメータを宣言する方法を学びます。\n\n## グローバル依存関係 { #global-dependencies }\n\n次に、`FastAPI`アプリケーション全体に依存関係を追加して、各*path operation*に適用する方法を見ていきます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# `yield`を持つ依存関係 { #dependencies-with-yield }\n\nFastAPIは、いくつかの<dfn title=\"「終了コード」「クリーンアップコード」「ティアダウンコード」「クローズコード」「コンテキストマネージャの終了コード」などと呼ばれることもあります\">終了後の追加のステップ</dfn>を行う依存関係をサポートしています。\n\nこれを行うには、`return`の代わりに`yield`を使い、その後に追加のステップ（コード）を書きます。\n\n/// tip | 豆知識\n\n`yield`は必ず依存関係ごとに1回だけ使用するようにしてください。\n\n///\n\n/// note | 技術詳細\n\n以下と一緒に使用できる関数なら何でも有効です:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) または\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nこれらは **FastAPI** の依存関係として使用するのに有効です。\n\n実際、FastAPIは内部的にこれら２つのデコレータを使用しています。\n\n///\n\n## `yield`を持つデータベースの依存関係 { #a-database-dependency-with-yield }\n\n例えば、これを使ってデータベースセッションを作成し、終了後にそれを閉じることができます。\n\nレスポンスを作成する前に、`yield`文より前のコード（および`yield`文を含む）が実行されます:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\n生成された値は、*path operations*や他の依存関係に注入されるものです:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\n`yield`文に続くコードは、レスポンスの後に実行されます:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip | 豆知識\n\n`async`や通常の関数を使用することができます。\n\n**FastAPI** は、通常の依存関係と同じように、それぞれで正しいことを行います。\n\n///\n\n## `yield`と`try`を持つ依存関係 { #a-dependency-with-yield-and-try }\n\n`yield`を持つ依存関係で`try`ブロックを使用した場合、その依存関係を使用した際にスローされたあらゆる例外を受け取ることになります。\n\n例えば、途中のどこかの時点で、別の依存関係や*path operation*の中で、データベーストランザクションを「ロールバック」したり、その他の例外を作成したりするコードがあった場合、依存関係の中で例外を受け取ることになります。\n\nそのため、依存関係の中にある特定の例外を`except SomeException`で探すことができます。\n\n同様に、`finally`を用いて例外があったかどうかにかかわらず、終了ステップを確実に実行することができます。\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## `yield`を持つサブ依存関係 { #sub-dependencies-with-yield }\n\n任意の大きさや形のサブ依存関係やサブ依存関係の「ツリー」を持つことができ、その中で`yield`を使用することができます。\n\n**FastAPI** は、`yield`を持つ各依存関係の「終了コード」が正しい順番で実行されていることを確認します。\n\n例えば、`dependency_c`は`dependency_b`に、そして`dependency_b`は`dependency_a`に依存することができます:\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\nそして、それらはすべて`yield`を使用することができます。\n\nこの場合、`dependency_c`は終了コードを実行するために、`dependency_b`（ここでは`dep_b`という名前）の値がまだ利用可能である必要があります。\n\nそして、`dependency_b`は`dependency_a`（ここでは`dep_a`という名前）の値を終了コードで利用できるようにする必要があります。\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\n同様に、`yield`を持つ依存関係と`return`を持つ他の依存関係をいくつか持ち、それらの一部が他の一部に依存するようにもできます。\n\nまた、単一の依存関係を持っていて、`yield`を持つ他の依存関係をいくつか必要とすることもできます。\n\n依存関係の組み合わせは自由です。\n\n**FastAPI** は、全てが正しい順序で実行されていることを確認します。\n\n/// note | 技術詳細\n\nこれはPythonの[コンテキストマネージャ](https://docs.python.org/3/library/contextlib.html)のおかげで動作します。\n\n**FastAPI** はこれを実現するために内部的に使用しています。\n\n///\n\n## `yield`と`HTTPException`を持つ依存関係 { #dependencies-with-yield-and-httpexception }\n\n`yield`を持つ依存関係を使い、何らかのコードを実行し、その後に`finally`の後で終了コードを実行しようとする`try`ブロックを持てることが分かりました。\n\nまた、`except`を使って発生した例外をキャッチし、それに対して何かをすることもできます。\n\n例えば、`HTTPException`のように別の例外を発生させることができます。\n\n/// tip | 豆知識\n\nこれはやや高度なテクニックで、ほとんどの場合は本当に必要にはなりません。例えば、*path operation 関数*など、アプリケーションコードの他の場所から（`HTTPException`を含む）例外を発生させられるためです。\n\nただし必要であれば使えます。 🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\n例外をキャッチして、それに基づいてカスタムレスポンスを作成したい場合は、[カスタム例外ハンドラ](../handling-errors.md#install-custom-exception-handlers)を作成してください。\n\n## `yield`と`except`を持つ依存関係 { #dependencies-with-yield-and-except }\n\n`yield`を持つ依存関係で`except`を使って例外をキャッチし、それを再度raiseしない（または新しい例外をraiseしない）場合、通常のPythonと同じように、FastAPIは例外があったことに気づけません:\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\nこの場合、（`HTTPException`やそれに類するものをraiseしていないため）クライアントには適切に*HTTP 500 Internal Server Error*レスポンスが返りますが、サーバーには**ログが一切残らず**、何がエラーだったのかを示す他の手がかりもありません。 😱\n\n### `yield`と`except`を持つ依存関係では常に`raise`する { #always-raise-in-dependencies-with-yield-and-except }\n\n`yield`を持つ依存関係で例外をキャッチした場合、別の`HTTPException`などをraiseするのでない限り、**元の例外を再raiseすべきです**。\n\n`raise`を使うと同じ例外を再raiseできます:\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\nこれでクライアントは同じ*HTTP 500 Internal Server Error*レスポンスを受け取りますが、サーバーのログにはカスタムの`InternalError`が残ります。 😎\n\n## `yield`を持つ依存関係の実行 { #execution-of-dependencies-with-yield }\n\n実行の順序は多かれ少なかれ以下の図のようになります。時間は上から下へと流れていきます。そして、各列はコードを相互作用させたり、実行したりしている部分の一つです。\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exception handler\nparticipant dep as Dep with yield\nparticipant operation as Path Operation\nparticipant tasks as Background tasks\n\n    Note over client,operation: Can raise exceptions, including HTTPException\n    client ->> dep: Start request\n    Note over dep: Run code up to yield\n    opt raise Exception\n        dep -->> handler: Raise Exception\n        handler -->> client: HTTP error response\n    end\n    dep ->> operation: Run dependency, e.g. DB session\n    opt raise\n        operation -->> dep: Raise Exception (e.g. HTTPException)\n        opt handle\n            dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception\n        end\n        handler -->> client: HTTP error response\n    end\n\n    operation ->> client: Return response to client\n    Note over client,operation: Response is already sent, can't change it anymore\n    opt Tasks\n        operation -->> tasks: Send background tasks\n    end\n    opt Raise other exception\n        tasks -->> tasks: Handle exceptions in the background task code\n    end\n```\n\n/// info | 情報\n\n**１つのレスポンス** だけがクライアントに送信されます。それはエラーレスポンスの一つかもしれませんし、*path operation*からのレスポンスかもしれません。\n\nいずれかのレスポンスが送信された後、他のレスポンスを送信することはできません。\n\n///\n\n/// tip | 豆知識\n\n*path operation 関数*のコードで例外をraiseした場合、`HTTPException`を含め、それはyieldを持つ依存関係に渡されます。ほとんどの場合、その例外が正しく処理されるように、`yield`を持つ依存関係から同じ例外、または新しい例外を再raiseしたくなるでしょう。\n\n///\n\n## 早期終了と`scope` { #early-exit-and-scope }\n\n通常、`yield`を持つ依存関係の終了コードは、クライアントに**レスポンスが送信された後**に実行されます。\n\nしかし、*path operation 関数*からreturnした後に依存関係を使う必要がないと分かっている場合は、`Depends(scope=\"function\")`を使って、**レスポンスが送信される前**に、*path operation 関数*のreturn後に依存関係を閉じるべきだとFastAPIに伝えられます。\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()`は、以下のいずれかを取る`scope`パラメータを受け取ります:\n\n* `\"function\"`: リクエストを処理する*path operation 関数*の前に依存関係を開始し、*path operation 関数*の終了後に依存関係を終了しますが、クライアントにレスポンスが返される**前**に終了します。つまり、依存関係関数は*path operation 関数*の**周囲**で実行されます。\n* `\"request\"`: リクエストを処理する*path operation 関数*の前に依存関係を開始し（`\"function\"`を使用する場合と同様）、クライアントにレスポンスが返された**後**に終了します。つまり、依存関係関数は**リクエスト**とレスポンスのサイクルの**周囲**で実行されます。\n\n指定されておらず、依存関係に`yield`がある場合、デフォルトで`scope`は`\"request\"`になります。\n\n### サブ依存関係の`scope` { #scope-for-sub-dependencies }\n\n`scope=\"request\"`（デフォルト）を持つ依存関係を宣言する場合、どのサブ依存関係も`\"request\"`の`scope`を持つ必要があります。\n\nしかし、`\"function\"`の`scope`を持つ依存関係は、`\"function\"`と`\"request\"`の`scope`を持つ依存関係を持てます。\n\nこれは、いずれの依存関係も、サブ依存関係より前に終了コードを実行できる必要があるためです（終了コードの実行中にサブ依存関係をまだ使う必要がある可能性があるためです）。\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Dep scope=\"request\"\nparticipant dep_func as Dep scope=\"function\"\nparticipant operation as Path Operation\n\n    client ->> dep_req: Start request\n    Note over dep_req: Run code up to yield\n    dep_req ->> dep_func: Pass dependency\n    Note over dep_func: Run code up to yield\n    dep_func ->> operation: Run path operation with dependency\n    operation ->> dep_func: Return from path operation\n    Note over dep_func: Run code after yield\n    Note over dep_func: ✅ Dependency closed\n    dep_func ->> client: Send response to client\n    Note over client: Response sent\n    Note over dep_req: Run code after yield\n    Note over dep_req: ✅ Dependency closed\n```\n\n## `yield`、`HTTPException`、`except`、バックグラウンドタスクを持つ依存関係 { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n`yield`を持つ依存関係は、さまざまなユースケースをカバーし、いくつかの問題を修正するために、時間とともに進化してきました。\n\nFastAPIの異なるバージョンで何が変わったのかを知りたい場合は、上級ガイドの[上級の依存関係 - `yield`、`HTTPException`、`except`、バックグラウンドタスクを持つ依存関係](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks)で詳しく読めます。\n## コンテキストマネージャ { #context-managers }\n\n### 「コンテキストマネージャ」とは { #what-are-context-managers }\n\n「コンテキストマネージャ」とは、`with`文の中で使用できるPythonオブジェクトのことです。\n\n例えば、[ファイルを読み込むには`with`を使用することができます](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files):\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\nその後の`open(\"./somefile.txt\")`は「コンテキストマネージャ」と呼ばれるオブジェクトを作成します。\n\n`with`ブロックが終了すると、例外があったとしてもファイルを確かに閉じます。\n\n`yield`を持つ依存関係を作成すると、**FastAPI** は内部的にそれをコンテキストマネージャに変換し、他の関連ツールと組み合わせます。\n\n### `yield`を持つ依存関係でのコンテキストマネージャの使用 { #using-context-managers-in-dependencies-with-yield }\n\n/// warning | 注意\n\nこれは多かれ少なかれ、「高度な」発想です。\n\n**FastAPI** を使い始めたばかりの方は、とりあえずスキップした方がよいかもしれません。\n\n///\n\nPythonでは、[以下の２つのメソッドを持つクラスを作成する: `__enter__()`と`__exit__()`](https://docs.python.org/3/reference/datamodel.html#context-managers)ことでコンテキストマネージャを作成することができます。\n\nまた、依存関数の中で`with`や`async with`文を使用することによって`yield`を持つ **FastAPI** の依存関係の中でそれらを使用することができます:\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip | 豆知識\n\nコンテキストマネージャを作成するもう一つの方法は次の方法です:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) または\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nこれらを使って、関数を単一の`yield`でデコレートすることができます。\n\nこれは **FastAPI** が内部的に`yield`を持つ依存関係のために使用しているものです。\n\nしかし、FastAPIの依存関係にデコレータを使う必要はありません（そして使うべきではありません）。\n\nFastAPIが内部的にやってくれます。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# グローバルな依存関係 { #global-dependencies }\n\nアプリケーションの種類によっては、アプリ全体に依存関係を追加したい場合があります。\n\n[`dependencies` を path operation のデコレータに追加](dependencies-in-path-operation-decorators.md)できるのと同様に、`FastAPI` アプリケーション自体にも追加できます。\n\nその場合、アプリケーション内のすべての path operation に適用されます:\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\nまた、[`dependencies` を path operation のデコレータに追加](dependencies-in-path-operation-decorators.md)する節で説明した考え方はすべて引き続き当てはまりますが、この場合はアプリ内のすべての path operation に対して適用されます。\n\n## path operation のグループに対する依存関係 { #dependencies-for-groups-of-path-operations }\n\n後で、複数ファイルを含む大規模アプリケーションの構成方法（[大規模アプリケーション - 複数ファイル](../../tutorial/bigger-applications.md)）を読むと、path operation のグループに対して 1 つの `dependencies` パラメータを宣言する方法を学びます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/dependencies/index.md",
    "content": "# 依存関係 { #dependencies }\n\n**FastAPI** は非常に強力でありながら直感的な **<dfn title=\"別名: コンポーネント、リソース、プロバイダ、サービス、インジェクタブル\">依存性注入</dfn>** システムを持っています。\n\nそれは非常にシンプルに使用できるように設計されており、開発者が他のコンポーネント **FastAPI** と統合するのが非常に簡単になるように設計されています。\n\n## 「Dependency Injection」とは { #what-is-dependency-injection }\n\n**「Dependency Injection」** とは、プログラミングにおいて、コード（この場合は、*path operation 関数*）が動作したり使用したりするために必要なもの（「依存関係」）を宣言する方法があることを意味します:\n\nそして、そのシステム（この場合は、**FastAPI**）は、必要な依存関係をコードに提供するために必要なことは何でも行います（依存関係を「注入」します）。\n\nこれは以下のようなことが必要な時にとても便利です:\n\n* ロジックを共有している。（同じコードロジックを何度も繰り返している）。\n* データベース接続を共有する。\n* セキュリティ、認証、ロール要件などを強制する。\n* そのほかにも多くのこと...\n\nこれらすべてを、コードの繰り返しを最小限に抑えながら行います。\n\n## 最初のステップ { #first-steps }\n\n非常にシンプルな例を見てみましょう。あまりにもシンプルなので、今のところはあまり参考にならないでしょう。\n\nしかし、この方法では **Dependency Injection** システムがどのように機能するかに焦点を当てることができます。\n\n### 依存関係（「dependable」）の作成 { #create-a-dependency-or-dependable }\n\nまずは依存関係に注目してみましょう。\n\n以下のように、*path operation 関数*と同じパラメータを全て取ることができる関数にすぎません:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\nこれだけです。\n\n**２行**。\n\nそして、それはすべての*path operation 関数*が持っているのと同じ形と構造を持っています。\n\n「デコレータ」を含まない（`@app.get(\"/some-path\")`を含まない）*path operation 関数*と考えることもできます。\n\nそして何でも返すことができます。\n\nこの場合、この依存関係は以下を期待しています:\n\n* オプショナルのクエリパラメータ`q`は`str`です。\n* オプショナルのクエリパラメータ`skip`は`int`で、デフォルトは`0`です。\n* オプショナルのクエリパラメータ`limit`は`int`で、デフォルトは`100`です。\n\nそして、これらの値を含む`dict`を返します。\n\n/// info | 情報\n\nFastAPI はバージョン 0.95.0 で `Annotated` のサポートを追加し（そして推奨し始めました）。\n\n古いバージョンを使用している場合、`Annotated` を使おうとするとエラーになります。\n\n`Annotated` を使用する前に、少なくとも 0.95.1 まで [FastAPI のバージョンをアップグレード](../../deployment/versions.md#upgrading-the-fastapi-versions) してください。\n\n///\n\n### `Depends`のインポート { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### 「dependant」での依存関係の宣言 { #declare-the-dependency-in-the-dependant }\n\n*path operation 関数*のパラメータに`Body`や`Query`などを使用するのと同じように、新しいパラメータに`Depends`を使用することができます:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\n関数のパラメータに`Depends`を使用するのは`Body`や`Query`などと同じですが、`Depends`の動作は少し異なります。\n\n`Depends`は１つのパラメータしか与えられません。\n\nこのパラメータは関数のようなものである必要があります。\n\n直接**呼び出しません**（末尾に括弧を付けません）。`Depends()` のパラメータとして渡すだけです。\n\nそして、その関数は、*path operation 関数*が行うのと同じ方法でパラメータを取ります。\n\n/// tip | 豆知識\n\n次の章では、関数以外の「もの」が依存関係として使用できるものを見ていきます。\n\n///\n\n新しいリクエストが到着するたびに、**FastAPI** が以下のような処理を行います:\n\n* 依存関係（\"dependable\"）関数を正しいパラメータで呼び出します。\n* 関数の結果を取得します。\n* *path operation 関数*のパラメータにその結果を代入してください。\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\nこの方法では、共有されるコードを一度書き、**FastAPI** が*path operation*のための呼び出しを行います。\n\n/// check | 確認\n\n特別なクラスを作成してどこかで **FastAPI** に渡して「登録」する必要はないことに注意してください。\n\n`Depends`を渡すだけで、**FastAPI** が残りの処理をしてくれます。\n\n///\n\n## `Annotated` 依存関係の共有 { #share-annotated-dependencies }\n\n上の例では、ほんの少し **コードの重複** があることがわかります。\n\n`common_parameters()` 依存関係を使う必要があるときは、型アノテーションと `Depends()` を含むパラメータ全体を書く必要があります:\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\nしかし、`Annotated` を使用しているので、その `Annotated` 値を変数に格納して複数箇所で使えます:\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | 豆知識\n\nこれはただの標準 Python で、「type alias」と呼ばれ、**FastAPI** 固有のものではありません。\n\nしかし **FastAPI** は `Annotated` を含む Python 標準に基づいているため、このテクニックをコードで使えます。 😎\n\n///\n\n依存関係は期待どおりに動作し続け、**一番良い点** は **型情報が保持される** ことです。つまり、エディタは **自動補完**、**インラインエラー** などを提供し続けられます。`mypy` のような他のツールでも同様です。\n\nこれは **大規模なコードベース** で、**同じ依存関係** を **多くの *path operation*** で何度も使う場合に特に役立ちます。\n\n## `async`にするかどうか { #to-async-or-not-to-async }\n\n依存関係は **FastAPI**（*path operation 関数*と同じ）からも呼び出されるため、関数を定義する際にも同じルールが適用されます。\n\n`async def`や通常の`def`を使用することができます。\n\nまた、通常の`def`*path operation 関数*の中に`async def`を入れて依存関係を宣言したり、`async def`*path operation 関数*の中に`def`を入れて依存関係を宣言したりすることなどができます。\n\nそれは重要ではありません。**FastAPI** は何をすべきかを知っています。\n\n/// note | 備考\n\nわからない場合は、ドキュメントの[Async: *「急いでいますか？」*](../../async.md#in-a-hurry)の中の`async`と`await`についてのセクションを確認してください。\n\n///\n\n## OpenAPIとの統合 { #integrated-with-openapi }\n\n依存関係（およびサブ依存関係）のすべてのリクエスト宣言、検証、および要件は、同じOpenAPIスキーマに統合されます。\n\nつまり、対話型ドキュメントにはこれらの依存関係から得られる全ての情報も含まれているということです:\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## 簡単な使い方 { #simple-usage }\n\n見てみると、*path*と*operation*が一致した時に*path operation 関数*が宣言されていて、**FastAPI** が正しいパラメータで関数を呼び出してリクエストからデータを抽出する処理をしています。\n\n実は、すべての（あるいはほとんどの）Webフレームワークは、このように動作します。\n\nこれらの関数を直接呼び出すことはありません。これらの関数はフレームワーク（この場合は、**FastAPI**）によって呼び出されます。\n\nDependency Injection システムでは、**FastAPI** に*path operation 関数*もまた、*path operation 関数*の前に実行されるべき他の何かに「依存」していることを伝えることができ、**FastAPI** がそれを実行し、結果を「注入」することを引き受けます。\n\n他にも、「dependency injection」と同じような考えの一般的な用語があります:\n\n* resources\n* providers\n* services\n* injectables\n* components\n\n## **FastAPI** プラグイン { #fastapi-plug-ins }\n\n統合や「プラグイン」は **Dependency Injection** システムを使って構築することができます。しかし、実際には、**「プラグイン」を作成する必要はありません**。依存関係を使用することで、無限の数の統合やインタラクションを宣言することができ、それが*path operation 関数*で利用可能になるからです。\n\n依存関係は非常にシンプルで直感的な方法で作成することができ、必要なPythonパッケージをインポートするだけで、*文字通り*数行のコードでAPI関数と統合することができます。\n\n次の章では、リレーショナルデータベースやNoSQLデータベース、セキュリティなどについて、その例を見ていきます。\n\n## **FastAPI** 互換性 { #fastapi-compatibility }\n\ndependency injection システムがシンプルなので、**FastAPI** は以下のようなものと互換性があります:\n\n* すべてのリレーショナルデータベース\n* NoSQLデータベース\n* 外部パッケージ\n* 外部API\n* 認証・認可システム\n* API利用状況監視システム\n* レスポンスデータ注入システム\n* など。\n\n## シンプルでパワフル { #simple-and-powerful }\n\n階層的な dependency injection システムは、定義や使用方法が非常にシンプルであるにもかかわらず、非常に強力なものとなっています。\n\n依存関係が、さらに依存関係を定義することもできます。\n\n最終的には、依存関係の階層ツリーが構築され、**Dependency Injection**システムが、これらの依存関係（およびそのサブ依存関係）をすべて解決し、各ステップで結果を提供（注入）します。\n\n例えば、４つのAPIエンドポイント（*path operation*）があるとします:\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\nそして、依存関係とサブ依存関係だけで、それぞれに異なるパーミッション要件を追加することができます:\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## **OpenAPI** との統合 { #integrated-with-openapi_1 }\n\nこれら全ての依存関係は、要件を宣言すると同時に、*path operation*にパラメータやバリデーションを追加します。\n\n**FastAPI** はそれをすべてOpenAPIスキーマに追加して、対話型のドキュメントシステムに表示されるようにします。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# サブ依存関係 { #sub-dependencies }\n\n**サブ依存関係** を持つ依存関係を作成することができます。\n\nそれらは必要なだけ **深く** することができます。\n\n**FastAPI** はそれらを解決してくれます。\n\n## 最初の依存関係「依存可能なもの」 { #first-dependency-dependable }\n\n以下のような最初の依存関係（「依存可能なもの」）を作成することができます:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\nこれはオプショナルのクエリパラメータ`q`を`str`として宣言し、それを返すだけです。\n\nこれは非常にシンプルです（あまり便利ではありません）が、サブ依存関係がどのように機能するかに焦点を当てるのに役立ちます。\n\n## 第二の依存関係 「依存可能なもの」と「依存」 { #second-dependency-dependable-and-dependant }\n\nそして、別の依存関数（「依存可能なもの」）を作成して、同時にそれ自身の依存関係を宣言することができます（つまりそれ自身も「依存」です）:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\n宣言されたパラメータに注目してみましょう:\n\n* この関数は依存関係（「依存可能なもの」）そのものであるにもかかわらず、別の依存関係を宣言しています（何か他のものに「依存」しています）。\n    * これは`query_extractor`に依存しており、それが返す値をパラメータ`q`に代入します。\n* また、オプショナルの`last_query`クッキーを`str`として宣言します。\n    * ユーザーがクエリ`q`を提供しなかった場合、クッキーに保存していた最後に使用したクエリを使用します。\n\n## 依存関係の使用 { #use-the-dependency }\n\n以下のように依存関係を使用することができます:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info | 情報\n\n*path operation 関数*の中で宣言している依存関係は`query_or_cookie_extractor`の1つだけであることに注意してください。\n\nしかし、**FastAPI** は`query_extractor`を最初に解決し、その結果を`query_or_cookie_extractor`を呼び出す時に渡す必要があることを知っています。\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## 同じ依存関係の複数回の使用 { #using-the-same-dependency-multiple-times }\n\n依存関係の1つが同じ*path operation*に対して複数回宣言されている場合、例えば、複数の依存関係が共通のサブ依存関係を持っている場合、**FastAPI** はリクエストごとに1回だけそのサブ依存関係を呼び出します。\n\nそして、返された値を<dfn title=\"計算/生成された値を保存し、再計算する代わりに再利用するためのユーティリティ/システム\">「キャッシュ」</dfn>に保存し、同じリクエストに対して依存関係を何度も呼び出す代わりに、その特定のリクエストでそれを必要とする全ての「依存」に渡すことになります。\n\n高度なシナリオでは、「キャッシュされた」値を使うのではなく、同じリクエストの各ステップ（おそらく複数回）で依存関係を呼び出す必要があることがわかっている場合、`Depends`を使用する際に、`use_cache=False`というパラメータを設定することができます:\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ 非Annotated\n\n/// tip | 豆知識\n\n可能であれば`Annotated`版を使うことを推奨します。\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## まとめ { #recap }\n\nここで使われている派手な言葉は別にして、**Dependency Injection** システムは非常にシンプルです。\n\n*path operation 関数*と同じように見えるただの関数です。\n\nしかし、それでも非常に強力で、任意の深くネストされた依存関係「グラフ」（ツリー）を宣言することができます。\n\n/// tip | 豆知識\n\nこれらの単純な例では、全てが役に立つとは言えないかもしれません。\n\nしかし、**security** についての章で、それがどれほど有用であるかがわかるでしょう。\n\nそして、あなたを救うコードの量もみることになるでしょう。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/tutorial/encoder.md",
    "content": "# JSON互換エンコーダ { #json-compatible-encoder }\n\nデータ型（Pydanticモデルのような）をJSONと互換性のあるもの（`dict`や`list`など）に変換する必要があるケースがあります。\n\n例えば、データベースに保存する必要がある場合です。\n\nそのために、**FastAPI** は`jsonable_encoder()`関数を提供しています。\n\n## `jsonable_encoder`の使用 { #using-the-jsonable-encoder }\n\nJSON互換のデータのみを受信するデータベース`fake_db`があるとしましょう。\n\n例えば、`datetime`オブジェクトはJSONと互換性がないので、受け取られません。\n\nそのため、`datetime`オブジェクトは[ISO形式](https://en.wikipedia.org/wiki/ISO_8601)のデータを含む`str`に変換されなければなりません。\n\n同様に、このデータベースはPydanticモデル（属性を持つオブジェクト）を受け取らず、`dict`だけを受け取ります。\n\nそのために`jsonable_encoder`を使用することができます。\n\nPydanticモデルのようなオブジェクトを受け取り、JSON互換版を返します:\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\nこの例では、Pydanticモデルを`dict`に、`datetime`を`str`に変換します。\n\n呼び出した結果は、Pythonの標準の[`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps)でエンコードできるものです。\n\nこれはJSON形式のデータを含む大きな`str`を（文字列として）返しません。JSONと互換性のある値とサブの値を持つPython標準のデータ構造（例：`dict`）を返します。\n\n/// note | 備考\n\n`jsonable_encoder`は実際には **FastAPI** が内部的にデータを変換するために使用します。しかしこれは他の多くのシナリオで有用です。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/tutorial/extra-data-types.md",
    "content": "# 追加データ型 { #extra-data-types }\n\n今まで、以下のような一般的なデータ型を使用してきました:\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\nしかし、より複雑なデータ型を使用することもできます。\n\nそして、今まで見てきたのと同じ機能を持つことになります:\n\n* 素晴らしいエディタのサポート。\n* 受信したリクエストからのデータ変換。\n* レスポンスデータのデータ変換。\n* データの検証。\n* 自動注釈と文書化。\n\n## 他のデータ型 { #other-data-types }\n\nここでは、使用できる追加のデータ型のいくつかを紹介します:\n\n* `UUID`:\n    * 多くのデータベースやシステムで共通のIDとして使用される、標準的な「ユニバーサルにユニークな識別子」です。\n    * リクエストとレスポンスでは`str`として表現されます。\n* `datetime.datetime`:\n    * Pythonの`datetime.datetime`です。\n    * リクエストとレスポンスはISO 8601形式の`str`で表現されます（例: `2008-09-15T15:53:00+05:00`）。\n* `datetime.date`:\n    * Python `datetime.date`。\n    * リクエストとレスポンスはISO 8601形式の`str`で表現されます（例: `2008-09-15`）。\n* `datetime.time`:\n    * Pythonの`datetime.time`。\n    * リクエストとレスポンスはISO 8601形式の`str`で表現されます（例: `14:23:55.003`）。\n* `datetime.timedelta`:\n    * Pythonの`datetime.timedelta`です。\n    * リクエストとレスポンスでは合計秒数の`float`で表現されます。\n    * Pydanticでは「ISO 8601 time diff encoding」として表現することも可能です。[詳細はドキュメントを参照してください](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers)。\n* `frozenset`:\n    * リクエストとレスポンスでは`set`と同じように扱われます:\n        * リクエストでは、リストが読み込まれ、重複を排除して`set`に変換されます。\n        * レスポンスでは`set`が`list`に変換されます。\n        * 生成されたスキーマは`set`の値が一意であることを指定します（JSON Schemaの`uniqueItems`を使用します）。\n* `bytes`:\n    * Pythonの標準的な`bytes`です。\n    * リクエストとレスポンスでは`str`として扱われます。\n    * 生成されたスキーマは`str`で`binary`の「フォーマット」を持つことを指定します。\n* `Decimal`:\n    * Pythonの標準的な`Decimal`です。\n    * リクエストとレスポンスでは`float`と同じように扱われます。\n* 有効なPydanticのデータ型はここで確認できます: [Pydantic のデータ型](https://docs.pydantic.dev/latest/usage/types/types/)。\n\n## 例 { #example }\n\nここでは、上記の型のいくつかを使用したパラメータを持つ*path operation*の例を示します。\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\n関数内のパラメータは自然なデータ型を持っていることに注意してください。そして、例えば、以下のように通常の日付操作を行うことができます:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/ja/docs/tutorial/extra-models.md",
    "content": "# 追加のモデル { #extra-models }\n\n先ほどの例に続き、複数の関連モデルを持つことは一般的です。\n\nこれはユーザーモデルの場合は特にそうです。なぜなら:\n\n* **入力モデル** にはパスワードが必要です。\n* **出力モデル**はパスワードをもつべきではありません。\n* **データベースモデル**はおそらくハッシュ化されたパスワードが必要になるでしょう。\n\n/// danger | 警告\n\nユーザーの平文のパスワードは絶対に保存しないでください。常に検証できる「安全なハッシュ」を保存してください。\n\n知らない方は、[セキュリティの章](security/simple-oauth2.md#password-hashing)で「パスワードハッシュ」とは何かを学ぶことができます。\n\n///\n\n## 複数のモデル { #multiple-models }\n\nここでは、パスワードフィールドをもつモデルがどのように見えるのか、また、どこで使われるのか、大まかなイメージを紹介します:\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### `**user_in.model_dump()` について { #about-user-in-model-dump }\n\n#### Pydanticの`.model_dump()` { #pydantics-model-dump }\n\n`user_in`は`UserIn`クラスのPydanticモデルです。\n\nPydanticモデルには、モデルのデータを含む`dict`を返す`.model_dump()`メソッドがあります。\n\nそこで、以下のようなPydanticオブジェクト`user_in`を作成すると:\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\nそして呼び出すと:\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\nこれで変数`user_dict`のデータを持つ`dict`ができました。（これはPydanticモデルのオブジェクトの代わりに`dict`です）。\n\nそして呼び出すと:\n\n```Python\nprint(user_dict)\n```\n\n以下のようなPythonの`dict`を得ることができます:\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### `dict`の展開 { #unpacking-a-dict }\n\n`user_dict`のような`dict`を受け取り、それを`**user_dict`を持つ関数（またはクラス）に渡すと、Pythonはそれを「展開」します。これは`user_dict`のキーと値を直接キー・バリューの引数として渡します。\n\nそこで上述の`user_dict`の続きを以下のように書くと:\n\n```Python\nUserInDB(**user_dict)\n```\n\n以下と同等の結果になります:\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\nもっと正確に言えば、`user_dict`を将来的にどんな内容であっても直接使用することになります:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### 別のモデルの内容からつくるPydanticモデル { #a-pydantic-model-from-the-contents-of-another }\n\n上述の例では`user_in.model_dump()`から`user_dict`をこのコードのように取得していますが:\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\nこれは以下と同等です:\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n...なぜなら`user_in.model_dump()`は`dict`であり、`**`を付与して`UserInDB`を渡してPythonに「展開」させているからです。\n\nそこで、別のPydanticモデルのデータからPydanticモデルを取得します。\n\n#### `dict`の展開と追加キーワード { #unpacking-a-dict-and-extra-keywords }\n\nそして、追加のキーワード引数`hashed_password=hashed_password`を以下のように追加すると:\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n...以下のようになります:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning | 注意\n\n追加のサポート関数`fake_password_hasher`と`fake_save_user`は、データの可能な流れをデモするだけであり、もちろん本当のセキュリティを提供しているわけではありません。\n\n///\n\n## 重複の削減 { #reduce-duplication }\n\nコードの重複を減らすことは、**FastAPI**の中核的なアイデアの１つです。\n\nコードの重複が増えると、バグやセキュリティの問題、コードの非同期化問題（ある場所では更新しても他の場所では更新されない場合）などが発生する可能性が高くなります。\n\nそして、これらのモデルは全てのデータを共有し、属性名や型を重複させています。\n\nもっと良い方法があります。\n\n他のモデルのベースとなる`UserBase`モデルを宣言することができます。そして、そのモデルの属性（型宣言、検証など）を継承するサブクラスを作ることができます。\n\nデータの変換、検証、文書化などはすべて通常通りに動作します。\n\nこのようにして、モデル間の違いだけを宣言することができます（平文の`password`、`hashed_password`、パスワードなし）:\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` または `anyOf` { #union-or-anyof }\n\nレスポンスを2つ以上の型の`Union`として宣言できます。つまり、そのレスポンスはそれらのいずれかになります。\n\nOpenAPIでは`anyOf`で定義されます。\n\nそのためには、標準的なPythonの型ヒント[`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union)を使用します:\n\n/// note | 備考\n\n[`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions)を定義する場合は、最も具体的な型を先に、その後により具体性の低い型を含めてください。以下の例では、より具体的な`PlaneItem`が`Union[PlaneItem, CarItem]`内で`CarItem`より前に来ています。\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### Python 3.10の`Union` { #union-in-python-3-10 }\n\nこの例では、引数`response_model`の値として`Union[PlaneItem, CarItem]`を渡しています。\n\n**型アノテーション**に書くのではなく、**引数の値**として渡しているため、Python 3.10でも`Union`を使う必要があります。\n\n型アノテーションであれば、次のように縦棒を使用できました:\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\nしかし、これを代入で`response_model=PlaneItem | CarItem`のように書くと、Pythonはそれを型アノテーションとして解釈するのではなく、`PlaneItem`と`CarItem`の間で**無効な操作**を行おうとしてしまうため、エラーになります。\n\n## モデルのリスト { #list-of-models }\n\n同じように、オブジェクトのリストのレスポンスを宣言できます。\n\nそのためには、標準のPythonの`list`を使用します:\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## 任意の`dict`によるレスポンス { #response-with-arbitrary-dict }\n\nまた、Pydanticモデルを使用せずに、キーと値の型だけを定義した任意の`dict`を使ってレスポンスを宣言することもできます。\n\nこれは、有効なフィールド・属性名（Pydanticモデルに必要なもの）を事前に知らない場合に便利です。\n\nこの場合、`dict`を使用できます:\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## まとめ { #recap }\n\n複数のPydanticモデルを使用し、ケースごとに自由に継承します。\n\nエンティティが異なる「状態」を持たなければならない場合は、エンティティごとに単一のデータモデルを持つ必要はありません。`password`、`password_hash`、パスワードなしを含む状態を持つユーザー「エンティティ」の場合と同様です。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/first-steps.md",
    "content": "# 最初のステップ { #first-steps }\n\n最もシンプルなFastAPIファイルは以下のようになります:\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\nこれを`main.py`にコピーします。\n\nライブサーバーを実行します:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n出力には次のような行があります:\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\nこの行はローカルマシンでアプリが提供されているURLを示しています。\n\n### チェック { #check-it }\n\nブラウザで[http://127.0.0.1:8000](http://127.0.0.1:8000)を開きます。\n\n次のようなJSONレスポンスが表示されます:\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### 対話的APIドキュメント { #interactive-api-docs }\n\n次に、[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)にアクセスします。\n\n自動生成された対話的APIドキュメントが表示されます（[Swagger UI](https://github.com/swagger-api/swagger-ui)で提供）:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### 代替APIドキュメント { #alternative-api-docs }\n\n次に、[http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)にアクセスします。\n\n先ほどとは異なる、自動生成された対話的APIドキュメントが表示されます（[ReDoc](https://github.com/Rebilly/ReDoc)によって提供）:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI**は、APIを定義するための**OpenAPI**標準規格を使用して、すべてのAPIの「スキーマ」を生成します。\n\n#### 「スキーマ」 { #schema }\n\n「スキーマ」は定義または説明です。実装コードではなく、単なる抽象的な説明です。\n\n#### API「スキーマ」 { #api-schema }\n\nここでは、[OpenAPI](https://github.com/OAI/OpenAPI-Specification)はAPIのスキーマ定義の方法を規定する仕様です。\n\nこのスキーマ定義はAPIパス、受け取り可能なパラメータなどが含まれます。\n\n#### データ「スキーマ」 { #data-schema }\n\n「スキーマ」という用語は、JSONコンテンツなどの一部のデータの形状を指す場合もあります。\n\nそのような場合、スキーマはJSON属性とそれらが持つデータ型などを意味します。\n\n#### OpenAPIおよびJSONスキーマ { #openapi-and-json-schema }\n\nOpenAPIはAPIのためのAPIスキーマを定義します。そして、そのスキーマは**JSONデータスキーマ**の標準規格である**JSON Schema**を利用するAPIによって送受されるデータの定義（または「スキーマ」）を含んでいます。\n\n#### `openapi.json`を確認 { #check-the-openapi-json }\n\n素のOpenAPIスキーマがどのようなものか興味がある場合、FastAPIはすべてのAPIの説明を含むJSON（スキーマ）を自動的に生成します。\n\n次の場所で直接確認できます: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).\n\n次のようなJSONが表示されます。\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### OpenAPIの目的 { #what-is-openapi-for }\n\nOpenAPIスキーマは、FastAPIに含まれている2つのインタラクティブなドキュメントシステムの動力源です。\n\nそして、OpenAPIに基づいた代替案が数十通りあります。 **FastAPI**で構築されたアプリケーションに、これらの選択肢を簡単に追加できます。\n\nまた、APIと通信するクライアント用のコードを自動的に生成するために使用することもできます。たとえば、フロントエンド、モバイル、またはIoTアプリケーションです。\n\n### `pyproject.toml`でアプリの`entrypoint`を設定 { #configure-the-app-entrypoint-in-pyproject-toml }\n\n`pyproject.toml`でアプリの場所を次のように設定できます:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nこの`entrypoint`は、`fastapi`コマンドに対して、次のようにアプリをインポートすべきであることを伝えます:\n\n```python\nfrom main import app\n```\n\nもしコード構成が次のようになっている場合:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nこのときは`entrypoint`を次のように設定します:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nこれは次と同等です:\n\n```python\nfrom backend.main import app\n```\n\n### パス付きの`fastapi dev` { #fastapi-dev-with-path }\n\n`fastapi dev`コマンドにファイルパスを渡すこともでき、使用すべきFastAPIのappオブジェクトを推測します:\n\n```console\n$ fastapi dev main.py\n```\n\nただし、その場合は毎回`fastapi`コマンドを呼ぶたびに正しいパスを渡すことを覚えておく必要があります。\n\nさらに、他のツール（たとえば、[VS Code 拡張機能](../editor-support.md)や[FastAPI Cloud](https://fastapicloud.com)）が見つけられない場合があります。そのため、`pyproject.toml`の`entrypoint`を使うことを推奨します。\n\n### アプリをデプロイ（任意） { #deploy-your-app-optional }\n\n任意でFastAPIアプリを[FastAPI Cloud](https://fastapicloud.com)にデプロイできます。まだなら、待機リストに登録してください。 🚀\n\nすでに**FastAPI Cloud**アカウントがある場合（待機リストから招待済みの場合😉）、1コマンドでアプリケーションをデプロイできます。\n\nデプロイする前に、ログインしていることを確認してください:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\nその後、アプリをデプロイします:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n以上です！これで、そのURLでアプリにアクセスできます。 ✨\n\n## ステップ毎の要約 { #recap-step-by-step }\n\n### Step 1: `FastAPI`をインポート { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI`は、APIのすべての機能を提供するPythonクラスです。\n\n/// note | 技術詳細\n\n`FastAPI`は`Starlette`を直接継承するクラスです。\n\n`FastAPI`でも[Starlette](https://www.starlette.dev/)のすべての機能を利用可能です。\n\n///\n\n### Step 2: `FastAPI`の「インスタンス」を生成 { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\nここで、`app`変数が`FastAPI`クラスの「インスタンス」になります。\n\nこれが、すべてのAPIを作成するための主要なポイントになります。\n\n### Step 3: *path operation*を作成 { #step-3-create-a-path-operation }\n\n#### パス { #path }\n\nここでの「パス」とは、最初の`/`から始まるURLの最後の部分を指します。\n\nしたがって、次のようなURLでは:\n\n```\nhttps://example.com/items/foo\n```\n\n...パスは次のようになります:\n\n```\n/items/foo\n```\n\n/// info | 情報\n\n「パス」は一般に「エンドポイント」または「ルート」とも呼ばれます。\n\n///\n\nAPIを構築する際、「パス」は「関心事」と「リソース」を分離するための主要な方法です。\n\n#### Operation { #operation }\n\nここでの「オペレーション」とは、HTTPの「メソッド」の1つを指します。\n\n以下のようなものの1つ:\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n...さらによりエキゾチックなもの:\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\nHTTPプロトコルでは、これらの「メソッド」の1つ（または複数）を使用して各パスにアクセスできます。\n\n---\n\nAPIを構築するときは、通常、これらの特定のHTTPメソッドを使用して特定のアクションを実行します。\n\n通常は次を使用します:\n\n* `POST`: データの作成\n* `GET`: データの読み取り\n* `PUT`: データの更新\n* `DELETE`: データの削除\n\nしたがって、OpenAPIでは、各HTTPメソッドは「オペレーション」と呼ばれます。\n\n「**オペレーションズ**」とも呼ぶことにします。\n\n#### *path operation デコレータ*を定義 { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\n`@app.get(\"/\")`は直下の関数が下記のリクエストの処理を担当することを**FastAPI**に伝えます:\n\n* パス `/`\n* <dfn title=\"HTTP GET メソッド\"><code>get</code> オペレーション</dfn>\n\n/// info | `@decorator` 情報\n\nPythonにおける`@something`シンタックスはデコレータと呼ばれます。\n\n「デコレータ」は関数の上に置きます。かわいらしい装飾的な帽子のようです（この用語の由来はそこにあると思います）。\n\n「デコレータ」は直下の関数を受け取り、それを使って何かを行います。\n\n私たちの場合、このデコレーターは直下の関数が**オペレーション** `get`を使用した**パス** `/`に対応することを**FastAPI** に通知します。\n\nこれが「*path operation デコレータ*」です。\n\n///\n\n他のオペレーションも使用できます:\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\nまた、よりエキゾチックなものも使用できます:\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip | 豆知識\n\n各オペレーション (HTTPメソッド)は自由に使用できます。\n\n**FastAPI**は特定の意味づけを強制しません。\n\nここでの情報は、要件ではなくガイドラインとして提示されます。\n\n例えば、GraphQLを使用する場合、通常は`POST`オペレーションのみを使用してすべてのアクションを実行します。\n\n///\n\n### Step 4: **path operation 関数**を定義 { #step-4-define-the-path-operation-function }\n\n以下は「**path operation 関数**」です:\n\n* **パス**: は`/`です。\n* **オペレーション**: は`get`です。\n* **関数**: 「デコレータ」の直下にある関数 (`@app.get(\"/\")`の直下) です。\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\nこれは、Pythonの関数です。\n\nこの関数は、`GET`オペレーションを使ったURL「`/`」へのリクエストを受け取るたびに**FastAPI**によって呼び出されます。\n\nこの場合、この関数は`async`関数です。\n\n---\n\n`async def`の代わりに通常の関数として定義することもできます:\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note | 備考\n\n違いが分からない場合は、[Async: *「急いでいますか？」*](../async.md#in-a-hurry)を確認してください。\n\n///\n\n### Step 5: コンテンツの返信 { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\n`dict`、`list`、`str`、`int`などの単一の値を返すことができます。\n\nPydanticモデルを返すこともできます（後で詳しく説明します）。\n\nJSONに自動的に変換されるオブジェクトやモデルは他にもたくさんあります（ORMなど）。 お気に入りのものを使ってみてください。すでにサポートされている可能性が高いです。\n\n### Step 6: デプロイする { #step-6-deploy-it }\n\n**[FastAPI Cloud](https://fastapicloud.com)**に1コマンドでアプリをデプロイします: `fastapi deploy`. 🎉\n\n#### FastAPI Cloudについて { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)**は、**FastAPI**の作者とそのチームによって開発されています。\n\n最小限の労力でAPIの**構築**、**デプロイ**、**アクセス**を行うプロセスを合理化します。\n\nFastAPIでアプリを構築するのと同じ**開発体験**を、クラウドへの**デプロイ**にもたらします。 🎉\n\nFastAPI Cloudは、*FastAPI and friends*のオープンソースプロジェクトに対する主要スポンサーであり、資金提供元です。 ✨\n\n#### 他のクラウドプロバイダにデプロイする { #deploy-to-other-cloud-providers }\n\nFastAPIはオープンソースで、標準に基づいています。選択した任意のクラウドプロバイダにFastAPIアプリをデプロイできます。\n\nクラウドプロバイダのガイドに従って、FastAPIアプリをデプロイしてください。 🤓\n\n## まとめ { #recap }\n\n* `FastAPI`をインポートします。\n* `app`インスタンスを生成します。\n* `@app.get(\"/\")`のようなデコレータを使用して、**path operation デコレータ**を記述します。\n* **path operation 関数**を定義します。例: `def root(): ...`。\n* `fastapi dev`コマンドで開発サーバーを起動します。\n* 任意で`fastapi deploy`を使ってアプリをデプロイします。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/handling-errors.md",
    "content": "# エラーハンドリング { #handling-errors }\n\nAPIを使用しているクライアントにエラーを通知する必要がある状況はたくさんあります。\n\nこのクライアントは、フロントエンドを持つブラウザ、誰かのコード、IoTデバイスなどが考えられます。\n\nクライアントに以下のようなことを伝える必要があるかもしれません:\n\n* クライアントにはその操作のための十分な権限がありません。\n* クライアントはそのリソースにアクセスできません。\n* クライアントがアクセスしようとしていた項目が存在しません。\n* など\n\nこれらの場合、通常は **400**（400から499）の範囲内の **HTTPステータスコード** を返すことになります。\n\nこれは200のHTTPステータスコード（200から299）に似ています。これらの「200」ステータスコードは、何らかの形でリクエスト「成功」であったことを意味します。\n\n400の範囲にあるステータスコードは、クライアントからのエラーがあったことを意味します。\n\n**\"404 Not Found\"** のエラー（およびジョーク）を覚えていますか？\n\n## `HTTPException`の使用 { #use-httpexception }\n\nHTTPレスポンスをエラーでクライアントに返すには、`HTTPException`を使用します。\n\n### `HTTPException`のインポート { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### コード内での`HTTPException`の発生 { #raise-an-httpexception-in-your-code }\n\n`HTTPException`は通常のPythonの例外であり、APIに関連するデータを追加したものです。\n\nPythonの例外なので、`return`ではなく、`raise`です。\n\nこれはまた、*path operation関数*の内部で呼び出しているユーティリティ関数の内部から`HTTPException`を発生させた場合、*path operation関数*の残りのコードは実行されず、そのリクエストを直ちに終了させ、`HTTPException`からのHTTPエラーをクライアントに送信することを意味します。\n\n値を返す`return`よりも例外を発生させることの利点は、「依存関係とセキュリティ」のセクションでより明確になります。\n\nこの例では、クライアントが存在しないIDでアイテムを要求した場合、`404`のステータスコードを持つ例外を発生させます:\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### レスポンス結果 { #the-resulting-response }\n\nクライアントが`http://example.com/items/foo`（`item_id` `\"foo\"`）をリクエストすると、HTTPステータスコードが200で、以下のJSONレスポンスが返されます:\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\nしかし、クライアントが`http://example.com/items/bar`（存在しない`item_id` `\"bar\"`）をリクエストした場合、HTTPステータスコード404（\"not found\"エラー）と以下のJSONレスポンスが返されます:\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip | 豆知識\n\n`HTTPException`を発生させる際には、`str`だけでなく、JSONに変換できる任意の値を`detail`パラメータとして渡すことができます。\n\n`dict`や`list`などを渡すことができます。\n\nこれらは **FastAPI** によって自動的に処理され、JSONに変換されます。\n\n///\n\n## カスタムヘッダーの追加 { #add-custom-headers }\n\n例えば、いくつかのタイプのセキュリティのために、HTTPエラーにカスタムヘッダを追加できると便利な状況がいくつかあります。\n\nおそらくコードの中で直接使用する必要はないでしょう。\n\nしかし、高度なシナリオのために必要な場合には、カスタムヘッダーを追加することができます:\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## カスタム例外ハンドラのインストール { #install-custom-exception-handlers }\n\nカスタム例外ハンドラは[Starletteと同じ例外ユーティリティ](https://www.starlette.dev/exceptions/)を使用して追加することができます。\n\nあなた（または使用しているライブラリ）が`raise`するかもしれないカスタム例外`UnicornException`があるとしましょう。\n\nそして、この例外をFastAPIでグローバルに処理したいと思います。\n\nカスタム例外ハンドラを`@app.exception_handler()`で追加することができます:\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\nここで、`/unicorns/yolo`をリクエストすると、*path operation*は`UnicornException`を`raise`します。\n\nしかし、これは`unicorn_exception_handler`で処理されます。\n\nそのため、HTTPステータスコードが`418`で、JSONの内容が以下のような明確なエラーを受け取ることになります:\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | 技術詳細\n\nまた、`from starlette.requests import Request`と`from starlette.responses import JSONResponse`を使用することもできます。\n\n**FastAPI** は開発者の利便性を考慮して、`fastapi.responses`と同じ`starlette.responses`を提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。これは`Request`と同じです。\n\n///\n\n## デフォルトの例外ハンドラのオーバーライド { #override-the-default-exception-handlers }\n\n**FastAPI** にはいくつかのデフォルトの例外ハンドラがあります。\n\nこれらのハンドラは、`HTTPException`を`raise`させた場合や、リクエストに無効なデータが含まれている場合にデフォルトのJSONレスポンスを返す役割を担っています。\n\nこれらの例外ハンドラを独自のものでオーバーライドすることができます。\n\n### リクエスト検証の例外のオーバーライド { #override-request-validation-exceptions }\n\nリクエストに無効なデータが含まれている場合、**FastAPI** は内部的に`RequestValidationError`を発生させます。\n\nまた、そのためのデフォルトの例外ハンドラも含まれています。\n\nこれをオーバーライドするには`RequestValidationError`をインポートして`@app.exception_handler(RequestValidationError)`と一緒に使用して例外ハンドラをデコレートします。\n\nこの例外ハンドラは`Request`と例外を受け取ります。\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\nこれで、`/items/foo`にアクセスすると、以下のデフォルトのJSONエラーの代わりに:\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\n以下のテキスト版を取得します:\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### `HTTPException`エラーハンドラのオーバーライド { #override-the-httpexception-error-handler }\n\n同様に、`HTTPException`ハンドラをオーバーライドすることもできます。\n\n例えば、これらのエラーに対しては、JSONではなくプレーンテキストを返すようにすることができます:\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | 技術詳細\n\nまた、`from starlette.responses import PlainTextResponse`を使用することもできます。\n\n**FastAPI** は開発者の利便性を考慮して、`fastapi.responses`と同じ`starlette.responses`を提供しています。しかし、利用可能なレスポンスのほとんどはStarletteから直接提供されます。\n\n///\n\n/// warning | 注意\n\n`RequestValidationError`には、検証エラーが発生したファイル名と行番号の情報が含まれているため、必要であれば関連情報と一緒にログに表示できます。\n\nしかし、そのまま文字列に変換して直接その情報を返すと、システムに関する情報が多少漏えいする可能性があります。そのため、ここではコードが各エラーを個別に抽出して表示します。\n\n///\n\n### `RequestValidationError`のボディの使用 { #use-the-requestvalidationerror-body }\n\n`RequestValidationError`には無効なデータを含む`body`が含まれています。\n\nアプリ開発中にボディのログを取ってデバッグしたり、ユーザーに返したりなどに使用することができます。\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\nここで、以下のような無効な項目を送信してみてください:\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\n受信したボディを含むデータが無効であることを示すレスポンスが表示されます:\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### FastAPIの`HTTPException`とStarletteの`HTTPException` { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI**は独自の`HTTPException`を持っています。\n\nまた、 **FastAPI**の`HTTPException`エラークラスはStarletteの`HTTPException`エラークラスを継承しています。\n\n唯一の違いは、**FastAPI** の`HTTPException`は`detail`フィールドにJSONに変換可能な任意のデータを受け付けるのに対し、Starletteの`HTTPException`は文字列のみを受け付けることです。\n\nそのため、コード内では通常通り **FastAPI** の`HTTPException`を発生させ続けることができます。\n\nしかし、例外ハンドラを登録する際には、Starletteの`HTTPException`に対して登録しておく必要があります。\n\nこれにより、Starletteの内部コードやStarletteの拡張機能やプラグインの一部がStarletteの`HTTPException`を発生させた場合、ハンドラがそれをキャッチして処理できるようになります。\n\nこの例では、同じコード内で両方の`HTTPException`を使用できるようにするために、Starletteの例外を`StarletteHTTPException`にリネームしています:\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### **FastAPI** の例外ハンドラの再利用 { #reuse-fastapis-exception-handlers }\n\n**FastAPI** から同じデフォルトの例外ハンドラと一緒に例外を使用したい場合は、`fastapi.exception_handlers`からデフォルトの例外ハンドラをインポートして再利用できます:\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\nこの例では、非常に表現力のあるメッセージでエラーを`print`しているだけですが、要点は理解できるはずです。例外を使用し、その後デフォルトの例外ハンドラを再利用できます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/header-param-models.md",
    "content": "# ヘッダーパラメータのモデル { #header-parameter-models }\n\n関連する**ヘッダーパラメータ**が一式ある場合、それらを宣言するための**Pydantic モデル**を作成できます。\n\nこれにより、モデルを**複数箇所**で**再利用**でき、さらにすべてのパラメータに対するバリデーションやメタデータを一括で宣言できます。😎\n\n/// note | 備考\n\nこれは FastAPI バージョン `0.115.0` 以降でサポートされています。🤓\n\n///\n\n## Pydantic モデルによるヘッダーパラメータ { #header-parameters-with-a-pydantic-model }\n\n必要な**ヘッダーパラメータ**を**Pydantic モデル**内で宣言し、関数引数ではそのパラメータを `Header` として宣言します:\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\n**FastAPI** はリクエストの**ヘッダー**から**各フィールド**の値を**抽出**し、定義した Pydantic モデルとして渡します。\n\n## ドキュメントの確認 { #check-the-docs }\n\n`/docs` のドキュメント UI で必要なヘッダーを確認できます:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## 余分なヘッダーを禁止 { #forbid-extra-headers }\n\n特殊なユースケース（あまり一般的ではありません）では、受け付けるヘッダーを**制限**したい場合があります。\n\nPydantic のモデル設定で `extra` フィールドを `forbid` にして禁止できます:\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\nクライアントが**余分なヘッダー**を送信しようとすると、**エラー**レスポンスが返されます。\n\n例えば、クライアントが値 `plumbus` の `tool` ヘッダーを送ろうとすると、ヘッダーパラメータ `tool` は許可されていない旨の**エラー**レスポンスが返されます:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## アンダースコア変換の無効化 { #disable-convert-underscores }\n\n通常のヘッダーパラメータと同様に、パラメータ名にアンダースコアがある場合は**自動的にハイフンに変換**されます。\n\n例えば、コード上でヘッダーパラメータ `save_data` を定義すると、想定される HTTP ヘッダーは `save-data` となり、ドキュメント上にもそのように表示されます。\n\n何らかの理由でこの自動変換を無効化する必要がある場合、ヘッダーパラメータ用の Pydantic モデルでも無効化できます。\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | 注意\n\n`convert_underscores` を `False` に設定する前に、アンダースコアを含むヘッダーの使用を禁止している HTTP プロキシやサーバーがあることに留意してください。\n\n///\n\n## まとめ { #summary }\n\n**Pydantic モデル**を使って **FastAPI** で **ヘッダー**を宣言できます。😎\n"
  },
  {
    "path": "docs/ja/docs/tutorial/header-params.md",
    "content": "# ヘッダーのパラメータ { #header-parameters }\n\nヘッダーのパラメータは、`Query`や`Path`、`Cookie`のパラメータを定義するのと同じように定義できます。\n\n## `Header`をインポート { #import-header }\n\nまず、`Header`をインポートします:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## `Header`のパラメータの宣言 { #declare-header-parameters }\n\n次に、`Path`や`Query`、`Cookie`と同じ構造を用いてヘッダーのパラメータを宣言します。\n\nデフォルト値に加えて、追加の検証パラメータや注釈パラメータをすべて定義できます:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | 技術詳細\n\n`Header`は`Path`や`Query`、`Cookie`の「姉妹」クラスです。また、同じ共通の`Param`クラスを継承しています。\n\nしかし、`fastapi`から`Query`や`Path`、`Header`などをインポートする場合、それらは実際には特殊なクラスを返す関数であることを覚えておいてください。\n\n///\n\n/// info | 情報\n\nヘッダーを宣言するには、`Header`を使う必要があります。なぜなら、そうしないと、パラメータがクエリのパラメータとして解釈されてしまうからです。\n\n///\n\n## 自動変換 { #automatic-conversion }\n\n`Header`は`Path`や`Query`、`Cookie`が提供する機能に加え、少しだけ追加の機能を持っています。\n\nほとんどの標準ヘッダーは、「マイナス記号」（`-`）としても知られる「ハイフン」文字で区切られています。\n\nしかし、`user-agent`のような変数はPythonでは無効です。\n\nそのため、デフォルトでは、`Header`はパラメータ名の文字をアンダースコア（`_`）からハイフン（`-`）に変換して、ヘッダーを抽出して文書化します。\n\nまた、HTTPヘッダは大文字小文字を区別しないので、Pythonの標準スタイル（別名「スネークケース」）で宣言することができます。\n\nそのため、`User_Agent`などのように最初の文字を大文字にする必要はなく、通常のPythonコードと同じように`user_agent`を使用することができます。\n\nもしなんらかの理由でアンダースコアからハイフンへの自動変換を無効にする必要がある場合は、`Header`のパラメータ`convert_underscores`を`False`に設定してください:\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | 注意\n\n`convert_underscores`を`False`に設定する前に、HTTPプロキシやサーバの中にはアンダースコアを含むヘッダーの使用を許可していないものがあることに注意してください。\n\n///\n\n## ヘッダーの重複 { #duplicate-headers }\n\n受信したヘッダーが重複することがあります。つまり、同じヘッダーで複数の値を持つということです。\n\nこれらの場合、型宣言でリストを使用して定義することができます。\n\n重複したヘッダーのすべての値をPythonの`list`として受け取ることができます。\n\n例えば、複数回出現する可能性のある`X-Token`のヘッダを定義するには、以下のように書くことができます:\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\nその*path operation*と通信する際に、次のように2つのHTTPヘッダーを送信する場合:\n\n```\nX-Token: foo\nX-Token: bar\n```\n\nレスポンスは以下のようになります:\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## まとめ { #recap }\n\nヘッダーは`Header`で宣言し、`Query`や`Path`、`Cookie`と同じ共通パターンを使用します。\n\nまた、変数のアンダースコアを気にする必要はありません。**FastAPI** がそれらの変換をすべて取り持ってくれます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/index.md",
    "content": "# チュートリアル - ユーザーガイド { #tutorial-user-guide }\n\nこのチュートリアルでは、**FastAPI**のほとんどの機能を使う方法を段階的に紹介します。\n\n各セクションは前のセクションを踏まえた内容になっています。しかし、トピックごとに分割されているので、特定のAPIのニーズを満たすために、任意の特定のトピックに直接進めるようになっています。\n\nまた、将来的にリファレンスとして機能するように構築されているので、後で戻ってきて必要なものを正確に確認できます。\n\n## コードを実行する { #run-the-code }\n\nすべてのコードブロックをコピーして直接使用できます（実際にテストされたPythonファイルです）。\n\nいずれかの例を実行するには、コードを `main.py`ファイルにコピーし、次のように `fastapi dev` を起動します:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nコードを記述またはコピーし、編集してローカルで実行することを**強く推奨します**。\n\nエディターで使用することで、書く必要のあるコードの少なさ、すべての型チェック、自動補完など、FastAPIの利点を本当に実感できます。\n\n---\n\n## FastAPIをインストールする { #install-fastapi }\n\n最初のステップは、FastAPIのインストールです。\n\n[仮想環境](../virtual-environments.md) を作成して有効化し、それから **FastAPIをインストール** してください:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | 備考\n\n`pip install \"fastapi[standard]\"` でインストールすると、`fastapi-cloud-cli` を含むいくつかのデフォルトのオプション標準依存関係が付属します。これにより、[FastAPI Cloud](https://fastapicloud.com) にデプロイできます。\n\nこれらのオプション依存関係が不要な場合は、代わりに `pip install fastapi` をインストールできます。\n\n標準依存関係はインストールしたいが `fastapi-cloud-cli` は不要な場合は、`pip install \"fastapi[standard-no-fastapi-cloud-cli]\"` でインストールできます。\n\n///\n\n/// tip | 豆知識\n\nFastAPI には [VS Code の公式拡張機能](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode)（および Cursor）があります。path operation エクスプローラー、path operation 検索、テスト内の CodeLens ナビゲーション（テストから定義へジャンプ）、そして FastAPI Cloud へのデプロイやログなど、さまざまな機能をエディターから利用できます。\n\n///\n\n## 高度なユーザーガイド { #advanced-user-guide }\n\nこの **チュートリアル - ユーザーガイド** の後で、後から読める **高度なユーザーガイド** もあります。\n\n**高度なユーザーガイド** は本チュートリアルをベースにしており、同じ概念を使用し、いくつかの追加機能を教えます。\n\nただし、最初に **チュートリアル - ユーザーガイド**（今読んでいる内容）をお読みください。\n\n**チュートリアル - ユーザーガイド** だけで完全なアプリケーションを構築できるように設計されており、その後ニーズに応じて、**高度なユーザーガイド** の追加のアイデアのいくつかを使って、さまざまな方法で拡張できます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/metadata.md",
    "content": "# メタデータとドキュメントのURL { #metadata-and-docs-urls }\n\n**FastAPI** アプリケーションのいくつかのメタデータ設定をカスタマイズできます。\n\n## APIのメタデータ { #metadata-for-api }\n\nOpenAPI仕様および自動APIドキュメントUIで使用される次のフィールドを設定できます:\n\n| パラメータ | 型 | 説明 |\n|------------|------|-------------|\n| `title` | `str` | APIのタイトルです。 |\n| `summary` | `str` | APIの短い要約です。 <small>OpenAPI 3.1.0、FastAPI 0.99.0 以降で利用できます。</small> |\n| `description` | `str` | APIの短い説明です。Markdownを使用できます。 |\n| `version` | `string` | APIのバージョンです。これはOpenAPIのバージョンではなく、あなた自身のアプリケーションのバージョンです。たとえば `2.5.0` です。 |\n| `terms_of_service` | `str` | APIの利用規約へのURLです。指定する場合、URLである必要があります。 |\n| `contact` | `dict` | 公開されるAPIの連絡先情報です。複数のフィールドを含められます。 <details><summary><code>contact</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>連絡先の個人/組織を識別する名前です。</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>連絡先情報を指すURLです。URL形式である必要があります。</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>連絡先の個人/組織のメールアドレスです。メールアドレス形式である必要があります。</td></tr></tbody></table></details> |\n| `license_info` | `dict` | 公開されるAPIのライセンス情報です。複数のフィールドを含められます。 <details><summary><code>license_info</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>必須</strong>（<code>license_info</code> が設定されている場合）。APIに使用されるライセンス名です。</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>APIの [SPDX](https://spdx.org/licenses/) ライセンス式です。<code>identifier</code> フィールドは <code>url</code> フィールドと同時に指定できません。 <small>OpenAPI 3.1.0、FastAPI 0.99.0 以降で利用できます。</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>APIに使用されるライセンスへのURLです。URL形式である必要があります。</td></tr></tbody></table></details> |\n\n以下のように設定できます:\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | 豆知識\n\n`description` フィールドにはMarkdownを書けて、出力ではレンダリングされます。\n\n///\n\nこの設定では、自動APIドキュメントは以下のようになります:\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## ライセンス識別子 { #license-identifier }\n\nOpenAPI 3.1.0 および FastAPI 0.99.0 以降では、`license_info` を `url` の代わりに `identifier` で設定することもできます。\n\n例:\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## タグのメタデータ { #metadata-for-tags }\n\nパラメータ `openapi_tags` を使うと、path operation をグループ分けするために使用する各タグに追加のメタデータを追加できます。\n\nそれぞれのタグごとに1つの辞書を含むリストを取ります。\n\nそれぞれの辞書は以下を含められます:\n\n* `name` (**必須**): *path operation* および `APIRouter` の `tags` パラメータで使用するのと同じタグ名の `str`。\n* `description`: タグの短い説明の `str`。Markdownを含められ、ドキュメントUIに表示されます。\n* `externalDocs`: 外部ドキュメントを説明する `dict`。以下を含みます:\n    * `description`: 外部ドキュメントの短い説明の `str`。\n    * `url` (**必須**): 外部ドキュメントのURLの `str`。\n\n### タグのメタデータの作成 { #create-metadata-for-tags }\n\n`users` と `items` のタグを使った例で試してみましょう。\n\nタグのメタデータを作成し、それを `openapi_tags` パラメータに渡します:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\n説明の中でMarkdownを使用できることに注意してください。たとえば「login」は太字 (**login**) で表示され、「fancy」は斜体 (_fancy_) で表示されます。\n\n/// tip | 豆知識\n\n使用するすべてのタグにメタデータを追加する必要はありません。\n\n///\n\n### タグの使用 { #use-your-tags }\n\n*path operation*（および `APIRouter`）の `tags` パラメータを使用して、それらを異なるタグに割り当てます:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info | 情報\n\nタグの詳細は [Path Operation の設定](path-operation-configuration.md#tags) を参照してください。\n\n///\n\n### ドキュメントの確認 { #check-the-docs }\n\nここでドキュメントを確認すると、追加したメタデータがすべて表示されます:\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### タグの順番 { #order-of-tags }\n\nタグのメタデータ辞書の順序は、ドキュメントUIに表示される順序の定義にもなります。\n\nたとえば、`users` はアルファベット順では `items` の後に続きますが、リストの最初の辞書としてメタデータを追加したため、それより前に表示されます。\n\n## OpenAPI URL { #openapi-url }\n\nデフォルトでは、OpenAPIスキーマは `/openapi.json` で提供されます。\n\nただし、パラメータ `openapi_url` を使用して設定を変更できます。\n\nたとえば、`/api/v1/openapi.json` で提供されるように設定するには:\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\nOpenAPIスキーマを完全に無効にする場合は、`openapi_url=None` を設定できます。これにより、それを使用するドキュメントUIも無効になります。\n\n## ドキュメントのURL { #docs-urls }\n\n含まれている2つのドキュメントUIを設定できます:\n\n* **Swagger UI**: `/docs` で提供されます。\n    * URL はパラメータ `docs_url` で設定できます。\n    * `docs_url=None` を設定することで無効にできます。\n* **ReDoc**: `/redoc` で提供されます。\n    * URL はパラメータ `redoc_url` で設定できます。\n    * `redoc_url=None` を設定することで無効にできます。\n\nたとえば、`/documentation` でSwagger UIが提供されるように設定し、ReDocを無効にするには:\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/ja/docs/tutorial/middleware.md",
    "content": "# ミドルウェア { #middleware }\n\n**FastAPI** アプリケーションにミドルウェアを追加できます。\n\n「ミドルウェア」は、すべての**リクエスト**に対して、それがあらゆる特定の*path operation*によって処理される前に機能する関数です。また、すべての**レスポンス**に対して、それを返す前に機能します。\n\n* ミドルウェアはアプリケーションに届いたそれぞれの**リクエスト**を受け取ります。\n* その後、その**リクエスト**に対して何かを実行したり、必要なコードを実行したりできます。\n* 次に、アプリケーションの残りの部分に**リクエスト**を渡して (*path operation* によって) 処理させます。\n* 次に、ミドルウェアはアプリケーション (の *path operation*) によって生成された**レスポンス**を受け取ります。\n* その**レスポンス**に対して何かを実行したり、必要なコードを実行したりできます。\n* そして、**レスポンス**を返します。\n\n/// note | 技術詳細\n\n`yield` を使った依存関係をもつ場合は、終了コードはミドルウェアの *後に* 実行されます。\n\nバックグラウンドタスク ([バックグラウンドタスク](background-tasks.md) セクションで説明します。後で確認できます) がある場合は、それらは全てのミドルウェアの *後に* 実行されます。\n\n///\n\n## ミドルウェアの作成 { #create-a-middleware }\n\nミドルウェアを作成するには、関数の上部でデコレータ `@app.middleware(\"http\")` を使用します。\n\nミドルウェア関数は以下を受け取ります:\n\n* `request`。\n* パラメータとして `request` を受け取る関数 `call_next`。\n    * この関数は、対応する*path operation*に `request` を渡します。\n    * 次に、対応する*path operation*によって生成された `response` を返します。\n* その後、`response` を返す前にさらに `response` を変更することもできます。\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip | 豆知識\n\nカスタムの独自ヘッダーは [`X-` プレフィックスを使用](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)して追加できる点に注意してください。\n\nただし、ブラウザのクライアントに表示させたいカスタムヘッダーがある場合は、[CORS (Cross-Origin Resource Sharing)](cors.md) の設定に、[StarletteのCORSドキュメント](https://www.starlette.dev/middleware/#corsmiddleware)に記載されているパラメータ `expose_headers` を使用して、それらを追加する必要があります。\n\n///\n\n/// note | 技術詳細\n\n`from starlette.requests import Request` を使用することもできます。\n\n**FastAPI**は、開発者の便利のためにこれを提供していますが、Starletteから直接きています。\n\n///\n\n### `response` の前後 { #before-and-after-the-response }\n\n*path operation* が `request` を受け取る前に、 `request` とともに実行されるコードを追加できます。\n\nまた `response` が生成された後、それを返す前にも追加できます。\n\n例えば、リクエストの処理とレスポンスの生成にかかった秒数を含むカスタムヘッダー `X-Process-Time` を追加できます:\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip | 豆知識\n\nここでは、これらのユースケースに対してより正確になり得るため、`time.time()` の代わりに [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) を使用しています。 🤓\n\n///\n\n## 複数ミドルウェアの実行順序 { #multiple-middleware-execution-order }\n\n`@app.middleware()` デコレータまたは `app.add_middleware()` メソッドのいずれかを使って複数のミドルウェアを追加すると、新しく追加された各ミドルウェアがアプリケーションをラップし、スタックを形成します。最後に追加されたミドルウェアが *最も外側*、最初に追加されたミドルウェアが *最も内側* になります。\n\nリクエスト経路では、*最も外側* のミドルウェアが最初に実行されます。\n\nレスポンス経路では、最後に実行されます。\n\n例:\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\nこれにより、実行順序は次のようになります:\n\n* **リクエスト**: MiddlewareB → MiddlewareA → route\n\n* **レスポンス**: route → MiddlewareA → MiddlewareB\n\nこのスタック動作により、ミドルウェアが予測可能で制御しやすい順序で実行されることが保証されます。\n\n## その他のミドルウェア { #other-middlewares }\n\n他のミドルウェアの詳細については、[高度なユーザーガイド: 高度なミドルウェア](../advanced/middleware.md)を参照してください。\n\n次のセクションでは、ミドルウェアを使用して <abbr title=\"Cross-Origin Resource Sharing - クロスオリジンリソース共有\">CORS</abbr> を処理する方法について説明します。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/path-operation-configuration.md",
    "content": "# Path Operationの設定 { #path-operation-configuration }\n\n*path operationデコレータ*を設定するためのパラメータがいくつかあります。\n\n/// warning | 注意\n\nこれらのパラメータは*path operationデコレータ*に直接渡され、*path operation関数*に渡されないことに注意してください。\n\n///\n\n## レスポンスステータスコード { #response-status-code }\n\n*path operation*のレスポンスで使用する（HTTP）`status_code`を定義することができます。\n\n`404`のように`int`のコードを直接渡すことができます。\n\nしかし、それぞれの番号コードが何のためのものか覚えていない場合は、`status`のショートカット定数を使用することができます:\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\nそのステータスコードはレスポンスで使用され、OpenAPIスキーマに追加されます。\n\n/// note | 技術詳細\n\n`from starlette import status`を使用することもできます。\n\n**FastAPI** は開発者の利便性を考慮して、`fastapi.status`と同じ`starlette.status`を提供しています。しかし、これはStarletteから直接提供されています。\n\n///\n\n## タグ { #tags }\n\n`tags`パラメータを`str`の`list`（通常は１つの`str`）と一緒に渡すと、*path operation*にタグを追加できます:\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\nこれらはOpenAPIスキーマに追加され、自動ドキュメントのインターフェースで使用されます:\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### Enumを使ったタグ { #tags-with-enums }\n\n大きなアプリケーションの場合、**複数のタグ**が蓄積されていき、関連する*path operations*に対して常に**同じタグ**を使っていることを確認したくなるかもしれません。\n\nこのような場合、タグを`Enum`に格納すると理にかなっています。\n\n**FastAPI** は、プレーンな文字列の場合と同じ方法でそれをサポートしています:\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## 概要と説明 { #summary-and-description }\n\n`summary`と`description`を追加できます:\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## docstringを用いた説明 { #description-from-docstring }\n\n説明文は長くて複数行におよぶ傾向があるので、関数<dfn title=\"関数内の最初の式（どの変数にも代入されない）として記述される、ドキュメント用の複数行の文字列\">docstring</dfn>内に*path operation*の説明文を宣言できます。すると、**FastAPI** は説明文を読み込んでくれます。\n\ndocstringに[Markdown](https://en.wikipedia.org/wiki/Markdown)を記述すれば、正しく解釈されて表示されます。（docstringのインデントを考慮して）\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\nこれは対話的ドキュメントで使用されます:\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## レスポンスの説明 { #response-description }\n\n`response_description`パラメータでレスポンスの説明をすることができます。\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info | 情報\n\n`response_description`は具体的にレスポンスを参照し、`description`は*path operation*全般を参照していることに注意してください。\n\n///\n\n/// check | 確認\n\nOpenAPIは*path operation*ごとにレスポンスの説明を必要としています。\n\nそのため、それを提供しない場合は、**FastAPI** が自動的に「成功のレスポンス」を生成します。\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## *path operation*を非推奨にする { #deprecate-a-path-operation }\n\n*path operation*を<dfn title=\"非推奨、使用しないことを推奨\">deprecated</dfn>としてマークする必要があるが、それを削除しない場合は、`deprecated`パラメータを渡します:\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\n対話的ドキュメントでは非推奨と明記されます:\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\n*path operations*が非推奨である場合とそうでない場合でどのように見えるかを確認してください:\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## まとめ { #recap }\n\n*path operationデコレータ*にパラメータを渡すことで、*path operations*のメタデータを簡単に設定・追加することができます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/path-params-numeric-validations.md",
    "content": "# パスパラメータと数値の検証 { #path-parameters-and-numeric-validations }\n\nクエリパラメータに対して`Query`でより多くのバリデーションとメタデータを宣言できるのと同じように、パスパラメータに対しても`Path`で同じ種類のバリデーションとメタデータを宣言することができます。\n\n## `Path`のインポート { #import-path }\n\nまず初めに、`fastapi`から`Path`をインポートし、`Annotated`もインポートします:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info | 情報\n\nFastAPI はバージョン 0.95.0 で`Annotated`のサポートを追加し（そして推奨し始めました）。\n\n古いバージョンの場合、`Annotated`を使おうとするとエラーになります。\n\n`Annotated`を使用する前に、FastAPI のバージョンを少なくとも 0.95.1 まで[アップグレードしてください](../deployment/versions.md#upgrading-the-fastapi-versions)。\n\n///\n\n## メタデータの宣言 { #declare-metadata }\n\nパラメータは`Query`と同じものを宣言することができます。\n\n例えば、パスパラメータ`item_id`に対して`title`のメタデータを宣言するには以下のようにします:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note | 備考\n\nパスパラメータはパスの一部でなければならないので、常に必須です。`None`で宣言したりデフォルト値を設定したりしても何も影響せず、常に必須のままです。\n\n///\n\n## 必要に応じてパラメータを並び替える { #order-the-parameters-as-you-need }\n\n/// tip | 豆知識\n\n`Annotated`を使う場合、これはおそらくそれほど重要でも必要でもありません。\n\n///\n\nクエリパラメータ`q`を必須の`str`として宣言したいとしましょう。\n\nまた、このパラメータには何も宣言する必要がないので、`Query`を使う必要はありません。\n\nしかし、パスパラメータ`item_id`のために`Path`を使用する必要があります。そして何らかの理由で`Annotated`を使いたくないとします。\n\nPythonは「デフォルト」を持つ値を「デフォルト」を持たない値の前に置くとエラーになります。\n\nしかし、それらを並び替えることができ、デフォルト値を持たない値（クエリパラメータ`q`）を最初に持つことができます。\n\n**FastAPI**では関係ありません。パラメータは名前、型、デフォルトの宣言（`Query`、`Path`など）で検出され、順番は気にしません。\n\nそのため、以下のように関数を宣言することができます:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\nただし、`Annotated`を使う場合はこの問題は起きないことを覚えておいてください。`Query()`や`Path()`に関数パラメータのデフォルト値を使わないためです。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## 必要に応じてパラメータを並び替えるトリック { #order-the-parameters-as-you-need-tricks }\n\n/// tip | 豆知識\n\n`Annotated`を使う場合、これはおそらくそれほど重要でも必要でもありません。\n\n///\n\nこれは**小さなトリック**で、便利な場合がありますが、頻繁に必要になることはありません。\n\n次のことをしたい場合:\n\n* `q`クエリパラメータを`Query`もデフォルト値もなしで宣言する\n* パスパラメータ`item_id`を`Path`を使って宣言する\n* それらを別の順番にする\n* `Annotated`を使わない\n\n...Pythonにはそのための少し特殊な構文があります。\n\n関数の最初のパラメータとして`*`を渡します。\n\nPythonはその`*`で何かをすることはありませんが、それ以降のすべてのパラメータがキーワード引数（キーと値のペア）として呼ばれるべきものであると知っているでしょう。それは<abbr title=\"From: K-ey W-ord Arg-uments - キーワード引数\"><code>kwargs</code></abbr>としても知られています。たとえデフォルト値がなくても。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### `Annotated`のほうがよい { #better-with-annotated }\n\n`Annotated`を使う場合は、関数パラメータのデフォルト値を使わないため、この問題は起きず、おそらく`*`を使う必要もありません。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## 数値の検証: 以上 { #number-validations-greater-than-or-equal }\n\n`Query`と`Path`（、そして後述する他のもの）を用いて、数値の制約を宣言できます。\n\nここで、`ge=1`の場合、`item_id`は`1`「より大きい`g`か、同じ`e`」整数でなければなりません。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## 数値の検証: より大きいと小なりイコール { #number-validations-greater-than-and-less-than-or-equal }\n\n以下も同様です:\n\n* `gt`: `g`reater `t`han\n* `le`: `l`ess than or `e`qual\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## 数値の検証: 浮動小数点、 大なり小なり { #number-validations-floats-greater-than-and-less-than }\n\n数値のバリデーションは`float`の値に対しても有効です。\n\nここで重要になってくるのは<abbr title=\"greater than – より大きい\"><code>gt</code></abbr>だけでなく<abbr title=\"greater than or equal – 以上\"><code>ge</code></abbr>も宣言できることです。これと同様に、例えば、値が`1`より小さくても`0`より大きくなければならないことを要求することができます。\n\nしたがって、`0.5`は有効な値ですが、`0.0`や`0`はそうではありません。\n\nこれは<abbr title=\"less than – より小さい\"><code>lt</code></abbr>も同じです。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## まとめ { #recap }\n\n`Query`と`Path`（そしてまだ見たことない他のもの）では、[クエリパラメータと文字列の検証](query-params-str-validations.md)と同じようにメタデータと文字列の検証を宣言することができます。\n\nまた、数値のバリデーションを宣言することもできます:\n\n* `gt`: `g`reater `t`han\n* `ge`: `g`reater than or `e`qual\n* `lt`: `l`ess `t`han\n* `le`: `l`ess than or `e`qual\n\n/// info | 情報\n\n`Query`、`Path`、および後で見る他のクラスは、共通の`Param`クラスのサブクラスです。\n\nそれらはすべて、これまで見てきた追加のバリデーションとメタデータの同じパラメータを共有しています。\n\n///\n\n/// note | 技術詳細\n\n`fastapi`から`Query`、`Path`などをインポートすると、これらは実際には関数です。\n\n呼び出されると、同じ名前のクラスのインスタンスを返します。\n\nそのため、関数である`Query`をインポートし、それを呼び出すと、`Query`という名前のクラスのインスタンスが返されます。\n\nこれらの関数は（クラスを直接使うのではなく）エディタが型についてエラーとしないようにするために存在します。\n\nこの方法によって、これらのエラーを無視するための設定を追加することなく、通常のエディタやコーディングツールを使用することができます。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/tutorial/path-params.md",
    "content": "# パスパラメータ { #path-parameters }\n\nPythonのformat文字列と同様のシンタックスで「パスパラメータ」や「パス変数」を宣言できます:\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\nパスパラメータ `item_id` の値は、引数 `item_id` として関数に渡されます。\n\nしたがって、この例を実行して [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo) にアクセスすると、次のレスポンスが表示されます。\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## 型付きパスパラメータ { #path-parameters-with-types }\n\n標準のPythonの型アノテーションを使用して、関数内のパスパラメータの型を宣言できます:\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\nここでは、 `item_id` は `int` として宣言されています。\n\n/// check | 確認\n\nこれにより、関数内でのエディターサポート (エラーチェックや補完など) が提供されます。\n\n///\n\n## データ<dfn title=\"別名: シリアライズ、パース、マーシャリング\">変換</dfn> { #data-conversion }\n\nこの例を実行し、ブラウザで [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3) を開くと、次のレスポンスが表示されます:\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check | 確認\n\n関数が受け取った（および返した）値は、文字列の `\"3\"` ではなく、Pythonの `int` としての `3` であることに注意してください。\n\nしたがって、その型宣言を使うと、**FastAPI**は自動リクエスト <dfn title=\"HTTPリクエストから受け取った文字列をPythonのデータに変換する\">\"解析\"</dfn> を行います。\n\n///\n\n## データバリデーション { #data-validation }\n\nしかしブラウザで [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo) を開くと、次のHTTPエラーが表示されます:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\nこれは、パスパラメータ `item_id` が `int` ではない値 `\"foo\"` だからです。\n\n[http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2) で見られるように、`int` のかわりに `float` が与えられた場合にも同様なエラーが表示されます。\n\n/// check | 確認\n\nしたがって、同じPythonの型宣言を使用することで、**FastAPI**はデータのバリデーションを行います。\n\n表示されたエラーには、バリデーションが通らなかった箇所が明確に示されていることに注意してください。\n\nこれは、APIとやり取りするコードを開発・デバッグする際に非常に役立ちます。\n\n///\n\n## ドキュメント { #documentation }\n\nそしてブラウザで [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) を開くと、以下の様な自動的に生成された対話的なAPIドキュメントが表示されます。\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check | 確認\n\n繰り返しになりますが、同じPython型宣言を使用するだけで、**FastAPI**は対話的なドキュメントを自動的に生成します（Swagger UIを統合）。\n\nパスパラメータが整数として宣言されていることに注意してください。\n\n///\n\n## 標準ベースのメリット、ドキュメンテーションの代替物 { #standards-based-benefits-alternative-documentation }\n\nまた、生成されたスキーマが [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md) 標準に従っているので、互換性のあるツールが多数あります。\n\nこのため、**FastAPI**自体が代替のAPIドキュメントを提供します（ReDocを使用）。これは、 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) にアクセスすると確認できます。\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\n同様に、互換性のあるツールが多数あります。多くの言語用のコード生成ツールを含みます。\n\n## Pydantic { #pydantic }\n\nすべてのデータバリデーションは [Pydantic](https://docs.pydantic.dev/) によって内部で実行されるため、Pydanticの全てのメリットが得られます。そして、安心して利用することができます。\n\n`str`、 `float` 、 `bool` および他の多くの複雑なデータ型を型宣言に使用できます。\n\nこれらのいくつかについては、チュートリアルの次の章で説明します。\n\n## 順序の問題 { #order-matters }\n\n*path operations* を作成する際、固定パスをもつ状況があり得ます。\n\n`/users/me` から、現在のユーザに関するデータを取得するとします。\n\nさらに、ユーザIDによって特定のユーザに関する情報を取得するパス  `/users/{user_id}` ももつことができます。\n\n*path operations* は順に評価されるので、 `/users/me` が `/users/{user_id}` よりも先に宣言されているか確認する必要があります:\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\nそれ以外の場合、 `/users/{user_id}` は `/users/me` としてもマッチします。値が `\"me\"` であるパラメータ `user_id` を受け取ると「考え」ます。\n\n同様に、path operation を再定義することはできません:\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\nパスは最初にマッチしたものが常に使われるため、最初のものが常に使用されます。\n\n## 定義済みの値 { #predefined-values }\n\n*パスパラメータ*を受け取る *path operation* をもち、有効な*パスパラメータ*の値を事前に定義したい場合は、標準のPython <abbr title=\"Enumeration - 列挙型\">`Enum`</abbr> を利用できます。\n\n### `Enum` クラスの作成 { #create-an-enum-class }\n\n`Enum` をインポートし、 `str` と `Enum` を継承したサブクラスを作成します。\n\n`str` を継承することで、APIドキュメントは値が `string` 型でなければいけないことを知り、正確にレンダリングできるようになります。\n\nそして、固定値のクラス属性を作ります。すると、その値が使用可能な値となります:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip | 豆知識\n\n\"AlexNet\"、\"ResNet\"そして\"LeNet\"は機械学習<dfn title=\"厳密には、Deep Learning のモデルアーキテクチャ\">モデル</dfn>の名前です。\n\n///\n\n### *パスパラメータ*の宣言 { #declare-a-path-parameter }\n\n次に、作成したenumクラスである`ModelName`を使用した型アノテーションをもつ*パスパラメータ*を作成します:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### ドキュメントの確認 { #check-the-docs }\n\n*パスパラメータ*の利用可能な値が事前に定義されているので、対話的なドキュメントで適切に表示できます:\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### Python*列挙型*の利用 { #working-with-python-enumerations }\n\n*パスパラメータ*の値は*列挙型メンバ*となります。\n\n#### *列挙型メンバ*の比較 { #compare-enumeration-members }\n\nこれは、作成した列挙型 `ModelName` の*列挙型メンバ*と比較できます:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### *列挙値*の取得 { #get-the-enumeration-value }\n\n`model_name.value` 、もしくは一般に、 `your_enum_member.value` を使用して実際の値 (この場合は `str`) を取得できます。\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip | 豆知識\n\n`ModelName.lenet.value` でも `\"lenet\"` 値にアクセスできます。\n\n///\n\n#### *列挙型メンバ*の返却 { #return-enumeration-members }\n\n*path operation* から*列挙型メンバ*を返すことができます。JSONボディ（例: `dict`）でネストすることもできます。\n\nそれらはクライアントに返される前に適切な値 (この場合は文字列) に変換されます。\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\nクライアントは以下の様なJSONレスポンスを得ます:\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## パスを含んだパスパラメータ { #path-parameters-containing-paths }\n\nパス `/files/{file_path}` となる *path operation* を持っているとしましょう。\n\nただし、 `home/johndoe/myfile.txt` のような*パス*を含んだ `file_path` が必要です。\n\nしたがって、そのファイルのURLは `/files/home/johndoe/myfile.txt` の様になります。\n\n### OpenAPIサポート { #openapi-support }\n\nOpenAPIはテストや定義が困難なシナリオにつながる可能性があるため、内部に*パス*を含む*パスパラメータ*の宣言をサポートしていません。\n\nそれにも関わらず、Starletteの内部ツールのひとつを使用することで、**FastAPI**はそれが実現できます。\n\nそして、パラメータがパスを含むべきであることを示すドキュメントを追加しなくても、ドキュメントは動作します。\n\n### パスコンバーター { #path-convertor }\n\nStarletteのオプションを直接使用することで、以下のURLの様な*パス*を含んだ、*パスパラメータ*の宣言ができます:\n\n```\n/files/{file_path:path}\n```\n\nこの場合、パラメータ名は `file_path` です。そして、最後の部分 `:path` はパラメータがいかなる*パス*にもマッチすることを示します。\n\nしたがって、以下の様に使用できます:\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip | 豆知識\n\n最初のスラッシュ (`/`)が付いている `/home/johndoe/myfile.txt` をパラメータが含んでいる必要があるかもしれません。\n\nこの場合、URLは `files` と `home` の間にダブルスラッシュ (`//`) のある、 `/files//home/johndoe/myfile.txt` になります。\n\n///\n\n## まとめ { #recap }\n\n簡潔で、本質的で、標準的なPythonの型宣言を使用することで、**FastAPI**は以下を行います:\n\n* エディターサポート: エラーチェック、自動補完、など\n* データ「<dfn title=\"HTTPリクエストから受け取った文字列をPythonのデータに変換する\">解析</dfn>」\n* データバリデーション\n* APIアノテーションと自動ドキュメント生成\n\nそしてこれはたった一度宣言するだけです。\n\nこれは恐らく、(パフォーマンスを除いて) 他のフレームワークと比較したときの、**FastAPI**の主な目に見える利点です。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/query-param-models.md",
    "content": "# クエリパラメータモデル { #query-parameter-models }\n\nもし関連する**複数のクエリパラメータ**から成るグループがあるなら、それらを宣言するために、**Pydanticモデル**を作成できます。\n\nこうすることで、**複数の場所**で**そのモデルを再利用**でき、バリデーションやメタデータを、すべてのパラメータに対して一度に宣言できます。😎\n\n/// note | 備考\n\nこの機能は、FastAPIのバージョン `0.115.0` からサポートされています。🤓\n\n///\n\n## Pydanticモデルを使ったクエリパラメータ { #query-parameters-with-a-pydantic-model }\n\n必要な**クエリパラメータ**を**Pydanticモデル**で宣言し、さらに、そのパラメータを `Query` として宣言しましょう:\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\n**FastAPI**は、リクエストの**クエリパラメータ**からそれぞれの**フィールド**のデータを**抽出**し、定義したPydanticモデルを提供します。\n\n## ドキュメントの確認 { #check-the-docs }\n\n対話的APIドキュメント `/docs` でクエリパラメータを確認できます:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## 余分なクエリパラメータを禁止する { #forbid-extra-query-parameters }\n\n特定の（あまり一般的ではないかもしれない）ユースケースで、受け取りたいクエリパラメータを**制限**したい場合があります。\n\nPydanticのモデル設定を使って、あらゆる `extra` フィールドを `forbid` にできます。\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\nもしクライアントが**クエリパラメータ**として**余分な**データを送ろうとすると、**エラー**レスポンスが返されます。\n\n例えば、クライアントがクエリパラメータ `tool` に、値 `plumbus` を設定して送ろうとすると:\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\nクエリパラメータ `tool` が許可されていないことを伝える**エラー**レスポンスが返されます。\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## まとめ { #summary }\n\n**FastAPI**では、**クエリパラメータ**を宣言するために、**Pydanticモデル**を使用できます。😎\n\n/// tip | 豆知識\n\nネタバレ注意: Pydanticモデルはクッキーやヘッダーの宣言にも使用できますが、その内容については後のチュートリアルで学びます。🤫\n\n///\n"
  },
  {
    "path": "docs/ja/docs/tutorial/query-params-str-validations.md",
    "content": "# クエリパラメータと文字列の検証 { #query-parameters-and-string-validations }\n\n**FastAPI** ではパラメータの追加情報とバリデーションを宣言することができます。\n\n以下のアプリケーションを例にしてみましょう:\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\nクエリパラメータ `q` は `str | None` 型で、`str` 型ですが `None` にもなり得ることを意味し、実際にデフォルト値は `None` なので、FastAPIはそれが必須ではないと理解します。\n\n/// note | 備考\n\nFastAPIは、 `q` はデフォルト値が `= None` であるため、必須ではないと理解します。\n\n`str | None` を使うことで、エディターによるより良いサポートとエラー検出を可能にします。\n\n///\n\n## バリデーションの追加 { #additional-validation }\n\n`q`はオプショナルですが、もし値が渡されてきた場合には、**長さが50文字を超えないこと**を強制してみましょう。\n\n### `Query` と `Annotated` のインポート { #import-query-and-annotated }\n\nそのために、まずは以下をインポートします:\n\n* `fastapi` から `Query`\n* `typing` から `Annotated`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info | 情報\n\nFastAPI はバージョン 0.95.0 で `Annotated` のサポートを追加し（推奨し始め）ました。\n\n古いバージョンの場合、`Annotated` を使おうとするとエラーになります。\n\n`Annotated` を使う前に、FastAPI のバージョンを少なくとも 0.95.1 にするために、[FastAPI のバージョンをアップグレード](../deployment/versions.md#upgrading-the-fastapi-versions)してください。\n\n///\n\n## `q` パラメータの型で `Annotated` を使う { #use-annotated-in-the-type-for-the-q-parameter }\n\n以前、[Python Types Intro](../python-types.md#type-hints-with-metadata-annotations) で `Annotated` を使ってパラメータにメタデータを追加できると説明したことを覚えていますか？\n\nいよいよ FastAPI で使うときです。 🚀\n\n次の型アノテーションがありました:\n\n```Python\nq: str | None = None\n```\n\nこれを `Annotated` で包んで、次のようにします:\n\n```Python\nq: Annotated[str | None] = None\n```\n\nどちらも同じ意味で、`q` は `str` または `None` になり得るパラメータで、デフォルトでは `None` です。\n\nでは、面白いところに進みましょう。 🎉\n\n## `q` パラメータの `Annotated` に `Query` を追加する { #add-query-to-annotated-in-the-q-parameter }\n\n追加情報（この場合は追加のバリデーション）を入れられる `Annotated` ができたので、`Annotated` の中に `Query` を追加し、パラメータ `max_length` を `50` に設定します:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\nデフォルト値は引き続き `None` なので、このパラメータは依然としてオプショナルです。\n\nしかし、`Annotated` の中に `Query(max_length=50)` を入れることで、この値に **追加のバリデーション** をしたい、最大 50 文字にしたい、と FastAPI に伝えています。 😎\n\n/// tip | 豆知識\n\nここでは **クエリパラメータ** なので `Query()` を使っています。後で `Path()`、`Body()`、`Header()`、`Cookie()` など、`Query()` と同じ引数を受け取れるものも見ていきます。\n\n///\n\nFastAPI は次を行います:\n\n* 最大長が 50 文字であることを確かめるようデータを **検証** する\n* データが有効でないときに、クライアントに **明確なエラー** を表示する\n* OpenAPI スキーマの *path operation* にパラメータを **ドキュメント化** する（その結果、**自動ドキュメント UI** に表示されます）\n\n## 代替（古い方法）: デフォルト値としての `Query` { #alternative-old-query-as-the-default-value }\n\nFastAPI の以前のバージョン（<dfn title=\"2023-03 より前\">0.95.0</dfn> より前）では、パラメータのデフォルト値として `Query` を使う必要があり、`Annotated` の中に入れるのではありませんでした。これを使ったコードを見かける可能性が高いので、説明します。\n\n/// tip | 豆知識\n\n新しいコードでは、可能な限り上で説明したとおり `Annotated` を使ってください。複数の利点（後述）があり、欠点はありません。 🍰\n\n///\n\n関数パラメータのデフォルト値として `Query()` を使い、パラメータ `max_length` を 50 に設定する方法は次のとおりです:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\nこの場合（`Annotated` を使わない場合）、関数内のデフォルト値 `None` を `Query()` に置き換える必要があるため、`Query(default=None)` のパラメータでデフォルト値を設定する必要があります。これは（少なくとも FastAPI にとっては）そのデフォルト値を定義するのと同じ目的を果たします。\n\nなので:\n\n```Python\nq: str | None = Query(default=None)\n```\n\n...はデフォルト値 `None` を持つオプショナルなパラメータになり、以下と同じです:\n\n\n```Python\nq: str | None = None\n```\n\nただし `Query` のバージョンでは、クエリパラメータであることを明示的に宣言しています。\n\nそして、さらに多くのパラメータを`Query`に渡すことができます。この場合、文字列に適用される、`max_length`パラメータを指定します。\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\nこれにより、データを検証し、データが有効でない場合は明確なエラーを表示し、OpenAPIスキーマの　*path operation* にパラメータを記載します。\n\n### デフォルト値としての `Query` または `Annotated` 内の `Query` { #query-as-the-default-value-or-in-annotated }\n\n`Annotated` の中で `Query` を使う場合、`Query` の `default` パラメータは使えないことに注意してください。\n\nその代わりに、関数パラメータの実際のデフォルト値を使います。そうしないと整合性が取れなくなります。\n\n例えば、これは許可されません:\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n...なぜなら、デフォルト値が `\"rick\"` なのか `\"morty\"` なのかが不明確だからです。\n\nそのため、（できれば）次のようにします:\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n...または、古いコードベースでは次のようなものが見つかるでしょう:\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### `Annotated` の利点 { #advantages-of-annotated }\n\n関数パラメータのデフォルト値スタイルではなく、**`Annotated` を使うことが推奨** されます。複数の理由で **より良い** からです。 🤓\n\n**関数パラメータ** の **デフォルト値** は **実際のデフォルト値** であり、Python 全般としてより直感的です。 😌\n\nFastAPI なしで同じ関数を **別の場所** から **呼び出しても**、**期待どおりに動作** します。**必須** パラメータ（デフォルト値がない）があれば、**エディター** がエラーで知らせてくれますし、**Python** も必須パラメータを渡さずに実行すると文句を言います。\n\n`Annotated` を使わずに **（古い）デフォルト値スタイル** を使う場合、FastAPI なしでその関数を **別の場所** で呼び出すとき、正しく動かすために関数へ引数を渡すことを **覚えておく** 必要があります。そうしないと値が期待と異なります（例えば `str` の代わりに `QueryInfo` か、それに類するものになります）。また、エディターも警告せず、Python もその関数の実行で文句を言いません。内部の処理がエラーになるときに初めて問題が出ます。\n\n`Annotated` は複数のメタデータアノテーションを持てるので、[Typer](https://typer.tiangolo.com/) のような別ツールと同じ関数を使うこともできます。 🚀\n\n## バリデーションをさらに追加する { #add-more-validations }\n\nパラメータ`min_length`も追加することができます:\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## 正規表現の追加 { #add-regular-expressions }\n\nパラメータが一致するべき <dfn title=\"正規表現、regex、regexp は、文字列に対する検索パターンを定義する文字の並びです。\">正規表現</dfn> `pattern` を定義することができます:\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\nこの特定の正規表現パターンは受け取ったパラメータの値をチェックします:\n\n* `^`: は、これ以降の文字で始まり、これより以前には文字はありません。\n* `fixedquery`: は、正確な`fixedquery`を持っています.\n* `$`: で終わる場合、`fixedquery`以降には文字はありません.\n\nもしこれらすべての **「正規表現」** のアイデアについて迷っていても、心配しないでください。多くの人にとって難しい話題です。正規表現を必要としなくても、まだ、多くのことができます。\n\nこれで、必要になったときにはいつでも **FastAPI** で使えることが分かりました。\n\n## デフォルト値 { #default-values }\n\nもちろん、`None` 以外のデフォルト値も使えます。\n\nクエリパラメータ `q` の `min_length` を `3` とし、デフォルト値を `\"fixedquery\"` として宣言したいとします:\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | 備考\n\n`None` を含む任意の型のデフォルト値があると、パラメータはオプショナル（必須ではない）になります。\n\n///\n\n## 必須パラメータ { #required-parameters }\n\nこれ以上、バリデーションやメタデータを宣言する必要がない場合は、デフォルト値を宣言しないだけでクエリパラメータ `q` を必須にできます。以下のように:\n\n```Python\nq: str\n```\n\n以下の代わりに:\n\n```Python\nq: str | None = None\n```\n\nしかし今は、例えば次のように `Query` で宣言しています:\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\nそのため、`Query` を使いながら値を必須として宣言したい場合は、単にデフォルト値を宣言しません:\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### 必須、`None` にできる { #required-can-be-none }\n\nパラメータが `None` を受け付けるが、それでも必須である、と宣言できます。これにより、値が `None` であってもクライアントは値を送らなければならなくなります。\n\nそのために、`None` が有効な型であることを宣言しつつ、単にデフォルト値を宣言しません:\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## クエリパラメータのリスト / 複数の値 { #query-parameter-list-multiple-values }\n\nクエリパラメータを明示的に `Query` で定義すると、値のリストを受け取るように宣言したり、言い換えると複数の値を受け取るように宣言したりすることもできます。\n\n例えば、URL内に複数回出現するクエリパラメータ`q`を宣言するには以下のように書きます:\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\nそして、次のような URL なら:\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\n*path operation function* 内の *function parameter* `q` で、複数の `q` *query parameters'* 値（`foo` と `bar`）を Python の `list` として受け取ります。\n\nそのため、このURLのレスポンスは以下のようになります:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | 豆知識\n\n上述の例のように、`list`型のクエリパラメータを宣言するには明示的に`Query`を使用する必要があります。そうしない場合、リクエストボディと解釈されます。\n\n///\n\n対話的APIドキュメントは複数の値を許可するために自動的に更新されます。\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### デフォルト値を持つ、クエリパラメータのリスト / 複数の値 { #query-parameter-list-multiple-values-with-defaults }\n\nまた、値が指定されていない場合はデフォルトの `list` を定義することもできます。\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\n以下にアクセスすると:\n\n```\nhttp://localhost:8000/items/\n```\n\n`q`のデフォルトは: `[\"foo\", \"bar\"]` となり、レスポンスは以下のようになります:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### `list` だけを使う { #using-just-list }\n\n`list[str]` の代わりに直接 `list` を使うこともできます:\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | 備考\n\nこの場合、FastAPIはリストの内容をチェックしないことを覚えておいてください。\n\n例えば`list[int]`はリストの内容が整数であるかどうかをチェックします(そして、文書化します)。しかし`list`だけではそうしません。\n\n///\n\n## より多くのメタデータを宣言する { #declare-more-metadata }\n\nパラメータに関する情報をさらに追加することができます。\n\nその情報は、生成されたOpenAPIに含まれ、ドキュメントのユーザーインターフェースや外部のツールで使用されます。\n\n/// note | 備考\n\nツールによってOpenAPIのサポートのレベルが異なる可能性があることを覚えておいてください。\n\nその中には、宣言されたすべての追加情報が表示されていないものもあるかもしれませんが、ほとんどの場合、不足している機能はすでに開発の計画がされています。\n\n///\n\n`title`を追加できます:\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\n`description`を追加できます:\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## エイリアスパラメータ { #alias-parameters }\n\nパラメータに`item-query`を指定するとします.\n\n以下のような感じです:\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\nしかし、`item-query`は有効なPythonの変数名ではありません。\n\n最も近いのは`item_query`でしょう。\n\nしかし、どうしても`item-query`と正確に一致している必要があるとします...\n\nそれならば、`alias`を宣言することができます。エイリアスはパラメータの値を見つけるのに使用されます:\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## パラメータを非推奨にする { #deprecating-parameters }\n\nさて、このパラメータが気に入らなくなったとしましょう。\n\nそれを使っているクライアントがいるので、しばらくは残しておく必要がありますが、ドキュメントには<dfn title=\"廃止予定、使用は推奨されません\">廃止予定</dfn>と明記しておきたいです。\n\nその場合、`Query`にパラメータ`deprecated=True`を渡します:\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\nドキュメントは以下のようになります:\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## OpenAPI からパラメータを除外する { #exclude-parameters-from-openapi }\n\n生成される OpenAPI スキーマ（つまり自動ドキュメントシステム）からクエリパラメータを除外するには、`Query` のパラメータ `include_in_schema` を `False` に設定します:\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## カスタムバリデーション { #custom-validation }\n\n上で示したパラメータではできない **カスタムバリデーション** が必要になる場合があります。\n\nその場合、通常のバリデーション（例: 値が `str` であることの検証）の後に適用される **カスタムバリデータ関数** を使えます。\n\nこれを行うには、`Annotated` の中で [Pydantic の `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) を使います。\n\n/// tip | 豆知識\n\nPydantic には [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) などもあります。 🤓\n\n///\n\n例えば、このカスタムバリデータは、<abbr title=\"International Standard Book Number - 国際標準図書番号\">ISBN</abbr> の書籍番号なら item ID が `isbn-` で始まること、<abbr title=\"Internet Movie Database - インターネット・ムービー・データベース: 映画に関する情報を掲載する Web サイト\">IMDB</abbr> の movie URL ID なら `imdb-` で始まることをチェックします:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info | 情報\n\nこれは Pydantic バージョン 2 以上で利用できます。 😎\n\n///\n\n/// tip | 豆知識\n\nデータベースや別の API など、何らかの **外部コンポーネント** との通信が必要なタイプのバリデーションを行う必要がある場合は、代わりに **FastAPI Dependencies** を使うべきです。これについては後で学びます。\n\nこれらのカスタムバリデータは、リクエストで提供された **同じデータのみ** でチェックできるもの向けです。\n\n///\n\n### そのコードを理解する { #understand-that-code }\n\n重要なのは、**`Annotated` の中で関数と一緒に `AfterValidator` を使うこと** だけです。この部分は飛ばしても構いません。 🤸\n\n---\n\nただし、この具体的なコード例が気になっていて、まだ興味が続くなら、追加の詳細を示します。\n\n#### `value.startswith()` を使う文字列 { #string-with-value-startswith }\n\n気づきましたか？`value.startswith()` を使う文字列はタプルを受け取れ、そのタプル内の各値をチェックします:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### ランダムなアイテム { #a-random-item }\n\n`data.items()` で、辞書の各アイテムのキーと値を含むタプルを持つ <dfn title=\"for ループで繰り返し処理できるもの（list、set など）\">反復可能オブジェクト</dfn> を取得します。\n\nこの反復可能オブジェクトを `list(data.items())` で適切な `list` に変換します。\n\nそして `random.choice()` でその `list` から **ランダムな値** を取得するので、`(id, name)` のタプルを得ます。これは `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")` のようになります。\n\n次に、そのタプルの **2つの値を代入** して、変数 `id` と `name` に入れます。\n\nつまり、ユーザーが item ID を提供しなかった場合でも、ランダムな提案を受け取ります。\n\n...これを **単一のシンプルな1行** で行っています。 🤯 Python が好きになりませんか？ 🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## まとめ { #recap }\n\nパラメータに追加のバリデーションとメタデータを宣言することができます。\n\n一般的なバリデーションとメタデータ:\n\n* `alias`\n* `title`\n* `description`\n* `deprecated`\n\n文字列に固有のバリデーション:\n\n* `min_length`\n* `max_length`\n* `pattern`\n\n`AfterValidator` を使ったカスタムバリデーション。\n\nこの例では、`str` の値のバリデーションを宣言する方法を見てきました。\n\n数値のような他の型のバリデーションを宣言する方法は次の章を参照してください。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/query-params.md",
    "content": "# クエリパラメータ { #query-parameters }\n\nパスパラメータではない関数パラメータを宣言すると、それらは自動的に「クエリ」パラメータとして解釈されます。\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\nクエリはURL内で `?` の後に続くキーとバリューの組で、 `&` で区切られています。\n\n例えば、以下の様なURL内で:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n...クエリパラメータは:\n\n* `skip`: 値は `0`\n* `limit`: 値は `10`\n\nこれらはURLの一部なので、「自然に」文字列になります。\n\nしかしPythonの型を宣言すると (上記の例では `int` として)、その型に変換されバリデーションが行われます。\n\nパスパラメータに適用される処理と完全に同様な処理がクエリパラメータにも施されます:\n\n* エディターサポート (明らかに)\n* データ <dfn title=\"HTTP リクエストから来る文字列を Python のデータに変換すること\">「解析」</dfn>\n* データバリデーション\n* 自動ドキュメント生成\n\n## デフォルト { #defaults }\n\nクエリパラメータはパスの固定部分ではないので、オプショナルとしたり、デフォルト値をもつことができます。\n\n上述の例では、`skip=0` と `limit=10` というデフォルト値を持っています。\n\nしたがって、以下のURLにアクセスすることは:\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\n以下のURLにアクセスすることと同等になります:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\nしかし、例えば、以下にアクセスすると:\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\n関数内のパラメータの値は以下の様になります:\n\n* `skip=20`: URL内にセットしたため\n* `limit=10`: デフォルト値だったため\n\n## オプショナルなパラメータ { #optional-parameters }\n\n同様に、デフォルト値を `None` とすることで、オプショナルなクエリパラメータを宣言できます:\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\nこの場合、関数パラメータ `q` はオプショナルとなり、デフォルトでは `None` になります。\n\n/// check | 確認\n\nパスパラメータ `item_id` はパスパラメータであり、`q` はそれとは違ってクエリパラメータであると判別できるほど**FastAPI** が賢いということにも注意してください。\n\n///\n\n## クエリパラメータの型変換 { #query-parameter-type-conversion }\n\n`bool` 型も宣言でき、変換されます:\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\nこの場合、以下にアクセスすると:\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\nもしくは、\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\nもしくは、\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\nもしくは、\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\nもしくは、\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\nもしくは、他の大文字小文字のバリエーション (アッパーケース、最初の文字だけアッパーケース、など)で、関数は `short` パラメータを `True` な `bool` 値として扱います。それ以外は `False` になります。\n\n\n## 複数のパスパラメータとクエリパラメータ { #multiple-path-and-query-parameters }\n\n複数のパスパラメータとクエリパラメータを同時に宣言できます。**FastAPI**はどれがどれかを把握しています。\n\nそして特定の順序で宣言しなくてもよいです。\n\n名前で判別されます:\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## 必須のクエリパラメータ { #required-query-parameters }\n\nパスパラメータ以外のパラメータ (今のところ、クエリパラメータのみ見てきました) のデフォルト値を宣言した場合、そのパラメータは必須ではなくなります。\n\n特定の値を与えずにただオプショナルにしたい場合はデフォルト値を `None` にして下さい。\n\nしかしクエリパラメータを必須にしたい場合は、ただデフォルト値を宣言しなければよいです:\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\nここで、クエリパラメータ `needy` は `str` 型の必須のクエリパラメータです。\n\n以下のURLをブラウザで開くと:\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n...必須のパラメータ `needy` を加えなかったので、以下の様なエラーが表示されます:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\n`needy` は必須のパラメータなので、URLにセットする必要があります:\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n...これはうまくいくでしょう:\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\nそして当然、あるパラメータを必須に、あるパラメータにデフォルト値を設定し、またあるパラメータを完全にオプショナルにできます:\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\nこの場合、3つのクエリパラメータがあります。:\n\n* `needy`、必須の `str` 。\n* `skip`、デフォルト値を `0` とする `int` 。\n* `limit`、オプショナルな `int` 。\n\n/// tip | 豆知識\n\n[パスパラメータ](path-params.md#predefined-values)と同様に `Enum` を使用できます。\n\n///\n"
  },
  {
    "path": "docs/ja/docs/tutorial/request-files.md",
    "content": "# リクエストファイル { #request-files }\n\n`File` を使って、クライアントがアップロードするファイルを定義できます。\n\n/// info | 情報\n\nアップロードされたファイルを受け取るには、まず [`python-multipart`](https://github.com/Kludex/python-multipart) をインストールします。\n\n[仮想環境](../virtual-environments.md)を作成して有効化し、次のようにインストールしてください:\n\n```console\n$ pip install python-multipart\n```\n\nアップロードされたファイルは「form data」として送信されるためです。\n\n///\n\n## `File` をインポート { #import-file }\n\n`fastapi` から `File` と `UploadFile` をインポートします:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## `File` パラメータの定義 { #define-file-parameters }\n\n`Body` や `Form` と同様の方法でファイルのパラメータを作成します:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info | 情報\n\n`File` は `Form` を直接継承したクラスです。\n\nただし、`fastapi` から `Query`、`Path`、`File` などをインポートするとき、それらは実際には特殊なクラスを返す関数であることに注意してください。\n\n///\n\n/// tip | 豆知識\n\nファイルのボディを宣言するには `File` を使う必要があります。そうしないと、パラメータはクエリパラメータやボディ（JSON）パラメータとして解釈されます。\n\n///\n\nファイルは「form data」としてアップロードされます。\n\n*path operation 関数* のパラメータの型を `bytes` として宣言すると、**FastAPI** がファイルを読み取り、内容を `bytes` として受け取ります。\n\nこれは内容全体がメモリに保持されることを意味します。小さなファイルには有効です。\n\nしかし、多くの場合は `UploadFile` を使う方が有利です。\n\n## `UploadFile` によるファイルパラメータ { #file-parameters-with-uploadfile }\n\n型を `UploadFile` にしてファイルパラメータを定義します:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\n`UploadFile` を使うことには `bytes` に対する次の利点があります:\n\n- パラメータのデフォルト値に `File()` を使う必要がありません。\n- 「spooled」ファイルを使います:\n    - 最大サイズまではメモリに保持し、それを超えるとディスクに格納されるファイルです。\n- そのため、画像・動画・大きなバイナリなどの大きなファイルでも、メモリを使い果たすことなくうまく動作します。\n- アップロードされたファイルからメタデータを取得できます。\n- [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) な `async` インターフェースを持ちます。\n- 実際の Python の [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) オブジェクトを公開しており、file-like オブジェクトを期待する他のライブラリにそのまま渡せます。\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` には次の属性があります:\n\n- `filename`: アップロード時の元のファイル名を表す `str`（例: `myimage.jpg`）\n- `content_type`: コンテントタイプ（MIME タイプ / メディアタイプ）を表す `str`（例: `image/jpeg`）\n- `file`: [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile)（[file-like](https://docs.python.org/3/glossary.html#term-file-like-object) なオブジェクト）。これは実際の Python のファイルオブジェクトで、「file-like」オブジェクトを期待する関数やライブラリに直接渡せます。\n\n`UploadFile` には次の `async` メソッドがあります。いずれも内部で対応するファイルメソッド（内部の `SpooledTemporaryFile`）を呼び出します。\n\n- `write(data)`: `data`（`str` または `bytes`）を書き込みます。\n- `read(size)`: `size`（`int`）バイト/文字を読み込みます。\n- `seek(offset)`: ファイル内のバイト位置 `offset`（`int`）に移動します。\n    - 例: `await myfile.seek(0)` はファイルの先頭に移動します。\n    - 一度 `await myfile.read()` を実行して、もう一度内容を読みたい場合に特に便利です。\n- `close()`: ファイルを閉じます。\n\nこれらはすべて `async` メソッドなので、`await` する必要があります。\n\n例えば、`async` の *path operation 関数* 内では次のように内容を取得できます:\n\n```Python\ncontents = await myfile.read()\n```\n\n通常の `def` の *path operation 関数* 内にいる場合は、`UploadFile.file` に直接アクセスできます。例えば:\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | `async` の技術詳細\n\n`async` メソッドを使うと、**FastAPI** はファイルメソッドをスレッドプールで実行し、その完了を待機します。\n\n///\n\n/// note | Starlette の技術詳細\n\n**FastAPI** の `UploadFile` は **Starlette** の `UploadFile` を直接継承していますが、**Pydantic** や FastAPI の他の部分と互換にするために必要な要素を追加しています。\n\n///\n\n## 「Form Data」とは { #what-is-form-data }\n\nHTML フォーム（`<form></form>`）がサーバーにデータを送る方法は、そのデータに対して通常「特別な」エンコーディングを用い、JSON とは異なります。\n\n**FastAPI** は JSON ではなく、適切な場所からそのデータを読み取るようにします。\n\n/// note | 技術詳細\n\nファイルを含まない場合、フォームからのデータは通常「メディアタイプ」`application/x-www-form-urlencoded` でエンコードされます。\n\nただしフォームにファイルが含まれる場合は、`multipart/form-data` としてエンコードされます。`File` を使うと、**FastAPI** はボディ内の正しい部分からファイルを取得すべきであると認識します。\n\nこれらのエンコーディングやフォームフィールドの詳細は、[<abbr title=\"Mozilla Developer Network - Mozilla 開発者ネットワーク\">MDN</abbr> Web Docs の `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) を参照してください。\n\n///\n\n/// warning | 注意\n\n1 つの *path operation* に複数の `File` および `Form` パラメータを宣言できますが、同時に JSON として受け取ることを期待する `Body` フィールドを宣言することはできません。リクエストのボディは `application/json` ではなく `multipart/form-data` でエンコードされるためです。\n\nこれは **FastAPI** の制限ではなく、HTTP プロトコルの仕様です。\n\n///\n\n## 任意のファイルアップロード { #optional-file-upload }\n\n標準の型アノテーションを使い、デフォルト値を `None` に設定することで、ファイルを任意にできます:\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## 追加メタデータつきの `UploadFile` { #uploadfile-with-additional-metadata }\n\n例えば追加のメタデータを設定するために、`UploadFile` と併せて `File()` を使うこともできます:\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## 複数ファイルのアップロード { #multiple-file-uploads }\n\n同時に複数のファイルをアップロードできます。\n\nそれらは「form data」で送信される同じ「フォームフィールド」に関連付けられます。\n\nそのためには、`bytes` または `UploadFile` のリストを宣言します:\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\n宣言どおり、`bytes` または `UploadFile` の `list` を受け取ります。\n\n/// note | 技術詳細\n\n`from starlette.responses import HTMLResponse` を使うこともできます。\n\n**FastAPI** は利便性のため、`starlette.responses` と同じものを `fastapi.responses` として提供しています。ただし、利用可能なレスポンスの多くは Starlette から直接提供されています。\n\n///\n\n### 追加メタデータつきの複数ファイルアップロード { #multiple-file-uploads-with-additional-metadata }\n\n先ほどと同様に、`UploadFile` に対しても `File()` を使って追加のパラメータを設定できます:\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## まとめ { #recap }\n\nリクエストでフォームデータとして送信されるアップロードファイルを宣言するには、`File`、`bytes`、`UploadFile` を使います。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/request-form-models.md",
    "content": "# フォームモデル { #form-models }\n\nFastAPI では、フォームフィールドを宣言するために **Pydantic モデル**を使用できます。\n\n/// info | 情報\n\nフォームを使うには、まず [`python-multipart`](https://github.com/Kludex/python-multipart) をインストールします。\n\nまず [仮想環境](../virtual-environments.md) を作成して有効化し、そのうえでインストールしてください。例えば:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note | 備考\n\nこれは FastAPI バージョン `0.113.0` 以降でサポートされています。🤓\n\n///\n\n## フォーム用の Pydantic モデル { #pydantic-models-for-forms }\n\n受け取りたいフィールドを **フォームフィールド** として持つ **Pydantic モデル** を宣言し、パラメータを `Form` として宣言するだけです:\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI** はリクエストの **フォームデータ** から **各フィールド** のデータを **抽出** し、定義した Pydantic モデルとして渡します。\n\n## ドキュメントで確認 { #check-the-docs }\n\n`/docs` のドキュメント UI で確認できます:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## 追加のフォームフィールドを禁止 { #forbid-extra-form-fields }\n\n一部の特殊なユースケース（おそらくあまり一般的ではありません）では、フォームフィールドを Pydantic モデルで宣言したもののみに**制限**し、**追加**のフィールドを**禁止**したい場合があります。\n\n/// note | 備考\n\nこれは FastAPI バージョン `0.114.0` 以降でサポートされています。🤓\n\n///\n\nPydantic のモデル設定で、`extra` フィールドを `forbid` にできます:\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\nクライアントが余分なデータを送信しようとすると、**エラー**のレスポンスを受け取ります。\n\n例えば、クライアントが次のフォームフィールドを送ろうとした場合:\n\n- `username`: `Rick`\n- `password`: `Portal Gun`\n- `extra`: `Mr. Poopybutthole`\n\nフィールド `extra` は許可されていない旨のエラーレスポンスが返されます:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## まとめ { #summary }\n\nFastAPI でフォームフィールドを宣言するために Pydantic モデルを使用できます。😎\n"
  },
  {
    "path": "docs/ja/docs/tutorial/request-forms-and-files.md",
    "content": "# リクエストフォームとファイル { #request-forms-and-files }\n\n`File`と`Form`を同時に使うことでファイルとフォームフィールドを定義することができます。\n\n/// info | 情報\n\nアップロードされたファイルやフォームデータを受信するには、まず[`python-multipart`](https://github.com/Kludex/python-multipart)をインストールします。\n\n[仮想環境](../virtual-environments.md)を作成し、それを有効化してから、例えば次のようにインストールしてください:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## `File`と`Form`のインポート { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## `File`と`Form`のパラメータの定義 { #define-file-and-form-parameters }\n\nファイルやフォームのパラメータは`Body`や`Query`の場合と同じように作成します:\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\nファイルとフォームフィールドがフォームデータとしてアップロードされ、ファイルとフォームフィールドを受け取ります。\n\nまた、いくつかのファイルを`bytes`として、いくつかのファイルを`UploadFile`として宣言することができます。\n\n/// warning | 注意\n\n*path operation*で複数の`File`と`Form`パラメータを宣言することができますが、JSONとして受け取ることを期待している`Body`フィールドを宣言することはできません。なぜなら、リクエストのボディは`application/json`の代わりに`multipart/form-data`を使ってエンコードされているからです。\n\nこれは **FastAPI** の制限ではなく、HTTPプロトコルの一部です。\n\n///\n\n## まとめ { #recap }\n\n同じリクエストでデータやファイルを受け取る必要がある場合は、`File` と`Form`を一緒に使用します。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/request-forms.md",
    "content": "# フォームデータ { #form-data }\n\nJSONの代わりにフィールドを受け取る場合は、`Form`を使用します。\n\n/// info | 情報\n\nフォームを使うためには、まず[`python-multipart`](https://github.com/Kludex/python-multipart)をインストールします。\n\n必ず[仮想環境](../virtual-environments.md)を作成して有効化してから、例えば次のようにインストールしてください:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## `Form`のインポート { #import-form }\n\n`fastapi`から`Form`をインポートします:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## `Form`のパラメータの定義 { #define-form-parameters }\n\n`Body`や`Query`の場合と同じようにフォームパラメータを作成します:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\n例えば、OAuth2仕様が使用できる方法の１つ（「パスワードフロー」と呼ばれる）では、フォームフィールドとして`username`と`password`を送信する必要があります。\n\n<dfn title=\"仕様\">仕様</dfn>では、フィールドの名前が正確に`username`と`password`であることと、JSONではなくフォームフィールドとして送信されることを要求しています。\n\n`Form`では`Body`（および`Query`や`Path`、`Cookie`）と同じ設定を宣言することができます。これには、バリデーション、例、エイリアス（例えば`username`の代わりに`user-name`）などが含まれます。\n\n/// info | 情報\n\n`Form`は`Body`を直接継承するクラスです。\n\n///\n\n/// tip | 豆知識\n\nフォームのボディを宣言するには、明示的に`Form`を使用する必要があります。なぜなら、これを使わないと、パラメータはクエリパラメータやボディ（JSON）パラメータとして解釈されるからです。\n\n///\n\n## 「フォームフィールド」について { #about-form-fields }\n\nHTMLフォーム（`<form></form>`）がサーバにデータを送信する方法は、通常、そのデータに「特別な」エンコーディングを使用していますが、これはJSONとは異なります。\n\n**FastAPI** は、JSONの代わりにそのデータを適切な場所から読み込むようにします。\n\n/// note | 技術詳細\n\nフォームからのデータは通常、`application/x-www-form-urlencoded`の「media type」を使用してエンコードされます。\n\nしかし、フォームがファイルを含む場合は、`multipart/form-data`としてエンコードされます。ファイルの扱いについては次の章で説明します。\n\nこれらのエンコーディングやフォームフィールドの詳細については、[<abbr title=\"Mozilla Developer Network - Mozilla 開発者ネットワーク\">MDN</abbr> の `POST` ウェブドキュメント](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)を参照してください。\n\n///\n\n/// warning | 注意\n\n*path operation*で複数の`Form`パラメータを宣言することができますが、JSONとして受け取ることを期待している`Body`フィールドを宣言することはできません。なぜなら、リクエストは`application/x-www-form-urlencoded`の代わりに`application/json`を使ってボディをエンコードするからです。\n\nこれは **FastAPI**の制限ではなく、HTTPプロトコルの一部です。\n\n///\n\n## まとめ { #recap }\n\nフォームデータの入力パラメータを宣言するには、`Form`を使用する。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/response-model.md",
    "content": "# レスポンスモデル - 戻り値の型 { #response-model-return-type }\n\n*path operation 関数*の**戻り値の型**にアノテーションを付けることで、レスポンスに使用される型を宣言できます。\n\n関数**パラメータ**の入力データと同じように **型アノテーション** を使用できます。Pydanticモデル、リスト、辞書、整数や真偽値などのスカラー値を使用できます。\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPIはこの戻り値の型を使って以下を行います:\n\n* 返却データを**検証**します。\n    * データが不正（例: フィールドが欠けている）であれば、それは*あなた*のアプリコードが壊れていて、返すべきものを返していないことを意味し、不正なデータを返す代わりにサーバーエラーを返します。これにより、あなたとクライアントは、期待されるデータとデータ形状を受け取れることを確実にできます。\n* OpenAPIの *path operation* に、レスポンス用の **JSON Schema** を追加します。\n    * これは**自動ドキュメント**で使用されます。\n    * 自動クライアントコード生成ツールでも使用されます。\n* 返却データを Pydantic を使ってJSONに**シリアライズ**します。Pydantic は内部が**Rust**で実装されているため、**非常に高速**です。\n\nしかし、最も重要なのは:\n\n* 戻り値の型で定義された内容に合わせて、出力データを**制限しフィルタリング**します。\n    * これは**セキュリティ**の観点で特に重要です。以下で詳しく見ていきます。\n\n## `response_model`パラメータ { #response-model-parameter }\n\n型が宣言している内容とまったく同じではないデータを返す必要がある、またはそうしたいケースがあります。\n\n例えば、**辞書を返す**、またはデータベースオブジェクトを返したいが、**Pydanticモデルとして宣言**したい場合があります。こうすることで、Pydanticモデルが返したオブジェクト（例: 辞書やデータベースオブジェクト）のドキュメント化、バリデーションなどをすべて行ってくれます。\n\n戻り値の型アノテーションを追加すると、ツールやエディタが（正しく）エラーとして、関数が宣言した型（例: Pydanticモデル）とは異なる型（例: dict）を返していると警告します。\n\nそのような場合、戻り値の型の代わりに、*path operation デコレータ*のパラメータ `response_model` を使用できます。\n\n`response_model`パラメータは、いずれの *path operation* でも使用できます:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* など。\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | 備考\n\n`response_model`は「デコレータ」メソッド（`get`、`post`など）のパラメータです。関数のパラメータやボディなどとは違い、*path operation 関数*のパラメータではありません。\n\n///\n\n`response_model`は、Pydanticモデルのフィールドで宣言するのと同じ型を受け取ります。そのため、Pydanticモデルにもできますし、例えば `List[Item]` のように、Pydanticモデルの `list` にもできます。\n\nFastAPIはこの `response_model` を使って、データのドキュメント化や検証などを行い、さらに出力データを型宣言に合わせて**変換・フィルタリング**します。\n\n/// tip | 豆知識\n\nエディタやmypyなどで厳密な型チェックをしている場合、関数の戻り値の型を `Any` として宣言できます。\n\nそうすると、意図的に何でも返していることをエディタに伝えられます。それでもFastAPIは `response_model` を使って、データのドキュメント化、検証、フィルタリングなどを行います。\n\n///\n\n### `response_model`の優先順位 { #response-model-priority }\n\n戻り値の型と `response_model` の両方を宣言した場合、`response_model` が優先され、FastAPIで使用されます。\n\nこれにより、レスポンスモデルとは異なる型を返している場合でも、エディタやmypyなどのツールで使用するために関数へ正しい型アノテーションを追加できます。それでもFastAPIは `response_model` を使用してデータの検証やドキュメント化などを実行できます。\n\nまた `response_model=None` を使用して、その*path operation*のレスポンスモデル生成を無効化することもできます。これは、Pydanticのフィールドとして有効ではないものに対して型アノテーションを追加する場合に必要になることがあります。以下のセクションのいずれかで例を示します。\n\n## 同じ入力データの返却 { #return-the-same-input-data }\n\nここでは `UserIn` モデルを宣言しています。これには平文のパスワードが含まれます:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | 情報\n\n`EmailStr` を使用するには、最初に [`email-validator`](https://github.com/JoshData/python-email-validator) をインストールしてください。\n\n[仮想環境](../virtual-environments.md)を作成して有効化してから、例えば次のようにインストールしてください:\n\n```console\n$ pip install email-validator\n```\n\nまたは次のようにします:\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\nそして、このモデルを使用して入力を宣言し、同じモデルを使って出力を宣言しています:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\nこれで、ブラウザがパスワードを使ってユーザーを作成する際に、APIがレスポンスで同じパスワードを返すようになりました。\n\nこの場合、同じユーザーがパスワードを送信しているので問題ないかもしれません。\n\nしかし、同じモデルを別の*path operation*に使用すると、すべてのクライアントにユーザーのパスワードを送信してしまう可能性があります。\n\n/// danger | 警告\n\nすべての注意点を理解していて、自分が何をしているか分かっている場合を除き、ユーザーの平文のパスワードを保存したり、このようにレスポンスで送信したりしないでください。\n\n///\n\n## 出力モデルの追加 { #add-an-output-model }\n\n代わりに、平文のパスワードを持つ入力モデルと、パスワードを持たない出力モデルを作成できます:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\nここでは、*path operation 関数*がパスワードを含む同じ入力ユーザーを返しているにもかかわらず:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n...`response_model`を、パスワードを含まない `UserOut` モデルとして宣言しました:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\nそのため、**FastAPI** は出力モデルで宣言されていないすべてのデータをフィルタリングしてくれます（Pydanticを使用）。\n\n### `response_model`または戻り値の型 { #response-model-or-return-type }\n\nこのケースでは2つのモデルが異なるため、関数の戻り値の型を `UserOut` としてアノテーションすると、エディタやツールは、異なるクラスなので不正な型を返していると警告します。\n\nそのため、この例では `response_model` パラメータで宣言する必要があります。\n\n...しかし、これを解決する方法を以下で確認しましょう。\n\n## 戻り値の型とデータフィルタリング { #return-type-and-data-filtering }\n\n前の例から続けます。**関数に1つの型をアノテーション**したい一方で、関数からは実際には**より多くのデータ**を含むものを返せるようにしたいとします。\n\nFastAPIにはレスポンスモデルを使用してデータを**フィルタリング**し続けてほしいです。つまり、関数がより多くのデータを返しても、レスポンスにはレスポンスモデルで宣言されたフィールドのみが含まれます。\n\n前の例ではクラスが異なるため `response_model` パラメータを使う必要がありました。しかしそれは、エディタやツールによる関数の戻り値の型チェックのサポートを受けられないことも意味します。\n\nしかし、このようなことが必要になる多くのケースでは、この例のようにモデルでデータの一部を**フィルタ/削除**したいだけです。\n\nそのような場合、クラスと継承を利用して関数の**型アノテーション**を活用し、エディタやツールのサポートを改善しつつ、FastAPIの**データフィルタリング**も得られます。\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\nこれにより、このコードは型として正しいためエディタやmypyからのツール支援を得られますし、FastAPIによるデータフィルタリングも得られます。\n\nこれはどのように動作するのでしょうか？確認してみましょう。🤓\n\n### 型アノテーションとツール支援 { #type-annotations-and-tooling }\n\nまず、エディタ、mypy、その他のツールがこれをどう見るかを見てみます。\n\n`BaseUser` には基本フィールドがあります。次に `UserIn` が `BaseUser` を継承して `password` フィールドを追加するため、両方のモデルのフィールドがすべて含まれます。\n\n関数の戻り値の型を `BaseUser` としてアノテーションしますが、実際には `UserIn` インスタンスを返しています。\n\nエディタやmypyなどのツールはこれに文句を言いません。typingの観点では、`UserIn` は `BaseUser` のサブクラスであり、期待されるものが `BaseUser` であれば `UserIn` は*有効*な型だからです。\n\n### FastAPIのデータフィルタリング { #fastapi-data-filtering }\n\n一方FastAPIでは、戻り値の型を見て、返す内容にその型で宣言されたフィールド**だけ**が含まれることを確認します。\n\nFastAPIは、返却データのフィルタリングにクラス継承の同じルールが使われてしまわないようにするため、内部でPydanticを使っていくつかの処理を行っています。そうでないと、期待以上に多くのデータを返してしまう可能性があります。\n\nこの方法で、**ツール支援**付きの型アノテーションと**データフィルタリング**の両方という、いいとこ取りができます。\n\n## ドキュメントを見る { #see-it-in-the-docs }\n\n自動ドキュメントを見ると、入力モデルと出力モデルがそれぞれ独自のJSON Schemaを持っていることが確認できます:\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\nそして、両方のモデルは対話型のAPIドキュメントに使用されます:\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## その他の戻り値の型アノテーション { #other-return-type-annotations }\n\nPydanticフィールドとして有効ではないものを返し、ツール（エディタやmypyなど）が提供するサポートを得るためだけに、関数でそれをアノテーションするケースがあるかもしれません。\n\n### レスポンスを直接返す { #return-a-response-directly }\n\n最も一般的なケースは、[高度なドキュメントで後述する「Responseを直接返す」](../advanced/response-directly.md)場合です。\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\nこのシンプルなケースは、戻り値の型アノテーションが `Response` のクラス（またはサブクラス）であるため、FastAPIが自動的に処理します。\n\nまた `RedirectResponse` と `JSONResponse` の両方は `Response` のサブクラスなので、ツールも型アノテーションが正しいとして問題にしません。\n\n### `Response`のサブクラスをアノテーションする { #annotate-a-response-subclass }\n\n型アノテーションで `Response` のサブクラスを使うこともできます:\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\nこれは `RedirectResponse` が `Response` のサブクラスであり、FastAPIがこのシンプルなケースを自動処理するため、同様に動作します。\n\n### 無効な戻り値の型アノテーション { #invalid-return-type-annotations }\n\nしかし、Pydantic型として有効ではない別の任意のオブジェクト（例: データベースオブジェクト）を返し、関数でそのようにアノテーションすると、FastAPIはその型アノテーションからPydanticレスポンスモデルを作成しようとして失敗します。\n\n同様に、<dfn title=\"複数の型のユニオンは「これらの型のいずれか」を意味します。\">ユニオン</dfn>のように、複数の型のうち1つ以上がPydantic型として有効でないものを含む場合も起こります。例えば次は失敗します 💥:\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n...これは、型アノテーションがPydantic型ではなく、単一の `Response` クラス（またはサブクラス）でもないために失敗します。`Response` と `dict` の間のunion（どちらか）になっているからです。\n\n### レスポンスモデルを無効化する { #disable-response-model }\n\n上の例を続けると、FastAPIが実行するデフォルトのデータ検証、ドキュメント化、フィルタリングなどを行いたくないこともあるでしょう。\n\nしかし、エディタや型チェッカー（例: mypy）などのツール支援を得るために、関数の戻り値の型アノテーションは残したいかもしれません。\n\nその場合、`response_model=None` を設定することでレスポンスモデルの生成を無効にできます:\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\nこれによりFastAPIはレスポンスモデル生成をスキップし、FastAPIアプリケーションに影響させずに必要な戻り値の型アノテーションを付けられます。🤓\n\n## レスポンスモデルのエンコーディングパラメータ { #response-model-encoding-parameters }\n\nレスポンスモデルには次のようにデフォルト値を設定できます:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None`（またはPython 3.10では `str | None = None`）はデフォルトが `None` です。\n* `tax: float = 10.5` はデフォルトが `10.5` です。\n* `tags: List[str] = []` はデフォルトが空のリスト `[]` です。\n\nただし、それらが実際には保存されていない場合、結果から省略したいことがあります。\n\n例えば、NoSQLデータベースに多くのオプション属性を持つモデルがあるが、デフォルト値でいっぱいの非常に長いJSONレスポンスを送信したくない場合です。\n\n### `response_model_exclude_unset`パラメータの使用 { #use-the-response-model-exclude-unset-parameter }\n\n*path operation デコレータ*のパラメータ `response_model_exclude_unset=True` を設定できます:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\nそうすると、デフォルト値はレスポンスに含まれず、実際に設定された値のみが含まれます。\n\nそのため、ID `foo` のitemに対してその *path operation* へリクエストを送ると、レスポンスは以下のようになります（デフォルト値を含まない）:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | 情報\n\n以下も使用できます:\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\n`exclude_defaults` と `exclude_none` については、[Pydanticのドキュメント](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict)で説明されている通りです。\n\n///\n\n#### デフォルト値を持つフィールドに値があるデータ { #data-with-values-for-fields-with-defaults }\n\nしかし、ID `bar` のitemのように、デフォルト値が設定されているモデルのフィールドに値が設定されている場合:\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\nそれらはレスポンスに含まれます。\n\n#### デフォルト値と同じ値を持つデータ { #data-with-the-same-values-as-the-defaults }\n\nID `baz` のitemのようにデフォルト値と同じ値を持つデータの場合:\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nFastAPIは十分に賢いので（実際には、Pydanticが十分に賢い）、`description` や `tax`、`tags` がデフォルト値と同じ値であっても、明示的に設定された（デフォルトから取得されたのではない）ことを理解します。\n\nそのため、それらはJSONレスポンスに含まれます。\n\n/// tip | 豆知識\n\nデフォルト値は `None` だけではないことに注意してください。\n\nリスト（`[]`）や `10.5` の `float` などでも構いません。\n\n///\n\n### `response_model_include`と`response_model_exclude` { #response-model-include-and-response-model-exclude }\n\n*path operation デコレータ*のパラメータ `response_model_include` と `response_model_exclude` も使用できます。\n\nこれらは、含める（残りを省略する）または除外する（残りを含む）属性名を持つ `str` の `set` を受け取ります。\n\nこれは、Pydanticモデルが1つしかなく、出力からいくつかのデータを削除したい場合のクイックショートカットとして使用できます。\n\n/// tip | 豆知識\n\nそれでも、これらのパラメータではなく、上で示したアイデアのように複数のクラスを使うことが推奨されます。\n\nこれは、`response_model_include` や `response_model_exclude` を使っていくつかの属性を省略しても、アプリのOpenAPI（とドキュメント）で生成されるJSON Schemaが完全なモデルのままになるためです。\n\n同様に動作する `response_model_by_alias` にも当てはまります。\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | 豆知識\n\n`{\"name\", \"description\"}` の構文は、それら2つの値を持つ `set` を作成します。\n\nこれは `set([\"name\", \"description\"])` と同等です。\n\n///\n\n#### `set`の代わりに`list`を使用する { #using-lists-instead-of-sets }\n\nもし `set` を使用することを忘れて、代わりに `list` や `tuple` を使用しても、FastAPIはそれを `set` に変換して正しく動作します:\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## まとめ { #recap }\n\n*path operation デコレータ*のパラメータ `response_model` を使用してレスポンスモデルを定義し、とくにプライベートデータがフィルタリングされることを保証します。\n\n明示的に設定された値のみを返すには、`response_model_exclude_unset` を使用します。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/response-status-code.md",
    "content": "# レスポンスステータスコード { #response-status-code }\n\nレスポンスモデルを指定するのと同じ方法で、レスポンスに使用されるHTTPステータスコードを以下の*path operations*のいずれかの`status_code`パラメータで宣言することもできます。\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* etc.\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | 備考\n\n`status_code`は「デコレータ」メソッド（`get`、`post`など）のパラメータであることに注意してください。すべてのパラメータやボディのように、*path operation function*のものではありません。\n\n///\n\n`status_code`パラメータはHTTPステータスコードを含む数値を受け取ります。\n\n/// info | 情報\n\n`status_code`は代わりに、Pythonの[`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus)のように、`IntEnum`を受け取ることもできます。\n\n///\n\nこれは:\n\n* レスポンスでステータスコードを返します。\n* OpenAPIスキーマ（およびユーザーインターフェース）に以下のように文書化します:\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | 備考\n\nいくつかのレスポンスコード（次のセクションを参照）は、レスポンスにボディがないことを示しています。\n\nFastAPIはこれを知っていて、レスポンスボディがないというOpenAPIドキュメントを生成します。\n\n///\n\n## HTTPステータスコードについて { #about-http-status-codes }\n\n/// note | 備考\n\nすでにHTTPステータスコードが何であるかを知っている場合は、次のセクションにスキップしてください。\n\n///\n\nHTTPでは、レスポンスの一部として3桁の数字のステータスコードを送信します。\n\nこれらのステータスコードは、それらを認識するために関連付けられた名前を持っていますが、重要な部分は番号です。\n\nつまり:\n\n* `100 - 199` は「情報」のためのものです。直接使うことはほとんどありません。これらのステータスコードを持つレスポンスはボディを持つことができません。\n* **`200 - 299`** は「成功」のレスポンスのためのものです。これらは最も利用するであろうものです。\n    * `200`はデフォルトのステータスコードで、すべてが「OK」であったことを意味します。\n    * 別の例としては、`201`（Created）があります。これはデータベースに新しいレコードを作成した後によく使用されます。\n    * 特殊なケースとして、`204`（No Content）があります。このレスポンスはクライアントに返すコンテンツがない場合に使用されるため、レスポンスはボディを持ってはいけません。\n* **`300 - 399`** は「リダイレクト」のためのものです。これらのステータスコードを持つレスポンスは`304`（Not Modified）を除き、ボディを持つことも持たないこともできます。`304`はボディを持ってはいけません。\n* **`400 - 499`** は「クライアントエラー」のレスポンスのためのものです。これらは、おそらく最も多用するであろう2番目のタイプです。\n    * 例えば、`404`は「Not Found」レスポンスです。\n    * クライアントからの一般的なエラーについては、`400`を使用することができます。\n* `500 - 599` はサーバーエラーのためのものです。これらを直接使うことはほとんどありません。アプリケーションコードやサーバーのどこかで何か問題が発生した場合、これらのステータスコードのいずれかが自動的に返されます。\n\n/// tip | 豆知識\n\nそれぞれのステータスコードとどのコードが何のためのコードなのかについての詳細は、[<abbr title=\"Mozilla Developer Network - Mozilla 開発者ネットワーク\">MDN</abbr> のHTTPステータスコードに関するドキュメント](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)を参照してください。\n\n///\n\n## 名前を覚えるための近道 { #shortcut-to-remember-the-names }\n\n先ほどの例をもう一度見てみましょう:\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201`は「作成完了」のためのステータスコードです。\n\nしかし、それぞれのコードの意味を暗記する必要はありません。\n\n`fastapi.status`の便利な変数を利用することができます。\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\nそれらは単なる便利なものであり、同じ番号を保持しています。しかし、その方法ではエディタの自動補完を使用してそれらを見つけることができます。\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | 技術詳細\n\nまた、`from starlette import status`を使うこともできます。\n\n**FastAPI** は、開発者の利便性を考慮して、fastapi.statusと同じ`starlette.status`を提供しています。しかし、これはStarletteから直接提供されています。\n\n///\n\n## デフォルトの変更 { #changing-the-default }\n\n後に、[高度なユーザーガイド](../advanced/response-change-status-code.md)で、ここで宣言しているデフォルトとは異なるステータスコードを返す方法を見ていきます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/schema-extra-example.md",
    "content": "# リクエストのExampleデータの宣言 { #declare-request-example-data }\n\nアプリが受け取れるデータの例を宣言できます。\n\nここでは、それを行ういくつかの方法を紹介します。\n\n## Pydanticモデルでの追加JSON Schemaデータ { #extra-json-schema-data-in-pydantic-models }\n\n生成されるJSON Schemaに追加されるPydanticモデルの`examples`を宣言できます。\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\nその追加情報は、そのモデルの出力**JSON Schema**にそのまま追加され、APIドキュメントで使用されます。\n\n[Pydanticのドキュメント: Configuration](https://docs.pydantic.dev/latest/api/config/)で説明されているように、`dict`を受け取る属性`model_config`を使用できます。\n\n生成されるJSON Schemaに表示したい追加データ（`examples`を含む）を含む`dict`を使って、`\"json_schema_extra\"`を設定できます。\n\n/// tip | 豆知識\n\n同じ手法を使ってJSON Schemaを拡張し、独自のカスタム追加情報を追加できます。\n\n例えば、フロントエンドのユーザーインターフェースのためのメタデータを追加する、などに使えます。\n\n///\n\n/// info | 情報\n\nOpenAPI 3.1.0（FastAPI 0.99.0以降で使用）では、**JSON Schema**標準の一部である`examples`がサポートされました。\n\nそれ以前は、単一の例を持つキーワード`example`のみがサポートされていました。これはOpenAPI 3.1.0でも引き続きサポートされていますが、非推奨であり、JSON Schema標準の一部ではありません。そのため、`example`から`examples`への移行が推奨されます。🤓\n\n詳細はこのページの最後で読めます。\n\n///\n\n## `Field`の追加引数 { #field-additional-arguments }\n\nPydanticモデルで`Field()`を使う場合、追加の`examples`も宣言できます:\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## JSON Schema内の`examples` - OpenAPI { #examples-in-json-schema-openapi }\n\n以下のいずれかを使用する場合:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\n追加情報を含む`examples`のグループを宣言でき、それらは**OpenAPI**内のそれぞれの**JSON Schemas**に追加されます。\n\n### `examples`を使う`Body` { #body-with-examples }\n\nここでは、`Body()`で期待されるデータの例を1つ含む`examples`を渡します:\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### ドキュメントUIでの例 { #example-in-the-docs-ui }\n\n上記のいずれの方法でも、`/docs`の中では以下のようになります:\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### 複数の`examples`を使う`Body` { #body-with-multiple-examples }\n\nもちろん、複数の`examples`を渡すこともできます:\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\nこの場合、examplesはそのボディデータの内部**JSON Schema**の一部になります。\n\nそれでも、<dfn title=\"2023-08-26\">執筆時点</dfn>では、ドキュメントUIの表示を担当するツールであるSwagger UIは、**JSON Schema**内のデータに対して複数の例を表示することをサポートしていません。しかし、回避策については以下を読んでください。\n\n### OpenAPI固有の`examples` { #openapi-specific-examples }\n\n**JSON Schema**が`examples`をサポートする前から、OpenAPIは同じく`examples`という別のフィールドをサポートしていました。\n\nこの**OpenAPI固有**の`examples`は、OpenAPI仕様の別のセクションに入ります。各JSON Schemaの中ではなく、**各*path operation*の詳細**に入ります。\n\nそしてSwagger UIは、この特定の`examples`フィールドを以前からサポートしています。そのため、これを使って**ドキュメントUIに異なる例を表示**できます。\n\nこのOpenAPI固有フィールド`examples`の形は**複数の例**（`list`ではなく）を持つ`dict`であり、それぞれに追加情報が含まれ、その追加情報は**OpenAPI**にも追加されます。\n\nこれはOpenAPIに含まれる各JSON Schemaの中には入らず、外側の、*path operation*に直接入ります。\n\n### `openapi_examples`パラメータの使用 { #using-the-openapi-examples-parameter }\n\nFastAPIでは、以下に対してパラメータ`openapi_examples`を使って、OpenAPI固有の`examples`を宣言できます:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\n`dict`のキーは各例を識別し、各値は別の`dict`です。\n\n`examples`内の各特定の例`dict`には、次の内容を含められます:\n\n* `summary`: 例の短い説明。\n* `description`: Markdownテキストを含められる長い説明。\n* `value`: 実際に表示される例（例: `dict`）。\n* `externalValue`: `value`の代替で、例を指すURLです。ただし、`value`ほど多くのツールでサポートされていない可能性があります。\n\n次のように使えます:\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### ドキュメントUIのOpenAPI Examples { #openapi-examples-in-the-docs-ui }\n\n`Body()`に`openapi_examples`を追加すると、`/docs`は次のようになります:\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## 技術詳細 { #technical-details }\n\n/// tip | 豆知識\n\nすでに**FastAPI**バージョン**0.99.0以上**を使用している場合、おそらくこれらの詳細は**スキップ**できます。\n\nこれらは、OpenAPI 3.1.0が利用可能になる前の古いバージョンにより関連します。\n\nこれは簡単なOpenAPIとJSON Schemaの**歴史の授業**だと考えられます。🤓\n\n///\n\n/// warning | 注意\n\nここでは、標準である**JSON Schema**と**OpenAPI**についての非常に技術的な詳細を扱います。\n\n上のアイデアがすでにうまく動いているなら、それで十分かもしれませんし、おそらくこの詳細は不要です。気軽にスキップしてください。\n\n///\n\nOpenAPI 3.1.0より前は、OpenAPIは古く改変されたバージョンの**JSON Schema**を使用していました。\n\nJSON Schemaには`examples`がなかったため、OpenAPIは自身が改変したバージョンに独自の`example`フィールドを追加しました。\n\nOpenAPIは、仕様の他の部分にも`example`と`examples`フィールドを追加しました:\n\n* [`Parameter Object`（仕様内）](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object)。FastAPIの以下で使用されました:\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object`、`Media Type Object`の`content`フィールド（仕様内）](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object)。FastAPIの以下で使用されました:\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info | 情報\n\nこの古いOpenAPI固有の`examples`パラメータは、FastAPI `0.103.0`以降は`openapi_examples`になりました。\n\n///\n\n### JSON Schemaの`examples`フィールド { #json-schemas-examples-field }\n\nしかしその後、JSON Schemaは新しいバージョンの仕様に[`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5)フィールドを追加しました。\n\nそして、新しいOpenAPI 3.1.0は、この新しいフィールド`examples`を含む最新バージョン（JSON Schema 2020-12）に基づくようになりました。\n\nそして現在、この新しい`examples`フィールドは、古い単一（かつカスタム）の`example`フィールドより優先され、`example`は現在非推奨です。\n\nJSON Schemaのこの新しい`examples`フィールドは、OpenAPIの他の場所（上で説明）にあるような追加メタデータを持つdictではなく、**単なる例の`list`**です。\n\n/// info | 情報\n\nOpenAPI 3.1.0がこのJSON Schemaとの新しいよりシンプルな統合とともにリリースされた後も、しばらくの間、自動ドキュメントを提供するツールであるSwagger UIはOpenAPI 3.1.0をサポートしていませんでした（バージョン5.0.0からサポートされています🎉）。\n\nそのため、FastAPI 0.99.0より前のバージョンは、OpenAPI 3.1.0より低いバージョンのOpenAPIをまだ使用していました。\n\n///\n\n### PydanticとFastAPIの`examples` { #pydantic-and-fastapi-examples }\n\nPydanticモデル内で、`schema_extra`または`Field(examples=[\"something\"])`を使って`examples`を追加すると、その例はそのPydanticモデルの**JSON Schema**に追加されます。\n\nそしてそのPydanticモデルの**JSON Schema**はAPIの**OpenAPI**に含まれ、ドキュメントUIで使用されます。\n\nFastAPI 0.99.0より前のバージョン（0.99.0以上は新しいOpenAPI 3.1.0を使用）では、他のユーティリティ（`Query()`、`Body()`など）で`example`または`examples`を使っても、それらの例はそのデータを説明するJSON Schema（OpenAPI独自版のJSON Schemaでさえ）には追加されず、OpenAPI内の*path operation*宣言に直接追加されていました（JSON Schemaを使用するOpenAPIの部分の外側）。\n\nしかし、FastAPI 0.99.0以上ではOpenAPI 3.1.0を使用し、それはJSON Schema 2020-12とSwagger UI 5.0.0以上を使うため、すべてがより一貫し、例はJSON Schemaに含まれます。\n\n### Swagger UIとOpenAPI固有の`examples` { #swagger-ui-and-openapi-specific-examples }\n\nSwagger UIは複数のJSON Schema examplesをサポートしていなかった（2023-08-26時点）ため、ユーザーはドキュメントで複数の例を表示する手段がありませんでした。\n\nそれを解決するため、FastAPI `0.103.0`は、新しいパラメータ`openapi_examples`で、同じ古い**OpenAPI固有**の`examples`フィールドを宣言するための**サポートを追加**しました。🤓\n\n### まとめ { #summary }\n\n昔は歴史があまり好きではないと言っていました...が、今の私は「技術の歴史」の授業をしています。😅\n\n要するに、**FastAPI 0.99.0以上にアップグレード**してください。そうすれば、物事はもっと**シンプルで一貫性があり直感的**になり、これらの歴史的詳細を知る必要もありません。😎\n"
  },
  {
    "path": "docs/ja/docs/tutorial/security/first-steps.md",
    "content": "# セキュリティ - 最初の一歩 { #security-first-steps }\n\nあるドメインに、**バックエンド** APIを持っているとしましょう。\n\nそして、別のドメインか同じドメインの違うパス（またはモバイルアプリケーションの中）に **フロントエンド**を持っています。\n\nさらに、フロントエンドが**ユーザー名**と**パスワード**を使って、バックエンドで認証する方法を用意したいです。\n\n**FastAPI**では、これを**OAuth2**を使用して構築できます。\n\nですが、ちょっとした必要な情報を探すために、長い仕様のすべてを読む必要はありません。\n\n**FastAPI**が提供するツールを使って、セキュリティを制御してみましょう。\n\n## どう見えるか { #how-it-looks }\n\nまずはこのコードを使って、どう動くか観察します。その後で、何が起こっているのか理解しましょう。\n\n## `main.py`を作成 { #create-main-py }\n\n`main.py`に、下記の例をコピーします:\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## 実行 { #run-it }\n\n/// info | 情報\n\n[`python-multipart`](https://github.com/Kludex/python-multipart) パッケージは、`pip install \"fastapi[standard]\"` コマンドを実行すると **FastAPI** と一緒に自動的にインストールされます。\n\nしかし、`pip install fastapi` コマンドを使用する場合、`python-multipart` パッケージはデフォルトでは含まれません。\n\n手動でインストールするには、[仮想環境](../../virtual-environments.md)を作成して有効化し、次のコマンドでインストールしてください:\n\n```console\n$ pip install python-multipart\n```\n\nこれは、**OAuth2**が `username` と `password` を送信するために、「フォームデータ」を使うからです。\n\n///\n\n例を実行します:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## 確認 { #check-it }\n\n次のインタラクティブなドキュメントにアクセスしてください: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n下記のように見えるでしょう:\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Authorizeボタン!\n\nすでにピカピカの新しい「Authorize」ボタンがあります。\n\nそして、あなたの*path operation*には、右上にクリックできる小さな鍵アイコンがあります。\n\n///\n\nそれをクリックすると、`username` と `password`（およびその他のオプションフィールド）を入力する小さな認可フォームが表示されます:\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | 備考\n\nフォームに何を入力しても、まだうまくいきません。ですが、これから動くようになります。\n\n///\n\nもちろんエンドユーザーのためのフロントエンドではありません。しかし、すべてのAPIをインタラクティブにドキュメント化するための素晴らしい自動ツールです。\n\nフロントエンドチームはこれを利用できます (また、あなたも利用できます) 。\n\nサードパーティのアプリケーションやシステムでも使用可能です。\n\nまた、同じアプリケーションのデバッグ、チェック、テストのためにも利用できます。\n\n## `password` フロー { #the-password-flow }\n\nでは、少し話を戻して、どうなっているか理解しましょう。\n\n`password`の「フロー」は、OAuth2で定義されているセキュリティと認証を扱う方法 (「フロー」) の1つです。\n\nOAuth2は、バックエンドやAPIがユーザーを認証するサーバーから独立したものとして設計されていました。\n\nしかし、この場合、同じ**FastAPI**アプリケーションがAPIと認証を処理します。\n\nそこで、簡略化した箇所から見直してみましょう:\n\n* ユーザーはフロントエンドで`username`と`password`を入力し、`Enter`を押します。\n* フロントエンド (ユーザーのブラウザで実行中) は、`username`と`password`をAPIの特定のURL (`tokenUrl=\"token\"`で宣言された) に送信します。\n* APIは`username`と`password`をチェックし、「トークン」を返却します (まだ実装していません)。\n    * 「トークン」はただの文字列であり、あとでこのユーザーを検証するために使用します。\n    * 通常、トークンは時間が経つと期限切れになるように設定されています。\n        * トークンが期限切れの場合は、再度ログインする必要があります。\n        * トークンが盗まれたとしても、リスクは低いです。永久キーのように永遠に機能するものではありません（ほとんどの場合）。\n* フロントエンドはそのトークンを一時的にどこかに保存します。\n* ユーザーがフロントエンドでクリックして、フロントエンドのWebアプリの別のセクションに移動します。\n* フロントエンドはAPIからさらにデータを取得する必要があります。\n    * しかし、特定のエンドポイントの認証が必要です。\n    * したがって、APIで認証するため、HTTPヘッダー`Authorization`に`Bearer`の文字列とトークンを加えた値を送信します。\n    * トークンに`foobar`が含まれている場合、`Authorization`ヘッダーの内容は次のようになります: `Bearer foobar`。\n\n## **FastAPI**の`OAuth2PasswordBearer` { #fastapis-oauth2passwordbearer }\n\n**FastAPI**は、これらのセキュリティ機能を実装するために、抽象度の異なる複数のツールを提供しています。\n\nこの例では、**Bearer**トークンを使用して**OAuth2**を**Password**フローで使用します。これには`OAuth2PasswordBearer`クラスを使用します。\n\n/// info | 情報\n\n「bearer」トークンが、唯一の選択肢ではありません。\n\nしかし、私たちのユースケースには最適です。\n\nあなたがOAuth2の専門家で、あなたのニーズに適した別のオプションがある理由を正確に知っている場合を除き、ほとんどのユースケースに最適かもしれません。\n\nその場合、**FastAPI**はそれを構築するためのツールも提供します。\n\n///\n\n`OAuth2PasswordBearer` クラスのインスタンスを作成する時に、パラメーター`tokenUrl`を渡します。このパラメーターには、クライアント (ユーザーのブラウザで動作するフロントエンド) がトークンを取得するために`username`と`password`を送信するURLを指定します。\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip | 豆知識\n\nここで、`tokenUrl=\"token\"`は、まだ作成していない相対URL`token`を指します。相対URLなので、`./token`と同じです。\n\n相対URLを使っているので、APIが`https://example.com/`にある場合、`https://example.com/token`を参照します。しかし、APIが`https://example.com/api/v1/`にある場合は`https://example.com/api/v1/token`を参照することになります。\n\n相対 URL を使うことは、[プロキシの背後](../../advanced/behind-a-proxy.md)のような高度なユースケースでもアプリケーションを動作させ続けるために重要です。\n\n///\n\nこのパラメーターはエンドポイント/ *path operation*を作成しません。しかし、URL`/token`はクライアントがトークンを取得するために使用するものであると宣言します。この情報は OpenAPI やインタラクティブな API ドキュメントシステムで使われます。\n\n実際の path operation もすぐに作ります。\n\n/// info | 情報\n\n非常に厳格な「Pythonista」であれば、パラメーター名のスタイルが`tokenUrl`ではなく`token_url`であることを気に入らないかもしれません。\n\nそれはOpenAPI仕様と同じ名前を使用しているからです。そのため、これらのセキュリティスキームについてもっと調べる必要がある場合は、それをコピーして貼り付ければ、それについての詳細な情報を見つけることができます。\n\n///\n\n変数`oauth2_scheme`は`OAuth2PasswordBearer`のインスタンスですが、「呼び出し可能」です。\n\n次のように、呼ぶことができます:\n\n```Python\noauth2_scheme(some, parameters)\n```\n\nそのため、`Depends`と一緒に使うことができます。\n\n### 使い方 { #use-it }\n\nこれで`oauth2_scheme`を`Depends`で依存関係に渡すことができます。\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nこの依存関係は、*path operation 関数*のパラメーター`token`に代入される`str`を提供します。\n\n**FastAPI**は、この依存関係を使用してOpenAPIスキーマ (および自動APIドキュメント) で「セキュリティスキーム」を定義できることを知っています。\n\n/// info | 技術詳細\n\n**FastAPI**は、`OAuth2PasswordBearer` クラス (依存関係で宣言されている) を使用してOpenAPIのセキュリティスキームを定義できることを知っています。これは`fastapi.security.oauth2.OAuth2`、`fastapi.security.base.SecurityBase`を継承しているからです。\n\nOpenAPIと統合するセキュリティユーティリティ (および自動APIドキュメント) はすべて`SecurityBase`を継承しています。それにより、**FastAPI**はそれらをOpenAPIに統合する方法を知ることができます。\n\n///\n\n## 何をするか { #what-it-does }\n\nリクエストの中に`Authorization`ヘッダーを探しに行き、その値が`Bearer `と何らかのトークンを含んでいるかどうかをチェックし、そのトークンを`str`として返します。\n\nもし`Authorization`ヘッダーが見つからなかったり、値が`Bearer `トークンを持っていなかったりすると、401 ステータスコードエラー (`UNAUTHORIZED`) で直接応答します。\n\nトークンが存在するかどうかをチェックしてエラーを返す必要はありません。関数が実行された場合、そのトークンに`str`が含まれていることを確信できます。\n\nインタラクティブなドキュメントですでに試すことができます:\n\n<img src=\"/img/tutorial/security/image03.png\">\n\nまだトークンの有効性を検証しているわけではありませんが、これはもう始まっています。\n\n## まとめ { #recap }\n\nつまり、たった3~4行の追加で、すでに何らかの基礎的なセキュリティの形になっています。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/security/get-current-user.md",
    "content": "# 現在のユーザーの取得 { #get-current-user }\n\n一つ前の章では、（依存性注入システムに基づいた）セキュリティシステムは、 *path operation 関数* に `str` として `token` を与えていました:\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nしかし、それはまだそんなに有用ではありません。\n\n現在のユーザーを取得するようにしてみましょう。\n\n## ユーザーモデルの作成 { #create-a-user-model }\n\nまずは、Pydanticのユーザーモデルを作成しましょう。\n\nボディを宣言するのにPydanticを使用するのと同じやり方で、Pydanticを別のどんなところでも使うことができます:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## 依存関係 `get_current_user` を作成 { #create-a-get-current-user-dependency }\n\n依存関係 `get_current_user` を作ってみましょう。\n\n依存関係はサブ依存関係を持つことができるのを覚えていますか？\n\n`get_current_user` は前に作成した `oauth2_scheme` と同じ依存関係を持ちます。\n\n以前直接 *path operation* の中でしていたのと同じように、新しい依存関係である `get_current_user` はサブ依存関係である `oauth2_scheme` から `str` として `token` を受け取るようになります:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## ユーザーの取得 { #get-the-user }\n\n`get_current_user` は作成した（偽物の）ユーティリティ関数を使って、 `str` としてトークンを受け取り、先ほどのPydanticの `User` モデルを返却します:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## 現在のユーザーの注入 { #inject-the-current-user }\n\nですので、 `get_current_user` に対して同様に *path operation* の中で `Depends` を利用できます。\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\nPydanticモデルの `User` として、 `current_user` の型を宣言することに注意してください。\n\nその関数の中ですべての入力補完や型チェックを行う際に役に立ちます。\n\n/// tip | 豆知識\n\nリクエストボディはPydanticモデルでも宣言できることを覚えているかもしれません。\n\nここでは `Depends` を使っているおかげで、 **FastAPI** が混乱することはありません。\n\n///\n\n/// check | 確認\n\n依存関係システムがこのように設計されているおかげで、 `User` モデルを返却する別の依存関係（別の「dependables」）を持つことができます。\n\n同じデータ型を返却する依存関係は一つだけしか持てない、という制約が入ることはないのです。\n\n///\n\n## 別のモデル { #other-models }\n\nこれで、*path operation 関数* の中で現在のユーザーを直接取得し、`Depends` を使って、 **依存性注入** レベルでセキュリティメカニズムを処理できるようになりました。\n\nそして、セキュリティ要件のためにどんなモデルやデータでも利用することができます。（この場合は、 Pydanticモデルの `User`）\n\nしかし、特定のデータモデルやクラス、型に制限されることはありません。\n\nモデルを、 `id` と `email` は持つが、 `username` は全く持たないようにしたいですか？ わかりました。同じ手段でこうしたこともできます。\n\nある `str` だけを持ちたい？ あるいはある `dict` だけですか？ それとも、データベースクラスのモデルインスタンスを直接持ちたいですか？ すべて同じやり方で機能します。\n\n実際には、あなたのアプリケーションにはログインするようなユーザーはおらず、単にアクセストークンを持つロボットやボット、別のシステムがありますか？ここでも、全く同じようにすべて機能します。\n\nあなたのアプリケーションに必要なのがどんな種類のモデル、どんな種類のクラス、どんな種類のデータベースであったとしても、 **FastAPI** は依存性注入システムでカバーしてくれます。\n\n## コードサイズ { #code-size }\n\nこの例は冗長に見えるかもしれません。セキュリティとデータモデルユーティリティ関数および *path operation* が同じファイルに混在しているということを覚えておいてください。\n\nしかし、ここに重要なポイントがあります。\n\nセキュリティと依存性注入に関するものは、一度だけ書きます。\n\nそして、それは好きなだけ複雑にすることができます。それでも、一箇所に、一度だけ書くのです。すべての柔軟性を備えます。\n\nしかし、同じセキュリティシステムを使って何千ものエンドポイント（*path operation*）を持つことができます。\n\nそして、それらエンドポイントのすべて（必要な、どの部分でも）がこうした依存関係や、あなたが作成する別の依存関係を再利用する利点を享受できるのです。\n\nさらに、こうした何千もの *path operation* は、たった3行で表現できるのです:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## まとめ { #recap }\n\nこれで、 *path operation 関数* の中で直接現在のユーザーを取得できるようになりました。\n\n既に半分のところまで来ています。\n\nあとは、ユーザー/クライアントが実際に `username` と `password` を送信するための *path operation* を追加する必要があるだけです。\n\n次はそれを説明します。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/security/index.md",
    "content": "# セキュリティ入門 { #security }\n\nセキュリティ、認証、認可を扱うには多くの方法があります。\n\nそして、通常、それは複雑で「難しい」トピックです。\n\n多くのフレームワークやシステムでは、セキュリティと認証を処理するだけで、膨大な労力とコードが必要になります（多くの場合、書かれた全コードの50%以上を占めることがあります）。\n\n**FastAPI** は、セキュリティの仕様をすべて勉強して学ぶことなく、標準的な方法で簡単に、迅速に**セキュリティ**を扱うためのツールをいくつか提供します。\n\nしかし、その前に、いくつかの小さな概念を確認しましょう。\n\n## お急ぎですか？ { #in-a-hurry }\n\nもし、これらの用語に興味がなく、ユーザー名とパスワードに基づく認証でセキュリティを**今すぐ**確保する必要がある場合は、次の章に進んでください。\n\n## OAuth2 { #oauth2 }\n\nOAuth2は、認証と認可を処理するためのいくつかの方法を定義した仕様です。\n\nかなり広範囲な仕様で、いくつかの複雑なユースケースをカバーしています。\n\nこれには「サードパーティ」を使用して認証する方法が含まれています。\n\nこれが、「Facebook、Google、X (Twitter)、GitHubを使ってログイン」を使用したすべてのシステムの背後で使われている仕組みです。\n\n### OAuth 1 { #oauth-1 }\n\nOAuth 1というものもありましたが、これはOAuth2とは全く異なり、通信をどのように暗号化するかという仕様が直接的に含まれており、より複雑なものとなっています。\n\n現在ではあまり普及していませんし、使われてもいません。\n\nOAuth2は、通信を暗号化する方法を指定せず、アプリケーションがHTTPSで提供されることを想定しています。\n\n/// tip | 豆知識\n\n**デプロイ**のセクションでは、TraefikとLet's Encryptを使用して、無料でHTTPSを設定する方法が紹介されています。\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connectは、**OAuth2**をベースにした別の仕様です。\n\nこれはOAuth2を拡張したもので、OAuth2ではやや曖昧だった部分を明確にし、より相互運用性を高めようとしたものです。\n\n例として、GoogleのログインはOpenID Connectを使用しています（これはOAuth2がベースになっています）。\n\nしかし、FacebookのログインはOpenID Connectをサポートしていません。OAuth2を独自にアレンジしています。\n\n### OpenID (「OpenID Connect」ではない) { #openid-not-openid-connect }\n\nまた、「OpenID」という仕様もありました。それは、**OpenID Connect**と同じことを解決しようとしたものですが、OAuth2に基づいているわけではありませんでした。\n\nつまり、完全な追加システムだったのです。\n\n現在ではあまり普及していませんし、使われてもいません。\n\n## OpenAPI { #openapi }\n\nOpenAPI（以前はSwaggerとして知られていました）は、APIを構築するためのオープンな仕様です（現在はLinux Foundationの一部になっています）。\n\n**FastAPI**は、**OpenAPI**をベースにしています。\n\nそれが、複数の自動対話型ドキュメント・インターフェースやコード生成などを可能にしているのです。\n\nOpenAPIには、複数のセキュリティ「スキーム」を定義する方法があります。\n\nそれらを使用することで、これらの対話型ドキュメントシステムを含む、標準ベースのツールをすべて活用できます。\n\nOpenAPIでは、以下のセキュリティスキームを定義しています:\n\n* `apiKey`: アプリケーション固有のキーで、これらのものから取得できます。\n    * クエリパラメータ\n    * ヘッダー\n    * クッキー\n* `http`: 標準的なHTTP認証システムで、これらのものを含みます。\n    * `bearer`: ヘッダ `Authorization` の値が `Bearer ` で、トークンが含まれます。これはOAuth2から継承しています。\n    * HTTP Basic認証\n    * HTTP ダイジェスト認証など\n* `oauth2`: OAuth2のセキュリティ処理方法（「フロー」と呼ばれます）のすべて。\n    * これらのフローのいくつかは、OAuth 2.0認証プロバイダ（Google、Facebook、X (Twitter)、GitHubなど）を構築するのに適しています。\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * しかし、同じアプリケーション内で認証を直接処理するために完全に機能する特定の「フロー」があります。\n        * `password`: 次のいくつかの章では、その例を紹介します。\n* `openIdConnect`: OAuth2認証データを自動的に発見する方法を定義できます。\n    * この自動検出メカニズムは、OpenID Connectの仕様で定義されているものです。\n\n\n/// tip | 豆知識\n\nGoogle、Facebook、X (Twitter)、GitHubなど、他の認証/認可プロバイダを統合することも可能で、比較的簡単です。\n\n最も複雑な問題は、それらのような認証/認可プロバイダを構築することですが、**FastAPI**は、あなたのために重い仕事をこなしながら、それを簡単に行うためのツールを提供します。\n\n///\n\n## **FastAPI** ユーティリティ { #fastapi-utilities }\n\nFastAPIは `fastapi.security` モジュールの中で、これらのセキュリティスキームごとにいくつかのツールを提供し、これらのセキュリティメカニズムを簡単に使用できるようにします。\n\n次の章では、**FastAPI** が提供するこれらのツールを使って、あなたのAPIにセキュリティを追加する方法について見ていきます。\n\nまた、それがどのようにインタラクティブなドキュメントシステムに自動的に統合されるかも見ていきます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/security/oauth2-jwt.md",
    "content": "# パスワード（およびハッシュ化）によるOAuth2、JWTトークンによるBearer { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\nこれでセキュリティの流れが全てわかったので、<abbr title=\"JSON Web Tokens - JSON Web Token\">JWT</abbr>トークンと安全なパスワードのハッシュ化を使用して、実際にアプリケーションを安全にしてみましょう。\n\nこのコードは、アプリケーションで実際に使用したり、パスワードハッシュをデータベースに保存するといった用途に利用できます。\n\n本章では、前章の続きから始めて、コードをアップデートしていきます。\n\n## JWT について { #about-jwt }\n\nJWTとは「JSON Web Tokens」の略称です。\n\nJSONオブジェクトをスペースのない長く密集した文字列で表現したトークンの仕様です。例えば次のようになります：\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\nこれらは暗号化されていないので、誰でもコンテンツから情報を復元できてしまいます。\n\nしかし、トークンは署名されているため、あなたが発行したトークンを受け取った人は、あなたが実際に発行したということを検証できます。\n\n例えば、1週間の有効期限を持つトークンを作成したとします。ユーザーが翌日そのトークンを持って戻ってきたとき、そのユーザーはまだシステムにログインしていることがわかります。\n\n1週間後、トークンが期限切れとなるとどうなるでしょうか？ユーザーは認可されず、新しいトークンを得るために再びサインインしなければなりません。また、ユーザー（または第三者）がトークンを修正して有効期限を変更しようとした場合、署名が一致しないため、トークンの修正を検知できます。\n\nJWT トークンを使って遊んでみたいという方は、[https://jwt.io](https://jwt.io/) をチェックしてください。\n\n## `PyJWT` のインストール { #install-pyjwt }\n\nPythonでJWTトークンの生成と検証を行うために、`PyJWT`をインストールする必要があります。\n\n[仮想環境](../../virtual-environments.md)を作成し、アクティベートしてから、`pyjwt`をインストールしてください。\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info | 情報\n\nRSAやECDSAのようなデジタル署名アルゴリズムを使用する予定がある場合は、cryptographyライブラリの依存関係`pyjwt[crypto]`をインストールしてください。\n\n詳細は[PyJWT Installation docs](https://pyjwt.readthedocs.io/en/latest/installation.html)で確認できます。\n\n///\n\n## パスワードのハッシュ化 { #password-hashing }\n\n「ハッシュ化」とは、あるコンテンツ（ここではパスワード）を、規則性のないバイト列（単なる文字列）に変換することです。\n\n特徴として、全く同じ内容（全く同じパスワード）を渡すと、全く同じ規則性のないバイト列に変換されます。\n\nしかし、規則性のないバイト列から元のパスワードに戻すことはできません。\n\n### パスワードのハッシュ化を使う理由 { #why-use-password-hashing }\n\nデータベースが盗まれても、ユーザーの平文のパスワードは盗まれず、ハッシュ値だけが盗まれます。\n\nしたがって、泥棒はそのパスワードを別のシステムで使えません（多くのユーザーはどこでも同じパスワードを使用しているため、危険性があります）。\n\n## `pwdlib` のインストール { #install-pwdlib }\n\npwdlib は、パスワードのハッシュを処理するための優れたPythonパッケージです。\n\nこのパッケージは、多くの安全なハッシュアルゴリズムとユーティリティをサポートします。\n\n推奨されるアルゴリズムは「Argon2」です。\n\n[仮想環境](../../virtual-environments.md)を作成し、アクティベートしてから、Argon2付きでpwdlibをインストールしてください。\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | 豆知識\n\n`pwdlib`を使用すると、**Django**や**Flask**のセキュリティプラグインなどで作成されたパスワードを読み取れるように設定できます。\n\n例えば、Djangoアプリケーションからデータベース内の同じデータをFastAPIアプリケーションと共有できるだけではなく、同じデータベースを使用してDjangoアプリケーションを徐々に移行することもできます。\n\nまた、ユーザーはDjangoアプリまたは**FastAPI**アプリからも、同時にログインできるようになります。\n\n///\n\n## パスワードのハッシュ化と検証 { #hash-and-verify-the-passwords }\n\n必要なツールを `pwdlib`からインポートします。\n\n推奨設定でPasswordHashインスタンスを作成します。これは、パスワードのハッシュ化と検証に使用されます。\n\n/// tip | 豆知識\n\npwdlibはbcryptハッシュアルゴリズムもサポートしていますが、レガシーアルゴリズムは含みません。古いハッシュを扱うには、passlibライブラリを使用することが推奨されます。\n\n例えば、この機能を使用して、別のシステム（Djangoなど）によって生成されたパスワードを読み取って検証し、Argon2やBcryptなどの別のアルゴリズムを使用して新しいパスワードをハッシュするといったことができます。\n\nそして、同時にそれらはすべてに互換性があります。\n\n///\n\nユーザーから送られてきたパスワードをハッシュ化するユーティリティー関数を作成します。\n\nまた、受け取ったパスワードが保存されているハッシュと一致するかどうかを検証するユーティリティも作成します。\n\nさらに、ユーザーを認証して返す関数も作成します。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\n`authenticate_user` がデータベースに存在しないユーザー名で呼び出された場合でも、ダミーのハッシュを使って `verify_password` を実行します。\n\nこれにより、ユーザー名が有効かどうかに関わらずエンドポイントの応答時間がおおよそ同じになり、既存のユーザー名を列挙するために悪用されうる「タイミング攻撃」を防止できます。\n\n/// note | 備考\n\n新しい（偽の）データベース`fake_users_db`を確認すると、ハッシュ化されたパスワードが次のようになっていることがわかります：`\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`。\n\n///\n\n## JWTトークンの取り扱い { #handle-jwt-tokens }\n\nインストールした複数のモジュールをインポートします。\n\nJWTトークンの署名に使用されるランダムな秘密鍵を生成します。\n\n安全なランダム秘密鍵を生成するには、次のコマンドを使用します：\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\nそして、出力された文字列を変数`SECRET_KEY`にコピーします。（例に記載している秘密鍵は実際に使用しないでください）\n\nJWTトークンの署名に使用するアルゴリズム`\"HS256\"`を指定した変数`ALGORITHM`を作成します。\n\nトークンの有効期限を指定した変数を作成します。\n\nレスポンスのトークンエンドポイントで使用するPydanticモデルを定義します。\n\n新しいアクセストークンを生成するユーティリティ関数を作成します。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## 依存関係の更新 { #update-the-dependencies }\n\n`get_current_user`を更新して、先ほどと同じトークンを受け取るようにしますが、今回はJWTトークンを使用します。\n\n受け取ったトークンをデコードして検証し、現在のユーザーを返します。\n\nトークンが無効な場合は、すぐにHTTPエラーを返します。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## `/token` *path operation* の更新 { #update-the-token-path-operation }\n\nトークンの有効期限を表す`timedelta`を作成します。\n\n実際のJWTアクセストークンを作成し、それを返します。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### JWTの「subject」`sub` についての技術的な詳細 { #technical-details-about-the-jwt-subject-sub }\n\nJWTの仕様では、トークンのsubjectを表すキー`sub`があるとされています。\n\n使用するかどうかは任意ですが、`sub`はユーザーの識別情報を入れるように規定されているので、ここで使用します。\n\nJWTは、ユーザーを識別して、そのユーザーがAPI上で直接操作を実行できるようにする以外にも、他の用途で使用されることがあります。\n\n例えば、「車」や「ブログ記事」を識別することができます。\n\nそして、「ドライブ」（車の場合）や「編集」（ブログの場合）など、そのエンティティに関する権限も追加できます。\n\nまた、JWTトークンをユーザー（またはボット）に渡すことができます。ユーザーは、JWTトークンを使用するだけで、アカウントを持っていなくても、APIが生成したJWTトークンを使ってそれらの行動（車の運転、ブログ投稿の編集）を実行できるのです。\n\nこれらのアイデアを使用すると、JWTをより高度なシナリオに使用できます。\n\nしかしながら、それらのエンティティのいくつかが同じIDを持つ可能性があります。例えば、`foo`（ユーザー`foo`、車 `foo`、ブログ投稿`foo`）などです。\n\nIDの衝突を回避するために、ユーザーのJWTトークンを作成するとき、subキーの値にプレフィックスを付けることができます（例えば、`username:`）。したがって、この例では、`sub`の値は次のようになっている可能性があります：`username:johndoe`。\n\n覚えておくべき重要なことは、`sub`キーはアプリケーション全体で一意の識別子を持ち、文字列である必要があるということです。\n\n## 確認 { #check-it }\n\nサーバーを実行し、ドキュメントに移動します：[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n次のようなユーザーインターフェイスが表示されます：\n\n<img src=\"/img/tutorial/security/image07.png\">\n\n前回と同じ方法でアプリケーションの認可を行います。\n\n次の認証情報を使用します：\n\nUsername: `johndoe`\nPassword: `secret`\n\n/// check | 確認\n\nコードのどこにも平文のパスワード\"`secret`\"はなく、ハッシュ化されたものしかないことを確認してください。\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\nエンドポイント`/users/me/`を呼び出すと、次のようなレスポンスが得られます：\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\n開発者ツールを開くと、送信されるデータにはトークンだけが含まれており、パスワードはユーザーを認証してアクセストークンを取得する最初のリクエストでのみ送信され、その後は送信されないことがわかります：\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | 備考\n\nヘッダーの`Authorization`には、`Bearer `で始まる値があります。\n\n///\n\n## `scopes` を使った高度なユースケース { #advanced-usage-with-scopes }\n\nOAuth2には、「スコープ」という概念があります。\n\nこれらを利用して、JWTトークンに特定の権限セットを追加することができます。\n\nそして、このトークンをユーザーに直接、または第三者に与えて、制限付きでAPIを操作できます。\n\nこれらの使用方法や**FastAPI**への統合方法については、**高度なユーザーガイド**で後ほど説明します。\n\n## まとめ { #recap }\n\nここまでの説明で、OAuth2やJWTなどの規格を使った安全な**FastAPI**アプリケーションを設定することができます。\n\nほとんどのフレームワークにおいて、セキュリティを扱うことは非常に複雑な課題となります。\n\n簡略化しすぎたパッケージの多くは、データモデルやデータベース、利用可能な機能について多くの妥協をしなければなりません。そして、あまりにも単純化されたパッケージの中には、実はセキュリティ上の欠陥があるものもあります。\n\n---\n\n**FastAPI**は、どのようなデータベース、データモデル、ツールに対しても妥協することはありません。\n\nそのため、プロジェクトに合わせて自由に選択することができます。\n\nまた、**FastAPI**は外部パッケージを統合するために複雑な仕組みを必要としないため、`pwdlib`や`PyJWT`のようなよく整備され広く使われている多くのパッケージを直接使用することができます。\n\nしかし、柔軟性、堅牢性、セキュリティを損なうことなく、可能な限りプロセスを簡素化するためのツールを提供します。\n\nまた、OAuth2のような安全で標準的なプロトコルを比較的簡単な方法で使用できるだけではなく、実装することもできます。\n\nOAuth2の「スコープ」を使って、同じ基準でより細かい権限システムを実現する方法については、**高度なユーザーガイド**で詳しく説明しています。スコープ付きのOAuth2は、Facebook、Google、GitHub、Microsoft、X (Twitter)など、多くの大手認証プロバイダが、サードパーティのアプリケーションと自社のAPIとのやり取りをユーザーに代わって認可するために使用している仕組みです。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/security/simple-oauth2.md",
    "content": "# パスワードとBearerによるシンプルなOAuth2 { #simple-oauth2-with-password-and-bearer }\n\n前章から発展させて、完全なセキュリティフローに必要な不足部分を追加していきます。\n\n## `username` と `password` を取得する { #get-the-username-and-password }\n\n`username` と `password` を取得するために **FastAPI** のセキュリティユーティリティを使います。\n\nOAuth2 では、「password flow」（ここで使用するフロー）を使う場合、クライアント/ユーザーはフォームデータとして `username` と `password` フィールドを送信する必要があります。\n\nしかも、フィールド名はこの通りでなければなりません。つまり、`user-name` や `email` では動作しません。\n\nただし、フロントエンドで最終ユーザーにどう表示するかは自由です。\n\nまた、データベースのモデルでは任意の別名を使って構いません。\n\nしかし、ログイン用の path operation では、仕様との互換性を保つ（たとえば組み込みのAPIドキュメントシステムを使えるようにする）ために、これらの名前を使う必要があります。\n\nまた、仕様では `username` と `password` はフォームデータとして送らなければならない（つまり、ここではJSONは使わない）ことも定められています。\n\n### `scope` { #scope }\n\n仕様では、クライアントは追加のフォームフィールド「`scope`」を送ることができるとも書かれています。\n\nフォームフィールド名は `scope`（単数形）ですが、実態はスペース区切りの「スコープ」文字列を並べた長い文字列です。\n\n各「スコープ」は（スペースを含まない）単なる文字列です。\n\n通常、特定のセキュリティ権限を宣言するために使われます。例えば:\n\n- `users:read` や `users:write` はよくある例です。\n- `instagram_basic` は Facebook / Instagram で使われます。\n- `https://www.googleapis.com/auth/drive` は Google で使われます。\n\n/// info | 情報\n\nOAuth2 における「スコープ」は、要求される特定の権限を表す単なる文字列です。\n\n`:` のような他の文字を含んでいても、URL であっても構いません。\n\nそれらの詳細は実装依存です。\n\nOAuth2 にとっては単なる文字列です。\n\n///\n\n## `username` と `password` を取得するコード { #code-to-get-the-username-and-password }\n\nでは、これを処理するために **FastAPI** が提供するユーティリティを使いましょう。\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\nまず、`OAuth2PasswordRequestForm` をインポートし、`/token` の path operation に `Depends` で依存関係として使います:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm` は次のフォームボディを宣言するクラス依存関係です:\n\n- `username`\n- `password`\n- スペース区切りの文字列で構成される、オプションの `scope` フィールド\n- オプションの `grant_type`\n\n/// tip | 豆知識\n\nOAuth2 の仕様では、固定値 `password` を持つフィールド `grant_type` が実際には必須ですが、`OAuth2PasswordRequestForm` はそれを強制しません。\n\n強制したい場合は、`OAuth2PasswordRequestForm` の代わりに `OAuth2PasswordRequestFormStrict` を使ってください。\n\n///\n\n- オプションの `client_id`（この例では不要）\n- オプションの `client_secret`（この例では不要）\n\n/// info | 情報\n\n`OAuth2PasswordRequestForm` は、`OAuth2PasswordBearer` のように **FastAPI** にとって特別なクラスではありません。\n\n`OAuth2PasswordBearer` は **FastAPI** にセキュリティスキームであることを認識させます。そのため OpenAPI にそのように追加されます。\n\n一方、`OAuth2PasswordRequestForm` は、あなた自身でも書けるような単なるクラス依存関係であり、直接 `Form` パラメータを宣言することもできます。\n\nただし一般的なユースケースなので、簡単に使えるよう **FastAPI** が直接提供しています。\n\n///\n\n### フォームデータの利用 { #use-the-form-data }\n\n/// tip | 豆知識\n\n依存関係クラス `OAuth2PasswordRequestForm` のインスタンスは、スペース区切りの長い文字列を持つ `scope` 属性は持ちません。代わりに、送られてきた各スコープの実際の文字列リストを格納する `scopes` 属性を持ちます。\n\nこの例では `scopes` は使いませんが、必要ならその機能が利用できます。\n\n///\n\n次に、フォームフィールドの `username` を使って（疑似の）データベースからユーザーデータを取得します。\n\nそのユーザーが存在しない場合は、「Incorrect username or password」というエラーを返します。\n\nエラーには `HTTPException` 例外を使います:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### パスワードのチェック { #check-the-password }\n\nこの時点でデータベースからユーザーデータは取得できましたが、まだパスワードを確認していません。\n\nまず、そのデータを Pydantic の `UserInDB` モデルに入れます。\n\nプレーンテキストのパスワードを保存してはいけないので、（疑似の）パスワードハッシュ化システムを使います。\n\nパスワードが一致しなければ、同じエラーを返します。\n\n#### パスワードハッシュ化 { #password-hashing }\n\n「ハッシュ化」とは、ある内容（ここではパスワード）を、乱雑に見えるバイト列（単なる文字列）に変換することを指します。\n\nまったく同じ内容（まったく同じパスワード）を渡すと、毎回まったく同じ乱雑な文字列が得られます。\n\nしかし、その乱雑な文字列から元のパスワードに戻すことはできません。\n\n##### なぜパスワードをハッシュ化するのか { #why-use-password-hashing }\n\nもしデータベースが盗まれても、盗んだ側が手にするのはユーザーのプレーンテキストのパスワードではなく、ハッシュだけです。\n\nしたがって、盗んだ側は同じパスワードを別のシステムで試すことができません（多くのユーザーがあらゆる場所で同じパスワードを使っているため、これは危険になり得ます）。\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### `**user_dict` について { #about-user-dict }\n\n`UserInDB(**user_dict)` は次を意味します:\n\n`user_dict` のキーと値を、そのままキーワード引数として渡します。つまり次と同等です:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info | 情報\n\n`**user_dict` のより完全な解説は、[**追加モデル**のドキュメント](../extra-models.md#about-user-in-dict)を参照してください。\n\n///\n\n## トークンを返す { #return-the-token }\n\n`token` エンドポイントのレスポンスは JSON オブジェクトでなければなりません。\n\n`token_type` を含める必要があります。ここでは「Bearer」トークンを使うので、トークンタイプは「`bearer`」です。\n\nそして `access_token` を含め、その中にアクセストークンの文字列を入れます。\n\nこの単純な例では、完全に安全ではありませんが、トークンとして同じ `username` をそのまま返します。\n\n/// tip | 豆知識\n\n次の章では、パスワードハッシュ化と <abbr title=\"JSON Web Tokens - JSON Web Token\">JWT</abbr> トークンを使った本当に安全な実装を見ます。\n\nしかし今は、必要な特定の詳細に集中しましょう。\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip | 豆知識\n\n仕様に従うと、この例と同じく `access_token` と `token_type` を含む JSON を返す必要があります。\n\nこれはあなた自身のコードで実装する必要があり、これらのJSONキーを使っていることを確認してください。\n\n仕様に準拠するために、あなた自身が正しく覚えて実装すべきことは、ほぼこれだけです。\n\nそれ以外は **FastAPI** が面倒を見てくれます。\n\n///\n\n## 依存関係の更新 { #update-the-dependencies }\n\nここで依存関係を更新します。\n\nアクティブなユーザーの場合にのみ `current_user` を取得したいとします。\n\nそこで、`get_current_active_user` を依存関係として利用する追加の依存関係 `get_current_active_user` を作成します。\n\nこれら2つの依存関係は、ユーザーが存在しない、または非アクティブである場合に、HTTPエラーを返すだけです。\n\nしたがって、エンドポイントでは、ユーザーが存在し、正しく認証され、かつアクティブである場合にのみ、ユーザーを取得します:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info | 情報\n\nここで返している値が `Bearer` の追加ヘッダー `WWW-Authenticate` も仕様の一部です。\n\nHTTP（エラー）ステータスコード 401「UNAUTHORIZED」は、`WWW-Authenticate` ヘッダーも返すことになっています。\n\nベアラートークン（今回のケース）の場合、そのヘッダーの値は `Bearer` であるべきです。\n\n実際のところ、この追加ヘッダーを省略しても動作はします。\n\nしかし、仕様に準拠するためにここでは付与しています。\n\nまた、（今または将来）それを想定して利用するツールがあるかもしれず、あなたやユーザーにとって有用になる可能性があります。\n\nこれが標準の利点です…。\n\n///\n\n## 動作確認 { #see-it-in-action }\n\nインタラクティブドキュメントを開きます: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n### 認証 { #authenticate }\n\n「Authorize」ボタンをクリックします。\n\n次の認証情報を使います:\n\nUser: `johndoe`\n\nPassword: `secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\nシステムで認証されると、次のように表示されます:\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### 自分のユーザーデータを取得 { #get-your-own-user-data }\n\n`GET` の path `/users/me` を使います。\n\n次のようなユーザーデータが取得できます:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\n錠前アイコンをクリックしてログアウトし、同じ操作を再度試すと、次のような HTTP 401 エラーになります:\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### 非アクティブユーザー { #inactive-user }\n\n今度は非アクティブなユーザーで試してみます。次で認証してください:\n\nUser: `alice`\n\nPassword: `secret2`\n\nそして `GET` の path `/users/me` を使います。\n\n次のような「Inactive user」エラーになります:\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## まとめ { #recap }\n\nこれで、API のために `username` と `password` に基づく完全なセキュリティシステムを実装するための道具が揃いました。\n\nこれらの道具を使えば、任意のデータベース、任意のユーザー/データモデルと互換性のあるセキュリティシステムを構築できます。\n\nただし、実際にはまだ「安全」ではありません。\n\n次の章では、安全なパスワードハッシュライブラリと <abbr title=\"JSON Web Tokens - JSON Web Token\">JWT</abbr> トークンの使い方を見ていきます。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/server-sent-events.md",
    "content": "# Server-Sent Events (SSE) { #server-sent-events-sse }\n\n**Server-Sent Events** (SSE) を使うと、クライアントへデータをストリーミングできます。\n\nこれは[JSON Lines のストリーミング](stream-json-lines.md)に似ていますが、`text/event-stream` フォーマットを使用します。これはブラウザがネイティブに [`EventSource` API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) でサポートしています。\n\n/// info | 情報\n\nFastAPI 0.135.0 で追加されました。\n\n///\n\n## Server-Sent Events とは { #what-are-server-sent-events }\n\nSSE は、HTTP 経由でサーバーからクライアントへデータをストリーミングするための標準です。\n\n各イベントは、`data`、`event`、`id`、`retry` などの「フィールド」を含む小さなテキストブロックで、空行で区切られます。\n\n次のようになります:\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE は、AI チャットのストリーミング、ライブ通知、ログやオブザビリティなど、サーバーがクライアントへ更新をプッシュする用途で一般的に使われます。\n\n/// tip | 豆知識\n\nバイナリデータ（例: 動画や音声）をストリーミングしたい場合は、上級ガイド [データのストリーミング](../advanced/stream-data.md) を参照してください。\n\n///\n\n## FastAPI で SSE をストリーミング { #stream-sse-with-fastapi }\n\nFastAPI で SSE をストリーミングするには、*path operation 関数*で `yield` を使い、`response_class=EventSourceResponse` を設定します。\n\n`EventSourceResponse` は `fastapi.sse` からインポートします:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\nyield された各アイテムは JSON にエンコードされ、SSE イベントの `data:` フィールドで送信されます。\n\n戻り値の型を `AsyncIterable[Item]` と宣言すると、FastAPI は Pydantic を用いてデータを**検証**、**ドキュメント化**、**シリアライズ**します。\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip | 豆知識\n\nPydantic が**Rust** 側でシリアライズを行うため、戻り値の型を宣言しない場合に比べて大幅に**高性能**になります。\n\n///\n\n### 非 async の *path operation 関数* { #non-async-path-operation-functions }\n\n通常の `def` 関数（`async` なし）も使用でき、同様に `yield` を使えます。\n\nイベントループをブロックしないよう、FastAPI が正しく実行されるように調整します。\n\nこの場合は関数が async ではないため、適切な戻り値の型は `Iterable[Item]` です:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### 戻り値の型なし { #no-return-type }\n\n戻り値の型を省略することもできます。FastAPI は [`jsonable_encoder`](./encoder.md) を使ってデータを変換し、送信します。\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\n`event`、`id`、`retry`、`comment` などの SSE フィールドを設定する必要がある場合は、生データの代わりに `ServerSentEvent` オブジェクトを `yield` できます。\n\n`ServerSentEvent` は `fastapi.sse` からインポートします:\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\n`data` フィールドは常に JSON にエンコードされます。Pydantic モデルを含む、JSON にシリアライズ可能な任意の値を渡せます。\n\n## 生データ { #raw-data }\n\nJSON エンコードせずにデータを送る必要がある場合は、`data` の代わりに `raw_data` を使用します。\n\nこれは、整形済みテキスト、ログ行、または `[DONE]` のような特別な <dfn title=\"特別な条件や状態を示すために用いられる値\">\"センチネル\"</dfn> 値を送るのに有用です。\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note | 備考\n\n`data` と `raw_data` は相互排他的です。各 `ServerSentEvent` ではどちらか一方しか設定できません。\n\n///\n\n## `Last-Event-ID` での再開 { #resuming-with-last-event-id }\n\n接続が途切れた後にブラウザが再接続すると、最後に受信した `id` を `Last-Event-ID` ヘッダーで送信します。\n\nこれをヘッダーパラメータとして受け取り、クライアントが離脱した位置からストリームを再開できます:\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## POST での SSE { #sse-with-post }\n\nSSE は `GET` だけでなく、**任意の HTTP メソッド**で動作します。\n\nこれは、`POST` 上で SSE をストリーミングする [MCP](https://modelcontextprotocol.io) のようなプロトコルで有用です:\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## 技術詳細 { #technical-details }\n\nFastAPI は SSE のいくつかのベストプラクティスを標準で実装しています。\n\n- メッセージがない場合は 15 秒ごとに「キープアライブ」用の `ping` コメントを送信し、一部のプロキシが接続を閉じるのを防ぎます（[HTML 仕様: Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes) の推奨に従います）。\n- ストリームの**キャッシュを防止**するため、`Cache-Control: no-cache` ヘッダーを設定します。\n- Nginx など一部のプロキシでの**バッファリングを防ぐ**ため、特別なヘッダー `X-Accel-Buffering: no` を設定します。\n\n追加の設定は不要で、そのまま動作します。🤓\n"
  },
  {
    "path": "docs/ja/docs/tutorial/sql-databases.md",
    "content": "# SQL（リレーショナル）データベース { #sql-relational-databases }\n\nFastAPI は SQL（リレーショナル）データベースの使用を必須にはしません。必要であれば、任意のデータベースを使用できます。\n\nここでは [SQLModel](https://sqlmodel.tiangolo.com/) を使った例を見ていきます。\n\nSQLModel は [SQLAlchemy](https://www.sqlalchemy.org/) と Pydantic の上に構築されています。FastAPI と同じ作者により、SQL データベースを使う必要がある FastAPI アプリに最適になるように作られています。\n\n/// tip | 豆知識\n\n他の任意の SQL あるいは NoSQL のデータベースライブラリ（場合によっては <abbr title=\"Object Relational Mapper - オブジェクト関係マッパー: いくつかのクラスが SQL テーブルを表し、そのインスタンスがそれらのテーブルの行を表すライブラリを指す専門用語\">\"ORMs\"</abbr> と呼ばれます）を使うこともできます。FastAPI は何も強制しません。😎\n\n///\n\nSQLModel は SQLAlchemy をベースにしているため、SQLAlchemy がサポートする任意のデータベース（SQLModel からもサポートされます）を簡単に使えます。例えば:\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server など\n\nこの例では、単一ファイルで動作し、Python に統合サポートがあるため、SQLite を使います。つまり、この例をそのままコピーして実行できます。\n\n本番アプリでは、PostgreSQL のようなデータベースサーバーを使いたくなるかもしれません。\n\n/// tip | 豆知識\n\nフロントエンドやその他のツールを含む、FastAPI と PostgreSQL の公式プロジェクトジェネレーターがあります: [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\nこれはとてもシンプルで短いチュートリアルです。データベースや SQL、より高度な機能について学びたい場合は、[SQLModel のドキュメント](https://sqlmodel.tiangolo.com/)をご覧ください。\n\n## `SQLModel` のインストール { #install-sqlmodel }\n\nまずは [仮想環境](../virtual-environments.md) を作成・有効化し、`sqlmodel` をインストールします:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## 単一モデルでアプリ作成 { #create-the-app-with-a-single-model }\n\nまずは最も簡単な、単一の SQLModel モデルだけを使うバージョンを作ります。\n\n後で、下記のとおり複数モデルにしてセキュリティと汎用性を高めます。🤓\n\n### モデルの作成 { #create-models }\n\n`SQLModel` をインポートしてデータベースモデルを作成します:\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\n`Hero` クラスは Pydantic モデルによく似ています（実際には内部的に Pydantic モデルでもあります）。\n\nいくつかの違いがあります:\n\n* `table=True` は SQLModel に対して「これはテーブルモデルであり、SQL データベースのテーブルを表す。単なるデータモデル（通常の Pydantic クラス）ではない」と伝えます。\n\n* `Field(primary_key=True)` は `id` が SQL データベースのプライマリキーであることを SQLModel に伝えます（SQL のプライマリキーについては SQLModel ドキュメントを参照してください）。\n\n    注: プライマリキーのフィールドには `int | None` を使っています。これは Python コード内で `id=None` のように「`id` なしでオブジェクトを作成」し、保存時にデータベースが生成することを想定するためです。SQLModel はデータベースが `id` を提供することを理解し、スキーマでは「NULL 不可の `INTEGER` 列」を定義します。詳細は [SQLModel のプライマリキーに関するドキュメント](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) を参照してください。\n\n* `Field(index=True)` は、この列に対して SQL のインデックスを作成するよう SQLModel に指示します。これにより、この列でフィルタしてデータを読む場合に検索が高速になります。\n\n    `str` と宣言されたものは、SQL の `TEXT`（データベースによっては `VARCHAR`）型の列になることを SQLModel は理解します。\n\n### Engine の作成 { #create-an-engine }\n\nSQLModel の `engine`（内部的には SQLAlchemy の `engine`）は、データベースへの接続を保持します。\n\n同じデータベースに接続するために、コード全体で 1 つの `engine` オブジェクトを共有します。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\n`check_same_thread=False` を使うと、FastAPI が異なるスレッドで同じ SQLite データベースを使えるようになります。これは、依存関係などにより 1 つのリクエストが複数スレッドを使う可能性があるため、必要です。\n\n心配はいりません。このコードの構成では、後で「1 リクエストにつき 1 つの SQLModel セッション」を確実に使うようにします。実際、`check_same_thread` はそれを実現しようとしています。\n\n### テーブルの作成 { #create-the-tables }\n\n`SQLModel.metadata.create_all(engine)` を使って、すべてのテーブルモデルのテーブルを作成する関数を追加します。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### Session 依存関係の作成 { #create-a-session-dependency }\n\n`Session` は、メモリ上でオブジェクトを保持して変更を追跡し、`engine` を使ってデータベースと通信します。\n\n各リクエストごとに新しい `Session` を提供する、`yield` を使った FastAPI の依存関係を作成します。これにより、1 リクエストにつき 1 つのセッションを使うことが保証されます。🤓\n\n続いて、この依存関係を使うコードを簡潔にするために、`Annotated` による依存関係 `SessionDep` を作成します。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### 起動時にテーブルを作成 { #create-database-tables-on-startup }\n\nアプリケーションの起動時にデータベースのテーブルを作成します。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\nここでは、アプリケーションのスタートアップイベントでテーブルを作成しています。\n\n本番では、アプリを起動する前にマイグレーションスクリプトを実行するのが一般的でしょう。🤓\n\n/// tip | 豆知識\n\nSQLModel は Alembic をラップしたマイグレーションユーティリティを提供予定ですが、現時点では [Alembic](https://alembic.sqlalchemy.org/en/latest/) を直接使えます。\n\n///\n\n### Hero の作成 { #create-a-hero }\n\n各 SQLModel モデルは Pydantic モデルでもあるため、Pydantic モデルと同じように型アノテーションで使えます。\n\n例えば、`Hero` 型のパラメータを宣言すると、JSON ボディから読み込まれます。\n\n同様に、関数の戻り値の型として宣言すると、そのデータ形状が自動 API ドキュメントの UI に表示されます。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\nここでは `SessionDep` 依存関係（`Session`）を使って、新しい `Hero` を `Session` インスタンスに追加し、データベースにコミットし、`hero` のデータをリフレッシュしてから返します。\n\n### Hero の取得 { #read-heroes }\n\n`select()` を使ってデータベースから `Hero` を取得できます。結果のページネーションのために `limit` と `offset` を含められます。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### 単一の Hero を取得 { #read-one-hero }\n\n単一の `Hero` を取得できます。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### Hero の削除 { #delete-a-hero }\n\n`Hero` を削除することもできます。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### アプリの起動 { #run-the-app }\n\nアプリを起動します:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nその後 `/docs` の UI にアクセスすると、FastAPI がこれらのモデルを使って API をドキュメント化し、同時にデータのシリアライズとバリデーションにも使っていることがわかります。\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## 複数モデルでアプリを更新 { #update-the-app-with-multiple-models }\n\nここで、少しリファクタリングしてセキュリティと汎用性を高めましょう。\n\n前のアプリでは、UI 上でクライアントが作成する `Hero` の `id` を自分で決められてしまいます。😱\n\nそれは許可すべきではありません。すでに DB で割り当て済みの `id` を上書きされる可能性があります。`id` の決定はクライアントではなく、バックエンドまたはデータベースが行うべきです。\n\nさらに、`secret_name` を作っていますが、現状ではそれをどこでも返してしまっています。これではあまり「シークレット」ではありません... 😅\n\nこれらを、いくつかの追加モデルで修正します。ここで SQLModel の真価が発揮されます。✨\n\n### 複数モデルの作成 { #create-multiple-models }\n\nSQLModel では、`table=True` のあるモデルクラスがテーブルモデルです。\n\n`table=True` のないモデルクラスはデータモデルで、実体は（小さな機能がいくつか追加された）Pydantic モデルです。🤓\n\nSQLModel では継承を使って、あらゆるケースでフィールドの重複を避けられます。\n\n#### `HeroBase` - ベースクラス { #herobase-the-base-class }\n\nまず、すべてのモデルで共有されるフィールドを持つ `HeroBase` モデルを作ります:\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` - テーブルモデル { #hero-the-table-model }\n\n次に、実際のテーブルモデルである `Hero` を作ります。他のモデルには常に含まれない追加フィールドを持ちます:\n\n* `id`\n* `secret_name`\n\n`Hero` は `HeroBase` を継承しているため、`HeroBase` で宣言されたフィールドも持ちます。つまり、`Hero` の全フィールドは次のとおりです:\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` - 公開用データモデル { #heropublic-the-public-data-model }\n\n次に、API のクライアントに返す `HeroPublic` モデルを作ります。\n\nこれは `HeroBase` と同じフィールドを持つため、`secret_name` は含みません。\n\nこれでヒーローの正体は守られます！🥷\n\nまた、`id: int` を再宣言します。これにより、API クライアントとの間で「常に `id` が存在し、`int` である（`None` にはならない）」という契約を結びます。\n\n/// tip | 豆知識\n\n戻り値のモデルで、値が常に存在し常に `int`（`None` ではない）であることを保証すると、API クライアント側のコードははるかにシンプルに書けます。\n\n加えて、自動生成クライアントのインターフェースも簡潔になり、あなたの API とやり取りする開発者体験が向上します。😎\n\n///\n\n`HeroPublic` のフィールドは `HeroBase` と同じで、`id` は `int`（`None` ではない）として宣言されます:\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` - 作成用データモデル { #herocreate-the-data-model-to-create-a-hero }\n\n次に、クライアントからのデータをバリデートする `HeroCreate` モデルを作ります。\n\nこれは `HeroBase` と同じフィールドに加え、`secret_name` も持ちます。\n\nこれで、クライアントが新しいヒーローを作成する際に `secret_name` を送信し、データベースに保存されますが、そのシークレット名は API ではクライアントに返されません。\n\n/// tip | 豆知識\n\nこれはパスワードを扱う際の方法と同じです。受け取りますが、API では返しません。\n\nまた、保存前にパスワードの値はハッシュ化し、平文のまま保存しないでください。\n\n///\n\n`HeroCreate` のフィールド:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` - 更新用データモデル { #heroupdate-the-data-model-to-update-a-hero }\n\n前のバージョンのアプリにはヒーローを更新する方法がありませんでしたが、複数モデルを使えば可能です。🎉\n\n`HeroUpdate` データモデルは少し特殊で、新しいヒーローを作成するのに必要なフィールドと同じフィールドをすべて持ちますが、すべてのフィールドがオプショナル（デフォルト値を持つ）です。これにより、更新時には変更したいフィールドだけを送れます。\n\nすべてのフィールドの型が実質的に変わる（`None` を含み、デフォルト値が `None` になる）ため、フィールドは再宣言する必要があります。\n\nすべてのフィールドを再宣言するので、厳密には `HeroBase` を継承する必要はありません。一貫性のためにここでは継承していますが、必須ではありません。好みの問題です。🤷\n\n`HeroUpdate` のフィールド:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### `HeroCreate` で作成し `HeroPublic` を返す { #create-with-herocreate-and-return-a-heropublic }\n\n複数モデルが用意できたので、それらを使うようにアプリの部分を更新します。\n\nリクエストでは `HeroCreate` データモデルを受け取り、そこから `Hero` テーブルモデルを作成します。\n\nこの新しいテーブルモデル `Hero` は、クライアントから送られたフィールドを持ち、データベースによって生成された `id` も持ちます。\n\n関数からはこのテーブルモデル `Hero` をそのまま返します。しかし `response_model` に `HeroPublic` データモデルを指定しているため、FastAPI が `HeroPublic` を使ってデータをバリデート・シリアライズします。\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | 豆知識\n\n今回は返却値の型アノテーション `-> HeroPublic` の代わりに `response_model=HeroPublic` を使います。返している値は実際には `HeroPublic` ではないためです。\n\nもし `-> HeroPublic` と宣言すると、エディタや Linter は（正しく）「`HeroPublic` ではなく `Hero` を返している」と警告します。\n\n`response_model` に指定することで、型アノテーションやエディタ等の補助を崩さずに、FastAPI にシリアライズの仕事を任せられます。\n\n///\n\n### `HeroPublic` で Hero を取得 { #read-heroes-with-heropublic }\n\n前と同様に `Hero` を取得できます。再び `response_model=list[HeroPublic]` を使って、データが正しくバリデート・シリアライズされることを保証します。\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### `HeroPublic` で単一の Hero を取得 { #read-one-hero-with-heropublic }\n\n単一のヒーローを取得します:\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### `HeroUpdate` で Hero を更新 { #update-a-hero-with-heroupdate }\n\nヒーローを更新できます。ここでは HTTP の `PATCH` を使います。\n\nコードでは、クライアントが送ったデータのみ（デフォルト値として入ってくる値は除外）を持つ `dict` を取得します。これには `exclude_unset=True` を使います。これが主なコツです。🪄\n\nその後、`hero_db.sqlmodel_update(hero_data)` を使って、`hero_db` を `hero_data` の内容で更新します。\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### 再度 Hero を削除 { #delete-a-hero-again }\n\nヒーローの削除はほとんど変わりません。\n\nここはリファクタリング欲求を満たさないままにしておきます。😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### アプリの再起動 { #run-the-app-again }\n\nアプリを再度起動します:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n`/docs` の API UI に行くと、内容が更新されており、ヒーロー作成時にクライアントから `id` を受け取ることは期待されていない、などが確認できます。\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## まとめ { #recap }\n\n[SQLModel](https://sqlmodel.tiangolo.com/) を使って SQL データベースとやり取りし、データモデルとテーブルモデルでコードを簡潔にできます。\n\nさらに多くを学ぶには SQLModel のドキュメントをご覧ください。[FastAPI と SQLModel を使うチュートリアル](https://sqlmodel.tiangolo.com/tutorial/fastapi/) もあります。🚀\n"
  },
  {
    "path": "docs/ja/docs/tutorial/static-files.md",
    "content": "# 静的ファイル { #static-files }\n\n`StaticFiles` を使用して、ディレクトリから静的ファイルを自動的に提供できます。\n\n## `StaticFiles` の使用 { #use-staticfiles }\n\n* `StaticFiles` をインポート。\n* `StaticFiles()` インスタンスを特定のパスに「マウント」。\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | 技術詳細\n\n`from starlette.staticfiles import StaticFiles` も使用できます。\n\n**FastAPI**は、開発者の利便性のために、`starlette.staticfiles` と同じ `fastapi.staticfiles` を提供します。しかし、実際にはStarletteから直接渡されています。\n\n///\n\n### 「マウント」とは { #what-is-mounting }\n\n「マウント」とは、特定のパスに完全な「独立した」アプリケーションを追加することを意味します。これにより、すべてのサブパスの処理がなされます。\n\nこれは、マウントされたアプリケーションが完全に独立しているため、`APIRouter` とは異なります。メインアプリケーションのOpenAPIとドキュメントには、マウントされたアプリケーションの内容などは含まれません。\n\nこれについて詳しくは、[高度なユーザーガイド](../advanced/index.md) をご覧ください。\n\n## 詳細 { #details }\n\n最初の `\"/static\"` は、この「サブアプリケーション」が「マウント」されるサブパスを指します。したがって、`\"/static\"` から始まるパスはすべてサブアプリケーションによって処理されます。\n\n`directory=\"static\"` は、静的ファイルを含むディレクトリの名前を指します。\n\n`name=\"static\"` は、**FastAPI** が内部で使用できる名前を付けます。\n\nこれらのパラメータはすべて「`static`」とは異なる場合があり、独自のアプリケーションのニーズと詳細に合わせて調整します。\n\n## より詳しい情報 { #more-info }\n\n詳細とオプションについては、[Starletteの静的ファイルに関するドキュメント](https://www.starlette.dev/staticfiles/)を確認してください。\n"
  },
  {
    "path": "docs/ja/docs/tutorial/stream-json-lines.md",
    "content": "# JSON Lines をストリームする { #stream-json-lines }\n\nデータのシーケンスを**「ストリーム」**で送りたい場合、**JSON Lines** を使って実現できます。\n\n/// info | 情報\n\nFastAPI 0.134.0 で追加されました。\n\n///\n\n## ストリームとは { #what-is-a-stream }\n\nデータを**ストリーミング**するとは、アイテムの全シーケンスが用意できるのを待たずに、アプリがデータアイテムの送信をクライアントに対して開始することを意味します。\n\nつまり、最初のアイテムを送信し、クライアントはそれを受け取って処理を始めます。その間に、次のアイテムをまだ生成しているかもしれません。\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\nデータを送り続ける無限ストリームにすることもできます。\n\n## JSON Lines { #json-lines }\n\nこのような場合、1 行に 1 つの JSON オブジェクトを送る「**JSON Lines**」形式を使うのが一般的です。\n\nレスポンスの content type は `application/jsonl`（`application/json` の代わり）となり、ボディは次のようになります:\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\nこれは JSON 配列（Python の list に相当）にとてもよく似ていますが、`[]` で囲まず、アイテム間の `,` もありません。その代わりに、**1 行に 1 つの JSON オブジェクト**で、改行文字で区切られます。\n\n/// info | 情報\n\n重要な点は、クライアントが前の行を消費している間に、アプリ側は次の行を順次生成して送れることです。\n\n///\n\n/// note | 技術詳細\n\n各 JSON オブジェクトは改行で区切られるため、内容にリテラルな改行文字は含められません。ですが、エスケープした改行（`\\n`）は含められます。これは JSON 標準の一部です。\n\nとはいえ、通常は気にする必要はありません。自動で処理されますので、読み進めてください。🤓\n\n///\n\n## ユースケース { #use-cases }\n\nこれは **AI LLM** サービス、**ログ**や**テレメトリ**、あるいは **JSON** アイテムとして構造化できる他の種類のデータをストリームするのに使えます。\n\n/// tip | 豆知識\n\n動画や音声などのバイナリデータをストリームしたい場合は、上級ガイドを参照してください: [データのストリーム](../advanced/stream-data.md)。\n\n///\n\n## FastAPI で JSON Lines をストリームする { #stream-json-lines-with-fastapi }\n\nFastAPI で JSON Lines をストリームするには、*path operation 関数*で `return` を使う代わりに、`yield` を使って各アイテムを順に生成します。\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\n送り返す各 JSON アイテムが `Item`（Pydantic モデル）型で、関数が async の場合、戻り値の型を `AsyncIterable[Item]` と宣言できます:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\n戻り値の型を宣言すると、FastAPI はそれを使ってデータを**検証**し、OpenAPI に**ドキュメント化**し、**フィルター**し、Pydantic で**シリアライズ**します。\n\n/// tip | 豆知識\n\nPydantic は **Rust** 側でシリアライズを行うため、戻り値の型を宣言しない場合に比べて大幅に高い**パフォーマンス**が得られます。\n\n///\n\n### 非 async の *path operation 関数* { #non-async-path-operation-functions }\n\n`async` を使わない通常の `def` 関数でも同様に `yield` を使えます。\n\nFastAPI が適切に実行されるように処理するため、イベントループをブロックしません。\n\nこの場合は関数が async ではないので、適切な戻り値の型は `Iterable[Item]` です:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### 戻り値の型なし { #no-return-type }\n\n戻り値の型を省略することもできます。FastAPI はその場合、データを JSON にシリアライズ可能な形に変換するために [`jsonable_encoder`](./encoder.md) を使い、JSON Lines として送信します。\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## Server-Sent Events (SSE) { #server-sent-events-sse }\n\nFastAPI は Server-Sent Events (SSE) にもファーストクラスで対応しています。とても似ていますが、いくつか追加の詳細があります。次の章で学べます: [Server-Sent Events (SSE)](server-sent-events.md)。🤓\n"
  },
  {
    "path": "docs/ja/docs/tutorial/testing.md",
    "content": "# テスト { #testing }\n\n[Starlette](https://www.starlette.dev/testclient/) のおかげで、**FastAPI** アプリケーションのテストは簡単で楽しいものになっています。\n\n[HTTPX](https://www.python-httpx.org) がベースで、さらにその設計は Requests をベースにしているため、とても馴染みがあり直感的です。\n\nこれを使用すると、**FastAPI** と共に [pytest](https://docs.pytest.org/) を直接利用できます。\n\n## `TestClient` を使用 { #using-testclient }\n\n/// info\n\n`TestClient` を使用するには、まず [`httpx`](https://www.python-httpx.org) をインストールします。\n\n[仮想環境](../virtual-environments.md) を作成し、それを有効化してから、例えば以下のようにインストールしてください:\n\n```console\n$ pip install httpx\n```\n\n///\n\n`TestClient` をインポートします。\n\n`TestClient` を作成し、**FastAPI** に渡します。\n\n`test_` から始まる名前の関数を作成します (これは `pytest` の標準的なコンベンションです)。\n\n`httpx` と同じ様に `TestClient` オブジェクトを使用します。\n\nチェックしたい Python の標準的な式と共に、シンプルに `assert` 文を記述します (これも `pytest` の標準です)。\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip\n\nテスト関数は `async def` ではなく、通常の `def` であることに注意してください。\n\nまた、クライアントへの呼び出しも通常の呼び出しであり、`await` を使用しません。\n\nこれにより、煩雑にならずに、`pytest` を直接使用できます。\n\n///\n\n/// note | 技術詳細\n\n`from starlette.testclient import TestClient` も使用できます。\n\n**FastAPI** は開発者の利便性のために `fastapi.testclient` と同じ `starlette.testclient` を提供します。しかし、実際にはStarletteから直接渡されています。\n\n///\n\n/// tip\n\nFastAPIアプリケーションへのリクエストの送信とは別に、テストで `async` 関数 (非同期データベース関数など) を呼び出したい場合は、高度なチュートリアルの[Async Tests](../advanced/async-tests.md) を参照してください。\n\n///\n\n## テストの分離 { #separating-tests }\n\n実際のアプリケーションでは、おそらくテストを別のファイルに保存します。\n\nまた、**FastAPI** アプリケーションは、複数のファイル/モジュールなどで構成されている場合もあります。\n\n### **FastAPI** アプリファイル { #fastapi-app-file }\n\n[Bigger Applications](bigger-applications.md) で説明されている、次のようなファイル構成があるとします:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\nファイル `main.py` に **FastAPI** アプリがあります:\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### テストファイル { #testing-file }\n\n次に、テストを含む `test_main.py` ファイルを用意できます。これは同じ Python パッケージ (`__init__.py` ファイルがある同じディレクトリ) に置けます:\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nこのファイルは同じパッケージ内にあるため、相対インポートを使って `main` モジュール (`main.py`) からオブジェクト `app` をインポートできます:\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n\n...そして、これまでと同じようにテストコードを書けます。\n\n## テスト: 例の拡張 { #testing-extended-example }\n\n次に、この例を拡張し、詳細を追加して、さまざまなパーツをテストする方法を確認しましょう。\n\n### 拡張版 **FastAPI** アプリファイル { #extended-fastapi-app-file }\n\n先ほどと同じファイル構成で続けます:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nここで、**FastAPI** アプリがある `main.py` ファイルには、他の path operation があります。\n\nエラーを返す可能性のある `GET` オペレーションがあります。\n\nいくつかのエラーを返す可能性のある `POST` オペレーションもあります。\n\n両方の *path operation* には `X-Token` ヘッダーが必要です。\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### 拡張版テストファイル { #extended-testing-file }\n\n次に、拡張版のテストで `test_main.py` を更新できます:\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\n\nリクエストに情報を渡せるクライアントが必要で、その方法がわからない場合はいつでも、`httpx` での実現方法、あるいは HTTPX の設計が Requests の設計をベースにしているため `requests` での実現方法を検索 (Google) できます。\n\nテストでも同じことを行います。\n\n例えば:\n\n* *パス* または *クエリ* パラメータを渡すには、それをURL自体に追加します。\n* JSONボディを渡すには、Pythonオブジェクト (例: `dict`) を `json` パラメータに渡します。\n* JSONの代わりに *フォームデータ* を送信する必要がある場合は、代わりに `data` パラメータを使用してください。\n* *ヘッダー* を渡すには、`headers` パラメータに `dict` を渡します。\n* *cookies* の場合、 `cookies` パラメータに `dict` です。\n\n(`httpx` または `TestClient` を使用して) バックエンドにデータを渡す方法の詳細は、[HTTPXのドキュメント](https://www.python-httpx.org)を確認してください。\n\n/// info\n\n`TestClient` は、Pydanticモデルではなく、JSONに変換できるデータを受け取ることに注意してください。\n\nテストにPydanticモデルがあり、テスト中にそのデータをアプリケーションに送信したい場合は、[JSON互換エンコーダ](encoder.md) で説明されている `jsonable_encoder` が利用できます。\n\n///\n\n## 実行 { #run-it }\n\nその後、`pytest` をインストールするだけです。\n\n[仮想環境](../virtual-environments.md) を作成し、それを有効化してから、例えば以下のようにインストールしてください:\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\nファイルとテストを自動的に検出し、実行して、結果のレポートを返します。\n\n以下でテストを実行します:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/ja/docs/virtual-environments.md",
    "content": "# 仮想環境 { #virtual-environments }\n\nPythonプロジェクトの作業では、**仮想環境**（または類似の仕組み）を使用し、プロジェクトごとにインストールするパッケージを分離するべきでしょう。\n\n/// info | 情報\n\nもし、仮想環境の概要や作成方法、使用方法について既にご存知なら、このセクションをスキップした方がよいかもしれません。🤓\n\n///\n\n/// tip | 豆知識\n\n**仮想環境**は、**環境変数**とは異なります。\n\n**環境変数**は、プログラムが使用できるシステム内の変数です。\n\n**仮想環境**は、ファイルをまとめたディレクトリのことです。\n\n///\n\n/// info | 情報\nこのページでは、**仮想環境**の使用方法と、そのはたらきについて説明します。\n\nもし**すべてを管理するツール**（Pythonのインストールも含む）を導入する準備ができているなら、[uv](https://github.com/astral-sh/uv) をお試しください。\n\n///\n\n## プロジェクトの作成 { #create-a-project }\n\nまず、プロジェクト用のディレクトリを作成します。\n\n私は通常 home/user ディレクトリの中に `code` というディレクトリを用意していて、プロジェクトごとに1つのディレクトリをその中に作成しています。\n\n<div class=\"termy\">\n\n```console\n// Go to the home directory\n$ cd\n// Create a directory for all your code projects\n$ mkdir code\n// Enter into that code directory\n$ cd code\n// Create a directory for this project\n$ mkdir awesome-project\n// Enter into that project directory\n$ cd awesome-project\n```\n\n</div>\n\n## 仮想環境の作成 { #create-a-virtual-environment }\n\nPythonプロジェクトでの**初めての**作業を開始する際には、**<dfn title=\"他の選択肢もありますが、これはシンプルなガイドラインです\">プロジェクト内</dfn>**に仮想環境を作成してください。\n\n/// tip | 豆知識\n\nこれを行うのは、**プロジェクトごとに1回だけ**です。作業のたびに行う必要はありません。\n\n///\n\n//// tab | `venv`\n\n仮想環境を作成するには、Pythonに付属している `venv` モジュールを使用できます。\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | このコマンドの意味\n\n* `python`: `python` というプログラムを呼び出します\n* `-m`: モジュールをスクリプトとして呼び出します。どのモジュールを呼び出すのか、この次に指定します\n* `venv`: 通常Pythonに付随してインストールされる `venv`モジュールを使用します\n* `.venv`: 仮想環境を`.venv`という新しいディレクトリに作成します\n\n///\n\n////\n\n//// tab | `uv`\n\nもし [`uv`](https://github.com/astral-sh/uv) をインストール済みなら、仮想環境を作成するために `uv` を使うこともできます。\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip | 豆知識\n\nデフォルトでは、 `uv` は `.venv` というディレクトリに仮想環境を作成します。\n\nただし、追加の引数にディレクトリ名を与えてカスタマイズすることもできます。\n\n///\n\n////\n\nこのコマンドは `.venv` というディレクトリに新しい仮想環境を作成します。\n\n/// details | `.venv` またはその他の名前\n\n仮想環境を別のディレクトリに作成することも可能ですが、 `.venv` と名付けるのが一般的な慣習です。\n\n///\n\n## 仮想環境の有効化 { #activate-the-virtual-environment }\n\n実行されるPythonコマンドやインストールされるパッケージが新しく作成した仮想環境を使用するよう、その仮想環境を有効化しましょう。\n\n/// tip | 豆知識\n\nそのプロジェクトの作業で**新しいターミナルセッション**を開始する際には、**毎回**有効化してください。\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nもしWindowsでBashを使用している場合 ([Git Bash](https://gitforwindows.org/)など):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip | 豆知識\n\n**新しいパッケージ**を仮想環境にインストールするたびに、環境をもう一度**有効化**してください。\n\nこうすることで、そのパッケージがインストールした**ターミナル（<abbr title=\"command line interface - コマンドラインインターフェース\">CLI</abbr>）プログラム**を使用する場合に、仮想環境内のものが確実に使われ、グローバル環境にインストールされている別のもの（おそらく必要なものとは異なるバージョン）を誤って使用することを防ぎます。\n\n///\n\n## 仮想環境が有効であることを確認する { #check-the-virtual-environment-is-active }\n\n仮想環境が有効である（前のコマンドが正常に機能した）ことを確認します。\n\n/// tip | 豆知識\n\nこれは**任意**ですが、すべてが期待通りに機能し、意図した仮想環境を使用していることを**確認する**良い方法です。\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n`.venv/bin/python` にある `python` バイナリが、プロジェクト（この場合は `awesome-project` ）内に表示されていれば、正常に動作しています 🎉。\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n`.venv\\Scripts\\python` にある `python` バイナリが、プロジェクト（この場合は `awesome-project` ）内に表示されていれば、正常に動作しています 🎉。\n\n////\n\n## `pip` をアップグレードする { #upgrade-pip }\n\n/// tip | 豆知識\n\nもし [`uv`](https://github.com/astral-sh/uv) を使用している場合は、 `pip` の代わりに `uv` を使ってインストールを行うため、 `pip` をアップグレードする必要はありません 😎。\n\n///\n\nもしパッケージのインストールに `pip`（Pythonに標準で付属しています）を使用しているなら、 `pip` を最新バージョンに**アップグレード**しましょう。\n\nパッケージのインストール中に発生する想定外のエラーの多くは、最初に `pip` をアップグレードしておくだけで解決されます。\n\n/// tip | 豆知識\n\n通常、これは仮想環境を作成した直後に**一度だけ**実行します。\n\n///\n\n仮想環境が有効であることを（上で説明したコマンドで）確認し、アップグレードを実行しましょう：\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip | 豆知識\n\nときどき、pip をアップグレードしようとすると **`No module named pip`** エラーが表示されることがあります。\n\nその場合は、以下のコマンドで pip をインストールしてアップグレードしてください:\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\nこのコマンドは、pip がまだインストールされていなければ pip をインストールし、また、インストールされる pip のバージョンが `ensurepip` で利用可能なもの以上に新しいことも保証します。\n\n///\n\n## `.gitignore` を追加する { #add-gitignore }\n\n**Git**を使用している場合（使用するべきでしょう）、 `.gitignore` ファイルを追加して、 `.venv` 内のあらゆるファイルをGitの管理対象から除外します。\n\n/// tip | 豆知識\n\nもし [`uv`](https://github.com/astral-sh/uv) を使用して仮想環境を作成した場合、すでにこの作業は済んでいるので、この手順をスキップできます 😎。\n\n///\n\n/// tip | 豆知識\n\nこれも、仮想環境を作成した直後に**一度だけ**実行します。\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | このコマンドの意味\n\n* `echo \"*\"`: ターミナルに `*` というテキストを「表示」しようとします。（次の部分によってその動作が少し変わります）\n* `>`: `>` の左側のコマンドがターミナルに表示しようとする内容を、ターミナルには表示せず、 `>` の右側のファイルに書き込みます。\n* `.gitignore`: `*` を書き込むファイル名。\n\nここで、Gitにおける `*` は「すべて」を意味するので、このコマンドによって `.venv` ディレクトリ内のすべてがGitに無視されるようになります。\n\nこのコマンドは以下のテキストを持つ `.gitignore` ファイルを作成します：\n\n```gitignore\n*\n```\n\n///\n\n## パッケージのインストール { #install-packages }\n\n仮想環境を有効化した後、その中でパッケージをインストールできます。\n\n/// tip | 豆知識\n\nプロジェクトに必要なパッケージをインストールまたはアップグレードする場合、これを**一度**実行します。\n\nもし新しいパッケージを追加したり、バージョンをアップグレードする必要がある場合は、もう**一度この手順を繰り返し**ます。\n\n///\n\n### パッケージを直接インストールする { #install-packages-directly }\n\n急いでいて、プロジェクトのパッケージ要件を宣言するファイルを使いたくない場合、パッケージを直接インストールできます。\n\n/// tip | 豆知識\n\nプログラムが必要とするパッケージとバージョンをファイル（例えば `requirements.txt` や `pyproject.toml` ）に記載しておくのは、（とても）良い考えです。\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nもし [`uv`](https://github.com/astral-sh/uv) を使用できるなら:\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### `requirements.txt` からインストールする { #install-from-requirements-txt }\n\nもし `requirements.txt` があるなら、パッケージのインストールに使用できます。\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nもし [`uv`](https://github.com/astral-sh/uv) を使用できるなら:\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\nパッケージが記載された `requirements.txt` は以下のようになっています:\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## プログラムを実行する { #run-your-program }\n\n仮想環境を有効化した後、プログラムを実行できます。この際、仮想環境内のPythonと、そこにインストールしたパッケージが使用されます。\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## エディタの設定 { #configure-your-editor }\n\nプロジェクトではおそらくエディタを使用するでしょう。コード補完やインラインエラーの表示ができるように、作成した仮想環境をエディタでも使えるよう設定してください。（多くの場合、自動検出されます）\n\n設定例:\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip | 豆知識\n\nこの設定は通常、仮想環境を作成した際に**一度だけ**行います。\n\n///\n\n## 仮想環境の無効化 { #deactivate-the-virtual-environment }\n\nプロジェクトの作業が終了したら、その仮想環境を**無効化**できます。\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\nこれにより、 `python` コマンドを実行しても、そのプロジェクト用（のパッケージがインストールされた）仮想環境から `python` プログラムを呼び出そうとはしなくなります。\n\n## 作業準備完了 { #ready-to-work }\n\nこれで、プロジェクトの作業を始める準備が整いました。\n\n\n\n/// tip | 豆知識\n\n上記の内容を理解したいですか？\n\nもしそうなら、以下を読み進めてください。👇🤓\n\n///\n\n## なぜ仮想環境？ { #why-virtual-environments }\n\nFastAPIを使った作業をするには、[Python](https://www.python.org/) のインストールが必要です。\n\nそれから、FastAPIや、使用したいその他の**パッケージ**を**インストール**する必要があります。\n\nパッケージをインストールするには、通常、Python に付属する `pip` コマンド (または同様の代替コマンド) を使用します。\n\nただし、`pip` を直接使用すると、パッケージは**グローバルなPython環境**（OS全体にインストールされたPython環境）にインストールされます。\n\n### 問題点 { #the-problem }\n\nでは、グローバルPython環境にパッケージをインストールすることの問題点は何でしょうか？\n\nある時点で、あなたは**異なるパッケージ**に依存する多くのプログラムを書くことになるでしょう。そして、これらの中には同じパッケージの**異なるバージョン**に依存するものも出てくるでしょう。😱\n\n例えば、 `philosophers-stone` （賢者の石）というプロジェクトを作成するとします。このプログラムは **`harry` （ハリー）というパッケージのバージョン `1`**に依存しています。そのため、 `harry` （ハリー）をインストールする必要があります。\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n\nそれから、 `prisoner-of-azkaban` （アズカバンの囚人）という別のプロジェクトを作成したとします。このプロジェクトも `harry` （ハリー）に依存していますが、**`harry` （ハリー）のバージョン `3`**が必要です。\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]\n```\n\nしかし、ここで問題になるのは、もしローカルの**仮想環境**ではなくグローバル（環境）にパッケージをインストールするなら、 `harry` （ハリー）のどのバージョンをインストールするか選ばないといけないことです。\n\n例えば、 `philosophers-stone` （賢者の石）を実行するには、まず `harry` （ハリー）のバージョン `1` をインストールする必要があります：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\nこれにより、`harry` （ハリー）バージョン1がグローバルなPython環境にインストールされます。\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\nしかし、 `prisoner-of-azkaban` （アズカバンの囚人）を実行したい場合は、`harry` （ハリー）のバージョン `1` をアンインストールし、`harry` （ハリー）のバージョン `3` をインストールし直す必要があります。（あるいは、単に`harry` （ハリー）のバージョン `3` をインストールすることで、自動的にバージョン `1` がアンインストールされます）\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\nこのようにして、グローバル環境への `harry` （ハリー）のバージョン `3` のインストールが完了します。\n\nそれから、 `philosophers-stone` （賢者の石）を再び実行しようとすると、このプログラムは `harry` （ハリー）のバージョン `1` が必要なため、**動作しなくなる**可能性があります。\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --> |requires| harry-3\n    end\n```\n\n/// tip | 豆知識\n\nPythonのパッケージでは、**新しいバージョン**で**互換性を損なう変更を避ける**よう努めるのが一般的ですが、それでも注意が必要です。すべてが正常に動作することをテストで確認してから、意図的に指定して新しいバージョンをインストールするのが良いでしょう。\n\n///\n\nあなたのすべての**プロジェクトが依存している**、**多数の**他の**パッケージ**が上記の問題を抱えていると想像してください。これは管理が非常に困難です。そして、**互換性のないバージョン**のパッケージを使ってプロジェクトを実行し、なぜ動作しないのか分からなくなるでしょう。\n\nまた、使用しているOS（Linux、Windows、macOS など）によっては、Pythonがすでにインストールされていることがあります。この場合、特定のバージョンのパッケージが**OSの動作に必要である**ことがあります。グローバル環境にパッケージをインストールすると、OSに付属するプログラムを**壊してしまう**可能性があります。\n\n## パッケージのインストール先 { #where-are-packages-installed }\n\nPythonをインストールしたとき、ファイルを含んだいくつかのディレクトリが作成されます。\n\nこれらの中には、インストールされたパッケージを保存するためのものもあります。\n\n以下のコマンドを実行したとき：\n\n<div class=\"termy\">\n\n```console\n// Don't run this now, it's just an example 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\nFastAPIのコードを含む圧縮ファイルが、通常は [PyPI](https://pypi.org/project/fastapi/) からダウンロードされます。\n\nまた、FastAPIが依存する他のパッケージも**ダウンロード**されます。\n\nそれから、これらのファイルは**解凍**され、コンピュータのあるディレクトリに配置されます。\n\nデフォルトでは、これらのファイルはPythonのインストール時に作成されるディレクトリ、つまり**グローバル環境**に配置されます。\n\n## 仮想環境とは { #what-are-virtual-environments }\n\nすべてのパッケージをグローバル環境に配置することによって生じる問題の解決策は、作業する**プロジェクトごとの仮想環境**を使用することです。\n\n仮想環境は**ディレクトリ**であり、グローバル環境と非常に似ていて、一つのプロジェクトで使う特定のパッケージ群をインストールできる場所です。\n\nこのようにして、それぞれのプロジェクトが独自の仮想環境（`.venv` ディレクトリ）に独自のパッケージ群を持つことができます。\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) --->|requires| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --->|requires| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## 仮想環境の有効化とは { #what-does-activating-a-virtual-environment-mean }\n\n仮想環境を有効にしたとき、例えば次のコマンドを実行した場合を考えます：\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nあるいは、WindowsでBashを使用している場合 ([Git Bash](https://gitforwindows.org/)など):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\nこれによって、いくつかの [環境変数](environment-variables.md) が作成・修正され、次に実行されるコマンドで使用できるようになります。\n\nこれらの環境変数のひとつに、 `PATH` 変数があります。\n\n/// tip | 豆知識\n\n`PATH` 変数についての詳細は [環境変数](environment-variables.md#path-environment-variable) を参照してください。\n\n///\n\n仮想環境を有効にすると、その仮想環境のパス `.venv/bin` （LinuxとmacOS）、あるいは `.venv\\Scripts` （Windows）が `PATH` 変数に追加されます。\n\nその環境を有効にする前の `PATH` 変数が次のようになっているとします。\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nこれは、OSが以下のディレクトリ中でプログラムを探すことを意味します：\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\nこれは、OSが以下のディレクトリ中でプログラムを探すことを意味します：\n\n* `C:\\Windows\\System32`\n\n////\n\n仮想環境を有効にすると、 `PATH` 変数は次のようになります。\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nこれは、OSが他のディレクトリを探すより前に、最初に以下のディレクトリ中でプログラムを探し始めることを意味します：\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\nそのため、ターミナルで `python` と入力した際に、OSはPythonプログラムを以下のパスで発見し、使用します。\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\nこれは、OSが他のディレクトリを探すより前に、最初に以下のディレクトリ中でプログラムを探し始めることを意味します：\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\nそのため、ターミナルで `python` と入力した際に、OSはPythonプログラムを以下のパスで発見し、使用します。\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n////\n\n重要な点は、仮想環境のパスを `PATH` 変数の**先頭**に配置することです。OSは利用可能な他のPythonを見つけるより**前に**、この仮想環境のPythonを見つけるようになります。このようにして、 `python` を実行したときに、他の `python` （例えばグローバル環境の `python` ）ではなく、**その仮想環境の**Pythonを使用するようになります。\n\n仮想環境を有効にして変更されることは他にもありますが、これが最も重要な変更のひとつです。\n\n## 仮想環境の確認 { #checking-a-virtual-environment }\n\n仮想環境が有効かどうか、例えば次のように確認できます。：\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\nこれは、使用される `python` プログラムが**その仮想環境の**ものであることを意味します。\n\nLinuxやmacOSでは `which` を、Windows PowerShellでは `Get-Command` を使用します。\n\nこのコマンドの動作は、 `PATH`変数に設定された**それぞれのパスを順に**確認していき、呼ばれている `python` プログラムを探します。そして、見つかり次第そのプログラムへの**パスを表示します**。\n\n最も重要なことは、 `python` が呼ばれたときに、まさにこのコマンドで確認した \"`python`\" が実行されることです。\n\nこうして、自分が想定通りの仮想環境にいるかを確認できます。\n\n/// tip | 豆知識\n\nある仮想環境を有効にし、そのPythonを使用したまま**他のプロジェクトに移動して**しまうことは簡単に起こり得ます。\n\nそして、その第二のプロジェクトは動作しないでしょう。なぜなら別のプロジェクトの仮想環境の**誤ったPython**を使用しているからです。\n\nそのため、どの `python` が使用されているのか確認できることは役立ちます。🤓\n\n///\n\n## なぜ仮想環境を無効化するのか { #why-deactivate-a-virtual-environment }\n\n例えば、`philosophers-stone` （賢者の石）というプロジェクトで作業をしていて、**その仮想環境を有効にし**、必要なパッケージをインストールしてその環境内で作業を進めているとします。\n\nそれから、**別のプロジェクト**、 `prisoner-of-azkaban` （アズカバンの囚人）に取り掛かろうとします。\n\nそのプロジェクトディレクトリへ移動します：\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\nもし `philosophers-stone` （賢者の石）の仮想環境を無効化していないと、`python` を実行したとき、 ターミナルは `philosophers-stone` （賢者の石）のPythonを使用しようとします。\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// Error importing sirius, it's not installed 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\nしかし、その仮想環境を無効化し、 `prisoner-of-askaban` のための新しい仮想環境を有効にすれば、 `python` を実行したときに `prisoner-of-azkaban` （アズカバンの囚人）の仮想環境の Python が使用されるようになります。\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// You don't need to be in the old directory to deactivate, you can do it wherever you are, even after going to the other project 😎\n$ deactivate\n\n// Activate the virtual environment in prisoner-of-azkaban/.venv 🚀\n$ source .venv/bin/activate\n\n// Now when you run python, it will find the package sirius installed in this virtual environment ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## 代替手段 { #alternatives }\n\nこれは、あらゆる仕組みを**根本から**学ぶためのシンプルな入門ガイドです。\n\n仮想環境、パッケージの依存関係（requirements）、プロジェクトの管理には、多くの**代替手段**があります。\n\n準備が整い、パッケージの依存関係、仮想環境など**プロジェクト全体の管理**ツールを使いたいと考えたら、[uv](https://github.com/astral-sh/uv) を試してみることをおすすめします。\n\n`uv` では以下のような多くのことができます：\n\n* 異なるバージョンも含めた**Python のインストール**\n* プロジェクトごとの**仮想環境**の管理\n* **パッケージ**のインストール\n* プロジェクトのパッケージの**依存関係やバージョン**の管理\n* パッケージとそのバージョンの、依存関係を含めた**厳密な**組み合わせを保持し、これによって、本番環境で、開発環境と全く同じようにプロジェクトを実行できる（これは**locking**と呼ばれます）\n* その他のさまざまな機能\n\n## まとめ { #conclusion }\n\nここまで読みすべて理解したなら、世間の多くの開発者と比べて、仮想環境について**あなたはより多くのことを知っています**。🤓\n\nこれらの詳細を知ることは、将来、複雑に見える何かのデバッグにきっと役立つでしょう。しかし、その頃には、あなたは**そのすべての動作を根本から**理解しているでしょう。😎\n"
  },
  {
    "path": "docs/ja/llm-prompt.md",
    "content": "### Target language\n\nTranslate to Japanese (日本語).\n\nLanguage code: ja.\n\n### Grammar and tone\n\n- Use polite, instructional Japanese (です/ます調).\n- Keep the tone concise and technical (match existing Japanese FastAPI docs).\n\n### Headings\n\n- Follow the existing Japanese style: short, descriptive headings (often noun phrases), e.g. 「チェック」.\n- Do not add a trailing period at the end of headings.\n\n### Quotes\n\n- Prefer Japanese corner brackets 「」 in normal prose when quoting a term.\n- Do not change quotes inside inline code, code blocks, URLs, or file paths.\n\n### Ellipsis\n\n- Keep ellipsis style consistent with existing Japanese docs (commonly `...`).\n- Never change `...` in code, URLs, or CLI examples.\n\n### Preferred translations / glossary\n\nUse the following preferred translations when they apply in documentation prose:\n\n- request (HTTP): リクエスト\n- response (HTTP): レスポンス\n- path operation: path operation (do not translate)\n\n### `///` admonitions\n\n1) Keep the admonition keyword in English (do not translate `note`, `tip`, etc.).\n2) If a title is present, prefer these canonical titles:\n\n- `/// note | 備考`\n- `/// note | 技術詳細`\n- `/// tip | 豆知識`\n- `/// warning | 注意`\n- `/// info | 情報`\n- `/// check | 確認`\n- `/// danger | 警告`\n"
  },
  {
    "path": "docs/ja/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs/ko/docs/_llm-test.md",
    "content": "# LLM 테스트 파일 { #llm-test-file }\n\n이 문서는 문서를 번역하는 <abbr title=\"Large Language Model - 대규모 언어 모델\">LLM</abbr>이 `scripts/translate.py`의 `general_prompt`와 `docs/{language code}/llm-prompt.md`의 언어별 프롬프트를 이해하는지 테스트합니다. 언어별 프롬프트는 `general_prompt`에 추가됩니다.\n\n여기에 추가된 테스트는 언어별 프롬프트를 설계하는 모든 사람이 보게 됩니다.\n\n사용 방법은 다음과 같습니다:\n\n* 언어별 프롬프트 `docs/{language code}/llm-prompt.md`를 준비합니다.\n* 이 문서를 원하는 대상 언어로 새로 번역합니다(예: `translate.py`의 `translate-page` 명령). 그러면 `docs/{language code}/docs/_llm-test.md` 아래에 번역이 생성됩니다.\n* 번역에서 문제가 없는지 확인합니다.\n* 필요하다면 언어별 프롬프트, 일반 프롬프트, 또는 영어 문서를 개선합니다.\n* 그런 다음 번역에서 남아 있는 문제를 수동으로 수정해 좋은 번역이 되게 합니다.\n* 좋은 번역을 둔 상태에서 다시 번역합니다. 이상적인 결과는 LLM이 더 이상 번역에 변경을 만들지 않는 것입니다. 이는 일반 프롬프트와 언어별 프롬프트가 가능한 한 최선이라는 뜻입니다(때때로 몇 가지 seemingly random 변경을 할 수 있는데, 그 이유는 [LLM은 결정론적 알고리즘이 아니기 때문](https://doublespeak.chat/#/handbook#deterministic-output)입니다).\n\n테스트:\n\n## 코드 스니펫 { #code-snippets }\n\n//// tab | 테스트\n\n다음은 코드 스니펫입니다: `foo`. 그리고 이것은 또 다른 코드 스니펫입니다: `bar`. 그리고 또 하나: `baz quux`.\n\n////\n\n//// tab | 정보\n\n코드 스니펫의 내용은 그대로 두어야 합니다.\n\n`scripts/translate.py`의 일반 프롬프트에서 `### Content of code snippets` 섹션을 참고하세요.\n\n////\n\n## 따옴표 { #quotes }\n\n//// tab | 테스트\n\n어제 제 친구가 이렇게 썼습니다: \"If you spell incorrectly correctly, you have spelled it incorrectly\". 이에 저는 이렇게 답했습니다: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\".\n\n/// note | 참고\n\nLLM은 아마 이것을 잘못 번역할 것입니다. 흥미로운 점은 재번역할 때 고정된 번역을 유지하는지 여부뿐입니다.\n\n///\n\n////\n\n//// tab | 정보\n\n프롬프트 설계자는 중립 따옴표를 타이포그래피 따옴표로 변환할지 선택할 수 있습니다. 그대로 두어도 괜찮습니다.\n\n예를 들어 `docs/de/llm-prompt.md`의 `### Quotes` 섹션을 참고하세요.\n\n////\n\n## 코드 스니펫의 따옴표 { #quotes-in-code-snippets }\n\n//// tab | 테스트\n\n`pip install \"foo[bar]\"`\n\n코드 스니펫에서 문자열 리터럴의 예: `\"this\"`, `'that'`.\n\n코드 스니펫에서 문자열 리터럴의 어려운 예: `f\"I like {'oranges' if orange else \"apples\"}\"`\n\n하드코어: `Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | 정보\n\n... 하지만 코드 스니펫 안의 따옴표는 그대로 유지되어야 합니다.\n\n////\n\n## 코드 블록 { #code-blocks }\n\n//// tab | 테스트\n\nBash 코드 예시...\n\n```bash\n# 우주에 인사말 출력\necho \"Hello universe\"\n```\n\n...그리고 콘솔 코드 예시...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n...그리고 또 다른 콘솔 코드 예시...\n\n```console\n// \"Code\" 디렉터리 생성\n$ mkdir code\n// 해당 디렉터리로 이동\n$ cd code\n```\n\n...그리고 Python 코드 예시...\n\n```Python\nwont_work()  # 이건 동작하지 않습니다 😱\nworks(foo=\"bar\")  # 이건 동작합니다 🎉\n```\n\n...이상입니다.\n\n////\n\n//// tab | 정보\n\n코드 블록의 코드는(주석을 제외하고) 수정하면 안 됩니다.\n\n`scripts/translate.py`의 일반 프롬프트에서 `### Content of code blocks` 섹션을 참고하세요.\n\n////\n\n## 탭과 색상 박스 { #tabs-and-colored-boxes }\n\n//// tab | 테스트\n\n/// info | 정보\n일부 텍스트\n///\n\n/// note | 참고\n일부 텍스트\n///\n\n/// note | 기술 세부사항\n일부 텍스트\n///\n\n/// check | 확인\n일부 텍스트\n///\n\n/// tip | 팁\n일부 텍스트\n///\n\n/// warning | 경고\n일부 텍스트\n///\n\n/// danger | 위험\n일부 텍스트\n///\n\n////\n\n//// tab | 정보\n\n탭과 `Info`/`Note`/`Warning`/등의 블록은 제목 번역을 수직 막대(`|`) 뒤에 추가해야 합니다.\n\n`scripts/translate.py`의 일반 프롬프트에서 `### Special blocks`와 `### Tab blocks` 섹션을 참고하세요.\n\n////\n\n## 웹 및 내부 링크 { #web-and-internal-links }\n\n//// tab | 테스트\n\n링크 텍스트는 번역되어야 하고, 링크 주소는 변경되지 않아야 합니다:\n\n* [위의 제목으로 가는 링크](#code-snippets)\n* [내부 링크](index.md#installation)\n* [외부 링크](https://sqlmodel.tiangolo.com/)\n* [스타일로 가는 링크](https://fastapi.tiangolo.com/css/styles.css)\n* [스크립트로 가는 링크](https://fastapi.tiangolo.com/js/logic.js)\n* [이미지로 가는 링크](https://fastapi.tiangolo.com/img/foo.jpg)\n\n링크 텍스트는 번역되어야 하고, 링크 주소는 번역 페이지를 가리켜야 합니다:\n\n* [FastAPI 링크](https://fastapi.tiangolo.com/ko/)\n\n////\n\n//// tab | 정보\n\n링크는 번역되어야 하지만, 주소는 변경되지 않아야 합니다. 예외는 FastAPI 문서 페이지로 향하는 절대 링크이며, 이 경우 번역 페이지로 연결되어야 합니다.\n\n`scripts/translate.py`의 일반 프롬프트에서 `### Links` 섹션을 참고하세요.\n\n////\n\n## HTML \"abbr\" 요소 { #html-abbr-elements }\n\n//// tab | 테스트\n\n여기 HTML \"abbr\" 요소로 감싼 몇 가지가 있습니다(일부는 임의로 만든 것입니다):\n\n### abbr가 전체 문구를 제공 { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done - 일을 끝내는 방법론\">GTD</abbr>\n* <abbr title=\"less than - 보다 작음\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token - XML 웹 토큰\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface - 병렬 서버 게이트웨이 인터페이스\">PSGI</abbr>\n\n### abbr가 전체 문구와 설명을 제공 { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network - 모질라 개발자 네트워크: Firefox를 만드는 사람들이 작성한 개발자용 문서\">MDN</abbr>\n* <abbr title=\"Input/Output - 입력/출력: 디스크 읽기 또는 쓰기, 네트워크 통신.\">I/O</abbr>.\n\n////\n\n//// tab | 정보\n\n\"abbr\" 요소의 \"title\" 속성은 몇 가지 구체적인 지침에 따라 번역됩니다.\n\n번역에서는(영어 단어를 설명하기 위해) 자체 \"abbr\" 요소를 추가할 수 있으며, LLM은 이를 제거하면 안 됩니다.\n\n`scripts/translate.py`의 일반 프롬프트에서 `### HTML abbr elements` 섹션을 참고하세요.\n\n////\n\n## HTML \"dfn\" 요소 { #html-dfn-elements }\n\n* <dfn title=\"어떤 방식으로든 서로 연결되고 함께 작동하도록 구성된 머신들의 집합입니다.\">클러스터</dfn>\n* <dfn title=\"입력과 출력 계층 사이에 수많은 은닉 계층을 둔 인공 신경망을 사용하는 머신 러닝 방법으로, 이를 통해 포괄적인 내부 구조를 형성합니다\">딥 러닝</dfn>\n\n## 제목 { #headings }\n\n//// tab | 테스트\n\n### 웹앱 개발하기 - 튜토리얼 { #develop-a-webapp-a-tutorial }\n\n안녕하세요.\n\n### 타입 힌트와 -애너테이션 { #type-hints-and-annotations }\n\n다시 안녕하세요.\n\n### super- 및 subclasses { #super-and-subclasses }\n\n다시 안녕하세요.\n\n////\n\n//// tab | 정보\n\n제목에 대한 유일한 강한 규칙은, LLM이 중괄호 안의 해시 부분을 변경하지 않아 링크가 깨지지 않게 하는 것입니다.\n\n`scripts/translate.py`의 일반 프롬프트에서 `### Headings` 섹션을 참고하세요.\n\n언어별 지침은 예를 들어 `docs/de/llm-prompt.md`의 `### Headings` 섹션을 참고하세요.\n\n////\n\n## 문서에서 사용되는 용어 { #terms-used-in-the-docs }\n\n//// tab | 테스트\n\n* 여러분\n* 여러분의\n\n* 예:\n* 등\n\n* `foo`로서의 `int`\n* `bar`로서의 `str`\n* `baz`로서의 `list`\n\n* 튜토리얼 - 사용자 가이드\n* 고급 사용자 가이드\n* SQLModel 문서\n* API 문서\n* 자동 문서\n\n* Data Science\n* Deep Learning\n* Machine Learning\n* Dependency Injection\n* HTTP Basic authentication\n* HTTP Digest\n* ISO format\n* JSON Schema 표준\n* JSON schema\n* schema definition\n* Password Flow\n* Mobile\n\n* deprecated\n* designed\n* invalid\n* on the fly\n* standard\n* default\n* case-sensitive\n* case-insensitive\n\n* 애플리케이션을 서빙하다\n* 페이지를 서빙하다\n\n* 앱\n* 애플리케이션\n\n* 요청\n* 응답\n* 오류 응답\n\n* 경로 처리\n* 경로 처리 데코레이터\n* 경로 처리 함수\n\n* body\n* 요청 body\n* 응답 body\n* JSON body\n* form body\n* file body\n* 함수 body\n\n* parameter\n* body parameter\n* path parameter\n* query parameter\n* cookie parameter\n* header parameter\n* form parameter\n* function parameter\n\n* event\n* startup event\n* 서버 startup\n* shutdown event\n* lifespan event\n\n* handler\n* event handler\n* exception handler\n* 처리하다\n\n* model\n* Pydantic model\n* data model\n* database model\n* form model\n* model object\n\n* class\n* base class\n* parent class\n* subclass\n* child class\n* sibling class\n* class method\n\n* header\n* headers\n* authorization header\n* `Authorization` header\n* forwarded header\n\n* dependency injection system\n* dependency\n* dependable\n* dependant\n\n* I/O bound\n* CPU bound\n* concurrency\n* parallelism\n* multiprocessing\n\n* env var\n* environment variable\n* `PATH`\n* `PATH` variable\n\n* authentication\n* authentication provider\n* authorization\n* authorization form\n* authorization provider\n* 사용자가 인증한다\n* 시스템이 사용자를 인증한다\n\n* CLI\n* command line interface\n\n* server\n* client\n\n* cloud provider\n* cloud service\n\n* development\n* development stages\n\n* dict\n* dictionary\n* enumeration\n* enum\n* enum member\n\n* encoder\n* decoder\n* encode하다\n* decode하다\n\n* exception\n* raise하다\n\n* expression\n* statement\n\n* frontend\n* backend\n\n* GitHub discussion\n* GitHub issue\n\n* performance\n* performance optimization\n\n* return type\n* return value\n\n* security\n* security scheme\n\n* task\n* background task\n* task function\n\n* template\n* template engine\n\n* type annotation\n* type hint\n\n* server worker\n* Uvicorn worker\n* Gunicorn Worker\n* worker process\n* worker class\n* workload\n\n* deployment\n* deploy하다\n\n* SDK\n* software development kit\n\n* `APIRouter`\n* `requirements.txt`\n* Bearer Token\n* breaking change\n* bug\n* button\n* callable\n* code\n* commit\n* context manager\n* coroutine\n* database session\n* disk\n* domain\n* engine\n* fake X\n* HTTP GET method\n* item\n* library\n* lifespan\n* lock\n* middleware\n* mobile application\n* module\n* mounting\n* network\n* origin\n* override\n* payload\n* processor\n* property\n* proxy\n* pull request\n* query\n* RAM\n* remote machine\n* status code\n* string\n* tag\n* web framework\n* wildcard\n* return하다\n* validate하다\n\n////\n\n//// tab | 정보\n\n이것은 문서에서 보이는 (대부분) 기술 용어의 불완전하고 비규범적인 목록입니다. 프롬프트 설계자가 어떤 용어에 대해 LLM에 추가적인 도움이 필요한지 파악하는 데 유용할 수 있습니다. 예를 들어, 좋은 번역을 계속 덜 좋은 번역으로 되돌릴 때, 또는 언어에서 용어의 활용/변화를 처리하는 데 문제가 있을 때 도움이 됩니다.\n\n예를 들어 `docs/de/llm-prompt.md`의 `### List of English terms and their preferred German translations` 섹션을 참고하세요.\n\n////\n"
  },
  {
    "path": "docs/ko/docs/about/index.md",
    "content": "# 소개 { #about }\n\nFastAPI, 그 디자인, 영감 등에 대해 🤓\n"
  },
  {
    "path": "docs/ko/docs/advanced/additional-responses.md",
    "content": "# OpenAPI에서 추가 응답 { #additional-responses-in-openapi }\n\n/// warning | 경고\n\n이는 꽤 고급 주제입니다.\n\n**FastAPI**를 막 시작했다면, 이 내용이 필요 없을 수도 있습니다.\n\n///\n\n추가 상태 코드, 미디어 타입, 설명 등을 포함한 추가 응답을 선언할 수 있습니다.\n\n이러한 추가 응답은 OpenAPI 스키마에 포함되므로 API 문서에도 표시됩니다.\n\n하지만 이러한 추가 응답의 경우, 상태 코드와 콘텐츠를 포함하여 `JSONResponse` 같은 `Response`를 직접 반환하도록 반드시 처리해야 합니다.\n\n## `model`을 사용한 추가 응답 { #additional-response-with-model }\n\n*경로 처리 데코레이터*에 `responses` 파라미터를 전달할 수 있습니다.\n\n이는 `dict`를 받습니다. 키는 각 응답의 상태 코드(예: `200`)이고, 값은 각 응답에 대한 정보를 담은 다른 `dict`입니다.\n\n각 응답 `dict`에는 `response_model`처럼 Pydantic 모델을 담는 `model` 키가 있을 수 있습니다.\n\n**FastAPI**는 그 모델을 사용해 JSON Schema를 생성하고, OpenAPI의 올바른 위치에 포함합니다.\n\n예를 들어, 상태 코드 `404`와 Pydantic 모델 `Message`를 사용하는 다른 응답을 선언하려면 다음과 같이 작성할 수 있습니다:\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | 참고\n\n`JSONResponse`를 직접 반환해야 한다는 점을 기억하세요.\n\n///\n\n/// info | 정보\n\n`model` 키는 OpenAPI의 일부가 아닙니다.\n\n**FastAPI**는 여기에서 Pydantic 모델을 가져와 JSON Schema를 생성하고 올바른 위치에 넣습니다.\n\n올바른 위치는 다음과 같습니다:\n\n* 값으로 또 다른 JSON 객체(`dict`)를 가지는 `content` 키 안에:\n    * 미디어 타입(예: `application/json`)을 키로 가지며, 값으로 또 다른 JSON 객체를 포함하고:\n        * `schema` 키가 있고, 그 값이 모델에서 생성된 JSON Schema입니다. 이것이 올바른 위치입니다.\n            * **FastAPI**는 이를 직접 포함하는 대신, OpenAPI의 다른 위치에 있는 전역 JSON Schemas를 참조하도록 여기에서 reference를 추가합니다. 이렇게 하면 다른 애플리케이션과 클라이언트가 그 JSON Schema를 직접 사용할 수 있고, 더 나은 코드 생성 도구 등을 제공할 수 있습니다.\n\n///\n\n이 *경로 처리*에 대해 OpenAPI에 생성되는 응답은 다음과 같습니다:\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n스키마는 OpenAPI 스키마 내부의 다른 위치를 참조합니다:\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## 주요 응답에 대한 추가 미디어 타입 { #additional-media-types-for-the-main-response }\n\n같은 `responses` 파라미터를 사용해 동일한 주요 응답에 대해 다른 미디어 타입을 추가할 수도 있습니다.\n\n예를 들어, *경로 처리*가 JSON 객체(미디어 타입 `application/json`) 또는 PNG 이미지(미디어 타입 `image/png`)를 반환할 수 있다고 선언하기 위해 `image/png`라는 추가 미디어 타입을 추가할 수 있습니다:\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | 참고\n\n이미지는 `FileResponse`를 사용해 직접 반환해야 한다는 점에 유의하세요.\n\n///\n\n/// info | 정보\n\n`responses` 파라미터에서 다른 미디어 타입을 명시적으로 지정하지 않는 한, FastAPI는 응답이 주요 응답 클래스와 동일한 미디어 타입(기본값 `application/json`)을 가진다고 가정합니다.\n\n하지만 커스텀 응답 클래스를 지정하면서 미디어 타입을 `None`으로 설정했다면, FastAPI는 연결된 모델이 있는 모든 추가 응답에 대해 `application/json`을 사용합니다.\n\n///\n\n## 정보 결합하기 { #combining-information }\n\n`response_model`, `status_code`, `responses` 파라미터를 포함해 여러 위치의 응답 정보를 결합할 수도 있습니다.\n\n기본 상태 코드 `200`(또는 필요하다면 커스텀 코드)을 사용하여 `response_model`을 선언하고, 그와 동일한 응답에 대한 추가 정보를 `responses`에서 OpenAPI 스키마에 직접 선언할 수 있습니다.\n\n**FastAPI**는 `responses`의 추가 정보를 유지하고, 모델의 JSON Schema와 결합합니다.\n\n예를 들어, Pydantic 모델을 사용하고 커스텀 `description`을 가진 상태 코드 `404` 응답을 선언할 수 있습니다.\n\n또한 `response_model`을 사용하는 상태 코드 `200` 응답을 선언하되, 커스텀 `example`을 포함할 수도 있습니다:\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\n이 모든 내용은 OpenAPI에 결합되어 포함되고, API 문서에 표시됩니다:\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## 미리 정의된 응답과 커스텀 응답 결합하기 { #combine-predefined-responses-and-custom-ones }\n\n여러 *경로 처리*에 적용되는 미리 정의된 응답이 필요할 수도 있지만, 각 *경로 처리*마다 필요한 커스텀 응답과 결합하고 싶을 수도 있습니다.\n\n그런 경우 Python의 `dict` “unpacking” 기법인 `**dict_to_unpack`을 사용할 수 있습니다:\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\n여기서 `new_dict`는 `old_dict`의 모든 키-값 쌍에 더해 새 키-값 쌍까지 포함합니다:\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\n이 기법을 사용해 *경로 처리*에서 일부 미리 정의된 응답을 재사용하고, 추가 커스텀 응답과 결합할 수 있습니다.\n\n예를 들어:\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## OpenAPI 응답에 대한 추가 정보 { #more-information-about-openapi-responses }\n\n응답에 정확히 무엇을 포함할 수 있는지 보려면, OpenAPI 사양의 다음 섹션을 확인하세요:\n\n* [OpenAPI Responses Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object): `Response Object`를 포함합니다.\n* [OpenAPI Response Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object): `responses` 파라미터 안의 각 응답에 이것의 어떤 항목이든 직접 포함할 수 있습니다. `description`, `headers`, `content`(여기에서 서로 다른 미디어 타입과 JSON Schema를 선언합니다), `links` 등을 포함할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/advanced/additional-status-codes.md",
    "content": "# 추가 상태 코드 { #additional-status-codes }\n\n기본적으로 **FastAPI**는 응답을 `JSONResponse`를 사용하여 반환하며, *경로 처리*에서 반환한 내용을 해당 `JSONResponse` 안에 넣어 반환합니다.\n\n기본 상태 코드 또는 *경로 처리*에서 설정한 상태 코드를 사용합니다.\n\n## 추가 상태 코드 { #additional-status-codes_1 }\n\n기본 상태 코드와 별도로 추가 상태 코드를 반환하려면 `JSONResponse`와 같이 `Response`를 직접 반환하고 추가 상태 코드를 직접 설정할 수 있습니다.\n\n예를 들어 항목을 업데이트할 수 있는 *경로 처리*가 있고 성공 시 200 “OK”의 HTTP 상태 코드를 반환한다고 가정해 보겠습니다.\n\n하지만 새로운 항목을 허용하기를 원할 것입니다. 그리고 항목이 이전에 존재하지 않았다면 이를 생성하고 HTTP 상태 코드 201 \"Created\"를 반환합니다.\n\n이를 위해서는 `JSONResponse`를 가져와서 원하는 `status_code`를 설정하여 콘텐츠를 직접 반환합니다:\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning\n\n위의 예제처럼 `Response`를 직접 반환하면 바로 반환됩니다.\n\n모델 등과 함께 직렬화되지 않습니다.\n\n원하는 데이터가 있는지, 값이 유효한 JSON인지 확인합니다(`JSONResponse`를 사용하는 경우).\n\n///\n\n/// note | 기술 세부사항\n\n`from starlette.responses import JSONResponse`를 사용할 수도 있습니다.\n\n**FastAPI**는 개발자 여러분을 위한 편의성으로 `fastapi.responses`와 동일한 `starlette.responses`를 제공합니다. 그러나 사용 가능한 응답의 대부분은 Starlette에서 직접 제공됩니다. `status` 또한 마찬가지입니다.\n\n///\n\n## OpenAPI 및 API 문서 { #openapi-and-api-docs }\n\n추가 상태 코드와 응답을 직접 반환하는 경우, FastAPI는 반환할 내용을 미리 알 수 있는 방법이 없기 때문에 OpenAPI 스키마(API 문서)에 포함되지 않습니다.\n\n하지만 다음을 사용하여 코드에 이를 문서화할 수 있습니다: [추가 응답](additional-responses.md).\n"
  },
  {
    "path": "docs/ko/docs/advanced/advanced-dependencies.md",
    "content": "# 고급 의존성 { #advanced-dependencies }\n\n## 매개변수화된 의존성 { #parameterized-dependencies }\n\n지금까지 본 모든 의존성은 고정된 함수 또는 클래스입니다.\n\n하지만 여러 개의 함수나 클래스를 선언하지 않고도 의존성에 매개변수를 설정해야 하는 경우가 있을 수 있습니다.\n\n예를 들어, `q` 쿼리 매개변수가 특정 고정된 내용을 포함하고 있는지 확인하는 의존성을 원한다고 가정해 봅시다.\n\n이때 해당 고정된 내용을 매개변수화할 수 있길 바랍니다.\n\n## \"호출 가능한\" 인스턴스 { #a-callable-instance }\n\nPython에는 클래스의 인스턴스를 \"호출 가능\"하게 만드는 방법이 있습니다.\n\n클래스 자체(이미 호출 가능함)가 아니라 해당 클래스의 인스턴스에 대해 호출 가능하게 하는 것입니다.\n\n이를 위해 `__call__` 메서드를 선언합니다:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\n이 경우, **FastAPI**는 추가 매개변수와 하위 의존성을 확인하기 위해 `__call__`을 사용하게 되며,\n나중에 *경로 처리 함수*에서 매개변수에 값을 전달할 때 이를 호출하게 됩니다.\n\n## 인스턴스 매개변수화하기 { #parameterize-the-instance }\n\n이제 `__init__`을 사용하여 의존성을 \"매개변수화\"할 수 있는 인스턴스의 매개변수를 선언할 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\n이 경우, **FastAPI**는 `__init__`에 전혀 관여하지 않으며, 우리는 이 메서드를 코드에서 직접 사용하게 됩니다.\n\n## 인스턴스 생성하기 { #create-an-instance }\n\n다음과 같이 이 클래스의 인스턴스를 생성할 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\n이렇게 하면 `checker.fixed_content` 속성에 `\"bar\"`라는 값을 담아 의존성을 \"매개변수화\"할 수 있습니다.\n\n## 인스턴스를 의존성으로 사용하기 { #use-the-instance-as-a-dependency }\n\n그런 다음, 클래스 자체가 아닌 인스턴스 `checker`가 의존성이 되므로, `Depends(FixedContentQueryChecker)` 대신 `Depends(checker)`에서 이 `checker` 인스턴스를 사용할 수 있습니다.\n\n의존성을 해결할 때 **FastAPI**는 이 `checker`를 다음과 같이 호출합니다:\n\n```Python\nchecker(q=\"somequery\")\n```\n\n...그리고 이때 반환되는 값을 *경로 처리 함수*의 의존성 값으로, `fixed_content_included` 매개변수에 전달합니다:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | 팁\n\n이 모든 과정이 복잡하게 느껴질 수 있습니다. 그리고 지금은 이 방법이 얼마나 유용한지 명확하지 않을 수도 있습니다.\n\n이 예시는 의도적으로 간단하게 만들었지만, 전체 구조가 어떻게 작동하는지 보여줍니다.\n\n보안 관련 장에서는 이와 같은 방식으로 구현된 유틸리티 함수들이 있습니다.\n\n이 모든 과정을 이해했다면, 이러한 보안용 유틸리티 도구들이 내부적으로 어떻게 작동하는지 이미 파악한 것입니다.\n\n///\n\n## `yield`, `HTTPException`, `except`, 백그라운드 태스크가 있는 의존성 { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | 경고\n\n대부분의 경우 이러한 기술 세부사항이 필요하지 않을 것입니다.\n\n이 세부사항은 주로 0.121.0 이전의 FastAPI 애플리케이션이 있고 `yield`가 있는 의존성에서 문제가 발생하는 경우에 유용합니다.\n\n///\n\n`yield`가 있는 의존성은 여러 사용 사례를 수용하고 일부 문제를 해결하기 위해 시간이 지나며 발전해 왔습니다. 다음은 변경된 내용의 요약입니다.\n\n### `yield`와 `scope`가 있는 의존성 { #dependencies-with-yield-and-scope }\n\n0.121.0 버전에서 FastAPI는 `Depends(scope=\"function\")` 지원을 추가했습니다.\n\n`Depends(scope=\"function\")`를 사용하면, `yield` 이후의 종료 코드는 *경로 처리 함수*가 끝난 직후(클라이언트에 응답이 반환되기 전)에 실행됩니다.\n\n그리고 `Depends(scope=\"request\")`(기본값)를 사용하면, `yield` 이후의 종료 코드는 응답이 전송된 후에 실행됩니다.\n\n자세한 내용은 [`yield`가 있는 의존성 - 조기 종료와 `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) 문서를 참고하세요.\n\n### `yield`가 있는 의존성과 `StreamingResponse`, 기술 세부사항 { #dependencies-with-yield-and-streamingresponse-technical-details }\n\nFastAPI 0.118.0 이전에는 `yield`가 있는 의존성을 사용하면, *경로 처리 함수*가 반환된 뒤 응답을 보내기 직전에 `yield` 이후의 종료 코드가 실행되었습니다.\n\n의도는 응답이 네트워크를 통해 전달되기를 기다리면서 필요한 것보다 더 오래 리소스를 점유하지 않도록 하는 것이었습니다.\n\n이 변경은 `StreamingResponse`를 반환하는 경우에도 `yield`가 있는 의존성의 종료 코드가 이미 실행된다는 의미이기도 했습니다.\n\n예를 들어, `yield`가 있는 의존성에 데이터베이스 세션이 있다면, `StreamingResponse`는 데이터를 스트리밍하는 동안 해당 세션을 사용할 수 없게 됩니다. `yield` 이후의 종료 코드에서 세션이 이미 닫혔기 때문입니다.\n\n이 동작은 0.118.0에서 되돌려져, `yield` 이후의 종료 코드가 응답이 전송된 뒤 실행되도록 변경되었습니다.\n\n/// info | 정보\n\n아래에서 보시겠지만, 이는 0.106.0 버전 이전의 동작과 매우 비슷하지만, 여러 개선 사항과 코너 케이스에 대한 버그 수정이 포함되어 있습니다.\n\n///\n\n#### 종료 코드를 조기에 실행하는 사용 사례 { #use-cases-with-early-exit-code }\n\n특정 조건의 일부 사용 사례에서는 응답을 보내기 전에 `yield`가 있는 의존성의 종료 코드를 실행하던 예전 동작이 도움이 될 수 있습니다.\n\n예를 들어, `yield`가 있는 의존성에서 데이터베이스 세션을 사용해 사용자를 검증만 하고, *경로 처리 함수*에서는 그 데이터베이스 세션을 다시는 사용하지 않으며(의존성에서만 사용), **그리고** 응답을 전송하는 데 오랜 시간이 걸리는 경우를 생각해 봅시다. 예를 들어 데이터를 천천히 보내는 `StreamingResponse`인데, 어떤 이유로든 데이터베이스를 사용하지는 않는 경우입니다.\n\n이 경우 데이터베이스 세션은 응답 전송이 끝날 때까지 유지되지만, 사용하지 않는다면 굳이 유지할 필요가 없습니다.\n\n다음과 같이 보일 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\n다음에서 `Session`을 자동으로 닫는 종료 코드는:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n...응답이 느린 데이터 전송을 마친 뒤에 실행됩니다:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\n하지만 `generate_stream()`는 데이터베이스 세션을 사용하지 않으므로, 응답을 전송하는 동안 세션을 열린 채로 유지할 필요는 없습니다.\n\nSQLModel(또는 SQLAlchemy)을 사용하면서 이런 특정 사용 사례가 있다면, 더 이상 필요하지 않을 때 세션을 명시적으로 닫을 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\n그러면 세션이 데이터베이스 연결을 해제하여, 다른 요청들이 이를 사용할 수 있게 됩니다.\n\n`yield`가 있는 의존성에서 조기 종료가 필요한 다른 사용 사례가 있다면, 여러분의 구체적인 사용 사례와 `yield`가 있는 의존성에 대한 조기 종료가 어떤 점에서 이득이 되는지를 포함해 [GitHub Discussions 질문](https://github.com/fastapi/fastapi/discussions/new?category=questions)을 생성해 주세요.\n\n`yield`가 있는 의존성에서 조기 종료에 대한 설득력 있는 사용 사례가 있다면, 조기 종료를 선택적으로 활성화할 수 있는 새로운 방법을 추가하는 것을 고려하겠습니다.\n\n### `yield`가 있는 의존성과 `except`, 기술 세부사항 { #dependencies-with-yield-and-except-technical-details }\n\nFastAPI 0.110.0 이전에는 `yield`가 있는 의존성을 사용한 다음 그 의존성에서 `except`로 예외를 잡고, 예외를 다시 발생시키지 않으면, 예외가 자동으로 어떤 예외 핸들러 또는 내부 서버 오류 핸들러로 raise/forward 되었습니다.\n\n이는 핸들러 없이 전달된 예외(내부 서버 오류)로 인해 처리되지 않은 메모리 사용이 발생하는 문제를 수정하고, 일반적인 Python 코드의 동작과 일관되게 하기 위해 0.110.0 버전에서 변경되었습니다.\n\n### 백그라운드 태스크와 `yield`가 있는 의존성, 기술 세부사항 { #background-tasks-and-dependencies-with-yield-technical-details }\n\nFastAPI 0.106.0 이전에는 `yield` 이후에 예외를 발생시키는 것이 불가능했습니다. `yield`가 있는 의존성의 종료 코드는 응답이 전송된 *후에* 실행되었기 때문에, [예외 핸들러](../tutorial/handling-errors.md#install-custom-exception-handlers)가 이미 실행된 뒤였습니다.\n\n이는 주로 백그라운드 태스크 안에서 의존성이 \"yield\"한 동일한 객체들을 사용할 수 있게 하기 위한 설계였습니다. 백그라운드 태스크가 끝난 뒤에 종료 코드가 실행되었기 때문입니다.\n\n이는 응답이 네트워크를 통해 전달되기를 기다리는 동안 리소스를 점유하지 않기 위한 의도로 FastAPI 0.106.0에서 변경되었습니다.\n\n/// tip | 팁\n\n추가로, 백그라운드 태스크는 보통 별도의 리소스(예: 자체 데이터베이스 연결)를 가지고 따로 처리되어야 하는 독립적인 로직 집합입니다.\n\n따라서 이 방식이 코드를 더 깔끔하게 만들어줄 가능성이 큽니다.\n\n///\n\n이 동작에 의존하던 경우라면, 이제는 백그라운드 태스크를 위한 리소스를 백그라운드 태스크 내부에서 생성하고, 내부적으로는 `yield`가 있는 의존성의 리소스에 의존하지 않는 데이터만 사용해야 합니다.\n\n예를 들어, 동일한 데이터베이스 세션을 사용하는 대신, 백그라운드 태스크 내부에서 새 데이터베이스 세션을 생성하고, 이 새 세션을 사용해 데이터베이스에서 객체를 가져오면 됩니다. 그리고 데이터베이스에서 가져온 객체를 백그라운드 태스크 함수의 매개변수로 전달하는 대신, 해당 객체의 ID를 전달한 다음 백그라운드 태스크 함수 내부에서 객체를 다시 가져오면 됩니다.\n"
  },
  {
    "path": "docs/ko/docs/advanced/advanced-python-types.md",
    "content": "# 고급 Python 타입 { #advanced-python-types }\n\nPython 타입을 다룰 때 유용할 수 있는 몇 가지 추가 아이디어를 소개합니다.\n\n## `Union` 또는 `Optional` 사용 { #using-union-or-optional }\n\n어떤 이유로 코드에서 `|`를 사용할 수 없다면, 예를 들어 타입 어노테이션이 아니라 `response_model=` 같은 곳이라면, 파이프 문자(`|`) 대신 `typing`의 `Union`을 사용할 수 있습니다.\n\n예를 들어, 어떤 값이 `str` 또는 `None`이 될 수 있다고 선언할 수 있습니다:\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\n`typing`에는 `None`이 될 수 있음을 선언하는 축약형으로 `Optional`도 있습니다.\n\n아주 개인적인 관점에서의 팁입니다:\n\n- 🚨 `Optional[SomeType]` 사용은 피하세요\n- 대신 ✨ **`Union[SomeType, None]`를 사용하세요** ✨.\n\n둘은 동등하며 내부적으로도 같습니다. 하지만 단어 \"optional\"은 값이 선택 사항이라는 인상을 주는 반면, 실제 의미는 \"값이 `None`이 될 수 있다\"는 뜻입니다. 값이 선택 사항이 아니라 여전히 필수인 경우에도 그렇습니다.\n\n`Union[SomeType, None]`가 의미를 더 명확하게 드러낸다고 생각합니다.\n\n이는 단지 단어와 명칭의 문제입니다. 하지만 이런 단어가 여러분과 팀원이 코드를 어떻게 생각하는지에 영향을 줄 수 있습니다.\n\n예를 들어, 다음 함수를 보세요:\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\n매개변수 `name`은 `Optional[str]`로 정의되어 있지만, 사실 선택적이지 않습니다. 이 매개변수 없이 함수를 호출할 수 없습니다:\n\n```Python\nsay_hi()  # 이런, 에러가 발생합니다! 😱\n```\n\n`name` 매개변수는 기본값이 없기 때문에 여전히 필수입니다(선택적이 아님). 대신, `name`에는 `None`을 전달할 수 있습니다:\n\n```Python\nsay_hi(name=None)  # 작동합니다. None은 유효합니다 🎉\n```\n\n좋은 소식은, 대부분의 경우 타입의 합집합을 정의할 때 그냥 `|`를 사용할 수 있다는 점입니다:\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\n그래서 보통은 `Optional`과 `Union` 같은 이름에 대해 걱정하지 않으셔도 됩니다. 😎\n"
  },
  {
    "path": "docs/ko/docs/advanced/async-tests.md",
    "content": "# 비동기 테스트 { #async-tests }\n\n제공된 `TestClient`를 사용하여 **FastAPI** 애플리케이션을 테스트하는 방법을 이미 살펴보았습니다. 지금까지는 `async` 함수를 사용하지 않고, 동기 테스트를 작성하는 방법만 보았습니다.\n\n테스트에서 비동기 함수를 사용할 수 있으면 유용할 수 있습니다. 예를 들어 데이터베이스를 비동기로 쿼리하는 경우를 생각해 보세요. FastAPI 애플리케이션에 요청을 보낸 다음, async 데이터베이스 라이브러리를 사용하면서 백엔드가 데이터베이스에 올바른 데이터를 성공적으로 기록했는지 검증하고 싶을 수 있습니다.\n\n어떻게 동작하게 만들 수 있는지 살펴보겠습니다.\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\n테스트에서 비동기 함수를 호출하려면, 테스트 함수도 비동기여야 합니다. AnyIO는 이를 위한 깔끔한 플러그인을 제공하며, 일부 테스트 함수를 비동기로 호출하도록 지정할 수 있습니다.\n\n## HTTPX { #httpx }\n\n**FastAPI** 애플리케이션이 `async def` 대신 일반 `def` 함수를 사용하더라도, 내부적으로는 여전히 `async` 애플리케이션입니다.\n\n`TestClient`는 표준 pytest를 사용하여, 일반 `def` 테스트 함수 안에서 비동기 FastAPI 애플리케이션을 호출하도록 내부에서 마법 같은 처리를 합니다. 하지만 비동기 함수 안에서 이를 사용하면 그 마법은 더 이상 동작하지 않습니다. 테스트를 비동기로 실행하면, 테스트 함수 안에서 `TestClient`를 더 이상 사용할 수 없습니다.\n\n`TestClient`는 [HTTPX](https://www.python-httpx.org)를 기반으로 하며, 다행히 HTTPX를 직접 사용해 API를 테스트할 수 있습니다.\n\n## 예시 { #example }\n\n간단한 예시로, [더 큰 애플리케이션](../tutorial/bigger-applications.md)과 [테스트](../tutorial/testing.md)에서 설명한 것과 비슷한 파일 구조를 살펴보겠습니다:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n`main.py` 파일은 다음과 같습니다:\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\n`test_main.py` 파일에는 `main.py`에 대한 테스트가 있으며, 이제 다음과 같이 보일 수 있습니다:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## 실행하기 { #run-it }\n\n다음과 같이 평소처럼 테스트를 실행할 수 있습니다:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## 자세히 보기 { #in-detail }\n\n`@pytest.mark.anyio` 마커는 pytest에게 이 테스트 함수가 비동기로 호출되어야 한다고 알려줍니다:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip | 팁\n\n`TestClient`를 사용할 때처럼 단순히 `def`가 아니라, 이제 테스트 함수가 `async def`라는 점에 주목하세요.\n\n///\n\n그 다음 앱으로 `AsyncClient`를 만들고, `await`를 사용해 비동기 요청을 보낼 수 있습니다.\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\n이는 다음과 동등합니다:\n\n```Python\nresponse = client.get('/')\n```\n\n`TestClient`로 요청을 보내기 위해 사용하던 코드입니다.\n\n/// tip | 팁\n\n새 `AsyncClient`와 함께 async/await를 사용하고 있다는 점에 주목하세요. 요청은 비동기입니다.\n\n///\n\n/// warning | 경고\n\n애플리케이션이 lifespan 이벤트에 의존한다면, `AsyncClient`는 이러한 이벤트를 트리거하지 않습니다. 이벤트가 트리거되도록 하려면 [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage)의 `LifespanManager`를 사용하세요.\n\n///\n\n## 기타 비동기 함수 호출 { #other-asynchronous-function-calls }\n\n테스트 함수가 이제 비동기이므로, 테스트에서 FastAPI 애플리케이션에 요청을 보내는 것 외에도 다른 `async` 함수를 코드의 다른 곳에서 호출하듯이 동일하게 호출하고 (`await`) 사용할 수도 있습니다.\n\n/// tip | 팁\n\n테스트에 비동기 함수 호출을 통합할 때(예: [MongoDB의 MotorClient](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop)를 사용할 때) `RuntimeError: Task attached to a different loop`를 마주친다면, 이벤트 루프가 필요한 객체는 async 함수 안에서만 인스턴스화해야 한다는 점을 기억하세요. 예를 들어 `@app.on_event(\"startup\")` 콜백에서 인스턴스화할 수 있습니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/advanced/behind-a-proxy.md",
    "content": "# 프록시 뒤에서 실행하기 { #behind-a-proxy }\n\n많은 경우 FastAPI 앱 앞단에 Traefik이나 Nginx 같은 **프록시(proxy)**를 두고 사용합니다.\n\n이런 프록시는 HTTPS 인증서 처리 등 여러 작업을 담당할 수 있습니다.\n\n## 프록시 전달 헤더 { #proxy-forwarded-headers }\n\n애플리케이션 앞단의 **프록시**는 보통 **서버**로 요청을 보내기 전에, 해당 요청이 프록시에 의해 **전달(forwarded)**되었다는 것을 서버가 알 수 있도록 몇몇 헤더를 동적으로 설정합니다. 이를 통해 서버는 도메인을 포함한 원래의 (공개) URL, HTTPS 사용 여부 등 정보를 알 수 있습니다.\n\n**서버** 프로그램(예: **FastAPI CLI**를 통해 실행되는 **Uvicorn**)은 이런 헤더를 해석할 수 있고, 그 정보를 애플리케이션으로 전달할 수 있습니다.\n\n하지만 보안상, 서버는 자신이 신뢰할 수 있는 프록시 뒤에 있다는 것을 모르면 해당 헤더를 해석하지 않습니다.\n\n/// note | 기술 세부사항\n\n프록시 헤더는 다음과 같습니다:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### 프록시 전달 헤더 활성화하기 { #enable-proxy-forwarded-headers }\n\nFastAPI CLI를 *CLI 옵션* `--forwarded-allow-ips`로 실행하고, 전달 헤더를 읽을 수 있도록 신뢰할 IP 주소들을 넘길 수 있습니다.\n\n`--forwarded-allow-ips=\"*\"`로 설정하면 들어오는 모든 IP를 신뢰합니다.\n\n**서버**가 신뢰할 수 있는 **프록시** 뒤에 있고 프록시만 서버에 접근한다면, 이는 해당 **프록시**의 IP가 무엇이든 간에 받아들이게 됩니다.\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### HTTPS에서 리디렉션 { #redirects-with-https }\n\n예를 들어, *경로 처리* `/items/`를 정의했다고 해봅시다:\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\n클라이언트가 `/items`로 접근하면, 기본적으로 `/items/`로 리디렉션됩니다.\n\n하지만 *CLI 옵션* `--forwarded-allow-ips`를 설정하기 전에는 `http://localhost:8000/items/`로 리디렉션될 수 있습니다.\n\n그런데 애플리케이션이 `https://mysuperapp.com`에 호스팅되어 있고, 리디렉션도 `https://mysuperapp.com/items/`로 되어야 할 수 있습니다.\n\n이때 `--proxy-headers`를 설정하면 FastAPI가 올바른 위치로 리디렉션할 수 있습니다. 😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip | 팁\n\nHTTPS에 대해 더 알아보려면 가이드 [HTTPS에 대하여](../deployment/https.md)를 확인하세요.\n\n///\n\n### 프록시 전달 헤더가 동작하는 방식 { #how-proxy-forwarded-headers-work }\n\n다음은 **프록시**가 클라이언트와 **애플리케이션 서버** 사이에서 전달 헤더를 추가하는 과정을 시각적으로 나타낸 것입니다:\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Proxy as Proxy/Load Balancer\n    participant Server as FastAPI Server\n\n    Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: Proxy adds forwarded headers\n\n    Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)\n\n    Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs\n\n    Proxy->>Client: HTTPS Response\n```\n\n**프록시**는 원래의 클라이언트 요청을 가로채고, **애플리케이션 서버**로 요청을 전달하기 전에 특수한 *forwarded* 헤더(`X-Forwarded-*`)를 추가합니다.\n\n이 헤더들은 그렇지 않으면 사라질 수 있는 원래 요청의 정보를 보존합니다:\n\n* **X-Forwarded-For**: 원래 클라이언트의 IP 주소\n* **X-Forwarded-Proto**: 원래 프로토콜(`https`)\n* **X-Forwarded-Host**: 원래 호스트(`mysuperapp.com`)\n\n**FastAPI CLI**를 `--forwarded-allow-ips`로 설정하면, 이 헤더를 신뢰하고 사용합니다. 예를 들어 리디렉션에서 올바른 URL을 생성하는 데 사용됩니다.\n\n## 제거된 경로 접두사를 가진 프록시 { #proxy-with-a-stripped-path-prefix }\n\n애플리케이션에 경로 접두사(prefix)를 추가하는 프록시를 둘 수도 있습니다.\n\n이런 경우 `root_path`를 사용해 애플리케이션을 구성할 수 있습니다.\n\n`root_path`는 (FastAPI가 Starlette를 통해 기반으로 하는) ASGI 사양에서 제공하는 메커니즘입니다.\n\n`root_path`는 이러한 특정 사례를 처리하는 데 사용됩니다.\n\n또한 서브 애플리케이션을 마운트할 때 내부적으로도 사용됩니다.\n\n경로 접두사가 제거(stripped)되는 프록시가 있다는 것은, 코드에서는 `/app`에 경로를 선언하지만, 위에 한 겹(프록시)을 추가해 **FastAPI** 애플리케이션을 `/api/v1` 같은 경로 아래에 두는 것을 의미합니다.\n\n이 경우 원래 경로 `/app`은 실제로 `/api/v1/app`에서 서비스됩니다.\n\n코드는 모두 `/app`만 있다고 가정하고 작성되어 있는데도 말입니다.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\n그리고 프록시는 요청을 앱 서버(아마 FastAPI CLI를 통해 실행되는 Uvicorn)로 전달하기 전에, 동적으로 **경로 접두사**를 **\"제거\"**합니다. 그래서 애플리케이션은 여전히 `/app`에서 서비스된다고 믿게 되고, 코드 전체를 `/api/v1` 접두사를 포함하도록 수정할 필요가 없어집니다.\n\n여기까지는 보통 정상적으로 동작합니다.\n\n하지만 통합 문서 UI(프론트엔드)를 열면, OpenAPI 스키마를 `/api/v1/openapi.json`이 아니라 `/openapi.json`에서 가져오려고 합니다.\n\n그래서 브라우저에서 실행되는 프론트엔드는 `/openapi.json`에 접근하려고 시도하지만 OpenAPI 스키마를 얻지 못합니다.\n\n앱에 대해 `/api/v1` 경로 접두사를 가진 프록시가 있으므로, 프론트엔드는 `/api/v1/openapi.json`에서 OpenAPI 스키마를 가져와야 합니다.\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy on http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server on http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip | 팁\n\nIP `0.0.0.0`은 보통 해당 머신/서버에서 사용 가능한 모든 IP에서 프로그램이 리슨한다는 의미로 사용됩니다.\n\n///\n\n문서 UI는 또한 OpenAPI 스키마에서 이 API `server`가 `/api/v1`(프록시 뒤) 위치에 있다고 선언해야 합니다. 예:\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // 여기에 다른 내용이 더 있습니다\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // 여기에 다른 내용이 더 있습니다\n    }\n}\n```\n\n이 예시에서 \"Proxy\"는 **Traefik** 같은 것이고, 서버는 **Uvicorn**으로 실행되는 FastAPI CLI처럼, FastAPI 애플리케이션을 실행하는 구성일 수 있습니다.\n\n### `root_path` 제공하기 { #providing-the-root-path }\n\n이를 달성하려면 다음처럼 커맨드 라인 옵션 `--root-path`를 사용할 수 있습니다:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nHypercorn을 사용한다면, Hypercorn에도 `--root-path` 옵션이 있습니다.\n\n/// note | 기술 세부사항\n\nASGI 사양은 이 사용 사례를 위해 `root_path`를 정의합니다.\n\n그리고 커맨드 라인 옵션 `--root-path`가 그 `root_path`를 제공합니다.\n\n///\n\n### 현재 `root_path` 확인하기 { #checking-the-current-root-path }\n\n요청마다 애플리케이션에서 사용 중인 현재 `root_path`를 얻을 수 있는데, 이는 `scope` 딕셔너리(ASGI 사양의 일부)에 포함되어 있습니다.\n\n여기서는 데모 목적을 위해 메시지에 포함하고 있습니다.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\n그 다음 Uvicorn을 다음과 같이 시작하면:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n응답은 다음과 비슷할 것입니다:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### FastAPI 앱에서 `root_path` 설정하기 { #setting-the-root-path-in-the-fastapi-app }\n\n또는 `--root-path` 같은 커맨드 라인 옵션(또는 동등한 방법)을 제공할 수 없는 경우, FastAPI 앱을 생성할 때 `root_path` 파라미터를 설정할 수 있습니다:\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\n`FastAPI`에 `root_path`를 전달하는 것은 Uvicorn이나 Hypercorn에 커맨드 라인 옵션 `--root-path`를 전달하는 것과 동일합니다.\n\n### `root_path`에 대하여 { #about-root-path }\n\n서버(Uvicorn)는 그 `root_path`를 앱에 전달하는 것 외에는 다른 용도로 사용하지 않는다는 점을 기억하세요.\n\n하지만 브라우저로 [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app)에 접속하면 정상 응답을 볼 수 있습니다:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n따라서 `http://127.0.0.1:8000/api/v1/app`로 접근될 것이라고 기대하지는 않습니다.\n\nUvicorn은 프록시가 `http://127.0.0.1:8000/app`에서 Uvicorn에 접근할 것을 기대하고, 그 위에 `/api/v1` 접두사를 추가하는 것은 프록시의 책임입니다.\n\n## 제거된 경로 접두사를 가진 프록시에 대하여 { #about-proxies-with-a-stripped-path-prefix }\n\n경로 접두사가 제거되는 프록시는 구성 방법 중 하나일 뿐이라는 점을 기억하세요.\n\n많은 경우 기본값은 프록시가 경로 접두사를 제거하지 않는 방식일 것입니다.\n\n그런 경우(경로 접두사를 제거하지 않는 경우) 프록시는 `https://myawesomeapp.com` 같은 곳에서 리슨하고, 브라우저가 `https://myawesomeapp.com/api/v1/app`로 접근하면, 서버(예: Uvicorn)가 `http://127.0.0.1:8000`에서 리슨하고 있을 때 프록시(경로 접두사를 제거하지 않는)는 동일한 경로로 Uvicorn에 접근합니다: `http://127.0.0.1:8000/api/v1/app`.\n\n## Traefik으로 로컬 테스트하기 { #testing-locally-with-traefik }\n\n[Traefik](https://docs.traefik.io/)을 사용하면, 경로 접두사가 제거되는 구성을 로컬에서 쉽게 실험할 수 있습니다.\n\n[Traefik 다운로드](https://github.com/containous/traefik/releases)는 단일 바이너리이며, 압축 파일을 풀고 터미널에서 바로 실행할 수 있습니다.\n\n그 다음 다음 내용을 가진 `traefik.toml` 파일을 생성하세요:\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\n이는 Traefik이 9999 포트에서 리슨하고, 다른 파일 `routes.toml`을 사용하도록 지시합니다.\n\n/// tip | 팁\n\n표준 HTTP 포트 80 대신 9999 포트를 사용해서, 관리자(`sudo`) 권한으로 실행하지 않아도 되게 했습니다.\n\n///\n\n이제 다른 파일 `routes.toml`을 생성하세요:\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\n이 파일은 Traefik이 경로 접두사 `/api/v1`을 사용하도록 설정합니다.\n\n그리고 Traefik은 요청을 `http://127.0.0.1:8000`에서 실행 중인 Uvicorn으로 전달합니다.\n\n이제 Traefik을 시작하세요:\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\n그리고 `--root-path` 옵션을 사용해 앱을 시작하세요:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### 응답 확인하기 { #check-the-responses }\n\n이제 Uvicorn의 포트로 된 URL인 [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app)로 접속하면 정상 응답을 볼 수 있습니다:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip | 팁\n\n`http://127.0.0.1:8000/app`로 접근했는데도 `/api/v1`의 `root_path`가 표시되는 것에 주의하세요. 이는 옵션 `--root-path`에서 가져온 값입니다.\n\n///\n\n이제 Traefik의 포트가 포함되고 경로 접두사가 포함된 URL [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app)을 여세요.\n\n동일한 응답을 얻습니다:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n하지만 이번에는 프록시가 제공한 접두사 경로 `/api/v1`이 포함된 URL에서의 응답입니다.\n\n물론 여기서의 아이디어는 모두가 프록시를 통해 앱에 접근한다는 것이므로, `/api/v1` 경로 접두사가 있는 버전이 \"올바른\" 접근입니다.\n\n그리고 경로 접두사가 없는 버전(`http://127.0.0.1:8000/app`)은 Uvicorn이 직접 제공하는 것이며, 오직 _프록시_(Traefik)가 접근하기 위한 용도입니다.\n\n이는 프록시(Traefik)가 경로 접두사를 어떻게 사용하는지, 그리고 서버(Uvicorn)가 옵션 `--root-path`로부터의 `root_path`를 어떻게 사용하는지를 보여줍니다.\n\n### 문서 UI 확인하기 { #check-the-docs-ui }\n\n하지만 재미있는 부분은 여기입니다. ✨\n\n앱에 접근하는 \"공식\" 방법은 우리가 정의한 경로 접두사를 가진 프록시를 통해서입니다. 따라서 기대하는 대로, URL에 경로 접두사가 없는 상태에서 Uvicorn이 직접 제공하는 docs UI를 시도하면, 프록시를 통해 접근된다고 가정하고 있기 때문에 동작하지 않습니다.\n\n[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)에서 확인할 수 있습니다:\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\n하지만 프록시(포트 `9999`)를 사용해 \"공식\" URL인 `/api/v1/docs`에서 docs UI에 접근하면, 올바르게 동작합니다! 🎉\n\n[http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs)에서 확인할 수 있습니다:\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\n원하던 그대로입니다. ✔️\n\n이는 FastAPI가 이 `root_path`를 사용해, OpenAPI에서 기본 `server`를 `root_path`가 제공한 URL로 생성하기 때문입니다.\n\n## 추가 서버 { #additional-servers }\n\n/// warning | 경고\n\n이는 더 고급 사용 사례입니다. 건너뛰어도 괜찮습니다.\n\n///\n\n기본적으로 **FastAPI**는 OpenAPI 스키마에서 `root_path`의 URL로 `server`를 생성합니다.\n\n하지만 예를 들어 동일한 docs UI가 스테이징과 프로덕션 환경 모두와 상호작용하도록 하려면, 다른 대안 `servers`를 제공할 수도 있습니다.\n\n사용자 정의 `servers` 리스트를 전달했고 `root_path`(API가 프록시 뒤에 있기 때문)가 있다면, **FastAPI**는 리스트의 맨 앞에 이 `root_path`를 가진 \"server\"를 삽입합니다.\n\n예:\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\n다음과 같은 OpenAPI 스키마를 생성합니다:\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // 여기에 다른 내용이 더 있습니다\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // 여기에 다른 내용이 더 있습니다\n    }\n}\n```\n\n/// tip | 팁\n\n`root_path`에서 가져온 값인 `/api/v1`의 `url` 값을 가진, 자동 생성된 server에 주목하세요.\n\n///\n\n[http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs)의 docs UI에서는 다음처럼 보입니다:\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip | 팁\n\ndocs UI는 선택한 server와 상호작용합니다.\n\n///\n\n/// note | 기술 세부사항\n\nOpenAPI 사양에서 `servers` 속성은 선택 사항입니다.\n\n`servers` 파라미터를 지정하지 않고 `root_path`가 `/`와 같다면, 생성된 OpenAPI 스키마의 `servers` 속성은 기본적으로 완전히 생략되며, 이는 `url` 값이 `/`인 단일 server와 동등합니다.\n\n///\n\n### `root_path`에서 자동 server 비활성화하기 { #disable-automatic-server-from-root-path }\n\n**FastAPI**가 `root_path`를 사용한 자동 server를 포함하지 않게 하려면, `root_path_in_servers=False` 파라미터를 사용할 수 있습니다:\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\n그러면 OpenAPI 스키마에 포함되지 않습니다.\n\n## 서브 애플리케이션 마운트하기 { #mounting-a-sub-application }\n\n프록시에서 `root_path`를 사용하면서도, [서브 애플리케이션 - 마운트](sub-applications.md)에 설명된 것처럼 서브 애플리케이션을 마운트해야 한다면, 기대하는 대로 일반적으로 수행할 수 있습니다.\n\nFastAPI가 내부적으로 `root_path`를 똑똑하게 사용하므로, 그냥 동작합니다. ✨\n"
  },
  {
    "path": "docs/ko/docs/advanced/custom-response.md",
    "content": "# 사용자 정의 응답 - HTML, Stream, 파일, 기타 { #custom-response-html-stream-file-others }\n\n기본적으로 **FastAPI**는 JSON 응답을 반환합니다.\n\n[응답을 직접 반환하기](response-directly.md)에서 본 것처럼 `Response`를 직접 반환하여 이를 재정의할 수 있습니다.\n\n그러나 `Response`를 직접 반환하면(또는 `JSONResponse`와 같은 하위 클래스를 반환하면) 데이터가 자동으로 변환되지 않으며(비록 `response_model`을 선언했다 하더라도), 문서도 자동으로 생성되지 않습니다(예를 들어, 생성된 OpenAPI의 일부로 HTTP 헤더 `Content-Type`에 특정 \"미디어 타입\"을 포함하는 것 등).\n\n하지만 *경로 처리 데코레이터*에서 `response_class` 매개변수를 사용하여 사용할 `Response`(예: 어떤 `Response` 하위 클래스든)를 선언할 수도 있습니다.\n\n*경로 처리 함수*에서 반환하는 내용은 해당 `Response` 안에 담깁니다.\n\n/// note | 참고\n\n미디어 타입이 없는 응답 클래스를 사용하는 경우, FastAPI는 응답에 내용이 없을 것으로 예상하므로 생성된 OpenAPI 문서에서 응답 형식을 문서화하지 않습니다.\n\n///\n\n## JSON 응답 { #json-responses }\n\n기본적으로 FastAPI는 JSON 응답을 반환합니다.\n\n[응답 모델](../tutorial/response-model.md)을 선언하면 FastAPI는 Pydantic을 사용해 데이터를 JSON으로 직렬화합니다.\n\n응답 모델을 선언하지 않으면 FastAPI는 [JSON 호환 가능 인코더](../tutorial/encoder.md)에서 설명한 `jsonable_encoder`를 사용해 데이터를 변환한 뒤 `JSONResponse`에 넣습니다.\n\n`JSONResponse`처럼 JSON 미디어 타입(`application/json`)을 가진 `response_class`를 선언하면, 여러분이 *경로 처리 데코레이터*에서 선언한 Pydantic의 `response_model`로 데이터가 자동 변환(및 필터링)됩니다. 하지만 데이터의 JSON 바이트 직렬화 자체는 Pydantic이 수행하지 않고, `jsonable_encoder`로 변환한 후 `JSONResponse` 클래스에 전달하며, 그 클래스가 Python 표준 JSON 라이브러리를 사용해 바이트로 직렬화합니다.\n\n### JSON 성능 { #json-performance }\n\n요약하면, 최대 성능이 필요하다면 [응답 모델](../tutorial/response-model.md)을 사용하고, *경로 처리 데코레이터*에 `response_class`를 선언하지 마세요.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## HTML 응답 { #html-response }\n\n**FastAPI**에서 HTML 응답을 직접 반환하려면 `HTMLResponse`를 사용하세요.\n\n* `HTMLResponse`를 임포트합니다.\n* *경로 처리 데코레이터*의 `response_class` 매개변수로 `HTMLResponse`를 전달합니다.\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info | 정보\n\n`response_class` 매개변수는 응답의 \"미디어 타입\"을 정의하는 데에도 사용됩니다.\n\n이 경우, HTTP 헤더 `Content-Type`은 `text/html`로 설정됩니다.\n\n그리고 이는 OpenAPI에 그대로 문서화됩니다.\n\n///\n\n### `Response` 반환하기 { #return-a-response }\n\n[응답을 직접 반환하기](response-directly.md)에서 본 것처럼, *경로 처리*에서 응답을 직접 반환하여 재정의할 수도 있습니다.\n\n위의 예제와 동일하게 `HTMLResponse`를 반환하는 코드는 다음과 같을 수 있습니다:\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning | 경고\n\n*경로 처리 함수*에서 직접 반환된 `Response`는 OpenAPI에 문서화되지 않습니다(예를 들어, `Content-Type`이 문서화되지 않음) 그리고 자동 대화형 문서에도 표시되지 않습니다.\n\n///\n\n/// info | 정보\n\n물론 실제 `Content-Type` 헤더, 상태 코드 등은 반환된 `Response` 객체에서 가져옵니다.\n\n///\n\n### OpenAPI에 문서화하고 `Response` 재정의하기 { #document-in-openapi-and-override-response }\n\n함수 내부에서 응답을 재정의하면서 동시에 OpenAPI에서 \"미디어 타입\"을 문서화하고 싶다면, `response_class` 매개변수를 사용하면서 `Response` 객체를 반환할 수 있습니다.\n\n이 경우 `response_class`는 OpenAPI *경로 처리*를 문서화하는 데만 사용되고, 실제로는 여러분이 반환한 `Response`가 그대로 사용됩니다.\n\n#### `HTMLResponse` 직접 반환하기 { #return-an-htmlresponse-directly }\n\n예를 들어, 다음과 같이 작성할 수 있습니다:\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\n이 예제에서 `generate_html_response()` 함수는 HTML을 `str`로 반환하는 대신 이미 `Response`를 생성하고 반환합니다.\n\n`generate_html_response()`를 호출한 결과를 반환함으로써, 기본적인 **FastAPI** 동작을 재정의하는 `Response`를 이미 반환하고 있습니다.\n\n하지만 `response_class`에 `HTMLResponse`를 함께 전달했기 때문에, **FastAPI**는 이를 OpenAPI 및 대화형 문서에서 `text/html`의 HTML로 문서화하는 방법을 알 수 있습니다:\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## 사용 가능한 응답들 { #available-responses }\n\n다음은 사용할 수 있는 몇 가지 응답들입니다.\n\n`Response`를 사용하여 다른 어떤 것도 반환할 수 있으며, 직접 하위 클래스를 만들 수도 있습니다.\n\n/// note | 기술 세부사항\n\n`from starlette.responses import HTMLResponse`를 사용할 수도 있습니다.\n\n**FastAPI**는 개발자인 여러분의 편의를 위해 `starlette.responses`를 `fastapi.responses`로 동일하게 제공하지만, 대부분의 사용 가능한 응답은 Starlette에서 직접 가져옵니다.\n\n///\n\n### `Response` { #response }\n\n기본 `Response` 클래스이며, 다른 모든 응답 클래스가 이를 상속합니다.\n\n이 클래스를 직접 반환할 수 있습니다.\n\n다음 매개변수를 받을 수 있습니다:\n\n* `content` - `str` 또는 `bytes`.\n* `status_code` - HTTP 상태 코드를 나타내는 `int`.\n* `headers` - 문자열로 이루어진 `dict`.\n* `media_type` - 미디어 타입을 나타내는 `str` 예: `\"text/html\"`.\n\nFastAPI(정확히는 Starlette)가 자동으로 Content-Length 헤더를 포함시킵니다. 또한 `media_type`에 기반하여 Content-Type 헤더를 포함하며, 텍스트 타입의 경우 문자 집합을 추가합니다.\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\n텍스트 또는 바이트를 받아 HTML 응답을 반환합니다. 위에서 설명한 내용과 같습니다.\n\n### `PlainTextResponse` { #plaintextresponse }\n\n텍스트 또는 바이트를 받아 일반 텍스트 응답을 반환합니다.\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\n데이터를 받아 `application/json`으로 인코딩된 응답을 반환합니다.\n\n이는 위에서 설명했듯이 **FastAPI**에서 기본적으로 사용되는 응답 형식입니다.\n\n/// note | 기술 세부사항\n\n하지만 응답 모델 또는 반환 타입을 선언한 경우, 해당 모델이 데이터를 JSON으로 직렬화하는 데 직접 사용되며, 올바른 JSON 미디어 타입의 응답이 `JSONResponse` 클래스를 사용하지 않고 바로 반환됩니다.\n\n이 방식이 최상의 성능을 얻는 이상적인 방법입니다.\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\nHTTP 리디렉션 응답을 반환합니다. 기본적으로 상태 코드는 307(임시 리디렉션)으로 설정됩니다.\n\n`RedirectResponse`를 직접 반환할 수 있습니다:\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\n또는 `response_class` 매개변수에서 사용할 수도 있습니다:\n\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\n이 경우, *경로 처리* 함수에서 URL을 직접 반환할 수 있습니다.\n\n이 경우, 사용되는 `status_code`는 `RedirectResponse`의 기본값인 `307`입니다.\n\n---\n\n`status_code` 매개변수를 `response_class` 매개변수와 함께 사용할 수도 있습니다:\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\n비동기 제너레이터 또는 일반 제너레이터/이터레이터(`yield`가 있는 함수)를 받아 응답 본문을 스트리밍합니다.\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | 기술 세부사항\n\n`async` 작업은 `await`에 도달했을 때만 취소될 수 있습니다. `await`가 없으면 제너레이터(`yield`가 있는 함수)는 제대로 취소될 수 없고, 취소가 요청된 후에도 계속 실행될 수 있습니다.\n\n이 작은 예제는 어떤 `await`도 필요하지 않으므로, 이벤트 루프가 취소를 처리할 기회를 주기 위해 `await anyio.sleep(0)`를 추가합니다.\n\n대규모 또는 무한 스트림에서는 더욱 중요합니다.\n\n///\n\n/// tip | 팁\n\n`StreamingResponse`를 직접 반환하는 대신, [데이터 스트리밍](./stream-data.md)에서의 스타일을 따르는 것이 더 편리하며 백그라운드에서 취소 처리를 해줍니다.\n\nJSON Lines를 스트리밍한다면, [JSON Lines 스트리밍](../tutorial/stream-json-lines.md) 튜토리얼을 확인하세요.\n\n///\n\n### `FileResponse` { #fileresponse }\n\n파일을 비동기로 스트리밍하여 응답합니다.\n\n다른 응답 유형과는 다른 인수를 사용하여 객체를 생성합니다:\n\n* `path` - 스트리밍할 파일의 경로.\n* `headers` - 딕셔너리 형식의 사용자 정의 헤더.\n* `media_type` - 미디어 타입을 나타내는 문자열. 설정되지 않은 경우 파일 이름이나 경로를 사용하여 추론합니다.\n* `filename` - 설정된 경우 응답의 `Content-Disposition`에 포함됩니다.\n\n파일 응답에는 적절한 `Content-Length`, `Last-Modified`, 및 `ETag` 헤더가 포함됩니다.\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\n또한 `response_class` 매개변수를 사용할 수도 있습니다:\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\n이 경우, 경로 처리 함수에서 파일 경로를 직접 반환할 수 있습니다.\n\n## 사용자 정의 응답 클래스 { #custom-response-class }\n\n`Response`를 상속받아 사용자 정의 응답 클래스를 생성하고 사용할 수 있습니다.\n\n예를 들어, [`orjson`](https://github.com/ijl/orjson)을 일부 설정과 함께 사용하고 싶다고 가정해봅시다.\n\n들여쓰기 및 포맷된 JSON을 반환하고 싶다면, orjson 옵션 `orjson.OPT_INDENT_2`를 사용할 수 있습니다.\n\n`CustomORJSONResponse`를 생성할 수 있습니다. 여기서 핵심은 `Response.render(content)` 메서드를 생성하여 내용을 `bytes`로 반환하는 것입니다:\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\n이제 다음 대신:\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n...이 응답은 이렇게 반환됩니다:\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\n물론 JSON 포맷팅보다 더 유용하게 활용할 방법을 찾을 수 있을 것입니다. 😉\n\n### `orjson` 또는 응답 모델 { #orjson-or-response-model }\n\n성능이 목적이라면, `orjson` 응답을 사용하는 것보다 [응답 모델](../tutorial/response-model.md)을 사용하는 편이 더 나을 가능성이 큽니다.\n\n응답 모델을 사용하면 FastAPI는 중간 단계(예: `jsonable_encoder`로의 변환) 없이 Pydantic을 사용해 데이터를 JSON으로 직렬화합니다. 이런 중간 단계는 다른 경우에 발생합니다.\n\n그리고 내부적으로 Pydantic은 JSON 직렬화를 위해 `orjson`과 동일한 Rust 기반 메커니즘을 사용하므로, 응답 모델만으로도 이미 최상의 성능을 얻게 됩니다.\n\n## 기본 응답 클래스 { #default-response-class }\n\n**FastAPI** 클래스 인스턴스 또는 `APIRouter`를 생성할 때 기본으로 사용할 응답 클래스를 지정할 수 있습니다.\n\n이를 정의하는 매개변수는 `default_response_class`입니다.\n\n아래 예제에서 **FastAPI**는 모든 *경로 처리*에서 JSON 대신 기본적으로 `HTMLResponse`를 사용합니다.\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip | 팁\n\n여전히 이전처럼 *경로 처리*에서 `response_class`를 재정의할 수 있습니다.\n\n///\n\n## 추가 문서화 { #additional-documentation }\n\nOpenAPI에서 `responses`를 사용하여 미디어 타입 및 기타 세부 정보를 선언할 수도 있습니다: [OpenAPI에서 추가 응답](additional-responses.md).\n"
  },
  {
    "path": "docs/ko/docs/advanced/dataclasses.md",
    "content": "# Dataclasses 사용하기 { #using-dataclasses }\n\nFastAPI는 **Pydantic** 위에 구축되어 있으며, 지금까지는 Pydantic 모델을 사용해 요청과 응답을 선언하는 방법을 보여드렸습니다.\n\n하지만 FastAPI는 [`dataclasses`](https://docs.python.org/3/library/dataclasses.html)도 같은 방식으로 사용하는 것을 지원합니다:\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\n이는 **Pydantic** 덕분에 여전히 지원되는데, Pydantic이 [`dataclasses`에 대한 내부 지원](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel)을 제공하기 때문입니다.\n\n따라서 위 코드처럼 Pydantic을 명시적으로 사용하지 않더라도, FastAPI는 Pydantic을 사용해 표준 dataclasses를 Pydantic의 dataclasses 변형으로 변환합니다.\n\n그리고 물론 다음과 같은 기능도 동일하게 지원합니다:\n\n* 데이터 검증\n* 데이터 직렬화\n* 데이터 문서화 등\n\n이는 Pydantic 모델을 사용할 때와 같은 방식으로 동작합니다. 그리고 실제로도 내부적으로는 Pydantic을 사용해 같은 방식으로 구현됩니다.\n\n/// info\n\ndataclasses는 Pydantic 모델이 할 수 있는 모든 것을 할 수는 없다는 점을 기억하세요.\n\n그래서 여전히 Pydantic 모델을 사용해야 할 수도 있습니다.\n\n하지만 이미 여러 dataclasses를 가지고 있다면, 이것은 FastAPI로 웹 API를 구동하는 데 그것들을 활용할 수 있는 좋은 방법입니다. 🤓\n\n///\n\n## `response_model`에서 Dataclasses 사용하기 { #dataclasses-in-response-model }\n\n`response_model` 매개변수에서도 `dataclasses`를 사용할 수 있습니다:\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\ndataclass는 자동으로 Pydantic dataclass로 변환됩니다.\n\n이렇게 하면 해당 스키마가 API docs 사용자 인터페이스에 표시됩니다:\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## 중첩 데이터 구조에서 Dataclasses 사용하기 { #dataclasses-in-nested-data-structures }\n\n`dataclasses`를 다른 타입 애너테이션과 조합해 중첩 데이터 구조를 만들 수도 있습니다.\n\n일부 경우에는 Pydantic 버전의 `dataclasses`를 사용해야 할 수도 있습니다. 예를 들어 자동 생성된 API 문서에서 오류가 발생하는 경우입니다.\n\n그런 경우 표준 `dataclasses`를 드롭인 대체재인 `pydantic.dataclasses`로 간단히 바꾸면 됩니다:\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. 표준 `dataclasses`에서 `field`를 계속 임포트합니다.\n\n2. `pydantic.dataclasses`는 `dataclasses`의 드롭인 대체재입니다.\n\n3. `Author` dataclass에는 `Item` dataclasses의 리스트가 포함됩니다.\n\n4. `Author` dataclass가 `response_model` 매개변수로 사용됩니다.\n\n5. 요청 본문으로 dataclasses와 함께 다른 표준 타입 애너테이션을 사용할 수 있습니다.\n\n    이 경우에는 `Item` dataclasses의 리스트입니다.\n\n6. 여기서는 dataclasses 리스트인 `items`를 포함하는 딕셔너리를 반환합니다.\n\n    FastAPI는 여전히 데이터를 JSON으로 <dfn title=\"데이터를 전송 가능한 형식으로 변환하는 것\">직렬화</dfn>할 수 있습니다.\n\n7. 여기서 `response_model`은 `Author` dataclasses 리스트에 대한 타입 애너테이션을 사용합니다.\n\n    다시 말해, `dataclasses`를 표준 타입 애너테이션과 조합할 수 있습니다.\n\n8. 이 *경로 처리 함수*는 `async def` 대신 일반 `def`를 사용하고 있다는 점에 주목하세요.\n\n    언제나처럼 FastAPI에서는 필요에 따라 `def`와 `async def`를 조합해 사용할 수 있습니다.\n\n    어떤 것을 언제 사용해야 하는지 다시 확인하고 싶다면, [`async`와 `await`](../async.md#in-a-hurry) 문서의 _\"급하신가요?\"_ 섹션을 확인하세요.\n\n9. 이 *경로 처리 함수*는 dataclasses를(물론 반환할 수도 있지만) 반환하지 않고, 내부 데이터를 담은 딕셔너리들의 리스트를 반환합니다.\n\n    FastAPI는 `response_model` 매개변수(dataclasses 포함)를 사용해 응답을 변환합니다.\n\n`dataclasses`는 다른 타입 애너테이션과 매우 다양한 조합으로 결합해 복잡한 데이터 구조를 구성할 수 있습니다.\n\n더 구체적인 내용은 위 코드 내 애너테이션 팁을 확인하세요.\n\n## 더 알아보기 { #learn-more }\n\n`dataclasses`를 다른 Pydantic 모델과 조합하거나, 이를 상속하거나, 여러분의 모델에 포함하는 등의 작업도 할 수 있습니다.\n\n자세한 내용은 [dataclasses에 관한 Pydantic 문서](https://docs.pydantic.dev/latest/concepts/dataclasses/)를 참고하세요.\n\n## 버전 { #version }\n\n이 기능은 FastAPI `0.67.0` 버전부터 사용할 수 있습니다. 🔖\n"
  },
  {
    "path": "docs/ko/docs/advanced/events.md",
    "content": "# Lifespan 이벤트 { #lifespan-events }\n\n애플리케이션이 **시작**하기 전에 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이는 이 코드가 **한 번**만 실행되며, 애플리케이션이 **요청을 받기 시작하기 전**에 실행된다는 의미입니다.\n\n마찬가지로, 애플리케이션이 **종료**될 때 실행되어야 하는 로직(코드)을 정의할 수 있습니다. 이 경우, 이 코드는 **한 번**만 실행되며, **여러 요청을 처리한 후**에 실행됩니다.\n\n이 코드는 애플리케이션이 요청을 받기 **시작**하기 전에 실행되고, 요청 처리를 **끝낸 직후**에 실행되기 때문에 전체 애플리케이션의 **수명(lifespan)**을 다룹니다(잠시 후 \"lifespan\"이라는 단어가 중요해집니다 😉).\n\n이는 전체 앱에서 사용해야 하는 **자원**을 설정하고, 요청 간에 **공유되는** 자원을 설정하고, 그리고/또는 이후에 **정리**하는 데 매우 유용할 수 있습니다. 예를 들어, 데이터베이스 연결 풀 또는 공유 머신러닝 모델을 로드하는 경우입니다.\n\n## 사용 사례 { #use-case }\n\n먼저 **사용 사례** 예시로 시작한 다음, 이를 어떻게 해결할지 살펴보겠습니다.\n\n요청을 처리하는 데 사용하고 싶은 **머신러닝 모델**이 있다고 상상해 봅시다. 🤖\n\n동일한 모델이 요청 간에 공유되므로, 요청마다 모델이 하나씩 있거나 사용자마다 하나씩 있는 등의 방식이 아닙니다.\n\n모델을 로드하는 데 **상당한 시간이 걸린다고 상상해 봅시다**, 왜냐하면 모델이 **디스크에서 많은 데이터를 읽어야** 하기 때문입니다. 그래서 모든 요청마다 이를 수행하고 싶지는 않습니다.\n\n모듈/파일의 최상위에서 로드할 수도 있지만, 그러면 단순한 자동화된 테스트를 실행하는 경우에도 **모델을 로드**하게 되고, 테스트가 코드의 독립적인 부분을 실행하기 전에 모델이 로드될 때까지 기다려야 하므로 **느려집니다**.\n\n이것이 우리가 해결할 문제입니다. 요청을 처리하기 전에 모델을 로드하되, 코드가 로드되는 동안이 아니라 애플리케이션이 요청을 받기 시작하기 직전에만 로드하겠습니다.\n\n## Lifespan { #lifespan }\n\n`FastAPI` 앱의 `lifespan` 매개변수와 \"컨텍스트 매니저\"를 사용하여 *시작*과 *종료* 로직을 정의할 수 있습니다(컨텍스트 매니저가 무엇인지 잠시 후에 보여드리겠습니다).\n\n예제로 시작한 다음 자세히 살펴보겠습니다.\n\n`yield`를 사용해 비동기 함수 `lifespan()`을 다음과 같이 생성합니다:\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\n여기서는 `yield` 이전에 (가짜) 모델 함수를 머신러닝 모델이 들어 있는 딕셔너리에 넣어 모델을 로드하는 비용이 큰 *시작* 작업을 시뮬레이션합니다. 이 코드는 애플리케이션이 **요청을 받기 시작하기 전**, *시작* 동안에 실행됩니다.\n\n그리고 `yield` 직후에는 모델을 언로드합니다. 이 코드는 애플리케이션이 **요청 처리를 마친 후**, *종료* 직전에 실행됩니다. 예를 들어 메모리나 GPU 같은 자원을 해제할 수 있습니다.\n\n/// tip | 팁\n\n`shutdown`은 애플리케이션을 **중지**할 때 발생합니다.\n\n새 버전을 시작해야 할 수도 있고, 그냥 실행하는 게 지겨워졌을 수도 있습니다. 🤷\n\n///\n\n### Lifespan 함수 { #lifespan-function }\n\n먼저 주목할 점은 `yield`를 사용하여 비동기 함수를 정의하고 있다는 것입니다. 이는 `yield`를 사용하는 의존성과 매우 유사합니다.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\n함수의 첫 번째 부분, 즉 `yield` 이전의 코드는 애플리케이션이 시작되기 **전에** 실행됩니다.\n\n그리고 `yield` 이후의 부분은 애플리케이션이 종료된 **후에** 실행됩니다.\n\n### 비동기 컨텍스트 매니저 { #async-context-manager }\n\n확인해 보면, 함수는 `@asynccontextmanager`로 데코레이션되어 있습니다.\n\n이는 함수를 \"**비동기 컨텍스트 매니저**\"라고 불리는 것으로 변환합니다.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\n파이썬에서 **컨텍스트 매니저**는 `with` 문에서 사용할 수 있는 것입니다. 예를 들어, `open()`은 컨텍스트 매니저로 사용할 수 있습니다:\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\n최근 버전의 파이썬에는 **비동기 컨텍스트 매니저**도 있습니다. 이를 `async with`와 함께 사용합니다:\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\n위와 같은 컨텍스트 매니저 또는 비동기 컨텍스트 매니저를 만들면, `with` 블록에 들어가기 전에 `yield` 이전의 코드를 실행하고, `with` 블록을 벗어난 후에는 `yield` 이후의 코드를 실행합니다.\n\n위의 코드 예제에서는 직접 사용하지 않고, FastAPI에 전달하여 FastAPI가 이를 사용하도록 합니다.\n\n`FastAPI` 앱의 `lifespan` 매개변수는 **비동기 컨텍스트 매니저**를 받으므로, 새 `lifespan` 비동기 컨텍스트 매니저를 전달할 수 있습니다.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## 대체 이벤트(사용 중단) { #alternative-events-deprecated }\n\n/// warning | 경고\n\n*시작*과 *종료*를 처리하는 권장 방법은 위에서 설명한 대로 `FastAPI` 앱의 `lifespan` 매개변수를 사용하는 것입니다. `lifespan` 매개변수를 제공하면 `startup`과 `shutdown` 이벤트 핸들러는 더 이상 호출되지 않습니다. `lifespan`만 쓰거나 이벤트만 쓰거나 둘 중 하나이지, 둘 다는 아닙니다.\n\n이 부분은 아마 건너뛰셔도 됩니다.\n\n///\n\n*시작*과 *종료* 동안 실행될 이 로직을 정의하는 대체 방법이 있습니다.\n\n애플리케이션이 시작되기 전에 또는 애플리케이션이 종료될 때 실행되어야 하는 이벤트 핸들러(함수)를 정의할 수 있습니다.\n\n이 함수들은 `async def` 또는 일반 `def`로 선언할 수 있습니다.\n\n### `startup` 이벤트 { #startup-event }\n\n애플리케이션이 시작되기 전에 실행되어야 하는 함수를 추가하려면, `\"startup\"` 이벤트로 선언합니다:\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\n이 경우, `startup` 이벤트 핸들러 함수는 \"database\"(그냥 `dict`) 항목을 일부 값으로 초기화합니다.\n\n여러 개의 이벤트 핸들러 함수를 추가할 수 있습니다.\n\n그리고 모든 `startup` 이벤트 핸들러가 완료될 때까지 애플리케이션은 요청을 받기 시작하지 않습니다.\n\n### `shutdown` 이벤트 { #shutdown-event }\n\n애플리케이션이 종료될 때 실행되어야 하는 함수를 추가하려면, `\"shutdown\"` 이벤트로 선언합니다:\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\n여기서 `shutdown` 이벤트 핸들러 함수는 텍스트 한 줄 `\"Application shutdown\"`을 `log.txt` 파일에 기록합니다.\n\n/// info | 정보\n\n`open()` 함수에서 `mode=\"a\"`는 \"append\"(추가)를 의미하므로, 기존 내용을 덮어쓰지 않고 파일에 있던 내용 뒤에 줄이 추가됩니다.\n\n///\n\n/// tip | 팁\n\n이 경우에는 파일과 상호작용하는 표준 파이썬 `open()` 함수를 사용하고 있습니다.\n\n따라서 I/O(input/output)가 포함되어 있어 디스크에 기록되는 것을 \"기다리는\" 과정이 필요합니다.\n\n하지만 `open()`은 `async`와 `await`를 사용하지 않습니다.\n\n그래서 이벤트 핸들러 함수는 `async def` 대신 표준 `def`로 선언합니다.\n\n///\n\n### `startup`과 `shutdown`을 함께 { #startup-and-shutdown-together }\n\n*시작*과 *종료* 로직은 연결되어 있을 가능성이 높습니다. 무언가를 시작했다가 끝내거나, 자원을 획득했다가 해제하는 등의 작업이 필요할 수 있습니다.\n\n로직이나 변수를 함께 공유하지 않는 분리된 함수에서 이를 처리하면, 전역 변수에 값을 저장하거나 비슷한 트릭이 필요해져 더 어렵습니다.\n\n그 때문에, 이제는 위에서 설명한 대로 `lifespan`을 사용하는 것이 권장됩니다.\n\n## 기술적 세부사항 { #technical-details }\n\n호기심 많은 분들을 위한 기술적인 세부사항입니다. 🤓\n\n내부적으로 ASGI 기술 사양에서는 이것이 [Lifespan Protocol](https://asgi.readthedocs.io/en/latest/specs/lifespan.html)의 일부이며, `startup`과 `shutdown`이라는 이벤트를 정의합니다.\n\n/// info | 정보\n\nStarlette `lifespan` 핸들러에 대해서는 [Starlette의 Lifespan 문서](https://www.starlette.dev/lifespan/)에서 더 읽어볼 수 있습니다.\n\n또한 코드의 다른 영역에서 사용할 수 있는 lifespan 상태를 처리하는 방법도 포함되어 있습니다.\n\n///\n\n## 서브 애플리케이션 { #sub-applications }\n\n🚨 이 lifespan 이벤트(startup 및 shutdown)는 메인 애플리케이션에 대해서만 실행되며, [서브 애플리케이션 - Mounts](sub-applications.md)에는 실행되지 않음을 유의하세요.\n"
  },
  {
    "path": "docs/ko/docs/advanced/generate-clients.md",
    "content": "# SDK 생성하기 { #generating-sdks }\n\n**FastAPI**는 **OpenAPI** 사양을 기반으로 하므로, FastAPI의 API는 많은 도구가 이해할 수 있는 표준 형식으로 설명할 수 있습니다.\n\n덕분에 여러 언어용 클라이언트 라이브러리(<abbr title=\"Software Development Kits - 소프트웨어 개발 키트\">**SDKs**</abbr>), 최신 **문서**, 그리고 코드와 동기화된 **테스트** 또는 **자동화 워크플로**를 쉽게 생성할 수 있습니다.\n\n이 가이드에서는 FastAPI 백엔드용 **TypeScript SDK**를 생성하는 방법을 배웁니다.\n\n## 오픈 소스 SDK 생성기 { #open-source-sdk-generators }\n\n다양하게 활용할 수 있는 옵션으로 [OpenAPI Generator](https://openapi-generator.tech/)가 있으며, **다양한 프로그래밍 언어**를 지원하고 OpenAPI 사양으로부터 SDK를 생성할 수 있습니다.\n\n**TypeScript 클라이언트**의 경우 [Hey API](https://heyapi.dev/)는 TypeScript 생태계에 최적화된 경험을 제공하는 목적에 맞게 설계된 솔루션입니다.\n\n더 많은 SDK 생성기는 [OpenAPI.Tools](https://openapi.tools/#sdk)에서 확인할 수 있습니다.\n\n/// tip | 팁\n\nFastAPI는 **OpenAPI 3.1** 사양을 자동으로 생성하므로, 사용하는 도구는 이 버전을 지원해야 합니다.\n\n///\n\n## FastAPI 스폰서의 SDK 생성기 { #sdk-generators-from-fastapi-sponsors }\n\n이 섹션에서는 FastAPI를 후원하는 회사들이 제공하는 **벤처 투자 기반** 및 **기업 지원** 솔루션을 소개합니다. 이 제품들은 고품질로 생성된 SDK에 더해 **추가 기능**과 **통합**을 제공합니다.\n\n✨ [**FastAPI 후원하기**](../help-fastapi.md#sponsor-the-author) ✨를 통해, 이 회사들은 프레임워크와 그 **생태계**가 건강하고 **지속 가능**하게 유지되도록 돕습니다.\n\n또한 이들의 후원은 FastAPI **커뮤니티**(여러분)에 대한 강한 헌신을 보여주며, **좋은 서비스**를 제공하는 것뿐 아니라, 견고하고 활발한 프레임워크인 FastAPI를 지원하는 데에도 관심이 있음을 나타냅니다. 🙇\n\n예를 들어 다음을 사용해 볼 수 있습니다:\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\n이 중 일부는 오픈 소스이거나 무료 티어를 제공하므로, 비용 부담 없이 사용해 볼 수 있습니다. 다른 상용 SDK 생성기도 있으며 온라인에서 찾을 수 있습니다. 🤓\n\n## TypeScript SDK 만들기 { #create-a-typescript-sdk }\n\n간단한 FastAPI 애플리케이션으로 시작해 보겠습니다:\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\n*경로 처리*에서 요청 페이로드와 응답 페이로드에 사용하는 모델을 `Item`, `ResponseMessage` 모델로 정의하고 있다는 점에 주목하세요.\n\n### API 문서 { #api-docs }\n\n`/docs`로 이동하면, 요청으로 보낼 데이터와 응답으로 받을 데이터에 대한 **스키마(schemas)**가 있는 것을 볼 수 있습니다:\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\n이 스키마는 앱에서 모델로 선언되었기 때문에 볼 수 있습니다.\n\n그 정보는 앱의 **OpenAPI 스키마**에서 사용할 수 있고, 이후 API 문서에 표시됩니다.\n\nOpenAPI에 포함된 모델의 동일한 정보가 **클라이언트 코드 생성**에 사용될 수 있습니다.\n\n### Hey API { #hey-api }\n\n모델이 포함된 FastAPI 앱이 준비되면, Hey API를 사용해 TypeScript 클라이언트를 생성할 수 있습니다. 가장 빠른 방법은 npx를 사용하는 것입니다.\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\n이 명령은 `./src/client`에 TypeScript SDK를 생성합니다.\n\n[`@hey-api/openapi-ts` 설치 방법](https://heyapi.dev/openapi-ts/get-started)과 [생성된 결과물](https://heyapi.dev/openapi-ts/output)은 해당 웹사이트에서 확인할 수 있습니다.\n\n### SDK 사용하기 { #using-the-sdk }\n\n이제 클라이언트 코드를 import해서 사용할 수 있습니다. 아래처럼 사용할 수 있으며, 메서드에 대한 자동 완성이 제공되는 것을 확인할 수 있습니다:\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\n보낼 페이로드에 대해서도 자동 완성이 제공됩니다:\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip | 팁\n\n`name`과 `price`에 대한 자동 완성은 FastAPI 애플리케이션에서 `Item` 모델에 정의된 내용입니다.\n\n///\n\n전송하는 데이터에 대해 인라인 오류도 표시됩니다:\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\n응답 객체도 자동 완성을 제공합니다:\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## 태그가 있는 FastAPI 앱 { #fastapi-app-with-tags }\n\n대부분의 경우 FastAPI 앱은 더 커지고, 서로 다른 *경로 처리* 그룹을 분리하기 위해 태그를 사용하게 될 가능성이 큽니다.\n\n예를 들어 **items** 섹션과 **users** 섹션이 있고, 이를 태그로 분리할 수 있습니다:\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### 태그로 TypeScript 클라이언트 생성하기 { #generate-a-typescript-client-with-tags }\n\n태그를 사용하는 FastAPI 앱에 대해 클라이언트를 생성하면, 일반적으로 생성된 클라이언트 코드도 태그를 기준으로 분리됩니다.\n\n이렇게 하면 클라이언트 코드에서 항목들이 올바르게 정렬되고 그룹화됩니다:\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\n이 경우 다음이 있습니다:\n\n* `ItemsService`\n* `UsersService`\n\n### 클라이언트 메서드 이름 { #client-method-names }\n\n현재 `createItemItemsPost` 같은 생성된 메서드 이름은 그다지 깔끔하지 않습니다:\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n...이는 클라이언트 생성기가 각 *경로 처리*에 대해 OpenAPI 내부의 **operation ID**를 사용하기 때문입니다.\n\nOpenAPI는 모든 *경로 처리* 전체에서 operation ID가 각각 유일해야 한다고 요구합니다. 그래서 FastAPI는 operation ID가 유일하도록 **함수 이름**, **경로**, **HTTP method/operation**을 조합해 operation ID를 생성합니다.\n\n하지만 다음에서 이를 개선하는 방법을 보여드리겠습니다. 🤓\n\n## 커스텀 Operation ID와 더 나은 메서드 이름 { #custom-operation-ids-and-better-method-names }\n\n클라이언트에서 **더 단순한 메서드 이름**을 갖도록, operation ID가 **생성되는 방식**을 **수정**할 수 있습니다.\n\n이 경우 operation ID가 다른 방식으로도 **유일**하도록 보장해야 합니다.\n\n예를 들어 각 *경로 처리*이 태그를 갖도록 한 다음, **태그**와 *경로 처리* **이름**(함수 이름)을 기반으로 operation ID를 생성할 수 있습니다.\n\n### 유일 ID 생성 함수 커스터마이징 { #custom-generate-unique-id-function }\n\nFastAPI는 각 *경로 처리*에 대해 **유일 ID**를 사용하며, 이는 **operation ID** 및 요청/응답에 필요한 커스텀 모델 이름에도 사용됩니다.\n\n이 함수를 커스터마이징할 수 있습니다. 이 함수는 `APIRoute`를 받아 문자열을 반환합니다.\n\n예를 들어 아래에서는 첫 번째 태그(대부분 태그는 하나만 있을 것입니다)와 *경로 처리* 이름(함수 이름)을 사용합니다.\n\n그 다음 이 커스텀 함수를 `generate_unique_id_function` 매개변수로 **FastAPI**에 전달할 수 있습니다:\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### 커스텀 Operation ID로 TypeScript 클라이언트 생성하기 { #generate-a-typescript-client-with-custom-operation-ids }\n\n이제 클라이언트를 다시 생성하면, 개선된 메서드 이름을 확인할 수 있습니다:\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\n보시다시피, 이제 메서드 이름은 태그 다음에 함수 이름이 오며, URL 경로와 HTTP operation의 정보는 포함하지 않습니다.\n\n### 클라이언트 생성기를 위한 OpenAPI 사양 전처리 { #preprocess-the-openapi-specification-for-the-client-generator }\n\n생성된 코드에는 여전히 일부 **중복 정보**가 있습니다.\n\n`ItemsService`(태그에서 가져옴)에 이미 **items**가 포함되어 있어 이 메서드가 items와 관련되어 있음을 알 수 있지만, 메서드 이름에도 태그 이름이 접두사로 붙어 있습니다. 😕\n\nOpenAPI 전반에서는 operation ID가 **유일**하다는 것을 보장하기 위해 이 방식을 유지하고 싶을 수 있습니다.\n\n하지만 생성된 클라이언트에서는, 클라이언트를 생성하기 직전에 OpenAPI operation ID를 **수정**해서 메서드 이름을 더 보기 좋고 **깔끔하게** 만들 수 있습니다.\n\nOpenAPI JSON을 `openapi.json` 파일로 다운로드한 뒤, 아래와 같은 스크립트로 **접두사 태그를 제거**할 수 있습니다:\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\n이렇게 하면 operation ID가 `items-get_items` 같은 형태에서 `get_items`로 변경되어, 클라이언트 생성기가 더 단순한 메서드 이름을 생성할 수 있습니다.\n\n### 전처리된 OpenAPI로 TypeScript 클라이언트 생성하기 { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\n이제 최종 결과가 `openapi.json` 파일에 있으므로, 입력 위치를 업데이트해야 합니다:\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\n새 클라이언트를 생성한 후에는 **깔끔한 메서드 이름**을 가지면서도, **자동 완성**, **인라인 오류** 등은 그대로 제공됩니다:\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## 장점 { #benefits }\n\n자동으로 생성된 클라이언트를 사용하면 다음에 대해 **자동 완성**을 받을 수 있습니다:\n\n* 메서드\n* 본문(body)의 요청 페이로드, 쿼리 파라미터 등\n* 응답 페이로드\n\n또한 모든 것에 대해 **인라인 오류**도 확인할 수 있습니다.\n\n그리고 백엔드 코드를 업데이트한 뒤 프론트엔드를 **재생성(regenerate)**하면, 새 *경로 처리*가 메서드로 추가되고 기존 것은 제거되며, 그 밖의 변경 사항도 생성된 코드에 반영됩니다. 🤓\n\n이는 무언가 변경되면 그 변경이 클라이언트 코드에도 자동으로 **반영**된다는 뜻입니다. 또한 클라이언트를 **빌드(build)**하면 사용된 데이터가 **불일치(mismatch)**할 경우 오류가 발생합니다.\n\n따라서 운영 환경에서 최종 사용자에게 오류가 노출된 뒤 문제를 추적하는 대신, 개발 사이클 초기에 **많은 오류를 매우 빨리 감지**할 수 있습니다. ✨\n"
  },
  {
    "path": "docs/ko/docs/advanced/index.md",
    "content": "# 심화 사용자 안내서 { #advanced-user-guide }\n\n## 추가 기능 { #additional-features }\n\n메인 [자습서 - 사용자 안내서](../tutorial/index.md)는 여러분이 **FastAPI**의 모든 주요 기능을 둘러보시기에 충분할 것입니다.\n\n이어지는 장에서는 여러분이 다른 옵션, 구성 및 추가 기능을 보실 수 있습니다.\n\n/// tip | 팁\n\n다음 장들이 **반드시 \"심화\"**인 것은 아닙니다.\n\n그리고 여러분의 사용 사례에 대한 해결책이 그중 하나에 있을 수 있습니다.\n\n///\n\n## 자습서를 먼저 읽으십시오 { #read-the-tutorial-first }\n\n여러분은 메인 [자습서 - 사용자 안내서](../tutorial/index.md)의 지식으로 **FastAPI**의 대부분의 기능을 사용하실 수 있습니다.\n\n이어지는 장들은 여러분이 메인 자습서 - 사용자 안내서를 이미 읽으셨으며 주요 아이디어를 알고 계신다고 가정합니다.\n"
  },
  {
    "path": "docs/ko/docs/advanced/json-base64-bytes.md",
    "content": "# 바이트를 Base64로 포함하는 JSON { #json-with-bytes-as-base64 }\n\n애플리케이션에서 JSON 데이터를 주고받아야 하지만 그 안에 바이너리 데이터를 포함해야 한다면, base64로 인코딩해서 포함할 수 있습니다.\n\n## Base64와 파일 { #base64-vs-files }\n\n바이너리 데이터 업로드에는 [요청 파일](../tutorial/request-files.md)을, 바이너리 데이터 전송에는 [커스텀 응답 - FileResponse](./custom-response.md#fileresponse--fileresponse-)를 사용할 수 있는지 먼저 고려하세요. JSON으로 인코딩하는 대신 말입니다.\n\nJSON은 UTF-8로 인코딩된 문자열만 포함할 수 있으므로, 원시 바이트를 그대로 담을 수 없습니다.\n\nBase64는 바이너리 데이터를 문자열로 인코딩할 수 있지만, 이를 위해 원래의 바이너리 데이터보다 더 많은 문자 수를 사용해야 하므로 일반적인 파일 전송보다 비효율적일 수 있습니다.\n\n반드시 JSON 안에 바이너리 데이터를 포함해야 하고, 파일을 사용할 수 없을 때만 base64를 사용하세요.\n\n## Pydantic `bytes` { #pydantic-bytes }\n\n`bytes` 필드를 가진 Pydantic 모델을 선언하고, 모델 설정에서 `val_json_bytes`를 사용하도록 지정하면 입력 JSON 데이터를 base64로 “검증”하도록 할 수 있습니다. 이 검증 과정의 일부로 base64 문자열을 바이트로 디코딩합니다.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\n`/docs`를 확인하면 `data` 필드가 base64로 인코딩된 bytes를 기대한다고 표시됩니다:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\n아래와 같은 요청을 보낼 수 있습니다:\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip | 팁\n\n`aGVsbG8=`는 `hello`의 base64 인코딩입니다.\n\n///\n\n그러면 Pydantic이 base64 문자열을 디코딩하여 모델의 `data` 필드에 원래 바이트를 제공합니다.\n\n다음과 같은 응답을 받게 됩니다:\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## 출력 데이터용 Pydantic `bytes` { #pydantic-bytes-for-output-data }\n\n출력 데이터에도 모델 설정에서 `ser_json_bytes`와 함께 `bytes` 필드를 사용할 수 있습니다. 그러면 Pydantic이 JSON 응답을 생성할 때 바이트를 base64로 “직렬화”합니다.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## 입력과 출력 데이터용 Pydantic `bytes` { #pydantic-bytes-for-input-and-output-data }\n\n물론, 동일한 모델을 사용해 JSON 데이터를 받을 때는 `val_json_bytes`로 입력을 “검증”하고, JSON 데이터를 보낼 때는 `ser_json_bytes`로 출력을 “직렬화”하도록 base64를 모두 처리하게 구성할 수 있습니다.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/ko/docs/advanced/middleware.md",
    "content": "# 고급 Middleware { #advanced-middleware }\n\n메인 튜토리얼에서 애플리케이션에 [커스텀 Middleware](../tutorial/middleware.md)를 추가하는 방법을 읽었습니다.\n\n그리고 [`CORSMiddleware`로 CORS 처리하기](../tutorial/cors.md)도 읽었습니다.\n\n이 섹션에서는 다른 middleware들을 사용하는 방법을 살펴보겠습니다.\n\n## ASGI middleware 추가하기 { #adding-asgi-middlewares }\n\n**FastAPI**는 Starlette를 기반으로 하고 <abbr title=\"Asynchronous Server Gateway Interface - 비동기 서버 게이트웨이 인터페이스\">ASGI</abbr> 사양을 구현하므로, 어떤 ASGI middleware든 사용할 수 있습니다.\n\nASGI 사양을 따르기만 하면, FastAPI나 Starlette를 위해 만들어진 middleware가 아니어도 동작합니다.\n\n일반적으로 ASGI middleware는 첫 번째 인자로 ASGI 앱을 받도록 기대하는 클래스입니다.\n\n그래서 서드파티 ASGI middleware 문서에서는 아마 다음과 같이 하라고 안내할 것입니다:\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\n하지만 FastAPI(정확히는 Starlette)는 더 간단한 방법을 제공하며, 이를 통해 내부 middleware가 서버 오류를 처리하고 커스텀 예외 핸들러가 올바르게 동작하도록 보장합니다.\n\n이를 위해(그리고 CORS 예제에서처럼) `app.add_middleware()`를 사용합니다.\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()`는 첫 번째 인자로 middleware 클래스를 받고, 그 뒤에는 middleware에 전달할 추가 인자들을 받습니다.\n\n## 통합 middleware { #integrated-middlewares }\n\n**FastAPI**에는 일반적인 사용 사례를 위한 여러 middleware가 포함되어 있습니다. 다음에서 이를 사용하는 방법을 살펴보겠습니다.\n\n/// note | 기술 세부사항\n\n다음 예제에서는 `from starlette.middleware.something import SomethingMiddleware`를 사용해도 됩니다.\n\n**FastAPI**는 개발자 편의를 위해 `fastapi.middleware`에 여러 middleware를 제공하지만, 사용 가능한 대부분의 middleware는 Starlette에서 직접 제공됩니다.\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\n들어오는 모든 요청이 `https` 또는 `wss`여야 하도록 강제합니다.\n\n`http` 또는 `ws`로 들어오는 모든 요청은 대신 보안 스킴으로 리디렉션됩니다.\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\nHTTP Host Header 공격을 방어하기 위해, 들어오는 모든 요청에 올바르게 설정된 `Host` 헤더가 있어야 하도록 강제합니다.\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\n다음 인자들을 지원합니다:\n\n* `allowed_hosts` - 호스트명으로 허용할 도메인 이름 목록입니다. `*.example.com` 같은 와일드카드 도메인으로 서브도메인을 매칭하는 것도 지원합니다. 어떤 호스트명이든 허용하려면 `allowed_hosts=[\"*\"]`를 사용하거나 middleware를 생략하세요.\n* `www_redirect` - True로 설정하면, 허용된 호스트의 non-www 버전으로 들어오는 요청을 www 버전으로 리디렉션합니다. 기본값은 `True`입니다.\n\n들어오는 요청이 올바르게 검증되지 않으면 `400` 응답이 전송됩니다.\n\n## `GZipMiddleware` { #gzipmiddleware }\n\n`Accept-Encoding` 헤더에 `\"gzip\"`이 포함된 어떤 요청이든 GZip 응답을 처리합니다.\n\n이 middleware는 일반 응답과 스트리밍 응답을 모두 처리합니다.\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\n다음 인자들을 지원합니다:\n\n* `minimum_size` - 바이트 단위로 지정한 최소 크기보다 작은 응답은 GZip으로 압축하지 않습니다. 기본값은 `500`입니다.\n* `compresslevel` - GZip 압축 중에 사용됩니다. 1부터 9까지의 정수입니다. 기본값은 `9`입니다. 값이 낮을수록 압축은 더 빠르지만 파일 크기는 더 커지고, 값이 높을수록 압축은 더 느리지만 파일 크기는 더 작아집니다.\n\n## 다른 middleware { #other-middlewares }\n\n다른 ASGI middleware도 많이 있습니다.\n\n예를 들어:\n\n* [Uvicorn의 `ProxyHeadersMiddleware`](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n* [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\n사용 가능한 다른 middleware를 보려면 [Starlette의 Middleware 문서](https://www.starlette.dev/middleware/)와 [ASGI Awesome List](https://github.com/florimondmanca/awesome-asgi)를 확인하세요.\n"
  },
  {
    "path": "docs/ko/docs/advanced/openapi-callbacks.md",
    "content": "# OpenAPI 콜백 { #openapi-callbacks }\n\n다른 사람이 만든 *external API*(아마도 여러분의 API를 *사용*할 동일한 개발자)가 요청을 트리거하도록 만드는 *경로 처리*를 가진 API를 만들 수 있습니다.\n\n여러분의 API 앱이 *external API*를 호출할 때 일어나는 과정을 \"callback\"이라고 합니다. 외부 개발자가 작성한 소프트웨어가 여러분의 API로 요청을 보낸 다음, 여러분의 API가 다시 *external API*로 요청을 보내 *되돌려 호출*하기 때문입니다(아마도 같은 개발자가 만든 API일 것입니다).\n\n이 경우, 그 *external API*가 어떤 형태여야 하는지 문서화하고 싶을 수 있습니다. 어떤 *경로 처리*를 가져야 하는지, 어떤 body를 기대하는지, 어떤 응답을 반환해야 하는지 등입니다.\n\n## 콜백이 있는 앱 { #an-app-with-callbacks }\n\n예시로 확인해 보겠습니다.\n\n청구서를 생성할 수 있는 앱을 개발한다고 가정해 보세요.\n\n이 청구서는 `id`, `title`(선택 사항), `customer`, `total`을 갖습니다.\n\n여러분의 API 사용자(외부 개발자)는 POST 요청으로 여러분의 API에서 청구서를 생성합니다.\n\n그 다음 여러분의 API는(가정해 보면):\n\n* 청구서를 외부 개발자의 고객에게 전송합니다.\n* 돈을 수금합니다.\n* API 사용자(외부 개발자)의 API로 다시 알림을 보냅니다.\n    * 이는 (여러분의 API에서) 그 외부 개발자가 제공하는 어떤 *external API*로 POST 요청을 보내는 방식으로 수행됩니다(이것이 \"callback\"입니다).\n\n## 일반적인 **FastAPI** 앱 { #the-normal-fastapi-app }\n\n먼저 콜백을 추가하기 전, 일반적인 API 앱이 어떻게 생겼는지 보겠습니다.\n\n`Invoice` body를 받는 *경로 처리*와, 콜백을 위한 URL을 담는 쿼리 파라미터 `callback_url`이 있을 것입니다.\n\n이 부분은 꽤 일반적이며, 대부분의 코드는 이미 익숙할 것입니다:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip | 팁\n\n`callback_url` 쿼리 파라미터는 Pydantic의 [Url](https://docs.pydantic.dev/latest/api/networks/) 타입을 사용합니다.\n\n///\n\n유일하게 새로운 것은 *경로 처리 데코레이터*의 인자로 `callbacks=invoices_callback_router.routes`가 들어간다는 점입니다. 이것이 무엇인지 다음에서 보겠습니다.\n\n## 콜백 문서화하기 { #documenting-the-callback }\n\n실제 콜백 코드는 여러분의 API 앱에 크게 의존합니다.\n\n그리고 앱마다 많이 달라질 수 있습니다.\n\n다음처럼 한두 줄의 코드일 수도 있습니다:\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\n하지만 콜백에서 가장 중요한 부분은, 여러분의 API 사용자(외부 개발자)가 콜백 요청 body로 *여러분의 API*가 보낼 데이터 등에 맞춰 *external API*를 올바르게 구현하도록 보장하는 것입니다.\n\n그래서 다음으로 할 일은, *여러분의 API*에서 보내는 콜백을 받기 위해 그 *external API*가 어떤 형태여야 하는지 문서화하는 코드를 추가하는 것입니다.\n\n그 문서는 여러분의 API에서 `/docs`의 Swagger UI에 표시되며, 외부 개발자들이 *external API*를 어떻게 만들어야 하는지 알 수 있게 해줍니다.\n\n이 예시는 콜백 자체(한 줄 코드로도 될 수 있음)를 구현하지 않고, 문서화 부분만 구현합니다.\n\n/// tip | 팁\n\n실제 콜백은 단지 HTTP 요청입니다.\n\n콜백을 직접 구현할 때는 [HTTPX](https://www.python-httpx.org)나 [Requests](https://requests.readthedocs.io/) 같은 것을 사용할 수 있습니다.\n\n///\n\n## 콜백 문서화 코드 작성하기 { #write-the-callback-documentation-code }\n\n이 코드는 앱에서 실행되지 않습니다. 그 *external API*가 어떤 형태여야 하는지 *문서화*하는 데만 필요합니다.\n\n하지만 **FastAPI**로 API의 자동 문서를 쉽게 생성하는 방법은 이미 알고 있습니다.\n\n따라서 그와 같은 지식을 사용해 *external API*가 어떻게 생겨야 하는지 문서화할 것입니다... 즉 외부 API가 구현해야 하는 *경로 처리(들)*(여러분의 API가 호출할 것들)을 만들어서 말입니다.\n\n/// tip | 팁\n\n콜백을 문서화하는 코드를 작성할 때는, 자신이 그 *외부 개발자*라고 상상하는 것이 유용할 수 있습니다. 그리고 지금은 *여러분의 API*가 아니라 *external API*를 구현하고 있다고 생각해 보세요.\n\n이 관점(외부 개발자의 관점)을 잠시 채택하면, 그 *external API*를 위해 파라미터, body용 Pydantic 모델, 응답 등을 어디에 두어야 하는지가 더 명확하게 느껴질 수 있습니다.\n\n///\n\n### 콜백 `APIRouter` 생성하기 { #create-a-callback-apirouter }\n\n먼저 하나 이상의 콜백을 담을 새 `APIRouter`를 만듭니다.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### 콜백 *경로 처리* 생성하기 { #create-the-callback-path-operation }\n\n콜백 *경로 처리*를 만들려면 위에서 만든 동일한 `APIRouter`를 사용합니다.\n\n일반적인 FastAPI *경로 처리*처럼 보일 것입니다:\n\n* 아마도 받아야 할 body 선언이 있을 것입니다(예: `body: InvoiceEvent`).\n* 그리고 반환해야 할 응답 선언도 있을 수 있습니다(예: `response_model=InvoiceEventReceived`).\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\n일반적인 *경로 처리*와의 주요 차이점은 2가지입니다:\n\n* 실제 코드를 가질 필요가 없습니다. 여러분의 앱은 이 코드를 절대 호출하지 않기 때문입니다. 이는 *external API*를 문서화하는 데만 사용됩니다. 따라서 함수는 그냥 `pass`만 있어도 됩니다.\n* *path*에는 [OpenAPI 3 표현식](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression)(자세한 내용은 아래 참고)이 포함될 수 있으며, 이를 통해 *여러분의 API*로 보내진 원래 요청의 파라미터와 일부 값을 변수로 사용할 수 있습니다.\n\n### 콜백 경로 표현식 { #the-callback-path-expression }\n\n콜백 *path*는 *여러분의 API*로 보내진 원래 요청의 일부를 포함할 수 있는 [OpenAPI 3 표현식](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression)을 가질 수 있습니다.\n\n이 경우, 다음 `str`입니다:\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\n따라서 여러분의 API 사용자(외부 개발자)가 *여러분의 API*로 다음 요청을 보내고:\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\nJSON body가 다음과 같다면:\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\n그러면 *여러분의 API*는 청구서를 처리하고, 나중에 어느 시점에서 `callback_url`(즉 *external API*)로 콜백 요청을 보냅니다:\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\n그리고 다음과 같은 JSON body를 포함할 것입니다:\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\n또한 그 *external API*로부터 다음과 같은 JSON body 응답을 기대합니다:\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip | 팁\n\n콜백 URL에는 `callback_url` 쿼리 파라미터로 받은 URL(`https://www.external.org/events`)뿐 아니라, JSON body 안의 청구서 `id`(`2expen51ve`)도 함께 사용된다는 점에 주목하세요.\n\n///\n\n### 콜백 라우터 추가하기 { #add-the-callback-router }\n\n이 시점에서, 위에서 만든 콜백 라우터 안에 *콜백 경로 처리(들)*(즉 *external developer*가 *external API*에 구현해야 하는 것들)을 준비했습니다.\n\n이제 *여러분의 API 경로 처리 데코레이터*에서 `callbacks` 파라미터를 사용해, 그 콜백 라우터의 `.routes` 속성(실제로는 routes/*경로 처리*의 `list`)을 전달합니다:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip | 팁\n\n`callback=`에 라우터 자체(`invoices_callback_router`)를 넘기는 것이 아니라, `invoices_callback_router.routes`처럼 `.routes` 속성을 넘긴다는 점에 주목하세요.\n\n///\n\n### 문서 확인하기 { #check-the-docs }\n\n이제 앱을 실행하고 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)로 이동하세요.\n\n*경로 처리*에 대해 \"Callbacks\" 섹션을 포함한 문서가 표시되며, *external API*가 어떤 형태여야 하는지 확인할 수 있습니다:\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/ko/docs/advanced/openapi-webhooks.md",
    "content": "# OpenAPI Webhooks { #openapi-webhooks }\n\n앱이 어떤 데이터와 함께 (요청을 보내서) *사용자의* 앱을 호출할 수 있고, 보통 어떤 **이벤트**를 **알리기** 위해 그렇게 할 수 있다는 것을 API **사용자**에게 알려야 하는 경우가 있습니다.\n\n이는 사용자가 여러분의 API로 요청을 보내는 일반적인 과정 대신, **여러분의 API**(또는 앱)가 **사용자의 시스템**(사용자의 API, 사용자의 앱)으로 **요청을 보낼 수 있다**는 의미입니다.\n\n이를 보통 **webhook**이라고 합니다.\n\n## Webhooks 단계 { #webhooks-steps }\n\n일반적인 과정은, 여러분이 코드에서 보낼 메시지, 즉 **요청 본문(body)**이 무엇인지 **정의**하는 것입니다.\n\n또한 여러분의 앱이 어떤 **시점**에 그 요청(또는 이벤트)을 보낼지도 어떤 방식으로든 정의합니다.\n\n그리고 **사용자**는 (예: 어딘가의 웹 대시보드에서) 여러분의 앱이 그 요청을 보내야 할 **URL**을 어떤 방식으로든 정의합니다.\n\nwebhook의 URL을 등록하는 방법과 실제로 그 요청을 보내는 코드에 대한 모든 **로직**은 여러분에게 달려 있습니다. **여러분의 코드**에서 원하는 방식으로 작성하면 됩니다.\n\n## **FastAPI**와 OpenAPI로 webhooks 문서화하기 { #documenting-webhooks-with-fastapi-and-openapi }\n\n**FastAPI**에서는 OpenAPI를 사용해, 이러한 webhook의 이름, 여러분의 앱이 보낼 수 있는 HTTP 작업 타입(예: `POST`, `PUT` 등), 그리고 여러분의 앱이 보낼 요청 **본문(body)**을 정의할 수 있습니다.\n\n이렇게 하면 사용자가 여러분의 **webhook** 요청을 받기 위해 **자신들의 API를 구현**하기가 훨씬 쉬워지고, 경우에 따라서는 자신의 API 코드 일부를 자동 생성할 수도 있습니다.\n\n/// info | 정보\n\nWebhooks는 OpenAPI 3.1.0 이상에서 사용할 수 있으며, FastAPI `0.99.0` 이상에서 지원됩니다.\n\n///\n\n## webhooks가 있는 앱 { #an-app-with-webhooks }\n\n**FastAPI** 애플리케이션을 만들면, *경로 처리*를 정의하는 것과 같은 방식으로(예: `@app.webhooks.post()`), *webhooks*를 정의하는 데 사용할 수 있는 `webhooks` 속성이 있습니다.\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\n여러분이 정의한 webhook은 **OpenAPI** 스키마와 자동 **docs UI**에 포함됩니다.\n\n/// info | 정보\n\n`app.webhooks` 객체는 실제로 `APIRouter`일 뿐이며, 여러 파일로 앱을 구조화할 때 사용하는 것과 동일한 타입입니다.\n\n///\n\nwebhook에서는 실제로(`/items/` 같은) *경로(path)*를 선언하지 않는다는 점에 유의하세요. 그곳에 전달하는 텍스트는 webhook의 **식별자**(이벤트 이름)일 뿐입니다. 예를 들어 `@app.webhooks.post(\"new-subscription\")`에서 webhook 이름은 `new-subscription`입니다.\n\n이는 **사용자**가 webhook 요청을 받고 싶은 실제 **URL 경로**를 다른 방식(예: 웹 대시보드)으로 정의할 것이라고 기대하기 때문입니다.\n\n### 문서 확인하기 { #check-the-docs }\n\n이제 앱을 실행하고 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)로 이동하세요.\n\n문서에 일반적인 *경로 처리*가 보이고, 이제는 일부 **webhooks**도 함께 보일 것입니다:\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/ko/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# 경로 처리 고급 구성 { #path-operation-advanced-configuration }\n\n## OpenAPI operationId { #openapi-operationid }\n\n/// warning | 경고\n\nOpenAPI “전문가”가 아니라면, 아마 이 내용은 필요하지 않을 것입니다.\n\n///\n\n매개변수 `operation_id`를 사용해 *경로 처리*에 사용할 OpenAPI `operationId`를 설정할 수 있습니다.\n\n각 작업마다 고유하도록 보장해야 합니다.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### *경로 처리 함수* 이름을 operationId로 사용하기 { #using-the-path-operation-function-name-as-the-operationid }\n\nAPI의 함수 이름을 `operationId`로 사용하고 싶다면, 모든 API를 순회하면서 `APIRoute.name`을 사용해 각 *경로 처리*의 `operation_id`를 덮어쓸 수 있습니다.\n\n모든 *경로 처리*를 추가한 뒤에 수행해야 합니다.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip | 팁\n\n`app.openapi()`를 수동으로 호출한다면, 그 전에 `operationId`들을 업데이트해야 합니다.\n\n///\n\n/// warning | 경고\n\n이렇게 할 경우, 각 *경로 처리 함수*의 이름이 고유하도록 보장해야 합니다.\n\n서로 다른 모듈(파이썬 파일)에 있어도 마찬가지입니다.\n\n///\n\n## OpenAPI에서 제외하기 { #exclude-from-openapi }\n\n생성된 OpenAPI 스키마(따라서 자동 문서화 시스템)에서 특정 *경로 처리*를 제외하려면, `include_in_schema` 매개변수를 `False`로 설정하세요:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## docstring에서 고급 설명 가져오기 { #advanced-description-from-docstring }\n\nOpenAPI에 사용할 *경로 처리 함수*의 docstring 줄 수를 제한할 수 있습니다.\n\n`\\f`(이스케이프된 \"form feed\" 문자)를 추가하면 **FastAPI**는 이 지점에서 OpenAPI에 사용할 출력 내용을 잘라냅니다.\n\n문서에는 표시되지 않지만, Sphinx 같은 다른 도구는 나머지 부분을 사용할 수 있습니다.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## 추가 응답 { #additional-responses }\n\n*경로 처리*에 대해 `response_model`과 `status_code`를 선언하는 방법을 이미 보셨을 것입니다.\n\n이는 *경로 처리*의 기본 응답에 대한 메타데이터를 정의합니다.\n\n모델, 상태 코드 등과 함께 추가 응답도 선언할 수 있습니다.\n\n이에 대한 문서의 전체 장이 있으니, [OpenAPI의 추가 응답](additional-responses.md)에서 읽어보세요.\n\n## OpenAPI Extra { #openapi-extra }\n\n애플리케이션에서 *경로 처리*를 선언하면, **FastAPI**는 OpenAPI 스키마에 포함될 해당 *경로 처리*의 관련 메타데이터를 자동으로 생성합니다.\n\n/// note | 기술 세부사항\n\nOpenAPI 명세에서는 이를 [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object)라고 부릅니다.\n\n///\n\n여기에는 *경로 처리*에 대한 모든 정보가 있으며, 자동 문서를 생성하는 데 사용됩니다.\n\n`tags`, `parameters`, `requestBody`, `responses` 등이 포함됩니다.\n\n이 *경로 처리* 전용 OpenAPI 스키마는 보통 **FastAPI**가 자동으로 생성하지만, 확장할 수도 있습니다.\n\n/// tip | 팁\n\n이는 저수준 확장 지점입니다.\n\n추가 응답만 선언하면 된다면, 더 편리한 방법은 [OpenAPI의 추가 응답](additional-responses.md)을 사용하는 것입니다.\n\n///\n\n`openapi_extra` 매개변수를 사용해 *경로 처리*의 OpenAPI 스키마를 확장할 수 있습니다.\n\n### OpenAPI 확장 { #openapi-extensions }\n\n예를 들어 `openapi_extra`는 [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions)를 선언하는 데 도움이 될 수 있습니다:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\n자동 API 문서를 열면, 해당 특정 *경로 처리*의 하단에 확장이 표시됩니다.\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\n또한 API의 `/openapi.json`에서 결과 OpenAPI를 보면, 특정 *경로 처리*의 일부로 확장이 포함된 것도 확인할 수 있습니다:\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### 사용자 정의 OpenAPI *경로 처리* 스키마 { #custom-openapi-path-operation-schema }\n\n`openapi_extra`의 딕셔너리는 *경로 처리*에 대해 자동으로 생성된 OpenAPI 스키마와 깊게 병합됩니다.\n\n따라서 자동 생성된 스키마에 추가 데이터를 더할 수 있습니다.\n\n예를 들어 Pydantic과 함께 FastAPI의 자동 기능을 사용하지 않고, 자체 코드로 요청을 읽고 검증하기로 결정할 수도 있지만, OpenAPI 스키마에는 여전히 그 요청을 정의하고 싶을 수 있습니다.\n\n그럴 때 `openapi_extra`를 사용할 수 있습니다:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\n이 예시에서는 어떤 Pydantic 모델도 선언하지 않았습니다. 사실 요청 바디는 JSON으로 <dfn title=\"bytes 같은 일반 형식에서 Python 객체로 변환\">파싱</dfn>되지도 않고, `bytes`로 직접 읽습니다. 그리고 함수 `magic_data_reader()`가 어떤 방식으로든 이를 파싱하는 역할을 담당합니다.\n\n그럼에도 불구하고, 요청 바디에 대해 기대하는 스키마를 선언할 수 있습니다.\n\n### 사용자 정의 OpenAPI 콘텐츠 타입 { #custom-openapi-content-type }\n\n같은 트릭을 사용하면, Pydantic 모델을 이용해 JSON Schema를 정의하고 이를 *경로 처리*의 사용자 정의 OpenAPI 스키마 섹션에 포함시킬 수 있습니다.\n\n요청의 데이터 타입이 JSON이 아니더라도 이렇게 할 수 있습니다.\n\n예를 들어 이 애플리케이션에서는 Pydantic 모델에서 JSON Schema를 추출하는 FastAPI의 통합 기능도, JSON에 대한 자동 검증도 사용하지 않습니다. 실제로 요청 콘텐츠 타입을 JSON이 아니라 YAML로 선언합니다:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\n그럼에도 기본 통합 기능을 사용하지 않더라도, YAML로 받고자 하는 데이터에 대한 JSON Schema를 수동으로 생성하기 위해 Pydantic 모델을 여전히 사용합니다.\n\n그 다음 요청을 직접 사용하고, 바디를 `bytes`로 추출합니다. 이는 FastAPI가 요청 페이로드를 JSON으로 파싱하려고 시도조차 하지 않는다는 뜻입니다.\n\n그리고 코드에서 YAML 콘텐츠를 직접 파싱한 뒤, 다시 같은 Pydantic 모델을 사용해 YAML 콘텐츠를 검증합니다:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip | 팁\n\n여기서는 같은 Pydantic 모델을 재사용합니다.\n\n하지만 마찬가지로, 다른 방식으로 검증할 수도 있습니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/advanced/response-change-status-code.md",
    "content": "# 응답 - 상태 코드 변경 { #response-change-status-code }\n\n기본 [응답 상태 코드 설정](../tutorial/response-status-code.md)이 가능하다는 걸 이미 알고 계실 겁니다.\n\n하지만 경우에 따라 기본 설정과 다른 상태 코드를 반환해야 할 때가 있습니다.\n\n## 사용 예 { #use-case }\n\n예를 들어 기본적으로 HTTP 상태 코드 \"OK\" `200`을 반환하고 싶다고 가정해 봅시다.\n\n하지만 데이터가 존재하지 않으면 이를 새로 생성하고, HTTP 상태 코드 \"CREATED\" `201`을 반환하고자 할 때가 있을 수 있습니다.\n\n하지만 여전히 `response_model`을 사용하여 반환하는 데이터를 필터링하고 변환할 수 있기를 원합니다.\n\n이런 경우에는 `Response` 파라미터를 사용할 수 있습니다.\n\n## `Response` 파라미터 사용하기 { #use-a-response-parameter }\n\n*경로 처리 함수*에 `Response` 타입의 파라미터를 선언할 수 있습니다. (쿠키와 헤더에 대해 선언하는 것과 유사하게)\n\n그리고 이 *임시* 응답 객체에서 `status_code`를 설정할 수 있습니다.\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\n그리고 평소처럼 필요한 어떤 객체든 반환할 수 있습니다(`dict`, 데이터베이스 모델 등).\n\n`response_model`을 선언했다면 반환된 객체는 여전히 필터링되고 변환됩니다.\n\n**FastAPI**는 이 *임시* 응답 객체에서 상태 코드(쿠키와 헤더 포함)를 추출하여, `response_model`로 필터링된 반환 값을 포함하는 최종 응답에 넣습니다.\n\n또한, 의존성에서도 `Response` 파라미터를 선언하고 그 안에서 상태 코드를 설정할 수 있습니다. 단, 마지막으로 설정된 상태 코드가 우선 적용된다는 점을 유의하세요.\n"
  },
  {
    "path": "docs/ko/docs/advanced/response-cookies.md",
    "content": "# 응답 쿠키 { #response-cookies }\n\n## `Response` 매개변수 사용하기 { #use-a-response-parameter }\n\n*경로 처리 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다.\n\n그런 다음 해당 *임시* 응답 객체에서 쿠키를 설정할 수 있습니다.\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\n그런 다음 일반적으로 하듯이 필요한 어떤 객체든 반환할 수 있습니다(`dict`, 데이터베이스 모델 등).\n\n그리고 `response_model`을 선언했다면 반환한 객체를 거르고 변환하는 데 여전히 사용됩니다.\n\n**FastAPI**는 그 *임시* 응답에서 쿠키(또한 헤더 및 상태 코드)를 추출하고, `response_model`로 필터링된 반환 값이 포함된 최종 응답에 이를 넣습니다.\n\n또한 의존관계에서 `Response` 매개변수를 선언하고, 해당 의존성에서 쿠키(및 헤더)를 설정할 수도 있습니다.\n\n## `Response`를 직접 반환하기 { #return-a-response-directly }\n\n코드에서 `Response`를 직접 반환할 때도 쿠키를 생성할 수 있습니다.\n\n이를 위해 [Response를 직접 반환하기](response-directly.md)에서 설명한 대로 응답을 생성할 수 있습니다.\n\n그런 다음 쿠키를 설정하고 반환하면 됩니다:\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip\n\n`Response` 매개변수를 사용하지 않고 응답을 직접 반환하는 경우, FastAPI는 이를 직접 반환한다는 점에 유의하세요.\n\n따라서 데이터가 올바른 유형인지 확인해야 합니다. 예: `JSONResponse`를 반환하는 경우, JSON과 호환되는지 확인하세요.\n\n또한 `response_model`로 필터링되어야 했던 데이터를 전송하지 않도록 하세요.\n\n///\n\n### 추가 정보 { #more-info }\n\n/// note | 기술 세부사항\n\n`from starlette.responses import Response` 또는 `from starlette.responses import JSONResponse`를 사용할 수도 있습니다.\n\n**FastAPI**는 개발자의 편의를 위해 `fastapi.responses`로 동일한 `starlette.responses`를 제공합니다. 하지만 사용 가능한 대부분의 응답은 Starlette에서 직접 제공됩니다.\n\n또한 `Response`는 헤더와 쿠키를 설정하는 데 자주 사용되므로, **FastAPI**는 이를 `fastapi.Response`로도 제공합니다.\n\n///\n\n사용 가능한 모든 매개변수와 옵션은 [Starlette의 문서](https://www.starlette.dev/responses/#set-cookie)에서 확인할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/advanced/response-directly.md",
    "content": "# 응답을 직접 반환하기 { #return-a-response-directly }\n\n**FastAPI**에서 *경로 처리(path operation)*를 생성할 때, 일반적으로 `dict`, `list`, Pydantic 모델, 데이터베이스 모델 등의 데이터를 반환할 수 있습니다.\n\n[응답 모델](../tutorial/response-model.md)을 선언하면 FastAPI는 Pydantic을 사용해 데이터를 JSON으로 직렬화합니다.\n\n응답 모델을 선언하지 않으면, FastAPI는 [JSON 호환 가능 인코더](../tutorial/encoder.md)에 설명된 `jsonable_encoder`를 사용해 데이터를 변환하고 이를 `JSONResponse`에 넣습니다.\n\n또한 `JSONResponse`를 직접 생성해 반환할 수도 있습니다.\n\n/// tip | 팁\n\n일반적으로 `JSONResponse`를 직접 반환하는 것보다 [응답 모델](../tutorial/response-model.md)을 사용하는 편이 성능이 훨씬 좋습니다. 이렇게 하면 Pydantic이 Rust에서 데이터를 직렬화합니다.\n\n///\n\n## `Response` 반환하기 { #return-a-response }\n\n`Response` 또는 그 하위 클래스를 반환할 수 있습니다.\n\n/// info | 정보\n\n`JSONResponse` 자체도 `Response`의 하위 클래스입니다.\n\n///\n\n그리고 `Response`를 반환하면 **FastAPI**가 이를 그대로 전달합니다.\n\nPydantic 모델로 데이터 변환을 수행하지 않으며, 내용을 다른 형식으로 변환하지 않습니다.\n\n이로 인해 많은 유연성을 얻을 수 있습니다. 어떤 데이터 유형이든 반환할 수 있고, 데이터 선언이나 유효성 검사를 재정의할 수 있습니다.\n\n또한 많은 책임도 따릅니다. 반환하는 데이터가 올바르고, 올바른 형식이며, 직렬화가 가능하도록 여러분이 직접 보장해야 합니다.\n\n## `Response`에서 `jsonable_encoder` 사용하기 { #using-the-jsonable-encoder-in-a-response }\n\n**FastAPI**는 반환하는 `Response`에 아무런 변경도 하지 않으므로, 그 내용이 준비되어 있는지 확인해야 합니다.\n\n예를 들어, Pydantic 모델을 먼저 `dict`로 변환하고 `datetime`, `UUID` 등의 모든 데이터 타입을 JSON 호환 타입으로 변환하지 않으면 Pydantic 모델을 `JSONResponse`에 넣을 수 없습니다.\n\n이러한 경우, 데이터를 응답에 전달하기 전에 `jsonable_encoder`를 사용하여 변환할 수 있습니다:\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | 기술 세부사항\n\n`from starlette.responses import JSONResponse`를 사용할 수도 있습니다.\n\n**FastAPI**는 개발자의 편의를 위해 `starlette.responses`를 `fastapi.responses`로 제공합니다. 하지만 대부분의 사용 가능한 응답은 Starlette에서 직접 제공합니다.\n\n///\n\n## 사용자 정의 `Response` 반환하기 { #returning-a-custom-response }\n\n위 예제는 필요한 모든 부분을 보여주지만, 아직은 그다지 유용하지 않습니다. `item`을 그냥 직접 반환했어도 **FastAPI**가 기본으로 이를 `JSONResponse`에 넣고 `dict`로 변환하는 등의 작업을 모두 수행해 주었을 것이기 때문입니다.\n\n이제, 이를 사용해 사용자 정의 응답을 반환하는 방법을 알아보겠습니다.\n\n예를 들어 [XML](https://en.wikipedia.org/wiki/XML) 응답을 반환하고 싶다고 가정해 보겠습니다.\n\nXML 내용을 문자열에 넣고, 이를 `Response`에 넣어 반환할 수 있습니다:\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## 응답 모델 동작 방식 { #how-a-response-model-works }\n\n경로 처리에서 [응답 모델 - 반환 타입](../tutorial/response-model.md)을 선언하면 **FastAPI**는 Pydantic을 사용해 데이터를 JSON으로 직렬화합니다.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\n이는 Rust 측에서 처리되므로, 일반적인 Python과 `JSONResponse` 클래스로 수행하는 것보다 성능이 훨씬 좋습니다.\n\n`response_model` 또는 반환 타입을 사용할 때 FastAPI는 `jsonable_encoder`로 데이터를 변환(이는 더 느립니다)하지도 않고, `JSONResponse` 클래스를 사용하지도 않습니다.\n\n대신 응답 모델(또는 반환 타입)을 사용해 Pydantic이 생성한 JSON 바이트를 가져와, JSON에 맞는 미디어 타입(`application/json`)을 가진 `Response`를 직접 반환합니다.\n\n## 참고 사항 { #notes }\n\n`Response`를 직접 반환할 때, 그 데이터는 자동으로 유효성 검사되거나, 변환(직렬화)되거나, 문서화되지 않습니다.\n\n그러나 [OpenAPI에서 추가 응답](additional-responses.md)에서 설명된 대로 문서화할 수 있습니다.\n\n이후 섹션에서 자동 데이터 변환, 문서화 등을 계속 사용하면서 이러한 사용자 정의 `Response`를 사용하는/선언하는 방법을 확인할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/advanced/response-headers.md",
    "content": "# 응답 헤더 { #response-headers }\n\n## `Response` 매개변수 사용하기 { #use-a-response-parameter }\n\n여러분은 *경로 처리 함수*에서 `Response` 타입의 매개변수를 선언할 수 있습니다 (쿠키와 같이 사용할 수 있습니다).\n\n그런 다음, 여러분은 해당 *임시* 응답 객체에서 헤더를 설정할 수 있습니다.\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\n그 후, 일반적으로 사용하듯이 필요한 객체(`dict`, 데이터베이스 모델 등)를 반환할 수 있습니다.\n\n`response_model`을 선언한 경우, 반환한 객체를 필터링하고 변환하는 데 여전히 사용됩니다.\n\n**FastAPI**는 해당 *임시* 응답에서 헤더(쿠키와 상태 코드도 포함)를 추출하여, 여러분이 반환한 값을 포함하는 최종 응답에 `response_model`로 필터링된 값을 넣습니다.\n\n또한, 종속성에서 `Response` 매개변수를 선언하고 그 안에서 헤더(및 쿠키)를 설정할 수 있습니다.\n\n## `Response` 직접 반환하기 { #return-a-response-directly }\n\n`Response`를 직접 반환할 때에도 헤더를 추가할 수 있습니다.\n\n[응답을 직접 반환하기](response-directly.md)에 설명한 대로 응답을 생성하고, 헤더를 추가 매개변수로 전달하세요:\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | 기술 세부사항\n\n`from starlette.responses import Response`나 `from starlette.responses import JSONResponse`를 사용할 수도 있습니다.\n\n**FastAPI**는 개발자인 여러분의 편의를 위해 `starlette.responses`와 동일한 것을 `fastapi.responses`로도 제공합니다. 하지만 사용 가능한 대부분의 응답은 Starlette에서 직접 제공합니다.\n\n그리고 `Response`는 헤더와 쿠키를 설정하는 데 자주 사용될 수 있으므로, **FastAPI**는 `fastapi.Response`로도 이를 제공합니다.\n\n///\n\n## 커스텀 헤더 { #custom-headers }\n\n커스텀 사설 헤더는 [`X-` 접두어를 사용하여](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) 추가할 수 있다는 점을 기억하세요.\n\n하지만, 여러분이 브라우저에서 클라이언트가 볼 수 있기를 원하는 커스텀 헤더가 있는 경우, CORS 설정에 이를 추가해야 합니다([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)에서 자세히 알아보세요). [Starlette의 CORS 문서](https://www.starlette.dev/middleware/#corsmiddleware)에 문서화된 `expose_headers` 매개변수를 사용하세요.\n"
  },
  {
    "path": "docs/ko/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP Basic Auth { #http-basic-auth }\n\n가장 단순한 경우에는 HTTP Basic Auth를 사용할 수 있습니다.\n\nHTTP Basic Auth에서는 애플리케이션이 사용자명과 비밀번호가 들어 있는 헤더를 기대합니다.\n\n이를 받지 못하면 HTTP 401 \"Unauthorized\" 오류를 반환합니다.\n\n그리고 값이 `Basic`이고 선택적으로 `realm` 파라미터를 포함하는 `WWW-Authenticate` 헤더를 반환합니다.\n\n이는 브라우저가 사용자명과 비밀번호를 입력하는 통합 프롬프트를 표시하도록 알려줍니다.\n\n그다음 사용자명과 비밀번호를 입력하면, 브라우저가 자동으로 해당 값을 헤더에 담아 전송합니다.\n\n## 간단한 HTTP Basic Auth { #simple-http-basic-auth }\n\n* `HTTPBasic`과 `HTTPBasicCredentials`를 임포트합니다.\n* `HTTPBasic`을 사용해 \"`security` scheme\"을 생성합니다.\n* *경로 처리*에서 dependency로 해당 `security`를 사용합니다.\n* `HTTPBasicCredentials` 타입의 객체를 반환합니다:\n    * 전송된 `username`과 `password`를 포함합니다.\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\n처음으로 URL을 열어보면(또는 문서에서 \"Execute\" 버튼을 클릭하면) 브라우저가 사용자명과 비밀번호를 물어봅니다:\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## 사용자명 확인하기 { #check-the-username }\n\n더 완전한 예시입니다.\n\ndependency를 사용해 사용자명과 비밀번호가 올바른지 확인하세요.\n\n이를 위해 Python 표준 모듈 [`secrets`](https://docs.python.org/3/library/secrets.html)를 사용해 사용자명과 비밀번호를 확인합니다.\n\n`secrets.compare_digest()`는 `bytes` 또는 ASCII 문자(영어에서 사용하는 문자)만 포함한 `str`을 받아야 합니다. 즉, `Sebastián`의 `á` 같은 문자가 있으면 동작하지 않습니다.\n\n이를 처리하기 위해 먼저 `username`과 `password`를 UTF-8로 인코딩해서 `bytes`로 변환합니다.\n\n그런 다음 `secrets.compare_digest()`를 사용해 `credentials.username`이 `\"stanleyjobson\"`이고 `credentials.password`가 `\"swordfish\"`인지 확실히 확인할 수 있습니다.\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\n이는 다음과 비슷합니다:\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # 어떤 오류를 반환\n    ...\n```\n\n하지만 `secrets.compare_digest()`를 사용하면 \"timing attacks\"라고 불리는 한 유형의 공격에 대해 안전해집니다.\n\n### 타이밍 공격 { #timing-attacks }\n\n그렇다면 \"timing attack\"이란 무엇일까요?\n\n공격자들이 사용자명과 비밀번호를 추측하려고 한다고 가정해봅시다.\n\n그리고 사용자명 `johndoe`, 비밀번호 `love123`으로 요청을 보냅니다.\n\n그러면 애플리케이션의 Python 코드는 대략 다음과 같을 것입니다:\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\n하지만 Python이 `johndoe`의 첫 글자 `j`를 `stanleyjobson`의 첫 글자 `s`와 비교하는 순간, 두 문자열이 같지 않다는 것을 이미 알게 되어 `False`를 반환합니다. 이는 “나머지 글자들을 비교하느라 계산을 더 낭비할 필요가 없다”고 판단하기 때문입니다. 그리고 애플리케이션은 \"Incorrect username or password\"라고 말합니다.\n\n그런데 공격자들이 사용자명을 `stanleyjobsox`, 비밀번호를 `love123`으로 다시 시도합니다.\n\n그러면 애플리케이션 코드는 다음과 비슷하게 동작합니다:\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nPython은 두 문자열이 같지 않다는 것을 알아차리기 전까지 `stanleyjobsox`와 `stanleyjobson` 양쪽의 `stanleyjobso` 전체를 비교해야 합니다. 그래서 \"Incorrect username or password\"라고 응답하기까지 추가로 몇 마이크로초가 더 걸릴 것입니다.\n\n#### 응답 시간은 공격자에게 도움이 됩니다 { #the-time-to-answer-helps-the-attackers }\n\n이 시점에서 서버가 \"Incorrect username or password\" 응답을 보내는 데 몇 마이크로초 더 걸렸다는 것을 알아채면, 공격자들은 _무언가_ 맞았다는 것(초기 몇 글자가 맞았다는 것)을 알게 됩니다.\n\n그리고 `johndoe`보다는 `stanleyjobsox`에 더 가까운 값을 시도해야 한다는 것을 알고 다시 시도할 수 있습니다.\n\n#### \"전문적인\" 공격 { #a-professional-attack }\n\n물론 공격자들은 이런 작업을 손으로 하지 않습니다. 보통 초당 수천~수백만 번 테스트할 수 있는 프로그램을 작성할 것이고, 한 번에 정답 글자 하나씩 추가로 얻어낼 수 있습니다.\n\n그렇게 하면 몇 분 또는 몇 시간 만에, 응답에 걸린 시간만을 이용해(우리 애플리케이션의 “도움”을 받아) 올바른 사용자명과 비밀번호를 추측할 수 있게 됩니다.\n\n#### `secrets.compare_digest()`로 해결하기 { #fix-it-with-secrets-compare-digest }\n\n하지만 우리 코드는 실제로 `secrets.compare_digest()`를 사용하고 있습니다.\n\n요약하면, `stanleyjobsox`와 `stanleyjobson`을 비교하는 데 걸리는 시간은 `johndoe`와 `stanleyjobson`을 비교하는 데 걸리는 시간과 같아집니다. 비밀번호도 마찬가지입니다.\n\n이렇게 애플리케이션 코드에서 `secrets.compare_digest()`를 사용하면, 이러한 범위의 보안 공격 전반에 대해 안전해집니다.\n\n### 오류 반환하기 { #return-the-error }\n\n자격 증명이 올바르지 않다고 판단되면, 상태 코드 401(자격 증명이 제공되지 않았을 때와 동일)을 사용하는 `HTTPException`을 반환하고 브라우저가 로그인 프롬프트를 다시 표시하도록 `WWW-Authenticate` 헤더를 추가하세요:\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/ko/docs/advanced/security/index.md",
    "content": "# 고급 보안 { #advanced-security }\n\n## 추가 기능 { #additional-features }\n\n[튜토리얼 - 사용자 가이드: 보안](../../tutorial/security/index.md)에서 다룬 내용 외에도, 보안을 처리하기 위한 몇 가지 추가 기능이 있습니다.\n\n/// tip | 팁\n\n다음 섹션들은 **반드시 \"고급\"이라고 할 수는 없습니다**.\n\n그리고 사용 사례에 따라, 그중 하나에 해결책이 있을 수도 있습니다.\n\n///\n\n## 먼저 튜토리얼 읽기 { #read-the-tutorial-first }\n\n다음 섹션은 주요 [튜토리얼 - 사용자 가이드: 보안](../../tutorial/security/index.md)을 이미 읽었다고 가정합니다.\n\n모두 동일한 개념을 기반으로 하지만, 몇 가지 추가 기능을 사용할 수 있게 해줍니다.\n"
  },
  {
    "path": "docs/ko/docs/advanced/security/oauth2-scopes.md",
    "content": "# OAuth2 스코프 { #oauth2-scopes }\n\n**FastAPI**에서 OAuth2 스코프를 직접 사용할 수 있으며, 자연스럽게 동작하도록 통합되어 있습니다.\n\n이를 통해 OAuth2 표준을 따르는 더 세밀한 권한 시스템을 OpenAPI 애플리케이션(및 API 문서)에 통합할 수 있습니다.\n\n스코프를 사용하는 OAuth2는 Facebook, Google, GitHub, Microsoft, X(Twitter) 등 많은 대형 인증 제공자가 사용하는 메커니즘입니다. 이들은 이를 통해 사용자와 애플리케이션에 특정 권한을 제공합니다.\n\nFacebook, Google, GitHub, Microsoft, X(Twitter)로 “로그인”할 때마다, 해당 애플리케이션은 스코프가 있는 OAuth2를 사용하고 있습니다.\n\n이 섹션에서는 **FastAPI** 애플리케이션에서 동일한 “스코프가 있는 OAuth2”로 인증(Authentication)과 인가(Authorization)를 관리하는 방법을 확인합니다.\n\n/// warning | 경고\n\n이 섹션은 다소 고급 내용입니다. 이제 막 시작했다면 건너뛰어도 됩니다.\n\nOAuth2 스코프가 반드시 필요한 것은 아니며, 인증과 인가는 원하는 방식으로 처리할 수 있습니다.\n\n하지만 스코프가 있는 OAuth2는 (OpenAPI와 함께) API 및 API 문서에 깔끔하게 통합될 수 있습니다.\n\n그럼에도 불구하고, 해당 스코프(또는 그 밖의 어떤 보안/인가 요구사항이든)는 코드에서 필요에 맞게 직접 강제해야 합니다.\n\n많은 경우 스코프가 있는 OAuth2는 과한 선택일 수 있습니다.\n\n하지만 필요하다고 알고 있거나 궁금하다면 계속 읽어보세요.\n\n///\n\n## OAuth2 스코프와 OpenAPI { #oauth2-scopes-and-openapi }\n\nOAuth2 사양은 “스코프(scopes)”를 공백으로 구분된 문자열 목록으로 정의합니다.\n\n각 문자열의 내용은 어떤 형식이든 될 수 있지만, 공백을 포함하면 안 됩니다.\n\n이 스코프들은 “권한”을 나타냅니다.\n\nOpenAPI(예: API 문서)에서는 “security schemes”를 정의할 수 있습니다.\n\n이 security scheme 중 하나가 OAuth2를 사용한다면, 스코프도 선언하고 사용할 수 있습니다.\n\n각 “스코프”는 (공백 없는) 문자열일 뿐입니다.\n\n보통 다음과 같이 특정 보안 권한을 선언하는 데 사용합니다:\n\n* `users:read` 또는 `users:write` 는 흔한 예시입니다.\n* `instagram_basic` 는 Facebook/Instagram에서 사용합니다.\n* `https://www.googleapis.com/auth/drive` 는 Google에서 사용합니다.\n\n/// info | 정보\n\nOAuth2에서 “스코프”는 필요한 특정 권한을 선언하는 문자열일 뿐입니다.\n\n`:` 같은 다른 문자가 있거나 URL이어도 상관없습니다.\n\n그런 세부사항은 구현에 따라 달라집니다.\n\nOAuth2 입장에서는 그저 문자열입니다.\n\n///\n\n## 전체 개요 { #global-view }\n\n먼저, 메인 **튜토리얼 - 사용자 가이드**의 [비밀번호(및 해싱)를 사용하는 OAuth2, JWT 토큰을 사용하는 Bearer](../../tutorial/security/oauth2-jwt.md) 예제에서 어떤 부분이 바뀌는지 빠르게 살펴보겠습니다. 이제 OAuth2 스코프를 사용합니다:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\n이제 변경 사항을 단계별로 살펴보겠습니다.\n\n## OAuth2 보안 스킴 { #oauth2-security-scheme }\n\n첫 번째 변경 사항은 이제 사용 가능한 스코프 2개(`me`, `items`)로 OAuth2 보안 스킴을 선언한다는 점입니다.\n\n`scopes` 매개변수는 각 스코프를 키로 하고, 설명을 값으로 하는 `dict`를 받습니다:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\n이제 스코프를 선언했기 때문에, 로그인/인가할 때 API 문서에 스코프가 표시됩니다.\n\n그리고 접근을 허용할 스코프를 선택할 수 있게 됩니다: `me`와 `items`.\n\n이는 Facebook, Google, GitHub 등으로 로그인하면서 권한을 부여할 때 사용되는 것과 동일한 메커니즘입니다:\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## 스코프를 포함한 JWT 토큰 { #jwt-token-with-scopes }\n\n이제 토큰 *경로 처리*를 수정해, 요청된 스코프를 반환하도록 합니다.\n\n여전히 동일한 `OAuth2PasswordRequestForm`을 사용합니다. 여기에는 요청에서 받은 각 스코프를 담는 `scopes` 속성이 있으며, 타입은 `str`의 `list`입니다.\n\n그리고 JWT 토큰의 일부로 스코프를 반환합니다.\n\n/// danger | 위험\n\n단순화를 위해, 여기서는 요청으로 받은 스코프를 그대로 토큰에 추가하고 있습니다.\n\n하지만 실제 애플리케이션에서는 보안을 위해, 사용자가 실제로 가질 수 있는 스코프만(또는 미리 정의한 것만) 추가하도록 반드시 확인해야 합니다.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## *경로 처리*와 의존성에서 스코프 선언하기 { #declare-scopes-in-path-operations-and-dependencies }\n\n이제 `/users/me/items/`에 대한 *경로 처리*가 스코프 `items`를 요구한다고 선언합니다.\n\n이를 위해 `fastapi`에서 `Security`를 import하여 사용합니다.\n\n`Security`는 (`Depends`처럼) 의존성을 선언하는 데 사용할 수 있지만, `Security`는 스코프(문자열) 목록을 받는 `scopes` 매개변수도 받습니다.\n\n이 경우, 의존성 함수 `get_current_active_user`를 `Security`에 전달합니다(`Depends`로 할 때와 같은 방식).\n\n하지만 스코프 `list`도 함께 전달합니다. 여기서는 스코프 하나만: `items`(더 많을 수도 있습니다).\n\n또한 의존성 함수 `get_current_active_user`는 `Depends`뿐 아니라 `Security`로도 하위 의존성을 선언할 수 있습니다. 자체 하위 의존성 함수(`get_current_user`)와 추가 스코프 요구사항을 선언합니다.\n\n이 경우에는 스코프 `me`를 요구합니다(여러 스코프를 요구할 수도 있습니다).\n\n/// note | 참고\n\n반드시 서로 다른 곳에 서로 다른 스코프를 추가해야 하는 것은 아닙니다.\n\n여기서는 **FastAPI**가 서로 다른 레벨에서 선언된 스코프를 어떻게 처리하는지 보여주기 위해 이렇게 합니다.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | 기술 세부사항\n\n`Security`는 실제로 `Depends`의 서브클래스이며, 나중에 보게 될 추가 매개변수 하나만 더 있습니다.\n\n하지만 `Depends` 대신 `Security`를 사용하면, **FastAPI**는 보안 스코프를 선언할 수 있음을 알고 내부적으로 이를 사용하며, OpenAPI로 API를 문서화할 수 있습니다.\n\n하지만 `fastapi`에서 `Query`, `Path`, `Depends`, `Security` 등을 import할 때, 이것들은 실제로 특수한 클래스를 반환하는 함수입니다.\n\n///\n\n## `SecurityScopes` 사용하기 { #use-securityscopes }\n\n이제 의존성 `get_current_user`를 업데이트합니다.\n\n이는 위의 의존성들이 사용하는 것입니다.\n\n여기에서 앞서 만든 동일한 OAuth2 스킴을 의존성으로 선언하여 사용합니다: `oauth2_scheme`.\n\n이 의존성 함수 자체에는 스코프 요구사항이 없기 때문에, `oauth2_scheme`와 함께 `Depends`를 사용할 수 있습니다. 보안 스코프를 지정할 필요가 없을 때는 `Security`를 쓸 필요가 없습니다.\n\n또한 `fastapi.security`에서 import한 `SecurityScopes` 타입의 특별한 매개변수를 선언합니다.\n\n이 `SecurityScopes` 클래스는 `Request`와 비슷합니다(`Request`는 요청 객체를 직접 얻기 위해 사용했습니다).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## `scopes` 사용하기 { #use-the-scopes }\n\n매개변수 `security_scopes`의 타입은 `SecurityScopes`입니다.\n\n여기에는 `scopes` 속성이 있으며, 자기 자신과 이 함수를 하위 의존성으로 사용하는 모든 의존성이 요구하는 스코프 전체를 담은 `list`를 가집니다. 즉, 모든 “dependants”... 다소 헷갈릴 수 있는데, 아래에서 다시 설명합니다.\n\n`security_scopes` 객체(`SecurityScopes` 클래스)에는 또한 `scope_str` 속성이 있는데, 공백으로 구분된 단일 문자열로 스코프들을 담고 있습니다(이를 사용할 것입니다).\n\n나중에 여러 지점에서 재사용(`raise`)할 수 있는 `HTTPException`을 생성합니다.\n\n이 예외에는 필요한 스코프(있다면)를 공백으로 구분된 문자열(`scope_str`)로 포함합니다. 그리고 그 스코프 문자열을 `WWW-Authenticate` 헤더에 넣습니다(이는 사양의 일부입니다).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## `username`과 데이터 형태 검증하기 { #verify-the-username-and-data-shape }\n\n`username`을 얻었는지 확인하고, 스코프를 추출합니다.\n\n그런 다음 Pydantic 모델로 데이터를 검증합니다(`ValidationError` 예외를 잡습니다). JWT 토큰을 읽거나 Pydantic으로 데이터를 검증하는 과정에서 오류가 나면, 앞에서 만든 `HTTPException`을 raise합니다.\n\n이를 위해 Pydantic 모델 `TokenData`에 새 속성 `scopes`를 추가합니다.\n\nPydantic으로 데이터를 검증하면, 예를 들어 스코프가 정확히 `str`의 `list`이고 `username`이 `str`인지 등을 보장할 수 있습니다.\n\n예를 들어 `dict`나 다른 형태라면, 나중에 애플리케이션이 어느 시점에 깨지면서 보안 위험이 될 수 있습니다.\n\n또한 해당 username을 가진 사용자가 있는지 확인하고, 없다면 앞에서 만든 동일한 예외를 raise합니다.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## `scopes` 검증하기 { #verify-the-scopes }\n\n이제 이 의존성과 모든 dependant( *경로 처리* 포함)가 요구하는 모든 스코프가, 받은 토큰의 스코프에 포함되어 있는지 확인합니다. 그렇지 않으면 `HTTPException`을 raise합니다.\n\n이를 위해, 모든 스코프를 `str`로 담고 있는 `security_scopes.scopes`를 사용합니다.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## 의존성 트리와 스코프 { #dependency-tree-and-scopes }\n\n이 의존성 트리와 스코프를 다시 살펴보겠습니다.\n\n`get_current_active_user` 의존성은 `get_current_user`를 하위 의존성으로 가지므로, `get_current_active_user`에서 선언된 스코프 `\"me\"`는 `get_current_user`에 전달되는 `security_scopes.scopes`의 요구 스코프 목록에 포함됩니다.\n\n*경로 처리* 자체도 스코프 `\"items\"`를 선언하므로, 이것 또한 `get_current_user`에 전달되는 `security_scopes.scopes` 목록에 포함됩니다.\n\n의존성과 스코프의 계층 구조는 다음과 같습니다:\n\n* *경로 처리* `read_own_items`는:\n    * 의존성과 함께 요구 스코프 `[\"items\"]`를 가집니다:\n    * `get_current_active_user`:\n        * 의존성 함수 `get_current_active_user`는:\n            * 의존성과 함께 요구 스코프 `[\"me\"]`를 가집니다:\n            * `get_current_user`:\n                * 의존성 함수 `get_current_user`는:\n                    * 자체적으로는 요구 스코프가 없습니다.\n                    * `oauth2_scheme`를 사용하는 의존성이 있습니다.\n                    * `SecurityScopes` 타입의 `security_scopes` 매개변수가 있습니다:\n                        * 이 `security_scopes` 매개변수는 위에서 선언된 모든 스코프를 담은 `list`인 `scopes` 속성을 가지므로:\n                            * *경로 처리* `read_own_items`의 경우 `security_scopes.scopes`에는 `[\"me\", \"items\"]`가 들어갑니다.\n                            * *경로 처리* `read_users_me`의 경우 `security_scopes.scopes`에는 `[\"me\"]`가 들어갑니다. 이는 의존성 `get_current_active_user`에서 선언되기 때문입니다.\n                            * *경로 처리* `read_system_status`의 경우 `security_scopes.scopes`에는 `[]`(없음)가 들어갑니다. `scopes`가 있는 `Security`를 선언하지 않았고, 그 의존성인 `get_current_user`도 `scopes`를 선언하지 않았기 때문입니다.\n\n/// tip | 팁\n\n여기서 중요한 “마법 같은” 점은 `get_current_user`가 각 *경로 처리*마다 검사해야 하는 `scopes` 목록이 달라진다는 것입니다.\n\n이는 특정 *경로 처리*에 대한 의존성 트리에서, 각 *경로 처리*와 각 의존성에 선언된 `scopes`에 따라 달라집니다.\n\n///\n\n## `SecurityScopes`에 대한 추가 설명 { #more-details-about-securityscopes }\n\n`SecurityScopes`는 어느 지점에서든, 그리고 여러 곳에서 사용할 수 있으며, “루트” 의존성에만 있어야 하는 것은 아닙니다.\n\n`SecurityScopes`는 **해당 특정** *경로 처리*와 **해당 특정** 의존성 트리에 대해, 현재 `Security` 의존성과 모든 dependant에 선언된 보안 스코프를 항상 갖고 있습니다.\n\n`SecurityScopes`에는 dependant가 선언한 모든 스코프가 포함되므로, 중앙의 의존성 함수에서 토큰이 필요한 스코프를 가지고 있는지 검증한 다음, 서로 다른 *경로 처리*에서 서로 다른 스코프 요구사항을 선언할 수 있습니다.\n\n이들은 각 *경로 처리*마다 독립적으로 검사됩니다.\n\n## 확인하기 { #check-it }\n\nAPI 문서를 열면, 인증하고 인가할 스코프를 지정할 수 있습니다.\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n어떤 스코프도 선택하지 않으면 “인증”은 되지만, `/users/me/` 또는 `/users/me/items/`에 접근하려고 하면 권한이 충분하지 않다는 오류가 발생합니다. `/status/`에는 여전히 접근할 수 있습니다.\n\n그리고 스코프 `me`는 선택했지만 스코프 `items`는 선택하지 않았다면, `/users/me/`에는 접근할 수 있지만 `/users/me/items/`에는 접근할 수 없습니다.\n\n이는 사용자가 애플리케이션에 얼마나 많은 권한을 부여했는지에 따라, 제3자 애플리케이션이 사용자로부터 제공받은 토큰으로 이 *경로 처리*들 중 하나에 접근하려고 할 때 발생하는 상황과 같습니다.\n\n## 제3자 통합에 대해 { #about-third-party-integrations }\n\n이 예제에서는 OAuth2 “password” 플로우를 사용하고 있습니다.\n\n이는 보통 자체 프론트엔드가 있는 우리 애플리케이션에 로그인할 때 적합합니다.\n\n우리가 이를 통제하므로 `username`과 `password`를 받는 것을 신뢰할 수 있기 때문입니다.\n\n하지만 다른 사람들이 연결할 OAuth2 애플리케이션(즉, Facebook, Google, GitHub 등과 동등한 인증 제공자를 만들고 있다면)을 구축한다면, 다른 플로우 중 하나를 사용해야 합니다.\n\n가장 흔한 것은 implicit 플로우입니다.\n\n가장 안전한 것은 code 플로우이지만, 더 많은 단계가 필요해 구현이 더 복잡합니다. 복잡하기 때문에 많은 제공자는 implicit 플로우를 권장하게 됩니다.\n\n/// note | 참고\n\n인증 제공자마다 자신들의 브랜드의 일부로 만들기 위해, 각 플로우를 서로 다른 방식으로 이름 붙이는 경우가 흔합니다.\n\n하지만 결국, 동일한 OAuth2 표준을 구현하고 있는 것입니다.\n\n///\n\n**FastAPI**는 `fastapi.security.oauth2`에 이러한 모든 OAuth2 인증 플로우를 위한 유틸리티를 포함합니다.\n\n## 데코레이터 `dependencies`에서의 `Security` { #security-in-decorator-dependencies }\n\n[경로 처리 데코레이터의 의존성](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)에서 설명한 것처럼 데코레이터의 `dependencies` 매개변수에 `Depends`의 `list`를 정의할 수 있는 것과 같은 방식으로, 거기에서 `scopes`와 함께 `Security`를 사용할 수도 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/advanced/settings.md",
    "content": "# 설정과 환경 변수 { #settings-and-environment-variables }\n\n많은 경우 애플리케이션에는 외부 설정이나 구성(예: secret key, 데이터베이스 자격 증명, 이메일 서비스 자격 증명 등)이 필요할 수 있습니다.\n\n이러한 설정 대부분은 데이터베이스 URL처럼 변동 가능(변경될 수 있음)합니다. 그리고 많은 설정은 secret처럼 민감할 수 있습니다.\n\n이 때문에 보통 애플리케이션이 읽어들이는 환경 변수로 이를 제공하는 것이 일반적입니다.\n\n/// tip | 팁\n\n환경 변수를 이해하려면 [환경 변수](../environment-variables.md)를 읽어보세요.\n\n///\n\n## 타입과 검증 { #types-and-validation }\n\n이 환경 변수들은 Python 외부에 있으며 다른 프로그램 및 시스템의 나머지 부분(그리고 Linux, Windows, macOS 같은 서로 다른 운영체제와도)과 호환되어야 하므로, 텍스트 문자열만 다룰 수 있습니다.\n\n즉, Python에서 환경 변수로부터 읽어온 어떤 값이든 `str`이 되며, 다른 타입으로의 변환이나 검증은 코드에서 수행해야 합니다.\n\n## Pydantic `Settings` { #pydantic-settings }\n\n다행히 Pydantic은 환경 변수에서 오는 이러한 설정을 처리할 수 있는 훌륭한 유틸리티를 [Pydantic: Settings 관리](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)로 제공합니다.\n\n### `pydantic-settings` 설치하기 { #install-pydantic-settings }\n\n먼저 [가상 환경](../virtual-environments.md)을 만들고 활성화한 다음, `pydantic-settings` 패키지를 설치하세요:\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\n또는 다음처럼 `all` extras를 설치하면 함께 포함됩니다:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### `Settings` 객체 만들기 { #create-the-settings-object }\n\nPydantic에서 `BaseSettings`를 import하고, Pydantic 모델과 매우 비슷하게 서브클래스를 만드세요.\n\nPydantic 모델과 같은 방식으로, 타입 어노테이션(그리고 필요하다면 기본값)과 함께 클래스 속성을 선언합니다.\n\n다양한 데이터 타입, `Field()`로 추가 검증 등 Pydantic 모델에서 사용하는 동일한 검증 기능과 도구를 모두 사용할 수 있습니다.\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip | 팁\n\n빠르게 복사/붙여넣기할 예시가 필요하다면, 이 예시는 사용하지 말고 아래의 마지막 예시를 사용하세요.\n\n///\n\n그 다음, 해당 `Settings` 클래스의 인스턴스(여기서는 `settings` 객체)를 생성하면 Pydantic이 대소문자를 구분하지 않고 환경 변수를 읽습니다. 따라서 대문자 변수 `APP_NAME`도 `app_name` 속성에 대해 읽힙니다.\n\n이후 데이터를 변환하고 검증합니다. 그래서 그 `settings` 객체를 사용할 때는 선언한 타입의 데이터를 갖게 됩니다(예: `items_per_user`는 `int`가 됩니다).\n\n### `settings` 사용하기 { #use-the-settings }\n\n이제 애플리케이션에서 새 `settings` 객체를 사용할 수 있습니다:\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### 서버 실행하기 { #run-the-server }\n\n다음으로 환경 변수를 통해 구성을 전달하면서 서버를 실행합니다. 예를 들어 다음처럼 `ADMIN_EMAIL`과 `APP_NAME`을 설정할 수 있습니다:\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip | 팁\n\n하나의 명령에 여러 env var를 설정하려면 공백으로 구분하고, 모두 명령 앞에 두세요.\n\n///\n\n그러면 `admin_email` 설정은 `\"deadpool@example.com\"`으로 설정됩니다.\n\n`app_name`은 `\"ChimichangApp\"`이 됩니다.\n\n그리고 `items_per_user`는 기본값 `50`을 유지합니다.\n\n## 다른 모듈의 설정 { #settings-in-another-module }\n\n[더 큰 애플리케이션 - 여러 파일](../tutorial/bigger-applications.md)에서 본 것처럼, 설정을 다른 모듈 파일에 넣을 수도 있습니다.\n\n예를 들어 `config.py` 파일을 다음처럼 만들 수 있습니다:\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\n그리고 `main.py` 파일에서 이를 사용합니다:\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip | 팁\n\n[더 큰 애플리케이션 - 여러 파일](../tutorial/bigger-applications.md)에서 본 것처럼 `__init__.py` 파일도 필요합니다.\n\n///\n\n## 의존성에서 설정 사용하기 { #settings-in-a-dependency }\n\n어떤 경우에는 어디서나 사용되는 전역 `settings` 객체를 두는 대신, 의존성에서 설정을 제공하는 것이 유용할 수 있습니다.\n\n이는 특히 테스트 중에 유용할 수 있는데, 사용자 정의 설정으로 의존성을 override하기가 매우 쉽기 때문입니다.\n\n### config 파일 { #the-config-file }\n\n이전 예시에서 이어서, `config.py` 파일은 다음과 같을 수 있습니다:\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\n이제는 기본 인스턴스 `settings = Settings()`를 생성하지 않는다는 점에 유의하세요.\n\n### 메인 앱 파일 { #the-main-app-file }\n\n이제 새로운 `config.Settings()`를 반환하는 의존성을 생성합니다.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip | 팁\n\n`@lru_cache`는 조금 뒤에 다룹니다.\n\n지금은 `get_settings()`가 일반 함수라고 가정해도 됩니다.\n\n///\n\n그 다음 *경로 처리 함수*에서 이를 의존성으로 요구하고, 필요한 어디서든 사용할 수 있습니다.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### 설정과 테스트 { #settings-and-testing }\n\n그 다음, `get_settings`에 대한 의존성 override를 만들어 테스트 중에 다른 설정 객체를 제공하기가 매우 쉬워집니다:\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\n의존성 override에서는 새 `Settings` 객체를 생성할 때 `admin_email`의 새 값을 설정하고, 그 새 객체를 반환합니다.\n\n그 다음 그것이 사용되는지 테스트할 수 있습니다.\n\n## `.env` 파일 읽기 { #reading-a-env-file }\n\n많이 바뀔 수 있는 설정이 많고, 서로 다른 환경에서 사용한다면, 이를 파일에 넣어 환경 변수인 것처럼 읽는 것이 유용할 수 있습니다.\n\n이 관행은 충분히 흔해서 이름도 있는데, 이러한 환경 변수들은 보통 `.env` 파일에 두며, 그 파일을 \"dotenv\"라고 부릅니다.\n\n/// tip | 팁\n\n점(`.`)으로 시작하는 파일은 Linux, macOS 같은 Unix 계열 시스템에서 숨김 파일입니다.\n\n하지만 dotenv 파일이 꼭 그 정확한 파일명을 가져야 하는 것은 아닙니다.\n\n///\n\nPydantic은 외부 라이브러리를 사용해 이런 유형의 파일에서 읽는 기능을 지원합니다. 자세한 내용은 [Pydantic Settings: Dotenv (.env) 지원](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support)을 참고하세요.\n\n/// tip | 팁\n\n이를 사용하려면 `pip install python-dotenv`가 필요합니다.\n\n///\n\n### `.env` 파일 { #the-env-file }\n\n다음과 같은 `.env` 파일을 둘 수 있습니다:\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### `.env`에서 설정 읽기 { #read-settings-from-env }\n\n그리고 `config.py`를 다음처럼 업데이트합니다:\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip | 팁\n\n`model_config` 속성은 Pydantic 설정을 위한 것입니다. 자세한 내용은 [Pydantic: 개념: 구성](https://docs.pydantic.dev/latest/concepts/config/)을 참고하세요.\n\n///\n\n여기서는 Pydantic `Settings` 클래스 안에 config `env_file`을 정의하고, 사용하려는 dotenv 파일의 파일명을 값으로 설정합니다.\n\n### `lru_cache`로 `Settings`를 한 번만 생성하기 { #creating-the-settings-only-once-with-lru-cache }\n\n디스크에서 파일을 읽는 것은 보통 비용이 큰(느린) 작업이므로, 각 요청마다 읽기보다는 한 번만 수행하고 동일한 settings 객체를 재사용하는 것이 좋습니다.\n\n하지만 매번 다음을 수행하면:\n\n```Python\nSettings()\n```\n\n새 `Settings` 객체가 생성되고, 생성 시점에 `.env` 파일을 다시 읽게 됩니다.\n\n의존성 함수가 단순히 다음과 같다면:\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\n요청마다 객체를 생성하게 되고, 요청마다 `.env` 파일을 읽게 됩니다. ⚠️\n\n하지만 위에 `@lru_cache` 데코레이터를 사용하고 있으므로, `Settings` 객체는 최초 호출 시 딱 한 번만 생성됩니다. ✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\n그 다음 요청들에서 의존성으로 `get_settings()`가 다시 호출될 때마다, `get_settings()`의 내부 코드를 실행해서 새 `Settings` 객체를 만드는 대신, 첫 호출에서 반환된 동일한 객체를 계속 반환합니다.\n\n#### `lru_cache` 기술 세부사항 { #lru-cache-technical-details }\n\n`@lru_cache`는 데코레이션한 함수가 매번 다시 계산하는 대신, 첫 번째에 반환된 동일한 값을 반환하도록 함수를 수정합니다(즉, 매번 함수 코드를 실행하지 않습니다).\n\n따라서 아래의 함수는 인자 조합마다 한 번씩 실행됩니다. 그리고 각각의 인자 조합에 대해 반환된 값은, 함수가 정확히 같은 인자 조합으로 호출될 때마다 반복해서 사용됩니다.\n\n예를 들어 다음 함수가 있다면:\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\n프로그램은 다음과 같이 실행될 수 있습니다:\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Execute function\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n```\n\n우리의 의존성 `get_settings()`의 경우, 함수가 어떤 인자도 받지 않으므로 항상 같은 값을 반환합니다.\n\n이렇게 하면 거의 전역 변수처럼 동작합니다. 하지만 의존성 함수를 사용하므로 테스트를 위해 쉽게 override할 수 있습니다.\n\n`@lru_cache`는 Python 표준 라이브러리의 `functools`에 포함되어 있으며, 자세한 내용은 [`@lru_cache`에 대한 Python 문서](https://docs.python.org/3/library/functools.html#functools.lru_cache)에서 확인할 수 있습니다.\n\n## 정리 { #recap }\n\nPydantic Settings를 사용하면 Pydantic 모델의 모든 강력한 기능을 활용해 애플리케이션의 설정 또는 구성을 처리할 수 있습니다.\n\n* 의존성을 사용하면 테스트를 단순화할 수 있습니다.\n* `.env` 파일을 사용할 수 있습니다.\n* `@lru_cache`를 사용하면 각 요청마다 dotenv 파일을 반복해서 읽는 것을 피하면서도, 테스트 중에는 이를 override할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/advanced/stream-data.md",
    "content": "# 데이터 스트리밍 { #stream-data }\n\nJSON으로 구조화할 수 있는 데이터를 스트리밍하려면 [JSON Lines 스트리밍](../tutorial/stream-json-lines.md)을 사용하세요.\n\n하지만 순수 바이너리 데이터나 문자열을 스트리밍하려면 다음과 같이 하면 됩니다.\n\n/// info | 정보\n\nFastAPI 0.134.0에 추가되었습니다.\n\n///\n\n## 사용 예시 { #use-cases }\n\n예를 들어 AI LLM 서비스의 출력에서 바로 순수 문자열을 스트리밍하고 싶다면 이를 사용할 수 있습니다.\n\n또한 큰 바이너리 파일을 스트리밍하는 데 사용할 수 있습니다. 한 번에 모두 메모리로 읽지 않고, 읽는 즉시 데이터 청크를 순차적으로 스트리밍합니다.\n\n이 방식으로 비디오나 오디오를 스트리밍할 수도 있으며, 처리하면서 생성된 데이터를 곧바로 전송할 수도 있습니다.\n\n## `yield`와 함께 `StreamingResponse` 사용하기 { #a-streamingresponse-with-yield }\n\n경로 처리 함수에서 `response_class=StreamingResponse`를 선언하면 `yield`를 사용해 데이터 청크를 순차적으로 보낼 수 있습니다.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI는 각 데이터 청크를 있는 그대로 `StreamingResponse`에 전달하며, JSON 등으로 변환하려고 하지 않습니다.\n\n### async가 아닌 경로 처리 함수 { #non-async-path-operation-functions }\n\n`async`가 없는 일반 `def` 함수에서도 동일하게 `yield`를 사용할 수 있습니다.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### 타입 애너테이션 생략하기 { #no-annotation }\n\n바이너리 데이터를 스트리밍할 때는 반환 타입 애너테이션을 굳이 선언할 필요가 없습니다.\n\nFastAPI는 데이터를 Pydantic으로 JSON으로 변환하거나 어떤 방식으로든 직렬화하지 않으므로, 이 경우 타입 애너테이션은 편집기나 도구를 위한 용도일 뿐이며 FastAPI에서는 사용되지 않습니다.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\n이는 곧 `StreamingResponse`를 사용할 때 타입 애너테이션과 무관하게, 전송 기준에 맞춰 바이트 데이터를 생성하고 인코딩할 자유와 책임이 여러분에게 있음을 의미합니다. 🤓\n\n### 바이트 스트리밍 { #stream-bytes }\n\n주요 사용 사례 중 하나는 문자열 대신 `bytes`를 스트리밍하는 것입니다. 물론 그렇게 할 수 있습니다.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## 사용자 정의 `PNGStreamingResponse` { #a-custom-pngstreamingresponse }\n\n위 예시에서는 바이트 데이터를 스트리밍했지만, 응답에 `Content-Type` 헤더가 없어 클라이언트는 어떤 유형의 데이터를 받는지 알 수 없습니다.\n\n스트리밍하는 데이터 유형에 맞춰 `Content-Type` 헤더를 설정하는 `StreamingResponse`의 하위 클래스를 직접 만들 수 있습니다.\n\n예를 들어 `media_type` 속성을 사용해 `Content-Type` 헤더를 `image/png`로 설정하는 `PNGStreamingResponse`를 만들 수 있습니다:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\n그런 다음 경로 처리 함수에서 `response_class=PNGStreamingResponse`로 이 새 클래스를 사용할 수 있습니다:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### 파일 시뮬레이션 { #simulate-a-file }\n\n이 예시에서는 `io.BytesIO`로 파일을 시뮬레이션합니다. 이는 메모리에서만 존재하지만 파일과 동일한 인터페이스를 제공하는 파일 유사 객체입니다.\n\n예를 들어 실제 파일처럼 내용을 소비하기 위해 순회(iterate)할 수 있습니다.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | 기술 세부사항\n\n다른 두 변수 `image_base64`와 `binary_image`는 이미지를 Base64로 인코딩한 뒤 바이트로 변환한 것이며, 이를 `io.BytesIO`에 전달합니다.\n\n이 예시에서 하나의 파일 안에 모두 담아, 그대로 복사해 실행할 수 있도록 하기 위한 목적입니다. 🥚\n\n///\n\n`with` 블록을 사용하면 제너레이터 함수(`yield`가 있는 함수)가 끝난 뒤, 즉 응답 전송이 완료된 후 파일 유사 객체가 닫히도록 보장합니다.\n\n이 예시처럼 메모리 상의 가짜 파일(`io.BytesIO`)이라면 크게 중요하지 않지만, 실제 파일의 경우 작업이 끝난 뒤 파일을 닫는 것이 매우 중요합니다.\n\n### 파일과 비동기 { #files-and-async }\n\n대부분의 경우 파일 유사 객체는 기본적으로 async/await와 호환되지 않습니다.\n\n예를 들어 `await file.read()`나 `async for chunk in file`과 같은 패턴을 지원하지 않습니다.\n\n또한 디스크나 네트워크에서 읽기 때문에, 많은 경우 읽기 작업은 이벤트 루프를 막을 수 있는 블로킹 연산입니다.\n\n/// info | 정보\n\n위의 예시는 예외적인 경우입니다. `io.BytesIO` 객체는 이미 메모리에 있으므로 읽기가 아무 것도 차단하지 않습니다.\n\n하지만 실제 파일이나 파일 유사 객체를 읽을 때는 블로킹되는 경우가 많습니다.\n\n///\n\n이벤트 루프가 블로킹되는 것을 피하려면 경로 처리 함수를 `async def` 대신 일반 `def`로 선언하세요. 그러면 FastAPI가 스레드풀 워커에서 실행하여 메인 루프가 막히지 않도록 합니다.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip | 팁\n\n비동기 함수 안에서 블로킹 코드를 호출해야 하거나, 반대로 블로킹 함수 안에서 비동기 함수를 호출해야 한다면 FastAPI의 형제 라이브러리인 [Asyncer](https://asyncer.tiangolo.com)를 사용할 수 있습니다.\n\n///\n\n### `yield from` { #yield-from }\n\n파일 유사 객체처럼 어떤 것을 순회하면서 각 항목마다 `yield`를 하는 대신, `yield from`을 사용해 각 항목을 직접 전달하고 `for` 루프를 생략할 수 있습니다.\n\n이는 FastAPI에 특화된 기능이 아니라 순수한 파이썬 기능이지만, 알아두면 유용한 트릭입니다. 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/ko/docs/advanced/strict-content-type.md",
    "content": "# 엄격한 Content-Type 확인 { #strict-content-type-checking }\n\n기본적으로 **FastAPI**는 JSON 요청 본문에 대해 엄격한 `Content-Type` 헤더 검사를 사용합니다. 이는 JSON 요청의 본문을 JSON으로 파싱하려면 유효한 `Content-Type` 헤더(예: `application/json`)를 반드시 포함해야 함을 의미합니다.\n\n## CSRF 위험 { #csrf-risk }\n\n이 기본 동작은 매우 특정한 시나리오에서 **Cross-Site Request Forgery (CSRF)** 공격의 한 유형에 대한 보호를 제공합니다.\n\n이러한 공격은 브라우저가 다음과 같은 경우 CORS 사전 요청(preflight) 검사를 수행하지 않고 스크립트가 요청을 보내도록 허용한다는 점을 악용합니다:\n\n- `Content-Type` 헤더가 없음(예: `Blob` 본문과 함께 `fetch()` 사용)\n- 그리고 어떠한 인증 자격 증명도 보내지 않음\n\n이 유형의 공격은 주로 다음과 같은 경우에 관련이 있습니다:\n\n- 애플리케이션이 로컬(예: `localhost`) 또는 내부 네트워크에서 실행 중이고\n- 애플리케이션에 인증이 없어 같은 네트워크에서 오는 모든 요청을 신뢰한다고 가정하는 경우\n\n## 공격 예시 { #example-attack }\n\n로컬 AI 에이전트를 실행하는 방법을 만들었다고 가정해 봅시다.\n\n이 에이전트는 다음 위치에 API를 제공합니다:\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\n또한 다음 위치에 프론트엔드가 있습니다:\n\n```\nhttp://localhost:8000\n```\n\n/// tip | 팁\n\n두 주소 모두 같은 호스트를 사용합니다.\n\n///\n\n그런 다음 프론트엔드를 통해 AI 에이전트가 여러분을 대신해 작업을 수행하도록 할 수 있습니다.\n\n이는 공개 인터넷이 아니라 로컬에서 실행되므로, 여러분은 로컬 네트워크 접근만을 신뢰하고 별도의 인증을 설정하지 않기로 합니다.\n\n그 후 사용자는 이를 설치해 로컬에서 실행할 수 있습니다.\n\n그리고 다음과 같은 악성 웹사이트를 열 수 있습니다:\n\n```\nhttps://evilhackers.example.com\n```\n\n그 악성 웹사이트가 `Blob` 본문으로 `fetch()`를 사용해 로컬 API로 요청을 보냅니다:\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\n악성 웹사이트의 호스트와 로컬 앱의 호스트가 다르더라도, 브라우저는 다음과 같은 이유로 CORS 사전 요청(preflight)을 트리거하지 않습니다:\n\n- 인증 없이 동작하므로 자격 증명을 보낼 필요가 없습니다.\n- 브라우저는 JSON을 보내지 않는다고 판단합니다(`Content-Type` 헤더가 없기 때문).\n\n그러면 악성 웹사이트가 로컬 AI 에이전트로 하여금 사용자의 전 직장 상사에게 화난 메시지를 보내게 하거나... 더 나쁜 일을 시킬 수도 있습니다. 😅\n\n## 공개 인터넷 { #open-internet }\n\n여러분의 앱이 공개 인터넷에 있다면, '네트워크를 신뢰'하여 누구나 인증 없이 권한 있는 요청을 보내도록 두지는 않을 것입니다.\n\n공격자는 브라우저 상호작용 없이도 스크립트를 실행해 여러분의 API로 요청을 보낼 수 있으므로, 아마 이미 권한이 필요한 엔드포인트는 보호하고 있을 것입니다.\n\n그런 경우에는 이 공격/위험은 해당하지 않습니다.\n\n이 위험과 공격은 주로 앱이 **로컬 네트워크**에서 실행되고 그것이 **유일한 보호수단**이라고 가정할 때 관련이 있습니다.\n\n## Content-Type 없이 요청 허용하기 { #allowing-requests-without-content-type }\n\n만약 `Content-Type` 헤더를 보내지 않는 클라이언트를 지원해야 한다면, `strict_content_type=False`로 설정해 엄격한 검사를 비활성화할 수 있습니다:\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\n이 설정을 사용하면 `Content-Type` 헤더가 없는 요청도 본문이 JSON으로 파싱됩니다. 이는 이전 버전의 FastAPI와 동일한 동작입니다.\n\n/// info | 정보\n\n이 동작과 설정은 FastAPI 0.132.0에 추가되었습니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/advanced/sub-applications.md",
    "content": "# 하위 애플리케이션 - 마운트 { #sub-applications-mounts }\n\n각각의 독립적인 OpenAPI와 문서 UI를 갖는 두 개의 독립적인 FastAPI 애플리케이션이 필요하다면, 메인 앱을 두고 하나(또는 그 이상)의 하위 애플리케이션을 \"마운트\"할 수 있습니다.\n\n## **FastAPI** 애플리케이션 마운트 { #mounting-a-fastapi-application }\n\n\"마운트\"란 완전히 \"독립적인\" 애플리케이션을 특정 경로에 추가하고, 그 하위 애플리케이션에 선언된 _경로 처리_로 해당 경로 아래의 모든 것을 처리하도록 하는 것을 의미합니다.\n\n### 최상위 애플리케이션 { #top-level-application }\n\n먼저, 메인 최상위 **FastAPI** 애플리케이션과 그 *경로 처리*를 생성합니다:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### 하위 애플리케이션 { #sub-application }\n\n그 다음, 하위 애플리케이션과 그 *경로 처리*를 생성합니다.\n\n이 하위 애플리케이션은 또 다른 표준 FastAPI 애플리케이션이지만, \"마운트\"될 애플리케이션입니다:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### 하위 애플리케이션 마운트 { #mount-the-sub-application }\n\n최상위 애플리케이션 `app`에서 하위 애플리케이션 `subapi`를 마운트합니다.\n\n이 경우 `/subapi` 경로에 마운트됩니다:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### 자동 API 문서 확인 { #check-the-automatic-api-docs }\n\n이제 `fastapi` 명령어를 실행하세요:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n그리고 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)에서 문서를 여세요.\n\n메인 앱의 자동 API 문서를 보게 될 것이며, 메인 앱 자체의 _경로 처리_만 포함됩니다:\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\n그 다음, [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs)에서 하위 애플리케이션의 문서를 여세요.\n\n하위 애플리케이션의 자동 API 문서를 보게 될 것이며, 하위 경로 접두사 `/subapi` 아래에 올바르게 포함된 하위 애플리케이션 자체의 _경로 처리_만 포함됩니다:\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\n두 사용자 인터페이스 중 어느 것과 상호작용을 시도하더라도 올바르게 동작할 것입니다. 브라우저가 각 특정 앱 또는 하위 앱과 통신할 수 있기 때문입니다.\n\n### 기술적 세부사항: `root_path` { #technical-details-root-path }\n\n위에서 설명한 대로 하위 애플리케이션을 마운트하면, FastAPI는 ASGI 명세의 메커니즘인 `root_path`를 사용해 하위 애플리케이션에 대한 마운트 경로를 전달하는 작업을 처리합니다.\n\n이렇게 하면 하위 애플리케이션은 문서 UI를 위해 해당 경로 접두사를 사용해야 한다는 것을 알게 됩니다.\n\n또한 하위 애플리케이션도 자체적으로 하위 앱을 마운트할 수 있으며, FastAPI가 이 모든 `root_path`를 자동으로 처리하기 때문에 모든 것이 올바르게 동작합니다.\n\n`root_path`와 이를 명시적으로 사용하는 방법에 대해서는 [프록시 뒤](behind-a-proxy.md) 섹션에서 더 알아볼 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/advanced/templates.md",
    "content": "# 템플릿 { #templates }\n\n**FastAPI**와 함께 원하는 어떤 템플릿 엔진도 사용할 수 있습니다.\n\n일반적인 선택은 Jinja2로, Flask와 다른 도구에서도 사용됩니다.\n\n설정을 쉽게 할 수 있는 유틸리티가 있으며, 이를 **FastAPI** 애플리케이션에서 직접 사용할 수 있습니다(Starlette 제공).\n\n## 의존성 설치 { #install-dependencies }\n\n[가상 환경](../virtual-environments.md)을 생성하고, 활성화한 후 `jinja2`를 설치해야 합니다:\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## `Jinja2Templates` 사용하기 { #using-jinja2templates }\n\n* `Jinja2Templates`를 가져옵니다.\n* 나중에 재사용할 수 있는 `templates` 객체를 생성합니다.\n* 템플릿을 반환할 *경로 처리*에 `Request` 매개변수를 선언합니다.\n* 생성한 `templates`를 사용하여 `TemplateResponse`를 렌더링하고 반환합니다. 템플릿의 이름, 요청 객체 및 Jinja2 템플릿 내에서 사용될 키-값 쌍이 포함된 \"컨텍스트\" 딕셔너리도 전달합니다.\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note | 참고\n\nFastAPI 0.108.0 이전, Starlette 0.29.0에서는 `name`이 첫 번째 매개변수였습니다.\n\n또한 그 이전 버전에서는 `request` 객체가 Jinja2의 컨텍스트에서 키-값 쌍의 일부로 전달되었습니다.\n\n///\n\n/// tip | 팁\n\n`response_class=HTMLResponse`를 선언하면 문서 UI가 응답이 HTML임을 알 수 있습니다.\n\n///\n\n/// note | 기술 세부사항\n\n`from starlette.templating import Jinja2Templates`를 사용할 수도 있습니다.\n\n**FastAPI**는 개발자를 위한 편리함으로 `fastapi.templating`과 동일하게 `starlette.templating`을 제공합니다. 하지만 대부분의 사용 가능한 응답은 Starlette에서 직접 옵니다. `Request` 및 `StaticFiles`도 마찬가지입니다.\n\n///\n\n## 템플릿 작성하기 { #writing-templates }\n\n그런 다음 `templates/item.html`에 템플릿을 작성할 수 있습니다. 예를 들면:\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### 템플릿 컨텍스트 값 { #template-context-values }\n\n다음과 같은 HTML에서:\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n...이는 전달한 \"컨텍스트\" `dict`에서 가져온 `id`를 표시합니다:\n\n```Python\n{\"id\": id}\n```\n\n예를 들어, ID가 `42`일 경우, 이는 다음과 같이 렌더링됩니다:\n\n```html\nItem ID: 42\n```\n\n### 템플릿 `url_for` 인수 { #template-url-for-arguments }\n\n템플릿 내에서 `url_for()`를 사용할 수도 있으며, 이는 *경로 처리 함수*에서 사용될 인수와 동일한 인수를 받습니다.\n\n따라서 다음과 같은 부분에서:\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n...이는 *경로 처리 함수* `read_item(id=id)`가 처리할 동일한 URL로 링크를 생성합니다.\n\n예를 들어, ID가 `42`일 경우, 이는 다음과 같이 렌더링됩니다:\n\n```html\n<a href=\"/items/42\">\n```\n\n## 템플릿과 정적 파일 { #templates-and-static-files }\n\n템플릿 내에서 `url_for()`를 사용할 수 있으며, 예를 들어 `name=\"static\"`으로 마운트한 `StaticFiles`와 함께 사용할 수 있습니다.\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n이 예제에서는 다음을 통해 `static/styles.css`에 있는 CSS 파일에 링크합니다:\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\n그리고 `StaticFiles`를 사용하고 있으므로, 해당 CSS 파일은 **FastAPI** 애플리케이션에서 `/static/styles.css` URL로 자동 제공됩니다.\n\n## 더 많은 세부 사항 { #more-details }\n\n템플릿 테스트를 포함한 더 많은 세부 사항은 [Starlette의 템플릿 문서](https://www.starlette.dev/templates/)를 확인하세요.\n"
  },
  {
    "path": "docs/ko/docs/advanced/testing-dependencies.md",
    "content": "# 오버라이드로 의존성 테스트하기 { #testing-dependencies-with-overrides }\n\n## 테스트 중 의존성 오버라이드하기 { #overriding-dependencies-during-testing }\n\n테스트를 진행하다 보면 테스트 중에 의존성을 오버라이드해야 하는 경우가 있습니다.\n\n원래 의존성을 실행하고 싶지 않을 수도 있습니다(또는 그 의존성이 가지고 있는 하위 의존성까지도 실행되지 않길 원할 수 있습니다).\n\n대신, 테스트 동안(특정 테스트에서만) 사용될 다른 의존성을 제공하고, 원래 의존성이 사용되던 곳에서 사용할 수 있는 값을 제공하기를 원할 수 있습니다.\n\n### 사용 사례: 외부 서비스 { #use-cases-external-service }\n\n예를 들어, 외부 인증 제공자를 호출해야 하는 경우를 생각해봅시다.\n\n토큰을 보내면 인증된 사용자를 반환합니다.\n\n제공자는 요청당 요금을 부과할 수 있으며, 테스트를 위해 고정된 모의 사용자가 있는 경우보다 호출하는 데 시간이 더 걸릴 수 있습니다.\n\n외부 제공자를 한 번만 테스트하고 싶을 수도 있지만 테스트를 실행할 때마다 반드시 호출할 필요는 없습니다.\n\n이 경우 해당 공급자를 호출하는 의존성을 오버라이드하고 테스트에 대해서만 모의 사용자를 반환하는 사용자 지정 의존성을 사용할 수 있습니다.\n\n### `app.dependency_overrides` 속성 사용하기 { #use-the-app-dependency-overrides-attribute }\n\n이런 경우를 위해 **FastAPI** 애플리케이션에는 `app.dependency_overrides`라는 속성이 있습니다. 이는 간단한 `dict`입니다.\n\n테스트를 위해 의존성을 오버라이드하려면, 원래 의존성(함수)을 키로 설정하고 오버라이드할 의존성(다른 함수)을 값으로 설정합니다.\n\n그럼 **FastAPI**는 원래 의존성 대신 오버라이드된 의존성을 호출합니다.\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip | 팁\n\n**FastAPI** 애플리케이션 어디에서든 사용된 의존성에 대해 오버라이드를 설정할 수 있습니다.\n\n원래 의존성은 *경로 처리 함수*, *경로 처리 데코레이터*(반환값을 사용하지 않는 경우), `.include_router()` 호출 등에서 사용될 수 있습니다.\n\nFastAPI는 여전히 이를 오버라이드할 수 있습니다.\n\n///\n\n그런 다음, `app.dependency_overrides`를 빈 `dict`로 설정하여 오버라이드를 재설정(제거)할 수 있습니다:\n\n```Python\napp.dependency_overrides = {}\n```\n\n/// tip | 팁\n\n특정 테스트에서만 의존성을 오버라이드하고 싶다면, 테스트 시작 시(테스트 함수 내부) 오버라이드를 설정하고 테스트 종료 시(테스트 함수 끝부분) 재설정하면 됩니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/advanced/testing-events.md",
    "content": "# 이벤트 테스트: 라이프스팬 및 시작 - 종료 { #testing-events-lifespan-and-startup-shutdown }\n\n테스트에서 `lifespan`을 실행해야 하는 경우, `with` 문과 함께 `TestClient`를 사용할 수 있습니다:\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\n\n[\"공식 Starlette 문서 사이트에서 테스트에서 라이프스팬 실행하기.\"](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)에 대한 자세한 내용을 더 읽을 수 있습니다.\n\n더 이상 권장되지 않는 `startup` 및 `shutdown` 이벤트의 경우, 다음과 같이 `TestClient`를 사용할 수 있습니다:\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/ko/docs/advanced/testing-websockets.md",
    "content": "# WebSocket 테스트하기 { #testing-websockets }\n\n같은 `TestClient`를 사용하여 WebSocket을 테스트할 수 있습니다.\n\n이를 위해 `with` 문에서 `TestClient`를 사용하여 WebSocket에 연결합니다:\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note\n\n자세한 내용은 Starlette의 [WebSocket 테스트](https://www.starlette.dev/testclient/#testing-websocket-sessions) 문서를 확인하세요.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/advanced/using-request-directly.md",
    "content": "# `Request` 직접 사용하기 { #using-the-request-directly }\n\n지금까지 요청에서 필요한 부분을 각 타입으로 선언하여 사용해 왔습니다.\n\n다음과 같은 곳에서 데이터를 가져왔습니다:\n\n* 경로를 매개변수로.\n* 헤더.\n* 쿠키.\n* 기타 등등.\n\n이렇게 함으로써, **FastAPI**는 데이터를 검증하고 변환하며, API에 대한 문서를 자동화로 생성합니다.\n\n하지만 `Request` 객체에 직접 접근해야 하는 상황이 있을 수 있습니다.\n\n## `Request` 객체에 대한 세부 사항 { #details-about-the-request-object }\n\n**FastAPI**는 실제로 내부에 **Starlette**을 사용하며, 그 위에 여러 도구를 덧붙인 구조입니다. 따라서 여러분이 필요할 때 Starlette의 [`Request`](https://www.starlette.dev/requests/) 객체를 직접 사용할 수 있습니다.\n\n또한 이는 `Request` 객체에서 데이터를 직접 가져오는 경우(예: 본문을 읽기) FastAPI가 해당 데이터를 검증하거나 변환하지 않으며, 문서화(OpenAPI를 통한 자동 API 사용자 인터페이스용)도 되지 않는다는 의미이기도 합니다.\n\n그러나 다른 매개변수(예: Pydantic 모델을 사용한 본문)는 여전히 검증, 변환, 주석 추가 등이 이루어집니다.\n\n하지만 특정한 경우에는 `Request` 객체를 가져오는 것이 유용할 수 있습니다.\n\n## `Request` 객체를 직접 사용하기 { #use-the-request-object-directly }\n\n여러분이 클라이언트의 IP 주소/호스트 정보를 *경로 처리 함수* 내부에서 가져와야 한다고 가정해 보겠습니다.\n\n이를 위해서는 요청에 직접 접근해야 합니다.\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\n*경로 처리 함수* 매개변수를 `Request` 타입으로 선언하면 **FastAPI**가 해당 매개변수에 `Request`를 전달하는 것을 알게 됩니다.\n\n/// tip | 팁\n\n이 경우, 요청 매개변수 옆에 경로 매개변수를 선언하고 있다는 점을 참고하세요.\n\n따라서, 경로 매개변수는 추출되고 검증되며 지정된 타입으로 변환되고 OpenAPI로 주석이 추가됩니다.\n\n이와 같은 방식으로, 다른 매개변수들을 평소처럼 선언하면서, 부가적으로 `Request`도 가져올 수 있습니다.\n\n///\n\n## `Request` 설명서 { #request-documentation }\n\n여러분은 [`Request` 객체에 대한 공식 Starlette 설명서 사이트](https://www.starlette.dev/requests/)에 대한 더 자세한 내용을 읽어볼 수 있습니다.\n\n/// note | 기술 세부사항\n\n`from starlette.requests import Request`를 사용할 수도 있습니다.\n\n**FastAPI**는 여러분(개발자)를 위한 편의를 위해 이를 직접 제공하지만, Starlette에서 직접 가져온 것입니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\n여러분은 **FastAPI**에서 [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)를 사용할 수 있습니다.\n\n## `websockets` 설치 { #install-websockets }\n\n[가상 환경](../virtual-environments.md)을 생성하고 활성화한 다음, `websockets`(\"WebSocket\" 프로토콜을 쉽게 사용할 수 있게 해주는 Python 라이브러리)를 설치하세요:\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## WebSockets 클라이언트 { #websockets-client }\n\n### 프로덕션 환경에서 { #in-production }\n\n여러분의 프로덕션 시스템에서는 React, Vue.js 또는 Angular와 같은 최신 프레임워크로 생성된 프런트엔드를 사용하고 있을 가능성이 높습니다.\n\n그리고 백엔드와 WebSockets을 사용해 통신하려면 아마도 프런트엔드의 유틸리티를 사용할 것입니다.\n\n또는 네이티브 코드로 WebSocket 백엔드와 직접 통신하는 네이티브 모바일 애플리케이션을 가질 수도 있습니다.\n\n혹은 WebSocket 엔드포인트와 통신할 수 있는 다른 방법이 있을 수도 있습니다.\n\n---\n\n하지만 이번 예제에서는 일부 자바스크립트를 포함한 매우 간단한 HTML 문서를 사용하겠습니다. 모든 것을 긴 문자열 안에 넣습니다.\n\n물론, 이는 최적의 방법이 아니며 프로덕션 환경에서는 사용하지 않을 것입니다.\n\n프로덕션 환경에서는 위에서 설명한 옵션 중 하나를 사용할 것입니다.\n\n그러나 이는 WebSockets의 서버 측에 집중하고 동작하는 예제를 제공하는 가장 간단한 방법입니다:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## `websocket` 생성하기 { #create-a-websocket }\n\n**FastAPI** 애플리케이션에서 `websocket`을 생성합니다:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | 기술 세부사항\n\n`from starlette.websockets import WebSocket`을 사용할 수도 있습니다.\n\n**FastAPI**는 개발자를 위한 편의를 위해 동일한 `WebSocket`을 직접 제공합니다. 하지만 이는 Starlette에서 가져옵니다.\n\n///\n\n## 메시지를 대기하고 전송하기 { #await-for-messages-and-send-messages }\n\nWebSocket 경로에서 메시지를 대기(`await`)하고 전송할 수 있습니다.\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\n여러분은 이진 데이터, 텍스트, JSON 데이터를 받을 수 있고 전송할 수 있습니다.\n\n## 시도해보기 { #try-it }\n\n코드를 `main.py` 파일에 넣고 애플리케이션을 실행합니다:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n브라우저에서 [http://127.0.0.1:8000](http://127.0.0.1:8000)을 여세요.\n\n간단한 페이지가 나타날 것입니다:\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\n입력창에 메시지를 입력하고 전송할 수 있습니다:\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\n그리고 WebSockets가 포함된 **FastAPI** 애플리케이션이 응답을 돌려줄 것입니다:\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\n여러 메시지를 전송(그리고 수신)할 수 있습니다:\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\n그리고 모든 메시지는 동일한 WebSocket 연결을 사용합니다.\n\n## `Depends` 및 기타 사용하기 { #using-depends-and-others }\n\nWebSocket 엔드포인트에서 `fastapi`에서 다음을 가져와 사용할 수 있습니다:\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\n이들은 다른 FastAPI 엔드포인트/*경로 처리*와 동일하게 동작합니다:\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info | 정보\n\nWebSocket이기 때문에 `HTTPException`을 발생시키는 것은 적절하지 않습니다. 대신 `WebSocketException`을 발생시킵니다.\n\n명세서에 정의된 [유효한 코드](https://tools.ietf.org/html/rfc6455#section-7.4.1)를 사용하여 종료 코드를 설정할 수 있습니다.\n\n///\n\n### 종속성을 가진 WebSockets 시도해보기 { #try-the-websockets-with-dependencies }\n\n애플리케이션을 실행합니다:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n브라우저에서 [http://127.0.0.1:8000](http://127.0.0.1:8000)을 여세요.\n\n여기에서 다음을 설정할 수 있습니다:\n\n* 경로에 사용된 \"Item ID\".\n* 쿼리 매개변수로 사용된 \"Token\".\n\n/// tip | 팁\n\n쿼리 `token`은 종속성에 의해 처리됩니다.\n\n///\n\n이렇게 하면 WebSocket에 연결하고 메시지를 전송 및 수신할 수 있습니다:\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## 연결 해제 및 다중 클라이언트 처리 { #handling-disconnections-and-multiple-clients }\n\nWebSocket 연결이 닫히면, `await websocket.receive_text()`가 `WebSocketDisconnect` 예외를 발생시킵니다. 그러면 이 예제처럼 이를 잡아 처리할 수 있습니다.\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\n테스트해보기:\n\n* 여러 브라우저 탭에서 앱을 엽니다.\n* 각 탭에서 메시지를 작성합니다.\n* 그런 다음 탭 중 하나를 닫아보세요.\n\n`WebSocketDisconnect` 예외가 발생하며, 다른 모든 클라이언트가 다음과 같은 메시지를 수신합니다:\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip | 팁\n\n위 앱은 여러 WebSocket 연결에 메시지를 처리하고 브로드캐스트하는 방법을 보여주는 최소한의 간단한 예제입니다.\n\n하지만 모든 것을 메모리의 단일 리스트로 처리하므로, 프로세스가 실행 중인 동안만 동작하며 단일 프로세스에서만 작동한다는 점을 기억하세요.\n\nFastAPI와 쉽게 통합할 수 있으면서 더 견고하고 Redis, PostgreSQL 등을 지원하는 도구가 필요하다면, [encode/broadcaster](https://github.com/encode/broadcaster)를 확인하세요.\n\n///\n\n## 추가 정보 { #more-info }\n\n다음 옵션에 대해 더 알아보려면 Starlette의 문서를 확인하세요:\n\n* [`WebSocket` 클래스](https://www.starlette.dev/websockets/).\n* [클래스 기반 WebSocket 처리](https://www.starlette.dev/endpoints/#websocketendpoint).\n"
  },
  {
    "path": "docs/ko/docs/advanced/wsgi.md",
    "content": "# WSGI 포함하기 - Flask, Django 등 { #including-wsgi-flask-django-others }\n\n[서브 애플리케이션 - 마운트](sub-applications.md), [프록시 뒤에서](behind-a-proxy.md)에서 본 것처럼 WSGI 애플리케이션을 마운트할 수 있습니다.\n\n이를 위해 `WSGIMiddleware`를 사용해 WSGI 애플리케이션(예: Flask, Django 등)을 감쌀 수 있습니다.\n\n## `WSGIMiddleware` 사용하기 { #using-wsgimiddleware }\n\n/// info | 정보\n\n이를 사용하려면 `a2wsgi`를 설치해야 합니다. 예: `pip install a2wsgi`\n\n///\n\n`a2wsgi`에서 `WSGIMiddleware`를 import 해야 합니다.\n\n그런 다음, WSGI(예: Flask) 애플리케이션을 미들웨어로 감쌉니다.\n\n그리고 해당 경로에 마운트합니다.\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note | 참고\n\n이전에 `fastapi.middleware.wsgi`의 `WSGIMiddleware` 사용을 권장했지만 이제는 더 이상 권장되지 않습니다.\n\n대신 `a2wsgi` 패키지 사용을 권장합니다. 사용 방법은 동일합니다.\n\n단, `a2wsgi` 패키지가 설치되어 있고 `a2wsgi`에서 `WSGIMiddleware`를 올바르게 import 하는지만 확인하세요.\n\n///\n\n## 확인하기 { #check-it }\n\n이제 `/v1/` 경로에 있는 모든 요청은 Flask 애플리케이션에서 처리됩니다.\n\n그리고 나머지는 **FastAPI**에 의해 처리됩니다.\n\n실행하고 [http://localhost:8000/v1/](http://localhost:8000/v1/)로 이동하면 Flask의 응답을 볼 수 있습니다:\n\n```txt\nHello, World from Flask!\n```\n\n그리고 [http://localhost:8000/v2](http://localhost:8000/v2)로 이동하면 **FastAPI**의 응답을 볼 수 있습니다:\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/ko/docs/alternatives.md",
    "content": "# 대안, 영감, 비교 { #alternatives-inspiration-and-comparisons }\n\n**FastAPI**에 영감을 준 것들, 대안과의 비교, 그리고 그로부터 무엇을 배웠는지에 대한 내용입니다.\n\n## 소개 { #intro }\n\n다른 사람들의 이전 작업이 없었다면 **FastAPI**는 존재하지 않았을 것입니다.\n\n그 전에 만들어진 많은 도구들이 **FastAPI**의 탄생에 영감을 주었습니다.\n\n저는 여러 해 동안 새로운 framework를 만드는 것을 피하고 있었습니다. 먼저 **FastAPI**가 다루는 모든 기능을 여러 서로 다른 framework, plug-in, 도구를 사용해 해결해 보려고 했습니다.\n\n하지만 어느 시점에는, 이전 도구들의 가장 좋은 아이디어를 가져와 가능한 최선의 방식으로 조합하고, 이전에는 존재하지 않았던 언어 기능(Python 3.6+ type hints)을 활용해 이 모든 기능을 제공하는 무언가를 만드는 것 외에는 다른 선택지가 없었습니다.\n\n## 이전 도구들 { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\n가장 인기 있는 Python framework이며 널리 신뢰받고 있습니다. Instagram 같은 시스템을 만드는 데 사용됩니다.\n\n상대적으로 관계형 데이터베이스(예: MySQL 또는 PostgreSQL)와 강하게 결합되어 있어서, NoSQL 데이터베이스(예: Couchbase, MongoDB, Cassandra 등)를 주 저장 엔진으로 사용하는 것은 그리 쉽지 않습니다.\n\n백엔드에서 HTML을 생성하기 위해 만들어졌지, 현대적인 프런트엔드(예: React, Vue.js, Angular)나 다른 시스템(예: <abbr title=\"Internet of Things - 사물 인터넷\">IoT</abbr> 기기)에서 사용되는 API를 만들기 위해 설계된 것은 아닙니다.\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nDjango REST framework는 Django를 기반으로 Web API를 구축하기 위한 유연한 toolkit으로 만들어졌고, Django의 API 기능을 개선하기 위한 목적이었습니다.\n\nMozilla, Red Hat, Eventbrite를 포함해 많은 회사에서 사용합니다.\n\n**자동 API 문서화**의 초기 사례 중 하나였고, 이것이 특히 **FastAPI**를 \"찾게 된\" 첫 아이디어 중 하나였습니다.\n\n/// note | 참고\n\nDjango REST Framework는 Tom Christie가 만들었습니다. **FastAPI**의 기반이 되는 Starlette와 Uvicorn을 만든 사람과 동일합니다.\n\n///\n\n/// check | **FastAPI**에 영감을 준 것\n\n자동 API 문서화 웹 사용자 인터페이스를 제공하기.\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask는 \"microframework\"로, Django에 기본으로 포함된 데이터베이스 통합이나 여러 기능들을 포함하지 않습니다.\n\n이 단순함과 유연성 덕분에 NoSQL 데이터베이스를 주 데이터 저장 시스템으로 사용하는 같은 작업이 가능합니다.\n\n매우 단순하기 때문에 비교적 직관적으로 배울 수 있지만, 문서가 어떤 지점에서는 다소 기술적으로 깊어지기도 합니다.\n\n또한 데이터베이스, 사용자 관리, 혹은 Django에 미리 구축되어 있는 다양한 기능들이 꼭 필요하지 않은 다른 애플리케이션에도 흔히 사용됩니다. 물론 이런 기능들 중 다수는 plug-in으로 추가할 수 있습니다.\n\n이런 구성요소의 분리와, 필요한 것만 정확히 덧붙여 확장할 수 있는 \"microframework\"라는 점은 제가 유지하고 싶었던 핵심 특성이었습니다.\n\nFlask의 단순함을 고려하면 API를 구축하는 데 잘 맞는 것처럼 보였습니다. 다음으로 찾고자 했던 것은 Flask용 \"Django REST Framework\"였습니다.\n\n/// check | **FastAPI**에 영감을 준 것\n\nmicro-framework가 되기. 필요한 도구와 구성요소를 쉽게 조합할 수 있도록 하기.\n\n단순하고 사용하기 쉬운 routing 시스템을 갖기.\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI**는 실제로 **Requests**의 대안이 아닙니다. 둘의 범위는 매우 다릅니다.\n\n실제로 FastAPI 애플리케이션 *내부에서* Requests를 사용하는 경우도 흔합니다.\n\n그럼에도 FastAPI는 Requests로부터 꽤 많은 영감을 얻었습니다.\n\n**Requests**는 (클라이언트로서) API와 *상호작용*하기 위한 라이브러리이고, **FastAPI**는 (서버로서) API를 *구축*하기 위한 라이브러리입니다.\n\n대략 말하면 서로 반대편에 있으며, 서로를 보완합니다.\n\nRequests는 매우 단순하고 직관적인 설계를 가졌고, 합리적인 기본값을 바탕으로 사용하기가 아주 쉽습니다. 동시에 매우 강력하고 커스터마이징도 가능합니다.\n\n그래서 공식 웹사이트에서 말하듯이:\n\n> Requests is one of the most downloaded Python packages of all time\n\n사용 방법은 매우 간단합니다. 예를 들어 `GET` 요청을 하려면 다음처럼 작성합니다:\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\n이에 대응하는 FastAPI의 API *경로 처리*는 다음과 같이 보일 수 있습니다:\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\n`requests.get(...)`와 `@app.get(...)`의 유사성을 확인해 보세요.\n\n/// check | **FastAPI**에 영감을 준 것\n\n* 단순하고 직관적인 API를 갖기.\n* HTTP method 이름(operations)을 직접, 직관적이고 명확한 방식으로 사용하기.\n* 합리적인 기본값을 제공하되, 강력한 커스터마이징을 가능하게 하기.\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\n제가 Django REST Framework에서 가장 원했던 주요 기능은 자동 API 문서화였습니다.\n\n그 후 JSON(또는 JSON의 확장인 YAML)을 사용해 API를 문서화하는 표준인 Swagger가 있다는 것을 알게 되었습니다.\n\n그리고 Swagger API를 위한 웹 사용자 인터페이스도 이미 만들어져 있었습니다. 그래서 API에 대한 Swagger 문서를 생성할 수 있다면, 이 웹 사용자 인터페이스를 자동으로 사용할 수 있게 됩니다.\n\n어느 시점에 Swagger는 Linux Foundation으로 넘어가 OpenAPI로 이름이 바뀌었습니다.\n\n그래서 2.0 버전을 이야기할 때는 \"Swagger\"라고 말하는 것이 일반적이고, 3+ 버전은 \"OpenAPI\"라고 말하는 것이 일반적입니다.\n\n/// check | **FastAPI**에 영감을 준 것\n\n커스텀 schema 대신, API 사양을 위한 열린 표준을 채택하고 사용하기.\n\n또한 표준 기반의 사용자 인터페이스 도구를 통합하기:\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\n이 두 가지는 꽤 대중적이고 안정적이기 때문에 선택되었습니다. 하지만 간단히 검색해보면 OpenAPI를 위한 대안 UI가 수십 가지나 있다는 것을 알 수 있습니다(**FastAPI**와 함께 사용할 수 있습니다).\n\n///\n\n### Flask REST framework들 { #flask-rest-frameworks }\n\nFlask REST framework는 여러 개가 있지만, 시간을 들여 조사해 본 결과, 상당수가 중단되었거나 방치되어 있었고, 해결되지 않은 여러 이슈 때문에 적합하지 않은 경우가 많았습니다.\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nAPI 시스템에 필요한 주요 기능 중 하나는 데이터 \"<dfn title=\"마샬링, 변환이라고도 함\">직렬화</dfn>\"입니다. 이는 코드(Python)에서 데이터를 가져와 네트워크로 전송할 수 있는 형태로 변환하는 것을 의미합니다. 예를 들어 데이터베이스의 데이터를 담은 객체를 JSON 객체로 변환하거나, `datetime` 객체를 문자열로 변환하는 등의 작업입니다.\n\nAPI에 또 하나 크게 필요한 기능은 데이터 검증입니다. 특정 파라미터를 기준으로 데이터가 유효한지 확인하는 것입니다. 예를 들어 어떤 필드가 `int`인지, 임의의 문자열이 아닌지 확인하는 식입니다. 이는 특히 들어오는 데이터에 유용합니다.\n\n데이터 검증 시스템이 없다면, 모든 검사를 코드에서 수동으로 해야 합니다.\n\n이런 기능들을 제공하기 위해 Marshmallow가 만들어졌습니다. 훌륭한 라이브러리이며, 저도 이전에 많이 사용했습니다.\n\n하지만 Python type hints가 존재하기 전에 만들어졌습니다. 그래서 각 <dfn title=\"데이터가 어떻게 구성되어야 하는지에 대한 정의\">스키마</dfn>를 정의하려면 Marshmallow가 제공하는 특정 유틸리티와 클래스를 사용해야 합니다.\n\n/// check | **FastAPI**에 영감을 준 것\n\n데이터 타입과 검증을 제공하는 \"schema\"를 코드로 정의하고, 이를 자동으로 활용하기.\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nAPI에 필요한 또 다른 큰 기능은 들어오는 요청에서 데이터를 <dfn title=\"읽어서 Python 데이터로 변환하기\">파싱</dfn>하는 것입니다.\n\nWebargs는 Flask를 포함한 여러 framework 위에서 이를 제공하기 위해 만들어진 도구입니다.\n\n내부적으로 Marshmallow를 사용해 데이터 검증을 수행합니다. 그리고 같은 개발자들이 만들었습니다.\n\n아주 훌륭한 도구이며, 저도 **FastAPI**를 만들기 전에 많이 사용했습니다.\n\n/// info | 정보\n\nWebargs는 Marshmallow와 같은 개발자들이 만들었습니다.\n\n///\n\n/// check | **FastAPI**에 영감을 준 것\n\n들어오는 요청 데이터의 자동 검증을 갖기.\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow와 Webargs는 plug-in 형태로 검증, parsing, serialization을 제공합니다.\n\n하지만 문서화는 여전히 부족했습니다. 그래서 APISpec이 만들어졌습니다.\n\n이는 여러 framework를 위한 plug-in이며(Starlette용 plug-in도 있습니다).\n\n작동 방식은, 각 route를 처리하는 함수의 docstring 안에 YAML 형식으로 schema 정의를 작성하고,\n\n그로부터 OpenAPI schema를 생성합니다.\n\nFlask, Starlette, Responder 등에서 이런 방식으로 동작합니다.\n\n하지만 다시, Python 문자열 내부(큰 YAML)에서 micro-syntax를 다루어야 한다는 문제가 있습니다.\n\n에디터가 이를 크게 도와주지 못합니다. 또한 파라미터나 Marshmallow schema를 수정해놓고 YAML docstring도 같이 수정하는 것을 잊어버리면, 생성된 schema는 오래된 상태가 됩니다.\n\n/// info | 정보\n\nAPISpec은 Marshmallow와 같은 개발자들이 만들었습니다.\n\n///\n\n/// check | **FastAPI**에 영감을 준 것\n\nAPI를 위한 열린 표준인 OpenAPI를 지원하기.\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\nFlask plug-in으로, Webargs, Marshmallow, APISpec을 묶어줍니다.\n\nWebargs와 Marshmallow의 정보를 사용해 APISpec으로 OpenAPI schema를 자동 생성합니다.\n\n훌륭한 도구인데도 과소평가되어 있습니다. 다른 많은 Flask plug-in보다 훨씬 더 유명해져야 합니다. 문서가 너무 간결하고 추상적이라서 그럴 수도 있습니다.\n\n이 도구는 Python docstring 내부에 YAML(또 다른 문법)을 작성해야 하는 문제를 해결했습니다.\n\nFlask + Flask-apispec + Marshmallow + Webargs 조합은 **FastAPI**를 만들기 전까지 제가 가장 좋아하던 백엔드 stack이었습니다.\n\n이를 사용하면서 여러 Flask full-stack generator가 만들어졌습니다. 이것들이 지금까지 저(그리고 여러 외부 팀)가 사용해 온 주요 stack입니다:\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\n그리고 이 동일한 full-stack generator들이 [**FastAPI** Project Generators](project-generation.md)의 기반이 되었습니다.\n\n/// info | 정보\n\nFlask-apispec은 Marshmallow와 같은 개발자들이 만들었습니다.\n\n///\n\n/// check | **FastAPI**에 영감을 준 것\n\nserialization과 validation을 정의하는 동일한 코드로부터 OpenAPI schema를 자동 생성하기.\n\n///\n\n### [NestJS](https://nestjs.com/) (그리고 [Angular](https://angular.io/)) { #nestjs-and-angular }\n\n이건 Python도 아닙니다. NestJS는 Angular에서 영감을 받은 JavaScript(TypeScript) NodeJS framework입니다.\n\nFlask-apispec으로 할 수 있는 것과 어느 정도 비슷한 것을 달성합니다.\n\nAngular 2에서 영감을 받은 의존성 주입 시스템이 통합되어 있습니다. 제가 아는 다른 의존성 주입 시스템들처럼 \"injectable\"을 사전에 등록해야 하므로, 장황함과 코드 반복이 늘어납니다.\n\n파라미터가 TypeScript 타입(Python type hints와 유사함)으로 설명되기 때문에 에디터 지원은 꽤 좋습니다.\n\n하지만 TypeScript 데이터는 JavaScript로 컴파일된 뒤에는 보존되지 않기 때문에, 타입에 의존해 검증, serialization, 문서화를 동시에 정의할 수 없습니다. 이 점과 일부 설계 결정 때문에, 검증/serialization/자동 schema 생성을 하려면 여러 곳에 decorator를 추가해야 하며, 결과적으로 매우 장황해집니다.\n\n중첩 모델을 잘 처리하지 못합니다. 즉, 요청의 JSON body가 내부 필드를 가진 JSON 객체이고 그 내부 필드들이 다시 중첩된 JSON 객체인 경우, 제대로 문서화하고 검증할 수 없습니다.\n\n/// check | **FastAPI**에 영감을 준 것\n\nPython 타입을 사용해 뛰어난 에디터 지원을 제공하기.\n\n강력한 의존성 주입 시스템을 갖추기. 코드 반복을 최소화하는 방법을 찾기.\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\n`asyncio` 기반의 매우 빠른 Python framework 중 초기 사례였습니다. Flask와 매우 유사하게 만들어졌습니다.\n\n/// note | 기술 세부사항\n\n[`uvloop`](https://github.com/MagicStack/uvloop)를 기본 Python `asyncio` 루프 대신 사용했습니다. 이것이 매우 빠르게 만든 요인입니다.\n\n이는 Uvicorn과 Starlette에 명확히 영감을 주었고, 현재 공개 benchmark에서는 이 둘이 Sanic보다 더 빠릅니다.\n\n///\n\n/// check | **FastAPI**에 영감을 준 것\n\n미친 성능을 낼 수 있는 방법을 찾기.\n\n그래서 **FastAPI**는 Starlette를 기반으로 합니다. Starlette는 사용 가능한 framework 중 가장 빠르기 때문입니다(서드파티 benchmark로 테스트됨).\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon은 또 다른 고성능 Python framework로, 최소한으로 설계되었고 Hug 같은 다른 framework의 기반으로 동작하도록 만들어졌습니다.\n\n함수가 두 개의 파라미터(하나는 \"request\", 하나는 \"response\")를 받도록 설계되어 있습니다. 그런 다음 request에서 일부를 \"읽고\", response에 일부를 \"작성\"합니다. 이 설계 때문에, 표준 Python type hints를 함수 파라미터로 사용해 요청 파라미터와 body를 선언하는 것이 불가능합니다.\n\n따라서 데이터 검증, serialization, 문서화는 자동으로 되지 않고 코드로 해야 합니다. 또는 Hug처럼 Falcon 위에 framework를 얹어 구현해야 합니다. request 객체 하나와 response 객체 하나를 파라미터로 받는 Falcon의 설계에서 영감을 받은 다른 framework에서도 같은 구분이 나타납니다.\n\n/// check | **FastAPI**에 영감을 준 것\n\n훌륭한 성능을 얻는 방법을 찾기.\n\nHug(= Falcon 기반)과 함께, 함수에서 `response` 파라미터를 선언하도록 **FastAPI**에 영감을 주었습니다.\n\n다만 FastAPI에서는 선택 사항이며, 주로 헤더, 쿠키, 그리고 대체 status code를 설정하는 데 사용됩니다.\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\n**FastAPI**를 만들기 시작한 초기 단계에서 Molten을 알게 되었고, 꽤 비슷한 아이디어를 갖고 있었습니다:\n\n* Python type hints 기반\n* 이 타입으로부터 검증과 문서화 생성\n* 의존성 주입 시스템\n\nPydantic 같은 서드파티 라이브러리를 사용해 데이터 검증/serialization/문서화를 하지 않고 자체 구현을 사용합니다. 그래서 이런 데이터 타입 정의를 쉽게 재사용하기는 어렵습니다.\n\n조금 더 장황한 설정이 필요합니다. 또한 WSGI(ASGI가 아니라) 기반이므로, Uvicorn, Starlette, Sanic 같은 도구가 제공하는 고성능을 활용하도록 설계되지 않았습니다.\n\n의존성 주입 시스템은 의존성을 사전에 등록해야 하고, 선언된 타입을 기반으로 의존성을 해결합니다. 따라서 특정 타입을 제공하는 \"component\"를 두 개 이상 선언할 수 없습니다.\n\nRoute는 한 곳에서 선언하고, 다른 곳에 선언된 함수를 사용합니다(엔드포인트를 처리하는 함수 바로 위에 둘 수 있는 decorator를 사용하는 대신). 이는 Flask(및 Starlette)보다는 Django 방식에 가깝습니다. 코드에서 상대적으로 강하게 결합된 것들을 분리해 놓습니다.\n\n/// check | **FastAPI**에 영감을 준 것\n\n모델 속성의 \"default\" 값으로 데이터 타입에 대한 추가 검증을 정의하기. 이는 에디터 지원을 개선하며, 이전에는 Pydantic에 없었습니다.\n\n이것은 실제로 Pydantic의 일부를 업데이트하여 같은 검증 선언 스타일을 지원하도록 하는 데 영감을 주었습니다(이 기능은 이제 Pydantic에 이미 포함되어 있습니다).\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug는 Python type hints를 사용해 API 파라미터 타입을 선언하는 기능을 구현한 초기 framework 중 하나였습니다. 이는 다른 도구들도 같은 방식을 하도록 영감을 준 훌륭한 아이디어였습니다.\n\n표준 Python 타입 대신 커스텀 타입을 선언에 사용했지만, 여전히 큰 진전이었습니다.\n\n또한 전체 API를 JSON으로 선언하는 커스텀 schema를 생성한 초기 framework 중 하나였습니다.\n\nOpenAPI나 JSON Schema 같은 표준을 기반으로 하지 않았기 때문에 Swagger UI 같은 다른 도구와 통합하는 것은 직관적이지 않았습니다. 하지만 역시 매우 혁신적인 아이디어였습니다.\n\n흥미롭고 흔치 않은 기능이 하나 있습니다. 같은 framework로 API뿐 아니라 CLI도 만들 수 있습니다.\n\n동기식 Python 웹 framework의 이전 표준(WSGI) 기반이어서 Websockets와 다른 것들을 처리할 수는 없지만, 성능은 여전히 높습니다.\n\n/// info | 정보\n\nHug는 Timothy Crosley가 만들었습니다. Python 파일에서 import를 자동으로 정렬하는 훌륭한 도구인 [`isort`](https://github.com/timothycrosley/isort)의 제작자이기도 합니다.\n\n///\n\n/// check | **FastAPI**에 영감을 준 아이디어들\n\nHug는 APIStar의 일부에 영감을 주었고, 저는 APIStar와 함께 Hug를 가장 유망한 도구 중 하나로 보았습니다.\n\nHug는 Python type hints로 파라미터를 선언하고, API를 정의하는 schema를 자동으로 생성하도록 **FastAPI**에 영감을 주었습니다.\n\nHug는 헤더와 쿠키를 설정하기 위해 함수에 `response` 파라미터를 선언하도록 **FastAPI**에 영감을 주었습니다.\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0.5) { #apistar-0-5 }\n\n**FastAPI**를 만들기로 결정하기 직전에 **APIStar** 서버를 발견했습니다. 찾고 있던 거의 모든 것을 갖추고 있었고 설계도 훌륭했습니다.\n\nNestJS와 Molten보다 앞서, Python type hints를 사용해 파라미터와 요청을 선언하는 framework 구현을 제가 처음 본 사례들 중 하나였습니다. Hug와 거의 같은 시기에 발견했습니다. 하지만 APIStar는 OpenAPI 표준을 사용했습니다.\n\n여러 위치에서 동일한 type hints를 기반으로 자동 데이터 검증, 데이터 serialization, OpenAPI schema 생성을 제공했습니다.\n\nBody schema 정의는 Pydantic처럼 동일한 Python type hints를 사용하지는 않았고 Marshmallow와 조금 더 비슷해서 에디터 지원은 그만큼 좋지 않았지만, 그래도 APIStar는 당시 사용할 수 있는 최선의 선택지였습니다.\n\n당시 최고의 성능 benchmark를 가졌습니다(Starlette에 의해서만 추월됨).\n\n처음에는 자동 API 문서화 웹 UI가 없었지만, Swagger UI를 추가할 수 있다는 것을 알고 있었습니다.\n\n의존성 주입 시스템도 있었습니다. 위에서 언급한 다른 도구들처럼 component의 사전 등록이 필요했지만, 여전히 훌륭한 기능이었습니다.\n\n보안 통합이 없어서 전체 프로젝트에서 사용해 볼 수는 없었습니다. 그래서 Flask-apispec 기반 full-stack generator로 갖추고 있던 모든 기능을 대체할 수 없었습니다. 그 기능을 추가하는 pull request를 만드는 것이 제 백로그에 있었습니다.\n\n하지만 이후 프로젝트의 초점이 바뀌었습니다.\n\n더 이상 API web framework가 아니게 되었는데, 제작자가 Starlette에 집중해야 했기 때문입니다.\n\n이제 APIStar는 web framework가 아니라 OpenAPI 사양을 검증하기 위한 도구 모음입니다.\n\n/// info | 정보\n\nAPIStar는 Tom Christie가 만들었습니다. 다음을 만든 사람과 동일합니다:\n\n* Django REST Framework\n* Starlette(**FastAPI**의 기반)\n* Uvicorn(Starlette와 **FastAPI**에서 사용)\n\n///\n\n/// check | **FastAPI**에 영감을 준 것\n\n존재하게 만들기.\n\n동일한 Python 타입으로 여러 가지(데이터 검증, serialization, 문서화)를 선언하면서 동시에 뛰어난 에디터 지원을 제공한다는 아이디어는 제가 매우 훌륭하다고 생각했습니다.\n\n그리고 오랫동안 비슷한 framework를 찾아 여러 대안을 테스트한 끝에, APIStar가 그때 이용 가능한 최선의 선택지였습니다.\n\n그 후 APIStar 서버가 더는 존재하지 않게 되고 Starlette가 만들어졌는데, 이는 그런 시스템을 위한 더 새롭고 더 나은 기반이었습니다. 이것이 **FastAPI**를 만들게 된 최종 영감이었습니다.\n\n저는 **FastAPI**를 APIStar의 \"정신적 후계자\"로 생각합니다. 동시에, 이 모든 이전 도구들에서 배운 것들을 바탕으로 기능, typing 시스템, 그리고 다른 부분들을 개선하고 확장했습니다.\n\n///\n\n## **FastAPI**가 사용하는 것 { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic은 Python type hints를 기반으로 데이터 검증, serialization, 문서화(JSON Schema 사용)를 정의하는 라이브러리입니다.\n\n그 덕분에 매우 직관적입니다.\n\nMarshmallow와 비교할 수 있습니다. 다만 benchmark에서 Marshmallow보다 빠릅니다. 그리고 동일한 Python type hints를 기반으로 하므로 에디터 지원도 훌륭합니다.\n\n/// check | **FastAPI**가 이를 사용하는 목적\n\n모든 데이터 검증, 데이터 serialization, 자동 모델 문서화(JSON Schema 기반)를 처리하기.\n\n그 다음 **FastAPI**는 그 JSON Schema 데이터를 가져와 OpenAPI에 포함시키며, 그 외에도 여러 작업을 수행합니다.\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette는 경량 <dfn title=\"비동기 Python 웹 애플리케이션을 구축하기 위한 새로운 표준\">ASGI</dfn> framework/toolkit으로, 고성능 asyncio 서비스를 만들기에 이상적입니다.\n\n매우 단순하고 직관적입니다. 쉽게 확장할 수 있도록 설계되었고, 모듈식 component를 갖습니다.\n\n다음이 포함됩니다:\n\n* 정말 인상적인 성능.\n* WebSocket 지원.\n* 프로세스 내 백그라운드 작업.\n* 시작 및 종료 이벤트.\n* HTTPX 기반의 테스트 클라이언트.\n* CORS, GZip, Static Files, Streaming responses.\n* 세션 및 쿠키 지원.\n* 100% 테스트 커버리지.\n* 100% 타입 주석이 달린 코드베이스.\n* 소수의 필수 의존성.\n\nStarlette는 현재 테스트된 Python framework 중 가장 빠릅니다. 단, framework가 아니라 서버인 Uvicorn이 더 빠릅니다.\n\nStarlette는 웹 microframework의 기본 기능을 모두 제공합니다.\n\n하지만 자동 데이터 검증, serialization, 문서화는 제공하지 않습니다.\n\n그것이 **FastAPI**가 위에 추가하는 핵심 중 하나이며, 모두 Python type hints(Pydantic 사용)를 기반으로 합니다. 여기에 더해 의존성 주입 시스템, 보안 유틸리티, OpenAPI schema 생성 등도 포함됩니다.\n\n/// note | 기술 세부사항\n\nASGI는 Django 코어 팀 멤버들이 개발 중인 새로운 \"표준\"입니다. 아직 \"Python 표준\"(PEP)은 아니지만, 그 방향으로 진행 중입니다.\n\n그럼에도 이미 여러 도구에서 \"표준\"으로 사용되고 있습니다. 이는 상호운용성을 크게 개선합니다. 예를 들어 Uvicorn을 다른 ASGI 서버(예: Daphne 또는 Hypercorn)로 교체할 수도 있고, `python-socketio` 같은 ASGI 호환 도구를 추가할 수도 있습니다.\n\n///\n\n/// check | **FastAPI**가 이를 사용하는 목적\n\n핵심 웹 부분을 모두 처리하기. 그 위에 기능을 추가하기.\n\n`FastAPI` 클래스 자체는 `Starlette` 클래스를 직접 상속합니다.\n\n따라서 Starlette로 할 수 있는 모든 것은 기본적으로 **FastAPI**로도 직접 할 수 있습니다. 즉, **FastAPI**는 사실상 Starlette에 강력한 기능을 더한 것입니다.\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn은 uvloop과 httptools로 구축된 초고속 ASGI 서버입니다.\n\nweb framework가 아니라 서버입니다. 예를 들어 경로 기반 routing을 위한 도구는 제공하지 않습니다. 그런 것은 Starlette(또는 **FastAPI**) 같은 framework가 위에서 제공합니다.\n\nStarlette와 **FastAPI**에서 권장하는 서버입니다.\n\n/// check | **FastAPI**가 이를 권장하는 방식\n\n**FastAPI** 애플리케이션을 실행하기 위한 주요 웹 서버.\n\n또한 `--workers` 커맨드라인 옵션을 사용하면 비동기 멀티프로세스 서버로 실행할 수도 있습니다.\n\n자세한 내용은 [배포](deployment/index.md) 섹션을 확인하세요.\n\n///\n\n## 벤치마크와 속도 { #benchmarks-and-speed }\n\nUvicorn, Starlette, FastAPI 사이의 차이를 이해하고 비교하려면 [벤치마크](benchmarks.md) 섹션을 확인하세요.\n"
  },
  {
    "path": "docs/ko/docs/async.md",
    "content": "# 동시성과 async / await { #concurrency-and-async-await }\n\n*경로 처리 함수*에서의 `async def` 문법에 대한 세부사항과 비동기 코드, 동시성 및 병렬성에 대한 배경\n\n## 바쁘신가요? { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - 너무 길어서 읽지 않음\"><strong>TL;DR:</strong></abbr>\n\n다음과 같이 `await`를 사용해 호출하라고 안내하는 제3자 라이브러리를 사용하는 경우:\n\n```Python\nresults = await some_library()\n```\n\n다음처럼 *경로 처리 함수*를 `async def`를 사용해 선언하십시오:\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | 참고\n\n`async def`로 생성된 함수 내부에서만 `await`를 사용할 수 있습니다.\n\n///\n\n---\n\n데이터베이스, API, 파일시스템 등과 의사소통하는 제3자 라이브러리를 사용하고, 그것이 `await` 사용을 지원하지 않는 경우(현재 대부분의 데이터베이스 라이브러리가 그러합니다), *경로 처리 함수*를 일반적인 `def`를 사용해 선언하십시오:\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\n만약 여러분의 애플리케이션이 (어째서인지) 다른 어떤 것과도 통신하고 그 응답을 기다릴 필요가 없다면, 내부에서 `await`를 사용할 필요가 없더라도 `async def`를 사용하세요.\n\n---\n\n잘 모르겠다면, 일반적인 `def`를 사용하세요.\n\n---\n\n**참고**: *경로 처리 함수*에서 필요한 만큼 `def`와 `async def`를 혼용할 수 있으며, 각각에 대해 가장 알맞은 옵션을 선택해 정의하면 됩니다. FastAPI가 올바르게 처리합니다.\n\n어쨌든 위의 어떤 경우에서도 FastAPI는 여전히 비동기적으로 동작하며 매우 빠릅니다.\n\n하지만 위의 단계를 따르면, 몇 가지 성능 최적화를 할 수 있습니다.\n\n## 기술적 세부사항 { #technical-details }\n\n최신 파이썬 버전은 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 **`async` 및 `await`** 문법과 함께 지원합니다.\n\n아래 섹션들에서 해당 문장을 부분별로 살펴보겠습니다:\n\n* **비동기 코드**\n* **`async`와 `await`**\n* **코루틴**\n\n## 비동기 코드 { #asynchronous-code }\n\n비동기 코드는 언어 💬 가 코드의 어느 한 부분에서 컴퓨터/프로그램 🤖 에게, 어느 시점에는 어딘가에서 *다른 무언가*가 끝날 때까지 기다려야 한다고 말할 수 있는 방법이 있다는 의미입니다. 그 *다른 무언가*를 \"slow-file\" 📝 이라고 해보겠습니다.\n\n따라서 그 시간 동안 컴퓨터는 \"slow-file\" 📝 이 끝나는 동안 다른 작업을 하러 갈 수 있습니다.\n\n그 다음 컴퓨터/프로그램 🤖 은 다시 기다리는 중이기 때문에 기회가 있을 때마다 돌아오거나, 혹은 그 시점에 해야 할 작업을 모두 끝낼 때마다 돌아옵니다. 그리고 기다리던 작업 중 이미 끝난 것이 있는지 확인하면서, 해야 했던 작업을 수행합니다.\n\n다음으로, 완료된 첫 번째 작업(우리의 \"slow-file\" 📝 이라고 해보겠습니다)을 가져와서, 그에 대해 해야 했던 작업을 계속합니다.\n\n이 \"다른 무언가를 기다리는 것\"은 일반적으로 프로세서와 RAM 메모리 속도에 비해 상대적으로 \"느린\" <abbr title=\"Input and Output - 입력/출력\">I/O</abbr> 작업을 의미합니다. 예를 들어 다음을 기다리는 것입니다:\n\n* 네트워크를 통해 클라이언트가 데이터를 보내는 것\n* 네트워크를 통해 클라이언트가 여러분의 프로그램이 보낸 데이터를 받는 것\n* 시스템이 디스크의 파일 내용을 읽어서 프로그램에 전달하는 것\n* 프로그램이 시스템에 전달한 내용을 디스크에 쓰는 것\n* 원격 API 작업\n* 데이터베이스 작업이 완료되는 것\n* 데이터베이스 쿼리가 결과를 반환하는 것\n* 기타 등등\n\n실행 시간의 대부분이 <abbr title=\"Input and Output - 입력/출력\">I/O</abbr> 작업을 기다리는 데 소비되기 때문에, 이를 \"I/O bound\" 작업이라고 부릅니다.\n\n이것은 컴퓨터/프로그램이 느린 작업과 \"동기화\"되어, 아무것도 하지 않은 채 그 작업이 끝나는 정확한 시점만 기다렸다가 결과를 가져와 일을 계속할 필요가 없기 때문에 \"비동기\"라고 불립니다.\n\n대신 \"비동기\" 시스템에서는, 작업이 끝나면 컴퓨터/프로그램이 하러 갔던 일을 마칠 때까지 잠시(몇 마이크로초) 줄에서 기다렸다가, 다시 돌아와 결과를 받아 이를 사용해 작업을 계속할 수 있습니다.\n\n\"동기\"(“비동기”의 반대)는 보통 \"순차\"라는 용어로도 불리는데, 컴퓨터/프로그램이 다른 작업으로 전환하기 전에 모든 단계를 순서대로 따르기 때문이며, 그 단계들에 기다림이 포함되어 있더라도 마찬가지입니다.\n\n### 동시성과 햄버거 { #concurrency-and-burgers }\n\n위에서 설명한 **비동기** 코드에 대한 개념은 때때로 **\"동시성\"**이라고도 불립니다. 이는 **\"병렬성\"**과는 다릅니다.\n\n**동시성**과 **병렬성**은 모두 \"대략 같은 시간에 일어나는 서로 다른 일들\"과 관련이 있습니다.\n\n하지만 *동시성*과 *병렬성*의 세부적인 개념에는 꽤 차이가 있습니다.\n\n차이를 보기 위해, 다음의 햄버거 이야기를 상상해보세요:\n\n### 동시 햄버거 { #concurrent-burgers }\n\n여러분은 짝사랑 상대와 패스트푸드를 먹으러 갔고, 점원이 여러분 앞 사람들의 주문을 받는 동안 줄을 서서 기다립니다. 😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\n이제 여러분 차례가 되어, 여러분과 짝사랑 상대를 위해 매우 고급스러운 햄버거 2개를 주문합니다. 🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\n점원은 주방의 요리사에게 무언가를 말해, (지금은 앞선 손님들의 주문을 준비하고 있더라도) 여러분의 햄버거를 준비해야 한다는 것을 알게 합니다.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\n여러분이 돈을 냅니다. 💸\n\n점원은 여러분 차례 번호를 줍니다.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\n기다리는 동안, 여러분은 짝사랑 상대와 함께 자리를 고르고 앉아 오랫동안 대화를 나눕니다(여러분의 햄버거는 매우 고급스럽기 때문에 준비하는 데 시간이 좀 걸립니다).\n\n짝사랑 상대와 테이블에 앉아 햄버거를 기다리는 동안, 그 사람이 얼마나 멋지고 귀엽고 똑똑한지 감탄하며 시간을 보낼 수 있습니다 ✨😍✨.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\n기다리며 대화하는 동안, 때때로 여러분은 카운터에 표시되는 번호를 확인해 여러분 차례인지 봅니다.\n\n그러다 어느 순간 마침내 여러분 차례가 됩니다. 여러분은 카운터에 가서 햄버거를 받고, 테이블로 돌아옵니다.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\n여러분과 짝사랑 상대는 햄버거를 먹으며 좋은 시간을 보냅니다. ✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info | 정보\n\n아름다운 일러스트: [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\n이 이야기에서 여러분이 컴퓨터/프로그램 🤖 이라고 상상해보세요.\n\n줄을 서 있는 동안, 여러분은 그냥 쉬고 😴, 차례를 기다리며, 그다지 \"생산적인\" 일을 하지 않습니다. 하지만 점원은 주문만 받지(음식을 준비하진 않기) 때문에 줄이 빠르게 줄어들어 괜찮습니다.\n\n그 다음 여러분 차례가 되면, 여러분은 실제로 \"생산적인\" 일을 합니다. 메뉴를 처리하고, 무엇을 먹을지 결정하고, 짝사랑 상대의 선택을 확인하고, 결제하고, 올바른 현금이나 카드를 냈는지 확인하고, 정확히 청구되었는지 확인하고, 주문에 올바른 항목들이 들어갔는지 확인하는 등등을 합니다.\n\n하지만 그 다음에는, 아직 햄버거를 받지 못했더라도, 햄버거가 준비될 때까지 기다려야 🕙 하므로 점원과의 작업은 \"일시정지\" ⏸ 상태입니다.\n\n하지만 번호를 들고 카운터에서 벗어나 테이블에 앉으면, 여러분은 짝사랑 상대에게 관심을 전환 🔀 하고, 그에 대한 \"작업\" ⏯ 🤓 을 할 수 있습니다. 그러면 여러분은 다시 짝사랑 상대에게 작업을 거는 매우 \"생산적인\" 일을 하게 됩니다 😍.\n\n그 다음 점원 💁 이 카운터 화면에 여러분 번호를 띄워 \"햄버거를 만들었어요\"라고 말하지만, 표시된 번호가 여러분 차례로 바뀌었다고 해서 즉시 미친 듯이 뛰어가지는 않습니다. 여러분은 여러분 번호를 갖고 있고, 다른 사람들은 그들의 번호를 갖고 있으니, 아무도 여러분 햄버거를 훔쳐갈 수 없다는 것을 알기 때문입니다.\n\n그래서 여러분은 짝사랑 상대가 이야기를 끝낼 때까지 기다린 다음(현재 작업 ⏯ / 처리 중인 작업 🤓 을 끝내고), 부드럽게 미소 지으며 햄버거를 가지러 가겠다고 말합니다 ⏸.\n\n그 다음 여러분은 카운터로 가서 🔀, 이제 끝난 초기 작업 ⏯ 으로 돌아와 햄버거를 받고, 감사 인사를 하고, 테이블로 가져옵니다. 이로써 카운터와 상호작용하는 그 단계/작업이 끝납니다 ⏹. 그리고 이는 새로운 작업인 \"햄버거 먹기\" 🔀 ⏯ 를 만들지만, 이전 작업인 \"햄버거 받기\"는 끝났습니다 ⏹.\n\n### 병렬 햄버거 { #parallel-burgers }\n\n이제 이것이 \"동시 햄버거\"가 아니라 \"병렬 햄버거\"라고 상상해봅시다.\n\n여러분은 짝사랑 상대와 함께 병렬 패스트푸드를 먹으러 갑니다.\n\n여러분은 여러 명(예: 8명)의 점원이 동시에 요리사이기도 하여 여러분 앞 사람들의 주문을 받는 동안 줄을 서 있습니다.\n\n여러분 앞의 모든 사람들은, 8명의 점원 각각이 다음 주문을 받기 전에 바로 햄버거를 준비하러 가기 때문에, 카운터를 떠나지 않고 햄버거가 준비될 때까지 기다립니다.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\n마침내 여러분 차례가 되어, 여러분과 짝사랑 상대를 위해 매우 고급스러운 햄버거 2개를 주문합니다.\n\n여러분이 돈을 냅니다 💸.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\n점원은 주방으로 갑니다.\n\n여러분은 번호표가 없으므로, 다른 사람이 여러분보다 먼저 햄버거를 가져가지 못하도록 카운터 앞에 서서 기다립니다 🕙.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\n여러분과 짝사랑 상대는 햄버거가 나오면 다른 사람이 끼어들어 가져가지 못하게 하느라 바쁘기 때문에, 짝사랑 상대에게 집중할 수 없습니다. 😞\n\n이것은 \"동기\" 작업이며, 여러분은 점원/요리사 👨‍🍳 와 \"동기화\"되어 있습니다. 점원/요리사 👨‍🍳 가 햄버거를 완성해 여러분에게 주는 정확한 순간에 그 자리에 있어야 하므로, 여러분은 기다려야 🕙 하고, 그렇지 않으면 다른 사람이 가져갈 수도 있습니다.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\n그러다 점원/요리사 👨‍🍳 가 카운터 앞에서 오랫동안 기다린 🕙 끝에 마침내 햄버거를 가지고 돌아옵니다.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\n여러분은 햄버거를 받아 짝사랑 상대와 테이블로 갑니다.\n\n그냥 먹고, 끝입니다. ⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\n대부분의 시간을 카운터 앞에서 기다리는 데 🕙 썼기 때문에, 대화하거나 작업을 걸 시간은 많지 않았습니다. 😞\n\n/// info | 정보\n\n아름다운 일러스트: [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\n이 병렬 햄버거 시나리오에서, 여러분은 두 개의 프로세서(여러분과 짝사랑 상대)를 가진 컴퓨터/프로그램 🤖 이며, 둘 다 기다리고 🕙 오랫동안 \"카운터에서 기다리기\" 🕙 에 주의를 ⏯ 기울입니다.\n\n패스트푸드점에는 8개의 프로세서(점원/요리사)가 있습니다. 동시 햄버거 가게는 2개(점원 1명, 요리사 1명)만 있었을 것입니다.\n\n하지만 여전히 최종 경험은 그다지 좋지 않습니다. 😞\n\n---\n\n이것이 햄버거의 병렬 버전에 해당하는 이야기입니다. 🍔\n\n좀 더 \"현실적인\" 예시로, 은행을 상상해보세요.\n\n최근까지 대부분의 은행에는 여러 은행원 👨‍💼👨‍💼👨‍💼👨‍💼 과 긴 줄 🕙🕙🕙🕙🕙🕙🕙🕙 이 있었습니다.\n\n모든 은행원이 한 고객씩 순서대로 모든 일을 처리합니다 👨‍💼⏯.\n\n그리고 여러분은 오랫동안 줄에서 기다려야 🕙 하며, 그렇지 않으면 차례를 잃습니다.\n\n아마 은행 🏦 업무를 보러 갈 때 짝사랑 상대 😍 를 데려가고 싶지는 않을 것입니다.\n\n### 햄버거 예시의 결론 { #burger-conclusion }\n\n\"짝사랑 상대와의 패스트푸드점 햄버거\" 시나리오에서는 기다림 🕙 이 많기 때문에, 동시 시스템 ⏸🔀⏯ 을 사용하는 것이 훨씬 더 합리적입니다.\n\n대부분의 웹 애플리케이션이 그렇습니다.\n\n매우 많은 사용자들이 있고, 서버는 그들의 좋지 않은 연결을 통해 요청이 전송되기를 기다립니다 🕙.\n\n그리고 응답이 돌아오기를 다시 기다립니다 🕙.\n\n이 \"기다림\" 🕙 은 마이크로초 단위로 측정되지만, 모두 합치면 결국 꽤 많은 대기 시간이 됩니다.\n\n그래서 웹 API에는 비동기 ⏸🔀⏯ 코드를 사용하는 것이 매우 합리적입니다.\n\n이러한 종류의 비동기성은 NodeJS가 인기 있는 이유(비록 NodeJS가 병렬은 아니지만)이자, 프로그래밍 언어로서 Go의 강점입니다.\n\n그리고 이것이 **FastAPI**로 얻는 것과 같은 수준의 성능입니다.\n\n또한 병렬성과 비동기성을 동시에 사용할 수 있으므로, 대부분의 테스트된 NodeJS 프레임워크보다 더 높은 성능을 얻고, C에 더 가까운 컴파일 언어인 Go와 동등한 성능을 얻을 수 있습니다 [(모두 Starlette 덕분입니다)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).\n\n### 동시성이 병렬성보다 더 나은가요? { #is-concurrency-better-than-parallelism }\n\n아니요! 그게 이 이야기의 교훈은 아닙니다.\n\n동시성은 병렬성과 다릅니다. 그리고 많은 기다림이 포함되는 **특정한** 시나리오에서는 더 낫습니다. 그 때문에 웹 애플리케이션 개발에서는 일반적으로 병렬성보다 훨씬 더 낫습니다. 하지만 모든 것에 해당하진 않습니다.\n\n그래서 균형을 맞추기 위해, 다음의 짧은 이야기를 상상해보세요:\n\n> 여러분은 크고 더러운 집을 청소해야 합니다.\n\n*네, 이게 전부입니다*.\n\n---\n\n어디에도 기다림 🕙 은 없고, 집의 여러 장소에서 해야 할 일이 많을 뿐입니다.\n\n햄버거 예시처럼 거실부터, 그 다음은 부엌처럼 순서를 정할 수도 있지만, 어떤 것도 기다리지 🕙 않고 계속 청소만 하기 때문에, 순서는 아무런 영향을 주지 않습니다.\n\n순서가 있든 없든(동시성) 끝내는 데 걸리는 시간은 같고, 같은 양의 일을 하게 됩니다.\n\n하지만 이 경우, 전(前) 점원/요리사이자 현(現) 청소부가 된 8명을 데려올 수 있고, 각자(그리고 여러분)가 집의 구역을 하나씩 맡아 청소한다면, 추가 도움과 함께 모든 일을 **병렬**로 수행하여 훨씬 더 빨리 끝낼 수 있습니다.\n\n이 시나리오에서 (여러분을 포함한) 각 청소부는 프로세서가 되어, 맡은 일을 수행합니다.\n\n그리고 실행 시간의 대부분이 기다림이 아니라 실제 작업에 쓰이고, 컴퓨터에서 작업은 <abbr title=\"Central Processing Unit - 중앙 처리 장치\">CPU</abbr>가 수행하므로, 이런 문제를 \"CPU bound\"라고 부릅니다.\n\n---\n\nCPU bound 작업의 흔한 예시는 복잡한 수학 처리가 필요한 것들입니다.\n\n예를 들어:\n\n* **오디오** 또는 **이미지** 처리\n* **컴퓨터 비전**: 이미지는 수백만 개의 픽셀로 구성되며, 각 픽셀은 3개의 값/색을 갖습니다. 보통 그 픽셀들에 대해 동시에 무언가를 계산해야 합니다.\n* **머신러닝**: 보통 많은 \"matrix\"와 \"vector\" 곱셈이 필요합니다. 숫자가 있는 거대한 스프레드시트를 생각하고, 그 모든 수를 동시에 곱한다고 생각해보세요.\n* **딥러닝**: 머신러닝의 하위 분야이므로 동일하게 적용됩니다. 다만 곱해야 할 숫자가 있는 스프레드시트가 하나가 아니라, 아주 큰 집합이며, 많은 경우 그 모델을 만들고/또는 사용하기 위해 특별한 프로세서를 사용합니다.\n\n### 동시성 + 병렬성: 웹 + 머신러닝 { #concurrency-parallelism-web-machine-learning }\n\n**FastAPI**를 사용하면 웹 개발에서 매우 흔한 동시성의 이점을( NodeJS의 주요 매력과 같은) 얻을 수 있습니다.\n\n또한 머신러닝 시스템처럼 **CPU bound** 워크로드에 대해 병렬성과 멀티프로세싱(여러 프로세스를 병렬로 실행)을 활용할 수도 있습니다.\n\n이것은 파이썬이 **데이터 사이언스**, 머신러닝, 특히 딥러닝의 주요 언어라는 단순한 사실과 더해져, FastAPI를 데이터 사이언스/머신러닝 웹 API 및 애플리케이션(그 외에도 많은 것들)에 매우 잘 맞는 선택으로 만들어 줍니다.\n\n프로덕션에서 이 병렬성을 어떻게 달성하는지 보려면 [배포](deployment/index.md) 섹션을 참고하세요.\n\n## `async`와 `await` { #async-and-await }\n\n최신 파이썬 버전에는 비동기 코드를 정의하는 매우 직관적인 방법이 있습니다. 이 방법은 이를 평범한 \"순차\" 코드처럼 보이게 하고, 적절한 순간에 여러분을 위해 \"기다림\"을 수행합니다.\n\n결과를 주기 전에 기다림이 필요한 작업이 있고, 이러한 새로운 파이썬 기능을 지원한다면, 다음과 같이 작성할 수 있습니다:\n\n```Python\nburgers = await get_burgers(2)\n```\n\n여기서 핵심은 `await`입니다. 이는 파이썬에게 `get_burgers(2)`가 그 일을 끝낼 때까지 🕙 기다리도록 ⏸ 말하고, 그 결과를 `burgers`에 저장하기 전에 완료되기를 기다리라고 합니다. 이를 통해 파이썬은 그동안(예: 다른 요청을 받는 것처럼) 다른 일을 하러 갈 수 있다는 것 🔀 ⏯ 을 알게 됩니다.\n\n`await`가 동작하려면, 이 비동기성을 지원하는 함수 내부에 있어야 합니다. 그러려면 `async def`로 선언하기만 하면 됩니다:\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # 햄버거를 만들기 위한 비동기 처리를 수행\n    return burgers\n```\n\n...`def` 대신:\n\n```Python hl_lines=\"2\"\n# 비동기가 아닙니다\ndef get_sequential_burgers(number: int):\n    # 햄버거를 만들기 위한 순차 처리를 수행\n    return burgers\n```\n\n`async def`를 사용하면, 파이썬은 그 함수 내부에서 `await` 표현식에 주의해야 하며, 그 함수의 실행을 \"일시정지\" ⏸ 하고 다시 돌아오기 전에 다른 일을 하러 갈 수 있다는 것 🔀 을 알게 됩니다.\n\n`async def` 함수를 호출하고자 할 때는, 그 함수를 \"await\" 해야 합니다. 따라서 아래는 동작하지 않습니다:\n\n```Python\n# 동작하지 않습니다. get_burgers는 async def로 정의되었습니다\nburgers = get_burgers(2)\n```\n\n---\n\n따라서, `await`로 호출할 수 있다고 말하는 라이브러리를 사용한다면, 다음과 같이 그것을 사용하는 *경로 처리 함수*를 `async def`로 만들어야 합니다:\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### 더 세부적인 기술적 사항 { #more-technical-details }\n\n`await`는 `async def`로 정의된 함수 내부에서만 사용할 수 있다는 것을 눈치채셨을 것입니다.\n\n하지만 동시에, `async def`로 정의된 함수는 \"await\" 되어야 합니다. 따라서 `async def`를 가진 함수는 `async def`로 정의된 함수 내부에서만 호출될 수 있습니다.\n\n그렇다면, 닭이 먼저냐 달걀이 먼저냐처럼, 첫 번째 `async` 함수는 어떻게 호출할 수 있을까요?\n\n**FastAPI**로 작업한다면 걱정할 필요가 없습니다. 그 \"첫\" 함수는 여러분의 *경로 처리 함수*가 될 것이고, FastAPI는 올바르게 처리하는 방법을 알고 있기 때문입니다.\n\n하지만 FastAPI 없이 `async` / `await`를 사용하고 싶다면, 그것도 가능합니다.\n\n### 여러분만의 async 코드 작성하기 { #write-your-own-async-code }\n\nStarlette(그리고 **FastAPI**)는 [AnyIO](https://anyio.readthedocs.io/en/stable/)를 기반으로 하고 있으며, 파이썬 표준 라이브러리 [asyncio](https://docs.python.org/3/library/asyncio-task.html)와 [Trio](https://trio.readthedocs.io/en/stable/) 모두와 호환됩니다.\n\n특히, 코드에서 더 고급 패턴이 필요한 고급 동시성 사용 사례에서는 직접 [AnyIO](https://anyio.readthedocs.io/en/stable/)를 사용할 수 있습니다.\n\n그리고 FastAPI를 사용하지 않더라도, 높은 호환성을 확보하고 그 이점(예: *structured concurrency*)을 얻기 위해 [AnyIO](https://anyio.readthedocs.io/en/stable/)로 여러분만의 async 애플리케이션을 작성할 수도 있습니다.\n\n저는 AnyIO 위에 얇은 레이어로 또 다른 라이브러리를 만들었는데, 타입 어노테이션을 조금 개선하고 더 나은 **자동완성**, **인라인 오류** 등을 얻기 위한 것입니다. 또한 **이해**하고 **여러분만의 async 코드**를 작성하도록 돕는 친절한 소개와 튜토리얼도 제공합니다: [Asyncer](https://asyncer.tiangolo.com/). 특히 **async 코드와 일반**(blocking/동기) 코드를 **결합**해야 한다면 아주 유용합니다.\n\n### 비동기 코드의 다른 형태 { #other-forms-of-asynchronous-code }\n\n`async`와 `await`를 사용하는 이 스타일은 언어에서 비교적 최근에 추가되었습니다.\n\n하지만 비동기 코드를 다루는 일을 훨씬 더 쉽게 만들어 줍니다.\n\n거의 동일한 문법이 최근 브라우저와 NodeJS의 최신 JavaScript에도 포함되었습니다.\n\n하지만 그 이전에는 비동기 코드를 처리하는 것이 훨씬 더 복잡하고 어려웠습니다.\n\n이전 버전의 파이썬에서는 스레드 또는 [Gevent](https://www.gevent.org/)를 사용할 수 있었을 것입니다. 하지만 코드를 이해하고, 디버깅하고, 이에 대해 생각하는 것이 훨씬 더 복잡합니다.\n\n이전 버전의 NodeJS/브라우저 JavaScript에서는 \"callback\"을 사용했을 것입니다. 이는 \"callback hell\"로 이어집니다.\n\n## 코루틴 { #coroutines }\n\n**코루틴**은 `async def` 함수가 반환하는 것에 대한 매우 고급스러운 용어일 뿐입니다. 파이썬은 그것이 함수와 비슷한 무언가로서 시작할 수 있고, 어느 시점에 끝나지만, 내부에 `await`가 있을 때마다 내부적으로도 일시정지 ⏸ 될 수 있다는 것을 알고 있습니다.\n\n하지만 `async` 및 `await`와 함께 비동기 코드를 사용하는 이 모든 기능은 종종 \"코루틴\"을 사용한다고 요약됩니다. 이는 Go의 주요 핵심 기능인 \"Goroutines\"에 비견됩니다.\n\n## 결론 { #conclusion }\n\n위의 같은 문장을 다시 봅시다:\n\n> 최신 파이썬 버전은 **“코루틴”**이라고 하는 것을 사용하는 **“비동기 코드”**를 **`async` 및 `await`** 문법과 함께 지원합니다.\n\n이제 더 이해가 될 것입니다. ✨\n\n이 모든 것이 FastAPI(Starlette을 통해)를 구동하고, 인상적인 성능을 내게 하는 원동력입니다.\n\n## 매우 세부적인 기술적 사항 { #very-technical-details }\n\n/// warning | 경고\n\n이 부분은 아마 건너뛰어도 됩니다.\n\n이것들은 **FastAPI**가 내부적으로 어떻게 동작하는지에 대한 매우 세부적인 기술사항입니다.\n\n(코루틴, 스레드, 블로킹 등) 같은 기술 지식이 꽤 있고 FastAPI가 `async def`와 일반 `def`를 어떻게 처리하는지 궁금하다면, 계속 읽어보세요.\n\n///\n\n### 경로 처리 함수 { #path-operation-functions }\n\n*경로 처리 함수*를 `async def` 대신 일반적인 `def`로 선언하면, (서버를 블로킹할 수 있으므로 직접 호출하는 대신) 외부 스레드풀에서 실행되고 그 결과를 await 합니다.\n\n위에서 설명한 방식으로 동작하지 않는 다른 async 프레임워크를 사용해본 적이 있고, 아주 작은 성능 향상(약 100 나노초)을 위해 계산만 하는 사소한 *경로 처리 함수*를 일반 `def`로 정의하곤 했다면, **FastAPI**에서는 그 효과가 정반대가 될 수 있다는 점에 유의하세요. 이런 경우에는 *경로 처리 함수*에서 블로킹 <abbr title=\"Input/Output - 입력/출력: 디스크 읽기 또는 쓰기, 네트워크 통신.\">I/O</abbr> 를 수행하는 코드를 사용하지 않는 한 `async def`를 사용하는 편이 더 낫습니다.\n\n그럼에도 두 경우 모두, **FastAPI**는 이전에 사용하던 프레임워크보다 [여전히 더 빠를](index.md#performance) 가능성이 높습니다(또는 최소한 비슷합니다).\n\n### 의존성 { #dependencies }\n\n[의존성](tutorial/dependencies/index.md)에도 동일하게 적용됩니다. 의존성이 `async def` 대신 표준 `def` 함수라면, 외부 스레드풀에서 실행됩니다.\n\n### 하위 의존성 { #sub-dependencies }\n\n서로를 필요로 하는 여러 의존성과 [하위 의존성](tutorial/dependencies/sub-dependencies.md)을 함수 정의의 매개변수로 가질 수 있으며, 그중 일부는 `async def`로, 다른 일부는 일반 `def`로 생성되었을 수 있습니다. 그래도 정상 동작하며, 일반 `def`로 생성된 것들은 \"await\"되는 대신 (스레드풀에서) 외부 스레드에서 호출됩니다.\n\n### 다른 유틸리티 함수 { #other-utility-functions }\n\n직접 호출하는 다른 모든 유틸리티 함수는 일반 `def`나 `async def`로 생성될 수 있으며, FastAPI는 호출 방식에 영향을 주지 않습니다.\n\n이는 FastAPI가 여러분을 위해 호출하는 함수(즉, *경로 처리 함수*와 의존성)와 대비됩니다.\n\n유틸리티 함수가 `def`로 만든 일반 함수라면, 스레드풀이 아니라 직접(코드에 작성한 대로) 호출됩니다. 그리고 `async def`로 생성된 함수라면, 코드에서 호출할 때 그 함수를 `await` 해야 합니다.\n\n---\n\n다시 말하지만, 이것들은 아마도 이를 찾고 있었던 경우에 유용한 매우 세부적인 기술사항입니다.\n\n그렇지 않다면, 위 섹션의 가이드라인이면 충분합니다: <a href=\"#in-a-hurry\">바쁘신가요?</a>.\n"
  },
  {
    "path": "docs/ko/docs/benchmarks.md",
    "content": "# 벤치마크 { #benchmarks }\n\n독립적인 TechEmpower 벤치마크에 따르면 **FastAPI** 애플리케이션이 Uvicorn을 사용하여 [사용 가능한 가장 빠른 Python 프레임워크 중 하나](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7)로 실행되며, Starlette와 Uvicorn 자체(내부적으로 FastAPI가 사용하는 도구)보다 조금 아래에 위치합니다.\n\n그러나 벤치마크와 비교를 확인할 때 다음 사항을 염두에 두어야 합니다.\n\n## 벤치마크와 속도 { #benchmarks-and-speed }\n\n벤치마크를 확인할 때, 일반적으로 여러 가지 유형의 도구가 동등한 것으로 비교되는 것을 볼 수 있습니다.\n\n특히, Uvicorn, Starlette, FastAPI가 함께 비교되는 경우가 많습니다(다른 여러 도구와 함께).\n\n도구가 해결하는 문제가 단순할수록 성능이 더 좋아집니다. 그리고 대부분의 벤치마크는 도구가 제공하는 추가 기능을 테스트하지 않습니다.\n\n계층 구조는 다음과 같습니다:\n\n* **Uvicorn**: ASGI 서버\n    * **Starlette**: (Uvicorn 사용) 웹 마이크로 프레임워크\n        * **FastAPI**: (Starlette 사용) 데이터 검증 등 API를 구축하기 위한 여러 추가 기능이 포함된 API 마이크로 프레임워크\n\n* **Uvicorn**:\n    * 서버 자체 외에는 많은 추가 코드가 없기 때문에 최고의 성능을 발휘합니다.\n    * 직접 Uvicorn으로 응용 프로그램을 작성하지는 않을 것입니다. 즉, 사용자의 코드에는 적어도 Starlette(또는 **FastAPI**)에서 제공하는 모든 코드가 포함되어야 합니다. 그렇게 하면 최종 응용 프로그램은 프레임워크를 사용하고 앱 코드와 버그를 최소화하는 것과 동일한 오버헤드를 갖게 됩니다.\n    * Uvicorn을 비교할 때는 Daphne, Hypercorn, uWSGI 등의 응용 프로그램 서버와 비교하세요.\n* **Starlette**:\n    * Uvicorn 다음으로 좋은 성능을 발휘합니다. 사실 Starlette는 Uvicorn을 사용하여 실행됩니다. 따라서 더 많은 코드를 실행해야 하기 때문에 Uvicorn보다 \"느려질\" 수밖에 없습니다.\n    * 하지만 경로 기반 라우팅 등 간단한 웹 응용 프로그램을 구축할 수 있는 도구를 제공합니다.\n    * Starlette를 비교할 때는 Sanic, Flask, Django 등의 웹 프레임워크(또는 마이크로 프레임워크)와 비교하세요.\n* **FastAPI**:\n    * Starlette가 Uvicorn을 사용하므로 Uvicorn보다 빨라질 수 없는 것과 마찬가지로, **FastAPI**는 Starlette를 사용하므로 더 빠를 수 없습니다.\n    * FastAPI는 Starlette에 추가적으로 더 많은 기능을 제공합니다. API를 구축할 때 거의 항상 필요한 데이터 검증 및 직렬화와 같은 기능들이 포함되어 있습니다. 그리고 이를 사용하면 문서 자동화 기능도 제공됩니다(문서 자동화는 응용 프로그램 실행 시 오버헤드를 추가하지 않고 시작 시 생성됩니다).\n    * FastAPI를 사용하지 않고 직접 Starlette(또는 다른 도구, 예: Sanic, Flask, Responder 등)를 사용했다면 데이터 검증 및 직렬화를 직접 구현해야 합니다. 따라서 최종 응용 프로그램은 FastAPI를 사용한 것과 동일한 오버헤드를 가지게 될 것입니다. 많은 경우 데이터 검증 및 직렬화가 응용 프로그램에서 작성된 코드 중 가장 많은 부분을 차지합니다.\n    * 따라서 FastAPI를 사용함으로써 개발 시간, 버그, 코드 라인을 줄일 수 있으며, FastAPI를 사용하지 않았을 때와 동일한 성능(또는 더 나은 성능)을 얻을 수 있을 것입니다(코드에서 모두 구현해야 하기 때문에).\n    * FastAPI를 비교할 때는 Flask-apispec, NestJS, Molten 등 데이터 검증, 직렬화 및 문서화를 제공하는 웹 애플리케이션 프레임워크(또는 도구 집합)와 비교하세요. 통합된 자동 데이터 검증, 직렬화 및 문서화를 제공하는 프레임워크입니다.\n"
  },
  {
    "path": "docs/ko/docs/deployment/cloud.md",
    "content": "# 클라우드 제공업체에서 FastAPI 배포하기 { #deploy-fastapi-on-cloud-providers }\n\n사실상 거의 **모든 클라우드 제공업체**를 사용하여 여러분의 FastAPI 애플리케이션을 배포할 수 있습니다.\n\n대부분의 경우, 주요 클라우드 제공업체에서는 FastAPI를 배포할 수 있도록 가이드를 제공합니다.\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)**는 **FastAPI**를 만든 동일한 작성자와 팀이 구축했습니다.\n\n최소한의 노력으로 API를 **구축**, **배포**, **접근**하는 과정을 간소화합니다.\n\nFastAPI로 앱을 빌드할 때의 동일한 **개발자 경험**을 클라우드에 **배포**하는 데에도 제공합니다. 🎉\n\nFastAPI Cloud는 *FastAPI and friends* 오픈 소스 프로젝트의 주요 후원자이자 자금 제공자입니다. ✨\n\n## 클라우드 제공업체 - 후원자들 { #cloud-providers-sponsors }\n\n다른 몇몇 클라우드 제공업체들도 ✨ [**FastAPI를 후원합니다**](../help-fastapi.md#sponsor-the-author) ✨. 🙇\n\n가이드를 따라 하고 서비스를 사용해보기 위해 이들도 고려해볼 수 있습니다:\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/ko/docs/deployment/concepts.md",
    "content": "# 배포 개념 { #deployments-concepts }\n\n**FastAPI** 애플리케이션(사실 어떤 종류의 웹 API든)을 배포할 때는, 여러분이 신경 써야 할 여러 개념이 있습니다. 그리고 이 개념들을 활용하면 **애플리케이션을 배포하기 위한 가장 적절한 방법**을 찾을 수 있습니다.\n\n중요한 개념 몇 가지는 다음과 같습니다:\n\n* 보안 - HTTPS\n* 시작 시 실행\n* 재시작\n* 복제(실행 중인 프로세스 수)\n* 메모리\n* 시작 전 사전 단계\n\n이것들이 **배포**에 어떤 영향을 주는지 살펴보겠습니다.\n\n결국 최종 목표는 **API 클라이언트에 서비스를 제공**할 때 **보안**을 보장하고, **중단을 피하며**, **컴퓨팅 리소스**(예: 원격 서버/가상 머신)를 가능한 한 효율적으로 사용하는 것입니다. 🚀\n\n여기서 이 **개념들**을 조금 더 설명하겠습니다. 그러면 서로 매우 다른 환경, 심지어 아직 존재하지 않는 **미래**의 환경에서도 API를 어떻게 배포할지 결정하는 데 필요한 **직관**을 얻을 수 있을 것입니다.\n\n이 개념들을 고려하면, 여러분은 **자신의 API**를 배포하기 위한 최선의 방법을 **평가하고 설계**할 수 있습니다.\n\n다음 장들에서는 FastAPI 애플리케이션을 배포하기 위한 더 **구체적인 레시피**를 제공하겠습니다.\n\n하지만 지금은, 이 중요한 **개념적 아이디어**들을 확인해 봅시다. 이 개념들은 다른 어떤 종류의 웹 API에도 동일하게 적용됩니다. 💡\n\n## 보안 - HTTPS { #security-https }\n\n[이전 HTTPS 장](https.md)에서 HTTPS가 API에 암호화를 제공하는 방식에 대해 배웠습니다.\n\n또한 HTTPS는 일반적으로 애플리케이션 서버 바깥의 **외부** 컴포넌트인 **TLS Termination Proxy**가 제공한다는 것도 확인했습니다.\n\n그리고 **HTTPS 인증서 갱신**을 담당하는 무언가가 필요합니다. 같은 컴포넌트가 그 역할을 할 수도 있고, 다른 무언가가 담당할 수도 있습니다.\n\n### HTTPS를 위한 도구 예시 { #example-tools-for-https }\n\nTLS Termination Proxy로 사용할 수 있는 도구는 예를 들어 다음과 같습니다:\n\n* Traefik\n    * 인증서 갱신을 자동으로 처리 ✨\n* Caddy\n    * 인증서 갱신을 자동으로 처리 ✨\n* Nginx\n    * 인증서 갱신을 위해 Certbot 같은 외부 컴포넌트 사용\n* HAProxy\n    * 인증서 갱신을 위해 Certbot 같은 외부 컴포넌트 사용\n* Nginx 같은 Ingress Controller를 사용하는 Kubernetes\n    * 인증서 갱신을 위해 cert-manager 같은 외부 컴포넌트 사용\n* 클라우드 제공자가 서비스 일부로 내부적으로 처리(아래를 읽어보세요 👇)\n\n또 다른 선택지는 HTTPS 설정을 포함해 더 많은 일을 대신해주는 **클라우드 서비스**를 사용하는 것입니다. 제약이 있거나 비용이 더 들 수도 있습니다. 하지만 그 경우에는 TLS Termination Proxy를 직접 설정할 필요가 없습니다.\n\n다음 장에서 구체적인 예시를 보여드리겠습니다.\n\n---\n\n다음으로 고려할 개념들은 실제로 여러분의 API를 실행하는 프로그램(예: Uvicorn)과 관련된 내용입니다.\n\n## 프로그램과 프로세스 { #program-and-process }\n\n실행 중인 \"**프로세스**\"에 대해 많이 이야기하게 될 텐데, 이 말이 무엇을 의미하는지, 그리고 \"**프로그램**\"이라는 단어와 무엇이 다른지 명확히 해두는 것이 유용합니다.\n\n### 프로그램이란 { #what-is-a-program }\n\n**프로그램**이라는 단어는 보통 여러 가지를 가리키는 데 사용됩니다:\n\n* 여러분이 작성하는 **코드**, 즉 **Python 파일**들\n* 운영체제에서 **실행**할 수 있는 **파일**, 예: `python`, `python.exe`, `uvicorn`\n* 운영체제에서 **실행 중**인 특정 프로그램으로, CPU를 사용하고 메모리에 내용을 저장합니다. 이것을 **프로세스**라고도 합니다.\n\n### 프로세스란 { #what-is-a-process }\n\n**프로세스**라는 단어는 보통 더 구체적으로, 운영체제에서 실행 중인 것(위 마지막 항목처럼)만을 가리키는 데 사용됩니다:\n\n* 운영체제에서 **실행 중**인 특정 프로그램\n    * 파일이나 코드를 의미하는 것이 아니라, 운영체제가 **실제로 실행**하고 관리하는 대상을 **구체적으로** 의미합니다.\n* 어떤 프로그램이든 어떤 코드든, **실행**될 때만 무언가를 **할 수 있습니다**. 즉, **프로세스가 실행 중**일 때입니다.\n* 프로세스는 여러분이, 혹은 운영체제가 **종료**(또는 “kill”)할 수 있습니다. 그러면 실행이 멈추고, 더 이상 **아무것도 할 수 없습니다**.\n* 컴퓨터에서 실행 중인 각 애플리케이션 뒤에는 프로세스가 있습니다. 실행 중인 프로그램, 각 창 등도 마찬가지입니다. 그리고 컴퓨터가 켜져 있는 동안 보통 많은 프로세스가 **동시에** 실행됩니다.\n* **같은 프로그램**의 **여러 프로세스**가 동시에 실행될 수도 있습니다.\n\n운영체제의 “작업 관리자(task manager)”나 “시스템 모니터(system monitor)”(또는 비슷한 도구)를 확인해 보면, 이런 프로세스가 많이 실행 중인 것을 볼 수 있습니다.\n\n또 예를 들어, 같은 브라우저 프로그램(Firefox, Chrome, Edge 등)을 실행하는 프로세스가 여러 개 있는 것도 보일 가능성이 큽니다. 보통 탭마다 하나의 프로세스를 실행하고, 그 외에도 추가 프로세스 몇 개가 더 있습니다.\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\n이제 **프로세스**와 **프로그램**의 차이를 알았으니, 배포에 대한 이야기를 계속해 보겠습니다.\n\n## 시작 시 실행 { #running-on-startup }\n\n대부분의 경우 웹 API를 만들면, 클라이언트가 언제나 접근할 수 있도록 **항상 실행**되고 중단되지 않기를 원합니다. 물론 특정 상황에서만 실행하고 싶은 특별한 이유가 있을 수는 있지만, 대부분은 지속적으로 실행되며 **사용 가능**한 상태이기를 원합니다.\n\n### 원격 서버에서 { #in-a-remote-server }\n\n원격 서버(클라우드 서버, 가상 머신 등)를 설정할 때, 가장 단순한 방법은 로컬 개발 때처럼 수동으로 `fastapi run`(Uvicorn을 사용합니다)이나 비슷한 명령을 실행하는 것입니다.\n\n이 방식은 동작하고, **개발 중에는** 유용합니다.\n\n하지만 서버에 대한 연결이 끊기면, 실행 중인 **프로세스**도 아마 종료될 것입니다.\n\n또 서버가 재시작되면(예: 업데이트 이후, 혹은 클라우드 제공자의 마이그레이션 이후) 여러분은 아마 **알아차리지 못할** 겁니다. 그 결과, 프로세스를 수동으로 다시 시작해야 한다는 사실도 모르게 됩니다. 그러면 API는 그냥 죽은 상태로 남습니다. 😱\n\n### 시작 시 자동 실행 { #run-automatically-on-startup }\n\n일반적으로 서버 프로그램(예: Uvicorn)은 서버가 시작될 때 자동으로 시작되고, **사람의 개입** 없이도 FastAPI 앱을 실행하는 프로세스가 항상 실행 중이도록(예: FastAPI 앱을 실행하는 Uvicorn) 구성하고 싶을 것입니다.\n\n### 별도의 프로그램 { #separate-program }\n\n이를 위해 보통 애플리케이션이 시작 시 실행되도록 보장하는 **별도의 프로그램**을 둡니다. 그리고 많은 경우, 데이터베이스 같은 다른 컴포넌트나 애플리케이션도 함께 실행되도록 보장합니다.\n\n### 시작 시 실행을 위한 도구 예시 { #example-tools-to-run-at-startup }\n\n이 역할을 할 수 있는 도구 예시는 다음과 같습니다:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Swarm Mode의 Docker\n* Systemd\n* Supervisor\n* 클라우드 제공자가 서비스 일부로 내부적으로 처리\n* 기타...\n\n다음 장에서 더 구체적인 예시를 제공하겠습니다.\n\n## 재시작 { #restarts }\n\n애플리케이션이 시작 시 실행되도록 보장하는 것과 비슷하게, 장애가 발생했을 때 **재시작**되도록 보장하고 싶을 것입니다.\n\n### 우리는 실수합니다 { #we-make-mistakes }\n\n사람은 언제나 **실수**합니다. 소프트웨어에는 거의 *항상* 여기저기에 숨은 **버그**가 있습니다. 🐛\n\n그리고 개발자는 버그를 발견하고 새로운 기능을 구현하면서 코드를 계속 개선합니다(새로운 버그도 추가할 수 있겠죠 😅).\n\n### 작은 오류는 자동으로 처리됨 { #small-errors-automatically-handled }\n\nFastAPI로 웹 API를 만들 때 코드에 오류가 있으면, FastAPI는 보통 그 오류를 발생시킨 단일 요청 안에만 문제를 가둡니다. 🛡\n\n클라이언트는 해당 요청에 대해 **500 Internal Server Error**를 받지만, 애플리케이션은 완전히 크래시하지 않고 다음 요청부터는 계속 동작합니다.\n\n### 더 큰 오류 - 크래시 { #bigger-errors-crashes }\n\n그럼에도 불구하고, 우리가 작성한 코드가 **전체 애플리케이션을 크래시**시켜 Uvicorn과 Python 자체가 종료되는 경우가 있을 수 있습니다. 💥\n\n그래도 한 군데 오류 때문에 애플리케이션이 죽은 채로 남아 있기를 바라지는 않을 것입니다. 망가진 경로 처리를 제외한 나머지 *경로 처리*라도 **계속 실행**되기를 원할 가능성이 큽니다.\n\n### 크래시 후 재시작 { #restart-after-crash }\n\n하지만 실행 중인 **프로세스**가 크래시하는 정말 심각한 오류의 경우에는, 적어도 몇 번은 프로세스를 **재시작**하도록 담당하는 외부 컴포넌트가 필요합니다...\n\n/// tip | 팁\n\n...다만 애플리케이션 전체가 **즉시 계속 크래시**한다면, 무한히 재시작하는 것은 아마 의미가 없을 것입니다. 그런 경우에는 개발 중에, 또는 최소한 배포 직후에 알아차릴 가능성이 큽니다.\n\n그러니 여기서는, 특정한 경우에만 전체가 크래시할 수 있고 **미래**에도 그럴 수 있으며, 그래도 재시작하는 것이 의미 있는 주요 사례에 집중해 봅시다.\n\n///\n\n애플리케이션을 재시작하는 역할은 **외부 컴포넌트**가 맡는 편이 보통 좋습니다. 그 시점에는 Uvicorn과 Python을 포함한 애플리케이션이 이미 크래시했기 때문에, 같은 앱의 같은 코드 안에서 이를 해결할 방법이 없기 때문입니다.\n\n### 자동 재시작을 위한 도구 예시 { #example-tools-to-restart-automatically }\n\n대부분의 경우 **시작 시 실행**에 사용한 도구가 자동 **재시작**도 함께 처리합니다.\n\n예를 들어 다음이 가능합니다:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Swarm Mode의 Docker\n* Systemd\n* Supervisor\n* 클라우드 제공자가 서비스 일부로 내부적으로 처리\n* 기타...\n\n## 복제 - 프로세스와 메모리 { #replication-processes-and-memory }\n\nFastAPI 애플리케이션은 Uvicorn을 실행하는 `fastapi` 명령 같은 서버 프로그램을 사용하면, **하나의 프로세스**로 실행하더라도 여러 클라이언트를 동시에 처리할 수 있습니다.\n\n하지만 많은 경우, 여러 워커 프로세스를 동시에 실행하고 싶을 것입니다.\n\n### 여러 프로세스 - 워커 { #multiple-processes-workers }\n\n단일 프로세스가 처리할 수 있는 것보다 클라이언트가 더 많고(예: 가상 머신이 그리 크지 않을 때), 서버 CPU에 **여러 코어**가 있다면, 같은 애플리케이션을 실행하는 **여러 프로세스**를 동시에 띄우고 요청을 분산시킬 수 있습니다.\n\n같은 API 프로그램을 **여러 프로세스**로 실행할 때, 이 프로세스들을 보통 **workers**라고 부릅니다.\n\n### 워커 프로세스와 포트 { #worker-processes-and-ports }\n\n[HTTPS에 대한 문서](https.md)에서, 서버에서 하나의 포트와 IP 주소 조합에는 하나의 프로세스만 리스닝할 수 있다는 것을 기억하시나요?\n\n이것은 여전히 사실입니다.\n\n따라서 **여러 프로세스**를 동시에 실행하려면, 먼저 **포트에서 리스닝하는 단일 프로세스**가 있어야 하고, 그 프로세스가 어떤 방식으로든 각 워커 프로세스로 통신을 전달해야 합니다.\n\n### 프로세스당 메모리 { #memory-per-process }\n\n이제 프로그램이 메모리에 무언가를 로드한다고 해봅시다. 예를 들어 머신러닝 모델을 변수에 올리거나 큰 파일 내용을 변수에 올리는 경우입니다. 이런 것들은 서버의 **메모리(RAM)**를 어느 정도 사용합니다.\n\n그리고 여러 프로세스는 보통 **메모리를 공유하지 않습니다**. 즉, 각 실행 중인 프로세스는 자체 변수와 메모리를 갖습니다. 코드에서 메모리를 많이 사용한다면, **각 프로세스**가 그만큼의 메모리를 사용하게 됩니다.\n\n### 서버 메모리 { #server-memory }\n\n예를 들어 코드가 크기 **1 GB**의 머신러닝 모델을 로드한다고 해봅시다. API를 프로세스 하나로 실행하면 RAM을 최소 1GB 사용합니다. 그리고 **4개 프로세스**(워커 4개)를 시작하면 각각 1GB RAM을 사용합니다. 즉 총 **4 GB RAM**을 사용합니다.\n\n그런데 원격 서버나 가상 머신의 RAM이 3GB뿐이라면, 4GB를 넘게 로드하려고 할 때 문제가 생깁니다. 🚨\n\n### 여러 프로세스 - 예시 { #multiple-processes-an-example }\n\n이 예시에서는 **Manager Process**가 두 개의 **Worker Processes**를 시작하고 제어합니다.\n\n이 Manager Process는 아마 IP의 **포트**에서 리스닝하는 역할을 합니다. 그리고 모든 통신을 워커 프로세스로 전달합니다.\n\n워커 프로세스들이 실제로 애플리케이션을 실행하며, **요청**을 받아 **응답**을 반환하는 주요 연산을 수행하고, RAM에 변수로 로드한 모든 내용을 담습니다.\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\n그리고 물론 같은 머신에는 애플리케이션 외에도 **다른 프로세스**들이 실행 중일 가능성이 큽니다.\n\n흥미로운 점은 각 프로세스의 **CPU 사용률**은 시간에 따라 크게 **변동**할 수 있지만, **메모리(RAM)**는 보통 대체로 **안정적**으로 유지된다는 것입니다.\n\n매번 비슷한 양의 연산을 수행하는 API이고 클라이언트가 많다면, **CPU 사용률**도 (급격히 오르내리기보다는) *안정적일* 가능성이 큽니다.\n\n### 복제 도구와 전략 예시 { #examples-of-replication-tools-and-strategies }\n\n이를 달성하는 접근 방식은 여러 가지가 있을 수 있으며, 다음 장들에서 Docker와 컨테이너를 설명할 때 구체적인 전략을 더 알려드리겠습니다.\n\n고려해야 할 주요 제약은 **공개 IP**의 **포트**를 처리하는 **단일** 컴포넌트가 있어야 한다는 점입니다. 그리고 그 컴포넌트는 복제된 **프로세스/워커**로 통신을 **전달**할 방법이 있어야 합니다.\n\n가능한 조합과 전략 몇 가지는 다음과 같습니다:\n\n* `--workers` 옵션을 사용한 **Uvicorn**\n    * 하나의 Uvicorn **프로세스 매니저**가 **IP**와 **포트**에서 리스닝하고, **여러 Uvicorn 워커 프로세스**를 시작합니다.\n* **Kubernetes** 및 기타 분산 **컨테이너 시스템**\n    * **Kubernetes** 레이어의 무언가가 **IP**와 **포트**에서 리스닝합니다. 그리고 **여러 컨테이너**를 두어 복제하며, 각 컨테이너에는 **하나의 Uvicorn 프로세스**가 실행됩니다.\n* 이를 대신 처리해주는 **클라우드 서비스**\n    * 클라우드 서비스가 **복제를 대신 처리**해줄 가능성이 큽니다. 실행할 **프로세스**나 사용할 **컨테이너 이미지**를 정의하게 해줄 수도 있지만, 어떤 경우든 대개 **단일 Uvicorn 프로세스**를 기준으로 하고, 클라우드 서비스가 이를 복제하는 역할을 맡습니다.\n\n/// tip | 팁\n\n**컨테이너**, Docker, Kubernetes에 대한 일부 내용이 아직은 잘 이해되지 않아도 괜찮습니다.\n\n다음 장에서 컨테이너 이미지, Docker, Kubernetes 등을 더 설명하겠습니다: [컨테이너에서 FastAPI - Docker](docker.md).\n\n///\n\n## 시작 전 사전 단계 { #previous-steps-before-starting }\n\n애플리케이션을 **시작하기 전에** 어떤 단계를 수행하고 싶은 경우가 많습니다.\n\n예를 들어 **데이터베이스 마이그레이션**을 실행하고 싶을 수 있습니다.\n\n하지만 대부분의 경우, 이런 단계는 **한 번만** 수행하고 싶을 것입니다.\n\n그래서 애플리케이션을 시작하기 전에 그 **사전 단계**를 수행할 **단일 프로세스**를 두고 싶을 것입니다.\n\n또한 이후에 애플리케이션 자체를 **여러 프로세스**(여러 워커)로 시작하더라도, 사전 단계를 수행하는 프로세스는 *반드시* 하나만 실행되도록 해야 합니다. 만약 사전 단계를 **여러 프로세스**가 수행하면, **병렬로** 실행하면서 작업이 **중복**될 수 있습니다. 그리고 데이터베이스 마이그레이션처럼 민감한 작업이라면 서로 충돌을 일으킬 수 있습니다.\n\n물론 사전 단계를 여러 번 실행해도 문제가 없는 경우도 있습니다. 그런 경우에는 처리하기가 훨씬 쉽습니다.\n\n/// tip | 팁\n\n또한 설정에 따라, 어떤 경우에는 애플리케이션을 시작하기 전에 **사전 단계가 전혀 필요 없을** 수도 있다는 점을 기억하세요.\n\n그런 경우에는 이런 것들을 전혀 걱정할 필요가 없습니다. 🤷\n\n///\n\n### 사전 단계 전략 예시 { #examples-of-previous-steps-strategies }\n\n이는 여러분이 **시스템을 배포하는 방식**에 크게 좌우되며, 프로그램을 시작하는 방식, 재시작 처리 방식 등과도 연결되어 있을 가능성이 큽니다.\n\n가능한 아이디어는 다음과 같습니다:\n\n* 앱 컨테이너보다 먼저 실행되는 Kubernetes의 “Init Container”\n* 사전 단계를 실행한 다음 애플리케이션을 시작하는 bash 스크립트\n    * 이 bash 스크립트를 시작/재시작하고, 오류를 감지하는 등의 방법도 여전히 필요합니다.\n\n/// tip | 팁\n\n컨테이너로 이를 처리하는 더 구체적인 예시는 다음 장에서 제공하겠습니다: [컨테이너에서 FastAPI - Docker](docker.md).\n\n///\n\n## 리소스 활용 { #resource-utilization }\n\n서버는 여러분이 프로그램으로 소비하거나 **활용(utilize)**할 수 있는 **리소스**입니다. CPU의 계산 시간과 사용 가능한 RAM 메모리가 대표적입니다.\n\n시스템 리소스를 얼마나 소비/활용하고 싶으신가요? “많지 않게”라고 생각하기 쉽지만, 실제로는 **크래시하지 않는 선에서 가능한 한 많이** 사용하고 싶을 가능성이 큽니다.\n\n서버 3대를 비용을 내고 쓰고 있는데 RAM과 CPU를 조금만 사용한다면, 아마 **돈을 낭비**하고 💸, **서버 전력도 낭비**하고 🌎, 기타 등등이 될 수 있습니다.\n\n그 경우에는 서버를 2대만 두고, 각 서버의 리소스(CPU, 메모리, 디스크, 네트워크 대역폭 등)를 더 높은 비율로 사용하는 것이 더 나을 수 있습니다.\n\n반대로 서버 2대를 두고 CPU와 RAM을 **100%** 사용하고 있다면, 어느 시점에 프로세스 하나가 더 많은 메모리를 요청하게 되고, 서버는 디스크를 “메모리”처럼 사용해야 할 수도 있습니다(수천 배 느릴 수 있습니다). 또는 심지어 **크래시**할 수도 있습니다. 혹은 어떤 프로세스가 계산을 해야 하는데 CPU가 다시 비워질 때까지 기다려야 할 수도 있습니다.\n\n이 경우에는 **서버 한 대를 추가**로 확보하고 일부 프로세스를 그쪽에서 실행해, 모두가 **충분한 RAM과 CPU 시간**을 갖도록 하는 편이 더 낫습니다.\n\n또 어떤 이유로 API 사용량이 **급증(spike)**할 가능성도 있습니다. 바이럴이 되었거나, 다른 서비스나 봇이 사용하기 시작했을 수도 있습니다. 그런 경우를 대비해 추가 리소스를 확보해두고 싶을 수 있습니다.\n\n리소스 활용률 목표로 **임의의 수치**를 정할 수 있습니다. 예를 들어 **50%에서 90% 사이**처럼요. 요점은, 이런 것들이 배포를 조정할 때 측정하고 튜닝하는 주요 지표가 될 가능성이 크다는 것입니다.\n\n`htop` 같은 간단한 도구로 서버의 CPU와 RAM 사용량, 또는 각 프로세스별 사용량을 볼 수 있습니다. 혹은 서버 여러 대에 분산될 수도 있는 더 복잡한 모니터링 도구를 사용할 수도 있습니다.\n\n## 요약 { #recap }\n\n여기까지 애플리케이션 배포 방식을 결정할 때 염두에 두어야 할 주요 개념들을 읽었습니다:\n\n* 보안 - HTTPS\n* 시작 시 실행\n* 재시작\n* 복제(실행 중인 프로세스 수)\n* 메모리\n* 시작 전 사전 단계\n\n이 아이디어들을 이해하고 적용하는 방법을 알면, 배포를 구성하고 조정할 때 필요한 직관을 얻는 데 도움이 될 것입니다. 🤓\n\n다음 섹션에서는 따라 할 수 있는 가능한 전략의 더 구체적인 예시를 제공하겠습니다. 🚀\n"
  },
  {
    "path": "docs/ko/docs/deployment/docker.md",
    "content": "# 컨테이너의 FastAPI - 도커 { #fastapi-in-containers-docker }\n\nFastAPI 애플리케이션을 배포할 때 일반적인 접근 방법은 **리눅스 컨테이너 이미지**를 빌드하는 것입니다. 보통 [**Docker**](https://www.docker.com/)를 사용해 수행합니다. 그런 다음 해당 컨테이너 이미지를 몇 가지 가능한 방법 중 하나로 배포할 수 있습니다.\n\n리눅스 컨테이너를 사용하면 **보안**, **재현 가능성**, **단순함** 등 여러 장점이 있습니다.\n\n/// tip | 팁\n\n시간이 없고 이미 이런 내용들을 알고 계신가요? 아래의 [`Dockerfile` 👇](#build-a-docker-image-for-fastapi)로 이동하세요.\n\n///\n\n<details>\n<summary>Dockerfile Preview 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# If running behind a proxy like Nginx or Traefik add --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## 컨테이너란 { #what-is-a-container }\n\n컨테이너(주로 리눅스 컨테이너)는 모든 의존성과 필요한 파일을 포함해 애플리케이션을 패키징하면서, 같은 시스템의 다른 컨테이너(다른 애플리케이션이나 컴포넌트)와는 분리된 상태로 유지할 수 있는 매우 **가벼운** 방법입니다.\n\n리눅스 컨테이너는 호스트(머신, 가상 머신, 클라우드 서버 등)와 같은 리눅스 커널을 사용해 실행됩니다. 즉, 전체 운영체제를 에뮬레이션하는 완전한 가상 머신에 비해 매우 가볍습니다.\n\n이 방식으로 컨테이너는 프로세스를 직접 실행하는 것과 비슷한 수준의 **적은 자원**을 소비합니다(가상 머신은 훨씬 더 많은 자원을 소비합니다).\n\n또한 컨테이너는 자체적인 **격리된** 실행 프로세스(보통 하나의 프로세스), 파일 시스템, 네트워크를 가지므로 배포, 보안, 개발 등을 단순화합니다.\n\n## 컨테이너 이미지란 { #what-is-a-container-image }\n\n**컨테이너**는 **컨테이너 이미지**에서 실행됩니다.\n\n컨테이너 이미지는 컨테이너에 있어야 하는 모든 파일, 환경 변수, 기본 명령/프로그램의 **정적** 버전입니다. 여기서 **정적**이라는 것은 컨테이너 **이미지**가 실행 중이거나 수행되는 것이 아니라, 패키징된 파일과 메타데이터일 뿐이라는 뜻입니다.\n\n저장된 정적 콘텐츠인 \"**컨테이너 이미지**\"와 달리, \"**컨테이너**\"는 보통 실행 중인 인스턴스, 즉 **실행되는** 대상을 의미합니다.\n\n**컨테이너**가 시작되어 실행 중이면(**컨테이너 이미지**로부터 시작됨) 파일, 환경 변수 등을 생성하거나 변경할 수 있습니다. 이러한 변경은 해당 컨테이너에만 존재하며, 기반이 되는 컨테이너 이미지에는 지속되지 않습니다(디스크에 저장되지 않습니다).\n\n컨테이너 이미지는 **프로그램** 파일과 그 콘텐츠, 예를 들어 `python`과 어떤 파일 `main.py`에 비유할 수 있습니다.\n\n그리고 **컨테이너** 자체는(**컨테이너 이미지**와 달리) 이미지의 실제 실행 인스턴스로서 **프로세스**에 비유할 수 있습니다. 실제로 컨테이너는 **실행 중인 프로세스**가 있을 때만 실행됩니다(보통 단일 프로세스입니다). 컨테이너 내부에 실행 중인 프로세스가 없으면 컨테이너는 중지됩니다.\n\n## 컨테이너 이미지 { #container-images }\n\nDocker는 **컨테이너 이미지**와 **컨테이너**를 생성하고 관리하는 주요 도구 중 하나입니다.\n\n또한 [Docker Hub](https://hub.docker.com/)에는 다양한 도구, 환경, 데이터베이스, 애플리케이션을 위한 미리 만들어진 **공식 컨테이너 이미지**가 공개되어 있습니다.\n\n예를 들어, 공식 [Python Image](https://hub.docker.com/_/python)가 있습니다.\n\n그리고 데이터베이스 등 다양한 용도의 다른 이미지도 많이 있습니다. 예를 들면:\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis) 등\n\n미리 만들어진 컨테이너 이미지를 사용하면 서로 다른 도구를 **결합**하고 사용하기가 매우 쉽습니다. 예를 들어 새로운 데이터베이스를 시험해 볼 때도 그렇습니다. 대부분의 경우 **공식 이미지**를 사용하고, 환경 변수로 설정만 하면 됩니다.\n\n이렇게 하면 많은 경우 컨테이너와 Docker를 학습하고, 그 지식을 여러 다른 도구와 컴포넌트에 재사용할 수 있습니다.\n\n따라서 데이터베이스, Python 애플리케이션, React 프론트엔드 애플리케이션이 있는 웹 서버 등 서로 다른 것들을 담은 **여러 컨테이너**를 실행하고 내부 네트워크를 통해 연결할 수 있습니다.\n\nDocker나 Kubernetes 같은 모든 컨테이너 관리 시스템에는 이러한 네트워킹 기능이 통합되어 있습니다.\n\n## 컨테이너와 프로세스 { #containers-and-processes }\n\n**컨테이너 이미지**는 보통 **컨테이너**가 시작될 때 실행되어야 하는 기본 프로그램/명령과 해당 프로그램에 전달할 매개변수를 메타데이터에 포함합니다. 커맨드 라인에서 실행할 때와 매우 유사합니다.\n\n**컨테이너**가 시작되면 해당 명령/프로그램을 실행합니다(다만 오버라이드하여 다른 명령/프로그램을 실행하게 할 수도 있습니다).\n\n컨테이너는 **메인 프로세스**(명령 또는 프로그램)가 실행되는 동안 실행됩니다.\n\n컨테이너는 보통 **단일 프로세스**를 가지지만, 메인 프로세스에서 서브프로세스를 시작할 수도 있으며, 그러면 같은 컨테이너에 **여러 프로세스**가 존재하게 됩니다.\n\n하지만 **최소 하나의 실행 중인 프로세스** 없이 실행 중인 컨테이너를 가질 수는 없습니다. 메인 프로세스가 중지되면 컨테이너도 중지됩니다.\n\n## FastAPI를 위한 도커 이미지 빌드하기 { #build-a-docker-image-for-fastapi }\n\n좋습니다, 이제 무언가를 만들어 봅시다! 🚀\n\n**공식 Python** 이미지에 기반하여 FastAPI용 **Docker 이미지**를 **처음부터** 빌드하는 방법을 보여드리겠습니다.\n\n이는 **대부분의 경우**에 하고 싶은 방식입니다. 예를 들면:\n\n* **Kubernetes** 또는 유사한 도구를 사용할 때\n* **Raspberry Pi**에서 실행할 때\n* 컨테이너 이미지를 대신 실행해주는 클라우드 서비스를 사용할 때 등\n\n### 패키지 요구사항 { #package-requirements }\n\n보통 애플리케이션의 **패키지 요구사항**을 어떤 파일에 적어 둡니다.\n\n이는 주로 그 요구사항을 **설치**하는 데 사용하는 도구에 따라 달라집니다.\n\n가장 일반적인 방법은 패키지 이름과 버전을 한 줄에 하나씩 적어 둔 `requirements.txt` 파일을 사용하는 것입니다.\n\n버전 범위를 설정할 때는 [FastAPI 버전들에 대하여](versions.md)에서 읽은 것과 같은 아이디어를 사용하면 됩니다.\n\n예를 들어 `requirements.txt`는 다음과 같을 수 있습니다:\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\n그리고 보통 `pip`로 패키지 의존성을 설치합니다. 예를 들면:\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info | 정보\n\n패키지 의존성을 정의하고 설치하는 다른 형식과 도구도 있습니다.\n\n///\n\n### **FastAPI** 코드 생성하기 { #create-the-fastapi-code }\n\n* `app` 디렉터리를 만들고 들어갑니다.\n* 빈 파일 `__init__.py`를 만듭니다.\n* 다음 내용으로 `main.py` 파일을 만듭니다:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\n이제 같은 프로젝트 디렉터리에 다음 내용으로 `Dockerfile` 파일을 만듭니다:\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. 공식 Python 베이스 이미지에서 시작합니다.\n\n2. 현재 작업 디렉터리를 `/code`로 설정합니다.\n\n    여기에 `requirements.txt` 파일과 `app` 디렉터리를 둘 것입니다.\n\n3. 요구사항 파일을 `/code` 디렉터리로 복사합니다.\n\n    처음에는 요구사항 파일만 **단독으로** 복사하고, 나머지 코드는 복사하지 않습니다.\n\n    이 파일은 **자주 바뀌지 않기** 때문에 Docker는 이를 감지하여 이 단계에서 **캐시**를 사용하고, 다음 단계에서도 캐시를 사용할 수 있게 해줍니다.\n\n4. 요구사항 파일에 있는 패키지 의존성을 설치합니다.\n\n    `--no-cache-dir` 옵션은 `pip`가 다운로드한 패키지를 로컬에 저장하지 않도록 합니다. 이는 `pip`가 같은 패키지를 설치하기 위해 다시 실행될 때만 의미가 있지만, 컨테이너 작업에서는 그렇지 않기 때문입니다.\n\n    /// note | 참고\n\n    `--no-cache-dir`는 `pip`에만 관련되어 있으며 Docker나 컨테이너와는 관련이 없습니다.\n\n    ///\n\n    `--upgrade` 옵션은 이미 설치된 패키지가 있다면 `pip`가 이를 업그레이드하도록 합니다.\n\n    이전 단계에서 파일을 복사한 것이 **Docker 캐시**에 의해 감지될 수 있으므로, 이 단계에서도 가능하면 **Docker 캐시를 사용**합니다.\n\n    이 단계에서 캐시를 사용하면 개발 중에 이미지를 반복해서 빌드할 때, 의존성을 **매번 다운로드하고 설치하는** 대신 많은 **시간**을 **절약**할 수 있습니다.\n\n5. `./app` 디렉터리를 `/code` 디렉터리 안으로 복사합니다.\n\n    이 디렉터리에는 **가장 자주 변경되는** 코드가 모두 포함되어 있으므로, Docker **캐시**는 이 단계나 **이후 단계들**에서는 쉽게 사용되지 않습니다.\n\n    따라서 컨테이너 이미지 빌드 시간을 최적화하려면 `Dockerfile`의 **끝부분 근처**에 두는 것이 중요합니다.\n\n6. 내부적으로 Uvicorn을 사용하는 `fastapi run`을 사용하도록 **명령**을 설정합니다.\n\n    `CMD`는 문자열 리스트를 받으며, 각 문자열은 커맨드 라인에서 공백으로 구분해 입력하는 항목들입니다.\n\n    이 명령은 **현재 작업 디렉터리**에서 실행되며, 이는 위에서 `WORKDIR /code`로 설정한 `/code` 디렉터리와 같습니다.\n\n/// tip | 팁\n\n코드의 각 숫자 버블을 클릭해 각 줄이 하는 일을 확인하세요. 👆\n\n///\n\n/// warning | 경고\n\n아래에서 설명하는 것처럼 `CMD` 지시어는 **항상** **exec form**을 사용해야 합니다.\n\n///\n\n#### `CMD` 사용하기 - Exec Form { #use-cmd-exec-form }\n\nDocker 지시어 [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd)는 두 가지 형식으로 작성할 수 있습니다:\n\n✅ **Exec** form:\n\n```Dockerfile\n# ✅ 이렇게 하세요\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ **Shell** form:\n\n```Dockerfile\n# ⛔️ 이렇게 하지 마세요\nCMD fastapi run app/main.py --port 80\n```\n\nFastAPI가 정상적으로 종료(graceful shutdown)되고 [lifespan 이벤트](../advanced/events.md)가 트리거되도록 하려면, 항상 **exec** form을 사용하세요.\n\n자세한 내용은 [shell and exec form에 대한 Docker 문서](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form)를 참고하세요.\n\n이는 `docker compose`를 사용할 때 꽤 눈에 띌 수 있습니다. 좀 더 기술적인 상세 내용은 Docker Compose FAQ 섹션을 참고하세요: [Why do my services take 10 seconds to recreate or stop?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).\n\n#### 디렉터리 구조 { #directory-structure }\n\n이제 다음과 같은 디렉터리 구조가 되어야 합니다:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### TLS 종료 프록시의 배후 { #behind-a-tls-termination-proxy }\n\nNginx나 Traefik 같은 TLS 종료 프록시(로드 밸런서) 뒤에서 컨테이너를 실행하고 있다면 `--proxy-headers` 옵션을 추가하세요. 이 옵션은 (FastAPI CLI를 통해) Uvicorn에게 해당 프록시가 보낸 헤더를 신뢰하도록 하여, 애플리케이션이 HTTPS 뒤에서 실행 중임을 알게 합니다.\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### 도커 캐시 { #docker-cache }\n\n이 `Dockerfile`에는 중요한 트릭이 있습니다. 먼저 **의존성 파일만** 복사하고, 나머지 코드는 복사하지 않는 것입니다. 왜 그런지 설명하겠습니다.\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker와 다른 도구들은 `Dockerfile`의 위에서부터 시작해, 각 지시어가 만든 파일을 포함하며 **레이어를 하나씩 위에 쌓는 방식으로** 컨테이너 이미지를 **점진적으로** 빌드합니다.\n\nDocker와 유사한 도구들은 이미지를 빌드할 때 **내부 캐시**도 사용합니다. 어떤 파일이 마지막으로 컨테이너 이미지를 빌드했을 때부터 바뀌지 않았다면, 파일을 다시 복사하고 새 레이어를 처음부터 만드는 대신, 이전에 만든 **같은 레이어를 재사용**합니다.\n\n파일 복사를 피하는 것만으로 큰 개선이 생기지는 않을 수 있지만, 해당 단계에서 캐시를 사용했기 때문에 **다음 단계에서도 캐시를 사용할 수** 있습니다. 예를 들어 다음과 같이 의존성을 설치하는 지시어에서 캐시를 사용할 수 있습니다:\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\n패키지 요구사항 파일은 **자주 변경되지 않습니다**. 따라서 그 파일만 복사하면 Docker는 그 단계에서 **캐시를 사용할 수** 있습니다.\n\n그리고 Docker는 그 다음 단계에서 의존성을 다운로드하고 설치할 때도 **캐시를 사용할 수** 있습니다. 바로 여기에서 **많은 시간을 절약**하게 됩니다. ✨ ...그리고 기다리며 지루해지는 것도 피할 수 있습니다. 😪😆\n\n패키지 의존성을 다운로드하고 설치하는 데에는 **몇 분**이 걸릴 수 있지만, **캐시**를 사용하면 많아야 **몇 초**면 끝납니다.\n\n또한 개발 중에 코드 변경 사항이 동작하는지 확인하기 위해 컨테이너 이미지를 계속 빌드하게 되므로, 이렇게 절약되는 시간은 누중되어 상당히 커집니다.\n\n그 다음 `Dockerfile`의 끝부분 근처에서 모든 코드를 복사합니다. 이 부분은 **가장 자주 변경되는** 부분이므로, 거의 항상 이 단계 이후에는 캐시를 사용할 수 없기 때문에 끝부분에 둡니다.\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### 도커 이미지 생성하기 { #build-the-docker-image }\n\n이제 모든 파일이 제자리에 있으니 컨테이너 이미지를 빌드해봅시다.\n\n* 프로젝트 디렉터리로 이동합니다(`Dockerfile`이 있고 `app` 디렉터리를 포함하는 위치).\n* FastAPI 이미지를 빌드합니다:\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | 팁\n\n끝에 있는 `.`에 주목하세요. 이는 `./`와 동일하며, Docker에게 컨테이너 이미지를 빌드할 때 사용할 디렉터리를 알려줍니다.\n\n이 경우 현재 디렉터리(`.`)입니다.\n\n///\n\n### 도커 컨테이너 시작하기 { #start-the-docker-container }\n\n* 여러분의 이미지에 기반하여 컨테이너를 실행합니다:\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## 확인하기 { #check-it }\n\nDocker 컨테이너의 URL에서 확인할 수 있어야 합니다. 예를 들어: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) 또는 [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery)(또는 Docker 호스트를 사용해 동등하게 확인할 수 있습니다).\n\n아래와 같은 것을 보게 될 것입니다:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## 인터랙티브 API 문서 { #interactive-api-docs }\n\n이제 [http://192.168.99.100/docs](http://192.168.99.100/docs) 또는 [http://127.0.0.1/docs](http://127.0.0.1/docs)(또는 Docker 호스트를 사용해 동등하게 접근)로 이동할 수 있습니다.\n\n자동으로 생성된 인터랙티브 API 문서([Swagger UI](https://github.com/swagger-api/swagger-ui) 제공)를 볼 수 있습니다:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## 대안 API 문서 { #alternative-api-docs }\n\n또한 [http://192.168.99.100/redoc](http://192.168.99.100/redoc) 또는 [http://127.0.0.1/redoc](http://127.0.0.1/redoc)(또는 Docker 호스트를 사용해 동등하게 접근)로 이동할 수도 있습니다.\n\n대안 자동 문서([ReDoc](https://github.com/Rebilly/ReDoc) 제공)를 볼 수 있습니다:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## 단일 파일 FastAPI로 도커 이미지 빌드하기 { #build-a-docker-image-with-a-single-file-fastapi }\n\nFastAPI가 단일 파일(예: `./app` 디렉터리 없이 `main.py`만 있는 경우)이라면, 파일 구조는 다음과 같을 수 있습니다:\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\n그런 다음 `Dockerfile`에서 해당 파일을 복사하도록 경로만 맞게 변경하면 됩니다:\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. `main.py` 파일을 `/code` 디렉터리로 직접 복사합니다(`./app` 디렉터리 없이).\n\n2. 단일 파일 `main.py`에 있는 애플리케이션을 제공(serve)하기 위해 `fastapi run`을 사용합니다.\n\n`fastapi run`에 파일을 전달하면, 이것이 패키지의 일부가 아닌 단일 파일이라는 것을 자동으로 감지하고, 어떻게 임포트해서 FastAPI 앱을 제공할지 알아냅니다. 😎\n\n## 배포 개념 { #deployment-concepts }\n\n컨테이너 관점에서 같은 [배포 개념](concepts.md)들을 다시 이야기해 봅시다.\n\n컨테이너는 주로 애플리케이션의 **빌드 및 배포** 과정을 단순화하는 도구이지만, 이러한 **배포 개념**을 처리하는 특정 접근 방식을 강제하지는 않으며, 가능한 전략은 여러 가지입니다.\n\n**좋은 소식**은 각 전략마다 모든 배포 개념을 다룰 수 있는 방법이 있다는 점입니다. 🎉\n\n컨테이너 관점에서 이 **배포 개념**들을 살펴봅시다:\n\n* HTTPS\n* 시작 시 자동 실행\n* 재시작\n* 복제(실행 중인 프로세스 수)\n* 메모리\n* 시작 전 사전 단계\n\n## HTTPS { #https }\n\nFastAPI 애플리케이션의 **컨테이너 이미지**(그리고 나중에 실행 중인 **컨테이너**)에만 집중한다면, HTTPS는 보통 다른 도구에 의해 **외부적으로** 처리됩니다.\n\n예를 들어 [Traefik](https://traefik.io/)을 사용하는 다른 컨테이너가 **HTTPS**와 **인증서**의 **자동** 획득을 처리할 수 있습니다.\n\n/// tip | 팁\n\nTraefik은 Docker, Kubernetes 등과 통합되어 있어, 이를 사용해 컨테이너에 HTTPS를 설정하고 구성하기가 매우 쉽습니다.\n\n///\n\n또는 HTTPS를 클라우드 제공자가 서비스의 일부로 처리할 수도 있습니다(애플리케이션은 여전히 컨테이너에서 실행됩니다).\n\n## 시작 시 자동 실행과 재시작 { #running-on-startup-and-restarts }\n\n보통 컨테이너를 **시작하고 실행**하는 역할을 담당하는 다른 도구가 있습니다.\n\n직접 **Docker**일 수도 있고, **Docker Compose**, **Kubernetes**, **클라우드 서비스** 등일 수도 있습니다.\n\n대부분(또는 전부)의 경우, 시작 시 컨테이너를 실행하고 실패 시 재시작을 활성화하는 간단한 옵션이 있습니다. 예를 들어 Docker에서는 커맨드 라인 옵션 `--restart`입니다.\n\n컨테이너를 사용하지 않으면 애플리케이션을 시작 시 자동 실행하고 재시작까지 구성하는 것이 번거롭고 어렵습니다. 하지만 **컨테이너로 작업할 때**는 대부분의 경우 그 기능이 기본으로 포함되어 있습니다. ✨\n\n## 복제 - 프로세스 개수 { #replication-number-of-processes }\n\n**Kubernetes**, Docker Swarm Mode, Nomad 등의 복잡한 시스템으로 여러 머신에 분산된 컨테이너를 관리하는 <dfn title=\"어떤 방식으로 연결되어 함께 동작하도록 구성된 머신의 그룹\">클러스터</dfn>를 사용한다면, 각 컨테이너에서(**워커를 사용하는 Uvicorn** 같은) **프로세스 매니저**를 쓰는 대신, **클러스터 레벨**에서 **복제를 처리**하고 싶을 가능성이 큽니다.\n\nKubernetes 같은 분산 컨테이너 관리 시스템은 보통 들어오는 요청에 대한 **로드 밸런싱**을 지원하면서도, **컨테이너 복제**를 처리하는 통합된 방법을 가지고 있습니다. 모두 **클러스터 레벨**에서요.\n\n그런 경우에는 [위에서 설명한 대로](#dockerfile) 의존성을 설치하고, 여러 Uvicorn 워커를 사용하는 대신 **단일 Uvicorn 프로세스**를 실행하는 **처음부터 만든 Docker 이미지**를 사용하는 것이 좋을 것입니다.\n\n### 로드 밸런서 { #load-balancer }\n\n컨테이너를 사용할 때는 보통 **메인 포트에서 대기(listening)하는** 컴포넌트가 있습니다. **HTTPS**를 처리하기 위한 **TLS 종료 프록시** 역할을 하는 다른 컨테이너일 수도 있고, 유사한 도구일 수도 있습니다.\n\n이 컴포넌트가 요청의 **부하(load)**를 받아 워커들에 (가능하면) **균형 있게** 분산한다면, 보통 **로드 밸런서**라고 부릅니다.\n\n/// tip | 팁\n\nHTTPS에 사용되는 동일한 **TLS 종료 프록시** 컴포넌트가 **로드 밸런서**이기도 한 경우가 많습니다.\n\n///\n\n또한 컨테이너로 작업할 때, 이를 시작하고 관리하는 시스템은 이미 해당 **로드 밸런서**(또는 **TLS 종료 프록시**)에서 여러분의 앱이 있는 컨테이너로 **네트워크 통신**(예: HTTP 요청)을 전달하는 내부 도구를 가지고 있습니다.\n\n### 하나의 로드 밸런서 - 여러 워커 컨테이너 { #one-load-balancer-multiple-worker-containers }\n\n**Kubernetes** 같은 분산 컨테이너 관리 시스템에서는 내부 네트워킹 메커니즘을 통해, 메인 **포트**에서 대기하는 단일 **로드 밸런서**가 여러분의 앱을 실행하는 **여러 컨테이너**로 통신(요청)을 전달할 수 있습니다.\n\n앱을 실행하는 각 컨테이너는 보통 **프로세스 하나만** 가집니다(예: FastAPI 애플리케이션을 실행하는 Uvicorn 프로세스). 모두 같은 것을 실행하는 **동일한 컨테이너**이지만, 각자 고유한 프로세스, 메모리 등을 가집니다. 이렇게 하면 CPU의 **서로 다른 코어** 또는 **서로 다른 머신**에서 **병렬화**의 이점을 얻을 수 있습니다.\n\n그리고 **로드 밸런서**가 있는 분산 컨테이너 시스템은 여러분의 앱을 실행하는 각 컨테이너에 **번갈아가며** 요청을 **분산**합니다. 따라서 각 요청은 여러분의 앱을 실행하는 여러 **복제된 컨테이너** 중 하나에서 처리될 수 있습니다.\n\n또한 보통 이 **로드 밸런서**는 클러스터 내 *다른* 앱으로 가는 요청(예: 다른 도메인, 또는 다른 URL 경로 접두사 아래로 가는 요청)도 처리할 수 있으며, 그 통신을 클러스터에서 실행 중인 *그 다른* 애플리케이션의 올바른 컨테이너로 전달할 수 있습니다.\n\n### 컨테이너당 하나의 프로세스 { #one-process-per-container }\n\n이 시나리오에서는 이미 클러스터 레벨에서 복제를 처리하고 있으므로, **컨테이너당 단일 (Uvicorn) 프로세스**를 두는 것이 좋을 가능성이 큽니다.\n\n따라서 이 경우 컨테이너에서 `--workers` 커맨드 라인 옵션 같은 방식으로 여러 워커를 두고 싶지는 **않을** 것입니다. 컨테이너당 **단일 Uvicorn 프로세스**만 두고(하지만 컨테이너는 여러 개일 수 있습니다) 싶을 것입니다.\n\n컨테이너 내부에 (여러 워커를 위한) 또 다른 프로세스 매니저를 두는 것은, 이미 클러스터 시스템에서 처리하고 있는 **불필요한 복잡성**만 추가할 가능성이 큽니다.\n\n### 여러 프로세스를 가진 컨테이너와 특수한 경우 { #containers-with-multiple-processes-and-special-cases }\n\n물론 컨테이너 하나에 여러 **Uvicorn 워커 프로세스**를 두고 싶을 수 있는 **특수한 경우**도 있습니다.\n\n그런 경우에는 `--workers` 커맨드 라인 옵션을 사용해 실행할 워커 수를 설정할 수 있습니다:\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. 여기서는 `--workers` 커맨드 라인 옵션으로 워커 수를 4로 설정합니다.\n\n이런 방식이 의미가 있을 수 있는 예시는 다음과 같습니다:\n\n#### 단순한 앱 { #a-simple-app }\n\n애플리케이션이 **충분히 단순**해서 클러스터가 아닌 **단일 서버**에서 실행할 수 있다면, 컨테이너에 프로세스 매니저를 두고 싶을 수 있습니다.\n\n#### Docker Compose { #docker-compose }\n\n**Docker Compose**로 클러스터가 아닌 **단일 서버**에 배포하는 경우, 공유 네트워크와 **로드 밸런싱**을 유지하면서(Docker Compose로) 컨테이너 복제를 관리하는 쉬운 방법이 없을 수 있습니다.\n\n그렇다면 **프로세스 매니저**가 컨테이너 내부에서 **여러 워커 프로세스**를 시작하는 **단일 컨테이너**를 원할 수 있습니다.\n\n---\n\n핵심은, 이것들 중 **어느 것도** 무조건 따라야 하는 **절대적인 규칙**은 아니라는 것입니다. 이 아이디어들을 사용해 **여러분의 사용 사례를 평가**하고, 여러분의 시스템에 가장 적합한 접근 방식을 결정하면서 다음 개념을 어떻게 관리할지 확인할 수 있습니다:\n\n* 보안 - HTTPS\n* 시작 시 자동 실행\n* 재시작\n* 복제(실행 중인 프로세스 수)\n* 메모리\n* 시작 전 사전 단계\n\n## 메모리 { #memory }\n\n**컨테이너당 단일 프로세스**를 실행하면, 각 컨테이너(복제된 경우 여러 개)마다 소비하는 메모리 양이 대체로 잘 정의되고 안정적이며 제한된 값이 됩니다.\n\n그런 다음 컨테이너 관리 시스템(예: **Kubernetes**) 설정에서 동일하게 메모리 제한과 요구사항을 설정할 수 있습니다. 그러면 클러스터에서 사용 가능한 머신에 있는 메모리와 컨테이너가 필요로 하는 메모리 양을 고려해 **컨테이너를 복제**할 수 있습니다.\n\n애플리케이션이 **단순**하다면 이는 아마도 **문제가 되지 않을** 것이고, 엄격한 메모리 제한을 지정할 필요가 없을 수도 있습니다. 하지만 **많은 메모리를 사용한다면**(예: **머신 러닝** 모델), 얼마나 많은 메모리를 소비하는지 확인하고, **각 머신**에서 실행되는 **컨테이너 수**를 조정해야 합니다(필요하다면 클러스터에 머신을 더 추가할 수도 있습니다).\n\n**컨테이너당 여러 프로세스**를 실행한다면, 시작되는 프로세스 수가 사용 가능한 것보다 **더 많은 메모리를 소비하지** 않는지 확인해야 합니다.\n\n## 시작 전 단계와 컨테이너 { #previous-steps-before-starting-and-containers }\n\n컨테이너(예: Docker, Kubernetes)를 사용한다면, 사용할 수 있는 주요 접근 방식은 두 가지입니다.\n\n### 여러 컨테이너 { #multiple-containers }\n\n**여러 컨테이너**가 있고 각 컨테이너가 보통 **단일 프로세스**를 실행한다면(예: **Kubernetes** 클러스터), 복제된 워커 컨테이너를 실행하기 **전에**, 단일 컨테이너에서 단일 프로세스로 **시작 전 사전 단계**를 수행하는 **별도의 컨테이너**를 두고 싶을 가능성이 큽니다.\n\n/// info | 정보\n\nKubernetes를 사용한다면, 이는 아마도 [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)일 것입니다.\n\n///\n\n사용 사례에서 시작 전 사전 단계를 **여러 번 병렬로 실행**해도 문제가 없다면(예: 데이터베이스 마이그레이션을 실행하는 것이 아니라, 데이터베이스가 준비되었는지 확인만 하는 경우), 메인 프로세스를 시작하기 직전에 각 컨테이너에 그 단계를 넣을 수도 있습니다.\n\n### 단일 컨테이너 { #single-container }\n\n**단일 컨테이너**에서 여러 **워커 프로세스**(또는 단일 프로세스)를 시작하는 단순한 셋업이라면, 앱이 있는 프로세스를 시작하기 직전에 같은 컨테이너에서 시작 전 사전 단계를 실행할 수 있습니다.\n\n### 베이스 도커 이미지 { #base-docker-image }\n\n과거에는 공식 FastAPI Docker 이미지가 있었습니다: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). 하지만 이제는 deprecated되었습니다. ⛔️\n\n아마도 이 베이스 도커 이미지(또는 유사한 다른 이미지)는 **사용하지 않는** 것이 좋습니다.\n\n**Kubernetes**(또는 다른 도구)를 사용하고, 클러스터 레벨에서 여러 **컨테이너**로 **복제**를 이미 설정해 둔 경우라면, 위에서 설명한 대로 **처음부터 이미지를 빌드하는 것**이 더 낫습니다: [FastAPI를 위한 도커 이미지 빌드하기](#build-a-docker-image-for-fastapi).\n\n그리고 여러 워커가 필요하다면, `--workers` 커맨드 라인 옵션을 간단히 사용하면 됩니다.\n\n/// note | 기술 세부사항\n\n이 Docker 이미지는 Uvicorn이 죽은 워커를 관리하고 재시작하는 기능을 지원하지 않던 시기에 만들어졌습니다. 그래서 Gunicorn과 Uvicorn을 함께 사용해야 했고, Gunicorn이 Uvicorn 워커 프로세스를 관리하고 재시작하도록 하기 위해 상당한 복잡성이 추가되었습니다.\n\n하지만 이제 Uvicorn(그리고 `fastapi` 명령)은 `--workers`를 지원하므로, 베이스 도커 이미지를 사용하는 대신 직접 이미지를 빌드하지 않을 이유가 없습니다(코드 양도 사실상 거의 같습니다 😅).\n\n///\n\n## 컨테이너 이미지 배포하기 { #deploy-the-container-image }\n\n컨테이너(Docker) 이미지를 만든 후에는 이를 배포하는 여러 방법이 있습니다.\n\n예를 들어:\n\n* 단일 서버에서 **Docker Compose**로\n* **Kubernetes** 클러스터로\n* Docker Swarm Mode 클러스터로\n* Nomad 같은 다른 도구로\n* 컨테이너 이미지를 받아 배포해주는 클라우드 서비스로\n\n## `uv`를 사용하는 도커 이미지 { #docker-image-with-uv }\n\n프로젝트를 설치하고 관리하기 위해 [uv](https://github.com/astral-sh/uv)를 사용한다면, [uv Docker guide](https://docs.astral.sh/uv/guides/integration/docker/)를 따를 수 있습니다.\n\n## 요약 { #recap }\n\n컨테이너 시스템(예: **Docker**, **Kubernetes**)을 사용하면 모든 **배포 개념**을 다루는 것이 상당히 단순해집니다:\n\n* HTTPS\n* 시작 시 자동 실행\n* 재시작\n* 복제(실행 중인 프로세스 수)\n* 메모리\n* 시작 전 사전 단계\n\n대부분의 경우 베이스 이미지는 사용하지 않고, 공식 Python Docker 이미지에 기반해 **처음부터 컨테이너 이미지를 빌드**하는 것이 좋습니다.\n\n`Dockerfile`에서 지시어의 **순서**와 **Docker 캐시**를 신경 쓰면 **빌드 시간을 최소화**해 생산성을 최대화할 수 있습니다(그리고 지루함도 피할 수 있습니다). 😎\n"
  },
  {
    "path": "docs/ko/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\n**한 번의 명령**으로 FastAPI 앱을 [FastAPI Cloud](https://fastapicloud.com)에 배포할 수 있습니다. 아직이라면 대기자 명단에 등록해 보세요. 🚀\n\n## 로그인하기 { #login }\n\n먼저 **FastAPI Cloud** 계정이 이미 있는지 확인하세요(대기자 명단에서 초대해 드렸을 거예요 😉).\n\n그다음 로그인합니다:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## 배포하기 { #deploy }\n\n이제 **한 번의 명령**으로 앱을 배포합니다:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n이게 전부입니다! 이제 해당 URL에서 앱에 접근할 수 있습니다. ✨\n\n## FastAPI Cloud 소개 { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)**는 **FastAPI**를 만든 동일한 저자와 팀이 구축했습니다.\n\n최소한의 노력으로 API를 **구축**, **배포**, **접근**하는 과정을 간소화합니다.\n\nFastAPI로 앱을 만들 때의 동일한 **개발자 경험**을, 클라우드에 **배포**할 때도 제공합니다. 🎉\n\n또한 앱을 배포할 때 보통 필요한 대부분의 것들도 처리해 줍니다. 예를 들면:\n\n* HTTPS\n* 요청을 기반으로 자동 스케일링하는 복제(Replication)\n* 등\n\nFastAPI Cloud는 *FastAPI and friends* 오픈 소스 프로젝트의 주요 스폰서이자 자금 지원 제공자입니다. ✨\n\n## 다른 클라우드 제공업체에 배포하기 { #deploy-to-other-cloud-providers }\n\nFastAPI는 오픈 소스이며 표준을 기반으로 합니다. 원하는 어떤 클라우드 제공업체에도 FastAPI 앱을 배포할 수 있습니다.\n\n해당 클라우드 제공업체의 가이드를 따라 FastAPI 앱을 배포하세요. 🤓\n\n## 자체 서버에 배포하기 { #deploy-your-own-server }\n\n또한 이 **Deployment** 가이드에서 이후에 모든 세부사항을 알려드릴 거예요. 그래서 무슨 일이 일어나고 있는지, 무엇이 필요하며, 본인의 서버를 포함해 직접 FastAPI 앱을 어떻게 배포하는지까지 이해할 수 있게 될 것입니다. 🤓\n"
  },
  {
    "path": "docs/ko/docs/deployment/https.md",
    "content": "# HTTPS 알아보기 { #about-https }\n\nHTTPS는 그냥 “켜져 있거나” 아니면 “꺼져 있는” 것이라고 생각하기 쉽습니다.\n\n하지만 실제로는 훨씬 더 복잡합니다.\n\n/// tip | 팁\n\n바쁘거나 별로 신경 쓰고 싶지 않다면, 다음 섹션에서 다양한 기법으로 모든 것을 설정하는 단계별 안내를 계속 보세요.\n\n///\n\n소비자 관점에서 **HTTPS의 기본을 배우려면** [https://howhttps.works/](https://howhttps.works/)를 확인하세요.\n\n이제 **개발자 관점**에서 HTTPS를 생각할 때 염두에 두어야 할 여러 가지가 있습니다:\n\n* HTTPS를 사용하려면, **서버**가 **제3자**가 발급한 **\"인증서(certificates)\"**를 **보유**해야 합니다.\n    * 이 인증서는 실제로 '생성'되는 것이 아니라 제3자로부터 **발급/획득**하는 것입니다.\n* 인증서에는 **유효 기간**이 있습니다.\n    * 즉, **만료**됩니다.\n    * 그리고 나면 제3자로부터 다시 **갱신**해서 **재발급/재획득**해야 합니다.\n* 연결의 암호화는 **TCP 레벨**에서 일어납니다.\n    * 이는 **HTTP보다 한 계층 아래**입니다.\n    * 따라서 **인증서와 암호화** 처리는 **HTTP 이전**에 수행됩니다.\n* **TCP는 \"도메인\"을 모릅니다.** IP 주소만 압니다.\n    * 어떤 **특정 도메인**을 요청했는지에 대한 정보는 **HTTP 데이터**에 들어 있습니다.\n* **HTTPS 인증서**는 특정 **도메인**을 “인증”하지만, 프로토콜과 암호화는 TCP 레벨에서 일어나며, 어떤 도메인을 다루는지 **알기 전에** 처리됩니다.\n* **기본적으로** 이는 IP 주소 하나당 **HTTPS 인증서 하나만** 둘 수 있다는 뜻입니다.\n    * 서버가 아무리 크든, 그 위에 올린 각 애플리케이션이 아무리 작든 상관없습니다.\n    * 하지만 이에 대한 **해결책**이 있습니다.\n* **TLS** 프로토콜(HTTP 이전, TCP 레벨에서 암호화를 처리하는 것)에 대한 **확장** 중에 **[<abbr title=\"Server Name Indication - 서버 이름 표시\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**라는 것이 있습니다.\n    * 이 SNI 확장을 사용하면, 단일 서버(**단일 IP 주소**)에서 **여러 HTTPS 인증서**를 사용하고 **여러 HTTPS 도메인/애플리케이션**을 제공할 수 있습니다.\n    * 이를 위해서는 서버에서 **공개 IP 주소**로 리스닝하는 **하나의** 컴포넌트(프로그램)가 서버에 있는 **모든 HTTPS 인증서**에 접근할 수 있어야 합니다.\n* 보안 연결을 얻은 **이후에도**, 통신 프로토콜 자체는 **여전히 HTTP**입니다.\n    * **HTTP 프로토콜**로 전송되더라도, 내용은 **암호화**되어 있습니다.\n\n일반적으로 서버(머신, 호스트 등)에는 **프로그램/HTTP 서버 하나**를 실행해 **HTTPS 관련 부분 전체**를 관리하게 합니다: **암호화된 HTTPS 요청**을 받고, 복호화된 **HTTP 요청**을 같은 서버에서 실행 중인 실제 HTTP 애플리케이션(이 경우 **FastAPI** 애플리케이션)으로 전달하고, 애플리케이션의 **HTTP 응답**을 받아 적절한 **HTTPS 인증서**로 **암호화**한 뒤 **HTTPS**로 클라이언트에 다시 보내는 역할입니다. 이런 서버를 흔히 **[TLS Termination Proxy](https://en.wikipedia.org/wiki/TLS_termination_proxy)**라고 부릅니다.\n\nTLS Termination Proxy로 사용할 수 있는 옵션은 다음과 같습니다:\n\n* Traefik (인증서 갱신도 처리 가능)\n* Caddy (인증서 갱신도 처리 가능)\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\nLet's Encrypt 이전에는 이러한 **HTTPS 인증서**가 신뢰할 수 있는 제3자에 의해 판매되었습니다.\n\n인증서를 획득하는 과정은 번거롭고, 꽤 많은 서류 작업이 필요했으며, 인증서도 상당히 비쌌습니다.\n\n하지만 그 후 **[Let's Encrypt](https://letsencrypt.org/)**가 만들어졌습니다.\n\n이는 Linux Foundation의 프로젝트입니다. 표준 암호학적 보안을 모두 사용하는 **HTTPS 인증서**를 **무료로**, 자동화된 방식으로 제공합니다. 이 인증서들은 수명이 짧고(약 3개월) 그래서 유효 기간이 짧은 만큼 **실제로 보안이 더 좋아지기도** 합니다.\n\n도메인은 안전하게 검증되며 인증서는 자동으로 생성됩니다. 또한 이로 인해 인증서 갱신도 자동화할 수 있습니다.\n\n목표는 인증서의 발급과 갱신을 자동화하여 **무료로, 영구히, 안전한 HTTPS**를 사용할 수 있게 하는 것입니다.\n\n## 개발자를 위한 HTTPS { #https-for-developers }\n\n개발자에게 중요한 개념들을 중심으로, HTTPS API가 단계별로 어떻게 보일 수 있는지 예시를 들어 보겠습니다.\n\n### 도메인 이름 { #domain-name }\n\n아마도 시작은 **도메인 이름**을 **획득**하는 것일 겁니다. 그 다음 DNS 서버(아마 같은 클라우드 제공업체)에서 이를 설정합니다.\n\n대개 클라우드 서버(가상 머신) 같은 것을 사용하게 되고, 거기에는 <dfn title=\"시간이 지나도 변하지 않음. 동적이지 않음\">고정</dfn> **공개 IP 주소**가 있습니다.\n\nDNS 서버(들)에서 **도메인**이 서버의 **공개 IP 주소**를 가리키도록 레코드(“`A record`”)를 설정합니다.\n\n보통은 처음 한 번, 모든 것을 설정할 때만 이 작업을 합니다.\n\n/// tip | 팁\n\n도메인 이름 부분은 HTTPS보다 훨씬 이전 단계지만, 모든 것이 도메인과 IP 주소에 의존하므로 여기서 언급할 가치가 있습니다.\n\n///\n\n### DNS { #dns }\n\n이제 실제 HTTPS 부분에 집중해 보겠습니다.\n\n먼저 브라우저는 **DNS 서버**에 질의하여, 여기서는 `someapp.example.com`이라는 **도메인에 대한 IP**가 무엇인지 확인합니다.\n\nDNS 서버는 브라우저에게 특정 **IP 주소**를 사용하라고 알려줍니다. 이는 DNS 서버에 설정해 둔, 서버가 사용하는 공개 IP 주소입니다.\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### TLS 핸드셰이크 시작 { #tls-handshake-start }\n\n그 다음 브라우저는 **포트 443**(HTTPS 포트)에서 해당 IP 주소와 통신합니다.\n\n통신의 첫 부분은 클라이언트와 서버 사이의 연결을 설정하고, 사용할 암호화 키 등을 결정하는 과정입니다.\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\n클라이언트와 서버가 TLS 연결을 설정하기 위해 상호작용하는 이 과정을 **TLS 핸드셰이크**라고 합니다.\n\n### SNI 확장을 사용하는 TLS { #tls-with-sni-extension }\n\n서버에서는 특정 **IP 주소**의 특정 **포트**에서 **하나의 프로세스만** 리스닝할 수 있습니다. 같은 IP 주소에서 다른 포트로 리스닝하는 프로세스는 있을 수 있지만, IP 주소와 포트 조합마다 하나만 가능합니다.\n\nTLS(HTTPS)는 기본적으로 특정 포트 `443`을 사용합니다. 따라서 우리가 필요한 포트는 이것입니다.\n\n이 포트에서 하나의 프로세스만 리스닝할 수 있으므로, 그 역할을 하는 프로세스는 **TLS Termination Proxy**가 됩니다.\n\nTLS Termination Proxy는 하나 이상의 **TLS 인증서**(HTTPS 인증서)에 접근할 수 있습니다.\n\n앞에서 설명한 **SNI 확장**을 사용해, TLS Termination Proxy는 이 연결에 사용할 수 있는 TLS(HTTPS) 인증서들 중에서 클라이언트가 기대하는 도메인과 일치하는 것을 확인해 선택합니다.\n\n이 경우에는 `someapp.example.com`에 대한 인증서를 사용합니다.\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\n클라이언트는 이미 해당 TLS 인증서를 생성한 주체(여기서는 Let's Encrypt이지만, 이는 뒤에서 다시 보겠습니다)를 **신뢰**하므로, 인증서가 유효한지 **검증**할 수 있습니다.\n\n그 다음 인증서를 사용해 클라이언트와 TLS Termination Proxy는 나머지 **TCP 통신**을 어떻게 **암호화할지 결정**합니다. 이로써 **TLS 핸드셰이크** 단계가 완료됩니다.\n\n이후 클라이언트와 서버는 TLS가 제공하는 **암호화된 TCP 연결**을 갖게 됩니다. 그리고 그 연결을 사용해 실제 **HTTP 통신**을 시작할 수 있습니다.\n\n이것이 바로 **HTTPS**입니다. 순수(암호화되지 않은) TCP 연결 대신 **안전한 TLS 연결** 안에서 **HTTP**를 그대로 사용하는 것입니다.\n\n/// tip | 팁\n\n통신의 암호화는 HTTP 레벨이 아니라 **TCP 레벨**에서 일어난다는 점에 주의하세요.\n\n///\n\n### HTTPS 요청 { #https-request }\n\n이제 클라이언트와 서버(구체적으로는 브라우저와 TLS Termination Proxy)가 **암호화된 TCP 연결**을 갖게 되었으니 **HTTP 통신**을 시작할 수 있습니다.\n\n따라서 클라이언트는 **HTTPS 요청**을 보냅니다. 이는 암호화된 TLS 연결을 통해 전달되는 HTTP 요청일 뿐입니다.\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### 요청 복호화 { #decrypt-the-request }\n\nTLS Termination Proxy는 합의된 암호화를 사용해 **요청을 복호화**하고, 애플리케이션을 실행 중인 프로세스(예: FastAPI 애플리케이션을 실행하는 Uvicorn 프로세스)에 **일반(복호화된) HTTP 요청**을 전달합니다.\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### HTTP 응답 { #http-response }\n\n애플리케이션은 요청을 처리하고 **일반(암호화되지 않은) HTTP 응답**을 TLS Termination Proxy로 보냅니다.\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### HTTPS 응답 { #https-response }\n\n그 다음 TLS Termination Proxy는 이전에 합의한 암호화( `someapp.example.com` 인증서로 시작된 것)를 사용해 **응답을 암호화**하고, 브라우저로 다시 보냅니다.\n\n이후 브라우저는 응답이 유효한지, 올바른 암호화 키로 암호화되었는지 등을 확인합니다. 그런 다음 **응답을 복호화**하고 처리합니다.\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\n클라이언트(브라우저)는 앞서 **HTTPS 인증서**로 합의한 암호화를 사용하고 있으므로, 해당 응답이 올바른 서버에서 왔다는 것을 알 수 있습니다.\n\n### 여러 애플리케이션 { #multiple-applications }\n\n같은 서버(또는 여러 서버)에는 예를 들어 다른 API 프로그램이나 데이터베이스처럼 **여러 애플리케이션**이 있을 수 있습니다.\n\n특정 IP와 포트 조합은 하나의 프로세스만 처리할 수 있지만(예시에서는 TLS Termination Proxy), 다른 애플리케이션/프로세스도 **공개 IP와 포트 조합**을 동일하게 쓰려고만 하지 않는다면 서버에서 함께 실행될 수 있습니다.\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\n이렇게 하면 TLS Termination Proxy가 **여러 도메인**에 대한 HTTPS와 인증서를 **여러 애플리케이션**에 대해 처리하고, 각 경우에 맞는 애플리케이션으로 요청을 전달할 수 있습니다.\n\n### 인증서 갱신 { #certificate-renewal }\n\n미래의 어느 시점에는 각 인증서가 **만료**됩니다(획득 후 약 3개월).\n\n그 다음에는 또 다른 프로그램(경우에 따라 별도 프로그램일 수도 있고, 경우에 따라 같은 TLS Termination Proxy일 수도 있습니다)이 Let's Encrypt와 통신하여 인증서를 갱신합니다.\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\n**TLS 인증서**는 IP 주소가 아니라 **도메인 이름**과 **연결**되어 있습니다.\n\n따라서 인증서를 갱신하려면, 갱신 프로그램이 권한 기관(Let's Encrypt)에게 해당 도메인을 실제로 **“소유”하고 제어하고 있음**을 **증명**해야 합니다.\n\n이를 위해, 그리고 다양한 애플리케이션 요구를 수용하기 위해 여러 방법이 있습니다. 널리 쓰이는 방법은 다음과 같습니다:\n\n* **일부 DNS 레코드 수정**.\n    * 이를 위해서는 갱신 프로그램이 DNS 제공업체의 API를 지원해야 하므로, 사용하는 DNS 제공업체에 따라 가능할 수도, 아닐 수도 있습니다.\n* 도메인과 연결된 공개 IP 주소에서 **서버로 실행**(적어도 인증서 발급 과정 동안).\n    * 앞에서 말했듯 특정 IP와 포트에서는 하나의 프로세스만 리스닝할 수 있습니다.\n    * 이것이 동일한 TLS Termination Proxy가 인증서 갱신 과정까지 처리할 때 매우 유용한 이유 중 하나입니다.\n    * 그렇지 않으면 TLS Termination Proxy를 잠시 중지하고, 갱신 프로그램을 시작해 인증서를 획득한 다음, TLS Termination Proxy에 인증서를 설정하고, 다시 TLS Termination Proxy를 재시작해야 할 수도 있습니다. 이는 TLS Termination Proxy가 꺼져 있는 동안 앱(들)을 사용할 수 없으므로 이상적이지 않습니다.\n\n앱을 계속 제공하면서 이 갱신 과정을 처리할 수 있는 것은, 애플리케이션 서버(예: Uvicorn)에서 TLS 인증서를 직접 쓰는 대신 TLS Termination Proxy로 HTTPS를 처리하는 **별도의 시스템**을 두고 싶어지는 주요 이유 중 하나입니다.\n\n## 프록시 전달 헤더 { #proxy-forwarded-headers }\n\n프록시를 사용해 HTTPS를 처리할 때, **애플리케이션 서버**(예: FastAPI CLI를 통한 Uvicorn)는 HTTPS 과정에 대해 아무것도 알지 못하고 **TLS Termination Proxy**와는 일반 HTTP로 통신합니다.\n\n이 **프록시**는 보통 요청을 **애플리케이션 서버**에 전달하기 전에, 요청이 프록시에 의해 **전달(forwarded)**되고 있음을 애플리케이션 서버가 알 수 있도록 일부 HTTP 헤더를 즉석에서 설정합니다.\n\n/// note | 기술 세부사항\n\n프록시 헤더는 다음과 같습니다:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n그럼에도 불구하고 **애플리케이션 서버**는 자신이 신뢰할 수 있는 **프록시** 뒤에 있다는 것을 모르므로, 기본적으로는 그 헤더들을 신뢰하지 않습니다.\n\n하지만 **애플리케이션 서버**가 **프록시**가 보낸 *forwarded* 헤더를 신뢰하도록 설정할 수 있습니다. FastAPI CLI를 사용하고 있다면, *CLI Option* `--forwarded-allow-ips`를 사용해 어떤 IP에서 온 *forwarded* 헤더를 신뢰할지 지정할 수 있습니다.\n\n예를 들어 **애플리케이션 서버**가 신뢰하는 **프록시**로부터만 통신을 받는다면, `--forwarded-allow-ips=\"*\"`로 설정해 들어오는 모든 IP를 신뢰하게 할 수 있습니다. 어차피 **프록시**가 사용하는 IP에서만 요청을 받게 될 것이기 때문입니다.\n\n이렇게 하면 애플리케이션은 자신이 사용하는 공개 URL이 무엇인지, HTTPS를 사용하는지, 도메인이 무엇인지 등을 알 수 있습니다.\n\n예를 들어 리다이렉트를 올바르게 처리하는 데 유용합니다.\n\n/// tip | 팁\n\n이에 대해서는 [프록시 뒤에서 실행하기 - 프록시 전달 헤더 활성화](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers) 문서에서 더 알아볼 수 있습니다.\n\n///\n\n## 요약 { #recap }\n\n**HTTPS**는 매우 중요하며, 대부분의 경우 상당히 **핵심적**입니다. 개발자가 HTTPS와 관련해 해야 하는 노력의 대부분은 결국 **이 개념들을 이해**하고 그것들이 어떻게 동작하는지 파악하는 것입니다.\n\n하지만 **개발자를 위한 HTTPS**의 기본 정보를 알고 나면, 여러 도구를 쉽게 조합하고 설정하여 모든 것을 간단하게 관리할 수 있습니다.\n\n다음 장들에서는 **FastAPI** 애플리케이션을 위한 **HTTPS** 설정 방법을 여러 구체적인 예시로 보여드리겠습니다. 🔒\n"
  },
  {
    "path": "docs/ko/docs/deployment/index.md",
    "content": "# 배포 { #deployment }\n\n**FastAPI** 애플리케이션을 배포하는 것은 비교적 쉽습니다.\n\n## 배포의 의미 { #what-does-deployment-mean }\n\n애플리케이션을 **배포**한다는 것은 **사용자가 사용**할 수 있도록 하는 데 필요한 단계를 수행하는 것을 의미합니다.\n\n**웹 API**의 경우, 일반적으로 **원격 머신**에 이를 설치하고, 좋은 성능, 안정성 등을 제공하는 **서버 프로그램**과 함께 구성하여 **사용자**가 중단이나 문제 없이 애플리케이션에 효율적으로 **접근**할 수 있게 하는 것을 포함합니다.\n\n이는 지속적으로 코드를 변경하고, 망가뜨리고 고치고, 개발 서버를 중지했다가 다시 시작하는 등의 **개발** 단계와 대조됩니다.\n\n## 배포 전략 { #deployment-strategies }\n\n구체적인 사용 사례와 사용하는 도구에 따라 여러 가지 방법이 있습니다.\n\n여러 도구를 조합해 직접 **서버를 배포**할 수도 있고, 작업의 일부를 대신해 주는 **클라우드 서비스**를 사용할 수도 있으며, 다른 가능한 선택지도 있습니다.\n\n예를 들어, FastAPI 뒤에 있는 저희 팀은 FastAPI로 작업하는 것과 같은 개발자 경험을 유지하면서, FastAPI 앱을 클라우드에 가능한 한 간소화된 방식으로 배포할 수 있도록 [**FastAPI Cloud**](https://fastapicloud.com)를 만들었습니다.\n\n**FastAPI** 애플리케이션을 배포할 때 아마 염두에 두어야 할 몇 가지 주요 개념을 보여드리겠습니다(대부분은 다른 유형의 웹 애플리케이션에도 적용됩니다).\n\n다음 섹션에서 염두에 둘 더 많은 세부사항과 이를 위한 몇 가지 기술을 볼 수 있습니다. ✨\n"
  },
  {
    "path": "docs/ko/docs/deployment/manually.md",
    "content": "# 서버를 수동으로 실행하기 { #run-a-server-manually }\n\n## `fastapi run` 명령 사용하기 { #use-the-fastapi-run-command }\n\n요약하면, `fastapi run`을 사용해 FastAPI 애플리케이션을 서비스하세요:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\n대부분의 경우에는 이것으로 동작합니다. 😎\n\n예를 들어 이 명령은 컨테이너나 서버 등에서 **FastAPI** 앱을 시작할 때 사용할 수 있습니다.\n\n## ASGI 서버 { #asgi-servers }\n\n이제 조금 더 자세히 살펴보겠습니다.\n\nFastAPI는 <abbr title=\"Asynchronous Server Gateway Interface - 비동기 서버 게이트웨이 인터페이스\">ASGI</abbr>라고 불리는, Python 웹 프레임워크와 서버를 만들기 위한 표준을 사용합니다. FastAPI는 ASGI 웹 프레임워크입니다.\n\n원격 서버 머신에서 **FastAPI** 애플리케이션(또는 다른 ASGI 애플리케이션)을 실행하기 위해 필요한 핵심 요소는 **Uvicorn** 같은 ASGI 서버 프로그램입니다. `fastapi` 명령에는 기본으로 이것이 포함되어 있습니다.\n\n다음을 포함해 여러 대안이 있습니다:\n\n* [Uvicorn](https://www.uvicorn.dev/): 고성능 ASGI 서버.\n* [Hypercorn](https://hypercorn.readthedocs.io/): HTTP/2 및 Trio 등 여러 기능과 호환되는 ASGI 서버.\n* [Daphne](https://github.com/django/daphne): Django Channels를 위해 만들어진 ASGI 서버.\n* [Granian](https://github.com/emmett-framework/granian): Python 애플리케이션을 위한 Rust HTTP 서버.\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit은 가볍고 다용도로 사용할 수 있는 웹 애플리케이션 런타임입니다.\n\n## 서버 머신과 서버 프로그램 { #server-machine-and-server-program }\n\n이름에 관해 기억해 둘 작은 디테일이 있습니다. 💡\n\n\"**server**\"라는 단어는 보통 원격/클라우드 컴퓨터(물리 또는 가상 머신)와, 그 머신에서 실행 중인 프로그램(예: Uvicorn) 둘 다를 가리키는 데 사용됩니다.\n\n일반적으로 \"server\"를 읽을 때, 이 두 가지 중 하나를 의미할 수 있다는 점을 기억하세요.\n\n원격 머신을 가리킬 때는 **server**라고 부르는 것이 일반적이지만, **machine**, **VM**(virtual machine), **node**라고 부르기도 합니다. 이것들은 보통 Linux를 실행하는 원격 머신의 한 형태를 뜻하며, 그곳에서 프로그램을 실행합니다.\n\n## 서버 프로그램 설치하기 { #install-the-server-program }\n\nFastAPI를 설치하면 프로덕션 서버인 Uvicorn이 함께 설치되며, `fastapi run` 명령으로 시작할 수 있습니다.\n\n하지만 ASGI 서버를 수동으로 설치할 수도 있습니다.\n\n[가상 환경](../virtual-environments.md)을 만들고 활성화한 다음, 서버 애플리케이션을 설치하세요.\n\n예를 들어 Uvicorn을 설치하려면:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\n다른 어떤 ASGI 서버 프로그램도 비슷한 과정이 적용됩니다.\n\n/// tip | 팁\n\n`standard`를 추가하면 Uvicorn이 권장되는 추가 의존성 몇 가지를 설치하고 사용합니다.\n\n여기에는 `uvloop`가 포함되며, 이는 `asyncio`를 고성능으로 대체할 수 있는 드롭인 대체재로, 큰 동시성 성능 향상을 제공합니다.\n\n`pip install \"fastapi[standard]\"` 같은 방식으로 FastAPI를 설치하면 `uvicorn[standard]`도 함께 설치됩니다.\n\n///\n\n## 서버 프로그램 실행하기 { #run-the-server-program }\n\nASGI 서버를 수동으로 설치했다면, 보통 FastAPI 애플리케이션을 임포트하기 위해 특별한 형식의 import string을 전달해야 합니다:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note | 참고\n\n`uvicorn main:app` 명령은 다음을 가리킵니다:\n\n* `main`: 파일 `main.py`(Python \"module\").\n* `app`: `main.py` 안에서 `app = FastAPI()` 라인으로 생성된 객체.\n\n이는 다음과 동일합니다:\n\n```Python\nfrom main import app\n```\n\n///\n\n각 ASGI 서버 프로그램의 대안도 비슷한 명령을 갖고 있으며, 자세한 내용은 각자의 문서를 참고하세요.\n\n/// warning | 경고\n\nUvicorn과 다른 서버는 개발 중에 유용한 `--reload` 옵션을 지원합니다.\n\n`--reload` 옵션은 훨씬 더 많은 리소스를 소비하고, 더 불안정합니다.\n\n**개발** 중에는 큰 도움이 되지만, **프로덕션**에서는 사용하지 **말아야** 합니다.\n\n///\n\n## 배포 개념 { #deployment-concepts }\n\n이 예제들은 서버 프로그램(예: Uvicorn)을 실행하여 **단일 프로세스**를 시작하고, 사전에 정한 포트(예: `80`)에서 모든 IP(`0.0.0.0`)로 들어오는 요청을 받도록 합니다.\n\n이것이 기본 아이디어입니다. 하지만 보통은 다음과 같은 추가 사항들도 처리해야 합니다:\n\n* 보안 - HTTPS\n* 시작 시 자동 실행\n* 재시작\n* 복제(실행 중인 프로세스 수)\n* 메모리\n* 시작 전 선행 단계\n\n다음 장들에서 이 각각의 개념을 어떻게 생각해야 하는지, 그리고 이를 다루기 위한 전략의 구체적인 예시를 더 알려드리겠습니다. 🚀\n"
  },
  {
    "path": "docs/ko/docs/deployment/server-workers.md",
    "content": "# 서버 워커 - 워커와 함께 사용하는 Uvicorn { #server-workers-uvicorn-with-workers }\n\n이전의 배포 개념들을 다시 확인해보겠습니다:\n\n* 보안 - HTTPS\n* 서버 시작 시 실행\n* 재시작\n* **복제(실행 중인 프로세스 수)**\n* 메모리\n* 시작하기 전의 이전 단계\n\n지금까지 문서의 모든 튜토리얼을 참고하면서, `fastapi` 명령어처럼 Uvicorn을 실행하는 **서버 프로그램**을 사용해 **단일 프로세스**로 실행해 왔을 가능성이 큽니다.\n\n애플리케이션을 배포할 때는 **다중 코어**를 활용하고 더 많은 요청을 처리할 수 있도록 **프로세스 복제**를 하고 싶을 가능성이 큽니다.\n\n이전 장의 [배포 개념들](concepts.md)에서 본 것처럼, 사용할 수 있는 전략이 여러 가지 있습니다.\n\n여기서는 `fastapi` 명령어를 사용하거나 `uvicorn` 명령어를 직접 사용해서, **워커 프로세스**와 함께 **Uvicorn**을 사용하는 방법을 보여드리겠습니다.\n\n/// info | 정보\n\nDocker나 Kubernetes 같은 컨테이너를 사용하고 있다면, 다음 장인 [컨테이너에서의 FastAPI - 도커](docker.md)에서 더 자세히 설명하겠습니다.\n\n특히 **Kubernetes**에서 실행할 때는 워커를 사용하기보다는, 대신 **컨테이너당 단일 Uvicorn 프로세스 하나**를 실행하고 싶을 가능성이 크지만, 해당 내용은 그 장의 뒤에서 설명하겠습니다.\n\n///\n\n## 여러 워커 { #multiple-workers }\n\n`--workers` 명령어 옵션으로 여러 워커를 시작할 수 있습니다:\n\n//// tab | `fastapi`\n\n`fastapi` 명령어를 사용한다면:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\n`uvicorn` 명령어를 직접 사용하는 편이 좋다면:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\n여기서 새로운 옵션은 `--workers`뿐이며, Uvicorn에게 워커 프로세스 4개를 시작하라고 알려줍니다.\n\n또한 각 프로세스의 **PID**도 확인할 수 있는데, 상위 프로세스(이것이 **프로세스 관리자**)의 PID는 `27365`이고, 각 워커 프로세스의 PID는 `27368`, `27369`, `27370`, `27367`입니다.\n\n## 배포 개념들 { #deployment-concepts }\n\n여기서는 여러 **워커**를 사용해 애플리케이션 실행을 **병렬화**하고, CPU의 **다중 코어**를 활용하며, **더 많은 요청**을 제공할 수 있는 방법을 살펴봤습니다.\n\n위의 배포 개념 목록에서 워커를 사용하는 것은 주로 **복제** 부분에 도움이 되고, **재시작**에도 약간 도움이 되지만, 나머지 항목들도 여전히 신경 써야 합니다:\n\n* **보안 - HTTPS**\n* **서버 시작 시 실행**\n* ***재시작***\n* 복제(실행 중인 프로세스 수)\n* **메모리**\n* **시작하기 전의 이전 단계**\n\n## 컨테이너와 도커 { #containers-and-docker }\n\n다음 장인 [컨테이너에서의 FastAPI - 도커](docker.md)에서는 다른 **배포 개념들**을 처리하기 위해 사용할 수 있는 몇 가지 전략을 설명하겠습니다.\n\n단일 Uvicorn 프로세스를 실행하기 위해, **처음부터 여러분만의 이미지를 직접 빌드**하는 방법을 보여드리겠습니다. 이는 간단한 과정이며, **Kubernetes** 같은 분산 컨테이너 관리 시스템을 사용할 때 아마도 이렇게 하고 싶을 것입니다.\n\n## 요약 { #recap }\n\n`fastapi` 또는 `uvicorn` 명령어에서 `--workers` CLI 옵션을 사용해 여러 워커 프로세스를 실행하면, **멀티 코어 CPU**를 활용해 **여러 프로세스를 병렬로 실행**할 수 있습니다.\n\n다른 배포 개념들을 직접 처리하면서 **자체 배포 시스템**을 구축하는 경우, 이러한 도구와 아이디어를 활용할 수 있습니다.\n\n다음 장에서 컨테이너(예: Docker 및 Kubernetes)와 함께 사용하는 **FastAPI**에 대해 알아보세요. 해당 도구들이 다른 **배포 개념들**도 간단히 해결하는 방법이 있다는 것을 확인할 수 있습니다. ✨\n"
  },
  {
    "path": "docs/ko/docs/deployment/versions.md",
    "content": "# FastAPI 버전들에 대하여 { #about-fastapi-versions }\n\n**FastAPI**는 이미 많은 애플리케이션과 시스템에서 프로덕션으로 사용되고 있습니다. 그리고 테스트 커버리지는 100%로 유지됩니다. 하지만 개발은 여전히 빠르게 진행되고 있습니다.\n\n새로운 기능이 자주 추가되고, 버그가 규칙적으로 수정되며, 코드는 계속해서 지속적으로 개선되고 있습니다.\n\n그래서 현재 버전이 아직 `0.x.x`인 것입니다. 이는 각 버전이 잠재적으로 하위 호환성이 깨지는 변경을 포함할 수 있음을 반영합니다. 이는 [Semantic Versioning](https://semver.org/) 관례를 따릅니다.\n\n지금 바로 **FastAPI**로 프로덕션 애플리케이션을 만들 수 있습니다(그리고 아마도 한동안 그렇게 해오셨을 것입니다). 다만 나머지 코드와 함께 올바르게 동작하는 버전을 사용하고 있는지 확인하기만 하면 됩니다.\n\n## `fastapi` 버전을 고정하기 { #pin-your-fastapi-version }\n\n가장 먼저 해야 할 일은 여러분의 애플리케이션에서 올바르게 동작하는 것으로 알고 있는 **FastAPI**의 최신 구체 버전에 맞춰 사용 중인 버전을 \"고정(pin)\"하는 것입니다.\n\n예를 들어, 앱에서 `0.112.0` 버전을 사용하고 있다고 가정해 보겠습니다.\n\n`requirements.txt` 파일을 사용한다면 다음과 같이 버전을 지정할 수 있습니다:\n\n```txt\nfastapi[standard]==0.112.0\n```\n\n이는 정확히 `0.112.0` 버전을 사용한다는 의미입니다.\n\n또는 다음과 같이 고정할 수도 있습니다:\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\n이는 `0.112.0` 이상이면서 `0.113.0` 미만의 버전을 사용한다는 의미입니다. 예를 들어 `0.112.2` 버전도 허용됩니다.\n\n`uv`, Poetry, Pipenv 등 다른 도구로 설치를 관리한다면, 모두 패키지의 특정 버전을 정의할 수 있는 방법을 제공합니다.\n\n## 이용 가능한 버전들 { #available-versions }\n\n사용 가능한 버전(예: 현재 최신 버전이 무엇인지 확인하기 위해)은 [릴리스 노트](../release-notes.md)에서 확인할 수 있습니다.\n\n## 버전들에 대해 { #about-versions }\n\nSemantic Versioning 관례에 따르면, `1.0.0` 미만의 어떤 버전이든 잠재적으로 하위 호환성이 깨지는 변경을 추가할 수 있습니다.\n\nFastAPI는 또한 \"PATCH\" 버전 변경은 버그 수정과 하위 호환성이 깨지지 않는 변경을 위한 것이라는 관례를 따릅니다.\n\n/// tip | 팁\n\n\"PATCH\"는 마지막 숫자입니다. 예를 들어 `0.2.3`에서 PATCH 버전은 `3`입니다.\n\n///\n\n따라서 다음과 같이 버전을 고정할 수 있어야 합니다:\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\n하위 호환성이 깨지는 변경과 새로운 기능은 \"MINOR\" 버전에 추가됩니다.\n\n/// tip | 팁\n\n\"MINOR\"는 가운데 숫자입니다. 예를 들어 `0.2.3`에서 MINOR 버전은 `2`입니다.\n\n///\n\n## FastAPI 버전 업그레이드하기 { #upgrading-the-fastapi-versions }\n\n앱에 테스트를 추가해야 합니다.\n\n**FastAPI**에서는 매우 쉽습니다(Starlette 덕분에). 문서를 확인해 보세요: [테스트](../tutorial/testing.md)\n\n테스트를 갖춘 뒤에는 **FastAPI** 버전을 더 최신 버전으로 업그레이드하고, 테스트를 실행하여 모든 코드가 올바르게 동작하는지 확인하세요.\n\n모든 것이 동작하거나 필요한 변경을 한 뒤 모든 테스트가 통과한다면, `fastapi`를 그 새로운 최신 버전으로 고정할 수 있습니다.\n\n## Starlette에 대해 { #about-starlette }\n\n`starlette`의 버전은 고정하지 않는 것이 좋습니다.\n\n서로 다른 **FastAPI** 버전은 Starlette의 특정한 더 새로운 버전을 사용하게 됩니다.\n\n따라서 **FastAPI**가 올바른 Starlette 버전을 사용하도록 그냥 두면 됩니다.\n\n## Pydantic에 대해 { #about-pydantic }\n\nPydantic은 자체 테스트에 **FastAPI**에 대한 테스트도 포함하고 있으므로, Pydantic의 새 버전(`1.0.0` 초과)은 항상 FastAPI와 호환됩니다.\n\n여러분에게 맞는 `1.0.0` 초과의 어떤 Pydantic 버전으로든 고정할 수 있습니다.\n\n예를 들어:\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/ko/docs/editor-support.md",
    "content": "# 에디터 지원 { #editor-support }\n\n공식 [FastAPI 확장](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode)은 FastAPI 개발 워크플로우를 강화해 줍니다. *경로 처리* 탐색 및 이동, FastAPI Cloud 배포, 실시간 로그 스트리밍을 제공합니다.\n\n확장에 대한 자세한 내용은 [GitHub 저장소](https://github.com/fastapi/fastapi-vscode)의 README를 참고하세요.\n\n## 설치 및 설정 { #setup-and-installation }\n\n**FastAPI 확장**은 [VS Code](https://code.visualstudio.com/)와 [Cursor](https://www.cursor.com/)에서 사용할 수 있습니다. 각 에디터의 확장(Extensions) 패널에서 \"FastAPI\"로 검색한 뒤 **FastAPI Labs**가 배포한 확장을 선택해 바로 설치할 수 있습니다. 또한 [vscode.dev](https://vscode.dev), [github.dev](https://github.dev) 같은 브라우저 기반 에디터에서도 동작합니다.\n\n### 애플리케이션 자동 감지 { #application-discovery }\n\n기본적으로 이 확장은 작업 공간에서 `FastAPI()`를 생성하는 파일을 스캔하여 FastAPI 애플리케이션을 자동으로 감지합니다. 프로젝트 구조상 자동 감지가 어려운 경우, `pyproject.toml`의 `[tool.fastapi]` 항목이나 VS Code 설정 `fastapi.entryPoint`에 모듈 표기(예: `myapp.main:app`)로 엔트리포인트를 지정할 수 있습니다.\n\n## 기능 { #features }\n\n- **경로 처리 탐색기** - 애플리케이션의 모든 <dfn title=\"경로, 엔드포인트\">*경로 처리*</dfn>를 사이드바 트리 뷰로 확인합니다. 클릭하면 해당 경로 또는 라우터 정의로 바로 이동합니다.\n- **경로 검색** - <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>)로 경로, 메서드, 이름으로 검색합니다.\n- **CodeLens 탐색** - 테스트 클라이언트 호출(예: `client.get('/items')`) 위의 클릭 가능한 링크를 통해 해당 *경로 처리*로 즉시 이동하여 테스트와 구현 간을 빠르게 오갈 수 있습니다.\n- **FastAPI Cloud에 배포** - [FastAPI Cloud](https://fastapicloud.com/)로 원클릭 배포를 지원합니다.\n- **애플리케이션 로그 스트리밍** - FastAPI Cloud에 배포된 애플리케이션의 로그를 실시간으로 스트리밍하며, 레벨 필터링과 텍스트 검색을 제공합니다.\n\n확장의 기능을 먼저 익혀보고 싶다면, 명령 팔레트(<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>, macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>)를 열고 \"Welcome: Open walkthrough...\"를 선택한 뒤 \"Get started with FastAPI\" walkthrough를 선택해 보세요.\n"
  },
  {
    "path": "docs/ko/docs/environment-variables.md",
    "content": "# 환경 변수 { #environment-variables }\n\n/// tip | 팁\n\n만약 \"환경 변수\"가 무엇이고, 어떻게 사용하는지 알고 계시다면, 이 챕터를 스킵하셔도 좋습니다.\n\n///\n\n환경 변수(또는 \"**env var**\"라고도 합니다)는 파이썬 코드의 **바깥**인, **운영 체제**에 존재하는 변수이며, 파이썬 코드(또는 다른 프로그램에서도)에서 읽을 수 있습니다.\n\n환경 변수는 애플리케이션 **설정**을 처리하거나, 파이썬의 **설치** 과정의 일부로 유용할 수 있습니다.\n\n## 환경 변수를 만들고 사용하기 { #create-and-use-env-vars }\n\n파이썬 없이도, **셸 (터미널)** 에서 환경 변수를 **생성** 하고 사용할 수 있습니다.\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// 환경 변수 MY_NAME을 다음과 같이 생성할 수 있습니다\n$ export MY_NAME=\"Wade Wilson\"\n\n// 그런 다음 다른 프로그램과 함께 사용할 수 있습니다. 예:\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// 환경 변수 MY_NAME 생성\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// 다른 프로그램과 함께 사용하기. 예:\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## 파이썬에서 env var 읽기 { #read-env-vars-in-python }\n\n파이썬 **바깥**인 터미널에서(또는 다른 어떤 방법으로든) 환경 변수를 만들고, 그런 다음 **파이썬에서 읽을 수 있습니다**.\n\n예를 들어 다음과 같은 `main.py` 파일이 있다고 합시다:\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip | 팁\n\n[`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) 의 두 번째 인자는 반환할 기본값입니다.\n\n제공하지 않으면 기본값은 `None`이며, 여기서는 사용할 기본값으로 `\"World\"`를 제공합니다.\n\n///\n\n그러면 해당 파이썬 프로그램을 다음과 같이 호출할 수 있습니다:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// 여기서는 아직 환경 변수를 설정하지 않습니다\n$ python main.py\n\n// 환경 변수를 설정하지 않았으므로 기본값이 사용됩니다\n\nHello World from Python\n\n// 하지만 먼저 환경 변수를 생성하면\n$ export MY_NAME=\"Wade Wilson\"\n\n// 그리고 프로그램을 다시 실행하면\n$ python main.py\n\n// 이제 환경 변수를 읽을 수 있습니다\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// 여기서는 아직 환경 변수를 설정하지 않습니다\n$ python main.py\n\n// 환경 변수를 설정하지 않았으므로 기본값이 사용됩니다\n\nHello World from Python\n\n// 하지만 먼저 환경 변수를 생성하면\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// 그리고 프로그램을 다시 실행하면\n$ python main.py\n\n// 이제 환경 변수를 읽을 수 있습니다\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n환경변수는 코드 바깥에서 설정될 수 있지만, 코드에서 읽을 수 있고, 나머지 파일과 함께 저장(`git`에 커밋)할 필요가 없으므로, 구성이나 **설정** 에 사용하는 것이 일반적입니다.\n\n또한 **특정 프로그램 호출**에 대해서만 사용할 수 있는 환경 변수를 만들 수도 있는데, 해당 프로그램에서만 사용할 수 있고, 해당 프로그램이 실행되는 동안만 사용할 수 있습니다.\n\n그렇게 하려면 프로그램 바로 앞, 같은 줄에 환경 변수를 만들어야 합니다:\n\n<div class=\"termy\">\n\n```console\n// 이 프로그램 호출을 위해 같은 줄에서 환경 변수 MY_NAME 생성\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// 이제 환경 변수를 읽을 수 있습니다\n\nHello Wade Wilson from Python\n\n// 이후에는 해당 환경 변수가 존재하지 않습니다\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip | 팁\n\n[The Twelve-Factor App: Config](https://12factor.net/config) 에서 좀 더 자세히 알아볼 수 있습니다.\n\n///\n\n## 타입과 검증 { #types-and-validation }\n\n이 환경변수들은 오직 **텍스트 문자열**로만 처리할 수 있습니다. 텍스트 문자열은 파이썬 외부에 있으며 다른 프로그램 및 나머지 시스템(그리고 Linux, Windows, macOS 같은 서로 다른 운영 체제에서도)과 호환되어야 합니다.\n\n즉, 파이썬에서 환경 변수로부터 읽은 **모든 값**은 **`str`**이 되고, 다른 타입으로의 변환이나 검증은 코드에서 수행해야 합니다.\n\n**애플리케이션 설정**을 처리하기 위한 환경 변수 사용에 대한 자세한 내용은 [고급 사용자 가이드 - 설정 및 환경 변수](./advanced/settings.md) 에서 확인할 수 있습니다.\n\n## `PATH` 환경 변수 { #path-environment-variable }\n\n**`PATH`**라고 불리는, **특별한** 환경변수가 있습니다. 운영체제(Linux, macOS, Windows)에서 실행할 프로그램을 찾기위해 사용됩니다.\n\n변수 `PATH`의 값은 Linux와 macOS에서는 콜론 `:`, Windows에서는 세미콜론 `;`으로 구분된 디렉토리로 구성된 긴 문자열입니다.\n\n예를 들어, `PATH` 환경 변수는 다음과 같습니다:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\n이는 시스템이 다음 디렉토리에서 프로그램을 찾아야 함을 의미합니다:\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\n이는 시스템이 다음 디렉토리에서 프로그램을 찾아야 함을 의미합니다:\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\n터미널에 **명령어**를 입력하면 운영 체제는 `PATH` 환경 변수에 나열된 **각 디렉토리**에서 프로그램을 **찾습니다.**\n\n예를 들어 터미널에 `python`을 입력하면 운영 체제는 해당 목록의 **첫 번째 디렉토리**에서 `python`이라는 프로그램을 찾습니다.\n\n찾으면 **사용합니다**. 그렇지 않으면 **다른 디렉토리**에서 계속 찾습니다.\n\n### 파이썬 설치와 `PATH` 업데이트 { #installing-python-and-updating-the-path }\n\n파이썬을 설치할 때, 아마 `PATH` 환경 변수를 업데이트 할 것이냐고 물어봤을 겁니다.\n\n//// tab | Linux, macOS\n\n파이썬을 설치하고 그것이 `/opt/custompython/bin` 디렉토리에 있다고 가정해 보겠습니다.\n\n`PATH` 환경 변수를 업데이트하도록 \"예\"라고 하면 설치 관리자가 `/opt/custompython/bin`을 `PATH` 환경 변수에 추가합니다.\n\n다음과 같이 보일 수 있습니다:\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\n이렇게 하면 터미널에 `python`을 입력할 때, 시스템이 `/opt/custompython/bin`(마지막 디렉토리)에서 파이썬 프로그램을 찾아 사용합니다.\n\n////\n\n//// tab | Windows\n\n파이썬을 설치하고 그것이 `C:\\opt\\custompython\\bin` 디렉토리에 있다고 가정해 보겠습니다.\n\n`PATH` 환경 변수를 업데이트하도록 \"예\"라고 하면 설치 관리자가 `C:\\opt\\custompython\\bin`을 `PATH` 환경 변수에 추가합니다.\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\n이렇게 하면 터미널에 `python`을 입력할 때, 시스템이 `C:\\opt\\custompython\\bin`(마지막 디렉토리)에서 파이썬 프로그램을 찾아 사용합니다.\n\n////\n\n그래서, 다음과 같이 입력한다면:\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\n시스템은 `/opt/custompython/bin`에서 `python` 프로그램을 **찾아** 실행합니다.\n\n다음과 같이 입력하는 것과 거의 같습니다:\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\n시스템은 `C:\\opt\\custompython\\bin\\python`에서 `python` 프로그램을 **찾아** 실행합니다.\n\n다음과 같이 입력하는 것과 거의 같습니다:\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\n이 정보는 [가상 환경](virtual-environments.md) 에 대해 알아볼 때 유용할 것입니다.\n\n## 결론 { #conclusion }\n\n이 문서를 통해 **환경 변수**가 무엇이고 파이썬에서 어떻게 사용하는지 기본적으로 이해하셨을 겁니다.\n\n또한 [환경 변수에 대한 위키피디아](https://en.wikipedia.org/wiki/Environment_variable)에서 이에 대해 자세히 알아볼 수 있습니다.\n\n많은 경우에서, 환경 변수가 어떻게 유용하고 적용 가능한지 바로 명확하게 알 수는 없습니다. 하지만 개발할 때 다양한 시나리오에서 계속 나타나므로 이에 대해 아는 것이 좋습니다.\n\n예를 들어, 다음 섹션인 [가상 환경](virtual-environments.md)에서 이 정보가 필요합니다.\n"
  },
  {
    "path": "docs/ko/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - 명령줄 인터페이스\">CLI</abbr>**는 FastAPI 애플리케이션을 서빙하고, FastAPI 프로젝트를 관리하는 등 다양한 작업에 사용할 수 있는 커맨드 라인 프로그램입니다.\n\nFastAPI를 설치하면(예: `pip install \"fastapi[standard]\"`) 터미널에서 실행할 수 있는 커맨드 라인 프로그램이 함께 제공됩니다.\n\n개발용으로 FastAPI 애플리케이션을 실행하려면 `fastapi dev` 명령어를 사용할 수 있습니다:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip | 팁\n\n프로덕션에서는 `fastapi dev` 대신 `fastapi run`을 사용합니다. 🚀\n\n///\n\n내부적으로 **FastAPI CLI**는 고성능의, 프로덕션에 적합한 ASGI 서버인 [Uvicorn](https://www.uvicorn.dev)을 사용합니다. 😎\n\n`fastapi` CLI는 기본적으로 실행할 FastAPI 앱을 자동으로 감지하려고 시도합니다. `main.py` 파일 안의 `app`이라는 객체(또는 몇 가지 변형)가 있다고 가정합니다.\n\n하지만 사용할 앱을 명시적으로 구성할 수도 있습니다.\n\n## `pyproject.toml`에서 앱 `entrypoint` 구성하기 { #configure-the-app-entrypoint-in-pyproject-toml }\n\n`pyproject.toml` 파일에서 앱이 어디에 있는지 다음과 같이 구성할 수 있습니다:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\n이 `entrypoint`는 `fastapi` 명령어에 다음과 같이 앱을 임포트하라고 알려줍니다:\n\n```python\nfrom main import app\n```\n\n코드 구조가 다음과 같다면:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\n`entrypoint`를 다음과 같이 설정합니다:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\n이는 다음과 동일합니다:\n\n```python\nfrom backend.main import app\n```\n\n### 경로와 함께 `fastapi dev` { #fastapi-dev-with-path }\n\n`fastapi dev` 명령어에 파일 경로를 전달할 수도 있으며, 그러면 사용할 FastAPI 앱 객체를 추정합니다:\n\n```console\n$ fastapi dev main.py\n```\n\n하지만 매번 `fastapi` 명령어를 호출할 때 올바른 경로를 전달하는 것을 기억해야 합니다.\n\n또한 [VS Code 확장](editor-support.md)이나 [FastAPI Cloud](https://fastapicloud.com) 같은 다른 도구에서는 이를 찾지 못할 수도 있으므로, `pyproject.toml`의 `entrypoint`를 사용하는 것을 권장합니다.\n\n## `fastapi dev` { #fastapi-dev }\n\n`fastapi dev`를 실행하면 개발 모드가 시작됩니다.\n\n기본적으로 **auto-reload**가 활성화되어 코드에 변경이 생기면 서버를 자동으로 다시 로드합니다. 이는 리소스를 많이 사용하며, 비활성화했을 때보다 안정성이 떨어질 수 있습니다. 개발 환경에서만 사용해야 합니다. 또한 컴퓨터가 자신과만 통신하기 위한(`localhost`) IP인 `127.0.0.1`에서 연결을 대기합니다.\n\n## `fastapi run` { #fastapi-run }\n\n`fastapi run`을 실행하면 프로덕션 모드로 FastAPI가 시작됩니다.\n\n기본적으로 **auto-reload**는 비활성화되어 있습니다. 또한 사용 가능한 모든 IP 주소를 의미하는 `0.0.0.0`에서 연결을 대기하므로, 해당 컴퓨터와 통신할 수 있는 누구에게나 공개적으로 접근 가능해집니다. 보통 프로덕션에서는 이렇게 실행하며, 예를 들어 컨테이너에서 이런 방식으로 실행합니다.\n\n대부분의 경우 위에 \"termination proxy\"를 두고 HTTPS를 처리하게(그리고 처리해야) 됩니다. 이는 애플리케이션을 배포하는 방식에 따라 달라지며, 제공자가 이 작업을 대신 처리해줄 수도 있고 직접 설정해야 할 수도 있습니다.\n\n/// tip | 팁\n\n자세한 내용은 [배포 문서](deployment/index.md)에서 확인할 수 있습니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/features.md",
    "content": "# 기능 { #features }\n\n## FastAPI의 기능 { #fastapi-features }\n\n**FastAPI**는 다음과 같은 기능을 제공합니다:\n\n### 개방형 표준을 기반으로 { #based-on-open-standards }\n\n* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification): <dfn title=\"또한 다음으로도 불림: 엔드포인트, 라우트\">경로</dfn> <dfn title=\"HTTP 메소드(POST, GET, PUT, DELETE 등)로도 알려짐\">처리</dfn>, 매개변수, 요청 본문, 보안 등의 선언을 포함하여 API를 생성합니다.\n* [**JSON Schema**](https://json-schema.org/)를 사용한 자동 데이터 모델 문서화(OpenAPI 자체가 JSON Schema를 기반으로 하기 때문입니다).\n* 단순히 떠올려서 덧붙인 레이어가 아니라, 세심한 검토를 거친 뒤 이러한 표준을 중심으로 설계되었습니다.\n* 이는 또한 다양한 언어로 자동 **클라이언트 코드 생성**을 사용할 수 있게 해줍니다.\n\n### 문서 자동화 { #automatic-docs }\n\n대화형 API 문서와 탐색용 웹 사용자 인터페이스를 제공합니다. 프레임워크가 OpenAPI를 기반으로 하기에 여러 옵션이 있으며, 기본으로 2가지가 포함됩니다.\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui)로 대화형 탐색이 가능하며 브라우저에서 직접 API를 호출하고 테스트할 수 있습니다.\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* [**ReDoc**](https://github.com/Rebilly/ReDoc)을 이용한 대체 API 문서화.\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### 그저 현대 파이썬 { #just-modern-python }\n\n(Pydantic 덕분에) 모든 것이 표준 **Python 타입** 선언을 기반으로 합니다. 새로 배울 문법이 없습니다. 그저 표준적인 현대 파이썬입니다.\n\nPython 타입을 어떻게 사용하는지 2분 정도 복습이 필요하다면(FastAPI를 사용하지 않더라도), 다음의 짧은 자습서를 확인하세요: [Python 타입](python-types.md).\n\n여러분은 타입이 있는 표준 Python을 다음과 같이 작성합니다:\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# 변수를 str로 선언합니다\n# 그리고 함수 내부에서 편집기 지원을 받습니다\ndef main(user_id: str):\n    return user_id\n\n\n# Pydantic 모델\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\n그 다음 다음과 같이 사용할 수 있습니다:\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n/// info | 정보\n\n`**second_user_data`는 다음을 의미합니다:\n\n`second_user_data` `dict`의 키와 값을 키-값 인자로서 바로 넘겨주는 것으로, 다음과 동일합니다: `User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### 편집기 지원 { #editor-support }\n\n프레임워크 전체는 사용하기 쉽고 직관적으로 설계되었으며, 최고의 개발 경험을 보장하기 위해 개발을 시작하기도 전에 모든 결정은 여러 편집기에서 테스트되었습니다.\n\nPython 개발자 설문조사에서 [가장 많이 사용되는 기능 중 하나가 \"자동 완성\"이라는 점](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features)이 분명합니다.\n\n**FastAPI** 프레임워크 전체는 이를 만족하기 위해 만들어졌습니다. 자동 완성은 어디서나 작동합니다.\n\n문서로 다시 돌아올 일은 거의 없을 것입니다.\n\n편집기가 여러분을 어떻게 도와줄 수 있는지 살펴보세요:\n\n* [Visual Studio Code](https://code.visualstudio.com/)에서:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* [PyCharm](https://www.jetbrains.com/pycharm/)에서:\n\n![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\n이전에 불가능하다고 생각했을 코드에서도 자동 완성을 받을 수 있습니다. 예를 들어, 요청에서 전달되는(중첩될 수도 있는) JSON 본문 내부의 `price` 키 같은 경우입니다.\n\n더 이상 잘못된 키 이름을 입력하거나, 문서 사이를 왔다 갔다 하거나, `username`을 썼는지 `user_name`을 썼는지 찾으려고 위아래로 스크롤할 필요가 없습니다.\n\n### 간결함 { #short }\n\n선택적 구성을 어디서나 할 수 있도록 하면서도, 모든 것에 합리적인 **기본값**이 설정되어 있습니다. 모든 매개변수는 필요한 작업을 하거나 필요한 API를 정의하기 위해 미세하게 조정할 수 있습니다.\n\n하지만 기본적으로 모든 것이 **\"그냥 작동합니다\"**.\n\n### 검증 { #validation }\n\n* 다음을 포함해 대부분(혹은 전부?)의 Python **데이터 타입**에 대한 검증:\n    * JSON 객체 (`dict`).\n    * 아이템 타입을 정의하는 JSON 배열 (`list`).\n    * 최소/최대 길이를 정의하는 문자열(`str`) 필드.\n    * 최소/최대 값을 가지는 숫자(`int`, `float`) 등.\n\n* 다음과 같은 좀 더 이색적인 타입에 대한 검증:\n    * URL.\n    * Email.\n    * UUID.\n    * ...그 외.\n\n모든 검증은 잘 확립되어 있고 견고한 **Pydantic**이 처리합니다.\n\n### 보안과 인증 { #security-and-authentication }\n\n보안과 인증이 통합되어 있습니다. 데이터베이스나 데이터 모델과 타협하지 않습니다.\n\n다음을 포함해 OpenAPI에 정의된 모든 보안 스키마:\n\n* HTTP Basic.\n* **OAuth2**(**JWT tokens** 또한 포함). [JWT를 사용한 OAuth2](tutorial/security/oauth2-jwt.md) 자습서를 확인해 보세요.\n* 다음에 들어 있는 API 키:\n    * 헤더.\n    * 쿼리 매개변수.\n    * 쿠키 등.\n\n추가로 Starlette의 모든 보안 기능(**세션 쿠키** 포함)도 제공합니다.\n\n모두 재사용 가능한 도구와 컴포넌트로 만들어져 있어, 여러분의 시스템, 데이터 저장소, 관계형 및 NoSQL 데이터베이스 등과 쉽게 통합할 수 있습니다.\n\n### 의존성 주입 { #dependency-injection }\n\nFastAPI는 사용하기 매우 쉽지만, 매우 강력한 <dfn title='또한 다음으로도 불림: \"컴포넌트\", \"자원\", \"서비스\", \"제공자\"'><strong>의존성 주입</strong></dfn> 시스템을 포함하고 있습니다.\n\n* 의존성도 의존성을 가질 수 있어, 의존성의 계층 또는 **의존성의 \"그래프\"**를 생성합니다.\n* 모든 것이 프레임워크에 의해 **자동으로 처리됩니다**.\n* 모든 의존성은 요청에서 데이터를 요구할 수 있으며, **경로 처리** 제약과 자동 문서화를 강화할 수 있습니다.\n* 의존성에 정의된 *경로 처리* 매개변수에 대해서도 **자동 검증**을 합니다.\n* 복잡한 사용자 인증 시스템, **데이터베이스 연결** 등을 지원합니다.\n* 데이터베이스, 프론트엔드 등과 **타협하지 않습니다**. 하지만 모두와 쉽게 통합할 수 있습니다.\n\n### 제한 없는 \"플러그인\" { #unlimited-plug-ins }\n\n또 다른 방식으로는, 그것들이 필요 없습니다. 필요한 코드를 임포트해서 사용하면 됩니다.\n\n어떤 통합이든(의존성과 함께) 사용하기 매우 간단하도록 설계되어 있어, *경로 처리*에 사용된 것과 동일한 구조와 문법을 사용해 2줄의 코드로 애플리케이션용 \"플러그인\"을 만들 수 있습니다.\n\n### 테스트됨 { #tested }\n\n* 100% <dfn title=\"자동으로 테스트되는 코드의 양\">테스트 커버리지</dfn>.\n* 100% <dfn title=\"Python 타입 어노테이션으로, 이를 통해 편집기와 외부 도구가 더 나은 지원을 제공할 수 있습니다\">타입 어노테이션</dfn> 코드 베이스.\n* 프로덕션 애플리케이션에서 사용됩니다.\n\n## Starlette 기능 { #starlette-features }\n\n**FastAPI**는 [**Starlette**](https://www.starlette.dev/)와 완전히 호환되며(또한 이를 기반으로 합니다). 따라서 추가로 가지고 있는 Starlette 코드도 모두 동작합니다.\n\n`FastAPI`는 실제로 `Starlette`의 하위 클래스입니다. 그래서 Starlette을 이미 알고 있거나 사용하고 있다면, 대부분의 기능이 같은 방식으로 동작할 것입니다.\n\n**FastAPI**를 사용하면 **Starlette**의 모든 기능을 얻게 됩니다(FastAPI는 Starlette에 강력한 기능을 더한 것입니다):\n\n* 정말 인상적인 성능. [**NodeJS**와 **Go**에 버금가는, 사용 가능한 가장 빠른 Python 프레임워크 중 하나입니다](https://github.com/encode/starlette#performance).\n* **WebSocket** 지원.\n* 프로세스 내 백그라운드 작업.\n* 시작 및 종료 이벤트.\n* HTTPX 기반 테스트 클라이언트.\n* **CORS**, GZip, 정적 파일, 스트리밍 응답.\n* **세션과 쿠키** 지원.\n* 100% test coverage.\n* 100% type annotated codebase.\n\n## Pydantic 기능 { #pydantic-features }\n\n**FastAPI**는 [**Pydantic**](https://docs.pydantic.dev/)과 완벽하게 호환되며(또한 이를 기반으로 합니다). 따라서 추가로 가지고 있는 Pydantic 코드도 모두 동작합니다.\n\n데이터베이스를 위한 <abbr title=\"Object-Relational Mapper - 객체-관계 매퍼\">ORM</abbr>, <abbr title=\"Object-Document Mapper - 객체-문서 매퍼\">ODM</abbr>과 같은, Pydantic을 기반으로 하는 외부 라이브러리도 포함합니다.\n\n이는 모든 것이 자동으로 검증되기 때문에, 많은 경우 요청에서 얻은 동일한 객체를 **직접 데이터베이스로** 넘겨줄 수 있다는 의미이기도 합니다.\n\n반대로도 마찬가지이며, 많은 경우 데이터베이스에서 얻은 객체를 **직접 클라이언트로** 그대로 넘겨줄 수 있습니다.\n\n**FastAPI**를 사용하면(모든 데이터 처리를 위해 FastAPI가 Pydantic을 기반으로 하기에) **Pydantic**의 모든 기능을 얻게 됩니다:\n\n* **No brainfuck**:\n    * 새로운 스키마 정의 마이크로 언어를 배울 필요가 없습니다.\n    * Python 타입을 알고 있다면 Pydantic 사용법도 알고 있는 것입니다.\n* 여러분의 **<abbr title=\"Integrated Development Environment - 통합 개발 환경: 코드 편집기와 비슷합니다\">IDE</abbr>/<dfn title=\"코드 오류를 확인하는 프로그램\">린터</dfn>/뇌**와 잘 어울립니다:\n    * pydantic 데이터 구조는 여러분이 정의한 클래스 인스턴스일 뿐이므로, 자동 완성, 린팅, mypy, 그리고 직관까지도 검증된 데이터와 함께 제대로 작동합니다.\n* **복잡한 구조**를 검증합니다:\n    * 계층적인 Pydantic 모델, Python `typing`의 `List`와 `Dict` 등을 사용합니다.\n    * 그리고 validator는 복잡한 데이터 스키마를 명확하고 쉽게 정의하고, 검사하고, JSON Schema로 문서화할 수 있게 해줍니다.\n    * 깊게 **중첩된 JSON** 객체를 가질 수 있으며, 이를 모두 검증하고 주석을 달 수 있습니다.\n* **확장 가능**:\n    * Pydantic은 사용자 정의 데이터 타입을 정의할 수 있게 하거나, validator decorator가 붙은 모델 메서드로 검증을 확장할 수 있습니다.\n* 100% test coverage.\n"
  },
  {
    "path": "docs/ko/docs/help-fastapi.md",
    "content": "# FastAPI 지원 - 도움 받기 { #help-fastapi-get-help }\n\n**FastAPI** 가 마음에 드시나요?\n\nFastAPI, 다른 사용자, 개발자를 응원하고 싶으신가요?\n\n혹은 **FastAPI** 에 대해 도움이 필요하신가요?\n\n아주 간단하게 응원할 수 있습니다 (몇 번의 클릭만으로).\n\n또한 도움을 받을 수 있는 방법도 몇 가지 있습니다.\n\n## 뉴스레터 구독 { #subscribe-to-the-newsletter }\n\n(자주 발송되지 않는) [**FastAPI and friends** 뉴스레터](newsletter.md)를 구독하여 최신 정보를 유지할 수 있습니다:\n\n* FastAPI and friends에 대한 뉴스 🚀\n* 가이드 📝\n* 기능 ✨\n* 획기적인 변화 🚨\n* 팁과 요령 ✅\n\n## X(Twitter)에서 FastAPI 팔로우하기 { #follow-fastapi-on-x-twitter }\n\n[**X (Twitter)**의 @fastapi를 팔로우](https://x.com/fastapi)하여 **FastAPI** 에 대한 최신 뉴스를 얻을 수 있습니다. 🐦\n\n## GitHub에서 **FastAPI**에 Star 주기 { #star-fastapi-in-github }\n\nGitHub에서 FastAPI에 \"star\"를 붙일 수 있습니다 (오른쪽 상단의 star 버튼을 클릭): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). ⭐️\n\n스타를 늘림으로써, 다른 사용자들이 좀 더 쉽게 찾을 수 있고, 많은 사람들에게 유용한 것임을 나타낼 수 있습니다.\n\n## 릴리즈 확인을 위해 GitHub 저장소 보기 { #watch-the-github-repository-for-releases }\n\nGitHub에서 FastAPI를 \"watch\"할 수 있습니다 (오른쪽 상단 \"watch\" 버튼을 클릭): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\n여기서 \"Releases only\"를 선택할 수 있습니다.\n\n이렇게하면, **FastAPI** 의 버그 수정 및 새로운 기능의 구현 등의 새로운 릴리즈(새 버전)가 있을 때마다 (이메일) 통지를 받을 수 있습니다.\n\n## 개발자와의 연결 { #connect-with-the-author }\n\n개발자(작성자)인 [저(Sebastián Ramírez / `tiangolo`)](https://tiangolo.com)와 연락을 취할 수 있습니다.\n\n여러분은 할 수 있습니다:\n\n* [**GitHub**에서 팔로우하기](https://github.com/tiangolo).\n    * 여러분에게 도움이 될 저의 다른 오픈소스 프로젝트를 확인하십시오.\n    * 새로운 오픈소스 프로젝트를 만들었을 때 확인하려면 팔로우 하십시오.\n* [**X (Twitter)**](https://x.com/tiangolo) 또는 [Mastodon](https://fosstodon.org/@tiangolo)에서 팔로우하기.\n    * FastAPI의 사용 용도를 알려주세요 (그것을 듣는 것을 좋아합니다).\n    * 발표나 새로운 툴 출시 소식을 받아보십시오.\n    * [X(Twitter)에서 @fastapi를 팔로우](https://x.com/fastapi) (별도 계정에서) 할 수 있습니다.\n* [**LinkedIn**에서 팔로우하기](https://www.linkedin.com/in/tiangolo/).\n    * 새로운 툴의 발표나 출시 소식을 받아보십시오 (단, X (Twitter)를 더 자주 사용합니다 🤷‍♂).\n* [**Dev.to**](https://dev.to/tiangolo) 또는 [**Medium**](https://medium.com/@tiangolo)에서 제가 작성한 내용을 읽어 보십시오 (또는 팔로우).\n    * 다른 아이디어와 기사들을 읽고, 제가 만들어왔던 툴에 대해서도 읽으십시오.\n    * 새로운 내용을 게시할 때 읽기 위해 팔로우 하십시오.\n\n## **FastAPI**에 대해 트윗하기 { #tweet-about-fastapi }\n\n[**FastAPI**에 대해 트윗](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi) 하고 저와 다른 사람들에게 FastAPI가 마음에 드는 이유를 알려주세요. 🎉\n\n**FastAPI**가 어떻게 사용되고 있는지, 어떤 점이 마음에 들었는지, 어떤 프로젝트/회사에서 사용하고 있는지 등에 대해 듣고 싶습니다.\n\n## FastAPI에 투표하기 { #vote-for-fastapi }\n\n* [Slant에서 **FastAPI** 에 대해 투표하십시오](https://www.slant.co/options/34241/~fastapi-review).\n* [AlternativeTo에서 **FastAPI** 에 대해 투표하십시오](https://alternativeto.net/software/fastapi/about/).\n* [StackShare에서 **FastAPI**를 사용한다고 표시하세요](https://stackshare.io/pypi-fastapi).\n\n## GitHub에서 질문으로 다른 사람 돕기 { #help-others-with-questions-in-github }\n\n다른 사람들의 질문에 도움을 줄 수 있습니다:\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\n많은 경우, 여러분은 이미 그 질문에 대한 답을 알고 있을 수도 있습니다. 🤓\n\n만약 많은 사람들의 질문을 도와준다면, 공식적인 [FastAPI 전문가](fastapi-people.md#fastapi-experts)가 될 것입니다. 🎉\n\n가장 중요한 점은: 친절하려고 노력하는 것입니다. 사람들은 좌절감을 안고 오며, 많은 경우 최선의 방식으로 질문하지 않을 수도 있습니다. 하지만 최대한 친절하게 대하려고 노력하세요. 🤗\n\n**FastAPI** 커뮤니티의 목표는 친절하고 환영하는 것입니다. 동시에, 괴롭힘이나 무례한 행동을 받아들이지 마세요. 우리는 서로를 돌봐야 합니다.\n\n---\n\n다른 사람들의 질문(디스커션 또는 이슈에서) 해결을 도울 수 있는 방법은 다음과 같습니다.\n\n### 질문 이해하기 { #understand-the-question }\n\n* 질문하는 사람이 가진 **목적**과 사용 사례를 이해할 수 있는지 확인하세요.\n\n* 그런 다음 질문(대부분은 질문입니다)이 **명확**한지 확인하세요.\n\n* 많은 경우 사용자가 상상한 해결책에 대한 질문을 하지만, 더 **좋은** 해결책이 있을 수 있습니다. 문제와 사용 사례를 더 잘 이해하면 더 나은 **대안적인 해결책**을 제안할 수 있습니다.\n\n* 질문을 이해할 수 없다면, 더 **자세한 정보**를 요청하세요.\n\n### 문제 재현하기 { #reproduce-the-problem }\n\n대부분의 경우 그리고 대부분의 질문에서는 질문자의 **원본 코드**와 관련된 내용이 있습니다.\n\n많은 경우, 코드의 일부만 복사해서 올리지만, 그것만으로는 **문제를 재현**하기에 충분하지 않습니다.\n\n* 질문자에게 [최소한의 재현 가능한 예제](https://stackoverflow.com/help/minimal-reproducible-example)를 제공해달라고 요청할 수 있습니다. 이렇게 하면 코드를 **복사-붙여넣기**하여 로컬에서 실행하고, 질문자가 보고 있는 것과 동일한 오류나 동작을 확인하거나 사용 사례를 더 잘 이해할 수 있습니다.\n\n* 너그러운 마음이 든다면, 문제 설명만을 기반으로 직접 **예제를 만들어**볼 수도 있습니다. 다만 이는 시간이 많이 걸릴 수 있으므로, 먼저 문제를 명확히 해달라고 요청하는 것이 더 나을 수 있다는 점을 기억하세요.\n\n### 해결책 제안하기 { #suggest-solutions }\n\n* 질문을 충분히 이해한 후에는 가능한 **답변**을 제공할 수 있습니다.\n\n* 많은 경우, 질문자의 **근본적인 문제나 사용 사례**를 이해하는 것이 더 좋습니다. 그들이 시도하는 방법보다 더 나은 해결책이 있을 수 있기 때문입니다.\n\n### 종료 요청하기 { #ask-to-close }\n\n질문자가 답변을 하면, 여러분이 문제를 해결했을 가능성이 높습니다. 축하합니다, **여러분은 영웅입니다**! 🦸\n\n* 이제 문제를 해결했다면, 질문자에게 다음을 요청할 수 있습니다.\n\n    * GitHub Discussions에서: 댓글을 **답변**으로 표시하도록 요청하세요.\n    * GitHub Issues에서: 이슈를 **닫아달라고** 요청하세요.\n\n## GitHub 저장소 보기 { #watch-the-github-repository }\n\nGitHub에서 FastAPI를 \"watch\"할 수 있습니다 (오른쪽 상단 \"watch\" 버튼을 클릭): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\n\"Releases only\" 대신 \"Watching\"을 선택하면 누군가가 새 이슈나 질문을 만들 때 알림을 받게 됩니다. 또한 새 이슈, 디스커션, PR 등만 알림을 받도록 지정할 수도 있습니다.\n\n그런 다음 이런 질문들을 해결하도록 도와줄 수 있습니다.\n\n## 질문하기 { #ask-questions }\n\nGitHub 저장소에서 [새 질문을 생성](https://github.com/fastapi/fastapi/discussions/new?category=questions)할 수 있습니다. 예를 들면 다음과 같습니다:\n\n* **질문**을 하거나 **문제**에 대해 질문합니다.\n* 새로운 **기능**을 제안 합니다.\n\n**참고**: 만약 이렇게 한다면, 저는 여러분에게 다른 사람들도 도와달라고 요청할 것입니다. 😉\n\n## Pull Request 리뷰하기 { #review-pull-requests }\n\n다른 사람들이 만든 pull request를 리뷰하는 데 저를 도와줄 수 있습니다.\n\n다시 한번 말하지만, 최대한 친절하게 리뷰해 주세요. 🤗\n\n---\n\nPull request를 리뷰할 때 고려해야 할 사항과 방법은 다음과 같습니다:\n\n### 문제 이해하기 { #understand-the-problem }\n\n* 먼저, 해당 pull request가 해결하려는 **문제를 이해하는지** 확인하세요. GitHub Discussion 또는 이슈에서 더 긴 논의가 있었을 수도 있습니다.\n\n* Pull request가 실제로 필요하지 않을 가능성도 큽니다. 문제가 **다른 방식**으로 해결될 수 있기 때문입니다. 그런 경우 그 방법을 제안하거나 질문할 수 있습니다.\n\n### 스타일에 너무 신경 쓰지 않기 { #dont-worry-about-style }\n\n* 커밋 메시지 스타일 같은 것에 너무 신경 쓰지 마세요. 저는 커밋을 수동으로 조정해서 squash and merge를 할 것입니다.\n\n* 코드 스타일 규칙도 걱정할 필요 없습니다. 이미 자동화된 도구들이 이를 검사하고 있습니다.\n\n그리고 다른 스타일이나 일관성 관련 필요 사항이 있다면, 제가 직접 요청하거나 필요한 변경 사항을 위에 커밋으로 추가할 것입니다.\n\n### 코드 확인하기 { #check-the-code }\n\n* 코드를 확인하고 읽어서 말이 되는지 보고, **로컬에서 실행**해 실제로 문제가 해결되는지 확인하세요.\n\n* 그런 다음 그렇게 했다고 **댓글**로 남겨 주세요. 그래야 제가 정말로 확인했음을 알 수 있습니다.\n\n/// info | 정보\n\n불행히도, 제가 단순히 여러 개의 승인만으로 PR을 신뢰할 수는 없습니다.\n\n여러 번, 설명이 그럴듯해서인지 3개, 5개 이상의 승인이 달린 PR이 있었지만, 제가 확인해보면 실제로는 깨져 있거나, 버그가 있거나, 주장하는 문제를 해결하지 못하는 경우가 있었습니다. 😅\n\n따라서, 정말로 코드를 읽고 실행한 뒤, 댓글로 확인 내용을 남겨 주는 것이 매우 중요합니다. 🤓\n\n///\n\n* PR을 더 단순하게 만들 수 있다면 그렇게 요청할 수 있지만, 너무 까다로울 필요는 없습니다. 주관적인 견해가 많이 있을 수 있기 때문입니다(그리고 저도 제 견해가 있을 거예요 🙈). 따라서 핵심적인 부분에 집중하는 것이 좋습니다.\n\n### 테스트 { #tests }\n\n* PR에 **테스트**가 포함되어 있는지 확인하는 데 도움을 주세요.\n\n* PR 전에는 테스트가 **실패**하는지 확인하세요. 🚨\n\n* 그런 다음 PR 후에는 테스트가 **통과**하는지 확인하세요. ✅\n\n* 많은 PR에는 테스트가 없습니다. 테스트를 추가하도록 **상기**시켜줄 수도 있고, 직접 테스트를 **제안**할 수도 있습니다. 이는 시간이 가장 많이 드는 것들 중 하나이며, 그 부분을 많이 도와줄 수 있습니다.\n\n* 그리고 시도한 내용을 댓글로 남겨주세요. 그러면 제가 확인했다는 걸 알 수 있습니다. 🤓\n\n## Pull Request 만들기 { #create-a-pull-request }\n\nPull Requests를 이용하여 소스 코드에 [기여](contributing.md)할 수 있습니다. 예를 들면 다음과 같습니다:\n\n* 문서에서 발견한 오타를 수정할 때.\n* FastAPI에 대한 글, 비디오, 팟캐스트를 작성했거나 발견했다면 [이 파일을 편집](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml)하여 공유할 때.\n    * 해당 섹션의 시작 부분에 링크를 추가해야 합니다.\n* 여러분의 언어로 [문서 번역에](contributing.md#translations) 도움을 줄 때.\n    * 다른 사람이 작성한 번역을 검토하는 것도 도울 수 있습니다.\n* 새로운 문서 섹션을 제안할 때.\n* 기존 이슈/버그를 수정할 때.\n    * 테스트를 반드시 추가해야 합니다.\n* 새로운 기능을 추가할 때.\n    * 테스트를 반드시 추가해야 합니다.\n    * 관련 문서가 있다면 반드시 추가해야 합니다.\n\n## FastAPI 유지 관리 돕기 { #help-maintain-fastapi }\n\n**FastAPI** 유지를 도와주세요! 🤓\n\n할 일이 많고, 그중 대부분은 **여러분**이 할 수 있습니다.\n\n지금 할 수 있는 주요 작업은:\n\n* [GitHub에서 질문으로 다른 사람 돕기](#help-others-with-questions-in-github) (위의 섹션을 참조하세요).\n* [Pull Request 리뷰하기](#review-pull-requests) (위의 섹션을 참조하세요).\n\n이 두 작업이 **가장 많은 시간을 소모**합니다. 이것이 FastAPI를 유지 관리하는 주요 작업입니다.\n\n이 작업을 도와주신다면, **FastAPI 유지를 돕는 것**이며 FastAPI가 **더 빠르고 더 잘 발전하는 것**을 보장하는 것입니다. 🚀\n\n## 채팅에 참여하기 { #join-the-chat }\n\n👥 [Discord 채팅 서버](https://discord.gg/VQjSZaeJmf) 👥 에 참여해서 FastAPI 커뮤니티의 다른 사람들과 어울리세요.\n\n/// tip | 팁\n\n질문은 [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions)에서 하세요. [FastAPI Experts](fastapi-people.md#fastapi-experts)로부터 도움을 받을 가능성이 훨씬 높습니다.\n\n채팅은 다른 일반적인 대화를 위해서만 사용하세요.\n\n///\n\n### 질문을 위해 채팅을 사용하지 마세요 { #dont-use-the-chat-for-questions }\n\n채팅은 더 많은 \"자유로운 대화\"를 허용하기 때문에, 너무 일반적인 질문이나 답하기 어려운 질문을 쉽게 할 수 있어 답변을 받지 못할 수도 있다는 점을 기억하세요.\n\nGitHub에서는 템플릿이 올바른 질문을 작성하도록 안내하여 더 쉽게 좋은 답변을 얻거나, 질문하기 전에 스스로 문제를 해결할 수도 있습니다. 그리고 GitHub에서는 시간이 조금 걸리더라도 제가 항상 모든 것에 답하도록 보장할 수 있습니다. 채팅 시스템에서는 제가 개인적으로 그렇게 할 수 없습니다. 😅\n\n채팅 시스템에서의 대화 또한 GitHub만큼 쉽게 검색할 수 없기 때문에, 질문과 답변이 대화 속에서 사라질 수 있습니다. 그리고 GitHub에 있는 것만 [FastAPI Expert](fastapi-people.md#fastapi-experts)가 되는 것으로 인정되므로, GitHub에서 더 많은 관심을 받게 될 가능성이 큽니다.\n\n반면, 채팅 시스템에는 수천 명의 사용자가 있으므로, 거의 항상 대화 상대를 찾을 가능성이 높습니다. 😄\n\n## 개발자 스폰서 되기 { #sponsor-the-author }\n\n여러분의 **제품/회사**가 **FastAPI**에 의존하거나 관련되어 있고, FastAPI 사용자를 대상으로 알리고 싶다면 [GitHub sponsors](https://github.com/sponsors/tiangolo)를 통해 개발자(저)를 스폰서할 수 있습니다. 티어에 따라 문서에 배지 같은 추가 혜택을 받을 수도 있습니다. 🎁\n\n---\n\n감사합니다! 🚀\n"
  },
  {
    "path": "docs/ko/docs/history-design-future.md",
    "content": "# 역사, 디자인 그리고 미래 { #history-design-and-future }\n\n얼마 전, [한 **FastAPI** 사용자가 이렇게 물었습니다](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920):\n\n> 이 프로젝트의 역사는 무엇인가요? 몇 주 만에 아무 데서도 갑자기 나타나 엄청나게 좋아진 것처럼 보이네요 [...]\n\n여기서 그 역사에 대해 간단히 설명하겠습니다.\n\n## 대안 { #alternatives }\n\n저는 여러 해 동안 복잡한 요구사항(머신러닝, 분산 시스템, 비동기 작업, NoSQL 데이터베이스 등)을 가진 API를 만들면서 여러 개발 팀을 이끌어 왔습니다.\n\n그 과정에서 많은 대안을 조사하고, 테스트하고, 사용해야 했습니다.\n\n**FastAPI**의 역사는 상당 부분 그 이전에 있던 도구들의 역사입니다.\n\n[대안](alternatives.md) 섹션에서 언급된 것처럼:\n\n<blockquote markdown=\"1\">\n\n**FastAPI**는 다른 사람들이 이전에 해온 작업이 없었다면 존재하지 않았을 것입니다.\n\n그 전에 만들어진 많은 도구들이 이것의 탄생에 영감을 주었습니다.\n\n저는 여러 해 동안 새로운 프레임워크를 만드는 것을 피하고 있었습니다. 처음에는 **FastAPI**가 다루는 모든 기능을 여러 다른 프레임워크, 플러그인, 도구들을 사용해 해결하려고 했습니다.\n\n하지만 어느 시점에는, 이전 도구들의 최고의 아이디어를 가져와 가능한 한 최선의 방식으로 조합하고, 이전에는 존재하지 않았던 언어 기능(Python 3.6+ type hints)을 사용해 이 모든 기능을 제공하는 무언가를 만드는 것 외에는 다른 선택지가 없었습니다.\n\n</blockquote>\n\n## 조사 { #investigation }\n\n이전의 모든 대안을 사용해 보면서, 각 도구로부터 배울 기회를 얻었고, 아이디어를 가져와 제가 일해온 개발 팀들과 저 자신에게 가장 적합하다고 찾은 방식으로 조합할 수 있었습니다.\n\n예를 들어, 이상적으로는 표준 Python 타입 힌트에 기반해야 한다는 점이 분명했습니다.\n\n또한, 가장 좋은 접근법은 이미 존재하는 표준을 사용하는 것이었습니다.\n\n그래서 **FastAPI**의 코딩을 시작하기도 전에, OpenAPI, JSON Schema, OAuth2 등과 같은 명세를 몇 달 동안 공부했습니다. 이들의 관계, 겹치는 부분, 차이점을 이해하기 위해서였습니다.\n\n## 디자인 { #design }\n\n그 다음에는 (FastAPI를 사용하는 개발자로서) 사용자로서 갖고 싶었던 개발자 \"API\"를 디자인하는 데 시간을 썼습니다.\n\n가장 인기 있는 Python 편집기들: PyCharm, VS Code, Jedi 기반 편집기에서 여러 아이디어를 테스트했습니다.\n\n약 80%의 사용자를 포함하는 최근 [Python Developer Survey](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools)에 따르면 그렇습니다.\n\n즉, **FastAPI**는 Python 개발자의 80%가 사용하는 편집기들로 특별히 테스트되었습니다. 그리고 대부분의 다른 편집기도 유사하게 동작하는 경향이 있으므로, 그 모든 이점은 사실상 모든 편집기에서 동작해야 합니다.\n\n그렇게 해서 코드 중복을 가능한 한 많이 줄이고, 어디서나 자동 완성, 타입 및 에러 검사 등을 제공하는 최선의 방법을 찾을 수 있었습니다.\n\n모든 개발자에게 최고의 개발 경험을 제공하는 방식으로 말입니다.\n\n## 필요조건 { #requirements }\n\n여러 대안을 테스트한 후, 장점 때문에 [**Pydantic**](https://docs.pydantic.dev/)을 사용하기로 결정했습니다.\n\n그 후, JSON Schema를 완전히 준수하도록 하고, 제약 조건 선언을 정의하는 다양한 방식을 지원하며, 여러 편집기에서의 테스트를 바탕으로 편집기 지원(타입 검사, 자동 완성)을 개선하기 위해 기여했습니다.\n\n개발 과정에서, 또 다른 핵심 필요조건인 [**Starlette**](https://www.starlette.dev/)에도 기여했습니다.\n\n## 개발 { #development }\n\n**FastAPI** 자체를 만들기 시작했을 때쯤에는, 대부분의 조각들이 이미 갖춰져 있었고, 디자인은 정의되어 있었며, 필요조건과 도구는 준비되어 있었고, 표준과 명세에 대한 지식도 명확하고 최신 상태였습니다.\n\n## 미래 { #future }\n\n이 시점에는, **FastAPI**가 그 아이디어와 함께 많은 사람들에게 유용하다는 것이 이미 분명합니다.\n\n많은 사용 사례에 더 잘 맞기 때문에 이전 대안들보다 선택되고 있습니다.\n\n많은 개발자와 팀이 이미 자신의 프로젝트를 위해 **FastAPI**에 의존하고 있습니다(저와 제 팀도 포함해서요).\n\n하지만 여전히, 앞으로 나올 개선 사항과 기능들이 많이 있습니다.\n\n**FastAPI**의 미래는 밝습니다.\n\n그리고 [여러분의 도움](help-fastapi.md)은 큰 힘이 됩니다.\n"
  },
  {
    "path": "docs/ko/docs/how-to/authentication-error-status-code.md",
    "content": "# 이전 403 인증 오류 상태 코드 사용하기 { #use-old-403-authentication-error-status-codes }\n\nFastAPI 버전 `0.122.0` 이전에는, 통합 보안 유틸리티가 인증 실패 후 클라이언트에 오류를 반환할 때 HTTP 상태 코드 `403 Forbidden`을 사용했습니다.\n\nFastAPI 버전 `0.122.0`부터는 더 적절한 HTTP 상태 코드 `401 Unauthorized`를 사용하며, HTTP 명세인 [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized)를 따라 응답에 합리적인 `WWW-Authenticate` 헤더를 반환합니다.\n\n하지만 어떤 이유로든 클라이언트가 이전 동작에 의존하고 있다면, 보안 클래스에서 `make_not_authenticated_error` 메서드를 오버라이드하여 이전 동작으로 되돌릴 수 있습니다.\n\n예를 들어, 기본값인 `401 Unauthorized` 오류 대신 `403 Forbidden` 오류를 반환하는 `HTTPBearer`의 서브클래스를 만들 수 있습니다:\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip | 팁\n\n함수는 예외를 `return`하는 것이지 `raise`하지 않는다는 점에 유의하세요. 예외를 발생시키는(`raise`) 작업은 내부 코드의 나머지 부분에서 수행됩니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/how-to/conditional-openapi.md",
    "content": "# 조건부 OpenAPI { #conditional-openapi }\n\n필요한 경우, 설정 및 환경 변수를 사용하여 환경에 따라 OpenAPI를 조건부로 구성하고 완전히 비활성화할 수도 있습니다.\n\n## 보안, API 및 docs에 대해서 { #about-security-apis-and-docs }\n\n프로덕션에서, 문서화된 사용자 인터페이스(UI)를 숨기는 것이 API를 보호하는 방법이 되어서는 안 됩니다.\n\n이는 API에 추가적인 보안을 제공하지 않으며, *경로 처리*는 여전히 동일한 위치에서 사용 할 수 있습니다.\n\n코드에 보안 결함이 있다면, 그 결함은 여전히 존재할 것입니다.\n\n문서를 숨기는 것은 API와 상호작용하는 방법을 이해하기 어렵게 만들며, 프로덕션에서 디버깅을 더 어렵게 만들 수 있습니다. 이는 단순히 [은폐를 통한 보안](https://en.wikipedia.org/wiki/Security_through_obscurity)의 한 형태로 간주될 수 있습니다.\n\nAPI를 보호하고 싶다면, 예를 들어 다음과 같은 더 나은 방법들이 있습니다:\n\n* 요청 본문과 응답에 대해 잘 정의된 Pydantic 모델이 있는지 확인하세요.\n* 종속성을 사용하여 필요한 권한과 역할을 구성하세요.\n* 평문 비밀번호를 절대 저장하지 말고, 비밀번호 해시만 저장하세요.\n* pwdlib와 JWT 토큰 등과 같은 잘 알려진 암호화 도구들을 구현하고 사용하세요.\n* 필요한 곳에 OAuth2 범위를 사용하여 더 세분화된 권한 제어를 추가하세요.\n* ...등등.\n\n그럼에도 불구하고, 특정 환경(예: 프로덕션)에서 또는 환경 변수의 설정에 따라 API docs를 비활성화해야 하는 매우 특정한 사용 사례가 있을 수 있습니다.\n\n## 설정 및 환경변수의 조건부 OpenAPI { #conditional-openapi-from-settings-and-env-vars }\n\n동일한 Pydantic 설정을 사용하여 생성된 OpenAPI 및 docs UI를 쉽게 구성할 수 있습니다.\n\n예를 들어:\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\n여기서 `openapi_url` 설정을 기본값인 `\"/openapi.json\"`으로 선언합니다.\n\n그런 뒤, 우리는 `FastAPI` 앱을 만들 때 그것을 사용합니다.\n\n그런 다음 환경 변수 `OPENAPI_URL`을 빈 문자열로 설정하여 OpenAPI(UI docs 포함)를 비활성화할 수도 있습니다. 예를 들어:\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n그리고 `/openapi.json`, `/docs` 또는 `/redoc`의 URL로 이동하면 `404 Not Found`라는 오류가 다음과 같이 표시됩니다:\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/ko/docs/how-to/configure-swagger-ui.md",
    "content": "# Swagger UI 구성 { #configure-swagger-ui }\n\n추가적인 [Swagger UI 매개변수](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)를 구성할 수 있습니다.\n\n구성을 하려면, `FastAPI()` 앱 객체를 생성할 때 또는 `get_swagger_ui_html()` 함수에 `swagger_ui_parameters` 인수를 전달하십시오.\n\n`swagger_ui_parameters`는 Swagger UI에 직접 전달된 구성을 포함하는 딕셔너리를 받습니다.\n\nFastAPI는 이 구성을 **JSON** 형식으로 변환하여 JavaScript와 호환되도록 합니다. 이는 Swagger UI에서 필요로 하는 형식입니다.\n\n## 구문 강조 비활성화 { #disable-syntax-highlighting }\n\n예를 들어, Swagger UI에서 구문 강조 기능을 비활성화할 수 있습니다.\n\n설정을 변경하지 않으면, 기본적으로 구문 강조 기능이 활성화되어 있습니다:\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\n그러나 `syntaxHighlight`를 `False`로 설정하여 구문 강조 기능을 비활성화할 수 있습니다:\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n...그럼 Swagger UI에서 더 이상 구문 강조 기능이 표시되지 않습니다:\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## 테마 변경 { #change-the-theme }\n\n동일한 방식으로 `\"syntaxHighlight.theme\"` 키를 사용하여 구문 강조 테마를 설정할 수 있습니다 (중간에 점이 포함된 것을 참고하십시오).\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\n이 설정은 구문 강조 색상 테마를 변경합니다:\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## 기본 Swagger UI 매개변수 변경 { #change-default-swagger-ui-parameters }\n\nFastAPI는 대부분의 사용 사례에 적합한 몇 가지 기본 구성 매개변수를 포함하고 있습니다.\n\n기본 구성에는 다음이 포함됩니다:\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\n`swagger_ui_parameters` 인수에 다른 값을 설정하여 이러한 기본값 중 어느 것이든 재정의할 수 있습니다.\n\n예를 들어, `deepLinking`을 비활성화하려면 `swagger_ui_parameters`에 다음 설정을 전달할 수 있습니다:\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## 기타 Swagger UI 매개변수 { #other-swagger-ui-parameters }\n\n사용할 수 있는 다른 모든 구성 옵션을 확인하려면, 공식 [Swagger UI 매개변수 문서](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)를 참조하십시오.\n\n## JavaScript 전용 설정 { #javascript-only-settings }\n\nSwagger UI는 **JavaScript 전용** 객체(예: JavaScript 함수)로 다른 구성을 허용하기도 합니다.\n\nFastAPI는 이러한 JavaScript 전용 `presets` 설정을 포함하고 있습니다:\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\n이들은 문자열이 아닌 **JavaScript** 객체이므로 Python 코드에서 직접 전달할 수 없습니다.\n\n이와 같은 JavaScript 전용 구성을 사용해야 하는 경우, 위의 방법 중 하나를 사용할 수 있습니다. Swagger UI *경로 처리*를 모두 재정의하고 필요한 JavaScript를 수동으로 작성하세요.\n"
  },
  {
    "path": "docs/ko/docs/how-to/custom-docs-ui-assets.md",
    "content": "# 커스텀 Docs UI 정적 에셋(자체 호스팅) { #custom-docs-ui-static-assets-self-hosting }\n\nAPI 문서는 **Swagger UI**와 **ReDoc**을 사용하며, 각각 JavaScript와 CSS 파일이 필요합니다.\n\n기본적으로 이러한 파일은 <abbr title=\"Content Delivery Network - 콘텐츠 전송 네트워크: 일반적으로 여러 서버로 구성되어 JavaScript와 CSS 같은 정적 파일을 제공하는 서비스입니다. 보통 클라이언트에 더 가까운 서버에서 파일을 제공해 성능을 향상시키는 데 사용됩니다.\">CDN</abbr>에서 제공됩니다.\n\n하지만 이를 커스터마이징할 수 있으며, 특정 CDN을 지정하거나 파일을 직접 제공할 수도 있습니다.\n\n## JavaScript와 CSS용 커스텀 CDN { #custom-cdn-for-javascript-and-css }\n\n예를 들어 다른 <abbr title=\"Content Delivery Network - 콘텐츠 전송 네트워크\">CDN</abbr>을 사용하고 싶다고 해봅시다. 예를 들면 `https://unpkg.com/`을 사용하려는 경우입니다.\n\n이는 예를 들어 특정 국가에서 일부 URL을 제한하는 경우에 유용할 수 있습니다.\n\n### 자동 문서 비활성화하기 { #disable-the-automatic-docs }\n\n첫 번째 단계는 자동 문서를 비활성화하는 것입니다. 기본적으로 자동 문서는 기본 CDN을 사용하기 때문입니다.\n\n비활성화하려면 `FastAPI` 앱을 생성할 때 해당 URL을 `None`으로 설정하세요:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### 커스텀 문서 포함하기 { #include-the-custom-docs }\n\n이제 커스텀 문서를 위한 *경로 처리*를 만들 수 있습니다.\n\nFastAPI 내부 함수를 재사용해 문서용 HTML 페이지를 생성하고, 필요한 인자를 전달할 수 있습니다:\n\n* `openapi_url`: 문서 HTML 페이지가 API의 OpenAPI 스키마를 가져올 수 있는 URL입니다. 여기서는 `app.openapi_url` 속성을 사용할 수 있습니다.\n* `title`: API의 제목입니다.\n* `oauth2_redirect_url`: 기본값을 사용하려면 여기서 `app.swagger_ui_oauth2_redirect_url`을 사용할 수 있습니다.\n* `swagger_js_url`: Swagger UI 문서의 HTML이 **JavaScript** 파일을 가져올 수 있는 URL입니다. 커스텀 CDN URL입니다.\n* `swagger_css_url`: Swagger UI 문서의 HTML이 **CSS** 파일을 가져올 수 있는 URL입니다. 커스텀 CDN URL입니다.\n\nReDoc도 마찬가지입니다...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip | 팁\n\n`swagger_ui_redirect`에 대한 *경로 처리*는 OAuth2를 사용할 때 도움이 되는 헬퍼입니다.\n\nAPI를 OAuth2 provider와 통합하면 인증을 수행한 뒤 획득한 자격 증명으로 API 문서로 다시 돌아올 수 있습니다. 그리고 실제 OAuth2 인증을 사용해 API와 상호작용할 수 있습니다.\n\nSwagger UI가 이 과정을 백그라운드에서 처리해 주지만, 이를 위해 이 \"redirect\" 헬퍼가 필요합니다.\n\n///\n\n### 테스트용 *경로 처리* 만들기 { #create-a-path-operation-to-test-it }\n\n이제 모든 것이 제대로 동작하는지 테스트할 수 있도록 *경로 처리*를 하나 만드세요:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### 테스트하기 { #test-it }\n\n이제 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)에서 문서에 접속한 뒤 페이지를 새로고침하면, 새 CDN에서 에셋을 불러오는 것을 확인할 수 있습니다.\n\n## 문서용 JavaScript와 CSS 자체 호스팅하기 { #self-hosting-javascript-and-css-for-docs }\n\nJavaScript와 CSS를 자체 호스팅하는 것은 예를 들어, 오프라인 상태이거나 외부 인터넷에 접근할 수 없는 환경, 또는 로컬 네트워크에서도 앱이 계속 동작해야 할 때 유용할 수 있습니다.\n\n여기서는 동일한 FastAPI 앱에서 해당 파일을 직접 제공하고, 문서가 이를 사용하도록 설정하는 방법을 살펴봅니다.\n\n### 프로젝트 파일 구조 { #project-file-structure }\n\n프로젝트 파일 구조가 다음과 같다고 해봅시다:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\n이제 해당 정적 파일을 저장할 디렉터리를 만드세요.\n\n새 파일 구조는 다음과 같을 수 있습니다:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### 파일 다운로드하기 { #download-the-files }\n\n문서에 필요한 정적 파일을 다운로드해서 `static/` 디렉터리에 넣으세요.\n\n각 링크를 우클릭한 뒤 \"링크를 다른 이름으로 저장...\"과 비슷한 옵션을 선택하면 될 것입니다.\n\n**Swagger UI**는 다음 파일을 사용합니다:\n\n* [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n* [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\n**ReDoc**은 다음 파일을 사용합니다:\n\n* [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\n이후 파일 구조는 다음과 같을 수 있습니다:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### 정적 파일 제공하기 { #serve-the-static-files }\n\n* `StaticFiles`를 import합니다.\n* 특정 경로에 `StaticFiles()` 인스턴스를 \"마운트(mount)\"합니다.\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### 정적 파일 테스트하기 { #test-the-static-files }\n\n애플리케이션을 시작하고 [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js)로 이동하세요.\n\n**ReDoc**용 매우 긴 JavaScript 파일이 보일 것입니다.\n\n예를 들어 다음과 같이 시작할 수 있습니다:\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\n이는 앱에서 정적 파일을 제공할 수 있고, 문서용 정적 파일을 올바른 위치에 배치했다는 것을 확인해 줍니다.\n\n이제 문서가 이 정적 파일을 사용하도록 앱을 설정할 수 있습니다.\n\n### 정적 파일을 위한 자동 문서 비활성화하기 { #disable-the-automatic-docs-for-static-files }\n\n커스텀 CDN을 사용할 때와 마찬가지로, 첫 단계는 자동 문서를 비활성화하는 것입니다. 자동 문서는 기본적으로 CDN을 사용합니다.\n\n비활성화하려면 `FastAPI` 앱을 생성할 때 해당 URL을 `None`으로 설정하세요:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### 정적 파일을 위한 커스텀 문서 포함하기 { #include-the-custom-docs-for-static-files }\n\n그리고 커스텀 CDN을 사용할 때와 동일한 방식으로, 이제 커스텀 문서를 위한 *경로 처리*를 만들 수 있습니다.\n\n다시 한 번, FastAPI 내부 함수를 재사용해 문서용 HTML 페이지를 생성하고, 필요한 인자를 전달할 수 있습니다:\n\n* `openapi_url`: 문서 HTML 페이지가 API의 OpenAPI 스키마를 가져올 수 있는 URL입니다. 여기서는 `app.openapi_url` 속성을 사용할 수 있습니다.\n* `title`: API의 제목입니다.\n* `oauth2_redirect_url`: 기본값을 사용하려면 여기서 `app.swagger_ui_oauth2_redirect_url`을 사용할 수 있습니다.\n* `swagger_js_url`: Swagger UI 문서의 HTML이 **JavaScript** 파일을 가져올 수 있는 URL입니다. **이제는 여러분의 앱이 직접 제공하는 파일입니다**.\n* `swagger_css_url`: Swagger UI 문서의 HTML이 **CSS** 파일을 가져올 수 있는 URL입니다. **이제는 여러분의 앱이 직접 제공하는 파일입니다**.\n\nReDoc도 마찬가지입니다...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip | 팁\n\n`swagger_ui_redirect`에 대한 *경로 처리*는 OAuth2를 사용할 때 도움이 되는 헬퍼입니다.\n\nAPI를 OAuth2 provider와 통합하면 인증을 수행한 뒤 획득한 자격 증명으로 API 문서로 다시 돌아올 수 있습니다. 그리고 실제 OAuth2 인증을 사용해 API와 상호작용할 수 있습니다.\n\nSwagger UI가 이 과정을 백그라운드에서 처리해 주지만, 이를 위해 이 \"redirect\" 헬퍼가 필요합니다.\n\n///\n\n### 정적 파일 테스트용 *경로 처리* 만들기 { #create-a-path-operation-to-test-static-files }\n\n이제 모든 것이 제대로 동작하는지 테스트할 수 있도록 *경로 처리*를 하나 만드세요:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### 정적 파일 UI 테스트하기 { #test-static-files-ui }\n\n이제 WiFi 연결을 끊고 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)에서 문서에 접속한 뒤 페이지를 새로고침해 보세요.\n\n인터넷이 없어도 API 문서를 보고, API와 상호작용할 수 있을 것입니다.\n"
  },
  {
    "path": "docs/ko/docs/how-to/custom-request-and-route.md",
    "content": "# 커스텀 Request 및 APIRoute 클래스 { #custom-request-and-apiroute-class }\n\n일부 경우에는 `Request`와 `APIRoute` 클래스에서 사용되는 로직을 오버라이드하고 싶을 수 있습니다.\n\n특히, 이는 middleware에 있는 로직의 좋은 대안이 될 수 있습니다.\n\n예를 들어, 애플리케이션에서 처리되기 전에 요청 바디를 읽거나 조작하고 싶을 때가 그렇습니다.\n\n/// danger | 위험\n\n이 기능은 \"고급\" 기능입니다.\n\n**FastAPI**를 이제 막 시작했다면 이 섹션은 건너뛰는 것이 좋습니다.\n\n///\n\n## 사용 사례 { #use-cases }\n\n사용 사례에는 다음이 포함됩니다:\n\n* JSON이 아닌 요청 바디를 JSON으로 변환하기(예: [`msgpack`](https://msgpack.org/index.html)).\n* gzip으로 압축된 요청 바디 압축 해제하기.\n* 모든 요청 바디를 자동으로 로깅하기.\n\n## 커스텀 요청 바디 인코딩 처리하기 { #handling-custom-request-body-encodings }\n\n커스텀 `Request` 서브클래스를 사용해 gzip 요청의 압축을 해제하는 방법을 살펴보겠습니다.\n\n그리고 그 커스텀 요청 클래스를 사용하기 위한 `APIRoute` 서브클래스도 함께 보겠습니다.\n\n### 커스텀 `GzipRequest` 클래스 만들기 { #create-a-custom-gziprequest-class }\n\n/// tip | 팁\n\n이 예시는 동작 방식 시연을 위한 장난감 예제입니다. Gzip 지원이 필요하다면 제공되는 [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware)를 사용할 수 있습니다.\n\n///\n\n먼저, `GzipRequest` 클래스를 만듭니다. 이 클래스는 `Request.body()` 메서드를 덮어써서, 적절한 헤더가 있는 경우 바디를 압축 해제합니다.\n\n헤더에 `gzip`이 없으면 바디를 압축 해제하려고 시도하지 않습니다.\n\n이렇게 하면 동일한 route 클래스가 gzip으로 압축된 요청과 압축되지 않은 요청을 모두 처리할 수 있습니다.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### 커스텀 `GzipRoute` 클래스 만들기 { #create-a-custom-gziproute-class }\n\n다음으로, `GzipRequest`를 활용하는 `fastapi.routing.APIRoute`의 커스텀 서브클래스를 만듭니다.\n\n이번에는 `APIRoute.get_route_handler()` 메서드를 오버라이드합니다.\n\n이 메서드는 함수를 반환합니다. 그리고 그 함수가 요청을 받아 응답을 반환합니다.\n\n여기서는 원본 요청으로부터 `GzipRequest`를 만들기 위해 이를 사용합니다.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | 기술 세부사항\n\n`Request`에는 `request.scope` 속성이 있는데, 이는 요청과 관련된 메타데이터를 담고 있는 Python `dict`입니다.\n\n`Request`에는 또한 `request.receive`가 있는데, 이는 요청의 바디를 \"받기(receive)\" 위한 함수입니다.\n\n`scope` `dict`와 `receive` 함수는 모두 ASGI 명세의 일부입니다.\n\n그리고 이 두 가지, `scope`와 `receive`가 새로운 `Request` 인스턴스를 만드는 데 필요한 것들입니다.\n\n`Request`에 대해 더 알아보려면 [Starlette의 Requests 문서](https://www.starlette.dev/requests/)를 확인하세요.\n\n///\n\n`GzipRequest.get_route_handler`가 반환하는 함수가 다르게 하는 유일한 것은 `Request`를 `GzipRequest`로 변환하는 것입니다.\n\n이렇게 하면, 우리의 `GzipRequest`가 *경로 처리*로 전달하기 전에(필요하다면) 데이터의 압축 해제를 담당하게 됩니다.\n\n그 이후의 모든 처리 로직은 동일합니다.\n\n하지만 `GzipRequest.body`에서 변경을 했기 때문에, 필요할 때 **FastAPI**가 로드하는 시점에 요청 바디는 자동으로 압축 해제됩니다.\n\n## 예외 핸들러에서 요청 바디 접근하기 { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip | 팁\n\n같은 문제를 해결하려면 `RequestValidationError`에 대한 커스텀 핸들러에서 `body`를 사용하는 편이 아마 훨씬 더 쉽습니다([오류 처리하기](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)).\n\n하지만 이 예시도 여전히 유효하며, 내부 컴포넌트와 상호작용하는 방법을 보여줍니다.\n\n///\n\n같은 접근 방식을 사용해 예외 핸들러에서 요청 바디에 접근할 수도 있습니다.\n\n필요한 것은 `try`/`except` 블록 안에서 요청을 처리하는 것뿐입니다:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\n예외가 발생하더라도 `Request` 인스턴스는 여전히 스코프 안에 남아 있으므로, 오류를 처리할 때 요청 바디를 읽고 활용할 수 있습니다:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## 라우터에서의 커스텀 `APIRoute` 클래스 { #custom-apiroute-class-in-a-router }\n\n`APIRouter`의 `route_class` 파라미터를 설정할 수도 있습니다:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\n이 예시에서는 `router` 아래의 *경로 처리*들이 커스텀 `TimedRoute` 클래스를 사용하며, 응답을 생성하는 데 걸린 시간을 담은 추가 `X-Response-Time` 헤더가 응답에 포함됩니다:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/ko/docs/how-to/extending-openapi.md",
    "content": "# OpenAPI 확장하기 { #extending-openapi }\n\n생성된 OpenAPI 스키마를 수정해야 하는 경우가 있습니다.\n\n이 섹션에서 그 방법을 살펴보겠습니다.\n\n## 일반적인 과정 { #the-normal-process }\n\n일반적인(기본) 과정은 다음과 같습니다.\n\n`FastAPI` 애플리케이션(인스턴스)에는 OpenAPI 스키마를 반환해야 하는 `.openapi()` 메서드가 있습니다.\n\n애플리케이션 객체를 생성하는 과정에서 `/openapi.json`(또는 `openapi_url`에 설정한 경로)용 *경로 처리*가 등록됩니다.\n\n이 경로 처리는 애플리케이션의 `.openapi()` 메서드 결과를 JSON 응답으로 반환할 뿐입니다.\n\n기본적으로 `.openapi()` 메서드는 프로퍼티 `.openapi_schema`에 내용이 있는지 확인하고, 있으면 그 내용을 반환합니다.\n\n없으면 `fastapi.openapi.utils.get_openapi`에 있는 유틸리티 함수를 사용해 생성합니다.\n\n그리고 `get_openapi()` 함수는 다음을 파라미터로 받습니다:\n\n* `title`: 문서에 표시되는 OpenAPI 제목.\n* `version`: API 버전. 예: `2.5.0`.\n* `openapi_version`: 사용되는 OpenAPI 스펙 버전. 기본값은 최신인 `3.1.0`.\n* `summary`: API에 대한 짧은 요약.\n* `description`: API 설명. markdown을 포함할 수 있으며 문서에 표시됩니다.\n* `routes`: 라우트 목록. 각각 등록된 *경로 처리*입니다. `app.routes`에서 가져옵니다.\n\n/// info | 정보\n\n`summary` 파라미터는 OpenAPI 3.1.0 이상에서 사용할 수 있으며, FastAPI 0.99.0 이상에서 지원됩니다.\n\n///\n\n## 기본값 덮어쓰기 { #overriding-the-defaults }\n\n위 정보를 바탕으로, 동일한 유틸리티 함수를 사용해 OpenAPI 스키마를 생성하고 필요한 각 부분을 덮어쓸 수 있습니다.\n\n예를 들어, [커스텀 로고를 포함하기 위한 ReDoc의 OpenAPI 확장](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo)을 추가해 보겠습니다.\n\n### 일반적인 **FastAPI** { #normal-fastapi }\n\n먼저, 평소처럼 **FastAPI** 애플리케이션을 모두 작성합니다:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### OpenAPI 스키마 생성하기 { #generate-the-openapi-schema }\n\n그다음 `custom_openapi()` 함수 안에서, 동일한 유틸리티 함수를 사용해 OpenAPI 스키마를 생성합니다:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### OpenAPI 스키마 수정하기 { #modify-the-openapi-schema }\n\n이제 OpenAPI 스키마의 `info` \"object\"에 커스텀 `x-logo`를 추가하여 ReDoc 확장을 더할 수 있습니다:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### OpenAPI 스키마 캐시하기 { #cache-the-openapi-schema }\n\n생성한 스키마를 저장하기 위한 \"cache\"로 `.openapi_schema` 프로퍼티를 사용할 수 있습니다.\n\n이렇게 하면 사용자가 API 문서를 열 때마다 애플리케이션이 스키마를 매번 생성하지 않아도 됩니다.\n\n스키마는 한 번만 생성되고, 이후 요청에서는 같은 캐시된 스키마가 사용됩니다.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### 메서드 오버라이드하기 { #override-the-method }\n\n이제 `.openapi()` 메서드를 새 함수로 교체할 수 있습니다.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### 확인하기 { #check-it }\n\n[http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)로 이동하면 커스텀 로고(이 예시에서는 **FastAPI** 로고)를 사용하는 것을 확인할 수 있습니다:\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/ko/docs/how-to/general.md",
    "content": "# 일반 - 사용 방법 - 레시피 { #general-how-to-recipes }\n\n일반적이거나 자주 나오는 질문에 대해, 문서의 다른 위치로 안내하는 몇 가지 포인터를 소개합니다.\n\n## 데이터 필터링 - 보안 { #filter-data-security }\n\n반환하면 안 되는 데이터를 과도하게 반환하지 않도록 하려면, [튜토리얼 - 응답 모델 - 반환 타입](../tutorial/response-model.md) 문서를 읽어보세요.\n\n## 응답 성능 최적화 - 응답 모델 - 반환 타입 { #optimize-response-performance-response-model-return-type }\n\nJSON 데이터를 반환할 때 성능을 최적화하려면 반환 타입 또는 응답 모델을 사용하세요. 그러면 Pydantic이 Python을 거치지 않고 Rust 측에서 JSON 직렬화를 처리합니다. 자세한 내용은 [튜토리얼 - 응답 모델 - 반환 타입](../tutorial/response-model.md) 문서를 참고하세요.\n\n## 문서화 태그 - OpenAPI { #documentation-tags-openapi }\n\n*경로 처리*에 태그를 추가하고, 문서 UI에서 이를 그룹화하려면 [튜토리얼 - 경로 처리 구성 - 태그](../tutorial/path-operation-configuration.md#tags) 문서를 읽어보세요.\n\n## 문서화 요약 및 설명 - OpenAPI { #documentation-summary-and-description-openapi }\n\n*경로 처리*에 요약과 설명을 추가하고, 문서 UI에 표시하려면 [튜토리얼 - 경로 처리 구성 - 요약 및 설명](../tutorial/path-operation-configuration.md#summary-and-description) 문서를 읽어보세요.\n\n## 문서화 응답 설명 - OpenAPI { #documentation-response-description-openapi }\n\n문서 UI에 표시되는 응답의 설명을 정의하려면 [튜토리얼 - 경로 처리 구성 - 응답 설명](../tutorial/path-operation-configuration.md#response-description) 문서를 읽어보세요.\n\n## 문서화 *경로 처리* 지원 중단하기 - OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\n*경로 처리*를 지원 중단(deprecate)으로 표시하고, 문서 UI에 보여주려면 [튜토리얼 - 경로 처리 구성 - 지원 중단](../tutorial/path-operation-configuration.md#deprecate-a-path-operation) 문서를 읽어보세요.\n\n## 어떤 데이터든 JSON 호환으로 변환하기 { #convert-any-data-to-json-compatible }\n\n어떤 데이터든 JSON 호환 형식으로 변환하려면 [튜토리얼 - JSON 호환 인코더](../tutorial/encoder.md) 문서를 읽어보세요.\n\n## OpenAPI 메타데이터 - 문서 { #openapi-metadata-docs }\n\n라이선스, 버전, 연락처 등의 정보를 포함해 OpenAPI 스키마에 메타데이터를 추가하려면 [튜토리얼 - 메타데이터와 문서 URL](../tutorial/metadata.md) 문서를 읽어보세요.\n\n## OpenAPI 사용자 정의 URL { #openapi-custom-url }\n\nOpenAPI URL을 커스터마이즈(또는 제거)하려면 [튜토리얼 - 메타데이터와 문서 URL](../tutorial/metadata.md#openapi-url) 문서를 읽어보세요.\n\n## OpenAPI 문서 URL { #openapi-docs-urls }\n\n자동으로 생성되는 문서 사용자 인터페이스에서 사용하는 URL을 업데이트하려면 [튜토리얼 - 메타데이터와 문서 URL](../tutorial/metadata.md#docs-urls) 문서를 읽어보세요.\n"
  },
  {
    "path": "docs/ko/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\n**FastAPI**는 **ASGI** 표준을 기반으로 하므로, ASGI와도 호환되는 어떤 **GraphQL** 라이브러리든 매우 쉽게 통합할 수 있습니다.\n\n같은 애플리케이션에서 일반 FastAPI **경로 처리**와 GraphQL을 함께 조합할 수 있습니다.\n\n/// tip | 팁\n\n**GraphQL**은 몇 가지 매우 특정한 사용 사례를 해결합니다.\n\n일반적인 **web API**와 비교했을 때 **장점**과 **단점**이 있습니다.\n\n여러분의 사용 사례에서 **이점**이 **단점**을 상쇄하는지 꼭 평가해 보세요. 🤓\n\n///\n\n## GraphQL 라이브러리 { #graphql-libraries }\n\n다음은 **ASGI** 지원이 있는 **GraphQL** 라이브러리들입니다. **FastAPI**와 함께 사용할 수 있습니다:\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * [FastAPI용 문서](https://strawberry.rocks/docs/integrations/fastapi) 제공\n* [Ariadne](https://ariadnegraphql.org/)\n    * [FastAPI용 문서](https://ariadnegraphql.org/docs/fastapi-integration) 제공\n* [Tartiflette](https://tartiflette.io/)\n    * ASGI 통합을 제공하기 위해 [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) 사용\n* [Graphene](https://graphene-python.org/)\n    * [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3) 사용\n\n## Strawberry로 GraphQL 사용하기 { #graphql-with-strawberry }\n\n**GraphQL**로 작업해야 하거나 작업하고 싶다면, [**Strawberry**](https://strawberry.rocks/)를 **권장**합니다. **FastAPI**의 설계와 가장 가깝고, 모든 것이 **type annotations**에 기반해 있기 때문입니다.\n\n사용 사례에 따라 다른 라이브러리를 선호할 수도 있지만, 제게 묻는다면 아마 **Strawberry**를 먼저 시도해 보라고 제안할 것입니다.\n\n다음은 Strawberry를 FastAPI와 통합하는 방법에 대한 간단한 미리보기입니다:\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\n[Strawberry 문서](https://strawberry.rocks/)에서 Strawberry에 대해 더 알아볼 수 있습니다.\n\n또한 [FastAPI에서 Strawberry 사용](https://strawberry.rocks/docs/integrations/fastapi)에 대한 문서도 확인해 보세요.\n\n## Starlette의 예전 `GraphQLApp` { #older-graphqlapp-from-starlette }\n\n이전 버전의 Starlette에는 [Graphene](https://graphene-python.org/)과 통합하기 위한 `GraphQLApp` 클래스가 포함되어 있었습니다.\n\n이것은 Starlette에서 deprecated 되었지만, 이를 사용하던 코드가 있다면 같은 사용 사례를 다루고 **거의 동일한 인터페이스**를 가진 [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)로 쉽게 **마이그레이션**할 수 있습니다.\n\n/// tip | 팁\n\nGraphQL이 필요하다면, 커스텀 클래스와 타입 대신 type annotations에 기반한 [Strawberry](https://strawberry.rocks/)를 여전히 확인해 보시길 권장합니다.\n\n///\n\n## 더 알아보기 { #learn-more }\n\n[공식 GraphQL 문서](https://graphql.org/)에서 **GraphQL**에 대해 더 알아볼 수 있습니다.\n\n또한 위에서 설명한 각 라이브러리에 대해서도 해당 링크에서 더 자세히 읽어볼 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/how-to/index.md",
    "content": "# How To - 레시피 { #how-to-recipes }\n\n여기에서는 **여러 주제**에 대한 다양한 레시피(“how to” 가이드)를 볼 수 있습니다.\n\n대부분의 아이디어는 어느 정도 **서로 독립적**이며, 대부분의 경우 **여러분의 프로젝트**에 직접 적용되는 경우에만 학습하면 됩니다.\n\n프로젝트에 흥미롭고 유용해 보이는 것이 있다면 확인해 보세요. 그렇지 않다면 아마 건너뛰어도 됩니다.\n\n/// tip | 팁\n\n**FastAPI를 구조적으로 학습**하고 싶다면(권장), 대신 [튜토리얼 - 사용자 가이드](../tutorial/index.md)를 장별로 읽어보세요.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# Pydantic v1에서 Pydantic v2로 마이그레이션하기 { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\n오래된 FastAPI 앱이 있다면 Pydantic 버전 1을 사용하고 있을 수 있습니다.\n\nFastAPI 0.100.0 버전은 Pydantic v1 또는 v2 중 하나를 지원했습니다. 설치되어 있는 쪽을 사용했습니다.\n\nFastAPI 0.119.0 버전에서는 v2로의 마이그레이션을 쉽게 하기 위해, Pydantic v2 내부에서 Pydantic v1을(`pydantic.v1`로) 부분적으로 지원하기 시작했습니다.\n\nFastAPI 0.126.0 버전에서는 Pydantic v1 지원을 중단했지만, `pydantic.v1`은 잠시 동안 계속 지원했습니다.\n\n/// warning | 경고\n\nPydantic 팀은 최신 Python 버전에서 Pydantic v1 지원을 중단했으며, 시작 버전은 **Python 3.14**입니다.\n\n여기에는 `pydantic.v1`도 포함되며, Python 3.14 이상에서는 더 이상 지원되지 않습니다.\n\nPython의 최신 기능을 사용하려면 Pydantic v2를 사용하고 있는지 확인해야 합니다.\n\n///\n\nPydantic v1을 사용하는 오래된 FastAPI 앱이 있다면, 여기서는 이를 Pydantic v2로 마이그레이션하는 방법과 점진적 마이그레이션을 돕는 **FastAPI 0.119.0의 기능**을 소개하겠습니다.\n\n## 공식 가이드 { #official-guide }\n\nPydantic에는 v1에서 v2로의 공식 [마이그레이션 가이드](https://docs.pydantic.dev/latest/migration/)가 있습니다.\n\n여기에는 무엇이 바뀌었는지, 검증이 이제 어떻게 더 정확하고 엄격해졌는지, 가능한 주의사항 등도 포함되어 있습니다.\n\n변경된 내용을 더 잘 이해하기 위해 읽어보면 좋습니다.\n\n## 테스트 { #tests }\n\n앱에 대한 [테스트](../tutorial/testing.md)가 있는지 확인하고, 지속적 통합(CI)에서 테스트를 실행하세요.\n\n이렇게 하면 업그레이드를 진행하면서도 모든 것이 기대한 대로 계속 동작하는지 확인할 수 있습니다.\n\n## `bump-pydantic` { #bump-pydantic }\n\n많은 경우, 커스터마이징 없이 일반적인 Pydantic 모델을 사용하고 있다면 Pydantic v1에서 Pydantic v2로의 마이그레이션 과정 대부분을 자동화할 수 있습니다.\n\n같은 Pydantic 팀이 제공하는 [`bump-pydantic`](https://github.com/pydantic/bump-pydantic)를 사용할 수 있습니다.\n\n이 도구는 변경해야 하는 코드의 대부분을 자동으로 바꾸는 데 도움을 줍니다.\n\n그 다음 테스트를 실행해서 모든 것이 동작하는지 확인하면 됩니다. 잘 된다면 끝입니다. 😎\n\n## v2 안의 Pydantic v1 { #pydantic-v1-in-v2 }\n\nPydantic v2는 Pydantic v1의 모든 것을 서브모듈 `pydantic.v1`로 포함합니다. 하지만 이는 Python 3.13보다 높은 버전에서는 더 이상 지원되지 않습니다.\n\n즉, Pydantic v2의 최신 버전을 설치한 뒤, 이 서브모듈에서 예전 Pydantic v1 구성 요소를 import하여 예전 Pydantic v1을 설치한 것처럼 사용할 수 있습니다.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### v2 안의 Pydantic v1에 대한 FastAPI 지원 { #fastapi-support-for-pydantic-v1-in-v2 }\n\nFastAPI 0.119.0부터는 v2로의 마이그레이션을 쉽게 하기 위해, Pydantic v2 내부의 Pydantic v1에 대해서도 부분적인 지원이 있습니다.\n\n따라서 Pydantic을 최신 v2로 업그레이드하고, import를 `pydantic.v1` 서브모듈을 사용하도록 바꾸면, 많은 경우 그대로 동작합니다.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning | 경고\n\nPydantic 팀이 Python 3.14부터 최신 Python 버전에서 Pydantic v1을 더 이상 지원하지 않으므로, `pydantic.v1`을 사용하는 것 역시 Python 3.14 이상에서는 지원되지 않는다는 점을 염두에 두세요.\n\n///\n\n### 같은 앱에서 Pydantic v1과 v2 함께 사용하기 { #pydantic-v1-and-v2-on-the-same-app }\n\nPydantic에서는 Pydantic v2 모델의 필드를 Pydantic v1 모델로 정의하거나 그 반대로 하는 것을 **지원하지 않습니다**.\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n...하지만 같은 앱에서 Pydantic v1과 v2를 사용하되, 모델을 분리해서 둘 수는 있습니다.\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n어떤 경우에는 FastAPI 앱의 같은 **경로 처리**에서 Pydantic v1과 v2 모델을 함께 사용하는 것도 가능합니다:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\n위 예제에서 입력 모델은 Pydantic v1 모델이고, 출력 모델(`response_model=ItemV2`로 정의됨)은 Pydantic v2 모델입니다.\n\n### Pydantic v1 파라미터 { #pydantic-v1-parameters }\n\nPydantic v1 모델과 함께 `Body`, `Query`, `Form` 등 파라미터용 FastAPI 전용 도구 일부를 사용해야 한다면, Pydantic v2로의 마이그레이션을 마칠 때까지 `fastapi.temp_pydantic_v1_params`에서 import할 수 있습니다:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### 단계적으로 마이그레이션하기 { #migrate-in-steps }\n\n/// tip | 팁\n\n먼저 `bump-pydantic`로 시도해 보세요. 테스트가 통과하고 잘 동작한다면, 한 번의 명령으로 끝입니다. ✨\n\n///\n\n`bump-pydantic`가 여러분의 사용 사례에 맞지 않는다면, 같은 앱에서 Pydantic v1과 v2 모델을 모두 지원하는 기능을 이용해 Pydantic v2로 점진적으로 마이그레이션할 수 있습니다.\n\n먼저 Pydantic을 최신 v2로 업그레이드하고, 모든 모델의 import를 `pydantic.v1`을 사용하도록 바꿀 수 있습니다.\n\n그 다음 Pydantic v1에서 v2로 모델을 그룹 단위로, 점진적인 단계로 마이그레이션을 시작하면 됩니다. 🚶\n"
  },
  {
    "path": "docs/ko/docs/how-to/separate-openapi-schemas.md",
    "content": "# 입력과 출력에 대해 OpenAPI 스키마를 분리할지 여부 { #separate-openapi-schemas-for-input-and-output-or-not }\n\n**Pydantic v2**가 릴리스된 이후, 생성되는 OpenAPI는 이전보다 조금 더 정확하고 **올바르게** 만들어집니다. 😎\n\n실제로 어떤 경우에는, 같은 Pydantic 모델에 대해 OpenAPI 안에 **두 개의 JSON Schema**가 생기기도 합니다. **기본값(default value)**이 있는지 여부에 따라, 입력용과 출력용으로 나뉩니다.\n\n이것이 어떻게 동작하는지, 그리고 필요하다면 어떻게 변경할 수 있는지 살펴보겠습니다.\n\n## 입력과 출력을 위한 Pydantic 모델 { #pydantic-models-for-input-and-output }\n\n예를 들어, 다음처럼 기본값이 있는 Pydantic 모델이 있다고 해보겠습니다:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### 입력용 모델 { #model-for-input }\n\n이 모델을 다음처럼 입력으로 사용하면:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n...`description` 필드는 **필수가 아닙니다**. `None`이라는 기본값이 있기 때문입니다.\n\n### 문서에서의 입력 모델 { #input-model-in-docs }\n\n문서에서 `description` 필드에 **빨간 별표**가 없고, 필수로 표시되지 않는 것을 확인할 수 있습니다:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### 출력용 모델 { #model-for-output }\n\n하지만 같은 모델을 다음처럼 출력으로 사용하면:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n...`description`에 기본값이 있기 때문에, 그 필드에 대해 **아무것도 반환하지 않더라도** 여전히 그 **기본값**이 들어가게 됩니다.\n\n### 출력 응답 데이터용 모델 { #model-for-output-response-data }\n\n문서에서 직접 동작시켜 응답을 확인해 보면, 코드가 `description` 필드 중 하나에 아무것도 추가하지 않았더라도 JSON 응답에는 기본값(`null`)이 포함되어 있습니다:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\n이는 해당 필드가 **항상 값을 가진다는 것**을 의미합니다. 다만 그 값이 때로는 `None`(JSON에서는 `null`)일 수 있습니다.\n\n즉, API를 사용하는 클라이언트는 값이 존재하는지 여부를 확인할 필요가 없고, **필드가 항상 존재한다고 가정**할 수 있습니다. 다만 어떤 경우에는 기본값 `None`이 들어갑니다.\n\n이를 OpenAPI에서 표현하는 방법은, 그 필드를 **required**로 표시하는 것입니다. 항상 존재하기 때문입니다.\n\n이 때문에, 하나의 모델이라도 **입력용인지 출력용인지**에 따라 JSON Schema가 달라질 수 있습니다:\n\n* **입력**에서는 `description`이 **필수가 아님**\n* **출력**에서는 **필수임** (그리고 값은 `None`일 수도 있으며, JSON 용어로는 `null`)\n\n### 문서에서의 출력용 모델 { #model-for-output-in-docs }\n\n문서에서 출력 모델을 확인해 보면, `name`과 `description` **둘 다** **빨간 별표**로 **필수**로 표시되어 있습니다:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### 문서에서의 입력과 출력 모델 { #model-for-input-and-output-in-docs }\n\n또 OpenAPI에서 사용 가능한 모든 Schemas(JSON Schemas)를 확인해 보면, `Item-Input` 하나와 `Item-Output` 하나, 이렇게 두 개가 있는 것을 볼 수 있습니다.\n\n`Item-Input`에서는 `description`이 **필수가 아니며**, 빨간 별표가 없습니다.\n\n하지만 `Item-Output`에서는 `description`이 **필수이며**, 빨간 별표가 있습니다.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi_schemas/image04.png\">\n</div>\n\n**Pydantic v2**의 이 기능 덕분에 API 문서는 더 **정밀**해지고, 자동 생성된 클라이언트와 SDK가 있다면 그것들도 더 정밀해져서 더 나은 **developer experience**와 일관성을 제공할 수 있습니다. 🎉\n\n## 스키마를 분리하지 않기 { #do-not-separate-schemas }\n\n이제 어떤 경우에는 **입력과 출력에 대해 같은 스키마를 사용**하고 싶을 수도 있습니다.\n\n가장 대표적인 경우는, 이미 자동 생성된 클라이언트 코드/SDK가 있고, 아직은 그 자동 생성된 클라이언트 코드/SDK들을 전부 업데이트하고 싶지 않은 경우입니다. 언젠가는 업데이트해야 할 가능성이 높지만, 지금 당장은 아닐 수도 있습니다.\n\n그런 경우에는, **FastAPI**에서 `separate_input_output_schemas=False` 파라미터로 이 기능을 비활성화할 수 있습니다.\n\n/// info | 정보\n\n`separate_input_output_schemas` 지원은 FastAPI `0.102.0`에 추가되었습니다. 🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### 문서에서 입력과 출력 모델에 같은 스키마 사용 { #same-schema-for-input-and-output-models-in-docs }\n\n이제 모델에 대해 입력과 출력 모두에 사용되는 단일 스키마(오직 `Item`만)가 생성되며, `description`은 **필수가 아닌 것**으로 표시됩니다:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/ko/docs/how-to/testing-database.md",
    "content": "# 데이터베이스 테스트하기 { #testing-a-database }\n\n데이터베이스, SQL, SQLModel에 대해서는 [SQLModel 문서](https://sqlmodel.tiangolo.com/)에서 학습할 수 있습니다. 🤓\n\n[FastAPI에서 SQLModel을 사용하는 방법에 대한 미니 튜토리얼](https://sqlmodel.tiangolo.com/tutorial/fastapi/)도 있습니다. ✨\n\n해당 튜토리얼에는 [SQL 데이터베이스 테스트](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/)에 대한 섹션도 포함되어 있습니다. 😎\n"
  },
  {
    "path": "docs/ko/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/ko\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>FastAPI 프레임워크, 고성능, 간편한 학습, 빠른 코드 작성, 준비된 프로덕션</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**문서**: [https://fastapi.tiangolo.com/ko](https://fastapi.tiangolo.com/ko)\n\n**소스 코드**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI는 현대적이고, 빠르며(고성능), 파이썬 표준 타입 힌트에 기초한 Python의 API를 빌드하기 위한 웹 프레임워크입니다.\n\n주요 특징으로:\n\n* **빠름**: (Starlette과 Pydantic 덕분에) **NodeJS** 및 **Go**와 대등할 정도로 매우 높은 성능. [사용 가능한 가장 빠른 파이썬 프레임워크 중 하나](#performance).\n* **빠른 코드 작성**: 약 200%에서 300%까지 기능 개발 속도 증가. *\n* **적은 버그**: 사람(개발자)에 의한 에러 약 40% 감소. *\n* **직관적**: 훌륭한 편집기 지원. <dfn title=\"다른 말로는: 자동 완성, 자동완성, IntelliSense\">자동완성</dfn>이 모든 곳에서 동작. 적은 디버깅 시간.\n* **쉬움**: 쉽게 사용하고 배우도록 설계. 적은 문서 읽기 시간.\n* **짧음**: 코드 중복 최소화. 각 매개변수 선언의 여러 기능. 적은 버그.\n* **견고함**: 준비된 프로덕션 용 코드를 얻으십시오. 자동 대화형 문서와 함께.\n* **표준 기반**: API에 대한 (완전히 호환되는) 개방형 표준 기반: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (이전에 Swagger로 알려졌던) 및 [JSON Schema](https://json-schema.org/).\n\n<small>* 내부 개발팀의 프로덕션 애플리케이션을 빌드한 테스트에 근거한 측정</small>\n\n## 스폰서 { #sponsors }\n\n<!-- sponsors -->\n\n### 키스톤 스폰서 { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### 골드 및 실버 스폰서 { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[다른 스폰서](https://fastapi.tiangolo.com/ko/fastapi-people/#sponsors)\n\n## 의견들 { #opinions }\n\n\"_[...] 저는 요즘 **FastAPI**를 많이 사용하고 있습니다. [...] 사실 우리 팀의 **마이크로소프트 ML 서비스** 전부를 바꿀 계획입니다. 그중 일부는 핵심 **Windows**와 몇몇의 **Office** 제품들이 통합되고 있습니다._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>마이크로소프트</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n\"_**FastAPI** 라이브러리를 채택하여 **예측**을 얻기 위해 쿼리를 실행 할 수 있는 **REST** 서버를 생성했습니다. [Ludwig을 위해]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin 그리고 Sai Sumanth Miryala - <strong>우버</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n\"_**Netflix**는 우리의 오픈 소스 배포판인 **위기 관리** 오케스트레이션 프레임워크를 발표할 수 있어 기쁩니다: 바로 **Dispatch**입니다! [**FastAPI**로 빌드]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>넷플릭스</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n\"_**FastAPI**가 너무 좋아서 구름 위를 걷는듯 합니다. 정말 즐겁습니다!_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken - <strong>[Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855) podcast host</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(ref)</small></a></div>\n\n---\n\n\"_솔직히, 당신이 만든 것은 매우 견고하고 세련되어 보입니다. 여러 면에서 **Hug**가 이렇게 되었으면 합니다 - 그걸 만든 누군가를 보는 것은 많은 영감을 줍니다._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley - <strong>[Hug](https://github.com/hugapi/hug) 제작자</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(ref)</small></a></div>\n\n---\n\n\"_REST API를 만들기 위해 **현대적인 프레임워크**를 찾고 있다면 **FastAPI**를 확인해 보십시오. [...] 빠르고, 쓰기 쉽고, 배우기도 쉽습니다 [...]_\"\n\n\"_우리 **API**를 **FastAPI**로 바꿨습니다  [...] 아마 여러분도 좋아하실 것입니다 [...]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani - Matthew Honnibal - <strong>[Explosion AI](https://explosion.ai) 설립자 - [spaCy](https://spacy.io) 제작자</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(ref)</small></a> - <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(ref)</small></a></div>\n\n---\n\n\"_프로덕션 Python API를 만들고자 한다면, 저는 **FastAPI**를 강력히 추천합니다. **아름답게 설계**되었고, **사용이 간단**하며, **확장성이 매우 뛰어나**고, 우리의 API 우선 개발 전략에서 **핵심 구성 요소**가 되었으며 Virtual TAC Engineer 같은 많은 자동화와 서비스를 이끌고 있습니다._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n## FastAPI 미니 다큐멘터리 { #fastapi-mini-documentary }\n\n2025년 말에 공개된 [FastAPI 미니 다큐멘터리](https://www.youtube.com/watch?v=mpR8ngthqiE)가 있습니다. 온라인에서 시청할 수 있습니다:\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**, CLI를 위한 FastAPI { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\n웹 API 대신 터미널에서 사용할 <abbr title=\"Command Line Interface - 커맨드 라인 인터페이스\">CLI</abbr> 앱을 만들고 있다면, [**Typer**](https://typer.tiangolo.com/)를 확인해 보십시오.\n\n**Typer**는 FastAPI의 동생입니다. 그리고 **CLI를 위한 FastAPI**가 되기 위해 생겼습니다. ⌨️ 🚀\n\n## 요구사항 { #requirements }\n\nFastAPI는 거인들의 어깨 위에 서 있습니다:\n\n* [Starlette](https://www.starlette.dev/) — 웹 부분을 담당합니다.\n* [Pydantic](https://docs.pydantic.dev/) — 데이터 부분을 담당합니다.\n\n## 설치 { #installation }\n\n[가상 환경](https://fastapi.tiangolo.com/ko/virtual-environments/)을 생성하고 활성화한 다음 FastAPI를 설치하세요:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Note**: 모든 터미널에서 동작하도록 `\"fastapi[standard]\"`를 따옴표로 감싸 넣었는지 확인하세요.\n\n## 예제 { #example }\n\n### 만들기 { #create-it }\n\n다음 내용으로 `main.py` 파일을 만드십시오:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>또는 <code>async def</code> 사용하기...</summary>\n\n여러분의 코드가 `async` / `await`을 사용한다면, `async def`를 사용하십시오:\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Note**:\n\n잘 모르겠다면, [\"급하세요?\"](https://fastapi.tiangolo.com/ko/async/#in-a-hurry) 섹션을 확인해 보십시오.\n\n</details>\n\n### 실행하기 { #run-it }\n\n다음 명령으로 서버를 실행하십시오:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary><code>fastapi dev</code> 명령에 관하여...</summary>\n\n`fastapi dev` 명령은 여러분의 `main.py` 파일을 자동으로 읽고, 그 안의 **FastAPI** 앱을 감지한 다음, [Uvicorn](https://www.uvicorn.dev)을 사용해 서버를 시작합니다.\n\n기본적으로 `fastapi dev`는 로컬 개발을 위해 auto-reload가 활성화된 상태로 시작됩니다.\n\n자세한 내용은 [FastAPI CLI 문서](https://fastapi.tiangolo.com/ko/fastapi-cli/)에서 확인할 수 있습니다.\n\n</details>\n\n### 확인하기 { #check-it }\n\n브라우저로 [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery)를 열어보십시오.\n\n아래의 JSON 응답을 볼 수 있습니다:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n여러분은 벌써 API를 만들었습니다:\n\n* _경로_ `/` 및 `/items/{item_id}`에서 HTTP 요청 받기.\n* 두 _경로_ 모두 `GET` <em>연산</em>(HTTP _메소드_ 로 알려진)을 받습니다.\n* _경로_ `/items/{item_id}`는 `int`형 이어야 하는 _경로 매개변수_ `item_id`를 가지고 있습니다.\n* _경로_ `/items/{item_id}`는 선택적인 `str`형 _쿼리 매개변수_ `q`를 가지고 있습니다.\n\n### 대화형 API 문서 { #interactive-api-docs }\n\n이제 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)로 가보십시오.\n\n자동 대화형 API 문서를 볼 수 있습니다 ([Swagger UI](https://github.com/swagger-api/swagger-ui) 제공):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### 대안 API 문서 { #alternative-api-docs }\n\n그리고 이제 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)로 가봅시다.\n\n다른 자동 문서를 볼 수 있습니다([ReDoc](https://github.com/Rebilly/ReDoc) 제공):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## 예제 업그레이드 { #example-upgrade }\n\n이제 `PUT` 요청에서 본문을 받기 위해 `main.py` 파일을 수정해봅시다.\n\nPydantic 덕분에 표준 Python 타입을 사용해 본문을 선언합니다.\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n`fastapi dev` 서버는 자동으로 리로딩되어야 합니다.\n\n### 대화형 API 문서 업그레이드 { #interactive-api-docs-upgrade }\n\n이제 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)로 이동합니다.\n\n* 대화형 API 문서는 새 본문을 포함해 자동으로 업데이트됩니다:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* \"Try it out\" 버튼을 클릭하면, 매개변수를 채우고 API와 직접 상호작용할 수 있습니다:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* 그런 다음 \"Execute\" 버튼을 클릭하면, 사용자 인터페이스가 API와 통신하고 매개변수를 전송한 뒤 결과를 받아 화면에 표시합니다:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### 대안 API 문서 업그레이드 { #alternative-api-docs-upgrade }\n\n그리고 이제, [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)로 이동합니다.\n\n* 대안 문서 역시 새 쿼리 매개변수와 본문을 반영합니다:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### 요약 { #recap }\n\n요약하면, 여러분은 매개변수의 타입, 본문 등을 함수 매개변수로서 **한번에** 선언했습니다.\n\n여러분은 현대 표준 파이썬 타입으로 이를 행했습니다.\n\n새로운 문법, 특정 라이브러리의 메소드나 클래스 등을 배울 필요가 없습니다.\n\n그저 표준 **Python** 입니다.\n\n예를 들어, `int`에 대해선:\n\n```Python\nitem_id: int\n```\n\n또는 좀 더 복잡한 `Item` 모델에 대해선:\n\n```Python\nitem: Item\n```\n\n...그리고 단 하나의 선언으로 여러분이 얻는 것은:\n\n* 다음을 포함한 편집기 지원:\n    * 자동완성.\n    * 타입 검사.\n* 데이터 검증:\n    * 데이터가 유효하지 않을 때 자동으로 생성하는 명확한 에러.\n    * 깊이 중첩된 JSON 객체에 대한 유효성 검사.\n* 입력 데이터 <dfn title=\"다른 말로는: 직렬화, 파싱, 마샬링\">변환</dfn>: 네트워크에서 파이썬 데이터 및 타입으로 전송. 읽을 수 있는 것들:\n    * JSON.\n    * 경로 매개변수.\n    * 쿼리 매개변수.\n    * 쿠키.\n    * 헤더.\n    * 폼(Forms).\n    * 파일.\n* 출력 데이터 <dfn title=\"다른 말로는: 직렬화, 파싱, 마샬링\">변환</dfn>: 파이썬 데이터 및 타입을 네트워크 데이터로 전환(JSON 형식으로):\n    * 파이썬 타입 변환 (`str`, `int`, `float`, `bool`, `list`, 등).\n    * `datetime` 객체.\n    * `UUID` 객체.\n    * 데이터베이스 모델.\n    * ...더 많은 것들.\n* 대안가능한 사용자 인터페이스를 2개 포함한 자동 대화형 API 문서:\n    * Swagger UI.\n    * ReDoc.\n\n---\n\n이전 코드 예제로 돌아가서, **FastAPI**는 다음처럼 처리합니다:\n\n* `GET` 및 `PUT` 요청에 `item_id`가 경로에 있는지 검증.\n* `GET` 및 `PUT` 요청에 `item_id`가 `int` 타입인지 검증.\n    * 그렇지 않다면 클라이언트는 유용하고 명확한 에러를 볼 수 있습니다.\n* `GET` 요청에 `q`라는 선택적인 쿼리 매개변수가 있는지 검사(`http://127.0.0.1:8000/items/foo?q=somequery`처럼).\n    * `q` 매개변수는 `= None`으로 선언되었기 때문에 선택사항입니다.\n    * `None`이 없다면 필수사항입니다(`PUT`의 경우와 마찬가지로).\n* `/items/{item_id}`으로의 `PUT` 요청은 본문을 JSON으로 읽음:\n    * `name`을 필수 속성으로 갖고 `str` 형인지 검사.\n    * `price`를 필수 속성으로 갖고 `float` 형이어야 하는지 검사.\n    * 만약 주어진다면, `is_offer`를 선택 속성으로 갖고 `bool` 형이어야 하는지 검사.\n    * 이 모든 것은 깊이 중첩된 JSON 객체에도 적용됩니다.\n* JSON을 변환하거나 JSON으로 변환하는 것을 자동화.\n* 다음에서 사용할 수 있는 모든 것을 OpenAPI로 문서화:\n    * 대화형 문서 시스템.\n    * 여러 언어들에 대한 자동 클라이언트 코드 생성 시스템.\n* 2개의 대화형 문서 웹 인터페이스를 직접 제공.\n\n---\n\n우리는 그저 수박 겉 핥기만 했을 뿐인데 여러분은 벌써 어떻게 작동하는지 알고 있습니다.\n\n다음 줄을 바꿔보십시오:\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n...에서:\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n...으로:\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n...그러고 나서 여러분의 편집기가 속성과 타입을 알고 자동 완성하는지 보십시오:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n더 많은 기능을 포함한 보다 완전한 예제의 경우, <a href=\"https://fastapi.tiangolo.com/ko/tutorial/\">튜토리얼 - 사용자 가이드</a>를 보십시오.\n\n**스포일러 주의**: 튜토리얼 - 사용자 가이드는:\n\n* 서로 다른 장소에서 **매개변수** 선언: **헤더**, **쿠키**, **폼 필드** 그리고 **파일**.\n* `maximum_length` 또는 `regex`처럼 **유효성 제약**하는 방법.\n* 강력하고 사용하기 쉬운 **<dfn title=\"다른 말로는: 컴포넌트, 리소스, 프로바이더, 서비스, 인젝터블\">의존성 주입</dfn>** 시스템.\n* **OAuth2** 지원을 포함한 **JWT tokens** 및 **HTTP Basic**을 갖는 보안과 인증.\n* (Pydantic 덕분에) **깊은 중첩 JSON 모델**을 선언하는데 더 진보한 (하지만 마찬가지로 쉬운) 기술.\n* [Strawberry](https://strawberry.rocks) 및 기타 라이브러리와의 **GraphQL** 통합.\n* (Starlette 덕분에) 많은 추가 기능:\n    * **웹 소켓**\n    * HTTPX 및 `pytest`에 기반한 극히 쉬운 테스트\n    * **CORS**\n    * **쿠키 세션**\n    * ...기타 등등.\n\n### 앱 배포하기(선택 사항) { #deploy-your-app-optional }\n\n선택적으로 FastAPI 앱을 [FastAPI Cloud](https://fastapicloud.com)에 배포할 수 있습니다. 아직이라면 대기자 명단에 등록해 보세요. 🚀\n\n이미 **FastAPI Cloud** 계정이 있다면(대기자 명단에서 초대해 드렸습니다 😉), 한 번의 명령으로 애플리케이션을 배포할 수 있습니다.\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n이게 전부입니다! 이제 해당 URL에서 앱에 접근할 수 있습니다. ✨\n\n#### FastAPI Cloud 소개 { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)**는 **FastAPI** 뒤에 있는 동일한 작성자와 팀이 만들었습니다.\n\n최소한의 노력으로 API를 **빌드**, **배포**, **접근**하는 과정을 간소화합니다.\n\nFastAPI로 앱을 빌드할 때의 동일한 **개발자 경험**을 클라우드에 **배포**하는 데까지 확장해 줍니다. 🎉\n\nFastAPI Cloud는 *FastAPI and friends* 오픈 소스 프로젝트의 주요 스폰서이자 자금 제공자입니다. ✨\n\n#### 다른 클라우드 제공자에 배포하기 { #deploy-to-other-cloud-providers }\n\nFastAPI는 오픈 소스이며 표준을 기반으로 합니다. 선택한 어떤 클라우드 제공자에도 FastAPI 앱을 배포할 수 있습니다.\n\n클라우드 제공자의 가이드를 따라 FastAPI 앱을 배포하세요. 🤓\n\n## 성능 { #performance }\n\n독립된 TechEmpower 벤치마크에서 Uvicorn에서 작동하는 **FastAPI** 애플리케이션이 [사용 가능한 가장 빠른 Python 프레임워크 중 하나](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7)로 Starlette와 Uvicorn(FastAPI에서 내부적으로 사용)에만 밑돌고 있습니다. (*)\n\n자세한 내용은 [벤치마크](https://fastapi.tiangolo.com/ko/benchmarks/) 섹션을 보십시오.\n\n## 의존성 { #dependencies }\n\nFastAPI는 Pydantic과 Starlette에 의존합니다.\n\n### `standard` 의존성 { #standard-dependencies }\n\n`pip install \"fastapi[standard]\"`로 FastAPI를 설치하면 `standard` 그룹의 선택적 의존성이 함께 설치됩니다.\n\nPydantic이 사용하는:\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - 이메일 유효성 검사.\n\nStarlette이 사용하는:\n\n* [`httpx`](https://www.python-httpx.org) - `TestClient`를 사용하려면 필요.\n* [`jinja2`](https://jinja.palletsprojects.com) - 기본 템플릿 설정을 사용하려면 필요.\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - `request.form()`과 함께 form <dfn title=\"HTTP 요청에서 온 문자열을 파이썬 데이터로 변환\">\"파싱\"</dfn> 지원을 원하면 필요.\n\nFastAPI가 사용하는:\n\n* [`uvicorn`](https://www.uvicorn.dev) - 애플리케이션을 로드하고 제공하는 서버를 위한 것입니다. 여기에는 고성능 서빙에 필요한 일부 의존성(예: `uvloop`)이 포함된 `uvicorn[standard]`가 포함됩니다.\n* `fastapi-cli[standard]` - `fastapi` 명령을 제공하기 위한 것입니다.\n    * 여기에는 [FastAPI Cloud](https://fastapicloud.com)에 FastAPI 애플리케이션을 배포할 수 있게 해주는 `fastapi-cloud-cli`가 포함됩니다.\n\n### `standard` 의존성 없이 { #without-standard-dependencies }\n\n`standard` 선택적 의존성을 포함하고 싶지 않다면, `pip install \"fastapi[standard]\"` 대신 `pip install fastapi`로 설치할 수 있습니다.\n\n### `fastapi-cloud-cli` 없이 { #without-fastapi-cloud-cli }\n\n표준 의존성과 함께 FastAPI를 설치하되 `fastapi-cloud-cli` 없이 설치하고 싶다면, `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`로 설치할 수 있습니다.\n\n### 추가 선택적 의존성 { #additional-optional-dependencies }\n\n추가로 설치하고 싶을 수 있는 의존성도 있습니다.\n\n추가 선택적 Pydantic 의존성:\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - 설정 관리를 위한 것입니다.\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - Pydantic에서 사용할 추가 타입을 위한 것입니다.\n\n추가 선택적 FastAPI 의존성:\n\n* [`orjson`](https://github.com/ijl/orjson) - `ORJSONResponse`를 사용하려면 필요.\n* [`ujson`](https://github.com/esnme/ultrajson) - `UJSONResponse`를 사용하려면 필요.\n\n## 라이센스 { #license }\n\n이 프로젝트는 MIT 라이센스 조약에 따라 라이센스가 부여됩니다.\n"
  },
  {
    "path": "docs/ko/docs/learn/index.md",
    "content": "# 배우기 { #learn }\n\n여기 **FastAPI**를 배우기 위한 입문 섹션과 자습서가 있습니다.\n\n여러분은 이것을 FastAPI를 배우기 위한 **책**, **강의**, **공식**이자 권장되는 방법으로 생각할 수 있습니다. 😎\n"
  },
  {
    "path": "docs/ko/docs/project-generation.md",
    "content": "# Full Stack FastAPI 템플릿 { #full-stack-fastapi-template }\n\n템플릿은 일반적으로 특정 설정과 함께 제공되지만, 유연하고 커스터마이징이 가능하게 디자인 되었습니다. 이 특성들은 여러분이 프로젝트의 요구사항에 맞춰 수정, 적용을 할 수 있게 해주고, 템플릿이 완벽한 시작점이 되게 해줍니다. 🏁\n\n많은 초기 설정, 보안, 데이터베이스 및 일부 API 엔드포인트가 이미 준비되어 있으므로, 여러분은 이 템플릿을 시작하는 데 사용할 수 있습니다.\n\nGitHub 저장소: [Full Stack FastAPI 템플릿](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## Full Stack FastAPI 템플릿 - 기술 스택과 기능들 { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ Python 백엔드 API를 위한 [**FastAPI**](https://fastapi.tiangolo.com/ko).\n    - 🧰 Python SQL 데이터베이스 상호작용을 위한 [SQLModel](https://sqlmodel.tiangolo.com) (ORM).\n    - 🔍 FastAPI에 의해 사용되는, 데이터 검증과 설정 관리를 위한 [Pydantic](https://docs.pydantic.dev).\n    - 💾 SQL 데이터베이스로서의 [PostgreSQL](https://www.postgresql.org).\n- 🚀 프론트엔드를 위한 [React](https://react.dev).\n    - 💃 TypeScript, hooks, Vite 및 기타 현대적인 프론트엔드 스택을 사용.\n    - 🎨 프론트엔드 컴포넌트를 위한 [Tailwind CSS](https://tailwindcss.com) 및 [shadcn/ui](https://ui.shadcn.com).\n    - 🤖 자동으로 생성된 프론트엔드 클라이언트.\n    - 🧪 End-to-End 테스트를 위한 [Playwright](https://playwright.dev).\n    - 🦇 다크 모드 지원.\n- 🐋 개발 환경과 프로덕션(운영)을 위한 [Docker Compose](https://www.docker.com).\n- 🔒 기본으로 지원되는 안전한 비밀번호 해싱.\n- 🔑 JWT (JSON Web Token) 인증.\n- 📫 이메일 기반 비밀번호 복구.\n- ✅ [Pytest](https://pytest.org)를 이용한 테스트.\n- 📞 리버스 프록시 / 로드 밸런서로서의 [Traefik](https://traefik.io).\n- 🚢 Docker Compose를 이용한 배포 지침: 자동 HTTPS 인증서를 처리하기 위한 프론트엔드 Traefik 프록시 설정 방법을 포함.\n- 🏭 GitHub Actions를 기반으로 CI (지속적인 통합) 및 CD (지속적인 배포).\n"
  },
  {
    "path": "docs/ko/docs/python-types.md",
    "content": "# 파이썬 타입 소개 { #python-types-intro }\n\n파이썬은 선택적으로 \"타입 힌트(type hints)\"(“type annotations”라고도 함)를 지원합니다.\n\n이러한 **\"타입 힌트\"** 또는 애너테이션은 변수의 <dfn title=\"예: str, int, float, bool\">타입</dfn>을 선언할 수 있게 해주는 특수한 구문입니다.\n\n변수의 타입을 선언하면 에디터와 도구가 더 나은 지원을 제공할 수 있습니다.\n\n이 문서는 파이썬 타입 힌트에 대한 **빠른 자습서 / 내용 환기**입니다. **FastAPI**와 함께 사용하기 위해 필요한 최소한만 다룹니다... 실제로는 아주 조금만 있으면 됩니다.\n\n**FastAPI**는 모두 이러한 타입 힌트에 기반을 두고 있으며, 이는 많은 장점과 이점을 제공합니다.\n\n하지만 **FastAPI**를 전혀 사용하지 않더라도, 타입 힌트를 조금만 배워도 도움이 됩니다.\n\n/// note | 참고\n\n파이썬에 능숙하고 타입 힌트에 대해 이미 모두 알고 있다면, 다음 장으로 건너뛰세요.\n\n///\n\n## 동기 부여 { #motivation }\n\n간단한 예제로 시작해봅시다:\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\n이 프로그램을 호출하면 다음이 출력됩니다:\n\n```\nJohn Doe\n```\n\n이 함수는 다음을 수행합니다:\n\n* `first_name`과 `last_name`를 받습니다.\n* `title()`로 각각의 첫 글자를 대문자로 변환합니다.\n* 가운데에 공백을 두고 <dfn title=\"서로를 하나로 합칩니다. 하나의 내용 뒤에 다른 것의 내용을 이어 붙입니다.\">연결</dfn>합니다.\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### 수정하기 { #edit-it }\n\n매우 간단한 프로그램입니다.\n\n하지만 이제, 이것을 처음부터 작성한다고 상상해봅시다.\n\n어느 시점엔 함수를 정의하기 시작했고, 매개변수도 준비해두었을 겁니다...\n\n그런데 \"첫 글자를 대문자로 변환하는 그 메서드\"를 호출해야 합니다.\n\n`upper`였나요? `uppercase`였나요? `first_uppercase`? `capitalize`?\n\n그 다음, 개발자들의 오랜 친구인 에디터 자동완성을 시도합니다.\n\n함수의 첫 번째 매개변수인 `first_name`을 입력하고, 점(`.`)을 찍은 다음, 완성을 트리거하기 위해 `Ctrl+Space`를 누릅니다.\n\n하지만, 슬프게도 쓸만한 게 아무것도 없습니다:\n\n<img src=\"/img/python-types/image01.png\">\n\n### 타입 추가하기 { #add-types }\n\n이전 버전에서 한 줄만 수정해봅시다.\n\n함수의 매개변수인 정확히 이 부분을:\n\n```Python\n    first_name, last_name\n```\n\n에서:\n\n```Python\n    first_name: str, last_name: str\n```\n\n로 바꾸겠습니다.\n\n이게 다입니다.\n\n이것들이 \"타입 힌트\"입니다:\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\n이것은 다음처럼 기본값을 선언하는 것과는 다릅니다:\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\n다른 것입니다.\n\n등호(`=`)가 아니라 콜론(`:`)을 사용합니다.\n\n그리고 보통 타입 힌트를 추가해도, 타입 힌트 없이 일어나는 일과 비교해 특별히 달라지는 것은 없습니다.\n\n하지만 이제, 타입 힌트를 포함해 그 함수를 다시 만드는 중이라고 상상해봅시다.\n\n같은 지점에서 `Ctrl+Space`로 자동완성을 트리거하면 다음이 보입니다:\n\n<img src=\"/img/python-types/image02.png\">\n\n그러면 스크롤하며 옵션을 보다가, \"기억나는\" 것을 찾을 수 있습니다:\n\n<img src=\"/img/python-types/image03.png\">\n\n## 더 큰 동기부여 { #more-motivation }\n\n이 함수를 확인해보세요. 이미 타입 힌트가 있습니다:\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\n에디터가 변수의 타입을 알고 있기 때문에, 자동완성만 되는 게 아니라 오류 검사도 할 수 있습니다:\n\n<img src=\"/img/python-types/image04.png\">\n\n이제 고쳐야 한다는 것을 알고, `age`를 `str(age)`로 문자열로 바꿉니다:\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## 타입 선언 { #declaring-types }\n\n방금 타입 힌트를 선언하는 주요 위치를 보았습니다. 함수 매개변수입니다.\n\n이것은 **FastAPI**와 함께 사용할 때도 주요 위치입니다.\n\n### Simple 타입 { #simple-types }\n\n`str`뿐 아니라 모든 파이썬 표준 타입을 선언할 수 있습니다.\n\n예를 들어 다음을 사용할 수 있습니다:\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### `typing` 모듈 { #typing-module }\n\n몇 가지 추가적인 사용 사례에서는 표준 라이브러리의 `typing` 모듈에서 무언가를 import해야 할 수 있습니다. 예를 들어 어떤 값이 \"아무 타입\"일 수 있다고 선언하려면, `typing`의 `Any`를 사용할 수 있습니다:\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### Generic(제네릭) 타입 { #generic-types }\n\n일부 타입은 대괄호 안에 \"타입 매개변수\"를 받아 내부 타입을 정의할 수 있습니다. 예를 들어 \"문자열의 리스트\"는 `list[str]`로 선언합니다.\n\n이렇게 타입 매개변수를 받을 수 있는 타입을 **Generic types** 또는 **Generics**라고 부릅니다.\n\n대괄호와 내부 타입을 사용해 동일한 내장 타입들을 제네릭으로 사용할 수 있습니다:\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### List { #list }\n\n예를 들어, `str`의 `list`인 변수를 정의해봅시다.\n\n같은 콜론(`:`) 문법으로 변수를 선언합니다.\n\n타입으로 `list`를 넣습니다.\n\n`list`는 내부 타입을 포함하는 타입이므로, 그 타입들을 대괄호 안에 넣습니다:\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info | 정보\n\n대괄호 안의 내부 타입은 \"type parameters\"라고 부릅니다.\n\n이 경우 `str`이 `list`에 전달된 타입 매개변수입니다.\n\n///\n\n이는 \"변수 `items`는 `list`이고, 이 `list`의 각 아이템은 `str`이다\"라는 뜻입니다.\n\n이렇게 하면, 에디터는 리스트의 아이템을 처리하는 동안에도 지원을 제공할 수 있습니다:\n\n<img src=\"/img/python-types/image05.png\">\n\n타입이 없으면, 이는 거의 불가능합니다.\n\n변수 `item`이 리스트 `items`의 요소 중 하나라는 점에 주목하세요.\n\n그리고 에디터는 여전히 이것이 `str`임을 알고, 그에 대한 지원을 제공합니다.\n\n#### Tuple과 Set { #tuple-and-set }\n\n`tuple`과 `set`도 동일하게 선언할 수 있습니다:\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\n이는 다음을 의미합니다:\n\n* 변수 `items_t`는 3개의 아이템을 가진 `tuple`이며, `int`, 또 다른 `int`, 그리고 `str`입니다.\n* 변수 `items_s`는 `set`이며, 각 아이템의 타입은 `bytes`입니다.\n\n#### Dict { #dict }\n\n`dict`를 정의하려면, 쉼표로 구분된 2개의 타입 매개변수를 전달합니다.\n\n첫 번째 타입 매개변수는 `dict`의 키를 위한 것입니다.\n\n두 번째 타입 매개변수는 `dict`의 값을 위한 것입니다:\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\n이는 다음을 의미합니다:\n\n* 변수 `prices`는 `dict`입니다:\n    * 이 `dict`의 키는 `str` 타입입니다(예: 각 아이템의 이름).\n    * 이 `dict`의 값은 `float` 타입입니다(예: 각 아이템의 가격).\n\n#### Union { #union }\n\n변수가 **여러 타입 중 어떤 것이든** 될 수 있다고 선언할 수 있습니다. 예를 들어 `int` 또는 `str`입니다.\n\n이를 정의하려면 두 타입을 <dfn title='“비트 단위 OR 연산자”라고도 하지만, 여기서는 그 의미와 관련이 없습니다'>세로 막대(`|`)</dfn>로 구분해 사용합니다.\n\n이는 두 타입 집합의 합집합(union) 안의 어느 것이든 될 수 있다는 뜻이므로 \"유니온\"이라고 부릅니다.\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\n이는 `item`이 `int` 또는 `str`일 수 있다는 뜻입니다.\n\n#### `None`일 수도 있음 { #possibly-none }\n\n값이 `str` 같은 타입일 수도 있지만, `None`일 수도 있다고 선언할 수 있습니다.\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\n그냥 `str` 대신 `str | None`을 사용하면, 값이 항상 `str`이라고 가정하고 있지만 실제로는 `None`일 수도 있는 상황에서 에디터가 오류를 감지하도록 도와줍니다.\n\n### 타입으로서의 클래스 { #classes-as-types }\n\n변수의 타입으로 클래스를 선언할 수도 있습니다.\n\n이름을 가진 `Person` 클래스가 있다고 해봅시다:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\n그러면 `Person` 타입의 변수를 선언할 수 있습니다:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\n그리고 다시, 에디터의 모든 지원을 받을 수 있습니다:\n\n<img src=\"/img/python-types/image06.png\">\n\n이는 \"`one_person`은 `Person` 클래스의 **인스턴스**\"라는 뜻입니다.\n\n\"`one_person`은 `Person`이라는 **클래스**다\"라는 뜻이 아닙니다.\n\n## Pydantic 모델 { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/)은 데이터 검증을 수행하는 파이썬 라이브러리입니다.\n\n속성을 가진 클래스 형태로 데이터의 \"모양(shape)\"을 선언합니다.\n\n그리고 각 속성은 타입을 가집니다.\n\n그 다음 그 클래스의 인스턴스를 몇 가지 값으로 생성하면, 값들을 검증하고, (그런 경우라면) 적절한 타입으로 변환한 뒤, 모든 데이터를 가진 객체를 제공합니다.\n\n그리고 그 결과 객체에 대해 에디터의 모든 지원을 받을 수 있습니다.\n\nPydantic 공식 문서의 예시:\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info | 정보\n\nPydantic에 대해 더 알아보려면 [문서를 확인하세요](https://docs.pydantic.dev/).\n\n///\n\n**FastAPI**는 모두 Pydantic에 기반을 두고 있습니다.\n\n이 모든 것은 [자습서 - 사용자 안내서](tutorial/index.md)에서 실제로 많이 보게 될 것입니다.\n\n## 메타데이터 애너테이션이 있는 타입 힌트 { #type-hints-with-metadata-annotations }\n\n파이썬에는 `Annotated`를 사용해 이러한 타입 힌트에 **추가 <dfn title=\"데이터에 대한 데이터, 여기서는 타입에 대한 정보(예: 설명)\">메타데이터</dfn>**를 넣을 수 있는 기능도 있습니다.\n\n`Annotated`는 `typing`에서 import할 수 있습니다.\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\n파이썬 자체는 이 `Annotated`로 아무것도 하지 않습니다. 그리고 에디터와 다른 도구들에게는 타입이 여전히 `str`입니다.\n\n하지만 `Annotated`의 이 공간을 사용해, 애플리케이션이 어떻게 동작하길 원하는지에 대한 추가 메타데이터를 **FastAPI**에 제공할 수 있습니다.\n\n기억해야 할 중요한 점은 `Annotated`에 전달하는 **첫 번째 *타입 매개변수***가 **실제 타입**이라는 것입니다. 나머지는 다른 도구를 위한 메타데이터일 뿐입니다.\n\n지금은 `Annotated`가 존재하며, 표준 파이썬이라는 것만 알면 됩니다. 😎\n\n나중에 이것이 얼마나 **강력**할 수 있는지 보게 될 것입니다.\n\n/// tip | 팁\n\n이것이 **표준 파이썬**이라는 사실은, 에디터에서 가능한 **최고의 개발자 경험**을 계속 얻을 수 있다는 뜻이기도 합니다. 사용하는 도구로 코드를 분석하고 리팩터링하는 등에서도요. ✨\n\n또한 코드가 많은 다른 파이썬 도구 및 라이브러리와 매우 호환된다는 뜻이기도 합니다. 🚀\n\n///\n\n## **FastAPI**에서의 타입 힌트 { #type-hints-in-fastapi }\n\n**FastAPI**는 이러한 타입 힌트를 활용해 여러 가지를 합니다.\n\n**FastAPI**에서는 타입 힌트로 매개변수를 선언하면 다음을 얻습니다:\n\n* **에디터 도움**.\n* **타입 확인**.\n\n...그리고 **FastAPI**는 같은 선언을 다음에도 사용합니다:\n\n* **요구사항 정의**: 요청 경로 매개변수, 쿼리 매개변수, 헤더, 바디, 의존성 등에서.\n* **데이터 변환**: 요청에서 필요한 타입으로.\n* **데이터 검증**: 각 요청에서:\n    * 데이터가 유효하지 않을 때 클라이언트에 반환되는 **자동 오류**를 생성합니다.\n* OpenAPI를 사용해 API를 **문서화**:\n    * 자동 상호작용 문서 UI에서 사용됩니다.\n\n이 모든 것이 다소 추상적으로 들릴 수도 있습니다. 걱정하지 마세요. [자습서 - 사용자 안내서](tutorial/index.md)에서 실제로 확인하게 될 것입니다.\n\n가장 중요한 점은 표준 파이썬 타입을 한 곳에서 사용함으로써(더 많은 클래스, 데코레이터 등을 추가하는 대신) **FastAPI**가 여러분을 위해 많은 일을 해준다는 사실입니다.\n\n/// info | 정보\n\n자습서를 모두 끝내고 타입에 대해 더 알아보기 위해 다시 돌아왔다면, 좋은 자료로 [`mypy`의 \"cheat sheet\"](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html)가 있습니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/resources/index.md",
    "content": "# 리소스 { #resources }\n\n추가 리소스, 외부 링크, 그리고 더 많은 자료. ✈️\n"
  },
  {
    "path": "docs/ko/docs/translation-banner.md",
    "content": "/// details | 🌐 AI와 사람이 함께한 번역\n\n이 번역은 사람의 안내를 받아 AI가 만들었습니다. 🤝\n\n원문의 의미를 오해하거나 부자연스러워 보이는 등 오류가 있을 수 있습니다. 🤖\n\n[AI LLM을 더 잘 안내하는 데 도움을 주세요](https://fastapi.tiangolo.com/ko/contributing/#translations).\n\n[영문 버전](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/ko/docs/tutorial/background-tasks.md",
    "content": "# 백그라운드 작업 { #background-tasks }\n\nFastAPI에서는 응답을 반환한 *후에* 실행할 백그라운드 작업을 정의할 수 있습니다.\n\n백그라운드 작업은 요청 후에 발생해야 하지만, 클라이언트가 응답을 받기 전에 작업이 완료될 때까지 기다릴 필요가 없는 작업에 유용합니다.\n\n예를 들면 다음과 같습니다.\n\n* 작업을 수행한 후 전송되는 이메일 알림:\n    * 이메일 서버에 연결하고 이메일을 전송하는 것은 (몇 초 정도) \"느린\" 경향이 있으므로, 응답은 즉시 반환하고 이메일 알림은 백그라운드에서 전송할 수 있습니다.\n* 데이터 처리:\n    * 예를 들어 처리에 오랜 시간이 걸리는 프로세스를 거쳐야 하는 파일을 받았다면, \"Accepted\"(HTTP 202) 응답을 반환하고 백그라운드에서 파일을 처리할 수 있습니다.\n\n## `BackgroundTasks` 사용 { #using-backgroundtasks }\n\n먼저 `BackgroundTasks`를 임포트하고, `BackgroundTasks` 타입 선언으로 *경로 처리 함수*에 매개변수를 정의합니다:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI**가 `BackgroundTasks` 타입의 객체를 생성하고 해당 매개변수로 전달합니다.\n\n## 작업 함수 생성 { #create-a-task-function }\n\n백그라운드 작업으로 실행할 함수를 생성합니다.\n\n이는 매개변수를 받을 수 있는 표준 함수일 뿐입니다.\n\n`async def` 함수일 수도, 일반 `def` 함수일 수도 있으며, **FastAPI**가 이를 올바르게 처리하는 방법을 알고 있습니다.\n\n이 경우 작업 함수는 파일에 쓰기를 수행합니다(이메일 전송을 시뮬레이션).\n\n그리고 쓰기 작업은 `async`와 `await`를 사용하지 않으므로, 일반 `def`로 함수를 정의합니다:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## 백그라운드 작업 추가 { #add-the-background-task }\n\n*경로 처리 함수* 내부에서 `.add_task()` 메서드로 작업 함수를 *백그라운드 작업* 객체에 전달합니다:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()`는 다음 인자를 받습니다:\n\n* 백그라운드에서 실행될 작업 함수(`write_notification`).\n* 작업 함수에 순서대로 전달되어야 하는 인자 시퀀스(`email`).\n* 작업 함수에 전달되어야 하는 키워드 인자(`message=\"some notification\"`).\n\n## 의존성 주입 { #dependency-injection }\n\n`BackgroundTasks`는 의존성 주입 시스템에서도 동작하며, *경로 처리 함수*, 의존성(dependable), 하위 의존성 등 여러 수준에서 `BackgroundTasks` 타입의 매개변수를 선언할 수 있습니다.\n\n**FastAPI**는 각 경우에 무엇을 해야 하는지와 동일한 객체를 어떻게 재사용해야 하는지를 알고 있으므로, 모든 백그라운드 작업이 함께 병합되어 이후 백그라운드에서 실행됩니다:\n\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\n\n이 예제에서는 응답이 전송된 *후에* 메시지가 `log.txt` 파일에 작성됩니다.\n\n요청에 쿼리가 있었다면, 백그라운드 작업으로 로그에 작성됩니다.\n\n그 다음 *경로 처리 함수*에서 생성된 또 다른 백그라운드 작업이 `email` 경로 매개변수를 사용해 메시지를 작성합니다.\n\n## 기술적 세부사항 { #technical-details }\n\n`BackgroundTasks` 클래스는 [`starlette.background`](https://www.starlette.dev/background/)에서 직접 가져옵니다.\n\nFastAPI에 직접 임포트/포함되어 있으므로 `fastapi`에서 임포트할 수 있고, 실수로 `starlette.background`에서 대안인 `BackgroundTask`(끝에 `s`가 없음)를 임포트하는 것을 피할 수 있습니다.\n\n`BackgroundTask`가 아닌 `BackgroundTasks`만 사용하면, 이를 *경로 처리 함수*의 매개변수로 사용할 수 있고 나머지는 **FastAPI**가 `Request` 객체를 직접 사용할 때처럼 대신 처리해 줍니다.\n\nFastAPI에서 `BackgroundTask`만 단독으로 사용하는 것도 가능하지만, 코드에서 객체를 생성하고 이를 포함하는 Starlette `Response`를 반환해야 합니다.\n\n더 자세한 내용은 [Starlette의 Background Tasks 공식 문서](https://www.starlette.dev/background/)에서 확인할 수 있습니다.\n\n## 주의사항 { #caveat }\n\n무거운 백그라운드 계산을 수행해야 하고, 반드시 동일한 프로세스에서 실행할 필요가 없다면(예: 메모리, 변수 등을 공유할 필요가 없음) [Celery](https://docs.celeryq.dev) 같은 더 큰 도구를 사용하는 것이 도움이 될 수 있습니다.\n\n이들은 RabbitMQ나 Redis 같은 메시지/작업 큐 관리자 등 더 복잡한 설정을 필요로 하는 경향이 있지만, 여러 프로세스에서, 특히 여러 서버에서 백그라운드 작업을 실행할 수 있습니다.\n\n하지만 동일한 **FastAPI** 앱의 변수와 객체에 접근해야 하거나, 작은 백그라운드 작업(예: 이메일 알림 전송)을 수행해야 한다면, `BackgroundTasks`를 간단히 사용하면 됩니다.\n\n## 요약 { #recap }\n\n*경로 처리 함수*와 의존성에서 매개변수로 `BackgroundTasks`를 임포트해 사용하여 백그라운드 작업을 추가합니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/bigger-applications.md",
    "content": "# 더 큰 애플리케이션 - 여러 파일 { #bigger-applications-multiple-files }\n\n애플리케이션이나 웹 API를 만들 때, 모든 것을 하나의 파일에 담을 수 있는 경우는 드뭅니다.\n\n**FastAPI**는 모든 유연성을 유지하면서도 애플리케이션을 구조화할 수 있게 해주는 편리한 도구를 제공합니다.\n\n/// info | 정보\n\nFlask를 사용해 보셨다면, 이는 Flask의 Blueprints에 해당하는 개념입니다.\n\n///\n\n## 예시 파일 구조 { #an-example-file-structure }\n\n다음과 같은 파일 구조가 있다고 해봅시다:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | 팁\n\n`__init__.py` 파일이 여러 개 있습니다: 각 디렉터리 또는 하위 디렉터리에 하나씩 있습니다.\n\n이 파일들이 한 파일의 코드를 다른 파일로 import할 수 있게 해줍니다.\n\n예를 들어 `app/main.py`에는 다음과 같은 줄이 있을 수 있습니다:\n\n```\nfrom app.routers import items\n```\n\n///\n\n* `app` 디렉터리에는 모든 것이 들어 있습니다. 그리고 비어 있는 파일 `app/__init__.py`가 있어 \"Python package\"(“Python modules”의 모음)인 `app`이 됩니다.\n* `app/main.py` 파일이 있습니다. Python package(`__init__.py` 파일이 있는 디렉터리) 안에 있으므로, 이 package의 \"module\"입니다: `app.main`.\n* `app/dependencies.py` 파일도 있습니다. `app/main.py`와 마찬가지로 \"module\"입니다: `app.dependencies`.\n* `app/routers/` 하위 디렉터리가 있고, 여기에 또 `__init__.py` 파일이 있으므로 \"Python subpackage\"입니다: `app.routers`.\n* `app/routers/items.py` 파일은 `app/routers/` package 안에 있으므로, submodule입니다: `app.routers.items`.\n* `app/routers/users.py`도 동일하게 또 다른 submodule입니다: `app.routers.users`.\n* `app/internal/` 하위 디렉터리도 있고 여기에 `__init__.py`가 있으므로 또 다른 \"Python subpackage\"입니다: `app.internal`.\n* 그리고 `app/internal/admin.py` 파일은 또 다른 submodule입니다: `app.internal.admin`.\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n같은 파일 구조에 주석을 추가하면 다음과 같습니다:\n\n```bash\n.\n├── app                  # 'app'은 Python 패키지입니다\n│   ├── __init__.py      # 이 파일로 'app'이 'Python 패키지'가 됩니다\n│   ├── main.py          # 'main' 모듈, 예: import app.main\n│   ├── dependencies.py  # 'dependencies' 모듈, 예: import app.dependencies\n│   └── routers          # 'routers'는 'Python 하위 패키지'입니다\n│   │   ├── __init__.py  # 이 파일로 'routers'가 'Python 하위 패키지'가 됩니다\n│   │   ├── items.py     # 'items' 서브모듈, 예: import app.routers.items\n│   │   └── users.py     # 'users' 서브모듈, 예: import app.routers.users\n│   └── internal         # 'internal'은 'Python 하위 패키지'입니다\n│       ├── __init__.py  # 이 파일로 'internal'이 'Python 하위 패키지'가 됩니다\n│       └── admin.py     # 'admin' 서브모듈, 예: import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\n사용자만 처리하는 전용 파일이 `/app/routers/users.py`의 submodule이라고 해봅시다.\n\n코드를 정리하기 위해 사용자와 관련된 *path operations*를 나머지 코드와 분리해 두고 싶을 것입니다.\n\n하지만 이것은 여전히 같은 **FastAPI** 애플리케이션/웹 API의 일부입니다(같은 \"Python Package\"의 일부입니다).\n\n`APIRouter`를 사용해 해당 모듈의 *path operations*를 만들 수 있습니다.\n\n### `APIRouter` import하기 { #import-apirouter }\n\n`FastAPI` 클래스와 동일한 방식으로 import하고 \"instance\"를 생성합니다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### `APIRouter`로 *path operations* 만들기 { #path-operations-with-apirouter }\n\n그 다음 이를 사용해 *path operations*를 선언합니다.\n\n`FastAPI` 클래스를 사용할 때와 동일한 방식으로 사용합니다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\n`APIRouter`는 \"미니 `FastAPI`\" 클래스라고 생각할 수 있습니다.\n\n동일한 옵션들이 모두 지원됩니다.\n\n동일한 `parameters`, `responses`, `dependencies`, `tags` 등등.\n\n/// tip | 팁\n\n이 예시에서는 변수 이름이 `router`이지만, 원하는 이름으로 지어도 됩니다.\n\n///\n\n이제 이 `APIRouter`를 메인 `FastAPI` 앱에 포함(include)할 것이지만, 먼저 dependencies와 다른 `APIRouter` 하나를 확인해 보겠습니다.\n\n## Dependencies { #dependencies }\n\n애플리케이션의 여러 위치에서 사용되는 dependencies가 일부 필요하다는 것을 알 수 있습니다.\n\n그래서 이를 별도의 `dependencies` 모듈(`app/dependencies.py`)에 둡니다.\n\n이제 간단한 dependency를 사용해 커스텀 `X-Token` 헤더를 읽어 보겠습니다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | 팁\n\n이 예시를 단순화하기 위해 임의로 만든 헤더를 사용하고 있습니다.\n\n하지만 실제 상황에서는 통합된 [Security 유틸리티](security/index.md)를 사용하는 것이 더 좋은 결과를 얻을 수 있습니다.\n\n///\n\n## `APIRouter`가 있는 또 다른 모듈 { #another-module-with-apirouter }\n\n애플리케이션의 \"items\"를 처리하는 전용 endpoint들도 `app/routers/items.py` 모듈에 있다고 해봅시다.\n\n여기에는 다음에 대한 *path operations*가 있습니다:\n\n* `/items/`\n* `/items/{item_id}`\n\n구조는 `app/routers/users.py`와 완전히 동일합니다.\n\n하지만 우리는 조금 더 똑똑하게, 코드를 약간 단순화하고 싶습니다.\n\n이 모듈의 모든 *path operations*에는 다음이 동일하게 적용됩니다:\n\n* 경로 `prefix`: `/items`.\n* `tags`: (태그 하나: `items`).\n* 추가 `responses`.\n* `dependencies`: 모두 우리가 만든 `X-Token` dependency가 필요합니다.\n\n따라서 각 *path operation*마다 매번 모두 추가하는 대신, `APIRouter`에 한 번에 추가할 수 있습니다.\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\n각 *path operation*의 경로는 다음처럼 `/`로 시작해야 하므로:\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n...prefix에는 마지막 `/`가 포함되면 안 됩니다.\n\n따라서 이 경우 prefix는 `/items`입니다.\n\n또한 이 router에 포함된 모든 *path operations*에 적용될 `tags` 목록과 추가 `responses`도 넣을 수 있습니다.\n\n그리고 router의 모든 *path operations*에 추가될 `dependencies` 목록도 추가할 수 있으며, 해당 경로들로 들어오는 각 요청마다 실행/해결됩니다.\n\n/// tip | 팁\n\n[*path operation decorator의 dependencies*](dependencies/dependencies-in-path-operation-decorators.md)와 마찬가지로, *path operation function*에 어떤 값도 전달되지 않습니다.\n\n///\n\n최종적으로 item 경로는 다음과 같습니다:\n\n* `/items/`\n* `/items/{item_id}`\n\n...의도한 그대로입니다.\n\n* 단일 문자열 `\"items\"`를 포함하는 태그 목록으로 표시됩니다.\n    * 이 \"tags\"는 자동 대화형 문서 시스템(OpenAPI 사용)에 특히 유용합니다.\n* 모두 미리 정의된 `responses`를 포함합니다.\n* 이 모든 *path operations*는 실행되기 전에 `dependencies` 목록이 평가/실행됩니다.\n    * 특정 *path operation*에 dependencies를 추가로 선언하면 **그것들도 실행됩니다**.\n    * router dependencies가 먼저 실행되고, 그 다음에 [decorator의 `dependencies`](dependencies/dependencies-in-path-operation-decorators.md), 그리고 일반 파라미터 dependencies가 실행됩니다.\n    * [`scopes`가 있는 `Security` dependencies](../advanced/security/oauth2-scopes.md)도 추가할 수 있습니다.\n\n/// tip | 팁\n\n`APIRouter`에 `dependencies`를 두는 것은 예를 들어 전체 *path operations* 그룹에 인증을 요구할 때 사용할 수 있습니다. 각 경로 처리에 개별적으로 dependencies를 추가하지 않아도 됩니다.\n\n///\n\n/// check | 확인\n\n`prefix`, `tags`, `responses`, `dependencies` 파라미터는 (다른 많은 경우와 마찬가지로) 코드 중복을 피하도록 도와주는 **FastAPI**의 기능입니다.\n\n///\n\n### dependencies import하기 { #import-the-dependencies }\n\n이 코드는 모듈 `app.routers.items`, 파일 `app/routers/items.py`에 있습니다.\n\n그리고 dependency 함수는 모듈 `app.dependencies`, 파일 `app/dependencies.py`에서 가져와야 합니다.\n\n그래서 dependencies에 대해 `..`를 사용하는 상대 import를 사용합니다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### 상대 import가 동작하는 방식 { #how-relative-imports-work }\n\n/// tip | 팁\n\nimport가 동작하는 방식을 완벽히 알고 있다면, 아래 다음 섹션으로 넘어가세요.\n\n///\n\n다음과 같이 점 하나 `.`를 쓰면:\n\n```Python\nfrom .dependencies import get_token_header\n```\n\n의미는 다음과 같습니다:\n\n* 이 모듈(파일 `app/routers/items.py`)이 속한 같은 package(디렉터리 `app/routers/`)에서 시작해서...\n* `dependencies` 모듈(가상의 파일 `app/routers/dependencies.py`)을 찾고...\n* 그 안에서 함수 `get_token_header`를 import합니다.\n\n하지만 그 파일은 존재하지 않습니다. dependencies는 `app/dependencies.py` 파일에 있습니다.\n\n우리 앱/파일 구조를 다시 떠올려 보세요:\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\n다음처럼 점 두 개 `..`를 쓰면:\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\n의미는 다음과 같습니다:\n\n* 이 모듈(파일 `app/routers/items.py`)이 속한 같은 package(디렉터리 `app/routers/`)에서 시작해서...\n* 상위 package(디렉터리 `app/`)로 올라가고...\n* 그 안에서 `dependencies` 모듈(파일 `app/dependencies.py`)을 찾고...\n* 그 안에서 함수 `get_token_header`를 import합니다.\n\n이렇게 하면 제대로 동작합니다! 🎉\n\n---\n\n같은 방식으로 점 세 개 `...`를 사용했다면:\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\n의미는 다음과 같습니다:\n\n* 이 모듈(파일 `app/routers/items.py`)이 속한 같은 package(디렉터리 `app/routers/`)에서 시작해서...\n* 상위 package(디렉터리 `app/`)로 올라가고...\n* 그 package의 상위로 또 올라가는데(상위 package가 없습니다, `app`이 최상위입니다 😱)...\n* 그 안에서 `dependencies` 모듈(파일 `app/dependencies.py`)을 찾고...\n* 그 안에서 함수 `get_token_header`를 import합니다.\n\n이는 `app/` 위쪽의 어떤 package(자신의 `__init__.py` 파일 등을 가진)에 대한 참조가 됩니다. 하지만 우리는 그런 것이 없습니다. 그래서 이 예시에서는 에러가 발생합니다. 🚨\n\n이제 어떻게 동작하는지 알았으니, 앱이 얼마나 복잡하든 상대 import를 사용할 수 있습니다. 🤓\n\n### 커스텀 `tags`, `responses`, `dependencies` 추가하기 { #add-some-custom-tags-responses-and-dependencies }\n\n`APIRouter`에 이미 prefix `/items`와 `tags=[\"items\"]`를 추가했기 때문에 각 *path operation*에 이를 추가하지 않습니다.\n\n하지만 특정 *path operation*에만 적용될 _추가_ `tags`를 더할 수도 있고, 그 *path operation* 전용의 추가 `responses`도 넣을 수 있습니다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | 팁\n\n이 마지막 경로 처리는 `[\"items\", \"custom\"]` 태그 조합을 갖게 됩니다.\n\n그리고 문서에는 `404`용 응답과 `403`용 응답, 두 가지 모두가 표시됩니다.\n\n///\n\n## 메인 `FastAPI` { #the-main-fastapi }\n\n이제 `app/main.py` 모듈을 봅시다.\n\n여기에서 `FastAPI` 클래스를 import하고 사용합니다.\n\n이 파일은 모든 것을 하나로 엮는 애플리케이션의 메인 파일이 될 것입니다.\n\n그리고 대부분의 로직이 각자의 특정 모듈로 분리되어 있으므로, 메인 파일은 꽤 단순해집니다.\n\n### `FastAPI` import하기 { #import-fastapi }\n\n평소처럼 `FastAPI` 클래스를 import하고 생성합니다.\n\n또한 각 `APIRouter`의 dependencies와 결합될 [global dependencies](dependencies/global-dependencies.md)도 선언할 수 있습니다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### `APIRouter` import하기 { #import-the-apirouter }\n\n이제 `APIRouter`가 있는 다른 submodule들을 import합니다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\n`app/routers/users.py`와 `app/routers/items.py` 파일은 같은 Python package `app`에 속한 submodule들이므로, 점 하나 `.`를 사용해 \"상대 import\"로 가져올 수 있습니다.\n\n### import가 동작하는 방식 { #how-the-importing-works }\n\n다음 구문은:\n\n```Python\nfrom .routers import items, users\n```\n\n의미는 다음과 같습니다:\n\n* 이 모듈(파일 `app/main.py`)이 속한 같은 package(디렉터리 `app/`)에서 시작해서...\n* subpackage `routers`(디렉터리 `app/routers/`)를 찾고...\n* 그 안에서 submodule `items`(파일 `app/routers/items.py`)와 `users`(파일 `app/routers/users.py`)를 import합니다...\n\n`items` 모듈에는 `router` 변수(`items.router`)가 있습니다. 이는 `app/routers/items.py` 파일에서 만든 것과 동일하며 `APIRouter` 객체입니다.\n\n그리고 `users` 모듈도 같은 방식입니다.\n\n다음처럼 import할 수도 있습니다:\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info | 정보\n\n첫 번째 버전은 \"상대 import\"입니다:\n\n```Python\nfrom .routers import items, users\n```\n\n두 번째 버전은 \"절대 import\"입니다:\n\n```Python\nfrom app.routers import items, users\n```\n\nPython Packages와 Modules에 대해 더 알아보려면 [Modules에 대한 Python 공식 문서](https://docs.python.org/3/tutorial/modules.html)를 읽어보세요.\n\n///\n\n### 이름 충돌 피하기 { #avoid-name-collisions }\n\nsubmodule `items`를 직접 import하고, 그 안의 `router` 변수만 import하지는 않습니다.\n\n이는 submodule `users`에도 `router`라는 이름의 변수가 있기 때문입니다.\n\n만약 다음처럼 순서대로 import했다면:\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\n`users`의 `router`가 `items`의 `router`를 덮어써서 동시에 사용할 수 없게 됩니다.\n\n따라서 같은 파일에서 둘 다 사용할 수 있도록 submodule들을 직접 import합니다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### `users`와 `items`용 `APIRouter` 포함하기 { #include-the-apirouters-for-users-and-items }\n\n이제 submodule `users`와 `items`의 `router`를 포함해 봅시다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info | 정보\n\n`users.router`는 `app/routers/users.py` 파일 안의 `APIRouter`를 담고 있습니다.\n\n`items.router`는 `app/routers/items.py` 파일 안의 `APIRouter`를 담고 있습니다.\n\n///\n\n`app.include_router()`로 각 `APIRouter`를 메인 `FastAPI` 애플리케이션에 추가할 수 있습니다.\n\n그 router의 모든 route가 애플리케이션의 일부로 포함됩니다.\n\n/// note | 기술 세부사항\n\n내부적으로는 `APIRouter`에 선언된 각 *path operation*마다 *path operation*을 실제로 생성합니다.\n\n즉, 내부적으로는 모든 것이 동일한 하나의 앱인 것처럼 동작합니다.\n\n///\n\n/// check | 확인\n\nrouter를 포함(include)할 때 성능을 걱정할 필요는 없습니다.\n\n이 작업은 마이크로초 단위이며 시작 시에만 발생합니다.\n\n따라서 성능에 영향을 주지 않습니다. ⚡\n\n///\n\n### 커스텀 `prefix`, `tags`, `responses`, `dependencies`로 `APIRouter` 포함하기 { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\n이제 조직에서 `app/internal/admin.py` 파일을 받았다고 가정해 봅시다.\n\n여기에는 조직에서 여러 프로젝트 간에 공유하는 관리자용 *path operations*가 있는 `APIRouter`가 들어 있습니다.\n\n이 예시에서는 매우 단순하게 만들겠습니다. 하지만 조직 내 다른 프로젝트와 공유되기 때문에, 이를 수정할 수 없어 `prefix`, `dependencies`, `tags` 등을 `APIRouter`에 직접 추가할 수 없다고 해봅시다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\n하지만 `APIRouter`를 포함할 때 커스텀 `prefix`를 지정해 모든 *path operations*가 `/admin`으로 시작하게 하고, 이 프로젝트에서 이미 가진 `dependencies`로 보호하고, `tags`와 `responses`도 포함하고 싶습니다.\n\n원래 `APIRouter`를 수정하지 않고도 `app.include_router()`에 파라미터를 전달해서 이를 선언할 수 있습니다:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\n이렇게 하면 원래 `APIRouter`는 수정되지 않으므로, 조직 내 다른 프로젝트에서도 동일한 `app/internal/admin.py` 파일을 계속 공유할 수 있습니다.\n\n결과적으로 우리 앱에서 `admin` 모듈의 각 *path operations*는 다음을 갖게 됩니다:\n\n* prefix `/admin`.\n* tag `admin`.\n* dependency `get_token_header`.\n* 응답 `418`. 🍵\n\n하지만 이는 우리 앱에서 그 `APIRouter`에만 영향을 주며, 이를 사용하는 다른 코드에는 영향을 주지 않습니다.\n\n따라서 다른 프로젝트들은 같은 `APIRouter`를 다른 인증 방식으로 사용할 수도 있습니다.\n\n### *path operation* 포함하기 { #include-a-path-operation }\n\n*path operations*를 `FastAPI` 앱에 직접 추가할 수도 있습니다.\n\n여기서는 가능하다는 것을 보여주기 위해... 그냥 해봅니다 🤷:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\n그리고 `app.include_router()`로 추가한 다른 모든 *path operations*와 함께 올바르게 동작합니다.\n\n/// info | 매우 기술적인 세부사항\n\n**참고**: 이는 매우 기술적인 세부사항이라 아마 **그냥 건너뛰어도 됩니다**.\n\n---\n\n`APIRouter`는 \"mount\"되는 것이 아니며, 애플리케이션의 나머지 부분과 격리되어 있지 않습니다.\n\n이는 OpenAPI 스키마와 사용자 인터페이스에 그들의 *path operations*를 포함시키고 싶기 때문입니다.\n\n나머지와 독립적으로 격리해 \"mount\"할 수 없으므로, *path operations*는 직접 포함되는 것이 아니라 \"clone\"(재생성)됩니다.\n\n///\n\n## `pyproject.toml`에서 `entrypoint` 구성하기 { #configure-the-entrypoint-in-pyproject-toml }\n\nFastAPI `app` 객체가 `app/main.py`에 있으므로 `pyproject.toml` 파일에서 `entrypoint`를 다음과 같이 구성할 수 있습니다:\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\n이는 다음과 같이 import하는 것과 동일합니다:\n\n```python\nfrom app.main import app\n```\n\n이렇게 하면 `fastapi` 명령어가 여러분의 앱이 어디에 있는지 알 수 있습니다.\n\n/// Note | 참고\n\n명령어에 경로를 직접 전달할 수도 있습니다:\n\n```console\n$ fastapi dev app/main.py\n```\n\n하지만 `fastapi` 명령어를 실행할 때마다 올바른 경로를 기억해 전달해야 합니다.\n\n또한 [VS Code 확장](../editor-support.md)이나 [FastAPI Cloud](https://fastapicloud.com) 같은 다른 도구들이 이를 찾지 못할 수도 있으므로, `pyproject.toml`의 `entrypoint`를 사용하는 것을 권장합니다.\n\n///\n\n## 자동 API 문서 확인하기 { #check-the-automatic-api-docs }\n\n이제 앱을 실행하세요:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n그리고 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)에서 문서를 여세요.\n\n올바른 경로(및 prefix)와 올바른 태그를 사용해, 모든 submodule의 경로를 포함한 자동 API 문서를 볼 수 있습니다:\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## 같은 router를 다른 `prefix`로 여러 번 포함하기 { #include-the-same-router-multiple-times-with-different-prefix }\n\n`.include_router()`를 사용해 *같은* router를 서로 다른 prefix로 여러 번 포함할 수도 있습니다.\n\n예를 들어 `/api/v1`과 `/api/latest`처럼 서로 다른 prefix로 동일한 API를 노출할 때 유용할 수 있습니다.\n\n이는 고급 사용 방식이라 실제로 필요하지 않을 수도 있지만, 필요할 때를 위해 제공됩니다.\n\n## `APIRouter`에 다른 `APIRouter` 포함하기 { #include-an-apirouter-in-another }\n\n`APIRouter`를 `FastAPI` 애플리케이션에 포함할 수 있는 것과 같은 방식으로, 다음을 사용해 `APIRouter`를 다른 `APIRouter`에 포함할 수 있습니다:\n\n```Python\nrouter.include_router(other_router)\n```\n\n`FastAPI` 앱에 `router`를 포함하기 전에 수행해야 하며, 그래야 `other_router`의 *path operations*도 함께 포함됩니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/body-fields.md",
    "content": "# 본문 - 필드 { #body-fields }\n\n`Query`, `Path`와 `Body`를 사용해 *경로 처리 함수* 매개변수 내에서 추가적인 검증이나 메타데이터를 선언한 것처럼 Pydantic의 `Field`를 사용하여 모델 내에서 검증과 메타데이터를 선언할 수 있습니다.\n\n## `Field` 임포트 { #import-field }\n\n먼저 이를 임포트해야 합니다:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n/// warning | 경고\n\n`Field`는 다른 것들처럼 (`Query`, `Path`, `Body` 등) `fastapi`에서가 아닌 `pydantic`에서 바로 임포트 되는 점에 주의하세요.\n\n///\n\n## 모델 어트리뷰트 선언 { #declare-model-attributes }\n\n그 다음 모델 어트리뷰트와 함께 `Field`를 사용할 수 있습니다:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field`는 `Query`, `Path`와 `Body`와 같은 방식으로 동작하며, 모두 같은 매개변수들 등을 가집니다.\n\n/// note | 기술 세부사항\n\n실제로 `Query`, `Path`등, 여러분이 앞으로 볼 다른 것들은 공통 클래스인 `Param` 클래스의 서브클래스 객체를 만드는데, 그 자체로 Pydantic의 `FieldInfo` 클래스의 서브클래스입니다.\n\n그리고 Pydantic의 `Field` 또한 `FieldInfo`의 인스턴스를 반환합니다.\n\n`Body` 또한 `FieldInfo`의 서브클래스 객체를 직접적으로 반환합니다. 그리고 `Body` 클래스의 서브클래스인 것들도 여러분이 나중에 보게될 것입니다.\n\n `Query`, `Path`와 그 외 것들을 `fastapi`에서 임포트할 때, 이는 실제로 특별한 클래스를 반환하는 함수인 것을 기억해 주세요.\n\n///\n\n/// tip | 팁\n\n주목할 점은 타입, 기본 값 및 `Field`로 이루어진 각 모델 어트리뷰트가  `Path`, `Query`와 `Body`대신 `Field`를 사용하는 *경로 처리 함수*의 매개변수와 같은 구조를 가진다는 점 입니다.\n\n///\n\n## 별도 정보 추가 { #add-extra-information }\n\n`Field`, `Query`, `Body`, 그 외 안에 별도 정보를 선언할 수 있습니다. 이는 생성된 JSON 스키마에 포함됩니다.\n\n여러분이 예제를 선언할 때 나중에 이 공식 문서에서 별도 정보를 추가하는 방법을 배울 것입니다.\n\n/// warning | 경고\n\n별도 키가 전달된 `Field` 또한 여러분의 애플리케이션의 OpenAPI 스키마에 나타날 것입니다.\n이런 키가 OpenAPI 명세서의 일부가 아닐 수도 있으므로, [OpenAPI validator](https://validator.swagger.io/) 같은 몇몇 OpenAPI 도구들은 여러분이 생성한 스키마와 호환되지 않을 수 있습니다.\n\n///\n\n## 요약 { #recap }\n\n모델 어트리뷰트를 위한 추가 검증과 메타데이터 선언하기 위해 Pydantic의 `Field` 를 사용할 수 있습니다.\n\n또한 추가적인 JSON 스키마 메타데이터를 전달하기 위한 별도의 키워드 인자를 사용할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/body-multiple-params.md",
    "content": "# 본문 - 다중 매개변수 { #body-multiple-parameters }\n\n이제 `Path`와 `Query`를 어떻게 사용하는지 확인했으니, 요청 본문 선언에 대한 더 고급 사용법을 살펴보겠습니다.\n\n## `Path`, `Query` 및 본문 매개변수 혼합 { #mix-path-query-and-body-parameters }\n\n먼저, 물론 `Path`, `Query` 및 요청 본문 매개변수 선언을 자유롭게 혼합해서 사용할 수 있고, **FastAPI**는 어떤 동작을 할지 압니다.\n\n또한 기본 값을 `None`으로 설정해 본문 매개변수를 선택사항으로 선언할 수 있습니다:\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | 참고\n\n이 경우에는 본문에서 가져올 `item`이 선택사항이라는 점을 유의하세요. 기본값이 `None`이기 때문입니다.\n\n///\n\n## 다중 본문 매개변수 { #multiple-body-parameters }\n\n이전 예제에서, *경로 처리*는 아래처럼 `Item`의 속성을 가진 JSON 본문을 예상합니다:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n하지만, 다중 본문 매개변수 역시 선언할 수 있습니다. 예. `item`과 `user`:\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\n\n이 경우에, **FastAPI**는 이 함수에 본문 매개변수가 1개보다 많다는 것을 알아챌 것입니다(두 매개변수가 Pydantic 모델입니다).\n\n그래서, 본문에서 매개변수 이름을 키(필드 이름)로 사용하고, 다음과 같은 본문을 예상합니다:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | 참고\n\n`item`이 이전과 같은 방식으로 선언되었더라도, 이제는 본문에서 `item` 키 안에 있을 것으로 예상된다는 점을 유의하세요.\n\n///\n\n**FastAPI**는 요청에서 자동으로 변환을 수행하여, 매개변수 `item`이 해당하는 내용을 받고 `user`도 마찬가지로 받도록 합니다.\n\n복합 데이터의 검증을 수행하고, OpenAPI 스키마 및 자동 문서에도 그에 맞게 문서화합니다.\n\n## 본문 내의 단일 값 { #singular-values-in-body }\n\n쿼리 및 경로 매개변수에 대한 추가 데이터를 정의하는 `Query`와 `Path`가 있는 것과 같은 방식으로, **FastAPI**는 동등한 `Body`를 제공합니다.\n\n예를 들어 이전 모델을 확장해서, `item`과 `user` 외에도 같은 본문에 `importance`라는 다른 키를 두고 싶을 수 있습니다.\n\n단일 값이므로 그대로 선언하면, **FastAPI**는 이를 쿼리 매개변수라고 가정할 것입니다.\n\n하지만 `Body`를 사용하여 다른 본문 키로 처리하도록 **FastAPI**에 지시할 수 있습니다:\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\n\n이 경우에는 **FastAPI**가 다음과 같은 본문을 예상할 것입니다:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\n다시 말해, 데이터 타입을 변환하고, 검증하고, 문서화하는 등의 작업을 수행합니다.\n\n## 다중 본문 매개변수와 쿼리 { #multiple-body-params-and-query }\n\n물론, 필요할 때마다 어떤 본문 매개변수에 추가로 쿼리 매개변수도 선언할 수 있습니다.\n\n기본적으로 단일 값은 쿼리 매개변수로 해석되므로, 명시적으로 `Query`를 추가할 필요 없이 이렇게 하면 됩니다:\n\n```Python\nq: str | None = None\n```\n\n예를 들어:\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n\n/// info | 정보\n\n`Body` 또한 `Query`, `Path` 그리고 이후에 볼 다른 것들과 마찬가지로 동일한 추가 검증과 메타데이터 매개변수를 모두 갖고 있습니다.\n\n///\n\n## 단일 본문 매개변수 삽입하기 { #embed-a-single-body-parameter }\n\nPydantic 모델 `Item`에서 가져온 단일 `item` 본문 매개변수만 있다고 하겠습니다.\n\n기본적으로 **FastAPI**는 그 본문을 직접 예상합니다.\n\n하지만 추가 본문 매개변수를 선언할 때처럼, `item` 키를 가지고 그 안에 모델 내용이 들어 있는 JSON을 예상하게 하려면, `Body`의 특별한 매개변수 `embed`를 사용할 수 있습니다:\n\n```Python\nitem: Item = Body(embed=True)\n```\n\n다음과 같이요:\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\n\n이 경우 **FastAPI**는 다음과 같은 본문을 예상합니다:\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\n다음 대신에:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## 정리 { #recap }\n\n요청은 본문을 하나만 가질 수 있지만, *경로 처리 함수*에 다중 본문 매개변수를 추가할 수 있습니다.\n\n하지만 **FastAPI**는 이를 처리하고, 함수에 올바른 데이터를 제공하며, *경로 처리*에서 올바른 스키마를 검증하고 문서화합니다.\n\n또한 단일 값을 본문의 일부로 받도록 선언할 수 있습니다.\n\n그리고 단 하나의 매개변수만 선언되어 있더라도, **FastAPI**에 본문을 키 안에 삽입하도록 지시할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/body-nested-models.md",
    "content": "# 본문 - 중첩 모델 { #body-nested-models }\n\n**FastAPI**를 사용하면 (Pydantic 덕분에) 임의로 깊게 중첩된 모델을 정의, 검증, 문서화하고 사용할 수 있습니다.\n\n## 리스트 필드 { #list-fields }\n\n어트리뷰트를 서브타입으로 정의할 수 있습니다. 예를 들어 파이썬 `list`는:\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\n이는 `tags`를 리스트로 만들지만, 리스트 요소의 타입을 선언하지는 않습니다.\n\n## 타입 매개변수가 있는 리스트 필드 { #list-fields-with-type-parameter }\n\n하지만 파이썬에는 내부 타입, 즉 \"타입 매개변수\"를 사용해 리스트를 선언하는 특정한 방법이 있습니다:\n\n### 타입 매개변수로 `list` 선언 { #declare-a-list-with-a-type-parameter }\n\n`list`, `dict`, `tuple`처럼 타입 매개변수(내부 타입)를 갖는 타입을 선언하려면,\n대괄호 `[` 및 `]`를 사용해 내부 타입(들)을 \"타입 매개변수\"로 전달하세요.\n\n```Python\nmy_list: list[str]\n```\n\n이 모든 것은 타입 선언을 위한 표준 파이썬 문법입니다.\n\n내부 타입을 갖는 모델 어트리뷰트에 대해 동일한 표준 문법을 사용하세요.\n\n마찬가지로 예제에서 `tags`를 구체적으로 \"문자열의 리스트\"로 만들 수 있습니다:\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## 집합 타입 { #set-types }\n\n그런데 생각해보니 태그는 반복되면 안 되고, 아마 고유한 문자열이어야 할 것입니다.\n\n그리고 파이썬에는 고유한 항목들의 집합을 위한 특별한 데이터 타입 `set`이 있습니다.\n\n그렇다면 `tags`를 문자열의 집합으로 선언할 수 있습니다:\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\n이렇게 하면 중복 데이터가 있는 요청을 받더라도 고유한 항목들의 집합으로 변환됩니다.\n\n그리고 해당 데이터를 출력할 때마다, 소스에 중복이 있더라도 고유한 항목들의 집합으로 출력됩니다.\n\n또한 그에 따라 주석이 생기고 문서화됩니다.\n\n## 중첩 모델 { #nested-models }\n\nPydantic 모델의 각 어트리뷰트는 타입을 갖습니다.\n\n그런데 그 타입 자체가 또 다른 Pydantic 모델일 수 있습니다.\n\n따라서 특정한 어트리뷰트 이름, 타입, 검증을 사용하여 깊게 중첩된 JSON \"객체\"를 선언할 수 있습니다.\n\n모든 것이 임의의 깊이로 중첩됩니다.\n\n### 서브모델 정의 { #define-a-submodel }\n\n예를 들어, `Image` 모델을 정의할 수 있습니다:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### 서브모델을 타입으로 사용 { #use-the-submodel-as-a-type }\n\n그리고 이를 어트리뷰트의 타입으로 사용할 수 있습니다:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\n이는 **FastAPI**가 다음과 유사한 본문을 기대한다는 것을 의미합니다:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\n다시 한번, **FastAPI**로 그 선언만 해도 얻는 것은:\n\n* 중첩 모델도 편집기 지원(자동완성 등)\n* 데이터 변환\n* 데이터 검증\n* 자동 문서화\n\n## 특별한 타입과 검증 { #special-types-and-validation }\n\n`str`, `int`, `float` 등과 같은 일반적인 단일 타입과는 별개로, `str`을 상속하는 더 복잡한 단일 타입을 사용할 수 있습니다.\n\n사용할 수 있는 모든 옵션을 보려면 [Pydantic의 Type Overview](https://docs.pydantic.dev/latest/concepts/types/)를 확인하세요. 다음 장에서 몇 가지 예제를 볼 수 있습니다.\n\n예를 들어 `Image` 모델에는 `url` 필드가 있으므로, 이를 `str` 대신 Pydantic의 `HttpUrl` 인스턴스로 선언할 수 있습니다:\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\n이 문자열은 유효한 URL인지 검사되며, JSON Schema / OpenAPI에도 그에 맞게 문서화됩니다.\n\n## 서브모델 리스트를 갖는 어트리뷰트 { #attributes-with-lists-of-submodels }\n\n`list`, `set` 등의 서브타입으로 Pydantic 모델을 사용할 수도 있습니다:\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\n아래와 같은 JSON 본문을 예상(변환, 검증, 문서화 등)합니다:\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info | 정보\n\n`images` 키가 이제 이미지 객체 리스트를 갖는지 주목하세요.\n\n///\n\n## 깊게 중첩된 모델 { #deeply-nested-models }\n\n임의로 깊게 중첩된 모델을 정의할 수 있습니다:\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info | 정보\n\n`Offer`가 `Item`의 리스트를 가지고, 그 `Item`이 다시 선택 사항인 `Image` 리스트를 갖는지 주목하세요\n\n///\n\n## 순수 리스트의 본문 { #bodies-of-pure-lists }\n\n예상되는 JSON 본문의 최상위 값이 JSON `array`(파이썬 `list`)라면, Pydantic 모델에서와 마찬가지로 함수의 매개변수에서 타입을 선언할 수 있습니다:\n\n```Python\nimages: list[Image]\n```\n\n이를 아래처럼:\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## 어디서나 편집기 지원 { #editor-support-everywhere }\n\n그리고 어디서나 편집기 지원을 받을 수 있습니다.\n\n리스트 내부 항목의 경우에도:\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\nPydantic 모델 대신 `dict`로 직접 작업한다면 이런 종류의 편집기 지원을 받을 수 없습니다.\n\n하지만 그 부분에 대해서도 걱정할 필요는 없습니다. 들어오는 dict는 자동으로 변환되고, 출력도 자동으로 JSON으로 변환됩니다.\n\n## 임의의 `dict` 본문 { #bodies-of-arbitrary-dicts }\n\n또한 키는 어떤 타입이고 값은 다른 타입인 `dict`로 본문을 선언할 수 있습니다.\n\n이렇게 하면 (Pydantic 모델을 사용하는 경우처럼) 유효한 필드/어트리뷰트 이름이 무엇인지 미리 알 필요가 없습니다.\n\n아직 모르는 키를 받으려는 경우에 유용합니다.\n\n---\n\n또 다른 유용한 경우는 다른 타입(예: `int`)의 키를 갖고 싶을 때입니다.\n\n여기서 그 경우를 볼 것입니다.\n\n이 경우, `int` 키와 `float` 값을 가진 한 어떤 `dict`든 받아들입니다:\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip | 팁\n\nJSON은 키로 `str`만 지원한다는 것을 염두에 두세요.\n\n하지만 Pydantic은 자동 데이터 변환 기능이 있습니다.\n\n즉, API 클라이언트는 키로 문자열만 보낼 수 있더라도, 해당 문자열이 순수한 정수를 포함하기만 하면 Pydantic이 이를 변환하고 검증합니다.\n\n그리고 `weights`로 받는 `dict`는 실제로 `int` 키와 `float` 값을 갖게 됩니다.\n\n///\n\n## 요약 { #recap }\n\n**FastAPI**를 사용하면 Pydantic 모델이 제공하는 최대 유연성을 확보하면서 코드를 간단하고 짧고 우아하게 유지할 수 있습니다.\n\n하지만 아래의 모든 이점도 있습니다:\n\n* 편집기 지원(어디서나 자동완성!)\n* 데이터 변환(일명 파싱/직렬화)\n* 데이터 검증\n* 스키마 문서화\n* 자동 문서\n"
  },
  {
    "path": "docs/ko/docs/tutorial/body-updates.md",
    "content": "# Body - 업데이트 { #body-updates }\n\n## `PUT`으로 교체 업데이트하기 { #update-replacing-with-put }\n\n항목을 업데이트하려면 [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) 작업을 사용할 수 있습니다.\n\n`jsonable_encoder`를 사용해 입력 데이터를 JSON으로 저장할 수 있는 데이터로 변환할 수 있습니다(예: NoSQL 데이터베이스 사용 시). 예를 들어 `datetime`을 `str`로 변환하는 경우입니다.\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT`은 기존 데이터를 **대체**해야 하는 데이터를 받는 데 사용합니다.\n\n### 대체 시 주의사항 { #warning-about-replacing }\n\n즉, `PUT`으로 항목 `bar`를 업데이트하면서 다음과 같은 body를 보낸다면:\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\n이미 저장된 속성 `\"tax\": 20.2`가 포함되어 있지 않기 때문에, 입력 모델은 `\"tax\": 10.5`라는 기본값을 사용하게 됩니다.\n\n그리고 데이터는 그 “새로운” `tax` 값 `10.5`로 저장됩니다.\n\n## `PATCH`로 부분 업데이트하기 { #partial-updates-with-patch }\n\n[HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) 작업을 사용해 데이터를 *부분적으로* 업데이트할 수도 있습니다.\n\n이는 업데이트하려는 데이터만 보내고, 나머지는 그대로 두는 것을 의미합니다.\n\n/// note | 참고\n\n`PATCH`는 `PUT`보다 덜 일반적으로 사용되고 덜 알려져 있습니다.\n\n그리고 많은 팀이 부분 업데이트에도 `PUT`만 사용합니다.\n\n여러분은 원하는 방식으로 **자유롭게** 사용할 수 있으며, **FastAPI**는 어떤 제한도 강제하지 않습니다.\n\n다만 이 가이드는 의도된 사용 방식이 대략 어떻게 되는지를 보여줍니다.\n\n///\n\n### Pydantic의 `exclude_unset` 파라미터 사용하기 { #using-pydantics-exclude-unset-parameter }\n\n부분 업데이트를 받으려면 Pydantic 모델의 `.model_dump()`에서 `exclude_unset` 파라미터를 사용하는 것이 매우 유용합니다.\n\n예: `item.model_dump(exclude_unset=True)`.\n\n이는 `item` 모델을 만들 때 실제로 설정된 데이터만 포함하는 `dict`를 생성하고, 기본값은 제외합니다.\n\n그 다음 이를 사용해 (요청에서 전송되어) 설정된 데이터만 포함하고 기본값은 생략한 `dict`를 만들 수 있습니다:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### Pydantic의 `update` 파라미터 사용하기 { #using-pydantics-update-parameter }\n\n이제 `.model_copy()`를 사용해 기존 모델의 복사본을 만들고, 업데이트할 데이터가 들어있는 `dict`를 `update` 파라미터로 전달할 수 있습니다.\n\n예: `stored_item_model.model_copy(update=update_data)`:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### 부분 업데이트 요약 { #partial-updates-recap }\n\n정리하면, 부분 업데이트를 적용하려면 다음을 수행합니다:\n\n* (선택 사항) `PUT` 대신 `PATCH`를 사용합니다.\n* 저장된 데이터를 조회합니다.\n* 그 데이터를 Pydantic 모델에 넣습니다.\n* 입력 모델에서 기본값이 제외된 `dict`를 생성합니다(`exclude_unset` 사용).\n    * 이렇게 하면 모델의 기본값으로 이미 저장된 값을 덮어쓰지 않고, 사용자가 실제로 설정한 값만 업데이트할 수 있습니다.\n* 저장된 모델의 복사본을 만들고, 받은 부분 업데이트로 해당 속성들을 갱신합니다(`update` 파라미터 사용).\n* 복사한 모델을 DB에 저장할 수 있는 형태로 변환합니다(예: `jsonable_encoder` 사용).\n    * 이는 모델의 `.model_dump()` 메서드를 다시 사용하는 것과 비슷하지만, JSON으로 변환 가능한 데이터 타입으로 값이 확실히 변환되도록 보장합니다(예: `datetime` → `str`).\n* 데이터를 DB에 저장합니다.\n* 업데이트된 모델을 반환합니다.\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | 팁\n\n동일한 기법을 HTTP `PUT` 작업에서도 실제로 사용할 수 있습니다.\n\n하지만 여기의 예시는 이런 사용 사례를 위해 만들어진 `PATCH`를 사용합니다.\n\n///\n\n/// note | 참고\n\n입력 모델은 여전히 검증된다는 점에 유의하세요.\n\n따라서 모든 속성을 생략할 수 있는 부분 업데이트를 받으려면, 모든 속성이 optional로 표시된(기본값을 가지거나 `None`을 기본값으로 가지는) 모델이 필요합니다.\n\n**업데이트**를 위한 “모든 값이 optional인” 모델과, **생성**을 위한 “필수 값이 있는” 모델을 구분하려면 [추가 모델](extra-models.md)에 설명된 아이디어를 사용할 수 있습니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/tutorial/body.md",
    "content": "# 요청 본문 { #request-body }\n\n클라이언트(브라우저라고 해봅시다)로부터 여러분의 API로 데이터를 보내야 할 때, **요청 본문**으로 보냅니다.\n\n**요청** 본문은 클라이언트에서 API로 보내지는 데이터입니다. **응답** 본문은 API가 클라이언트로 보내는 데이터입니다.\n\n여러분의 API는 대부분의 경우 **응답** 본문을 보내야 합니다. 하지만 클라이언트는 항상 **요청 본문**을 보낼 필요는 없고, 때로는 (쿼리 매개변수와 함께) 어떤 경로만 요청하고 본문은 보내지 않을 수도 있습니다.\n\n**요청** 본문을 선언하기 위해서 모든 강력함과 이점을 갖춘 [Pydantic](https://docs.pydantic.dev/) 모델을 사용합니다.\n\n/// info | 정보\n\n데이터를 보내기 위해, (좀 더 보편적인) `POST`, `PUT`, `DELETE` 혹은 `PATCH` 중에 하나를 사용하는 것이 좋습니다.\n\n`GET` 요청에 본문을 담아 보내는 것은 명세서에 정의되지 않은 행동입니다. 그럼에도 불구하고, 이 방식은 아주 복잡한/극한의 사용 상황에서만 FastAPI에 의해 지원됩니다.\n\n`GET` 요청에 본문을 담는 것은 권장되지 않기에, Swagger UI같은 대화형 문서에서는 `GET` 사용시 담기는 본문에 대한 문서를 표시하지 않으며, 중간에 있는 프록시는 이를 지원하지 않을 수도 있습니다.\n\n///\n\n## Pydantic의 `BaseModel` 임포트 { #import-pydantics-basemodel }\n\n먼저 `pydantic`에서 `BaseModel`를 임포트해야 합니다:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## 여러분의 데이터 모델 만들기 { #create-your-data-model }\n\n`BaseModel`를 상속받은 클래스로 여러분의 데이터 모델을 선언합니다.\n\n모든 어트리뷰트에 대해 표준 파이썬 타입을 사용합니다:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\n\n쿼리 매개변수를 선언할 때와 같이, 모델 어트리뷰트가 기본 값을 가지고 있어도 이는 필수가 아닙니다. 그외에는 필수입니다. 그저 `None`을 사용하여 선택적으로 만들 수 있습니다.\n\n예를 들면, 위의 이 모델은 JSON \"`object`\" (혹은 파이썬 `dict`)을 다음과 같이 선언합니다:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n...`description`과 `tax`는 (기본 값이 `None`으로 되어 있어) 선택적이기 때문에, 이 JSON \"`object`\"는 다음과 같은 상황에서도 유효합니다:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## 매개변수로서 선언하기 { #declare-it-as-a-parameter }\n\n여러분의 *경로 처리*에 추가하기 위해, 경로 매개변수 그리고 쿼리 매개변수에서 선언했던 것과 같은 방식으로 선언하면 됩니다.\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n...그리고 만들어낸 모델인 `Item`으로 타입을 선언합니다.\n\n## 결과 { #results }\n\n위에서의 단순한 파이썬 타입 선언으로, **FastAPI**는 다음과 같이 동작합니다:\n\n* 요청의 본문을 JSON으로 읽어 들입니다.\n* (필요하다면) 대응되는 타입으로 변환합니다.\n* 데이터를 검증합니다.\n    * 만약 데이터가 유효하지 않다면, 정확히 어떤 것이 그리고 어디에서 데이터가 잘 못 되었는지 지시하는 친절하고 명료한 에러를 반환할 것입니다.\n* 매개변수 `item`에 포함된 수신 데이터를 제공합니다.\n    * 함수 내에서 매개변수를 `Item` 타입으로 선언했기 때문에, 모든 어트리뷰트와 그에 대한 타입에 대한 편집기 지원(완성 등)을 또한 받을 수 있습니다.\n* 여러분의 모델을 위한 [JSON Schema](https://json-schema.org) 정의를 생성합니다. 여러분의 프로젝트에 적합하다면 여러분이 사용하고 싶은 곳 어디에서나 사용할 수 있습니다.\n* 이러한 스키마는, 생성된 OpenAPI 스키마 일부가 될 것이며, 자동 문서화 <abbr title=\"User Interfaces - 사용자 인터페이스\">UIs</abbr>에 사용됩니다.\n\n## 자동 문서화 { #automatic-docs }\n\n모델의 JSON 스키마는 생성된 OpenAPI 스키마에 포함되며 대화형 API 문서에 표시됩니다:\n\n<img src=\"/img/tutorial/body/image01.png\">\n\n이를 필요로 하는 각각의 *경로 처리* 내부의 API 문서에도 사용됩니다:\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## 편집기 지원 { #editor-support }\n\n편집기에서, 함수 내에서 타입 힌트와 완성을 어디서나 (만약 Pydantic model 대신에 `dict`을 받을 경우 나타나지 않을 수 있습니다) 받을 수 있습니다:\n\n<img src=\"/img/tutorial/body/image03.png\">\n\n잘못된 타입 연산에 대한 에러 확인도 받을 수 있습니다:\n\n<img src=\"/img/tutorial/body/image04.png\">\n\n단순한 우연이 아닙니다. 프레임워크 전체가 이러한 디자인을 중심으로 설계되었습니다.\n\n그 어떤 구현 전에, 모든 편집기에서 작동할 수 있도록 보장하기 위해 설계 단계에서 혹독하게 테스트되었습니다.\n\n이를 지원하기 위해 Pydantic 자체에서 몇몇 변경점이 있었습니다.\n\n이전 스크린샷은 [Visual Studio Code](https://code.visualstudio.com)로 찍은 것입니다.\n\n하지만 똑같은 편집기 지원을 [PyCharm](https://www.jetbrains.com/pycharm/)와 대부분의 다른 파이썬 편집기에서도 받을 수 있습니다:\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip | 팁\n\n만약 [PyCharm](https://www.jetbrains.com/pycharm/)를 편집기로 사용한다면, [Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/)을 사용할 수 있습니다.\n\n다음 사항을 포함해 Pydantic 모델에 대한 편집기 지원을 향상시킵니다:\n\n* auto-completion\n* type checks\n* refactoring\n* searching\n* inspections\n\n///\n\n## 모델 사용하기 { #use-the-model }\n\n함수 안에서 모델 객체의 모든 어트리뷰트에 직접 접근 가능합니다:\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## 요청 본문 + 경로 매개변수 { #request-body-path-parameters }\n\n경로 매개변수와 요청 본문을 동시에 선언할 수 있습니다.\n\n**FastAPI**는 경로 매개변수와 일치하는 함수 매개변수가 **경로에서 가져와야 한다**는 것을 인지하며, Pydantic 모델로 선언된 그 함수 매개변수는 **요청 본문에서 가져와야 한다**는 것을 인지할 것입니다.\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n\n## 요청 본문 + 경로 + 쿼리 매개변수 { #request-body-path-query-parameters }\n\n**본문**, **경로** 그리고 **쿼리** 매개변수 모두 동시에 선언할 수도 있습니다.\n\n**FastAPI**는 각각을 인지하고 데이터를 올바른 위치에 가져올 것입니다.\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\n함수 매개변수는 다음을 따라서 인지하게 됩니다:\n\n* 만약 매개변수가 **경로**에도 선언되어 있다면, 이는 경로 매개변수로 사용될 것입니다.\n* 만약 매개변수가 (`int`, `float`, `str`, `bool` 등과 같은) **유일한 타입**으로 되어있으면, **쿼리** 매개변수로 해석될 것입니다.\n* 만약 매개변수가 **Pydantic 모델** 타입으로 선언되어 있으면, 요청 **본문**으로 해석될 것입니다.\n\n/// note | 참고\n\nFastAPI는 `q`의 값이 필요없음을 기본 값 `= None` 때문에 알게 됩니다.\n\n`str | None`은 FastAPI가 값이 필수인지 아닌지를 판단하기 위해 사용하지 않습니다. 기본 값이 `= None`이므로 필수가 아님을 알게 됩니다.\n\n하지만 타입 어노테이션을 추가하면 편집기가 더 나은 지원을 제공하고 오류를 감지할 수 있습니다.\n\n///\n\n## Pydantic없이 { #without-pydantic }\n\n만약 Pydantic 모델을 사용하고 싶지 않다면, **Body** 매개변수를 사용할 수도 있습니다. [Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body) 문서를 확인하세요.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/cookie-param-models.md",
    "content": "# 쿠키 매개변수 모델 { #cookie-parameter-models }\n\n관련있는 **쿠키**들의 그룹이 있는 경우, **Pydantic 모델**을 생성하여 선언할 수 있습니다. 🍪\n\n이를 통해 **여러 위치**에서 **모델을 재사용** 할 수 있고 모든 매개변수에 대한 유효성 검사 및 메타데이터를 한 번에 선언할 수도 있습니다. 😎\n\n/// note | 참고\n\n이 기능은 FastAPI 버전 `0.115.0` 이후부터 지원됩니다. 🤓\n\n///\n\n/// tip | 팁\n\n동일한 기술이 `Query`, `Cookie`, 그리고 `Header`에 적용됩니다. 😎\n\n///\n\n## Pydantic 모델을 사용한 쿠키 { #cookies-with-a-pydantic-model }\n\n**Pydantic 모델**에 필요한 **쿠키** 매개변수를 선언한 다음, 해당 매개변수를 `Cookie`로 선언합니다:\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI**는 요청에서 받은 **쿠키**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다.\n\n## 문서 확인하기 { #check-the-docs }\n\n문서 UI `/docs`에서 정의한 쿠키를 볼 수 있습니다:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info | 정보\n\n명심하세요, 내부적으로 **브라우저는 쿠키를 특별한 방식으로 처리**하기 때문에 **자바스크립트**가 쉽게 쿠키를 건드릴 수 **없습니다**.\n\n`/docs`에서 **API 문서 UI**로 이동하면 *경로 처리*에 대한 쿠키의 **문서**를 볼 수 있습니다.\n\n하지만 아무리 **데이터를 입력**하고 \"실행(Execute)\"을 클릭해도, 문서 UI는 **자바스크립트**로 작동하기 때문에 쿠키는 전송되지 않고, 아무 값도 쓰지 않은 것처럼 **오류** 메시지를 보게 됩니다.\n\n///\n\n## 추가 쿠키 금지하기 { #forbid-extra-cookies }\n\n일부 특별한 사용 사례(흔하지는 않겠지만)에서는 수신하려는 쿠키를 **제한**할 수 있습니다.\n\n이제 API는 자신의 <dfn title=\"혹시라도 오해할까 봐 하는 농담입니다. 쿠키 동의와는 아무 관련이 없지만, 이제 API도 불쌍한 쿠키를 거절할 수 있다는 점이 웃기네요. 쿠키 하나 드세요. 🍪\">쿠키 동의</dfn>를 제어할 수 있는 권한을 갖게 되었습니다. 🤪🍪\n\nPydantic의 모델 구성을 사용하여 추가(`extra`) 필드를 금지(`forbid`)할 수 있습니다:\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\n클라이언트가 **추가 쿠키**를 보내려고 시도하면, **오류** 응답을 받게 됩니다.\n\n동의를 얻기 위해 애쓰는 불쌍한 쿠키 배너(팝업)들, <dfn title=\"이것도 농담입니다. 신경 쓰지 마세요. 쿠키와 함께 커피 한 잔 하세요. ☕\">API가 거부</dfn>하는데도. 🍪\n\n예를 들어, 클라이언트가 `good-list-please` 값으로 `santa_tracker` 쿠키를 보내려고 하면 클라이언트는 `santa_tracker` <dfn title=\"산타는 쿠키가 부족한 것을 못마땅해합니다. 🎅 좋아요, 이제 더 이상 쿠키 농담은 하지 않겠습니다.\">쿠키가 허용되지 않는다</dfn>는 **오류** 응답을 받게 됩니다:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## 요약 { #summary }\n\n**Pydantic 모델**을 사용하여 **FastAPI**에서 <dfn title=\"가시기 전에 마지막 쿠키 하나 드세요. 🍪\">**쿠키**</dfn>를 선언할 수 있습니다. 😎\n"
  },
  {
    "path": "docs/ko/docs/tutorial/cookie-params.md",
    "content": "# 쿠키 매개변수 { #cookie-parameters }\n\n쿠키 매개변수를 `Query`와 `Path` 매개변수들과 같은 방식으로 정의할 수 있습니다.\n\n## `Cookie` 임포트 { #import-cookie }\n\n먼저 `Cookie`를 임포트합니다:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## `Cookie` 매개변수 선언 { #declare-cookie-parameters }\n\n그런 다음, `Path`와 `Query`처럼 동일한 구조를 사용하는 쿠키 매개변수를 선언합니다.\n\n첫 번째 값은 기본값이며, 추가 검증이나 어노테이션 매개변수 모두 전달할 수 있습니다:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | 기술 세부사항\n\n`Cookie`는 `Path` 및 `Query`의 \"자매\"클래스입니다. 이 역시 동일한 공통 `Param` 클래스를 상속합니다.\n\n하지만 `fastapi`에서 `Query`, `Path`, `Cookie` 그리고 다른 것들을 임포트할 때, 실제로는 특별한 클래스를 반환하는 함수임을 기억하세요.\n\n///\n\n/// info\n\n쿠키를 선언하기 위해서는 `Cookie`를 사용해야 합니다. 그렇지 않으면 해당 매개변수를 쿼리 매개변수로 해석하기 때문입니다.\n\n///\n\n/// info\n\n**브라우저는 쿠키를** 내부적으로 특별한 방식으로 처리하기 때문에, **JavaScript**가 쉽게 쿠키를 다루도록 허용하지 않는다는 점을 염두에 두세요.\n\n`/docs`의 **API docs UI**로 이동하면 *경로 처리*에 대한 쿠키 **문서**를 확인할 수 있습니다.\n\n하지만 **데이터를 채우고** \"Execute\"를 클릭하더라도, docs UI는 **JavaScript**로 동작하기 때문에 쿠키가 전송되지 않고, 아무 값도 입력하지 않은 것처럼 **오류** 메시지를 보게 될 것입니다.\n\n///\n\n## 요약 { #recap }\n\n`Query`와 `Path`에서 사용하는 것과 동일한 공통 패턴으로, `Cookie`를 사용해 쿠키를 선언합니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/cors.md",
    "content": "# CORS (교차-출처 리소스 공유) { #cors-cross-origin-resource-sharing }\n\n[CORS 또는 \"Cross-Origin Resource Sharing\"](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)란, 브라우저에서 실행되는 프론트엔드에 백엔드와 통신하는 JavaScript 코드가 있고, 백엔드가 프론트엔드와 다른 \"출처(origin)\"에 있는 상황을 의미합니다.\n\n## 출처 { #origin }\n\n출처란 프로토콜(`http`, `https`), 도메인(`myapp.com`, `localhost`, `localhost.tiangolo.com`), 그리고 포트(`80`, `443`, `8080`)의 조합을 의미합니다.\n\n따라서, 아래는 모두 상이한 출처입니다:\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\n모두 `localhost`에 있더라도, 서로 다른 프로토콜이나 포트를 사용하므로 서로 다른 \"출처\"입니다.\n\n## 단계 { #steps }\n\n그러면 브라우저에서 `http://localhost:8080`으로 실행되는 프론트엔드가 있고, 그 JavaScript가 `http://localhost`에서 실행되는 백엔드와 통신하려고 한다고 해봅시다(포트를 명시하지 않았기 때문에, 브라우저는 기본 포트 `80`을 가정합니다).\n\n그러면 브라우저는 `:80`-백엔드에 HTTP `OPTIONS` 요청을 보내고, 백엔드가 이 다른 출처(`http://localhost:8080`)로부터의 통신을 허가하는 적절한 헤더를 보내면, `:8080`-브라우저는 프론트엔드의 JavaScript가 `:80`-백엔드에 요청을 보낼 수 있도록 합니다.\n\n이를 위해, `:80`-백엔드는 \"허용된 출처(allowed origins)\" 목록을 가지고 있어야 합니다.\n\n이 경우, `:8080`-프론트엔드가 올바르게 동작하려면 목록에 `http://localhost:8080`이 포함되어야 합니다.\n\n## 와일드카드 { #wildcards }\n\n또한 목록을 `\"*\"`(\"와일드카드\")로 선언해 모두 허용된다고 말할 수도 있습니다.\n\n하지만 그러면 자격 증명(credentials)이 포함된 모든 것을 제외하고 특정 유형의 통신만 허용하게 됩니다. 예: 쿠키, Bearer Token에 사용되는 것과 같은 Authorization 헤더 등.\n\n따라서 모든 것이 올바르게 동작하게 하려면, 허용된 출처를 명시적으로 지정하는 것이 더 좋습니다.\n\n## `CORSMiddleware` 사용 { #use-corsmiddleware }\n\n`CORSMiddleware`를 사용하여 **FastAPI** 애플리케이션에서 이를 설정할 수 있습니다.\n\n* `CORSMiddleware`를 임포트합니다.\n* 허용된 출처(문자열)의 리스트를 생성합니다.\n* **FastAPI** 애플리케이션에 \"미들웨어(middleware)\"로 추가합니다.\n\n또한 백엔드가 다음을 허용할지 여부도 지정할 수 있습니다:\n\n* 자격 증명(Authorization 헤더, 쿠키 등).\n* 특정 HTTP 메서드(`POST`, `PUT`) 또는 와일드카드 `\"*\"`를 사용한 모든 메서드.\n* 특정 HTTP 헤더 또는 와일드카드 `\"*\"`를 사용한 모든 헤더.\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\n\n`CORSMiddleware` 구현에서 사용하는 기본 매개변수는 기본적으로 제한적이므로, 브라우저가 Cross-Domain 컨텍스트에서 특정 출처, 메서드 또는 헤더를 사용할 수 있도록 하려면 이를 명시적으로 활성화해야 합니다.\n\n다음 인자들이 지원됩니다:\n\n* `allow_origins` - 교차-출처 요청을 보낼 수 있도록 허용해야 하는 출처의 리스트입니다. 예: `['https://example.org', 'https://www.example.org']`. 모든 출처를 허용하려면 `['*']`를 사용할 수 있습니다.\n* `allow_origin_regex` - 교차-출처 요청을 보낼 수 있도록 허용해야 하는 출처와 매칭할 정규표현식 문자열입니다. 예: `'https://.*\\.example\\.org'`.\n* `allow_methods` - 교차-출처 요청에 허용되어야 하는 HTTP 메서드의 리스트입니다. 기본값은 `['GET']`입니다. 모든 표준 메서드를 허용하려면 `['*']`를 사용할 수 있습니다.\n* `allow_headers` - 교차-출처 요청에 대해 지원되어야 하는 HTTP 요청 헤더의 리스트입니다. 기본값은 `[]`입니다. 모든 헤더를 허용하려면 `['*']`를 사용할 수 있습니다. `Accept`, `Accept-Language`, `Content-Language`, `Content-Type` 헤더는 [단순 CORS 요청](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests)에 대해 항상 허용됩니다.\n* `allow_credentials` - 교차-출처 요청에 대해 쿠키를 지원해야 함을 나타냅니다. 기본값은 `False`입니다.\n\n    `allow_credentials`가 `True`로 설정된 경우 `allow_origins`, `allow_methods`, `allow_headers` 중 어느 것도 `['*']`로 설정할 수 없습니다. 모두 [명시적으로 지정](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards)되어야 합니다.\n\n* `expose_headers` - 브라우저에서 접근 가능해야 하는 모든 응답 헤더를 나타냅니다. 기본값은 `[]`입니다.\n* `max_age` - 브라우저가 CORS 응답을 캐시하는 최대 시간을 초 단위로 설정합니다. 기본값은 `600`입니다.\n\n미들웨어는 두 가지 특정한 종류의 HTTP 요청에 응답합니다...\n\n### CORS 사전 요청 { #cors-preflight-requests }\n\n`Origin` 및 `Access-Control-Request-Method` 헤더가 있는 모든 `OPTIONS` 요청입니다.\n\n이 경우 미들웨어는 들어오는 요청을 가로채 적절한 CORS 헤더와 함께, 정보 제공 목적으로 `200` 또는 `400` 응답을 반환합니다.\n\n### 단순한 요청 { #simple-requests }\n\n`Origin` 헤더가 있는 모든 요청입니다. 이 경우 미들웨어는 요청을 정상적으로 통과시키지만, 응답에 적절한 CORS 헤더를 포함합니다.\n\n## 더 많은 정보 { #more-info }\n\n<abbr title=\"Cross-Origin Resource Sharing - 교차-출처 리소스 공유\">CORS</abbr>에 대한 더 많은 정보는 [Mozilla CORS 문서](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)를 참고하세요.\n\n/// note | 기술 세부사항\n\n`from starlette.middleware.cors import CORSMiddleware`도 사용할 수 있습니다.\n\n**FastAPI**는 개발자인 여러분의 편의를 위해 `fastapi.middleware`에 여러 미들웨어를 제공합니다. 하지만 사용 가능한 미들웨어 대부분은 Starlette에서 직접 제공됩니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/tutorial/debugging.md",
    "content": "# 디버깅 { #debugging }\n\n예를 들면 Visual Studio Code 또는 PyCharm을 사용하여 편집기에서 디버거를 연결할 수 있습니다.\n\n## `uvicorn` 호출 { #call-uvicorn }\n\nFastAPI 애플리케이션에서 `uvicorn`을 직접 임포트하여 실행합니다:\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### `__name__ == \"__main__\"` 에 대하여 { #about-name-main }\n\n`__name__ == \"__main__\"`의 주요 목적은 다음과 같이 파일이 호출될 때 실행되는 일부 코드를 갖는 것입니다.\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\n그러나 다음과 같이 다른 파일을 가져올 때는 호출되지 않습니다.\n\n```Python\nfrom myapp import app\n```\n\n#### 추가 세부사항 { #more-details }\n\n파일 이름이 `myapp.py`라고 가정해 보겠습니다.\n\n다음과 같이 실행하면\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nPython에 의해 자동으로 생성된 파일의 내부 변수 `__name__`은 문자열 `\"__main__\"`을 값으로 갖게 됩니다.\n\n따라서 섹션\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\n이 실행됩니다.\n\n---\n\n해당 모듈(파일)을 가져오면 이런 일이 발생하지 않습니다\n\n그래서 다음과 같은 다른 파일 `importer.py`가 있는 경우:\n\n```Python\nfrom myapp import app\n\n# Some more code\n```\n\n이 경우 `myapp.py` 내부의 자동 변수 `__name__`에는 값이 `\"__main__\"`이 들어가지 않습니다.\n\n따라서 다음 행\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\n은 실행되지 않습니다.\n\n/// info | 정보\n\n자세한 내용은 [공식 Python 문서](https://docs.python.org/3/library/__main__.html)를 확인하세요.\n\n///\n\n## 디버거로 코드 실행 { #run-your-code-with-your-debugger }\n\n코드에서 직접 Uvicorn 서버를 실행하고 있기 때문에 디버거에서 직접 Python 프로그램(FastAPI 애플리케이션)을 호출할 수 있습니다.\n\n---\n\n예를 들어 Visual Studio Code에서 다음을 수행할 수 있습니다.\n\n* \"Debug\" 패널로 이동합니다.\n* \"Add configuration...\".\n* \"Python\"을 선택합니다.\n* \"`Python: Current File (Integrated Terminal)`\" 옵션으로 디버거를 실행합니다.\n\n그런 다음 **FastAPI** 코드로 서버를 시작하고 중단점 등에서 중지합니다.\n\n다음과 같이 표시됩니다.\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\nPycharm을 사용하는 경우 다음을 수행할 수 있습니다\n\n* \"Run\" 메뉴를 엽니다.\n* \"Debug...\" 옵션을 선택합니다.\n* 그러면 상황에 맞는 메뉴가 나타납니다.\n* 디버그할 파일을 선택합니다(이 경우 `main.py`).\n\n그런 다음 **FastAPI** 코드로 서버를 시작하고 중단점 등에서 중지합니다.\n\n다음과 같이 표시됩니다.\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/ko/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# 의존성으로서의 클래스 { #classes-as-dependencies }\n\n**의존성 주입** 시스템에 대해 더 깊이 살펴보기 전에, 이전 예제를 업그레이드해 보겠습니다.\n\n## 이전 예제의 `dict` { #a-dict-from-the-previous-example }\n\n이전 예제에서는 의존성(\"dependable\")에서 `dict`를 반환하고 있었습니다:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\n하지만 그러면 *경로 처리 함수*의 매개변수 `commons`에서 `dict`를 받게 됩니다.\n\n그리고 에디터는 `dict`의 키와 값 타입을 알 수 없기 때문에 `dict`에 대해서는 (완성 기능 같은) 많은 지원을 제공할 수 없다는 것을 알고 있습니다.\n\n더 나은 방법이 있습니다...\n\n## 의존성이 되기 위한 조건 { #what-makes-a-dependency }\n\n지금까지는 함수로 선언된 의존성을 봤습니다.\n\n하지만 그것만이 의존성을 선언하는 유일한 방법은 아닙니다(아마도 더 일반적이긴 하겠지만요).\n\n핵심 요소는 의존성이 \"호출 가능(callable)\"해야 한다는 것입니다.\n\n파이썬에서 \"**호출 가능(callable)**\"이란 파이썬이 함수처럼 \"호출\"할 수 있는 모든 것입니다.\n\n따라서 `something`(함수가 _아닐_ 수도 있습니다)이라는 객체가 있고, 다음처럼 \"호출\"(실행)할 수 있다면:\n\n```Python\nsomething()\n```\n\n또는\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\n그것은 \"호출 가능(callable)\"입니다.\n\n## 의존성으로서의 클래스 { #classes-as-dependencies_1 }\n\n파이썬 클래스의 인스턴스를 만들 때도 같은 문법을 사용한다는 것을 알 수 있을 겁니다.\n\n예를 들어:\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\n이 경우 `fluffy`는 클래스 `Cat`의 인스턴스입니다.\n\n그리고 `fluffy`를 만들기 위해 `Cat`을 \"호출\"하고 있습니다.\n\n따라서 파이썬 클래스도 **호출 가능(callable)**합니다.\n\n그러면 **FastAPI**에서는 파이썬 클래스를 의존성으로 사용할 수 있습니다.\n\nFastAPI가 실제로 확인하는 것은 그것이 \"호출 가능(callable)\"(함수, 클래스, 또는 다른 무엇이든)한지와 정의된 매개변수들입니다.\n\n**FastAPI**에서 \"호출 가능(callable)\"한 것을 의존성으로 넘기면, 그 \"호출 가능(callable)\"한 것의 매개변수들을 분석하고 *경로 처리 함수*의 매개변수와 동일한 방식으로 처리합니다. 하위 의존성도 포함해서요.\n\n이것은 매개변수가 전혀 없는 callable에도 적용됩니다. 매개변수가 없는 *경로 처리 함수*에 적용되는 것과 동일합니다.\n\n그러면 위의 의존성(\"dependable\") `common_parameters`를 클래스 `CommonQueryParams`로 바꿀 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\n클래스의 인스턴스를 만들 때 사용하는 `__init__` 메서드에 주목하세요:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n...이전의 `common_parameters`와 동일한 매개변수를 가지고 있습니다:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\n이 매개변수들이 **FastAPI**가 의존성을 \"해결\"하는 데 사용할 것들입니다.\n\n두 경우 모두 다음을 갖게 됩니다:\n\n* `str`인 선택적 쿼리 매개변수 `q`.\n* 기본값이 `0`인 `int` 쿼리 매개변수 `skip`.\n* 기본값이 `100`인 `int` 쿼리 매개변수 `limit`.\n\n두 경우 모두 데이터는 변환되고, 검증되며, OpenAPI 스키마에 문서화되는 등 여러 처리가 적용됩니다.\n\n## 사용하기 { #use-it }\n\n이제 이 클래스를 사용해 의존성을 선언할 수 있습니다.\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI**는 `CommonQueryParams` 클래스를 호출합니다. 그러면 해당 클래스의 \"인스턴스\"가 생성되고, 그 인스턴스가 함수의 매개변수 `commons`로 전달됩니다.\n\n## 타입 어노테이션 vs `Depends` { #type-annotation-vs-depends }\n\n위 코드에서 `CommonQueryParams`를 두 번 작성하는 방식에 주목하세요:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ Annotated 미사용\n\n/// tip | 팁\n\n가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n마지막 `CommonQueryParams`는, 다음에서:\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n...**FastAPI**가 실제로 무엇이 의존성인지 알기 위해 사용하는 것입니다.\n\nFastAPI는 여기에서 선언된 매개변수들을 추출하고, 실제로 이것을 호출합니다.\n\n---\n\n이 경우 첫 번째 `CommonQueryParams`는 다음에서:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ Annotated 미사용\n\n/// tip | 팁\n\n가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n...**FastAPI**에 특별한 의미가 없습니다. FastAPI는 이를 데이터 변환, 검증 등에 사용하지 않습니다(그런 용도로는 `Depends(CommonQueryParams)`를 사용하고 있기 때문입니다).\n\n실제로는 이렇게만 작성해도 됩니다:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ Annotated 미사용\n\n/// tip | 팁\n\n가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n...다음과 같이요:\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\n하지만 타입을 선언하는 것을 권장합니다. 그러면 에디터가 매개변수 `commons`에 무엇이 전달되는지 알 수 있고, 코드 완성, 타입 체크 등에서 도움을 받을 수 있습니다:\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## 단축 { #shortcut }\n\n하지만 `CommonQueryParams`를 두 번 작성하는 코드 반복이 있다는 것을 볼 수 있습니다:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ Annotated 미사용\n\n/// tip | 팁\n\n가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n**FastAPI**는 이런 경우를 위한 단축 방법을 제공합니다. 이때 의존성은 *특히* **FastAPI**가 \"호출\"해서 클래스 자체의 인스턴스를 만들도록 하는 클래스입니다.\n\n이 특정한 경우에는 다음과 같이 할 수 있습니다:\n\n다음처럼 작성하는 대신:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ Annotated 미사용\n\n/// tip | 팁\n\n가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n...이렇게 작성합니다:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ Annotated 미사용\n\n/// tip | 팁\n\n가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\n의존성을 매개변수의 타입으로 선언하고, `Depends(CommonQueryParams)` 안에 클래스 전체를 *다시* 작성하는 대신 매개변수 없이 `Depends()`를 사용합니다.\n\n그러면 같은 예제는 다음처럼 보일 겁니다:\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n...그리고 **FastAPI**는 무엇을 해야 하는지 알게 됩니다.\n\n/// tip | 팁\n\n도움이 되기보다 더 헷갈린다면, 무시하세요. 이건 *필수*가 아닙니다.\n\n그저 단축 방법일 뿐입니다. **FastAPI**는 코드 반복을 최소화하도록 도와주는 것을 중요하게 생각하기 때문입니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# 경로 처리 데코레이터에서의 의존성 { #dependencies-in-path-operation-decorators }\n\n몇몇 경우에는, *경로 처리 함수* 안에서 의존성의 반환 값이 필요하지 않습니다.\n\n또는 의존성이 값을 반환하지 않습니다.\n\n그러나 여전히 실행/해결될 필요가 있습니다.\n\n그런 경우에, `Depends`를 사용하여 *경로 처리 함수*의 매개변수로 선언하는 대신 *경로 처리 데코레이터*에 `dependencies`의 `list`를 추가할 수 있습니다.\n\n## *경로 처리 데코레이터*에 `dependencies` 추가하기 { #add-dependencies-to-the-path-operation-decorator }\n\n*경로 처리 데코레이터*는 선택적인 인자 `dependencies`를 받습니다.\n\n`Depends()`로 된 `list`이어야 합니다:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\n이러한 의존성들은 기존 의존성들과 같은 방식으로 실행/해결됩니다. 그러나 값은 (무엇이든 반환한다면) *경로 처리 함수*에 제공되지 않습니다.\n\n/// tip | 팁\n\n일부 편집기에서는 사용되지 않는 함수 매개변수를 검사하고 오류로 표시합니다.\n\n*경로 처리 데코레이터*에서 이러한 `dependencies`를 사용하면 편집기/도구 오류를 피하면서도 실행되도록 할 수 있습니다.\n\n또한 코드에서 사용되지 않는 매개변수를 보고 불필요하다고 생각할 수 있는 새로운 개발자의 혼란을 방지하는데 도움이 될 수 있습니다.\n\n///\n\n/// info | 정보\n\n이 예시에서 `X-Key`와 `X-Token`이라는 커스텀 헤더를 만들어 사용했습니다.\n\n그러나 실제로 보안을 구현할 때는 통합된 [보안 유틸리티 (다음 챕터)](../security/index.md)를 사용하는 것이 더 많은 이점을 얻을 수 있습니다.\n\n///\n\n## 의존성 오류와 값 반환하기 { #dependencies-errors-and-return-values }\n\n평소에 사용하던대로 같은 의존성 *함수*를 사용할 수 있습니다.\n\n### 의존성 요구사항 { #dependency-requirements }\n\n(헤더같은) 요청 요구사항이나 하위-의존성을 선언할 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### 오류 발생시키기 { #raise-exceptions }\n\n다음 의존성은 기존 의존성과 동일하게 예외를 `raise`할 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### 값 반환하기 { #return-values }\n\n값을 반환하거나, 그러지 않을 수 있으며 값은 사용되지 않습니다.\n\n그래서 이미 다른 곳에서 사용된 (값을 반환하는) 일반적인 의존성을 재사용할 수 있고, 비록 값은 사용되지 않지만 의존성은 실행될 것입니다:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## *경로 처리* 모음에 대한 의존성 { #dependencies-for-a-group-of-path-operations }\n\n나중에 여러 파일을 가지고 있을 수 있는 더 큰 애플리케이션을 구조화하는 법([더 큰 애플리케이션 - 여러 파일들](../../tutorial/bigger-applications.md))을 읽을 때, *경로 처리* 모음에 대한 단일 `dependencies` 매개변수를 선언하는 법에 대해서 배우게 될 것입니다.\n\n## 전역 의존성 { #global-dependencies }\n\n다음으로 각 *경로 처리*에 적용되도록 `FastAPI` 애플리케이션 전체에 의존성을 추가하는 법을 볼 것입니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# `yield`를 사용하는 의존성 { #dependencies-with-yield }\n\nFastAPI는 <dfn title='때로는 \"exit code\", \"cleanup code\", \"teardown code\", \"closing code\", \"context manager exit code\" 등으로도 불립니다'>작업 완료 후 추가 단계</dfn>를 수행하는 의존성을 지원합니다.\n\n이를 구현하려면 `return` 대신 `yield`를 사용하고, 추가로 실행할 단계 (코드)를 그 뒤에 작성하세요.\n\n/// tip\n\n각 의존성마다 `yield`는 한 번만 사용해야 합니다.\n\n///\n\n/// note | 기술 세부사항\n\n다음과 함께 사용할 수 있는 모든 함수:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) 또는\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\n는 **FastAPI**의 의존성으로 사용할 수 있습니다.\n\n사실, FastAPI는 내부적으로 이 두 데코레이터를 사용합니다.\n\n///\n\n## `yield`를 사용하는 데이터베이스 의존성 { #a-database-dependency-with-yield }\n\n예를 들어, 이 기능을 사용하면 데이터베이스 세션을 생성하고 작업이 끝난 후에 세션을 종료할 수 있습니다.\n\n응답을 생성하기 전에는 `yield`문을 포함하여 그 이전의 코드만이 실행됩니다:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\nyield된 값은 *경로 처리* 및 다른 의존성들에 주입되는 값 입니다:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\n`yield`문 다음의 코드는 응답을 생성한 후 실행됩니다:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip\n\n`async` 함수와 일반 함수 모두 사용할 수 있습니다.\n\n**FastAPI**는 일반 의존성과 마찬가지로 각각의 함수를 올바르게 처리할 것입니다.\n\n///\n\n## `yield`와 `try`를 사용하는 의존성 { #a-dependency-with-yield-and-try }\n\n`yield`를 사용하는 의존성에서 `try` 블록을 사용한다면, 의존성을 사용하는 도중 발생한 모든 예외를 받을 수 있습니다.\n\n예를 들어, 다른 의존성이나 *경로 처리*의 중간에 데이터베이스 트랜잭션 \"롤백\"이 발생하거나 다른 오류가 발생한다면, 해당 예외를 의존성에서 받을 수 있습니다.\n\n따라서, 의존성 내에서 `except SomeException`을 사용하여 특정 예외를 처리할 수 있습니다.\n\n마찬가지로, `finally`를 사용하여 예외 발생 여부와 관계 없이 종료 단계까 실행되도록 할 수 있습니다.\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## `yield`를 사용하는 하위 의존성 { #sub-dependencies-with-yield }\n\n모든 크기와 형태의 하위 의존성과 하위 의존성의 \"트리\"도 가질 수 있으며, 이들 모두가 `yield`를 사용할 수 있습니다.\n\n**FastAPI**는 `yield`를 사용하는 각 의존성의 \"종료 코드\"가 올바른 순서로 실행되도록 보장합니다.\n\n예를 들어, `dependency_c`는 `dependency_b`에 의존할 수 있고, `dependency_b`는 `dependency_a`에 의존할 수 있습니다.\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\n이들 모두는 `yield`를 사용할 수 있습니다.\n\n이 경우 `dependency_c`는 종료 코드를 실행하기 위해, `dependency_b`의 값 (여기서는 `dep_b`로 명명)이 여전히 사용 가능해야 합니다.\n\n그리고, `dependency_b`는 종료 코드를 위해 `dependency_a`의 값 (여기서는 `dep_a`로 명명) 이 사용 가능해야 합니다.\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\n같은 방식으로, `yield`를 사용하는 의존성과 `return`을 사용하는 의존성을 함께 사용할 수 있으며, 이들 중 일부가 다른 것들에 의존할 수 있습니다.\n\n그리고 `yield`를 사용하는 다른 여러 의존성을 필요로 하는 단일 의존성을 가질 수도 있습니다.\n\n원하는 의존성을 원하는 대로 조합할 수 있습니다.\n\n**FastAPI**는 모든 것이 올바른 순서로 실행되도록 보장합니다.\n\n/// note | 기술 세부사항\n\n파이썬의 [Context Managers](https://docs.python.org/3/library/contextlib.html) 덕분에 이 기능이 작동합니다.\n\n**FastAPI**는 이를 내부적으로 사용하여 이를 달성합니다.\n\n///\n\n## `yield`와 `HTTPException`를 사용하는 의존성 { #dependencies-with-yield-and-httpexception }\n\n`yield`를 사용하는 의존성에서 `try` 블록을 사용해 코드를 실행하고, 그 다음 `finally` 뒤에 종료 코드를 실행할 수 있다는 것을 보았습니다.\n\n또한 `except`를 사용해 발생한 예외를 잡고 그에 대해 무언가를 할 수도 있습니다.\n\n예를 들어, `HTTPException` 같은 다른 예외를 발생시킬 수 있습니다.\n\n/// tip\n\n이는 다소 고급 기술이며, 대부분의 경우 실제로는 필요하지 않을 것입니다. 예를 들어, *경로 처리 함수* 등 나머지 애플리케이션 코드 내부에서 예외 (`HTTPException` 포함)를 발생시킬 수 있기 때문입니다.\n\n하지만 필요한 경우 사용할 수 있습니다. 🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\n예외를 잡고 그에 기반해 사용자 정의 응답을 생성하려면, [사용자 정의 예외 처리기](../handling-errors.md#install-custom-exception-handlers)를 생성하세요.\n\n## `yield`와 `except`를 사용하는 의존성 { #dependencies-with-yield-and-except }\n\n`yield`를 사용하는 의존성에서 `except`를 사용하여 예외를 포착하고 예외를 다시 발생시키지 않거나 (또는 새 예외를 발생시키지 않으면), FastAPI는 일반적인 Python에서와 마찬가지로 예외가 있었다는 것을 알아차릴 수 없습니다:\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\n이 경우, `HTTPException`이나 유사한 예외를 발생시키지 않기 때문에 클라이언트는 마땅히 *HTTP 500 Internal Server Error* 응답을 보게 되지만, 서버에는 어떤 오류였는지에 대한 **로그**나 다른 표시가 **전혀 남지 않게 됩니다**. 😱\n\n### `yield`와 `except`를 사용하는 의존성에서 항상 `raise` 하기 { #always-raise-in-dependencies-with-yield-and-except }\n\n`yield`가 있는 의존성에서 예외를 잡았을 때, 다른 `HTTPException`이나 유사한 예외를 발생시키는 것이 아니라면, **원래 예외를 다시 발생시켜야 합니다**.\n\n`raise`를 사용하여 동일한 예외를 다시 발생시킬 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\n이제 클라이언트는 동일한 *HTTP 500 Internal Server Error* 응답을 받게 되지만, 서버 로그에는 사용자 정의 `InternalError`가 기록됩니다. 😎\n\n## `yield`를 사용하는 의존성의 실행 순서 { #execution-of-dependencies-with-yield }\n\n실행 순서는 아래 다이어그램과 거의 비슷합니다. 시간은 위에서 아래로 흐릅니다. 그리고 각 열은 상호 작용하거나 코드를 실행하는 부분 중 하나입니다.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exception handler\nparticipant dep as Dep with yield\nparticipant operation as Path Operation\nparticipant tasks as Background tasks\n\n    Note over client,operation: Can raise exceptions, including HTTPException\n    client ->> dep: Start request\n    Note over dep: Run code up to yield\n    opt raise Exception\n        dep -->> handler: Raise Exception\n        handler -->> client: HTTP error response\n    end\n    dep ->> operation: Run dependency, e.g. DB session\n    opt raise\n        operation -->> dep: Raise Exception (e.g. HTTPException)\n        opt handle\n            dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception\n        end\n        handler -->> client: HTTP error response\n    end\n\n    operation ->> client: Return response to client\n    Note over client,operation: Response is already sent, can't change it anymore\n    opt Tasks\n        operation -->> tasks: Send background tasks\n    end\n    opt Raise other exception\n        tasks -->> tasks: Handle exceptions in the background task code\n    end\n```\n\n/// info\n\n클라이언트에는 **하나의 응답**만 전송됩니다. 이는 오류 응답 중 하나일 수도 있고, *경로 처리*에서 생성된 응답일 수도 있습니다.\n\n이러한 응답 중 하나가 전송된 후에는 다른 응답을 보낼 수 없습니다.\n\n///\n\n/// tip\n\n*경로 처리 함수*의 코드에서 어떤 예외를 발생시키면 `HTTPException`을 포함해 `yield`를 사용하는 의존성으로 전달됩니다. 대부분의 경우 해당 예외(또는 새 예외)를 `yield`를 사용하는 의존성에서 다시 발생시켜, 제대로 처리되도록 해야 합니다.\n\n///\n\n## 조기 종료와 `scope` { #early-exit-and-scope }\n\n일반적으로 `yield`를 사용하는 의존성의 종료 코드는 클라이언트로 **응답이 전송된 후에** 실행됩니다.\n\n하지만 *경로 처리 함수*에서 반환한 뒤에는 더 이상 해당 의존성이 필요 없다는 것을 알고 있다면, `Depends(scope=\"function\")`을 사용하여 FastAPI에 *경로 처리 함수*가 반환된 후, 하지만 **응답이 전송되기 전에** 의존성을 종료(닫기)해야 한다고 알려줄 수 있습니다.\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()`는 다음이 될 수 있는 `scope` 매개변수를 받습니다:\n\n* `\"function\"`: 요청을 처리하는 *경로 처리 함수* 전에 의존성을 시작하고, *경로 처리 함수*가 끝난 후, 하지만 응답이 클라이언트로 전송되기 **전에** 의존성을 종료합니다. 즉, 의존성 함수는 *경로 처리 **함수***를 **둘러싸며** 실행됩니다.\n* `\"request\"`: 요청을 처리하는 *경로 처리 함수* 전에 의존성을 시작하고(`\"function\"`을 사용할 때와 유사), 응답이 클라이언트로 전송된 **후에** 종료합니다. 즉, 의존성 함수는 **요청**과 응답 사이클을 **둘러싸며** 실행됩니다.\n\n지정하지 않고 의존성이 `yield`를 사용한다면, 기본 `scope`는 `\"request\"`입니다.\n\n### 하위 의존성을 위한 `scope` { #scope-for-sub-dependencies }\n\n`scope=\"request\"`(기본값)로 의존성을 선언하면, 모든 하위 의존성도 `scope`가 `\"request\"`여야 합니다.\n\n하지만 `scope`가 `\"function\"`인 의존성은 `scope`가 `\"function\"`인 의존성과 `\"request\"`인 의존성을 모두 의존성으로 가질 수 있습니다.\n\n이는 어떤 의존성이든, 종료 코드에서 하위 의존성을 계속 사용해야 할 수도 있으므로, 하위 의존성보다 먼저 종료 코드를 실행할 수 있어야 하기 때문입니다.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Dep scope=\"request\"\nparticipant dep_func as Dep scope=\"function\"\nparticipant operation as Path Operation\n\n    client ->> dep_req: Start request\n    Note over dep_req: Run code up to yield\n    dep_req ->> dep_func: Pass dependency\n    Note over dep_func: Run code up to yield\n    dep_func ->> operation: Run path operation with dependency\n    operation ->> dep_func: Return from path operation\n    Note over dep_func: Run code after yield\n    Note over dep_func: ✅ Dependency closed\n    dep_func ->> client: Send response to client\n    Note over client: Response sent\n    Note over dep_req: Run code after yield\n    Note over dep_req: ✅ Dependency closed\n```\n\n## `yield`, `HTTPException`, `except` 및 백그라운드 작업을 사용하는 의존성 { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n`yield`를 사용하는 의존성은 시간이 지나면서 서로 다른 사용 사례를 다루고 일부 문제를 수정하기 위해 발전해 왔습니다.\n\nFastAPI의 여러 버전에서 무엇이 바뀌었는지 보고 싶다면, 고급 가이드의 [고급 의존성 - `yield`, `HTTPException`, `except` 및 백그라운드 작업을 사용하는 의존성](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks)에서 더 자세히 읽을 수 있습니다.\n## 컨텍스트 관리자 { #context-managers }\n\n### \"컨텍스트 관리자\"란 { #what-are-context-managers }\n\n\"컨텍스트 관리자\"는 Python에서 `with` 문에서 사용할 수 있는 모든 객체를 의미합니다.\n\n예를 들어, [with를 사용해 파일을 읽을 수 있습니다](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files):\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\n내부적으로 `open(\"./somefile.txt\")` 는 \"컨텍스트 관리자(Context Manager)\"라고 불리는 객체를 생성합니다.\n\n`with` 블록이 끝나면, 예외가 발생했더라도 파일을 닫도록 보장합니다.\n\n`yield`가 있는 의존성을 생성하면 **FastAPI**는 내부적으로 이를 위한 컨텍스트 매니저를 생성하고 다른 관련 도구들과 결합합니다.\n\n### `yield`를 사용하는 의존성에서 컨텍스트 관리자 사용하기 { #using-context-managers-in-dependencies-with-yield }\n\n/// warning\n\n이것은 어느 정도 \"고급\" 개념입니다.\n\n**FastAPI**를 처음 시작하는 경우 지금은 이 부분을 건너뛰어도 좋습니다.\n\n///\n\nPython에서는 [두 가지 메서드: `__enter__()`와 `__exit__()`가 있는 클래스를 생성하여](https://docs.python.org/3/reference/datamodel.html#context-managers) 컨텍스트 관리자를 만들 수 있습니다.\n\n**FastAPI**의 `yield`가 있는 의존성 내에서\n`with` 또는 `async with`문을 사용하여 이들을 활용할 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip\n\n컨텍스트 관리자를 생성하는 또 다른 방법은 다음과 같습니다:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) 또는\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\n이들은 단일 `yield`가 있는 함수를 꾸미는 데 사용합니다.\n\n이것이 **FastAPI**가 `yield`가 있는 의존성을 위해 내부적으로 사용하는 방식입니다.\n\n하지만 FastAPI 의존성에는 이러한 데코레이터를 사용할 필요가 없습니다(그리고 사용해서도 안됩니다).\n\nFastAPI가 내부적으로 이를 처리해 줄 것입니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# 전역 의존성 { #global-dependencies }\n\n몇몇 유형의 애플리케이션에서는 애플리케이션 전체에 의존성을 추가하고 싶을 수 있습니다.\n\n[*경로 처리 데코레이터*에 `dependencies` 추가하기](dependencies-in-path-operation-decorators.md)와 유사한 방법으로 `FastAPI` 애플리케이션에 그것들을 추가할 수 있습니다.\n\n그런 경우에, 애플리케이션의 모든 *경로 처리*에 적용될 것입니다:\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\n그리고 [*경로 처리 데코레이터*에 `dependencies` 추가하기](dependencies-in-path-operation-decorators.md) 섹션의 모든 아이디어는 여전히 적용되지만, 이 경우에는 애플리케이션의 모든 *경로 처리*에 적용됩니다.\n\n## *경로 처리* 그룹에 대한 의존성 { #dependencies-for-groups-of-path-operations }\n\n나중에 여러 파일을 포함할 수도 있는 더 큰 애플리케이션을 구조화하는 법([더 큰 애플리케이션 - 여러 파일들](../../tutorial/bigger-applications.md))을 읽을 때, *경로 처리* 그룹에 대한 단일 `dependencies` 매개변수를 선언하는 법을 배우게 될 것입니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/dependencies/index.md",
    "content": "# 의존성 { #dependencies }\n\n**FastAPI**는 아주 강력하지만 직관적인 **<dfn title=\"컴포넌트, 리소스, 제공자, 서비스, 인젝터블로도 알려져 있음\">의존성 주입</dfn>** 시스템을 가지고 있습니다.\n\n이는 사용하기 아주 쉽게 설계했으며, 어느 개발자나 다른 컴포넌트와 **FastAPI**를 쉽게 통합할 수 있도록 만들었습니다.\n\n## \"의존성 주입\"은 무엇입니까? { #what-is-dependency-injection }\n\n**\"의존성 주입\"**은 프로그래밍에서 여러분의 코드(이 경우, *경로 처리 함수*)가 작동하고 사용하는 데 필요로 하는 것, 즉 \"의존성\"을 선언할 수 있는 방법을 의미합니다.\n\n그 후에, 시스템(이 경우 **FastAPI**)은 여러분의 코드가 요구하는 의존성을 제공하기 위해 필요한 모든 작업을 처리합니다.(의존성을 \"주입\"합니다)\n\n이는 여러분이 다음과 같은 사항을 필요로 할 때 매우 유용합니다:\n\n* 공용된 로직을 가졌을 경우 (같은 코드 로직이 계속 반복되는 경우).\n* 데이터베이스 연결을 공유하는 경우.\n* 보안, 인증, 역할 요구 사항 등을 강제하는 경우.\n* 그리고 많은 다른 사항...\n\n이 모든 사항을 할 때 코드 반복을 최소화합니다.\n\n## 첫번째 단계 { #first-steps }\n\n아주 간단한 예제를 봅시다. 너무 간단할 것이기에 지금 당장은 유용하지 않을 수 있습니다.\n\n하지만 이를 통해 **의존성 주입** 시스템이 어떻게 작동하는지에 중점을 둘 것입니다.\n\n### 의존성 혹은 \"디펜더블\" 만들기 { #create-a-dependency-or-dependable }\n\n의존성에 집중해 봅시다.\n\n*경로 처리 함수*가 가질 수 있는 모든 매개변수를 갖는 단순한 함수입니다:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\n이게 다입니다.\n\n**단 두 줄입니다**.\n\n그리고, 이 함수는 여러분의 모든 *경로 처리 함수*가 가지고 있는 것과 같은 형태와 구조를 가지고 있습니다.\n\n여러분은 이를 \"데코레이터\"가 없는 (`@app.get(\"/some-path\")`가 없는) *경로 처리 함수*라고 생각할 수 있습니다.\n\n그리고 여러분이 원하는 무엇이든 반환할 수 있습니다.\n\n이 경우, 이 의존성은 다음과 같은 경우를 기대합니다:\n\n* 선택적인 쿼리 매개변수 `q`, `str`을 자료형으로 가집니다.\n* 선택적인 쿼리 매개변수 `skip`, `int`를 자료형으로 가지며 기본 값은 `0`입니다.\n* 선택적인 쿼리 매개변수 `limit`, `int`를 자료형으로 가지며 기본 값은 `100`입니다.\n\n그 후 위의 값을 포함한 `dict` 자료형으로 반환할 뿐입니다.\n\n/// info | 정보\n\nFastAPI는 0.95.0 버전부터 `Annotated`에 대한 지원을 (그리고 이를 사용하기 권장합니다) 추가했습니다.\n\n옛날 버전을 가지고 있는 경우, `Annotated`를 사용하려 하면 에러를 맞이하게 될 것입니다.\n\n`Annotated`를 사용하기 전에 최소 0.95.1로 [FastAPI 버전 업그레이드](../../deployment/versions.md#upgrading-the-fastapi-versions)를 확실하게 하세요.\n\n///\n\n### `Depends` 불러오기 { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### \"의존자\"에 의존성 명시하기 { #declare-the-dependency-in-the-dependant }\n\n*경로 처리 함수*의 매개변수로 `Body`, `Query` 등을 사용하는 방식과 같이 새로운 매개변수로 `Depends`를 사용합니다:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\n비록 `Depends`를 함수의 매개변수에서 `Body`, `Query` 등을 사용하는 것과 같은 방식으로 사용하지만, `Depends`는 약간 다르게 작동합니다.\n\n`Depends`에 단일 매개변수만 전달했습니다.\n\n이 매개변수는 함수같은 것이어야 합니다.\n\n여러분은 직접 **호출하지 않았습니다** (끝에 괄호를 치지 않았습니다), 단지 `Depends()`에 매개변수로 넘겨 줬을 뿐입니다.\n\n그리고 그 함수는 *경로 처리 함수*가 작동하는 것과 같은 방식으로 매개변수를 받습니다.\n\n/// tip | 팁\n\n여러분은 다음 장에서 함수를 제외하고서, \"다른 것들\"이 어떻게 의존성으로 사용되는지 알게 될 것입니다.\n\n///\n\n새로운 요청이 도착할 때마다, **FastAPI**는 다음을 처리합니다:\n\n* 올바른 매개변수를 가진 의존성(\"디펜더블\") 함수를 호출합니다.\n* 함수에서 결과를 받아옵니다.\n* *경로 처리 함수*에 있는 매개변수에 그 결과를 할당합니다\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\n이렇게 하면 공용 코드를 한번만 적어도 되며, **FastAPI**는 *경로 처리*을 위해 이에 대한 호출을 처리합니다.\n\n/// check | 확인\n\n특별한 클래스를 만들지 않아도 되며, 이러한 것 혹은 비슷한 종류를 **FastAPI**에 \"등록\"하기 위해 어떤 곳에 넘겨주지 않아도 됩니다.\n\n단순히 `Depends`에 넘겨주기만 하면 되며, **FastAPI**는 나머지를 어찌할지 알고 있습니다.\n\n///\n\n## `Annotated`인 의존성 공유하기 { #share-annotated-dependencies }\n\n위의 예제에서 몇몇 작은 **코드 중복**이 있다는 것을 보았을 겁니다.\n\n`common_parameters()`의존을 사용해야 한다면, 타입 명시와 `Depends()`와 함께 전체 매개변수를 적어야 합니다:\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\n하지만 `Annotated`를 사용하고 있기에, `Annotated` 값을 변수에 저장하고 여러 장소에서 사용할 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | 팁\n\n이는 그저 표준 파이썬이고 \"type alias\"라고 부르며 사실 **FastAPI**에 국한되는 것은 아닙니다.\n\n하지만, `Annotated`를 포함하여, **FastAPI**가 파이썬 표준을 기반으로 하고 있기에, 이를 여러분의 코드 트릭으로 사용할 수 있습니다. 😎\n\n///\n\n이 의존성은 계속해서 예상한대로 작동할 것이며, **제일 좋은 부분**은 **타입 정보가 보존된다는 것입니다**. 즉 여러분의 편집기가 **자동 완성**, **인라인 에러** 등을 계속해서 제공할 수 있다는 것입니다. `mypy`같은 다른 도구도 마찬가지입니다.\n\n이는 특히 **많은 *경로 처리***에서 **같은 의존성**을 계속해서 사용하는 **거대 코드 기반**안에서 사용하면 유용할 것입니다.\n\n## `async`하게, 혹은 `async`하지 않게 { #to-async-or-not-to-async }\n\n의존성이 (*경로 처리 함수*에서 처럼 똑같이) **FastAPI**에 의해 호출될 수 있으며, 함수를 정의할 때 동일한 규칙이 적용됩니다.\n\n`async def`을 사용하거나 혹은 일반적인 `def`를 사용할 수 있습니다.\n\n그리고 일반적인 `def` *경로 처리 함수* 안에 `async def`로 의존성을 선언할 수 있으며, `async def` *경로 처리 함수* 안에 `def`로 의존성을 선언하는 등의 방법이 있습니다.\n\n아무 문제 없습니다. **FastAPI**는 무엇을 할지 알고 있습니다.\n\n/// note | 참고\n\n잘 모르시겠다면, [Async: *\"In a hurry?\"*](../../async.md#in-a-hurry) 문서에서 `async`와 `await`에 대해 확인할 수 있습니다.\n\n///\n\n## OpenAPI와 통합 { #integrated-with-openapi }\n\n모든 요청 선언, 검증과 의존성(및 하위 의존성)에 대한 요구 사항은 동일한 OpenAPI 스키마에 통합됩니다.\n\n따라서 대화형 문서에 이러한 의존성에 대한 모든 정보 역시 포함하고 있습니다:\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## 간단한 사용법 { #simple-usage }\n\n이를 보면, *경로 처리 함수*는 *경로*와 *작동*이 매칭되면 언제든지 사용되도록 정의되었으며, **FastAPI**는 올바른 매개변수를 가진 함수를 호출하고 해당 요청에서 데이터를 추출합니다.\n\n사실, 모든 (혹은 대부분의) 웹 프레임워크는 이와 같은 방식으로 작동합니다.\n\n여러분은 이러한 함수들을 절대 직접 호출하지 않습니다. 프레임워크(이 경우 **FastAPI**)에 의해 호출됩니다.\n\n의존성 주입 시스템과 함께라면 **FastAPI**에게 여러분의 *경로 처리 함수*가 실행되기 전에 실행되어야 하는 무언가에 여러분의 *경로 처리 함수* 또한 \"의존\"하고 있음을 알릴 수 있으며, **FastAPI**는 이를 실행하고 결과를 \"주입\"할 것입니다.\n\n\"의존성 주입\"이라는 동일한 아이디어에 대한 다른 일반적인 용어는 다음과 같습니다:\n\n* 리소스\n* 제공자\n* 서비스\n* 인젝터블\n* 컴포넌트\n\n## **FastAPI** 플러그인 { #fastapi-plug-ins }\n\n통합과 \"플러그인\"은 **의존성 주입** 시스템을 사용하여 구축할 수 있습니다. 하지만 실제로 **\"플러그인\"을 만들 필요는 없습니다**, 왜냐하면 의존성을 사용함으로써 여러분의 *경로 처리 함수*에 통합과 상호 작용을 무한대로 선언할 수 있기 때문입니다.\n\n그리고 \"말 그대로\", 그저 필요로 하는 파이썬 패키지를 임포트하고 단 몇 줄의 코드로 여러분의 API 함수와 통합함으로써, 의존성을 아주 간단하고 직관적인 방법으로 만들 수 있습니다.\n\n관계형 및 NoSQL 데이터베이스, 보안 등, 이에 대한 예시를 다음 장에서 볼 수 있습니다.\n\n## **FastAPI** 호환성 { #fastapi-compatibility }\n\n의존성 주입 시스템의 단순함은 **FastAPI**를 다음과 같은 요소들과 호환할 수 있게 합니다:\n\n* 모든 관계형 데이터베이스\n* NoSQL 데이터베이스\n* 외부 패키지\n* 외부 API\n* 인증 및 권한 부여 시스템\n* API 사용 모니터링 시스템\n* 응답 데이터 주입 시스템\n* 기타 등등.\n\n## 간편하고 강력하다 { #simple-and-powerful }\n\n계층적인 의존성 주입 시스템은 정의하고 사용하기 쉽지만, 여전히 매우 강력합니다.\n\n여러분은 스스로를 의존하는 의존성을 정의할 수 있습니다.\n\n끝에는, 계층적인 나무로 된 의존성이 만들어지며, 그리고 **의존성 주입** 시스템은 (하위 의존성도 마찬가지로) 이러한 의존성들을 처리하고 각 단계마다 결과를 제공합니다(주입합니다).\n\n예를 들면, 여러분이 4개의 API 엔드포인트(*경로 처리*)를 가지고 있다고 해봅시다:\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\n그 다음 각각에 대해 그저 의존성과 하위 의존성을 사용하여 다른 권한 요구 사항을 추가할 수 있을 겁니다:\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## **OpenAPI**와의 통합 { #integrated-with-openapi_1 }\n\n이 모든 의존성은 각각의 요구사항을 선언하는 동시에, *경로 처리*에 매개변수, 검증 등을 추가합니다.\n\n**FastAPI**는 이 모든 것을 OpenAPI 스키마에 추가할 것이며, 이를 통해 대화형 문서 시스템에 나타날 것입니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# 하위 의존성 { #sub-dependencies }\n\n**하위 의존성**을 가지는 의존성을 만들 수 있습니다.\n\n필요한 만큼 **깊게** 중첩할 수도 있습니다.\n\n이것을 해결하는 일은 **FastAPI**가 알아서 처리합니다.\n\n## 첫 번째 의존성 \"dependable\" { #first-dependency-dependable }\n\n다음과 같이 첫 번째 의존성(\"dependable\")을 만들 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\n이 의존성은 선택적 쿼리 파라미터 `q`를 `str`로 선언하고, 그대로 반환합니다.\n\n매우 단순한 예시(그다지 유용하진 않음)이지만, 하위 의존성이 어떻게 동작하는지에 집중하는 데 도움이 됩니다.\n\n## 두 번째 의존성 \"dependable\"과 \"dependant\" { #second-dependency-dependable-and-dependant }\n\n그다음, 또 다른 의존성 함수(\"dependable\")를 만들 수 있는데, 이 함수는 동시에 자기 자신의 의존성도 선언합니다(그래서 \"dependant\"이기도 합니다):\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\n선언된 파라미터를 살펴보겠습니다:\n\n* 이 함수 자체가 의존성(\"dependable\")이지만, 다른 의존성도 하나 선언합니다(즉, 다른 무언가에 \"의존\"합니다).\n    * `query_extractor`에 의존하며, 그 반환값을 파라미터 `q`에 할당합니다.\n* 또한 선택적 `last_query` 쿠키를 `str`로 선언합니다.\n    * 사용자가 쿼리 `q`를 제공하지 않았다면, 이전에 쿠키에 저장해 둔 마지막 쿼리를 사용합니다.\n\n## 의존성 사용하기 { #use-the-dependency }\n\n그다음 다음과 같이 의존성을 사용할 수 있습니다:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info | 정보\n\n*경로 처리 함수*에서는 `query_or_cookie_extractor`라는 의존성 하나만 선언하고 있다는 점에 주목하세요.\n\n하지만 **FastAPI**는 `query_or_cookie_extractor`를 호출하는 동안 그 결과를 전달하기 위해, 먼저 `query_extractor`를 해결해야 한다는 것을 알고 있습니다.\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## 같은 의존성을 여러 번 사용하기 { #using-the-same-dependency-multiple-times }\n\n같은 *경로 처리*에 대해 의존성 중 하나가 여러 번 선언되는 경우(예: 여러 의존성이 공통 하위 의존성을 갖는 경우), **FastAPI**는 그 하위 의존성을 요청당 한 번만 호출해야 한다는 것을 알고 있습니다.\n\n그리고 같은 요청에 대해 동일한 의존성을 여러 번 호출하는 대신, 반환값을 <dfn title=\"계산/생성된 값을 저장해 두었다가, 다시 계산하지 않고 재사용하기 위한 유틸리티/시스템.\">\"캐시\"</dfn>에 저장하고, 그 요청에서 해당 값이 필요한 모든 \"dependants\"에 전달합니다.\n\n고급 시나리오로, 같은 요청에서 \"cached\" 값을 쓰는 대신 매 단계마다(아마도 여러 번) 의존성이 호출되어야 한다는 것을 알고 있다면, `Depends`를 사용할 때 `use_cache=False` 파라미터를 설정할 수 있습니다:\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ 비 Annotated\n\n/// tip | 팁\n\n가능하다면 `Annotated` 버전을 사용하는 것을 권장합니다.\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## 정리 { #recap }\n\n여기서 사용한 그럴듯한 용어들을 제외하면, **Dependency Injection** 시스템은 꽤 단순합니다.\n\n*경로 처리 함수*와 같은 형태의 함수들일 뿐입니다.\n\n하지만 여전히 매우 강력하며, 임의로 깊게 중첩된 의존성 \"그래프\"(트리)를 선언할 수 있습니다.\n\n/// tip | 팁\n\n이 단순한 예시만 보면 그다지 유용해 보이지 않을 수도 있습니다.\n\n하지만 **보안**에 관한 챕터에서 이것이 얼마나 유용한지 보게 될 것입니다.\n\n또한 얼마나 많은 코드를 아껴주는지도 보게 될 것입니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/tutorial/encoder.md",
    "content": "# JSON 호환 가능 인코더 { #json-compatible-encoder }\n\n데이터 유형(예: Pydantic 모델)을 JSON과 호환되는 형태(예: `dict`, `list` 등)로 변환해야 하는 경우가 있습니다.\n\n예를 들면, 데이터베이스에 저장해야 하는 경우입니다.\n\n이를 위해, **FastAPI**에서는 `jsonable_encoder()` 함수를 제공합니다.\n\n## `jsonable_encoder` 사용 { #using-the-jsonable-encoder }\n\nJSON 호환 가능 데이터만 수신하는 `fake_db` 데이터베이스가 존재한다고 가정하겠습니다.\n\n예를 들면, `datetime` 객체는 JSON과 호환되지 않으므로 이 데이터베이스는 이를 받지 않습니다.\n\n따라서 `datetime` 객체는 [ISO 형식](https://en.wikipedia.org/wiki/ISO_8601)의 데이터를 포함하는 `str`로 변환되어야 합니다.\n\n같은 방식으로 이 데이터베이스는 Pydantic 모델(속성이 있는 객체)을 받지 않고, `dict`만을 받습니다.\n\n이를 위해 `jsonable_encoder`를 사용할 수 있습니다.\n\nPydantic 모델 같은 객체를 받고 JSON 호환 가능한 버전을 반환합니다:\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\n이 예시에서는 Pydantic 모델을 `dict`로, `datetime`을 `str`로 변환합니다.\n\n이렇게 호출한 결과는 파이썬 표준인 [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps)로 인코딩할 수 있습니다.\n\nJSON 형식(문자열)의 데이터가 들어있는 큰 `str`을 반환하지 않습니다. JSON과 모두 호환되는 값과 하위 값이 있는 파이썬 표준 데이터 구조(예: `dict`)를 반환합니다.\n\n/// note | 참고\n\n`jsonable_encoder`는 실제로 **FastAPI**에서 내부적으로 데이터를 변환하는 데 사용하지만, 다른 많은 시나리오에서도 유용합니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/tutorial/extra-data-types.md",
    "content": "# 추가 데이터 자료형 { #extra-data-types }\n\n지금까지 일반적인 데이터 자료형을 사용했습니다. 예를 들면 다음과 같습니다:\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\n하지만 더 복잡한 데이터 자료형 또한 사용할 수 있습니다.\n\n그리고 지금까지와 같은 기능들을 여전히 사용할 수 있습니다.\n\n* 훌륭한 편집기 지원.\n* 들어오는 요청의 데이터 변환.\n* 응답 데이터의 데이터 변환.\n* 데이터 검증.\n* 자동 어노테이션과 문서화.\n\n## 다른 데이터 자료형 { #other-data-types }\n\n아래의 추가적인 데이터 자료형을 사용할 수 있습니다:\n\n* `UUID`:\n    * 표준 \"범용 고유 식별자\"로, 많은 데이터베이스와 시스템에서 ID로 사용됩니다.\n    * 요청과 응답에서 `str`로 표현됩니다.\n* `datetime.datetime`:\n    * 파이썬의 `datetime.datetime`.\n    * 요청과 응답에서 `2008-09-15T15:53:00+05:00`와 같은 ISO 8601 형식의 `str`로 표현됩니다.\n* `datetime.date`:\n    * 파이썬의 `datetime.date`.\n    * 요청과 응답에서 `2008-09-15`와 같은 ISO 8601 형식의 `str`로 표현됩니다.\n* `datetime.time`:\n    * 파이썬의 `datetime.time`.\n    * 요청과 응답에서 `14:23:55.003`와 같은 ISO 8601 형식의 `str`로 표현됩니다.\n* `datetime.timedelta`:\n    * 파이썬의 `datetime.timedelta`.\n    * 요청과 응답에서 전체 초(seconds)의 `float`로 표현됩니다.\n    * Pydantic은 \"ISO 8601 time diff encoding\"으로 표현하는 것 또한 허용합니다. [더 많은 정보는 문서를 확인하세요](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).\n* `frozenset`:\n    * 요청과 응답에서 `set`와 동일하게 취급됩니다:\n        * 요청 시, 리스트를 읽어 중복을 제거하고 `set`로 변환합니다.\n        * 응답 시, `set`는 `list`로 변환됩니다.\n        * 생성된 스키마는 (JSON 스키마의 `uniqueItems`를 이용해) `set`의 값이 고유함을 명시합니다.\n* `bytes`:\n    * 표준 파이썬의 `bytes`.\n    * 요청과 응답에서 `str`로 취급됩니다.\n    * 생성된 스키마는 이것이 `binary` \"형식\"의 `str`임을 명시합니다.\n* `Decimal`:\n    * 표준 파이썬의 `Decimal`.\n    * 요청과 응답에서 `float`와 동일하게 다뤄집니다.\n* 여기에서 모든 유효한 Pydantic 데이터 자료형을 확인할 수 있습니다: [Pydantic 데이터 자료형](https://docs.pydantic.dev/latest/usage/types/types/).\n\n## 예시 { #example }\n\n위의 몇몇 자료형을 매개변수로 사용하는 *경로 처리* 예시입니다.\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\n함수 안의 매개변수가 그들만의 데이터 자료형을 가지고 있으며, 예를 들어, 다음과 같이 날짜를 조작할 수 있음을 참고하십시오:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/ko/docs/tutorial/extra-models.md",
    "content": "# 추가 모델 { #extra-models }\n\n지난 예제에 이어서, 연관된 모델을 여러 개 갖는 것은 흔한 일입니다.\n\n특히 사용자 모델의 경우에 그러한데, 왜냐하면:\n\n* **입력 모델**은 비밀번호를 가질 수 있어야 합니다.\n* **출력 모델**은 비밀번호를 가지면 안 됩니다.\n* **데이터베이스 모델**은 아마도 해시 처리된 비밀번호를 가질 필요가 있을 것입니다.\n\n/// danger\n\n절대 사용자의 비밀번호를 평문으로 저장하지 마세요. 항상 이후에 검증 가능한 \"안전한 해시(secure hash)\"로 저장하세요.\n\n만약 이게 무엇인지 모르겠다면, [보안 장](security/simple-oauth2.md#password-hashing)에서 \"password hash\"가 무엇인지 배울 수 있습니다.\n\n///\n\n## 다중 모델 { #multiple-models }\n\n아래는 비밀번호 필드와 해당 필드가 사용되는 위치를 포함하여, 각 모델들이 어떤 형태를 가질 수 있는지 전반적인 예시입니다:\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### `**user_in.model_dump()` 에 대하여 { #about-user-in-model-dump }\n\n#### Pydantic의 `.model_dump()` { #pydantics-model-dump }\n\n`user_in`은 Pydantic 모델 클래스인 `UserIn`입니다.\n\nPydantic 모델은 모델 데이터를 포함한 `dict`를 반환하는 `.model_dump()` 메서드를 제공합니다.\n\n따라서, 다음과 같이 Pydantic 객체 `user_in`을 생성할 수 있습니다:\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\n그 다음, 다음과 같이 호출합니다:\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\n이제 변수 `user_dict`에 데이터가 포함된 `dict`를 가지게 됩니다(이는 Pydantic 모델 객체가 아닌 `dict`입니다).\n\n그리고 다음과 같이 호출하면:\n\n```Python\nprint(user_dict)\n```\n\nPython의 `dict`가 다음과 같이 출력됩니다:\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### `dict` 언패킹 { #unpacking-a-dict }\n\n`user_dict`와 같은 `dict`를 함수(또는 클래스)에 `**user_dict`로 전달하면, Python은 이를 \"언팩(unpack)\"합니다. 이 과정에서 `user_dict`의 키와 값을 각각 키-값 인자로 직접 전달합니다.\n\n따라서, 위에서 생성한 `user_dict`를 사용하여 다음과 같이 작성하면:\n\n```Python\nUserInDB(**user_dict)\n```\n\n다음과 같은 결과를 생성합니다:\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\n혹은 더 정확히 말하자면, `user_dict`를 직접 사용하는 것은, 나중에 어떤 값이 추가되더라도 아래와 동일한 효과를 냅니다:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### 다른 모델 데이터로 새 Pydantic 모델 생성 { #a-pydantic-model-from-the-contents-of-another }\n\n위의 예제에서 `user_in.model_dump()`로부터 `user_dict`를 생성한 것처럼, 아래 코드는:\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\n다음과 동일합니다:\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n...왜냐하면 `user_in.model_dump()`는 `dict`이며, 이를 `**`로 Python이 \"언팩(unpack)\"하도록 하여 `UserInDB`에 전달하기 때문입니다.\n\n따라서, 다른 Pydantic 모델의 데이터를 사용하여 새로운 Pydantic 모델을 생성할 수 있습니다.\n\n#### `dict` 언패킹과 추가 키워드 { #unpacking-a-dict-and-extra-keywords }\n\n그리고 다음과 같이 추가 키워드 인자 `hashed_password=hashed_password`를 추가하면:\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n다음과 같은 결과를 생성합니다:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning\n\n추가적으로 제공된 함수 `fake_password_hasher`와 `fake_save_user`는 데이터 흐름을 시연하기 위한 예제일 뿐이며, 실제 보안을 제공하지 않습니다.\n\n///\n\n## 중복 줄이기 { #reduce-duplication }\n\n코드 중복을 줄이는 것은 **FastAPI**의 핵심 아이디어 중 하나입니다.\n\n코드 중복은 버그, 보안 문제, 코드 비동기화 문제(한 곳은 업데이트되었지만 다른 곳은 업데이트되지 않는 문제) 등의 가능성을 증가시킵니다.\n\n그리고 이 모델들은 많은 데이터를 공유하면서 속성 이름과 타입을 중복하고 있습니다.\n\n더 나은 방법이 있습니다.\n\n`UserBase` 모델을 선언하여 다른 모델들의 기본(base)으로 사용할 수 있습니다. 그런 다음 이 모델을 상속받아 속성과 타입 선언(유형 선언, 검증 등)을 상속하는 서브클래스를 만들 수 있습니다.\n\n모든 데이터 변환, 검증, 문서화 등은 정상적으로 작동할 것입니다.\n\n이렇게 하면 각 모델 간의 차이점만 선언할 수 있습니다(평문 `password`, `hashed_password`, 그리고 비밀번호가 없는 경우):\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` 또는 `anyOf` { #union-or-anyof }\n\n두 가지 이상의 타입을 포함하는 `Union`으로 응답을 선언할 수 있습니다. 이는 응답이 그 중 하나의 타입일 수 있음을 의미합니다.\n\nOpenAPI에서는 이를 `anyOf`로 정의합니다.\n\n이를 위해 표준 Python 타입 힌트인 [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union)을 사용할 수 있습니다:\n\n/// note\n\n[`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions)을 정의할 때는 더 구체적인 타입을 먼저 포함하고, 덜 구체적인 타입을 그 뒤에 나열해야 합니다. 아래 예제에서는 `Union[PlaneItem, CarItem]`에서 더 구체적인 `PlaneItem`이 `CarItem`보다 앞에 위치합니다.\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### Python 3.10에서 `Union` { #union-in-python-3-10 }\n\n위의 예제에서는 `response_model` 인자 값으로 `Union[PlaneItem, CarItem]`을 전달합니다.\n\n이 경우, 이를 **타입 어노테이션(type annotation)**이 아닌 **인자 값(argument value)**으로 전달하고 있기 때문에 Python 3.10에서도 `Union`을 사용해야 합니다.\n\n만약 타입 어노테이션에 사용한다면, 다음과 같이 수직 막대(|)를 사용할 수 있습니다:\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\n하지만 이를 `response_model=PlaneItem | CarItem`과 같이 할당하면 에러가 발생합니다. 이는 Python이 이를 타입 어노테이션으로 해석하지 않고, `PlaneItem`과 `CarItem` 사이의 **잘못된 연산(invalid operation)**을 시도하기 때문입니다.\n\n## 모델 리스트 { #list-of-models }\n\n마찬가지로, 객체 리스트 형태의 응답을 선언할 수도 있습니다.\n\n이를 위해 표준 Python의 `list`를 사용하세요:\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## 임의의 `dict` 응답 { #response-with-arbitrary-dict }\n\nPydantic 모델을 사용하지 않고, 키와 값의 타입만 선언하여 평범한 임의의 `dict`로 응답을 선언할 수도 있습니다.\n\n이는 Pydantic 모델에 필요한 유효한 필드/속성 이름을 사전에 알 수 없는 경우에 유용합니다.\n\n이 경우, `dict`를 사용할 수 있습니다:\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## 요약 { #recap }\n\n여러 Pydantic 모델을 사용하고, 각 경우에 맞게 자유롭게 상속하세요.\n\n엔터티가 서로 다른 \"상태\"를 가져야 하는 경우, 엔터티당 단일 데이터 모델을 사용할 필요는 없습니다. 예를 들어, 사용자 \"엔터티\"가 `password`, `password_hash`, 그리고 비밀번호가 없는 상태를 포함할 수 있는 경우처럼 말입니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/first-steps.md",
    "content": "# 첫걸음 { #first-steps }\n\n가장 단순한 FastAPI 파일은 다음과 같이 보일 것입니다:\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\n위 코드를 `main.py`에 복사합니다.\n\n라이브 서버를 실행합니다:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n출력되는 줄들 중에는 아래와 같은 내용이 있습니다:\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n해당 줄은 로컬 머신에서 앱이 서비스되는 URL을 보여줍니다.\n\n### 확인하기 { #check-it }\n\n브라우저로 [http://127.0.0.1:8000](http://127.0.0.1:8000)를 여세요.\n\n아래와 같은 JSON 응답을 볼 수 있습니다:\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### 대화형 API 문서 { #interactive-api-docs }\n\n이제 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)로 가봅니다.\n\n자동 대화형 API 문서를 볼 수 있습니다 ([Swagger UI](https://github.com/swagger-api/swagger-ui) 제공):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### 대안 API 문서 { #alternative-api-docs }\n\n그리고 이제, [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)로 가봅니다.\n\n대안 자동 문서를 볼 수 있습니다 ([ReDoc](https://github.com/Rebilly/ReDoc) 제공):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI**는 API를 정의하기 위한 **OpenAPI** 표준을 사용하여 여러분의 모든 API를 이용해 \"스키마\"를 생성합니다.\n\n#### \"스키마\" { #schema }\n\n\"스키마\"는 무언가의 정의 또는 설명입니다. 이를 구현하는 코드가 아니라 추상적인 설명일 뿐입니다.\n\n#### API \"스키마\" { #api-schema }\n\n이 경우, [OpenAPI](https://github.com/OAI/OpenAPI-Specification)는 여러분의 API 스키마를 어떻게 정의하는지 지시하는 규격입니다.\n\n이 스키마 정의는 API 경로, 가능한 매개변수 등을 포함합니다.\n\n#### 데이터 \"스키마\" { #data-schema }\n\n\"스키마\"라는 용어는 JSON처럼 어떤 데이터의 형태를 나타낼 수도 있습니다.\n\n이러한 경우 JSON 속성, 가지고 있는 데이터 타입 등을 뜻합니다.\n\n#### OpenAPI와 JSON 스키마 { #openapi-and-json-schema }\n\nOpenAPI는 여러분의 API에 대한 API 스키마를 정의합니다. 또한 이 스키마는 JSON 데이터 스키마의 표준인 **JSON 스키마**를 사용하여 여러분의 API가 보내고 받는 데이터의 정의(또는 \"스키마\")를 포함합니다.\n\n#### `openapi.json` 확인 { #check-the-openapi-json }\n\n가공되지 않은 OpenAPI 스키마가 어떻게 생겼는지 궁금하다면, FastAPI는 자동으로 여러분의 모든 API에 대한 설명과 함께 JSON (스키마)를 생성합니다.\n\n여기에서 직접 볼 수 있습니다: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).\n\n다음과 같이 시작하는 JSON을 확인할 수 있습니다:\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### OpenAPI의 용도 { #what-is-openapi-for }\n\nOpenAPI 스키마는 포함된 두 개의 대화형 문서 시스템을 제공합니다.\n\n그리고 OpenAPI의 모든 것을 기반으로 하는 수십 가지 대안이 있습니다. **FastAPI**로 빌드한 애플리케이션에 이러한 대안을 쉽게 추가 할 수 있습니다.\n\nAPI와 통신하는 클라이언트(프론트엔드, 모바일, IoT 애플리케이션 등)를 위해 코드를 자동으로 생성하는 데도 사용할 수 있습니다.\n\n### `pyproject.toml`에 앱 `entrypoint` 구성하기 { #configure-the-app-entrypoint-in-pyproject-toml }\n\n다음과 같이 `pyproject.toml` 파일에서 앱이 위치한 곳을 구성할 수 있습니다:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\n해당 `entrypoint`는 `fastapi` 명령어에 다음과 같이 앱을 임포트하라고 알려줍니다:\n\n```python\nfrom main import app\n```\n\n코드 구조가 다음과 같다면:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\n그럼 `entrypoint`를 다음과 같이 설정합니다:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\n이는 다음과 동일합니다:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev`에 경로 지정하기 { #fastapi-dev-with-path }\n\n`fastapi dev` 명령어에 파일 경로를 전달할 수도 있으며, 그러면 사용할 FastAPI app 객체를 추정합니다:\n\n```console\n$ fastapi dev main.py\n```\n\n하지만 매번 `fastapi` 명령어를 호출할 때마다 올바른 경로를 전달해야 합니다.\n\n또한 다른 도구들, 예를 들어 [VS Code 확장](../editor-support.md)이나 [FastAPI Cloud](https://fastapicloud.com)가 이를 찾지 못할 수 있으므로, `pyproject.toml`의 `entrypoint`를 사용하는 것을 권장합니다.\n\n### 앱 배포하기(선택 사항) { #deploy-your-app-optional }\n\n선택적으로 FastAPI 앱을 [FastAPI Cloud](https://fastapicloud.com)에 배포할 수 있습니다. 아직 대기자 명단에 등록하지 않았다면, 등록하러 가세요. 🚀\n\n이미 **FastAPI Cloud** 계정이 있다면(대기자 명단에서 초대해 드렸습니다 😉), 한 번의 명령으로 애플리케이션을 배포할 수 있습니다.\n\n배포하기 전에, 로그인되어 있는지 확인하세요:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n그 다음 앱을 배포합니다:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n이게 전부입니다! 이제 해당 URL에서 앱에 접근할 수 있습니다. ✨\n\n## 단계별 요약 { #recap-step-by-step }\n\n### 1 단계: `FastAPI` 임포트 { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI`는 여러분의 API를 위한 모든 기능을 제공하는 파이썬 클래스입니다.\n\n/// note | 기술 세부사항\n\n`FastAPI`는 `Starlette`를 직접 상속하는 클래스입니다.\n\n`FastAPI`로 [Starlette](https://www.starlette.dev/)의 모든 기능을 사용할 수 있습니다.\n\n///\n\n### 2 단계: `FastAPI` \"인스턴스\" 생성 { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\n여기에서 `app` 변수는 `FastAPI` 클래스의 \"인스턴스\"가 됩니다.\n\n이것은 여러분의 모든 API를 생성하기 위한 상호작용의 주요 지점이 될 것입니다.\n\n### 3 단계: *경로 처리* 생성 { #step-3-create-a-path-operation }\n\n#### 경로 { #path }\n\n여기서 \"경로\"는 첫 번째 `/`부터 시작하는 URL의 뒷부분을 의미합니다.\n\n그러므로 아래와 같은 URL에서:\n\n```\nhttps://example.com/items/foo\n```\n\n...경로는 다음과 같습니다:\n\n```\n/items/foo\n```\n\n/// info | 정보\n\n\"경로\"는 일반적으로 \"엔드포인트\" 또는 \"라우트\"라고도 불립니다.\n\n///\n\nAPI를 설계할 때 \"경로\"는 \"관심사\"와 \"리소스\"를 분리하기 위한 주요한 방법입니다.\n\n#### 작동 { #operation }\n\n\"작동(Operation)\"은 HTTP \"메소드\" 중 하나를 나타냅니다.\n\n다음 중 하나이며:\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n...흔히 사용되지 않는 것들도 있습니다:\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\nHTTP 프로토콜에서는 이러한 \"메소드\"를 하나(또는 이상) 사용하여 각 경로와 통신할 수 있습니다.\n\n---\n\nAPI를 설계할 때 일반적으로 특정 행동을 수행하기 위해 특정 HTTP 메소드를 사용합니다.\n\n일반적으로 다음과 같습니다:\n\n* `POST`: 데이터를 생성하기 위해.\n* `GET`: 데이터를 읽기 위해.\n* `PUT`: 데이터를 수정하기 위해.\n* `DELETE`: 데이터를 삭제하기 위해.\n\n그래서 OpenAPI에서는 각 HTTP 메소드들을 \"작동\"이라 부릅니다.\n\n우리 역시 이제부터 메소드를 \"**작동**\"이라고 부를 것입니다.\n\n#### *경로 처리 데코레이터* 정의 { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\n`@app.get(\"/\")`은 **FastAPI**에게 바로 아래에 있는 함수가 다음으로 이동하는 요청을 처리한다는 것을 알려줍니다:\n\n* 경로 `/`\n* <dfn title=\"HTTP GET 메소드\"><code>get</code> 작동</dfn> 사용\n\n/// info | `@decorator` 정보\n\n이 `@something` 문법은 파이썬에서 \"데코레이터\"라 부릅니다.\n\n마치 예쁜 장식용(Decorative) 모자처럼(개인적으로 이 용어가 여기서 유래한 것 같습니다) 함수 맨 위에 놓습니다.\n\n\"데코레이터\"는 아래 있는 함수를 받아 그것으로 무언가를 합니다.\n\n우리의 경우, 이 데코레이터는 **FastAPI**에게 아래 함수가 **경로** `/`의 `get` **작동**에 해당한다고 알려줍니다.\n\n이것이 \"**경로 처리 데코레이터**\"입니다.\n\n///\n\n다른 작동도 사용할 수 있습니다:\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\n흔히 사용되지 않는 것들도 있습니다:\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip | 팁\n\n각 작동(HTTP 메소드)을 원하는 대로 사용해도 됩니다.\n\n**FastAPI**는 특정 의미를 강제하지 않습니다.\n\n여기서 정보는 지침서일뿐 강제사항이 아닙니다.\n\n예를 들어 GraphQL을 사용하는 경우, 일반적으로 `POST` 작동만 사용하여 모든 행동을 수행합니다.\n\n///\n\n### 4 단계: **경로 처리 함수** 정의 { #step-4-define-the-path-operation-function }\n\n다음은 우리의 \"**경로 처리 함수**\"입니다:\n\n* **경로**: 는 `/`입니다.\n* **작동**: 은 `get`입니다.\n* **함수**: 는 \"데코레이터\" 아래에 있는 함수입니다 (`@app.get(\"/\")` 아래).\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\n이것은 파이썬 함수입니다.\n\nURL \"`/`\"에 대한 `GET` 작동을 사용하는 요청을 받을 때마다 **FastAPI**에 의해 호출됩니다.\n\n위의 예시에서 이 함수는 `async`(비동기) 함수입니다.\n\n---\n\n`async def`을 이용하는 대신 일반 함수로 정의할 수 있습니다:\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note | 참고\n\n차이점을 모르겠다면 [Async: *\"바쁘신 경우\"*](../async.md#in-a-hurry)를 확인하세요.\n\n///\n\n### 5 단계: 콘텐츠 반환 { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\n`dict`, `list`, 단일값을 가진 `str`, `int` 등을 반환할 수 있습니다.\n\nPydantic 모델을 반환할 수도 있습니다(나중에 더 자세히 살펴봅니다).\n\nJSON으로 자동 변환되는 객체들과 모델들(ORM 등을 포함해서)이 많이 있습니다. 가장 마음에 드는 것을 사용하십시오, 이미 지원되고 있을 것입니다.\n\n### 6 단계: 배포하기 { #step-6-deploy-it }\n\n한 번의 명령으로 **[FastAPI Cloud](https://fastapicloud.com)**에 앱을 배포합니다: `fastapi deploy`. 🎉\n\n#### FastAPI Cloud 소개 { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)**는 **FastAPI** 뒤에 있는 동일한 작성자와 팀이 만들었습니다.\n\n최소한의 노력으로 API를 **빌드**, **배포**, **접근**하는 과정을 간소화합니다.\n\nFastAPI로 앱을 빌드할 때의 동일한 **개발자 경험**을 클라우드에 **배포**할 때도 제공합니다. 🎉\n\nFastAPI Cloud는 *FastAPI와 친구들* 오픈 소스 프로젝트의 주요 스폰서이자 자금 제공자입니다. ✨\n\n#### 다른 클라우드 제공업체에 배포하기 { #deploy-to-other-cloud-providers }\n\nFastAPI는 오픈 소스이며 표준을 기반으로 합니다. 선택한 어떤 클라우드 제공업체에도 FastAPI 앱을 배포할 수 있습니다.\n\n클라우드 제공업체의 가이드를 따라 FastAPI 앱을 배포하세요. 🤓\n\n## 요약 { #recap }\n\n* `FastAPI` 임포트.\n* `app` 인스턴스 생성.\n* (`@app.get(\"/\")`처럼) **경로 처리 데코레이터** 작성.\n* (위에 있는 `def root(): ...`처럼) **경로 처리 함수** 작성.\n* `fastapi dev` 명령으로 개발 서버 실행.\n* 선택적으로 `fastapi deploy`로 앱 배포.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/handling-errors.md",
    "content": "# 오류 처리 { #handling-errors }\n\nAPI를 사용하는 클라이언트에 오류를 알려야 하는 상황은 많이 있습니다.\n\n이 클라이언트는 프론트엔드가 있는 브라우저일 수도 있고, 다른 사람이 작성한 코드일 수도 있고, IoT 장치일 수도 있습니다.\n\n클라이언트에 다음과 같은 내용을 알려야 할 수도 있습니다:\n\n* 클라이언트가 해당 작업을 수행할 충분한 권한이 없습니다.\n* 클라이언트가 해당 리소스에 접근할 수 없습니다.\n* 클라이언트가 접근하려고 한 항목이 존재하지 않습니다.\n* 등등.\n\n이런 경우 보통 **400**번대(400에서 499) 범위의 **HTTP 상태 코드**를 반환합니다.\n\n이는 200번대 HTTP 상태 코드(200에서 299)와 비슷합니다. \"200\" 상태 코드는 어떤 형태로든 요청이 \"성공\"했음을 의미합니다.\n\n400번대 상태 코드는 클라이언트 측에서 오류가 발생했음을 의미합니다.\n\n**\"404 Not Found\"** 오류(그리고 농담들)도 다들 기억하시죠?\n\n## `HTTPException` 사용하기 { #use-httpexception }\n\n클라이언트에 오류가 포함된 HTTP 응답을 반환하려면 `HTTPException`을 사용합니다.\n\n### `HTTPException` 가져오기 { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### 코드에서 `HTTPException` 발생시키기 { #raise-an-httpexception-in-your-code }\n\n`HTTPException`은 API와 관련된 추가 데이터를 가진 일반적인 Python 예외입니다.\n\nPython 예외이므로 `return` 하는 것이 아니라 `raise` 합니다.\n\n이는 또한, *경로 처리 함수* 내부에서 호출하는 유틸리티 함수 안에서 `HTTPException`을 `raise`하면, *경로 처리 함수*의 나머지 코드는 실행되지 않고 즉시 해당 요청이 종료되며 `HTTPException`의 HTTP 오류가 클라이언트로 전송된다는 뜻입니다.\n\n값을 반환하는 것보다 예외를 발생시키는 것의 이점은 의존성과 보안에 대한 섹션에서 더 분명해집니다.\n\n이 예시에서는, 클라이언트가 존재하지 않는 ID로 항목을 요청하면 상태 코드 `404`로 예외를 발생시킵니다:\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### 결과 응답 { #the-resulting-response }\n\n클라이언트가 `http://example.com/items/foo`( `item_id` `\"foo\"`)를 요청하면, HTTP 상태 코드 200과 다음 JSON 응답을 받습니다:\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\n하지만 클라이언트가 `http://example.com/items/bar`(존재하지 않는 `item_id` `\"bar\"`)를 요청하면, HTTP 상태 코드 404(\"not found\" 오류)와 다음 JSON 응답을 받습니다:\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip | 팁\n\n`HTTPException`을 발생시킬 때 `detail` 파라미터로 `str`만 전달할 수 있는 것이 아니라, JSON으로 변환할 수 있는 어떤 값이든 전달할 수 있습니다.\n\n`dict`, `list` 등을 전달할 수 있습니다.\n\n이들은 **FastAPI**가 자동으로 처리해 JSON으로 변환합니다.\n\n///\n\n## 커스텀 헤더 추가하기 { #add-custom-headers }\n\nHTTP 오류에 커스텀 헤더를 추가할 수 있으면 유용한 상황이 있습니다. 예를 들어 특정 보안 유형에서 그렇습니다.\n\n아마 코드에서 직접 사용할 일은 거의 없을 것입니다.\n\n하지만 고급 시나리오에서 필요하다면 커스텀 헤더를 추가할 수 있습니다:\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## 커스텀 예외 핸들러 설치하기 { #install-custom-exception-handlers }\n\n[Starlette의 동일한 예외 유틸리티](https://www.starlette.dev/exceptions/)를 사용해 커스텀 예외 핸들러를 추가할 수 있습니다.\n\n여러분(또는 사용하는 라이브러리)이 `raise`할 수 있는 커스텀 예외 `UnicornException`이 있다고 가정해 봅시다.\n\n그리고 이 예외를 FastAPI에서 전역적으로 처리하고 싶다고 해봅시다.\n\n`@app.exception_handler()`로 커스텀 예외 핸들러를 추가할 수 있습니다:\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\n여기서 `/unicorns/yolo`를 요청하면, *경로 처리*가 `UnicornException`을 `raise`합니다.\n\n하지만 `unicorn_exception_handler`가 이를 처리합니다.\n\n따라서 HTTP 상태 코드 `418`과 다음 JSON 내용을 가진 깔끔한 오류를 받게 됩니다:\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | 기술 세부사항\n\n`from starlette.requests import Request`와 `from starlette.responses import JSONResponse`를 사용할 수도 있습니다.\n\n**FastAPI**는 개발자의 편의를 위해 `starlette.responses`를 `fastapi.responses`로도 동일하게 제공합니다. 하지만 사용 가능한 대부분의 응답은 Starlette에서 직접 옵니다. `Request`도 마찬가지입니다.\n\n///\n\n## 기본 예외 핸들러 오버라이드하기 { #override-the-default-exception-handlers }\n\n**FastAPI**에는 몇 가지 기본 예외 핸들러가 있습니다.\n\n이 핸들러들은 `HTTPException`을 `raise`했을 때, 그리고 요청에 유효하지 않은 데이터가 있을 때 기본 JSON 응답을 반환하는 역할을 합니다.\n\n이 예외 핸들러들을 여러분의 것으로 오버라이드할 수 있습니다.\n\n### 요청 검증 예외 오버라이드하기 { #override-request-validation-exceptions }\n\n요청에 유효하지 않은 데이터가 포함되면, **FastAPI**는 내부적으로 `RequestValidationError`를 `raise`합니다.\n\n그리고 이에 대한 기본 예외 핸들러도 포함되어 있습니다.\n\n이를 오버라이드하려면 `RequestValidationError`를 가져오고, `@app.exception_handler(RequestValidationError)`로 예외 핸들러를 데코레이트해 사용하세요.\n\n예외 핸들러는 `Request`와 예외를 받습니다.\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\n이제 `/items/foo`로 이동하면, 다음과 같은 기본 JSON 오류 대신:\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\n다음과 같은 텍스트 버전을 받게 됩니다:\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### `HTTPException` 오류 핸들러 오버라이드하기 { #override-the-httpexception-error-handler }\n\n같은 방식으로 `HTTPException` 핸들러도 오버라이드할 수 있습니다.\n\n예를 들어, 이런 오류들에 대해 JSON 대신 일반 텍스트 응답을 반환하고 싶을 수 있습니다:\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | 기술 세부사항\n\n`from starlette.responses import PlainTextResponse`를 사용할 수도 있습니다.\n\n**FastAPI**는 개발자의 편의를 위해 `starlette.responses`를 `fastapi.responses`로도 동일하게 제공합니다. 하지만 사용 가능한 대부분의 응답은 Starlette에서 직접 옵니다.\n\n///\n\n/// warning | 경고\n\n`RequestValidationError`에는 검증 오류가 발생한 파일 이름과 줄 정보가 포함되어 있어, 원한다면 관련 정보와 함께 로그에 표시할 수 있다는 점을 유념하세요.\n\n하지만 이는 단순히 문자열로 변환해 그 정보를 그대로 반환하면 시스템에 대한 일부 정보를 누설할 수 있다는 뜻이기도 합니다. 그래서 여기의 코드는 각 오류를 독립적으로 추출해 보여줍니다.\n\n///\n\n### `RequestValidationError`의 body 사용하기 { #use-the-requestvalidationerror-body }\n\n`RequestValidationError`에는 유효하지 않은 데이터와 함께 받은 `body`가 포함됩니다.\n\n앱을 개발하는 동안 body를 로그로 남기고 디버그하거나, 사용자에게 반환하는 등으로 사용할 수 있습니다.\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\n이제 다음처럼 유효하지 않은 item을 보내보세요:\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\n받은 body를 포함해 데이터가 유효하지 않다고 알려주는 응답을 받게 됩니다:\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### FastAPI의 `HTTPException` vs Starlette의 `HTTPException` { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI**에는 자체 `HTTPException`이 있습니다.\n\n그리고 **FastAPI**의 `HTTPException` 오류 클래스는 Starlette의 `HTTPException` 오류 클래스를 상속합니다.\n\n유일한 차이는 **FastAPI**의 `HTTPException`은 `detail` 필드에 JSON으로 변환 가능한 어떤 데이터든 받을 수 있는 반면, Starlette의 `HTTPException`은 문자열만 받을 수 있다는 점입니다.\n\n따라서 코드에서는 평소처럼 **FastAPI**의 `HTTPException`을 계속 `raise`하면 됩니다.\n\n하지만 예외 핸들러를 등록할 때는 Starlette의 `HTTPException`에 대해 등록해야 합니다.\n\n이렇게 하면 Starlette 내부 코드의 어떤 부분, 또는 Starlette 확장/플러그인이 Starlette `HTTPException`을 `raise`하더라도, 여러분의 핸들러가 이를 잡아서 처리할 수 있습니다.\n\n이 예시에서는 동일한 코드에서 두 `HTTPException`을 모두 사용할 수 있도록, Starlette의 예외를 `StarletteHTTPException`으로 이름을 바꿉니다:\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### **FastAPI**의 예외 핸들러 재사용하기 { #reuse-fastapis-exception-handlers }\n\n예외를 사용하면서 **FastAPI**의 동일한 기본 예외 핸들러도 함께 사용하고 싶다면, `fastapi.exception_handlers`에서 기본 예외 핸들러를 가져와 재사용할 수 있습니다:\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\n이 예시에서는 매우 표현력 있는 메시지로 오류를 출력만 하고 있지만, 요지는 이해하셨을 겁니다. 예외를 사용한 뒤 기본 예외 핸들러를 그대로 재사용할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/header-param-models.md",
    "content": "# 헤더 매개변수 모델 { #header-parameter-models }\n\n관련 있는 **헤더 매개변수** 그룹이 있는 경우, **Pydantic 모델**을 생성하여 선언할 수 있습니다.\n\n이를 통해 **여러 위치**에서 **모델을 재사용할** 수 있고 모든 매개변수에 대한 유효성 검사 및 메타데이터를 한 번에 선언할 수도 있습니다. 😎\n\n/// note | 참고\n\n이 기능은 FastAPI 버전 `0.115.0` 이후부터 지원됩니다. 🤓\n\n///\n\n## Pydantic 모델을 사용한 헤더 매개변수 { #header-parameters-with-a-pydantic-model }\n\n**Pydantic 모델**에 필요한 **헤더 매개변수**를 선언한 다음, 해당 매개변수를 `Header`로 선언합니다:\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\n**FastAPI**는 요청에서 받은 **헤더**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다.\n\n## 문서 확인하기 { #check-the-docs }\n\n문서 UI `/docs`에서 필요한 헤더를 볼 수 있습니다:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## 추가 헤더 금지하기 { #forbid-extra-headers }\n\n일부 특별한 사용 사례(흔하지는 않겠지만)에서는 수신하려는 헤더를 **제한**할 수 있습니다.\n\nPydantic의 모델 구성을 사용하여 추가(`extra`) 필드를 금지(`forbid`)할 수 있습니다:\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\n클라이언트가 **추가 헤더**를 보내려고 시도하면, **오류** 응답을 받게 됩니다.\n\n예를 들어, 클라이언트가 `plumbus` 값으로 `tool` 헤더를 보내려고 하면, 클라이언트는 헤더 매개변수 `tool`이 허용되지 않는다는 **오류** 응답을 받게 됩니다:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## 밑줄 변환 비활성화하기 { #disable-convert-underscores }\n\n일반적인 헤더 매개변수와 마찬가지로, 매개변수 이름에 밑줄 문자가 있으면 **자동으로 하이픈으로 변환**됩니다.\n\n예를 들어, 코드에 `save_data` 헤더 매개변수가 있으면, 기대되는 HTTP 헤더는 `save-data`이고, 문서에서도 그렇게 표시됩니다.\n\n어떤 이유로든 이 자동 변환을 비활성화해야 한다면, 헤더 매개변수용 Pydantic 모델에서도 비활성화할 수 있습니다.\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | 경고\n\n`convert_underscores`를 `False`로 설정하기 전에, 일부 HTTP 프록시와 서버에서는 밑줄이 포함된 헤더 사용을 허용하지 않는다는 점을 염두에 두세요.\n\n///\n\n## 요약 { #summary }\n\n**Pydantic 모델**을 사용하여 **FastAPI**에서 **헤더**를 선언할 수 있습니다. 😎\n"
  },
  {
    "path": "docs/ko/docs/tutorial/header-params.md",
    "content": "# 헤더 매개변수 { #header-parameters }\n\n헤더 매개변수를 `Query`, `Path` 그리고 `Cookie` 매개변수들과 같은 방식으로 정의할 수 있습니다.\n\n## `Header` 임포트 { #import-header }\n\n먼저 `Header`를 임포트합니다:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## `Header` 매개변수 선언 { #declare-header-parameters }\n\n`Path`, `Query` 그리고 `Cookie`를 사용한 동일한 구조를 이용하여 헤더 매개변수를 선언합니다.\n\n첫 번째 값은 기본값이며, 추가 검증이나 어노테이션 매개변수 모두 전달할 수 있습니다:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | 기술 세부사항\n\n`Header`는 `Path`, `Query` 및 `Cookie`의 \"자매\"클래스입니다. 이 역시 동일한 공통 `Param` 클래스를 상속합니다.\n\n`Query`, `Path`, `Header` 그리고 다른 것들을 `fastapi`에서 임포트 할 때, 이들은 실제로 특별한 클래스를 반환하는 함수임을 기억하세요.\n\n///\n\n/// info | 정보\n\n헤더를 선언하기 위해서 `Header`를 사용해야 합니다. 그렇지 않으면 해당 매개변수를 쿼리 매개변수로 해석하기 때문입니다.\n\n///\n\n## 자동 변환 { #automatic-conversion }\n\n`Header`는 `Path`, `Query` 그리고 `Cookie`가 제공하는 것 외에 기능이 조금 더 있습니다.\n\n대부분의 표준 헤더는 \"마이너스 기호\" (`-`)라고도 하는 \"하이픈\" 문자로 구분됩니다.\n\n그러나 파이썬에서 `user-agent`와 같은 형태의 변수는 유효하지 않습니다.\n\n따라서 `Header`는 기본적으로 매개변수 이름을 언더스코어(`_`)에서 하이픈(`-`)으로 변환하여 헤더를 추출하고 기록합니다.\n\n또한 HTTP 헤더는 대소문자를 구분하지 않으므로 \"snake_case\"로 알려진 표준 파이썬 스타일로 선언할 수 있습니다.\n\n따라서, `User_Agent` 등과 같이 첫 문자를 대문자화할 필요없이 파이썬 코드에서처럼 `user_agent`로 사용합니다.\n\n만약 언더스코어를 하이픈으로 자동 변환을 비활성화해야 할 어떤 이유가 있다면, `Header`의 `convert_underscores` 매개변수를 `False`로 설정하십시오:\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | 경고\n\n`convert_underscores`를 `False`로 설정하기 전에, 어떤 HTTP 프록시들과 서버들은 언더스코어가 포함된 헤더 사용을 허락하지 않는다는 것을 명심하십시오.\n\n///\n\n## 중복 헤더 { #duplicate-headers }\n\n중복 헤더들을 수신할 수 있습니다. 즉, 다중값을 갖는 동일한 헤더를 뜻합니다.\n\n타입 정의에서 리스트를 사용하여 이러한 케이스를 정의할 수 있습니다.\n\n중복 헤더의 모든 값을 파이썬 `list`로 수신합니다.\n\n예를 들어, 두 번 이상 나타날 수 있는 `X-Token`헤더를 선언하려면, 다음과 같이 작성합니다:\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\n다음과 같은 두 개의 HTTP 헤더를 전송하여 해당 *경로 처리* 와 통신할 경우:\n\n```\nX-Token: foo\nX-Token: bar\n```\n\n응답은 다음과 같습니다:\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## 요약 { #recap }\n\n`Header`는 `Query`, `Path`, `Cookie`와 동일한 패턴을 사용하여 선언합니다.\n\n변수의 언더스코어를 걱정하지 마십시오, **FastAPI**가 변수를 변환할 것입니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/index.md",
    "content": "# 자습서 - 사용자 안내서 { #tutorial-user-guide }\n\n이 자습서는 **FastAPI**의 대부분의 기능을 단계별로 사용하는 방법을 보여줍니다.\n\n각 섹션은 이전 섹션을 바탕으로 점진적으로 구성되지만, 주제를 분리한 구조로 되어 있어 특정 API 요구사항을 해결하기 위해 원하는 섹션으로 바로 이동할 수 있습니다.\n\n또한 나중에 참고 자료로도 사용할 수 있도록 만들어졌으므로, 필요할 때 다시 돌아와 정확히 필요한 내용을 확인할 수 있습니다.\n\n## 코드 실행하기 { #run-the-code }\n\n모든 코드 블록은 복사해서 바로 사용할 수 있습니다(실제로 테스트된 Python 파일입니다).\n\n예제 중 어떤 것이든 실행하려면, 코드를 `main.py` 파일에 복사하고 다음으로 `fastapi dev`를 시작하세요:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n코드를 작성하거나 복사한 뒤 편집하고, 로컬에서 실행하는 것을 **강력히 권장**합니다.\n\n에디터에서 사용해 보면, 작성해야 하는 코드가 얼마나 적은지, 모든 타입 검사와 자동완성 등 FastAPI의 이점을 제대로 확인할 수 있습니다.\n\n---\n\n## FastAPI 설치 { #install-fastapi }\n\n첫 단계는 FastAPI를 설치하는 것입니다.\n\n[가상 환경](../virtual-environments.md)을 생성하고 활성화한 다음, **FastAPI를 설치**하세요:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | 참고\n\n`pip install \"fastapi[standard]\"`로 설치하면 `fastapi-cloud-cli`를 포함한 몇 가지 기본 선택적 standard 의존성이 함께 설치되며, 이를 사용해 [FastAPI Cloud](https://fastapicloud.com)에 배포할 수 있습니다.\n\n이러한 선택적 의존성이 필요 없다면 `pip install fastapi`로 대신 설치할 수 있습니다.\n\nstandard 의존성은 설치하되 `fastapi-cloud-cli` 없이 설치하려면 `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`로 설치할 수 있습니다.\n\n///\n\n/// tip | 팁\n\nFastAPI는 VS Code(및 Cursor)용 [공식 확장 프로그램](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode)이 있습니다. 경로 처리 탐색기, 경로 처리 검색, 테스트에서의 CodeLens 탐색(테스트에서 정의로 바로 이동), FastAPI Cloud 배포와 로그 등 많은 기능을 에디터에서 바로 제공합니다.\n\n///\n\n## 고급 사용자 안내서 { #advanced-user-guide }\n\n이 **자습서 - 사용자 안내서**를 읽은 뒤에 나중에 읽을 수 있는 **고급 사용자 안내서**도 있습니다.\n\n**고급 사용자 안내서**는 이 문서를 바탕으로 동일한 개념을 사용하며, 몇 가지 추가 기능을 알려줍니다.\n\n하지만 먼저 **자습서 - 사용자 안내서**(지금 읽고 있는 내용)를 읽어야 합니다.\n\n**자습서 - 사용자 안내서**만으로 완전한 애플리케이션을 만들 수 있도록 설계되었고, 필요에 따라 **고급 사용자 안내서**의 추가 아이디어를 활용해 다양한 방식으로 확장할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/metadata.md",
    "content": "# 메타데이터 및 문서화 URL { #metadata-and-docs-urls }\n\n**FastAPI** 애플리케이션에서 다양한 메타데이터 구성을 사용자 맞춤 설정할 수 있습니다.\n\n## API에 대한 메타데이터 { #metadata-for-api }\n\nOpenAPI 명세 및 자동화된 API 문서 UI에 사용되는 다음 필드를 설정할 수 있습니다:\n\n| 매개변수 | 타입 | 설명 |\n|----------|------|-------|\n| `title` | `str` | API의 제목입니다. |\n| `summary` | `str` | API에 대한 짧은 요약입니다. <small>OpenAPI 3.1.0, FastAPI 0.99.0부터 사용 가능.</small> |\n| `description` | `str` | API에 대한 짧은 설명입니다. 마크다운을 사용할 수 있습니다. |\n| `version` | `string` | API의 버전입니다. OpenAPI의 버전이 아닌, 여러분의 애플리케이션의 버전을 나타냅니다. 예: `2.5.0`. |\n| `terms_of_service` | `str` | API 이용 약관의 URL입니다. 제공하는 경우 URL 형식이어야 합니다. |\n| `contact` | `dict` | 노출된 API에 대한 연락처 정보입니다. 여러 필드를 포함할 수 있습니다. <details><summary><code>contact</code> 필드</summary><table><thead><tr><th>매개변수</th><th>타입</th><th>설명</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>연락처 인물/조직의 식별명입니다.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>연락처 정보가 담긴 URL입니다. URL 형식이어야 합니다.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>연락처 인물/조직의 이메일 주소입니다. 이메일 주소 형식이어야 합니다.</td></tr></tbody></table></details> |\n| `license_info` | `dict` | 노출된 API의 라이선스 정보입니다. 여러 필드를 포함할 수 있습니다. <details><summary><code>license_info</code> 필드</summary><table><thead><tr><th>매개변수</th><th>타입</th><th>설명</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>필수</strong> (<code>license_info</code>가 설정된 경우). API에 사용된 라이선스 이름입니다.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>API에 대한 [SPDX](https://spdx.org/licenses/) 라이선스 표현입니다. <code>identifier</code> 필드는 <code>url</code> 필드와 상호 배타적입니다. <small>OpenAPI 3.1.0, FastAPI 0.99.0부터 사용 가능.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>API에 사용된 라이선스의 URL입니다. URL 형식이어야 합니다.</td></tr></tbody></table></details> |\n\n다음과 같이 설정할 수 있습니다:\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | 팁\n\n`description` 필드에 마크다운을 사용할 수 있으며, 출력에서 렌더링됩니다.\n\n///\n\n이 구성을 사용하면 문서 자동화(로 생성된) API 문서는 다음과 같이 보입니다:\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## 라이선스 식별자 { #license-identifier }\n\nOpenAPI 3.1.0 및 FastAPI 0.99.0부터 `license_info`에 `url` 대신 `identifier`를 설정할 수도 있습니다.\n\n예:\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## 태그에 대한 메타데이터 { #metadata-for-tags }\n\n`openapi_tags` 매개변수를 사용하여 경로 처리를 그룹화하는 데 사용되는 여러 태그에 추가 메타데이터를 추가할 수도 있습니다.\n\n리스트는 각 태그에 대해 하나의 딕셔너리를 포함합니다.\n\n각 딕셔너리에는 다음이 포함될 수 있습니다:\n\n* `name` (**필수**): *경로 처리* 및 `APIRouter`의 `tags` 매개변수에서 사용하는 태그 이름과 동일한 `str`입니다.\n* `description`: 태그에 대한 간단한 설명을 담은 `str`입니다. 마크다운을 포함할 수 있으며 문서 UI에 표시됩니다.\n* `externalDocs`: 외부 문서를 설명하는 `dict`이며:\n    * `description`: 외부 문서에 대한 간단한 설명을 담은 `str`입니다.\n    * `url` (**필수**): 외부 문서의 URL을 담은 `str`입니다.\n\n### 태그에 대한 메타데이터 생성 { #create-metadata-for-tags }\n\n`users` 및 `items`에 대한 태그 예시로 시도해 보겠습니다.\n\n태그에 대한 메타데이터를 생성하고 이를 `openapi_tags` 매개변수로 전달하세요:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\n설명 안에 마크다운을 사용할 수 있다는 점에 유의하세요. 예를 들어 \"login\"은 굵게(**login**) 표시되고, \"fancy\"는 기울임꼴(_fancy_)로 표시됩니다.\n\n/// tip | 팁\n\n사용 중인 모든 태그에 메타데이터를 추가할 필요는 없습니다.\n\n///\n\n### 태그 사용 { #use-your-tags }\n\n`tags` 매개변수를 *경로 처리* (및 `APIRouter`)와 함께 사용하여 이를 서로 다른 태그에 할당하세요:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info | 정보\n\n태그에 대한 자세한 내용은 [경로 처리 구성](path-operation-configuration.md#tags)에서 읽어보세요.\n\n///\n\n### 문서 확인 { #check-the-docs }\n\n이제 문서를 확인하면 모든 추가 메타데이터가 표시됩니다:\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### 태그 순서 { #order-of-tags }\n\n각 태그 메타데이터 딕셔너리의 순서는 문서 UI에 표시되는 순서도 정의합니다.\n\n예를 들어, 알파벳 순서상 `users`는 `items` 뒤에 오지만, 우리는 해당 메타데이터를 리스트의 첫 번째 딕셔너리로 추가했기 때문에 먼저 표시됩니다.\n\n## OpenAPI URL { #openapi-url }\n\n기본적으로 OpenAPI 스키마는 `/openapi.json`에서 제공됩니다.\n\n하지만 `openapi_url` 매개변수로 이를 설정할 수 있습니다.\n\n예를 들어, 이를 `/api/v1/openapi.json`에서 제공하도록 설정하려면:\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\nOpenAPI 스키마를 완전히 비활성화하려면 `openapi_url=None`으로 설정할 수 있으며, 이를 사용하여 문서화 사용자 인터페이스도 비활성화됩니다.\n\n## 문서화 URL { #docs-urls }\n\n포함된 두 가지 문서화 사용자 인터페이스를 설정할 수 있습니다:\n\n* **Swagger UI**: `/docs`에서 제공됩니다.\n    * `docs_url` 매개변수로 URL을 설정할 수 있습니다.\n    * `docs_url=None`으로 설정하여 비활성화할 수 있습니다.\n* **ReDoc**: `/redoc`에서 제공됩니다.\n    * `redoc_url` 매개변수로 URL을 설정할 수 있습니다.\n    * `redoc_url=None`으로 설정하여 비활성화할 수 있습니다.\n\n예를 들어, Swagger UI를 `/documentation`에서 제공하고 ReDoc을 비활성화하려면:\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/ko/docs/tutorial/middleware.md",
    "content": "# 미들웨어 { #middleware }\n\n미들웨어를 **FastAPI** 애플리케이션에 추가할 수 있습니다.\n\n\"미들웨어\"는 특정 *경로 처리*에 의해 처리되기 전, 모든 **요청**에 대해서 동작하는 함수입니다. 또한 모든 **응답**이 반환되기 전에도 동일하게 동작합니다.\n\n* 미들웨어는 애플리케이션으로 오는 각 **요청**을 가져옵니다.\n* 그런 다음 해당 **요청**에 대해 무언가를 하거나 필요한 코드를 실행할 수 있습니다.\n* 그런 다음 **요청**을 나머지 애플리케이션(어떤 *경로 처리*가)을 통해 처리되도록 전달합니다.\n* 그런 다음 애플리케이션(어떤 *경로 처리*가)이 생성한 **응답**을 가져옵니다.\n* 그런 다음 해당 **응답**에 대해 무언가를 하거나 필요한 코드를 실행할 수 있습니다.\n* 그런 다음 **응답**을 반환합니다.\n\n/// note | 기술 세부사항\n\n`yield`를 사용하는 의존성이 있다면, exit 코드는 미들웨어 *후에* 실행됩니다.\n\n백그라운드 작업(뒤에서 보게 될 [백그라운드 작업](background-tasks.md) 섹션에서 다룹니다)이 있다면, 모든 미들웨어 *후에* 실행됩니다.\n\n///\n\n## 미들웨어 만들기 { #create-a-middleware }\n\n미들웨어를 만들기 위해 함수 상단에 데코레이터 `@app.middleware(\"http\")`를 사용합니다.\n\n미들웨어 함수는 다음을 받습니다:\n\n* `request`.\n* `request`를 매개변수로 받는 `call_next` 함수.\n    * 이 함수는 `request`를 해당하는 *경로 처리*로 전달합니다.\n    * 그런 다음 해당 *경로 처리*가 생성한 `response`를 반환합니다.\n* 그런 다음 반환하기 전에 `response`를 추가로 수정할 수 있습니다.\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip | 팁\n\n사용자 정의 독점 헤더는 [`X-` 접두사를 사용](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)하여 추가할 수 있다는 점을 기억하세요.\n\n하지만 브라우저에서 클라이언트가 볼 수 있게 하려는 사용자 정의 헤더가 있다면, [CORS (Cross-Origin Resource Sharing)](cors.md) 설정에 [Starlette의 CORS 문서](https://www.starlette.dev/middleware/#corsmiddleware)에 문서화된 `expose_headers` 매개변수를 사용해 추가해야 합니다.\n\n///\n\n/// note | 기술 세부사항\n\n`from starlette.requests import Request`를 사용할 수도 있습니다.\n\n**FastAPI**는 개발자인 여러분의 편의를 위해 이를 제공합니다. 하지만 이는 Starlette에서 직접 가져온 것입니다.\n\n///\n\n### `response`의 전과 후 { #before-and-after-the-response }\n\n어떤 *경로 처리*가 받기 전에, `request`와 함께 실행될 코드를 추가할 수 있습니다.\n\n또한 `response`가 생성된 후, 반환하기 전에 코드를 추가할 수도 있습니다.\n\n예를 들어, 요청을 처리하고 응답을 생성하는 데 걸린 시간을 초 단위로 담는 사용자 정의 헤더 `X-Process-Time`을 추가할 수 있습니다:\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip | 팁\n\n여기서는 이러한 사용 사례에서 더 정확할 수 있기 때문에 `time.time()` 대신 [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter)를 사용합니다. 🤓\n\n///\n\n## 여러 미들웨어 실행 순서 { #multiple-middleware-execution-order }\n\n`@app.middleware()` 데코레이터 또는 `app.add_middleware()` 메서드를 사용해 여러 미들웨어를 추가하면, 새로 추가된 각 미들웨어가 애플리케이션을 감싸 스택을 형성합니다. 마지막에 추가된 미들웨어가 *가장 바깥쪽*이고, 처음에 추가된 미들웨어가 *가장 안쪽*입니다.\n\n요청 경로에서는 *가장 바깥쪽* 미들웨어가 먼저 실행됩니다.\n\n응답 경로에서는 마지막에 실행됩니다.\n\n예를 들어:\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\n이 경우 실행 순서는 다음과 같습니다:\n\n* **요청**: MiddlewareB → MiddlewareA → route\n\n* **응답**: route → MiddlewareA → MiddlewareB\n\n이러한 스태킹 동작은 미들웨어가 예측 가능하고 제어 가능한 순서로 실행되도록 보장합니다.\n\n## 다른 미들웨어 { #other-middlewares }\n\n다른 미들웨어에 대한 더 많은 정보는 나중에 [숙련된 사용자 안내서: 향상된 미들웨어](../advanced/middleware.md)에서 확인할 수 있습니다.\n\n다음 섹션에서 미들웨어로 <abbr title=\"Cross-Origin Resource Sharing - 교차 출처 리소스 공유\">CORS</abbr>를 처리하는 방법을 보게 될 것입니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/path-operation-configuration.md",
    "content": "# 경로 처리 설정 { #path-operation-configuration }\n\n*경로 처리 데코레이터*를 설정하기 위해 전달할 수 있는 몇 가지 매개변수가 있습니다.\n\n/// warning | 경고\n\n아래 매개변수들은 *경로 처리 함수*가 아닌 *경로 처리 데코레이터*에 직접 전달된다는 사실을 기억하세요.\n\n///\n\n## 응답 상태 코드 { #response-status-code }\n\n*경로 처리*의 응답에 사용될 (HTTP) `status_code`를 정의할 수 있습니다.\n\n`404`와 같은 `int`형 코드를 직접 전달할 수 있습니다.\n\n하지만 각 숫자 코드가 무엇을 의미하는지 기억하지 못한다면, `status`에 있는 단축 상수들을 사용할 수 있습니다:\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\n해당 상태 코드는 응답에 사용되며, OpenAPI 스키마에 추가됩니다.\n\n/// note | 기술 세부사항\n\n다음과 같이 임포트하셔도 좋습니다. `from starlette import status`.\n\n**FastAPI**는 개발자 여러분의 편의를 위해 `starlette.status`와 동일한 `fastapi.status`를 제공합니다. 하지만 이는 Starlette에서 직접 온 것입니다.\n\n///\n\n## 태그 { #tags }\n\n(보통 단일 `str`인) `str`로 구성된 `list`와 함께 매개변수 `tags`를 전달하여, *경로 처리*에 태그를 추가할 수 있습니다:\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\n전달된 태그들은 OpenAPI의 스키마에 추가되며, 자동 문서 인터페이스에서 사용됩니다:\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### Enum을 사용한 태그 { #tags-with-enums }\n\n큰 애플리케이션이 있다면, **여러 태그**가 쌓이게 될 수 있고, 관련된 *경로 처리*에 항상 **같은 태그**를 사용하는지 확인하고 싶을 것입니다.\n\n이런 경우에는 태그를 `Enum`에 저장하는 것이 합리적일 수 있습니다.\n\n**FastAPI**는 일반 문자열과 동일한 방식으로 이를 지원합니다:\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## 요약과 설명 { #summary-and-description }\n\n`summary`와 `description`을 추가할 수 있습니다:\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## 독스트링으로 만든 설명 { #description-from-docstring }\n\n설명은 보통 길어지고 여러 줄에 걸쳐있기 때문에, *경로 처리* 설명을 함수 <dfn title=\"문서화에 사용되는 함수 내부 첫 표현식의 여러 줄 문자열(어떤 변수에도 할당되지 않음)\">독스트링</dfn>에 선언할 수 있으며, **FastAPI**는 그곳에서 이를 읽습니다.\n\n독스트링에는 [Markdown](https://en.wikipedia.org/wiki/Markdown)을 작성할 수 있으며, (독스트링의 들여쓰기를 고려하여) 올바르게 해석되고 표시됩니다.\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\n이는 대화형 문서에서 사용됩니다:\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## 응답 설명 { #response-description }\n\n`response_description` 매개변수로 응답에 관한 설명을 명시할 수 있습니다:\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info | 정보\n\n`response_description`은 구체적으로 응답을 지칭하며, `description`은 일반적인 *경로 처리*를 지칭합니다.\n\n///\n\n/// check | 확인\n\nOpenAPI는 각 *경로 처리*가 응답에 관한 설명을 요구할 것을 명시합니다.\n\n따라서, 응답에 관한 설명을 제공하지 않으면, **FastAPI**가 \"Successful response\" 중 하나를 자동으로 생성합니다.\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## *경로 처리* 지원중단하기 { #deprecate-a-path-operation }\n\n*경로 처리*를 제거하지 않고 <dfn title=\"구식이며 사용하지 않는 것이 권장됨\">지원중단</dfn>으로 표시해야 한다면, `deprecated` 매개변수를 전달하면 됩니다:\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\n대화형 문서에서 지원중단으로 명확하게 표시됩니다:\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\n지원중단된 *경로 처리*와 지원중단되지 않은 *경로 처리*가 어떻게 보이는지 확인해 보세요:\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## 정리 { #recap }\n\n*경로 처리 데코레이터*에 매개변수(들)를 전달하여 *경로 처리*를 설정하고 메타데이터를 쉽게 추가할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/path-params-numeric-validations.md",
    "content": "# 경로 매개변수와 숫자 검증 { #path-parameters-and-numeric-validations }\n\n`Query`를 사용하여 쿼리 매개변수에 더 많은 검증과 메타데이터를 선언하는 방법과 동일하게 `Path`를 사용하여 경로 매개변수에 검증과 메타데이터를 같은 타입으로 선언할 수 있습니다.\n\n## `Path` 임포트 { #import-path }\n\n먼저 `fastapi`에서 `Path`를 임포트하고, `Annotated`도 임포트합니다:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info | 정보\n\nFastAPI는 0.95.0 버전에서 `Annotated` 지원을 추가했고(그리고 이를 권장하기 시작했습니다).\n\n더 오래된 버전이 있다면 `Annotated`를 사용하려고 할 때 오류가 발생합니다.\n\n`Annotated`를 사용하기 전에 최소 0.95.1까지 [FastAPI 버전 업그레이드](../deployment/versions.md#upgrading-the-fastapi-versions)를 꼭 하세요.\n\n///\n\n## 메타데이터 선언 { #declare-metadata }\n\n`Query`에 동일한 매개변수를 선언할 수 있습니다.\n\n예를 들어, 경로 매개변수 `item_id`에 `title` 메타데이터 값을 선언하려면 다음과 같이 입력할 수 있습니다:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note | 참고\n\n경로 매개변수는 경로의 일부여야 하므로 언제나 필수입니다. `None`으로 선언하거나 기본값을 지정하더라도 아무 영향이 없으며, 항상 필수입니다.\n\n///\n\n## 필요한 대로 매개변수 정렬하기 { #order-the-parameters-as-you-need }\n\n/// tip | 팁\n\n`Annotated`를 사용한다면 이것은 아마 그렇게 중요하지 않거나 필요하지 않을 수 있습니다.\n\n///\n\n`str` 형인 쿼리 매개변수 `q`를 필수로 선언하고 싶다고 해봅시다.\n\n해당 매개변수에 대해 아무런 선언을 할 필요가 없으므로 `Query`를 정말로 써야 할 필요는 없습니다.\n\n하지만 `item_id` 경로 매개변수는 여전히 `Path`를 사용해야 합니다. 그리고 어떤 이유로 `Annotated`를 사용하고 싶지 않다고 해봅시다.\n\n파이썬은 \"기본값\"이 있는 값을 \"기본값\"이 없는 값 앞에 두면 불평합니다.\n\n하지만 순서를 재정렬해서 기본값이 없는 값(쿼리 매개변수 `q`)을 앞에 둘 수 있습니다.\n\n**FastAPI**에서는 중요하지 않습니다. 이름, 타입 그리고 기본값 선언(`Query`, `Path` 등)로 매개변수를 감지하며 순서는 신경 쓰지 않습니다.\n\n따라서 함수를 다음과 같이 선언할 수 있습니다:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\n하지만 `Annotated`를 사용하면 이 문제가 없다는 점을 기억하세요. `Query()`나 `Path()`에 함수 매개변수 기본값을 사용하지 않기 때문에, 순서는 중요하지 않습니다.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## 필요한 대로 매개변수 정렬하기, 트릭 { #order-the-parameters-as-you-need-tricks }\n\n/// tip | 팁\n\n`Annotated`를 사용한다면 이것은 아마 그렇게 중요하지 않거나 필요하지 않을 수 있습니다.\n\n///\n\n유용할 수 있는 **작은 트릭**이 하나 있지만, 자주 필요하진 않을 겁니다.\n\n만약 다음을 원한다면:\n\n* `Query`나 어떤 기본값 없이 쿼리 매개변수 `q`를 선언하기\n* `Path`를 사용해서 경로 매개변수 `item_id`를 선언하기\n* 이들을 다른 순서로 두기\n* `Annotated`를 사용하지 않기\n\n...이를 위해 파이썬에는 작은 특별한 문법이 있습니다.\n\n함수의 첫 번째 매개변수로 `*`를 전달하세요.\n\n파이썬은 `*`으로 아무것도 하지 않지만, 뒤따르는 모든 매개변수는 키워드 인자(키-값 쌍)로 호출되어야 함을 알게 됩니다. 이는 <abbr title=\"출처: K-ey W-ord Arg-uments - 키워드 인자\"><code>kwargs</code></abbr>로도 알려져 있습니다. 기본값이 없더라도 마찬가지입니다.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### `Annotated`를 쓰면 더 좋습니다 { #better-with-annotated }\n\n`Annotated`를 사용하면 함수 매개변수 기본값을 사용하지 않기 때문에 이 문제가 발생하지 않으며, 아마 `*`도 사용할 필요가 없다는 점을 기억하세요.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## 숫자 검증: 크거나 같음 { #number-validations-greater-than-or-equal }\n\n`Query`와 `Path`(그리고 나중에 볼 다른 것들)를 사용하여 숫자 제약을 선언할 수 있습니다.\n\n여기서 `ge=1`인 경우, `item_id`는 `1`보다 \"`g`reater than or `e`qual\"(크거나 같은) 정수형 숫자여야 합니다.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## 숫자 검증: 크거나 및 작거나 같음 { #number-validations-greater-than-and-less-than-or-equal }\n\n동일하게 적용됩니다:\n\n* `gt`: `g`reater `t`han\n* `le`: `l`ess than or `e`qual\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## 숫자 검증: 부동소수, 크거나 및 작거나 { #number-validations-floats-greater-than-and-less-than }\n\n숫자 검증은 `float` 값에도 동작합니다.\n\n여기에서 <abbr title=\"greater than - 보다 큼\"><code>gt</code></abbr>를, <abbr title=\"greater than or equal - 크거나 같음\"><code>ge</code></abbr>뿐만 아니라 선언할 수 있다는 점이 중요해집니다. 예를 들어 값이 `1`보다 작더라도, 반드시 `0`보다 커야 한다고 요구할 수 있습니다.\n\n즉, `0.5`는 유효한 값입니다. 그러나 `0.0` 또는 `0`은 그렇지 않습니다.\n\n<abbr title=\"less than - 보다 작음\"><code>lt</code></abbr> 역시 마찬가지입니다.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## 요약 { #recap }\n\n`Query`, `Path`(아직 보지 못한 다른 것들도)를 사용하면 [쿼리 매개변수와 문자열 검증](query-params-str-validations.md)에서와 마찬가지로 메타데이터와 문자열 검증을 선언할 수 있습니다.\n\n그리고 숫자 검증 또한 선언할 수 있습니다:\n\n* `gt`: `g`reater `t`han\n* `ge`: `g`reater than or `e`qual\n* `lt`: `l`ess `t`han\n* `le`: `l`ess than or `e`qual\n\n/// info | 정보\n\n`Query`, `Path`, 그리고 나중에 보게 될 다른 클래스들은 공통 `Param` 클래스의 서브클래스입니다.\n\n이들 모두는 여러분이 본 추가 검증과 메타데이터에 대한 동일한 매개변수를 공유합니다.\n\n///\n\n/// note | 기술 세부사항\n\n`fastapi`에서 `Query`, `Path` 등을 임포트할 때, 이것들은 실제로 함수입니다.\n\n호출되면 동일한 이름의 클래스의 인스턴스를 반환합니다.\n\n즉, 함수인 `Query`를 임포트한 겁니다. 그리고 호출하면 `Query`라는 이름을 가진 클래스의 인스턴스를 반환합니다.\n\n이 함수들이 있는 이유는(클래스를 직접 사용하는 대신) 편집기에서 타입에 대한 오류를 표시하지 않도록 하기 위해서입니다.\n\n이렇게 하면 오류를 무시하기 위한 사용자 설정을 추가하지 않고도 일반 편집기와 코딩 도구를 사용할 수 있습니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/tutorial/path-params.md",
    "content": "# 경로 매개변수 { #path-parameters }\n\n파이썬의 포맷 문자열 리터럴에서 사용되는 문법을 이용하여 경로 \"매개변수\" 또는 \"변수\"를 선언할 수 있습니다:\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\n경로 매개변수 `item_id`의 값은 함수의 `item_id` 인자로 전달됩니다.\n\n그래서 이 예제를 실행하고 [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo)로 이동하면, 다음 응답을 볼 수 있습니다:\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## 타입이 있는 경로 매개변수 { #path-parameters-with-types }\n\n파이썬 표준 타입 어노테이션을 사용하여 함수에 있는 경로 매개변수의 타입을 선언할 수 있습니다:\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\n위의 예시에서, `item_id`는 `int`로 선언되었습니다.\n\n/// check | 확인\n\n이 기능은 함수 내에서 오류 검사, 자동완성 등의 편집기 기능을 활용할 수 있게 해줍니다.\n\n///\n\n## 데이터 <dfn title=\"다음으로도 알려져 있습니다: 직렬화, 파싱, 마샬링\">변환</dfn> { #data-conversion }\n\n이 예제를 실행하고 [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3)을 열면, 다음 응답을 볼 수 있습니다:\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check | 확인\n\n함수가 받은(반환도 하는) 값은 문자열 `\"3\"`이 아니라 파이썬 `int` 형인 `3`입니다.\n\n즉, 타입 선언을 하면 **FastAPI**는 자동으로 요청을 <dfn title=\"HTTP 요청에서 전달되는 문자열을 파이썬 데이터로 변환\">\"파싱\"</dfn>합니다.\n\n///\n\n## 데이터 검증 { #data-validation }\n\n하지만 브라우저에서 [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo)로 이동하면, 다음과 같은 HTTP 오류를 볼 수 있습니다:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\n경로 매개변수 `item_id`가 `int`가 아닌 `\"foo\"` 값을 가졌기 때문입니다.\n\n`int` 대신 `float`을 제공하면(예: [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)) 동일한 오류가 나타납니다.\n\n/// check | 확인\n\n즉, 파이썬 타입 선언을 하면 **FastAPI**는 데이터 검증을 합니다.\n\n또한 오류에는 검증을 통과하지 못한 지점이 정확히 명시됩니다.\n\n이는 API와 상호 작용하는 코드를 개발하고 디버깅하는 데 매우 유용합니다.\n\n///\n\n## 문서화 { #documentation }\n\n그리고 브라우저에서 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)를 열면, 다음과 같이 자동 대화식 API 문서를 볼 수 있습니다:\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check | 확인\n\n다시 한 번, 동일한 파이썬 타입 선언만으로 **FastAPI**는 자동 대화형 문서(Swagger UI 통합)를 제공합니다.\n\n경로 매개변수가 정수형으로 선언된 것을 확인할 수 있습니다.\n\n///\n\n## 표준 기반의 이점, 대체 문서 { #standards-based-benefits-alternative-documentation }\n\n그리고 생성된 스키마는 [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md) 표준에서 나온 것이기 때문에 호환되는 도구가 많이 있습니다.\n\n이 덕분에 **FastAPI** 자체에서 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)로 접속할 수 있는 (ReDoc을 사용하는) 대체 API 문서를 제공합니다:\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\n이와 마찬가지로 다양한 언어에 대한 코드 생성 도구를 포함하여 여러 호환되는 도구가 있습니다.\n\n## Pydantic { #pydantic }\n\n모든 데이터 검증은 [Pydantic](https://docs.pydantic.dev/)에 의해 내부적으로 수행되므로 이로 인한 이점을 모두 얻을 수 있습니다. 여러분은 관리를 잘 받고 있음을 느낄 수 있습니다.\n\n`str`, `float`, `bool`, 그리고 다른 여러 복잡한 데이터 타입 선언을 할 수 있습니다.\n\n이 중 몇 가지는 자습서의 다음 장에 설명되어 있습니다.\n\n## 순서 문제 { #order-matters }\n\n*경로 처리*를 만들 때 고정 경로를 갖고 있는 상황들을 맞닥뜨릴 수 있습니다.\n\n`/users/me`처럼, 현재 사용자의 데이터를 가져온다고 합시다.\n\n사용자 ID를 이용해 특정 사용자의 정보를 가져오는 경로 `/users/{user_id}`도 있습니다.\n\n*경로 처리*는 순차적으로 평가되기 때문에 `/users/me`에 대한 경로가 `/users/{user_id}` 이전에 먼저 선언되었는지 확인해야 합니다:\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\n그렇지 않으면 `/users/{user_id}`에 대한 경로가 `/users/me`에도 매칭되어, 매개변수 `user_id`에 `\"me\"` 값이 들어왔다고 \"생각하게\" 됩니다.\n\n마찬가지로, 경로 처리를 재정의할 수는 없습니다:\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\n경로가 먼저 매칭되기 때문에 첫 번째 것이 항상 사용됩니다.\n\n## 사전정의 값 { #predefined-values }\n\n만약 *경로 매개변수*를 받는 *경로 처리*가 있지만, 가능한 유효한 *경로 매개변수* 값들을 미리 정의하고 싶다면 파이썬 표준 <abbr title=\"Enumeration - 열거형\">`Enum`</abbr>을 사용할 수 있습니다.\n\n### `Enum` 클래스 생성 { #create-an-enum-class }\n\n`Enum`을 임포트하고 `str`과 `Enum`을 상속하는 서브 클래스를 만듭니다.\n\n`str`을 상속함으로써 API 문서는 값이 `string` 형이어야 하는 것을 알게 되고 이는 문서에 제대로 표시됩니다.\n\n가능한 값들에 해당하는 고정된 값의 클래스 어트리뷰트들을 만듭니다:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip | 팁\n\n혹시 궁금하다면, \"AlexNet\", \"ResNet\", 그리고 \"LeNet\"은 그저 머신 러닝 <dfn title=\"기술적으로는 딥 러닝 모델 아키텍처\">모델</dfn>들의 이름입니다.\n\n///\n\n### *경로 매개변수* 선언 { #declare-a-path-parameter }\n\n생성한 열거형 클래스(`ModelName`)를 사용하는 타입 어노테이션으로 *경로 매개변수를* 만듭니다:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### 문서 확인 { #check-the-docs }\n\n*경로 매개변수*에 사용할 수 있는 값은 미리 정의되어 있으므로 대화형 문서에서 잘 표시됩니다:\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### 파이썬 *열거형*으로 작업하기 { #working-with-python-enumerations }\n\n*경로 매개변수*의 값은 *열거형 멤버*가 됩니다.\n\n#### *열거형 멤버* 비교 { #compare-enumeration-members }\n\n생성한 열거형 `ModelName`의 *열거형 멤버*와 비교할 수 있습니다:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### *열거형 값* 가져오기 { #get-the-enumeration-value }\n\n`model_name.value` 또는 일반적으로 `your_enum_member.value`를 이용하여 실제 값(위 예시의 경우 `str`)을 가져올 수 있습니다:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip | 팁\n\n`ModelName.lenet.value`로도 값 `\"lenet\"`에 접근할 수 있습니다.\n\n///\n\n#### *열거형 멤버* 반환 { #return-enumeration-members }\n\n*경로 처리*에서 *enum 멤버*를 반환할 수 있습니다. 이는 JSON 본문(예: `dict`) 내에 중첩된 형태로도 가능합니다.\n\n클라이언트에 반환하기 전에 해당 값(이 경우 문자열)으로 변환됩니다:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\n클라이언트는 아래와 같은 JSON 응답을 얻게 됩니다:\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## 경로를 포함하는 경로 매개변수 { #path-parameters-containing-paths }\n\n경로 `/files/{file_path}`를 가진 *경로 처리*가 있다고 해봅시다.\n\n하지만 `file_path` 자체가 `home/johndoe/myfile.txt`와 같은 *경로*를 포함해야 합니다.\n\n이때 해당 파일의 URL은 다음처럼 됩니다: `/files/home/johndoe/myfile.txt`.\n\n### OpenAPI 지원 { #openapi-support }\n\n테스트와 정의가 어려운 시나리오로 이어질 수 있으므로 OpenAPI는 *경로*를 포함하는 *경로 매개변수*를 내부에 선언하는 방법을 지원하지 않습니다.\n\n그럼에도 Starlette의 내부 도구 중 하나를 사용하여 **FastAPI**에서는 이가 가능합니다.\n\n또한 문서가 여전히 동작하긴 하지만, 매개변수에 경로가 포함되어야 한다는 내용을 추가로 문서화하지는 않습니다.\n\n### 경로 변환기 { #path-convertor }\n\nStarlette의 옵션을 직접 이용하여 다음과 같은 URL을 사용함으로써 *경로*를 포함하는 *경로 매개변수*를 선언할 수 있습니다:\n\n```\n/files/{file_path:path}\n```\n\n이러한 경우 매개변수의 이름은 `file_path`이며, 마지막 부분 `:path`는 매개변수가 어떤 *경로*와도 매칭되어야 함을 의미합니다.\n\n따라서 다음과 같이 사용할 수 있습니다:\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip | 팁\n\n매개변수가 선행 슬래시(`/`)가 있는 `/home/johndoe/myfile.txt`를 포함해야 할 수도 있습니다.\n\n그 경우 URL은: `/files//home/johndoe/myfile.txt`이며 `files`와 `home` 사이에 이중 슬래시(`//`)가 생깁니다.\n\n///\n\n## 요약 { #recap }\n\n**FastAPI**를 이용하면 짧고 직관적인 표준 파이썬 타입 선언을 사용하여 다음을 얻을 수 있습니다:\n\n* 편집기 지원: 오류 검사, 자동완성 등\n* 데이터 \"<dfn title=\"HTTP 요청에서 전달되는 문자열을 파이썬 데이터로 변환\">파싱</dfn>\"\n* 데이터 검증\n* API 주석(Annotation)과 자동 문서\n\n그리고 한 번만 선언하면 됩니다.\n\n이는 대체 프레임워크와 비교했을 때 (엄청나게 빠른 성능 외에도) **FastAPI**의 주요한 장점일 것입니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/query-param-models.md",
    "content": "# 쿼리 매개변수 모델 { #query-parameter-models }\n\n연관된 **쿼리 매개변수** 그룹이 있다면 이를 선언하기 위해 **Pydantic 모델**을 생성할 수 있습니다.\n\n이렇게 하면 **여러 곳**에서 **모델을 재사용**할 수 있을 뿐만 아니라, 매개변수에 대한 검증 및 메타데이터도 한 번에 선언할 수 있습니다. 😎\n\n/// note | 참고\n\n이 기능은 FastAPI 버전 `0.115.0`부터 지원됩니다. 🤓\n\n///\n\n## Pydantic 모델과 쿼리 매개변수 { #query-parameters-with-a-pydantic-model }\n\n필요한 **쿼리 매개변수**를 **Pydantic 모델** 안에 선언한 다음, 매개변수를 `Query`로 선언합니다:\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\n**FastAPI**는 요청의 **쿼리 매개변수**에서 **각 필드**의 데이터를 **추출**해 정의한 Pydantic 모델을 제공합니다.\n\n## 문서 확인하기 { #check-the-docs }\n\n`/docs`의 문서 UI에서 쿼리 매개변수를 확인할 수 있습니다:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## 추가 쿼리 매개변수 금지 { #forbid-extra-query-parameters }\n\n몇몇의 특이한 경우에 (흔치 않지만), 받으려는 쿼리 매개변수를 **제한**하고 싶을 수 있습니다.\n\nPydantic의 모델 설정을 사용해 어떤 `extra` 필드도 `forbid`할 수 있습니다:\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\n클라이언트가 **쿼리 매개변수**로 **추가적인** 데이터를 보내려고 하면 **에러** 응답을 받게 됩니다.\n\n예를 들어, 아래와 같이 클라이언트가 `tool` 쿼리 매개변수에 `plumbus` 값을 보내려고 하면:\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\n쿼리 매개변수 `tool`이 허용되지 않는다는 **에러** 응답을 받게 됩니다:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## 요약 { #summary }\n\n**FastAPI**에서 **쿼리 매개변수**를 선언할 때 **Pydantic 모델**을 사용할 수 있습니다. 😎\n\n/// tip | 팁\n\n스포일러 경고: Pydantic 모델을 쿠키와 헤더에도 사용할 수 있지만, 이에 대해서는 이후 튜토리얼에서 읽게 될 것입니다. 🤫\n\n///\n"
  },
  {
    "path": "docs/ko/docs/tutorial/query-params-str-validations.md",
    "content": "# 쿼리 매개변수와 문자열 검증 { #query-parameters-and-string-validations }\n\n**FastAPI**를 사용하면 매개변수에 대한 추가 정보 및 검증을 선언할 수 있습니다.\n\n이 애플리케이션을 예로 들어보겠습니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\n쿼리 매개변수 `q`는 `str | None` 자료형입니다. 즉, `str` 자료형이지만 `None` 역시 될 수 있음을 뜻하고, 실제로 기본값은 `None`이기 때문에 FastAPI는 이 매개변수가 필수가 아니라는 것을 압니다.\n\n/// note | 참고\n\nFastAPI는 `q`의 기본값이 `= None`이기 때문에 필수가 아님을 압니다.\n\n`str | None`을 사용하면 편집기가 더 나은 지원과 오류 탐지를 제공하게 해줍니다.\n\n///\n\n## 추가 검증 { #additional-validation }\n\n`q`가 선택적이지만 값이 주어질 때마다 **길이가 50자를 초과하지 않게** 강제하려 합니다.\n\n### `Query`와 `Annotated` 임포트 { #import-query-and-annotated }\n\n이를 위해 먼저 다음을 임포트합니다:\n\n* `fastapi`에서 `Query`\n* `typing`에서 `Annotated`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info | 정보\n\nFastAPI는 0.95.0 버전에서 `Annotated` 지원을 추가했고(그리고 이를 권장하기 시작했습니다).\n\n이전 버전을 사용하면 `Annotated`를 사용하려고 할 때 오류가 발생합니다.\n\n`Annotated`를 사용하기 전에 최소 0.95.1 버전으로 [FastAPI 버전 업그레이드](../deployment/versions.md#upgrading-the-fastapi-versions)를 진행하세요.\n\n///\n\n## `q` 매개변수의 타입에 `Annotated` 사용하기 { #use-annotated-in-the-type-for-the-q-parameter }\n\n이전에 [Python 타입 소개](../python-types.md#type-hints-with-metadata-annotations)에서 `Annotated`를 사용해 매개변수에 메타데이터를 추가할 수 있다고 말씀드린 것을 기억하시나요?\n\n이제 FastAPI에서 사용할 차례입니다. 🚀\n\n다음과 같은 타입 어노테이션이 있었습니다:\n\n```Python\nq: str | None = None\n```\n\n여기서 `Annotated`로 감싸서 다음과 같이 만듭니다:\n\n```Python\nq: Annotated[str | None] = None\n```\n\n두 버전 모두 같은 의미로, `q`는 `str` 또는 `None`이 될 수 있는 매개변수이며 기본값은 `None`입니다.\n\n이제 재미있는 부분으로 넘어가 봅시다. 🎉\n\n## `q` 매개변수의 `Annotated`에 `Query` 추가하기 { #add-query-to-annotated-in-the-q-parameter }\n\n이제 이 `Annotated`에 더 많은 정보를 넣을 수 있으므로(이 경우에는 추가 검증), `Annotated` 안에 `Query`를 추가하고 `max_length` 매개변수를 `50`으로 설정합니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\n기본값은 여전히 `None`이므로, 매개변수는 여전히 선택적입니다.\n\n하지만 `Annotated` 안에 `Query(max_length=50)`를 넣음으로써, 이 값에 대해 **추가 검증**을 적용하고 최대 50자까지만 허용하도록 FastAPI에 알려줍니다. 😎\n\n/// tip | 팁\n\n여기서는 **쿼리 매개변수**이기 때문에 `Query()`를 사용합니다. 나중에 `Path()`, `Body()`, `Header()`, `Cookie()`와 같이 `Query()`와 동일한 인자를 받는 것들도 보게 될 것입니다.\n\n///\n\n이제 FastAPI는 다음을 수행합니다:\n\n* 최대 길이가 50자인지 확인하도록 데이터를 **검증**합니다\n* 데이터가 유효하지 않을 때 클라이언트에게 **명확한 오류**를 보여줍니다\n* OpenAPI 스키마 *경로 처리*에 매개변수를 **문서화**합니다(따라서 **자동 문서 UI**에 표시됩니다)\n\n## 대안(이전 방식): 기본값으로 `Query` 사용 { #alternative-old-query-as-the-default-value }\n\n이전 FastAPI 버전(<dfn title=\"2023-03 이전\">0.95.0</dfn> 이전)에서는 `Annotated`에 넣는 대신, 매개변수의 기본값으로 `Query`를 사용해야 했습니다. 주변에서 이 방식을 사용하는 코드를 볼 가능성이 높기 때문에 설명해 드리겠습니다.\n\n/// tip | 팁\n\n새 코드를 작성할 때와 가능할 때는 위에서 설명한 대로 `Annotated`를 사용하세요. 여러 장점이 있고(아래에서 설명합니다) 단점은 없습니다. 🍰\n\n///\n\n다음은 함수 매개변수의 기본값으로 `Query()`를 사용하면서 `max_length`를 50으로 설정하는 방법입니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\n이 경우(`Annotated`를 사용하지 않는 경우) 함수에서 기본값 `None`을 `Query()`로 바꿔야 하므로, 이제 `Query(default=None)`로 기본값을 설정해야 합니다. (최소한 FastAPI 입장에서는) 이 인자는 해당 기본값을 정의하는 것과 같은 목적을 수행합니다.\n\n그러므로:\n\n```Python\nq: str | None = Query(default=None)\n```\n\n...위 코드는 기본값이 `None`인 선택적 매개변수를 만들며, 아래와 동일합니다:\n\n\n```Python\nq: str | None = None\n```\n\n하지만 `Query` 버전은 이것이 쿼리 매개변수임을 명시적으로 선언합니다.\n\n그 다음, `Query`로 더 많은 매개변수를 전달할 수 있습니다. 지금의 경우 문자열에 적용되는 `max_length` 매개변수입니다:\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\n이는 데이터를 검증할 것이고, 데이터가 유효하지 않다면 명백한 오류를 보여주며, OpenAPI 스키마 *경로 처리*에 매개변수를 문서화 합니다.\n\n### 기본값으로 `Query` 사용 또는 `Annotated`에 넣기 { #query-as-the-default-value-or-in-annotated }\n\n`Annotated` 안에서 `Query`를 사용할 때는 `Query`에 `default` 매개변수를 사용할 수 없다는 점을 기억하세요.\n\n대신 함수 매개변수의 실제 기본값을 사용하세요. 그렇지 않으면 일관성이 깨집니다.\n\n예를 들어, 다음은 허용되지 않습니다:\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n...왜냐하면 기본값이 `\"rick\"`인지 `\"morty\"`인지 명확하지 않기 때문입니다.\n\n따라서 (가능하면) 다음과 같이 사용합니다:\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n...또는 오래된 코드베이스에서는 다음과 같은 코드를 찾게 될 것입니다:\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### `Annotated`의 장점 { #advantages-of-annotated }\n\n함수 매개변수의 기본값 방식 대신 **`Annotated`를 사용하는 것을 권장**합니다. 여러 이유로 **더 좋기** 때문입니다. 🤓\n\n**함수 매개변수**의 **기본값**이 **실제 기본값**이 되므로, 전반적으로 Python에 더 직관적입니다. 😌\n\nFastAPI 없이도 **다른 곳에서** 같은 함수를 **호출**할 수 있고, **예상대로 동작**합니다. **필수** 매개변수(기본값이 없는 경우)가 있다면 **편집기**가 오류로 알려줄 것이고, 필수 매개변수를 전달하지 않고 실행하면 **Python**도 오류를 냅니다.\n\n`Annotated`를 사용하지 않고 **(이전) 기본값 스타일**을 사용하면, FastAPI 없이 **다른 곳에서** 함수를 호출할 때도 제대로 동작하도록 함수에 인자를 전달해야 한다는 것을 **기억**해야 합니다. 그렇지 않으면 값이 기대와 다르게 됩니다(예: `str` 대신 `QueryInfo` 같은 것). 그리고 편집기도 경고하지 않고 Python도 그 함수를 실행할 때는 불평하지 않으며, 오직 내부 동작에서 오류가 발생할 때만 문제가 드러납니다.\n\n`Annotated`는 하나 이상의 메타데이터 어노테이션을 가질 수 있기 때문에, 이제 [Typer](https://typer.tiangolo.com/) 같은 다른 도구에서도 같은 함수를 사용할 수 있습니다. 🚀\n\n## 검증 더 추가하기 { #add-more-validations }\n\n`min_length` 매개변수도 추가할 수 있습니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## 정규식 추가 { #add-regular-expressions }\n\n매개변수와 일치해야 하는 <dfn title=\"정규 표현식(regex 또는 regexp)은 문자열에 대한 검색 패턴을 정의하는 문자 시퀀스입니다.\">정규 표현식</dfn> `pattern`을 정의할 수 있습니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\n이 특정 정규표현식 패턴은 전달 받은 매개변수 값이 다음을 만족하는지 검사합니다:\n\n* `^`: 뒤따르는 문자로 시작하며, 앞에는 문자가 없습니다.\n* `fixedquery`: 정확히 `fixedquery` 값을 가집니다.\n* `$`: 여기서 끝나며, `fixedquery` 이후로 더 이상 문자가 없습니다.\n\n**\"정규 표현식\"** 개념에 대해 상실감을 느꼈다면 걱정하지 않아도 됩니다. 많은 사람에게 어려운 주제입니다. 아직은 정규 표현식 없이도 많은 작업들을 할 수 있습니다.\n\n이제 필요할 때 언제든지 **FastAPI**에서 직접 사용할 수 있다는 사실을 알게 되었습니다.\n\n## 기본값 { #default-values }\n\n물론 `None`이 아닌 다른 기본값을 사용할 수도 있습니다.\n\n`q` 쿼리 매개변수에 `min_length`를 `3`으로 설정하고, 기본값을 `\"fixedquery\"`로 선언하고 싶다고 해봅시다:\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | 참고\n\n`None`을 포함해 어떤 타입이든 기본값을 가지면 매개변수는 선택적(필수 아님)이 됩니다.\n\n///\n\n## 필수 매개변수 { #required-parameters }\n\n더 많은 검증이나 메타데이터를 선언할 필요가 없는 경우, 다음과 같이 기본값을 선언하지 않고 쿼리 매개변수 `q`를 필수로 만들 수 있습니다:\n\n```Python\nq: str\n```\n\n아래 대신:\n\n```Python\nq: str | None = None\n```\n\n하지만 이제는 예를 들어 다음과 같이 `Query`로 선언합니다:\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\n따라서 `Query`를 사용하면서 값을 필수로 선언해야 할 때는, 기본값을 선언하지 않으면 됩니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### 필수지만 `None` 가능 { #required-can-be-none }\n\n매개변수가 `None`을 허용하지만 여전히 필수라고 선언할 수 있습니다. 이렇게 하면 값이 `None`이더라도 클라이언트는 값을 반드시 전송해야 합니다.\n\n이를 위해 `None`이 유효한 타입이라고 선언하되, 기본값은 선언하지 않으면 됩니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## 쿼리 매개변수 리스트 / 다중값 { #query-parameter-list-multiple-values }\n\n`Query`로 쿼리 매개변수를 명시적으로 정의할 때 값들의 리스트를 받도록 선언할 수도 있고, 다른 말로 하면 여러 값을 받도록 선언할 수도 있습니다.\n\n예를 들어, URL에서 여러 번 나타날 수 있는 `q` 쿼리 매개변수를 선언하려면 다음과 같이 작성할 수 있습니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\n그 다음, 아래와 같은 URL로:\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\n여러 `q` *쿼리 매개변수* 값들(`foo` 및 `bar`)을 파이썬 `list`로 *경로 처리 함수*의 *함수 매개변수* `q`에서 받게 됩니다.\n\n따라서 해당 URL에 대한 응답은 다음과 같습니다:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | 팁\n\n위의 예와 같이 `list` 타입으로 쿼리 매개변수를 선언하려면 `Query`를 명시적으로 사용해야 합니다. 그렇지 않으면 요청 본문으로 해석됩니다.\n\n///\n\n대화형 API 문서는 여러 값을 허용하도록 수정 됩니다:\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### 쿼리 매개변수 리스트 / 기본값이 있는 다중값 { #query-parameter-list-multiple-values-with-defaults }\n\n제공된 값이 없으면 기본 `list` 값을 정의할 수도 있습니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\n다음으로 이동하면:\n\n```\nhttp://localhost:8000/items/\n```\n\n`q`의 기본값은 `[\"foo\", \"bar\"]`가 되고, 응답은 다음이 됩니다:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### `list`만 사용하기 { #using-just-list }\n\n`list[str]` 대신 `list`를 직접 사용할 수도 있습니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | 참고\n\n이 경우 FastAPI는 리스트의 내용을 검사하지 않음을 명심하세요.\n\n예를 들어, `list[int]`는 리스트 내용이 정수인지 검사(및 문서화)합니다. 하지만 `list` 단독일 경우는 아닙니다.\n\n///\n\n## 더 많은 메타데이터 선언 { #declare-more-metadata }\n\n매개변수에 대한 정보를 추가할 수 있습니다.\n\n해당 정보는 생성된 OpenAPI에 포함되고 문서 사용자 인터페이스 및 외부 도구에서 사용됩니다.\n\n/// note | 참고\n\n도구에 따라 OpenAPI 지원 수준이 다를 수 있음을 명심하세요.\n\n일부는 아직 선언된 추가 정보를 모두 표시하지 않을 수 있지만, 대부분의 경우 누락된 기능은 이미 개발 계획이 있습니다.\n\n///\n\n`title`을 추가할 수 있습니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\n그리고 `description`도 추가할 수 있습니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## 별칭 매개변수 { #alias-parameters }\n\n매개변수가 `item-query`이길 원한다고 가정해 봅시다.\n\n마치 다음과 같습니다:\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\n그러나 `item-query`는 유효한 파이썬 변수 이름이 아닙니다.\n\n가장 가까운 것은 `item_query`일 겁니다.\n\n하지만 정확히 `item-query`이길 원합니다...\n\n이럴 경우 `alias`를 선언할 수 있으며, 해당 별칭은 매개변수 값을 찾는 데 사용됩니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## 매개변수 사용 중단하기 { #deprecating-parameters }\n\n이제는 더 이상 이 매개변수를 마음에 들어하지 않는다고 가정해 봅시다.\n\n이 매개변수를 사용하는 클라이언트가 있기 때문에 한동안은 남겨둬야 하지만, 문서에서 <dfn title=\"구식이며, 사용하지 않기를 권장함\">사용 중단됨</dfn>으로 명확하게 보여주고 싶습니다.\n\n그렇다면 `deprecated=True` 매개변수를 `Query`로 전달합니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\n문서가 아래와 같이 보일겁니다:\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## OpenAPI에서 매개변수 제외 { #exclude-parameters-from-openapi }\n\n생성된 OpenAPI 스키마(따라서 자동 문서화 시스템)에서 쿼리 매개변수를 제외하려면 `Query`의 `include_in_schema` 매개변수를 `False`로 설정하세요:\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## 커스텀 검증 { #custom-validation }\n\n위에 나온 매개변수들로는 할 수 없는 **커스텀 검증**이 필요한 경우가 있을 수 있습니다.\n\n그런 경우에는 일반적인 검증(예: 값이 `str`인지 검증한 뒤) 이후에 적용되는 **커스텀 검증 함수**를 사용할 수 있습니다.\n\n`Annotated` 안에서 [Pydantic의 `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator)를 사용하면 이를 구현할 수 있습니다.\n\n/// tip | 팁\n\nPydantic에는 [BeforeValidator](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator)와 같은 다른 것들도 있습니다. 🤓\n\n///\n\n예를 들어, 이 커스텀 validator는 <abbr title=\"International Standard Book Number - 국제 표준 도서 번호\">ISBN</abbr> 도서 번호의 경우 아이템 ID가 `isbn-`으로 시작하고, <abbr title=\"Internet Movie Database - 인터넷 영화 데이터베이스: 영화에 대한 정보를 제공하는 웹사이트\">IMDB</abbr> 영화 URL ID의 경우 `imdb-`로 시작하는지 확인합니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info | 정보\n\n이는 Pydantic 2 이상 버전에서 사용할 수 있습니다. 😎\n\n///\n\n/// tip | 팁\n\n데이터베이스나 다른 API 같은 **외부 구성요소**와 통신이 필요한 어떤 종류의 검증이든 해야 한다면, 대신 **FastAPI Dependencies**를 사용해야 합니다. 이에 대해서는 나중에 배우게 됩니다.\n\n이 커스텀 validator는 요청에서 제공된 **같은 데이터만**으로 확인할 수 있는 것들을 위한 것입니다.\n\n///\n\n### 코드 이해하기 { #understand-that-code }\n\n중요한 부분은 **`Annotated` 안에서 함수와 함께 `AfterValidator`를 사용한다는 것**뿐입니다. 이 부분은 건너뛰셔도 됩니다. 🤸\n\n---\n\n하지만 이 특정 코드 예제가 궁금하고 계속 보고 싶다면, 추가 세부사항은 다음과 같습니다.\n\n#### `value.startswith()`를 사용한 문자열 { #string-with-value-startswith }\n\n알고 계셨나요? `value.startswith()`를 사용하는 문자열은 튜플을 받을 수 있으며, 튜플에 있는 각 값을 확인합니다:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### 임의의 항목 { #a-random-item }\n\n`data.items()`를 사용하면 각 딕셔너리 항목의 키와 값을 담은 튜플로 구성된 <dfn title=\"리스트, 세트 등처럼 for 루프로 순회할 수 있는 것\">이터러블 객체</dfn>를 얻습니다.\n\n이 이터러블 객체를 `list(data.items())`로 적절한 `list`로 변환합니다.\n\n그 다음 `random.choice()`로 리스트에서 **무작위 값**을 얻어 `(id, name)` 형태의 튜플을 얻습니다. 예를 들어 `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")` 같은 값이 될 것입니다.\n\n그 다음 이 튜플의 **두 값을** 변수 `id`와 `name`에 **할당**합니다.\n\n따라서 사용자가 아이템 ID를 제공하지 않더라도, 무작위 추천을 받게 됩니다.\n\n...이 모든 것을 **단 하나의 간단한 줄**로 합니다. 🤯 Python 정말 좋지 않나요? 🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## 요약 { #recap }\n\n매개변수에 검증과 메타데이터를 추가 선언할 수 있습니다.\n\n제네릭 검증과 메타데이터:\n\n* `alias`\n* `title`\n* `description`\n* `deprecated`\n\n문자열에 특화된 검증:\n\n* `min_length`\n* `max_length`\n* `pattern`\n\n`AfterValidator`를 사용하는 커스텀 검증.\n\n예제에서 `str` 값의 검증을 어떻게 추가하는지 살펴보았습니다.\n\n숫자와 같은 다른 타입에 대한 검증을 어떻게 선언하는지 확인하려면 다음 장을 확인하기 바랍니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/query-params.md",
    "content": "# 쿼리 매개변수 { #query-parameters }\n\n경로 매개변수의 일부가 아닌 다른 함수 매개변수를 선언하면 \"쿼리\" 매개변수로 자동 해석합니다.\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\n쿼리는 URL에서 `?` 후에 나오고 `&`으로 구분되는 키-값 쌍의 집합입니다.\n\n예를 들어, 아래 URL에서:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n...쿼리 매개변수는:\n\n* `skip`: 값 `0`을 가집니다.\n* `limit`: 값 `10`을 가집니다.\n\nURL의 일부이므로 \"자연스럽게\" 문자열입니다.\n\n하지만 파이썬 타입과 함께 선언할 경우(위 예에서 `int`), 해당 타입으로 변환 및 검증됩니다.\n\n경로 매개변수에 적용된 동일한 프로세스가 쿼리 매개변수에도 적용됩니다:\n\n* (당연히) 편집기 지원\n* 데이터 <dfn title=\"HTTP 요청에서 온 문자열을 Python 데이터로 변환하는 것\">\"파싱\"</dfn>\n* 데이터 검증\n* 자동 문서화\n\n## 기본값 { #defaults }\n\n쿼리 매개변수는 경로에서 고정된 부분이 아니기 때문에 선택적일 수 있고 기본값을 가질 수 있습니다.\n\n위 예에서 `skip=0`과 `limit=10`은 기본값을 갖고 있습니다.\n\n그러므로 URL로 이동하는 것은:\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\n아래로 이동하는 것과 같습니다:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n하지만 가령 아래로 이동한 경우:\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\n함수의 매개변수 값은 아래가 됩니다:\n\n* `skip=20`: URL에서 지정했기 때문입니다\n* `limit=10`: 기본값이기 때문입니다\n\n## 선택적 매개변수 { #optional-parameters }\n\n같은 방법으로 기본값을 `None`으로 설정하여 선택적 매개변수를 선언할 수 있습니다:\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\n이 경우 함수 매개변수 `q`는 선택적이며 기본값으로 `None` 값이 됩니다.\n\n/// check\n\n또한 **FastAPI**는 `item_id`가 경로 매개변수이고 `q`는 경로 매개변수가 아니라서 쿼리 매개변수라는 것을 알 정도로 충분히 똑똑하다는 점도 확인하세요.\n\n///\n\n## 쿼리 매개변수 형변환 { #query-parameter-type-conversion }\n\n`bool` 형으로 선언할 수도 있고, 아래처럼 변환됩니다:\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\n이 경우, 아래로 이동하면:\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\n또는\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\n또는\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\n또는\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\n또는\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\n또는 다른 어떤 변형(대문자, 첫글자만 대문자 등)이더라도 함수는 `bool` 값이 `True`인 매개변수 `short`를 보게 됩니다. 그렇지 않은 경우 `False`입니다.\n\n\n## 여러 경로/쿼리 매개변수 { #multiple-path-and-query-parameters }\n\n여러 경로 매개변수와 쿼리 매개변수를 동시에 선언할 수 있으며 **FastAPI**는 어느 것이 무엇인지 알고 있습니다.\n\n그리고 특정 순서로 선언할 필요가 없습니다.\n\n매개변수들은 이름으로 감지됩니다:\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## 필수 쿼리 매개변수 { #required-query-parameters }\n\n경로가 아닌 매개변수에 대한 기본값을 선언할 때(지금은 쿼리 매개변수만 보았습니다), 해당 매개변수는 필수적(Required)이지 않았습니다.\n\n특정값을 추가하지 않고 선택적으로 만들기 위해선 기본값을 `None`으로 설정하면 됩니다.\n\n그러나 쿼리 매개변수를 필수로 만들려면 단순히 기본값을 선언하지 않으면 됩니다:\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\n여기 쿼리 매개변수 `needy`는 `str`형인 필수 쿼리 매개변수입니다.\n\n브라우저에서 아래와 같은 URL을 연다면:\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n...필수 매개변수 `needy`를 넣지 않았기 때문에 아래와 같은 오류를 보게 됩니다:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\n`needy`는 필수 매개변수이므로 URL에 반드시 설정해줘야 합니다:\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n...아래처럼 작동합니다:\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\n그리고 물론, 일부 매개변수는 필수로, 다른 일부는 기본값을, 또 다른 일부는 선택적으로 선언할 수 있습니다:\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\n위 예시에서는 3가지 쿼리 매개변수가 있습니다:\n\n* `needy`, 필수적인 `str`.\n* `skip`, 기본값이 `0`인 `int`.\n* `limit`, 선택적인 `int`.\n\n/// tip\n\n[경로 매개변수](path-params.md#predefined-values)와 마찬가지로 `Enum`을 사용할 수 있습니다.\n\n///\n"
  },
  {
    "path": "docs/ko/docs/tutorial/request-files.md",
    "content": "# 파일 요청 { #request-files }\n\n`File`을 사용하여 클라이언트가 업로드할 파일들을 정의할 수 있습니다.\n\n/// info | 정보\n\n업로드된 파일을 전달받기 위해 먼저 [`python-multipart`](https://github.com/Kludex/python-multipart)를 설치해야합니다.\n\n[가상 환경](../virtual-environments.md)을 생성하고, 활성화한 다음, 예를 들어 다음과 같이 설치하세요:\n\n```console\n$ pip install python-multipart\n```\n\n업로드된 파일들은 \"폼 데이터\"의 형태로 전송되기 때문에 이 작업이 필요합니다.\n\n///\n\n## `File` 임포트 { #import-file }\n\n`fastapi` 에서 `File` 과 `UploadFile` 을 임포트 합니다:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## `File` 매개변수 정의 { #define-file-parameters }\n\n`Body` 및 `Form` 과 동일한 방식으로 파일의 매개변수를 생성합니다:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info | 정보\n\n`File` 은 `Form` 으로부터 직접 상속된 클래스입니다.\n\n하지만 `fastapi`로부터 `Query`, `Path`, `File` 등을 임포트 할 때, 이것들은 특별한 클래스들을 반환하는 함수라는 것을 기억하기 바랍니다.\n\n///\n\n/// tip | 팁\n\nFile의 본문을 선언할 때, 매개변수가 쿼리 매개변수 또는 본문(JSON) 매개변수로 해석되는  것을 방지하기 위해 `File` 을 사용해야합니다.\n\n///\n\n파일들은 \"폼 데이터\"의 형태로 업로드 됩니다.\n\n*경로 처리 함수*의 매개변수를 `bytes` 로 선언하는 경우 **FastAPI**는 파일을 읽고 `bytes` 형태의 내용을 전달합니다.\n\n이것은 전체 내용이 메모리에 저장된다는 것을 의미한다는 걸 염두하기 바랍니다. 이는 작은 크기의 파일들에 적합합니다.\n\n어떤 경우에는 `UploadFile` 을 사용하는 것이 더 유리합니다.\n\n## `UploadFile`을 사용하는 `File` 매개변수 { #file-parameters-with-uploadfile }\n\n`File` 매개변수를 `UploadFile` 타입으로 정의합니다:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\n`UploadFile` 을 사용하는 것은 `bytes` 과 비교해 다음과 같은 장점이 있습니다:\n\n* 매개변수의 기본값에서 `File()`을 사용할 필요가 없습니다.\n* \"스풀 파일\"을 사용합니다.\n    *  최대 크기 제한까지만 메모리에 저장되며, 이를 초과하는 경우 디스크에 저장됩니다.\n* 따라서 이미지, 동영상, 큰 이진코드와 같은 대용량 파일들을 많은 메모리를 소모하지 않고 처리하기에 적합합니다.\n* 업로드 된 파일의 메타데이터를 얻을 수 있습니다.\n* [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) `async` 인터페이스를 갖고 있습니다.\n* file-like object를 필요로하는 다른 라이브러리에 직접적으로 전달할 수 있는 파이썬 [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) 객체를 반환합니다.\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` 은 다음과 같은 어트리뷰트가 있습니다:\n\n* `filename` : 문자열(`str`)로 된 업로드된 파일의 파일명입니다 (예: `myimage.jpg`).\n* `content_type` : 문자열(`str`)로 된 파일 형식(MIME type / media type)입니다 (예: `image/jpeg`).\n* `file` :  [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (a [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) object)입니다. 이것은 \"file-like\" 객체를 필요로하는 다른 함수나 라이브러리에 직접적으로 전달할 수 있는 실질적인 파이썬 파일 객체입니다.\n\n`UploadFile` 에는 다음의 `async` 메소드들이 있습니다. 이들은 내부적인 `SpooledTemporaryFile` 을 사용하여 해당하는 파일 메소드를 호출합니다.\n\n* `write(data)`: `data`(`str` 또는 `bytes`)를 파일에 작성합니다.\n* `read(size)`: 파일의 바이트 및 글자의 `size`(`int`)를 읽습니다.\n* `seek(offset)`: 파일 내 `offset`(`int`) 위치의 바이트로 이동합니다.\n    * 예) `await myfile.seek(0)` 를 사용하면 파일의 시작부분으로 이동합니다.\n    * `await myfile.read()` 를 사용한 후 내용을 다시 읽을 때 유용합니다.\n* `close()`: 파일을 닫습니다.\n\n상기 모든 메소드들이 `async` 메소드이기 때문에 “await”을 사용하여야 합니다.\n\n예를들어, `async` *경로 처리 함수*의 내부에서 다음과 같은 방식으로 내용을 가져올 수 있습니다:\n\n```Python\ncontents = await myfile.read()\n```\n\n만약 일반적인 `def` *경로 처리 함수*의 내부라면, 다음과 같이 `UploadFile.file` 에 직접 접근할 수 있습니다:\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | `async` 기술 세부사항\n\n`async` 메소드들을 사용할 때 **FastAPI**는 스레드풀에서 파일 메소드들을 실행하고 그들을 기다립니다.\n\n///\n\n/// note | Starlette 기술 세부사항\n\n**FastAPI**의 `UploadFile` 은 **Starlette**의 `UploadFile` 을 직접적으로 상속받지만, **Pydantic** 및 FastAPI의 다른 부분들과의 호환성을 위해 필요한 부분들이 추가되었습니다.\n\n///\n\n## \"폼 데이터\"란 { #what-is-form-data }\n\nHTML의 폼들(`<form></form>`)이 서버에 데이터를 전송하는 방식은 대개 데이터에 JSON과는 다른 \"특별한\" 인코딩을 사용합니다.\n\n**FastAPI**는 JSON 대신 올바른 위치에서 데이터를 읽을 수 있도록 합니다.\n\n/// note | 기술 세부사항\n\n폼의 데이터는 파일이 포함되지 않은 경우 일반적으로 \"미디어 유형\" `application/x-www-form-urlencoded` 을 사용해 인코딩 됩니다.\n\n하지만 파일이 포함된 경우, `multipart/form-data`로 인코딩됩니다. `File`을 사용하였다면, **FastAPI**는 본문의 적합한 부분에서 파일을 가져와야 한다는 것을 인지합니다.\n\n인코딩과 폼 필드에 대해 더 알고싶다면, [<abbr title=\"Mozilla Developer Network - 모질라 개발자 네트워크\">MDN</abbr> 웹 문서의 `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)를 참고하기 바랍니다.\n\n///\n\n/// warning | 경고\n\n다수의 `File` 과 `Form` 매개변수를 한 *경로 처리*에 선언하는 것이 가능하지만, 요청의 본문이 `application/json` 가 아닌 `multipart/form-data` 로 인코딩 되기 때문에 JSON으로 받아야하는 `Body` 필드를 함께 선언할 수는 없습니다.\n\n이는 **FastAPI**의 한계가 아니라, HTTP 프로토콜에 의한 것입니다.\n\n///\n\n## 선택적 파일 업로드 { #optional-file-upload }\n\n표준 타입 애너테이션을 사용하고 기본값을 `None`으로 설정하여 파일을 선택적으로 만들 수 있습니다:\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## 추가 메타데이터를 포함한 `UploadFile` { #uploadfile-with-additional-metadata }\n\n추가 메타데이터를 설정하기 위해 예를 들어 `UploadFile`과 함께 `File()`을 사용할 수도 있습니다:\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## 다중 파일 업로드 { #multiple-file-uploads }\n\n여러 파일을 동시에 업로드 할 수 있습니다.\n\n그들은 \"폼 데이터\"를 사용하여 전송된 동일한 \"폼 필드\"에 연결됩니다.\n\n이 기능을 사용하기 위해 , `bytes` 의 `List` 또는 `UploadFile` 를 선언하기 바랍니다:\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\n선언한대로, `bytes` 의 `list` 또는 `UploadFile` 들을 전송받을 것입니다.\n\n/// note | 기술 세부사항\n\n`from starlette.responses import HTMLResponse` 역시 사용할  수 있습니다.\n\n**FastAPI**는 개발자의 편의를 위해 `fastapi.responses` 와 동일한 `starlette.responses` 도 제공합니다. 하지만 대부분의 응답들은 Starlette로부터 직접 제공됩니다.\n\n///\n\n### 추가 메타데이터를 포함한 다중 파일 업로드 { #multiple-file-uploads-with-additional-metadata }\n\n이전과 같은 방식으로 `UploadFile`에 대해서도 `File()`을 사용해 추가 매개변수를 설정할 수 있습니다:\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## 요약 { #recap }\n\n`File`, `bytes`, `UploadFile`을 사용하여 폼 데이터로 전송되는 요청에서 업로드할 파일을 선언하세요.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/request-form-models.md",
    "content": "# 폼 모델 { #form-models }\n\nFastAPI에서 **Pydantic 모델**을 이용하여 **폼 필드**를 선언할 수 있습니다.\n\n/// info | 정보\n\n폼을 사용하려면, 먼저 [`python-multipart`](https://github.com/Kludex/python-multipart)를 설치하세요.\n\n[가상 환경](../virtual-environments.md)을 생성하고 활성화한 다음, 예를 들어 아래와 같이 설치하세요:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note | 참고\n\n이 기능은 FastAPI 버전 `0.113.0` 이후부터 지원됩니다. 🤓\n\n///\n\n## 폼을 위한 Pydantic 모델 { #pydantic-models-for-forms }\n\n**폼 필드**로 받고 싶은 필드를 **Pydantic 모델**로 선언한 다음, 매개변수를 `Form`으로 선언하면 됩니다:\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI**는 요청에서 받은 **폼 데이터**에서 **각 필드**에 대한 데이터를 **추출**하고 정의한 Pydantic 모델을 줍니다.\n\n## 문서 확인하기 { #check-the-docs }\n\n문서 UI `/docs`에서 확인할 수 있습니다:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## 추가 폼 필드 금지하기 { #forbid-extra-form-fields }\n\n일부 특별한 사용 사례(아마도 흔하지는 않겠지만)에서는 Pydantic 모델에서 선언된 폼 필드로만 **제한**하길 원할 수도 있습니다. 그리고 **추가** 필드를 **금지**할 수도 있습니다.\n\n/// note | 참고\n\n이 기능은 FastAPI 버전 `0.114.0` 이후부터 지원됩니다. 🤓\n\n///\n\nPydantic의 모델 구성을 사용하여 `extra` 필드를 `forbid`할 수 있습니다:\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\n클라이언트가 추가 데이터를 보내려고 하면 **오류** 응답을 받게 됩니다.\n\n예를 들어, 클라이언트가 폼 필드를 보내려고 하면:\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\n`extra` 필드가 허용되지 않는다는 오류 응답을 받게 됩니다:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## 요약 { #summary }\n\nPydantic 모델을 사용하여 FastAPI에서 폼 필드를 선언할 수 있습니다. 😎\n"
  },
  {
    "path": "docs/ko/docs/tutorial/request-forms-and-files.md",
    "content": "# 폼 및 파일 요청 { #request-forms-and-files }\n\n`File` 과 `Form` 을 사용하여 파일과 폼 필드를 동시에 정의할 수 있습니다.\n\n/// info\n\n업로드된 파일 및/또는 폼 데이터를 받으려면 먼저 [`python-multipart`](https://github.com/Kludex/python-multipart)를 설치해야 합니다.\n\n[가상 환경](../virtual-environments.md)을 생성하고, 활성화한 다음 설치해야 합니다. 예:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## `File` 및 `Form` 임포트 { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## `File` 및 `Form` 매개변수 정의 { #define-file-and-form-parameters }\n\n`Body` 및 `Query`와 동일한 방식으로 파일과 폼의 매개변수를 생성합니다:\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\n파일과 폼 필드는 폼 데이터로 업로드되며, 파일과 폼 필드를 받게 됩니다.\n\n또한 일부 파일은 `bytes`로, 일부 파일은 `UploadFile`로 선언할 수 있습니다.\n\n/// warning\n\n다수의 `File`과 `Form` 매개변수를 한 *경로 처리*에 선언하는 것이 가능하지만, 요청의 본문이 `application/json`가 아닌 `multipart/form-data`로 인코딩되기 때문에 JSON으로 받기를 기대하는 `Body` 필드를 함께 선언할 수는 없습니다.\n\n이는 **FastAPI**의 한계가 아니라, HTTP 프로토콜의 일부입니다.\n\n///\n\n## 요약 { #recap }\n\n하나의 요청으로 데이터와 파일들을 받아야 할 경우 `File`과 `Form`을 함께 사용하기 바랍니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/request-forms.md",
    "content": "# 폼 데이터 { #form-data }\n\nJSON 대신 폼 필드를 받아야 하는 경우 `Form`을 사용할 수 있습니다.\n\n/// info | 정보\n\n폼을 사용하려면, 먼저 [`python-multipart`](https://github.com/Kludex/python-multipart)를 설치하세요.\n\n[가상 환경](../virtual-environments.md)을 생성하고 활성화한 다음, 예를 들어 다음과 같이 설치하세요:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## `Form` 임포트하기 { #import-form }\n\n`fastapi`에서 `Form`을 임포트합니다:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## `Form` 매개변수 정의하기 { #define-form-parameters }\n\n`Body` 또는 `Query`와 동일한 방식으로 폼 매개변수를 만듭니다:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\n예를 들어, OAuth2 사양을 사용할 수 있는 방법 중 하나(\"패스워드 플로우\"라고 함)로 `username`과 `password`를 폼 필드로 보내야 합니다.\n\n<dfn title=\"사양\">사양</dfn>에서는 필드 이름이 `username` 및 `password`로 정확하게 명명되어야 하고, JSON이 아닌 폼 필드로 전송해야 합니다.\n\n`Form`을 사용하면 유효성 검사, 예제, 별칭(예: `username` 대신 `user-name`) 등을 포함하여 `Body`(및 `Query`, `Path`, `Cookie`)와 동일한 구성을 선언할 수 있습니다.\n\n/// info | 정보\n\n`Form`은 `Body`에서 직접 상속되는 클래스입니다.\n\n///\n\n/// tip | 팁\n\n폼 본문을 선언할 때는 `Form`을 명시적으로 사용해야 합니다. 그렇지 않으면 매개변수가 쿼리 매개변수나 본문(JSON) 매개변수로 해석됩니다.\n\n///\n\n## \"폼 필드\"에 대해 { #about-form-fields }\n\nHTML 폼(`<form></form>`)이 데이터를 서버로 보내는 방식은 일반적으로 해당 데이터에 대해 \"특수\" 인코딩을 사용하며, 이는 JSON과 다릅니다.\n\n**FastAPI**는 JSON 대신 올바른 위치에서 해당 데이터를 읽습니다.\n\n/// note | 기술 세부사항\n\n폼의 데이터는 일반적으로 \"미디어 유형(media type)\" `application/x-www-form-urlencoded`를 사용하여 인코딩합니다.\n\n그러나 폼에 파일이 포함된 경우, `multipart/form-data`로 인코딩합니다. 다음 장에서 파일 처리에 대해 읽을 겁니다.\n\n이러한 인코딩 및 폼 필드에 대해 더 읽고 싶다면, [`POST`에 대한 <abbr title=\"Mozilla Developer Network - Mozilla 개발자 네트워크\">MDN</abbr> 웹 문서를 참조하세요](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | 경고\n\n*경로 처리*에서 여러 `Form` 매개변수를 선언할 수 있지만, JSON으로 수신할 것으로 예상되는 `Body` 필드와 함께 선언할 수 없습니다. 요청 본문은 `application/json` 대신에 `application/x-www-form-urlencoded`를 사용하여 인코딩되기 때문입니다.\n\n이는 **FastAPI**의 제한 사항이 아니며 HTTP 프로토콜의 일부입니다.\n\n///\n\n## 요약 { #recap }\n\n폼 데이터 입력 매개변수를 선언하려면 `Form`을 사용하세요.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/response-model.md",
    "content": "# 응답 모델 - 반환 타입 { #response-model-return-type }\n\n*경로 처리 함수*의 **반환 타입**을 어노테이션하여 응답에 사용될 타입을 선언할 수 있습니다.\n\n함수 **매개변수**에서 입력 데이터를 위해 사용하는 것과 동일하게 **타입 어노테이션**을 사용할 수 있으며, Pydantic 모델, 리스트, 딕셔너리, 정수/불리언 같은 스칼라 값 등을 사용할 수 있습니다.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPI는 이 반환 타입을 사용하여:\n\n* 반환된 데이터를 **검증**합니다.\n    * 데이터가 유효하지 않다면(예: 필드가 누락된 경우), 이는 *여러분의* 앱 코드가 깨져서 의도한 값을 반환하지 못한다는 의미이며, 잘못된 데이터를 반환하는 대신 서버 오류를 반환합니다. 이렇게 하면 여러분과 클라이언트는 기대한 데이터와 데이터 형태를 받는다는 것을 확실히 할 수 있습니다.\n* OpenAPI *경로 처리*의 응답에 **JSON Schema**를 추가합니다.\n    * 이는 **자동 문서**에서 사용됩니다.\n    * 또한 자동 클라이언트 코드 생성 도구에서도 사용됩니다.\n* 반환된 데이터를 Pydantic을 사용해 JSON으로 **직렬화**합니다. Pydantic은 **Rust**로 작성되어 있어 **훨씬 더 빠릅니다**.\n\n하지만 가장 중요한 것은:\n\n* 반환 타입에 정의된 내용으로 출력 데이터를 **제한하고 필터링**합니다.\n    * 이는 특히 **보안**에 매우 중요합니다. 아래에서 더 자세히 살펴보겠습니다.\n\n## `response_model` 매개변수 { #response-model-parameter }\n\n타입 선언이 말하는 것과 정확히 일치하지 않는 데이터를 반환해야 하거나 반환하고 싶은 경우가 있습니다.\n\n예를 들어, **딕셔너리**나 데이터베이스 객체를 **반환**하고 싶지만, **Pydantic 모델로 선언**하고 싶을 수 있습니다. 이렇게 하면 Pydantic 모델이 반환한 객체(예: 딕셔너리나 데이터베이스 객체)에 대해 데이터 문서화, 검증 등 모든 작업을 수행합니다.\n\n반환 타입 어노테이션을 추가했다면, 도구와 에디터가 함수가 선언한 타입(예: Pydantic 모델)과 다른 타입(예: dict)을 반환하고 있다는 (올바른) 오류로 불평할 것입니다.\n\n그런 경우에는 반환 타입 대신 *경로 처리 데코레이터*의 매개변수 `response_model`을 사용할 수 있습니다.\n\n`response_model` 매개변수는 모든 *경로 처리*에서 사용할 수 있습니다:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* 등.\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | 참고\n\n`response_model`은 \"데코레이터\" 메서드(`get`, `post` 등)의 매개변수입니다. 모든 매개변수와 body처럼, *경로 처리 함수*의 매개변수가 아닙니다.\n\n///\n\n`response_model`은 Pydantic 모델 필드에 선언하는 것과 동일한 타입을 받습니다. 따라서 Pydantic 모델이 될 수도 있고, `List[Item]`처럼 Pydantic 모델의 `list`가 될 수도 있습니다.\n\nFastAPI는 이 `response_model`을 사용해 데이터 문서화, 검증 등을 수행하고, 또한 출력 데이터를 타입 선언에 맞게 **변환하고 필터링**합니다.\n\n/// tip | 팁\n\n에디터, mypy 등에서 엄격한 타입 체크를 사용하고 있다면, 함수 반환 타입을 `Any`로 선언할 수 있습니다.\n\n이렇게 하면 에디터에 의도적으로 어떤 값이든 반환한다고 알려줍니다. 하지만 FastAPI는 여전히 `response_model`을 사용하여 데이터 문서화, 검증, 필터링 등을 수행합니다.\n\n///\n\n### `response_model` 우선순위 { #response-model-priority }\n\n반환 타입과 `response_model`을 둘 다 선언하면, `response_model`이 우선순위를 가지며 FastAPI에서 사용됩니다.\n\n이렇게 하면 응답 모델과 다른 타입을 반환하는 경우에도 에디터와 mypy 같은 도구에서 사용할 올바른 타입 어노테이션을 함수에 추가할 수 있습니다. 그리고 동시에 FastAPI가 `response_model`을 사용하여 데이터 검증, 문서화 등을 수행하게 할 수도 있습니다.\n\n또한 `response_model=None`을 사용해 해당 *경로 처리*에 대한 응답 모델 생성을 비활성화할 수도 있습니다. 이는 유효한 Pydantic 필드가 아닌 것들에 대해 타입 어노테이션을 추가하는 경우에 필요할 수 있으며, 아래 섹션 중 하나에서 예시를 볼 수 있습니다.\n\n## 동일한 입력 데이터 반환 { #return-the-same-input-data }\n\n여기서는 평문 비밀번호를 포함하는 `UserIn` 모델을 선언합니다:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | 정보\n\n`EmailStr`을 사용하려면 먼저 [`email-validator`](https://github.com/JoshData/python-email-validator)를 설치하세요.\n\n[가상 환경](../virtual-environments.md)을 생성하고, 활성화한 다음 설치해야 합니다. 예를 들어:\n\n```console\n$ pip install email-validator\n```\n\n또는 다음과 같이:\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\n그리고 이 모델을 사용하여 입력을 선언하고 같은 모델로 출력을 선언합니다:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\n이제 브라우저가 비밀번호로 사용자를 만들 때마다 API는 응답으로 동일한 비밀번호를 반환합니다.\n\n이 경우, 동일한 사용자가 비밀번호를 보내는 것이므로 문제가 되지 않을 수도 있습니다.\n\n하지만 동일한 모델을 다른 *경로 처리*에서 사용하면, 모든 클라이언트에게 사용자의 비밀번호를 보내게 될 수도 있습니다.\n\n/// danger | 위험\n\n모든 주의사항을 알고 있으며 무엇을 하는지 정확히 알고 있지 않다면, 이런 방식으로 사용자의 평문 비밀번호를 저장하거나 응답으로 보내지 마세요.\n\n///\n\n## 출력 모델 추가 { #add-an-output-model }\n\n대신 평문 비밀번호를 포함하는 입력 모델과, 비밀번호가 없는 출력 모델을 만들 수 있습니다:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\n여기서 *경로 처리 함수*가 비밀번호를 포함하는 동일한 입력 사용자를 반환하더라도:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n...비밀번호를 포함하지 않는 `UserOut` 모델로 `response_model`을 선언했습니다:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\n따라서 **FastAPI**는 출력 모델에 선언되지 않은 모든 데이터를 (Pydantic을 사용하여) 필터링합니다.\n\n### `response_model` 또는 반환 타입 { #response-model-or-return-type }\n\n이 경우 두 모델이 서로 다르기 때문에, 함수 반환 타입을 `UserOut`으로 어노테이션하면 에디터와 도구는 서로 다른 클래스인데 잘못된 타입을 반환하고 있다고 불평할 것입니다.\n\n그래서 이 예제에서는 `response_model` 매개변수로 선언해야 합니다.\n\n...하지만 아래를 계속 읽으면 이를 극복하는 방법을 볼 수 있습니다.\n\n## 반환 타입과 데이터 필터링 { #return-type-and-data-filtering }\n\n이전 예제에서 계속해 봅시다. 함수에 **하나의 타입으로 어노테이션**을 하고 싶지만, 함수에서 실제로는 **더 많은 데이터**를 포함하는 것을 반환할 수 있길 원했습니다.\n\nFastAPI가 응답 모델을 사용해 데이터를 계속 **필터링**하길 원합니다. 그래서 함수가 더 많은 데이터를 반환하더라도, 응답에는 응답 모델에 선언된 필드만 포함되게 합니다.\n\n이전 예제에서는 클래스가 달랐기 때문에 `response_model` 매개변수를 써야 했습니다. 하지만 이는 에디터와 도구가 함수 반환 타입을 체크해 주는 지원을 받지 못한다는 뜻이기도 합니다.\n\n하지만 대부분 이런 작업이 필요한 경우에는, 이 예제처럼 모델로 일부 데이터를 **필터링/제거**하길 원하는 경우가 많습니다.\n\n그리고 그런 경우에는 클래스와 상속을 사용하여 함수 **타입 어노테이션**을 활용해 에디터/도구에서 더 나은 지원을 받으면서도 FastAPI의 **데이터 필터링**을 유지할 수 있습니다.\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\n이를 통해 이 코드는 타입 관점에서 올바르므로 에디터와 mypy 등의 도구 지원을 받을 수 있고, 동시에 FastAPI의 데이터 필터링도 받을 수 있습니다.\n\n이게 어떻게 동작할까요? 확인해 봅시다. 🤓\n\n### 타입 어노테이션과 도구 지원 { #type-annotations-and-tooling }\n\n먼저 에디터, mypy 및 기타 도구가 이를 어떻게 보는지 살펴봅시다.\n\n`BaseUser`는 기본 필드를 가집니다. 그리고 `UserIn`은 `BaseUser`를 상속하고 `password` 필드를 추가하므로, 두 모델의 모든 필드를 포함하게 됩니다.\n\n함수 반환 타입을 `BaseUser`로 어노테이션하지만, 실제로는 `UserIn` 인스턴스를 반환합니다.\n\n에디터, mypy 및 기타 도구는 이에 대해 불평하지 않습니다. 타이핑 관점에서 `UserIn`은 `BaseUser`의 서브클래스이므로, `BaseUser`인 어떤 것이 기대되는 곳에서는 *유효한* 타입이기 때문입니다.\n\n### FastAPI 데이터 필터링 { #fastapi-data-filtering }\n\n이제 FastAPI는 반환 타입을 보고, 여러분이 반환하는 값이 해당 타입에 선언된 필드 **만** 포함하도록 보장합니다.\n\nFastAPI는 Pydantic을 내부적으로 여러 방식으로 사용하여, 클래스 상속의 동일한 규칙이 반환 데이터 필터링에는 적용되지 않도록 합니다. 그렇지 않으면 기대한 것보다 훨씬 더 많은 데이터를 반환하게 될 수도 있습니다.\n\n이렇게 하면 **도구 지원**이 있는 타입 어노테이션과 **데이터 필터링**이라는 두 가지 장점을 모두 얻을 수 있습니다.\n\n## 문서에서 보기 { #see-it-in-the-docs }\n\n자동 생성 문서를 보면 입력 모델과 출력 모델이 각자의 JSON Schema를 가지고 있음을 확인할 수 있습니다:\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\n그리고 두 모델 모두 대화형 API 문서에 사용됩니다:\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## 기타 반환 타입 어노테이션 { #other-return-type-annotations }\n\n유효한 Pydantic 필드가 아닌 것을 반환하면서도, 도구(에디터, mypy 등)가 제공하는 지원을 받기 위해 함수에 어노테이션을 달아두는 경우가 있을 수 있습니다.\n\n### 응답을 직접 반환하기 { #return-a-response-directly }\n\n가장 흔한 경우는 [고급 문서에서 나중에 설명하는 대로 Response를 직접 반환하는 것](../advanced/response-directly.md)입니다.\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\n이 간단한 경우는 반환 타입 어노테이션이 `Response` 클래스(또는 그 서브클래스)이기 때문에 FastAPI에서 자동으로 처리됩니다.\n\n그리고 `RedirectResponse`와 `JSONResponse`는 모두 `Response`의 서브클래스이므로, 타입 어노테이션이 올바르기 때문에 도구들도 만족합니다.\n\n### Response 서브클래스 어노테이션 { #annotate-a-response-subclass }\n\n타입 어노테이션에 `Response`의 서브클래스를 사용할 수도 있습니다:\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\n이는 `RedirectResponse`가 `Response`의 서브클래스이기 때문에 동작하며, FastAPI가 이 간단한 경우를 자동으로 처리합니다.\n\n### 유효하지 않은 반환 타입 어노테이션 { #invalid-return-type-annotations }\n\n하지만 유효한 Pydantic 타입이 아닌 다른 임의의 객체(예: 데이터베이스 객체)를 반환하고, 함수에서 그렇게 어노테이션하면, FastAPI는 그 타입 어노테이션으로부터 Pydantic 응답 모델을 만들려고 시도하다가 실패합니다.\n\n또한, 유효한 Pydantic 타입이 아닌 타입이 하나 이상 포함된 여러 타입 간의 <dfn title=\"여러 타입 간의 union은 '이 타입들 중 아무거나'를 의미합니다.\">union</dfn>이 있는 경우에도 동일합니다. 예를 들어, 아래는 실패합니다 💥:\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n...이는 타입 어노테이션이 Pydantic 타입이 아니고, 단일 `Response` 클래스/서브클래스도 아니며, `Response`와 `dict` 간 union(둘 중 아무거나)이기 때문에 실패합니다.\n\n### 응답 모델 비활성화 { #disable-response-model }\n\n위 예제에서 이어서, FastAPI가 수행하는 기본 데이터 검증, 문서화, 필터링 등을 원하지 않을 수 있습니다.\n\n하지만 에디터나 타입 체커(예: mypy) 같은 도구 지원을 받기 위해 함수에 반환 타입 어노테이션은 유지하고 싶을 수도 있습니다.\n\n이 경우 `response_model=None`으로 설정하여 응답 모델 생성을 비활성화할 수 있습니다:\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\n그러면 FastAPI는 응답 모델 생성을 건너뛰며, FastAPI 애플리케이션에 영향을 주지 않고 필요한 반환 타입 어노테이션을 어떤 것이든 사용할 수 있습니다. 🤓\n\n## 응답 모델 인코딩 매개변수 { #response-model-encoding-parameters }\n\n응답 모델은 아래와 같이 기본값을 가질 수 있습니다:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None` (또는 Python 3.10에서 `str | None = None`)은 기본값으로 `None`을 갖습니다.\n* `tax: float = 10.5`는 기본값으로 `10.5`를 갖습니다.\n* `tags: List[str] = []`는 기본값으로 빈 리스트 `[]`를 갖습니다.\n\n하지만 실제로 저장되지 않았을 경우 결과에서 이를 생략하고 싶을 수 있습니다.\n\n예를 들어, NoSQL 데이터베이스에 많은 선택적 속성이 있는 모델이 있지만, 기본값으로 가득 찬 매우 긴 JSON 응답을 보내고 싶지 않습니다.\n\n### `response_model_exclude_unset` 매개변수 사용 { #use-the-response-model-exclude-unset-parameter }\n\n*경로 처리 데코레이터* 매개변수 `response_model_exclude_unset=True`로 설정할 수 있습니다:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\n그러면 이러한 기본값은 응답에 포함되지 않고, 실제로 설정된 값만 포함됩니다.\n\n따라서 ID가 `foo`인 항목에 대해 해당 *경로 처리*로 요청을 보내면, (기본값을 제외한) 응답은 다음과 같습니다:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | 정보\n\n다음도 사용할 수 있습니다:\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\n`exclude_defaults` 및 `exclude_none`에 대해 [Pydantic 문서](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict)에 설명된 대로 사용할 수 있습니다.\n\n///\n\n#### 기본값이 있는 필드에 값이 있는 데이터 { #data-with-values-for-fields-with-defaults }\n\n하지만 ID가 `bar`인 항목처럼, 기본값이 있는 모델의 필드에 값이 있다면:\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\n응답에 포함됩니다.\n\n#### 기본값과 동일한 값을 갖는 데이터 { #data-with-the-same-values-as-the-defaults }\n\n데이터가 ID가 `baz`인 항목처럼 기본값과 동일한 값을 갖는다면:\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nFastAPI는 충분히 똑똑해서(사실, Pydantic이 충분히 똑똑합니다) `description`, `tax`, `tags`가 기본값과 동일하더라도, 기본값에서 가져온 것이 아니라 명시적으로 설정되었다는 것을 알아냅니다.\n\n그래서 JSON 응답에 포함됩니다.\n\n/// tip | 팁\n\n기본값은 `None`뿐만 아니라 어떤 것이든 될 수 있습니다.\n\n리스트(`[]`), `float`인 `10.5` 등이 될 수 있습니다.\n\n///\n\n### `response_model_include` 및 `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\n*경로 처리 데코레이터* 매개변수 `response_model_include` 및 `response_model_exclude`를 사용할 수도 있습니다.\n\n이들은 포함(나머지 생략)하거나 제외(나머지 포함)할 어트리뷰트 이름을 담은 `str`의 `set`을 받습니다.\n\nPydantic 모델이 하나만 있고 출력에서 일부 데이터를 제거하려는 경우, 빠른 지름길로 사용할 수 있습니다.\n\n/// tip | 팁\n\n하지만 이러한 매개변수 대신, 위에서 설명한 것처럼 여러 클래스를 사용하는 것을 여전히 권장합니다.\n\n이는 일부 어트리뷰트를 생략하기 위해 `response_model_include` 또는 `response_model_exclude`를 사용하더라도, 앱의 OpenAPI(및 문서)에 생성되는 JSON Schema가 여전히 전체 모델에 대한 스키마이기 때문입니다.\n\n비슷하게 동작하는 `response_model_by_alias`에도 동일하게 적용됩니다.\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | 팁\n\n문법 `{\"name\", \"description\"}`은 두 값을 갖는 `set`을 만듭니다.\n\n이는 `set([\"name\", \"description\"])`과 동일합니다.\n\n///\n\n#### `set` 대신 `list` 사용하기 { #using-lists-instead-of-sets }\n\n`set`을 쓰는 것을 잊고 `list`나 `tuple`을 대신 사용하더라도, FastAPI는 이를 `set`으로 변환하므로 올바르게 동작합니다:\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## 요약 { #recap }\n\n응답 모델을 정의하고 특히 개인정보가 필터링되도록 보장하려면 *경로 처리 데코레이터*의 매개변수 `response_model`을 사용하세요.\n\n명시적으로 설정된 값만 반환하려면 `response_model_exclude_unset`을 사용하세요.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/response-status-code.md",
    "content": "# 응답 상태 코드 { #response-status-code }\n\n응답 모델을 지정하는 것과 같은 방법으로, 어떤 *경로 처리*에서든 `status_code` 매개변수를 사용하여 응답에 사용할 HTTP 상태 코드를 선언할 수도 있습니다:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* 등\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | 참고\n\n`status_code` 는 \"데코레이터\" 메소드(`get`, `post` 등)의 매개변수입니다. 모든 매개변수들과 본문처럼 *경로 처리 함수*가 아닙니다.\n\n///\n\n`status_code` 매개변수는 HTTP 상태 코드를 숫자로 입력받습니다.\n\n/// info | 정보\n\n`status_code` 는 파이썬의 [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus) 와 같은 `IntEnum` 을 입력받을 수도 있습니다.\n\n///\n\n`status_code` 매개변수는:\n\n* 응답에서 해당 상태 코드를 반환합니다.\n* 상태 코드를 OpenAPI 스키마(따라서, 사용자 인터페이스에도)에 문서화합니다:\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | 참고\n\n일부 응답 코드(다음 섹션 참고)는 응답에 본문이 없다는 것을 나타냅니다.\n\nFastAPI는 이를 알고 있으며, 응답 본문이 없다고 명시하는 OpenAPI 문서를 생성합니다.\n\n///\n\n## HTTP 상태 코드에 대하여 { #about-http-status-codes }\n\n/// note | 참고\n\n만약 HTTP 상태 코드가 무엇인지 이미 알고 있다면, 다음 섹션으로 넘어가세요.\n\n///\n\nHTTP에서는 응답의 일부로 3자리 숫자 상태 코드를 보냅니다.\n\n이 상태 코드들은 이를 식별할 수 있도록 이름이 연결되어 있지만, 중요한 부분은 숫자입니다.\n\n요약하자면:\n\n* `100 - 199` 는 \"정보\"용입니다. 직접 사용할 일은 거의 없습니다. 이 상태 코드를 갖는 응답은 본문을 가질 수 없습니다.\n* **`200 - 299`** 는 \"성공적인\" 응답을 위한 것입니다. 가장 많이 사용하게 될 유형입니다.\n    * `200` 은 기본 상태 코드로, 모든 것이 \"OK\"임을 의미합니다.\n    * 다른 예로는 `201` \"생성됨\"이 있습니다. 일반적으로 데이터베이스에 새 레코드를 생성한 후 사용합니다.\n    * 특별한 경우로 `204` \"내용 없음\"이 있습니다. 이 응답은 클라이언트에게 반환할 내용이 없을 때 사용되며, 따라서 응답은 본문을 가지면 안 됩니다.\n* **`300 - 399`** 는 \"리다이렉션\"용입니다. 이 상태 코드를 갖는 응답은 본문이 있을 수도 없을 수도 있으며, 본문이 없어야 하는 `304` \"수정되지 않음\"을 제외합니다.\n* **`400 - 499`** 는 \"클라이언트 오류\" 응답을 위한 것입니다. 아마 두 번째로 가장 많이 사용하게 될 유형입니다.\n    * 예를 들어 `404` 는 \"찾을 수 없음\" 응답을 위해 사용합니다.\n    * 클라이언트의 일반적인 오류에는 `400` 을 그냥 사용할 수 있습니다.\n* `500 - 599` 는 서버 오류에 사용됩니다. 직접 사용할 일은 거의 없습니다. 애플리케이션 코드의 일부나 서버에서 문제가 발생하면 자동으로 이들 상태 코드 중 하나를 반환합니다.\n\n/// tip | 팁\n\n각 상태 코드와 어떤 코드가 어떤 용도인지 더 알고 싶다면 [<abbr title=\"Mozilla Developer Network - 모질라 개발자 네트워크\">MDN</abbr>의 HTTP 상태 코드에 관한 문서](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)를 확인하세요.\n\n///\n\n## 이름을 기억하는 쉬운 방법 { #shortcut-to-remember-the-names }\n\n이전 예시를 다시 확인해보겠습니다:\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201` 은 \"생성됨\"을 위한 상태 코드입니다.\n\n하지만 각각의 코드가 무엇을 의미하는지 외울 필요는 없습니다.\n\n`fastapi.status` 의 편의 변수를 사용할 수 있습니다.\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\n이것들은 단지 편의를 위한 것으로, 동일한 숫자를 갖고 있지만, 이를 통해 편집기의 자동완성 기능으로 찾을 수 있습니다:\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | 기술 세부사항\n\n`from starlette import status` 역시 사용할 수 있습니다.\n\n**FastAPI**는 개발자인 여러분의 편의를 위해 `fastapi.status` 와 동일한 `starlette.status` 도 제공합니다. 하지만 이것은 Starlette로부터 직접 제공됩니다.\n\n///\n\n## 기본값 변경 { #changing-the-default }\n\n나중에 [고급 사용자 지침서](../advanced/response-change-status-code.md)에서, 여기서 선언하는 기본값과 다른 상태 코드를 반환하는 방법을 확인할 수 있습니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/schema-extra-example.md",
    "content": "# 요청 예제 데이터 선언 { #declare-request-example-data }\n\n여러분의 앱이 받을 수 있는 데이터 예제를 선언할 수 있습니다.\n\n여기 이를 위한 몇 가지 방식이 있습니다.\n\n## Pydantic 모델 속 추가 JSON 스키마 데이터 { #extra-json-schema-data-in-pydantic-models }\n\n생성된 JSON 스키마에 추가될 Pydantic 모델을 위한 `examples`을 선언할 수 있습니다.\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\n추가 정보는 있는 그대로 해당 모델의 **JSON 스키마** 결과에 추가되고, API 문서에서 사용합니다.\n\n[Pydantic 문서: Configuration](https://docs.pydantic.dev/latest/api/config/)에 설명된 것처럼 `dict`를 받는 `model_config` 어트리뷰트를 사용할 수 있습니다.\n\n`\"json_schema_extra\"`를 생성된 JSON 스키마에서 보여주고 싶은 별도의 데이터와 `examples`를 포함하는 `dict`으로 설정할 수 있습니다.\n\n/// tip | 팁\n\nJSON 스키마를 확장하고 여러분의 별도의 자체 데이터를 추가하기 위해 같은 기술을 사용할 수 있습니다.\n\n예를 들면, 프론트엔드 사용자 인터페이스에 메타데이터를 추가하는 등에 사용할 수 있습니다.\n\n///\n\n/// info | 정보\n\n(FastAPI 0.99.0부터 쓰이기 시작한) OpenAPI 3.1.0은 **JSON 스키마** 표준의 일부인 `examples`에 대한 지원을 추가했습니다.\n\n그 전에는, 하나의 예제만 가능한 `example` 키워드만 지원했습니다. 이는 아직 OpenAPI 3.1.0에서 지원하지만, 지원이 종료될 것이며 JSON 스키마 표준에 포함되지 않습니다. 그렇기에 `example`을 `examples`으로 이전하는 것을 추천합니다. 🤓\n\n이 페이지 끝에서 더 많은 내용을 읽을 수 있습니다.\n\n///\n\n## `Field` 추가 인자 { #field-additional-arguments }\n\nPydantic 모델과 같이 `Field()`를 사용할 때 추가적인 `examples`를 선언할 수 있습니다:\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## JSON Schema에서의 `examples` - OpenAPI { #examples-in-json-schema-openapi }\n\n다음 중 하나를 사용할 때:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\n**OpenAPI** 안의 **JSON 스키마**에 추가될 부가적인 정보를 포함한 `examples` 모음을 선언할 수도 있습니다.\n\n### `examples`를 포함한 `Body` { #body-with-examples }\n\n여기, `Body()`에 예상되는 예제 데이터 하나를 포함한 `examples`를 넘겼습니다:\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### 문서 UI 예시 { #example-in-the-docs-ui }\n\n위의 어느 방법과 함께라면 `/docs`에서 다음과 같이 보일 것입니다:\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### 다중 `examples`를 포함한 `Body` { #body-with-multiple-examples }\n\n물론 여러 `examples`를 넘길 수 있습니다:\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\n이와 같이 하면 예제들은 그 본문 데이터의 내부 **JSON 스키마**의 일부가 될 것입니다.\n\n그럼에도 불구하고, 지금 <dfn title=\"2023-08-26\">이 문서를 작성하는 시간</dfn>에, 문서 UI를 보여주는 역할을 맡은 Swagger UI는 **JSON 스키마** 속 데이터를 위한 여러 예제의 표현을 지원하지 않습니다. 하지만 해결 방안을 밑에서 읽어보세요.\n\n### OpenAPI-특화 `examples` { #openapi-specific-examples }\n\n**JSON 스키마**가 `examples`를 지원하기 전부터 OpenAPI는 `examples`이라 불리는 다른 필드를 지원해 왔습니다.\n\n이 **OpenAPI-특화** `examples`는 OpenAPI 명세서의 다른 구역으로 들어갑니다. 각 JSON 스키마 내부가 아니라 **각 *경로 처리* 세부 정보**에 포함됩니다.\n\n그리고 Swagger UI는 이 특정한 `examples` 필드를 한동안 지원했습니다. 그래서, 이를 다른 **문서 UI에 있는 예제**를 **표시**하기 위해 사용할 수 있습니다.\n\n이 OpenAPI-특화 필드인 `examples`의 형태는 (`list` 대신에) **다중 예제**가 포함된 `dict`이며, 각각의 별도 정보 또한 **OpenAPI**에 추가될 것입니다.\n\n이는 OpenAPI에 포함된 각 JSON 스키마 안으로 포함되지 않으며, *경로 처리*에 직접적으로 포함됩니다.\n\n### `openapi_examples` 매개변수 사용하기 { #using-the-openapi-examples-parameter }\n\n다음에 대해 FastAPI에서 매개변수 `openapi_examples`로 OpenAPI-특화 `examples`를 선언할 수 있습니다:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\n`dict`의 키는 각 예제를 식별하고, 각 값은 또 다른 `dict`입니다.\n\n`examples` 안의 각 특정 예제 `dict`에는 다음이 포함될 수 있습니다:\n\n* `summary`: 예제에 대한 짧은 설명문.\n* `description`: 마크다운 텍스트를 포함할 수 있는 긴 설명문.\n* `value`: 실제로 보여지는 예시, 예를 들면 `dict`.\n* `externalValue`: `value`의 대안이며 예제를 가리키는 URL. 비록 `value`처럼 많은 도구를 지원하지 못할 수 있습니다.\n\n이를 다음과 같이 사용할 수 있습니다:\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### 문서 UI에서의 OpenAPI 예시 { #openapi-examples-in-the-docs-ui }\n\n`Body()`에 `openapi_examples`가 추가되면 `/docs`는 다음과 같이 보일 것입니다:\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## 기술적 세부 사항 { #technical-details }\n\n/// tip | 팁\n\n이미 **FastAPI**의 **0.99.0 혹은 그 이상** 버전을 사용하고 있다면, 이 세부 사항을 **스킵**해도 상관 없을 것입니다.\n\n세부 사항은 OpenAPI 3.1.0이 사용가능하기 전, 예전 버전과 더 관련있습니다.\n\n간략한 OpenAPI와 JSON 스키마 **역사 강의**로 생각할 수 있습니다. 🤓\n\n///\n\n/// warning | 경고\n\n표준 **JSON 스키마**와 **OpenAPI**에 대한 아주 기술적인 세부사항입니다.\n\n만약 위의 생각이 작동한다면, 그것으로 충분하며 이 세부 사항은 필요없을 것이니, 마음 편하게 스킵하셔도 됩니다.\n\n///\n\nOpenAPI 3.1.0 전에 OpenAPI는 오래된 **JSON 스키마**의 수정된 버전을 사용했습니다.\n\nJSON 스키마는 `examples`를 가지고 있지 않았고, 따라서 OpenAPI는 그들만의 `example` 필드를 수정된 버전에 추가했습니다.\n\nOpenAPI는 또한 `example`과 `examples` 필드를 명세서의 다른 부분에 추가했습니다:\n\n* [`Parameter Object` (명세서에 있는)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object)는 FastAPI의 다음 기능에서 쓰였습니다:\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object`, `Media Type Object` (명세서에 있는)의 `content` 필드에 있는](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object)는 FastAPI의 다음 기능에서 쓰였습니다:\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info | 정보\n\n이 예전 OpenAPI-특화 `examples` 매개변수는 이제 FastAPI `0.103.0`부터 `openapi_examples`입니다.\n\n///\n\n### JSON 스키마의 `examples` 필드 { #json-schemas-examples-field }\n\n하지만, 후에 JSON 스키마는 [`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5) 필드를 명세서의 새 버전에 추가했습니다.\n\n그리고 새로운 OpenAPI 3.1.0은 이 새로운 `examples` 필드가 포함된 최신 버전 (JSON 스키마 2020-12)을 기반으로 했습니다.\n\n그리고 이제 이 새로운 `examples` 필드는 이제 지원 중단된, 예전의 단일 (그리고 커스텀) `example` 필드보다 우선됩니다.\n\nJSON 스키마의 새로운 `examples` 필드는 예제의 **단순한 `list`**일 뿐이며, (위에서 상술한 것처럼) OpenAPI의 다른 곳에 존재하는 추가 메타데이터가 있는 dict가 아닙니다.\n\n/// info | 정보\n\n더 쉽고 새로운 JSON 스키마와의 통합과 함께 OpenAPI 3.1.0가 배포되었지만, 잠시동안 자동 문서 생성을 제공하는 도구인 Swagger UI는 OpenAPI 3.1.0을 지원하지 않았습니다 (5.0.0 버전부터 지원합니다 🎉).\n\n이로인해, FastAPI 0.99.0 이전 버전은 아직 OpenAPI 3.1.0 보다 낮은 버전을 사용했습니다.\n\n///\n\n### Pydantic과 FastAPI `examples` { #pydantic-and-fastapi-examples }\n\nPydantic 모델 안에 `examples`를 추가할 때, `schema_extra` 또는 `Field(examples=[\"something\"])`를 사용하면 그 예제는 해당 Pydantic 모델의 **JSON 스키마**에 추가됩니다.\n\n그리고 Pydantic 모델의 **JSON 스키마**는 API의 **OpenAPI**에 포함되고, 그 후 문서 UI 속에서 사용됩니다.\n\nFastAPI 0.99.0 이전 버전에서 (0.99.0 이상 버전은 새로운 OpenAPI 3.1.0을 사용합니다), 다른 유틸리티(`Query()`, `Body()` 등)와 함께 `example` 또는 `examples`를 사용했을 때, 그러한 예제는 그 데이터를 설명하는 JSON 스키마에 추가되지 않고 (OpenAPI 자체의 JSON 스키마에도 포함되지 않습니다), OpenAPI의 *경로 처리* 선언에 직접적으로 추가됩니다 (JSON 스키마를 사용하는 OpenAPI 부분 밖에서).\n\n하지만 이제 FastAPI 0.99.0 및 이후 버전에서는 JSON 스키마 2020-12를 사용하는 OpenAPI 3.1.0과 Swagger UI 5.0.0 및 이후 버전을 사용하기 때문에, 모든 것이 더 일관성을 띄고 예제도 JSON 스키마에 포함됩니다.\n\n### Swagger UI와 OpenAPI-특화 `examples` { #swagger-ui-and-openapi-specific-examples }\n\nSwagger UI는 다중 JSON 스키마 예제를 지원하지 않았기 때문에(2023-08-26 기준), 사용자는 문서에 여러 예제를 표시할 방법이 없었습니다.\n\n이를 해결하기 위해, FastAPI `0.103.0`은 새로운 매개변수인 `openapi_examples`로 동일한 예전 **OpenAPI-특화** `examples` 필드를 선언하는 **지원**을 추가했습니다. 🤓\n\n### 요약 { #summary }\n\n저는 역사를 그다지 좋아하는 편이 아니라고 말하고는 했지만... \"기술 역사\" 강의를 하는 지금의 저를 보세요. 😅\n\n요약하자면 **FastAPI 0.99.0 혹은 그 이상의 버전**으로 업그레이드하면, 많은 것들이 훨씬 더 **단순하고, 일관적이며 직관적**이 되며, 여러분은 이 모든 역사적 세부 사항을 알 필요가 없습니다. 😎\n"
  },
  {
    "path": "docs/ko/docs/tutorial/security/first-steps.md",
    "content": "# 보안 - 첫 단계 { #security-first-steps }\n\n어떤 도메인에 **backend** API가 있다고 가정해 보겠습니다.\n\n그리고 다른 도메인에 **frontend**가 있거나, 같은 도메인의 다른 경로에 있거나(또는 모바일 애플리케이션에 있을 수도 있습니다).\n\n그리고 frontend가 **username**과 **password**를 사용해 backend에 인증할 수 있는 방법이 필요하다고 해봅시다.\n\n**FastAPI**와 함께 **OAuth2**를 사용해서 이를 구현할 수 있습니다.\n\n하지만 필요한 작은 정보 조각들을 찾기 위해 길고 긴 전체 스펙을 읽느라 시간을 쓰지 않도록 하겠습니다.\n\n보안을 처리하기 위해 **FastAPI**가 제공하는 도구들을 사용해 봅시다.\n\n## 어떻게 보이는지 { #how-it-looks }\n\n먼저 코드를 그냥 사용해서 어떻게 동작하는지 보고, 그다음에 무슨 일이 일어나는지 이해하러 다시 돌아오겠습니다.\n\n## `main.py` 만들기 { #create-main-py }\n\n예제를 파일 `main.py`에 복사하세요:\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## 실행하기 { #run-it }\n\n/// info | 정보\n\n[`python-multipart`](https://github.com/Kludex/python-multipart) 패키지는 `pip install \"fastapi[standard]\"` 명령을 실행하면 **FastAPI**와 함께 자동으로 설치됩니다.\n\n하지만 `pip install fastapi` 명령을 사용하면 `python-multipart` 패키지가 기본으로 포함되지 않습니다.\n\n수동으로 설치하려면, [가상 환경](../../virtual-environments.md)을 만들고 활성화한 다음, 아래로 설치하세요:\n\n```console\n$ pip install python-multipart\n```\n\n이는 **OAuth2**가 `username`과 `password`를 보내기 위해 \"form data\"를 사용하기 때문입니다.\n\n///\n\n다음으로 예제를 실행하세요:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## 확인하기 { #check-it }\n\n대화형 문서로 이동하세요: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n다음과 비슷한 화면이 보일 것입니다:\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Authorize 버튼!\n\n반짝이는 새 \"Authorize\" 버튼이 이미 있습니다.\n\n그리고 *경로 처리*에는 오른쪽 상단에 클릭할 수 있는 작은 자물쇠가 있습니다.\n\n///\n\n그리고 이를 클릭하면 `username`과 `password`(그리고 다른 선택적 필드들)를 입력할 수 있는 작은 인증 폼이 나타납니다:\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | 참고\n\n폼에 무엇을 입력하든 아직은 동작하지 않습니다. 하지만 곧 여기까지 구현할 것입니다.\n\n///\n\n물론 이것은 최종 사용자를 위한 frontend는 아니지만, 모든 API를 대화형으로 문서화하는 훌륭한 자동 도구입니다.\n\nfrontend 팀(그게 본인일 수도 있습니다)이 사용할 수 있습니다.\n\n서드파티 애플리케이션과 시스템에서도 사용할 수 있습니다.\n\n그리고 동일한 애플리케이션을 디버그하고, 확인하고, 테스트하기 위해 본인이 사용할 수도 있습니다.\n\n## `password` 플로우 { #the-password-flow }\n\n이제 조금 돌아가서 이것들이 무엇인지 이해해 봅시다.\n\n`password` \"flow\"는 보안과 인증을 처리하기 위해 OAuth2에서 정의한 여러 방식(\"flows\") 중 하나입니다.\n\nOAuth2는 backend 또는 API가 사용자를 인증하는 서버와 독립적일 수 있도록 설계되었습니다.\n\n하지만 이 경우에는 같은 **FastAPI** 애플리케이션이 API와 인증을 모두 처리합니다.\n\n따라서, 단순화된 관점에서 다시 정리해보면:\n\n* 사용자가 frontend에서 `username`과 `password`를 입력하고 `Enter`를 누릅니다.\n* frontend(사용자의 브라우저에서 실행됨)는 해당 `username`과 `password`를 우리 API의 특정 URL로 보냅니다(`tokenUrl=\"token\"`로 선언됨).\n* API는 `username`과 `password`를 확인하고 \"token\"으로 응답합니다(아직 아무것도 구현하지 않았습니다).\n    * \"token\"은 나중에 이 사용자를 검증하는 데 사용할 수 있는 어떤 내용이 담긴 문자열일 뿐입니다.\n    * 보통 token은 일정 시간이 지나면 만료되도록 설정합니다.\n        * 그래서 사용자는 나중에 어느 시점엔 다시 로그인해야 합니다.\n        * 그리고 token이 도난당하더라도 위험이 더 낮습니다. 대부분의 경우 영구적으로 항상 동작하는 키와는 다릅니다.\n* frontend는 그 token을 임시로 어딘가에 저장합니다.\n* 사용자가 frontend에서 클릭해서 frontend 웹 앱의 다른 섹션으로 이동합니다.\n* frontend는 API에서 더 많은 데이터를 가져와야 합니다.\n    * 하지만 그 특정 endpoint에는 인증이 필요합니다.\n    * 그래서 우리 API에 인증하기 위해 `Authorization` 헤더를, 값은 `Bearer `에 token을 더한 형태로 보냅니다.\n    * token에 `foobar`가 들어 있다면 `Authorization` 헤더의 내용은 `Bearer foobar`가 됩니다.\n\n## **FastAPI**의 `OAuth2PasswordBearer` { #fastapis-oauth2passwordbearer }\n\n**FastAPI**는 이런 보안 기능을 구현하기 위해, 서로 다른 추상화 수준에서 여러 도구를 제공합니다.\n\n이 예제에서는 **OAuth2**의 **Password** 플로우와 **Bearer** token을 사용합니다. 이를 위해 `OAuth2PasswordBearer` 클래스를 사용합니다.\n\n/// info | 정보\n\n\"bearer\" token만이 유일한 선택지는 아닙니다.\n\n하지만 이 사용 사례에는 가장 적합한 선택입니다.\n\n또한 OAuth2 전문가로서 왜 다른 옵션이 더 적합한지 정확히 아는 경우가 아니라면, 대부분의 사용 사례에도 가장 적합할 가능성이 큽니다.\n\n그런 경우를 위해서도 **FastAPI**는 이를 구성할 수 있는 도구를 제공합니다.\n\n///\n\n`OAuth2PasswordBearer` 클래스의 인스턴스를 만들 때 `tokenUrl` 파라미터를 전달합니다. 이 파라미터에는 클라이언트(사용자의 브라우저에서 실행되는 frontend)가 token을 받기 위해 `username`과 `password`를 보낼 URL이 들어 있습니다.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip | 팁\n\n여기서 `tokenUrl=\"token\"`은 아직 만들지 않은 상대 URL `token`을 가리킵니다. 상대 URL이므로 `./token`과 동일합니다.\n\n상대 URL을 사용하므로, 예를 들어 API가 `https://example.com/`에 있다면 `https://example.com/token`을 가리킵니다. 하지만 API가 `https://example.com/api/v1/`에 있다면 `https://example.com/api/v1/token`을 가리킵니다.\n\n상대 URL을 사용하는 것은 [프록시 뒤에서](../../advanced/behind-a-proxy.md) 같은 고급 사용 사례에서도 애플리케이션이 계속 동작하도록 보장하는 데 중요합니다.\n\n///\n\n이 파라미터는 그 endpoint / *경로 처리*를 만들지는 않지만, URL `/token`이 클라이언트가 token을 얻기 위해 사용해야 할 URL이라고 선언합니다. 이 정보는 OpenAPI에 사용되고, 이어서 대화형 API 문서 시스템에서도 사용됩니다.\n\n곧 실제 경로 처리를 만들 것입니다.\n\n/// info | 정보\n\n엄격한 \"Pythonista\"라면 `token_url` 대신 `tokenUrl` 같은 파라미터 이름 스타일이 마음에 들지 않을 수도 있습니다.\n\n이는 OpenAPI 스펙에서 사용하는 이름과 동일하게 맞춘 것이기 때문입니다. 그래서 이런 보안 스킴에 대해 더 조사해야 할 때, 그대로 복사해서 붙여 넣어 더 많은 정보를 찾을 수 있습니다.\n\n///\n\n`oauth2_scheme` 변수는 `OAuth2PasswordBearer`의 인스턴스이지만, \"callable\"이기도 합니다.\n\n다음처럼 호출될 수 있습니다:\n\n```Python\noauth2_scheme(some, parameters)\n```\n\n따라서 `Depends`와 함께 사용할 수 있습니다.\n\n### 사용하기 { #use-it }\n\n이제 `Depends`로 `oauth2_scheme`를 의존성에 전달할 수 있습니다.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\n이 의존성은 `str`을 제공하고, 그 값은 *경로 처리 함수*의 파라미터 `token`에 할당됩니다.\n\n**FastAPI**는 이 의존성을 사용해 OpenAPI 스키마(및 자동 API 문서)에 \"security scheme\"를 정의할 수 있다는 것을 알게 됩니다.\n\n/// info | 기술 세부사항\n\n**FastAPI**는 (의존성에 선언된) `OAuth2PasswordBearer` 클래스를 사용해 OpenAPI에서 보안 스킴을 정의할 수 있다는 것을 알고 있습니다. 이는 `OAuth2PasswordBearer`가 `fastapi.security.oauth2.OAuth2`를 상속하고, 이것이 다시 `fastapi.security.base.SecurityBase`를 상속하기 때문입니다.\n\nOpenAPI(및 자동 API 문서)와 통합되는 모든 보안 유틸리티는 `SecurityBase`를 상속하며, 그래서 **FastAPI**가 이를 OpenAPI에 어떻게 통합할지 알 수 있습니다.\n\n///\n\n## 무엇을 하는지 { #what-it-does }\n\n요청에서 `Authorization` 헤더를 찾아, 값이 `Bearer `에 어떤 token이 붙은 형태인지 확인한 뒤, 그 token을 `str`로 반환합니다.\n\n`Authorization` 헤더가 없거나, 값에 `Bearer ` token이 없다면, 곧바로 401 상태 코드 오류(`UNAUTHORIZED`)로 응답합니다.\n\n오류를 반환하기 위해 token이 존재하는지 직접 확인할 필요조차 없습니다. 함수가 실행되었다면 그 token에는 `str`이 들어 있다고 확신할 수 있습니다.\n\n대화형 문서에서 이미 시도해 볼 수 있습니다:\n\n<img src=\"/img/tutorial/security/image03.png\">\n\n아직 token의 유효성을 검증하진 않지만, 이것만으로도 시작은 된 셈입니다.\n\n## 요약 { #recap }\n\n즉, 추가로 3~4줄만으로도 이미 원시적인 형태의 보안을 갖추게 됩니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/security/get-current-user.md",
    "content": "# 현재 사용자 가져오기 { #get-current-user }\n\n이전 장에서 (의존성 주입 시스템을 기반으로 한) 보안 시스템은 *경로 처리 함수*에 `str`로 `token`을 제공했습니다:\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\n하지만 이는 여전히 그다지 유용하지 않습니다.\n\n현재 사용자를 제공하도록 해봅시다.\n\n## 사용자 모델 생성하기 { #create-a-user-model }\n\n먼저 Pydantic 사용자 모델을 만들어 봅시다.\n\nPydantic을 사용해 본문을 선언하는 것과 같은 방식으로, 다른 곳에서도 어디서든 사용할 수 있습니다:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## `get_current_user` 의존성 생성하기 { #create-a-get-current-user-dependency }\n\n의존성 `get_current_user`를 만들어 봅시다.\n\n의존성이 하위 의존성을 가질 수 있다는 것을 기억하시나요?\n\n`get_current_user`는 이전에 생성한 것과 동일한 `oauth2_scheme`에 대한 의존성을 갖게 됩니다.\n\n이전에 *경로 처리*에서 직접 수행했던 것과 동일하게, 새 의존성 `get_current_user`는 하위 의존성 `oauth2_scheme`로부터 `str`로 `token`을 받게 됩니다:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## 사용자 가져오기 { #get-the-user }\n\n`get_current_user`는 우리가 만든 (가짜) 유틸리티 함수를 사용합니다. 이 함수는 `str`로 토큰을 받아 Pydantic `User` 모델을 반환합니다:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## 현재 사용자 주입하기 { #inject-the-current-user }\n\n이제 *경로 처리*에서 `get_current_user`와 함께 같은 `Depends`를 사용할 수 있습니다:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\n`current_user`의 타입을 Pydantic 모델 `User`로 선언한다는 점에 주목하세요.\n\n이는 함수 내부에서 자동 완성과 타입 체크에 도움을 줍니다.\n\n/// tip | 팁\n\n요청 본문도 Pydantic 모델로 선언된다는 것을 기억하실지도 모릅니다.\n\n여기서 **FastAPI**는 `Depends`를 사용하고 있기 때문에 혼동하지 않습니다.\n\n///\n\n/// check | 확인\n\n이 의존성 시스템이 설계된 방식은 모두 `User` 모델을 반환하는 서로 다른 의존성(서로 다른 \"dependables\")을 가질 수 있도록 합니다.\n\n해당 타입의 데이터를 반환할 수 있는 의존성이 하나만 있어야 하는 것으로 제한되지 않습니다.\n\n///\n\n## 다른 모델 { #other-models }\n\n이제 *경로 처리 함수*에서 현재 사용자를 직접 가져올 수 있으며, `Depends`를 사용해 **의존성 주입** 수준에서 보안 메커니즘을 처리할 수 있습니다.\n\n그리고 보안 요구 사항을 위해 어떤 모델이나 데이터든 사용할 수 있습니다(이 경우 Pydantic 모델 `User`).\n\n하지만 특정 데이터 모델, 클래스 또는 타입만 사용해야 하는 것은 아닙니다.\n\n모델에 `id`와 `email`이 있고 `username`은 없게 하고 싶으신가요? 물론입니다. 같은 도구를 사용할 수 있습니다.\n\n`str`만 갖고 싶으신가요? 아니면 `dict`만요? 또는 데이터베이스 클래스 모델 인스턴스를 직접 쓰고 싶으신가요? 모두 같은 방식으로 동작합니다.\n\n애플리케이션에 로그인하는 사용자는 없고, 액세스 토큰만 가진 로봇, 봇 또는 다른 시스템만 있나요? 이것도 마찬가지로 모두 동일하게 동작합니다.\n\n애플리케이션에 필요한 어떤 종류의 모델, 어떤 종류의 클래스, 어떤 종류의 데이터베이스든 사용하세요. **FastAPI**는 의존성 주입 시스템으로 이를 지원합니다.\n\n## 코드 크기 { #code-size }\n\n이 예시는 장황해 보일 수 있습니다. 동일한 파일에서 보안, 데이터 모델, 유틸리티 함수 및 *경로 처리*를 섞어서 사용하고 있다는 점을 기억하세요.\n\n하지만 여기 핵심이 있습니다.\n\n보안과 의존성 주입 관련 코드는 한 번만 작성합니다.\n\n그리고 원하는 만큼 복잡하게 만들 수 있습니다. 그럼에도 여전히 한 번만, 한 곳에만 작성하면 됩니다. 유연성을 모두 유지하면서요.\n\n하지만 같은 보안 시스템을 사용해 수천 개의 엔드포인트(*경로 처리*)를 가질 수 있습니다.\n\n그리고 그들 모두(또는 원하는 일부)는 이러한 의존성 또는 여러분이 생성한 다른 의존성을 재사용하는 이점을 얻을 수 있습니다.\n\n그리고 이 수천 개의 *경로 처리*는 3줄 정도로도 만들 수 있습니다:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## 요약 { #recap }\n\n이제 *경로 처리 함수*에서 현재 사용자를 직접 가져올 수 있습니다.\n\n우리는 이미 절반은 왔습니다.\n\n사용자/클라이언트가 실제로 `username`과 `password`를 보내도록 하는 *경로 처리*만 추가하면 됩니다.\n\n다음에 이어집니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/security/index.md",
    "content": "# 보안 { #security }\n\n보안, 인증(authentication), 인가(authorization)를 처리하는 방법은 매우 다양합니다.\n\n그리고 보통 복잡하고 \"어려운\" 주제이기도 합니다.\n\n많은 프레임워크와 시스템에서 보안과 인증만 처리하는 데도 큰 노력과 코드가 필요합니다(많은 경우 작성된 전체 코드의 50% 이상이 될 수도 있습니다).\n\n**FastAPI**는 모든 보안 명세를 전부 공부하고 배울 필요 없이, 표준적인 방식으로 쉽고 빠르게 **보안(Security)** 을 다룰 수 있도록 여러 도구를 제공합니다.\n\n하지만 먼저, 몇 가지 작은 개념을 확인해 보겠습니다.\n\n## 급하신가요? { #in-a-hurry }\n\n이 용어들에 관심이 없고 사용자명과 비밀번호 기반 인증을 사용한 보안을 *지금 당장* 추가하기만 하면 된다면, 다음 장들로 넘어가세요.\n\n## OAuth2 { #oauth2 }\n\nOAuth2는 인증과 인가를 처리하는 여러 방법을 정의하는 명세입니다.\n\n상당히 방대한 명세이며 여러 복잡한 사용 사례를 다룹니다.\n\n\"제3자\"를 사용해 인증하는 방법도 포함합니다.\n\n바로 `\"Facebook, Google, X (Twitter), GitHub로 로그인\"` 같은 시스템들이 내부적으로 사용하는 방식입니다.\n\n### OAuth 1 { #oauth-1 }\n\nOAuth 1도 있었는데, 이는 OAuth2와 매우 다르고 통신을 암호화하는 방법까지 직접 명세에 포함했기 때문에 더 복잡했습니다.\n\n요즘에는 그다지 인기 있거나 사용되지는 않습니다.\n\nOAuth2는 통신을 어떻게 암호화할지는 명세하지 않고, 애플리케이션이 HTTPS로 제공될 것을 기대합니다.\n\n/// tip | 팁\n\n**배포**에 대한 섹션에서 Traefik과 Let's Encrypt를 사용해 무료로 HTTPS를 설정하는 방법을 볼 수 있습니다.\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect는 **OAuth2**를 기반으로 한 또 다른 명세입니다.\n\nOAuth2에서 비교적 모호한 부분을 일부 구체화하여 상호 운용성을 높이려는 확장입니다.\n\n예를 들어, Google 로그인은 OpenID Connect를 사용합니다(내부적으로는 OAuth2를 사용).\n\n하지만 Facebook 로그인은 OpenID Connect를 지원하지 않습니다. 자체적인 변형의 OAuth2를 사용합니다.\n\n### OpenID(\"OpenID Connect\"가 아님) { #openid-not-openid-connect }\n\n\"OpenID\"라는 명세도 있었습니다. 이는 **OpenID Connect**와 같은 문제를 해결하려고 했지만, OAuth2를 기반으로 하지 않았습니다.\n\n따라서 완전히 별도의 추가 시스템이었습니다.\n\n요즘에는 그다지 인기 있거나 사용되지는 않습니다.\n\n## OpenAPI { #openapi }\n\nOpenAPI(이전에는 Swagger로 알려짐)는 API를 구축하기 위한 공개 명세입니다(현재 Linux Foundation의 일부).\n\n**FastAPI**는 **OpenAPI**를 기반으로 합니다.\n\n이 덕분에 여러 자동 대화형 문서 인터페이스, 코드 생성 등과 같은 기능을 사용할 수 있습니다.\n\nOpenAPI에는 여러 보안 \"scheme\"을 정의하는 방법이 있습니다.\n\n이를 사용하면 이러한 대화형 문서 시스템을 포함해, 표준 기반 도구들을 모두 활용할 수 있습니다.\n\nOpenAPI는 다음 보안 scheme들을 정의합니다:\n\n* `apiKey`: 다음에서 전달될 수 있는 애플리케이션 전용 키:\n    * 쿼리 파라미터\n    * 헤더\n    * 쿠키\n* `http`: 표준 HTTP 인증 시스템, 예:\n    * `bearer`: `Authorization` 헤더에 `Bearer ` + 토큰 값을 넣는 방식. OAuth2에서 유래했습니다.\n    * HTTP Basic 인증\n    * HTTP Digest 등\n* `oauth2`: 보안을 처리하는 모든 OAuth2 방식(이를 \"flow\"라고 부릅니다).\n    * 이 flow들 중 여러 개는 OAuth 2.0 인증 제공자(예: Google, Facebook, X (Twitter), GitHub 등)를 구축하는 데 적합합니다:\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * 하지만 같은 애플리케이션에서 직접 인증을 처리하는 데 완벽하게 사용할 수 있는 특정 \"flow\"도 하나 있습니다:\n        * `password`: 다음 장들에서 이에 대한 예시를 다룹니다.\n* `openIdConnect`: OAuth2 인증 데이터를 자동으로 탐색(discover)하는 방법을 정의합니다.\n    * 이 자동 탐색은 OpenID Connect 명세에서 정의됩니다.\n\n\n/// tip | 팁\n\nGoogle, Facebook, X (Twitter), GitHub 등 다른 인증/인가 제공자를 통합하는 것도 가능하며 비교적 쉽습니다.\n\n가장 복잡한 문제는 그런 인증/인가 제공자 자체를 구축하는 것이지만, **FastAPI**는 어려운 작업을 대신 처리해 주면서 이를 쉽게 할 수 있는 도구를 제공합니다.\n\n///\n\n## **FastAPI** 유틸리티 { #fastapi-utilities }\n\nFastAPI는 `fastapi.security` 모듈에서 각 보안 scheme에 대한 여러 도구를 제공하며, 이러한 보안 메커니즘을 더 쉽게 사용할 수 있게 해줍니다.\n\n다음 장들에서는 **FastAPI**가 제공하는 도구를 사용해 API에 보안을 추가하는 방법을 보게 될 것입니다.\n\n또한 대화형 문서 시스템에 어떻게 자동으로 통합되는지도 확인하게 됩니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/security/oauth2-jwt.md",
    "content": "# 패스워드(해싱 포함)를 사용하는 OAuth2, JWT 토큰을 사용하는 Bearer { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\n모든 보안 흐름을 구성했으므로, 이제 <abbr title=\"JSON 웹 토큰\">JWT</abbr> 토큰과 안전한 패스워드 해싱을 사용해 애플리케이션을 실제로 안전하게 만들겠습니다.\n\n이 코드는 실제로 애플리케이션에서 사용할 수 있으며, 패스워드 해시를 데이터베이스에 저장하는 등의 작업에 활용할 수 있습니다.\n\n이전 장에서 멈춘 지점부터 시작해 내용을 확장해 나가겠습니다.\n\n## JWT 알아보기 { #about-jwt }\n\nJWT는 \"JSON Web Tokens\"를 의미합니다.\n\nJSON 객체를 공백이 없는 길고 밀집된 문자열로 부호화하는 표준입니다. 다음과 같은 형태입니다:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\n암호화된 것이 아니므로, 누구나 내용에서 정보를 복원할 수 있습니다.\n\n하지만 서명되어 있습니다. 따라서 자신이 발급한 토큰을 받았을 때, 실제로 자신이 발급한 것이 맞는지 검증할 수 있습니다.\n\n예를 들어 만료 기간이 1주일인 토큰을 생성할 수 있습니다. 그리고 사용자가 다음 날 토큰을 가지고 돌아오면, 그 사용자가 시스템에 여전히 로그인되어 있다는 것을 알 수 있습니다.\n\n1주일 뒤에는 토큰이 만료되고 사용자는 인가되지 않으므로 새 토큰을 받기 위해 다시 로그인해야 합니다. 그리고 사용자(또는 제3자)가 만료 시간을 바꾸기 위해 토큰을 수정하려고 하면, 서명이 일치하지 않기 때문에 이를 알아챌 수 있습니다.\n\nJWT 토큰을 직접 다뤄보고 동작 방식을 확인해보고 싶다면 [https://jwt.io](https://jwt.io/)를 확인하십시오.\n\n## `PyJWT` 설치 { #install-pyjwt }\n\nPython에서 JWT 토큰을 생성하고 검증하려면 `PyJWT`를 설치해야 합니다.\n\n[가상환경](../../virtual-environments.md)을 만들고 활성화한 다음 `pyjwt`를 설치하십시오:\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info | 정보\n\nRSA나 ECDSA 같은 전자 서명 알고리즘을 사용할 계획이라면, cryptography 라이브러리 의존성인 `pyjwt[crypto]`를 설치해야 합니다.\n\n자세한 내용은 [PyJWT 설치 문서](https://pyjwt.readthedocs.io/en/latest/installation.html)에서 확인할 수 있습니다.\n\n///\n\n## 패스워드 해싱 { #password-hashing }\n\n\"해싱(Hashing)\"은 어떤 내용(여기서는 패스워드)을 알아볼 수 없는 바이트 시퀀스(그냥 문자열)로 변환하는 것을 의미합니다.\n\n정확히 같은 내용(정확히 같은 패스워드)을 넣으면 정확히 같은 알아볼 수 없는 문자열이 나옵니다.\n\n하지만 그 알아볼 수 없는 문자열에서 다시 패스워드로 되돌릴 수는 없습니다.\n\n### 패스워드 해싱을 사용하는 이유 { #why-use-password-hashing }\n\n데이터베이스를 탈취당하더라도, 침입자는 사용자의 평문 패스워드 대신 해시만 얻게 됩니다.\n\n따라서 침입자는 그 패스워드를 다른 시스템에서 사용해 보려고 시도할 수 없습니다(많은 사용자가 어디서나 같은 패스워드를 사용하므로, 이는 위험합니다).\n\n## `pwdlib` 설치 { #install-pwdlib }\n\npwdlib는 패스워드 해시를 다루기 위한 훌륭한 Python 패키지입니다.\n\n많은 안전한 해싱 알고리즘과 이를 다루기 위한 유틸리티를 지원합니다.\n\n추천 알고리즘은 \"Argon2\"입니다.\n\n[가상환경](../../virtual-environments.md)을 만들고 활성화한 다음 Argon2와 함께 pwdlib를 설치하십시오:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | 팁\n\n`pwdlib`를 사용하면 **Django**, **Flask** 보안 플러그인 또는 다른 여러 도구로 생성한 패스워드를 읽을 수 있도록 설정할 수도 있습니다.\n\n따라서 예를 들어, FastAPI 애플리케이션과 Django 애플리케이션이 같은 데이터베이스에서 동일한 데이터를 공유할 수 있습니다. 또는 같은 데이터베이스를 사용하면서 Django 애플리케이션을 점진적으로 마이그레이션할 수도 있습니다.\n\n그리고 사용자는 Django 앱 또는 **FastAPI** 앱에서 동시에 로그인할 수 있습니다.\n\n///\n\n## 패스워드 해시 및 검증 { #hash-and-verify-the-passwords }\n\n`pwdlib`에서 필요한 도구를 임포트합니다.\n\n권장 설정으로 PasswordHash 인스턴스를 생성합니다. 이는 패스워드를 해싱하고 검증하는 데 사용됩니다.\n\n/// tip | 팁\n\npwdlib는 bcrypt 해싱 알고리즘도 지원하지만 레거시 알고리즘은 포함하지 않습니다. 오래된 해시로 작업해야 한다면 passlib 라이브러리를 사용하는 것을 권장합니다.\n\n예를 들어, 다른 시스템(Django 같은)에서 생성한 패스워드를 읽고 검증하되, 새 패스워드는 Argon2나 Bcrypt 같은 다른 알고리즘으로 해싱하도록 할 수 있습니다.\n\n그리고 동시에 그 모든 것과 호환되게 만들 수 있습니다.\n\n///\n\n사용자로부터 받은 패스워드를 해싱하는 유틸리티 함수를 생성합니다.\n\n그리고 받은 패스워드가 저장된 해시와 일치하는지 검증하는 또 다른 유틸리티도 생성합니다.\n\n그리고 사용자를 인증하고 반환하는 또 다른 함수도 생성합니다.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\n`authenticate_user`가 데이터베이스에 존재하지 않는 사용자이름으로 호출되더라도, 여전히 `verify_password`를 더미 해시에 대해 실행합니다.\n\n이렇게 하면 사용자이름이 유효하든 아니든 엔드포인트가 응답하는 데 걸리는 시간이 대략 동일해져, 기존 사용자이름을 열거하는 데 악용될 수 있는 **타이밍 공격**을 방지합니다.\n\n/// note | 참고\n\n새로운 (가짜) 데이터베이스 `fake_users_db`를 확인하면, 이제 해시 처리된 패스워드가 어떻게 생겼는지 볼 수 있습니다: `\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`.\n\n///\n\n## JWT 토큰 처리 { #handle-jwt-tokens }\n\n설치된 모듈을 임포트합니다.\n\nJWT 토큰을 서명하는 데 사용할 임의의 비밀 키를 생성합니다.\n\n안전한 임의의 비밀 키를 생성하려면 다음 명령을 사용하십시오:\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\n그리고 출력 결과를 변수 `SECRET_KEY`에 복사합니다(예제의 값을 사용하지 마십시오).\n\nJWT 토큰을 서명하는 데 사용될 알고리즘을 위한 변수 `ALGORITHM`을 생성하고 `\"HS256\"`으로 설정합니다.\n\n토큰 만료를 위한 변수를 생성합니다.\n\n응답을 위해 토큰 엔드포인트에서 사용될 Pydantic 모델을 정의합니다.\n\n새 액세스 토큰을 생성하기 위한 유틸리티 함수를 생성합니다.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## 의존성 업데이트 { #update-the-dependencies }\n\n`get_current_user`가 이전과 동일한 토큰을 받도록 업데이트하되, 이번에는 JWT 토큰을 사용하도록 합니다.\n\n받은 토큰을 디코딩하고 검증한 뒤 현재 사용자를 반환합니다.\n\n토큰이 유효하지 않다면 즉시 HTTP 오류를 반환합니다.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## `/token` *경로 처리* 업데이트 { #update-the-token-path-operation }\n\n토큰의 만료 시간으로 `timedelta`를 생성합니다.\n\n실제 JWT 액세스 토큰을 생성하여 반환합니다.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### JWT \"주체(subject)\" `sub`에 대한 기술 세부사항 { #technical-details-about-the-jwt-subject-sub }\n\nJWT 명세에 따르면 토큰의 주체를 담는 `sub` 키가 있습니다.\n\n선택적으로 사용할 수 있지만, 여기에 사용자 식별 정보를 넣게 되므로 여기서는 이를 사용합니다.\n\nJWT는 사용자를 식별하고 사용자가 API에서 직접 작업을 수행할 수 있도록 허용하는 것 외에도 다른 용도로 사용될 수 있습니다.\n\n예를 들어 \"자동차\"나 \"블로그 게시물\"을 식별할 수 있습니다.\n\n그런 다음 해당 엔터티에 대한 권한(자동차의 경우 \"drive\", 블로그의 경우 \"edit\" 등)을 추가할 수 있습니다.\n\n그리고 그 JWT 토큰을 사용자(또는 봇)에게 제공하면, 계정이 없어도 API가 생성한 JWT 토큰만으로 그 동작들(자동차 운전, 블로그 편집)을 수행할 수 있습니다.\n\n이러한 아이디어를 활용하면 JWT는 훨씬 더 정교한 시나리오에도 사용될 수 있습니다.\n\n그런 경우 여러 엔터티가 동일한 ID(예: `foo`)를 가질 수도 있습니다(사용자 `foo`, 자동차 `foo`, 블로그 게시물 `foo`).\n\n따라서 ID 충돌을 방지하기 위해, 사용자에 대한 JWT 토큰을 생성할 때 `sub` 키의 값에 접두사를 붙일 수 있습니다. 예를 들어 `username:` 같은 것입니다. 그러면 이 예제에서 `sub` 값은 `username:johndoe`가 될 수 있습니다.\n\n기억해야 할 중요한 점은 `sub` 키가 전체 애플리케이션에서 고유한 식별자여야 하고, 문자열이어야 한다는 것입니다.\n\n## 확인하기 { #check-it }\n\n서버를 실행하고 문서로 이동하십시오: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n다음과 같은 사용자 인터페이스가 보일 것입니다:\n\n<img src=\"/img/tutorial/security/image07.png\">\n\n이전과 같은 방법으로 애플리케이션을 인가하십시오.\n\n다음 인증 정보를 사용하십시오:\n\nUsername: `johndoe`\nPassword: `secret`\n\n/// check | 확인\n\n코드 어디에도 평문 패스워드 \"`secret`\"은 없고, 해시된 버전만 있다는 점에 유의하십시오.\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\n엔드포인트 `/users/me/`를 호출하면 다음과 같은 응답을 받게 됩니다:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\n개발자 도구를 열어보면 전송된 데이터에는 토큰만 포함되어 있고, 패스워드는 사용자를 인증하고 해당 액세스 토큰을 얻기 위한 첫 번째 요청에서만 전송되며 이후에는 전송되지 않는 것을 확인할 수 있습니다:\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | 참고\n\n`Bearer `로 시작하는 값을 가진 `Authorization` 헤더에 주목하십시오.\n\n///\n\n## `scopes`의 고급 사용법 { #advanced-usage-with-scopes }\n\nOAuth2에는 \"scopes\"라는 개념이 있습니다.\n\n이를 사용해 JWT 토큰에 특정 권한 집합을 추가할 수 있습니다.\n\n그런 다음 이 토큰을 사용자에게 직접 제공하거나 제3자에게 제공하여, 특정 제한사항 하에서 API와 상호작용하도록 할 수 있습니다.\n\n어떻게 사용하는지, 그리고 **FastAPI**에 어떻게 통합되는지는 이후 **심화 사용자 안내서**에서 배울 수 있습니다.\n\n## 요약 { #recap }\n\n지금까지 살펴본 내용을 바탕으로, OAuth2와 JWT 같은 표준을 사용해 안전한 **FastAPI** 애플리케이션을 설정할 수 있습니다.\n\n거의 모든 프레임워크에서 보안 처리는 꽤 빠르게 복잡한 주제가 됩니다.\n\n이를 크게 단순화하는 많은 패키지들은 데이터 모델, 데이터베이스, 사용 가능한 기능들에 대해 많은 타협을 해야 합니다. 그리고 지나치게 단순화하는 일부 패키지들은 실제로 내부에 보안 결함이 있기도 합니다.\n\n---\n\n**FastAPI**는 어떤 데이터베이스, 데이터 모델, 도구에도 타협하지 않습니다.\n\n프로젝트에 가장 잘 맞는 것들을 선택할 수 있는 모든 유연성을 제공합니다.\n\n그리고 **FastAPI**는 외부 패키지를 통합하기 위해 복잡한 메커니즘을 요구하지 않기 때문에 `pwdlib`와 `PyJWT` 같은 잘 관리되고 널리 사용되는 패키지들을 바로 사용할 수 있습니다.\n\n하지만 유연성, 견고성, 보안성을 해치지 않으면서 과정을 가능한 한 단순화할 수 있도록 도구들을 제공합니다.\n\n또한 OAuth2 같은 안전한 표준 프로토콜을 비교적 간단한 방식으로 사용하고 구현할 수 있습니다.\n\n더 세분화된 권한 시스템을 위해 OAuth2 \"scopes\"를 사용하는 방법은, 같은 표준을 따르는 방식으로 **심화 사용자 안내서**에서 더 자세히 배울 수 있습니다. 스코프를 사용하는 OAuth2는 Facebook, Google, GitHub, Microsoft, X (Twitter) 등 많은 대형 인증 제공업체들이 제3자 애플리케이션이 사용자 대신 그들의 API와 상호작용할 수 있도록 인가하는 데 사용하는 메커니즘입니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/security/simple-oauth2.md",
    "content": "# 패스워드와 Bearer를 이용한 간단한 OAuth2 { #simple-oauth2-with-password-and-bearer }\n\n이제 이전 장에서 빌드하고 누락된 부분을 추가하여 완전한 보안 흐름을 갖도록 하겠습니다.\n\n## `username`와 `password` 얻기 { #get-the-username-and-password }\n\n**FastAPI** 보안 유틸리티를 사용하여 `username` 및 `password`를 가져올 것입니다.\n\nOAuth2는 (우리가 사용하고 있는) \"패스워드 플로우\"을 사용할 때 클라이언트/유저가 `username` 및 `password` 필드를 폼 데이터로 보내야 함을 지정합니다.\n\n그리고 사양에는 필드의 이름을 그렇게 지정해야 한다고 나와 있습니다. 따라서 `user-name` 또는 `email`은 작동하지 않습니다.\n\n하지만 걱정하지 않아도 됩니다. 프런트엔드에서 최종 사용자에게 원하는 대로 표시할 수 있습니다.\n\n그리고 데이터베이스 모델은 원하는 다른 이름을 사용할 수 있습니다.\n\n그러나 로그인 *경로 처리*의 경우 사양과 호환되도록 이러한 이름을 사용해야 합니다(예를 들어 통합 API 문서 시스템을 사용할 수 있어야 합니다).\n\n사양에는 또한 `username`과 `password`가 폼 데이터로 전송되어야 한다고 명시되어 있습니다(따라서 여기에는 JSON이 없습니다).\n\n### `scope` { #scope }\n\n사양에는 클라이언트가 다른 폼 필드 \"`scope`\"를 보낼 수 있다고 나와 있습니다.\n\n폼 필드 이름은 `scope`(단수형)이지만 실제로는 공백으로 구분된 \"범위\"가 있는 긴 문자열입니다.\n\n각 \"범위\"는 공백이 없는 문자열입니다.\n\n일반적으로 특정 보안 권한을 선언하는 데 사용됩니다. 다음을 봅시다:\n\n* `users:read` 또는 `users:write`는 일반적인 예시입니다.\n* `instagram_basic`은 페이스북/인스타그램에서 사용합니다.\n* `https://www.googleapis.com/auth/drive`는 Google에서 사용합니다.\n\n/// info | 정보\n\nOAuth2에서 \"범위\"는 필요한 특정 권한을 선언하는 문자열입니다.\n\n`:`과 같은 다른 문자가 있는지 또는 URL인지는 중요하지 않습니다.\n\n이러한 세부 사항은 구현에 따라 다릅니다.\n\nOAuth2의 경우 문자열일 뿐입니다.\n\n///\n\n## `username`과 `password`를 가져오는 코드 { #code-to-get-the-username-and-password }\n\n이제 **FastAPI**에서 제공하는 유틸리티를 사용하여 이를 처리해 보겠습니다.\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\n먼저 `OAuth2PasswordRequestForm`을 가져와 `/token`에 대한 *경로 처리*에서 `Depends`의 의존성으로 사용합니다.\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm`은 다음을 사용하여 폼 본문을 선언하는 클래스 의존성입니다:\n\n* `username`.\n* `password`.\n* `scope`는 선택적인 필드로 공백으로 구분된 문자열로 구성된 큰 문자열입니다.\n* `grant_type`(선택적으로 사용).\n\n/// tip | 팁\n\nOAuth2 사양은 실제로 `password`라는 고정 값이 있는 `grant_type` 필드를 *요구*하지만 `OAuth2PasswordRequestForm`은 이를 강요하지 않습니다.\n\n사용해야 한다면 `OAuth2PasswordRequestForm` 대신 `OAuth2PasswordRequestFormStrict`를 사용하면 됩니다.\n\n///\n\n* `client_id`(선택적으로 사용) (예제에서는 필요하지 않습니다).\n* `client_secret`(선택적으로 사용) (예제에서는 필요하지 않습니다).\n\n/// info | 정보\n\n`OAuth2PasswordRequestForm`은 `OAuth2PasswordBearer`와 같이 **FastAPI**에 대한 특수 클래스가 아닙니다.\n\n`OAuth2PasswordBearer`는 **FastAPI**가 보안 체계임을 알도록 합니다. 그래서 OpenAPI에 그렇게 추가됩니다.\n\n그러나 `OAuth2PasswordRequestForm`은 직접 작성하거나 `Form` 매개변수를 직접 선언할 수 있는 클래스 의존성일 뿐입니다.\n\n그러나 일반적인 사용 사례이므로 더 쉽게 하기 위해 **FastAPI**에서 직접 제공합니다.\n\n///\n\n### 폼 데이터 사용하기 { #use-the-form-data }\n\n/// tip | 팁\n\n종속성 클래스 `OAuth2PasswordRequestForm`의 인스턴스에는 공백으로 구분된 긴 문자열이 있는 `scope` 속성이 없고 대신 전송된 각 범위에 대한 실제 문자열 목록이 있는 `scopes` 속성이 있습니다.\n\n이 예제에서는 `scopes`를 사용하지 않지만 필요한 경우, 기능이 있습니다.\n\n///\n\n이제 폼 필드의 `username`을 사용하여 (가짜) 데이터베이스에서 유저 데이터를 가져옵니다.\n\n해당 사용자가 없으면 \"잘못된 사용자 이름 또는 패스워드\"라는 오류가 반환됩니다.\n\n오류의 경우 `HTTPException` 예외를 사용합니다:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### 패스워드 확인하기 { #check-the-password }\n\n이 시점에서 데이터베이스의 사용자 데이터 형식을 확인했지만 암호를 확인하지 않았습니다.\n\n먼저 데이터를 Pydantic `UserInDB` 모델에 넣겠습니다.\n\n일반 텍스트 암호를 저장하면 안 되니 (가짜) 암호 해싱 시스템을 사용합니다.\n\n두 패스워드가 일치하지 않으면 동일한 오류가 반환됩니다.\n\n#### 패스워드 해싱 { #password-hashing }\n\n\"해싱\"은 일부 콘텐츠(이 경우 패스워드)를 횡설수설하는 것처럼 보이는 일련의 바이트(문자열)로 변환하는 것을 의미합니다.\n\n정확히 동일한 콘텐츠(정확히 동일한 패스워드)를 전달할 때마다 정확히 동일한 횡설수설이 발생합니다.\n\n그러나 횡설수설에서 암호로 다시 변환할 수는 없습니다.\n\n##### 패스워드 해싱을 사용해야 하는 이유 { #why-use-password-hashing }\n\n데이터베이스가 유출된 경우 해커는 사용자의 일반 텍스트 암호가 아니라 해시만 갖게 됩니다.\n\n따라서 해커는 다른 시스템에서 동일한 암호를 사용하려고 시도할 수 없습니다(많은 사용자가 모든 곳에서 동일한 암호를 사용하므로 이는 위험할 수 있습니다).\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### `**user_dict`에 대해 { #about-user-dict }\n\n`UserInDB(**user_dict)`는 다음을 의미한다:\n\n*`user_dict`의 키와 값을 다음과 같은 키-값 인수로 직접 전달합니다:*\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info | 정보\n\n`**user_dict`에 대한 자세한 설명은 [**추가 모델** 문서](../extra-models.md#about-user-in-dict)를 다시 확인해보세요.\n\n///\n\n## 토큰 반환하기 { #return-the-token }\n\n`token` 엔드포인트의 응답은 JSON 객체여야 합니다.\n\n`token_type`이 있어야 합니다. 여기서는 \"Bearer\" 토큰을 사용하므로 토큰 유형은 \"`bearer`\"여야 합니다.\n\n그리고 액세스 토큰을 포함하는 문자열과 함께 `access_token`이 있어야 합니다.\n\n이 간단한 예제에서는 완전히 안전하지 않고, 동일한 `username`을 토큰으로 반환합니다.\n\n/// tip | 팁\n\n다음 장에서는 패스워드 해싱 및 <abbr title=\"JSON Web Tokens - JSON 웹 토큰\">JWT</abbr> 토큰을 사용하여 실제 보안 구현을 볼 수 있습니다.\n\n하지만 지금은 필요한 세부 정보에 집중하겠습니다.\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip | 팁\n\n사양에 따라 이 예제와 동일하게 `access_token` 및 `token_type`이 포함된 JSON을 반환해야 합니다.\n\n이는 코드에서 직접 수행해야 하며 해당 JSON 키를 사용해야 합니다.\n\n사양을 준수하기 위해 스스로 올바르게 수행하기 위해 거의 유일하게 기억해야 하는 것입니다.\n\n나머지는 **FastAPI**가 처리합니다.\n\n///\n\n## 의존성 업데이트하기 { #update-the-dependencies }\n\n이제 의존성을 업데이트를 할 겁니다.\n\n이 사용자가 활성화되어 있는 *경우에만* `current_user`를 가져올 겁니다.\n\n따라서 `get_current_user`를 의존성으로 사용하는 추가 의존성 `get_current_active_user`를 만듭니다.\n\n이러한 의존성 모두, 사용자가 존재하지 않거나 비활성인 경우 HTTP 오류를 반환합니다.\n\n따라서 엔드포인트에서는 사용자가 존재하고 올바르게 인증되었으며 활성 상태인 경우에만 사용자를 얻습니다:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info | 정보\n\n여기서 반환하는 값이 `Bearer`인 추가 헤더 `WWW-Authenticate`도 사양의 일부입니다.\n\n모든 HTTP(오류) 상태 코드 401 \"UNAUTHORIZED\"는 `WWW-Authenticate` 헤더도 반환해야 합니다.\n\n베어러 토큰의 경우(지금의 경우) 해당 헤더의 값은 `Bearer`여야 합니다.\n\n실제로 추가 헤더를 건너뛸 수 있으며 여전히 작동합니다.\n\n그러나 여기에서는 사양을 준수하도록 제공됩니다.\n\n또한 이를 예상하고 (현재 또는 미래에) 사용하는 도구가 있을 수 있으며, 현재 또는 미래에 자신 혹은 자신의 유저들에게 유용할 것입니다.\n\n그것이 표준의 이점입니다 ...\n\n///\n\n## 확인하기 { #see-it-in-action }\n\n대화형 문서 열기: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n### 인증하기 { #authenticate }\n\n\"Authorize\" 버튼을 눌러봅시다.\n\n자격 증명을 사용합니다.\n\n유저명: `johndoe`\n\n패스워드: `secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\n시스템에서 인증하면 다음과 같이 표시됩니다:\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### 자신의 유저 데이터 가져오기 { #get-your-own-user-data }\n\n이제 `/users/me` 경로에 `GET` 작업을 진행합시다.\n\n다음과 같은 사용자 데이터를 얻을 수 있습니다:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\n잠금 아이콘을 클릭하고 로그아웃한 다음 동일한 작업을 다시 시도하면 다음과 같은 HTTP 401 오류가 발생합니다.\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### 비활성된 유저 { #inactive-user }\n\n이제 비활성된 사용자로 시도하고, 인증해봅시다:\n\n유저명: `alice`\n\n패스워드: `secret2`\n\n그리고 `/users/me` 경로와 함께 `GET` 작업을 사용해 봅시다.\n\n다음과 같은 \"Inactive user\" 오류가 발생합니다:\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## 요약 { #recap }\n\n이제 API에 대한 `username` 및 `password`를 기반으로 완전한 보안 시스템을 구현할 수 있는 도구가 있습니다.\n\n이러한 도구를 사용하여 보안 시스템을 모든 데이터베이스 및 모든 사용자 또는 데이터 모델과 호환되도록 만들 수 있습니다.\n\n유일한 오점은 아직 실제로 \"안전\"하지 않다는 것입니다.\n\n다음 장에서는 안전한 패스워드 해싱 라이브러리와 <abbr title=\"JSON Web Tokens - JSON 웹 토큰\">JWT</abbr> 토큰을 사용하는 방법을 살펴보겠습니다.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/server-sent-events.md",
    "content": "# 서버 전송 이벤트(SSE) { #server-sent-events-sse }\n\n브라우저 클라이언트로 데이터를 스트리밍하려면 **Server-Sent Events**(SSE)를 사용할 수 있습니다.\n\n이는 [JSON Lines 스트리밍](stream-json-lines.md)과 비슷하지만, 브라우저가 기본적으로 [`EventSource` API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource)를 통해 지원하는 `text/event-stream` 형식을 사용합니다.\n\n/// info | 정보\n\nFastAPI 0.135.0에 추가되었습니다.\n\n///\n\n## Server-Sent Events란 { #what-are-server-sent-events }\n\nSSE는 서버에서 클라이언트로 HTTP를 통해 데이터를 스트리밍하기 위한 표준입니다.\n\n각 이벤트는 `data`, `event`, `id`, `retry`와 같은 \"필드\"를 가진 작은 텍스트 블록이며, 빈 줄로 구분됩니다.\n\n다음과 같습니다:\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE는 AI 채팅 스트리밍, 실시간 알림, 로그와 관측성, 그리고 서버가 클라이언트로 업데이트를 푸시하는 여러 경우에 흔히 사용됩니다.\n\n/// tip | 팁\n\n비디오나 오디오처럼 바이너리 데이터를 스트리밍하려면 고급 가이드: [데이터 스트리밍](../advanced/stream-data.md)을 확인하세요.\n\n///\n\n## FastAPI로 SSE 스트리밍 { #stream-sse-with-fastapi }\n\nFastAPI에서 SSE를 스트리밍하려면, 경로 처리 함수에서 `yield`를 사용하고 `response_class=EventSourceResponse`를 설정하세요.\n\n`EventSourceResponse`는 `fastapi.sse`에서 임포트합니다:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\n각 `yield`된 항목은 JSON으로 인코딩되어 SSE 이벤트의 `data:` 필드로 전송됩니다.\n\n반환 타입을 `AsyncIterable[Item]`으로 선언하면 FastAPI가 이를 사용해 데이터를 Pydantic으로 **검증**, **문서화**, **직렬화**합니다.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip | 팁\n\nPydantic이 **Rust** 쪽에서 직렬화하므로, 반환 타입을 선언하지 않았을 때보다 훨씬 더 높은 **성능**을 얻을 수 있습니다.\n\n///\n\n### 비 async *경로 처리 함수* { #non-async-path-operation-functions }\n\n`async`가 없는 일반 `def` 함수도 사용할 수 있으며, 동일하게 `yield`를 사용할 수 있습니다.\n\nFastAPI가 이벤트 루프를 막지 않도록 올바르게 실행을 보장합니다.\n\n이 경우 함수가 async가 아니므로 적절한 반환 타입은 `Iterable[Item]`입니다:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### 반환 타입 없음 { #no-return-type }\n\n반환 타입을 생략할 수도 있습니다. FastAPI는 [`jsonable_encoder`](./encoder.md)를 사용해 데이터를 변환하고 전송합니다.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\n`event`, `id`, `retry`, `comment` 같은 SSE 필드를 설정해야 한다면, 일반 데이터 대신 `ServerSentEvent` 객체를 `yield`할 수 있습니다.\n\n`ServerSentEvent`는 `fastapi.sse`에서 임포트합니다:\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\n`data` 필드는 항상 JSON으로 인코딩됩니다. Pydantic 모델을 포함해 JSON으로 직렬화할 수 있는 값을 모두 전달할 수 있습니다.\n\n## 원시 데이터 { #raw-data }\n\nJSON 인코딩 없이 데이터를 보내야 한다면, `data` 대신 `raw_data`를 사용하세요.\n\n미리 포맷된 텍스트, 로그 라인, 또는 `[DONE]`과 같은 특수한 <dfn title=\"특수한 조건이나 상태를 나타내는 데 사용되는 값\">\"센티널\"</dfn> 값을 보낼 때 유용합니다.\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note | 참고\n\n`data`와 `raw_data`는 상호 배타적입니다. 각 `ServerSentEvent`에는 이 둘 중 하나만 설정할 수 있습니다.\n\n///\n\n## `Last-Event-ID`로 재개하기 { #resuming-with-last-event-id }\n\n브라우저가 연결이 끊긴 후 재연결할 때, 마지막으로 받은 `id`를 `Last-Event-ID` 헤더에 담아 보냅니다.\n\n헤더 파라미터로 이를 읽어와 클라이언트가 중단한 지점부터 스트림을 재개할 수 있습니다:\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## POST로 SSE 사용하기 { #sse-with-post }\n\nSSE는 `GET`뿐만 아니라 **모든 HTTP 메서드**와 함께 동작합니다.\n\n이는 `POST`로 SSE를 스트리밍하는 [MCP](https://modelcontextprotocol.io) 같은 프로토콜에 유용합니다:\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## 기술 세부사항 { #technical-details }\n\nFastAPI는 일부 SSE 모범 사례를 기본으로 구현합니다.\n\n- 메시지가 없을 때는 15초마다 **\"keep alive\" `ping` 주석**을 보내 일부 프록시가 연결을 종료하지 않도록 합니다. [HTML 사양: Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes)에서 권장합니다.\n- 스트림이 **캐시되지 않도록** `Cache-Control: no-cache` 헤더를 설정합니다.\n- Nginx 같은 일부 프록시에서 **버퍼링을 방지**하기 위해 특수 헤더 `X-Accel-Buffering: no`를 설정합니다.\n\n여러분이 따로 할 일은 없습니다. 기본값으로 동작합니다. 🤓\n"
  },
  {
    "path": "docs/ko/docs/tutorial/sql-databases.md",
    "content": "# SQL (관계형) 데이터베이스 { #sql-relational-databases }\n\n**FastAPI**에서 SQL(관계형) 데이터베이스 사용은 필수가 아닙니다. 하지만 여러분이 원하는 **어떤 데이터베이스든** 사용할 수 있습니다.\n\n여기서는 [SQLModel](https://sqlmodel.tiangolo.com/)을 사용하는 예제를 살펴보겠습니다.\n\n**SQLModel**은 [SQLAlchemy](https://www.sqlalchemy.org/)와 Pydantic을 기반으로 구축되었습니다. **SQL 데이터베이스**를 사용해야 하는 FastAPI 애플리케이션에 완벽히 어울리도록 **FastAPI**와 같은 제작자가 만든 도구입니다.\n\n/// tip | 팁\n\n다른 SQL 또는 NoSQL 데이터베이스 라이브러리를 사용할 수도 있습니다 (일부는 <abbr title=\"Object Relational Mapper - 객체-관계 매퍼: 일부 클래스는 SQL 테이블을, 인스턴스는 해당 테이블의 행을 나타내는 라이브러리를 가리키는 용어\">\"ORMs\"</abbr>이라고도 불립니다), FastAPI는 특정 라이브러리의 사용을 강요하지 않습니다. 😎\n\n///\n\nSQLModel은 SQLAlchemy를 기반으로 하므로, SQLAlchemy에서 **지원하는 모든 데이터베이스**를 손쉽게 사용할 수 있습니다(이것들은 SQLModel에서도 지원됩니다). 예를 들면:\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server 등.\n\n이 예제에서는 **SQLite**를 사용합니다. SQLite는 단일 파일을 사용하고 Python에서 통합 지원하기 때문입니다. 따라서 이 예제를 그대로 복사하여 실행할 수 있습니다.\n\n나중에 프로덕션 애플리케이션에서는 **PostgreSQL**과 같은 데이터베이스 서버를 사용하는 것이 좋습니다.\n\n/// tip | 팁\n\n프론트엔드와 더 많은 도구를 포함하여 **FastAPI**와 **PostgreSQL**을 포함한 공식 프로젝트 생성기가 있습니다: [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\n이 튜토리얼은 매우 간단하고 짧습니다. 데이터베이스 기본 개념, SQL, 또는 더 고급 기능에 대해 배우고 싶다면, [SQLModel 문서](https://sqlmodel.tiangolo.com/)를 참고하세요.\n\n## `SQLModel` 설치하기 { #install-sqlmodel }\n\n먼저, [가상 환경](../virtual-environments.md)을 생성하고 활성화한 다음, `sqlmodel`을 설치하세요:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## 단일 모델로 애플리케이션 생성하기 { #create-the-app-with-a-single-model }\n\n우선 단일 **SQLModel** 모델을 사용하여 애플리케이션의 가장 간단한 첫 번째 버전을 생성해보겠습니다.\n\n이후 아래에서 **여러 모델**로 보안과 유연성을 강화하며 개선하겠습니다. 🤓\n\n### 모델 생성하기 { #create-models }\n\n`SQLModel`을 가져오고 데이터베이스 모델을 생성합니다:\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\n`Hero` 클래스는 Pydantic 모델과 매우 유사합니다 (실제로 내부적으로 *Pydantic 모델이기도 합니다*).\n\n몇 가지 차이점이 있습니다:\n\n* `table=True`는 SQLModel에 이 모델이 *테이블 모델*이며, SQL 데이터베이스의 **테이블**을 나타내야 한다는 것을 알려줍니다. (다른 일반적인 Pydantic 클래스처럼) 단순한 *데이터 모델*이 아닙니다.\n\n* `Field(primary_key=True)`는 SQLModel에 `id`가 SQL 데이터베이스의 **기본 키**임을 알려줍니다 (SQL 기본 키에 대한 자세한 내용은 SQLModel 문서를 참고하세요).\n\n    **참고:** 기본 키 필드에 `int | None`을 사용하는 이유는, Python 코드에서 *`id` 없이 객체를 생성*할 수 있게 하기 위해서입니다(`id=None`). 데이터베이스가 *저장할 때 생성해 줄 것*이라고 가정합니다. SQLModel은 데이터베이스가 `id`를 제공한다는 것을 이해하고, 데이터베이스 스키마에서 *해당 열을 null이 아닌 `INTEGER`*로 정의합니다. 자세한 내용은 [기본 키에 대한 SQLModel 문서](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id)를 참고하세요.\n\n* `Field(index=True)`는 SQLModel에 해당 열에 대해 **SQL 인덱스**를 생성하도록 지시합니다. 이를 통해 데이터베이스에서 이 열로 필터링된 데이터를 읽을 때 더 빠르게 조회할 수 있습니다.\n\n    SQLModel은 `str`으로 선언된 항목이 SQL 데이터베이스에서 `TEXT` (또는 데이터베이스에 따라 `VARCHAR`) 유형의 열로 저장된다는 것을 인식합니다.\n\n### 엔진 생성하기 { #create-an-engine }\n\nSQLModel의 `engine` (내부적으로는 SQLAlchemy `engine`)은 데이터베이스에 대한 **연결을 유지**하는 역할을 합니다.\n\n코드 전체에서 동일한 데이터베이스에 연결하기 위해 **하나의 단일 `engine` 객체**를 사용합니다.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\n`check_same_thread=False`를 사용하면 FastAPI에서 여러 스레드에서 동일한 SQLite 데이터베이스를 사용할 수 있습니다. 이는 **하나의 단일 요청**이 **둘 이상의 스레드**를 사용할 수 있기 때문에 필요합니다(예: 의존성에서 사용되는 경우).\n\n걱정하지 마세요. 코드가 구조화된 방식으로 인해, 이후에 **각 요청마다 단일 SQLModel *세션*을 사용**하도록 보장할 것입니다. 실제로 이것이 `check_same_thread`가 하려는 것입니다.\n\n### 테이블 생성하기 { #create-the-tables }\n\n그 다음 `SQLModel.metadata.create_all(engine)`을 사용하여 모든 *테이블 모델*의 **테이블을 생성**하는 함수를 추가합니다.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### 세션 의존성 생성하기 { #create-a-session-dependency }\n\n**`Session`**은 **메모리에 객체**를 저장하고 데이터에 필요한 모든 변경 사항을 추적한 후, **`engine`을 통해** 데이터베이스와 통신합니다.\n\n`yield`를 사용해 FastAPI의 **의존성**을 생성하여 각 요청마다 새로운 `Session`을 제공합니다. 이는 요청당 하나의 세션만 사용되도록 보장합니다. 🤓\n\n그런 다음 이 의존성을 사용하는 나머지 코드를 간소화하기 위해 `Annotated` 의존성 `SessionDep`을 생성합니다.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### 시작 시 데이터베이스 테이블 생성하기 { #create-database-tables-on-startup }\n\n애플리케이션 시작 시 데이터베이스 테이블을 생성합니다.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\n여기서는 애플리케이션 시작 이벤트 시 테이블을 생성합니다.\n\n프로덕션 환경에서는 애플리케이션을 시작하기 전에 실행되는 마이그레이션 스크립트를 사용할 가능성이 높습니다. 🤓\n\n/// tip | 팁\n\nSQLModel은 Alembic을 감싸는 마이그레이션 유틸리티를 제공할 예정입니다. 하지만 현재 [Alembic](https://alembic.sqlalchemy.org/en/latest/)을 직접 사용할 수 있습니다.\n\n///\n\n### Hero 생성하기 { #create-a-hero }\n\n각 SQLModel 모델은 Pydantic 모델이기도 하므로, Pydantic 모델을 사용할 수 있는 동일한 **타입 어노테이션**에서 사용할 수 있습니다.\n\n예를 들어, 파라미터를 `Hero` 타입으로 선언하면 **JSON 본문**에서 값을 읽어옵니다.\n\n마찬가지로, 함수의 **반환 타입**으로 선언하면 해당 데이터의 구조가 자동으로 생성되는 API 문서의 UI에 나타납니다.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\n여기서는 `SessionDep` 의존성(`Session`)을 사용하여 새로운 `Hero`를 `Session` 인스턴스에 추가하고, 데이터베이스에 변경 사항을 커밋하고, `hero` 데이터의 최신 상태를 갱신한 다음 이를 반환합니다.\n\n### Heroes 조회하기 { #read-heroes }\n\n`select()`를 사용하여 데이터베이스에서 `Hero`를 **조회**할 수 있습니다. 결과에 페이지네이션을 적용하기 위해 `limit`와 `offset`을 포함할 수 있습니다.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### 단일 Hero 조회하기 { #read-one-hero }\n\n단일 `Hero`를 **조회**할 수도 있습니다.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### Hero 삭제하기 { #delete-a-hero }\n\n`Hero`를 **삭제**하는 것도 가능합니다.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### 애플리케이션 실행하기 { #run-the-app }\n\n애플리케이션을 실행할 수 있습니다:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n그런 다음 `/docs` UI로 이동하면, **FastAPI**가 이 **모델**들을 사용해 API를 **문서화**하고, 데이터를 **직렬화**하고 **검증**하는 데에도 사용하는 것을 확인할 수 있습니다.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## 여러 모델로 애플리케이션 업데이트 { #update-the-app-with-multiple-models }\n\n이제 이 애플리케이션을 약간 **리팩터링**하여 **보안**과 **유연성**을 개선해 보겠습니다.\n\n이전 애플리케이션을 확인해 보면, 지금까지는 UI에서 클라이언트가 생성할 `Hero`의 `id`를 결정할 수 있게 되어 있는 것을 볼 수 있습니다. 😱\n\n이렇게 해서는 안 됩니다. 클라이언트가 DB에 이미 할당되어 있는 `id`를 덮어쓸 수 있기 때문입니다. `id`를 결정하는 것은 **백엔드** 또는 **데이터베이스**가 해야 하며, **클라이언트**가 해서는 안 됩니다.\n\n또한 hero에 대한 `secret_name`을 생성하지만, 지금까지는 이 값을 어디에서나 반환하고 있습니다. 이는 그다지 **비밀스럽지** 않습니다... 😅\n\n이러한 문제는 몇 가지 **추가 모델**을 추가해 해결하겠습니다. 바로 여기서 SQLModel이 빛을 발하게 됩니다. ✨\n\n### 여러 모델 생성하기 { #create-multiple-models }\n\n**SQLModel**에서 `table=True`가 설정된 모델 클래스는 **테이블 모델**입니다.\n\n그리고 `table=True`가 없는 모델 클래스는 **데이터 모델**인데, 이것들은 실제로는 (몇 가지 작은 추가 기능이 있는) Pydantic 모델일 뿐입니다. 🤓\n\nSQLModel을 사용하면 **상속**을 통해 모든 경우에 필드를 **중복 선언하지 않아도** 됩니다.\n\n#### `HeroBase` - 기본 클래스 { #herobase-the-base-class }\n\n모든 모델에서 **공유되는 필드**를 가진 `HeroBase` 모델을 시작해 봅시다:\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` - *테이블 모델* { #hero-the-table-model }\n\n다음으로 실제 *테이블 모델*인 `Hero`를 생성합니다. 이 모델은 다른 모델에는 항상 포함되는 건 아닌 **추가 필드**를 포함합니다:\n\n* `id`\n* `secret_name`\n\n`Hero`는 `HeroBase`를 상속하므로 `HeroBase`에 선언된 필드도 **또한** 포함합니다. 따라서 `Hero`의 모든 필드는 다음과 같습니다:\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` - 공개 *데이터 모델* { #heropublic-the-public-data-model }\n\n다음으로 `HeroPublic` 모델을 생성합니다. 이 모델은 API 클라이언트에 **반환**되는 모델입니다.\n\n`HeroPublic`은 `HeroBase`와 동일한 필드를 가지므로, `secret_name`은 포함하지 않습니다.\n\n마침내 우리의 heroes의 정체가 보호됩니다! 🥷\n\n또한 `id: int`를 다시 선언합니다. 이를 통해, API 클라이언트와 **계약**을 맺어 `id`가 항상 존재하며 항상 `int` 타입이라는 것을 보장합니다(`None`이 될 수 없습니다).\n\n/// tip | 팁\n\n반환 모델이 값이 항상 존재하고 항상 `int`(`None`이 아님)를 보장하는 것은 API 클라이언트에게 매우 유용합니다. 이를 통해 API 클라이언트는 이런 확신을 바탕으로 훨씬 더 간단한 코드를 작성할 수 있습니다.\n\n또한 **자동으로 생성된 클라이언트**는 더 단순한 인터페이스를 제공하므로, API와 소통하는 개발자들이 API를 사용하면서 훨씬 더 좋은 경험을 할 수 있습니다. 😎\n\n///\n\n`HeroPublic`의 모든 필드는 `HeroBase`와 동일하며, `id`는 `int`로 선언됩니다(`None`이 아님):\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` - hero 생성용 *데이터 모델* { #herocreate-the-data-model-to-create-a-hero }\n\n이제 `HeroCreate` 모델을 생성합니다. 이 모델은 클라이언트로부터 받은 데이터를 **검증**하는 역할을 합니다.\n\n`HeroCreate`는 `HeroBase`와 동일한 필드를 가지며, `secret_name`도 포함합니다.\n\n이제 클라이언트가 **새 hero를 생성**할 때 `secret_name`을 보내면, 데이터베이스에 저장되지만, 그 비밀 이름은 API를 통해 클라이언트에게 반환되지 않습니다.\n\n/// tip | 팁\n\n이 방식은 **비밀번호**를 처리하는 방법과 동일합니다. 비밀번호를 받지만, 이를 API에서 반환하지는 않습니다.\n\n또한 비밀번호 값을 저장하기 전에 **해싱**하여 저장하고, **평문으로 저장하지 마십시오**.\n\n///\n\n`HeroCreate`의 필드는 다음과 같습니다:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` - hero 수정용 *데이터 모델* { #heroupdate-the-data-model-to-update-a-hero }\n\n이전 버전의 애플리케이션에서는 **hero를 수정**할 방법이 없었지만, 이제 **여러 모델**로 이를 할 수 있습니다. 🎉\n\n`HeroUpdate` *데이터 모델*은 약간 특별한데, 새 hero를 생성할 때 필요한 **모든 동일한 필드**를 가지지만, 모든 필드가 **선택적**(기본값이 있음)입니다. 이렇게 하면 hero를 수정할 때 수정하려는 필드만 보낼 수 있습니다.\n\n모든 **필드가 실제로 변경**되기 때문에(타입이 이제 `None`을 포함하고, 기본값도 이제 `None`이 됨), 우리는 필드를 **다시 선언**해야 합니다.\n\n`HeroBase`를 상속할 필요는 없습니다. 모든 필드를 다시 선언하기 때문입니다. 일관성을 위해 상속을 유지하긴 했지만, 필수는 아닙니다. 이는 개인적인 취향의 문제입니다. 🤷\n\n`HeroUpdate`의 필드는 다음과 같습니다:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### `HeroCreate`로 생성하고 `HeroPublic` 반환하기 { #create-with-herocreate-and-return-a-heropublic }\n\n이제 **여러 모델**을 사용하므로 애플리케이션의 관련 부분을 업데이트할 수 있습니다.\n\n요청에서 `HeroCreate` *데이터 모델*을 받아 이를 기반으로 `Hero` *테이블 모델*을 생성합니다.\n\n이 새 *테이블 모델* `Hero`는 클라이언트에서 보낸 필드를 가지며, 데이터베이스에서 생성된 `id`도 포함합니다.\n\n그런 다음 함수를 통해 동일한 *테이블 모델* `Hero`를 그대로 반환합니다. 하지만 `response_model`로 `HeroPublic` *데이터 모델*을 선언했기 때문에, **FastAPI**는 `HeroPublic`을 사용하여 데이터를 검증하고 직렬화합니다.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | 팁\n\n이제 **반환 타입 어노테이션** `-> HeroPublic` 대신 `response_model=HeroPublic`을 사용합니다. 반환하는 값이 실제로 `HeroPublic`이 *아니기* 때문입니다.\n\n만약 `-> HeroPublic`으로 선언했다면, 에디터와 린터에서 `HeroPublic` 대신 `Hero`를 반환한다고 (당연히) 불평할 것입니다.\n\n`response_model`에 선언함으로써 **FastAPI**가 처리하도록 하고, 타입 어노테이션과 에디터 및 다른 도구의 도움에는 영향을 미치지 않도록 합니다.\n\n///\n\n### `HeroPublic`으로 Heroes 조회하기 { #read-heroes-with-heropublic }\n\n이전과 동일하게 `Hero`를 **조회**할 수 있습니다. 이번에도 `response_model=list[HeroPublic]`을 사용하여 데이터가 올바르게 검증되고 직렬화되도록 보장합니다.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### `HeroPublic`으로 단일 Hero 조회하기 { #read-one-hero-with-heropublic }\n\n단일 hero를 **조회**할 수도 있습니다:\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### `HeroUpdate`로 Hero 수정하기 { #update-a-hero-with-heroupdate }\n\n**hero를 수정**할 수도 있습니다. 이를 위해 HTTP `PATCH` 작업을 사용합니다.\n\n그리고 코드에서는 클라이언트가 보낸 모든 데이터가 담긴 `dict`를 가져오는데, **클라이언트가 보낸 데이터만** 포함하고, 기본값이어서 들어가 있는 값은 제외합니다. 이를 위해 `exclude_unset=True`를 사용합니다. 이것이 주요 핵심입니다. 🪄\n\n그런 다음, `hero_db.sqlmodel_update(hero_data)`를 사용하여 `hero_data`의 데이터로 `hero_db`를 업데이트합니다.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### Hero 다시 삭제하기 { #delete-a-hero-again }\n\nhero **삭제**는 이전과 거의 동일합니다.\n\n이번에는 모든 것을 리팩터링하고 싶은 욕구를 만족시키지 못하겠습니다. 😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### 애플리케이션 다시 실행하기 { #run-the-app-again }\n\n애플리케이션을 다시 실행할 수 있습니다:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n`/docs` API UI로 이동하면 이제 업데이트되어 있고, hero를 생성할 때 클라이언트가 `id`를 보낼 것이라고 기대하지 않는 것 등을 확인할 수 있습니다.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## 요약 { #recap }\n\n[**SQLModel**](https://sqlmodel.tiangolo.com/)을 사용하여 SQL 데이터베이스와 상호작용하고, *데이터 모델* 및 *테이블 모델*로 코드를 간소화할 수 있습니다.\n\n더 많은 내용을 배우려면 **SQLModel** 문서를 참고하세요. **FastAPI**와 함께 SQLModel을 사용하는 더 긴 미니 [튜토리얼](https://sqlmodel.tiangolo.com/tutorial/fastapi/)도 있습니다. 🚀\n"
  },
  {
    "path": "docs/ko/docs/tutorial/static-files.md",
    "content": "# 정적 파일 { #static-files }\n\n`StaticFiles`를 사용하면 디렉터리에서 정적 파일을 자동으로 제공할 수 있습니다.\n\n## `StaticFiles` 사용 { #use-staticfiles }\n\n* `StaticFiles`를 임포트합니다.\n* 특정 경로에 `StaticFiles()` 인스턴스를 \"마운트\"합니다.\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | 기술 세부사항\n\n`from starlette.staticfiles import StaticFiles`를 사용할 수도 있습니다.\n\n**FastAPI**는 개발자인 여러분의 편의를 위해 `fastapi.staticfiles`로 `starlette.staticfiles`와 동일한 것을 제공합니다. 하지만 실제로는 Starlette에서 직접 가져온 것입니다.\n\n///\n\n### \"마운팅\"이란 { #what-is-mounting }\n\n\"마운팅\"은 특정 경로에 완전한 \"독립적인\" 애플리케이션을 추가하고, 그 애플리케이션이 모든 하위 경로를 처리하도록 하는 것을 의미합니다.\n\n마운트된 애플리케이션은 완전히 독립적이므로 `APIRouter`를 사용하는 것과는 다릅니다. 메인 애플리케이션의 OpenAPI 및 문서에는 마운트된 애플리케이션의 내용 등이 포함되지 않습니다.\n\n자세한 내용은 [고급 사용자 가이드](../advanced/index.md)에서 확인할 수 있습니다.\n\n## 세부사항 { #details }\n\n첫 번째 `\"/static\"`은 이 \"하위 애플리케이션\"이 \"마운트\"될 하위 경로를 가리킵니다. 따라서 `\"/static\"`으로 시작하는 모든 경로는 이 애플리케이션이 처리합니다.\n\n`directory=\"static\"`은 정적 파일이 들어 있는 디렉터리의 이름을 나타냅니다.\n\n`name=\"static\"`은 **FastAPI**에서 내부적으로 사용할 수 있는 이름을 제공합니다.\n\n이 모든 매개변수는 \"`static`\"과 다를 수 있으며, 여러분의 애플리케이션 요구 사항 및 구체적인 세부 정보에 맞게 조정하세요.\n\n## 추가 정보 { #more-info }\n\n자세한 내용과 옵션은 [Starlette의 정적 파일 문서](https://www.starlette.dev/staticfiles/)를 확인하세요.\n"
  },
  {
    "path": "docs/ko/docs/tutorial/stream-json-lines.md",
    "content": "# JSON Lines 스트리밍 { #stream-json-lines }\n\n연속된 데이터를 \"**스트림**\"으로 보내고 싶다면 **JSON Lines**를 사용할 수 있습니다.\n\n/// info\n\nFastAPI 0.134.0에 추가되었습니다.\n\n///\n\n## 스트림이란 { #what-is-a-stream }\n\n데이터를 \"**스트리밍**\"한다는 것은 애플리케이션이 전체 항목 시퀀스가 모두 준비될 때까지 기다리지 않고 클라이언트로 데이터 항목을 보내기 시작한다는 뜻입니다.\n\n즉, 첫 번째 항목을 보내면 클라이언트는 그것을 받아 처리하기 시작하고, 그동안 애플리케이션은 다음 항목을 계속 생성할 수 있습니다.\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\n데이터를 계속 보내는 무한 스트림일 수도 있습니다.\n\n## JSON Lines { #json-lines }\n\n이런 경우에는 한 줄에 하나의 JSON 객체를 보내는 형식인 \"**JSON Lines**\"를 사용하는 것이 일반적입니다.\n\n응답의 콘텐츠 타입은 `application/json` 대신 `application/jsonl`이고, 본문은 다음과 같습니다:\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\nJSON 배열(Python의 list에 해당)과 매우 비슷하지만, 항목들을 `[]`로 감싸고 항목 사이에 `,`를 넣는 대신, 줄마다 하나의 JSON 객체가 있고, 새 줄 문자로 구분됩니다.\n\n/// info\n\n핵심은 애플리케이션이 각 줄을 차례로 생성하는 동안, 클라이언트는 이전 줄을 소비할 수 있다는 점입니다.\n\n///\n\n/// note | 기술 세부사항\n\n각 JSON 객체는 새 줄로 구분되므로, 내용에 실제 줄바꿈 문자를 포함할 수는 없습니다. 하지만 JSON 표준의 일부인 이스케이프된 줄바꿈(`\\n`)은 포함할 수 있습니다.\n\n보통은 신경 쓸 필요가 없습니다. 자동으로 처리되니 계속 읽어 주세요. 🤓\n\n///\n\n## 사용 예 { #use-cases }\n\n이 방법을 사용해 **AI LLM** 서비스, **로그** 또는 **telemetry**에서 오는 데이터, 혹은 **JSON** 항목으로 구조화할 수 있는 다른 유형의 데이터를 스트리밍할 수 있습니다.\n\n/// tip\n\n비디오나 오디오처럼 바이너리 데이터를 스트리밍하려면 고급 가이드를 확인하세요: [스트림 데이터](../advanced/stream-data.md).\n\n///\n\n## FastAPI로 JSON Lines 스트리밍 { #stream-json-lines-with-fastapi }\n\nFastAPI에서 JSON Lines를 스트리밍하려면, *경로 처리 함수*에서 `return`을 사용하는 대신 `yield`로 각 항목을 차례로 생성하면 됩니다.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\n보내려는 각 JSON 항목의 타입이 `Item`(Pydantic 모델)이고 함수가 async라면, 반환 타입을 `AsyncIterable[Item]`로 선언할 수 있습니다:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\n반환 타입을 선언하면 FastAPI가 이를 사용해 데이터를 **검증**하고, OpenAPI에 **문서화**하고, **필터링**하고, Pydantic으로 **직렬화**합니다.\n\n/// tip\n\nPydantic이 **Rust** 측에서 직렬화하므로, 반환 타입을 선언하지 않았을 때보다 훨씬 높은 **성능**을 얻게 됩니다.\n\n///\n\n### 비동기 아님 *경로 처리 함수* { #non-async-path-operation-functions }\n\n일반 `def` 함수(`async` 없이)도 사용할 수 있으며, 동일하게 `yield`를 사용할 수 있습니다.\n\nFastAPI가 이벤트 루프를 막지 않도록 올바르게 실행되게 보장합니다.\n\n이 경우 함수가 async가 아니므로, 올바른 반환 타입은 `Iterable[Item]`입니다:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### 반환 타입 생략 { #no-return-type }\n\n반환 타입을 생략할 수도 있습니다. 그러면 FastAPI가 [`jsonable_encoder`](./encoder.md)를 사용해 데이터를 JSON으로 직렬화 가능한 형태로 변환한 뒤 JSON Lines로 전송합니다.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## 서버 전송 이벤트(SSE) { #server-sent-events-sse }\n\nFastAPI는 Server-Sent Events(SSE)도 일급으로 지원합니다. 매우 비슷하지만 몇 가지 추가 세부사항이 있습니다. 다음 장에서 자세히 알아보세요: [Server-Sent Events (SSE)](server-sent-events.md). 🤓\n"
  },
  {
    "path": "docs/ko/docs/tutorial/testing.md",
    "content": "# 테스팅 { #testing }\n\n[Starlette](https://www.starlette.dev/testclient/) 덕분에 **FastAPI** 애플리케이션을 테스트하는 일은 쉽고 즐거운 일이 되었습니다.\n\n이는 [HTTPX](https://www.python-httpx.org)를 기반으로 하며, 이는 Requests를 기반으로 설계되었기 때문에 매우 친숙하고 직관적입니다.\n\n이를 사용하면 **FastAPI**에서 [pytest](https://docs.pytest.org/)를 직접 사용할 수 있습니다.\n\n## `TestClient` 사용하기 { #using-testclient }\n\n/// info | 정보\n\n`TestClient` 사용하려면, 우선 [`httpx`](https://www.python-httpx.org)를 설치해야 합니다.\n\n[가상 환경](../virtual-environments.md)을 만들고, 활성화한 뒤 설치하세요. 예시:\n\n```console\n$ pip install httpx\n```\n\n///\n\n`TestClient`를 임포트하세요.\n\n**FastAPI** 애플리케이션을 전달하여 `TestClient`를 만드세요.\n\n이름이 `test_`로 시작하는 함수를 만드세요(`pytest`의 표준적인 관례입니다).\n\n`httpx`를 사용하는 것과 같은 방식으로 `TestClient` 객체를 사용하세요.\n\n표준적인 파이썬 표현식으로 확인이 필요한 곳에 간단한 `assert` 문장을 작성하세요(역시 표준적인 `pytest` 관례입니다).\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip | 팁\n\n테스트를 위한 함수는 `async def`가 아니라 `def`로 작성됨에 주의하세요.\n\n그리고 클라이언트에 대한 호출도 `await`를 사용하지 않는 일반 호출입니다.\n\n이렇게 하여 복잡한 과정 없이 `pytest`를 직접적으로 사용할 수 있습니다.\n\n///\n\n/// note | 기술 세부사항\n\n`from starlette.testclient import TestClient` 역시 사용할 수 있습니다.\n\n**FastAPI**는 개발자의 편의를 위해 `starlette.testclient`를 `fastapi.testclient`로도 제공할 뿐입니다. 하지만 이는 Starlette에서 직접 가져옵니다.\n\n///\n\n/// tip | 팁\n\nFastAPI 애플리케이션에 요청을 보내는 것 외에도 테스트에서 `async` 함수를 호출하고 싶다면 (예: 비동기 데이터베이스 함수), 심화 튜토리얼의 [비동기 테스트](../advanced/async-tests.md)를 참조하세요.\n\n///\n\n## 테스트 분리하기 { #separating-tests }\n\n실제 애플리케이션에서는 테스트를 별도의 파일로 나누는 경우가 많습니다.\n\n그리고 **FastAPI** 애플리케이션도 여러 파일이나 모듈 등으로 구성될 수 있습니다.\n\n### **FastAPI** app 파일 { #fastapi-app-file }\n\n[더 큰 애플리케이션](bigger-applications.md)에 묘사된 파일 구조를 가지고 있는 것으로 가정해봅시다.\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\n`main.py` 파일 안에 **FastAPI** app 을 만들었습니다:\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### 테스트 파일 { #testing-file }\n\n테스트를 위해 `test_main.py`라는 파일을 생성할 수 있습니다. 이 파일은 동일한 Python 패키지(즉, `__init__.py` 파일이 있는 동일한 디렉터리)에 위치할 수 있습니다.\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n파일들이 동일한 패키지에 위치해 있으므로, 상대 임포트를 사용하여 `main` 모듈(`main.py`)에서 `app` 객체를 임포트 해올 수 있습니다.\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n\n...그리고 이전에 작성했던 것과 같은 테스트 코드를 작성할 수 있습니다.\n\n## 테스트: 확장된 예시 { #testing-extended-example }\n\n이제 위의 예시를 확장하고 더 많은 세부 사항을 추가하여 다양한 부분을 어떻게 테스트하는지 살펴보겠습니다.\n\n### 확장된 **FastAPI** app 파일 { #extended-fastapi-app-file }\n\n이전과 같은 파일 구조를 계속 사용해 보겠습니다.\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n이제 **FastAPI** 앱이 있는 `main.py` 파일에 몇 가지 다른 **경로 처리**가 추가된 경우를 생각해봅시다.\n\n오류를 반환할 수 있는 `GET` 작업이 있습니다.\n\n여러 다른 오류를 반환할 수 있는 `POST` 작업이 있습니다.\n\n두 *경로 처리* 모두 `X-Token` 헤더를 요구합니다.\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### 확장된 테스트 파일 { #extended-testing-file }\n\n이제는 `test_main.py`를 확장된 테스트들로 수정할 수 있습니다:\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\n\n클라이언트가 요청에 정보를 전달해야 하는데 방법을 모르겠다면, Requests의 디자인을 기반으로 설계된 HTTPX처럼 `httpx`에서 해당 작업을 수행하는 방법을 검색(Google)하거나, `requests`에서의 방법을 검색해보세요.\n\n그 후, 테스트에서도 동일하게 적용하면 됩니다.\n\n예시:\n\n* *경로* 혹은 *쿼리* 매개변수를 전달하려면, URL 자체에 추가한다.\n* JSON 본문을 전달하려면, 파이썬 객체 (예를들면 `dict`)를 `json` 파라미터로 전달한다.\n* JSON 대신 *폼 데이터*를 보내야한다면, `data` 파라미터를 대신 전달한다.\n* *헤더*를 전달하려면, `headers` 파라미터에 `dict`를 전달한다.\n* *쿠키*를 전달하려면, `cookies` 파라미터에 `dict`를 전달한다.\n\n백엔드로 데이터를 어떻게 보내는지 정보를 더 얻으려면 (`httpx` 혹은 `TestClient`를 이용해서) [HTTPX 문서](https://www.python-httpx.org)를 확인하세요.\n\n/// info | 정보\n\n`TestClient`는 Pydantic 모델이 아니라 JSON으로 변환될 수 있는 데이터를 받습니다.\n\n만약 테스트 중 Pydantic 모델을 가지고 있고 테스트 중에 애플리케이션으로 해당 데이터를 보내고 싶다면, [JSON 호환 인코더](encoder.md)에 설명되어 있는 `jsonable_encoder`를 사용할 수 있습니다.\n\n///\n\n## 실행하기 { #run-it }\n\n그 후에는 `pytest`를 설치하기만 하면 됩니다.\n\n[가상 환경](../virtual-environments.md)을 만들고, 활성화 시킨 뒤에 설치하세요. 예시:\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\n`pytest`는 파일과 테스트를 자동으로 감지하고 실행한 다음, 결과를 보고할 것입니다.\n\n테스트를 다음 명령어로 실행하세요.\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/ko/docs/virtual-environments.md",
    "content": "# 가상 환경 { #virtual-environments }\n\nPython 프로젝트를 작업할 때는 **가상 환경**(또는 이와 유사한 메커니즘)을 사용해 각 프로젝트마다 설치하는 패키지를 분리하는 것이 좋습니다.\n\n/// info\n\n이미 가상 환경에 대해 알고 있고, 어떻게 생성하고 사용하는지도 알고 있다면, 이 섹션은 건너뛰어도 괜찮습니다. 🤓\n\n///\n\n/// tip\n\n**가상 환경**은 **환경 변수**와 다릅니다.\n\n**환경 변수**는 시스템에 존재하며, 프로그램이 사용할 수 있는 변수입니다.\n\n**가상 환경**은 몇몇 파일로 구성된 하나의 디렉터리입니다.\n\n///\n\n/// info\n\n이 페이지에서는 **가상 환경**을 사용하는 방법과 작동 방식을 알려드립니다.\n\nPython 설치까지 포함해 **모든 것을 관리해주는 도구**를 도입할 준비가 되었다면 [uv](https://github.com/astral-sh/uv)를 사용해 보세요.\n\n///\n\n## 프로젝트 생성 { #create-a-project }\n\n먼저, 프로젝트를 위한 디렉터리를 하나 생성합니다.\n\n제가 보통 하는 방법은 사용자 홈/유저 디렉터리 안에 `code`라는 디렉터리를 만드는 것입니다.\n\n그리고 그 안에 프로젝트마다 디렉터리를 하나씩 만듭니다.\n\n<div class=\"termy\">\n\n```console\n// 홈 디렉터리로 이동\n$ cd\n// 모든 코드 프로젝트를 위한 디렉터리 생성\n$ mkdir code\n// 그 code 디렉터리로 이동\n$ cd code\n// 이 프로젝트를 위한 디렉터리 생성\n$ mkdir awesome-project\n// 그 프로젝트 디렉터리로 이동\n$ cd awesome-project\n```\n\n</div>\n\n## 가상 환경 생성 { #create-a-virtual-environment }\n\nPython 프로젝트를 **처음 시작할 때**, 가상 환경을 **<dfn title=\"다른 옵션도 있지만, 이것은 간단한 가이드라인입니다\">프로젝트 내부</dfn>**에 생성하세요.\n\n/// tip\n\n이 작업은 **프로젝트당 한 번만** 하면 되며, 작업할 때마다 할 필요는 없습니다.\n\n///\n\n//// tab | `venv`\n\n가상 환경을 만들려면 Python에 포함된 `venv` 모듈을 사용할 수 있습니다.\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | 명령어 의미\n\n* `python`: `python`이라는 프로그램을 사용합니다\n* `-m`: 모듈을 스크립트로 호출합니다. 다음에 어떤 모듈인지 지정합니다\n* `venv`: 보통 Python에 기본으로 설치되어 있는 `venv` 모듈을 사용합니다\n* `.venv`: 새 디렉터리인 `.venv`에 가상 환경을 생성합니다\n\n///\n\n////\n\n//// tab | `uv`\n\n[`uv`](https://github.com/astral-sh/uv)가 설치되어 있다면, 이를 사용해 가상 환경을 생성할 수 있습니다.\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip\n\n기본적으로 `uv`는 `.venv`라는 디렉터리에 가상 환경을 생성합니다.\n\n하지만 디렉터리 이름을 추가 인자로 전달해 이를 커스터마이즈할 수 있습니다.\n\n///\n\n////\n\n해당 명령어는 `.venv`라는 디렉터리에 새로운 가상 환경을 생성합니다.\n\n/// details | `.venv` 또는 다른 이름\n\n가상 환경을 다른 디렉터리에 생성할 수도 있지만, 관례적으로 `.venv`라는 이름을 사용합니다.\n\n///\n\n## 가상 환경 활성화 { #activate-the-virtual-environment }\n\n이후 실행하는 Python 명령어와 설치하는 패키지가 새 가상 환경을 사용하도록, 새 가상 환경을 활성화하세요.\n\n/// tip\n\n프로젝트 작업을 위해 **새 터미널 세션**을 시작할 때마다 **매번** 이 작업을 하세요.\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\n또는 Windows에서 Bash(예: [Git Bash](https://gitforwindows.org/))를 사용하는 경우:\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip\n\n해당 환경에 **새 패키지**를 설치할 때마다, 환경을 다시 **활성화**하세요.\n\n이렇게 하면 해당 패키지가 설치한 **터미널(<abbr title=\"command line interface - 명령줄 인터페이스\">CLI</abbr>) 프로그램**을 사용할 때, 전역으로 설치되어 있을 수도 있는(아마 필요한 버전과는 다른 버전인) 다른 프로그램이 아니라 가상 환경에 있는 것을 사용하게 됩니다.\n\n///\n\n## 가상 환경 활성화 여부 확인 { #check-the-virtual-environment-is-active }\n\n가상 환경이 활성화되어 있는지(이전 명령어가 작동했는지) 확인합니다.\n\n/// tip\n\n이 단계는 **선택 사항**이지만, 모든 것이 예상대로 작동하고 있는지, 그리고 의도한 가상 환경을 사용하고 있는지 **확인**하는 좋은 방법입니다.\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n프로젝트 내부(이 경우 `awesome-project`)의 `.venv/bin/python`에 있는 `python` 바이너리가 표시된다면, 정상적으로 작동한 것입니다. 🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n프로젝트 내부(이 경우 `awesome-project`)의 `.venv\\Scripts\\python`에 있는 `python` 바이너리가 표시된다면, 정상적으로 작동한 것입니다. 🎉\n\n////\n\n## `pip` 업그레이드 { #upgrade-pip }\n\n/// tip\n\n[`uv`](https://github.com/astral-sh/uv)를 사용한다면, `pip` 대신 `uv`로 설치하게 되므로 `pip`을 업그레이드할 필요가 없습니다. 😎\n\n///\n\n`pip`로 패키지를 설치한다면(Python에 기본으로 포함되어 있습니다) 최신 버전으로 **업그레이드**하는 것이 좋습니다.\n\n패키지 설치 중 발생하는 다양한 특이한 오류는 먼저 `pip`를 업그레이드하는 것만으로 해결되는 경우가 많습니다.\n\n/// tip\n\n보통 이 작업은 가상 환경을 만든 직후 **한 번만** 하면 됩니다.\n\n///\n\n가상 환경이 활성화된 상태인지 확인한 다음(위의 명령어 사용) 아래를 실행하세요:\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip\n\n때로는 pip를 업그레이드하려고 할 때 **`No module named pip`** 오류가 발생할 수 있습니다.\n\n이 경우 아래 명령어로 pip를 설치하고 업그레이드하세요:\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\n이 명령어는 pip가 아직 설치되어 있지 않다면 설치하며, 설치된 pip 버전이 `ensurepip`에서 제공 가능한 버전만큼 최신임을 보장합니다.\n\n///\n\n## `.gitignore` 추가하기 { #add-gitignore }\n\n**Git**을 사용하고 있다면(사용하는 것이 좋습니다), `.venv`의 모든 내용을 Git에서 제외하도록 `.gitignore` 파일을 추가하세요.\n\n/// tip\n\n[`uv`](https://github.com/astral-sh/uv)로 가상 환경을 만들었다면, 이미 자동으로 처리되어 있으므로 이 단계는 건너뛰어도 됩니다. 😎\n\n///\n\n/// tip\n\n가상 환경을 만든 직후 **한 번만** 하면 됩니다.\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | 명령어 의미\n\n* `echo \"*\"`: 터미널에 `*` 텍스트를 \"출력\"합니다(다음 부분이 이를 약간 변경합니다)\n* `>`: `>` 왼쪽 명령어가 터미널에 출력한 내용을 터미널에 출력하지 않고, `>` 오른쪽에 있는 파일에 기록하라는 의미입니다\n* `.gitignore`: 텍스트가 기록될 파일 이름입니다\n\n그리고 Git에서 `*`는 \"모든 것\"을 의미합니다. 따라서 `.venv` 디렉터리 안의 모든 것을 무시합니다.\n\n이 명령어는 다음 내용을 가진 `.gitignore` 파일을 생성합니다:\n\n```gitignore\n*\n```\n\n///\n\n## 패키지 설치 { #install-packages }\n\n환경을 활성화한 뒤, 그 안에 패키지를 설치할 수 있습니다.\n\n/// tip\n\n프로젝트에 필요한 패키지를 설치하거나 업그레이드할 때는 **한 번**만 하면 됩니다.\n\n버전을 업그레이드하거나 새 패키지를 추가해야 한다면 **다시 이 작업을** 하게 됩니다.\n\n///\n\n### 패키지 직접 설치 { #install-packages-directly }\n\n급하게 작업 중이고 프로젝트의 패키지 요구사항을 선언하는 파일을 사용하고 싶지 않다면, 패키지를 직접 설치할 수 있습니다.\n\n/// tip\n\n프로그램에 필요한 패키지와 버전을 파일(예: `requirements.txt` 또는 `pyproject.toml`)에 적어두는 것은 (매우) 좋은 생각입니다.\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\n[`uv`](https://github.com/astral-sh/uv)가 있다면:\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### `requirements.txt`에서 설치 { #install-from-requirements-txt }\n\n`requirements.txt`가 있다면, 이제 이를 사용해 그 안의 패키지를 설치할 수 있습니다.\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\n[`uv`](https://github.com/astral-sh/uv)가 있다면:\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\n일부 패키지가 있는 `requirements.txt`는 다음과 같이 생겼을 수 있습니다:\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## 프로그램 실행 { #run-your-program }\n\n가상 환경을 활성화한 뒤에는 프로그램을 실행할 수 있으며, 설치한 패키지가 들어있는 가상 환경 내부의 Python을 사용하게 됩니다.\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## 에디터 설정 { #configure-your-editor }\n\n아마 에디터를 사용할 텐데, 자동 완성과 인라인 오류 표시를 받을 수 있도록 생성한 가상 환경을 사용하도록 설정하세요(대부분 자동 감지합니다).\n\n예를 들면:\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip\n\n보통 이 설정은 가상 환경을 만들 때 **한 번만** 하면 됩니다.\n\n///\n\n## 가상 환경 비활성화 { #deactivate-the-virtual-environment }\n\n프로젝트 작업을 마쳤다면 가상 환경을 **비활성화**할 수 있습니다.\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\n이렇게 하면 `python`을 실행할 때, 해당 가상 환경과 그 안에 설치된 패키지에서 실행하려고 하지 않습니다.\n\n## 작업할 준비 완료 { #ready-to-work }\n\n이제 프로젝트 작업을 시작할 준비가 되었습니다.\n\n\n\n/// tip\n\n위의 내용이 무엇인지 더 이해하고 싶으신가요?\n\n계속 읽어보세요. 👇🤓\n\n///\n\n## 가상 환경을 왜 사용하나요 { #why-virtual-environments }\n\nFastAPI로 작업하려면 [Python](https://www.python.org/)을 설치해야 합니다.\n\n그 다음 FastAPI와 사용하려는 다른 **패키지**를 **설치**해야 합니다.\n\n패키지를 설치할 때는 보통 Python에 포함된 `pip` 명령어(또는 유사한 대안)를 사용합니다.\n\n하지만 `pip`를 그대로 직접 사용하면, 패키지는 **전역 Python 환경**(전역 Python 설치)에 설치됩니다.\n\n### 문제점 { #the-problem }\n\n그렇다면, 전역 Python 환경에 패키지를 설치하면 어떤 문제가 있을까요?\n\n어느 시점이 되면 **서로 다른 패키지**에 의존하는 다양한 프로그램을 작성하게 될 것입니다. 그리고 작업하는 프로젝트 중 일부는 같은 패키지의 **서로 다른 버전**에 의존할 수도 있습니다. 😱\n\n예를 들어 `philosophers-stone`이라는 프로젝트를 만들 수 있습니다. 이 프로그램은 **`harry`라는 다른 패키지의 버전 `1`**에 의존합니다. 그래서 `harry`를 설치해야 합니다.\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n\n그다음, 나중에 `prisoner-of-azkaban`이라는 또 다른 프로젝트를 만들고, 이 프로젝트도 `harry`에 의존하지만, 이 프로젝트는 **`harry` 버전 `3`**이 필요합니다.\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]\n```\n\n하지만 이제 문제가 생깁니다. 로컬 **가상 환경**이 아니라 전역(전역 환경)에 패키지를 설치한다면, 어떤 버전의 `harry`를 설치할지 선택해야 합니다.\n\n`philosophers-stone`을 실행하고 싶다면, 먼저 `harry` 버전 `1`을 다음과 같이 설치해야 합니다:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\n그리고 전역 Python 환경에 `harry` 버전 `1`이 설치된 상태가 됩니다.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\n하지만 `prisoner-of-azkaban`을 실행하려면 `harry` 버전 `1`을 제거하고 `harry` 버전 `3`을 설치해야 합니다(또는 버전 `3`을 설치하기만 해도 버전 `1`이 자동으로 제거됩니다).\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\n그러면 전역 Python 환경에 `harry` 버전 `3`이 설치된 상태가 됩니다.\n\n그리고 `philosophers-stone`을 다시 실행하려고 하면, `harry` 버전 `1`이 필요하기 때문에 **작동하지 않을** 가능성이 있습니다.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --> |requires| harry-3\n    end\n```\n\n/// tip\n\nPython 패키지에서는 **새 버전**에서 **호환성을 깨뜨리는 변경(breaking changes)**을 **피하려고** 최선을 다하는 것이 매우 일반적이지만, 안전을 위해 더 최신 버전은 의도적으로 설치하고, 테스트를 실행해 모든 것이 올바르게 작동하는지 확인할 수 있을 때 설치하는 것이 좋습니다.\n\n///\n\n이제 이런 일이 여러분의 **모든 프로젝트가 의존하는** **많은** 다른 **패키지**에서도 일어난다고 상상해 보세요. 이는 관리하기가 매우 어렵습니다. 그리고 결국 일부 프로젝트는 패키지의 **호환되지 않는 버전**으로 실행하게 될 가능성이 높으며, 왜 무언가가 작동하지 않는지 알지 못하게 될 수 있습니다.\n\n또한 운영체제(Linux, Windows, macOS 등)에 따라 Python이 이미 설치되어 있을 수도 있습니다. 그런 경우에는 시스템에 **필요한 특정 버전**의 패키지가 일부 미리 설치되어 있을 가능성이 큽니다. 전역 Python 환경에 패키지를 설치하면, 운영체제에 포함된 프로그램 일부가 **깨질** 수 있습니다.\n\n## 패키지는 어디에 설치되나요 { #where-are-packages-installed }\n\nPython을 설치하면 컴퓨터에 몇몇 파일이 들어 있는 디렉터리가 생성됩니다.\n\n이 디렉터리 중 일부는 설치한 모든 패키지를 담는 역할을 합니다.\n\n다음을 실행하면:\n\n<div class=\"termy\">\n\n```console\n// 지금은 실행하지 마세요, 예시일 뿐입니다 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\nFastAPI 코드를 담은 압축 파일을 다운로드합니다. 보통 [PyPI](https://pypi.org/project/fastapi/)에서 받습니다.\n\n또한 FastAPI가 의존하는 다른 패키지들의 파일도 **다운로드**합니다.\n\n그 다음 모든 파일을 **압축 해제**하고 컴퓨터의 한 디렉터리에 넣습니다.\n\n기본적으로, 다운로드하고 압축 해제한 파일들은 Python 설치와 함께 제공되는 디렉터리, 즉 **전역 환경**에 저장됩니다.\n\n## 가상 환경이란 무엇인가요 { #what-are-virtual-environments }\n\n전역 환경에 모든 패키지를 두는 문제에 대한 해결책은 작업하는 **각 프로젝트마다 가상 환경**을 사용하는 것입니다.\n\n가상 환경은 전역 환경과 매우 유사한 하나의 **디렉터리**이며, 프로젝트의 패키지를 설치할 수 있습니다.\n\n이렇게 하면 각 프로젝트는 자체 가상 환경(`.venv` 디렉터리)과 자체 패키지를 갖게 됩니다.\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) --->|requires| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --->|requires| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## 가상 환경을 활성화한다는 것은 무엇을 의미하나요 { #what-does-activating-a-virtual-environment-mean }\n\n가상 환경을 활성화한다는 것은, 예를 들어 다음과 같은 명령어로:\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\n또는 Windows에서 Bash(예: [Git Bash](https://gitforwindows.org/))를 사용하는 경우:\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n다음 명령어들에서 사용할 수 있는 몇몇 [환경 변수](environment-variables.md)를 생성하거나 수정하는 것을 의미합니다.\n\n그 변수 중 하나가 `PATH` 변수입니다.\n\n/// tip\n\n`PATH` 환경 변수에 대해 더 알아보려면 [환경 변수](environment-variables.md#path-environment-variable) 섹션을 참고하세요.\n\n///\n\n가상 환경을 활성화하면 가상 환경의 경로인 `.venv/bin`(Linux와 macOS) 또는 `.venv\\Scripts`(Windows)를 `PATH` 환경 변수에 추가합니다.\n\n가령 환경을 활성화하기 전에는 `PATH` 변수가 다음과 같았다고 해보겠습니다:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\n이는 시스템이 다음 위치에서 프로그램을 찾는다는 뜻입니다:\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\n이는 시스템이 다음 위치에서 프로그램을 찾는다는 뜻입니다:\n\n* `C:\\Windows\\System32`\n\n////\n\n가상 환경을 활성화한 뒤에는 `PATH` 변수가 다음과 같이 보일 수 있습니다:\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\n이는 시스템이 이제 다음 위치에서 프로그램을 가장 먼저 찾기 시작한다는 뜻입니다:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\n그리고 나서 다른 디렉터리들을 탐색합니다.\n\n따라서 터미널에 `python`을 입력하면, 시스템은 다음 위치에서 Python 프로그램을 찾고:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n그것을 사용하게 됩니다.\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\n이는 시스템이 이제 다음 위치에서 프로그램을 가장 먼저 찾기 시작한다는 뜻입니다:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\n그리고 나서 다른 디렉터리들을 탐색합니다.\n\n따라서 터미널에 `python`을 입력하면, 시스템은 다음 위치에서 Python 프로그램을 찾고:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n그것을 사용하게 됩니다.\n\n////\n\n중요한 세부 사항은 가상 환경 경로가 `PATH` 변수의 **맨 앞**에 들어간다는 점입니다. 시스템은 다른 어떤 Python보다도 **먼저** 이를 찾게 됩니다. 이렇게 하면 `python`을 실행할 때, 다른 어떤 `python`(예: 전역 환경의 `python`)이 아니라 **가상 환경의 Python**을 사용하게 됩니다.\n\n가상 환경을 활성화하면 다른 몇 가지도 변경되지만, 이것이 그중 가장 중요한 것 중 하나입니다.\n\n## 가상 환경 확인하기 { #checking-a-virtual-environment }\n\n가상 환경이 활성화되어 있는지 확인할 때는, 예를 들어 다음을 사용합니다:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\n이는 사용될 `python` 프로그램이 **가상 환경 내부에 있는 것**이라는 뜻입니다.\n\nLinux와 macOS에서는 `which`, Windows PowerShell에서는 `Get-Command`를 사용합니다.\n\n이 명령어는 `PATH` 환경 변수에 있는 경로를 **순서대로** 확인하면서 `python`이라는 프로그램을 찾습니다. 찾는 즉시, 그 프로그램의 **경로를 보여줍니다**.\n\n가장 중요한 부분은 `python`을 호출했을 때, 실행될 정확한 \"`python`\"이 무엇인지 알 수 있다는 점입니다.\n\n따라서 올바른 가상 환경에 있는지 확인할 수 있습니다.\n\n/// tip\n\n가상 환경을 하나 활성화해서 Python을 사용한 다음, **다른 프로젝트로 이동**하기 쉽습니다.\n\n그리고 두 번째 프로젝트는 다른 프로젝트의 가상 환경에서 온 **잘못된 Python**을 사용하고 있기 때문에 **작동하지 않을** 수 있습니다.\n\n어떤 `python`이 사용되고 있는지 확인할 수 있으면 유용합니다. 🤓\n\n///\n\n## 가상 환경을 왜 비활성화하나요 { #why-deactivate-a-virtual-environment }\n\n예를 들어 `philosophers-stone` 프로젝트에서 작업하면서, **그 가상 환경을 활성화**하고, 패키지를 설치하고, 그 환경으로 작업하고 있다고 해보겠습니다.\n\n그런데 이제 **다른 프로젝트**인 `prisoner-of-azkaban`에서 작업하고 싶습니다.\n\n해당 프로젝트로 이동합니다:\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\n`philosophers-stone`의 가상 환경을 비활성화하지 않으면, 터미널에서 `python`을 실행할 때 `philosophers-stone`의 Python을 사용하려고 할 것입니다.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// sirius 임포트 오류, 설치되어 있지 않습니다 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\n하지만 가상 환경을 비활성화하고 `prisoner-of-askaban`에 대한 새 가상 환경을 활성화하면, `python`을 실행할 때 `prisoner-of-azkaban`의 가상 환경에 있는 Python을 사용하게 됩니다.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// 비활성화를 위해 이전 디렉터리에 있을 필요는 없습니다. 어디서든, 다른 프로젝트로 이동한 뒤에도 할 수 있습니다 😎\n$ deactivate\n\n// prisoner-of-azkaban/.venv의 가상 환경을 활성화하세요 🚀\n$ source .venv/bin/activate\n\n// 이제 python을 실행하면, 이 가상 환경에 설치된 sirius 패키지를 찾습니다 ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## 대안들 { #alternatives }\n\n이 문서는 시작을 돕고, 내부에서 모든 것이 어떻게 작동하는지 알려주는 간단한 가이드입니다.\n\n가상 환경, 패키지 의존성(requirements), 프로젝트를 관리하는 방법에는 많은 **대안**이 있습니다.\n\n준비가 되었고 **프로젝트 전체**, 패키지 의존성, 가상 환경 등을 **관리**하는 도구를 사용하고 싶다면 [uv](https://github.com/astral-sh/uv)를 사용해 보시길 권합니다.\n\n`uv`는 많은 일을 할 수 있습니다. 예를 들어:\n\n* 여러 버전을 포함해 **Python을 설치**\n* 프로젝트의 **가상 환경** 관리\n* **패키지** 설치\n* 프로젝트의 패키지 **의존성과 버전** 관리\n* 의존성을 포함해 설치할 패키지와 버전의 **정확한** 세트를 보장하여, 개발 중인 컴퓨터와 동일하게 프로덕션에서 실행할 수 있도록 합니다. 이를 **locking**이라고 합니다\n* 그 외에도 많은 기능이 있습니다\n\n## 결론 { #conclusion }\n\n여기까지 모두 읽고 이해했다면, 이제 많은 개발자들보다 가상 환경에 대해 **훨씬 더 많이** 알게 된 것입니다. 🤓\n\n이 세부 사항을 알고 있으면, 나중에 복잡해 보이는 무언가를 디버깅할 때 아마도 도움이 될 것입니다. **내부에서 어떻게 작동하는지** 알고 있기 때문입니다. 😎\n"
  },
  {
    "path": "docs/ko/llm-prompt.md",
    "content": "### Target language\n\nTranslate to Korean (한국어).\n\nLanguage code: ko.\n\n### Grammar and tone\n\n- Use polite, instructional Korean (e.g. 합니다/하세요 style).\n- Keep the tone consistent with the existing Korean FastAPI docs.\n- Do not translate “You” literally as “당신”. Use “여러분” where appropriate, or omit the subject if it sounds more natural in Korean.\n\n### Headings\n\n- Follow existing Korean heading style (short, action-oriented headings like “확인하기”).\n- Do not add trailing punctuation to headings.\n\n### Quotes\n\n- Keep quote style consistent with the existing Korean docs.\n- Never change quotes inside inline code, code blocks, URLs, or file paths.\n\n### Ellipsis\n\n- Keep ellipsis style consistent with existing Korean docs (often `...`).\n- Never change `...` in code, URLs, or CLI examples.\n\n### Preferred translations / glossary\n\nUse the following preferred translations when they apply in documentation prose:\n\n- request (HTTP): 요청\n- response (HTTP): 응답\n- path operation: 경로 처리\n- path operation function: 경로 처리 함수\n- app: 애플리케이션\n- command: 명령어\n- burger: 햄버거 (NOT 버거)\n\n### `///` admonitions\n\n1) Keep the admonition keyword in English (do not translate `note`, `tip`, etc.).\n2) If a title is present, prefer these canonical titles:\n\n- `/// note | 참고`\n- `/// tip | 팁`\n- `/// warning | 경고`\n- `/// info | 정보`\n- `/// danger | 위험`\n- `/// note Technical Details | 기술 세부사항`\n- `/// check | 확인`\nNotes:\n\n- `details` blocks exist in Korean docs; keep `/// details` as-is and translate only the title after `|`.\n- Example canonical title used: `/// details | 상세 설명`\n"
  },
  {
    "path": "docs/ko/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs/language_names.yml",
    "content": "aa: Afaraf\nab: аҧсуа бызшәа\nae: avesta\naf: Afrikaans\nak: Akan\nam: አማርኛ\nan: aragonés\nar: اللغة العربية\nas: অসমীয়া\nav: авар мацӀ\nay: aymar aru\naz: azərbaycan dili\nba: башҡорт теле\nbe: беларуская мова\nbg: български език\nbh: भोजपुरी\nbi: Bislama\nbm: bamanankan\nbn: বাংলা\nbo: བོད་ཡིག\nbr: brezhoneg\nbs: bosanski jezik\nca: Català\nce: нохчийн мотт\nch: Chamoru\nco: corsu\ncr: ᓀᐦᐃᔭᐍᐏᐣ\ncs: čeština\ncu: ѩзыкъ словѣньскъ\ncv: чӑваш чӗлхи\ncy: Cymraeg\nda: dansk\nde: Deutsch\ndv: Dhivehi\ndz: རྫོང་ཁ\nee: Eʋegbe\nel: Ελληνικά\nen: English\neo: Esperanto\nes: español\net: eesti\neu: euskara\nfa: فارسی\nff: Fulfulde\nfi: suomi\nfj: Vakaviti\nfo: føroyskt\nfr: français\nfy: Frysk\nga: Gaeilge\ngd: Gàidhlig\ngl: galego\ngu: ગુજરાતી\ngv: Gaelg\nha: هَوُسَ\nhe: עברית\nhi: हिन्दी\nho: Hiri Motu\nhr: Hrvatski\nht: Kreyòl ayisyen\nhu: magyar\nhy: Հայերեն\nhz: Otjiherero\nia: Interlingua\nid: Bahasa Indonesia\nie: Interlingue\nig: Asụsụ Igbo\nii: ꆈꌠ꒿ Nuosuhxop\nik: Iñupiaq\nio: Ido\nis: Íslenska\nit: italiano\niu: ᐃᓄᒃᑎᑐᑦ\nja: 日本語\njv: basa Jawa\nka: ქართული\nkg: Kikongo\nki: Gĩkũyũ\nkj: Kuanyama\nkk: қазақ тілі\nkl: kalaallisut\nkm: ខេមរភាសា\nkn: ಕನ್ನಡ\nko: 한국어\nkr: Kanuri\nks: कश्मीरी\nku: Kurdî\nkv: коми кыв\nkw: Kernewek\nky: Кыргызча\nla: latine\nlb: Lëtzebuergesch\nlg: Luganda\nli: Limburgs\nln: Lingála\nlo: ພາສາ\nlt: lietuvių kalba\nlu: Tshiluba\nlv: latviešu valoda\nmg: fiteny malagasy\nmh: Kajin M̧ajeļ\nmi: te reo Māori\nmk: македонски јазик\nml: മലയാളം\nmn: Монгол хэл\nmr: मराठी\nms: Bahasa Malaysia\nmt: Malti\nmy: ဗမာစာ\nna: Ekakairũ Naoero\nnb: Norsk bokmål\nnd: isiNdebele\nne: नेपाली\nng: Owambo\nnl: Nederlands\nnn: Norsk nynorsk\n'no': Norsk\nnr: isiNdebele\nnv: Diné bizaad\nny: chiCheŵa\noc: occitan\noj: ᐊᓂᔑᓈᐯᒧᐎᓐ\nom: Afaan Oromoo\nor: ଓଡ଼ିଆ\nos: ирон æвзаг\npa: ਪੰਜਾਬੀ\npi: पाऴि\npl: Polski\nps: پښتو\npt: português\nqu: Runa Simi\nrm: rumantsch grischun\nrn: Ikirundi\nro: Română\nru: русский язык\nrw: Ikinyarwanda\nsa: संस्कृतम्\nsc: sardu\nsd: सिन्धी\nse: Davvisámegiella\nsg: yângâ tî sängö\nsi: සිංහල\nsk: slovenčina\nsl: slovenščina\nsn: chiShona\nso: Soomaaliga\nsq: shqip\nsr: српски језик\nss: SiSwati\nst: Sesotho\nsu: Basa Sunda\nsv: svenska\nsw: Kiswahili\nta: தமிழ்\nte: తెలుగు\ntg: тоҷикӣ\nth: ไทย\nti: ትግርኛ\ntk: Türkmen\ntl: Wikang Tagalog\ntn: Setswana\nto: faka Tonga\ntr: Türkçe\nts: Xitsonga\ntt: татар теле\ntw: Twi\nty: Reo Tahiti\nug: ئۇيغۇرچە‎\nuk: українська мова\nur: اردو\nuz: Ўзбек\nve: Tshivenḓa\nvi: Tiếng Việt\nvo: Volapük\nwa: walon\nwo: Wollof\nxh: isiXhosa\nyi: ייִדיש\nyo: Yorùbá\nza: Saɯ cueŋƅ\nzh: 简体中文\nzh-hant: 繁體中文\nzu: isiZulu\n"
  },
  {
    "path": "docs/missing-translation.md",
    "content": "/// warning\n\nThis page hasn’t been translated into your language yet. 🌍\n\nWe’re currently switching to an automated translation system 🤖, which will help keep all translations complete and up to date.\n\nLearn more: [Contributing - Translations](https://fastapi.tiangolo.com/contributing/#translations){.internal-link target=_blank}\n\n///\n"
  },
  {
    "path": "docs/pt/docs/_llm-test.md",
    "content": "# Arquivo de teste de LLM { #llm-test-file }\n\nEste documento testa se o <abbr title=\"Large Language Model - Modelo de Linguagem de Grande Porte\">LLM</abbr>, que traduz a documentação, entende o `general_prompt` em `scripts/translate.py` e o prompt específico do idioma em `docs/{language code}/llm-prompt.md`. O prompt específico do idioma é anexado ao `general_prompt`.\n\nOs testes adicionados aqui serão vistos por todos os designers dos prompts específicos de idioma.\n\nUse da seguinte forma:\n\n* Tenha um prompt específico do idioma – `docs/{language code}/llm-prompt.md`.\n* Faça uma tradução nova deste documento para o seu idioma de destino (veja, por exemplo, o comando `translate-page` do `translate.py`). Isso criará a tradução em `docs/{language code}/docs/_llm-test.md`.\n* Verifique se está tudo certo na tradução.\n* Se necessário, melhore seu prompt específico do idioma, o prompt geral ou o documento em inglês.\n* Em seguida, corrija manualmente os problemas restantes na tradução, para que fique uma boa tradução.\n* Retraduzir, tendo a boa tradução no lugar. O resultado ideal seria que o LLM não fizesse mais mudanças na tradução. Isso significa que o prompt geral e o seu prompt específico do idioma estão tão bons quanto possível (às vezes fará algumas mudanças aparentemente aleatórias, a razão é que [LLMs não são algoritmos determinísticos](https://doublespeak.chat/#/handbook#deterministic-output)).\n\nOs testes:\n\n## Trechos de código { #code-snippets }\n\n//// tab | Teste\n\nEste é um trecho de código: `foo`. E este é outro trecho de código: `bar`. E mais um: `baz quux`.\n\n////\n\n//// tab | Informação\n\nO conteúdo dos trechos de código deve ser deixado como está.\n\nVeja a seção `### Content of code snippets` no prompt geral em `scripts/translate.py`.\n\n////\n\n## Citações { #quotes }\n\n//// tab | Teste\n\nOntem, meu amigo escreveu: \"Se você soletrar incorretamente corretamente, você a soletrou incorretamente\". Ao que respondi: \"Correto, mas 'incorrectly' está incorretamente não '\"incorrectly\"'\".\n\n/// note | Nota\n\nO LLM provavelmente vai traduzir isso errado. O interessante é apenas se ele mantém a tradução corrigida ao retraduzir.\n\n///\n\n////\n\n//// tab | Informação\n\nO designer do prompt pode escolher se quer converter aspas neutras em aspas tipográficas. Também é aceitável deixá-las como estão.\n\nVeja, por exemplo, a seção `### Quotes` em `docs/de/llm-prompt.md`.\n\n////\n\n## Citações em trechos de código { #quotes-in-code-snippets }\n\n//// tab | Teste\n\n`pip install \"foo[bar]\"`\n\nExemplos de literais de string em trechos de código: `\"this\"`, `'that'`.\n\nUm exemplo difícil de literais de string em trechos de código: `f\"I like {'oranges' if orange else \"apples\"}\"`\n\nPesado: `Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | Informação\n\n... No entanto, as aspas dentro de trechos de código devem permanecer como estão.\n\n////\n\n## Blocos de código { #code-blocks }\n\n//// tab | Teste\n\nUm exemplo de código Bash...\n\n```bash\n# Imprimir uma saudação ao universo\necho \"Hello universe\"\n```\n\n...e um exemplo de código de console...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n...e outro exemplo de código de console...\n\n```console\n// Criar um diretório \"Code\"\n$ mkdir code\n// Mudar para esse diretório\n$ cd code\n```\n\n...e um exemplo de código Python...\n\n```Python\nwont_work()  # Isto não vai funcionar 😱\nworks(foo=\"bar\")  # Isto funciona 🎉\n```\n\n...e é isso.\n\n////\n\n//// tab | Informação\n\nO código em blocos de código não deve ser modificado, com exceção dos comentários.\n\nVeja a seção `### Content of code blocks` no prompt geral em `scripts/translate.py`.\n\n////\n\n## Abas e caixas coloridas { #tabs-and-colored-boxes }\n\n//// tab | Teste\n\n/// info | Informação\nAlgum texto\n///\n\n/// note | Nota\nAlgum texto\n///\n\n/// note | Detalhes Técnicos\nAlgum texto\n///\n\n/// check | Verifique\nAlgum texto\n///\n\n/// tip | Dica\nAlgum texto\n///\n\n/// warning | Atenção\nAlgum texto\n///\n\n/// danger | Cuidado\nAlgum texto\n///\n\n////\n\n//// tab | Informação\n\nAbas e blocos `Info`/`Note`/`Warning`/etc. devem ter a tradução do seu título adicionada após uma barra vertical (`|`).\n\nVeja as seções `### Special blocks` e `### Tab blocks` no prompt geral em `scripts/translate.py`.\n\n////\n\n## Links da Web e internos { #web-and-internal-links }\n\n//// tab | Teste\n\nO texto do link deve ser traduzido, o endereço do link deve permanecer inalterado:\n\n* [Link para o título acima](#code-snippets)\n* [Link interno](index.md#installation)\n* [Link externo](https://sqlmodel.tiangolo.com/)\n* [Link para um estilo](https://fastapi.tiangolo.com/css/styles.css)\n* [Link para um script](https://fastapi.tiangolo.com/js/logic.js)\n* [Link para uma imagem](https://fastapi.tiangolo.com/img/foo.jpg)\n\nO texto do link deve ser traduzido, o endereço do link deve apontar para a tradução:\n\n* [Link do FastAPI](https://fastapi.tiangolo.com/pt/)\n\n////\n\n//// tab | Informação\n\nOs links devem ser traduzidos, mas seus endereços devem permanecer inalterados. Uma exceção são links absolutos para páginas da documentação do FastAPI. Nesse caso, devem apontar para a tradução.\n\nVeja a seção `### Links` no prompt geral em `scripts/translate.py`.\n\n////\n\n## Elementos HTML \"abbr\" { #html-abbr-elements }\n\n//// tab | Teste\n\nAqui estão algumas coisas envolvidas em elementos HTML \"abbr\" (algumas são inventadas):\n\n### O abbr fornece uma frase completa { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done – Fazer as Coisas\">GTD</abbr>\n* <abbr title=\"less than – menos que\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token – Token Web XML\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface – Interface de Gateway de Servidor Paralelo\">PSGI</abbr>\n\n### O abbr fornece uma frase completa e uma explicação { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network – Rede de Desenvolvedores da Mozilla: documentação para desenvolvedores, escrita pelo pessoal do Firefox\">MDN</abbr>\n* <abbr title=\"Input/Output – Entrada/Saída: leitura ou escrita em disco, comunicações de rede.\">I/O</abbr>.\n\n////\n\n//// tab | Informação\n\nOs atributos \"title\" dos elementos \"abbr\" são traduzidos seguindo algumas instruções específicas.\n\nAs traduções podem adicionar seus próprios elementos \"abbr\" que o LLM não deve remover. Por exemplo, para explicar palavras em inglês.\n\nVeja a seção `### HTML abbr elements` no prompt geral em `scripts/translate.py`.\n\n////\n\n## Elementos HTML \"dfn\" { #html-dfn-elements }\n\n* <dfn title=\"Um grupo de máquinas configuradas para estarem conectadas e trabalharem juntas de alguma forma.\">cluster</dfn>\n* <dfn title=\"Um método de aprendizado de máquina que usa redes neurais artificiais com numerosas camadas ocultas entre as camadas de entrada e saída, desenvolvendo assim uma estrutura interna abrangente\">Deep Learning</dfn>\n\n## Títulos { #headings }\n\n//// tab | Teste\n\n### Desenvolver uma webapp - um tutorial { #develop-a-webapp-a-tutorial }\n\nOlá.\n\n### Anotações de tipo e -anotações { #type-hints-and-annotations }\n\nOlá novamente.\n\n### Super- e subclasses { #super-and-subclasses }\n\nOlá novamente.\n\n////\n\n//// tab | Informação\n\nA única regra rígida para títulos é que o LLM deixe a parte do hash dentro de chaves inalterada, o que garante que os links não quebrem.\n\nVeja a seção `### Headings` no prompt geral em `scripts/translate.py`.\n\nPara algumas instruções específicas do idioma, veja, por exemplo, a seção `### Headings` em `docs/de/llm-prompt.md`.\n\n////\n\n## Termos usados na documentação { #terms-used-in-the-docs }\n\n//// tab | Teste\n\n* você\n* seu\n\n* por exemplo\n* etc.\n\n* `foo` como um `int`\n* `bar` como uma `str`\n* `baz` como uma `list`\n\n* o Tutorial - Guia do Usuário\n* o Guia do Usuário Avançado\n* a documentação do SQLModel\n* a documentação da API\n* a documentação automática\n\n* Ciência de Dados\n* Deep Learning\n* Aprendizado de Máquina\n* Injeção de Dependências\n* autenticação HTTP Basic\n* HTTP Digest\n* formato ISO\n* o padrão JSON Schema\n* o JSON schema\n* a definição do schema\n* Fluxo de Senha\n* Mobile\n\n* descontinuado\n* projetado\n* inválido\n* dinamicamente\n* padrão\n* padrão predefinido\n* sensível a maiúsculas e minúsculas\n* não sensível a maiúsculas e minúsculas\n\n* servir a aplicação\n* servir a página\n\n* o app\n* a aplicação\n\n* a requisição\n* a resposta\n* a resposta de erro\n\n* a operação de rota\n* o decorador de operação de rota\n* a função de operação de rota\n\n* o corpo\n* o corpo da requisição\n* o corpo da resposta\n* o corpo JSON\n* o corpo do formulário\n* o corpo do arquivo\n* o corpo da função\n\n* o parâmetro\n* o parâmetro de corpo\n* o parâmetro de path\n* o parâmetro de query\n* o parâmetro de cookie\n* o parâmetro de header\n* o parâmetro de formulário\n* o parâmetro da função\n\n* o evento\n* o evento de inicialização\n* a inicialização do servidor\n* o evento de encerramento\n* o evento de lifespan\n\n* o manipulador\n* o manipulador de eventos\n* o manipulador de exceções\n* tratar\n\n* o modelo\n* o modelo Pydantic\n* o modelo de dados\n* o modelo de banco de dados\n* o modelo de formulário\n* o objeto de modelo\n\n* a classe\n* a classe base\n* a classe pai\n* a subclasse\n* a classe filha\n* a classe irmã\n* o método de classe\n\n* o cabeçalho\n* os cabeçalhos\n* o cabeçalho de autorização\n* o cabeçalho `Authorization`\n* o cabeçalho encaminhado\n\n* o sistema de injeção de dependências\n* a dependência\n* o dependable\n* o dependant\n\n* limitado por I/O\n* limitado por CPU\n* concorrência\n* paralelismo\n* multiprocessamento\n\n* a env var\n* a variável de ambiente\n* o `PATH`\n* a variável `PATH`\n\n* a autenticação\n* o provedor de autenticação\n* a autorização\n* o formulário de autorização\n* o provedor de autorização\n* o usuário se autentica\n* o sistema autentica o usuário\n\n* a CLI\n* a interface de linha de comando\n\n* o servidor\n* o cliente\n\n* o provedor de nuvem\n* o serviço de nuvem\n\n* o desenvolvimento\n* as etapas de desenvolvimento\n\n* o dict\n* o dicionário\n* a enumeração\n* o enum\n* o membro do enum\n\n* o codificador\n* o decodificador\n* codificar\n* decodificar\n\n* a exceção\n* lançar\n\n* a expressão\n* a instrução\n\n* o frontend\n* o backend\n\n* a discussão do GitHub\n* a issue do GitHub\n\n* o desempenho\n* a otimização de desempenho\n\n* o tipo de retorno\n* o valor de retorno\n\n* a segurança\n* o esquema de segurança\n\n* a tarefa\n* a tarefa em segundo plano\n* a função da tarefa\n\n* o template\n* o mecanismo de template\n\n* a anotação de tipo\n* a anotação de tipo\n\n* o worker de servidor\n* o worker do Uvicorn\n* o Worker do Gunicorn\n* o processo worker\n* a classe de worker\n* a carga de trabalho\n\n* a implantação\n* implantar\n\n* o SDK\n* o kit de desenvolvimento de software\n\n* o `APIRouter`\n* o `requirements.txt`\n* o Bearer Token\n* a alteração com quebra de compatibilidade\n* o bug\n* o botão\n* o chamável\n* o código\n* o commit\n* o gerenciador de contexto\n* a corrotina\n* a sessão do banco de dados\n* o disco\n* o domínio\n* o mecanismo\n* o X falso\n* o método HTTP GET\n* o item\n* a biblioteca\n* o lifespan\n* o bloqueio\n* o middleware\n* a aplicação mobile\n* o módulo\n* a montagem\n* a rede\n* a origem\n* a sobrescrita\n* a carga útil\n* o processador\n* a propriedade\n* o proxy\n* o pull request\n* a consulta\n* a RAM\n* a máquina remota\n* o código de status\n* a string\n* a tag\n* o framework web\n* o curinga\n* retornar\n* validar\n\n////\n\n//// tab | Informação\n\nEsta é uma lista não completa e não normativa de termos (principalmente) técnicos vistos na documentação. Pode ser útil para o designer do prompt descobrir para quais termos o LLM precisa de uma ajudinha. Por exemplo, quando ele continua revertendo uma boa tradução para uma tradução subótima. Ou quando tem problemas para conjugar/declinar um termo no seu idioma.\n\nVeja, por exemplo, a seção `### List of English terms and their preferred German translations` em `docs/de/llm-prompt.md`.\n\n////\n"
  },
  {
    "path": "docs/pt/docs/about/index.md",
    "content": "# Sobre { #about }\n\nSobre o FastAPI, seu design, inspiração e mais. 🤓\n"
  },
  {
    "path": "docs/pt/docs/advanced/additional-responses.md",
    "content": "# Retornos Adicionais no OpenAPI { #additional-responses-in-openapi }\n\n/// warning | Atenção\n\nEste é um tema bem avançado.\n\nSe você está começando com o **FastAPI**, provavelmente você não precisa disso.\n\n///\n\nVocê pode declarar retornos adicionais, com códigos de status adicionais, media types, descrições, etc.\n\nEssas respostas adicionais serão incluídas no esquema do OpenAPI, e também aparecerão na documentação da API.\n\nPorém para as respostas adicionais, você deve garantir que está retornando um `Response` como por exemplo o `JSONResponse` diretamente, junto com o código de status e o conteúdo.\n\n## Retorno Adicional com `model` { #additional-response-with-model }\n\nVocê pode fornecer o parâmetro `responses` aos seus *decoradores de caminho*.\n\nEste parâmetro recebe um `dict`, as chaves são os códigos de status para cada retorno, como por exemplo `200`, e os valores são um outro `dict` com a informação de cada um deles.\n\nCada um desses `dict` de retorno pode ter uma chave `model`, contendo um modelo do Pydantic, assim como o `response_model`.\n\nO **FastAPI** pegará este modelo, gerará o esquema JSON dele e incluirá no local correto do OpenAPI.\n\nPor exemplo, para declarar um outro retorno com o status code `404` e um modelo do Pydantic chamado `Message`, você pode escrever:\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | Nota\n\nLembre-se que você deve retornar o `JSONResponse` diretamente.\n\n///\n\n/// info | Informação\n\nA chave `model` não é parte do OpenAPI.\n\nO **FastAPI** pegará o modelo do Pydantic, gerará o `JSON Schema`, e adicionará no local correto.\n\nO local correto é:\n\n* Na chave `content`, que tem como valor um outro objeto JSON (`dict`) que contém:\n    * Uma chave com o media type, como por exemplo `application/json`, que contém como valor um outro objeto JSON, contendo::\n        * Uma chave `schema`, que contém como valor o JSON Schema do modelo, sendo este o local correto.\n            * O **FastAPI** adiciona aqui a referência dos esquemas JSON globais que estão localizados em outro lugar, ao invés de incluí-lo diretamente. Deste modo, outras aplicações e clientes podem utilizar estes esquemas JSON diretamente, fornecer melhores ferramentas de geração de código, etc.\n\n///\n\nO retorno gerado no OpenAPI para esta *operação de rota* será:\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nOs esquemas são referenciados em outro local dentro do esquema OpenAPI:\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## Media types adicionais para o retorno principal { #additional-media-types-for-the-main-response }\n\nVocê pode utilizar o mesmo parâmetro `responses` para adicionar diferentes media types para o mesmo retorno principal.\n\nPor exemplo, você pode adicionar um media type adicional de `image/png`, declarando que a sua *operação de rota* pode retornar um objeto JSON (com o media type `application/json`) ou uma imagem PNG:\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | Nota\n\nNote que você deve retornar a imagem utilizando um `FileResponse` diretamente.\n\n///\n\n/// info | Informação\n\nA menos que você especifique um media type diferente explicitamente em seu parâmetro `responses`, o FastAPI assumirá que o retorno possui o mesmo media type contido na classe principal de retorno (padrão `application/json`).\n\nPorém se você especificou uma classe de retorno com o valor `None` como media type, o FastAPI utilizará `application/json` para qualquer retorno adicional que possui um modelo associado.\n\n///\n\n## Combinando informações { #combining-information }\n\nVocê também pode combinar informações de diferentes lugares, incluindo os parâmetros `response_model`, `status_code`, e `responses`.\n\nVocê pode declarar um `response_model`, utilizando o código de status padrão `200` (ou um customizado caso você precise), e depois adicionar informações adicionais para esse mesmo retorno em `responses`, diretamente no esquema OpenAPI.\n\nO **FastAPI** manterá as informações adicionais do `responses`, e combinará com o esquema JSON do seu modelo.\n\nPor exemplo, você pode declarar um retorno com o código de status `404` que utiliza um modelo do Pydantic e tem uma `description` customizada.\n\nE um retorno com o código de status `200` que utiliza o seu `response_model`, porém inclui um `example` customizado:\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\nIsso será combinado e incluído em seu OpenAPI, e disponibilizado na documentação da sua API:\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## Combinar retornos predefinidos e personalizados { #combine-predefined-responses-and-custom-ones }\n\nVocê pode querer possuir alguns retornos predefinidos que são aplicados para diversas *operações de rota*, porém você deseja combinar com retornos personalizados que são necessários para cada *operação de rota*.\n\nPara estes casos, você pode utilizar a técnica do Python de \"desempacotamento\" de um `dict` utilizando `**dict_to_unpack`:\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\nAqui, o `new_dict` terá todos os pares de chave-valor do `old_dict` mais o novo par de chave-valor:\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\nVocê pode utilizar essa técnica para reutilizar alguns retornos predefinidos nas suas *operações de rota* e combiná-las com personalizações adicionais.\n\nPor exemplo:\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## Mais informações sobre retornos OpenAPI { #more-information-about-openapi-responses }\n\nPara verificar exatamente o que você pode incluir nos retornos, você pode conferir estas seções na especificação do OpenAPI:\n\n* [Objeto de Retornos do OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object), inclui o `Response Object`.\n* [Objeto de Retorno do OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object), você pode incluir qualquer coisa dele diretamente em cada retorno dentro do seu parâmetro `responses`. Incluindo `description`, `headers`, `content` (dentro dele que você declara diferentes media types e esquemas JSON), e `links`.\n"
  },
  {
    "path": "docs/pt/docs/advanced/additional-status-codes.md",
    "content": "# Códigos de status adicionais { #additional-status-codes }\n\nPor padrão, o **FastAPI** retornará as respostas utilizando o `JSONResponse`, adicionando o conteúdo do retorno da sua *operação de rota* dentro do `JSONResponse`.\n\nEle usará o código de status padrão ou o que você definir na sua *operação de rota*.\n\n## Códigos de status adicionais { #additional-status-codes_1 }\n\nCaso você queira retornar códigos de status adicionais além do código principal, você pode fazer isso retornando um `Response` diretamente, como por exemplo um `JSONResponse`, e definir os códigos de status adicionais diretamente.\n\nPor exemplo, vamos dizer que você deseja ter uma *operação de rota* que permita atualizar itens, e retornar um código de status HTTP 200 \"OK\" quando for bem sucedido.\n\nMas você também deseja aceitar novos itens. E quando os itens não existiam, ele os cria, e retorna o código de status HTTP 201 \"Created\".\n\nPara conseguir isso, importe `JSONResponse` e retorne o seu conteúdo diretamente, definindo o `status_code` que você deseja:\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning | Atenção\n\nQuando você retorna um `Response` diretamente, como no exemplo acima, ele será retornado diretamente.\n\nEle não será serializado com um modelo, etc.\n\nGaranta que ele tenha toda informação que você deseja, e que os valores sejam um JSON válido (caso você esteja usando `JSONResponse`).\n\n///\n\n/// note | Detalhes Técnicos\n\nVocê também pode utilizar `from starlette.responses import JSONResponse`.\n\nO **FastAPI** disponibiliza o `starlette.responses` como `fastapi.responses` apenas por conveniência para você, o programador. Porém a maioria dos retornos disponíveis vem diretamente do Starlette. O mesmo com `status`.\n\n///\n\n## OpenAPI e documentação da API { #openapi-and-api-docs }\n\nSe você retorna códigos de status adicionais e retornos diretamente, eles não serão incluídos no esquema do OpenAPI (a documentação da API), porque o FastAPI não tem como saber de antemão o que será retornado.\n\nMas você pode documentar isso no seu código, utilizando: [Retornos Adicionais](additional-responses.md).\n"
  },
  {
    "path": "docs/pt/docs/advanced/advanced-dependencies.md",
    "content": "# Dependências avançadas { #advanced-dependencies }\n\n## Dependências parametrizadas { #parameterized-dependencies }\n\nTodas as dependências que vimos até agora são funções ou classes fixas.\n\nMas podem ocorrer casos onde você deseja ser capaz de definir parâmetros na dependência, sem ter a necessidade de declarar diversas funções ou classes.\n\nVamos imaginar que queremos ter uma dependência que verifica se o parâmetro de consulta `q` possui um valor fixo.\n\nPorém nós queremos poder parametrizar o conteúdo fixo.\n\n## Uma instância \"chamável\" { #a-callable-instance }\n\nEm Python existe uma maneira de fazer com que uma instância de uma classe seja um \"chamável\".\n\nNão propriamente a classe (que já é um chamável), mas a instância desta classe.\n\nPara fazer isso, nós declaramos o método `__call__`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\nNeste caso, o `__call__` é o que o **FastAPI** utilizará para verificar parâmetros adicionais e sub dependências, e isso é o que será chamado para passar o valor ao parâmetro na sua *função de operação de rota* posteriormente.\n\n## Parametrizar a instância { #parameterize-the-instance }\n\nE agora, nós podemos utilizar o `__init__` para declarar os parâmetros da instância que podemos utilizar para \"parametrizar\" a dependência:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\nNeste caso, o **FastAPI** nunca tocará ou se importará com o `__init__`, nós vamos utilizar diretamente em nosso código.\n\n## Crie uma instância { #create-an-instance }\n\nNós poderíamos criar uma instância desta classe com:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\nE deste modo nós podemos \"parametrizar\" a nossa dependência, que agora possui `\"bar\"` dentro dele, como o atributo `checker.fixed_content`.\n\n## Utilize a instância como dependência { #use-the-instance-as-a-dependency }\n\nEntão, nós podemos utilizar este `checker` em um `Depends(checker)`, no lugar de `Depends(FixedContentQueryChecker)`, porque a dependência é a instância, `checker`, e não a própria classe.\n\nE quando a dependência for resolvida, o **FastAPI** chamará este `checker` como:\n\n```Python\nchecker(q=\"somequery\")\n```\n\n...e passar o que quer que isso retorne como valor da dependência em nossa *função de operação de rota* como o parâmetro `fixed_content_included`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | Dica\n\nTudo isso parece não ser natural. E pode não estar muito claro ou aparentar ser útil ainda.\n\nEstes exemplos são intencionalmente simples, porém mostram como tudo funciona.\n\nNos capítulos sobre segurança, existem funções utilitárias que são implementadas desta maneira.\n\nSe você entendeu tudo isso, você já sabe como essas funções utilitárias para segurança funcionam por debaixo dos panos.\n\n///\n\n## Dependências com `yield`, `HTTPException`, `except` e Tarefas em Segundo Plano { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | Atenção\n\nMuito provavelmente você não precisa desses detalhes técnicos.\n\nEsses detalhes são úteis principalmente se você tinha uma aplicação FastAPI anterior à versão 0.121.0 e está enfrentando problemas com dependências com `yield`.\n\n///\n\nDependências com `yield` evoluíram ao longo do tempo para contemplar diferentes casos de uso e corrigir alguns problemas, aqui está um resumo do que mudou.\n\n### Dependências com `yield` e `scope` { #dependencies-with-yield-and-scope }\n\nNa versão 0.121.0, o FastAPI adicionou suporte a `Depends(scope=\"function\")` para dependências com `yield`.\n\nUsando `Depends(scope=\"function\")`, o código de saída após o `yield` é executado logo depois que a *função de operação de rota* termina, antes de a response ser enviada de volta ao cliente.\n\nE ao usar `Depends(scope=\"request\")` (o padrão), o código de saída após o `yield` é executado depois que a response é enviada.\n\nVocê pode ler mais na documentação em [Dependências com `yield` - Saída antecipada e `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope).\n\n### Dependências com `yield` e `StreamingResponse`, Detalhes Técnicos { #dependencies-with-yield-and-streamingresponse-technical-details }\n\nAntes do FastAPI 0.118.0, se você usasse uma dependência com `yield`, o código de saída (após o `yield`) rodaria depois que a *função de operação de rota* retornasse, mas logo antes de enviar a resposta.\n\nA intenção era evitar manter recursos por mais tempo que o necessário, esperando a resposta percorrer a rede.\n\nEssa mudança também significava que, se você retornasse um `StreamingResponse`, o código de saída da dependência com `yield` já teria sido executado.\n\nPor exemplo, se você tivesse uma sessão de banco de dados em uma dependência com `yield`, o `StreamingResponse` não conseguiria usar essa sessão enquanto transmite dados, porque a sessão já teria sido fechada no código de saída após o `yield`.\n\nEsse comportamento foi revertido na versão 0.118.0, para que o código de saída após o `yield` seja executado depois que a resposta for enviada.\n\n/// info | Informação\n\nComo você verá abaixo, isso é muito semelhante ao comportamento antes da versão 0.106.0, mas com várias melhorias e correções de bugs para casos extremos.\n\n///\n\n#### Casos de uso com código de saída antecipado { #use-cases-with-early-exit-code }\n\nHá alguns casos de uso, com condições específicas, que poderiam se beneficiar do comportamento antigo de executar o código de saída das dependências com `yield` antes de enviar a resposta.\n\nPor exemplo, imagine que você tem código que usa uma sessão de banco de dados em uma dependência com `yield` apenas para verificar um usuário, mas a sessão de banco de dados nunca é usada novamente na *função de operação de rota*, somente na dependência, e a resposta demora a ser enviada, como um `StreamingResponse` que envia dados lentamente, mas por algum motivo não usa o banco de dados.\n\nNesse caso, a sessão de banco de dados seria mantida até que a resposta termine de ser enviada, mas se você não a usa, então não seria necessário mantê-la.\n\nVeja como poderia ser:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\nO código de saída, o fechamento automático da `Session` em:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n...seria executado depois que a resposta terminar de enviar os dados lentos:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nMas como `generate_stream()` não usa a sessão do banco de dados, não é realmente necessário manter a sessão aberta enquanto envia a resposta.\n\nSe você tiver esse caso específico usando SQLModel (ou SQLAlchemy), você poderia fechar explicitamente a sessão depois que não precisar mais dela:\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\nDessa forma a sessão liberaria a conexão com o banco de dados, para que outras requisições pudessem usá-la.\n\nSe você tiver um caso diferente que precise sair antecipadamente de uma dependência com `yield`, por favor crie uma [Pergunta no GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions) com o seu caso específico e por que você se beneficiaria de ter o fechamento antecipado para dependências com `yield`.\n\nSe houver casos de uso convincentes para fechamento antecipado em dependências com `yield`, considerarei adicionar uma nova forma de optar por esse fechamento antecipado.\n\n### Dependências com `yield` e `except`, Detalhes Técnicos { #dependencies-with-yield-and-except-technical-details }\n\nAntes do FastAPI 0.110.0, se você usasse uma dependência com `yield`, e então capturasse uma exceção com `except` nessa dependência, e você não relançasse a exceção, a exceção seria automaticamente levantada/encaminhada para quaisquer tratadores de exceção ou para o tratador de erro interno do servidor.\n\nIsso foi alterado na versão 0.110.0 para corrigir consumo de memória não tratado decorrente de exceções encaminhadas sem um tratador (erros internos do servidor), e para torná-lo consistente com o comportamento do código Python regular.\n\n### Tarefas em Segundo Plano e Dependências com `yield`, Detalhes Técnicos { #background-tasks-and-dependencies-with-yield-technical-details }\n\nAntes do FastAPI 0.106.0, lançar exceções após o `yield` não era possível, o código de saída em dependências com `yield` era executado depois que a resposta era enviada, então [Tratadores de Exceções](../tutorial/handling-errors.md#install-custom-exception-handlers) já teriam sido executados.\n\nIsso foi projetado assim principalmente para permitir o uso dos mesmos objetos \"yielded\" por dependências dentro de tarefas em segundo plano, porque o código de saída seria executado depois que as tarefas em segundo plano fossem concluídas.\n\nIsso foi alterado no FastAPI 0.106.0 com a intenção de não manter recursos enquanto se espera a response percorrer a rede.\n\n/// tip | Dica\n\nAlém disso, uma tarefa em segundo plano normalmente é um conjunto de lógica independente que deve ser tratado separadamente, com seus próprios recursos (por exemplo, sua própria conexão de banco de dados).\n\nAssim, desta forma você provavelmente terá um código mais limpo.\n\n///\n\nSe você costumava depender desse comportamento, agora você deve criar os recursos para tarefas em segundo plano dentro da própria tarefa em segundo plano, e usar internamente apenas dados que não dependam dos recursos de dependências com `yield`.\n\nPor exemplo, em vez de usar a mesma sessão de banco de dados, você criaria uma nova sessão de banco de dados dentro da tarefa em segundo plano, e obteria os objetos do banco de dados usando essa nova sessão. E então, em vez de passar o objeto do banco de dados como parâmetro para a função da tarefa em segundo plano, você passaria o ID desse objeto e então obteria o objeto novamente dentro da função da tarefa em segundo plano.\n"
  },
  {
    "path": "docs/pt/docs/advanced/advanced-python-types.md",
    "content": "# Tipos Avançados de Python { #advanced-python-types }\n\nAqui estão algumas ideias adicionais que podem ser úteis ao trabalhar com tipos em Python.\n\n## Usando `Union` ou `Optional` { #using-union-or-optional }\n\nSe, por algum motivo, seu código não puder usar `|`, por exemplo, se não for em uma anotação de tipo, mas em algo como `response_model=`, em vez de usar a barra vertical (`|`) você pode usar `Union` do `typing`.\n\nPor exemplo, você poderia declarar que algo pode ser `str` ou `None`:\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\nO `typing` também tem um atalho para declarar que algo pode ser `None`, com `Optional`.\n\nAqui vai uma dica do meu ponto de vista bem subjetivo:\n\n* 🚨 Evite usar `Optional[SomeType]`\n* Em vez disso ✨ use **`Union[SomeType, None]`** ✨.\n\nAmbos são equivalentes e, por baixo, são a mesma coisa, mas eu recomendaria `Union` em vez de `Optional` porque a palavra \"opcional\" sugere que o valor é opcional; na verdade, significa \"pode ser `None`\", mesmo quando não é opcional e continua sendo obrigatório.\n\nAcho que `Union[SomeType, None]` é mais explícito quanto ao significado.\n\nÉ apenas uma questão de palavras e nomes. Mas essas palavras podem influenciar como você e sua equipe pensam sobre o código.\n\nComo exemplo, veja esta função:\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\nO parâmetro `name` é definido como `Optional[str]`, mas não é opcional; não é possível chamar a função sem o parâmetro:\n\n```Python\nsay_hi()  # Ah, não, isso gera um erro! 😱\n```\n\nO parâmetro `name` continua obrigatório (não é opcional) porque não tem valor padrão. Ainda assim, `name` aceita `None` como valor:\n\n```Python\nsay_hi(name=None)  # Isso funciona, None é válido 🎉\n```\n\nA boa notícia é que, na maioria dos casos, você poderá simplesmente usar `|` para definir uniões de tipos:\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\nEntão, normalmente você não precisa se preocupar com nomes como `Optional` e `Union`. 😎\n"
  },
  {
    "path": "docs/pt/docs/advanced/async-tests.md",
    "content": "# Testes Assíncronos { #async-tests }\n\nVocê já viu como testar as suas aplicações **FastAPI** utilizando o `TestClient` que é fornecido. Até agora, você viu apenas como escrever testes síncronos, sem utilizar funções `async`.\n\nSer capaz de utilizar funções assíncronas em seus testes pode ser útil, por exemplo, quando você está realizando uma consulta em seu banco de dados de maneira assíncrona. Imagine que você deseja testar realizando requisições para a sua aplicação FastAPI e depois verificar que a sua aplicação inseriu corretamente as informações no banco de dados, ao utilizar uma biblioteca assíncrona para banco de dados.\n\nVamos ver como nós podemos fazer isso funcionar.\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\nSe quisermos chamar funções assíncronas em nossos testes, as nossas funções de teste precisam ser assíncronas. O AnyIO oferece um plugin bem legal para isso, que nos permite especificar que algumas das nossas funções de teste precisam ser chamadas de forma assíncrona.\n\n## HTTPX { #httpx }\n\nMesmo que a sua aplicação **FastAPI** utilize funções normais com `def` no lugar de `async def`, ela ainda é uma aplicação `async` por baixo dos panos.\n\nO `TestClient` faz algumas mágicas para invocar a aplicação FastAPI assíncrona em suas funções `def` normais, utilizando o pytest padrão. Porém a mágica não acontece mais quando nós estamos utilizando dentro de funções assíncronas. Ao executar os nossos testes de forma assíncrona, nós não podemos mais utilizar o `TestClient` dentro das nossas funções de teste.\n\nO `TestClient` é baseado no [HTTPX](https://www.python-httpx.org), e felizmente nós podemos utilizá-lo diretamente para testar a API.\n\n## Exemplo { #example }\n\nPara um exemplos simples, vamos considerar uma estrutura de arquivos semelhante ao descrito em [Aplicações Maiores](../tutorial/bigger-applications.md) e [Testes](../tutorial/testing.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nO arquivo `main.py` teria:\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\nO arquivo `test_main.py` teria os testes para para o arquivo `main.py`, ele poderia ficar assim:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## Executá-lo { #run-it }\n\nVocê pode executar os seus testes normalmente via:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## Em Detalhes { #in-detail }\n\nO marcador `@pytest.mark.anyio` informa ao pytest que esta função de teste deve ser invocada de maneira assíncrona:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip | Dica\n\nNote que a função de teste é `async def` agora, no lugar de apenas `def` como quando estávamos utilizando o `TestClient` anteriormente.\n\n///\n\nEntão podemos criar um `AsyncClient` com a aplicação, e enviar requisições assíncronas para ela utilizando `await`.\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\nIsso é equivalente a:\n\n```Python\nresponse = client.get('/')\n```\n\n...que nós utilizamos para fazer as nossas requisições utilizando o `TestClient`.\n\n/// tip | Dica\n\nNote que nós estamos utilizando async/await com o novo `AsyncClient` - a requisição é assíncrona.\n\n///\n\n/// warning | Atenção\n\nSe a sua aplicação depende de eventos de lifespan, o `AsyncClient` não acionará estes eventos. Para garantir que eles são acionados, utilize o `LifespanManager` do [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage).\n\n///\n\n## Outras Chamadas de Funções Assíncronas { #other-asynchronous-function-calls }\n\nComo a função de teste agora é assíncrona, você pode chamar (e `await`) outras funções `async` além de enviar requisições para a sua aplicação FastAPI em seus testes, exatamente como você as chamaria em qualquer outro lugar do seu código.\n\n/// tip | Dica\n\nSe você se deparar com um `RuntimeError: Task attached to a different loop` ao integrar funções assíncronas em seus testes (e.g. ao utilizar o [MotorClient do MongoDB](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop)) Lembre-se de instanciar objetos que precisam de um loop de eventos (*event loop*) apenas em funções assíncronas, e.g. um callback `@app.on_event(\"startup\")`.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/advanced/behind-a-proxy.md",
    "content": "# Atrás de um Proxy { #behind-a-proxy }\n\nEm muitas situações, você usaria um **proxy** como Traefik ou Nginx na frente da sua aplicação FastAPI.\n\nEsses proxies podem lidar com certificados HTTPS e outras coisas.\n\n## Headers Encaminhados pelo Proxy { #proxy-forwarded-headers }\n\nUm **proxy** na frente da sua aplicação normalmente definiria alguns headers dinamicamente antes de enviar as requisições para o seu **servidor**, para informar ao servidor que a requisição foi **encaminhada** pelo proxy, informando a URL original (pública), incluindo o domínio, que está usando HTTPS, etc.\n\nO programa do **servidor** (por exemplo, **Uvicorn** via **CLI do FastAPI**) é capaz de interpretar esses headers e então repassar essas informações para a sua aplicação.\n\nMas, por segurança, como o servidor não sabe que está atrás de um proxy confiável, ele não interpretará esses headers.\n\n/// note | Detalhes Técnicos\n\nOs headers do proxy são:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### Ativar headers encaminhados pelo proxy { #enable-proxy-forwarded-headers }\n\nVocê pode iniciar a CLI do FastAPI com a opção de linha de comando `--forwarded-allow-ips` e informar os endereços IP que devem ser confiáveis para ler esses headers encaminhados.\n\nSe você definir como `--forwarded-allow-ips=\"*\"`, ele confiará em todos os IPs de entrada.\n\nSe o seu **servidor** estiver atrás de um **proxy** confiável e somente o proxy falar com ele, isso fará com que ele aceite seja qual for o IP desse **proxy**.\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Redirecionamentos com HTTPS { #redirects-with-https }\n\nPor exemplo, suponha que você defina uma *operação de rota* `/items/`:\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\nSe o cliente tentar ir para `/items`, por padrão, ele seria redirecionado para `/items/`.\n\nMas antes de definir a opção de linha de comando `--forwarded-allow-ips`, poderia redirecionar para `http://localhost:8000/items/`.\n\nMas talvez sua aplicação esteja hospedada em `https://mysuperapp.com`, e o redirecionamento deveria ser para `https://mysuperapp.com/items/`.\n\nAo definir `--proxy-headers`, agora o FastAPI conseguirá redirecionar para o local correto. 😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip | Dica\n\nSe você quiser saber mais sobre HTTPS, confira o tutorial [Sobre HTTPS](../deployment/https.md).\n\n///\n\n### Como funcionam os headers encaminhados pelo proxy { #how-proxy-forwarded-headers-work }\n\nAqui está uma representação visual de como o **proxy** adiciona headers encaminhados entre o cliente e o **servidor da aplicação**:\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Proxy as Proxy/Load Balancer\n    participant Server as FastAPI Server\n\n    Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: Proxy adds forwarded headers\n\n    Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)\n\n    Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs\n\n    Proxy->>Client: HTTPS Response\n```\n\nO **proxy** intercepta a requisição original do cliente e adiciona os headers especiais de encaminhamento (`X-Forwarded-*`) antes de repassar a requisição para o **servidor da aplicação**.\n\nEsses headers preservam informações sobre a requisição original que, de outra forma, seriam perdidas:\n\n* **X-Forwarded-For**: o endereço IP original do cliente\n* **X-Forwarded-Proto**: o protocolo original (`https`)\n* **X-Forwarded-Host**: o host original (`mysuperapp.com`)\n\nQuando a **CLI do FastAPI** é configurada com `--forwarded-allow-ips`, ela confia nesses headers e os utiliza, por exemplo, para gerar as URLs corretas em redirecionamentos.\n\n## Proxy com um prefixo de path removido { #proxy-with-a-stripped-path-prefix }\n\nVocê pode ter um proxy que adiciona um prefixo de path à sua aplicação.\n\nNesses casos, você pode usar `root_path` para configurar sua aplicação.\n\nO `root_path` é um mecanismo fornecido pela especificação ASGI (na qual o FastAPI é construído, através do Starlette).\n\nO `root_path` é usado para lidar com esses casos específicos.\n\nE também é usado internamente ao montar sub-aplicações.\n\nTer um proxy com um prefixo de path removido, nesse caso, significa que você poderia declarar um path em `/app` no seu código, mas então você adiciona uma camada no topo (o proxy) que colocaria sua aplicação **FastAPI** sob um path como `/api/v1`.\n\nNesse caso, o path original `/app` seria servido em `/api/v1/app`.\n\nEmbora todo o seu código esteja escrito assumindo que existe apenas `/app`.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\nE o proxy estaria **\"removendo\"** o **prefixo de path** dinamicamente antes de transmitir a solicitação para o servidor da aplicação (provavelmente Uvicorn via CLI do FastAPI), mantendo sua aplicação convencida de que está sendo servida em `/app`, para que você não precise atualizar todo o seu código para incluir o prefixo `/api/v1`.\n\nAté aqui, tudo funcionaria normalmente.\n\nMas então, quando você abre a interface de documentação integrada (o frontend), ela esperaria obter o OpenAPI schema em `/openapi.json`, em vez de `/api/v1/openapi.json`.\n\nEntão, o frontend (que roda no navegador) tentaria acessar `/openapi.json` e não conseguiria obter o OpenAPI schema.\n\nComo temos um proxy com um prefixo de path de `/api/v1` para nossa aplicação, o frontend precisa buscar o OpenAPI schema em `/api/v1/openapi.json`.\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy on http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server on http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip | Dica\n\nO IP `0.0.0.0` é comumente usado para significar que o programa escuta em todos os IPs disponíveis naquela máquina/servidor.\n\n///\n\nA interface de documentação também precisaria do OpenAPI schema para declarar que este `server` da API está localizado em `/api/v1` (atrás do proxy). Por exemplo:\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // Mais coisas aqui\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // Mais coisas aqui\n    }\n}\n```\n\nNeste exemplo, o \"Proxy\" poderia ser algo como **Traefik**. E o servidor seria algo como a CLI do FastAPI com **Uvicorn**, executando sua aplicação FastAPI.\n\n### Fornecendo o `root_path` { #providing-the-root-path }\n\nPara conseguir isso, você pode usar a opção de linha de comando `--root-path` assim:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nSe você usar Hypercorn, ele também tem a opção `--root-path`.\n\n/// note | Detalhes Técnicos\n\nA especificação ASGI define um `root_path` para esse caso de uso.\n\nE a opção de linha de comando `--root-path` fornece esse `root_path`.\n\n///\n\n### Verificando o `root_path` atual { #checking-the-current-root-path }\n\nVocê pode obter o `root_path` atual usado pela sua aplicação para cada solicitação, ele faz parte do dicionário `scope` (que faz parte da especificação ASGI).\n\nAqui estamos incluindo-o na mensagem apenas para fins de demonstração.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\nEntão, se você iniciar o Uvicorn com:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nA resposta seria algo como:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### Configurando o `root_path` na aplicação FastAPI { #setting-the-root-path-in-the-fastapi-app }\n\nAlternativamente, se você não tiver uma maneira de fornecer uma opção de linha de comando como `--root-path` ou equivalente, você pode definir o parâmetro `root_path` ao criar sua aplicação FastAPI:\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\nPassar o `root_path` para `FastAPI` seria o equivalente a passar a opção de linha de comando `--root-path` para Uvicorn ou Hypercorn.\n\n### Sobre `root_path` { #about-root-path }\n\nTenha em mente que o servidor (Uvicorn) não usará esse `root_path` para nada além de passá-lo para a aplicação.\n\nMas se você acessar com seu navegador [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app) você verá a resposta normal:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nPortanto, ele não esperará ser acessado em `http://127.0.0.1:8000/api/v1/app`.\n\nO Uvicorn esperará que o proxy acesse o Uvicorn em `http://127.0.0.1:8000/app`, e então seria responsabilidade do proxy adicionar o prefixo extra `/api/v1` no topo.\n\n## Sobre proxies com um prefixo de path removido { #about-proxies-with-a-stripped-path-prefix }\n\nTenha em mente que um proxy com prefixo de path removido é apenas uma das maneiras de configurá-lo.\n\nProvavelmente, em muitos casos, o padrão será que o proxy não tenha um prefixo de path removido.\n\nEm um caso como esse (sem um prefixo de path removido), o proxy escutaria em algo como `https://myawesomeapp.com`, e então, se o navegador acessar `https://myawesomeapp.com/api/v1/app` e seu servidor (por exemplo, Uvicorn) escutar em `http://127.0.0.1:8000`, o proxy (sem um prefixo de path removido) acessaria o Uvicorn no mesmo path: `http://127.0.0.1:8000/api/v1/app`.\n\n## Testando localmente com Traefik { #testing-locally-with-traefik }\n\nVocê pode facilmente executar o experimento localmente com um prefixo de path removido usando [Traefik](https://docs.traefik.io/).\n\n[Faça o download do Traefik](https://github.com/containous/traefik/releases), ele é um único binário, você pode extrair o arquivo compactado e executá-lo diretamente do terminal.\n\nEntão, crie um arquivo `traefik.toml` com:\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\nIsso diz ao Traefik para escutar na porta 9999 e usar outro arquivo `routes.toml`.\n\n/// tip | Dica\n\nEstamos usando a porta 9999 em vez da porta padrão HTTP 80 para que você não precise executá-lo com privilégios de administrador (`sudo`).\n\n///\n\nAgora crie esse outro arquivo `routes.toml`:\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\nEsse arquivo configura o Traefik para usar o prefixo de path `/api/v1`.\n\nE então o Traefik redirecionará suas solicitações para seu Uvicorn rodando em `http://127.0.0.1:8000`.\n\nAgora inicie o Traefik:\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\nE agora inicie sua aplicação, usando a opção `--root-path`:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Verifique as respostas { #check-the-responses }\n\nAgora, se você for ao URL com a porta para o Uvicorn: [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), você verá a resposta normal:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip | Dica\n\nPerceba que, mesmo acessando em `http://127.0.0.1:8000/app`, ele mostra o `root_path` de `/api/v1`, retirado da opção `--root-path`.\n\n///\n\nE agora abra o URL com a porta para o Traefik, incluindo o prefixo de path: [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app).\n\nObtemos a mesma resposta:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nmas desta vez no URL com o prefixo de path fornecido pelo proxy: `/api/v1`.\n\nClaro, a ideia aqui é que todos acessariam a aplicação através do proxy, então a versão com o prefixo de path `/api/v1` é a \"correta\".\n\nE a versão sem o prefixo de path (`http://127.0.0.1:8000/app`), fornecida diretamente pelo Uvicorn, seria exclusivamente para o _proxy_ (Traefik) acessá-la.\n\nIsso demonstra como o Proxy (Traefik) usa o prefixo de path e como o servidor (Uvicorn) usa o `root_path` da opção `--root-path`.\n\n### Verifique a interface de documentação { #check-the-docs-ui }\n\nMas aqui está a parte divertida. ✨\n\nA maneira \"oficial\" de acessar a aplicação seria através do proxy com o prefixo de path que definimos. Então, como esperaríamos, se você tentar a interface de documentação servida diretamente pelo Uvicorn, sem o prefixo de path no URL, ela não funcionará, porque espera ser acessada através do proxy.\n\nVocê pode verificar em [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\nMas se acessarmos a interface de documentação no URL \"oficial\" usando o proxy com a porta `9999`, em `/api/v1/docs`, ela funciona corretamente! 🎉\n\nVocê pode verificar em [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\nExatamente como queríamos. ✔️\n\nIsso porque o FastAPI usa esse `root_path` para criar o `server` padrão no OpenAPI com o URL fornecido pelo `root_path`.\n\n## Servidores adicionais { #additional-servers }\n\n/// warning | Atenção\n\nEste é um caso de uso mais avançado. Sinta-se à vontade para pular.\n\n///\n\nPor padrão, o **FastAPI** criará um `server` no OpenAPI schema com o URL para o `root_path`.\n\nMas você também pode fornecer outros `servers` alternativos, por exemplo, se quiser que a mesma interface de documentação interaja com ambientes de staging e produção.\n\nSe você passar uma lista personalizada de `servers` e houver um `root_path` (porque sua API está atrás de um proxy), o **FastAPI** inserirá um \"server\" com esse `root_path` no início da lista.\n\nPor exemplo:\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\nGerará um OpenAPI schema como:\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // Mais coisas aqui\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // Mais coisas aqui\n    }\n}\n```\n\n/// tip | Dica\n\nPerceba o servidor gerado automaticamente com um valor `url` de `/api/v1`, retirado do `root_path`.\n\n///\n\nNa interface de documentação em [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) parecerá:\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip | Dica\n\nA interface de documentação interagirá com o servidor que você selecionar.\n\n///\n\n/// note | Detalhes Técnicos\n\nA propriedade `servers` na especificação OpenAPI é opcional.\n\nSe você não especificar o parâmetro `servers` e `root_path` for igual a `/`, a propriedade `servers` no OpenAPI gerado será totalmente omitida por padrão, o que equivale a um único servidor com valor de `url` igual a `/`.\n\n///\n\n### Desabilitar servidor automático de `root_path` { #disable-automatic-server-from-root-path }\n\nSe você não quiser que o **FastAPI** inclua um servidor automático usando o `root_path`, você pode usar o parâmetro `root_path_in_servers=False`:\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\ne então ele não será incluído no OpenAPI schema.\n\n## Montando uma sub-aplicação { #mounting-a-sub-application }\n\nSe você precisar montar uma sub-aplicação (como descrito em [Sub-aplicações - Montagens](sub-applications.md)) enquanto também usa um proxy com `root_path`, você pode fazer isso normalmente, como esperaria.\n\nO FastAPI usará internamente o `root_path` de forma inteligente, então tudo funcionará. ✨\n"
  },
  {
    "path": "docs/pt/docs/advanced/custom-response.md",
    "content": "# Resposta Personalizada - HTML, Stream, File e outras { #custom-response-html-stream-file-others }\n\nPor padrão, o **FastAPI** retornará respostas JSON.\n\nVocê pode sobrescrever isso retornando uma `Response` diretamente, como visto em [Retornando uma Resposta Diretamente](response-directly.md).\n\nMas se você retornar uma `Response` diretamente (ou qualquer subclasse, como `JSONResponse`), os dados não serão convertidos automaticamente (mesmo que você declare um `response_model`), e a documentação não será gerada automaticamente (por exemplo, incluindo o \"media type\" específico, no cabeçalho HTTP `Content-Type` como parte do OpenAPI gerado).\n\nMas você também pode declarar a `Response` que deseja utilizar (e.g. qualquer subclasse de `Response`), no *decorador de operação de rota* usando o parâmetro `response_class`.\n\nO conteúdo que você retorna da sua *função de operação de rota* será colocado dentro dessa `Response`.\n\n/// note | Nota\n\nSe você utilizar uma classe de resposta sem media type, o FastAPI esperará que sua resposta não tenha conteúdo, então ele não irá documentar o formato da resposta na documentação OpenAPI gerada.\n\n///\n\n## Respostas JSON { #json-responses }\n\nPor padrão, o FastAPI retorna respostas JSON.\n\nSe você declarar um [Modelo de Resposta](../tutorial/response-model.md), o FastAPI irá usá-lo para serializar os dados para JSON, usando Pydantic.\n\nSe você não declarar um modelo de resposta, o FastAPI usará o `jsonable_encoder` explicado em [Codificador Compatível com JSON](../tutorial/encoder.md) e o colocará em uma `JSONResponse`.\n\nSe você declarar uma `response_class` com um media type JSON (`application/json`), como no caso de `JSONResponse`, os dados que você retorna serão automaticamente convertidos (e filtrados) com qualquer `response_model` do Pydantic que você declarou no *decorador de operação de rota*. Mas os dados não serão serializados para bytes JSON com Pydantic; em vez disso, serão convertidos com o `jsonable_encoder` e então passados para a classe `JSONResponse`, que fará a serialização para bytes usando a biblioteca padrão de JSON do Python.\n\n### Performance com JSON { #json-performance }\n\nResumindo, se você quer o máximo de performance, use um [Modelo de Resposta](../tutorial/response-model.md) e não declare uma `response_class` no *decorador de operação de rota*.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## Resposta HTML { #html-response }\n\nPara retornar uma resposta com HTML diretamente do **FastAPI**, utilize `HTMLResponse`.\n\n* Importe `HTMLResponse`.\n* Passe `HTMLResponse` como o parâmetro de `response_class` do seu *decorador de operação de rota*.\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info | Informação\n\nO parâmetro `response_class` também será usado para definir o \"media type\" da resposta.\n\nNeste caso, o cabeçalho HTTP `Content-Type` será definido como `text/html`.\n\nE será documentado como tal no OpenAPI.\n\n///\n\n### Retornando uma `Response` { #return-a-response }\n\nComo visto em [Retornando uma Resposta Diretamente](response-directly.md), você também pode sobrescrever a resposta diretamente na sua *operação de rota*, ao retornar ela.\n\nO mesmo exemplo de antes, retornando uma `HTMLResponse`, poderia parecer com:\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning | Atenção\n\nUma `Response` retornada diretamente em sua *função de operação de rota* não será documentada no OpenAPI (por exemplo, o `Content-Type` não será documentado) e não será visível na documentação interativa automática.\n\n///\n\n/// info | Informação\n\nObviamente, o cabeçalho `Content-Type`, o código de status, etc, virão do objeto `Response` que você retornou.\n\n///\n\n### Documentar no OpenAPI e sobrescrever `Response` { #document-in-openapi-and-override-response }\n\nSe você deseja sobrescrever a resposta dentro de uma função, mas ao mesmo tempo documentar o \"media type\" no OpenAPI, você pode utilizar o parâmetro `response_class` E retornar um objeto `Response`.\n\nA `response_class` será usada apenas para documentar o OpenAPI da *operação de rota*, mas sua `Response` será usada como foi definida.\n\n#### Retornando uma `HTMLResponse` diretamente { #return-an-htmlresponse-directly }\n\nPor exemplo, poderia ser algo como:\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\nNeste exemplo, a função `generate_html_response()` já cria e retorna uma `Response` em vez de retornar o HTML em uma `str`.\n\nAo retornar o resultado chamando `generate_html_response()`, você já está retornando uma `Response` que irá sobrescrever o comportamento padrão do **FastAPI**.\n\nMas como você passou `HTMLResponse` em `response_class` também, o **FastAPI** saberá como documentar isso no OpenAPI e na documentação interativa como um HTML com `text/html`:\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## Respostas disponíveis { #available-responses }\n\nAqui estão algumas das respostas disponíveis.\n\nLembre-se que você pode utilizar `Response` para retornar qualquer outra coisa, ou até mesmo criar uma subclasse personalizada.\n\n/// note | Detalhes Técnicos\n\nVocê também pode utilizar `from starlette.responses import HTMLResponse`.\n\nO **FastAPI** provê a mesma `starlette.responses` como `fastapi.responses` apenas como uma facilidade para você, desenvolvedor. Mas a maioria das respostas disponíveis vêm diretamente do Starlette.\n\n///\n\n### `Response` { #response }\n\nA classe principal de respostas, todas as outras respostas herdam dela.\n\nVocê pode retorná-la diretamente.\n\nEla aceita os seguintes parâmetros:\n\n* `content` - Uma `str` ou `bytes`.\n* `status_code` - Um código de status HTTP do tipo `int`.\n* `headers` - Um `dict` de strings.\n* `media_type` - Uma `str` informando o media type. E.g. `\"text/html\"`.\n\nO FastAPI (Starlette, na verdade) irá incluir o cabeçalho Content-Length automaticamente. Ele também irá incluir o cabeçalho Content-Type, baseado no `media_type` e acrescentando uma codificação para tipos textuais.\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\nUsa algum texto ou sequência de bytes e retorna uma resposta HTML. Como você leu acima.\n\n### `PlainTextResponse` { #plaintextresponse }\n\nUsa algum texto ou sequência de bytes para retornar uma resposta de texto não formatado.\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\nPega alguns dados e retorna uma resposta com codificação `application/json`.\n\nÉ a resposta padrão utilizada no **FastAPI**, como você leu acima.\n\n/// note | Detalhes Técnicos\n\nMas se você declarar um modelo de resposta ou tipo de retorno, isso será usado diretamente para serializar os dados para JSON, e uma resposta com o media type correto para JSON será retornada diretamente, sem usar a classe `JSONResponse`.\n\nEsta é a forma ideal para obter a melhor performance.\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\nRetorna um redirecionamento HTTP. Utiliza o código de status 307 (Redirecionamento Temporário) por padrão.\n\nVocê pode retornar uma `RedirectResponse` diretamente:\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\nOu você pode utilizá-la no parâmetro `response_class`:\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\nSe você fizer isso, então você pode retornar a URL diretamente da sua *função de operação de rota*.\n\nNeste caso, o `status_code` utilizado será o padrão de `RedirectResponse`, que é `307`.\n\n---\n\nVocê também pode utilizar o parâmetro `status_code` combinado com o parâmetro `response_class`:\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\nRecebe um gerador assíncrono ou um gerador/iterador comum (uma função com `yield`) e transmite (stream) o corpo da resposta.\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | Detalhes Técnicos\n\nUma tarefa `async` só pode ser cancelada quando alcança um `await`. Se não houver `await`, o gerador (função com `yield`) não pode ser cancelado adequadamente e pode continuar executando mesmo após o cancelamento ser solicitado.\n\nComo este pequeno exemplo não precisa de nenhuma instrução `await`, adicionamos um `await anyio.sleep(0)` para dar ao event loop a chance de lidar com o cancelamento.\n\nIsso seria ainda mais importante com streams grandes ou infinitos.\n\n///\n\n/// tip | Dica\n\nEm vez de retornar uma `StreamingResponse` diretamente, você deveria provavelmente seguir o estilo em [Transmitir Dados](./stream-data.md), é muito mais conveniente e lida com cancelamento nos bastidores para você.\n\nSe você estiver transmitindo JSON Lines, siga o tutorial [Transmitir JSON Lines](../tutorial/stream-json-lines.md).\n\n///\n\n### `FileResponse` { #fileresponse }\n\nEnvia um arquivo de forma assíncrona e contínua (stream).\n\nRecebe um conjunto de argumentos do construtor diferente dos outros tipos de resposta:\n\n* `path` - O caminho do arquivo que será transmitido.\n* `headers` - Quaisquer cabeçalhos personalizados a serem incluídos, como um dicionário.\n* `media_type` - Uma string com o media type. Se não for definida, o nome do arquivo ou path será usado para inferir um media type.\n* `filename` - Se definido, será incluído no cabeçalho `Content-Disposition`.\n\nRespostas de arquivos incluirão os cabeçalhos apropriados `Content-Length`, `Last-Modified` e `ETag`.\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\nVocê também pode usar o parâmetro `response_class`:\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\nNesse caso, você pode retornar o path do arquivo diretamente da sua *função de operação de rota*.\n\n## Classe de resposta personalizada { #custom-response-class }\n\nVocê pode criar sua própria classe de resposta personalizada, herdando de `Response` e usando-a.\n\nPor exemplo, vamos supor que você queira usar [`orjson`](https://github.com/ijl/orjson) com algumas configurações.\n\nVamos supor que você queira retornar um JSON indentado e formatado, então você quer utilizar a opção `orjson.OPT_INDENT_2` do orjson.\n\nVocê poderia criar uma `CustomORJSONResponse`. A principal coisa que você tem que fazer é criar um método `Response.render(content)` que retorne o conteúdo como `bytes`:\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\nAgora em vez de retornar:\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n...essa resposta retornará:\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\nObviamente, você provavelmente vai encontrar maneiras muito melhores de se aproveitar disso do que a formatação de JSON. 😉\n\n### `orjson` ou Modelo de Resposta { #orjson-or-response-model }\n\nSe o que você procura é performance, provavelmente é melhor usar um [Modelo de Resposta](../tutorial/response-model.md) do que uma resposta com `orjson`.\n\nCom um modelo de resposta, o FastAPI usará o Pydantic para serializar os dados para JSON, sem passos intermediários, como convertê-los com `jsonable_encoder`, o que aconteceria em qualquer outro caso.\n\nE, por baixo dos panos, o Pydantic usa os mesmos mecanismos em Rust que o `orjson` para serializar para JSON, então você já terá a melhor performance com um modelo de resposta.\n\n## Classe de resposta padrão { #default-response-class }\n\nQuando você criar uma instância da classe **FastAPI** ou um `APIRouter` você pode especificar qual classe de resposta utilizar por padrão.\n\nO parâmetro que define isso é o `default_response_class`.\n\nNo exemplo abaixo, o **FastAPI** utilizará `HTMLResponse` por padrão, em todas as *operações de rota*, em vez de JSON.\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip | Dica\n\nVocê ainda pode substituir `response_class` em *operações de rota* como antes.\n\n///\n\n## Documentação adicional { #additional-documentation }\n\nVocê também pode declarar o media type e muitos outros detalhes no OpenAPI utilizando `responses`: [Respostas Adicionais no OpenAPI](additional-responses.md).\n"
  },
  {
    "path": "docs/pt/docs/advanced/dataclasses.md",
    "content": "# Usando Dataclasses { #using-dataclasses }\n\nFastAPI é construído em cima do **Pydantic**, e eu tenho mostrado como usar modelos Pydantic para declarar requisições e respostas.\n\nMas o FastAPI também suporta o uso de [`dataclasses`](https://docs.python.org/3/library/dataclasses.html) da mesma forma:\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\nIsso ainda é suportado graças ao **Pydantic**, pois ele tem [suporte interno para `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).\n\nEntão, mesmo com o código acima que não usa Pydantic explicitamente, o FastAPI está usando Pydantic para converter essas dataclasses padrão para a versão do Pydantic.\n\nE claro, ele suporta o mesmo:\n\n* validação de dados\n* serialização de dados\n* documentação de dados, etc.\n\nIsso funciona da mesma forma que com os modelos Pydantic. E na verdade é alcançado da mesma maneira por baixo dos panos, usando Pydantic.\n\n/// info | Informação\n\nLembre-se de que dataclasses não podem fazer tudo o que os modelos Pydantic podem fazer.\n\nEntão, você ainda pode precisar usar modelos Pydantic.\n\nMas se você tem um monte de dataclasses por aí, este é um truque legal para usá-las para alimentar uma API web usando FastAPI. 🤓\n\n///\n\n## Dataclasses em `response_model` { #dataclasses-in-response-model }\n\nVocê também pode usar `dataclasses` no parâmetro `response_model`:\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\nA dataclass será automaticamente convertida para uma dataclass Pydantic.\n\nDessa forma, seu esquema aparecerá na interface de documentação da API:\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## Dataclasses em Estruturas de Dados Aninhadas { #dataclasses-in-nested-data-structures }\n\nVocê também pode combinar `dataclasses` com outras anotações de tipo para criar estruturas de dados aninhadas.\n\nEm alguns casos, você ainda pode ter que usar a versão do Pydantic das `dataclasses`. Por exemplo, se você tiver erros com a documentação da API gerada automaticamente.\n\nNesse caso, você pode simplesmente trocar as `dataclasses` padrão por `pydantic.dataclasses`, que é um substituto direto:\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. Ainda importamos `field` das `dataclasses` padrão.\n\n2. `pydantic.dataclasses` é um substituto direto para `dataclasses`.\n\n3. A dataclass `Author` inclui uma lista de dataclasses `Item`.\n\n4. A dataclass `Author` é usada como o parâmetro `response_model`.\n\n5. Você pode usar outras anotações de tipo padrão com dataclasses como o corpo da requisição.\n\n    Neste caso, é uma lista de dataclasses `Item`.\n\n6. Aqui estamos retornando um dicionário que contém `items`, que é uma lista de dataclasses.\n\n    O FastAPI ainda é capaz de <dfn title=\"converter os dados para um formato que pode ser transmitido\">serializar</dfn> os dados para JSON.\n\n7. Aqui o `response_model` está usando uma anotação de tipo de uma lista de dataclasses `Author`.\n\n    Novamente, você pode combinar `dataclasses` com anotações de tipo padrão.\n\n8. Note que esta *função de operação de rota* usa `def` regular em vez de `async def`.\n\n    Como sempre, no FastAPI você pode combinar `def` e `async def` conforme necessário.\n\n    Se você precisar de uma atualização sobre quando usar qual, confira a seção _\"Com pressa?\"_ na documentação sobre [`async` e `await`](../async.md#in-a-hurry).\n\n9. Esta *função de operação de rota* não está retornando dataclasses (embora pudesse), mas uma lista de dicionários com dados internos.\n\n    O FastAPI usará o parâmetro `response_model` (que inclui dataclasses) para converter a resposta.\n\nVocê pode combinar `dataclasses` com outras anotações de tipo em muitas combinações diferentes para formar estruturas de dados complexas.\n\nConfira as dicas de anotação no código acima para ver mais detalhes específicos.\n\n## Saiba Mais { #learn-more }\n\nVocê também pode combinar `dataclasses` com outros modelos Pydantic, herdar deles, incluí-los em seus próprios modelos, etc.\n\nPara saber mais, confira a [documentação do Pydantic sobre dataclasses](https://docs.pydantic.dev/latest/concepts/dataclasses/).\n\n## Versão { #version }\n\nIsso está disponível desde a versão `0.67.0` do FastAPI. 🔖\n"
  },
  {
    "path": "docs/pt/docs/advanced/events.md",
    "content": "# Eventos de lifespan { #lifespan-events }\n\nVocê pode definir a lógica (código) que deve ser executada antes da aplicação **inicializar**. Isso significa que esse código será executado **uma vez**, **antes** de a aplicação **começar a receber requisições**.\n\nDa mesma forma, você pode definir a lógica (código) que deve ser executada quando a aplicação estiver **encerrando**. Nesse caso, esse código será executado **uma vez**, **depois** de possivelmente ter tratado **várias requisições**.\n\nComo esse código é executado antes de a aplicação **começar** a receber requisições e logo depois que ela **termina** de lidar com as requisições, ele cobre todo o **lifespan** da aplicação (a palavra \"lifespan\" será importante em um segundo 😉).\n\nIsso pode ser muito útil para configurar **recursos** que você precisa usar por toda a aplicação, e que são **compartilhados** entre as requisições e/ou que você precisa **limpar** depois. Por exemplo, um pool de conexões com o banco de dados ou o carregamento de um modelo de Aprendizado de Máquina compartilhado.\n\n## Caso de uso { #use-case }\n\nVamos começar com um exemplo de **caso de uso** e então ver como resolvê-lo com isso.\n\nVamos imaginar que você tem alguns **modelos de Aprendizado de Máquina** que deseja usar para lidar com as requisições. 🤖\n\nOs mesmos modelos são compartilhados entre as requisições, então não é um modelo por requisição, ou um por usuário, ou algo parecido.\n\nVamos imaginar que o carregamento do modelo pode **demorar bastante tempo**, porque ele precisa ler muitos **dados do disco**. Então você não quer fazer isso a cada requisição.\n\nVocê poderia carregá-lo no nível mais alto do módulo/arquivo, mas isso também significaria **carregar o modelo** mesmo se você estivesse executando um teste automatizado simples; então esse teste poderia ser **lento** porque teria que esperar o carregamento do modelo antes de conseguir executar uma parte independente do código.\n\nÉ isso que vamos resolver: vamos carregar o modelo antes de as requisições serem tratadas, mas apenas um pouco antes de a aplicação começar a receber requisições, não enquanto o código estiver sendo carregado.\n\n## Lifespan { #lifespan }\n\nVocê pode definir essa lógica de *inicialização* e *encerramento* usando o parâmetro `lifespan` da aplicação `FastAPI`, e um \"gerenciador de contexto\" (vou mostrar o que é isso em um segundo).\n\nVamos começar com um exemplo e depois ver em detalhes.\n\nNós criamos uma função assíncrona `lifespan()` com `yield` assim:\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\nAqui estamos simulando a operação de *inicialização* custosa de carregar o modelo, colocando a (falsa) função do modelo no dicionário com modelos de Aprendizado de Máquina antes do `yield`. Esse código será executado **antes** de a aplicação **começar a receber requisições**, durante a *inicialização*.\n\nE então, logo após o `yield`, descarregamos o modelo. Esse código será executado **depois** de a aplicação **terminar de lidar com as requisições**, pouco antes do *encerramento*. Isso poderia, por exemplo, liberar recursos como memória ou uma GPU.\n\n/// tip | Dica\n\nO `shutdown` aconteceria quando você estivesse **encerrando** a aplicação.\n\nTalvez você precise iniciar uma nova versão, ou apenas cansou de executá-la. 🤷\n\n///\n\n### Função lifespan { #lifespan-function }\n\nA primeira coisa a notar é que estamos definindo uma função assíncrona com `yield`. Isso é muito semelhante a Dependências com `yield`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\nA primeira parte da função, antes do `yield`, será executada **antes** de a aplicação iniciar.\n\nE a parte posterior ao `yield` será executada **depois** de a aplicação ter terminado.\n\n### Gerenciador de contexto assíncrono { #async-context-manager }\n\nSe você verificar, a função está decorada com um `@asynccontextmanager`.\n\nIsso converte a função em algo chamado \"**gerenciador de contexto assíncrono**\".\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\nUm **gerenciador de contexto** em Python é algo que você pode usar em uma declaração `with`, por exemplo, `open()` pode ser usado como um gerenciador de contexto:\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\nEm versões mais recentes do Python, há também um **gerenciador de contexto assíncrono**. Você o usaria com `async with`:\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\nQuando você cria um gerenciador de contexto ou um gerenciador de contexto assíncrono como acima, o que ele faz é: antes de entrar no bloco `with`, ele executa o código antes do `yield`, e após sair do bloco `with`, ele executa o código depois do `yield`.\n\nNo nosso exemplo de código acima, não o usamos diretamente, mas passamos para o FastAPI para que ele o use.\n\nO parâmetro `lifespan` da aplicação `FastAPI` aceita um **gerenciador de contexto assíncrono**, então podemos passar para ele nosso novo gerenciador de contexto assíncrono `lifespan`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## Eventos alternativos (descontinuados) { #alternative-events-deprecated }\n\n/// warning | Atenção\n\nA forma recomendada de lidar com a *inicialização* e o *encerramento* é usando o parâmetro `lifespan` da aplicação `FastAPI`, como descrito acima. Se você fornecer um parâmetro `lifespan`, os manipuladores de eventos `startup` e `shutdown` não serão mais chamados. É tudo `lifespan` ou tudo por eventos, não ambos.\n\nVocê provavelmente pode pular esta parte.\n\n///\n\nExiste uma forma alternativa de definir essa lógica para ser executada durante a *inicialização* e durante o *encerramento*.\n\nVocê pode definir manipuladores de eventos (funções) que precisam ser executados antes de a aplicação iniciar ou quando a aplicação estiver encerrando.\n\nEssas funções podem ser declaradas com `async def` ou `def` normal.\n\n### Evento `startup` { #startup-event }\n\nPara adicionar uma função que deve rodar antes de a aplicação iniciar, declare-a com o evento `\"startup\"`:\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\nNesse caso, a função de manipulador do evento `startup` inicializará os itens do \"banco de dados\" (apenas um `dict`) com alguns valores.\n\nVocê pode adicionar mais de uma função de manipulador de eventos.\n\nE sua aplicação não começará a receber requisições até que todos os manipuladores de eventos `startup` sejam concluídos.\n\n### Evento `shutdown` { #shutdown-event }\n\nPara adicionar uma função que deve ser executada quando a aplicação estiver encerrando, declare-a com o evento `\"shutdown\"`:\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\nAqui, a função de manipulador do evento `shutdown` escreverá uma linha de texto `\"Application shutdown\"` no arquivo `log.txt`.\n\n/// info | Informação\n\nNa função `open()`, o `mode=\"a\"` significa \"acrescentar\", então a linha será adicionada depois do que já estiver naquele arquivo, sem sobrescrever o conteúdo anterior.\n\n///\n\n/// tip | Dica\n\nPerceba que, nesse caso, estamos usando a função padrão do Python `open()` que interage com um arquivo.\n\nEntão, isso envolve I/O (input/output), que requer \"esperar\" que as coisas sejam escritas em disco.\n\nMas `open()` não usa `async` e `await`.\n\nAssim, declaramos a função de manipulador de evento com `def` padrão em vez de `async def`.\n\n///\n\n### `startup` e `shutdown` juntos { #startup-and-shutdown-together }\n\nHá uma grande chance de que a lógica para sua *inicialização* e *encerramento* esteja conectada, você pode querer iniciar alguma coisa e então finalizá-la, adquirir um recurso e então liberá-lo, etc.\n\nFazer isso em funções separadas que não compartilham lógica ou variáveis entre si é mais difícil, pois você precisaria armazenar valores em variáveis globais ou truques semelhantes.\n\nPor causa disso, agora é recomendado usar o `lifespan`, como explicado acima.\n\n## Detalhes técnicos { #technical-details }\n\nApenas um detalhe técnico para nerds curiosos. 🤓\n\nPor baixo, na especificação técnica do ASGI, isso é parte do [Protocolo Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), e define eventos chamados `startup` e `shutdown`.\n\n/// info | Informação\n\nVocê pode ler mais sobre os manipuladores de `lifespan` do Starlette na [Documentação do Lifespan do Starlette](https://www.starlette.dev/lifespan/).\n\nIncluindo como lidar com estado do lifespan que pode ser usado em outras áreas do seu código.\n\n///\n\n## Sub Aplicações { #sub-applications }\n\n🚨 Tenha em mente que esses eventos de lifespan (inicialização e encerramento) serão executados apenas para a aplicação principal, não para [Sub Aplicações - Montagem](sub-applications.md).\n"
  },
  {
    "path": "docs/pt/docs/advanced/generate-clients.md",
    "content": "# Gerando SDKs { #generating-sdks }\n\nComo o **FastAPI** é baseado na especificação **OpenAPI**, suas APIs podem ser descritas em um formato padrão que muitas ferramentas entendem.\n\nIsso facilita gerar **documentação** atualizada, bibliotecas clientes (<abbr title=\"Software Development Kits - Kits de Desenvolvimento de Software\">**SDKs**</abbr>) em várias linguagens e **testes** ou **fluxos de trabalho de automação** que permanecem em sincronia com o seu código.\n\nNeste guia, você aprenderá como gerar um **SDK em TypeScript** para o seu backend FastAPI.\n\n## Geradores de SDK de código aberto { #open-source-sdk-generators }\n\nUma opção versátil é o [OpenAPI Generator](https://openapi-generator.tech/), que suporta **muitas linguagens de programação** e pode gerar SDKs a partir da sua especificação OpenAPI.\n\nPara **clientes TypeScript**, o [Hey API](https://heyapi.dev/) é uma solução feita sob medida, oferecendo uma experiência otimizada para o ecossistema TypeScript.\n\nVocê pode descobrir mais geradores de SDK em [OpenAPI.Tools](https://openapi.tools/#sdk).\n\n/// tip | Dica\n\nO FastAPI gera automaticamente especificações **OpenAPI 3.1**, então qualquer ferramenta que você usar deve suportar essa versão.\n\n///\n\n## Geradores de SDK dos patrocinadores do FastAPI { #sdk-generators-from-fastapi-sponsors }\n\nEsta seção destaca soluções **financiadas por investimento** e **com suporte de empresas** que patrocinam o FastAPI. Esses produtos fornecem **funcionalidades adicionais** e **integrações** além de SDKs gerados com alta qualidade.\n\nAo ✨ [**patrocinar o FastAPI**](../help-fastapi.md#sponsor-the-author) ✨, essas empresas ajudam a garantir que o framework e seu **ecossistema** continuem saudáveis e **sustentáveis**.\n\nO patrocínio também demonstra um forte compromisso com a **comunidade** FastAPI (você), mostrando que elas se importam não apenas em oferecer um **ótimo serviço**, mas também em apoiar um **framework robusto e próspero**, o FastAPI. 🙇\n\nPor exemplo, você pode querer experimentar:\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\nAlgumas dessas soluções também podem ser open source ou oferecer planos gratuitos, para que você possa testá-las sem compromisso financeiro. Outros geradores comerciais de SDK estão disponíveis e podem ser encontrados online. 🤓\n\n## Crie um SDK em TypeScript { #create-a-typescript-sdk }\n\nVamos começar com uma aplicação FastAPI simples:\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\nNote que as *operações de rota* definem os modelos que usam para o corpo da requisição e o corpo da resposta, usando os modelos `Item` e `ResponseMessage`.\n\n### Documentação da API { #api-docs }\n\nSe você for para `/docs`, verá que ela tem os **schemas** para os dados a serem enviados nas requisições e recebidos nas respostas:\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\nVocê pode ver esses schemas porque eles foram declarados com os modelos no app.\n\nEssas informações estão disponíveis no **schema OpenAPI** do app e são mostradas na documentação da API.\n\nE essas mesmas informações dos modelos que estão incluídas no OpenAPI são o que pode ser usado para **gerar o código do cliente**.\n\n### Hey API { #hey-api }\n\nDepois que tivermos uma aplicação FastAPI com os modelos, podemos usar o Hey API para gerar um cliente TypeScript. A forma mais rápida é via npx.\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\nIsso gerará um SDK TypeScript em `./src/client`.\n\nVocê pode aprender como [instalar `@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started) e ler sobre o [resultado gerado](https://heyapi.dev/openapi-ts/output) no site deles.\n\n### Usando o SDK { #using-the-sdk }\n\nAgora você pode importar e usar o código do cliente. Poderia ser assim, observe que você obtém preenchimento automático para os métodos:\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\nVocê também obterá preenchimento automático para o corpo a ser enviado:\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip | Dica\n\nObserve o preenchimento automático para `name` e `price`, que foi definido na aplicação FastAPI, no modelo `Item`.\n\n///\n\nVocê terá erros em linha para os dados que você envia:\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\nO objeto de resposta também terá preenchimento automático:\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## Aplicação FastAPI com Tags { #fastapi-app-with-tags }\n\nEm muitos casos, sua aplicação FastAPI será maior, e você provavelmente usará tags para separar diferentes grupos de *operações de rota*.\n\nPor exemplo, você poderia ter uma seção para **items** e outra seção para **users**, e elas poderiam ser separadas por tags:\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### Gere um cliente TypeScript com Tags { #generate-a-typescript-client-with-tags }\n\nSe você gerar um cliente para uma aplicação FastAPI usando tags, normalmente também separará o código do cliente com base nas tags.\n\nDessa forma, você poderá ter as coisas ordenadas e agrupadas corretamente para o código do cliente:\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\nNesse caso você tem:\n\n* `ItemsService`\n* `UsersService`\n\n### Nomes dos métodos do cliente { #client-method-names }\n\nAgora os nomes dos métodos gerados como `createItemItemsPost` não parecem muito “limpos”:\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n...isso ocorre porque o gerador de clientes usa o **ID de operação** interno do OpenAPI para cada *operação de rota*.\n\nO OpenAPI exige que cada ID de operação seja único em todas as *operações de rota*, então o FastAPI usa o **nome da função**, o **path** e o **método/operação HTTP** para gerar esse ID de operação, porque dessa forma ele pode garantir que os IDs de operação sejam únicos.\n\nMas eu vou te mostrar como melhorar isso a seguir. 🤓\n\n## IDs de operação personalizados e nomes de métodos melhores { #custom-operation-ids-and-better-method-names }\n\nVocê pode **modificar** a maneira como esses IDs de operação são **gerados** para torná-los mais simples e ter **nomes de método mais simples** nos clientes.\n\nNeste caso, você terá que garantir que cada ID de operação seja **único** de alguma outra maneira.\n\nPor exemplo, você poderia garantir que cada *operação de rota* tenha uma tag, e então gerar o ID de operação com base na **tag** e no **nome** da *operação de rota* (o nome da função).\n\n### Função personalizada para gerar IDs exclusivos { #custom-generate-unique-id-function }\n\nO FastAPI usa um **ID exclusivo** para cada *operação de rota*, ele é usado para o **ID de operação** e também para os nomes de quaisquer modelos personalizados necessários, para requisições ou respostas.\n\nVocê pode personalizar essa função. Ela recebe uma `APIRoute` e retorna uma string.\n\nPor exemplo, aqui está usando a primeira tag (Você provavelmente terá apenas uma tag) e o nome da *operação de rota* (o nome da função).\n\nVocê pode então passar essa função personalizada para o **FastAPI** como o parâmetro `generate_unique_id_function`:\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### Gere um cliente TypeScript com IDs de operação personalizados { #generate-a-typescript-client-with-custom-operation-ids }\n\nAgora, se você gerar o cliente novamente, verá que ele tem os nomes dos métodos melhorados:\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\nComo você pode ver, os nomes dos métodos agora têm a tag e, em seguida, o nome da função. Agora eles não incluem informações do path da URL e da operação HTTP.\n\n### Pré-processar a especificação OpenAPI para o gerador de clientes { #preprocess-the-openapi-specification-for-the-client-generator }\n\nO código gerado ainda tem algumas **informações duplicadas**.\n\nNós já sabemos que esse método está relacionado aos **items** porque essa palavra está no `ItemsService` (retirada da tag), mas ainda temos o nome da tag prefixado no nome do método também. 😕\n\nProvavelmente ainda queremos mantê-lo para o OpenAPI em geral, pois isso garantirá que os IDs de operação sejam **únicos**.\n\nMas para o cliente gerado, poderíamos **modificar** os IDs de operação do OpenAPI logo antes de gerar os clientes, apenas para tornar esses nomes de método mais agradáveis e **limpos**.\n\nPoderíamos baixar o JSON do OpenAPI para um arquivo `openapi.json` e então poderíamos **remover essa tag prefixada** com um script como este:\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\nCom isso, os IDs de operação seriam renomeados de coisas como `items-get_items` para apenas `get_items`, dessa forma o gerador de clientes pode gerar nomes de métodos mais simples.\n\n### Gere um cliente TypeScript com o OpenAPI pré-processado { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\nComo o resultado final está agora em um arquivo `openapi.json`, você precisa atualizar o local de entrada:\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\nDepois de gerar o novo cliente, você terá agora **nomes de métodos “limpos”**, com todo o **preenchimento automático**, **erros em linha**, etc:\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## Benefícios { #benefits }\n\nAo usar os clientes gerados automaticamente, você terá **preenchimento automático** para:\n\n* Métodos.\n* Corpos de requisições, parâmetros de query, etc.\n* Corpos de respostas.\n\nVocê também terá **erros em linha** para tudo.\n\nE sempre que você atualizar o código do backend e **regenerar** o frontend, ele terá quaisquer novas *operações de rota* disponíveis como métodos, as antigas removidas, e qualquer outra alteração será refletida no código gerado. 🤓\n\nIsso também significa que, se algo mudou, será **refletido** no código do cliente automaticamente. E se você **construir** o cliente, ele falhará caso haja qualquer **incompatibilidade** nos dados usados.\n\nAssim, você **detectará muitos erros** muito cedo no ciclo de desenvolvimento, em vez de ter que esperar que os erros apareçam para seus usuários finais em produção e então tentar depurar onde está o problema. ✨\n"
  },
  {
    "path": "docs/pt/docs/advanced/index.md",
    "content": "# Guia de Usuário Avançado { #advanced-user-guide }\n\n## Recursos Adicionais { #additional-features }\n\nO [Tutorial - Guia de Usuário](../tutorial/index.md) principal deve ser o suficiente para dar a você um tour por todos os principais recursos do **FastAPI**.\n\nNas próximas seções você verá outras opções, configurações, e recursos adicionais.\n\n/// tip | Dica\n\nAs próximas seções **não são necessariamente \"avançadas\"**.\n\nE é possível que para seu caso de uso, a solução esteja em uma delas.\n\n///\n\n## Leia o Tutorial primeiro { #read-the-tutorial-first }\n\nVocê ainda pode usar a maior parte dos recursos no **FastAPI** com o conhecimento do [Tutorial - Guia de Usuário](../tutorial/index.md) principal.\n\nE as próximas seções assumem que você já leu ele, e que você conhece suas ideias principais.\n"
  },
  {
    "path": "docs/pt/docs/advanced/json-base64-bytes.md",
    "content": "# JSON com bytes em Base64 { #json-with-bytes-as-base64 }\n\nSe sua aplicação precisa receber e enviar dados JSON, mas você precisa incluir dados binários nele, você pode codificá-los em base64.\n\n## Base64 vs Arquivos { #base64-vs-files }\n\nPrimeiro, considere se você pode usar [Arquivos na request](../tutorial/request-files.md) para fazer upload de dados binários e [Response personalizada - FileResponse](./custom-response.md#fileresponse--fileresponse-) para enviar dados binários, em vez de codificá-los em JSON.\n\nJSON só pode conter strings codificadas em UTF-8, portanto não pode conter bytes puros.\n\nBase64 pode codificar dados binários em strings, mas, para isso, precisa usar mais caracteres do que os dados binários originais; assim, normalmente é menos eficiente do que arquivos comuns.\n\nUse base64 apenas se realmente precisar incluir dados binários em JSON e não puder usar arquivos para isso.\n\n## Pydantic `bytes` { #pydantic-bytes }\n\nVocê pode declarar um modelo Pydantic com campos `bytes` e então usar `val_json_bytes` na configuração do modelo para indicar que deve usar base64 para *validar* os dados JSON de entrada; como parte dessa validação, ele decodificará a string base64 em bytes.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\nSe você verificar a `/docs`, verá que o campo `data` espera bytes codificados em base64:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\nVocê poderia enviar uma request assim:\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip | Dica\n\n`aGVsbG8=` é a codificação base64 de `hello`.\n\n///\n\nEm seguida, o Pydantic decodificará a string base64 e fornecerá os bytes originais no campo `data` do modelo.\n\nVocê receberá uma response assim:\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## Pydantic `bytes` para dados de saída { #pydantic-bytes-for-output-data }\n\nVocê também pode usar campos `bytes` com `ser_json_bytes` na configuração do modelo para dados de saída, e o Pydantic irá *serializar* os bytes como base64 ao gerar a response JSON.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## Pydantic `bytes` para dados de entrada e saída { #pydantic-bytes-for-input-and-output-data }\n\nE, claro, você pode usar o mesmo modelo configurado para usar base64 para lidar tanto com a entrada (*validar*) com `val_json_bytes` quanto com a saída (*serializar*) com `ser_json_bytes` ao receber e enviar dados JSON.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/pt/docs/advanced/middleware.md",
    "content": "# Middleware Avançado { #advanced-middleware }\n\nNo tutorial principal você leu como adicionar [Middleware Personalizado](../tutorial/middleware.md) à sua aplicação.\n\nE então você também leu como lidar com [CORS com o `CORSMiddleware`](../tutorial/cors.md).\n\nNesta seção, veremos como usar outros middlewares.\n\n## Adicionando middlewares ASGI { #adding-asgi-middlewares }\n\nComo o **FastAPI** é baseado no Starlette e implementa a especificação <abbr title=\"Asynchronous Server Gateway Interface – Interface de Gateway de Servidor Assíncrona\">ASGI</abbr>, você pode usar qualquer middleware ASGI.\n\nO middleware não precisa ser feito para o FastAPI ou Starlette para funcionar, desde que siga a especificação ASGI.\n\nNo geral, os middlewares ASGI são classes que esperam receber um aplicativo ASGI como o primeiro argumento.\n\nEntão, na documentação de middlewares ASGI de terceiros, eles provavelmente dirão para você fazer algo como:\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\nMas, o FastAPI (na verdade, o Starlette) fornece uma maneira mais simples de fazer isso que garante que os middlewares internos lidem com erros do servidor e que os manipuladores de exceções personalizados funcionem corretamente.\n\nPara isso, você usa `app.add_middleware()` (como no exemplo para CORS).\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` recebe uma classe de middleware como o primeiro argumento e quaisquer argumentos adicionais a serem passados para o middleware.\n\n## Middlewares Integrados { #integrated-middlewares }\n\n**FastAPI** inclui vários middlewares para casos de uso comuns, veremos a seguir como usá-los.\n\n/// note | Detalhes Técnicos\n\nPara os próximos exemplos, você também poderia usar `from starlette.middleware.something import SomethingMiddleware`.\n\n**FastAPI** fornece vários middlewares em `fastapi.middleware` apenas como uma conveniência para você, o desenvolvedor. Mas a maioria dos middlewares disponíveis vem diretamente do Starlette.\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\nGarante que todas as requisições devem ser `https` ou `wss`.\n\nQualquer requisição para `http` ou `ws` será redirecionada para o esquema seguro.\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\nGarante que todas as requisições recebidas tenham um cabeçalho `Host` corretamente configurado, a fim de proteger contra ataques de cabeçalho de host HTTP.\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\nOs seguintes argumentos são suportados:\n\n* `allowed_hosts` - Uma lista de nomes de domínio que são permitidos como nomes de host. Domínios com curingas, como `*.example.com`, são suportados para corresponder a subdomínios. Para permitir qualquer nome de host, use `allowed_hosts=[\"*\"]` ou omita o middleware.\n* `www_redirect` - Se definido como True, as requisições para versões sem www dos hosts permitidos serão redirecionadas para suas versões com www. O padrão é `True`.\n\nSe uma requisição recebida não for validada corretamente, uma resposta `400` será enviada.\n\n## `GZipMiddleware` { #gzipmiddleware }\n\nGerencia respostas GZip para qualquer requisição que inclua `\"gzip\"` no cabeçalho `Accept-Encoding`.\n\nO middleware lidará com respostas padrão e de streaming.\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\nOs seguintes argumentos são suportados:\n\n* `minimum_size` - Não comprima respostas menores que este tamanho mínimo em bytes. O padrão é `500`.\n* `compresslevel` - Usado durante a compressão GZip. É um inteiro variando de 1 a 9. O padrão é `9`. Um valor menor resulta em uma compressão mais rápida, mas em arquivos maiores, enquanto um valor maior resulta em uma compressão mais lenta, mas em arquivos menores.\n\n## Outros middlewares { #other-middlewares }\n\nHá muitos outros middlewares ASGI.\n\nPor exemplo:\n\n* [`ProxyHeadersMiddleware` do Uvicorn](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n* [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\nPara checar outros middlewares disponíveis, confira [Documentação de Middlewares do Starlette](https://www.starlette.dev/middleware/) e a [Lista Incrível do ASGI](https://github.com/florimondmanca/awesome-asgi).\n"
  },
  {
    "path": "docs/pt/docs/advanced/openapi-callbacks.md",
    "content": "# Callbacks na OpenAPI { #openapi-callbacks }\n\nVocê poderia criar uma API com uma *operação de rota* que poderia acionar um request a uma *API externa* criada por outra pessoa (provavelmente o mesmo desenvolvedor que estaria *usando* sua API).\n\nO processo que acontece quando sua aplicação de API chama a *API externa* é chamado de \"callback\". Porque o software que o desenvolvedor externo escreveu envia um request para sua API e então sua API *chama de volta*, enviando um request para uma *API externa* (que provavelmente foi criada pelo mesmo desenvolvedor).\n\nNesse caso, você poderia querer documentar como essa API externa *deveria* ser. Que *operação de rota* ela deveria ter, que corpo ela deveria esperar, que resposta ela deveria retornar, etc.\n\n## Um aplicativo com callbacks { #an-app-with-callbacks }\n\nVamos ver tudo isso com um exemplo.\n\nImagine que você desenvolve um aplicativo que permite criar faturas.\n\nEssas faturas terão um `id`, `title` (opcional), `customer` e `total`.\n\nO usuário da sua API (um desenvolvedor externo) criará uma fatura na sua API com um request POST.\n\nEntão sua API irá (vamos imaginar):\n\n* Enviar a fatura para algum cliente do desenvolvedor externo.\n* Coletar o dinheiro.\n* Enviar a notificação de volta para o usuário da API (o desenvolvedor externo).\n    * Isso será feito enviando um request POST (de *sua API*) para alguma *API externa* fornecida por esse desenvolvedor externo (este é o \"callback\").\n\n## O aplicativo **FastAPI** normal { #the-normal-fastapi-app }\n\nVamos primeiro ver como o aplicativo da API normal se pareceria antes de adicionar o callback.\n\nEle terá uma *operação de rota* que receberá um corpo `Invoice`, e um parâmetro de consulta `callback_url` que conterá a URL para o callback.\n\nEssa parte é bastante normal, a maior parte do código provavelmente já é familiar para você:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip | Dica\n\nO parâmetro de consulta `callback_url` usa um tipo Pydantic [Url](https://docs.pydantic.dev/latest/api/networks/).\n\n///\n\nA única novidade é o `callbacks=invoices_callback_router.routes` como argumento do decorador da *operação de rota*. Veremos o que é isso a seguir.\n\n## Documentando o callback { #documenting-the-callback }\n\nO código real do callback dependerá muito da sua própria aplicação de API.\n\nE provavelmente variará muito de um aplicativo para o outro.\n\nPoderia ser apenas uma ou duas linhas de código, como:\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\nMas possivelmente a parte mais importante do callback é garantir que o usuário da sua API (o desenvolvedor externo) implemente a *API externa* corretamente, de acordo com os dados que *sua API* vai enviar no corpo do request do callback, etc.\n\nEntão, o que faremos a seguir é adicionar o código para documentar como essa *API externa* deve ser para receber o callback de *sua API*.\n\nA documentação aparecerá na Swagger UI em `/docs` na sua API, e permitirá que os desenvolvedores externos saibam como construir a *API externa*.\n\nEsse exemplo não implementa o callback em si (que poderia ser apenas uma linha de código), apenas a parte da documentação.\n\n/// tip | Dica\n\nO callback real é apenas um request HTTP.\n\nAo implementar o callback por conta própria, você pode usar algo como [HTTPX](https://www.python-httpx.org) ou [Requests](https://requests.readthedocs.io/).\n\n///\n\n## Escreva o código de documentação do callback { #write-the-callback-documentation-code }\n\nEsse código não será executado em seu aplicativo, nós só precisamos dele para *documentar* como essa *API externa* deveria ser.\n\nMas, você já sabe como criar facilmente documentação automática para uma API com o **FastAPI**.\n\nEntão vamos usar esse mesmo conhecimento para documentar como a *API externa* deveria ser... criando as *operações de rota* que a *API externa* deveria implementar (as que sua API irá chamar).\n\n/// tip | Dica\n\nAo escrever o código para documentar um callback, pode ser útil imaginar que você é aquele *desenvolvedor externo*. E que você está atualmente implementando a *API externa*, não *sua API*.\n\nAdotar temporariamente esse ponto de vista (do *desenvolvedor externo*) pode ajudar a perceber mais facilmente onde colocar os parâmetros, o modelo Pydantic para o corpo, para a resposta, etc. para essa *API externa*.\n\n///\n\n### Crie um `APIRouter` de callback { #create-a-callback-apirouter }\n\nPrimeiro crie um novo `APIRouter` que conterá um ou mais callbacks.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### Crie a *operação de rota* do callback { #create-the-callback-path-operation }\n\nPara criar a *operação de rota* do callback, use o mesmo `APIRouter` que você criou acima.\n\nEla deve parecer exatamente como uma *operação de rota* normal do FastAPI:\n\n* Ela provavelmente deveria ter uma declaração do corpo que deveria receber, por exemplo, `body: InvoiceEvent`.\n* E também poderia ter uma declaração da resposta que deveria retornar, por exemplo, `response_model=InvoiceEventReceived`.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\nHá 2 diferenças principais de uma *operação de rota* normal:\n\n* Ela não necessita ter nenhum código real, porque seu aplicativo nunca chamará esse código. Ele é usado apenas para documentar a *API externa*. Então, a função poderia ter apenas `pass`.\n* O *path* pode conter uma [expressão OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (veja mais abaixo) em que pode usar variáveis com parâmetros e partes do request original enviado para *sua API*.\n\n### A expressão do path do callback { #the-callback-path-expression }\n\nO *path* do callback pode ter uma [expressão OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) que pode conter partes do request original enviado para *sua API*.\n\nNesse caso, é a `str`:\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\nEntão, se o usuário da sua API (o desenvolvedor externo) enviar um request para *sua API* para:\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\ncom um corpo JSON de:\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\nentão *sua API* processará a fatura e, em algum momento posterior, enviará um request de callback para o `callback_url` (a *API externa*):\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\ncom um corpo JSON contendo algo como:\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\ne esperaria uma resposta daquela *API externa* com um corpo JSON como:\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip | Dica\n\nPerceba como a URL de callback usada contém a URL recebida como um parâmetro de consulta em `callback_url` (`https://www.external.org/events`) e também o `id` da fatura de dentro do corpo JSON (`2expen51ve`).\n\n///\n\n### Adicione o roteador de callback { #add-the-callback-router }\n\nNesse ponto você tem a(s) *operação(ões) de rota de callback* necessária(s) (a(s) que o *desenvolvedor externo* deveria implementar na *API externa*) no roteador de callback que você criou acima.\n\nAgora use o parâmetro `callbacks` no decorador da *operação de rota da sua API* para passar o atributo `.routes` (que é na verdade apenas uma `list` de rotas/*operações de path*) do roteador de callback:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip | Dica\n\nPerceba que você não está passando o roteador em si (`invoices_callback_router`) para `callback=`, mas o atributo `.routes`, como em `invoices_callback_router.routes`.\n\n///\n\n### Verifique a documentação { #check-the-docs }\n\nAgora você pode iniciar seu aplicativo e ir para [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVocê verá sua documentação incluindo uma seção \"Callbacks\" para sua *operação de rota* que mostra como a *API externa* deveria ser:\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/pt/docs/advanced/openapi-webhooks.md",
    "content": "# Webhooks OpenAPI { #openapi-webhooks }\n\nExistem situações onde você deseja informar os **usuários** da sua API que a sua aplicação pode chamar a aplicação *deles* (enviando uma requisição) com alguns dados, normalmente para **notificar** algum tipo de **evento**.\n\nIsso significa que no lugar do processo normal de seus usuários enviarem requisições para a sua API, é a **sua API** (ou sua aplicação) que poderia **enviar requisições para o sistema deles** (para a API deles, a aplicação deles).\n\nIsso normalmente é chamado de **webhook**.\n\n## Etapas dos webhooks { #webhooks-steps }\n\nNormalmente, o processo é que **você define** em seu código qual é a mensagem que você irá mandar, o **corpo da sua requisição**.\n\nVocê também define de alguma maneira em quais **momentos** a sua aplicação mandará essas requisições ou eventos.\n\nE os **seus usuários** definem de alguma forma (em algum painel por exemplo) a **URL** que a sua aplicação deve enviar essas requisições.\n\nToda a **lógica** sobre como cadastrar as URLs para os webhooks e o código para enviar de fato as requisições cabe a você definir. Você escreve da maneira que você desejar no **seu próprio código**.\n\n## Documentando webhooks com o **FastAPI** e OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }\n\nCom o **FastAPI**, utilizando o OpenAPI, você pode definir os nomes destes webhooks, os tipos das operações HTTP que a sua aplicação pode enviar (e.g. `POST`, `PUT`, etc.) e os **corpos** da requisição que a sua aplicação enviaria.\n\nIsto pode facilitar bastante para os seus usuários **implementarem as APIs deles** para receber as requisições dos seus **webhooks**, eles podem inclusive ser capazes de gerar parte do código da API deles.\n\n/// info | Informação\n\nWebhooks estão disponíveis a partir do OpenAPI 3.1.0, e possui suporte do FastAPI a partir da versão `0.99.0`.\n\n///\n\n## Uma aplicação com webhooks { #an-app-with-webhooks }\n\nQuando você cria uma aplicação com o **FastAPI**, existe um atributo chamado `webhooks`, que você utilizar para defini-los da mesma maneira que você definiria as suas **operações de rotas**, utilizando por exemplo `@app.webhooks.post()`.\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\nOs webhooks que você define aparecerão no esquema do **OpenAPI** e na **página de documentação** gerada automaticamente.\n\n/// info | Informação\n\nO objeto `app.webhooks` é na verdade apenas um `APIRouter`, o mesmo tipo que você utilizaria ao estruturar a sua aplicação com diversos arquivos.\n\n///\n\nNote que utilizando webhooks você não está de fato declarando um *path* (como `/items/`), o texto que informa é apenas um **identificador** do webhook (o nome do evento), por exemplo em `@app.webhooks.post(\"new-subscription\")`, o nome do webhook é `new-subscription`.\n\nIsto porque espera-se que os **seus usuários** definam o verdadeiro **URL path** onde eles desejam receber a requisição do webhook de algum outra maneira. (e.g. um painel).\n\n### Confira a documentação { #check-the-docs }\n\nAgora você pode iniciar a sua aplicação e ir até [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVocê verá que a sua documentação possui as *operações de rota* normais e agora também possui alguns **webhooks**:\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/pt/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# Configuração Avançada da Operação de Rota { #path-operation-advanced-configuration }\n\n## operationId do OpenAPI { #openapi-operationid }\n\n/// warning | Atenção\n\nSe você não é um \"especialista\" no OpenAPI, você provavelmente não precisa disso.\n\n///\n\nVocê pode definir o `operationId` do OpenAPI que será utilizado na sua *operação de rota* com o parâmetro `operation_id`.\n\nVocê deveria ter certeza que ele é único para cada operação.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### Utilizando o nome da *função de operação de rota* como o operationId { #using-the-path-operation-function-name-as-the-operationid }\n\nSe você quiser utilizar o nome das funções da sua API como `operationId`s, você pode iterar sobre todos esses nomes e sobrescrever o `operation_id` em  cada *operação de rota* utilizando o `APIRoute.name` dela.\n\nVocê deveria fazer isso depois de adicionar todas as suas *operações de rota*.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip | Dica\n\nSe você chamar `app.openapi()` manualmente, você deveria atualizar os `operationId`s antes dessa chamada.\n\n///\n\n/// warning | Atenção\n\nSe você fizer isso, você tem que ter certeza de que cada uma das suas *funções de operação de rota* tem um nome único.\n\nMesmo que elas estejam em módulos (arquivos Python) diferentes.\n\n///\n\n## Excluir do OpenAPI { #exclude-from-openapi }\n\nPara excluir uma *operação de rota* do esquema OpenAPI gerado (e por consequência, dos sistemas de documentação automáticos), utilize o parâmetro `include_in_schema` e defina ele como `False`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## Descrição avançada a partir de docstring { #advanced-description-from-docstring }\n\nVocê pode limitar as linhas utilizadas a partir da docstring de uma *função de operação de rota* para o OpenAPI.\n\nAdicionar um `\\f` (um caractere de escape para \"form feed\") faz com que o **FastAPI** trunque a saída usada para o OpenAPI até esse ponto.\n\nEle não será mostrado na documentação, mas outras ferramentas (como o Sphinx) serão capazes de utilizar o resto.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## Respostas Adicionais { #additional-responses }\n\nVocê provavelmente já viu como declarar o `response_model` e `status_code` para uma *operação de rota*.\n\nIsso define os metadados sobre a resposta principal da *operação de rota*.\n\nVocê também pode declarar respostas adicionais, com seus modelos, códigos de status, etc.\n\nExiste um capítulo inteiro da nossa documentação sobre isso, você pode ler em [Respostas Adicionais no OpenAPI](additional-responses.md).\n\n## Extras do OpenAPI { #openapi-extra }\n\nQuando você declara uma *operação de rota* na sua aplicação, o **FastAPI** irá gerar os metadados relevantes da *operação de rota* automaticamente para serem incluídos no esquema do OpenAPI.\n\n/// note | Detalhes Técnicos\n\nNa especificação do OpenAPI, isso é chamado de um [Objeto de Operação](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object).\n\n///\n\nEle possui toda a informação sobre a *operação de rota* e é usado para gerar a documentação automaticamente.\n\nEle inclui os atributos `tags`, `parameters`, `requestBody`, `responses`, etc.\n\nEsse esquema específico para uma *operação de rota* normalmente é gerado automaticamente pelo **FastAPI**, mas você também pode estender ele.\n\n/// tip | Dica\n\nEsse é um ponto de extensão de baixo nível.\n\nCaso você só precise declarar respostas adicionais, uma forma conveniente de fazer isso é com [Respostas Adicionais no OpenAPI](additional-responses.md).\n\n///\n\nVocê pode estender o esquema do OpenAPI para uma *operação de rota* utilizando o parâmetro `openapi_extra`.\n\n### Extensões do OpenAPI { #openapi-extensions }\n\nEsse parâmetro `openapi_extra` pode ser útil, por exemplo, para declarar [Extensões do OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\nSe você abrir os documentos criados automaticamente para a API, sua extensão aparecerá no final da *operação de rota* específica.\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\nE se você olhar o esquema OpenAPI resultante (na rota `/openapi.json` da sua API), você verá que a sua extensão também faz parte da *operação de rota* específica:\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### Esquema de *operação de rota* do OpenAPI personalizado { #custom-openapi-path-operation-schema }\n\nO dicionário em `openapi_extra` vai ser mesclado profundamente com o esquema OpenAPI gerado automaticamente para a *operação de rota*.\n\nEntão, você pode adicionar dados extras ao esquema gerado automaticamente.\n\nPor exemplo, você poderia decidir ler e validar a requisição com seu próprio código, sem usar as funcionalidades automáticas do FastAPI com o Pydantic, mas ainda assim querer definir a requisição no esquema OpenAPI.\n\nVocê pode fazer isso com `openapi_extra`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\nNesse exemplo, nós não declaramos nenhum modelo do Pydantic. Na verdade, o corpo da requisição não está nem mesmo <dfn title=\"convertido de algum formato simples, como bytes, em objetos Python\">analisado</dfn> como JSON, ele é lido diretamente como `bytes`, e a função `magic_data_reader()` seria a responsável por analisá-lo de alguma forma.\n\nDe toda forma, nós podemos declarar o esquema esperado para o corpo da requisição.\n\n### Tipo de conteúdo do OpenAPI personalizado { #custom-openapi-content-type }\n\nUtilizando esse mesmo truque, você pode usar um modelo Pydantic para definir o JSON Schema que é então incluído na seção do esquema personalizado do OpenAPI na *operação de rota*.\n\nE você pode fazer isso até mesmo quando o tipo de dados na requisição não é JSON.\n\nPor exemplo, nesta aplicação nós não usamos a funcionalidade integrada ao FastAPI de extrair o JSON Schema dos modelos Pydantic nem a validação automática para JSON. Na verdade, estamos declarando o tipo de conteúdo da requisição como YAML, em vez de JSON:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\nEntretanto, mesmo que não utilizemos a funcionalidade integrada por padrão, ainda estamos usando um modelo Pydantic para gerar um JSON Schema manualmente para os dados que queremos receber em YAML.\n\nEntão utilizamos a requisição diretamente e extraímos o corpo como `bytes`. Isso significa que o FastAPI não vai sequer tentar analisar o payload da requisição como JSON.\n\nE então no nosso código, nós analisamos o conteúdo YAML diretamente e, em seguida, estamos usando novamente o mesmo modelo Pydantic para validar o conteúdo YAML:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip | Dica\n\nAqui reutilizamos o mesmo modelo do Pydantic.\n\nMas da mesma forma, nós poderíamos ter validado de alguma outra forma.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/advanced/response-change-status-code.md",
    "content": "# Retorno - Altere o Código de Status { #response-change-status-code }\n\nVocê provavelmente leu anteriormente que você pode definir um [Código de Status do Retorno](../tutorial/response-status-code.md) padrão.\n\nPorém em alguns casos você precisa retornar um código de status diferente do padrão.\n\n## Caso de uso { #use-case }\n\nPor exemplo, imagine que você deseja retornar um código de status HTTP de \"OK\" `200` por padrão.\n\nMas se o dado não existir, você quer criá-lo e retornar um código de status HTTP de \"CREATED\" `201`.\n\nMas você ainda quer ser capaz de filtrar e converter o dado que você retornará com um `response_model`.\n\nPara estes casos, você pode utilizar um parâmetro `Response`.\n\n## Use um parâmetro `Response` { #use-a-response-parameter }\n\nVocê pode declarar um parâmetro do tipo `Response` em sua *função de operação de rota* (assim como você pode fazer para cookies e headers).\n\nE então você pode definir o `status_code` neste objeto de retorno *temporal*.\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\nE então você pode retornar qualquer objeto que você precise, como você faria normalmente (um `dict`, um modelo de banco de dados, etc.).\n\nE se você declarar um `response_model`, ele ainda será utilizado para filtrar e converter o objeto que você retornou.\n\nO **FastAPI** utilizará este retorno *temporal* para extrair o código de status (e também cookies e headers), e irá colocá-los no retorno final que contém o valor que você retornou, filtrado por qualquer `response_model`.\n\nVocê também pode declarar o parâmetro `Response` nas dependências, e definir o código de status nelas. Mas lembre-se que o último que for definido é o que prevalecerá.\n"
  },
  {
    "path": "docs/pt/docs/advanced/response-cookies.md",
    "content": "# Cookies de Resposta { #response-cookies }\n\n## Use um parâmetro `Response` { #use-a-response-parameter }\n\nVocê pode declarar um parâmetro do tipo `Response` na sua *função de operação de rota*.\n\nE então você pode definir cookies nesse objeto de resposta *temporário*.\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\nEm seguida, você pode retornar qualquer objeto que precise, como normalmente faria (um `dict`, um modelo de banco de dados, etc).\n\nE se você declarou um `response_model`, ele ainda será usado para filtrar e converter o objeto que você retornou.\n\n**FastAPI** usará essa resposta *temporária* para extrair os cookies (também os cabeçalhos e código de status) e os colocará na resposta final que contém o valor que você retornou, filtrado por qualquer `response_model`.\n\nVocê também pode declarar o parâmetro `Response` em dependências e definir cookies (e cabeçalhos) nelas.\n\n## Retorne uma `Response` diretamente { #return-a-response-directly }\n\nVocê também pode criar cookies ao retornar uma `Response` diretamente no seu código.\n\nPara fazer isso, você pode criar uma resposta como descrito em [Retorne uma Resposta Diretamente](response-directly.md).\n\nEntão, defina os cookies nela e a retorne:\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip | Dica\n\nLembre-se de que se você retornar uma resposta diretamente em vez de usar o parâmetro `Response`, FastAPI a retornará diretamente.\n\nPortanto, você terá que garantir que seus dados sejam do tipo correto. E.g. será compatível com JSON se você estiver retornando um `JSONResponse`.\n\nE também que você não esteja enviando nenhum dado que deveria ter sido filtrado por um `response_model`.\n\n///\n\n### Mais informações { #more-info }\n\n/// note | Detalhes Técnicos\n\nVocê também poderia usar `from starlette.responses import Response` ou `from starlette.responses import JSONResponse`.\n\n**FastAPI** fornece as mesmas `starlette.responses` em `fastapi.responses` apenas como uma conveniência para você, o desenvolvedor. Mas a maioria das respostas disponíveis vem diretamente do Starlette.\n\nE como o `Response` pode ser usado frequentemente para definir cabeçalhos e cookies, o **FastAPI** também o fornece em `fastapi.Response`.\n\n///\n\nPara ver todos os parâmetros e opções disponíveis, verifique a [documentação no Starlette](https://www.starlette.dev/responses/#set-cookie).\n"
  },
  {
    "path": "docs/pt/docs/advanced/response-directly.md",
    "content": "# Retornando uma Resposta Diretamente { #return-a-response-directly }\n\nQuando você cria uma *operação de rota* no **FastAPI**, normalmente você pode retornar qualquer dado: um `dict`, uma `list`, um modelo do Pydantic, um modelo do banco de dados, etc.\n\nSe você declarar um [Modelo de resposta](../tutorial/response-model.md), o FastAPI irá usá-lo para serializar os dados para JSON, usando o Pydantic.\n\nSe você não declarar um modelo de resposta, o FastAPI usará o `jsonable_encoder` explicado em [Codificador Compatível com JSON](../tutorial/encoder.md) e o colocará em uma `JSONResponse`.\n\nVocê também pode criar uma `JSONResponse` diretamente e retorná-la.\n\n/// tip | Dica\n\nNormalmente você terá um desempenho muito melhor usando um [Modelo de resposta](../tutorial/response-model.md) do que retornando uma `JSONResponse` diretamente, pois assim ele serializa os dados usando o Pydantic, em Rust.\n\n///\n\n## Retornando uma `Response` { #return-a-response }\n\nVocê pode retornar uma `Response` ou qualquer subclasse dela.\n\n/// info | Informação\n\nA própria `JSONResponse` é uma subclasse de `Response`.\n\n///\n\nE quando você retorna uma `Response`, o **FastAPI** vai repassá-la diretamente.\n\nEle não fará conversões de dados com modelos do Pydantic, não converterá o conteúdo para nenhum tipo, etc.\n\nIsso te dá bastante flexibilidade. Você pode retornar qualquer tipo de dado, sobrescrever qualquer declaração e validação nos dados, etc.\n\nIsso também te dá muita responsabilidade. Você precisa garantir que os dados retornados estão corretos, no formato correto, que podem ser serializados, etc.\n\n## Utilizando o `jsonable_encoder` em uma `Response` { #using-the-jsonable-encoder-in-a-response }\n\nComo o **FastAPI** não realiza nenhuma mudança na `Response` que você retorna, você precisa garantir que o conteúdo dela está pronto para uso.\n\nPor exemplo, você não pode colocar um modelo do Pydantic em uma `JSONResponse` sem antes convertê-lo em um `dict` com todos os tipos de dados (como `datetime`, `UUID`, etc) convertidos para tipos compatíveis com JSON.\n\nPara esses casos, você pode usar o `jsonable_encoder` para converter seus dados antes de repassá-los para a resposta:\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | Detalhes Técnicos\n\nVocê também pode utilizar `from starlette.responses import JSONResponse`.\n\n**FastAPI** utiliza a mesma `starlette.responses` como `fastapi.responses` apenas como uma conveniência para você, desenvolvedor. Mas maior parte das respostas disponíveis vem diretamente do Starlette.\n\n///\n\n## Retornando uma `Response` personalizada { #returning-a-custom-response }\n\nO exemplo acima mostra todas as partes que você precisa, mas ainda não é muito útil, já que você poderia ter retornado o `item` diretamente, e o **FastAPI** colocaria em uma `JSONResponse` para você, convertendo em um `dict`, etc. Tudo isso por padrão.\n\nAgora, vamos ver como você pode usar isso para retornar uma resposta personalizada.\n\nVamos dizer que você quer retornar uma resposta [XML](https://en.wikipedia.org/wiki/XML).\n\nVocê pode colocar o seu conteúdo XML em uma string, colocar em uma `Response`, e retorná-lo:\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## Como funciona um Modelo de resposta { #how-a-response-model-works }\n\nQuando você declara um [Modelo de resposta - Tipo de retorno](../tutorial/response-model.md) em uma operação de rota, o **FastAPI** irá usá-lo para serializar os dados para JSON, usando o Pydantic.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nComo isso acontece no lado do Rust, o desempenho será muito melhor do que se fosse feito com Python comum e a classe `JSONResponse`.\n\nAo usar um `response_model` ou tipo de retorno, o FastAPI não usará o `jsonable_encoder` para converter os dados (o que seria mais lento) nem a classe `JSONResponse`.\n\nEm vez disso, ele pega os bytes JSON gerados com o Pydantic usando o modelo de resposta (ou tipo de retorno) e retorna uma `Response` com o media type correto para JSON diretamente (`application/json`).\n\n## Notas { #notes }\n\nQuando você retorna uma `Response` diretamente os dados não são validados, convertidos (serializados) ou documentados automaticamente.\n\nMas você ainda pode documentar como descrito em [Respostas adicionais no OpenAPI](additional-responses.md).\n\nVocê pode ver nas próximas seções como usar/declarar essas `Responses` customizadas enquanto mantém a conversão e documentação automática dos dados.\n"
  },
  {
    "path": "docs/pt/docs/advanced/response-headers.md",
    "content": "# Cabeçalhos de resposta { #response-headers }\n\n## Use um parâmetro `Response` { #use-a-response-parameter }\n\nVocê pode declarar um parâmetro do tipo `Response` na sua *função de operação de rota* (assim como você pode fazer para cookies).\n\nEntão você pode definir os cabeçalhos nesse objeto de resposta *temporário*.\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\nEm seguida você pode retornar qualquer objeto que precisar, da maneira que faria normalmente (um `dict`, um modelo de banco de dados, etc.).\n\nSe você declarou um `response_model`, ele ainda será utilizado para filtrar e converter o objeto que você retornou.\n\n**FastAPI** usará essa resposta *temporária* para extrair os cabeçalhos (cookies e código de status também) e os colocará na resposta final que contém o valor que você retornou, filtrado por qualquer `response_model`.\n\nVocê também pode declarar o parâmetro `Response` em dependências e definir cabeçalhos (e cookies) nelas.\n\n## Retorne uma `Response` diretamente { #return-a-response-directly }\n\nVocê também pode adicionar cabeçalhos quando retornar uma `Response` diretamente.\n\nCrie uma resposta conforme descrito em [Retornar uma resposta diretamente](response-directly.md) e passe os cabeçalhos como um parâmetro adicional:\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | Detalhes Técnicos\n\nVocê também pode usar `from starlette.responses import Response` ou `from starlette.responses import JSONResponse`.\n\n**FastAPI** fornece as mesmas `starlette.responses` como `fastapi.responses` apenas como uma conveniência para você, desenvolvedor. Mas a maioria das respostas disponíveis vem diretamente do Starlette.\n\nE como a `Response` pode ser usada frequentemente para definir cabeçalhos e cookies, **FastAPI** também a fornece em `fastapi.Response`.\n\n///\n\n## Cabeçalhos personalizados { #custom-headers }\n\nTenha em mente que cabeçalhos personalizados proprietários podem ser adicionados [usando o prefixo `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nPorém, se você tiver cabeçalhos personalizados que deseja que um cliente no navegador possa ver, você precisa adicioná-los às suas configurações de CORS (saiba mais em [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), usando o parâmetro `expose_headers` descrito na [documentação de CORS do Starlette](https://www.starlette.dev/middleware/#corsmiddleware).\n"
  },
  {
    "path": "docs/pt/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP Basic Auth { #http-basic-auth }\n\nPara os casos mais simples, você pode utilizar o HTTP Basic Auth.\n\nNo HTTP Basic Auth, a aplicação espera um cabeçalho que contém um usuário e uma senha.\n\nCaso ela não receba, ela retorna um erro HTTP 401 \"Unauthorized\".\n\nE retorna um cabeçalho `WWW-Authenticate` com o valor `Basic`, e um parâmetro opcional `realm`.\n\nIsso sinaliza ao navegador para mostrar o prompt integrado para um usuário e senha.\n\nEntão, quando você digitar o usuário e senha, o navegador os envia automaticamente no cabeçalho.\n\n## HTTP Basic Auth Simples { #simple-http-basic-auth }\n\n* Importe `HTTPBasic` e `HTTPBasicCredentials`.\n* Crie um \"esquema `security`\" utilizando `HTTPBasic`.\n* Utilize o `security` com uma dependência em sua *operação de rota*.\n* Isso retorna um objeto do tipo `HTTPBasicCredentials`:\n    * Isto contém o `username` e o `password` enviado.\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\nQuando você tentar abrir a URL pela primeira vez (ou clicar no botão \"Executar\" na documentação) o navegador vai pedir pelo seu usuário e senha:\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## Verifique o usuário { #check-the-username }\n\nAqui está um exemplo mais completo.\n\nUtilize uma dependência para verificar se o usuário e a senha estão corretos.\n\nPara isso, utilize o módulo padrão do Python [`secrets`](https://docs.python.org/3/library/secrets.html) para verificar o usuário e senha.\n\nO `secrets.compare_digest()` necessita receber `bytes` ou `str` que possuem apenas caracteres ASCII (os em inglês). Isso significa que não funcionaria com caracteres como o `á`, como em `Sebastián`.\n\nPara lidar com isso, primeiramente nós convertemos o `username` e o `password` para `bytes`, codificando-os com UTF-8.\n\nEntão nós podemos utilizar o `secrets.compare_digest()` para garantir que o `credentials.username` é `\"stanleyjobson\"`, e que o `credentials.password` é `\"swordfish\"`.\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\nIsso seria parecido com:\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # Return some error\n    ...\n```\n\nPorém, ao utilizar o `secrets.compare_digest()`, isso estará seguro contra um tipo de ataque chamado \"timing attacks\".\n\n### Ataques de Temporização { #timing-attacks }\n\nMas o que é um \"timing attack\"?\n\nVamos imaginar que alguns invasores estão tentando adivinhar o usuário e a senha.\n\nE eles enviam uma requisição com um usuário `johndoe` e uma senha `love123`.\n\nEntão o código Python em sua aplicação seria equivalente a algo como:\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nMas no exato momento que o Python compara o primeiro `j` em `johndoe` contra o primeiro `s` em `stanleyjobson`, ele retornará `False`, porque ele já sabe que aquelas duas strings não são a mesma, pensando que \"não existe a necessidade de desperdiçar mais poder computacional comparando o resto das letras\". E a sua aplicação dirá \"Usuário ou senha incorretos\".\n\nEntão os invasores vão tentar com o usuário `stanleyjobsox` e a senha `love123`.\n\nE a sua aplicação faz algo como:\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nO Python terá que comparar todo o `stanleyjobso` tanto em `stanleyjobsox` como em `stanleyjobson` antes de perceber que as strings não são a mesma. Então isso levará alguns microssegundos a mais para retornar \"Usuário ou senha incorretos\".\n\n#### O tempo para responder ajuda os invasores { #the-time-to-answer-helps-the-attackers }\n\nNeste ponto, ao perceber que o servidor demorou alguns microssegundos a mais para enviar o retorno \"Usuário ou senha incorretos\", os invasores irão saber que eles acertaram _alguma coisa_, algumas das letras iniciais estavam certas.\n\nE eles podem tentar de novo sabendo que provavelmente é algo mais parecido com `stanleyjobsox` do que com `johndoe`.\n\n#### Um ataque \"profissional\" { #a-professional-attack }\n\nClaro, os invasores não tentariam tudo isso de forma manual, eles escreveriam um programa para fazer isso, possivelmente com milhares ou milhões de testes por segundo. E obteriam apenas uma letra a mais por vez.\n\nMas fazendo isso, em alguns minutos ou horas os invasores teriam adivinhado o usuário e senha corretos, com a \"ajuda\" da nossa aplicação, apenas usando o tempo levado para responder.\n\n#### Corrija com o `secrets.compare_digest()` { #fix-it-with-secrets-compare-digest }\n\nMas em nosso código já estamos utilizando o `secrets.compare_digest()`.\n\nResumindo, levará o mesmo tempo para comparar `stanleyjobsox` com `stanleyjobson` do que comparar `johndoe` com `stanleyjobson`. E o mesmo para a senha.\n\nDeste modo, ao utilizar `secrets.compare_digest()` no código de sua aplicação, ela estará a salvo contra toda essa gama de ataques de segurança.\n\n### Retorne o erro { #return-the-error }\n\nApós detectar que as credenciais estão incorretas, retorne um `HTTPException` com o status 401 (o mesmo retornado quando nenhuma credencial foi informada) e adicione o cabeçalho `WWW-Authenticate` para fazer com que o navegador mostre o prompt de login novamente:\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/pt/docs/advanced/security/index.md",
    "content": "# Segurança Avançada { #advanced-security }\n\n## Funcionalidades Adicionais { #additional-features }\n\nExistem algumas funcionalidades adicionais para lidar com segurança além das cobertas em [Tutorial - Guia de Usuário: Segurança](../../tutorial/security/index.md).\n\n/// tip | Dica\n\nAs próximas seções **não são necessariamente \"avançadas\"**.\n\nE é possível que para o seu caso de uso, a solução está em uma delas.\n\n///\n\n## Leia o Tutorial primeiro { #read-the-tutorial-first }\n\nAs próximas seções pressupõem que você já leu o principal [Tutorial - Guia de Usuário: Segurança](../../tutorial/security/index.md).\n\nTodas elas são baseadas nos mesmos conceitos, mas permitem algumas funcionalidades extras.\n"
  },
  {
    "path": "docs/pt/docs/advanced/security/oauth2-scopes.md",
    "content": "# Escopos OAuth2 { #oauth2-scopes }\n\nVocê pode utilizar escopos do OAuth2 diretamente com o **FastAPI**, eles são integrados para funcionar perfeitamente.\n\nIsso permitiria que você tivesse um sistema de permissionamento mais refinado, seguindo o padrão do OAuth2 integrado na sua aplicação OpenAPI (e as documentações da API).\n\nOAuth2 com escopos é o mecanismo utilizado por muitos provedores de autenticação, como o Facebook, Google, GitHub, Microsoft, X (Twitter), etc. Eles utilizam isso para prover permissões específicas para os usuários e aplicações.\n\nToda vez que você \"se autentica com\" Facebook, Google, GitHub, Microsoft, X (Twitter), aquela aplicação está utilizando o OAuth2 com escopos.\n\nNesta seção, você verá como gerenciar a autenticação e autorização com os mesmos escopos do OAuth2 em sua aplicação **FastAPI**.\n\n/// warning | Atenção\n\nIsso é uma seção mais ou menos avançada. Se você está apenas começando, você pode pular.\n\nVocê não necessariamente precisa de escopos do OAuth2, e você pode lidar com autenticação e autorização da maneira que você achar melhor.\n\nMas o OAuth2 com escopos pode ser integrado de maneira fácil em sua API (com OpenAPI) e a sua documentação de API.\n\nNo entanto, você ainda aplica estes escopos, ou qualquer outro requisito de segurança/autorização, conforme necessário, em seu código.\n\nEm muitos casos, OAuth2 com escopos pode ser um exagero.\n\nMas se você sabe que precisa, ou está curioso, continue lendo.\n\n///\n\n## Escopos OAuth2 e OpenAPI { #oauth2-scopes-and-openapi }\n\nA especificação OAuth2 define \"escopos\" como uma lista de strings separadas por espaços.\n\nO conteúdo de cada uma dessas strings pode ter qualquer formato, mas não devem possuir espaços.\n\nEstes escopos representam \"permissões\".\n\nNo OpenAPI (e.g. os documentos da API), você pode definir \"esquemas de segurança\".\n\nQuando um desses esquemas de segurança utiliza OAuth2, você pode também declarar e utilizar escopos.\n\nCada \"escopo\" é apenas uma string (sem espaços).\n\nEles são normalmente utilizados para declarar permissões de segurança específicas, como por exemplo:\n\n* `users:read` or `users:write` são exemplos comuns.\n* `instagram_basic` é utilizado pelo Facebook / Instagram.\n* `https://www.googleapis.com/auth/drive` é utilizado pelo Google.\n\n/// info | Informação\n\nNo OAuth2, um \"escopo\" é apenas uma string que declara uma permissão específica necessária.\n\nNão importa se ela contém outros caracteres como `:` ou se ela é uma URL.\n\nEstes detalhes são específicos da implementação.\n\nPara o OAuth2, eles são apenas strings.\n\n///\n\n## Visão global { #global-view }\n\nPrimeiro, vamos olhar rapidamente as partes que mudam dos exemplos do **Tutorial - Guia de Usuário** para [OAuth2 com Senha (e hash), Bearer com tokens JWT](../../tutorial/security/oauth2-jwt.md). Agora utilizando escopos OAuth2:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\nAgora vamos revisar essas mudanças passo a passo.\n\n## Esquema de segurança OAuth2 { #oauth2-security-scheme }\n\nA primeira mudança é que agora nós estamos declarando o esquema de segurança OAuth2 com dois escopos disponíveis, `me` e `items`.\n\nO parâmetro `scopes` recebe um `dict` contendo cada escopo como chave e a descrição como valor:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\nPelo motivo de estarmos declarando estes escopos, eles aparecerão nos documentos da API quando você se autenticar/autorizar.\n\nE você poderá selecionar quais escopos você deseja dar acesso: `me` e `items`.\n\nEste é o mesmo mecanismo utilizado quando você adiciona permissões enquanto se autentica com o Facebook, Google, GitHub, etc:\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## Token JWT com escopos { #jwt-token-with-scopes }\n\nAgora, modifique a *operação de rota* do token para retornar os escopos solicitados.\n\nNós ainda estamos utilizando o mesmo `OAuth2PasswordRequestForm`. Ele inclui a propriedade `scopes` com uma `list` de `str`, com cada escopo que ele recebeu na requisição.\n\nE nós retornamos os escopos como parte do token JWT.\n\n/// danger | Cuidado\n\nPara manter as coisas simples, aqui nós estamos apenas adicionando os escopos recebidos diretamente ao token.\n\nPorém em sua aplicação, por segurança, você deveria garantir que você apenas adiciona os escopos que o usuário possui permissão de fato, ou aqueles que você predefiniu.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## Declare escopos em *operações de rota* e dependências { #declare-scopes-in-path-operations-and-dependencies }\n\nAgora nós declaramos que a *operação de rota* para `/users/me/items/` exige o escopo `items`.\n\nPara isso, nós importamos e utilizamos `Security` de `fastapi`.\n\nVocê pode utilizar `Security` para declarar dependências (assim como `Depends`), porém o `Security` também recebe o parâmetro `scopes` com uma lista de escopos (strings).\n\nNeste caso, nós passamos a função `get_current_active_user` como dependência para `Security` (da mesma forma que nós faríamos com `Depends`).\n\nMas nós também passamos uma `list` de escopos, neste caso com apenas um escopo: `items` (poderia ter mais).\n\nE a função de dependência `get_current_active_user` também pode declarar subdependências, não apenas com `Depends`, mas também com `Security`. Ao declarar sua própria função de subdependência (`get_current_user`), e mais requisitos de escopo.\n\nNeste caso, ele requer o escopo `me` (poderia requerer mais de um escopo).\n\n/// note | Nota\n\nVocê não necessariamente precisa adicionar diferentes escopos em diferentes lugares.\n\nNós estamos fazendo isso aqui para demonstrar como o **FastAPI** lida com escopos declarados em diferentes níveis.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// note | Detalhes Técnicos\n\n`Security` é na verdade uma subclasse de `Depends`, e ele possui apenas um parâmetro extra que veremos depois.\n\nPorém ao utilizar `Security` no lugar de `Depends`, o **FastAPI** saberá que ele pode declarar escopos de segurança, utilizá-los internamente, e documentar a API com o OpenAPI.\n\nMas quando você importa `Query`, `Path`, `Depends`, `Security` entre outros de `fastapi`, eles são na verdade funções que retornam classes especiais.\n\n///\n\n## Utilize `SecurityScopes` { #use-securityscopes }\n\nAgora atualize a dependência `get_current_user`.\n\nEste é o usado pelas dependências acima.\n\nAqui é onde estamos utilizando o mesmo esquema OAuth2 que nós declaramos antes, declarando-o como uma dependência: `oauth2_scheme`.\n\nPorque esta função de dependência não possui nenhum requerimento de escopo, nós podemos utilizar `Depends` com o `oauth2_scheme`. Nós não precisamos utilizar `Security` quando nós não precisamos especificar escopos de segurança.\n\nNós também declaramos um parâmetro especial do tipo `SecurityScopes`, importado de `fastapi.security`.\n\nA classe `SecurityScopes` é semelhante à classe `Request` (`Request` foi utilizada para obter o objeto da requisição diretamente).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## Utilize os `scopes` { #use-the-scopes }\n\nO parâmetro `security_scopes` será do tipo `SecurityScopes`.\n\nEle terá a propriedade `scopes` com uma lista contendo todos os escopos requeridos por ele e todas as dependências que utilizam ele como uma subdependência. Isso significa, todos  os \"dependentes\"... pode soar meio confuso, e isso será explicado novamente mais adiante.\n\nO objeto `security_scopes` (da classe `SecurityScopes`) também oferece um atributo `scope_str` com uma única string, contendo os escopos separados por espaços (nós vamos utilizar isso).\n\nNós criamos uma `HTTPException` que nós podemos reutilizar (`raise`) mais tarde em diversos lugares.\n\nNesta exceção, nós incluímos os escopos necessários (se houver algum) como uma string separada por espaços (utilizando `scope_str`). Nós colocamos esta string contendo os escopos no cabeçalho `WWW-Authenticate` (isso é parte da especificação).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## Verifique o `username` e o formato dos dados { #verify-the-username-and-data-shape }\n\nNós verificamos que nós obtemos um `username`, e extraímos os escopos.\n\nE depois nós validamos esse dado com o modelo Pydantic (capturando a exceção `ValidationError`), e se nós obtemos um erro ao ler o token JWT ou validando os dados com o Pydantic, nós levantamos a exceção `HTTPException` que criamos anteriormente.\n\nPara isso, nós atualizamos o modelo Pydantic `TokenData` com a nova propriedade `scopes`.\n\nAo validar os dados com o Pydantic nós podemos garantir que temos, por exemplo, exatamente uma `list` de `str` com os escopos e uma `str` com o `username`.\n\nNo lugar de, por exemplo, um `dict`, ou alguma outra coisa, que poderia quebrar a aplicação em algum lugar mais tarde, tornando isso um risco de segurança.\n\nNós também verificamos que nós temos um usuário com o \"*username*\", e caso contrário, nós levantamos a mesma exceção que criamos anteriormente.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## Verifique os `scopes` { #verify-the-scopes }\n\nNós verificamos agora que todos os escopos necessários, por essa dependência e todos os dependentes (incluindo as *operações de rota*) estão incluídas nos escopos fornecidos pelo token recebido, caso contrário, levantamos uma `HTTPException`.\n\nPara isso, nós utilizamos `security_scopes.scopes`, que contém uma `list` com todos esses escopos como uma `str`.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## Árvore de dependência e escopos { #dependency-tree-and-scopes }\n\nVamos rever novamente essa árvore de dependência e os escopos.\n\nComo a dependência `get_current_active_user` possui uma subdependência em `get_current_user`, o escopo `\"me\"` declarado em `get_current_active_user` será incluído na lista de escopos necessários em `security_scopes.scopes` passado para `get_current_user`.\n\nA própria *operação de rota* também declara o escopo, `\"items\"`, então ele também estará na lista de `security_scopes.scopes` passado para o `get_current_user`.\n\nAqui está como a hierarquia de dependências e escopos parecem:\n\n* A *operação de rota* `read_own_items` possui:\n    * Escopos necessários `[\"items\"]` com a dependência:\n    * `get_current_active_user`:\n        *  A função de dependência `get_current_active_user` possui:\n            * Escopos necessários `[\"me\"]` com a dependência:\n            * `get_current_user`:\n                * A função de dependência `get_current_user` possui:\n                    * Nenhum escopo necessário.\n                    * Uma dependência utilizando `oauth2_scheme`.\n                    * Um parâmetro `security_scopes` do tipo `SecurityScopes`:\n                        * Este parâmetro `security_scopes` possui uma propriedade `scopes` com uma `list` contendo todos estes escopos declarados acima, então:\n                            * `security_scopes.scopes` terá `[\"me\", \"items\"]` para a *operação de rota* `read_own_items`.\n                            * `security_scopes.scopes` terá `[\"me\"]` para a *operação de rota* `read_users_me`, porque ela declarou na dependência `get_current_active_user`.\n                            * `security_scopes.scopes` terá `[]` (nada) para a *operação de rota* `read_system_status`, porque ele não declarou nenhum `Security` com `scopes`, e sua dependência, `get_current_user`, não declara nenhum `scopes` também.\n\n/// tip | Dica\n\nA coisa importante e \"mágica\" aqui é que `get_current_user` terá diferentes listas de `scopes` para validar para cada *operação de rota*.\n\nTudo depende dos `scopes` declarados em cada *operação de rota* e cada dependência da árvore de dependências para aquela *operação de rota* específica.\n\n///\n\n## Mais detalhes sobre `SecurityScopes` { #more-details-about-securityscopes }\n\nVocê pode utilizar `SecurityScopes` em qualquer lugar, e em diversos lugares. Ele não precisa estar na dependência \"raiz\".\n\nEle sempre terá os escopos de segurança declarados nas dependências atuais de `Security` e todos os dependentes para **aquela** *operação de rota* **específica** e **aquela** árvore de dependência **específica**.\n\nPorque o `SecurityScopes` terá todos os escopos declarados por dependentes, você pode utilizá-lo para verificar se o token possui os escopos necessários em uma função de dependência central, e depois declarar diferentes requisitos de escopo em diferentes *operações de rota*.\n\nTodos eles serão validados independentemente para cada *operação de rota*.\n\n## Verifique { #check-it }\n\nSe você abrir os documentos da API, você pode autenticar e especificar quais escopos você quer autorizar.\n\n<img src=\"/img/tutorial/security/image11.png\">\n\nSe você não selecionar nenhum escopo, você terá \"autenticado\", mas quando você tentar acessar `/users/me/` ou `/users/me/items/`, você vai obter um erro dizendo que você não possui as permissões necessárias. Você ainda poderá acessar `/status/`.\n\nE se você selecionar o escopo `me`, mas não o escopo `items`, você poderá acessar `/users/me/`, mas não `/users/me/items/`.\n\nIsso é o que aconteceria se uma aplicação terceira que tentou acessar uma dessas *operações de rota* com um token fornecido por um usuário, dependendo de quantas permissões o usuário forneceu para a aplicação.\n\n## Sobre integrações de terceiros { #about-third-party-integrations }\n\nNeste exemplo nós estamos utilizando o fluxo de senha do OAuth2.\n\nIsso é apropriado quando nós estamos autenticando em nossa própria aplicação, provavelmente com o nosso próprio \"*frontend*\".\n\nPorque nós podemos confiar nele para receber o `username` e o `password`, pois nós controlamos isso.\n\nMas se nós estamos construindo uma aplicação OAuth2 que outros poderiam conectar (i.e., se você está construindo um provedor de autenticação equivalente ao Facebook, Google, GitHub, etc.) você deveria utilizar um dos outros fluxos.\n\nO mais comum é o fluxo implícito.\n\nO mais seguro é o fluxo de código, mas ele é mais complexo para implementar, pois ele necessita mais passos. Como ele é mais complexo, muitos provedores terminam sugerindo o fluxo implícito.\n\n/// note | Nota\n\nÉ comum que cada provedor de autenticação nomeie os seus fluxos de forma diferente, para torná-lo parte de sua marca.\n\nMas no final, eles estão implementando o mesmo padrão OAuth2.\n\n///\n\nO **FastAPI** inclui utilitários para todos esses fluxos de autenticação OAuth2 em `fastapi.security.oauth2`.\n\n## `Security` em decoradores de `dependencies` { #security-in-decorator-dependencies }\n\nDa mesma forma que você pode definir uma `list` de `Depends` no parâmetro `dependencies` do decorador (como explicado em [Dependências em decoradores de operações de rota](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)), você também pode utilizar `Security` com escopos lá.\n"
  },
  {
    "path": "docs/pt/docs/advanced/settings.md",
    "content": "# Configurações e Variáveis de Ambiente { #settings-and-environment-variables }\n\nEm muitos casos, sua aplicação pode precisar de configurações externas, por exemplo chaves secretas, credenciais de banco de dados, credenciais para serviços de e-mail, etc.\n\nA maioria dessas configurações é variável (pode mudar), como URLs de banco de dados. E muitas podem ser sensíveis, como segredos.\n\nPor esse motivo, é comum fornecê-las em variáveis de ambiente lidas pela aplicação.\n\n/// tip | Dica\n\nPara entender variáveis de ambiente, você pode ler [Variáveis de Ambiente](../environment-variables.md).\n\n///\n\n## Tipagem e validação { #types-and-validation }\n\nEssas variáveis de ambiente só conseguem lidar com strings de texto, pois são externas ao Python e precisam ser compatíveis com outros programas e com o resto do sistema (e até com diferentes sistemas operacionais, como Linux, Windows, macOS).\n\nIsso significa que qualquer valor lido em Python a partir de uma variável de ambiente será uma `str`, e qualquer conversão para um tipo diferente ou validação precisa ser feita em código.\n\n## Pydantic `Settings` { #pydantic-settings }\n\nFelizmente, o Pydantic fornece uma ótima utilidade para lidar com essas configurações vindas de variáveis de ambiente com [Pydantic: Settings management](https://docs.pydantic.dev/latest/concepts/pydantic_settings/).\n\n### Instalar `pydantic-settings` { #install-pydantic-settings }\n\nPrimeiro, certifique-se de criar seu [ambiente virtual](../virtual-environments.md), ativá-lo e então instalar o pacote `pydantic-settings`:\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\nEle também vem incluído quando você instala os extras `all` com:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### Criar o objeto `Settings` { #create-the-settings-object }\n\nImporte `BaseSettings` do Pydantic e crie uma subclasse, muito parecido com um modelo do Pydantic.\n\nDa mesma forma que com modelos do Pydantic, você declara atributos de classe com anotações de tipo e, possivelmente, valores padrão.\n\nVocê pode usar as mesmas funcionalidades e ferramentas de validação que usa em modelos do Pydantic, como diferentes tipos de dados e validações adicionais com `Field()`.\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip | Dica\n\nSe você quer algo rápido para copiar e colar, não use este exemplo, use o último abaixo.\n\n///\n\nEntão, quando você cria uma instância dessa classe `Settings` (neste caso, no objeto `settings`), o Pydantic vai ler as variáveis de ambiente sem diferenciar maiúsculas de minúsculas; assim, uma variável em maiúsculas `APP_NAME` ainda será lida para o atributo `app_name`.\n\nEm seguida, ele converterá e validará os dados. Assim, quando você usar esse objeto `settings`, terá dados dos tipos que declarou (por exemplo, `items_per_user` será um `int`).\n\n### Usar o `settings` { #use-the-settings }\n\nDepois você pode usar o novo objeto `settings` na sua aplicação:\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### Executar o servidor { #run-the-server }\n\nEm seguida, você executaria o servidor passando as configurações como variáveis de ambiente, por exemplo, você poderia definir `ADMIN_EMAIL` e `APP_NAME` com:\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip | Dica\n\nPara definir várias variáveis de ambiente para um único comando, basta separá-las com espaço e colocá-las todas antes do comando.\n\n///\n\nEntão a configuração `admin_email` seria definida como `\"deadpool@example.com\"`.\n\nO `app_name` seria `\"ChimichangApp\"`.\n\nE `items_per_user` manteria seu valor padrão de `50`.\n\n## Configurações em outro módulo { #settings-in-another-module }\n\nVocê pode colocar essas configurações em outro arquivo de módulo como visto em [Aplicações Maiores - Múltiplos Arquivos](../tutorial/bigger-applications.md).\n\nPor exemplo, você poderia ter um arquivo `config.py` com:\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\nE então usá-lo em um arquivo `main.py`:\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip | Dica\n\nVocê também precisaria de um arquivo `__init__.py` como visto em [Aplicações Maiores - Múltiplos Arquivos](../tutorial/bigger-applications.md).\n\n///\n\n## Configurações em uma dependência { #settings-in-a-dependency }\n\nEm algumas ocasiões, pode ser útil fornecer as configurações a partir de uma dependência, em vez de ter um objeto global `settings` usado em todos os lugares.\n\nIsso pode ser especialmente útil durante os testes, pois é muito fácil sobrescrever uma dependência com suas próprias configurações personalizadas.\n\n### O arquivo de configuração { #the-config-file }\n\nVindo do exemplo anterior, seu arquivo `config.py` poderia ser assim:\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\nPerceba que agora não criamos uma instância padrão `settings = Settings()`.\n\n### O arquivo principal da aplicação { #the-main-app-file }\n\nAgora criamos uma dependência que retorna um novo `config.Settings()`.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip | Dica\n\nVamos discutir o `@lru_cache` em breve.\n\nPor enquanto, você pode assumir que `get_settings()` é uma função normal.\n\n///\n\nE então podemos exigi-la na *função de operação de rota* como dependência e usá-la onde for necessário.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### Configurações e testes { #settings-and-testing }\n\nEntão seria muito fácil fornecer um objeto de configurações diferente durante os testes criando uma sobrescrita de dependência para `get_settings`:\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\nNa sobrescrita da dependência definimos um novo valor para `admin_email` ao criar o novo objeto `Settings`, e então retornamos esse novo objeto.\n\nDepois podemos testar que ele é usado.\n\n## Lendo um arquivo `.env` { #reading-a-env-file }\n\nSe você tiver muitas configurações que possivelmente mudam bastante, talvez em diferentes ambientes, pode ser útil colocá-las em um arquivo e então lê-las como se fossem variáveis de ambiente.\n\nEssa prática é tão comum que tem um nome: essas variáveis de ambiente são comumente colocadas em um arquivo `.env`, e o arquivo é chamado de \"dotenv\".\n\n/// tip | Dica\n\nUm arquivo começando com um ponto (`.`) é um arquivo oculto em sistemas tipo Unix, como Linux e macOS.\n\nMas um arquivo dotenv não precisa ter exatamente esse nome de arquivo.\n\n///\n\nO Pydantic tem suporte para leitura desses tipos de arquivos usando uma biblioteca externa. Você pode ler mais em [Pydantic Settings: Dotenv (.env) support](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support).\n\n/// tip | Dica\n\nPara isso funcionar, você precisa executar `pip install python-dotenv`.\n\n///\n\n### O arquivo `.env` { #the-env-file }\n\nVocê poderia ter um arquivo `.env` com:\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### Ler configurações do `.env` { #read-settings-from-env }\n\nE então atualizar seu `config.py` com:\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip | Dica\n\nO atributo `model_config` é usado apenas para configuração do Pydantic. Você pode ler mais em [Pydantic: Concepts: Configuration](https://docs.pydantic.dev/latest/concepts/config/).\n\n///\n\nAqui definimos a configuração `env_file` dentro da sua classe `Settings` do Pydantic e definimos o valor como o nome do arquivo dotenv que queremos usar.\n\n### Criando o `Settings` apenas uma vez com `lru_cache` { #creating-the-settings-only-once-with-lru-cache }\n\nLer um arquivo do disco normalmente é uma operação custosa (lenta), então você provavelmente vai querer fazer isso apenas uma vez e depois reutilizar o mesmo objeto de configurações, em vez de lê-lo a cada requisição.\n\nMas toda vez que fizermos:\n\n```Python\nSettings()\n```\n\num novo objeto `Settings` seria criado e, na criação, ele leria o arquivo `.env` novamente.\n\nSe a função de dependência fosse assim:\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\ncriaríamos esse objeto para cada requisição e leríamos o arquivo `.env` para cada requisição. ⚠️\n\nMas como estamos usando o decorador `@lru_cache` por cima, o objeto `Settings` será criado apenas uma vez, na primeira vez em que for chamado. ✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\nEm qualquer chamada subsequente de `get_settings()` nas dependências das próximas requisições, em vez de executar o código interno de `get_settings()` e criar um novo objeto `Settings`, ele retornará o mesmo objeto que foi retornado na primeira chamada, repetidamente.\n\n#### Detalhes Técnicos do `lru_cache` { #lru-cache-technical-details }\n\n`@lru_cache` modifica a função que decora para retornar o mesmo valor que foi retornado na primeira vez, em vez de calculá-lo novamente executando o código da função todas as vezes.\n\nAssim, a função abaixo dele será executada uma vez para cada combinação de argumentos. E então os valores retornados para cada uma dessas combinações de argumentos serão usados repetidamente sempre que a função for chamada com exatamente a mesma combinação de argumentos.\n\nPor exemplo, se você tiver uma função:\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\nseu programa poderia executar assim:\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Execute function\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n```\n\nNo caso da nossa dependência `get_settings()`, a função nem recebe argumentos, então ela sempre retorna o mesmo valor.\n\nDessa forma, ela se comporta quase como se fosse apenas uma variável global. Mas como usa uma função de dependência, podemos sobrescrevê-la facilmente para testes.\n\n`@lru_cache` faz parte de `functools`, que faz parte da biblioteca padrão do Python; você pode ler mais sobre isso na [documentação do Python para `@lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache).\n\n## Recapitulando { #recap }\n\nVocê pode usar Pydantic Settings para lidar com as configurações da sua aplicação, com todo o poder dos modelos Pydantic.\n\n* Usando uma dependência você pode simplificar os testes.\n* Você pode usar arquivos `.env` com ele.\n* Usar `@lru_cache` permite evitar ler o arquivo dotenv repetidamente a cada requisição, enquanto permite sobrescrevê-lo durante os testes.\n"
  },
  {
    "path": "docs/pt/docs/advanced/stream-data.md",
    "content": "# Transmitir dados { #stream-data }\n\nSe você quer transmitir dados que podem ser estruturados como JSON, você deveria [Transmitir JSON Lines](../tutorial/stream-json-lines.md).\n\nMas se você quer transmitir dados binários puros ou strings, veja como fazer.\n\n/// info | Informação\n\nAdicionado no FastAPI 0.134.0.\n\n///\n\n## Casos de uso { #use-cases }\n\nVocê pode usar isto para transmitir strings puras, por exemplo diretamente da saída de um serviço de AI LLM.\n\nVocê também pode usá-lo para transmitir arquivos binários grandes, enviando cada bloco de dados à medida que o lê, sem precisar carregar tudo na memória de uma vez.\n\nVocê também pode transmitir vídeo ou áudio desta forma; pode até ser gerado enquanto você processa e envia.\n\n## Um `StreamingResponse` com `yield` { #a-streamingresponse-with-yield }\n\nSe você declarar `response_class=StreamingResponse` na sua função de operação de rota, você pode usar `yield` para enviar cada bloco de dados em sequência.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nO FastAPI entregará cada bloco de dados para `StreamingResponse` como está, não tentará convertê-lo para JSON nem nada semelhante.\n\n### Funções de operação de rota não assíncronas { #non-async-path-operation-functions }\n\nVocê também pode usar funções `def` normais (sem `async`) e usar `yield` da mesma forma.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### Sem anotação { #no-annotation }\n\nVocê não precisa declarar a anotação de tipo de retorno para transmitir dados binários.\n\nComo o FastAPI não tentará converter os dados para JSON com Pydantic nem serializá-los de nenhuma forma, neste caso a anotação de tipo serve apenas para seu editor e ferramentas; ela não será usada pelo FastAPI.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\nIsso também significa que, com `StreamingResponse`, você tem a liberdade e a responsabilidade de produzir e codificar os bytes exatamente como precisam ser enviados, independentemente das anotações de tipo. 🤓\n\n### Transmitir bytes { #stream-bytes }\n\nUm dos principais casos de uso é transmitir `bytes` em vez de strings; você pode fazer isso sem problemas.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## Um `PNGStreamingResponse` personalizado { #a-custom-pngstreamingresponse }\n\nNos exemplos acima, os bytes eram transmitidos, mas a resposta não tinha um cabeçalho `Content-Type`, então o cliente não sabia que tipo de dado estava recebendo.\n\nVocê pode criar uma subclasse personalizada de `StreamingResponse` que define o cabeçalho `Content-Type` para o tipo de dado que você está transmitindo.\n\nPor exemplo, você pode criar um `PNGStreamingResponse` que define o cabeçalho `Content-Type` como `image/png` usando o atributo `media_type`:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\nEm seguida, você pode usar essa nova classe em `response_class=PNGStreamingResponse` na sua função de operação de rota:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### Simular um arquivo { #simulate-a-file }\n\nNeste exemplo, estamos simulando um arquivo com `io.BytesIO`, que é um objeto semelhante a arquivo que vive somente na memória, mas nos permite usar a mesma interface.\n\nPor exemplo, podemos iterar sobre ele para consumir seu conteúdo, como faríamos com um arquivo.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | Detalhes Técnicos\n\nAs outras duas variáveis, `image_base64` e `binary_image`, são uma imagem codificada em Base64 e depois convertida para bytes, para então passá-la para `io.BytesIO`.\n\nApenas para que possa viver no mesmo arquivo deste exemplo e você possa copiar e executar como está. 🥚\n\n///\n\nAo usar um bloco `with`, garantimos que o objeto semelhante a arquivo seja fechado após a função geradora (a função com `yield`) terminar. Ou seja, após terminar de enviar a resposta.\n\nIsso não seria tão importante neste exemplo específico porque é um arquivo falso em memória (com `io.BytesIO`), mas com um arquivo real, seria importante garantir que o arquivo fosse fechado ao final do trabalho.\n\n### Arquivos e async { #files-and-async }\n\nNa maioria dos casos, objetos semelhantes a arquivo não são compatíveis com async e await por padrão.\n\nPor exemplo, eles não têm `await file.read()`, nem `async for chunk in file`.\n\nE, em muitos casos, lê-los seria uma operação bloqueante (que poderia bloquear o loop de eventos), pois são lidos do disco ou da rede.\n\n/// info | Informação\n\nO exemplo acima é, na verdade, uma exceção, porque o objeto `io.BytesIO` já está em memória, então lê-lo não bloqueará nada.\n\nMas, em muitos casos, ler um arquivo ou um objeto semelhante a arquivo bloquearia.\n\n///\n\nPara evitar bloquear o loop de eventos, você pode simplesmente declarar a função de operação de rota com `def` normal em vez de `async def`. Assim, o FastAPI a executará em um worker de threadpool, evitando bloquear o loop principal.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip | Dica\n\nSe você precisar chamar código bloqueante de dentro de uma função assíncrona ou uma função assíncrona de dentro de uma função bloqueante, você poderia usar o [Asyncer](https://asyncer.tiangolo.com), uma biblioteca irmã do FastAPI.\n\n///\n\n### `yield from` { #yield-from }\n\nQuando você está iterando sobre algo, como um objeto semelhante a arquivo, e faz `yield` para cada item, você também pode usar `yield from` para produzir cada item diretamente e pular o loop `for`.\n\nIsso não é particular do FastAPI, é apenas Python, mas é um truque útil para conhecer. 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/pt/docs/advanced/strict-content-type.md",
    "content": "# Verificação Estrita de Content-Type { #strict-content-type-checking }\n\nPor padrão, o **FastAPI** usa verificação estrita do cabeçalho `Content-Type` para corpos de requisição JSON; isso significa que requisições JSON devem incluir um `Content-Type` válido (por exemplo, `application/json`) para que o corpo seja interpretado como JSON.\n\n## Risco de CSRF { #csrf-risk }\n\nEsse comportamento padrão oferece proteção contra uma classe de ataques de **Cross-Site Request Forgery (CSRF)** em um cenário muito específico.\n\nEsses ataques exploram o fato de que navegadores permitem que scripts enviem requisições sem fazer qualquer verificação de preflight de CORS quando:\n\n- não têm um cabeçalho `Content-Type` (por exemplo, usando `fetch()` com um corpo `Blob`)\n- e não enviam nenhuma credencial de autenticação.\n\nEsse tipo de ataque é relevante principalmente quando:\n\n- a aplicação está em execução localmente (por exemplo, em `localhost`) ou em uma rede interna\n- e a aplicação não tem autenticação, pressupondo que qualquer requisição da mesma rede é confiável.\n\n## Exemplo de Ataque { #example-attack }\n\nImagine que você desenvolve uma forma de executar um agente de IA local.\n\nEle fornece uma API em\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nHá também um frontend em\n\n```\nhttp://localhost:8000\n```\n\n/// tip | Dica\n\nObserve que ambos têm o mesmo host.\n\n///\n\nUsando o frontend, você pode fazer o agente de IA executar ações em seu nome.\n\nComo está em execução localmente e não na Internet aberta, você decide não configurar autenticação, confiando apenas no acesso à rede local.\n\nEntão um de seus usuários poderia instalá-lo e executá-lo localmente.\n\nEm seguida, poderia abrir um site malicioso, por exemplo:\n\n```\nhttps://evilhackers.example.com\n```\n\nE esse site malicioso envia requisições usando `fetch()` com um corpo `Blob` para a API local em\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nMesmo que o host do site malicioso e o da aplicação local sejam diferentes, o navegador não acionará uma requisição preflight de CORS porque:\n\n- Está em execução sem autenticação, não precisa enviar credenciais.\n- O navegador acha que não está enviando JSON (devido à falta do cabeçalho `Content-Type`).\n\nEntão o site malicioso poderia fazer o agente de IA local enviar mensagens raivosas ao ex-chefe do usuário... ou pior. 😅\n\n## Internet Aberta { #open-internet }\n\nSe sua aplicação está na Internet aberta, você não “confiaria na rede” nem deixaria qualquer pessoa enviar requisições privilegiadas sem autenticação.\n\nAtacantes poderiam simplesmente executar um script para enviar requisições à sua API, sem necessidade de interação do navegador, então você provavelmente já está protegendo quaisquer endpoints privilegiados.\n\nNesse caso, esse ataque/risco não se aplica a você.\n\nEsse risco e ataque é relevante principalmente quando a aplicação roda na rede local e essa é a única proteção presumida.\n\n## Permitindo Requisições sem Content-Type { #allowing-requests-without-content-type }\n\nSe você precisa dar suporte a clientes que não enviam um cabeçalho `Content-Type`, você pode desativar a verificação estrita definindo `strict_content_type=False`:\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\nCom essa configuração, requisições sem um cabeçalho `Content-Type` terão o corpo interpretado como JSON, o mesmo comportamento das versões mais antigas do FastAPI.\n\n/// info | Informação\n\nEsse comportamento e configuração foram adicionados no FastAPI 0.132.0.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/advanced/sub-applications.md",
    "content": "# Sub Aplicações - Montagens { #sub-applications-mounts }\n\nSe você precisar ter duas aplicações FastAPI independentes, cada uma com seu próprio OpenAPI e suas próprias interfaces de documentação, você pode ter um aplicativo principal e \"montar\" uma (ou mais) sub-aplicações.\n\n## Montando uma aplicação **FastAPI** { #mounting-a-fastapi-application }\n\n\"Montar\" significa adicionar uma aplicação completamente \"independente\" em um path específico, que então se encarrega de lidar com tudo sob esse path, com as _operações de rota_ declaradas nessa sub-aplicação.\n\n### Aplicação de nível superior { #top-level-application }\n\nPrimeiro, crie a aplicação principal, de nível superior, **FastAPI**, e suas *operações de rota*:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### Sub-aplicação { #sub-application }\n\nEm seguida, crie sua sub-aplicação e suas *operações de rota*.\n\nEssa sub-aplicação é apenas outra aplicação FastAPI padrão, mas esta é a que será \"montada\":\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### Monte a sub-aplicação { #mount-the-sub-application }\n\nNa sua aplicação de nível superior, `app`, monte a sub-aplicação, `subapi`.\n\nNeste caso, ela será montada no path `/subapi`:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### Verifique a documentação automática da API { #check-the-automatic-api-docs }\n\nAgora, execute o comando `fastapi`:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nE abra a documentação em [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVocê verá a documentação automática da API para a aplicação principal, incluindo apenas suas próprias _operações de rota_:\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\nE então, abra a documentação para a sub-aplicação, em [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs).\n\nVocê verá a documentação automática da API para a sub-aplicação, incluindo apenas suas próprias _operações de rota_, todas sob o prefixo de sub-path correto `/subapi`:\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\nSe você tentar interagir com qualquer uma das duas interfaces de usuário, elas funcionarão corretamente, porque o navegador será capaz de se comunicar com cada aplicação ou sub-aplicação específica.\n\n### Detalhes Técnicos: `root_path` { #technical-details-root-path }\n\nQuando você monta uma sub-aplicação como descrito acima, o FastAPI se encarrega de comunicar o path de montagem para a sub-aplicação usando um mecanismo da especificação ASGI chamado `root_path`.\n\nDessa forma, a sub-aplicação saberá usar esse prefixo de path para a interface de documentação.\n\nE a sub-aplicação também poderia ter suas próprias sub-aplicações montadas e tudo funcionaria corretamente, porque o FastAPI lida com todos esses `root_path`s automaticamente.\n\nVocê aprenderá mais sobre o `root_path` e como usá-lo explicitamente na seção sobre [Atrás de um Proxy](behind-a-proxy.md).\n"
  },
  {
    "path": "docs/pt/docs/advanced/templates.md",
    "content": "# Templates { #templates }\n\nVocê pode usar qualquer template engine com o **FastAPI**.\n\nUma escolha comum é o Jinja2, o mesmo usado pelo Flask e outras ferramentas.\n\nExistem utilitários para configurá-lo facilmente que você pode usar diretamente em sua aplicação **FastAPI** (fornecidos pelo Starlette).\n\n## Instalar dependências { #install-dependencies }\n\nCertifique-se de criar um [ambiente virtual](../virtual-environments.md), ativá-lo e instalar `jinja2`:\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## Usando `Jinja2Templates` { #using-jinja2templates }\n\n* Importe `Jinja2Templates`.\n* Crie um objeto `templates` que você possa reutilizar posteriormente.\n* Declare um parâmetro `Request` no *path operation* que retornará um template.\n* Use o `templates` que você criou para renderizar e retornar uma `TemplateResponse`, passe o nome do template, o objeto `request` e um dicionário \"context\" com pares chave-valor a serem usados dentro do template do Jinja2.\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note | Nota\n\nAntes do FastAPI 0.108.0, Starlette 0.29.0, `name` era o primeiro parâmetro.\n\nAlém disso, em versões anteriores, o objeto `request` era passado como parte dos pares chave-valor no \"context\" dict para o Jinja2.\n\n///\n\n/// tip | Dica\n\nAo declarar `response_class=HTMLResponse`, a documentação entenderá que a resposta será HTML.\n\n///\n\n/// note | Detalhes Técnicos\n\nVocê também poderia usar `from starlette.templating import Jinja2Templates`.\n\n**FastAPI** fornece o mesmo `starlette.templating` como `fastapi.templating` apenas como uma conveniência para você, o desenvolvedor. Mas a maioria das respostas disponíveis vêm diretamente do Starlette. O mesmo acontece com `Request` e `StaticFiles`.\n\n///\n\n## Escrevendo templates { #writing-templates }\n\nEntão você pode escrever um template em `templates/item.html`, por exemplo:\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### Valores de contexto do template { #template-context-values }\n\nNo código HTML que contém:\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n...aparecerá o `id` obtido do \"context\" `dict` que você passou:\n\n```Python\n{\"id\": id}\n```\n\nPor exemplo, dado um ID de valor `42`, aparecerá:\n\n```html\nItem ID: 42\n```\n\n### Argumentos do `url_for` no template { #template-url-for-arguments }\n\nVocê também pode usar `url_for()` dentro do template, ele recebe como argumentos os mesmos argumentos que seriam usados pela sua *path operation function*.\n\nLogo, a seção com:\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n...irá gerar um link para a mesma URL que será tratada pela *path operation function* `read_item(id=id)`.\n\nPor exemplo, com um ID de `42`, isso renderizará:\n\n```html\n<a href=\"/items/42\">\n```\n\n## Templates e arquivos estáticos { #templates-and-static-files }\n\nVocê também pode usar `url_for()` dentro do template e usá-lo, por exemplo, com o `StaticFiles` que você montou com o `name=\"static\"`.\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\nNeste exemplo, ele seria vinculado a um arquivo CSS em `static/styles.css` com:\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\nE como você está usando `StaticFiles`, este arquivo CSS será automaticamente servido pela sua aplicação **FastAPI** na URL `/static/styles.css`.\n\n## Mais detalhes { #more-details }\n\nPara obter mais detalhes, incluindo como testar templates, consulte a [documentação da Starlette sobre templates](https://www.starlette.dev/templates/).\n"
  },
  {
    "path": "docs/pt/docs/advanced/testing-dependencies.md",
    "content": "# Testando Dependências com Sobreposições { #testing-dependencies-with-overrides }\n\n## Sobrepondo dependências durante os testes { #overriding-dependencies-during-testing }\n\nExistem alguns cenários onde você deseje sobrepor uma dependência durante os testes.\n\nVocê não quer que a dependência original execute (e nenhuma das subdependências que você possa ter).\n\nEm vez disso, você deseja fornecer uma dependência diferente que será usada somente durante os testes (possivelmente apenas para alguns testes específicos) e fornecerá um valor que pode ser usado onde o valor da dependência original foi usado.\n\n### Casos de uso: serviço externo { #use-cases-external-service }\n\nUm exemplo pode ser que você possua um provedor de autenticação externo que você precisa chamar.\n\nVocê envia ao serviço um *token* e ele retorna um usuário autenticado.\n\nEste provedor pode cobrar por requisição, e chamá-lo pode levar mais tempo do que se você tivesse um usuário fixo para os testes.\n\nVocê provavelmente quer testar o provedor externo uma vez, mas não necessariamente chamá-lo em todos os testes que executarem.\n\nNeste caso, você pode sobrepor (*override*) a dependência que chama o provedor, e utilizar uma dependência customizada que retorna um *mock* do usuário, apenas para os seus testes.\n\n### Utilize o atributo `app.dependency_overrides` { #use-the-app-dependency-overrides-attribute }\n\nPara estes casos, a sua aplicação **FastAPI** possui o atributo `app.dependency_overrides`. Ele é um simples `dict`.\n\nPara sobrepor a dependência para os testes, você coloca como chave a dependência original (a função), e como valor, a sua sobreposição da dependência (outra função).\n\nE então o **FastAPI** chamará a sobreposição no lugar da dependência original.\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip | Dica\n\nVocê pode definir uma sobreposição de dependência para uma dependência que é utilizada em qualquer lugar da sua aplicação **FastAPI**.\n\nA dependência original pode estar sendo utilizada em uma *função de operação de rota*, um *decorador de operação de rota* (quando você não utiliza o valor retornado), uma chamada ao `.include_router()`, etc.\n\nO FastAPI ainda poderá sobrescrevê-la.\n\n///\n\nE então você pode redefinir as suas sobreposições (removê-las) definindo o `app.dependency_overrides` como um `dict` vazio:\n\n```Python\napp.dependency_overrides = {}\n```\n\n\n/// tip | Dica\n\nSe você quer sobrepor uma dependência apenas para alguns testes, você pode definir a sobreposição no início do teste (dentro da função de teste) e reiniciá-la ao final (no final da função de teste).\n\n///\n"
  },
  {
    "path": "docs/pt/docs/advanced/testing-events.md",
    "content": "# Testando eventos: lifespan e inicialização - encerramento { #testing-events-lifespan-and-startup-shutdown }\n\nQuando você precisa que o `lifespan` seja executado em seus testes, você pode utilizar o `TestClient` com a instrução `with`:\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\nVocê pode ler mais detalhes sobre o [\"Executando lifespan em testes no site oficial da documentação do Starlette.\"](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)\n\nPara os eventos `startup` e `shutdown` descontinuados, você pode usar o `TestClient` da seguinte forma:\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/pt/docs/advanced/testing-websockets.md",
    "content": "# Testando WebSockets { #testing-websockets }\n\nVocê pode usar o mesmo `TestClient` para testar WebSockets.\n\nPara isso, você utiliza o `TestClient` dentro de uma instrução `with`, conectando com o WebSocket:\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note | Nota\n\nPara mais detalhes, confira a documentação do Starlette para [testar WebSockets](https://www.starlette.dev/testclient/#testing-websocket-sessions).\n\n///\n"
  },
  {
    "path": "docs/pt/docs/advanced/using-request-directly.md",
    "content": "# Utilizando o Request diretamente { #using-the-request-directly }\n\nAté agora você declarou as partes da requisição que você precisa utilizando os seus tipos.\n\nObtendo dados de:\n\n* O path como parâmetros.\n* Cabeçalhos.\n* Cookies.\n* etc.\n\nE ao fazer isso, o **FastAPI** está validando as informações, convertendo-as e gerando documentação para a sua API automaticamente.\n\nPorém há situações em que você possa precisar acessar o objeto `Request` diretamente.\n\n## Detalhes sobre o objeto `Request` { #details-about-the-request-object }\n\nComo o **FastAPI** é na verdade o **Starlette** por baixo, com camadas de diversas funcionalidades por cima, você pode utilizar o objeto [`Request`](https://www.starlette.dev/requests/) do Starlette diretamente quando precisar.\n\nIsso significaria também que se você obtiver informações do objeto `Request` diretamente (ler o corpo da requisição por exemplo), as informações não serão validadas, convertidas ou documentadas (com o OpenAPI, para a interface de usuário automática da API) pelo FastAPI.\n\nEmbora qualquer outro parâmetro declarado normalmente (o corpo da requisição com um modelo Pydantic, por exemplo) ainda seria validado, convertido, anotado, etc.\n\nMas há situações específicas onde é útil utilizar o objeto `Request`.\n\n## Utilize o objeto `Request` diretamente { #use-the-request-object-directly }\n\nVamos imaginar que você deseja obter o endereço de IP/host do cliente dentro da sua *função de operação de rota*.\n\nPara isso você precisa acessar a requisição diretamente.\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\nAo declarar o parâmetro com o tipo sendo um `Request` em sua *função de operação de rota*, o **FastAPI** saberá como passar o `Request` neste parâmetro.\n\n/// tip | Dica\n\nNote que neste caso, nós estamos declarando o parâmetro de path ao lado do parâmetro da requisição.\n\nAssim, o parâmetro de path será extraído, validado, convertido para o tipo especificado e anotado com OpenAPI.\n\nDo mesmo jeito, você pode declarar qualquer outro parâmetro normalmente, e além disso, obter o `Request` também.\n\n///\n\n## Documentação do `Request` { #request-documentation }\n\nVocê pode ler mais sobre os detalhes do [objeto `Request` no site da documentação oficial do Starlette](https://www.starlette.dev/requests/).\n\n/// note | Detalhes Técnicos\n\nVocê também pode utilizar `from starlette.requests import Request`.\n\nO **FastAPI** fornece isso diretamente apenas como uma conveniência para você, o desenvolvedor. Mas ele vem diretamente do Starlette.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\nVocê pode usar [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) com **FastAPI**.\n\n## Instale `websockets` { #install-websockets }\n\nGaranta que você criou um [ambiente virtual](../virtual-environments.md), o ativou e instalou o `websockets` (uma biblioteca Python que facilita o uso do protocolo \"WebSocket\"):\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## Cliente WebSockets { #websockets-client }\n\n### Em produção { #in-production }\n\nEm seu sistema de produção, você provavelmente tem um frontend criado com um framework moderno como React, Vue.js ou Angular.\n\nE para comunicar usando WebSockets com seu backend, você provavelmente usaria as utilidades do seu frontend.\n\nOu você pode ter um aplicativo móvel nativo que se comunica diretamente com seu backend WebSocket, em código nativo.\n\nOu você pode ter qualquer outra forma de comunicar com o endpoint WebSocket.\n\n---\n\nMas para este exemplo, usaremos um documento HTML muito simples com algum JavaScript, tudo dentro de uma string longa.\n\nEsse, é claro, não é o ideal e você não o usaria para produção.\n\nNa produção, você teria uma das opções acima.\n\nMas é a maneira mais simples de focar no lado do servidor de WebSockets e ter um exemplo funcional:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## Crie um `websocket` { #create-a-websocket }\n\nEm sua aplicação **FastAPI**, crie um `websocket`:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | Detalhes Técnicos\n\nVocê também poderia usar `from starlette.websockets import WebSocket`.\n\nA **FastAPI** fornece o mesmo `WebSocket` diretamente apenas como uma conveniência para você, o desenvolvedor. Mas ele vem diretamente do Starlette.\n\n///\n\n## Aguarde mensagens e envie mensagens { #await-for-messages-and-send-messages }\n\nEm sua rota WebSocket você pode esperar (`await`) por mensagens e enviar mensagens.\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\nVocê pode receber e enviar dados binários, de texto e JSON.\n\n## Tente { #try-it }\n\nColoque seu código em um arquivo `main.py` e então execute sua aplicação:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nAbra seu navegador em: [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nVocê verá uma página simples como:\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\nVocê pode digitar mensagens na caixa de entrada e enviá-las:\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\nE sua aplicação **FastAPI** com WebSockets responderá de volta:\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\nVocê pode enviar (e receber) muitas mensagens:\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\nE todas elas usarão a mesma conexão WebSocket.\n\n## Usando `Depends` e outros { #using-depends-and-others }\n\nNos endpoints WebSocket você pode importar do `fastapi` e usar:\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\nEles funcionam da mesma forma que para outros endpoints FastAPI/*operações de rota*:\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info | Informação\n\nComo isso é um WebSocket, não faz muito sentido levantar uma `HTTPException`, em vez disso levantamos uma `WebSocketException`.\n\nVocê pode usar um código de fechamento dos [códigos válidos definidos na especificação](https://tools.ietf.org/html/rfc6455#section-7.4.1).\n\n///\n\n### Tente os WebSockets com dependências { #try-the-websockets-with-dependencies }\n\nExecute sua aplicação:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nAbra seu navegador em: [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nLá você pode definir:\n\n* O \"Item ID\", usado no path.\n* O \"Token\" usado como um parâmetro de consulta.\n\n/// tip | Dica\n\nPerceba que a consulta `token` será manipulada por uma dependência.\n\n///\n\nCom isso você pode conectar o WebSocket e então enviar e receber mensagens:\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## Lidando com desconexões e múltiplos clientes { #handling-disconnections-and-multiple-clients }\n\nQuando uma conexão WebSocket é fechada, o `await websocket.receive_text()` levantará uma exceção `WebSocketDisconnect`, que você pode então capturar e lidar como neste exemplo.\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\nPara testar:\n\n* Abra o aplicativo com várias abas do navegador.\n* Escreva mensagens a partir delas.\n* Então feche uma das abas.\n\nIsso levantará a exceção `WebSocketDisconnect`, e todos os outros clientes receberão uma mensagem como:\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip | Dica\n\nO app acima é um exemplo mínimo e simples para demonstrar como lidar e transmitir mensagens para várias conexões WebSocket.\n\nMas tenha em mente que, como tudo é manipulado na memória, em uma única list, ele só funcionará enquanto o processo estiver em execução e só funcionará com um único processo.\n\nSe você precisa de algo fácil de integrar com o FastAPI, mas que seja mais robusto, suportado por Redis, PostgreSQL ou outros, verifique [encode/broadcaster](https://github.com/encode/broadcaster).\n\n///\n\n## Mais informações { #more-info }\n\nPara aprender mais sobre as opções, verifique a documentação do Starlette para:\n\n* [A classe `WebSocket`](https://www.starlette.dev/websockets/).\n* [Manipulação de WebSockets baseada em classes](https://www.starlette.dev/endpoints/#websocketendpoint).\n"
  },
  {
    "path": "docs/pt/docs/advanced/wsgi.md",
    "content": "# Adicionando WSGI - Flask, Django, entre outros { #including-wsgi-flask-django-others }\n\nComo você viu em [Subaplicações - Montagens](sub-applications.md) e [Atrás de um Proxy](behind-a-proxy.md), você pode montar aplicações WSGI.\n\nPara isso, você pode utilizar o `WSGIMiddleware` para encapsular a sua aplicação WSGI, como por exemplo Flask, Django, etc.\n\n## Usando `WSGIMiddleware` { #using-wsgimiddleware }\n\n/// info | Informação\n\nIsso requer instalar `a2wsgi`, por exemplo com `pip install a2wsgi`.\n\n///\n\nVocê precisa importar o `WSGIMiddleware` de `a2wsgi`.\n\nEm seguida, encapsule a aplicação WSGI (e.g. Flask) com o middleware.\n\nE então monte isso sob um path.\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note | Nota\n\nAnteriormente, recomendava-se usar `WSGIMiddleware` de `fastapi.middleware.wsgi`, mas agora está descontinuado.\n\nÉ aconselhável usar o pacote `a2wsgi` em seu lugar. O uso permanece o mesmo.\n\nApenas certifique-se de que o pacote `a2wsgi` está instalado e importe `WSGIMiddleware` corretamente de `a2wsgi`.\n\n///\n\n## Confira { #check-it }\n\nAgora, todas as requisições sob o path `/v1/` serão manipuladas pela aplicação Flask.\n\nE o resto será manipulado pelo **FastAPI**.\n\nSe você rodar a aplicação e ir até [http://localhost:8000/v1/](http://localhost:8000/v1/), você verá o retorno do Flask:\n\n```txt\nHello, World from Flask!\n```\n\nE se você for até [http://localhost:8000/v2](http://localhost:8000/v2), você verá o retorno do FastAPI:\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/pt/docs/alternatives.md",
    "content": "# Alternativas, Inspiração e Comparações { #alternatives-inspiration-and-comparisons }\n\nO que inspirou o **FastAPI**, como ele se compara às alternativas e o que ele aprendeu com elas.\n\n## Introdução { #intro }\n\n**FastAPI** não existiria se não fosse pelo trabalho anterior de outras pessoas.\n\nHouve muitas ferramentas criadas antes que ajudaram a inspirar sua criação.\n\nTenho evitado criar um novo framework por vários anos. Primeiro tentei resolver todas as funcionalidades cobertas pelo **FastAPI** utilizando muitos frameworks, plug-ins e ferramentas diferentes.\n\nMas em algum momento, não havia outra opção senão criar algo que fornecesse todos esses recursos, pegando as melhores ideias de ferramentas anteriores e combinando-as da melhor maneira possível, usando funcionalidades da linguagem que nem sequer estavam disponíveis antes (anotações de tipo no Python 3.6+).\n\n## Ferramentas anteriores { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\nÉ o framework Python mais popular e amplamente confiável. É utilizado para construir sistemas como o Instagram.\n\nÉ relativamente bem acoplado com bancos de dados relacionais (como MySQL ou PostgreSQL), então, ter um banco de dados NoSQL (como Couchbase, MongoDB, Cassandra, etc.) como mecanismo principal de armazenamento não é muito fácil.\n\nFoi criado para gerar o HTML no backend, não para criar APIs usadas por um frontend moderno (como React, Vue.js e Angular) ou por outros sistemas (como dispositivos <abbr title=\"Internet of Things - Internet das Coisas\">IoT</abbr>) comunicando com ele.\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nDjango REST framework foi criado para ser uma caixa de ferramentas flexível para construção de APIs Web utilizando Django por baixo, para melhorar suas capacidades de API.\n\nEle é utilizado por muitas empresas incluindo Mozilla, Red Hat e Eventbrite.\n\nFoi um dos primeiros exemplos de **documentação automática de API**, e essa foi especificamente uma das primeiras ideias que inspirou \"a busca por\" **FastAPI**.\n\n/// note | Nota\n\nDjango REST Framework foi criado por Tom Christie. O mesmo criador de Starlette e Uvicorn, nos quais **FastAPI** é baseado.\n\n///\n\n/// check | Inspirou o **FastAPI** a\n\nTer uma interface web de documentação automática da API.\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask é um \"microframework\", não inclui integrações com banco de dados nem muitas das coisas que vêm por padrão no Django.\n\nEssa simplicidade e flexibilidade permitem fazer coisas como utilizar bancos de dados NoSQL como o principal sistema de armazenamento de dados.\n\nPor ser muito simples, é relativamente intuitivo de aprender, embora a documentação se torne um pouco técnica em alguns pontos.\n\nEle também é comumente utilizado por outras aplicações que não necessariamente precisam de banco de dados, gerenciamento de usuários, ou qualquer uma das muitas funcionalidades que já vêm prontas no Django. Embora muitas dessas funcionalidades possam ser adicionadas com plug-ins.\n\nEsse desacoplamento de partes, e ser um \"microframework\" que pode ser estendido para cobrir exatamente o que é necessário era uma funcionalidade chave que eu queria manter.\n\nDada a simplicidade do Flask, ele parecia uma boa opção para construção de APIs. A próxima coisa a encontrar era um \"Django REST Framework\" para Flask.\n\n/// check | Inspirou o **FastAPI** a\n\nSer um microframework. Tornar fácil misturar e combinar as ferramentas e partes necessárias.\n\nTer um sistema de roteamento simples e fácil de usar.\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI** na verdade não é uma alternativa ao **Requests**. O escopo deles é muito diferente.\n\nNa verdade, é comum utilizar Requests dentro de uma aplicação FastAPI.\n\nAinda assim, o FastAPI tirou bastante inspiração do Requests.\n\n**Requests** é uma biblioteca para interagir com APIs (como um cliente), enquanto **FastAPI** é uma biblioteca para construir APIs (como um servidor).\n\nEles estão, mais ou menos, em pontas opostas, complementando-se.\n\nRequests tem um design muito simples e intuitivo, é muito fácil de usar, com padrões sensatos. Mas ao mesmo tempo, é muito poderoso e personalizável.\n\nÉ por isso que, como dito no site oficial:\n\n> Requests é um dos pacotes Python mais baixados de todos os tempos\n\nO jeito de usar é muito simples. Por exemplo, para fazer uma requisição `GET`, você escreveria:\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\nA contra-parte na aplicação FastAPI, a operação de rota, poderia ficar assim:\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\nVeja as similaridades em `requests.get(...)` e `@app.get(...)`.\n\n/// check | Inspirou o **FastAPI** a\n\n* Ter uma API simples e intuitiva.\n* Utilizar nomes de métodos HTTP (operações) diretamente, de um jeito direto e intuitivo.\n* Ter padrões sensatos, mas customizações poderosas.\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\nA principal funcionalidade que eu queria do Django REST Framework era a documentação automática da API.\n\nEntão descobri que existia um padrão para documentar APIs, utilizando JSON (ou YAML, uma extensão do JSON) chamado Swagger.\n\nE havia uma interface web para APIs Swagger já criada. Então, ser capaz de gerar documentação Swagger para uma API permitiria usar essa interface web automaticamente.\n\nEm algum ponto, Swagger foi doado para a Fundação Linux, para ser renomeado OpenAPI.\n\nÉ por isso que ao falar sobre a versão 2.0 é comum dizer \"Swagger\", e para a versão 3+ \"OpenAPI\".\n\n/// check | Inspirou o **FastAPI** a\n\nAdotar e usar um padrão aberto para especificações de API, em vez de um schema personalizado.\n\nE integrar ferramentas de interface para usuários baseadas nos padrões:\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\nEssas duas foram escolhidas por serem bem populares e estáveis, mas fazendo uma pesquisa rápida, você pode encontrar dúzias de interfaces alternativas adicionais para OpenAPI (que você pode utilizar com **FastAPI**).\n\n///\n\n### Flask REST frameworks { #flask-rest-frameworks }\n\nExistem vários Flask REST frameworks, mas depois de investir tempo e trabalho investigando-os, descobri que muitos estão descontinuados ou abandonados, com diversas questões em aberto que os tornaram inadequados.\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nUma das principais funcionalidades necessárias em sistemas de API é a \"<dfn title=\"também chamado: marshalling, conversão\">serialização</dfn>\" de dados, que é pegar dados do código (Python) e convertê-los em algo que possa ser enviado pela rede. Por exemplo, converter um objeto contendo dados de um banco de dados em um objeto JSON. Converter objetos `datetime` em strings, etc.\n\nOutra grande funcionalidade necessária pelas APIs é a validação de dados, garantindo que os dados são válidos, dados certos parâmetros. Por exemplo, que algum campo seja `int`, e não alguma string aleatória. Isso é especialmente útil para dados de entrada.\n\nSem um sistema de validação de dados, você teria que realizar todas as verificações manualmente, no código.\n\nEssas funcionalidades são o que o Marshmallow foi construído para fornecer. É uma ótima biblioteca, e eu a utilizei bastante antes.\n\nMas ele foi criado antes de existirem as anotações de tipo do Python. Então, para definir cada <dfn title=\"a definição de como os dados devem ser formados\">schema</dfn> você precisa utilizar utilitários e classes específicos fornecidos pelo Marshmallow.\n\n/// check | Inspirou o **FastAPI** a\n\nUsar código para definir \"schemas\" que forneçam, automaticamente, tipos de dados e validação.\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nOutra grande funcionalidade requerida pelas APIs é o <dfn title=\"ler e converter para dados do Python\">parsing</dfn> de dados vindos de requisições de entrada.\n\nWebargs é uma ferramenta feita para fornecer isso no topo de vários frameworks, inclusive Flask.\n\nEle utiliza Marshmallow por baixo para a validação de dados. E foi criado pelos mesmos desenvolvedores.\n\nÉ uma grande ferramenta e eu também a utilizei bastante, antes de ter o **FastAPI**.\n\n/// info | Informação\n\nWebargs foi criado pelos mesmos desenvolvedores do Marshmallow.\n\n///\n\n/// check | Inspirou o **FastAPI** a\n\nTer validação automática dos dados de requisições de entrada.\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow e Webargs fornecem validação, parsing e serialização como plug-ins.\n\nMas a documentação ainda estava faltando. Então APISpec foi criado.\n\nÉ um plug-in para muitos frameworks (e há um plug-in para Starlette também).\n\nO jeito como ele funciona é que você escreve a definição do schema usando formato YAML dentro da docstring de cada função que lida com uma rota.\n\nE ele gera schemas OpenAPI.\n\nÉ assim como funciona no Flask, Starlette, Responder, etc.\n\nMas então, temos novamente o problema de ter uma micro-sintaxe, dentro de uma string Python (um grande YAML).\n\nO editor não pode ajudar muito com isso. E se modificarmos parâmetros ou schemas do Marshmallow e esquecermos de também modificar aquela docstring em YAML, o schema gerado ficaria obsoleto.\n\n/// info | Informação\n\nAPISpec foi criado pelos mesmos desenvolvedores do Marshmallow.\n\n///\n\n/// check | Inspirou o **FastAPI** a\n\nDar suporte ao padrão aberto para APIs, OpenAPI.\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\nÉ um plug-in Flask, que amarra juntos Webargs, Marshmallow e APISpec.\n\nEle utiliza a informação do Webargs e Marshmallow para gerar automaticamente schemas OpenAPI, usando APISpec.\n\nÉ uma grande ferramenta, muito subestimada. Deveria ser bem mais popular do que muitos plug-ins Flask por aí. Pode ser devido à sua documentação ser concisa e abstrata demais.\n\nIsso resolveu ter que escrever YAML (outra sintaxe) dentro das docstrings do Python.\n\nEssa combinação de Flask, Flask-apispec com Marshmallow e Webargs foi a minha stack de backend favorita até construir o **FastAPI**.\n\nUsá-la levou à criação de vários geradores Flask full-stack. Estas são as principais stacks que eu (e várias equipes externas) tenho utilizado até agora:\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\nE esses mesmos geradores full-stack foram a base dos [Geradores de Projetos **FastAPI**](project-generation.md).\n\n/// info | Informação\n\nFlask-apispec foi criado pelos mesmos desenvolvedores do Marshmallow.\n\n///\n\n/// check | Inspirou o **FastAPI** a\n\nGerar o schema OpenAPI automaticamente, a partir do mesmo código que define serialização e validação.\n\n///\n\n### [NestJS](https://nestjs.com/) (e [Angular](https://angular.io/)) { #nestjs-and-angular }\n\nIsso nem é Python, NestJS é um framework NodeJS em JavaScript (TypeScript) inspirado pelo Angular.\n\nEle alcança algo um tanto similar ao que pode ser feito com Flask-apispec.\n\nEle tem um sistema de injeção de dependência integrado, inspirado pelo Angular 2. É necessário fazer o pré-registro dos \"injetáveis\" (como todos os sistemas de injeção de dependência que conheço), então, adiciona verbosidade e repetição de código.\n\nComo os parâmetros são descritos com tipos do TypeScript (similares às anotações de tipo do Python), o suporte do editor é muito bom.\n\nMas como os dados do TypeScript não são preservados após a compilação para JavaScript, ele não pode depender dos tipos para definir validação, serialização e documentação ao mesmo tempo. Devido a isso e a algumas decisões de projeto, para obter validação, serialização e geração automática de schema, é necessário adicionar decorators em muitos lugares. Então, ele se torna bastante verboso.\n\nEle não consegue lidar muito bem com modelos aninhados. Então, se o corpo JSON na requisição for um objeto JSON que contém campos internos que por sua vez são objetos JSON aninhados, ele não consegue ser documentado e validado apropriadamente.\n\n/// check | Inspirou o **FastAPI** a\n\nUsar tipos do Python para ter um ótimo suporte do editor.\n\nTer um sistema de injeção de dependência poderoso. Encontrar um jeito de minimizar repetição de código.\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\nEle foi um dos primeiros frameworks Python extremamente rápidos baseados em `asyncio`. Ele foi feito para ser muito similar ao Flask.\n\n/// note | Detalhes Técnicos\n\nEle utilizava [`uvloop`](https://github.com/MagicStack/uvloop) em vez do loop `asyncio` padrão do Python. É isso que o deixava tão rápido.\n\nEle claramente inspirou Uvicorn e Starlette, que atualmente são mais rápidos que o Sanic em benchmarks abertos.\n\n///\n\n/// check | Inspirou o **FastAPI** a\n\nEncontrar um jeito de ter uma performance insana.\n\nÉ por isso que o **FastAPI** é baseado em Starlette, pois ela é o framework mais rápido disponível (testado por benchmarks de terceiros).\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon é outro framework Python de alta performance, projetado para ser minimalista, e servir como base para outros frameworks como Hug.\n\nEle é projetado para ter funções que recebem dois parâmetros, uma \"request\" e uma \"response\". Então você \"lê\" partes da requisição, e \"escreve\" partes para a resposta. Por causa desse design, não é possível declarar parâmetros de requisição e corpos com as anotações de tipo padrão do Python como parâmetros de função.\n\nEntão, validação de dados, serialização e documentação têm que ser feitos no código, não automaticamente. Ou eles têm que ser implementados como um framework acima do Falcon, como o Hug. Essa mesma distinção acontece em outros frameworks inspirados pelo design do Falcon, de ter um objeto de request e um objeto de response como parâmetros.\n\n/// check | Inspirou o **FastAPI** a\n\nEncontrar maneiras de obter uma ótima performance.\n\nJuntamente com Hug (como Hug é baseado no Falcon) inspirou **FastAPI** a declarar um parâmetro de `response` nas funções.\n\nEmbora no FastAPI seja opcional, é utilizado principalmente para configurar cabeçalhos, cookies e códigos de status alternativos.\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\nEu descobri Molten nos primeiros estágios da construção do **FastAPI**. E ele tem ideias bastante similares:\n\n* Baseado nas anotações de tipo do Python.\n* Validação e documentação a partir desses tipos.\n* Sistema de Injeção de Dependência.\n\nEle não utiliza uma biblioteca de terceiros para validação de dados, serialização e documentação como o Pydantic, ele tem a sua própria. Então, essas definições de tipos de dados não seriam reutilizáveis tão facilmente.\n\nEle exige configurações um pouco mais verbosas. E como é baseado em WSGI (em vez de ASGI), ele não é projetado para tirar vantagem da alta performance fornecida por ferramentas como Uvicorn, Starlette e Sanic.\n\nO sistema de injeção de dependência exige pré-registro das dependências e elas são resolvidas com base nos tipos declarados. Então, não é possível declarar mais de um \"componente\" que forneça um certo tipo.\n\nAs rotas são declaradas em um único lugar, usando funções declaradas em outros lugares (em vez de usar decorators que possam ser colocados diretamente acima da função que lida com o endpoint). Isso é mais próximo de como o Django faz do que de como o Flask (e o Starlette) fazem. Separa no código coisas que são relativamente bem acopladas.\n\n/// check | Inspirou o **FastAPI** a\n\nDefinir validações extras para tipos de dados usando o valor \"padrão\" de atributos dos modelos. Isso melhora o suporte do editor, e não estava disponível no Pydantic antes.\n\nIsso na verdade inspirou a atualização de partes do Pydantic, para dar suporte ao mesmo estilo de declaração da validação (toda essa funcionalidade já está disponível no Pydantic).\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug foi um dos primeiros frameworks a implementar a declaração de tipos de parâmetros de API usando anotações de tipo do Python. Isso foi uma ótima ideia que inspirou outras ferramentas a fazer o mesmo.\n\nEle usou tipos personalizados em suas declarações em vez dos tipos padrão do Python, mas mesmo assim foi um grande passo adiante.\n\nEle também foi um dos primeiros frameworks a gerar um schema personalizado declarando a API inteira em JSON.\n\nEle não era baseado em um padrão como OpenAPI e JSON Schema. Então não seria simples integrá-lo com outras ferramentas, como Swagger UI. Mas novamente, era uma ideia muito inovadora.\n\nEle tem um recurso interessante e incomum: usando o mesmo framework, é possível criar APIs e também CLIs.\n\nComo é baseado no padrão anterior para frameworks web Python síncronos (WSGI), ele não consegue lidar com Websockets e outras coisas, embora ainda tenha alta performance também.\n\n/// info | Informação\n\nHug foi criado por Timothy Crosley, o mesmo criador do [`isort`](https://github.com/timothycrosley/isort), uma ótima ferramenta para ordenar automaticamente imports em arquivos Python.\n\n///\n\n/// check | Ideias que inspiraram o **FastAPI**\n\nHug inspirou partes do APIStar, e foi uma das ferramentas que achei mais promissoras, ao lado do APIStar.\n\nHug ajudou a inspirar o **FastAPI** a usar anotações de tipo do Python para declarar parâmetros e para gerar um schema definindo a API automaticamente.\n\nHug inspirou **FastAPI** a declarar um parâmetro de `response` em funções para definir cabeçalhos e cookies.\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0.5) { #apistar-0-5 }\n\nPouco antes de decidir construir o **FastAPI** eu encontrei o servidor **APIStar**. Ele tinha quase tudo o que eu estava procurando e tinha um ótimo design.\n\nFoi uma das primeiras implementações de um framework usando anotações de tipo do Python para declarar parâmetros e requisições que eu já vi (antes do NestJS e Molten). Eu o encontrei mais ou menos na mesma época que o Hug. Mas o APIStar utilizava o padrão OpenAPI.\n\nEle tinha validação de dados automática, serialização de dados e geração de schema OpenAPI baseadas nas mesmas anotações de tipo em vários locais.\n\nAs definições de schema de corpo não utilizavam as mesmas anotações de tipo do Python como o Pydantic, eram um pouco mais similares ao Marshmallow, então o suporte do editor não seria tão bom, ainda assim, APIStar era a melhor opção disponível.\n\nEle obteve os melhores benchmarks de performance na época (somente ultrapassado por Starlette).\n\nA princípio, ele não tinha uma interface web com documentação automática da API, mas eu sabia que poderia adicionar o Swagger UI a ele.\n\nEle tinha um sistema de injeção de dependência. Exigia pré-registro dos componentes, como outras ferramentas já discutidas acima. Mas ainda assim era um grande recurso.\n\nEu nunca fui capaz de usá-lo em um projeto completo, pois ele não tinha integração de segurança, então, eu não pude substituir todos os recursos que eu tinha com os geradores full-stack baseados no Flask-apispec. Eu tinha no meu backlog de projetos criar um pull request adicionando essa funcionalidade.\n\nMas então, o foco do projeto mudou.\n\nEle não era mais um framework web de API, pois o criador precisava focar no Starlette.\n\nAgora APIStar é um conjunto de ferramentas para validar especificações OpenAPI, não um framework web.\n\n/// info | Informação\n\nAPIStar foi criado por Tom Christie. O mesmo cara que criou:\n\n* Django REST Framework\n* Starlette (no qual **FastAPI** é baseado)\n* Uvicorn (usado por Starlette e **FastAPI**)\n\n///\n\n/// check | Inspirou o **FastAPI** a\n\nExistir.\n\nA ideia de declarar múltiplas coisas (validação de dados, serialização e documentação) com os mesmos tipos do Python, que ao mesmo tempo fornecessem grande suporte ao editor, era algo que eu considerava uma ideia brilhante.\n\nE após procurar por muito tempo por um framework similar e testar muitas alternativas diferentes, APIStar foi a melhor opção disponível.\n\nEntão APIStar deixou de existir como servidor e o Starlette foi criado, sendo uma nova e melhor fundação para tal sistema. Essa foi a inspiração final para construir o **FastAPI**.\n\nEu considero o **FastAPI** um \"sucessor espiritual\" do APIStar, enquanto aprimora e amplia as funcionalidades, o sistema de tipagem e outras partes, baseado nos aprendizados de todas essas ferramentas anteriores.\n\n///\n\n## Usados por **FastAPI** { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic é uma biblioteca para definir validação de dados, serialização e documentação (usando JSON Schema) com base nas anotações de tipo do Python.\n\nIsso o torna extremamente intuitivo.\n\nEle é comparável ao Marshmallow. Embora seja mais rápido que o Marshmallow em benchmarks. E como é baseado nas mesmas anotações de tipo do Python, o suporte do editor é ótimo.\n\n/// check | **FastAPI** usa isso para\n\nControlar toda a validação de dados, serialização de dados e documentação automática de modelos (baseada no JSON Schema).\n\n**FastAPI** então pega esses dados do JSON Schema e os coloca no OpenAPI, além de todas as outras coisas que faz.\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette é um framework/caixa de ferramentas <dfn title=\"O novo padrão para construir aplicações web Python assíncronas\">ASGI</dfn> leve, o que é ideal para construir serviços asyncio de alta performance.\n\nEle é muito simples e intuitivo. É projetado para ser facilmente extensível, e ter componentes modulares.\n\nEle tem:\n\n* Performance seriamente impressionante.\n* Suporte a WebSocket.\n* Tarefas em segundo plano dentro do processo.\n* Eventos de inicialização e encerramento.\n* Cliente de testes construído com HTTPX.\n* CORS, GZip, Arquivos Estáticos, respostas Streaming.\n* Suporte para Sessão e Cookie.\n* 100% coberto por testes.\n* Código base 100% anotado com tipagem.\n* Poucas dependências obrigatórias.\n\nStarlette é atualmente o framework Python mais rápido testado. Somente ultrapassado pelo Uvicorn, que não é um framework, mas um servidor.\n\nStarlette fornece toda a funcionalidade básica de um microframework web.\n\nMas ele não fornece validação de dados automática, serialização ou documentação.\n\nEssa é uma das principais coisas que o **FastAPI** adiciona por cima, tudo baseado nas anotações de tipo do Python (usando Pydantic). Isso, mais o sistema de injeção de dependência, utilidades de segurança, geração de schema OpenAPI, etc.\n\n/// note | Detalhes Técnicos\n\nASGI é um novo \"padrão\" sendo desenvolvido por membros do time central do Django. Ele ainda não é um \"padrão Python\" (uma PEP), embora eles estejam no processo de fazer isso.\n\nNo entanto, ele já está sendo utilizado como \"padrão\" por diversas ferramentas. Isso melhora enormemente a interoperabilidade, pois você poderia trocar Uvicorn por qualquer outro servidor ASGI (como Daphne ou Hypercorn), ou você poderia adicionar ferramentas compatíveis com ASGI, como `python-socketio`.\n\n///\n\n/// check | **FastAPI** usa isso para\n\nControlar todas as partes web centrais. Adiciona funcionalidades por cima.\n\nA classe `FastAPI` em si herda diretamente da classe `Starlette`.\n\nEntão, qualquer coisa que você pode fazer com Starlette, você pode fazer diretamente com o **FastAPI**, pois ele é basicamente um Starlette com esteróides.\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn é um servidor ASGI extremamente rápido, construído com uvloop e httptools.\n\nEle não é um framework web, mas sim um servidor. Por exemplo, ele não fornece ferramentas para roteamento por paths. Isso é algo que um framework como Starlette (ou **FastAPI**) forneceria por cima.\n\nEle é o servidor recomendado para Starlette e **FastAPI**.\n\n/// check | **FastAPI** o recomenda como\n\nO principal servidor web para rodar aplicações **FastAPI**.\n\nVocê também pode usar a opção de linha de comando `--workers` para ter um servidor assíncrono multi-processos.\n\nVerifique mais detalhes na seção [Implantação](deployment/index.md).\n\n///\n\n## Benchmarks e velocidade { #benchmarks-and-speed }\n\nPara entender, comparar e ver a diferença entre Uvicorn, Starlette e FastAPI, verifique a seção sobre [Benchmarks](benchmarks.md).\n"
  },
  {
    "path": "docs/pt/docs/async.md",
    "content": "# Concorrência e async / await { #concurrency-and-async-await }\n\nDetalhes sobre a sintaxe `async def` para *funções de operação de rota* e alguns conceitos de código assíncrono, concorrência e paralelismo.\n\n## Com pressa? { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - muito longo; não li\"><strong>TL;DR:</strong></abbr>\n\nSe você estiver utilizando bibliotecas de terceiros que dizem para você chamar as funções com `await`, como:\n\n```Python\nresults = await some_library()\n```\n\nEntão, declare suas *funções de operação de rota* com `async def` como:\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | Nota\n\nVocê só pode usar `await` dentro de funções criadas com `async def`.\n\n///\n\n---\n\nSe você está usando uma biblioteca de terceiros que se comunica com alguma coisa (um banco de dados, uma API, o sistema de arquivos etc.) e não tem suporte para utilizar `await` (esse é atualmente o caso para a maioria das bibliotecas de banco de dados), então declare suas *funções de operação de rota* normalmente, com apenas `def`, como:\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\nSe sua aplicação (de alguma forma) não tem que se comunicar com nada mais e esperar que o respondam, use `async def`, mesmo que você não precise usar `await` dentro dela.\n\n---\n\nSe você simplesmente não sabe, use apenas `def`.\n\n---\n\n**Note**: Você pode misturar `def` e `async def` nas suas *funções de operação de rota* tanto quanto necessário e definir cada função usando a melhor opção para você. FastAPI irá fazer a coisa certa com elas.\n\nDe qualquer forma, em ambos os casos acima, FastAPI irá trabalhar assincronamente e ser extremamente rápido.\n\nMas, seguindo os passos acima, ele será capaz de fazer algumas otimizações de performance.\n\n## Detalhes Técnicos { #technical-details }\n\nVersões modernas de Python têm suporte para **\"código assíncrono\"** usando algo chamado **\"corrotinas\"**, com sintaxe **`async` e `await`**.\n\nVamos ver aquela frase por partes nas seções abaixo:\n\n* **Código assíncrono**\n* **`async` e `await`**\n* **Corrotinas**\n\n## Código assíncrono { #asynchronous-code }\n\nCódigo assíncrono apenas significa que a linguagem 💬 tem um jeito de dizer para o computador / programa 🤖 que em certo ponto do código, ele 🤖 terá que esperar *algo* finalizar em outro lugar. Vamos dizer que esse *algo* seja chamado \"arquivo lento\" 📝.\n\nEntão, durante esse tempo, o computador pode ir e fazer outro trabalho, enquanto o \"arquivo lento\" 📝 termina.\n\nEntão o computador / programa 🤖 irá voltar sempre que tiver uma chance, seja porque ele está esperando novamente, ou quando ele 🤖 terminar todo o trabalho que tem até esse ponto. E ele 🤖 irá ver se alguma das tarefas que estava esperando já terminaram de fazer o que quer que tinham que fazer.\n\nDepois, ele 🤖 pega a primeira tarefa para finalizar (vamos dizer, nosso \"arquivo lento\" 📝) e continua o que tem que fazer com ela.\n\nEsse \"esperar por algo\" normalmente se refere a operações <abbr title=\"Input and Output - Entrada e Saída\">I/O</abbr> que são relativamente \"lentas\" (comparadas à velocidade do processador e da memória RAM), como esperar por:\n\n* dados do cliente para serem enviados através da rede\n* dados enviados pelo seu programa serem recebidos pelo cliente através da rede\n* conteúdo de um arquivo no disco ser lido pelo sistema e entregue ao seu programa\n* conteúdo que seu programa deu ao sistema para ser escrito no disco\n* uma operação em uma API remota\n* uma operação no banco de dados finalizar\n* uma solicitação no banco de dados retornar o resultado\n* etc.\n\nQuanto o tempo de execução é consumido majoritariamente pela espera de operações <abbr title=\"Input and Output - Entrada e Saída\">I/O</abbr>, essas operações são chamadas operações \"limitadas por I/O\".\n\nIsso é chamado de \"assíncrono\" porque o computador / programa não tem que ser \"sincronizado\" com a tarefa lenta, esperando pelo momento exato em que a tarefa finaliza, enquanto não faz nada, para ser capaz de pegar o resultado da tarefa e dar continuidade ao trabalho.\n\nAo invés disso, sendo um sistema \"assíncrono\", uma vez finalizada, a tarefa pode esperar na fila um pouco (alguns microssegundos) para que o computador / programa finalize o que quer que esteja fazendo, e então volte para pegar o resultado e continue trabalhando com ele.\n\nPara \"síncrono\" (contrário de \"assíncrono\") também é utilizado o termo \"sequencial\", porquê o computador / programa segue todos os passos, em sequência, antes de trocar para uma tarefa diferente, mesmo se alguns passos envolvam esperar.\n\n### Concorrência e hambúrgueres { #concurrency-and-burgers }\n\nEssa ideia de código **assíncrono** descrita acima é às vezes chamada de **\"concorrência\"**. Isso é diferente de **\"paralelismo\"**.\n\n**Concorrência** e **paralelismo** ambos são relacionados a \"diferentes coisas acontecendo mais ou menos ao mesmo tempo\".\n\nMas os detalhes entre *concorrência* e *paralelismo* são bem diferentes.\n\nPara ver essa diferença, imagine a seguinte história sobre hambúrgueres:\n\n### Hambúrgueres concorrentes { #concurrent-burgers }\n\nVocê vai com seu _crush_ na lanchonete, e fica na fila enquanto o caixa pega os pedidos das pessoas na sua frente. 😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\nEntão chega a sua vez, você pede dois saborosos hambúrgueres para você e seu _crush_.  🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\nO caixa diz alguma coisa para o cozinheiro na cozinha para que eles saibam que têm que preparar seus hambúrgueres (mesmo que ele esteja atualmente preparando os lanches dos outros clientes).\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\nVocê paga. 💸\n\nO caixa te entrega seu número de chamada.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\nEnquanto você espera, você vai com seu _crush_ e pega uma mesa, senta e conversa com seu _crush_ por um bom tempo (já que seus hambúrgueres são muito saborosos, e leva um tempo para serem preparados).\n\nJá que você está sentado na mesa com seu _crush_, esperando os hambúrgueres, você pode passar esse tempo admirando o quão lindo, maravilhoso e esperto é seu _crush_ ✨😍✨.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\nEnquanto espera e conversa com seu _crush_, de tempos em tempos, você verifica o número da chamada exibido no balcão para ver se já é sua vez.\n\nEntão em algum momento, é finalmente sua vez. Você vai ao balcão, pega seus hambúrgueres e volta para a mesa.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\nVocê e seu _crush_ comem os hambúrgueres e aproveitam o tempo. ✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info | Informação\n\nBelas ilustrações de [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nImagine que você seja o computador / programa 🤖 nessa história.\n\nEnquanto você está na fila, você está somente ocioso 😴, esperando por sua vez, sem fazer nada muito \"produtivo\". Mas a fila é rápida porque o caixa só está pegando os pedidos (não os preparando), então está tudo bem.\n\nEntão, quando é sua vez, você faz trabalho realmente \"produtivo\", você processa o menu, decide o que quer, pega a escolha de seu _crush_, paga, verifica se entregou o cartão ou a cédula correta, verifica se foi cobrado corretamente, verifica se seu pedido está correto etc.\n\nMas então, embora você ainda não tenha os hambúrgueres, seu trabalho no caixa está \"pausado\" ⏸, porque você tem que esperar 🕙 seus hambúrgueres ficarem prontos.\n\nContudo, à medida que você se afasta do balcão e senta na mesa, com um número para sua chamada, você pode trocar 🔀 sua atenção para seu _crush_, e \"trabalhar\" ⏯ 🤓 nisso. Então você está novamente fazendo algo muito \"produtivo\", como flertar com seu _crush_ 😍.\n\nEntão o caixa 💁 diz que \"seus hambúrgueres estão prontos\" colocando seu número no balcão, mas você não corre que nem um maluco imediatamente quando o número exibido é o seu. Você sabe que ninguém irá roubar seus hambúrgueres porque você tem o seu número da chamada, e os outros têm os deles.\n\nEntão você espera seu _crush_ terminar a história que estava contando (terminar o trabalho atual ⏯ / tarefa sendo processada 🤓), sorri gentilmente e diz que você está indo buscar os hambúrgueres ⏸.\n\nEntão você vai ao balcão 🔀, para a tarefa inicial que agora está finalizada ⏯, pega os hambúrgueres, agradece, e leva-os para a mesa. Isso finaliza esse passo / tarefa da interação com o balcão ⏹. Isso, por sua vez, cria uma nova tarefa, a de \"comer hambúrgueres\" 🔀 ⏯, mas a tarefa anterior de \"pegar os hambúrgueres\" já está finalizada ⏹.\n\n### Hambúrgueres paralelos { #parallel-burgers }\n\nAgora vamos imaginar que esses não são \"Hambúrgueres Concorrentes\", e sim \"Hambúrgueres Paralelos\".\n\nVocê vai com seu _crush_ na lanchonete paralela.\n\nVocê fica na fila enquanto vários (vamos dizer 8) caixas que também são cozinheiros pegam os pedidos das pessoas na sua frente.\n\nTodo mundo na sua frente está esperando seus hambúrgueres ficarem prontos antes de deixar o caixa porque cada um dos 8 caixas vai e prepara o hambúrguer logo após receber o pedido, antes de pegar o próximo pedido.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\nEntão é finalmente sua vez, você pede 2 hambúrgueres muito saborosos para você e seu _crush_.\n\nVocê paga 💸.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\nO caixa vai para a cozinha.\n\nVocê espera, na frente do balcão 🕙, para que ninguém pegue seus hambúrgueres antes de você, já que não tem números de chamadas.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\nComo você e seu _crush_ estão ocupados não permitindo que ninguém passe na frente e pegue seus hambúrgueres assim que estiverem prontos, você não pode dar atenção ao seu _crush_. 😞\n\nIsso é trabalho \"síncrono\", você está \"sincronizado\" com o caixa / cozinheiro 👨‍🍳. Você tem que esperar 🕙 e estar lá no exato momento que o caixa / cozinheiro 👨‍🍳 terminar os hambúrgueres e os der a você, ou então, outro alguém pode pegá-los.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\nEntão seu caixa / cozinheiro 👨‍🍳 finalmente volta com seus hambúrgueres, depois de um longo tempo esperando 🕙 por eles em frente ao balcão.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\nVocê pega seus hambúrgueres e vai para a mesa com seu _crush_.\n\nVocês comem os hambúrgueres, e o trabalho está terminado. ⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\nNão houve muita conversa ou flerte já que a maior parte do tempo foi gasto esperando 🕙 na frente do balcão. 😞\n\n/// info | Informação\n\nBelas ilustrações de [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nNesse cenário dos hambúrgueres paralelos, você é um computador / programa 🤖 com dois processadores (você e seu _crush_), ambos esperando 🕙 e dedicando sua atenção ⏯ \"esperando no balcão\" 🕙 por um bom tempo.\n\nA lanchonete paralela tem 8 processadores (caixas / cozinheiros), enquanto a lanchonete dos hambúrgueres concorrentes tinha apenas 2 (um caixa e um cozinheiro).\n\nAinda assim, a experiência final não foi a melhor. 😞\n\n---\n\nEssa seria o equivalente paralelo à história dos hambúrgueres. 🍔\n\nPara um exemplo \"mais real\", imagine um banco.\n\nAté recentemente, a maioria dos bancos tinham muitos caixas 👨‍💼👨‍💼👨‍💼👨‍💼 e uma grande fila 🕙🕙🕙🕙🕙🕙🕙🕙.\n\nTodos os caixas fazendo todo o trabalho, um cliente após o outro 👨‍💼⏯.\n\nE você tinha que esperar 🕙 na fila por um longo tempo ou poderia perder a vez.\n\nVocê provavelmente não gostaria de levar seu _crush_ 😍 com você para um rolezinho no banco 🏦.\n\n### Conclusão dos hambúrgueres { #burger-conclusion }\n\nNesse cenário dos \"hambúrgueres com seu _crush_\", como tem muita espera, faz mais sentido ter um sistema concorrente ⏸🔀⏯.\n\nEsse é o caso da maioria das aplicações web.\n\nMuitos, muitos usuários, mas seu servidor está esperando 🕙 pela sua conexão não tão boa enviar suas requisições.\n\nE então esperando 🕙 novamente as respostas voltarem.\n\nEssa \"espera\" 🕙 é medida em microssegundos, mas ainda assim, somando tudo, é um monte de espera no final.\n\nPor isso que faz bastante sentido utilizar código assíncrono ⏸🔀⏯ para APIs web.\n\nEsse tipo de assincronicidade é o que fez NodeJS popular (embora NodeJS não seja paralelo) e essa é a força do Go como uma linguagem de programação.\n\nE esse é o mesmo nível de performance que você tem com o **FastAPI**.\n\nE como você pode ter paralelismo e assincronicidade ao mesmo tempo, você tem uma maior performance do que a maioria dos frameworks NodeJS testados e lado a lado com Go, que é uma linguagem compilada, mais próxima ao C [(tudo graças ao Starlette)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).\n\n### Concorrência é melhor que paralelismo? { #is-concurrency-better-than-parallelism }\n\nNão! Essa não é a moral da história.\n\nConcorrência é diferente de paralelismo. E é melhor em cenários **específicos** que envolvam um monte de espera. Por isso, geralmente é muito melhor do que paralelismo para desenvolvimento de aplicações web. Mas não para tudo.\n\nEntão, para equilibrar tudo, imagine a seguinte historinha:\n\n> Você tem que limpar uma casa grande e suja.\n\n*Sim, essa é toda a história*.\n\n---\n\nNão há espera 🕙 em lugar algum, apenas um monte de trabalho para ser feito, em múltiplos cômodos da casa.\n\nVocê poderia ter turnos como no exemplo dos hambúrgueres, primeiro a sala de estar, então a cozinha, mas como você não está esperando por nada, apenas limpando e limpando, as chamadas não afetariam em nada.\n\nLevaria o mesmo tempo para finalizar com ou sem turnos (concorrência) e você teria feito o mesmo tanto de trabalho.\n\nMas nesse caso, se você trouxesse os 8 ex-caixas / cozinheiros / agora-faxineiros, e cada um deles (mais você) pudessem dividir a casa para limpá-la, vocês fariam toda a limpeza em **paralelo**, com a ajuda extra, e terminariam muito mais cedo.\n\nNesse cenário, cada um dos faxineiros (incluindo você) poderia ser um processador, fazendo a sua parte do trabalho.\n\nE a maior parte do tempo de execução é tomada por trabalho real (ao invés de ficar esperando), e o trabalho em um computador é feito pela <abbr title=\"Central Processing Unit - Unidade Central de Processamento\">CPU</abbr>. Eles chamam esses problemas de \"limitados por CPU\".\n\n---\n\nExemplos comuns de operações limitadas por CPU são coisas que exigem processamento matemático complexo.\n\nPor exemplo:\n\n* **Processamento de áudio** ou **imagem**\n* **Visão Computacional**: uma imagem é composta por milhões de pixels, cada pixel tem 3 valores / cores, processar isso normalmente exige alguma computação em todos esses pixels ao mesmo tempo\n* **Aprendizado de Máquina**: Normalmente exige muita multiplicação de matrizes e vetores. Pense numa grande planilha com números e em multiplicar todos eles juntos e ao mesmo tempo.\n* **Deep Learning**: Esse é um subcampo do Aprendizado de Máquina, então, o mesmo se aplica. A diferença é que não há apenas uma grande planilha com números para multiplicar, mas um grande conjunto delas, e em muitos casos, você utiliza um processador especial para construir e/ou usar esses modelos.\n\n### Concorrência + Paralelismo: Web + Aprendizado de Máquina { #concurrency-parallelism-web-machine-learning }\n\nCom **FastAPI** você pode levar a vantagem da concorrência que é muito comum para desenvolvimento web (o mesmo atrativo de NodeJS).\n\nMas você também pode explorar os benefícios do paralelismo e multiprocessamento (tendo múltiplos processadores rodando em paralelo) para trabalhos **limitados por CPU** como aqueles em sistemas de Aprendizado de Máquina.\n\nIsso, somado ao simples fato que Python é a principal linguagem para **Data Science**, Aprendizado de Máquina e especialmente Deep Learning, faz do FastAPI uma ótima escolha para APIs web e aplicações com Data Science / Aprendizado de Máquina (entre muitas outras).\n\nPara ver como alcançar esse paralelismo em produção veja a seção sobre [Implantação](deployment/index.md).\n\n## `async` e `await` { #async-and-await }\n\nVersões modernas do Python têm um modo muito intuitivo para definir código assíncrono. Isso faz parecer do mesmo jeito do código normal \"sequencial\" e fazer a \"espera\" para você nos momentos certos.\n\nQuando tem uma operação que exigirá espera antes de dar os resultados e tem suporte para esses novos recursos do Python, você pode escrever assim:\n\n```Python\nburgers = await get_burgers(2)\n```\n\nA chave aqui é o `await`. Ele diz ao Python que ele tem que esperar ⏸ por `get_burgers(2)` finalizar suas coisas 🕙 antes de armazenar os resultados em `burgers`. Com isso, o Python saberá que ele pode ir e fazer outras coisas 🔀 ⏯ nesse meio tempo (como receber outra requisição).\n\nPara o `await` funcionar, tem que estar dentro de uma função que suporte essa assincronicidade. Para fazer isso, apenas declare a função com `async def`:\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # Faz alguma coisa assíncrona para criar os hambúrgueres\n    return burgers\n```\n\n...ao invés de `def`:\n\n```Python hl_lines=\"2\"\n# Isso não é assíncrono\ndef get_sequential_burgers(number: int):\n    # Faz alguma coisa sequencial para criar os hambúrgueres\n    return burgers\n```\n\nCom `async def`, o Python sabe que, dentro dessa função, ele deve estar ciente das expressões `await`, e que isso poderá \"pausar\" ⏸ a execução dessa função, e ir fazer outra coisa 🔀 antes de voltar.\n\nQuando você quiser chamar uma função `async def`, você tem que \"esperar\" ela. Então, isso não funcionará:\n\n```Python\n# Isso não irá funcionar, porquê get_burgers foi definido com: async def\nburgers = get_burgers(2)\n```\n\n---\n\nEntão, se você está usando uma biblioteca que diz que você pode chamá-la com `await`, você precisa criar as *funções de operação de rota* com `async def`, como em:\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### Mais detalhes técnicos { #more-technical-details }\n\nVocê deve ter observado que `await` pode ser usado somente dentro de funções definidas com `async def`.\n\nMas ao mesmo tempo, funções definidas com `async def` têm que ser \"aguardadas\". Então, funções com `async def` podem ser chamadas somente dentro de funções definidas com `async def` também.\n\nEntão, sobre o ovo e a galinha, como você chama a primeira função async?\n\nSe você estivar trabalhando com **FastAPI** não terá que se preocupar com isso, porquê essa \"primeira\" função será a sua *função de operação de rota*, e o FastAPI saberá como fazer a coisa certa.\n\nMas se você quiser usar `async` / `await` sem FastAPI, você também pode fazê-lo.\n\n### Escreva seu próprio código assíncrono { #write-your-own-async-code }\n\nStarlette (e **FastAPI**) são baseados no [AnyIO](https://anyio.readthedocs.io/en/stable/), o que o torna compatível com ambos o [asyncio](https://docs.python.org/3/library/asyncio-task.html) da biblioteca padrão do Python, e o [Trio](https://trio.readthedocs.io/en/stable/).\n\nEm particular, você pode usar diretamente o [AnyIO](https://anyio.readthedocs.io/en/stable/) para seus casos de uso avançados de concorrência que requerem padrões mais avançados no seu próprio código.\n\nE até se você não estiver utilizando FastAPI, você também pode escrever suas próprias aplicações assíncronas com o [AnyIO](https://anyio.readthedocs.io/en/stable/) por ser altamente compatível e ganhar seus benefícios (e.g. *concorrência estruturada*).\n\nEu criei outra biblioteca em cima do AnyIO, como uma fina camada acima, para melhorar um pouco as anotações de tipo e obter melhor **preenchimento automático**, **erros inline**, etc. Ela também possui uma introdução amigável e um tutorial para ajudar você a **entender** e escrever **seu próprio código async**: [Asyncer](https://asyncer.tiangolo.com/). Seria particularmente útil se você precisar **combinar código async com código regular** (bloqueador/síncrono).\n\n### Outras formas de código assíncrono { #other-forms-of-asynchronous-code }\n\nEsse estilo de usar `async` e `await` é relativamente novo na linguagem.\n\nMas ele faz o trabalho com código assíncrono muito mais fácil.\n\nEssa mesma sintaxe (ou quase a mesma) foi também incluída recentemente em versões modernas do JavaScript (no navegador e NodeJS).\n\nMas antes disso, controlar código assíncrono era bem mais complexo e difícil.\n\nNas versões anteriores do Python, você poderia utilizar threads ou [Gevent](https://www.gevent.org/). Mas o código é bem mais complexo de entender, debugar, e pensar sobre.\n\nNas versões anteriores do NodeJS / Navegador JavaScript, você utilizaria \"callbacks\". O que leva ao \"inferno do callback\".\n\n## Corrotinas { #coroutines }\n\n**Corrotina** é apenas um jeito bonitinho para a coisa que é retornada de uma função `async def`. O Python sabe que é algo como uma função, que pode começar e que vai terminar em algum ponto, mas que pode ser pausada ⏸ internamente também, sempre que tiver um `await` dentro dela.\n\nMas toda essa funcionalidade de código assíncrono com `async` e `await` é muitas vezes resumida como usando \"corrotinas\". É comparável ao principal recurso chave do Go, a \"Gorrotina\".\n\n## Conclusão { #conclusion }\n\nVamos ver a mesma frase de cima:\n\n> Versões modernas do Python têm suporte para **\"código assíncrono\"** usando algo chamado **\"corrotinas\"**, com sintaxe **`async` e `await`**.\n\nIsso pode fazer mais sentido agora. ✨\n\nTudo isso é o que empodera o FastAPI (através do Starlette) e que o faz ter uma performance tão impressionante.\n\n## Detalhes muito técnicos { #very-technical-details }\n\n/// warning | Atenção\n\nVocê pode provavelmente pular isso.\n\nEsses são detalhes muito técnicos de como **FastAPI** funciona por baixo do capô.\n\nSe você tem certo conhecimento técnico (corrotinas, threads, blocking etc) e está curioso sobre como o FastAPI controla o `async def` vs normal `def`, vá em frente.\n\n///\n\n### Funções de operação de rota { #path-operation-functions }\n\nQuando você declara uma *função de operação de rota* com `def` normal ao invés de `async def`, ela é rodada em uma threadpool externa que é então aguardada, ao invés de ser chamada diretamente (já que ela bloquearia o servidor).\n\nSe você está chegando de outro framework assíncrono que não funciona como descrito acima e você está acostumado a definir *funções de operação de rota* triviais somente de computação com simples `def` para ter um mínimo ganho de performance (cerca de 100 nanosegundos), por favor observe que no **FastAPI** o efeito pode ser bem o oposto. Nesses casos, é melhor usar `async def` a menos que suas *funções de operação de rota* utilizem código que performe bloqueamento <abbr title=\"Input/Output - Entrada e Saída: leitura ou escrita no disco, comunicações de rede.\">I/O</abbr>.\n\nAinda, em ambas as situações, as chances são que o **FastAPI** [ainda será mais rápido](index.md#performance) do que (ou ao menos comparável a) seu framework anterior.\n\n### Dependências { #dependencies }\n\nO mesmo se aplica para as [dependências](tutorial/dependencies/index.md). Se uma dependência tem as funções com padrão `def` ao invés de `async def`, ela é rodada no threadpool externo.\n\n### Sub-dependências { #sub-dependencies }\n\nVocê pode ter múltiplas dependências e [sub-dependências](tutorial/dependencies/sub-dependencies.md) requisitando uma à outra (como parâmetros de definições de funções), algumas delas podem ser criadas com `async def` e algumas com `def` normal. Isso ainda funcionaria, e aquelas criadas com `def` normal seriam chamadas em uma thread externa (do threadpool) ao invés de serem \"aguardadas\".\n\n### Outras funções de utilidade { #other-utility-functions }\n\nQualquer outra função de utilidade que você chame diretamente pode ser criada com `def` normal ou `async def` e o FastAPI não irá afetar o modo como você a chama.\n\nIsso está em contraste às funções que o FastAPI chama para você: *funções de operação de rota* e dependências.\n\nSe sua função de utilidade é uma função normal com `def`, ela será chamada diretamente (como você a escreve no código), não em uma threadpool, se a função é criada com `async def` então você deve esperar por essa função quando você chamá-la no seu código.\n\n---\n\nNovamente, esses são detalhes muito técnicos que provavelmente seriam úteis caso você esteja procurando por eles.\n\nCaso contrário, você deve ficar bem com as dicas da seção acima: <a href=\"#in-a-hurry\">Com pressa?</a>.\n"
  },
  {
    "path": "docs/pt/docs/benchmarks.md",
    "content": "# Benchmarks { #benchmarks }\n\nBenchmarks independentes da TechEmpower mostram as aplicações **FastAPI** rodando com Uvicorn como [um dos frameworks Python mais rápidos disponíveis](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), somente atrás dos próprios Starlette e Uvicorn (utilizados internamente pelo FastAPI).\n\nMas quando se checa _benchmarks_ e comparações você deveria ter o seguinte em mente.\n\n## Benchmarks e velocidade { #benchmarks-and-speed }\n\nAo verificar os _benchmarks_, é comum observar algumas ferramentas de diferentes tipos comparadas como equivalentes.\n\nEspecificamente, observa-se Uvicorn, Starlette e FastAPI comparados juntos (entre muitas outras ferramentas).\n\nQuanto mais simples o problema resolvido pela ferramenta, melhor a performance que ela terá. E a maioria dos _benchmarks_ não testam as características adicionais fornecidas pela ferramenta.\n\nA hierarquia segue assim:\n\n* **Uvicorn**: um servidor ASGI\n    * **Starlette**: (utiliza Uvicorn) um _microframework web_\n        * **FastAPI**: (utiliza Starlette) um _microframework_ de API com vários recursos adicionais para construção de APIs, com validação de dados, etc.\n\n* **Uvicorn**:\n    * Terá a melhor performance, já que ele não tem muito código extra além do servidor em si.\n    * Você não conseguiria escrever uma aplicação em Uvicorn diretamente. Isso significa que seu código deveria conter, mais ou menos, todo o código fornecido pelo Starlette (ou **FastAPI**). E se você fizesse isso, sua aplicação final poderia ter a mesma sobrecarga que utilizar um _framework_ que minimiza o código e _bugs_ da sua aplicação.\n    * Se você quer fazer comparações com o Uvicorn, compare com Daphne, Hypercorn, uWSGI, etc. Servidores de Aplicação.\n* **Starlette**:\n    * Terá a melhor performance, depois do Uvicorn. De fato, Starlette utiliza Uvicorn para rodar. Então, ele provavelmente será \"mais lento\" que Uvicorn por ter que executar mais código.\n    * Mas ele fornece a você as ferramentas para construir aplicações _web_ simples, com roteamento baseado em caminhos, etc.\n    * Se você quer fazer comparações com o Starlette, compare com Sanic, Flask, Django, etc. _Frameworks Web_ (ou _microframeworks_).\n* **FastAPI**:\n    * Do mesmo modo que Starlette utiliza Uvicorn e não pode ser mais rápido que ele, **FastAPI** utiliza o Starlette, então não tem como ser mais rápido do que o Starlette.\n    * FastAPI fornece mais recursos acima do Starlette. Recursos que você quase sempre precisará quando construir APIs, como validação de dados e serialização. E utilizando eles, você terá uma documentação automática de graça (a documentação automática nem sequer adiciona peso para rodar as aplicações, ela é gerada na inicialização).\n    * Se você não utilizasse o FastAPI e utilizasse diretamente o Starlette (ou outra ferramenta, como Sanic, Flask, Responder, etc), você teria que implementar toda a validação de dados e serialização por conta. Então, sua aplicação final poderia ainda ter a mesma sobrecarga como se fosse desenvolvida com FastAPI. Em muitos casos, a validação de dados e serialização é o maior pedaço de código escrito em aplicações.\n    * Então, ao utilizar o FastAPI você estará economizando tempo de desenvolvimento, evitará _bugs_, linhas de código, e você provavelmente terá a mesma performance (ou melhor) do que não utilizá-lo (já que você teria que implementar tudo isso em seu código).\n    * Se você quer fazer comparações com o FastAPI, compare com um _framework_  (ou conjunto de ferramentas) para aplicações _web_ que forneça validação de dados, serialização e documentação, como Flask-apispec, NestJS, Molten, etc. _Frameworks_ com validação de dados automática, serialização e documentação integradas.\n"
  },
  {
    "path": "docs/pt/docs/deployment/cloud.md",
    "content": "# Implantar FastAPI em provedores de nuvem { #deploy-fastapi-on-cloud-providers }\n\nVocê pode usar praticamente **qualquer provedor de nuvem** para implantar sua aplicação FastAPI.\n\nNa maioria dos casos, os principais provedores de nuvem têm tutoriais para implantar o FastAPI com eles.\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** é desenvolvido pelo mesmo autor e equipe por trás do **FastAPI**.\n\nEle simplifica o processo de **criar**, **implantar** e **acessar** uma API com o mínimo de esforço.\n\nTraz a mesma **experiência do desenvolvedor** de criar aplicações com FastAPI para **implantá-las** na nuvem. 🎉\n\nFastAPI Cloud é o patrocinador principal e provedor de financiamento dos projetos de código aberto *FastAPI and friends*. ✨\n\n## Provedores de Nuvem - Patrocinadores { #cloud-providers-sponsors }\n\nAlguns outros provedores de nuvem ✨ [**patrocinam o FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ também. 🙇\n\nVocê também pode considerá-los para seguir seus tutoriais e experimentar seus serviços:\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/pt/docs/deployment/concepts.md",
    "content": "# Conceitos de Implantações { #deployments-concepts }\n\nAo implantar um aplicativo **FastAPI**, ou na verdade, qualquer tipo de API da web, há vários conceitos com os quais você provavelmente se importa e, usando-os, você pode encontrar a maneira **mais apropriada** de **implantar seu aplicativo**.\n\nAlguns dos conceitos importantes são:\n\n* Segurança - HTTPS\n* Executando na inicialização\n* Reinicializações\n* Replicação (o número de processos em execução)\n* Memória\n* Etapas anteriores antes de iniciar\n\nVeremos como eles afetariam as **implantações**.\n\nNo final, o principal objetivo é ser capaz de **atender seus clientes de API** de uma forma **segura**, **evitar interrupções** e usar os **recursos de computação** (por exemplo, servidores remotos/máquinas virtuais) da forma mais eficiente possível. 🚀\n\nVou lhe contar um pouco mais sobre esses **conceitos** aqui, e espero que isso lhe dê a **intuição** necessária para decidir como implantar sua API em ambientes muito diferentes, possivelmente até mesmo em **futuros** ambientes que ainda não existem.\n\nAo considerar esses conceitos, você será capaz de **avaliar e projetar** a melhor maneira de implantar **suas próprias APIs**.\n\nNos próximos capítulos, darei a você mais **receitas concretas** para implantar aplicativos FastAPI.\n\nMas por enquanto, vamos verificar essas importantes **ideias conceituais**. Esses conceitos também se aplicam a qualquer outro tipo de API da web. 💡\n\n## Segurança - HTTPS { #security-https }\n\nNo [capítulo anterior sobre HTTPS](https.md) aprendemos como o HTTPS fornece criptografia para sua API.\n\nTambém vimos que o HTTPS normalmente é fornecido por um componente **externo** ao seu servidor de aplicativos, um **Proxy de terminação TLS**.\n\nE tem que haver algo responsável por **renovar os certificados HTTPS**, pode ser o mesmo componente ou pode ser algo diferente.\n\n### Ferramentas de exemplo para HTTPS { #example-tools-for-https }\n\nAlgumas das ferramentas que você pode usar como um proxy de terminação TLS são:\n\n* Traefik\n    * Lida automaticamente com renovações de certificados ✨\n* Caddy\n    * Lida automaticamente com renovações de certificados ✨\n* Nginx\n    * Com um componente externo como o Certbot para renovações de certificados\n* HAProxy\n    * Com um componente externo como o Certbot para renovações de certificados\n* Kubernetes com um controlador Ingress como o Nginx\n    * Com um componente externo como cert-manager para renovações de certificados\n* Gerenciado internamente por um provedor de nuvem como parte de seus serviços (leia abaixo 👇)\n\nOutra opção é que você poderia usar um **serviço de nuvem** que faz mais do trabalho, incluindo a configuração de HTTPS. Ele pode ter algumas restrições ou cobrar mais, etc. Mas, nesse caso, você não teria que configurar um Proxy de terminação TLS sozinho.\n\nMostrarei alguns exemplos concretos nos próximos capítulos.\n\n---\n\nOs próximos conceitos a serem considerados são todos sobre o programa que executa sua API real (por exemplo, Uvicorn).\n\n## Programa e Processo { #program-and-process }\n\nFalaremos muito sobre o \"**processo**\" em execução, então é útil ter clareza sobre o que ele significa e qual é a diferença com a palavra \"**programa**\".\n\n### O que é um Programa { #what-is-a-program }\n\nA palavra **programa** é comumente usada para descrever muitas coisas:\n\n* O **código** que você escreve, os **arquivos Python**.\n* O **arquivo** que pode ser **executado** pelo sistema operacional, por exemplo: `python`, `python.exe` ou `uvicorn`.\n* Um programa específico enquanto está **em execução** no sistema operacional, usando a CPU e armazenando coisas na memória. Isso também é chamado de **processo**.\n\n### O que é um Processo { #what-is-a-process }\n\nA palavra **processo** normalmente é usada de forma mais específica, referindo-se apenas ao que está sendo executado no sistema operacional (como no último ponto acima):\n\n* Um programa específico enquanto está **em execução** no sistema operacional.\n    * Isso não se refere ao arquivo, nem ao código, refere-se **especificamente** à coisa que está sendo **executada** e gerenciada pelo sistema operacional.\n* Qualquer programa, qualquer código, **só pode fazer coisas** quando está sendo **executado**. Então, quando há um **processo em execução**.\n* O processo pode ser **terminado** (ou \"morto\") por você, ou pelo sistema operacional. Nesse ponto, ele para de rodar/ser executado, e ele **não pode mais fazer coisas**.\n* Cada aplicativo que você tem em execução no seu computador tem algum processo por trás dele, cada programa em execução, cada janela, etc. E normalmente há muitos processos em execução **ao mesmo tempo** enquanto um computador está ligado.\n* Pode haver **vários processos** do **mesmo programa** em execução ao mesmo tempo.\n\nSe você verificar o \"gerenciador de tarefas\" ou o \"monitor do sistema\" (ou ferramentas semelhantes) no seu sistema operacional, poderá ver muitos desses processos em execução.\n\nE, por exemplo, você provavelmente verá que há vários processos executando o mesmo programa de navegador (Firefox, Chrome, Edge, etc.). Eles normalmente executam um processo por aba, além de alguns outros processos extras.\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\nAgora que sabemos a diferença entre os termos **processo** e **programa**, vamos continuar falando sobre implantações.\n\n## Executando na inicialização { #running-on-startup }\n\nNa maioria dos casos, quando você cria uma API web, você quer que ela esteja **sempre em execução**, ininterrupta, para que seus clientes possam sempre acessá-la. Isso é claro, a menos que você tenha um motivo específico para querer que ela seja executada somente em certas situações, mas na maioria das vezes você quer que ela esteja constantemente em execução e **disponível**.\n\n### Em um servidor remoto { #in-a-remote-server }\n\nAo configurar um servidor remoto (um servidor em nuvem, uma máquina virtual, etc.), a coisa mais simples que você pode fazer é usar `fastapi run` (que usa Uvicorn) ou algo semelhante, manualmente, da mesma forma que você faz ao desenvolver localmente.\n\nE funcionará e será útil **durante o desenvolvimento**.\n\nMas se sua conexão com o servidor for perdida, o **processo em execução** provavelmente morrerá.\n\nE se o servidor for reiniciado (por exemplo, após atualizações ou migrações do provedor de nuvem), você provavelmente **não notará**. E por causa disso, você nem saberá que precisa reiniciar o processo manualmente. Então, sua API simplesmente permanecerá inativa. 😱\n\n### Executar automaticamente na inicialização { #run-automatically-on-startup }\n\nEm geral, você provavelmente desejará que o programa do servidor (por exemplo, Uvicorn) seja iniciado automaticamente na inicialização do servidor e, sem precisar de nenhuma **intervenção humana**, tenha um processo sempre em execução com sua API (por exemplo, Uvicorn executando seu aplicativo FastAPI).\n\n### Programa separado { #separate-program }\n\nPara conseguir isso, você normalmente terá um **programa separado** que garantiria que seu aplicativo fosse executado na inicialização. E em muitos casos, ele também garantiria que outros componentes ou aplicativos também fossem executados, por exemplo, um banco de dados.\n\n### Ferramentas de exemplo para executar na inicialização { #example-tools-to-run-at-startup }\n\nAlguns exemplos de ferramentas que podem fazer esse trabalho são:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker em Modo Swarm\n* Systemd\n* Supervisor\n* Gerenciado internamente por um provedor de nuvem como parte de seus serviços\n* Outros...\n\nDarei exemplos mais concretos nos próximos capítulos.\n\n## Reinicializações { #restarts }\n\nSemelhante a garantir que seu aplicativo seja executado na inicialização, você provavelmente também deseja garantir que ele seja **reiniciado** após falhas.\n\n### Nós cometemos erros { #we-make-mistakes }\n\nNós, como humanos, cometemos **erros** o tempo todo. O software quase *sempre* tem **bugs** escondidos em lugares diferentes. 🐛\n\nE nós, como desenvolvedores, continuamos aprimorando o código à medida que encontramos esses bugs e implementamos novos recursos (possivelmente adicionando novos bugs também 😅).\n\n### Pequenos erros são tratados automaticamente { #small-errors-automatically-handled }\n\nAo criar APIs da web com FastAPI, se houver um erro em nosso código, o FastAPI normalmente o conterá na única solicitação que acionou o erro. 🛡\n\nO cliente receberá um **Erro Interno do Servidor 500** para essa solicitação, mas o aplicativo continuará funcionando para as próximas solicitações em vez de travar completamente.\n\n### Erros maiores - Travamentos { #bigger-errors-crashes }\n\nNo entanto, pode haver casos em que escrevemos algum código que **trava todo o aplicativo**, fazendo com que o Uvicorn e o Python travem. 💥\n\nE ainda assim, você provavelmente não gostaria que o aplicativo permanecesse inativo porque houve um erro em um lugar, você provavelmente quer que ele **continue em execução** pelo menos para as *operações de rota* que não estão quebradas.\n\n### Reiniciar após falha { #restart-after-crash }\n\nMas nos casos com erros realmente graves que travam o **processo** em execução, você vai querer um componente externo que seja responsável por **reiniciar** o processo, pelo menos algumas vezes...\n\n/// tip | Dica\n\n...Embora se o aplicativo inteiro estiver **travando imediatamente**, provavelmente não faça sentido reiniciá-lo para sempre. Mas nesses casos, você provavelmente notará isso durante o desenvolvimento, ou pelo menos logo após a implantação.\n\nEntão, vamos nos concentrar nos casos principais, onde ele pode travar completamente em alguns casos específicos **no futuro**, e ainda faz sentido reiniciá-lo.\n\n///\n\nVocê provavelmente gostaria de ter a coisa responsável por reiniciar seu aplicativo como um **componente externo**, porque a essa altura, o mesmo aplicativo com Uvicorn e Python já havia travado, então não há nada no mesmo código do mesmo aplicativo que possa fazer algo a respeito.\n\n### Ferramentas de exemplo para reiniciar automaticamente { #example-tools-to-restart-automatically }\n\nNa maioria dos casos, a mesma ferramenta usada para **executar o programa na inicialização** também é usada para lidar com **reinicializações** automáticas.\n\nPor exemplo, isso poderia ser resolvido por:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker no Modo Swarm\n* Systemd\n* Supervisor\n* Gerenciado internamente por um provedor de nuvem como parte de seus serviços\n* Outros...\n\n## Replicação - Processos e Memória { #replication-processes-and-memory }\n\nCom um aplicativo FastAPI, usando um programa de servidor como o comando `fastapi` que executa o Uvicorn, executá-lo uma vez em **um processo** pode atender a vários clientes simultaneamente.\n\nMas em muitos casos, você desejará executar vários processos de trabalho ao mesmo tempo.\n\n### Processos Múltiplos - Trabalhadores { #multiple-processes-workers }\n\nSe você tiver mais clientes do que um único processo pode manipular (por exemplo, se a máquina virtual não for muito grande) e tiver **vários núcleos** na CPU do servidor, você poderá ter **vários processos** em execução com o mesmo aplicativo ao mesmo tempo e distribuir todas as solicitações entre eles.\n\nQuando você executa **vários processos** do mesmo programa de API, eles são comumente chamados de **trabalhadores**.\n\n### Processos do Trabalhador e Portas { #worker-processes-and-ports }\n\nLembra da documentação [Sobre HTTPS](https.md) que diz que apenas um processo pode escutar em uma combinação de porta e endereço IP em um servidor?\n\nIsso ainda é verdade.\n\nEntão, para poder ter **vários processos** ao mesmo tempo, tem que haver um **único processo escutando em uma porta** que então transmite a comunicação para cada processo de trabalho de alguma forma.\n\n### Memória por Processo { #memory-per-process }\n\nAgora, quando o programa carrega coisas na memória, por exemplo, um modelo de aprendizado de máquina em uma variável, ou o conteúdo de um arquivo grande em uma variável, tudo isso **consome um pouco da memória (RAM)** do servidor.\n\nE vários processos normalmente **não compartilham nenhuma memória**. Isso significa que cada processo em execução tem suas próprias coisas, variáveis ​​e memória. E se você estiver consumindo uma grande quantidade de memória em seu código, **cada processo** consumirá uma quantidade equivalente de memória.\n\n### Memória do servidor { #server-memory }\n\nPor exemplo, se seu código carrega um modelo de Aprendizado de Máquina com **1 GB de tamanho**, quando você executa um processo com sua API, ele consumirá pelo menos 1 GB de RAM. E se você iniciar **4 processos** (4 trabalhadores), cada um consumirá 1 GB de RAM. Então, no total, sua API consumirá **4 GB de RAM**.\n\nE se o seu servidor remoto ou máquina virtual tiver apenas 3 GB de RAM, tentar carregar mais de 4 GB de RAM causará problemas. 🚨\n\n### Processos Múltiplos - Um Exemplo { #multiple-processes-an-example }\n\nNeste exemplo, há um **Processo Gerenciador** que inicia e controla dois **Processos de Trabalhadores**.\n\nEste Processo de Gerenciador provavelmente seria o que escutaria na **porta** no IP. E ele transmitiria toda a comunicação para os processos de trabalho.\n\nEsses processos de trabalho seriam aqueles que executariam seu aplicativo, eles executariam os cálculos principais para receber uma **solicitação** e retornar uma **resposta**, e carregariam qualquer coisa que você colocasse em variáveis ​​na RAM.\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\nE, claro, a mesma máquina provavelmente teria **outros processos** em execução, além do seu aplicativo.\n\nUm detalhe interessante é que a porcentagem da **CPU usada** por cada processo pode **variar** muito ao longo do tempo, mas a **memória (RAM)** normalmente fica mais ou menos **estável**.\n\nSe você tiver uma API que faz uma quantidade comparável de cálculos todas as vezes e tiver muitos clientes, então a **utilização da CPU** provavelmente *também será estável* (em vez de ficar constantemente subindo e descendo rapidamente).\n\n### Exemplos de ferramentas e estratégias de replicação { #examples-of-replication-tools-and-strategies }\n\nPode haver várias abordagens para conseguir isso, e falarei mais sobre estratégias específicas nos próximos capítulos, por exemplo, ao falar sobre Docker e contêineres.\n\nA principal restrição a ser considerada é que tem que haver um **único** componente manipulando a **porta** no **IP público**. E então tem que ter uma maneira de **transmitir** a comunicação para os **processos/trabalhadores** replicados.\n\nAqui estão algumas combinações e estratégias possíveis:\n\n* **Uvicorn** com `--workers`\n    * Um **gerenciador de processos** Uvicorn escutaria no **IP** e na **porta** e iniciaria **vários processos de trabalho Uvicorn**.\n* **Kubernetes** e outros **sistemas de contêineres** distribuídos\n    * Algo na camada **Kubernetes** escutaria no **IP** e na **porta**. A replicação seria por ter **vários contêineres**, cada um com **um processo Uvicorn** em execução.\n* **Serviços de nuvem** que cuidam disso para você\n    * O serviço de nuvem provavelmente **cuidará da replicação para você**. Ele possivelmente deixaria você definir **um processo para executar**, ou uma **imagem de contêiner** para usar, em qualquer caso, provavelmente seria **um único processo Uvicorn**, e o serviço de nuvem seria responsável por replicá-lo.\n\n/// tip | Dica\n\nNão se preocupe se alguns desses itens sobre **contêineres**, Docker ou Kubernetes ainda não fizerem muito sentido.\n\nFalarei mais sobre imagens de contêiner, Docker, Kubernetes, etc. em um capítulo futuro: [FastAPI em contêineres - Docker](docker.md).\n\n///\n\n## Etapas anteriores antes de começar { #previous-steps-before-starting }\n\nHá muitos casos em que você deseja executar algumas etapas **antes de iniciar** sua aplicação.\n\nPor exemplo, você pode querer executar **migrações de banco de dados**.\n\nMas na maioria dos casos, você precisará executar essas etapas apenas **uma vez**.\n\nPortanto, você vai querer ter um **processo único** para executar essas **etapas anteriores** antes de iniciar o aplicativo.\n\nE você terá que se certificar de que é um único processo executando essas etapas anteriores *mesmo* se depois, você iniciar **vários processos** (vários trabalhadores) para o próprio aplicativo. Se essas etapas fossem executadas por **vários processos**, eles **duplicariam** o trabalho executando-o em **paralelo**, e se as etapas fossem algo delicado como uma migração de banco de dados, elas poderiam causar conflitos entre si.\n\nClaro, há alguns casos em que não há problema em executar as etapas anteriores várias vezes; nesse caso, é muito mais fácil de lidar.\n\n/// tip | Dica\n\nAlém disso, tenha em mente que, dependendo da sua configuração, em alguns casos você **pode nem precisar de nenhuma etapa anterior** antes de iniciar sua aplicação.\n\nNesse caso, você não precisaria se preocupar com nada disso. 🤷\n\n///\n\n### Exemplos de estratégias de etapas anteriores { #examples-of-previous-steps-strategies }\n\nIsso **dependerá muito** da maneira como você **implanta seu sistema** e provavelmente estará conectado à maneira como você inicia programas, lida com reinicializações, etc.\n\nAqui estão algumas ideias possíveis:\n\n* Um \"Init Container\" no Kubernetes que roda antes do seu app container\n* Um script bash que roda os passos anteriores e então inicia seu aplicativo\n    * Você ainda precisaria de uma maneira de iniciar/reiniciar *aquele* script bash, detectar erros, etc.\n\n/// tip | Dica\n\nDarei exemplos mais concretos de como fazer isso com contêineres em um capítulo futuro: [FastAPI em contêineres - Docker](docker.md).\n\n///\n\n## Utilização de recursos { #resource-utilization }\n\nSeu(s) servidor(es) é(são) um **recurso** que você pode consumir ou **utilizar**, com seus programas, o tempo de computação nas CPUs e a memória RAM disponível.\n\nQuanto dos recursos do sistema você quer consumir/utilizar? Pode ser fácil pensar \"não muito\", mas, na realidade, você provavelmente vai querer consumir **o máximo possível sem travar**.\n\nSe você está pagando por 3 servidores, mas está usando apenas um pouco de RAM e CPU, você provavelmente está **desperdiçando dinheiro** 💸, e provavelmente **desperdiçando energia elétrica do servidor** 🌎, etc.\n\nNesse caso, seria melhor ter apenas 2 servidores e usar uma porcentagem maior de seus recursos (CPU, memória, disco, largura de banda de rede, etc).\n\nPor outro lado, se você tem 2 servidores e está usando **100% da CPU e RAM deles**, em algum momento um processo pedirá mais memória, e o servidor terá que usar o disco como \"memória\" (o que pode ser milhares de vezes mais lento), ou até mesmo **travar**. Ou um processo pode precisar fazer alguma computação e teria que esperar até que a CPU esteja livre novamente.\n\nNesse caso, seria melhor obter **um servidor extra** e executar alguns processos nele para que todos tenham **RAM e tempo de CPU suficientes**.\n\nTambém há a chance de que, por algum motivo, você tenha um **pico** de uso da sua API. Talvez ela tenha se tornado viral, ou talvez alguns outros serviços ou bots comecem a usá-la. E você pode querer ter recursos extras para estar seguro nesses casos.\n\nVocê poderia colocar um **número arbitrário** para atingir, por exemplo, algo **entre 50% a 90%** da utilização de recursos. O ponto é que essas são provavelmente as principais coisas que você vai querer medir e usar para ajustar suas implantações.\n\nVocê pode usar ferramentas simples como `htop` para ver a CPU e a RAM usadas no seu servidor ou a quantidade usada por cada processo. Ou você pode usar ferramentas de monitoramento mais complexas, que podem ser distribuídas entre servidores, etc.\n\n## Recapitular { #recap }\n\nVocê leu aqui alguns dos principais conceitos que provavelmente precisa ter em mente ao decidir como implantar seu aplicativo:\n\n* Segurança - HTTPS\n* Executando na inicialização\n* Reinicializações\n* Replicação (o número de processos em execução)\n* Memória\n* Etapas anteriores antes de iniciar\n\nEntender essas ideias e como aplicá-las deve lhe dar a intuição necessária para tomar qualquer decisão ao configurar e ajustar suas implantações. 🤓\n\nNas próximas seções, darei exemplos mais concretos de possíveis estratégias que você pode seguir. 🚀\n"
  },
  {
    "path": "docs/pt/docs/deployment/docker.md",
    "content": "# FastAPI em contêineres - Docker { #fastapi-in-containers-docker }\n\nAo fazer o deploy de aplicações FastAPI uma abordagem comum é construir uma **imagem de contêiner Linux**. Isso normalmente é feito usando o [**Docker**](https://www.docker.com/). Você pode a partir disso fazer o deploy dessa imagem de algumas maneiras.\n\nUsando contêineres Linux você tem diversas vantagens incluindo **segurança**, **replicabilidade**, **simplicidade**, entre outras.\n\n/// tip | Dica\n\nEstá com pressa e já sabe dessas coisas? Pode ir direto para o [`Dockerfile` abaixo 👇](#build-a-docker-image-for-fastapi).\n\n///\n\n<details>\n<summary>Visualização do Dockerfile 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# Se estiver executando atrás de um proxy como Nginx ou Traefik, adicione --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## O que é um Contêiner { #what-is-a-container }\n\nContêineres (principalmente contêineres Linux) são um jeito muito **leve** de empacotar aplicações contendo todas as dependências e arquivos necessários enquanto os mantém isolados de outros contêineres (outras aplicações ou componentes) no mesmo sistema.\n\nContêineres Linux rodam usando o mesmo kernel Linux do hospedeiro (máquina, máquina virtual, servidor na nuvem, etc). Isso simplesmente significa que eles são muito leves (comparados com máquinas virtuais emulando um sistema operacional completo).\n\nDessa forma, contêineres consomem **poucos recursos**, uma quantidade comparável com rodar os processos diretamente (uma máquina virtual consumiria muito mais).\n\nContêineres também possuem seus próprios processos em execução (comumente **um único processo**), sistema de arquivos e rede **isolados**, simplificando deploy, segurança, desenvolvimento, etc.\n\n## O que é uma Imagem de Contêiner { #what-is-a-container-image }\n\nUm **contêiner** roda a partir de uma **imagem de contêiner**.\n\nUma imagem de contêiner é uma versão **estática** de todos os arquivos, variáveis de ambiente e do comando/programa padrão que deve estar presente num contêiner. **Estática** aqui significa que a **imagem** de contêiner não está rodando, não está sendo executada, somente contém os arquivos e metadados empacotados.\n\nEm contraste com a \"**imagem de contêiner**\" que contém os conteúdos estáticos armazenados, um \"**contêiner**\" normalmente se refere à instância rodando, a coisa que está sendo **executada**.\n\nQuando o **contêiner** é iniciado e está rodando (iniciado a partir de uma **imagem de contêiner**), ele pode criar ou modificar arquivos, variáveis de ambiente, etc. Essas mudanças vão existir somente nesse contêiner, mas não persistirão na imagem subjacente do container (não serão salvas no disco).\n\nUma imagem de contêiner é comparável ao arquivo de **programa** e seus conteúdos, ex.: `python` e algum arquivo `main.py`.\n\nE o **contêiner** em si (em contraste à **imagem de contêiner**) é a própria instância da imagem rodando, comparável a um **processo**. Na verdade, um contêiner está rodando somente quando há um **processo rodando** (e normalmente é somente um processo). O contêiner finaliza quando não há um processo rodando nele.\n\n## Imagens de contêiner { #container-images }\n\nDocker tem sido uma das principais ferramentas para criar e gerenciar **imagens de contêiner** e **contêineres**.\n\nE existe um [Docker Hub](https://hub.docker.com/) público com **imagens de contêiner oficiais** pré-prontas para diversas ferramentas, ambientes, bancos de dados e aplicações.\n\nPor exemplo, há uma [Imagem Python](https://hub.docker.com/_/python) oficial.\n\nE existe muitas outras imagens para diferentes coisas, como bancos de dados, por exemplo:\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis), etc.\n\nUsando imagens de contêiner pré-prontas é muito fácil **combinar** e usar diferentes ferramentas. Por exemplo, para testar um novo banco de dados. Em muitos casos, você pode usar as **imagens oficiais**, precisando somente de variáveis de ambiente para configurá-las.\n\nDessa forma, em muitos casos você pode aprender sobre contêineres e Docker e reusar essa experiência com diversos componentes e ferramentas.\n\nEntão, você rodaria **vários contêineres** com coisas diferentes, como um banco de dados, uma aplicação Python, um servidor web com uma aplicação frontend React, e conectá-los juntos via sua rede interna.\n\nTodos os sistemas de gerenciamento de contêineres (como Docker ou Kubernetes) possuem essas funcionalidades de rede integradas a eles.\n\n## Contêineres e Processos { #containers-and-processes }\n\nUma **imagem de contêiner** normalmente inclui em seus metadados o programa padrão ou comando que deve ser executado quando o **contêiner** é iniciado e os parâmetros a serem passados para esse programa. Muito similar ao que seria se estivesse na linha de comando.\n\nQuando um **contêiner** é iniciado, ele irá rodar esse comando/programa (embora você possa sobrescrevê-lo e fazer com que ele rode um comando/programa diferente).\n\nUm contêiner está rodando enquanto o **processo principal** (comando ou programa) estiver rodando.\n\nUm contêiner normalmente tem um **único processo**, mas também é possível iniciar sub-processos a partir do processo principal, e dessa forma você terá **vários processos** no mesmo contêiner.\n\nMas não é possível ter um contêiner rodando sem **pelo menos um processo rodando**. Se o processo principal parar, o contêiner também para.\n\n## Construir uma Imagem Docker para FastAPI { #build-a-docker-image-for-fastapi }\n\nOkay, vamos construir algo agora! 🚀\n\nEu vou mostrar como construir uma **imagem Docker** para FastAPI **do zero**, baseada na imagem **oficial do Python**.\n\nIsso é o que você quer fazer na **maioria dos casos**, por exemplo:\n\n* Usando **Kubernetes** ou ferramentas similares\n* Quando rodando em uma **Raspberry Pi**\n* Usando um serviço em nuvem que irá rodar uma imagem de contêiner para você, etc.\n\n### Requisitos de Pacotes { #package-requirements }\n\nVocê normalmente teria os **requisitos de pacotes** da sua aplicação em algum arquivo.\n\nIsso pode depender principalmente da ferramenta que você usa para **instalar** esses requisitos.\n\nA forma mais comum de fazer isso é ter um arquivo `requirements.txt` com os nomes dos pacotes e suas versões, um por linha.\n\nVocê, naturalmente, usaria as mesmas ideias que você leu em [Sobre versões do FastAPI](versions.md) para definir os intervalos de versões.\n\nPor exemplo, seu `requirements.txt` poderia parecer com:\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\nE você normalmente instalaria essas dependências de pacote com `pip`, por exemplo:\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info | Informação\n\nHá outros formatos e ferramentas para definir e instalar dependências de pacotes.\n\n///\n\n### Crie o código do **FastAPI** { #create-the-fastapi-code }\n\n* Crie um diretório `app` e entre nele.\n* Crie um arquivo vazio `__init__.py`.\n* Crie um arquivo `main.py` com:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\nAgora, no mesmo diretório do projeto, crie um arquivo `Dockerfile` com:\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. Inicie a partir da imagem base oficial do Python.\n\n2. Defina o diretório de trabalho atual para `/code`.\n\n    Esse é o diretório onde colocaremos o arquivo `requirements.txt` e o diretório `app`.\n\n3. Copie o arquivo com os requisitos para o diretório `/code`.\n\n    Copie **somente** o arquivo com os requisitos primeiro, não o resto do código.\n\n    Como esse arquivo **não muda com frequência**, o Docker irá detectá-lo e usar o **cache** para esse passo, habilitando o cache para o próximo passo também.\n\n4. Instale as dependências de pacote vindas do arquivo de requisitos.\n\n    A opção `--no-cache-dir` diz ao `pip` para não salvar os pacotes baixados localmente, pois isso só aconteceria se `pip` fosse executado novamente para instalar os mesmos pacotes, mas esse não é o caso quando trabalhamos com contêineres.\n\n    /// note | Nota\n\n    `--no-cache-dir` é apenas relacionado ao `pip`, não tem nada a ver com Docker ou contêineres.\n\n    ///\n\n    A opção `--upgrade` diz ao `pip` para atualizar os pacotes se eles já estiverem instalados.\n\n    Por causa do passo anterior de copiar o arquivo, ele pode ser detectado pelo **cache do Docker**, esse passo também **usará o cache do Docker** quando disponível.\n\n    Usando o cache nesse passo irá **salvar** muito **tempo** quando você for construir a imagem repetidas vezes durante o desenvolvimento, ao invés de **baixar e instalar** todas as dependências **toda vez**.\n\n5. Copie o diretório `./app` dentro do diretório `/code`.\n\n    Como isso tem todo o código contendo o que **muda com mais frequência**, o **cache do Docker** não será usado para esse passo ou para **qualquer passo seguinte** facilmente.\n\n    Então, é importante colocar isso **perto do final** do `Dockerfile`, para otimizar o tempo de construção da imagem do contêiner.\n\n6. Defina o **comando** para usar `fastapi run`, que utiliza o Uvicorn por baixo dos panos.\n\n    `CMD` recebe uma lista de strings, cada uma dessas strings é o que você digitaria na linha de comando separado por espaços.\n\n    Esse comando será executado a partir do **diretório de trabalho atual**, o mesmo diretório `/code` que você definiu acima com `WORKDIR /code`.\n\n/// tip | Dica\n\nRevise o que cada linha faz clicando em cada bolha com o número no código. 👆\n\n///\n\n/// warning | Atenção\n\nCertifique-se de **sempre** usar a **forma exec** da instrução `CMD`, como explicado abaixo.\n\n///\n\n#### Use `CMD` - Forma Exec { #use-cmd-exec-form }\n\nA instrução [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) no Docker pode ser escrita de duas formas:\n\n✅ Forma **Exec**:\n\n```Dockerfile\n# ✅ Faça assim\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ Forma **Shell**:\n\n```Dockerfile\n# ⛔️ Não faça assim\nCMD fastapi run app/main.py --port 80\n```\n\nGaranta que você sempre use a forma **exec** para assegurar que o FastAPI consiga encerrar graciosamente e que os [eventos de lifespan](../advanced/events.md) sejam disparados.\n\nVocê pode ler mais na [documentação do Docker sobre as formas shell e exec](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).\n\nIsso pode ser bem perceptível ao usar `docker compose`. Veja esta seção de FAQ do Docker Compose para mais detalhes técnicos: [Por que meus serviços demoram 10 segundos para recriar ou parar?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).\n\n#### Estrutura de diretórios { #directory-structure }\n\nAgora você deve haver uma estrutura de diretório como:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### Por trás de um Proxy de Terminação TLS { #behind-a-tls-termination-proxy }\n\nSe você está executando seu contêiner atrás de um Proxy de Terminação TLS (load balancer) como Nginx ou Traefik, adicione a opção `--proxy-headers`, isso fará com que o Uvicorn (pela CLI do FastAPI) confie nos cabeçalhos enviados por esse proxy, informando que o aplicativo está sendo executado atrás do HTTPS, etc.\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Cache Docker { #docker-cache }\n\nExiste um truque importante nesse `Dockerfile`, primeiro copiamos o **arquivo com as dependências sozinho**, não o resto do código. Deixe-me te contar o porquê disso.\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker e outras ferramentas **constróem** essas imagens de contêiner **incrementalmente**, adicionando **uma camada em cima da outra**, começando do topo do `Dockerfile` e adicionando qualquer arquivo criado por cada uma das instruções do `Dockerfile`.\n\nDocker e ferramentas similares também usam um **cache interno** ao construir a imagem, se um arquivo não mudou desde a última vez que a imagem do contêiner foi construída, então ele irá **reutilizar a mesma camada** criada na última vez, ao invés de copiar o arquivo novamente e criar uma nova camada do zero.\n\nSomente evitar a cópia de arquivos não melhora muito as coisas, mas porque ele usou o cache para esse passo, ele pode **usar o cache para o próximo passo**. Por exemplo, ele pode usar o cache para a instrução que instala as dependências com:\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\nO arquivo com os requisitos de pacote **não muda com frequência**. Então, ao copiar apenas esse arquivo, o Docker será capaz de **usar o cache** para esse passo.\n\nE então, o Docker será capaz de **usar o cache para o próximo passo** que baixa e instala essas dependências. E é aqui que **salvamos muito tempo**. ✨ ...e evitamos tédio esperando. 😪😆\n\nBaixar e instalar as dependências do pacote **pode levar minutos**, mas usando o **cache** leva **segundos** no máximo.\n\nE como você estaria construindo a imagem do contêiner novamente e novamente durante o desenvolvimento para verificar se suas alterações de código estão funcionando, há muito tempo acumulado que isso economizaria.\n\nA partir daí, perto do final do `Dockerfile`, copiamos todo o código. Como isso é o que **muda com mais frequência**, colocamos perto do final, porque quase sempre, qualquer coisa depois desse passo não será capaz de usar o cache.\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### Construa a Imagem Docker { #build-the-docker-image }\n\nAgora que todos os arquivos estão no lugar, vamos construir a imagem do contêiner.\n\n* Vá para o diretório do projeto (onde está o seu `Dockerfile`, contendo o diretório `app`).\n* Construa sua imagem FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | Dica\n\nNote o `.` no final, é equivalente a `./`, ele diz ao Docker o diretório a ser usado para construir a imagem do contêiner.\n\nNesse caso, é o mesmo diretório atual (`.`).\n\n///\n\n### Inicie o Contêiner Docker { #start-the-docker-container }\n\n* Execute um contêiner baseado na sua imagem:\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## Verifique { #check-it }\n\nVocê deve ser capaz de verificar isso no URL do seu contêiner Docker, por exemplo: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) ou [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (ou equivalente, usando seu host Docker).\n\nVocê verá algo como:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## Documentação interativa da API { #interactive-api-docs }\n\nAgora você pode ir para [http://192.168.99.100/docs](http://192.168.99.100/docs) ou [http://127.0.0.1/docs](http://127.0.0.1/docs) (ou equivalente, usando seu host Docker).\n\nVocê verá a documentação interativa automática da API (fornecida pelo [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## Documentação alternativa da API { #alternative-api-docs }\n\nE você também pode ir para [http://192.168.99.100/redoc](http://192.168.99.100/redoc) ou [http://127.0.0.1/redoc](http://127.0.0.1/redoc) (ou equivalente, usando seu host Docker).\n\nVocê verá a documentação alternativa automática (fornecida pelo [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Construa uma Imagem Docker com um FastAPI de Arquivo Único { #build-a-docker-image-with-a-single-file-fastapi }\n\nSe seu FastAPI for um único arquivo, por exemplo, `main.py` sem um diretório `./app`, sua estrutura de arquivos poderia ser assim:\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\nEntão você só teria que alterar os caminhos correspondentes para copiar o arquivo dentro do `Dockerfile`:\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. Copie o arquivo `main.py` para o diretório `/code` diretamente (sem nenhum diretório `./app`).\n\n2. Use `fastapi run` para servir sua aplicação no arquivo único `main.py`.\n\nQuando você passa o arquivo para `fastapi run` ele detecta automaticamente que é um arquivo único e não parte de um pacote e sabe como importá-lo e servir sua aplicação FastAPI. 😎\n\n## Conceitos de Implantação { #deployment-concepts }\n\nVamos falar novamente sobre alguns dos mesmos [Conceitos de Implantação](concepts.md) em termos de contêineres.\n\nContêineres são principalmente uma ferramenta para simplificar o processo de **construção e implantação** de um aplicativo, mas eles não impõem uma abordagem particular para lidar com esses **conceitos de implantação** e existem várias estratégias possíveis.\n\nA **boa notícia** é que com cada estratégia diferente há uma maneira de cobrir todos os conceitos de implantação. 🎉\n\nVamos revisar esses **conceitos de implantação** em termos de contêineres:\n\n* HTTPS\n* Executando na inicialização\n* Reinicializações\n* Replicação (número de processos rodando)\n* Memória\n* Passos anteriores antes de começar\n\n## HTTPS { #https }\n\nSe nos concentrarmos apenas na **imagem do contêiner** para um aplicativo FastAPI (e posteriormente no **contêiner** em execução), o HTTPS normalmente seria tratado **externamente** por outra ferramenta.\n\nIsso poderia ser outro contêiner, por exemplo, com [Traefik](https://traefik.io/), lidando com **HTTPS** e aquisição **automática** de **certificados**.\n\n/// tip | Dica\n\nTraefik tem integrações com Docker, Kubernetes e outros, portanto, é muito fácil configurar o HTTPS para seus contêineres com ele.\n\n///\n\nAlternativamente, o HTTPS poderia ser tratado por um provedor de nuvem como um de seus serviços (enquanto ainda executasse o aplicativo em um contêiner).\n\n## Executando na inicialização e reinicializações { #running-on-startup-and-restarts }\n\nNormalmente, outra ferramenta é responsável por **iniciar e executar** seu contêiner.\n\nEla poderia ser o **Docker** diretamente, **Docker Compose**, **Kubernetes**, um **serviço de nuvem**, etc.\n\nNa maioria (ou em todos) os casos, há uma opção simples para habilitar a execução do contêiner na inicialização e habilitar reinicializações em falhas. Por exemplo, no Docker, é a opção de linha de comando `--restart`.\n\nSem usar contêineres, fazer aplicativos executarem na inicialização e com reinicializações pode ser trabalhoso e difícil. Mas quando **trabalhando com contêineres** em muitos casos essa funcionalidade é incluída por padrão. ✨\n\n## Replicação - Número de Processos { #replication-number-of-processes }\n\nSe você tiver um <dfn title=\"Um grupo de máquinas que são configuradas para estarem conectadas e trabalharem juntas de alguma forma.\">cluster</dfn> de máquinas com **Kubernetes**, Docker Swarm Mode, Nomad ou outro sistema complexo semelhante para gerenciar contêineres distribuídos em várias máquinas, então provavelmente desejará **lidar com a replicação** no **nível do cluster** em vez de usar um **gerenciador de processos** (como Uvicorn com workers) em cada contêiner.\n\nUm desses sistemas de gerenciamento de contêineres distribuídos como o Kubernetes normalmente tem alguma maneira integrada de lidar com a **replicação de contêineres** enquanto ainda oferece **balanceamento de carga** para as solicitações recebidas. Tudo no **nível do cluster**.\n\nNesses casos, você provavelmente desejará criar uma **imagem Docker do zero** como [explicado acima](#dockerfile), instalando suas dependências e executando **um único processo Uvicorn** em vez de usar múltiplos workers do Uvicorn.\n\n### Balanceador de Carga { #load-balancer }\n\nQuando usando contêineres, normalmente você terá algum componente **escutando na porta principal**. Poderia ser outro contêiner que também é um **Proxy de Terminação TLS** para lidar com **HTTPS** ou alguma ferramenta semelhante.\n\nComo esse componente assumiria a **carga** de solicitações e distribuiria isso entre os workers de uma maneira (esperançosamente) **balanceada**, ele também é comumente chamado de **Balanceador de Carga**.\n\n/// tip | Dica\n\nO mesmo componente **Proxy de Terminação TLS** usado para HTTPS provavelmente também seria um **Balanceador de Carga**.\n\n///\n\nE quando trabalhar com contêineres, o mesmo sistema que você usa para iniciar e gerenciá-los já terá ferramentas internas para transmitir a **comunicação de rede** (por exemplo, solicitações HTTP) do **balanceador de carga** (que também pode ser um **Proxy de Terminação TLS**) para o(s) contêiner(es) com seu aplicativo.\n\n### Um Balanceador de Carga - Múltiplos Contêineres de Workers { #one-load-balancer-multiple-worker-containers }\n\nQuando trabalhando com **Kubernetes** ou sistemas similares de gerenciamento de contêiner distribuído, usar seus mecanismos de rede internos permite que o único **balanceador de carga** que está escutando na **porta principal** transmita a comunicação (solicitações) para possivelmente **múltiplos contêineres** executando seu aplicativo.\n\nCada um desses contêineres executando seu aplicativo normalmente teria **apenas um processo** (ex.: um processo Uvicorn executando seu aplicativo FastAPI). Todos seriam **contêineres idênticos**, executando a mesma coisa, mas cada um com seu próprio processo, memória, etc. Dessa forma, você aproveitaria a **paralelização** em **núcleos diferentes** da CPU, ou até mesmo em **máquinas diferentes**.\n\nE o sistema de contêiner com o **balanceador de carga** iria **distribuir as solicitações** para cada um dos contêineres com seu aplicativo **em turnos**. Portanto, cada solicitação poderia ser tratada por um dos múltiplos **contêineres replicados** executando seu aplicativo.\n\nE normalmente esse **balanceador de carga** seria capaz de lidar com solicitações que vão para *outros* aplicativos em seu cluster (por exemplo, para um domínio diferente, ou sob um prefixo de URL diferente), e transmitiria essa comunicação para os contêineres certos para *esse outro* aplicativo em execução em seu cluster.\n\n### Um Processo por Contêiner { #one-process-per-container }\n\nNesse tipo de cenário, provavelmente você desejará ter **um único processo (Uvicorn) por contêiner**, pois já estaria lidando com a replicação no nível do cluster.\n\nEntão, nesse caso, você **não** desejará ter múltiplos workers no contêiner, por exemplo com a opção de linha de comando `--workers`. Você desejará ter apenas um **único processo Uvicorn** por contêiner (mas provavelmente vários contêineres).\n\nTer outro gerenciador de processos dentro do contêiner (como seria com múltiplos workers) só adicionaria **complexidade desnecessária** que você provavelmente já está cuidando com seu sistema de cluster.\n\n### Contêineres com Múltiplos Processos e Casos Especiais { #containers-with-multiple-processes-and-special-cases }\n\nClaro, existem **casos especiais** em que você pode querer ter **um contêiner** com vários **processos workers do Uvicorn** dentro.\n\nNesses casos, você pode usar a opção de linha de comando `--workers` para definir o número de workers que deseja executar:\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. Aqui usamos a opção de linha de comando `--workers` para definir o número de workers como 4.\n\nAqui estão alguns exemplos de quando isso pode fazer sentido:\n\n#### Um Aplicativo Simples { #a-simple-app }\n\nVocê pode querer um gerenciador de processos no contêiner se seu aplicativo for **simples o suficiente** para rodar em um **único servidor**, não em um cluster.\n\n#### Docker Compose { #docker-compose }\n\nVocê pode estar implantando em um **único servidor** (não em um cluster) com o **Docker Compose**, então você não teria uma maneira fácil de gerenciar a replicação de contêineres (com o Docker Compose) enquanto preserva a rede compartilhada e o **balanceamento de carga**.\n\nEntão você pode querer ter **um único contêiner** com um **gerenciador de processos** iniciando **vários processos workers** dentro.\n\n---\n\nO ponto principal é que **nenhum** desses são **regras escritas em pedra** que você deve seguir cegamente. Você pode usar essas ideias para **avaliar seu próprio caso de uso** e decidir qual é a melhor abordagem para seu sistema, verificando como gerenciar os conceitos de:\n\n* Segurança - HTTPS\n* Executando na inicialização\n* Reinicializações\n* Replicação (o número de processos em execução)\n* Memória\n* Passos anteriores antes de iniciar\n\n## Memória { #memory }\n\nSe você executar **um único processo por contêiner**, terá uma quantidade mais ou menos bem definida, estável e limitada de memória consumida por cada um desses contêineres (mais de um se eles forem replicados).\n\nE então você pode definir esses mesmos limites e requisitos de memória em suas configurações para seu sistema de gerenciamento de contêineres (por exemplo, no **Kubernetes**). Dessa forma, ele poderá **replicar os contêineres** nas **máquinas disponíveis** levando em consideração a quantidade de memória necessária por eles e a quantidade disponível nas máquinas no cluster.\n\nSe sua aplicação for **simples**, isso provavelmente **não será um problema**, e você pode não precisar especificar limites de memória rígidos. Mas se você estiver **usando muita memória** (por exemplo, com **modelos de aprendizado de máquina**), deve verificar quanta memória está consumindo e ajustar o **número de contêineres** que executa em **cada máquina** (e talvez adicionar mais máquinas ao seu cluster).\n\nSe você executar **múltiplos processos por contêiner**, deve garantir que o número de processos iniciados não **consuma mais memória** do que o disponível.\n\n## Passos anteriores antes de iniciar e contêineres { #previous-steps-before-starting-and-containers }\n\nSe você estiver usando contêineres (por exemplo, Docker, Kubernetes), existem duas abordagens principais que você pode usar.\n\n### Contêineres Múltiplos { #multiple-containers }\n\nSe você tiver **múltiplos contêineres**, provavelmente cada um executando um **único processo** (por exemplo, em um cluster do **Kubernetes**), então provavelmente você gostaria de ter um **contêiner separado** fazendo o trabalho dos **passos anteriores** em um único contêiner, executando um único processo, **antes** de executar os contêineres workers replicados.\n\n/// info | Informação\n\nSe você estiver usando o Kubernetes, provavelmente será um [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).\n\n///\n\nSe no seu caso de uso não houver problema em executar esses passos anteriores **em paralelo várias vezes** (por exemplo, se você não estiver executando migrações de banco de dados, mas apenas verificando se o banco de dados está pronto), então você também pode colocá-los em cada contêiner logo antes de iniciar o processo principal.\n\n### Contêiner Único { #single-container }\n\nSe você tiver uma configuração simples, com um **único contêiner** que então inicia vários **processos workers** (ou também apenas um processo), então poderia executar esses passos anteriores no mesmo contêiner, logo antes de iniciar o processo com o aplicativo.\n\n### Imagem Docker base { #base-docker-image }\n\nAntes havia uma imagem oficial do FastAPI para Docker: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). Mas agora ela está descontinuada. ⛔️\n\nVocê provavelmente **não** deve usar essa imagem base do Docker (ou qualquer outra semelhante).\n\nSe você está usando **Kubernetes** (ou outros) e já está definindo a **replicação** no nível do cluster, com vários **contêineres**. Nesses casos, é melhor **construir uma imagem do zero** como descrito acima: [Construir uma Imagem Docker para FastAPI](#build-a-docker-image-for-fastapi).\n\nE se você precisar ter múltiplos workers, você pode simplesmente usar a opção de linha de comando `--workers`.\n\n/// note | Detalhes Técnicos\n\nA imagem Docker foi criada quando o Uvicorn não suportava gerenciar e reiniciar workers mortos, então era necessário usar o Gunicorn com o Uvicorn, o que adicionava bastante complexidade, apenas para que o Gunicorn gerenciasse e reiniciasse os processos workers do Uvicorn.\n\nMas agora que o Uvicorn (e o comando `fastapi`) suportam o uso de `--workers`, não há razão para usar uma imagem base do Docker em vez de construir a sua própria (é praticamente a mesma quantidade de código 😅).\n\n///\n\n## Deploy da Imagem do Contêiner { #deploy-the-container-image }\n\nDepois de ter uma imagem de contêiner (Docker), existem várias maneiras de implantá-la.\n\nPor exemplo:\n\n* Com **Docker Compose** em um único servidor\n* Com um cluster **Kubernetes**\n* Com um cluster Docker Swarm Mode\n* Com outra ferramenta como o Nomad\n* Com um serviço de nuvem que pega sua imagem de contêiner e a implanta\n\n## Imagem Docker com `uv` { #docker-image-with-uv }\n\nSe você está usando o [uv](https://github.com/astral-sh/uv) para instalar e gerenciar seu projeto, você pode seguir o [guia de Docker do uv](https://docs.astral.sh/uv/guides/integration/docker/).\n\n## Recapitulando { #recap }\n\nUsando sistemas de contêiner (por exemplo, com **Docker** e **Kubernetes**), torna-se bastante simples lidar com todos os **conceitos de implantação**:\n\n* HTTPS\n* Executando na inicialização\n* Reinícios\n* Replicação (o número de processos rodando)\n* Memória\n* Passos anteriores antes de iniciar\n\nNa maioria dos casos, você provavelmente não desejará usar nenhuma imagem base e, em vez disso, **construir uma imagem de contêiner do zero** baseada na imagem oficial do Docker Python.\n\nTendo cuidado com a **ordem** das instruções no `Dockerfile` e o **cache do Docker**, você pode **minimizar os tempos de construção**, para maximizar sua produtividade (e evitar o tédio). 😎\n"
  },
  {
    "path": "docs/pt/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\nVocê pode implantar sua aplicação FastAPI no [FastAPI Cloud](https://fastapicloud.com) com um **único comando**; entre na lista de espera, caso ainda não tenha feito isso. 🚀\n\n## Login { #login }\n\nCertifique-se de que você já tem uma conta no **FastAPI Cloud** (nós convidamos você a partir da lista de espera 😉).\n\nDepois, faça login:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## Implantar { #deploy }\n\nAgora, implante sua aplicação, com **um único comando**:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nÉ isso! Agora você pode acessar sua aplicação nesse URL. ✨\n\n## Sobre o FastAPI Cloud { #about-fastapi-cloud }\n\nO **[FastAPI Cloud](https://fastapicloud.com)** é desenvolvido pelo mesmo autor e equipe por trás do **FastAPI**.\n\nEle simplifica o processo de **criar**, **implantar** e **acessar** uma API com esforço mínimo.\n\nTraz a mesma **experiência do desenvolvedor** de criar aplicações com FastAPI para **implantá-las** na nuvem. 🎉\n\nEle também cuidará da maioria das coisas de que você precisaria ao implantar uma aplicação, como:\n\n* HTTPS\n* Replicação, com dimensionamento automático baseado em requests\n* etc.\n\nO FastAPI Cloud é o patrocinador principal e provedor de financiamento dos projetos open source do ecossistema *FastAPI and friends*. ✨\n\n## Implantar em outros provedores de nuvem { #deploy-to-other-cloud-providers }\n\nFastAPI é open source e baseado em padrões. Você pode implantar aplicações FastAPI em qualquer provedor de nuvem que escolher.\n\nSiga os tutoriais do seu provedor de nuvem para implantar aplicações FastAPI com esse provedor. 🤓\n\n## Implantar no seu próprio servidor { #deploy-your-own-server }\n\nTambém vou lhe ensinar, mais adiante neste guia de **Implantação**, todos os detalhes, para que você possa entender o que está acontecendo, o que precisa acontecer, ou como implantar aplicações FastAPI por conta própria, inclusive nos seus próprios servidores. 🤓\n"
  },
  {
    "path": "docs/pt/docs/deployment/https.md",
    "content": "# Sobre HTTPS { #about-https }\n\nÉ fácil assumir que HTTPS é algo que é apenas \"habilitado\" ou não.\n\nMas é bem mais complexo do que isso.\n\n/// tip | Dica\n\nSe você está com pressa ou não se importa, continue com as seções seguintes para instruções passo a passo para configurar tudo com diferentes técnicas.\n\n///\n\nPara aprender o básico de HTTPS do ponto de vista do consumidor, verifique [https://howhttps.works/](https://howhttps.works/).\n\nAgora, a partir de uma perspectiva do desenvolvedor, aqui estão algumas coisas para ter em mente ao pensar em HTTPS:\n\n* Para HTTPS, o servidor precisa ter \"certificados\" gerados por um terceiro.\n    * Esses certificados são na verdade adquiridos de um terceiro, eles não são simplesmente \"gerados\".\n* Certificados têm um tempo de vida.\n    * Eles expiram.\n    * E então eles precisam ser renovados, adquirindo-os novamente de um terceiro.\n* A criptografia da conexão acontece no nível TCP.\n    * Essa é uma camada abaixo do HTTP.\n    * Portanto, o manuseio do certificado e da criptografia é feito antes do HTTP.\n* O TCP não sabe sobre \"domínios\". Apenas sobre endereços IP.\n    * As informações sobre o domínio específico solicitado vão nos dados HTTP.\n* Os certificados HTTPS “certificam” um determinado domínio, mas o protocolo e a encriptação acontecem ao nível do TCP, antes de sabermos de que domínio se trata.\n* Por padrão, isso significa que você só pode ter um certificado HTTPS por endereço IP.\n    * Não importa o tamanho do seu servidor ou quão pequeno cada aplicativo que você tem nele possa ser.\n    * No entanto, existe uma solução para isso.\n* Há uma extensão para o protocolo TLS (aquele que lida com a criptografia no nível TCP, antes do HTTP) chamada [<abbr title=\"Server Name Indication - Indicação do Nome do Servidor\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication).\n    * Esta extensão SNI permite que um único servidor (com um único endereço IP) tenha vários certificados HTTPS e atenda a vários domínios / aplicativos HTTPS.\n    * Para que isso funcione, um único componente (programa) em execução no servidor, ouvindo no endereço IP público, deve ter todos os certificados HTTPS no servidor.\n* Depois de obter uma conexão segura, o protocolo de comunicação ainda é HTTP.\n    * Os conteúdos são criptografados, embora sejam enviados com o protocolo HTTP.\n\nÉ uma prática comum ter um programa/servidor HTTP em execução no servidor (máquina, host, etc.) e gerenciar todas as partes HTTPS: recebendo as requisições HTTPS encriptadas, enviando as solicitações HTTP descriptografadas para o aplicativo HTTP real em execução no mesmo servidor (a aplicação FastAPI, neste caso), pegar a resposta HTTP do aplicativo, criptografá-la usando o certificado HTTPS apropriado e enviá-la de volta ao cliente usando HTTPS. Este servidor é frequentemente chamado de [Proxy de Terminação TLS](https://en.wikipedia.org/wiki/TLS_termination_proxy).\n\nAlgumas das opções que você pode usar como Proxy de Terminação TLS são:\n\n* Traefik (que também pode gerenciar a renovação de certificados)\n* Caddy (que também pode gerenciar a renovação de certificados)\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\nAntes de Let's Encrypt, esses certificados HTTPS eram vendidos por terceiros confiáveis.\n\nO processo de aquisição de um desses certificados costumava ser complicado, exigia bastante papelada e os certificados eram bastante caros.\n\nMas então o [Let's Encrypt](https://letsencrypt.org/) foi criado.\n\nEle é um projeto da Linux Foundation que fornece certificados HTTPS gratuitamente. De forma automatizada. Esses certificados usam toda a segurança criptográfica padrão e têm vida curta (cerca de 3 meses), então a segurança é, na verdade, melhor por causa do seu lifespan reduzido.\n\nOs domínios são verificados com segurança e os certificados são gerados automaticamente. Isso também permite automatizar a renovação desses certificados.\n\nA ideia é automatizar a aquisição e renovação desses certificados, para que você tenha HTTPS seguro, de graça e para sempre.\n\n## HTTPS para Desenvolvedores { #https-for-developers }\n\nAqui está um exemplo de como uma API HTTPS poderia ser estruturada, passo a passo, com foco principal nas ideias relevantes para desenvolvedores.\n\n### Nome do domínio { #domain-name }\n\nA etapa inicial provavelmente seria adquirir algum nome de domínio. Então, você iria configurá-lo em um servidor DNS (possivelmente no mesmo provedor em nuvem).\n\nVocê provavelmente usaria um servidor em nuvem (máquina virtual) ou algo parecido, e ele teria um <dfn title=\"Não muda ao longo do tempo. Não é dinâmico.\">fixo</dfn> Endereço IP público.\n\nNo(s) servidor(es) DNS, você configuraria um registro (um `A record`) para apontar seu domínio para o endereço IP público do seu servidor.\n\nVocê provavelmente fará isso apenas uma vez, na primeira vez em que tudo estiver sendo configurado.\n\n/// tip | Dica\n\nEssa parte do Nome do Domínio se dá muito antes do HTTPS, mas como tudo depende do domínio e endereço IP público, vale a pena mencioná-la aqui.\n\n///\n\n### DNS { #dns }\n\nAgora vamos focar em todas as partes que realmente fazem parte do HTTPS.\n\nPrimeiro, o navegador iria verificar com os servidores DNS qual o IP do domínio, nesse caso, `someapp.example.com`.\n\nOs servidores DNS iriam informar o navegador para utilizar algum endereço IP específico. Esse seria o endereço IP público em uso no seu servidor, que você configurou nos servidores DNS.\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### Início do Handshake TLS { #tls-handshake-start }\n\nO navegador então irá comunicar-se com esse endereço IP na porta 443 (a porta HTTPS).\n\nA primeira parte dessa comunicação é apenas para estabelecer a conexão entre o cliente e o servidor e para decidir as chaves criptográficas a serem utilizadas, etc.\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\nEsse interação entre o cliente e o servidor para estabelecer uma conexão TLS é chamada de Handshake TLS.\n\n### TLS com a Extensão SNI { #tls-with-sni-extension }\n\nApenas um processo no servidor pode se conectar a uma porta em um endereço IP. Poderiam existir outros processos conectados em outras portas desse mesmo endereço IP, mas apenas um para cada combinação de endereço IP e porta.\n\nTLS (HTTPS) usa a porta `443` por padrão. Então essa é a porta que precisamos.\n\nComo apenas um único processo pode se comunicar com essa porta, o processo que faria isso seria o Proxy de Terminação TLS.\n\nO Proxy de Terminação TLS teria acesso a um ou mais certificados TLS (certificados HTTPS).\n\nUtilizando a extensão SNI discutida acima, o Proxy de Terminação TLS iria checar qual dos certificados TLS (HTTPS) disponíveis deve ser usado para essa conexão, utilizando o que corresponda ao domínio esperado pelo cliente.\n\nNesse caso, ele usaria o certificado para `someapp.example.com`.\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\nO cliente já confia na entidade que gerou o certificado TLS (nesse caso, o Let's Encrypt, mas veremos sobre isso mais tarde), então ele pode verificar que o certificado é válido.\n\nEntão, utilizando o certificado, o cliente e o Proxy de Terminação TLS decidem como encriptar o resto da comunicação TCP. Isso completa a parte do Handshake TLS.\n\nApós isso, o cliente e o servidor possuem uma conexão TCP encriptada, que é provida pelo TLS. E então eles podem usar essa conexão para começar a comunicação HTTP propriamente dita.\n\nE isso resume o que é HTTPS, apenas HTTP simples dentro de uma conexão TLS segura em vez de uma conexão TCP pura (não encriptada).\n\n/// tip | Dica\n\nPercebe que a encriptação da comunicação acontece no nível do TCP, não no nível do HTTP.\n\n///\n\n### Solicitação HTTPS { #https-request }\n\nAgora que o cliente e servidor (especialmente o navegador e o Proxy de Terminação TLS) possuem uma conexão TCP encriptada, eles podem iniciar a comunicação HTTP.\n\nEntão, o cliente envia uma solicitação HTTPS. Que é apenas uma solicitação HTTP sobre uma conexão TLS encriptada.\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### Desencripte a Solicitação { #decrypt-the-request }\n\nO Proxy de Terminação TLS então usaria a encriptação combinada para desencriptar a solicitação, e transmitiria a solicitação básica (desencriptada) para o processo executando a aplicação (por exemplo, um processo com Uvicorn executando a aplicação FastAPI).\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### Resposta HTTP { #http-response }\n\nA aplicação processaria a solicitação e retornaria uma resposta HTTP básica (não encriptada) para o Proxy de Terminação TLS.\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### Resposta HTTPS { #https-response }\n\nO Proxy de Terminação TLS iria encriptar a resposta utilizando a criptografia combinada anteriormente (que foi definida com o certificado para `someapp.example.com`), e devolveria para o navegador.\n\nNo próximo passo, o navegador verifica que a resposta é válida e encriptada com a chave criptográfica correta, etc. E depois desencripta a resposta e a processa.\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\nO cliente (navegador) saberá que a resposta vem do servidor correto por que ela usa a criptografia que foi combinada entre eles usando o certificado HTTPS anterior.\n\n### Múltiplas Aplicações { #multiple-applications }\n\nPodem existir múltiplas aplicações em execução no mesmo servidor (ou servidores), por exemplo: outras APIs ou um banco de dados.\n\nApenas um processo pode estar vinculado a um IP e porta (o Proxy de Terminação TLS, por exemplo), mas outras aplicações/processos também podem estar em execução no(s) servidor(es), desde que não tentem usar a mesma combinação de IP público e porta.\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\nDessa forma, o Proxy de Terminação TLS pode gerenciar o HTTPS e os certificados de múltiplos domínios, para múltiplas aplicações, e então transmitir as requisições para a aplicação correta em cada caso.\n\n### Renovação de Certificados { #certificate-renewal }\n\nEm algum momento futuro, cada certificado irá expirar (aproximadamente 3 meses após a aquisição).\n\nE então, haverá outro programa (em alguns casos pode ser o próprio Proxy de Terminação TLS) que irá interagir com o Let's Encrypt e renovar o(s) certificado(s).\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\nOs certificados TLS são associados com um nome de domínio, e não a um endereço IP.\n\nEntão para renovar os certificados, o programa de renovação precisa provar para a autoridade (Let's Encrypt) que ele realmente \"possui\" e controla esse domínio.\n\nPara fazer isso, e acomodar as necessidades de diferentes aplicações, existem diferentes opções para esse programa. Algumas escolhas populares são:\n\n* Modificar alguns registros DNS\n    * Para isso, o programa de renovação precisa ter suporte às APIs do provedor DNS, então, dependendo do provedor DNS que você utilize, isso pode ou não ser uma opção viável.\n* Executar como um servidor (ao menos durante o processo de aquisição do certificado) no endereço IP público associado com o domínio.\n    * Como dito anteriormente, apenas um processo pode estar ligado a uma porta e IP específicos.\n    * Essa é uma dos motivos que fazem utilizar o mesmo Proxy de Terminação TLS para gerenciar a renovação de certificados ser tão útil.\n    * Caso contrário, você pode ter que parar a execução do Proxy de Terminação TLS momentaneamente, inicializar o programa de renovação para adquirir os certificados, depois configurá-los com o Proxy de Terminação TLS, e então reiniciar o Proxy de Terminação TLS. Isso não é o ideal, já que sua(s) aplicação(ões) não vão estar disponíveis enquanto o Proxy de Terminação TLS estiver desligado.\n\nTodo esse processo de renovação, enquanto o aplicativo ainda funciona, é uma das principais razões para preferir um sistema separado para gerenciar HTTPS com um Proxy de Terminação TLS em vez de usar os certificados TLS no servidor da aplicação diretamente (e.g. com o Uvicorn).\n\n## Cabeçalhos encaminhados por Proxy { #proxy-forwarded-headers }\n\nAo usar um proxy para lidar com HTTPS, seu servidor de aplicação (por exemplo, Uvicorn via FastAPI CLI) não sabe nada sobre o processo de HTTPS; ele se comunica com HTTP simples com o Proxy de Terminação TLS.\n\nEsse proxy normalmente define alguns cabeçalhos HTTP dinamicamente antes de transmitir a requisição para o servidor de aplicação, para informar ao servidor de aplicação que a requisição está sendo encaminhada pelo proxy.\n\n/// note | Detalhes Técnicos\n\nOs cabeçalhos do proxy são:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\nNo entanto, como o servidor de aplicação não sabe que está atrás de um proxy confiável, por padrão ele não confiaria nesses cabeçalhos.\n\nMas você pode configurar o servidor de aplicação para confiar nos cabeçalhos encaminhados enviados pelo proxy. Se você estiver usando o FastAPI CLI, pode usar a opção de CLI `--forwarded-allow-ips` para dizer de quais IPs ele deve confiar nesses cabeçalhos encaminhados.\n\nPor exemplo, se o servidor de aplicação só estiver recebendo comunicação do proxy confiável, você pode defini-lo como `--forwarded-allow-ips=\"*\"` para fazê-lo confiar em todos os IPs de entrada, já que ele só receberá requisições de seja lá qual for o IP usado pelo proxy.\n\nDessa forma, a aplicação seria capaz de saber qual é sua própria URL pública, se está usando HTTPS, o domínio, etc.\n\nIsso seria útil, por exemplo, para lidar corretamente com redirecionamentos.\n\n/// tip | Dica\n\nVocê pode saber mais sobre isso na documentação em [Atrás de um Proxy - Habilitar cabeçalhos encaminhados pelo proxy](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)\n\n///\n\n## Recapitulando { #recap }\n\nPossuir HTTPS habilitado na sua aplicação é bastante importante, e até crítico na maioria dos casos. A maior parte do esforço que você tem que colocar sobre o HTTPS como desenvolvedor está em entender esses conceitos e como eles funcionam.\n\nMas uma vez que você saiba o básico de HTTPS para desenvolvedores, você pode combinar e configurar diferentes ferramentas facilmente para gerenciar tudo de uma forma simples.\n\nEm alguns dos próximos capítulos, eu mostrarei para você vários exemplos concretos de como configurar o HTTPS para aplicações FastAPI. 🔒\n"
  },
  {
    "path": "docs/pt/docs/deployment/index.md",
    "content": "# Implantação { #deployment }\n\nImplantar uma aplicação **FastAPI** é relativamente fácil.\n\n## O que significa Implantação { #what-does-deployment-mean }\n\n**Implantar** uma aplicação significa executar as etapas necessárias para torná-la **disponível para os usuários**.\n\nPara uma **web API**, isso normalmente envolve colocá-la em uma **máquina remota**, com um **programa de servidor** que ofereça bom desempenho, estabilidade, etc., de modo que seus **usuários** possam **acessar** a aplicação com eficiência e sem interrupções ou problemas.\n\nIsso contrasta com as fases de **desenvolvimento**, em que você está constantemente alterando o código, quebrando e consertando, parando e reiniciando o servidor de desenvolvimento, etc.\n\n## Estratégias de Implantação { #deployment-strategies }\n\nHá várias maneiras de fazer isso, dependendo do seu caso de uso específico e das ferramentas que você utiliza.\n\nVocê pode **implantar um servidor** por conta própria usando uma combinação de ferramentas, pode usar um **serviço em nuvem** que faça parte do trabalho por você, entre outras opções.\n\nPor exemplo, nós, a equipe por trás do FastAPI, criamos [**FastAPI Cloud**](https://fastapicloud.com), para tornar a implantação de aplicações FastAPI na nuvem o mais simples possível, com a mesma experiência de desenvolvimento de trabalhar com o FastAPI.\n\nVou mostrar alguns dos principais conceitos que você provavelmente deve ter em mente ao implantar uma aplicação **FastAPI** (embora a maior parte se aplique a qualquer outro tipo de aplicação web).\n\nVocê verá mais detalhes para ter em mente e algumas das técnicas para fazer isso nas próximas seções. ✨\n"
  },
  {
    "path": "docs/pt/docs/deployment/manually.md",
    "content": "# Execute um Servidor Manualmente { #run-a-server-manually }\n\n## Utilize o comando `fastapi run` { #use-the-fastapi-run-command }\n\nEm resumo, utilize o comando `fastapi run` para inicializar sua aplicação FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\nIsto deve funcionar para a maioria dos casos. 😎\n\nVocê pode utilizar esse comando, por exemplo, para iniciar sua aplicação **FastAPI** em um contêiner, em um servidor, etc.\n\n## Servidores ASGI { #asgi-servers }\n\nVamos nos aprofundar um pouco mais em detalhes.\n\nFastAPI utiliza um padrão para construir frameworks e servidores web em Python chamado <abbr title=\"Asynchronous Server Gateway Interface - Interface de Gateway de Servidor Assíncrono\">ASGI</abbr>. FastAPI é um framework web ASGI.\n\nA principal coisa que você precisa para executar uma aplicação **FastAPI** (ou qualquer outra aplicação ASGI) em uma máquina de servidor remoto é um programa de servidor ASGI como o **Uvicorn**, que é o que vem por padrão no comando `fastapi`.\n\nExistem diversas alternativas, incluindo:\n\n* [Uvicorn](https://www.uvicorn.dev/): um servidor ASGI de alta performance.\n* [Hypercorn](https://hypercorn.readthedocs.io/): um servidor ASGI compatível com HTTP/2, Trio e outros recursos.\n* [Daphne](https://github.com/django/daphne): servidor ASGI construído para Django Channels.\n* [Granian](https://github.com/emmett-framework/granian): um servidor HTTP Rust para aplicações Python.\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit é um runtime de aplicação web leve e versátil.\n\n## Máquina Servidora e Programa Servidor { #server-machine-and-server-program }\n\nExiste um pequeno detalhe sobre estes nomes para se manter em mente. 💡\n\nA palavra \"**servidor**\" é comumente usada para se referir tanto ao computador remoto/nuvem (a máquina física ou virtual) quanto ao programa que está sendo executado nessa máquina (por exemplo, Uvicorn).\n\nApenas tenha em mente que quando você ler \"servidor\" em geral, isso pode se referir a uma dessas duas coisas.\n\nQuando se refere à máquina remota, é comum chamá-la de **servidor**, mas também de **máquina**, **VM** (máquina virtual), **nó**. Todos esses termos se referem a algum tipo de máquina remota, normalmente executando Linux, onde você executa programas.\n\n## Instale o Programa Servidor { #install-the-server-program }\n\nQuando você instala o FastAPI, ele vem com um servidor de produção, o Uvicorn, e você pode iniciá-lo com o comando `fastapi run`.\n\nMas você também pode instalar um servidor ASGI manualmente.\n\nCertifique-se de criar um [ambiente virtual](../virtual-environments.md), ativá-lo e, em seguida, você pode instalar a aplicação do servidor.\n\nPor exemplo, para instalar o Uvicorn:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\nUm processo semelhante se aplicaria a qualquer outro programa de servidor ASGI.\n\n/// tip | Dica\n\nAdicionando o `standard`, o Uvicorn instalará e usará algumas dependências extras recomendadas.\n\nIsso inclui o `uvloop`, a substituição de alto desempenho para `asyncio`, que fornece um grande aumento de desempenho de concorrência.\n\nQuando você instala o FastAPI com algo como `pip install \"fastapi[standard]\"`, você já obtém `uvicorn[standard]` também.\n\n///\n\n## Execute o Programa Servidor { #run-the-server-program }\n\nSe você instalou um servidor ASGI manualmente, normalmente precisará passar uma string de importação em um formato especial para que ele importe sua aplicação FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note | Nota\n\nO comando `uvicorn main:app` refere-se a:\n\n* `main`: o arquivo `main.py` (o \"módulo\" Python).\n* `app`: o objeto criado dentro de `main.py` com a linha `app = FastAPI()`.\n\nÉ equivalente a:\n\n```Python\nfrom main import app\n```\n\n///\n\nCada programa de servidor ASGI alternativo teria um comando semelhante, você pode ler mais na documentação respectiva.\n\n/// warning | Atenção\n\nUvicorn e outros servidores suportam a opção `--reload` que é útil durante o desenvolvimento.\n\nA opção `--reload` consome muito mais recursos, é mais instável, etc.\n\nEla ajuda muito durante o **desenvolvimento**, mas você **não deve** usá-la em **produção**.\n\n///\n\n## Conceitos de Implantação { #deployment-concepts }\n\nEsses exemplos executam o programa do servidor (por exemplo, Uvicorn), iniciando **um único processo**, ouvindo em todos os IPs (`0.0.0.0`) em uma porta predefinida (por exemplo, `80`).\n\nEsta é a ideia básica. Mas você provavelmente vai querer cuidar de algumas coisas adicionais, como:\n\n* Segurança - HTTPS\n* Executando na inicialização\n* Reinicializações\n* Replicação (o número de processos em execução)\n* Memória\n* Passos anteriores antes de começar\n\nVou te contar mais sobre cada um desses conceitos, como pensar sobre eles e alguns exemplos concretos com estratégias para lidar com eles nos próximos capítulos. 🚀\n"
  },
  {
    "path": "docs/pt/docs/deployment/server-workers.md",
    "content": "# Trabalhadores do Servidor - Uvicorn com Trabalhadores { #server-workers-uvicorn-with-workers }\n\nVamos rever os conceitos de implantação anteriores:\n\n* Segurança - HTTPS\n* Executando na inicialização\n* Reinicializações\n* **Replicação (o número de processos em execução)**\n* Memória\n* Etapas anteriores antes de iniciar\n\nAté este ponto, com todos os tutoriais nos documentos, você provavelmente estava executando um **programa de servidor**, por exemplo, usando o comando `fastapi`, que executa o Uvicorn, executando um **único processo**.\n\nAo implantar aplicativos, você provavelmente desejará ter alguma **replicação de processos** para aproveitar **vários núcleos** e poder lidar com mais solicitações.\n\nComo você viu no capítulo anterior sobre [Conceitos de implantação](concepts.md), há várias estratégias que você pode usar.\n\nAqui mostrarei como usar o **Uvicorn** com **processos de trabalho** usando o comando `fastapi` ou o comando `uvicorn` diretamente.\n\n/// info | Informação\n\nSe você estiver usando contêineres, por exemplo com Docker ou Kubernetes, falarei mais sobre isso no próximo capítulo: [FastAPI em contêineres - Docker](docker.md).\n\nEm particular, ao executar no **Kubernetes** você provavelmente **não** vai querer usar vários trabalhadores e, em vez disso, executar **um único processo Uvicorn por contêiner**, mas falarei sobre isso mais adiante neste capítulo.\n\n///\n\n## Vários trabalhadores { #multiple-workers }\n\nVocê pode iniciar vários trabalhadores com a opção de linha de comando `--workers`:\n\n//// tab | `fastapi`\n\nSe você usar o comando `fastapi`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\nSe você preferir usar o comando `uvicorn` diretamente:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\nA única opção nova aqui é `--workers` informando ao Uvicorn para iniciar 4 processos de trabalho.\n\nVocê também pode ver que ele mostra o **PID** de cada processo, `27365` para o processo pai (este é o **gerenciador de processos**) e um para cada processo de trabalho: `27368`, `27369`, `27370` e `27367`.\n\n## Conceitos de Implantação { #deployment-concepts }\n\nAqui você viu como usar vários **trabalhadores** para **paralelizar** a execução do aplicativo, aproveitar **vários núcleos** na CPU e conseguir atender **mais solicitações**.\n\nDa lista de conceitos de implantação acima, o uso de trabalhadores ajudaria principalmente com a parte da **replicação** e um pouco com as **reinicializações**, mas você ainda precisa cuidar dos outros:\n\n* **Segurança - HTTPS**\n* **Executando na inicialização**\n* ***Reinicializações***\n* Replicação (o número de processos em execução)\n* **Memória**\n* **Etapas anteriores antes de iniciar**\n\n## Contêineres e Docker { #containers-and-docker }\n\nNo próximo capítulo sobre [FastAPI em contêineres - Docker](docker.md), explicarei algumas estratégias que você pode usar para lidar com os outros **conceitos de implantação**.\n\nVou mostrar como **construir sua própria imagem do zero** para executar um único processo Uvicorn. É um processo simples e provavelmente é o que você gostaria de fazer ao usar um sistema de gerenciamento de contêineres distribuídos como o **Kubernetes**.\n\n## Recapitular { #recap }\n\nVocê pode usar vários processos de trabalho com a opção CLI `--workers` com os comandos `fastapi` ou `uvicorn` para aproveitar as vantagens de **CPUs multi-core** e executar **vários processos em paralelo**.\n\nVocê pode usar essas ferramentas e ideias se estiver configurando **seu próprio sistema de implantação** enquanto cuida dos outros conceitos de implantação.\n\nConfira o próximo capítulo para aprender sobre **FastAPI** com contêineres (por exemplo, Docker e Kubernetes). Você verá que essas ferramentas têm maneiras simples de resolver os outros **conceitos de implantação** também. ✨\n"
  },
  {
    "path": "docs/pt/docs/deployment/versions.md",
    "content": "# Sobre as versões do FastAPI { #about-fastapi-versions }\n\n**FastAPI** já está sendo usado em produção em muitas aplicações e sistemas. E a cobertura de testes é mantida em 100%. Mas seu desenvolvimento ainda está avançando rapidamente.\n\nNovas funcionalidades são adicionadas com frequência, bugs são corrigidos regularmente e o código continua melhorando continuamente.\n\nÉ por isso que as versões atuais ainda são `0.x.x`, isso reflete que cada versão pode potencialmente ter mudanças significativas. Isso segue as convenções de [Versionamento Semântico](https://semver.org/).\n\nVocê pode criar aplicações de produção com **FastAPI** agora mesmo (e provavelmente já vem fazendo isso há algum tempo), apenas certifique-se de usar uma versão que funcione corretamente com o resto do seu código.\n\n## Fixe a sua versão de `fastapi` { #pin-your-fastapi-version }\n\nA primeira coisa que você deve fazer é \"fixar\" a versão do **FastAPI** que você está utilizando na versão mais recente específica que você sabe que funciona corretamente para a sua aplicação.\n\nPor exemplo, suponha que você esteja usando a versão `0.112.0` em sua aplicação.\n\nSe você usa um arquivo `requirements.txt`, você poderia especificar a versão com:\n\n```txt\nfastapi[standard]==0.112.0\n```\n\nisso significaria que você usaria exatamente a versão `0.112.0`.\n\nOu você também poderia fixá-la com:\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\nisso significaria que você usaria as versões `0.112.0` ou superiores, mas menores que `0.113.0`, por exemplo, a versão `0.112.2` ainda seria aceita.\n\nSe você usa qualquer outra ferramenta para gerenciar suas instalações, como `uv`, Poetry, Pipenv ou outras, todas elas têm uma forma de definir versões específicas para seus pacotes.\n\n## Versões disponíveis { #available-versions }\n\nVocê pode ver as versões disponíveis (por exemplo, para verificar qual é a mais recente) nas [Release Notes](../release-notes.md).\n\n## Sobre versões { #about-versions }\n\nSeguindo as convenções de Versionamento Semântico, qualquer versão abaixo de `1.0.0` pode potencialmente adicionar mudanças significativas.\n\nFastAPI também segue a convenção de que qualquer alteração de versão \"PATCH\" é para correções de bugs e mudanças que não quebram compatibilidade.\n\n/// tip | Dica\n\nO \"PATCH\" é o último número, por exemplo, em `0.2.3`, a versão PATCH é `3`.\n\n///\n\nLogo, você deveria conseguir fixar a versão, como:\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\nMudanças significativas e novas funcionalidades são adicionadas em versões \"MINOR\".\n\n/// tip | Dica\n\nO \"MINOR\" é o número do meio, por exemplo, em `0.2.3`, a versão MINOR é `2`.\n\n///\n\n## Atualizando as versões do FastAPI { #upgrading-the-fastapi-versions }\n\nVocê deveria adicionar testes para a sua aplicação.\n\nCom **FastAPI** isso é muito fácil (graças ao Starlette), veja a documentação: [Testes](../tutorial/testing.md)\n\nDepois que você tiver testes, você pode atualizar a sua versão do **FastAPI** para uma mais recente e se certificar de que todo o seu código está funcionando corretamente executando seus testes.\n\nSe tudo estiver funcionando, ou após você realizar as alterações necessárias e todos os testes estiverem passando, então você pode fixar sua versão de `fastapi` para essa versão mais recente.\n\n## Sobre Starlette { #about-starlette }\n\nNão é recomendado fixar a versão de `starlette`.\n\nVersões diferentes de **FastAPI** utilizarão uma versão específica e mais recente de Starlette.\n\nEntão, você pode deixar **FastAPI** usar a versão correta do Starlette.\n\n## Sobre Pydantic { #about-pydantic }\n\nPydantic inclui os testes para **FastAPI** em seus próprios testes, então novas versões do Pydantic (acima de `1.0.0`) são sempre compatíveis com FastAPI.\n\nVocê pode fixar o Pydantic em qualquer versão acima de `1.0.0` que funcione para você.\n\nPor exemplo:\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/pt/docs/editor-support.md",
    "content": "# Suporte a Editores { #editor-support }\n\nA [FastAPI Extension](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) oficial melhora seu fluxo de trabalho de desenvolvimento com descoberta e navegação de *operação de rota*, além de implantação no FastAPI Cloud e transmissão ao vivo de logs.\n\nPara mais detalhes sobre a extensão, consulte o README no [repositório do GitHub](https://github.com/fastapi/fastapi-vscode).\n\n## Configuração e Instalação { #setup-and-installation }\n\nA **FastAPI Extension** está disponível para [VS Code](https://code.visualstudio.com/) e [Cursor](https://www.cursor.com/). Pode ser instalada diretamente pelo painel de Extensões de cada editor, pesquisando por \"FastAPI\" e selecionando a extensão publicada por **FastAPI Labs**. A extensão também funciona em editores no navegador, como [vscode.dev](https://vscode.dev) e [github.dev](https://github.dev).\n\n### Descoberta da Aplicação { #application-discovery }\n\nPor padrão, a extensão descobre automaticamente aplicações FastAPI no seu workspace procurando por arquivos que instanciam `FastAPI()`. Se a detecção automática não funcionar para a estrutura do seu projeto, você pode especificar um ponto de entrada via `[tool.fastapi]` em `pyproject.toml` ou pela configuração `fastapi.entryPoint` do VS Code usando notação de módulo (por exemplo, `myapp.main:app`).\n\n## Funcionalidades { #features }\n\n- **Explorador de Operações de Rota** - Uma visualização em árvore na barra lateral de todas as <dfn title=\"rotas, endpoints\">*operações de rota*</dfn> da sua aplicação. Clique para ir diretamente a qualquer definição de rota ou de router.\n- **Pesquisa de Rotas** - Pesquise por path, método ou nome com <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (no macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>).\n- **Navegação com CodeLens** - Links clicáveis acima das chamadas do cliente de testes (por exemplo, `client.get('/items')`) que levam à *operação de rota* correspondente, facilitando a navegação entre testes e implementação.\n- **Implantar no FastAPI Cloud** - Implantação com um clique da sua aplicação no [FastAPI Cloud](https://fastapicloud.com/).\n- **Transmitir logs da aplicação** - Transmissão em tempo real dos logs da aplicação implantada no FastAPI Cloud, com filtragem por nível e busca de texto.\n\nSe quiser se familiarizar com as funcionalidades da extensão, você pode abrir o walkthrough da extensão acessando a Paleta de Comandos (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> ou no macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>), selecionando \"Welcome: Open walkthrough...\" e, em seguida, escolhendo o walkthrough \"Get started with FastAPI\".\n"
  },
  {
    "path": "docs/pt/docs/environment-variables.md",
    "content": "# Variáveis de Ambiente { #environment-variables }\n\n/// tip | Dica\n\nSe você já sabe o que são \"variáveis de ambiente\" e como usá-las, pode pular esta seção.\n\n///\n\nUma variável de ambiente (também conhecida como \"**env var**\") é uma variável que existe **fora** do código Python, no **sistema operacional**, e pode ser lida pelo seu código Python (ou por outros programas também).\n\nVariáveis de ambiente podem ser úteis para lidar com **configurações** do aplicativo, como parte da **instalação** do Python, etc.\n\n## Criar e Usar Variáveis de Ambiente { #create-and-use-env-vars }\n\nVocê pode **criar** e usar variáveis de ambiente no **shell (terminal)**, sem precisar do Python:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Você pode criar uma variável de ambiente MY_NAME com\n$ export MY_NAME=\"Wade Wilson\"\n\n// Então você pode usá-la com outros programas, como\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Criar uma variável de ambiente MY_NAME\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Usá-la com outros programas, como\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## Ler Variáveis de Ambiente no Python { #read-env-vars-in-python }\n\nVocê também pode criar variáveis de ambiente **fora** do Python, no terminal (ou com qualquer outro método) e depois **lê-las no Python**.\n\nPor exemplo, você poderia ter um arquivo `main.py` com:\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip | Dica\n\nO segundo argumento para [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) é o valor padrão a ser retornado.\n\nSe não for fornecido, é `None` por padrão, Aqui fornecemos `\"World\"` como o valor padrão a ser usado.\n\n///\n\nEntão você poderia chamar esse programa Python:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Aqui ainda não definimos a variável de ambiente\n$ python main.py\n\n// Como não definimos a variável de ambiente, obtemos o valor padrão\n\nHello World from Python\n\n// Mas se criarmos uma variável de ambiente primeiro\n$ export MY_NAME=\"Wade Wilson\"\n\n// E então chamar o programa novamente\n$ python main.py\n\n// Agora ele pode ler a variável de ambiente\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Aqui ainda não definimos a variável de ambiente\n$ python main.py\n\n// Como não definimos a variável de ambiente, obtemos o valor padrão\n\nHello World from Python\n\n// Mas se criarmos uma variável de ambiente primeiro\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// E então chamar o programa novamente\n$ python main.py\n\n// Agora ele pode ler a variável de ambiente\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\nComo as variáveis de ambiente podem ser definidas fora do código, mas podem ser lidas pelo código e não precisam ser armazenadas (com versão no `git`) com o restante dos arquivos, é comum usá-las para configurações ou **definições**.\n\nVocê também pode criar uma variável de ambiente apenas para uma **invocação específica do programa**, que só está disponível para aquele programa e apenas pela duração dele.\n\nPara fazer isso, crie-a na mesma linha, antes do próprio programa:\n\n<div class=\"termy\">\n\n```console\n// Criar uma variável de ambiente MY_NAME para esta chamada de programa\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// Agora ele pode ler a variável de ambiente\n\nHello Wade Wilson from Python\n\n// A variável de ambiente não existe mais depois\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip | Dica\n\nVocê pode ler mais sobre isso em [The Twelve-Factor App: Config](https://12factor.net/config).\n\n///\n\n## Tipos e Validação { #types-and-validation }\n\nEssas variáveis de ambiente só podem lidar com **strings de texto**, pois são externas ao Python e precisam ser compatíveis com outros programas e com o resto do sistema (e até mesmo com diferentes sistemas operacionais, como Linux, Windows, macOS).\n\nIsso significa que **qualquer valor** lido em Python de uma variável de ambiente **será uma `str`**, e qualquer conversão para um tipo diferente ou qualquer validação precisa ser feita no código.\n\nVocê aprenderá mais sobre como usar variáveis de ambiente para lidar com **configurações do aplicativo** no [Guia do Usuário Avançado - Configurações e Variáveis de Ambiente](./advanced/settings.md).\n\n## Variável de Ambiente `PATH` { #path-environment-variable }\n\nExiste uma variável de ambiente **especial** chamada **`PATH`** que é usada pelos sistemas operacionais (Linux, macOS, Windows) para encontrar programas para executar.\n\nO valor da variável `PATH` é uma longa string composta por diretórios separados por dois pontos `:` no Linux e macOS, e por ponto e vírgula `;` no Windows.\n\nPor exemplo, a variável de ambiente `PATH` poderia ter esta aparência:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nIsso significa que o sistema deve procurar programas nos diretórios:\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\nIsso significa que o sistema deve procurar programas nos diretórios:\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\nQuando você digita um **comando** no terminal, o sistema operacional **procura** o programa em **cada um dos diretórios** listados na variável de ambiente `PATH`.\n\nPor exemplo, quando você digita `python` no terminal, o sistema operacional procura um programa chamado `python` no **primeiro diretório** dessa lista.\n\nSe ele o encontrar, então ele o **usará**. Caso contrário, ele continua procurando nos **outros diretórios**.\n\n### Instalando o Python e Atualizando o `PATH` { #installing-python-and-updating-the-path }\n\nDurante a instalação do Python, você pode ser questionado sobre a atualização da variável de ambiente `PATH`.\n\n//// tab | Linux, macOS\n\nVamos supor que você instale o Python e ele fique em um diretório `/opt/custompython/bin`.\n\nSe você concordar em atualizar a variável de ambiente `PATH`, o instalador adicionará `/opt/custompython/bin` para a variável de ambiente `PATH`.\n\nPoderia parecer assim:\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\nDessa forma, ao digitar `python` no terminal, o sistema encontrará o programa Python em `/opt/custompython/bin` (último diretório) e o utilizará.\n\n////\n\n//// tab | Windows\n\nDigamos que você instala o Python e ele acaba em um diretório `C:\\opt\\custompython\\bin`.\n\nSe você disser sim para atualizar a variável de ambiente `PATH`, o instalador adicionará `C:\\opt\\custompython\\bin` à variável de ambiente `PATH`.\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\nDessa forma, quando você digitar `python` no terminal, o sistema encontrará o programa Python em `C:\\opt\\custompython\\bin` (o último diretório) e o utilizará.\n\n////\n\nEntão, se você digitar:\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\nO sistema **encontrará** o programa `python` em `/opt/custompython/bin` e o executará.\n\nSeria aproximadamente equivalente a digitar:\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\nO sistema **encontrará** o programa `python` em `C:\\opt\\custompython\\bin\\python` e o executará.\n\nSeria aproximadamente equivalente a digitar:\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\nEssas informações serão úteis ao aprender sobre [Ambientes Virtuais](virtual-environments.md).\n\n## Conclusão { #conclusion }\n\nCom isso, você deve ter uma compreensão básica do que são **variáveis ​​de ambiente** e como usá-las em Python.\n\nVocê também pode ler mais sobre elas na [Wikipedia para Variáveis ​​de Ambiente](https://en.wikipedia.org/wiki/Environment_variable).\n\nEm muitos casos, não é muito óbvio como as variáveis ​​de ambiente seriam úteis e aplicáveis ​​imediatamente. Mas elas continuam aparecendo em muitos cenários diferentes quando você está desenvolvendo, então é bom saber sobre elas.\n\nPor exemplo, você precisará dessas informações na próxima seção, sobre [Ambientes Virtuais](virtual-environments.md).\n"
  },
  {
    "path": "docs/pt/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - interface de linha de comando\">CLI</abbr>** é um programa de linha de comando que você pode usar para servir sua aplicação FastAPI, gerenciar seu projeto FastAPI e muito mais.\n\nQuando você instala o FastAPI (por exemplo, com `pip install \"fastapi[standard]\"`), ele vem com um programa de linha de comando que você pode executar no terminal.\n\nPara executar sua aplicação FastAPI durante o desenvolvimento, você pode usar o comando `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip | Dica\n\nEm produção, você usaria `fastapi run` em vez de `fastapi dev`. 🚀\n\n///\n\nInternamente, o **FastAPI CLI** usa o [Uvicorn](https://www.uvicorn.dev), um servidor ASGI de alta performance e pronto para produção. 😎\n\nO CLI `fastapi` tentará detectar automaticamente a aplicação FastAPI a ser executada, assumindo que seja um objeto chamado `app` em um arquivo `main.py` (ou algumas outras variantes).\n\nMas você pode configurar explicitamente a aplicação a ser usada.\n\n## Configure o `entrypoint` da aplicação em `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nVocê pode configurar onde sua aplicação está localizada em um arquivo `pyproject.toml`, assim:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nEsse `entrypoint` dirá ao comando `fastapi` que ele deve importar a aplicação assim:\n\n```python\nfrom main import app\n```\n\nSe o seu código estivesse estruturado assim:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nEntão você definiria o `entrypoint` como:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\no que seria equivalente a:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` com caminho { #fastapi-dev-with-path }\n\nVocê também pode passar o caminho do arquivo para o comando `fastapi dev`, e ele deduzirá o objeto da aplicação FastAPI a usar:\n\n```console\n$ fastapi dev main.py\n```\n\nMas você teria que lembrar de passar o caminho correto toda vez que chamar o comando `fastapi`.\n\nAlém disso, outras ferramentas podem não conseguir encontrá-la, por exemplo a [Extensão do VS Code](editor-support.md) ou a [FastAPI Cloud](https://fastapicloud.com), então é recomendado usar o `entrypoint` em `pyproject.toml`.\n\n## `fastapi dev` { #fastapi-dev }\n\nExecutar `fastapi dev` inicia o modo de desenvolvimento.\n\nPor padrão, o **recarregamento automático** está ativado, recarregando o servidor automaticamente quando você faz mudanças no seu código. Isso consome muitos recursos e pode ser menos estável do que quando está desativado. Você deveria usá-lo apenas no desenvolvimento. Ele também escuta no endereço IP `127.0.0.1`, que é o IP para a sua máquina se comunicar apenas consigo mesma (`localhost`).\n\n## `fastapi run` { #fastapi-run }\n\nExecutar `fastapi run` inicia o FastAPI em modo de produção.\n\nPor padrão, o **recarregamento automático** está desativado. Ele também escuta no endereço IP `0.0.0.0`, o que significa todos os endereços IP disponíveis; dessa forma, ficará acessível publicamente para qualquer pessoa que consiga se comunicar com a máquina. É assim que você normalmente o executaria em produção, por exemplo, em um contêiner.\n\nNa maioria dos casos, você teria (e você deveria ter) um \"proxy de terminação\" tratando o HTTPS por cima; isso dependerá de como você faz o deploy da sua aplicação, seu provedor pode fazer isso por você ou talvez seja necessário que você configure isso por conta própria.\n\n/// tip | Dica\n\nVocê pode aprender mais sobre isso na [documentação de deployment](deployment/index.md).\n\n///\n"
  },
  {
    "path": "docs/pt/docs/features.md",
    "content": "# Recursos { #features }\n\n## Recursos do FastAPI { #fastapi-features }\n\n**FastAPI** te oferece o seguinte:\n\n### Baseado em padrões abertos { #based-on-open-standards }\n\n* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) para criação de APIs, incluindo declarações de <dfn title=\"também conhecido como: endpoints, rotas\">caminho</dfn> <dfn title=\"também conhecido como métodos HTTP, como POST, GET, PUT, DELETE\">operações</dfn>, parâmetros, requisições de corpo, segurança etc.\n* Documentação automática de modelos de dados com [**JSON Schema**](https://json-schema.org/) (já que o OpenAPI em si é baseado no JSON Schema).\n* Projetado em torno desses padrões, após um estudo meticuloso. Em vez de uma camada improvisada por cima.\n* Isso também permite o uso de **geração de código do cliente** automaticamente em muitas linguagens.\n\n### Documentação automática { #automatic-docs }\n\nDocumentação interativa da API e navegação web da interface de usuário. Como o framework é baseado no OpenAPI, há várias opções, 2 incluídas por padrão.\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui), com navegação interativa, chame e teste sua API diretamente do navegador.\n\n![Interação Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Documentação alternativa da API com [**ReDoc**](https://github.com/Rebilly/ReDoc).\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Apenas Python moderno { #just-modern-python }\n\nTudo é baseado no padrão das declarações de **tipos do Python** (graças ao Pydantic). Nenhuma sintaxe nova para aprender. Apenas o padrão moderno do Python.\n\nSe 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).\n\nVocê escreve Python padrão com tipos:\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# Declare uma variável como str\n# e obtenha suporte do editor dentro da função\ndef main(user_id: str):\n    return user_id\n\n\n# Um modelo do Pydantic\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\nQue então pode ser usado como:\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n/// info | Informação\n\n`**second_user_data` quer dizer:\n\nPasse as chaves e valores do dicionário `second_user_data` diretamente como argumentos chave-valor, equivalente a: `User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### Suporte de editores { #editor-support }\n\nTodo o framework foi projetado para ser fácil e intuitivo de usar, todas as decisões foram testadas em vários editores antes do início do desenvolvimento, para garantir a melhor experiência de desenvolvimento.\n\nNa pesquisa de desenvolvedores Python, ficou claro [que um dos recursos mais utilizados é o \"preenchimento automático\"](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).\n\nTodo o framework **FastAPI** é feito para satisfazer isso. O preenchimento automático funciona em todos os lugares.\n\nVocê raramente precisará voltar à documentação.\n\nAqui está como o editor poderá te ajudar:\n\n* no [Visual Studio Code](https://code.visualstudio.com/):\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* no [PyCharm](https://www.jetbrains.com/pycharm/):\n\n![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\nVocê terá preenchimento automático no seu código que você poderia considerar impossível antes. Como por exemplo, a chave `price` dentro do corpo JSON (que poderia ter sido aninhado) que vem de uma requisição.\n\nSem a necessidade de digitar nomes de chaves erroneamente, ir e voltar entre documentações, ou rolar pela página para descobrir se você utilizou `username` ou `user_name`.\n\n### Breve { #short }\n\nHá **padrões** sensíveis para tudo, com configurações adicionais em todos os lugares. Todos os parâmetros podem ser regulados para fazer o que você precisa e para definir a API que você necessita.\n\nPor padrão, tudo **\"simplesmente funciona\"**.\n\n### Validação { #validation }\n\n* Validação para a maioria dos (ou todos?) **tipos de dados** do Python, incluindo:\n    * objetos JSON (`dict`).\n    * arrays JSON (`list`), definindo tipos dos itens.\n    * campos String (`str`), definindo tamanho mínimo e máximo.\n    * Numbers (`int`, `float`) com valores mínimos e máximos, etc.\n\n* Validação de tipos mais exóticos, como:\n    * URL.\n    * Email.\n    * UUID.\n    * ...e outros.\n\nToda a validação é controlada pelo robusto e bem estabelecido **Pydantic**.\n\n### Segurança e autenticação { #security-and-authentication }\n\nSegurança e autenticação integradas. Sem nenhum compromisso com bancos de dados ou modelos de dados.\n\nTodos os esquemas de seguranças definidos no OpenAPI, incluindo:\n\n* HTTP Basic.\n* **OAuth2** (também com **tokens JWT**). Confira o tutorial em [OAuth2 com JWT](tutorial/security/oauth2-jwt.md).\n* Chaves de API em:\n    * Headers.\n    * parâmetros da Query.\n    * Cookies etc.\n\nAlém disso, todos os recursos de segurança do Starlette (incluindo **cookies de sessão**).\n\nTudo construído como ferramentas e componentes reutilizáveis que são fáceis de integrar com seus sistemas, armazenamento de dados, banco de dados relacionais e não-relacionais etc.\n\n### Injeção de dependência { #dependency-injection }\n\nFastAPI inclui um sistema de <dfn title='também conhecido como \"componentes\", \"recursos\", \"serviços\", \"provedores\"'><strong>injeção de dependência</strong></dfn> extremamente fácil de usar, mas extremamente poderoso.\n\n* Mesmo dependências podem ter dependências, criando uma hierarquia ou **\"grafo\" de dependências**.\n* Tudo **automaticamente controlado** pelo framework.\n* Todas as dependências podem pedir dados das requisições e **ampliar** as restrições e documentação automática da **operação de rota**.\n* **Validação automática** mesmo para parâmetros da *operação de rota* definidos em dependências.\n* Suporte para sistemas de autenticação complexos, **conexões com banco de dados** etc.\n* **Sem comprometer** os bancos de dados, frontends etc. Mas fácil integração com todos eles.\n\n### \"Plug-ins\" ilimitados { #unlimited-plug-ins }\n\nOu, de outra forma, sem a necessidade deles, importe e use o código que precisar.\n\nQualquer integração é projetada para ser tão simples de usar (com dependências) que você pode criar um \"plug-in\" para suas aplicações com 2 linhas de código usando a mesma estrutura e sintaxe para as suas *operações de rota*.\n\n### Testado { #tested }\n\n* 100% <dfn title=\"A quantidade de código que é testada automaticamente\">de cobertura de testes</dfn>.\n* 100% do código com <dfn title=\"Anotações de tipo do Python, com isso seu editor e ferramentas externas podem te dar um suporte melhor\">anotações de tipo</dfn>.\n* Usado para aplicações em produção.\n\n## Recursos do Starlette { #starlette-features }\n\n**FastAPI** é totalmente compatível com (e baseado no) [**Starlette**](https://www.starlette.dev/). Então, qualquer código adicional Starlette que você tiver, também funcionará.\n\n`FastAPI` é na verdade uma sub-classe do `Starlette`. Então, se você já conhece ou usa Starlette, a maioria das funcionalidades se comportará da mesma forma.\n\nCom **FastAPI**, você terá todos os recursos do **Starlette** (já que FastAPI é apenas um Starlette com esteróides):\n\n* Desempenho realmente impressionante. É [um dos frameworks Python disponíveis mais rápidos, a par com o **NodeJS** e **Go**](https://github.com/encode/starlette#performance).\n* Suporte a **WebSocket**.\n* Tarefas em processo background.\n* Eventos na inicialização e encerramento.\n* Cliente de testes construído sobre HTTPX.\n* Respostas em **CORS**, GZip, Static Files, Streaming.\n* Suporte a **Session e Cookie**.\n* 100% de cobertura de testes.\n* 100% do código utilizando anotações de tipo.\n\n## Recursos do Pydantic { #pydantic-features }\n\n**FastAPI** é totalmente compatível com (e baseado no) [**Pydantic**](https://docs.pydantic.dev/). Então, qualquer código Pydantic adicional que você tiver, também funcionará.\n\nIncluindo bibliotecas externas também baseadas no Pydantic, como <abbr title=\"Object-Relational Mapper - Mapeador Objeto-Relacional\">ORM</abbr>s e <abbr title=\"Object-Document Mapper - Mapeador Objeto-Documento\">ODM</abbr>s para bancos de dados.\n\nIsso também significa que em muitos casos você poderá passar o mesmo objeto que você receber de uma requisição **diretamente para o banco de dados**, já que tudo é validado automaticamente.\n\nO mesmo se aplica no sentido inverso, em muitos casos você poderá simplesmente passar o objeto que você recebeu do banco de dados **diretamente para o cliente**.\n\nCom **FastAPI** você terá todos os recursos do **Pydantic** (já que FastAPI utiliza o Pydantic para todo o controle dos dados):\n\n* **Sem pegadinhas**:\n    * Sem novas definições de esquema de micro-linguagem para aprender.\n    * Se você conhece os tipos do Python, você sabe como usar o Pydantic.\n* Vai bem com o/a seu/sua **<abbr title=\"Integrated Development Environment - Ambiente de Desenvolvimento Integrado: similar a um editor de código\">IDE</abbr>/<dfn title=\"Um programa que confere erros de código\">linter</dfn>/cérebro**:\n    * Como as estruturas de dados do Pydantic são apenas instâncias de classes que você define, o preenchimento automático, linting, mypy e a sua intuição devem funcionar corretamente com seus dados validados.\n* Valida **estruturas complexas**:\n    * Use modelos hierárquicos do Pydantic, `List` e `Dict` do `typing` do Python, etc.\n    * Validadores permitem que esquemas de dados complexos sejam limpos e facilmente definidos, conferidos e documentados como JSON Schema.\n    * Você pode ter **JSONs aninhados** profundamente e tê-los todos validados e anotados.\n* **Extensível**:\n    * Pydantic permite que tipos de dados personalizados sejam definidos ou você pode estender a validação com métodos em um modelo decorado com seu decorador de validador.\n* 100% de cobertura de testes.\n"
  },
  {
    "path": "docs/pt/docs/help-fastapi.md",
    "content": "# Ajude o FastAPI - Obtenha ajuda { #help-fastapi-get-help }\n\nVocê gosta do **FastAPI**?\n\nVocê gostaria de ajudar o FastAPI, outras pessoas usuárias e o autor?\n\nOu você gostaria de obter ajuda com o **FastAPI**?\n\nHá maneiras muito simples de ajudar (várias envolvem apenas um ou dois cliques).\n\nE também há várias formas de obter ajuda.\n\n## Assine a newsletter { #subscribe-to-the-newsletter }\n\nVocê pode assinar a (infrequente) [newsletter do **FastAPI and friends**](newsletter.md) para ficar por dentro de:\n\n* Notícias sobre FastAPI e amigos 🚀\n* Tutoriais 📝\n* Funcionalidades ✨\n* Mudanças incompatíveis 🚨\n* Dicas e truques ✅\n\n## Siga o FastAPI no X (Twitter) { #follow-fastapi-on-x-twitter }\n\n[Siga @fastapi no **X (Twitter)**](https://x.com/fastapi) para receber as últimas notícias sobre o **FastAPI**. 🐦\n\n## Dê uma estrela ao **FastAPI** no GitHub { #star-fastapi-in-github }\n\nVocê pode “marcar com estrela” o FastAPI no GitHub (clicando no botão de estrela no canto superior direito): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). ⭐️\n\nAo adicionar uma estrela, outras pessoas conseguirão encontrá-lo com mais facilidade e verão que já foi útil para muita gente.\n\n## Acompanhe o repositório no GitHub para lançamentos { #watch-the-github-repository-for-releases }\n\nVocê pode “acompanhar” (watch) o FastAPI no GitHub (clicando no botão “watch” no canto superior direito): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nLá você pode selecionar “Apenas lançamentos”.\n\nFazendo isso, você receberá notificações (no seu email) sempre que houver um novo lançamento (uma nova versão) do **FastAPI** com correções de bugs e novas funcionalidades.\n\n## Conecte-se com o autor { #connect-with-the-author }\n\nVocê pode se conectar [comigo (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com), o autor.\n\nVocê pode:\n\n* [Me seguir no **GitHub**](https://github.com/tiangolo).\n    * Ver outros projetos Open Source que criei e que podem ajudar você.\n    * Me seguir para saber quando eu criar um novo projeto Open Source.\n* [Me seguir no **X (Twitter)**](https://x.com/tiangolo) ou no [Mastodon](https://fosstodon.org/@tiangolo).\n    * Me contar como você usa o FastAPI (adoro saber disso).\n    * Ficar sabendo quando eu fizer anúncios ou lançar novas ferramentas.\n    * Você também pode [seguir @fastapi no X (Twitter)](https://x.com/fastapi) (uma conta separada).\n* [Me seguir no **LinkedIn**](https://www.linkedin.com/in/tiangolo/).\n    * Ver quando eu fizer anúncios ou lançar novas ferramentas (embora eu use mais o X (Twitter) 🤷‍♂).\n* Ler o que escrevo (ou me seguir) no [**Dev.to**](https://dev.to/tiangolo) ou no [**Medium**](https://medium.com/@tiangolo).\n    * Ler outras ideias, artigos e conhecer ferramentas que criei.\n    * Me seguir para ver quando eu publicar algo novo.\n\n## Tweet sobre o **FastAPI** { #tweet-about-fastapi }\n\n[Tweet sobre o **FastAPI**](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi) e conte para mim e para outras pessoas por que você gosta dele. 🎉\n\nEu adoro saber como o **FastAPI** está sendo usado, o que você tem curtido nele, em qual projeto/empresa você o utiliza, etc.\n\n## Vote no FastAPI { #vote-for-fastapi }\n\n* [Vote no **FastAPI** no Slant](https://www.slant.co/options/34241/~fastapi-review).\n* [Vote no **FastAPI** no AlternativeTo](https://alternativeto.net/software/fastapi/about/).\n* [Diga que você usa o **FastAPI** no StackShare](https://stackshare.io/pypi-fastapi).\n\n## Ajude outras pessoas com perguntas no GitHub { #help-others-with-questions-in-github }\n\nVocê pode tentar ajudar outras pessoas com suas perguntas em:\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\nEm muitos casos você já pode saber a resposta para aquelas perguntas. 🤓\n\nSe você estiver ajudando muitas pessoas com suas perguntas, você se tornará um(a) [Especialista em FastAPI](fastapi-people.md#fastapi-experts) oficial. 🎉\n\nApenas lembre-se, o ponto mais importante é: tente ser gentil. As pessoas chegam com frustrações e, em muitos casos, não perguntam da melhor forma, mas tente ao máximo ser gentil. 🤗\n\nA ideia é que a comunidade do **FastAPI** seja gentil e acolhedora. Ao mesmo tempo, não aceite bullying ou comportamentos desrespeitosos com outras pessoas. Temos que cuidar uns dos outros.\n\n---\n\nVeja como ajudar outras pessoas com perguntas (em discussions ou issues):\n\n### Entenda a pergunta { #understand-the-question }\n\n* Verifique se você consegue entender qual é o **objetivo** e o caso de uso de quem está perguntando.\n\n* Depois verifique se a pergunta (a grande maioria são perguntas) está **clara**.\n\n* Em muitos casos a pergunta feita é sobre uma solução imaginada pela pessoa usuária, mas pode haver uma solução **melhor**. Se você entender melhor o problema e o caso de uso, pode sugerir uma **solução alternativa** melhor.\n\n* Se você não entender a pergunta, peça mais **detalhes**.\n\n### Reproduza o problema { #reproduce-the-problem }\n\nNa maioria dos casos e na maioria das perguntas há algo relacionado ao **código original** da pessoa.\n\nEm muitos casos ela só copia um fragmento do código, mas isso não é suficiente para **reproduzir o problema**.\n\n* Você pode pedir que forneçam um [exemplo mínimo, reproduzível](https://stackoverflow.com/help/minimal-reproducible-example), que você possa **copiar e colar** e executar localmente para ver o mesmo erro ou comportamento que elas estão vendo, ou para entender melhor o caso de uso.\n\n* Se você estiver muito generoso, pode tentar **criar um exemplo** assim você mesmo, apenas com base na descrição do problema. Só tenha em mente que isso pode levar bastante tempo e pode ser melhor pedir primeiro que esclareçam o problema.\n\n### Sugira soluções { #suggest-solutions }\n\n* Depois de conseguir entender a pergunta, você pode dar uma possível **resposta**.\n\n* Em muitos casos, é melhor entender o **problema subjacente ou caso de uso**, pois pode haver uma forma melhor de resolver do que aquilo que estão tentando fazer.\n\n### Peça para encerrar { #ask-to-close }\n\nSe a pessoa responder, há uma grande chance de você ter resolvido o problema, parabéns, **você é um herói**! 🦸\n\n* Agora, se isso resolveu o problema, você pode pedir para:\n\n    * No GitHub Discussions: marcar o comentário como a **resposta**.\n    * No GitHub Issues: **encerrar** a issue.\n\n## Acompanhe o repositório do GitHub { #watch-the-github-repository }\n\nVocê pode “acompanhar” (watch) o FastAPI no GitHub (clicando no botão “watch” no canto superior direito): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nSe você selecionar “Acompanhando” em vez de “Apenas lançamentos”, receberá notificações quando alguém criar uma nova issue ou pergunta. Você também pode especificar que quer ser notificado apenas sobre novas issues, ou discussions, ou PRs, etc.\n\nAssim você pode tentar ajudar a resolver essas questões.\n\n## Faça perguntas { #ask-questions }\n\nVocê pode [criar uma nova pergunta](https://github.com/fastapi/fastapi/discussions/new?category=questions) no repositório do GitHub, por exemplo para:\n\n* Fazer uma **pergunta** ou perguntar sobre um **problema**.\n* Sugerir uma nova **funcionalidade**.\n\n**Nota**: se você fizer isso, então vou pedir que você também ajude outras pessoas. 😉\n\n## Revise Pull Requests { #review-pull-requests }\n\nVocê pode me ajudar revisando pull requests de outras pessoas.\n\nNovamente, por favor tente ao máximo ser gentil. 🤗\n\n---\n\nVeja o que ter em mente e como revisar um pull request:\n\n### Entenda o problema { #understand-the-problem }\n\n* Primeiro, garanta que você **entendeu o problema** que o pull request tenta resolver. Pode haver uma discussão mais longa em uma Discussion ou issue do GitHub.\n\n* Também há uma boa chance de o pull request não ser realmente necessário porque o problema pode ser resolvido de uma **forma diferente**. Aí você pode sugerir ou perguntar sobre isso.\n\n### Não se preocupe com estilo { #dont-worry-about-style }\n\n* Não se preocupe muito com coisas como estilos de mensagens de commit, eu vou fazer squash e merge personalizando o commit manualmente.\n\n* Também não se preocupe com regras de estilo, já há ferramentas automatizadas verificando isso.\n\nE se houver qualquer outra necessidade de estilo ou consistência, vou pedir diretamente, ou vou adicionar commits por cima com as mudanças necessárias.\n\n### Verifique o código { #check-the-code }\n\n* Verifique e leia o código, veja se faz sentido, **execute localmente** e veja se realmente resolve o problema.\n\n* Depois **comente** dizendo que você fez isso, é assim que saberei que você realmente verificou.\n\n/// info | Informação\n\nInfelizmente, eu não posso simplesmente confiar em PRs que têm várias aprovações.\n\nJá aconteceu várias vezes de haver PRs com 3, 5 ou mais aprovações, provavelmente porque a descrição é atraente, mas quando eu verifico os PRs, eles estão quebrados, têm um bug, ou não resolvem o problema que afirmam resolver. 😅\n\nPor isso, é realmente importante que você leia e execute o código, e me avise nos comentários que você fez isso. 🤓\n\n///\n\n* Se o PR puder ser simplificado de alguma forma, você pode pedir isso, mas não há necessidade de ser exigente demais, pode haver muitos pontos de vista subjetivos (e eu terei o meu também 🙈), então é melhor focar nas coisas fundamentais.\n\n### Testes { #tests }\n\n* Me ajude a verificar se o PR tem **testes**.\n\n* Verifique se os testes **falham** antes do PR. 🚨\n\n* Depois verifique se os testes **passam** após o PR. ✅\n\n* Muitos PRs não têm testes, você pode **lembrar** a pessoa de adicionar testes, ou até **sugerir** alguns testes você mesmo. Essa é uma das coisas que consomem mais tempo e você pode ajudar muito com isso.\n\n* Depois também comente o que você testou, assim vou saber que você verificou. 🤓\n\n## Crie um Pull Request { #create-a-pull-request }\n\nVocê pode [contribuir](contributing.md) com o código-fonte fazendo Pull Requests, por exemplo:\n\n* Para corrigir um erro de digitação que você encontrou na documentação.\n* Para compartilhar um artigo, vídeo ou podcast que você criou ou encontrou sobre o FastAPI, [editando este arquivo](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml).\n    * Garanta que você adicione seu link no início da seção correspondente.\n* Para ajudar a [traduzir a documentação](contributing.md#translations) para seu idioma.\n    * Você também pode ajudar a revisar as traduções criadas por outras pessoas.\n* Para propor novas seções de documentação.\n* Para corrigir uma issue/bug existente.\n    * Garanta que você adicione testes.\n* Para adicionar uma nova funcionalidade.\n    * Garanta que você adicione testes.\n    * Garanta que você adicione documentação se for relevante.\n\n## Ajude a manter o FastAPI { #help-maintain-fastapi }\n\nAjude-me a manter o **FastAPI**! 🤓\n\nHá muito trabalho a fazer e, para a maior parte dele, **VOCÊ** pode ajudar.\n\nAs principais tarefas que você pode fazer agora são:\n\n* [Ajudar outras pessoas com perguntas no GitHub](#help-others-with-questions-in-github) (veja a seção acima).\n* [Revisar Pull Requests](#review-pull-requests) (veja a seção acima).\n\nEssas duas tarefas são as que **mais consomem tempo**. Esse é o principal trabalho de manter o FastAPI.\n\nSe você puder me ajudar com isso, **você está me ajudando a manter o FastAPI** e garantindo que ele continue **avançando mais rápido e melhor**. 🚀\n\n## Entre no chat { #join-the-chat }\n\nEntre no 👥 [servidor de chat do Discord](https://discord.gg/VQjSZaeJmf) 👥 e converse com outras pessoas da comunidade FastAPI.\n\n/// tip | Dica\n\nPara perguntas, faça-as no [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions), há uma chance muito maior de você receber ajuda pelos [Especialistas em FastAPI](fastapi-people.md#fastapi-experts).\n\nUse o chat apenas para outras conversas gerais.\n\n///\n\n### Não use o chat para perguntas { #dont-use-the-chat-for-questions }\n\nTenha em mente que, como os chats permitem uma “conversa mais livre”, é fácil fazer perguntas muito gerais e mais difíceis de responder, então você pode acabar não recebendo respostas.\n\nNo GitHub, o template vai orientar você a escrever a pergunta certa para que você consiga obter uma boa resposta com mais facilidade, ou até resolver o problema sozinho antes de perguntar. E no GitHub eu consigo garantir que sempre vou responder tudo, mesmo que leve algum tempo. Eu pessoalmente não consigo fazer isso com os sistemas de chat. 😅\n\nAs conversas nos sistemas de chat também não são tão fáceis de pesquisar quanto no GitHub, então perguntas e respostas podem se perder na conversa. E somente as que estão no GitHub contam para você se tornar um(a) [Especialista em FastAPI](fastapi-people.md#fastapi-experts), então é bem provável que você receba mais atenção no GitHub.\n\nPor outro lado, há milhares de usuários nos sistemas de chat, então há uma grande chance de você encontrar alguém para conversar por lá quase o tempo todo. 😄\n\n## Patrocine o autor { #sponsor-the-author }\n\nSe o seu **produto/empresa** depende de ou está relacionado ao **FastAPI** e você quer alcançar suas pessoas usuárias, você pode patrocinar o autor (eu) através do [GitHub sponsors](https://github.com/sponsors/tiangolo). Dependendo do nível, você pode obter benefícios extras, como um selo na documentação. 🎁\n\n---\n\nObrigado! 🚀\n"
  },
  {
    "path": "docs/pt/docs/history-design-future.md",
    "content": "# História, Design e Futuro { #history-design-and-future }\n\nHá algum tempo, [um usuário **FastAPI** perguntou](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920):\n\n> Qual é a história desse projeto? Parece que surgiu do nada e se tornou incrível em poucas semanas [...]\n\nAqui está um pouco dessa história.\n\n## Alternativas { #alternatives }\n\nEu tenho criado APIs com requisitos complexos por vários anos (Aprendizado de Máquina, sistemas distribuídos, tarefas assíncronas, banco de dados NoSQL etc.), liderando vários times de desenvolvedores.\n\nComo parte disso, eu precisava investigar, testar e usar muitas alternativas.\n\nA história do **FastAPI** é, em grande parte, a história de seus predecessores.\n\nComo dito na seção [Alternativas](alternatives.md):\n\n<blockquote markdown=\"1\">\n\n**FastAPI** não existiria se não pelo trabalho anterior de outros.\n\nHá muitas ferramentas criadas antes que ajudaram a inspirar sua criação.\n\nEu estive evitando a criação de um novo _framework_ por vários anos. Primeiro tentei resolver todas as funcionalidades cobertas por **FastAPI** usando muitos _frameworks_, _plug-ins_ e ferramentas diferentes.\n\nMas em algum ponto, não havia outra opção senão criar algo que oferecia todas as funcionalidades, aproveitando as melhores ideias de ferramentas anteriores, e combinando-as da melhor maneira possível, usando funcionalidades da linguagem que nem estavam disponíveis antes (anotações de tipo do Python 3.6+).\n\n</blockquote>\n\n## Investigação { #investigation }\n\nAo usar todas as alternativas anteriores, eu tive a chance de aprender com todas elas, aproveitar ideias e combiná-las da melhor maneira que encontrei para mim e para os times de desenvolvedores com os quais trabalhava.\n\nPor exemplo, estava claro que idealmente ele deveria ser baseado nas anotações de tipo padrão do Python.\n\nTambém, a melhor abordagem era usar padrões já existentes.\n\nEntão, antes mesmo de começar a codificar o **FastAPI**, eu investi vários meses estudando as especificações do OpenAPI, JSON Schema, OAuth2 etc. Entendendo suas relações, sobreposições e diferenças.\n\n## Design { #design }\n\nEu então dediquei algum tempo projetando a \"API\" de desenvolvimento que eu queria como usuário (como um desenvolvedor usando o FastAPI).\n\nEu testei várias ideias nos editores Python mais populares: PyCharm, VS Code, e editores baseados no Jedi.\n\nPela última [Pesquisa do Desenvolvedor Python](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools), isso cobre cerca de 80% dos usuários.\n\nIsso significa que o **FastAPI** foi testado especificamente com os editores usados por 80% dos desenvolvedores Python. Como a maioria dos outros editores tendem a funcionar de forma similar, todos os seus benefícios devem funcionar para virtualmente todos os editores.\n\nDessa forma eu pude encontrar a melhor maneira de reduzir duplicação de código o máximo possível, ter preenchimento automático em todos os lugares, conferência de tipos e erros etc.\n\nTudo de uma forma que oferecesse a melhor experiência de desenvolvimento para todos os desenvolvedores.\n\n## Requisitos { #requirements }\n\nApós testar várias alternativas, eu decidi que usaria o [**Pydantic**](https://docs.pydantic.dev/) por suas vantagens.\n\nEntão eu contribuí com ele, para deixá-lo completamente de acordo com o JSON Schema, para dar suporte a diferentes maneiras de definir declarações de restrições, e melhorar o suporte a editores (conferências de tipos, preenchimento automático) baseado nos testes em vários editores.\n\nDurante o desenvolvimento, eu também contribuí com o [**Starlette**](https://www.starlette.dev/), outro requisito chave.\n\n## Desenvolvimento { #development }\n\nQuando comecei a criar o **FastAPI** de fato, a maior parte das peças já estavam encaixadas, o design estava definido, os requisitos e ferramentas já estavam prontos, e o conhecimento sobre os padrões e especificações estavam claros e frescos.\n\n## Futuro { #future }\n\nNesse ponto, já está claro que o **FastAPI** com suas ideias está sendo útil para muitas pessoas.\n\nEle está sendo escolhido em relação a alternativas anteriores por se adequar melhor em muitos casos.\n\nMuitos desenvolvedores e times já dependem do **FastAPI** para seus projetos (incluindo eu e meu time).\n\nMas ainda há muitas melhorias e funcionalidades a vir.\n\n**FastAPI** tem um grande futuro à frente.\n\nE [sua ajuda](help-fastapi.md) é muito bem-vinda.\n"
  },
  {
    "path": "docs/pt/docs/how-to/authentication-error-status-code.md",
    "content": "# Usar antigos códigos de status de erro de autenticação 403 { #use-old-403-authentication-error-status-codes }\n\nAntes da versão `0.122.0` do FastAPI, quando os utilitários de segurança integrados retornavam um erro ao cliente após uma falha na autenticação, eles usavam o código de status HTTP `403 Forbidden`.\n\nA partir da versão `0.122.0` do FastAPI, eles usam o código de status HTTP `401 Unauthorized`, mais apropriado, e retornam um cabeçalho `WWW-Authenticate` adequado na response, seguindo as especificações HTTP, [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized).\n\nMas, se por algum motivo seus clientes dependem do comportamento antigo, você pode voltar a ele sobrescrevendo o método `make_not_authenticated_error` nas suas classes de segurança.\n\nPor exemplo, você pode criar uma subclasse de `HTTPBearer` que retorne um erro `403 Forbidden` em vez do erro padrão `401 Unauthorized`:\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip | Dica\n\nPerceba que a função retorna a instância da exceção, ela não a lança. O lançamento é feito no restante do código interno.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/how-to/conditional-openapi.md",
    "content": "# OpenAPI condicional { #conditional-openapi }\n\nSe necessário, você pode usar configurações e variáveis de ambiente para configurar o OpenAPI condicionalmente dependendo do ambiente e até mesmo desativá-lo completamente.\n\n## Sobre segurança, APIs e documentação { #about-security-apis-and-docs }\n\nOcultar suas interfaces de usuário de documentação na produção não *deveria* ser a maneira de proteger sua API.\n\nIsso não adiciona nenhuma segurança extra à sua API; as *operações de rota* ainda estarão disponíveis onde estão.\n\nSe houver uma falha de segurança no seu código, ela ainda existirá.\n\nOcultar a documentação apenas torna mais difícil entender como interagir com sua API e pode dificultar sua depuração na produção. Pode ser considerado simplesmente uma forma de [Segurança através da obscuridade](https://en.wikipedia.org/wiki/Security_through_obscurity).\n\nSe você quiser proteger sua API, há várias coisas melhores que você pode fazer, por exemplo:\n\n* Certifique-se de ter modelos Pydantic bem definidos para seus corpos de request e respostas.\n* Configure quaisquer permissões e funções necessárias usando dependências.\n* Nunca armazene senhas em texto simples, apenas hashes de senha.\n* Implemente e use ferramentas criptográficas bem conhecidas, como pwdlib e tokens JWT, etc.\n* Adicione controles de permissão mais granulares com escopos OAuth2 quando necessário.\n* ...etc.\n\nNo entanto, você pode ter um caso de uso muito específico em que realmente precisa desabilitar a documentação da API para algum ambiente (por exemplo, para produção) ou dependendo de configurações de variáveis de ambiente.\n\n## OpenAPI condicional com configurações e variáveis de ambiente { #conditional-openapi-from-settings-and-env-vars }\n\nVocê pode usar facilmente as mesmas configurações do Pydantic para configurar sua OpenAPI gerada e as interfaces de usuário da documentação.\n\nPor exemplo:\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\nAqui declaramos a configuração `openapi_url` com o mesmo padrão de `\"/openapi.json\"`.\n\nE então a usamos ao criar a aplicação `FastAPI`.\n\nEntão você pode desabilitar o OpenAPI (incluindo a documentação da interface do usuário) definindo a variável de ambiente `OPENAPI_URL` como a string vazia, como:\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nEntão, se você acessar as URLs em `/openapi.json`, `/docs` ou `/redoc`, você receberá apenas um erro `404 Not Found` como:\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/pt/docs/how-to/configure-swagger-ui.md",
    "content": "# Configure a UI do Swagger { #configure-swagger-ui }\n\nVocê pode configurar alguns [parâmetros extras da UI do Swagger](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\nPara configurá-los, passe o argumento `swagger_ui_parameters` ao criar o objeto da aplicação `FastAPI()` ou para a função `get_swagger_ui_html()`.\n\n`swagger_ui_parameters` recebe um dicionário com as configurações passadas diretamente para o Swagger UI.\n\nO FastAPI converte as configurações para **JSON** para torná-las compatíveis com JavaScript, pois é disso que o Swagger UI precisa.\n\n## Desabilitar destaque de sintaxe { #disable-syntax-highlighting }\n\nPor exemplo, você pode desabilitar o destaque de sintaxe na UI do Swagger.\n\nSem alterar as configurações, o destaque de sintaxe é habilitado por padrão:\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\nMas você pode desabilitá-lo definindo `syntaxHighlight` como `False`:\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n...e então o Swagger UI não mostrará mais o destaque de sintaxe:\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## Alterar o tema { #change-the-theme }\n\nDa mesma forma que você pode definir o tema de destaque de sintaxe com a chave `\"syntaxHighlight.theme\"` (observe que há um ponto no meio):\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\nEssa configuração alteraria o tema de cores de destaque de sintaxe:\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## Alterar parâmetros de UI padrão do Swagger { #change-default-swagger-ui-parameters }\n\nO FastAPI inclui alguns parâmetros de configuração padrão apropriados para a maioria dos casos de uso.\n\nInclui estas configurações padrão:\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\nVocê pode substituir qualquer um deles definindo um valor diferente no argumento `swagger_ui_parameters`.\n\nPor exemplo, para desabilitar `deepLinking` você pode passar essas configurações para `swagger_ui_parameters`:\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## Outros parâmetros da UI do Swagger { #other-swagger-ui-parameters }\n\nPara ver todas as outras configurações possíveis que você pode usar, leia a [documentação oficial dos parâmetros da UI do Swagger](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\n## Configurações somente JavaScript { #javascript-only-settings }\n\nA UI do Swagger também permite que outras configurações sejam objetos **somente JavaScript** (por exemplo, funções JavaScript).\n\nO FastAPI também inclui estas configurações `presets` somente para JavaScript:\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\nEsses são objetos **JavaScript**, não strings, então você não pode passá-los diretamente do código Python.\n\nSe você precisar usar configurações somente JavaScript como essas, você pode usar um dos métodos acima. Substitua toda a *operação de rota* do Swagger UI e escreva manualmente qualquer JavaScript que você precisar.\n"
  },
  {
    "path": "docs/pt/docs/how-to/custom-docs-ui-assets.md",
    "content": "# Recursos Estáticos Personalizados para a UI de Documentação (Hospedagem Própria) { #custom-docs-ui-static-assets-self-hosting }\n\nA documentação da API usa **Swagger UI** e **ReDoc**, e cada um deles precisa de alguns arquivos JavaScript e CSS.\n\nPor padrão, esses arquivos são fornecidos por um <abbr title=\"Content Delivery Network - Rede de Entrega de Conteúdo: Um serviço, normalmente composto por vários servidores, que fornece arquivos estáticos, como JavaScript e CSS. É comumente usado para servir esses arquivos a partir do servidor mais próximo do cliente, melhorando o desempenho.\">CDN</abbr>.\n\nMas é possível personalizá-los, você pode definir um CDN específico ou providenciar os arquivos você mesmo.\n\n## CDN Personalizado para JavaScript e CSS { #custom-cdn-for-javascript-and-css }\n\nVamos supor que você deseja usar um <abbr title=\"Content Delivery Network - Rede de Entrega de Conteúdo\">CDN</abbr> diferente, por exemplo, você deseja usar `https://unpkg.com/`.\n\nIsso pode ser útil se, por exemplo, você mora em um país que restringe algumas URLs.\n\n### Desativar a documentação automática { #disable-the-automatic-docs }\n\nO primeiro passo é desativar a documentação automática, pois por padrão, ela usa o CDN padrão.\n\nPara desativá-los, defina suas URLs como `None` ao criar sua aplicação FastAPI:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### Incluir a documentação personalizada { #include-the-custom-docs }\n\nAgora você pode criar as *operações de rota* para a documentação personalizada.\n\nVocê pode reutilizar as funções internas do FastAPI para criar as páginas HTML para a documentação e passar os argumentos necessários:\n\n* `openapi_url`: a URL onde a página HTML para a documentação pode obter o esquema OpenAPI para a sua API. Você pode usar aqui o atributo `app.openapi_url`.\n* `title`: o título da sua API.\n* `oauth2_redirect_url`: você pode usar `app.swagger_ui_oauth2_redirect_url` aqui para usar o padrão.\n* `swagger_js_url`: a URL onde a página HTML para a sua documentação do Swagger UI pode obter o arquivo **JavaScript**. Este é o URL do CDN personalizado.\n* `swagger_css_url`: a URL onde a página HTML para a sua documentação do Swagger UI pode obter o arquivo **CSS**. Este é o URL do CDN personalizado.\n\nE de forma semelhante para o ReDoc...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip | Dica\n\nA *operação de rota* para `swagger_ui_redirect` é um auxiliar para quando você usa OAuth2.\n\nSe você integrar sua API com um provedor OAuth2, você poderá autenticar e voltar para a documentação da API com as credenciais adquiridas. E interagir com ela usando a autenticação OAuth2 real.\n\nSwagger UI lidará com isso nos bastidores para você, mas ele precisa desse auxiliar de \"redirecionamento\".\n\n///\n\n### Criar uma *operação de rota* para testar { #create-a-path-operation-to-test-it }\n\nAgora, para poder testar se tudo funciona, crie uma *operação de rota*:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### Teste { #test-it }\n\nAgora, você deve ser capaz de ir para a documentação em [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), e recarregar a página, ela carregará esses recursos do novo CDN.\n\n## Hospedagem Própria de JavaScript e CSS para a documentação { #self-hosting-javascript-and-css-for-docs }\n\nHospedar o JavaScript e o CSS pode ser útil se, por exemplo, você precisa que seu aplicativo continue funcionando mesmo offline, sem acesso aberto à Internet, ou em uma rede local.\n\nAqui você verá como providenciar esses arquivos você mesmo, na mesma aplicação FastAPI, e configurar a documentação para usá-los.\n\n### Estrutura de Arquivos do Projeto { #project-file-structure }\n\nVamos supor que a estrutura de arquivos do seu projeto se pareça com isso:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\nAgora crie um diretório para armazenar esses arquivos estáticos.\n\nSua nova estrutura de arquivos poderia se parecer com isso:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### Baixe os arquivos { #download-the-files }\n\nBaixe os arquivos estáticos necessários para a documentação e coloque-os no diretório `static/`.\n\nVocê provavelmente pode clicar com o botão direito em cada link e selecionar uma opção semelhante a \"Salvar link como...\".\n\n**Swagger UI** usa os arquivos:\n\n* [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n* [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\nE o **ReDoc** usa o arquivo:\n\n* [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\nDepois disso, sua estrutura de arquivos deve se parecer com:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### Prover os arquivos estáticos { #serve-the-static-files }\n\n* Importe `StaticFiles`.\n* \"Monte\" a instância `StaticFiles()` em um caminho específico.\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### Teste os arquivos estáticos { #test-the-static-files }\n\nInicialize seu aplicativo e vá para [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js).\n\nVocê deverá ser ver um arquivo JavaScript muito longo para o **ReDoc**.\n\nEsse arquivo pode começar com algo como:\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\nIsso confirma que você está conseguindo fornecer arquivos estáticos do seu aplicativo e que você colocou os arquivos estáticos para a documentação no local correto.\n\nAgora, podemos configurar o aplicativo para usar esses arquivos estáticos para a documentação.\n\n### Desativar a documentação automática para arquivos estáticos { #disable-the-automatic-docs-for-static-files }\n\nDa mesma forma que ao usar um CDN personalizado, o primeiro passo é desativar a documentação automática, pois ela usa o CDN padrão.\n\nPara desativá-los, defina suas URLs como `None` ao criar sua aplicação FastAPI:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### Incluir a documentação personalizada para arquivos estáticos { #include-the-custom-docs-for-static-files }\n\nE da mesma forma que com um CDN personalizado, agora você pode criar as *operações de rota* para a documentação personalizada.\n\nNovamente, você pode reutilizar as funções internas do FastAPI para criar as páginas HTML para a documentação e passar os argumentos necessários:\n\n* `openapi_url`: a URL onde a página HTML para a documentação pode obter o esquema OpenAPI para a sua API. Você pode usar aqui o atributo `app.openapi_url`.\n* `title`: o título da sua API.\n* `oauth2_redirect_url`: Você pode usar `app.swagger_ui_oauth2_redirect_url` aqui para usar o padrão.\n* `swagger_js_url`: a URL onde a página HTML para a sua documentação do Swagger UI pode obter o arquivo **JavaScript**. **Este é o URL que seu aplicativo está fornecendo**.\n* `swagger_css_url`: a URL onde a página HTML para a sua documentação do Swagger UI pode obter o arquivo **CSS**. **Esse é o que seu aplicativo está fornecendo**.\n\nE de forma semelhante para o ReDoc...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip | Dica\n\nA *operação de rota* para `swagger_ui_redirect` é um auxiliar para quando você usa OAuth2.\n\nSe você integrar sua API com um provedor OAuth2, você poderá autenticar e voltar para a documentação da API com as credenciais adquiridas. E, então, interagir com ela usando a autenticação OAuth2 real.\n\nSwagger UI lidará com isso nos bastidores para você, mas ele precisa desse auxiliar de \"redirect\".\n\n///\n\n### Criar uma *operação de rota* para testar arquivos estáticos { #create-a-path-operation-to-test-static-files }\n\nAgora, para poder testar se tudo funciona, crie uma *operação de rota*:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### Teste a UI de Arquivos Estáticos { #test-static-files-ui }\n\nAgora, você deve ser capaz de desconectar o WiFi, ir para a documentação em [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), e recarregar a página.\n\nE mesmo sem Internet, você será capaz de ver a documentação da sua API e interagir com ela.\n"
  },
  {
    "path": "docs/pt/docs/how-to/custom-request-and-route.md",
    "content": "# Request e classe APIRoute personalizadas { #custom-request-and-apiroute-class }\n\nEm alguns casos, você pode querer sobrescrever a lógica usada pelas classes `Request` e `APIRoute`.\n\nEm particular, isso pode ser uma boa alternativa para uma lógica em um middleware.\n\nPor exemplo, se você quiser ler ou manipular o corpo da requisição antes que ele seja processado pela sua aplicação.\n\n/// danger | Cuidado\n\nIsso é um recurso \"avançado\".\n\nSe você for um iniciante em **FastAPI** você deve considerar pular essa seção.\n\n///\n\n## Casos de Uso { #use-cases }\n\nAlguns casos de uso incluem:\n\n* Converter requisições não-JSON para JSON (por exemplo, [`msgpack`](https://msgpack.org/index.html)).\n* Descomprimir corpos de requisição comprimidos com gzip.\n* Registrar automaticamente todos os corpos de requisição.\n\n## Manipulando codificações de corpo de requisição personalizadas { #handling-custom-request-body-encodings }\n\nVamos ver como usar uma subclasse personalizada de `Request` para descomprimir requisições gzip.\n\nE uma subclasse de `APIRoute` para usar essa classe de requisição personalizada.\n\n### Criar uma classe `GzipRequest` personalizada { #create-a-custom-gziprequest-class }\n\n/// tip | Dica\n\nIsso é um exemplo de brincadeira para demonstrar como funciona, se você precisar de suporte para Gzip, você pode usar o [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware) fornecido.\n\n///\n\nPrimeiro, criamos uma classe `GzipRequest`, que irá sobrescrever o método `Request.body()` para descomprimir o corpo na presença de um cabeçalho apropriado.\n\nSe não houver `gzip` no cabeçalho, ele não tentará descomprimir o corpo.\n\nDessa forma, a mesma classe de rota pode lidar com requisições comprimidas ou não comprimidas.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### Criar uma classe `GzipRoute` personalizada { #create-a-custom-gziproute-class }\n\nEm seguida, criamos uma subclasse personalizada de `fastapi.routing.APIRoute` que fará uso do `GzipRequest`.\n\nDessa vez, ele irá sobrescrever o método `APIRoute.get_route_handler()`.\n\nEsse método retorna uma função. E essa função é o que irá receber uma requisição e retornar uma resposta.\n\nAqui nós usamos para criar um `GzipRequest` a partir da requisição original.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | Detalhes Técnicos\n\nUm `Request` tem um atributo `request.scope`, que é apenas um `dict` do Python contendo os metadados relacionados à requisição.\n\nUm `Request` também tem um `request.receive`, que é uma função para \"receber\" o corpo da requisição.\n\nO dicionário `scope` e a função `receive` são ambos parte da especificação ASGI.\n\nE essas duas coisas, `scope` e `receive`, são o que é necessário para criar uma nova instância de `Request`.\n\nPara aprender mais sobre o `Request` confira a [documentação do Starlette sobre Requests](https://www.starlette.dev/requests/).\n\n///\n\nA única coisa que a função retornada por `GzipRequest.get_route_handler` faz de diferente é converter o `Request` para um `GzipRequest`.\n\nFazendo isso, nosso `GzipRequest` irá cuidar de descomprimir os dados (se necessário) antes de passá-los para nossas *operações de rota*.\n\nDepois disso, toda a lógica de processamento é a mesma.\n\nMas por causa das nossas mudanças em `GzipRequest.body`, o corpo da requisição será automaticamente descomprimido quando for carregado pelo **FastAPI** quando necessário.\n\n## Acessando o corpo da requisição em um manipulador de exceção { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip | Dica\n\nPara resolver esse mesmo problema, é provavelmente muito mais fácil usar o `body` em um manipulador personalizado para `RequestValidationError` ([Tratando Erros](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)).\n\nMas esse exemplo ainda é valido e mostra como interagir com os componentes internos.\n\n///\n\nTambém podemos usar essa mesma abordagem para acessar o corpo da requisição em um manipulador de exceção.\n\nTudo que precisamos fazer é manipular a requisição dentro de um bloco `try`/`except`:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\nSe uma exceção ocorrer, a instância `Request` ainda estará em escopo, então podemos ler e fazer uso do corpo da requisição ao lidar com o erro:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## Classe `APIRoute` personalizada em um router { #custom-apiroute-class-in-a-router }\n\nVocê também pode definir o parâmetro `route_class` de uma `APIRouter`:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\nNesse exemplo, as *operações de rota* sob o `router` irão usar a classe `TimedRoute` personalizada, e terão um cabeçalho extra `X-Response-Time` na resposta com o tempo que levou para gerar a resposta:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/pt/docs/how-to/extending-openapi.md",
    "content": "# Extendendo o OpenAPI { #extending-openapi }\n\nExistem alguns casos em que pode ser necessário modificar o esquema OpenAPI gerado.\n\nNesta seção, você verá como fazer isso.\n\n## O processo normal { #the-normal-process }\n\nO processo normal (padrão) é o seguinte:\n\nUma aplicação (instância) do `FastAPI` possui um método `.openapi()` que deve retornar o esquema OpenAPI.\n\nComo parte da criação do objeto de aplicação, uma *operação de rota* para `/openapi.json` (ou para o que você definir como `openapi_url`) é registrada.\n\nEla apenas retorna uma resposta JSON com o resultado do método `.openapi()` da aplicação.\n\nPor padrão, o que o método `.openapi()` faz é verificar se a propriedade `.openapi_schema` tem conteúdo e retorná-lo.\n\nSe não tiver, ele gera o conteúdo usando a função utilitária em `fastapi.openapi.utils.get_openapi`.\n\nE essa função `get_openapi()` recebe como parâmetros:\n\n* `title`: O título do OpenAPI, exibido na documentação.\n* `version`: A versão da sua API, por exemplo, `2.5.0`.\n* `openapi_version`: A versão da especificação OpenAPI utilizada. Por padrão, a mais recente: `3.1.0`.\n* `summary`: Um resumo curto da API.\n* `description`: A descrição da sua API, que pode incluir markdown e será exibida na documentação.\n* `routes`: Uma lista de rotas, que são cada uma das *operações de rota* registradas. Elas são obtidas de `app.routes`.\n\n/// info | Informação\n\nO parâmetro `summary` está disponível no OpenAPI 3.1.0 e superior, suportado pelo FastAPI 0.99.0 e superior.\n\n///\n\n## Sobrescrevendo os padrões { #overriding-the-defaults }\n\nCom as informações acima, você pode usar a mesma função utilitária para gerar o esquema OpenAPI e sobrescrever cada parte que precisar.\n\nPor exemplo, vamos adicionar [Extensão OpenAPI do ReDoc para incluir um logo personalizado](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo).\n\n### **FastAPI** Normal { #normal-fastapi }\n\nPrimeiro, escreva toda a sua aplicação **FastAPI** normalmente:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### Gerar o esquema OpenAPI { #generate-the-openapi-schema }\n\nEm seguida, use a mesma função utilitária para gerar o esquema OpenAPI, dentro de uma função `custom_openapi()`:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### Modificar o esquema OpenAPI { #modify-the-openapi-schema }\n\nAgora, você pode adicionar a extensão do ReDoc, incluindo um `x-logo` personalizado ao \"objeto\" `info` no esquema OpenAPI:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### Armazenar em cache o esquema OpenAPI { #cache-the-openapi-schema }\n\nVocê pode usar a propriedade `.openapi_schema` como um \"cache\" para armazenar o esquema gerado.\n\nDessa forma, sua aplicação não precisará gerar o esquema toda vez que um usuário abrir a documentação da sua API.\n\nEle será gerado apenas uma vez, e o mesmo esquema armazenado em cache será utilizado nas próximas requisições.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### Sobrescrever o método { #override-the-method }\n\nAgora, você pode substituir o método `.openapi()` pela sua nova função.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### Verificar { #check-it }\n\nUma vez que você acessar [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc), verá que está usando seu logo personalizado (neste exemplo, o logo do **FastAPI**):\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/pt/docs/how-to/general.md",
    "content": "# Geral - Como Fazer - Receitas { #general-how-to-recipes }\n\nAqui estão vários links para outros locais na documentação, para perguntas gerais ou frequentes.\n\n## Filtro de dados- Segurança { #filter-data-security }\n\nPara assegurar que você não vai retornar mais dados do que deveria, leia a documentação de [Tutorial - Modelo de Resposta - Tipo de Retorno](../tutorial/response-model.md).\n\n## Otimizar Desempenho da Resposta - Modelo de Resposta - Tipo de Retorno { #optimize-response-performance-response-model-return-type }\n\nPara otimizar o desempenho ao retornar dados JSON, use um tipo de retorno ou modelo de resposta; assim, o Pydantic fará a serialização para JSON no lado do Rust, sem passar pelo Python. Leia mais na documentação de [Tutorial - Modelo de Resposta - Tipo de Retorno](../tutorial/response-model.md).\n\n## Tags de Documentação - OpenAPI { #documentation-tags-openapi }\nPara adicionar tags às suas *operações de rota* e agrupá-las na UI da documentação, leia a documentação de [Tutorial - Configurações da Operação de Rota - Tags](../tutorial/path-operation-configuration.md#tags).\n\n## Resumo e Descrição da documentação - OpenAPI { #documentation-summary-and-description-openapi }\n\nPara adicionar um resumo e uma descrição às suas *operações de rota* e exibi-los na UI da documentação, leia a documentação de [Tutorial - Configurações da Operação de Rota - Resumo e Descrição](../tutorial/path-operation-configuration.md#summary-and-description).\n\n## Documentação - Descrição da Resposta - OpenAPI { #documentation-response-description-openapi }\n\nPara definir a descrição de uma resposta exibida na interface da documentação, leia a documentação de [Tutorial - Configurações da Operação de Rota - Descrição da Resposta](../tutorial/path-operation-configuration.md#response-description).\n\n## Documentação - Descontinuar uma *Operação de Rota* - OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\nPara descontinuar uma *operação de rota* e exibi-la na UI da documentação, leia a documentação de [Tutorial - Configurações da Operação de Rota - Descontinuação](../tutorial/path-operation-configuration.md#deprecate-a-path-operation).\n\n## Converter qualquer dado para compatível com JSON { #convert-any-data-to-json-compatible }\n\nPara converter qualquer dado para um formato compatível com JSON, leia a documentação de [Tutorial - Codificador Compatível com JSON](../tutorial/encoder.md).\n\n## OpenAPI Metadata - Docs { #openapi-metadata-docs }\n\nPara adicionar metadados ao seu esquema OpenAPI, incluindo licença, versão, contato, etc, leia a documentação de [Tutorial - Metadados e URLs da Documentação](../tutorial/metadata.md).\n\n## OpenAPI com URL customizada { #openapi-custom-url }\n\nPara customizar a URL do OpenAPI (ou removê-la), leia a documentação de [Tutorial - Metadados e URLs da Documentação](../tutorial/metadata.md#openapi-url).\n\n## URLs de documentação do OpenAPI { #openapi-docs-urls }\n\nPara alterar as URLs usadas ​​para as interfaces de usuário da documentação gerada automaticamente, leia a documentação de [Tutorial - Metadados e URLs da Documentação](../tutorial/metadata.md#docs-urls).\n"
  },
  {
    "path": "docs/pt/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\nComo o **FastAPI** é baseado no padrão **ASGI**, é muito fácil integrar qualquer biblioteca **GraphQL** também compatível com ASGI.\n\nVocê pode combinar *operações de rota* normais do FastAPI com GraphQL na mesma aplicação.\n\n/// tip | Dica\n\n**GraphQL** resolve alguns casos de uso muito específicos.\n\nEle tem **vantagens** e **desvantagens** quando comparado a **web APIs** comuns.\n\nCertifique-se de avaliar se os **benefícios** para o seu caso de uso compensam as **desvantagens**. 🤓\n\n///\n\n## Bibliotecas GraphQL { #graphql-libraries }\n\nAqui estão algumas das bibliotecas **GraphQL** que têm suporte **ASGI**. Você pode usá-las com **FastAPI**:\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * Com [documentação para FastAPI](https://strawberry.rocks/docs/integrations/fastapi)\n* [Ariadne](https://ariadnegraphql.org/)\n    * Com [documentação para FastAPI](https://ariadnegraphql.org/docs/fastapi-integration)\n* [Tartiflette](https://tartiflette.io/)\n    * Com [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) para fornecer integração ASGI\n* [Graphene](https://graphene-python.org/)\n    * Com [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)\n\n## GraphQL com Strawberry { #graphql-with-strawberry }\n\nSe você precisar ou quiser trabalhar com **GraphQL**, [**Strawberry**](https://strawberry.rocks/) é a biblioteca **recomendada** pois tem o design mais próximo ao design do **FastAPI**, ela é toda baseada em **anotações de tipo**.\n\nDependendo do seu caso de uso, você pode preferir usar uma biblioteca diferente, mas se você me perguntasse, eu provavelmente sugeriria que você experimentasse o **Strawberry**.\n\nAqui está uma pequena prévia de como você poderia integrar Strawberry com FastAPI:\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\nVocê pode aprender mais sobre Strawberry na [documentação do Strawberry](https://strawberry.rocks/).\n\nE também na documentação sobre [Strawberry com FastAPI](https://strawberry.rocks/docs/integrations/fastapi).\n\n## Antigo `GraphQLApp` do Starlette { #older-graphqlapp-from-starlette }\n\nVersões anteriores do Starlette incluiam uma classe `GraphQLApp` para integrar com [Graphene](https://graphene-python.org/).\n\nEla foi descontinuada do Starlette, mas se você tem código que a utilizava, você pode facilmente **migrar** para [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3), que cobre o mesmo caso de uso e tem uma **interface quase idêntica**.\n\n/// tip | Dica\n\nSe você precisa de GraphQL, eu ainda recomendaria que você desse uma olhada no [Strawberry](https://strawberry.rocks/), pois ele é baseado em anotações de tipo em vez de classes e tipos personalizados.\n\n///\n\n## Saiba Mais { #learn-more }\n\nVocê pode aprender mais sobre **GraphQL** na [documentação oficial do GraphQL](https://graphql.org/).\n\nVocê também pode ler mais sobre cada uma das bibliotecas descritas acima em seus links.\n"
  },
  {
    "path": "docs/pt/docs/how-to/index.md",
    "content": "# Como Fazer - Receitas { #how-to-recipes }\n\nAqui você encontrará diferentes exemplos práticos ou tutoriais de \"como fazer\" para **vários tópicos**.\n\nA maioria dessas ideias será mais ou menos **independente**, e na maioria dos casos você deveria estudá-las apenas se elas se aplicarem diretamente ao **seu projeto**.\n\nSe algo parecer interessante e útil para o seu projeto, vá em frente e dê uma olhada. Caso contrário, você pode simplesmente ignorá-las.\n\n/// tip | Dica\n\nSe você deseja **aprender FastAPI** de forma estruturada (recomendado), leia capítulo por capítulo [Tutorial - Guia de Usuário](../tutorial/index.md) em vez disso.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# Migrar do Pydantic v1 para o Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\nSe você tem uma aplicação FastAPI antiga, pode estar usando o Pydantic versão 1.\n\nO FastAPI versão 0.100.0 tinha suporte ao Pydantic v1 ou v2. Ele usaria aquele que você tivesse instalado.\n\nO FastAPI versão 0.119.0 introduziu suporte parcial ao Pydantic v1 a partir de dentro do Pydantic v2 (como `pydantic.v1`), para facilitar a migração para o v2.\n\nO FastAPI 0.126.0 removeu o suporte ao Pydantic v1, enquanto ainda oferece suporte a `pydantic.v1` por mais algum tempo.\n\n/// warning | Atenção\n\nA equipe do Pydantic interrompeu o suporte ao Pydantic v1 para as versões mais recentes do Python, a partir do **Python 3.14**.\n\nIsso inclui `pydantic.v1`, que não é mais suportado no Python 3.14 e superiores.\n\nSe quiser usar as funcionalidades mais recentes do Python, você precisará garantir que usa o Pydantic v2.\n\n///\n\nSe você tem uma aplicação FastAPI antiga com Pydantic v1, aqui vou mostrar como migrá-la para o Pydantic v2, e as **funcionalidades no FastAPI 0.119.0** para ajudar em uma migração gradual.\n\n## Guia oficial { #official-guide }\n\nO Pydantic tem um [Guia de Migração](https://docs.pydantic.dev/latest/migration/) oficial do v1 para o v2.\n\nEle também inclui o que mudou, como as validações agora são mais corretas e rigorosas, possíveis ressalvas, etc.\n\nVocê pode lê-lo para entender melhor o que mudou.\n\n## Testes { #tests }\n\nGaranta que você tenha [testes](../tutorial/testing.md) para sua aplicação e que os execute na integração contínua (CI).\n\nAssim, você pode fazer a atualização e garantir que tudo continua funcionando como esperado.\n\n## `bump-pydantic` { #bump-pydantic }\n\nEm muitos casos, quando você usa modelos Pydantic regulares sem personalizações, será possível automatizar a maior parte do processo de migração do Pydantic v1 para o Pydantic v2.\n\nVocê pode usar [`bump-pydantic`](https://github.com/pydantic/bump-pydantic) da própria equipe do Pydantic.\n\nEssa ferramenta ajuda a alterar automaticamente a maior parte do código que precisa ser modificado.\n\nDepois disso, você pode rodar os testes e verificar se tudo funciona. Se funcionar, está concluído. 😎\n\n## Pydantic v1 no v2 { #pydantic-v1-in-v2 }\n\nO Pydantic v2 inclui tudo do Pydantic v1 como um submódulo `pydantic.v1`. Mas isso não é mais suportado em versões acima do Python 3.13.\n\nIsso significa que você pode instalar a versão mais recente do Pydantic v2 e importar e usar os componentes antigos do Pydantic v1 a partir desse submódulo, como se tivesse o Pydantic v1 antigo instalado.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### Suporte do FastAPI ao Pydantic v1 no v2 { #fastapi-support-for-pydantic-v1-in-v2 }\n\nDesde o FastAPI 0.119.0, há também suporte parcial ao Pydantic v1 a partir de dentro do Pydantic v2, para facilitar a migração para o v2.\n\nAssim, você pode atualizar o Pydantic para a versão 2 mais recente e alterar os imports para usar o submódulo `pydantic.v1`, e em muitos casos tudo simplesmente funcionará.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning | Atenção\n\nTenha em mente que, como a equipe do Pydantic não oferece mais suporte ao Pydantic v1 nas versões recentes do Python, a partir do Python 3.14, o uso de `pydantic.v1` também não é suportado no Python 3.14 e superiores.\n\n///\n\n### Pydantic v1 e v2 na mesma aplicação { #pydantic-v1-and-v2-on-the-same-app }\n\nNão é **suportado** pelo Pydantic ter um modelo do Pydantic v2 com campos próprios definidos como modelos do Pydantic v1, ou vice-versa.\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n...mas, você pode ter modelos separados usando Pydantic v1 e v2 na mesma aplicação.\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\nEm alguns casos, é até possível ter modelos Pydantic v1 e v2 na mesma **operação de rota** na sua aplicação FastAPI:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\nNo exemplo acima, o modelo de entrada é um modelo Pydantic v1, e o modelo de saída (definido em `response_model=ItemV2`) é um modelo Pydantic v2.\n\n### Parâmetros do Pydantic v1 { #pydantic-v1-parameters }\n\nSe você precisar usar algumas das ferramentas específicas do FastAPI para parâmetros como `Body`, `Query`, `Form` etc. com modelos do Pydantic v1, pode importá-las de `fastapi.temp_pydantic_v1_params` enquanto conclui a migração para o Pydantic v2:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### Migre em etapas { #migrate-in-steps }\n\n/// tip | Dica\n\nPrimeiro tente com o `bump-pydantic`, se seus testes passarem e isso funcionar, então você concluiu tudo com um único comando. ✨\n\n///\n\nSe o `bump-pydantic` não funcionar para o seu caso, você pode usar o suporte a modelos Pydantic v1 e v2 na mesma aplicação para fazer a migração para o Pydantic v2 gradualmente.\n\nVocê poderia primeiro atualizar o Pydantic para usar a versão 2 mais recente e alterar os imports para usar `pydantic.v1` para todos os seus modelos.\n\nDepois, você pode começar a migrar seus modelos do Pydantic v1 para o v2 em grupos, em etapas graduais. 🚶\n"
  },
  {
    "path": "docs/pt/docs/how-to/separate-openapi-schemas.md",
    "content": "# Esquemas OpenAPI Separados para Entrada e Saída ou Não { #separate-openapi-schemas-for-input-and-output-or-not }\n\nDesde que o **Pydantic v2** foi lançado, o OpenAPI gerado é um pouco mais exato e **correto** do que antes. 😎\n\nDe fato, em alguns casos, ele terá até **dois JSON Schemas** no OpenAPI para o mesmo modelo Pydantic, para entrada e saída, dependendo se eles possuem **valores padrão**.\n\nVamos ver como isso funciona e como alterar se for necessário.\n\n## Modelos Pydantic para Entrada e Saída { #pydantic-models-for-input-and-output }\n\nDigamos que você tenha um modelo Pydantic com valores padrão, como este:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### Modelo para Entrada { #model-for-input }\n\nSe você usar esse modelo como entrada, como aqui:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n... então o campo `description` **não será obrigatório**. Porque ele tem um valor padrão de `None`.\n\n### Modelo de Entrada na Documentação { #input-model-in-docs }\n\nVocê pode confirmar que na documentação, o campo `description` não tem um **asterisco vermelho**, não é marcado como obrigatório:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### Modelo para Saída { #model-for-output }\n\nMas se você usar o mesmo modelo como saída, como aqui:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n... então, como `description` tem um valor padrão, se você **não retornar nada** para esse campo, ele ainda terá o **valor padrão**.\n\n### Modelo para Dados de Resposta de Saída { #model-for-output-response-data }\n\nSe você interagir com a documentação e verificar a resposta, mesmo que o código não tenha adicionado nada em um dos campos `description`, a resposta JSON contém o valor padrão (`null`):\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\nIsso significa que ele **sempre terá um valor**, só que às vezes o valor pode ser `None` (ou `null` em termos de JSON).\n\nIsso quer dizer que, os clientes que usam sua API não precisam verificar se o valor existe ou não, eles podem **assumir que o campo sempre estará lá**, mas que em alguns casos terá o valor padrão de `None`.\n\nA maneira de descrever isso no OpenAPI é marcar esse campo como **obrigatório**, porque ele sempre estará lá.\n\nPor causa disso, o JSON Schema para um modelo pode ser diferente dependendo se ele é usado para **entrada ou saída**:\n\n* para **entrada**, o `description` **não será obrigatório**\n* para **saída**, ele será **obrigatório** (e possivelmente `None`, ou em termos de JSON, `null`)\n\n### Modelo para Saída na Documentação { #model-for-output-in-docs }\n\nVocê pode verificar o modelo de saída na documentação também, **ambos** `name` e `description` são marcados como **obrigatórios** com um **asterisco vermelho**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### Modelo para Entrada e Saída na Documentação { #model-for-input-and-output-in-docs }\n\nE se você verificar todos os Schemas disponíveis (JSON Schemas) no OpenAPI, verá que há dois, um `Item-Input` e um `Item-Output`.\n\nPara `Item-Input`, `description` **não é obrigatório**, não tem um asterisco vermelho.\n\nMas para `Item-Output`, `description` **é obrigatório**, tem um asterisco vermelho.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\nCom esse recurso do **Pydantic v2**, sua documentação da API fica mais **precisa**, e se você tiver clientes e SDKs gerados automaticamente, eles serão mais precisos também, proporcionando uma melhor **experiência para desenvolvedores** e consistência. 🎉\n\n## Não Separe Schemas { #do-not-separate-schemas }\n\nAgora, há alguns casos em que você pode querer ter o **mesmo esquema para entrada e saída**.\n\nProvavelmente, o principal caso de uso para isso é se você já tem algum código de cliente/SDK gerado automaticamente e não quer atualizar todo o código de cliente/SDK gerado ainda, você provavelmente vai querer fazer isso em algum momento, mas talvez não agora.\n\nNesse caso, você pode desativar esse recurso no **FastAPI**, com o parâmetro `separate_input_output_schemas=False`.\n\n/// info | Informação\n\nO suporte para `separate_input_output_schemas` foi adicionado no FastAPI `0.102.0`. 🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### Mesmo Esquema para Modelos de Entrada e Saída na Documentação { #same-schema-for-input-and-output-models-in-docs }\n\nE agora haverá um único esquema para entrada e saída para o modelo, apenas `Item`, e ele terá `description` como **não obrigatório**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/pt/docs/how-to/testing-database.md",
    "content": "# Testando a Base de Dados { #testing-a-database }\n\nVocê pode estudar sobre bases de dados, SQL e SQLModel na [documentação de SQLModel](https://sqlmodel.tiangolo.com/). 🤓\n\nAqui tem um mini [tutorial de como usar SQLModel com FastAPI](https://sqlmodel.tiangolo.com/tutorial/fastapi/). ✨\n\nEsse tutorial inclui uma seção sobre [testar bases de dados SQL](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/). 😎\n"
  },
  {
    "path": "docs/pt/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/pt\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>Framework FastAPI, alta performance, fácil de aprender, rápido para codar, pronto para produção</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**Documentação**: [https://fastapi.tiangolo.com/pt](https://fastapi.tiangolo.com/pt)\n\n**Código fonte**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI é um framework web moderno e rápido (alta performance) para construção de APIs com Python, baseado nos type hints padrões do Python.\n\nOs recursos chave são:\n\n* **Rápido**: alta performance, equivalente a **NodeJS** e **Go** (graças ao Starlette e Pydantic). [Um dos frameworks Python mais rápidos disponíveis](#performance).\n* **Rápido para codar**: Aumenta a velocidade para desenvolver recursos entre 200% a 300%. *\n* **Poucos bugs**: Reduz cerca de 40% de erros induzidos por humanos (desenvolvedores). *\n* **Intuitivo**: Grande suporte a editores. <dfn title=\"também conhecido como: autocompletar, preenchimento automático, IntelliSense\">Completação</dfn> em todos os lugares. Menos tempo debugando.\n* **Fácil**: Projetado para ser fácil de aprender e usar. Menos tempo lendo docs.\n* **Enxuto**: Minimize duplicação de código. Múltiplas funcionalidades para cada declaração de parâmetro. Menos bugs.\n* **Robusto**: Tenha código pronto para produção. E com documentação interativa automática.\n* **Baseado em padrões**: Baseado em (e totalmente compatível com) os padrões abertos para APIs: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (anteriormente conhecido como Swagger) e [JSON Schema](https://json-schema.org/).\n\n<small>* estimativas baseadas em testes realizados com equipe interna de desenvolvimento, construindo aplicações em produção.</small>\n\n## Patrocinadores { #sponsors }\n\n<!-- sponsors -->\n\n### Patrocinador Keystone { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### Patrocinadores Ouro e Prata { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[Outros patrocinadores](https://fastapi.tiangolo.com/pt/fastapi-people/#sponsors)\n\n## Opiniões { #opinions }\n\n\"_[...] Estou usando **FastAPI** muito esses dias. [...] Estou na verdade planejando utilizar ele em todos os times de **serviços ML na Microsoft**. Alguns deles estão sendo integrados no _core_ do produto **Windows** e alguns produtos **Office**._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n\"_Nós adotamos a biblioteca **FastAPI** para iniciar um servidor **REST** que pode ser consultado para obter **previsões**. [para o Ludwig]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, e Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n\"_A **Netflix** tem o prazer de anunciar o lançamento open-source do nosso framework de orquestração de **gerenciamento de crises**: **Dispatch**! [criado com **FastAPI**]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n\"_Estou muito entusiasmado com o **FastAPI**. É tão divertido!_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken - <strong>[Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855) apresentador do podcast</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(ref)</small></a></div>\n\n---\n\n\"_Honestamente, o que você construiu parece super sólido e refinado. De muitas formas, é o que eu queria que o **Hug** fosse - é realmente inspirador ver alguém construir isso._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley - <strong>criador do [Hug](https://github.com/hugapi/hug)</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(ref)</small></a></div>\n\n---\n\n\"_Se você está procurando aprender um **framework moderno** para construir APIs REST, dê uma olhada no **FastAPI** [...] É rápido, fácil de usar e fácil de aprender [...]_\"\n\n\"_Nós trocamos nossas **APIs** por **FastAPI** [...] Acredito que você gostará dele [...]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani - Matthew Honnibal - <strong>fundadores da [Explosion AI](https://explosion.ai) - criadores da [spaCy](https://spacy.io)</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(ref)</small></a> - <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(ref)</small></a></div>\n\n---\n\n\"_Se alguém estiver procurando construir uma API Python para produção, eu recomendaria fortemente o **FastAPI**. Ele é **lindamente projetado**, **simples de usar** e **altamente escalável**, e se tornou um **componente chave** para a nossa estratégia de desenvolvimento API first, impulsionando diversas automações e serviços, como o nosso Virtual TAC Engineer._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n## Mini documentário do FastAPI { #fastapi-mini-documentary }\n\nHá um [mini documentário do FastAPI](https://www.youtube.com/watch?v=mpR8ngthqiE) lançado no fim de 2025, você pode assisti-lo online:\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**, o FastAPI das interfaces de linhas de comando { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\nSe você estiver construindo uma aplicação <abbr title=\"Command Line Interface - Interface de Linha de Comando\">CLI</abbr> para ser utilizada no terminal ao invés de uma API web, dê uma olhada no [**Typer**](https://typer.tiangolo.com/).\n\n**Typer** é o irmão menor do FastAPI. E seu propósito é ser o **FastAPI das CLIs**. ⌨️ 🚀\n\n## Requisitos { #requirements }\n\nFastAPI está nos ombros de gigantes:\n\n* [Starlette](https://www.starlette.dev/) para as partes web.\n* [Pydantic](https://docs.pydantic.dev/) para a parte de dados.\n\n## Instalação { #installation }\n\nCrie e ative um [ambiente virtual](https://fastapi.tiangolo.com/pt/virtual-environments/) e então instale o FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Nota**: Certifique-se de que você colocou `\"fastapi[standard]\"` com aspas, para garantir que funcione em todos os terminais.\n\n## Exemplo { #example }\n\n### Crie { #create-it }\n\nCrie um arquivo `main.py` com:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>Ou use <code>async def</code>...</summary>\n\nSe seu código utiliza `async` / `await`, use `async def`:\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Nota**:\n\nSe você não sabe, verifique a seção _\"Com pressa?\"_ sobre [`async` e `await` nas docs](https://fastapi.tiangolo.com/pt/async/#in-a-hurry).\n\n</details>\n\n### Rode { #run-it }\n\nRode o servidor com:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary>Sobre o comando <code>fastapi dev</code>...</summary>\n\nO comando `fastapi dev` lê automaticamente o seu arquivo `main.py`, detecta a aplicação **FastAPI** nele e inicia um servidor usando o [Uvicorn](https://www.uvicorn.dev).\n\nPor padrão, o `fastapi dev` iniciará com auto-reload habilitado para desenvolvimento local.\n\nVocê pode ler mais sobre isso na [documentação do FastAPI CLI](https://fastapi.tiangolo.com/pt/fastapi-cli/).\n\n</details>\n\n### Verifique { #check-it }\n\nAbra seu navegador em [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery).\n\nVocê verá a resposta JSON como:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\nVocê acabou de criar uma API que:\n\n* Recebe requisições HTTP nos _paths_ `/` e `/items/{item_id}`.\n* Ambos _paths_ fazem <em>operações</em> `GET` (também conhecido como _métodos_ HTTP).\n* O _path_ `/items/{item_id}` tem um _parâmetro de path_ `item_id` que deve ser um `int`.\n* O _path_ `/items/{item_id}` tem um _parâmetro query_ `q` `str` opcional.\n\n### Documentação Interativa da API { #interactive-api-docs }\n\nAgora vá para [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVocê verá a documentação automática interativa da API (fornecida por [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Documentação Alternativa da API { #alternative-api-docs }\n\nE agora, vá para [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nVocê verá a documentação automática alternativa (fornecida por [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Evoluindo o Exemplo { #example-upgrade }\n\nAgora modifique o arquivo `main.py` para receber um corpo de uma requisição `PUT`.\n\nDeclare o corpo utilizando tipos padrão Python, graças ao Pydantic.\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\nO servidor `fastapi dev` deverá recarregar automaticamente.\n\n### Evoluindo a Documentação Interativa da API { #interactive-api-docs-upgrade }\n\nAgora vá para [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n* A documentação interativa da API será automaticamente atualizada, incluindo o novo corpo:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Clique no botão \"Try it out\", ele permitirá que você preencha os parâmetros e interaja diretamente com a API:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* Então clique no botão \"Execute\", a interface do usuário irá se comunicar com a API, enviar os parâmetros, pegar os resultados e mostrá-los na tela:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### Evoluindo a Documentação Alternativa da API { #alternative-api-docs-upgrade }\n\nE agora, vá para [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\n* A documentação alternativa também irá refletir o novo parâmetro query e o corpo:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Recapitulando { #recap }\n\nResumindo, você declara **uma vez** os tipos dos parâmetros, corpo etc. como parâmetros de função.\n\nVocê faz isso com os tipos padrão do Python moderno.\n\nVocê não terá que aprender uma nova sintaxe, os métodos ou classes de uma biblioteca específica etc.\n\nApenas **Python** padrão.\n\nPor exemplo, para um `int`:\n\n```Python\nitem_id: int\n```\n\nou para um modelo mais complexo, `Item`:\n\n```Python\nitem: Item\n```\n\n...e com essa única declaração você tem:\n\n* Suporte ao Editor, incluindo:\n    * Completação.\n    * Verificação de tipos.\n* Validação de dados:\n    * Erros automáticos e claros quando o dado é inválido.\n    * Validação até para objetos JSON profundamente aninhados.\n* <dfn title=\"também conhecido como: serialização, parsing, marshalling\">Conversão</dfn> de dados de entrada: vindo da rede para dados e tipos Python. Consegue ler:\n    * JSON.\n    * Parâmetros de path.\n    * Parâmetros query.\n    * Cookies.\n    * Cabeçalhos.\n    * Formulários.\n    * Arquivos.\n* <dfn title=\"também conhecido como: serialização, parsing, marshalling\">Conversão</dfn> de dados de saída: convertendo de tipos e dados Python para dados de rede (como JSON):\n    * Converte tipos Python (`str`, `int`, `float`, `bool`, `list` etc).\n    * Objetos `datetime`.\n    * Objetos `UUID`.\n    * Modelos de Banco de Dados.\n    * ...e muito mais.\n* Documentação interativa automática da API, incluindo 2 alternativas de interface de usuário:\n    * Swagger UI.\n    * ReDoc.\n\n---\n\nVoltando ao código do exemplo anterior, **FastAPI** irá:\n\n* Validar que existe um `item_id` no path para requisições `GET` e `PUT`.\n* Validar que `item_id` é do tipo `int` para requisições `GET` e `PUT`.\n    * Se não for, o cliente verá um erro útil e claro.\n* Verificar se existe um parâmetro query opcional nomeado como `q` (como em `http://127.0.0.1:8000/items/foo?q=somequery`) para requisições `GET`.\n    * Como o parâmetro `q` é declarado com `= None`, ele é opcional.\n    * Sem o `None` ele seria obrigatório (como o corpo no caso de `PUT`).\n* Para requisições `PUT` para `/items/{item_id}`, lerá o corpo como JSON:\n    * Verifica que tem um atributo obrigatório `name` que deve ser `str`.\n    * Verifica que tem um atributo obrigatório `price` que tem que ser um `float`.\n    * Verifica que tem um atributo opcional `is_offer`, que deve ser um `bool`, se presente.\n    * Tudo isso também funcionaria para objetos JSON profundamente aninhados.\n* Converter de e para JSON automaticamente.\n* Documentar tudo com OpenAPI, que poderá ser usado por:\n    * Sistemas de documentação interativos.\n    * Sistemas de clientes de geração de código automáticos, para muitas linguagens.\n* Fornecer diretamente 2 interfaces web de documentação interativa.\n\n---\n\nNós apenas arranhamos a superfície, mas você já tem ideia de como tudo funciona.\n\nExperimente mudar a seguinte linha:\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n...de:\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n...para:\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n...e veja como seu editor irá auto-completar os atributos e saberá os tipos:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\nPara um exemplo mais completo incluindo mais recursos, veja o <a href=\"https://fastapi.tiangolo.com/pt/tutorial/\">Tutorial - Guia do Usuário</a>.\n\n**Alerta de Spoiler**: o tutorial - guia do usuário inclui:\n\n* Declaração de **parâmetros** de diferentes lugares como: **cabeçalhos**, **cookies**, **campos de formulários** e **arquivos**.\n* Como configurar **limitações de validação** como `maximum_length` ou `regex`.\n* Um poderoso e fácil de usar sistema de **<dfn title=\"também conhecido como: componentes, recursos, provedores, serviços, injetáveis\">Injeção de Dependência</dfn>**.\n* Segurança e autenticação, incluindo suporte para **OAuth2** com autenticação com **JWT tokens** e **HTTP Basic**.\n* Técnicas mais avançadas (mas igualmente fáceis) para declaração de **modelos JSON profundamente aninhados** (graças ao Pydantic).\n* Integrações **GraphQL** com o [Strawberry](https://strawberry.rocks) e outras bibliotecas.\n* Muitos recursos extras (graças ao Starlette) como:\n    * **WebSockets**\n    * testes extremamente fáceis baseados em HTTPX e `pytest`\n    * **CORS**\n    * **Cookie Sessions**\n    * ...e mais.\n\n### Implemente sua aplicação (opcional) { #deploy-your-app-optional }\n\nVocê pode opcionalmente implantar sua aplicação FastAPI na [FastAPI Cloud](https://fastapicloud.com), vá e entre na lista de espera se ainda não o fez. 🚀\n\nSe você já tem uma conta na **FastAPI Cloud** (nós convidamos você da lista de espera 😉), pode implantar sua aplicação com um único comando.\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nÉ isso! Agora você pode acessar sua aplicação nesse URL. ✨\n\n#### Sobre a FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** é construída pelo mesmo autor e equipe por trás do **FastAPI**.\n\nEla simplifica o processo de **construir**, **implantar** e **acessar** uma API com esforço mínimo.\n\nTraz a mesma **experiência do desenvolvedor** de construir aplicações com FastAPI para **implantá-las** na nuvem. 🎉\n\nA FastAPI Cloud é a principal patrocinadora e financiadora dos projetos open source do ecossistema *FastAPI and friends*. ✨\n\n#### Implante em outros provedores de nuvem { #deploy-to-other-cloud-providers }\n\nFastAPI é open source e baseado em padrões. Você pode implantar aplicações FastAPI em qualquer provedor de nuvem que escolher.\n\nSiga os tutoriais do seu provedor de nuvem para implantar aplicações FastAPI com eles. 🤓\n\n## Performance { #performance }\n\nTestes de performance independentes do TechEmpower mostram aplicações **FastAPI** rodando sob Uvicorn como [um dos frameworks Python mais rápidos disponíveis](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), somente atrás de Starlette e Uvicorn (utilizados internamente pelo FastAPI). (*)\n\nPara entender mais sobre isso, veja a seção [Comparações](https://fastapi.tiangolo.com/pt/benchmarks/).\n\n## Dependências { #dependencies }\n\nO FastAPI depende do Pydantic e do Starlette.\n\n### Dependências `standard` { #standard-dependencies }\n\nQuando você instala o FastAPI com `pip install \"fastapi[standard]\"`, ele vem com o grupo `standard` de dependências opcionais:\n\nUtilizado pelo Pydantic:\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - para validação de email.\n\nUtilizado pelo Starlette:\n\n* [`httpx`](https://www.python-httpx.org) - Obrigatório caso você queira utilizar o `TestClient`.\n* [`jinja2`](https://jinja.palletsprojects.com) - Obrigatório se você quer utilizar a configuração padrão de templates.\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - Obrigatório se você deseja suporte a <dfn title=\"convertendo a string que vem de uma requisição HTTP em dados Python\">\"parsing\"</dfn> de formulário, com `request.form()`.\n\nUtilizado pelo FastAPI:\n\n* [`uvicorn`](https://www.uvicorn.dev) - para o servidor que carrega e serve a sua aplicação. Isto inclui `uvicorn[standard]`, que inclui algumas dependências (e.g. `uvloop`) necessárias para servir em alta performance.\n* `fastapi-cli[standard]` - que disponibiliza o comando `fastapi`.\n    * Isso inclui `fastapi-cloud-cli`, que permite implantar sua aplicação FastAPI na [FastAPI Cloud](https://fastapicloud.com).\n\n### Sem as dependências `standard` { #without-standard-dependencies }\n\nSe você não deseja incluir as dependências opcionais `standard`, você pode instalar utilizando `pip install fastapi` ao invés de `pip install \"fastapi[standard]\"`.\n\n### Sem o `fastapi-cloud-cli` { #without-fastapi-cloud-cli }\n\nSe você quiser instalar o FastAPI com as dependências padrão, mas sem o `fastapi-cloud-cli`, você pode instalar com `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n### Dependências opcionais adicionais { #additional-optional-dependencies }\n\nExistem algumas dependências adicionais que você pode querer instalar.\n\nDependências opcionais adicionais do Pydantic:\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - para gerenciamento de configurações.\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - para tipos extras a serem utilizados com o Pydantic.\n\nDependências opcionais adicionais do FastAPI:\n\n* [`orjson`](https://github.com/ijl/orjson) - Obrigatório se você deseja utilizar o `ORJSONResponse`.\n* [`ujson`](https://github.com/esnme/ultrajson) - Obrigatório se você deseja utilizar o `UJSONResponse`.\n\n## Licença { #license }\n\nEsse projeto é licenciado sob os termos da licença MIT.\n"
  },
  {
    "path": "docs/pt/docs/learn/index.md",
    "content": "# Aprender { #learn }\n\nAqui estão as seções introdutórias e os tutoriais para aprender o **FastAPI**.\n\nPode considerar isto um **livro**, um **curso**, a forma **oficial** e recomendada de aprender o FastAPI. 😎\n"
  },
  {
    "path": "docs/pt/docs/project-generation.md",
    "content": "# Full Stack FastAPI Template { #full-stack-fastapi-template }\n\n_Templates_, embora tipicamente venham com alguma configuração específica, são desenhados para serem flexíveis e customizáveis. Isso permite que você os modifique e adapte para as especificações do seu projeto, fazendo-os um excelente ponto de partida. 🏁\n\nVocê pode usar esse _template_ para começar, já que ele inclui várias configurações iniciais, segurança, banco de dados, e alguns _endpoints_ de API já feitos para você.\n\nRepositório GitHub: [Full Stack FastAPI Template](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## Full Stack FastAPI Template - Pilha de Tecnologias e Recursos { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/pt) para a API do backend em Python.\n    - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para as interações do Python com bancos de dados SQL (ORM).\n    - 🔍 [Pydantic](https://docs.pydantic.dev), usado pelo FastAPI, para validação de dados e gerenciamento de configurações.\n    - 💾 [PostgreSQL](https://www.postgresql.org) como banco de dados SQL.\n- 🚀 [React](https://react.dev) para o frontend.\n    - 💃 Usando TypeScript, hooks, Vite, e outras partes de uma _stack_ frontend moderna.\n    - 🎨 [Tailwind CSS](https://tailwindcss.com) e [shadcn/ui](https://ui.shadcn.com) para os componentes de frontend.\n    - 🤖 Um cliente frontend automaticamente gerado.\n    - 🧪 [Playwright](https://playwright.dev) para testes Ponta-a-Ponta.\n    - 🦇 Suporte para modo escuro.\n- 🐋 [Docker Compose](https://www.docker.com) para desenvolvimento e produção.\n- 🔒 Hash seguro de senhas por padrão.\n- 🔑 Autenticação JWT (JSON Web Token).\n- 📫 Recuperação de senhas baseada em email.\n- ✅ Testes com [Pytest](https://pytest.org).\n- 📞 [Traefik](https://traefik.io) como proxy reverso / balanceador de carga.\n- 🚢 Instruções de deployment usando Docker Compose, incluindo como configurar um proxy frontend com Traefik para gerenciar automaticamente certificados HTTPS.\n- 🏭 CI (Integração Contínua) e CD (_Deploy_ Contínuo) baseado em GitHub Actions.\n"
  },
  {
    "path": "docs/pt/docs/python-types.md",
    "content": "# Introdução aos tipos Python { #python-types-intro }\n\nO Python possui suporte para \"type hints\" opcionais (também chamados de \"type annotations\").\n\nEsses **\"type hints\"** ou anotações são uma sintaxe especial que permite declarar o <dfn title=\"por exemplo: str, int, float, bool\">tipo</dfn> de uma variável.\n\nAo declarar tipos para suas variáveis, editores e ferramentas podem oferecer um melhor suporte.\n\nEste é apenas um **tutorial rápido / atualização** sobre type hints do Python. Ele cobre apenas o mínimo necessário para usá-los com o **FastAPI**... que é realmente muito pouco.\n\nO **FastAPI** é todo baseado nesses type hints, eles oferecem muitas vantagens e benefícios.\n\nMas mesmo que você nunca use o **FastAPI**, você se beneficiaria de aprender um pouco sobre eles.\n\n/// note | Nota\n\nSe você é um especialista em Python e já sabe tudo sobre type hints, pule para o próximo capítulo.\n\n///\n\n## Motivação { #motivation }\n\nVamos começar com um exemplo simples:\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\nA chamada deste programa gera:\n\n```\nJohn Doe\n```\n\nA função faz o seguinte:\n\n* Pega um `first_name` e `last_name`.\n* Converte a primeira letra de cada uma em maiúsculas com `title()`.\n* <dfn title=\"Coloca-os juntos, como um só. Com o conteúdo de um após o outro.\">Concatena</dfn> com um espaço no meio.\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### Edite-o { #edit-it }\n\nÉ um programa muito simples.\n\nMas agora imagine que você estava escrevendo do zero.\n\nEm algum momento você teria iniciado a definição da função, já tinha os parâmetros prontos...\n\nMas então você deve chamar \"esse método que converte a primeira letra em maiúscula\".\n\nEra `upper`? Era `uppercase`? `first_uppercase`? `capitalize`?\n\nEm seguida, tente com o velho amigo do programador, o preenchimento automático do editor.\n\nVocê digita o primeiro parâmetro da função, `first_name`, depois um ponto (`.`) e, em seguida, pressiona `Ctrl+Space` para acionar o preenchimento automático.\n\nMas, infelizmente, você não obtém nada útil:\n\n<img src=\"/img/python-types/image01.png\">\n\n### Adicionar tipos { #add-types }\n\nVamos modificar uma única linha da versão anterior.\n\nVamos mudar exatamente esse fragmento, os parâmetros da função, de:\n\n```Python\n    first_name, last_name\n```\n\npara:\n\n```Python\n    first_name: str, last_name: str\n```\n\nÉ isso aí.\n\nEsses são os \"type hints\":\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\nIsso não é o mesmo que declarar valores padrão como seria com:\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\nÉ uma coisa diferente.\n\nEstamos usando dois pontos (`:`), não sinal de igual (`=`).\n\nE adicionar type hints normalmente não muda o que acontece do que aconteceria sem eles.\n\nMas agora, imagine que você está novamente no meio da criação dessa função, mas com type hints.\n\nNo mesmo ponto, você tenta acionar o preenchimento automático com o `Ctrl+Space` e vê:\n\n<img src=\"/img/python-types/image02.png\">\n\nCom isso, você pode rolar, vendo as opções, até encontrar o que \"soa familiar\":\n\n<img src=\"/img/python-types/image03.png\">\n\n## Mais motivação { #more-motivation }\n\nVerifique esta função, ela já possui type hints:\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\nComo o editor conhece os tipos das variáveis, você não obtém apenas o preenchimento automático, mas também as verificações de erro:\n\n<img src=\"/img/python-types/image04.png\">\n\nAgora você sabe que precisa corrigi-la, convertendo `age` em uma string com `str(age)`:\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## Declarando tipos { #declaring-types }\n\nVocê acabou de ver o local principal para declarar type hints. Como parâmetros de função.\n\nEste também é o principal local em que você os usaria com o **FastAPI**.\n\n### Tipos simples { #simple-types }\n\nVocê pode declarar todos os tipos padrão de Python, não apenas `str`.\n\nVocê pode usar, por exemplo:\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### Módulo `typing` { #typing-module }\n\nPara alguns casos adicionais, você pode precisar importar alguns itens do módulo padrão `typing`, por exemplo, quando quiser declarar que algo pode ter \"qualquer tipo\", você pode usar `Any` de `typing`:\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### Tipos genéricos { #generic-types }\n\nAlguns tipos podem receber \"parâmetros de tipo\" entre colchetes, para definir seus tipos internos, por exemplo, uma \"lista de strings\" seria declarada como `list[str]`.\n\nEsses tipos que podem receber parâmetros de tipo são chamados **tipos genéricos** ou **genéricos**.\n\nVocê pode usar os mesmos tipos internos como genéricos (com colchetes e tipos dentro):\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### List { #list }\n\nPor exemplo, vamos definir uma variável para ser uma `list` de `str`.\n\nDeclare a variável, com a mesma sintaxe com dois pontos (`:`).\n\nComo o tipo, coloque `list`.\n\nComo a lista é um tipo que contém tipos internos, você os coloca entre colchetes:\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info | Informação\n\nEsses tipos internos dentro dos colchetes são chamados de \"parâmetros de tipo\".\n\nNeste caso, `str` é o parâmetro de tipo passado para `list`.\n\n///\n\nIsso significa: \"a variável `items` é uma `list`, e cada um dos itens desta lista é uma `str`\".\n\nAo fazer isso, seu editor pode fornecer suporte mesmo durante o processamento de itens da lista:\n\n<img src=\"/img/python-types/image05.png\">\n\nSem tipos, isso é quase impossível de alcançar.\n\nObserve que a variável `item` é um dos elementos da lista `items`.\n\nE, ainda assim, o editor sabe que é um `str` e fornece suporte para isso.\n\n#### Tuple e Set { #tuple-and-set }\n\nVocê faria o mesmo para declarar `tuple`s e `set`s:\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\nIsso significa:\n\n* A variável `items_t` é uma `tuple` com 3 itens, um `int`, outro `int` e uma `str`.\n* A variável `items_s` é um `set`, e cada um de seus itens é do tipo `bytes`.\n\n#### Dict { #dict }\n\nPara definir um `dict`, você passa 2 parâmetros de tipo, separados por vírgulas.\n\nO primeiro parâmetro de tipo é para as chaves do `dict`.\n\nO segundo parâmetro de tipo é para os valores do `dict`:\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\nIsso significa que:\n\n* A variável `prices` é um `dict`:\n    * As chaves deste `dict` são do tipo `str` (digamos, o nome de cada item).\n    * Os valores deste `dict` são do tipo `float` (digamos, o preço de cada item).\n\n#### Union { #union }\n\nVocê pode declarar que uma variável pode ser de qualquer um dentre **vários tipos**, por exemplo, um `int` ou um `str`.\n\nPara defini-la, você usa a <dfn title='também chamado de \"operador OU bit a bit\", mas esse significado não é relevante aqui'>barra vertical (`|`)</dfn> para separar ambos os tipos.\n\nIsso é chamado de \"união\", porque a variável pode ser qualquer coisa na união desses dois conjuntos de tipos.\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\nIsso significa que `item` pode ser um `int` ou um `str`.\n\n#### Possivelmente `None` { #possibly-none }\n\nVocê pode declarar que um valor pode ter um tipo, como `str`, mas que ele também pode ser `None`.\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\nUsar `str | None` em vez de apenas `str` permitirá que o editor o ajude a detectar erros em que você poderia estar assumindo que um valor é sempre um `str`, quando na verdade ele também pode ser `None`.\n\n### Classes como tipos { #classes-as-types }\n\nVocê também pode declarar uma classe como o tipo de uma variável.\n\nDigamos que você tenha uma classe `Person`, com um nome:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\nEntão você pode declarar que uma variável é do tipo `Person`:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\nE então, novamente, você recebe todo o suporte do editor:\n\n<img src=\"/img/python-types/image06.png\">\n\nPerceba que isso significa que \"`one_person` é uma **instância** da classe `Person`\".\n\nIsso não significa que \"`one_person` é a **classe** chamada `Person`\".\n\n## Modelos Pydantic { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/) é uma biblioteca Python para executar a validação de dados.\n\nVocê declara a \"forma\" dos dados como classes com atributos.\n\nE cada atributo tem um tipo.\n\nEm seguida, você cria uma instância dessa classe com alguns valores e ela os validará, os converterá para o tipo apropriado (se for esse o caso) e fornecerá um objeto com todos os dados.\n\nE você recebe todo o suporte do editor com esse objeto resultante.\n\nUm exemplo da documentação oficial do Pydantic:\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info | Informação\n\nPara saber mais sobre o [Pydantic, verifique a documentação](https://docs.pydantic.dev/).\n\n///\n\nO **FastAPI** é todo baseado em Pydantic.\n\nVocê verá muito mais disso na prática no [Tutorial - Guia do usuário](tutorial/index.md).\n\n## Type Hints com Metadados de Anotações { #type-hints-with-metadata-annotations }\n\nO Python também possui uma funcionalidade que permite incluir **<dfn title=\"Informações sobre os dados, neste caso, informações sobre o tipo, por exemplo, uma descrição.\">metadados</dfn> adicionais** nesses type hints utilizando `Annotated`.\n\nVocê pode importar `Annotated` de `typing`.\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nO Python em si não faz nada com este `Annotated`. E para editores e outras ferramentas, o tipo ainda é `str`.\n\nMas você pode utilizar este espaço dentro do `Annotated` para fornecer ao **FastAPI** metadados adicionais sobre como você deseja que a sua aplicação se comporte.\n\nO importante aqui de se lembrar é que **o primeiro *type parameter*** que você informar ao `Annotated` é o **tipo de fato**. O resto é apenas metadado para outras ferramentas.\n\nPor hora, você precisa apenas saber que o `Annotated` existe, e que ele é Python padrão. 😎\n\nMais tarde você verá o quão **poderoso** ele pode ser.\n\n/// tip | Dica\n\nO fato de que isso é **Python padrão** significa que você ainda obtém a **melhor experiência de desenvolvedor possível** no seu editor, com as ferramentas que você utiliza para analisar e refatorar o seu código, etc. ✨\n\nE também que o seu código será muito compatível com diversas outras ferramentas e bibliotecas Python. 🚀\n\n///\n\n## Type hints no **FastAPI** { #type-hints-in-fastapi }\n\nO **FastAPI** aproveita esses type hints para fazer várias coisas.\n\nCom o **FastAPI**, você declara parâmetros com type hints e obtém:\n\n* **Suporte ao editor**.\n* **Verificações de tipo**.\n\n... e o **FastAPI** usa as mesmas declarações para:\n\n* **Definir requisitos**: dos parâmetros de path da request, parâmetros da query, cabeçalhos, corpos, dependências, etc.\n* **Converter dados**: da request para o tipo necessário.\n* **Validar dados**: provenientes de cada request:\n    * Gerando **erros automáticos** retornados ao cliente quando os dados são inválidos.\n* **Documentar** a API usando OpenAPI:\n    * que é usada pelas interfaces de usuário da documentação interativa automática.\n\nTudo isso pode parecer abstrato. Não se preocupe. Você verá tudo isso em ação no [Tutorial - Guia do usuário](tutorial/index.md).\n\nO importante é que, usando tipos padrão de Python, em um único local (em vez de adicionar mais classes, decoradores, etc.), o **FastAPI** fará muito trabalho para você.\n\n/// info | Informação\n\nSe você já passou por todo o tutorial e voltou para ver mais sobre os tipos, um bom recurso é [a \"cheat sheet\" do `mypy`](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html).\n\n///\n"
  },
  {
    "path": "docs/pt/docs/resources/index.md",
    "content": "# Recursos { #resources }\n\nMaterial complementar, links externos e mais. ✈️\n"
  },
  {
    "path": "docs/pt/docs/translation-banner.md",
    "content": "/// details | 🌐 Tradução por IA e humanos\n\nEsta tradução foi feita por IA orientada por humanos. 🤝\n\nEla pode conter erros de interpretação do significado original ou soar pouco natural, etc. 🤖\n\nVocê pode melhorar esta tradução [ajudando-nos a orientar melhor o LLM de IA](https://fastapi.tiangolo.com/pt/contributing/#translations).\n\n[Versão em inglês](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/pt/docs/tutorial/background-tasks.md",
    "content": "# Tarefas em segundo plano { #background-tasks }\n\nVocê pode definir tarefas em segundo plano para serem executadas *após* retornar uma resposta.\n\nIsso é útil para operações que precisam acontecer após uma request, mas que o cliente não precisa realmente esperar a operação terminar antes de receber a resposta.\n\nIsso inclui, por exemplo:\n\n* Notificações por e-mail enviadas após realizar uma ação:\n    * Como conectar-se a um servidor de e-mail e enviar um e-mail tende a ser “lento” (vários segundos), você pode retornar a resposta imediatamente e enviar a notificação por e-mail em segundo plano.\n* Processamento de dados:\n    * Por exemplo, digamos que você receba um arquivo que precisa passar por um processo lento; você pode retornar uma resposta “Accepted” (HTTP 202) e processar o arquivo em segundo plano.\n\n## Usando `BackgroundTasks` { #using-backgroundtasks }\n\nPrimeiro, importe `BackgroundTasks` e defina um parâmetro na sua *função de operação de rota* com uma declaração de tipo `BackgroundTasks`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\nO **FastAPI** criará o objeto do tipo `BackgroundTasks` para você e o passará como esse parâmetro.\n\n## Crie uma função de tarefa { #create-a-task-function }\n\nCrie uma função para ser executada como a tarefa em segundo plano.\n\nÉ apenas uma função padrão que pode receber parâmetros.\n\nPode ser uma função `async def` ou um `def` normal, o **FastAPI** saberá como lidar com isso corretamente.\n\nNeste caso, a função da tarefa escreverá em um arquivo (simulando o envio de um e-mail).\n\nE como a operação de escrita não usa `async` e `await`, definimos a função com um `def` normal:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## Adicione a tarefa em segundo plano { #add-the-background-task }\n\nDentro da sua *função de operação de rota*, passe sua função de tarefa para o objeto de *tarefas em segundo plano* com o método `.add_task()`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\nO `.add_task()` recebe como argumentos:\n\n* Uma função de tarefa a ser executada em segundo plano (`write_notification`).\n* Qualquer sequência de argumentos que deve ser passada para a função de tarefa na ordem (`email`).\n* Quaisquer argumentos nomeados que devem ser passados para a função de tarefa (`message=\"some notification\"`).\n\n## Injeção de dependências { #dependency-injection }\n\nUsar `BackgroundTasks` também funciona com o sistema de injeção de dependências; você pode declarar um parâmetro do tipo `BackgroundTasks` em vários níveis: em uma *função de operação de rota*, em uma dependência (dependable), em uma subdependência, etc.\n\nO **FastAPI** sabe o que fazer em cada caso e como reutilizar o mesmo objeto, de forma que todas as tarefas em segundo plano sejam combinadas e executadas em segundo plano depois:\n\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\nNeste exemplo, as mensagens serão escritas no arquivo `log.txt` *após* o envio da resposta.\n\nSe houver uma query na request, ela será registrada em uma tarefa em segundo plano.\n\nE então outra tarefa em segundo plano gerada na *função de operação de rota* escreverá uma mensagem usando o parâmetro de path `email`.\n\n## Detalhes técnicos { #technical-details }\n\nA classe `BackgroundTasks` vem diretamente de [`starlette.background`](https://www.starlette.dev/background/).\n\nEla é importada/incluída diretamente no FastAPI para que você possa importá-la de `fastapi` e evitar importar acidentalmente a alternativa `BackgroundTask` (sem o `s` no final) de `starlette.background`.\n\nUsando apenas `BackgroundTasks` (e não `BackgroundTask`), é possível usá-la como um parâmetro de *função de operação de rota* e deixar o **FastAPI** cuidar do resto para você, assim como ao usar o objeto `Request` diretamente.\n\nAinda é possível usar `BackgroundTask` sozinho no FastAPI, mas você precisa criar o objeto no seu código e retornar uma `Response` da Starlette incluindo-o.\n\nVocê pode ver mais detalhes na [documentação oficial da Starlette para tarefas em segundo plano](https://www.starlette.dev/background/).\n\n## Ressalva { #caveat }\n\nSe você precisar realizar computação pesada em segundo plano e não necessariamente precisar que seja executada pelo mesmo processo (por exemplo, você não precisa compartilhar memória, variáveis, etc.), pode se beneficiar do uso de outras ferramentas maiores, como o [Celery](https://docs.celeryq.dev).\n\nElas tendem a exigir configurações mais complexas, um gerenciador de fila de mensagens/tarefas, como RabbitMQ ou Redis, mas permitem executar tarefas em segundo plano em vários processos e, especialmente, em vários servidores.\n\nMas se você precisa acessar variáveis e objetos da mesma aplicação **FastAPI**, ou precisa realizar pequenas tarefas em segundo plano (como enviar uma notificação por e-mail), você pode simplesmente usar `BackgroundTasks`.\n\n## Recapitulando { #recap }\n\nImporte e use `BackgroundTasks` com parâmetros em *funções de operação de rota* e dependências para adicionar tarefas em segundo plano.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/bigger-applications.md",
    "content": "# Aplicações Maiores - Múltiplos Arquivos { #bigger-applications-multiple-files }\n\nSe você está construindo uma aplicação ou uma API web, é raro que você possa colocar tudo em um único arquivo.\n\n**FastAPI** oferece uma ferramenta conveniente para estruturar sua aplicação, mantendo toda a flexibilidade.\n\n/// info | Informação\n\nSe você vem do Flask, isso seria o equivalente aos Blueprints do Flask.\n\n///\n\n## Um exemplo de estrutura de arquivos { #an-example-file-structure }\n\nDigamos que você tenha uma estrutura de arquivos como esta:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | Dica\n\nExistem vários arquivos `__init__.py`: um em cada diretório ou subdiretório.\n\nIsso permite a importação de código de um arquivo para outro.\n\nPor exemplo, no arquivo `app/main.py`, você poderia ter uma linha como:\n\n```\nfrom app.routers import items\n```\n\n///\n\n* O diretório `app` contém tudo. E possui um arquivo vazio `app/__init__.py`, então ele é um \"pacote Python\" (uma coleção de \"módulos Python\"): `app`.\n* Ele contém um arquivo `app/main.py`. Como está dentro de um pacote Python (um diretório com um arquivo `__init__.py`), ele é um \"módulo\" desse pacote: `app.main`.\n* Existe também um arquivo `app/dependencies.py`, assim como `app/main.py`, ele é um \"módulo\": `app.dependencies`.\n* Há um subdiretório `app/routers/` com outro arquivo `__init__.py`, então ele é um \"subpacote Python\": `app.routers`.\n* O arquivo `app/routers/items.py` está dentro de um pacote, `app/routers/`, portanto é um submódulo: `app.routers.items`.\n* O mesmo com `app/routers/users.py`, ele é outro submódulo: `app.routers.users`.\n* Há também um subdiretório `app/internal/` com outro arquivo `__init__.py`, então ele é outro \"subpacote Python\": `app.internal`.\n* E o arquivo `app/internal/admin.py` é outro submódulo: `app.internal.admin`.\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\nA mesma estrutura de arquivos com comentários:\n\n```bash\n.\n├── app                  # \"app\" é um pacote Python\n│   ├── __init__.py      # este arquivo torna \"app\" um \"pacote Python\"\n│   ├── main.py          # módulo \"main\", p.ex., import app.main\n│   ├── dependencies.py  # módulo \"dependencies\", p.ex., import app.dependencies\n│   └── routers          # \"routers\" é um \"subpacote Python\"\n│   │   ├── __init__.py  # torna \"routers\" um \"subpacote Python\"\n│   │   ├── items.py     # submódulo \"items\", p.ex., import app.routers.items\n│   │   └── users.py     # submódulo \"users\", p.ex., import app.routers.users\n│   └── internal         # \"internal\" é um \"subpacote Python\"\n│       ├── __init__.py  # torna \"internal\" um \"subpacote Python\"\n│       └── admin.py     # submódulo \"admin\", p.ex., import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\nVamos supor que o arquivo dedicado a lidar apenas com usuários seja o submódulo em `/app/routers/users.py`.\n\nVocê quer manter as *operações de rota* relacionadas aos seus usuários separadas do restante do código, para mantê-lo organizado.\n\nMas ele ainda faz parte da mesma aplicação/web API **FastAPI** (faz parte do mesmo \"pacote Python\").\n\nVocê pode criar as *operações de rota* para esse módulo usando o `APIRouter`.\n\n### Importe `APIRouter` { #import-apirouter }\n\nVocê o importa e cria uma \"instância\" da mesma maneira que faria com a classe `FastAPI`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### *Operações de Rota* com `APIRouter` { #path-operations-with-apirouter }\n\nE então você o utiliza para declarar suas *operações de rota*.\n\nUtilize-o da mesma maneira que utilizaria a classe `FastAPI`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\nVocê pode pensar em `APIRouter` como uma classe \"mini `FastAPI`\".\n\nTodas as mesmas opções são suportadas.\n\nTodos os mesmos `parameters`, `responses`, `dependencies`, `tags`, etc.\n\n/// tip | Dica\n\nNeste exemplo, a variável é chamada de `router`, mas você pode nomeá-la como quiser.\n\n///\n\nVamos incluir este `APIRouter` na aplicação principal `FastAPI`, mas primeiro, vamos verificar as dependências e outro `APIRouter`.\n\n## Dependências { #dependencies }\n\nVemos que precisaremos de algumas dependências usadas em vários lugares da aplicação.\n\nEntão, as colocamos em seu próprio módulo de `dependencies` (`app/dependencies.py`).\n\nAgora usaremos uma dependência simples para ler um cabeçalho `X-Token` personalizado:\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | Dica\n\nEstamos usando um cabeçalho inventado para simplificar este exemplo.\n\nMas em casos reais, você obterá melhores resultados usando os [Utilitários de Segurança](security/index.md) integrados.\n\n///\n\n## Outro módulo com `APIRouter` { #another-module-with-apirouter }\n\nDigamos que você também tenha os endpoints dedicados a manipular \"itens\" do seu aplicativo no módulo em `app/routers/items.py`.\n\nVocê tem *operações de rota* para:\n\n* `/items/`\n* `/items/{item_id}`\n\nÉ tudo a mesma estrutura de `app/routers/users.py`.\n\nMas queremos ser mais inteligentes e simplificar um pouco o código.\n\nSabemos que todas as *operações de rota* neste módulo têm o mesmo:\n\n* Path `prefix`: `/items`.\n* `tags`: (apenas uma tag: `items`).\n* Extra `responses`.\n* `dependencies`: todas elas precisam da dependência `X-Token` que criamos.\n\nEntão, em vez de adicionar tudo isso a cada *operação de rota*, podemos adicioná-lo ao `APIRouter`.\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\nComo o path de cada *operação de rota* tem que começar com `/`, como em:\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n...o prefixo não deve incluir um `/` final.\n\nEntão, o prefixo neste caso é `/items`.\n\nTambém podemos adicionar uma list de `tags` e `responses` extras que serão aplicadas a todas as *operações de rota* incluídas neste router.\n\nE podemos adicionar uma list de `dependencies` que serão adicionadas a todas as *operações de rota* no router e serão executadas/resolvidas para cada request feita a elas.\n\n/// tip | Dica\n\nObserve que, assim como [dependências em *decoradores de operação de rota*](dependencies/dependencies-in-path-operation-decorators.md), nenhum valor será passado para sua *função de operação de rota*.\n\n///\n\nO resultado final é que os paths dos itens agora são:\n\n* `/items/`\n* `/items/{item_id}`\n\n...como pretendíamos.\n\n* Elas serão marcadas com uma lista de tags que contêm uma única string `\"items\"`.\n    * Essas \"tags\" são especialmente úteis para os sistemas de documentação interativa automática (usando OpenAPI).\n* Todas elas incluirão as `responses` predefinidas.\n* Todas essas *operações de rota* terão a list de `dependencies` avaliada/executada antes delas.\n    * Se você também declarar dependências em uma *operação de rota* específica, **elas também serão executadas**.\n    * As dependências do router são executadas primeiro, depois as [`dependencies` no decorador](dependencies/dependencies-in-path-operation-decorators.md) e, em seguida, as dependências de parâmetros normais.\n    * Você também pode adicionar [dependências de `Segurança` com `scopes`](../advanced/security/oauth2-scopes.md).\n\n/// tip | Dica\n\nTer `dependencies` no `APIRouter` pode ser usado, por exemplo, para exigir autenticação para um grupo inteiro de *operações de rota*. Mesmo que as dependências não sejam adicionadas individualmente a cada uma delas.\n\n///\n\n/// check | Verifique\n\nOs parâmetros `prefix`, `tags`, `responses` e `dependencies` são (como em muitos outros casos) apenas um recurso do **FastAPI** para ajudar a evitar duplicação de código.\n\n///\n\n### Importe as dependências { #import-the-dependencies }\n\nEste código reside no módulo `app.routers.items`, o arquivo `app/routers/items.py`.\n\nE precisamos obter a função de dependência do módulo `app.dependencies`, o arquivo `app/dependencies.py`.\n\nEntão usamos uma importação relativa com `..` para as dependências:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### Como funcionam as importações relativas { #how-relative-imports-work }\n\n/// tip | Dica\n\nSe você sabe perfeitamente como funcionam as importações, continue para a próxima seção abaixo.\n\n///\n\nUm único ponto `.`, como em:\n\n```Python\nfrom .dependencies import get_token_header\n```\n\nsignificaria:\n\n* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) vive (o diretório `app/routers/`)...\n* encontre o módulo `dependencies` (um arquivo imaginário em `app/routers/dependencies.py`)...\n* e dele, importe a função `get_token_header`.\n\nMas esse arquivo não existe, nossas dependências estão em um arquivo em `app/dependencies.py`.\n\nLembre-se de como nossa estrutura app/file se parece:\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\nOs dois pontos `..`, como em:\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\nsignifica:\n\n* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) vive (o diretório `app/routers/`)...\n* vá para o pacote pai (o diretório `app/`)...\n* e lá, encontre o módulo `dependencies` (o arquivo em `app/dependencies.py`)...\n* e dele, importe a função `get_token_header`.\n\nIsso funciona corretamente! 🎉\n\n---\n\nDa mesma forma, se tivéssemos usado três pontos `...`, como em:\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\nisso significaria:\n\n* Começando no mesmo pacote em que este módulo (o arquivo `app/routers/items.py`) vive (o diretório `app/routers/`)...\n* vá para o pacote pai (o diretório `app/`)...\n* então vá para o pai daquele pacote (não há pacote pai, `app` é o nível superior 😱)...\n* e lá, encontre o módulo `dependencies` (o arquivo em `app/dependencies.py`)...\n* e dele, importe a função `get_token_header`.\n\nIsso se referiria a algum pacote acima de `app/`, com seu próprio arquivo `__init__.py`, etc. Mas não temos isso. Então, isso geraria um erro em nosso exemplo. 🚨\n\nMas agora você sabe como funciona, então você pode usar importações relativas em seus próprios aplicativos, não importa o quão complexos eles sejam. 🤓\n\n### Adicione algumas `tags`, `responses` e `dependencies` personalizadas { #add-some-custom-tags-responses-and-dependencies }\n\nNão estamos adicionando o prefixo `/items` nem `tags=[\"items\"]` a cada *operação de rota* porque os adicionamos ao `APIRouter`.\n\nMas ainda podemos adicionar _mais_ `tags` que serão aplicadas a uma *operação de rota* específica, e também algumas `responses` extras específicas para essa *operação de rota*:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | Dica\n\nEsta última operação de rota terá a combinação de tags: `[\"items\", \"custom\"]`.\n\nE também terá ambas as responses na documentação, uma para `404` e uma para `403`.\n\n///\n\n## O principal `FastAPI` { #the-main-fastapi }\n\nAgora, vamos ver o módulo em `app/main.py`.\n\nAqui é onde você importa e usa a classe `FastAPI`.\n\nEste será o arquivo principal em seu aplicativo que une tudo.\n\nE como a maior parte de sua lógica agora viverá em seu próprio módulo específico, o arquivo principal será bem simples.\n\n### Importe o `FastAPI` { #import-fastapi }\n\nVocê importa e cria uma classe `FastAPI` normalmente.\n\nE podemos até declarar [dependências globais](dependencies/global-dependencies.md) que serão combinadas com as dependências para cada `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### Importe o `APIRouter` { #import-the-apirouter }\n\nAgora importamos os outros submódulos que possuem `APIRouter`s:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\nComo os arquivos `app/routers/users.py` e `app/routers/items.py` são submódulos que fazem parte do mesmo pacote Python `app`, podemos usar um único ponto `.` para importá-los usando \"importações relativas\".\n\n### Como funciona a importação { #how-the-importing-works }\n\nA seção:\n\n```Python\nfrom .routers import items, users\n```\n\nsignifica:\n\n* Começando no mesmo pacote em que este módulo (o arquivo `app/main.py`) vive (o diretório `app/`)...\n* procure o subpacote `routers` (o diretório em `app/routers/`)...\n* e dele, importe o submódulo `items` (o arquivo em `app/routers/items.py`) e `users` (o arquivo em `app/routers/users.py`)...\n\nO módulo `items` terá uma variável `router` (`items.router`). Esta é a mesma que criamos no arquivo `app/routers/items.py`, é um objeto `APIRouter`.\n\nE então fazemos o mesmo para o módulo `users`.\n\nTambém poderíamos importá-los como:\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info | Informação\n\nA primeira versão é uma \"importação relativa\":\n\n```Python\nfrom .routers import items, users\n```\n\nA segunda versão é uma \"importação absoluta\":\n\n```Python\nfrom app.routers import items, users\n```\n\nPara saber mais sobre pacotes e módulos Python, leia [a documentação oficial do Python sobre módulos](https://docs.python.org/3/tutorial/modules.html).\n\n///\n\n### Evite colisões de nomes { #avoid-name-collisions }\n\nEstamos importando o submódulo `items` diretamente, em vez de importar apenas sua variável `router`.\n\nIsso ocorre porque também temos outra variável chamada `router` no submódulo `users`.\n\nSe tivéssemos importado um após o outro, como:\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\no `router` de `users` sobrescreveria o de `items` e não poderíamos usá-los ao mesmo tempo.\n\nEntão, para poder usar ambos no mesmo arquivo, importamos os submódulos diretamente:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### Inclua os `APIRouter`s para `users` e `items` { #include-the-apirouters-for-users-and-items }\n\nAgora, vamos incluir os `router`s dos submódulos `users` e `items`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info | Informação\n\n`users.router` contém o `APIRouter` dentro do arquivo `app/routers/users.py`.\n\nE `items.router` contém o `APIRouter` dentro do arquivo `app/routers/items.py`.\n\n///\n\nCom `app.include_router()` podemos adicionar cada `APIRouter` ao aplicativo principal `FastAPI`.\n\nEle incluirá todas as rotas daquele router como parte dele.\n\n/// note | Detalhes Técnicos\n\nNa verdade, ele criará internamente uma *operação de rota* para cada *operação de rota* que foi declarada no `APIRouter`.\n\nEntão, nos bastidores, ele realmente funcionará como se tudo fosse o mesmo aplicativo único.\n\n///\n\n/// check | Verifique\n\nVocê não precisa se preocupar com desempenho ao incluir routers.\n\nIsso levará microssegundos e só acontecerá na inicialização.\n\nEntão não afetará o desempenho. ⚡\n\n///\n\n### Inclua um `APIRouter` com um `prefix`, `tags`, `responses` e `dependencies` personalizados { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\nAgora, vamos imaginar que sua organização lhe deu o arquivo `app/internal/admin.py`.\n\nEle contém um `APIRouter` com algumas *operações de rota* de administração que sua organização compartilha entre vários projetos.\n\nPara este exemplo, será super simples. Mas digamos que, como ele é compartilhado com outros projetos na organização, não podemos modificá-lo e adicionar um `prefix`, `dependencies`, `tags`, etc. diretamente ao `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nMas ainda queremos definir um `prefix` personalizado ao incluir o `APIRouter` para que todas as suas *operações de rota* comecem com `/admin`, queremos protegê-lo com as `dependencies` que já temos para este projeto e queremos incluir `tags` e `responses`.\n\nPodemos declarar tudo isso sem precisar modificar o `APIRouter` original passando esses parâmetros para `app.include_router()`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\nDessa forma, o `APIRouter` original permanecerá inalterado, para que possamos compartilhar o mesmo arquivo `app/internal/admin.py` com outros projetos na organização.\n\nO resultado é que em nosso aplicativo, cada uma das *operações de rota* do módulo `admin` terá:\n\n* O prefixo `/admin`.\n* A tag `admin`.\n* A dependência `get_token_header`.\n* A resposta `418`. 🍵\n\nMas isso afetará apenas o `APIRouter` em nosso aplicativo, e não em nenhum outro código que o utilize.\n\nAssim, por exemplo, outros projetos poderiam usar o mesmo `APIRouter` com um método de autenticação diferente.\n\n### Inclua uma *operação de rota* { #include-a-path-operation }\n\nTambém podemos adicionar *operações de rota* diretamente ao aplicativo `FastAPI`.\n\nAqui fazemos isso... só para mostrar que podemos 🤷:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\ne funcionará corretamente, junto com todas as outras *operações de rota* adicionadas com `app.include_router()`.\n\n/// note | Detalhes Técnicos Avançados\n\n**Nota**: este é um detalhe muito técnico que você provavelmente pode **simplesmente pular**.\n\n---\n\nOs `APIRouter`s não são \"montados\", eles não são isolados do resto do aplicativo.\n\nIsso ocorre porque queremos incluir suas *operações de rota* no esquema OpenAPI e nas interfaces de usuário.\n\nComo não podemos simplesmente isolá-los e \"montá-los\" independentemente do resto, as *operações de rota* são \"clonadas\" (recriadas), não incluídas diretamente.\n\n///\n\n## Configure o `entrypoint` em `pyproject.toml` { #configure-the-entrypoint-in-pyproject-toml }\n\nComo seu objeto `app` do FastAPI fica em `app/main.py`, você pode configurar o `entrypoint` no seu arquivo `pyproject.toml` assim:\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\nisso é equivalente a importar como:\n\n```python\nfrom app.main import app\n```\n\nDessa forma o comando `fastapi` saberá onde encontrar sua aplicação.\n\n/// Note | Nota\n\nVocê também poderia passar o path para o comando, como:\n\n```console\n$ fastapi dev app/main.py\n```\n\nMas você teria que lembrar de passar o path correto toda vez que chamar o comando `fastapi`.\n\nAlém disso, outras ferramentas podem não conseguir encontrá-la, por exemplo a [Extensão do VS Code](../editor-support.md) ou a [FastAPI Cloud](https://fastapicloud.com), portanto é recomendável usar o `entrypoint` em `pyproject.toml`.\n\n///\n\n## Verifique a documentação automática da API { #check-the-automatic-api-docs }\n\nAgora, execute sua aplicação:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nE abra a documentação em [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVocê verá a documentação automática da API, incluindo os paths de todos os submódulos, usando os paths (e prefixos) corretos e as tags corretas:\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## Inclua o mesmo router várias vezes com `prefix` diferentes { #include-the-same-router-multiple-times-with-different-prefix }\n\nVocê também pode usar `.include_router()` várias vezes com o *mesmo* router usando prefixos diferentes.\n\nIsso pode ser útil, por exemplo, para expor a mesma API sob prefixos diferentes, por exemplo, `/api/v1` e `/api/latest`.\n\nEsse é um uso avançado que você pode não precisar, mas está lá caso precise.\n\n## Inclua um `APIRouter` em outro { #include-an-apirouter-in-another }\n\nDa mesma forma que você pode incluir um `APIRouter` em uma aplicação `FastAPI`, você pode incluir um `APIRouter` em outro `APIRouter` usando:\n\n```Python\nrouter.include_router(other_router)\n```\n\nCertifique-se de fazer isso antes de incluir `router` na aplicação `FastAPI`, para que as *operações de rota* de `other_router` também sejam incluídas.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/body-fields.md",
    "content": "# Corpo - Campos { #body-fields }\n\nDa mesma forma que você pode declarar validações adicionais e metadados nos parâmetros de uma *função de operação de rota* com `Query`, `Path` e `Body`, você pode declarar validações e metadados dentro de modelos do Pydantic usando `Field` do Pydantic.\n\n## Importe `Field` { #import-field }\n\nPrimeiro, você tem que importá-lo:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n/// warning | Atenção\n\nNote que `Field` é importado diretamente do `pydantic`, não do `fastapi` como todo o resto (`Query`, `Path`, `Body`, etc).\n\n///\n\n## Declare atributos do modelo { #declare-model-attributes }\n\nVocê pode então utilizar `Field` com atributos do modelo:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field` funciona da mesma forma que `Query`, `Path` e `Body`, ele possui todos os mesmos parâmetros, etc.\n\n/// note | Detalhes Técnicos\n\nNa realidade, `Query`, `Path` e outros que você verá em seguida, criam objetos de subclasses de uma classe `Param` comum, que é ela mesma uma subclasse da classe `FieldInfo` do Pydantic.\n\nE `Field` do Pydantic retorna uma instância de `FieldInfo` também.\n\n`Body` também retorna objetos de uma subclasse de `FieldInfo` diretamente. E tem outras que você verá mais tarde que são subclasses da classe `Body`.\n\nLembre-se que quando você importa `Query`, `Path`, e outros de `fastapi`, esse são na realidade funções que retornam classes especiais.\n\n///\n\n/// tip | Dica\n\nNote como cada atributo do modelo com um tipo, valor padrão e `Field` possuem a mesma estrutura que parâmetros de *funções de operações de rota*, com `Field` ao invés de `Path`, `Query` e `Body`.\n\n///\n\n## Adicione informações extras { #add-extra-information }\n\nVocê pode declarar informação extra em `Field`, `Query`, `Body`, etc. E isso será incluído no JSON Schema gerado.\n\nVocê irá aprender mais sobre adicionar informações extras posteriormente nessa documentação, quando estiver aprendendo a declarar exemplos.\n\n/// warning | Atenção\n\nChaves extras passadas para `Field` também estarão presentes no schema OpenAPI resultante da sua aplicação.\nComo essas chaves podem não fazer necessariamente parte da especificação OpenAPI, algumas ferramentas de OpenAPI, por exemplo [o validador do OpenAPI](https://validator.swagger.io/), podem não funcionar com o schema gerado.\n\n///\n\n## Recapitulando { #recap }\n\nVocê pode usar `Field` do Pydantic para declarar validações extras e metadados para atributos do modelo.\n\nVocê também pode usar os argumentos de palavras-chave extras para passar metadados do JSON Schema adicionais.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/body-multiple-params.md",
    "content": "# Corpo - Múltiplos parâmetros { #body-multiple-parameters }\n\nAgora que nós vimos como usar `Path` e `Query`, veremos usos mais avançados de declarações no corpo da requisição.\n\n## Misture `Path`, `Query` e parâmetros de corpo { #mix-path-query-and-body-parameters }\n\nPrimeiro, é claro, você pode misturar `Path`, `Query` e declarações de parâmetro no corpo da requisição livremente e o **FastAPI** saberá o que fazer.\n\nE você também pode declarar parâmetros de corpo como opcionais, definindo o valor padrão com `None`:\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | Nota\n\nRepare que, neste caso, o `item` que seria capturado a partir do corpo é opcional. Visto que ele possui `None` como valor padrão.\n\n///\n\n## Múltiplos parâmetros de corpo { #multiple-body-parameters }\n\nNo exemplo anterior, as *operações de rota* esperariam um JSON no corpo contendo os atributos de um `Item`, exemplo:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\nMas você pode também declarar múltiplos parâmetros de corpo, por exemplo, `item` e `user`:\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\nNeste caso, o **FastAPI** perceberá que existe mais de um parâmetro de corpo na função (dois parâmetros que são modelos Pydantic).\n\nEntão, ele usará o nome dos parâmetros como chaves (nome dos campos) no corpo, e espera um corpo como:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | Nota\n\nRepare que mesmo que o `item` esteja declarado da mesma maneira que antes, agora é esperado que ele esteja dentro do corpo com uma chave `item`.\n\n///\n\nO **FastAPI** fará a conversão automática a partir da requisição, assim esse parâmetro `item` receberá seu respectivo conteúdo e o mesmo ocorrerá com `user`.\n\nEle executará a validação dos dados compostos e irá documentá-los de maneira compatível com o esquema OpenAPI e documentação automática.\n\n## Valores singulares no corpo { #singular-values-in-body }\n\nAssim como existem uma `Query` e uma `Path` para definir dados adicionais para parâmetros de consulta e de rota, o **FastAPI** provê o equivalente para `Body`.\n\nPor exemplo, extendendo o modelo anterior, você poder decidir por ter uma outra chave `importance` no mesmo corpo, além de `item` e `user`.\n\nSe você declará-lo como é, porque é um valor singular, o **FastAPI** assumirá que se trata de um parâmetro de consulta.\n\nMas você pode instruir o **FastAPI** para tratá-lo como outra chave do corpo usando `Body`:\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\nNeste caso, o **FastAPI** esperará um corpo como:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\nMais uma vez, ele converterá os tipos de dados, validar, documentar, etc.\n\n## Múltiplos parâmetros de corpo e consulta { #multiple-body-params-and-query }\n\nObviamente, você também pode declarar parâmetros de consulta assim que você precisar, de modo adicional a quaisquer parâmetros de corpo.\n\nDado que, por padrão, valores singulares são interpretados como parâmetros de consulta, você não precisa explicitamente adicionar uma `Query`, você pode somente:\n\n```Python\nq: str | None = None\n```\n\nPor exemplo:\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n/// info | Informação\n\n`Body` também possui todas as validações adicionais e metadados de parâmetros como em `Query`,`Path` e outras que você verá depois.\n\n///\n\n## Declare um único parâmetro de corpo indicando sua chave { #embed-a-single-body-parameter }\n\nSuponha que você tem um único parâmetro de corpo `item`, a partir de um modelo Pydantic `Item`.\n\nPor padrão, o **FastAPI** esperará que seu conteúdo venha no corpo diretamente.\n\nMas se você quiser que ele espere por um JSON com uma chave `item` e dentro dele os conteúdos do modelo, como ocorre ao declarar vários parâmetros de corpo, você pode usar o parâmetro especial de `Body` chamado `embed`:\n\n```Python\nitem: Item = Body(embed=True)\n```\n\ncomo em:\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\nNeste caso o **FastAPI** esperará um corpo como:\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\nao invés de:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## Recapitulando { #recap }\n\nVocê pode adicionar múltiplos parâmetros de corpo para sua *função de operação de rota*, mesmo que a requisição possa ter somente um único corpo.\n\nE o **FastAPI** vai manipulá-los, mandar para você os dados corretos na sua função, e validar e documentar o schema correto na *operação de rota*.\n\nVocê também pode declarar valores singulares para serem recebidos como parte do corpo.\n\nE você pode instruir o **FastAPI** para requisitar no corpo a indicação de chave mesmo quando existe somente um único parâmetro declarado.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/body-nested-models.md",
    "content": "# Corpo - Modelos aninhados { #body-nested-models }\n\nCom o **FastAPI**, você pode definir, validar, documentar e usar modelos arbitrariamente e profundamente aninhados (graças ao Pydantic).\n\n## Campos do tipo Lista { #list-fields }\n\nVocê pode definir um atributo como um subtipo. Por exemplo, uma `list` do Python:\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\nIsso fará com que tags seja uma lista de itens mesmo sem declarar o tipo dos elementos desta lista.\n\n## Campos do tipo Lista com um parâmetro de tipo { #list-fields-with-type-parameter }\n\nMas o Python tem uma maneira específica de declarar listas com tipos internos ou \"parâmetros de tipo\":\n\n### Declare uma `list` com um parâmetro de tipo { #declare-a-list-with-a-type-parameter }\n\nPara declarar tipos que têm parâmetros de tipo (tipos internos), como `list`, `dict`, `tuple`,\npasse o(s) tipo(s) interno(s) como \"parâmetros de tipo\" usando colchetes: `[` e `]`\n\n```Python\nmy_list: list[str]\n```\n\nEssa é a sintaxe padrão do Python para declarações de tipo.\n\nUse a mesma sintaxe padrão para atributos de modelo com tipos internos.\n\nPortanto, em nosso exemplo, podemos fazer com que `tags` sejam especificamente uma \"lista de strings\":\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## Tipos \"set\" { #set-types }\n\nMas então, quando nós pensamos mais, percebemos que as tags não devem se repetir, elas provavelmente devem ser strings únicas.\n\nE que o Python tem um tipo de dados especial para conjuntos de itens únicos, o `set`.\n\nEntão podemos declarar `tags` como um conjunto de strings:\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\nCom isso, mesmo que você receba uma requisição contendo dados duplicados, ela será convertida em um conjunto de itens exclusivos.\n\nE sempre que você enviar esses dados como resposta, mesmo se a fonte tiver duplicatas, eles serão gerados como um conjunto de itens exclusivos.\n\nE também teremos anotações/documentação em conformidade.\n\n## Modelos aninhados { #nested-models }\n\nCada atributo de um modelo Pydantic tem um tipo.\n\nMas esse tipo pode ser outro modelo Pydantic.\n\nPortanto, você pode declarar \"objects\" JSON profundamente aninhados com nomes, tipos e validações de atributos específicos.\n\nTudo isso, aninhado arbitrariamente.\n\n### Defina um sub-modelo { #define-a-submodel }\n\nPor exemplo, nós podemos definir um modelo `Image`:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### Use o sub-modelo como um tipo { #use-the-submodel-as-a-type }\n\nE então podemos usá-lo como o tipo de um atributo:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\nIsso significa que o **FastAPI** vai esperar um corpo similar à:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\nNovamente, apenas fazendo essa declaração, com o **FastAPI**, você ganha:\n\n* Suporte do editor (preenchimento automático, etc.), inclusive para modelos aninhados\n* Conversão de dados\n* Validação de dados\n* Documentação automática\n\n## Tipos especiais e validação { #special-types-and-validation }\n\nAlém dos tipos singulares normais como `str`, `int`, `float`, etc. Você também pode usar tipos singulares mais complexos que herdam de `str`.\n\nPara ver todas as opções possíveis, consulte a [Visão geral dos tipos do Pydantic](https://docs.pydantic.dev/latest/concepts/types/). Você verá alguns exemplos no próximo capítulo.\n\nPor exemplo, no modelo `Image` nós temos um campo `url`, nós podemos declará-lo como um `HttpUrl` do Pydantic invés de como uma `str`:\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\nA string será verificada para se tornar uma URL válida e documentada no JSON Schema / OpenAPI como tal.\n\n## Atributos como listas de submodelos { #attributes-with-lists-of-submodels }\n\nVocê também pode usar modelos Pydantic como subtipos de `list`, `set`, etc:\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\nIsso vai esperar (converter, validar, documentar, etc) um corpo JSON tal qual:\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info | Informação\n\nObserve como a chave `images` agora tem uma lista de objetos de imagem.\n\n///\n\n## Modelos profundamente aninhados { #deeply-nested-models }\n\nVocê pode definir modelos profundamente aninhados de forma arbitrária:\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info | Informação\n\nObserve como `Offer` tem uma lista de `Item`s, que por sua vez têm uma lista opcional de `Image`s\n\n///\n\n## Corpos de listas puras { #bodies-of-pure-lists }\n\nSe o valor de primeiro nível do corpo JSON que você espera for um `array` do JSON (uma` lista` do Python), você pode declarar o tipo no parâmetro da função, da mesma forma que nos modelos do Pydantic:\n\n```Python\nimages: list[Image]\n```\n\ncomo em:\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## Suporte de editor em todo canto { #editor-support-everywhere }\n\nE você obtém suporte do editor em todos os lugares.\n\nMesmo para itens dentro de listas:\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\nVocê não conseguiria este tipo de suporte de editor se estivesse trabalhando diretamente com `dict` em vez de modelos Pydantic.\n\nMas você também não precisa se preocupar com eles, os dicts de entrada são convertidos automaticamente e sua saída é convertida automaticamente para JSON também.\n\n## Corpos de `dict`s arbitrários { #bodies-of-arbitrary-dicts }\n\nVocê também pode declarar um corpo como um `dict` com chaves de algum tipo e valores de outro tipo.\n\nSem ter que saber de antemão quais são os nomes de campos/atributos válidos (como seria o caso dos modelos Pydantic).\n\nIsso seria útil se você deseja receber chaves que ainda não conhece.\n\n---\n\nOutro caso útil é quando você deseja ter chaves de outro tipo, por exemplo, `int`.\n\nÉ isso que vamos ver aqui.\n\nNeste caso, você aceitaria qualquer `dict`, desde que tenha chaves` int` com valores `float`:\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip | Dica\n\nLeve em consideração que o JSON só suporta `str` como chaves.\n\nMas o Pydantic tem conversão automática de dados.\n\nIsso significa que, embora os clientes da API só possam enviar strings como chaves, desde que essas strings contenham inteiros puros, o Pydantic irá convertê-los e validá-los.\n\nE o `dict` que você recebe como `weights` terá, na verdade, chaves `int` e valores` float`.\n\n///\n\n## Recapitulação { #recap }\n\nCom **FastAPI** você tem a flexibilidade máxima fornecida pelos modelos Pydantic, enquanto seu código é mantido simples, curto e elegante.\n\nMas com todos os benefícios:\n\n* Suporte do editor (preenchimento automático em todo canto!)\n* Conversão de dados (parsing/serialização)\n* Validação de dados\n* Documentação dos esquemas\n* Documentação automática\n"
  },
  {
    "path": "docs/pt/docs/tutorial/body-updates.md",
    "content": "# Corpo - Atualizações { #body-updates }\n\n## Atualização substituindo com `PUT` { #update-replacing-with-put }\n\nPara atualizar um item, você pode usar a operação [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT).\n\nVocê pode usar `jsonable_encoder` para converter os dados de entrada em dados que podem ser armazenados como JSON (por exemplo, com um banco de dados NoSQL). Por exemplo, convertendo `datetime` em `str`.\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT` é usado para receber dados que devem substituir os dados existentes.\n\n### Aviso sobre a substituição { #warning-about-replacing }\n\nIsso significa que, se você quiser atualizar o item `bar` usando `PUT` com um corpo contendo:\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\ncomo ele não inclui o atributo já armazenado `\"tax\": 20.2`, o modelo de entrada assumiria o valor padrão de `\"tax\": 10.5`.\n\nE os dados seriam salvos com esse \"novo\" `tax` de `10.5`.\n\n## Atualizações parciais com `PATCH` { #partial-updates-with-patch }\n\nVocê também pode usar a operação [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) para atualizar dados *parcialmente*.\n\nIsso significa que você pode enviar apenas os dados que deseja atualizar, deixando o restante intacto.\n\n/// note | Nota\n\n`PATCH` é menos comumente usado e conhecido do que `PUT`.\n\nE muitas equipes usam apenas `PUT`, mesmo para atualizações parciais.\n\nVocê é **livre** para usá-los como preferir, **FastAPI** não impõe restrições.\n\nMas este guia mostra, mais ou menos, como eles são destinados a serem usados.\n\n///\n\n### Usando o parâmetro `exclude_unset` do Pydantic { #using-pydantics-exclude-unset-parameter }\n\nSe você quiser receber atualizações parciais, é muito útil usar o parâmetro `exclude_unset` no `.model_dump()` do modelo do Pydantic.\n\nComo `item.model_dump(exclude_unset=True)`.\n\nIsso geraria um `dict` com apenas os dados que foram definidos ao criar o modelo `item`, excluindo os valores padrão.\n\nEntão, você pode usar isso para gerar um `dict` com apenas os dados definidos (enviados na solicitação), omitindo valores padrão:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### Usando o parâmetro `update` do Pydantic { #using-pydantics-update-parameter }\n\nAgora, você pode criar uma cópia do modelo existente usando `.model_copy()`, e passar o parâmetro `update` com um `dict` contendo os dados para atualizar.\n\nComo `stored_item_model.model_copy(update=update_data)`:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### Recapitulando as atualizações parciais { #partial-updates-recap }\n\nResumindo, para aplicar atualizações parciais você deveria:\n\n* (Opcionalmente) usar `PATCH` em vez de `PUT`.\n* Recuperar os dados armazenados.\n* Colocar esses dados em um modelo do Pydantic.\n* Gerar um `dict` sem valores padrão a partir do modelo de entrada (usando `exclude_unset`).\n    * Dessa forma, você pode atualizar apenas os valores realmente definidos pelo usuário, em vez de substituir valores já armazenados por valores padrão do modelo.\n* Criar uma cópia do modelo armazenado, atualizando seus atributos com as atualizações parciais recebidas (usando o parâmetro `update`).\n* Converter o modelo copiado em algo que possa ser armazenado no seu BD (por exemplo, usando o `jsonable_encoder`).\n    * Isso é comparável a usar o método `.model_dump()` do modelo novamente, mas garante (e converte) os valores para tipos de dados que possam ser convertidos em JSON, por exemplo, `datetime` para `str`.\n* Salvar os dados no seu BD.\n* Retornar o modelo atualizado.\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | Dica\n\nVocê pode realmente usar essa mesma técnica com uma operação HTTP `PUT`.\n\nMas o exemplo aqui usa `PATCH` porque foi criado para esses casos de uso.\n\n///\n\n/// note | Nota\n\nObserve que o modelo de entrada ainda é validado.\n\nPortanto, se você quiser receber atualizações parciais que possam omitir todos os atributos, você precisa ter um modelo com todos os atributos marcados como opcionais (com valores padrão ou `None`).\n\nPara distinguir entre os modelos com todos os valores opcionais para **atualizações** e modelos com valores obrigatórios para **criação**, você pode usar as ideias descritas em [Modelos Adicionais](extra-models.md).\n\n///\n"
  },
  {
    "path": "docs/pt/docs/tutorial/body.md",
    "content": "# Corpo da requisição { #request-body }\n\nQuando você precisa enviar dados de um cliente (como de um navegador) para sua API, você os envia como um **corpo da requisição**.\n\nO corpo da **requisição** é a informação enviada pelo cliente para sua API. O corpo da **resposta** é a informação que sua API envia para o cliente.\n\nSua API quase sempre precisa enviar um corpo na **resposta**. Mas os clientes não necessariamente precisam enviar **corpos de requisição** o tempo todo, às vezes eles apenas requisitam um path, talvez com alguns parâmetros de consulta, mas não enviam um corpo.\n\nPara declarar um corpo da **requisição**, você utiliza os modelos do [Pydantic](https://docs.pydantic.dev/) com todos os seus poderes e benefícios.\n\n/// info | Informação\n\nPara enviar dados, você deveria usar um dos: `POST` (o mais comum), `PUT`, `DELETE` ou `PATCH`.\n\nEnviar um corpo em uma requisição `GET` não tem um comportamento definido nas especificações, porém é suportado pelo FastAPI, apenas para casos de uso bem complexos/extremos.\n\nComo é desencorajado, a documentação interativa com Swagger UI não irá mostrar a documentação para o corpo da requisição ao usar `GET`, e proxies intermediários podem não suportá-lo.\n\n///\n\n## Importe o `BaseModel` do Pydantic { #import-pydantics-basemodel }\n\nPrimeiro, você precisa importar `BaseModel` do `pydantic`:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## Crie seu modelo de dados { #create-your-data-model }\n\nEntão você declara seu modelo de dados como uma classe que herda `BaseModel`.\n\nUtilize os tipos Python padrão para todos os atributos:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\n\nAssim como quando declaramos parâmetros de consulta, quando um atributo do modelo possui um valor padrão, ele não é obrigatório. Caso contrário, é obrigatório. Use `None` para torná-lo apenas opcional.\n\nPor exemplo, o modelo acima declara um JSON \"`object`\" (ou `dict` no Python) como esse:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n...como `description` e `tax` são opcionais (com um valor padrão de `None`), esse JSON \"`object`\" também é válido:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## Declare como um parâmetro { #declare-it-as-a-parameter }\n\nPara adicioná-lo à sua *operação de rota*, declare-o da mesma maneira que você declarou parâmetros de rota e de consulta:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n...e declare o seu tipo como o modelo que você criou, `Item`.\n\n## Resultados { #results }\n\nApenas com essa declaração de tipos do Python, o **FastAPI** irá:\n\n* Ler o corpo da requisição como JSON.\n* Converter os tipos correspondentes (se necessário).\n* Validar os dados.\n    * Se algum dado for inválido, irá retornar um erro bem claro, indicando exatamente onde e o que estava incorreto.\n* Entregar a você a informação recebida no parâmetro `item`.\n    * Como você o declarou na função como do tipo `Item`, você também terá o suporte do editor (preenchimento automático, etc) para todos os atributos e seus tipos.\n* Gerar definições de [JSON Schema](https://json-schema.org) para o seu modelo; você também pode usá-las em qualquer outro lugar se fizer sentido para o seu projeto.\n* Esses schemas farão parte do esquema OpenAPI gerado, e serão usados pelas <abbr title=\"User Interfaces - Interfaces de usuário\">UIs</abbr> de documentação automática.\n\n## Documentação automática { #automatic-docs }\n\nOs JSON Schemas dos seus modelos farão parte do esquema OpenAPI gerado para sua aplicação, e aparecerão na documentação interativa da API:\n\n<img src=\"/img/tutorial/body/image01.png\">\n\nE também serão utilizados na documentação da API dentro de cada *operação de rota* que precisar deles:\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## Suporte do editor { #editor-support }\n\nNo seu editor, dentro da função você receberá dicas de tipos e preenchimento automático em todo lugar (isso não aconteceria se você recebesse um `dict` em vez de um modelo Pydantic):\n\n<img src=\"/img/tutorial/body/image03.png\">\n\nVocê também poderá receber verificações de erros para operações de tipos incorretas:\n\n<img src=\"/img/tutorial/body/image04.png\">\n\nIsso não é por acaso, todo o framework foi construído em volta deste design.\n\nE foi imensamente testado na fase de design, antes de qualquer implementação, para garantir que funcionaria para todos os editores de texto.\n\nHouveram mudanças no próprio Pydantic para que isso fosse possível.\n\nAs capturas de tela anteriores foram capturas no [Visual Studio Code](https://code.visualstudio.com).\n\nMas você terá o mesmo suporte do editor no [PyCharm](https://www.jetbrains.com/pycharm/) e na maioria dos editores Python:\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip | Dica\n\nSe você utiliza o [PyCharm](https://www.jetbrains.com/pycharm/) como editor, você pode utilizar o [Plugin do Pydantic para o PyCharm](https://github.com/koxudaxi/pydantic-pycharm-plugin/).\n\nMelhora o suporte do editor para seus modelos Pydantic com:\n\n* preenchimento automático\n* verificação de tipos\n* refatoração\n* buscas\n* inspeções\n\n///\n\n## Use o modelo { #use-the-model }\n\nDentro da função, você pode acessar todos os atributos do objeto do modelo diretamente:\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## Corpo da requisição + parâmetros de rota { #request-body-path-parameters }\n\nVocê pode declarar parâmetros de rota e corpo da requisição ao mesmo tempo.\n\nO **FastAPI** irá reconhecer que os parâmetros da função que combinam com parâmetros de rota devem ser **retirados da rota**, e que parâmetros da função que são declarados como modelos Pydantic sejam **retirados do corpo da requisição**.\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n\n## Corpo da requisição + parâmetros de rota + parâmetros de consulta { #request-body-path-query-parameters }\n\nVocê também pode declarar parâmetros de **corpo**, **rota** e **consulta**, ao mesmo tempo.\n\nO **FastAPI** irá reconhecer cada um deles e retirar a informação do local correto.\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\nOs parâmetros da função serão reconhecidos conforme abaixo:\n\n* Se o parâmetro também é declarado no **path**, será utilizado como um parâmetro de rota.\n* Se o parâmetro é de um **tipo único** (como `int`, `float`, `str`, `bool`, etc) será interpretado como um parâmetro de **consulta**.\n* Se o parâmetro é declarado como um **modelo Pydantic**, será interpretado como o **corpo** da requisição.\n\n/// note | Nota\n\nO FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`.\n\nO `str | None` não é utilizado pelo FastAPI para determinar que o valor não é obrigatório, ele saberá que não é obrigatório porque tem um valor padrão `= None`.\n\nMas adicionar as anotações de tipo permitirá ao seu editor oferecer um suporte melhor e detectar erros.\n\n///\n\n## Sem o Pydantic { #without-pydantic }\n\nSe você não quer utilizar os modelos Pydantic, você também pode utilizar o parâmetro **Body**. Veja a documentação para [Body - Parâmetros múltiplos: Valores singulares no body](body-multiple-params.md#singular-values-in-body).\n"
  },
  {
    "path": "docs/pt/docs/tutorial/cookie-param-models.md",
    "content": "# Modelos de Parâmetros de Cookie { #cookie-parameter-models }\n\nSe você possui um grupo de **cookies** que estão relacionados, você pode criar um **modelo Pydantic** para declará-los. 🍪\n\nIsso lhe permitiria **reutilizar o modelo** em **diversos lugares** e também declarar validações e metadata para todos os parâmetros de uma vez. 😎\n\n/// note | Nota\n\nIsso é suportado desde a versão `0.115.0` do FastAPI. 🤓\n\n///\n\n/// tip | Dica\n\nEssa mesma técnica se aplica para `Query`, `Cookie`, e `Header`. 😎\n\n///\n\n## Cookies com Modelos Pydantic { #cookies-with-a-pydantic-model }\n\nDeclare os parâmetros de **cookie** de que você precisa em um **modelo Pydantic**, e depois declare o parâmetro como `Cookie`:\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\nO **FastAPI** irá **extrair** os dados para **cada campo** dos **cookies** recebidos na requisição e lhe fornecer o modelo Pydantic que você definiu.\n\n## Verifique a Documentação { #check-the-docs }\n\nVocê pode ver os cookies definidos na IU da documentação em `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info | Informação\n\nTenha em mente que, como os **navegadores lidam com cookies** de maneira especial e por baixo dos panos, eles **não** permitem facilmente que o **JavaScript** lidem com eles.\n\nSe você for na **IU da documentação da API** em `/docs` você poderá ver a **documentação** para cookies das suas *operações de rotas*.\n\nMas mesmo que você **adicionar os dados** e clicar em \"Executar\", pelo motivo da IU da documentação trabalhar com **JavaScript**, os cookies não serão enviados, e você verá uma mensagem de **erro** como se você não tivesse escrito nenhum dado.\n\n///\n\n## Proibir Cookies Adicionais { #forbid-extra-cookies }\n\nEm alguns casos especiais (provavelmente não muito comuns), você pode querer **restringir** os cookies que você deseja receber.\n\nAgora a sua API possui o poder de controlar o seu próprio <dfn title=\"Isso é uma brincadeira, só por precaução. Isso não tem nada a ver com consentimentos de cookies, mas é engraçado que até a API consegue rejeitar os coitados dos cookies. Coma um biscoito. 🍪\">consentimento de cookie</dfn>. 🤪🍪\n\nVocê pode utilizar a configuração do modelo Pydantic para `proibir` qualquer campo `extra`:\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\nSe o cliente tentar enviar alguns **cookies extras**, eles receberão um retorno de **erro**.\n\nCoitados dos banners de cookies com todo o seu esforço para obter o seu consentimento para a <dfn title=\"Isso é uma outra piada. Não preste atenção em mim. Beba um café com o seu cookie. ☕\">API rejeitá-lo</dfn>. 🍪\n\nPor exemplo, se o cliente tentar enviar um cookie `santa_tracker` com o valor de `good-list-please`, o cliente receberá uma resposta de **erro** informando que o `santa_tracker` <dfn title=\"O papai noel desaprova a falta de biscoitos. 🎅 Ok, chega de piadas com os cookies.\">cookie não é permitido</dfn>:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## Resumo { #summary }\n\nVocê consegue utilizar **modelos Pydantic** para declarar <dfn title=\"Coma um último biscoito antes de você ir embora. 🍪\">**cookies**</dfn> no **FastAPI**. 😎\n"
  },
  {
    "path": "docs/pt/docs/tutorial/cookie-params.md",
    "content": "# Parâmetros de Cookie { #cookie-parameters }\n\nVocê pode definir parâmetros de Cookie da mesma maneira que define parâmetros com `Query` e `Path`.\n\n## Importe `Cookie` { #import-cookie }\n\nPrimeiro importe `Cookie`:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## Declare parâmetros de `Cookie` { #declare-cookie-parameters }\n\nEntão declare os parâmetros de cookie usando a mesma estrutura que em `Path` e `Query`.\n\nVocê pode definir o valor padrão, assim como todas as validações extras ou parâmetros de anotação:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Detalhes Técnicos\n\n`Cookie` é uma classe \"irmã\" de `Path` e `Query`. Ela também herda da mesma classe em comum `Param`.\n\nMas lembre-se que quando você importa `Query`, `Path`, `Cookie` e outras de `fastapi`, elas são na verdade funções que retornam classes especiais.\n\n///\n\n/// info | Informação\n\nPara declarar cookies, você precisa usar `Cookie`, pois caso contrário, os parâmetros seriam interpretados como parâmetros de consulta.\n\n///\n\n/// info | Informação\n\nTenha em mente que, como os **navegadores lidam com cookies** de maneiras especiais e nos bastidores, eles **não** permitem facilmente que o **JavaScript** os acesse.\n\nSe você for à **interface de documentação da API** em `/docs`, poderá ver a **documentação** de cookies para suas *operações de rota*.\n\nMas mesmo que você **preencha os dados** e clique em \"Execute\", como a interface de documentação funciona com **JavaScript**, os cookies não serão enviados e você verá uma mensagem de **erro** como se você não tivesse escrito nenhum valor.\n\n///\n\n## Recapitulando { #recap }\n\nDeclare cookies com `Cookie`, usando o mesmo padrão comum que utiliza-se em `Query` e `Path`.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/cors.md",
    "content": "# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }\n\n[CORS ou \"Cross-Origin Resource Sharing\"](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) refere-se às situações em que um frontend rodando em um navegador possui um código JavaScript que se comunica com um backend, e o backend está em uma \"origem\" diferente do frontend.\n\n## Origem { #origin }\n\nUma origem é a combinação de protocolo (`http`, `https`), domínio (`myapp.com`, `localhost`, `localhost.tiangolo.com`), e porta (`80`, `443`, `8080`).\n\nEntão, todos estes são origens diferentes:\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\nMesmo se todos estiverem em `localhost`, eles usam diferentes protocolos ou portas, portanto, são \"origens\" diferentes.\n\n## Passos { #steps }\n\nEntão, digamos que você tenha um frontend rodando no seu navegador em `http://localhost:8080`, e seu JavaScript esteja tentando se comunicar com um backend rodando em `http://localhost` (como não especificamos uma porta, o navegador assumirá a porta padrão `80`).\n\nPortanto, o navegador enviará uma requisição HTTP `OPTIONS` ao backend `:80`, e se o backend enviar os cabeçalhos apropriados autorizando a comunicação a partir dessa origem diferente (`http://localhost:8080`), então o navegador `:8080` permitirá que o JavaScript no frontend envie sua requisição para o backend `:80`.\n\nPara conseguir isso, o backend `:80` deve ter uma lista de \"origens permitidas\".\n\nNeste caso, a lista terá que incluir `http://localhost:8080` para o frontend `:8080` funcionar corretamente.\n\n## Curingas { #wildcards }\n\nÉ possível declarar a lista como `\"*\"` (um \"curinga\") para dizer que tudo está permitido.\n\nMas isso só permitirá certos tipos de comunicação, excluindo tudo que envolva credenciais: cookies, cabeçalhos de autorização como aqueles usados ​​com Bearer Tokens, etc.\n\nEntão, para que tudo funcione corretamente, é melhor especificar explicitamente as origens permitidas.\n\n## Usar `CORSMiddleware` { #use-corsmiddleware }\n\nVocê pode configurá-lo em sua aplicação **FastAPI** usando o `CORSMiddleware`.\n\n* Importe `CORSMiddleware`.\n* Crie uma lista de origens permitidas (como strings).\n* Adicione-a como um \"middleware\" à sua aplicação **FastAPI**.\n\nVocê também pode especificar se o seu backend permite:\n\n* Credenciais (Cabeçalhos de autorização, Cookies, etc).\n* Métodos HTTP específicos (`POST`, `PUT`) ou todos eles com o curinga `\"*\"`.\n* Cabeçalhos HTTP específicos ou todos eles com o curinga `\"*\"`.\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\n\nOs parâmetros padrão usados ​​pela implementação `CORSMiddleware` são restritivos por padrão, então você precisará habilitar explicitamente as origens, métodos ou cabeçalhos específicos para que os navegadores tenham permissão para usá-los em um contexto cross domain.\n\nOs seguintes argumentos são suportados:\n\n* `allow_origins` - Uma lista de origens que devem ter permissão para fazer requisições de origem cruzada. Por exemplo, `['https://example.org', 'https://www.example.org']`. Você pode usar `['*']` para permitir qualquer origem.\n* `allow_origin_regex` - Uma string regex para corresponder às origens que devem ter permissão para fazer requisições de origem cruzada. Por exemplo, `'https://.*\\.example\\.org'`.\n* `allow_methods` - Uma lista de métodos HTTP que devem ser permitidos para requisições de origem cruzada. O padrão é `['GET']`. Você pode usar `['*']` para permitir todos os métodos padrão.\n* `allow_headers` - Uma lista de cabeçalhos de solicitação HTTP que devem ter suporte para requisições de origem cruzada. O padrão é `[]`. Você pode usar `['*']` para permitir todos os cabeçalhos. Os cabeçalhos `Accept`, `Accept-Language`, `Content-Language` e `Content-Type` são sempre permitidos para [requisições CORS simples](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).\n* `allow_credentials` - Indica que os cookies devem ser suportados para requisições de origem cruzada. O padrão é `False`.\n\n    Nenhum de `allow_origins`, `allow_methods` e `allow_headers` pode ser definido como `['*']` se `allow_credentials` estiver definido como `True`. Todos eles devem ser [especificados explicitamente](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards).\n\n* `expose_headers` - Indica quaisquer cabeçalhos de resposta que devem ser disponibilizados ao navegador. O padrão é `[]`.\n* `max_age` - Define um tempo máximo em segundos para os navegadores armazenarem em cache as respostas CORS. O padrão é `600`.\n\nO middleware responde a dois tipos específicos de solicitação HTTP...\n\n### Requisições CORS pré-voo (preflight) { #cors-preflight-requests }\n\nEstas são quaisquer solicitações `OPTIONS` com cabeçalhos `Origin` e `Access-Control-Request-Method`.\n\nNesse caso, o middleware interceptará a solicitação recebida e responderá com cabeçalhos CORS apropriados e uma resposta `200` ou `400` para fins informativos.\n\n### Requisições Simples { #simple-requests }\n\nQualquer solicitação com um cabeçalho `Origin`. Neste caso, o middleware passará a solicitação normalmente, mas incluirá cabeçalhos CORS apropriados na resposta.\n\n## Mais informações { #more-info }\n\nPara mais informações sobre <abbr title=\"Cross-Origin Resource Sharing\">CORS</abbr>, consulte a [documentação do CORS da Mozilla](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).\n\n/// note | Detalhes Técnicos\n\nVocê também pode usar `from starlette.middleware.cors import CORSMiddleware`.\n\n**FastAPI** fornece vários middlewares em `fastapi.middleware` apenas como uma conveniência para você, o desenvolvedor. Mas a maioria dos middlewares disponíveis vêm diretamente da Starlette.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/tutorial/debugging.md",
    "content": "# Depuração { #debugging }\n\nVocê pode conectar o depurador no seu editor, por exemplo, com o Visual Studio Code ou PyCharm.\n\n## Chamar `uvicorn` { #call-uvicorn }\n\nEm sua aplicação FastAPI, importe e execute `uvicorn` diretamente:\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### Sobre `__name__ == \"__main__\"` { #about-name-main }\n\nO objetivo principal de `__name__ == \"__main__\"` é ter algum código que seja executado quando seu arquivo for chamado com:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nmas não é chamado quando outro arquivo o importa, como em:\n\n```Python\nfrom myapp import app\n```\n\n#### Mais detalhes { #more-details }\n\nDigamos que seu arquivo se chama `myapp.py`.\n\nSe você executá-lo com:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nentão a variável interna `__name__` no seu arquivo, criada automaticamente pelo Python, terá como valor a string `\"__main__\"`.\n\nEntão, a seção:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nvai executar.\n\n---\n\nIsso não acontecerá se você importar esse módulo (arquivo).\n\nEntão, se você tiver outro arquivo `importer.py` com:\n\n```Python\nfrom myapp import app\n\n# Mais um pouco de código\n```\n\nnesse caso, a variável `__name__` criada automaticamente dentro de `myapp.py` não terá o valor `\"__main__\"`.\n\nEntão, a linha:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nnão será executada.\n\n/// info | Informação\n\nPara mais informações, consulte [a documentação oficial do Python](https://docs.python.org/3/library/__main__.html).\n\n///\n\n## Execute seu código com seu depurador { #run-your-code-with-your-debugger }\n\nComo você está executando o servidor Uvicorn diretamente do seu código, você pode chamar seu programa Python (sua aplicação FastAPI) diretamente do depurador.\n\n---\n\nPor exemplo, no Visual Studio Code, você pode:\n\n* Ir para o painel \"Debug\".\n* \"Add configuration...\".\n* Selecionar \"Python\"\n* Executar o depurador com a opção \"`Python: Current File (Integrated Terminal)`\".\n\nEm seguida, ele iniciará o servidor com seu código **FastAPI**, parará em seus pontos de interrupção, etc.\n\nVeja como pode parecer:\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\nSe você usar o Pycharm, você pode:\n\n* Abrir o menu \"Executar\".\n* Selecionar a opção \"Depurar...\".\n* Então um menu de contexto aparece.\n* Selecionar o arquivo para depurar (neste caso, `main.py`).\n\nEm seguida, ele iniciará o servidor com seu código **FastAPI**, parará em seus pontos de interrupção, etc.\n\nVeja como pode parecer:\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/pt/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# Classes como Dependências { #classes-as-dependencies }\n\nAntes de nos aprofundarmos no sistema de **Injeção de Dependência**, vamos melhorar o exemplo anterior.\n\n## `dict` do exemplo anterior { #a-dict-from-the-previous-example }\n\nNo exemplo anterior, nós retornávamos um `dict` da nossa dependência (\"injetável\"):\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\nMas assim obtemos um `dict` como valor do parâmetro `commons` na *função de operação de rota*.\n\nE sabemos que editores de texto não têm como oferecer muitas funcionalidades (como sugestões automáticas) para objetos do tipo `dict`, por que não há como eles saberem o tipo das chaves e dos valores.\n\nPodemos fazer melhor...\n\n## O que caracteriza uma dependência { #what-makes-a-dependency }\n\nAté agora você apenas viu dependências declaradas como funções.\n\nMas essa não é a única forma de declarar dependências (mesmo que provavelmente seja a mais comum).\n\nO fator principal para uma dependência é que ela deve ser \"chamável\"\n\nUm objeto \"chamável\" em Python é qualquer coisa que o Python possa \"chamar\" como uma função\n\nEntão se você tiver um objeto `alguma_coisa` (que pode *não* ser uma função) que você possa \"chamar\" (executá-lo) dessa maneira:\n\n```Python\nsomething()\n```\n\nou\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\nEntão esse objeto é um \"chamável\".\n\n## Classes como dependências { #classes-as-dependencies_1 }\n\nVocê deve ter percebido que para criar um instância de uma classe em Python, a mesma sintaxe é utilizada.\n\nPor exemplo:\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\nNesse caso,  `fluffy` é uma instância da classe `Cat`.\n\nE para criar `fluffy`, você está \"chamando\" `Cat`.\n\nEntão, uma classe Python também é \"chamável\".\n\nEntão, no **FastAPI**, você pode utilizar uma classe Python como uma dependência.\n\nO que o FastAPI realmente verifica, é se a dependência é algo chamável (função, classe, ou outra coisa) e os parâmetros que foram definidos.\n\nSe você passar algo \"chamável\" como uma dependência do **FastAPI**, o framework irá analisar os parâmetros desse \"chamável\" e processá-los da mesma forma que os parâmetros de uma *função de operação de rota*. Incluindo as sub-dependências.\n\nIsso também se aplica a objetos chamáveis que não recebem nenhum parâmetro. Da mesma forma que uma *função de operação de rota* sem parâmetros.\n\nEntão, podemos mudar o \"injetável\" na dependência `common_parameters` acima para a classe `CommonQueryParams`:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\nObserve o método `__init__` usado para criar uma instância da classe:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n...ele possui os mesmos parâmetros que nosso `common_parameters` anterior:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\nEsses parâmetros são utilizados pelo **FastAPI** para \"definir\" a dependência.\n\nEm ambos os casos teremos:\n\n* Um parâmetro de consulta `q` opcional do tipo `str`.\n* Um parâmetro de consulta `skip` do tipo `int`, com valor padrão `0`.\n* Um parâmetro de consulta `limit` do tipo `int`, com valor padrão `100`.\n\nOs dados serão convertidos, validados, documentados no esquema da OpenAPI e etc nos dois casos.\n\n## Utilizando { #use-it }\n\nAgora você pode declarar sua dependência utilizando essa classe.\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\nO **FastAPI** chama a classe `CommonQueryParams`. Isso cria uma \"instância\" dessa classe e é a instância que será passada para o parâmetro `commons` na sua função.\n\n## Anotações de Tipo vs `Depends` { #type-annotation-vs-depends }\n\nPerceba como escrevemos `CommonQueryParams` duas vezes no código abaixo:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip | Dica\n\nUtilize a versão com `Annotated` se possível.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\nO último `CommonQueryParams`, em:\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n...é o que o **FastAPI** irá realmente usar para saber qual é a dependência.\n\nÉ a partir dele que o FastAPI irá extrair os parâmetros passados e será o que o FastAPI irá realmente chamar.\n\n---\n\nNesse caso, o primeiro `CommonQueryParams`, em:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip | Dica\n\nUtilize a versão com `Annotated` se possível.\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n...não tem nenhum signficado especial para o **FastAPI**. O FastAPI não irá utilizá-lo para conversão dos dados, validação, etc (já que ele utiliza `Depends(CommonQueryParams)` para isso).\n\nNa verdade você poderia escrever apenas:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip | Dica\n\nUtilize a versão com `Annotated` se possível.\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n...como em:\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\nMas declarar o tipo é encorajado por que é a forma que o seu editor de texto sabe o que será passado como valor do parâmetro `commons`, e assim ele pode ajudar com preenchimento automático, verificações de tipo, etc:\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## Pegando um Atalho { #shortcut }\n\nMas você pode ver que temos uma repetição do código neste exemplo, escrevendo `CommonQueryParams` duas vezes:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip | Dica\n\nUtilize a versão com `Annotated` se possível.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\nO **FastAPI** nos fornece um atalho para esses casos, onde a dependência é *especificamente* uma classe que o **FastAPI** irá \"chamar\" para criar uma instância da própria classe.\n\nPara esses casos específicos, você pode fazer o seguinte:\n\nEm vez de escrever:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip | Dica\n\nUtilize a versão com `Annotated` se possível.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n...escreva:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip | Dica\n\nUtilize a versão com `Annotated` se possível.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\nVocê declara a dependência como o tipo do parâmetro, e utiliza `Depends()` sem nenhum parâmetro, em vez de ter que escrever a classe *novamente* dentro de `Depends(CommonQueryParams)`.\n\nO mesmo exemplo ficaria então dessa forma:\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n...e o **FastAPI** saberá o que fazer.\n\n/// tip | Dica\n\nSe isso parece mais confuso do que útil, não utilize, você não *precisa* disso.\n\nÉ apenas um atalho. Por que o **FastAPI** se preocupa em ajudar a minimizar a repetição de código.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# Dependências em decoradores de operações de rota { #dependencies-in-path-operation-decorators }\n\nEm alguns casos você não precisa necessariamente do valor de retorno de uma dependência dentro de uma *função de operação de rota*.\n\nOu a dependência não retorna nenhum valor.\n\nMas você ainda precisa que ela seja executada/resolvida.\n\nPara esses casos, em vez de declarar um parâmetro em uma *função de operação de rota* com `Depends`, você pode adicionar um argumento `dependencies` do tipo `list` ao decorador da operação de rota.\n\n## Adicione `dependencies` ao *decorador da operação de rota* { #add-dependencies-to-the-path-operation-decorator }\n\nO *decorador da operação de rota* recebe um argumento opcional `dependencies`.\n\nEle deve ser uma lista de `Depends()`:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\nEssas dependências serão executadas/resolvidas da mesma forma que dependências comuns. Mas o valor delas (se existir algum) não será passado para a sua *função de operação de rota*.\n\n/// tip | Dica\n\nAlguns editores de texto checam parâmetros de funções não utilizados, e os mostram como erros.\n\nUtilizando `dependencies` no *decorador da operação de rota* você pode garantir que elas serão executadas enquanto evita erros de editores/ferramentas.\n\nIsso também pode ser útil para evitar confundir novos desenvolvedores que ao ver um parâmetro não usado no seu código podem pensar que ele é desnecessário.\n\n///\n\n/// info | Informação\n\nNeste exemplo utilizamos cabeçalhos personalizados inventados `X-Key` e `X-Token`.\n\nMas em situações reais, como implementações de segurança, você pode obter mais vantagens em usar as [Ferramentas de segurança integradas (o próximo capítulo)](../security/index.md).\n\n///\n\n## Erros das dependências e valores de retorno { #dependencies-errors-and-return-values }\n\nVocê pode utilizar as mesmas *funções* de dependências que você usaria normalmente.\n\n### Requisitos de Dependências { #dependency-requirements }\n\nDependências podem declarar requisitos de requisições (como cabeçalhos) ou outras subdependências:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### Levantar exceções { #raise-exceptions }\n\nEssas dependências podem `raise` exceções, da mesma forma que dependências comuns:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### Valores de retorno { #return-values }\n\nE elas também podem ou não retornar valores, eles não serão utilizados.\n\nEntão, você pode reutilizar uma dependência comum (que retorna um valor) que já seja utilizada em outro lugar, e mesmo que o valor não seja utilizado, a dependência será executada:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## Dependências para um grupo de *operações de rota* { #dependencies-for-a-group-of-path-operations }\n\nMais a frente, quando você ler sobre como estruturar aplicações maiores ([Aplicações maiores - Múltiplos arquivos](../../tutorial/bigger-applications.md)), possivelmente com múltiplos arquivos, você aprenderá a declarar um único parâmetro `dependencies` para um grupo de *operações de rota*.\n\n## Dependências globais { #global-dependencies }\n\nNo próximo passo veremos como adicionar dependências para uma aplicação `FastAPI` inteira, para que elas sejam aplicadas em toda *operação de rota*.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# Dependências com yield { #dependencies-with-yield }\n\nO **FastAPI** possui suporte para dependências que realizam <dfn title='às vezes também chamado de \"código de saída\", \"código de limpeza\", \"código de teardown\", \"código de fechamento\", \"código de saída do gerenciador de contexto\", etc.'>alguns passos extras ao finalizar</dfn>.\n\nPara fazer isso, utilize `yield` em vez de `return`, e escreva os passos extras (código) depois.\n\n/// tip | Dica\n\nGaranta utilizar `yield` apenas uma vez por dependência.\n\n///\n\n/// note | Detalhes Técnicos\n\nQualquer função que possa ser utilizada com:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) ou\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\npode ser utilizada como uma dependência do **FastAPI**.\n\nNa realidade, o FastAPI utiliza esses dois decoradores internamente.\n\n///\n\n## Uma dependência de banco de dados com `yield` { #a-database-dependency-with-yield }\n\nPor exemplo, você poderia utilizar isso para criar uma sessão do banco de dados, e fechá-la após terminar.\n\nApenas o código anterior à declaração com `yield` e o código contendo essa declaração são executados antes de criar uma resposta:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\nO valor gerado (yielded) é o que é injetado nas *operações de rota* e outras dependências:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\nO código após o `yield` é executado após a resposta:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip | Dica\n\nVocê pode usar funções assíncronas (`async`) ou funções comuns.\n\nO **FastAPI** saberá o que fazer com cada uma, da mesma forma que as dependências comuns.\n\n///\n\n## Uma dependência com `yield` e `try` { #a-dependency-with-yield-and-try }\n\nSe você utilizar um bloco `try` em uma dependência com `yield`, você irá capturar qualquer exceção que for lançada enquanto a dependência é utilizada.\n\nPor exemplo, se algum código em um certo momento no meio, em outra dependência ou em uma *operação de rota*, fizer um \"rollback\" de uma transação de banco de dados ou causar qualquer outra exceção, você irá capturar a exceção em sua dependência.\n\nEntão, você pode procurar por essa exceção específica dentro da dependência com `except AlgumaExcecao`.\n\nDa mesma forma, você pode utilizar `finally` para garantir que os passos de saída são executados, com ou sem exceções.\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## Subdependências com `yield` { #sub-dependencies-with-yield }\n\nVocê pode ter subdependências e \"árvores\" de subdependências de qualquer tamanho e forma, e qualquer uma ou todas elas podem utilizar `yield`.\n\nO **FastAPI** garantirá que o \"código de saída\" em cada dependência com `yield` é executado na ordem correta.\n\nPor exemplo, `dependency_c` pode depender de `dependency_b`, e `dependency_b` depender de `dependency_a`:\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\nE todas elas podem utilizar `yield`.\n\nNeste caso, `dependency_c`, para executar seu código de saída, precisa que o valor de `dependency_b` (nomeado de `dep_b` aqui) continue disponível.\n\nE, por outro lado, `dependency_b` precisa que o valor de `dependency_a` (nomeado de `dep_a`) esteja disponível para executar seu código de saída.\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\nDa mesma forma, você pode ter algumas dependências com `yield` e outras com `return` e ter uma relação de dependência entre algumas das duas.\n\nE você poderia ter uma única dependência que precisa de diversas outras dependências com `yield`, etc.\n\nVocê pode ter qualquer combinação de dependências que você quiser.\n\nO **FastAPI** se encarrega de executá-las na ordem certa.\n\n/// note | Detalhes Técnicos\n\nTudo isso funciona graças aos [gerenciadores de contexto](https://docs.python.org/3/library/contextlib.html) do Python.\n\nO **FastAPI** utiliza eles internamente para alcançar isso.\n\n///\n\n## Dependências com `yield` e `HTTPException` { #dependencies-with-yield-and-httpexception }\n\nVocê viu que pode usar dependências com `yield` e ter blocos `try` que tentam executar algum código e depois executar algum código de saída com `finally`.\n\nVocê também pode usar `except` para capturar a exceção que foi levantada e fazer algo com ela.\n\nPor exemplo, você pode levantar uma exceção diferente, como `HTTPException`.\n\n/// tip | Dica\n\nEssa é uma técnica relativamente avançada, e na maioria dos casos você não vai precisar dela, já que você pode levantar exceções (incluindo `HTTPException`) dentro do resto do código da sua aplicação, por exemplo, na *função de operação de rota*.\n\nMas ela existe para ser utilizada caso você precise. 🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\nSe você quiser capturar exceções e criar uma resposta personalizada com base nisso, crie um [Manipulador de Exceções Customizado](../handling-errors.md#install-custom-exception-handlers).\n\n## Dependências com `yield` e `except` { #dependencies-with-yield-and-except }\n\nSe você capturar uma exceção com `except` em uma dependência que utilize `yield` e ela não for levantada novamente (ou uma nova exceção for levantada), o FastAPI não será capaz de identificar que houve uma exceção, da mesma forma que aconteceria com Python puro:\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\nNeste caso, o cliente irá ver uma resposta *HTTP 500 Internal Server Error* como deveria acontecer, já que não estamos levantando nenhuma `HTTPException` ou coisa parecida, mas o servidor **não terá nenhum log** ou qualquer outra indicação de qual foi o erro. 😱\n\n### Sempre levante (`raise`) em Dependências com `yield` e `except` { #always-raise-in-dependencies-with-yield-and-except }\n\nSe você capturar uma exceção em uma dependência com `yield`, a menos que você esteja levantando outra `HTTPException` ou coisa parecida, **você deve relançar a exceção original**.\n\nVocê pode relançar a mesma exceção utilizando `raise`:\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\nAgora o cliente irá receber a mesma resposta *HTTP 500 Internal Server Error*, mas o servidor terá nosso `InternalError` personalizado nos logs. 😎\n\n## Execução de dependências com `yield` { #execution-of-dependencies-with-yield }\n\nA sequência de execução é mais ou menos como esse diagrama. O tempo passa do topo para baixo. E cada coluna é uma das partes interagindo ou executando código.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Cliente\nparticipant handler as Manipulador de exceções\nparticipant dep as Dep com yield\nparticipant operation as Operação de Rota\nparticipant tasks as Tarefas de Background\n\n    Note over client,operation: pode lançar exceções, incluindo HTTPException\n    client ->> dep: Iniciar requisição\n    Note over dep: Executar código até o yield\n    opt lançar Exceção\n        dep -->> handler: lançar Exceção\n        handler -->> client: resposta de erro HTTP\n    end\n    dep ->> operation: Executar dependência, e.g. sessão de BD\n    opt raise\n        operation -->> dep: Lançar exceção (e.g. HTTPException)\n        opt handle\n            dep -->> dep: Pode capturar exceções, lançar uma nova HTTPException, lançar outras exceções\n        end\n        handler -->> client: resposta de erro HTTP\n    end\n\n    operation ->> client: Retornar resposta ao cliente\n    Note over client,operation: Resposta já foi enviada, e não pode ser modificada\n    opt Tarefas\n        operation -->> tasks: Enviar tarefas de background\n    end\n    opt Lançar outra exceção\n        tasks -->> tasks: Manipula exceções no código da tarefa de background\n    end\n```\n\n/// info | Informação\n\nApenas **uma resposta** será enviada para o cliente. Ela pode ser uma das respostas de erro, ou então a resposta da *operação de rota*.\n\nApós uma dessas respostas ser enviada, nenhuma outra resposta pode ser enviada.\n\n///\n\n/// tip | Dica\n\nSe você levantar qualquer exceção no código da *função de operação de rota*, ela será passada para as dependências com `yield`, incluindo `HTTPException`. Na maioria dos casos, você vai querer relançar essa mesma exceção ou uma nova a partir da dependência com `yield` para garantir que ela seja tratada adequadamente.\n\n///\n\n## Saída antecipada e `scope` { #early-exit-and-scope }\n\nNormalmente, o código de saída das dependências com `yield` é executado **após a resposta** ser enviada ao cliente.\n\nMas se você sabe que não precisará usar a dependência depois de retornar da *função de operação de rota*, você pode usar `Depends(scope=\"function\")` para dizer ao FastAPI que deve fechar a dependência depois que a *função de operação de rota* retornar, mas **antes** de a **resposta ser enviada**.\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()` recebe um parâmetro `scope` que pode ser:\n\n* `\"function\"`: iniciar a dependência antes da *função de operação de rota* que trata a requisição, encerrar a dependência depois que a *função de operação de rota* termina, mas **antes** de a resposta ser enviada de volta ao cliente. Assim, a função da dependência será executada **em torno** da *função de operação de rota*.\n* `\"request\"`: iniciar a dependência antes da *função de operação de rota* que trata a requisição (semelhante a quando se usa `\"function\"`), mas encerrar **depois** que a resposta é enviada de volta ao cliente. Assim, a função da dependência será executada **em torno** do ciclo de **requisição** e resposta.\n\nSe não for especificado e a dependência tiver `yield`, ela terá `scope` igual a `\"request\"` por padrão.\n\n### `scope` para subdependências { #scope-for-sub-dependencies }\n\nQuando você declara uma dependência com `scope=\"request\"` (o padrão), qualquer subdependência também precisa ter `scope` igual a `\"request\"`.\n\nMas uma dependência com `scope` igual a `\"function\"` pode ter dependências com `scope` igual a `\"function\"` e com `scope` igual a `\"request\"`.\n\nIsso porque qualquer dependência precisa conseguir executar seu código de saída antes das subdependências, pois pode ainda precisar usá-las durante seu código de saída.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Cliente\nparticipant dep_req as Dep scope=\"request\"\nparticipant dep_func as Dep scope=\"function\"\nparticipant operation as Operação de Rota\n\n    client ->> dep_req: Iniciar requisição\n    Note over dep_req: Executar código até o yield\n    dep_req ->> dep_func: Passar dependência\n    Note over dep_func: Executar código até o yield\n    dep_func ->> operation: Executar operação de rota com dependência\n    operation ->> dep_func: Retornar da operação de rota\n    Note over dep_func: Executar código após o yield\n    Note over dep_func: ✅ Dependência fechada\n    dep_func ->> client: Enviar resposta ao cliente\n    Note over client: Resposta enviada\n    Note over dep_req: Executar código após o yield\n    Note over dep_req: ✅ Dependência fechada\n```\n\n## Dependências com `yield`, `HTTPException`, `except` e Tarefas de Background { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\nDependências com `yield` evoluíram ao longo do tempo para cobrir diferentes casos de uso e corrigir alguns problemas.\n\nSe você quiser ver o que mudou em diferentes versões do FastAPI, você pode ler mais sobre isso no guia avançado, em [Dependências Avançadas - Dependências com `yield`, `HTTPException`, `except` e Tarefas de Background](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).\n## Gerenciadores de contexto { #context-managers }\n\n### O que são \"Gerenciadores de Contexto\" { #what-are-context-managers }\n\n\"Gerenciadores de Contexto\" são qualquer um dos objetos Python que podem ser utilizados com a declaração `with`.\n\nPor exemplo, [você pode utilizar `with` para ler um arquivo](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files):\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\nPor baixo dos panos, o código `open(\"./somefile.txt\")` cria um objeto que é chamado de \"Gerenciador de Contexto\".\n\nQuando o bloco `with` finaliza, ele se certifica de fechar o arquivo, mesmo que tenha ocorrido alguma exceção.\n\nQuando você cria uma dependência com `yield`, o **FastAPI** irá criar um gerenciador de contexto internamente para ela, e combiná-lo com algumas outras ferramentas relacionadas.\n\n### Utilizando gerenciadores de contexto em dependências com `yield` { #using-context-managers-in-dependencies-with-yield }\n\n/// warning | Atenção\n\nIsso é uma ideia mais ou menos \"avançada\".\n\nSe você está apenas iniciando com o **FastAPI** você pode querer pular isso por enquanto.\n\n///\n\nEm Python, você pode criar Gerenciadores de Contexto ao [criar uma classe com dois métodos: `__enter__()` e `__exit__()`](https://docs.python.org/3/reference/datamodel.html#context-managers).\n\nVocê também pode usá-los dentro de dependências com `yield` do **FastAPI** ao utilizar\n`with` ou `async with` dentro da função da dependência:\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip | Dica\n\nOutra forma de criar um gerenciador de contexto é utilizando:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) ou\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nPara decorar uma função com um único `yield`.\n\nIsso é o que o **FastAPI** usa internamente para dependências com `yield`.\n\nMas você não precisa usar esses decoradores para as dependências do FastAPI (e você não deveria).\n\nO FastAPI irá fazer isso para você internamente.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# Dependências Globais { #global-dependencies }\n\nPara alguns tipos de aplicação você pode querer adicionar dependências para toda a aplicação.\n\nDe forma semelhante a [adicionar `dependencies` aos *decoradores de operação de rota*](dependencies-in-path-operation-decorators.md), você pode adicioná-las à aplicação `FastAPI`.\n\nNesse caso, elas serão aplicadas a todas as *operações de rota* da aplicação:\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\n\nE todos os conceitos apresentados na seção sobre [adicionar `dependencies` aos *decoradores de operação de rota*](dependencies-in-path-operation-decorators.md) ainda se aplicam, mas nesse caso, para todas as *operações de rota* da aplicação.\n\n## Dependências para conjuntos de *operações de rota* { #dependencies-for-groups-of-path-operations }\n\nMais para a frente, quando você ler sobre como estruturar aplicações maiores ([Aplicações Maiores - Múltiplos Arquivos](../../tutorial/bigger-applications.md)), possivelmente com múltiplos arquivos, você irá aprender a declarar um único parâmetro `dependencies` para um conjunto de *operações de rota*.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/dependencies/index.md",
    "content": "# Dependências { #dependencies }\n\nO **FastAPI** possui um poderoso, mas intuitivo sistema de **<dfn title=\"também conhecida como componentes, recursos, provedores, serviços, injetáveis\">Injeção de Dependência</dfn>**.\n\nEsse sistema foi pensado para ser fácil de usar, e permitir que qualquer desenvolvedor possa integrar facilmente outros componentes ao **FastAPI**.\n\n## O que é \"Injeção de Dependência\" { #what-is-dependency-injection }\n\n**\"Injeção de Dependência\"** no mundo da programação significa, que existe uma maneira de declarar no seu código (nesse caso, suas *funções de operação de rota*) para declarar as coisas que ele precisa para funcionar e que serão utilizadas: \"dependências\".\n\nEntão, esse sistema (nesse caso o **FastAPI**) se encarrega de fazer o que for preciso para fornecer essas dependências para o código (\"injetando\" as dependências).\n\nIsso é bastante útil quando você precisa:\n\n* Definir uma lógica compartilhada (mesmo formato de código repetidamente).\n* Compartilhar conexões com banco de dados.\n* Aplicar regras de segurança, autenticação, papéis de usuários, etc.\n* E muitas outras coisas...\n\nTudo isso, enquanto minimizamos a repetição de código.\n\n## Primeiros passos { #first-steps }\n\nVamos ver um exemplo simples. Tão simples que não será muito útil, por enquanto.\n\nMas dessa forma podemos focar em como o sistema de **Injeção de Dependência** funciona.\n\n### Criando uma dependência, ou \"dependable\" { #create-a-dependency-or-dependable }\n\nPrimeiro vamos focar na dependência.\n\nEla é apenas uma função que pode receber os mesmos parâmetros de uma *função de operação de rota*:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\nE pronto.\n\n**2 linhas**.\n\nE com a mesma forma e estrutura de todas as suas *funções de operação de rota*.\n\nVocê pode pensar nela como uma *função de operação de rota* sem o \"decorador\" (sem a linha `@app.get(\"/some-path\")`).\n\nE com qualquer retorno que você desejar.\n\nNeste caso, a dependência espera por:\n\n* Um parâmetro de consulta opcional `q` do tipo `str`.\n* Um parâmetro de consulta opcional `skip` do tipo `int`, e igual a `0` por padrão.\n* Um parâmetro de consulta opcional `limit` do tipo `int`, e igual a `100` por padrão.\n\nE então retorna um `dict` contendo esses valores.\n\n/// info | Informação\n\nFastAPI passou a suportar a notação `Annotated` (e começou a recomendá-la) na versão 0.95.0.\n\nSe você utiliza uma versão anterior, ocorrerão erros ao tentar utilizar `Annotated`.\n\nCertifique-se de [Atualizar a versão do FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions) para pelo menos 0.95.1 antes de usar `Annotated`.\n\n///\n\n### Importando `Depends` { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### Declarando a dependência, no \"dependente\" { #declare-the-dependency-in-the-dependant }\n\nDa mesma forma que você utiliza `Body`, `Query`, etc. Como parâmetros de sua *função de operação de rota*, utilize `Depends` com um novo parâmetro:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\nAinda que `Depends` seja utilizado nos parâmetros da função da mesma forma que `Body`, `Query`, etc, `Depends` funciona de uma forma um pouco diferente.\n\nVocê fornece um único parâmetro para `Depends`.\n\nEsse parâmetro deve ser algo como uma função.\n\nVocê **não chama a função** diretamente (não adicione os parênteses no final), apenas a passe como parâmetro de `Depends()`.\n\nE essa função vai receber os parâmetros da mesma forma que uma *função de operação de rota*.\n\n/// tip | Dica\n\nVocê verá quais outras \"coisas\", além de funções, podem ser usadas como dependências no próximo capítulo.\n\n///\n\nSempre que uma nova requisição for realizada, o **FastAPI** se encarrega de:\n\n* Chamar sua dependência (\"dependable\") com os parâmetros corretos.\n* Obter o resultado da função.\n* Atribuir esse resultado para o parâmetro em sua *função de operação de rota*.\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\nAssim, você escreve um código compartilhado apenas uma vez e o **FastAPI** se encarrega de chamá-lo em suas *operações de rota*.\n\n/// check | Verifique\n\nPerceba que você não precisa criar uma classe especial e enviar a dependência para algum outro lugar em que o **FastAPI** a \"registre\" ou realize qualquer operação similar.\n\nVocê apenas envia para `Depends` e o **FastAPI** sabe como fazer o resto.\n\n///\n\n## Compartilhando dependências `Annotated` { #share-annotated-dependencies }\n\nNos exemplos acima, você pode ver que existe uma pequena **duplicação de código**.\n\nQuando você precisa utilizar a dependência `common_parameters()`, você precisa escrever o parâmetro inteiro com uma anotação de tipo e `Depends()`:\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\nMas como estamos utilizando `Annotated`, podemos guardar esse valor `Annotated` em uma variável e utilizá-la em múltiplos locais:\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | Dica\n\nIsso é apenas Python padrão, essa funcionalidade é chamada de \"type alias\", e na verdade não é específica ao **FastAPI**.\n\nMas como o **FastAPI** se baseia em convenções do Python, incluindo `Annotated`, você pode incluir esse truque no seu código. 😎\n\n///\n\nAs dependências continuarão funcionando como esperado, e a **melhor parte** é que a **informação sobre o tipo é preservada**, o que signfica que seu editor de texto ainda irá incluir **preenchimento automático**, **visualização de erros**, etc. O mesmo vale para ferramentas como `mypy`.\n\nIsso é especialmente útil para uma **base de código grande** onde **as mesmas dependências** são utilizadas repetidamente em **muitas *operações de rota***.\n\n## `Async` ou não, eis a questão { #to-async-or-not-to-async }\n\nComo as dependências também serão chamadas pelo **FastAPI** (da mesma forma que *funções de operação de rota*), as mesmas regras se aplicam ao definir suas funções.\n\nVocê pode utilizar `async def` ou apenas `def`.\n\nE você pode declarar dependências utilizando `async def` dentro de *funções de operação de rota* definidas com `def`, ou declarar dependências com `def` e utilizar dentro de *funções de operação de rota* definidas com `async def`, etc.\n\nNão faz diferença. O **FastAPI** sabe o que fazer.\n\n/// note | Nota\n\nCaso você não conheça, veja em [Async: *\"Com Pressa?\"*](../../async.md#in-a-hurry) a sessão acerca de `async` e `await` na documentação.\n\n///\n\n## Integrando com OpenAPI { #integrated-with-openapi }\n\nTodas as declarações de requisições, validações e requisitos para suas dependências (e sub-dependências) serão integradas em um mesmo esquema OpenAPI.\n\nEntão, a documentação interativa também terá toda a informação sobre essas dependências:\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## Caso de Uso Simples { #simple-usage }\n\nSe você parar para ver, *funções de operação de rota* são declaradas para serem usadas sempre que uma *rota* e uma *operação* se encaixam, e então o **FastAPI** se encarrega de chamar a função correspondente com os argumentos corretos, extraindo os dados da requisição.\n\nNa verdade, todos (ou a maioria) dos frameworks web funcionam da mesma forma.\n\nVocê nunca chama essas funções diretamente. Elas são chamadas pelo framework utilizado (nesse caso, **FastAPI**).\n\nCom o Sistema de Injeção de Dependência, você também pode informar ao **FastAPI** que sua *função de operação de rota* também \"depende\" em algo a mais que deve ser executado antes de sua *função de operação de rota*, e o **FastAPI** se encarrega de executar e \"injetar\" os resultados.\n\nOutros termos comuns para essa mesma ideia de \"injeção de dependência\" são:\n\n* recursos\n* provedores\n* serviços\n* injetáveis\n* componentes\n\n## Plug-ins em **FastAPI** { #fastapi-plug-ins }\n\nIntegrações e \"plug-ins\" podem ser construídos com o sistema de **Injeção de Dependência**. Mas na verdade, **não há necessidade de criar \"plug-ins\"**, já que utilizando dependências é possível declarar um número infinito de integrações e interações que se tornam disponíveis para as suas *funções de operação de rota*.\n\nE as dependências podem ser criadas de uma forma bastante simples e intuitiva que permite que você importe apenas os pacotes Python que forem necessários, e integrá-los com as funções de sua API em algumas linhas de código, *literalmente*.\n\nVocê verá exemplos disso nos próximos capítulos, acerca de bancos de dados relacionais e NoSQL, segurança, etc.\n\n## Compatibilidade do **FastAPI** { #fastapi-compatibility }\n\nA simplicidade do sistema de injeção de dependência do **FastAPI** faz ele compatível com:\n\n* todos os bancos de dados relacionais\n* bancos de dados NoSQL\n* pacotes externos\n* APIs externas\n* sistemas de autenticação e autorização\n* sistemas de monitoramento de uso para APIs\n* sistemas de injeção de dados de resposta\n* etc.\n\n## Simples e Poderoso { #simple-and-powerful }\n\nMesmo que o sistema hierárquico de injeção de dependência seja simples de definir e utilizar, ele ainda é bastante poderoso.\n\nVocê pode definir dependências que por sua vez definem suas próprias dependências.\n\nPor fim, uma árvore hierárquica de dependências é criada, e o sistema de **Injeção de Dependência** toma conta de resolver todas essas dependências (e as sub-dependências delas) para você, e provê (injeta) os resultados em cada passo.\n\nPor exemplo, vamos supor que você possua 4 endpoints na sua API (*operações de rota*):\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\nVocê poderia adicionar diferentes requisitos de permissão para cada um deles utilizando apenas dependências e sub-dependências:\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## Integração com **OpenAPI** { #integrated-with-openapi_1 }\n\nTodas essas dependências, ao declarar os requisitos para suas *operações de rota*, também adicionam parâmetros, validações, etc.\n\nO **FastAPI** se encarrega de adicionar tudo isso ao esquema OpenAPI, para que seja mostrado nos sistemas de documentação interativa.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# Subdependências { #sub-dependencies }\n\nVocê pode criar dependências que possuem **subdependências**.\n\nElas podem ter o nível de **profundidade** que você achar necessário.\n\nO **FastAPI** se encarrega de resolver essas dependências.\n\n## Primeira dependência \"dependable\" { #first-dependency-dependable }\n\nVocê pode criar uma primeira dependência (\"dependable\") dessa forma:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\nEsse código declara um parâmetro de consulta opcional, `q`, com o tipo `str`, e então retorna esse parâmetro.\n\nIsso é bastante simples (e não muito útil), mas irá nos ajudar a focar em como as subdependências funcionam.\n\n## Segunda dependência, \"dependable\" e \"dependente\" { #second-dependency-dependable-and-dependant }\n\nEntão, você pode criar uma outra função para uma dependência (um \"dependable\") que ao mesmo tempo declara sua própria dependência (o que faz dela um \"dependente\" também):\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\nVamos focar nos parâmetros declarados:\n\n* Mesmo que essa função seja uma dependência (\"dependable\") por si mesma, ela também declara uma outra dependência (ela \"depende\" de outra coisa).\n    * Ela depende do `query_extractor`, e atribui o valor retornado pela função ao parâmetro `q`.\n* Ela também declara um cookie opcional `last_query`, do tipo `str`.\n    * Se o usuário não passou nenhuma consulta `q`, a última consulta é utilizada, que foi salva em um cookie anteriormente.\n\n## Utilizando a dependência { #use-the-dependency }\n\nEntão podemos utilizar a dependência com:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info | Informação\n\nPerceba que nós estamos declarando apenas uma dependência na *função de operação de rota*, em `query_or_cookie_extractor`.\n\nMas o **FastAPI** saberá que precisa solucionar `query_extractor` primeiro, para passar o resultado para `query_or_cookie_extractor` enquanto chama a função.\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## Utilizando a mesma dependência múltiplas vezes { #using-the-same-dependency-multiple-times }\n\nSe uma de suas dependências é declarada várias vezes para a mesma *operação de rota*, por exemplo, múltiplas dependências com uma mesma subdependência, o **FastAPI** irá chamar essa subdependência uma única vez para cada requisição.\n\nE o valor retornado é salvo em um <dfn title=\"Um utilitário/sistema para armazenar valores calculados/gerados para serem reutilizados em vez de computá-los novamente.\">\"cache\"</dfn> e repassado para todos os \"dependentes\" que precisam dele em uma requisição específica, em vez de chamar a dependência múltiplas vezes para uma mesma requisição.\n\nEm um cenário avançado onde você precise que a dependência seja calculada em cada passo (possivelmente várias vezes) de uma requisição em vez de utilizar o valor em \"cache\", você pode definir o parâmetro `use_cache=False` em `Depends`:\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ non-Annotated\n\n/// tip | Dica\n\nUtilize a versão com `Annotated` se possível.\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## Recapitulando { #recap }\n\nCom exceção de todas as palavras complicadas usadas aqui, o sistema de **Injeção de Dependência** é bastante simples.\n\nConsiste apenas de funções que parecem idênticas a *funções de operação de rota*.\n\nMas ainda assim, é bastante poderoso, e permite que você declare grafos (árvores) de dependências com uma profundidade arbitrária.\n\n/// tip | Dica\n\nTudo isso pode não parecer muito útil com esses exemplos.\n\nMas você verá o quão útil isso é nos capítulos sobre **segurança**.\n\nE você também verá a quantidade de código que você não precisara escrever.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/tutorial/encoder.md",
    "content": "# Codificador Compatível com JSON { #json-compatible-encoder }\n\nExistem alguns casos em que você pode precisar converter um tipo de dados (como um modelo Pydantic) para algo compatível com JSON (como um `dict`, `list`, etc).\n\nPor exemplo, se você precisar armazená-lo em um banco de dados.\n\nPara isso, **FastAPI** fornece uma função `jsonable_encoder()`.\n\n## Usando a função `jsonable_encoder` { #using-the-jsonable-encoder }\n\nVamos imaginar que você tenha um banco de dados `fake_db` que recebe apenas dados compatíveis com JSON.\n\nPor exemplo, ele não recebe objetos `datetime`, pois estes objetos não são compatíveis com JSON.\n\nEntão, um objeto `datetime` teria que ser convertido em um `str` contendo os dados no [formato ISO](https://en.wikipedia.org/wiki/ISO_8601).\n\nDa mesma forma, este banco de dados não receberia um modelo Pydantic (um objeto com atributos), apenas um `dict`.\n\nVocê pode usar a função `jsonable_encoder` para resolver isso.\n\nA função recebe um objeto, como um modelo Pydantic e retorna uma versão compatível com JSON:\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\nNeste exemplo, ele converteria o modelo Pydantic em um `dict`, e o `datetime` em um `str`.\n\nO resultado de chamar a função é algo que pode ser codificado com o padrão do Python [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps).\n\nA função não retorna um grande `str` contendo os dados no formato JSON (como uma string). Mas sim, retorna uma estrutura de dados padrão do Python (por exemplo, um `dict`) com valores e subvalores compatíveis com JSON.\n\n/// note | Nota\n\n`jsonable_encoder` é realmente usado pelo **FastAPI** internamente para converter dados. Mas também é útil em muitos outros cenários.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/tutorial/extra-data-types.md",
    "content": "# Tipos de dados extras { #extra-data-types }\n\nAté agora, você tem usado tipos de dados comuns, tais como:\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\nMas você também pode usar tipos de dados mais complexos.\n\nE você ainda terá os mesmos recursos que viu até agora:\n\n* Ótimo suporte do editor.\n* Conversão de dados das requisições recebidas.\n* Conversão de dados para os dados da resposta.\n* Validação de dados.\n* Anotação e documentação automáticas.\n\n## Outros tipos de dados { #other-data-types }\n\nAqui estão alguns dos tipos de dados adicionais que você pode usar:\n\n* `UUID`:\n    * Um \"Identificador Universalmente Único\" padrão, comumente usado como ID em muitos bancos de dados e sistemas.\n    * Em requisições e respostas será representado como uma `str`.\n* `datetime.datetime`:\n    * O `datetime.datetime` do Python.\n    * Em requisições e respostas será representado como uma `str` no formato ISO 8601, exemplo: `2008-09-15T15:53:00+05:00`.\n* `datetime.date`:\n    * O `datetime.date` do Python.\n    * Em requisições e respostas será representado como uma `str` no formato ISO 8601, exemplo: `2008-09-15`.\n* `datetime.time`:\n    * O `datetime.time` do Python.\n    * Em requisições e respostas será representado como uma `str` no formato ISO 8601, exemplo: `14:23:55.003`.\n* `datetime.timedelta`:\n    * O `datetime.timedelta` do Python.\n    * Em requisições e respostas será representado como um `float` de segundos totais.\n    * O Pydantic também permite representá-lo como uma \"codificação ISO 8601 diferença de tempo\", [cheque a documentação para mais informações](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).\n* `frozenset`:\n    * Em requisições e respostas, será tratado da mesma forma que um `set`:\n        * Nas requisições, uma lista será lida, eliminando duplicadas e convertendo-a em um `set`.\n        * Nas respostas, o `set` será convertido para uma `list`.\n        * O esquema gerado vai especificar que os valores do `set` são únicos (usando o `uniqueItems` do JSON Schema).\n* `bytes`:\n    * O `bytes` padrão do Python.\n    * Em requisições e respostas será representado como uma `str`.\n    * O esquema gerado vai especificar que é uma `str` com o \"formato\" `binary`.\n* `Decimal`:\n    * O `Decimal` padrão do Python.\n    * Em requisições e respostas será representado como um `float`.\n* Você pode checar todos os tipos de dados válidos do Pydantic aqui: [Tipos de dados do Pydantic](https://docs.pydantic.dev/latest/usage/types/types/).\n\n## Exemplo { #example }\n\nAqui está um exemplo de *operação de rota* com parâmetros utilizando-se de alguns dos tipos acima.\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\nNote que os parâmetros dentro da função têm seu tipo de dados natural, e você pode, por exemplo, realizar manipulações normais de data, como:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/pt/docs/tutorial/extra-models.md",
    "content": "# Modelos Adicionais { #extra-models }\n\nContinuando com o exemplo anterior, será comum ter mais de um modelo relacionado.\n\nIsso é especialmente o caso para modelos de usuários, porque:\n\n* O **modelo de entrada** precisa ser capaz de ter uma senha.\n* O **modelo de saída** não deve ter uma senha.\n* O **modelo de banco de dados** provavelmente precisaria ter uma senha com hash.\n\n/// danger | Cuidado\n\nNunca armazene senhas em texto simples dos usuários. Sempre armazene uma \"hash segura\" que você pode verificar depois.\n\nSe não souber, você aprenderá o que é uma \"senha hash\" nos [capítulos de segurança](security/simple-oauth2.md#password-hashing).\n\n///\n\n## Múltiplos modelos { #multiple-models }\n\nAqui está uma ideia geral de como os modelos poderiam parecer com seus campos de senha e os lugares onde são usados:\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### Sobre `**user_in.model_dump()` { #about-user-in-model-dump }\n\n#### O `.model_dump()` do Pydantic { #pydantics-model-dump }\n\n`user_in` é um modelo Pydantic da classe `UserIn`.\n\nOs modelos Pydantic possuem um método `.model_dump()` que retorna um `dict` com os dados do modelo.\n\nEntão, se criarmos um objeto Pydantic `user_in` como:\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\ne depois chamarmos:\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\nagora temos um `dict` com os dados na variável `user_dict` (é um `dict` em vez de um objeto de modelo Pydantic).\n\nE se chamarmos:\n\n```Python\nprint(user_dict)\n```\n\nteríamos um `dict` Python com:\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### Desembrulhando um `dict` { #unpacking-a-dict }\n\nSe tomarmos um `dict` como `user_dict` e passarmos para uma função (ou classe) com `**user_dict`, o Python irá \"desembrulhá-lo\". Ele passará as chaves e valores do `user_dict` diretamente como argumentos chave-valor.\n\nEntão, continuando com o `user_dict` acima, escrevendo:\n\n```Python\nUserInDB(**user_dict)\n```\n\nResultaria em algo equivalente a:\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\nOu mais exatamente, usando `user_dict` diretamente, com qualquer conteúdo que ele possa ter no futuro:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### Um modelo Pydantic a partir do conteúdo de outro { #a-pydantic-model-from-the-contents-of-another }\n\nComo no exemplo acima, obtivemos o `user_dict` a partir do `user_in.model_dump()`, este código:\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\nseria equivalente a:\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n...porque `user_in.model_dump()` é um `dict`, e depois fazemos o Python \"desembrulhá-lo\" passando-o para `UserInDB` precedido por `**`.\n\nEntão, obtemos um modelo Pydantic a partir dos dados em outro modelo Pydantic.\n\n#### Desembrulhando um `dict` e palavras-chave extras { #unpacking-a-dict-and-extra-keywords }\n\nE, então, adicionando o argumento de palavra-chave extra `hashed_password=hashed_password`, como em:\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n...acaba sendo como:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning | Atenção\n\nAs funções adicionais de suporte `fake_password_hasher` e `fake_save_user` servem apenas para demonstrar um fluxo possível dos dados, mas é claro que elas não fornecem segurança real.\n\n///\n\n## Reduzir duplicação { #reduce-duplication }\n\nReduzir a duplicação de código é uma das ideias principais no **FastAPI**.\n\nA duplicação de código aumenta as chances de bugs, problemas de segurança, problemas de desincronização de código (quando você atualiza em um lugar, mas não em outros), etc.\n\nE esses modelos estão compartilhando muitos dos dados e duplicando nomes e tipos de atributos.\n\nNós poderíamos fazer melhor.\n\nPodemos declarar um modelo `UserBase` que serve como base para nossos outros modelos. E então podemos fazer subclasses desse modelo que herdam seus atributos (declarações de tipo, validação, etc.).\n\nToda conversão de dados, validação, documentação, etc. ainda funcionará normalmente.\n\nDessa forma, podemos declarar apenas as diferenças entre os modelos (com `password` em texto claro, com `hashed_password` e sem senha):\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` ou `anyOf` { #union-or-anyof }\n\nVocê pode declarar uma resposta como o `Union` de dois ou mais tipos, o que significa que a resposta seria qualquer um deles.\n\nIsso será definido no OpenAPI com `anyOf`.\n\nPara fazer isso, use a anotação de tipo padrão do Python [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union):\n\n/// note | Nota\n\nAo definir um [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions), 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]`.\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### `Union` no Python 3.10 { #union-in-python-3-10 }\n\nNeste exemplo, passamos `Union[PlaneItem, CarItem]` como o valor do argumento `response_model`.\n\nDado que estamos passando-o como um **valor para um argumento** em vez de colocá-lo em uma **anotação de tipo**, precisamos usar `Union` mesmo no Python 3.10.\n\nSe estivesse em uma anotação de tipo, poderíamos ter usado a barra vertical, como:\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\nMas se colocarmos isso na atribuição `response_model=PlaneItem | CarItem`, teríamos um erro, pois o Python tentaria executar uma **operação inválida** entre `PlaneItem` e `CarItem` em vez de interpretar isso como uma anotação de tipo.\n\n## Lista de modelos { #list-of-models }\n\nDa mesma forma, você pode declarar respostas de listas de objetos.\n\nPara isso, use o padrão Python `list`:\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## Resposta com `dict` arbitrário { #response-with-arbitrary-dict }\n\nVocê também pode declarar uma resposta usando um simples `dict` arbitrário, declarando apenas o tipo das chaves e valores, sem usar um modelo Pydantic.\n\nIsso é útil se você não souber os nomes de campo / atributo válidos (que seriam necessários para um modelo Pydantic) antecipadamente.\n\nNeste caso, você pode usar `dict`:\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## Recapitulação { #recap }\n\nUse vários modelos Pydantic e herde livremente para cada caso.\n\nNão é necessário ter um único modelo de dados por entidade se essa entidade precisar ter diferentes \"estados\". No caso da \"entidade\" de usuário com um estado que inclui `password`, `password_hash` e sem senha.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/first-steps.md",
    "content": "# Primeiros Passos { #first-steps }\n\nO arquivo FastAPI mais simples pode se parecer com:\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\nCopie o conteúdo para um arquivo `main.py`.\n\nExecute o servidor ao vivo:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nNa saída, há uma linha com algo como:\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\nEssa linha mostra a URL onde a sua aplicação está sendo servida, na sua máquina local.\n\n### Confira { #check-it }\n\nAbra o seu navegador em [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nVocê verá essa resposta em JSON:\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### Documentação Interativa de APIs { #interactive-api-docs }\n\nAgora vá para [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVocê verá a documentação interativa automática da API (fornecida por [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Documentação Alternativa de APIs { #alternative-api-docs }\n\nE agora, vá para [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nVocê verá a documentação alternativa automática (fornecida por [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\nO **FastAPI** gera um \"*schema*\" com toda a sua API usando o padrão **OpenAPI** para definir APIs.\n\n#### \"*Schema*\" { #schema }\n\nUm \"*schema*\" é uma definição ou descrição de algo. Não o código que o implementa, mas apenas uma descrição abstrata.\n\n#### API \"*schema*\" { #api-schema }\n\nNesse caso, [OpenAPI](https://github.com/OAI/OpenAPI-Specification) é uma especificação que determina como definir um *schema* da sua API.\n\nEsta definição de *schema* inclui os paths da sua API, os parâmetros possíveis que eles usam, etc.\n\n#### \"*Schema*\" de dados { #data-schema }\n\nO termo \"*schema*\" também pode se referir à forma de alguns dados, como um conteúdo JSON.\n\nNesse caso, significaria os atributos JSON e os tipos de dados que eles possuem, etc.\n\n#### OpenAPI e JSON Schema { #openapi-and-json-schema }\n\nOpenAPI define um *schema* de API para sua API. E esse *schema* inclui definições (ou \"*schemas*\") dos dados enviados e recebidos por sua API usando **JSON Schema**, o padrão para *schemas* de dados JSON.\n\n#### Verifique o `openapi.json` { #check-the-openapi-json }\n\nSe você está curioso(a) sobre a aparência do *schema* bruto OpenAPI, o FastAPI gera automaticamente um JSON (*schema*) com as descrições de toda a sua API.\n\nVocê pode ver isso diretamente em: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).\n\nEle mostrará um JSON começando com algo como:\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### Para que serve o OpenAPI { #what-is-openapi-for }\n\nO *schema* OpenAPI é o que possibilita os dois sistemas de documentação interativos mostrados.\n\nE existem dezenas de alternativas, todas baseadas em OpenAPI. Você pode facilmente adicionar qualquer uma dessas alternativas à sua aplicação criada com **FastAPI**.\n\nVocê também pode usá-lo para gerar código automaticamente para clientes que se comunicam com sua API. Por exemplo, aplicativos front-end, móveis ou IoT.\n\n### Configure o `entrypoint` da aplicação em `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nVocê pode configurar onde sua aplicação está localizada em um arquivo `pyproject.toml`, assim:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nEsse `entrypoint` dirá ao comando `fastapi` que ele deve importar a aplicação assim:\n\n```python\nfrom main import app\n```\n\nSe o seu código estiver estruturado assim:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nEntão você definiria o `entrypoint` como:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\no que seria equivalente a:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` com path { #fastapi-dev-with-path }\n\nVocê também pode passar o path do arquivo para o comando `fastapi dev`, e ele vai deduzir o objeto de aplicação FastAPI a ser usado:\n\n```console\n$ fastapi dev main.py\n```\n\nMas você teria que lembrar de passar o path correto toda vez que chamar o comando `fastapi`.\n\nAlém disso, outras ferramentas podem não conseguir encontrá-la, por exemplo, a [Extensão do VS Code](../editor-support.md) ou a [FastAPI Cloud](https://fastapicloud.com), então é recomendado usar o `entrypoint` no `pyproject.toml`.\n\n### Faça o deploy da sua aplicação (opcional) { #deploy-your-app-optional }\n\nVocê pode, opcionalmente, fazer o deploy da sua aplicação FastAPI na [FastAPI Cloud](https://fastapicloud.com); acesse e entre na lista de espera, se ainda não entrou. 🚀\n\nSe você já tem uma conta na **FastAPI Cloud** (nós convidamos você da lista de espera 😉), pode fazer o deploy da sua aplicação com um único comando.\n\nAntes do deploy, certifique-se de que está autenticado:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\nEm seguida, faça o deploy da sua aplicação:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nÉ isso! Agora você pode acessar sua aplicação nessa URL. ✨\n\n## Recapitulando, passo a passo { #recap-step-by-step }\n\n### Passo 1: importe `FastAPI` { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI` é uma classe Python que fornece todas as funcionalidades para sua API.\n\n/// note | Detalhes Técnicos\n\n`FastAPI` é uma classe que herda diretamente de `Starlette`.\n\nVocê pode usar todas as funcionalidades do [Starlette](https://www.starlette.dev/) com `FastAPI` também.\n\n///\n\n### Passo 2: crie uma \"instância\" de `FastAPI` { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\nAqui, a variável `app` será uma \"instância\" da classe `FastAPI`.\n\nEste será o principal ponto de interação para criar toda a sua API.\n\n### Passo 3: crie uma operação de rota { #step-3-create-a-path-operation }\n\n#### Path { #path }\n\n\"Path\" aqui se refere à última parte da URL, começando do primeiro `/`.\n\nEntão, em uma URL como:\n\n```\nhttps://example.com/items/foo\n```\n\n...o path seria:\n\n```\n/items/foo\n```\n\n/// info | Informação\n\nUm \"path\" também é comumente chamado de \"endpoint\" ou de \"rota\".\n\n///\n\nAo construir uma API, o \"path\" é a principal forma de separar \"preocupações\" e \"recursos\".\n\n#### Operação { #operation }\n\n\"Operação\" aqui se refere a um dos \"métodos\" HTTP.\n\nUm dos:\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n...e os mais exóticos:\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\nNo protocolo HTTP, você pode se comunicar com cada path usando um (ou mais) desses \"métodos\".\n\n---\n\nAo construir APIs, você normalmente usa esses métodos HTTP para executar uma ação específica.\n\nNormalmente você usa:\n\n* `POST`: para criar dados.\n* `GET`: para ler dados.\n* `PUT`: para atualizar dados.\n* `DELETE`: para deletar dados.\n\nPortanto, no OpenAPI, cada um dos métodos HTTP é chamado de \"operação\".\n\nVamos chamá-los de \"**operações**\" também.\n\n#### Defina um decorador de operação de rota { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\nO `@app.get(\"/\")` diz ao **FastAPI** que a função logo abaixo é responsável por tratar as requisições que vão para:\n\n* o path `/`\n* usando uma <dfn title=\"um método HTTP GET\"><code>get</code> operação</dfn>\n\n/// info | Informações sobre `@decorator`\n\nEssa sintaxe `@alguma_coisa` em Python é chamada de \"decorador\".\n\nVocê o coloca em cima de uma função. Como um chapéu decorativo (acho que é daí que vem o termo).\n\nUm \"decorador\" pega a função abaixo e faz algo com ela.\n\nEm nosso caso, este decorador informa ao **FastAPI** que a função abaixo corresponde ao **path** `/` com uma **operação** `get`.\n\nÉ o \"**decorador de operação de rota**\".\n\n///\n\nVocê também pode usar as outras operações:\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\nE os mais exóticos:\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip | Dica\n\nVocê está livre para usar cada operação (método HTTP) como desejar.\n\nO **FastAPI** não impõe nenhum significado específico.\n\nAs informações aqui são apresentadas como uma orientação, não uma exigência.\n\nPor exemplo, ao usar GraphQL, você normalmente executa todas as ações usando apenas operações `POST`.\n\n///\n\n### Passo 4: defina a **função de operação de rota** { #step-4-define-the-path-operation-function }\n\nEsta é a nossa \"**função de operação de rota**\":\n\n* **path**: é `/`.\n* **operação**: é `get`.\n* **função**: é a função abaixo do \"decorador\" (abaixo do `@app.get(\"/\")`).\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\nEsta é uma função Python.\n\nEla será chamada pelo **FastAPI** sempre que receber uma requisição para a URL \"`/`\" usando uma operação `GET`.\n\nNeste caso, é uma função `async`.\n\n---\n\nVocê também pode defini-la como uma função normal em vez de `async def`:\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note | Nota\n\nSe você não sabe a diferença, verifique o [Async: *\"Com pressa?\"*](../async.md#in-a-hurry).\n\n///\n\n### Passo 5: retorne o conteúdo { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\nVocê pode retornar um `dict`, `list` e valores singulares como `str`, `int`, etc.\n\nVocê também pode devolver modelos Pydantic ( você verá mais sobre isso mais tarde).\n\nExistem muitos outros objetos e modelos que serão convertidos automaticamente para JSON (incluindo ORMs, etc). Tente usar seus favoritos, é altamente provável que já sejam compatíveis.\n\n### Passo 6: Faça o deploy { #step-6-deploy-it }\n\nFaça o deploy da sua aplicação para a **[FastAPI Cloud](https://fastapicloud.com)** com um comando: `fastapi deploy`. 🎉\n\n#### Sobre o FastAPI Cloud { #about-fastapi-cloud }\n\nA **[FastAPI Cloud](https://fastapicloud.com)** é construída pelo mesmo autor e equipe por trás do **FastAPI**.\n\nEla simplifica o processo de **construir**, **fazer deploy** e **acessar** uma API com o mínimo de esforço.\n\nTraz a mesma **experiência do desenvolvedor** de criar aplicações com FastAPI para **fazer o deploy** delas na nuvem. 🎉\n\nA FastAPI Cloud é a principal patrocinadora e financiadora dos projetos open source do ecossistema *FastAPI and friends*. ✨\n\n#### Faça o deploy em outros provedores de nuvem { #deploy-to-other-cloud-providers }\n\nFastAPI é open source e baseado em padrões. Você pode fazer deploy de aplicações FastAPI em qualquer provedor de nuvem que preferir.\n\nSiga os tutoriais do seu provedor de nuvem para fazer deploy de aplicações FastAPI com eles. 🤓\n\n## Recapitulando { #recap }\n\n* Importe `FastAPI`.\n* Crie uma instância do `app`.\n* Escreva um **decorador de operação de rota** usando decoradores como `@app.get(\"/\")`.\n* Defina uma **função de operação de rota**; por exemplo, `def root(): ...`.\n* Execute o servidor de desenvolvimento usando o comando `fastapi dev`.\n* Opcionalmente, faça o deploy da sua aplicação com `fastapi deploy`.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/handling-errors.md",
    "content": "# Manipulação de erros { #handling-errors }\n\nHá diversas situações em que você precisa notificar um erro a um cliente que está utilizando a sua API.\n\nEsse cliente pode ser um browser com um frontend, o código de outra pessoa, um dispositivo IoT, etc.\n\nPode ser que você precise comunicar ao cliente que:\n\n* O cliente não tem direitos para realizar aquela operação.\n* O cliente não tem acesso aquele recurso.\n* O item que o cliente está tentando acessar não existe.\n* etc.\n\nNesses casos, você normalmente retornaria um **HTTP status code** próximo ao status code na faixa do status code **400** (do 400 ao 499).\n\nIsso é bastante similar ao caso do HTTP status code 200 (do 200 ao 299). Esses \"200\" status codes significam que, de algum modo, houve sucesso na requisição.\n\nOs status codes na faixa dos 400 significam que houve um erro por parte do cliente.\n\nVocê se lembra de todos aqueles erros (e piadas) a respeito do \"**404 Not Found**\"?\n\n## Use o `HTTPException` { #use-httpexception }\n\nPara retornar ao cliente *responses* HTTP com erros, use o `HTTPException`.\n\n### Import `HTTPException` { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### Lance o `HTTPException` no seu código { #raise-an-httpexception-in-your-code }\n\n`HTTPException`, ao fundo, nada mais é do que a conjunção entre uma exceção comum do Python e informações adicionais relevantes para APIs.\n\nE porque é uma exceção do Python, você não **retorna** (return) o `HTTPException`, você lança o (raise) no seu código.\n\nIsso também significa que, se você está escrevendo uma função de utilidade, a qual você está chamando dentro da sua função de operação de rota, e você lança o `HTTPException` dentro da função de utilidade, o resto do seu código não será executado dentro da função de operação de rota. Ao contrário, o `HTTPException` irá finalizar a requisição no mesmo instante e enviará o erro HTTP oriundo do `HTTPException` para o cliente.\n\nO benefício de lançar uma exceção em vez de retornar um valor ficará mais evidente na seção sobre Dependências e Segurança.\n\nNeste exemplo, quando o cliente pede, na requisição, por um item cujo ID não existe, a exceção com o status code `404` é lançada:\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### A response resultante { #the-resulting-response }\n\nSe o cliente faz uma requisição para `http://example.com/items/foo` (um `item_id` `\"foo\"`), esse cliente receberá um HTTP status code 200, e uma resposta JSON:\n\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\nMas se o cliente faz uma requisição para `http://example.com/items/bar` (ou seja, um não existente `item_id \"bar\"`), esse cliente receberá um HTTP status code 404 (o erro \"não encontrado\" — *not found error*), e uma resposta JSON:\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip | Dica\n\nQuando você lançar um `HTTPException`, você pode passar qualquer valor convertível em JSON como parâmetro de `detail`, e não apenas `str`.\n\nVocê pode passar um `dict` ou um `list`, etc.\nEsses tipos de dados são manipulados automaticamente pelo **FastAPI** e convertidos em JSON.\n\n///\n\n## Adicione headers customizados { #add-custom-headers }\n\nHá certas situações em que é bastante útil poder adicionar headers customizados no HTTP error. Exemplo disso seria adicionar headers customizados para tipos de segurança.\n\nVocê provavelmente não precisará utilizar esses headers diretamente no seu código.\n\nMas caso você precise, para um cenário mais complexo, você pode adicionar headers customizados:\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## Instale manipuladores de exceções customizados { #install-custom-exception-handlers }\n\nVocê pode adicionar manipuladores de exceção customizados com [a mesma seção de utilidade de exceções presentes no Starlette](https://www.starlette.dev/exceptions/).\n\nDigamos que você tenha uma exceção customizada `UnicornException` que você (ou uma biblioteca que você use) precise lançar (`raise`).\n\nNesse cenário, se você precisa manipular essa exceção de modo global com o FastAPI, você pode adicionar um manipulador de exceção customizada com `@app.exception_handler()`.\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\nNesse cenário, se você fizer uma requisição para `/unicorns/yolo`, a *operação de rota* vai lançar (`raise`) o `UnicornException`.\n\nEssa exceção será manipulada, contudo, pelo `unicorn_exception_handler`.\n\nDessa forma você receberá um erro \"limpo\", com o HTTP status code `418` e um JSON com o conteúdo:\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | Detalhes Técnicos\n\nVocê também pode usar `from starlette.requests import Request` e `from starlette.responses import JSONResponse`.\n\n**FastAPI** disponibiliza o mesmo `starlette.responses` através do `fastapi.responses` por conveniência ao desenvolvedor. Contudo, a maior parte das respostas disponíveis vem diretamente do Starlette. O mesmo acontece com o `Request`.\n\n///\n\n## Sobrescreva os manipuladores de exceções padrão { #override-the-default-exception-handlers }\n\n**FastAPI** tem alguns manipuladores padrão de exceções.\n\nEsses manipuladores são os responsáveis por retornar o JSON padrão de respostas quando você lança (`raise`) o `HTTPException` e quando a requisição tem dados inválidos.\n\nVocê pode sobrescrever esses manipuladores de exceção com os seus próprios manipuladores.\n\n### Sobrescreva exceções de validação da requisição { #override-request-validation-exceptions }\n\nQuando a requisição contém dados inválidos, **FastAPI** internamente lança para o `RequestValidationError`.\n\nE também inclui um manipulador de exceções padrão para ele.\n\nPara sobrescrevê-lo, importe o `RequestValidationError` e use-o com o `@app.exception_handler(RequestValidationError)` para decorar o manipulador de exceções.\n\nO manipulador de exceções receberá um `Request` e a exceção.\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\nSe você for ao `/items/foo`, em vez de receber o JSON padrão com o erro:\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\nvocê receberá a versão em texto:\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### Sobrescreva o manipulador de erro `HTTPException` { #override-the-httpexception-error-handler }\n\nDo mesmo modo, você pode sobrescrever o `HTTPException`.\n\nPor exemplo, você pode querer retornar uma *response* em *plain text* ao invés de um JSON para os seguintes erros:\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | Detalhes Técnicos\n\nVocê pode usar `from starlette.responses import PlainTextResponse`.\n\n**FastAPI** disponibiliza o mesmo `starlette.responses` como `fastapi.responses`, como conveniência a você, desenvolvedor. Contudo, a maior parte das respostas disponíveis vem diretamente do Starlette.\n\n///\n\n/// warning | Atenção\n\nTenha em mente que o `RequestValidationError` contém as informações do nome do arquivo e da linha onde o erro de validação acontece, para que você possa mostrá-las nos seus logs com as informações relevantes, se quiser.\n\nMas isso significa que, se você simplesmente convertê-lo para uma string e retornar essa informação diretamente, você pode acabar vazando um pouco de informação sobre o seu sistema; por isso, aqui o código extrai e mostra cada erro de forma independente.\n\n///\n\n### Use o body do `RequestValidationError` { #use-the-requestvalidationerror-body }\n\nO `RequestValidationError` contém o `body` que ele recebeu de dados inválidos.\n\nVocê pode utilizá-lo enquanto desenvolve seu app para registrar o *body* e debugá-lo, e assim retorná-lo ao usuário, etc.\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\nTente enviar um item inválido como este:\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\nVocê receberá uma *response* informando-o de que os dados são inválidos, e contendo o *body* recebido:\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### O `HTTPException` do FastAPI vs o `HTTPException` do Starlette { #fastapis-httpexception-vs-starlettes-httpexception }\n\nO **FastAPI** tem o seu próprio `HTTPException`.\n\nE a classe de erro `HTTPException` do **FastAPI** herda da classe de erro do `HTTPException` do Starlette.\n\nA única diferença é que o `HTTPException` do **FastAPI** aceita qualquer dado que possa ser convertido em JSON para o campo `detail`, enquanto o `HTTPException` do Starlette aceita apenas strings para esse campo.\n\nPortanto, você pode continuar lançando o `HTTPException` do **FastAPI** normalmente no seu código.\n\nPorém, quando você registrar um manipulador de exceção, você deve registrá-lo através do `HTTPException` do Starlette.\n\nDessa forma, se qualquer parte do código interno, extensão ou plug-in do Starlette lançar um `HTTPException` do Starlette, o seu manipulador poderá capturar e tratá-lo.\n\nNeste exemplo, para poder ter ambos os `HTTPException` no mesmo código, a exceção do Starlette é renomeada para `StarletteHTTPException`:\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### Reutilize os manipuladores de exceção do **FastAPI** { #reuse-fastapis-exception-handlers }\n\nSe você quer usar a exceção em conjunto com o mesmo manipulador de exceção *default* do **FastAPI**, você pode importar e re-usar esses manipuladores de exceção do `fastapi.exception_handlers`:\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\nNesse exemplo você apenas imprime (`print`) o erro com uma mensagem expressiva. Mesmo assim, dá para pegar a ideia. Você pode usar a exceção e então apenas re-usar o manipulador de exceção *default*.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/header-param-models.md",
    "content": "# Modelos de Parâmetros do Cabeçalho { #header-parameter-models }\n\nSe você possui um grupo de **parâmetros de cabeçalho** relacionados, você pode criar um **modelo do Pydantic** para declará-los.\n\nIsso vai lhe permitir **reusar o modelo** em **múltiplos lugares** e também declarar validações e metadados para todos os parâmetros de uma vez. 😎\n\n/// note | Nota\n\nIsso é possível desde a versão `0.115.0` do FastAPI. 🤓\n\n///\n\n## Parâmetros do Cabeçalho com um Modelo Pydantic { #header-parameters-with-a-pydantic-model }\n\nDeclare os **parâmetros de cabeçalho** que você precisa em um **modelo do Pydantic**, e então declare o parâmetro como `Header`:\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\nO **FastAPI** irá **extrair** os dados de **cada campo** a partir dos **cabeçalhos** da requisição e te retornará o modelo do Pydantic que você definiu.\n\n## Checando a documentação { #check-the-docs }\n\nVocê pode ver os headers necessários na interface gráfica da documentação em `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## Proibindo Cabeçalhos adicionais { #forbid-extra-headers }\n\nEm alguns casos de uso especiais (provavelmente não muito comuns), você pode querer **restringir** os cabeçalhos que você quer receber.\n\nVocê pode usar a configuração dos modelos do Pydantic para proibir (`forbid`) quaisquer campos `extra`:\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\nSe um cliente tentar enviar alguns **cabeçalhos extra**, eles irão receber uma resposta de **erro**.\n\nPor exemplo, se o cliente tentar enviar um cabeçalho `tool` com o valor `plumbus`, ele irá receber uma resposta de **erro** informando que o parâmetro do cabeçalho `tool` não é permitido:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## Desativar conversão de underscores { #disable-convert-underscores }\n\nDa mesma forma que com parâmetros de cabeçalho normais, quando você tem caracteres de sublinhado nos nomes dos parâmetros, eles são **automaticamente convertidos em hifens**.\n\nPor exemplo, se você tem um parâmetro de cabeçalho `save_data` no código, o cabeçalho HTTP esperado será `save-data`, e ele aparecerá assim na documentação.\n\nSe por algum motivo você precisar desativar essa conversão automática, também poderá fazê-lo para modelos do Pydantic para parâmetros de cabeçalho.\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | Atenção\n\nAntes de definir `convert_underscores` como `False`, tenha em mente que alguns proxies e servidores HTTP não permitem o uso de cabeçalhos com sublinhados.\n\n///\n\n## Resumo { #summary }\n\nVocê pode utilizar **modelos do Pydantic** para declarar **cabeçalhos** no **FastAPI**. 😎\n"
  },
  {
    "path": "docs/pt/docs/tutorial/header-params.md",
    "content": "# Parâmetros de Cabeçalho { #header-parameters }\n\nVocê pode definir parâmetros de Cabeçalho da mesma maneira que define paramêtros com `Query`, `Path` e `Cookie`.\n\n## Importe `Header` { #import-header }\n\nPrimeiro importe `Header`:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## Declare parâmetros de `Header` { #declare-header-parameters }\n\nEntão declare os paramêtros de cabeçalho usando a mesma estrutura que em `Path`, `Query` e `Cookie`.\n\nVocê pode definir o valor padrão, assim como todas as validações extras ou parâmetros de anotação:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Detalhes Técnicos\n\n`Header` é uma classe \"irmã\" de `Path`, `Query` e `Cookie`. Ela também herda da mesma classe em comum `Param`.\n\nMas lembre-se que quando você importa `Query`, `Path`, `Header`, e outras de `fastapi`, elas são na verdade funções que retornam classes especiais.\n\n///\n\n/// info | Informação\n\nPara declarar headers, você precisa usar `Header`, caso contrário, os parâmetros seriam interpretados como parâmetros de consulta.\n\n///\n\n## Conversão automática { #automatic-conversion }\n\n`Header` tem algumas funcionalidades a mais em relação a `Path`, `Query` e `Cookie`.\n\nA maioria dos cabeçalhos padrão são separados pelo caractere \"hífen\", também conhecido como \"sinal de menos\" (`-`).\n\nMas uma variável como `user-agent` é inválida em Python.\n\nPortanto, por padrão, `Header` converterá os caracteres de nomes de parâmetros de sublinhado (`_`) para hífen (`-`) para extrair e documentar os cabeçalhos.\n\nAlém disso, os cabeçalhos HTTP não diferenciam maiúsculas de minúsculas, portanto, você pode declará-los com o estilo padrão do Python (também conhecido como \"snake_case\").\n\nPortanto, você pode usar `user_agent` como faria normalmente no código Python, em vez de precisar colocar as primeiras letras em maiúsculas como `User_Agent` ou algo semelhante.\n\nSe por algum motivo você precisar desabilitar a conversão automática de sublinhados para hífens, defina o parâmetro `convert_underscores` de `Header` para `False`:\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | Atenção\n\nAntes de definir `convert_underscores` como `False`, lembre-se de que alguns proxies e servidores HTTP não permitem o uso de cabeçalhos com sublinhados.\n\n///\n\n## Cabeçalhos duplicados { #duplicate-headers }\n\nÉ possível receber cabeçalhos duplicados. Isso significa, o mesmo cabeçalho com vários valores.\n\nVocê pode definir esses casos usando uma lista na declaração de tipo.\n\nVocê receberá todos os valores do cabeçalho duplicado como uma `list` Python.\n\nPor exemplo, para declarar um cabeçalho de `X-Token` que pode aparecer mais de uma vez, você pode escrever:\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\nSe você se comunicar com essa *operação de rota* enviando dois cabeçalhos HTTP como:\n\n```\nX-Token: foo\nX-Token: bar\n```\n\nA resposta seria como:\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## Recapitulando { #recap }\n\nDeclare cabeçalhos com `Header`, usando o mesmo padrão comum que utiliza-se em `Query`, `Path` e `Cookie`.\n\nE não se preocupe com sublinhados em suas variáveis, **FastAPI** cuidará da conversão deles.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/index.md",
    "content": "# Tutorial - Guia de Usuário { #tutorial-user-guide }\n\nEsse tutorial mostra como usar o **FastAPI** com a maior parte de seus recursos, passo a passo.\n\nCada seção constrói, gradualmente, sobre as anteriores, mas sua estrutura são tópicos separados, para que você possa ir a qualquer um específico e resolver suas necessidades específicas de API.\n\nEle também foi construído para servir como uma referência futura, então você pode voltar e ver exatamente o que você precisa.\n\n## Rode o código { #run-the-code }\n\nTodos os blocos de código podem ser copiados e utilizados diretamente (eles são, na verdade, arquivos Python testados).\n\nPara rodar qualquer um dos exemplos, copie o código para um arquivo `main.py`, e inicie o `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nÉ **ALTAMENTE recomendado** que você escreva ou copie o código, edite-o e rode-o localmente.\n\nUsá-lo em seu editor é o que realmente te mostra os benefícios do FastAPI, ver quão pouco código você tem que escrever, todas as conferências de tipo, preenchimento automático, etc.\n\n---\n\n## Instale o FastAPI { #install-fastapi }\n\nO primeiro passo é instalar o FastAPI.\n\nCertifique-se de criar um [ambiente virtual](../virtual-environments.md), ativá-lo e então **instalar o FastAPI**:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | Nota\n\nQuando você instala com `pip install \"fastapi[standard]\"`, ele vem com algumas dependências opcionais padrão, incluindo `fastapi-cloud-cli`, que permite fazer deploy na [FastAPI Cloud](https://fastapicloud.com).\n\nSe você não quiser ter essas dependências opcionais, pode instalar `pip install fastapi` em vez disso.\n\nSe você quiser instalar as dependências padrão, mas sem o `fastapi-cloud-cli`, você pode instalar com `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n///\n\n/// tip | Dica\n\nO FastAPI tem uma [extensão oficial para o VS Code](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (e para o Cursor), que fornece vários recursos, incluindo um explorador de operações de rota, busca de operações de rota, navegação CodeLens em testes (ir para a definição a partir dos testes) e deploy e logs da FastAPI Cloud, tudo direto do seu editor.\n\n///\n\n## Guia Avançado de Usuário { #advanced-user-guide }\n\nHá também um **Guia Avançado de Usuário** que você pode ler após esse **Tutorial - Guia de Usuário**.\n\nO **Guia Avançado de Usuário** constrói sobre esse, usa os mesmos conceitos e te ensina algumas funcionalidades extras.\n\nMas você deveria ler primeiro o **Tutorial - Guia de Usuário** (que você está lendo agora).\n\nEle foi projetado para que você possa construir uma aplicação completa com apenas o **Tutorial - Guia de Usuário**, e então estendê-la de diferentes formas, dependendo das suas necessidades, usando algumas ideias adicionais do **Guia Avançado de Usuário**.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/metadata.md",
    "content": "# Metadados e URLs da Documentação { #metadata-and-docs-urls }\n\nVocê pode personalizar várias configurações de metadados na sua aplicação **FastAPI**.\n\n## Metadados para API { #metadata-for-api }\n\nVocê pode definir os seguintes campos que são usados na especificação OpenAPI e nas interfaces automáticas de documentação da API:\n\n| Parâmetro | Tipo | Descrição |\n|------------|------|-------------|\n| `title` | `str` | O título da API. |\n| `summary` | `str` | Um breve resumo da API. <small>Disponível desde OpenAPI 3.1.0, FastAPI 0.99.0.</small> |\n| `description` | `str` | Uma breve descrição da API. Pode usar Markdown. |\n| `version` | `string` | A versão da API. Esta é a versão da sua aplicação, não do OpenAPI. Por exemplo, `2.5.0`. |\n| `terms_of_service` | `str` | Uma URL para os Termos de Serviço da API. Se fornecido, deve ser uma URL. |\n| `contact` | `dict` | As informações de contato da API exposta. Pode conter vários campos. <details><summary>Campos de <code>contact</code></summary><table><thead><tr><th>Parâmetro</th><th>Tipo</th><th>Descrição</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>O nome identificador da pessoa/organização de contato.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>A URL que aponta para as informações de contato. DEVE estar no formato de uma URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>O endereço de e-mail da pessoa/organização de contato. DEVE estar no formato de um endereço de e-mail.</td></tr></tbody></table></details> |\n| `license_info` | `dict` | As informações de licença para a API exposta. Ela pode conter vários campos. <details><summary>Campos de <code>license_info</code></summary><table><thead><tr><th>Parâmetro</th><th>Tipo</th><th>Descrição</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>OBRIGATÓRIO</strong> (se um <code>license_info</code> for definido). O nome da licença usada para a API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Uma expressão de licença [SPDX](https://spdx.org/licenses/) para a API. O campo <code>identifier</code> é mutuamente exclusivo do campo <code>url</code>. <small>Disponível desde OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>Uma URL para a licença usada para a API. DEVE estar no formato de uma URL.</td></tr></tbody></table></details> |\n\nVocê pode defini-los da seguinte maneira:\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | Dica\n\nVocê pode escrever Markdown no campo `description` e ele será renderizado na saída.\n\n///\n\nCom essa configuração, a documentação automática da API se pareceria com:\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## Identificador de Licença { #license-identifier }\n\nDesde o OpenAPI 3.1.0 e FastAPI 0.99.0, você também pode definir o `license_info` com um `identifier` em vez de uma `url`.\n\nPor exemplo:\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## Metadados para tags { #metadata-for-tags }\n\nVocê também pode adicionar metadados adicionais para as diferentes tags usadas para agrupar suas operações de rota com o parâmetro `openapi_tags`.\n\nEle recebe uma lista contendo um dicionário para cada tag.\n\nCada dicionário pode conter:\n\n* `name` (**obrigatório**): uma `str` com o mesmo nome da tag que você usa no parâmetro `tags` nas suas *operações de rota* e `APIRouter`s.\n* `description`: uma `str` com uma breve descrição da tag. Pode conter Markdown e será exibido na interface de documentação.\n* `externalDocs`: um `dict` descrevendo a documentação externa com:\n    * `description`: uma `str` com uma breve descrição da documentação externa.\n    * `url` (**obrigatório**): uma `str` com a URL da documentação externa.\n\n### Criar Metadados para tags { #create-metadata-for-tags }\n\nVamos tentar isso em um exemplo com tags para `users` e `items`.\n\nCrie metadados para suas tags e passe-os para o parâmetro `openapi_tags`:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\nObserve que você pode usar Markdown dentro das descrições. Por exemplo, \"login\" será exibido em negrito (**login**) e \"fancy\" será exibido em itálico (_fancy_).\n\n/// tip | Dica\n\nVocê não precisa adicionar metadados para todas as tags que você usa.\n\n///\n\n### Use suas tags { #use-your-tags }\n\nUse o parâmetro `tags` com suas *operações de rota* (e `APIRouter`s) para atribuí-los a diferentes tags:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info | Informação\n\nLeia mais sobre tags em [Configuração de operação de rota](path-operation-configuration.md#tags).\n\n///\n\n### Cheque os documentos { #check-the-docs }\n\nAgora, se você verificar a documentação, ela exibirá todos os metadados adicionais:\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### Ordem das tags { #order-of-tags }\n\nA ordem de cada dicionário de metadados de tag também define a ordem exibida na interface de documentação.\n\nPor exemplo, embora `users` apareça após `items` em ordem alfabética, ele é exibido antes deles, porque adicionamos seus metadados como o primeiro dicionário na lista.\n\n## URL da OpenAPI { #openapi-url }\n\nPor padrão, o esquema OpenAPI é servido em `/openapi.json`.\n\nMas você pode configurá-lo com o parâmetro `openapi_url`.\n\nPor exemplo, para defini-lo para ser servido em `/api/v1/openapi.json`:\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\nSe você quiser desativar completamente o esquema OpenAPI, pode definir `openapi_url=None`, o que também desativará as interfaces de documentação que o utilizam.\n\n## URLs da Documentação { #docs-urls }\n\nVocê pode configurar as duas interfaces de documentação incluídas:\n\n* **Swagger UI**: acessível em `/docs`.\n    * Você pode definir sua URL com o parâmetro `docs_url`.\n    * Você pode desativá-la definindo `docs_url=None`.\n* **ReDoc**: acessível em `/redoc`.\n    * Você pode definir sua URL com o parâmetro `redoc_url`.\n    * Você pode desativá-la definindo `redoc_url=None`.\n\nPor exemplo, para definir o Swagger UI para ser servido em `/documentation` e desativar o ReDoc:\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/pt/docs/tutorial/middleware.md",
    "content": "# Middleware { #middleware }\n\nVocê pode adicionar middleware à suas aplicações **FastAPI**.\n\nUm \"middleware\" é uma função que manipula cada **requisição** antes de ser processada por qualquer *operação de rota* específica. E também cada **resposta** antes de retorná-la.\n\n* Ele pega cada **requisição** que chega ao seu aplicativo.\n* Ele pode então fazer algo com essa **requisição** ou executar qualquer código necessário.\n* Então ele passa a **requisição** para ser processada pelo resto do aplicativo (por alguma *operação de rota*).\n* Ele então pega a **resposta** gerada pelo aplicativo (por alguma *operação de rota*).\n* Ele pode fazer algo com essa **resposta** ou executar qualquer código necessário.\n* Então ele retorna a **resposta**.\n\n/// note | Detalhes Técnicos\n\nSe você tiver dependências com `yield`, o código de saída será executado *depois* do middleware.\n\nSe houver alguma tarefa em segundo plano (abordada na seção [Tarefas em segundo plano](background-tasks.md), que você verá mais adiante), ela será executada *depois* de todo o middleware.\n\n///\n\n## Criar um middleware { #create-a-middleware }\n\nPara criar um middleware, use o decorador `@app.middleware(\"http\")` logo acima de uma função.\n\nA função middleware recebe:\n\n* A `request`.\n* Uma função `call_next` que receberá o `request` como um parâmetro.\n    * Esta função passará a `request` para a *operação de rota* correspondente.\n    * Então ela retorna a `response` gerada pela *operação de rota* correspondente.\n* Você pode então modificar ainda mais o `response` antes de retorná-lo.\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip | Dica\n\nTenha em mente que cabeçalhos proprietários personalizados podem ser adicionados [usando o prefixo `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nMas se você tiver cabeçalhos personalizados desejando que um cliente em um navegador esteja apto a ver, você precisa adicioná-los às suas configurações CORS ([CORS (Cross-Origin Resource Sharing)](cors.md)) usando o parâmetro `expose_headers` documentado na [Documentação CORS da Starlette](https://www.starlette.dev/middleware/#corsmiddleware).\n\n///\n\n/// note | Detalhes Técnicos\n\nVocê também pode usar `from starlette.requests import Request`.\n\n**FastAPI** fornece isso como uma conveniência para você, o desenvolvedor. Mas vem diretamente da Starlette.\n\n///\n\n### Antes e depois da `response` { #before-and-after-the-response }\n\nVocê pode adicionar código para ser executado com a `request`, antes que qualquer *operação de rota* o receba.\n\nE também depois que a `response` é gerada, antes de retorná-la.\n\nPor exemplo, você pode adicionar um cabeçalho personalizado `X-Process-Time` contendo o tempo em segundos que levou para processar a solicitação e gerar uma resposta:\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip | Dica\n\nAqui usamos [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) em vez de `time.time()` porque ele pode ser mais preciso para esses casos de uso. 🤓\n\n///\n\n## Ordem de execução de múltiplos middlewares { #multiple-middleware-execution-order }\n\nQuando você adiciona múltiplos middlewares usando o decorador `@app.middleware()` ou o método `app.add_middleware()`, cada novo middleware envolve a aplicação, formando uma pilha. O último middleware adicionado é o mais externo, e o primeiro é o mais interno.\n\nNo caminho da requisição, o middleware mais externo roda primeiro.\n\nNo caminho da resposta, ele roda por último.\n\nPor exemplo:\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\nIsso resulta na seguinte ordem de execução:\n\n* **Requisição**: MiddlewareB → MiddlewareA → rota\n\n* **Resposta**: rota → MiddlewareA → MiddlewareB\n\nEsse comportamento de empilhamento garante que os middlewares sejam executados em uma ordem previsível e controlável.\n\n## Outros middlewares { #other-middlewares }\n\nMais tarde, você pode ler mais sobre outros middlewares no [Guia do usuário avançado: Middleware avançado](../advanced/middleware.md).\n\nVocê lerá sobre como manipular <abbr title=\"Cross-Origin Resource Sharing\">CORS</abbr> com um middleware na próxima seção.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/path-operation-configuration.md",
    "content": "# Configuração da Operação de Rota { #path-operation-configuration }\n\nExistem vários parâmetros que você pode passar para o seu *decorador de operação de rota* para configurá-lo.\n\n/// warning | Atenção\n\nObserve que esses parâmetros são passados diretamente para o *decorador de operação de rota*, não para a sua *função de operação de rota*.\n\n///\n\n## Código de Status da Resposta { #response-status-code }\n\nVocê pode definir o `status_code` (HTTP) para ser usado na resposta da sua *operação de rota*.\n\nVocê pode passar diretamente o código `int`, como `404`.\n\nMas se você não se lembrar o que cada código numérico significa, pode usar as constantes de atalho em `status`:\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\nEsse código de status será usado na resposta e será adicionado ao esquema OpenAPI.\n\n/// note | Detalhes Técnicos\n\nVocê também poderia usar `from starlette import status`.\n\n**FastAPI** fornece o mesmo `starlette.status` como `fastapi.status` apenas como uma conveniência para você, o desenvolvedor. Mas vem diretamente do Starlette.\n\n///\n\n## Tags { #tags }\n\nVocê pode adicionar tags para sua *operação de rota*, passe o parâmetro `tags` com uma `list` de `str` (comumente apenas um `str`):\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\nEles serão adicionados ao esquema OpenAPI e usados pelas interfaces de documentação automática:\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### Tags com Enums { #tags-with-enums }\n\nSe você tem uma grande aplicação, você pode acabar acumulando **várias tags**, e você gostaria de ter certeza de que você sempre usa a ** mesma tag** para *operações de rota* relacionadas.\n\nNestes casos, pode fazer sentido armazenar as tags em um `Enum`.\n\n**FastAPI** suporta isso da mesma maneira que com strings simples:\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## Resumo e descrição { #summary-and-description }\n\nVocê pode adicionar um `summary` e uma `description`:\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## Descrição do docstring { #description-from-docstring }\n\nComo as descrições tendem a ser longas e cobrir várias linhas, você pode declarar a descrição da *operação de rota* na <dfn title=\"uma string de várias linhas como a primeira expressão dentro de uma função (não atribuída a nenhuma variável) usada para documentação\">docstring</dfn> da função e o **FastAPI** irá lê-la de lá.\n\nVocê pode escrever [Markdown](https://en.wikipedia.org/wiki/Markdown) na docstring, ele será interpretado e exibido corretamente (levando em conta a indentação da docstring).\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\nEla será usada nas documentações interativas:\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## Descrição da resposta { #response-description }\n\nVocê pode especificar a descrição da resposta com o parâmetro `response_description`:\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info | Informação\n\nNote que `response_description` se refere especificamente à resposta, a `description` se refere à *operação de rota* em geral.\n\n///\n\n/// check | Verifique\n\nOpenAPI especifica que cada *operação de rota* requer uma descrição de resposta.\n\nEntão, se você não fornecer uma, o **FastAPI** irá gerar automaticamente uma de \"Resposta bem-sucedida\".\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## Descontinuar uma *operação de rota* { #deprecate-a-path-operation }\n\nSe você precisar marcar uma *operação de rota* como <dfn title=\"obsoleta, recomendado não usar\">descontinuada</dfn>, mas sem removê-la, passe o parâmetro `deprecated`:\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\nEla será claramente marcada como descontinuada nas documentações interativas:\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\nVerifique como *operações de rota* descontinuadas e não descontinuadas se parecem:\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## Resumindo { #recap }\n\nVocê pode configurar e adicionar metadados para suas *operações de rota* facilmente passando parâmetros para os *decoradores de operação de rota*.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/path-params-numeric-validations.md",
    "content": "# Parâmetros de path e validações numéricas { #path-parameters-and-numeric-validations }\n\nDa mesma forma que você pode declarar mais validações e metadados para parâmetros de consulta com `Query`, você pode declarar o mesmo tipo de validações e metadados para parâmetros de path com `Path`.\n\n## Importe `Path` { #import-path }\n\nPrimeiro, importe `Path` de `fastapi`, e importe `Annotated`:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info | Informação\n\nO FastAPI adicionou suporte a `Annotated` (e passou a recomendá-lo) na versão 0.95.0.\n\nSe você tiver uma versão mais antiga, verá erros ao tentar usar `Annotated`.\n\nCertifique-se de [Atualizar a versão do FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) para pelo menos 0.95.1 antes de usar `Annotated`.\n\n///\n\n## Declare metadados { #declare-metadata }\n\nVocê pode declarar todos os mesmos parâmetros que em `Query`.\n\nPor exemplo, para declarar um valor de metadado `title` para o parâmetro de path `item_id` você pode digitar:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note | Nota\n\nUm parâmetro de path é sempre obrigatório, pois precisa fazer parte do path. Mesmo que você o declare como `None` ou defina um valor padrão, isso não afetaria nada, ele ainda seria sempre obrigatório.\n\n///\n\n## Ordene os parâmetros de acordo com sua necessidade { #order-the-parameters-as-you-need }\n\n/// tip | Dica\n\nIsso provavelmente não é tão importante ou necessário se você usar `Annotated`.\n\n///\n\nVamos supor que você queira declarar o parâmetro de consulta `q` como uma `str` obrigatória.\n\nE você não precisa declarar mais nada para esse parâmetro, então você realmente não precisa usar `Query`.\n\nMas você ainda precisa usar `Path` para o parâmetro de path `item_id`. E você não quer usar `Annotated` por algum motivo.\n\nO Python vai reclamar se você colocar um valor com “padrão” antes de um valor que não tem “padrão”.\n\nMas você pode reordená-los e colocar primeiro o valor sem padrão (o parâmetro de consulta `q`).\n\nIsso não faz diferença para o **FastAPI**. Ele vai detectar os parâmetros pelos seus nomes, tipos e declarações de padrão (`Query`, `Path`, etc.), sem se importar com a ordem.\n\nEntão, você pode declarar sua função assim:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\nMas tenha em mente que, se você usar `Annotated`, você não terá esse problema, não fará diferença, pois você não está usando valores padrão de parâmetros de função para `Query()` ou `Path()`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## Ordene os parâmetros de acordo com sua necessidade, truques { #order-the-parameters-as-you-need-tricks }\n\n/// tip | Dica\n\nIsso provavelmente não é tão importante ou necessário se você usar `Annotated`.\n\n///\n\nAqui vai um pequeno truque que pode ser útil, mas você não vai precisar dele com frequência.\n\nSe você quiser:\n\n* declarar o parâmetro de consulta `q` sem um `Query` nem qualquer valor padrão\n* declarar o parâmetro de path `item_id` usando `Path`\n* tê-los em uma ordem diferente\n* não usar `Annotated`\n\n...o Python tem uma pequena sintaxe especial para isso.\n\nPasse `*`, como o primeiro parâmetro da função.\n\nO Python não fará nada com esse `*`, mas saberá que todos os parâmetros seguintes devem ser chamados como argumentos nomeados (pares chave-valor), também conhecidos como <abbr title=\"De: K-ey W-ord Arg-uments\"><code>kwargs</code></abbr>. Mesmo que eles não tenham um valor padrão.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### Melhor com `Annotated` { #better-with-annotated }\n\nTenha em mente que, se você usar `Annotated`, como você não está usando valores padrão de parâmetros de função, você não terá esse problema e provavelmente não precisará usar `*`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## Validações numéricas: maior que ou igual { #number-validations-greater-than-or-equal }\n\nCom `Query` e `Path` (e outras que você verá depois) você pode declarar restrições numéricas.\n\nAqui, com `ge=1`, `item_id` precisará ser um número inteiro “`g`reater than or `e`qual” a `1`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## Validações numéricas: maior que e menor que ou igual { #number-validations-greater-than-and-less-than-or-equal }\n\nO mesmo se aplica a:\n\n* `gt`: maior que (`g`reater `t`han)\n* `le`: menor que ou igual (`l`ess than or `e`qual)\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## Validações numéricas: floats, maior que e menor que { #number-validations-floats-greater-than-and-less-than }\n\nValidações numéricas também funcionam para valores `float`.\n\nAqui é onde se torna importante poder declarar <abbr title=\"greater than – maior que\"><code>gt</code></abbr> e não apenas <abbr title=\"greater than or equal – maior que ou igual\"><code>ge</code></abbr>. Com isso você pode exigir, por exemplo, que um valor seja maior que `0`, mesmo que seja menor que `1`.\n\nAssim, `0.5` seria um valor válido. Mas `0.0` ou `0` não seriam.\n\nE o mesmo para <abbr title=\"less than – menor que\"><code>lt</code></abbr>.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## Recapitulando { #recap }\n\nCom `Query`, `Path` (e outras que você ainda não viu) você pode declarar metadados e validações de string do mesmo modo que em [Parâmetros de consulta e validações de string](query-params-str-validations.md).\n\nE você também pode declarar validações numéricas:\n\n* `gt`: maior que (`g`reater `t`han)\n* `ge`: maior que ou igual (`g`reater than or `e`qual)\n* `lt`: menor que (`l`ess `t`han)\n* `le`: menor que ou igual (`l`ess than or `e`qual)\n\n/// info | Informação\n\n`Query`, `Path` e outras classes que você verá depois são subclasses de uma classe comum `Param`.\n\nTodas elas compartilham os mesmos parâmetros para validação adicional e metadados que você viu.\n\n///\n\n/// note | Detalhes Técnicos\n\nQuando você importa `Query`, `Path` e outras de `fastapi`, elas são na verdade funções.\n\nQue, quando chamadas, retornam instâncias de classes de mesmo nome.\n\nEntão, você importa `Query`, que é uma função. E quando você a chama, ela retorna uma instância de uma classe também chamada `Query`.\n\nEssas funções existem (em vez de usar diretamente as classes) para que seu editor não marque erros sobre seus tipos.\n\nDessa forma, você pode usar seu editor e ferramentas de codificação normais sem precisar adicionar configurações personalizadas para desconsiderar esses erros.\n\n///\n"
  },
  {
    "path": "docs/pt/docs/tutorial/path-params.md",
    "content": "# Parâmetros de path { #path-parameters }\n\nVocê pode declarar \"parâmetros\" ou \"variáveis\" de path com a mesma sintaxe usada por strings de formatação do Python:\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\nO valor do parâmetro de path `item_id` será passado para a sua função como o argumento `item_id`.\n\nEntão, se você executar este exemplo e acessar [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), você verá uma resposta:\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## Parâmetros de path com tipos { #path-parameters-with-types }\n\nVocê pode declarar o tipo de um parâmetro de path na função, usando as anotações de tipo padrão do Python:\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\nNeste caso, `item_id` é declarado como um `int`.\n\n/// check | Verifique\nIsso fornecerá suporte do editor dentro da sua função, com verificações de erros, preenchimento automático, etc.\n///\n\n## Dados <dfn title=\"também conhecido como: serialização, parsing, marshalling\">conversão</dfn> { #data-conversion }\n\nSe você executar este exemplo e abrir seu navegador em [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3), você verá uma resposta:\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check | Verifique\nPerceba que o valor que sua função recebeu (e retornou) é `3`, como um `int` do Python, não uma string `\"3\"`.\n\nEntão, com essa declaração de tipo, o **FastAPI** fornece <dfn title=\"convertendo a string que vem de um request HTTP em dados Python\">\"parsing\"</dfn> automático do request.\n///\n\n## Validação de dados { #data-validation }\n\nMas se você for no navegador para [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), verá um bom erro HTTP:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\nporque o parâmetro de path `item_id` tinha o valor `\"foo\"`, que não é um `int`.\n\nO mesmo erro apareceria se você fornecesse um `float` em vez de um `int`, como em: [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)\n\n/// check | Verifique\nEntão, com a mesma declaração de tipo do Python, o **FastAPI** fornece validação de dados.\n\nObserve que o erro também declara claramente exatamente o ponto onde a validação não passou.\n\nIsso é incrivelmente útil ao desenvolver e depurar código que interage com sua API.\n///\n\n## Documentação { #documentation }\n\nE quando você abrir seu navegador em [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), você verá documentação automática, interativa, da API como:\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check | Verifique\nNovamente, apenas com a mesma declaração de tipo do Python, o **FastAPI** fornece documentação automática e interativa (integrando o Swagger UI).\n\nObserve que o parâmetro de path está declarado como um inteiro.\n///\n\n## Benefícios baseados em padrões, documentação alternativa { #standards-based-benefits-alternative-documentation }\n\nE como o schema gerado é do padrão [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md), existem muitas ferramentas compatíveis.\n\nPor causa disso, o próprio **FastAPI** fornece uma documentação alternativa da API (usando ReDoc), que você pode acessar em [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc):\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\nDa mesma forma, existem muitas ferramentas compatíveis. Incluindo ferramentas de geração de código para muitas linguagens.\n\n## Pydantic { #pydantic }\n\nToda a validação de dados é realizada nos bastidores pelo [Pydantic](https://docs.pydantic.dev/), então você recebe todos os benefícios disso. E você sabe que está em boas mãos.\n\nVocê pode usar as mesmas declarações de tipo com `str`, `float`, `bool` e muitos outros tipos de dados complexos.\n\nVários deles são explorados nos próximos capítulos do tutorial.\n\n## A ordem importa { #order-matters }\n\nAo criar *operações de rota*, você pode encontrar situações em que tem um path fixo.\n\nComo `/users/me`, digamos que seja para obter dados sobre o usuário atual.\n\nE então você também pode ter um path `/users/{user_id}` para obter dados sobre um usuário específico por algum ID de usuário.\n\nComo as *operações de rota* são avaliadas em ordem, você precisa garantir que o path para `/users/me` seja declarado antes do de `/users/{user_id}`:\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\nCaso contrário, o path para `/users/{user_id}` também corresponderia a `/users/me`, \"achando\" que está recebendo um parâmetro `user_id` com o valor `\"me\"`.\n\nDa mesma forma, você não pode redefinir uma operação de rota:\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\nA primeira sempre será usada, já que o path corresponde primeiro.\n\n## Valores predefinidos { #predefined-values }\n\nSe você tem uma *operação de rota* que recebe um *parâmetro de path*, mas quer que os valores válidos possíveis do *parâmetro de path* sejam predefinidos, você pode usar um <abbr title=\"Enumeração\">`Enum`</abbr> padrão do Python.\n\n### Crie uma classe `Enum` { #create-an-enum-class }\n\nImporte `Enum` e crie uma subclasse que herde de `str` e de `Enum`.\n\nAo herdar de `str`, a documentação da API saberá que os valores devem ser do tipo `string` e poderá renderizá-los corretamente.\n\nEm seguida, crie atributos de classe com valores fixos, que serão os valores válidos disponíveis:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip | Dica\nSe você está se perguntando, \"AlexNet\", \"ResNet\" e \"LeNet\" são apenas nomes de modelos de Aprendizado de Máquina <dfn title=\"Tecnicamente, arquiteturas de modelos de Deep Learning\">modelos</dfn>.\n///\n\n### Declare um parâmetro de path { #declare-a-path-parameter }\n\nEm seguida, crie um *parâmetro de path* com anotação de tipo usando a classe enum que você criou (`ModelName`):\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### Verifique a documentação { #check-the-docs }\n\nComo os valores disponíveis para o *parâmetro de path* são predefinidos, a documentação interativa pode mostrá-los de forma agradável:\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### Trabalhando com *enumerações* do Python { #working-with-python-enumerations }\n\nO valor do *parâmetro de path* será um *membro de enumeração*.\n\n#### Compare membros de enumeração { #compare-enumeration-members }\n\nVocê pode compará-lo com o *membro de enumeração* no seu enum `ModelName` criado:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### Obtenha o valor da enumeração { #get-the-enumeration-value }\n\nVocê pode obter o valor real (um `str` neste caso) usando `model_name.value`, ou, em geral, `your_enum_member.value`:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip | Dica\nVocê também pode acessar o valor `\"lenet\"` com `ModelName.lenet.value`.\n///\n\n#### Retorne membros de enumeração { #return-enumeration-members }\n\nVocê pode retornar *membros de enum* da sua *operação de rota*, até mesmo aninhados em um corpo JSON (por exemplo, um `dict`).\n\nEles serão convertidos para seus valores correspondentes (strings neste caso) antes de serem retornados ao cliente:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\nNo seu cliente, você receberá uma resposta JSON como:\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## Parâmetros de path que contêm paths { #path-parameters-containing-paths }\n\nDigamos que você tenha uma *operação de rota* com um path `/files/{file_path}`.\n\nMas você precisa que o próprio `file_path` contenha um *path*, como `home/johndoe/myfile.txt`.\n\nEntão, a URL para esse arquivo seria algo como: `/files/home/johndoe/myfile.txt`.\n\n### Suporte do OpenAPI { #openapi-support }\n\nO OpenAPI não oferece suporte a uma maneira de declarar um *parâmetro de path* que contenha um *path* dentro, pois isso poderia levar a cenários difíceis de testar e definir.\n\nAinda assim, você pode fazer isso no **FastAPI**, usando uma das ferramentas internas do Starlette.\n\nE a documentação continuará funcionando, embora não adicione nenhuma informação dizendo que o parâmetro deve conter um path.\n\n### Conversor de path { #path-convertor }\n\nUsando uma opção diretamente do Starlette você pode declarar um *parâmetro de path* contendo um *path* usando uma URL como:\n\n```\n/files/{file_path:path}\n```\n\nNesse caso, o nome do parâmetro é `file_path`, e a última parte, `:path`, diz que o parâmetro deve corresponder a qualquer *path*.\n\nEntão, você pode usá-lo com:\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip | Dica\nVocê pode precisar que o parâmetro contenha `/home/johndoe/myfile.txt`, com uma barra inicial (`/`).\n\nNesse caso, a URL seria: `/files//home/johndoe/myfile.txt`, com uma barra dupla (`//`) entre `files` e `home`.\n///\n\n## Recapitulação { #recap }\n\nCom o **FastAPI**, ao usar declarações de tipo do Python curtas, intuitivas e padrão, você obtém:\n\n- Suporte no editor: verificações de erro, preenchimento automático, etc.\n- \"<dfn title=\"convertendo a string que vem de um request HTTP em dados Python\">parsing</dfn>\" de dados\n- Validação de dados\n- Anotação da API e documentação automática\n\nE você só precisa declará-los uma vez.\n\nEssa é provavelmente a principal vantagem visível do **FastAPI** em comparação com frameworks alternativos (além do desempenho bruto).\n"
  },
  {
    "path": "docs/pt/docs/tutorial/query-param-models.md",
    "content": "# Modelos de Parâmetros de Consulta { #query-parameter-models }\n\nSe você possui um grupo de **parâmetros de consultas** que são relacionados, você pode criar um **modelo Pydantic** para declará-los.\n\nIsso permitiria que você **reutilizasse o modelo** em **diversos lugares**, e também declarasse validações e metadados de todos os parâmetros de uma única vez. 😎\n\n/// note | Nota\n\nIsso é suportado desde o FastAPI versão `0.115.0`. 🤓\n\n///\n\n## Parâmetros de Consulta com um Modelo Pydantic { #query-parameters-with-a-pydantic-model }\n\nDeclare os **parâmetros de consulta** que você precisa em um **modelo Pydantic**, e então declare o parâmetro como `Query`:\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\nO **FastAPI** **extrairá** os dados para **cada campo** dos **parâmetros de consulta** presentes na requisição, e fornecerá o modelo Pydantic que você definiu.\n\n## Verifique a Documentação { #check-the-docs }\n\nVocê pode ver os parâmetros de consulta na IU da documentação em `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## Restrinja Parâmetros de Consulta Extras { #forbid-extra-query-parameters }\n\nEm alguns casos especiais (provavelmente não muito comuns), você queira **restringir** os parâmetros de consulta que deseja receber.\n\nVocê pode usar a configuração do modelo Pydantic para `forbid` qualquer campo `extra`:\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\nCaso um cliente tente enviar alguns dados **extras** nos **parâmetros de consulta**, eles receberão um retorno de **erro**.\n\nPor exemplo, se o cliente tentar enviar um parâmetro de consulta `tool` com o valor `plumbus`, como:\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\nEles receberão um retorno de **erro** informando-os que o parâmetro de consulta `tool` não é permitido:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## Resumo { #summary }\n\nVocê pode utilizar **modelos Pydantic** para declarar **parâmetros de consulta** no **FastAPI**. 😎\n\n/// tip | Dica\n\nAlerta de spoiler: você também pode utilizar modelos Pydantic para declarar cookies e cabeçalhos, mas você irá ler sobre isso mais a frente no tutorial. 🤫\n\n///\n"
  },
  {
    "path": "docs/pt/docs/tutorial/query-params-str-validations.md",
    "content": "# Parâmetros de consulta e validações de string { #query-parameters-and-string-validations }\n\nO **FastAPI** permite declarar informações adicionais e validações para os seus parâmetros.\n\nVamos usar esta aplicação como exemplo:\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\nO parâmetro de consulta `q` é do tipo `str | None`, isso significa que é do tipo `str`, mas também pode ser `None`, e de fato, o valor padrão é `None`, então o FastAPI saberá que não é obrigatório.\n\n/// note | Nota\n\nO FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`.\n\nTer `str | None` permitirá que seu editor lhe ofereça melhor suporte e detecte erros.\n\n///\n\n## Validação adicional { #additional-validation }\n\nVamos impor que, embora `q` seja opcional, sempre que for fornecido, seu comprimento não exceda 50 caracteres.\n\n### Importe `Query` e `Annotated` { #import-query-and-annotated }\n\nPara isso, primeiro importe:\n\n* `Query` de `fastapi`\n* `Annotated` de `typing`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info | Informação\n\nO FastAPI adicionou suporte a `Annotated` (e passou a recomendá-lo) na versão 0.95.0.\n\nSe você tiver uma versão mais antiga, teria erros ao tentar usar `Annotated`.\n\nCertifique-se de [Atualizar a versão do FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) para pelo menos 0.95.1 antes de usar `Annotated`.\n\n///\n\n## Use `Annotated` no tipo do parâmetro `q` { #use-annotated-in-the-type-for-the-q-parameter }\n\nLembra que eu disse antes que `Annotated` pode ser usado para adicionar metadados aos seus parâmetros na [Introdução aos tipos do Python](../python-types.md#type-hints-with-metadata-annotations)?\n\nAgora é a hora de usá-lo com FastAPI. 🚀\n\nTínhamos esta anotação de tipo:\n\n```Python\nq: str | None = None\n```\n\nO que faremos é envolver isso com `Annotated`, para que fique assim:\n\n```Python\nq: Annotated[str | None] = None\n```\n\nAmbas as versões significam a mesma coisa, `q` é um parâmetro que pode ser `str` ou `None`, e por padrão é `None`.\n\nAgora vamos pular para a parte divertida. 🎉\n\n## Adicione `Query` ao `Annotated` no parâmetro `q` { #add-query-to-annotated-in-the-q-parameter }\n\nAgora que temos esse `Annotated` onde podemos colocar mais informações (neste caso, uma validação adicional), adicione `Query` dentro de `Annotated` e defina o parâmetro `max_length` como `50`:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\nPerceba que o valor padrão continua sendo `None`, então o parâmetro ainda é opcional.\n\nMas agora, com `Query(max_length=50)` dentro de `Annotated`, estamos dizendo ao FastAPI que queremos validação adicional para este valor, queremos que tenha no máximo 50 caracteres. 😎\n\n/// tip | Dica\n\nAqui estamos usando `Query()` porque este é um parâmetro de consulta. Mais adiante veremos outros como `Path()`, `Body()`, `Header()` e `Cookie()`, que também aceitam os mesmos argumentos que `Query()`.\n\n///\n\nAgora o FastAPI vai:\n\n* Validar os dados garantindo que o comprimento máximo seja de 50 caracteres\n* Mostrar um erro claro para o cliente quando os dados não forem válidos\n* Documentar o parâmetro na operação de rota do esquema OpenAPI (então ele aparecerá na UI de docs automática)\n\n## Alternativa (antiga): `Query` como valor padrão { #alternative-old-query-as-the-default-value }\n\nVersões anteriores do FastAPI (antes de <dfn title=\"antes de 2023-03\">0.95.0</dfn>) exigiam que você usasse `Query` como valor padrão do seu parâmetro, em vez de colocá-lo em `Annotated`, há uma grande chance de você ver código usando isso por aí, então vou explicar.\n\n/// tip | Dica\n\nPara código novo e sempre que possível, use `Annotated` como explicado acima. Há múltiplas vantagens (explicadas abaixo) e nenhuma desvantagem. 🍰\n\n///\n\nÉ assim que você usaria `Query()` como valor padrão do parâmetro da sua função, definindo o parâmetro `max_length` como 50:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\nComo neste caso (sem usar `Annotated`) temos que substituir o valor padrão `None` na função por `Query()`, agora precisamos definir o valor padrão com o parâmetro `Query(default=None)`, ele serve ao mesmo propósito de definir esse valor padrão (pelo menos para o FastAPI).\n\nEntão:\n\n```Python\nq: str | None = Query(default=None)\n```\n\n...torna o parâmetro opcional, com um valor padrão de `None`, o mesmo que:\n\n\n```Python\nq: str | None = None\n```\n\nMas a versão com `Query` o declara explicitamente como sendo um parâmetro de consulta.\n\nEntão, podemos passar mais parâmetros para `Query`. Neste caso, o parâmetro `max_length` que se aplica a strings:\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\nIsso validará os dados, mostrará um erro claro quando os dados não forem válidos e documentará o parâmetro na operação de rota do esquema OpenAPI.\n\n### `Query` como valor padrão ou em `Annotated` { #query-as-the-default-value-or-in-annotated }\n\nTenha em mente que, ao usar `Query` dentro de `Annotated`, você não pode usar o parâmetro `default` de `Query`.\n\nEm vez disso, use o valor padrão real do parâmetro da função. Caso contrário, haveria inconsistência.\n\nPor exemplo, isto não é permitido:\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n...porque não está claro se o valor padrão deveria ser `\"rick\"` ou `\"morty\"`.\n\nEntão, você usaria (preferencialmente):\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n...ou em bases de código mais antigas você encontrará:\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### Vantagens de `Annotated` { #advantages-of-annotated }\n\nUsar `Annotated` é recomendado em vez do valor padrão nos parâmetros da função, é melhor por vários motivos. 🤓\n\nO valor padrão do parâmetro da função é o valor padrão real, isso é mais intuitivo com Python em geral. 😌\n\nVocê poderia chamar essa mesma função em outros lugares sem FastAPI, e ela funcionaria como esperado. Se houver um parâmetro obrigatório (sem valor padrão), seu editor vai avisar com um erro, e o Python também reclamará se você executá-la sem passar o parâmetro obrigatório.\n\nQuando você não usa `Annotated` e em vez disso usa o estilo de valor padrão (antigo), se você chamar essa função sem FastAPI em outros lugares, terá que lembrar de passar os argumentos para a função para que funcione corretamente, caso contrário os valores serão diferentes do esperado (por exemplo, `QueryInfo` ou algo parecido em vez de `str`). E seu editor não vai avisar, e o Python também não vai reclamar ao executar a função, apenas quando as operações internas falharem.\n\nComo `Annotated` pode ter mais de uma anotação de metadados, você agora pode até usar a mesma função com outras ferramentas, como o [Typer](https://typer.tiangolo.com/). 🚀\n\n## Adicione mais validações { #add-more-validations }\n\nVocê também pode adicionar um parâmetro `min_length`:\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## Adicione expressões regulares { #add-regular-expressions }\n\nVocê pode definir um `pattern` de <dfn title=\"Uma expressão regular (regex ou regexp) é uma sequência de caracteres que define um padrão de busca para strings.\">expressão regular</dfn> que o parâmetro deve corresponder:\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\nEsse padrão específico de expressão regular verifica se o valor recebido no parâmetro:\n\n* `^`: começa com os caracteres seguintes, não tem caracteres antes.\n* `fixedquery`: tem exatamente o valor `fixedquery`.\n* `$`: termina ali, não tem mais caracteres depois de `fixedquery`.\n\nSe você se sentir perdido com essas ideias de \"expressão regular\", não se preocupe. Esse é um assunto difícil para muitas pessoas. Você ainda pode fazer muitas coisas sem precisar de expressões regulares por enquanto.\n\nAgora você sabe que, sempre que precisar delas, pode usá-las no FastAPI.\n\n## Valores padrão { #default-values }\n\nVocê pode, claro, usar valores padrão diferentes de `None`.\n\nDigamos que você queira declarar o parâmetro de consulta `q` com `min_length` de `3` e ter um valor padrão de `\"fixedquery\"`:\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | Nota\n\nTer um valor padrão de qualquer tipo, incluindo `None`, torna o parâmetro opcional (não obrigatório).\n\n///\n\n## Parâmetros obrigatórios { #required-parameters }\n\nQuando não precisamos declarar mais validações ou metadados, podemos tornar o parâmetro de consulta `q` obrigatório simplesmente não declarando um valor padrão, assim:\n\n```Python\nq: str\n```\n\nem vez de:\n\n```Python\nq: str | None = None\n```\n\nMas agora estamos declarando com `Query`, por exemplo assim:\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\nEntão, quando você precisa declarar um valor como obrigatório usando `Query`, você pode simplesmente não declarar um valor padrão:\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### Obrigatório, pode ser `None` { #required-can-be-none }\n\nVocê pode declarar que um parâmetro pode aceitar `None`, mas que ainda assim é obrigatório. Isso forçaria os clientes a enviarem um valor, mesmo que o valor seja `None`.\n\nPara isso, você pode declarar que `None` é um tipo válido, mas simplesmente não declarar um valor padrão:\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## Lista de parâmetros de consulta / múltiplos valores { #query-parameter-list-multiple-values }\n\nQuando você define explicitamente um parâmetro de consulta com `Query`, você também pode declará-lo para receber uma lista de valores, ou seja, receber múltiplos valores.\n\nPor exemplo, para declarar um parâmetro de consulta `q` que pode aparecer várias vezes na URL, você pode escrever:\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\nEntão, com uma URL como:\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\nvocê receberia os múltiplos valores dos parâmetros de consulta `q` (`foo` e `bar`) em uma `list` Python dentro da sua função de operação de rota, no parâmetro da função `q`.\n\nAssim, a resposta para essa URL seria:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | Dica\n\nPara declarar um parâmetro de consulta com tipo `list`, como no exemplo acima, você precisa usar explicitamente `Query`, caso contrário seria interpretado como um corpo da requisição.\n\n///\n\nA documentação interativa da API será atualizada de acordo, permitindo múltiplos valores:\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### Lista de parâmetros de consulta / múltiplos valores com valores padrão { #query-parameter-list-multiple-values-with-defaults }\n\nVocê também pode definir uma `list` de valores padrão caso nenhum seja fornecido:\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\nSe você for até:\n\n```\nhttp://localhost:8000/items/\n```\n\no valor padrão de `q` será: `[\"foo\", \"bar\"]` e sua resposta será:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### Usando apenas `list` { #using-just-list }\n\nVocê também pode usar `list` diretamente em vez de `list[str]`:\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | Nota\n\nTenha em mente que, neste caso, o FastAPI não verificará o conteúdo da lista.\n\nPor exemplo, `list[int]` verificaria (and documentaria) que os conteúdos da lista são inteiros. Mas `list` sozinho não.\n\n///\n\n## Declare mais metadados { #declare-more-metadata }\n\nVocê pode adicionar mais informações sobre o parâmetro.\n\nEssas informações serão incluídas no OpenAPI gerado e usadas pelas interfaces de documentação e por ferramentas externas.\n\n/// note | Nota\n\nTenha em mente que ferramentas diferentes podem ter níveis diferentes de suporte ao OpenAPI.\n\nAlgumas delas podem ainda não mostrar todas as informações extras declaradas, embora na maioria dos casos a funcionalidade ausente já esteja planejada para desenvolvimento.\n\n///\n\nVocê pode adicionar um `title`:\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\nE uma `description`:\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## Parâmetros com alias { #alias-parameters }\n\nImagine que você queira que o parâmetro seja `item-query`.\n\nAssim:\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\nMas `item-query` não é um nome de variável Python válido.\n\nO mais próximo seria `item_query`.\n\nMas você ainda precisa que seja exatamente `item-query`...\n\nEntão você pode declarar um `alias`, e esse alias será usado para encontrar o valor do parâmetro:\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## Descontinuando parâmetros { #deprecating-parameters }\n\nAgora digamos que você não gosta mais desse parâmetro.\n\nVocê tem que deixá-lo por um tempo, pois há clientes usando-o, mas quer que a documentação mostre claramente que ele está <dfn title=\"obsoleto, recomenda-se não usá-lo\">descontinuado</dfn>.\n\nEntão passe o parâmetro `deprecated=True` para `Query`:\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\nA documentação vai mostrar assim:\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## Excluir parâmetros do OpenAPI { #exclude-parameters-from-openapi }\n\nPara excluir um parâmetro de consulta do OpenAPI gerado (e portanto, dos sistemas de documentação automáticos), defina o parâmetro `include_in_schema` de `Query` como `False`:\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## Validação personalizada { #custom-validation }\n\nPodem existir casos em que você precise fazer alguma validação personalizada que não pode ser feita com os parâmetros mostrados acima.\n\nNesses casos, você pode usar uma função validadora personalizada que é aplicada após a validação normal (por exemplo, depois de validar que o valor é uma `str`).\n\nVocê pode fazer isso usando o [`AfterValidator` do Pydantic](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) dentro de `Annotated`.\n\n/// tip | Dica\n\nO Pydantic também tem [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) e outros. 🤓\n\n///\n\nPor exemplo, este validador personalizado verifica se o ID do item começa com `isbn-` para um número de livro <abbr title=\"International Standard Book Number - Número Padrão Internacional de Livro\">ISBN</abbr> ou com `imdb-` para um ID de URL de filme <abbr title=\"Internet Movie Database - Base de Dados de Filmes da Internet: um site com informações sobre filmes\">IMDB</abbr>:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info | Informação\n\nIsso está disponível com a versão 2 do Pydantic ou superior. 😎\n\n///\n\n/// tip | Dica\n\nSe você precisar fazer qualquer tipo de validação que exija comunicação com algum componente externo, como um banco de dados ou outra API, você deveria usar Dependências do FastAPI em vez disso; você aprenderá sobre elas mais adiante.\n\nEsses validadores personalizados são para coisas que podem ser verificadas apenas com os mesmos dados fornecidos na requisição.\n\n///\n\n### Entenda esse código { #understand-that-code }\n\nO ponto importante é apenas usar `AfterValidator` com uma função dentro de `Annotated`. Sinta-se à vontade para pular esta parte. 🤸\n\n---\n\nMas se você estiver curioso sobre este exemplo de código específico e ainda entretido, aqui vão alguns detalhes extras.\n\n#### String com `value.startswith()` { #string-with-value-startswith }\n\nPercebeu? Uma string usando `value.startswith()` pode receber uma tupla, e verificará cada valor na tupla:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### Um item aleatório { #a-random-item }\n\nCom `data.items()` obtemos um <dfn title=\"Algo que podemos iterar com um laço for, como uma list, set, etc.\">objeto iterável</dfn> com tuplas contendo a chave e o valor de cada item do dicionário.\n\nConvertimos esse objeto iterável em uma `list` adequada com `list(data.items())`.\n\nEm seguida, com `random.choice()` podemos obter um valor aleatório da lista, então obtemos uma tupla com `(id, name)`. Será algo como `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")`.\n\nDepois atribuímos esses dois valores da tupla às variáveis `id` e `name`.\n\nAssim, se o usuário não fornecer um ID de item, ele ainda receberá uma sugestão aleatória.\n\n...fazemos tudo isso em uma única linha simples. 🤯 Você não ama Python? 🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## Recapitulando { #recap }\n\nVocê pode declarar validações adicionais e metadados para seus parâmetros.\n\nValidações e metadados genéricos:\n\n* `alias`\n* `title`\n* `description`\n* `deprecated`\n\nValidações específicas para strings:\n\n* `min_length`\n* `max_length`\n* `pattern`\n\nValidações personalizadas usando `AfterValidator`.\n\nNestes exemplos você viu como declarar validações para valores `str`.\n\nVeja os próximos capítulos para aprender a declarar validações para outros tipos, como números.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/query-params.md",
    "content": "# Parâmetros de Consulta { #query-parameters }\n\nQuando você declara outros parâmetros na função que não fazem parte dos parâmetros da rota, esses parâmetros são automaticamente interpretados como parâmetros de \"consulta\".\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\nA consulta é o conjunto de pares chave-valor que vai depois de `?` na URL, separado pelo caractere `&`.\n\nPor exemplo, na URL:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n...os parâmetros da consulta são:\n\n* `skip`: com o valor `0`\n* `limit`: com o valor `10`\n\nComo eles são parte da URL, eles são \"naturalmente\" strings.\n\nMas quando você declara eles com os tipos do Python (no exemplo acima, como `int`), eles são convertidos para aquele tipo e validados em relação a ele.\n\nTodo o processo que era aplicado para parâmetros de rota também é aplicado para parâmetros de consulta:\n\n* Suporte do editor (obviamente)\n* <dfn title=\"convertendo a string que vem de um request HTTP em dados Python\">\"análise\"</dfn> de dados\n* Validação de dados\n* Documentação automática\n\n## Valores padrão { #defaults }\n\nComo os parâmetros de consulta não são uma parte fixa da rota, eles podem ser opcionais e podem ter valores padrão.\n\nNo exemplo acima eles tem valores padrão de `skip=0` e `limit=10`.\n\nEntão, se você for até a URL:\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\nSeria o mesmo que ir para:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\nMas, se por exemplo você for para:\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\nOs valores dos parâmetros na sua função serão:\n\n* `skip=20`: Por que você definiu isso na URL\n* `limit=10`: Por que esse era o valor padrão\n\n## Parâmetros opcionais { #optional-parameters }\n\nDa mesma forma, você pode declarar parâmetros de consulta opcionais, definindo o valor padrão para `None`:\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\nNesse caso, o parâmetro da função `q` será opcional, e `None` será o padrão.\n\n/// check | Verifique\n\nVocê também pode notar que o **FastAPI** é esperto o suficiente para perceber que o parâmetro da rota `item_id` é um parâmetro da rota, e `q` não é, portanto, `q` é o parâmetro de consulta.\n\n///\n\n## Conversão dos tipos de parâmetros de consulta { #query-parameter-type-conversion }\n\nVocê também pode declarar tipos `bool`, e eles serão convertidos:\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\nNesse caso, se você for para:\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\nou\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\nou\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\nou\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\nou\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\nou qualquer outra variação (tudo em maiúscula, primeira letra em maiúscula, etc), a sua função vai ver o parâmetro `short` com um valor `bool` de `True`. Caso contrário `False`.\n\n## Múltiplos parâmetros de rota e consulta { #multiple-path-and-query-parameters }\n\nVocê pode declarar múltiplos parâmetros de rota e parâmetros de consulta ao mesmo tempo, o **FastAPI** vai saber o quê é o quê.\n\nE você não precisa declarar eles em nenhuma ordem específica.\n\nEles serão detectados pelo nome:\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## Parâmetros de consulta obrigatórios { #required-query-parameters }\n\nQuando você declara um valor padrão para parâmetros que não são de rota (até agora, nós vimos apenas parâmetros de consulta), então eles não são obrigatórios.\n\nCaso você não queira adicionar um valor específico mas queira apenas torná-lo opcional, defina o valor padrão como `None`.\n\nPorém, quando você quiser fazer com que o parâmetro de consulta seja obrigatório, você pode simplesmente não declarar nenhum valor como padrão.\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\nAqui o parâmetro da consulta `needy` é um valor obrigatório, do tipo `str`.\n\nSe você abrir no seu navegador a URL:\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n... sem adicionar o parâmetro obrigatório `needy`, você verá um erro como:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\nComo `needy` é um parâmetro obrigatório, você precisaria defini-lo na URL:\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n...isso deve funcionar:\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\nE claro, você pode definir alguns parâmetros como obrigatórios, alguns possuindo um valor padrão, e outros sendo totalmente opcionais:\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\nNesse caso, existem 3 parâmetros de consulta:\n\n* `needy`, um `str` obrigatório.\n* `skip`, um `int` com o valor padrão `0`.\n* `limit`, um `int` opcional.\n\n/// tip | Dica\n\nVocê também poderia usar `Enum`s da mesma forma que com [Parâmetros de rota](path-params.md#predefined-values).\n\n///\n"
  },
  {
    "path": "docs/pt/docs/tutorial/request-files.md",
    "content": "# Arquivos de Requisição { #request-files }\n\nVocê pode definir arquivos para serem enviados pelo cliente usando `File`.\n\n/// info | Informação\n\nPara receber arquivos enviados, primeiro instale [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nGaranta que você criou um [ambiente virtual](../virtual-environments.md), o ativou e então o instalou, por exemplo:\n\n```console\n$ pip install python-multipart\n```\n\nIsso é necessário, visto que os arquivos enviados são enviados como \"dados de formulário\".\n\n///\n\n## Importe `File` { #import-file }\n\nImporte `File` e `UploadFile` de `fastapi`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## Definir Parâmetros `File` { #define-file-parameters }\n\nCrie parâmetros de arquivo da mesma forma que você faria para `Body` ou `Form`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info | Informação\n\n`File` é uma classe que herda diretamente de `Form`.\n\nMas lembre-se que quando você importa `Query`, `Path`, `File` e outros de `fastapi`, eles são, na verdade, funções que retornam classes especiais.\n\n///\n\n/// tip | Dica\n\nPara declarar corpos de arquivos, você precisa usar `File`, caso contrário, os parâmetros seriam interpretados como parâmetros de consulta ou parâmetros de corpo (JSON).\n\n///\n\nOs arquivos serão enviados como \"dados de formulário\".\n\nSe você declarar o tipo do parâmetro da função da sua *operação de rota* como `bytes`, o **FastAPI** lerá o arquivo para você e você receberá o conteúdo como `bytes`.\n\nMantenha em mente que isso significa que todo o conteúdo será armazenado na memória. Isso funcionará bem para arquivos pequenos.\n\nMas há muitos casos em que você pode se beneficiar do uso de `UploadFile`.\n\n## Parâmetros de Arquivo com `UploadFile` { #file-parameters-with-uploadfile }\n\nDefina um parâmetro de arquivo com um tipo de `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\nUtilizar `UploadFile` tem várias vantagens sobre `bytes`:\n\n* Você não precisa utilizar o `File()` no valor padrão do parâmetro.\n* Ele utiliza um arquivo \"spooled\":\n    * Um arquivo armazenado na memória até um limite máximo de tamanho, e após passar esse limite, ele será armazenado no disco.\n* Isso significa que funcionará bem para arquivos grandes como imagens, vídeos, binários grandes, etc., sem consumir toda a memória.\n* Você pode receber metadados do arquivo enviado.\n* Ele tem uma [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) interface `assíncrona`.\n* Ele expõe um objeto python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) que você pode passar diretamente para outras bibliotecas que esperam um objeto semelhante a um arquivo.\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` tem os seguintes atributos:\n\n* `filename`: Uma `str` com o nome do arquivo original que foi enviado (por exemplo, `myimage.jpg`).\n* `content_type`: Uma `str` com o tipo de conteúdo (MIME type / media type) (por exemplo, `image/jpeg`).\n* `file`: Um [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (um [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) objeto). Este é o objeto de arquivo Python que você pode passar diretamente para outras funções ou bibliotecas que esperam um objeto semelhante a um arquivo.\n\n`UploadFile` tem os seguintes métodos `assíncronos`. Todos eles chamam os métodos de arquivo correspondentes por baixo dos panos (usando o `SpooledTemporaryFile` interno).\n\n* `write(data)`: Escreve `data` (`str` ou `bytes`) no arquivo.\n* `read(size)`: Lê `size` (`int`) bytes/caracteres do arquivo.\n* `seek(offset)`: Vai para o byte na posição `offset` (`int`) no arquivo.\n    * Por exemplo, `await myfile.seek(0)` irá para o início do arquivo.\n    * Isso é especialmente útil se você executar `await myfile.read()` uma vez e precisar ler o conteúdo novamente.\n* `close()`: Fecha o arquivo.\n\nComo todos esses métodos são métodos `assíncronos`, você precisa \"aguardar\" por eles.\n\nPor exemplo, dentro de uma função de *operação de rota* `assíncrona`, você pode obter o conteúdo com:\n\n```Python\ncontents = await myfile.read()\n```\n\nSe você estiver dentro de uma função de *operação de rota* normal `def`, você pode acessar o `UploadFile.file` diretamente, por exemplo:\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | Detalhes Técnicos do `async`\n\nQuando você usa os métodos `async`, o **FastAPI** executa os métodos de arquivo em um threadpool e aguarda por eles.\n\n///\n\n/// note | Detalhes Técnicos do Starlette\n\nO `UploadFile` do **FastAPI** herda diretamente do `UploadFile` do **Starlette**, mas adiciona algumas partes necessárias para torná-lo compatível com o **Pydantic** e as outras partes do FastAPI.\n\n///\n\n## O que é \"Form Data\" { #what-is-form-data }\n\nO jeito que os formulários HTML (`<form></form>`) enviam os dados para o servidor normalmente usa uma codificação \"especial\" para esses dados, a qual é diferente do JSON.\n\n**FastAPI** se certificará de ler esses dados do lugar certo, ao invés de JSON.\n\n/// note | Detalhes Técnicos\n\nDados de formulários normalmente são codificados usando o \"media type\" `application/x-www-form-urlencoded` quando não incluem arquivos.\n\nMas quando o formulário inclui arquivos, ele é codificado como `multipart/form-data`. Se você usar `File`, o **FastAPI** saberá que tem que pegar os arquivos da parte correta do corpo da requisição.\n\nSe você quiser ler mais sobre essas codificações e campos de formulário, vá para a [<abbr title=\"Mozilla Developer Network - Rede de Desenvolvedores da Mozilla\">MDN</abbr> web docs para `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Atenção\n\nVocê pode declarar múltiplos parâmetros `File` e `Form` em uma *operação de rota*, mas você não pode declarar campos `Body` que você espera receber como JSON, pois a requisição terá o corpo codificado usando `multipart/form-data` ao invés de `application/json`.\n\nIsso não é uma limitação do **FastAPI**, é parte do protocolo HTTP.\n\n///\n\n## Upload de Arquivo Opcional { #optional-file-upload }\n\nVocê pode tornar um arquivo opcional usando anotações de tipo padrão e definindo um valor padrão de `None`:\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## `UploadFile` com Metadados Adicionais { #uploadfile-with-additional-metadata }\n\nVocê também pode usar `File()` com `UploadFile`, por exemplo, para definir metadados adicionais:\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## Uploads de Múltiplos Arquivos { #multiple-file-uploads }\n\nÉ possível realizar o upload de vários arquivos ao mesmo tempo.\n\nEles serão associados ao mesmo \"campo de formulário\" enviado usando \"dados de formulário\".\n\nPara usar isso, declare uma lista de `bytes` ou `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\nVocê receberá, tal como declarado, uma `list` de `bytes` ou `UploadFile`.\n\n/// note | Detalhes Técnicos\n\nVocê também pode usar `from starlette.responses import HTMLResponse`.\n\n**FastAPI** providencia o mesmo `starlette.responses` que `fastapi.responses` apenas como uma conveniência para você, o desenvolvedor. Mas a maioria das respostas disponíveis vem diretamente do Starlette.\n\n///\n\n### Uploads de Múltiplos Arquivos com Metadados Adicionais { #multiple-file-uploads-with-additional-metadata }\n\nDa mesma forma de antes, você pode usar `File()` para definir parâmetros adicionais, mesmo para `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## Recapitulando { #recap }\n\nUtilize `File`, `bytes` e `UploadFile` para declarar arquivos a serem enviados na requisição, enviados como dados de formulário.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/request-form-models.md",
    "content": "# Modelos de Formulários { #form-models }\n\nVocê pode utilizar **Modelos Pydantic** para declarar **campos de formulários** no FastAPI.\n\n/// info | Informação\n\nPara utilizar formulários, instale primeiramente o [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nCertifique-se de criar um [ambiente virtual](../virtual-environments.md), ativá-lo, e então instalar. Por exemplo:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note | Nota\n\nIsto é suportado desde a versão `0.113.0` do FastAPI. 🤓\n\n///\n\n## Modelos Pydantic para Formulários { #pydantic-models-for-forms }\n\nVocê precisa apenas declarar um **modelo Pydantic** com os campos que deseja receber como **campos de formulários**, e então declarar o parâmetro como um `Form`:\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\nO **FastAPI** irá **extrair** as informações para **cada campo** dos **dados do formulário** na requisição e dar para você o modelo Pydantic que você definiu.\n\n## Confira os Documentos { #check-the-docs }\n\nVocê pode verificar na UI de documentação em `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## Proibir Campos Extras de Formulários { #forbid-extra-form-fields }\n\nEm alguns casos de uso especiais (provavelmente não muito comum), você pode desejar **restringir** os campos do formulário para aceitar apenas os declarados no modelo Pydantic. E **proibir** qualquer campo **extra**.\n\n/// note | Nota\n\nIsso é suportado desde a versão `0.114.0` do FastAPI. 🤓\n\n///\n\nVocê pode utilizar a configuração de modelo do Pydantic para `proibir` qualquer campo `extra`:\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\nCaso um cliente tente enviar informações adicionais, ele receberá um retorno de **erro**.\n\nPor exemplo, se o cliente tentar enviar os campos de formulário:\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\nEle receberá um retorno de erro informando-o que o campo `extra` não é permitido:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## Resumo { #summary }\n\nVocê pode utilizar modelos Pydantic para declarar campos de formulários no FastAPI. 😎\n"
  },
  {
    "path": "docs/pt/docs/tutorial/request-forms-and-files.md",
    "content": "# Formulários e Arquivos da Requisição { #request-forms-and-files }\n\nVocê pode definir arquivos e campos de formulário ao mesmo tempo usando `File` e `Form`.\n\n/// info | Informação\n\nPara receber arquivos carregados e/ou dados de formulário, primeiro instale [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nCertifique-se de criar um [ambiente virtual](../virtual-environments.md), ativá-lo e então instalar, por exemplo:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Importe `File` e `Form` { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## Defina parâmetros de `File` e `Form` { #define-file-and-form-parameters }\n\nCrie parâmetros de arquivo e formulário da mesma forma que você faria para `Body` ou `Query`:\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\nOs arquivos e campos de formulário serão carregados como dados de formulário e você receberá os arquivos e campos de formulário.\n\nE você pode declarar alguns dos arquivos como `bytes` e alguns como `UploadFile`.\n\n/// warning | Atenção\n\nVocê pode declarar vários parâmetros `File` e `Form` em uma *operação de rota*, mas não é possível declarar campos `Body` para receber como JSON, pois a requisição terá o corpo codificado usando `multipart/form-data` ao invés de `application/json`.\n\nIsso não é uma limitação do **FastAPI**, é parte do protocolo HTTP.\n\n///\n\n## Recapitulando { #recap }\n\nUse `File` e `Form` juntos quando precisar receber dados e arquivos na mesma requisição.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/request-forms.md",
    "content": "# Dados do formulário { #form-data }\n\nQuando você precisar receber campos de formulário em vez de JSON, você pode usar `Form`.\n\n/// info | Informação\n\nPara usar formulários, primeiro instale [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nCertifique-se de criar um [ambiente virtual](../virtual-environments.md), ativá-lo e então instalá-lo, por exemplo:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Importe `Form` { #import-form }\n\nImporte `Form` de `fastapi`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## Defina parâmetros de `Form` { #define-form-parameters }\n\nCrie parâmetros de formulário da mesma forma que você faria para `Body` ou `Query`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\nPor exemplo, em uma das maneiras que a especificação OAuth2 pode ser usada (chamada \"fluxo de senha\"), é necessário enviar um `username` e uma `password` como campos do formulário.\n\nA <dfn title=\"especificação\">especificação</dfn> exige que os campos sejam exatamente nomeados como `username` e `password` e sejam enviados como campos de formulário, não JSON.\n\nCom `Form` você pode declarar as mesmas configurações que com `Body` (e `Query`, `Path`, `Cookie`), incluindo validação, exemplos, um alias (por exemplo, `user-name` em vez de `username`), etc.\n\n/// info | Informação\n\n`Form` é uma classe que herda diretamente de `Body`.\n\n///\n\n/// tip | Dica\n\nPara declarar corpos de formulário, você precisa usar `Form` explicitamente, porque sem ele os parâmetros seriam interpretados como parâmetros de consulta ou parâmetros de corpo (JSON).\n\n///\n\n## Sobre \"Campos de formulário\" { #about-form-fields }\n\nA forma como os formulários HTML (`<form></form>`) enviam os dados para o servidor normalmente usa uma codificação \"especial\" para esses dados, é diferente do JSON.\n\nO **FastAPI** fará a leitura desses dados no lugar certo em vez de JSON.\n\n/// note | Detalhes Técnicos\n\nOs dados dos formulários são normalmente codificados usando o \"media type\" `application/x-www-form-urlencoded`.\n\nMas quando o formulário inclui arquivos, ele é codificado como `multipart/form-data`. Você lerá sobre como lidar com arquivos no próximo capítulo.\n\nSe você quiser ler mais sobre essas codificações e campos de formulário, vá para o [<abbr title=\"Mozilla Developer Network - Rede de Desenvolvedores da Mozilla\">MDN</abbr> web docs para `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Atenção\n\nVocê pode declarar vários parâmetros `Form` em uma *operação de rota*, mas não pode declarar campos `Body` que espera receber como JSON, pois a requisição terá o corpo codificado usando `application/x-www-form-urlencoded` em vez de `application/json`.\n\nIsso não é uma limitação do **FastAPI**, é parte do protocolo HTTP.\n\n///\n\n## Recapitulando { #recap }\n\nUse `Form` para declarar os parâmetros de entrada de dados de formulário.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/response-model.md",
    "content": "# Modelo de resposta - Tipo de retorno { #response-model-return-type }\n\nVocê pode declarar o tipo usado para a resposta anotando o **tipo de retorno** da *função de operação de rota*.\n\nVocê pode usar **anotações de tipo** da mesma forma que usaria para dados de entrada em **parâmetros** de função, você pode usar modelos Pydantic, listas, dicionários, valores escalares como inteiros, booleanos, etc.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nO FastAPI usará este tipo de retorno para:\n\n* **Validar** os dados retornados.\n    * Se os dados forem inválidos (por exemplo, se estiver faltando um campo), significa que o código do *seu* aplicativo está quebrado, não retornando o que deveria, e retornará um erro de servidor em vez de retornar dados incorretos. Dessa forma, você e seus clientes podem ter certeza de que receberão os dados e o formato de dados esperados.\n* Adicionar um **JSON Schema** para a resposta, na *operação de rota* do OpenAPI.\n    * Isso será usado pela **documentação automática**.\n    * Também será usado por ferramentas de geração automática de código do cliente.\n* **Serializar** os dados retornados para JSON usando Pydantic, que é escrito em **Rust**, então será **muito mais rápido**.\n\nMas o mais importante:\n\n* Ele **limitará e filtrará** os dados de saída para o que está definido no tipo de retorno.\n    * Isso é particularmente importante para a **segurança**, veremos mais sobre isso abaixo.\n\n## Parâmetro `response_model` { #response-model-parameter }\n\nExistem alguns casos em que você precisa ou deseja retornar alguns dados que não são exatamente o que o tipo declara.\n\nPor exemplo, você pode querer **retornar um dicionário** ou um objeto de banco de dados, mas **declará-lo como um modelo Pydantic**. Dessa forma, o modelo Pydantic faria toda a documentação de dados, validação, etc. para o objeto que você retornou (por exemplo, um dicionário ou objeto de banco de dados).\n\nSe você adicionasse a anotação do tipo de retorno, ferramentas e editores reclamariam com um erro (correto) informando que sua função está retornando um tipo (por exemplo, um dict) diferente do que você declarou (por exemplo, um modelo Pydantic).\n\nNesses casos, você pode usar o parâmetro `response_model` do *decorador de operação de rota* em vez do tipo de retorno.\n\nVocê pode usar o parâmetro `response_model` em qualquer uma das *operações de rota*:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* etc.\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | Nota\n\nObserve que `response_model` é um parâmetro do método \"decorator\" (`get`, `post`, etc). Não da sua *função de operação de rota*, como todos os parâmetros e corpo.\n\n///\n\n`response_model` recebe o mesmo tipo que você declararia para um campo de modelo Pydantic, então, pode ser um modelo Pydantic, mas também pode ser, por exemplo, uma `list` de modelos Pydantic, como `List[Item]`.\n\nO FastAPI usará este `response_model` para fazer toda a documentação de dados, validação, etc. e também para **converter e filtrar os dados de saída** para sua declaração de tipo.\n\n/// tip | Dica\n\nSe você tiver verificações de tipo rigorosas em seu editor, mypy, etc, você pode declarar o tipo de retorno da função como `Any`.\n\nDessa forma, você diz ao editor que está retornando qualquer coisa intencionalmente. Mas o FastAPI ainda fará a documentação de dados, validação, filtragem, etc. com o `response_model`.\n\n///\n\n### Prioridade `response_model` { #response-model-priority }\n\nSe você declarar tanto um tipo de retorno quanto um `response_model`, o `response_model` terá prioridade e será usado pelo FastAPI.\n\nDessa forma, você pode adicionar anotações de tipo corretas às suas funções, mesmo quando estiver retornando um tipo diferente do modelo de resposta, para ser usado pelo editor e ferramentas como mypy. E ainda assim você pode fazer com que o FastAPI faça a validação de dados, documentação, etc. usando o `response_model`.\n\nVocê também pode usar `response_model=None` para desabilitar a criação de um modelo de resposta para essa *operação de rota*, você pode precisar fazer isso se estiver adicionando anotações de tipo para coisas que não são campos Pydantic válidos, você verá um exemplo disso em uma das seções abaixo.\n\n## Retorne os mesmos dados de entrada { #return-the-same-input-data }\n\nAqui estamos declarando um modelo `UserIn`, ele conterá uma senha em texto simples:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | Informação\n\nPara usar `EmailStr`, primeiro instale [`email-validator`](https://github.com/JoshData/python-email-validator).\n\nCertifique-se de criar um [ambiente virtual](../virtual-environments.md), ative-o e então instale-o, por exemplo:\n\n```console\n$ pip install email-validator\n```\n\nou com:\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\nE estamos usando este modelo para declarar nossa entrada e o mesmo modelo para declarar nossa saída:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\nAgora, sempre que um navegador estiver criando um usuário com uma senha, a API retornará a mesma senha na resposta.\n\nNeste caso, pode não ser um problema, porque é o mesmo usuário enviando a senha.\n\nMas se usarmos o mesmo modelo para outra *operação de rota*, poderíamos estar enviando as senhas dos nossos usuários para todos os clientes.\n\n/// danger | Cuidado\n\nNunca armazene a senha simples de um usuário ou envie-a em uma resposta como esta, a menos que você saiba todas as ressalvas e saiba o que está fazendo.\n\n///\n\n## Adicione um modelo de saída { #add-an-output-model }\n\nPodemos, em vez disso, criar um modelo de entrada com a senha em texto simples e um modelo de saída sem ela:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\nAqui, embora nossa *função de operação de rota* esteja retornando o mesmo usuário de entrada que contém a senha:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n...declaramos o `response_model` como nosso modelo `UserOut`, que não inclui a senha:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\nEntão, **FastAPI** cuidará de filtrar todos os dados que não são declarados no modelo de saída (usando Pydantic).\n\n### `response_model` ou Tipo de Retorno { #response-model-or-return-type }\n\nNeste caso, como os dois modelos são diferentes, se anotássemos o tipo de retorno da função como `UserOut`, o editor e as ferramentas reclamariam que estamos retornando um tipo inválido, pois são classes diferentes.\n\nÉ por isso que neste exemplo temos que declará-lo no parâmetro `response_model`.\n\n...mas continue lendo abaixo para ver como superar isso.\n\n## Tipo de Retorno e Filtragem de Dados { #return-type-and-data-filtering }\n\nVamos continuar do exemplo anterior. Queríamos **anotar a função com um tipo**, mas queríamos poder retornar da função algo que realmente incluísse **mais dados**.\n\nQueremos que o FastAPI continue **filtrando** os dados usando o modelo de resposta. Para que, embora a função retorne mais dados, a resposta inclua apenas os campos declarados no modelo de resposta.\n\nNo exemplo anterior, como as classes eram diferentes, tivemos que usar o parâmetro `response_model`. Mas isso também significa que não temos suporte do editor e das ferramentas verificando o tipo de retorno da função.\n\nMas na maioria dos casos em que precisamos fazer algo assim, queremos que o modelo apenas **filtre/remova** alguns dados como neste exemplo.\n\nE nesses casos, podemos usar classes e herança para aproveitar as **anotações de tipo** de função para obter melhor suporte no editor e nas ferramentas, e ainda obter a **filtragem de dados** FastAPI.\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\nCom isso, temos suporte de ferramentas, de editores e mypy, pois este código está correto em termos de tipos, mas também obtemos a filtragem de dados do FastAPI.\n\nComo isso funciona? Vamos verificar. 🤓\n\n### Anotações de tipo e ferramentas { #type-annotations-and-tooling }\n\nPrimeiro, vamos ver como editores, mypy e outras ferramentas veriam isso.\n\n`BaseUser` tem os campos base. Então `UserIn` herda de `BaseUser` e adiciona o campo `password`, então, ele incluirá todos os campos de ambos os modelos.\n\nAnotamos o tipo de retorno da função como `BaseUser`, mas na verdade estamos retornando uma instância `UserIn`.\n\nO editor, mypy e outras ferramentas não reclamarão disso porque, em termos de digitação, `UserIn` é uma subclasse de `BaseUser`, o que significa que é um tipo *válido* quando o que é esperado é qualquer coisa que seja um `BaseUser`.\n\n### Filtragem de dados FastAPI { #fastapi-data-filtering }\n\nAgora, para FastAPI, ele verá o tipo de retorno e garantirá que o que você retornar inclua **apenas** os campos que são declarados no tipo.\n\nO FastAPI faz várias coisas internamente com o Pydantic para garantir que essas mesmas regras de herança de classe não sejam usadas para a filtragem de dados retornados, caso contrário, você pode acabar retornando muito mais dados do que o esperado.\n\nDessa forma, você pode obter o melhor dos dois mundos: anotações de tipo com **suporte a ferramentas** e **filtragem de dados**.\n\n## Veja na documentação { #see-it-in-the-docs }\n\nQuando você vê a documentação automática, pode verificar se o modelo de entrada e o modelo de saída terão seus próprios esquemas JSON:\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\nE ambos os modelos serão usados ​​para a documentação interativa da API:\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## Outras anotações de tipo de retorno { #other-return-type-annotations }\n\nPode haver casos em que você retorna algo que não é um campo Pydantic válido e anota na função, apenas para obter o suporte fornecido pelas ferramentas (o editor, mypy, etc).\n\n### Retorne uma Response diretamente { #return-a-response-directly }\n\nO caso mais comum seria [retornar uma Response diretamente, conforme explicado posteriormente na documentação avançada](../advanced/response-directly.md).\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\nEste caso simples é tratado automaticamente pelo FastAPI porque a anotação do tipo de retorno é a classe (ou uma subclasse de) `Response`.\n\nE as ferramentas também ficarão felizes porque `RedirectResponse` e ​​`JSONResponse` são subclasses de `Response`, então a anotação de tipo está correta.\n\n### Anote uma subclasse de Response { #annotate-a-response-subclass }\n\nVocê também pode usar uma subclasse de `Response` na anotação de tipo:\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\nIsso também funcionará porque `RedirectResponse` é uma subclasse de `Response`, e o FastAPI tratará automaticamente este caso simples.\n\n### Anotações de Tipo de Retorno Inválido { #invalid-return-type-annotations }\n\nMas quando você retorna algum outro objeto arbitrário que não é um tipo Pydantic válido (por exemplo, um objeto de banco de dados) e você o anota dessa forma na função, o FastAPI tentará criar um modelo de resposta Pydantic a partir dessa anotação de tipo e falhará.\n\nO mesmo aconteceria se você tivesse algo como uma <dfn title=\"uma união entre vários tipos significa 'qualquer um desses tipos'.\">união</dfn> entre tipos diferentes onde um ou mais deles não são tipos Pydantic válidos, por exemplo, isso falharia 💥:\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n...isso falha porque a anotação de tipo não é um tipo Pydantic e não é apenas uma única classe ou subclasse `Response`, é uma união (qualquer uma das duas) entre um `Response` e ​​um `dict`.\n\n### Desative o modelo de resposta { #disable-response-model }\n\nContinuando com o exemplo acima, você pode não querer ter a validação de dados padrão, documentação, filtragem, etc. que é realizada pelo FastAPI.\n\nMas você pode querer manter a anotação do tipo de retorno na função para obter o suporte de ferramentas como editores e verificadores de tipo (por exemplo, mypy).\n\nNeste caso, você pode desabilitar a geração do modelo de resposta definindo `response_model=None`:\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\nIsso fará com que o FastAPI pule a geração do modelo de resposta e, dessa forma, você pode ter quaisquer anotações de tipo de retorno que precisar sem afetar seu aplicativo FastAPI. 🤓\n\n## Parâmetros de codificação do modelo de resposta { #response-model-encoding-parameters }\n\nSeu modelo de resposta pode ter valores padrão, como:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None` (ou `str | None = None` no Python 3.10) tem um padrão de `None`.\n* `tax: float = 10.5` tem um padrão de `10.5`.\n* `tags: List[str] = []` tem um padrão de uma lista vazia: `[]`.\n\nmas você pode querer omiti-los do resultado se eles não foram realmente armazenados.\n\nPor exemplo, se você tem modelos com muitos atributos opcionais em um banco de dados NoSQL, mas não quer enviar respostas JSON muito longas cheias de valores padrão.\n\n### Use o parâmetro `response_model_exclude_unset` { #use-the-response-model-exclude-unset-parameter }\n\nVocê pode definir o parâmetro `response_model_exclude_unset=True` do *decorador de operação de rota*:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\ne esses valores padrão não serão incluídos na resposta, apenas os valores realmente definidos.\n\nEntão, se você enviar uma solicitação para essa *operação de rota* para o item com ID `foo`, a resposta (sem incluir valores padrão) será:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | Informação\n\nVocê também pode usar:\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\nconforme descrito na [documentação do Pydantic](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict) para `exclude_defaults` e `exclude_none`.\n\n///\n\n#### Dados com valores para campos com padrões { #data-with-values-for-fields-with-defaults }\n\nMas se seus dados tiverem valores para os campos do modelo com valores padrões, como o item com ID `bar`:\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\neles serão incluídos na resposta.\n\n#### Dados com os mesmos valores que os padrões { #data-with-the-same-values-as-the-defaults }\n\nSe os dados tiverem os mesmos valores que os padrões, como o item com ID `baz`:\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nO FastAPI é inteligente o suficiente (na verdade, o Pydantic é inteligente o suficiente) para perceber que, embora `description`, `tax` e `tags` tenham os mesmos valores que os padrões, eles foram definidos explícita e diretamente (em vez de retirados dos padrões).\n\nPortanto, eles serão incluídos na resposta JSON.\n\n/// tip | Dica\n\nObserve que os valores padrão podem ser qualquer coisa, não apenas `None`.\n\nEles podem ser uma lista (`[]`), um `float` de `10.5`, etc.\n\n///\n\n### `response_model_include` e `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\nVocê também pode usar os parâmetros `response_model_include` e `response_model_exclude` do *decorador de operação de rota*.\n\nEles pegam um `set` de `str` com o nome dos atributos para incluir (omitindo o resto) ou para excluir (incluindo o resto).\n\nIsso pode ser usado como um atalho rápido se você tiver apenas um modelo Pydantic e quiser remover alguns dados da saída.\n\n/// tip | Dica\n\nMas ainda é recomendado usar as ideias acima, usando várias classes, em vez desses parâmetros.\n\nIsso ocorre porque o JSON Schema gerado no OpenAPI do seu aplicativo (e a documentação) ainda será o único para o modelo completo, mesmo que você use `response_model_include` ou `response_model_exclude` para omitir alguns atributos.\n\nIsso também se aplica ao `response_model_by_alias` que funciona de forma semelhante.\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | Dica\n\nA sintaxe `{\"name\", \"description\"}` cria um `set` com esses dois valores.\n\nÉ equivalente a `set([\"name\", \"description\"])`.\n\n///\n\n#### Usando `list`s em vez de `set`s { #using-lists-instead-of-sets }\n\nSe você esquecer de usar um `set` e usar uma `list` ou `tuple` em vez disso, o FastAPI ainda o converterá em um `set` e funcionará corretamente:\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## Recapitulação { #recap }\n\nUse o parâmetro `response_model` do *decorador de operação de rota* para definir modelos de resposta e, especialmente, para garantir que dados privados sejam filtrados.\n\nUse `response_model_exclude_unset` para retornar apenas os valores definidos explicitamente.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/response-status-code.md",
    "content": "# Código de status de resposta { #response-status-code }\n\nDa mesma forma que você pode especificar um modelo de resposta, você também pode declarar o código de status HTTP usado para a resposta com o parâmetro `status_code` em qualquer uma das *operações de rota*:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* etc.\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | Nota\n\nObserve que `status_code` é um parâmetro do método \"decorador\" (`get`, `post`, etc). Não da sua função de *operação de rota*, como todos os parâmetros e corpo.\n\n///\n\nO parâmetro `status_code` recebe um número com o código de status HTTP.\n\n/// info | Informação\n\n`status_code` também pode receber um `IntEnum`, como [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus) do Python.\n\n///\n\nDessa forma:\n\n* Este código de status será retornado na resposta.\n* Será documentado como tal no esquema OpenAPI (e, portanto, nas interfaces do usuário):\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | Nota\n\nAlguns códigos de resposta (consulte a próxima seção) indicam que a resposta não possui um corpo.\n\nO FastAPI sabe disso e produzirá documentos OpenAPI informando que não há corpo de resposta.\n\n///\n\n## Sobre os códigos de status HTTP { #about-http-status-codes }\n\n/// note | Nota\n\nSe você já sabe o que são códigos de status HTTP, pule para a próxima seção.\n\n///\n\nEm HTTP, você envia um código de status numérico de 3 dígitos como parte da resposta.\n\nEsses códigos de status têm um nome associado para reconhecê-los, mas o importante é o número.\n\nResumidamente:\n\n* `100 - 199` são para \"Informações\". Você raramente os usa diretamente. As respostas com esses códigos de status não podem ter um corpo.\n* **`200 - 299`** são para respostas \"Bem-sucedidas\". Estes são os que você mais usaria.\n    * `200` é o código de status padrão, o que significa que tudo estava \"OK\".\n    * Outro exemplo seria `201`, \"Criado\". É comumente usado após a criação de um novo registro no banco de dados.\n    * Um caso especial é `204`, \"Sem Conteúdo\". Essa resposta é usada quando não há conteúdo para retornar ao cliente e, portanto, a resposta não deve ter um corpo.\n* **`300 - 399`** são para \"Redirecionamento\". As respostas com esses códigos de status podem ou não ter um corpo, exceto `304`, \"Não modificado\", que não deve ter um.\n* **`400 - 499`** são para respostas de \"Erro do cliente\". Este é o segundo tipo que você provavelmente mais usaria.\n    * Um exemplo é `404`, para uma resposta \"Não encontrado\".\n    * Para erros genéricos do cliente, você pode usar apenas `400`.\n* `500 - 599` são para erros do servidor. Você quase nunca os usa diretamente. Quando algo der errado em alguma parte do código do seu aplicativo ou servidor, ele retornará automaticamente um desses códigos de status.\n\n/// tip | Dica\n\nPara saber mais sobre cada código de status e qual código serve para quê, verifique a [documentação do <abbr title=\"Mozilla Developer Network - Rede de Desenvolvedores da Mozilla\">MDN</abbr> sobre códigos de status HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).\n\n///\n\n## Atalho para lembrar os nomes { #shortcut-to-remember-the-names }\n\nVamos ver o exemplo anterior novamente:\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201` é o código de status para \"Criado\".\n\nMas você não precisa memorizar o que cada um desses códigos significa.\n\nVocê pode usar as variáveis de conveniência de `fastapi.status`.\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\nEles são apenas uma conveniência, eles possuem o mesmo número, mas dessa forma você pode usar o preenchimento automático do editor para encontrá-los:\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | Detalhes Técnicos\n\nVocê também pode usar `from starlette import status`.\n\n**FastAPI** fornece o mesmo `starlette.status` como `fastapi.status` apenas como uma conveniência para você, o desenvolvedor. Mas vem diretamente da Starlette.\n\n///\n\n## Alterando o padrão { #changing-the-default }\n\nMais tarde, no [Guia do Usuário Avançado](../advanced/response-change-status-code.md), você verá como retornar um código de status diferente do padrão que você está declarando aqui.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/schema-extra-example.md",
    "content": "# Declare dados de exemplo da requisição { #declare-request-example-data }\n\nVocê pode declarar exemplos dos dados que sua aplicação pode receber.\n\nAqui estão várias maneiras de fazer isso.\n\n## Dados extras de JSON Schema em modelos Pydantic { #extra-json-schema-data-in-pydantic-models }\n\nVocê pode declarar `examples` para um modelo Pydantic que serão adicionados ao JSON Schema gerado.\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\nEssas informações extras serão adicionadas como estão ao **JSON Schema** de saída para esse modelo e serão usadas na documentação da API.\n\nVocê pode usar o atributo `model_config`, que recebe um `dict`, conforme descrito na [documentação do Pydantic: Configuration](https://docs.pydantic.dev/latest/api/config/).\n\nVocê pode definir `\"json_schema_extra\"` com um `dict` contendo quaisquer dados adicionais que você queira que apareçam no JSON Schema gerado, incluindo `examples`.\n\n/// tip | Dica\n\nVocê poderia usar a mesma técnica para estender o JSON Schema e adicionar suas próprias informações extras personalizadas.\n\nPor exemplo, você poderia usá-la para adicionar metadados para uma interface de usuário de front-end, etc.\n\n///\n\n/// info | Informação\n\nO OpenAPI 3.1.0 (usado desde o FastAPI 0.99.0) adicionou suporte a `examples`, que faz parte do padrão **JSON Schema**.\n\nAntes disso, ele suportava apenas a palavra‑chave `example` com um único exemplo. Isso ainda é suportado pelo OpenAPI 3.1.0, mas é descontinuado e não faz parte do padrão JSON Schema. Portanto, você é incentivado a migrar de `example` para `examples`. 🤓\n\nVocê pode ler mais no final desta página.\n\n///\n\n## Argumentos adicionais de `Field` { #field-additional-arguments }\n\nAo usar `Field()` com modelos Pydantic, você também pode declarar `examples` adicionais:\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## `examples` no JSON Schema - OpenAPI { #examples-in-json-schema-openapi }\n\nAo usar qualquer um de:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nvocê também pode declarar um grupo de `examples` com informações adicionais que serão adicionadas aos seus **JSON Schemas** dentro do **OpenAPI**.\n\n### `Body` com `examples` { #body-with-examples }\n\nAqui passamos `examples` contendo um exemplo dos dados esperados em `Body()`:\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### Exemplo na UI da documentação { #example-in-the-docs-ui }\n\nCom qualquer um dos métodos acima, ficaria assim em `/docs`:\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### `Body` com vários `examples` { #body-with-multiple-examples }\n\nVocê também pode, é claro, passar vários `examples`:\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\nQuando fizer isso, os exemplos farão parte do **JSON Schema** interno para esses dados do body.\n\nNo entanto, <dfn title=\"2023-08-26\">no momento em que isto foi escrito</dfn>, o Swagger UI, a ferramenta responsável por exibir a UI da documentação, não suporta mostrar vários exemplos para os dados no **JSON Schema**. Mas leia abaixo para uma solução alternativa.\n\n### `examples` específicos do OpenAPI { #openapi-specific-examples }\n\nAntes do **JSON Schema** suportar `examples`, o OpenAPI já tinha suporte para um campo diferente também chamado `examples`.\n\nEsse `examples` **específico do OpenAPI** vai em outra seção da especificação OpenAPI. Ele fica nos **detalhes de cada *operação de rota***, não dentro de cada JSON Schema.\n\nE o Swagger UI tem suportado esse campo `examples` particular há algum tempo. Então, você pode usá-lo para **mostrar** diferentes **exemplos na UI da documentação**.\n\nO formato desse campo `examples` específico do OpenAPI é um `dict` com **vários exemplos** (em vez de uma `list`), cada um com informações extras que também serão adicionadas ao **OpenAPI**.\n\nIsso não vai dentro de cada JSON Schema contido no OpenAPI, vai fora, diretamente na *operação de rota*.\n\n### Usando o parâmetro `openapi_examples` { #using-the-openapi-examples-parameter }\n\nVocê pode declarar o `examples` específico do OpenAPI no FastAPI com o parâmetro `openapi_examples` para:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nAs chaves do `dict` identificam cada exemplo, e cada valor é outro `dict`.\n\nCada `dict` de exemplo específico em `examples` pode conter:\n\n* `summary`: Descrição curta do exemplo.\n* `description`: Uma descrição longa que pode conter texto em Markdown.\n* `value`: Este é o exemplo em si, por exemplo, um `dict`.\n* `externalValue`: Alternativa a `value`, uma URL apontando para o exemplo. Embora isso possa não ser suportado por tantas ferramentas quanto `value`.\n\nVocê pode usá-lo assim:\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### Exemplos do OpenAPI na UI da documentação { #openapi-examples-in-the-docs-ui }\n\nCom `openapi_examples` adicionado a `Body()`, o `/docs` ficaria assim:\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## Detalhes Técnicos { #technical-details }\n\n/// tip | Dica\n\nSe você já está usando o **FastAPI** na versão **0.99.0 ou superior**, você provavelmente pode **pular** esses detalhes.\n\nEles são mais relevantes para versões antigas, antes de o OpenAPI 3.1.0 estar disponível.\n\nVocê pode considerar isto uma breve **aula de história** sobre OpenAPI e JSON Schema. 🤓\n\n///\n\n/// warning | Atenção\n\nEstes são detalhes muito técnicos sobre os padrões **JSON Schema** e **OpenAPI**.\n\nSe as ideias acima já funcionam para você, isso pode ser suficiente, e você provavelmente não precisa desses detalhes, sinta-se à vontade para pular.\n\n///\n\nAntes do OpenAPI 3.1.0, o OpenAPI usava uma versão mais antiga e modificada do **JSON Schema**.\n\nO JSON Schema não tinha `examples`, então o OpenAPI adicionou seu próprio campo `example` à sua versão modificada.\n\nO OpenAPI também adicionou os campos `example` e `examples` a outras partes da especificação:\n\n* [`Parameter Object` (na especificação)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object), usado no FastAPI por:\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object`, no campo `content`, no `Media Type Object` (na especificação)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object), usado no FastAPI por:\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info | Informação\n\nEsse parâmetro antigo `examples` específico do OpenAPI agora é `openapi_examples` desde o FastAPI `0.103.0`.\n\n///\n\n### Campo `examples` do JSON Schema { #json-schemas-examples-field }\n\nDepois, o JSON Schema adicionou um campo [`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5) em uma nova versão da especificação.\n\nE então o novo OpenAPI 3.1.0 passou a se basear na versão mais recente (JSON Schema 2020-12), que incluiu esse novo campo `examples`.\n\nE agora esse novo campo `examples` tem precedência sobre o antigo campo único (e customizado) `example`, que agora está descontinuado.\n\nEsse novo campo `examples` no JSON Schema é **apenas uma `list`** de exemplos, não um dict com metadados extras como nos outros lugares do OpenAPI (descritos acima).\n\n/// info | Informação\n\nMesmo após o lançamento do OpenAPI 3.1.0 com essa nova integração mais simples com o JSON Schema, por um tempo o Swagger UI, a ferramenta que fornece a documentação automática, não suportava OpenAPI 3.1.0 (passou a suportar desde a versão 5.0.0 🎉).\n\nPor causa disso, versões do FastAPI anteriores à 0.99.0 ainda usavam versões do OpenAPI inferiores à 3.1.0.\n\n///\n\n### `examples` no Pydantic e no FastAPI { #pydantic-and-fastapi-examples }\n\nQuando você adiciona `examples` dentro de um modelo Pydantic, usando `schema_extra` ou `Field(examples=[\"something\"])`, esse exemplo é adicionado ao **JSON Schema** para esse modelo Pydantic.\n\nE esse **JSON Schema** do modelo Pydantic é incluído no **OpenAPI** da sua API e, então, é usado na UI da documentação.\n\nEm versões do FastAPI anteriores à 0.99.0 (0.99.0 e superiores usam o novo OpenAPI 3.1.0), quando você usava `example` ou `examples` com qualquer uma das outras utilidades (`Query()`, `Body()`, etc.), esses exemplos não eram adicionados ao JSON Schema que descreve esses dados (nem mesmo à versão própria do JSON Schema do OpenAPI), eles eram adicionados diretamente à declaração da *operação de rota* no OpenAPI (fora das partes do OpenAPI que usam o JSON Schema).\n\nMas agora que o FastAPI 0.99.0 e superiores usam o OpenAPI 3.1.0, que usa o JSON Schema 2020-12, e o Swagger UI 5.0.0 e superiores, tudo é mais consistente e os exemplos são incluídos no JSON Schema.\n\n### Swagger UI e `examples` específicos do OpenAPI { #swagger-ui-and-openapi-specific-examples }\n\nAgora, como o Swagger UI não suportava vários exemplos no JSON Schema (em 2023-08-26), os usuários não tinham uma forma de mostrar vários exemplos na documentação.\n\nPara resolver isso, o FastAPI `0.103.0` **adicionou suporte** para declarar o mesmo antigo campo **específico do OpenAPI** `examples` com o novo parâmetro `openapi_examples`. 🤓\n\n### Resumo { #summary }\n\nEu costumava dizer que não gostava tanto de história... e olha eu aqui agora dando aulas de \"história tech\". 😅\n\nEm resumo, **atualize para o FastAPI 0.99.0 ou superior**, e as coisas ficam muito mais **simples, consistentes e intuitivas**, e você não precisa saber todos esses detalhes históricos. 😎\n"
  },
  {
    "path": "docs/pt/docs/tutorial/security/first-steps.md",
    "content": "# Segurança - Primeiros Passos { #security-first-steps }\n\nVamos imaginar que você tem a sua API de **backend** em algum domínio.\n\nE você tem um **frontend** em outro domínio ou em um path diferente no mesmo domínio (ou em uma aplicação mobile).\n\nE você quer uma maneira de o frontend autenticar com o backend, usando um **username** e **password**.\n\nPodemos usar **OAuth2** para construir isso com o **FastAPI**.\n\nMas vamos poupar o seu tempo de ler toda a especificação extensa apenas para achar as pequenas informações de que você precisa.\n\nVamos usar as ferramentas fornecidas pelo **FastAPI** para lidar com segurança.\n\n## Como Parece { #how-it-looks }\n\nVamos primeiro usar o código e ver como funciona, e depois voltaremos para entender o que está acontecendo.\n\n## Crie um `main.py` { #create-main-py }\n\nCopie o exemplo em um arquivo `main.py`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## Execute-o { #run-it }\n\n/// info | Informação\n\nO pacote [`python-multipart`](https://github.com/Kludex/python-multipart) é instalado automaticamente com o **FastAPI** quando você executa o comando `pip install \"fastapi[standard]\"`.\n\nEntretanto, se você usar o comando `pip install fastapi`, o pacote `python-multipart` não é incluído por padrão.\n\nPara instalá-lo manualmente, certifique-se de criar um [ambiente virtual](../../virtual-environments.md), ativá-lo e então instalá-lo com:\n\n```console\n$ pip install python-multipart\n```\n\nIsso ocorre porque o **OAuth2** usa \"form data\" para enviar o `username` e o `password`.\n\n///\n\nExecute o exemplo com:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## Verifique-o { #check-it }\n\nVá até a documentação interativa em: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVocê verá algo deste tipo:\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Botão Autorizar!\n\nVocê já tem um novo botão 'Authorize'.\n\nE sua operação de rota tem um pequeno cadeado no canto superior direito em que você pode clicar.\n\n///\n\nE se você clicar, verá um pequeno formulário de autorização para digitar um `username` e um `password` (e outros campos opcionais):\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | Nota\n\nNão importa o que você digite no formulário, ainda não vai funcionar. Mas nós vamos chegar lá.\n\n///\n\nClaro que este não é o frontend para os usuários finais, mas é uma ótima ferramenta automática para documentar interativamente toda a sua API.\n\nPode ser usada pelo time de frontend (que pode ser você mesmo).\n\nPode ser usada por aplicações e sistemas de terceiros.\n\nE também pode ser usada por você mesmo, para depurar, verificar e testar a mesma aplicação.\n\n## O fluxo de `password` { #the-password-flow }\n\nAgora vamos voltar um pouco e entender o que é isso tudo.\n\nO \"fluxo\" `password` é uma das formas (\"fluxos\") definidas no OAuth2 para lidar com segurança e autenticação.\n\nO OAuth2 foi projetado para que o backend ou a API pudesse ser independente do servidor que autentica o usuário.\n\nMas, neste caso, a mesma aplicação **FastAPI** irá lidar com a API e com a autenticação.\n\nEntão, vamos rever de um ponto de vista simplificado:\n\n* O usuário digita o `username` e o `password` no frontend e pressiona `Enter`.\n* O frontend (rodando no navegador do usuário) envia esse `username` e `password` para uma URL específica na nossa API (declarada com `tokenUrl=\"token\"`).\n* A API verifica esse `username` e `password`, e responde com um \"token\" (ainda não implementamos nada disso).\n    * Um \"token\" é apenas uma string com algum conteúdo que podemos usar depois para verificar esse usuário.\n    * Normalmente, um token é definido para expirar depois de algum tempo.\n        * Então, o usuário terá que fazer login novamente em algum momento.\n        * E se o token for roubado, o risco é menor. Não é como uma chave permanente que funcionará para sempre (na maioria dos casos).\n* O frontend armazena esse token temporariamente em algum lugar.\n* O usuário clica no frontend para ir para outra seção do aplicativo web.\n* O frontend precisa buscar mais dados da API.\n    * Mas precisa de autenticação para aquele endpoint específico.\n    * Então, para autenticar com nossa API, ele envia um header `Authorization` com o valor `Bearer ` mais o token.\n    * Se o token contém `foobar`, o conteúdo do header `Authorization` seria: `Bearer foobar`.\n\n## O `OAuth2PasswordBearer` do **FastAPI** { #fastapis-oauth2passwordbearer }\n\nO **FastAPI** fornece várias ferramentas, em diferentes níveis de abstração, para implementar essas funcionalidades de segurança.\n\nNeste exemplo, vamos usar **OAuth2**, com o fluxo **Password**, usando um token **Bearer**. Fazemos isso usando a classe `OAuth2PasswordBearer`.\n\n/// info | Informação\n\nUm token \"bearer\" não é a única opção.\n\nMas é a melhor para o nosso caso de uso.\n\nE pode ser a melhor para a maioria dos casos de uso, a menos que você seja um especialista em OAuth2 e saiba exatamente por que existe outra opção que se adapta melhor às suas necessidades.\n\nNesse caso, o **FastAPI** também fornece as ferramentas para construí-la.\n\n///\n\nQuando criamos uma instância da classe `OAuth2PasswordBearer`, passamos o parâmetro `tokenUrl`. Esse parâmetro contém a URL que o client (o frontend rodando no navegador do usuário) usará para enviar o `username` e o `password` para obter um token.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip | Dica\n\nAqui `tokenUrl=\"token\"` refere-se a uma URL relativa `token` que ainda não criamos. Como é uma URL relativa, é equivalente a `./token`.\n\nComo estamos usando uma URL relativa, se sua API estivesse localizada em `https://example.com/`, então se referiria a `https://example.com/token`. Mas se sua API estivesse localizada em `https://example.com/api/v1/`, então se referiria a `https://example.com/api/v1/token`.\n\nUsar uma URL relativa é importante para garantir que sua aplicação continue funcionando mesmo em um caso de uso avançado como [Atrás de um Proxy](../../advanced/behind-a-proxy.md).\n\n///\n\nEsse parâmetro não cria aquele endpoint/operação de rota, mas declara que a URL `/token` será aquela que o client deve usar para obter o token. Essa informação é usada no OpenAPI e depois nos sistemas de documentação interativa da API.\n\nEm breve também criaremos a operação de rota real.\n\n/// info | Informação\n\nSe você é um \"Pythonista\" muito rigoroso, pode não gostar do estilo do nome do parâmetro `tokenUrl` em vez de `token_url`.\n\nIsso ocorre porque ele usa o mesmo nome da especificação do OpenAPI. Assim, se você precisar investigar mais sobre qualquer um desses esquemas de segurança, pode simplesmente copiar e colar para encontrar mais informações sobre isso.\n\n///\n\nA variável `oauth2_scheme` é uma instância de `OAuth2PasswordBearer`, mas também é um \"callable\".\n\nEla pode ser chamada como:\n\n```Python\noauth2_scheme(some, parameters)\n```\n\nEntão, pode ser usada com `Depends`.\n\n### Use-o { #use-it }\n\nAgora você pode passar esse `oauth2_scheme` em uma dependência com `Depends`.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nEssa dependência fornecerá uma `str` que é atribuída ao parâmetro `token` da função de operação de rota.\n\nO **FastAPI** saberá que pode usar essa dependência para definir um \"esquema de segurança\" no esquema OpenAPI (e na documentação automática da API).\n\n/// info | Detalhes Técnicos\n\nO **FastAPI** saberá que pode usar a classe `OAuth2PasswordBearer` (declarada em uma dependência) para definir o esquema de segurança no OpenAPI porque ela herda de `fastapi.security.oauth2.OAuth2`, que por sua vez herda de `fastapi.security.base.SecurityBase`.\n\nTodos os utilitários de segurança que se integram com o OpenAPI (e com a documentação automática da API) herdam de `SecurityBase`, é assim que o **FastAPI** sabe como integrá-los ao OpenAPI.\n\n///\n\n## O que ele faz { #what-it-does }\n\nEle irá procurar na requisição pelo header `Authorization`, verificar se o valor é `Bearer ` mais algum token e retornará o token como uma `str`.\n\nSe não houver um header `Authorization`, ou se o valor não tiver um token `Bearer `, ele responderá diretamente com um erro de status 401 (`UNAUTHORIZED`).\n\nVocê nem precisa verificar se o token existe para retornar um erro. Você pode ter certeza de que, se sua função for executada, ela terá uma `str` nesse token.\n\nVocê já pode experimentar na documentação interativa:\n\n<img src=\"/img/tutorial/security/image03.png\">\n\nAinda não estamos verificando a validade do token, mas isso já é um começo.\n\n## Recapitulando { #recap }\n\nEntão, com apenas 3 ou 4 linhas extras, você já tem alguma forma primitiva de segurança.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/security/get-current-user.md",
    "content": "# Obter Usuário Atual { #get-current-user }\n\nNo capítulo anterior, o sistema de segurança (que é baseado no sistema de injeção de dependências) estava fornecendo à *função de operação de rota* um `token` como uma `str`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nMas isso ainda não é tão útil.\n\nVamos fazer com que ele nos forneça o usuário atual.\n\n## Criar um modelo de usuário { #create-a-user-model }\n\nPrimeiro, vamos criar um modelo de usuário com Pydantic.\n\nDa mesma forma que usamos o Pydantic para declarar corpos, podemos usá-lo em qualquer outro lugar:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## Criar uma dependência `get_current_user` { #create-a-get-current-user-dependency }\n\nVamos criar uma dependência chamada `get_current_user`.\n\nLembra que as dependências podem ter subdependências?\n\n`get_current_user` terá uma dependência com o mesmo `oauth2_scheme` que criamos antes.\n\nDa mesma forma que estávamos fazendo antes diretamente na *operação de rota*, a nossa nova dependência `get_current_user` receberá um `token` como uma `str` da subdependência `oauth2_scheme`:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## Obter o usuário { #get-the-user }\n\n`get_current_user` usará uma função utilitária (falsa) que criamos, que recebe um token como uma `str` e retorna nosso modelo Pydantic `User`:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## Injetar o usuário atual { #inject-the-current-user }\n\nEntão agora nós podemos usar o mesmo `Depends` com nosso `get_current_user` na *operação de rota*:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\nObserve que nós declaramos o tipo de `current_user` como o modelo Pydantic `User`.\n\nIsso nos ajudará dentro da função com todo o preenchimento automático e verificações de tipo.\n\n/// tip | Dica\n\nVocê pode se lembrar que corpos de requisição também são declarados com modelos Pydantic.\n\nAqui, o **FastAPI** não ficará confuso porque você está usando `Depends`.\n\n///\n\n/// check | Verifique\n\nA forma como esse sistema de dependências foi projetado nos permite ter diferentes dependências (diferentes \"dependables\") que retornam um modelo `User`.\n\nNão estamos restritos a ter apenas uma dependência que possa retornar esse tipo de dado.\n\n///\n\n## Outros modelos { #other-models }\n\nAgora você pode obter o usuário atual diretamente nas *funções de operação de rota* e lidar com os mecanismos de segurança no nível da **Injeção de Dependências**, usando `Depends`.\n\nE você pode usar qualquer modelo ou dado para os requisitos de segurança (neste caso, um modelo Pydantic `User`).\n\nMas você não está restrito a usar um modelo de dados, classe ou tipo específico.\n\nVocê quer ter apenas um `id` e `email`, sem incluir nenhum `username` no modelo? Claro. Você pode usar essas mesmas ferramentas.\n\nVocê quer ter apenas uma `str`? Ou apenas um `dict`? Ou uma instância de modelo de classe de banco de dados diretamente? Tudo funciona da mesma forma.\n\nNa verdade, você não tem usuários que fazem login no seu aplicativo, mas sim robôs, bots ou outros sistemas, que possuem apenas um token de acesso? Novamente, tudo funciona da mesma forma.\n\nApenas use qualquer tipo de modelo, qualquer tipo de classe, qualquer tipo de banco de dados que você precise para a sua aplicação. O **FastAPI** cobre tudo com o sistema de injeção de dependências.\n\n## Tamanho do código { #code-size }\n\nEste exemplo pode parecer verboso. Lembre-se de que estamos misturando segurança, modelos de dados, funções utilitárias e *operações de rota* no mesmo arquivo.\n\nMas aqui está o ponto principal.\n\nO código relacionado à segurança e à injeção de dependências é escrito apenas uma vez.\n\nE você pode torná-lo tão complexo quanto quiser. E ainda assim, tê-lo escrito apenas uma vez, em um único lugar. Com toda a flexibilidade.\n\nMas você pode ter milhares de endpoints (*operações de rota*) usando o mesmo sistema de segurança.\n\nE todos eles (ou qualquer parte deles que você desejar) podem aproveitar o reuso dessas dependências ou de quaisquer outras dependências que você criar.\n\nE todos esses milhares de *operações de rota* podem ter apenas 3 linhas:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## Recapitulação { #recap }\n\nAgora você pode obter o usuário atual diretamente na sua *função de operação de rota*.\n\nJá estamos na metade do caminho.\n\nSó precisamos adicionar uma *operação de rota* para que o usuário/cliente realmente envie o `username` e `password`.\n\nIsso vem a seguir.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/security/index.md",
    "content": "# Segurança { #security }\n\nHá várias formas de lidar segurança, autenticação e autorização.\n\nE isso normalmente é um tópico “difícil” e complexo.\n\nEm muitos frameworks e sistemas, apenas lidar com segurança e autenticação exige muito esforço e código (em muitos casos isso pode ser 50% ou mais de todo o código escrito).\n\n**FastAPI** tem muitas ferramentas para ajudar você com a parte de **Segurança** facilmente, rapidamente, de uma forma padrão, sem ter que estudar e aprender tudo sobre especificações de segurança.\n\nMas primeiro, vamos verificar alguns pequenos conceitos.\n\n## Está com pressa? { #in-a-hurry }\n\nSe você não se importa com qualquer um desses termos e só precisa adicionar segurança com autenticação baseada em usuário e senha _agora_, pule para os próximos capítulos.\n\n## OAuth2 { #oauth2 }\n\nOAuth2 é uma especificação que define várias formas para lidar com autenticação e autorização.\n\nEla é bastante extensiva na especificação e cobre casos de uso muito complexos.\n\nEla inclui uma forma para autenticação usando “third party”/aplicações de terceiros.\n\nIsso é o que todos os sistemas com “Login with Facebook, Google, X (Twitter), GitHub” usam por baixo.\n\n### OAuth 1 { #oauth-1 }\n\nHavia um OAuth 1, que é bem diferente do OAuth2, e mais complexo, isso incluía diretamente as especificações de como criptografar a comunicação.\n\nNão é muito popular ou usado nos dias atuais.\n\nOAuth2 não especifica como criptografar a comunicação, ele espera que você tenha sua aplicação em um servidor HTTPS.\n\n/// tip | Dica\n\nNa seção sobre **deployment** você irá ver como configurar HTTPS de modo gratuito, usando Traefik e Let’s Encrypt.\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect é outra especificação, baseada em **OAuth2**.\n\nEla é apenas uma extensão do OAuth2 especificando algumas coisas que são relativamente ambíguas no OAuth2, para tentar torná-lo mais interoperável.\n\nPor exemplo, o login do Google usa OpenID Connect (que por baixo dos panos usa OAuth2).\n\nMas o login do Facebook não tem suporte para OpenID Connect. Ele tem a própria implementação do OAuth2.\n\n### OpenID (não \"OpenID Connect\") { #openid-not-openid-connect }\n\nHouve também uma especificação “OpenID”. Ela tentou resolver a mesma coisa que a **OpenID Connect**, mas não baseada em OAuth2.\n\nEntão, ela foi um sistema adicional completo.\n\nEla não é muito popular ou usada nos dias de hoje.\n\n## OpenAPI { #openapi }\n\nOpenAPI (anteriormente conhecido como Swagger) é a especificação aberta para a criação de APIs (agora parte da Linux Foundation).\n\n**FastAPI** é baseado no **OpenAPI**.\n\nIsso é o que torna possível ter múltiplas automações interativas de interfaces de documentação, geração de código, etc.\n\nOpenAPI tem uma forma para definir múltiplos “esquemas” de segurança.\n\nPor usá-los, você pode ter vantagens de todas essas ferramentas baseadas nos padrões, incluindo os sistemas de documentação interativa.\n\nOpenAPI define os seguintes esquemas de segurança:\n\n* `apiKey`: uma chave específica de aplicação que pode vir de:\n    * Um parâmetro query.\n    * Um header.\n    * Um cookie.\n* `http`: padrão HTTP de sistemas autenticação, incluindo:\n    * `bearer`: um header de `Authorization` com valor de `Bearer` adicionado de um token. Isso é herança do OAuth2.\n    * HTTP Basic authentication.\n    * HTTP Digest, etc.\n* `oauth2`: todas as formas do OAuth2 para lidar com segurança (chamados \"fluxos\").\n    * Vários desses fluxos são apropriados para construir um provedor de autenticação OAuth2 (como Google, Facebook, X (Twitter), GitHub, etc):\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * Mas existe um “fluxo” específico que pode ser perfeitamente usado para resolver autenticação diretamente na mesma aplicação:\n        * `password`: alguns dos próximos capítulos tratarão disso.\n* `openIdConnect`: tem uma forma para definir como descobrir automaticamente o dado da autenticação OAuth2.\n    * Essa descoberta automática é o que é definido na especificação OpenID Connect.\n\n/// tip | Dica\n\nIntegração com outros provedores de autenticação/autorização como Google, Facebook, X (Twitter), GitHub, etc. é bem possível e relativamente fácil.\n\nO problema mais complexo é criar um provedor de autenticação/autorização como eles, mas o FastAPI dá a você ferramentas para fazer isso facilmente, enquanto faz o trabalho pesado para você.\n\n///\n\n## **FastAPI** utilitários { #fastapi-utilities }\n\n**FastAPI** fornece várias ferramentas para cada um desses esquemas de segurança no módulo `fastapi.security` que simplificam o uso desses mecanismos de segurança.\n\nNos próximos capítulos você irá ver como adicionar segurança à sua API usando essas ferramentas disponibilizadas pelo **FastAPI**.\n\nE você irá ver também como isso é automaticamente integrado dentro do sistema de documentação interativo.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/security/oauth2-jwt.md",
    "content": "# OAuth2 com Senha (e hashing), Bearer com tokens JWT { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\nAgora que temos todo o fluxo de segurança, vamos tornar a aplicação realmente segura, usando tokens <abbr title=\"JSON Web Tokens\">JWT</abbr> e hashing de senhas seguras.\n\nEste código é algo que você pode realmente usar na sua aplicação, salvar os hashes das senhas no seu banco de dados, etc.\n\nVamos começar de onde paramos no capítulo anterior e incrementá-lo.\n\n## Sobre o JWT { #about-jwt }\n\nJWT significa \"JSON Web Tokens\".\n\nÉ um padrão para codificar um objeto JSON em uma string longa e densa sem espaços. Ele se parece com isso:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\nEle não é criptografado, então qualquer pessoa pode recuperar as informações do seu conteúdo.\n\nMas ele é assinado. Assim, quando você recebe um token que você emitiu, você pode verificar que foi realmente você quem o emitiu.\n\nDessa forma, você pode criar um token com um prazo de expiração, digamos, de 1 semana. E então, quando o usuário voltar no dia seguinte com o token, você sabe que ele ainda está logado no seu sistema.\n\nDepois de uma semana, o token expirará e o usuário não estará autorizado, precisando fazer login novamente para obter um novo token. E se o usuário (ou uma terceira parte) tentar modificar o token para alterar a expiração, você seria capaz de descobrir isso, pois as assinaturas não iriam corresponder.\n\nSe você quiser brincar com tokens JWT e ver como eles funcionam, visite [https://jwt.io](https://jwt.io/).\n\n## Instalar `PyJWT` { #install-pyjwt }\n\nNós precisamos instalar o `PyJWT` para criar e verificar os tokens JWT em Python.\n\nCertifique-se de criar um [ambiente virtual](../../virtual-environments.md), ativá-lo e então instalar o `pyjwt`:\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info | Informação\n\nSe você pretente utilizar algoritmos de assinatura digital como o RSA ou o ECDSA, você deve instalar a dependência da biblioteca de criptografia `pyjwt[crypto]`.\n\nVocê pode ler mais sobre isso na [documentação de instalação do PyJWT](https://pyjwt.readthedocs.io/en/latest/installation.html).\n\n///\n\n## Hashing de senhas { #password-hashing }\n\n\"Hashing\" significa converter algum conteúdo (uma senha neste caso) em uma sequência de bytes (apenas uma string) que parece um monte de caracteres sem sentido.\n\nSempre que você passar exatamente o mesmo conteúdo (exatamente a mesma senha), você obterá exatamente o mesmo resultado.\n\nMas não é possível converter os caracteres sem sentido de volta para a senha original.\n\n### Por que usar hashing de senhas { #why-use-password-hashing }\n\nSe o seu banco de dados for roubado, o invasor não terá as senhas em texto puro dos seus usuários, apenas os hashes.\n\nEntão, o invasor não poderá tentar usar essas senhas em outro sistema (como muitos usuários utilizam a mesma senha em vários lugares, isso seria perigoso).\n\n## Instalar o `pwdlib` { #install-pwdlib }\n\npwdlib é um excelente pacote Python para lidar com hashes de senhas.\n\nEle suporta muitos algoritmos de hashing seguros e utilitários para trabalhar com eles.\n\nO algoritmo recomendado é o \"Argon2\".\n\nCertifique-se de criar um [ambiente virtual](../../virtual-environments.md), ativá-lo e então instalar o pwdlib com Argon2:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | Dica\n\nCom o `pwdlib`, você poderia até configurá-lo para ser capaz de ler senhas criadas pelo **Django**, um plug-in de segurança do **Flask** ou muitos outros.\n\nAssim, você poderia, por exemplo, compartilhar os mesmos dados de um aplicativo Django em um banco de dados com um aplicativo FastAPI. Ou migrar gradualmente uma aplicação Django usando o mesmo banco de dados.\n\nE seus usuários poderiam fazer login tanto pela sua aplicação Django quanto pela sua aplicação **FastAPI**, ao mesmo tempo.\n\n///\n\n## Criar o hash e verificar as senhas { #hash-and-verify-the-passwords }\n\nImporte as ferramentas que nós precisamos de `pwdlib`.\n\nCrie uma instância de PasswordHash com as configurações recomendadas – ela será usada para criar o hash e verificar as senhas.\n\n/// tip | Dica\n\npwdlib também oferece suporte ao algoritmo de hashing bcrypt, mas não inclui algoritmos legados – para trabalhar com hashes antigos, é recomendado usar a biblioteca passlib.\n\nPor exemplo, você poderia usá-lo para ler e verificar senhas geradas por outro sistema (como Django), mas criar o hash de novas senhas com um algoritmo diferente, como o Argon2 ou o Bcrypt.\n\nE ser compatível com todos eles ao mesmo tempo.\n\n///\n\nCrie uma função utilitária para criar o hash de uma senha fornecida pelo usuário.\n\nE outra função utilitária para verificar se uma senha recebida corresponde ao hash armazenado.\n\nE outra para autenticar e retornar um usuário.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\nQuando `authenticate_user` é chamado com um nome de usuário que não existe no banco de dados, ainda executamos `verify_password` contra um hash fictício.\n\nIsso garante que o endpoint leve aproximadamente o mesmo tempo para responder, seja o nome de usuário válido ou não, prevenindo **timing attacks** que poderiam ser usados para enumerar nomes de usuário existentes.\n\n/// note | Nota\n\nSe você verificar o novo banco de dados (falso) `fake_users_db`, você verá como o hash da senha se parece agora: `\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`.\n\n///\n\n## Manipular tokens JWT { #handle-jwt-tokens }\n\nImporte os módulos instalados.\n\nCrie uma chave secreta aleatória que será usada para assinar os tokens JWT.\n\nPara gerar uma chave secreta aleatória e segura, use o comando:\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\nE copie a saída para a variável `SECRET_KEY` (não use a do exemplo).\n\nCrie uma variável `ALGORITHM` com o algoritmo usado para assinar o token JWT e defina como `\"HS256\"`.\n\nCrie uma variável para a expiração do token.\n\nDefina um modelo Pydantic que será usado no endpoint de token para a resposta.\n\nCrie uma função utilitária para gerar um novo token de acesso.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## Atualize as dependências { #update-the-dependencies }\n\nAtualize `get_current_user` para receber o mesmo token de antes, mas desta vez, usando tokens JWT.\n\nDecodifique o token recebido, verifique-o e retorne o usuário atual.\n\nSe o token for inválido, retorne um erro HTTP imediatamente.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## Atualize a *operação de rota* `/token` { #update-the-token-path-operation }\n\nCrie um `timedelta` com o tempo de expiração do token.\n\nCrie um token de acesso JWT real e o retorne.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### Detalhes técnicos sobre o \"sujeito\" `sub` do JWT { #technical-details-about-the-jwt-subject-sub }\n\nA especificação JWT diz que existe uma chave `sub`, com o sujeito do token.\n\nÉ opcional usá-la, mas é onde você colocaria a identificação do usuário, então nós estamos usando aqui.\n\nO JWT pode ser usado para outras coisas além de identificar um usuário e permitir que ele execute operações diretamente na sua API.\n\nPor exemplo, você poderia identificar um \"carro\" ou uma \"postagem de blog\".\n\nDepois, você poderia adicionar permissões sobre essa entidade, como \"dirigir\" (para o carro) ou \"editar\" (para o blog).\n\nE então, poderia dar esse token JWT para um usuário (ou bot), e ele poderia usá-lo para realizar essas ações (dirigir o carro ou editar o blog) sem sequer precisar ter uma conta, apenas com o token JWT que sua API gerou para isso.\n\nUsando essas ideias, o JWT pode ser usado para cenários muito mais sofisticados.\n\nNesses casos, várias dessas entidades poderiam ter o mesmo ID, digamos `foo` (um usuário `foo`, um carro `foo` e uma postagem de blog `foo`).\n\nEntão, para evitar colisões de ID, ao criar o token JWT para o usuário, você poderia prefixar o valor da chave `sub`, por exemplo, com `username:`. Assim, neste exemplo, o valor de `sub` poderia ser: `username:johndoe`.\n\nO importante a se lembrar é que a chave `sub` deve ter um identificador único em toda a aplicação e deve ser uma string.\n\n## Verifique { #check-it }\n\nExecute o servidor e vá para a documentação: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nVocê verá a interface de usuário assim:\n\n<img src=\"/img/tutorial/security/image07.png\">\n\nAutorize a aplicação da mesma maneira que antes.\n\nUsando as credenciais:\n\nUsername: `johndoe`\nPassword: `secret`\n\n/// check | Verifique\n\nObserve que em nenhuma parte do código está a senha em texto puro \"`secret`\", nós temos apenas o hash.\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\nChame o endpoint `/users/me/`, você receberá o retorno como:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\nSe você abrir as ferramentas de desenvolvedor, poderá ver que os dados enviados incluem apenas o token. A senha é enviada apenas na primeira requisição para autenticar o usuário e obter o token de acesso, mas não é enviada nas próximas requisições:\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | Nota\n\nPerceba que o cabeçalho `Authorization`, com o valor que começa com `Bearer `.\n\n///\n\n## Uso avançado com `scopes` { #advanced-usage-with-scopes }\n\nO OAuth2 tem a noção de \"scopes\" (escopos).\n\nVocê pode usá-los para adicionar um conjunto específico de permissões a um token JWT.\n\nEntão, você pode dar este token diretamente a um usuário ou a uma terceira parte para interagir com sua API com um conjunto de restrições.\n\nVocê pode aprender como usá-los e como eles são integrados ao **FastAPI** mais adiante no **Guia Avançado do Usuário**.\n\n## Recapitulação { #recap }\n\nCom o que você viu até agora, você pode configurar uma aplicação **FastAPI** segura usando padrões como OAuth2 e JWT.\n\nEm quase qualquer framework, lidar com a segurança se torna rapidamente um assunto bastante complexo.\n\nMuitos pacotes que simplificam bastante isso precisam fazer muitas concessões com o modelo de dados, o banco de dados e os recursos disponíveis. E alguns desses pacotes que simplificam demais na verdade têm falhas de segurança subjacentes.\n\n---\n\nO **FastAPI** não faz nenhuma concessão com nenhum banco de dados, modelo de dados ou ferramenta.\n\nEle oferece toda a flexibilidade para você escolher as opções que melhor se ajustam ao seu projeto.\n\nE você pode usar diretamente muitos pacotes bem mantidos e amplamente utilizados, como `pwdlib` e `PyJWT`, porque o **FastAPI** não exige mecanismos complexos para integrar pacotes externos.\n\nMas ele fornece as ferramentas para simplificar o processo o máximo possível, sem comprometer a flexibilidade, robustez ou segurança.\n\nE você pode usar e implementar protocolos padrão seguros, como o OAuth2, de uma maneira relativamente simples.\n\nVocê pode aprender mais no **Guia Avançado do Usuário** sobre como usar os \"scopes\" do OAuth2 para um sistema de permissões mais refinado, seguindo esses mesmos padrões. O OAuth2 com scopes é o mecanismo usado por muitos provedores grandes de autenticação, como o Facebook, Google, GitHub, Microsoft, X (Twitter), etc. para autorizar aplicativos de terceiros a interagir com suas APIs em nome de seus usuários.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/security/simple-oauth2.md",
    "content": "# Simples OAuth2 com senha e Bearer { #simple-oauth2-with-password-and-bearer }\n\nAgora vamos construir a partir do capítulo anterior e adicionar as partes que faltam para ter um fluxo de segurança completo.\n\n## Obtenha o `username` e a `password` { #get-the-username-and-password }\n\nÉ utilizado o utils de segurança da **FastAPI** para obter o `username` e a `password`.\n\nOAuth2 especifica que ao usar o \"password flow\" (fluxo de senha), que estamos usando, o cliente/usuário deve enviar os campos `username` e `password` como dados do formulário.\n\nE a especificação diz que os campos devem ser nomeados assim. Portanto, `user-name` ou `email` não funcionariam.\n\nMas não se preocupe, você pode mostrá-lo como quiser aos usuários finais no frontend.\n\nE seus modelos de banco de dados podem usar qualquer outro nome que você desejar.\n\nMas para a *operação de rota* de login, precisamos usar esses nomes para serem compatíveis com a especificação (e poder, por exemplo, usar o sistema integrado de documentação da API).\n\nA especificação também afirma que o `username` e a `password` devem ser enviados como dados de formulário (portanto, não há JSON aqui).\n\n### `scope` { #scope }\n\nA especificação também diz que o cliente pode enviar outro campo de formulário \"`scope`\".\n\nO nome do campo do formulário é `scope` (no singular), mas na verdade é uma longa string com \"escopos\" separados por espaços.\n\nCada “scope” é apenas uma string (sem espaços).\n\nNormalmente são usados para declarar permissões de segurança específicas, por exemplo:\n\n* `users:read` ou `users:write` são exemplos comuns.\n* `instagram_basic` é usado pelo Facebook e Instagram.\n* `https://www.googleapis.com/auth/drive` é usado pelo Google.\n\n/// info | Informação\n\nNo OAuth2, um \"scope\" é apenas uma string que declara uma permissão específica necessária.\n\nNão importa se tem outros caracteres como `:` ou se é uma URL.\n\nEsses detalhes são específicos da implementação.\n\nPara OAuth2 são apenas strings.\n\n///\n\n## Código para conseguir o `username` e a `password` { #code-to-get-the-username-and-password }\n\nAgora vamos usar os utilitários fornecidos pelo **FastAPI** para lidar com isso.\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\nPrimeiro, importe `OAuth2PasswordRequestForm` e use-o como uma dependência com `Depends` na *operação de rota* para `/token`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm` é uma dependência de classe que declara um corpo de formulário com:\n\n* O `username`.\n* A `password`.\n* Um campo `scope` opcional como uma string grande, composta de strings separadas por espaços.\n* Um `grant_type` opcional.\n\n/// tip | Dica\n\nA especificação OAuth2 na verdade *requer* um campo `grant_type` com um valor fixo de `password`, mas `OAuth2PasswordRequestForm` não o impõe.\n\nSe você precisar aplicá-lo, use `OAuth2PasswordRequestFormStrict` em vez de `OAuth2PasswordRequestForm`.\n\n///\n\n* Um `client_id` opcional (não precisamos dele em nosso exemplo).\n* Um `client_secret` opcional (não precisamos dele em nosso exemplo).\n\n/// info | Informação\n\nO `OAuth2PasswordRequestForm` não é uma classe especial para **FastAPI** como é `OAuth2PasswordBearer`.\n\n`OAuth2PasswordBearer` faz com que **FastAPI** saiba que é um esquema de segurança. Portanto, é adicionado dessa forma ao OpenAPI.\n\nMas `OAuth2PasswordRequestForm` é apenas uma dependência de classe que você mesmo poderia ter escrito ou poderia ter declarado os parâmetros do `Form` (formulário) diretamente.\n\nMas como é um caso de uso comum, ele é fornecido diretamente pelo **FastAPI**, apenas para facilitar.\n\n///\n\n### Use os dados do formulário { #use-the-form-data }\n\n/// tip | Dica\n\nA instância da classe de dependência `OAuth2PasswordRequestForm` não terá um atributo `scope` com a string longa separada por espaços, em vez disso, terá um atributo `scopes` com a lista real de strings para cada escopo enviado.\n\nNão estamos usando `scopes` neste exemplo, mas a funcionalidade está disponível se você precisar.\n\n///\n\nAgora, obtenha os dados do usuário do banco de dados (falso), usando o `username` do campo do formulário.\n\nSe não existir tal usuário, retornaremos um erro dizendo \"Incorrect username or password\".\n\nPara o erro, usamos a exceção `HTTPException`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### Confira a senha { #check-the-password }\n\nNeste ponto temos os dados do usuário do nosso banco de dados, mas não verificamos a senha.\n\nVamos colocar esses dados primeiro no modelo `UserInDB` do Pydantic.\n\nVocê nunca deve salvar senhas em texto simples, portanto, usaremos o sistema de hashing de senhas (falsas).\n\nSe as senhas não corresponderem, retornaremos o mesmo erro.\n\n#### Hashing de senha { #password-hashing }\n\n\"Hashing\" significa: converter algum conteúdo (uma senha neste caso) em uma sequência de bytes (apenas uma string) que parece algo sem sentido.\n\nSempre que você passa exatamente o mesmo conteúdo (exatamente a mesma senha), você obtém exatamente a mesma sequência aleatória de caracteres.\n\nMas você não pode converter a sequência aleatória de caracteres de volta para a senha.\n\n##### Porque usar hashing de senha { #why-use-password-hashing }\n\nSe o seu banco de dados for roubado, o ladrão não terá as senhas em texto simples dos seus usuários, apenas os hashes.\n\nAssim, o ladrão não poderá tentar usar essas mesmas senhas em outro sistema (como muitos usuários usam a mesma senha em todos os lugares, isso seria perigoso).\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### Sobre `**user_dict` { #about-user-dict }\n\n`UserInDB(**user_dict)` significa:\n\n*Passe as chaves e valores de `user_dict` diretamente como argumentos de valor-chave, equivalente a:*\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n\n/// info | Informação\n\nPara uma explicação mais completa de `**user_dict`, verifique [a documentação para **Extra Models**](../extra-models.md#about-user-in-dict).\n\n///\n\n## Retorne o token { #return-the-token }\n\nA resposta do endpoint `token` deve ser um objeto JSON.\n\nDeve ter um `token_type`. No nosso caso, como estamos usando tokens \"Bearer\", o tipo de token deve ser \"`bearer`\".\n\nE deve ter um `access_token`, com uma string contendo nosso token de acesso.\n\nPara este exemplo simples, seremos completamente inseguros e retornaremos o mesmo `username` do token.\n\n/// tip | Dica\n\nNo próximo capítulo, você verá uma implementação realmente segura, com hash de senha e tokens <abbr title=\"JSON Web Tokens\">JWT</abbr>.\n\nMas, por enquanto, vamos nos concentrar nos detalhes específicos de que precisamos.\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip | Dica\n\nPela especificação, você deve retornar um JSON com um `access_token` e um `token_type`, o mesmo que neste exemplo.\n\nIsso é algo que você mesmo deve fazer em seu código e certifique-se de usar essas chaves JSON.\n\nÉ quase a única coisa que você deve se lembrar de fazer corretamente, para estar em conformidade com as especificações.\n\nDe resto, **FastAPI** cuida disso para você.\n\n///\n\n## Atualize as dependências { #update-the-dependencies }\n\nAgora vamos atualizar nossas dependências.\n\nQueremos obter o `current_user` *somente* se este usuário estiver ativo.\n\nPortanto, criamos uma dependência adicional `get_current_active_user` que por sua vez usa `get_current_user` como dependência.\n\nAmbas as dependências retornarão apenas um erro HTTP se o usuário não existir ou se estiver inativo.\n\nPortanto, em nosso endpoint, só obteremos um usuário se o usuário existir, tiver sido autenticado corretamente e estiver ativo:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info | Informação\n\nO cabeçalho adicional `WWW-Authenticate` com valor `Bearer` que estamos retornando aqui também faz parte da especificação.\n\nQualquer código de status HTTP (erro) 401 \"UNAUTHORIZED\" também deve retornar um cabeçalho `WWW-Authenticate`.\n\nNo caso de tokens ao portador (nosso caso), o valor desse cabeçalho deve ser `Bearer`.\n\nNa verdade, você pode pular esse cabeçalho extra e ainda funcionaria.\n\nMas é fornecido aqui para estar em conformidade com as especificações.\n\nAlém disso, pode haver ferramentas que esperam e usam isso (agora ou no futuro) e que podem ser úteis para você ou seus usuários, agora ou no futuro.\n\nEsse é o benefício dos padrões...\n\n///\n\n## Veja em ação { #see-it-in-action }\n\nAbra o docs interativo: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n### Autentique-se { #authenticate }\n\nClique no botão \"Authorize\".\n\nUse as credenciais:\n\nUser: `johndoe`\n\nPassword: `secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\nApós autenticar no sistema, você verá assim:\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### Obtenha seus próprios dados de usuário { #get-your-own-user-data }\n\nAgora use a operação `GET` com o caminho `/users/me`.\n\nVocê obterá os dados do seu usuário, como:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\nSe você clicar no ícone de cadeado, sair e tentar a mesma operação novamente, receberá um erro HTTP 401 de:\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### Usuário inativo { #inactive-user }\n\nAgora tente com um usuário inativo, autentique-se com:\n\nUser: `alice`\n\nPassword: `secret2`\n\nE tente usar a operação `GET` com o caminho `/users/me`.\n\nVocê receberá um erro \"Usuário inativo\", como:\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## Recapitulando { #recap }\n\nAgora você tem as ferramentas para implementar um sistema de segurança completo baseado em `username` e `password` para sua API.\n\nUsando essas ferramentas, você pode tornar o sistema de segurança compatível com qualquer banco de dados e com qualquer usuário ou modelo de dados.\n\nO único detalhe que falta é que ainda não é realmente \"seguro\".\n\nNo próximo capítulo você verá como usar uma biblioteca de hashing de senha segura e tokens <abbr title=\"JSON Web Tokens\">JWT</abbr>.\n"
  },
  {
    "path": "docs/pt/docs/tutorial/server-sent-events.md",
    "content": "# Eventos Enviados pelo Servidor (SSE) { #server-sent-events-sse }\n\nVocê pode transmitir dados para o cliente usando Server-Sent Events (SSE).\n\nIsso é semelhante a [Stream de JSON Lines](stream-json-lines.md), mas usa o formato `text/event-stream`, que é suportado nativamente pelos navegadores com a [`EventSource` API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).\n\n/// info | Informação\n\nAdicionado no FastAPI 0.135.0.\n\n///\n\n## O que são Server-Sent Events? { #what-are-server-sent-events }\n\nSSE é um padrão para transmitir dados do servidor para o cliente via HTTP.\n\nCada evento é um pequeno bloco de texto com “campos” como `data`, `event`, `id` e `retry`, separados por linhas em branco.\n\nFica assim:\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE é comumente usado para streaming de chat de IA, notificações em tempo real, logs e observabilidade, e outros casos em que o servidor envia atualizações para o cliente.\n\n/// tip | Dica\n\nSe você quiser transmitir dados binários, por exemplo vídeo ou áudio, veja o guia avançado: [Stream de Dados](../advanced/stream-data.md).\n\n///\n\n## Transmitir SSE com FastAPI { #stream-sse-with-fastapi }\n\nPara transmitir SSE com FastAPI, use `yield` na sua função de operação de rota e defina `response_class=EventSourceResponse`.\n\nImporte `EventSourceResponse` de `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\nCada item produzido é codificado como JSON e enviado no campo `data:` de um evento SSE.\n\nSe você declarar o tipo de retorno como `AsyncIterable[Item]`, o FastAPI o usará para validar, documentar e serializar os dados com o Pydantic.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip | Dica\n\nComo o Pydantic fará a serialização no lado em **Rust**, você terá um desempenho muito maior do que se não declarar um tipo de retorno.\n\n///\n\n### *Funções de operação de rota* não assíncronas { #non-async-path-operation-functions }\n\nVocê também pode usar funções `def` normais (sem `async`) e usar `yield` da mesma forma.\n\nO FastAPI garantirá a execução correta para não bloquear o event loop.\n\nComo, neste caso, a função não é assíncrona, o tipo de retorno adequado seria `Iterable[Item]`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### Sem tipo de retorno { #no-return-type }\n\nVocê também pode omitir o tipo de retorno. O FastAPI usará o [`jsonable_encoder`](./encoder.md) para converter os dados e enviá-los.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\nSe você precisar definir campos de SSE como `event`, `id`, `retry` ou `comment`, você pode produzir objetos `ServerSentEvent` em vez de dados simples.\n\nImporte `ServerSentEvent` de `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\nO campo `data` é sempre codificado como JSON. Você pode passar qualquer valor que possa ser serializado como JSON, incluindo modelos do Pydantic.\n\n## Dados brutos { #raw-data }\n\nSe você precisar enviar dados sem codificação JSON, use `raw_data` em vez de `data`.\n\nIsto é útil para enviar texto pré-formatado, linhas de log ou valores <dfn title=\"um valor usado para indicar uma condição ou estado especial\">\"sentinela\"</dfn> especiais como `[DONE]`.\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note | Nota\n\n`data` e `raw_data` são mutuamente exclusivos. Você só pode definir um deles em cada `ServerSentEvent`.\n\n///\n\n## Retomando com `Last-Event-ID` { #resuming-with-last-event-id }\n\nQuando um navegador se reconecta após uma queda na conexão, ele envia o último `id` recebido no cabeçalho `Last-Event-ID`.\n\nVocê pode lê-lo como um parâmetro de cabeçalho e usá-lo para retomar o stream de onde o cliente parou:\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## SSE com POST { #sse-with-post }\n\nSSE funciona com qualquer método HTTP, não apenas `GET`.\n\nIsso é útil para protocolos como o [MCP](https://modelcontextprotocol.io) que fazem stream de SSE via `POST`:\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## Detalhes Técnicos { #technical-details }\n\nO FastAPI implementa algumas boas práticas de SSE prontas para uso.\n\n- Enviar um comentário de keep alive `ping` a cada 15 segundos quando não houver mensagens, para evitar que alguns proxies fechem a conexão, como sugerido na [especificação HTML: Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes).\n- Definir o cabeçalho `Cache-Control: no-cache` para evitar o cache do stream.\n- Definir o cabeçalho especial `X-Accel-Buffering: no` para evitar buffering em alguns proxies como o Nginx.\n\nVocê não precisa fazer nada, isso funciona automaticamente. 🤓\n"
  },
  {
    "path": "docs/pt/docs/tutorial/sql-databases.md",
    "content": "# Bancos de Dados SQL (Relacionais) { #sql-relational-databases }\n\n**FastAPI** não exige que você use um banco de dados SQL (relacional). Mas você pode usar **qualquer banco de dados** que quiser.\n\nAqui veremos um exemplo usando [SQLModel](https://sqlmodel.tiangolo.com/).\n\n**SQLModel** é construído sobre [SQLAlchemy](https://www.sqlalchemy.org/) e Pydantic. Ele foi criado pelo mesmo autor do **FastAPI** para ser o par perfeito para aplicações **FastAPI** que precisam usar **bancos de dados SQL**.\n\n/// tip | Dica\n\nVocê pode usar qualquer outra biblioteca de banco de dados SQL ou NoSQL que quiser (em alguns casos chamadas de <abbr title=\"Object Relational Mapper - Mapeador Objeto-Relacional: um termo sofisticado para uma biblioteca onde algumas classes representam tabelas SQL e instâncias representam linhas nessas tabelas\">\"ORMs\"</abbr>), o FastAPI não obriga você a usar nada. 😎\n\n///\n\nComo o SQLModel é baseado no SQLAlchemy, você pode facilmente usar **qualquer banco de dados suportado** pelo SQLAlchemy (o que também os torna suportados pelo SQLModel), como:\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server, etc.\n\nNeste exemplo, usaremos **SQLite**, porque ele usa um único arquivo e o Python tem suporte integrado. Assim, você pode copiar este exemplo e executá-lo como está.\n\nMais tarde, para sua aplicação em produção, você pode querer usar um servidor de banco de dados como o **PostgreSQL**.\n\n/// tip | Dica\n\nExiste um gerador de projetos oficial com **FastAPI** e **PostgreSQL** incluindo um frontend e mais ferramentas: [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\nEste é um tutorial muito simples e curto, se você quiser aprender sobre bancos de dados em geral, sobre SQL ou recursos mais avançados, acesse a [documentação do SQLModel](https://sqlmodel.tiangolo.com/).\n\n## Instalar o `SQLModel` { #install-sqlmodel }\n\nPrimeiro, certifique-se de criar seu [ambiente virtual](../virtual-environments.md), ativá-lo e, em seguida, instalar o `sqlmodel`:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## Crear o App com um Único Modelo { #create-the-app-with-a-single-model }\n\nVamos criar a primeira versão mais simples do app com um único modelo **SQLModel**.\n\nDepois, vamos melhorá-lo aumentando a segurança e versatilidade com **múltiplos modelos** abaixo. 🤓\n\n### Criar Modelos { #create-models }\n\nImporte o `SQLModel` e crie um modelo de banco de dados:\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\nA classe `Hero` é muito semelhante a um modelo Pydantic (na verdade, por baixo dos panos, ela *é um modelo Pydantic*).\n\nExistem algumas diferenças:\n\n* `table=True` informa ao SQLModel que este é um *modelo de tabela*, ele deve representar uma **tabela** no banco de dados SQL, não é apenas um *modelo de dados* (como seria qualquer outra classe Pydantic comum).\n\n* `Field(primary_key=True)` informa ao SQLModel que o `id` é a **chave primária** no banco de dados SQL (você pode aprender mais sobre chaves primárias SQL na documentação do SQLModel).\n\n    **Nota:** Usamos `int | None` para o campo de chave primária para que, no código Python, possamos *criar um objeto sem um `id`* (`id=None`), assumindo que o banco de dados irá *gerá-lo ao salvar*. O SQLModel entende que o banco de dados fornecerá o `id` e *define a coluna como um `INTEGER` não nulo* no esquema do banco de dados. Veja a [documentação do SQLModel sobre chaves primárias](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) para detalhes.\n\n* `Field(index=True)` informa ao SQLModel que ele deve criar um **índice SQL** para essa coluna, o que permitirá buscas mais rápidas no banco de dados ao ler dados filtrados por essa coluna.\n\n    O SQLModel saberá que algo declarado como `str` será uma coluna SQL do tipo `TEXT` (ou `VARCHAR`, dependendo do banco de dados).\n\n### Criar um Engine { #create-an-engine }\nUm `engine` SQLModel (por baixo dos panos, ele é na verdade um `engine` do SQLAlchemy) é o que **mantém as conexões** com o banco de dados.\n\nVocê teria **um único objeto `engine`** para todo o seu código se conectar ao mesmo banco de dados.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\nUsar `check_same_thread=False` permite que o FastAPI use o mesmo banco de dados SQLite em diferentes threads. Isso é necessário, pois **uma única requisição** pode usar **mais de uma thread** (por exemplo, em dependências).\n\nNão se preocupe, com a forma como o código está estruturado, garantiremos que usamos **uma única *sessão* SQLModel por requisição** mais tarde, isso é realmente o que o `check_same_thread` está tentando conseguir.\n\n### Criar as Tabelas { #create-the-tables }\n\nEm seguida, adicionamos uma função que usa `SQLModel.metadata.create_all(engine)` para **criar as tabelas** para todos os *modelos de tabela*.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### Criar uma Dependência de Sessão { #create-a-session-dependency }\n\nUma **`Session`** é o que armazena os **objetos na memória** e acompanha as alterações necessárias nos dados, para então **usar o `engine`** para se comunicar com o banco de dados.\n\nVamos criar uma **dependência** do FastAPI com `yield` que fornecerá uma nova `Session` para cada requisição. Isso é o que garante que usamos uma única sessão por requisição. 🤓\n\nEntão, criamos uma dependência `Annotated` chamada `SessionDep` para simplificar o restante do código que usará essa dependência.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### Criar Tabelas de Banco de Dados na Inicialização { #create-database-tables-on-startup }\n\nVamos criar as tabelas do banco de dados quando o aplicativo for iniciado.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\nAqui, criamos as tabelas em um evento de inicialização do aplicativo.\n\nPara produção, você provavelmente usaria um script de migração que é executado antes de iniciar seu app. 🤓\n\n/// tip | Dica\n\nO SQLModel terá utilitários de migração envolvendo o Alembic, mas por enquanto, você pode usar o [Alembic](https://alembic.sqlalchemy.org/en/latest/) diretamente.\n\n///\n\n### Criar um Hero { #create-a-hero }\n\nComo cada modelo SQLModel também é um modelo Pydantic, você pode usá-lo nas mesmas **anotações de tipo** que usaria para modelos Pydantic.\n\nPor exemplo, se você declarar um parâmetro do tipo `Hero`, ele será lido do **corpo JSON**.\n\nDa mesma forma, você pode declará-lo como o **tipo de retorno** da função, e então o formato dos dados aparecerá na interface de documentação automática da API.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\nAqui, usamos a dependência `SessionDep` (uma `Session`) para adicionar o novo `Hero` à instância `Session`, fazer commit das alterações no banco de dados, atualizar os dados no `hero` e então retorná-lo.\n\n### Ler Heroes { #read-heroes }\n\nPodemos **ler** `Hero`s do banco de dados usando um `select()`. Podemos incluir um `limit` e `offset` para paginar os resultados.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### Ler um Único Hero { #read-one-hero }\n\nPodemos **ler** um único `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### Deletar um Hero { #delete-a-hero }\n\nTambém podemos **deletar** um `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### Executar o App { #run-the-app }\n\nVocê pode executar o app:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nEntão, vá para a interface `/docs`, você verá que o **FastAPI** está usando esses **modelos** para **documentar** a API, e ele também os usará para **serializar** e **validar** os dados.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## Atualizar o App com Múltiplos Modelos { #update-the-app-with-multiple-models }\n\nAgora vamos **refatorar** este app um pouco para aumentar a **segurança** e **versatilidade**.\n\nSe você verificar o app anterior, na interface você pode ser que, até agora, ele permite que o cliente decida o `id` do `Hero` a ser criado. 😱\n\nNão deveríamos deixar isso acontecer, eles poderiam sobrescrever um `id` que já atribuimos na base de dados. Decidir o `id` deve ser feito pelo **backend** ou pelo **banco de dados**, **não pelo cliente**.\n\nAlém disso, criamos um `secret_name` para o hero, mas até agora estamos retornando ele em todos os lugares, isso não é muito **secreto**... 😅\n\nVamos corrigir essas coisas adicionando alguns **modelos extras**. Aqui é onde o SQLModel vai brilhar. ✨\n\n### Criar Múltiplos Modelos { #create-multiple-models }\n\nNo **SQLModel**, qualquer classe de modelo que tenha `table=True` é um **modelo de tabela**.\n\nE qualquer classe de modelo que não tenha `table=True` é um **modelo de dados**, esses são na verdade apenas modelos Pydantic (com alguns recursos extras pequenos). 🤓\n\nCom o SQLModel, podemos usar a **herança** para **evitar duplicação** de todos os campos em todos os casos.\n\n#### `HeroBase` - a classe base { #herobase-the-base-class }\n\nVamos começar com um modelo `HeroBase` que tem todos os **campos compartilhados** por todos os modelos:\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` - o *modelo de tabela* { #hero-the-table-model }\n\nEm seguida, vamos criar `Hero`, o verdadeiro *modelo de tabela*, com os **campos extras** que nem sempre estão nos outros modelos:\n\n* `id`\n* `secret_name`\n\nComo `Hero` herda de `HeroBase`, ele **também** tem os **campos** declarados em `HeroBase`, então todos os campos para `Hero` são:\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` - o *modelo de dados* público { #heropublic-the-public-data-model }\n\nEm seguida, criamos um modelo `HeroPublic`, que será **retornado** para os clientes da API.\n\nEle tem os mesmos campos que `HeroBase`, então não incluirá `secret_name`.\n\nFinalmente, a identidade dos nossos heróis está protegida! 🥷\n\nEle também declara novamente `id: int`. Ao fazer isso, estamos fazendo um **contrato** com os clientes da API, para que eles possam sempre esperar que o `id` estará lá e será um `int` (nunca será `None`).\n\n/// tip | Dica\n\nFazer com que o modelo de retorno garanta que um valor esteja sempre disponível e sempre seja um `int` (não `None`) é muito útil para os clientes da API, eles podem escrever código muito mais simples com essa certeza.\n\nAlém disso, **clientes gerados automaticamente** terão interfaces mais simples, para que os desenvolvedores que se comunicam com sua API possam ter uma experiência muito melhor trabalhando com sua API. 😎\n\n///\n\nTodos os campos em `HeroPublic` são os mesmos que em `HeroBase`, com `id` declarado como `int` (não `None`):\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` - o *modelo de dados* para criar um hero { #herocreate-the-data-model-to-create-a-hero }\n\nAgora criamos um modelo `HeroCreate`, este é o que **validará** os dados dos clientes.\n\nEle tem os mesmos campos que `HeroBase`, e também tem `secret_name`.\n\nAgora, quando os clientes **criarem um novo hero**, eles enviarão o `secret_name`, ele será armazenado no banco de dados, mas esses nomes secretos não serão retornados na API para os clientes.\n\n/// tip | Dica\n\nÉ assim que você trataria **senhas**. Receba-as, mas não as retorne na API.\n\nVocê também faria um **hash** com os valores das senhas antes de armazená-los, **nunca os armazene em texto simples**.\n\n///\n\nOs campos de `HeroCreate` são:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` - o *modelo de dados* para atualizar um hero { #heroupdate-the-data-model-to-update-a-hero }\n\nNão tínhamos uma maneira de **atualizar um hero** na versão anterior do app, mas agora com **múltiplos modelos**, podemos fazer isso. 🎉\n\nO *modelo de dados* `HeroUpdate` é um pouco especial, ele tem **todos os mesmos campos** que seriam necessários para criar um novo hero, mas todos os campos são **opcionais** (todos têm um valor padrão). Dessa forma, quando você atualizar um hero, poderá enviar apenas os campos que deseja atualizar.\n\nComo todos os **campos realmente mudam** (o tipo agora inclui `None` e eles agora têm um valor padrão de `None`), precisamos **declarar novamente** todos eles.\n\nNão precisamos herdar de `HeroBase`, pois estamos redeclarando todos os campos. Vou deixá-lo herdando apenas por consistência, mas isso não é necessário. É mais uma questão de gosto pessoal. 🤷\n\nOs campos de `HeroUpdate` são:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### Criar com `HeroCreate` e retornar um `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }\n\nAgora que temos **múltiplos modelos**, podemos atualizar as partes do app que os utilizam.\n\nRecebemos na requisição um *modelo de dados* `HeroCreate`, e a partir dele, criamos um *modelo de tabela* `Hero`.\n\nEsse novo *modelo de tabela* `Hero` terá os campos enviados pelo cliente, e também terá um `id` gerado pelo banco de dados.\n\nEm seguida, retornamos o mesmo *modelo de tabela* `Hero` como está na função. Mas como declaramos o `response_model` com o *modelo de dados* `HeroPublic`, o **FastAPI** usará `HeroPublic` para validar e serializar os dados.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | Dica\n\nAgora usamos `response_model=HeroPublic` em vez da **anotação de tipo de retorno** `-> HeroPublic` porque o valor que estamos retornando na verdade *não* é um `HeroPublic`.\n\nSe tivéssemos declarado `-> HeroPublic`, seu editor e o linter reclamariam (com razão) que você está retornando um `Hero` em vez de um `HeroPublic`.\n\nAo declará-lo no `response_model`, estamos dizendo ao **FastAPI** para fazer o seu trabalho, sem interferir nas anotações de tipo e na ajuda do seu editor e de outras ferramentas.\n\n///\n\n### Ler Heroes com `HeroPublic` { #read-heroes-with-heropublic }\n\nPodemos fazer o mesmo que antes para **ler** `Hero`s, novamente, usamos `response_model=list[HeroPublic]` para garantir que os dados sejam validados e serializados corretamente.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### Ler Um Hero com `HeroPublic` { #read-one-hero-with-heropublic }\n\nPodemos **ler** um único herói:\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### Atualizar um Hero com `HeroUpdate` { #update-a-hero-with-heroupdate }\n\nPodemos **atualizar um hero**. Para isso, usamos uma operação HTTP `PATCH`.\n\nE no código, obtemos um `dict` com todos os dados enviados pelo cliente, **apenas os dados enviados pelo cliente**, excluindo quaisquer valores que estariam lá apenas por serem os valores padrão. Para fazer isso, usamos `exclude_unset=True`. Este é o truque principal. 🪄\n\nEm seguida, usamos `hero_db.sqlmodel_update(hero_data)` para atualizar o `hero_db` com os dados de `hero_data`.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### Deletar um Hero Novamente { #delete-a-hero-again }\n\n**Deletar** um hero permanece praticamente o mesmo.\n\nNão vamos satisfazer o desejo de refatorar tudo neste aqui. 😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### Executar o App Novamente { #run-the-app-again }\n\nVocê pode executar o app novamente:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nSe você for para a interface `/docs` da API, verá que agora ela está atualizada e não esperará receber o `id` do cliente ao criar um hero, etc.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## Recapitulando { #recap }\n\nVocê pode usar [**SQLModel**](https://sqlmodel.tiangolo.com/) para interagir com um banco de dados SQL e simplificar o código com *modelos de dados* e *modelos de tabela*.\n\nVocê pode aprender muito mais na documentação do **SQLModel**, há um mini [tutorial sobre como usar SQLModel com **FastAPI**](https://sqlmodel.tiangolo.com/tutorial/fastapi/) mais longo. 🚀\n"
  },
  {
    "path": "docs/pt/docs/tutorial/static-files.md",
    "content": "# Arquivos Estáticos { #static-files }\n\nVocê pode servir arquivos estáticos automaticamente a partir de um diretório usando `StaticFiles`.\n\n## Use `StaticFiles` { #use-staticfiles }\n\n* Importe `StaticFiles`.\n* \"Monte\" uma instância de `StaticFiles()` em um path específico.\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | Detalhes Técnicos\n\nVocê também pode usar `from starlette.staticfiles import StaticFiles`.\n\nO **FastAPI** fornece o mesmo que `starlette.staticfiles` como `fastapi.staticfiles` apenas como uma conveniência para você, o desenvolvedor. Mas na verdade vem diretamente da Starlette.\n\n///\n\n### O que é \"Montagem\" { #what-is-mounting }\n\n\"Montagem\" significa adicionar uma aplicação completamente \"independente\" em um path específico, que então cuida de lidar com todos os sub-paths.\n\nIsso é diferente de usar um `APIRouter`, pois uma aplicação montada é completamente independente. A OpenAPI e a documentação da sua aplicação principal não incluirão nada da aplicação montada, etc.\n\nVocê pode ler mais sobre isso no [Guia Avançado do Usuário](../advanced/index.md).\n\n## Detalhes { #details }\n\nO primeiro `\"/static\"` refere-se ao sub-path no qual este \"subaplicativo\" será \"montado\". Assim, qualquer path que comece com `\"/static\"` será tratado por ele.\n\nO `directory=\"static\"` refere-se ao nome do diretório que contém seus arquivos estáticos.\n\nO `name=\"static\"` dá a ele um nome que pode ser usado internamente pelo **FastAPI**.\n\nTodos esses parâmetros podem ser diferentes de \"`static`\", ajuste-os de acordo com as necessidades e detalhes específicos da sua própria aplicação.\n\n## Mais informações { #more-info }\n\nPara mais detalhes e opções, consulte [a documentação da Starlette sobre Arquivos Estáticos](https://www.starlette.dev/staticfiles/).\n"
  },
  {
    "path": "docs/pt/docs/tutorial/stream-json-lines.md",
    "content": "# Stream de JSON Lines { #stream-json-lines }\n\nVocê pode ter uma sequência de dados que deseja enviar em um \"**Stream**\"; é possível fazer isso com **JSON Lines**.\n\n/// info | Informação\n\nAdicionado no FastAPI 0.134.0.\n\n///\n\n## O que é um Stream? { #what-is-a-stream }\n\n\"**Streaming**\" de dados significa que sua aplicação começará a enviar itens ao cliente sem esperar que toda a sequência esteja pronta.\n\nAssim, ela envia o primeiro item, o cliente o recebe e começa a processá-lo, enquanto você ainda pode estar produzindo o próximo item.\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\nPode até ser um Stream infinito, em que você continua enviando dados.\n\n## JSON Lines { #json-lines }\n\nNesses casos, é comum enviar \"**JSON Lines**\", um formato em que você envia um objeto JSON por linha.\n\nUma response teria um tipo de conteúdo `application/jsonl` (em vez de `application/json`) e o corpo seria algo como:\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\nÉ muito semelhante a um array JSON (equivalente a uma list do Python), mas em vez de estar envolto em `[]` e ter `,` entre os itens, há **um objeto JSON por linha**, separados por um caractere de nova linha.\n\n/// info | Informação\n\nO ponto importante é que sua aplicação poderá produzir cada linha em sequência, enquanto o cliente consome as anteriores.\n\n///\n\n/// note | Detalhes Técnicos\n\nComo cada objeto JSON será separado por uma nova linha, eles não podem conter caracteres de nova linha literais em seu conteúdo, mas podem conter novas linhas com escape (`\\n`), o que faz parte do padrão JSON.\n\nMas, normalmente, você não precisará se preocupar com isso, é feito automaticamente, continue lendo. 🤓\n\n///\n\n## Casos de uso { #use-cases }\n\nVocê pode usar isso para transmitir dados de um serviço de **IA LLM**, de **logs** ou **telemetria**, ou de outros tipos de dados que possam ser estruturados em itens **JSON**.\n\n/// tip | Dica\n\nSe você quiser transmitir dados binários, por exemplo vídeo ou áudio, confira o guia avançado: [Stream Data](../advanced/stream-data.md).\n\n///\n\n## Stream de JSON Lines com FastAPI { #stream-json-lines-with-fastapi }\n\nPara transmitir JSON Lines com FastAPI, em vez de usar `return` na sua *função de operação de rota*, use `yield` para produzir cada item em sequência.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\nSe cada item JSON que você quer enviar de volta for do tipo `Item` (um modelo Pydantic) e a função for assíncrona, você pode declarar o tipo de retorno como `AsyncIterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\nSe você declarar o tipo de retorno, o FastAPI o usará para **validar** os dados, **documentá-los** no OpenAPI, **filtrá-los** e **serializá-los** usando o Pydantic.\n\n/// tip | Dica\n\nComo o Pydantic fará a serialização no lado em **Rust**, você terá uma **performance** muito maior do que se não declarar um tipo de retorno.\n\n///\n\n### Funções de operação de rota não assíncronas { #non-async-path-operation-functions }\n\nVocê também pode usar funções `def` normais (sem `async`) e usar `yield` da mesma forma.\n\nO FastAPI garantirá que sejam executadas corretamente para não bloquear o event loop.\n\nComo, neste caso, a função não é assíncrona, o tipo de retorno adequado seria `Iterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### Sem tipo de retorno { #no-return-type }\n\nVocê também pode omitir o tipo de retorno. O FastAPI então usará o [`jsonable_encoder`](./encoder.md) para converter os dados em algo que possa ser serializado para JSON e depois enviá-los como JSON Lines.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## Eventos enviados pelo servidor (SSE) { #server-sent-events-sse }\n\nO FastAPI também tem suporte de primeira classe a Server-Sent Events (SSE), que são bastante semelhantes, mas com alguns detalhes extras. Você pode aprender sobre eles no próximo capítulo: [Eventos enviados pelo servidor (SSE)](server-sent-events.md). 🤓\n"
  },
  {
    "path": "docs/pt/docs/tutorial/testing.md",
    "content": "# Testando { #testing }\n\nGraças ao [Starlette](https://www.starlette.dev/testclient/), testar aplicações **FastAPI** é fácil e agradável.\n\nEle é baseado no [HTTPX](https://www.python-httpx.org), que por sua vez é projetado com base em Requests, por isso é muito familiar e intuitivo.\n\nCom ele, você pode usar o [pytest](https://docs.pytest.org/) diretamente com **FastAPI**.\n\n## Usando `TestClient` { #using-testclient }\n\n/// info | Informação\n\nPara usar o `TestClient`, primeiro instale [`httpx`](https://www.python-httpx.org).\n\nCertifique-se de criar um [ambiente virtual](../virtual-environments.md), ativá-lo e instalá-lo, por exemplo:\n\n```console\n$ pip install httpx\n```\n\n///\n\nImporte `TestClient`.\n\nCrie um `TestClient` passando sua aplicação **FastAPI** para ele.\n\nCrie funções com um nome que comece com `test_` (essa é a convenção padrão do `pytest`).\n\nUse o objeto `TestClient` da mesma forma que você faz com `httpx`.\n\nEscreva instruções `assert` simples com as expressões Python padrão que você precisa verificar (novamente, `pytest` padrão).\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip | Dica\n\nObserve que as funções de teste são `def` normais, não `async def`.\n\nE as chamadas para o cliente também são chamadas normais, não usando `await`.\n\nIsso permite que você use `pytest` diretamente sem complicações.\n\n///\n\n/// note | Detalhes Técnicos\n\nVocê também pode usar `from starlette.testclient import TestClient`.\n\n**FastAPI** fornece o mesmo `starlette.testclient` que `fastapi.testclient` apenas como uma conveniência para você, o desenvolvedor. Mas ele vem diretamente da Starlette.\n\n///\n\n/// tip | Dica\n\nSe você quiser chamar funções `async` em seus testes além de enviar solicitações à sua aplicação FastAPI (por exemplo, funções de banco de dados assíncronas), dê uma olhada em [Testes assíncronos](../advanced/async-tests.md) no tutorial avançado.\n\n///\n\n## Separando testes { #separating-tests }\n\nEm uma aplicação real, você provavelmente teria seus testes em um arquivo diferente.\n\nE sua aplicação **FastAPI** também pode ser composta de vários arquivos/módulos, etc.\n\n### Arquivo da aplicação **FastAPI** { #fastapi-app-file }\n\nDigamos que você tenha uma estrutura de arquivo conforme descrito em [Aplicações maiores](bigger-applications.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\nNo arquivo `main.py` você tem sua aplicação **FastAPI**:\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### Arquivo de teste { #testing-file }\n\nEntão você poderia ter um arquivo `test_main.py` com seus testes. Ele poderia estar no mesmo pacote Python (o mesmo diretório com um arquivo `__init__.py`):\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nComo esse arquivo está no mesmo pacote, você pode usar importações relativas para importar o objeto `app` do módulo `main` (`main.py`):\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n...e ter o código para os testes como antes.\n\n## Testando: exemplo estendido { #testing-extended-example }\n\nAgora vamos estender este exemplo e adicionar mais detalhes para ver como testar diferentes partes.\n\n### Arquivo de aplicação **FastAPI** estendido { #extended-fastapi-app-file }\n\nVamos continuar com a mesma estrutura de arquivo de antes:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nDigamos que agora o arquivo `main.py` com sua aplicação **FastAPI** tenha algumas outras **operações de rotas**.\n\nEle tem uma operação `GET` que pode retornar um erro.\n\nEle tem uma operação `POST` que pode retornar vários erros.\n\nAmbas as *operações de rotas* requerem um cabeçalho `X-Token`.\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### Arquivo de teste estendido { #extended-testing-file }\n\nVocê pode então atualizar `test_main.py` com os testes estendidos:\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\nSempre que você precisar que o cliente passe informações na requisição e não souber como, você pode pesquisar (no Google) como fazer isso no `httpx`, ou até mesmo como fazer isso com `requests`, já que o design do HTTPX é baseado no design do Requests.\n\nDepois é só fazer o mesmo nos seus testes.\n\nPor exemplo:\n\n* Para passar um parâmetro *path* ou *query*, adicione-o à própria URL.\n* Para passar um corpo JSON, passe um objeto Python (por exemplo, um `dict`) para o parâmetro `json`.\n* Se você precisar enviar *Dados de Formulário* em vez de JSON, use o parâmetro `data`.\n* Para passar *headers*, use um `dict` no parâmetro `headers`.\n* Para *cookies*, um `dict` no parâmetro `cookies`.\n\nPara mais informações sobre como passar dados para o backend (usando `httpx` ou `TestClient`), consulte a [documentação do HTTPX](https://www.python-httpx.org).\n\n/// info | Informação\n\nObserve que o `TestClient` recebe dados que podem ser convertidos para JSON, não para modelos Pydantic.\n\nSe você tiver um modelo Pydantic em seu teste e quiser enviar seus dados para o aplicativo durante o teste, poderá usar o `jsonable_encoder` descrito em [Codificador compatível com JSON](encoder.md).\n\n///\n\n## Execute-o { #run-it }\n\nDepois disso, você só precisa instalar o `pytest`.\n\nCertifique-se de criar um [ambiente virtual](../virtual-environments.md), ativá-lo e instalá-lo, por exemplo:\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\nEle detectará os arquivos e os testes automaticamente, os executará e informará os resultados para você.\n\nExecute os testes com:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/pt/docs/virtual-environments.md",
    "content": "# Ambientes Virtuais { #virtual-environments }\n\nAo trabalhar em projetos Python, você provavelmente deveria usar um **ambiente virtual** (ou um mecanismo similar) para isolar os pacotes que você instala para cada projeto.\n\n/// info | Informação\n\nSe você já sabe sobre ambientes virtuais, como criá-los e usá-los, talvez seja melhor pular esta seção. 🤓\n\n///\n\n/// tip | Dica\n\nUm **ambiente virtual** é diferente de uma **variável de ambiente**.\n\nUma **variável de ambiente** é uma variável no sistema que pode ser usada por programas.\n\nUm **ambiente virtual** é um diretório com alguns arquivos.\n\n///\n\n/// info | Informação\n\nEsta página lhe ensinará como usar **ambientes virtuais** e como eles funcionam.\n\nSe você estiver pronto para adotar uma **ferramenta que gerencia tudo** para você (incluindo a instalação do Python), experimente [uv](https://github.com/astral-sh/uv).\n\n///\n\n## Criar um Projeto { #create-a-project }\n\nPrimeiro, crie um diretório para seu projeto.\n\nO que normalmente faço é criar um diretório chamado `code` dentro do meu diretório home/user.\n\nE dentro disso eu crio um diretório por projeto.\n\n<div class=\"termy\">\n\n```console\n// Vá para o diretório inicial\n$ cd\n// Crie um diretório para todos os seus projetos de código\n$ mkdir code\n// Entre nesse diretório de código\n$ cd code\n// Crie um diretório para este projeto\n$ mkdir awesome-project\n// Entre no diretório do projeto\n$ cd awesome-project\n```\n\n</div>\n\n## Crie um ambiente virtual { #create-a-virtual-environment }\n\nAo começar a trabalhar em um projeto Python **pela primeira vez**, crie um ambiente virtual **<dfn title=\"existem outras opções, esta é uma diretriz simples\">dentro do seu projeto</dfn>**.\n\n/// tip | Dica\n\nVocê só precisa fazer isso **uma vez por projeto**, não toda vez que trabalhar.\n\n///\n\n//// tab | `venv`\n\nPara criar um ambiente virtual, você pode usar o módulo `venv` que vem com o Python.\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | O que esse comando significa\n\n* `python`: usa o programa chamado `python`\n* `-m`: chama um módulo como um script, nós diremos a ele qual módulo vem em seguida\n* `venv`: usa o módulo chamado `venv` que normalmente vem instalado com o Python\n* `.venv`: cria o ambiente virtual no novo diretório `.venv`\n\n///\n\n////\n\n//// tab | `uv`\n\nSe você tiver [`uv`](https://github.com/astral-sh/uv) instalado, poderá usá-lo para criar um ambiente virtual.\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip | Dica\n\nPor padrão, `uv` criará um ambiente virtual em um diretório chamado `.venv`.\n\nMas você pode personalizá-lo passando um argumento adicional com o nome do diretório.\n\n///\n\n////\n\nEsse comando cria um novo ambiente virtual em um diretório chamado `.venv`.\n\n/// details | `.venv` ou outro nome\n\nVocê pode criar o ambiente virtual em um diretório diferente, mas há uma convenção para chamá-lo de `.venv`.\n\n///\n\n## Ative o ambiente virtual { #activate-the-virtual-environment }\n\nAtive o novo ambiente virtual para que qualquer comando Python que você executar ou pacote que você instalar o utilize.\n\n/// tip | Dica\n\nFaça isso **toda vez** que iniciar uma **nova sessão de terminal** para trabalhar no projeto.\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nOu se você usa o Bash para Windows (por exemplo, [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip | Dica\n\nToda vez que você instalar um **novo pacote** naquele ambiente, **ative** o ambiente novamente.\n\nIsso garante que, se você usar um **programa de terminal (<abbr title=\"command line interface - interface de linha de comando\">CLI</abbr>)** instalado por esse pacote, você usará aquele do seu ambiente virtual e não qualquer outro que possa ser instalado globalmente, provavelmente com uma versão diferente do que você precisa.\n\n///\n\n## Verifique se o ambiente virtual está ativo { #check-the-virtual-environment-is-active }\n\nVerifique se o ambiente virtual está ativo (o comando anterior funcionou).\n\n/// tip | Dica\n\nIsso é **opcional**, mas é uma boa maneira de **verificar** se tudo está funcionando conforme o esperado e se você está usando o ambiente virtual pretendido.\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\nSe ele mostrar o binário `python` em `.venv/bin/python`, dentro do seu projeto (neste caso `awesome-project`), então funcionou. 🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\nSe ele mostrar o binário `python` em `.venv\\Scripts\\python`, dentro do seu projeto (neste caso `awesome-project`), então funcionou. 🎉\n\n////\n\n## Atualizar `pip` { #upgrade-pip }\n\n/// tip | Dica\n\nSe você usar [`uv`](https://github.com/astral-sh/uv), você o usará para instalar coisas em vez do `pip`, então não precisará atualizar o `pip`. 😎\n\n///\n\nSe você estiver usando `pip` para instalar pacotes (ele vem por padrão com o Python), você deveria **atualizá-lo** para a versão mais recente.\n\nMuitos erros exóticos durante a instalação de um pacote são resolvidos apenas atualizando o `pip` primeiro.\n\n/// tip | Dica\n\nNormalmente, você faria isso **uma vez**, logo após criar o ambiente virtual.\n\n///\n\nCertifique-se de que o ambiente virtual esteja ativo (com o comando acima) e execute:\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip | Dica\n\nÀs vezes, você pode receber um erro **`No module named pip`** ao tentar atualizar o pip.\n\nSe isso acontecer, instale e atualize o pip usando o comando abaixo:\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\nEsse comando instalará o pip caso ele ainda não esteja instalado e também garante que a versão instalada do pip seja pelo menos tão recente quanto a disponível em `ensurepip`.\n\n///\n\n## Adicionar `.gitignore` { #add-gitignore }\n\nSe você estiver usando **Git** (você deveria), adicione um arquivo `.gitignore` para excluir tudo em seu `.venv` do Git.\n\n/// tip | Dica\n\nSe você usou [`uv`](https://github.com/astral-sh/uv) para criar o ambiente virtual, ele já fez isso para você, você pode pular esta etapa. 😎\n\n///\n\n/// tip | Dica\n\nFaça isso **uma vez**, logo após criar o ambiente virtual.\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | O que esse comando significa\n\n* `echo \"*\"`: irá \"imprimir\" o texto `*` no terminal (a próxima parte muda isso um pouco)\n* `>`: qualquer coisa impressa no terminal pelo comando à esquerda de `>` não deve ser impressa, mas sim escrita no arquivo que vai à direita de `>`\n* `.gitignore`: o nome do arquivo onde o texto deve ser escrito\n\nE `*` para Git significa \"tudo\". Então, ele ignorará tudo no diretório `.venv`.\n\nEsse comando criará um arquivo `.gitignore` com o conteúdo:\n\n```gitignore\n*\n```\n\n///\n\n## Instalar Pacotes { #install-packages }\n\nApós ativar o ambiente, você pode instalar pacotes nele.\n\n/// tip | Dica\n\nFaça isso **uma vez** ao instalar ou atualizar os pacotes que seu projeto precisa.\n\nSe precisar atualizar uma versão ou adicionar um novo pacote, você **fará isso novamente**.\n\n///\n\n### Instalar pacotes diretamente { #install-packages-directly }\n\nSe estiver com pressa e não quiser usar um arquivo para declarar os requisitos de pacote do seu projeto, você pode instalá-los diretamente.\n\n/// tip | Dica\n\nÉ uma (muito) boa ideia colocar os pacotes e versões que seu programa precisa em um arquivo (por exemplo `requirements.txt` ou `pyproject.toml`).\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nSe você tem o [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### Instalar a partir de `requirements.txt` { #install-from-requirements-txt }\n\nSe você tiver um `requirements.txt`, agora poderá usá-lo para instalar seus pacotes.\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nSe você tem o [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\nUm `requirements.txt` com alguns pacotes poderia se parecer com:\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## Execute seu programa { #run-your-program }\n\nDepois de ativar o ambiente virtual, você pode executar seu programa, e ele usará o Python dentro do seu ambiente virtual com os pacotes que você instalou lá.\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## Configure seu editor { #configure-your-editor }\n\nVocê provavelmente usaria um editor. Certifique-se de configurá-lo para usar o mesmo ambiente virtual que você criou (ele provavelmente o detectará automaticamente) para que você possa obter preenchimento automático e erros em linha.\n\nPor exemplo:\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip | Dica\n\nNormalmente, você só precisa fazer isso **uma vez**, ao criar o ambiente virtual.\n\n///\n\n## Desativar o ambiente virtual { #deactivate-the-virtual-environment }\n\nQuando terminar de trabalhar no seu projeto, você pode **desativar** o ambiente virtual.\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\nDessa forma, quando você executar `python`, ele não tentará executá-lo naquele ambiente virtual com os pacotes instalados nele.\n\n## Pronto para trabalhar { #ready-to-work }\n\nAgora você está pronto para começar a trabalhar no seu projeto.\n\n\n\n/// tip | Dica\n\nVocê quer entender o que é tudo isso acima?\n\nContinue lendo. 👇🤓\n\n///\n\n## Por que ambientes virtuais { #why-virtual-environments }\n\nPara trabalhar com o FastAPI, você precisa instalar o [Python](https://www.python.org/).\n\nDepois disso, você precisará **instalar** o FastAPI e quaisquer outros **pacotes** que queira usar.\n\nPara instalar pacotes, você normalmente usaria o comando `pip` que vem com o Python (ou alternativas semelhantes).\n\nNo entanto, se você usar `pip` diretamente, os pacotes serão instalados no seu **ambiente Python global** (a instalação global do Python).\n\n### O Problema { #the-problem }\n\nEntão, qual é o problema em instalar pacotes no ambiente global do Python?\n\nEm algum momento, você provavelmente acabará escrevendo muitos programas diferentes que dependem de **pacotes diferentes**. E alguns desses projetos em que você trabalha dependerão de **versões diferentes** do mesmo pacote. 😱\n\nPor exemplo, você pode criar um projeto chamado `philosophers-stone`, este programa depende de outro pacote chamado **`harry`, usando a versão `1`**. Então, você precisa instalar `harry`.\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n\nEntão, em algum momento depois, você cria outro projeto chamado `prisoner-of-azkaban`, e esse projeto também depende de `harry`, mas esse projeto precisa do **`harry` versão `3`**.\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]\n```\n\nMas agora o problema é que, se você instalar os pacotes globalmente (no ambiente global) em vez de em um **ambiente virtual** local, você terá que escolher qual versão do `harry` instalar.\n\nSe você quiser executar `philosophers-stone`, precisará primeiro instalar `harry` versão `1`, por exemplo com:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\nE então você acabaria com `harry` versão `1` instalado em seu ambiente Python global.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\nMas se você quiser executar `prisoner-of-azkaban`, você precisará desinstalar `harry` versão `1` e instalar `harry` versão `3` (ou apenas instalar a versão `3` desinstalaria automaticamente a versão `1`).\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\nE então você acabaria com `harry` versão `3` instalado em seu ambiente Python global.\n\nE se você tentar executar `philosophers-stone` novamente, há uma chance de que **não funcione** porque ele precisa de `harry` versão `1`.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --> |requires| harry-3\n    end\n```\n\n/// tip | Dica\n\nÉ muito comum em pacotes Python tentar ao máximo **evitar alterações drásticas** em **novas versões**, mas é melhor prevenir do que remediar e instalar versões mais recentes intencionalmente e, quando possível, executar os testes para verificar se tudo está funcionando corretamente.\n\n///\n\nAgora, imagine isso com **muitos** outros **pacotes** dos quais todos os seus **projetos dependem**. Isso é muito difícil de gerenciar. E você provavelmente acabaria executando alguns projetos com algumas **versões incompatíveis** dos pacotes, e não saberia por que algo não está funcionando.\n\nAlém disso, dependendo do seu sistema operacional (por exemplo, Linux, Windows, macOS), ele pode ter vindo com o Python já instalado. E, nesse caso, provavelmente tinha alguns pacotes pré-instalados com algumas versões específicas **necessárias para o seu sistema**. Se você instalar pacotes no ambiente global do Python, poderá acabar **quebrando** alguns dos programas que vieram com seu sistema operacional.\n\n## Onde os pacotes são instalados { #where-are-packages-installed }\n\nQuando você instala o Python, ele cria alguns diretórios com alguns arquivos no seu computador.\n\nAlguns desses diretórios são os responsáveis ​​por ter todos os pacotes que você instala.\n\nQuando você executa:\n\n<div class=\"termy\">\n\n```console\n// Não execute isso agora, é apenas um exemplo 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\nIsso fará o download de um arquivo compactado com o código FastAPI, normalmente do [PyPI](https://pypi.org/project/fastapi/).\n\nEle também fará o **download** de arquivos para outros pacotes dos quais o FastAPI depende.\n\nEm seguida, ele **extrairá** todos esses arquivos e os colocará em um diretório no seu computador.\n\nPor padrão, ele colocará os arquivos baixados e extraídos no diretório que vem com a instalação do Python, que é o **ambiente global**.\n\n## O que são ambientes virtuais { #what-are-virtual-environments }\n\nA solução para os problemas de ter todos os pacotes no ambiente global é usar um **ambiente virtual para cada projeto** em que você trabalha.\n\nUm ambiente virtual é um **diretório**, muito semelhante ao global, onde você pode instalar os pacotes para um projeto.\n\nDessa forma, cada projeto terá seu próprio ambiente virtual (diretório `.venv`) com seus próprios pacotes.\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) --->|requires| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --->|requires| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## O que significa ativar um ambiente virtual { #what-does-activating-a-virtual-environment-mean }\n\nQuando você ativa um ambiente virtual, por exemplo com:\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nOu se você usa o Bash para Windows (por exemplo, [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\nEsse comando criará ou modificará algumas [variáveis ​​de ambiente](environment-variables.md) que estarão disponíveis para os próximos comandos.\n\nUma dessas variáveis ​​é a variável `PATH`.\n\n/// tip | Dica\n\nVocê pode aprender mais sobre a variável de ambiente `PATH` na seção [Variáveis ​​de ambiente](environment-variables.md#path-environment-variable).\n\n///\n\nA ativação de um ambiente virtual adiciona seu caminho `.venv/bin` (no Linux e macOS) ou `.venv\\Scripts` (no Windows) à variável de ambiente `PATH`.\n\nDigamos que antes de ativar o ambiente, a variável `PATH` estava assim:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nIsso significa que o sistema procuraria programas em:\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\nIsso significa que o sistema procuraria programas em:\n\n* `C:\\Windows\\System32`\n\n////\n\nApós ativar o ambiente virtual, a variável `PATH` ficaria mais ou menos assim:\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nIsso significa que o sistema agora começará a procurar primeiro por programas em:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\nantes de procurar nos outros diretórios.\n\nEntão, quando você digita `python` no terminal, o sistema encontrará o programa Python em\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\ne usa esse.\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\nIsso significa que o sistema agora começará a procurar primeiro por programas em:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\nantes de procurar nos outros diretórios.\n\nEntão, quando você digita `python` no terminal, o sistema encontrará o programa Python em\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\ne usa esse.\n\n////\n\nUm detalhe importante é que ele colocará o caminho do ambiente virtual no **início** da variável `PATH`. O sistema o encontrará **antes** de encontrar qualquer outro Python disponível. Dessa forma, quando você executar `python`, ele usará o Python **do ambiente virtual** em vez de qualquer outro `python` (por exemplo, um `python` de um ambiente global).\n\nAtivar um ambiente virtual também muda algumas outras coisas, mas esta é uma das mais importantes.\n\n## Verificando um ambiente virtual { #checking-a-virtual-environment }\n\nAo verificar se um ambiente virtual está ativo, por exemplo com:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\nIsso significa que o programa `python` que será usado é aquele **no ambiente virtual**.\n\nvocê usa `which` no Linux e macOS e `Get-Command` no Windows PowerShell.\n\nA maneira como esse comando funciona é que ele vai e verifica na variável de ambiente `PATH`, passando por **cada caminho em ordem**, procurando pelo programa chamado `python`. Uma vez que ele o encontre, ele **mostrará o caminho** para esse programa.\n\nA parte mais importante é que quando você chama `python`, esse é exatamente o \"`python`\" que será executado.\n\nAssim, você pode confirmar se está no ambiente virtual correto.\n\n/// tip | Dica\n\nÉ fácil ativar um ambiente virtual, obter um Python e então **ir para outro projeto**.\n\nE o segundo projeto **não funcionaria** porque você está usando o **Python incorreto**, de um ambiente virtual para outro projeto.\n\nÉ útil poder verificar qual `python` está sendo usado. 🤓\n\n///\n\n## Por que desativar um ambiente virtual { #why-deactivate-a-virtual-environment }\n\nPor exemplo, você pode estar trabalhando em um projeto `philosophers-stone`, **ativar esse ambiente virtual**, instalar pacotes e trabalhar com esse ambiente.\n\nE então você quer trabalhar em **outro projeto** `prisoner-of-azkaban`.\n\nVocê vai para aquele projeto:\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\nSe você não desativar o ambiente virtual para `philosophers-stone`, quando você executar `python` no terminal, ele tentará usar o Python de `philosophers-stone`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// Erro ao importar o Sirius, ele não está instalado 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\nMas se você desativar o ambiente virtual e ativar o novo para `prisoner-of-askaban`, quando você executar `python`, ele usará o Python do ambiente virtual em `prisoner-of-azkaban`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// Você não precisa estar no diretório antigo para desativar, você pode fazer isso de onde estiver, mesmo depois de ir para o outro projeto 😎\n$ deactivate\n\n// Ative o ambiente virtual em prisoner-of-azkaban/.venv 🚀\n$ source .venv/bin/activate\n\n// Agora, quando você executar o python, ele encontrará o pacote sirius instalado neste ambiente virtual ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## Alternativas { #alternatives }\n\nEste é um guia simples para você começar e lhe ensinar como tudo funciona **por baixo**.\n\nExistem muitas **alternativas** para gerenciar ambientes virtuais, dependências de pacotes (requisitos) e projetos.\n\nQuando estiver pronto e quiser usar uma ferramenta para **gerenciar todo o projeto**, dependências de pacotes, ambientes virtuais, etc., sugiro que você experimente o [uv](https://github.com/astral-sh/uv).\n\n`uv` pode fazer muitas coisas, ele pode:\n\n* **Instalar o Python** para você, incluindo versões diferentes\n* Gerenciar o **ambiente virtual** para seus projetos\n* Instalar **pacotes**\n* Gerenciar **dependências e versões** de pacotes para seu projeto\n* Certificar-se de que você tenha um conjunto **exato** de pacotes e versões para instalar, incluindo suas dependências, para que você possa ter certeza de que pode executar seu projeto em produção exatamente da mesma forma que em seu computador durante o desenvolvimento, isso é chamado de **bloqueio**\n* E muitas outras coisas\n\n## Conclusão { #conclusion }\n\nSe você leu e entendeu tudo isso, agora **você sabe muito mais** sobre ambientes virtuais do que muitos desenvolvedores por aí. 🤓\n\nSaber esses detalhes provavelmente será útil no futuro, quando você estiver depurando algo que parece complexo, mas você saberá **como tudo funciona**. 😎\n"
  },
  {
    "path": "docs/pt/llm-prompt.md",
    "content": "### Target language\n\nTranslate to Portuguese (Português).\n\nLanguage code: pt.\n\nFor instructions or titles in imperative, keep them in imperative, for example \"Import FastAPI\" to \"Importe o FastAPI\".\n\nKeep existing translations as they are if the term is already translated.\n\nWhen translating documentation into Portuguese, use neutral and widely understandable language. Although Portuguese originated in Portugal and has its largest number of speakers in Brazil, it is also an official language in several countries and regions, such as Equatorial Guinea, Mozambique, Angola, Cape Verde, and São Tomé and Príncipe. Avoid words or expressions that are specific to a single country or region.\n\nOnly keep parentheses if they exist in the source text. Do not add parentheses to terms that do not have them.\n\n### Avoiding Repetition in Translation\n\nWhen translating sentences, avoid unnecessary repetition of words or phrases that are implied in context.\n- Merge repeated words naturally while keeping the meaning.\n- Do **not** introduce extra words to replace repeated phrases unnecessarily.\n- Keep translations fluent and concise, but maintain the original meaning.\n\n**Example:**\n\nSource:\nLet's see how that works and how to change it if you need to do that.\n\nAvoid translating literally as:\nVamos ver como isso funciona e como alterar isso se você precisar fazer isso.\n\nBetter translation:\nVamos ver como isso funciona e como alterar se você precisar.\n\n---\n\nFor the next terms, use the following translations:\n\n* /// check: /// check | Verifique\n* /// danger: /// danger | Cuidado\n* /// info: /// info | Informação\n* /// note | Technical Details: /// note | Detalhes Técnicos\n* /// info | Very Technical Details: /// note | Detalhes Técnicos Avançados\n* /// note: /// note | Nota\n* /// tip: /// tip | Dica\n* /// warning: /// warning | Atenção\n* you should: você deveria\n* async context manager: gerenciador de contexto assíncrono\n* autocomplete: autocompletar\n* autocompletion: preenchimento automático\n* auto-completion: preenchimento automático\n* bug: bug\n* context manager: gerenciador de contexto\n* cross domain: cross domain (do not translate to \"domínio cruzado\")\n* cross origin: cross origin (do not translate to \"origem cruzada\")\n* Cross-Origin Resource Sharing: Cross-Origin Resource Sharing (do not translate to \"Compartilhamento de Recursos de Origem Cruzada\")\n* Deep Learning: Deep Learning (do not translate to \"Aprendizado Profundo\")\n* dependable: dependable\n* dependencies: dependências\n* deprecated: descontinuado\n* docs: documentação\n* FastAPI app: aplicação FastAPI\n* framework: framework (do not translate)\n* feature: funcionalidade\n* guides: tutoriais\n* I/O (as in \"input and output\"): I/O (do not translate to \"E/S\")\n* JSON Schema: JSON Schema\n* library: biblioteca\n* lifespan: lifespan (do not translate to \"vida útil\")\n* list (as in Python list): list\n* Machine Learning: Aprendizado de Máquina\n* media type: media type (do not translate to \"tipo de mídia\")\n* non-Annotated: non-Annotated (do not translate non-Annotated when it comes after a Python version.e.g., “Python 3.10+ non-Annotated”)\n* operation IDs: IDs de operação\n* path (as in URL path): path\n* path operation: operação de rota\n* path operation function: função de operação de rota\n* prefix: prefixo\n* request (as in HTTP request): request (do not change if it's already translated to requisição)\n* router (as in FastAPI's router): router (do not change if it's already translated to \"roteador\" or \"roteadores\")\n* response (as in HTTP response): response (do not change if it's already translated to resposta)\n* shutdown (of the app): encerramento\n* shutdown event (of the app): evento de encerramento\n* startup (as in the event of the app): inicialização\n* startup event (as in the event of the app): evento de inicialização\n* Stream: Stream\n* string: string\n* type hints: anotações de tipo\n* wildcards: curingas\n"
  },
  {
    "path": "docs/pt/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs/ru/docs/_llm-test.md",
    "content": "# Тестовый файл LLM { #llm-test-file }\n\nЭтот документ проверяет, понимает ли <abbr title=\"Large Language Model - Большая языковая модель\">LLM</abbr>, переводящая документацию, `general_prompt` в `scripts/translate.py` и языковой специфичный промпт в `docs/{language code}/llm-prompt.md`. Языковой специфичный промпт добавляется к `general_prompt`.\n\nТесты, добавленные здесь, увидят все создатели языковых специфичных промптов.\n\nИспользование:\n\n* Подготовьте языковой специфичный промпт — `docs/{language code}/llm-prompt.md`.\n* Выполните новый перевод этого документа на нужный целевой язык (см., например, команду `translate-page` в `translate.py`). Это создаст перевод в `docs/{language code}/docs/_llm-test.md`.\n* Проверьте, всё ли в порядке в переводе.\n* При необходимости улучшите ваш языковой специфичный промпт, общий промпт или английский документ.\n* Затем вручную исправьте оставшиеся проблемы в переводе, чтобы он был хорошим.\n* Переведите заново, имея хороший перевод на месте. Идеальным результатом будет ситуация, когда LLM больше не вносит изменений в перевод. Это означает, что общий промпт и ваш языковой специфичный промпт настолько хороши, насколько это возможно (иногда он будет делать несколько, казалось бы, случайных изменений, причина в том, что [LLM — недетерминированные алгоритмы](https://doublespeak.chat/#/handbook#deterministic-output)).\n\nТесты:\n\n## Фрагменты кода { #code-snippets }\n\n//// tab | Тест\n\nЭто фрагмент кода: `foo`. А это ещё один фрагмент кода: `bar`. И ещё один: `baz quux`.\n\n////\n\n//// tab | Информация\n\nСодержимое фрагментов кода должно оставаться как есть.\n\nСм. раздел `### Content of code snippets` в общем промпте в `scripts/translate.py`.\n\n////\n\n## Кавычки { #quotes }\n\n//// tab | Тест\n\nВчера мой друг написал: \"Если вы написали incorrectly правильно, значит вы написали это неправильно\". На что я ответил: \"Верно, но 'incorrectly' — это неправильно, а не '\"incorrectly\"'\".\n\n/// note | Примечание\n\nLLM, вероятно, переведёт это неправильно. Интересно лишь то, сохранит ли она фиксированный перевод при повторном переводе.\n\n///\n\n////\n\n//// tab | Информация\n\nАвтор промпта может выбрать, хочет ли он преобразовывать нейтральные кавычки в типографские. Допускается оставить их как есть.\n\nСм., например, раздел `### Quotes` в `docs/de/llm-prompt.md`.\n\n////\n\n## Кавычки во фрагментах кода { #quotes-in-code-snippets }\n\n//// tab | Тест\n\n`pip install \"foo[bar]\"`\n\nПримеры строковых литералов во фрагментах кода: `\"this\"`, `'that'`.\n\nСложный пример строковых литералов во фрагментах кода: `f\"I like {'oranges' if orange else \"apples\"}\"`\n\nХардкор: `Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | Информация\n\n... Однако кавычки внутри фрагментов кода должны оставаться как есть.\n\n////\n\n## Блоки кода { #code-blocks }\n\n//// tab | Тест\n\nПример кода Bash...\n\n```bash\n# Вывести приветствие вселенной\necho \"Hello universe\"\n```\n\n...и пример вывода в консоли...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n...и ещё один пример вывода в консоли...\n\n```console\n// Создать директорию \"Code\"\n$ mkdir code\n// Перейти в эту директорию\n$ cd code\n```\n\n...и пример кода на Python...\n\n```Python\nwont_work()  # Это не сработает 😱\nworks(foo=\"bar\")  # Это работает 🎉\n```\n\n...и на этом всё.\n\n////\n\n//// tab | Информация\n\nКод в блоках кода не должен изменяться, за исключением комментариев.\n\nСм. раздел `### Content of code blocks` в общем промпте в `scripts/translate.py`.\n\n////\n\n## Вкладки и цветные блоки { #tabs-and-colored-boxes }\n\n//// tab | Тест\n\n/// info | Информация\nНекоторый текст\n///\n\n/// note | Примечание\nНекоторый текст\n///\n\n/// note | Технические подробности\nНекоторый текст\n///\n\n/// check | Проверка\nНекоторый текст\n///\n\n/// tip | Совет\nНекоторый текст\n///\n\n/// warning | Предупреждение\nНекоторый текст\n///\n\n/// danger | Опасность\nНекоторый текст\n///\n\n////\n\n//// tab | Информация\n\nДля вкладок и блоков `Info`/`Note`/`Warning`/и т.п. нужно добавить перевод их заголовка после вертикальной черты (`|`).\n\nСм. разделы `### Special blocks` и `### Tab blocks` в общем промпте в `scripts/translate.py`.\n\n////\n\n## Веб- и внутренние ссылки { #web-and-internal-links }\n\n//// tab | Тест\n\nТекст ссылок должен переводиться, адрес ссылки не должен изменяться:\n\n* [Ссылка на заголовок выше](#code-snippets)\n* [Внутренняя ссылка](index.md#installation)\n* [Внешняя ссылка](https://sqlmodel.tiangolo.com/)\n* [Ссылка на стиль](https://fastapi.tiangolo.com/css/styles.css)\n* [Ссылка на скрипт](https://fastapi.tiangolo.com/js/logic.js)\n* [Ссылка на изображение](https://fastapi.tiangolo.com/img/foo.jpg)\n\nТекст ссылок должен переводиться, адрес ссылки должен указывать на перевод:\n\n* [Ссылка на FastAPI](https://fastapi.tiangolo.com/ru/)\n\n////\n\n//// tab | Информация\n\nСсылки должны переводиться, но их адреса не должны изменяться. Исключение — абсолютные ссылки на страницы документации FastAPI. В этом случае ссылка должна вести на перевод.\n\nСм. раздел `### Links` в общем промпте в `scripts/translate.py`.\n\n////\n\n## HTML-элементы \"abbr\" { #html-abbr-elements }\n\n//// tab | Тест\n\nВот некоторые элементы, обёрнутые в HTML-элементы \"abbr\" (часть выдумана):\n\n### abbr даёт полную расшифровку { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done - Как привести дела в порядок\">GTD</abbr>\n* <abbr title=\"less than - меньше чем\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token - XML веб‑токен\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface - Параллельный серверный интерфейс шлюза\">PSGI</abbr>\n\n### abbr даёт полную расшифровку и объяснение { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network - Сеть разработчиков Mozilla: документация для разработчиков, созданная командой Firefox\">MDN</abbr>\n* <abbr title=\"Input/Output - Ввод/Вывод: чтение или запись на диск, сетевое взаимодействие.\">I/O</abbr>.\n\n////\n\n//// tab | Информация\n\nАтрибуты \"title\" элементов \"abbr\" переводятся по определённым правилам.\n\nПереводы могут добавлять свои собственные элементы \"abbr\", которые LLM не должна удалять. Например, чтобы объяснить английские слова.\n\nСм. раздел `### HTML abbr elements` в общем промпте в `scripts/translate.py`.\n\n////\n\n## HTML-элементы \"dfn\" { #html-dfn-elements }\n\n* <dfn title=\"Группа машин, которые настроены на соединение и совместную работу определённым образом.\">кластер</dfn>\n* <dfn title=\"Метод машинного обучения, который использует искусственные нейронные сети с многочисленными скрытыми слоями между входным и выходным слоями, тем самым формируя сложную внутреннюю структуру\">Глубокое обучение</dfn>\n\n## Заголовки { #headings }\n\n//// tab | Тест\n\n### Разработка веб‑приложения — руководство { #develop-a-webapp-a-tutorial }\n\nПривет.\n\n### Аннотации типов и -аннотации { #type-hints-and-annotations }\n\nСнова привет.\n\n### Супер- и подклассы { #super-and-subclasses }\n\nСнова привет.\n\n////\n\n//// tab | Информация\n\nЕдинственное жёсткое правило для заголовков — LLM должна оставить часть хеша в фигурных скобках без изменений, чтобы ссылки не ломались.\n\nСм. раздел `### Headings` в общем промпте в `scripts/translate.py`.\n\nДля некоторых языковых инструкций см., например, раздел `### Headings` в `docs/de/llm-prompt.md`.\n\n////\n\n## Термины, используемые в документации { #terms-used-in-the-docs }\n\n//// tab | Тест\n\n* вы\n* ваш\n\n* например\n* и т.д.\n\n* `foo` как `int`\n* `bar` как `str`\n* `baz` как `list`\n\n* Учебник — Руководство пользователя\n* Расширенное руководство пользователя\n* Документация по SQLModel\n* Документация API\n* Автоматическая документация\n\n* Наука о данных\n* Глубокое обучение\n* Машинное обучение\n* Внедрение зависимостей\n* Аутентификация HTTP Basic\n* HTTP Digest\n* формат ISO\n* стандарт JSON Schema\n* JSON-схема\n* определение схемы\n* password flow\n* Мобильный\n\n* устаревший\n* спроектированный\n* некорректный\n* на лету\n* стандарт\n* по умолчанию\n* чувствительный к регистру\n* нечувствительный к регистру\n\n* отдавать приложение\n* отдавать страницу\n\n* приложение\n* приложение\n\n* HTTP-запрос\n* HTTP-ответ\n* ответ с ошибкой\n\n* операция пути\n* декоратор операции пути\n* функция-обработчик пути\n\n* тело\n* тело запроса\n* тело ответа\n* JSON-тело\n* тело формы\n* тело файла\n* тело функции\n\n* параметр\n* body-параметр\n* path-параметр\n* query-параметр\n* cookie-параметр\n* параметр заголовка\n* параметр формы\n* параметр функции\n\n* событие\n* событие запуска\n* запуск сервера\n* событие остановки\n* событие lifespan\n\n* обработчик\n* обработчик события\n* обработчик исключений\n* обрабатывать\n\n* модель\n* Pydantic-модель\n* модель данных\n* модель базы данных\n* модель формы\n* объект модели\n\n* класс\n* базовый класс\n* родительский класс\n* подкласс\n* дочерний класс\n* родственный класс\n* метод класса\n\n* заголовок\n* HTTP-заголовки\n* заголовок авторизации\n* заголовок `Authorization`\n* заголовок `Forwarded`\n\n* система внедрения зависимостей\n* зависимость\n* зависимый объект\n* зависимый\n\n* ограниченный вводом/выводом\n* ограниченный процессором\n* конкурентность\n* параллелизм\n* многопроцессность\n\n* переменная окружения\n* переменная окружения\n* `PATH`\n* переменная `PATH`\n\n* аутентификация\n* провайдер аутентификации\n* авторизация\n* форма авторизации\n* провайдер авторизации\n* пользователь аутентифицируется\n* система аутентифицирует пользователя\n\n* CLI\n* интерфейс командной строки\n\n* сервер\n* клиент\n\n* облачный провайдер\n* облачный сервис\n\n* разработка\n* этапы разработки\n\n* dict\n* словарь\n* перечисление\n* enum\n* член перечисления\n\n* кодировщик\n* декодировщик\n* кодировать\n* декодировать\n\n* исключение\n* вызвать\n\n* выражение\n* оператор\n\n* фронтенд\n* бэкенд\n\n* обсуждение на GitHub\n* Issue на GitHub (тикет/обращение)\n\n* производительность\n* оптимизация производительности\n\n* тип возвращаемого значения\n* возвращаемое значение\n\n* безопасность\n* схема безопасности\n\n* задача\n* фоновая задача\n* функция задачи\n\n* шаблон\n* шаблонизатор\n\n* аннотация типов\n* аннотация типов\n\n* воркер сервера\n* воркер Uvicorn\n* воркер Gunicorn\n* воркер-процесс\n* класс воркера\n* рабочая нагрузка\n\n* деплой\n* развернуть\n\n* SDK\n* набор средств разработки ПО\n\n* `APIRouter`\n* `requirements.txt`\n* токен Bearer\n* несовместимое изменение\n* баг\n* кнопка\n* вызываемый объект\n* код\n* коммит\n* менеджер контекста\n* корутина\n* сессия базы данных\n* диск\n* домен\n* движок\n* фиктивный X\n* метод HTTP GET\n* элемент\n* библиотека\n* lifespan\n* блокировка\n* middleware (Промежуточный слой)\n* мобильное приложение\n* модуль\n* монтирование\n* сеть\n* origin (источник)\n* переопределение\n* полезная нагрузка\n* процессор\n* свойство\n* прокси\n* пулл-реквест (запрос на изменение)\n* запрос\n* ОЗУ\n* удалённая машина\n* статус-код\n* строка\n* тег\n* веб‑фреймворк\n* подстановочный знак\n* вернуть\n* валидировать\n\n////\n\n//// tab | Информация\n\nЭто неполный и ненормативный список (в основном) технических терминов, встречающихся в документации. Он может помочь автору промпта понять, по каким терминам LLM нужна подсказка. Например, когда она продолжает возвращать действительно хороший перевод к неоптимальному. Или когда у неё возникают проблемы со склонением/спряжением термина на вашем языке.\n\nСм., например, раздел `### List of English terms and their preferred German translations` в `docs/de/llm-prompt.md`.\n\n////\n"
  },
  {
    "path": "docs/ru/docs/about/index.md",
    "content": "# О проекте { #about }\n\nО FastAPI, его дизайне, источниках вдохновения и многом другом. 🤓\n"
  },
  {
    "path": "docs/ru/docs/advanced/additional-responses.md",
    "content": "# Дополнительные ответы в OpenAPI { #additional-responses-in-openapi }\n\n/// warning | Предупреждение\n\nЭто довольно продвинутая тема.\n\nЕсли вы только начинаете работать с **FastAPI**, возможно, вам это пока не нужно.\n\n///\n\nВы можете объявлять дополнительные ответы с дополнительными статус-кодами, типами содержимого, описаниями и т.д.\n\nЭти дополнительные ответы будут включены в схему OpenAPI, и поэтому появятся в документации API.\n\nНо для таких дополнительных ответов убедитесь, что вы возвращаете `Response`, например `JSONResponse`, напрямую, со своим статус-кодом и содержимым.\n\n## Дополнительный ответ с `model` { #additional-response-with-model }\n\nВы можете передать вашим декораторам операции пути параметр `responses`.\n\nОн принимает `dict`: ключи — это статус-коды для каждого ответа (например, `200`), а значения — другие `dict` с информацией для каждого из них.\n\nКаждый из этих `dict` для ответа может иметь ключ `model`, содержащий Pydantic-модель, аналогично `response_model`.\n\n**FastAPI** возьмёт эту модель, сгенерирует для неё JSON‑схему и включит её в нужное место в OpenAPI.\n\nНапример, чтобы объявить ещё один ответ со статус-кодом `404` и Pydantic-моделью `Message`, можно написать:\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | Примечание\n\nИмейте в виду, что необходимо возвращать `JSONResponse` напрямую.\n\n///\n\n/// info | Информация\n\nКлюч `model` не является частью OpenAPI.\n\n**FastAPI** возьмёт Pydantic-модель оттуда, сгенерирует JSON‑схему и поместит её в нужное место.\n\nНужное место:\n\n* В ключе `content`, значением которого является другой JSON‑объект (`dict`), содержащий:\n    * Ключ с типом содержимого, например `application/json`, значением которого является другой JSON‑объект, содержащий:\n        * Ключ `schema`, значением которого является JSON‑схема из модели — вот нужное место.\n            * **FastAPI** добавляет здесь ссылку на глобальные JSON‑схемы в другом месте вашего OpenAPI вместо того, чтобы включать схему напрямую. Так другие приложения и клиенты смогут использовать эти JSON‑схемы напрямую, предоставлять лучшие инструменты генерации кода и т.д.\n\n///\n\nСгенерированные в OpenAPI ответы для этой операции пути будут такими:\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nСхемы даны как ссылки на другое место внутри схемы OpenAPI:\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## Дополнительные типы содержимого для основного ответа { #additional-media-types-for-the-main-response }\n\nВы можете использовать этот же параметр `responses`, чтобы добавить разные типы содержимого для того же основного ответа.\n\nНапример, вы можете добавить дополнительный тип содержимого `image/png`, объявив, что ваша операция пути может возвращать JSON‑объект (с типом содержимого `application/json`) или PNG‑изображение:\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | Примечание\n\nУчтите, что изображение нужно возвращать напрямую, используя `FileResponse`.\n\n///\n\n/// info | Информация\n\nЕсли вы явно не укажете другой тип содержимого в параметре `responses`, FastAPI будет считать, что ответ имеет тот же тип содержимого, что и основной класс ответа (по умолчанию `application/json`).\n\nНо если вы указали пользовательский класс ответа с `None` в качестве его типа содержимого, FastAPI использует `application/json` для любого дополнительного ответа, у которого есть связанная модель.\n\n///\n\n## Комбинирование информации { #combining-information }\n\nВы также можете комбинировать информацию об ответах из нескольких мест, включая параметры `response_model`, `status_code` и `responses`.\n\nВы можете объявить `response_model`, используя статус-код по умолчанию `200` (или свой, если нужно), а затем объявить дополнительную информацию для этого же ответа в `responses`, напрямую в схеме OpenAPI.\n\n**FastAPI** сохранит дополнительную информацию из `responses` и объединит её с JSON‑схемой из вашей модели.\n\nНапример, вы можете объявить ответ со статус-кодом `404`, который использует Pydantic-модель и имеет пользовательское `description`.\n\nА также ответ со статус-кодом `200`, который использует ваш `response_model`, но включает пользовательский `example`:\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\nВсё это будет объединено и включено в ваш OpenAPI и отображено в документации API:\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## Комбинирование предопределённых и пользовательских ответов { #combine-predefined-responses-and-custom-ones }\n\nВозможно, вы хотите иметь некоторые предопределённые ответы, применимые ко многим операциям пути, но при этом комбинировать их с пользовательскими ответами, необходимыми для каждой конкретной операции пути.\n\nВ таких случаях вы можете использовать приём Python «распаковки» `dict` с помощью `**dict_to_unpack`:\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\nЗдесь `new_dict` будет содержать все пары ключ-значение из `old_dict` плюс новую пару ключ-значение:\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\nВы можете использовать этот приём, чтобы переиспользовать некоторые предопределённые ответы в ваших операциях пути и комбинировать их с дополнительными пользовательскими.\n\nНапример:\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## Дополнительная информация об ответах OpenAPI { #more-information-about-openapi-responses }\n\nЧтобы увидеть, что именно можно включать в ответы, посмотрите эти разделы спецификации OpenAPI:\n\n* [Объект Responses OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object), он включает `Response Object`.\n* [Объект Response OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object), вы можете включить всё из этого объекта напрямую в каждый ответ внутри вашего параметра `responses`. Включая `description`, `headers`, `content` (внутри него вы объявляете разные типы содержимого и JSON‑схемы) и `links`.\n"
  },
  {
    "path": "docs/ru/docs/advanced/additional-status-codes.md",
    "content": "# Дополнительные статус-коды { #additional-status-codes }\n\nПо умолчанию **FastAPI** будет возвращать ответы, используя `JSONResponse`, помещая содержимое, которое вы возвращаете из вашей *операции пути*, внутрь этого `JSONResponse`.\n\nОн будет использовать статус-код по умолчанию или тот, который вы укажете в вашей *операции пути*.\n\n## Дополнительные статус-коды { #additional-status-codes_1 }\n\nЕсли вы хотите возвращать дополнительные статус-коды помимо основного, вы можете сделать это, возвращая `Response` напрямую, например `JSONResponse`, и устанавливая дополнительный статус-код напрямую.\n\nНапример, предположим, что вы хотите иметь *операцию пути*, которая позволяет обновлять элементы и возвращает HTTP статус-код 200 «OK» при успешном выполнении.\n\nНо вы также хотите, чтобы она принимала новые элементы. И если элементы ранее не существовали, она создаёт их и возвращает HTTP статус-код 201 «Created».\n\nЧтобы добиться этого, импортируйте `JSONResponse` и верните туда свой контент напрямую, установив нужный вам `status_code`:\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning | Внимание\n\nКогда вы возвращаете `Response` напрямую, как в примере выше, он будет возвращён как есть.\n\nОн не будет сериализован с помощью модели и т.п.\n\nУбедитесь, что в нём именно те данные, которые вы хотите, и что значения являются валидным JSON (если вы используете `JSONResponse`).\n\n///\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette.responses import JSONResponse`.\n\n**FastAPI** предоставляет тот же `starlette.responses` через `fastapi.responses` просто для вашего удобства как разработчика. Но большинство доступных Response-классов приходят напрямую из Starlette. То же самое со `status`.\n\n///\n\n## OpenAPI и документация API { #openapi-and-api-docs }\n\nЕсли вы возвращаете дополнительные статус-коды и ответы напрямую, они не будут включены в схему OpenAPI (документацию API), потому что у FastAPI нет способа заранее знать, что вы собираетесь вернуть.\n\nНо вы можете задокументировать это в своём коде, используя: [Дополнительные ответы](additional-responses.md).\n"
  },
  {
    "path": "docs/ru/docs/advanced/advanced-dependencies.md",
    "content": "# Продвинутые зависимости { #advanced-dependencies }\n\n## Параметризованные зависимости { #parameterized-dependencies }\n\nВсе зависимости, которые мы видели, — это конкретная функция или класс.\n\nНо бывают случаи, когда нужно задавать параметры зависимости, не объявляя много разных функций или классов.\n\nПредставим, что нам нужна зависимость, которая проверяет, содержит ли query-параметр `q` некоторое фиксированное содержимое.\n\nНо при этом мы хотим иметь возможность параметризовать это фиксированное содержимое.\n\n## «Вызываемый» экземпляр { #a-callable-instance }\n\nВ Python есть способ сделать экземпляр класса «вызываемым» объектом.\n\nНе сам класс (он уже является вызываемым), а экземпляр этого класса.\n\nДля этого объявляем метод `__call__`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\nВ этом случае именно `__call__` **FastAPI** использует для проверки дополнительных параметров и подзависимостей, и именно он будет вызван, чтобы позже передать значение параметру в вашей *функции-обработчике пути*.\n\n## Параметризуем экземпляр { #parameterize-the-instance }\n\nТеперь мы можем использовать `__init__`, чтобы объявить параметры экземпляра, с помощью которых будем «параметризовать» зависимость:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\nВ этом случае **FastAPI** вовсе не трогает `__init__` и не зависит от него — мы используем его напрямую в нашем коде.\n\n## Создаём экземпляр { #create-an-instance }\n\nМы можем создать экземпляр этого класса так:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\nТак мы «параметризуем» нашу зависимость: теперь внутри неё хранится \"bar\" в атрибуте `checker.fixed_content`.\n\n## Используем экземпляр как зависимость { #use-the-instance-as-a-dependency }\n\nЗатем мы можем использовать этот `checker` в `Depends(checker)` вместо `Depends(FixedContentQueryChecker)`, потому что зависимостью является экземпляр `checker`, а не сам класс.\n\nИ при разрешении зависимости **FastAPI** вызовет `checker` примерно так:\n\n```Python\nchecker(q=\"somequery\")\n```\n\n…и передаст возвращённое значение как значение зависимости в параметр `fixed_content_included` нашей *функции-обработчику пути*:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | Совет\n\nВсе это может показаться притянутым за уши. И пока может быть не совсем понятно, чем это полезно.\n\nЭти примеры намеренно простые, но они показывают, как всё устроено.\n\nВ главах про безопасность есть вспомогательные функции, реализованные тем же способом.\n\nЕсли вы поняли всё выше, вы уже знаете, как «под капотом» работают эти утилиты для безопасности.\n\n///\n\n## Зависимости с `yield`, `HTTPException`, `except` и фоновыми задачами { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | Предупреждение\n\nСкорее всего, вам не понадобятся эти технические детали.\n\nОни полезны главным образом, если у вас было приложение FastAPI версии ниже 0.121.0 и вы столкнулись с проблемами зависимостей с `yield`.\n\n///\n\nЗависимости с `yield` со временем изменялись, чтобы учитывать разные случаи применения и исправлять проблемы. Ниже — краткое резюме изменений.\n\n### Зависимости с `yield` и `scope` { #dependencies-with-yield-and-scope }\n\nВ версии 0.121.0 FastAPI добавил поддержку `Depends(scope=\"function\")` для зависимостей с `yield`.\n\nПри использовании `Depends(scope=\"function\")` код после `yield` выполняется сразу после завершения *функции-обработчика пути*, до отправки ответа клиенту.\n\nА при использовании `Depends(scope=\"request\")` (значение по умолчанию) код после `yield` выполняется после отправки ответа.\n\nПодробнее читайте в документации: [Зависимости с `yield` — раннее завершение и `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope).\n\n### Зависимости с `yield` и `StreamingResponse`, технические детали { #dependencies-with-yield-and-streamingresponse-technical-details }\n\nДо FastAPI 0.118.0, если вы использовали зависимость с `yield`, код после `yield` выполнялся после возврата из *функции-обработчика пути*, но прямо перед отправкой ответа.\n\nИдея состояла в том, чтобы не удерживать ресурсы дольше необходимого, пока ответ «путешествует» по сети.\n\nЭто изменение также означало, что если вы возвращали `StreamingResponse`, код после `yield` в зависимости уже успевал выполниться.\n\nНапример, если у вас была сессия базы данных в зависимости с `yield`, `StreamingResponse` не смог бы использовать эту сессию во время стриминга данных, потому что сессия уже была закрыта в коде после `yield`.\n\nВ версии 0.118.0 это поведение было возвращено к тому, что код после `yield` выполняется после отправки ответа.\n\n/// info | Информация\n\nКак вы увидите ниже, это очень похоже на поведение до версии 0.106.0, но с несколькими улучшениями и исправлениями краевых случаев.\n\n///\n\n#### Сценарии с ранним выполнением кода после `yield` { #use-cases-with-early-exit-code }\n\nЕсть некоторые сценарии со специфическими условиями, которым могло бы помочь старое поведение — выполнение кода после `yield` перед отправкой ответа.\n\nНапример, представьте, что вы используете сессию базы данных в зависимости с `yield` только для проверки пользователя, а в самой *функции-обработчике пути* эта сессия больше не используется, и при этом ответ отправляется долго, например, это `StreamingResponse`, который медленно отправляет данные и по какой-то причине не использует базу данных.\n\nВ таком случае сессия базы данных будет удерживаться до завершения отправки ответа, хотя если вы её не используете, удерживать её не требуется.\n\nЭто могло бы выглядеть так:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\nКод после `yield`, автоматическое закрытие `Session` в:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n…будет выполнен после того, как ответ закончит отправку медленных данных:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nНо поскольку `generate_stream()` не использует сессию базы данных, нет реальной необходимости держать сессию открытой во время отправки ответа.\n\nЕсли у вас именно такой сценарий с SQLModel (или SQLAlchemy), вы можете явно закрыть сессию, когда она больше не нужна:\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\nТак сессия освободит подключение к базе данных, и другие запросы смогут его использовать.\n\nЕсли у вас есть другой сценарий, где нужно раннее завершение зависимости с `yield`, пожалуйста, создайте [вопрос в GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions) с описанием конкретного кейса и почему вам было бы полезно иметь раннее закрытие для зависимостей с `yield`.\n\nЕсли появятся веские причины для раннего закрытия в зависимостях с `yield`, я рассмотрю добавление нового способа опционально включать раннее закрытие.\n\n### Зависимости с `yield` и `except`, технические детали { #dependencies-with-yield-and-except-technical-details }\n\nДо FastAPI 0.110.0, если вы использовали зависимость с `yield`, затем перехватывали исключение с `except` в этой зависимости и не пробрасывали исключение снова, исключение автоматически пробрасывалось дальше к обработчикам исключений или к обработчику внутренней ошибки сервера.\n\nВ версии 0.110.0 это было изменено, чтобы исправить неконтролируемое потребление памяти из‑за проброшенных исключений без обработчика (внутренние ошибки сервера) и привести поведение в соответствие с обычным поведением Python-кода.\n\n### Фоновые задачи и зависимости с `yield`, технические детали { #background-tasks-and-dependencies-with-yield-technical-details }\n\nДо FastAPI 0.106.0 вызывать исключения после `yield` было невозможно: код после `yield` в зависимостях выполнялся уже после отправки ответа, поэтому [Обработчики исключений](../tutorial/handling-errors.md#install-custom-exception-handlers) к тому моменту уже отработали.\n\nТак было сделано в основном для того, чтобы можно было использовать те же объекты, «отданные» зависимостями через `yield`, внутри фоновых задач, потому что код после `yield` выполнялся после завершения фоновых задач.\n\nВ FastAPI 0.106.0 это изменили, чтобы не удерживать ресурсы, пока ответ передаётся по сети.\n\n/// tip | Совет\n\nКроме того, фоновая задача обычно — это самостоятельный фрагмент логики, который следует обрабатывать отдельно, со своими ресурсами (например, со своим подключением к базе данных).\n\nТак код, скорее всего, будет чище.\n\n///\n\nЕсли вы полагались на прежнее поведение, теперь ресурсы для фоновых задач следует создавать внутри самой фоновой задачи и использовать внутри неё только данные, которые не зависят от ресурсов зависимостей с `yield`.\n\nНапример, вместо использования той же сессии базы данных, создайте новую сессию в фоновой задаче и получите объекты из базы данных с помощью этой новой сессии. И затем, вместо передачи объекта из базы данных параметром в функцию фоновой задачи, передавайте идентификатор этого объекта и заново получайте объект внутри функции фоновой задачи.\n"
  },
  {
    "path": "docs/ru/docs/advanced/advanced-python-types.md",
    "content": "# Продвинутые типы Python { #advanced-python-types }\n\nНиже несколько дополнительных идей, которые могут быть полезны при работе с типами Python.\n\n## Использование `Union` или `Optional` { #using-union-or-optional }\n\nЕсли по какой-то причине ваш код не может использовать `|`, например, если это не аннотация типов, а что-то вроде `response_model=`, вместо вертикальной черты (`|`) можно использовать `Union` из `typing`.\n\nНапример, вы можете объявить, что значение может быть `str` или `None`:\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\nВ `typing` также есть сокращение, чтобы объявить, что значение может быть `None`, — `Optional`.\n\nВот совет с моей очень субъективной точки зрения:\n\n- 🚨 Избегайте использования `Optional[SomeType]`\n- Вместо этого ✨ используйте **`Union[SomeType, None]`** ✨.\n\nОба варианта эквивалентны и под капотом это одно и то же, но я бы рекомендовал `Union` вместо `Optional`, потому что слово «optional» может наводить на мысль, что значение необязательное, тогда как на самом деле это означает «значение может быть `None`», даже если оно не является необязательным и по-прежнему требуется.\n\nПо-моему, `Union[SomeType, None]` более явно передаёт смысл.\n\nРечь только о словах и названиях. Но эти слова могут влиять на то, как вы и ваша команда думаете о коде.\n\nВ качестве примера возьмём такую функцию:\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\nПараметр `name` объявлен как `Optional[str]`, но он не является необязательным: вы не можете вызвать функцию без этого параметра:\n\n```Python\nsay_hi()  # О нет, это вызывает ошибку! 😱\n```\n\nПараметр `name` по-прежнему обязателен (не «optional»), так как у него нет значения по умолчанию. При этом `name` принимает `None` в качестве значения:\n\n```Python\nsay_hi(name=None)  # Это работает, None допустим 🎉\n```\n\nХорошая новость: в большинстве случаев вы сможете просто использовать `|` для объявления объединений типов:\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\nТак что обычно вам не о чем переживать из‑за названий вроде `Optional` и `Union`. 😎\n"
  },
  {
    "path": "docs/ru/docs/advanced/async-tests.md",
    "content": "# Асинхронное тестирование { #async-tests }\n\nВы уже видели как тестировать **FastAPI** приложение, используя имеющийся класс `TestClient`. К этому моменту вы видели только как писать тесты в синхронном стиле без использования `async` функций.\n\nВозможность использования асинхронных функций в ваших тестах может быть полезнa, когда, например, вы асинхронно обращаетесь к вашей базе данных. Представьте, что вы хотите отправить запросы в ваше FastAPI приложение, а затем при помощи асинхронной библиотеки для работы с базой данных удостовериться, что ваш бекэнд корректно записал данные в базу данных.\n\nДавайте рассмотрим, как мы можем это реализовать.\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\nЕсли мы хотим вызывать асинхронные функции в наших тестах, то наши тестовые функции должны быть асинхронными. AnyIO предоставляет для этого отличный плагин, который позволяет нам указывать, какие тестовые функции должны вызываться асинхронно.\n\n## HTTPX { #httpx }\n\nДаже если **FastAPI** приложение использует обычные функции `def` вместо `async def`, это все равно `async` приложение 'под капотом'.\n\nЧтобы работать с асинхронным FastAPI приложением в ваших обычных тестовых функциях `def`, используя стандартный pytest, `TestClient` внутри себя делает некоторую магию. Но эта магия перестает работать, когда мы используем его внутри асинхронных функций. Запуская наши тесты асинхронно, мы больше не можем использовать `TestClient` внутри наших тестовых функций.\n\n`TestClient` основан на [HTTPX](https://www.python-httpx.org), и, к счастью, мы можем использовать его (`HTTPX`) напрямую для тестирования API.\n\n## Пример { #example }\n\nВ качестве простого примера, давайте рассмотрим файловую структуру, схожую с описанной в [Большие приложения](../tutorial/bigger-applications.md) и [Тестирование](../tutorial/testing.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nФайл `main.py`:\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\nФайл `test_main.py` содержит тесты для `main.py`, теперь он может выглядеть так:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## Запуск тестов { #run-it }\n\nВы можете запустить свои тесты как обычно:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## Подробнее { #in-detail }\n\nМаркер `@pytest.mark.anyio` говорит pytest, что тестовая функция должна быть вызвана асинхронно:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip | Подсказка\n\nОбратите внимание, что тестовая функция теперь `async def` вместо простого `def`, как это было при использовании `TestClient`.\n\n///\n\nЗатем мы можем создать `AsyncClient` со ссылкой на приложение и посылать асинхронные запросы, используя `await`.\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\nЭто эквивалентно следующему:\n\n```Python\nresponse = client.get('/')\n```\n\n...которое мы использовали для отправки наших запросов с `TestClient`.\n\n/// tip | Подсказка\n\nОбратите внимание, что мы используем async/await с `AsyncClient` - запрос асинхронный.\n\n///\n\n/// warning | Внимание\n\nЕсли ваше приложение полагается на lifespan события, то `AsyncClient` не запустит эти события. Чтобы обеспечить их срабатывание используйте `LifespanManager` из [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage).\n\n///\n\n## Вызов других асинхронных функций { #other-asynchronous-function-calls }\n\nТеперь тестовая функция стала асинхронной, поэтому внутри нее вы можете вызывать также и другие `async` функции, не связанные с отправлением запросов в ваше FastAPI приложение. Как если бы вы вызывали их в любом другом месте вашего кода.\n\n/// tip | Подсказка\n\nЕсли вы столкнулись с `RuntimeError: Task attached to a different loop` при вызове асинхронных функций в ваших тестах (например, при использовании [MongoDB's MotorClient](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop)), то не забывайте создавать экземпляры объектов, которым нужен цикл событий (event loop), только внутри асинхронных функций, например, в `@app.on_event(\"startup\")` callback.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/advanced/behind-a-proxy.md",
    "content": "# За прокси‑сервером { #behind-a-proxy }\n\nВо многих случаях перед приложением FastAPI используется прокси‑сервер, например Traefik или Nginx.\n\nТакие прокси могут обрабатывать HTTPS‑сертификаты и многое другое.\n\n## Пересылаемые заголовки прокси { #proxy-forwarded-headers }\n\nПрокси перед вашим приложением обычно на лету добавляет некоторые HTTP‑заголовки перед отправкой запроса на ваш сервер, чтобы сообщить ему, что запрос был переслан прокси, а также передать исходный (публичный) URL (включая домен), информацию об использовании HTTPS и т.д.\n\nПрограмма сервера (например, Uvicorn, запущенный через FastAPI CLI) умеет интерпретировать эти заголовки и передавать соответствующую информацию вашему приложению.\n\nНо из соображений безопасности, пока сервер не уверен, что находится за доверенным прокси, он не будет интерпретировать эти заголовки.\n\n/// note | Технические детали\n\nЗаголовки прокси:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### Включить пересылаемые заголовки прокси { #enable-proxy-forwarded-headers }\n\nВы можете запустить FastAPI CLI с опцией командной строки `--forwarded-allow-ips` и передать IP‑адреса, которым следует доверять при чтении этих пересылаемых заголовков.\n\nЕсли указать `--forwarded-allow-ips=\"*\"`, приложение будет доверять всем входящим IP.\n\nЕсли ваш сервер находится за доверенным прокси и только прокси обращается к нему, этого достаточно, чтобы он принимал IP этого прокси.\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Редиректы с HTTPS { #redirects-with-https }\n\nНапример, вы объявили операцию пути `/items/`:\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\nЕсли клиент обратится к `/items`, по умолчанию произойдёт редирект на `/items/`.\n\nНо до установки опции `--forwarded-allow-ips` редирект может вести на `http://localhost:8000/items/`.\n\nОднако приложение может быть доступно по `https://mysuperapp.com`, и редирект должен вести на `https://mysuperapp.com/items/`.\n\nУказав `--proxy-headers`, FastAPI сможет редиректить на корректный адрес. 😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip | Совет\n\nЕсли хотите узнать больше об HTTPS, смотрите руководство [О HTTPS](../deployment/https.md).\n\n///\n\n### Как работают пересылаемые заголовки прокси { #how-proxy-forwarded-headers-work }\n\nНиже показано, как прокси добавляет пересылаемые заголовки между клиентом и сервером приложения:\n\n```mermaid\nsequenceDiagram\n    participant Client as Клиент\n    participant Proxy as Прокси/Балансировщик нагрузки\n    participant Server as FastAPI-сервер\n\n    Client->>Proxy: HTTPS-запрос<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: Прокси-сервер добавляет пересылаемые заголовки\n\n    Proxy->>Server: HTTP-запрос<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: Server интерпретирует HTTP-заголовки<br/>(если --forwarded-allow-ips установлен)\n\n    Server->>Proxy: HTTP-ответ<br/>с верными HTTPS URLs\n\n    Proxy->>Client: HTTPS-ответ\n```\n\nПрокси перехватывает исходный клиентский запрос и добавляет специальные пересылаемые заголовки (`X-Forwarded-*`) перед передачей запроса на сервер приложения.\n\nЭти заголовки сохраняют информацию об исходном запросе, которая иначе была бы потеряна:\n\n* X-Forwarded-For: исходный IP‑адрес клиента\n* X-Forwarded-Proto: исходный протокол (`https`)\n* X-Forwarded-Host: исходный хост (`mysuperapp.com`)\n\nКогда FastAPI CLI сконфигурирован с `--forwarded-allow-ips`, он доверяет этим заголовкам и использует их, например, чтобы формировать корректные URL в редиректах.\n\n## Прокси с функцией удаления префикса пути { #proxy-with-a-stripped-path-prefix }\n\nПрокси может добавлять к вашему приложению префикс пути (размещать приложение по пути с дополнительным префиксом).\n\nВ таких случаях вы можете использовать `root_path` для настройки приложения.\n\nМеханизм `root_path` определён спецификацией ASGI (на которой построен FastAPI, через Starlette).\n\n`root_path` используется для обработки таких специфических случаев.\n\nОн также используется внутри при монтировании вложенных приложений.\n\nПрокси с функцией удаления префикса пути в этом случае означает, что вы объявляете путь `/app` в коде, а затем добавляете сверху слой (прокси), который размещает ваше приложение FastAPI под путём вида `/api/v1`.\n\nТогда исходный путь `/app` фактически будет обслуживаться по адресу `/api/v1/app`.\n\nХотя весь ваш код написан с расчётом, что путь один — `/app`.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\nПрокси будет «обрезать» префикс пути на лету перед передачей запроса на сервер приложения (скорее всего Uvicorn, запущенный через FastAPI CLI), поддерживая у вашего приложения иллюзию, что его обслуживают по `/app`, чтобы вам не пришлось менять весь код и добавлять префикс `/api/v1`.\n\nДо этого момента всё будет работать как обычно.\n\nНо когда вы откроете встроенный интерфейс документации (фронтенд), он будет ожидать получить схему OpenAPI по адресу `/openapi.json`, а не `/api/v1/openapi.json`.\n\nПоэтому фронтенд (который работает в браузере) попытается обратиться к `/openapi.json` и не сможет получить схему OpenAPI.\n\nТак как для нашего приложения используется прокси с префиксом пути `/api/v1`, фронтенду нужно забирать схему OpenAPI по `/api/v1/openapi.json`.\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy on http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server on http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip | Совет\n\nIP `0.0.0.0` обычно означает, что программа слушает на всех IP‑адресах, доступных на этой машине/сервере.\n\n///\n\nИнтерфейсу документации также нужна схема OpenAPI, в которой будет указано, что этот API `server` находится по пути `/api/v1` (за прокси). Например:\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // Здесь ещё что-то\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // Здесь ещё что-то\n    }\n}\n```\n\nВ этом примере «Proxy» может быть, например, Traefik. А сервером будет что‑то вроде FastAPI CLI с Uvicorn, на котором запущено ваше приложение FastAPI.\n\n### Указание `root_path` { #providing-the-root-path }\n\nДля этого используйте опцию командной строки `--root-path`, например так:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nЕсли вы используете Hypercorn, у него тоже есть опция `--root-path`.\n\n/// note | Технические детали\n\nСпецификация ASGI определяет `root_path` для такого случая.\n\nА опция командной строки `--root-path` передаёт этот `root_path`.\n\n///\n\n### Проверка текущего `root_path` { #checking-the-current-root-path }\n\nВы можете получить текущий `root_path`, используемый вашим приложением для каждого запроса, — он входит в словарь `scope` (часть спецификации ASGI).\n\nЗдесь мы добавляем его в сообщение лишь для демонстрации.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\nЗатем, если вы запустите Uvicorn так:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nОтвет будет примерно таким:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### Установка `root_path` в приложении FastAPI { #setting-the-root-path-in-the-fastapi-app }\n\nЕсли нет возможности передать опцию командной строки `--root-path` (или аналог), вы можете указать параметр `root_path` при создании приложения FastAPI:\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\nПередача `root_path` в `FastAPI` эквивалентна опции командной строки `--root-path` для Uvicorn или Hypercorn.\n\n### О `root_path` { #about-root-path }\n\nУчтите, что сервер (Uvicorn) не использует `root_path` ни для чего, кроме как передать его в приложение.\n\nЕсли вы откроете в браузере [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), вы увидите обычный ответ:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nТо есть он не ожидает, что к нему обратятся по адресу `http://127.0.0.1:8000/api/v1/app`.\n\nUvicorn ожидает, что прокси обратится к нему по `http://127.0.0.1:8000/app`, а уже задача прокси — добавить сверху префикс `/api/v1`.\n\n## О прокси с функцией удаления префикса пути { #about-proxies-with-a-stripped-path-prefix }\n\nПомните, что прокси с функцией удаления префикса пути — лишь один из вариантов настройки.\n\nВо многих случаях по умолчанию прокси будет без функции удаления префикса пути.\n\nВ таком случае (без функции удаления префикса пути) прокси слушает, например, по адресу `https://myawesomeapp.com`, и если браузер идёт на `https://myawesomeapp.com/api/v1/app`, а ваш сервер (например, Uvicorn) слушает на `http://127.0.0.1:8000`, то прокси (без урезанного префикса) обратится к Uvicorn по тому же пути: `http://127.0.0.1:8000/api/v1/app`.\n\n## Локальное тестирование с Traefik { #testing-locally-with-traefik }\n\nВы можете легко поэкспериментировать локально с функцией удаления префикса пути, используя [Traefik](https://docs.traefik.io/).\n\n[Скачайте Traefik](https://github.com/containous/traefik/releases) — это один бинарный файл; распакуйте архив и запустите его прямо из терминала.\n\nЗатем создайте файл `traefik.toml` со следующим содержимым:\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\nЭто говорит Traefik слушать порт 9999 и использовать другой файл `routes.toml`.\n\n/// tip | Совет\n\nМы используем порт 9999 вместо стандартного HTTP‑порта 80, чтобы не нужно было запускать с правами администратора (`sudo`).\n\n///\n\nТеперь создайте второй файл `routes.toml`:\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\nЭтот файл настраивает Traefik на использование префикса пути `/api/v1`.\n\nДалее Traefik будет проксировать запросы на ваш Uvicorn, работающий на `http://127.0.0.1:8000`.\n\nТеперь запустите Traefik:\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\nИ запустите приложение с опцией `--root-path`:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Проверьте ответы { #check-the-responses }\n\nТеперь, если вы перейдёте на URL с портом Uvicorn: [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), вы увидите обычный ответ:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip | Совет\n\nОбратите внимание, что хотя вы обращаетесь по `http://127.0.0.1:8000/app`, в ответе указан `root_path` равный `/api/v1`, взятый из опции `--root-path`.\n\n///\n\nА теперь откройте URL с портом Traefik и префиксом пути: [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app).\n\nМы получим тот же ответ:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nно уже по URL с префиксом, который добавляет прокси: `/api/v1`.\n\nРазумеется, задумывается, что все будут обращаться к приложению через прокси, поэтому вариант с префиксом пути `/api/v1` является «правильным».\n\nА вариант без префикса (`http://127.0.0.1:8000/app`), выдаваемый напрямую Uvicorn, предназначен исключительно для того, чтобы прокси (Traefik) мог к нему обращаться.\n\nЭто демонстрирует, как прокси (Traefik) использует префикс пути и как сервер (Uvicorn) использует `root_path`, переданный через опцию `--root-path`.\n\n### Проверьте интерфейс документации { #check-the-docs-ui }\n\nА вот самое интересное. ✨\n\n«Официальный» способ доступа к приложению — через прокси с заданным префиксом пути. Поэтому, как и ожидается, если открыть интерфейс документации, отдаваемый напрямую Uvicorn, без префикса пути в URL, он не будет работать, так как предполагается доступ через прокси.\n\nПроверьте по адресу [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\nА вот если открыть интерфейс документации по «официальному» URL через прокси на порту `9999`, по `/api/v1/docs`, всё работает корректно! 🎉\n\nПроверьте по адресу [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\nИменно как и хотелось. ✔️\n\nЭто потому, что FastAPI использует `root_path`, чтобы создать в OpenAPI сервер по умолчанию с URL из `root_path`.\n\n## Дополнительные серверы { #additional-servers }\n\n/// warning | Предупреждение\n\nЭто более продвинутый сценарий. Можно пропустить.\n\n///\n\nПо умолчанию FastAPI создаёт в схеме OpenAPI `server` с URL из `root_path`.\n\nНо вы также можете указать дополнительные `servers`, например, если хотите, чтобы один и тот же интерфейс документации работал и со <abbr title=\"«промежуточное» или «предпродакшн» окружение\">стейджингом</abbr>, и с продакшн.\n\nЕсли вы передадите свой список `servers` и при этом задан `root_path` (потому что ваш API работает за прокси), FastAPI вставит «server» с этим `root_path` в начало списка.\n\nНапример:\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\nБудет сгенерирована схема OpenAPI примерно такая:\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // Здесь ещё что-то\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // Здесь ещё что-то\n    }\n}\n```\n\n/// tip | Совет\n\nОбратите внимание на автоматически добавленный сервер с `url` равным `/api/v1`, взятым из `root_path`.\n\n///\n\nВ интерфейсе документации по адресу [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) это будет выглядеть так:\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip | Совет\n\nИнтерфейс документации будет взаимодействовать с сервером, который вы выберете.\n\n///\n\n/// note | Технические детали\n\nСвойство `servers` в спецификации OpenAPI является необязательным.\n\nЕсли вы не укажете параметр `servers`, а `root_path` равен `/`, то свойство `servers` в сгенерированной схеме OpenAPI по умолчанию будет опущено. Это эквивалентно серверу со значением `url` равным `/`.\n\n///\n\n### Отключить автоматическое добавление сервера из `root_path` { #disable-automatic-server-from-root-path }\n\nЕсли вы не хотите, чтобы FastAPI добавлял автоматический сервер, используя `root_path`, укажите параметр `root_path_in_servers=False`:\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\nи тогда этот сервер не будет добавлен в схему OpenAPI.\n\n## Монтирование вложенного приложения { #mounting-a-sub-application }\n\nЕсли вам нужно смонтировать вложенное приложение (как описано в [Вложенные приложения — монтирование](sub-applications.md)), и при этом вы используете прокси с `root_path`, делайте это обычным образом — всё будет работать, как ожидается.\n\nFastAPI умно использует `root_path` внутри, так что всё просто работает. ✨\n"
  },
  {
    "path": "docs/ru/docs/advanced/custom-response.md",
    "content": "# Кастомные ответы — HTML, поток, файл и другие { #custom-response-html-stream-file-others }\n\nПо умолчанию **FastAPI** возвращает ответы в формате JSON.\n\nВы можете переопределить это, вернув `Response` напрямую, как показано в разделе [Вернуть Response напрямую](response-directly.md).\n\nНо если вы возвращаете `Response` напрямую (или любой его подкласс, например `JSONResponse`), данные не будут автоматически преобразованы (даже если вы объявили `response_model`), и документация не будет автоматически сгенерирована (например, со специфичным «типом содержимого» в HTTP-заголовке `Content-Type` как частью сгенерированного OpenAPI).\n\nНо вы также можете объявить `Response`, который хотите использовать (например, любой подкласс `Response`), в декораторе операции пути, указав параметр `response_class`.\n\nСодержимое, которое вы возвращаете из своей функции-обработчика пути, будет помещено внутрь этого `Response`.\n\n/// note | Примечание\n\nЕсли вы используете класс ответа без типа содержимого, FastAPI будет ожидать, что у вашего ответа нет содержимого, поэтому он не будет документировать формат ответа в сгенерированной документации OpenAPI.\n\n///\n\n## JSON-ответы { #json-responses }\n\nПо умолчанию FastAPI возвращает ответы в формате JSON.\n\nЕсли вы объявите [Модель ответа](../tutorial/response-model.md), FastAPI использует её для сериализации данных в JSON с помощью Pydantic.\n\nЕсли вы не объявите модель ответа, FastAPI использует `jsonable_encoder`, описанный в разделе [JSON-совместимый энкодер](../tutorial/encoder.md), и поместит результат в `JSONResponse`.\n\nЕсли вы объявите `response_class` с JSON типом содержимого (`application/json`), как в случае с `JSONResponse`, данные, которые вы возвращаете, будут автоматически преобразованы (и отфильтрованы) любой Pydantic-моделью ответа (`response_model`), объявленной вами в декораторе операции пути. Но данные не будут сериализованы в JSON-байты через Pydantic; вместо этого они будут преобразованы с помощью `jsonable_encoder`, а затем переданы в класс `JSONResponse`, который сериализует их в байты, используя стандартную JSON-библиотеку Python.\n\n### Производительность JSON { #json-performance }\n\nКоротко: если вам нужна максимальная производительность, используйте [Модель ответа](../tutorial/response-model.md) и не объявляйте `response_class` в декораторе операции пути.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## HTML-ответ { #html-response }\n\nЧтобы вернуть ответ с HTML напрямую из **FastAPI**, используйте `HTMLResponse`.\n\n- Импортируйте `HTMLResponse`.\n- Передайте `HTMLResponse` в параметр `response_class` вашего декоратора операции пути.\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info | Информация\n\nПараметр `response_class` также используется для указания «типа содержимого» ответа.\n\nВ этом случае HTTP-заголовок `Content-Type` будет установлен в `text/html`.\n\nИ это будет задокументировано как таковое в OpenAPI.\n\n///\n\n### Вернуть `Response` { #return-a-response }\n\nКак показано в разделе [Вернуть Response напрямую](response-directly.md), вы также можете переопределить ответ прямо в своей операции пути, просто вернув его.\n\nТот же пример сверху, возвращающий `HTMLResponse`, может выглядеть так:\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning | Предупреждение\n\n`Response`, возвращённый напрямую вашей функцией-обработчиком пути, не будет задокументирован в OpenAPI (например, `Content-Type` не будет задокументирован) и не будет виден в автоматически сгенерированной интерактивной документации.\n\n///\n\n/// info | Информация\n\nРазумеется, фактический заголовок `Content-Type`, статус-код и т.д. возьмутся из объекта `Response`, который вы вернули.\n\n///\n\n### Задокументировать в OpenAPI и переопределить `Response` { #document-in-openapi-and-override-response }\n\nЕсли вы хотите переопределить ответ внутри функции, но при этом задокументировать «тип содержимого» в OpenAPI, вы можете использовать параметр `response_class` И вернуть объект `Response`.\n\nТогда `response_class` будет использоваться только для документирования *операции пути* в OpenAPI, а ваш `Response` будет использован как есть.\n\n#### Вернуть `HTMLResponse` напрямую { #return-an-htmlresponse-directly }\n\nНапример, это может быть что-то вроде:\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\nВ этом примере функция `generate_html_response()` уже генерирует и возвращает `Response` вместо возврата HTML в `str`.\n\nВозвращая результат вызова `generate_html_response()`, вы уже возвращаете `Response`, который переопределит поведение **FastAPI** по умолчанию.\n\nНо поскольку вы также передали `HTMLResponse` в `response_class`, **FastAPI** будет знать, как задокументировать это в OpenAPI и интерактивной документации как HTML с `text/html`:\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## Доступные ответы { #available-responses }\n\nНиже перечислены некоторые доступные классы ответов.\n\nУчтите, что вы можете использовать `Response`, чтобы вернуть что угодно ещё, или даже создать собственный подкласс.\n\n/// note | Технические детали\n\nВы также могли бы использовать `from starlette.responses import HTMLResponse`.\n\n**FastAPI** предоставляет те же `starlette.responses` как `fastapi.responses` для вашего удобства как разработчика. Но большинство доступных классов ответов приходят непосредственно из Starlette.\n\n///\n\n### `Response` { #response }\n\nБазовый класс `Response`, от него наследуются все остальные ответы.\n\nЕго можно возвращать напрямую.\n\nОн принимает следующие параметры:\n\n- `content` — `str` или `bytes`.\n- `status_code` — целое число, HTTP статус-код.\n- `headers` — словарь строк.\n- `media_type` — строка, задающая тип содержимого. Например, `\"text/html\"`.\n\nFastAPI (фактически Starlette) автоматически добавит заголовок Content-Length. Также будет добавлен заголовок Content-Type, основанный на `media_type` и с добавлением charset для текстовых типов.\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\nПринимает текст или байты и возвращает HTML-ответ, как описано выше.\n\n### `PlainTextResponse` { #plaintextresponse }\n\nПринимает текст или байты и возвращает ответ в виде простого текста.\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\nПринимает данные и возвращает ответ, кодированный как `application/json`.\n\nЭто ответ по умолчанию, используемый в **FastAPI**, как было сказано выше.\n\n/// note | Технические детали\n\nНо если вы объявите модель ответа или тип возвращаемого значения, они будут использованы напрямую для сериализации данных в JSON, и ответ с корректным типом содержимого для JSON будет возвращён напрямую, без использования класса `JSONResponse`.\n\nЭто идеальный способ получить наилучшую производительность.\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\nВозвращает HTTP-редирект. По умолчанию использует статус-код 307 (Temporary Redirect — временное перенаправление).\n\nВы можете вернуть `RedirectResponse` напрямую:\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\nИли можно использовать его в параметре `response_class`:\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\nЕсли вы сделаете так, то сможете возвращать URL напрямую из своей функции-обработчика пути.\n\nВ этом случае будет использован статус-код по умолчанию для `RedirectResponse`, то есть `307`.\n\n---\n\nТакже вы можете использовать параметр `status_code` в сочетании с параметром `response_class`:\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\nПринимает асинхронный генератор или обычный генератор/итератор (функцию с `yield`) и отправляет тело ответа потоково.\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | Технические детали\n\nЗадача `async` может быть отменена только при достижении `await`. Если `await` отсутствует, генератор (функция с `yield`) не может быть корректно отменён и может продолжить работу даже после запроса на отмену.\n\nТак как этому небольшому примеру не нужны операторы `await`, мы добавляем `await anyio.sleep(0)`, чтобы дать циклу событий возможность обработать отмену.\n\nЭто ещё более важно для больших или бесконечных потоков.\n\n///\n\n/// tip | Совет\n\nВместо того чтобы возвращать `StreamingResponse` напрямую, вероятно, лучше следовать стилю из раздела [Передача данных потоком](./stream-data.md) - так гораздо удобнее, и отмена обрабатывается «за кулисами».\n\nЕсли вы передаёте JSON Lines потоком, следуйте руководству [Поток JSON Lines](../tutorial/stream-json-lines.md).\n\n///\n\n### `FileResponse` { #fileresponse }\n\nАсинхронно отправляет файл как ответ.\n\nДля создания экземпляра принимает иной набор аргументов, чем другие типы ответов:\n\n- `path` — путь к файлу, который будет отправлен.\n- `headers` — любые дополнительные заголовки для включения, в виде словаря.\n- `media_type` — строка, задающая тип содержимого. Если не задан, для определения типа содержимого будет использовано имя файла или путь.\n- `filename` — если задан, будет включён в заголовок ответа `Content-Disposition`.\n\nФайловые ответы будут содержать соответствующие заголовки `Content-Length`, `Last-Modified` и `ETag`.\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\nВы также можете использовать параметр `response_class`:\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\nВ этом случае вы можете возвращать путь к файлу напрямую из своей функции-обработчика пути.\n\n## Пользовательский класс ответа { #custom-response-class }\n\nВы можете создать собственный класс ответа, унаследовавшись от `Response`, и использовать его.\n\nНапример, предположим, что вы хотите использовать [`orjson`](https://github.com/ijl/orjson) с некоторыми настройками.\n\nСкажем, вы хотите, чтобы возвращался отформатированный JSON с отступами, то есть хотите использовать опцию orjson `orjson.OPT_INDENT_2`.\n\nВы могли бы создать `CustomORJSONResponse`. Главное, что вам нужно сделать — реализовать метод `Response.render(content)`, который возвращает содержимое как `bytes`:\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\nТеперь вместо того, чтобы возвращать:\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n...этот ответ вернёт:\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\nРазумеется, вы наверняка найдёте гораздо более полезные способы воспользоваться этим, чем просто форматирование JSON. 😉\n\n### `orjson` или Модель ответа { #orjson-or-response-model }\n\nЕсли вы стремитесь увеличить производительность, вероятно, лучше использовать [Модель ответа](../tutorial/response-model.md), чем ответ на базе `orjson`.\n\nС моделью ответа FastAPI использует Pydantic для сериализации данных в JSON, без промежуточных шагов, таких как преобразование через `jsonable_encoder`, которое происходило бы в любом другом случае.\n\nА под капотом Pydantic использует те же базовые механизмы на Rust, что и `orjson`, для сериализации в JSON, так что с моделью ответа вы и так получите лучшую производительность.\n\n## Класс ответа по умолчанию { #default-response-class }\n\nПри создании экземпляра класса **FastAPI** или `APIRouter` вы можете указать, какой класс ответа использовать по умолчанию.\n\nПараметр, который это определяет, — `default_response_class`.\n\nВ примере ниже **FastAPI** будет использовать `HTMLResponse` по умолчанию во всех операциях пути, вместо JSON.\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip | Совет\n\nВы по-прежнему можете переопределять `response_class` в операциях пути, как и раньше.\n\n///\n\n## Дополнительная документация { #additional-documentation }\n\nВы также можете объявить тип содержимого и многие другие детали в OpenAPI с помощью `responses`: [Дополнительные ответы в OpenAPI](additional-responses.md).\n"
  },
  {
    "path": "docs/ru/docs/advanced/dataclasses.md",
    "content": "# Использование dataclasses { #using-dataclasses }\n\nFastAPI построен поверх **Pydantic**, и я показывал вам, как использовать Pydantic-модели для объявления HTTP-запросов и HTTP-ответов.\n\nНо FastAPI также поддерживает использование [`dataclasses`](https://docs.python.org/3/library/dataclasses.html) тем же способом:\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\nЭто по-прежнему поддерживается благодаря **Pydantic**, так как в нём есть [встроенная поддержка `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).\n\nТак что даже если в коде выше Pydantic не используется явно, FastAPI использует Pydantic, чтобы конвертировать стандартные dataclasses в собственный вариант dataclasses от Pydantic.\n\nИ, конечно, поддерживаются те же возможности:\n\n- валидация данных\n- сериализация данных\n- документирование данных и т.д.\n\nЭто работает так же, как с Pydantic-моделями. И на самом деле под капотом это достигается тем же образом, с использованием Pydantic.\n\n/// info | Информация\n\nПомните, что dataclasses не умеют всего того, что умеют Pydantic-модели.\n\nПоэтому вам всё ещё может потребоваться использовать Pydantic-модели.\n\nНо если у вас уже есть набор dataclasses, это полезный приём — задействовать их для веб-API на FastAPI. 🤓\n\n///\n\n## Dataclasses в `response_model` { #dataclasses-in-response-model }\n\nВы также можете использовать `dataclasses` в параметре `response_model`:\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\nЭтот dataclass будет автоматически преобразован в Pydantic dataclass.\n\nТаким образом, его схема появится в интерфейсе документации API:\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## Dataclasses во вложенных структурах данных { #dataclasses-in-nested-data-structures }\n\nВы также можете комбинировать `dataclasses` с другими аннотациями типов, чтобы создавать вложенные структуры данных.\n\nВ некоторых случаях вам всё же может понадобиться использовать версию `dataclasses` из Pydantic. Например, если у вас возникают ошибки с автоматически генерируемой документацией API.\n\nВ таком случае вы можете просто заменить стандартные `dataclasses` на `pydantic.dataclasses`, которая является полностью совместимой заменой (drop-in replacement):\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. Мы по-прежнему импортируем `field` из стандартных `dataclasses`.\n\n2. `pydantic.dataclasses` — полностью совместимая замена (drop-in replacement) для `dataclasses`.\n\n3. Dataclass `Author` содержит список dataclass `Item`.\n\n4. Dataclass `Author` используется в параметре `response_model`.\n\n5. Вы можете использовать и другие стандартные аннотации типов вместе с dataclasses в качестве тела запроса.\n\n    В этом случае это список dataclass `Item`.\n\n6. Здесь мы возвращаем словарь, содержащий `items`, который является списком dataclass.\n\n    FastAPI по-прежнему способен <dfn title=\"преобразование данных в формат, который можно передавать\">сериализовать</dfn> данные в JSON.\n\n7. Здесь `response_model` использует аннотацию типа — список dataclass `Author`.\n\n    Снова, вы можете комбинировать `dataclasses` со стандартными аннотациями типов.\n\n8. Обратите внимание, что эта *функция-обработчик пути* использует обычный `def` вместо `async def`.\n\n    Как и всегда в FastAPI, вы можете сочетать `def` и `async def` по необходимости.\n\n    Если хотите освежить в памяти, когда что использовать, посмотрите раздел _\"Нет времени?\"_ в документации про [`async` и `await`](../async.md#in-a-hurry).\n\n9. Эта *функция-обработчик пути* возвращает не dataclasses (хотя могла бы), а список словарей с внутренними данными.\n\n    FastAPI использует параметр `response_model` (в котором заданы dataclasses), чтобы преобразовать HTTP-ответ.\n\nВы можете комбинировать `dataclasses` с другими аннотациями типов множеством способов, чтобы формировать сложные структуры данных.\n\nСмотрите подсказки в коде выше, чтобы увидеть более конкретные детали.\n\n## Узнать больше { #learn-more }\n\nВы также можете комбинировать `dataclasses` с другими Pydantic-моделями, наследоваться от них, включать их в свои модели и т.д.\n\nЧтобы узнать больше, посмотрите [документацию Pydantic о dataclasses](https://docs.pydantic.dev/latest/concepts/dataclasses/).\n\n## Версия { #version }\n\nДоступно начиная с версии FastAPI `0.67.0`. 🔖\n"
  },
  {
    "path": "docs/ru/docs/advanced/events.md",
    "content": "# События lifespan { #lifespan-events }\n\nВы можете определить логику (код), которую нужно выполнить перед тем, как приложение начнет запускаться. Это означает, что этот код будет выполнен один раз, перед тем как приложение начнет получать HTTP-запросы.\n\nАналогично, вы можете определить логику (код), которую нужно выполнить, когда приложение завершает работу. В этом случае код будет выполнен один раз, после обработки, возможно, многих запросов.\n\nПоскольку этот код выполняется до того, как приложение начинает принимать запросы, и сразу после того, как оно заканчивает их обрабатывать, он охватывает весь lifespan (жизненный цикл) приложения (слово «lifespan» станет важным через секунду 😉).\n\nЭто может быть очень полезно для настройки ресурсов, которые нужны для всего приложения, которые разделяются между запросами и/или которые нужно затем очистить. Например, пул подключений к базе данных или загрузка общей модели Машинного обучения.\n\n## Вариант использования { #use-case }\n\nНачнем с примера варианта использования, а затем посмотрим, как это решить.\n\nПредставим, что у вас есть несколько моделей Машинного обучения, которые вы хотите использовать для обработки запросов. 🤖\n\nЭти же модели разделяются между запросами, то есть это не одна модель на запрос, не одна на пользователя и т.п.\n\nПредставим, что загрузка модели может занимать довольно много времени, потому что ей нужно прочитать много данных с диска. Поэтому вы не хотите делать это для каждого запроса.\n\nВы могли бы загрузить её на верхнем уровне модуля/файла, но это означало бы, что модель загружается даже если вы просто запускаете простой автоматический тест; тогда этот тест будет медленным, так как ему придется ждать загрузки модели перед запуском независимой части кода.\n\nИменно это мы и решим: давайте загружать модель перед тем, как начнётся обработка запросов, но только непосредственно перед тем, как приложение начнет принимать запросы, а не во время загрузки кода.\n\n## Lifespan { #lifespan }\n\nВы можете определить логику для startup и shutdown, используя параметр `lifespan` приложения `FastAPI` и «менеджер контекста» (через секунду покажу что это).\n\nНачнем с примера, а затем разберём его подробнее.\n\nМы создаём асинхронную функцию `lifespan()` с `yield` примерно так:\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\nЗдесь мы симулируем дорогую операцию startup по загрузке модели, помещая (фиктивную) функцию модели в словарь с моделями Машинного обучения до `yield`. Этот код будет выполнен до того, как приложение начнет принимать запросы, во время startup.\n\nА затем сразу после `yield` мы выгружаем модель. Этот код будет выполнен после того, как приложение закончит обрабатывать запросы, непосредственно перед shutdown. Это может, например, освободить ресурсы, такие как память или GPU.\n\n/// tip | Совет\n\n`shutdown` произойдёт, когда вы останавливаете приложение.\n\nВозможно, вам нужно запустить новую версию, или вы просто устали от него. 🤷\n\n///\n\n### Функция lifespan { #lifespan-function }\n\nПервое, на что стоит обратить внимание, — мы определяем асинхронную функцию с `yield`. Это очень похоже на Зависимости с `yield`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\nПервая часть функции, до `yield`, будет выполнена до запуска приложения.\n\nА часть после `yield` будет выполнена после завершения работы приложения.\n\n### Асинхронный менеджер контекста { #async-context-manager }\n\nЕсли присмотреться, функция декорирована `@asynccontextmanager`.\n\nЭто превращает функцию в «асинхронный менеджер контекста».\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\nМенеджер контекста в Python — это то, что можно использовать в операторе `with`. Например, `open()` можно использовать как менеджер контекста:\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\nВ последних версиях Python есть также асинхронный менеджер контекста. Его используют с `async with`:\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\nКогда вы создаёте менеджер контекста или асинхронный менеджер контекста, как выше, он перед входом в блок `with` выполнит код до `yield`, а после выхода из блока `with` выполнит код после `yield`.\n\nВ нашем примере выше мы не используем его напрямую, а передаём его в FastAPI, чтобы он использовал его сам.\n\nПараметр `lifespan` приложения `FastAPI` принимает асинхронный менеджер контекста, поэтому мы можем передать ему наш новый асинхронный менеджер контекста `lifespan`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## Альтернативные события (устаревшие) { #alternative-events-deprecated }\n\n/// warning | Предупреждение\n\nРекомендуемый способ обрабатывать startup и shutdown — использовать параметр `lifespan` приложения `FastAPI`, как описано выше. Если вы укажете параметр `lifespan`, обработчики событий `startup` и `shutdown` больше вызываться не будут. Либо всё через `lifespan`, либо всё через события — не одновременно.\n\nЭту часть, скорее всего, можно пропустить.\n\n///\n\nЕсть альтернативный способ определить логику, которую нужно выполнить во время startup и во время shutdown.\n\nВы можете определить обработчики событий (функции), которые нужно выполнить до старта приложения или при его завершении.\n\nЭти функции можно объявить с `async def` или обычным `def`.\n\n### Событие `startup` { #startup-event }\n\nЧтобы добавить функцию, которую нужно запустить до старта приложения, объявите её как обработчик события `\"startup\"`:\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\nВ этом случае функция-обработчик события `startup` инициализирует «базу данных» items (это просто `dict`) некоторыми значениями.\n\nВы можете добавить более одного обработчика события.\n\nИ ваше приложение не начнет принимать запросы, пока все обработчики события `startup` не завершатся.\n\n### Событие `shutdown` { #shutdown-event }\n\nЧтобы добавить функцию, которую нужно запустить при завершении работы приложения, объявите её как обработчик события `\"shutdown\"`:\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\nЗдесь функция-обработчик события `shutdown` запишет строку текста `\"Application shutdown\"` в файл `log.txt`.\n\n/// info | Информация\n\nВ функции `open()` параметр `mode=\"a\"` означает «добавление» (append), то есть строка будет добавлена в конец файла, без перезаписи предыдущего содержимого.\n\n///\n\n/// tip | Совет\n\nОбратите внимание, что в этом случае мы используем стандартную Python-функцию `open()`, которая взаимодействует с файлом.\n\nТо есть это I/O (ввод/вывод), требующий «ожидания» записи на диск.\n\nНо `open()` не использует `async` и `await`.\n\nПоэтому мы объявляем обработчик события обычным `def` вместо `async def`.\n\n///\n\n### `startup` и `shutdown` вместе { #startup-and-shutdown-together }\n\nС высокой вероятностью логика для вашего startup и shutdown связана: вы можете хотеть что-то запустить, а затем завершить, получить ресурс, а затем освободить его и т.д.\n\nДелать это в отдельных функциях, которые не разделяют общую логику или переменные, сложнее, так как придётся хранить значения в глобальных переменных или использовать похожие приёмы.\n\nПоэтому теперь рекомендуется использовать `lifespan`, как описано выше.\n\n## Технические детали { #technical-details }\n\nНемного технических подробностей для любопытных умников. 🤓\n\nПод капотом, в ASGI-технической спецификации, это часть [Протокола Lifespan](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), и он определяет события `startup` и `shutdown`.\n\n/// info | Информация\n\nВы можете прочитать больше про обработчики `lifespan` в Starlette в [документации Starlette по Lifespan](https://www.starlette.dev/lifespan/).\n\nВключая то, как работать с состоянием lifespan, которое можно использовать в других частях вашего кода.\n\n///\n\n## Подприложения { #sub-applications }\n\n🚨 Имейте в виду, что эти события lifespan (startup и shutdown) будут выполнены только для основного приложения, а не для [Подприложения — Mounts](sub-applications.md).\n"
  },
  {
    "path": "docs/ru/docs/advanced/generate-clients.md",
    "content": "# Генерация SDK { #generating-sdks }\n\nПоскольку **FastAPI** основан на спецификации **OpenAPI**, его API можно описать в стандартном формате, понятном множеству инструментов.\n\nЭто упрощает генерацию актуальной **документации**, клиентских библиотек (<abbr title=\"Software Development Kits - Наборы средств разработки\">**SDKs**</abbr>) на разных языках, а также **тестирования** или **воркфлоу автоматизации**, которые остаются синхронизированными с вашим кодом.\n\nВ этом руководстве вы узнаете, как сгенерировать **TypeScript SDK** для вашего бэкенда на FastAPI.\n\n## Генераторы SDK с открытым исходным кодом { #open-source-sdk-generators }\n\nГибкий вариант — [OpenAPI Generator](https://openapi-generator.tech/), который поддерживает **многие языки программирования** и умеет генерировать SDK из вашей спецификации OpenAPI.\n\nДля **TypeScript‑клиентов** [Hey API](https://heyapi.dev/) — специализированное решение, обеспечивающее оптимальный опыт для экосистемы TypeScript.\n\nБольше генераторов SDK можно найти на [OpenAPI.Tools](https://openapi.tools/#sdk).\n\n/// tip | Совет\n\nFastAPI автоматически генерирует спецификации **OpenAPI 3.1**, поэтому любой используемый инструмент должен поддерживать эту версию.\n\n///\n\n## Генераторы SDK от спонсоров FastAPI { #sdk-generators-from-fastapi-sponsors }\n\nВ этом разделе представлены решения с **венчурной поддержкой** и **поддержкой компаний** от компаний, которые спонсируют FastAPI. Эти продукты предоставляют **дополнительные возможности** и **интеграции** сверх высококачественно генерируемых SDK.\n\nБлагодаря ✨ [**спонсорству FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ эти компании помогают обеспечивать, чтобы фреймворк и его **экосистема** оставались здоровыми и **устойчивыми**.\n\nИх спонсорство также демонстрирует серьёзную приверженность **сообществу** FastAPI (вам), показывая, что им важно не только предоставлять **отличный сервис**, но и поддерживать **надёжный и процветающий фреймворк** FastAPI. 🙇\n\nНапример, вы можете попробовать:\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\nНекоторые из этих решений также могут быть open source или иметь бесплатные тарифы, так что вы сможете попробовать их без финансовых затрат. Другие коммерческие генераторы SDK доступны и их можно найти онлайн. 🤓\n\n## Создать TypeScript SDK { #create-a-typescript-sdk }\n\nНачнём с простого приложения FastAPI:\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\nОбратите внимание, что *операции пути (обработчики пути)* определяют модели, которые они используют для полезной нагрузки запроса и полезной нагрузки ответа, с помощью моделей `Item` и `ResponseMessage`.\n\n### Документация API { #api-docs }\n\nЕсли перейти на `/docs`, вы увидите **схемы** данных, отправляемых в запросах и принимаемых в ответах:\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\nВы видите эти схемы, потому что они были объявлены с моделями в приложении.\n\nЭта информация доступна в **схеме OpenAPI** приложения и затем отображается в документации API.\n\nТа же информация из моделей, включённая в OpenAPI, может использоваться для **генерации клиентского кода**.\n\n### Hey API { #hey-api }\n\nКак только у нас есть приложение FastAPI с моделями, мы можем использовать Hey API для генерации TypeScript‑клиента. Самый быстрый способ сделать это — через npx.\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\nЭто сгенерирует TypeScript SDK в `./src/client`.\n\nВы можете узнать, как [установить `@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started) и почитать о [сгенерированном результате](https://heyapi.dev/openapi-ts/output) на их сайте.\n\n### Использование SDK { #using-the-sdk }\n\nТеперь вы можете импортировать и использовать клиентский код. Это может выглядеть так, обратите внимание, что вы получаете автозавершение для методов:\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\nВы также получите автозавершение для отправляемой полезной нагрузки:\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip | Совет\n\nОбратите внимание на автозавершение для `name` и `price`, это было определено в приложении FastAPI, в модели `Item`.\n\n///\n\nВы получите ошибки прямо в редакторе для отправляемых данных:\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\nОбъект ответа также будет иметь автозавершение:\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## Приложение FastAPI с тегами { #fastapi-app-with-tags }\n\nВо многих случаях ваше приложение FastAPI будет больше, и вы, вероятно, будете использовать теги, чтобы разделять разные группы *операций пути*.\n\nНапример, у вас может быть раздел для **items** и другой раздел для **users**, и они могут быть разделены тегами:\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### Генерация TypeScript‑клиента с тегами { #generate-a-typescript-client-with-tags }\n\nЕсли вы генерируете клиент для приложения FastAPI с использованием тегов, обычно клиентский код также будет разделён по тегам.\n\nТаким образом вы сможете иметь всё правильно упорядоченным и сгруппированным в клиентском коде:\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\nВ этом случае у вас есть:\n\n* `ItemsService`\n* `UsersService`\n\n### Имена методов клиента { #client-method-names }\n\nСейчас сгенерированные имена методов вроде `createItemItemsPost` выглядят не очень аккуратно:\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n...это потому, что генератор клиента использует внутренний **ID операции** OpenAPI для каждой *операции пути*.\n\nOpenAPI требует, чтобы каждый ID операции был уникален среди всех *операций пути*, поэтому FastAPI использует **имя функции**, **путь** и **HTTP‑метод/операцию** для генерации этого ID операции, так как таким образом можно гарантировать уникальность ID операций.\n\nНо далее я покажу, как это улучшить. 🤓\n\n## Пользовательские ID операций и лучшие имена методов { #custom-operation-ids-and-better-method-names }\n\nВы можете **изменить** способ **генерации** этих ID операций, чтобы сделать их проще, а имена методов в клиентах — **более простыми**.\n\nВ этом случае вам нужно будет обеспечить, чтобы каждый ID операции был **уникальным** другим способом.\n\nНапример, вы можете гарантировать, что у каждой *операции пути* есть тег, и затем генерировать ID операции на основе **тега** и **имени** *операции пути* (имени функции).\n\n### Пользовательская функция генерации уникального ID { #custom-generate-unique-id-function }\n\nFastAPI использует **уникальный ID** для каждой *операции пути*, который применяется для **ID операции**, а также для имён любых необходимых пользовательских моделей запросов или ответов.\n\nВы можете кастомизировать эту функцию. Она принимает `APIRoute` и возвращает строку.\n\nНапример, здесь берётся первый тег (скорее всего у вас один тег) и имя *операции пути* (имя функции).\n\nЗатем вы можете передать эту пользовательскую функцию в **FastAPI** через параметр `generate_unique_id_function`:\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### Генерация TypeScript‑клиента с пользовательскими ID операций { #generate-a-typescript-client-with-custom-operation-ids }\n\nТеперь, если снова сгенерировать клиент, вы увидите, что имена методов улучшились:\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\nКак видите, теперь имена методов содержат тег, а затем имя функции; больше они не включают информацию из URL‑пути и HTTP‑операции.\n\n### Предобработка спецификации OpenAPI для генератора клиента { #preprocess-the-openapi-specification-for-the-client-generator }\n\nВ сгенерированном коде всё ещё есть **дублирующаяся информация**.\n\nМы уже знаем, что этот метод относится к **items**, потому что это слово есть в `ItemsService` (взято из тега), но при этом имя тега всё ещё добавлено префиксом к имени метода. 😕\n\nСкорее всего мы захотим оставить это в OpenAPI в целом, так как это гарантирует, что ID операций будут **уникальны**.\n\nНо для сгенерированного клиента мы можем **модифицировать** ID операций OpenAPI непосредственно перед генерацией клиентов, чтобы сделать имена методов более приятными и **чистыми**.\n\nМы можем скачать OpenAPI JSON в файл `openapi.json`, а затем **убрать этот префикс‑тег** таким скриптом:\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\nПосле этого ID операций будут переименованы с чего‑то вроде `items-get_items` просто в `get_items`, и генератор клиента сможет создавать более простые имена методов.\n\n### Генерация TypeScript‑клиента с предобработанным OpenAPI { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\nТак как конечный результат теперь в файле `openapi.json`, нужно обновить входное расположение:\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\nПосле генерации нового клиента у вас будут **чистые имена методов**, со всем **автозавершением**, **ошибками прямо в редакторе** и т.д.:\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## Преимущества { #benefits }\n\nПри использовании автоматически сгенерированных клиентов вы получите **автозавершение** для:\n\n* Методов.\n* Данных запроса — в теле запроса, query‑параметрах и т.д.\n* Данных ответа.\n\nУ вас также будут **ошибки прямо в редакторе** для всего.\n\nИ каждый раз, когда вы обновляете код бэкенда и **перегенерируете** фронтенд, в нём появятся новые *операции пути* как методы, старые будут удалены, а любые другие изменения отразятся в сгенерированном коде. 🤓\n\nЭто также означает, что если что‑то изменилось, это будет **отражено** в клиентском коде автоматически. И если вы **соберёте** клиент, он завершится с ошибкой, если где‑то есть **несоответствие** в используемых данных.\n\nТаким образом, вы **обнаружите многие ошибки** очень рано в цикле разработки, вместо того чтобы ждать, когда ошибки проявятся у конечных пользователей в продакшн, и затем пытаться отладить, в чём проблема. ✨\n"
  },
  {
    "path": "docs/ru/docs/advanced/index.md",
    "content": "# Расширенное руководство пользователя { #advanced-user-guide }\n\n## Дополнительные возможности { #additional-features }\n\nОсновное [Учебник - Руководство пользователя](../tutorial/index.md) должно быть достаточно, чтобы познакомить вас со всеми основными функциями **FastAPI**.\n\nВ следующих разделах вы увидите другие варианты, конфигурации и дополнительные возможности.\n\n/// tip | Совет\n\nСледующие разделы **не обязательно являются \"продвинутыми\"**.\n\nИ вполне возможно, что для вашего случая использования решение находится в одном из них.\n\n///\n\n## Сначала прочитайте Учебник - Руководство пользователя { #read-the-tutorial-first }\n\nВы все еще можете использовать большинство функций **FastAPI** со знаниями из [Учебник - Руководство пользователя](../tutorial/index.md).\n\nИ следующие разделы предполагают, что вы уже прочитали его, и предполагают, что вы знаете эти основные идеи.\n"
  },
  {
    "path": "docs/ru/docs/advanced/json-base64-bytes.md",
    "content": "# JSON с байтами в Base64 { #json-with-bytes-as-base64 }\n\nЕсли вашему приложению нужно принимать и отправлять JSON-данные, но при этом необходимо включать в них бинарные данные, вы можете кодировать их в base64.\n\n## Base64 и файлы { #base64-vs-files }\n\nСначала рассмотрите возможность использовать [Файлы в запросе](../tutorial/request-files.md) для загрузки бинарных данных и [Пользовательский HTTP-ответ — FileResponse](./custom-response.md#fileresponse--fileresponse-) для отправки бинарных данных вместо кодирования их в JSON.\n\nJSON может содержать только строки в кодировке UTF-8, поэтому он не может содержать «сырые» байты.\n\nBase64 может кодировать бинарные данные в строки, но для этого используется больше символов, чем в исходных бинарных данных, поэтому обычно это менее эффективно, чем обычные файлы.\n\nИспользуйте base64 только если вам действительно нужно включать бинарные данные в JSON и вы не можете использовать файлы для этого.\n\n## Pydantic `bytes` { #pydantic-bytes }\n\nВы можете объявить Pydantic-модель с полями `bytes`, а затем использовать `val_json_bytes` в конфиге модели, чтобы указать использовать base64 для валидации входящих JSON-данных; как часть этой валидации строка base64 будет декодирована в байты.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\nЕсли вы откроете `/docs`, вы увидите, что поле `data` ожидает байты, закодированные в base64:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\nВы можете отправить такой HTTP-запрос:\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip | Совет\n\n`aGVsbG8=` — это base64-кодирование строки `hello`.\n\n///\n\nЗатем Pydantic декодирует строку base64 и передаст вам исходные байты в поле `data` модели.\n\nВы получите такой HTTP-ответ:\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## Pydantic `bytes` для выходных данных { #pydantic-bytes-for-output-data }\n\nВы также можете использовать поля `bytes` с `ser_json_bytes` в конфиге модели для выходных данных, и Pydantic будет сериализовать байты в base64 при формировании JSON-ответа.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## Pydantic `bytes` для входных и выходных данных { #pydantic-bytes-for-input-and-output-data }\n\nИ, конечно, вы можете использовать одну и ту же модель, настроенную на использование base64, чтобы обрабатывать и входящие данные (валидация) с `val_json_bytes`, и исходящие данные (сериализация) с `ser_json_bytes` при приеме и отправке JSON-данных.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/ru/docs/advanced/middleware.md",
    "content": "# Расширенное использование middleware { #advanced-middleware }\n\nВ основном руководстве вы читали, как добавить [пользовательское middleware](../tutorial/middleware.md) в ваше приложение.\n\nА затем — как работать с [CORS с помощью `CORSMiddleware`](../tutorial/cors.md).\n\nВ этом разделе посмотрим, как использовать другие middleware.\n\n## Добавление ASGI middleware { #adding-asgi-middlewares }\n\nТак как **FastAPI** основан на Starlette и реализует спецификацию <abbr title=\"Asynchronous Server Gateway Interface – Асинхронный шлюзовой интерфейс сервера\">ASGI</abbr>, вы можете использовать любое ASGI middleware.\n\nMiddleware не обязательно должно быть сделано специально для FastAPI или Starlette — достаточно, чтобы оно соответствовало спецификации ASGI.\n\nВ общем случае ASGI middleware — это классы, которые ожидают получить ASGI‑приложение первым аргументом.\n\nПоэтому в документации к сторонним ASGI middleware, скорее всего, вы увидите что‑то вроде:\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\nНо FastAPI (точнее, Starlette) предоставляет более простой способ, который гарантирует корректную обработку внутренних ошибок сервера и корректную работу пользовательских обработчиков исключений.\n\nДля этого используйте `app.add_middleware()` (как в примере с CORS).\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` принимает класс middleware в качестве первого аргумента и любые дополнительные аргументы, которые будут переданы этому middleware.\n\n## Встроенные middleware { #integrated-middlewares }\n\n**FastAPI** включает несколько middleware для распространённых сценариев. Ниже рассмотрим, как их использовать.\n\n/// note | Технические детали\n\nВ следующих примерах вы также можете использовать `from starlette.middleware.something import SomethingMiddleware`.\n\n**FastAPI** предоставляет несколько middleware в `fastapi.middleware` для удобства разработчика. Но большинство доступных middleware приходит напрямую из Starlette.\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\nГарантирует, что все входящие запросы должны использовать либо `https`, либо `wss`.\n\nЛюбой входящий запрос по `http` или `ws` будет перенаправлен на безопасную схему.\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\nГарантирует, что во всех входящих запросах корректно установлен `Host`‑заголовок, чтобы защититься от атак на HTTP‑заголовок Host.\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\nПоддерживаются следующие аргументы:\n\n- `allowed_hosts` — список доменных имён, которые следует разрешить как имена хостов. Подстановки вида `*.example.com` поддерживаются для сопоставления поддоменов. Чтобы разрешить любой хост, используйте либо `allowed_hosts=[\"*\"]`, либо не добавляйте это middleware.\n- `www_redirect` — если установлено в True, запросы к не‑www версиям разрешённых хостов будут перенаправляться на их www‑аналоги. По умолчанию — `True`.\n\nЕсли входящий запрос не проходит валидацию, будет отправлен ответ `400`.\n\n## `GZipMiddleware` { #gzipmiddleware }\n\nОбрабатывает GZip‑ответы для любых запросов, которые включают `\"gzip\"` в заголовке `Accept-Encoding`.\n\nЭто middleware обрабатывает как обычные, так и потоковые ответы.\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\nПоддерживаются следующие аргументы:\n\n- `minimum_size` — не сжимать GZip‑ом ответы, размер которых меньше этого минимального значения в байтах. По умолчанию — `500`.\n- `compresslevel` — уровень GZip‑сжатия. Целое число от 1 до 9. По умолчанию — `9`. Более низкое значение — быстрее сжатие, но больший размер файла; более высокое значение — более медленное сжатие, но меньший размер файла.\n\n## Другие middleware { #other-middlewares }\n\nСуществует много других ASGI middleware.\n\nНапример:\n\n- [`ProxyHeadersMiddleware` от Uvicorn](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n- [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\nЧтобы увидеть другие доступные middleware, посмотрите [документацию по middleware в Starlette](https://www.starlette.dev/middleware/) и [список ASGI Awesome](https://github.com/florimondmanca/awesome-asgi).\n"
  },
  {
    "path": "docs/ru/docs/advanced/openapi-callbacks.md",
    "content": "# Обратные вызовы в OpenAPI { #openapi-callbacks }\n\nВы можете создать API с *операцией пути* (обработчиком пути), которая будет инициировать HTTP-запрос к *внешнему API*, созданному кем-то другим (скорее всего тем же разработчиком, который будет использовать ваш API).\n\nПроцесс, происходящий, когда ваше приложение API обращается к *внешнему API*, называется «callback» (обратный вызов). Программное обеспечение, написанное внешним разработчиком, отправляет HTTP-запрос вашему API, а затем ваш API выполняет обратный вызов, отправляя HTTP-запрос во *внешний API* (который, вероятно, тоже создал тот же разработчик).\n\nВ этом случае вам может понадобиться задокументировать, как должно выглядеть это внешнее API: какую *операцию пути* оно должно иметь, какое тело запроса ожидать, какой ответ возвращать и т.д.\n\n## Приложение с обратными вызовами { #an-app-with-callbacks }\n\nДавайте рассмотрим это на примере.\n\nПредставьте, что вы разрабатываете приложение, позволяющее создавать счета.\n\nЭти счета будут иметь `id`, `title` (необязательный), `customer` и `total`.\n\nПользователь вашего API (внешний разработчик) создаст счет в вашем API с помощью POST-запроса.\n\nЗатем ваш API (предположим) сделает следующее:\n\n* Отправит счет клиенту внешнего разработчика.\n* Получит оплату.\n* Отправит уведомление обратно пользователю API (внешнему разработчику).\n    * Это будет сделано отправкой POST-запроса (из *вашего API*) в *внешний API*, предоставленный этим внешним разработчиком (это и есть «callback»).\n\n## Обычное приложение **FastAPI** { #the-normal-fastapi-app }\n\nСначала посмотрим, как будет выглядеть обычное приложение API до добавления обратного вызова.\n\nВ нём будет *операция пути*, которая получит тело запроса `Invoice`, и query-параметр `callback_url`, содержащий URL для обратного вызова.\n\nЭта часть вполне обычна, большая часть кода вам уже знакома:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip | Совет\n\nQuery-параметр `callback_url` использует тип Pydantic [Url](https://docs.pydantic.dev/latest/api/networks/).\n\n///\n\nЕдинственное новое — это `callbacks=invoices_callback_router.routes` в качестве аргумента *декоратора операции пути*. Далее разберёмся, что это такое.\n\n## Документирование обратного вызова { #documenting-the-callback }\n\nРеальный код обратного вызова будет сильно зависеть от вашего приложения API.\n\nИ, вероятно, он будет заметно отличаться от одного приложения к другому.\n\nЭто могут быть буквально одна-две строки кода, например:\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\nНо, возможно, самая важная часть обратного вызова — это убедиться, что пользователь вашего API (внешний разработчик) правильно реализует *внешний API* в соответствии с данными, которые *ваш API* будет отправлять в теле запроса обратного вызова и т.п.\n\nПоэтому далее мы добавим код, документирующий, как должен выглядеть этот *внешний API*, чтобы получать обратный вызов от *вашего API*.\n\nЭта документация отобразится в Swagger UI по адресу `/docs` в вашем API и позволит внешним разработчикам понять, как построить *внешний API*.\n\nВ этом примере сам обратный вызов не реализуется (это может быть всего одна строка кода), реализуется только часть с документацией.\n\n/// tip | Совет\n\nСам обратный вызов — это всего лишь HTTP-запрос.\n\nРеализуя обратный вызов, вы можете использовать, например, [HTTPX](https://www.python-httpx.org) или [Requests](https://requests.readthedocs.io/).\n\n///\n\n## Напишите код документации обратного вызова { #write-the-callback-documentation-code }\n\nЭтот код не будет выполняться в вашем приложении, он нужен только для *документирования* того, как должен выглядеть *внешний API*.\n\nНо вы уже знаете, как легко получить автоматическую документацию для API с **FastAPI**.\n\nМы используем те же знания, чтобы задокументировать, как должен выглядеть *внешний API*... создав *операции пути*, которые внешний API должен реализовать (те, которые ваш API будет вызывать).\n\n/// tip | Совет\n\nКогда вы пишете код для документирования обратного вызова, полезно представить, что вы — тот самый *внешний разработчик*. И что вы сейчас реализуете *внешний API*, а не *свой API*.\n\nВременное принятие этой точки зрения (внешнего разработчика) поможет интуитивно понять, куда поместить параметры, какую Pydantic-модель использовать для тела запроса, для ответа и т.д. во *внешнем API*.\n\n///\n\n### Создайте `APIRouter` для обратного вызова { #create-a-callback-apirouter }\n\nСначала создайте новый `APIRouter`, который будет содержать один или несколько обратных вызовов.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### Создайте *операцию пути* для обратного вызова { #create-the-callback-path-operation }\n\nЧтобы создать *операцию пути* для обратного вызова, используйте тот же `APIRouter`, который вы создали выше.\n\nОна должна выглядеть как обычная *операция пути* FastAPI:\n\n* Вероятно, в ней должно быть объявление тела запроса, например `body: InvoiceEvent`.\n* А также может быть объявление модели ответа, например `response_model=InvoiceEventReceived`.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\nЕсть 2 основных отличия от обычной *операции пути*:\n\n* Ей не нужен реальный код, потому что ваше приложение никогда не будет вызывать эту функцию. Она используется только для документирования *внешнего API*. Поэтому в функции может быть просто `pass`.\n* *Путь* может содержать [выражение OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (подробнее ниже), где можно использовать переменные с параметрами и части исходного HTTP-запроса, отправленного *вашему API*.\n\n### Выражение пути для обратного вызова { #the-callback-path-expression }\n\n*Путь* обратного вызова может содержать [выражение OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression), которое может включать части исходного запроса, отправленного *вашему API*.\n\nВ нашем случае это `str`:\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\nИтак, если пользователь вашего API (внешний разработчик) отправляет HTTP-запрос вашему API по адресу:\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\nс телом JSON:\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\nто *ваш API* обработает счёт и, в какой-то момент позже, отправит запрос обратного вызова на `callback_url` (*внешний API*):\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\nс телом JSON примерно такого вида:\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\nи будет ожидать от *внешнего API* ответ с телом JSON вида:\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip | Совет\n\nОбратите внимание, что используемый URL обратного вызова содержит URL, полученный как query-параметр в `callback_url` (`https://www.external.org/events`), а также `id` счёта из тела JSON (`2expen51ve`).\n\n///\n\n### Подключите маршрутизатор обратного вызова { #add-the-callback-router }\n\nК этому моменту у вас есть необходимые *операции пути* обратного вызова (те, которые *внешний разработчик* должен реализовать во *внешнем API*) в созданном выше маршрутизаторе обратных вызовов.\n\nТеперь используйте параметр `callbacks` в *декораторе операции пути вашего API*, чтобы передать атрибут `.routes` (это, по сути, просто `list` маршрутов/*операций пути*) из этого маршрутизатора обратных вызовов:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip | Совет\n\nОбратите внимание, что вы передаёте не сам маршрутизатор (`invoices_callback_router`) в `callback=`, а его атрибут `.routes`, то есть `invoices_callback_router.routes`.\n\n///\n\n### Проверьте документацию { #check-the-docs }\n\nТеперь вы можете запустить приложение и перейти по адресу [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВы увидите документацию, включающую раздел «Callbacks» для вашей *операции пути*, который показывает, как должен выглядеть *внешний API*:\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/ru/docs/advanced/openapi-webhooks.md",
    "content": "# Вебхуки OpenAPI { #openapi-webhooks }\n\nБывают случаи, когда вы хотите сообщить пользователям вашего API, что ваше приложение может вызвать их приложение (отправив HTTP-запрос) с некоторыми данными, обычно чтобы уведомить о каком-то событии.\n\nЭто означает, что вместо обычного процесса, когда пользователи отправляют запросы вашему API, ваш API (или ваше приложение) может отправлять запросы в их систему (в их API, их приложение).\n\nОбычно это называется вебхуком.\n\n## Шаги вебхуков { #webhooks-steps }\n\nОбычно процесс таков: вы определяете в своем коде, какое сообщение вы будете отправлять, то есть тело запроса.\n\nВы также определяете, в какие моменты (при каких событиях) ваше приложение будет отправлять эти запросы (события).\n\nА ваши пользователи каким-то образом (например, в веб‑панели) указывают URL-адрес, на который ваше приложение должно отправлять эти запросы.\n\nВся логика регистрации URL-адресов для вебхуков и код, который реально отправляет эти запросы, целиком на вашей стороне. Вы пишете это так, как вам нужно, в своем собственном коде.\n\n## Документирование вебхуков с помощью **FastAPI** и OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }\n\nС **FastAPI**, используя OpenAPI, вы можете определить имена этих вебхуков, типы HTTP-операций, которые ваше приложение может отправлять (например, `POST`, `PUT` и т.д.), а также тела запросов, которые ваше приложение будет отправлять.\n\nЭто значительно упростит вашим пользователям реализацию их API для приема ваших вебхук-запросов; возможно, они даже смогут автоматически сгенерировать часть кода своего API.\n\n/// info | Информация\n\nВебхуки доступны в OpenAPI 3.1.0 и выше, поддерживаются в FastAPI `0.99.0` и новее.\n\n///\n\n## Приложение с вебхуками { #an-app-with-webhooks }\n\nПри создании приложения на **FastAPI** есть атрибут `webhooks`, с помощью которого можно объявлять вебхуки так же, как вы объявляете операции пути (обработчики пути), например с `@app.webhooks.post()`.\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\nОпределенные вами вебхуки попадут в схему **OpenAPI** и в автоматический **интерфейс документации**.\n\n/// info | Информация\n\nОбъект `app.webhooks` на самом деле — это обычный `APIRouter`, тот же тип, который вы используете при структурировании приложения по нескольким файлам.\n\n///\n\nОбратите внимание: в случае с вебхуками вы на самом деле не объявляете путь (например, `/items/`), передаваемый туда текст — это лишь идентификатор вебхука (имя события). Например, в `@app.webhooks.post(\"new-subscription\")` имя вебхука — `new-subscription`.\n\nЭто связано с тем, что предполагается: фактический URL‑путь, по которому они хотят получать запрос вебхука, ваши пользователи укажут каким-то другим образом (например, в веб‑панели).\n\n### Посмотрите документацию { #check-the-docs }\n\nТеперь вы можете запустить приложение и перейти по ссылке [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВы увидите, что в документации есть обычные операции пути, а также появились вебхуки:\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/ru/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# Расширенная конфигурация операций пути { #path-operation-advanced-configuration }\n\n## OpenAPI operationId { #openapi-operationid }\n\n/// warning | Предупреждение\n\nЕсли вы не «эксперт» по OpenAPI, скорее всего, это вам не нужно.\n\n///\n\nВы можете задать OpenAPI `operationId`, который будет использоваться в вашей *операции пути*, с помощью параметра `operation_id`.\n\nНужно убедиться, что он уникален для каждой операции.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### Использование имени *функции-обработчика пути* как operationId { #using-the-path-operation-function-name-as-the-operationid }\n\nЕсли вы хотите использовать имена функций ваших API в качестве `operationId`, вы можете пройти по всем из них и переопределить `operation_id` каждой *операции пути* с помощью их `APIRoute.name`.\n\nДелать это следует после добавления всех *операций пути*.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip | Совет\n\nЕсли вы вызываете `app.openapi()` вручную, обновите `operationId` до этого.\n\n///\n\n/// warning | Предупреждение\n\nЕсли вы делаете это, убедитесь, что каждая из ваших *функций-обработчиков пути* имеет уникальное имя.\n\nДаже если они находятся в разных модулях (файлах Python).\n\n///\n\n## Исключить из OpenAPI { #exclude-from-openapi }\n\nЧтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматических систем документации), используйте параметр `include_in_schema` и установите его в `False`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## Расширенное описание из docstring { #advanced-description-from-docstring }\n\nВы можете ограничить количество строк из docstring *функции-обработчика пути*, используемых для OpenAPI.\n\nДобавление `\\f` (экранированного символа «form feed») заставит **FastAPI** обрезать текст, используемый для OpenAPI, в этой точке.\n\nЭто не отобразится в документации, но другие инструменты (например, Sphinx) смогут использовать остальное.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## Дополнительные ответы { #additional-responses }\n\nВы, вероятно, уже видели, как объявлять `response_model` и `status_code` для *операции пути*.\n\nЭто определяет метаданные об основном HTTP-ответе *операции пути*.\n\nТакже можно объявлять дополнительные ответы с их моделями, статус-кодами и т.д.\n\nВ документации есть целая глава об этом — [Дополнительные ответы в OpenAPI](additional-responses.md).\n\n## Дополнительные данные OpenAPI { #openapi-extra }\n\nКогда вы объявляете *операцию пути* в своём приложении, **FastAPI** автоматически генерирует соответствующие метаданные об этой *операции пути* для включения в схему OpenAPI.\n\n/// note | Технические детали\n\nВ спецификации OpenAPI это называется [Объект операции](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object).\n\n///\n\nОн содержит всю информацию об *операции пути* и используется для генерации автоматической документации.\n\nТам есть `tags`, `parameters`, `requestBody`, `responses` и т.д.\n\nЭта специфичная для *операции пути* схема OpenAPI обычно генерируется автоматически **FastAPI**, но вы также можете её расширить.\n\n/// tip | Совет\n\nЭто низкоуровневая возможность расширения.\n\nЕсли вам нужно лишь объявить дополнительные ответы, удобнее сделать это через [Дополнительные ответы в OpenAPI](additional-responses.md).\n\n///\n\nВы можете расширить схему OpenAPI для *операции пути* с помощью параметра `openapi_extra`.\n\n### Расширения OpenAPI { #openapi-extensions }\n\n`openapi_extra` может пригодиться, например, чтобы объявить [Расширения OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\nЕсли вы откроете автоматическую документацию API, ваше расширение появится внизу страницы конкретной *операции пути*.\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\nИ если вы посмотрите на итоговый OpenAPI (по адресу `/openapi.json` вашего API), вы также увидите своё расширение в составе описания соответствующей *операции пути*:\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### Пользовательская схема OpenAPI для *операции пути* { #custom-openapi-path-operation-schema }\n\nСловарь в `openapi_extra` будет глубоко объединён с автоматически сгенерированной схемой OpenAPI для *операции пути*.\n\nТаким образом, вы можете добавить дополнительные данные к автоматически сгенерированной схеме.\n\nНапример, вы можете решить читать и валидировать HTTP-запрос своим кодом, не используя автоматические возможности FastAPI и Pydantic, но при этом захотите описать HTTP-запрос в схеме OpenAPI.\n\nЭто можно сделать с помощью `openapi_extra`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\nВ этом примере мы не объявляли никакую Pydantic-модель. Фактически тело запроса даже не <dfn title=\"преобразован из простого формата, например байтов, в объекты Python\">распарсено</dfn> как JSON, оно читается напрямую как `bytes`, а функция `magic_data_reader()` будет отвечать за его парсинг каким-то способом.\n\nТем не менее, мы можем объявить ожидаемую схему для тела запроса.\n\n### Пользовательский тип содержимого в OpenAPI { #custom-openapi-content-type }\n\nИспользуя тот же приём, вы можете воспользоваться Pydantic-моделью, чтобы определить JSON Schema, которая затем будет включена в пользовательский раздел схемы OpenAPI для *операции пути*.\n\nИ вы можете сделать это, даже если тип данных в HTTP-запросе — не JSON.\n\nНапример, в этом приложении мы не используем встроенную функциональность FastAPI для извлечения JSON Schema из моделей Pydantic, равно как и автоматическую валидацию JSON. Мы объявляем тип содержимого HTTP-запроса как YAML, а не JSON:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\nТем не менее, хотя мы не используем встроенную функциональность по умолчанию, мы всё равно используем Pydantic-модель, чтобы вручную сгенерировать JSON Schema для данных, которые мы хотим получить в YAML.\n\nЗатем мы работаем с HTTP-запросом напрямую и извлекаем тело как `bytes`. Это означает, что FastAPI даже не попытается распарсить полезную нагрузку HTTP-запроса как JSON.\n\nА затем в нашем коде мы напрямую парсим это содержимое YAML и снова используем ту же Pydantic-модель, чтобы валидировать YAML-содержимое:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip | Совет\n\nЗдесь мы переиспользуем ту же Pydantic-модель.\n\nНо аналогично мы могли бы валидировать данные и каким-то другим способом.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/advanced/response-change-status-code.md",
    "content": "# Response - Изменение статус-кода { #response-change-status-code }\n\nВы, вероятно, уже читали о том, что можно установить [статус-код ответа по умолчанию](../tutorial/response-status-code.md).\n\nНо в некоторых случаях нужно вернуть другой статус-код, отличный от значения по умолчанию.\n\n## Пример использования { #use-case }\n\nНапример, представьте, что вы хотите по умолчанию возвращать HTTP статус-код «OK» `200`.\n\nНо если данные не существовали, вы хотите создать их и вернуть HTTP статус-код «CREATED» `201`.\n\nПри этом вы всё ещё хотите иметь возможность фильтровать и преобразовывать возвращаемые данные с помощью `response_model`.\n\nДля таких случаев вы можете использовать параметр `Response`.\n\n## Использование параметра `Response` { #use-a-response-parameter }\n\nВы можете объявить параметр типа `Response` в вашей *функции обработки пути* (как и для cookies и HTTP-заголовков).\n\nИ затем вы можете установить `status_code` в этом *временном* объекте ответа.\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\nПосле этого вы можете вернуть любой объект, который вам нужен, как обычно (`dict`, модель базы данных и т.д.).\n\nИ если вы объявили `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта.\n\n**FastAPI** будет использовать этот *временный* ответ для извлечения статус-кода (а также cookies и HTTP-заголовков) и поместит их в финальный ответ, который содержит возвращаемое вами значение, отфильтрованное любым `response_model`.\n\nВы также можете объявить параметр `Response` в зависимостях и установить в них статус-код. Но помните, что последнее установленное значение будет иметь приоритет.\n"
  },
  {
    "path": "docs/ru/docs/advanced/response-cookies.md",
    "content": "# Cookies в ответе { #response-cookies }\n\n## Использование параметра `Response` { #use-a-response-parameter }\n\nВы можете объявить параметр типа `Response` в вашей функции-обработчике пути.\n\nЗатем установить cookies в этом временном объекте ответа.\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\nПосле этого можно вернуть любой объект, как и раньше (например, `dict`, объект модели базы данных и так далее).\n\nЕсли вы указали `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта.\n\n**FastAPI** извлечет cookies (а также HTTP-заголовки и статус-код) из временного ответа и включит их в окончательный ответ, содержащий ваше возвращаемое значение, отфильтрованное через `response_model`.\n\nВы также можете объявить параметр типа `Response` в зависимостях и устанавливать cookies (и HTTP-заголовки) там.\n\n## Возвращение `Response` напрямую { #return-a-response-directly }\n\nВы также можете установить Cookies, если возвращаете `Response` напрямую в вашем коде.\n\nДля этого создайте объект `Response`, как описано в разделе [Возвращение ответа напрямую](response-directly.md).\n\nЗатем установите cookies и верните этот объект:\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip | Совет\n\nИмейте в виду, что если вы возвращаете ответ напрямую, вместо использования параметра `Response`, FastAPI вернёт его напрямую.\n\nУбедитесь, что ваши данные имеют корректный тип. Например, они должны быть совместимы с JSON, если вы возвращаете `JSONResponse`.\n\nТакже убедитесь, что вы не отправляете данные, которые должны были быть отфильтрованы через `response_model`.\n\n///\n\n### Дополнительная информация { #more-info }\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette.responses import Response` или `from starlette.responses import JSONResponse`.\n\n**FastAPI** предоставляет `fastapi.responses`, которые являются теми же объектами, что и `starlette.responses`, просто для удобства. Однако большинство доступных типов ответов поступает непосредственно из **Starlette**.\n\nИ так как `Response` часто используется для установки HTTP-заголовков и cookies, **FastAPI** также предоставляет его как `fastapi.Response`.\n\n///\n\nЧтобы увидеть все доступные параметры и настройки, ознакомьтесь с [документацией Starlette](https://www.starlette.dev/responses/#set-cookie).\n"
  },
  {
    "path": "docs/ru/docs/advanced/response-directly.md",
    "content": "# Возврат ответа напрямую { #return-a-response-directly }\n\nКогда вы создаёте **FastAPI** *операцию пути*, вы можете возвращать из неё любые данные: `dict`, `list`, Pydantic-модель, модель базы данных и т.д.\n\nЕсли вы объявите [Модель ответа](../tutorial/response-model.md), FastAPI будет использовать её для сериализации данных в JSON с помощью Pydantic.\n\nЕсли вы не объявите модель ответа, FastAPI использует `jsonable_encoder`, как описано в [JSON кодировщик](../tutorial/encoder.md), и поместит результат в `JSONResponse`.\n\nТакже вы можете создать `JSONResponse` напрямую и вернуть его.\n\n/// tip | Подсказка\n\nОбычно вы получите значительно лучшую производительность, если будете использовать [Модель ответа](../tutorial/response-model.md), а не возвращать `JSONResponse` напрямую, так как в этом случае сериализация данных с помощью Pydantic происходит на стороне Rust.\n\n///\n\n## Возврат `Response` { #return-a-response }\n\nВы можете возвращать `Response` или любой его подкласс.\n\n/// info | Информация\n\n`JSONResponse` сам по себе является подклассом `Response`.\n\n///\n\nИ когда вы возвращаете `Response`, **FastAPI** передаст его напрямую.\n\nЭто не приведет к преобразованию данных с помощью Pydantic-моделей, содержимое не будет преобразовано в какой-либо тип и т.д.\n\nЭто даёт вам большую гибкость. Вы можете возвращать любые типы данных, переопределять любые объявления или валидацию данных и т.д.\n\nЭто также накладывает на вас ответственность. Вам нужно удостовериться, что возвращаемые данные корректны, в правильном формате, что их можно сериализовать и т.д.\n\n## Использование `jsonable_encoder` в `Response` { #using-the-jsonable-encoder-in-a-response }\n\nПоскольку **FastAPI** не изменяет объект `Response`, который вы возвращаете, вы должны убедиться, что его содержимое готово к отправке.\n\nНапример, вы не можете поместить Pydantic-модель в `JSONResponse`, не преобразовав её сначала в `dict` с помощью преобразования всех типов данных (таких как `datetime`, `UUID` и т.д.) в совместимые с JSON типы.\n\nВ таких случаях вы можете использовать `jsonable_encoder` для преобразования данных перед передачей их в ответ:\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette.responses import JSONResponse`.\n\n**FastAPI** предоставляет `starlette.responses` через `fastapi.responses` просто для вашего удобства, как разработчика. Но большинство доступных Response-классов поступают напрямую из Starlette.\n\n///\n\n## Возврат пользовательского `Response` { #returning-a-custom-response }\n\nПример выше показывает все необходимые части, но он пока не очень полезен, так как вы могли бы просто вернуть `item` напрямую, и **FastAPI** поместил бы его в `JSONResponse`, преобразовав в `dict` и т.д. Всё это происходит по умолчанию.\n\nТеперь давайте посмотрим, как можно использовать это для возврата пользовательского ответа.\n\nДопустим, вы хотите вернуть ответ в формате [XML](https://en.wikipedia.org/wiki/XML).\n\nВы можете поместить ваш XML-контент в строку, поместить её в `Response` и вернуть:\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## Как работает модель ответа { #how-a-response-model-works }\n\nКогда вы объявляете [Модель ответа - возвращаемый тип](../tutorial/response-model.md) в операции пути, **FastAPI** будет использовать её для сериализации данных в JSON с помощью Pydantic.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nПоскольку это происходит на стороне Rust, производительность будет значительно выше, чем если бы это выполнялось обычным Python и классом `JSONResponse`.\n\nПри использовании `response_model` или возвращаемого типа FastAPI не будет использовать `jsonable_encoder` для преобразования данных (что было бы медленнее) и не будет использовать класс `JSONResponse`.\n\nВместо этого он берёт JSON-байты, сгенерированные Pydantic с использованием модели ответа (или возвращаемого типа), и возвращает `Response` с правильным типом содержимого для JSON (`application/json`) напрямую.\n\n## Примечания { #notes }\n\nКогда вы возвращаете объект `Response` напрямую, его данные не валидируются, не преобразуются (не сериализуются) и не документируются автоматически.\n\nНо вы всё равно можете задокументировать это, как описано в [Дополнительные ответы в OpenAPI](additional-responses.md).\n\nВ следующих разделах вы увидите, как использовать/объявлять такие кастомные `Response`, при этом сохраняя автоматическое преобразование данных, документацию и т.д.\n"
  },
  {
    "path": "docs/ru/docs/advanced/response-headers.md",
    "content": "# HTTP-заголовки ответа { #response-headers }\n\n## Использовать параметр `Response` { #use-a-response-parameter }\n\nВы можете объявить параметр типа `Response` в вашей функции-обработчике пути (как можно сделать и для cookie).\n\nА затем вы можете устанавливать HTTP-заголовки в этом *временном* объекте ответа.\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\nПосле этого вы можете вернуть любой нужный объект, как обычно (например, `dict`, модель из базы данных и т.д.).\n\nИ, если вы объявили `response_model`, он всё равно будет использован для фильтрации и преобразования возвращённого объекта.\n\n**FastAPI** использует этот *временный* ответ, чтобы извлечь HTTP-заголовки (а также cookie и статус-код) и поместит их в финальный HTTP-ответ, который содержит возвращённое вами значение, отфильтрованное согласно `response_model`.\n\nВы также можете объявлять параметр `Response` в зависимостях и устанавливать в них заголовки (и cookie).\n\n## Вернуть `Response` напрямую { #return-a-response-directly }\n\nВы также можете добавить HTTP-заголовки, когда возвращаете `Response` напрямую.\n\nСоздайте ответ, как описано в [Вернуть Response напрямую](response-directly.md), и передайте заголовки как дополнительный параметр:\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette.responses import Response` или `from starlette.responses import JSONResponse`.\n\n**FastAPI** предоставляет те же самые `starlette.responses` как `fastapi.responses` — для вашего удобства как разработчика. Но большинство доступных классов ответов поступают напрямую из Starlette.\n\nИ поскольку `Response` часто используется для установки заголовков и cookie, **FastAPI** также предоставляет его как `fastapi.Response`.\n\n///\n\n## Пользовательские HTTP-заголовки { #custom-headers }\n\nПомните, что собственные проприетарные заголовки можно добавлять, [используя префикс `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nНо если у вас есть пользовательские заголовки, которые вы хотите показывать клиенту в браузере, вам нужно добавить их в настройки CORS (подробнее см. в [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), используя параметр `expose_headers`, описанный в [документации Starlette по CORS](https://www.starlette.dev/middleware/#corsmiddleware).\n"
  },
  {
    "path": "docs/ru/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP Basic Auth { #http-basic-auth }\n\nДля самых простых случаев можно использовать HTTP Basic Auth.\n\nПри HTTP Basic Auth приложение ожидает HTTP-заголовок, который содержит имя пользователя и пароль.\n\nЕсли его нет, возвращается ошибка HTTP 401 «Unauthorized».\n\nТакже возвращается заголовок `WWW-Authenticate` со значением `Basic` и необязательным параметром `realm`.\n\nЭто говорит браузеру показать встроенное окно запроса имени пользователя и пароля.\n\nЗатем, когда вы вводите эти данные, браузер автоматически отправляет их в заголовке.\n\n## Простой HTTP Basic Auth { #simple-http-basic-auth }\n\n* Импортируйте `HTTPBasic` и `HTTPBasicCredentials`.\n* Создайте «схему» `security` с помощью `HTTPBasic`.\n* Используйте эту `security` как зависимость в вашей *операции пути*.\n* Она возвращает объект типа `HTTPBasicCredentials`:\n    * Он содержит отправленные `username` и `password`.\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\nКогда вы впервые откроете URL (или нажмёте кнопку «Execute» в документации), браузер попросит ввести имя пользователя и пароль:\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## Проверка имени пользователя { #check-the-username }\n\nВот более полный пример.\n\nИспользуйте зависимость, чтобы проверить, корректны ли имя пользователя и пароль.\n\nДля этого используйте стандартный модуль Python [`secrets`](https://docs.python.org/3/library/secrets.html) для проверки имени пользователя и пароля.\n\n`secrets.compare_digest()` должен получать `bytes` или `str`, который содержит только символы ASCII (английские символы). Это значит, что он не будет работать с символами вроде `á`, как в `Sebastián`.\n\nЧтобы это обработать, сначала преобразуем `username` и `password` в `bytes`, закодировав их в UTF-8.\n\nЗатем можно использовать `secrets.compare_digest()`, чтобы убедиться, что `credentials.username` равен `\"stanleyjobson\"`, а `credentials.password` — `\"swordfish\"`.\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\nЭто было бы похоже на:\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # Вернуть ошибку\n    ...\n```\n\nНо используя `secrets.compare_digest()`, вы защитите код от атак типа «тайминговая атака» (атака по времени).\n\n### Тайминговые атаки { #timing-attacks }\n\nЧто такое «тайминговая атака»?\n\nПредставим, что злоумышленники пытаются угадать имя пользователя и пароль.\n\nИ они отправляют запрос с именем пользователя `johndoe` и паролем `love123`.\n\nТогда Python-код в вашем приложении будет эквивалентен чему-то вроде:\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nНо в момент, когда Python сравнит первую `j` в `johndoe` с первой `s` в `stanleyjobson`, он вернёт `False`, потому что уже ясно, что строки не совпадают, решив, что «нет смысла тратить ресурсы на сравнение остальных букв». И ваше приложение ответит «Неверное имя пользователя или пароль».\n\nЗатем злоумышленники попробуют имя пользователя `stanleyjobsox` и пароль `love123`.\n\nИ ваш код сделает что-то вроде:\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nPythonу придётся сравнить весь общий префикс `stanleyjobso` в `stanleyjobsox` и `stanleyjobson`, прежде чем понять, что строки отличаются. Поэтому на ответ «Неверное имя пользователя или пароль» уйдёт на несколько микросекунд больше.\n\n#### Время ответа помогает злоумышленникам { #the-time-to-answer-helps-the-attackers }\n\nЗамечая, что сервер прислал «Неверное имя пользователя или пароль» на несколько микросекунд позже, злоумышленники поймут, что какая-то часть была угадана — начальные буквы верны.\n\nТогда они могут попробовать снова, зная, что правильнее что-то ближе к `stanleyjobsox`, чем к `johndoe`.\n\n#### «Профессиональная» атака { #a-professional-attack }\n\nКонечно, злоумышленники не будут делать всё это вручную — они напишут программу, возможно, с тысячами или миллионами попыток в секунду. И будут подбирать по одной дополнительной верной букве за раз.\n\nТак за минуты или часы они смогут угадать правильные имя пользователя и пароль — с «помощью» нашего приложения — используя лишь время, затраченное на ответ.\n\n#### Исправление с помощью `secrets.compare_digest()` { #fix-it-with-secrets-compare-digest }\n\nНо в нашем коде мы используем `secrets.compare_digest()`.\n\nВкратце: сравнение `stanleyjobsox` с `stanleyjobson` займёт столько же времени, сколько и сравнение `johndoe` с `stanleyjobson`. То же относится и к паролю.\n\nТаким образом, используя `secrets.compare_digest()` в коде приложения, вы защитите его от всего этого класса атак на безопасность.\n\n### Возврат ошибки { #return-the-error }\n\nПосле того как обнаружено, что учётные данные некорректны, верните `HTTPException` со статус-кодом ответа 401 (тем же, что и при отсутствии учётных данных) и добавьте HTTP-заголовок `WWW-Authenticate`, чтобы браузер снова показал окно входа:\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/ru/docs/advanced/security/index.md",
    "content": "# Расширенная безопасность { #advanced-security }\n\n## Дополнительные возможности { #additional-features }\n\nЕсть дополнительные возможности для работы с безопасностью помимо тех, что описаны в [Учебник — Руководство пользователя: Безопасность](../../tutorial/security/index.md).\n\n/// tip | Совет\n\nСледующие разделы не обязательно являются «продвинутыми».\n\nИ возможно, что решение для вашего варианта использования находится в одном из них.\n\n///\n\n## Сначала прочитайте руководство { #read-the-tutorial-first }\n\nВ следующих разделах предполагается, что вы уже прочитали основной [Учебник — Руководство пользователя: Безопасность](../../tutorial/security/index.md).\n\nВсе они основаны на тех же концепциях, но предоставляют дополнительные возможности.\n"
  },
  {
    "path": "docs/ru/docs/advanced/security/oauth2-scopes.md",
    "content": "# OAuth2 scopes { #oauth2-scopes }\n\nВы можете использовать OAuth2 scopes напрямую с **FastAPI** — они интегрированы и работают бесшовно.\n\nЭто позволит вам иметь более детальную систему разрешений по стандарту OAuth2, интегрированную в ваше OpenAPI‑приложение (и документацию API).\n\nOAuth2 со scopes — это механизм, который используют многие крупные провайдеры аутентификации: Facebook, Google, GitHub, Microsoft, X (Twitter) и т.д. Они применяют его, чтобы предоставлять конкретные разрешения пользователям и приложениям.\n\nКаждый раз, когда вы «входите через» Facebook, Google, GitHub, Microsoft, X (Twitter), это приложение использует OAuth2 со scopes.\n\nВ этом разделе вы увидите, как управлять аутентификацией и авторизацией с теми же OAuth2 scopes в вашем приложении на **FastAPI**.\n\n/// warning | Предупреждение\n\nЭто более-менее продвинутый раздел. Если вы только начинаете, можете пропустить его.\n\nВам не обязательно нужны OAuth2 scopes — аутентификацию и авторизацию можно реализовать любым нужным вам способом.\n\nНо OAuth2 со scopes можно красиво интегрировать в ваш API (через OpenAPI) и документацию API.\n\nТак или иначе, вы все равно будете применять эти scopes или какие-то другие требования безопасности/авторизации, как вам нужно, в вашем коде.\n\nВо многих случаях OAuth2 со scopes может быть избыточным.\n\nНо если вы знаете, что это нужно, или вам просто интересно — продолжайте чтение.\n\n///\n\n## OAuth2 scopes и OpenAPI { #oauth2-scopes-and-openapi }\n\nСпецификация OAuth2 определяет «scopes» как список строк, разделённых пробелами.\n\nСодержимое каждой такой строки может иметь любой формат, но не должно содержать пробелов.\n\nЭти scopes представляют «разрешения».\n\nВ OpenAPI (например, в документации API) можно определить «схемы безопасности» (security schemes).\n\nКогда одна из таких схем безопасности использует OAuth2, вы также можете объявлять и использовать scopes.\n\nКаждый «scope» — это просто строка (без пробелов).\n\nОбычно они используются для объявления конкретных разрешений безопасности, например:\n\n- `users:read` или `users:write` — распространённые примеры.\n- `instagram_basic` используется Facebook / Instagram.\n- `https://www.googleapis.com/auth/drive` используется Google.\n\n/// info | Информация\n\nВ OAuth2 «scope» — это просто строка, объявляющая требуемое конкретное разрешение.\n\nНеважно, есть ли там другие символы, такие как `:`, или это URL.\n\nЭти детали зависят от реализации.\n\nДля OAuth2 это просто строки.\n\n///\n\n## Взгляд издалека { #global-view }\n\nСначала быстро посмотрим, что изменилось по сравнению с примерами из основного раздела **Учебник - Руководство пользователя** — [OAuth2 с паролем (и хешированием), Bearer с JWT-токенами](../../tutorial/security/oauth2-jwt.md). Теперь — с использованием OAuth2 scopes:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\nТеперь рассмотрим эти изменения шаг за шагом.\n\n## OAuth2 схема безопасности { #oauth2-security-scheme }\n\nПервое изменение — мы объявляем схему безопасности OAuth2 с двумя доступными scopes: `me` и `items`.\n\nПараметр `scopes` получает `dict`, где каждый scope — это ключ, а описание — значение:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\nТак как теперь мы объявляем эти scopes, они появятся в документации API при входе/авторизации.\n\nИ вы сможете выбрать, какие scopes вы хотите выдать доступ: `me` и `items`.\n\nЭто тот же механизм, когда вы даёте разрешения при входе через Facebook, Google, GitHub и т.д.:\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## JWT-токены со scopes { #jwt-token-with-scopes }\n\nТеперь измените операцию пути, выдающую токен, чтобы возвращать запрошенные scopes.\n\nМы всё ещё используем тот же `OAuth2PasswordRequestForm`. Он включает свойство `scopes` с `list` из `str` — каждый scope, полученный в запросе.\n\nИ мы возвращаем scopes как часть JWT‑токена.\n\n/// danger | Опасность\n\nДля простоты здесь мы просто добавляем полученные scopes прямо в токен.\n\nНо в вашем приложении, в целях безопасности, следует убедиться, что вы добавляете только те scopes, которые пользователь действительно может иметь, или те, которые вы заранее определили.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## Объявление scopes в *обработчиках путей* и зависимостях { #declare-scopes-in-path-operations-and-dependencies }\n\nТеперь объявим, что операция пути для `/users/me/items/` требует scope `items`.\n\nДля этого импортируем и используем `Security` из `fastapi`.\n\nВы можете использовать `Security` для объявления зависимостей (как `Depends`), но `Security` также принимает параметр `scopes` со списком scopes (строк).\n\nВ этом случае мы передаём функцию‑зависимость `get_current_active_user` в `Security` (точно так же, как сделали бы с `Depends`).\n\nНо мы также передаём `list` scopes — в данном случае только один scope: `items` (их могло быть больше).\n\nИ функция‑зависимость `get_current_active_user` тоже может объявлять подзависимости не только через `Depends`, но и через `Security`, объявляя свою подзависимость (`get_current_user`) и дополнительные требования по scopes.\n\nВ данном случае требуется scope `me` (их также могло быть больше одного).\n\n/// note | Примечание\n\nВам не обязательно добавлять разные scopes в разных местах.\n\nМы делаем это здесь, чтобы показать, как **FastAPI** обрабатывает scopes, объявленные на разных уровнях.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | Технические детали\n\n`Security` на самом деле является подклассом `Depends` и имеет всего один дополнительный параметр, который мы рассмотрим позже.\n\nНо используя `Security` вместо `Depends`, **FastAPI** будет знать, что можно объявлять security scopes, использовать их внутри и документировать API в OpenAPI.\n\nОднако когда вы импортируете `Query`, `Path`, `Depends`, `Security` и другие из `fastapi`, это на самом деле функции, возвращающие специальные классы.\n\n///\n\n## Использование `SecurityScopes` { #use-securityscopes }\n\nТеперь обновим зависимость `get_current_user`.\n\nИменно её используют зависимости выше.\n\nЗдесь мы используем ту же схему OAuth2, созданную ранее, объявляя её как зависимость: `oauth2_scheme`.\n\nПоскольку у этой функции‑зависимости нет собственных требований по scopes, мы можем использовать `Depends` с `oauth2_scheme` — нам не нужно использовать `Security`, если не требуется указывать security scopes.\n\nМы также объявляем специальный параметр типа `SecurityScopes`, импортированный из `fastapi.security`.\n\nКласс `SecurityScopes` похож на `Request` (через `Request` мы получали сам объект запроса).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## Использование `scopes` { #use-the-scopes }\n\nПараметр `security_scopes` будет типа `SecurityScopes`.\n\nУ него есть свойство `scopes` со списком, содержащим все scopes, требуемые им самим и всеми зависимостями, использующими его как подзависимость. То есть всеми «зависящими»… это может звучать запутанно, ниже есть дополнительное объяснение.\n\nОбъект `security_scopes` (класс `SecurityScopes`) также предоставляет атрибут `scope_str` — это одна строка с этими scopes, разделёнными пробелами (мы будем её использовать).\n\nМы создаём `HTTPException`, который можем переиспользовать (`raise`) в нескольких местах.\n\nВ этом исключении мы включаем требуемые scopes (если есть) в виде строки, разделённой пробелами (используя `scope_str`). Эту строку со scopes мы помещаем в HTTP‑заголовок `WWW-Authenticate` (это часть спецификации).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## Проверка `username` и формата данных { #verify-the-username-and-data-shape }\n\nМы проверяем, что получили `username`, и извлекаем scopes.\n\nЗатем валидируем эти данные с помощью Pydantic‑модели (перехватывая исключение `ValidationError`), и если возникает ошибка при чтении JWT‑токена или при валидации данных с Pydantic, мы вызываем `HTTPException`, созданное ранее.\n\nДля этого мы обновляем Pydantic‑модель `TokenData`, добавляя новое свойство `scopes`.\n\nВалидируя данные с помощью Pydantic, мы можем удостовериться, что у нас, например, именно `list` из `str` со scopes и `str` с `username`.\n\nА не, скажем, `dict` или что‑то ещё — ведь это могло бы где‑то позже сломать приложение и создать риск для безопасности.\n\nМы также проверяем, что существует пользователь с таким именем, и если нет — вызываем то же исключение, созданное ранее.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## Проверка `scopes` { #verify-the-scopes }\n\nТеперь проверяем, что все требуемые scopes — этой зависимостью и всеми зависящими (включая операции пути) — присутствуют среди scopes, предоставленных в полученном токене, иначе вызываем `HTTPException`.\n\nДля этого используем `security_scopes.scopes`, содержащий `list` со всеми этими scopes как `str`.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## Дерево зависимостей и scopes { #dependency-tree-and-scopes }\n\nЕщё раз рассмотрим дерево зависимостей и scopes.\n\nТак как у зависимости `get_current_active_user` есть подзависимость `get_current_user`, scope `\"me\"`, объявленный в `get_current_active_user`, будет включён в список требуемых scopes в `security_scopes.scopes`, передаваемый в `get_current_user`.\n\nСама операция пути тоже объявляет scope — `\"items\"`, поэтому он также будет в списке `security_scopes.scopes`, передаваемом в `get_current_user`.\n\nИерархия зависимостей и scopes выглядит так:\n\n- Операция пути `read_own_items`:\n  - Запрашивает scopes `[\"items\"]` с зависимостью:\n  - `get_current_active_user`:\n    - Функция‑зависимость `get_current_active_user`:\n      - Запрашивает scopes `[\"me\"]` с зависимостью:\n      - `get_current_user`:\n        - Функция‑зависимость `get_current_user`:\n          - Собственных scopes не запрашивает.\n          - Имеет зависимость, использующую `oauth2_scheme`.\n          - Имеет параметр `security_scopes` типа `SecurityScopes`:\n            - Этот параметр `security_scopes` имеет свойство `scopes` с `list`, содержащим все объявленные выше scopes, то есть:\n              - `security_scopes.scopes` будет содержать `[\"me\", \"items\"]` для операции пути `read_own_items`.\n              - `security_scopes.scopes` будет содержать `[\"me\"]` для операции пути `read_users_me`, потому что он объявлен в зависимости `get_current_active_user`.\n              - `security_scopes.scopes` будет содержать `[]` (ничего) для операции пути `read_system_status`, потому что там не объявлялся `Security` со `scopes`, и его зависимость `get_current_user` тоже не объявляет `scopes`.\n\n/// tip | Совет\n\nВажный и «магический» момент здесь в том, что `get_current_user` будет иметь разный список `scopes` для проверки для каждой операции пути.\n\nВсё это зависит от `scopes`, объявленных в каждой операции пути и в каждой зависимости в дереве зависимостей конкретной операции пути.\n\n///\n\n## Больше деталей о `SecurityScopes` { #more-details-about-securityscopes }\n\nВы можете использовать `SecurityScopes` в любой точке и в нескольких местах — необязательно в «корневой» зависимости.\n\nОн всегда будет содержать security scopes, объявленные в текущих зависимостях `Security`, и всеми зависящими — для этой конкретной операции пути и этого конкретного дерева зависимостей.\n\nПоскольку `SecurityScopes` будет содержать все scopes, объявленные зависящими, вы можете использовать его, чтобы централизованно проверять наличие требуемых scopes в токене в одной функции‑зависимости, а затем объявлять разные требования по scopes в разных операциях пути.\n\nОни будут проверяться независимо для каждой операции пути.\n\n## Проверим это { #check-it }\n\nОткройте документацию API — вы сможете аутентифицироваться и указать, какие scopes вы хотите авторизовать.\n\n<img src=\"/img/tutorial/security/image11.png\">\n\nЕсли вы не выберете ни один scope, вы будете «аутентифицированы», но при попытке доступа к `/users/me/` или `/users/me/items/` получите ошибку о недостаточных разрешениях. При этом доступ к `/status/` будет возможен.\n\nЕсли вы выберете scope `me`, но не `items`, вы сможете получить доступ к `/users/me/`, но не к `/users/me/items/`.\n\nТак и будет происходить со сторонним приложением, которое попытается обратиться к одной из этих операций пути с токеном, предоставленным пользователем, — в зависимости от того, сколько разрешений пользователь дал приложению.\n\n## О сторонних интеграциях { #about-third-party-integrations }\n\nВ этом примере мы используем OAuth2 «password flow» (аутентификация по паролю).\n\nЭто уместно, когда мы входим в наше собственное приложение, вероятно, с нашим собственным фронтендом.\n\nМы можем ему доверять при получении `username` и `password`, потому что он под нашим контролем.\n\nНо если вы создаёте OAuth2‑приложение, к которому будут подключаться другие (т.е. вы строите провайдера аутентификации наподобие Facebook, Google, GitHub и т.п.), вам следует использовать один из других «flows».\n\nСамый распространённый — «implicit flow».\n\nСамый безопасный — «code flow», но он сложнее в реализации, так как требует больше шагов. Из‑за сложности многие провайдеры в итоге рекомендуют «implicit flow».\n\n/// note | Примечание\n\nЧасто каждый провайдер аутентификации называет свои «flows» по‑разному — как часть бренда.\n\nНо в итоге они реализуют один и тот же стандарт OAuth2.\n\n///\n\n**FastAPI** включает утилиты для всех этих OAuth2‑flows в `fastapi.security.oauth2`.\n\n## `Security` в параметре `dependencies` декоратора { #security-in-decorator-dependencies }\n\nТочно так же, как вы можете определить `list` из `Depends` в параметре `dependencies` декоратора (см. [Зависимости в декораторах операции пути](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)), вы можете использовать там и `Security` со `scopes`.\n"
  },
  {
    "path": "docs/ru/docs/advanced/settings.md",
    "content": "# Настройки и переменные окружения { #settings-and-environment-variables }\n\nВо многих случаях вашему приложению могут понадобиться внешние настройки или конфигурации, например секретные ключи, учетные данные для базы данных, учетные данные для email‑сервисов и т.д.\n\nБольшинство таких настроек являются изменяемыми (могут меняться), например URL базы данных. И многие из них могут быть «чувствительными», например секреты.\n\nПо этой причине обычно их передают через переменные окружения, которые считываются приложением.\n\n/// tip | Совет\n\nЧтобы понять, что такое переменные окружения, вы можете прочитать [Переменные окружения](../environment-variables.md).\n\n///\n\n## Типы и валидация { #types-and-validation }\n\nПеременные окружения могут содержать только текстовые строки, так как они внешние по отношению к Python и должны быть совместимы с другими программами и остальной системой (и даже с разными операционными системами, такими как Linux, Windows, macOS).\n\nЭто означает, что любое значение, прочитанное в Python из переменной окружения, будет `str`, а любые преобразования к другим типам или любая валидация должны выполняться в коде.\n\n## Pydantic `Settings` { #pydantic-settings }\n\nК счастью, Pydantic предоставляет отличную утилиту для работы с этими настройками, поступающими из переменных окружения, — [Pydantic: управление настройками](https://docs.pydantic.dev/latest/concepts/pydantic_settings/).\n\n### Установка `pydantic-settings` { #install-pydantic-settings }\n\nСначала убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md), активировали его, а затем установили пакет `pydantic-settings`:\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\nОн также включен при установке набора `all` с:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### Создание объекта `Settings` { #create-the-settings-object }\n\nИмпортируйте `BaseSettings` из Pydantic и создайте подкласс, очень похожий на Pydantic‑модель.\n\nАналогично Pydantic‑моделям, вы объявляете атрибуты класса с аннотациями типов и, при необходимости, значениями по умолчанию.\n\nВы можете использовать все те же возможности валидации и инструменты, что и для Pydantic‑моделей, например разные типы данных и дополнительную валидацию через `Field()`.\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip | Совет\n\nЕсли вам нужно что-то быстро скопировать и вставить, не используйте этот пример — воспользуйтесь последним ниже.\n\n///\n\nЗатем, когда вы создаете экземпляр этого класса `Settings` (в нашем случае объект `settings`), Pydantic прочитает переменные окружения регистронезависимо, то есть переменная в верхнем регистре `APP_NAME` будет прочитана для атрибута `app_name`.\n\nДалее он преобразует и провалидирует данные. Поэтому при использовании объекта `settings` вы получите данные тех типов, которые объявили (например, `items_per_user` будет `int`).\n\n### Использование `settings` { #use-the-settings }\n\nЗатем вы можете использовать новый объект `settings` в вашем приложении:\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### Запуск сервера { #run-the-server }\n\nДалее вы можете запустить сервер, передав конфигурации через переменные окружения. Например, можно задать `ADMIN_EMAIL` и `APP_NAME` так:\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip | Совет\n\nЧтобы задать несколько переменных окружения для одной команды, просто разделяйте их пробелами и укажите все перед командой.\n\n///\n\nТогда параметр `admin_email` будет установлен в `\"deadpool@example.com\"`.\n\n`app_name` будет `\"ChimichangApp\"`.\n\nА `items_per_user` сохранит значение по умолчанию `50`.\n\n## Настройки в другом модуле { #settings-in-another-module }\n\nВы можете вынести эти настройки в другой модуль, как показано в разделе [Большие приложения — несколько файлов](../tutorial/bigger-applications.md).\n\nНапример, у вас может быть файл `config.py` со следующим содержимым:\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\nА затем использовать его в файле `main.py`:\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip | Совет\n\nВам также понадобится файл `__init__.py`, как в разделе [Большие приложения — несколько файлов](../tutorial/bigger-applications.md).\n\n///\n\n## Настройки как зависимость { #settings-in-a-dependency }\n\nИногда может быть полезно предоставлять настройки через зависимость, вместо глобального объекта `settings`, используемого повсюду.\n\nЭто особенно удобно при тестировании, так как очень легко переопределить зависимость своими настройками.\n\n### Файл конфигурации { #the-config-file }\n\nПродолжая предыдущий пример, ваш файл `config.py` может выглядеть так:\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\nОбратите внимание, что теперь мы не создаем экземпляр по умолчанию `settings = Settings()`.\n\n### Основной файл приложения { #the-main-app-file }\n\nТеперь мы создаем зависимость, которая возвращает новый `config.Settings()`.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip | Совет\n\nСкоро мы обсудим `@lru_cache`.\n\nПока можно считать, что `get_settings()` — это обычная функция.\n\n///\n\nЗатем мы можем запросить ее в *функции-обработчике пути* как зависимость и использовать там, где нужно.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### Настройки и тестирование { #settings-and-testing }\n\nДалее будет очень просто предоставить другой объект настроек во время тестирования, создав переопределение зависимости для `get_settings`:\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\nВ переопределении зависимости мы задаем новое значение `admin_email` при создании нового объекта `Settings`, а затем возвращаем этот новый объект.\n\nПосле этого можно протестировать, что он используется.\n\n## Чтение файла `.env` { #reading-a-env-file }\n\nЕсли у вас много настроек, которые могут часто меняться, возможно в разных окружениях, может быть удобно поместить их в файл и читать оттуда как переменные окружения.\n\nЭта практика достаточно распространена и имеет название: такие переменные окружения обычно размещают в файле `.env`, а сам файл называют «dotenv».\n\n/// tip | Совет\n\nФайл, начинающийся с точки (`.`), является скрытым в системах, подобных Unix, таких как Linux и macOS.\n\nНо файл dotenv не обязательно должен иметь именно такое имя.\n\n///\n\nPydantic поддерживает чтение таких файлов с помощью внешней библиотеки. Подробнее вы можете прочитать здесь: [Pydantic Settings: поддержка Dotenv (.env)](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support).\n\n/// tip | Совет\n\nЧтобы это работало, вам нужно `pip install python-dotenv`.\n\n///\n\n### Файл `.env` { #the-env-file }\n\nУ вас может быть файл `.env` со следующим содержимым:\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### Чтение настроек из `.env` { #read-settings-from-env }\n\nЗатем обновите ваш `config.py` так:\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip | Совет\n\nАтрибут `model_config` используется только для конфигурации Pydantic. Подробнее см. [Pydantic: Concepts: Configuration](https://docs.pydantic.dev/latest/concepts/config/).\n\n///\n\nЗдесь мы задаем параметр конфигурации `env_file` внутри вашего класса Pydantic `Settings` и устанавливаем значение равным имени файла dotenv, который хотим использовать.\n\n### Создание `Settings` только один раз с помощью `lru_cache` { #creating-the-settings-only-once-with-lru-cache }\n\nЧтение файла с диска обычно затратная (медленная) операция, поэтому, вероятно, вы захотите сделать это один раз и затем переиспользовать один и тот же объект настроек, а не читать файл при каждом запросе.\n\nНо каждый раз, когда мы делаем:\n\n```Python\nSettings()\n```\n\nсоздается новый объект `Settings`, и при создании он снова считывает файл `.env`.\n\nЕсли бы функция зависимости была такой:\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\nмы бы создавали этот объект для каждого запроса и читали файл `.env` на каждый запрос. ⚠️\n\nНо так как мы используем декоратор `@lru_cache` сверху, объект `Settings` будет создан только один раз — при первом вызове. ✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\nЗатем при любых последующих вызовах `get_settings()` в зависимостях для следующих запросов, вместо выполнения внутреннего кода `get_settings()` и создания нового объекта `Settings`, будет возвращаться тот же объект, что был возвращен при первом вызове, снова и снова.\n\n#### Технические детали `lru_cache` { #lru-cache-technical-details }\n\n`@lru_cache` модифицирует декорируемую функцию так, что она возвращает то же значение, что и в первый раз, вместо повторного вычисления, то есть вместо выполнения кода функции каждый раз.\n\nТаким образом, функция под декоратором будет выполнена один раз для каждой комбинации аргументов. Затем значения, возвращенные для каждой из этих комбинаций, будут использоваться снова и снова при вызове функции с точно такой же комбинацией аргументов.\n\nНапример, если у вас есть функция:\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\nваша программа может выполняться так:\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Execute function\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n```\n\nВ случае нашей зависимости `get_settings()` функция вообще не принимает аргументов, поэтому она всегда возвращает одно и то же значение.\n\nТаким образом, она ведет себя почти как глобальная переменная. Но так как используется функция‑зависимость, мы можем легко переопределить ее для тестирования.\n\n`@lru_cache` — часть `functools`, что входит в стандартную библиотеку Python. Подробнее можно прочитать в [документации Python по `@lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache).\n\n## Итоги { #recap }\n\nВы можете использовать Pydantic Settings для управления настройками и конфигурациями вашего приложения с полной мощью Pydantic‑моделей.\n\n* Используя зависимость, вы упрощаете тестирование.\n* Можно использовать файлы `.env`.\n* `@lru_cache` позволяет не читать файл dotenv снова и снова для каждого запроса, при этом давая возможность переопределять его во время тестирования.\n"
  },
  {
    "path": "docs/ru/docs/advanced/stream-data.md",
    "content": "# Потоковая передача данных { #stream-data }\n\nЕсли вам нужно передавать потоковые данные, которые можно представить как JSON, воспользуйтесь [стримингом JSON Lines](../tutorial/stream-json-lines.md).\n\nНо если вы хотите передавать в потоке чистые бинарные данные или строки, ниже показано, как это сделать.\n\n/// info | Информация\n\nДобавлено в FastAPI 0.134.0.\n\n///\n\n## Варианты использования { #use-cases }\n\nЭто можно использовать, если вы хотите стримить чистые строки, например, напрямую из вывода сервиса **AI LLM**.\n\nТакже вы можете стримить **большие бинарные файлы**, передавая каждый чанк данных по мере чтения, без необходимости загружать всё в память сразу.\n\nАналогично можно стримить **видео** или **аудио** — данные могут даже генерироваться по мере обработки и отправки.\n\n## «`StreamingResponse` с `yield`» { #a-streamingresponse-with-yield }\n\nЕсли вы укажете `response_class=StreamingResponse` в своей *функции-обработчике пути*, вы можете использовать `yield`, чтобы по очереди отправлять каждый чанк данных.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI будет передавать каждый чанк данных в `StreamingResponse` как есть, не пытаясь конвертировать его в JSON или что-то подобное.\n\n### Не-async *функции-обработчики пути* { #non-async-path-operation-functions }\n\nМожно использовать и обычные функции `def` (без `async`) и точно так же применять `yield`.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### Без аннотации { #no-annotation }\n\nДля потоковой передачи бинарных данных вам не нужно указывать аннотацию типа возвращаемого значения.\n\nПоскольку FastAPI не будет пытаться конвертировать данные в JSON с помощью Pydantic или сериализовать их каким-либо образом, в данном случае аннотация типа нужна только для вашего редактора кода и инструментов, FastAPI её использовать не будет.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\nЭто также означает, что с `StreamingResponse` у вас есть и свобода, и ответственность — производить и кодировать байты данных ровно в том виде, в котором они должны быть отправлены, независимо от аннотаций типов. 🤓\n\n### Потоковая передача байтов { #stream-bytes }\n\nОдин из основных сценариев — стримить `bytes` вместо строк, и, конечно, это можно сделать.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## Пользовательский `PNGStreamingResponse` { #a-custom-pngstreamingresponse }\n\nВ примерах выше байты данных передавались потоком, но в ответе не было HTTP-заголовка `Content-Type`, поэтому клиент не знал, какой тип данных он получает.\n\nВы можете создать пользовательский подкласс `StreamingResponse`, который устанавливает HTTP-заголовок `Content-Type` в тип данных, которые вы стримите.\n\nНапример, вы можете создать `PNGStreamingResponse`, который устанавливает HTTP-заголовок `Content-Type` в `image/png` с помощью атрибута `media_type`:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\nЗатем вы можете использовать этот новый класс в `response_class=PNGStreamingResponse` в своей *функции-обработчике пути*:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### Симулировать файл { #simulate-a-file }\n\nВ этом примере мы симулируем файл с помощью `io.BytesIO` — это «файлоподобный» объект, который существует только в памяти, но позволяет использовать тот же интерфейс.\n\nНапример, мы можем итерироваться по нему, чтобы потреблять его содержимое, как и по обычному файлу.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | Технические детали\n\nДве другие переменные, `image_base64` и `binary_image`, — это изображение, закодированное в Base64, а затем преобразованное в байты, после чего переданное в `io.BytesIO`.\n\nТолько для того, чтобы всё помещалось в одном файле для этого примера, и вы могли скопировать код и запустить его как есть. 🥚\n\n///\n\nИспользуя блок `with`, мы гарантируем, что объект, ведущий себя как файл, будет закрыт после завершения работы функции‑генератора (функции с `yield`). То есть после того, как она закончит отправку ответа.\n\nВ этом конкретном примере это не столь важно, потому что это «фейковый» файл в памяти (`io.BytesIO`), но для реального файла важно удостовериться, что файл закрыт после завершения работы с ним.\n\n### Файлы и async { #files-and-async }\n\nВ большинстве случаев «файлоподобные» объекты по умолчанию не совместимы с async и await.\n\nНапример, у них нет `await file.read()` или `async for chunk in file`.\n\nИ во многих случаях чтение таких объектов будет блокирующей операцией (которая может заблокировать цикл событий), потому что данные читаются с диска или из сети.\n\n/// info | Информация\n\nПриведённый выше пример — исключение, потому что объект `io.BytesIO` уже находится в памяти, поэтому чтение ничего не блокирует.\n\nНо во многих случаях чтение файла или «файлоподобного» объекта будет блокировать.\n\n///\n\nЧтобы не блокировать цикл событий, вы можете просто объявить *функцию-обработчик пути* обычной `def` вместо `async def`. Тогда FastAPI выполнит её в воркере из пула потоков (threadpool), чтобы не блокировать основной цикл.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip | Совет\n\nЕсли вам нужно вызвать блокирующий код изнутри async-функции, или async-функцию изнутри блокирующей функции, вы можете использовать [Asyncer](https://asyncer.tiangolo.com), родственную библиотеку к FastAPI.\n\n///\n\n### `yield from` { #yield-from }\n\nКогда вы итерируетесь по чему‑то, например, по «файлоподобному» объекту, и делаете `yield` для каждого элемента, вы можете также использовать `yield from`, чтобы отдавать каждый элемент напрямую и не писать цикл `for`.\n\nЭто не специфично для FastAPI, это просто Python, но полезный приём. 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/ru/docs/advanced/strict-content-type.md",
    "content": "# Строгая проверка HTTP-заголовка Content-Type { #strict-content-type-checking }\n\nПо умолчанию **FastAPI** использует строгую проверку HTTP-заголовка `Content-Type` для JSON-тел запросов. Это означает, что JSON-запросы должны включать корректный заголовок `Content-Type` (например, `application/json`), чтобы тело запроса было обработано как JSON.\n\n## Риск CSRF { #csrf-risk }\n\nТакое поведение по умолчанию обеспечивает защиту от класса атак **Cross-Site Request Forgery (CSRF)** в очень специфическом сценарии.\n\nЭти атаки используют то, что браузеры позволяют скриптам отправлять запросы без выполнения CORS preflight, когда они:\n\n- не имеют заголовка `Content-Type` (например, при использовании `fetch()` с телом `Blob`)\n- и не отправляют никаких учетных данных аутентификации.\n\nЭтот тип атак в основном актуален, когда:\n\n- приложение запускается локально (например, на `localhost`) или во внутренней сети\n- и в приложении нет аутентификации, оно предполагает, что любому запросу из той же сети можно доверять.\n\n## Пример атаки { #example-attack }\n\nПредставьте, что вы сделали способ запускать локального ИИ-агента.\n\nОн предоставляет API по адресу\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nЕсть также фронтенд по адресу\n\n```\nhttp://localhost:8000\n```\n\n/// tip | Совет\n\nОбратите внимание, что у обоих один и тот же хост.\n\n///\n\nЧерез фронтенд вы можете заставлять ИИ-агента выполнять действия от вашего имени.\n\nТак как он работает локально и не в открытом интернете, вы решаете не настраивать аутентификацию, полагаясь на доступ к локальной сети.\n\nЗатем один из ваших пользователей может установить это и запускать локально.\n\nПотом он может открыть вредоносный сайт, например что-то вроде\n\n```\nhttps://evilhackers.example.com\n```\n\nИ этот вредоносный сайт отправит запросы с помощью `fetch()` с телом `Blob` к локальному API по адресу\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nНесмотря на то, что хост вредоносного сайта и локального приложения различается, браузер не запустит CORS preflight-запрос, потому что:\n\n- Приложение работает без аутентификации, ему не нужно отправлять какие-либо учетные данные.\n- Браузер «считает», что он не отправляет JSON (из-за отсутствия заголовка `Content-Type`).\n\nВ итоге вредоносный сайт может заставить локального ИИ-агента отправить злые сообщения бывшему начальнику пользователя... или что-то похуже. 😅\n\n## Открытый интернет { #open-internet }\n\nЕсли ваше приложение доступно в открытом интернете, вы не будете «доверять сети» и позволять кому угодно отправлять привилегированные запросы без аутентификации.\n\nЗлоумышленники могут просто запустить скрипт и слать запросы к вашему API, без участия браузера, так что вы, вероятно, уже защищаете любые привилегированные эндпоинты.\n\nВ этом случае эта атака/риск на вас не распространяется.\n\nЭтот риск и атака в основном актуальны, когда приложение работает в локальной сети и это единственная предполагаемая защита.\n\n## Разрешение запросов без Content-Type { #allowing-requests-without-content-type }\n\nЕсли вам нужно поддерживать клиентов, которые не отправляют заголовок `Content-Type`, вы можете отключить строгую проверку, установив `strict_content_type=False`:\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\nС этой настройкой запросы без заголовка `Content-Type` будут иметь тело запроса, обработанное как JSON — это такое же поведение, как в более старых версиях FastAPI.\n\n/// info | Информация\n\nЭто поведение и настройка были добавлены в FastAPI 0.132.0.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/advanced/sub-applications.md",
    "content": "# Подприложения — Mounts (монтирование) { #sub-applications-mounts }\n\nЕсли вам нужны два независимых приложения FastAPI, каждое со своим собственным OpenAPI и собственными интерфейсами документации, вы можете иметь основное приложение и «смонтировать» одно (или несколько) подприложений.\n\n## Монтирование приложения **FastAPI** { #mounting-a-fastapi-application }\n\n«Монтирование» означает добавление полностью независимого приложения по конкретному пути; далее оно будет обрабатывать всё под этим путём, используя объявленные в подприложении _операции пути_.\n\n### Приложение верхнего уровня { #top-level-application }\n\nСначала создайте основное, верхнего уровня, приложение **FastAPI** и его *операции пути*:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### Подприложение { #sub-application }\n\nЗатем создайте подприложение и его *операции пути*.\n\nЭто подприложение — обычное стандартное приложение FastAPI, но именно оно будет «смонтировано»:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### Смонтируйте подприложение { #mount-the-sub-application }\n\nВ вашем приложении верхнего уровня, `app`, смонтируйте подприложение `subapi`.\n\nВ этом случае оно будет смонтировано по пути `/subapi`:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### Проверьте автоматическую документацию API { #check-the-automatic-api-docs }\n\nТеперь запустите команду `fastapi`:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nИ откройте документацию по адресу [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВы увидите автоматическую документацию API для основного приложения, включающую только его собственные _операции пути_:\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\nЗатем откройте документацию для подприложения по адресу [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs).\n\nВы увидите автоматическую документацию API для подприложения, включающую только его собственные _операции пути_, все под корректным префиксом подпути `/subapi`:\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\nЕсли вы попробуете взаимодействовать с любым из двух интерфейсов, всё будет работать корректно, потому что браузер сможет обращаться к каждому конкретному приложению и подприложению.\n\n### Технические подробности: `root_path` { #technical-details-root-path }\n\nКогда вы монтируете подприложение, как описано выше, FastAPI позаботится о передаче пути монтирования для подприложения, используя механизм из спецификации ASGI под названием `root_path`.\n\nТаким образом подприложение будет знать, что для интерфейса документации нужно использовать этот префикс пути.\n\nУ подприложения также могут быть свои собственные смонтированные подприложения, и всё будет работать корректно, потому что FastAPI автоматически обрабатывает все эти `root_path`.\n\nВы узнаете больше о `root_path` и о том, как использовать его явно, в разделе [За прокси](behind-a-proxy.md).\n"
  },
  {
    "path": "docs/ru/docs/advanced/templates.md",
    "content": "# Шаблоны { #templates }\n\nВы можете использовать любой шаблонизатор вместе с **FastAPI**.\n\nЧасто выбирают Jinja2 — тот же, что используется во Flask и других инструментах.\n\nЕсть утилиты для простой настройки, которые вы можете использовать прямо в своем приложении **FastAPI** (предоставляются Starlette).\n\n## Установка зависимостей { #install-dependencies }\n\nУбедитесь, что вы создали [виртуальное окружение](../virtual-environments.md), активировали его и установили `jinja2`:\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## Использование `Jinja2Templates` { #using-jinja2templates }\n\n- Импортируйте `Jinja2Templates`.\n- Создайте объект `templates`, который сможете переиспользовать позже.\n- Объявите параметр `Request` в *операции пути*, которая будет возвращать шаблон.\n- Используйте созданный `templates`, чтобы отрендерить и вернуть `TemplateResponse`; передайте имя шаблона, объект `request` и словарь «context» с парами ключ-значение для использования внутри шаблона Jinja2.\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note | Примечание\n\nДо FastAPI 0.108.0, Starlette 0.29.0, `name` был первым параметром.\n\nТакже раньше, в предыдущих версиях, объект `request` передавался как часть пар ключ-значение в контексте для Jinja2.\n\n///\n\n/// tip | Совет\n\nЕсли указать `response_class=HTMLResponse`, интерфейс документации сможет определить, что ответ будет в формате HTML.\n\n///\n\n/// note | Технические детали\n\nМожно также использовать `from starlette.templating import Jinja2Templates`.\n\n**FastAPI** предоставляет тот же `starlette.templating` как `fastapi.templating` просто для удобства разработчика. Но большинство доступных ответов приходят напрямую из Starlette. Так же и с `Request` и `StaticFiles`.\n\n///\n\n## Написание шаблонов { #writing-templates }\n\nЗатем вы можете создать шаблон в `templates/item.html`, например:\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### Значения контекста шаблона { #template-context-values }\n\nВ HTML, который содержит:\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n...будет показан `id`, взятый из переданного вами «context» `dict`:\n\n```Python\n{\"id\": id}\n```\n\nНапример, для ID `42` это отрендерится как:\n\n```html\nItem ID: 42\n```\n\n### Аргументы `url_for` в шаблоне { #template-url-for-arguments }\n\nВы также можете использовать `url_for()` внутри шаблона — он принимает те же аргументы, что использовались бы вашей *функцией-обработчиком пути*.\n\nТаким образом, фрагмент:\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n...сгенерирует ссылку на тот же URL, который обрабатывается *функцией-обработчиком пути* `read_item(id=id)`.\n\nНапример, для ID `42` это отрендерится как:\n\n```html\n<a href=\"/items/42\">\n```\n\n## Шаблоны и статические файлы { #templates-and-static-files }\n\nВы также можете использовать `url_for()` внутри шаблона, например, с `StaticFiles`, которые вы монтировали с `name=\"static\"`.\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\nВ этом примере будет создана ссылка на CSS-файл `static/styles.css` с помощью:\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\nИ, так как вы используете `StaticFiles`, этот CSS-файл будет автоматически «отдаваться» вашим приложением **FastAPI** по URL `/static/styles.css`.\n\n## Подробнее { #more-details }\n\nБольше подробностей, включая то, как тестировать шаблоны, смотрите в [документации Starlette по шаблонам](https://www.starlette.dev/templates/).\n"
  },
  {
    "path": "docs/ru/docs/advanced/testing-dependencies.md",
    "content": "# Тестирование зависимостей с переопределениями { #testing-dependencies-with-overrides }\n\n## Переопределение зависимостей во время тестирования { #overriding-dependencies-during-testing }\n\nЕсть сценарии, когда может понадобиться переопределить зависимость во время тестирования.\n\nВы не хотите, чтобы исходная зависимость выполнялась (и любые её подзависимости тоже).\n\nВместо этого вы хотите предоставить другую зависимость, которая будет использоваться только во время тестов (возможно, только в некоторых конкретных тестах) и будет возвращать значение, которое можно использовать везде, где использовалось значение исходной зависимости.\n\n### Варианты использования: внешний сервис { #use-cases-external-service }\n\nПример: у вас есть внешний провайдер аутентификации, к которому нужно обращаться.\n\nВы отправляете ему токен, а он возвращает аутентифицированного пользователя.\n\nТакой провайдер может брать плату за каждый запрос, и его вызов может занимать больше времени, чем использование фиксированного мок-пользователя для тестов.\n\nВероятно, вы захотите протестировать внешний провайдер один раз, но не обязательно вызывать его для каждого запускаемого теста.\n\nВ таком случае вы можете переопределить зависимость, которая обращается к этому провайдеру, и использовать собственную зависимость, возвращающую мок-пользователя, только для ваших тестов.\n\n### Используйте атрибут `app.dependency_overrides` { #use-the-app-dependency-overrides-attribute }\n\nДля таких случаев у вашего приложения **FastAPI** есть атрибут `app.dependency_overrides`, это простой `dict`.\n\nЧтобы переопределить зависимость для тестирования, укажите в качестве ключа исходную зависимость (функцию), а в качестве значения — ваше переопределение зависимости (другую функцию).\n\nТогда **FastAPI** будет вызывать это переопределение вместо исходной зависимости.\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip | Совет\n\nВы можете задать переопределение для зависимости, используемой в любом месте вашего приложения **FastAPI**.\n\nИсходная зависимость может использоваться в функции-обработчике пути, в декораторе операции пути (когда вы не используете возвращаемое значение), в вызове `.include_router()` и т.д.\n\nFastAPI всё равно сможет её переопределить.\n\n///\n\nЗатем вы можете сбросить переопределения (удалить их), установив `app.dependency_overrides` в пустой `dict`:\n\n```Python\napp.dependency_overrides = {}\n```\n\n/// tip | Совет\n\nЕсли вы хотите переопределять зависимость только во время некоторых тестов, задайте переопределение в начале теста (внутри функции теста) и сбросьте его в конце (в конце функции теста).\n\n///\n"
  },
  {
    "path": "docs/ru/docs/advanced/testing-events.md",
    "content": "# Тестирование событий: lifespan и startup - shutdown { #testing-events-lifespan-and-startup-shutdown }\n\nЕсли вам нужно, чтобы `lifespan` выполнялся в ваших тестах, вы можете использовать `TestClient` вместе с оператором `with`:\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\n\nВы можете узнать больше подробностей в статье [Запуск lifespan в тестах на официальном сайте документации Starlette.](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)\n\nДля устаревших событий `startup` и `shutdown` вы можете использовать `TestClient` следующим образом:\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/ru/docs/advanced/testing-websockets.md",
    "content": "# Тестирование WebSocket { #testing-websockets }\n\nВы можете использовать тот же `TestClient` для тестирования WebSocket.\n\nДля этого используйте `TestClient` с менеджером контекста `with`, подключаясь к WebSocket:\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note | Примечание\n\nПодробности смотрите в документации Starlette по [тестированию WebSocket](https://www.starlette.dev/testclient/#testing-websocket-sessions).\n\n///\n"
  },
  {
    "path": "docs/ru/docs/advanced/using-request-directly.md",
    "content": "# Прямое использование Request { #using-the-request-directly }\n\nДо этого вы объявляли нужные части HTTP-запроса вместе с их типами.\n\nИзвлекая данные из:\n\n* пути (как параметров),\n* HTTP-заголовков,\n* Cookie,\n* и т.д.\n\nТем самым **FastAPI** валидирует эти данные, преобразует их и автоматически генерирует документацию для вашего API.\n\nНо бывают ситуации, когда нужно обратиться к объекту `Request` напрямую.\n\n## Подробности об объекте `Request` { #details-about-the-request-object }\n\nТак как под капотом **FastAPI** — это **Starlette** с дополнительным слоем инструментов, вы можете при необходимости напрямую использовать объект [`Request`](https://www.starlette.dev/requests/) из Starlette.\n\nЭто также означает, что если вы получаете данные напрямую из объекта `Request` (например, читаете тело запроса), то они не будут валидироваться, конвертироваться или документироваться (с OpenAPI, для автоматического пользовательского интерфейса API) средствами FastAPI.\n\nПри этом любой другой параметр, объявленный обычным образом (например, тело запроса с Pydantic-моделью), по-прежнему будет валидироваться, конвертироваться, аннотироваться и т.д.\n\nНо есть конкретные случаи, когда полезно получить объект `Request`.\n\n## Используйте объект `Request` напрямую { #use-the-request-object-directly }\n\nПредставим, что вы хотите получить IP-адрес/хост клиента внутри вашей *функции-обработчика пути*.\n\nДля этого нужно обратиться к запросу напрямую.\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\nЕсли объявить параметр *функции-обработчика пути* с типом `Request`, **FastAPI** поймёт, что нужно передать объект `Request` в этот параметр.\n\n/// tip | Совет\n\nОбратите внимание, что в этом примере мы объявляем path-параметр вместе с параметром `Request`.\n\nТаким образом, path-параметр будет извлечён, валидирован, преобразован к указанному типу и задокументирован в OpenAPI.\n\nТочно так же вы можете объявлять любые другие параметры как обычно и, дополнительно, получать `Request`.\n\n///\n\n## Документация по `Request` { #request-documentation }\n\nПодробнее об [объекте `Request` на официальном сайте документации Starlette](https://www.starlette.dev/requests/).\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette.requests import Request`.\n\n**FastAPI** предоставляет его напрямую для удобства разработчика, но сам объект приходит из Starlette.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/advanced/websockets.md",
    "content": "# Веб-сокеты { #websockets }\n\nВы можете использовать [веб-сокеты](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) в **FastAPI**.\n\n## Установка `websockets` { #install-websockets }\n\nУбедитесь, что вы создали [виртуальное окружение](../virtual-environments.md), активировали его и установили `websockets` (библиотека Python, упрощающая работу с протоколом \"WebSocket\"):\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## Клиент WebSockets { #websockets-client }\n\n### В продакшн { #in-production }\n\nВ продакшн у вас, вероятно, есть фронтенд, созданный с помощью современного фреймворка вроде React, Vue.js или Angular.\n\nИ для взаимодействия с бекендом по WebSocket вы, скорее всего, будете использовать инструменты вашего фронтенда.\n\nТакже у вас может быть нативное мобильное приложение, которое напрямую, нативным кодом, взаимодействует с вашим WebSocket-бекендом.\n\nЛибо у вас может быть любой другой способ взаимодействия с WebSocket-эндпоинтом.\n\n---\n\nНо для этого примера мы воспользуемся очень простым HTML‑документом с небольшим JavaScript, всё внутри одной длинной строки.\n\nКонечно же, это неоптимально, и вы бы не использовали это в продакшн.\n\nВ продакшн у вас был бы один из вариантов выше.\n\nДля примера нам нужен наиболее простой способ, который позволит сосредоточиться на серверной части веб‑сокетов и получить рабочий код:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## Создание `websocket` { #create-a-websocket }\n\nСоздайте `websocket` в своем **FastAPI** приложении:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette.websockets import WebSocket`.\n\n**FastAPI** напрямую предоставляет тот же самый `WebSocket` просто для удобства. На самом деле это `WebSocket` из Starlette.\n\n///\n\n## Ожидание и отправка сообщений { #await-for-messages-and-send-messages }\n\nЧерез эндпоинт веб-сокета вы можете получать и отправлять сообщения.\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\nВы можете получать и отправлять двоичные, текстовые и JSON данные.\n\n## Проверка в действии { #try-it }\n\nПоместите ваш код в файл `main.py`, затем запустите приложение:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nОткройте браузер по адресу [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nВы увидите следующую простенькую страницу:\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\nВы можете набирать сообщения в поле ввода и отправлять их:\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\nИ ваше **FastAPI** приложение с веб-сокетами ответит:\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\nВы можете отправлять и получать множество сообщений:\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\nИ все они будут использовать одно и то же веб-сокет соединение.\n\n## Использование `Depends` и не только { #using-depends-and-others }\n\nВы можете импортировать из `fastapi` и использовать в эндпоинте вебсокета:\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\nОни работают так же, как и в других FastAPI эндпоинтах/*операциях пути*:\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info | Примечание\n\nВ веб-сокете вызывать `HTTPException` не имеет смысла. Вместо этого нужно использовать `WebSocketException`.\n\nВы можете использовать код закрытия из [допустимых кодов, определённых в спецификации](https://tools.ietf.org/html/rfc6455#section-7.4.1).\n\n///\n\n### Веб-сокеты с зависимостями: проверка в действии { #try-the-websockets-with-dependencies }\n\nЗапустите приложение:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nОткройте браузер по адресу [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nТам вы можете задать:\n\n* \"Item ID\", используемый в пути.\n* \"Token\", используемый как query-параметр.\n\n/// tip | Подсказка\n\nОбратите внимание, что query-параметр `token` будет обработан в зависимости.\n\n///\n\nТеперь вы можете подключиться к веб-сокету и начинать отправку и получение сообщений:\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## Обработка отключений и работа с несколькими клиентами { #handling-disconnections-and-multiple-clients }\n\nЕсли веб-сокет соединение закрыто, то `await websocket.receive_text()` вызовет исключение `WebSocketDisconnect`, которое можно поймать и обработать как в этом примере.\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\nЧтобы воспроизвести пример:\n\n* Откройте приложение в нескольких вкладках браузера.\n* Отправьте из них сообщения.\n* Затем закройте одну из вкладок.\n\nЭто вызовет исключение `WebSocketDisconnect`, и все остальные клиенты получат следующее сообщение:\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip | Подсказка\n\nПриложение выше - это всего лишь простой минимальный пример, демонстрирующий обработку и передачу сообщений нескольким веб-сокет соединениям.\n\nНо имейте в виду, что это будет работать только в одном процессе и только пока он активен, так как всё обрабатывается в простом списке в оперативной памяти.\n\nЕсли нужно что-то легко интегрируемое с FastAPI, но более надежное и с поддержкой Redis, PostgreSQL или другого, то можно воспользоваться [encode/broadcaster](https://github.com/encode/broadcaster).\n\n///\n\n## Дополнительная информация { #more-info }\n\nДля более глубокого изучения темы воспользуйтесь документацией Starlette:\n\n* [Класс `WebSocket`](https://www.starlette.dev/websockets/).\n* [Обработка WebSocket на основе классов](https://www.starlette.dev/endpoints/#websocketendpoint).\n"
  },
  {
    "path": "docs/ru/docs/advanced/wsgi.md",
    "content": "# Подключение WSGI — Flask, Django и другие { #including-wsgi-flask-django-others }\n\nВы можете монтировать WSGI‑приложения, как вы видели в [Подприложения — Mounts](sub-applications.md), [За прокси‑сервером](behind-a-proxy.md).\n\nДля этого вы можете использовать `WSGIMiddleware` и обернуть им ваше WSGI‑приложение, например Flask, Django и т.д.\n\n## Использование `WSGIMiddleware` { #using-wsgimiddleware }\n\n/// info | Информация\n\nДля этого требуется установить `a2wsgi`, например с помощью `pip install a2wsgi`.\n\n///\n\nНужно импортировать `WSGIMiddleware` из `a2wsgi`.\n\nЗатем оберните WSGI‑приложение (например, Flask) в middleware (Промежуточный слой).\n\nПосле этого смонтируйте его на путь.\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note | Примечание\n\nРанее рекомендовалось использовать `WSGIMiddleware` из `fastapi.middleware.wsgi`, но теперь он помечен как устаревший.\n\nВместо него рекомендуется использовать пакет `a2wsgi`. Использование остаётся таким же.\n\nПросто убедитесь, что пакет `a2wsgi` установлен, и импортируйте `WSGIMiddleware` из `a2wsgi`.\n\n///\n\n## Проверьте { #check-it }\n\nТеперь каждый HTTP‑запрос по пути `/v1/` будет обрабатываться приложением Flask.\n\nА всё остальное будет обрабатываться **FastAPI**.\n\nЕсли вы запустите это и перейдёте по [http://localhost:8000/v1/](http://localhost:8000/v1/), вы увидите HTTP‑ответ от Flask:\n\n```txt\nHello, World from Flask!\n```\n\nА если вы перейдёте по [http://localhost:8000/v2](http://localhost:8000/v2), вы увидите HTTP‑ответ от FastAPI:\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/ru/docs/alternatives.md",
    "content": "# Альтернативы, источники вдохновения и сравнения { #alternatives-inspiration-and-comparisons }\n\nЧто вдохновило **FastAPI**, сравнение с альтернативами и чему он у них научился.\n\n## Введение { #intro }\n\n**FastAPI** не существовал бы без предыдущих работ других людей.\n\nБыло создано множество инструментов, которые вдохновили на его появление.\n\nЯ несколько лет избегал создания нового фреймворка. Сначала пытался закрыть все возможности, которые сейчас предоставляет **FastAPI**, с помощью множества разных фреймворков, плагинов и инструментов.\n\nНо в какой-то момент не осталось другого варианта, кроме как создать что-то, что включает все эти возможности, взяв лучшие идеи из прежних инструментов и совместив их максимально удачным образом, используя возможности языка, которых прежде не было (аннотации типов в Python 3.6+).\n\n## Предшествующие инструменты { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\nЭто самый популярный Python-фреймворк, ему широко доверяют. Он используется для построения систем вроде Instagram.\n\nОн относительно тесно связан с реляционными базами данных (например, MySQL или PostgreSQL), поэтому использовать NoSQL-базу данных (например, Couchbase, MongoDB, Cassandra и т. п.) в качестве основного хранилища не очень просто.\n\nОн был создан для генерации HTML на бэкенде, а не для создания API, используемых современным фронтендом (например, React, Vue.js и Angular) или другими системами (например, устройствами <abbr title=\"Internet of Things – Интернет вещей\">IoT</abbr>), которые с ним общаются.\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nDjango REST Framework был создан как гибкий набор инструментов для построения веб-API поверх Django, чтобы улучшить его возможности в части API.\n\nОн используется многими компаниями, включая Mozilla, Red Hat и Eventbrite.\n\nЭто был один из первых примеров **автоматической документации API**, и именно эта идея одной из первых вдохновила на «поиск» **FastAPI**.\n\n/// note | Заметка\n\nDjango REST Framework был создан Томом Кристи. Он же создал Starlette и Uvicorn, на которых основан **FastAPI**.\n\n///\n\n/// check | Вдохновило **FastAPI** на\n\nНаличие пользовательского веб-интерфейса с автоматической документацией API.\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask — это «микрофреймворк», он не включает интеграции с базами данных и многие другие вещи, которые в Django идут «из коробки».\n\nЭта простота и гибкость позволяет, например, использовать NoSQL-базы в качестве основной системы хранения данных.\n\nОн очень прост, его относительно легко интуитивно освоить, хотя местами документация довольно техническая.\n\nЕго также часто используют для приложений, которым не нужна база данных, управление пользователями или многие другие функции, предварительно встроенные в Django. Хотя многие из этих возможностей можно добавить плагинами.\n\nТакое разбиение на части и то, что это «микрофреймворк», который можно расширять ровно под нужды, — ключевая особенность, которую хотелось сохранить.\n\nС учётом простоты Flask он казался хорошим вариантом для создания API. Следующим было найти «Django REST Framework» для Flask.\n\n/// check | Вдохновило **FastAPI** на\n\nБыть микро-фреймворком. Облегчить комбинирование необходимых инструментов и компонентов.\n\nИметь простую и удобную систему маршрутизации.\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI** на самом деле не альтернатива **Requests**. Их области применения очень различны.\n\nОбычно Requests используют даже внутри приложения FastAPI.\n\nИ всё же **FastAPI** во многом вдохновлялся Requests.\n\n**Requests** — это библиотека для взаимодействия с API (как клиент), а **FastAPI** — библиотека для создания API (как сервер).\n\nОни, в каком-то смысле, находятся на противоположных концах и дополняют друг друга.\n\nRequests имеет очень простой и понятный дизайн, им очень легко пользоваться, есть разумные значения по умолчанию. И при этом он очень мощный и настраиваемый.\n\nИменно поэтому на официальном сайте сказано:\n\n> Requests — один из самых загружаемых Python-пакетов всех времён\n\nПользоваться им очень просто. Например, чтобы сделать запрос `GET`, вы бы написали:\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\nСоответствующая в FastAPI API-операция пути могла бы выглядеть так:\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\nПосмотрите, насколько похожи `requests.get(...)` и `@app.get(...)`.\n\n/// check | Вдохновило **FastAPI** на\n\n* Иметь простой и понятный API.\n* Использовать названия HTTP-методов (операций) напрямую, простым и интуитивным образом.\n* Иметь разумные значения по умолчанию, но и мощные настройки.\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\nГлавной возможностью, которую хотелось взять из Django REST Framework, была автоматическая документация API.\n\nЗатем я обнаружил, что есть стандарт для документирования API с использованием JSON (или YAML — расширения JSON), под названием Swagger.\n\nИ уже существовал веб-интерфейс для Swagger API. Поэтому возможность генерировать документацию Swagger для API позволила бы автоматически использовать этот веб-интерфейс.\n\nВ какой-то момент Swagger был передан Linux Foundation и переименован в OpenAPI.\n\nВот почему, говоря о версии 2.0, обычно говорят «Swagger», а о версии 3+ — «OpenAPI».\n\n/// check | Вдохновило **FastAPI** на\n\nИспользовать открытый стандарт для спецификаций API вместо самодельной схемы.\n\nИ интегрировать основанные на стандартах инструменты пользовательского интерфейса:\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\nЭти два инструмента выбраны за популярность и стабильность, но даже при беглом поиске можно найти десятки альтернативных интерфейсов для OpenAPI (которые можно использовать с **FastAPI**).\n\n///\n\n### REST-фреймворки для Flask { #flask-rest-frameworks }\n\nСуществует несколько REST-фреймворков для Flask, но, вложив время и усилия в исследование, я обнаружил, что многие из них прекращены или заброшены, с несколькими нерешёнными Issue (тикет\\обращение), из-за которых они непригодны.\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nОдна из основных возможностей, нужных системам API, — «<dfn title=\"также называемая маршаллингом, преобразованием\">сериализация</dfn>» данных, то есть преобразование данных из кода (Python) во что-то, что можно отправить по сети. Например, преобразование объекта с данными из базы в JSON-объект. Преобразование объектов `datetime` в строки и т. п.\n\nЕщё одна важная возможность, востребованная API, — валидация данных: убеждаться, что данные валидны с учётом заданных параметров. Например, что какое-то поле — `int`, а не произвольная строка. Это особенно полезно для входящих данных.\n\nБез системы валидации данных вам пришлось бы выполнять все проверки вручную в коде.\n\nИменно для этих возможностей и был создан Marshmallow. Это отличная библиотека, я много ей пользовался раньше.\n\nНо она появилась до того, как в Python появились аннотации типов. Поэтому для определения каждой <dfn title=\"определение того, как должны быть сформированы данные\">схемы</dfn> нужно использовать специальные утилиты и классы, предоставляемые Marshmallow.\n\n/// check | Вдохновило **FastAPI** на\n\nИспользовать код для автоматического определения «схем», задающих типы данных и их валидацию.\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nЕщё одна важная возможность для API — <dfn title=\"чтение и преобразование в данные Python\">парсинг</dfn> данных из входящих HTTP-запросов.\n\nWebargs — это инструмент, созданный для этого поверх нескольких фреймворков, включая Flask.\n\nОн использует Marshmallow для валидации данных. И создан теми же разработчиками.\n\nЭто отличный инструмент, и я тоже много им пользовался до появления **FastAPI**.\n\n/// info | Информация\n\nWebargs был создан теми же разработчиками, что и Marshmallow.\n\n///\n\n/// check | Вдохновило **FastAPI** на\n\nАвтоматическую валидацию входящих данных HTTP-запроса.\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow и Webargs предоставляют валидацию, парсинг и сериализацию как плагины.\n\nНо документации всё ещё не было. Тогда появился APISpec.\n\nЭто плагин для многих фреймворков (есть плагин и для Starlette).\n\nОн работает так: вы пишете определение схемы в формате YAML внутри докстринга каждой функции, обрабатывающей маршрут.\n\nИ он генерирует схемы OpenAPI.\n\nТак это работает во Flask, Starlette, Responder и т. д.\n\nНо у нас снова возникает проблема: появляется микро-синтаксис внутри строки Python (большой YAML).\n\nРедактор кода мало чем может помочь. И если мы изменим параметры или схемы Marshmallow и забудем также изменить YAML в докстринге, сгенерированная схема устареет.\n\n/// info | Информация\n\nAPISpec был создан теми же разработчиками, что и Marshmallow.\n\n///\n\n/// check | Вдохновило **FastAPI** на\n\nПоддержку открытого стандарта для API — OpenAPI.\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\nЭто плагин для Flask, который связывает Webargs, Marshmallow и APISpec.\n\nОн использует информацию из Webargs и Marshmallow, чтобы автоматически генерировать схемы OpenAPI с помощью APISpec.\n\nОтличный и недооценённый инструмент. Он заслуживает большей популярности, чем многие плагины для Flask. Возможно, из-за слишком краткой и абстрактной документации.\n\nЭто решило проблему необходимости писать YAML (ещё один синтаксис) в докстрингах Python.\n\nКомбинация Flask, Flask-apispec с Marshmallow и Webargs была моим любимым бэкенд-стеком до создания **FastAPI**.\n\nЕго использование привело к созданию нескольких full-stack генераторов на Flask. Это основные стеки, которые я (и несколько внешних команд) использовали до сих пор:\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\nИ эти же full-stack генераторы стали основой для [Генераторов проектов **FastAPI**](project-generation.md).\n\n/// info | Информация\n\nFlask-apispec был создан теми же разработчиками, что и Marshmallow.\n\n///\n\n/// check | Вдохновило **FastAPI** на\n\nАвтоматическую генерацию схемы OpenAPI из того же кода, который определяет сериализацию и валидацию.\n\n///\n\n### [NestJS](https://nestjs.com/) (и [Angular](https://angular.io/)) { #nestjs-and-angular }\n\nЭто даже не Python. NestJS — это JavaScript/TypeScript-фреймворк на NodeJS, вдохновлённый Angular.\n\nОн достигает чего-то отчасти похожего на то, что можно сделать с Flask-apispec.\n\nВ нём встроена система внедрения зависимостей, вдохновлённая Angular 2. Требуется предварительная регистрация «инжектируемых» компонентов (как и во всех известных мне системах внедрения зависимостей), что добавляет многословности и повторяемости кода.\n\nПоскольку параметры описываются с помощью типов TypeScript (аналог аннотаций типов в Python), поддержка редактора кода весьма хороша.\n\nНо так как данные о типах TypeScript не сохраняются после компиляции в JavaScript, он не может полагаться на типы для одновременного определения валидации, сериализации и документации. Из‑за этого и некоторых проектных решений для получения валидации, сериализации и автоматической генерации схем приходится добавлять декораторы во многих местах. В итоге это становится довольно многословным.\n\nОн плохо справляется с вложенными моделями. Если JSON-тело запроса — это объект JSON, содержащий внутренние поля, которые сами являются вложенными объектами JSON, это нельзя как следует задокументировать и провалидировать.\n\n/// check | Вдохновило **FastAPI** на\n\nИспользовать типы Python для отличной поддержки в редакторе кода.\n\nИметь мощную систему внедрения зависимостей. Найти способ минимизировать повторение кода.\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\nЭто был один из первых чрезвычайно быстрых Python-фреймворков на основе `asyncio`. Он был сделан очень похожим на Flask.\n\n/// note | Технические детали\n\nОн использовал [`uvloop`](https://github.com/MagicStack/uvloop) вместо стандартного цикла `asyncio` в Python. Это и сделало его таким быстрым.\n\nОн явно вдохновил Uvicorn и Starlette, которые сейчас быстрее Sanic в открытых бенчмарках.\n\n///\n\n/// check | Вдохновило **FastAPI** на\n\nПоиск способа достичь сумасшедшей производительности.\n\nИменно поэтому **FastAPI** основан на Starlette, так как это самый быстрый доступный фреймворк (по данным сторонних бенчмарков).\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon — ещё один высокопроизводительный Python-фреймворк, он минималистичен и служит основой для других фреймворков, таких как Hug.\n\nОн спроектирован так, что функции получают два параметра: «request» и «response». Затем вы «читаете» части из запроса и «пишете» части в ответ. Из‑за такого дизайна невозможно объявить параметры запроса и тело запроса стандартными аннотациями типов Python как параметры функции.\n\nПоэтому валидация данных, сериализация и документация должны выполняться в коде вручную, не автоматически. Либо должны быть реализованы во фреймворке поверх Falcon, как в Hug. Та же особенность есть и в других фреймворках, вдохновлённых дизайном Falcon — с одним объектом запроса и одним объектом ответа в параметрах.\n\n/// check | Вдохновило **FastAPI** на\n\nПоиск способов получить отличную производительность.\n\nВместе с Hug (так как Hug основан на Falcon) вдохновило **FastAPI** объявлять параметр `response` в функциях.\n\nХотя в FastAPI это необязательно, и используется в основном для установки HTTP-заголовков, cookie и альтернативных статус-кодов.\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\nЯ обнаружил Molten на ранних этапах создания **FastAPI**. И у него были очень похожие идеи:\n\n* Основан на аннотациях типов Python.\n* Валидация и документация из этих типов.\n* Система внедрения зависимостей.\n\nОн не использует стороннюю библиотеку для валидации, сериализации и документации, такую как Pydantic, — у него своя. Поэтому такие определения типов данных будет сложнее переиспользовать.\n\nТребуются более многословные конфигурации. И так как он основан на WSGI (вместо ASGI), он не предназначен для использования преимуществ высокой производительности инструментов вроде Uvicorn, Starlette и Sanic.\n\nСистема внедрения зависимостей требует предварительной регистрации зависимостей, а зависимости разрешаются по объявленным типам. Поэтому невозможно объявить более одного «компонента», предоставляющего определённый тип.\n\nМаршруты объявляются в одном месте, используя функции, объявленные в других местах (вместо декораторов, которые можно разместить прямо над функцией, обрабатывающей эндпоинт). Это ближе к тому, как это делает Django, чем Flask (и Starlette). Это разделяет в коде вещи, которые довольно тесно связаны.\n\n/// check | Вдохновило **FastAPI** на\n\nОпределять дополнительные проверки типов данных, используя значение «по умолчанию» атрибутов модели. Это улучшает поддержку в редакторе кода, и раньше этого не было в Pydantic.\n\nФактически это вдохновило на обновление частей Pydantic, чтобы поддерживать такой же стиль объявления валидации (вся эта функциональность теперь уже есть в Pydantic).\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug был одним из первых фреймворков, реализовавших объявление типов параметров API с использованием аннотаций типов Python. Это была отличная идея, которая вдохновила и другие инструменты.\n\nОн использовал собственные типы в объявлениях вместо стандартных типов Python, но это всё равно был огромный шаг вперёд.\n\nОн также был одним из первых фреймворков, генерировавших собственную схему, описывающую весь API в JSON.\n\nОн не был основан на стандартах вроде OpenAPI и JSON Schema. Поэтому интегрировать его с другими инструментами, такими как Swagger UI, было бы непросто. Но, опять же, это была очень инновационная идея.\n\nУ него есть интересная и необычная особенность: с помощью одного и того же фреймворка можно создавать и API, и CLI.\n\nТак как он основан на предыдущем стандарте для синхронных веб-фреймворков Python (WSGI), он не может работать с WebSocket и прочим, хотя также демонстрирует высокую производительность.\n\n/// info | Информация\n\nHug был создан Тимоти Кросли, тем же автором [`isort`](https://github.com/timothycrosley/isort), отличного инструмента для автоматической сортировки импортов в файлах Python.\n\n///\n\n/// check | Идеи, вдохновившие **FastAPI**\n\nHug вдохновил части APIStar и был одним из наиболее многообещающих инструментов, которые я нашёл, наряду с APIStar.\n\nHug помог вдохновить **FastAPI** использовать аннотации типов Python для объявления параметров и автоматически генерировать схему, определяющую API.\n\nHug вдохновил **FastAPI** объявлять параметр `response` в функциях для установки HTTP-заголовков и cookie.\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0.5) { #apistar-0-5 }\n\nПрямо перед решением строить **FastAPI** я нашёл сервер **APIStar**. В нём было почти всё, что я искал, и отличный дизайн.\n\nЭто была одна из первых реализаций фреймворка, использующего аннотации типов Python для объявления параметров и запросов (до NestJS и Molten), которые я видел. Я обнаружил его примерно в то же время, что и Hug. Но APIStar использовал стандарт OpenAPI.\n\nВ нём были автоматические валидация данных, сериализация данных и генерация схемы OpenAPI на основе тех же аннотаций типов в нескольких местах.\n\nОпределение схемы тела запроса не использовало те же аннотации типов Python, как в Pydantic, — это было ближе к Marshmallow, поэтому поддержка редактора кода была бы хуже, но всё равно APIStar оставался лучшим доступным вариантом.\n\nНа тот момент у него были лучшие показатели в бенчмарках (его превосходил только Starlette).\n\nСначала у него не было веб‑UI для автоматической документации API, но я знал, что могу добавить к нему Swagger UI.\n\nУ него была система внедрения зависимостей. Она требовала предварительной регистрации компонентов, как и другие инструменты, обсуждавшиеся выше. Но всё же это была отличная возможность.\n\nМне так и не удалось использовать его в полном проекте, поскольку не было интеграции с системой безопасности, поэтому я не мог заменить все возможности, которые имел с full-stack генераторами на основе Flask-apispec. В моём бэклоге было создать пулл-реквест (запрос на изменение), добавляющий эту функциональность.\n\nЗатем фокус проекта сместился.\n\nЭто перестал быть веб-фреймворк для API, так как автору нужно было сосредоточиться на Starlette.\n\nСейчас APIStar — это набор инструментов для валидации спецификаций OpenAPI, а не веб-фреймворк.\n\n/// info | Информация\n\nAPIStar был создан Томом Кристи. Тем самым человеком, который создал:\n\n* Django REST Framework\n* Starlette (на котором основан **FastAPI**)\n* Uvicorn (используется Starlette и **FastAPI**)\n\n///\n\n/// check | Вдохновило **FastAPI** на\n\nСуществование.\n\nИдея объявлять сразу несколько вещей (валидацию данных, сериализацию и документацию) с помощью одних и тех же типов Python, которые одновременно обеспечивают отличную поддержку в редакторе кода, показалась мне блестящей.\n\nПосле долгих поисков похожего фреймворка и тестирования множества альтернатив APIStar был лучшим доступным вариантом.\n\nЗатем APIStar перестал существовать как сервер, а был создан Starlette — новая и лучшая основа для такой системы. Это стало окончательным вдохновением для создания **FastAPI**.\n\nЯ считаю **FastAPI** «духовным преемником» APIStar, который улучшает и расширяет возможности, систему типов и другие части, опираясь на уроки от всех этих предыдущих инструментов.\n\n///\n\n## Что используется в **FastAPI** { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic — это библиотека для определения валидации данных, сериализации и документации (с использованием JSON Schema) на основе аннотаций типов Python.\n\nБлагодаря этому он чрезвычайно интуитивен.\n\nЕго можно сравнить с Marshmallow. Хотя в бенчмарках он быстрее Marshmallow. И поскольку он основан на тех же аннотациях типов Python, поддержка в редакторе кода отличная.\n\n/// check | **FastAPI** использует его для\n\nОбработки всей валидации данных, сериализации данных и автоматической документации моделей (на основе JSON Schema).\n\nЗатем **FastAPI** берёт эти данные JSON Schema и помещает их в OpenAPI, помимо всех прочих функций.\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette — это лёгкий <dfn title=\"Новый стандарт построения асинхронных веб-приложений на Python\">ASGI</dfn> фреймворк/набор инструментов, идеально подходящий для создания высокопроизводительных asyncio‑сервисов.\n\nОн очень простой и интуитивный. Спроектирован так, чтобы его было легко расширять, и чтобы компоненты были модульными.\n\nВ нём есть:\n\n* Впечатляющая производительность.\n* Поддержка WebSocket.\n* Фоновые задачи, выполняемые в том же процессе.\n* События запуска и завершения.\n* Тестовый клиент на базе HTTPX.\n* CORS, GZip, статические файлы, потоковые ответы.\n* Поддержка сессий и cookie.\n* 100% покрытие тестами.\n* 100% кодовой базы с аннотациями типов.\n* Мало жёстких зависимостей.\n\nВ настоящее время Starlette — самый быстрый из протестированных Python-фреймворков. Его превосходит только Uvicorn, который не фреймворк, а сервер.\n\nStarlette предоставляет весь базовый функционал веб-микрофреймворка.\n\nНо он не предоставляет автоматическую валидацию данных, сериализацию или документацию.\n\nЭто одна из главных вещей, которые **FastAPI** добавляет поверх, всё на основе аннотаций типов Python (с использованием Pydantic). Плюс система внедрения зависимостей, утилиты безопасности, генерация схемы OpenAPI и т. д.\n\n/// note | Технические детали\n\nASGI — это новый «стандарт», разрабатываемый участниками core-команды Django. Он всё ещё не является «стандартом Python» (PEP), хотя процесс идёт.\n\nТем не менее его уже используют как «стандарт» несколько инструментов. Это сильно улучшает совместимость: вы можете заменить Uvicorn на любой другой ASGI-сервер (например, Daphne или Hypercorn) или добавить совместимые с ASGI инструменты, такие как `python-socketio`.\n\n///\n\n/// check | **FastAPI** использует его для\n\nОбработки всех основных веб-частей. Добавляя возможности поверх.\n\nКласс `FastAPI` напрямую наследуется от класса `Starlette`.\n\nТак что всё, что вы можете сделать со Starlette, вы можете сделать напрямую с **FastAPI**, по сути это «Starlette на стероидах».\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn — молниеносный ASGI-сервер, построенный на uvloop и httptools.\n\nЭто не веб-фреймворк, а сервер. Например, он не предоставляет инструменты для маршрутизации по путям. Это предоставляет сверху фреймворк, такой как Starlette (или **FastAPI**).\n\nЭто рекомендуемый сервер для Starlette и **FastAPI**.\n\n/// check | **FastAPI** рекомендует его как\n\nОсновной веб-сервер для запуска приложений **FastAPI**.\n\nТакже вы можете использовать опцию командной строки `--workers`, чтобы получить асинхронный многопроцессный сервер.\n\nПодробнее см. раздел [Развёртывание](deployment/index.md).\n\n///\n\n## Бенчмарки и скорость { #benchmarks-and-speed }\n\nЧтобы понять, сравнить и увидеть разницу между Uvicorn, Starlette и FastAPI, см. раздел о [Бенчмарках](benchmarks.md).\n"
  },
  {
    "path": "docs/ru/docs/async.md",
    "content": "# Конкурентность и async / await { #concurrency-and-async-await }\n\nПодробности о синтаксисе `async def` для *функций-обработчиков пути* и немного фона об асинхронном коде, конкурентности и параллелизме.\n\n## Нет времени? { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - слишком длинно; не читал\"><strong>TL;DR:</strong></abbr>\n\nЕсли вы используете сторонние библиотеки, которые нужно вызывать с `await`, например:\n\n```Python\nresults = await some_library()\n```\n\nТогда объявляйте *функции-обработчиков пути* с `async def`, например:\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | Примечание\n\n`await` можно использовать только внутри функций, объявленных с `async def`.\n\n///\n\n---\n\nЕсли вы используете стороннюю библиотеку, которая взаимодействует с чем-то (база данных, API, файловая система и т.д.) и не поддерживает использование `await` (сейчас это относится к большинству библиотек для БД), тогда объявляйте *функции-обработчиков пути* как обычно, просто с `def`, например:\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\nЕсли вашему приложению (по какой-то причине) не нужно ни с чем взаимодействовать и ждать ответа, используйте `async def`, даже если внутри не нужен `await`.\n\n---\n\nЕсли вы просто не уверены, используйте обычный `def`.\n\n---\n\n**Примечание**: вы можете смешивать `def` и `async def` в *функциях-обработчиков пути* столько, сколько нужно, и объявлять каждую так, как лучше для вашего случая. FastAPI сделает с ними всё как надо.\n\nВ любом из случаев выше FastAPI всё равно работает асинхронно и очень быстро.\n\nНо следуя этим шагам, он сможет выполнить некоторые оптимизации производительности.\n\n## Технические подробности { #technical-details }\n\nСовременные версии Python поддерживают **«асинхронный код»** с помощью **«сопрограмм»** (coroutines) и синтаксиса **`async` и `await`**.\n\nРазберём эту фразу по частям в разделах ниже:\n\n* **Асинхронный код**\n* **`async` и `await`**\n* **Сопрограммы**\n\n## Асинхронный код { #asynchronous-code }\n\nАсинхронный код значит, что в языке 💬 есть способ сказать компьютеру/программе 🤖, что в некоторый момент кода ему 🤖 придётся подождать, пока *что-то ещё* где-то в другом месте завершится. Назовём это *что-то ещё* «медленный файл» 📝.\n\nИ пока мы ждём завершения работы с «медленным файлом» 📝, компьютер может заняться другой работой.\n\nЗатем компьютер/программа 🤖 будет возвращаться каждый раз, когда появится возможность (пока снова где-то идёт ожидание), или когда 🤖 завершит всю текущую работу. И он 🤖 проверит, не завершилась ли какая-либо из задач, которых он ждал, и сделает то, что нужно.\n\nДалее он 🤖 возьмёт первую завершившуюся задачу (скажем, наш «медленный файл» 📝) и продолжит делать с ней то, что требуется.\n\nЭто «ожидание чего-то ещё» обычно относится к операциям <abbr title=\"Input and Output - Ввод/вывод\">I/O</abbr>, которые относительно «медленные» (по сравнению со скоростью процессора и оперативной памяти), например ожидание:\n\n* отправки данных клиентом по сети\n* получения клиентом данных, отправленных вашей программой по сети\n* чтения системой содержимого файла на диске и передачи этих данных вашей программе\n* записи на диск содержимого, которое ваша программа передала системе\n* операции удалённого API\n* завершения операции базы данных\n* возврата результатов запроса к базе данных\n* и т.д.\n\nПоскольку основное время выполнения уходит на ожидание операций <abbr title=\"Input and Output - Ввод/вывод\">I/O</abbr>, их называют операциями, «ограниченными вводом-выводом» (I/O bound).\n\nЭто называется «асинхронным», потому что компьютеру/программе не нужно «синхронизироваться» с медленной задачей, простаивая и выжидая точный момент её завершения, чтобы забрать результат и продолжить работу.\n\nВместо этого, в «асинхронной» системе, уже завершившаяся задача может немного подождать (несколько микросекунд) в очереди, пока компьютер/программа завершит то, чем занимался, и затем вернётся, чтобы забрать результаты и продолжить работу с ними.\n\nДля «синхронного» (в противоположность «асинхронному») исполнения часто используют термин «последовательный», потому что компьютер/программа выполняет все шаги по порядку, прежде чем переключиться на другую задачу, даже если эти шаги включают ожидание.\n\n### Конкурентность и бургеры { #concurrency-and-burgers }\n\nТа идея **асинхронного** кода, описанная выше, иногда также называется **«конкурентностью»**. Она отличается от **«параллелизма»**.\n\nИ **конкурентность**, и **параллелизм** относятся к «разным вещам, происходящим примерно одновременно».\n\nНо различия между *конкурентностью* и *параллелизмом* довольно существенные.\n\nЧтобы их увидеть, представьте следующую историю про бургеры:\n\n### Конкурентные бургеры { #concurrent-burgers }\n\nВы идёте со своей возлюбленной за фастфудом, вы стоите в очереди, пока кассир принимает заказы у людей перед вами. 😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\nНаконец ваша очередь: вы заказываете 2 очень «навороченных» бургера — для вашей возлюбленной и для себя. 🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\nКассир говорит что-то повару на кухне, чтобы они знали, что нужно приготовить ваши бургеры (хотя сейчас они готовят бургеры для предыдущих клиентов).\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\nВы платите. 💸\n\nКассир выдаёт вам номер вашей очереди.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\nПока вы ждёте, вы вместе со своей возлюбленной идёте и выбираете столик, садитесь и долго болтаете (ваши бургеры очень «навороченные», поэтому им нужно время на приготовление).\n\nСидя за столиком со своей возлюбленной в ожидании бургеров, вы можете провести это время, восхищаясь тем, какая она классная, милая и умная ✨😍✨.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\nПока вы ждёте и разговариваете, время от времени вы поглядываете на номер на табло, чтобы понять, не подошла ли уже ваша очередь.\n\nИ вот в какой-то момент ваша очередь наступает. Вы подходите к стойке, забираете свои бургеры и возвращаетесь к столику.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\nВы со своей возлюбленной едите бургеры и отлично проводите время. ✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info | Информация\n\nПрекрасные иллюстрации от [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nПредставьте, что в этой истории вы — компьютер/программа 🤖.\n\nПока вы стоите в очереди, вы просто бездействуете 😴, ждёте своей очереди и не делаете ничего особо «продуктивного». Но очередь движется быстро, потому что кассир только принимает заказы (а не готовит их), так что это нормально.\n\nКогда приходит ваша очередь, вы выполняете действительно «продуктивную» работу: просматриваете меню, решаете, чего хотите, учитываете выбор своей возлюбленной, платите, проверяете, что дали правильную купюру/карту, что сумма списана корректно, что в заказе верные позиции и т.д.\n\nНо затем, хотя у вас ещё нет бургеров, ваша «работа» с кассиром поставлена «на паузу» ⏸, потому что нужно подождать 🕙, пока бургеры будут готовы.\n\nНо, отойдя от стойки и сев за столик с номерком, вы можете переключить 🔀 внимание на свою возлюбленную и «поработать» ⏯ 🤓 над этим. Снова очень «продуктивно» — флирт с вашей возлюбленной 😍.\n\nПотом кассир 💁 «говорит»: «Я закончил делать бургеры», — выводя ваш номер на табло, но вы не подпрыгиваете как сумасшедший в ту же секунду, как только номер сменился на ваш. Вы знаете, что ваши бургеры никто не украдёт, потому что у вас есть номер вашей очереди, а у других — их.\n\nПоэтому вы дожидаетесь, пока ваша возлюбленная закончит историю (завершится текущая работа ⏯ / выполняемая задача 🤓), мягко улыбаетесь и говорите, что идёте за бургерами ⏸.\n\nЗатем вы идёте к стойке 🔀, к исходной задаче, которая теперь завершена ⏯, забираете бургеры, благодарите и несёте их к столику. На этом шаг/задача взаимодействия со стойкой завершён ⏹. Это, в свою очередь, создаёт новую задачу — «есть бургеры» 🔀 ⏯, но предыдущая «получить бургеры» — завершена ⏹.\n\n### Параллельные бургеры { #parallel-burgers }\n\nТеперь представим, что это не «Конкурентные бургеры», а «Параллельные бургеры».\n\nВы идёте со своей возлюбленной за параллельным фастфудом.\n\nВы стоите в очереди, пока несколько (скажем, 8) кассиров, которые одновременно являются поварами, принимают заказы у людей перед вами.\n\nВсе перед вами ждут, пока их бургеры будут готовы, не отходя от стойки, потому что каждый из 8 кассиров сразу идёт готовить бургер перед тем, как принять следующий заказ.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\nНаконец ваша очередь: вы заказываете 2 очень «навороченных» бургера — для вашей возлюбленной и для себя.\n\nВы платите 💸.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\nКассир уходит на кухню.\n\nВы ждёте, стоя у стойки 🕙, чтобы никто не забрал ваши бургеры раньше вас, так как никаких номерков нет.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\nТак как вы со своей возлюбленной заняты тем, чтобы никто не встал перед вами и не забрал ваши бургеры, как только они появятся, вы не можете уделить внимание своей возлюбленной. 😞\n\nЭто «синхронная» работа, вы «синхронизированы» с кассиром/поваром 👨‍🍳. Вам нужно ждать 🕙 и находиться там в точный момент, когда кассир/повар 👨‍🍳 закончит бургеры и вручит их вам, иначе их может забрать кто-то другой.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\nЗатем ваш кассир/повар 👨‍🍳 наконец возвращается с вашими бургерами, после долгого ожидания 🕙 у стойки.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\nВы берёте бургеры и идёте со своей возлюбленной к столику.\n\nВы просто их съедаете — и всё. ⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\nРазговоров и флирта было немного, потому что большую часть времени вы ждали 🕙 у стойки. 😞\n\n/// info | Информация\n\nПрекрасные иллюстрации от [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nВ этом сценарии «параллельных бургеров» вы — компьютер/программа 🤖 с двумя процессорами (вы и ваша возлюбленная), оба ждут 🕙 и уделяют внимание ⏯ тому, чтобы «ждать у стойки» 🕙 долгое время.\n\nВ ресторане 8 процессоров (кассиров/поваров). Тогда как в «конкурентных бургерах» могло быть только 2 (один кассир и один повар).\n\nИ всё же финальный опыт — не самый лучший. 😞\n\n---\n\nЭто была параллельная версия истории про бургеры. 🍔\n\nДля более «жизненного» примера представьте банк.\n\nДо недавнего времени в большинстве банков было несколько кассиров 👨‍💼👨‍💼👨‍💼👨‍💼 и длинная очередь 🕙🕙🕙🕙🕙🕙🕙🕙.\n\nВсе кассиры делают всю работу с одним клиентом за другим 👨‍💼⏯.\n\nИ вам приходится долго 🕙 стоять в очереди, иначе вы потеряете свою очередь.\n\nВы вряд ли захотите взять свою возлюбленную 😍 с собой, чтобы заняться делами в банке 🏦.\n\n### Вывод про бургеры { #burger-conclusion }\n\nВ этом сценарии «фастфуда с вашей возлюбленной», так как много ожидания 🕙, гораздо логичнее иметь конкурентную систему ⏸🔀⏯.\n\nТак обстоит дело и с большинством веб-приложений.\n\nОчень много пользователей, но ваш сервер ждёт 🕙, пока их не самое хорошее соединение отправит их запросы.\n\nА затем снова ждёт 🕙, пока отправятся ответы.\n\nЭто «ожидание» 🕙 измеряется микросекундами, но если всё сложить, то в сумме получается много ожидания.\n\nВот почему асинхронный ⏸🔀⏯ код очень уместен для веб-API.\n\nИменно такая асинхронность сделала NodeJS популярным (хотя NodeJS — не параллельный), и это сильная сторона Go как языка программирования.\n\nТого же уровня производительности вы получаете с **FastAPI**.\n\nА так как можно одновременно использовать параллелизм и асинхронность, вы получаете производительность выше, чем у большинства протестированных фреймворков на NodeJS и на уровне Go, который — компилируемый язык, ближе к C [(всё благодаря Starlette)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).\n\n### Конкурентность лучше параллелизма? { #is-concurrency-better-than-parallelism }\n\nНет! Мораль истории не в этом.\n\nКонкурентность отличается от параллелизма. И она лучше в **конкретных** сценариях, где много ожидания. Поэтому при разработке веб-приложений она обычно намного лучше параллелизма. Но не во всём.\n\nЧтобы уравновесить это, представьте такую короткую историю:\n\n> Вам нужно убрать большой грязный дом.\n\n*Да, это вся история*.\n\n---\n\nЗдесь нигде нет ожидания 🕙, просто очень много работы в разных местах дома.\n\nМожно организовать «очереди» как в примере с бургерами — сначала гостиная, потом кухня, — но так как вы ничего не ждёте 🕙, а просто убираете и убираете, очереди ни на что не повлияют.\n\nНа завершение уйдёт одинаковое время — с очередями (конкурентностью) и без них — и объём выполненной работы будет одинаковым.\n\nНо в этом случае, если бы вы могли привести 8 бывших кассиров/поваров, а теперь — уборщиков, и каждый из них (плюс вы) взял бы свою зону дома для уборки, вы могли бы сделать всю работу **параллельно**, с дополнительной помощью, и завершить гораздо быстрее.\n\nВ этом сценарии каждый уборщик (включая вас) был бы процессором, выполняющим свою часть работы.\n\nИ так как основное время выполнения уходит на реальную работу (а не ожидание), а работу в компьютере выполняет <abbr title=\"Central Processing Unit - Центральный процессор\">CPU</abbr>, такие задачи называют «ограниченными процессором» (CPU bound).\n\n---\n\nТипичные примеры CPU-bound операций — те, которые требуют сложной математической обработки.\n\nНапример:\n\n* Обработка **аудио** или **изображений**.\n* **Компьютерное зрение**: изображение состоит из миллионов пикселей, каждый пиксель имеет 3 значения/цвета; обычно требуется вычислить что-то для всех этих пикселей одновременно.\n* **Машинное обучение**: обычно требует множества умножений «матриц» и «векторов». Представьте огромную таблицу с числами и умножение всех этих чисел «одновременно».\n* **Глубокое обучение**: это подполе Машинного обучения, так что всё вышесказанное применимо. Просто это не одна таблица чисел, а их огромный набор, и во многих случаях вы используете специальный процессор, чтобы строить и/или использовать такие модели.\n\n### Конкурентность + параллелизм: Веб + Машинное обучение { #concurrency-parallelism-web-machine-learning }\n\nС **FastAPI** вы можете использовать преимущества конкурентности, что очень распространено в веб-разработке (это та же основная «фишка» NodeJS).\n\nНо вы также можете использовать выгоды параллелизма и многопроцессности (когда несколько процессов работают параллельно) для рабочих нагрузок, **ограниченных процессором** (CPU bound), как в системах Машинного обучения.\n\nПлюс к этому простой факт, что Python — основной язык для **Data Science**, Машинного обучения и особенно Глубокого обучения, делает FastAPI очень хорошим выбором для веб-API и приложений в области Data Science / Машинного обучения (среди многих других).\n\nКак добиться такого параллелизма в продакшн, см. раздел [Развёртывание](deployment/index.md).\n\n## `async` и `await` { #async-and-await }\n\nВ современных версиях Python есть очень интуитивный способ определять асинхронный код. Это делает его похожим на обычный «последовательный» код, а «ожидание» выполняется за вас в нужные моменты.\n\nКогда есть операция, которой нужно подождать перед тем, как вернуть результат, и она поддерживает эти новые возможности Python, вы можете написать так:\n\n```Python\nburgers = await get_burgers(2)\n```\n\nКлюч здесь — `await`. Он говорит Python, что нужно подождать ⏸, пока `get_burgers(2)` закончит своё дело 🕙, прежде чем сохранять результат в `burgers`. Благодаря этому Python будет знать, что за это время можно заняться чем-то ещё 🔀 ⏯ (например, принять другой запрос).\n\nЧтобы `await` работал, он должен находиться внутри функции, которая поддерживает такую асинхронность. Для этого просто объявите её с `async def`:\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # Сделать что-то асинхронное, чтобы приготовить бургеры\n    return burgers\n```\n\n...вместо `def`:\n\n```Python hl_lines=\"2\"\n# Это не асинхронный код\ndef get_sequential_burgers(number: int):\n    # Сделать что-то последовательное, чтобы приготовить бургеры\n    return burgers\n```\n\nС `async def` Python знает, что внутри этой функции нужно учитывать выражения `await` и что выполнение такой функции можно «приостанавливать» ⏸ и идти делать что-то ещё 🔀, чтобы потом вернуться.\n\nКогда вы хотите вызвать функцию, объявленную с `async def`, нужно её «ожидать». Поэтому вот так не сработает:\n\n```Python\n# Это не сработает, потому что get_burgers определена с: async def\nburgers = get_burgers(2)\n```\n\n---\n\nИтак, если вы используете библиотеку, которую можно вызывать с `await`, вам нужно создать *функцию-обработчик пути*, которая её использует, с `async def`, например:\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### Более технические подробности { #more-technical-details }\n\nВы могли заметить, что `await` можно использовать только внутри функций, определённых с `async def`.\n\nНо при этом функции, определённые с `async def`, нужно «ожидать». Значит, функции с `async def` тоже можно вызывать только из функций, определённых с `async def`.\n\nТак что же с «яйцом и курицей» — как вызвать первую `async` функцию?\n\nЕсли вы работаете с **FastAPI**, вам не о чем беспокоиться, потому что этой «первой» функцией будет ваша *функция-обработчик пути*, а FastAPI знает, как сделать всё правильно.\n\nНо если вы хотите использовать `async` / `await` без FastAPI, вы тоже можете это сделать.\n\n### Пишите свой асинхронный код { #write-your-own-async-code }\n\nStarlette (и **FastAPI**) основаны на [AnyIO](https://anyio.readthedocs.io/en/stable/), что делает их совместимыми и со стандартной библиотекой Python [asyncio](https://docs.python.org/3/library/asyncio-task.html), и с [Trio](https://trio.readthedocs.io/en/stable/).\n\nВ частности, вы можете напрямую использовать [AnyIO](https://anyio.readthedocs.io/en/stable/) для продвинутых сценариев конкурентности, где в вашем коде нужны более сложные паттерны.\n\nИ даже если вы не используете FastAPI, вы можете писать свои асинхронные приложения с [AnyIO](https://anyio.readthedocs.io/en/stable/), чтобы они были максимально совместимыми и получали его преимущества (например, *структурную конкурентность*).\n\nЯ создал ещё одну библиотеку поверх AnyIO, тонкий слой, чтобы немного улучшить аннотации типов и получить более качественное **автозавершение**, **ошибки прямо в редакторе** и т.д. Там также есть дружелюбное введение и руководство, чтобы помочь вам **понять** и писать **свой собственный асинхронный код**: [Asyncer](https://asyncer.tiangolo.com/). Она особенно полезна, если вам нужно **комбинировать асинхронный код с обычным** (блокирующим/синхронным) кодом.\n\n### Другие формы асинхронного кода { #other-forms-of-asynchronous-code }\n\nТакой стиль использования `async` и `await` относительно новый в языке.\n\nНо он сильно упрощает работу с асинхронным кодом.\n\nТакой же (или почти такой же) синтаксис недавно появился в современных версиях JavaScript (в браузере и NodeJS).\n\nДо этого работа с асинхронным кодом была заметно сложнее и труднее для понимания.\n\nВ предыдущих версиях Python можно было использовать потоки или [Gevent](https://www.gevent.org/). Но такой код гораздо сложнее понимать, отлаживать и держать в голове.\n\nВ прежних версиях NodeJS/браузерного JavaScript вы бы использовали «callbacks» (обратные вызовы), что приводит к «callback hell» (ад обратных вызовов).\n\n## Сопрограммы { #coroutines }\n\n**Сопрограмма** (coroutine) — это просто «навороченное» слово для того, что возвращает функция `async def`. Python знает, что это похоже на функцию: её можно запустить, она когда-нибудь завершится, но её выполнение может приостанавливаться ⏸ внутри, когда встречается `await`.\n\nЧасто всю функциональность использования асинхронного кода с `async` и `await` кратко называют «сопрограммами». Это сопоставимо с ключевой особенностью Go — «goroutines».\n\n## Заключение { #conclusion }\n\nВернёмся к той же фразе:\n\n> Современные версии Python поддерживают **«асинхронный код»** с помощью **«сопрограмм»** (coroutines) и синтаксиса **`async` и `await`**.\n\nТеперь это должно звучать понятнее. ✨\n\nИменно это «движет» FastAPI (через Starlette) и обеспечивает столь впечатляющую производительность.\n\n## Очень технические подробности { #very-technical-details }\n\n/// warning | Предупреждение\n\nСкорее всего, этот раздел можно пропустить.\n\nЗдесь — очень технические подробности о том, как **FastAPI** работает «под капотом».\n\nЕсли у вас есть достаточно технических знаний (сопрограммы, потоки, блокировки и т.д.) и вам интересно, как FastAPI обрабатывает `async def` по сравнению с обычным `def`, — вперёд.\n\n///\n\n### Функции-обработчики пути { #path-operation-functions }\n\nКогда вы объявляете *функцию-обработчик пути* обычным `def` вместо `async def`, она запускается во внешнем пуле потоков, который затем «ожидается», вместо прямого вызова (прямой вызов заблокировал бы сервер).\n\nЕсли вы пришли из другого async-фреймворка, который работает иначе, и привыкли объявлять тривиальные *функции-обработчики пути*, выполняющие только вычисления, через простой `def` ради крошечной выгоды в производительности (около 100 наносекунд), обратите внимание: в **FastAPI** эффект будет противоположным. В таких случаях лучше использовать `async def`, если только ваши *функции-обработчики пути* не используют код, выполняющий блокирующий <abbr title=\"Input/Output - Ввод/вывод: чтение или запись на диск, сетевые соединения.\">I/O</abbr>.\n\nТем не менее, в обоих случаях велика вероятность, что **FastAPI** [всё равно будет быстрее](index.md#performance) (или как минимум сопоставим) с вашим предыдущим фреймворком.\n\n### Зависимости { #dependencies }\n\nТо же относится к [зависимостям](tutorial/dependencies/index.md). Если зависимость — это обычная функция `def`, а не `async def`, она запускается во внешнем пуле потоков.\n\n### Подзависимости { #sub-dependencies }\n\nУ вас может быть несколько зависимостей и [подзависимостей](tutorial/dependencies/sub-dependencies.md), которые требуют друг друга (в виде параметров определений функций): часть из них может быть объявлена с `async def`, а часть — обычным `def`. Всё будет работать, а те, что объявлены обычным `def`, будут вызываться во внешнем потоке (из пула), а не «ожидаться».\n\n### Другие служебные функции { #other-utility-functions }\n\nЛюбые другие служебные функции, которые вы вызываете напрямую, можно объявлять обычным `def` или `async def`, и FastAPI не будет влиять на то, как вы их вызываете.\n\nВ отличие от функций, которые FastAPI вызывает за вас: *функции-обработчики пути* и зависимости.\n\nЕсли служебная функция — обычная функция с `def`, она будет вызвана напрямую (как вы и пишете в коде), не в пуле потоков; если функция объявлена с `async def`, тогда при её вызове в вашем коде вы должны использовать `await`.\n\n---\n\nСнова: это очень технические подробности, полезные, вероятно, только если вы целенаправленно их ищете.\n\nИначе вам достаточно руководствоваться рекомендациями из раздела выше: <a href=\"#in-a-hurry\">Нет времени?</a>.\n"
  },
  {
    "path": "docs/ru/docs/benchmarks.md",
    "content": "# Бенчмарки (тесты производительности) { #benchmarks }\n\nНезависимые бенчмарки TechEmpower показывают, что приложения **FastAPI** под управлением Uvicorn — [одни из самых быстрых Python‑фреймворков](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), уступающие только Starlette и самому Uvicorn (используются внутри FastAPI).\n\nНо при просмотре бенчмарков и сравнений следует иметь в виду следующее.\n\n## Бенчмарки и скорость { #benchmarks-and-speed }\n\nПри проверке бенчмарков часто можно увидеть, что инструменты разных типов сравнивают как эквивалентные.\n\nВ частности, часто сравнивают вместе Uvicorn, Starlette и FastAPI (среди многих других инструментов).\n\nЧем проще задача, которую решает инструмент, тем выше его производительность. И большинство бенчмарков не тестируют дополнительные возможности, предоставляемые инструментом.\n\nИерархия выглядит так:\n\n* **Uvicorn**: ASGI-сервер\n    * **Starlette**: (использует Uvicorn) веб-микрофреймворк\n        * **FastAPI**: (использует Starlette) API-микрофреймворк с рядом дополнительных возможностей для создания API, включая валидацию данных и т.п.\n\n* **Uvicorn**:\n    * Будет иметь наилучшую производительность, так как помимо самого сервера у него немного дополнительного кода.\n    * Вы не будете писать приложение непосредственно на Uvicorn. Это означало бы, что Ваш код должен включать как минимум весь код, предоставляемый Starlette (или **FastAPI**). И если Вы так сделаете, то в конечном итоге Ваше приложение будет иметь те же накладные расходы, что и при использовании фреймворка, минимизирующего код Вашего приложения и Ваши ошибки.\n    * Если Вы сравниваете Uvicorn, сравнивайте его с Daphne, Hypercorn, uWSGI и т.д. — серверами приложений.\n* **Starlette**:\n    * Будет на следующем месте по производительности после Uvicorn. Фактически Starlette запускается под управлением Uvicorn, поэтому он может быть только «медленнее» Uvicorn из‑за выполнения большего объёма кода.\n    * Зато он предоставляет Вам инструменты для создания простых веб‑приложений с маршрутизацией по путям и т.п.\n    * Если Вы сравниваете Starlette, сравнивайте его с Sanic, Flask, Django и т.д. — веб‑фреймворками (или микрофреймворками).\n* **FastAPI**:\n    * Точно так же, как Starlette использует Uvicorn и не может быть быстрее него, **FastAPI** использует Starlette, поэтому не может быть быстрее его.\n    * FastAPI предоставляет больше возможностей поверх Starlette — те, которые почти всегда нужны при создании API, такие как валидация и сериализация данных. В довесок Вы ещё и получаете автоматическую документацию (автоматическая документация даже не увеличивает накладные расходы при работе приложения, так как она создаётся при запуске).\n    * Если бы Вы не использовали FastAPI, а использовали Starlette напрямую (или другой инструмент вроде Sanic, Flask, Responder и т.д.), Вам пришлось бы самостоятельно реализовать валидацию и сериализацию данных. То есть, в итоге, Ваше приложение имело бы такие же накладные расходы, как если бы оно было создано с использованием FastAPI. И во многих случаях валидация и сериализация данных представляют собой самый большой объём кода, написанного в приложениях.\n    * Таким образом, используя FastAPI, Вы экономите время разработки, уменьшаете количество ошибок, строк кода и, вероятно, получите ту же производительность (или лучше), как и если бы не использовали его (поскольку Вам пришлось бы реализовать все его возможности в своём коде).\n    * Если Вы сравниваете FastAPI, сравнивайте его с фреймворком веб‑приложений (или набором инструментов), который обеспечивает валидацию данных, сериализацию и документацию, такими как Flask-apispec, NestJS, Molten и им подобные. Фреймворки с интегрированной автоматической валидацией данных, сериализацией и документацией.\n"
  },
  {
    "path": "docs/ru/docs/deployment/cloud.md",
    "content": "# Развертывание FastAPI у облачных провайдеров { #deploy-fastapi-on-cloud-providers }\n\nВы можете использовать практически любого облачного провайдера, чтобы развернуть свое приложение на FastAPI.\n\nВ большинстве случаев у основных облачных провайдеров есть руководства по развертыванию FastAPI на их платформе.\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** создан тем же автором и командой, стоящими за **FastAPI**.\n\nОн упрощает процесс **создания образа**, **развертывания** и **доступа** к API с минимальными усилиями.\n\nОн переносит тот же **опыт разработчика** создания приложений с FastAPI на их **развертывание** в облаке. 🎉\n\nFastAPI Cloud — основной спонсор и источник финансирования для open source проектов *FastAPI and friends*. ✨\n\n## Облачные провайдеры — спонсоры { #cloud-providers-sponsors }\n\nНекоторые другие облачные провайдеры ✨ [**спонсируют FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ тоже. 🙇\n\nВозможно, вы захотите попробовать их сервисы и воспользоваться их руководствами:\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/ru/docs/deployment/concepts.md",
    "content": "# Концепции развёртывания { #deployments-concepts }\n\nПри развёртывании приложения **FastAPI** (и вообще любого веб‑API) есть несколько концепций, о которых стоит думать — с их помощью можно выбрать **наиболее подходящий** способ **развёртывания вашего приложения**.\n\nНекоторые из важных концепций:\n\n* Безопасность — HTTPS\n* Запуск при старте\n* Перезапуски\n* Репликация (количество запущенных процессов)\n* Память\n* Предварительные шаги перед запуском\n\nПосмотрим, как они влияют на **развёртывания**.\n\nВ конечном итоге цель — **обслуживать клиентов вашего API** безопасно, **избегать перебоев** и максимально эффективно использовать **вычислительные ресурсы** (например, удалённые серверы/виртуальные машины). 🚀\n\nЗдесь я немного расскажу о этих **концепциях**, чтобы у вас появилась **интуиция**, как развёртывать ваш API в разных окружениях, возможно даже в **будущих**, которых ещё не существует.\n\nУчитывая эти концепции, вы сможете **оценить и спроектировать** лучший способ развёртывания **своих API**.\n\nВ следующих главах я дам более **конкретные рецепты** по развёртыванию приложений FastAPI.\n\nА пока давайте разберём важные **идеи**. Эти концепции применимы и к другим типам веб‑API. 💡\n\n## Безопасность — HTTPS { #security-https }\n\nВ [предыдущей главе про HTTPS](https.md) мы разобрались, как HTTPS обеспечивает шифрование для вашего API.\n\nТакже мы увидели, что HTTPS обычно обеспечивает компонент, **внешний** по отношению к серверу вашего приложения — **прокси-сервер TSL-терминации**.\n\nИ должен быть компонент, отвечающий за **обновление HTTPS‑сертификатов** — это может быть тот же самый компонент или отдельный.\n\n### Примеры инструментов для HTTPS { #example-tools-for-https }\n\nНекоторые инструменты, которые можно использовать как прокси-сервер TSL-терминации:\n\n* Traefik\n    * Автоматически обновляет сертификаты ✨\n* Caddy\n    * Автоматически обновляет сертификаты ✨\n* Nginx\n    * С внешним компонентом (например, Certbot) для обновления сертификатов\n* HAProxy\n    * С внешним компонентом (например, Certbot) для обновления сертификатов\n* Kubernetes с Ingress Controller (например, Nginx)\n    * С внешним компонентом (например, cert-manager) для обновления сертификатов\n* Обрабатывается внутри облачного провайдера как часть его услуг (см. ниже 👇)\n\nДругой вариант — использовать **облачный сервис**, который возьмёт на себя больше задач, включая настройку HTTPS. Там могут быть ограничения или дополнительная стоимость и т.п., но в таком случае вам не придётся самим настраивать прокси-сервер TSL-терминации.\n\nВ следующих главах я покажу конкретные примеры.\n\n---\n\nДалее рассмотрим концепции, связанные с программой, которая запускает ваш реальный API (например, Uvicorn).\n\n## Программа и процесс { #program-and-process }\n\nМы часто будем говорить о работающем \"**процессе**\", поэтому полезно чётко понимать, что это значит и чем отличается от \"**программы**\".\n\n### Что такое программа { #what-is-a-program }\n\nСловом **программа** обычно называют разные вещи:\n\n* **Код**, который вы пишете, то есть **Python‑файлы**.\n* **Файл**, который может быть **запущен** операционной системой, например: `python`, `python.exe` или `uvicorn`.\n* Конкретную программу в момент, когда она **работает** в операционной системе, используя CPU и память. Это также называют **процессом**.\n\n### Что такое процесс { #what-is-a-process }\n\nСлово **процесс** обычно используют более конкретно — только для того, что реально выполняется в операционной системе (как в последнем пункте выше):\n\n* Конкретная программа в момент, когда она **запущена** в операционной системе.\n    * Речь не о файле и не о коде, а **конкретно** о том, что **исполняется** и управляется операционной системой.\n* Любая программа, любой код **могут что‑то делать** только когда **исполняются**, то есть когда есть **работающий процесс**.\n* Процесс можно **завершить** (или «убить») вами или операционной системой. В этот момент он перестаёт выполняться и **больше ничего делать не может**.\n* У каждого запущенного приложения на вашем компьютере есть свой процесс; у каждой программы, у каждого окна и т.д. Обычно одновременно **работает много процессов**, пока компьютер включён.\n* Могут **одновременно** работать **несколько процессов** одной и той же **программы**.\n\nЕсли вы посмотрите «диспетчер задач» или «системный монитор» (или аналогичные инструменты) в вашей операционной системе, то увидите множество работающих процессов.\n\nНапример, вы, скорее всего, увидите несколько процессов одного и того же браузера (Firefox, Chrome, Edge и т.д.). Обычно браузеры запускают один процесс на вкладку плюс дополнительные процессы.\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\nТеперь, когда мы понимаем разницу между **процессом** и **программой**, продолжим разговор о развёртываниях.\n\n## Запуск при старте { #running-on-startup }\n\nВ большинстве случаев, создавая веб‑API, вы хотите, чтобы он **работал постоянно**, без перерывов, чтобы клиенты всегда могли к нему обратиться. Разве что у вас есть особые причины запускать его только при определённых условиях, но обычно вы хотите, чтобы он был постоянно запущен и **доступен**.\n\n### На удалённом сервере { #in-a-remote-server }\n\nКогда вы настраиваете удалённый сервер (облачный сервер, виртуальную машину и т.п.), самый простой вариант — вручную использовать `fastapi run` (он использует Uvicorn) или что‑то похожее, как вы делаете при локальной разработке.\n\nЭто будет работать и полезно **во время разработки**.\n\nНо если соединение с сервером прервётся, **запущенный процесс**, скорее всего, завершится.\n\nА если сервер перезагрузится (например, после обновлений или миграций у облачного провайдера), вы, вероятно, **даже не заметите этого**. Из‑за этого вы не узнаете, что нужно вручную перезапустить процесс — и ваш API просто будет «мёртв». 😱\n\n### Автоматический запуск при старте { #run-automatically-on-startup }\n\nКак правило, вы захотите, чтобы серверная программа (например, Uvicorn) запускалась автоматически при старте сервера и без **участия человека**, чтобы всегда был процесс, запущенный с вашим API (например, Uvicorn, запускающий ваше приложение FastAPI).\n\n### Отдельная программа { #separate-program }\n\nЧтобы этого добиться, обычно используют **отдельную программу**, которая гарантирует запуск вашего приложения при старте. Во многих случаях она также запускает и другие компоненты/приложения, например базу данных.\n\n### Примеры инструментов для запуска при старте { #example-tools-to-run-at-startup }\n\nПримеры инструментов, которые могут с этим справиться:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker в режиме Swarm (Swarm Mode)\n* Systemd\n* Supervisor\n* Обработка внутри облачного провайдера как часть его услуг\n* Прочие...\n\nБолее конкретные примеры будут в следующих главах.\n\n## Перезапуски { #restarts }\n\nПодобно тому как вы обеспечиваете запуск приложения при старте, вы, вероятно, захотите обеспечить его **перезапуск** после сбоев.\n\n### Мы ошибаемся { #we-make-mistakes }\n\nМы, люди, постоянно совершаем **ошибки**. В программном обеспечении почти всегда есть **баги**, скрытые в разных местах. 🐛\n\nИ мы, как разработчики, продолжаем улучшать код — находим баги и добавляем новые возможности (иногда добавляя новые баги 😅).\n\n### Небольшие ошибки обрабатываются автоматически { #small-errors-automatically-handled }\n\nСоздавая веб‑API с FastAPI, если в нашем коде возникает ошибка, FastAPI обычно «локализует» её в пределах одного запроса, который эту ошибку вызвал. 🛡\n\nКлиент получит **500 Internal Server Error** для этого запроса, но приложение продолжит работать для последующих запросов, а не «упадёт» целиком.\n\n### Большие ошибки — падения { #bigger-errors-crashes }\n\nТем не менее возможны случаи, когда код **роняет всё приложение**, приводя к сбою Uvicorn и Python. 💥\n\nИ вы, скорее всего, не захотите, чтобы приложение оставалось «мёртвым» из‑за ошибки в одном месте — вы захотите, чтобы оно **продолжало работать** хотя бы для *операций пути*, которые не сломаны.\n\n### Перезапуск после падения { #restart-after-crash }\n\nВ случаях действительно серьёзных ошибок, которые роняют работающий **процесс**, вам понадобится внешний компонент, отвечающий за **перезапуск** процесса, как минимум пару раз...\n\n/// tip | Совет\n\n...Хотя если приложение **падает сразу же**, вероятно, нет смысла перезапускать его бесконечно. Но такие случаи вы, скорее всего, заметите во время разработки или как минимум сразу после развёртывания.\n\nДавайте сосредоточимся на основных сценариях, когда в каких‑то конкретных ситуациях **в будущем** приложение может падать целиком, и при этом имеет смысл его перезапускать.\n\n///\n\nСкорее всего, вы захотите, чтобы перезапуском вашего приложения занимался **внешний компонент**, потому что к тому моменту Uvicorn и Python уже упали, и внутри того же кода вашего приложения сделать уже ничего нельзя.\n\n### Примеры инструментов для автоматического перезапуска { #example-tools-to-restart-automatically }\n\nВ большинстве случаев тот же инструмент, который **запускает программу при старте**, умеет обрабатывать и автоматические **перезапуски**.\n\nНапример, это может быть:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker в режиме Swarm (Swarm Mode)\n* Systemd\n* Supervisor\n* Обработка внутри облачного провайдера как часть его услуг\n* Прочие...\n\n## Репликация — процессы и память { #replication-processes-and-memory }\n\nВ приложении FastAPI, используя серверную программу (например, команду `fastapi`, которая запускает Uvicorn), запуск в **одном процессе** уже позволяет обслуживать нескольких клиентов одновременно.\n\nНо во многих случаях вы захотите одновременно запустить несколько процессов‑воркеров.\n\n### Несколько процессов — Воркеры { #multiple-processes-workers }\n\nЕсли клиентов больше, чем способен обслужить один процесс (например, если виртуальная машина не слишком мощная), и на сервере есть **несколько ядер CPU**, вы можете запустить **несколько процессов** одного и того же приложения параллельно и распределять запросы между ними.\n\nКогда вы запускаете **несколько процессов** одной и той же программы API, их обычно называют **воркерами**.\n\n### Процессы‑воркеры и порты { #worker-processes-and-ports }\n\nПомните из раздела [Об HTTPS](https.md), что на сервере только один процесс может слушать конкретную комбинацию порта и IP‑адреса?\n\nЭто по‑прежнему так.\n\nПоэтому, чтобы одновременно работало **несколько процессов**, должен быть **один процесс, слушающий порт**, который затем каким‑то образом передаёт коммуникацию каждому воркер‑процессу.\n\n### Память на процесс { #memory-per-process }\n\nКогда программа загружает что‑то в память (например, модель машинного обучения в переменную или содержимое большого файла в переменную), всё это **потребляет часть памяти (RAM)** сервера.\n\nИ разные процессы обычно **не делят память**. Это значит, что у каждого процесса свои переменные и своя память. Если ваш код потребляет много памяти, то **каждый процесс** будет потреблять сопоставимый объём памяти.\n\n### Память сервера { #server-memory }\n\nНапример, если ваш код загружает модель Машинного обучения размером **1 ГБ**, то при запуске одного процесса с вашим API он будет использовать как минимум 1 ГБ RAM. А если вы запустите **4 процесса** (4 воркера), каждый процесс будет использовать 1 ГБ RAM. Всего ваш API будет потреблять **4 ГБ RAM**.\n\nИ если у вашего удалённого сервера или виртуальной машины только 3 ГБ RAM, попытка загрузить более 4 ГБ вызовет проблемы. 🚨\n\n### Несколько процессов — пример { #multiple-processes-an-example }\n\nВ этом примере есть **процесс‑менеджер**, который запускает и контролирует два **процесса‑воркера**.\n\nПроцесс‑менеджер, вероятно, будет тем, кто слушает **порт** на IP. И он будет передавать всю коммуникацию воркер‑процессам.\n\nЭти воркеры будут запускать ваше приложение, выполнять основные вычисления для получения **HTTP‑запроса** и возврата **HTTP‑ответа**, и загружать всё, что вы кладёте в переменные, в RAM.\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\nКонечно, на той же машине помимо вашего приложения, скорее всего, будут работать и **другие процессы**.\n\nИнтересная деталь: процент **использования CPU** каждым процессом со временем может сильно **меняться**, но **память (RAM)** обычно остаётся более‑менее **стабильной**.\n\nЕсли у вас API, который каждый раз выполняет сопоставимый объём вычислений, и у вас много клиентов, то **загрузка процессора**, вероятно, *тоже будет стабильной* (вместо того, чтобы быстро и постоянно «скакать»).\n\n### Примеры инструментов и стратегий репликации { #examples-of-replication-tools-and-strategies }\n\nЕсть несколько подходов для достижения этого, и я расскажу больше о конкретных стратегиях в следующих главах, например, говоря о Docker и контейнерах.\n\nГлавное ограничение: должен быть **один** компонент, который обрабатывает **порт** на **публичном IP**. И у него должен быть способ **передавать** коммуникацию реплицированным **процессам/воркерам**.\n\nНекоторые возможные комбинации и стратегии:\n\n* **Uvicorn** с `--workers`\n    * Один **процесс‑менеджер** Uvicorn будет слушать **IP** и **порт** и запускать **несколько процессов‑воркеров Uvicorn**.\n* **Kubernetes** и другие распределённые **контейнерные системы**\n    * Некий компонент на уровне **Kubernetes** будет слушать **IP** и **порт**. Репликация достигается с помощью **нескольких контейнеров**, в каждом из которых работает **один процесс Uvicorn**.\n* **Облачные сервисы**, которые берут это на себя\n    * Облачный сервис, скорее всего, **возьмёт репликацию на себя**. Он, возможно, позволит указать **процесс для запуска** или **образ контейнера**. В любом случае это, скорее всего, будет **один процесс Uvicorn**, а сервис займётся его репликацией.\n\n/// tip | Совет\n\nНе беспокойтесь, если некоторые пункты про **контейнеры**, Docker или Kubernetes пока кажутся неочевидными.\n\nЯ расскажу больше про образы контейнеров, Docker, Kubernetes и т.п. в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md).\n\n///\n\n## Предварительные шаги перед запуском { #previous-steps-before-starting }\n\nВо многих случаях вы захотите выполнить некоторые шаги **перед запуском** приложения.\n\nНапример, запустить **миграции базы данных**.\n\nНо чаще всего эти шаги нужно выполнять только **один раз**.\n\nПоэтому вы захотите иметь **один процесс**, который выполнит эти **предварительные шаги**, прежде чем запускать приложение.\n\nИ вам нужно будет убедиться, что это делает один процесс **даже** если потом вы запускаете **несколько процессов** (несколько воркеров) самого приложения. Если эти шаги выполнят **несколько процессов**, они **дублируют** работу, запустив её **параллельно**, и, если речь о чём‑то деликатном (например, миграции БД), это может вызвать конфликты.\n\nКонечно, бывают случаи, когда нет проблем, если предварительные шаги выполняются несколько раз — тогда всё проще.\n\n/// tip | Совет\n\nТакже учтите, что в зависимости от вашей схемы развёртывания в некоторых случаях **предварительные шаги могут вовсе не требоваться**.\n\nТогда об этом можно не беспокоиться. 🤷\n\n///\n\n### Примеры стратегий для предварительных шагов { #examples-of-previous-steps-strategies }\n\nЭто будет **сильно зависеть** от того, как вы **развёртываете систему**, как запускаете программы, обрабатываете перезапуски и т.д.\n\nНекоторые возможные идеи:\n\n* «Init Container» в Kubernetes, который запускается перед контейнером с приложением\n* Bash‑скрипт, который выполняет предварительные шаги, а затем запускает приложение\n    * При этом всё равно нужен способ запускать/перезапускать *этот* bash‑скрипт, обнаруживать ошибки и т.п.\n\n/// tip | Совет\n\nЯ приведу более конкретные примеры с контейнерами в следующей главе: [FastAPI внутри контейнеров — Docker](docker.md).\n\n///\n\n## Использование ресурсов { #resource-utilization }\n\nВаш сервер(а) — это **ресурс**, который ваши программы могут потреблять или **использовать**: время вычислений на CPU и доступную оперативную память (RAM).\n\nКакую долю системных ресурсов вы хотите потреблять/использовать? Можно подумать «немного», но на практике вы, вероятно, захотите потреблять **максимум без падений**.\n\nЕсли вы платите за 3 сервера, но используете лишь малую часть их RAM и CPU, вы, вероятно, **тратите деньги впустую** 💸 и **электроэнергию серверов** 🌎 и т.п.\n\nВ таком случае лучше иметь 2 сервера и использовать более высокий процент их ресурсов (CPU, память, диск, сетевую полосу и т.д.).\n\nС другой стороны, если у вас 2 сервера и вы используете **100% их CPU и RAM**, в какой‑то момент один процесс попросит больше памяти, и сервер начнёт использовать диск как «память» (что в тысячи раз медленнее) или даже **упадёт**. Или процессу понадобятся вычисления, но ему придётся ждать освобождения CPU.\n\nВ таком случае лучше добавить **ещё один сервер** и запустить часть процессов на нём, чтобы у всех было **достаточно RAM и времени CPU**.\n\nТакже возможен **всплеск** использования вашего API: он мог «взорваться» по популярности, или какие‑то сервисы/боты начали его активно использовать. На такие случаи стоит иметь запас ресурсов.\n\nМожно задать **целевое значение**, например **между 50% и 90%** использования ресурсов. Скорее всего, именно эти вещи вы будете измерять и на их основе настраивать развёртывание.\n\nМожно использовать простые инструменты вроде `htop`, чтобы смотреть загрузку CPU и RAM на сервере или по процессам. Или более сложные распределённые системы мониторинга.\n\n## Резюме { #recap }\n\nЗдесь вы прочитали о некоторых основных концепциях, которые, вероятно, стоит учитывать при выборе способа развёртывания приложения:\n\n* Безопасность — HTTPS\n* Запуск при старте\n* Перезапуски\n* Репликация (количество запущенных процессов)\n* Память\n* Предварительные шаги перед запуском\n\nПонимание этих идей и того, как их применять, даст вам интуицию, необходимую для принятия решений при настройке и доработке ваших развёртываний. 🤓\n\nВ следующих разделах я приведу более конкретные примеры возможных стратегий. 🚀\n"
  },
  {
    "path": "docs/ru/docs/deployment/docker.md",
    "content": "# FastAPI в контейнерах — Docker { #fastapi-in-containers-docker }\n\nПри развёртывании приложений FastAPI распространённый подход — собирать **образ контейнера на Linux**. Обычно это делают с помощью [**Docker**](https://www.docker.com/). Затем такой образ контейнера можно развернуть несколькими способами.\n\nИспользование Linux-контейнеров даёт ряд преимуществ: **безопасность**, **воспроизводимость**, **простоту** и другие.\n\n/// tip | Подсказка\n\nНет времени и вы уже знакомы с этим? Перейдите к [`Dockerfile` ниже 👇](#build-a-docker-image-for-fastapi).\n\n///\n\n<details>\n<summary>Предпросмотр Dockerfile 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# Если запускаете за прокси, например Nginx или Traefik, добавьте --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## Что такое контейнер { #what-is-a-container }\n\nКонтейнеры (в основном Linux-контейнеры) — это очень **легковесный** способ упаковать приложения вместе со всеми их зависимостями и необходимыми файлами, изолировав их от других контейнеров (других приложений или компонентов) в той же системе.\n\nLinux-контейнеры запускаются, используя то же ядро Linux хоста (машины, виртуальной машины, облачного сервера и т.п.). Это означает, что они очень легковесные (по сравнению с полноценными виртуальными машинами, эмулирующими целую операционную систему).\n\nТаким образом, контейнеры потребляют **малое количество ресурсов**, сопоставимое с запуском процессов напрямую (виртуальная машина потребовала бы намного больше ресурсов).\n\nУ контейнеров также есть собственные **изолированные** выполняемые процессы (обычно всего один процесс), файловая система и сеть, что упрощает развёртывание, безопасность, разработку и т.д.\n\n## Что такое образ контейнера { #what-is-a-container-image }\n\n**Контейнер** запускается из **образа контейнера**.\n\nОбраз контейнера — это **статическая** версия всех файлов, переменных окружения и команды/программы по умолчанию, которые должны присутствовать в контейнере. Здесь **статическая** означает, что **образ** не запущен, он не выполняется — это только упакованные файлы и метаданные.\n\nВ противоположность «**образу контейнера**» (хранящему статическое содержимое), «**контейнер**» обычно означает запущенный экземпляр, то, что **выполняется**.\n\nКогда **контейнер** запущен (на основе **образа контейнера**), он может создавать или изменять файлы, переменные окружения и т.д.. Эти изменения существуют только внутри контейнера и не сохраняются в исходном образе контейнера (не записываются на диск).\n\nОбраз контейнера можно сравнить с **файлами программы**, например `python` и каким-то файлом `main.py`.\n\nА сам **контейнер** (в отличие от **образа контейнера**) — это фактически запущенный экземпляр образа, сопоставимый с **процессом**. По сути, контейнер работает только тогда, когда в нём есть **запущенный процесс** (и обычно это один процесс). Контейнер останавливается, когда в нём не остаётся запущенных процессов.\n\n## Образы контейнеров { #container-images }\n\nDocker — один из основных инструментов для создания и управления **образами контейнеров** и **контейнерами**.\n\nСуществует публичный [Docker Hub](https://hub.docker.com/) с готовыми **официальными образами** для многих инструментов, окружений, баз данных и приложений.\n\nНапример, есть официальный [образ Python](https://hub.docker.com/_/python).\n\nА также множество образов для разных вещей, например баз данных:\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis), и т.д.\n\nИспользуя готовые образы, очень легко **комбинировать** разные инструменты и использовать их. Например, чтобы попробовать новую базу данных. В большинстве случаев можно воспользоваться **официальными образами** и просто настроить их через переменные окружения.\n\nТаким образом, во многих случаях вы можете изучить контейнеры и Docker и переиспользовать эти знания с множеством различных инструментов и компонентов.\n\nНапример, вы можете запустить **несколько контейнеров**: с базой данных, Python-приложением, веб-сервером с фронтендом на React и связать их через внутреннюю сеть.\n\nВсе системы управления контейнерами (такие как Docker или Kubernetes) имеют интегрированные возможности для такого сетевого взаимодействия.\n\n## Контейнеры и процессы { #containers-and-processes }\n\n**Образ контейнера** обычно включает в свои метаданные программу или команду по умолчанию, которую следует запускать при старте **контейнера**, а также параметры, передаваемые этой программе. Это очень похоже на запуск команды в терминале.\n\nКогда **контейнер** стартует, он выполняет указанную команду/программу (хотя вы можете переопределить это и запустить другую команду/программу).\n\nКонтейнер работает до тех пор, пока работает его **главный процесс** (команда или программа).\n\nОбычно в контейнере есть **один процесс**, но главный процесс может запускать подпроцессы, и тогда в том же контейнере будет **несколько процессов**.\n\nНельзя иметь работающий контейнер без **хотя бы одного запущенного процесса**. Если главный процесс останавливается, контейнер останавливается.\n\n## Создать Docker-образ для FastAPI { #build-a-docker-image-for-fastapi }\n\nИтак, давайте что-нибудь соберём! 🚀\n\nЯ покажу, как собрать **Docker-образ** для FastAPI **с нуля** на основе **официального образа Python**.\n\nИменно так стоит делать в **большинстве случаев**, например:\n\n* При использовании **Kubernetes** или похожих инструментов\n* При запуске на **Raspberry Pi**\n* При использовании облачного сервиса, который запускает для вас образ контейнера и т.п.\n\n### Зависимости пакетов { #package-requirements }\n\nОбычно **зависимости** вашего приложения описаны в каком-то файле.\n\nКонкретный формат зависит в основном от инструмента, которым вы **устанавливаете** эти зависимости.\n\nЧаще всего используется файл `requirements.txt` с именами пакетов и их версиями по одному на строку.\n\nРазумеется, вы будете придерживаться тех же идей, что описаны здесь: [О версиях FastAPI](versions.md), чтобы задать диапазоны версий.\n\nНапример, ваш `requirements.txt` может выглядеть так:\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\nИ обычно вы установите эти зависимости командой `pip`, например:\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info | Информация\n\nСуществуют и другие форматы и инструменты для описания и установки зависимостей.\n\n///\n\n### Создать код **FastAPI** { #create-the-fastapi-code }\n\n* Создайте директорию `app` и перейдите в неё.\n* Создайте пустой файл `__init__.py`.\n* Создайте файл `main.py` со следующим содержимым:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\nТеперь в той же директории проекта создайте файл `Dockerfile`:\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. Начинаем с официального базового образа Python.\n\n2. Устанавливаем текущую рабочую директорию в `/code`.\n\n    Здесь мы разместим файл `requirements.txt` и директорию `app`.\n\n3. Копируем файл с зависимостями в директорию `/code`.\n\n    Сначала копируйте **только** файл с зависимостями, не остальной код.\n\n    Так как этот файл **меняется нечасто**, Docker определит это и использует **кэш** на этом шаге, что позволит использовать кэш и на следующем шаге.\n\n4. Устанавливаем зависимости из файла с требованиями.\n\n    Опция `--no-cache-dir` указывает `pip` не сохранять загруженные пакеты локально, т.к. это нужно только если `pip` будет запускаться снова для установки тех же пакетов, а при работе с контейнерами это обычно не требуется.\n\n    /// note | Заметка\n\n    `--no-cache-dir` относится только к `pip` и не имеет отношения к Docker или контейнерам.\n\n    ///\n\n    Опция `--upgrade` указывает `pip` обновлять пакеты, если они уже установлены.\n\n    Поскольку предыдущий шаг с копированием файла может быть обработан **кэшем Docker**, этот шаг также **использует кэш Docker**, когда это возможно.\n\n    Использование кэша на этом шаге **сэкономит** вам много **времени** при повторных сборках образа во время разработки, вместо того чтобы **загружать и устанавливать** все зависимости **каждый раз**.\n\n5. Копируем директорию `./app` внутрь директории `/code`.\n\n    Так как здесь весь код, который **меняется чаще всего**, кэш Docker **вряд ли** будет использоваться для этого шага или **последующих шагов**.\n\n    Поэтому важно разместить этот шаг **ближе к концу** `Dockerfile`, чтобы оптимизировать время сборки образа контейнера.\n\n6. Указываем **команду** для запуска `fastapi run`, под капотом используется Uvicorn.\n\n    `CMD` принимает список строк, каждая из которых — это то, что вы бы ввели в командной строке, разделяя пробелами.\n\n    Эта команда будет выполнена из **текущей рабочей директории**, той самой `/code`, которую вы задали выше `WORKDIR /code`.\n\n/// tip | Подсказка\n\nПосмотрите, что делает каждая строка, кликнув по номеру рядом со строкой. 👆\n\n///\n\n/// warning | Предупреждение\n\nВсегда используйте **exec-форму** инструкции `CMD`, как описано ниже.\n\n///\n\n#### Используйте `CMD` — exec-форма { #use-cmd-exec-form }\n\nИнструкцию Docker [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) можно писать в двух формах:\n\n✅ **Exec**-форма:\n\n```Dockerfile\n# ✅ Делайте так\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ **Shell**-форма:\n\n```Dockerfile\n# ⛔️ Не делайте так\nCMD fastapi run app/main.py --port 80\n```\n\nОбязательно используйте **exec**-форму, чтобы FastAPI мог корректно завершаться и чтобы срабатывали [события lifespan](../advanced/events.md).\n\nПодробнее об этом читайте в [документации Docker о shell- и exec-формах](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).\n\nЭто особенно заметно при использовании `docker compose`. См. раздел FAQ Docker Compose с техническими подробностями: [Почему мои сервисы пересоздаются или останавливаются 10 секунд?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).\n\n#### Структура директорий { #directory-structure }\n\nТеперь у вас должна быть такая структура:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### За прокси-сервером TSL-терминации { #behind-a-tls-termination-proxy }\n\nЕсли вы запускаете контейнер за прокси-сервером TSL-терминации (балансировщиком нагрузки), таким как Nginx или Traefik, добавьте опцию `--proxy-headers`. Это сообщит Uvicorn (через FastAPI CLI), что приложение работает за HTTPS и можно доверять соответствующим заголовкам.\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Кэш Docker { #docker-cache }\n\nВ этом `Dockerfile` есть важная хитрость: мы сначала копируем **только файл с зависимостями**, а не весь код. Вот зачем.\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker и подобные инструменты **строят** образы контейнеров **инкрементально**, добавляя **слой за слоем**, начиная с первой строки `Dockerfile` и добавляя любые файлы, создаваемые каждой инструкцией `Dockerfile`.\n\nDocker и подобные инструменты также используют **внутренний кэш** при сборке образа: если файл не изменился с момента предыдущей сборки, будет **переиспользован слой**, созданный в прошлый раз, вместо повторного копирования файла и создания нового слоя с нуля.\n\nСамо по себе избегание копирования всех файлов не всегда даёт много, но благодаря использованию кэша на этом шаге Docker сможет **использовать кэш и на следующем шаге**. Например, на шаге установки зависимостей:\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\nФайл с зависимостями **меняется нечасто**. Поэтому, копируя только его, Docker сможет **использовать кэш** для этого шага.\n\nА затем Docker сможет **использовать кэш и на следующем шаге**, где скачиваются и устанавливаются зависимости. Здесь мы как раз **экономим много времени**. ✨ ...и не скучаем в ожидании. 😪😆\n\nСкачивание и установка зависимостей **может занять минуты**, но использование **кэша** — **секунды**.\n\nПоскольку во время разработки вы будете пересобирать образ снова и снова, чтобы проверить изменения в коде, суммарно это сэкономит немало времени.\n\nЗатем, ближе к концу `Dockerfile`, мы копируем весь код. Так как он **меняется чаще всего**, мы ставим этот шаг в конец, потому что почти всегда всё, что после него, уже не сможет использовать кэш.\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### Собрать Docker-образ { #build-the-docker-image }\n\nТеперь, когда все файлы на месте, соберём образ контейнера.\n\n* Перейдите в директорию проекта (где ваш `Dockerfile` и директория `app`).\n* Соберите образ FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | Подсказка\n\nОбратите внимание на точку `.` в конце — это то же самое, что `./`. Так мы указываем Docker, из какой директории собирать образ контейнера.\n\nВ данном случае это текущая директория (`.`).\n\n///\n\n### Запустить Docker-контейнер { #start-the-docker-container }\n\n* Запустите контейнер на основе вашего образа:\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## Проверка { #check-it }\n\nПроверьте работу по адресу вашего Docker-хоста, например: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) или [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (или аналогичный URL вашего Docker-хоста).\n\nВы увидите что-то вроде:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## Интерактивная документация API { #interactive-api-docs }\n\nТеперь зайдите на [http://192.168.99.100/docs](http://192.168.99.100/docs) или [http://127.0.0.1/docs](http://127.0.0.1/docs) (или аналогичный URL вашего Docker-хоста).\n\nВы увидите автоматическую интерактивную документацию API (на базе [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## Альтернативная документация API { #alternative-api-docs }\n\nТакже можно открыть [http://192.168.99.100/redoc](http://192.168.99.100/redoc) или [http://127.0.0.1/redoc](http://127.0.0.1/redoc) (или аналогичный URL вашего Docker-хоста).\n\nВы увидите альтернативную автоматическую документацию (на базе [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Собрать Docker-образ для однофайлового FastAPI { #build-a-docker-image-with-a-single-file-fastapi }\n\nЕсли ваше приложение FastAPI — один файл, например `main.py` без директории `./app`, структура файлов может быть такой:\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\nТогда в `Dockerfile` нужно изменить пути копирования:\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. Копируем файл `main.py` напрямую в `/code` (без директории `./app`).\n\n2. Используем `fastapi run` для запуска приложения из одного файла `main.py`.\n\nКогда вы передаёте файл в `fastapi run`, он автоматически определит, что это одиночный файл, а не часть пакета, и поймёт, как его импортировать и запустить ваше FastAPI-приложение. 😎\n\n## Концепции развертывания { #deployment-concepts }\n\nЕщё раз рассмотрим [концепции развертывания](concepts.md) применительно к контейнерам.\n\nКонтейнеры главным образом упрощают **сборку и развёртывание** приложения, но не навязывают конкретный подход к этим **концепциям развертывания**, и существует несколько стратегий.\n\n**Хорошая новость** в том, что при любой стратегии есть способ охватить все концепции развертывания. 🎉\n\nРассмотрим эти **концепции развертывания** в терминах контейнеров:\n\n* HTTPS\n* Запуск при старте\n* Перезапуски\n* Репликация (количество запущенных процессов)\n* Память\n* Предварительные шаги перед запуском\n\n## HTTPS { #https }\n\nЕсли мы рассматриваем только **образ контейнера** для приложения FastAPI (и далее запущенный **контейнер**), то HTTPS обычно обрабатывается **внешним** инструментом.\n\nЭто может быть другой контейнер, например с [Traefik](https://traefik.io/), который берёт на себя **HTTPS** и **автоматическое** получение **сертификатов**.\n\n/// tip | Подсказка\n\nУ Traefik есть интеграции с Docker, Kubernetes и другими, поэтому очень легко настроить и сконфигурировать HTTPS для ваших контейнеров.\n\n///\n\nВ качестве альтернативы HTTPS может быть реализован как сервис облачного провайдера (при этом приложение всё равно работает в контейнере).\n\n## Запуск при старте и перезапуски { #running-on-startup-and-restarts }\n\nОбычно есть другой инструмент, отвечающий за **запуск и работу** вашего контейнера.\n\nЭто может быть сам **Docker**, **Docker Compose**, **Kubernetes**, **облачный сервис** и т.п.\n\nВ большинстве (или во всех) случаев есть простая опция, чтобы включить запуск контейнера при старте системы и перезапуски при сбоях. Например, в Docker это опция командной строки `--restart`.\n\nБез контейнеров обеспечить запуск при старте и перезапуски может быть сложно. Но при **работе с контейнерами** в большинстве случаев этот функционал доступен по умолчанию. ✨\n\n## Репликация — количество процессов { #replication-number-of-processes }\n\nЕсли у вас есть <dfn title=\"Группа машин, настроенных так, чтобы быть соединенными и работать вместе определенным образом.\">кластер</dfn> машин с **Kubernetes**, Docker Swarm Mode, Nomad или другой похожей системой для управления распределёнными контейнерами на нескольких машинах, скорее всего вы будете **управлять репликацией** на **уровне кластера**, а не использовать **менеджер процессов** (например, Uvicorn с воркерами) в каждом контейнере.\n\nОдна из таких систем управления распределёнными контейнерами, как Kubernetes, обычно имеет встроенный способ управлять **репликацией контейнеров**, поддерживая **балансировку нагрузки** для входящих запросов — всё это на **уровне кластера**.\n\nВ таких случаях вы, скорее всего, захотите собрать **Docker-образ с нуля**, как [описано выше](#dockerfile), установить зависимости и запускать **один процесс Uvicorn** вместо множества воркеров Uvicorn.\n\n### Балансировщик нагрузки { #load-balancer }\n\nПри использовании контейнеров обычно есть компонент, **слушающий главный порт**. Это может быть другой контейнер — **прокси-сервер TSL-терминации** для обработки **HTTPS** или похожий инструмент.\n\nПоскольку этот компонент принимает **нагрузку** запросов и распределяет её между воркерами **сбалансированно**, его часто называют **балансировщиком нагрузки**.\n\n/// tip | Подсказка\n\nТот же компонент **прокси-сервер TSL-терминации**, который обрабатывает HTTPS, скорее всего также будет **балансировщиком нагрузки**.\n\n///\n\nПри работе с контейнерами система, которую вы используете для запуска и управления ими, уже имеет внутренние средства для передачи **сетевого взаимодействия** (например, HTTP-запросов) от **балансировщика нагрузки** (который также может быть **прокси-сервером TSL-терминации**) к контейнеру(-ам) с вашим приложением.\n\n### Один балансировщик — несколько контейнеров-воркеров { #one-load-balancer-multiple-worker-containers }\n\nПри работе с **Kubernetes** или похожими системами управления распределёнными контейнерами их внутренние механизмы сети позволяют одному **балансировщику нагрузки**, слушающему главный **порт**, передавать запросы в **несколько контейнеров**, где запущено ваше приложение.\n\nКаждый такой контейнер с вашим приложением обычно имеет **только один процесс** (например, процесс Uvicorn с вашим приложением FastAPI). Все они — **одинаковые контейнеры**, запускающие одно и то же, но у каждого свой процесс, память и т.п. Так вы используете **параллелизм** по **разным ядрам** CPU или даже **разным машинам**.\n\nСистема распределённых контейнеров с **балансировщиком нагрузки** будет **распределять запросы** между контейнерами с вашим приложением **по очереди**. То есть каждый запрос может обрабатываться одним из нескольких **реплицированных контейнеров**.\n\nОбычно такой **балансировщик нагрузки** может также обрабатывать запросы к *другим* приложениям в вашем кластере (например, к другому домену или под другим префиксом пути URL) и направлять их к нужным контейнерам этого *другого* приложения.\n\n### Один процесс на контейнер { #one-process-per-container }\n\nВ таком сценарии, скорее всего, вы захотите иметь **один (Uvicorn) процесс на контейнер**, так как репликация уже управляется на уровне кластера.\n\nПоэтому в контейнере **не нужно** поднимать несколько воркеров, например через опцию командной строки `--workers`. Нужен **один процесс Uvicorn** на контейнер (но, возможно, несколько контейнеров).\n\nНаличие отдельного менеджера процессов внутри контейнера (как при нескольких воркерах) только добавит **лишнюю сложность**, которую, вероятно, уже берёт на себя ваша кластерная система.\n\n### Контейнеры с несколькими процессами и особые случаи { #containers-with-multiple-processes-and-special-cases }\n\nКонечно, есть **особые случаи**, когда может понадобиться **контейнер** с несколькими **воркерами Uvicorn** внутри.\n\nВ таких случаях вы можете использовать опцию командной строки `--workers`, чтобы указать нужное количество воркеров:\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. Здесь мы используем опцию `--workers`, чтобы установить число воркеров равным 4.\n\nПримеры, когда это может быть уместно:\n\n#### Простое приложение { #a-simple-app }\n\nВам может понадобиться менеджер процессов в контейнере, если приложение **достаточно простое**, чтобы запускаться на **одном сервере**, а не в кластере.\n\n#### Docker Compose { #docker-compose }\n\nВы можете развёртывать на **одном сервере** (не кластере) с **Docker Compose**, и у вас не будет простого способа управлять репликацией контейнеров (в Docker Compose), сохраняя общую сеть и **балансировку нагрузки**.\n\nТогда вы можете захотеть **один контейнер** с **менеджером процессов**, который запускает **несколько воркеров** внутри.\n\n---\n\nГлавное — **ни одно** из этих правил не является **строго обязательным**. Используйте эти идеи, чтобы **оценить свой конкретный случай** и решить, какой подход лучше для вашей системы, учитывая:\n\n* Безопасность — HTTPS\n* Запуск при старте\n* Перезапуски\n* Репликацию (количество запущенных процессов)\n* Память\n* Предварительные шаги перед запуском\n\n## Память { #memory }\n\nЕсли вы запускаете **один процесс на контейнер**, у каждого контейнера будет более-менее чётко определённый, стабильный и ограниченный объём потребляемой памяти (контейнеров может быть несколько при репликации).\n\nЗатем вы можете задать такие же лимиты и требования по памяти в конфигурации вашей системы управления контейнерами (например, в **Kubernetes**). Так система сможет **реплицировать контейнеры** на **доступных машинах**, учитывая объём необходимой памяти и доступной памяти в машинах кластера.\n\nЕсли приложение **простое**, это, вероятно, **не будет проблемой**, и жёсткие лимиты памяти можно не указывать. Но если вы **используете много памяти** (например, с моделями **Машинного обучения**), проверьте, сколько памяти потребляется, и отрегулируйте **число контейнеров** на **каждой машине** (и, возможно, добавьте машины в кластер).\n\nЕсли вы запускаете **несколько процессов в контейнере**, нужно убедиться, что их суммарное потребление **не превысит доступную память**.\n\n## Предварительные шаги перед запуском и контейнеры { #previous-steps-before-starting-and-containers }\n\nЕсли вы используете контейнеры (например, Docker, Kubernetes), есть два основных подхода.\n\n### Несколько контейнеров { #multiple-containers }\n\nЕсли у вас **несколько контейнеров**, и, вероятно, каждый запускает **один процесс** (например, в кластере **Kubernetes**), то вы, скорее всего, захотите иметь **отдельный контейнер**, выполняющий **предварительные шаги** в одном контейнере и одном процессе **до** запуска реплицированных контейнеров-воркеров.\n\n/// info | Информация\n\nЕсли вы используете Kubernetes, это, вероятно, будет [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).\n\n///\n\nЕсли в вашем случае нет проблемы с тем, чтобы выполнять эти предварительные шаги **многократно и параллельно** (например, вы не запускаете миграции БД, а только проверяете готовность БД), вы можете просто выполнить их в каждом контейнере прямо перед стартом основного процесса.\n\n### Один контейнер { #single-container }\n\nЕсли у вас простая схема с **одним контейнером**, который затем запускает несколько **воркеров** (или один процесс), можно выполнить подготовительные шаги в этом же контейнере непосредственно перед запуском процесса с приложением.\n\n### Базовый Docker-образ { #base-docker-image }\n\nРанее существовал официальный Docker-образ FastAPI: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). Сейчас он помечен как устаревший. ⛔️\n\nСкорее всего, вам **не стоит** использовать этот базовый образ (или какой-либо аналогичный).\n\nЕсли вы используете **Kubernetes** (или другое) и уже настраиваете **репликацию** на уровне кластера через несколько **контейнеров**, в этих случаях лучше **собрать образ с нуля**, как описано выше: [Создать Docker-образ для FastAPI](#build-a-docker-image-for-fastapi).\n\nА если вам нужны несколько воркеров, просто используйте опцию командной строки `--workers`.\n\n/// note | Технические подробности\n\nЭтот Docker-образ был создан в то время, когда Uvicorn не умел управлять и перезапускать «упавших» воркеров, и приходилось использовать Gunicorn вместе с Uvicorn, что добавляло заметную сложность, лишь бы Gunicorn управлял и перезапускал воркеров Uvicorn.\n\nНо теперь, когда Uvicorn (и команда `fastapi`) поддерживают `--workers`, нет причин использовать базовый Docker-образ вместо сборки своего (кода получается примерно столько же 😅).\n\n///\n\n## Развёртывание образа контейнера { #deploy-the-container-image }\n\nПосле того как у вас есть образ контейнера (Docker), его можно развёртывать несколькими способами.\n\nНапример:\n\n* С **Docker Compose** на одном сервере\n* В кластере **Kubernetes**\n* В кластере Docker Swarm Mode\n* С другим инструментом, например Nomad\n* С облачным сервисом, который принимает ваш образ контейнера и разворачивает его\n\n## Docker-образ с `uv` { #docker-image-with-uv }\n\nЕсли вы используете [uv](https://github.com/astral-sh/uv) для установки и управления проектом, следуйте их [руководству по Docker для uv](https://docs.astral.sh/uv/guides/integration/docker/).\n\n## Резюме { #recap }\n\nИспользуя системы контейнеризации (например, **Docker** и **Kubernetes**), довольно просто закрыть все **концепции развертывания**:\n\n* HTTPS\n* Запуск при старте\n* Перезапуски\n* Репликация (количество запущенных процессов)\n* Память\n* Предварительные шаги перед запуском\n\nВ большинстве случаев вы, вероятно, не захотите использовать какой-либо базовый образ, а вместо этого **соберёте образ контейнера с нуля** на основе официального Docker-образа Python.\n\nЗаботясь о **порядке**  инструкций в `Dockerfile` и используя **кэш Docker**, вы можете **минимизировать время сборки**, чтобы повысить продуктивность (и не скучать). 😎\n"
  },
  {
    "path": "docs/ru/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\nВы можете развернуть своё приложение FastAPI в [FastAPI Cloud](https://fastapicloud.com) одной командой, присоединяйтесь к списку ожидания, если ещё не сделали этого. 🚀\n\n## Вход { #login }\n\nУбедитесь, что у вас уже есть аккаунт **FastAPI Cloud** (мы пригласили вас из списка ожидания 😉).\n\nЗатем выполните вход:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## Деплой { #deploy }\n\nТеперь разверните приложение одной командой:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nВот и всё! Теперь вы можете открыть своё приложение по этому URL. ✨\n\n## О FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** создан тем же автором и командой, что и **FastAPI**.\n\nОн упрощает процесс **создания образа**, **развертывания** и **доступа** к API с минимальными усилиями.\n\nОн переносит тот же **опыт разработчика**, что вы получаете при создании приложений на FastAPI, на их **развертывание** в облаке. 🎉\n\nОн также возьмёт на себя большинство вещей, которые требуются при развертывании приложения, например:\n\n* HTTPS\n* Репликация с автоматическим масштабированием на основе запросов\n* и т.д.\n\nFastAPI Cloud — основной спонсор и источник финансирования open source‑проектов «FastAPI и друзья». ✨\n\n## Развертывание у других облачных провайдеров { #deploy-to-other-cloud-providers }\n\nFastAPI — проект с открытым исходным кодом и основан на стандартах. Вы можете развернуть приложения FastAPI у любого облачного провайдера на ваш выбор.\n\nСледуйте руководствам вашего облачного провайдера, чтобы развернуть приложения FastAPI у них. 🤓\n\n## Развертывание на собственном сервере { #deploy-your-own-server }\n\nПозже в этом руководстве по **развертыванию** я также расскажу все детали — чтобы вы понимали, что происходит, что нужно сделать и как развернуть приложения FastAPI самостоятельно, в том числе на собственных серверах. 🤓\n"
  },
  {
    "path": "docs/ru/docs/deployment/https.md",
    "content": "# Об HTTPS { #about-https }\n\nЛегко предположить, что HTTPS — это что-то, что просто «включено» или нет.\n\nНо на самом деле всё гораздо сложнее.\n\n/// tip | Совет\n\nЕсли вы торопитесь или вам это не важно, переходите к следующим разделам с пошаговыми инструкциями по настройке всего разными способами.\n\n///\n\nЧтобы **изучить основы HTTPS** с точки зрения пользователя, загляните на [https://howhttps.works/](https://howhttps.works/).\n\nТеперь, со стороны **разработчика**, вот несколько вещей, которые стоит держать в голове, размышляя об HTTPS:\n\n* Для HTTPS **серверу** нужно **иметь «сертификаты»**, сгенерированные  **третьей стороной**.\n    * Эти сертификаты на самом деле **приобретаются** у третьей стороны, а не «генерируются».\n* У сертификатов есть **срок действия**.\n    * Они **истекают**.\n    * После этого их нужно **обновлять**, то есть **получать заново** у третьей стороны.\n* Шифрование соединения происходит на **уровне TCP**.\n    * Это на один уровень **ниже HTTP**.\n    * Поэтому **сертификаты и шифрование** обрабатываются **до HTTP**.\n* **TCP не знает о «доменах»**. Только об IP-адресах.\n    * Информация о **конкретном домене** передаётся в **данных HTTP**.\n* **HTTPS-сертификаты** «сертифицируют» **определённый домен**, но протокол и шифрование происходят на уровне TCP, **до того как** становится известен домен, с которым идёт работа.\n* **По умолчанию** это означает, что вы можете иметь **лишь один HTTPS-сертификат на один IP-адрес**.\n    * Неважно, насколько мощный у вас сервер или насколько маленькие приложения на нём работают.\n    * Однако у этого есть **решение**.\n* Есть **расширение** протокола **TLS** (того самого, что занимается шифрованием на уровне TCP, до HTTP) под названием **[<abbr title=\"Server Name Indication - Указание имени сервера\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**.\n    * Это расширение SNI позволяет одному серверу (с **одним IP-адресом**) иметь **несколько HTTPS-сертификатов** и обслуживать **несколько HTTPS-доменов/приложений**.\n    * Чтобы это работало, **один** компонент (программа), запущенный на сервере и слушающий **публичный IP-адрес**, должен иметь **все HTTPS-сертификаты** на этом сервере.\n* **После** установления защищённого соединения, протокол обмена данными — **всё ещё HTTP**.\n    * Содержимое **зашифровано**, несмотря на то, что оно отправляется по **протоколу HTTP**.\n\nОбычно на сервере (машине, хосте и т.п.) запускают **одну программу/HTTP‑сервер**, которая **управляет всей частью, связанной с HTTPS**: принимает **зашифрованные HTTPS-запросы**, отправляет **расшифрованные HTTP-запросы** в само HTTP‑приложение, работающее на том же сервере (в нашем случае это приложение **FastAPI**), получает **HTTP-ответ** от приложения, **шифрует его** с использованием подходящего **HTTPS‑сертификата** и отправляет клиенту по **HTTPS**. Такой сервер часто называют **[прокси‑сервером TLS-терминации](https://en.wikipedia.org/wiki/TLS_termination_proxy)**.\n\nНекоторые варианты, которые вы можете использовать как прокси‑сервер TLS-терминации:\n\n* Traefik (умеет обновлять сертификаты)\n* Caddy (умеет обновлять сертификаты)\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\nДо появления Let's Encrypt эти **HTTPS-сертификаты** продавались доверенными третьими сторонами.\n\nПроцесс получения таких сертификатов был неудобным, требовал бумажной волокиты, а сами сертификаты были довольно дорогими.\n\nЗатем появился **[Let's Encrypt](https://letsencrypt.org/)**.\n\nЭто проект Linux Foundation. Он предоставляет **HTTPS‑сертификаты бесплатно**, в автоматическом режиме. Эти сертификаты используют стандартные криптографические механизмы и имеют короткий срок действия (около 3 месяцев), поэтому **безопасность фактически выше** благодаря уменьшенному сроку жизни.\n\nДомены безопасно проверяются, а сертификаты выдаются автоматически. Это также позволяет автоматизировать процесс их продления.\n\nИдея — автоматизировать получение и продление сертификатов, чтобы у вас был **безопасный HTTPS, бесплатно и навсегда**.\n\n## HTTPS для разработчиков { #https-for-developers }\n\nНиже приведён пример того, как может выглядеть HTTPS‑API, шаг за шагом, с акцентом на идеях, важных для разработчиков.\n\n### Имя домена { #domain-name }\n\nЧаще всего всё начинается с **приобретения** **имени домена**. Затем вы настраиваете его на DNS‑сервере (возможно, у того же облачного провайдера).\n\nСкорее всего, вы получите облачный сервер (виртуальную машину) или что-то подобное, и у него будет <dfn title=\"Со временем не меняется. Не динамический.\">постоянный</dfn> **публичный IP-адрес**.\n\nНа DNS‑сервере(ах) вы настроите запись («`A record`» - запись типа A), указывающую, что **ваш домен** должен указывать на публичный **IP‑адрес вашего сервера**.\n\nОбычно это делается один раз — при первоначальной настройке всего.\n\n/// tip | Совет\n\nЧасть про доменное имя относится к этапам задолго до HTTPS, но так как всё зависит от домена и IP‑адреса, здесь стоит это упомянуть.\n\n///\n\n### DNS { #dns }\n\nТеперь сфокусируемся на собственно частях, связанных с HTTPS.\n\nСначала браузер спросит у **DNS‑серверов**, какой **IP соответствует домену**, в нашем примере `someapp.example.com`.\n\nDNS‑серверы ответят браузеру, какой **конкретный IP‑адрес** использовать. Это будет публичный IP‑адрес вашего сервера, который вы указали в настройках DNS.\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### Начало TLS-рукопожатия { #tls-handshake-start }\n\nДалее браузер будет общаться с этим IP‑адресом на **порту 443** (порт HTTPS).\n\nПервая часть взаимодействия — установить соединение между клиентом и сервером и договориться о криптографических ключах и т.п.\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\nЭто взаимодействие клиента и сервера для установления TLS‑соединения называется **TLS‑рукопожатием**.\n\n### TLS с расширением SNI { #tls-with-sni-extension }\n\nНа сервере **только один процесс** может слушать конкретный **порт** на конкретном **IP‑адресе**. Могут быть другие процессы, слушающие другие порты на том же IP‑адресе, но не более одного процесса на каждую комбинацию IP‑адреса и порта.\n\nПо умолчанию TLS (HTTPS) использует порт `443`. Значит, он нам и нужен.\n\nТак как только один процесс может слушать этот порт, делать это будет **прокси‑сервер TLS-терминации**.\n\nУ прокси‑сервера TLS-терминации будет доступ к одному или нескольким **TLS‑сертификатам** (HTTPS‑сертификатам).\n\nИспользуя **расширение SNI**, упомянутое выше, прокси‑сервер TLS-терминации определит, какой из доступных TLS (HTTPS)‑сертификатов нужно использовать для этого соединения, выбрав тот, который соответствует домену, ожидаемому клиентом.\n\nВ нашем случае это будет сертификат для `someapp.example.com`.\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\nКлиент уже **доверяет** организации, выдавшей этот TLS‑сертификат (в нашем случае — Let's Encrypt, но об этом позже), поэтому может **проверить**, что сертификат действителен.\n\nЗатем, используя сертификат, клиент и прокси‑сервер TLS-терминации **договариваются о способе шифрования** остальной **TCP‑коммуникации**. На этом **TLS‑рукопожатие** завершено.\n\nПосле этого у клиента и сервера есть **зашифрованное TCP‑соединение** — это и предоставляет TLS. И они могут использовать это соединение, чтобы начать собственно **HTTP‑обмен**.\n\nСобственно, **HTTPS** — это обычный **HTTP** внутри **защищённого TLS‑соединения**, вместо чистого (незашифрованного) TCP‑соединения.\n\n/// tip | Совет\n\nОбратите внимание, что шифрование обмена происходит на **уровне TCP**, а не на уровне HTTP.\n\n///\n\n### HTTPS‑запрос { #https-request }\n\nТеперь, когда у клиента и сервера (конкретно у браузера и прокси‑сервера TLS-терминации) есть **зашифрованное TCP‑соединение**, они могут начать **HTTP‑обмен**.\n\nКлиент отправляет **HTTPS‑запрос**. Это обычный HTTP‑запрос через зашифрованное TLS‑соединение.\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### Расшифровка запроса { #decrypt-the-request }\n\nПрокси‑сервер TLS-терминации использует согласованное шифрование, чтобы **расшифровать запрос**, и передаёт **обычный (расшифрованный) HTTP‑запрос** процессу, запускающему приложение (например, процессу с Uvicorn, который запускает приложение FastAPI).\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### HTTP‑ответ { #http-response }\n\nПриложение обработает запрос и отправит **обычный (незашифрованный) HTTP‑ответ** прокси‑серверу TLS-терминации.\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### HTTPS‑ответ { #https-response }\n\nЗатем прокси‑сервер TLS-терминации **зашифрует ответ** с использованием ранее согласованного способа шифрования (который начали использовать для сертификата для `someapp.example.com`) и отправит его обратно в браузер.\n\nДалее браузер проверит, что ответ корректен и зашифрован правильным криптографическим ключом и т.п., затем **расшифрует ответ** и обработает его.\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\nКлиент (браузер) узнает, что ответ пришёл от правильного сервера, потому что используется способ шифрования, о котором они договорились ранее с помощью **HTTPS‑сертификата**.\n\n### Несколько приложений { #multiple-applications }\n\nНа одном и том же сервере (или серверах) могут работать **несколько приложений**, например другие программы с API или база данных.\n\nТолько один процесс может обрабатывать конкретную комбинацию IP и порта (в нашем примере — прокси‑сервер TLS-терминации), но остальные приложения/процессы тоже могут работать на сервере(ах), пока они не пытаются использовать ту же **комбинацию публичного IP и порта**.\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\nТаким образом, прокси‑сервер TLS-терминации может обрабатывать HTTPS и сертификаты для **нескольких доменов** (для нескольких приложений), а затем передавать запросы нужному приложению в каждом случае.\n\n### Продление сертификата { #certificate-renewal }\n\nСо временем каждый сертификат **истечёт** (примерно через 3 месяца после получения).\n\nЗатем будет другая программа (иногда это отдельная программа, иногда — тот же прокси‑сервер TLS-терминации), которая свяжется с Let's Encrypt и продлит сертификат(ы).\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\n**TLS‑сертификаты** **связаны с именем домена**, а не с IP‑адресом.\n\nПоэтому, чтобы продлить сертификаты, программа продления должна **доказать** удостоверяющему центру (Let's Encrypt), что она действительно **«владеет» и контролирует этот домен**.\n\nДля этого, учитывая разные потребности приложений, есть несколько способов. Популярные из них:\n\n* **Изменить некоторые DNS‑записи**.\n    * Для этого программа продления должна поддерживать API DNS‑провайдера, поэтому, в зависимости от используемого провайдера DNS, этот вариант может быть доступен или нет.\n* **Запуститься как сервер** (как минимум на время получения сертификатов) на публичном IP‑адресе, связанном с доменом.\n    * Как сказано выше, только один процесс может слушать конкретный IP и порт.\n    * Это одна из причин, почему очень удобно, когда тот же прокси‑сервер TLS-терминации также занимается процессом продления сертификатов.\n    * В противном случае вам, возможно, придётся временно остановить прокси‑сервер TLS-терминации, запустить программу продления для получения сертификатов, затем настроить их в прокси‑сервере TLS-терминации и перезапустить его. Это не идеально, так как ваше приложение(я) будут недоступны, пока прокси‑сервер TLS-терминации остановлен.\n\nВесь этот процесс продления, совмещённый с обслуживанием приложения, — одна из главных причин иметь **отдельную систему для работы с HTTPS** в виде прокси‑сервера TLS-терминации, вместо использования TLS‑сертификатов напрямую в сервере приложения (например, Uvicorn).\n\n## Пересылаемые HTTP-заголовки прокси { #proxy-forwarded-headers }\n\nКогда вы используете прокси для обработки HTTPS, ваш **сервер приложения** (например, Uvicorn через FastAPI CLI) ничего не знает о процессе HTTPS, он общается обычным HTTP с **прокси‑сервером TLS-терминации**.\n\nОбычно этот **прокси** на лету добавляет некоторые HTTP‑заголовки перед тем, как переслать запрос на **сервер приложения**, чтобы тот знал, что запрос был **проксирован**.\n\n/// note | Технические детали\n\nЗаголовки прокси:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\nТем не менее, так как **сервер приложения** не знает, что он находится за доверенным **прокси**, по умолчанию он не будет доверять этим заголовкам.\n\nНо вы можете настроить **сервер приложения**, чтобы он доверял *пересылаемым* заголовкам, отправленным **прокси**. Если вы используете FastAPI CLI, вы можете использовать *опцию CLI* `--forwarded-allow-ips`, чтобы указать, с каких IP‑адресов следует доверять этим *пересылаемым* заголовкам.\n\nНапример, если **сервер приложения** получает запросы только от доверенного **прокси**, вы можете установить `--forwarded-allow-ips=\"*\"`, чтобы доверять всем входящим IP, так как он всё равно будет получать запросы только с IP‑адреса, используемого **прокси**.\n\nТаким образом, приложение сможет знать свой публичный URL, использует ли оно HTTPS, какой домен и т.п.\n\nЭто будет полезно, например, для корректной обработки редиректов.\n\n/// tip | Совет\n\nПодробнее об этом вы можете узнать в документации: [За прокси — Включить пересылаемые заголовки прокси](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)\n\n///\n\n## Резюме { #recap }\n\nНаличие **HTTPS** очень важно и во многих случаях довольно **критично**. Большая часть усилий, которые вам, как разработчику, нужно приложить вокруг HTTPS, — это просто **понимание этих концепций** и того, как они работают.\n\nЗная базовую информацию о **HTTPS для разработчиков**, вы сможете легко комбинировать и настраивать разные инструменты, чтобы управлять всем этим простым способом.\n\nВ некоторых из следующих глав я покажу вам несколько конкретных примеров настройки **HTTPS** для приложений **FastAPI**. 🔒\n"
  },
  {
    "path": "docs/ru/docs/deployment/index.md",
    "content": "# Развёртывание { #deployment }\n\nРазвернуть приложение **FastAPI** довольно просто.\n\n## Что означает развёртывание { #what-does-deployment-mean }\n\nТермин **развёртывание** (приложения) означает выполнение необходимых шагов, чтобы сделать приложение **доступным для пользователей**.\n\nДля **веб-API** это обычно означает размещение его на **удалённой машине** с **серверной программой**, обеспечивающей хорошую производительность, стабильность и т.д., чтобы ваши **пользователи** могли **получать доступ** к приложению эффективно и без перебоев или проблем.\n\nЭто отличается от этапов **разработки**, когда вы постоянно меняете код, ломаете его и исправляете, останавливаете и перезапускаете сервер разработки и т.д.\n\n## Стратегии развёртывания { #deployment-strategies }\n\nЕсть несколько способов сделать это, в зависимости от вашего конкретного случая и используемых вами инструментов.\n\nВы можете **развернуть сервер** самостоятельно, используя различные инструменты. Например, можно использовать **облачный сервис**, который выполнит часть работы за вас. Также возможны и другие варианты.\n\nНапример, мы, команда, стоящая за FastAPI, создали [**FastAPI Cloud**](https://fastapicloud.com), чтобы сделать развёртывание приложений FastAPI в облаке как можно более простым и прямолинейным, с тем же удобством для разработчика, что и при работе с FastAPI.\n\nЯ покажу вам некоторые из основных концепций, которые вы, вероятно, должны иметь в виду при развертывании приложения **FastAPI** (хотя большинство из них применимо к любому другому типу веб-приложений).\n\nВ последующих разделах вы узнаете больше деталей и методов, необходимых для этого. ✨\n"
  },
  {
    "path": "docs/ru/docs/deployment/manually.md",
    "content": "# Запуск сервера вручную { #run-a-server-manually }\n\n## Используйте команду `fastapi run` { #use-the-fastapi-run-command }\n\nКоротко: используйте `fastapi run`, чтобы запустить ваше приложение FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\nВ большинстве случаев этого достаточно. 😎\n\nЭтой командой, например, можно запускать приложение **FastAPI** в контейнере, на сервере и т.д.\n\n## ASGI‑серверы { #asgi-servers }\n\nДавайте немного углубимся в детали.\n\nFastAPI использует стандарт для построения Python‑веб‑фреймворков и серверов под названием <abbr title=\"Asynchronous Server Gateway Interface – Асинхронный шлюзовый интерфейс сервера\">ASGI</abbr>. FastAPI — ASGI-веб‑фреймворк.\n\nГлавное, что вам нужно, чтобы запустить приложение **FastAPI** (или любое другое ASGI‑приложение) на удалённой серверной машине, — это программа ASGI‑сервера, такая как **Uvicorn**; именно он используется по умолчанию в команде `fastapi`.\n\nЕсть несколько альтернатив, например:\n\n* [Uvicorn](https://www.uvicorn.dev/): высокопроизводительный ASGI‑сервер.\n* [Hypercorn](https://hypercorn.readthedocs.io/): ASGI‑сервер, среди прочего совместимый с HTTP/2 и Trio.\n* [Daphne](https://github.com/django/daphne): ASGI‑сервер, созданный для Django Channels.\n* [Granian](https://github.com/emmett-framework/granian): HTTP‑сервер на Rust для Python‑приложений.\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit — лёгкая и многофункциональная среда выполнения веб‑приложений.\n\n## Сервер как машина и сервер как программа { #server-machine-and-server-program }\n\nЕсть небольшой нюанс в терминологии, о котором стоит помнить. 💡\n\nСлово «сервер» обычно используют и для обозначения удалённого/облачного компьютера (физической или виртуальной машины), и для программы, работающей на этой машине (например, Uvicorn).\n\nИмейте в виду, что слово «сервер» в целом может означать любое из этих двух.\n\nКогда речь идёт об удалённой машине, её зачастую называют **сервер**, а также **машина**, **VM** (виртуальная машина), **нода**. Всё это — варианты названия удалённой машины, обычно под управлением Linux, на которой вы запускаете программы.\n\n## Установка серверной программы { #install-the-server-program }\n\nПри установке FastAPI он поставляется с продакшн‑сервером Uvicorn, и вы можете запустить его командой `fastapi run`.\n\nНо вы также можете установить ASGI‑сервер вручную.\n\nСоздайте [виртуальное окружение](../virtual-environments.md), активируйте его и затем установите серверное приложение.\n\nНапример, чтобы установить Uvicorn:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\nАналогично устанавливаются и другие ASGI‑серверы.\n\n/// tip | Совет\n\nС добавлением `standard` Uvicorn установит и будет использовать ряд рекомендованных дополнительных зависимостей.\n\nВ их числе `uvloop` — высокопроизводительная замена `asyncio`, дающая серьёзный прирост производительности при параллельной работе.\n\nЕсли вы устанавливаете FastAPI, например так: `pip install \"fastapi[standard]\"`, вы уже получаете и `uvicorn[standard]`.\n\n///\n\n## Запуск серверной программы { #run-the-server-program }\n\nЕсли вы установили ASGI‑сервер вручную, обычно нужно передать строку импорта в специальном формате, чтобы он смог импортировать ваше приложение FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note | Примечание\n\nКоманда `uvicorn main:app` означает:\n\n* `main`: файл `main.py` (Python‑«модуль»).\n* `app`: объект, созданный в `main.py` строкой `app = FastAPI()`.\n\nЭквивалентно:\n\n```Python\nfrom main import app\n```\n\n///\n\nУ каждого альтернативного ASGI‑сервера будет похожая команда; подробнее см. в их документации.\n\n/// warning | Предупреждение\n\nUvicorn и другие серверы поддерживают опцию `--reload`, полезную в период разработки.\n\nОпция `--reload` потребляет значительно больше ресурсов, менее стабильна и т.п.\n\nОна сильно помогает во время **разработки**, но в **продакшн** её использовать **не следует**.\n\n///\n\n## Концепции развёртывания { #deployment-concepts }\n\nВ этих примерах серверная программа (например, Uvicorn) запускает **один процесс**, слушающий все IP‑адреса (`0.0.0.0`) на заранее заданном порту (например, `80`).\n\nЭто базовая идея. Но, вероятно, вам понадобится позаботиться и о некоторых дополнительных вещах, например:\n\n* Безопасность — HTTPS\n* Запуск при старте системы\n* Перезапуски\n* Репликация (количество запущенных процессов)\n* Память\n* Предварительные шаги перед запуском\n\nВ следующих главах я расскажу подробнее про каждую из этих концепций, о том, как о них думать, и приведу конкретные примеры со стратегиями, как с ними работать. 🚀\n"
  },
  {
    "path": "docs/ru/docs/deployment/server-workers.md",
    "content": "# Серверные воркеры — Uvicorn с воркерами { #server-workers-uvicorn-with-workers }\n\nДавайте снова вспомним те концепции деплоя, о которых говорили ранее:\n\n* Безопасность — HTTPS\n* Запуск при старте\n* Перезапуски\n* **Репликация (количество запущенных процессов)**\n* Память\n* Предварительные шаги перед запуском\n\nДо этого момента, следуя руководствам в документации, вы, вероятно, запускали **серверную программу**, например с помощью команды `fastapi`, которая запускает Uvicorn в **одном процессе**.\n\nПри деплое приложения вам, скорее всего, захочется использовать **репликацию процессов**, чтобы задействовать **несколько ядер** и иметь возможность обрабатывать больше запросов.\n\nКак вы видели в предыдущей главе о [Концепциях деплоя](concepts.md), существует несколько стратегий.\n\nЗдесь я покажу, как использовать **Uvicorn** с **воркер-процессами** через команду `fastapi` или напрямую через команду `uvicorn`.\n\n/// info | Информация\n\nЕсли вы используете контейнеры, например Docker или Kubernetes, я расскажу об этом подробнее в следующей главе: [FastAPI в контейнерах — Docker](docker.md).\n\nВ частности, при запуске в **Kubernetes** вам, скорее всего, **не** понадобится использовать воркеры — вместо этого запускайте **один процесс Uvicorn на контейнер**, но об этом подробнее далее в той главе.\n\n///\n\n## Несколько воркеров { #multiple-workers }\n\nМожно запустить несколько воркеров с помощью опции командной строки `--workers`:\n\n//// tab | `fastapi`\n\nЕсли вы используете команду `fastapi`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\nЕсли вы предпочитаете использовать команду `uvicorn` напрямую:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\nЕдинственная новая опция здесь — `--workers`, она говорит Uvicorn запустить 4 воркер-процесса.\n\nТакже видно, что выводится **PID** каждого процесса: `27365` — для родительского процесса (это **менеджер процессов**) и по одному для каждого воркер-процесса: `27368`, `27369`, `27370` и `27367`.\n\n## Концепции деплоя { #deployment-concepts }\n\nЗдесь вы увидели, как использовать несколько **воркеров**, чтобы **распараллелить** выполнение приложения, задействовать **несколько ядер** CPU и обслуживать **больше запросов**.\n\nИз списка концепций деплоя выше использование воркеров в основном помогает с **репликацией**, и немного — с **перезапусками**, но об остальных по-прежнему нужно позаботиться:\n\n* **Безопасность — HTTPS**\n* **Запуск при старте**\n* ***Перезапуски***\n* Репликация (количество запущенных процессов)\n* **Память**\n* **Предварительные шаги перед запуском**\n\n## Контейнеры и Docker { #containers-and-docker }\n\nВ следующей главе о [FastAPI в контейнерах — Docker](docker.md) я объясню стратегии, которые можно использовать для решения остальных **концепций деплоя**.\n\nЯ покажу, как **собрать свой образ с нуля**, чтобы запускать один процесс Uvicorn. Это простой подход и, вероятно, именно то, что вам нужно при использовании распределённой системы управления контейнерами, такой как **Kubernetes**.\n\n## Резюме { #recap }\n\nВы можете использовать несколько воркер-процессов с опцией командной строки `--workers` в командах `fastapi` или `uvicorn`, чтобы задействовать **многоядерные CPU**, запуская **несколько процессов параллельно**.\n\nВы можете использовать эти инструменты и идеи, если настраиваете **собственную систему деплоя** и самостоятельно закрываете остальные концепции деплоя.\n\nПерейдите к следующей главе, чтобы узнать о **FastAPI** в контейнерах (например, Docker и Kubernetes). Вы увидите, что эти инструменты тоже предлагают простые способы решить другие **концепции деплоя**. ✨\n"
  },
  {
    "path": "docs/ru/docs/deployment/versions.md",
    "content": "# О версиях FastAPI { #about-fastapi-versions }\n\n**FastAPI** уже используется в продакшн во многих приложениях и системах. Покрытие тестами поддерживается на уровне 100%. Но его разработка всё ещё движется быстрыми темпами.\n\nЧасто добавляются новые функции, регулярно исправляются баги, код продолжает постоянно совершенствоваться.\n\nПо указанным причинам текущие версии до сих пор `0.x.x`. Это говорит о том, что каждая версия может содержать обратно несовместимые изменения, следуя [Семантическому версионированию](https://semver.org/).\n\nУже сейчас вы можете создавать приложения в продакшн, используя **FastAPI** (и скорее всего так и делаете), главное убедиться в том, что вы используете версию, которая корректно работает с вашим кодом.\n\n## Закрепите вашу версию `fastapi` { #pin-your-fastapi-version }\n\nПервым делом вам следует \"закрепить\" конкретную последнюю используемую версию **FastAPI**, которая корректно работает с вашим приложением.\n\nНапример, в своём приложении вы используете версию `0.112.0`.\n\nЕсли вы используете файл `requirements.txt`, вы можете указать версию следующим способом:\n\n```txt\nfastapi[standard]==0.112.0\n```\n\nэто означает, что вы будете использовать именно версию `0.112.0`.\n\nИли вы можете закрепить версию следующим способом:\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\nэто значит, что вы используете версии `0.112.0` или выше, но меньше чем `0.113.0`. Например, версия `0.112.2` всё ещё будет подходить.\n\nЕсли вы используете любой другой инструмент для управления установками/зависимостями, например `uv`, Poetry, Pipenv или др., у них у всех имеется способ определения специфической версии для ваших пакетов.\n\n## Доступные версии { #available-versions }\n\nВы можете посмотреть доступные версии (например, проверить последнюю на данный момент) в [Примечаниях к выпуску](../release-notes.md).\n\n## О версиях { #about-versions }\n\nСледуя соглашению о Семантическом Версионировании, любые версии ниже `1.0.0` потенциально могут добавить обратно несовместимые изменения.\n\nFastAPI следует соглашению в том, что любые изменения \"ПАТЧ\"-версии предназначены для исправления багов и внесения обратно совместимых изменений.\n\n/// tip | Подсказка\n\n\"ПАТЧ\" — это последнее число. Например, в `0.2.3`, ПАТЧ-версия — это `3`.\n\n///\n\nИтак, вы можете закрепить версию следующим образом:\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\nОбратно несовместимые изменения и новые функции добавляются в \"МИНОРНЫЕ\" версии.\n\n/// tip | Подсказка\n\n\"МИНОРНАЯ\" версия — это число в середине. Например, в `0.2.3` МИНОРНАЯ версия — это `2`.\n\n///\n\n## Обновление версий FastAPI { #upgrading-the-fastapi-versions }\n\nВам следует добавить тесты для вашего приложения.\n\nС помощью **FastAPI** это очень просто (благодаря Starlette), см. документацию: [Тестирование](../tutorial/testing.md)\n\nПосле создания тестов вы можете обновить свою версию **FastAPI** до более новой. После этого следует убедиться, что ваш код работает корректно, запустив тесты.\n\nЕсли всё работает корректно, или после внесения необходимых изменений все ваши тесты проходят, только тогда вы можете закрепить вашу новую версию `fastapi`.\n\n## О Starlette { #about-starlette }\n\nНе следует закреплять версию `starlette`.\n\nРазные версии **FastAPI** будут использовать более новые версии Starlette.\n\nТак что решение об используемой версии Starlette, вы можете оставить **FastAPI**.\n\n## О Pydantic { #about-pydantic }\n\nPydantic включает свои собственные тесты для **FastAPI**, так что новые версии Pydantic (выше `1.0.0`) всегда совместимы с FastAPI.\n\nВы можете закрепить любую версию Pydantic, которая вам подходит, выше `1.0.0`.\n\nНапример:\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/ru/docs/editor-support.md",
    "content": "# Поддержка редактора кода { #editor-support }\n\nОфициальное [расширение FastAPI](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) улучшает ваш процесс разработки на FastAPI за счет обнаружения и навигации по *операциям пути* (обработчикам пути), а также развертывания в FastAPI Cloud и потоковой передачи логов в реальном времени.\n\nПодробности о расширении смотрите в README в [репозитории GitHub](https://github.com/fastapi/fastapi-vscode).\n\n## Установка и настройка { #setup-and-installation }\n\n**Расширение FastAPI** доступно как для [VS Code](https://code.visualstudio.com/), так и для [Cursor](https://www.cursor.com/). Его можно установить напрямую из панели расширений в каждом редакторе кода, выполнив поиск по «FastAPI» и выбрав расширение от **FastAPI Labs**. Расширение также работает в браузерных редакторах кода, таких как [vscode.dev](https://vscode.dev) и [github.dev](https://github.dev).\n\n### Обнаружение приложения { #application-discovery }\n\nПо умолчанию расширение автоматически обнаруживает приложения FastAPI в вашем рабочем пространстве, сканируя файлы, где создается экземпляр `FastAPI()`. Если авто-обнаружение не подходит для структуры вашего проекта, вы можете указать точку входа через `[tool.fastapi]` в `pyproject.toml` или настройку VS Code `fastapi.entryPoint`, используя модульную нотацию (например, `myapp.main:app`).\n\n## Возможности { #features }\n\n- **Обозреватель операций пути** — древовидное представление на боковой панели всех <dfn title=\"маршруты, конечные точки\">*операций пути*</dfn> вашего приложения. Нажмите, чтобы перейти к любому маршруту или определению роутера.\n- **Поиск маршрутов** — поиск по пути, методу или имени с помощью <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (на macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>).\n- **Навигация CodeLens** — кликабельные ссылки над вызовами тестового клиента (например, `client.get('/items')`), которые переходят к соответствующей *операции пути* для быстрой навигации между тестами и реализацией.\n- **Развернуть в FastAPI Cloud** — развертывание вашего приложения в один клик в [FastAPI Cloud](https://fastapicloud.com/).\n- **Поток логов приложения** — потоковая передача логов в реальном времени из вашего приложения, развернутого в FastAPI Cloud, с фильтрацией по уровню и текстовым поиском.\n\nЕсли вы хотите поверхностно ознакомиться с возможностями расширения, откройте палитру команд (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> или на macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>), выберите «Welcome: Open walkthrough...», а затем «Get started with FastAPI».\n"
  },
  {
    "path": "docs/ru/docs/environment-variables.md",
    "content": "# Переменные окружения { #environment-variables }\n\n/// tip | Совет\n\nЕсли вы уже знаете, что такое «переменные окружения» и как их использовать, можете пропустить это.\n\n///\n\nПеременная окружения (также известная как «**env var**») - это переменная, которая живет **вне** кода Python, в **операционной системе**, и может быть прочитана вашим кодом Python (или другими программами).\n\nПеременные окружения могут быть полезны для работы с **настройками** приложений, как часть **установки** Python и т.д.\n\n## Создание и использование переменных окружения { #create-and-use-env-vars }\n\nМожно **создавать** и использовать переменные окружения в **оболочке (терминале)**, не прибегая к помощи Python:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Вы можете создать переменную окружения MY_NAME с помощью\n$ export MY_NAME=\"Wade Wilson\"\n\n// Затем её можно использовать в других программах, например\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Создайте переменную окружения MY_NAME\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Используйте её с другими программами, например\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## Чтение переменных окружения в python { #read-env-vars-in-python }\n\nТак же существует возможность создания переменных окружения **вне** Python, в терминале (или любым другим способом), а затем **чтения их в Python**.\n\nНапример, у вас есть файл `main.py`:\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip | Совет\n\nВторой аргумент [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) - это возвращаемое по умолчанию значение.\n\nЕсли значение не указано, то по умолчанию оно равно `None`. В данном случае мы указываем `«World»` в качестве значения по умолчанию.\n\n///\n\nЗатем можно запустить эту программу на Python:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Здесь мы еще не устанавливаем переменную окружения\n$ python main.py\n\n// Поскольку мы не задали переменную окружения, мы получим значение по умолчанию\n\nHello World from Python\n\n// Но если мы сначала создадим переменную окружения\n$ export MY_NAME=\"Wade Wilson\"\n\n// А затем снова запустим программу\n$ python main.py\n\n// Теперь она прочитает переменную окружения\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Здесь мы еще не устанавливаем переменную окружения\n$ python main.py\n\n// Поскольку мы не задали переменную окружения, мы получим значение по умолчанию\n\nHello World from Python\n\n// Но если мы сначала создадим переменную окружения\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// А затем снова запустим программу\n$ python main.py\n\n// Теперь она может прочитать переменную окружения\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\nПоскольку переменные окружения могут быть установлены вне кода, но могут быть прочитаны кодом, и их не нужно хранить (фиксировать в `git`) вместе с остальными файлами, их принято использовать для конфигураций или **настроек**.\n\nВы также можете создать переменную окружения только для **конкретного вызова программы**, которая будет доступна только для этой программы и только на время ее выполнения.\n\nДля этого создайте её непосредственно перед самой программой, в той же строке:\n\n<div class=\"termy\">\n\n```console\n// Создайте переменную окружения MY_NAME в строке для этого вызова программы\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// Теперь она может прочитать переменную окружения\n\nHello Wade Wilson from Python\n\n// После этого переменная окружения больше не существует\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip | Совет\n\nПодробнее об этом можно прочитать на сайте [The Twelve-Factor App: Config](https://12factor.net/config).\n\n///\n\n## Типизация и Валидация { #types-and-validation }\n\nЭти переменные окружения могут работать только с **текстовыми строками**, поскольку они являются внешними по отношению к Python и должны быть совместимы с другими программами и остальной системой (и даже с различными операционными системами, такими как Linux, Windows, macOS).\n\nЭто означает, что **любое значение**, считанное в Python из переменной окружения, **будет `str`**, и любое преобразование к другому типу или любая валидация должны быть выполнены в коде.\n\nПодробнее об использовании переменных окружения для работы с **настройками приложения** вы узнаете в [Расширенное руководство пользователя - Настройки и переменные среды](./advanced/settings.md).\n\n## Переменная окружения `PATH` { #path-environment-variable }\n\nСуществует **специальная** переменная окружения **`PATH`**, которая используется операционными системами (Linux, macOS, Windows) для поиска программ для запуска.\n\nЗначение переменной `PATH` - это длинная строка, состоящая из каталогов, разделенных двоеточием `:` в Linux и macOS, и точкой с запятой `;` в Windows.\n\nНапример, переменная окружения `PATH` может выглядеть следующим образом:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nЭто означает, что система должна искать программы в каталогах:\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\nЭто означает, что система должна искать программы в каталогах:\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\nКогда вы вводите **команду** в терминале, операционная система **ищет** программу в **каждой из тех директорий**, которые перечислены в переменной окружения `PATH`.\n\nНапример, когда вы вводите `python` в терминале, операционная система ищет программу под названием `python` в **первой директории** в этом списке.\n\nЕсли она ее находит, то **использует ее**. В противном случае она продолжает искать в **других каталогах**.\n\n### Установка Python и обновление `PATH` { #installing-python-and-updating-the-path }\n\nПри установке Python вас могут спросить, нужно ли обновить переменную окружения `PATH`.\n\n//// tab | Linux, macOS\n\nДопустим, вы устанавливаете Python, и он оказывается в каталоге `/opt/custompython/bin`.\n\nЕсли вы скажете «да», чтобы обновить переменную окружения `PATH`, то программа установки добавит `/opt/custompython/bin` в переменную окружения `PATH`.\n\nЭто может выглядеть следующим образом:\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\nТаким образом, когда вы набираете `python` в терминале, система найдет программу Python в `/opt/custompython/bin` (последний каталог) и использует ее.\n\n////\n\n//// tab | Windows\n\nДопустим, вы устанавливаете Python, и он оказывается в каталоге `C:\\opt\\custompython\\bin`.\n\nЕсли вы согласитесь обновить переменную окружения `PATH`, то программа установки добавит `C:\\opt\\custompython\\bin` в переменную окружения `PATH`.\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\nТаким образом, когда вы набираете `python` в терминале, система найдет программу Python в `C:\\opt\\custompython\\bin` (последний каталог) и использует ее.\n\n////\n\nИтак, если вы напечатаете:\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\nСистема **найдет** программу `python` в `/opt/custompython/bin` и запустит ее.\n\nЭто примерно эквивалентно набору текста:\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\nСистема **найдет** программу `python` в каталоге `C:\\opt\\custompython\\bin\\python` и запустит ее.\n\nЭто примерно эквивалентно набору текста:\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\nЭта информация будет полезна при изучении [Виртуальных окружений](virtual-environments.md).\n\n## Вывод { #conclusion }\n\nБлагодаря этому вы должны иметь базовое представление о том, что такое **переменные окружения** и как использовать их в Python.\n\nПодробнее о них вы также можете прочитать в [статье о переменных окружения на википедии](https://en.wikipedia.org/wiki/Environment_variable).\n\nВо многих случаях не всегда очевидно, как переменные окружения могут быть полезны и применимы. Но они постоянно появляются в различных сценариях разработки, поэтому знать о них полезно.\n\nНапример, эта информация понадобится вам в следующем разделе, посвященном [Виртуальным окружениям](virtual-environments.md).\n"
  },
  {
    "path": "docs/ru/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - интерфейс командной строки\">CLI</abbr>** - это программа командной строки, которую вы можете использовать, чтобы предоставлять доступ к вашему приложению FastAPI, управлять проектом FastAPI и т.д.\n\nПри установке FastAPI (например, с помощью `pip install \"fastapi[standard]\"`) вместе с ним устанавливается программа командной строки, которую можно запускать в терминале.\n\nЧтобы запустить ваше приложение FastAPI в режиме разработки, используйте команду `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip | Подсказка\n\nВ продакшн вы будете использовать `fastapi run` вместо `fastapi dev`. 🚀\n\n///\n\nВнутри **FastAPI CLI** используется [Uvicorn](https://www.uvicorn.dev), высокопроизводительный, готовый к работе в продакшн ASGI-сервер. 😎\n\nИнструмент командной строки `fastapi` попытается автоматически обнаружить приложение FastAPI для запуска, предполагая, что это объект с именем `app` в файле `main.py` (или в некоторых других вариантах).\n\nНо вы можете явно указать, какое приложение использовать.\n\n## Настройте `entrypoint` приложения в `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nВы можете настроить, где находится ваше приложение, в файле `pyproject.toml`, например так:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nЭтот `entrypoint` сообщит команде `fastapi`, что приложение нужно импортировать так:\n\n```python\nfrom main import app\n```\n\nЕсли ваш код организован так:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nТогда следует указать `entrypoint` так:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nчто будет эквивалентно:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` с указанием пути { #fastapi-dev-with-path }\n\nВы также можете передать путь к файлу команде `fastapi dev`, и она постарается определить объект приложения FastAPI:\n\n```console\n$ fastapi dev main.py\n```\n\nНо тогда вам придется каждый раз не забывать передавать правильный путь при вызове команды `fastapi`.\n\nКроме того, другие инструменты могут не найти его, например [Расширение VS Code](editor-support.md) или [FastAPI Cloud](https://fastapicloud.com), поэтому рекомендуется использовать `entrypoint` в `pyproject.toml`.\n\n## `fastapi dev` { #fastapi-dev }\n\nВызов `fastapi dev` запускает режим разработки.\n\nПо умолчанию включена авто-перезагрузка (**auto-reload**), благодаря этому при изменении кода происходит перезагрузка сервера приложения. Эта установка требует значительных ресурсов и делает систему менее стабильной. Используйте её только при разработке. Приложение слушает входящие подключения на IP `127.0.0.1`. Это IP адрес вашей машины, предназначенный для внутренних коммуникаций (`localhost`).\n\n## `fastapi run` { #fastapi-run }\n\nВызов `fastapi run` по умолчанию запускает FastAPI в режиме продакшн.\n\nПо умолчанию авто-перезагрузка (**auto-reload**) отключена. Приложение слушает входящие подключения на IP `0.0.0.0`, т.е. на всех доступных адресах компьютера. Таким образом, приложение будет находиться в публичном доступе для любого, кто может подсоединиться к вашей машине. Продуктовые приложения запускаются именно так, например, с помощью контейнеров.\n\nВ большинстве случаев вы будете (и должны) использовать прокси-сервер (\"termination proxy\"), который будет поддерживать HTTPS поверх вашего приложения. Всё будет зависеть от того, как вы развертываете приложение: за вас это либо сделает ваш провайдер, либо вам придется сделать настройки самостоятельно.\n\n/// tip | Подсказка\n\nВы можете больше узнать об этом в [документации по развертыванию](deployment/index.md).\n\n///\n"
  },
  {
    "path": "docs/ru/docs/features.md",
    "content": "# Возможности { #features }\n\n## Возможности FastAPI { #fastapi-features }\n\n**FastAPI** предлагает вам следующее:\n\n### Основано на открытых стандартах { #based-on-open-standards }\n\n* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) для создания API, включая объявления <dfn title=\"также известны как HTTP-методы, например: POST, GET, PUT, DELETE\">операций</dfn> <dfn title=\"также известен как: эндпоинты, маршруты\">пути</dfn>, параметров, тел запросов, безопасности и т.д.\n* Автоматическая документация моделей данных с помощью [**JSON Schema**](https://json-schema.org/) (так как сама спецификация OpenAPI основана на JSON Schema).\n* Разработан вокруг этих стандартов, после тщательного их изучения. Это не дополнительная надстройка поверх.\n* Это также позволяет использовать автоматическую **генерацию клиентского кода** на многих языках.\n\n### Автоматическая документация { #automatic-docs }\n\nИнтерактивная документация для API и исследовательские веб-интерфейсы. Поскольку фреймворк основан на OpenAPI, существует несколько вариантов документирования, 2 из них включены по умолчанию.\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui), с интерактивным исследованием, вызовом и тестированием вашего API прямо из браузера.\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Альтернативная документация API в [**ReDoc**](https://github.com/Rebilly/ReDoc).\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Только современный Python { #just-modern-python }\n\nВсе основано на стандартных **аннотациях типов Python** (благодаря Pydantic). Не нужно изучать новый синтаксис. Только стандартный современный Python.\n\nЕсли вам нужно освежить знания о типах в Python (даже если вы не используете FastAPI), выделите 2 минуты и просмотрите краткое руководство: [Типы Python](python-types.md).\n\nВы пишете стандартный Python с типами:\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# Объявляем параметр как `str`\n# и получаем поддержку редактора кода внутри функции\ndef main(user_id: str):\n    return user_id\n\n\n# Модель Pydantic\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\nЭто можно использовать так:\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n/// info | Информация\n\n`**second_user_data` означает:\n\nПередать ключи и значения словаря `second_user_data` в качестве аргументов \"ключ-значение\", эквивалентно: `User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### Поддержка редакторов (IDE) { #editor-support }\n\nВесь фреймворк был продуман так, чтобы быть простым и интуитивно понятным в использовании, все решения были проверены на множестве редакторов еще до начала разработки, чтобы обеспечить наилучшие условия при написании кода.\n\nВ опросах Python‑разработчиков видно, [что одной из самых часто используемых функций является «автозавершение»](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).\n\nВся структура **FastAPI** основана на удовлетворении этой возможности. Автозавершение работает везде.\n\nВам редко нужно будет возвращаться к документации.\n\nВот как ваш редактор может вам помочь:\n\n* в [Visual Studio Code](https://code.visualstudio.com/):\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* в [PyCharm](https://www.jetbrains.com/pycharm/):\n\n![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\nВы будете получать автозавершение кода даже там, где вы считали это невозможным раньше. Как пример, ключ `price` внутри тела JSON (который может быть вложенным), приходящего в запросе.\n\nБольше никаких неправильных имён ключей, метания по документации или прокручивания кода вверх и вниз в попытках узнать — использовали вы ранее `username` или `user_name`.\n\n### Краткость { #short }\n\nFastAPI имеет продуманные значения **по умолчанию** для всего, с опциональными настройками везде. Все параметры могут быть тонко подстроены так, чтобы делать то, что вам нужно, и определять необходимый вам API.\n\nНо по умолчанию всё **«просто работает»**.\n\n### Проверка значений { #validation }\n\n* Проверка значений для большинства (или всех?) **типов данных** Python, включая:\n    * Объекты JSON (`dict`).\n    * Массив JSON (`list`) с определёнными типами элементов.\n    * Строковые (`str`) поля с ограничением минимальной и максимальной длины.\n    * Числа (`int`, `float`) с минимальными и максимальными значениями и т.п.\n\n* Проверка для более экзотических типов, таких как:\n    * URL.\n    * Email.\n    * UUID.\n    * ...и другие.\n\nВсе проверки обрабатываются хорошо зарекомендовавшим себя и надёжным **Pydantic**.\n\n### Безопасность и аутентификация { #security-and-authentication }\n\nВстроенные функции безопасности и аутентификации. Без каких‑либо компромиссов с базами данных или моделями данных.\n\nВсе схемы безопасности, определённые в OpenAPI, включая:\n\n* HTTP Basic.\n* **OAuth2** (также с **токенами JWT**). Ознакомьтесь с руководством [OAuth2 с JWT](tutorial/security/oauth2-jwt.md).\n* Ключи API в:\n    * HTTP-заголовках.\n    * Параметрах запросов.\n    * Cookies и т.п.\n\nВдобавок все функции безопасности от Starlette (включая **сессионные cookies**).\n\nВсе инструменты и компоненты спроектированы для многократного использования и легко интегрируются с вашими системами, хранилищами данных, реляционными и NoSQL базами данных и т.д.\n\n### Внедрение зависимостей { #dependency-injection }\n\nFastAPI включает в себя чрезвычайно простую в использовании, но чрезвычайно мощную систему <dfn title='также известна как: \"компоненты\", \"ресурсы\", \"сервисы\", \"провайдеры\"'><strong>Внедрения зависимостей</strong></dfn>.\n\n* Даже зависимости могут иметь зависимости, создавая иерархию или **«граф» зависимостей**.\n* Всё **автоматически обрабатывается** фреймворком.\n* Все зависимости могут запрашивать данные из запросов и **дополнять операции пути** ограничениями и автоматической документацией.\n* **Автоматическая проверка** даже для параметров *операций пути*, определённых в зависимостях.\n* Поддержка сложных систем аутентификации пользователей, **соединений с базами данных** и т.д.\n* **Никаких компромиссов** с базами данных, интерфейсами и т.д. Но при этом — лёгкая интеграция со всеми ними.\n\n### Нет ограничений на \"Плагины\" { #unlimited-plug-ins }\n\nИли, другими словами, нет необходимости в них — просто импортируйте и используйте нужный вам код.\n\nЛюбая интеграция разработана настолько простой в использовании (с зависимостями), что вы можете создать «плагин» для своего приложения в пару строк кода, используя ту же структуру и синтаксис, что и для ваших *операций пути*.\n\n### Проверен { #tested }\n\n* 100% <dfn title=\"Количество автоматически проверяемого кода\">покрытие тестами</dfn>.\n* 100% <dfn title=\"Аннотации типов Python, благодаря которым ваш редактор кода и внешние инструменты могут обеспечить вам лучшую поддержку\">аннотирование типов</dfn> в кодовой базе.\n* Используется в продакшн‑приложениях.\n\n## Возможности Starlette { #starlette-features }\n\n**FastAPI** основан на [**Starlette**](https://www.starlette.dev/) и полностью совместим с ним. Так что любой дополнительный код Starlette, который у вас есть, также будет работать.\n\nНа самом деле, `FastAPI` — это подкласс `Starlette`. Таким образом, если вы уже знаете или используете Starlette, большая часть функционала будет работать так же.\n\nС **FastAPI** вы получаете все возможности **Starlette** (так как FastAPI — это всего лишь Starlette на стероидах):\n\n* Серьёзно впечатляющая производительность. Это [один из самых быстрых фреймворков на Python, наравне с **NodeJS** и **Go**](https://github.com/encode/starlette#performance).\n* Поддержка **WebSocket**.\n* Фоновые задачи в том же процессе.\n* События запуска и выключения.\n* Тестовый клиент построен на HTTPX.\n* **CORS**, GZip, статические файлы, потоковые ответы.\n* Поддержка **сессий и cookie**.\n* 100% покрытие тестами.\n* 100% аннотирование типов в кодовой базе.\n\n## Возможности Pydantic { #pydantic-features }\n\n**FastAPI** полностью совместим с (и основан на) [**Pydantic**](https://docs.pydantic.dev/). Поэтому любой дополнительный код Pydantic, который у вас есть, также будет работать.\n\nВключая внешние библиотеки, также основанные на Pydantic, такие как <abbr title=\"Object-Relational Mapper - объектно-реляционный маппер\">ORM</abbr>’ы, <abbr title=\"Object-Document Mapper - объектно-документный маппер\">ODM</abbr>’ы для баз данных.\n\nЭто также означает, что во многих случаях вы можете передавать тот же объект, который получили из запроса, **непосредственно в базу данных**, так как всё проверяется автоматически.\n\nИ наоборот, во многих случаях вы можете просто передать объект, полученный из базы данных, **непосредственно клиенту**.\n\nС **FastAPI** вы получаете все возможности **Pydantic** (так как FastAPI основан на Pydantic для обработки данных):\n\n* **Никакой нервотрёпки**:\n    * Не нужно изучать новые схемы в микроязыках.\n    * Если вы знаете типы в Python, вы знаете, как использовать Pydantic.\n* Прекрасно сочетается с вашим **<abbr title=\"Integrated Development Environment - Интегрированная среда разработки: похоже на редактор кода\">IDE</abbr>/<dfn title=\"Программа, которая проверяет код на ошибки\">линтер</dfn>/мозгом**:\n    * Потому что структуры данных pydantic — это всего лишь экземпляры классов, определённых вами; автозавершение, проверка кода, mypy и ваша интуиция — всё будет работать с вашими валидированными данными.\n* Валидация **сложных структур**:\n    * Использование иерархических моделей Pydantic; `List`, `Dict` и т.п. из модуля `typing` (входит в стандартную библиотеку Python).\n    * Валидаторы позволяют чётко и легко определять, проверять и документировать сложные схемы данных в виде JSON Schema.\n    * У вас могут быть глубоко **вложенные объекты JSON**, и все они будут проверены и аннотированы.\n* **Расширяемость**:\n    * Pydantic позволяет определять пользовательские типы данных или расширять проверку методами модели с помощью декораторов валидаторов.\n* 100% покрытие тестами.\n"
  },
  {
    "path": "docs/ru/docs/help-fastapi.md",
    "content": "# Помочь FastAPI - Получить помощь { #help-fastapi-get-help }\n\nНравится ли Вам **FastAPI**?\n\nХотели бы Вы помочь FastAPI, другим пользователям и автору?\n\nИли Вы хотите получить помощь по **FastAPI**?\n\nЕсть несколько очень простых способов помочь (иногда достаточно всего лишь одного-двух кликов).\n\nИ также есть несколько способов получить помощь.\n\n## Подписаться на новостную рассылку { #subscribe-to-the-newsletter }\n\nВы можете подписаться на редкую [новостную рассылку **FastAPI и его друзья**](newsletter.md) и быть в курсе о:\n\n* Новостях о FastAPI и его друзьях 🚀\n* Руководствах 📝\n* Возможностях ✨\n* Ломающих изменениях 🚨\n* Подсказках и хитростях ✅\n\n## Подписаться на FastAPI в X (Twitter) { #follow-fastapi-on-x-twitter }\n\n[Подписаться на @fastapi в **X (Twitter)**](https://x.com/fastapi) для получения наисвежайших новостей о **FastAPI**. 🐦\n\n## Добавить **FastAPI** звезду на GitHub { #star-fastapi-in-github }\n\nВы можете добавить FastAPI \"звезду\" на GitHub (кликнув на кнопку звезды в правом верхнем углу): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). ⭐️\n\nЧем больше звёзд, тем легче другим пользователям найти проект и увидеть, что он уже оказался полезным для многих.\n\n## Отслеживать свежие выпуски в репозитории на GitHub { #watch-the-github-repository-for-releases }\n\nВы можете \"отслеживать\" FastAPI на GitHub (кликнув по кнопке \"watch\" наверху справа): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nТам же Вы можете выбрать \"Releases only\".\n\nС такой настройкой Вы будете получать уведомления на вашу электронную почту каждый раз, когда появится новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми возможностями.\n\n## Связаться с автором { #connect-with-the-author }\n\nМожно связаться со [мной (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com), автором.\n\nВы можете:\n\n* [Подписаться на меня на **GitHub**](https://github.com/tiangolo).\n    * Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам.\n    * Подписаться, чтобы видеть, когда я создаю новый проект с открытым кодом.\n* [Подписаться на меня в **X (Twitter)**](https://x.com/tiangolo) или в [Mastodon](https://fosstodon.org/@tiangolo).\n    * Поделиться со мной, как Вы используете FastAPI (я обожаю это читать).\n    * Узнавать, когда я делаю объявления или выпускаю новые инструменты.\n    * Вы также можете [подписаться на @fastapi в X (Twitter)](https://x.com/fastapi) (это отдельный аккаунт).\n* [Подписаться на меня в **LinkedIn**](https://www.linkedin.com/in/tiangolo/).\n    * Узнавать, когда я делаю объявления или выпускаю новые инструменты (хотя чаще я использую X (Twitter) 🤷‍♂).\n* Читать, что я пишу (или подписаться на меня) на [**Dev.to**](https://dev.to/tiangolo) или [**Medium**](https://medium.com/@tiangolo).\n    * Читать другие идеи, статьи и о созданных мной инструментах.\n    * Подписаться, чтобы читать, когда я публикую что-то новое.\n\n## Оставить сообщение в X (Twitter) о **FastAPI** { #tweet-about-fastapi }\n\n[Оставьте сообщение в X (Twitter) о **FastAPI**](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi) и позвольте мне и другим узнать, почему он Вам нравится. 🎉\n\nЯ люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы его используете и т.д.\n\n## Оставить голос за FastAPI { #vote-for-fastapi }\n\n* [Голосуйте за **FastAPI** в Slant](https://www.slant.co/options/34241/~fastapi-review).\n* [Голосуйте за **FastAPI** в AlternativeTo](https://alternativeto.net/software/fastapi/about/).\n* [Расскажите, что Вы используете **FastAPI** на StackShare](https://stackshare.io/pypi-fastapi).\n\n## Помочь другим с вопросами на GitHub { #help-others-with-questions-in-github }\n\nВы можете попробовать помочь другим с их вопросами в:\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\nВо многих случаях Вы уже можете знать ответы на эти вопросы. 🤓\n\nЕсли Вы много помогаете людям с их вопросами, Вы станете официальным [Экспертом FastAPI](fastapi-people.md#fastapi-experts). 🎉\n\nТолько помните, самое важное — постарайтесь быть добрыми. Люди приходят со своими разочарованиями и часто задают вопросы не лучшим образом, но постарайтесь, насколько можете, быть доброжелательными. 🤗\n\nИдея сообщества **FastAPI** — быть доброжелательным и гостеприимным. В то же время не допускайте травлю или неуважительное поведение по отношению к другим. Мы должны заботиться друг о друге.\n\n---\n\nКак помочь другим с вопросами (в обсуждениях или Issues):\n\n### Понять вопрос { #understand-the-question }\n\n* Убедитесь, что поняли **цель** и кейс использования задающего вопрос.\n\n* Затем проверьте, что вопрос (в подавляющем большинстве это вопросы) сформулирован **ясно**.\n\n* Во многих случаях спрашивают о воображаемом решении пользователя, но может быть решение **получше**. Если Вы лучше поймёте проблему и кейс, сможете предложить **альтернативное решение**.\n\n* Если вопрос непонятен, запросите больше **деталей**.\n\n### Воспроизвести проблему { #reproduce-the-problem }\n\nВ большинстве случаев и вопросов есть что-то связанное с **исходным кодом** автора.\n\nВо многих случаях предоставляют только фрагмент кода, но этого недостаточно, чтобы **воспроизвести проблему**.\n\n* Попросите предоставить [минимальный воспроизводимый пример](https://stackoverflow.com/help/minimal-reproducible-example), который Вы сможете **скопировать-вставить** и запустить локально, чтобы увидеть ту же ошибку или поведение, или лучше понять их кейс.\n\n* Если чувствуете себя особенно великодушными, можете попытаться **создать такой пример** сами, основываясь только на описании проблемы. Просто помните, что это может занять много времени, и, возможно, сначала лучше попросить уточнить проблему.\n\n### Предложить решение { #suggest-solutions }\n\n* После того как Вы поняли вопрос, Вы можете дать возможный **ответ**.\n\n* Во многих случаях лучше понять **исходную проблему или кейс**, потому что может существовать способ решить её лучше, чем то, что пытаются сделать.\n\n### Попросить закрыть { #ask-to-close }\n\nЕсли Вам ответили, велика вероятность, что Вы решили их проблему, поздравляю, **Вы — герой**! 🦸\n\n* Теперь, если проблема решена, можно попросить их:\n    * В GitHub Discussions: пометить комментарий как **answer** (ответ).\n    * В GitHub Issues: **закрыть** Issue.\n\n## Отслеживать репозиторий на GitHub { #watch-the-github-repository }\n\nВы можете \"отслеживать\" FastAPI на GitHub (кликнув по кнопке \"watch\" наверху справа): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nЕсли Вы выберете \"Watching\" вместо \"Releases only\", то будете получать уведомления, когда кто-либо создаёт новый вопрос или Issue. Вы также можете указать, что хотите получать уведомления только о новых Issues, или обсуждениях, или пулл-реквестах и т.д.\n\nТогда Вы можете попробовать помочь им с решением этих вопросов.\n\n## Задать вопросы { #ask-questions }\n\nВы можете [создать новый вопрос](https://github.com/fastapi/fastapi/discussions/new?category=questions) в репозитории GitHub, например:\n\n* Задать **вопрос** или спросить о **проблеме**.\n* Предложить новую **возможность**.\n\n**Заметка**: если Вы это сделаете, то я попрошу Вас также помогать другим. 😉\n\n## Проверять пулл-реквесты { #review-pull-requests }\n\nВы можете помочь мне проверять пулл-реквесты других участников.\n\nИ, снова, постарайтесь быть доброжелательными. 🤗\n\n---\n\nО том, что нужно иметь в виду и как проверять пулл-реквест:\n\n### Понять проблему { #understand-the-problem }\n\n* Во-первых, убедитесь, что **поняли проблему**, которую пулл-реквест пытается решить. Возможно, это обсуждалось более подробно в GitHub Discussion или Issue.\n\n* Также есть вероятность, что пулл-реквест не нужен, так как проблему можно решить **другим путём**. Тогда Вы можете предложить или спросить об этом.\n\n### Не переживайте о стиле { #dont-worry-about-style }\n\n* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах — при слиянии я выполню squash и настрою коммит вручную.\n\n* Также не беспокойтесь о правилах стиля, это уже проверяют автоматизированные инструменты.\n\nЕсли будет нужна какая-то другая стилистика или единообразие, я попрошу об этом напрямую или добавлю поверх свои коммиты с нужными изменениями.\n\n### Проверить код { #check-the-code }\n\n* Проверьте и прочитайте код, посмотрите, логичен ли он, **запустите его локально** и проверьте, действительно ли он решает проблему.\n\n* Затем оставьте **комментарий**, что Вы это сделали, так я пойму, что Вы действительно проверили код.\n\n/// info | Информация\n\nК сожалению, я не могу просто доверять PR-ам только потому, что у них есть несколько одобрений.\n\nНесколько раз было так, что у PR-ов было 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я их проверял, они оказывались сломанными, содержали баги или вовсе не решали заявленную проблему. 😅\n\nПоэтому очень важно действительно прочитать и запустить код и сообщить мне об этом в комментарии. 🤓\n\n///\n\n* Если PR можно упростить, Вы можете попросить об этом, но не нужно быть слишком придирчивым — может быть много субъективных мнений (и у меня тоже 🙈), поэтому лучше сосредоточиться на фундаментальных вещах.\n\n### Тестировать { #tests }\n\n* Помогите мне проверить, что у PR есть **тесты**.\n\n* Проверьте, что тесты **падают** до PR. 🚨\n\n* Затем проверьте, что тесты **проходят** после PR. ✅\n\n* Многие PR не имеют тестов — Вы можете **напомнить** добавить тесты или даже **предложить** некоторые тесты сами. Это одна из самых трудозатратных частей, и здесь Вы можете очень помочь.\n\n* Затем добавьте комментарий, что Вы попробовали, чтобы я знал, что Вы это проверили. 🤓\n\n## Создать пулл-реквест { #create-a-pull-request }\n\nВы можете [сделать вклад](contributing.md) в исходный код пулл-реквестами, например:\n\n* Исправить опечатку, найденную в документации.\n* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли, [изменив этот файл](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml).\n    * Убедитесь, что добавили свою ссылку в начало соответствующего раздела.\n* Помочь с [переводом документации](contributing.md#translations) на Ваш язык.\n    * Вы также можете проверять переводы, сделанные другими.\n* Предложить новые разделы документации.\n* Исправить существующую проблему/баг.\n    * Убедитесь, что добавили тесты.\n* Добавить новую возможность.\n    * Убедитесь, что добавили тесты.\n    * Убедитесь, что добавили документацию, если это уместно.\n\n## Помочь поддерживать FastAPI { #help-maintain-fastapi }\n\nПомогите мне поддерживать **FastAPI**! 🤓\n\nПредстоит ещё много работы, и, по большей части, **ВЫ** можете её сделать.\n\nОсновные задачи, которые Вы можете выполнить прямо сейчас:\n\n* [Помочь другим с вопросами на GitHub](#help-others-with-questions-in-github) (смотрите секцию выше).\n* [Проверять пулл-реквесты](#review-pull-requests) (смотрите секцию выше).\n\nИменно эти две задачи **забирают больше всего времени**. Это основная работа по поддержке FastAPI.\n\nЕсли Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и делаете так, чтобы он продолжал **развиваться быстрее и лучше**. 🚀\n\n## Подключиться к чату { #join-the-chat }\n\nПодключайтесь к 👥 [серверу чата в Discord](https://discord.gg/VQjSZaeJmf) 👥 и общайтесь с другими участниками сообщества FastAPI.\n\n/// tip | Подсказка\n\nПо вопросам — задавайте их в [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions), так гораздо выше шанс, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#fastapi-experts).\n\nИспользуйте чат только для прочих общих бесед.\n\n///\n\n### Не используйте чат для вопросов { #dont-use-the-chat-for-questions }\n\nИмейте в виду, что в чатах, благодаря \"свободному общению\", легко задать вопросы, которые слишком общие и на которые сложнее ответить, поэтому Вы можете не получить ответы.\n\nНа GitHub шаблон поможет Вам правильно сформулировать вопрос, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно ещё до того, как спросите. И на GitHub я могу следить за тем, чтобы всегда отвечать на всё, даже если это занимает время. А с чатами я не могу сделать этого лично. 😅\n\nКроме того, переписка в чатах хуже ищется, чем на GitHub, поэтому вопросы и ответы могут теряться среди остальных сообщений. И только те, что на GitHub, учитываются для получения лычки [Эксперт FastAPI](fastapi-people.md#fastapi-experts), так что вероятнее всего Вы получите больше внимания именно на GitHub.\n\nС другой стороны, в чатах тысячи пользователей, так что почти всегда есть шанс найти там кого-то для разговора. 😄\n\n## Спонсировать автора { #sponsor-the-author }\n\nЕсли Ваш **продукт/компания** зависят от **FastAPI** или связаны с ним и Вы хотите донести до пользователей информацию о себе, Вы можете спонсировать автора (меня) через [GitHub Sponsors](https://github.com/sponsors/tiangolo). В зависимости от уровня поддержки Вы можете получить дополнительные бонусы, например, бейдж в документации. 🎁\n\n---\n\nСпасибо! 🚀\n"
  },
  {
    "path": "docs/ru/docs/history-design-future.md",
    "content": "# История, проектирование и будущее { #history-design-and-future }\n\nОднажды, [один из пользователей **FastAPI** задал вопрос](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920):\n\n> Какова история этого проекта? Создаётся впечатление, что он явился из ниоткуда и завоевал мир за несколько недель [...]\n\nЧто ж, вот небольшая часть истории проекта.\n\n## Альтернативы { #alternatives }\n\nВ течение нескольких лет я, возглавляя различные команды разработчиков, создавал довольно сложные API для машинного обучения, распределённых систем, асинхронных задач, баз данных NoSQL и т.д.\n\nВ рамках работы над этими проектами я исследовал, проверял и использовал многие фреймворки.\n\nВо многом история **FastAPI** - история его предшественников.\n\nКак написано в разделе [Альтернативы](alternatives.md):\n\n<blockquote markdown=\"1\">\n\n**FastAPI** не существовал бы, если б не было более ранних работ других людей.\n\nОни создали большое количество инструментов, которые и вдохновили меня на создание **FastAPI**.\n\nЯ всячески избегал создания нового фреймворка в течение нескольких лет. Сначала я пытался собрать все нужные возможности, которые ныне есть в **FastAPI**, используя множество различных фреймворков, плагинов и инструментов.\n\nНо в какой-то момент не осталось другого выбора, кроме как создать что-то, что предоставляло бы все эти возможности сразу. Взять самые лучшие идеи из предыдущих инструментов и, используя введённые в Python аннотации типов (которых не было до версии 3.6), объединить их.\n\n</blockquote>\n\n## Исследования { #investigation }\n\nИспользуя все существовавшие ранее альтернативы, я получил возможность у каждой из них чему-то научиться, позаимствовать идеи и объединить их наилучшим образом для себя и для команд разработчиков, с которыми я работал.\n\nНапример, стало ясно, что необходимо брать за основу стандартные аннотации типов Python.\n\nТакже наилучшим подходом является использование уже существующих стандартов.\n\nИтак, прежде чем приступить к написанию **FastAPI**, я потратил несколько месяцев на изучение OpenAPI, JSON Schema, OAuth2, и т.п. для понимания их взаимосвязей, совпадений и различий.\n\n## Проектирование { #design }\n\nЗатем я потратил некоторое время на придумывание \"API\" разработчика, который я хотел иметь как пользователь (как разработчик, использующий FastAPI).\n\nЯ проверил несколько идей на самых популярных редакторах кода: PyCharm, VS Code, редакторы на базе Jedi.\n\nСогласно последнему [опросу Python-разработчиков](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools), который охватывает около 80% пользователей.\n\nЭто означает, что **FastAPI** был специально проверен на редакторах, используемых 80% Python-разработчиками. И поскольку большинство других редакторов, как правило, работают аналогичным образом, все его преимущества должны работать практически для всех редакторов.\n\nТаким образом, я смог найти наилучшие способы сократить дублирование кода, обеспечить повсеместное автозавершение, проверку типов и ошибок и т.д.\n\nИ все это, чтобы все разработчики могли получать наилучший опыт разработки.\n\n## Зависимости { #requirements }\n\nПротестировав несколько вариантов, я решил, что в качестве основы буду использовать [**Pydantic**](https://docs.pydantic.dev/) и его преимущества.\n\nПо моим предложениям был изменён код этого фреймворка, чтобы сделать его полностью совместимым с JSON Schema, поддержать различные способы определения ограничений и улучшить поддержку в редакторах кода (проверки типов, автозавершение) на основе тестов в нескольких редакторах.\n\nВо время разработки я также внес вклад в [**Starlette**](https://www.starlette.dev/), другую ключевую зависимость.\n\n## Разработка { #development }\n\nК тому времени, когда я начал создавать **FastAPI**, большинство необходимых деталей уже существовало, дизайн был определён, зависимости и прочие инструменты были готовы, а знания о стандартах и спецификациях были четкими и свежими.\n\n## Будущее { #future }\n\nСейчас уже ясно, что **FastAPI** со своими идеями стал полезен многим людям.\n\nПри сравнении с альтернативами, выбор падает на него, поскольку он лучше подходит для множества вариантов использования.\n\nМногие разработчики и команды уже используют **FastAPI** в своих проектах (включая меня и мою команду).\n\nНо, тем не менее, грядёт добавление ещё многих улучшений и возможностей.\n\nУ **FastAPI** великое будущее.\n\nИ [ваша помощь](help-fastapi.md) очень ценится.\n"
  },
  {
    "path": "docs/ru/docs/how-to/authentication-error-status-code.md",
    "content": "# Использование старых статус-кодов ошибок аутентификации 403 { #use-old-403-authentication-error-status-codes }\n\nДо версии FastAPI `0.122.0`, когда встроенные утилиты безопасности возвращали ошибку клиенту после неудачной аутентификации, они использовали HTTP статус-код `403 Forbidden`.\n\nНачиная с версии FastAPI `0.122.0`, используется более подходящий HTTP статус-код `401 Unauthorized`, и в ответе возвращается имеющий смысл HTTP-заголовок `WWW-Authenticate` в соответствии со спецификациями HTTP, [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized).\n\nНо если по какой-то причине ваши клиенты зависят от старого поведения, вы можете вернуть его, переопределив метод `make_not_authenticated_error` в ваших Security-классах.\n\nНапример, вы можете создать подкласс `HTTPBearer`, который будет возвращать ошибку `403 Forbidden` вместо стандартной `401 Unauthorized`:\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip | Совет\n\nОбратите внимание, что функция возвращает экземпляр исключения, не вызывает его. Выброс выполняется остальным внутренним кодом.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/how-to/conditional-openapi.md",
    "content": "# Условный OpenAPI { #conditional-openapi }\n\nПри необходимости вы можете использовать настройки и переменные окружения, чтобы условно настраивать OpenAPI в зависимости от окружения и даже полностью его отключать.\n\n## О безопасности, API и документации { #about-security-apis-and-docs }\n\nСкрытие пользовательских интерфейсов документации в продакшн не должно быть способом защиты вашего API.\n\nЭто не добавляет дополнительной безопасности вашему API, операции пути (обработчики пути) всё равно будут доступны по своим путям.\n\nЕсли в вашем коде есть уязвимость, она всё равно останется.\n\nСокрытие документации лишь усложняет понимание того, как взаимодействовать с вашим API, и может усложнить его отладку в продакшн. Это можно считать просто разновидностью [безопасности через сокрытие](https://en.wikipedia.org/wiki/Security_through_obscurity).\n\nЕсли вы хотите обезопасить свой API, есть несколько более эффективных вещей, которые можно сделать, например:\n\n* Убедитесь, что у вас чётко определены Pydantic-модели для тел запросов и ответов.\n* Настройте необходимые разрешения и роли с помощью зависимостей.\n* Никогда не храните пароли в открытом виде, только хэши паролей.\n* Реализуйте и используйте известные криптографические инструменты, например pwdlib и JWT-токены, и т.д.\n* Добавьте более тонкое управление доступом с помощью OAuth2 scopes (областей) там, где это необходимо.\n* ...и т.п.\n\nТем не менее, у вас может быть очень специфичный случай использования, когда действительно нужно отключить документацию API для некоторых окружений (например, в продакшн) или в зависимости от настроек из переменных окружения.\n\n## Условный OpenAPI из настроек и переменных окружения { #conditional-openapi-from-settings-and-env-vars }\n\nВы можете легко использовать те же настройки Pydantic, чтобы настроить сгенерированный OpenAPI и интерфейсы документации.\n\nНапример:\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\nЗдесь мы объявляем настройку `openapi_url` с тем же значением по умолчанию — `\"/openapi.json\"`.\n\nЗатем используем её при создании приложения FastAPI.\n\nДалее вы можете отключить OpenAPI (включая интерфейсы документации), установив переменную окружения `OPENAPI_URL` в пустую строку, например:\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nПосле этого, если перейти по адресам `/openapi.json`, `/docs` или `/redoc`, вы получите ошибку `404 Not Found`, например:\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/ru/docs/how-to/configure-swagger-ui.md",
    "content": "# Настройка Swagger UI { #configure-swagger-ui }\n\nВы можете настроить дополнительные [параметры Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\nЧтобы настроить их, передайте аргумент `swagger_ui_parameters` при создании объекта приложения `FastAPI()` или в функцию `get_swagger_ui_html()`.\n\n`swagger_ui_parameters` принимает словарь с настройками, которые передаются в Swagger UI напрямую.\n\nFastAPI преобразует эти настройки в **JSON**, чтобы они были совместимы с JavaScript, поскольку именно это требуется Swagger UI.\n\n## Отключить подсветку синтаксиса { #disable-syntax-highlighting }\n\nНапример, вы можете отключить подсветку синтаксиса в Swagger UI.\n\nБез изменения настроек подсветка синтаксиса включена по умолчанию:\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\nНо вы можете отключить её, установив `syntaxHighlight` в `False`:\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n…и после этого Swagger UI больше не будет показывать подсветку синтаксиса:\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## Изменить тему { #change-the-theme }\n\nАналогично вы можете задать тему подсветки синтаксиса с ключом \"syntaxHighlight.theme\" (обратите внимание, что посередине стоит точка):\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\nЭта настройка изменит цветовую тему подсветки синтаксиса:\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## Изменить параметры Swagger UI по умолчанию { #change-default-swagger-ui-parameters }\n\nFastAPI включает некоторые параметры конфигурации по умолчанию, подходящие для большинства случаев.\n\nЭто включает следующие настройки по умолчанию:\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\nВы можете переопределить любую из них, указав другое значение в аргументе `swagger_ui_parameters`.\n\nНапример, чтобы отключить `deepLinking`, можно передать такие настройки в `swagger_ui_parameters`:\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## Другие параметры Swagger UI { #other-swagger-ui-parameters }\n\nЧтобы увидеть все остальные возможные настройки, прочитайте официальную [документацию по параметрам Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\n## Настройки только для JavaScript { #javascript-only-settings }\n\nSwagger UI также допускает другие настройки, которые являются **чисто JavaScript-объектами** (например, JavaScript-функциями).\n\nFastAPI также включает следующие настройки `presets` (только для JavaScript):\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\nЭто объекты **JavaScript**, а не строки, поэтому напрямую передать их из Python-кода нельзя.\n\nЕсли вам нужны такие настройки только для JavaScript, используйте один из методов выше. Переопределите *операцию пути* Swagger UI и вручную напишите любой необходимый JavaScript.\n"
  },
  {
    "path": "docs/ru/docs/how-to/custom-docs-ui-assets.md",
    "content": "# Свои статические ресурсы UI документации (самостоятельный хостинг) { #custom-docs-ui-static-assets-self-hosting }\n\nДокументация API использует **Swagger UI** и **ReDoc**, и для каждого из них нужны некоторые файлы JavaScript и CSS.\n\nПо умолчанию эти файлы отдаются с <abbr title=\"Content Delivery Network – Сеть доставки контента: Сервис, обычно состоящий из нескольких серверов, который предоставляет статические файлы, такие как JavaScript и CSS. Обычно используется, чтобы отдавать эти файлы с сервера, расположенного ближе к клиенту, что улучшает производительность.\">CDN</abbr>.\n\nНо это можно настроить: вы можете указать конкретный CDN или отдавать файлы самостоятельно.\n\n## Пользовательский CDN для JavaScript и CSS { #custom-cdn-for-javascript-and-css }\n\nДопустим, вы хотите использовать другой <abbr title=\"Content Delivery Network – Сеть доставки контента\">CDN</abbr>, например `https://unpkg.com/`.\n\nЭто может быть полезно, если, например, вы живёте в стране, где некоторые URL ограничены.\n\n### Отключить автоматическую документацию { #disable-the-automatic-docs }\n\nПервый шаг — отключить автоматическую документацию, так как по умолчанию она использует стандартный CDN.\n\nЧтобы отключить её, установите их URL в значение `None` при создании вашего приложения `FastAPI`:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### Подключить пользовательскую документацию { #include-the-custom-docs }\n\nТеперь вы можете создать *операции пути* для пользовательской документации.\n\nВы можете переиспользовать внутренние функции FastAPI для создания HTML-страниц документации и передать им необходимые аргументы:\n\n* `openapi_url`: URL, по которому HTML-страница документации сможет получить схему OpenAPI для вашего API. Здесь можно использовать атрибут `app.openapi_url`.\n* `title`: заголовок вашего API.\n* `oauth2_redirect_url`: здесь можно использовать `app.swagger_ui_oauth2_redirect_url`, чтобы оставить значение по умолчанию.\n* `swagger_js_url`: URL, по которому HTML для документации Swagger UI сможет получить файл **JavaScript**. Это URL вашего пользовательского CDN.\n* `swagger_css_url`: URL, по которому HTML для документации Swagger UI сможет получить файл **CSS**. Это URL вашего пользовательского CDN.\n\nАналогично и для ReDoc...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip | Совет\n\n*Операция пути* для `swagger_ui_redirect` — это вспомогательный эндпоинт на случай, когда вы используете OAuth2.\n\nЕсли вы интегрируете свой API с провайдером OAuth2, вы сможете аутентифицироваться и вернуться к документации API с полученными учётными данными, а затем взаимодействовать с ним, используя реальную аутентификацию OAuth2.\n\nSwagger UI сделает это за вас «за кулисами», но для этого ему нужен этот вспомогательный «redirect» эндпоинт.\n\n///\n\n### Создайте *операцию пути*, чтобы проверить { #create-a-path-operation-to-test-it }\n\nЧтобы убедиться, что всё работает, создайте *операцию пути*:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### Тестирование { #test-it }\n\nТеперь вы должны иметь возможность открыть свою документацию по адресу [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) и перезагрузить страницу — «ассеты» (статические файлы) будут загружаться с нового CDN.\n\n## Самостоятельный хостинг JavaScript и CSS для документации { #self-hosting-javascript-and-css-for-docs }\n\nСамостоятельный хостинг JavaScript и CSS может быть полезен, если, например, вам нужно, чтобы приложение продолжало работать в офлайне, без доступа к открытому Интернету, или в локальной сети.\n\nЗдесь вы увидите, как отдавать эти файлы самостоятельно, в том же приложении FastAPI, и настроить документацию на их использование.\n\n### Структура файлов проекта { #project-file-structure }\n\nДопустим, структура файлов вашего проекта выглядит так:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\nТеперь создайте директорию для хранения этих статических файлов.\n\nНовая структура файлов может выглядеть так:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### Скачайте файлы { #download-the-files }\n\nСкачайте статические файлы, необходимые для документации, и поместите их в директорию `static/`.\n\nСкорее всего, вы можете кликнуть правой кнопкой на каждой ссылке и выбрать что-то вроде «Сохранить ссылку как...».\n\n**Swagger UI** использует файлы:\n\n* [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n* [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\nА **ReDoc** использует файл:\n\n* [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\nПосле этого структура файлов может выглядеть так:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### Предоставьте доступ к статическим файлам { #serve-the-static-files }\n\n* Импортируйте `StaticFiles`.\n* Смонтируйте экземпляр `StaticFiles()` в определённый путь.\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### Протестируйте статические файлы { #test-the-static-files }\n\nЗапустите своё приложение и откройте [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js).\n\nВы должны увидеть очень длинный JavaScript-файл для **ReDoc**.\n\nОн может начинаться примерно так:\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\nЭто подтверждает, что ваше приложение умеет отдавать статические файлы и что вы поместили файлы документации в нужное место.\n\nТеперь можно настроить приложение так, чтобы документация использовала эти статические файлы.\n\n### Отключить автоматическую документацию для статических файлов { #disable-the-automatic-docs-for-static-files }\n\nТак же, как и при использовании пользовательского CDN, первым шагом будет отключение автоматической документации, так как по умолчанию она использует CDN.\n\nЧтобы отключить её, установите их URL в значение `None` при создании вашего приложения `FastAPI`:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### Подключить пользовательскую документацию со статическими файлами { #include-the-custom-docs-for-static-files }\n\nАналогично пользовательскому CDN, теперь вы можете создать *операции пути* для собственной документации.\n\nСнова можно переиспользовать внутренние функции FastAPI для создания HTML-страниц документации и передать им необходимые аргументы:\n\n* `openapi_url`: URL, по которому HTML-страница документации сможет получить схему OpenAPI для вашего API. Здесь можно использовать атрибут `app.openapi_url`.\n* `title`: заголовок вашего API.\n* `oauth2_redirect_url`: здесь можно использовать `app.swagger_ui_oauth2_redirect_url`, чтобы оставить значение по умолчанию.\n* `swagger_js_url`: URL, по которому HTML для документации Swagger UI сможет получить файл **JavaScript**. **Это тот файл, который теперь отдаёт ваше собственное приложение**.\n* `swagger_css_url`: URL, по которому HTML для документации Swagger UI сможет получить файл **CSS**. **Это тот файл, который теперь отдаёт ваше собственное приложение**.\n\nАналогично и для ReDoc...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip | Совет\n\n*Операция пути* для `swagger_ui_redirect` — это вспомогательный эндпоинт на случай, когда вы используете OAuth2.\n\nЕсли вы интегрируете свой API с провайдером OAuth2, вы сможете аутентифицироваться и вернуться к документации API с полученными учётными данными, а затем взаимодействовать с ним, используя реальную аутентификацию OAuth2.\n\nSwagger UI сделает это за вас «за кулисами», но для этого ему нужен этот вспомогательный «redirect» эндпоинт.\n\n///\n\n### Создайте *операцию пути* для теста статических файлов { #create-a-path-operation-to-test-static-files }\n\nЧтобы убедиться, что всё работает, создайте *операцию пути*:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### Тестирование UI со статическими файлами { #test-static-files-ui }\n\nТеперь вы можете отключить Wi‑Fi, открыть свою документацию по адресу [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) и перезагрузить страницу.\n\nДаже без Интернета вы сможете видеть документацию к своему API и взаимодействовать с ним.\n"
  },
  {
    "path": "docs/ru/docs/how-to/custom-request-and-route.md",
    "content": "# Пользовательские классы Request и APIRoute { #custom-request-and-apiroute-class }\n\nВ некоторых случаях может понадобиться переопределить логику, используемую классами `Request` и `APIRoute`.\n\nВ частности, это может быть хорошей альтернативой логике в middleware.\n\nНапример, если вы хотите прочитать или изменить тело запроса до того, как оно будет обработано вашим приложением.\n\n/// danger | Опасность\n\nЭто «продвинутая» возможность.\n\nЕсли вы только начинаете работать с **FastAPI**, возможно, стоит пропустить этот раздел.\n\n///\n\n## Сценарии использования { #use-cases }\n\nНекоторые сценарии:\n\n* Преобразование тел запросов, не в формате JSON, в JSON (например, [`msgpack`](https://msgpack.org/index.html)).\n* Распаковка тел запросов, сжатых с помощью gzip.\n* Автоматическое логирование всех тел запросов.\n\n## Обработка пользовательского кодирования тела запроса { #handling-custom-request-body-encodings }\n\nПосмотрим как использовать пользовательский подкласс `Request` для распаковки gzip-запросов.\n\nИ подкласс `APIRoute`, чтобы использовать этот пользовательский класс запроса.\n\n### Создать пользовательский класс `GzipRequest` { #create-a-custom-gziprequest-class }\n\n/// tip | Совет\n\nЭто учебный пример, демонстрирующий принцип работы. Если вам нужна поддержка Gzip, вы можете использовать готовый [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware).\n\n///\n\nСначала создадим класс `GzipRequest`, который переопределит метод `Request.body()` и распакует тело запроса при наличии соответствующего HTTP-заголовка.\n\nЕсли в заголовке нет `gzip`, он не будет пытаться распаковывать тело.\n\nТаким образом, один и тот же класс маршрута сможет обрабатывать как gzip-сжатые, так и несжатые запросы.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### Создать пользовательский класс `GzipRoute` { #create-a-custom-gziproute-class }\n\nДалее создадим пользовательский подкласс `fastapi.routing.APIRoute`, который будет использовать `GzipRequest`.\n\nНа этот раз он переопределит метод `APIRoute.get_route_handler()`.\n\nЭтот метод возвращает функцию. Именно эта функция получает HTTP-запрос и возвращает HTTP-ответ.\n\nЗдесь мы используем её, чтобы создать `GzipRequest` из исходного HTTP-запроса.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | Технические детали\n\nУ `Request` есть атрибут `request.scope` — это просто Python-`dict`, содержащий метаданные, связанные с HTTP-запросом.\n\nУ `Request` также есть `request.receive` — функция для «получения» тела запроса.\n\nИ `dict` `scope`, и функция `receive` являются частью спецификации ASGI.\n\nИменно этих двух компонентов — `scope` и `receive` — достаточно, чтобы создать новый экземпляр `Request`.\n\nЧтобы узнать больше о `Request`, см. [документацию Starlette о запросах](https://www.starlette.dev/requests/).\n\n///\n\nЕдинственное, что делает по-другому функция, возвращённая `GzipRequest.get_route_handler`, — преобразует `Request` в `GzipRequest`.\n\nБлагодаря этому наш `GzipRequest` позаботится о распаковке данных (при необходимости) до передачи их в наши *операции пути*.\n\nДальше вся логика обработки остаётся прежней.\n\nНо благодаря изменениям в `GzipRequest.body` тело запроса будет автоматически распаковано при необходимости, когда оно будет загружено **FastAPI**.\n\n## Доступ к телу запроса в обработчике исключений { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip | Совет\n\nДля решения этой задачи, вероятно, намного проще использовать `body` в пользовательском обработчике `RequestValidationError` ([Обработка ошибок](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)).\n\nНо этот пример всё равно актуален и показывает, как взаимодействовать с внутренними компонентами.\n\n///\n\nТем же подходом можно воспользоваться, чтобы получить доступ к телу запроса в обработчике исключений.\n\nНужно лишь обработать запрос внутри блока `try`/`except`:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\nЕсли произойдёт исключение, экземпляр `Request` всё ещё будет в области видимости, поэтому мы сможем прочитать тело запроса и использовать его при обработке ошибки:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## Пользовательский класс `APIRoute` в роутере { #custom-apiroute-class-in-a-router }\n\nВы также можете задать параметр `route_class` у `APIRouter`:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\nВ этом примере *операции пути*, объявленные в `router`, будут использовать пользовательский класс `TimedRoute` и получат дополнительный HTTP-заголовок `X-Response-Time` в ответе с временем, затраченным на формирование ответа:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/ru/docs/how-to/extending-openapi.md",
    "content": "# Расширение OpenAPI { #extending-openapi }\n\nИногда может понадобиться изменить сгенерированную схему OpenAPI.\n\nВ этом разделе показано, как это сделать.\n\n## Обычный процесс { #the-normal-process }\n\nОбычный (по умолчанию) процесс выглядит так.\n\nПриложение `FastAPI` (экземпляр) имеет метод `.openapi()`, который должен возвращать схему OpenAPI.\n\nВ процессе создания объекта приложения регистрируется *операция пути* (обработчик пути) для `/openapi.json` (или для того, что указано в вашем `openapi_url`).\n\nОна просто возвращает JSON-ответ с результатом вызова метода приложения `.openapi()`.\n\nПо умолчанию метод `.openapi()` проверяет свойство `.openapi_schema`: если в нём уже есть данные, возвращает их.\n\nЕсли нет — генерирует схему с помощью вспомогательной функции `fastapi.openapi.utils.get_openapi`.\n\nФункция `get_openapi()` принимает параметры:\n\n* `title`: Заголовок OpenAPI, отображается в документации.\n* `version`: Версия вашего API, например `2.5.0`.\n* `openapi_version`: Версия используемой спецификации OpenAPI. По умолчанию — последняя: `3.1.0`.\n* `summary`: Краткое описание API.\n* `description`: Описание вашего API; может включать Markdown и будет отображаться в документации.\n* `routes`: Список маршрутов — это каждая зарегистрированная *операция пути*. Берутся из `app.routes`.\n\n/// info | Информация\n\nПараметр `summary` доступен в OpenAPI 3.1.0 и выше, поддерживается FastAPI версии 0.99.0 и выше.\n\n///\n\n## Переопределение значений по умолчанию { #overriding-the-defaults }\n\nИспользуя информацию выше, вы можете той же вспомогательной функцией сгенерировать схему OpenAPI и переопределить любые нужные части.\n\nНапример, добавим [расширение OpenAPI ReDoc для включения собственного логотипа](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo).\n\n### Обычный **FastAPI** { #normal-fastapi }\n\nСначала напишите приложение **FastAPI** как обычно:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### Сгенерируйте схему OpenAPI { #generate-the-openapi-schema }\n\nЗатем используйте ту же вспомогательную функцию для генерации схемы OpenAPI внутри функции `custom_openapi()`:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### Измените схему OpenAPI { #modify-the-openapi-schema }\n\nТеперь можно добавить расширение ReDoc, добавив кастомный `x-logo` в «объект» `info` в схеме OpenAPI:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### Кэшируйте схему OpenAPI { #cache-the-openapi-schema }\n\nВы можете использовать свойство `.openapi_schema` как «кэш» для хранения сгенерированной схемы.\n\nТак приложению не придётся генерировать схему каждый раз, когда пользователь открывает документацию API.\n\nОна будет создана один раз, а затем тот же кэшированный вариант будет использоваться для последующих запросов.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### Переопределите метод { #override-the-method }\n\nТеперь вы можете заменить метод `.openapi()` на вашу новую функцию.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### Проверьте { #check-it }\n\nПерейдите на [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) — вы увидите, что используется ваш кастомный логотип (в этом примере — логотип **FastAPI**):\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/ru/docs/how-to/general.md",
    "content": "# Общее — Как сделать — Рецепты { #general-how-to-recipes }\n\nЗдесь несколько указателей на другие места в документации для общих или частых вопросов.\n\n## Фильтрация данных — Безопасность { #filter-data-security }\n\nЧтобы убедиться, что вы не возвращаете больше данных, чем следует, прочитайте документацию: [Руководство — Модель ответа — Возвращаемый тип](../tutorial/response-model.md).\n\n## Оптимизация производительности ответа — Модель ответа — Возвращаемый тип { #optimize-response-performance-response-model-return-type }\n\nЧтобы оптимизировать производительность при возврате JSON-данных, используйте возвращаемый тип или модель ответа; таким образом Pydantic выполнит сериализацию в JSON на стороне Rust, без прохождения через Python. Подробнее читайте в документации: [Руководство — Модель ответа — Возвращаемый тип](../tutorial/response-model.md).\n\n## Теги в документации — OpenAPI { #documentation-tags-openapi }\n\nЧтобы добавить теги к вашим *операциям пути* и группировать их в интерфейсе документации, прочитайте документацию: [Руководство — Конфигурации операций пути — Теги](../tutorial/path-operation-configuration.md#tags).\n\n## Краткое описание и описание в документации — OpenAPI { #documentation-summary-and-description-openapi }\n\nЧтобы добавить краткое описание и описание к вашим *операциям пути* и отобразить их в интерфейсе документации, прочитайте документацию: [Руководство — Конфигурации операций пути — Краткое описание и описание](../tutorial/path-operation-configuration.md#summary-and-description).\n\n## Описание ответа в документации — OpenAPI { #documentation-response-description-openapi }\n\nЧтобы задать описание ответа, отображаемое в интерфейсе документации, прочитайте документацию: [Руководство — Конфигурации операций пути — Описание ответа](../tutorial/path-operation-configuration.md#response-description).\n\n## Документация — пометить операцию пути устаревшей — OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\nЧтобы пометить *операцию пути* как устаревшую и показать это в интерфейсе документации, прочитайте документацию: [Руководство — Конфигурации операций пути — Пометить операцию пути устаревшей](../tutorial/path-operation-configuration.md#deprecate-a-path-operation).\n\n## Преобразование любых данных к формату, совместимому с JSON { #convert-any-data-to-json-compatible }\n\nЧтобы преобразовать любые данные к формату, совместимому с JSON, прочитайте документацию: [Руководство — JSON-совместимый кодировщик](../tutorial/encoder.md).\n\n## Метаданные OpenAPI — Документация { #openapi-metadata-docs }\n\nЧтобы добавить метаданные в вашу схему OpenAPI, включая лицензию, версию, контакты и т.д., прочитайте документацию: [Руководство — Метаданные и URL документации](../tutorial/metadata.md).\n\n## Пользовательский URL OpenAPI { #openapi-custom-url }\n\nЧтобы настроить URL OpenAPI (или удалить его), прочитайте документацию: [Руководство — Метаданные и URL документации](../tutorial/metadata.md#openapi-url).\n\n## URL документации OpenAPI { #openapi-docs-urls }\n\nЧтобы изменить URL, используемые для автоматически сгенерированных пользовательских интерфейсов документации, прочитайте документацию: [Руководство — Метаданные и URL документации](../tutorial/metadata.md#docs-urls).\n"
  },
  {
    "path": "docs/ru/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\nТак как **FastAPI** основан на стандарте **ASGI**, очень легко интегрировать любую библиотеку **GraphQL**, также совместимую с ASGI.\n\nВы можете комбинировать обычные *операции пути* FastAPI с GraphQL в одном приложении.\n\n/// tip | Совет\n\n**GraphQL** решает некоторые очень специфические задачи.\n\nУ него есть как **преимущества**, так и **недостатки** по сравнению с обычными **веб-API**.\n\nУбедитесь, что **выгоды** для вашего случая использования перевешивают **недостатки**. 🤓\n\n///\n\n## Библиотеки GraphQL { #graphql-libraries }\n\nНиже приведены некоторые библиотеки **GraphQL** с поддержкой **ASGI**. Их можно использовать с **FastAPI**:\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * С [документацией для FastAPI](https://strawberry.rocks/docs/integrations/fastapi)\n* [Ariadne](https://ariadnegraphql.org/)\n    * С [документацией для FastAPI](https://ariadnegraphql.org/docs/fastapi-integration)\n* [Tartiflette](https://tartiflette.io/)\n    * С [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) для интеграции с ASGI\n* [Graphene](https://graphene-python.org/)\n    * С [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)\n\n## GraphQL со Strawberry { #graphql-with-strawberry }\n\nЕсли вам нужно или хочется работать с **GraphQL**, [**Strawberry**](https://strawberry.rocks/) — **рекомендуемая** библиотека, так как её дизайн ближе всего к дизайну **FastAPI**, всё основано на **аннотациях типов**.\n\nВ зависимости от вашего сценария использования вы можете предпочесть другую библиотеку, но если бы вы спросили меня, я, скорее всего, предложил бы попробовать **Strawberry**.\n\nВот небольшой пример того, как можно интегрировать Strawberry с FastAPI:\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\nПодробнее о Strawberry можно узнать в [документации Strawberry](https://strawberry.rocks/).\n\nА также в документации по [интеграции Strawberry с FastAPI](https://strawberry.rocks/docs/integrations/fastapi).\n\n## Устаревший `GraphQLApp` из Starlette { #older-graphqlapp-from-starlette }\n\nВ предыдущих версиях Starlette был класс `GraphQLApp` для интеграции с [Graphene](https://graphene-python.org/).\n\nОн был объявлен устаревшим в Starlette, но если у вас есть код, который его использовал, вы можете легко **мигрировать** на [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3), который решает ту же задачу и имеет **почти идентичный интерфейс**.\n\n/// tip | Совет\n\nЕсли вам нужен GraphQL, я всё же рекомендую посмотреть [Strawberry](https://strawberry.rocks/), так как он основан на аннотациях типов, а не на пользовательских классах и типах.\n\n///\n\n## Подробнее { #learn-more }\n\nПодробнее о **GraphQL** вы можете узнать в [официальной документации GraphQL](https://graphql.org/).\n\nТакже можно почитать больше о каждой из указанных выше библиотек по приведённым ссылкам.\n"
  },
  {
    "path": "docs/ru/docs/how-to/index.md",
    "content": "# Как сделать — Рецепты { #how-to-recipes }\n\nЗдесь вы найдете разные рецепты и руководства «как сделать» по **различным темам**.\n\nБольшинство из этих идей более-менее **независимы**, и в большинстве случаев вам стоит изучать их только если они напрямую относятся к **вашему проекту**.\n\nЕсли что-то кажется интересным и полезным для вашего проекта, смело изучайте; в противном случае, вероятно, можно просто пропустить.\n\n/// tip | Совет\n\nЕсли вы хотите **изучить FastAPI** структурированно (рекомендуется), вместо этого читайте [Учебник - Руководство пользователя](../tutorial/index.md) по главам.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# Миграция с Pydantic v1 на Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\nЕсли у вас старое приложение FastAPI, возможно, вы используете Pydantic версии 1.\n\nFastAPI версии 0.100.0 поддерживал либо Pydantic v1, либо v2. Он использовал ту версию, которая была установлена.\n\nFastAPI версии 0.119.0 добавил частичную поддержку Pydantic v1 изнутри Pydantic v2 (как `pydantic.v1`), чтобы упростить миграцию на v2.\n\nFastAPI 0.126.0 убрал поддержку Pydantic v1, при этом ещё некоторое время продолжал поддерживать `pydantic.v1`.\n\n/// warning | Предупреждение\n\nКоманда Pydantic прекратила поддержку Pydantic v1 для последних версий Python, начиная с **Python 3.14**.\n\nЭто включает `pydantic.v1`, который больше не поддерживается в Python 3.14 и выше.\n\nЕсли вы хотите использовать последние возможности Python, вам нужно убедиться, что вы используете Pydantic v2.\n\n///\n\nЕсли у вас старое приложение FastAPI с Pydantic v1, здесь я покажу, как мигрировать на Pydantic v2, и **возможности FastAPI 0.119.0**, которые помогут выполнить постепенную миграцию.\n\n## Официальное руководство { #official-guide }\n\nУ Pydantic есть официальное [руководство по миграции](https://docs.pydantic.dev/latest/migration/) с v1 на v2.\n\nТам также описано, что изменилось, как валидации стали более корректными и строгими, возможные нюансы и т.д.\n\nПрочитайте его, чтобы лучше понять, что изменилось.\n\n## Тесты { #tests }\n\nУбедитесь, что у вас есть [тесты](../tutorial/testing.md) для вашего приложения и что вы запускаете их в системе непрерывной интеграции (CI).\n\nТак вы сможете выполнить обновление и убедиться, что всё работает как ожидается.\n\n## `bump-pydantic` { #bump-pydantic }\n\nВо многих случаях, когда вы используете обычные Pydantic‑модели без пользовательских настроек, вы сможете автоматизировать большую часть процесса миграции с Pydantic v1 на Pydantic v2.\n\nВы можете использовать [`bump-pydantic`](https://github.com/pydantic/bump-pydantic) от той же команды Pydantic.\n\nЭтот инструмент поможет автоматически изменить большую часть кода, который нужно изменить.\n\nПосле этого вы можете запустить тесты и проверить, что всё работает. Если да — на этом всё. 😎\n\n## Pydantic v1 в v2 { #pydantic-v1-in-v2 }\n\nPydantic v2 включает всё из Pydantic v1 как подмодуль `pydantic.v1`. Но это больше не поддерживается в версиях Python выше 3.13.\n\nЭто означает, что вы можете установить последнюю версию Pydantic v2 и импортировать и использовать старые компоненты Pydantic v1 из этого подмодуля так, как если бы у вас был установлен старый Pydantic v1.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### Поддержка FastAPI для Pydantic v1 внутри v2 { #fastapi-support-for-pydantic-v1-in-v2 }\n\nНачиная с FastAPI 0.119.0, есть также частичная поддержка Pydantic v1 изнутри Pydantic v2, чтобы упростить миграцию на v2.\n\nТаким образом, вы можете обновить Pydantic до последней версии 2 и сменить импорты на подмодуль `pydantic.v1` — во многих случаях всё просто заработает.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning | Предупреждение\n\nИмейте в виду, что так как команда Pydantic больше не поддерживает Pydantic v1 в последних версиях Python, начиная с Python 3.14, использование `pydantic.v1` также не поддерживается в Python 3.14 и выше.\n\n///\n\n### Pydantic v1 и v2 в одном приложении { #pydantic-v1-and-v2-on-the-same-app }\n\nВ Pydantic **не поддерживается** ситуация, когда в одной модели Pydantic v2 используются поля, определённые как модели Pydantic v1, и наоборот.\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n…но в одном и том же приложении вы можете иметь отдельные модели на Pydantic v1 и v2.\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\nВ некоторых случаях можно использовать и модели Pydantic v1, и v2 в одной и той же **операции пути** (обработчике пути) вашего приложения FastAPI:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\nВ примере выше модель входных данных — это модель Pydantic v1, а модель выходных данных (указанная в `response_model=ItemV2`) — это модель Pydantic v2.\n\n### Параметры Pydantic v1 { #pydantic-v1-parameters }\n\nЕсли вам нужно использовать некоторые специфичные для FastAPI инструменты для параметров, такие как `Body`, `Query`, `Form` и т.п., с моделями Pydantic v1, вы можете импортировать их из `fastapi.temp_pydantic_v1_params`, пока завершаете миграцию на Pydantic v2:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### Мигрируйте по шагам { #migrate-in-steps }\n\n/// tip | Совет\n\nСначала попробуйте `bump-pydantic`: если тесты проходят и всё работает, вы справились одной командой. ✨\n\n///\n\nЕсли `bump-pydantic` не подходит для вашего случая, вы можете использовать поддержку одновременной работы моделей Pydantic v1 и v2 в одном приложении, чтобы мигрировать на Pydantic v2 постепенно.\n\nСначала вы можете обновить Pydantic до последней 2-й версии и изменить импорты так, чтобы все ваши модели использовали `pydantic.v1`.\n\nЗатем вы можете начать мигрировать ваши модели с Pydantic v1 на v2 группами, поэтапно. 🚶\n"
  },
  {
    "path": "docs/ru/docs/how-to/separate-openapi-schemas.md",
    "content": "# Разделять схемы OpenAPI для входа и выхода или нет { #separate-openapi-schemas-for-input-and-output-or-not }\n\nПри использовании **Pydantic v2** сгенерированный OpenAPI становится чуть более точным и **корректным**, чем раньше. 😎\n\nНа самом деле, в некоторых случаях в OpenAPI будет даже **две JSON-схемы** для одной и той же Pydantic‑модели: для входа и для выхода — в зависимости от наличия **значений по умолчанию**.\n\nПосмотрим, как это работает, и как это изменить при необходимости.\n\n## Pydantic‑модели для входа и выхода { #pydantic-models-for-input-and-output }\n\nПредположим, у вас есть Pydantic‑модель со значениями по умолчанию, как здесь:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### Модель для входа { #model-for-input }\n\nЕсли использовать эту модель как входную, как здесь:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n…то поле `description` **не будет обязательным**, потому что у него значение по умолчанию `None`.\n\n### Входная модель в документации { #input-model-in-docs }\n\nВ документации это видно: у поля `description` нет **красной звёздочки** — оно не отмечено как обязательное:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### Модель для выхода { #model-for-output }\n\nНо если использовать ту же модель как выходную, как здесь:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n…то, поскольку у `description` есть значение по умолчанию, если вы **ничего не вернёте** для этого поля, оно всё равно будет иметь это **значение по умолчанию**.\n\n### Модель для данных ответа { #model-for-output-response-data }\n\nЕсли поработать с интерактивной документацией и посмотреть ответ, то, хотя код ничего не добавил в одно из полей `description`, JSON‑ответ содержит значение по умолчанию (`null`):\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\nЭто означает, что у него **всегда будет какое‑то значение**, просто иногда это значение может быть `None` (или `null` в JSON).\n\nЭто означает, что клиентам, использующим ваш API, не нужно проверять, существует ли это значение или нет: они могут **исходить из того, что поле всегда присутствует**, но в некоторых случаях оно будет иметь значение по умолчанию `None`.\n\nВ OpenAPI это описывается тем, что поле помечается как **обязательное**, поскольку оно всегда присутствует.\n\nИз‑за этого JSON Schema для модели может отличаться в зависимости от использования для **входа** или **выхода**:\n\n* для **входа** `description` **не будет обязательным**\n* для **выхода** оно будет **обязательным** (и при этом может быть `None`, или, в терминах JSON, `null`)\n\n### Выходная модель в документации { #model-for-output-in-docs }\n\nВ документации это тоже видно, что **оба**: `name` и `description`, помечены **красной звёздочкой** как **обязательные**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### Модели для входа и выхода в документации { #model-for-input-and-output-in-docs }\n\nЕсли посмотреть все доступные схемы (JSON Schema) в OpenAPI, вы увидите две: `Item-Input` и `Item-Output`.\n\nДля `Item-Input` поле `description` **не является обязательным** — красной звёздочки нет.\n\nА для `Item-Output` `description` **обязательно** — красная звёздочка есть.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\nБлагодаря этой возможности **Pydantic v2** документация вашего API становится более **точной**; если у вас есть сгенерированные клиенты и SDK, они тоже будут точнее, с лучшим **удобством для разработчиков** и большей консистентностью. 🎉\n\n## Не разделять схемы { #do-not-separate-schemas }\n\nОднако бывают случаи, когда вы хотите иметь **одну и ту же схему для входа и выхода**.\n\nГлавный сценарий — когда у вас уже есть сгенерированный клиентский код/SDK, и вы пока не хотите обновлять весь этот автогенерируемый клиентский код/SDK, вероятно, вы захотите сделать это в какой-то момент, но, возможно, не прямо сейчас.\n\nВ таком случае вы можете отключить эту функциональность в **FastAPI** с помощью параметра `separate_input_output_schemas=False`.\n\n/// info | Информация\n\nПоддержка `separate_input_output_schemas` появилась в FastAPI `0.102.0`. 🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### Одна и та же схема для входной и выходной моделей в документации { #same-schema-for-input-and-output-models-in-docs }\n\nИ теперь для модели будет одна общая схема и для входа, и для выхода — только `Item`, и в ней `description` будет **не обязательным**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/ru/docs/how-to/testing-database.md",
    "content": "# Тестирование базы данных { #testing-a-database }\n\nВы можете изучить базы данных, SQL и SQLModel в [документации SQLModel](https://sqlmodel.tiangolo.com/). 🤓\n\nЕсть мини-[руководство по использованию SQLModel с FastAPI](https://sqlmodel.tiangolo.com/tutorial/fastapi/). ✨\n\nВ этом руководстве есть раздел о [тестировании SQL-баз данных](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/). 😎\n"
  },
  {
    "path": "docs/ru/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/ru\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>Фреймворк FastAPI: высокая производительность, прост в изучении, позволяет быстро писать код, готов к продакшн</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Тест\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Покрытие\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Версия пакета\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Поддерживаемые версии Python\">\n</a>\n</p>\n\n---\n\n**Документация**: [https://fastapi.tiangolo.com](https://fastapi.tiangolo.com/ru)\n\n**Исходный код**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI — это современный, быстрый (высокопроизводительный) веб-фреймворк для создания API на Python, основанный на стандартных аннотациях типов Python.\n\nКлючевые особенности:\n\n* **Скорость**: Очень высокая производительность, на уровне **NodeJS** и **Go** (благодаря Starlette и Pydantic). [Один из самых быстрых доступных фреймворков Python](#performance).\n* **Быстрота разработки**: Увеличьте скорость разработки фич примерно на 200–300%. *\n* **Меньше ошибок**: Сократите примерно на 40% количество ошибок, вызванных человеком (разработчиком). *\n* **Интуитивность**: Отличная поддержка редактора кода. <dfn title=\"также известное как: автодополнение, автозавершение, IntelliSense\">Автозавершение</dfn> везде. Меньше времени на отладку.\n* **Простота**: Разработан так, чтобы его было легко использовать и осваивать. Меньше времени на чтение документации.\n* **Краткость**: Минимизируйте дублирование кода. Несколько возможностей из каждого объявления параметров. Меньше ошибок.\n* **Надежность**: Получите код, готовый к продакшн. С автоматической интерактивной документацией.\n* **На основе стандартов**: Основан на открытых стандартах API и полностью совместим с ними: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (ранее известный как Swagger) и [JSON Schema](https://json-schema.org/).\n\n<small>* оценка на основе тестов внутренней команды разработчиков, создающих продакшн-приложения.</small>\n\n## Спонсоры { #sponsors }\n\n<!-- sponsors -->\n\n### Ключевой-спонсор { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### Золотые и серебряные спонсоры { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[Другие спонсоры](https://fastapi.tiangolo.com/ru/fastapi-people/#sponsors)\n\n## Мнения { #opinions }\n\n\"_[...] В последнее время я много где использую **FastAPI**. [...] На самом деле я планирую использовать его для всех **ML-сервисов моей команды в Microsoft**. Некоторые из них интегрируются в основной продукт **Windows**, а некоторые — в продукты **Office**._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n\"_Мы начали использовать библиотеку **FastAPI**, чтобы поднять **REST**-сервер, к которому можно обращаться за **предсказаниями**. [для Ludwig]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n\"_**Netflix** рада объявить об открытом релизе нашего фреймворка оркестрации **антикризисного управления**: **Dispatch**! [создан с помощью **FastAPI**]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n\"_Я в полном восторге от **FastAPI**. Это так весело!_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken - <strong>Ведущий подкаста [Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855)</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(ref)</small></a></div>\n\n---\n\n\"_Честно говоря, то, что вы создали, выглядит очень солидно и отполировано. Во многих смыслах это то, чем я хотел видеть **Hug** — очень вдохновляет видеть, как кто-то это создал._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley - <strong>Создатель [Hug](https://github.com/hugapi/hug)</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(ref)</small></a></div>\n\n---\n\n\"_Если вы хотите изучить один **современный фреймворк** для создания REST API, посмотрите **FastAPI** [...] Он быстрый, простой в использовании и лёгкий в изучении [...]_\"\n\n\"_Мы переключились на **FastAPI** для наших **API** [...] Думаю, вам тоже понравится [...]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani - Matthew Honnibal - <strong>Основатели [Explosion AI](https://explosion.ai) — создатели [spaCy](https://spacy.io)</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(ref)</small></a> - <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(ref)</small></a></div>\n\n---\n\n\"_Если кто-то собирается делать продакшн-API на Python, я настоятельно рекомендую **FastAPI**. Он **прекрасно спроектирован**, **прост в использовании** и **отлично масштабируется**, стал **ключевым компонентом** нашей стратегии API-first и приводит в действие множество автоматизаций и сервисов, таких как наш Virtual TAC Engineer._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n## Мини-документальный фильм о FastAPI { #fastapi-mini-documentary }\n\nВ конце 2025 года вышел [мини-документальный фильм о FastAPI](https://www.youtube.com/watch?v=mpR8ngthqiE), вы можете посмотреть его онлайн:\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**, FastAPI для CLI { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\nЕсли вы создаёте приложение <abbr title=\"Command Line Interface - Интерфейс командной строки\">CLI</abbr> для использования в терминале вместо веб-API, посмотрите [**Typer**](https://typer.tiangolo.com/).\n\n**Typer** — младший брат FastAPI. И он задуман как **FastAPI для CLI**. ⌨️ 🚀\n\n## Зависимости { #requirements }\n\nFastAPI стоит на плечах гигантов:\n\n* [Starlette](https://www.starlette.dev/) для части, связанной с вебом.\n* [Pydantic](https://docs.pydantic.dev/) для части, связанной с данными.\n\n## Установка { #installation }\n\nСоздайте и активируйте [виртуальное окружение](https://fastapi.tiangolo.com/ru/virtual-environments/), затем установите FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Примечание**: Обязательно заключите `\"fastapi[standard]\"` в кавычки, чтобы это работало во всех терминалах.\n\n## Пример { #example }\n\n### Создание { #create-it }\n\nСоздайте файл `main.py` со следующим содержимым:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>Или используйте <code>async def</code>...</summary>\n\nЕсли ваш код использует `async` / `await`, используйте `async def`:\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Примечание**:\n\nЕсли не уверены, посмотрите раздел _«Нет времени?»_ о [`async` и `await` в документации](https://fastapi.tiangolo.com/ru/async/#in-a-hurry).\n\n</details>\n\n### Запуск { #run-it }\n\nЗапустите сервер командой:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary>О команде <code>fastapi dev</code>...</summary>\n\nКоманда `fastapi dev` читает ваш файл `main.py`, находит в нём приложение **FastAPI** и запускает сервер с помощью [Uvicorn](https://www.uvicorn.dev).\n\nПо умолчанию `fastapi dev` запускается с включённой авто-перезагрузкой для локальной разработки.\n\nПодробнее в [документации по FastAPI CLI](https://fastapi.tiangolo.com/ru/fastapi-cli/).\n\n</details>\n\n### Проверка { #check-it }\n\nОткройте браузер на [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery).\n\nВы увидите JSON-ответ:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\nВы уже создали API, который:\n\n* Получает HTTP-запросы по _путям_ `/` и `/items/{item_id}`.\n* Оба _пути_ используют `GET` <em>операции</em> (также известные как HTTP _методы_).\n* _Путь_ `/items/{item_id}` имеет _path-параметр_ `item_id`, который должен быть `int`.\n* _Путь_ `/items/{item_id}` имеет необязательный `str` _параметр запроса_ `q`.\n\n### Интерактивная документация API { #interactive-api-docs }\n\nПерейдите на [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВы увидите автоматическую интерактивную документацию API (предоставлена [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Альтернативная документация API { #alternative-api-docs }\n\nТеперь откройте [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nВы увидите альтернативную автоматическую документацию (предоставлена [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Пример обновления { #example-upgrade }\n\nТеперь измените файл `main.py`, чтобы принимать тело запроса из `PUT` HTTP-запроса.\n\nОбъявите тело запроса, используя стандартные типы Python, спасибо Pydantic.\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\nСервер `fastapi dev` должен перезагрузиться автоматически.\n\n### Обновление интерактивной документации API { #interactive-api-docs-upgrade }\n\nПерейдите на [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n* Интерактивная документация API будет автоматически обновлена, включая новое тело запроса:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Нажмите кнопку «Try it out», это позволит вам заполнить параметры и напрямую взаимодействовать с API:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* Затем нажмите кнопку «Execute», интерфейс свяжется с вашим API, отправит параметры, получит результаты и отобразит их на экране:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### Обновление альтернативной документации API { #alternative-api-docs-upgrade }\n\nТеперь откройте [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\n* Альтернативная документация также отразит новый параметр запроса и тело запроса:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Подведём итоги { #recap }\n\nИтак, вы объявляете **один раз** типы параметров, тело запроса и т.д. как параметры функции.\n\nВы делаете это с помощью стандартных современных типов Python.\n\nВам не нужно изучать новый синтаксис, методы или классы конкретной библиотеки и т.п.\n\nТолько стандартный **Python**.\n\nНапример, для `int`:\n\n```Python\nitem_id: int\n```\n\nили для более сложной модели `Item`:\n\n```Python\nitem: Item\n```\n\n...и с этим единственным объявлением вы получаете:\n\n* Поддержку редактора кода, включая:\n    * Автозавершение.\n    * Проверку типов.\n* Валидацию данных:\n    * Автоматические и понятные ошибки, когда данные некорректны.\n    * Валидацию даже для глубоко вложенных объектов JSON.\n* <dfn title=\"также известное как: сериализация, парсинг, маршалинг\">Преобразование</dfn> входных данных: из сети в данные и типы Python. Чтение из:\n    * JSON.\n    * Параметров пути.\n    * Параметров запроса.\n    * Cookies.\n    * HTTP-заголовков.\n    * Форм.\n    * Файлов.\n* <dfn title=\"также известное как: сериализация, парсинг, маршалинг\">Преобразование</dfn> выходных данных: из данных и типов Python в данные сети (например, JSON):\n    * Преобразование типов Python (`str`, `int`, `float`, `bool`, `list` и т.д.).\n    * Объекты `datetime`.\n    * Объекты `UUID`.\n    * Модели баз данных.\n    * ...и многое другое.\n* Автоматическую интерактивную документацию API, включая 2 альтернативных интерфейса:\n    * Swagger UI.\n    * ReDoc.\n\n---\n\nВозвращаясь к предыдущему примеру кода, **FastAPI** будет:\n\n* Валидировать наличие `item_id` в пути для `GET` и `PUT` HTTP-запросов.\n* Валидировать, что `item_id` имеет тип `int` для `GET` и `PUT` HTTP-запросов.\n    * Если это не так, клиент увидит полезную понятную ошибку.\n* Проверять, есть ли необязательный параметр запроса с именем `q` (например, `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET` HTTP-запросов.\n    * Поскольку параметр `q` объявлен с `= None`, он необязателен.\n    * Без `None` он был бы обязательным (как тело запроса в случае с `PUT`).\n* Для `PUT` HTTP-запросов к `/items/{item_id}` читать тело запроса как JSON:\n    * Проверять, что есть обязательный атрибут `name`, который должен быть `str`.\n    * Проверять, что есть обязательный атрибут `price`, который должен быть `float`.\n    * Проверять, что есть необязательный атрибут `is_offer`, который должен быть `bool`, если он присутствует.\n    * Всё это также будет работать для глубоко вложенных объектов JSON.\n* Автоматически преобразовывать из и в JSON.\n* Документировать всё с помощью OpenAPI, что может быть использовано:\n    * Системами интерактивной документации.\n    * Системами автоматической генерации клиентского кода для многих языков.\n* Предоставлять 2 веб-интерфейса интерактивной документации напрямую.\n\n---\n\nМы только поверхностно ознакомились, но вы уже понимаете, как всё это работает.\n\nПопробуйте изменить строку:\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n...из:\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n...на:\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n...и посмотрите, как ваш редактор кода будет автоматически дополнять атрибуты и знать их типы:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\nБолее полный пример с дополнительными возможностями см. в <a href=\"https://fastapi.tiangolo.com/ru/tutorial/\">Учебник - Руководство пользователя</a>.\n\n**Осторожно, спойлер**: учебник - руководство пользователя включает:\n\n* Объявление **параметров** из других источников: **HTTP-заголовки**, **cookies**, **поля формы** и **файлы**.\n* Как задать **ограничения валидации** вроде `maximum_length` или `regex`.\n* Очень мощную и простую в использовании систему **<dfn title=\"также известна как: компоненты, ресурсы, провайдеры, сервисы, инъекции\">внедрения зависимостей</dfn>**.\n* Безопасность и аутентификацию, включая поддержку **OAuth2** с **JWT токенами** и **HTTP Basic** аутентификацию.\n* Более продвинутые (но столь же простые) приёмы объявления **глубоко вложенных JSON-моделей** (спасибо Pydantic).\n* Интеграцию **GraphQL** с [Strawberry](https://strawberry.rocks) и другими библиотеками.\n* Множество дополнительных функций (благодаря Starlette), таких как:\n    * **WebSockets**\n    * чрезвычайно простые тесты на основе HTTPX и `pytest`\n    * **CORS**\n    * **сессии с использованием cookie**\n    * ...и многое другое.\n\n### Разверните приложение (опционально) { #deploy-your-app-optional }\n\nПри желании вы можете развернуть своё приложение FastAPI в [FastAPI Cloud](https://fastapicloud.com), присоединяйтесь к списку ожидания, если ещё не сделали этого. 🚀\n\nЕсли у вас уже есть аккаунт **FastAPI Cloud** (мы пригласили вас из списка ожидания 😉), вы можете развернуть ваше приложение одной командой.\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nВот и всё! Теперь вы можете открыть ваше приложение по этой ссылке. ✨\n\n#### О FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** создан тем же автором и командой, что и **FastAPI**.\n\nОн упрощает процесс **создания образа**, **развертывания** и **доступа** к API при минимальных усилиях.\n\nОн переносит тот же **опыт разработчика**, что и при создании приложений на FastAPI, на их **развертывание** в облаке. 🎉\n\nFastAPI Cloud — основной спонсор и источник финансирования для проектов с открытым исходным кодом из экосистемы *FastAPI and friends*. ✨\n\n#### Развертывание у других облачных провайдеров { #deploy-to-other-cloud-providers }\n\nFastAPI — это open source и стандартизированный фреймворк. Вы можете развернуть приложения FastAPI у любого облачного провайдера на ваш выбор.\n\nСледуйте руководствам вашего облачного провайдера по развертыванию приложений FastAPI. 🤓\n\n## Производительность { #performance }\n\nНезависимые бенчмарки TechEmpower показывают приложения **FastAPI**, работающие под управлением Uvicorn, как [один из самых быстрых доступных фреймворков Python](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), уступающий только самим Starlette и Uvicorn (используются внутри FastAPI). (*)\n\nЧтобы узнать больше, см. раздел [Бенчмарки](https://fastapi.tiangolo.com/ru/benchmarks/).\n\n## Зависимости { #dependencies }\n\nFastAPI зависит от Pydantic и Starlette.\n\n### Зависимости `standard` { #standard-dependencies }\n\nКогда вы устанавливаете FastAPI с помощью `pip install \"fastapi[standard]\"`, он идёт с группой опциональных зависимостей `standard`:\n\nИспользуется Pydantic:\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) — для проверки адресов электронной почты.\n\nИспользуется Starlette:\n\n* [`httpx`](https://www.python-httpx.org) — обязателен, если вы хотите использовать `TestClient`.\n* [`jinja2`](https://jinja.palletsprojects.com) — обязателен, если вы хотите использовать конфигурацию шаблонов по умолчанию.\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - обязателен, если вы хотите поддерживать <dfn title=\"преобразование строки, полученной из HTTP-запроса, в данные Python\">«парсинг»</dfn> форм через `request.form()`.\n\nИспользуется FastAPI:\n\n* [`uvicorn`](https://www.uvicorn.dev) — сервер, который загружает и «отдаёт» ваше приложение. Включает `uvicorn[standard]`, содержащий некоторые зависимости (например, `uvloop`), нужные для высокой производительности.\n* `fastapi-cli[standard]` — чтобы предоставить команду `fastapi`.\n    * Включает `fastapi-cloud-cli`, который позволяет развернуть ваше приложение FastAPI в [FastAPI Cloud](https://fastapicloud.com).\n\n### Без зависимостей `standard` { #without-standard-dependencies }\n\nЕсли вы не хотите включать опциональные зависимости `standard`, можно установить `pip install fastapi` вместо `pip install \"fastapi[standard]\"`.\n\n### Без `fastapi-cloud-cli` { #without-fastapi-cloud-cli }\n\nЕсли вы хотите установить FastAPI со стандартными зависимостями, но без `fastapi-cloud-cli`, установите `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n### Дополнительные опциональные зависимости { #additional-optional-dependencies }\n\nЕсть дополнительные зависимости, которые вы можете установить.\n\nДополнительные опциональные зависимости Pydantic:\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) — для управления настройками.\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) — дополнительные типы для использования с Pydantic.\n\nДополнительные опциональные зависимости FastAPI:\n\n* [`orjson`](https://github.com/ijl/orjson) — обязателен, если вы хотите использовать `ORJSONResponse`.\n* [`ujson`](https://github.com/esnme/ultrajson) — обязателен, если вы хотите использовать `UJSONResponse`.\n\n## Лицензия { #license }\n\nЭтот проект распространяется на условиях лицензии MIT.\n"
  },
  {
    "path": "docs/ru/docs/learn/index.md",
    "content": "# Обучение { #learn }\n\nЗдесь представлены вводные разделы и учебные пособия для изучения **FastAPI**.\n\nВы можете считать это **книгой**, **курсом**, **официальным** и рекомендуемым способом изучения FastAPI. 😎\n"
  },
  {
    "path": "docs/ru/docs/project-generation.md",
    "content": "# Шаблон Full Stack FastAPI { #full-stack-fastapi-template }\n\nШаблоны, хотя обычно поставляются с определённой конфигурацией, спроектированы так, чтобы быть гибкими и настраиваемыми. Это позволяет вам изменять их и адаптировать под требования вашего проекта, что делает их отличной отправной точкой. 🏁\n\nВы можете использовать этот шаблон для старта: в нём уже сделана значительная часть начальной настройки, безопасность, база данных и несколько эндпоинтов API.\n\nРепозиторий GitHub: [Full Stack FastAPI Template](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## Шаблон Full Stack FastAPI — Технологический стек и возможности { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/ru) для бэкенд‑API на Python.\n    - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаимодействия с SQL‑базой данных на Python (ORM).\n    - 🔍 [Pydantic](https://docs.pydantic.dev), используется FastAPI, для валидации данных и управления настройками.\n    - 💾 [PostgreSQL](https://www.postgresql.org) в качестве SQL‑базы данных.\n- 🚀 [React](https://react.dev) для фронтенда.\n    - 💃 Используются TypeScript, хуки, Vite и другие части современного фронтенд‑стека.\n    - 🎨 [Tailwind CSS](https://tailwindcss.com) и [shadcn/ui](https://ui.shadcn.com) для компонентов фронтенда.\n    - 🤖 Автоматически сгенерированный фронтенд‑клиент.\n    - 🧪 [Playwright](https://playwright.dev) для End‑to‑End тестирования.\n    - 🦇 Поддержка тёмной темы.\n- 🐋 [Docker Compose](https://www.docker.com) для разработки и продакшн.\n- 🔒 Безопасное хэширование паролей по умолчанию.\n- 🔑 Аутентификация по JWT‑токенам.\n- 📫 Восстановление пароля по электронной почте.\n- ✅ Тесты с [Pytest](https://pytest.org).\n- 📞 [Traefik](https://traefik.io) в роли обратного прокси / балансировщика нагрузки.\n- 🚢 Инструкции по развёртыванию с использованием Docker Compose, включая настройку фронтенд‑прокси Traefik для автоматического получения сертификатов HTTPS.\n- 🏭 CI (continuous integration) и CD (continuous deployment) на основе GitHub Actions.\n"
  },
  {
    "path": "docs/ru/docs/python-types.md",
    "content": "# Введение в типы Python { #python-types-intro }\n\nPython поддерживает необязательные «подсказки типов» (их также называют «аннотациями типов»).\n\nЭти **«подсказки типов»** или аннотации — это специальный синтаксис, позволяющий объявлять <dfn title=\"например: str, int, float, bool\">тип</dfn> переменной.\n\nОбъявляя типы для ваших переменных, редакторы кода и инструменты смогут лучше вас поддерживать.\n\nЭто всего лишь **краткое руководство / напоминание** о подсказках типов в Python. Оно охватывает только минимум, необходимый для их использования с **FastAPI**... что на самом деле очень мало.\n\n**FastAPI** целиком основан на этих подсказках типов — они дают ему множество преимуществ и выгод.\n\nНо даже если вы никогда не используете **FastAPI**, вам будет полезно немного узнать о них.\n\n/// note | Примечание\n\nЕсли вы являетесь экспертом в Python и уже знаете всё о подсказках типов, переходите к следующей главе.\n\n///\n\n## Мотивация { #motivation }\n\nДавайте начнем с простого примера:\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\nВызов этой программы выводит:\n\n```\nJohn Doe\n```\n\nФункция делает следующее:\n\n* Принимает `first_name` и `last_name`.\n* Преобразует первую букву каждого значения в верхний регистр с помощью `title()`.\n* <dfn title=\"Соединяет их в одно. Содержимое одного — сразу после другого.\">Соединяет</dfn> их пробелом посередине.\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### Отредактируем пример { #edit-it }\n\nЭто очень простая программа.\n\nА теперь представьте, что вы пишете её с нуля.\n\nВ какой-то момент вы бы начали определение функции, у вас были бы готовы параметры...\n\nНо затем нужно вызвать «тот метод, который делает первую букву заглавной».\n\nЭто был `upper`? Или `uppercase`? `first_uppercase`? `capitalize`?\n\nТогда вы пробуете старого друга программиста — автозавершение редактора кода.\n\nВы вводите первый параметр функции, `first_name`, затем точку (`.`) и нажимаете `Ctrl+Space`, чтобы вызвать автозавершение.\n\nНо, к сожалению, ничего полезного не находится:\n\n<img src=\"/img/python-types/image01.png\">\n\n### Добавим типы { #add-types }\n\nДавайте изменим одну строку из предыдущей версии.\n\nМы поменяем ровно этот фрагмент — параметры функции — с:\n\n```Python\n    first_name, last_name\n```\n\nна:\n\n```Python\n    first_name: str, last_name: str\n```\n\nВот и всё.\n\nЭто и есть «подсказки типов»:\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\nЭто не то же самое, что объявление значений по умолчанию, как, например:\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\nЭто другая вещь.\n\nЗдесь мы используем двоеточия (`:`), а не знак равенства (`=`).\n\nИ добавление подсказок типов обычно не меняет поведение программы по сравнению с вариантом без них.\n\nНо теперь представьте, что вы снова посередине написания этой функции, только уже с подсказками типов.\n\nВ тот же момент вы пробуете вызвать автозавершение с помощью `Ctrl+Space` — и видите:\n\n<img src=\"/img/python-types/image02.png\">\n\nС этим вы можете прокручивать варианты, пока не найдёте тот самый:\n\n<img src=\"/img/python-types/image03.png\">\n\n## Больше мотивации { #more-motivation }\n\nПосмотрите на эту функцию — у неё уже есть подсказки типов:\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\nТак как редактор кода знает типы переменных, вы получаете не только автозавершение, но и проверки ошибок:\n\n<img src=\"/img/python-types/image04.png\">\n\nТеперь вы знаете, что нужно исправить — преобразовать `age` в строку с помощью `str(age)`:\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## Объявление типов { #declaring-types }\n\nВы только что увидели основное место, где объявляют подсказки типов — параметры функции.\n\nЭто также основное место, где вы будете использовать их с **FastAPI**.\n\n### Простые типы { #simple-types }\n\nВы можете объявлять все стандартные типы Python, не только `str`.\n\nМожно использовать, например:\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### Модуль `typing` { #typing-module }\n\nДля некоторых дополнительных сценариев может понадобиться импортировать что-то из стандартного модуля `typing`. Например, когда вы хотите объявить, что что-то имеет «любой тип», можно использовать `Any` из `typing`:\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### Generic-типы { #generic-types }\n\nНекоторые типы могут принимать «параметры типов» в квадратных скобках, чтобы определить их внутренние типы. Например, «список строк» объявляется как `list[str]`.\n\nТакие типы, которые принимают параметры типов, называются **Generic-типами** или **Generics**.\n\nВы можете использовать те же встроенные типы как generics (с квадратными скобками и типами внутри):\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### List { #list }\n\nНапример, давайте определим переменную как `list` из `str`.\n\nОбъявите переменную с тем же синтаксисом двоеточия (`:`).\n\nВ качестве типа укажите `list`.\n\nТак как список — это тип, содержащий внутренние типы, укажите их в квадратных скобках:\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info | Информация\n\nЭти внутренние типы в квадратных скобках называются «параметрами типов».\n\nВ данном случае `str` — это параметр типа, передаваемый в `list`.\n\n///\n\nЭто означает: «переменная `items` — это `list`, и каждый элемент этого списка — `str`».\n\nТаким образом, ваш редактор кода сможет помогать даже при обработке элементов списка:\n\n<img src=\"/img/python-types/image05.png\">\n\nБез типов добиться этого почти невозможно.\n\nОбратите внимание, что переменная `item` — один из элементов списка `items`.\n\nИ всё же редактор кода знает, что это `str`, и даёт соответствующую поддержку.\n\n#### Tuple и Set { #tuple-and-set }\n\nАналогично вы бы объявили `tuple` и `set`:\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\nЭто означает:\n\n* Переменная `items_t` — это `tuple` из 3 элементов: `int`, ещё один `int` и `str`.\n* Переменная `items_s` — это `set`, и каждый элемент имеет тип `bytes`.\n\n#### Dict { #dict }\n\nЧтобы определить `dict`, вы передаёте 2 параметра типов, разделённые запятой.\n\nПервый параметр типа — для ключей `dict`.\n\nВторой параметр типа — для значений `dict`:\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\nЭто означает:\n\n* Переменная `prices` — это `dict`:\n    * Ключи этого `dict` имеют тип `str` (скажем, название каждой позиции).\n    * Значения этого `dict` имеют тип `float` (скажем, цена каждой позиции).\n\n#### Union { #union }\n\nВы можете объявить, что переменная может быть **одним из нескольких типов**, например, `int` или `str`.\n\nЧтобы это определить, используйте <dfn title='также называется «побитовый оператор OR», но это значение здесь нерелевантно'>вертикальную черту (`|`)</dfn> для разделения обоих типов.\n\nЭто называется «объединение» (union), потому что переменная может быть чем угодно из объединения этих двух множеств типов.\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\nЭто означает, что `item` может быть `int` или `str`.\n\n#### Возможно `None` { #possibly-none }\n\nВы можете объявить, что значение может иметь определённый тип, например `str`, но также может быть и `None`.\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\nИспользование `str | None` вместо просто `str` позволит редактору кода помочь вам обнаружить ошибки, когда вы предполагаете, что значение всегда `str`, хотя на самом деле оно может быть и `None`.\n\n### Классы как типы { #classes-as-types }\n\nВы также можете объявлять класс как тип переменной.\n\nДопустим, у вас есть класс `Person` с именем:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\nТогда вы можете объявить переменную типа `Person`:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\nИ снова вы получите полную поддержку редактора кода:\n\n<img src=\"/img/python-types/image06.png\">\n\nОбратите внимание, что это означает: «`one_person` — это **экземпляр** класса `Person`».\n\nЭто не означает: «`one_person` — это **класс** с именем `Person`».\n\n## Pydantic-модели { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/) — это библиотека Python для валидации данных.\n\nВы объявляете «форму» данных как классы с атрибутами.\n\nИ у каждого атрибута есть тип.\n\nЗатем вы создаёте экземпляр этого класса с некоторыми значениями — он провалидирует значения, преобразует их к соответствующему типу (если это применимо) и вернёт вам объект со всеми данными.\n\nИ вы получите полную поддержку редактора кода для этого результирующего объекта.\n\nПример из официальной документации Pydantic:\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info | Информация\n\nЧтобы узнать больше о [Pydantic, ознакомьтесь с его документацией](https://docs.pydantic.dev/).\n\n///\n\n**FastAPI** целиком основан на Pydantic.\n\nВы увидите намного больше всего этого на практике в [Учебник - Руководство пользователя](tutorial/index.md).\n\n## Подсказки типов с аннотациями метаданных { #type-hints-with-metadata-annotations }\n\nВ Python также есть возможность добавлять **дополнительные <dfn title=\"Данные о данных, в данном случае — информация о типе, например описание.\">метаданные</dfn>** к подсказкам типов с помощью `Annotated`.\n\nВы можете импортировать `Annotated` из `typing`.\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nСам Python ничего не делает с `Annotated`. А для редакторов кода и других инструментов тип по-прежнему `str`.\n\nНо вы можете использовать это место в `Annotated`, чтобы передать **FastAPI** дополнительные метаданные о том, как вы хотите, чтобы ваше приложение себя вело.\n\nВажно помнить, что **первый параметр типа**, который вы передаёте в `Annotated`, — это **фактический тип**. Всё остальное — просто метаданные для других инструментов.\n\nПока вам достаточно знать, что `Annotated` существует и это — стандартный Python. 😎\n\nПозже вы увидите, насколько это **мощно**.\n\n/// tip | Совет\n\nТот факт, что это **стандартный Python**, означает, что вы по-прежнему получите **лучший возможный разработческий опыт** в вашем редакторе кода, с инструментами для анализа и рефакторинга кода и т.д. ✨\n\nА ещё ваш код будет очень совместим со множеством других инструментов и библиотек Python. 🚀\n\n///\n\n## Аннотации типов в **FastAPI** { #type-hints-in-fastapi }\n\n**FastAPI** использует эти подсказки типов для выполнения нескольких задач.\n\nС **FastAPI** вы объявляете параметры с подсказками типов и получаете:\n\n* **Поддержку редактора кода**.\n* **Проверки типов**.\n\n...и **FastAPI** использует эти же объявления для:\n\n* **Определения требований**: из path-параметров пути запроса, query-параметров, HTTP-заголовков, тел запросов, зависимостей и т.д.\n* **Преобразования данных**: из HTTP-запроса к требуемому типу.\n* **Валидации данных**: приходящих с каждого HTTP-запроса:\n    * Генерации **автоматических ошибок**, возвращаемых клиенту, когда данные некорректны.\n* **Документирования** API с использованием OpenAPI:\n    * что затем используется пользовательскими интерфейсами автоматической интерактивной документации.\n\nВсё это может звучать абстрактно. Не волнуйтесь. Вы увидите всё это в действии в [Учебник - Руководство пользователя](tutorial/index.md).\n\nВажно то, что, используя стандартные типы Python в одном месте (вместо добавления дополнительных классов, декораторов и т.д.), **FastAPI** сделает за вас большую часть работы.\n\n/// info | Информация\n\nЕсли вы уже прошли всё руководство и вернулись, чтобы узнать больше о типах, хорошим ресурсом будет [«шпаргалка» от `mypy`](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html).\n\n///\n"
  },
  {
    "path": "docs/ru/docs/resources/index.md",
    "content": "# Ресурсы { #resources }\n\nДополнительные ресурсы, внешние ссылки и многое другое. ✈️\n"
  },
  {
    "path": "docs/ru/docs/translation-banner.md",
    "content": "/// details | 🌐 Перевод выполнен с помощью ИИ и людей\n\nЭтот перевод был сделан ИИ под руководством людей. 🤝\n\nВ нем могут быть ошибки из-за неправильного понимания оригинального смысла или неестественности и т. д. 🤖\n\nВы можете улучшить этот перевод, [помогая нам лучше направлять ИИ LLM](https://fastapi.tiangolo.com/ru/contributing/#translations).\n\n[Английская версия](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/ru/docs/tutorial/background-tasks.md",
    "content": "# Фоновые задачи { #background-tasks }\n\nВы можете создавать фоновые задачи, которые будут выполняться после возврата ответа.\n\nЭто полезно для операций, которые должны произойти после HTTP-запроса, но клиенту не обязательно ждать их завершения, чтобы получить ответ.\n\nНапример:\n\n* Уведомления по электронной почте, отправляемые после выполнения действия:\n    * Так как подключение к почтовому серверу и отправка письма обычно «медленные» (несколько секунд), вы можете сразу вернуть ответ, а отправку уведомления выполнить в фоне.\n* Обработка данных:\n    * Например, если вы получаете файл, который должен пройти через медленный процесс, вы можете вернуть ответ «Accepted» (HTTP 202) и обработать файл в фоне.\n\n## Использование `BackgroundTasks` { #using-backgroundtasks }\n\nСначала импортируйте `BackgroundTasks` и объявите параметр в вашей функции‑обработчике пути с типом `BackgroundTasks`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI** создаст объект типа `BackgroundTasks` для вас и передаст его через этот параметр.\n\n## Создание функции для фоновой задачи { #create-a-task-function }\n\nСоздайте функцию, которую нужно запустить как фоновую задачу.\n\nЭто обычная функция, которая может принимать параметры.\n\nЭто может быть как `async def`, так и обычная функция `def`, **FastAPI** знает, как корректно её выполнить.\n\nВ этом случае функция задачи будет записывать данные в файл (имитируя отправку письма).\n\nТак как операция записи не использует `async` и `await`, мы определим функцию как обычную `def`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## Добавление фоновой задачи { #add-the-background-task }\n\nВнутри вашей функции‑обработчика пути передайте функцию задачи объекту фоновых задач методом `.add_task()`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()` принимает следующие аргументы:\n\n* Функцию задачи, которую нужно выполнить в фоне (`write_notification`).\n* Последовательность позиционных аргументов, которые должны быть переданы функции задачи, в порядке (`email`).\n* Любые именованные аргументы, которые должны быть переданы функции задачи (`message=\"some notification\"`).\n\n## Встраивание зависимостей { #dependency-injection }\n\nИспользование `BackgroundTasks` также работает с системой встраивания зависимостей, вы можете объявить параметр типа `BackgroundTasks` на нескольких уровнях: в функции‑обработчике пути, в зависимости (dependable), в подзависимости и т.д.\n\n**FastAPI** знает, что делать в каждом случае и как переиспользовать один и тот же объект, так чтобы все фоновые задачи были объединены и затем выполнены в фоне:\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\nВ этом примере сообщения будут записаны в файл `log.txt` после отправки ответа.\n\nЕсли в запросе была строка запроса (query), она будет записана в лог фоновой задачей.\n\nЗатем другая фоновая задача, созданная в функции‑обработчике пути, запишет сообщение, используя path‑параметр `email`.\n\n## Технические детали { #technical-details }\n\nКласс `BackgroundTasks` приходит напрямую из [`starlette.background`](https://www.starlette.dev/background/).\n\nОн импортируется/включается прямо в FastAPI, чтобы вы могли импортировать его из `fastapi` и избежать случайного импорта альтернативного `BackgroundTask` (без `s` на конце) из `starlette.background`.\n\nИспользуя только `BackgroundTasks` (а не `BackgroundTask`), его можно применять как параметр функции‑обработчика пути, и **FastAPI** сделает остальное за вас, как при использовании объекта `Request` напрямую.\n\nПо‑прежнему можно использовать один `BackgroundTask` в FastAPI, но тогда вам нужно создать объект в своём коде и вернуть Starlette `Response`, включающий его.\n\nПодробнее см. в [официальной документации Starlette по фоновым задачам](https://www.starlette.dev/background/).\n\n## Предостережение { #caveat }\n\nЕсли вам нужно выполнять тяжелые вычисления в фоне, и при этом они не обязательно должны запускаться тем же процессом (например, вам не нужно делиться памятью, переменными и т.п.), вам могут подойти более мощные инструменты, такие как [Celery](https://docs.celeryq.dev).\n\nОни обычно требуют более сложной конфигурации, менеджера очереди сообщений/заданий (например, RabbitMQ или Redis), но позволяют запускать фоновые задачи в нескольких процессах и, что особенно важно, на нескольких серверах.\n\nНо если вам нужен доступ к переменным и объектам из того же приложения **FastAPI**, или нужно выполнять небольшие фоновые задачи (например, отправку email‑уведомления), вы можете просто использовать `BackgroundTasks`.\n\n## Резюме { #recap }\n\nИмпортируйте и используйте `BackgroundTasks` с параметрами в функциях‑обработчиках пути и зависимостях, чтобы добавлять фоновые задачи.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/bigger-applications.md",
    "content": "# Большие приложения — несколько файлов { #bigger-applications-multiple-files }\n\nПри построении приложения или веб-API нам редко удается поместить всё в один файл.\n\n**FastAPI** предоставляет удобный инструментарий, который позволяет нам структурировать приложение, сохраняя при этом всю необходимую гибкость.\n\n/// info | Примечание\n\nЕсли вы раньше использовали Flask, то это аналог шаблонов Flask (Flask's Blueprints).\n\n///\n\n## Пример структуры приложения { #an-example-file-structure }\n\nДавайте предположим, что наше приложение имеет следующую структуру:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | Подсказка\n\nЕсть несколько файлов `__init__.py`: по одному в каждом каталоге или подкаталоге.\n\nЭто как раз то, что позволяет импортировать код из одного файла в другой.\n\nНапример, в файле `app/main.py` может быть следующая строка:\n\n```\nfrom app.routers import items\n```\n\n///\n\n* Всё помещается в каталоге `app`. В нём также находится пустой файл `app/__init__.py`. Таким образом, `app` является \"Python-пакетом\" (коллекцией \"Python-модулей\"): `app`.\n* Он содержит файл `app/main.py`. Данный файл является частью Python-пакета (т.е. находится внутри каталога, содержащего файл `__init__.py`), и, соответственно, он является модулем этого пакета: `app.main`.\n* Он также содержит файл `app/dependencies.py`, который также, как и `app/main.py`, является модулем: `app.dependencies`.\n* Здесь также находится подкаталог `app/routers/`, содержащий `__init__.py`. Он является Python-подпакетом: `app.routers`.\n* Файл `app/routers/items.py` находится внутри пакета `app/routers/`. Таким образом, он является подмодулем: `app.routers.items`.\n* Точно так же `app/routers/users.py` является ещё одним подмодулем: `app.routers.users`.\n* Подкаталог `app/internal/`, содержащий файл `__init__.py`, является ещё одним Python-подпакетом: `app.internal`.\n* А файл `app/internal/admin.py` является ещё одним подмодулем: `app.internal.admin`.\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\nТа же самая файловая структура приложения, но с комментариями:\n\n```bash\n.\n├── app                  # \"app\" пакет\n│   ├── __init__.py      # этот файл превращает \"app\" в \"Python-пакет\"\n│   ├── main.py          # модуль \"main\", напр.: import app.main\n│   ├── dependencies.py  # модуль \"dependencies\", напр.: import app.dependencies\n│   └── routers          # подпакет \"routers\"\n│   │   ├── __init__.py  # превращает \"routers\" в подпакет\n│   │   ├── items.py     # подмодуль \"items\", напр.: import app.routers.items\n│   │   └── users.py     # подмодуль \"users\", напр.: import app.routers.users\n│   └── internal         # подпакет \"internal\"\n│       ├── __init__.py  # превращает \"internal\" в подпакет\n│       └── admin.py     # подмодуль \"admin\", напр.: import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\nДавайте предположим, что для работы с пользователями используется отдельный файл (подмодуль) `/app/routers/users.py`.\n\nВы хотите отделить *операции пути*, связанные с пользователями, от остального кода, чтобы сохранить порядок.\n\nНо это всё равно часть того же приложения/веб-API на **FastAPI** (часть того же «Python-пакета»).\n\nС помощью `APIRouter` вы можете создать *операции пути* для этого модуля.\n\n### Импорт `APIRouter` { #import-apirouter }\n\nТочно так же, как и в случае с классом `FastAPI`, вам нужно импортировать и создать его «экземпляр»:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### *Операции пути* с `APIRouter` { #path-operations-with-apirouter }\n\nИ затем вы используете его, чтобы объявить ваши *операции пути*.\n\nИспользуйте его так же, как вы использовали бы класс `FastAPI`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\nВы можете думать об `APIRouter` как об «мини-классе `FastAPI`».\n\nПоддерживаются все те же опции.\n\nВсе те же `parameters`, `responses`, `dependencies`, `tags` и т.д.\n\n/// tip | Подсказка\n\nВ данном примере, в качестве названия переменной используется `router`, но вы можете использовать любое другое имя.\n\n///\n\nМы собираемся подключить данный `APIRouter` к нашему основному приложению на `FastAPI`, но сначала давайте проверим зависимости и ещё один `APIRouter`.\n\n## Зависимости { #dependencies }\n\nМы видим, что нам понадобятся некоторые зависимости, которые будут использоваться в нескольких местах приложения.\n\nПоэтому мы поместим их в отдельный модуль `dependencies` (`app/dependencies.py`).\n\nТеперь мы воспользуемся простой зависимостью, чтобы прочитать кастомный HTTP-заголовок `X-Token`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | Подсказка\n\nДля простоты мы воспользовались выдуманным заголовком.\n\nВ реальных случаях для получения наилучших результатов используйте интегрированные [утилиты безопасности](security/index.md).\n\n///\n\n## Ещё один модуль с `APIRouter` { #another-module-with-apirouter }\n\nДавайте также предположим, что у вас есть эндпоинты, отвечающие за обработку «items» в вашем приложении, и они находятся в модуле `app/routers/items.py`.\n\nУ вас определены *операции пути* для:\n\n* `/items/`\n* `/items/{item_id}`\n\nТут всё та же структура, как и в случае с `app/routers/users.py`.\n\nНо мы хотим поступить умнее и слегка упростить код.\n\nМы знаем, что все *операции пути* этого модуля имеют одинаковые:\n\n* `prefix` пути: `/items`.\n* `tags`: (один единственный тег: `items`).\n* Дополнительные `responses`.\n* `dependencies`: всем им нужна та зависимость `X-Token`, которую мы создали.\n\nТаким образом, вместо того чтобы добавлять всё это в каждую *операцию пути*, мы можем добавить это в `APIRouter`.\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\nТак как путь каждой *операции пути* должен начинаться с `/`, как здесь:\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n...то префикс не должен заканчиваться символом `/`.\n\nВ нашем случае префиксом является `/items`.\n\nМы также можем добавить список `tags` и дополнительные `responses`, которые будут применяться ко всем *операциям пути*, включённым в этот маршрутизатор.\n\nИ ещё мы можем добавить список `dependencies`, которые будут добавлены ко всем *операциям пути* в маршрутизаторе и будут выполняться/разрешаться для каждого HTTP-запроса к ним.\n\n/// tip | Подсказка\n\nОбратите внимание, что так же, как и в случае с [зависимостями в декораторах *операций пути*](dependencies/dependencies-in-path-operation-decorators.md), никакое значение не будет передано в вашу *функцию-обработчик пути*.\n\n///\n\nВ результате пути для items теперь такие:\n\n* `/items/`\n* `/items/{item_id}`\n\n...как мы и планировали.\n\n* Они будут помечены списком тегов, содержащим одну строку `\"items\"`.\n    * Эти «теги» особенно полезны для систем автоматической интерактивной документации (с использованием OpenAPI).\n* Все они будут включать предопределённые `responses`.\n* Все эти *операции пути* будут иметь список `dependencies`, вычисляемых/выполняемых перед ними.\n    * Если вы также объявите зависимости в конкретной *операции пути*, **они тоже будут выполнены**.\n    * Сначала выполняются зависимости маршрутизатора, затем [`dependencies` в декораторе](dependencies/dependencies-in-path-operation-decorators.md), и затем обычные параметрические зависимости.\n    * Вы также можете добавить [`Security`-зависимости с `scopes`](../advanced/security/oauth2-scopes.md).\n\n/// tip | Подсказка\n\nНапример, с помощью зависимостей в `APIRouter` мы можем потребовать аутентификации для доступа ко всей группе *операций пути*. Даже если зависимости не добавляются по отдельности к каждой из них.\n\n///\n\n/// check | Заметка\n\nПараметры `prefix`, `tags`, `responses` и `dependencies` — это (как и во многих других случаях) просто возможность **FastAPI**, помогающая избежать дублирования кода.\n\n///\n\n### Импорт зависимостей { #import-the-dependencies }\n\nЭтот код находится в модуле `app.routers.items`, в файле `app/routers/items.py`.\n\nИ нам нужно получить функцию зависимости из модуля `app.dependencies`, файла `app/dependencies.py`.\n\nПоэтому мы используем относительный импорт с `..` для зависимостей:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### Как работает относительный импорт { #how-relative-imports-work }\n\n/// tip | Подсказка\n\nЕсли вы прекрасно знаете, как работает импорт, переходите к следующему разделу ниже.\n\n///\n\nОдна точка `.`, как здесь:\n\n```Python\nfrom .dependencies import get_token_header\n```\n\nозначает:\n\n* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...\n* найти модуль `dependencies` (воображаемый файл `app/routers/dependencies.py`)...\n* и импортировать из него функцию `get_token_header`.\n\nНо такого файла не существует, наши зависимости находятся в файле `app/dependencies.py`.\n\nВспомните, как выглядит файловая структура нашего приложения:\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\nДве точки `..`, как здесь:\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\nозначают:\n\n* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...\n* перейти в родительский пакет (каталог `app/`)...\n* и там найти модуль `dependencies` (файл `app/dependencies.py`)...\n* и импортировать из него функцию `get_token_header`.\n\nЭто работает корректно! 🎉\n\n---\n\nАналогично, если бы мы использовали три точки `...`, как здесь:\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\nто это бы означало:\n\n* Начать в том же пакете, в котором находится этот модуль (файл `app/routers/items.py`) расположен в (каталоге `app/routers/`)...\n* перейти в родительский пакет (каталог `app/`)...\n* затем перейти в родительский пакет этого пакета (родительского пакета нет, `app` — верхний уровень 😱)...\n* и там найти модуль `dependencies` (файл `app/dependencies.py`)...\n* и импортировать из него функцию `get_token_header`.\n\nЭто ссылалось бы на какой-то пакет выше `app/`, со своим файлом `__init__.py` и т.п. Но у нас такого нет. Поэтому это вызвало бы ошибку в нашем примере. 🚨\n\nНо теперь вы знаете, как это работает, так что можете использовать относительные импорты в своих приложениях, независимо от того, насколько они сложные. 🤓\n\n### Добавление пользовательских `tags`, `responses` и `dependencies` { #add-some-custom-tags-responses-and-dependencies }\n\nМы не добавляем префикс `/items` и `tags=[\"items\"]` к каждой *операции пути*, потому что мы добавили их в `APIRouter`.\n\nНо мы всё равно можем добавить _ещё_ `tags`, которые будут применяться к конкретной *операции пути*, а также дополнительные `responses`, специфичные для этой *операции пути*:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | Подсказка\n\nЭта последняя операция пути будет иметь комбинацию тегов: `[\"items\", \"custom\"]`.\n\nИ в документации у неё будут оба ответа: один для `404` и один для `403`.\n\n///\n\n## Модуль main в `FastAPI` { #the-main-fastapi }\n\nТеперь давайте посмотрим на модуль `app/main.py`.\n\nИменно сюда вы импортируете и именно здесь вы используете класс `FastAPI`.\n\nЭто основной файл вашего приложения, который связывает всё воедино.\n\nИ так как большая часть вашей логики теперь будет находиться в отдельных специфичных модулях, основной файл будет довольно простым.\n\n### Импорт `FastAPI` { #import-fastapi }\n\nВы импортируете и создаёте класс `FastAPI` как обычно.\n\nИ мы даже можем объявить [глобальные зависимости](dependencies/global-dependencies.md), которые будут объединены с зависимостями для каждого `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### Импорт `APIRouter` { #import-the-apirouter }\n\nТеперь мы импортируем другие подмодули, содержащие `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\nТак как файлы `app/routers/users.py` и `app/routers/items.py` являются подмодулями, входящими в один и тот же Python-пакет `app`, мы можем использовать одну точку `.` для импорта через «относительные импорты».\n\n### Как работает импорт { #how-the-importing-works }\n\nЭтот фрагмент:\n\n```Python\nfrom .routers import items, users\n```\n\nозначает:\n\n* Начать в том же пакете, в котором находится этот модуль (файл `app/main.py`) расположен в (каталоге `app/`)...\n* найти подпакет `routers` (каталог `app/routers/`)...\n* и импортировать из него подмодули `items` (файл `app/routers/items.py`) и `users` (файл `app/routers/users.py`)...\n\nВ модуле `items` будет переменная `router` (`items.router`). Это та же самая, которую мы создали в файле `app/routers/items.py`, это объект `APIRouter`.\n\nИ затем мы делаем то же самое для модуля `users`.\n\nМы также могли бы импортировать их так:\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info | Примечание\n\nПервая версия — это «относительный импорт»:\n\n```Python\nfrom .routers import items, users\n```\n\nВторая версия — это «абсолютный импорт»:\n\n```Python\nfrom app.routers import items, users\n```\n\nЧтобы узнать больше о Python-пакетах и модулях, прочитайте [официальную документацию Python о модулях](https://docs.python.org/3/tutorial/modules.html).\n\n///\n\n### Избегайте конфликтов имён { #avoid-name-collisions }\n\nМы импортируем подмодуль `items` напрямую, вместо того чтобы импортировать только его переменную `router`.\n\nЭто потому, что у нас также есть другая переменная с именем `router` в подмодуле `users`.\n\nЕсли бы мы импортировали их одну за другой, как здесь:\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\nто `router` из `users` перезаписал бы `router` из `items`, и мы не смогли бы использовать их одновременно.\n\nПоэтому, чтобы иметь возможность использовать обе в одном файле, мы импортируем подмодули напрямую:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### Подключение `APIRouter` для `users` и `items` { #include-the-apirouters-for-users-and-items }\n\nТеперь давайте подключим `router` из подмодулей `users` и `items`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info | Примечание\n\n`users.router` содержит `APIRouter` из файла `app/routers/users.py`.\n\nА `items.router` содержит `APIRouter` из файла `app/routers/items.py`.\n\n///\n\nС помощью `app.include_router()` мы можем добавить каждый `APIRouter` в основное приложение `FastAPI`.\n\nОн включит все маршруты этого маршрутизатора как часть приложения.\n\n/// note | Технические детали\n\nФактически, внутри он создаст *операцию пути* для каждой *операции пути*, объявленной в `APIRouter`.\n\nТак что под капотом всё будет работать так, как будто всё было одним приложением.\n\n///\n\n/// check | Заметка\n\nПри подключении маршрутизаторов не нужно беспокоиться о производительности.\n\nЭто займёт микросекунды и произойдёт только при старте.\n\nТак что это не повлияет на производительность. ⚡\n\n///\n\n### Подключение `APIRouter` с пользовательскими `prefix`, `tags`, `responses` и `dependencies` { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\nТеперь давайте представим, что ваша организация передала вам файл `app/internal/admin.py`.\n\nОн содержит `APIRouter` с некоторыми административными *операциями пути*, которые ваша организация использует в нескольких проектах.\n\nДля этого примера всё будет очень просто. Но допустим, что поскольку он используется совместно с другими проектами в организации, мы не можем модифицировать его и добавить `prefix`, `dependencies`, `tags` и т.д. непосредственно в `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nНо мы всё равно хотим задать пользовательский `prefix` при подключении `APIRouter`, чтобы все его *операции пути* начинались с `/admin`, хотим защитить его с помощью `dependencies`, которые у нас уже есть для этого проекта, и хотим включить `tags` и `responses`.\n\nМы можем объявить всё это, не изменяя исходный `APIRouter`, передав эти параметры в `app.include_router()`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\nТаким образом исходный `APIRouter` не будет модифицирован, и мы сможем использовать файл `app/internal/admin.py` сразу в нескольких проектах организации.\n\nВ результате в нашем приложении каждая из *операций пути* из модуля `admin` будет иметь:\n\n* Префикс `/admin`.\n* Тег `admin`.\n* Зависимость `get_token_header`.\n* Ответ `418`. 🍵\n\nНо это повлияет только на этот `APIRouter` в нашем приложении, а не на любой другой код, который его использует.\n\nТак что, например, другие проекты могут использовать тот же `APIRouter` с другим методом аутентификации.\n\n### Подключение *операции пути* { #include-a-path-operation }\n\nМы также можем добавлять *операции пути* напрямую в приложение `FastAPI`.\n\nЗдесь мы делаем это... просто чтобы показать, что можем 🤷:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\nи это будет работать корректно вместе со всеми другими *операциями пути*, добавленными через `app.include_router()`.\n\n/// info | Очень технические детали\n\n**Примечание**: это очень техническая деталь, которую, вероятно, можно **просто пропустить**.\n\n---\n\n`APIRouter` не «монтируются», они не изолированы от остального приложения.\n\nЭто потому, что мы хотим включить их *операции пути* в OpenAPI-схему и пользовательские интерфейсы.\n\nТак как мы не можем просто изолировать их и «смонтировать» независимо от остального, *операции пути* «клонируются» (пересоздаются), а не включаются напрямую.\n\n///\n\n## Настройка `entrypoint` в `pyproject.toml` { #configure-the-entrypoint-in-pyproject-toml }\n\nТак как ваш объект FastAPI `app` находится в `app/main.py`, вы можете настроить `entrypoint` в файле `pyproject.toml` следующим образом:\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\nэто эквивалентно импорту:\n\n```python\nfrom app.main import app\n```\n\nТаким образом, команда `fastapi` будет знать, где найти ваше приложение.\n\n/// Note | Примечание\n\nВы также можете передать путь в команду, например:\n\n```console\n$ fastapi dev app/main.py\n```\n\nНо вам придётся каждый раз помнить и указывать корректный путь при вызове команды `fastapi`.\n\nКроме того, другие инструменты могут не суметь его найти, например [расширение VS Code](../editor-support.md) или [FastAPI Cloud](https://fastapicloud.com), поэтому рекомендуется использовать `entrypoint` в `pyproject.toml`.\n\n///\n\n## Проверка автоматической документации API { #check-the-automatic-api-docs }\n\nТеперь запустите приложение:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nОткройте документацию по адресу [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВы увидите автоматическую документацию API, включая пути из всех подмодулей, с использованием корректных путей (и префиксов) и корректных тегов:\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## Подключение одного и того же маршрутизатора несколько раз с разными `prefix` { #include-the-same-router-multiple-times-with-different-prefix }\n\nВы можете использовать `.include_router()` несколько раз с *одним и тем же* маршрутизатором, используя разные префиксы.\n\nЭто может быть полезно, например, чтобы предоставить доступ к одному и тому же API с разными префиксами, например `/api/v1` и `/api/latest`.\n\nЭто продвинутое использование, которое вам может и не понадобиться, но оно есть на случай, если понадобится.\n\n## Подключение `APIRouter` в другой `APIRouter` { #include-an-apirouter-in-another }\n\nТочно так же, как вы можете подключить `APIRouter` к приложению `FastAPI`, вы можете подключить `APIRouter` к другому `APIRouter`, используя:\n\n```Python\nrouter.include_router(other_router)\n```\n\nУбедитесь, что вы сделали это до подключения `router` к приложению `FastAPI`, чтобы *операции пути* из `other_router` также были подключены.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/body-fields.md",
    "content": "# Body - Поля { #body-fields }\n\nТаким же способом, как вы объявляете дополнительную валидацию и метаданные в параметрах *функции обработки пути* с помощью функций `Query`, `Path` и `Body`, вы можете объявлять валидацию и метаданные внутри Pydantic моделей, используя функцию `Field` из Pydantic.\n\n## Импорт `Field` { #import-field }\n\nСначала вы должны импортировать его:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n/// warning | Внимание\n\nОбратите внимание, что функция `Field` импортируется непосредственно из `pydantic`, а не из `fastapi`, как все остальные функции (`Query`, `Path`, `Body` и т.д.).\n\n///\n\n## Объявление атрибутов модели { #declare-model-attributes }\n\nВы можете использовать функцию `Field` с атрибутами модели:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\nФункция `Field` работает так же, как `Query`, `Path` и `Body`, у неё такие же параметры и т.д.\n\n/// note | Технические детали\n\nНа самом деле, `Query`, `Path` и другие функции, которые вы увидите в дальнейшем, создают объекты подклассов общего класса `Param`, который сам по себе является подклассом `FieldInfo` из Pydantic.\n\nИ `Field` (из Pydantic) также возвращает экземпляр `FieldInfo`.\n\n`Body` также напрямую возвращает объекты подкласса `FieldInfo`. И есть и другие, с которыми вы познакомитесь позже, которые являются подклассами класса `Body`.\n\nПомните, что когда вы импортируете `Query`, `Path` и другое из `fastapi`, это фактически функции, которые возвращают специальные классы.\n\n///\n\n/// tip | Подсказка\n\nОбратите внимание, что каждый атрибут модели с типом, значением по умолчанию и `Field` имеет ту же структуру, что и параметр *функции обработки пути* с `Field` вместо `Path`, `Query` и `Body`.\n\n///\n\n## Добавление дополнительной информации { #add-extra-information }\n\nВы можете объявлять дополнительную информацию в `Field`, `Query`, `Body` и т.п. Она будет включена в сгенерированную JSON схему.\n\nВы узнаете больше о добавлении дополнительной информации позже в документации, когда будете изучать, как задавать примеры.\n\n/// warning | Внимание\n\nДополнительные ключи, переданные в функцию `Field`, также будут присутствовать в сгенерированной OpenAPI схеме вашего приложения.\nПоскольку эти ключи не являются обязательной частью спецификации OpenAPI, некоторые инструменты OpenAPI, например, [валидатор OpenAPI](https://validator.swagger.io/), могут не работать с вашей сгенерированной схемой.\n\n///\n\n## Резюме { #recap }\n\nВы можете использовать функцию `Field` из Pydantic, чтобы задавать дополнительную валидацию и метаданные для атрибутов модели.\n\nВы также можете использовать дополнительные ключевые аргументы, чтобы добавить метаданные JSON схемы.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/body-multiple-params.md",
    "content": "# Body - Множество параметров { #body-multiple-parameters }\n\nТеперь, когда мы увидели, как использовать `Path` и `Query` параметры, давайте рассмотрим более продвинутые примеры объявления тела запроса.\n\n## Объединение `Path`, `Query` и параметров тела запроса { #mix-path-query-and-body-parameters }\n\nВо-первых, конечно, вы можете объединять параметры `Path`, `Query` и объявления тела запроса в своих функциях обработки, **FastAPI** автоматически определит, что с ними нужно делать.\n\nВы также можете объявить параметры тела запроса как необязательные, установив значение по умолчанию, равное `None`:\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | Заметка\n\nЗаметьте, что в данном случае параметр `item`, который будет взят из тела запроса, необязателен. Так как было установлено значение `None` по умолчанию.\n\n///\n\n## Несколько параметров тела запроса { #multiple-body-parameters }\n\nВ предыдущем примере, *операции пути* ожидали тело запроса в формате JSON, с параметрами, соответствующими атрибутам `Item`, например:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\nНо вы также можете объявить множество параметров тела запроса, например `item` и `user`:\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\nВ этом случае **FastAPI** заметит, что в функции есть более одного параметра тела (два параметра, которые являются Pydantic-моделями).\n\nТаким образом, имена параметров будут использоваться в качестве ключей (имён полей) в теле запроса, и будет ожидаться запрос следующего формата:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | Заметка\n\nОбратите внимание, что хотя параметр `item` был объявлен таким же способом, как и раньше, теперь предполагается, что он находится внутри тела с ключом `item`.\n\n///\n\n**FastAPI** сделает автоматическое преобразование из запроса, так что параметр `item` получит своё конкретное содержимое, и то же самое происходит с пользователем `user`.\n\nПроизойдёт проверка составных данных, и создание документации в схеме OpenAPI и автоматических документах.\n\n## Отдельные значения в теле запроса { #singular-values-in-body }\n\nТочно так же, как `Query` и `Path` используются для определения дополнительных данных для query и path параметров, **FastAPI** предоставляет аналогичный инструмент - `Body`.\n\nНапример, расширяя предыдущую модель, вы можете решить, что вам нужен еще один ключ `importance` в том же теле запроса, помимо параметров `item` и `user`.\n\nЕсли вы объявите его без указания, какой именно объект (Path, Query, Body и т.п.) ожидаете, то, поскольку это является простым типом данных, **FastAPI** будет считать, что это query-параметр.\n\nНо вы можете указать **FastAPI** обрабатывать его, как ещё один ключ тела запроса, используя `Body`:\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\nВ этом случае, **FastAPI** будет ожидать тело запроса в формате:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\nИ всё будет работать так же - преобразование типов данных, валидация, документирование и т.д.\n\n## Множество body и query параметров { #multiple-body-params-and-query }\n\nКонечно, вы также можете объявлять query-параметры в любое время, дополнительно к любым body-параметрам.\n\nПоскольку по умолчанию, отдельные значения интерпретируются как query-параметры, вам не нужно явно добавлять `Query`, вы можете просто сделать так:\n\n```Python\nq: str | None = None\n```\n\nНапример:\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n/// info | Информация\n\n`Body` также имеет все те же дополнительные параметры валидации и метаданных, как у `Query`, `Path` и других, которые вы увидите позже.\n\n///\n\n## Вложить один body-параметр { #embed-a-single-body-parameter }\n\nПредположим, у вас есть только один body-параметр `item` из Pydantic-модели `Item`.\n\nПо умолчанию, **FastAPI** ожидает получить тело запроса напрямую.\n\nНо если вы хотите чтобы он ожидал JSON с ключом `item` с содержимым модели внутри, также как это происходит при объявлении дополнительных body-параметров, вы можете использовать специальный параметр `embed` у типа `Body`:\n\n```Python\nitem: Item = Body(embed=True)\n```\n\nтак же, как в этом примере:\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\nВ этом случае **FastAPI** будет ожидать тело запроса в формате:\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\nвместо этого:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## Резюме { #recap }\n\nВы можете добавлять несколько body-параметров вашей *функции-обработчика пути*, несмотря даже на то, что запрос может содержать только одно тело.\n\nНо **FastAPI** справится с этим, предоставит правильные данные в вашей функции, а также сделает валидацию и документацию правильной схемы *операции пути*.\n\nВы также можете объявить отдельные значения для получения в рамках тела запроса.\n\nИ вы можете настроить **FastAPI** таким образом, чтобы включить тело запроса в ключ, даже если объявлен только один параметр.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/body-nested-models.md",
    "content": "# Body - Вложенные модели { #body-nested-models }\n\nС помощью **FastAPI** вы можете определять, валидировать, документировать и использовать модели произвольной глубины вложенности (благодаря Pydantic).\n\n## Поля-списки { #list-fields }\n\nВы можете определить атрибут как подтип. Например, Python-тип `list`:\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\nЭто приведёт к тому, что `tags` будет списком, несмотря на то, что тип его элементов не объявлен.\n\n## Поля-списки с параметром типа { #list-fields-with-type-parameter }\n\nВ Python есть специальный способ объявлять списки с внутренними типами, или «параметрами типа»:\n\n### Объявите `list` с параметром типа { #declare-a-list-with-a-type-parameter }\n\nДля объявления типов, у которых есть параметры типа (внутренние типы), таких как `list`, `dict`, `tuple`, передайте внутренний(ие) тип(ы) как «параметры типа», используя квадратные скобки: `[` и `]`\n\n```Python\nmy_list: list[str]\n```\n\nЭто всё стандартный синтаксис Python для объявления типов.\n\nИспользуйте этот же стандартный синтаксис для атрибутов модели с внутренними типами.\n\nТаким образом, в нашем примере мы можем явно указать тип данных для поля `tags` как «список строк»:\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## Типы множеств { #set-types }\n\nНо затем мы подумали и поняли, что теги не должны повторяться, вероятно, это должны быть уникальные строки.\n\nИ в Python есть специальный тип данных для множеств уникальных элементов — `set`.\n\nТогда мы можем объявить поле `tags` как множество строк:\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\nС помощью этого, даже если вы получите запрос с повторяющимися данными, они будут преобразованы в множество уникальных элементов.\n\nИ когда вы выводите эти данные, даже если исходный набор содержал дубликаты, они будут выведены в виде множества уникальных элементов.\n\nИ они также будут соответствующим образом аннотированы / задокументированы.\n\n## Вложенные модели { #nested-models }\n\nУ каждого атрибута Pydantic-модели есть тип.\n\nНо этот тип сам может быть другой моделью Pydantic.\n\nТаким образом, вы можете объявлять глубоко вложенные JSON «объекты» с определёнными именами атрибутов, типами и валидацией.\n\nВсё это может быть произвольно вложенным.\n\n### Определение подмодели { #define-a-submodel }\n\nНапример, мы можем определить модель `Image`:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### Использование подмодели как типа { #use-the-submodel-as-a-type }\n\nТакже мы можем использовать эту модель как тип атрибута:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\nЭто означает, что **FastAPI** будет ожидать тело запроса, аналогичное этому:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\nЕщё раз: сделав такое объявление, с помощью **FastAPI** вы получите:\n\n* Поддержку редактора кода (автозавершение и т.д.), даже для вложенных моделей\n* Преобразование данных\n* Валидацию данных\n* Автоматическую документацию\n\n## Особые типы и валидация { #special-types-and-validation }\n\nПомимо обычных простых типов, таких как `str`, `int`, `float` и т.д., вы можете использовать более сложные простые типы, которые наследуются от `str`.\n\nЧтобы увидеть все варианты, которые у вас есть, ознакомьтесь с [обзором типов Pydantic](https://docs.pydantic.dev/latest/concepts/types/). Вы увидите некоторые примеры в следующей главе.\n\nНапример, так как в модели `Image` у нас есть поле `url`, то мы можем объявить его как тип `HttpUrl` из Pydantic вместо типа `str`:\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\nСтрока будет проверена на соответствие допустимому URL-адресу и задокументирована в JSON Schema / OpenAPI как таковая.\n\n## Атрибуты, содержащие списки подмоделей { #attributes-with-lists-of-submodels }\n\nВы также можете использовать модели Pydantic в качестве подтипов для `list`, `set` и т.д.:\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\nТакая реализация будет ожидать (конвертировать, валидировать, документировать и т.д.) JSON-содержимое в следующем формате:\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info | Информация\n\nЗаметьте, что теперь у ключа `images` есть список объектов изображений.\n\n///\n\n## Глубоко вложенные модели { #deeply-nested-models }\n\nВы можете определять модели с произвольным уровнем вложенности:\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info | Информация\n\nЗаметьте, что у объекта `Offer` есть список объектов `Item`, которые, в свою очередь, могут содержать необязательный список объектов `Image`\n\n///\n\n## Тела с чистыми списками элементов { #bodies-of-pure-lists }\n\nЕсли верхний уровень значения тела JSON-объекта представляет собой JSON `array` (в Python — `list`), вы можете объявить тип в параметре функции, так же как в моделях Pydantic:\n\n```Python\nimages: list[Image]\n```\n\nнапример так:\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## Поддержка редактора кода везде { #editor-support-everywhere }\n\nИ вы получаете поддержку редактора кода везде.\n\nДаже для элементов внутри списков:\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\nВы не могли бы получить такую поддержку редактора кода, если бы работали напрямую с `dict`, а не с моделями Pydantic.\n\nНо вы также не должны беспокоиться об этом, входящие словари автоматически конвертируются, а ваш вывод также автоматически преобразуется в формат JSON.\n\n## Тела запросов с произвольными словарями (`dict`) { #bodies-of-arbitrary-dicts }\n\nВы также можете объявить тело запроса как `dict` с ключами определённого типа и значениями другого типа.\n\nБез необходимости знать заранее, какие значения являются допустимыми для имён полей/атрибутов (как это было бы в случае с моделями Pydantic).\n\nЭто было бы полезно, если вы хотите получить ключи, которые вы ещё не знаете.\n\n---\n\nДругой полезный случай — когда вы хотите, чтобы ключи были другого типа данных, например, `int`.\n\nИменно это мы сейчас и увидим здесь.\n\nВ этом случае вы принимаете любой `dict`, пока у него есть ключи типа `int` со значениями типа `float`:\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip | Совет\n\nИмейте в виду, что JSON поддерживает только ключи типа `str`.\n\nНо Pydantic обеспечивает автоматическое преобразование данных.\n\nЭто значит, что даже если клиенты вашего API могут отправлять только строки в качестве ключей, при условии, что эти строки содержат целые числа, Pydantic автоматически преобразует и валидирует эти данные.\n\nА `dict`, который вы получите как `weights`, действительно будет иметь ключи типа `int` и значения типа `float`.\n\n///\n\n## Резюме { #recap }\n\nС помощью **FastAPI** вы получаете максимальную гибкость, предоставляемую моделями Pydantic, сохраняя при этом простоту, краткость и элегантность вашего кода.\n\nИ дополнительно вы получаете:\n\n* Поддержку редактора кода (автозавершение доступно везде!)\n* Преобразование данных (также известно как парсинг / сериализация)\n* Валидацию данных\n* Документацию схемы данных\n* Автоматическую генерацию документации\n"
  },
  {
    "path": "docs/ru/docs/tutorial/body-updates.md",
    "content": "# Тело запроса - Обновления { #body-updates }\n\n## Обновление с заменой при помощи `PUT` { #update-replacing-with-put }\n\nЧтобы обновить элемент, вы можете использовать операцию [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT).\n\nВы можете использовать `jsonable_encoder`, чтобы преобразовать входные данные в данные, которые можно сохранить как JSON (например, в NoSQL-базе данных). Например, преобразование `datetime` в `str`.\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT` используется для получения данных, которые должны заменить существующие данные.\n\n### Предупреждение о замене { #warning-about-replacing }\n\nЭто означает, что если вы хотите обновить элемент `bar`, используя `PUT` с телом, содержащим:\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\nпоскольку оно не включает уже сохраненный атрибут `\"tax\": 20.2`, входная модель примет значение по умолчанию `\"tax\": 10.5`.\n\nИ данные будут сохранены с этим «новым» `tax`, равным `10.5`.\n\n## Частичное обновление с помощью `PATCH` { #partial-updates-with-patch }\n\nТакже можно использовать операцию [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) для частичного обновления данных.\n\nЭто означает, что можно передавать только те данные, которые необходимо обновить, оставляя остальные нетронутыми.\n\n/// note | Примечание\n\n`PATCH` менее распространен и известен, чем `PUT`.\n\nА многие команды используют только `PUT`, даже для частичного обновления.\n\nВы можете **свободно** использовать их как угодно, **FastAPI** не накладывает никаких ограничений.\n\nНо в данном руководстве более или менее понятно, как они должны использоваться.\n\n///\n\n### Использование параметра `exclude_unset` в Pydantic { #using-pydantics-exclude-unset-parameter }\n\nЕсли вы хотите получать частичные обновления, очень полезно использовать параметр `exclude_unset` в `.model_dump()` модели Pydantic.\n\nНапример, `item.model_dump(exclude_unset=True)`.\n\nВ результате будет сгенерирован `dict`, содержащий только те данные, которые были заданы при создании модели `item`, без учета значений по умолчанию.\n\nЗатем вы можете использовать это для создания `dict` только с теми данными, которые были установлены (отправлены в запросе), опуская значения по умолчанию:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### Использование параметра `update` в Pydantic { #using-pydantics-update-parameter }\n\nТеперь можно создать копию существующей модели, используя `.model_copy()`, и передать параметр `update` с `dict`, содержащим данные для обновления.\n\nНапример, `stored_item_model.model_copy(update=update_data)`:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### Кратко о частичном обновлении { #partial-updates-recap }\n\nВ целом, для применения частичных обновлений необходимо:\n\n* (Опционально) использовать `PATCH` вместо `PUT`.\n* Извлечь сохранённые данные.\n* Поместить эти данные в Pydantic-модель.\n* Сгенерировать `dict` без значений по умолчанию из входной модели (с использованием `exclude_unset`).\n    * Таким образом, можно обновлять только те значения, которые действительно установлены пользователем, вместо того чтобы переопределять уже сохраненные значения значениями по умолчанию из вашей модели.\n* Создать копию хранимой модели, обновив ее атрибуты полученными частичными обновлениями (с помощью параметра `update`).\n* Преобразовать скопированную модель в то, что может быть сохранено в вашей БД (например, с помощью `jsonable_encoder`).\n    * Это сравнимо с повторным использованием метода модели `.model_dump()`, но при этом происходит проверка (и преобразование) значений в типы данных, которые могут быть преобразованы в JSON, например, `datetime` в `str`.\n* Сохранить данные в своей БД.\n* Вернуть обновленную модель.\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | Подсказка\n\nНа самом деле эту же технику можно использовать и для операции HTTP `PUT`.\n\nНо в приведенном примере используется `PATCH`, поскольку он был создан именно для таких случаев использования.\n\n///\n\n/// note | Примечание\n\nОбратите внимание, что входная модель по-прежнему валидируется.\n\nТаким образом, если вы хотите получать частичные обновления, в которых могут быть опущены все атрибуты, вам необходимо иметь модель, в которой все атрибуты помечены как необязательные (со значениями по умолчанию или `None`).\n\nЧтобы отличить модели со всеми необязательными значениями для обновления и модели с обязательными значениями для создания, можно воспользоваться идеями, описанными в [Дополнительные модели](extra-models.md).\n\n///\n"
  },
  {
    "path": "docs/ru/docs/tutorial/body.md",
    "content": "# Тело запроса { #request-body }\n\nКогда вам необходимо отправить данные из клиента (например, браузера) в ваш API, вы отправляете их как **тело запроса**.\n\nТело **запроса** — это данные, отправляемые клиентом в ваш API. Тело **ответа** — это данные, которые ваш API отправляет клиенту.\n\nВаш API почти всегда должен отправлять тело **ответа**. Но клиентам не обязательно всегда отправлять **тело запроса**: иногда они запрашивают только путь, возможно с некоторыми параметрами запроса, но без тела.\n\nЧтобы объявить тело **запроса**, используйте модели [Pydantic](https://docs.pydantic.dev/), со всей их мощью и преимуществами.\n\n/// info | Информация\n\nЧтобы отправить данные, используйте один из методов: `POST` (чаще всего), `PUT`, `DELETE` или `PATCH`.\n\nОтправка тела с запросом `GET` имеет неопределённое поведение в спецификациях, тем не менее это поддерживается FastAPI, но только для очень сложных/крайних случаев использования.\n\nПоскольку это не рекомендуется, интерактивная документация со Swagger UI не будет отображать информацию для тела при использовании `GET`, а промежуточные прокси-серверы могут не поддерживать такой вариант запроса.\n\n///\n\n## Импортируйте `BaseModel` из Pydantic { #import-pydantics-basemodel }\n\nПервое, что нужно сделать, — импортировать `BaseModel` из пакета `pydantic`:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## Создайте модель данных { #create-your-data-model }\n\nЗатем опишите свою модель данных как класс, наследующийся от `BaseModel`.\n\nИспользуйте стандартные типы Python для всех атрибутов:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\n\nТак же, как при объявлении параметров запроса: когда атрибут модели имеет значение по умолчанию, он не обязателен. Иначе он обязателен. Используйте `None`, чтобы сделать его просто необязательным.\n\nНапример, модель выше описывает такой JSON \"`object`\" (или Python `dict`):\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n...так как `description` и `tax` являются необязательными (со значением по умолчанию `None`), такой JSON \"`object`\" тоже будет корректным:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## Объявите её как параметр { #declare-it-as-a-parameter }\n\nЧтобы добавить её в вашу *операцию пути*, объявите её так же, как вы объявляли параметры пути и параметры запроса:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n...и укажите тип параметра как созданную вами модель, `Item`.\n\n## Результаты { #results }\n\nВсего лишь с этой аннотацией типов Python **FastAPI**:\n\n* Считает тело запроса как JSON.\n* Приведёт данные к соответствующим типам (если потребуется).\n* Проведёт валидацию данных.\n    * Если данные некорректны, вернёт понятную и наглядную ошибку, указывающую, где именно и что было некорректно.\n* Передаст полученные данные в параметр `item`.\n    * Поскольку внутри функции вы объявили его с типом `Item`, у вас будет поддержка со стороны редактора кода (автозавершение и т.п.) для всех атрибутов и их типов.\n* Сгенерирует определения [JSON Schema](https://json-schema.org) для вашей модели; вы можете использовать их и в других местах, если это имеет смысл для вашего проекта.\n* Эти схемы будут частью сгенерированной схемы OpenAPI и будут использоваться автоматической документацией <abbr title=\"User Interfaces - Пользовательские интерфейсы\">UIs</abbr>.\n\n## Автоматическая документация { #automatic-docs }\n\nJSON Schema ваших моделей будет частью сгенерированной схемы OpenAPI и будет отображаться в интерактивной документации API:\n\n<img src=\"/img/tutorial/body/image01.png\">\n\nА также они будут использоваться в документации API внутри каждой *операции пути*, где это требуется:\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## Поддержка редактора кода { #editor-support }\n\nВ вашем редакторе кода внутри функции вы получите подсказки по типам и автозавершение повсюду (этого бы не было, если бы вы получали `dict` вместо модели Pydantic):\n\n<img src=\"/img/tutorial/body/image03.png\">\n\nТакже вы получите проверку ошибок при некорректных операциях с типами:\n\n<img src=\"/img/tutorial/body/image04.png\">\n\nЭто не случайность — весь фреймворк построен вокруг такого дизайна.\n\nИ это было тщательно протестировано ещё на этапе проектирования, до реализации, чтобы убедиться, что всё будет работать со всеми редакторами.\n\nВ сам Pydantic даже были внесены некоторые изменения для поддержки этого.\n\nПредыдущие скриншоты сделаны в [Visual Studio Code](https://code.visualstudio.com).\n\nНо вы получите такую же поддержку редактора кода в [PyCharm](https://www.jetbrains.com/pycharm/) и большинстве других редакторов Python:\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip | Совет\n\nЕсли вы используете [PyCharm](https://www.jetbrains.com/pycharm/) в качестве редактора кода, вы можете использовать плагин [Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/).\n\nОн улучшает поддержку моделей Pydantic в редакторе кода, включая:\n\n* автозавершение\n* проверки типов\n* рефакторинг\n* поиск\n* инспекции\n\n///\n\n## Использование модели { #use-the-model }\n\nВнутри функции вам доступны все атрибуты объекта модели напрямую:\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## Тело запроса + параметры пути { #request-body-path-parameters }\n\nВы можете одновременно объявить параметры пути и тело запроса.\n\n**FastAPI** распознает, что параметры функции, соответствующие параметрам пути, должны быть **получены из пути**, а параметры функции, объявленные как модели Pydantic, должны быть **получены из тела запроса**.\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n\n## Тело запроса + параметры пути + параметры запроса { #request-body-path-query-parameters }\n\nВы также можете одновременно объявить параметры **тела**, **пути** и **запроса**.\n\n**FastAPI** распознает каждый из них и возьмёт данные из правильного источника.\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\nПараметры функции будут распознаны следующим образом:\n\n* Если параметр также объявлен в **пути**, он будет использоваться как path-параметр.\n* Если параметр имеет **скалярный тип** (например, `int`, `float`, `str`, `bool` и т.п.), он будет интерпретирован как параметр **запроса**.\n* Если параметр объявлен как тип **модели Pydantic**, он будет интерпретирован как **тело** запроса.\n\n/// note | Заметка\n\nFastAPI понимает, что значение `q` не является обязательным из-за значения по умолчанию `= None`.\n\nАннотация типов `str | None` не используется FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`.\n\nНо добавление аннотаций типов позволит вашему редактору кода лучше вас поддерживать и обнаруживать ошибки.\n\n///\n\n## Без Pydantic { #without-pydantic }\n\nЕсли вы не хотите использовать модели Pydantic, вы также можете использовать параметры **Body**. См. раздел документации [Тело запроса - Несколько параметров: Единичные значения в теле](body-multiple-params.md#singular-values-in-body).\n"
  },
  {
    "path": "docs/ru/docs/tutorial/cookie-param-models.md",
    "content": "# Модели параметров cookie { #cookie-parameter-models }\n\nЕсли у вас есть группа **cookies**, которые связаны между собой, вы можете создать **Pydantic-модель** для их объявления. 🍪\n\nЭто позволит вам **переиспользовать модель** в **разных местах**, а также объявить проверки и метаданные сразу для всех параметров. 😎\n\n/// note | Заметка\n\nЭтот функционал доступен с версии `0.115.0`. 🤓\n\n///\n\n/// tip | Совет\n\nТакой же подход применяется для `Query`, `Cookie`, и `Header`. 😎\n\n///\n\n## Pydantic-модель для cookies { #cookies-with-a-pydantic-model }\n\nОбъявите параметры **cookie**, которые вам нужны, в **Pydantic-модели**, а затем объявите параметр как `Cookie`:\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI** **извлечёт** данные для **каждого поля** из **cookies**, полученных в запросе, и выдаст вам объявленную Pydantic-модель.\n\n## Проверка сгенерированной документации { #check-the-docs }\n\nВы можете посмотреть объявленные cookies в графическом интерфейсе Документации по пути `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info | Дополнительная информация\n\nИмейте в виду, что, поскольку **браузеры обрабатывают cookies** особым образом и под капотом, они **не** позволят **JavaScript** легко получить доступ к ним.\n\nЕсли вы перейдёте к **графическому интерфейсу документации API** по пути `/docs`, то сможете увидеть **документацию** по cookies для ваших *операций путей*.\n\nНо даже если вы **заполните данные** и нажмёте \"Execute\", поскольку графический интерфейс Документации работает с **JavaScript**, cookies не будут отправлены, и вы увидите сообщение об **ошибке** как будто не указывали никаких значений.\n\n///\n\n## Запрет дополнительных cookies { #forbid-extra-cookies }\n\nВ некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** cookies, которые вы хотите получать.\n\nТеперь у вашего API есть возможность контролировать своё <dfn title=\"Это шутка, на всякий случай. Это не имеет никакого отношения к согласию на использование cookie, но забавно, что даже API теперь может отклонять несчастные cookies. Съешьте печеньку. 🍪\">согласие на использование cookie</dfn>. 🤪🍪\n\nВы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) любые дополнительные (`extra`) поля:\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\nЕсли клиент попробует отправить **дополнительные cookies**, то в ответ он получит **ошибку**.\n\nБедные баннеры cookies, они всеми силами пытаются получить ваше согласие — и всё ради того, чтобы <dfn title=\"Это ещё одна шутка. Не обращайте на меня внимания. Выпейте кофе со своей печенькой. ☕\">API его отклонил</dfn>. 🍪\n\nНапример, если клиент попытается отправить cookie `santa_tracker` со значением `good-list-please`, то в ответ он получит **ошибку**, сообщающую ему, что `santa_tracker` <dfn title=\"Санта не одобряет пропажу печенья. 🎅 Ладно, больше никаких шуток про печенье.\">cookie не разрешён</dfn>:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## Заключение { #summary }\n\nВы можете использовать **Pydantic-модели** для объявления <dfn title=\"Съешьте последнюю печеньку, прежде чем уйти. 🍪\">**cookies**</dfn> в **FastAPI**. 😎\n"
  },
  {
    "path": "docs/ru/docs/tutorial/cookie-params.md",
    "content": "# Параметры Cookie { #cookie-parameters }\n\nВы можете задать параметры Cookie таким же способом, как `Query` и `Path` параметры.\n\n## Импорт `Cookie` { #import-cookie }\n\nСначала импортируйте `Cookie`:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## Объявление параметров `Cookie` { #declare-cookie-parameters }\n\nЗатем объявляйте параметры cookie, используя ту же структуру, что и с `Path` и `Query`.\n\nВы можете задать значение по умолчанию, а также все дополнительные параметры валидации или аннотации:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Технические детали\n\n`Cookie` - это класс, родственный `Path` и `Query`. Он также наследуется от общего класса `Param`.\n\nНо помните, что когда вы импортируете `Query`, `Path`, `Cookie` и другое из `fastapi`, это фактически функции, которые возвращают специальные классы.\n\n///\n\n/// info | Дополнительная информация\n\nДля объявления cookies, вам нужно использовать `Cookie`, иначе параметры будут интерпретированы как параметры запроса.\n\n///\n\n/// info | Дополнительная информация\n\nИмейте в виду, что, поскольку **браузеры обрабатывают cookies** особым образом и «за кулисами», они **не** позволяют **JavaScript** просто так получать к ним доступ.\n\nЕсли вы откроете **интерфейс документации API** на `/docs`, вы сможете увидеть **документацию** по cookies для ваших *операции пути*.\n\nНо даже если вы **заполните данные** и нажмёте «Execute», поскольку UI документации работает с **JavaScript**, cookies отправлены не будут, и вы увидите сообщение об **ошибке**, как будто вы не указали никаких значений.\n\n///\n\n## Резюме { #recap }\n\nОбъявляйте cookies с помощью `Cookie`, используя тот же общий шаблон, что и `Query`, и `Path`.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/cors.md",
    "content": "# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }\n\n[CORS или \"Cross-Origin Resource Sharing\"](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) относится к ситуациям, при которых запущенный в браузере фронтенд содержит JavaScript-код, который взаимодействует с бэкендом, находящимся на другом \"источнике\" (\"origin\").\n\n## Источник { #origin }\n\nИсточник — это совокупность протокола (`http`, `https`), домена (`myapp.com`, `localhost`, `localhost.tiangolo.com`) и порта (`80`, `443`, `8080`).\n\nПоэтому это три разных источника:\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\nДаже если они все расположены в `localhost`, они используют разные протоколы или порты, а значит, являются разными источниками.\n\n## Шаги { #steps }\n\nДопустим, у вас есть фронтенд, запущенный в браузере по адресу `http://localhost:8080`, и его JavaScript-код пытается взаимодействовать с бэкендом, запущенным по адресу `http://localhost` (поскольку мы не указали порт, браузер по умолчанию будет использовать порт `80`).\n\nЗатем браузер отправит на бэкенд на `:80` HTTP-запрос `OPTIONS`, и если бэкенд вернёт соответствующие HTTP-заголовки, авторизующие взаимодействие с другим источником (`http://localhost:8080`), то браузер на `:8080` разрешит JavaScript на фронтенде отправить свой запрос на бэкенд на `:80`.\n\nЧтобы это работало, у бэкенда на `:80` должен быть список \"разрешённых источников\" (\"allowed origins\").\n\nВ таком случае этот список должен содержать `http://localhost:8080`, чтобы фронтенд на `:8080` работал корректно.\n\n## Подстановочный символ \"*\" { #wildcards }\n\nВ качестве списка источников можно указать подстановочный символ `\"*\"` (\"wildcard\"), чтобы разрешить любые источники.\n\nНо тогда будут разрешены только некоторые виды взаимодействия, и всё, что связано с учётными данными, будет исключено: куки, HTTP-заголовки Authorization, как при использовании Bearer-токенов, и т.п.\n\nПоэтому, чтобы всё работало корректно, лучше явно указывать список разрешённых источников.\n\n## Использование `CORSMiddleware` { #use-corsmiddleware }\n\nВы можете настроить это в вашем **FastAPI**-приложении, используя `CORSMiddleware`.\n\n* Импортируйте `CORSMiddleware`.\n* Создайте список разрешённых источников (в виде строк).\n* Добавьте его как \"middleware\" (промежуточный слой) к вашему **FastAPI**-приложению.\n\nВы также можете указать, разрешает ли ваш бэкенд использование:\n\n* Учётных данных (HTTP-заголовки Authorization, куки и т.п.).\n* Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `\"*\"`.\n* Отдельных HTTP-заголовков или всех вместе, используя `\"*\"`.\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\n`CORSMiddleware` использует \"запрещающие\" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.\n\nПоддерживаются следующие аргументы:\n\n* `allow_origins` - Список источников, на которые разрешено выполнять кросс-доменные запросы. Например, `['https://example.org', 'https://www.example.org']`. Можно использовать `['*']`, чтобы разрешить любые источники.\n* `allow_origin_regex` - Регулярное выражение для определения источников, на которые разрешено выполнять кросс-доменные запросы. Например, `'https://.*\\.example\\.org'`.\n* `allow_methods` - Список HTTP-методов, которые разрешены для кросс-доменных запросов. По умолчанию `['GET']`. Можно использовать `['*']`, чтобы разрешить все стандартные методы.\n* `allow_headers` - Список HTTP-заголовков запроса, которые должны поддерживаться при кросс-доменных запросах. По умолчанию `[]`. Можно использовать `['*']`, чтобы разрешить все заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` и `Content-Type` всегда разрешены для [простых CORS-запросов](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).\n* `allow_credentials` - Указывает, что куки разрешены в кросс-доменных запросах. По умолчанию `False`.\n\n    Ни один из параметров `allow_origins`, `allow_methods` и `allow_headers` не может быть установлен в `['*']`, если `allow_credentials` имеет значение `True`. Все они должны быть [указаны явно](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards).\n\n* `expose_headers` - Указывает любые заголовки ответа, которые должны быть доступны браузеру. По умолчанию `[]`.\n* `max_age` - Устанавливает максимальное время в секундах, в течение которого браузер кэширует CORS-ответы. По умолчанию `600`.\n\n`CORSMiddleware` отвечает на два типа HTTP-запросов...\n\n### CORS-запросы с предварительной проверкой { #cors-preflight-requests }\n\nЭто любые `OPTIONS`-запросы с заголовками `Origin` и `Access-Control-Request-Method`.\n\nВ этом случае middleware перехватит входящий запрос и отправит соответствующие CORS-заголовки в ответе, а также ответ `200` или `400` в информационных целях.\n\n### Простые запросы { #simple-requests }\n\nЛюбые запросы с заголовком `Origin`. В этом случае middleware передаст запрос дальше как обычно, но добавит соответствующие CORS-заголовки к ответу.\n\n## Больше информации { #more-info }\n\nДля получения более подробной информации о <abbr title=\"Cross-Origin Resource Sharing - совместное использование ресурсов между источниками\">CORS</abbr> обратитесь к [документации CORS от Mozilla](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette.middleware.cors import CORSMiddleware`.\n\n**FastAPI** предоставляет несколько middleware в `fastapi.middleware` только для вашего удобства как разработчика. Но большинство доступных middleware взяты напрямую из Starlette.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/tutorial/debugging.md",
    "content": "# Отладка { #debugging }\n\nВы можете подключить отладчик в своем редакторе, например, в Visual Studio Code или PyCharm.\n\n## Вызов `uvicorn` { #call-uvicorn }\n\nВ вашем FastAPI приложении, импортируйте и вызовите `uvicorn` напрямую:\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### Описание `__name__ == \"__main__\"` { #about-name-main }\n\nГлавная цель использования `__name__ == \"__main__\"` в том, чтобы код выполнялся при запуске файла с помощью:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nно не вызывался, когда другой файл импортирует это, например:\n\n```Python\nfrom myapp import app\n```\n\n#### Больше деталей { #more-details }\n\nДавайте назовём ваш файл `myapp.py`.\n\nЕсли вы запустите его с помощью:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nто встроенная переменная `__name__`, автоматически создаваемая Python в вашем файле, будет иметь значение строкового типа `\"__main__\"`.\n\nТогда эта часть кода:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nбудет запущена.\n\n---\n\nНо этого не произойдет, если вы импортируете этот модуль (файл).\n\nТаким образом, если у вас есть файл `importer.py` с таким импортом:\n\n```Python\nfrom myapp import app\n\n# Еще немного кода\n```\n\nто автоматическая создаваемая внутри файла `myapp.py` переменная  `__name__` будет иметь значение отличающееся от `\"__main__\"`.\n\nСледовательно, строка:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nне будет выполнена.\n\n/// info | Информация\n\nДля получения дополнительной информации, ознакомьтесь с [официальной документацией Python](https://docs.python.org/3/library/__main__.html).\n\n///\n\n## Запуск вашего кода с помощью отладчика { #run-your-code-with-your-debugger }\n\nТак как вы запускаете сервер Uvicorn непосредственно из вашего кода, вы можете вызвать Python программу (ваше FastAPI приложение) напрямую из отладчика.\n\n---\n\nНапример, в Visual Studio Code вы можете выполнить следующие шаги:\n\n* Перейдите на панель \"Debug\".\n* Выберите \"Add configuration...\".\n* Выберите \"Python\"\n* Запустите отладчик \"`Python: Current File (Integrated Terminal)`\".\n\nЭто запустит сервер с вашим **FastAPI** кодом, остановится на точках останова, и т.д.\n\nВот как это может выглядеть:\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\nЕсли используете PyCharm, вы можете выполнить следующие шаги:\n\n* Открыть \"Run\" меню.\n* Выбрать опцию \"Debug...\".\n* Затем в появившемся контекстном меню.\n* Выбрать файл для отладки (в данном случае, `main.py`).\n\nЭто запустит сервер с вашим **FastAPI** кодом, остановится на точках останова, и т.д.\n\nВот как это может выглядеть:\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# Классы как зависимости { #classes-as-dependencies }\n\nПрежде чем углубиться в систему **Внедрения Зависимостей**, давайте обновим предыдущий пример.\n\n## `dict` из предыдущего примера { #a-dict-from-the-previous-example }\n\nВ предыдущем примере мы возвращали `dict` из нашей зависимости («dependable»):\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\nНо затем мы получаем `dict` в параметре `commons` *функции-обработчика пути*.\n\nИ мы знаем, что редакторы кода не могут обеспечить достаточную поддержку (например, автозавершение) для `dict`, поскольку они не могут знать их ключи и типы значений.\n\nМы можем сделать лучше...\n\n## Что делает зависимость { #what-makes-a-dependency }\n\nДо сих пор вы видели зависимости, объявленные как функции.\n\nНо это не единственный способ объявления зависимостей (хотя он, вероятно, более распространенный).\n\nКлючевым фактором является то, что зависимость должна быть «вызываемой».\n\nВ Python «**вызываемый**» — это всё, что Python может «вызвать», как функцию.\n\nТак, если у вас есть объект `something` (который может и _не_ быть функцией) и вы можете «вызвать» его (выполнить) так:\n\n```Python\nsomething()\n```\n\nили\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\nв таком случае он является «вызываемым».\n\n## Классы как зависимости { #classes-as-dependencies_1 }\n\nВы можете заметить, что для создания экземпляра класса в Python используется тот же синтаксис.\n\nНапример:\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\nВ данном случае `fluffy` является экземпляром класса `Cat`.\n\nА чтобы создать `fluffy`, вы «вызываете» `Cat`.\n\nТаким образом, класс в Python также является **вызываемым**.\n\nТогда в **FastAPI** в качестве зависимости можно использовать класс Python.\n\nНа самом деле FastAPI проверяет, что переданный объект является «вызываемым» (функция, класс или что-либо еще) и какие параметры у него определены.\n\nЕсли вы передаёте «вызываемый» объект в качестве зависимости в **FastAPI**, он проанализирует параметры, необходимые для этого «вызываемого» объекта, и обработает их так же, как параметры *функции-обработчика пути*. Включая подзависимости.\n\nЭто относится и к вызываемым объектам без параметров. Работа с ними происходит точно так же, как и для *функций-обработчиков пути* без параметров.\n\nТеперь мы можем изменить зависимость («dependable») `common_parameters`, указанную выше, на класс `CommonQueryParams`:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\nОбратите внимание на метод `__init__`, используемый для создания экземпляра класса:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n...он имеет те же параметры, что и ранее используемая функция `common_parameters`:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\nЭти параметры и будут использоваться **FastAPI** для «решения» зависимости.\n\nВ обоих случаях она будет иметь:\n\n* Необязательный параметр запроса `q`, представляющий собой `str`.\n* Параметр запроса `skip`, представляющий собой `int`, по умолчанию `0`.\n* Параметр запроса `limit`, представляющий собой `int`, по умолчанию `100`.\n\nВ обоих случаях данные будут конвертированы, валидированы, задокументированы в схеме OpenAPI и т.д.\n\n## Как это использовать { #use-it }\n\nТеперь вы можете объявить свою зависимость, используя этот класс.\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI** вызывает класс `CommonQueryParams`. При этом создается «экземпляр» этого класса, который будет передан в качестве параметра `commons` в вашу функцию.\n\n## Аннотация типа и `Depends` { #type-annotation-vs-depends }\n\nОбратите внимание, что в приведенном выше коде мы два раза пишем `CommonQueryParams`:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Подсказка\n\nРекомендуется использовать версию с `Annotated`, если возможно.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\nПоследний `CommonQueryParams`, в:\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n...это то, что **FastAPI** будет использовать, чтобы узнать, что является зависимостью.\n\nИз него FastAPI извлечёт объявленные параметры, и именно его FastAPI будет вызывать.\n\n---\n\nВ этом случае первый `CommonQueryParams`, в:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Подсказка\n\nРекомендуется использовать версию с `Annotated`, если возможно.\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n...не имеет никакого специального значения для **FastAPI**. FastAPI не будет использовать его для преобразования данных, валидации и т.д. (поскольку для этого используется `Depends(CommonQueryParams)`).\n\nНа самом деле можно написать просто:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Подсказка\n\nРекомендуется использовать версию с `Annotated`, если возможно.\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n...как тут:\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\nНо объявление типа приветствуется, так как в этом случае ваш редактор кода будет знать, что будет передано в качестве параметра `commons`, и тогда он сможет помочь вам с автозавершением, проверкой типов и т.д.:\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## Сокращение { #shortcut }\n\nНо вы видите, что здесь мы имеем некоторое повторение кода, дважды написав `CommonQueryParams`:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Подсказка\n\nРекомендуется использовать версию с `Annotated`, если возможно.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n**FastAPI** предоставляет сокращение для таких случаев, когда зависимость — это *конкретный* класс, который **FastAPI** будет «вызывать» для создания экземпляра этого класса.\n\nДля этих конкретных случаев вы можете сделать следующее.\n\nВместо того чтобы писать:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Подсказка\n\nРекомендуется использовать версию с `Annotated`, если возможно.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n...следует написать:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Подсказка\n\nРекомендуется использовать версию с `Annotated`, если возможно.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\nВы объявляете зависимость как тип параметра и используете `Depends()` без какого-либо параметра, вместо того чтобы *снова* писать полный класс внутри `Depends(CommonQueryParams)`.\n\nАналогичный пример будет выглядеть следующим образом:\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n...и **FastAPI** будет знать, что делать.\n\n/// tip | Подсказка\n\nЕсли это покажется вам более запутанным, чем полезным, не обращайте внимания — это вам не *нужно*.\n\nЭто просто сокращение. Потому что **FastAPI** заботится о том, чтобы помочь вам свести к минимуму повторение кода.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# Зависимости в декораторах операции пути { #dependencies-in-path-operation-decorators }\n\nВ некоторых случаях, возвращаемое значение зависимости не используется внутри *функции операции пути*.\n\nИли же зависимость не возвращает никакого значения.\n\nНо вам всё-таки нужно, чтобы она выполнилась.\n\nДля таких ситуаций, вместо объявления *функции операции пути* с параметром `Depends`, вы можете добавить список зависимостей `dependencies` в *декоратор операции пути*.\n\n## Добавление `dependencies` (зависимостей) в *декоратор операции пути* { #add-dependencies-to-the-path-operation-decorator }\n\n*Декоратор операции пути* получает необязательный аргумент `dependencies`.\n\nЭто должен быть `list` состоящий из `Depends()`:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\nЗависимости из dependencies выполнятся так же, как и обычные зависимости. Но их значения (если они были) не будут переданы в *функцию операции пути*.\n\n/// tip | Подсказка\n\nНекоторые редакторы кода определяют неиспользуемые параметры функций и подсвечивают их как ошибку.\n\nИспользование `dependencies` в *декораторе операции пути* гарантирует выполнение зависимостей, избегая при этом предупреждений редактора кода и других инструментов.\n\nЭто также должно помочь предотвратить путаницу у начинающих разработчиков, которые видят неиспользуемые параметры в коде и могут подумать что в них нет необходимости.\n\n///\n\n/// info | Примечание\n\nВ этом примере мы используем выдуманные пользовательские HTTP-заголовки `X-Key` и `X-Token`.\n\nНо в реальных проектах, при внедрении системы безопасности, вы получите больше пользы используя интегрированные [средства защиты (следующая глава)](../security/index.md).\n\n///\n\n## Ошибки в зависимостях и возвращаемые значения { #dependencies-errors-and-return-values }\n\nВы можете использовать те же *функции* зависимостей, что и обычно.\n\n### Требования к зависимостям { #dependency-requirements }\n\nОни могут объявлять требования к запросу (например HTTP-заголовки) или другие подзависимости:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### Вызов исключений { #raise-exceptions }\n\nЗависимости из dependencies могут вызывать исключения с помощью `raise`, как и обычные зависимости:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### Возвращаемые значения { #return-values }\n\nИ они могут возвращать значения или нет, эти значения использоваться не будут.\n\nТаким образом, вы можете переиспользовать обычную зависимость (возвращающую значение), которую вы уже используете где-то в другом месте, и хотя значение не будет использоваться, зависимость будет выполнена:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## Зависимости для группы *операций путей* { #dependencies-for-a-group-of-path-operations }\n\nПозже, читая о том как структурировать большие приложения ([Большие приложения — несколько файлов](../../tutorial/bigger-applications.md)), возможно, многофайловые, вы узнаете как объявить единый параметр `dependencies` для всей группы *операций путей*.\n\n## Глобальные Зависимости { #global-dependencies }\n\nДалее мы увидим, как можно добавить dependencies для всего `FastAPI` приложения, так чтобы они применялись к каждой *операции пути*.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# Зависимости с yield { #dependencies-with-yield }\n\nFastAPI поддерживает зависимости, которые выполняют некоторые <dfn title='иногда также называемые \"код выхода\", \"код очистки\", \"код завершения\", \"код закрытия\", \"код выхода менеджера контекста\" и т.п.'>дополнительные шаги после завершения</dfn>.\n\nДля этого используйте `yield` вместо `return`, а дополнительные шаги (код) напишите после него.\n\n/// tip | Подсказка\n\nУбедитесь, что используете `yield` только один раз на одну зависимость.\n\n///\n\n/// note | Технические детали\n\nЛюбая функция, с которой можно корректно использовать:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) или\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nбудет корректной для использования в качестве зависимости **FastAPI**.\n\nНа самом деле, FastAPI использует эти два декоратора внутренне.\n\n///\n\n## Зависимость базы данных с помощью `yield` { #a-database-dependency-with-yield }\n\nНапример, с его помощью можно создать сессию работы с базой данных и закрыть её после завершения.\n\nПеред созданием ответа будет выполнен только код до и включая оператор `yield`:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\nЗначение, полученное из `yield`, внедряется в *операции пути* и другие зависимости:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\nКод, следующий за оператором `yield`, выполняется после ответа:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip | Подсказка\n\nМожно использовать как `async`, так и обычные функции.\n\n**FastAPI** корректно обработает каждый вариант, так же как и с обычными зависимостями.\n\n///\n\n## Зависимость с `yield` и `try` { #a-dependency-with-yield-and-try }\n\nЕсли использовать блок `try` в зависимости с `yield`, то вы получите любое исключение, которое было выброшено при использовании зависимости.\n\nНапример, если какой-то код в какой-то момент в середине, в другой зависимости или в *операции пути*, сделал \"откат\" транзакции базы данных или создал любую другую ошибку, то вы получите это исключение в своей зависимости.\n\nТаким образом, можно искать конкретное исключение внутри зависимости с помощью `except SomeException`.\n\nТочно так же можно использовать `finally`, чтобы убедиться, что обязательные шаги при выходе выполнены независимо от того, было ли исключение или нет.\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## Подзависимости с `yield` { #sub-dependencies-with-yield }\n\nВы можете иметь подзависимости и \"деревья\" подзависимостей любого размера и формы, и любая из них или все они могут использовать `yield`.\n\n**FastAPI** проследит за тем, чтобы «код выхода» в каждой зависимости с `yield` выполнялся в правильном порядке.\n\nНапример, `dependency_c` может зависеть от `dependency_b`, а `dependency_b` — от `dependency_a`:\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\nИ все они могут использовать `yield`.\n\nВ этом случае `dependency_c` для выполнения своего кода выхода нуждается в том, чтобы значение из `dependency_b` (здесь `dep_b`) всё ещё было доступно.\n\nИ, в свою очередь, `dependency_b` нуждается в том, чтобы значение из `dependency_a` (здесь `dep_a`) было доступно для её кода выхода.\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\nТочно так же можно иметь часть зависимостей с `yield`, часть — с `return`, и какие-то из них могут зависеть друг от друга.\n\nЛибо у вас может быть одна зависимость, которая требует несколько других зависимостей с `yield` и т.д.\n\nКомбинации зависимостей могут быть какими угодно.\n\n**FastAPI** проследит за тем, чтобы всё выполнялось в правильном порядке.\n\n/// note | Технические детали\n\nЭто работает благодаря [менеджерам контекста](https://docs.python.org/3/library/contextlib.html) в Python.\n\n**FastAPI** использует их внутренне для достижения этого.\n\n///\n\n## Зависимости с `yield` и `HTTPException` { #dependencies-with-yield-and-httpexception }\n\nВы видели, что можно использовать зависимости с `yield` и иметь блоки `try`, которые пытаются выполнить некоторый код, а затем запускают код выхода в `finally`.\n\nТакже вы можете использовать `except`, чтобы поймать вызванное исключение и что-то с ним сделать.\n\nНапример, вы можете <abbr title=\"«raise» дословно - «поднять», но «вызвать», «сгенерировать» или «выбросить» употребляется чаще\">вызвать</abbr> другое исключение, например `HTTPException`.\n\n/// tip | Подсказка\n\nЭто довольно продвинутая техника, и в большинстве случаев она вам не понадобится, так как вы можете вызывать исключения (включая `HTTPException`) в остальном коде вашего приложения, например, в *функции-обработчике пути*.\n\nНо если понадобится — возможность есть. 🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\nЕсли вы хотите перехватывать исключения и формировать на их основе пользовательский ответ, создайте [Пользовательский обработчик исключений](../handling-errors.md#install-custom-exception-handlers).\n\n## Зависимости с `yield` и `except` { #dependencies-with-yield-and-except }\n\nЕсли вы ловите исключение с помощью `except` в зависимости с `yield` и не вызываете его снова (или не вызываете новое исключение), FastAPI не сможет заметить, что было исключение — так же, как это происходит в обычном Python:\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\nВ этом случае клиент получит *HTTP 500 Internal Server Error*, как и должно быть, поскольку мы не вызываем `HTTPException` или что-то подобное, но на сервере **не будет никаких логов** или других указаний на то, какая была ошибка. 😱\n\n### Всегда делайте `raise` в зависимостях с `yield` и `except` { #always-raise-in-dependencies-with-yield-and-except }\n\nЕсли вы ловите исключение в зависимости с `yield`, то, если вы не вызываете другой `HTTPException` или что-то подобное, вам следует повторно вызвать исходное исключение.\n\nВы можете повторно вызвать то же самое исключение с помощью `raise`:\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\nТеперь клиент получит тот же *HTTP 500 Internal Server Error*, но на сервере в логах будет наше пользовательское `InternalError`. 😎\n\n## Выполнение зависимостей с `yield` { #execution-of-dependencies-with-yield }\n\nПоследовательность выполнения примерно такая, как на этой схеме. Время течёт сверху вниз. А каждый столбец — это одна из частей, взаимодействующих с кодом или выполняющих код.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exception handler\nparticipant dep as Dep with yield\nparticipant operation as Path Operation\nparticipant tasks as Background tasks\n\n    Note over client,operation: Can raise exceptions, including HTTPException\n    client ->> dep: Start request\n    Note over dep: Run code up to yield\n    opt raise Exception\n        dep -->> handler: Raise Exception\n        handler -->> client: HTTP error response\n    end\n    dep ->> operation: Run dependency, e.g. DB session\n    opt raise\n        operation -->> dep: Raise Exception (e.g. HTTPException)\n        opt handle\n            dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception\n        end\n        handler -->> client: HTTP error response\n    end\n\n    operation ->> client: Return response to client\n    Note over client,operation: Response is already sent, can't change it anymore\n    opt Tasks\n        operation -->> tasks: Send background tasks\n    end\n    opt Raise other exception\n        tasks -->> tasks: Handle exceptions in the background task code\n    end\n```\n\n/// info | Дополнительная информация\n\nКлиенту будет отправлен только **один ответ**. Это может быть один из ответов об ошибке или ответ от *операции пути*.\n\nПосле отправки одного из этих ответов никакой другой ответ отправить нельзя.\n\n///\n\n/// tip | Подсказка\n\nЕсли вы вызовете какое-либо исключение в коде из *функции-обработчика пути*, оно будет передано зависимостям с `yield`, включая `HTTPException`. В большинстве случаев вы захотите повторно вызвать то же самое исключение или новое из зависимости с `yield`, чтобы убедиться, что оно корректно обработано.\n\n///\n\n## Ранний выход и `scope` { #early-exit-and-scope }\n\nОбычно «код выхода» зависимостей с `yield` выполняется **после того, как ответ** отправлен клиенту.\n\nНо если вы знаете, что не будете использовать зависимость после возврата из *функции-обработчика пути*, вы можете использовать `Depends(scope=\"function\")`, чтобы сообщить FastAPI, что он должен закрыть зависимость после возврата из *функции-обработчика пути*, но **до того**, как **ответ будет отправлен**.\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()` принимает параметр `scope`, который может быть:\n\n* `\"function\"`: начать зависимость до *функции-обработчика пути*, которая обрабатывает запрос, завершить зависимость после окончания *функции-обработчика пути*, но **до того**, как ответ будет отправлен обратно клиенту. То есть функция зависимости будет выполнена **вокруг** *функции-обработчика пути*.\n* `\"request\"`: начать зависимость до *функции-обработчика пути*, которая обрабатывает запрос (как и при использовании `\"function\"`), но завершить **после** того, как ответ будет отправлен обратно клиенту. То есть функция зависимости будет выполнена **вокруг** цикла запроса (**request**) и ответа.\n\nЕсли не указано и в зависимости есть `yield`, по умолчанию будет `scope` со значением `\"request\"`.\n\n### `scope` для подзависимостей { #scope-for-sub-dependencies }\n\nКогда вы объявляете зависимость с `scope=\"request\"` (значение по умолчанию), любая подзависимость также должна иметь `scope` равный `\"request\"`.\n\nНо зависимость со `scope` равным `\"function\"` может иметь зависимости со `scope` `\"function\"` и со `scope` `\"request\"`.\n\nЭто потому, что любая зависимость должна иметь возможность выполнить свой код выхода раньше подзависимостей, так как ей может понадобиться использовать их во время своего кода выхода.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Зависимость scope=\"request\"\nparticipant dep_func as Зависимость scope=\"function\"\nparticipant operation as Функция-обработчик пути\n\n    client ->> dep_req: Запрос\n    Note over dep_req: Выполнить код до yield\n    dep_req ->> dep_func: Передать значение\n    Note over dep_func: Выполнить код до yield\n    dep_func ->> operation: Выполнить функцию-обработчик пути\n    operation ->> dep_func: Выход из функции-обработчика пути\n    Note over dep_func: Выполнить код после yield\n    Note over dep_func: ✅ Зависимость закрыта\n    dep_func ->> client: Отправить ответ клиенту\n    Note over client: Ответ отправлен\n    Note over dep_req: Выполнить код после yield\n    Note over dep_req: ✅ Зависимость закрыта\n```\n\n## Зависимости с `yield`, `HTTPException`, `except` и фоновыми задачами { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\nЗависимости с `yield` со временем эволюционировали, чтобы покрыть разные сценарии и исправить некоторые проблемы.\n\nЕсли вы хотите посмотреть, что менялось в разных версиях FastAPI, вы можете прочитать об этом подробнее в продвинутом руководстве: [Продвинутые зависимости — зависимости с `yield`, `HTTPException`, `except` и фоновыми задачами](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).\n## Контекстные менеджеры { #context-managers }\n\n### Что такое «контекстные менеджеры» { #what-are-context-managers }\n\n«Контекстные менеджеры» — это любые объекты Python, которые можно использовать в операторе `with`.\n\nНапример, [можно использовать `with` для чтения файла](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files):\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\nПод капотом вызов `open(\"./somefile.txt\")` создаёт объект, называемый «контекстным менеджером».\n\nКогда блок `with` завершается, он обязательно закрывает файл, даже если были исключения.\n\nКогда вы создаёте зависимость с `yield`, **FastAPI** внутренне создаёт для неё менеджер контекста и сочетает его с некоторыми другими связанными инструментами.\n\n### Использование менеджеров контекста в зависимостях с `yield` { #using-context-managers-in-dependencies-with-yield }\n\n/// warning | Внимание\n\nЭто, более или менее, «продвинутая» идея.\n\nЕсли вы только начинаете работать с **FastAPI**, то лучше пока пропустить этот пункт.\n\n///\n\nВ Python можно создавать менеджеры контекста, [создав класс с двумя методами: `__enter__()` и `__exit__()`](https://docs.python.org/3/reference/datamodel.html#context-managers).\n\nИх также можно использовать внутри зависимостей **FastAPI** с `yield`, применяя операторы\n`with` или `async with` внутри функции зависимости:\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip | Подсказка\n\nДругой способ создания менеджера контекста — с помощью:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) или\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nоформив ими функцию с одним `yield`.\n\nИменно это **FastAPI** использует внутренне для зависимостей с `yield`.\n\nНо использовать эти декораторы для зависимостей FastAPI не обязательно (и не стоит).\n\nFastAPI сделает это за вас на внутреннем уровне.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# Глобальные зависимости { #global-dependencies }\n\nДля некоторых типов приложений может потребоваться добавить зависимости ко всему приложению.\n\nПодобно тому, как вы можете [добавлять `dependencies` (зависимости) в *декораторах операций пути*](dependencies-in-path-operation-decorators.md), вы можете добавлять зависимости сразу ко всему `FastAPI` приложению.\n\nВ этом случае они будут применяться ко всем *операциям пути* в приложении:\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\nВсе способы [добавления `dependencies` (зависимостей) в *декораторах операций пути*](dependencies-in-path-operation-decorators.md) по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения.\n\n## Зависимости для групп *операций пути* { #dependencies-for-groups-of-path-operations }\n\nПозднее, читая о том, как структурировать более крупные приложения ([Более крупные приложения - несколько файлов](../../tutorial/bigger-applications.md)), возможно, состоящие из нескольких файлов, вы узнаете, как объявить один параметр `dependencies` для целой группы *операций пути*.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/dependencies/index.md",
    "content": "# Зависимости { #dependencies }\n\n**FastAPI** имеет очень мощную, но интуитивную систему **<dfn title=\"также известно как: компоненты, ресурсы, провайдеры, сервисы, внедряемые зависимости\">Инъекция зависимостей</dfn>**.\n\nОна спроектирована так, чтобы быть очень простой в использовании и облегчать любому разработчику интеграцию других компонентов с **FastAPI**.\n\n## Что такое инъекция зависимостей («Dependency Injection») { #what-is-dependency-injection }\n\nВ программировании **«Dependency Injection»** означает, что у вашего кода (в данном случае у ваших *функций обработки пути*) есть способ объявить вещи, которые требуются для его работы и использования: «зависимости».\n\nИ затем эта система (в нашем случае **FastAPI**) позаботится о том, чтобы сделать всё необходимое для предоставления вашему коду этих зависимостей (сделать «инъекцию» зависимостей).\n\nЭто очень полезно, когда вам нужно:\n\n* Обеспечить общую логику (один и тот же алгоритм снова и снова).\n* Разделять соединения с базой данных.\n* Обеспечить безопасность, аутентификацию, требования к ролям и т.п.\n* И многое другое...\n\nВсё это при минимизации повторения кода.\n\n## Первые шаги { #first-steps }\n\nДавайте рассмотрим очень простой пример. Он настолько простой, что пока не очень полезен.\n\nНо так мы сможем сосредоточиться на том, как работает система **Dependency Injection**.\n\n### Создайте зависимость, или «dependable» (от чего что-то зависит) { #create-a-dependency-or-dependable }\n\nСначала сосредоточимся на зависимости.\n\nЭто просто функция, которая может принимать те же параметры, что и *функция обработки пути*:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\nИ всё.\n\n**2 строки.**\n\nИ она имеет ту же форму и структуру, что и все ваши *функции обработки пути*.\n\nМожно думать о ней как о *функции обработки пути* без «декоратора» (без `@app.get(\"/some-path\")`).\n\nИ она может возвращать что угодно.\n\nВ этом случае эта зависимость ожидает:\n\n* Необязательный query-параметр `q` типа `str`.\n* Необязательный query-параметр `skip` типа `int`, по умолчанию `0`.\n* Необязательный query-параметр `limit` типа `int`, по умолчанию `100`.\n\nА затем просто возвращает `dict`, содержащий эти значения.\n\n/// info | Информация\n\nFastAPI добавил поддержку `Annotated` (и начал рекомендовать его использование) в версии 0.95.0.\n\nЕсли у вас более старая версия, вы получите ошибки при попытке использовать `Annotated`.\n\nУбедитесь, что вы [обновили версию FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions) как минимум до 0.95.1, прежде чем использовать `Annotated`.\n\n///\n\n### Импорт `Depends` { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### Объявите зависимость в «зависимом» { #declare-the-dependency-in-the-dependant }\n\nТочно так же, как вы используете `Body`, `Query` и т.д. с параметрами вашей *функции обработки пути*, используйте `Depends` с новым параметром:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\nХотя вы используете `Depends` в параметрах вашей функции так же, как `Body`, `Query` и т.д., `Depends` работает немного иначе.\n\nВ `Depends` вы передаёте только один параметр.\n\nЭтот параметр должен быть чем-то вроде функции.\n\nВы **не вызываете её** напрямую (не добавляйте круглые скобки в конце), просто передаёте её как параметр в `Depends()`.\n\nИ эта функция принимает параметры так же, как *функции обработки пути*.\n\n/// tip | Подсказка\n\nВ следующей главе вы увидите, какие ещё «вещи», помимо функций, можно использовать в качестве зависимостей.\n\n///\n\nКаждый раз, когда приходит новый запрос, **FastAPI** позаботится о:\n\n* Вызове вашей зависимости («dependable») с корректными параметрами.\n* Получении результата из вашей функции.\n* Присваивании этого результата параметру в вашей *функции обработки пути*.\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\nТаким образом, вы пишете общий код один раз, а **FastAPI** позаботится о его вызове для ваших *операций пути*.\n\n/// check | Проверка\n\nОбратите внимание, что вам не нужно создавать специальный класс и передавать его куда-то в **FastAPI**, чтобы «зарегистрировать» его или что-то подобное.\n\nВы просто передаёте его в `Depends`, и **FastAPI** знает, что делать дальше.\n\n///\n\n## Использование зависимости с `Annotated` в нескольких местах { #share-annotated-dependencies }\n\nВ приведённых выше примерах есть небольшое **повторение кода**.\n\nКогда вам нужно использовать зависимость `common_parameters()`, вы должны написать весь параметр с аннотацией типа и `Depends()`:\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\nНо поскольку мы используем `Annotated`, мы можем сохранить это значение `Annotated` в переменную и использовать его в нескольких местах:\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | Подсказка\n\nЭто стандартный Python, это называется «type alias», и это не особенность **FastAPI**.\n\nНо поскольку **FastAPI** основан на стандартах Python, включая `Annotated`, вы можете использовать этот трюк в своём коде. 😎\n\n///\n\nЗависимости продолжат работать как ожидалось, и **лучшая часть** в том, что **информация о типах будет сохранена**, а значит, ваш редактор кода продолжит предоставлять **автозавершение**, **встроенные ошибки** и т.д. То же относится и к другим инструментам, таким как `mypy`.\n\nЭто особенно полезно, когда вы используете это в **большой кодовой базе**, где вы используете **одни и те же зависимости** снова и снова во **многих *операциях пути***.\n\n## Использовать `async` или не `async` { #to-async-or-not-to-async }\n\nПоскольку зависимости также вызываются **FastAPI** (как и ваши *функции обработки пути*), применяются те же правила при определении ваших функций.\n\nВы можете использовать `async def` или обычное `def`.\n\nИ вы можете объявлять зависимости с `async def` внутри обычных *функций обработки пути* `def`, или зависимости `def` внутри *функций обработки пути* `async def` и т.д.\n\nЭто не важно. **FastAPI** знает, что делать.\n\n/// note | Примечание\n\nЕсли вы не уверены, посмотрите раздел [Async: «Нет времени?»](../../async.md#in-a-hurry) о `async` и `await` в документации.\n\n///\n\n## Интеграция с OpenAPI { #integrated-with-openapi }\n\nВсе объявления запросов, проверки и требования ваших зависимостей (и подзависимостей) будут интегрированы в ту же схему OpenAPI.\n\nПоэтому в интерактивной документации будет вся информация и из этих зависимостей:\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## Простое использование { #simple-usage }\n\nЕсли посмотреть, *функции обработки пути* объявляются для использования всякий раз, когда *путь* и *операция* совпадают, и тогда **FastAPI** заботится о вызове функции с корректными параметрами, извлекая данные из запроса.\n\nНа самом деле все (или большинство) веб-фреймворков работают таким же образом.\n\nВы никогда не вызываете эти функции напрямую. Их вызывает ваш фреймворк (в нашем случае **FastAPI**).\n\nС системой **Dependency Injection** вы также можете сообщить **FastAPI**, что ваша *функция обработки пути* «зависит» от чего-то, что должно быть выполнено перед вашей *функцией обработки пути*, и **FastAPI** позаботится о его выполнении и «инъекции» результатов.\n\nДругие распространённые термины для описания той же идеи «dependency injection»:\n\n* ресурсы\n* провайдеры\n* сервисы\n* внедряемые зависимости\n* компоненты\n\n## Плагины **FastAPI** { #fastapi-plug-ins }\n\nИнтеграции и «плагины» могут быть построены с использованием системы **Dependency Injection**. Но на самом деле **нет необходимости создавать «плагины»**, так как, используя зависимости, можно объявить бесконечное количество интеграций и взаимодействий, которые становятся доступными вашим *функциям обработки пути*.\n\nИ зависимости можно создавать очень простым и интуитивным способом, который позволяет просто импортировать нужные пакеты Python и интегрировать их с вашими API-функциями в пару строк кода, *буквально*.\n\nВы увидите примеры этого в следующих главах о реляционных и NoSQL базах данных, безопасности и т.д.\n\n## Совместимость с **FastAPI** { #fastapi-compatibility }\n\nПростота системы **Dependency Injection** делает **FastAPI** совместимым с:\n\n* всеми реляционными базами данных\n* NoSQL базами данных\n* внешними пакетами\n* внешними API\n* системами аутентификации и авторизации\n* системами мониторинга использования API\n* системами инъекции данных в ответы\n* и т.д.\n\n## Просто и мощно { #simple-and-powerful }\n\nХотя иерархическая система dependency injection очень проста для определения и использования, она по-прежнему очень мощная.\n\nВы можете определять зависимости, которые, в свою очередь, могут иметь собственные зависимости.\n\nВ итоге строится иерархическое дерево зависимостей, и система **Dependency Injection** берёт на себя решение всех этих зависимостей (и их подзависимостей) и предоставляет (инъектирует) результаты на каждом шаге.\n\nНапример, у вас есть 4 API-эндпоинта (*операции пути*):\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\nтогда вы можете добавить разные требования к правам для каждого из них только с помощью зависимостей и подзависимостей:\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## Интегрировано с **OpenAPI** { #integrated-with-openapi_1 }\n\nВсе эти зависимости, объявляя свои требования, также добавляют параметры, проверки и т.д. к вашим *операциям пути*.\n\n**FastAPI** позаботится о добавлении всего этого в схему OpenAPI, чтобы это отображалось в системах интерактивной документации.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# Подзависимости { #sub-dependencies }\n\nВы можете создавать зависимости, которые имеют **подзависимости**.\n\nИх **вложенность** может быть любой глубины.\n\n**FastAPI** сам займётся их управлением.\n\n## Первая зависимость { #first-dependency-dependable }\n\nМожно создать первую зависимость следующим образом:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\nОна объявляет необязательный параметр запроса `q` как строку, а затем возвращает его.\n\nЭто довольно просто (хотя и не очень полезно), но поможет нам сосредоточиться на том, как работают подзависимости.\n\n## Вторая зависимость, «зависимость» и «зависимая» { #second-dependency-dependable-and-dependant }\n\nЗатем можно создать еще одну функцию зависимости, которая одновременно объявляет свою собственную зависимость (таким образом, она тоже является «зависимой»):\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\nОстановимся на объявленных параметрах:\n\n* Несмотря на то, что эта функция сама является зависимостью, она также является зависимой от чего-то другого.\n    * Она зависит от `query_extractor` и присваивает возвращаемое ей значение параметру `q`.\n* Она также объявляет необязательный куки-параметр `last_query` в виде строки.\n    * Если пользователь не указал параметр `q` в запросе, то мы используем последний использованный запрос, который мы ранее сохранили в куки-параметре `last_query`.\n\n## Использование зависимости { #use-the-dependency }\n\nЗатем мы можем использовать зависимость вместе с:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info | Дополнительная информация\n\nОбратите внимание, что мы объявляем только одну зависимость в *функции операции пути* - `query_or_cookie_extractor`.\n\nНо **FastAPI** будет знать, что сначала он должен выполнить `query_extractor`, чтобы передать результаты этого в `query_or_cookie_extractor` при его вызове.\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## Использование одной и той же зависимости несколько раз { #using-the-same-dependency-multiple-times }\n\nЕсли одна из ваших зависимостей объявлена несколько раз для одной и той же *функции операции пути*, например, несколько зависимостей имеют общую подзависимость, **FastAPI** будет знать, что вызывать эту подзависимость нужно только один раз за запрос.\n\nПри этом возвращаемое значение будет сохранено в <dfn title=\"Вспомогательная система для хранения вычисленных/сгенерированных значений, чтобы переиспользовать их вместо повторного вычисления.\">«кэш»</dfn> и будет передано всем \"зависимым\" функциям, которые нуждаются в нем внутри этого конкретного запроса, вместо того, чтобы вызывать зависимость несколько раз для одного и того же запроса.\n\nВ расширенном сценарии, когда вы знаете, что вам нужно, чтобы зависимость вызывалась на каждом шаге (возможно, несколько раз) в одном и том же запросе, вместо использования \"кэшированного\" значения, вы можете установить параметр `use_cache=False` при использовании `Depends`:\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Подсказка\n\nПредпочтительнее использовать версию с аннотацией, если это возможно.\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## Резюме { #recap }\n\nПомимо всех этих умных слов, используемых здесь, система внедрения зависимостей довольно проста.\n\nЭто просто функции, которые выглядят так же, как *функции операций путей*.\n\nНо, тем не менее, эта система очень мощная и позволяет вам объявлять вложенные графы (деревья) зависимостей сколь угодно глубоко.\n\n/// tip | Подсказка\n\nВсе это может показаться не столь полезным на этих простых примерах.\n\nНо вы увидите как это пригодится в главах посвященных безопасности.\n\nИ вы также увидите, сколько кода это вам сэкономит.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/tutorial/encoder.md",
    "content": "# JSON-совместимый кодировщик { #json-compatible-encoder }\n\nВ некоторых случаях может потребоваться преобразование типа данных (например, Pydantic-модели) в тип, совместимый с JSON (например, `dict`, `list` и т.д.).\n\nНапример, если необходимо хранить его в базе данных.\n\nДля этого **FastAPI** предоставляет функцию `jsonable_encoder()`.\n\n## Использование `jsonable_encoder` { #using-the-jsonable-encoder }\n\nПредставим, что у вас есть база данных `fake_db`, которая принимает только JSON-совместимые данные.\n\nНапример, она не принимает объекты `datetime`, так как они не совместимы с JSON.\n\nВ таком случае объект `datetime` следует преобразовать в `str`, содержащую данные в [формате ISO](https://en.wikipedia.org/wiki/ISO_8601).\n\nТочно так же эта база данных не может принять Pydantic-модель (объект с атрибутами), а только `dict`.\n\nДля этого можно использовать функцию `jsonable_encoder`.\n\nОна принимает объект, например, Pydantic-модель, и возвращает его версию, совместимую с JSON:\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\nВ данном примере она преобразует Pydantic-модель в `dict`, а `datetime` - в `str`.\n\nРезультатом её вызова является объект, который может быть закодирован с помощью функции из стандартной библиотеки Python – [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps).\n\nФункция не возвращает большой `str`, содержащий данные в формате JSON (в виде строки). Она возвращает стандартную структуру данных Python (например, `dict`) со значениями и подзначениями, которые совместимы с JSON.\n\n/// note | Примечание\n\n`jsonable_encoder` фактически используется **FastAPI** внутри системы для преобразования данных. Однако он полезен и во многих других сценариях.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/tutorial/extra-data-types.md",
    "content": "# Дополнительные типы данных { #extra-data-types }\n\nДо сих пор вы использовали простые типы данных, такие как:\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\nНо вы также можете использовать и более сложные типы.\n\nПри этом у вас останутся те же возможности, что и до сих пор:\n\n* Отличная поддержка редактора кода.\n* Преобразование данных из входящих запросов.\n* Преобразование данных для ответа.\n* Валидация данных.\n* Автоматическая аннотация и документация.\n\n## Другие типы данных { #other-data-types }\n\nНиже перечислены некоторые из дополнительных типов данных, которые вы можете использовать:\n\n* `UUID`:\n    * Стандартный \"Универсальный уникальный идентификатор\", используемый в качестве идентификатора во многих базах данных и системах.\n    * В запросах и ответах будет представлен как `str`.\n* `datetime.datetime`:\n    * Встроенный в Python `datetime.datetime`.\n    * В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15T15:53:00+05:00`.\n* `datetime.date`:\n    * Встроенный в Python `datetime.date`.\n    * В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `2008-09-15`.\n* `datetime.time`:\n    * Встроенный в Python `datetime.time`.\n    * В запросах и ответах будет представлен как `str` в формате ISO 8601, например: `14:23:55.003`.\n* `datetime.timedelta`:\n    * Встроенный в Python `datetime.timedelta`.\n    * В запросах и ответах будет представлен в виде общего количества секунд типа `float`.\n    * Pydantic также позволяет представить его как \"Кодировку разницы во времени ISO 8601\", [см. документацию для получения дополнительной информации](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).\n* `frozenset`:\n    * В запросах и ответах обрабатывается так же, как и `set`:\n        * В запросах будет прочитан список, исключены дубликаты и преобразован в `set`.\n        * В ответах `set` будет преобразован в `list`.\n        * В сгенерированной схеме будет указано, что значения `set` уникальны (с помощью JSON-схемы `uniqueItems`).\n* `bytes`:\n    * Встроенный в Python `bytes`.\n    * В запросах и ответах будет рассматриваться как `str`.\n    * В сгенерированной схеме будет указано, что это `str` в формате `binary`.\n* `Decimal`:\n    * Встроенный в Python `Decimal`.\n    * В запросах и ответах обрабатывается так же, как и `float`.\n* Вы можете проверить все допустимые типы данных Pydantic здесь: [Типы данных Pydantic](https://docs.pydantic.dev/latest/usage/types/types/).\n\n## Пример { #example }\n\nВот пример *операции пути* с параметрами, который демонстрирует некоторые из вышеперечисленных типов.\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\nОбратите внимание, что параметры внутри функции имеют свой естественный тип данных, и вы, например, можете выполнять обычные манипуляции с датами, такие как:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/ru/docs/tutorial/extra-models.md",
    "content": "# Дополнительные модели { #extra-models }\n\nВ продолжение прошлого примера будет уже обычным делом иметь несколько связанных между собой моделей.\n\nЭто особенно применимо в случае моделей пользователя, потому что:\n\n* **Модель для ввода** должна иметь возможность содержать пароль.\n* **Модель для вывода** не должна содержать пароль.\n* **Модель для базы данных**, возможно, должна содержать хэшированный пароль.\n\n/// danger | Внимание\n\nНикогда не храните пароли пользователей в чистом виде. Всегда храните \"безопасный хэш\", который вы затем сможете проверить.\n\nЕсли вам это не знакомо, вы можете узнать про \"хэш пароля\" в [главах о безопасности](security/simple-oauth2.md#password-hashing).\n\n///\n\n## Множественные модели { #multiple-models }\n\nНиже изложена основная идея того, как могут выглядеть эти модели с полями для паролей, а также описаны места, где они используются:\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### Про `**user_in.model_dump()` { #about-user-in-model-dump }\n\n#### `.model_dump()` из Pydantic { #pydantics-model-dump }\n\n`user_in` — это Pydantic-модель класса `UserIn`.\n\nУ Pydantic-моделей есть метод `.model_dump()`, который возвращает `dict` с данными модели.\n\nПоэтому, если мы создадим Pydantic-объект `user_in` таким способом:\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\nи затем вызовем:\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\nто теперь у нас есть `dict` с данными в переменной `user_dict` (это `dict` вместо объекта Pydantic-модели).\n\nИ если мы вызовем:\n\n```Python\nprint(user_dict)\n```\n\nмы получим Python `dict` с:\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### Распаковка `dict` { #unpacking-a-dict }\n\nЕсли мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python его \"распакует\". Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.\n\nПоэтому, продолжая описанный выше пример с `user_dict`, написание такого кода:\n\n```Python\nUserInDB(**user_dict)\n```\n\nбудет эквивалентно:\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\nИли, более точно, если использовать `user_dict` напрямую, с любым содержимым, которое он может иметь в будущем:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### Pydantic-модель из содержимого другой { #a-pydantic-model-from-the-contents-of-another }\n\nКак в примере выше мы получили `user_dict` из `user_in.model_dump()`, этот код:\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\nбудет равнозначен такому:\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n...потому что `user_in.model_dump()` — это `dict`, и затем мы указываем, чтобы Python его \"распаковал\", когда передаём его в `UserInDB` с префиксом `**`.\n\nТаким образом мы получаем Pydantic-модель на основе данных из другой Pydantic-модели.\n\n#### Распаковка `dict` и дополнительные именованные аргументы { #unpacking-a-dict-and-extra-keywords }\n\nИ затем, если мы добавим дополнительный именованный аргумент `hashed_password=hashed_password` как здесь:\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n...то в итоге получится что-то подобное:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning | Предупреждение\n\nВспомогательные дополнительные функции `fake_password_hasher` и `fake_save_user` используются только для демонстрации возможного потока данных и, конечно, не обеспечивают настоящую безопасность.\n\n///\n\n## Сократите дублирование { #reduce-duplication }\n\nСокращение дублирования кода — это одна из главных идей **FastAPI**.\n\nПоскольку дублирование кода повышает риск появления багов, проблем с безопасностью, проблем десинхронизации кода (когда вы обновляете код в одном месте, но не обновляете в другом), и т.д.\n\nА все описанные выше модели используют много общих данных и дублируют названия атрибутов и типов.\n\nМы можем это улучшить.\n\nМы можем определить модель `UserBase`, которая будет базовой для остальных моделей. И затем мы можем создать подклассы этой модели, которые будут наследовать её атрибуты (объявления типов, валидацию, и т.п.).\n\nВсе операции конвертации, валидации, документации, и т.п. будут по-прежнему работать нормально.\n\nВ этом случае мы можем определить только различия между моделями (с `password` в чистом виде, с `hashed_password` и без пароля):\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` или `anyOf` { #union-or-anyof }\n\nВы можете объявить HTTP-ответ как `Union` из двух или более типов. Это означает, что HTTP-ответ может быть любым из них.\n\nОн будет определён в OpenAPI как `anyOf`.\n\nДля этого используйте стандартную аннотацию типов в Python [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union):\n\n/// note | Примечание\n\nПри объявлении [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions) сначала указывайте наиболее специфичный тип, затем менее специфичный. В примере ниже более специфичный `PlaneItem` стоит перед `CarItem` в `Union[PlaneItem, CarItem]`.\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### `Union` в Python 3.10 { #union-in-python-3-10 }\n\nВ этом примере мы передаём `Union[PlaneItem, CarItem]` в качестве значения аргумента `response_model`.\n\nПоскольку мы передаём его как **значение аргумента** вместо того, чтобы поместить его в **аннотацию типа**, нам придётся использовать `Union` даже в Python 3.10.\n\nЕсли оно было бы указано в аннотации типа, то мы могли бы использовать вертикальную черту как в примере:\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\nНо если мы поместим это в присваивание `response_model=PlaneItem | CarItem`, мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.\n\n## Список моделей { #list-of-models }\n\nТаким же образом вы можете объявлять HTTP-ответы, возвращающие списки объектов.\n\nДля этого используйте стандартный `list` в Python:\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## Ответ с произвольным `dict` { #response-with-arbitrary-dict }\n\nВы также можете объявить HTTP-ответ, используя обычный произвольный `dict`, объявив только тип ключей и значений, без использования Pydantic-модели.\n\nЭто полезно, если вы заранее не знаете корректных названий полей/атрибутов (которые будут нужны при использовании Pydantic-модели).\n\nВ этом случае вы можете использовать `dict`:\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## Резюме { #recap }\n\nИспользуйте несколько Pydantic-моделей и свободно применяйте наследование для каждого случая.\n\nВам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных \"состояниях\". Как в случае с \"сущностью\" пользователя, у которого есть состояние, включающее `password`, `password_hash` и отсутствие пароля.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/first-steps.md",
    "content": "# Первые шаги { #first-steps }\n\nСамый простой файл FastAPI может выглядеть так:\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\nСкопируйте это в файл `main.py`.\n\nЗапустите сервер в режиме реального времени:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nВ выводе будет строка примерно такого вида:\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\nЭта строка показывает URL, по которому ваше приложение доступно на локальной машине.\n\n### Проверьте { #check-it }\n\nОткройте браузер по адресу: [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nВы увидите JSON-ответ вида:\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### Интерактивная документация API { #interactive-api-docs }\n\nТеперь перейдите по адресу: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВы увидите автоматически сгенерированную интерактивную документацию по API (предоставлено [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Альтернативная документация API { #alternative-api-docs }\n\nИ теперь перейдите по адресу [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nВы увидите альтернативную автоматически сгенерированную документацию (предоставлено [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI** генерирует «схему» всего вашего API, используя стандарт **OpenAPI** для описания API.\n\n#### «Схема» { #schema }\n\n«Схема» — это определение или описание чего-либо. Не код, который это реализует, а только абстрактное описание.\n\n#### «Схема» API { #api-schema }\n\nВ данном случае [OpenAPI](https://github.com/OAI/OpenAPI-Specification) — это спецификация, которая определяет, как описывать схему вашего API.\n\nЭто определение схемы включает пути вашего API, возможные параметры, которые они принимают, и т.п.\n\n#### «Схема» данных { #data-schema }\n\nТермин «схема» также может относиться к форме некоторых данных, например, к содержимому JSON.\n\nВ таком случае это будут атрибуты JSON, их типы данных и т.п.\n\n#### OpenAPI и JSON Schema { #openapi-and-json-schema }\n\nOpenAPI определяет схему API для вашего API. И эта схема включает определения (или «схемы») данных, отправляемых и получаемых вашим API, с использованием стандарта **JSON Schema** для схем данных JSON.\n\n#### Посмотрите `openapi.json` { #check-the-openapi-json }\n\nЕсли вам интересно, как выглядит исходная схема OpenAPI, FastAPI автоматически генерирует JSON (схему) с описанием всего вашего API.\n\nВы можете посмотреть её напрямую по адресу: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).\n\nВы увидите JSON, начинающийся примерно так:\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### Для чего нужен OpenAPI { #what-is-openapi-for }\n\nСхема OpenAPI является основой для обеих включённых систем интерактивной документации.\n\nЕсть десятки альтернатив, все основаны на OpenAPI. Вы можете легко добавить любую из них в ваше приложение, созданное с **FastAPI**.\n\nВы также можете использовать её для автоматической генерации кода для клиентов, которые взаимодействуют с вашим API. Например, для фронтенд-, мобильных или IoT-приложений.\n\n### Настройте app `entrypoint` в `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nВы можете указать расположение вашего приложения в файле `pyproject.toml`, например:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nЭтот `entrypoint` подскажет команде `fastapi`, что приложение нужно импортировать так:\n\n```python\nfrom main import app\n```\n\nЕсли структура вашего кода выглядит так:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nТогда следует указать такой `entrypoint`:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nчто будет эквивалентно:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` с путём { #fastapi-dev-with-path }\n\nВы также можете передать путь к файлу в команду `fastapi dev`, и она попытается определить объект приложения FastAPI для использования:\n\n```console\n$ fastapi dev main.py\n```\n\nНо в этом случае вам придётся каждый раз помнить о передаче корректного пути при вызове команды `fastapi`.\n\nКроме того, другие инструменты могут его не найти, например [Расширение VS Code](../editor-support.md) или [FastAPI Cloud](https://fastapicloud.com), поэтому рекомендуется использовать `entrypoint` в `pyproject.toml`.\n\n### Разверните приложение (необязательно) { #deploy-your-app-optional }\n\nПри желании вы можете развернуть своё приложение FastAPI в [FastAPI Cloud](https://fastapicloud.com), перейдите и присоединитесь к списку ожидания, если ещё не сделали этого. 🚀\n\nЕсли у вас уже есть аккаунт **FastAPI Cloud** (мы пригласили вас из списка ожидания 😉), вы можете развернуть приложение одной командой.\n\nПеред развертыванием убедитесь, что вы вошли в систему:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\nЗатем разверните приложение:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nГотово! Теперь вы можете открыть своё приложение по этому URL. ✨\n\n## Рассмотрим поэтапно { #recap-step-by-step }\n\n### Шаг 1: импортируйте `FastAPI` { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI` — это класс на Python, который предоставляет всю функциональность для вашего API.\n\n/// note | Технические детали\n\n`FastAPI` — это класс, который напрямую наследуется от `Starlette`.\n\nВы можете использовать весь функционал [Starlette](https://www.starlette.dev/) и в `FastAPI`.\n\n///\n\n### Шаг 2: создайте экземпляр `FastAPI` { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\nЗдесь переменная `app` будет экземпляром класса `FastAPI`.\n\nЭто будет основная точка взаимодействия для создания всего вашего API.\n\n### Шаг 3: создайте *операцию пути (path operation)* { #step-3-create-a-path-operation }\n\n#### Путь (path) { #path }\n\nЗдесь «путь» — это последняя часть URL, начиная с первого символа `/`.\n\nИтак, в таком URL:\n\n```\nhttps://example.com/items/foo\n```\n\n...путь будет:\n\n```\n/items/foo\n```\n\n/// info | Информация\n\n«Путь» также часто называют «эндпоинт» или «маршрут».\n\n///\n\nПри создании API «путь» — это основной способ разделения «задач» и «ресурсов».\n\n#### Операция (operation) { #operation }\n\n«Операция» здесь — это один из HTTP-«методов».\n\nОдин из:\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n...и более экзотические:\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\nВ протоколе HTTP можно обращаться к каждому пути, используя один (или несколько) из этих «методов».\n\n---\n\nПри создании API обычно используют конкретные HTTP-методы для выполнения конкретных действий.\n\nОбычно используют:\n\n* `POST`: создать данные.\n* `GET`: прочитать данные.\n* `PUT`: обновить данные.\n* `DELETE`: удалить данные.\n\nТаким образом, в OpenAPI каждый HTTP-метод называется «операцией».\n\nМы тоже будем называть их «операциями».\n\n#### Определите *декоратор операции пути (path operation decorator)* { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\n`@app.get(\"/\")` сообщает **FastAPI**, что функция прямо под ним отвечает за обработку запросов, поступающих:\n\n* по пути `/`\n* с использованием <dfn title=\"метод HTTP GET\"><code>get</code> операции</dfn>\n\n/// info | Информация о `@decorator`\n\nСинтаксис `@something` в Python называется «декоратор».\n\nЕго размещают над функцией. Как красивая декоративная шляпа (кажется, отсюда и пошёл термин).\n\n«Декоратор» берёт функцию ниже и делает с ней что-то.\n\nВ нашем случае этот декоратор сообщает **FastAPI**, что функция ниже соответствует **пути** `/` с **операцией** `get`.\n\nЭто и есть «декоратор операции пути».\n\n///\n\nМожно также использовать другие операции:\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\nИ более экзотические:\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip | Подсказка\n\nВы можете использовать каждый метод (HTTP-операцию) так, как считаете нужным.\n\n**FastAPI** не навязывает какого-либо конкретного смысла.\n\nЭта информация дана как рекомендация, а не требование.\n\nНапример, при использовании GraphQL обычно все действия выполняются только с помощью POST-операций.\n\n///\n\n### Шаг 4: определите **функцию операции пути** { #step-4-define-the-path-operation-function }\n\nВот наша «функция операции пути»:\n\n* **путь**: `/`.\n* **операция**: `get`.\n* **функция**: функция ниже «декоратора» (ниже `@app.get(\"/\")`).\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\nЭто функция на Python.\n\n**FastAPI** будет вызывать её каждый раз, когда получает запрос к URL «`/`» с операцией `GET`.\n\nВ данном случае это асинхронная (`async`) функция.\n\n---\n\nВы также можете определить её как обычную функцию вместо `async def`:\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note | Примечание\n\nЕсли вы не знаете, в чём разница, посмотрите [Асинхронность: *\"Нет времени?\"*](../async.md#in-a-hurry).\n\n///\n\n### Шаг 5: верните содержимое { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\nВы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д.\n\nТакже можно вернуть модели Pydantic (подробнее об этом позже).\n\nМногие другие объекты и модели будут автоматически преобразованы в JSON (включая ORM и т.п.). Попробуйте использовать те, что вам привычнее, с высокой вероятностью они уже поддерживаются.\n\n### Шаг 6: разверните приложение { #step-6-deploy-it }\n\nРазверните приложение в **[FastAPI Cloud](https://fastapicloud.com)** одной командой: `fastapi deploy`. 🎉\n\n#### О FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** создан тем же автором и командой, что и **FastAPI**.\n\nОн упрощает процесс **создания образа**, **развертывания** и **доступа** к API с минимальными усилиями.\n\nОн переносит тот же **опыт разработчика** при создании приложений с FastAPI на их **развертывание** в облаке. 🎉\n\nFastAPI Cloud — основной спонсор и источник финансирования для open-source проектов «FastAPI и друзья». ✨\n\n#### Развертывание у других облачных провайдеров { #deploy-to-other-cloud-providers }\n\nFastAPI — open-source и основан на стандартах. Вы можете развернуть приложения FastAPI у любого облачного провайдера по вашему выбору.\n\nСледуйте руководствам вашего облачного провайдера, чтобы развернуть приложения FastAPI у них. 🤓\n\n## Резюме { #recap }\n\n* Импортируйте `FastAPI`.\n* Создайте экземпляр `app`.\n* Напишите **декоратор операции пути**, например `@app.get(\"/\")`.\n* Определите **функцию операции пути**; например, `def root(): ...`.\n* Запустите сервер разработки командой `fastapi dev`.\n* При желании разверните приложение командой `fastapi deploy`.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/handling-errors.md",
    "content": "# Обработка ошибок { #handling-errors }\n\nСуществует множество ситуаций, когда необходимо сообщить об ошибке клиенту, использующему ваш API.\n\nТаким клиентом может быть браузер с фронтендом, чужой код, IoT-устройство и т.д.\n\nВозможно, вам придется сообщить клиенту о следующем:\n\n* Клиент не имеет достаточных привилегий для выполнения данной операции.\n* Клиент не имеет доступа к данному ресурсу.\n* Элемент, к которому клиент пытался получить доступ, не существует.\n* и т.д.\n\nВ таких случаях обычно возвращают **HTTP статус-код** в диапазоне **400** (от 400 до 499).\n\nОни похожи на двухсотые HTTP статус-коды (от 200 до 299), которые означают, что запрос обработан успешно.\n\nЧетырёхсотые статус-коды означают, что ошибка произошла по вине клиента.\n\nПомните ли ошибки **\"404 Not Found \"** (и шутки) ?\n\n## Использование `HTTPException` { #use-httpexception }\n\nДля возврата клиенту HTTP-ответов с ошибками используется `HTTPException`.\n\n### Импортируйте `HTTPException` { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### Вызовите `HTTPException` в своем коде { #raise-an-httpexception-in-your-code }\n\n`HTTPException` - это обычное исключение Python с дополнительными данными, актуальными для API.\n\nПоскольку это исключение Python, то его не `возвращают`, а `вызывают`.\n\nЭто также означает, что если вы находитесь внутри функции, которая вызывается внутри вашей *функции операции пути*, и вы поднимаете `HTTPException` внутри этой функции, то она не будет выполнять остальной код в *функции операции пути*, а сразу завершит запрос и отправит HTTP-ошибку из `HTTPException` клиенту.\n\nО том, насколько выгоднее `вызывать` исключение, чем `возвращать` значение, будет рассказано в разделе, посвященном зависимостям и безопасности.\n\nВ данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`:\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### Возвращаемый ответ { #the-resulting-response }\n\nЕсли клиент запросит `http://example.com/items/foo` (`item_id` `\"foo\"`), то он получит статус-код 200 и ответ в формате JSON:\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\nНо если клиент запросит `http://example.com/items/bar` (несуществующий `item_id` `\"bar\"`), то он получит статус-код 404 (ошибка \"не найдено\") и JSON-ответ в виде:\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip | Подсказка\n\nПри вызове `HTTPException` в качестве параметра `detail` можно передавать любое значение, которое может быть преобразовано в JSON, а не только `str`.\n\nВы можете передать `dict`, `list` и т.д.\n\nОни автоматически обрабатываются **FastAPI** и преобразуются в JSON.\n\n///\n\n## Добавление пользовательских заголовков { #add-custom-headers }\n\nВ некоторых ситуациях полезно иметь возможность добавлять пользовательские HTTP-заголовки к ошибке HTTP. Например, для некоторых типов безопасности.\n\nСкорее всего, вам не потребуется использовать его непосредственно в коде.\n\nНо в случае, если это необходимо для продвинутого сценария, можно добавить пользовательские заголовки:\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## Установка пользовательских обработчиков исключений { #install-custom-exception-handlers }\n\nВы можете добавить пользовательские обработчики исключений с помощью [тех же утилит обработки исключений из Starlette](https://www.starlette.dev/exceptions/).\n\nДопустим, у вас есть пользовательское исключение `UnicornException`, которое вы (или используемая вами библиотека) можете `вызвать`.\n\nИ вы хотите обрабатывать это исключение глобально с помощью FastAPI.\n\nМожно добавить собственный обработчик исключений с помощью `@app.exception_handler()`:\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\nЗдесь, если запросить `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`.\n\nНо оно будет обработано `unicorn_exception_handler`.\n\nТаким образом, вы получите чистую ошибку с кодом состояния HTTP `418` и содержимым JSON:\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | Технические детали\n\nТакже можно использовать `from starlette.requests import Request` и `from starlette.responses import JSONResponse`.\n\n**FastAPI** предоставляет тот же `starlette.responses`, что и `fastapi.responses`, просто для удобства разработчика. Однако большинство доступных ответов поступает непосредственно из Starlette. То же самое касается и `Request`.\n\n///\n\n## Переопределение стандартных обработчиков исключений { #override-the-default-exception-handlers }\n\n**FastAPI** имеет некоторые обработчики исключений по умолчанию.\n\nЭти обработчики отвечают за возврат стандартных JSON-ответов при `вызове` `HTTPException` и при наличии в запросе недопустимых данных.\n\nВы можете переопределить эти обработчики исключений на свои собственные.\n\n### Переопределение обработчика исключений проверки запроса { #override-request-validation-exceptions }\n\nКогда запрос содержит недопустимые данные, **FastAPI** внутренне вызывает ошибку `RequestValidationError`.\n\nА также включает в себя обработчик исключений по умолчанию.\n\nЧтобы переопределить его, импортируйте `RequestValidationError` и используйте его с `@app.exception_handler(RequestValidationError)` для создания обработчика исключений.\n\nОбработчик исключения получит объект `Request` и исключение.\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\nТеперь, если перейти к `/items/foo`, то вместо стандартной JSON-ошибки с:\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\nвы получите текстовую версию:\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### Переопределите обработчик ошибок `HTTPException` { #override-the-httpexception-error-handler }\n\nАналогичным образом можно переопределить обработчик `HTTPException`.\n\nНапример, для этих ошибок можно вернуть обычный текстовый ответ вместо JSON:\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | Технические детали\n\nМожно также использовать `from starlette.responses import PlainTextResponse`.\n\n**FastAPI** предоставляет тот же `starlette.responses`, что и `fastapi.responses`, просто для удобства разработчика. Однако большинство доступных ответов поступает непосредственно из Starlette.\n\n///\n\n/// warning | Внимание\n\nИмейте в виду, что `RequestValidationError` содержит информацию об имени файла и строке, где произошла ошибка валидации, чтобы вы могли при желании отобразить её в логах с релевантными данными.\n\nНо это означает, что если вы просто преобразуете её в строку и вернёте эту информацию напрямую, вы можете допустить небольшую утечку информации о своей системе, поэтому здесь код извлекает и показывает каждую ошибку отдельно.\n\n///\n\n### Используйте тело `RequestValidationError` { #use-the-requestvalidationerror-body }\n\nОшибка `RequestValidationError` содержит полученное `тело` с недопустимыми данными.\n\nВы можете использовать его при разработке приложения для регистрации тела и его отладки, возврата пользователю и т.д.\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\nТеперь попробуйте отправить недействительный элемент, например:\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\nВы получите ответ о том, что данные недействительны, содержащий следующее тело:\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### `HTTPException` в FastAPI или в Starlette { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI** имеет собственный `HTTPException`.\n\nКласс ошибок **FastAPI** `HTTPException` наследует от класса ошибок Starlette `HTTPException`.\n\nЕдинственное отличие состоит в том, что `HTTPException` в **FastAPI** принимает любые данные, пригодные для преобразования в JSON, в поле `detail`, тогда как `HTTPException` в Starlette принимает для него только строки.\n\nТаким образом, вы можете продолжать вызывать `HTTPException` от **FastAPI** как обычно в своем коде.\n\nНо когда вы регистрируете обработчик исключений, вы должны зарегистрировать его для `HTTPException` от Starlette.\n\nТаким образом, если какая-либо часть внутреннего кодa Starlette, расширение или плагин Starlette вызовет исключение Starlette `HTTPException`, ваш обработчик сможет перехватить и обработать его.\n\nВ данном примере, чтобы иметь возможность использовать оба `HTTPException` в одном коде, исключения Starlette переименованы в `StarletteHTTPException`:\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### Переиспользование обработчиков исключений **FastAPI** { #reuse-fastapis-exception-handlers }\n\nЕсли вы хотите использовать исключение вместе с теми же обработчиками исключений по умолчанию из **FastAPI**, вы можете импортировать и повторно использовать обработчики исключений по умолчанию из `fastapi.exception_handlers`:\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\nВ этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/header-param-models.md",
    "content": "# Модели Header-параметров { #header-parameter-models }\n\nЕсли у вас есть группа связанных **header-параметров**, то вы можете объединить их в одну **Pydantic-модель**.\n\nЭто позволит вам **переиспользовать модель** в **разных местах**, а также задать валидацию и метаданные сразу для всех параметров. 😎\n\n/// note | Заметка\n\nЭтот функционал доступен в FastAPI начиная с версии `0.115.0`. 🤓\n\n///\n\n## Header-параметры в виде Pydantic-модели { #header-parameters-with-a-pydantic-model }\n\nОбъявите нужные **header-параметры** в **Pydantic-модели** и затем аннотируйте параметр как `Header`:\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\n**FastAPI** **извлечёт** данные для **каждого поля** из **заголовков** запроса и выдаст заданную вами Pydantic-модель.\n\n## Проверьте документацию { #check-the-docs }\n\nВы можете посмотреть нужные header-параметры в графическом интерфейсе сгенерированной документации по пути `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## Как запретить дополнительные заголовки { #forbid-extra-headers }\n\nВ некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** заголовки, которые вы хотите получать.\n\nВы можете использовать возможности конфигурации Pydantic-модели для того, чтобы запретить (`forbid`) любые дополнительные (`extra`) поля:\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\nЕсли клиент попробует отправить **дополнительные заголовки**, то в ответ он получит **ошибку**.\n\nНапример, если клиент попытается отправить заголовок `tool` со значением `plumbus`, то в ответ он получит ошибку, сообщающую ему, что header-параметр `tool` не разрешен:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## Как отключить автоматическое преобразование подчеркиваний { #disable-convert-underscores }\n\nКак и в случае с обычными заголовками, если у вас в именах параметров имеются символы подчеркивания, они **автоматически преобразовываются в дефис**.\n\nНапример, если в коде есть header-параметр `save_data`, то ожидаемый HTTP-заголовок будет `save-data` и именно так он будет отображаться в документации.\n\nЕсли по каким-то причинам вам нужно отключить данное автоматическое преобразование, это можно сделать и для Pydantic-моделей для header-параметров.\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | Внимание\n\nПеред тем как устанавливать для параметра `convert_underscores` значение `False`, имейте в виду, что некоторые HTTP-прокси и серверы не разрешают использовать заголовки с символами подчеркивания.\n\n///\n\n## Резюме { #summary }\n\nВы можете использовать **Pydantic-модели** для объявления **header-параметров** в **FastAPI**. 😎\n"
  },
  {
    "path": "docs/ru/docs/tutorial/header-params.md",
    "content": "# Header-параметры { #header-parameters }\n\nВы можете определить параметры заголовка таким же образом, как вы определяете параметры `Query`, `Path` и `Cookie`.\n\n## Импорт `Header` { #import-header }\n\nСперва импортируйте `Header`:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## Объявление параметров `Header` { #declare-header-parameters }\n\nЗатем объявите параметры заголовка, используя ту же структуру, что и с `Path`, `Query` и `Cookie`.\n\nПервое значение является значением по умолчанию, вы можете передать все дополнительные параметры валидации или аннотации:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Технические детали\n\n`Header` - это \"родственный\" класс `Path`, `Query` и `Cookie`. Он также наследуется от того же общего класса `Param`.\n\nНо помните, что когда вы импортируете `Query`, `Path`, `Header` и другие из `fastapi`, на самом деле это функции, которые возвращают специальные классы.\n\n///\n\n/// info | Информация\n\nЧтобы объявить заголовки, важно использовать `Header`, иначе параметры интерпретируются как query-параметры.\n\n///\n\n## Автоматическое преобразование { #automatic-conversion }\n\n`Header` обладает небольшой дополнительной функциональностью в дополнение к тому, что предоставляют `Path`, `Query` и `Cookie`.\n\nБольшинство стандартных заголовков разделены символом \"дефис\", также известным как \"минус\" (`-`).\n\nНо переменная вроде `user-agent` недопустима в Python.\n\nПо умолчанию `Header` преобразует символы имен параметров из символа подчеркивания (`_`) в дефис (`-`) для извлечения и документирования заголовков.\n\nКроме того, HTTP-заголовки не чувствительны к регистру, поэтому вы можете объявить их в стандартном стиле Python (также известном как \"snake_case\").\n\nТаким образом вы можете использовать `user_agent`, как обычно, в коде Python, вместо того, чтобы вводить заглавные буквы как `User_Agent` или что-то подобное.\n\nЕсли по какой-либо причине вам необходимо отключить автоматическое преобразование подчеркиваний в дефисы, установите для параметра `convert_underscores` в `Header` значение `False`:\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | Внимание\n\nПрежде чем установить для `convert_underscores` значение `False`, имейте в виду, что некоторые HTTP-прокси и серверы запрещают использование заголовков с подчеркиванием.\n\n///\n\n## Повторяющиеся заголовки { #duplicate-headers }\n\nЕсть возможность получать несколько заголовков с одним и тем же именем, но разными значениями.\n\nВы можете определить эти случаи, используя список в объявлении типа.\n\nВы получите все значения из повторяющегося заголовка в виде `list` Python.\n\nНапример, чтобы объявить заголовок `X-Token`, который может появляться более одного раза, вы можете написать:\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\nЕсли вы взаимодействуете с этой *операцией пути*, отправляя два HTTP-заголовка, таких как:\n\n```\nX-Token: foo\nX-Token: bar\n```\n\nОтвет был бы таким:\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## Резюме { #recap }\n\nОбъявляйте заголовки с помощью `Header`, используя тот же общий шаблон, как при `Query`, `Path` и `Cookie`.\n\nИ не беспокойтесь о символах подчеркивания в ваших переменных, **FastAPI** позаботится об их преобразовании.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/index.md",
    "content": "# Учебник - Руководство пользователя { #tutorial-user-guide }\n\nВ этом руководстве шаг за шагом показано, как использовать **FastAPI** с большинством его функций.\n\nКаждый раздел постепенно основывается на предыдущих, но структура разделяет темы, так что вы можете сразу перейти к нужной теме для решения ваших конкретных задач по API.\n\nОн также создан как справочник на будущее, чтобы вы могли вернуться и посмотреть именно то, что вам нужно.\n\n## Запустите код { #run-the-code }\n\nВсе блоки кода можно копировать и использовать напрямую (это действительно протестированные файлы Python).\n\nЧтобы запустить любой из примеров, скопируйте код в файл `main.py` и запустите `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n**НАСТОЯТЕЛЬНО рекомендуется** написать или скопировать код, отредактировать его и запустить локально.\n\nИспользование кода в вашем редакторе кода — это то, что действительно показывает преимущества FastAPI: вы увидите, как мало кода нужно написать, все проверки типов, автозавершение и т.д.\n\n---\n\n## Установка FastAPI { #install-fastapi }\n\nПервый шаг — установить FastAPI.\n\nУбедитесь, что вы создали [виртуальное окружение](../virtual-environments.md), активировали его, и затем **установите FastAPI**:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | Примечание\n\nПри установке с помощью `pip install \"fastapi[standard]\"` добавляются некоторые стандартные необязательные зависимости по умолчанию, включая `fastapi-cloud-cli`, который позволяет развернуть приложение на [FastAPI Cloud](https://fastapicloud.com).\n\nЕсли вы не хотите иметь эти необязательные зависимости, установите просто `pip install fastapi`.\n\nЕсли вы хотите установить стандартные зависимости, но без `fastapi-cloud-cli`, установите `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n///\n\n/// tip | Совет\n\nУ FastAPI есть [официальное расширение для VS Code](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (и Cursor), которое предоставляет множество функций, включая обзор операций пути, поиск операций пути, навигацию CodeLens в тестах (переход к определению из тестов), а также развертывание в FastAPI Cloud и просмотр логов - всё прямо из вашего редактора кода.\n\n///\n\n## Продвинутое руководство пользователя { #advanced-user-guide }\n\nСуществует также **Продвинутое руководство пользователя**, которое вы сможете прочитать после **Учебник - Руководство пользователя**.\n\n**Продвинутое руководство пользователя** основано на этом, использует те же концепции и обучает некоторым дополнительным функциям.\n\nНо сначала вам следует прочитать **Учебник - Руководство пользователя** (то, что вы читаете прямо сейчас).\n\nОно спроектировано так, что вы можете создать полноценное приложение, используя только **Учебник - Руководство пользователя**, а затем расширить его различными способами, в зависимости от ваших потребностей, используя дополнительные идеи из **Продвинутого руководства пользователя**.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/metadata.md",
    "content": "# URL-адреса метаданных и документации { #metadata-and-docs-urls }\n\nВы можете настроить несколько конфигураций метаданных в вашем **FastAPI** приложении.\n\n## Метаданные для API { #metadata-for-api }\n\nВы можете задать следующие поля, которые используются в спецификации OpenAPI и в UI автоматической документации API:\n\n| Параметр | Тип | Описание |\n|------------|------|-------------|\n| `title` | `str` | Заголовок API. |\n| `summary` | `str` | Краткое резюме API. <small>Доступно начиная с OpenAPI 3.1.0, FastAPI 0.99.0.</small> |\n| `description` | `str` | Краткое описание API. Может быть использован Markdown. |\n| `version` | `string` | Версия API. Версия вашего собственного приложения, а не OpenAPI. К примеру `2.5.0`. |\n| `terms_of_service` | `str` | Ссылка к условиям пользования API. Если указано, то это должен быть URL-адрес. |\n| `contact` | `dict` | Контактная информация для открытого API. Может содержать несколько полей. <details><summary>поля <code>contact</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Идентификационное имя контактного лица/организации.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL указывающий на контактную информацию. ДОЛЖЕН быть в формате URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>Email адрес контактного лица/организации. ДОЛЖЕН быть в формате email адреса.</td></tr></tbody></table></details> |\n| `license_info` | `dict` | Информация о лицензии открытого API. Может содержать несколько полей. <details><summary>поля <code>license_info</code></summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Описание</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ОБЯЗАТЕЛЬНО</strong> (если установлен параметр <code>license_info</code>). Название лицензии, используемой для API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Выражение лицензии [SPDX](https://spdx.org/licenses/) для API. Поле <code>identifier</code> взаимоисключающее с полем <code>url</code>. <small>Доступно начиная с OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL, указывающий на лицензию, используемую для API. ДОЛЖЕН быть в формате URL.</td></tr></tbody></table></details> |\n\nВы можете задать их следующим образом:\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | Подсказка\n\nВы можете использовать Markdown в поле `description`, и оно будет отображено в выводе.\n\n///\n\nС этой конфигурацией автоматическая документация API будет выглядеть так:\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## Идентификатор лицензии { #license-identifier }\n\nНачиная с OpenAPI 3.1.0 и FastAPI 0.99.0, вы также можете задать `license_info` с помощью `identifier` вместо `url`.\n\nК примеру:\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## Метаданные для тегов { #metadata-for-tags }\n\nВы также можете добавить дополнительные метаданные для различных тегов, используемых для группировки ваших операций пути с помощью параметра `openapi_tags`.\n\nОн принимает список, содержащий один словарь для каждого тега.\n\nКаждый словарь может содержать в себе:\n\n* `name` (**обязательно**): `str`-значение с тем же именем тега, которое вы используете в параметре `tags` в ваших *операциях пути* и `APIRouter`ах.\n* `description`: `str`-значение с кратким описанием для тега. Может содержать Markdown и будет отображаться в UI документации.\n* `externalDocs`:  `dict`-значение описывающее внешнюю документацию. Включает в себя:\n    * `description`: `str`-значение с кратким описанием для внешней документации.\n    * `url` (**обязательно**): `str`-значение с URL-адресом для внешней документации.\n\n### Создание метаданных для тегов { #create-metadata-for-tags }\n\nДавайте попробуем сделать это на примере с тегами для `users` и `items`.\n\nСоздайте метаданные для ваших тегов и передайте их в параметре `openapi_tags`:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\nПомните, что вы можете использовать Markdown внутри описания, к примеру \"login\" будет отображен жирным шрифтом (**login**) и \"fancy\" будет отображаться курсивом (_fancy_).\n\n/// tip | Подсказка\n\nВам необязательно добавлять метаданные для всех используемых тегов\n\n///\n\n### Используйте собственные теги { #use-your-tags }\n\nИспользуйте параметр `tags` с вашими *операциями пути* (и `APIRouter`ами), чтобы присвоить им различные теги:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info | Дополнительная информация\n\nУзнайте больше о тегах в [Конфигурации операции пути](path-operation-configuration.md#tags).\n\n///\n\n### Проверьте документацию { #check-the-docs }\n\nТеперь, если вы проверите документацию, вы увидите всю дополнительную информацию:\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### Порядок расположения тегов { #order-of-tags }\n\nПорядок расположения словарей метаданных для каждого тега определяет также порядок, отображаемый в UI документации.\n\nК примеру, несмотря на то, что `users` будут идти после `items` в алфавитном порядке, они отображаются раньше, потому что мы добавляем свои метаданные в качестве первого словаря в списке.\n\n## URL-адрес OpenAPI { #openapi-url }\n\nПо умолчанию схема OpenAPI отображена по адресу `/openapi.json`.\n\nНо вы можете изменить это с помощью параметра `openapi_url`.\n\nК примеру, чтобы задать её отображение по адресу `/api/v1/openapi.json`:\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\nЕсли вы хотите отключить схему OpenAPI полностью, вы можете задать `openapi_url=None`, это также отключит пользовательские интерфейсы документации, которые её используют.\n\n## URL-адреса документации { #docs-urls }\n\nВы можете изменить конфигурацию двух пользовательских интерфейсов документации, которые включены:\n\n* **Swagger UI**: отображаемый по адресу `/docs`.\n    * Вы можете задать его URL с помощью параметра `docs_url`.\n    * Вы можете отключить это с помощью настройки `docs_url=None`.\n* **ReDoc**: отображаемый по адресу `/redoc`.\n    * Вы можете задать его URL с помощью параметра `redoc_url`.\n    * Вы можете отключить это с помощью настройки `redoc_url=None`.\n\nК примеру, чтобы задать отображение Swagger UI по адресу `/documentation` и отключить ReDoc:\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/ru/docs/tutorial/middleware.md",
    "content": "# Middleware (Промежуточный слой) { #middleware }\n\nВы можете добавить middleware (промежуточный слой) в **FastAPI** приложение.\n\n\"Middleware\" - это функция, которая выполняется с каждым **запросом** до его обработки какой-либо конкретной *операцией пути*. А также с каждым **ответом** перед его возвращением.\n\n* Она принимает каждый поступающий **запрос**.\n* Может что-то сделать с этим **запросом** или выполнить любой нужный код.\n* Затем передает **запрос** для последующей обработки (какой-либо *операцией пути*).\n* Получает **ответ** (от *операции пути*).\n* Может что-то сделать с этим **ответом** или выполнить любой нужный код.\n* И возвращает **ответ**.\n\n/// note | Технические детали\n\nЕсли у вас есть зависимости с `yield`, то код выхода (код после `yield`) будет выполняться *после* middleware.\n\nЕсли были какие‑либо фоновые задачи (рассматриваются в разделе [Фоновые задачи](background-tasks.md), вы увидите это позже), они будут запущены *после* всех middleware.\n\n///\n\n## Создание middleware { #create-a-middleware }\n\nДля создания middleware используйте декоратор `@app.middleware(\"http\")` поверх функции.\n\nФункция middleware получает:\n\n* `request`.\n* Функцию `call_next`, которая получает `request` в качестве параметра.\n    * Эта функция передаёт `request` соответствующей *операции пути*.\n    * Затем она возвращает `response`, сгенерированный соответствующей *операцией пути*.\n* Также имеется возможность видоизменить `response` перед тем как его вернуть.\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip | Совет\n\nИмейте в виду, что можно добавлять проприетарные HTTP-заголовки [с префиксом `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nНо если вы хотите, чтобы клиент в браузере мог видеть ваши пользовательские заголовки, необходимо добавить их в настройки CORS ([CORS (Cross-Origin Resource Sharing)](cors.md)), используя параметр `expose_headers`, описанный в [документации по CORS Starlette](https://www.starlette.dev/middleware/#corsmiddleware).\n\n///\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette.requests import Request`.\n\n**FastAPI** предоставляет такой доступ для удобства разработчиков. Но, на самом деле, это `Request` из Starlette.\n\n///\n\n### До и после `response` { #before-and-after-the-response }\n\nВы можете добавить код, использующий `request`, до передачи его какой-либо *операции пути*.\n\nА также после формирования `response`, до того, как вы его вернёте.\n\nНапример, вы можете добавить собственный заголовок `X-Process-Time`, содержащий время в секундах, необходимое для обработки запроса и генерации ответа:\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip | Совет\n\nМы используем [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) вместо `time.time()` для обеспечения большей точности в таких случаях. 🤓\n\n///\n\n## Порядок выполнения нескольких middleware { #multiple-middleware-execution-order }\n\nКогда вы добавляете несколько middleware с помощью декоратора `@app.middleware()` или метода `app.add_middleware()`, каждое новое middleware оборачивает приложение, формируя стек. Последнее добавленное middleware — самое внешнее (*outermost*), а первое — самое внутреннее (*innermost*).\n\nНа пути обработки запроса сначала выполняется самое внешнее middleware.\n\nНа пути формирования ответа оно выполняется последним.\n\nНапример:\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\nЭто приводит к следующему порядку выполнения:\n\n* **Запрос**: MiddlewareB → MiddlewareA → маршрут\n\n* **Ответ**: маршрут → MiddlewareA → MiddlewareB\n\nТакое стековое поведение обеспечивает предсказуемый и управляемый порядок выполнения middleware.\n\n## Другие middleware { #other-middlewares }\n\nО других middleware вы можете узнать больше в разделе [Расширенное руководство пользователя: Продвинутое middleware](../advanced/middleware.md).\n\nВ следующем разделе вы можете прочитать, как настроить <abbr title=\"Cross-Origin Resource Sharing - совместное использование ресурсов между источниками\">CORS</abbr> с помощью middleware.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/path-operation-configuration.md",
    "content": "# Конфигурация операций пути { #path-operation-configuration }\n\nСуществует несколько параметров, которые вы можете передать вашему *декоратору операций пути* для его настройки.\n\n/// warning | Внимание\n\nПомните, что эти параметры передаются непосредственно *декоратору операций пути*, а не вашей *функции-обработчику пути*.\n\n///\n\n## Статус-код ответа { #response-status-code }\n\nВы можете определить (HTTP) `status_code`, который будет использован в ответах вашей *операции пути*.\n\nВы можете передать только `int`-значение кода, например `404`.\n\nНо если вы не помните, для чего нужен каждый числовой код, вы можете использовать сокращенные константы в `status`:\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\nЭтот статус-код будет использован в ответе и будет добавлен в схему OpenAPI.\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette import status`.\n\n**FastAPI** предоставляет тот же `starlette.status` под псевдонимом `fastapi.status` для удобства разработчика. Но его источник - это непосредственно Starlette.\n\n///\n\n## Теги { #tags }\n\nВы можете добавлять теги к вашим *операциям пути*, добавив параметр `tags` с `list` заполненным `str`-значениями (обычно в нём только одна строка):\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\nОни будут добавлены в схему OpenAPI и будут использованы в автоматической документации интерфейса:\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### Теги с перечислениями { #tags-with-enums }\n\nЕсли у вас большое приложение, вы можете прийти к необходимости добавить **несколько тегов**, и возможно, вы захотите убедиться в том, что всегда используете **один и тот же тег** для связанных *операций пути*.\n\nВ этих случаях, имеет смысл хранить теги в классе `Enum`.\n\n**FastAPI** поддерживает это так же, как и в случае с обычными строками:\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## Краткое и развёрнутое содержание { #summary-and-description }\n\nВы можете добавить параметры `summary` и `description`:\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## Описание из строк документации { #description-from-docstring }\n\nТак как описания обычно длинные и содержат много строк, вы можете объявить описание *операции пути* в <dfn title=\"многострочная строка, первое выражение внутри функции (не присвоенное какой-либо переменной), используемая для документации\">строке документации</dfn> функции, и **FastAPI** прочитает её оттуда.\n\nВы можете использовать [Markdown](https://en.wikipedia.org/wiki/Markdown) в строке документации, и он будет интерпретирован и отображён корректно (с учетом отступа в строке документации).\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\nОн будет использован в интерактивной документации:\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## Описание ответа { #response-description }\n\nВы можете указать описание ответа с помощью параметра `response_description`:\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info | Дополнительная информация\n\nПомните, что `response_description` относится конкретно к ответу, а `description` относится к *операции пути* в целом.\n\n///\n\n/// check | Проверка\n\nOpenAPI указывает, что каждой *операции пути* необходимо описание ответа.\n\nЕсли вдруг вы не укажете его, то **FastAPI** автоматически сгенерирует это описание с текстом \"Successful response\".\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## Обозначение *операции пути* как устаревшей { #deprecate-a-path-operation }\n\nЕсли вам необходимо пометить *операцию пути* как <dfn title=\"устаревшая, рекомендуется не использовать\">устаревшую</dfn>, при этом не удаляя её, передайте параметр `deprecated`:\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\nОн будет четко помечен как устаревший в интерактивной документации:\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\nПроверьте, как будут выглядеть устаревшие и не устаревшие *операции пути*:\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## Резюме { #recap }\n\nВы можете легко конфигурировать и добавлять метаданные в ваши *операции пути*, передавая параметры *декораторам операций пути*.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/path-params-numeric-validations.md",
    "content": "# Path-параметры и валидация числовых данных { #path-parameters-and-numeric-validations }\n\nТак же, как с помощью `Query` вы можете добавлять валидацию и метаданные для query-параметров, так и с помощью `Path` вы можете добавлять такую же валидацию и метаданные для path-параметров.\n\n## Импорт `Path` { #import-path }\n\nСначала импортируйте `Path` из `fastapi`, а также импортируйте `Annotated`:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info | Информация\n\nПоддержка `Annotated` была добавлена в FastAPI начиная с версии 0.95.0 (и с этой версии рекомендуется использовать этот подход).\n\nЕсли вы используете более старую версию, вы столкнётесь с ошибками при попытке использовать `Annotated`.\n\nУбедитесь, что вы [обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) как минимум до 0.95.1 перед тем, как использовать `Annotated`.\n\n///\n\n## Определите метаданные { #declare-metadata }\n\nВы можете указать все те же параметры, что и для `Query`.\n\nНапример, чтобы указать значение метаданных `title` для path-параметра `item_id`, вы можете написать:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note | Примечание\n\nPath-параметр всегда является обязательным, поскольку он должен быть частью пути. Даже если вы объявите его как `None` или зададите значение по умолчанию, это ни на что не повлияет — параметр всё равно будет обязательным.\n\n///\n\n## Задайте нужный вам порядок параметров { #order-the-parameters-as-you-need }\n\n/// tip | Подсказка\n\nЭто не имеет большого значения, если вы используете `Annotated`.\n\n///\n\nДопустим, вы хотите объявить query-параметр `q` как обязательный параметр типа `str`.\n\nИ если вам больше ничего не нужно указывать для этого параметра, то нет необходимости использовать `Query`.\n\nНо вам по-прежнему нужно использовать `Path` для path-параметра `item_id`. И по какой-либо причине вы не хотите использовать `Annotated`.\n\nЕсли вы поместите параметр со значением по умолчанию перед другим параметром, у которого нет значения по умолчанию, то Python укажет на ошибку.\n\nНо вы можете изменить порядок параметров, чтобы параметр без значения по умолчанию (query-параметр `q`) шёл первым.\n\nЭто не имеет значения для **FastAPI**. Он распознает параметры по их названиям, типам и значениям по умолчанию (`Query`, `Path`, и т.д.), ему не важен их порядок.\n\nПоэтому вы можете определить функцию так:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\nНо имейте в виду, что если вы используете `Annotated`, вы не столкнётесь с этой проблемой, так как вы не используете значения по умолчанию параметров функции для `Query()` или `Path()`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## Задайте нужный вам порядок параметров, полезные приёмы { #order-the-parameters-as-you-need-tricks }\n\n/// tip | Подсказка\n\nЭто не имеет большого значения, если вы используете `Annotated`.\n\n///\n\nЗдесь описан **небольшой приём**, который может оказаться удобным, хотя часто он вам не понадобится.\n\nЕсли вы хотите:\n\n* объявить query-параметр `q` без `Query` и без значения по умолчанию\n* объявить path-параметр `item_id` с помощью `Path`\n* указать их в другом порядке\n* не использовать `Annotated`\n\n...то вы можете использовать специальную возможность синтаксиса Python.\n\nПередайте `*` в качестве первого параметра функции.\n\nPython не будет ничего делать с `*`, но он будет знать, что все следующие параметры являются именованными аргументами (парами ключ-значение), также известными как <abbr title=\"От: K-ey W-ord Arg-uments\"><code>kwargs</code></abbr>, даже если у них нет значений по умолчанию.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### Лучше с `Annotated` { #better-with-annotated }\n\nИмейте в виду, что если вы используете `Annotated`, то, поскольку вы не используете значений по умолчанию для параметров функции, у вас не возникнет подобной проблемы и вам, вероятно, не придётся использовать `*`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## Валидация числовых данных: больше или равно { #number-validations-greater-than-or-equal }\n\nС помощью `Query` и `Path` (и других классов, которые мы разберём позже) вы можете добавлять ограничения для числовых данных.\n\nВ этом примере при указании `ge=1`, параметр `item_id` должен быть целым числом \"`g`reater than or `e`qual\" — больше или равно `1`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## Валидация числовых данных: больше и меньше или равно { #number-validations-greater-than-and-less-than-or-equal }\n\nТо же самое применимо к:\n\n* `gt`: больше (`g`reater `t`han)\n* `le`: меньше или равно (`l`ess than or `e`qual)\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## Валидация числовых данных: числа с плавающей точкой, больше и меньше { #number-validations-floats-greater-than-and-less-than }\n\nВалидация также применима к значениям типа `float`.\n\nВ этом случае становится важной возможность добавить ограничение <abbr title=\"greater than - больше чем\"><code>gt</code></abbr>, вместо <abbr title=\"greater than or equal - больше или равно\"><code>ge</code></abbr>, поскольку в таком случае вы можете, например, создать ограничение, чтобы значение было больше `0`, даже если оно меньше `1`.\n\nТаким образом, `0.5` будет корректным значением. А `0.0` или `0` — нет.\n\nТо же самое справедливо и для <abbr title=\"less than - меньше чем\"><code>lt</code></abbr>.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## Резюме { #recap }\n\nС помощью `Query`, `Path` (и других классов, которые мы пока не затронули) вы можете добавлять метаданные и строковую валидацию тем же способом, как и в главе [Query-параметры и валидация строк](query-params-str-validations.md).\n\nА также вы можете добавить валидацию числовых данных:\n\n* `gt`: больше (`g`reater `t`han)\n* `ge`: больше или равно (`g`reater than or `e`qual)\n* `lt`: меньше (`l`ess `t`han)\n* `le`: меньше или равно (`l`ess than or `e`qual)\n\n/// info | Информация\n\n`Query`, `Path` и другие классы, которые вы разберёте позже, являются наследниками общего класса `Param`.\n\nВсе они используют те же параметры для дополнительной валидации и метаданных, которые вы видели ранее.\n\n///\n\n/// note | Технические детали\n\n`Query`, `Path` и другие \"классы\", которые вы импортируете из `fastapi`, на самом деле являются функциями, которые при вызове возвращают экземпляры одноимённых классов.\n\nОбъект `Query`, который вы импортируете, является функцией. И при вызове она возвращает экземпляр одноимённого класса `Query`.\n\nИспользование функций (вместо использования классов напрямую) нужно для того, чтобы ваш редактор не подсвечивал ошибки, связанные с их типами.\n\nТаким образом вы можете использовать привычный вам редактор и инструменты разработки, не добавляя дополнительных конфигураций для игнорирования подобных ошибок.\n\n///\n"
  },
  {
    "path": "docs/ru/docs/tutorial/path-params.md",
    "content": "# Path-параметры { #path-parameters }\n\nВы можете определить \"параметры\" или \"переменные\" пути, используя синтаксис форматированных строк Python:\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\nЗначение параметра пути `item_id` будет передано в функцию в качестве аргумента `item_id`.\n\nЕсли запустите этот пример и перейдёте по адресу: [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), то увидите ответ:\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## Параметры пути с типами { #path-parameters-with-types }\n\nВы можете объявить тип параметра пути в функции, используя стандартные аннотации типов Python:\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\nЗдесь, `item_id` объявлен типом `int`.\n\n/// check | Заметка\n\nЭто обеспечит поддержку редактора кода внутри функции (проверка ошибок, автозавершение и т.п.).\n\n///\n\n## <dfn title=\"также известно как: сериализация, парсинг, маршаллинг\">Преобразование</dfn> данных { #data-conversion }\n\nЕсли запустите этот пример и перейдёте по адресу: [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3), то увидите ответ:\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check | Заметка\n\nОбратите внимание на значение `3`, которое получила (и вернула) функция. Это целочисленный Python `int`, а не строка `\"3\"`.\n\nИспользуя такое объявление типов, **FastAPI** выполняет автоматический HTTP-запрос <dfn title=\"преобразование строки, которая приходит из HTTP-запроса, в данные Python\">\"парсинг\"</dfn>.\n\n///\n\n## Валидация данных { #data-validation }\n\nЕсли откроете браузер по адресу [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), то увидите интересную HTTP-ошибку:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\nиз-за того, что параметр пути `item_id` имеет значение `\"foo\"`, которое не является типом `int`.\n\nТа же ошибка возникнет, если вместо `int` передать `float`, например: [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)\n\n/// check | Заметка\n\n**FastAPI** обеспечивает валидацию данных, используя всё те же определения типов.\n\nОбратите внимание, что в тексте ошибки явно указано место, не прошедшее проверку.\n\nЭто очень полезно при разработке и отладке кода, который взаимодействует с API.\n\n///\n\n## Документация { #documentation }\n\nИ теперь, когда откроете браузер по адресу: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), то увидите вот такую автоматически сгенерированную документацию API:\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check | Заметка\n\nЕщё раз, просто используя определения типов, **FastAPI** обеспечивает автоматическую интерактивную документацию (с интеграцией Swagger UI).\n\nОбратите внимание, что параметр пути объявлен целочисленным.\n\n///\n\n## Преимущества стандартизации, альтернативная документация { #standards-based-benefits-alternative-documentation }\n\nПоскольку сгенерированная схема соответствует стандарту [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md), её можно использовать со множеством совместимых инструментов.\n\nИменно поэтому, **FastAPI** сам предоставляет альтернативную документацию API (используя ReDoc), которую можно получить по адресу: [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\nПо той же причине, есть множество совместимых инструментов, включая инструменты генерации кода для многих языков.\n\n## Pydantic { #pydantic }\n\nВся проверка данных выполняется под капотом с помощью [Pydantic](https://docs.pydantic.dev/), поэтому вы получаете все его преимущества. И вы можете быть уверены, что находитесь в надёжных руках.\n\nВы можете использовать в аннотациях как простые типы данных, вроде `str`, `float`, `bool`, так и более сложные типы.\n\nНекоторые из них рассматриваются в следующих главах данного руководства.\n\n## Порядок имеет значение { #order-matters }\n\nПри создании *операций пути* можно столкнуться с ситуацией, когда путь является фиксированным.\n\nНапример, `/users/me`. Предположим, что это путь для получения данных о текущем пользователе.\n\nУ вас также может быть путь `/users/{user_id}`, чтобы получить данные о конкретном пользователе по его ID.\n\nПоскольку *операции пути* выполняются в порядке их объявления, необходимо, чтобы путь для `/users/me` был объявлен раньше, чем путь для `/users/{user_id}`:\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\nИначе путь для `/users/{user_id}` также будет соответствовать `/users/me`, \"подразумевая\", что он получает параметр `user_id` со значением `\"me\"`.\n\nАналогично, вы не можете переопределить операцию с путем:\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\nПервый будет выполняться всегда, так как путь совпадает первым.\n\n## Предопределенные значения { #predefined-values }\n\nЧто если нам нужно заранее определить допустимые *параметры пути*, которые *операция пути* может принимать? В таком случае можно использовать стандартное перечисление <abbr title=\"Enumeration - Перечисление\">`Enum`</abbr> Python.\n\n### Создание класса `Enum` { #create-an-enum-class }\n\nИмпортируйте `Enum` и создайте подкласс, который наследуется от `str` и `Enum`.\n\nМы наследуемся от `str`, чтобы документация API могла понять, что значения должны быть типа `string` и отображалась правильно.\n\nЗатем создайте атрибуты класса с фиксированными допустимыми значениями:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip | Подсказка\n\nЕсли интересно, то \"AlexNet\", \"ResNet\" и \"LeNet\" - это названия <dfn title=\"Технически, архитектуры моделей глубокого обучения\">моделей</dfn> Машинного обучения.\n\n///\n\n### Определение *параметра пути* { #declare-a-path-parameter }\n\nОпределите *параметр пути*, используя в аннотации типа класс перечисления (`ModelName`), созданный ранее:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### Проверьте документацию { #check-the-docs }\n\nПоскольку доступные значения *параметра пути* определены заранее, интерактивная документация может наглядно их отображать:\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### Работа с *перечислениями* в Python { #working-with-python-enumerations }\n\nЗначение *параметра пути* будет *элементом перечисления*.\n\n#### Сравнение *элементов перечисления* { #compare-enumeration-members }\n\nВы можете сравнить это значение с *элементом перечисления* класса `ModelName`:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### Получение *значения перечисления* { #get-the-enumeration-value }\n\nМожно получить фактическое значение (в данном случае - `str`) с помощью `model_name.value` или в общем случае `your_enum_member.value`:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip | Подсказка\n\nЗначение `\"lenet\"` также можно получить с помощью `ModelName.lenet.value`.\n\n///\n\n#### Возврат *элементов перечисления* { #return-enumeration-members }\n\nИз *операции пути* можно вернуть *элементы перечисления*, даже вложенные в тело JSON (например в `dict`).\n\nОни будут преобразованы в соответствующие значения (в данном случае - строки) перед их возвратом клиенту:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\nНа стороне клиента вы получите такой JSON-ответ:\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## Path-параметры, содержащие пути { #path-parameters-containing-paths }\n\nПредположим, что есть *операция пути* с путем `/files/{file_path}`.\n\nНо вам нужно, чтобы `file_path` сам содержал *путь*, например, `home/johndoe/myfile.txt`.\n\nТогда URL для этого файла будет такой: `/files/home/johndoe/myfile.txt`.\n\n### Поддержка OpenAPI { #openapi-support }\n\nOpenAPI не поддерживает способов объявления *параметра пути*, содержащего внутри *путь*, так как это может привести к сценариям, которые сложно определять и тестировать.\n\nТем не менее это можно сделать в **FastAPI**, используя один из внутренних инструментов Starlette.\n\nДокументация по-прежнему будет работать, хотя и не добавит никакой информации о том, что параметр должен содержать путь.\n\n### Конвертер пути { #path-convertor }\n\nБлагодаря одной из опций Starlette, можете объявить *параметр пути*, содержащий *путь*, используя URL вроде:\n\n```\n/files/{file_path:path}\n```\n\nВ этом случае `file_path` - это имя параметра, а часть `:path`, указывает, что параметр должен соответствовать любому *пути*.\n\nМожете использовать так:\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip | Подсказка\n\nВозможно, вам понадобится, чтобы параметр содержал `/home/johndoe/myfile.txt` с ведущим слэшем (`/`).\n\nВ этом случае URL будет таким: `/files//home/johndoe/myfile.txt`, с двойным слэшем (`//`) между `files` и `home`.\n\n///\n\n## Резюме { #recap }\n\nИспользуя **FastAPI** вместе со стандартными объявлениями типов Python (короткими и интуитивно понятными), вы получаете:\n\n* Поддержку редактора кода (проверку ошибок, автозавершение и т.п.)\n* \"<dfn title=\"преобразование строки, которая приходит из HTTP-запроса, в данные Python\">Парсинг</dfn>\" данных\n* Валидацию данных\n* Аннотации API и автоматическую документацию\n\nИ объявлять типы достаточно один раз.\n\nЭто, вероятно, является главным заметным преимуществом **FastAPI** по сравнению с альтернативными фреймворками (кроме <abbr title=\"не считая оптимизаций\">сырой</abbr> производительности).\n"
  },
  {
    "path": "docs/ru/docs/tutorial/query-param-models.md",
    "content": "# Модели Query-Параметров { #query-parameter-models }\n\nЕсли у вас есть группа связанных **query-параметров**, то вы можете объединить их в одну **Pydantic-модель**.\n\nЭто позволит вам **переиспользовать модель** в **разных местах**, устанавливать валидаторы и метаданные, в том числе для сразу всех параметров, в одном месте. 😎\n\n/// note | Заметка\n\nЭто поддерживается начиная с версии FastAPI `0.115.0`. 🤓\n\n///\n\n## Pydantic-Модель для Query-Параметров { #query-parameters-with-a-pydantic-model }\n\nОбъявите нужные **query-параметры** в **Pydantic-модели**, а после аннотируйте параметр как `Query`:\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\n**FastAPI извлечёт** данные соответствующие **каждому полю модели** из **query-параметров** запроса и выдаст вам объявленную Pydantic-модель заполненную ими.\n\n## Проверьте Сгенерированную Документацию { #check-the-docs }\n\nВы можете посмотреть query-параметры в графическом интерфейсе сгенерированной документации по пути `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## Запретить Дополнительные Query-Параметры { #forbid-extra-query-parameters }\n\nВ некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** query-параметры, которые вы хотите получить.\n\nВы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) все дополнительные (`extra`) поля.\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\nЕсли клиент попробует отправить **дополнительные** данные в **query-параметрах**, то в ответ он получит **ошибку**.\n\nНапример, если клиент попытается отправить query-параметр `tool` с значением `plumbus`, в виде:\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\nТо в ответ он получит **ошибку**, сообщающую ему, что query-параметр `tool` не разрешен:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## Заключение { #summary }\n\nВы можете использовать **Pydantic-модели** для объявления **query-параметров** в **FastAPI**. 😎\n\n/// tip | Совет\n\nСпойлер: вы также можете использовать Pydantic-модели, чтобы объявлять cookies и HTTP-заголовки, но об этом вы прочитаете позже. 🤫\n\n///\n"
  },
  {
    "path": "docs/ru/docs/tutorial/query-params-str-validations.md",
    "content": "# Query-параметры и валидация строк { #query-parameters-and-string-validations }\n\n**FastAPI** позволяет определять дополнительную информацию и выполнять валидацию для ваших параметров.\n\nРассмотрим это приложение в качестве примера:\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\nQuery-параметр `q` имеет тип `str | None`, это означает, что он имеет тип `str`, но также может быть `None`. Значение по умолчанию действительно `None`, поэтому FastAPI будет знать, что он не обязателен.\n\n/// note | Примечание\n\nFastAPI поймёт, что значение `q` не обязательно, из‑за значения по умолчанию `= None`.\n\nАннотация `str | None` позволит вашему редактору кода обеспечить лучшую поддержку и находить ошибки.\n\n///\n\n## Дополнительная валидация { #additional-validation }\n\nМы собираемся добавить ограничение: хотя `q` и необязателен, когда он передан, **его длина не должна превышать 50 символов**.\n\n### Импорт `Query` и `Annotated` { #import-query-and-annotated }\n\nЧтобы сделать это, сначала импортируйте:\n\n* `Query` из `fastapi`\n* `Annotated` из `typing`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info | Дополнительная информация\n\nПоддержка `Annotated` (и рекомендация использовать его) появилась в FastAPI версии 0.95.0.\n\nЕсли у вас более старая версия, при попытке использовать `Annotated` вы получите ошибки.\n\nУбедитесь, что вы [обновили версию FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) как минимум до 0.95.1 перед использованием `Annotated`.\n\n///\n\n## Использовать `Annotated` в типе для параметра `q` { #use-annotated-in-the-type-for-the-q-parameter }\n\nПомните, я уже говорил, что `Annotated` можно использовать для добавления метаданных к параметрам в разделе [Введение в типы Python](../python-types.md#type-hints-with-metadata-annotations)?\n\nПришло время использовать его с FastAPI. 🚀\n\nУ нас была такая аннотация типа:\n\n```Python\nq: str | None = None\n```\n\nМы «обернём» это в `Annotated`, и получится:\n\n```Python\nq: Annotated[str | None] = None\n```\n\nОбе версии означают одно и то же: `q` — параметр, который может быть `str` или `None`, и по умолчанию равен `None`.\n\nА теперь к самому интересному. 🎉\n\n## Добавим `Query` в `Annotated` для параметра `q` { #add-query-to-annotated-in-the-q-parameter }\n\nТеперь, когда у нас есть `Annotated`, куда можно поместить дополнительную информацию (в нашем случае — дополнительные правила валидации), добавим `Query` внутрь `Annotated` и установим параметр `max_length` равным `50`:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\nОбратите внимание, что значение по умолчанию по‑прежнему `None`, то есть параметр остаётся необязательным.\n\nНо теперь, добавив `Query(max_length=50)` внутрь `Annotated`, мы говорим FastAPI, что этому значению нужна **дополнительная валидация** — максимум 50 символов. 😎\n\n/// tip | Совет\n\nЗдесь мы используем `Query()`, потому что это **query-параметр**. Позже мы увидим другие — `Path()`, `Body()`, `Header()` и `Cookie()`, — они также принимают те же аргументы, что и `Query()`.\n\n///\n\nТеперь FastAPI будет:\n\n* **валидировать** данные, удостоверяясь, что максимальная длина — 50 символов;\n* показывать **понятную ошибку** клиенту, если данные невалидны;\n* **документировать** параметр в *операции пути* схемы OpenAPI (он будет показан в **UI автоматической документации**).\n\n## Альтернатива (устаревшее): `Query` как значение по умолчанию { #alternative-old-query-as-the-default-value }\n\nВ предыдущих версиях FastAPI (до <dfn title=\"до 2023-03\">0.95.0</dfn>) требовалось использовать `Query` как значение по умолчанию для параметра вместо помещения его в `Annotated`. Скорее всего вы ещё встретите такой код, поэтому поясню.\n\n/// tip | Подсказка\n\nДля нового кода и везде, где это возможно, используйте `Annotated`, как описано выше. У этого есть несколько преимуществ (см. ниже) и нет недостатков. 🍰\n\n///\n\nВот как можно использовать `Query()` как значение по умолчанию для параметра функции, установив `max_length` равным 50:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\nТак как в этом случае (без `Annotated`) мы заменяем в функции значение по умолчанию `None` на `Query()`, теперь нужно указать значение по умолчанию через параметр `Query(default=None)`, это служит той же цели — задать значение по умолчанию (по крайней мере для FastAPI).\n\nИтак:\n\n```Python\nq: str | None = Query(default=None)\n```\n\n...делает параметр необязательным со значением по умолчанию `None`, так же как:\n\n```Python\nq: str | None = None\n```\n\nНо вариант с `Query` явно объявляет его как query-параметр.\n\nЗатем мы можем передать и другие параметры в `Query`. В данном случае — параметр `max_length`, применимый к строкам:\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\nЭто провалидирует данные, покажет понятную ошибку, если данные невалидны, и задокументирует параметр в *операции пути* схемы OpenAPI.\n\n### `Query` как значение по умолчанию или внутри `Annotated` { #query-as-the-default-value-or-in-annotated }\n\nПомните, что при использовании `Query` внутри `Annotated` нельзя указывать параметр `default` у `Query`.\n\nВместо этого используйте обычное значение по умолчанию параметра функции. Иначе это будет неоднозначно.\n\nНапример, так делать нельзя:\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n...потому что непонятно, какое значение должно быть по умолчанию: `\"rick\"` или `\"morty\"`.\n\nСледовательно, используйте (предпочтительно):\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n...или в старой кодовой базе вы увидите:\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### Преимущества `Annotated` { #advantages-of-annotated }\n\n**Рекомендуется использовать `Annotated`** вместо задания значения по умолчанию в параметрах функции — так **лучше** по нескольким причинам. 🤓\n\n**Значение по умолчанию** у **параметра функции** — это **настоящее значение по умолчанию**, что более интуитивно для Python. 😌\n\nВы можете **вызвать** эту же функцию в **других местах** без FastAPI, и она будет **работать как ожидается**. Если есть **обязательный** параметр (без значения по умолчанию), ваш **редактор** сообщит об ошибке, **Python** тоже пожалуется, если вы запустите её без передачи обязательного параметра.\n\nЕсли вы не используете `Annotated`, а применяете **(устаревший) стиль со значением по умолчанию**, то при вызове этой функции без FastAPI в **других местах** вам нужно **помнить** о том, что надо передать аргументы, чтобы всё работало корректно, иначе значения будут не такими, как вы ожидаете (например, вместо `str` будет `QueryInfo` или что-то подобное). И ни редактор, ни Python не будут ругаться при самом вызове функции — ошибка проявится лишь при операциях внутри.\n\nТак как `Annotated` может содержать больше одной аннотации метаданных, теперь вы можете использовать ту же функцию и с другими инструментами, например с [Typer](https://typer.tiangolo.com/). 🚀\n\n## Больше валидаций { #add-more-validations }\n\nМожно также добавить параметр `min_length`:\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## Регулярные выражения { #add-regular-expressions }\n\nВы можете определить <dfn title=\"Регулярное выражение (regex, regexp) — это последовательность символов, задающая шаблон поиска для строк.\">регулярное выражение</dfn> `pattern`, которому должен соответствовать параметр:\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\nДанный шаблон регулярного выражения проверяет, что полученное значение параметра:\n\n* `^`: начинается с следующих символов, до них нет символов.\n* `fixedquery`: имеет точное значение `fixedquery`.\n* `$`: заканчивается здесь, после `fixedquery` нет никаких символов.\n\nЕсли вы теряетесь во всех этих идеях про **«регулярные выражения»**, не переживайте. Это сложная тема для многих. Многое можно сделать и без них.\n\nТеперь вы знаете, что когда они понадобятся, вы сможете использовать их в **FastAPI**.\n\n## Значения по умолчанию { #default-values }\n\nКонечно, можно использовать и другие значения по умолчанию, не только `None`.\n\nДопустим, вы хотите объявить, что query-параметр `q` должен иметь `min_length` равный `3` и значение по умолчанию `\"fixedquery\"`:\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | Примечание\n\nНаличие значения по умолчанию любого типа, включая `None`, делает параметр необязательным.\n\n///\n\n## Обязательные параметры { #required-parameters }\n\nКогда не требуется объявлять дополнительные проверки или метаданные, можно сделать query-параметр `q` обязательным, просто не указывая значение по умолчанию, например:\n\n```Python\nq: str\n```\n\nвместо:\n\n```Python\nq: str | None = None\n```\n\nНо сейчас мы объявляем его через `Query`, например так:\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\nПоэтому, когда вам нужно объявить значение как обязательное при использовании `Query`, просто не указывайте значение по умолчанию:\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### Обязательный, но может быть `None` { #required-can-be-none }\n\nМожно объявить, что параметр может принимать `None`, но при этом остаётся обязательным. Это заставит клиентов отправлять значение, даже если это значение — `None`.\n\nДля этого объявите, что `None` — валидный тип, но просто не задавайте значение по умолчанию:\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## Query-параметр - список / несколько значений { #query-parameter-list-multiple-values }\n\nКогда вы явно объявляете query-параметр через `Query`, можно также указать, что он принимает список значений, иначе говоря — несколько значений.\n\nНапример, чтобы объявить query-параметр `q`, который может встречаться в URL несколько раз, можно написать:\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\nТогда при таком URL:\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\nвы получите множественные значения *query-параметров* `q` (`foo` и `bar`) в виде Python-`list` внутри вашей *функции-обработчика пути*, в *параметре функции* `q`.\n\nТаким образом, ответ на этот URL будет:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | Совет\n\nЧтобы объявить query-параметр типа `list`, как в примере выше, нужно явно использовать `Query`, иначе он будет интерпретирован как тело запроса.\n\n///\n\nИнтерактивная документация API обновится соответствующим образом и позволит передавать несколько значений:\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### Query-параметр - список / несколько значений со значением по умолчанию { #query-parameter-list-multiple-values-with-defaults }\n\nМожно также определить значение по умолчанию как `list`, если ничего не передано:\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\nЕсли вы перейдёте по адресу:\n\n```\nhttp://localhost:8000/items/\n```\n\nзначение по умолчанию для `q` будет: `[\"foo\", \"bar\"]`, и ответом будет:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### Просто `list` { #using-just-list }\n\nМожно использовать `list` напрямую вместо `list[str]`:\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | Примечание\n\nИмейте в виду, что в этом случае FastAPI не будет проверять содержимое списка.\n\nНапример, `list[int]` проверит (и задокументирует), что элементы списка — целые числа. А просто `list` — нет.\n\n///\n\n## Больше метаданных { #declare-more-metadata }\n\nМожно добавить больше информации о параметре.\n\nЭта информация будет включена в сгенерированную OpenAPI-схему и использована интерфейсами документации и внешними инструментами.\n\n/// note | Примечание\n\nПомните, что разные инструменты могут иметь разный уровень поддержки OpenAPI.\n\nНекоторые из них пока могут не показывать всю дополнительную информацию, хотя в большинстве случаев недостающая возможность уже запланирована к разработке.\n\n///\n\nМожно задать `title`:\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\nИ `description`:\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## Псевдонимы параметров { #alias-parameters }\n\nПредставьте, что вы хотите, чтобы параметр назывался `item-query`.\n\nНапример:\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\nНо `item-query` — недопустимое имя переменной в Python.\n\nБлижайший вариант — `item_query`.\n\nНо вам всё равно нужно именно `item-query`...\n\nТогда можно объявить `alias`, и этот псевдоним будет использован для поиска значения параметра:\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## Маркировка параметров как устаревших { #deprecating-parameters }\n\nПредположим, этот параметр вам больше не нравится.\n\nЕго нужно оставить на какое‑то время, так как клиенты его используют, но вы хотите, чтобы в документации он явно отображался как <dfn title=\"устаревший, не рекомендуется использовать\">устаревший</dfn>.\n\nТогда передайте параметр `deprecated=True` в `Query`:\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\nВ документации это будет показано так:\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## Исключить параметры из OpenAPI { #exclude-parameters-from-openapi }\n\nЧтобы исключить query-параметр из генерируемой OpenAPI-схемы (и, следовательно, из систем автоматической документации), укажите у `Query` параметр `include_in_schema=False`:\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## Кастомная валидация { #custom-validation }\n\nБывают случаи, когда нужна **кастомная валидация**, которую нельзя выразить параметрами выше.\n\nВ таких случаях можно использовать **кастомную функцию-валидатор**, которая применяется после обычной валидации (например, после проверки, что значение — это `str`).\n\nЭтого можно добиться, используя [`AfterValidator` Pydantic](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) внутри `Annotated`.\n\n/// tip | Совет\n\nВ Pydantic также есть [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) и другие. 🤓\n\n///\n\nНапример, эта кастомная проверка убеждается, что ID элемента начинается с `isbn-` для номера книги <abbr title=\"International Standard Book Number - Международный стандартный книжный номер\">ISBN</abbr> или с `imdb-` для ID URL фильма на <abbr title=\"Internet Movie Database - Интернетная база данных фильмов: веб‑сайт с информацией о фильмах\">IMDB</abbr>:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info | Дополнительная информация\n\nЭто доступно в Pydantic версии 2 и выше. 😎\n\n///\n\n/// tip | Совет\n\nЕсли вам нужна валидация, требующая общения с каким‑либо **внешним компонентом** — базой данных или другим API — вместо этого используйте **Зависимости FastAPI**, вы познакомитесь с ними позже.\n\nЭти кастомные валидаторы предназначены для проверок, которые можно выполнить, имея **только** те же **данные**, что пришли в запросе.\n\n///\n\n### Понимание этого кода { #understand-that-code }\n\nВажный момент — это использовать **`AfterValidator` с функцией внутри `Annotated`**. Смело пропускайте эту часть. 🤸\n\n---\n\nНо если вам любопытен именно этот пример и всё ещё интересно, вот немного подробностей.\n\n#### Строка и `value.startswith()` { #string-with-value-startswith }\n\nЗаметили? Метод строки `value.startswith()` может принимать кортеж — тогда будет проверено каждое значение из кортежа:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### Случайный элемент { #a-random-item }\n\nС помощью `data.items()` мы получаем <dfn title=\"Объект, по которому можно итерироваться циклом for, например список, множество и т.п.\">итерируемый объект</dfn> с кортежами, содержащими ключ и значение для каждого элемента словаря.\n\nМы превращаем этот итерируемый объект в обычный `list` через `list(data.items())`.\n\nЗатем с `random.choice()` можно получить **случайное значение** из списка — то есть кортеж вида `(id, name)`. Это будет что‑то вроде `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")`.\n\nПосле этого мы **присваиваем эти два значения** кортежа переменным `id` и `name`.\n\nТак что, если пользователь не передал ID элемента, он всё равно получит случайную рекомендацию.\n\n...и всё это в **одной простой строке**. 🤯 Разве не прекрасен Python? 🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## Резюме { #recap }\n\nВы можете объявлять дополнительные проверки и метаданные для параметров.\n\nОбщие метаданные и настройки:\n\n* `alias`\n* `title`\n* `description`\n* `deprecated`\n\nПроверки, специфичные для строк:\n\n* `min_length`\n* `max_length`\n* `pattern`\n\nКастомные проверки с использованием `AfterValidator`.\n\nВ этих примерах вы видели, как объявлять проверки для значений типа `str`.\n\nСмотрите следующие главы, чтобы узнать, как объявлять проверки для других типов, например чисел.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/query-params.md",
    "content": "# Query-параметры { #query-parameters }\n\nКогда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как \"query\"-параметры.\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\nQuery-параметры представляют из себя набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`.\n\nНапример, в этом URL-адресе:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n...параметры запроса такие:\n\n* `skip`: со значением `0`\n* `limit`: со значением `10`\n\nБудучи частью URL-адреса, они \"по умолчанию\" являются строками.\n\nНо когда вы объявляете их с использованием типов Python (в примере выше, как `int`), они конвертируются в указанный тип данных и проходят проверку на соответствие ему.\n\nВсе те же правила, которые применяются к path-параметрам, также применяются и query-параметрам:\n\n* Поддержка от редактора кода (очевидно)\n* <dfn title=\"преобразование строки, полученной из HTTP-запроса в данные Python\">\"Парсинг\"</dfn> данных\n* Проверка на соответствие данных (Валидация)\n* Автоматическая документация\n\n## Значения по умолчанию { #defaults }\n\nПоскольку query-параметры не являются фиксированной частью пути, они могут быть не обязательными и иметь значения по умолчанию.\n\nВ примере выше значения по умолчанию равны `skip=0` и `limit=10`.\n\nТаким образом, результат перехода по URL-адресу:\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\nбудет таким же, как если перейти используя параметры по умолчанию:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\nНо если вы введёте, например:\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\nЗначения параметров в вашей функции будут:\n\n* `skip=20`: потому что вы установили это в URL-адресе\n* `limit=10`: т.к это было значение по умолчанию\n\n## Необязательные параметры { #optional-parameters }\n\nАналогично, вы можете объявлять необязательные query-параметры, установив их значение по умолчанию, равное `None`:\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\nВ этом случае, параметр  `q` будет не обязательным и будет иметь значение `None` по умолчанию.\n\n/// check | Важно\n\nТакже обратите внимание, что **FastAPI** достаточно умён чтобы заметить, что параметр `item_id` является path-параметром, а `q` нет, поэтому, это параметр запроса.\n\n///\n\n## Преобразование типа параметра запроса { #query-parameter-type-conversion }\n\nВы также можете объявлять параметры с типом `bool`, которые будут преобразованы соответственно:\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\nВ этом случае, если вы сделаете запрос:\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\nили\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\nили\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\nили\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\nили\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\nили в любом другом варианте написания (в верхнем регистре, с заглавной буквой, и т.п), внутри вашей функции параметр `short` будет иметь значение `True` типа данных `bool` . В противном случае - `False`.\n\n## Смешивание query-параметров и path-параметров { #multiple-path-and-query-parameters }\n\nВы можете объявлять несколько query-параметров и path-параметров одновременно, **FastAPI** сам разберётся, что чем является.\n\nИ вы не обязаны объявлять их в каком-либо определенном порядке.\n\nОни будут обнаружены по именам:\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## Обязательные query-параметры { #required-query-parameters }\n\nКогда вы объявляете значение по умолчанию для параметра, который не является path-параметром (в этом разделе мы пока что рассмотрели только query-параметры), то он не является обязательным.\n\nЕсли вы не хотите задавать конкретное значение, но хотите сделать параметр необязательным, вы можете установить значение по умолчанию равным `None`.\n\nНо если вы хотите сделать query-параметр обязательным, вы можете просто не указывать значение по умолчанию:\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\nЗдесь параметр запроса `needy` является обязательным параметром с типом данных  `str`.\n\nЕсли вы откроете в браузере URL-адрес, например:\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n...без добавления обязательного параметра `needy`, вы увидите подобного рода ошибку:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\nПоскольку `needy` является обязательным параметром, вам необходимо указать его в URL-адресе:\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n...это будет работать:\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\nКонечно, вы можете определить некоторые параметры как обязательные, некоторые — со значением по умолчанию, а некоторые — полностью необязательные:\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\nВ этом примере, у нас есть 3 параметра запроса:\n\n* `needy`, обязательный `str`.\n* `skip`, типа `int` и со значением по умолчанию `0`.\n* `limit`, необязательный `int`.\n\n/// tip | Подсказка\n\nВы можете использовать класс `Enum` также, как ранее применяли его с [Path-параметрами](path-params.md#predefined-values).\n\n///\n"
  },
  {
    "path": "docs/ru/docs/tutorial/request-files.md",
    "content": "# Загрузка файлов { #request-files }\n\nИспользуя класс `File`, мы можем позволить клиентам загружать файлы.\n\n/// info | Дополнительная информация\n\nЧтобы получать загруженные файлы, сначала установите [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nУбедитесь, что вы создали [виртуальное окружение](../virtual-environments.md), активировали его, а затем установили пакет, например:\n\n```console\n$ pip install python-multipart\n```\n\nЭто связано с тем, что загружаемые файлы передаются как \"данные формы\".\n\n///\n\n## Импорт `File` { #import-file }\n\nИмпортируйте `File` и `UploadFile` из модуля `fastapi`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## Определите параметры `File` { #define-file-parameters }\n\nСоздайте параметры `File` так же, как вы это делаете для `Body` или `Form`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info | Дополнительная информация\n\n`File` - это класс, который наследуется непосредственно от `Form`.\n\nНо помните, что когда вы импортируете `Query`, `Path`, `File` и другие из `fastapi`, на самом деле это функции, которые возвращают специальные классы.\n\n///\n\n/// tip | Подсказка\n\nДля объявления тела файла необходимо использовать `File`, поскольку в противном случае параметры будут интерпретироваться как параметры запроса или параметры тела (JSON).\n\n///\n\nФайлы будут загружены как данные формы.\n\nЕсли вы объявите тип параметра у *функции операции пути* как `bytes`, то **FastAPI** прочитает файл за вас, и вы получите его содержимое в виде `bytes`.\n\nСледует иметь в виду, что все содержимое будет храниться в памяти. Это хорошо подходит для небольших файлов.\n\nОднако возможны случаи, когда использование `UploadFile` может оказаться полезным.\n\n## Параметры файла с `UploadFile` { #file-parameters-with-uploadfile }\n\nОпределите параметр файла с типом `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\nИспользование `UploadFile` имеет ряд преимуществ перед `bytes`:\n\n* Использовать `File()` в значении параметра по умолчанию не обязательно.\n* При этом используется \"буферный\" файл:\n    * Файл, хранящийся в памяти до максимального предела размера, после преодоления которого он будет храниться на диске.\n* Это означает, что он будет хорошо работать с большими файлами, такими как изображения, видео, большие бинарные файлы и т.д., не потребляя при этом всю память.\n* Из загруженного файла можно получить метаданные.\n* Он реализует [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) `async` интерфейс.\n* Он предоставляет реальный объект Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile), который вы можете передать непосредственно другим библиотекам, которые ожидают файл в качестве объекта.\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` имеет следующие атрибуты:\n\n* `filename`: Строка `str` с исходным именем файла, который был загружен (например, `myimage.jpg`).\n* `content_type`: Строка `str` с типом содержимого (MIME type / media type) (например, `image/jpeg`).\n* `file`: [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (a [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) объект). Это фактический файл Python, который можно передавать непосредственно другим функциям или библиотекам, ожидающим файл в качестве объекта.\n\n`UploadFile` имеет следующие методы `async`. Все они вызывают соответствующие файловые методы (используя внутренний `SpooledTemporaryFile`).\n\n* `write(data)`: Записать данные `data` (`str` или `bytes`) в файл.\n* `read(size)`: Прочитать количество `size` (`int`) байт/символов из файла.\n* `seek(offset)`: Перейти к байту на позиции `offset` (`int`) в файле.\n    * Например, `await myfile.seek(0)` перейдет к началу файла.\n    * Это особенно удобно, если вы один раз выполнили команду `await myfile.read()`, а затем вам нужно прочитать содержимое файла еще раз.\n* `close()`: Закрыть файл.\n\nПоскольку все эти методы являются `async` методами, вам следует использовать \"await\" вместе с ними.\n\nНапример, внутри `async` *функции операции пути* можно получить содержимое с помощью:\n\n```Python\ncontents = await myfile.read()\n```\n\nЕсли вы находитесь внутри обычной `def` *функции операции пути*, можно получить прямой доступ к файлу `UploadFile.file`, например:\n\n```Python\ncontents = myfile.file.read()\n```\n\n\n/// note | Технические детали `async`\n\nПри использовании методов `async` **FastAPI** запускает файловые методы в пуле потоков и ожидает их.\n\n///\n\n/// note | Технические детали Starlette\n\n**FastAPI** наследует `UploadFile` непосредственно из **Starlette**, но добавляет некоторые детали для совместимости с **Pydantic** и другими частями FastAPI.\n\n///\n\n## Что такое «данные формы» { #what-is-form-data }\n\nСпособ, которым HTML-формы (`<form></form>`) отправляют данные на сервер, обычно использует \"специальную\" кодировку для этих данных, отличную от JSON.\n\n**FastAPI** позаботится о том, чтобы считать эти данные из нужного места, а не из JSON.\n\n/// note | Технические детали\n\nДанные из форм обычно кодируются с использованием \"media type\" `application/x-www-form-urlencoded` когда он не включает файлы.\n\nНо когда форма включает файлы, она кодируется как `multipart/form-data`. Если вы используете `File`, **FastAPI** будет знать, что ему нужно получить файлы из нужной части тела.\n\nЕсли вы хотите узнать больше об этих кодировках и полях форм, перейдите по ссылке [<abbr title=\"Mozilla Developer Network - Сеть разработчиков Mozilla\">MDN</abbr> web docs for `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Внимание\n\nВ операции *функции операции пути* можно объявить несколько параметров `File` и `Form`, но нельзя также объявлять поля `Body`, которые предполагается получить в виде JSON, поскольку тело запроса будет закодировано с помощью `multipart/form-data`, а не `application/json`.\n\nЭто не является ограничением **FastAPI**, это часть протокола HTTP.\n\n///\n\n## Необязательная загрузка файлов { #optional-file-upload }\n\nВы можете сделать загрузку файла необязательной, используя стандартные аннотации типов и установив значение по умолчанию `None`:\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## `UploadFile` с дополнительными метаданными { #uploadfile-with-additional-metadata }\n\nВы также можете использовать `File()` вместе с `UploadFile`, например, для установки дополнительных метаданных:\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## Загрузка нескольких файлов { #multiple-file-uploads }\n\nМожно одновременно загружать несколько файлов.\n\nОни будут связаны с одним и тем же \"полем формы\", отправляемым с помощью данных формы.\n\nДля этого необходимо объявить список `bytes` или `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\nВы получите, как и было объявлено, список `list` из `bytes` или `UploadFile`.\n\n/// note | Технические детали\n\nМожно также использовать `from starlette.responses import HTMLResponse`.\n\n**FastAPI** предоставляет тот же `starlette.responses`, что и `fastapi.responses`, просто для удобства разработчика. Однако большинство доступных ответов поступает непосредственно из Starlette.\n\n///\n\n### Загрузка нескольких файлов с дополнительными метаданными { #multiple-file-uploads-with-additional-metadata }\n\nТак же, как и раньше, вы можете использовать `File()` для задания дополнительных параметров, даже для `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## Резюме { #recap }\n\nИспользуйте `File`, `bytes` и `UploadFile` для работы с файлами, которые будут загружаться и передаваться в виде данных формы.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/request-form-models.md",
    "content": "# Модели форм { #form-models }\n\nВы можете использовать **Pydantic-модели** для объявления **полей формы** в FastAPI.\n\n/// info | Дополнительная информация\n\nЧтобы использовать формы, сначала установите [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nУбедитесь, что вы создали и активировали [виртуальное окружение](../virtual-environments.md), а затем установите пакет, например:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note | Заметка\n\nЭтот функционал доступен начиная с версии FastAPI `0.113.0`. 🤓\n\n///\n\n## Pydantic-модели для форм { #pydantic-models-for-forms }\n\nВам просто нужно объявить **Pydantic-модель** с полями, которые вы хотите получить как **поля формы**, а затем объявить параметр как `Form`:\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI** **извлечёт** данные для **каждого поля** из **данных формы** в запросе и выдаст вам объявленную Pydantic-модель.\n\n## Проверьте документацию { #check-the-docs }\n\nВы можете проверить это в интерфейсе документации по адресу `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## Запрет дополнительных полей формы { #forbid-extra-form-fields }\n\nВ некоторых случаях (не особо часто встречающихся) вам может понадобиться **ограничить** поля формы только теми, которые объявлены в Pydantic-модели. И **запретить** любые **дополнительные** поля.\n\n/// note | Заметка\n\nЭтот функционал доступен начиная с версии FastAPI `0.114.0`. 🤓\n\n///\n\nВы можете сконфигурировать Pydantic-модель так, чтобы запретить (`forbid`) все дополнительные (`extra`) поля:\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\nЕсли клиент попробует отправить дополнительные данные, то в ответ он получит **ошибку**.\n\nНапример, если клиент попытается отправить поля формы:\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\nТо в ответ он получит **ошибку**, сообщающую ему, что поле `extra` не разрешено:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## Итоги { #summary }\n\nВы можете использовать Pydantic-модели для объявления полей форм в FastAPI. 😎\n"
  },
  {
    "path": "docs/ru/docs/tutorial/request-forms-and-files.md",
    "content": "# Файлы и формы в запросе { #request-forms-and-files }\n\nВы можете определять файлы и поля формы одновременно, используя `File` и `Form`.\n\n/// info | Информация\n\nЧтобы получать загруженные файлы и/или данные форм, сначала установите [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nУбедитесь, что вы создали [виртуальное окружение](../virtual-environments.md), активировали его, а затем установили пакет, например:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Импортируйте `File` и `Form` { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## Определите параметры `File` и `Form` { #define-file-and-form-parameters }\n\nСоздайте параметры файла и формы таким же образом, как для `Body` или `Query`:\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\nФайлы и поля формы будут загружены в виде данных формы, и вы получите файлы и поля формы.\n\nВы можете объявить некоторые файлы как `bytes`, а некоторые — как `UploadFile`.\n\n/// warning | Внимание\n\nВы можете объявить несколько параметров `File` и `Form` в операции пути, но вы не можете также объявить поля `Body`, которые вы ожидаете получить в виде JSON, так как запрос будет иметь тело, закодированное с помощью `multipart/form-data` вместо `application/json`.\n\nЭто не ограничение **FastAPI**, это часть протокола HTTP.\n\n///\n\n## Резюме { #recap }\n\nИспользуйте `File` и `Form` вместе, когда необходимо получить данные и файлы в одном запросе.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/request-forms.md",
    "content": "# Данные формы { #form-data }\n\nКогда вам нужно получить поля формы вместо JSON, вы можете использовать `Form`.\n\n/// info | Дополнительная информация\n\nЧтобы использовать формы, сначала установите [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nУбедитесь, что вы создали [виртуальное окружение](../virtual-environments.md), активировали его, а затем установили пакет, например:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Импорт `Form` { #import-form }\n\nИмпортируйте `Form` из `fastapi`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## Определение параметров `Form` { #define-form-parameters }\n\nСоздайте параметры формы так же, как это делается для `Body` или `Query`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\nНапример, в одном из способов использования спецификации OAuth2 (называемом «password flow» - аутентификация по паролю) требуется отправить `username` и `password` в виде полей формы.\n\n<dfn title=\"спецификация\">спецификация</dfn> требует, чтобы поля были строго названы `username` и `password` и отправлялись как поля формы, а не JSON.\n\nС помощью `Form` вы можете объявить те же настройки, что и с `Body` (и `Query`, `Path`, `Cookie`), включая валидацию, примеры, псевдоним (например, `user-name` вместо `username`) и т.д.\n\n/// info | Дополнительная информация\n\n`Form` — это класс, который наследуется непосредственно от `Body`.\n\n///\n\n/// tip | Подсказка\n\nЧтобы объявлять данные формы, вам нужно явно использовать `Form`, иначе параметры будут интерпретированы как параметры запроса или параметры тела (JSON).\n\n///\n\n## О «полях формы» { #about-form-fields }\n\nОбычно способ, которым HTML-формы (`<form></form>`) отправляют данные на сервер, использует «специальное» кодирование для этих данных, отличное от JSON.\n\n**FastAPI** гарантирует, что эти данные будут прочитаны из нужного места, а не из JSON.\n\n/// note | Технические детали\n\nДанные из форм обычно кодируются с использованием «типа содержимого» `application/x-www-form-urlencoded`.\n\nНо когда форма содержит файлы, она кодируется как `multipart/form-data`. О работе с файлами вы прочтёте в следующей главе.\n\nЕсли вы хотите узнать больше про эти кодировки и поля формы, обратитесь к [<abbr title=\"Mozilla Developer Network - Сеть разработчиков Mozilla\">MDN</abbr> веб-документации для `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Предупреждение\n\nВы можете объявлять несколько параметров `Form` в *операции пути*, но вы не можете одновременно объявлять поля `Body`, которые вы ожидаете получить в виде JSON, так как запрос будет иметь тело, закодированное с использованием `application/x-www-form-urlencoded`, а не `application/json`.\n\nЭто не ограничение **FastAPI**, это часть протокола HTTP.\n\n///\n\n## Резюме { #recap }\n\nИспользуйте `Form` для объявления входных параметров данных формы.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/response-model.md",
    "content": "# Модель ответа — Возвращаемый тип { #response-model-return-type }\n\nВы можете объявить тип, используемый для ответа, указав аннотацию **возвращаемого значения** для *функции-обработчика пути*.\n\nВы можете использовать **аннотации типов** так же, как и для входных данных в **параметрах** функции: Pydantic-модели, списки, словари, скалярные значения (целые числа, булевы и т.д.).\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPI будет использовать этот возвращаемый тип, чтобы:\n\n* **Валидировать** возвращаемые данные.\n    * Если данные невалидны (например, отсутствует поле), это означает, что код *вашего* приложения работает некорректно и возвращает не то, что должен. В таком случае будет возвращена ошибка сервера вместо неправильных данных. Так вы и ваши клиенты можете быть уверены, что получите ожидаемые данные и ожидаемую структуру данных.\n* Добавить **JSON Schema** для ответа в OpenAPI *операции пути*.\n    * Это будет использовано **автоматической документацией**.\n    * Это также будет использовано инструментами автоматической генерации клиентского кода.\n* **Сериализовать** возвращаемые данные в JSON с помощью Pydantic, который написан на **Rust**, поэтому это будет **намного быстрее**.\n\nНо самое главное:\n\n* Выходные данные будут **ограничены и отфильтрованы** в соответствии с тем, что определено в возвращаемом типе.\n    * Это особенно важно для **безопасности**, ниже мы рассмотрим это подробнее.\n\n## Параметр `response_model` { #response-model-parameter }\n\nБывают случаи, когда вам нужно или хочется возвращать данные, которые не в точности соответствуют объявленному типу.\n\nНапример, вы можете хотеть **возвращать словарь** или объект из базы данных, но **объявить его как Pydantic-модель**. Тогда Pydantic-модель выполнит документирование данных, валидацию и т.п. для объекта, который вы вернули (например, словаря или объекта из базы данных).\n\nЕсли вы добавите аннотацию возвращаемого типа, инструменты и редакторы кода начнут жаловаться (и будут правы), что функция возвращает тип (например, dict), отличный от объявленного (например, Pydantic-модель).\n\nВ таких случаях вместо аннотации возвращаемого типа можно использовать параметр `response_model` у *декоратора операции пути*.\n\nПараметр `response_model` можно указать у любой *операции пути*:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* и т.д.\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | Примечание\n\nОбратите внимание, что `response_model` — это параметр метода «декоратора» (`get`, `post` и т.д.), а не вашей *функции-обработчика пути*, в которой указываются параметры и тело запроса.\n\n///\n\n`response_model` принимает тот же тип, что вы бы объявили для поля Pydantic-модели, то есть это может быть одна Pydantic-модель, а может быть, например, `list` Pydantic-моделей, как `List[Item]`.\n\nFastAPI будет использовать этот `response_model` для документирования, валидации данных и т.п., а также для **конвертации и фильтрации выходных данных** к объявленному типу.\n\n/// tip | Совет\n\nЕсли у вас в редакторе кода, mypy и т.п. включены строгие проверки типов, вы можете объявить возвращаемый тип функции как `Any`.\n\nТак вы сообщите редактору, что намеренно возвращаете что угодно. Но FastAPI всё равно выполнит документирование, валидацию, фильтрацию данных и т.д. с помощью `response_model`.\n\n///\n\n### Приоритет `response_model` { #response-model-priority }\n\nЕсли вы объявите и возвращаемый тип, и `response_model`, приоритет будет у `response_model`, именно его использует FastAPI.\n\nТак вы можете добавить корректные аннотации типов к своим функциям, даже если фактически возвращаете тип, отличный от модели ответа, чтобы ими пользовались редактор кода и инструменты вроде mypy. И при этом FastAPI продолжит выполнять валидацию данных, документацию и т.д. с использованием `response_model`.\n\nВы также можете указать `response_model=None`, чтобы отключить создание модели ответа для данной *операции пути*. Это может понадобиться, если вы добавляете аннотации типов для вещей, не являющихся валидными полями Pydantic. Пример вы увидите ниже.\n\n## Вернуть те же входные данные { #return-the-same-input-data }\n\nЗдесь мы объявляем модель `UserIn`, она будет содержать пароль в открытом виде:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | Информация\n\nЧтобы использовать `EmailStr`, сначала установите [`email-validator`](https://github.com/JoshData/python-email-validator).\n\nУбедитесь, что вы создали [виртуальное окружение](../virtual-environments.md), активировали его, а затем установите пакет, например:\n\n```console\n$ pip install email-validator\n```\n\nили так:\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\nИ мы используем эту модель для объявления входных данных, и ту же модель — для объявления выходных данных:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\nТеперь, когда браузер создаёт пользователя с паролем, API вернёт тот же пароль в ответе.\n\nВ этом случае это может быть не проблемой, так как пароль отправляет тот же пользователь.\n\nНо если мы используем ту же модель в другой *операции пути*, мы можем начать отправлять пароли пользователей каждому клиенту.\n\n/// danger | Осторожно\n\nНикогда не храните пароль пользователя в открытом виде и не отправляйте его в ответе подобным образом, если только вы не понимаете всех рисков и точно знаете, что делаете.\n\n///\n\n## Добавить выходную модель { #add-an-output-model }\n\nВместо этого мы можем создать входную модель с паролем в открытом виде и выходную модель без него:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\nЗдесь, хотя *функция-обработчик пути* возвращает тот же входной объект пользователя, содержащий пароль:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n...мы объявили `response_model` как модель `UserOut`, в которой нет пароля:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\nТаким образом, **FastAPI** позаботится о том, чтобы отфильтровать все данные, не объявленные в выходной модели (используя Pydantic).\n\n### `response_model` или возвращаемый тип { #response-model-or-return-type }\n\nВ этом случае, поскольку две модели различаются, если бы мы аннотировали возвращаемый тип функции как `UserOut`, редактор кода и инструменты пожаловались бы, что мы возвращаем неверный тип, так как это разные классы.\n\nПоэтому в этом примере мы должны объявить тип ответа в параметре `response_model`.\n\n...но читайте дальше, чтобы узнать, как это обойти.\n\n## Возвращаемый тип и фильтрация данных { #return-type-and-data-filtering }\n\nПродолжим предыдущий пример. Мы хотели **аннотировать функцию одним типом**, но при этом иметь возможность вернуть из функции что-то, что фактически включает **больше данных**.\n\nМы хотим, чтобы FastAPI продолжал **фильтровать** данные с помощью модели ответа. Так что, даже если функция возвращает больше данных, в ответ будут включены только поля, объявленные в модели ответа.\n\nВ предыдущем примере, поскольку классы были разными, нам пришлось использовать параметр `response_model`. Но это также означает, что мы теряем поддержку от редактора кода и инструментов, проверяющих возвращаемый тип функции.\n\nОднако в большинстве таких случаев нам нужно лишь **отфильтровать/убрать** некоторые данные, как в этом примере.\n\nИ в этих случаях мы можем использовать классы и наследование, чтобы воспользоваться **аннотациями типов** функций для лучшей поддержки в редакторе кода и инструментах и при этом получить **фильтрацию данных** от FastAPI.\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\nТак мы получаем поддержку инструментов — редакторов кода и mypy, так как этот код корректен с точки зрения типов — и одновременно получаем фильтрацию данных от FastAPI.\n\nКак это работает? Давайте разберёмся. 🤓\n\n### Аннотации типов и инструменты { #type-annotations-and-tooling }\n\nСначала посмотрим, как это увидят редактор кода, mypy и другие инструменты.\n\n`BaseUser` содержит базовые поля. Затем `UserIn` наследуется от `BaseUser` и добавляет поле `password`, то есть он будет включать все поля обеих моделей.\n\nМы аннотируем возвращаемый тип функции как `BaseUser`, но фактически возвращаем экземпляр `UserIn`.\n\nРедактор кода, mypy и другие инструменты не будут возражать, потому что с точки зрения типов `UserIn` — подкласс `BaseUser`, что означает, что это *валидный* тип везде, где ожидается что-то, являющееся `BaseUser`.\n\n### Фильтрация данных FastAPI { #fastapi-data-filtering }\n\nТеперь для FastAPI: он увидит возвращаемый тип и убедится, что то, что вы возвращаете, включает **только** поля, объявленные в этом типе.\n\nFastAPI делает несколько вещей внутри вместе с Pydantic, чтобы гарантировать, что те же правила наследования классов не используются для фильтрации возвращаемых данных, иначе вы могли бы в итоге вернуть намного больше данных, чем ожидали.\n\nТаким образом вы получаете лучшее из обоих миров: аннотации типов с **поддержкой инструментов** и **фильтрацию данных**.\n\n## Посмотреть в документации { #see-it-in-the-docs }\n\nВ автоматической документации вы увидите, что у входной и выходной моделей есть свои JSON Schema:\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\nИ обе модели будут использоваться в интерактивной документации API:\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## Другие аннотации возвращаемых типов { #other-return-type-annotations }\n\nБывают случаи, когда вы возвращаете что-то, что не является валидным полем Pydantic, и аннотируете это в функции только ради поддержки инструментов (редактор кода, mypy и т.д.).\n\n### Возврат Response напрямую { #return-a-response-directly }\n\nСамый распространённый случай — [возвращать Response напрямую, как описано далее в разделах документации для продвинутых](../advanced/response-directly.md).\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\nЭтот простой случай обрабатывается FastAPI автоматически, потому что аннотация возвращаемого типа — это класс (или подкласс) `Response`.\n\nИ инструменты тоже будут довольны, потому что и `RedirectResponse`, и `JSONResponse` являются подклассами `Response`, так что аннотация типа корректна.\n\n### Аннотировать подкласс Response { #annotate-a-response-subclass }\n\nВы также можете использовать подкласс `Response` в аннотации типа:\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\nЭто тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот простой случай.\n\n### Некорректные аннотации возвращаемых типов { #invalid-return-type-annotations }\n\nНо когда вы возвращаете произвольный объект, не являющийся валидным типом Pydantic (например, объект базы данных), и аннотируете его таким образом в функции, FastAPI попытается создать модель ответа Pydantic из этой аннотации типа и потерпит неудачу.\n\nТо же произойдёт, если у вас будет что-то вроде <dfn title=\"Объединение нескольких типов означает «любой из этих типов».\">объединение</dfn> разных типов, где один или несколько не являются валидными типами Pydantic, например, это приведёт к ошибке 💥:\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n...это не сработает, потому что аннотация типа не является типом Pydantic и это не единственный класс `Response` или его подкласс, а объединение (`union`) из `Response` и `dict`.\n\n### Отключить модель ответа { #disable-response-model }\n\nПродолжая пример выше, вы можете не хотеть использовать стандартные валидацию данных, документирование, фильтрацию и т.п., выполняемые FastAPI.\n\nНо при этом вы можете хотеть сохранить аннотацию возвращаемого типа в функции, чтобы пользоваться поддержкой инструментов вроде редакторов кода и инструментов проверки типов (например, mypy).\n\nВ этом случае вы можете отключить генерацию модели ответа, установив `response_model=None`:\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\nТак FastAPI пропустит генерацию модели ответа, и вы сможете использовать любые аннотации возвращаемых типов, которые вам нужны, без влияния на ваше приложение FastAPI. 🤓\n\n## Параметры кодирования модели ответа { #response-model-encoding-parameters }\n\nУ вашей модели ответа могут быть значения по умолчанию, например:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None` (или `str | None = None` в Python 3.10) имеет значение по умолчанию `None`.\n* `tax: float = 10.5` имеет значение по умолчанию `10.5`.\n* `tags: List[str] = []` имеет значение по умолчанию пустого списка: `[]`.\n\nно вы можете захотеть опустить их в результате, если они фактически не были сохранены.\n\nНапример, если у вас есть модели с множеством необязательных атрибутов в NoSQL-базе данных, но вы не хотите отправлять очень длинные JSON-ответы, заполненные значениями по умолчанию.\n\n### Используйте параметр `response_model_exclude_unset` { #use-the-response-model-exclude-unset-parameter }\n\nВы можете установить у *декоратора операции пути* параметр `response_model_exclude_unset=True`:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\nи эти значения по умолчанию не будут включены в ответ — только те значения, которые действительно были установлены.\n\nИтак, если вы отправите запрос к этой *операции пути* для элемента с ID `foo`, ответ (без значений по умолчанию) будет таким:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | Информация\n\nВы также можете использовать:\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\nкак описано в [документации Pydantic](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict) для `exclude_defaults` и `exclude_none`.\n\n///\n\n#### Данные со значениями для полей, имеющих значения по умолчанию { #data-with-values-for-fields-with-defaults }\n\nНо если в ваших данных есть значения для полей модели, для которых указаны значения по умолчанию, как у элемента с ID `bar`:\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\nони будут включены в ответ.\n\n#### Данные с такими же значениями, как значения по умолчанию { #data-with-the-same-values-as-the-defaults }\n\nЕсли данные имеют те же значения, что и значения по умолчанию, как у элемента с ID `baz`:\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nFastAPI достаточно умен (на самом деле, это Pydantic), чтобы понять, что хотя `description`, `tax` и `tags` совпадают со значениями по умолчанию, они были установлены явно (а не взяты из значений по умолчанию).\n\nПоэтому они тоже будут включены в JSON-ответ.\n\n/// tip | Совет\n\nОбратите внимание, что значения по умолчанию могут быть любыми, не только `None`.\n\nЭто может быть список (`[]`), число с плавающей точкой `10.5` и т.д.\n\n///\n\n### `response_model_include` и `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\nВы также можете использовать параметры *декоратора операции пути* `response_model_include` и `response_model_exclude`.\n\nОни принимают `set` из `str` с именами атрибутов, которые нужно включить (исключив остальные) или исключить (оставив остальные).\n\nЭто можно использовать как быстрый способ, если у вас только одна Pydantic-модель и вы хотите убрать часть данных из ответа.\n\n/// tip | Совет\n\nНо всё же рекомендуется использовать подходы выше — несколько классов — вместо этих параметров.\n\nПотому что JSON Schema, генерируемая в OpenAPI вашего приложения (и документации), всё равно будет соответствовать полной модели, даже если вы используете `response_model_include` или `response_model_exclude`, чтобы опустить некоторые атрибуты.\n\nТо же относится к `response_model_by_alias`, который работает аналогично.\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | Совет\n\nСинтаксис `{\"name\", \"description\"}` создаёт `set` с этими двумя значениями.\n\nЭто эквивалентно `set([\"name\", \"description\"])`.\n\n///\n\n#### Использование `list` вместо `set` { #using-lists-instead-of-sets }\n\nЕсли вы забыли использовать `set` и применили `list` или `tuple` вместо него, FastAPI всё равно преобразует это в `set`, и всё будет работать корректно:\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## Резюме { #recap }\n\nИспользуйте параметр `response_model` у *декоратора операции пути*, чтобы задавать модели ответа, и особенно — чтобы приватные данные отфильтровывались.\n\nИспользуйте `response_model_exclude_unset`, чтобы возвращать только те значения, которые были установлены явно.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/response-status-code.md",
    "content": "# Статус-код ответа { #response-status-code }\n\nПодобно тому, как вы можете задать модель/схему ответа, вы можете объявить HTTP статус-код, используемый для ответа, с помощью параметра `status_code` в любой из *операций пути*:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* и других.\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | Примечание\n\nОбратите внимание, что `status_code` — это параметр метода-декоратора (`get`, `post` и т.д.), а не вашей *функции-обработчика пути*, в отличие от всех остальных параметров и тела запроса.\n\n///\n\nПараметр `status_code` принимает число, обозначающее HTTP статус-код.\n\n/// info | Информация\n\nВ качестве значения параметра `status_code` также может использоваться `IntEnum`, например, из библиотеки [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus) в Python.\n\n///\n\nЭто позволит:\n\n* Возвращать указанный код статуса в ответе.\n* Документировать его как код статуса ответа в OpenAPI схеме (а значит, и в пользовательских интерфейсах):\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | Примечание\n\nНекоторые коды статуса ответа (см. следующий раздел) указывают на то, что ответ не имеет тела.\n\nFastAPI знает об этом и создаст документацию OpenAPI, в которой будет указано, что тело ответа отсутствует.\n\n///\n\n## Об HTTP статус-кодах { #about-http-status-codes }\n\n/// note | Примечание\n\nЕсли вы уже знаете, что представляют собой HTTP статус-коды, можете перейти к следующему разделу.\n\n///\n\nВ протоколе HTTP числовой код состояния из 3 цифр отправляется как часть ответа.\n\nУ кодов статуса есть названия, чтобы упростить их распознавание, но важны именно числовые значения.\n\nКратко:\n\n* `100 - 199` – статус-коды информационного типа. Они редко используются разработчиками напрямую. Ответы с этими кодами не могут иметь тела.\n* **`200 - 299`** – статус-коды, сообщающие об успешной обработке запроса. Они используются чаще всего.\n    * `200` – это код статуса ответа по умолчанию, который означает, что все прошло \"OK\".\n    * Другим примером может быть статус `201`, \"Created\". Он обычно используется после создания новой записи в базе данных.\n    * Особый случай – `204`, \"No Content\". Этот статус ответа используется, когда нет содержимого для возврата клиенту, и поэтому ответ не должен иметь тела.\n* **`300 - 399`** – статус-коды, сообщающие о перенаправлениях. Ответы с этими кодами статуса могут иметь или не иметь тело, за исключением ответов со статусом `304`, \"Not Modified\", у которых не должно быть тела.\n* **`400 - 499`** – статус-коды, сообщающие о клиентской ошибке. Это ещё одна наиболее часто используемая категория.\n    * Пример – код `404` для статуса \"Not Found\".\n    * Для общих ошибок со стороны клиента можно просто использовать код `400`.\n* `500 - 599` – статус-коды, сообщающие о серверной ошибке. Они почти никогда не используются разработчиками напрямую. Когда что-то идет не так в какой-то части кода вашего приложения или на сервере, он автоматически вернёт один из этих кодов статуса.\n\n/// tip | Подсказка\n\nЧтобы узнать больше о HTTP кодах статуса и о том, для чего каждый из них предназначен, ознакомьтесь с [<abbr title=\"Mozilla Developer Network - Сеть разработчиков Mozilla\">MDN</abbr> документацией об HTTP статус-кодах](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).\n\n///\n\n## Краткие обозначения для запоминания названий кодов { #shortcut-to-remember-the-names }\n\nРассмотрим предыдущий пример еще раз:\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201` – это код статуса \"Создано\".\n\nНо вам не обязательно запоминать, что означает каждый из этих кодов.\n\nДля удобства вы можете использовать переменные из `fastapi.status`.\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\nОни содержат те же числовые значения, но позволяют использовать автозавершение редактора кода для выбора кода статуса:\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette import status`.\n\n**FastAPI** позволяет использовать как `starlette.status`, так и `fastapi.status` исключительно для удобства разработчиков. Но поставляется fastapi.status непосредственно из Starlette.\n\n///\n\n## Изменение кода статуса по умолчанию { #changing-the-default }\n\nПозже, в [Руководстве для продвинутых пользователей](../advanced/response-change-status-code.md), вы узнаете, как возвращать HTTP статус-код, отличный от значения по умолчанию, которое вы объявляете здесь.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/schema-extra-example.md",
    "content": "# Объявление примеров данных запроса { #declare-request-example-data }\n\nВы можете объявлять примеры данных, которые ваше приложение может получать.\n\nВот несколько способов, как это сделать.\n\n## Дополнительные данные JSON Schema в моделях Pydantic { #extra-json-schema-data-in-pydantic-models }\n\nВы можете объявить `examples` для модели Pydantic, которые будут добавлены в сгенерированную JSON Schema.\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\nЭта дополнительная информация будет добавлена как есть в выходную **JSON Schema** этой модели и будет использоваться в документации API.\n\nВы можете использовать атрибут `model_config`, который принимает `dict`, как описано в [Документация Pydantic: Конфигурация](https://docs.pydantic.dev/latest/api/config/).\n\nВы можете задать `\"json_schema_extra\"` с `dict`, содержащим любые дополнительные данные, которые вы хотите видеть в сгенерированной JSON Schema, включая `examples`.\n\n/// tip | Подсказка\n\nВы можете использовать тот же приём, чтобы расширить JSON Schema и добавить свою собственную дополнительную информацию.\n\nНапример, вы можете использовать это, чтобы добавить метаданные для фронтенд‑пользовательского интерфейса и т.д.\n\n///\n\n/// info | Информация\n\nOpenAPI 3.1.0 (используется начиная с FastAPI 0.99.0) добавил поддержку `examples`, который является частью стандарта **JSON Schema**.\n\nДо этого поддерживалось только ключевое слово `example` с одним примером. Оно всё ещё поддерживается в OpenAPI 3.1.0, но помечено как устаревшее и не является частью стандарта JSON Schema. Поэтому рекомендуется мигрировать `example` на `examples`. 🤓\n\nПодробнее — в конце этой страницы.\n\n///\n\n## Дополнительные аргументы `Field` { #field-additional-arguments }\n\nПри использовании `Field()` с моделями Pydantic вы также можете объявлять дополнительные `examples`:\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## `examples` в JSON Schema — OpenAPI { #examples-in-json-schema-openapi }\n\nПри использовании любой из функций:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nвы также можете объявить набор `examples` с дополнительной информацией, которая будет добавлена в их **JSON Schema** внутри **OpenAPI**.\n\n### `Body` с `examples` { #body-with-examples }\n\nЗдесь мы передаём `examples`, содержащий один пример данных, ожидаемых в `Body()`:\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### Пример в UI документации { #example-in-the-docs-ui }\n\nС любым из перечисленных выше методов это будет выглядеть так в `/docs`:\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### `Body` с несколькими `examples` { #body-with-multiple-examples }\n\nКонечно, вы можете передать и несколько `examples`:\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\nКогда вы делаете это, примеры становятся частью внутренней **JSON Schema** для данных тела запроса.\n\nТем не менее, на <dfn title=\"2023-08-26\">момент написания этого</dfn> Swagger UI, инструмент, отвечающий за отображение UI документации, не поддерживает показ нескольких примеров для данных в **JSON Schema**. Но ниже есть обходной путь.\n\n### Специфические для OpenAPI `examples` { #openapi-specific-examples }\n\nЕщё до того как **JSON Schema** поддержала `examples`, в OpenAPI была поддержка другого поля, также называемого `examples`.\n\nЭти **специфические для OpenAPI** `examples` находятся в другой секции спецификации OpenAPI. Они находятся в **подробностях для каждой операции пути (обработчика пути)**, а не внутри каждого объекта Schema.\n\nИ Swagger UI уже какое‑то время поддерживает именно это поле `examples`. Поэтому вы можете использовать его, чтобы **отобразить** разные **примеры в UI документации**.\n\nСтруктура этого специфичного для OpenAPI поля `examples` — это `dict` с **несколькими примерами** (вместо `list`), каждый с дополнительной информацией, которая также будет добавлена в **OpenAPI**.\n\nЭто не помещается внутрь каждого объекта Schema в OpenAPI, это находится снаружи, непосредственно на уровне самой *операции пути*.\n\n### Использование параметра `openapi_examples` { #using-the-openapi-examples-parameter }\n\nВы можете объявлять специфические для OpenAPI `examples` в FastAPI с помощью параметра `openapi_examples` для:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nКлючи `dict` идентифицируют каждый пример, а каждое значение — это ещё один `dict`.\n\nКаждый конкретный пример `dict` в `examples` может содержать:\n\n* `summary`: Краткое описание примера.\n* `description`: Подробное описание, которое может содержать текст в Markdown.\n* `value`: Это фактический пример, который отображается, например, `dict`.\n* `externalValue`: альтернатива `value`, URL, указывающий на пример. Хотя это может поддерживаться не так многими инструментами, как `value`.\n\nИспользовать это можно так:\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### OpenAPI-примеры в UI документации { #openapi-examples-in-the-docs-ui }\n\nС `openapi_examples`, добавленным в `Body()`, страница `/docs` будет выглядеть так:\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## Технические детали { #technical-details }\n\n/// tip | Подсказка\n\nЕсли вы уже используете **FastAPI** версии **0.99.0 или выше**, вы, вероятно, можете **пропустить** эти подробности.\n\nОни более актуальны для старых версий, до того как стала доступна OpenAPI 3.1.0.\n\nСчитайте это кратким **уроком истории** про OpenAPI и JSON Schema. 🤓\n\n///\n\n/// warning | Внимание\n\nДалее идут очень технические подробности о стандартах **JSON Schema** и **OpenAPI**.\n\nЕсли идеи выше уже работают для вас, этого может быть достаточно, и, вероятно, вам не нужны эти детали — смело пропускайте их.\n\n///\n\nДо OpenAPI 3.1.0 OpenAPI использовала более старую и модифицированную версию **JSON Schema**.\n\nВ JSON Schema не было `examples`, поэтому OpenAPI добавила собственное поле `example` в свою модифицированную версию.\n\nOpenAPI также добавила поля `example` и `examples` в другие части спецификации:\n\n* [`Parameter Object` (в спецификации)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object), которое использовалось в FastAPI:\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object`, в поле `content`, в `Media Type Object` (в спецификации)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object), которое использовалось в FastAPI:\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info | Информация\n\nЭтот старый специфичный для OpenAPI параметр `examples` теперь называется `openapi_examples`, начиная с FastAPI `0.103.0`.\n\n///\n\n### Поле `examples` в JSON Schema { #json-schemas-examples-field }\n\nПозже в новой версии спецификации JSON Schema было добавлено поле [`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5).\n\nА затем новый OpenAPI 3.1.0 был основан на последней версии (JSON Schema 2020-12), которая включала это новое поле `examples`.\n\nИ теперь это новое поле `examples` имеет приоритет над старым одиночным (и кастомным) полем `example`, которое теперь устарело.\n\nЭто новое поле `examples` в JSON Schema — это **просто `list`** примеров, а не dict с дополнительными метаданными, как в других местах OpenAPI (описанных выше).\n\n/// info | Информация\n\nДаже после того как OpenAPI 3.1.0 была выпущена с этой новой, более простой интеграцией с JSON Schema, какое‑то время Swagger UI, инструмент, предоставляющий автоматическую документацию, не поддерживал OpenAPI 3.1.0 (поддержка появилась начиная с версии 5.0.0 🎉).\n\nИз‑за этого версии FastAPI до 0.99.0 всё ещё использовали версии OpenAPI ниже 3.1.0.\n\n///\n\n### `examples` в Pydantic и FastAPI { #pydantic-and-fastapi-examples }\n\nКогда вы добавляете `examples` внутри модели Pydantic, используя `schema_extra` или `Field(examples=[\"something\"])`, этот пример добавляется в **JSON Schema** для этой модели Pydantic.\n\nИ эта **JSON Schema** модели Pydantic включается в **OpenAPI** вашего API, а затем используется в UI документации.\n\nВ версиях FastAPI до 0.99.0 (0.99.0 и выше используют новый OpenAPI 3.1.0), когда вы использовали `example` или `examples` с любыми другими утилитами (`Query()`, `Body()`, и т.д.), эти примеры не добавлялись в JSON Schema, описывающую эти данные (даже в собственную версию JSON Schema OpenAPI), они добавлялись непосредственно в объявление *операции пути* в OpenAPI (вне частей OpenAPI, использующих JSON Schema).\n\nНо теперь, когда FastAPI 0.99.0 и выше используют OpenAPI 3.1.0, который использует JSON Schema 2020-12, а также Swagger UI 5.0.0 и выше, всё стало более последовательным, и примеры включаются в JSON Schema.\n\n### Swagger UI и специфичные для OpenAPI `examples` { #swagger-ui-and-openapi-specific-examples }\n\nТеперь, поскольку Swagger UI не поддерживал несколько примеров JSON Schema (по состоянию на 2023-08-26), у пользователей не было способа показать несколько примеров в документации.\n\nЧтобы решить это, FastAPI `0.103.0` **добавил поддержку** объявления того же старого, **специфичного для OpenAPI**, поля `examples` с новым параметром `openapi_examples`. 🤓\n\n### Итог { #summary }\n\nРаньше я говорил, что не очень люблю историю... а теперь вот рассказываю «уроки технической истории». 😅\n\nКоротко: **обновитесь до FastAPI 0.99.0 или выше** — так всё будет значительно **проще, последовательнее и интуитивнее**, и вам не придётся знать все эти исторические подробности. 😎\n"
  },
  {
    "path": "docs/ru/docs/tutorial/security/first-steps.md",
    "content": "# Безопасность — первые шаги { #security-first-steps }\n\nПредставим, что у вас есть **бэкенд** API на некотором домене.\n\nИ у вас есть **фронтенд** на другом домене или на другом пути того же домена (или в мобильном приложении).\n\nИ вы хотите, чтобы фронтенд мог аутентифицироваться на бэкенде, используя **имя пользователя** и **пароль**.\n\nМы можем использовать **OAuth2**, чтобы построить это с **FastAPI**.\n\nНо давайте сэкономим вам время на чтение всей длинной спецификации в поисках тех небольших фрагментов информации, которые вам нужны.\n\nВоспользуемся инструментами, предоставленными **FastAPI**, чтобы работать с безопасностью.\n\n## Как это выглядит { #how-it-looks }\n\nСначала просто воспользуемся кодом и посмотрим, как он работает, а затем вернемся и разберемся, что происходит.\n\n## Создание `main.py` { #create-main-py }\n\nСкопируйте пример в файл `main.py`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## Запуск { #run-it }\n\n/// info | Дополнительная информация\n\nПакет [`python-multipart`](https://github.com/Kludex/python-multipart) автоматически устанавливается вместе с **FastAPI**, если вы запускаете команду `pip install \"fastapi[standard]\"`.\n\nОднако, если вы используете команду `pip install fastapi`, пакет `python-multipart` по умолчанию не включается.\n\nЧтобы установить его вручную, убедитесь, что вы создали [виртуальное окружение](../../virtual-environments.md), активировали его и затем установили пакет:\n\n```console\n$ pip install python-multipart\n```\n\nЭто связано с тем, что **OAuth2** использует «данные формы» для отправки `username` и `password`.\n\n///\n\nЗапустите пример командой:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## Проверка { #check-it }\n\nПерейдите к интерактивной документации по адресу: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВы увидите примерно следующее:\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Кнопка авторизации!\n\nУ вас уже появилась новая кнопка «Authorize».\n\nА у вашей *операции пути* в правом верхнем углу есть маленький замочек, на который можно нажать.\n\n///\n\nЕсли нажать на нее, появится небольшая форма авторизации, в которую нужно ввести `username` и `password` (и другие необязательные поля):\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | Примечание\n\nНеважно, что вы введете в форму — пока это не будет работать. Но мы скоро до этого дойдем.\n\n///\n\nКонечно, это не фронтенд для конечных пользователей, но это отличный автоматический инструмент для интерактивного документирования всего вашего API.\n\nИм может пользоваться команда фронтенда (которой можете быть и вы сами).\n\nИм могут пользоваться сторонние приложения и системы.\n\nИ им также можете пользоваться вы сами, чтобы отлаживать, проверять и тестировать то же самое приложение.\n\n## «`password` flow» (аутентификация по паролю) { #the-password-flow }\n\nТеперь давайте немного вернемся и разберемся, что это все такое.\n\n«`password` flow» — это один из способов («flows»), определенных в OAuth2, для обеспечения безопасности и аутентификации.\n\nOAuth2 был спроектирован так, чтобы бэкенд или API были независимы от сервера, который аутентифицирует пользователя.\n\nНо в нашем случае одно и то же приложение **FastAPI** будет работать и с API, и с аутентификацией.\n\nИтак, рассмотрим это с упрощенной точки зрения:\n\n* Пользователь вводит на фронтенде `username` и `password` и нажимает `Enter`.\n* Фронтенд (работающий в браузере пользователя) отправляет эти `username` и `password` на конкретный URL в нашем API (объявленный с `tokenUrl=\"token\"`).\n* API проверяет этот `username` и `password` и отвечает «токеном» (мы еще ничего из этого не реализовали).\n    * «Токен» — это просто строка с некоторым содержимым, которое мы сможем позже использовать для проверки этого пользователя.\n    * Обычно у токена установлен срок действия: он истекает через некоторое время.\n        * Поэтому пользователю придется снова войти в систему в какой‑то момент.\n        * И если токен украдут, риск меньше: это не постоянный ключ, который будет работать вечно (в большинстве случаев).\n* Фронтенд временно где‑то хранит этот токен.\n* Пользователь кликает во фронтенде, чтобы перейти в другой раздел веб‑приложения.\n* Фронтенду нужно получить дополнительные данные из API.\n    * Но для этого для конкретной конечной точки нужна аутентификация.\n    * Поэтому, чтобы аутентифицироваться в нашем API, он отправляет HTTP-заголовок `Authorization` со значением `Bearer ` плюс сам токен.\n    * Если токен содержит `foobar`, то содержимое заголовка `Authorization` будет: `Bearer foobar`.\n\n## Класс `OAuth2PasswordBearer` в **FastAPI** { #fastapis-oauth2passwordbearer }\n\n**FastAPI** предоставляет несколько средств на разных уровнях абстракции для реализации этих функций безопасности.\n\nВ этом примере мы будем использовать **OAuth2**, с потоком **Password**, используя токен **Bearer**. Для этого мы используем класс `OAuth2PasswordBearer`.\n\n/// info | Дополнительная информация\n\nТокен «bearer» — не единственный вариант.\n\nНо для нашего случая он — лучший.\n\nИ он может быть лучшим для большинства случаев использования, если только вы не являетесь экспертом по OAuth2 и точно знаете, почему другой вариант лучше подходит под ваши нужды.\n\nВ этом случае **FastAPI** также предоставляет инструменты, чтобы его реализовать.\n\n///\n\nПри создании экземпляра класса `OAuth2PasswordBearer` мы передаем параметр `tokenUrl`. Этот параметр содержит URL, который клиент (фронтенд, работающий в браузере пользователя) будет использовать для отправки `username` и `password`, чтобы получить токен.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip | Подсказка\n\nЗдесь `tokenUrl=\"token\"` ссылается на относительный URL `token`, который мы еще не создали. Поскольку это относительный URL, он эквивалентен `./token`.\n\nПоскольку мы используем относительный URL, если ваш API расположен по адресу `https://example.com/`, то он будет ссылаться на `https://example.com/token`. А если ваш API расположен по адресу `https://example.com/api/v1/`, то он будет ссылаться на `https://example.com/api/v1/token`.\n\nИспользование относительного URL важно для того, чтобы ваше приложение продолжало работать даже в таком продвинутом случае, как [За прокси-сервером](../../advanced/behind-a-proxy.md).\n\n///\n\nЭтот параметр не создает конечную точку / *операцию пути*, а объявляет, что URL `/token` — это тот, который клиент должен использовать для получения токена. Эта информация используется в OpenAPI, а затем в интерактивных системах документации по API.\n\nСкоро мы также создадим и саму операцию пути.\n\n/// info | Дополнительная информация\n\nЕсли вы очень строгий «питонист», вам может не понравиться стиль имени параметра `tokenUrl` вместо `token_url`.\n\nЭто потому, что используется то же имя, что и в спецификации OpenAPI. Так, если вам нужно разобраться подробнее в какой‑то из этих схем безопасности, вы можете просто скопировать и вставить это имя, чтобы найти больше информации.\n\n///\n\nПеременная `oauth2_scheme` — это экземпляр `OAuth2PasswordBearer`, но она также «вызываемая».\n\nЕе можно вызвать так:\n\n```Python\noauth2_scheme(some, parameters)\n```\n\nПоэтому ее можно использовать вместе с `Depends`.\n\n### Использование { #use-it }\n\nТеперь вы можете передать `oauth2_scheme` как зависимость с `Depends`.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nЭта зависимость предоставит `str`, который будет присвоен параметру `token` *функции-обработчика пути*.\n\n**FastAPI** будет знать, что может использовать эту зависимость для определения «схемы безопасности» в схеме OpenAPI (и в автоматической документации по API).\n\n/// info | Технические детали\n\n**FastAPI** будет знать, что может использовать класс `OAuth2PasswordBearer` (объявленный в зависимости) для определения схемы безопасности в OpenAPI, потому что он наследуется от `fastapi.security.oauth2.OAuth2`, который, в свою очередь, наследуется от `fastapi.security.base.SecurityBase`.\n\nВсе утилиты безопасности, интегрируемые с OpenAPI (и автоматической документацией по API), наследуются от `SecurityBase`, — так **FastAPI** понимает, как интегрировать их в OpenAPI.\n\n///\n\n## Что он делает { #what-it-does }\n\nОн будет искать в запросе заголовок `Authorization`, проверять, что его значение — это `Bearer ` плюс некоторый токен, и вернет токен как `str`.\n\nЕсли заголовок `Authorization` отсутствует или его значение не содержит токен `Bearer `, он сразу ответит ошибкой со статус-кодом 401 (`UNAUTHORIZED`).\n\nВам даже не нужно проверять наличие токена, чтобы вернуть ошибку. Вы можете быть уверены: если ваша функция была выполнена, в этом токене будет `str`.\n\nЭто уже можно попробовать в интерактивной документации:\n\n<img src=\"/img/tutorial/security/image03.png\">\n\nМы пока не проверяем валидность токена, но для начала это уже неплохо.\n\n## Резюме { #recap }\n\nТаким образом, всего за 3–4 дополнительные строки у вас уже есть некая примитивная форма защиты.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/security/get-current-user.md",
    "content": "# Получить текущего пользователя { #get-current-user }\n\nВ предыдущей главе система безопасности (основанная на системе внедрения зависимостей) передавала *функции-обработчику пути* `token` типа `str`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nНо это всё ещё не слишком полезно.\n\nСделаем так, чтобы она возвращала текущего пользователя.\n\n## Создать модель пользователя { #create-a-user-model }\n\nСначала создадим Pydantic-модель пользователя.\n\nТочно так же, как мы используем Pydantic для объявления тел запросов, мы можем использовать его где угодно:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## Создать зависимость `get_current_user` { #create-a-get-current-user-dependency }\n\nДавайте создадим зависимость `get_current_user`.\n\nПомните, что у зависимостей могут быть подзависимости?\n\n`get_current_user` будет иметь зависимость от того же `oauth2_scheme`, который мы создали ранее.\n\nАналогично тому, как мы делали ранее прямо в *операции пути*, новая зависимость `get_current_user` получит `token` типа `str` от подзависимости `oauth2_scheme`:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## Получить пользователя { #get-the-user }\n\n`get_current_user` будет использовать созданную нами (ненастоящую) служебную функцию, которая принимает токен типа `str` и возвращает нашу Pydantic-модель `User`:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## Внедрить текущего пользователя { #inject-the-current-user }\n\nТеперь мы можем использовать тот же `Depends` с нашей `get_current_user` в *операции пути*:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\nОбратите внимание, что мы объявляем тип `current_user` как Pydantic-модель `User`.\n\nЭто поможет внутри функции с автозавершением и проверками типов.\n\n/// tip | Подсказка\n\nВозможно, вы помните, что тела запросов также объявляются с помощью Pydantic-моделей.\n\nЗдесь **FastAPI** не запутается, потому что вы используете `Depends`.\n\n///\n\n/// check | Заметка\n\nТо, как устроена эта система зависимостей, позволяет иметь разные зависимости, которые возвращают модель `User`.\n\nМы не ограничены наличием только одной зависимости, которая может возвращать такой тип данных.\n\n///\n\n## Другие модели { #other-models }\n\nТеперь вы можете получать текущего пользователя напрямую в *функциях-обработчиках пути* и работать с механизмами безопасности на уровне **внедрения зависимостей**, используя `Depends`.\n\nИ вы можете использовать любую модель или данные для требований безопасности (в данном случае Pydantic-модель `User`).\n\nНо вы не ограничены использованием какой-то конкретной модели данных, класса или типа.\n\nХотите, чтобы в модели были `id` и `email`, но не было `username`? Пожалуйста. Можно использовать те же инструменты.\n\nХотите просто `str`? Или просто `dict`? Или напрямую экземпляр класса модели базы данных? Всё работает одинаково.\n\nУ вас вообще нет пользователей, которые входят в приложение, а есть роботы, боты или другие системы, у которых есть только токен доступа? Снова — всё работает так же.\n\nПросто используйте любую модель, любой класс, любую базу данных, которые нужны вашему приложению. Система внедрения зависимостей **FastAPI** поможет вам в этом.\n\n## Размер кода { #code-size }\n\nЭтот пример может показаться многословным. Имейте в виду, что в одном файле мы смешиваем безопасность, модели данных, служебные функции и *операции пути*.\n\nНо вот ключевой момент.\n\nВсё, что касается безопасности и внедрения зависимостей, пишется один раз.\n\nИ вы можете сделать это настолько сложным, насколько захотите. И всё равно это будет написано только один раз, в одном месте. Со всей гибкостью.\n\nПри этом у вас могут быть тысячи эндпоинтов (*операций пути*), использующих одну и ту же систему безопасности.\n\nИ все они (или любая их часть по вашему желанию) могут воспользоваться преимуществами повторного использования этих зависимостей или любых других зависимостей, которые вы создадите.\n\nИ все эти тысячи *операций пути* могут состоять всего из 3 строк:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## Резюме { #recap }\n\nТеперь вы можете получать текущего пользователя прямо в своей *функции-обработчике пути*.\n\nМы уже на полпути.\n\nНужно лишь добавить *операцию пути*, чтобы пользователь/клиент мог отправить `username` и `password`.\n\nЭто будет дальше.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/security/index.md",
    "content": "# Безопасность { #security }\n\nСуществует множество способов обеспечения безопасности, аутентификации и авторизации.\n\nОбычно эта тема является достаточно сложной и «трудной».\n\nВо многих фреймворках и системах только работа с безопасностью и аутентификацией требует значительных затрат усилий и написания множества кода (во многих случаях его объём может составлять 50% или более от всего написанного кода).\n\n**FastAPI** предоставляет несколько инструментов, которые помогут вам работать с **безопасностью** легко, быстро, стандартным способом, без необходимости изучать и разбираться во всех спецификациях по безопасности.\n\nНо сначала давайте рассмотрим несколько небольших концепций.\n\n## Нет времени? { #in-a-hurry }\n\nЕсли вам не важны какие-либо из этих терминов и вам просто нужно добавить защиту с аутентификацией на основе имени пользователя и пароля прямо сейчас, переходите к следующим главам.\n\n## OAuth2 { #oauth2 }\n\nOAuth2 - это спецификация, которая определяет несколько способов обработки аутентификации и авторизации.\n\nЭто довольно обширная спецификация, охватывающая несколько сложных вариантов использования.\n\nОна включает способы аутентификации с использованием «третьей стороны».\n\nИменно это используется во всех системах с кнопками «войти с помощью Facebook, Google, X (Twitter), GitHub».\n\n### OAuth 1 { #oauth-1 }\n\nРанее использовался OAuth 1, который сильно отличается от OAuth2 и является более сложным, поскольку он включал прямые спецификации того, как шифровать обмен данными.\n\nВ настоящее время он не очень популярен и не используется.\n\nOAuth2 не указывает, как шифровать обмен данными, он ожидает, что ваше приложение будет обслуживаться по протоколу HTTPS.\n\n/// tip | Подсказка\n\nВ разделе о **развертывании** вы увидите, как настроить HTTPS бесплатно, используя Traefik и Let's Encrypt.\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect — это ещё одна спецификация, основанная на **OAuth2**.\n\nОна просто расширяет OAuth2, уточняя некоторые вещи, которые относительно неоднозначны в OAuth2, стараясь сделать его более совместимым.\n\nНапример, для входа в Google используется OpenID Connect (который под капотом использует OAuth2).\n\nНо вход в Facebook не поддерживает OpenID Connect. У него есть собственная вариация OAuth2.\n\n### OpenID (не «OpenID Connect») { #openid-not-openid-connect }\n\nТакже ранее использовалась спецификация «OpenID», которая пыталась решить ту же задачу, что и **OpenID Connect**, но не была основана на OAuth2.\n\nТаким образом, это была полноценная дополнительная система.\n\nВ настоящее время не очень популярен и не используется.\n\n## OpenAPI { #openapi }\n\nOpenAPI (ранее известный как Swagger) - это открытая спецификация для создания API (в настоящее время является частью Linux Foundation).\n\n**FastAPI** основан на **OpenAPI**.\n\nЭто то, что делает возможными несколько автоматических интерактивных интерфейсов документации, генерацию кода и т.д.\n\nВ OpenAPI есть способ определить несколько «схем» безопасности.\n\nИспользуя их, вы можете воспользоваться преимуществами всех этих инструментов, основанных на стандартах, включая интерактивные системы документирования.\n\nOpenAPI определяет следующие схемы безопасности:\n\n* `apiKey`: специфичный для приложения ключ, который может поступать из:\n    * параметра запроса.\n    * HTTP-заголовка.\n    * cookie.\n* `http`: стандартные системы аутентификации по HTTP, включая:\n    * `bearer`: HTTP-заголовок `Authorization` со значением `Bearer ` плюс токен. Это унаследовано от OAuth2.\n    * Базовая аутентификация по HTTP.\n    * HTTP Digest и т.д.\n* `oauth2`: все способы OAuth2 для обеспечения безопасности (называются «потоками»).\n    * Несколько из этих «потоков» подходят для построения провайдера аутентификации OAuth 2.0 (например, Google, Facebook, X (Twitter), GitHub и т.д.):\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * Но есть один конкретный «поток», который можно идеально использовать для обработки аутентификации непосредственно в этом же приложении:\n        * `password`: в некоторых следующих главах будут приведены примеры.\n* `openIdConnect`: имеет способ определить, как автоматически обнаруживать данные аутентификации OAuth2.\n    * Именно это автоматическое обнаружение определено в спецификации OpenID Connect.\n\n\n/// tip | Подсказка\n\nИнтеграция сторонних провайдеров аутентификации/авторизации, таких как Google, Facebook, X (Twitter), GitHub и т.д., также возможна и относительно проста.\n\nСамой сложной задачей является создание такого провайдера аутентификации/авторизации, но **FastAPI** предоставляет вам инструменты, позволяющие легко это сделать, выполняя при этом всю тяжёлую работу за вас.\n\n///\n\n## Инструменты **FastAPI** { #fastapi-utilities }\n\nFastAPI предоставляет несколько инструментов для каждой из этих схем безопасности в модуле `fastapi.security`, которые упрощают использование этих механизмов безопасности.\n\nВ следующих главах вы увидите, как добавить безопасность в ваш API, используя инструменты, предоставляемые **FastAPI**.\n\nИ вы также увидите, как это автоматически интегрируется в систему интерактивной документации.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/security/oauth2-jwt.md",
    "content": "# OAuth2 с паролем (и хешированием), Bearer с JWT-токенами { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\nТеперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены <abbr title=\"JSON Web Tokens - веб‑токены JSON\">JWT</abbr> и безопасное хеширование паролей.\n\nЭтот код можно реально использовать в своем приложении, сохранять хэши паролей в базе данных и т.д.\n\nМы продолжим разбираться, начиная с того места, на котором остановились в предыдущей главе, и расширим его.\n\n## Про JWT { #about-jwt }\n\nJWT означает \"JSON Web Tokens\".\n\nЭто стандарт для кодирования JSON-объекта в виде длинной строки без пробелов. Выглядит это следующим образом:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\nОн не зашифрован, поэтому любой человек может восстановить информацию из его содержимого.\n\nНо он подписан. Следовательно, когда вы получаете токен, который вы эмитировали (выдавали), вы можете убедиться, что это именно вы его эмитировали.\n\nТаким образом, можно создать токен со сроком действия, скажем, 1 неделя. А когда пользователь вернется на следующий день с тем же токеном, вы будете знать, что он все еще авторизован в вашей системе.\n\nЧерез неделю срок действия токена истечет, пользователь не будет авторизован и ему придется заново входить в систему, чтобы получить новый токен. А если пользователь (или третье лицо) попытается модифицировать токен, чтобы изменить срок действия, вы сможете это обнаружить, поскольку подписи не будут совпадать.\n\nЕсли вы хотите поиграть с JWT-токенами и посмотреть, как они работают, посмотрите [https://jwt.io](https://jwt.io/).\n\n## Установка `PyJWT` { #install-pyjwt }\n\nНам необходимо установить `pyjwt` для генерации и проверки JWT-токенов на языке Python.\n\nУбедитесь, что вы создали [виртуальное окружение](../../virtual-environments.md), активируйте его, а затем установите `pyjwt`:\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info | Дополнительная информация\n\nЕсли вы планируете использовать алгоритмы цифровой подписи, такие как RSA или ECDSA, вам следует установить зависимость библиотеки криптографии `pyjwt[crypto]`.\n\nПодробнее об этом можно прочитать в [документации по установке PyJWT](https://pyjwt.readthedocs.io/en/latest/installation.html).\n\n///\n\n## Хеширование паролей { #password-hashing }\n\n\"Хеширование\" означает преобразование некоторого содержимого (в данном случае пароля) в последовательность байтов (просто строку), которая выглядит как тарабарщина.\n\nКаждый раз, когда вы передаете точно такое же содержимое (точно такой же пароль), вы получаете точно такую же тарабарщину.\n\nНо преобразовать тарабарщину обратно в пароль невозможно.\n\n### Для чего нужно хеширование паролей { #why-use-password-hashing }\n\nЕсли ваша база данных будет украдена, то вор не получит пароли пользователей в открытом виде, а только их хэши.\n\nТаким образом, вор не сможет использовать этот пароль в другой системе (поскольку многие пользователи везде используют один и тот же пароль, это было бы опасно).\n\n## Установка `pwdlib` { #install-pwdlib }\n\npwdlib — это отличный пакет Python для работы с хэшами паролей.\n\nОн поддерживает множество безопасных алгоритмов хеширования и утилит для работы с ними.\n\nРекомендуемый алгоритм — \"Argon2\".\n\nУбедитесь, что вы создали [виртуальное окружение](../../virtual-environments.md), активируйте его, и затем установите pwdlib вместе с Argon2:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | Подсказка\n\nС помощью `pwdlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками.\n\nТаким образом, вы сможете, например, совместно использовать одни и те же данные из приложения Django в базе данных с приложением FastAPI. Или постепенно мигрировать Django-приложение, используя ту же базу данных.\n\nПри этом пользователи смогут одновременно входить в систему как из приложения Django, так и из приложения **FastAPI**.\n\n///\n\n## Хеширование и проверка паролей { #hash-and-verify-the-passwords }\n\nИмпортируйте необходимые инструменты из `pwdlib`.\n\nСоздайте экземпляр PasswordHash с рекомендованными настройками — он будет использоваться для хэширования и проверки паролей.\n\n/// tip | Подсказка\n\npwdlib также поддерживает алгоритм хеширования bcrypt, но не включает устаревшие алгоритмы — для работы с устаревшими хэшами рекомендуется использовать библиотеку passlib.\n\nНапример, вы можете использовать ее для чтения и проверки паролей, сгенерированных другой системой (например, Django), но хэшировать все новые пароли другим алгоритмом, например Argon2 или Bcrypt.\n\nИ при этом быть совместимым со всеми этими системами.\n\n///\n\nСоздайте служебную функцию для хэширования пароля, поступающего от пользователя.\n\nА затем создайте другую — для проверки соответствия полученного пароля и хранимого хэша.\n\nИ еще одну — для аутентификации и возврата пользователя.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\nКогда `authenticate_user` вызывается с именем пользователя, которого нет в базе данных, мы все равно запускаем `verify_password` с использованием фиктивного хэша.\n\nЭто гарантирует, что эндпоинт отвечает примерно за одно и то же время вне зависимости от того, существует имя пользователя или нет, предотвращая тайминговые атаки (атака по времени), с помощью которых можно было бы перечислять существующие имена пользователей.\n\n/// note | Технические детали\n\nЕсли проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`.\n\n///\n\n## Работа с JWT токенами { #handle-jwt-tokens }\n\nИмпортируйте установленные модули.\n\nСоздайте случайный секретный ключ, который будет использоваться для подписи JWT-токенов.\n\nДля генерации безопасного случайного секретного ключа используйте команду:\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\nИ скопируйте полученный результат в переменную `SECRET_KEY` (не используйте тот, что в примере).\n\nСоздайте переменную `ALGORITHM` с алгоритмом, используемым для подписи JWT-токена, и установите для нее значение `\"HS256\"`.\n\nСоздайте переменную для срока действия токена.\n\nОпределите Pydantic-модель, которая будет использоваться для формирования ответа на запрос на получение токена.\n\nСоздайте служебную функцию для генерации нового токена доступа.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## Обновление зависимостей { #update-the-dependencies }\n\nОбновите `get_current_user` для получения того же токена, что и раньше, но на этот раз с использованием JWT-токенов.\n\nДекодируйте полученный токен, проверьте его и верните текущего пользователя.\n\nЕсли токен недействителен, то сразу же верните HTTP-ошибку.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## Обновление *операции пути* `/token` { #update-the-token-path-operation }\n\nСоздайте `timedelta` со временем истечения срока действия токена.\n\nСоздайте реальный токен доступа JWT и верните его\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### Технические подробности о JWT ключе `sub` { #technical-details-about-the-jwt-subject-sub }\n\nВ спецификации JWT говорится, что существует ключ `sub`, содержащий субъект токена.\n\nЕго использование необязательно, но это именно то место, куда вы должны поместить идентификатор пользователя, и поэтому мы здесь его и используем.\n\nJWT может использоваться и для других целей, помимо идентификации пользователя и предоставления ему возможности выполнять операции непосредственно в вашем API.\n\nНапример, вы могли бы определить \"автомобиль\" или \"запись в блоге\".\n\nЗатем вы могли бы добавить права доступа к этой сущности, например \"управлять\" (для автомобиля) или \"редактировать\" (для блога).\n\nЗатем вы могли бы передать этот JWT-токен пользователю (или боту), и они использовали бы его для выполнения определенных действий (управление автомобилем или редактирование запись в блоге), даже не имея учетной записи, просто используя JWT-токен, сгенерированный вашим API.\n\nИспользуя эти идеи, JWT можно применять для гораздо более сложных сценариев.\n\nВ отдельных случаях несколько сущностей могут иметь один и тот же идентификатор, скажем, `foo` (пользователь `foo`, автомобиль `foo` и запись в блоге `foo`).\n\nПоэтому, чтобы избежать коллизий идентификаторов, при создании JWT-токена для пользователя можно добавить префикс `username` к значению ключа `sub`. Таким образом, в данном примере значение `sub` было бы `username:johndoe`.\n\nВажно помнить, что ключ `sub` должен иметь уникальный идентификатор для всего приложения и представлять собой строку.\n\n## Проверка в действии { #check-it }\n\nЗапустите сервер и перейдите к документации: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВы увидите пользовательский интерфейс вида:\n\n<img src=\"/img/tutorial/security/image07.png\">\n\nПройдите авторизацию так же, как делали раньше.\n\nИспользуя учетные данные пользователя:\n\nUsername: `johndoe`\nPassword: `secret`\n\n/// check | Проверка\n\nОбратите внимание, что нигде в коде не используется открытый текст пароля \"`secret`\", мы используем только его хэшированную версию.\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\nВызвав эндпоинт `/users/me/`, вы получите ответ в виде:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\nЕсли открыть инструменты разработчика, то можно увидеть, что передаваемые данные включают только токен, пароль передается только в первом запросе для аутентификации пользователя и получения токена доступа, но не в последующих:\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | Техническая информация\n\nОбратите внимание на HTTP-заголовок `Authorization`, значение которого начинается с `Bearer `.\n\n///\n\n## Продвинутое использование `scopes` { #advanced-usage-with-scopes }\n\nВ OAuth2 существует понятие \"диапазоны\" (\"`scopes`\").\n\nС их помощью можно добавить определенный набор разрешений к JWT-токену.\n\nЗатем вы можете передать этот токен непосредственно пользователю или третьей стороне для взаимодействия с вашим API с определенным набором ограничений.\n\nО том, как их использовать и как они интегрированы в **FastAPI**, читайте далее в **Расширенном руководстве пользователя**.\n\n## Резюме { #recap }\n\nС учетом того, что вы видели до сих пор, вы можете создать безопасное приложение **FastAPI**, используя такие стандарты, как OAuth2 и JWT.\n\nПрактически в любом фреймворке работа с безопасностью довольно быстро превращается в сложную тему.\n\nМногие пакеты, сильно упрощающие эту задачу, вынуждены идти на многочисленные компромиссы с моделью данных, с базой данных и с доступным функционалом. Некоторые из этих пакетов, которые пытаются уж слишком все упростить, имеют даже \"дыры\" в системе безопасности.\n\n---\n\n**FastAPI** не делает уступок ни одной базе данных, модели данных или инструментарию.\n\nОн предоставляет вам полную свободу действий, позволяя выбирать то, что лучше всего подходит для вашего проекта.\n\nВы можете напрямую использовать многие хорошо поддерживаемые и широко распространенные пакеты, такие как `pwdlib` и `PyJWT`, поскольку **FastAPI** не требует сложных механизмов для интеграции внешних пакетов.\n\nНапротив, он предоставляет инструменты, позволяющие максимально упростить этот процесс без ущерба для гибкости, надежности и безопасности.\n\nПри этом вы можете использовать и реализовывать безопасные стандартные протоколы, такие как OAuth2, относительно простым способом.\n\nВ **Расширенном руководстве пользователя** вы можете узнать больше о том, как использовать \"диапазоны\" (\"`scopes`\") OAuth2 для создания более точно настроенной системы разрешений в соответствии с теми же стандартами. OAuth2 с диапазонами — это механизм, используемый многими крупными провайдерами сервиса аутентификации, такими как Facebook, Google, GitHub, Microsoft, X (Twitter) и др., для авторизации сторонних приложений на взаимодействие с их API от имени их пользователей.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/security/simple-oauth2.md",
    "content": "# Простая авторизация OAuth2 с паролем и «Bearer» { #simple-oauth2-with-password-and-bearer }\n\nТеперь, отталкиваясь от предыдущей главы, добавим недостающие части, чтобы получить полный поток безопасности.\n\n## Получение `username` и `password` { #get-the-username-and-password }\n\nДля получения `username` и `password` мы будем использовать утилиты безопасности **FastAPI**.\n\nOAuth2 определяет, что при использовании \"password flow\" (аутентификация по паролю - именно его мы используем) клиент/пользователь должен передавать поля `username` и `password` в полях формы.\n\nВ спецификации сказано, что поля должны быть названы именно так. Поэтому `user-name` или `email` работать не будут.\n\nНо не волнуйтесь, вы можете показать это конечным пользователям во фронтенде в том виде, в котором хотите.\n\nА ваши модели баз данных могут использовать любые другие имена.\n\nНо для логин-операции пути нам нужно использовать именно эти имена, чтобы быть совместимыми со спецификацией (и иметь возможность, например, использовать встроенную систему документации API).\n\nВ спецификации также указано, что `username` и `password` должны передаваться в виде данных формы (так что никакого JSON здесь нет).\n\n### `scope` { #scope }\n\nВ спецификации также говорится, что клиент может передать еще одно поле формы — `scope`.\n\nИмя поля формы — `scope` (в единственном числе), но на самом деле это длинная строка, состоящая из отдельных \"scopes\", разделенных пробелами.\n\nКаждый \"scope\" — это просто строка (без пробелов).\n\nОбычно они используются для указания уровней доступа, например:\n\n* `users:read` или `users:write` — распространенные примеры.\n* `instagram_basic` используется Facebook / Instagram.\n* `https://www.googleapis.com/auth/drive` используется Google.\n\n/// info | Дополнительная информация\nВ OAuth2 \"scope\" — это просто строка, которая указывает требуемое конкретное разрешение.\n\nНе имеет значения, содержит ли она другие символы, например `:`, или является ли это URL.\n\nЭти детали зависят от реализации.\n\nДля OAuth2 это просто строки.\n///\n\n## Код для получения `username` и `password` { #code-to-get-the-username-and-password }\n\nТеперь воспользуемся утилитами, предоставляемыми **FastAPI**, чтобы обработать это.\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\nСначала импортируйте `OAuth2PasswordRequestForm` и затем используйте её как зависимость с `Depends` в операции пути для `/token`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm` — это зависимость-класс, которая объявляет тело формы со следующими полями:\n\n* `username`.\n* `password`.\n* Необязательное поле `scope` в виде большой строки, состоящей из строк, разделенных пробелами.\n* Необязательное поле `grant_type`.\n\n/// tip | Подсказка\nПо спецификации OAuth2 поле `grant_type` обязательно и содержит фиксированное значение `password`, но `OAuth2PasswordRequestForm` это не проверяет строго.\n\nЕсли вам нужно это строгое требование, используйте `OAuth2PasswordRequestFormStrict` вместо `OAuth2PasswordRequestForm`.\n///\n\n* Необязательное поле `client_id` (в нашем примере оно не нужно).\n* Необязательное поле `client_secret` (в нашем примере оно не нужно).\n\n/// info | Дополнительная информация\n`OAuth2PasswordRequestForm` — это не специальный класс для **FastAPI**, как `OAuth2PasswordBearer`.\n\n`OAuth2PasswordBearer` сообщает **FastAPI**, что это схема безопасности. Поэтому она добавляется в OpenAPI соответствующим образом.\n\nА `OAuth2PasswordRequestForm` — это просто зависимость-класс, которую вы могли бы написать сами, или вы могли бы объявить параметры `Form` напрямую.\n\nНо так как это распространённый вариант использования, он предоставлен **FastAPI** напрямую, чтобы упростить задачу.\n///\n\n### Использование данных формы { #use-the-form-data }\n\n/// tip | Подсказка\nУ экземпляра зависимости `OAuth2PasswordRequestForm` не будет атрибута `scope` с длинной строкой, разделенной пробелами. Вместо этого будет атрибут `scopes` со списком отдельных строк — по одной для каждого переданного scope.\n\nВ данном примере мы не используем `scopes`, но если вам это необходимо, функциональность есть.\n///\n\nТеперь получим данные о пользователе из (ненастоящей) базы данных, используя `username` из поля формы.\n\nЕсли такого пользователя нет, то мы возвращаем ошибку \"Incorrect username or password\" (неверное имя пользователя или пароль).\n\nДля ошибки используем исключение `HTTPException`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### Проверка пароля { #check-the-password }\n\nНа данный момент у нас есть данные о пользователе из нашей базы данных, но мы еще не проверили пароль.\n\nДавайте сначала поместим эти данные в Pydantic-модель `UserInDB`.\n\nНикогда нельзя сохранять пароли в открытом виде, поэтому мы будем использовать (пока что ненастоящую) систему хеширования паролей.\n\nЕсли пароли не совпадают, мы возвращаем ту же ошибку.\n\n#### Хеширование паролей { #password-hashing }\n\n\"Хеширование\" означает: преобразование некоторого содержимого (в данном случае пароля) в последовательность байтов (просто строку), которая выглядит как тарабарщина.\n\nКаждый раз, когда вы передаете точно такое же содержимое (точно такой же пароль), вы получаете точно такую же тарабарщину.\n\nНо преобразовать тарабарщину обратно в пароль невозможно.\n\n##### Зачем использовать хеширование паролей { #why-use-password-hashing }\n\nЕсли вашу базу данных украдут, у злоумышленника не будет паролей пользователей в открытом виде, только хэши.\n\nТаким образом, он не сможет попробовать использовать эти же пароли в другой системе (поскольку многие пользователи используют один и тот же пароль повсеместно, это было бы опасно).\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### Про `**user_dict` { #about-user-dict }\n\n`UserInDB(**user_dict)` означает:\n\n*Передать ключи и значения `user_dict` непосредственно как аргументы ключ-значение, эквивалентно:*\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info | Дополнительная информация\nБолее полное объяснение `**user_dict` можно найти в [документации к **Дополнительным моделям**](../extra-models.md#about-user-in-dict).\n///\n\n## Возврат токена { #return-the-token }\n\nОтвет операции пути `/token` должен быть объектом JSON.\n\nВ нём должен быть `token_type`. В нашем случае, поскольку мы используем токены типа \"Bearer\", тип токена должен быть `bearer`.\n\nИ в нём должен быть `access_token` — строка, содержащая наш токен доступа.\n\nВ этом простом примере мы намеренно поступим небезопасно и вернём тот же `username` в качестве токена.\n\n/// tip | Подсказка\nВ следующей главе вы увидите реальную защищённую реализацию с хешированием паролей и токенами <abbr title=\"JSON Web Tokens – JSON веб-токены\">JWT</abbr>.\n\nНо пока давайте сосредоточимся на необходимых нам деталях.\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip | Подсказка\nСогласно спецификации, вы должны возвращать JSON с `access_token` и `token_type`, как в данном примере.\n\nЭто то, что вы должны сделать сами в своём коде и убедиться, что вы используете именно эти JSON-ключи.\n\nЭто практически единственное, о чём нужно не забыть, чтобы соответствовать спецификациям.\n\nОстальное за вас сделает **FastAPI**.\n///\n\n## Обновление зависимостей { #update-the-dependencies }\n\nТеперь мы обновим наши зависимости.\n\nМы хотим получить `current_user` только если этот пользователь активен.\n\nПоэтому мы создаём дополнительную зависимость `get_current_active_user`, которая, в свою очередь, использует в качестве зависимости `get_current_user`.\n\nОбе эти зависимости просто вернут HTTP-ошибку, если пользователь не существует или неактивен.\n\nТаким образом, в нашей операции пути мы получим пользователя только в том случае, если он существует, корректно аутентифицирован и активен:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info | Дополнительная информация\nДополнительный HTTP-заголовок `WWW-Authenticate` со значением `Bearer`, который мы здесь возвращаем, также является частью спецификации.\n\nЛюбой HTTP статус-код 401 \"UNAUTHORIZED\" должен также возвращать заголовок `WWW-Authenticate`.\n\nВ случае с bearer-токенами (наш случай) значение этого заголовка должно быть `Bearer`.\n\nФактически, этот дополнительный заголовок можно опустить, и всё будет работать.\n\nНо он приведён здесь для соответствия спецификациям.\n\nКроме того, могут существовать инструменты, которые ожидают его и могут использовать, и это может быть полезно для вас или ваших пользователей — сейчас или в будущем.\n\nВ этом и заключается преимущество стандартов...\n///\n\n## Посмотрим, как это работает { #see-it-in-action }\n\nОткройте интерактивную документацию: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n### Аутентификация { #authenticate }\n\nНажмите кнопку \"Authorize\".\n\nИспользуйте учётные данные:\n\nПользователь: `johndoe`\n\nПароль: `secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\nПосле аутентификации вы увидите следующее:\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### Получение собственных пользовательских данных { #get-your-own-user-data }\n\nТеперь используйте операцию `GET` с путём `/users/me`.\n\nВы получите свои пользовательские данные, например:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\nЕсли щёлкнуть на значке замка и выйти из системы, а затем попробовать выполнить ту же операцию ещё раз, будет выдана ошибка HTTP 401:\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### Неактивный пользователь { #inactive-user }\n\nТеперь попробуйте с неактивным пользователем, аутентифицируйтесь с:\n\nПользователь: `alice`\n\nПароль: `secret2`\n\nИ попробуйте использовать операцию `GET` с путём `/users/me`.\n\nВы получите ошибку \"Inactive user\", как здесь:\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## Резюме { #recap }\n\nТеперь у вас есть инструменты для реализации полноценной системы безопасности на основе `username` и `password` для вашего API.\n\nИспользуя эти средства, можно сделать систему безопасности совместимой с любой базой данных и с любой пользовательской или моделью данных.\n\nЕдинственная деталь, которой не хватает, — система пока ещё не \"защищена\" по-настоящему.\n\nВ следующей главе вы увидите, как использовать библиотеку безопасного хеширования паролей и токены <abbr title=\"JSON Web Tokens – JSON веб-токены\">JWT</abbr>.\n"
  },
  {
    "path": "docs/ru/docs/tutorial/server-sent-events.md",
    "content": "# События, отправляемые сервером (SSE) { #server-sent-events-sse }\n\nВы можете передавать данные потоком клиенту, используя Server-Sent Events (SSE).\n\nЭто похоже на [Стриминг JSON Lines](stream-json-lines.md), но использует формат `text/event-stream`, который нативно поддерживается браузерами через [`EventSource` API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).\n\n/// info | Информация\n\nДобавлено в FastAPI 0.135.0.\n\n///\n\n## Что такое Server-Sent Events? { #what-are-server-sent-events }\n\nSSE — это стандарт для потоковой передачи данных с сервера на клиента по HTTP.\n\nКаждое событие — это небольшой текстовый блок с «полями», такими как `data`, `event`, `id` и `retry`, разделёнными пустыми строками.\n\nЭто выглядит так:\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE часто используют для стриминга ответов ИИ в чатах, живых уведомлений, логов и наблюдаемости, а также в других случаях, когда сервер «проталкивает» обновления клиенту.\n\n/// tip | Совет\n\nЕсли вам нужно стримить бинарные данные, например видео или аудио, посмотрите расширенное руководство: [Stream Data](../advanced/stream-data.md).\n\n///\n\n## Стриминг SSE с FastAPI { #stream-sse-with-fastapi }\n\nЧтобы стримить SSE с FastAPI, используйте `yield` в своей функции-обработчике пути и укажите `response_class=EventSourceResponse`.\n\nИмпортируйте `EventSourceResponse` из `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\nКаждый возвращаемый через `yield` элемент кодируется как JSON и отправляется в поле `data:` события SSE.\n\nЕсли вы объявите тип возврата как `AsyncIterable[Item]`, FastAPI будет использовать его, чтобы выполнить **валидацию**, добавить **документацию** и **сериализовать** данные с помощью Pydantic.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip | Совет\n\nТак как Pydantic будет сериализовать это на стороне **Rust**, вы получите значительно более высокую **производительность**, чем если не объявите тип возврата.\n\n///\n\n### Несинхронные функции-обработчики пути { #non-async-path-operation-functions }\n\nВы также можете использовать обычные функции `def` (без `async`) и применять `yield` тем же образом.\n\nFastAPI проследит, чтобы выполнение прошло корректно и не блокировало цикл событий.\n\nТак как в этом случае функция не async, правильным типом возврата будет `Iterable[Item]`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### Без объявленного типа возврата { #no-return-type }\n\nВы также можете опустить тип возврата. FastAPI использует [`jsonable_encoder`](./encoder.md) для преобразования данных и их отправки.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\nЕсли вам нужно задать поля SSE, такие как `event`, `id`, `retry` или `comment`, вы можете возвращать через `yield` объекты `ServerSentEvent` вместо обычных данных.\n\nИмпортируйте `ServerSentEvent` из `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\nПоле `data` всегда кодируется как JSON. Вы можете передавать любое значение, сериализуемое в JSON, включая Pydantic-модели.\n\n## Необработанные данные { #raw-data }\n\nЕсли нужно отправлять данные без JSON-кодирования, используйте `raw_data` вместо `data`.\n\nЭто полезно для отправки заранее отформатированного текста, строк логов или специальных значений <dfn title=\"Значение, используемое для обозначения особого условия или состояния\">«сентинель»</dfn>, например `[DONE]`.\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note | Примечание\n\n`data` и `raw_data` взаимно исключают друг друга. В каждом `ServerSentEvent` можно задать только одно из них.\n\n///\n\n## Возобновление с `Last-Event-ID` { #resuming-with-last-event-id }\n\nКогда браузер переподключается после обрыва соединения, он отправляет последний полученный `id` в HTTP-заголовке `Last-Event-ID`.\n\nВы можете прочитать его как параметр заголовка и использовать, чтобы возобновить поток с того места, где клиент остановился:\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## SSE с POST { #sse-with-post }\n\nSSE работает с любым HTTP-методом, не только с `GET`.\n\nЭто полезно для таких протоколов, как [MCP](https://modelcontextprotocol.io), которые стримят SSE по `POST`:\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## Технические детали { #technical-details }\n\nFastAPI из коробки реализует некоторые лучшие практики для SSE.\n\n- Отправлять комментарий «ping» для поддержания соединения («keep alive») каждые 15 секунд, когда нет сообщений, чтобы предотвратить закрытие соединения некоторыми прокси, как рекомендовано в [HTML specification: Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes).\n- Устанавливать заголовок `Cache-Control: no-cache`, чтобы предотвратить кэширование потока.\n- Устанавливать специальный заголовок `X-Accel-Buffering: no`, чтобы предотвратить буферизацию в некоторых прокси, например Nginx.\n\nВам не нужно ничего настраивать, это работает из коробки. 🤓\n"
  },
  {
    "path": "docs/ru/docs/tutorial/sql-databases.md",
    "content": "# SQL (реляционные) базы данных { #sql-relational-databases }\n\n**FastAPI** не требует использовать SQL (реляционную) базу данных. Но вы можете использовать любую базу данных, которую хотите.\n\nЗдесь мы рассмотрим пример с использованием [SQLModel](https://sqlmodel.tiangolo.com/).\n\n**SQLModel** построен поверх [SQLAlchemy](https://www.sqlalchemy.org/) и Pydantic. Его создал тот же автор, что и **FastAPI**, чтобы он идеально подходил для приложений FastAPI, которым нужны **SQL базы данных**.\n\n/// tip | Подсказка\n\nВы можете использовать любую другую библиотеку для работы с SQL или NoSQL базами данных (иногда их называют <abbr title=\"Object Relational Mapper - Объектно-реляционный маппер: термин для библиотеки, где некоторые классы представляют SQL-таблицы, а экземпляры представляют строки в этих таблицах\">\"ORMs\"</abbr>), FastAPI ничего не навязывает. 😎\n\n///\n\nТак как SQLModel основан на SQLAlchemy, вы можете легко использовать **любую поддерживаемую** SQLAlchemy базу данных (а значит, и поддерживаемую SQLModel), например:\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server, и т.д.\n\nВ этом примере мы будем использовать **SQLite**, потому что она использует один файл и имеет встроенную поддержку в Python. Так что вы можете скопировать этот пример и запустить его как есть.\n\nПозже, для продакшн-приложения, возможно, вы захотите использовать серверную базу данных, например **PostgreSQL**.\n\n/// tip | Подсказка\n\nСуществует официальный генератор проектов на **FastAPI** и **PostgreSQL**, включающий frontend и другие инструменты: [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\nЭто очень простое и короткое руководство. Если вы хотите узнать больше о базах данных в целом, об SQL или о более продвинутых возможностях, обратитесь к [документации SQLModel](https://sqlmodel.tiangolo.com/).\n\n## Установка `SQLModel` { #install-sqlmodel }\n\nСначала убедитесь, что вы создали [виртуальное окружение](../virtual-environments.md), активировали его и затем установили `sqlmodel`:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## Создание приложения с единственной моделью { #create-the-app-with-a-single-model }\n\nСначала мы создадим самую простую первую версию приложения с одной моделью **SQLModel**.\n\nПозже мы улучшим его, повысив безопасность и универсальность, добавив **несколько моделей**. 🤓\n\n### Создание моделей { #create-models }\n\nИмпортируйте `SQLModel` и создайте модель базы данных:\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\nКласс `Hero` очень похож на модель Pydantic (фактически, под капотом, это и есть модель Pydantic).\n\nЕсть несколько отличий:\n\n* `table=True` сообщает SQLModel, что это *модель-таблица*, она должна представлять **таблицу** в SQL базе данных, это не просто *модель данных* (как обычный класс Pydantic).\n\n* `Field(primary_key=True)` сообщает SQLModel, что `id` — это **первичный ключ** в SQL базе данных (подробнее о первичных ключах SQL можно узнать в документации SQLModel).\n\n    **Примечание:** Мы используем `int | None` для поля первичного ключа, чтобы в Python-коде можно было *создать объект без `id`* (`id=None`), предполагая, что база данных *сгенерирует его при сохранении*. SQLModel понимает, что база данных предоставит `id`, и *определяет столбец как `INTEGER` (не `NULL`)* в схеме базы данных. См. [документацию SQLModel о первичных ключах](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) для подробностей.\n\n* `Field(index=True)` сообщает SQLModel, что нужно создать **SQL индекс** для этого столбца, что позволит быстрее выполнять выборки при чтении данных, отфильтрованных по этому столбцу.\n\n    SQLModel будет знать, что объявленное как `str` станет SQL-столбцом типа `TEXT` (или `VARCHAR`, в зависимости от базы данных).\n\n### Создание Engine { #create-an-engine }\n\nОбъект `engine` в SQLModel (под капотом это `engine` из SQLAlchemy) **удерживает соединения** с базой данных.\n\nУ вас должен быть **один объект `engine`** для всей кодовой базы, чтобы подключаться к одной и той же базе данных.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\nПараметр `check_same_thread=False` позволяет FastAPI использовать одну и ту же базу данных SQLite в разных потоках. Это необходимо, так как **один запрос** может использовать **больше одного потока** (например, в зависимостях).\n\nНе волнуйтесь, с такой структурой кода мы позже обеспечим использование **одной сессии SQLModel на запрос**, по сути именно этого и добивается `check_same_thread`.\n\n### Создание таблиц { #create-the-tables }\n\nДалее мы добавим функцию, которая использует `SQLModel.metadata.create_all(engine)`, чтобы **создать таблицы** для всех *моделей-таблиц*.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### Создание зависимости Session { #create-a-session-dependency }\n\n**`Session`** хранит **объекты в памяти** и отслеживает необходимые изменения в данных, затем **использует `engine`** для общения с базой данных.\n\nМы создадим **зависимость** FastAPI с `yield`, которая будет предоставлять новую `Session` для каждого запроса. Это и обеспечивает использование одной сессии на запрос. 🤓\n\nЗатем мы создадим объявленную (`Annotated`) зависимость `SessionDep`, чтобы упростить остальной код, который будет использовать эту зависимость.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### Создание таблиц базы данных при старте { #create-database-tables-on-startup }\n\nМы создадим таблицы базы данных при запуске приложения.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\nЗдесь мы создаём таблицы в обработчике события запуска приложения.\n\nДля продакшн вы, вероятно, будете использовать скрипт миграций, который выполняется до запуска приложения. 🤓\n\n/// tip | Подсказка\n\nВ SQLModel появятся утилиты миграций — обёртки над Alembic, но пока вы можете использовать [Alembic](https://alembic.sqlalchemy.org/en/latest/) напрямую.\n\n///\n\n### Создание героя (Hero) { #create-a-hero }\n\nТак как каждая модель SQLModel также является моделью Pydantic, вы можете использовать её в тех же **аннотациях типов**, в которых используете модели Pydantic.\n\nНапример, если вы объявите параметр типа `Hero`, он будет прочитан из **JSON body (тела запроса)**.\n\nАналогично вы можете объявить её как **тип возвращаемого значения** функции, и тогда форма данных отобразится в автоматически сгенерированном UI документации API.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\nЗдесь мы используем зависимость `SessionDep` (это `Session`), чтобы добавить нового `Hero` в экземпляр `Session`, зафиксировать изменения в базе данных, обновить данные в `hero` и затем вернуть его.\n\n### Чтение героев { #read-heroes }\n\nМы можем **читать** записи `Hero` из базы данных с помощью `select()`. Можно добавить `limit` и `offset` для постраничного вывода результатов.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### Чтение одного героя { #read-one-hero }\n\nМы можем **прочитать** одного `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### Удаление героя { #delete-a-hero }\n\nМы также можем **удалить** `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### Запуск приложения { #run-the-app }\n\nВы можете запустить приложение:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nЗатем перейдите в UI `/docs`. Вы увидите, что **FastAPI** использует эти **модели** для **документирования** API, а также для **сериализации** и **валидации** данных.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## Обновление приложения с несколькими моделями { #update-the-app-with-multiple-models }\n\nТеперь давайте немного **отрефакторим** приложение, чтобы повысить **безопасность** и **универсальность**.\n\nЕсли вы посмотрите на предыдущую версию, в UI видно, что до сих пор клиент мог сам задавать `id` создаваемого `Hero`. 😱\n\nТак делать нельзя, иначе они могли бы перезаписать `id`, который уже присвоен в БД. Решение по `id` должно приниматься **бэкендом** или **базой данных**, а **не клиентом**.\n\nКроме того, мы создаём для героя `secret_name`, но пока что возвращаем его повсюду — это не очень **секретно**... 😅\n\nМы исправим это, добавив несколько **дополнительных моделей**. Здесь SQLModel раскроется во всей красе. ✨\n\n### Создание нескольких моделей { #create-multiple-models }\n\nВ **SQLModel** любая модель с `table=True` — это **модель-таблица**.\n\nЛюбая модель без `table=True` — это **модель данных**, по сути обычная модель Pydantic (с парой небольших дополнений). 🤓\n\nС SQLModel мы можем использовать **наследование**, чтобы **избежать дублирования** полей.\n\n#### `HeroBase` — базовый класс { #herobase-the-base-class }\n\nНачнём с модели `HeroBase`, которая содержит **общие поля** для всех моделей:\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` — *модель-таблица* { #hero-the-table-model }\n\nДалее создадим `Hero`, фактическую *модель-таблицу*, с **дополнительными полями**, которых может не быть в других моделях:\n\n* `id`\n* `secret_name`\n\nТак как `Hero` наследуется от `HeroBase`, он **также** имеет **поля**, объявленные в `HeroBase`, поэтому все поля `Hero`:\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` — публичная *модель данных* { #heropublic-the-public-data-model }\n\nДалее мы создадим модель `HeroPublic`, именно она будет **возвращаться** клиентам API.\n\nУ неё те же поля, что и у `HeroBase`, поэтому она не включает `secret_name`.\n\nНаконец-то личность наших героев защищена! 🥷\n\nТакже здесь заново объявляется `id: int`. Тем самым мы заключаем **контракт** с клиентами API: они всегда могут рассчитывать, что поле `id` присутствует и это `int` (никогда не `None`).\n\n/// tip | Подсказка\n\nГарантия того, что в модели ответа значение всегда присутствует и это `int` (не `None`), очень полезна для клиентов API — так можно писать гораздо более простой код.\n\nКроме того, **автоматически сгенерированные клиенты** будут иметь более простые интерфейсы, и разработчикам, взаимодействующим с вашим API, будет работать значительно комфортнее. 😎\n\n///\n\nВсе поля `HeroPublic` такие же, как в `HeroBase`, а `id` объявлен как `int` (не `None`):\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` — *модель данных* для создания героя { #herocreate-the-data-model-to-create-a-hero }\n\nТеперь создадим модель `HeroCreate`, она будет **валидировать** данные от клиентов.\n\nУ неё те же поля, что и у `HeroBase`, а также есть `secret_name`.\n\nТеперь, когда клиенты **создают нового героя**, они будут отправлять `secret_name`, он сохранится в базе данных, но не будет возвращаться клиентам в API.\n\n/// tip | Подсказка\n\nТак следует обрабатывать **пароли**: принимать их, но не возвращать в API.\n\nТакже перед сохранением значения паролей нужно **хэшировать**, **никогда не храните их в открытом виде**.\n\n///\n\nПоля `HeroCreate`:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` — *модель данных* для обновления героя { #heroupdate-the-data-model-to-update-a-hero }\n\nВ предыдущей версии приложения у нас не было способа **обновлять героя**, но теперь, с **несколькими моделями**, мы можем это сделать. 🎉\n\n*Модель данных* `HeroUpdate` особенная: у неё **те же поля**, что и для создания нового героя, но все поля **необязательные** (у всех есть значение по умолчанию). Таким образом, при обновлении героя можно отправлять только те поля, которые нужно изменить.\n\nПоскольку **фактически меняются все поля** (их тип теперь включает `None`, и по умолчанию они равны `None`), нам нужно **переобъявить** их.\n\nНаследоваться от `HeroBase` не обязательно, так как мы заново объявляем все поля. Я оставлю наследование для единообразия, но это не необходимо. Скорее дело вкуса. 🤷\n\nПоля `HeroUpdate`:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### Создание с `HeroCreate` и возврат `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }\n\nТеперь, когда у нас есть **несколько моделей**, мы можем обновить части приложения, которые их используют.\n\nМы получаем в запросе *модель данных* `HeroCreate` и на её основе создаём *модель-таблицу* `Hero`.\n\nНовая *модель-таблица* `Hero` будет иметь поля, отправленные клиентом, а также `id`, сгенерированный базой данных.\n\nЗатем возвращаем из функции ту же *модель-таблицу* `Hero` как есть. Но так как мы объявили `response_model` с *моделью данных* `HeroPublic`, **FastAPI** использует `HeroPublic` для валидации и сериализации данных.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | Подсказка\n\nТеперь мы используем `response_model=HeroPublic` вместо **аннотации типа возвращаемого значения** `-> HeroPublic`, потому что фактически возвращаемое значение — это *не* `HeroPublic`.\n\nЕсли бы мы объявили `-> HeroPublic`, ваш редактор кода и линтер справедливо пожаловались бы, что вы возвращаете `Hero`, а не `HeroPublic`.\n\nОбъявляя модель в `response_model`, мы говорим **FastAPI** сделать своё дело, не вмешиваясь в аннотации типов и работу редактора кода и других инструментов.\n\n///\n\n### Чтение героев с `HeroPublic` { #read-heroes-with-heropublic }\n\nАналогично мы можем **читать** `Hero` — снова используем `response_model=list[HeroPublic]`, чтобы данные валидировались и сериализовались корректно.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### Чтение одного героя с `HeroPublic` { #read-one-hero-with-heropublic }\n\nМы можем **прочитать** одного героя:\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### Обновление героя с `HeroUpdate` { #update-a-hero-with-heroupdate }\n\nМы можем **обновить героя**. Для этого используем HTTP операцию `PATCH`.\n\nВ коде мы получаем `dict` со всеми данными, отправленными клиентом — **только с данными, отправленными клиентом**, исключая любые значения, которые были бы там лишь как значения по умолчанию. Для этого мы используем `exclude_unset=True`. Это главный трюк. 🪄\n\nЗатем мы используем `hero_db.sqlmodel_update(hero_data)`, чтобы обновить `hero_db` данными из `hero_data`.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### Снова удаление героя { #delete-a-hero-again }\n\nОперация **удаления** героя остаётся практически прежней.\n\nЖелание *«отрефакторить всё»* на этот раз останется неудовлетворённым. 😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### Снова запустим приложение { #run-the-app-again }\n\nВы можете снова запустить приложение:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nЕсли вы перейдёте в UI API `/docs`, вы увидите, что он обновился: теперь при создании героя он не ожидает получить `id` от клиента и т.д.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## Резюме { #recap }\n\nВы можете использовать [**SQLModel**](https://sqlmodel.tiangolo.com/) для взаимодействия с SQL базой данных и упростить код с помощью *моделей данных* и *моделей-таблиц*.\n\nГораздо больше вы можете узнать в документации **SQLModel**, там есть более подробное мини-[руководство по использованию SQLModel с **FastAPI**](https://sqlmodel.tiangolo.com/tutorial/fastapi/). 🚀\n"
  },
  {
    "path": "docs/ru/docs/tutorial/static-files.md",
    "content": "# Статические Файлы { #static-files }\n\nВы можете предоставлять статические файлы автоматически из директории, используя `StaticFiles`.\n\n## Использование `StaticFiles` { #use-staticfiles }\n\n* Импортируйте `StaticFiles`.\n* \"Примонтируйте\" экземпляр `StaticFiles()` к определённому пути.\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | Технические детали\n\nВы также можете использовать `from starlette.staticfiles import StaticFiles`.\n\n**FastAPI** предоставляет `starlette.staticfiles` под псевдонимом `fastapi.staticfiles`, просто для вашего удобства, как разработчика. Но на самом деле это берётся напрямую из библиотеки Starlette.\n\n///\n\n### Что такое \"Монтирование\" { #what-is-mounting }\n\n\"Монтирование\" означает добавление полноценного \"независимого\" приложения на определённый путь, которое затем обрабатывает все подпути.\n\nЭто отличается от использования `APIRouter`, так как примонтированное приложение является полностью независимым.\nOpenAPI и документация из вашего главного приложения не будут содержать ничего из примонтированного приложения, и т.д.\n\nВы можете прочитать больше об этом в [Расширенном руководстве пользователя](../advanced/index.md).\n\n## Детали { #details }\n\nПервый параметр `\"/static\"` относится к подпути, по которому это \"подприложение\" будет \"примонтировано\". Таким образом, любой путь начинающийся со `\"/static\"` будет обработан этим приложением.\n\nПараметр `directory=\"static\"` относится к имени директории, которая содержит ваши статические файлы.\n\n`name=\"static\"` даёт имя маршруту, которое может быть использовано внутри **FastAPI**.\n\nВсе эти параметры могут отличаться от \"`static`\", настройте их в соответствии с вашими нуждами и конкретными деталями вашего собственного приложения.\n\n## Больше информации { #more-info }\n\nДля получения дополнительной информации о деталях и настройках ознакомьтесь с [документацией Starlette о статических файлах](https://www.starlette.dev/staticfiles/).\n"
  },
  {
    "path": "docs/ru/docs/tutorial/stream-json-lines.md",
    "content": "# Стриминг JSON Lines { #stream-json-lines }\n\nУ вас может быть последовательность данных, которую вы хотите отправлять в «**потоке**». Это можно сделать с помощью **JSON Lines**.\n\n/// info | Информация\n\nДобавлено в FastAPI 0.134.0.\n\n///\n\n## Что такое поток? { #what-is-a-stream }\n\n«**Стриминг**» данных означает, что ваше приложение начнет отправлять элементы данных клиенту, не дожидаясь готовности всей последовательности.\n\nТо есть оно отправит первый элемент, клиент его получит и начнет обрабатывать, а вы в это время можете все еще генерировать следующий элемент.\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\nЭто может быть даже бесконечный поток, когда вы продолжаете отправлять данные.\n\n## JSON Lines { #json-lines }\n\nВ таких случаях часто отправляют «**JSON Lines**», это формат, в котором отправляется по одному JSON-объекту на строку.\n\nОтвет будет иметь тип содержимого `application/jsonl` (вместо `application/json`), а тело ответа будет примерно таким:\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\nЭто очень похоже на JSON-массив (эквивалент списка Python), но вместо того чтобы быть обернутым в `[]` и иметь `,` между элементами, здесь **один JSON-объект на строку**, они разделены символом новой строки.\n\n/// info | Информация\n\nВажный момент в том, что ваше приложение сможет по очереди производить каждую строку, пока клиент потребляет предыдущие строки.\n\n///\n\n/// note | Технические детали\n\nТак как каждый JSON-объект будет разделен новой строкой, в их содержимом не могут быть буквальные символы новой строки, но могут быть экранированные переводы строк (`\\n`), что входит в стандарт JSON.\n\nОднако обычно об этом не нужно беспокоиться — всё делается автоматически, читайте дальше. 🤓\n\n///\n\n## Варианты использования { #use-cases }\n\nВы можете использовать это для стриминга данных из сервиса **AI LLM**, из **логов** или **телеметрии**, или из других типов данных, которые можно структурировать в элементы **JSON**.\n\n/// tip | Совет\n\nЕсли вы хотите стримить бинарные данные, например видео или аудио, посмотрите расширенное руководство: [Потоковая передача данных](../advanced/stream-data.md).\n\n///\n\n## Стриминг JSON Lines с FastAPI { #stream-json-lines-with-fastapi }\n\nЧтобы стримить JSON Lines с FastAPI, вместо использования `return` в вашей *функции-обработчике пути* используйте `yield`, чтобы по очереди выдавать каждый элемент.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\nЕсли каждый JSON-элемент, который вы хотите отправить обратно, имеет тип `Item` (Pydantic-модель), и это асинхронная функция, вы можете объявить тип возвращаемого значения как `AsyncIterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\nЕсли вы объявите тип возвращаемого значения, FastAPI будет использовать его, чтобы **валидировать** данные, **документировать** их в OpenAPI, **фильтровать** и **сериализовать** с помощью Pydantic.\n\n/// tip | Совет\n\nТак как Pydantic будет сериализовывать это на стороне **Rust**, вы получите значительно более высокую **производительность**, чем если бы вы не указывали тип возвращаемого значения.\n\n///\n\n### Неасинхронные функции-обработчики пути { #non-async-path-operation-functions }\n\nВы также можете использовать обычные функции `def` (без `async`) и использовать `yield` таким же образом.\n\nFastAPI обеспечит корректное выполнение так, чтобы это не блокировало цикл событий.\n\nПоскольку в этом случае функция не асинхронная, подходящим типом возвращаемого значения будет `Iterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### Без возвращаемого типа { #no-return-type }\n\nВы также можете опустить тип возвращаемого значения. Тогда FastAPI использует [`jsonable_encoder`](./encoder.md), чтобы преобразовать данные к виду, который можно сериализовать в JSON, и затем отправит их как JSON Lines.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## События, отправляемые сервером (SSE) { #server-sent-events-sse }\n\nFastAPI также имеет полноценную поддержку Server-Sent Events (SSE), которые довольно похожи, но с парой дополнительных деталей. Вы можете узнать о них в следующей главе: [События, отправляемые сервером (SSE)](server-sent-events.md). 🤓\n"
  },
  {
    "path": "docs/ru/docs/tutorial/testing.md",
    "content": "# Тестирование { #testing }\n\nБлагодаря [Starlette](https://www.starlette.dev/testclient/), тестировать приложения **FastAPI** легко и приятно.\n\nТестирование основано на библиотеке [HTTPX](https://www.python-httpx.org), которая в свою очередь основана на библиотеке Requests, так что все действия знакомы и интуитивно понятны.\n\nИспользуя эти инструменты, Вы можете напрямую задействовать [pytest](https://docs.pytest.org/) с **FastAPI**.\n\n## Использование класса `TestClient` { #using-testclient }\n\n/// info | Информация\n\nДля использования класса `TestClient` сначала установите [`httpx`](https://www.python-httpx.org).\n\nУбедитесь, что Вы создали [виртуальное окружение](../virtual-environments.md), активировали его, а затем установили пакет, например:\n\n```console\n$ pip install httpx\n```\n\n///\n\nИмпортируйте `TestClient`.\n\nСоздайте объект `TestClient`, передав ему в качестве параметра Ваше приложение **FastAPI**.\n\nСоздайте функцию, название которой должно начинаться с `test_` (это стандарт из соглашений `pytest`).\n\nИспользуйте объект `TestClient` так же, как Вы используете `httpx`.\n\nНапишите простое утверждение с `assert` дабы проверить истинность Python-выражения (это тоже стандарт `pytest`).\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip | Подсказка\n\nОбратите внимание, что тестирующая функция является обычной `def`, а не асинхронной `async def`.\n\nИ вызов клиента также осуществляется без `await`.\n\nЭто позволяет вам использовать `pytest` без лишних усложнений.\n\n///\n\n/// note | Технические детали\n\nТакже можно написать `from starlette.testclient import TestClient`.\n\n**FastAPI** предоставляет тот же самый `starlette.testclient` как `fastapi.testclient`. Это всего лишь небольшое удобство для Вас, как разработчика. Но он берётся напрямую из Starlette.\n\n///\n\n/// tip | Подсказка\n\nЕсли для тестирования Вам, помимо запросов к приложению FastAPI, необходимо вызывать асинхронные функции (например, для подключения к базе данных с помощью асинхронного драйвера), то ознакомьтесь со страницей [Асинхронное тестирование](../advanced/async-tests.md) в расширенном руководстве.\n\n///\n\n## Разделение тестов { #separating-tests }\n\nВ реальном приложении Вы, вероятно, разместите тесты в отдельном файле.\n\nКроме того, Ваше приложение **FastAPI** может состоять из нескольких файлов, модулей и т.п.\n\n### Файл приложения **FastAPI** { #fastapi-app-file }\n\nДопустим, структура файлов Вашего приложения похожа на ту, что описана на странице [Более крупные приложения](bigger-applications.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\nВ файле `main.py` находится Ваше приложение **FastAPI**:\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### Файл тестов { #testing-file }\n\nТакже у Вас может быть файл `test_main.py` содержащий тесты. Он может находиться в том же Python-пакете (в той же директории с файлом `__init__.py`):\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nТак как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт:\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n\n...и писать дальше тесты, как и раньше.\n\n## Тестирование: расширенный пример { #testing-extended-example }\n\nТеперь давайте расширим наш пример и добавим деталей, чтоб посмотреть, как тестировать различные части приложения.\n\n### Расширенный файл приложения **FastAPI** { #extended-fastapi-app-file }\n\nМы продолжим работу с той же файловой структурой, что и ранее:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nПредположим, что в файле `main.py` с приложением **FastAPI** есть несколько **операций пути**.\n\nВ нём описана операция `GET`, которая может вернуть ошибку.\n\nЕщё есть операция `POST`, и она может вернуть несколько ошибок.\n\nОбе *операции пути* требуют наличия в запросе HTTP-заголовка `X-Token`.\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### Расширенный файл тестов { #extended-testing-file }\n\nТеперь обновим файл `test_main.py`, добавив в него тестов:\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\n\nЕсли Вы не знаете, как передать информацию в запросе, можете воспользоваться поисковиком (погуглить) и задать вопрос: \"Как передать информацию в запросе с помощью `httpx`\", можно даже спросить: \"Как передать информацию в запросе с помощью `requests`\", поскольку дизайн HTTPX основан на дизайне Requests.\n\nЗатем Вы просто применяете найденные ответы в тестах.\n\nНапример:\n\n* Передаёте *path*-параметры или *query*-параметры, вписав их непосредственно в строку URL.\n* Передаёте JSON в теле запроса, передав Python-объект (например: `dict`) через именованный параметр `json`.\n* Если же Вам необходимо отправить *форму с данными* вместо JSON, то используйте параметр `data` вместо `json`.\n* Для передачи *HTTP-заголовков*, передайте объект `dict` через параметр `headers`.\n* Для передачи *cookies* также передайте `dict`, но через параметр `cookies`.\n\nДля получения дополнительной информации о передаче данных на бэкенд с помощью `httpx` или `TestClient` ознакомьтесь с [документацией HTTPX](https://www.python-httpx.org).\n\n/// info | Информация\n\nОбратите внимание, что `TestClient` принимает данные, которые можно конвертировать в JSON, но не модели Pydantic.\n\nЕсли в Ваших тестах есть модели Pydantic и Вы хотите отправить их в тестируемое приложение, то можете использовать функцию `jsonable_encoder`, описанную на странице [Кодировщик совместимый с JSON](encoder.md).\n\n///\n\n## Запуск { #run-it }\n\nДалее Вам нужно установить `pytest`.\n\nУбедитесь, что Вы создали [виртуальное окружение](../virtual-environments.md), активировали его, а затем установили пакет, например:\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\nОн автоматически найдёт все файлы и тесты, выполнит их и предоставит Вам отчёт о результатах тестирования.\n\nЗапустите тесты:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/ru/docs/virtual-environments.md",
    "content": "# Виртуальные окружения { #virtual-environments }\n\nПри работе с проектами на Python рекомендуется использовать **виртуальное окружение** (или похожий механизм), чтобы изолировать пакеты, которые вы устанавливаете для каждого проекта.\n\n/// info | Дополнительная информация\n\nЕсли вы уже знакомы с виртуальными окружениями, знаете, как их создавать и использовать, вы можете пропустить этот раздел. 🤓\n\n///\n\n/// tip | Подсказка\n\n**Виртуальное окружение** — это не то же самое, что **переменная окружения**.\n\n**Переменная окружения** — это переменная в системе, которую могут использовать программы.\n\n**Виртуальное окружение** — это директория с файлами внутри.\n\n///\n\n/// info | Дополнительная информация\n\nНа этой странице вы узнаете, как пользоваться **виртуальными окружениями** и как они работают.\n\nЕсли вы готовы начать использовать **инструмент, который управляет всем** за вас (включая установку Python), попробуйте [uv](https://github.com/astral-sh/uv).\n\n///\n\n## Создание проекта { #create-a-project }\n\nСначала создайте директорию для вашего проекта.\n\nОбычно я создаю папку с именем `code` в моем домашнем каталоге.\n\nА внутри неё создаю отдельную директорию для каждого проекта.\n\n<div class=\"termy\">\n\n```console\n// Перейдите в домашний каталог\n$ cd\n// Создайте директорию для всех ваших проектов с кодом\n$ mkdir code\n// Перейдите в эту директорию code\n$ cd code\n// Создайте директорию для этого проекта\n$ mkdir awesome-project\n// Перейдите в директорию проекта\n$ cd awesome-project\n```\n\n</div>\n\n## Создание виртуального окружения { #create-a-virtual-environment }\n\nКогда вы начинаете работать над Python‑проектом **впервые**, создайте виртуальное окружение **<dfn title=\"есть и другие опции, но это простой ориентир\">внутри вашего проекта</dfn>**.\n\n/// tip | Подсказка\n\nДелать это нужно **один раз на проект**, не каждый раз, когда вы работаете.\n\n///\n\n//// tab | `venv`\n\nДля создания виртуального окружения вы можете использовать модуль `venv`, который поставляется вместе с Python.\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | Что делает эта команда?\n\n* `python`: использовать программу под названием `python`\n* `-m`: вызвать модуль как скрипт, далее мы укажем, какой модуль вызвать\n* `venv`: использовать модуль `venv`, который обычно устанавливается вместе с Python\n* `.venv`: создать виртуальное окружение в новой директории `.venv`\n\n///\n\n////\n\n//// tab | `uv`\n\nЕсли у вас установлен [`uv`](https://github.com/astral-sh/uv), вы можете использовать его для создания виртуального окружения.\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip | Подсказка\n\nПо умолчанию `uv` создаст виртуальное окружение в директории с именем `.venv`.\n\nНо вы можете переопределить это, передав дополнительный аргумент с именем директории.\n\n///\n\n////\n\nЭта команда создаст новое виртуальное окружение в директории `.venv`.\n\n/// details | `.venv` или другое имя?\n\nВы можете создать виртуальное окружение в другой директории, но по соглашению его называют `.venv`.\n\n///\n\n## Активация виртуального окружения { #activate-the-virtual-environment }\n\nАктивируйте новое виртуальное окружение, чтобы все команды Python и устанавливаемые пакеты использовали именно его.\n\n/// tip | Подсказка\n\nДелайте это **каждый раз**, когда вы начинаете **новую сессию терминала** для работы над проектом.\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nИли если вы используете Bash для Windows (например, [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip | Подсказка\n\nКаждый раз, когда вы устанавливаете **новый пакет** в это окружение, **активируйте** окружение снова.\n\nЭто гарантирует, что если вы используете **программу терминала (<abbr title=\"command line interface - интерфейс командной строки\">CLI</abbr>)**, установленную этим пакетом, вы будете использовать именно ту, что из вашего виртуального окружения, а не какую‑то глобально установленную, возможно другой версии, чем вам нужна.\n\n///\n\n## Проверка, что виртуальное окружение активно { #check-the-virtual-environment-is-active }\n\nПроверьте, что виртуальное окружение активно (предыдущая команда сработала).\n\n/// tip | Подсказка\n\nЭто **необязательно**, но это хороший способ **проверить**, что всё работает как ожидается и вы используете запланированное виртуальное окружение.\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\nЕсли отображается исполняемый файл `python` по пути `.venv/bin/python` внутри вашего проекта (в нашем случае `awesome-project`), значит всё сработало. 🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\nЕсли отображается исполняемый файл `python` по пути `.venv\\Scripts\\python` внутри вашего проекта (в нашем случае `awesome-project`), значит всё сработало. 🎉\n\n////\n\n## Обновление `pip` { #upgrade-pip }\n\n/// tip | Подсказка\n\nЕсли вы используете [`uv`](https://github.com/astral-sh/uv), то для установки вы будете использовать его вместо `pip`, поэтому обновлять `pip` не нужно. 😎\n\n///\n\nЕсли для установки пакетов вы используете `pip` (он идёт по умолчанию вместе с Python), вам стоит **обновить** его до последней версии.\n\nМногие экзотические ошибки при установке пакетов решаются простым предварительным обновлением `pip`.\n\n/// tip | Подсказка\n\nОбычно это делается **один раз**, сразу после создания виртуального окружения.\n\n///\n\nУбедитесь, что виртуальное окружение активно (см. команду выше) и запустите:\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip | Подсказка\n\nИногда при попытке обновить pip вы можете получить ошибку **`No module named pip`**.\n\nЕсли это произошло, установите и обновите pip с помощью команды ниже:\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\nЭта команда установит pip, если он ещё не установлен, а также гарантирует, что установленная версия pip будет не старее, чем версия, доступная в `ensurepip`.\n\n///\n\n## Добавление `.gitignore` { #add-gitignore }\n\nЕсли вы используете **Git** (а вам стоит его использовать), добавьте файл `.gitignore`, чтобы исключить из Git всё, что находится в вашей `.venv`.\n\n/// tip | Подсказка\n\nЕсли вы использовали [`uv`](https://github.com/astral-sh/uv) для создания виртуального окружения, он уже сделал это за вас — можно пропустить этот шаг. 😎\n\n///\n\n/// tip | Подсказка\n\nСделайте это **один раз**, сразу после создания виртуального окружения.\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | Что делает эта команда?\n\n* `echo \"*\"`: «напечатать» в терминале текст `*` (следующая часть немного меняет поведение)\n* `>`: всё, что команда слева от `>` выводит в терминал, вместо печати нужно записать в файл, указанный справа от `>`\n* `.gitignore`: имя файла, в который нужно записать текст\n\nА `*` в Git означает «всё». То есть будет игнорироваться всё в директории `.venv`.\n\nЭта команда создаст файл `.gitignore` со следующим содержимым:\n\n```gitignore\n*\n```\n\n///\n\n## Установка пакетов { #install-packages }\n\nПосле активации окружения вы можете устанавливать в него пакеты.\n\n/// tip | Подсказка\n\nСделайте это **один раз** при установке или обновлении пакетов, необходимых вашему проекту.\n\nЕсли вам нужно обновить версию или добавить новый пакет, вы **сделаете это снова**.\n\n///\n\n### Установка пакетов напрямую { #install-packages-directly }\n\nЕсли вы торопитесь и не хотите объявлять зависимости проекта в отдельном файле, вы можете установить их напрямую.\n\n/// tip | Подсказка\n\nОчень хорошая идея — указать используемые вашим проектом пакеты и их версии в файле (например, `requirements.txt` или `pyproject.toml`).\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nЕсли у вас установлен [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### Установка из `requirements.txt` { #install-from-requirements-txt }\n\nЕсли у вас есть `requirements.txt`, вы можете использовать его для установки пакетов.\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nЕсли у вас установлен [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\n`requirements.txt` с некоторыми пакетами может выглядеть так:\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## Запуск вашей программы { #run-your-program }\n\nПосле активации виртуального окружения вы можете запустить свою программу, и она будет использовать Python из вашего виртуального окружения вместе с установленными там пакетами.\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## Настройка вашего редактора кода { #configure-your-editor }\n\nСкорее всего, вы будете использовать редактор кода. Убедитесь, что вы настроили его на использование того же виртуального окружения, которое вы создали (обычно он определяет его автоматически), чтобы получить автозавершение и подсветку ошибок.\n\nНапример:\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip | Подсказка\n\nОбычно это нужно сделать только **один раз**, при создании виртуального окружения.\n\n///\n\n## Деактивация виртуального окружения { #deactivate-the-virtual-environment }\n\nКогда закончите работу над проектом, вы можете **деактивировать** виртуальное окружение.\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\nТаким образом, при запуске `python` он не будет пытаться запускаться из этого виртуального окружения с установленными там пакетами.\n\n## Готово к работе { #ready-to-work }\n\nТеперь вы готовы начать работать над своим проектом.\n\n\n\n/// tip | Подсказка\n\nХотите понять, что это всё было выше?\n\nПродолжайте читать. 👇🤓\n\n///\n\n## Зачем нужны виртуальные окружения { #why-virtual-environments }\n\nЧтобы работать с FastAPI, вам нужно установить [Python](https://www.python.org/).\n\nПосле этого вам нужно будет **установить** FastAPI и другие **пакеты**, которые вы хотите использовать.\n\nДля установки пакетов обычно используют команду `pip`, которая идет вместе с Python (или альтернативные инструменты).\n\nТем не менее, если просто использовать `pip` напрямую, пакеты будут установлены в **глобальное окружение Python** (глобально установленный Python).\n\n### Проблема { #the-problem }\n\nТак в чём проблема установки пакетов в глобальное окружение Python?\n\nСо временем вы, вероятно, будете писать много разных программ, зависящих от **разных пакетов**. И некоторые из ваших проектов будут зависеть от **разных версий** одного и того же пакета. 😱\n\nНапример, вы можете создать проект `philosophers-stone`, который зависит от пакета **`harry` версии `1`**. Значит, нужно установить `harry`.\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n\nЗатем вы создаёте другой проект `prisoner-of-azkaban`, который тоже зависит от `harry`, но ему нужен **`harry` версии `3`**.\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]\n```\n\nПроблема в том, что если устанавливать пакеты глобально (в глобальное окружение), а не в локальное **виртуальное окружение**, вам придётся выбирать, какую версию `harry` установить.\n\nЕсли вы хотите запустить `philosophers-stone`, сначала нужно установить `harry` версии `1`, например так:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\nТогда у вас в глобальном окружении Python будет установлен `harry` версии `1`:\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\nНо если затем вы захотите запустить `prisoner-of-azkaban`, вам нужно будет удалить `harry` версии `1` и установить `harry` версии `3` (или просто установка версии `3` автоматически удалит версию `1`).\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\nВ итоге у вас будет установлен `harry` версии `3` в глобальном окружении Python.\n\nА если вы снова попробуете запустить `philosophers-stone`, есть шанс, что он **не будет работать**, так как ему нужен `harry` версии `1`.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --> |requires| harry-3\n    end\n```\n\n/// tip | Подсказка\n\nВ Python-пакетах часто стараются изо всех сил **избегать ломающих изменений** в **новых версиях**, но лучше действовать осторожно: устанавливать новые версии осознанно и тогда, когда вы можете прогнать тесты и убедиться, что всё работает корректно.\n\n///\n\nТеперь представьте то же самое с **многими** другими **пакетами**, от которых зависят все ваши **проекты**. Этим очень сложно управлять. И вы, скорее всего, в какой‑то момент будете запускать проекты с **несовместимыми версиями** пакетов и не понимать, почему что‑то не работает.\n\nКроме того, в зависимости от ОС (например, Linux, Windows, macOS), она может поставляться с уже установленным Python. И тогда, вероятно, в системе уже есть предустановленные пакеты определённых версий, **нужные вашей системе**. Если вы устанавливаете пакеты в глобальное окружение Python, вы можете в итоге **сломать** некоторые системные программы.\n\n## Куда устанавливаются пакеты { #where-are-packages-installed }\n\nКогда вы устанавливаете Python, на вашем компьютере создаются некоторые директории с файлами.\n\nЧасть этих директорий отвечает за хранение всех устанавливаемых вами пакетов.\n\nКогда вы запускаете:\n\n<div class=\"termy\">\n\n```console\n// Не запускайте это сейчас, это просто пример 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\nБудет загружен сжатый файл с кодом FastAPI, обычно с [PyPI](https://pypi.org/project/fastapi/).\n\nТакже будут **загружены** файлы для других пакетов, от которых зависит FastAPI.\n\nЗатем все эти файлы будут **распакованы** и помещены в директорию на вашем компьютере.\n\nПо умолчанию они попадут в директорию из вашей установки Python — это **глобальное окружение**.\n\n## Что такое виртуальные окружения { #what-are-virtual-environments }\n\nРешение проблемы с пакетами в глобальном окружении — использовать **виртуальное окружение для каждого проекта**, над которым вы работаете.\n\nВиртуальное окружение — это **директория**, очень похожая на глобальную, куда вы можете устанавливать пакеты для конкретного проекта.\n\nТаким образом, у каждого проекта будет своё виртуальное окружение (директория `.venv`) со своими пакетами.\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) --->|requires| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --->|requires| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## Что означает активация виртуального окружения { #what-does-activating-a-virtual-environment-mean }\n\nКогда вы активируете виртуальное окружение, например так:\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nИли если вы используете Bash для Windows (например, [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\nЭта команда создаст или изменит некоторые [переменные окружения](environment-variables.md), которые будут доступны для следующих команд.\n\nОдна из таких переменных — `PATH`.\n\n/// tip | Подсказка\n\nВы можете узнать больше о переменной окружения `PATH` в разделе [Переменные окружения](environment-variables.md#path-environment-variable).\n\n///\n\nАктивация виртуального окружения добавляет его путь `.venv/bin` (на Linux и macOS) или `.venv\\Scripts` (на Windows) в переменную окружения `PATH`.\n\nПредположим, что до активации окружения переменная `PATH` выглядела так:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nЭто означает, что система будет искать программы в:\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\nЭто означает, что система будет искать программы в:\n\n* `C:\\Windows\\System32`\n\n////\n\nПосле активации виртуального окружения переменная `PATH` будет выглядеть примерно так:\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nЭто означает, что теперь система в первую очередь будет искать программы в:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\nпрежде чем искать в других директориях.\n\nПоэтому, когда вы введёте в терминале `python`, система найдёт программу Python по пути\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\nи использует именно её.\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\nЭто означает, что теперь система в первую очередь будет искать программы в:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\nпрежде чем искать в других директориях.\n\nПоэтому, когда вы введёте в терминале `python`, система найдёт программу Python по пути\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\nи использует именно её.\n\n////\n\nВажная деталь: путь к виртуальному окружению будет добавлен в самое **начало** переменной `PATH`. Система найдёт его **раньше**, чем любой другой установленный Python. Таким образом, при запуске `python` будет использоваться Python **из виртуального окружения**, а не какой‑то другой `python` (например, из глобального окружения).\n\nАктивация виртуального окружения также меняет ещё несколько вещей, но это — одна из важнейших.\n\n## Проверка виртуального окружения { #checking-a-virtual-environment }\n\nКогда вы проверяете, активно ли виртуальное окружение, например, так:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\nЭто означает, что будет использоваться программа `python` **из виртуального окружения**.\n\nНа Linux и macOS используется `which`, а в Windows PowerShell — `Get-Command`.\n\nКак работает эта команда: она проходит по переменной окружения `PATH`, идя **по каждому пути по порядку**, и ищет программу с именем `python`. Как только находит — **показывает путь** к этой программе.\n\nСамое важное — при вызове `python` именно этот «`python`» и будет выполняться.\n\nТак вы можете подтвердить, что находитесь в правильном виртуальном окружении.\n\n/// tip | Подсказка\n\nЛегко активировать одно виртуальное окружение, получить один Python, а затем **перейти к другому проекту**.\n\nИ второй проект **не будет работать**, потому что вы используете **не тот Python**, из виртуального окружения другого проекта.\n\nПолезно уметь проверить, какой именно `python` используется. 🤓\n\n///\n\n## Зачем деактивировать виртуальное окружение { #why-deactivate-a-virtual-environment }\n\nНапример, вы работаете над проектом `philosophers-stone`, **активируете виртуальное окружение**, устанавливаете пакеты и работаете с ним.\n\nЗатем вы хотите поработать над **другим проектом** `prisoner-of-azkaban`.\n\nВы переходите в этот проект:\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\nЕсли вы не деактивируете виртуальное окружение `philosophers-stone`, при запуске `python` в терминале он попытается использовать Python из `philosophers-stone`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// Error importing sirius, it's not installed 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\nНо если вы деактивируете виртуальное окружение и активируете новое для `prisoner-of-askaban`, тогда при запуске `python` он будет использовать Python из виртуального окружения `prisoner-of-azkaban`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// Вам не нужно находиться в старой директории, чтобы деактивировать окружение, вы можете сделать это где угодно, даже после перехода в другой проект 😎\n$ deactivate\n\n// Активируйте виртуальное окружение в prisoner-of-azkaban/.venv 🚀\n$ source .venv/bin/activate\n\n// Теперь при запуске python он найдёт пакет sirius, установленный в этом виртуальном окружении ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## Альтернативы { #alternatives }\n\nЭто простое руководство, чтобы вы начали и поняли, как всё работает **под капотом**.\n\nСуществует много **альтернатив** для управления виртуальными окружениями, зависимостями (requirements), проектами.\n\nКогда вы будете готовы и захотите использовать инструмент для **управления всем проектом** — зависимостями пакетов, виртуальными окружениями и т.п., я бы предложил попробовать [uv](https://github.com/astral-sh/uv).\n\n`uv` может многое:\n\n* **Устанавливать Python**, включая разные версии\n* Управлять **виртуальным окружением** ваших проектов\n* Устанавливать **пакеты**\n* Управлять **зависимостями и версиями** пакетов вашего проекта\n* Обеспечивать наличие **точного** набора пакетов и версий к установке, включая их зависимости, чтобы вы были уверены, что сможете запускать проект в продакшн точно так же, как и на компьютере при разработке — это называется **locking**\n* И многое другое\n\n## Заключение { #conclusion }\n\nЕсли вы прочитали и поняли всё это, теперь **вы знаете гораздо больше** о виртуальных окружениях, чем многие разработчики. 🤓\n\nЗнание этих деталей, скорее всего, пригодится вам в будущем, когда вы будете отлаживать что‑то сложное: вы будете понимать, **как всё работает под капотом**. 😎\n"
  },
  {
    "path": "docs/ru/llm-prompt.md",
    "content": "Translate to Russian (русский язык).\n\nLanguage code: ru.\n\n---\n\nUse a neutral tone (not overly formal or informal).\n\nUse correct Russian grammar — appropriate cases, suffixes, and endings depending on context.\n\nFor the following technical terms, use these specific translations to ensure consistency and clarity across the documentation:\n\n* production (meaning production software or environment): продакшн (do not change the ending, for example, translate `in production` as `в продакшн` (not `в продакшене`))\n* completion (meaning code auto-completion): автозавершение\n* editor (meaning component of IDE): редактор кода\n* adopt (meaning start to use): использовать (or `начать использовать`)\n* headers (meaning HTTP-headers): HTTP-заголовки\n* cookie sessions: сессии с использованием cookie\n* tested (adjective): протестированный\n* middleware: middleware (don't translate, but add `промежуточный слой` if clarification is needed)\n* path operation: операция пути (optionally clarify as `обработчик пути`)\n* path operation function: функция-обработчик пути (or `функция обработки пути`)\n* proprietary: проприетарный\n* benchmark: бенчмарк (add (`тест производительности`) if clarification is needed or use just `тест производительности`)\n* ASGI server: ASGI-сервер\n* In a hurry? : Нет времени?\n* response status code: статус-код ответа\n* HTTP status code: HTTP статус-код\n* issue (meaning GitHub issue): Issue (add `тикет\\обращение` if clarification is needed)\n* PR (meaning GitHub pull request): пулл-реквест (add `запрос на изменение` if clarification is needed)\n* run (meaning run the code): запустить (or `прогнать` if it's about testing the program)\n* to reach users: донести до пользователей (or `привлечь внимание пользователей` in the promotion context)\n* body (meaning HTTP request body): тело запроса\n* body (meaning HTTP response body): тело ответа\n* body parameter : body-параметр (or `параметр тела запроса`)\n* validate: валидировать (or `выполнить валидацию`)\n* requirements (meaning dependencies): зависимости\n* auto-reload: авто-перезагрузка (or `перезагрузить автоматически` if used as a verb)\n* show (meaning show on the screen): отобразить\n* parsing (noun): парсинг\n* origin (in web development): origin (add `источник` if clarification is needed)\n* include: включать (add `в себя` if it's appropriate, or use `содержать` as an alternative)\n* virtual environment: виртуальное окружение\n* framework: фреймворк\n* path paremeter: path-параметр\n* path (as in URL path): путь\n* form (as in HTML form): форма\n* media type: тип содержимого (or `медиа-тип`)\n* request: HTTP-запрос\n* response: HTTP-ответ\n* type hints: аннотации типов\n* type annotations: аннотации типов\n* context manager: менеджер контекста\n* code base: кодовая база\n* instantiate: создать экземпляр (avoid \"инстанцировать\")\n* load balancer: балансировщик нагрузки\n* load balance: балансировка нагрузки\n* worker process: воркер-процесс (or `процесс воркера`)\n* worker: воркер\n* lifespan: lifespan (do not translate when it's about lifespan events, but translate as `жизненный цикл` or `срок жизни` in other cases)\n* mount (verb): монтировать\n* mount (noun): точка монтирования / mount (keep in English if it's a FastAPI keyword)\n* plugin: плагин\n* plug-in: плагин\n* full stack: full stack (do not translate)\n* full-stack: full-stack (do not translate)\n* loop (as in async loop): цикл событий\n* Machine Learning: Машинное обучение\n* Deep Learning: Глубокое обучение\n* callback hell: callback hell (clarify as `ад обратных вызовов`)\n* on the fly: на лету\n* scratch the surface: поверхностно ознакомиться\n* tip: совет (or `подсказка` depending on context)\n* Pydantic model: Pydantic-модель (`модель Pydantic` and `Pydantic модель` are also fine)\n* declare: объявить\n* have the next best performance, after: быть на следующем месте по производительности после\n* timing attack: тайминговая атака (clarify `атака по времени` if needed)\n* OAuth2 scope: OAuth2 scope (clarify `область` if needed)\n* TLS Termination Proxy: прокси-сервер TSL-терминации\n* utilize (resources): использовать\n* сontent: содержимое (or `контент`)\n* raise exception: вызвать исключение (also possible to use `сгенерировать исключение` or `выбросить исключение`)\n* password flow: password flow (clarify as `аутентификация по паролю` if needed)\n* tutorial: руководство (or `учебник`)\n* too long; didn't read: слишком длинно; не читал\n* proxy with a stripped path prefix: прокси с функцией удаления префикса пути\n* nerd: умник\n* sub application: подприложение\n* webhook request: вебхук-запрос\n* serve (meaning providing access to something): «отдавать» (or `предоставлять доступ к`)\n* recap (noun): резюме\n* utility function: вспомогательная функция\n* fast to code: позволяет быстро писать код\n* Tutorial - User Guide: Учебник - Руководство пользователя\n* submodule: подмодуль\n* subpackage: подпакет\n* router: роутер\n* building, deploying, accessing (when describing features of FastAPI Cloud): созданиe образа, развертывание и доступ\n* type checker tool: инструмент проверки типов\n\nDo not add whitespace in `т.д.`, `т.п.`.\n"
  },
  {
    "path": "docs/ru/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs/tr/docs/_llm-test.md",
    "content": "# LLM test dosyası { #llm-test-file }\n\nBu doküman, dokümantasyonu çeviren <abbr title=\"Large Language Model\">LLM</abbr>'nin `scripts/translate.py` içindeki `general_prompt`'u ve `docs/{language code}/llm-prompt.md` içindeki dile özel prompt'u anlayıp anlamadığını test eder. Dile özel prompt, `general_prompt`'a eklenir.\n\nBuraya eklenen testler, dile özel prompt'ları tasarlayan herkes tarafından görülecektir.\n\nŞu şekilde kullanın:\n\n* Dile özel bir prompt bulundurun: `docs/{language code}/llm-prompt.md`.\n* Bu dokümanın hedeflediğiniz dile sıfırdan yeni bir çevirisini yapın (örneğin `translate.py` içindeki `translate-page` komutu). Bu, çeviriyi `docs/{language code}/docs/_llm-test.md` altında oluşturur.\n* Çeviride her şeyin yolunda olup olmadığını kontrol edin.\n* Gerekirse dile özel prompt'u, genel prompt'u veya İngilizce dokümanı iyileştirin.\n* Ardından çeviride kalan sorunları elle düzeltin; böylece iyi bir çeviri elde edin.\n* İyi çeviri yerindeyken yeniden çeviri yapın. İdeal sonuç, LLM'nin artık çeviride hiçbir değişiklik yapmamasıdır. Bu da genel prompt'un ve dile özel prompt'un olabilecek en iyi hâle geldiği anlamına gelir (bazen rastgele gibi görünen birkaç değişiklik yapabilir; çünkü [LLM'ler deterministik algoritmalar değildir](https://doublespeak.chat/#/handbook#deterministic-output)).\n\nTestler:\n\n## Code snippets { #code-snippets }\n\n//// tab | Test\n\nBu bir code snippet: `foo`. Bu da başka bir code snippet: `bar`. Bir tane daha: `baz quux`.\n\n////\n\n//// tab | Bilgi\n\nCode snippet'lerin içeriği olduğu gibi bırakılmalıdır.\n\n`scripts/translate.py` içindeki genel prompt'ta `### Content of code snippets` bölümüne bakın.\n\n////\n\n## Alıntılar { #quotes }\n\n//// tab | Test\n\nDün bir arkadaşım şunu yazdı: \"If you spell incorrectly correctly, you have spelled it incorrectly\". Ben de şunu yanıtladım: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\".\n\n/// note | Not\n\nLLM muhtemelen bunu yanlış çevirecektir. Yeniden çeviri yapıldığında düzeltilmiş çeviriyi koruyup korumadığı önemlidir.\n\n///\n\n////\n\n//// tab | Bilgi\n\nPrompt tasarlayan kişi, düz tırnakları tipografik tırnaklara dönüştürüp dönüştürmemeyi seçebilir. Olduğu gibi bırakmak da uygundur.\n\nÖrneğin `docs/de/llm-prompt.md` içindeki `### Quotes` bölümüne bakın.\n\n////\n\n## Code snippet'lerde alıntılar { #quotes-in-code-snippets }\n\n//// tab | Test\n\n`pip install \"foo[bar]\"`\n\nCode snippet'lerde string literal örnekleri: `\"this\"`, `'that'`.\n\nCode snippet'lerde string literal için zor bir örnek: `f\"I like {'oranges' if orange else \"apples\"}\"`\n\nHardcore: `Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | Bilgi\n\n... Ancak code snippet'lerin içindeki tırnaklar olduğu gibi kalmalıdır.\n\n////\n\n## Code block'lar { #code-blocks }\n\n//// tab | Test\n\nBir Bash code örneği...\n\n```bash\n# Evrene bir selam yazdır\necho \"Hello universe\"\n```\n\n...ve bir console code örneği...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n...ve bir başka console code örneği...\n\n```console\n// \"Code\" adında bir dizin oluştur\n$ mkdir code\n// O dizine geç\n$ cd code\n```\n\n...ve bir Python code örneği...\n\n```Python\nwont_work()  # Bu çalışmayacak 😱\nworks(foo=\"bar\")  # Bu çalışır 🎉\n```\n\n...ve hepsi bu.\n\n////\n\n//// tab | Bilgi\n\nCode block'ların içindeki code değiştirilmemelidir; tek istisna yorumlardır (comments).\n\n`scripts/translate.py` içindeki genel prompt'ta `### Content of code blocks` bölümüne bakın.\n\n////\n\n## Sekmeler ve renkli kutular { #tabs-and-colored-boxes }\n\n//// tab | Test\n\n/// info | Bilgi\nBazı metin\n///\n\n/// note | Not\nBazı metin\n///\n\n/// note | Teknik Detaylar\nBazı metin\n///\n\n/// check | Ek bilgi\nBazı metin\n///\n\n/// tip | İpucu\nBazı metin\n///\n\n/// warning | Uyarı\nBazı metin\n///\n\n/// danger | Tehlike\nBazı metin\n///\n\n////\n\n//// tab | Bilgi\n\nSekmelerin ve `Info`/`Note`/`Warning`/vb. blokların başlığı, dikey çizgiden (`|`) sonra çeviri olarak eklenmelidir.\n\n`scripts/translate.py` içindeki genel prompt'ta `### Special blocks` ve `### Tab blocks` bölümlerine bakın.\n\n////\n\n## Web ve internal link'ler { #web-and-internal-links }\n\n//// tab | Test\n\nLink metni çevrilmelidir, link adresi değişmeden kalmalıdır:\n\n* [Yukarıdaki başlığa link](#code-snippets)\n* [Dahili link](index.md#installation)\n* [Harici link](https://sqlmodel.tiangolo.com/)\n* [Bir stile bağlantı](https://fastapi.tiangolo.com/css/styles.css)\n* [Bir betiğe bağlantı](https://fastapi.tiangolo.com/js/logic.js)\n* [Bir görsele bağlantı](https://fastapi.tiangolo.com/img/foo.jpg)\n\nLink metni çevrilmelidir, link adresi çeviriye işaret etmelidir:\n\n* [FastAPI link](https://fastapi.tiangolo.com/tr/)\n\n////\n\n//// tab | Bilgi\n\nLink'ler çevrilmelidir, ancak adresleri değişmeden kalmalıdır. Bir istisna, FastAPI dokümantasyonunun sayfalarına verilen mutlak link'lerdir. Bu durumda link, çeviriye işaret etmelidir.\n\n`scripts/translate.py` içindeki genel prompt'ta `### Links` bölümüne bakın.\n\n////\n\n## HTML \"abbr\" öğeleri { #html-abbr-elements }\n\n//// tab | Test\n\nBurada HTML \"abbr\" öğeleriyle sarılmış bazı şeyler var (bazıları uydurma):\n\n### abbr tam bir ifade verir { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done - İşleri Bitirme\">GTD</abbr>\n* <abbr title=\"less than - küçüktür\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface - Paralel Sunucu Gateway Interface\">PSGI</abbr>\n\n### abbr tam bir ifade ve bir açıklama verir { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network - Mozilla Geliştirici Ağı: geliştiriciler için dokümantasyon, Firefox ekibi tarafından yazılmış\">MDN</abbr>\n* <abbr title=\"Input/Output - Girdi/Çıktı: disk okuma ya da yazma, ağ iletişimi.\">I/O</abbr>.\n\n////\n\n//// tab | Bilgi\n\n\"abbr\" öğelerinin \"title\" attribute'ları belirli talimatlara göre çevrilir.\n\nÇeviriler, LLM'nin kaldırmaması gereken kendi \"abbr\" öğelerini ekleyebilir. Örneğin İngilizce kelimeleri açıklamak için.\n\n`scripts/translate.py` içindeki genel prompt'ta `### HTML abbr elements` bölümüne bakın.\n\n////\n\n## HTML \"dfn\" öğeleri { #html-dfn-elements }\n\n* <dfn title=\"Bir şekilde birbirine bağlanacak ve birlikte çalışacak şekilde yapılandırılmış makinelerden oluşan bir grup.\">küme</dfn>\n* <dfn title=\"Girdi ve çıktı katmanları arasında çok sayıda gizli katman içeren yapay sinir ağlarını kullanan; böylece kapsamlı bir iç yapı geliştiren bir makine öğrenmesi yöntemi\">Derin Öğrenme</dfn>\n\n## Başlıklar { #headings }\n\n//// tab | Test\n\n### Bir web uygulaması geliştirin - bir öğretici { #develop-a-webapp-a-tutorial }\n\nMerhaba.\n\n### Type hint'ler ve -annotation'lar { #type-hints-and-annotations }\n\nTekrar merhaba.\n\n### Super- ve subclass'lar { #super-and-subclasses }\n\nTekrar merhaba.\n\n////\n\n//// tab | Bilgi\n\nBaşlıklarla ilgili tek katı kural, LLM'nin süslü parantezler içindeki hash kısmını değiştirmemesidir; böylece link'ler bozulmaz.\n\n`scripts/translate.py` içindeki genel prompt'ta `### Headings` bölümüne bakın.\n\nDile özel bazı talimatlar için örneğin `docs/de/llm-prompt.md` içindeki `### Headings` bölümüne bakın.\n\n////\n\n## Dokümanlarda kullanılan terimler { #terms-used-in-the-docs }\n\n//// tab | Test\n\n* siz\n* sizin\n\n* örn.\n* vb.\n\n* `foo` bir `int` olarak\n* `bar` bir `str` olarak\n* `baz` bir `list` olarak\n\n* Tutorial - Kullanıcı kılavuzu\n* İleri Düzey Kullanıcı Kılavuzu\n* SQLModel dokümanları\n* API dokümanları\n* otomatik dokümanlar\n\n* Veri Bilimi\n* Deep Learning\n* Machine Learning\n* Dependency Injection\n* HTTP Basic authentication\n* HTTP Digest\n* ISO formatı\n* JSON Schema standardı\n* JSON schema\n* schema tanımı\n* Password Flow\n* Mobil\n\n* deprecated\n* designed\n* invalid\n* on the fly\n* standard\n* default\n* case-sensitive\n* case-insensitive\n\n* uygulamayı serve etmek\n* sayfayı serve etmek\n\n* app\n* application\n\n* request\n* response\n* error response\n\n* path operation\n* path operation decorator\n* path operation function\n\n* body\n* request body\n* response body\n* JSON body\n* form body\n* file body\n* function body\n\n* parameter\n* body parameter\n* path parameter\n* query parameter\n* cookie parameter\n* header parameter\n* form parameter\n* function parameter\n\n* event\n* startup event\n* server'ın startup'ı\n* shutdown event\n* lifespan event\n\n* handler\n* event handler\n* exception handler\n* handle etmek\n\n* model\n* Pydantic model\n* data model\n* database model\n* form model\n* model object\n\n* class\n* base class\n* parent class\n* subclass\n* child class\n* sibling class\n* class method\n\n* header\n* headers\n* authorization header\n* `Authorization` header\n* forwarded header\n\n* dependency injection system\n* dependency\n* dependable\n* dependant\n\n* I/O bound\n* CPU bound\n* concurrency\n* parallelism\n* multiprocessing\n\n* env var\n* environment variable\n* `PATH`\n* `PATH` variable\n\n* authentication\n* authentication provider\n* authorization\n* authorization form\n* authorization provider\n* kullanıcı authenticate olur\n* sistem kullanıcıyı authenticate eder\n\n* CLI\n* command line interface\n\n* server\n* client\n\n* cloud provider\n* cloud service\n\n* geliştirme\n* geliştirme aşamaları\n\n* dict\n* dictionary\n* enumeration\n* enum\n* enum member\n\n* encoder\n* decoder\n* encode etmek\n* decode etmek\n\n* exception\n* raise etmek\n\n* expression\n* statement\n\n* frontend\n* backend\n\n* GitHub discussion\n* GitHub issue\n\n* performance\n* performance optimization\n\n* return type\n* return value\n\n* security\n* security scheme\n\n* task\n* background task\n* task function\n\n* template\n* template engine\n\n* type annotation\n* type hint\n\n* server worker\n* Uvicorn worker\n* Gunicorn Worker\n* worker process\n* worker class\n* workload\n\n* deployment\n* deploy etmek\n\n* SDK\n* software development kit\n\n* `APIRouter`\n* `requirements.txt`\n* Bearer Token\n* breaking change\n* bug\n* button\n* callable\n* code\n* commit\n* context manager\n* coroutine\n* database session\n* disk\n* domain\n* engine\n* fake X\n* HTTP GET method\n* item\n* library\n* lifespan\n* lock\n* middleware\n* mobile application\n* module\n* mounting\n* network\n* origin\n* override\n* payload\n* processor\n* property\n* proxy\n* pull request\n* query\n* RAM\n* remote machine\n* status code\n* string\n* tag\n* web framework\n* wildcard\n* return etmek\n* validate etmek\n\n////\n\n//// tab | Bilgi\n\nBu, dokümanlarda görülen (çoğunlukla) teknik terimlerin eksiksiz ve normatif olmayan bir listesidir. Prompt tasarlayan kişi için, LLM'nin hangi terimlerde desteğe ihtiyaç duyduğunu anlamada yardımcı olabilir. Örneğin iyi bir çeviriyi sürekli daha zayıf bir çeviriye geri alıyorsa. Ya da sizin dilinizde bir terimi çekimlemekte (conjugating/declinating) zorlanıyorsa.\n\nÖrneğin `docs/de/llm-prompt.md` içindeki `### List of English terms and their preferred German translations` bölümüne bakın.\n\n////\n"
  },
  {
    "path": "docs/tr/docs/about/index.md",
    "content": "# Hakkında { #about }\n\nFastAPI, tasarımı, ilham kaynağı ve daha fazlası hakkında. 🤓\n"
  },
  {
    "path": "docs/tr/docs/advanced/additional-responses.md",
    "content": "# OpenAPI'de Ek Response'lar { #additional-responses-in-openapi }\n\n/// warning | Uyarı\n\nBu konu oldukça ileri seviye bir konudur.\n\n**FastAPI**'ye yeni başlıyorsanız buna ihtiyaç duymayabilirsiniz.\n\n///\n\nEk status code'lar, media type'lar, açıklamalar vb. ile ek response'lar tanımlayabilirsiniz.\n\nBu ek response'lar OpenAPI şemasına dahil edilir; dolayısıyla API dokümanlarında da görünürler.\n\nAncak bu ek response'lar için, status code'unuzu ve içeriğinizi vererek `JSONResponse` gibi bir `Response`'u doğrudan döndürdüğünüzden emin olmanız gerekir.\n\n## `model` ile Ek Response { #additional-response-with-model }\n\n*Path operation decorator*'larınıza `responses` adlı bir parametre geçebilirsiniz.\n\nBu parametre bir `dict` alır: anahtarlar her response için status code'lardır (`200` gibi), değerler ise her birine ait bilgileri içeren başka `dict`'lerdir.\n\nBu response `dict`'lerinin her birinde, `response_model`'e benzer şekilde bir Pydantic model içeren `model` anahtarı olabilir.\n\n**FastAPI** bu modeli alır, JSON Schema'sını üretir ve OpenAPI'de doğru yere ekler.\n\nÖrneğin, `404` status code'u ve `Message` Pydantic model'i ile başka bir response tanımlamak için şunu yazabilirsiniz:\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | Not\n\n`JSONResponse`'u doğrudan döndürmeniz gerektiğini unutmayın.\n\n///\n\n/// info | Bilgi\n\n`model` anahtarı OpenAPI'nin bir parçası değildir.\n\n**FastAPI** buradaki Pydantic model'i alır, JSON Schema'yı üretir ve doğru yere yerleştirir.\n\nDoğru yer şurasıdır:\n\n* Değeri başka bir JSON nesnesi (`dict`) olan `content` anahtarının içinde:\n    * Media type anahtarı (örn. `application/json`) bulunur; bunun değeri başka bir JSON nesnesidir ve onun içinde:\n        * Değeri model'den gelen JSON Schema olan `schema` anahtarı vardır; doğru yer burasıdır.\n            * **FastAPI** bunu doğrudan gömmek yerine OpenAPI'deki başka bir yerde bulunan global JSON Schema'lara bir referans ekler. Böylece diğer uygulamalar ve client'lar bu JSON Schema'ları doğrudan kullanabilir, daha iyi code generation araçları sağlayabilir, vb.\n\n///\n\nBu *path operation* için OpenAPI'de üretilen response'lar şöyle olur:\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nSchema'lar OpenAPI şemasının içinde başka bir yere referanslanır:\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## Ana Response İçin Ek Media Type'lar { #additional-media-types-for-the-main-response }\n\nAynı `responses` parametresini, aynı ana response için farklı media type'lar eklemek amacıyla da kullanabilirsiniz.\n\nÖrneğin, `image/png` için ek bir media type ekleyerek, *path operation*'ınızın bir JSON nesnesi (media type `application/json`) ya da bir PNG görseli döndürebildiğini belirtebilirsiniz:\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | Not\n\nGörseli `FileResponse` kullanarak doğrudan döndürmeniz gerektiğine dikkat edin.\n\n///\n\n/// info | Bilgi\n\n`responses` parametrenizde açıkça farklı bir media type belirtmediğiniz sürece FastAPI, response'un ana response class'ı ile aynı media type'a sahip olduğunu varsayar (varsayılan `application/json`).\n\nAncak media type'ı `None` olan özel bir response class belirttiyseniz, FastAPI ilişkili bir model'i olan tüm ek response'lar için `application/json` kullanır.\n\n///\n\n## Bilgileri Birleştirme { #combining-information }\n\n`response_model`, `status_code` ve `responses` parametreleri dahil olmak üzere, response bilgilerini birden fazla yerden birleştirebilirsiniz.\n\nVarsayılan `200` status code'unu (ya da gerekiyorsa özel bir tane) kullanarak bir `response_model` tanımlayabilir, ardından aynı response için ek bilgileri `responses` içinde, doğrudan OpenAPI şemasına ekleyebilirsiniz.\n\n**FastAPI**, `responses` içindeki ek bilgileri korur ve model'inizin JSON Schema'sı ile birleştirir.\n\nÖrneğin, Pydantic model kullanan ve özel bir `description` içeren `404` status code'lu bir response tanımlayabilirsiniz.\n\nAyrıca `response_model`'inizi kullanan, ancak özel bir `example` içeren `200` status code'lu bir response da tanımlayabilirsiniz:\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\nBunların hepsi OpenAPI'nize birleştirilerek dahil edilir ve API dokümanlarında gösterilir:\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## Ön Tanımlı Response'ları Özel Olanlarla Birleştirme { #combine-predefined-responses-and-custom-ones }\n\nBirçok *path operation* için geçerli olacak bazı ön tanımlı response'larınız olabilir; ancak bunları her *path operation*'ın ihtiyaç duyduğu özel response'larla birleştirmek isteyebilirsiniz.\n\nBu durumlarda, Python'daki bir `dict`'i `**dict_to_unpack` ile \"unpacking\" tekniğini kullanabilirsiniz:\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\nBurada `new_dict`, `old_dict` içindeki tüm key-value çiftlerini ve buna ek olarak yeni key-value çiftini içerir:\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\nBu tekniği, *path operation*'larınızda bazı ön tanımlı response'ları yeniden kullanmak ve bunları ek özel response'larla birleştirmek için kullanabilirsiniz.\n\nÖrneğin:\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## OpenAPI Response'ları Hakkında Daha Fazla Bilgi { #more-information-about-openapi-responses }\n\nResponse'ların içine tam olarak neleri dahil edebileceğinizi görmek için OpenAPI spesifikasyonundaki şu bölümlere bakabilirsiniz:\n\n* [OpenAPI Responses Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object), `Response Object`'i içerir.\n* [OpenAPI Response Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object), buradaki her şeyi `responses` parametreniz içinde, her bir response'un içine doğrudan ekleyebilirsiniz. Buna `description`, `headers`, `content` (bunun içinde farklı media type'lar ve JSON Schema'lar tanımlarsınız) ve `links` dahildir.\n"
  },
  {
    "path": "docs/tr/docs/advanced/additional-status-codes.md",
    "content": "# Ek Status Code'ları { #additional-status-codes }\n\nVarsayılan olarak **FastAPI**, response'ları bir `JSONResponse` kullanarak döndürür; *path operation*'ınızdan döndürdüğünüz içeriği bu `JSONResponse`'un içine yerleştirir.\n\nVarsayılan status code'u veya *path operation* içinde sizin belirlediğiniz status code'u kullanır.\n\n## Ek status code'ları { #additional-status-codes_1 }\n\nAna status code'a ek olarak başka status code'lar da döndürmek istiyorsanız, `JSONResponse` gibi bir `Response`'u doğrudan döndürerek bunu yapabilirsiniz ve ek status code'u doğrudan orada ayarlarsınız.\n\nÖrneğin, item'ları güncellemeye izin veren bir *path operation*'ınız olduğunu düşünelim; başarılı olduğunda 200 \"OK\" HTTP status code'unu döndürüyor olsun.\n\nAncak yeni item'ları da kabul etmesini istiyorsunuz. Ve item daha önce yoksa, onu oluşturup 201 \"Created\" HTTP status code'unu döndürsün.\n\nBunu yapmak için `JSONResponse` import edin ve içeriğinizi doğrudan onunla döndürün; istediğiniz `status_code`'u da ayarlayın:\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning | Uyarı\n\nYukarıdaki örnekte olduğu gibi bir `Response`'u doğrudan döndürdüğünüzde, response aynen olduğu gibi döndürülür.\n\nBir model ile serialize edilmez, vb.\n\nİçinde olmasını istediğiniz veriyi taşıdığından emin olun ve değerlerin geçerli JSON olduğundan emin olun (eğer `JSONResponse` kullanıyorsanız).\n\n///\n\n/// note | Teknik Detaylar\n\n`from starlette.responses import JSONResponse` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içindekileri `fastapi.responses` altında da sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'ten gelir. `status` için de aynı durum geçerlidir.\n\n///\n\n## OpenAPI ve API docs { #openapi-and-api-docs }\n\nEk status code'ları ve response'ları doğrudan döndürürseniz, FastAPI sizin ne döndüreceğinizi önceden bilemeyeceği için bunlar OpenAPI şemasına (API docs) dahil edilmez.\n\nAncak bunu kodunuzda şu şekilde dokümante edebilirsiniz: [Ek Response'lar](additional-responses.md).\n"
  },
  {
    "path": "docs/tr/docs/advanced/advanced-dependencies.md",
    "content": "# Gelişmiş Dependency'ler { #advanced-dependencies }\n\n## Parametreli dependency'ler { #parameterized-dependencies }\n\nŞimdiye kadar gördüğümüz tüm dependency'ler sabit bir function ya da class idi.\n\nAncak, birçok farklı function veya class tanımlamak zorunda kalmadan, dependency üzerinde bazı parametreler ayarlamak isteyebileceğiniz durumlar olabilir.\n\nÖrneğin, query parametresi `q`'nun belirli bir sabit içeriği barındırıp barındırmadığını kontrol eden bir dependency istediğimizi düşünelim.\n\nAma bu sabit içeriği parametreleştirebilmek istiyoruz.\n\n## \"Callable\" bir instance { #a-callable-instance }\n\nPython'da bir class'ın instance'ını \"callable\" yapmanın bir yolu vardır.\n\nClass'ın kendisini değil (zaten callable'dır), o class'ın bir instance'ını.\n\nBunu yapmak için `__call__` adında bir method tanımlarız:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\nBu durumda, ek parametreleri ve alt-dependency'leri kontrol etmek için **FastAPI**'nin kullanacağı şey bu `__call__` olacaktır; ayrıca daha sonra *path operation function* içindeki parametreye bir değer geçmek için çağrılacak olan da budur.\n\n## Instance'ı parametreleştirme { #parameterize-the-instance }\n\nVe şimdi, dependency'yi \"parametreleştirmek\" için kullanacağımız instance parametrelerini tanımlamak üzere `__init__` kullanabiliriz:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\nBu durumda **FastAPI**, `__init__` ile asla uğraşmaz veya onu önemsemez; onu doğrudan kendi kodumuzda kullanırız.\n\n## Bir instance oluşturma { #create-an-instance }\n\nBu class'tan bir instance'ı şöyle oluşturabiliriz:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\nBöylece dependency'mizi \"parametreleştirmiş\" oluruz; artık içinde `\"bar\"` vardır ve bu değer `checker.fixed_content` attribute'u olarak durur.\n\n## Instance'ı dependency olarak kullanma { #use-the-instance-as-a-dependency }\n\nSonra `Depends(FixedContentQueryChecker)` yerine `Depends(checker)` içinde bu `checker`'ı kullanabiliriz. Çünkü dependency, class'ın kendisi değil, `checker` instance'ıdır.\n\nVe dependency çözülürken **FastAPI** bu `checker`'ı şöyle çağırır:\n\n```Python\nchecker(q=\"somequery\")\n```\n\n...ve bunun döndürdüğü her şeyi, *path operation function* içinde `fixed_content_included` parametresine dependency değeri olarak geçirir:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | İpucu\n\nBunların tamamı biraz yapay görünebilir. Ayrıca bunun nasıl faydalı olduğu da henüz çok net olmayabilir.\n\nBu örnekler bilerek basit tutuldu; ama mekanizmanın nasıl çalıştığını gösteriyor.\n\nSecurity bölümlerinde, aynı şekilde implement edilmiş yardımcı function'lar bulunuyor.\n\nBuradaki her şeyi anladıysanız, security için kullanılan bu yardımcı araçların arka planda nasıl çalıştığını da zaten biliyorsunuz demektir.\n\n///\n\n## `yield`, `HTTPException`, `except` ve Background Tasks ile Dependency'ler { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | Uyarı\n\nBüyük ihtimalle bu teknik detaylara ihtiyacınız yok.\n\nBu detaylar, özellikle 0.121.0'dan eski bir FastAPI uygulamanız varsa ve `yield` kullanan dependency'lerle ilgili sorunlar yaşıyorsanız faydalıdır.\n\n///\n\n`yield` kullanan dependency'ler; farklı kullanım senaryolarını kapsamak ve bazı sorunları düzeltmek için zaman içinde evrildi. Aşağıda nelerin değiştiğinin bir özeti var.\n\n### `yield` ve `scope` ile dependency'ler { #dependencies-with-yield-and-scope }\n\n0.121.0 sürümünde FastAPI, `Depends(scope=\"function\")` desteğini ekledi.\n\n`Depends(scope=\"function\")` kullanıldığında, `yield` sonrasındaki çıkış kodu, *path operation function* biter bitmez, response client'a geri gönderilmeden önce çalıştırılır.\n\n`Depends(scope=\"request\")` (varsayılan) kullanıldığında ise `yield` sonrasındaki çıkış kodu, response gönderildikten sonra çalıştırılır.\n\nDaha fazlasını [`yield` ile Dependency'ler - Erken çıkış ve `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) dokümantasyonunda okuyabilirsiniz.\n\n### `yield` ve `StreamingResponse` ile dependency'ler, Teknik Detaylar { #dependencies-with-yield-and-streamingresponse-technical-details }\n\nFastAPI 0.118.0 öncesinde, `yield` kullanan bir dependency kullanırsanız, *path operation function* döndükten sonra ama response gönderilmeden hemen önce `yield` sonrasındaki çıkış kodu çalıştırılırdı.\n\nAmaç, response'un ağ üzerinden taşınmasını beklerken gereğinden uzun süre resource tutmaktan kaçınmaktı.\n\nBu değişiklik aynı zamanda şunu da ifade ediyordu: `StreamingResponse` döndürürseniz, `yield` kullanan dependency'nin çıkış kodu zaten çalışmış olurdu.\n\nÖrneğin, `yield` kullanan bir dependency içinde bir veritabanı session'ınız varsa, `StreamingResponse` veri stream ederken bu session'ı kullanamazdı; çünkü `yield` sonrasındaki çıkış kodunda session zaten kapatılmış olurdu.\n\nBu davranış 0.118.0'da geri alındı ve `yield` sonrasındaki çıkış kodunun, response gönderildikten sonra çalıştırılması sağlandı.\n\n/// info | Bilgi\n\nAşağıda göreceğiniz gibi, bu davranış 0.106.0 sürümünden önceki davranışa oldukça benzer; ancak köşe durumlar için çeşitli iyileştirmeler ve bug fix'ler içerir.\n\n///\n\n#### Erken Çıkış Kodu için Kullanım Senaryoları { #use-cases-with-early-exit-code }\n\nBazı özel koşullardaki kullanım senaryoları, response gönderilmeden önce `yield` kullanan dependency'lerin çıkış kodunun çalıştırıldığı eski davranıştan fayda görebilir.\n\nÖrneğin, `yield` kullanan bir dependency içinde yalnızca bir kullanıcıyı doğrulamak için veritabanı session'ı kullanan bir kodunuz olduğunu düşünün; ama bu session *path operation function* içinde bir daha hiç kullanılmıyor, yalnızca dependency içinde kullanılıyor **ve** response'un gönderilmesi uzun sürüyor. Mesela veriyi yavaş gönderen bir `StreamingResponse` var, ama herhangi bir nedenle veritabanını kullanmıyor.\n\nBu durumda veritabanı session'ı, response tamamen gönderilene kadar elde tutulur. Ancak session kullanılmıyorsa, bunu elde tutmak gerekli değildir.\n\nŞöyle görünebilir:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\n`Session`'ın otomatik kapatılması olan çıkış kodu şurada:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n...yavaş veri gönderen response'un gönderimi bittikten sonra çalıştırılır:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nAma `generate_stream()` veritabanı session'ını kullanmadığı için, response gönderilirken session'ı açık tutmak aslında gerekli değildir.\n\nSQLModel (veya SQLAlchemy) kullanarak bu spesifik senaryoya sahipseniz, session'a artık ihtiyacınız kalmadıktan sonra session'ı açıkça kapatabilirsiniz:\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\nBöylece session veritabanı bağlantısını serbest bırakır ve diğer request'ler bunu kullanabilir.\n\n`yield` kullanan bir dependency'den erken çıkış gerektiren farklı bir kullanım senaryonuz varsa, lütfen kullanım senaryonuzla birlikte ve `yield` kullanan dependency'ler için erken kapatmadan neden fayda göreceğinizi açıklayarak bir [GitHub Discussion Sorusu](https://github.com/fastapi/fastapi/discussions/new?category=questions) oluşturun.\n\n`yield` kullanan dependency'lerde erken kapatma için ikna edici kullanım senaryoları varsa, erken kapatmayı seçmeli (opt-in) hale getiren yeni bir yöntem eklemeyi düşünebilirim.\n\n### `yield` ve `except` ile dependency'ler, Teknik Detaylar { #dependencies-with-yield-and-except-technical-details }\n\nFastAPI 0.110.0 öncesinde, `yield` kullanan bir dependency kullanır, sonra o dependency içinde `except` ile bir exception yakalar ve exception'ı tekrar raise etmezseniz; exception otomatik olarak herhangi bir exception handler'a veya internal server error handler'a raise/forward edilirdi.\n\nBu davranış 0.110.0 sürümünde değiştirildi. Amaç, handler olmayan (internal server errors) forward edilmiş exception'ların yönetilmemesinden kaynaklanan bellek tüketimini düzeltmek ve bunu normal Python kodunun davranışıyla tutarlı hale getirmekti.\n\n### Background Tasks ve `yield` ile dependency'ler, Teknik Detaylar { #background-tasks-and-dependencies-with-yield-technical-details }\n\nFastAPI 0.106.0 öncesinde, `yield` sonrasında exception raise etmek mümkün değildi; çünkü `yield` kullanan dependency'lerdeki çıkış kodu response gönderildikten *sonra* çalıştırılıyordu. Bu nedenle [Exception Handler'ları](../tutorial/handling-errors.md#install-custom-exception-handlers) zaten çalışmış olurdu.\n\nBu tasarımın ana sebeplerinden biri, background task'lerin içinde dependency'lerin \"yield ettiği\" aynı objeleri kullanmaya izin vermekti; çünkü çıkış kodu, background task'ler bittikten sonra çalıştırılıyordu.\n\nBu davranış FastAPI 0.106.0'da, response'un ağ üzerinde taşınmasını beklerken resource tutmamak amacıyla değiştirildi.\n\n/// tip | İpucu\n\nEk olarak, bir background task normalde ayrı ele alınması gereken bağımsız bir mantık setidir ve kendi resource'larına sahip olmalıdır (ör. kendi veritabanı bağlantısı).\n\nBu şekilde muhtemelen daha temiz bir kod elde edersiniz.\n\n///\n\nBu davranışa güvenerek kod yazdıysanız, artık background task'ler için resource'ları background task'in içinde oluşturmalı ve içeride yalnızca `yield` kullanan dependency'lerin resource'larına bağlı olmayan verileri kullanmalısınız.\n\nÖrneğin, aynı veritabanı session'ını kullanmak yerine background task içinde yeni bir veritabanı session'ı oluşturur ve veritabanındaki objeleri bu yeni session ile alırsınız. Ardından, background task function'ına veritabanından gelen objeyi parametre olarak geçirmek yerine, o objenin ID'sini geçirir ve objeyi background task function'ı içinde yeniden elde edersiniz.\n"
  },
  {
    "path": "docs/tr/docs/advanced/advanced-python-types.md",
    "content": "# Gelişmiş Python Tipleri { #advanced-python-types }\n\nPython tipleriyle çalışırken işinize yarayabilecek bazı ek fikirler.\n\n## `Union` veya `Optional` Kullanımı { #using-union-or-optional }\n\nKodunuz herhangi bir nedenle `|` kullanamıyorsa — örneğin bir tip açıklamasında (type annotation) değil de `response_model=` gibi bir yerdeyse — dikey çizgi (`|`) yerine `typing` içindeki `Union`'ı kullanabilirsiniz.\n\nÖrneğin, bir şeyin `str` ya da `None` olabileceğini şöyle belirtebilirsiniz:\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\n`typing`, bir şeyin `None` olabileceğini belirtmek için `Optional` ile bir kısayol da sunar.\n\nBenim oldukça öznel bakış açıma göre küçük bir ipucu:\n\n- 🚨 `Optional[SomeType]` kullanmaktan kaçının\n- Bunun yerine ✨ **`Union[SomeType, None]` kullanın** ✨.\n\nİkisi de eşdeğer ve temelde aynıdır; ancak \"**optional**\" kelimesi değerin isteğe bağlı olduğunu ima eder. Oysa aslında \" `None` olabilir\" demektir; değer isteğe bağlı olmasa ve hâlâ zorunlu olsa bile.\n\nBence `Union[SomeType, None]` ne demek istediğini daha açık anlatır.\n\nBurada mesele sadece kelimeler ve isimler. Ancak bu kelimeler sizin ve ekip arkadaşlarınızın koda bakışını etkileyebilir.\n\nÖrnek olarak şu fonksiyona bakalım:\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\n`name` parametresi `Optional[str]` olarak tanımlıdır; ancak isteğe bağlı değildir, parametre olmadan fonksiyonu çağıramazsınız:\n\n```Python\nsay_hi()  # Ah hayır, bu hata fırlatır! 😱\n```\n\n`name` parametresi varsayılan bir değeri olmadığı için hâlâ zorunludur (yani *optional* değildir). Yine de `name`, değer olarak `None` kabul eder:\n\n```Python\nsay_hi(name=None)  # Bu çalışır, None geçerlidir 🎉\n```\n\nİyi haber şu ki, çoğu durumda tip birliklerini (union) tanımlamak için doğrudan `|` kullanabilirsiniz:\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\nDolayısıyla, normalde `Optional` ve `Union` gibi isimler için endişelenmenize gerek yok. 😎\n"
  },
  {
    "path": "docs/tr/docs/advanced/async-tests.md",
    "content": "# Async Testler { #async-tests }\n\nSağlanan `TestClient` ile **FastAPI** uygulamalarınızı nasıl test edeceğinizi zaten gördünüz. Şimdiye kadar yalnızca senkron testler yazdık, yani `async` fonksiyonlar kullanmadan.\n\nTestlerinizde asenkron fonksiyonlar kullanabilmek faydalı olabilir; örneğin veritabanınızı asenkron olarak sorguluyorsanız. Diyelim ki FastAPI uygulamanıza request gönderilmesini test etmek ve ardından async bir veritabanı kütüphanesi kullanırken backend'in doğru veriyi veritabanına başarıyla yazdığını doğrulamak istiyorsunuz.\n\nBunu nasıl çalıştırabileceğimize bir bakalım.\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\nTestlerimizde asenkron fonksiyonlar çağırmak istiyorsak, test fonksiyonlarımızın da asenkron olması gerekir. AnyIO bunun için güzel bir plugin sağlar; böylece bazı test fonksiyonlarının asenkron olarak çağrılacağını belirtebiliriz.\n\n## HTTPX { #httpx }\n\n**FastAPI** uygulamanız `async def` yerine normal `def` fonksiyonları kullanıyor olsa bile, altta yatan yapı hâlâ bir `async` uygulamadır.\n\n`TestClient`, standart pytest kullanarak normal `def` test fonksiyonlarınızın içinden asenkron FastAPI uygulamasını çağırmak için içeride bazı “sihirli” işlemler yapar. Ancak bu sihir, onu asenkron fonksiyonların içinde kullandığımızda artık çalışmaz. Testlerimizi asenkron çalıştırdığımızda, test fonksiyonlarımızın içinde `TestClient` kullanamayız.\n\n`TestClient`, [HTTPX](https://www.python-httpx.org) tabanlıdır ve neyse ki API'yi test etmek için HTTPX'i doğrudan kullanabiliriz.\n\n## Örnek { #example }\n\nBasit bir örnek için, [Daha Büyük Uygulamalar](../tutorial/bigger-applications.md) ve [Test Etme](../tutorial/testing.md) bölümlerinde anlatılana benzer bir dosya yapısı düşünelim:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n`main.py` dosyası şöyle olur:\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\n`test_main.py` dosyasında `main.py` için testler yer alır, artık şöyle görünebilir:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## Çalıştırma { #run-it }\n\nTestlerinizi her zamanki gibi şu şekilde çalıştırabilirsiniz:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## Detaylı Anlatım { #in-detail }\n\n`@pytest.mark.anyio` marker'ı, pytest'e bu test fonksiyonunun asenkron olarak çağrılması gerektiğini söyler:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip | İpucu\n\nTest fonksiyonu artık `TestClient` kullanırken eskiden olduğu gibi sadece `def` değil, `async def`.\n\n///\n\nArdından app ile bir `AsyncClient` oluşturup `await` kullanarak ona async request'ler gönderebiliriz.\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\nBu, şu kullanıma denktir:\n\n```Python\nresponse = client.get('/')\n```\n\n...ki daha önce request'leri `TestClient` ile bu şekilde gönderiyorduk.\n\n/// tip | İpucu\n\nYeni `AsyncClient` ile async/await kullandığımızı unutmayın; request asenkron çalışır.\n\n///\n\n/// warning | Uyarı\n\nUygulamanız lifespan event'lerine dayanıyorsa, `AsyncClient` bu event'leri tetiklemez. Tetiklendiklerinden emin olmak için [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage) paketindeki `LifespanManager`'ı kullanın.\n\n///\n\n## Diğer Asenkron Fonksiyon Çağrıları { #other-asynchronous-function-calls }\n\nTest fonksiyonu artık asenkron olduğundan, testlerinizde FastAPI uygulamanıza request göndermenin yanında başka `async` fonksiyonları da (çağırıp `await` ederek) kodunuzun başka yerlerinde yaptığınız gibi aynı şekilde kullanabilirsiniz.\n\n/// tip | İpucu\n\nTestlerinize asenkron fonksiyon çağrıları entegre ederken `RuntimeError: Task attached to a different loop` hatasıyla karşılaşırsanız (ör. [MongoDB'nin MotorClient](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop) kullanımı), event loop gerektiren nesneleri yalnızca async fonksiyonların içinde oluşturmanız gerektiğini unutmayın; örneğin bir `@app.on_event(\"startup\")` callback'i içinde.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/advanced/behind-a-proxy.md",
    "content": "# Proxy Arkasında Çalıştırma { #behind-a-proxy }\n\nBirçok durumda, FastAPI uygulamanızın önünde Traefik veya Nginx gibi bir **proxy** kullanırsınız.\n\nBu proxy'ler HTTPS sertifikalarını ve diğer bazı işleri üstlenebilir.\n\n## Proxy Forwarded Header'ları { #proxy-forwarded-headers }\n\nUygulamanızın önündeki bir **proxy**, request'leri **server**'ınıza göndermeden önce genelde bazı header'ları dinamik olarak ayarlar. Böylece server, request'in proxy tarafından **forward** edildiğini; domain dahil orijinal (public) URL'yi, HTTPS kullanıldığını vb. bilgileri anlayabilir.\n\n**Server** programı (örneğin **FastAPI CLI** üzerinden **Uvicorn**) bu header'ları yorumlayabilir ve ardından bu bilgiyi uygulamanıza aktarabilir.\n\nAncak güvenlik nedeniyle, server güvenilir bir proxy arkasında olduğunu bilmediği için bu header'ları yorumlamaz.\n\n/// note | Teknik Detaylar\n\nProxy header'ları şunlardır:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### Proxy Forwarded Header'larını Etkinleştirme { #enable-proxy-forwarded-headers }\n\nFastAPI CLI'yi `--forwarded-allow-ips` *CLI Option*'ı ile başlatıp, bu forwarded header'ları okumada güvenilecek IP adreslerini verebilirsiniz.\n\nBunu `--forwarded-allow-ips=\"*\"` olarak ayarlarsanız, gelen tüm IP'lere güvenir.\n\n**Server**'ınız güvenilir bir **proxy** arkasındaysa ve onunla sadece proxy konuşuyorsa, bu ayar server'ın o **proxy**'nin IP'si her neyse onu kabul etmesini sağlar.\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### HTTPS ile Redirect'ler { #redirects-with-https }\n\nÖrneğin `/items/` adında bir *path operation* tanımladığınızı düşünelim:\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\nClient `/items`'a gitmeye çalışırsa, varsayılan olarak `/items/`'a redirect edilir.\n\nAncak *CLI Option* `--forwarded-allow-ips` ayarlanmadan önce, `http://localhost:8000/items/`'a redirect edebilir.\n\nOysa uygulamanız `https://mysuperapp.com` üzerinde host ediliyor olabilir ve redirect'in `https://mysuperapp.com/items/` olması gerekir.\n\nArtık `--proxy-headers` ayarını yaparak FastAPI'nin doğru adrese redirect edebilmesini sağlarsınız. 😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip | İpucu\n\nHTTPS hakkında daha fazla bilgi için [HTTPS Hakkında](../deployment/https.md) rehberine bakın.\n\n///\n\n### Proxy Forwarded Header'ları Nasıl Çalışır { #how-proxy-forwarded-headers-work }\n\n**Proxy**'nin, client ile **application server** arasında forwarded header'ları nasıl eklediğini gösteren görsel bir temsil:\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Proxy as Proxy/Load Balancer\n    participant Server as FastAPI Server\n\n    Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: Proxy adds forwarded headers\n\n    Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)\n\n    Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs\n\n    Proxy->>Client: HTTPS Response\n```\n\n**Proxy**, orijinal client request'ini araya girerek (intercept) alır ve request'i **application server**'a iletmeden önce özel *forwarded* header'ları (`X-Forwarded-*`) ekler.\n\nBu header'lar, aksi halde kaybolacak olan orijinal request bilgilerini korur:\n\n* **X-Forwarded-For**: Orijinal client'ın IP adresi\n* **X-Forwarded-Proto**: Orijinal protokol (`https`)\n* **X-Forwarded-Host**: Orijinal host (`mysuperapp.com`)\n\n**FastAPI CLI** `--forwarded-allow-ips` ile yapılandırıldığında bu header'lara güvenir ve örneğin redirect'lerde doğru URL'leri üretmek için bunları kullanır.\n\n## Path Prefix'i Kırpılan (Stripped) Bir Proxy { #proxy-with-a-stripped-path-prefix }\n\nUygulamanıza bir path prefix ekleyen bir proxy'niz olabilir.\n\nBu durumlarda uygulamanızı yapılandırmak için `root_path` kullanabilirsiniz.\n\n`root_path`, FastAPI'nin (Starlette üzerinden) üzerine kurulduğu ASGI spesifikasyonunun sağladığı bir mekanizmadır.\n\n`root_path` bu özel senaryoları yönetmek için kullanılır.\n\nAyrıca sub-application mount ederken de içeride kullanılır.\n\nPath prefix'i kırpılan bir proxy kullanmak, şu anlama gelir: Kodunuzda `/app` altında bir path tanımlarsınız; ancak üstte bir katman (proxy) ekleyip **FastAPI** uygulamanızı `/api/v1` gibi bir path'in altına koyarsınız.\n\nBu durumda, orijinal `/app` path'i aslında `/api/v1/app` altında servis edilir.\n\nKodunuzun tamamı sadece `/app` varmış gibi yazılmış olsa bile.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\nProxy, request'i app server'a (muhtemelen FastAPI CLI üzerinden Uvicorn) iletmeden önce **path prefix**'i anlık olarak **\"kırpar\"** (strip). Böylece uygulamanız hâlâ `/app` altında servis ediliyormuş gibi davranır ve tüm kodunuzu `/api/v1` prefix'ini içerecek şekilde güncellemeniz gerekmez.\n\nBuraya kadar her şey normal çalışır.\n\nAncak entegre doküman arayüzünü (frontend) açtığınızda, OpenAPI şemasını `/api/v1/openapi.json` yerine `/openapi.json` üzerinden almayı bekler.\n\nDolayısıyla tarayıcıda çalışan frontend `/openapi.json`'a erişmeye çalışır ve OpenAPI şemasını alamaz.\n\nÇünkü uygulamamız proxy arkasında `/api/v1` path prefix'i ile çalışmaktadır; frontend'in OpenAPI şemasını `/api/v1/openapi.json` üzerinden çekmesi gerekir.\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy on http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server on http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip | İpucu\n\n`0.0.0.0` IP'si, genelde programın ilgili makine/server üzerindeki tüm kullanılabilir IP'lerde dinlediği anlamına gelir.\n\n///\n\nDocs UI'nin, bu API `server`'ının (proxy arkasında) `/api/v1` altında bulunduğunu belirtmek için OpenAPI şemasına da ihtiyacı olur. Örneğin:\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // Burada daha fazla şey var\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // Burada daha fazla şey var\n    }\n}\n```\n\nBu örnekte \"Proxy\", **Traefik** gibi bir şey olabilir. Server da FastAPI uygulamanızı çalıştıran (Uvicorn'lu) FastAPI CLI olabilir.\n\n### `root_path` Sağlama { #providing-the-root-path }\n\nBunu yapmak için `--root-path` komut satırı seçeneğini şöyle kullanabilirsiniz:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nHypercorn kullanıyorsanız, onda da `--root-path` seçeneği vardır.\n\n/// note | Teknik Detaylar\n\nASGI spesifikasyonu bu kullanım senaryosu için bir `root_path` tanımlar.\n\n`--root-path` komut satırı seçeneği de bu `root_path`'i sağlar.\n\n///\n\n### Mevcut `root_path`'i Kontrol Etme { #checking-the-current-root-path }\n\nUygulamanızın her request için kullandığı mevcut `root_path` değerini alabilirsiniz; bu değer ASGI spesifikasyonunun bir parçası olan `scope` dict'inin içindedir.\n\nBurada sadece göstermek için bunu mesaja dahil ediyoruz.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\nArdından Uvicorn'u şu şekilde başlatırsanız:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nResponse şöyle bir şey olur:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### FastAPI Uygulamasında `root_path` Ayarlama { #setting-the-root-path-in-the-fastapi-app }\n\nAlternatif olarak, `--root-path` gibi bir komut satırı seçeneği (veya muadili) sağlayamıyorsanız, FastAPI uygulamanızı oluştururken `root_path` parametresini ayarlayabilirsiniz:\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\n`FastAPI`'ye `root_path` vermek, Uvicorn veya Hypercorn'a `--root-path` komut satırı seçeneğini vermekle eşdeğerdir.\n\n### `root_path` Hakkında { #about-root-path }\n\nŞunu unutmayın: Server (Uvicorn) bu `root_path`'i, uygulamaya iletmek dışında başka bir amaçla kullanmaz.\n\nAncak tarayıcınızla [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app) adresine giderseniz normal response'u görürsünüz:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nYani `http://127.0.0.1:8000/api/v1/app` üzerinden erişilmeyi beklemez.\n\nUvicorn, proxy'nin Uvicorn'a `http://127.0.0.1:8000/app` üzerinden erişmesini bekler; bunun üstüne ekstra `/api/v1` prefix'ini eklemek proxy'nin sorumluluğudur.\n\n## Stripped Path Prefix Kullanan Proxy'ler Hakkında { #about-proxies-with-a-stripped-path-prefix }\n\nStripped path prefix kullanan bir proxy, yapılandırma yöntemlerinden yalnızca biridir.\n\nBirçok durumda varsayılan davranış, proxy'nin stripped path prefix kullanmaması olacaktır.\n\nBöyle bir durumda (stripped path prefix olmadan), proxy `https://myawesomeapp.com` gibi bir yerde dinler; tarayıcı `https://myawesomeapp.com/api/v1/app`'e giderse ve sizin server'ınız (ör. Uvicorn) `http://127.0.0.1:8000` üzerinde dinliyorsa, proxy (stripped path prefix olmadan) Uvicorn'a aynı path ile erişir: `http://127.0.0.1:8000/api/v1/app`.\n\n## Traefik ile Local Olarak Test Etme { #testing-locally-with-traefik }\n\n[Traefik](https://docs.traefik.io/) kullanarak, stripped path prefix'li deneyi local'de kolayca çalıştırabilirsiniz.\n\n[Traefik'i indirin](https://github.com/containous/traefik/releases); tek bir binary'dir, sıkıştırılmış dosyayı çıkarıp doğrudan terminalden çalıştırabilirsiniz.\n\nArdından `traefik.toml` adında bir dosya oluşturup şunu yazın:\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\nBu, Traefik'e 9999 portunda dinlemesini ve `routes.toml` adlı başka bir dosyayı kullanmasını söyler.\n\n/// tip | İpucu\n\nStandart HTTP portu 80 yerine 9999 portunu kullanıyoruz; böylece admin (`sudo`) yetkileriyle çalıştırmanız gerekmez.\n\n///\n\nŞimdi diğer dosyayı, `routes.toml`'u oluşturun:\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\nBu dosya, Traefik'i `/api/v1` path prefix'ini kullanacak şekilde yapılandırır.\n\nArdından Traefik, request'leri `http://127.0.0.1:8000` üzerinde çalışan Uvicorn'unuza yönlendirir.\n\nŞimdi Traefik'i başlatın:\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\nVe şimdi uygulamanızı `--root-path` seçeneğiyle başlatın:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Response'ları Kontrol Edin { #check-the-responses }\n\nŞimdi Uvicorn'un portundaki URL'ye giderseniz: [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), normal response'u görürsünüz:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip | İpucu\n\n`http://127.0.0.1:8000/app` üzerinden erişiyor olsanız bile, `root_path` değerinin `--root-path` seçeneğinden alınıp `/api/v1` olarak gösterildiğine dikkat edin.\n\n///\n\nŞimdi de Traefik'in portundaki URL'yi, path prefix ile birlikte açın: [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app).\n\nAynı response'u alırız:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nama bu sefer proxy'nin sağladığı prefix path olan `/api/v1` ile gelen URL'de.\n\nElbette buradaki fikir, herkesin uygulamaya proxy üzerinden erişmesidir; dolayısıyla `/api/v1` path prefix'li sürüm \"doğru\" olandır.\n\nUvicorn'un doğrudan sunduğu, path prefix olmayan sürüm (`http://127.0.0.1:8000/app`) ise sadece _proxy_'nin (Traefik) erişmesi için kullanılmalıdır.\n\nBu da Proxy'nin (Traefik) path prefix'i nasıl kullandığını ve server'ın (Uvicorn) `--root-path` seçeneğinden gelen `root_path`'i nasıl kullandığını gösterir.\n\n### Docs UI'yi Kontrol Edin { #check-the-docs-ui }\n\nŞimdi işin eğlenceli kısmı. ✨\n\nUygulamaya erişmenin \"resmi\" yolu, tanımladığımız path prefix ile proxy üzerinden erişmektir. Bu yüzden beklendiği gibi, Uvicorn'un doğrudan servis ettiği docs UI'yi URL'de path prefix olmadan açarsanız çalışmaz; çünkü proxy üzerinden erişileceğini varsayar.\n\nŞuradan kontrol edebilirsiniz: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\nAncak docs UI'yi proxy üzerinden, `9999` portuyla, `/api/v1/docs` altında \"resmi\" URL'den açarsak doğru çalışır! 🎉\n\nŞuradan kontrol edebilirsiniz: [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\nTam istediğimiz gibi. ✔️\n\nBunun nedeni, FastAPI'nin OpenAPI içinde varsayılan `server`'ı, `root_path` tarafından verilen URL ile oluşturmak için bu `root_path`'i kullanmasıdır.\n\n## Ek `server`'lar { #additional-servers }\n\n/// warning | Uyarı\n\nBu daha ileri seviye bir kullanım senaryosudur. İsterseniz atlayabilirsiniz.\n\n///\n\nVarsayılan olarak **FastAPI**, OpenAPI şemasında `root_path` için bir `server` oluşturur.\n\nAncak başka alternatif `servers` da sağlayabilirsiniz; örneğin *aynı* docs UI'nin hem staging hem de production ortamıyla etkileşime girmesini istiyorsanız.\n\nÖzel bir `servers` listesi verirseniz ve bir `root_path` varsa (çünkü API'niz proxy arkasındadır), **FastAPI** bu `root_path` ile bir \"server\"ı listenin başına ekler.\n\nÖrneğin:\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\nŞöyle bir OpenAPI şeması üretir:\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // Burada daha fazla şey var\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // Burada daha fazla şey var\n    }\n}\n```\n\n/// tip | İpucu\n\n`url` değeri `/api/v1` olan, `root_path`'ten alınmış otomatik üretilen server'a dikkat edin.\n\n///\n\nDocs UI'de, [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) adresinde şöyle görünür:\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip | İpucu\n\nDocs UI, seçtiğiniz server ile etkileşime girer.\n\n///\n\n/// note | Teknik Detaylar\n\nOpenAPI spesifikasyonunda `servers` özelliği opsiyoneldir.\n\n`servers` parametresini belirtmezseniz ve `root_path` `/` ile aynıysa, üretilen OpenAPI şemasında `servers` özelliği varsayılan olarak tamamen çıkarılır; bu da `url` değeri `/` olan tek bir server ile eşdeğerdir.\n\n///\n\n### `root_path`'ten Otomatik `server` Eklenmesini Kapatma { #disable-automatic-server-from-root-path }\n\n**FastAPI**'nin `root_path` kullanarak otomatik bir server eklemesini istemiyorsanız, `root_path_in_servers=False` parametresini kullanabilirsiniz:\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\nBöylece OpenAPI şemasına dahil etmez.\n\n## Bir Sub-Application Mount Etme { #mounting-a-sub-application }\n\nBir sub-application'ı ([Sub Applications - Mounts](sub-applications.md) bölümünde anlatıldığı gibi) mount etmeniz gerekiyorsa ve aynı zamanda `root_path` ile bir proxy kullanıyorsanız, bunu beklendiği gibi normal şekilde yapabilirsiniz.\n\nFastAPI içeride `root_path`'i akıllıca kullanır; dolayısıyla doğrudan çalışır. ✨\n"
  },
  {
    "path": "docs/tr/docs/advanced/custom-response.md",
    "content": "# Özel Response - HTML, Stream, File ve Diğerleri { #custom-response-html-stream-file-others }\n\nVarsayılan olarak **FastAPI**, JSON response'lar döndürür.\n\nBunu, [Doğrudan bir Response döndür](response-directly.md) bölümünde gördüğünüz gibi doğrudan bir `Response` döndürerek geçersiz kılabilirsiniz.\n\nAncak doğrudan bir `Response` döndürürseniz (veya `JSONResponse` gibi herhangi bir alt sınıfını), veri otomatik olarak dönüştürülmez (bir `response_model` tanımlamış olsanız bile) ve dokümantasyon da otomatik üretilmez (örneğin, üretilen OpenAPI’nin parçası olarak HTTP header `Content-Type` içindeki ilgili \"media type\" dahil edilmez).\n\nBununla birlikte, *path operation decorator* içinde `response_class` parametresini kullanarak hangi `Response`’un (örn. herhangi bir `Response` alt sınıfı) kullanılacağını da ilan edebilirsiniz.\n\n*path operation function*’ınızdan döndürdüğünüz içerik, o `Response`’un içine yerleştirilir.\n\n/// note | Not\n\nMedia type’ı olmayan bir response class kullanırsanız, FastAPI response’unuzun content içermediğini varsayar; bu yüzden ürettiği OpenAPI dokümanında response formatını dokümante etmez.\n\n///\n\n## JSON Response'lar { #json-responses }\n\nVarsayılan olarak FastAPI JSON response'lar döndürür.\n\nBir [Response Model](../tutorial/response-model.md) tanımlarsanız, FastAPI veriyi Pydantic kullanarak JSON’a serialize eder.\n\nBir response modeli tanımlamazsanız, FastAPI [JSON Compatible Encoder](../tutorial/encoder.md) bölümünde açıklanan `jsonable_encoder`’ı kullanır ve sonucu bir `JSONResponse` içine koyar.\n\n`JSONResponse` örneğinde olduğu gibi JSON media type’ına (`application/json`) sahip bir `response_class` tanımlarsanız, döndürdüğünüz veri; *path operation decorator* içinde tanımladığınız herhangi bir Pydantic `response_model` ile otomatik olarak dönüştürülür (ve filtrelenir). Ancak veri Pydantic ile JSON bytes’a serialize edilmez; bunun yerine `jsonable_encoder` ile dönüştürülür ve ardından Python’un standart JSON kütüphanesini kullanarak bytes’a serialize edecek olan `JSONResponse` class’ına iletilir.\n\n### JSON Performansı { #json-performance }\n\nKısaca, en yüksek performansı istiyorsanız bir [Response Model](../tutorial/response-model.md) kullanın ve *path operation decorator* içinde `response_class` tanımlamayın.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## HTML Response { #html-response }\n\n**FastAPI**’den doğrudan HTML içeren bir response döndürmek için `HTMLResponse` kullanın.\n\n* `HTMLResponse` import edin.\n* *path operation decorator*’ınızın `response_class` parametresi olarak `HTMLResponse` verin.\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info | Bilgi\n\n`response_class` parametresi, response’un \"media type\"’ını tanımlamak için de kullanılır.\n\nBu durumda HTTP header `Content-Type`, `text/html` olarak ayarlanır.\n\nVe OpenAPI’de de bu şekilde dokümante edilir.\n\n///\n\n### Bir `Response` Döndür { #return-a-response }\n\n[Doğrudan bir Response döndür](response-directly.md) bölümünde görüldüğü gibi, *path operation* içinde doğrudan bir response döndürerek response’u override edebilirsiniz.\n\nYukarıdaki örneğin aynısı, bu sefer bir `HTMLResponse` döndürerek, şöyle görünebilir:\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning | Uyarı\n\n*path operation function*’ınızın doğrudan döndürdüğü bir `Response`, OpenAPI’de dokümante edilmez (örneğin `Content-Type` dokümante edilmez) ve otomatik interaktif dokümanlarda görünmez.\n\n///\n\n/// info | Bilgi\n\nElbette gerçek `Content-Type` header’ı, status code vb. değerler, döndürdüğünüz `Response` objesinden gelir.\n\n///\n\n### OpenAPI’de Dokümante Et ve `Response`’u Override Et { #document-in-openapi-and-override-response }\n\nResponse’u fonksiyonun içinden override etmek ama aynı zamanda OpenAPI’de \"media type\"’ı dokümante etmek istiyorsanız, `response_class` parametresini kullanıp ayrıca bir `Response` objesi döndürebilirsiniz.\n\nBu durumda `response_class` sadece OpenAPI *path operation*’ını dokümante etmek için kullanılır; sizin `Response`’unuz ise olduğu gibi kullanılır.\n\n#### Doğrudan bir `HTMLResponse` Döndür { #return-an-htmlresponse-directly }\n\nÖrneğin şöyle bir şey olabilir:\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\nBu örnekte `generate_html_response()` fonksiyonu, HTML’i bir `str` olarak döndürmek yerine zaten bir `Response` üretip döndürmektedir.\n\n`generate_html_response()` çağrısının sonucunu döndürerek, varsayılan **FastAPI** davranışını override edecek bir `Response` döndürmüş olursunuz.\n\nAma `response_class` içinde `HTMLResponse` da verdiğiniz için **FastAPI**, bunu OpenAPI’de ve interaktif dokümanlarda `text/html` ile HTML olarak nasıl dokümante edeceğini bilir:\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## Mevcut Response'lar { #available-responses }\n\nMevcut response'lardan bazıları aşağıdadır.\n\nUnutmayın: `Response` ile başka herhangi bir şeyi döndürebilir, hatta özel bir alt sınıf da oluşturabilirsiniz.\n\n/// note | Teknik Detaylar\n\n`from starlette.responses import HTMLResponse` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici için kolaylık olsun diye `starlette.responses` içindekileri `fastapi.responses` olarak da sağlar. Ancak mevcut response'ların çoğu doğrudan Starlette’ten gelir.\n\n///\n\n### `Response` { #response }\n\nAna `Response` class’ıdır; diğer tüm response'lar bundan türetilir.\n\nBunu doğrudan döndürebilirsiniz.\n\nŞu parametreleri kabul eder:\n\n* `content` - Bir `str` veya `bytes`.\n* `status_code` - Bir `int` HTTP status code.\n* `headers` - String’lerden oluşan bir `dict`.\n* `media_type` - Media type’ı veren bir `str`. Örn. `\"text/html\"`.\n\nFastAPI (aslında Starlette) otomatik olarak bir Content-Length header’ı ekler. Ayrıca `media_type`’a göre bir Content-Type header’ı ekler ve text türleri için sona bir charset ekler.\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\nYukarıda okuduğunuz gibi, bir miktar text veya bytes alır ve HTML response döndürür.\n\n### `PlainTextResponse` { #plaintextresponse }\n\nBir miktar text veya bytes alır ve düz metin response döndürür.\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\nBir miktar veri alır ve `application/json` olarak encode edilmiş bir response döndürür.\n\nYukarıda okuduğunuz gibi, **FastAPI**’de varsayılan response budur.\n\n/// note | Teknik Detaylar\n\nAncak bir response modeli veya dönüş tipi (return type) tanımlarsanız, veri doğrudan JSON’a serialize edilir ve JSON için doğru media type’a sahip bir response, `JSONResponse` class’ı kullanılmadan doğrudan döndürülür.\n\nBu, en iyi performansı elde etmenin ideal yoludur.\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\nHTTP redirect döndürür. Varsayılan olarak 307 status code (Temporary Redirect) kullanır.\n\n`RedirectResponse`’u doğrudan döndürebilirsiniz:\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\nVeya `response_class` parametresi içinde kullanabilirsiniz:\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\nBunu yaparsanız, *path operation* function’ınızdan doğrudan URL döndürebilirsiniz.\n\nBu durumda kullanılan `status_code`, `RedirectResponse` için varsayılan olan `307` olur.\n\n---\n\nAyrıca `status_code` parametresini `response_class` parametresiyle birlikte kullanabilirsiniz:\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\nBir async generator veya normal generator/iterator (içinde `yield` olan bir fonksiyon) alır ve response body’yi stream eder.\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | Teknik Detaylar\n\nBir `async` görev, yalnızca bir `await` noktasına geldiğinde iptal edilebilir. Eğer hiç `await` yoksa, generator (içinde `yield` olan fonksiyon) düzgün şekilde iptal edilemez ve iptal istendikten sonra bile çalışmaya devam edebilir.\n\nBu küçük örneğin `await` ifadesine ihtiyacı olmadığı için, event loop’un iptali ele alabilmesi adına `await anyio.sleep(0)` ekliyoruz.\n\nBüyük veya sonsuz akışlarda bu daha da önemlidir.\n\n///\n\n/// tip | İpucu\n\nDoğrudan bir `StreamingResponse` döndürmek yerine, muhtemelen [Veri Stream Etme](./stream-data.md) bölümündeki tarzı takip etmelisiniz; çok daha kullanışlıdır ve iptali arka planda sizin için halleder.\n\nJSON Lines stream ediyorsanız, [JSON Lines Stream Etme](../tutorial/stream-json-lines.md) kılavuzunu izleyin.\n\n///\n\n### `FileResponse` { #fileresponse }\n\nAsenkron olarak bir dosyayı response olarak stream eder.\n\nDiğer response türlerine göre instantiate ederken farklı argümanlar alır:\n\n* `path` - Stream edilecek dosyanın dosya path'i.\n* `headers` - Eklenecek özel header’lar; dictionary olarak.\n* `media_type` - Media type’ı veren string. Ayarlanmazsa, dosya adı veya path kullanılarak media type tahmin edilir.\n* `filename` - Ayarlanırsa response içindeki `Content-Disposition`’a dahil edilir.\n\nFile response'ları uygun `Content-Length`, `Last-Modified` ve `ETag` header’larını içerir.\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\n`response_class` parametresini de kullanabilirsiniz:\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\nBu durumda *path operation* function’ınızdan doğrudan dosya path'ini döndürebilirsiniz.\n\n## Özel response class { #custom-response-class }\n\n`Response`’dan türeterek kendi özel response class’ınızı oluşturabilir ve kullanabilirsiniz.\n\nÖrneğin, bazı ayarlarla [`orjson`](https://github.com/ijl/orjson) kullanmak istediğinizi varsayalım.\n\nDiyelim ki girintili ve biçimlendirilmiş JSON döndürmek istiyorsunuz; bunun için orjson seçeneği `orjson.OPT_INDENT_2`’yi kullanmak istiyorsunuz.\n\nBir `CustomORJSONResponse` oluşturabilirsiniz. Burada yapmanız gereken temel şey, content’i `bytes` olarak döndüren bir `Response.render(content)` metodu yazmaktır:\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\nArtık şunu döndürmek yerine:\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n...bu response şunu döndürür:\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\nElbette JSON’u formatlamaktan çok daha iyi şekillerde bundan faydalanabilirsiniz. 😉\n\n### `orjson` mı Response Model mi { #orjson-or-response-model }\n\nAradığınız şey performans ise, büyük olasılıkla bir `orjson` response’tan ziyade bir [Response Model](../tutorial/response-model.md) kullanmak daha iyi olacaktır.\n\nBir response modeliyle FastAPI, veriyi JSON’a serialize etmek için Pydantic’i kullanır; böylece diğer durumlarda olacağı gibi `jsonable_encoder` ile ara dönüşümlere gerek kalmaz.\n\nVe kaputun altında, Pydantic JSON’a serialize etmek için `orjson` ile aynı Rust tabanlı mekanizmaları kullanır; bu nedenle bir response modeliyle zaten en iyi performansı elde edersiniz.\n\n## Varsayılan response class { #default-response-class }\n\nBir **FastAPI** class instance’ı veya bir `APIRouter` oluştururken, varsayılan olarak hangi response class’ının kullanılacağını belirtebilirsiniz.\n\nBunu tanımlayan parametre `default_response_class`’tır.\n\nAşağıdaki örnekte **FastAPI**, tüm *path operations* için varsayılan olarak JSON yerine `HTMLResponse` kullanır.\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip | İpucu\n\nDaha önce olduğu gibi, *path operations* içinde `response_class`’ı yine override edebilirsiniz.\n\n///\n\n## Ek dokümantasyon { #additional-documentation }\n\nOpenAPI’de media type’ı ve daha birçok detayı `responses` kullanarak da tanımlayabilirsiniz: [OpenAPI’de Ek Response'lar](additional-responses.md).\n"
  },
  {
    "path": "docs/tr/docs/advanced/dataclasses.md",
    "content": "# Dataclass Kullanımı { #using-dataclasses }\n\nFastAPI, **Pydantic** üzerine inşa edilmiştir ve request/response tanımlamak için Pydantic model'lerini nasıl kullanacağınızı gösteriyordum.\n\nAncak FastAPI, [`dataclasses`](https://docs.python.org/3/library/dataclasses.html) kullanmayı da aynı şekilde destekler:\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\nBu destek hâlâ **Pydantic** sayesinde vardır; çünkü Pydantic, [`dataclasses` için dahili destek](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel) sunar.\n\nYani yukarıdaki kod Pydantic'i doğrudan kullanmasa bile, FastAPI bu standart dataclass'ları Pydantic'in kendi dataclass biçimine dönüştürmek için Pydantic'i kullanmaktadır.\n\nVe elbette aynı özellikleri destekler:\n\n* veri doğrulama (data validation)\n* veri serileştirme (data serialization)\n* veri dokümantasyonu (data documentation), vb.\n\nBu, Pydantic model'lerinde olduğu gibi çalışır. Aslında arka planda da aynı şekilde, Pydantic kullanılarak yapılır.\n\n/// info | Bilgi\n\nDataclass'ların, Pydantic model'lerinin yapabildiği her şeyi yapamadığını unutmayın.\n\nBu yüzden yine de Pydantic model'lerini kullanmanız gerekebilir.\n\nAncak elinizde zaten bir sürü dataclass varsa, bunları FastAPI ile bir web API'yi beslemek için kullanmak güzel bir numaradır. 🤓\n\n///\n\n## `response_model` İçinde Dataclass'lar { #dataclasses-in-response-model }\n\n`response_model` parametresinde `dataclasses` da kullanabilirsiniz:\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\nDataclass otomatik olarak bir Pydantic dataclass'ına dönüştürülür.\n\nBu sayede şeması API docs kullanıcı arayüzünde görünür:\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## İç İçe Veri Yapılarında Dataclass'lar { #dataclasses-in-nested-data-structures }\n\nİç içe veri yapıları oluşturmak için `dataclasses` ile diğer type annotation'ları da birleştirebilirsiniz.\n\nBazı durumlarda yine de Pydantic'in `dataclasses` sürümünü kullanmanız gerekebilir. Örneğin, otomatik oluşturulan API dokümantasyonunda hata alıyorsanız.\n\nBu durumda standart `dataclasses` yerine, drop-in replacement olan `pydantic.dataclasses` kullanabilirsiniz:\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. `field` hâlâ standart `dataclasses` içinden import edilir.\n\n2. `pydantic.dataclasses`, `dataclasses` için bir drop-in replacement'tır.\n\n3. `Author` dataclass'ı, `Item` dataclass'larından oluşan bir liste içerir.\n\n4. `Author` dataclass'ı, `response_model` parametresi olarak kullanılır.\n\n5. Request body olarak dataclass'larla birlikte diğer standart type annotation'ları da kullanabilirsiniz.\n\n    Bu örnekte, `Item` dataclass'larından oluşan bir listedir.\n\n6. Burada `items` içeren bir dictionary döndürüyoruz; `items` bir dataclass listesi.\n\n    FastAPI, veriyi JSON'a <dfn title=\"veriyi aktarılabilir bir formata dönüştürme\">serileştirme</dfn>yi yine başarır.\n\n7. Burada `response_model`, `Author` dataclass'larından oluşan bir listenin type annotation'ını kullanıyor.\n\n    Yine `dataclasses` ile standart type annotation'ları birleştirebilirsiniz.\n\n8. Bu *path operation function*, `async def` yerine normal `def` kullanıyor.\n\n    Her zaman olduğu gibi, FastAPI'de ihtiyaca göre `def` ve `async def`’i birlikte kullanabilirsiniz.\n\n    Hangisini ne zaman kullanmanız gerektiğine dair hızlı bir hatırlatma isterseniz, [`async` ve `await`](../async.md#in-a-hurry) dokümanındaki _\"In a hurry?\"_ bölümüne bakın.\n\n9. Bu *path operation function* dataclass döndürmüyor (isterse döndürebilir), onun yerine dahili verilerle bir dictionary listesi döndürüyor.\n\n    FastAPI, response'u dönüştürmek için (dataclass'ları içeren) `response_model` parametresini kullanacaktır.\n\nKarmaşık veri yapıları oluşturmak için `dataclasses` ile diğer type annotation'ları pek çok farklı kombinasyonda birleştirebilirsiniz.\n\nDaha spesifik ayrıntılar için yukarıdaki kod içi annotation ipuçlarına bakın.\n\n## Daha Fazla Öğrenin { #learn-more }\n\n`dataclasses`'ı diğer Pydantic model'leriyle de birleştirebilir, onlardan kalıtım alabilir, kendi model'lerinize dahil edebilirsiniz, vb.\n\nDaha fazlası için [Pydantic'in dataclasses dokümantasyonuna](https://docs.pydantic.dev/latest/concepts/dataclasses/) bakın.\n\n## Sürüm { #version }\n\nBu özellik FastAPI `0.67.0` sürümünden beri mevcuttur. 🔖\n"
  },
  {
    "path": "docs/tr/docs/advanced/events.md",
    "content": "# Lifespan Olayları { #lifespan-events }\n\nUygulama **başlamadan** önce çalıştırılması gereken mantığı (kodu) tanımlayabilirsiniz. Bu, bu kodun **bir kez**, uygulama **request almaya başlamadan önce** çalıştırılacağı anlamına gelir.\n\nBenzer şekilde, uygulama **kapanırken** çalıştırılması gereken mantığı (kodu) da tanımlayabilirsiniz. Bu durumda bu kod, muhtemelen **çok sayıda request** işlendi **sonra**, **bir kez** çalıştırılır.\n\nBu kod, uygulama request almaya **başlamadan** önce ve request’leri işlemeyi **bitirdikten** hemen sonra çalıştığı için, uygulamanın tüm **lifespan**’ını (birazdan \"lifespan\" kelimesi önemli olacak 😉) kapsar.\n\nBu yaklaşım, tüm uygulama boyunca kullanacağınız ve request’ler arasında **paylaşılan** **resource**’ları kurmak ve/veya sonrasında bunları **temizlemek** için çok faydalıdır. Örneğin bir veritabanı connection pool’u ya da paylaşılan bir machine learning modelini yüklemek gibi.\n\n## Kullanım Senaryosu { #use-case }\n\nÖnce bir **kullanım senaryosu** örneğiyle başlayalım, sonra bunu bununla nasıl çözeceğimize bakalım.\n\nRequest’leri işlemek için kullanmak istediğiniz bazı **machine learning modelleriniz** olduğunu hayal edelim. 🤖\n\nAynı modeller request’ler arasında paylaşılır; yani request başına bir model, kullanıcı başına bir model vb. gibi değil.\n\nModeli yüklemenin, diskten çok fazla **data** okunması gerektiği için **oldukça uzun sürebildiğini** düşünelim. Dolayısıyla bunu her request için yapmak istemezsiniz.\n\nModeli modülün/dosyanın en üst seviyesinde yükleyebilirdiniz; ancak bu, basit bir otomatik test çalıştırdığınızda bile **modelin yükleneceği** anlamına gelir. Böyle olunca test, kodun bağımsız bir kısmını çalıştırabilmek için önce modelin yüklenmesini beklemek zorunda kalır ve **yavaş** olur.\n\nBurada çözeceğimiz şey bu: modeli request’ler işlenmeden önce yükleyelim, ama kod yüklenirken değil; yalnızca uygulama request almaya başlamadan hemen önce.\n\n## Lifespan { #lifespan }\n\nBu *startup* ve *shutdown* mantığını, `FastAPI` uygulamasının `lifespan` parametresi ve bir \"context manager\" kullanarak tanımlayabilirsiniz (bunun ne olduğunu birazdan göstereceğim).\n\nÖnce bir örnekle başlayıp sonra ayrıntılarına bakalım.\n\nAşağıdaki gibi `yield` kullanan async bir `lifespan()` fonksiyonu oluşturuyoruz:\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\nBurada, `yield` öncesinde (sahte) model fonksiyonunu machine learning modellerini içeren dictionary’e koyarak, modeli yükleme gibi maliyetli bir *startup* işlemini simüle ediyoruz. Bu kod, *startup* sırasında, uygulama **request almaya başlamadan önce** çalıştırılır.\n\nArdından `yield`’den hemen sonra modeli bellekten kaldırıyoruz (unload). Bu kod, uygulama **request’leri işlemeyi bitirdikten sonra**, *shutdown*’dan hemen önce çalıştırılır. Örneğin memory veya GPU gibi resource’ları serbest bırakabilir.\n\n/// tip | İpucu\n\n`shutdown`, uygulamayı **durdurduğunuzda** gerçekleşir.\n\nBelki yeni bir sürüm başlatmanız gerekiyordur, ya da çalıştırmaktan sıkılmışsınızdır. 🤷\n\n///\n\n### Lifespan fonksiyonu { #lifespan-function }\n\nDikkat edilmesi gereken ilk şey, `yield` içeren async bir fonksiyon tanımlıyor olmamız. Bu, `yield` kullanan Dependencies’e oldukça benzer.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\nFonksiyonun `yield`’den önceki kısmı, uygulama başlamadan **önce** çalışır.\n\n`yield`’den sonraki kısım ise, uygulama işini bitirdikten **sonra** çalışır.\n\n### Async Context Manager { #async-context-manager }\n\nBakarsanız, fonksiyon `@asynccontextmanager` ile dekore edilmiş.\n\nBu da fonksiyonu \"**async context manager**\" denen şeye dönüştürür.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\nPython’da **context manager**, `with` ifadesi içinde kullanabildiğiniz bir yapıdır. Örneğin `open()` bir context manager olarak kullanılabilir:\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\nPython’ın güncel sürümlerinde bir de **async context manager** vardır. Bunu `async with` ile kullanırsınız:\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\nYukarıdaki gibi bir context manager veya async context manager oluşturduğunuzda, yaptığı şey şudur: `with` bloğuna girmeden önce `yield`’den önceki kodu çalıştırır, `with` bloğundan çıktıktan sonra da `yield`’den sonraki kodu çalıştırır.\n\nYukarıdaki kod örneğimizde bunu doğrudan kullanmıyoruz; bunun yerine FastAPI’ye veriyoruz ki o kullansın.\n\n`FastAPI` uygulamasının `lifespan` parametresi bir **async context manager** alır; dolayısıyla oluşturduğumuz yeni `lifespan` async context manager’ını buraya geçebiliriz.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## Alternatif Events (kullanımdan kaldırıldı) { #alternative-events-deprecated }\n\n/// warning | Uyarı\n\n*startup* ve *shutdown* işlemlerini yönetmenin önerilen yolu, yukarıda anlatıldığı gibi `FastAPI` uygulamasının `lifespan` parametresini kullanmaktır. Bir `lifespan` parametresi sağlarsanız, `startup` ve `shutdown` event handler’ları artık çağrılmaz. Ya tamamen `lifespan` ya da tamamen events; ikisi birden değil.\n\nMuhtemelen bu bölümü atlayabilirsiniz.\n\n///\n\n*startup* ve *shutdown* sırasında çalıştırılacak bu mantığı tanımlamanın alternatif bir yolu daha vardır.\n\nUygulama başlamadan önce veya uygulama kapanırken çalıştırılması gereken event handler’ları (fonksiyonları) tanımlayabilirsiniz.\n\nBu fonksiyonlar `async def` ile veya normal `def` ile tanımlanabilir.\n\n### `startup` eventi { #startup-event }\n\nUygulama başlamadan önce çalıştırılacak bir fonksiyon eklemek için, `\"startup\"` event’i ile tanımlayın:\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\nBu durumda `startup` event handler fonksiyonu, \"database\" öğesini (sadece bir `dict`) bazı değerlerle başlatır.\n\nBirden fazla event handler fonksiyonu ekleyebilirsiniz.\n\nVe tüm `startup` event handler’ları tamamlanmadan uygulamanız request almaya başlamaz.\n\n### `shutdown` eventi { #shutdown-event }\n\nUygulama kapanırken çalıştırılacak bir fonksiyon eklemek için, `\"shutdown\"` event’i ile tanımlayın:\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\nBurada `shutdown` event handler fonksiyonu, `log.txt` dosyasına `\"Application shutdown\"` satırını yazar.\n\n/// info | Bilgi\n\n`open()` fonksiyonunda `mode=\"a\"` \"append\" anlamına gelir; yani satır, önceki içeriği silmeden dosyada ne varsa onun sonuna eklenir.\n\n///\n\n/// tip | İpucu\n\nDikkat edin, bu örnekte bir dosyayla etkileşen standart Python `open()` fonksiyonunu kullanıyoruz.\n\nDolayısıyla disk’e yazılmasını beklemeyi gerektiren I/O (input/output) söz konusu.\n\nAncak `open()` `async` ve `await` kullanmaz.\n\nBu yüzden event handler fonksiyonunu `async def` yerine standart `def` ile tanımlarız.\n\n///\n\n### `startup` ve `shutdown` birlikte { #startup-and-shutdown-together }\n\n*startup* ve *shutdown* mantığınızın birbiriyle bağlantılı olma ihtimali yüksektir; bir şeyi başlatıp sonra bitirmek, bir resource edinip sonra serbest bırakmak vb. isteyebilirsiniz.\n\nBunu, ortak mantık veya değişken paylaşmayan ayrı fonksiyonlarda yapmak daha zordur; çünkü değerleri global değişkenlerde tutmanız veya benzer numaralar yapmanız gerekir.\n\nBu nedenle artık bunun yerine, yukarıda açıklandığı gibi `lifespan` kullanmanız önerilmektedir.\n\n## Teknik Detaylar { #technical-details }\n\nMeraklı nerd’ler için küçük bir teknik detay. 🤓\n\nAltta, ASGI teknik spesifikasyonunda bu, [Lifespan Protokolü](https://asgi.readthedocs.io/en/latest/specs/lifespan.html)’nün bir parçasıdır ve `startup` ile `shutdown` adında event’ler tanımlar.\n\n/// info | Bilgi\n\nStarlette `lifespan` handler’ları hakkında daha fazlasını [Starlette Lifespan dokümanları](https://www.starlette.dev/lifespan/) içinde okuyabilirsiniz.\n\nAyrıca kodunuzun başka bölgelerinde de kullanılabilecek lifespan state’i nasıl yöneteceğinizi de kapsar.\n\n///\n\n## Alt Uygulamalar { #sub-applications }\n\n🚨 Unutmayın: Bu lifespan event’leri (`startup` ve `shutdown`) yalnızca ana uygulama için çalıştırılır; [Alt Uygulamalar - Mounts](sub-applications.md) için çalıştırılmaz.\n"
  },
  {
    "path": "docs/tr/docs/advanced/generate-clients.md",
    "content": "# SDK Üretme { #generating-sdks }\n\n**FastAPI**, **OpenAPI** spesifikasyonunu temel aldığı için API'leri birçok aracın anlayabildiği standart bir formatta tanımlanabilir.\n\nBu sayede güncel **dokümantasyon**, birden fazla dilde istemci kütüphaneleri (<abbr title=\"Software Development Kits - Yazılım Geliştirme Kitleri\">**SDKs**</abbr>) ve kodunuzla senkron kalan **test** veya **otomasyon iş akışları** üretmek kolaylaşır.\n\nBu rehberde, FastAPI backend'iniz için bir **TypeScript SDK** üretmeyi öğreneceksiniz.\n\n## Açık Kaynak SDK Üreteçleri { #open-source-sdk-generators }\n\nEsnek bir seçenek olan [OpenAPI Generator](https://openapi-generator.tech/), **birçok programlama dilini** destekler ve OpenAPI spesifikasyonunuzdan SDK üretebilir.\n\n**TypeScript client**'lar için [Hey API](https://heyapi.dev/), TypeScript ekosistemi için özel olarak tasarlanmış, optimize bir deneyim sunan bir çözümdür.\n\nDaha fazla SDK üretecini [OpenAPI.Tools](https://openapi.tools/#sdk) üzerinde keşfedebilirsiniz.\n\n/// tip | İpucu\n\nFastAPI otomatik olarak **OpenAPI 3.1** spesifikasyonları üretir; bu yüzden kullanacağınız aracın bu sürümü desteklemesi gerekir.\n\n///\n\n## FastAPI Sponsorlarından SDK Üreteçleri { #sdk-generators-from-fastapi-sponsors }\n\nBu bölüm, FastAPI'yi sponsorlayan şirketlerin sunduğu **yatırım destekli** ve **şirket destekli** çözümleri öne çıkarır. Bu ürünler, yüksek kaliteli üretilen SDK'ların üzerine **ek özellikler** ve **entegrasyonlar** sağlar.\n\n✨ [**FastAPI'ye sponsor olarak**](../help-fastapi.md#sponsor-the-author) ✨ bu şirketler, framework'ün ve **ekosisteminin** sağlıklı ve **sürdürülebilir** kalmasına yardımcı olur.\n\nSponsor olmaları aynı zamanda FastAPI **topluluğuna** (size) güçlü bir bağlılığı da gösterir; yalnızca **iyi bir hizmet** sunmayı değil, aynı zamanda **güçlü ve gelişen bir framework** olan FastAPI'yi desteklemeyi de önemsediklerini gösterir. 🙇\n\nÖrneğin şunları deneyebilirsiniz:\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\nBu çözümlerin bazıları açık kaynak olabilir veya ücretsiz katman sunabilir; yani finansal bir taahhüt olmadan deneyebilirsiniz. Başka ticari SDK üreteçleri de vardır ve internette bulunabilir. 🤓\n\n## TypeScript SDK Oluşturma { #create-a-typescript-sdk }\n\nBasit bir FastAPI uygulamasıyla başlayalım:\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\n*Path operation*'ların, request payload ve response payload için kullandıkları modelleri `Item` ve `ResponseMessage` modelleriyle tanımladıklarına dikkat edin.\n\n### API Dokümanları { #api-docs }\n\n`/docs` adresine giderseniz, request'lerde gönderilecek ve response'larda alınacak veriler için **schema**'ları içerdiğini görürsünüz:\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\nBu schema'ları görebilirsiniz, çünkü uygulamada modellerle birlikte tanımlandılar.\n\nBu bilgi uygulamanın **OpenAPI schema**'sında bulunur ve sonrasında API dokümanlarında gösterilir.\n\nOpenAPI'ye dahil edilen, modellerden gelen bu bilginin aynısı **client code üretmek** için kullanılabilir.\n\n### Hey API { #hey-api }\n\nModelleri olan bir FastAPI uygulamamız olduğunda, Hey API ile bir TypeScript client üretebiliriz. Bunu yapmanın en hızlı yolu npx kullanmaktır.\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\nBu komut `./src/client` içine bir TypeScript SDK üretecektir.\n\nWeb sitelerinde [`@hey-api/openapi-ts` kurulumunu](https://heyapi.dev/openapi-ts/get-started) öğrenebilir ve [üretilen çıktıyı](https://heyapi.dev/openapi-ts/output) inceleyebilirsiniz.\n\n### SDK'yı Kullanma { #using-the-sdk }\n\nArtık client code'u import edip kullanabilirsiniz. Şuna benzer görünebilir; method'lar için otomatik tamamlama aldığınıza dikkat edin:\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\nAyrıca gönderilecek payload için de otomatik tamamlama alırsınız:\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip | İpucu\n\n`name` ve `price` için otomatik tamamlamaya dikkat edin; bunlar FastAPI uygulamasında, `Item` modelinde tanımlanmıştı.\n\n///\n\nGönderdiğiniz veriler için satır içi hatalar (inline errors) da alırsınız:\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\nResponse objesi de otomatik tamamlama sunacaktır:\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## Tag'lerle FastAPI Uygulaması { #fastapi-app-with-tags }\n\nBirçok durumda FastAPI uygulamanız daha büyük olacaktır ve farklı *path operation* gruplarını ayırmak için muhtemelen tag'leri kullanacaksınız.\n\nÖrneğin **items** için bir bölüm, **users** için başka bir bölüm olabilir ve bunları tag'lerle ayırabilirsiniz:\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### Tag'lerle TypeScript Client Üretme { #generate-a-typescript-client-with-tags }\n\nTag'leri kullanan bir FastAPI uygulaması için client ürettiğinizde, genelde client code da tag'lere göre ayrılır.\n\nBu sayede client code tarafında her şey doğru şekilde sıralanır ve gruplandırılır:\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\nBu örnekte şunlar var:\n\n* `ItemsService`\n* `UsersService`\n\n### Client Method İsimleri { #client-method-names }\n\nŞu an üretilen `createItemItemsPost` gibi method isimleri çok temiz görünmüyor:\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n...çünkü client üreteci, her *path operation* için OpenAPI'nin dahili **operation ID** değerini kullanır.\n\nOpenAPI, her operation ID'nin tüm *path operation*'lar arasında benzersiz olmasını ister. Bu yüzden FastAPI; operation ID'yi benzersiz tutabilmek için **function adı**, **path** ve **HTTP method/operation** bilgilerini birleştirerek üretir.\n\nAncak bunu bir sonraki adımda nasıl iyileştirebileceğinizi göstereceğim. 🤓\n\n## Özel Operation ID'ler ve Daha İyi Method İsimleri { #custom-operation-ids-and-better-method-names }\n\nBu operation ID'lerin **üretilme** şeklini **değiştirerek**, client'larda daha basit **method isimleri** elde edebilirsiniz.\n\nBu durumda, her operation ID'nin **benzersiz** olduğundan başka bir şekilde emin olmanız gerekir.\n\nÖrneğin, her *path operation*'ın bir tag'i olmasını sağlayabilir ve operation ID'yi **tag** ve *path operation* **adı**na (function adı) göre üretebilirsiniz.\n\n### Benzersiz ID Üreten Özel Fonksiyon { #custom-generate-unique-id-function }\n\nFastAPI, her *path operation* için bir **unique ID** kullanır. Bu ID, **operation ID** için ve ayrıca request/response'lar için gerekebilecek özel model isimleri için de kullanılır.\n\nBu fonksiyonu özelleştirebilirsiniz. Bir `APIRoute` alır ve string döndürür.\n\nÖrneğin burada ilk tag'i (muhtemelen tek tag'iniz olur) ve *path operation* adını (function adı) kullanıyor.\n\nSonrasında bu özel fonksiyonu `generate_unique_id_function` parametresiyle **FastAPI**'ye geçebilirsiniz:\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### Özel Operation ID'lerle TypeScript Client Üretme { #generate-a-typescript-client-with-custom-operation-ids }\n\nArtık client'ı tekrar üretirseniz, geliştirilmiş method isimlerini göreceksiniz:\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\nGördüğünüz gibi method isimleri artık önce tag'i, sonra function adını içeriyor; URL path'i ve HTTP operation bilgisini artık taşımıyor.\n\n### Client Üretecine Vermeden Önce OpenAPI Spesifikasyonunu Ön İşlemek { #preprocess-the-openapi-specification-for-the-client-generator }\n\nÜretilen kodda hâlâ bazı **tekrarlanan bilgiler** var.\n\nBu method'un **items** ile ilişkili olduğunu zaten biliyoruz; çünkü bu kelime `ItemsService` içinde var (tag'den geliyor). Ama method adında da tag adı önek olarak duruyor. 😕\n\nOpenAPI genelinde muhtemelen bunu korumak isteriz; çünkü operation ID'lerin **benzersiz** olmasını sağlar.\n\nAncak üretilen client için, client'ları üretmeden hemen önce OpenAPI operation ID'lerini **değiştirip**, method isimlerini daha hoş ve **temiz** hale getirebiliriz.\n\nOpenAPI JSON'u `openapi.json` diye bir dosyaya indirip, şu tarz bir script ile **öndeki tag'i kaldırabiliriz**:\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\nBununla operation ID'ler `items-get_items` gibi değerlerden sadece `get_items` olacak şekilde yeniden adlandırılır; böylece client üreteci daha basit method isimleri üretebilir.\n\n### Ön İşlenmiş OpenAPI ile TypeScript Client Üretme { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\nSonuç artık bir `openapi.json` dosyasında olduğuna göre, input konumunu güncellemeniz gerekir:\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\nYeni client'ı ürettikten sonra, tüm **otomatik tamamlama**, **satır içi hatalar**, vb. ile birlikte **temiz method isimleri** elde edersiniz:\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## Faydalar { #benefits }\n\nOtomatik üretilen client'ları kullanınca şu alanlarda **otomatik tamamlama** elde edersiniz:\n\n* Method'lar.\n* Body'deki request payload'ları, query parametreleri, vb.\n* Response payload'ları.\n\nAyrıca her şey için **satır içi hatalar** (inline errors) da olur.\n\nBackend kodunu her güncellediğinizde ve frontend'i **yeniden ürettiğinizde**, yeni *path operation*'lar method olarak eklenir, eskileri kaldırılır ve diğer değişiklikler de üretilen koda yansır. 🤓\n\nBu, bir şey değiştiğinde client code'a otomatik olarak **yansıyacağı** anlamına gelir. Ayrıca client'ı **build** ettiğinizde, kullanılan verilerde bir **uyuşmazlık** (mismatch) varsa hata alırsınız.\n\nBöylece üretimde son kullanıcılara hata yansımasını beklemek ve sonra sorunun nerede olduğunu debug etmeye çalışmak yerine, geliştirme sürecinin çok erken aşamalarında **birçok hatayı tespit edersiniz**. ✨\n"
  },
  {
    "path": "docs/tr/docs/advanced/index.md",
    "content": "# Gelişmiş Kullanıcı Rehberi { #advanced-user-guide }\n\n## Ek Özellikler { #additional-features }\n\nAna [Tutorial - User Guide](../tutorial/index.md) sayfası, **FastAPI**'nin tüm temel özelliklerini tanımanız için yeterli olmalıdır.\n\nSonraki bölümlerde diğer seçenekleri, konfigürasyonları ve ek özellikleri göreceksiniz.\n\n/// tip | İpucu\n\nSonraki bölümler **mutlaka \"gelişmiş\" olmak zorunda değildir**.\n\nVe kullanım amacınıza bağlı olarak, çözüm bunlardan birinde olabilir.\n\n///\n\n## Önce Tutorial'ı Okuyun { #read-the-tutorial-first }\n\nAna [Tutorial - User Guide](../tutorial/index.md) sayfasındaki bilgilerle **FastAPI**'nin çoğu özelliğini yine de kullanabilirsiniz.\n\nVe sonraki bölümler, onu zaten okuduğunuzu ve bu temel fikirleri bildiğinizi varsayar.\n"
  },
  {
    "path": "docs/tr/docs/advanced/json-base64-bytes.md",
    "content": "# JSON'da Bytes'i Base64 Olarak Kullanma { #json-with-bytes-as-base64 }\n\nUygulamanız JSON veri alıp gönderiyorsa ve bunun içine ikili (binary) veri eklemeniz gerekiyorsa, veriyi base64 olarak encode edebilirsiniz.\n\n## Base64 ve Dosyalar { #base64-vs-files }\n\nİkili veriyi JSON içinde encode etmek yerine, yükleme için [Request Files](../tutorial/request-files.md) ve gönderim için [Custom Response - FileResponse](./custom-response.md#fileresponse--fileresponse-) kullanıp kullanamayacağınıza önce bir bakın.\n\nJSON sadece UTF-8 ile encode edilmiş string'ler içerebilir, dolayısıyla ham bytes içeremez.\n\nBase64 ikili veriyi string olarak encode edebilir, ancak bunu yapmak için orijinal ikili veriden daha fazla karakter kullanır; bu yüzden genellikle normal dosyalardan daha verimsiz olur.\n\nBase64'ü sadece gerçekten JSON içine ikili veri koymanız gerekiyorsa ve bunun için dosya kullanamıyorsanız tercih edin.\n\n## Pydantic `bytes` { #pydantic-bytes }\n\n`bytes` alanları olan bir Pydantic model tanımlayabilir, ardından model config'inde `val_json_bytes` kullanarak giriş JSON verisini base64 ile doğrulamasını (validate) söyleyebilirsiniz; bu doğrulamanın bir parçası olarak base64 string'i bytes'a decode eder.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\n`/docs`'a bakarsanız, `data` alanının base64 ile encode edilmiş bytes beklediğini görürsünüz:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\nŞöyle bir request gönderebilirsiniz:\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip | İpucu\n\n`aGVsbG8=` değeri, `hello` kelimesinin base64 encoding'idir.\n\n///\n\nSonrasında Pydantic base64 string'ini decode eder ve modelin `data` alanında size orijinal bytes'ı verir.\n\nŞöyle bir response alırsınız:\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## Çıkış Verisi için Pydantic `bytes` { #pydantic-bytes-for-output-data }\n\nÇıkış verisi için de model config'inde `ser_json_bytes` ile `bytes` alanları kullanabilirsiniz; Pydantic JSON response üretirken bytes'ı base64 olarak serialize eder.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## Giriş ve Çıkış Verisi için Pydantic `bytes` { #pydantic-bytes-for-input-and-output-data }\n\nElbette, aynı modeli base64 kullanacak şekilde yapılandırıp hem girişte (*validate*) `val_json_bytes` ile hem de çıkışta (*serialize*) `ser_json_bytes` ile JSON veri alıp gönderirken kullanabilirsiniz.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/tr/docs/advanced/middleware.md",
    "content": "# İleri Seviye Middleware { #advanced-middleware }\n\nAna tutorial'da uygulamanıza [Özel Middleware](../tutorial/middleware.md) eklemeyi gördünüz.\n\nArdından [`CORSMiddleware` ile CORS'u yönetmeyi](../tutorial/cors.md) de okudunuz.\n\nBu bölümde diğer middleware'leri nasıl kullanacağımıza bakacağız.\n\n## ASGI middleware'leri ekleme { #adding-asgi-middlewares }\n\n**FastAPI**, Starlette üzerine kurulu olduğu ve <abbr title=\"Asynchronous Server Gateway Interface - Asenkron Sunucu Ağ Geçidi Arayüzü\">ASGI</abbr> spesifikasyonunu uyguladığı için, herhangi bir ASGI middleware'ini kullanabilirsiniz.\n\nBir middleware'in çalışması için özellikle FastAPI ya da Starlette için yazılmış olması gerekmez; ASGI spec'ine uyduğu sürece yeterlidir.\n\nGenel olarak ASGI middleware'leri, ilk argüman olarak bir ASGI app almayı bekleyen class'lar olur.\n\nDolayısıyla üçüncü taraf ASGI middleware'lerinin dokümantasyonunda muhtemelen şöyle bir şey yapmanızı söylerler:\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\nAncak FastAPI (aslında Starlette) bunu yapmanın daha basit bir yolunu sunar; böylece dahili middleware'ler server hatalarını doğru şekilde ele alır ve özel exception handler'lar düzgün çalışır.\n\nBunun için `app.add_middleware()` kullanırsınız (CORS örneğindeki gibi).\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` ilk argüman olarak bir middleware class'ı alır ve middleware'e aktarılacak ek argümanları da kabul eder.\n\n## Entegre middleware'ler { #integrated-middlewares }\n\n**FastAPI**, yaygın kullanım senaryoları için birkaç middleware içerir; şimdi bunları nasıl kullanacağımıza bakacağız.\n\n/// note | Teknik Detaylar\n\nBir sonraki örneklerde `from starlette.middleware.something import SomethingMiddleware` kullanmanız da mümkündür.\n\n**FastAPI**, size (geliştirici olarak) kolaylık olsun diye `fastapi.middleware` içinde bazı middleware'leri sağlar. Ancak mevcut middleware'lerin çoğu doğrudan Starlette'ten gelir.\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\nGelen tüm request'lerin `https` veya `wss` olmasını zorunlu kılar.\n\n`http` veya `ws` olarak gelen herhangi bir request, bunun yerine güvenli şemaya redirect edilir.\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\nHTTP Host Header saldırılarına karşı korunmak için, gelen tüm request'lerde `Host` header'ının doğru ayarlanmış olmasını zorunlu kılar.\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\nAşağıdaki argümanlar desteklenir:\n\n* `allowed_hosts` - Hostname olarak izin verilmesi gereken domain adlarının listesi. `*.example.com` gibi wildcard domain'ler subdomain eşleştirmesi için desteklenir. Herhangi bir hostname'e izin vermek için `allowed_hosts=[\"*\"]` kullanın veya middleware'i hiç eklemeyin.\n* `www_redirect` - True olarak ayarlanırsa, izin verilen host'ların www olmayan sürümlerine gelen request'ler www sürümlerine redirect edilir. Varsayılanı `True`'dur.\n\nGelen bir request doğru şekilde doğrulanmazsa `400` response gönderilir.\n\n## `GZipMiddleware` { #gzipmiddleware }\n\n`Accept-Encoding` header'ında `\"gzip\"` içeren herhangi bir request için GZip response'larını yönetir.\n\nMiddleware hem standart hem de streaming response'ları ele alır.\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\nAşağıdaki argümanlar desteklenir:\n\n* `minimum_size` - Bayt cinsinden bu minimum boyuttan küçük response'lara GZip uygulama. Varsayılanı `500`'dür.\n* `compresslevel` - GZip sıkıştırması sırasında kullanılır. 1 ile 9 arasında bir tamsayıdır. Varsayılanı `9`'dur. Daha düşük değer daha hızlı sıkıştırma ama daha büyük dosya boyutları üretir; daha yüksek değer daha yavaş sıkıştırma ama daha küçük dosya boyutları üretir.\n\n## Diğer middleware'ler { #other-middlewares }\n\nBaşka birçok ASGI middleware'i vardır.\n\nÖrneğin:\n\n* [Uvicorn'un `ProxyHeadersMiddleware`'i](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n* [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\nDiğer mevcut middleware'leri görmek için [Starlette'in Middleware dokümanlarına](https://www.starlette.dev/middleware/) ve [ASGI Awesome List](https://github.com/florimondmanca/awesome-asgi) listesine bakın.\n"
  },
  {
    "path": "docs/tr/docs/advanced/openapi-callbacks.md",
    "content": "# OpenAPI Callback'leri { #openapi-callbacks }\n\nBaşka biri tarafından (muhtemelen API'nizi kullanacak olan aynı geliştirici tarafından) oluşturulmuş bir *external API*'ye request tetikleyebilen bir *path operation* ile bir API oluşturabilirsiniz.\n\nAPI uygulamanızın *external API*'yi çağırdığı sırada gerçekleşen sürece \"callback\" denir. Çünkü dış geliştiricinin yazdığı yazılım API'nize bir request gönderir ve ardından API'niz geri çağrı yaparak (*call back*), bir *external API*'ye request gönderir (muhtemelen aynı geliştiricinin oluşturduğu).\n\nBu durumda, o external API'nin nasıl görünmesi gerektiğini dokümante etmek isteyebilirsiniz. Hangi *path operation*'a sahip olmalı, hangi body'yi beklemeli, hangi response'u döndürmeli, vb.\n\n## Callback'leri olan bir uygulama { #an-app-with-callbacks }\n\nBunların hepsine bir örnekle bakalım.\n\nFatura oluşturmayı sağlayan bir uygulama geliştirdiğinizi düşünün.\n\nBu faturaların `id`, `title` (opsiyonel), `customer` ve `total` alanları olacak.\n\nAPI'nizin kullanıcısı (external bir geliştirici) API'nizde bir POST request ile fatura oluşturacak.\n\nSonra API'niz (varsayalım ki):\n\n* Faturayı external geliştiricinin bir müşterisine gönderir.\n* Parayı tahsil eder.\n* API kullanıcısına (external geliştiriciye) tekrar bir bildirim gönderir.\n    * Bu, external geliştiricinin sağladığı bir *external API*'ye (sizin API'nizden) bir POST request gönderilerek yapılır (işte bu \"callback\"tir).\n\n## Normal **FastAPI** uygulaması { #the-normal-fastapi-app }\n\nÖnce callback eklemeden önce normal API uygulamasının nasıl görüneceğine bakalım.\n\nBir `Invoice` body alacak bir *path operation*'ı ve callback için URL'yi taşıyacak `callback_url` adlı bir query parametresi olacak.\n\nBu kısım oldukça standart; kodun çoğu muhtemelen size zaten tanıdık gelecektir:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip | İpucu\n\n`callback_url` query parametresi, Pydantic'in [Url](https://docs.pydantic.dev/latest/api/networks/) tipini kullanır.\n\n///\n\nTek yeni şey, *path operation decorator*'ına argüman olarak verilen `callbacks=invoices_callback_router.routes`. Bunun ne olduğuna şimdi bakacağız.\n\n## Callback'i dokümante etmek { #documenting-the-callback }\n\nCallback'in gerçek kodu, büyük ölçüde sizin API uygulamanıza bağlıdır.\n\nVe bir uygulamadan diğerine oldukça değişebilir.\n\nSadece bir-iki satır kod bile olabilir, örneğin:\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\nAncak callback'in belki de en önemli kısmı, API'nizin kullanıcısının (external geliştiricinin) *external API*'yi doğru şekilde uyguladığından emin olmaktır; çünkü sizin API'niz callback'in request body'sinde belirli veriler gönderecektir, vb.\n\nDolayısıyla sıradaki adım olarak, sizin API'nizden callback almak için o *external API*'nin nasıl görünmesi gerektiğini dokümante eden kodu ekleyeceğiz.\n\nBu dokümantasyon, API'nizde `/docs` altındaki Swagger UI'da görünecek ve external geliştiricilere *external API*'yi nasıl inşa edeceklerini gösterecek.\n\nBu örnek callback'in kendisini implemente etmiyor (o zaten tek satır kod olabilir), sadece dokümantasyon kısmını ekliyor.\n\n/// tip | İpucu\n\nGerçek callback, sadece bir HTTP request'tir.\n\nCallback'i kendiniz implemente ederken [HTTPX](https://www.python-httpx.org) veya [Requests](https://requests.readthedocs.io/) gibi bir şey kullanabilirsiniz.\n\n///\n\n## Callback dokümantasyon kodunu yazın { #write-the-callback-documentation-code }\n\nBu kod uygulamanızda çalıştırılmayacak; sadece o *external API*'nin nasıl görünmesi gerektiğini dokümante etmek için gerekiyor.\n\nAncak **FastAPI** ile bir API için otomatik dokümantasyonu kolayca nasıl üreteceğinizi zaten biliyorsunuz.\n\nO halde aynı bilgiyi kullanarak, *external API*'nin nasıl görünmesi gerektiğini dokümante edeceğiz... external API'nin implemente etmesi gereken *path operation*'ları oluşturarak (API'nizin çağıracağı olanlar).\n\n/// tip | İpucu\n\nBir callback'i dokümante eden kodu yazarken, kendinizi external geliştirici olarak hayal etmek faydalı olabilir. Ve şu anda sizin API'nizi değil, *external API*'yi implemente ettiğinizi düşünün.\n\nBu bakış açısını (external geliştiricinin bakış açısını) geçici olarak benimsemek; parametreleri nereye koyacağınızı, body için Pydantic modelini, response için modelini vb. external API tarafında nasıl tasarlayacağınızı daha net hale getirebilir.\n\n///\n\n### Bir callback `APIRouter` oluşturun { #create-a-callback-apirouter }\n\nÖnce bir veya daha fazla callback içerecek yeni bir `APIRouter` oluşturun.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### Callback *path operation*'ını oluşturun { #create-the-callback-path-operation }\n\nCallback *path operation*'ını oluşturmak için, yukarıda oluşturduğunuz aynı `APIRouter`'ı kullanın.\n\nNormal bir FastAPI *path operation*'ı gibi görünmelidir:\n\n* Muhtemelen alması gereken body'nin bir deklarasyonu olmalı, örn. `body: InvoiceEvent`.\n* Ayrıca döndürmesi gereken response'un deklarasyonu da olabilir, örn. `response_model=InvoiceEventReceived`.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\nNormal bir *path operation*'dan 2 temel farkı vardır:\n\n* Gerçek bir koda ihtiyaç duymaz; çünkü uygulamanız bu kodu asla çağırmayacak. Bu yalnızca *external API*'yi dokümante etmek için kullanılır. Yani fonksiyon sadece `pass` içerebilir.\n* *path*, bir [OpenAPI 3 expression](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (aşağıda daha fazlası) içerebilir; böylece parametreler ve sizin API'nize gönderilen orijinal request'in bazı parçalarıyla değişkenler kullanılabilir.\n\n### Callback path ifadesi { #the-callback-path-expression }\n\nCallback *path*'i, sizin API'nize gönderilen orijinal request'in bazı parçalarını içerebilen bir [OpenAPI 3 expression](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) barındırabilir.\n\nBu örnekte, bu bir `str`:\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\nYani API'nizin kullanıcısı (external geliştirici) sizin API'nize şu adrese bir request gönderirse:\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\nve JSON body şu şekilde olursa:\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\no zaman sizin API'niz faturayı işleyecek ve daha sonra bir noktada `callback_url`'ye (yani *external API*'ye) bir callback request gönderecek:\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\nve JSON body yaklaşık şöyle bir şey içerecek:\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\nve o *external API*'den şu gibi bir JSON body içeren response bekleyecek:\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip | İpucu\n\nCallback URL'sinin, `callback_url` içindeki query parametresi olarak alınan URL'yi (`https://www.external.org/events`) ve ayrıca JSON body'nin içindeki fatura `id`'sini (`2expen51ve`) birlikte kullandığına dikkat edin.\n\n///\n\n### Callback router'ını ekleyin { #add-the-callback-router }\n\nBu noktada, yukarıda oluşturduğunuz callback router'ında gerekli callback *path operation*'ları (external geliştiricinin *external API*'de implemente etmesi gerekenler) hazır.\n\nŞimdi sizin API'nizin *path operation decorator*'ında `callbacks` parametresini kullanarak, callback router'ının `.routes` attribute'unu (bu aslında route/*path operation*'lardan oluşan bir `list`) geçin:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip | İpucu\n\n`callback=` içine router'ın kendisini (`invoices_callback_router`) değil, `invoices_callback_router.routes` şeklinde `.routes` attribute'unu verdiğinize dikkat edin.\n\n///\n\n### Dokümanları kontrol edin { #check-the-docs }\n\nArtık uygulamanızı başlatıp [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) adresine gidebilirsiniz.\n\n*Path operation*'ınız için, *external API*'nin nasıl görünmesi gerektiğini gösteren bir \"Callbacks\" bölümünü içeren dokümanları göreceksiniz:\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/tr/docs/advanced/openapi-webhooks.md",
    "content": "# OpenAPI Webhook'lar { #openapi-webhooks }\n\nBazı durumlarda, API'nizi kullanan **kullanıcılara** uygulamanızın *onların* uygulamasını (request göndererek) bazı verilerle çağırabileceğini; genellikle bir tür **event** hakkında **bildirim** yapmak için kullanacağını söylemek istersiniz.\n\nBu da şunu ifade eder: Kullanıcılarınızın API'nize request göndermesi şeklindeki normal akış yerine, request'i **sizin API'niz** (veya uygulamanız) **onların sistemine** (onların API'sine, onların uygulamasına) **gönderebilir**.\n\nBuna genellikle **webhook** denir.\n\n## Webhook adımları { #webhooks-steps }\n\nSüreç genellikle şöyledir: Kodunuzda göndereceğiniz mesajın ne olduğunu, yani request'in **body**'sini **siz tanımlarsınız**.\n\nAyrıca uygulamanızın bu request'leri veya event'leri hangi **anlarda** göndereceğini de bir şekilde tanımlarsınız.\n\nVe **kullanıcılarınız** da bir şekilde (örneğin bir web dashboard üzerinden) uygulamanızın bu request'leri göndermesi gereken **URL**'yi tanımlar.\n\nWebhook'lar için URL'lerin nasıl kaydedileceğine dair tüm **mantık** ve bu request'leri gerçekten gönderen kod tamamen size bağlıdır. Bunu **kendi kodunuzda** istediğiniz gibi yazarsınız.\n\n## **FastAPI** ve OpenAPI ile webhook'ları dokümante etmek { #documenting-webhooks-with-fastapi-and-openapi }\n\n**FastAPI** ile OpenAPI kullanarak bu webhook'ların adlarını, uygulamanızın gönderebileceği HTTP operation türlerini (örn. `POST`, `PUT`, vb.) ve uygulamanızın göndereceği request **body**'lerini tanımlayabilirsiniz.\n\nBu, kullanıcılarınızın **webhook** request'lerinizi alacak şekilde **API'lerini implement etmesini** çok daha kolaylaştırabilir; hatta kendi API kodlarının bir kısmını otomatik üretebilirler.\n\n/// info | Bilgi\n\nWebhook'lar OpenAPI 3.1.0 ve üzeri sürümlerde mevcuttur; FastAPI `0.99.0` ve üzeri tarafından desteklenir.\n\n///\n\n## Webhook'ları olan bir uygulama { #an-app-with-webhooks }\n\nBir **FastAPI** uygulaması oluşturduğunuzda, *webhook*'ları tanımlamak için kullanabileceğiniz bir `webhooks` attribute'u vardır; *path operation* tanımlar gibi, örneğin `@app.webhooks.post()` ile.\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\nTanımladığınız webhook'lar **OpenAPI** şemasında ve otomatik **docs UI**'da yer alır.\n\n/// info | Bilgi\n\n`app.webhooks` nesnesi aslında sadece bir `APIRouter`'dır; uygulamanızı birden fazla dosya ile yapılandırırken kullanacağınız türün aynısıdır.\n\n///\n\nDikkat edin: Webhook'larda aslında bir *path* (ör. `/items/`) deklare etmiyorsunuz; oraya verdiğiniz metin sadece webhook'un bir **identifier**'ıdır (event'in adı). Örneğin `@app.webhooks.post(\"new-subscription\")` içinde webhook adı `new-subscription`'dır.\n\nBunun nedeni, webhook request'ini almak istedikleri gerçek **URL path**'i **kullanıcılarınızın** başka bir şekilde (örn. bir web dashboard üzerinden) tanımlamasının beklenmesidir.\n\n### Dokümanları kontrol edin { #check-the-docs }\n\nŞimdi uygulamanızı başlatıp [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) adresine gidin.\n\nDokümanlarınızda normal *path operation*'ları ve artık bazı **webhook**'ları da göreceksiniz:\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/tr/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# Path Operation İleri Düzey Yapılandırma { #path-operation-advanced-configuration }\n\n## OpenAPI operationId { #openapi-operationid }\n\n/// warning | Uyarı\n\nOpenAPI konusunda \"uzman\" değilseniz, muhtemelen buna ihtiyacınız yok.\n\n///\n\n*path operation*’ınızda kullanılacak OpenAPI `operationId` değerini `operation_id` parametresiyle ayarlayabilirsiniz.\n\nBunun her operation için benzersiz olduğundan emin olmanız gerekir.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### operationId olarak *path operation function* adını kullanma { #using-the-path-operation-function-name-as-the-operationid }\n\nAPI’lerinizin function adlarını `operationId` olarak kullanmak istiyorsanız, hepsini dolaşıp her *path operation*’ın `operation_id` değerini `APIRoute.name` ile override edebilirsiniz.\n\nBunu, tüm *path operation*’ları ekledikten sonra yapmalısınız.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip | İpucu\n\n`app.openapi()` fonksiyonunu manuel olarak çağırıyorsanız, bunu yapmadan önce `operationId`’leri güncellemelisiniz.\n\n///\n\n/// warning | Uyarı\n\nBunu yaparsanız, her bir *path operation function*’ın adının benzersiz olduğundan emin olmanız gerekir.\n\nFarklı modüllerde (Python dosyalarında) olsalar bile.\n\n///\n\n## OpenAPI’den Hariç Tutma { #exclude-from-openapi }\n\nBir *path operation*’ı üretilen OpenAPI şemasından (dolayısıyla otomatik dokümantasyon sistemlerinden) hariç tutmak için `include_in_schema` parametresini kullanın ve `False` yapın:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## Docstring’den İleri Düzey Açıklama { #advanced-description-from-docstring }\n\nOpenAPI için, bir *path operation function*’ın docstring’inden kullanılacak satırları sınırlandırabilirsiniz.\n\nBir `\\f` (escape edilmiş \"form feed\" karakteri) eklerseniz, **FastAPI** OpenAPI için kullanılan çıktıyı bu noktada **keser**.\n\nDokümantasyonda görünmez, ancak diğer araçlar (Sphinx gibi) geri kalan kısmı kullanabilir.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## Ek Responses { #additional-responses }\n\nMuhtemelen bir *path operation* için `response_model` ve `status_code` tanımlamayı görmüşsünüzdür.\n\nBu, bir *path operation*’ın ana response’u ile ilgili metadata’yı tanımlar.\n\nEk response’ları; modelleri, status code’ları vb. ile birlikte ayrıca da tanımlayabilirsiniz.\n\nDokümantasyonda bununla ilgili ayrı bir bölüm var; [OpenAPI’de Ek Responses](additional-responses.md) sayfasından okuyabilirsiniz.\n\n## OpenAPI Extra { #openapi-extra }\n\nUygulamanızda bir *path operation* tanımladığınızda, **FastAPI** OpenAPI şemasına dahil edilmek üzere o *path operation* ile ilgili metadata’yı otomatik olarak üretir.\n\n/// note | Teknik Detaylar\n\nOpenAPI spesifikasyonunda buna [Operation Nesnesi](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object) denir.\n\n///\n\nBu, *path operation* hakkında tüm bilgileri içerir ve otomatik dokümantasyonu üretmek için kullanılır.\n\n`tags`, `parameters`, `requestBody`, `responses` vb. alanları içerir.\n\nBu *path operation*’a özel OpenAPI şeması normalde **FastAPI** tarafından otomatik üretilir; ancak siz bunu genişletebilirsiniz.\n\n/// tip | İpucu\n\nBu, düşük seviyeli bir genişletme noktasıdır.\n\nYalnızca ek response’lar tanımlamanız gerekiyorsa, bunu yapmanın daha pratik yolu [OpenAPI’de Ek Responses](additional-responses.md) kullanmaktır.\n\n///\n\nBir *path operation* için OpenAPI şemasını `openapi_extra` parametresiyle genişletebilirsiniz.\n\n### OpenAPI Extensions { #openapi-extensions }\n\nÖrneğin bu `openapi_extra`, [OpenAPI Uzantıları](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) tanımlamak için faydalı olabilir:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\nOtomatik API dokümanlarını açtığınızda, extension’ınız ilgili *path operation*’ın en altında görünür.\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\nAyrıca ortaya çıkan OpenAPI’yi (API’nizde `/openapi.json`) görüntülerseniz, extension’ınızı ilgili *path operation*’ın bir parçası olarak orada da görürsünüz:\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### Özel OpenAPI *path operation* şeması { #custom-openapi-path-operation-schema }\n\n`openapi_extra` içindeki dictionary, *path operation* için otomatik üretilen OpenAPI şemasıyla derinlemesine (deep) birleştirilir.\n\nBöylece otomatik üretilen şemaya ek veri ekleyebilirsiniz.\n\nÖrneğin, Pydantic ile FastAPI’nin otomatik özelliklerini kullanmadan request’i kendi kodunuzla okuyup doğrulamaya karar verebilirsiniz; ancak yine de OpenAPI şemasında request’i tanımlamak isteyebilirsiniz.\n\nBunu `openapi_extra` ile yapabilirsiniz:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\nBu örnekte herhangi bir Pydantic model tanımlamadık. Hatta request body JSON olarak <dfn title=\"bytes gibi düz bir formattan, ör. bytes, Python nesnelerine dönüştürme\">ayrıştırılmıyor</dfn>; doğrudan `bytes` olarak okunuyor ve `magic_data_reader()` fonksiyonu bunu bir şekilde parse etmekten sorumlu oluyor.\n\nBuna rağmen, request body için beklenen şemayı tanımlayabiliriz.\n\n### Özel OpenAPI content type { #custom-openapi-content-type }\n\nAynı yöntemi kullanarak, Pydantic model ile JSON Schema’yı tanımlayıp bunu *path operation* için özel OpenAPI şeması bölümüne dahil edebilirsiniz.\n\nVe bunu, request içindeki veri tipi JSON olmasa bile yapabilirsiniz.\n\nÖrneğin bu uygulamada, FastAPI’nin Pydantic modellerinden JSON Schema çıkarmaya yönelik entegre işlevselliğini ve JSON için otomatik doğrulamayı kullanmıyoruz. Hatta request content type’ını JSON değil, YAML olarak tanımlıyoruz:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\nBuna rağmen, varsayılan entegre işlevselliği kullanmasak da, YAML olarak almak istediğimiz veri için JSON Schema’yı manuel üretmek üzere bir Pydantic model kullanmaya devam ediyoruz.\n\nArdından request’i doğrudan kullanıp body’yi `bytes` olarak çıkarıyoruz. Bu da FastAPI’nin request payload’ını JSON olarak parse etmeye çalışmayacağı anlamına gelir.\n\nSonrasında kodumuzda bu YAML içeriğini doğrudan parse ediyor, ardından YAML içeriğini doğrulamak için yine aynı Pydantic modeli kullanıyoruz:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip | İpucu\n\nBurada aynı Pydantic modeli tekrar kullanıyoruz.\n\nAynı şekilde, başka bir yöntemle de doğrulama yapabilirdik.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/advanced/response-change-status-code.md",
    "content": "# Response - Status Code Değiştirme { #response-change-status-code }\n\nMuhtemelen daha önce varsayılan bir [Response Status Code](../tutorial/response-status-code.md) ayarlayabileceğinizi okumuşsunuzdur.\n\nAncak bazı durumlarda, varsayılandan farklı bir status code döndürmeniz gerekir.\n\n## Kullanım senaryosu { #use-case }\n\nÖrneğin, varsayılan olarak \"OK\" `200` HTTP status code'u döndürmek istediğinizi düşünün.\n\nAma veri mevcut değilse onu oluşturmak ve \"CREATED\" `201` HTTP status code'u döndürmek istiyorsunuz.\n\nAynı zamanda, döndürdüğünüz veriyi bir `response_model` ile filtreleyip dönüştürebilmeyi de sürdürmek istiyorsunuz.\n\nBu tür durumlarda bir `Response` parametresi kullanabilirsiniz.\n\n## Bir `Response` parametresi kullanın { #use-a-response-parameter }\n\n*Path operation function* içinde `Response` tipinde bir parametre tanımlayabilirsiniz (cookie ve header'lar için yapabildiğiniz gibi).\n\nArdından bu *geçici (temporal)* `Response` nesnesi üzerinde `status_code` değerini ayarlayabilirsiniz.\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\nSonrasında, normalde yaptığınız gibi ihtiyacınız olan herhangi bir nesneyi döndürebilirsiniz (`dict`, bir veritabanı modeli, vb.).\n\nVe eğer bir `response_model` tanımladıysanız, döndürdüğünüz nesneyi filtrelemek ve dönüştürmek için yine kullanılacaktır.\n\n**FastAPI**, status code'u (ayrıca cookie ve header'ları) bu *geçici (temporal)* response'tan alır ve `response_model` ile filtrelenmiş, sizin döndürdüğünüz değeri içeren nihai response'a yerleştirir.\n\nAyrıca `Response` parametresini dependency'lerde de tanımlayıp status code'u orada ayarlayabilirsiniz. Ancak unutmayın, en son ayarlanan değer geçerli olur.\n"
  },
  {
    "path": "docs/tr/docs/advanced/response-cookies.md",
    "content": "# Response Cookie'leri { #response-cookies }\n\n## Bir `Response` parametresi kullanın { #use-a-response-parameter }\n\n*Path operation function* içinde `Response` tipinde bir parametre tanımlayabilirsiniz.\n\nArdından bu *geçici* response nesnesi üzerinde cookie'leri set edebilirsiniz.\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\nSonrasında normalde yaptığınız gibi ihtiyaç duyduğunuz herhangi bir nesneyi döndürebilirsiniz (bir `dict`, bir veritabanı modeli vb.).\n\nAyrıca bir `response_model` tanımladıysanız, döndürdüğünüz nesneyi filtrelemek ve dönüştürmek için yine kullanılacaktır.\n\n**FastAPI**, bu *geçici* response'u cookie'leri (ayrıca header'ları ve status code'u) çıkarmak için kullanır ve bunları, döndürdüğünüz değeri içeren nihai response'a ekler. Döndürdüğünüz değer, varsa `response_model` ile filtrelenmiş olur.\n\n`Response` parametresini dependency'lerde de tanımlayıp, onların içinde cookie (ve header) set edebilirsiniz.\n\n## Doğrudan bir `Response` döndürün { #return-a-response-directly }\n\nKodunuzda doğrudan bir `Response` döndürürken de cookie oluşturabilirsiniz.\n\nBunu yapmak için, [Doğrudan Response Döndürme](response-directly.md) bölümünde anlatıldığı gibi bir response oluşturabilirsiniz.\n\nSonra bunun içinde Cookie'leri set edin ve response'u döndürün:\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip\n\n`Response` parametresini kullanmak yerine doğrudan bir response döndürürseniz, FastAPI onu olduğu gibi (doğrudan) döndürür.\n\nBu yüzden, verinizin doğru tipte olduğundan emin olmanız gerekir. Örneğin `JSONResponse` döndürüyorsanız, verinin JSON ile uyumlu olması gerekir.\n\nAyrıca `response_model` tarafından filtrelenmesi gereken bir veriyi göndermediğinizden de emin olun.\n\n///\n\n### Daha fazla bilgi { #more-info }\n\n/// note | Teknik Detaylar\n\n`from starlette.responses import Response` veya `from starlette.responses import JSONResponse` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak size kolaylık olması için `fastapi.responses` içinde `starlette.responses` ile aynı response sınıflarını sunar. Ancak mevcut response'ların büyük kısmı doğrudan Starlette'ten gelir.\n\nVe `Response`, header ve cookie set etmek için sık kullanıldığından, **FastAPI** bunu `fastapi.Response` olarak da sağlar.\n\n///\n\nMevcut tüm parametreleri ve seçenekleri görmek için [Starlette dokümantasyonu](https://www.starlette.dev/responses/#set-cookie)'na bakın.\n"
  },
  {
    "path": "docs/tr/docs/advanced/response-directly.md",
    "content": "# Doğrudan Bir Response Döndürme { #return-a-response-directly }\n\n**FastAPI** ile bir *path operation* oluşturduğunuzda, normalde ondan herhangi bir veri döndürebilirsiniz: bir `dict`, bir `list`, bir Pydantic model, bir veritabanı modeli vb.\n\nBir [Response Model](../tutorial/response-model.md) deklare ederseniz, FastAPI veriyi Pydantic kullanarak JSON'a serialize etmek için bunu kullanır.\n\nBir response model deklare etmezseniz, FastAPI [JSON Uyumlu Encoder](../tutorial/encoder.md)'da anlatılan `jsonable_encoder`'ı kullanır ve bunu bir `JSONResponse` içine koyar.\n\nAyrıca doğrudan bir `JSONResponse` oluşturup döndürebilirsiniz.\n\n/// tip | İpucu\n\n[Response Model](../tutorial/response-model.md) kullanmak, doğrudan `JSONResponse` döndürmeye kıyasla genellikle çok daha iyi performans sağlar; çünkü veriyi Pydantic ile, Rust tarafında serialize eder.\n\n///\n\n## Bir `Response` Döndürme { #return-a-response }\n\nAslında herhangi bir `Response` veya onun herhangi bir alt sınıfını döndürebilirsiniz.\n\n/// info | Bilgi\n\n`JSONResponse` zaten `Response`'un bir alt sınıfıdır.\n\n///\n\nBir `Response` döndürdüğünüzde, **FastAPI** bunu olduğu gibi doğrudan iletir.\n\nPydantic model'leriyle herhangi bir veri dönüşümü yapmaz, içeriği başka bir tipe çevirmez vb.\n\nBu size ciddi bir esneklik sağlar. Herhangi bir veri türü döndürebilir, herhangi bir veri deklarasyonunu veya validasyonunu override edebilirsiniz.\n\nBu aynı zamanda size ciddi bir sorumluluk yükler. Döndürdüğünüz verinin doğru, doğru formatta, serialize edilebilir vb. olduğundan emin olmanız gerekir.\n\n## Bir `Response` İçinde `jsonable_encoder` Kullanma { #using-the-jsonable-encoder-in-a-response }\n\n**FastAPI**, sizin döndürdüğünüz `Response` üzerinde hiçbir değişiklik yapmadığı için, içeriğinin gönderilmeye hazır olduğundan emin olmanız gerekir.\n\nÖrneğin, bir Pydantic model'i, önce JSON-uyumlu tiplere çevrilmeden (`datetime`, `UUID` vb.) doğrudan bir `JSONResponse` içine koyamazsınız. Önce tüm veri tipleri JSON-uyumlu hale gelecek şekilde `dict`'e çevrilmesi gerekir.\n\nBu gibi durumlarda, response'a vermeden önce verinizi dönüştürmek için `jsonable_encoder` kullanabilirsiniz:\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | Teknik Detaylar\n\n`from starlette.responses import JSONResponse` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak size kolaylık olması için `starlette.responses` içeriğini `fastapi.responses` üzerinden de sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'tan gelir.\n\n///\n\n## Özel Bir `Response` Döndürme { #returning-a-custom-response }\n\nYukarıdaki örnek ihtiyaç duyduğunuz tüm parçaları gösteriyor, ancak henüz çok kullanışlı değil. Çünkü `item`'ı zaten doğrudan döndürebilirdiniz ve **FastAPI** varsayılan olarak onu sizin için bir `JSONResponse` içine koyup `dict`'e çevirirdi vb.\n\nŞimdi bunu kullanarak nasıl özel bir response döndürebileceğinize bakalım.\n\nDiyelim ki [XML](https://en.wikipedia.org/wiki/XML) response döndürmek istiyorsunuz.\n\nXML içeriğinizi bir string içine koyabilir, onu bir `Response` içine yerleştirip döndürebilirsiniz:\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## Bir Response Model Nasıl Çalışır { #how-a-response-model-works }\n\nBir path operation içinde [Response Model - Dönüş Tipi](../tutorial/response-model.md) deklare ettiğinizde, **FastAPI** veriyi Pydantic kullanarak JSON'a serialize etmek için bunu kullanır.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nBu işlem Rust tarafında gerçekleştiği için, sıradan Python ve `JSONResponse` sınıfıyla yapılmasına kıyasla performans çok daha iyi olacaktır.\n\nBir `response_model` veya dönüş tipi kullandığınızda, FastAPI veriyi dönüştürmek için (daha yavaş olacağı için) `jsonable_encoder`'ı ya da `JSONResponse` sınıfını kullanmaz.\n\nBunun yerine, response model'i (veya dönüş tipini) kullanarak Pydantic ile üretilen JSON baytlarını alır ve doğrudan JSON için doğru medya tipiyle (`application/json`) bir `Response` döndürür.\n\n## Notlar { #notes }\n\nBir `Response`'u doğrudan döndürdüğünüzde, verisi otomatik olarak validate edilmez, dönüştürülmez (serialize edilmez) veya dokümante edilmez.\n\nAncak yine de [OpenAPI'de Ek Response'lar](additional-responses.md) bölümünde anlatıldığı şekilde dokümante edebilirsiniz.\n\nİlerleyen bölümlerde, otomatik veri dönüşümü, dokümantasyon vb. özellikleri korurken bu özel `Response`'ları nasıl kullanıp declare edebileceğinizi göreceksiniz.\n"
  },
  {
    "path": "docs/tr/docs/advanced/response-headers.md",
    "content": "# Response Header'ları { #response-headers }\n\n## Bir `Response` parametresi kullanın { #use-a-response-parameter }\n\n*Path operation function* içinde (cookie'lerde yapabildiğiniz gibi) tipi `Response` olan bir parametre tanımlayabilirsiniz.\n\nSonra da bu *geçici* response nesnesi üzerinde header'ları ayarlayabilirsiniz.\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\nArdından normalde yaptığınız gibi ihtiyacınız olan herhangi bir nesneyi döndürebilirsiniz (bir `dict`, bir veritabanı modeli vb.).\n\nEğer bir `response_model` tanımladıysanız, döndürdüğünüz nesneyi filtrelemek ve dönüştürmek için yine kullanılacaktır.\n\n**FastAPI**, header'ları (aynı şekilde cookie'leri ve status code'u) bu *geçici* response'dan alır ve döndürdüğünüz değeri (varsa bir `response_model` ile filtrelenmiş hâliyle) içeren nihai response'a ekler.\n\n`Response` parametresini dependency'lerde de tanımlayıp, onların içinde header (ve cookie) ayarlayabilirsiniz.\n\n## Doğrudan bir `Response` döndürün { #return-a-response-directly }\n\nDoğrudan bir `Response` döndürdüğünüzde de header ekleyebilirsiniz.\n\n[Bir Response'u Doğrudan Döndürün](response-directly.md) bölümünde anlatıldığı gibi bir response oluşturun ve header'ları ek bir parametre olarak geçin:\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | Teknik Detaylar\n\n`from starlette.responses import Response` veya `from starlette.responses import JSONResponse` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içeriğini `fastapi.responses` olarak da sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'ten gelir.\n\nAyrıca `Response` header ve cookie ayarlamak için sık kullanıldığından, **FastAPI** bunu `fastapi.Response` altında da sağlar.\n\n///\n\n## Özel Header'lar { #custom-headers }\n\nÖzel/proprietary header'ların [`X-` prefix'i kullanılarak](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) eklenebileceğini unutmayın.\n\nAncak tarayıcıdaki bir client'ın görebilmesini istediğiniz özel header'larınız varsa, bunları CORS ayarlarınıza eklemeniz gerekir ([CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md) bölümünde daha fazla bilgi), bunun için [Starlette'in CORS dokümanında](https://www.starlette.dev/middleware/#corsmiddleware) açıklanan `expose_headers` parametresini kullanın.\n"
  },
  {
    "path": "docs/tr/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP Basic Auth { #http-basic-auth }\n\nEn basit senaryolarda HTTP Basic Auth kullanabilirsiniz.\n\nHTTP Basic Auth’ta uygulama, içinde kullanıcı adı ve şifre bulunan bir header bekler.\n\nEğer bunu almazsa HTTP 401 \"Unauthorized\" hatası döndürür.\n\nAyrıca değeri `Basic` olan ve isteğe bağlı `realm` parametresi içerebilen `WWW-Authenticate` header’ını da döndürür.\n\nBu da tarayıcıya, kullanıcı adı ve şifre için entegre giriş penceresini göstermesini söyler.\n\nArdından kullanıcı adı ve şifreyi yazdığınızda tarayıcı bunları otomatik olarak header içinde gönderir.\n\n## Basit HTTP Basic Auth { #simple-http-basic-auth }\n\n* `HTTPBasic` ve `HTTPBasicCredentials` import edin.\n* `HTTPBasic` kullanarak bir \"`security` scheme\" oluşturun.\n* *path operation*’ınızda bir dependency ile bu `security`’yi kullanın.\n* Bu, `HTTPBasicCredentials` tipinde bir nesne döndürür:\n    * İçinde gönderilen `username` ve `password` bulunur.\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\nURL’yi ilk kez açmaya çalıştığınızda (veya dokümanlardaki \"Execute\" butonuna tıkladığınızda) tarayıcı sizden kullanıcı adınızı ve şifrenizi ister:\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## Kullanıcı adını kontrol edin { #check-the-username }\n\nDaha kapsamlı bir örneğe bakalım.\n\nKullanıcı adı ve şifrenin doğru olup olmadığını kontrol etmek için bir dependency kullanın.\n\nBunun için kullanıcı adı ve şifreyi kontrol ederken Python standart modülü olan [`secrets`](https://docs.python.org/3/library/secrets.html)'i kullanın.\n\n`secrets.compare_digest()`; `bytes` ya da yalnızca ASCII karakterleri (İngilizce’deki karakterler) içeren bir `str` almalıdır. Bu da `Sebastián` içindeki `á` gibi karakterlerle çalışmayacağı anlamına gelir.\n\nBunu yönetmek için önce `username` ve `password` değerlerini UTF-8 ile encode ederek `bytes`’a dönüştürürüz.\n\nSonra `secrets.compare_digest()` kullanarak `credentials.username`’in `\"stanleyjobson\"` ve `credentials.password`’ün `\"swordfish\"` olduğundan emin olabiliriz.\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\nBu, kabaca şuna benzer olurdu:\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # Bir hata döndür\n    ...\n```\n\nAncak `secrets.compare_digest()` kullanarak, \"timing attacks\" denilen bir saldırı türüne karşı güvenli olursunuz.\n\n### Timing Attacks { #timing-attacks }\n\nPeki \"timing attack\" nedir?\n\nBazı saldırganların kullanıcı adı ve şifreyi tahmin etmeye çalıştığını düşünelim.\n\nVe `johndoe` kullanıcı adı ve `love123` şifresi ile bir request gönderiyorlar.\n\nUygulamanızdaki Python kodu o zaman kabaca şuna denk olur:\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nAncak Python, `johndoe` içindeki ilk `j` ile `stanleyjobson` içindeki ilk `s`’i karşılaştırdığı anda `False` döndürür; çünkü iki string’in aynı olmadığını zaten anlar ve \"kalan harfleri karşılaştırmak için daha fazla hesaplama yapmaya gerek yok\" diye düşünür. Uygulamanız da \"Incorrect username or password\" der.\n\nSonra saldırganlar bu sefer `stanleyjobsox` kullanıcı adı ve `love123` şifresi ile dener.\n\nUygulama kodunuz da şuna benzer bir şey yapar:\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nBu kez Python, iki string’in aynı olmadığını fark etmeden önce hem `stanleyjobsox` hem de `stanleyjobson` içinde `stanleyjobso` kısmının tamamını karşılaştırmak zorunda kalır. Bu nedenle \"Incorrect username or password\" yanıtını vermesi birkaç mikro saniye daha uzun sürer.\n\n#### Yanıt süresi saldırganlara yardımcı olur { #the-time-to-answer-helps-the-attackers }\n\nBu noktada saldırganlar, server’ın \"Incorrect username or password\" response’unu göndermesinin birkaç mikro saniye daha uzun sürdüğünü fark ederek _bir şeyleri_ doğru yaptıklarını anlar; yani başlangıçtaki bazı harfler doğrudur.\n\nSonra tekrar denerken, bunun `johndoe`’dan ziyade `stanleyjobsox`’a daha yakın bir şey olması gerektiğini bilerek devam edebilirler.\n\n#### \"Profesyonel\" bir saldırı { #a-professional-attack }\n\nElbette saldırganlar bunu elle tek tek denemez; bunu yapan bir program yazarlar. Muhtemelen saniyede binlerce ya da milyonlarca test yaparlar ve her seferinde yalnızca bir doğru harf daha elde ederler.\n\nBöylece birkaç dakika ya da birkaç saat içinde doğru kullanıcı adı ve şifreyi, yanıt süresini kullanarak ve uygulamamızın \"yardımıyla\" tahmin etmiş olurlar.\n\n#### `secrets.compare_digest()` ile düzeltin { #fix-it-with-secrets-compare-digest }\n\nAncak bizim kodumuzda `secrets.compare_digest()` kullanıyoruz.\n\nKısacası, `stanleyjobsox` ile `stanleyjobson`’u karşılaştırmak için geçen süre, `johndoe` ile `stanleyjobson`’u karşılaştırmak için geçen süreyle aynı olur. Şifre için de aynı şekilde.\n\nBu sayede uygulama kodunuzda `secrets.compare_digest()` kullanarak bu güvenlik saldırıları ailesine karşı güvenli olursunuz.\n\n### Hatayı döndürün { #return-the-error }\n\nCredential’ların hatalı olduğunu tespit ettikten sonra, 401 status code ile (credential verilmediğinde dönenle aynı) bir `HTTPException` döndürün ve tarayıcının giriş penceresini yeniden göstermesi için `WWW-Authenticate` header’ını ekleyin:\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/tr/docs/advanced/security/index.md",
    "content": "# Gelişmiş Güvenlik { #advanced-security }\n\n## Ek Özellikler { #additional-features }\n\n[Öğretici - Kullanıcı Kılavuzu: Güvenlik](../../tutorial/security/index.md) sayfasında ele alınanların dışında güvenlikle ilgili bazı ek özellikler vardır.\n\n/// tip | İpucu\n\nSonraki bölümler **mutlaka \"gelişmiş\" olmak zorunda değildir**.\n\nVe kullanım durumunuza göre, çözüm bu bölümlerden birinde olabilir.\n\n///\n\n## Önce Öğreticiyi Okuyun { #read-the-tutorial-first }\n\nSonraki bölümler, ana [Öğretici - Kullanıcı Kılavuzu: Güvenlik](../../tutorial/security/index.md) sayfasını zaten okuduğunuzu varsayar.\n\nHepsi aynı kavramlara dayanır, ancak bazı ek işlevselliklere izin verir.\n"
  },
  {
    "path": "docs/tr/docs/advanced/security/oauth2-scopes.md",
    "content": "# OAuth2 scope'ları { #oauth2-scopes }\n\nOAuth2 scope'larını **FastAPI** ile doğrudan kullanabilirsiniz; sorunsuz çalışacak şekilde entegre edilmiştir.\n\nBu sayede OAuth2 standardını takip eden, daha ince taneli bir izin sistemini OpenAPI uygulamanıza (ve API dokümanlarınıza) entegre edebilirsiniz.\n\nScope'lu OAuth2; Facebook, Google, GitHub, Microsoft, X (Twitter) vb. birçok büyük kimlik doğrulama sağlayıcısının kullandığı mekanizmadır. Kullanıcı ve uygulamalara belirli izinler vermek için bunu kullanırlar.\n\nFacebook, Google, GitHub, Microsoft, X (Twitter) ile \"giriş yaptığınızda\", o uygulama scope'lu OAuth2 kullanıyor demektir.\n\nBu bölümde, **FastAPI** uygulamanızda aynı scope'lu OAuth2 ile authentication ve authorization'ı nasıl yöneteceğinizi göreceksiniz.\n\n/// warning | Uyarı\n\nBu bölüm az çok ileri seviye sayılır. Yeni başlıyorsanız atlayabilirsiniz.\n\nOAuth2 scope'larına mutlaka ihtiyacınız yok; authentication ve authorization'ı istediğiniz şekilde ele alabilirsiniz.\n\nAncak scope'lu OAuth2, API'nize (OpenAPI ile) ve API dokümanlarınıza güzel biçimde entegre edilebilir.\n\nBuna rağmen, bu scope'ları (veya başka herhangi bir security/authorization gereksinimini) kodunuzda ihtiyaç duyduğunuz şekilde yine siz zorunlu kılarsınız.\n\nBirçok durumda scope'lu OAuth2 gereğinden fazla (overkill) olabilir.\n\nAma ihtiyacınız olduğunu biliyorsanız ya da merak ediyorsanız okumaya devam edin.\n\n///\n\n## OAuth2 scope'ları ve OpenAPI { #oauth2-scopes-and-openapi }\n\nOAuth2 spesifikasyonu, \"scope\"ları boşluklarla ayrılmış string'lerden oluşan bir liste olarak tanımlar.\n\nBu string'lerin her birinin içeriği herhangi bir formatta olabilir, ancak boşluk içermemelidir.\n\nBu scope'lar \"izinleri\" temsil eder.\n\nOpenAPI'de (ör. API dokümanlarında) \"security scheme\" tanımlayabilirsiniz.\n\nBu security scheme'lerden biri OAuth2 kullanıyorsa, scope'ları da tanımlayıp kullanabilirsiniz.\n\nHer bir \"scope\" sadece bir string'dir (boşluksuz).\n\nGenellikle belirli güvenlik izinlerini tanımlamak için kullanılır, örneğin:\n\n* `users:read` veya `users:write` sık görülen örneklerdir.\n* `instagram_basic` Facebook / Instagram tarafından kullanılır.\n* `https://www.googleapis.com/auth/drive` Google tarafından kullanılır.\n\n/// info | Bilgi\n\nOAuth2'de \"scope\", gereken belirli bir izni bildiren bir string'den ibarettir.\n\n`:` gibi başka karakterler içermesi ya da bir URL olması önemli değildir.\n\nBu detaylar implementasyon'a bağlıdır.\n\nOAuth2 için bunlar sadece string'dir.\n\n///\n\n## Genel görünüm { #global-view }\n\nÖnce, ana **Tutorial - User Guide** içindeki [Password (ve hashing) ile OAuth2, JWT token'lı Bearer](../../tutorial/security/oauth2-jwt.md) örneklerinden, OAuth2 scope'larına geçince hangi kısımların değiştiğine hızlıca bakalım:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\nŞimdi bu değişiklikleri adım adım inceleyelim.\n\n## OAuth2 Security scheme { #oauth2-security-scheme }\n\nİlk değişiklik, artık OAuth2 security scheme'ini iki adet kullanılabilir scope ile tanımlamamız: `me` ve `items`.\n\n`scopes` parametresi; her scope'un key, açıklamasının ise value olduğu bir `dict` alır:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\nBu scope'ları tanımladığımız için, login/authorize yaptığınızda API dokümanlarında görünecekler.\n\nVe hangi scope'lara erişim vermek istediğinizi seçebileceksiniz: `me` ve `items`.\n\nBu, Facebook/Google/GitHub vb. ile giriş yaparken izin verdiğinizde kullanılan mekanizmanın aynısıdır:\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## Scope'lu JWT token { #jwt-token-with-scopes }\n\nŞimdi token *path operation*'ını, istenen scope'ları döndürecek şekilde değiştirin.\n\nHâlâ aynı `OAuth2PasswordRequestForm` kullanılıyor. Bu form, request'te aldığı her scope için `str`'lerden oluşan bir `list` içeren `scopes` özelliğine sahiptir.\n\nVe scope'ları JWT token'ın bir parçası olarak döndürüyoruz.\n\n/// danger | Uyarı\n\nBasitlik için burada, gelen scope'ları doğrudan token'a ekliyoruz.\n\nAma uygulamanızda güvenlik açısından, yalnızca kullanıcının gerçekten sahip olabileceği scope'ları (veya sizin önceden tanımladıklarınızı) eklediğinizden emin olmalısınız.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## *Path operation*'larda ve dependency'lerde scope tanımlama { #declare-scopes-in-path-operations-and-dependencies }\n\nArtık `/users/me/items/` için olan *path operation*'ın `items` scope'unu gerektirdiğini tanımlıyoruz.\n\nBunun için `fastapi` içinden `Security` import edip kullanıyoruz.\n\nDependency'leri (`Depends` gibi) tanımlamak için `Security` kullanabilirsiniz; fakat `Security`, ayrıca string'lerden oluşan bir scope listesi alan `scopes` parametresini de alır.\n\nBu durumda `Security`'ye dependency fonksiyonu olarak `get_current_active_user` veriyoruz (`Depends` ile yaptığımız gibi).\n\nAma ayrıca bir `list` olarak scope'ları da veriyoruz; burada tek bir scope var: `items` (daha fazla da olabilir).\n\nVe `get_current_active_user` dependency fonksiyonu, sadece `Depends` ile değil `Security` ile de alt-dependency'ler tanımlayabilir. Kendi alt-dependency fonksiyonunu (`get_current_user`) ve daha fazla scope gereksinimini tanımlar.\n\nBu örnekte `me` scope'unu gerektiriyor (birden fazla scope da isteyebilirdi).\n\n/// note | Not\n\nFarklı yerlerde farklı scope'lar eklemek zorunda değilsiniz.\n\nBurada, **FastAPI**'nin farklı seviyelerde tanımlanan scope'ları nasıl ele aldığını göstermek için böyle yapıyoruz.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | Teknik Detaylar\n\n`Security` aslında `Depends`'in bir alt sınıfıdır ve sadece birazdan göreceğimiz bir ek parametreye sahiptir.\n\nAncak `Depends` yerine `Security` kullanınca **FastAPI**, security scope'larının tanımlanabileceğini bilir, bunları içeride kullanır ve API'yi OpenAPI ile dokümante eder.\n\nFakat `fastapi` içinden `Query`, `Path`, `Depends`, `Security` vb. import ettiğiniz şeyler, aslında özel sınıflar döndüren fonksiyonlardır.\n\n///\n\n## `SecurityScopes` kullanımı { #use-securityscopes }\n\nŞimdi `get_current_user` dependency'sini güncelleyelim.\n\nBu fonksiyon, yukarıdaki dependency'ler tarafından kullanılıyor.\n\nBurada, daha önce oluşturduğumuz aynı OAuth2 scheme'i dependency olarak tanımlıyoruz: `oauth2_scheme`.\n\nBu dependency fonksiyonunun kendi içinde bir scope gereksinimi olmadığı için, `oauth2_scheme` ile `Depends` kullanabiliriz; security scope'larını belirtmemiz gerekmiyorsa `Security` kullanmak zorunda değiliz.\n\nAyrıca `fastapi.security` içinden import edilen, `SecurityScopes` tipinde özel bir parametre tanımlıyoruz.\n\nBu `SecurityScopes` sınıfı, `Request`'e benzer (`Request`, request nesnesini doğrudan almak için kullanılmıştı).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## `scopes`'ları kullanma { #use-the-scopes }\n\n`security_scopes` parametresi `SecurityScopes` tipinde olacaktır.\n\nBu nesnenin `scopes` adlı bir özelliği vardır; bu liste, kendisinin ve bunu alt-dependency olarak kullanan tüm dependency'lerin gerektirdiği tüm scope'ları içerir. Yani tüm \"dependant\"lar... kafa karıştırıcı gelebilir; aşağıda tekrar açıklanıyor.\n\n`security_scopes` nesnesi (`SecurityScopes` sınıfından) ayrıca, bu scope'ları boşluklarla ayrılmış tek bir string olarak veren `scope_str` attribute'una sahiptir (bunu kullanacağız).\n\nSonrasında birkaç farklı noktada tekrar kullanabileceğimiz (`raise` edebileceğimiz) bir `HTTPException` oluşturuyoruz.\n\nBu exception içinde, gerekiyorsa, gerekli scope'ları boşlukla ayrılmış bir string olarak (`scope_str` ile) ekliyoruz. Bu scope'ları içeren string'i `WWW-Authenticate` header'ına koyuyoruz (spesifikasyonun bir parçası).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## `username` ve veri şeklinin doğrulanması { #verify-the-username-and-data-shape }\n\nBir `username` aldığımızı doğruluyoruz ve scope'ları çıkarıyoruz.\n\nArdından bu veriyi Pydantic model'i ile doğruluyoruz (`ValidationError` exception'ını yakalayarak). JWT token'ı okurken veya Pydantic ile veriyi doğrularken bir hata olursa, daha önce oluşturduğumuz `HTTPException`'ı fırlatıyoruz.\n\nBunun için Pydantic model'i `TokenData`'yı, `scopes` adlı yeni bir özellik ekleyerek güncelliyoruz.\n\nVeriyi Pydantic ile doğrulayarak örneğin scope'ların tam olarak `str`'lerden oluşan bir `list` olduğunu ve `username`'in bir `str` olduğunu garanti edebiliriz.\n\nAksi halde, örneğin bir `dict` veya başka bir şey gelebilir; bu da daha sonra uygulamanın bir yerinde kırılmaya yol açıp güvenlik riski oluşturabilir.\n\nAyrıca bu `username` ile bir kullanıcı olduğunu doğruluyoruz; yoksa yine aynı exception'ı fırlatıyoruz.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## `scopes`'ların doğrulanması { #verify-the-scopes }\n\nŞimdi bu dependency'nin ve tüm dependant'ların ( *path operation*'lar dahil) gerektirdiği tüm scope'ların, alınan token'da sağlanan scope'lar içinde olup olmadığını doğruluyoruz; değilse `HTTPException` fırlatıyoruz.\n\nBunun için, tüm bu scope'ları `str` olarak içeren bir `list` olan `security_scopes.scopes` kullanılır.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## Dependency ağacı ve scope'lar { #dependency-tree-and-scopes }\n\nBu dependency ağacını ve scope'ları tekrar gözden geçirelim.\n\n`get_current_active_user` dependency'si, alt-dependency olarak `get_current_user`'ı kullandığı için, `get_current_active_user` üzerinde tanımlanan `\"me\"` scope'u, `get_current_user`'a geçirilen `security_scopes.scopes` içindeki gerekli scope listesine dahil edilir.\n\n*Path operation*'ın kendisi de `\"items\"` scope'unu tanımlar; bu da `get_current_user`'a geçirilen `security_scopes.scopes` listesinde yer alır.\n\nDependency'lerin ve scope'ların hiyerarşisi şöyle görünür:\n\n* *Path operation* `read_own_items` şunlara sahiptir:\n    * Dependency ile gerekli scope'lar `[\"items\"]`:\n    * `get_current_active_user`:\n        * `get_current_active_user` dependency fonksiyonu şunlara sahiptir:\n            * Dependency ile gerekli scope'lar `[\"me\"]`:\n            * `get_current_user`:\n                * `get_current_user` dependency fonksiyonu şunlara sahiptir:\n                    * Kendisinin gerektirdiği scope yok.\n                    * `oauth2_scheme` kullanan bir dependency.\n                    * `SecurityScopes` tipinde bir `security_scopes` parametresi:\n                        * Bu `security_scopes` parametresinin `scopes` adlı bir özelliği vardır ve yukarıda tanımlanan tüm scope'ları içeren bir `list` taşır, yani:\n                            * *Path operation* `read_own_items` için `security_scopes.scopes` `[\"me\", \"items\"]` içerir.\n                            * *Path operation* `read_users_me` için `security_scopes.scopes` `[\"me\"]` içerir; çünkü bu scope `get_current_active_user` dependency'sinde tanımlanmıştır.\n                            * *Path operation* `read_system_status` için `security_scopes.scopes` `[]` (boş) olur; çünkü herhangi bir `Security` ile `scopes` tanımlamamıştır ve dependency'si olan `get_current_user` da `scopes` tanımlamaz.\n\n/// tip | İpucu\n\nBuradaki önemli ve \"sihirli\" nokta şu: `get_current_user`, her *path operation* için kontrol etmesi gereken farklı bir `scopes` listesi alır.\n\nBu, belirli bir *path operation* için dependency ağacındaki her *path operation* ve her dependency üzerinde tanımlanan `scopes`'lara bağlıdır.\n\n///\n\n## `SecurityScopes` hakkında daha fazla detay { #more-details-about-securityscopes }\n\n`SecurityScopes`'u herhangi bir noktada ve birden fazla yerde kullanabilirsiniz; mutlaka \"kök\" dependency'de olmak zorunda değildir.\n\nHer zaman, **o spesifik** *path operation* ve **o spesifik** dependency ağacı için, mevcut `Security` dependency'lerinde ve tüm dependant'larda tanımlanan security scope'larını içerir.\n\n`SecurityScopes`, dependant'ların tanımladığı tüm scope'ları barındırdığı için, gereken scope'ların token'da olup olmadığını merkezi bir dependency fonksiyonunda doğrulayıp, farklı *path operation*'larda farklı scope gereksinimleri tanımlayabilirsiniz.\n\nBu kontroller her *path operation* için bağımsız yapılır.\n\n## Deneyin { #check-it }\n\nAPI dokümanlarını açarsanız, authenticate olup hangi scope'ları authorize etmek istediğinizi seçebilirsiniz.\n\n<img src=\"/img/tutorial/security/image11.png\">\n\nHiç scope seçmezseniz \"authenticated\" olursunuz; ancak `/users/me/` veya `/users/me/items/`'e erişmeye çalıştığınızda, yeterli izniniz olmadığını söyleyen bir hata alırsınız. Yine de `/status/`'a erişebilirsiniz.\n\n`me` scope'unu seçip `items` scope'unu seçmezseniz `/users/me/`'a erişebilirsiniz ama `/users/me/items/`'e erişemezsiniz.\n\nBu, bir üçüncü taraf uygulamanın, bir kullanıcı tarafından sağlanan token ile bu *path operation*'lardan birine erişmeye çalıştığında; kullanıcının uygulamaya kaç izin verdiğine bağlı olarak yaşayacağı durumdur.\n\n## Üçüncü taraf entegrasyonları hakkında { #about-third-party-integrations }\n\nBu örnekte OAuth2 \"password\" flow'unu kullanıyoruz.\n\nBu, kendi uygulamamıza giriş yaptığımız durumlar için uygundur; muhtemelen kendi frontend'imiz vardır.\n\nÇünkü `username` ve `password` alacağını bildiğimiz frontend'i biz kontrol ediyoruz, dolayısıyla güvenebiliriz.\n\nAncak başkalarının bağlanacağı bir OAuth2 uygulaması geliştiriyorsanız (yani Facebook, Google, GitHub vb. gibi bir authentication provider muadili geliştiriyorsanız) diğer flow'lardan birini kullanmalısınız.\n\nEn yaygını implicit flow'dur.\n\nEn güvenlisi code flow'dur; ancak daha fazla adım gerektirdiği için implementasyonu daha karmaşıktır. Daha karmaşık olduğundan, birçok sağlayıcı implicit flow'yu önermeye yönelir.\n\n/// note | Not\n\nHer authentication provider'ın flow'ları markasının bir parçası yapmak için farklı şekilde adlandırması yaygındır.\n\nAma sonuçta aynı OAuth2 standardını implement ediyorlar.\n\n///\n\n**FastAPI**, bu OAuth2 authentication flow'larının tamamı için `fastapi.security.oauth2` içinde yardımcı araçlar sunar.\n\n## Decorator `dependencies` içinde `Security` { #security-in-decorator-dependencies }\n\nDecorator'ın `dependencies` parametresinde bir `list` `Depends` tanımlayabildiğiniz gibi ( [Path operation decorator'larında Dependencies](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md) bölümünde açıklandığı üzere), burada `scopes` ile birlikte `Security` de kullanabilirsiniz.\n"
  },
  {
    "path": "docs/tr/docs/advanced/settings.md",
    "content": "# Ayarlar ve Ortam Değişkenleri { #settings-and-environment-variables }\n\nBirçok durumda uygulamanızın bazı harici ayarlara veya konfigürasyonlara ihtiyacı olabilir; örneğin secret key'ler, veritabanı kimlik bilgileri, e-posta servisleri için kimlik bilgileri vb.\n\nBu ayarların çoğu değişkendir (değişebilir); örneğin veritabanı URL'leri. Ayrıca birçoğu hassas olabilir; örneğin secret'lar.\n\nBu nedenle bunları, uygulama tarafından okunan environment variable'lar ile sağlamak yaygındır.\n\n/// tip | İpucu\n\nEnvironment variable'ları anlamak için [Ortam Değişkenleri](../environment-variables.md) dokümanını okuyabilirsiniz.\n\n///\n\n## Tipler ve doğrulama { #types-and-validation }\n\nBu environment variable'lar yalnızca metin (string) taşıyabilir; çünkü Python'ın dışındadırlar ve diğer programlarla ve sistemin geri kalanıyla uyumlu olmaları gerekir (hatta Linux, Windows, macOS gibi farklı işletim sistemleriyle de).\n\nBu da, Python içinde bir environment variable'dan okunan herhangi bir değerin `str` olacağı anlamına gelir; farklı bir tipe dönüştürme veya herhangi bir doğrulama işlemi kod içinde yapılmalıdır.\n\n## Pydantic `Settings` { #pydantic-settings }\n\nNeyse ki Pydantic, environment variable'lardan gelen bu ayarları yönetmek için [Pydantic: Settings yönetimi](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) ile çok iyi bir yardımcı araç sunar.\n\n### `pydantic-settings`'i kurun { #install-pydantic-settings }\n\nÖnce, [Sanal ortam](../virtual-environments.md) oluşturduğunuzdan, aktive ettiğinizden emin olun ve ardından `pydantic-settings` paketini kurun:\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\nAyrıca `all` extras'ını şu şekilde kurduğunuzda da dahil gelir:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### `Settings` nesnesini oluşturun { #create-the-settings-object }\n\nPydantic'ten `BaseSettings` import edin ve bir alt sınıf (sub-class) oluşturun; tıpkı bir Pydantic model'inde olduğu gibi.\n\nPydantic model'lerinde olduğu gibi, type annotation'larla (ve gerekirse default değerlerle) class attribute'ları tanımlarsınız.\n\nPydantic model'lerinde kullandığınız aynı doğrulama özelliklerini ve araçlarını burada da kullanabilirsiniz; örneğin farklı veri tipleri ve `Field()` ile ek doğrulamalar.\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip | İpucu\n\nHızlıca kopyalayıp yapıştırmak istiyorsanız bu örneği kullanmayın; aşağıdaki son örneği kullanın.\n\n///\n\nArdından, bu `Settings` sınıfının bir instance'ını oluşturduğunuzda (bu örnekte `settings` nesnesi), Pydantic environment variable'ları büyük/küçük harfe duyarsız şekilde okur; yani büyük harfli `APP_NAME` değişkeni, yine de `app_name` attribute'u için okunur.\n\nSonrasında veriyi dönüştürür ve doğrular. Böylece `settings` nesnesini kullandığınızda, tanımladığınız tiplerde verilere sahip olursunuz (örn. `items_per_user` bir `int` olur).\n\n### `settings`'i kullanın { #use-the-settings }\n\nDaha sonra uygulamanızda yeni `settings` nesnesini kullanabilirsiniz:\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### Server'ı çalıştırın { #run-the-server }\n\nSonraki adımda server'ı çalıştırırken konfigürasyonları environment variable olarak geçersiniz; örneğin `ADMIN_EMAIL` ve `APP_NAME` şu şekilde ayarlanabilir:\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip | İpucu\n\nTek bir komut için birden fazla env var ayarlamak istiyorsanız aralarına boşluk koyun ve hepsini komuttan önce yazın.\n\n///\n\nBöylece `admin_email` ayarı `\"deadpool@example.com\"` olur.\n\n`app_name` `\"ChimichangApp\"` olur.\n\n`items_per_user` ise default değeri olan `50` olarak kalır.\n\n## Ayarları başka bir module'de tutma { #settings-in-another-module }\n\n[Daha Büyük Uygulamalar - Birden Fazla Dosya](../tutorial/bigger-applications.md) bölümünde gördüğünüz gibi, bu ayarları başka bir module dosyasına koyabilirsiniz.\n\nÖrneğin `config.py` adında bir dosyanız şu şekilde olabilir:\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\nVe ardından bunu `main.py` dosyasında kullanabilirsiniz:\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip | İpucu\n\n[Daha Büyük Uygulamalar - Birden Fazla Dosya](../tutorial/bigger-applications.md) bölümünde gördüğünüz gibi, ayrıca bir `__init__.py` dosyasına da ihtiyacınız olacak.\n\n///\n\n## Dependency içinde ayarlar { #settings-in-a-dependency }\n\nBazı durumlarda, her yerde kullanılan global bir `settings` nesnesi yerine ayarları bir dependency üzerinden sağlamak faydalı olabilir.\n\nBu özellikle test sırasında çok işe yarar; çünkü bir dependency'yi kendi özel ayarlarınızla override etmek çok kolaydır.\n\n### Config dosyası { #the-config-file }\n\nBir önceki örnekten devam edersek, `config.py` dosyanız şöyle görünebilir:\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\nDikkat edin, artık default bir instance `settings = Settings()` oluşturmuyoruz.\n\n### Ana uygulama dosyası { #the-main-app-file }\n\nŞimdi, yeni bir `config.Settings()` döndüren bir dependency oluşturuyoruz.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip | İpucu\n\n`@lru_cache` konusunu birazdan ele alacağız.\n\nŞimdilik `get_settings()`'in normal bir fonksiyon olduğunu varsayabilirsiniz.\n\n///\n\nSonra bunu dependency olarak *path operation function*'dan talep edebilir ve ihtiyaç duyduğumuz her yerde kullanabiliriz.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### Ayarlar ve test { #settings-and-testing }\n\nArdından, `get_settings` için bir dependency override oluşturarak test sırasında farklı bir settings nesnesi sağlamak çok kolay olur:\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\nDependency override içinde, yeni `Settings` nesnesini oluştururken `admin_email` için yeni bir değer ayarlarız ve sonra bu yeni nesneyi döndürürüz.\n\nSonrasında bunun kullanıldığını test edebiliriz.\n\n## `.env` dosyası okuma { #reading-a-env-file }\n\nÇok sayıda ayarınız varsa ve bunlar farklı ortamlarda sık sık değişiyorsa, bunları bir dosyaya koyup, sanki environment variable'mış gibi o dosyadan okumak faydalı olabilir.\n\nBu yaklaşım oldukça yaygındır ve bir adı vardır: Bu environment variable'lar genellikle `.env` adlı bir dosyaya konur ve bu dosyaya \"dotenv\" denir.\n\n/// tip | İpucu\n\nNokta (`.`) ile başlayan dosyalar, Linux ve macOS gibi Unix-benzeri sistemlerde gizli dosyadır.\n\nAncak dotenv dosyasının mutlaka bu dosya adına sahip olması gerekmez.\n\n///\n\nPydantic, harici bir kütüphane kullanarak bu tür dosyalardan okuma desteğine sahiptir. Daha fazlası için: [Pydantic Settings: Dotenv (.env) desteği](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support).\n\n/// tip | İpucu\n\nBunun çalışması için `pip install python-dotenv` yapmanız gerekir.\n\n///\n\n### `.env` dosyası { #the-env-file }\n\nŞöyle bir `.env` dosyanız olabilir:\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### Ayarları `.env`'den okuyun { #read-settings-from-env }\n\nArdından `config.py` dosyanızı şöyle güncelleyin:\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip | İpucu\n\n`model_config` attribute'u yalnızca Pydantic konfigürasyonu içindir. Daha fazlası için [Pydantic: Kavramlar: Konfigürasyon](https://docs.pydantic.dev/latest/concepts/config/).\n\n///\n\nBurada, Pydantic `Settings` sınıfınızın içinde `env_file` konfigürasyonunu tanımlar ve değer olarak kullanmak istediğimiz dotenv dosyasının dosya adını veririz.\n\n### `lru_cache` ile `Settings`'i yalnızca bir kez oluşturma { #creating-the-settings-only-once-with-lru-cache }\n\nDiskten dosya okumak normalde maliyetli (yavaş) bir işlemdir; bu yüzden muhtemelen bunu yalnızca bir kez yapıp aynı settings nesnesini tekrar kullanmak istersiniz. Her request için yeniden okumak istemezsiniz.\n\nAncak her seferinde şunu yaptığımızda:\n\n```Python\nSettings()\n```\n\nyeni bir `Settings` nesnesi oluşturulur ve oluşturulurken `.env` dosyasını yeniden okur.\n\nDependency fonksiyonu sadece şöyle olsaydı:\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\nbu nesneyi her request için oluştururduk ve `.env` dosyasını her request'te okurduk. ⚠️\n\nFakat en üstte `@lru_cache` decorator'ünü kullandığımız için `Settings` nesnesi yalnızca bir kez, ilk çağrıldığı anda oluşturulur. ✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\nSonraki request'lerde dependency'ler içinden `get_settings()` çağrıldığında, `get_settings()`'in iç kodu tekrar çalıştırılıp yeni bir `Settings` nesnesi yaratılmak yerine, ilk çağrıda döndürülen aynı nesne tekrar tekrar döndürülür.\n\n#### `lru_cache` Teknik Detayları { #lru-cache-technical-details }\n\n`@lru_cache`, decorator olarak uygulandığı fonksiyonu, her seferinde tekrar hesaplamak yerine ilk seferde döndürdüğü değeri döndürecek şekilde değiştirir; yani fonksiyon kodunu her çağrıda yeniden çalıştırmaz.\n\nBu nedenle altındaki fonksiyon, argüman kombinasyonlarının her biri için bir kez çalıştırılır. Sonra bu argüman kombinasyonlarının her biri için döndürülmüş değerler, fonksiyon aynı argüman kombinasyonuyla çağrıldıkça tekrar tekrar kullanılır.\n\nÖrneğin, şöyle bir fonksiyonunuz varsa:\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\nprogramınız şu şekilde çalışabilir:\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Execute function\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n```\n\nBizim `get_settings()` dependency'miz özelinde ise fonksiyon hiç argüman almaz; dolayısıyla her zaman aynı değeri döndürür.\n\nBu şekilde, neredeyse global bir değişken gibi davranır. Ancak bir dependency fonksiyonu kullandığı için testte kolayca override edebiliriz.\n\n`@lru_cache`, Python standart kütüphanesinin bir parçası olan `functools` içindedir. Daha fazla bilgi için: [Python dokümanları: `@lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache).\n\n## Özet { #recap }\n\nUygulamanızın ayarlarını veya konfigürasyonlarını yönetmek için, Pydantic model'lerinin tüm gücüyle birlikte Pydantic Settings'i kullanabilirsiniz.\n\n* Dependency kullanarak test etmeyi basitleştirebilirsiniz.\n* Bununla `.env` dosyalarını kullanabilirsiniz.\n* `@lru_cache` kullanmak, dotenv dosyasını her request için tekrar tekrar okumayı engellerken, test sırasında override etmenize de izin verir.\n"
  },
  {
    "path": "docs/tr/docs/advanced/stream-data.md",
    "content": "# Veri Akışı { #stream-data }\n\nVeriyi JSON olarak yapılandırabiliyorsanız, [JSON Lines Akışı](../tutorial/stream-json-lines.md) kullanın.\n\nAncak saf ikili (binary) veri ya da string akıtmak istiyorsanız, bunu şöyle yapabilirsiniz.\n\n/// info | Bilgi\n\nFastAPI 0.134.0 ile eklendi.\n\n///\n\n## Kullanım Senaryoları { #use-cases }\n\nDoğrudan bir AI LLM (Büyük Dil Modeli) servisinin çıktısından saf string'leri akıtmak istediğinizde kullanabilirsiniz.\n\nAyrıca **büyük ikili (binary) dosyaları** akıtmak için de kullanabilirsiniz; veriyi okurken her parçayı (chunk) sırayla gönderirsiniz, tamamını belleğe almak zorunda kalmazsınız.\n\nBu şekilde **video** veya **ses** de akıtabilirsiniz; hatta işledikçe üretilip gönderilebilir.\n\n## `yield` ile bir `StreamingResponse` { #a-streamingresponse-with-yield }\n\n*Path operation function* içinde `response_class=StreamingResponse` belirtirseniz, her veri parçasını sırayla göndermek için `yield` kullanabilirsiniz.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI her veri parçasını olduğu gibi `StreamingResponse`'a verir; JSON'a ya da benzeri bir formata dönüştürmeye çalışmaz.\n\n### Async Olmayan Path Operation Function'lar { #non-async-path-operation-functions }\n\nNormal `def` fonksiyonlarını (yani `async` olmadan) da kullanabilir ve aynı şekilde `yield` yazabilirsiniz.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### Tip Annotasyonu Yok { #no-annotation }\n\nİkili (binary) veri akıtıyorsanız dönüş tipi annotasyonu belirtmeniz şart değildir.\n\nFastAPI veriyi Pydantic ile JSON'a çevirmeye veya herhangi bir şekilde serileştirmeye çalışmayacağı için, bu durumda tip annotasyonu sadece editörünüz ve araçlarınız içindir; FastAPI tarafından kullanılmaz.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\nBu aynı zamanda `StreamingResponse` ile veriyi tam olarak ihtiyaç duyduğunuz biçimde üretme ve encode etme konusunda hem bir özgürlük hem de bir sorumluluk verdiği anlamına gelir; tip annotasyonlarından bağımsızdır. 🤓\n\n### Bytes Akışı { #stream-bytes }\n\nBaşlıca kullanım senaryolarından biri string yerine `bytes` akıtmaktır; elbette bunu yapabilirsiniz.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## Özel bir `PNGStreamingResponse` { #a-custom-pngstreamingresponse }\n\nYukarıdaki örneklerde veri baytları akıtıldı, ancak response'ta bir `Content-Type` header'ı yoktu; bu nedenle istemci hangi tür veriyi aldığını bilmiyordu.\n\nAkıttığınız veri türüne uygun `Content-Type` header'ını ayarlayan, `StreamingResponse`'tan türetilmiş özel bir alt sınıf (subclass) oluşturabilirsiniz.\n\nÖrneğin, `media_type` özniteliğini kullanarak `Content-Type` header'ını `image/png` olarak ayarlayan bir `PNGStreamingResponse` oluşturabilirsiniz:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\nArdından bu yeni sınıfı *path operation function* içinde `response_class=PNGStreamingResponse` olarak kullanabilirsiniz:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### Bir Dosyayı Simüle Etme { #simulate-a-file }\n\nBu örnekte, yalnızca bellekte yaşayan ama aynı arayüzü kullanmamıza izin veren, dosya benzeri bir nesne olan `io.BytesIO` ile bir dosyayı simüle ediyoruz.\n\nÖrneğin, bir dosyada yapabileceğimiz gibi, içeriğini tüketmek için üzerinde iterate edebiliriz.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | Teknik Detaylar\n\nDiğer iki değişken olan `image_base64` ve `binary_image`, Base64 ile encode edilmiş bir görüntüdür; daha sonra bayt'lara çevrilip `io.BytesIO`'ya aktarılır.\n\nSadece bu örnek aynı dosyada yaşayabilsin, kopyalayıp olduğu gibi çalıştırabilesiniz diye. 🥚\n\n///\n\n`with` bloğu kullanarak, jeneratör fonksiyonu (içinde `yield` olan fonksiyon) tamamlandığında dosya benzeri nesnenin kapandığından emin oluruz. Yani response gönderimi bittikten sonra.\n\nBu özel örnekte o kadar da önemli değil, çünkü sahte ve bellekte (yani `io.BytesIO` ile). Ancak gerçek bir dosyada, onunla işiniz bittiğinde dosyanın kapandığından emin olmak önemlidir.\n\n### Dosyalar ve Async { #files-and-async }\n\nÇoğu durumda dosya benzeri nesneler, varsayılan olarak async ve await ile uyumlu değildir.\n\nÖrneğin, `await file.read()` ya da `async for chunk in file` gibi şeyler yoktur.\n\nVe birçok durumda, diskte ya da ağda okundukları için, okumak engelleyici (event loop'u bloke edebilen) bir işlem olabilir.\n\n/// info | Bilgi\n\nYukarıdaki örnek aslında bir istisna; çünkü `io.BytesIO` nesnesi zaten bellekte, dolayısıyla onu okumak hiçbir şeyi bloke etmez.\n\nAncak çoğu durumda bir dosyayı veya dosya benzeri bir nesneyi okumak bloke edicidir.\n\n///\n\nEvent loop'u bloke etmemek için, *path operation function*'ı `async def` yerine normal `def` ile tanımlayabilirsiniz; böylece FastAPI ana döngüyü bloke etmemek için bunu bir thread pool worker (iş parçacığı havuzu çalışanı) üzerinde çalıştırır.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip | İpucu\n\nAsync bir fonksiyonun içinden bloklayıcı kod çağırmanız ya da bloklayıcı bir fonksiyonun içinden async bir fonksiyon çağırmanız gerekirse, FastAPI'nin kardeş kütüphanesi olan [Asyncer](https://asyncer.tiangolo.com)'ı kullanabilirsiniz.\n\n///\n\n### `yield from` { #yield-from }\n\nBir şeyin (ör. dosya benzeri bir nesne) üzerinde iterate ederken, her öğe için `yield` yapıyorsanız, `for` döngüsünü yazmak yerine `yield from` ile her öğeyi doğrudan yield edebilirsiniz.\n\nBu FastAPI'ye özgü değildir, tamamen Python'dur, ama bilinmesi güzel bir püf noktasıdır. 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/tr/docs/advanced/strict-content-type.md",
    "content": "# Sıkı Content-Type Kontrolü { #strict-content-type-checking }\n\nVarsayılan olarak FastAPI, JSON request body'leri için sıkı Content-Type header kontrolü uygular. Bu, JSON request'lerin body'lerinin JSON olarak parse edilebilmesi için geçerli bir Content-Type header'ı (örn. application/json) içermesi gerektiği anlamına gelir.\n\n## CSRF Riski { #csrf-risk }\n\nBu varsayılan davranış, çok belirli bir senaryoda bir sınıf Cross-Site Request Forgery (CSRF) saldırılarına karşı koruma sağlar.\n\nBu saldırılar, tarayıcıların aşağıdaki durumlarda herhangi bir CORS preflight kontrolü yapmadan script’lerin request göndermesine izin vermesinden faydalanır:\n\n- bir Content-Type header’ı yoksa (örn. body olarak Blob ile fetch() kullanıldığında)\n- ve herhangi bir kimlik doğrulama bilgisi gönderilmiyorsa.\n\nBu tür saldırılar özellikle şu durumlarda önemlidir:\n\n- uygulama yerelde (örn. localhost’ta) veya dahili bir ağda çalışıyorsa\n- ve uygulamada hiç kimlik doğrulama yoksa, aynı ağdan gelen her request’in güvenilir olduğu varsayılıyorsa.\n\n## Örnek Saldırı { #example-attack }\n\nYerelde çalışan bir AI agent’ı (yapay zeka ajanı) çalıştırmanın bir yolunu geliştirdiğinizi düşünün.\n\nBir API sunuyor:\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nAyrıca bir frontend var:\n\n```\nhttp://localhost:8000\n```\n\n/// tip | İpucu\n\nİkisinin de host’u aynıdır.\n\n///\n\nFrontend’i kullanarak AI agent’a sizin adınıza işler yaptırabiliyorsunuz.\n\nUygulama yerelde çalıştığı ve açık internette olmadığı için, sadece yerel ağa güvenip herhangi bir kimlik doğrulama kurmamaya karar verdiniz.\n\nKullanıcılarınızdan biri de bunu indirip yerelde çalıştırabilir.\n\nSonra kötü niyetli bir web sitesini açabilir, örneğin:\n\n```\nhttps://evilhackers.example.com\n```\n\nVe bu kötü niyetli site, body olarak Blob kullanan fetch() ile yerel API’ye request’ler gönderebilir:\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nKötü niyetli sitenin host’u ile yerel uygulamanın host’u farklı olsa bile, tarayıcı şu nedenlerle bir CORS preflight isteği tetiklemez:\n\n- Herhangi bir kimlik doğrulama yoktur, bu nedenle credential göndermesi gerekmez.\n- Tarayıcı, Content-Type header’ı eksik olduğundan JSON gönderildiğini düşünmez.\n\nBöylece kötü niyetli site, yerel AI agent’ın kullanıcının eski patronuna sinirli mesajlar göndermesini sağlayabilir... ya da daha kötüsü. 😅\n\n## Açık İnternet { #open-internet }\n\nUygulamanız açık internetteyse “ağa güvenmez” ve kimlik doğrulama olmadan kimsenin ayrıcalıklı request’ler göndermesine izin vermezsiniz.\n\nSaldırganlar tarayıcı etkileşimine ihtiyaç duymadan basitçe bir script çalıştırıp API’nize request gönderebilir, bu yüzden muhtemelen ayrıcalıklı endpoint’leri zaten güvenceye almışsınızdır.\n\nBu durumda bu saldırı/riski sizler için geçerli değildir.\n\nBu risk ve saldırı, esasen uygulama sadece yerel ağda çalıştığında ve tek koruma varsayımının bu olduğu durumlarda önemlidir.\n\n## Content-Type Olmadan Gelen Request’lere İzin Vermek { #allowing-requests-without-content-type }\n\nContent-Type header’ı göndermeyen client’ları desteklemeniz gerekiyorsa, strict kontrolü strict_content_type=False ayarıyla kapatabilirsiniz:\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\nBu ayarla, Content-Type header’ı olmayan request’lerin body’si JSON olarak parse edilir. Bu, FastAPI’nin eski sürümlerindeki davranışla aynıdır.\n\n/// info | Bilgi\n\nBu davranış ve yapılandırma FastAPI 0.132.0’da eklendi.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/advanced/sub-applications.md",
    "content": "# Alt Uygulamalar - Mount İşlemi { #sub-applications-mounts }\n\nKendi bağımsız OpenAPI şemaları ve kendi dokümantasyon arayüzleri olan iki bağımsız FastAPI uygulamasına ihtiyacınız varsa, bir ana uygulama oluşturup bir (veya daha fazla) alt uygulamayı \"mount\" edebilirsiniz.\n\n## Bir **FastAPI** uygulamasını mount etmek { #mounting-a-fastapi-application }\n\n\"Mount\" etmek, belirli bir path altında tamamen \"bağımsız\" bir uygulamayı eklemek anlamına gelir. Ardından o path’in altındaki her şeyi, alt uygulamada tanımlanan _path operation_’lar ile o alt uygulama yönetir.\n\n### Üst seviye uygulama { #top-level-application }\n\nÖnce ana, üst seviye **FastAPI** uygulamasını ve onun *path operation*’larını oluşturun:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### Alt uygulama { #sub-application }\n\nSonra alt uygulamanızı ve onun *path operation*’larını oluşturun.\n\nBu alt uygulama da standart bir FastAPI uygulamasıdır; ancak \"mount\" edilecek olan budur:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### Alt uygulamayı mount edin { #mount-the-sub-application }\n\nÜst seviye uygulamanızda (`app`), alt uygulama `subapi`’yi mount edin.\n\nBu örnekte `/subapi` path’ine mount edilecektir:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### Otomatik API dokümanlarını kontrol edin { #check-the-automatic-api-docs }\n\nŞimdi `fastapi` komutunu çalıştırın:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nVe dokümanları [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) adresinden açın.\n\nAna uygulama için otomatik API dokümanlarını göreceksiniz; yalnızca onun kendi _path operation_’larını içerir:\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\nSonra alt uygulamanın dokümanlarını [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs) adresinden açın.\n\nAlt uygulama için otomatik API dokümanlarını göreceksiniz; yalnızca onun kendi _path operation_’larını içerir ve hepsi doğru alt-path öneki `/subapi` altında yer alır:\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\nİki arayüzden herhangi biriyle etkileşime girmeyi denerseniz doğru şekilde çalıştıklarını görürsünüz; çünkü tarayıcı her bir uygulama ya da alt uygulama ile ayrı ayrı iletişim kurabilir.\n\n### Teknik Detaylar: `root_path` { #technical-details-root-path }\n\nYukarıda anlatıldığı gibi bir alt uygulamayı mount ettiğinizde FastAPI, ASGI spesifikasyonundaki `root_path` adlı bir mekanizmayı kullanarak alt uygulamaya mount path’ini iletmeyi otomatik olarak yönetir.\n\nBu sayede alt uygulama, dokümantasyon arayüzü için o path önekini kullanması gerektiğini bilir.\n\nAyrıca alt uygulamanın kendi mount edilmiş alt uygulamaları da olabilir; FastAPI tüm bu `root_path`’leri otomatik olarak yönettiği için her şey doğru şekilde çalışır.\n\n`root_path` hakkında daha fazlasını ve bunu açıkça nasıl kullanacağınızı [Proxy Arkasında](behind-a-proxy.md) bölümünde öğreneceksiniz.\n"
  },
  {
    "path": "docs/tr/docs/advanced/templates.md",
    "content": "# Şablonlar { #templates }\n\n**FastAPI** ile istediğiniz herhangi bir template engine'i kullanabilirsiniz.\n\nYaygın bir tercih, Flask ve diğer araçların da kullandığı Jinja2'dir.\n\nBunu kolayca yapılandırmak için, doğrudan **FastAPI** uygulamanızda kullanabileceğiniz yardımcı araçlar vardır (Starlette tarafından sağlanır).\n\n## Bağımlılıkları Yükleme { #install-dependencies }\n\nBir [sanal ortam](../virtual-environments.md) oluşturduğunuzdan, etkinleştirdiğinizden ve `jinja2`'yi yüklediğinizden emin olun:\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## `Jinja2Templates` Kullanımı { #using-jinja2templates }\n\n* `Jinja2Templates`'ı içe aktarın.\n* Daha sonra tekrar kullanabileceğiniz bir `templates` nesnesi oluşturun.\n* Template döndürecek *path operation* içinde bir `Request` parametresi tanımlayın.\n* Oluşturduğunuz `templates` nesnesini kullanarak bir `TemplateResponse` render edip döndürün; template'in adını, request nesnesini ve Jinja2 template'i içinde kullanılacak anahtar-değer çiftlerini içeren bir \"context\" sözlüğünü (dict) iletin.\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note | Not\n\nFastAPI 0.108.0 ve Starlette 0.29.0 öncesinde, ilk parametre `name` idi.\n\nAyrıca, daha önceki sürümlerde `request` nesnesi, Jinja2 için context içindeki anahtar-değer çiftlerinin bir parçası olarak geçirilirdi.\n\n///\n\n/// tip | İpucu\n\n`response_class=HTMLResponse` olarak tanımlarsanız doküman arayüzü (docs UI) response'un HTML olacağını anlayabilir.\n\n///\n\n/// note | Teknik Detaylar\n\n`from starlette.templating import Jinja2Templates` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici için kolaylık olması adına `starlette.templating` içeriğini `fastapi.templating` olarak da sunar. Ancak mevcut response'ların çoğu doğrudan Starlette'ten gelir. `Request` ve `StaticFiles` için de aynı durum geçerlidir.\n\n///\n\n## Template Yazma { #writing-templates }\n\nArdından örneğin `templates/item.html` konumunda bir template yazabilirsiniz:\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### Template Context Değerleri { #template-context-values }\n\nŞu HTML içeriğinde:\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n...gösterilecek olan `id`, sizin \"context\" olarak ilettiğiniz `dict` içinden alınır:\n\n```Python\n{\"id\": id}\n```\n\nÖrneğin ID değeri `42` ise, şu şekilde render edilir:\n\n```html\nItem ID: 42\n```\n\n### Template `url_for` Argümanları { #template-url-for-arguments }\n\nTemplate içinde `url_for()` da kullanabilirsiniz; argüman olarak, *path operation function*'ınızın kullandığı argümanların aynısını alır.\n\nDolayısıyla şu bölüm:\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n...*path operation function* olan `read_item(id=id)` tarafından handle edilecek URL'nin aynısına bir link üretir.\n\nÖrneğin ID değeri `42` ise, şu şekilde render edilir:\n\n```html\n<a href=\"/items/42\">\n```\n\n## Template'ler ve statik dosyalar { #templates-and-static-files }\n\nTemplate içinde `url_for()` kullanabilir ve örneğin `name=\"static\"` ile mount ettiğiniz `StaticFiles` ile birlikte kullanabilirsiniz.\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\nBu örnekte, şu şekilde `static/styles.css` konumundaki bir CSS dosyasına link verir:\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\nVe `StaticFiles` kullandığınız için, bu CSS dosyası **FastAPI** uygulamanız tarafından `/static/styles.css` URL'sinde otomatik olarak servis edilir.\n\n## Daha fazla detay { #more-details }\n\nTemplate'leri nasıl test edeceğiniz dahil daha fazla detay için [Starlette'in template dokümantasyonuna](https://www.starlette.dev/templates/) bakın.\n"
  },
  {
    "path": "docs/tr/docs/advanced/testing-dependencies.md",
    "content": "# Override Kullanarak Dependency'leri Test Etme { #testing-dependencies-with-overrides }\n\n## Test Sırasında Dependency Override Etme { #overriding-dependencies-during-testing }\n\nTest yazarken bazı durumlarda bir dependency'yi override etmek isteyebilirsiniz.\n\nOrijinal dependency'nin (ve varsa tüm alt dependency'lerinin) çalışmasını istemezsiniz.\n\nBunun yerine, yalnızca testler sırasında (hatta belki sadece belirli bazı testlerde) kullanılacak farklı bir dependency sağlarsınız; böylece orijinal dependency'nin ürettiği değerin kullanıldığı yerde, test için üretilen değeri kullanabilirsiniz.\n\n### Kullanım Senaryoları: Harici Servis { #use-cases-external-service }\n\nÖrneğin, çağırmanız gereken harici bir authentication provider'ınız olabilir.\n\nOna bir token gönderirsiniz ve o da authenticated bir user döndürür.\n\nBu provider request başına ücret alıyor olabilir ve onu çağırmak, testlerde sabit bir mock user kullanmaya kıyasla daha fazla zaman alabilir.\n\nMuhtemelen harici provider'ı bir kez test etmek istersiniz; ancak çalışan her testte onu çağırmanız şart değildir.\n\nBu durumda, o provider'ı çağıran dependency'yi override edebilir ve yalnızca testleriniz için mock user döndüren özel bir dependency kullanabilirsiniz.\n\n### `app.dependency_overrides` Attribute'ünü Kullanın { #use-the-app-dependency-overrides-attribute }\n\nBu tür durumlar için **FastAPI** uygulamanızda `app.dependency_overrides` adında bir attribute bulunur; bu basit bir `dict`'tir.\n\nTest için bir dependency'yi override etmek istediğinizde, key olarak orijinal dependency'yi (bir function), value olarak da override edecek dependency'nizi (başka bir function) verirsiniz.\n\nBöylece **FastAPI**, orijinal dependency yerine bu override'ı çağırır.\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip | İpucu\n\n**FastAPI** uygulamanızın herhangi bir yerinde kullanılan bir dependency için override tanımlayabilirsiniz.\n\nOrijinal dependency bir *path operation function* içinde, bir *path operation decorator* içinde (return value kullanmadığınız durumlarda), bir `.include_router()` çağrısında, vb. kullanılıyor olabilir.\n\nFastAPI yine de onu override edebilir.\n\n///\n\nSonrasında override'larınızı (yani kaldırıp sıfırlamayı) `app.dependency_overrides` değerini boş bir `dict` yaparak gerçekleştirebilirsiniz:\n\n```Python\napp.dependency_overrides = {}\n```\n\n\n/// tip | İpucu\n\nBir dependency'yi yalnızca bazı testler sırasında override etmek istiyorsanız, override'ı testin başında (test function'ının içinde) ayarlayıp testin sonunda (yine test function'ının sonunda) sıfırlayabilirsiniz.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/advanced/testing-events.md",
    "content": "# Event'leri Test Etme: lifespan ve startup - shutdown { #testing-events-lifespan-and-startup-shutdown }\n\nTest'lerinizde `lifespan`'ın çalışması gerektiğinde, `TestClient`'ı bir `with` ifadesiyle kullanabilirsiniz:\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\n\nBu konuda daha fazla ayrıntıyı resmi Starlette dokümantasyon sitesindeki [\"Testlerde lifespan'ı çalıştırma\"](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) bölümünde okuyabilirsiniz.\n\nKullanımdan kaldırılmış `startup` ve `shutdown` event'leri için ise `TestClient`'ı aşağıdaki gibi kullanabilirsiniz:\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/tr/docs/advanced/testing-websockets.md",
    "content": "# WebSockets'i Test Etmek { #testing-websockets }\n\nWebSockets'i test etmek için aynı `TestClient`'ı kullanabilirsiniz.\n\nBunun için `TestClient`'ı bir `with` ifadesinde kullanarak WebSocket'e bağlanırsınız:\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note | Not\n\nDaha fazla detay için Starlette'in [WebSockets'i test etme](https://www.starlette.dev/testclient/#testing-websocket-sessions) dokümantasyonuna bakın.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/advanced/using-request-directly.md",
    "content": "# Request'i Doğrudan Kullanmak { #using-the-request-directly }\n\nŞu ana kadar, ihtiyacınız olan request parçalarını tipleriyle birlikte tanımlıyordunuz.\n\nVerileri şuradan alarak:\n\n* path'ten parameter olarak.\n* Header'lardan.\n* Cookie'lerden.\n* vb.\n\nBunu yaptığınızda **FastAPI**, bu verileri doğrular (validate eder), dönüştürür ve API'niz için dokümantasyonu otomatik olarak üretir.\n\nAncak bazı durumlarda `Request` nesnesine doğrudan erişmeniz gerekebilir.\n\n## `Request` nesnesi hakkında detaylar { #details-about-the-request-object }\n\n**FastAPI** aslında altta **Starlette** çalıştırır ve üstüne çeşitli araçlardan oluşan bir katman ekler. Bu yüzden gerektiğinde Starlette'in [`Request`](https://www.starlette.dev/requests/) nesnesini doğrudan kullanabilirsiniz.\n\nBu ayrıca şu anlama gelir: `Request` nesnesinden veriyi doğrudan alırsanız (örneğin body'yi okursanız) FastAPI bu veriyi doğrulamaz, dönüştürmez veya dokümante etmez (otomatik API arayüzü için OpenAPI ile).\n\nBuna rağmen normal şekilde tanımladığınız diğer herhangi bir parameter (örneğin Pydantic model ile body) yine doğrulanır, dönüştürülür, annotate edilir, vb.\n\nAma bazı özel durumlarda `Request` nesnesini almak faydalıdır.\n\n## `Request` nesnesini doğrudan kullanın { #use-the-request-object-directly }\n\n*Path operation function* içinde client'ın IP adresini/host'unu almak istediğinizi düşünelim.\n\nBunun için request'e doğrudan erişmeniz gerekir.\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\nTipi `Request` olan bir *path operation function* parameter'ı tanımladığınızda **FastAPI**, o parameter'a `Request` nesnesini geçmesi gerektiğini anlar.\n\n/// tip | İpucu\n\nBu örnekte, request parameter'ının yanında bir path parameter'ı da tanımladığımıza dikkat edin.\n\nDolayısıyla path parameter'ı çıkarılır, doğrulanır, belirtilen tipe dönüştürülür ve OpenAPI ile annotate edilir.\n\nAynı şekilde, diğer parameter'ları normal biçimde tanımlamaya devam edip buna ek olarak `Request` de alabilirsiniz.\n\n///\n\n## `Request` dokümantasyonu { #request-documentation }\n\n[Resmi Starlette dokümantasyon sitesinde `Request` nesnesiyle ilgili daha fazla detayı](https://www.starlette.dev/requests/) okuyabilirsiniz.\n\n/// note | Teknik Detaylar\n\n`from starlette.requests import Request` de kullanabilirsiniz.\n\n**FastAPI** bunu size (geliştiriciye) kolaylık olsun diye doğrudan sunar. Ancak kendisi doğrudan Starlette'ten gelir.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\n**FastAPI** ile [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) kullanabilirsiniz.\n\n## `websockets` Kurulumu { #install-websockets }\n\nBir [sanal ortam](../virtual-environments.md) oluşturduğunuzdan, onu aktive ettiğinizden ve `websockets`'i (\"WebSocket\" protokolünü kullanmayı kolaylaştıran bir Python kütüphanesi) kurduğunuzdan emin olun:\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## WebSockets client { #websockets-client }\n\n### Production'da { #in-production }\n\nProduction sisteminizde muhtemelen React, Vue.js veya Angular gibi modern bir framework ile oluşturulmuş bir frontend vardır.\n\nWebSockets kullanarak backend'inizle iletişim kurmak için de büyük ihtimalle frontend'inizin sağladığı yardımcı araçları kullanırsınız.\n\nYa da native kod ile doğrudan WebSocket backend'inizle iletişim kuran native bir mobil uygulamanız olabilir.\n\nVeya WebSocket endpoint'i ile iletişim kurmak için başka herhangi bir yönteminizi de kullanıyor olabilirsiniz.\n\n---\n\nAncak bu örnek için, tamamı uzun bir string içinde olacak şekilde biraz JavaScript içeren çok basit bir HTML dokümanı kullanacağız.\n\nElbette bu optimal değil ve production için kullanmazsınız.\n\nProduction'da yukarıdaki seçeneklerden birini kullanırsınız.\n\nAma WebSockets'in server tarafına odaklanmak ve çalışan bir örnek görmek için en basit yol bu:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## Bir `websocket` Oluşturun { #create-a-websocket }\n\n**FastAPI** uygulamanızda bir `websocket` oluşturun:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | Teknik Detaylar\n\n`from starlette.websockets import WebSocket` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak işinizi kolaylaştırmak için aynı `WebSocket`'i doğrudan sağlar. Ancak aslında doğrudan Starlette'ten gelir.\n\n///\n\n## Mesajları `await` Edin ve Mesaj Gönderin { #await-for-messages-and-send-messages }\n\nWebSocket route'unuzda mesajları `await` edebilir ve mesaj gönderebilirsiniz.\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\nBinary, text ve JSON verisi alıp gönderebilirsiniz.\n\n## Deneyin { #try-it }\n\nKodunuzu `main.py` dosyasına koyun ve ardından uygulamanızı çalıştırın:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nTarayıcınızda [http://127.0.0.1:8000](http://127.0.0.1:8000) adresini açın.\n\nŞuna benzer basit bir sayfa göreceksiniz:\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\nInput kutusuna mesaj yazıp gönderebilirsiniz:\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\nVe WebSockets kullanan **FastAPI** uygulamanız yanıt döndürecektir:\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\nBirçok mesaj gönderebilir (ve alabilirsiniz):\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\nVe hepsinde aynı WebSocket bağlantısı kullanılacaktır.\n\n## `Depends` ve Diğerlerini Kullanma { #using-depends-and-others }\n\nWebSocket endpoint'lerinde `fastapi` içinden import edip şunları kullanabilirsiniz:\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\nDiğer FastAPI endpoint'leri/*path operations* ile aynı şekilde çalışırlar:\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info\n\nBu bir WebSocket olduğu için `HTTPException` raise etmek pek anlamlı değildir; bunun yerine `WebSocketException` raise ederiz.\n\n[Spesifikasyonda tanımlanan geçerli kodlar](https://tools.ietf.org/html/rfc6455#section-7.4.1) arasından bir kapatma kodu kullanabilirsiniz.\n\n///\n\n### Dependency'lerle WebSockets'i Deneyin { #try-the-websockets-with-dependencies }\n\nUygulamanızı çalıştırın:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nTarayıcınızda [http://127.0.0.1:8000](http://127.0.0.1:8000) adresini açın.\n\nBurada şunları ayarlayabilirsiniz:\n\n* path'te kullanılan \"Item ID\".\n* query parametresi olarak kullanılan \"Token\".\n\n/// tip\n\nquery'deki `token` değerinin bir dependency tarafından ele alınacağına dikkat edin.\n\n///\n\nBununla WebSocket'e bağlanabilir, ardından mesaj gönderip alabilirsiniz:\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## Bağlantı Kopmalarını ve Birden Fazla Client'ı Yönetme { #handling-disconnections-and-multiple-clients }\n\nBir WebSocket bağlantısı kapandığında, `await websocket.receive_text()` bir `WebSocketDisconnect` exception'ı raise eder; ardından bunu bu örnekteki gibi yakalayıp (catch) yönetebilirsiniz.\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\nDenemek için:\n\n* Uygulamayı birden fazla tarayıcı sekmesiyle açın.\n* Bu sekmelerden mesaj yazın.\n* Sonra sekmelerden birini kapatın.\n\nBu, `WebSocketDisconnect` exception'ını raise eder ve diğer tüm client'lar şuna benzer bir mesaj alır:\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip\n\nYukarıdaki uygulama, birden fazla WebSocket bağlantısına mesajları nasıl yönetip broadcast edeceğinizi göstermek için minimal ve basit bir örnektir.\n\nAncak her şey memory'de, tek bir list içinde yönetildiği için yalnızca process çalıştığı sürece ve yalnızca tek bir process ile çalışacaktır.\n\nFastAPI ile kolay entegre olan ama Redis, PostgreSQL vb. tarafından desteklenen daha sağlam bir şeye ihtiyacınız varsa [encode/broadcaster](https://github.com/encode/broadcaster)'a göz atın.\n\n///\n\n## Daha Fazla Bilgi { #more-info }\n\nSeçenekler hakkında daha fazlasını öğrenmek için Starlette dokümantasyonunda şunlara bakın:\n\n* [`WebSocket` class'ı](https://www.starlette.dev/websockets/).\n* [Class tabanlı WebSocket yönetimi](https://www.starlette.dev/endpoints/#websocketendpoint).\n"
  },
  {
    "path": "docs/tr/docs/advanced/wsgi.md",
    "content": "# WSGI'yi Dahil Etme - Flask, Django ve Diğerleri { #including-wsgi-flask-django-others }\n\nWSGI uygulamalarını [Alt Uygulamalar - Mount Etme](sub-applications.md), [Bir Proxy Arkasında](behind-a-proxy.md) bölümlerinde gördüğünüz gibi mount edebilirsiniz.\n\nBunun için `WSGIMiddleware`'ı kullanabilir ve bunu WSGI uygulamanızı (örneğin Flask, Django vb.) sarmalamak için kullanabilirsiniz.\n\n## `WSGIMiddleware` Kullanımı { #using-wsgimiddleware }\n\n/// info\n\nBunun için `a2wsgi` kurulmalıdır; örneğin `pip install a2wsgi` ile.\n\n///\n\n`WSGIMiddleware`'ı `a2wsgi` paketinden import etmeniz gerekir.\n\nArdından WSGI (örn. Flask) uygulamasını middleware ile sarmalayın.\n\nVe sonra bunu bir path'in altına mount edin.\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note\n\nÖnceden, `fastapi.middleware.wsgi` içindeki `WSGIMiddleware`'ın kullanılması öneriliyordu, ancak artık kullanımdan kaldırıldı.\n\nBunun yerine `a2wsgi` paketini kullanmanız önerilir. Kullanım aynıdır.\n\nSadece `a2wsgi` paketinin kurulu olduğundan emin olun ve `WSGIMiddleware`'ı `a2wsgi` içinden doğru şekilde import edin.\n\n///\n\n## Kontrol Edelim { #check-it }\n\nArtık `/v1/` path'i altındaki her request Flask uygulaması tarafından işlenecektir.\n\nGeri kalanı ise **FastAPI** tarafından işlenecektir.\n\nEğer uygulamanızı çalıştırıp [http://localhost:8000/v1/](http://localhost:8000/v1/) adresine giderseniz, Flask'tan gelen response'u göreceksiniz:\n\n```txt\nHello, World from Flask!\n```\n\nVe eğer [http://localhost:8000/v2](http://localhost:8000/v2) adresine giderseniz, FastAPI'den gelen response'u göreceksiniz:\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/tr/docs/alternatives.md",
    "content": "# Alternatifler, İlham Kaynakları ve Karşılaştırmalar { #alternatives-inspiration-and-comparisons }\n\n**FastAPI**'a nelerin ilham verdiği, alternatiflerle nasıl karşılaştırıldığı ve onlardan neler öğrendiği.\n\n## Giriş { #intro }\n\nBaşkalarının daha önceki çalışmaları olmasaydı, **FastAPI** var olmazdı.\n\nÖnceden oluşturulan birçok araç, ortaya çıkışına ilham verdi.\n\nYıllarca yeni bir framework oluşturmaktan kaçındım. Önce **FastAPI**’ın bugün kapsadığı özelliklerin tamamını, birçok farklı framework, eklenti ve araçla çözmeyi denedim.\n\nAncak bir noktada, geçmişteki araçlardan en iyi fikirleri alıp, mümkün olan en iyi şekilde birleştiren ve daha önce mevcut olmayan dil özelliklerini (Python 3.6+ tip belirteçleri) kullanarak tüm bu özellikleri sağlayan bir şey geliştirmekten başka seçenek kalmadı.\n\n## Daha Önce Geliştirilen Araçlar { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\nPython ekosistemindeki en popüler ve yaygın olarak güvenilen web framework’üdür. Instagram gibi sistemleri geliştirmede kullanılmıştır.\n\nMySQL veya PostgreSQL gibi ilişkisel veritabanlarıyla nispeten sıkı bağlıdır, bu nedenle Couchbase, MongoDB, Cassandra vb. gibi bir NoSQL veritabanını ana depolama motoru olarak kullanmak pek kolay değildir.\n\nModern bir ön uç (React, Vue.js, Angular gibi) veya onunla haberleşen diğer sistemler (ör. <abbr title=\"Internet of Things - Nesnelerin İnterneti\">IoT</abbr> cihazları) tarafından tüketilen API’lar üretmekten ziyade, arka uçta HTML üretmek için oluşturulmuştur.\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nDjango REST Framework, Django üzerine kurulu esnek bir araç takımı olarak, Web API’lar geliştirmeyi ve Django’nun API kabiliyetlerini artırmayı hedefler.\n\nMozilla, Red Hat ve Eventbrite gibi birçok şirket tarafından kullanılmaktadır.\n\n**Otomatik API dökümantasyonu**nun ilk örneklerinden biriydi ve bu, “**FastAPI** arayışına” ilham veren ilk fikirlerden biriydi.\n\n/// note | Not\n\nDjango REST Framework, **FastAPI**'ın üzerine inşa edildiği Starlette ve Uvicorn'un da yaratıcısı olan Tom Christie tarafından geliştirildi.\n\n///\n\n/// check | **FastAPI**'a ilham olan\n\nOtomatik API dökümantasyonu sağlayan bir web arayüzü sunmak.\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask bir “mikroframework”tür, Django’da varsayılan gelen pek çok özelliği (veritabanı entegrasyonları vb.) içermez.\n\nBu basitlik ve esneklik, NoSQL veritabanlarını ana veri depolama sistemi olarak kullanmak gibi şeyleri mümkün kılar.\n\nÇok basit olduğu için öğrenmesi nispeten sezgiseldir, ancak dökümantasyon bazı noktalarda biraz teknikleşebilir.\n\nAyrıca veritabanı, kullanıcı yönetimi veya Django’da önceden gelen pek çok özelliğe ihtiyaç duymayan uygulamalar için de yaygın olarak kullanılır. Yine de bu özelliklerin çoğu eklentilerle eklenebilir.\n\nBileşenlerin ayrık olması ve gerekeni tam olarak kapsayacak şekilde genişletilebilen bir “mikroframework” olması, özellikle korumak istediğim bir özelliktir.\n\nFlask’ın sadeliği göz önüne alındığında, API geliştirmek için iyi bir aday gibi görünüyordu. Sırada, Flask için bir “Django REST Framework” bulmak vardı.\n\n/// check | **FastAPI**'a ilham olan\n\nGereken araç ve parçaları kolayca eşleştirip birleştirmeyi sağlayan bir mikroframework olmak.\n\nBasit ve kullanımı kolay bir yönlendirme (routing) sistemine sahip olmak.\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI** aslında **Requests**’in bir alternatifi değildir. Kapsamları çok farklıdır.\n\nHatta bir FastAPI uygulamasının içinde Requests kullanmak yaygındır.\n\nYine de FastAPI, Requests’ten epey ilham almıştır.\n\n**Requests** bir kütüphane olarak API’larla (istemci olarak) etkileşime geçmeye yararken, **FastAPI** API’lar (sunucu olarak) geliştirmeye yarar.\n\nYani daha çok zıt uçlardadırlar ama birbirlerini tamamlarlar.\n\nRequests çok basit ve sezgisel bir tasarıma sahiptir, mantıklı varsayılanlarla kullanımı çok kolaydır. Aynı zamanda çok güçlü ve özelleştirilebilirdir.\n\nBu yüzden resmi web sitesinde de söylendiği gibi:\n\n> Requests, tüm zamanların en çok indirilen Python paketlerinden biridir\n\nKullanımı çok basittir. Örneğin bir `GET` isteği yapmak için:\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\nBuna karşılık bir FastAPI API *path operation*’ı şöyle olabilir:\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\n`requests.get(...)` ile `@app.get(...)` arasındaki benzerliklere bakın.\n\n/// check | **FastAPI**'a ilham olan\n\n* Basit ve sezgisel bir API’ya sahip olmak.\n* HTTP metot isimlerini (işlemlerini) doğrudan, anlaşılır ve sezgisel bir şekilde kullanmak.\n* Mantıklı varsayılanlara sahip olmak ama güçlü özelleştirmeler de sunmak.\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\nDjango REST Framework’ünden istediğim ana özellik otomatik API dökümantasyonuydu.\n\nSonra API’ları JSON (veya JSON’un bir uzantısı olan YAML) kullanarak dökümante etmek için Swagger adlı bir standart olduğunu gördüm.\n\nVe Swagger API’ları için zaten oluşturulmuş bir web arayüzü vardı. Yani bir API için Swagger dökümantasyonu üretebilmek, bu web arayüzünü otomatik kullanabilmek demekti.\n\nBir noktada Swagger, Linux Foundation’a devredildi ve OpenAPI olarak yeniden adlandırıldı.\n\nBu yüzden, 2.0 sürümü söz konusu olduğunda “Swagger”, 3+ sürümler için ise “OpenAPI” denmesi yaygındır.\n\n/// check | **FastAPI**'a ilham olan\n\nAPI spesifikasyonları için özel bir şema yerine açık bir standart benimsemek ve kullanmak.\n\nVe standartlara dayalı kullanıcı arayüzü araçlarını entegre etmek:\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\nBu ikisi oldukça popüler ve istikrarlı oldukları için seçildi; hızlı bir aramayla OpenAPI için onlarca alternatif kullanıcı arayüzü bulabilirsiniz (**FastAPI** ile de kullanabilirsiniz).\n\n///\n\n### Flask REST framework’leri { #flask-rest-frameworks }\n\nBirçok Flask REST framework’ü var; ancak zaman ayırıp inceledikten sonra çoğunun artık sürdürülmediğini veya bazı kritik sorunlar nedeniyle uygun olmadıklarını gördüm.\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nAPI sistemlerinin ihtiyaç duyduğu temel özelliklerden biri, koddan (Python) veriyi alıp ağ üzerinden gönderilebilecek bir şeye dönüştürmek, yani veri “<dfn title=\"başka adlarla: serileştirme, dönüştürme\">dönüşüm</dfn>”üdür. Örneğin, bir veritabanından gelen verileri içeren bir objeyi JSON objesine dönüştürmek, `datetime` objelerini string’e çevirmek vb.\n\nAPI’ların ihtiyaç duyduğu bir diğer önemli özellik, veri doğrulamadır; belirli parametreler göz önüne alındığında verinin geçerli olduğundan emin olmak. Örneğin, bir alanın `int` olması ve rastgele bir metin olmaması. Bu özellikle dışarıdan gelen veriler için kullanışlıdır.\n\nBir veri doğrulama sistemi olmadan, tüm bu kontrolleri kod içinde el ile yapmanız gerekir.\n\nMarshmallow, bu özellikleri sağlamak için inşa edildi. Harika bir kütüphanedir ve geçmişte çok kullandım.\n\nAncak Python tip belirteçlerinden önce yazılmıştır. Dolayısıyla her <dfn title=\"verinin nasıl oluşturulması gerektiğinin tanımı\">şemayı</dfn> tanımlamak için Marshmallow’un sağladığı belirli yardımcılar ve sınıflar kullanılır.\n\n/// check | **FastAPI**'a ilham olan\n\nKodla, veri tiplerini ve doğrulamayı otomatik sağlayan “şemalar” tanımlamak.\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nAPI’ların ihtiyaç duyduğu bir diğer büyük özellik, gelen isteklerden veriyi <dfn title=\"okuyup Python verisine dönüştürme\">ayrıştırma</dfn>dır.\n\nWebargs, Flask dahil birkaç framework’ün üzerinde bunu sağlamak için geliştirilmiş bir araçtır.\n\nVeri doğrulama için arka planda Marshmallow’u kullanır. Aynı geliştiriciler tarafından yazılmıştır.\n\n**FastAPI**’dan önce benim de çok kullandığım harika bir araçtır.\n\n/// info | Bilgi\n\nWebargs, Marshmallow geliştiricileri tarafından oluşturuldu.\n\n///\n\n/// check | **FastAPI**'a ilham olan\n\nGelen istek verisini otomatik doğrulamak.\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow ve Webargs; doğrulama, ayrıştırma ve dönüşümü eklenti olarak sağlar.\n\nAma dökümantasyon eksikti. Sonra APISpec geliştirildi.\n\nBirçok framework için bir eklentidir (Starlette için de bir eklenti vardır).\n\nÇalışma şekli: Her bir route’u işleyen fonksiyonun docstring’i içine YAML formatında şema tanımı yazarsınız.\n\nVe OpenAPI şemaları üretir.\n\nFlask, Starlette, Responder vb. için çalışma şekli böyledir.\n\nAncak yine, Python metni içinde (kocaman bir YAML) mikro bir söz dizimi sorunu ortaya çıkar.\n\nEditör bu konuda pek yardımcı olamaz. Parametreleri veya Marshmallow şemalarını değiştirip docstring’teki YAML’ı güncellemeyi unutursak, üretilen şema geçerliliğini yitirir.\n\n/// info | Bilgi\n\nAPISpec, Marshmallow geliştiricileri tarafından oluşturuldu.\n\n///\n\n/// check | **FastAPI**'a ilham olan\n\nAPI’lar için açık standart olan OpenAPI’ı desteklemek.\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\nWebargs, Marshmallow ve APISpec’i bir araya getiren bir Flask eklentisidir.\n\nWebargs ve Marshmallow’dan aldığı bilgiyi kullanarak, APISpec ile otomatik OpenAPI şemaları üretir.\n\nHarika ama yeterince değer görmeyen bir araçtır. Mevcut birçok Flask eklentisinden çok daha popüler olmalıydı. Muhtemelen dökümantasyonunun fazla kısa ve soyut olmasından kaynaklanıyor olabilir.\n\nPython docstring’leri içine YAML (farklı bir söz dizimi) yazma ihtiyacını ortadan kaldırdı.\n\n**FastAPI**’yı inşa edene kadar, Flask + Flask-apispec + Marshmallow + Webargs kombinasyonu benim favori arka uç stack’imdi.\n\nBunu kullanmak, birkaç Flask full‑stack üreticisinin ortaya çıkmasına yol açtı. Şu ana kadar benim (ve birkaç harici ekibin) kullandığı ana stack’ler:\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\nAynı full‑stack üreticiler, [**FastAPI** Proje Üreticileri](project-generation.md)’nin de temelini oluşturdu.\n\n/// info | Bilgi\n\nFlask-apispec, Marshmallow geliştiricileri tarafından oluşturuldu.\n\n///\n\n/// check | **FastAPI**'a ilham olan\n\nVeri dönüşümü ve doğrulamayı tanımlayan aynı koddan, OpenAPI şemasını otomatik üretmek.\n\n///\n\n### [NestJS](https://nestjs.com/) (ve [Angular](https://angular.io/)) { #nestjs-and-angular }\n\nBu Python bile değil; NestJS, Angular’dan ilham alan bir JavaScript (TypeScript) NodeJS framework’üdür.\n\nFlask-apispec ile yapılabilene kısmen benzer bir şey başarır.\n\nAngular 2’den esinlenen, entegre bir bağımlılık enjeksiyonu sistemi vardır. “Injectable”ları önceden kaydetmeyi gerektirir (bildiğim diğer bağımlılık enjeksiyonu sistemlerinde olduğu gibi), bu da ayrıntıyı ve kod tekrarını artırır.\n\nParametreler TypeScript tipleriyle (Python tip belirteçlerine benzer) açıklandığından, editör desteği oldukça iyidir.\n\nAncak TypeScript tip bilgisi JavaScript’e derlemeden sonra korunmadığından, aynı anda tiplere dayanarak doğrulama, dönüşüm ve dökümantasyon tanımlanamaz. Bu ve bazı tasarım kararları nedeniyle doğrulama, dönüşüm ve otomatik şema üretimi için birçok yere dekoratör eklemek gerekir; proje oldukça ayrıntılı hâle gelir.\n\nİçiçe modelleri çok iyi işleyemez. Yani istek gövdesindeki JSON, içinde başka alanları ve onlar da içiçe JSON objelerini içeriyorsa, doğru şekilde dökümante edilip doğrulanamaz.\n\n/// check | **FastAPI**'a ilham olan\n\nHarika editör desteği için Python tiplerini kullanmak.\n\nGüçlü bir bağımlılık enjeksiyonu sistemine sahip olmak. Kod tekrarını en aza indirmenin bir yolunu bulmak.\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\n`asyncio` tabanlı, son derece hızlı ilk Python framework’lerinden biriydi. Flask’a oldukça benzer olacak şekilde geliştirilmişti.\n\n/// note | Teknik Detaylar\n\nVarsayılan Python `asyncio` döngüsü yerine [`uvloop`](https://github.com/MagicStack/uvloop) kullanır; hızını esasen bu sağlar.\n\nAçık kıyaslamalarda, bugün Uvicorn ve Starlette’in Sanic’ten daha hızlı olduğu görülür; Sanic bu ikisine ilham vermiştir.\n\n///\n\n/// check | **FastAPI**'a ilham olan\n\nÇok yüksek performans elde etmenin bir yolunu bulmak.\n\nBu yüzden **FastAPI**, en hızlı framework olduğu için (üçüncü parti kıyaslamalara göre) Starlette üzerine kuruludur.\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon, başka bir yüksek performanslı Python framework’üdür; minimal olacak şekilde tasarlanmış ve Hug gibi diğer framework’lere temel olmuştur.\n\nİki parametre alan fonksiyonlar etrafında tasarlanmıştır: “request” ve “response”. İstekten parçalar “okur”, cevaba parçalar “yazarsınız”. Bu tasarım nedeniyle, fonksiyon parametreleriyle standart Python tip belirteçlerini kullanarak istek parametrelerini ve gövdelerini ilan etmek mümkün değildir.\n\nDolayısıyla veri doğrulama, dönüşüm ve dökümantasyon kodda yapılmalı; otomatik olmaz. Ya da Hug’da olduğu gibi Falcon’un üzerine bir framework olarak uygulanmalıdır. Falcon’un tasarımından etkilenen ve tek bir request objesi ile response objesini parametre olarak alan diğer framework’lerde de aynı ayrım vardır.\n\n/// check | **FastAPI**'a ilham olan\n\nHarika performans elde etmenin yollarını bulmak.\n\nHug ile birlikte (Hug, Falcon’a dayanır) **FastAPI**’da fonksiyonlarda opsiyonel bir `response` parametresi ilan edilmesi fikrine ilham vermek. FastAPI’da bu parametre çoğunlukla header, cookie ve alternatif durum kodlarını ayarlamak için kullanılır.\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\n**FastAPI**’ı geliştirmenin ilk aşamalarında Molten’ı keşfettim. Oldukça benzer fikirleri vardı:\n\n* Python tip belirteçlerine dayanır.\n* Bu tiplere bağlı doğrulama ve dökümantasyon sağlar.\n* Bağımlılık enjeksiyonu sistemi vardır.\n\nPydantic gibi doğrulama, dönüşüm ve dökümantasyon için üçüncü parti bir kütüphane kullanmaz; kendi içinde sağlar. Bu yüzden bu veri tipi tanımlarını tekrar kullanmak o kadar kolay olmaz.\n\nBiraz daha ayrıntılı yapılandırma ister. Ve ASGI yerine WSGI tabanlı olduğundan, Uvicorn, Starlette ve Sanic gibi araçların yüksek performansından faydalanmaya yönelik tasarlanmamıştır.\n\nBağımlılık enjeksiyonu sistemi, bağımlılıkların önceden kaydedilmesini ve tiplerine göre çözülmesini gerektirir. Yani belirli bir tipi sağlayan birden fazla “bileşen” tanımlanamaz.\n\nRoute’lar, endpoint’i işleyen fonksiyonun üstüne konan dekoratörlerle değil, tek bir yerde, farklı yerlerde tanımlanmış fonksiyonlar kullanılarak ilan edilir. Bu yaklaşım, Flask (ve Starlette) yerine Django’ya daha yakındır; kodda aslında birbirine sıkı bağlı olan şeyleri ayırır.\n\n/// check | **FastAPI**'a ilham olan\n\nModel özelliklerinin “varsayılan” değerlerini kullanarak veri tiplerine ekstra doğrulamalar tanımlamak. Bu, editör desteğini iyileştirir ve Pydantic’te daha önce yoktu.\n\nBu yaklaşım, Pydantic’te de aynı doğrulama beyan stilinin desteklenmesine ilham verdi (bu işlevselliklerin tamamı artık Pydantic’te mevcut).\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug, Python tip belirteçlerini kullanarak API parametre tiplerini ilan etmeyi uygulayan ilk framework’lerden biriydi. Diğer araçlara da ilham veren harika bir fikirdi.\n\nStandart Python tipleri yerine kendi özel tiplerini kullansa da büyük bir adımdı.\n\nJSON ile tüm API’ı beyan eden özel bir şema üreten ilk framework’lerden biriydi.\n\nOpenAPI veya JSON Schema gibi bir standarda dayanmadığı için Swagger UI gibi diğer araçlarla doğrudan entegre edilemezdi. Yine de oldukça yenilikçiydi.\n\nNadir bir özelliği daha vardı: aynı framework ile hem API’lar hem de CLI’lar oluşturmak mümkündü.\n\nSenkron Python web framework’leri için önceki standart olan WSGI’ye dayandığından, WebSocket vb. şeyleri işleyemez, ancak yine de yüksek performansa sahiptir.\n\n/// info | Bilgi\n\nHug, Python dosyalarındaki import’ları otomatik sıralayan harika bir araç olan [`isort`](https://github.com/timothycrosley/isort)’un geliştiricisi Timothy Crosley tarafından geliştirildi.\n\n///\n\n/// check | **FastAPI**'a ilham olan fikirler\n\nHug, APIStar’ın bazı kısımlarına ilham verdi ve APIStar ile birlikte en umut verici bulduğum araçlardandı.\n\n**FastAPI**, parametreleri ilan etmek ve API’ı otomatik tanımlayan bir şema üretmek için Python tip belirteçlerini kullanma fikrini Hug’dan ilhamla benimsedi.\n\nAyrıca header ve cookie ayarlamak için fonksiyonlarda `response` parametresi ilan etme fikrine de Hug ilham verdi.\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0.5) { #apistar-0-5 }\n\n**FastAPI**’yi inşa etmeye karar vermeden hemen önce **APIStar** sunucusunu buldum. Aradığım şeylerin neredeyse hepsine sahipti ve harika bir tasarımı vardı.\n\nPython tip belirteçleriyle parametreleri ve istekleri ilan eden bir framework’ün gördüğüm ilk örneklerindendi (NestJS ve Molten’dan önce). Aşağı yukarı Hug ile aynı zamanlarda buldum; ancak APIStar, OpenAPI standardını kullanıyordu.\n\nFarklı yerlerdeki aynı tip belirteçlerine dayanarak otomatik veri doğrulama, veri dönüşümü ve OpenAPI şeması üretimi vardı.\n\nGövde şema tanımları Pydantic’tekiyle aynı Python tip belirteçlerini kullanmıyordu; biraz daha Marshmallow’a benziyordu. Bu yüzden editör desteği o kadar iyi olmazdı; yine de APIStar mevcut en iyi seçenekti.\n\nO dönem kıyaslamalarda en iyi performansa sahipti (sadece Starlette tarafından geçiliyordu).\n\nBaşta otomatik API dökümantasyonu sunan bir web arayüzü yoktu ama Swagger UI ekleyebileceğimi biliyordum.\n\nBağımlılık enjeksiyonu sistemi vardı. Diğer araçlarda olduğu gibi bileşenlerin önceden kaydedilmesini gerektiriyordu. Yine de harika bir özellikti.\n\nGüvenlik entegrasyonu olmadığından tam bir projede kullanamadım; bu yüzden Flask-apispec tabanlı full‑stack üreticilerle sahip olduğum özelliklerin tamamını ikame edemedim. Bu işlevi ekleyen bir pull request’i yapılacaklar listeme almıştım.\n\nSonra projenin odağı değişti.\n\nArtık bir API web framework’ü değildi; geliştirici Starlette’e odaklanmak zorundaydı.\n\nŞimdi APIStar, bir web framework’ü değil, OpenAPI spesifikasyonlarını doğrulamak için araçlar takımından ibaret.\n\n/// info | Bilgi\n\nAPIStar, aşağıdakilerin de yaratıcısı olan Tom Christie tarafından geliştirildi:\n\n* Django REST Framework\n* **FastAPI**’ın üzerine kurulu Starlette\n* Starlette ve **FastAPI** tarafından kullanılan Uvicorn\n\n///\n\n/// check | **FastAPI**'a ilham olan\n\nVar olmak.\n\nAynı Python tipleriyle (hem veri doğrulama, dönüşüm ve dökümantasyon) birden çok şeyi ilan etmek ve aynı anda harika editör desteği sağlamak, bence dahiyane bir fikirdi.\n\nUzun süre benzer bir framework arayıp birçok alternatifi denedikten sonra, APIStar mevcut en iyi seçenekti.\n\nSonra APIStar bir sunucu olarak var olmaktan çıktı ve Starlette oluşturuldu; böyle bir sistem için daha iyi bir temel oldu. Bu, **FastAPI**’yi inşa etmek için son ilhamdı.\n\nÖnceki bu araçlardan edinilen deneyimler üzerine özellikleri, tip sistemi ve diğer kısımları geliştirip artırırken, **FastAPI**’yi APIStar’ın “ruhani varisi” olarak görüyorum.\n\n///\n\n## **FastAPI** Tarafından Kullanılanlar { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic, Python tip belirteçlerine dayalı olarak veri doğrulama, dönüşüm ve dökümantasyon (JSON Schema kullanarak) tanımlamak için bir kütüphanedir.\n\nBu onu aşırı sezgisel kılar.\n\nMarshmallow ile karşılaştırılabilir. Kıyaslamalarda Marshmallow’dan daha hızlıdır. Aynı Python tip belirteçlerine dayandığı için editör desteği harikadır.\n\n/// check | **FastAPI** bunu şurada kullanır\n\nTüm veri doğrulama, veri dönüşümü ve JSON Schema tabanlı otomatik model dökümantasyonunu halletmekte.\n\n**FastAPI** daha sonra bu JSON Schema verisini alır ve (yaptığı diğer şeylerin yanı sıra) OpenAPI içine yerleştirir.\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette, yüksek performanslı asyncio servisleri oluşturmak için ideal, hafif bir <dfn title=\"Asenkron Python web uygulamaları geliştirmek için yeni standart\">ASGI</dfn> framework’ü/araç takımıdır.\n\nÇok basit ve sezgiseldir. Kolayca genişletilebilir ve modüler bileşenlere sahip olacak şekilde tasarlanmıştır.\n\nŞunlara sahiptir:\n\n* Cidden etkileyici performans.\n* WebSocket desteği.\n* Süreç içi arka plan görevleri.\n* Başlatma ve kapatma olayları.\n* HTTPX üzerinde geliştirilmiş test istemcisi.\n* CORS, GZip, Statik Dosyalar, Streaming cevaplar.\n* Oturum (Session) ve Cookie desteği.\n* %100 test kapsamı.\n* %100 tip anotasyonlu kod tabanı.\n* Az sayıda zorunlu bağımlılık.\n\nStarlette, şu anda test edilen en hızlı Python framework’üdür. Yalnızca bir framework değil, bir sunucu olan Uvicorn tarafından geçilir.\n\nStarlette, temel web mikroframework işlevselliğinin tamamını sağlar.\n\nAncak otomatik veri doğrulama, dönüşüm veya dökümantasyon sağlamaz.\n\n**FastAPI**’nin bunun üzerine eklediği ana şeylerden biri, Pydantic kullanarak, bütünüyle Python tip belirteçlerine dayalı bu özelliklerdir. Buna ek olarak bağımlılık enjeksiyonu sistemi, güvenlik yardımcıları, OpenAPI şema üretimi vb. gelir.\n\n/// note | Teknik Detaylar\n\nASGI, Django çekirdek ekip üyeleri tarafından geliştirilen yeni bir “standart”tır. Hâlâ resmi bir “Python standardı” (PEP) değildir, ancak bu süreç üzerindedirler.\n\nBuna rağmen, şimdiden birçok araç tarafından bir “standart” olarak kullanılmaktadır. Bu, birlikte çalışabilirliği büyük ölçüde artırır; örneğin Uvicorn’u başka bir ASGI sunucusuyla (Daphne veya Hypercorn gibi) değiştirebilir ya da `python-socketio` gibi ASGI uyumlu araçlar ekleyebilirsiniz.\n\n///\n\n/// check | **FastAPI** bunu şurada kullanır\n\nTüm temel web kısımlarını ele almak; üzerine özellikler eklemek.\n\n`FastAPI` sınıfı, doğrudan `Starlette` sınıfından miras alır.\n\nDolayısıyla Starlette ile yapabildiğiniz her şeyi, adeta “turbo şarjlı Starlette” olan **FastAPI** ile de doğrudan yapabilirsiniz.\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn, uvloop ve httptools üzerinde inşa edilmiş, ışık hızında bir ASGI sunucusudur.\n\nBir web framework’ü değil, bir sunucudur. Örneğin path’lere göre yönlendirme araçları sağlamaz; bunu Starlette (veya **FastAPI**) gibi bir framework üstte sağlar.\n\nStarlette ve **FastAPI** için önerilen sunucudur.\n\n/// check | **FastAPI** bunu şöyle önerir\n\n**FastAPI** uygulamalarını çalıştırmak için ana web sunucusu.\n\nKomut satırında `--workers` seçeneğini kullanarak asenkron çok süreçli (multi‑process) bir sunucu da elde edebilirsiniz.\n\nDaha fazla detay için [Dağıtım](deployment/index.md) bölümüne bakın.\n\n///\n\n## Kıyaslamalar ve Hız { #benchmarks-and-speed }\n\nUvicorn, Starlette ve FastAPI arasındaki farkı anlamak ve karşılaştırmak için [Kıyaslamalar](benchmarks.md) bölümüne göz atın.\n"
  },
  {
    "path": "docs/tr/docs/async.md",
    "content": "# Eşzamanlılık ve async / await { #concurrency-and-async-await }\n\n*path operasyon fonksiyonları* için `async def` sözdizimi hakkında detaylar ve asenkron kod, eşzamanlılık (concurrency) ve paralellik üzerine arka plan bilgisi.\n\n## Aceleniz mi var? { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - çok uzun; okumadım\"><strong>TL;DR:</strong></abbr>\n\nEğer `await` ile çağırmanız gerektiğini söyleyen üçüncü taraf kütüphaneler kullanıyorsanız, örneğin:\n\n```Python\nresults = await some_library()\n```\n\nO zaman *path operasyon fonksiyonlarınızı* aşağıdaki gibi `async def` ile tanımlayın:\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | Not\n\n`await` yalnızca `async def` ile oluşturulan fonksiyonların içinde kullanılabilir.\n\n///\n\n---\n\nEğer bir veritabanı, bir API, dosya sistemi vb. ile iletişim kuran ve `await` desteği olmayan bir üçüncü taraf kütüphane kullanıyorsanız (bu şu anda çoğu veritabanı kütüphanesi için geçerlidir), o zaman *path operasyon fonksiyonlarınızı* normal olarak `def` ile tanımlayın:\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\nUygulamanız (bir şekilde) başka bir şeyle iletişim kurmak ve onun yanıtını beklemek zorunda değilse, içinde `await` kullanmanız gerekmese bile `async def` kullanın.\n\n---\n\nEmin değilseniz, normal `def` kullanın.\n\n---\n\nNot: *path operasyon fonksiyonlarınızda* `def` ve `async def`'i ihtiyacınız kadar karıştırabilirsiniz, her birini sizin için en iyi seçenekle tanımlayın. FastAPI onlar için doğru olanı yapacaktır.\n\nYukarıdaki durumların herhangi birinde FastAPI yine de asenkron olarak çalışır ve son derece hızlıdır.\n\nAncak yukarıdaki adımları izleyerek bazı performans optimizasyonları mümkün olur.\n\n## Teknik Detaylar { #technical-details }\n\nPython’un modern sürümleri, **`async` ve `await`** sözdizimiyle, **\"coroutines\"** denilen bir yapıyı kullanarak **\"asenkron kod\"** desteğine sahiptir.\n\nAşağıdaki bölümlerde bu ifadeyi parça parça ele alalım:\n\n* **Asenkron Kod**\n* **`async` ve `await`**\n* **Coroutine'ler**\n\n## Asenkron Kod { #asynchronous-code }\n\nAsenkron kod, dilin 💬 bilgisayara / programa 🤖 kodun bir noktasında, bir yerde *başka bir şeyin* bitmesini beklemesi gerektiğini söylemesinin bir yoludur. Diyelim ki bu *başka şeye* \"slow-file\" 📝 diyoruz.\n\nBu sırada bilgisayar, \"slow-file\" 📝 biterken gidip başka işler yapabilir.\n\nSonra bilgisayar / program 🤖, ya tekrar beklediği için ya da o anda elindeki tüm işleri bitirdiğinde fırsat buldukça geri gelir. Ve beklediği görevlerden herhangi biri bittiyse, yapılması gerekenleri yapar.\n\nArdından, 🤖 ilk biten görevi alır (örneğin bizim \"slow-file\" 📝) ve onunla yapması gerekenlere devam eder.\n\nBu \"başka bir şeyi beklemek\" genelde işlemci ve RAM hızına kıyasla nispeten \"yavaş\" olan <abbr title=\"Input and Output - Giriş ve Çıkış\">I/O</abbr> işlemlerine atıfta bulunur, örneğin şunları beklemek gibi:\n\n* istemciden verinin ağ üzerinden gelmesi\n* programınızın gönderdiği verinin ağ üzerinden istemciye ulaşması\n* diskteki bir dosyanın içeriğinin sistem tarafından okunup programınıza verilmesi\n* programınızın sisteme verdiği içeriğin diske yazılması\n* uzak bir API işlemi\n* bir veritabanı işleminin bitmesi\n* bir veritabanı sorgusunun sonuç döndürmesi\n* vb.\n\nÇalışma süresi çoğunlukla <abbr title=\"Input and Output - Giriş ve Çıkış\">I/O</abbr> işlemlerini beklemekle geçtiğinden, bunlara \"I/O bound\" işlemler denir.\n\n\"Bunun\" asenkron\" denmesinin sebebi, bilgisayarın / programın yavaş görevle \"senkronize\" olmak, görev tam bittiği anda orada olup görev sonucunu almak ve işe devam etmek için hiçbir şey yapmadan beklemek zorunda olmamasıdır.\n\nBunun yerine \"asenkron\" bir sistem olarak, görev bittiğinde, bilgisayarın / programın o sırada yaptığı işi bitirmesi için biraz (birkaç mikrosaniye) sırada bekleyebilir ve sonra sonuçları almak üzere geri dönüp onlarla çalışmaya devam edebilir.\n\n\"Senkron\" (asenkronun tersi) için genelde \"sıralı\" terimi de kullanılır; çünkü bilgisayar / program, farklı bir göreve geçmeden önce tüm adımları sırayla izler, bu adımlar beklemeyi içerse bile.\n\n### Eşzamanlılık ve Burgerler { #concurrency-and-burgers }\n\nYukarıda anlatılan **asenkron** kod fikrine bazen **\"eşzamanlılık\"** (concurrency) da denir. **\"Paralellik\"**ten (parallelism) farklıdır.\n\n**Eşzamanlılık** ve **paralellik**, \"aynı anda az çok birden fazla şeyin olması\" ile ilgilidir.\n\nAma *eşzamanlılık* ve *paralellik* arasındaki ayrıntılar oldukça farklıdır.\n\nFarkı görmek için burgerlerle ilgili şu hikayeyi hayal edin:\n\n### Eşzamanlı Burgerler { #concurrent-burgers }\n\nAşkınla fast food almaya gidiyorsun, kasiyer senden önceki insanların siparişlerini alırken sıraya giriyorsun. 😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\nSonra sıra size geliyor, sen ve aşkın için 2 çok havalı burger sipariş ediyorsun. 🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\nKasiyer, mutfaktaki aşçıya burgerlerini hazırlamaları gerektiğini söylüyor (o an önceki müşterilerin burgerlerini hazırlıyor olsalar bile).\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\nÖdeme yapıyorsun. 💸\n\nKasiyer sana sıra numaranı veriyor.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\nBeklerken aşkınla bir masa seçip oturuyorsunuz, uzun uzun sohbet ediyorsunuz (burgerler baya havalı ve hazırlanması biraz zaman alıyor).\n\nMasada aşkınla otururken, burgerleri beklerken, o zamanı aşkının ne kadar harika, tatlı ve zeki olduğuna hayran kalarak geçirebilirsin ✨😍✨.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\nBekler ve sohbet ederken, ara ara tezgâhtaki numaraya bakıp sıranın size gelip gelmediğini kontrol ediyorsun.\n\nBir noktada, nihayet sıra size geliyor. Tezgâha gidiyor, burgerleri alıp masaya dönüyorsun.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\nAşkınla burgerleri yiyip güzel vakit geçiriyorsunuz. ✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info | Bilgi\n\nHarika çizimler: [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nBu hikâyede bilgisayar / program 🤖 olduğunu hayal et.\n\nSıradayken sadece boştasın 😴, sıranı bekliyorsun, çok \"üretken\" bir şey yapmıyorsun. Ama sorun yok, çünkü kasiyer sadece sipariş alıyor (hazırlamıyor), bu yüzden sıra hızlı ilerliyor.\n\nSıra sana geldiğinde gerçekten \"üretken\" işler yapıyorsun: menüyü işliyorsun, ne istediğine karar veriyorsun, aşkının seçimini alıyorsun, ödüyorsun, doğru para ya da kartı verdiğini kontrol ediyorsun, doğru ücretlendirildiğini kontrol ediyorsun, sipariş kalemlerinin doğru olduğunu kontrol ediyorsun, vb.\n\nAma sonra, burgerlerin hâlâ gelmemiş olsa da, kasiyerle olan işin \"duraklatılıyor\" ⏸, çünkü burgerlerin hazır olmasını 🕙 beklemen gerekiyor.\n\nFakat tezgâhtan uzaklaşıp masada sıra numaranla oturduğun için, dikkatinizi 🔀 aşkına çevirebilir, onunla \"çalışmaya\" ⏯ 🤓 odaklanabilirsin. Yani yine çok \"üretken\" bir şey yapıyorsun, aşkınla flört etmek gibi 😍.\n\nArdından kasiyer 💁, tezgâh ekranına numaranı koyarak \"burgerleri bitirdim\" diyor; ama numara seninki olduğunda çılgınca sıçramıyorsun. Sıra numaran sende, herkesin kendi numarası var; kimse burgerlerini çalamaz.\n\nBu yüzden aşkının hikâyeyi bitirmesini (mevcut işi ⏯ / işlenen görevi 🤓 bitirmesini) bekliyor, nazikçe gülümsüyor ve burgerleri almaya gittiğini söylüyorsun ⏸.\n\nSonra tezgâha 🔀 gidip artık bitmiş olan ilk göreve ⏯ dönüyor, burgerleri alıyor, teşekkür ediyor ve masaya getiriyorsun. Tezgâhla etkileşimin bu adımı / görevi böylece bitiyor ⏹. Bu da yeni bir görev olan \"burgerleri yemek\" 🔀 ⏯ görevini oluşturuyor, ama \"burgerleri almak\" görevi tamamlandı ⏹.\n\n### Paralel Burgerler { #parallel-burgers }\n\nŞimdi bunların \"Eşzamanlı Burgerler\" değil, \"Paralel Burgerler\" olduğunu hayal edelim.\n\nAşkınla paralel fast food almaya gidiyorsun.\n\nAynı anda aşçı da olan birden fazla (8 diyelim) kasiyerin, senden önceki insanların siparişlerini aldığı bir sırada bekliyorsun.\n\nSenden önceki herkes, tezgâhtan ayrılmadan önce burgerlerinin hazırlanmasını bekliyor; çünkü 8 kasiyerin her biri bir sonraki siparişe geçmeden önce burgeri hemen gidip hazırlıyor.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\nSonunda sıra size geliyor, sen ve aşkın için 2 çok havalı burger siparişi veriyorsun.\n\nÖdüyorsun 💸.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\nKasiyer mutfağa gidiyor.\n\nTezgâhın önünde ayakta 🕙 bekliyorsun; sıra numarası olmadığından, burgerlerini senden önce kimsenin almaması için orada durman gerekiyor.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\nSen ve aşkın, kimsenin önünüze geçip burgerler gelince almaması için meşgul olduğunuzdan, aşkına dikkatini veremiyorsun. 😞\n\nBu \"senkron\" bir iştir; kasiyer/aşçı 👨‍🍳 ile \"senkronize\"sin. 🕙 Beklemen ve kasiyer/aşçı 👨‍🍳 burgerleri bitirip sana verdiği anda tam orada olman gerekir; yoksa bir başkası alabilir.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\nSonra kasiyer/aşçı 👨‍🍳, uzun süre tezgâhın önünde 🕙 bekledikten sonra nihayet burgerlerinle geri geliyor.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\nBurgerleri alıyor ve aşkınla masaya gidiyorsun.\n\nSadece yiyorsunuz ve iş bitiyor. ⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\nVaktin çoğu tezgâhın önünde 🕙 beklemekle geçtiğinden, pek konuşma ya da flört olmadı. 😞\n\n/// info | Bilgi\n\nHarika çizimler: [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nBu paralel burger senaryosunda, ikiniz (sen ve aşkın) iki işlemcili bir bilgisayar / programsınız 🤖; ikiniz de uzun süre tezgâhta \"bekleme\" işine 🕙 dikkat ⏯ ayırıyorsunuz.\n\nFast food dükkânında 8 işlemci var (kasiyer/aşçılar). Eşzamanlı burger dükkânında yalnızca 2 kişi olabilir (bir kasiyer ve bir aşçı).\n\nAma yine de nihai deneyim pek iyi değil. 😞\n\n---\n\nBu, burgerler için paralel karşılık gelen hikâye olurdu. 🍔\n\nDaha \"gerçek hayat\" bir örnek için, bir banka hayal edin.\n\nYakın zamana kadar, bankaların çoğunda birden çok gişe memuru 👨‍💼👨‍💼👨‍💼👨‍💼 ve uzun bir sıra 🕙🕙🕙🕙🕙🕙🕙🕙 vardı.\n\nTüm gişe memurları bir müşteriyle tüm işi yapar, sonra sıradakiyle 👨‍💼⏯.\n\nVe sıranı kaybetmemek için uzun süre 🕙 kuyrukta beklemen gerekir.\n\nMuhtemelen, bankada 🏦 işlerini hallederken aşkını 😍 yanında götürmek istemezsin.\n\n### Burger Sonucu { #burger-conclusion }\n\n\"Fast food burgerleri ve aşkın\" senaryosunda, çok fazla bekleme 🕙 olduğundan, eşzamanlı bir sistem ⏸🔀⏯ çok daha mantıklıdır.\n\nBu, çoğu web uygulaması için de geçerlidir.\n\nÇok fazla kullanıcı vardır; ancak sunucunuz, iyi olmayan bağlantılarından gelen istekleri 🕙 bekler.\n\nVe sonra yanıtların geri gelmesini yine 🕙 bekler.\n\nBu \"beklemeler\" 🕙 mikrosaniyelerle ölçülür; ama hepsi toplandığında sonuçta oldukça fazla bekleme olur.\n\nBu yüzden web API’leri için asenkron ⏸🔀⏯ kod kullanmak çok mantıklıdır.\n\nBu tür asenkronluk, NodeJS’i popüler yapan şeydir (NodeJS paralel olmasa bile) ve Go dilinin gücüdür.\n\nVe **FastAPI** ile elde ettiğiniz performans seviyesi de budur.\n\nAyrıca, aynı anda hem paralellik hem de asenkronluk kullanabildiğiniz için, test edilen çoğu NodeJS framework’ünden daha yüksek ve C’ye daha yakın derlenen bir dil olan Go ile başa baş performans elde edersiniz [(hepsi Starlette sayesinde)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).\n\n### Eşzamanlılık paralellikten daha mı iyi? { #is-concurrency-better-than-parallelism }\n\nHayır! Hikâyenin özü bu değil.\n\nEşzamanlılık paralellikten farklıdır. Ve çok fazla bekleme içeren **belirli** senaryolarda daha iyidir. Bu nedenle, genellikle web uygulaması geliştirme için paralellikten çok daha iyidir. Ama her şey için değil.\n\nBunu dengelemek için, şu kısa hikâyeyi hayal edin:\n\n> Büyük, kirli bir evi temizlemen gerekiyor.\n\n*Evet, tüm hikâye bu kadar*.\n\n---\n\nHiçbir yerde 🕙 bekleme yok; sadece evin birden fazla yerinde yapılacak çok iş var.\n\nHamburger örneğindeki gibi dönüşlerle ilerleyebilirsin, önce salon, sonra mutfak; ama hiçbir şey 🕙 beklemediğin için, sadece temizlik yaptığından, dönüşlerin hiçbir etkisi olmaz.\n\nDönüşlerle ya da dönüşsüz (eşzamanlılık) bitirmek aynı zaman alır ve aynı miktarda iş yapmış olursun.\n\nAma bu durumda, 8 eski kasiyer/aşçı—yeni temizlikçiyi getirip her birine (artı sana) evin bir bölümünü versen, fazladan yardımla tüm işleri **paralel** yaparak çok daha çabuk bitirebilirdin.\n\nBu senaryoda, her bir temizlikçi (sen dâhil) birer işlemci olur ve kendi iş payını yapar.\n\nVe yürütme süresinin çoğu gerçek işten (bekleme yerine) oluştuğu ve bilgisayardaki işi bir <abbr title=\"Central Processing Unit - Merkezi İşlem Birimi\">CPU</abbr> yaptığı için, bu sorunlara \"CPU bound\" denir.\n\n---\n\nCPU’ya bağlı işlemlerin yaygın örnekleri, karmaşık matematiksel işlem gerektiren iş yükleridir.\n\nÖrneğin:\n\n* **Ses** veya **görüntü işleme**.\n* **Bilgisayar görüsü**: bir görüntü milyonlarca pikselden oluşur, her pikselin 3 değeri / rengi vardır; işleme genellikle bu pikseller üzerinde aynı anda bir şeyler hesaplamayı gerektirir.\n* **Makine Öğrenimi**: genellikle çok sayıda \"matris\" ve \"vektör\" çarpımı gerekir. Sayılar içeren devasa bir elektronik tabloyu ve hepsini aynı anda çarpmayı düşünün.\n* **Derin Öğrenme**: Makine Öğreniminin bir alt alanıdır, dolayısıyla aynısı geçerlidir. Sadece çarpılacak tek bir sayı tablosu değil, kocaman bir sayı kümesi vardır ve çoğu durumda bu modelleri kurmak ve/veya kullanmak için özel işlemciler kullanırsınız.\n\n### Eşzamanlılık + Paralellik: Web + Makine Öğrenimi { #concurrency-parallelism-web-machine-learning }\n\n**FastAPI** ile web geliştirmede çok yaygın olan eşzamanlılıktan (NodeJS’in başlıca cazibesiyle aynı) yararlanabilirsiniz.\n\nAma ayrıca **CPU’ya bağlı** iş yükleri (Makine Öğrenimi sistemlerindeki gibi) için paralellik ve çoklu işlemden (paralel çalışan birden çok işlem) de yararlanabilirsiniz.\n\nBuna ek olarak Python’un **Veri Bilimi**, Makine Öğrenimi ve özellikle Derin Öğrenme için ana dil olması, FastAPI’yi Veri Bilimi / Makine Öğrenimi web API’leri ve uygulamaları için çok iyi bir seçenek yapar.\n\nProduction’da bu paralelliği nasıl sağlayacağınızı görmek için [Deployment](deployment/index.md) bölümüne bakın.\n\n## `async` ve `await` { #async-and-await }\n\nPython’un modern sürümleri, asenkron kodu tanımlamak için oldukça sezgisel bir yol sunar. Bu sayede kod normal \"sıralı\" kod gibi görünür ve doğru anlarda sizin yerinize \"beklemeyi\" yapar.\n\nSonuçları vermeden önce bekleme gerektiren ve bu yeni Python özelliklerini destekleyen bir işlem olduğunda, şöyle kodlayabilirsiniz:\n\n```Python\nburgers = await get_burgers(2)\n```\n\nBuradaki kilit nokta `await`. Python’a, sonuçları `burgers` değişkenine koymadan önce `get_burgers(2)` çalışmasının bitmesini 🕙 beklemesi ⏸ gerektiğini söyler. Böylece Python, bu arada başka bir şey 🔀 ⏯ yapabileceğini bilir (ör. başka bir request almak gibi).\n\n`await`’in çalışabilmesi için, bu asenkronluğu destekleyen bir fonksiyonun içinde olması gerekir. Bunu yapmak için fonksiyonu `async def` ile tanımlayın:\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # Burgerleri yaratmak için bazı asenkron işler yap\n    return burgers\n```\n\n...`def` yerine:\n\n```Python hl_lines=\"2\"\n# Bu asenkron değildir\ndef get_sequential_burgers(number: int):\n    # Burgerleri yaratmak için bazı sıralı işler yap\n    return burgers\n```\n\n`async def` ile Python, bu fonksiyonun içinde `await` ifadelerinin olabileceğini bilir ve bu fonksiyonun yürütülmesini \"duraklatıp\" ⏸ başka bir şey yapabileceğini 🔀, sonra geri dönebileceğini anlar.\n\n`async def` fonksiyonunu çağırmak istediğinizde, onu \"await\" etmeniz gerekir. Yani şu çalışmaz:\n\n```Python\n# Bu çalışmaz, çünkü get_burgers şöyle tanımlandı: async def\nburgers = get_burgers(2)\n```\n\n---\n\nDolayısıyla, `await` ile çağrılabileceğini söyleyen bir kütüphane kullanıyorsanız, onu kullanan *path operasyon fonksiyonunu* `async def` ile oluşturmanız gerekir, örneğin:\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### Daha teknik detaylar { #more-technical-details }\n\n`await`’in yalnızca `async def` ile tanımlanan fonksiyonların içinde kullanılabildiğini fark etmiş olabilirsiniz.\n\nAynı zamanda, `async def` ile tanımlanan fonksiyonların da \"await\" edilmesi gerekir. Yani `async def` ile tanımlanan fonksiyonlar yalnızca `async def` ile tanımlanan fonksiyonların içinde çağrılabilir.\n\nPeki, tavuk-yumurta meselesi: ilk `async` fonksiyon nasıl çağrılır?\n\n**FastAPI** ile çalışıyorsanız bunu dert etmenize gerek yok; çünkü o \"ilk\" fonksiyon sizin *path operasyon fonksiyonunuz* olacaktır ve FastAPI doğru olanı yapmasını bilir.\n\nAma FastAPI olmadan da `async` / `await` kullanmak isterseniz, bunu da yapabilirsiniz.\n\n### Kendi async kodunuzu yazın { #write-your-own-async-code }\n\nStarlette (ve **FastAPI**) [AnyIO](https://anyio.readthedocs.io/en/stable/) üzerine kuruludur; bu sayede Python standart kütüphanesindeki [asyncio](https://docs.python.org/3/library/asyncio-task.html) ve [Trio](https://trio.readthedocs.io/en/stable/) ile uyumludur.\n\nÖzellikle, kendi kodunuzda daha gelişmiş desenler gerektiren ileri seviye eşzamanlılık kullanım senaryoları için doğrudan [AnyIO](https://anyio.readthedocs.io/en/stable/) kullanabilirsiniz.\n\nHatta FastAPI kullanmıyor olsanız bile, yüksek uyumluluk ve avantajları (ör. *structured concurrency*) için [AnyIO](https://anyio.readthedocs.io/en/stable/) ile kendi async uygulamalarınızı yazabilirsiniz.\n\nAnyIO’nun üzerine, tür açıklamalarını biraz iyileştirmek ve daha iyi **otomatik tamamlama**, **satır içi hatalar** vb. elde etmek için ince bir katman olarak başka bir kütüphane daha oluşturdum. Ayrıca **kendi async kodunuzu** anlamanıza ve yazmanıza yardımcı olacak dostça bir giriş ve eğitim içerir: [Asyncer](https://asyncer.tiangolo.com/). Özellikle **async kodu normal** (bloklayan/senkron) **kodla birleştirmeniz** gerektiğinde faydalı olacaktır.\n\n### Asenkron kodun diğer biçimleri { #other-forms-of-asynchronous-code }\n\n`async` ve `await` kullanma tarzı, dilde nispeten yenidir.\n\nAma asenkron kodla çalışmayı çok daha kolaylaştırır.\n\nAynı (ya da neredeyse aynı) sözdizimi yakın zamanda modern JavaScript sürümlerine (Tarayıcı ve NodeJS) de eklendi.\n\nBundan önce, asenkron kodu ele almak oldukça daha karmaşık ve zordu.\n\nPython’un önceki sürümlerinde thread’ler veya [Gevent](https://www.gevent.org/) kullanabilirdiniz. Ama kodu anlamak, hata ayıklamak ve üzerine düşünmek çok daha zordu.\n\nNodeJS / Tarayıcı JavaScript’in önceki sürümlerinde \"callback\" kullanırdınız. Bu da \"callback cehennemi\"ne yol açardı.\n\n## Coroutine'ler { #coroutines }\n\n**Coroutine**, bir `async def` fonksiyonunun döndürdüğü şeye verilen süslü isimdir. Python bunun bir fonksiyona benzer bir şey olduğunu, bir noktada başlayıp biteceğini bilir; ama içinde bir `await` olduğunda dahili olarak duraklatılabileceğini ⏸ de bilir.\n\n`async` ve `await` ile asenkron kod kullanmanın bu işlevselliği çoğu zaman \"coroutine\" kullanmak olarak özetlenir. Go’nun ana kilit özelliği olan \"Goroutines\" ile karşılaştırılabilir.\n\n## Sonuç { #conclusion }\n\nYukarıdaki cümleyi tekrar görelim:\n\n> Python’un modern sürümleri, **`async` ve `await`** sözdizimiyle, **\"coroutines\"** denilen bir yapıyı kullanarak **\"asenkron kod\"** desteğine sahiptir.\n\nArtık daha anlamlı gelmeli. ✨\n\nBunların hepsi, FastAPI’ye (Starlette aracılığıyla) güç verir ve böylesine etkileyici bir performansa sahip olmasını sağlar.\n\n## Çok Teknik Detaylar { #very-technical-details }\n\n/// warning | Uyarı\n\nBüyük ihtimalle burayı atlayabilirsiniz.\n\nBunlar, **FastAPI**’nin altında nasıl çalıştığına dair oldukça teknik ayrıntılardır.\n\nCoroutine’ler, thread’ler, blocking vb. hakkında teknik bilginiz varsa ve FastAPI’nin `async def` ile normal `def` arasındaki farkı nasıl ele aldığını merak ediyorsanız, devam edin.\n\n///\n\n### Path Operasyon Fonksiyonları { #path-operation-functions }\n\nBir *path operasyon fonksiyonunu* `async def` yerine normal `def` ile tanımladığınızda, (sunucuyu bloklayacağından) doğrudan çağrılmak yerine, harici bir thread pool’da çalıştırılır ve ardından beklenir.\n\nYukarıda açıklanan şekilde çalışmayan başka bir async framework’ten geliyorsanız ve ufak bir performans kazancı (yaklaşık 100 nanosaniye) için yalnızca hesaplama yapan basit *path operasyon fonksiyonlarını* düz `def` ile tanımlamaya alışkınsanız, **FastAPI**’de etkinin tam tersi olacağını unutmayın. Bu durumlarda, *path operasyon fonksiyonlarınız* bloklayan <abbr title=\"Input/Output - Giriş/Çıkış: disk okuma veya yazma, ağ iletişimi.\">I/O</abbr> yapan kod kullanmadıkça `async def` kullanmak daha iyidir.\n\nYine de her iki durumda da, **FastAPI**’nin önceki framework’ünüzden [hala daha hızlı](index.md#performance) (ya da en azından karşılaştırılabilir) olması muhtemeldir.\n\n### Bağımlılıklar { #dependencies }\n\nAynısı [bağımlılıklar](tutorial/dependencies/index.md) için de geçerlidir. Bir bağımlılık `async def` yerine standart bir `def` fonksiyonuysa, harici thread pool’da çalıştırılır.\n\n### Alt-bağımlılıklar { #sub-dependencies }\n\nBirbirini gerektiren birden çok bağımlılık ve [alt-bağımlılık](tutorial/dependencies/sub-dependencies.md) olabilir (fonksiyon tanımlarının parametreleri olarak). Bazıları `async def` ile, bazıları normal `def` ile oluşturulmuş olabilir. Yine de çalışır ve normal `def` ile oluşturulanlar \"await\" edilmek yerine harici bir thread’de (thread pool’dan) çağrılır.\n\n### Diğer yardımcı fonksiyonlar { #other-utility-functions }\n\nDoğrudan çağırdığınız diğer yardımcı fonksiyonları normal `def` veya `async def` ile tanımlayabilirsiniz ve FastAPI onları çağırma biçiminizi etkilemez.\n\nBu, FastAPI’nin sizin için çağırdığı fonksiyonların tersidir: *path operasyon fonksiyonları* ve bağımlılıklar.\n\nYardımcı fonksiyonunuz `def` ile tanımlı normal bir fonksiyonsa, bir thread pool’da değil doğrudan (kodunuzda yazdığınız gibi) çağrılır; fonksiyon `async def` ile tanımlıysa kodunuzda çağırırken onu `await` etmelisiniz.\n\n---\n\nYine, bunlar muhtemelen özellikle aradığınızda işinize yarayacak çok teknik ayrıntılardır.\n\nAksi hâlde, yukarıdaki bölümdeki yönergeler yeterlidir: <a href=\"#in-a-hurry\">Aceleniz mi var?</a>.\n"
  },
  {
    "path": "docs/tr/docs/benchmarks.md",
    "content": "# Kıyaslamalar { #benchmarks }\n\nBağımsız TechEmpower kıyaslamaları, Uvicorn altında çalışan **FastAPI** uygulamalarının [mevcut en hızlı Python frameworklerinden biri](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7) olduğunu, yalnızca Starlette ve Uvicorn'un kendilerinin altında yer aldığını gösteriyor (FastAPI bunları dahili olarak kullanır).\n\nFakat kıyaslamaları ve karşılaştırmaları incelerken şunları aklınızda bulundurmalısınız.\n\n## Kıyaslamalar ve Hız { #benchmarks-and-speed }\n\nKıyaslamalara baktığınızda, farklı türlerdeki birkaç aracın eşdeğermiş gibi karşılaştırıldığını görmek yaygındır.\n\nÖzellikle, (diğer birçok araç arasında) Uvicorn, Starlette ve FastAPI'ın birlikte karşılaştırıldığını görebilirsiniz.\n\nAracın çözdüğü problem ne kadar basitse, elde edeceği performans o kadar iyi olur. Ayrıca kıyaslamaların çoğu, aracın sağladığı ek özellikleri test etmez.\n\nHiyerarşi şöyledir:\n\n* **Uvicorn**: bir ASGI sunucusu\n    * **Starlette**: (Uvicorn'u kullanır) bir web mikroframework'ü\n        * **FastAPI**: (Starlette'i kullanır) veri doğrulama vb. ile API'lar oluşturmak için çeşitli ek özelliklere sahip bir API mikroframework'ü\n\n* **Uvicorn**:\n    * Sunucunun kendisi dışında çok fazla ekstra kod içermediği için en iyi performansa sahip olacaktır.\n    * Uvicorn ile doğrudan bir uygulama yazmazsınız. Bu, kodunuzun en azından Starlette'in (veya **FastAPI**'nin) sağladığı kodun aşağı yukarı tamamını içermesi gerektiği anlamına gelir. Bunu yaparsanız, nihai uygulamanız; bir framework kullanmış olmanın ve uygulama kodunu ve bug'ları en aza indirmenin getirdiği ek yükle aynı ek yüke sahip olur.\n    * Uvicorn'u karşılaştırıyorsanız, Daphne, Hypercorn, uWSGI vb. application server'larla karşılaştırın.\n* **Starlette**:\n    * Uvicorn'dan sonra en iyi performansa sahip olacaktır. Aslında Starlette çalışmak için Uvicorn'u kullanır. Bu yüzden muhtemelen yalnızca daha fazla kod çalıştırmak zorunda kaldığı için Uvicorn'dan \"daha yavaş\" olabilir.\n    * Ancak path tabanlı routing vb. ile basit web uygulamaları oluşturmanız için araçlar sağlar.\n    * Starlette'i karşılaştırıyorsanız, Sanic, Flask, Django vb. web framework'lerle (veya mikroframework'lerle) karşılaştırın.\n* **FastAPI**:\n    * Starlette'in Uvicorn'u kullanıp ondan daha hızlı olamaması gibi, **FastAPI** da Starlette'i kullanır; dolayısıyla ondan daha hızlı olamaz.\n    * FastAPI, Starlette'in üzerine daha fazla özellik sağlar. API'lar oluştururken neredeyse her zaman ihtiyaç duyduğunuz veri doğrulama ve <abbr title=\"serialization - serileştirme\">serialization</abbr> gibi özellikler. Ayrıca bunu kullanarak ücretsiz olarak otomatik dokümantasyon elde edersiniz (otomatik dokümantasyon, çalışan uygulamalara ek yük bile getirmez; startup'ta üretilir).\n    * FastAPI'yi kullanmayıp Starlette'i doğrudan kullansaydınız (veya Sanic, Flask, Responder vb. başka bir aracı), tüm veri doğrulama ve serialization işlemlerini kendiniz uygulamak zorunda kalırdınız. Dolayısıyla nihai uygulamanız, FastAPI kullanılarak inşa edilmiş olsaydı sahip olacağı ek yükle hâlâ aynı ek yüke sahip olurdu. Ve çoğu durumda, uygulamalarda yazılan en büyük kod miktarı veri doğrulama ve serialization kısmıdır.\n    * Bu nedenle FastAPI kullanarak geliştirme süresinden, bug'lardan, kod satırlarından tasarruf edersiniz; ayrıca muhtemelen, onu kullanmasaydınız (tüm bunları kodunuzda kendiniz uygulamak zorunda kalacağınız için) elde edeceğiniz performansın aynısını (veya daha iyisini) elde edersiniz.\n    * FastAPI'yi karşılaştırıyorsanız, Flask-apispec, NestJS, Molten vb. veri doğrulama, serialization ve dokümantasyon sağlayan bir web uygulaması framework'ü (veya araç seti) ile karşılaştırın. Entegre otomatik veri doğrulama, serialization ve dokümantasyona sahip framework'ler.\n"
  },
  {
    "path": "docs/tr/docs/deployment/cloud.md",
    "content": "# Bulut Sağlayıcılar Üzerinde FastAPI Yayınlama { #deploy-fastapi-on-cloud-providers }\n\nFastAPI uygulamanızı yayınlamak için neredeyse **herhangi bir bulut sağlayıcıyı** kullanabilirsiniz.\n\nÇoğu durumda, ana bulut sağlayıcıların FastAPI'yi onlarla birlikte yayınlamak için kılavuzları vardır.\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)**, **FastAPI**'nin arkasındaki aynı yazar ve ekip tarafından geliştirilmiştir.\n\nBir API'yi minimum çabayla **oluşturma**, **yayınlama** ve **erişme** sürecini kolaylaştırır.\n\nFastAPI ile uygulama geliştirirken elde edilen aynı **geliştirici deneyimini**, onları buluta **yayınlamaya** da taşır. 🎉\n\nFastAPI Cloud, *FastAPI and friends* açık kaynak projelerinin birincil sponsoru ve finansman sağlayıcısıdır. ✨\n\n## Bulut Sağlayıcılar - Sponsorlar { #cloud-providers-sponsors }\n\nDiğer bazı bulut sağlayıcılar da ✨ [**FastAPI'ye sponsor olur**](../help-fastapi.md#sponsor-the-author) ✨. 🙇\n\nKılavuzlarını takip etmek ve servislerini denemek için onları da değerlendirmek isteyebilirsiniz:\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/tr/docs/deployment/concepts.md",
    "content": "# Deployment Kavramları { #deployments-concepts }\n\nBir **FastAPI** uygulamasını (hatta genel olarak herhangi bir web API'yi) deploy ederken, muhtemelen önemseyeceğiniz bazı kavramlar vardır. Bu kavramları kullanarak, **uygulamanızı deploy etmek** için **en uygun** yöntemi bulabilirsiniz.\n\nÖnemli kavramlardan bazıları şunlardır:\n\n* Güvenlik - HTTPS\n* Startup'ta çalıştırma\n* Yeniden başlatmalar\n* Replikasyon (çalışan process sayısı)\n* Bellek\n* Başlatmadan önceki adımlar\n\nBunların **deployment**'ları nasıl etkilediğine bakalım.\n\nNihai hedef, **API client**'larınıza **güvenli** bir şekilde hizmet verebilmek, **kesintileri** önlemek ve **hesaplama kaynaklarını** (ör. uzak server'lar/sanal makineler) olabildiğince verimli kullanmaktır. 🚀\n\nBurada bu **kavramlar** hakkında biraz daha bilgi vereceğim. Böylece, çok farklı ortamlarda—hatta bugün var olmayan **gelecekteki** ortamlarda bile—API'nizi nasıl deploy edeceğinize karar verirken ihtiyaç duyacağınız **sezgiyi** kazanmış olursunuz.\n\nBu kavramları dikkate alarak, **kendi API**'leriniz için en iyi deployment yaklaşımını **değerlendirebilir ve tasarlayabilirsiniz**.\n\nSonraki bölümlerde, FastAPI uygulamalarını deploy etmek için daha **somut tarifler** (recipes) paylaşacağım.\n\nAma şimdilik, bu önemli **kavramsal fikirleri** inceleyelim. Bu kavramlar diğer tüm web API türleri için de geçerlidir. 💡\n\n## Güvenlik - HTTPS { #security-https }\n\n[HTTPS hakkındaki önceki bölümde](https.md) HTTPS'in API'niz için nasıl şifreleme sağladığını öğrenmiştik.\n\nAyrıca HTTPS'in genellikle uygulama server'ınızın **dışında** yer alan bir bileşen tarafından sağlandığını, yani bir **TLS Termination Proxy** ile yapıldığını da görmüştük.\n\nVe **HTTPS sertifikalarını yenilemekten** sorumlu bir şey olmalıdır; bu aynı bileşen olabileceği gibi farklı bir bileşen de olabilir.\n\n### HTTPS için Örnek Araçlar { #example-tools-for-https }\n\nTLS Termination Proxy olarak kullanabileceğiniz bazı araçlar:\n\n* Traefik\n    * Sertifika yenilemelerini otomatik yönetir ✨\n* Caddy\n    * Sertifika yenilemelerini otomatik yönetir ✨\n* Nginx\n    * Sertifika yenilemeleri için Certbot gibi harici bir bileşenle\n* HAProxy\n    * Sertifika yenilemeleri için Certbot gibi harici bir bileşenle\n* Nginx gibi bir Ingress Controller ile Kubernetes\n    * Sertifika yenilemeleri için cert-manager gibi harici bir bileşenle\n* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi (aşağıyı okuyun 👇)\n\nBir diğer seçenek de, HTTPS kurulumunu da dahil olmak üzere işin daha büyük kısmını yapan bir **cloud service** kullanmaktır. Bunun bazı kısıtları olabilir veya daha pahalı olabilir vb. Ancak bu durumda TLS Termination Proxy'yi kendiniz kurmak zorunda kalmazsınız.\n\nSonraki bölümlerde bazı somut örnekler göstereceğim.\n\n---\n\nSonraki kavramlar, gerçek API'nizi çalıştıran programla (ör. Uvicorn) ilgilidir.\n\n## Program ve Process { #program-and-process }\n\nÇalışan \"**process**\" hakkında çok konuşacağız. Bu yüzden ne anlama geldiğini ve \"**program**\" kelimesinden farkının ne olduğunu netleştirmek faydalı.\n\n### Program Nedir { #what-is-a-program }\n\n**Program** kelimesi günlük kullanımda birçok şeyi anlatmak için kullanılır:\n\n* Yazdığınız **code**, yani **Python dosyaları**.\n* İşletim sistemi tarafından **çalıştırılabilen** **dosya**, örn: `python`, `python.exe` veya `uvicorn`.\n* İşletim sistemi üzerinde **çalışır durumdayken** CPU kullanan ve bellekte veri tutan belirli bir program. Buna **process** de denir.\n\n### Process Nedir { #what-is-a-process }\n\n**Process** kelimesi genellikle daha spesifik kullanılır; yalnızca işletim sistemi üzerinde çalışan şeye (yukarıdaki son madde gibi) işaret eder:\n\n* İşletim sistemi üzerinde **çalışır durumda** olan belirli bir program.\n    * Bu; dosyayı ya da code'u değil, işletim sistemi tarafından **çalıştırılan** ve yönetilen şeyi ifade eder.\n* Herhangi bir program, herhangi bir code, **yalnızca çalıştırılırken** bir şey yapabilir. Yani bir **process çalışıyorken**.\n* Process siz tarafından veya işletim sistemi tarafından **sonlandırılabilir** (ya da \"killed\" edilebilir). O anda çalışması/çalıştırılması durur ve artık **hiçbir şey yapamaz**.\n* Bilgisayarınızda çalışan her uygulamanın arkasında bir process vardır; çalışan her program, her pencere vb. Bilgisayar açıkken normalde **aynı anda** birçok process çalışır.\n* Aynı anda **aynı programın birden fazla process**'i çalışabilir.\n\nİşletim sisteminizdeki \"task manager\" veya \"system monitor\" (ya da benzeri araçlar) ile bu process'lerin birçoğunu çalışır halde görebilirsiniz.\n\nÖrneğin muhtemelen aynı browser programını (Firefox, Chrome, Edge vb.) çalıştıran birden fazla process göreceksiniz. Genelde her tab için bir process, üstüne bazı ek process'ler çalıştırırlar.\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\nArtık **process** ve **program** arasındaki farkı bildiğimize göre, deployment konusuna devam edelim.\n\n## Startup'ta Çalıştırma { #running-on-startup }\n\nÇoğu durumda bir web API oluşturduğunuzda, client'larınızın her zaman erişebilmesi için API'nizin kesintisiz şekilde **sürekli çalışıyor** olmasını istersiniz. Elbette sadece belirli durumlarda çalışmasını istemenizin özel bir sebebi olabilir; ancak çoğunlukla onu sürekli açık ve **kullanılabilir** halde tutarsınız.\n\n### Uzak Bir Server'da { #in-a-remote-server }\n\nUzak bir server (cloud server, sanal makine vb.) kurduğunuzda, yapabileceğiniz en basit şey; local geliştirme sırasında yaptığınız gibi, manuel olarak `fastapi run` (Uvicorn'u kullanır) veya benzeri bir komutla çalıştırmaktır.\n\nBu yöntem çalışır ve **geliştirme sırasında** faydalıdır.\n\nAncak server'a olan bağlantınız koparsa, **çalışan process** muhtemelen ölür.\n\nVe server yeniden başlatılırsa (örneğin update'lerden sonra ya da cloud provider'ın migration'larından sonra) bunu muhtemelen **fark etmezsiniz**. Dolayısıyla process'i manuel yeniden başlatmanız gerektiğini de bilmezsiniz. Sonuçta API'niz ölü kalır. 😱\n\n### Startup'ta Otomatik Çalıştırma { #run-automatically-on-startup }\n\nGenellikle server programının (ör. Uvicorn) server açılışında otomatik başlamasını ve herhangi bir **insan müdahalesi** gerektirmeden API'nizi çalıştıran bir process'in sürekli ayakta olmasını istersiniz (ör. FastAPI uygulamanızı çalıştıran Uvicorn).\n\n### Ayrı Bir Program { #separate-program }\n\nBunu sağlamak için genellikle startup'ta uygulamanızın çalıştığından emin olacak **ayrı bir program** kullanırsınız. Pek çok durumda bu program, örneğin bir veritabanı gibi diğer bileşenlerin/uygulamaların da çalıştığından emin olur.\n\n### Startup'ta Çalıştırmak için Örnek Araçlar { #example-tools-to-run-at-startup }\n\nBu işi yapabilen araçlara örnekler:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker in Swarm Mode\n* Systemd\n* Supervisor\n* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi\n* Diğerleri...\n\nSonraki bölümlerde daha somut örnekler vereceğim.\n\n## Yeniden Başlatmalar { #restarts }\n\nUygulamanızın startup'ta çalıştığından emin olmaya benzer şekilde, hatalardan sonra **yeniden başlatıldığından** da emin olmak istersiniz.\n\n### Hata Yaparız { #we-make-mistakes }\n\nBiz insanlar sürekli **hata** yaparız. Yazılımın neredeyse *her zaman* farklı yerlerinde gizli **bug**'lar vardır. 🐛\n\nVe biz geliştiriciler bu bug'ları buldukça ve yeni özellikler ekledikçe code'u iyileştiririz (muhtemelen yeni bug'lar da ekleyerek 😅).\n\n### Küçük Hatalar Otomatik Yönetilir { #small-errors-automatically-handled }\n\nFastAPI ile web API geliştirirken, code'umuzda bir hata olursa FastAPI genellikle bunu hatayı tetikleyen tek request ile sınırlar. 🛡\n\nClient o request için **500 Internal Server Error** alır; ancak uygulama tamamen çöküp durmak yerine sonraki request'ler için çalışmaya devam eder.\n\n### Daha Büyük Hatalar - Çökmeler { #bigger-errors-crashes }\n\nYine de bazı durumlarda, yazdığımız bir code **tüm uygulamayı çökertip** Uvicorn ve Python'ın crash olmasına neden olabilir. 💥\n\nBöyle bir durumda, tek bir noktadaki hata yüzünden uygulamanın ölü kalmasını istemezsiniz; bozuk olmayan *path operations* en azından çalışmaya devam etsin istersiniz.\n\n### Crash Sonrası Yeniden Başlatma { #restart-after-crash }\n\nAncak çalışan **process**'i çökerten gerçekten kötü hatalarda, process'i **yeniden başlatmaktan** sorumlu harici bir bileşen istersiniz; en azından birkaç kez...\n\n/// tip | İpucu\n\n...Yine de uygulama **hemen crash oluyorsa**, onu sonsuza kadar yeniden başlatmaya çalışmanın pek anlamı yoktur. Böyle durumları büyük ihtimalle geliştirme sırasında ya da en geç deploy'dan hemen sonra fark edersiniz.\n\nO yüzden ana senaryoya odaklanalım: Gelecekte bazı özel durumlarda tamamen çökebilir ve yine de yeniden başlatmak mantıklıdır.\n\n///\n\nUygulamanızı yeniden başlatmakla görevli bileşenin **harici bir bileşen** olmasını istersiniz. Çünkü o noktada Uvicorn ve Python ile birlikte aynı uygulama zaten crash olmuştur; aynı app'in içindeki aynı code'un bunu düzeltmek için yapabileceği bir şey kalmaz.\n\n### Otomatik Yeniden Başlatma için Örnek Araçlar { #example-tools-to-restart-automatically }\n\nÇoğu durumda, **startup'ta programı çalıştırmak** için kullanılan aracın aynısı otomatik **restart**'ları yönetmek için de kullanılır.\n\nÖrneğin bu şunlarla yönetilebilir:\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker in Swarm Mode\n* Systemd\n* Supervisor\n* Bir cloud provider tarafından servislerinin parçası olarak içeride yönetilmesi\n* Diğerleri...\n\n## Replikasyon - Process'ler ve Bellek { #replication-processes-and-memory }\n\nFastAPI uygulamasında, Uvicorn'u çalıştıran `fastapi` komutu gibi bir server programı kullanırken, uygulamayı **tek bir process** içinde bir kez çalıştırmak bile aynı anda birden fazla client'a hizmet verebilir.\n\nAncak birçok durumda, aynı anda birden fazla worker process çalıştırmak istersiniz.\n\n### Birden Fazla Process - Worker'lar { #multiple-processes-workers }\n\nTek bir process'in karşılayabileceğinden daha fazla client'ınız varsa (örneğin sanal makine çok büyük değilse) ve server CPU'sunda **birden fazla core** varsa, aynı uygulamayla **birden fazla process** çalıştırıp tüm request'leri bunlara dağıtabilirsiniz.\n\nAynı API programının **birden fazla process**'ini çalıştırdığınızda, bunlara genellikle **worker** denir.\n\n### Worker Process'ler ve Port'lar { #worker-processes-and-ports }\n\n[HTTPS hakkındaki dokümanda](https.md) bir server'da aynı port ve IP adresi kombinasyonunu yalnızca tek bir process'in dinleyebileceğini hatırlıyor musunuz?\n\nBu hâlâ geçerli.\n\nDolayısıyla **aynı anda birden fazla process** çalıştırabilmek için, **port** üzerinde dinleyen **tek bir process** olmalı ve bu process iletişimi bir şekilde worker process'lere aktarmalıdır.\n\n### Process Başına Bellek { #memory-per-process }\n\nProgram belleğe bir şeyler yüklediğinde—örneğin bir değişkende bir machine learning modelini veya büyük bir dosyanın içeriğini tutmak gibi—bunların hepsi server'ın **belleğini (RAM)** tüketir.\n\nVe birden fazla process normalde **belleği paylaşmaz**. Yani her çalışan process'in kendi verileri, değişkenleri ve belleği vardır. Code'unuz çok bellek tüketiyorsa, **her process** buna denk bir miktar bellek tüketir.\n\n### Server Belleği { #server-memory }\n\nÖrneğin code'unuz **1 GB** boyutunda bir Machine Learning modelini yüklüyorsa, API'niz tek process ile çalışırken en az 1 GB RAM tüketir. **4 process** (4 worker) başlatırsanız her biri 1 GB RAM tüketir. Yani toplamda API'niz **4 GB RAM** tüketir.\n\nUzak server'ınız veya sanal makineniz yalnızca 3 GB RAM'e sahipse, 4 GB'tan fazla RAM yüklemeye çalışmak sorun çıkarır. 🚨\n\n### Birden Fazla Process - Bir Örnek { #multiple-processes-an-example }\n\nBu örnekte, iki adet **Worker Process** başlatıp kontrol eden bir **Manager Process** vardır.\n\nBu Manager Process büyük ihtimalle IP üzerindeki **port**'u dinleyen süreçtir ve tüm iletişimi worker process'lere aktarır.\n\nWorker process'ler uygulamanızı çalıştıran process'lerdir; bir **request** alıp bir **response** döndürmek için asıl hesaplamaları yaparlar ve sizin RAM'de değişkenlere koyduğunuz her şeyi yüklerler.\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\nElbette aynı makinede, uygulamanız dışında da muhtemelen **başka process**'ler çalışır.\n\nİlginç bir detay: Her process'in kullandığı **CPU** yüzdesi zaman içinde çok **değişken** olabilir; ancak **bellek (RAM)** genellikle az çok **stabil** kalır.\n\nEğer API'niz her seferinde benzer miktarda hesaplama yapıyorsa ve çok sayıda client'ınız varsa, **CPU kullanımı** da muhtemelen *stabil olur* (hızlı hızlı sürekli yükselip alçalmak yerine).\n\n### Replikasyon Araçları ve Stratejileri Örnekleri { #examples-of-replication-tools-and-strategies }\n\nBunu başarmak için farklı yaklaşımlar olabilir. Sonraki bölümlerde, örneğin Docker ve container'lar konuşurken, belirli stratejileri daha detaylı anlatacağım.\n\nDikkate almanız gereken ana kısıt şudur: **public IP** üzerindeki **port**'u yöneten **tek** bir bileşen olmalı. Sonrasında bu bileşenin, replikasyonla çoğaltılmış **process/worker**'lara iletişimi **aktarmanın** bir yoluna sahip olması gerekir.\n\nOlası kombinasyonlar ve stratejiler:\n\n* `--workers` ile **Uvicorn**\n    * Bir Uvicorn **process manager** **IP** ve **port** üzerinde dinler ve **birden fazla Uvicorn worker process** başlatır.\n* **Kubernetes** ve diğer dağıtık **container sistemleri**\n    * **Kubernetes** katmanında bir şey **IP** ve **port** üzerinde dinler. Replikasyon, her birinde **tek bir Uvicorn process** çalışan **birden fazla container** ile yapılır.\n* Bunu sizin yerinize yapan **cloud service**'ler\n    * Cloud service muhtemelen **replikasyonu sizin yerinize yönetir**. Size çalıştırılacak **bir process** veya kullanılacak bir **container image** tanımlama imkânı verebilir; her durumda büyük ihtimalle **tek bir Uvicorn process** olur ve bunu çoğaltmaktan cloud service sorumlu olur.\n\n/// tip | İpucu\n\n**Container**, Docker veya Kubernetes ile ilgili bazı maddeler şimdilik çok anlamlı gelmiyorsa dert etmeyin.\n\nContainer image'ları, Docker, Kubernetes vb. konuları ilerideki bir bölümde daha detaylı anlatacağım: [Container'larda FastAPI - Docker](docker.md).\n\n///\n\n## Başlatmadan Önceki Adımlar { #previous-steps-before-starting }\n\nUygulamanızı **başlatmadan önce** bazı adımlar yapmak isteyeceğiniz birçok durum vardır.\n\nÖrneğin **database migrations** çalıştırmak isteyebilirsiniz.\n\nAncak çoğu durumda, bu adımları yalnızca **bir kez** çalıştırmak istersiniz.\n\nBu yüzden, uygulamayı başlatmadan önce bu **ön adımları** çalıştıracak **tek bir process** olmasını istersiniz.\n\nVe daha sonra uygulamanın kendisi için **birden fazla process** (birden fazla worker) başlatsanız bile, bu ön adımları çalıştıranın *yine* tek process olduğundan emin olmalısınız. Bu adımlar **birden fazla process** tarafından çalıştırılsaydı, işi **paralel** şekilde tekrarlarlardı. Adımlar database migration gibi hassas bir şeyse, birbirleriyle çakışıp çatışma çıkarabilirler.\n\nElbette bazı durumlarda ön adımları birden fazla kez çalıştırmak sorun değildir; bu durumda yönetmesi çok daha kolay olur.\n\n/// tip | İpucu\n\nAyrıca, kurulumunuza bağlı olarak bazı durumlarda uygulamanızı başlatmadan önce **hiç ön adıma ihtiyaç duymayabilirsiniz**.\n\nBu durumda bunların hiçbirini düşünmeniz gerekmez. 🤷\n\n///\n\n### Ön Adımlar için Strateji Örnekleri { #examples-of-previous-steps-strategies }\n\nBu konu, **sisteminizi nasıl deploy ettiğinize** çok bağlıdır ve muhtemelen programları nasıl başlattığınız, restart'ları nasıl yönettiğiniz vb. ile bağlantılıdır.\n\nBazı olası fikirler:\n\n* Kubernetes'te, app container'ınızdan önce çalışan bir \"Init Container\"\n* Ön adımları çalıştırıp sonra uygulamanızı başlatan bir bash script\n    * Yine de o bash script'i başlatmak/restart etmek, hataları tespit etmek vb. için bir mekanizmaya ihtiyacınız olur.\n\n/// tip | İpucu\n\nBunu container'larla nasıl yapabileceğinize dair daha somut örnekleri ilerideki bir bölümde anlatacağım: [Container'larda FastAPI - Docker](docker.md).\n\n///\n\n## Kaynak Kullanımı { #resource-utilization }\n\nServer(lar)ınız bir **kaynaktır**. Programlarınızla CPU'lardaki hesaplama zamanını ve mevcut RAM belleğini tüketebilir veya **kullanabilirsiniz**.\n\nSistem kaynaklarının ne kadarını tüketmek/kullanmak istersiniz? \"Az\" demek kolaydır; ancak pratikte hedef genellikle **çökmeden mümkün olduğunca fazla** kullanmaktır.\n\n3 server için para ödüyor ama onların RAM ve CPU'sunun yalnızca küçük bir kısmını kullanıyorsanız, muhtemelen **para israf ediyorsunuz** 💸 ve muhtemelen **elektrik tüketimini** de gereksiz yere artırıyorsunuz 🌎 vb.\n\nBu durumda 2 server ile devam edip onların kaynaklarını (CPU, bellek, disk, ağ bant genişliği vb.) daha yüksek oranlarda kullanmak daha iyi olabilir.\n\nÖte yandan, 2 server'ınız var ve CPU ile RAM'in **%100**'ünü kullanıyorsanız, bir noktada bir process daha fazla bellek ister; server diski \"bellek\" gibi kullanmak zorunda kalır (binlerce kat daha yavaş olabilir) ya da hatta **crash** edebilir. Ya da bir process bir hesaplama yapmak ister ve CPU tekrar boşalana kadar beklemek zorunda kalır.\n\nBu senaryoda **bir server daha** eklemek ve bazı process'leri orada çalıştırmak daha iyi olur; böylece hepsinin **yeterli RAM'i ve CPU zamanı** olur.\n\nAyrıca, herhangi bir sebeple API'nizde bir kullanım **spike**'ı olma ihtimali de vardır. Belki viral olur, belki başka servisler veya bot'lar kullanmaya başlar. Bu durumlarda güvende olmak için ekstra kaynak isteyebilirsiniz.\n\nHedef olarak **keyfi bir sayı** belirleyebilirsiniz; örneğin kaynak kullanımını **%50 ile %90 arasında** tutmak gibi. Önemli olan, bunların muhtemelen ölçmek isteyeceğiniz ve deployment'larınızı ayarlamak için kullanacağınız ana metrikler olmasıdır.\n\nServer'ınızda CPU ve RAM kullanımını veya her process'in ne kadar kullandığını görmek için `htop` gibi basit araçları kullanabilirsiniz. Ya da server'lar arasında dağıtık çalışan daha karmaşık monitoring araçları kullanabilirsiniz.\n\n## Özet { #recap }\n\nUygulamanızı nasıl deploy edeceğinize karar verirken aklınızda tutmanız gereken ana kavramların bazılarını okudunuz:\n\n* Güvenlik - HTTPS\n* Startup'ta çalıştırma\n* Yeniden başlatmalar\n* Replikasyon (çalışan process sayısı)\n* Bellek\n* Başlatmadan önceki adımlar\n\nBu fikirleri ve nasıl uygulayacağınızı anlamak, deployment'larınızı yapılandırırken ve ince ayar yaparken ihtiyaç duyacağınız sezgiyi kazanmanızı sağlamalıdır. 🤓\n\nSonraki bölümlerde, izleyebileceğiniz stratejilere dair daha somut örnekler paylaşacağım. 🚀\n"
  },
  {
    "path": "docs/tr/docs/deployment/docker.md",
    "content": "# Container'larda FastAPI - Docker { #fastapi-in-containers-docker }\n\nFastAPI uygulamalarını deploy ederken yaygın bir yaklaşım, bir **Linux container image** oluşturmaktır. Bu genellikle [**Docker**](https://www.docker.com/) kullanılarak yapılır. Ardından bu container image'ı birkaç farklı yöntemden biriyle deploy edebilirsiniz.\n\nLinux container'ları kullanmanın **güvenlik**, **tekrarlanabilirlik**, **basitlik** gibi birçok avantajı vardır.\n\n/// tip | İpucu\n\nAceleniz var ve bunları zaten biliyor musunuz? Aşağıdaki [`Dockerfile`'a atlayın 👇](#build-a-docker-image-for-fastapi).\n\n///\n\n<details>\n<summary>Dockerfile Önizleme 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# If running behind a proxy like Nginx or Traefik add --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## Container Nedir { #what-is-a-container }\n\nContainer'lar (özellikle Linux container'ları), bir uygulamayı tüm bağımlılıkları ve gerekli dosyalarıyla birlikte paketlemenin, aynı sistemdeki diğer container'lardan (diğer uygulama ya da bileşenlerden) izole tutarken yapılan, çok **hafif** bir yoludur.\n\nLinux container'ları, host'un (makine, sanal makine, cloud server vb.) aynı Linux kernel'ini kullanarak çalışır. Bu da, tüm bir işletim sistemini emüle eden tam sanal makinelere kıyasla çok daha hafif oldukları anlamına gelir.\n\nBu sayede container'lar **az kaynak** tüketir; süreçleri doğrudan çalıştırmaya benzer bir seviyede (bir sanal makine çok daha fazla tüketirdi).\n\nContainer'ların ayrıca kendi **izole** çalışan process'leri (çoğunlukla tek bir process), dosya sistemi ve ağı vardır. Bu da deployment, güvenlik, geliştirme vb. süreçleri kolaylaştırır.\n\n## Container Image Nedir { #what-is-a-container-image }\n\nBir **container**, bir **container image**'dan çalıştırılır.\n\nContainer image; bir container içinde bulunması gereken tüm dosyaların, environment variable'ların ve varsayılan komut/programın **statik** bir sürümüdür. Buradaki **statik**, container **image**'ının çalışmadığı, execute edilmediği; sadece paketlenmiş dosyalar ve metadata olduğu anlamına gelir.\n\nDepolanmış statik içerik olan \"**container image**\"ın aksine, \"**container**\" normalde çalışan instance'ı, yani **execute edilen** şeyi ifade eder.\n\n**Container** başlatılıp çalıştığında (bir **container image**'dan başlatılır), dosyalar oluşturabilir/değiştirebilir, environment variable'ları değiştirebilir vb. Bu değişiklikler sadece o container içinde kalır; alttaki container image'da kalıcı olmaz (diske kaydedilmez).\n\nBir container image, **program** dosyası ve içeriklerine benzetilebilir; örn. `python` ve `main.py` gibi bir dosya.\n\nVe **container**'ın kendisi (container image'a karşıt olarak) image'ın gerçek çalışan instance'ıdır; bir **process**'e benzer. Hatta bir container, yalnızca içinde **çalışan bir process** varken çalışır (ve genelde tek process olur). İçinde çalışan process kalmayınca container durur.\n\n## Container Image'lar { #container-images }\n\nDocker, **container image** ve **container** oluşturup yönetmek için kullanılan başlıca araçlardan biri olmuştur.\n\nAyrıca birçok araç, ortam, veritabanı ve uygulama için önceden hazırlanmış **resmi container image**'ların bulunduğu herkese açık bir [Docker Hub](https://hub.docker.com/) vardır.\n\nÖrneğin, resmi bir [Python Image](https://hub.docker.com/_/python) bulunur.\n\nVe veritabanları gibi farklı şeyler için de birçok image vardır; örneğin:\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis), vb.\n\nHazır bir container image kullanarak farklı araçları **birleştirmek** ve birlikte kullanmak çok kolaydır. Örneğin yeni bir veritabanını denemek için. Çoğu durumda **resmi image**'ları kullanıp sadece environment variable'lar ile yapılandırmanız yeterlidir.\n\nBu şekilde, çoğu zaman container'lar ve Docker hakkında öğrendiklerinizi farklı araç ve bileşenlerde tekrar kullanabilirsiniz.\n\nDolayısıyla; veritabanı, Python uygulaması, React frontend uygulaması olan bir web server gibi farklı şeyler için **birden fazla container** çalıştırır ve bunları internal network üzerinden birbirine bağlarsınız.\n\nDocker veya Kubernetes gibi tüm container yönetim sistemlerinde bu ağ özellikleri entegre olarak bulunur.\n\n## Container'lar ve Process'ler { #containers-and-processes }\n\nBir **container image** normalde metadata içinde, **container** başlatıldığında çalıştırılacak varsayılan program/komutu ve o programa geçirilecek parametreleri içerir. Bu, komut satırında yazacağınız şeye çok benzer.\n\nBir **container** başlatıldığında bu komutu/programı çalıştırır (ancak isterseniz bunu override edip başka bir komut/program çalıştırabilirsiniz).\n\nBir container, **ana process** (komut/program) çalıştığı sürece çalışır.\n\nContainer'larda normalde **tek bir process** olur. Ancak ana process içinden subprocess'ler başlatmak da mümkündür; böylece aynı container içinde **birden fazla process** olur.\n\nAma **en az bir çalışan process olmadan** çalışan bir container olamaz. Ana process durursa container da durur.\n\n## FastAPI için Docker Image Oluşturalım { #build-a-docker-image-for-fastapi }\n\nTamam, şimdi bir şeyler inşa edelim! 🚀\n\nResmi **Python** image'ını temel alarak, FastAPI için **sıfırdan** bir **Docker image** nasıl oluşturulur göstereceğim.\n\nBu, örneğin şu durumlarda **çoğu zaman** yapmak isteyeceğiniz şeydir:\n\n* **Kubernetes** veya benzeri araçlar kullanırken\n* **Raspberry Pi** üzerinde çalıştırırken\n* Container image'ınızı sizin için çalıştıran bir cloud servisi kullanırken, vb.\n\n### Paket Gereksinimleri { #package-requirements }\n\nUygulamanızın **paket gereksinimleri** genelde bir dosyada yer alır.\n\nBu, gereksinimleri **yüklemek** için kullandığınız araca göre değişir.\n\nEn yaygın yöntem, paket adları ve versiyonlarının satır satır yazıldığı bir `requirements.txt` dosyasına sahip olmaktır.\n\nVersiyon aralıklarını belirlemek için elbette [FastAPI sürümleri hakkında](versions.md) bölümünde okuduğunuz fikirleri kullanırsınız.\n\nÖrneğin `requirements.txt` şöyle görünebilir:\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\nVe bu bağımlılıkları normalde `pip` ile yüklersiniz, örneğin:\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info | Bilgi\n\nPaket bağımlılıklarını tanımlamak ve yüklemek için başka formatlar ve araçlar da vardır.\n\n///\n\n### **FastAPI** Kodunu Oluşturun { #create-the-fastapi-code }\n\n* Bir `app` dizini oluşturun ve içine girin.\n* Boş bir `__init__.py` dosyası oluşturun.\n* Aşağıdakilerle bir `main.py` dosyası oluşturun:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\nŞimdi aynı proje dizininde `Dockerfile` adlı bir dosya oluşturun ve içine şunları yazın:\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. Resmi Python base image'ından başlayın.\n\n2. Geçerli çalışma dizinini `/code` olarak ayarlayın.\n\n    `requirements.txt` dosyasını ve `app` dizinini buraya koyacağız.\n\n3. Gereksinimleri içeren dosyayı `/code` dizinine kopyalayın.\n\n    Önce kodun tamamını değil, **sadece** gereksinim dosyasını kopyalayın.\n\n    Bu dosya **çok sık değişmediği** için Docker bunu tespit eder ve bu adımda **cache** kullanır; böylece bir sonraki adım için de cache devreye girer.\n\n4. Gereksinim dosyasındaki paket bağımlılıklarını yükleyin.\n\n    `--no-cache-dir` seçeneği, indirilen paketlerin yerel olarak kaydedilmemesini `pip`'e söyler. Bu kayıt, `pip` aynı paketleri tekrar yüklemek için yeniden çalıştırılacaksa işe yarar; ancak container'larla çalışırken genelde bu durum geçerli değildir.\n\n    /// note | Not\n\n    `--no-cache-dir` yalnızca `pip` ile ilgilidir; Docker veya container'larla ilgili değildir.\n\n    ///\n\n    `--upgrade` seçeneği, paketler zaten yüklüyse `pip`'e onları yükseltmesini söyler.\n\n    Bir önceki adım (dosyayı kopyalama) **Docker cache** tarafından tespit edilebildiği için, bu adım da uygun olduğunda **Docker cache'i kullanır**.\n\n    Bu adımda cache kullanmak, geliştirme sırasında image'ı tekrar tekrar build ederken size çok **zaman** kazandırır; her seferinde bağımlılıkları **indirip yüklemek** zorunda kalmazsınız.\n\n5. `./app` dizinini `/code` dizininin içine kopyalayın.\n\n    Burada en sık değişen şey olan kodun tamamı bulunduğundan, bu adım (ve genelde bundan sonraki adımlar) için Docker **cache**'i kolay kolay kullanılamaz.\n\n    Bu yüzden, container image build sürelerini optimize etmek için bunu `Dockerfile`'ın **sonlarına yakın** koymak önemlidir.\n\n6. Altta Uvicorn kullanan `fastapi run` komutunu **command** olarak ayarlayın.\n\n    `CMD` bir string listesi alır; bu string'lerin her biri komut satırında boşlukla ayrılmış şekilde yazacağınız parçaları temsil eder.\n\n    Bu komut, yukarıda `WORKDIR /code` ile ayarladığınız `/code` dizininden çalıştırılır.\n\n/// tip | İpucu\n\nKod içindeki her numara balonuna tıklayarak her satırın ne yaptığını gözden geçirin. 👆\n\n///\n\n/// warning | Uyarı\n\nAşağıda açıklandığı gibi `CMD` talimatının **her zaman** **exec form**'unu kullandığınızdan emin olun.\n\n///\n\n#### `CMD` Kullanımı - Exec Form { #use-cmd-exec-form }\n\n[`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) Docker talimatı iki formda yazılabilir:\n\n✅ **Exec** form:\n\n```Dockerfile\n# ✅ Do this\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ **Shell** form:\n\n```Dockerfile\n# ⛔️ Don't do this\nCMD fastapi run app/main.py --port 80\n```\n\nFastAPI'nin düzgün şekilde kapanabilmesi ve [lifespan event](../advanced/events.md)'lerinin tetiklenmesi için her zaman **exec** formunu kullanın.\n\nDetaylar için [shell ve exec form için Docker dokümanlarına](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form) bakabilirsiniz.\n\nBu durum `docker compose` kullanırken oldukça belirgin olabilir. Daha teknik detaylar için şu Docker Compose FAQ bölümüne bakın: [Hizmetlerimin yeniden oluşturulması veya durması neden 10 saniye sürüyor?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).\n\n#### Dizin Yapısı { #directory-structure }\n\nArtık dizin yapınız şöyle olmalı:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### TLS Termination Proxy Arkasında { #behind-a-tls-termination-proxy }\n\nContainer'ınızı Nginx veya Traefik gibi bir TLS Termination Proxy (load balancer) arkasında çalıştırıyorsanız `--proxy-headers` seçeneğini ekleyin. Bu, Uvicorn'a (FastAPI CLI üzerinden) uygulamanın HTTPS arkasında çalıştığını söyleyen proxy header'larına güvenmesini söyler.\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Docker Cache { #docker-cache }\n\nBu `Dockerfile` içinde önemli bir numara var: önce kodun geri kalanını değil, **sadece bağımlılık dosyasını** kopyalıyoruz. Nedenini anlatayım.\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker ve benzeri araçlar bu container image'larını **artımlı (incremental)** olarak **build** eder; `Dockerfile`'ın en üstünden başlayıp her talimatın oluşturduğu dosyaları ekleyerek **katman katman (layer)** ilerler.\n\nDocker ve benzeri araçlar image build ederken ayrıca bir **internal cache** kullanır. Son build'den beri bir dosya değişmediyse, dosyayı tekrar kopyalayıp sıfırdan yeni bir layer oluşturmak yerine, daha önce oluşturulan **aynı layer**'ı yeniden kullanır.\n\nSadece dosya kopyalamayı azaltmak her zaman büyük fark yaratmaz. Ancak o adımda cache kullanıldığı için, **bir sonraki adımda da cache kullanılabilir**. Örneğin bağımlılıkları yükleyen şu talimat için:\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\nPaket gereksinimleri dosyası **sık sık değişmez**. Bu yüzden sadece bu dosyayı kopyalayınca, Docker bu adımda **cache** kullanabilir.\n\nSonra Docker, bağımlılıkları indirip yükleyen **bir sonraki adımda** da cache kullanabilir. Asıl **çok zaman kazandığımız** yer de burasıdır. ✨ ...ve beklerken sıkılmayı engeller. 😪😆\n\nBağımlılıkları indirip yüklemek **dakikalar sürebilir**, fakat **cache** kullanmak en fazla **saniyeler** alır.\n\nGeliştirme sırasında kod değişikliklerinizin çalıştığını kontrol etmek için container image'ı tekrar tekrar build edeceğinizden, bu ciddi birikimli zaman kazancı sağlar.\n\nSonra `Dockerfile`'ın sonlarına doğru tüm kodu kopyalarız. En sık değişen kısım bu olduğu için sona koyarız; çünkü neredeyse her zaman bu adımdan sonra gelen adımlar cache kullanamaz.\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### Docker Image'ını Build Edin { #build-the-docker-image }\n\nTüm dosyalar hazır olduğuna göre container image'ı build edelim.\n\n* Proje dizinine gidin (`Dockerfile`'ınızın olduğu ve `app` dizininizi içeren dizin).\n* FastAPI image'ınızı build edin:\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | İpucu\n\nSondaki `.` ifadesine dikkat edin; `./` ile aynı anlama gelir ve Docker'a container image build etmek için hangi dizini kullanacağını söyler.\n\nBu örnekte, mevcut dizindir (`.`).\n\n///\n\n### Docker Container'ını Başlatın { #start-the-docker-container }\n\n* Image'ınızdan bir container çalıştırın:\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## Kontrol Edin { #check-it }\n\nDocker container'ınızın URL'inden kontrol edebilmelisiniz. Örneğin: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) veya [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (ya da Docker host'unuzu kullanarak eşdeğeri).\n\nŞuna benzer bir şey görürsünüz:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## Etkileşimli API Dokümanları { #interactive-api-docs }\n\nŞimdi [http://192.168.99.100/docs](http://192.168.99.100/docs) veya [http://127.0.0.1/docs](http://127.0.0.1/docs) adresine gidebilirsiniz (ya da Docker host'unuzla eşdeğeri).\n\nOtomatik etkileşimli API dokümantasyonunu görürsünüz ( [Swagger UI](https://github.com/swagger-api/swagger-ui) tarafından sağlanır):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## Alternatif API Dokümanları { #alternative-api-docs }\n\nAyrıca [http://192.168.99.100/redoc](http://192.168.99.100/redoc) veya [http://127.0.0.1/redoc](http://127.0.0.1/redoc) adresine de gidebilirsiniz (ya da Docker host'unuzla eşdeğeri).\n\nAlternatif otomatik dokümantasyonu görürsünüz ([ReDoc](https://github.com/Rebilly/ReDoc) tarafından sağlanır):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Tek Dosyalık FastAPI ile Docker Image Oluşturma { #build-a-docker-image-with-a-single-file-fastapi }\n\nFastAPI uygulamanız tek bir dosyaysa; örneğin `./app` dizini olmadan sadece `main.py` varsa, dosya yapınız şöyle olabilir:\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\nBu durumda `Dockerfile` içinde dosyayı kopyaladığınız path'leri buna göre değiştirmeniz yeterlidir:\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. `main.py` dosyasını doğrudan `/code` dizinine kopyalayın (herhangi bir `./app` dizini olmadan).\n\n2. Tek dosya olan `main.py` içindeki uygulamanızı sunmak için `fastapi run` kullanın.\n\nDosyayı `fastapi run`'a verdiğinizde, bunun bir package'ın parçası değil tek bir dosya olduğunu otomatik olarak algılar; nasıl import edip FastAPI uygulamanızı nasıl serve edeceğini bilir. 😎\n\n## Deployment Kavramları { #deployment-concepts }\n\nAynı [Deployment Kavramları](concepts.md)nı bu kez container'lar açısından tekrar konuşalım.\n\nContainer'lar, bir uygulamayı **build etme ve deploy etme** sürecini basitleştiren bir araçtır. Ancak bu **deployment kavramları**nı ele almak için belirli bir yaklaşımı zorunlu kılmazlar; birkaç farklı strateji mümkündür.\n\n**İyi haber** şu: Hangi stratejiyi seçerseniz seçin, deployment kavramlarının tamamını kapsayacak bir yol vardır. 🎉\n\nBu **deployment kavramları**nı container'lar açısından gözden geçirelim:\n\n* HTTPS\n* Startup'ta çalıştırma\n* Restart'lar\n* Replication (çalışan process sayısı)\n* Memory\n* Başlatmadan önceki adımlar\n\n## HTTPS { #https }\n\nBir FastAPI uygulamasının sadece **container image**'ına (ve sonra çalışan **container**'a) odaklanırsak, HTTPS genellikle **haricen** başka bir araçla ele alınır.\n\nÖrneğin [Traefik](https://traefik.io/) kullanan başka bir container olabilir; **HTTPS** ve **sertifika**ların **otomatik** alınmasını o yönetebilir.\n\n/// tip | İpucu\n\nTraefik; Docker, Kubernetes ve diğerleriyle entegre çalışır. Bu sayede container'larınız için HTTPS'i kurup yapılandırmak oldukça kolaydır.\n\n///\n\nAlternatif olarak HTTPS, bir cloud provider'ın sunduğu servislerden biri tarafından da yönetilebilir (uygulama yine container içinde çalışırken).\n\n## Startup'ta Çalıştırma ve Restart'lar { #running-on-startup-and-restarts }\n\nContainer'ınızı **başlatıp çalıştırmaktan** sorumlu genellikle başka bir araç olur.\n\nBu; doğrudan **Docker**, **Docker Compose**, **Kubernetes**, bir **cloud service** vb. olabilir.\n\nÇoğu (veya tüm) durumda, container'ı startup'ta çalıştırmayı ve hata durumlarında restart'ları etkinleştirmeyi sağlayan basit bir seçenek vardır. Örneğin Docker'da bu, `--restart` komut satırı seçeneğidir.\n\nContainer kullanmadan, uygulamaları startup'ta çalıştırmak ve restart mekanizması eklemek zahmetli ve zor olabilir. Ancak **container'larla çalışırken** çoğu zaman bu işlevler varsayılan olarak hazır gelir. ✨\n\n## Replication - Process Sayısı { #replication-number-of-processes }\n\nEğer bir <dfn title=\"Bir şekilde birbirine bağlanacak ve birlikte çalışacak şekilde yapılandırılmış makineler grubu.\">küme</dfn> (cluster) olarak yapılandırılmış makineler grubunuz varsa ve bunları **Kubernetes**, Docker Swarm Mode, Nomad veya benzeri, birden çok makinede dağıtık container'ları yöneten karmaşık bir sistemle yönetiyorsanız, replication'ı her container içinde bir **process manager** (ör. worker'lı Uvicorn) kullanarak yönetmek yerine, muhtemelen **küme seviyesinde (cluster level)** ele almak istersiniz.\n\nKubernetes gibi dağıtık container yönetim sistemleri, gelen request'ler için **load balancing** desteği sunarken aynı zamanda **container replication**'ını yönetmek için entegre mekanizmalara sahiptir. Hepsi **cluster seviyesinde**.\n\nBu tür durumlarda, yukarıda [anlatıldığı gibi](#dockerfile) bağımlılıkları yükleyip **sıfırdan bir Docker image** build etmek ve birden fazla Uvicorn worker kullanmak yerine **tek bir Uvicorn process** çalıştırmak istersiniz.\n\n### Load Balancer { #load-balancer }\n\nContainer'lar kullanırken, genellikle ana port'ta dinleyen bir bileşen olur. Bu, **HTTPS**'i ele almak için bir **TLS Termination Proxy** olan başka bir container da olabilir ya da benzeri bir araç olabilir.\n\nBu bileşen request'lerin **yükünü** alıp worker'lar arasında (umarım) **dengeli** şekilde dağıttığı için yaygın olarak **Load Balancer** diye de adlandırılır.\n\n/// tip | İpucu\n\nHTTPS için kullanılan aynı **TLS Termination Proxy** bileşeni muhtemelen bir **Load Balancer** olarak da çalışır.\n\n///\n\nContainer'larla çalışırken, onları başlatıp yönettiğiniz sistem; bu **load balancer**'dan (aynı zamanda **TLS Termination Proxy** de olabilir) uygulamanızın bulunduğu container(lar)a **network communication**'ı (ör. HTTP request'leri) iletmek için zaten dahili araçlar sunar.\n\n### Tek Load Balancer - Çoklu Worker Container { #one-load-balancer-multiple-worker-containers }\n\n**Kubernetes** veya benzeri dağıtık container yönetim sistemleriyle çalışırken, dahili ağ mekanizmaları sayesinde ana **port**'u dinleyen tek bir **load balancer**, uygulamanızı çalıştıran muhtemelen **birden fazla container**'a request'leri iletebilir.\n\nUygulamanızı çalıştıran bu container'ların her birinde normalde **tek bir process** olur (ör. FastAPI uygulamanızı çalıştıran bir Uvicorn process). Hepsi aynı şeyi çalıştıran **özdeş container**'lardır; ancak her birinin kendi process'i, memory'si vb. vardır. Böylece CPU'nun **farklı core**'larında, hatta **farklı makinelerde** paralelleştirmeden yararlanırsınız.\n\nLoad balancer'lı dağıtık sistem, request'leri uygulamanızın bulunduğu container'ların her birine sırayla **dağıtır**. Böylece her request, uygulamanızın birden fazla **replicated container**'ından biri tarafından işlenebilir.\n\nVe bu **load balancer** normalde cluster'ınızdaki *diğer* uygulamalara giden request'leri de (ör. farklı bir domain ya da farklı bir URL path prefix altında) yönetebilir ve iletişimi o *diğer* uygulamanın doğru container'larına iletir.\n\n### Container Başına Tek Process { #one-process-per-container }\n\nBu senaryoda, replication'ı zaten cluster seviyesinde yaptığınız için, muhtemelen **container başına tek bir (Uvicorn) process** istersiniz.\n\nDolayısıyla bu durumda container içinde `--workers` gibi bir komut satırı seçeneğiyle çoklu worker istemezsiniz. Container başına sadece **tek bir Uvicorn process** istersiniz (ama muhtemelen birden fazla container).\n\nContainer içine ekstra bir process manager koymak (çoklu worker gibi) çoğu zaman zaten cluster sisteminizle çözdüğünüz şeye ek **gereksiz karmaşıklık** katar.\n\n### Birden Fazla Process'li Container'lar ve Özel Durumlar { #containers-with-multiple-processes-and-special-cases }\n\nElbette bazı **özel durumlarda** bir container içinde birden fazla **Uvicorn worker process** çalıştırmak isteyebilirsiniz.\n\nBu durumlarda çalıştırmak istediğiniz worker sayısını `--workers` komut satırı seçeneğiyle ayarlayabilirsiniz:\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. Burada worker sayısını 4 yapmak için `--workers` komut satırı seçeneğini kullanıyoruz.\n\nBunun mantıklı olabileceği birkaç örnek:\n\n#### Basit Bir Uygulama { #a-simple-app }\n\nUygulamanız tek bir server üzerinde (cluster değil) çalışacak kadar **basitse**, container içinde bir process manager isteyebilirsiniz.\n\n#### Docker Compose { #docker-compose }\n\n**Docker Compose** ile **tek bir server**'a (cluster değil) deploy ediyor olabilirsiniz. Bu durumda, paylaşılan ağı ve **load balancing**'i koruyarak container replication'ını (Docker Compose ile) yönetmenin kolay bir yolu olmayabilir.\n\nBu durumda, tek bir container içinde **bir process manager** ile **birden fazla worker process** başlatmak isteyebilirsiniz.\n\n---\n\nAna fikir şu: Bunların **hiçbiri** körü körüne uymanız gereken **değişmez kurallar** değildir. Bu fikirleri, kendi kullanım senaryonuzu **değerlendirmek** ve sisteminiz için en iyi yaklaşımı seçmek için kullanabilirsiniz. Şu kavramları nasıl yöneteceğinize bakarak karar verin:\n\n* Güvenlik - HTTPS\n* Startup'ta çalıştırma\n* Restart'lar\n* Replication (çalışan process sayısı)\n* Memory\n* Başlatmadan önceki adımlar\n\n## Memory { #memory }\n\n**Container başına tek process** çalıştırırsanız, her container'ın tüketeceği memory miktarı aşağı yukarı tanımlı, stabil ve sınırlı olur (replication varsa birden fazla container için).\n\nSonra aynı memory limit ve gereksinimlerini container yönetim sisteminizin (ör. **Kubernetes**) konfigürasyonlarında belirleyebilirsiniz. Böylece sistem; ihtiyaç duyulan memory miktarını ve cluster'daki makinelerde mevcut memory'yi dikkate alarak **uygun makinelerde container'ları replicate edebilir**.\n\nUygulamanız **basitse**, muhtemelen bu **bir sorun olmaz** ve katı memory limitleri belirlemeniz gerekmeyebilir. Ancak **çok memory kullanıyorsanız** (ör. **machine learning** modelleriyle), ne kadar memory tükettiğinizi kontrol edip **her makinede** çalışacak **container sayısını** ayarlamalısınız (ve gerekirse cluster'a daha fazla makine eklemelisiniz).\n\n**Container başına birden fazla process** çalıştırırsanız, başlatılan process sayısının mevcut olandan **fazla memory tüketmediğinden** emin olmanız gerekir.\n\n## Başlatmadan Önceki Adımlar ve Container'lar { #previous-steps-before-starting-and-containers }\n\nContainer kullanıyorsanız (örn. Docker, Kubernetes), temelde iki yaklaşım vardır.\n\n### Birden Fazla Container { #multiple-containers }\n\n**Birden fazla container**'ınız varsa ve muhtemelen her biri **tek process** çalıştırıyorsa (ör. bir **Kubernetes** cluster'ında), replication yapılan worker container'lar çalışmadan **önce**, **başlatmadan önceki adımlar**ın işini yapan **ayrı bir container** kullanmak isteyebilirsiniz (tek container, tek process).\n\n/// info | Bilgi\n\nKubernetes kullanıyorsanız, bu muhtemelen bir [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) olur.\n\n///\n\nKullanım senaryonuzda bu adımları **paralel olarak birden fazla kez** çalıştırmak sorun değilse (örneğin veritabanı migration çalıştırmıyor, sadece veritabanı hazır mı diye kontrol ediyorsanız), o zaman her container'da ana process başlamadan hemen önce de çalıştırabilirsiniz.\n\n### Tek Container { #single-container }\n\nBasit bir kurulumda; **tek bir container** olup onun içinde birden fazla **worker process** (ya da sadece bir process) başlatıyorsanız, bu adımları aynı container içinde, uygulama process'ini başlatmadan hemen önce çalıştırabilirsiniz.\n\n### Base Docker Image { #base-docker-image }\n\nEskiden resmi bir FastAPI Docker image'ı vardı: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). Ancak artık kullanımdan kaldırıldı (deprecated). ⛔️\n\nMuhtemelen bu base Docker image'ını (veya benzeri başka bir image'ı) kullanmamalısınız.\n\n**Kubernetes** (veya diğerleri) kullanıyor ve cluster seviyesinde birden fazla **container** ile **replication** ayarlıyorsanız, bu durumda yukarıda anlatıldığı gibi **sıfırdan bir image build etmek** daha iyi olur: [FastAPI için Docker Image Oluşturalım](#build-a-docker-image-for-fastapi).\n\nVe birden fazla worker gerekiyorsa, sadece `--workers` komut satırı seçeneğini kullanabilirsiniz.\n\n/// note | Teknik Detaylar\n\nBu Docker image, Uvicorn dead worker'ları yönetmeyi ve yeniden başlatmayı desteklemediği dönemde oluşturulmuştu. Bu yüzden Uvicorn ile birlikte Gunicorn kullanmak gerekiyordu; sırf Gunicorn, Uvicorn worker process'lerini yönetip yeniden başlatsın diye oldukça fazla karmaşıklık ekleniyordu.\n\nAncak artık Uvicorn (ve `fastapi` komutu) `--workers` kullanımını desteklediğine göre, kendi image'ınızı build etmek yerine bir base Docker image kullanmanın bir nedeni kalmadı (kod miktarı da hemen hemen aynı 😅).\n\n///\n\n## Container Image'ı Deploy Etme { #deploy-the-container-image }\n\nBir Container (Docker) Image'ınız olduktan sonra bunu deploy etmenin birkaç yolu vardır.\n\nÖrneğin:\n\n* Tek bir server'da **Docker Compose** ile\n* Bir **Kubernetes** cluster'ı ile\n* Docker Swarm Mode cluster'ı ile\n* Nomad gibi başka bir araçla\n* Container image'ınızı alıp deploy eden bir cloud servisiyle\n\n## `uv` ile Docker Image { #docker-image-with-uv }\n\nProjenizi yüklemek ve yönetmek için [uv](https://github.com/astral-sh/uv) kullanıyorsanız, onların [uv Docker rehberini](https://docs.astral.sh/uv/guides/integration/docker/) takip edebilirsiniz.\n\n## Özet { #recap }\n\nContainer sistemleri (örn. **Docker** ve **Kubernetes** ile) kullanınca tüm **deployment kavramları**nı ele almak oldukça kolaylaşır:\n\n* HTTPS\n* Startup'ta çalıştırma\n* Restart'lar\n* Replication (çalışan process sayısı)\n* Memory\n* Başlatmadan önceki adımlar\n\nÇoğu durumda bir base image kullanmak istemezsiniz; bunun yerine resmi Python Docker image'ını temel alarak **sıfırdan bir container image** build edersiniz.\n\n`Dockerfile` içindeki talimatların **sırasına** ve **Docker cache**'ine dikkat ederek **build sürelerini minimize edebilir**, üretkenliğinizi artırabilirsiniz (ve beklerken sıkılmayı önlersiniz). 😎\n"
  },
  {
    "path": "docs/tr/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\nFastAPI uygulamanızı [FastAPI Cloud](https://fastapicloud.com)'a **tek bir komutla** deploy edebilirsiniz. Henüz yapmadıysanız gidip bekleme listesine katılın. 🚀\n\n## Giriş Yapma { #login }\n\nÖnceden bir **FastAPI Cloud** hesabınız olduğundan emin olun (sizi bekleme listesinden davet ettik 😉).\n\nArdından giriş yapın:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## Deploy { #deploy }\n\nŞimdi uygulamanızı **tek bir komutla** deploy edin:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nHepsi bu! Artık uygulamanıza o URL üzerinden erişebilirsiniz. ✨\n\n## FastAPI Cloud Hakkında { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)**, **FastAPI**'nin arkasındaki aynı yazar ve ekip tarafından geliştirilmiştir.\n\nBir API'yi minimum eforla **geliştirme**, **deploy etme** ve **erişilebilir kılma** sürecini sadeleştirir.\n\nFastAPI ile uygulama geliştirirken elde ettiğiniz aynı **developer experience**'ı, onları buluta **deploy etmeye** de taşır. 🎉\n\nAyrıca bir uygulamayı deploy ederken ihtiyaç duyacağınız pek çok şeyi de sizin için halleder; örneğin:\n\n* HTTPS\n* Replication (çoğaltma), request'lere göre autoscaling ile\n* vb.\n\nFastAPI Cloud, *FastAPI and friends* açık kaynak projelerinin birincil sponsoru ve finansman sağlayıcısıdır. ✨\n\n## Diğer cloud sağlayıcılarına deploy etme { #deploy-to-other-cloud-providers }\n\nFastAPI açık kaynaklıdır ve standartlara dayanır. FastAPI uygulamalarını seçtiğiniz herhangi bir cloud sağlayıcısına deploy edebilirsiniz.\n\nFastAPI uygulamalarını deploy etmek için cloud sağlayıcınızın kendi kılavuzlarını takip edin. 🤓\n\n## Kendi server'ınıza deploy etme { #deploy-your-own-server }\n\nBu **Deployment** kılavuzunun ilerleyen bölümlerinde tüm detayları da ele alacağız; böylece neler olduğunu, nelerin gerçekleşmesi gerektiğini ve FastAPI uygulamalarını kendi başınıza (kendi server'larınızla da) nasıl deploy edebileceğinizi anlayacaksınız. 🤓\n"
  },
  {
    "path": "docs/tr/docs/deployment/https.md",
    "content": "# HTTPS Hakkında { #about-https }\n\nHTTPS’in sadece \"açık\" ya da \"kapalı\" olan bir şey olduğunu düşünmek kolaydır.\n\nAncak bundan çok daha karmaşıktır.\n\n/// tip | İpucu\n\nAceleniz varsa veya çok da önemsemiyorsanız, her şeyi farklı tekniklerle adım adım kurmak için sonraki bölümlere geçin.\n\n///\n\nBir kullanıcı gözüyle **HTTPS’in temellerini öğrenmek** için [https://howhttps.works/](https://howhttps.works/) adresine bakın.\n\nŞimdi de **geliştirici perspektifinden**, HTTPS hakkında düşünürken akılda tutulması gereken birkaç nokta:\n\n* HTTPS için **server**’ın, **üçüncü bir taraf** tarafından verilen **\"sertifikalara\"** sahip olması gerekir.\n    * Bu sertifikalar aslında üçüncü tarafça \"üretilmez\", üçüncü taraftan **temin edilir**.\n* Sertifikaların bir **geçerlilik süresi** vardır.\n    * Süresi **dolar**.\n    * Sonrasında **yenilenmeleri**, üçüncü taraftan **yeniden temin edilmeleri** gerekir.\n* Bağlantının şifrelenmesi **TCP seviyesinde** gerçekleşir.\n    * Bu, **HTTP’nin bir katman altıdır**.\n    * Dolayısıyla **sertifika ve şifreleme** işlemleri **HTTP’den önce** yapılır.\n* **TCP \"domain\"leri bilmez**. Yalnızca IP adreslerini bilir.\n    * İstenen **spesifik domain** bilgisi **HTTP verisinin** içindedir.\n* **HTTPS sertifikaları** belirli bir **domain**’i \"sertifikalandırır\"; ancak protokol ve şifreleme TCP seviyesinde, hangi domain ile çalışıldığı **henüz bilinmeden** gerçekleşir.\n* **Varsayılan olarak** bu, IP adresi başına yalnızca **bir HTTPS sertifikası** olabileceği anlamına gelir.\n    * Server’ınız ne kadar büyük olursa olsun ya da üzerindeki her uygulama ne kadar küçük olursa olsun.\n    * Ancak bunun bir **çözümü** vardır.\n* **TLS** protokolüne (TCP seviyesinde, HTTP’den önce şifrelemeyi yapan) eklenen **[<abbr title=\"Server Name Indication - Sunucu Adı Belirtimi\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)** adlı bir **extension** vardır.\n    * Bu SNI extension’ı, tek bir server’ın (tek bir **IP adresiyle**) **birden fazla HTTPS sertifikası** kullanmasına ve **birden fazla HTTPS domain/uygulama** sunmasına izin verir.\n    * Bunun çalışması için server üzerinde, **public IP adresini** dinleyen tek bir bileşenin (programın) server’daki **tüm HTTPS sertifikalarına** sahip olması gerekir.\n* Güvenli bir bağlantı elde edildikten **sonra**, iletişim protokolü **hâlâ HTTP**’dir.\n    * İçerikler, **HTTP protokolü** ile gönderiliyor olsa bile **şifrelenmiştir**.\n\nYaygın yaklaşım, server’da (makine, host vb.) çalışan **tek bir program/HTTP server** bulundurup **HTTPS ile ilgili tüm kısımları** yönetmektir: **şifreli HTTPS request**’leri almak, aynı server’da çalışan gerçek HTTP uygulamasına (bu örnekte **FastAPI** uygulaması) **şifresi çözülmüş HTTP request**’leri iletmek, uygulamadan gelen **HTTP response**’u almak, uygun **HTTPS sertifikası** ile **şifrelemek** ve **HTTPS** ile client’a geri göndermek. Bu server’a çoğu zaman **[TLS Termination Proxy](https://en.wikipedia.org/wiki/TLS_termination_proxy)** denir.\n\nTLS Termination Proxy olarak kullanabileceğiniz seçeneklerden bazıları:\n\n* Traefik (sertifika yenilemelerini de yönetebilir)\n* Caddy (sertifika yenilemelerini de yönetebilir)\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\nLet's Encrypt’ten önce bu **HTTPS sertifikaları**, güvenilen üçüncü taraflar tarafından satılırdı.\n\nBu sertifikalardan birini temin etme süreci zahmetliydi, epey evrak işi gerektirirdi ve sertifikalar oldukça pahalıydı.\n\nSonra **[Let's Encrypt](https://letsencrypt.org/)** ortaya çıktı.\n\nLinux Foundation’ın bir projesidir. **HTTPS sertifikalarını ücretsiz** ve otomatik bir şekilde sağlar. Bu sertifikalar tüm standart kriptografik güvenliği kullanır ve kısa ömürlüdür (yaklaşık 3 ay). Bu yüzden, ömürleri kısa olduğu için **güvenlik aslında daha iyidir**.\n\nDomain’ler güvenli şekilde doğrulanır ve sertifikalar otomatik üretilir. Bu sayede sertifikaların yenilenmesini otomatikleştirmek de mümkün olur.\n\nAmaç, bu sertifikaların temin edilmesi ve yenilenmesini otomatikleştirerek **ücretsiz, kalıcı olarak güvenli HTTPS** sağlamaktır.\n\n## Geliştiriciler İçin HTTPS { #https-for-developers }\n\nBurada, bir HTTPS API’nin adım adım nasıl görünebileceğine dair, özellikle geliştiriciler için önemli fikirlere odaklanan bir örnek var.\n\n### Domain Adı { #domain-name }\n\nMuhtemelen her şey, bir **domain adı** **temin etmenizle** başlar. Sonra bunu bir DNS server’ında (muhtemelen aynı cloud provider’ınızda) yapılandırırsınız.\n\nMuhtemelen bir cloud server (virtual machine) ya da benzeri bir şey alırsınız ve bunun <dfn title=\"Zamanla değişmeyen. Dinamik olmayan.\">sabit</dfn> bir **public IP adresi** olur.\n\nDNS server(lar)ında, bir kaydı (\"`A record`\") **domain**’inizi server’ınızın **public IP adresine** yönlendirecek şekilde yapılandırırsınız.\n\nBunu büyük olasılıkla ilk kurulumda, sadece bir kez yaparsınız.\n\n/// tip | İpucu\n\nBu Domain Adı kısmı HTTPS’ten çok daha önce gelir. Ancak her şey domain ve IP adresine bağlı olduğu için burada bahsetmeye değer.\n\n///\n\n### DNS { #dns }\n\nŞimdi gerçek HTTPS parçalarına odaklanalım.\n\nÖnce tarayıcı, bu örnekte `someapp.example.com` olan domain için **IP**’nin ne olduğunu **DNS server**’larına sorar.\n\nDNS server’ları tarayıcıya belirli bir **IP adresini** kullanmasını söyler. Bu, DNS server’larında yapılandırdığınız ve server’ınızın kullandığı public IP adresidir.\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### TLS Handshake Başlangıcı { #tls-handshake-start }\n\nTarayıcı daha sonra bu IP adresiyle **443 portu** (HTTPS portu) üzerinden iletişim kurar.\n\nİletişimin ilk kısmı, client ile server arasında bağlantıyı kurmak ve hangi kriptografik anahtarların kullanılacağına karar vermek vb. içindir.\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\nClient ile server arasındaki, TLS bağlantısını kurmaya yönelik bu etkileşime **TLS handshake** denir.\n\n### SNI Extension’ı ile TLS { #tls-with-sni-extension }\n\nServer’da, belirli bir **IP adresindeki** belirli bir **portu** dinleyen **yalnızca bir process** olabilir. Aynı IP adresinde başka portları dinleyen başka process’ler olabilir, ancak IP+port kombinasyonu başına yalnızca bir tane olur.\n\nTLS (HTTPS) varsayılan olarak `443` portunu kullanır. Yani ihtiyaç duyacağımız port budur.\n\nBu portu yalnızca bir process dinleyebileceği için, bunu yapacak process **TLS Termination Proxy** olur.\n\nTLS Termination Proxy, bir ya da daha fazla **TLS sertifikasına** (HTTPS sertifikası) erişebilir.\n\nYukarıda bahsettiğimiz **SNI extension**’ını kullanarak TLS Termination Proxy, bu bağlantı için elindeki TLS (HTTPS) sertifikalarından hangisini kullanacağını kontrol eder; client’ın beklediği domain ile eşleşen sertifikayı seçer.\n\nBu örnekte `someapp.example.com` sertifikasını kullanır.\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\nClient, bu TLS sertifikasını üreten kuruluşa zaten **güvenir** (bu örnekte Let's Encrypt; birazdan ona da geleceğiz). Bu sayede sertifikanın geçerli olduğunu **doğrulayabilir**.\n\nArdından client ve TLS Termination Proxy, sertifikayı kullanarak **TCP iletişiminin geri kalanını nasıl şifreleyeceklerine** karar verir. Böylece **TLS Handshake** kısmı tamamlanır.\n\nBundan sonra client ve server arasında **şifreli bir TCP bağlantısı** vardır; TLS’in sağladığı şey budur. Sonra bu bağlantıyı kullanarak gerçek **HTTP iletişimini** başlatabilirler.\n\nVe **HTTPS** de tam olarak budur: şifrelenmemiş bir TCP bağlantısı yerine, **güvenli bir TLS bağlantısının içinde** düz **HTTP**’dir.\n\n/// tip | İpucu\n\nŞifrelemenin HTTP seviyesinde değil, **TCP seviyesinde** gerçekleştiğine dikkat edin.\n\n///\n\n### HTTPS Request { #https-request }\n\nArtık client ile server (özellikle tarayıcı ile TLS Termination Proxy) arasında **şifreli bir TCP bağlantısı** olduğuna göre, **HTTP iletişimi** başlayabilir.\n\nDolayısıyla client bir **HTTPS request** gönderir. Bu, şifreli bir TLS bağlantısı üzerinden giden bir HTTP request’tir.\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### Request’in Şifresini Çözme { #decrypt-the-request }\n\nTLS Termination Proxy, üzerinde anlaşılan şifrelemeyi kullanarak **request’in şifresini çözer** ve **düz (şifresi çözülmüş) HTTP request**’i uygulamayı çalıştıran process’e iletir (ör. FastAPI uygulamasını çalıştıran Uvicorn process’i).\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### HTTP Response { #http-response }\n\nUygulama request’i işler ve TLS Termination Proxy’ye **düz (şifrelenmemiş) bir HTTP response** gönderir.\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### HTTPS Response { #https-response }\n\nTLS Termination Proxy daha sonra response’u, daha önce üzerinde anlaşılan kriptografi ile (başlangıcı `someapp.example.com` sertifikasına dayanan) **şifreler** ve tarayıcıya geri gönderir.\n\nSonrasında tarayıcı response’un geçerli olduğunu ve doğru kriptografik anahtarla şifrelendiğini doğrular vb. Ardından **response’un şifresini çözer** ve işler.\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\nClient (tarayıcı), response’un doğru server’dan geldiğini bilir; çünkü daha önce **HTTPS sertifikası** ile üzerinde anlaştıkları kriptografiyi kullanmaktadır.\n\n### Birden Fazla Uygulama { #multiple-applications }\n\nAynı server’da (veya server’larda) örneğin başka API programları ya da bir veritabanı gibi **birden fazla uygulama** olabilir.\n\nBelirli IP ve port kombinasyonunu yalnızca bir process yönetebilir (örneğimizde TLS Termination Proxy). Ancak diğer uygulamalar/process’ler, aynı **public IP + port kombinasyonunu** kullanmaya çalışmadıkları sürece server(lar)da çalışabilir.\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\nBu şekilde TLS Termination Proxy, birden fazla uygulama için **birden fazla domain**’in HTTPS ve sertifika işlerini yönetebilir ve her durumda request’leri doğru uygulamaya iletebilir.\n\n### Sertifika Yenileme { #certificate-renewal }\n\nGelecekte bir noktada, her sertifikanın süresi **dolar** (temin edildikten yaklaşık 3 ay sonra).\n\nArdından başka bir program (bazı durumlarda ayrı bir programdır, bazı durumlarda aynı TLS Termination Proxy olabilir) Let's Encrypt ile konuşup sertifika(ları) yeniler.\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\n**TLS sertifikaları** bir IP adresiyle değil, **domain adıyla ilişkilidir**.\n\nBu yüzden sertifikaları yenilemek için, yenileme programı otoriteye (Let's Encrypt) gerçekten o domain’i **\"sahiplendiğini\" ve kontrol ettiğini** **kanıtlamalıdır**.\n\nBunu yapmak ve farklı uygulama ihtiyaçlarını karşılamak için birden fazla yöntem vardır. Yaygın yöntemlerden bazıları:\n\n* Bazı **DNS kayıtlarını değiştirmek**.\n    * Bunun için yenileme programının DNS provider API’lerini desteklemesi gerekir. Dolayısıyla kullandığınız DNS provider’a bağlı olarak bu seçenek mümkün de olabilir, olmayabilir de.\n* Domain ile ilişkili public IP adresinde **server olarak çalışmak** (en azından sertifika temin sürecinde).\n    * Yukarıda söylediğimiz gibi, belirli bir IP ve portu yalnızca bir process dinleyebilir.\n    * Bu, aynı TLS Termination Proxy’nin sertifika yenileme sürecini de yönetmesinin neden çok faydalı olduğunun sebeplerinden biridir.\n    * Aksi halde TLS Termination Proxy’yi kısa süreliğine durdurmanız, sertifikaları temin etmek için yenileme programını başlatmanız, sonra bunları TLS Termination Proxy ile yapılandırmanız ve ardından TLS Termination Proxy’yi tekrar başlatmanız gerekebilir. Bu ideal değildir; çünkü TLS Termination Proxy kapalıyken uygulama(lar)ınıza erişilemez.\n\nUygulamayı servis etmeye devam ederken tüm bu yenileme sürecini yönetebilmek, TLS sertifikalarını doğrudan uygulama server’ıyla (örn. Uvicorn) kullanmak yerine, TLS Termination Proxy ile HTTPS’i yönetecek **ayrı bir sistem** istemenizin başlıca nedenlerinden biridir.\n\n## Proxy Forwarded Headers { #proxy-forwarded-headers }\n\nHTTPS’i bir proxy ile yönetirken, **application server**’ınız (örneğin FastAPI CLI üzerinden Uvicorn) HTTPS süreci hakkında hiçbir şey bilmez; **TLS Termination Proxy** ile düz HTTP üzerinden iletişim kurar.\n\nBu **proxy** normalde request’i **application server**’a iletmeden önce, request’in proxy tarafından **forward** edildiğini application server’a bildirmek için bazı HTTP header’larını anlık olarak ekler.\n\n/// note | Teknik Detaylar\n\nProxy header’ları şunlardır:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\nBuna rağmen **application server**, güvenilen bir **proxy** arkasında olduğunu bilmediği için varsayılan olarak bu header’lara güvenmez.\n\nAncak **application server**’ı, **proxy**’nin gönderdiği *forwarded* header’larına güvenecek şekilde yapılandırabilirsiniz. FastAPI CLI kullanıyorsanız, hangi IP’lerden gelen *forwarded* header’lara güvenmesi gerektiğini söylemek için *CLI Option* `--forwarded-allow-ips` seçeneğini kullanabilirsiniz.\n\nÖrneğin **application server** yalnızca güvenilen **proxy**’den iletişim alıyorsa, yalnızca **proxy**’nin kullandığı IP’den request alacağı için `--forwarded-allow-ips=\"*\"` ayarlayıp gelen tüm IP’lere güvenmesini sağlayabilirsiniz.\n\nBu sayede uygulama kendi public URL’inin ne olduğunu, HTTPS kullanıp kullanmadığını, domain’i vb. bilebilir.\n\nBu, örneğin redirect’leri doğru şekilde yönetmek için faydalıdır.\n\n/// tip | İpucu\n\nBununla ilgili daha fazlasını [Bir Proxy Arkasında - Proxy Forwarded Headers'ı Etkinleştir](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers) dokümantasyonunda öğrenebilirsiniz.\n\n///\n\n## Özet { #recap }\n\n**HTTPS** kullanmak çok önemlidir ve çoğu durumda oldukça **kritiktir**. Geliştirici olarak HTTPS etrafında harcadığınız çabanın büyük kısmı, aslında **bu kavramları** ve nasıl çalıştıklarını **anlamaktır**.\n\nAncak **geliştiriciler için HTTPS**’in temel bilgilerini öğrendikten sonra, her şeyi basitçe yönetmek için farklı araçları kolayca birleştirip yapılandırabilirsiniz.\n\nSonraki bölümlerin bazılarında, **FastAPI** uygulamaları için **HTTPS**’i nasıl kuracağınıza dair birkaç somut örnek göstereceğim. 🔒\n"
  },
  {
    "path": "docs/tr/docs/deployment/index.md",
    "content": "# Dağıtım { #deployment }\n\n**FastAPI** uygulamasını deploy etmek nispeten kolaydır.\n\n## Dağıtım Ne Anlama Gelir? { #what-does-deployment-mean }\n\nBir uygulamayı **deploy** etmek, onu **kullanıcılara erişilebilir hale getirmek** için gerekli adımları gerçekleştirmek anlamına gelir.\n\nBir **web API** için bu süreç normalde uygulamayı **uzak bir makineye** yerleştirmeyi, iyi performans, kararlılık vb. özellikler sağlayan bir **sunucu programı** ile **kullanıcılarınızın** uygulamaya etkili ve kesintisiz bir şekilde, sorun yaşamadan **erişebilmesini** kapsar.\n\nBu, kodu sürekli olarak değiştirdiğiniz, bozup düzelttiğiniz, geliştirme sunucusunu durdurup yeniden başlattığınız vb. **geliştirme** aşamalarının tam tersidir.\n\n## Dağıtım Stratejileri { #deployment-strategies }\n\nKullanım durumunuza ve kullandığınız araçlara bağlı olarak bunu yapmanın birkaç yolu vardır.\n\nBir dizi araç kombinasyonunu kullanarak kendiniz **bir sunucu deploy edebilirsiniz**, yayınlama sürecinin bir kısmını sizin için gerçekleştiren bir **bulut hizmeti** veya diğer olası seçenekleri kullanabilirsiniz.\n\nÖrneğin, FastAPI'nin arkasındaki ekip olarak, FastAPI uygulamalarını buluta mümkün olduğunca akıcı şekilde deploy etmeyi sağlamak için, FastAPI ile çalışmanın aynı geliştirici deneyimini sunarak [**FastAPI Cloud**](https://fastapicloud.com)'u oluşturduk.\n\n**FastAPI** uygulamasını yayınlarken aklınızda bulundurmanız gereken ana kavramlardan bazılarını size göstereceğim (ancak bunların çoğu diğer web uygulamaları için de geçerlidir).\n\nSonraki bölümlerde akılda tutulması gereken diğer ayrıntıları ve bunu yapmaya yönelik bazı teknikleri göreceksiniz. ✨\n"
  },
  {
    "path": "docs/tr/docs/deployment/manually.md",
    "content": "# Bir Sunucuyu Manuel Olarak Çalıştırın { #run-a-server-manually }\n\n## `fastapi run` Komutunu Kullanın { #use-the-fastapi-run-command }\n\nKısacası, FastAPI uygulamanızı sunmak için `fastapi run` kullanın:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\nBu, çoğu durumda işinizi görür. 😎\n\nÖrneğin bu komutu, **FastAPI** app'inizi bir container içinde, bir sunucuda vb. başlatmak için kullanabilirsiniz.\n\n## ASGI Sunucuları { #asgi-servers }\n\nŞimdi biraz daha detaya inelim.\n\nFastAPI, Python web framework'leri ve sunucularını inşa etmek için kullanılan <abbr title=\"Asynchronous Server Gateway Interface - Asenkron Sunucu Ağ Geçidi Arayüzü\">ASGI</abbr> adlı bir standardı kullanır. FastAPI bir ASGI web framework'üdür.\n\nUzak bir sunucu makinesinde **FastAPI** uygulamasını (veya herhangi bir ASGI uygulamasını) çalıştırmak için gereken ana şey, **Uvicorn** gibi bir ASGI server programıdır. `fastapi` komutuyla varsayılan olarak gelen de budur.\n\nBuna alternatif birkaç seçenek daha vardır, örneğin:\n\n* [Uvicorn](https://www.uvicorn.dev/): yüksek performanslı bir ASGI server.\n* [Hypercorn](https://hypercorn.readthedocs.io/): diğer özelliklerin yanında HTTP/2 ve Trio ile uyumlu bir ASGI server.\n* [Daphne](https://github.com/django/daphne): Django Channels için geliştirilmiş ASGI server.\n* [Granian](https://github.com/emmett-framework/granian): Python uygulamaları için bir Rust HTTP server.\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit, hafif ve çok yönlü bir web uygulaması runtime'ıdır.\n\n## Sunucu Makinesi ve Sunucu Programı { #server-machine-and-server-program }\n\nİsimlendirme konusunda akılda tutulması gereken küçük bir detay var. 💡\n\n\"**server**\" kelimesi yaygın olarak hem uzak/bulut bilgisayarı (fiziksel veya sanal makine) hem de o makinede çalışan programı (ör. Uvicorn) ifade etmek için kullanılır.\n\nDolayısıyla genel olarak \"server\" dendiğinde, bu iki şeyden birini kast ediyor olabilir.\n\nUzak makineden bahsederken genelde **server** denir; ayrıca **machine**, **VM** (virtual machine), **node** ifadeleri de kullanılır. Bunların hepsi, genellikle Linux çalıştıran ve üzerinde programlarınızı çalıştırdığınız bir tür uzak makineyi ifade eder.\n\n## Sunucu Programını Yükleyin { #install-the-server-program }\n\nFastAPI'yi kurduğunuzda, production sunucusu olarak Uvicorn da beraberinde gelir ve bunu `fastapi run` komutuyla başlatabilirsiniz.\n\nAncak bir ASGI server'ı manuel olarak da kurabilirsiniz.\n\nBir [sanal ortam](../virtual-environments.md) oluşturduğunuzdan, etkinleştirdiğinizden emin olun; ardından server uygulamasını kurabilirsiniz.\n\nÖrneğin Uvicorn'u kurmak için:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\nBenzer bir süreç, diğer ASGI server programlarının tamamı için de geçerlidir.\n\n/// tip | İpucu\n\n`standard` eklediğinizde Uvicorn, önerilen bazı ek bağımlılıkları kurar ve kullanır.\n\nBunlara, `asyncio` için yüksek performanslı bir drop-in replacement olan ve concurrency performansını ciddi şekilde artıran `uvloop` da dahildir.\n\nFastAPI'yi `pip install \"fastapi[standard]\"` gibi bir şekilde kurduğunuzda `uvicorn[standard]` da zaten kurulmuş olur.\n\n///\n\n## Sunucu Programını Çalıştırın { #run-the-server-program }\n\nBir ASGI server'ı manuel olarak kurduysanız, FastAPI uygulamanızı import edebilmesi için genellikle özel bir formatta bir import string geçirmeniz gerekir:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note | Not\n\n`uvicorn main:app` komutu şunları ifade eder:\n\n* `main`: `main.py` dosyası (Python \"module\").\n* `app`: `main.py` içinde `app = FastAPI()` satırıyla oluşturulan nesne.\n\nŞununla eşdeğerdir:\n\n```Python\nfrom main import app\n```\n\n///\n\nHer alternatif ASGI server programı için benzer bir komut bulunur; daha fazlası için ilgili dokümantasyonlarına bakabilirsiniz.\n\n/// warning | Uyarı\n\nUvicorn ve diğer sunucular, geliştirme sırasında faydalı olan `--reload` seçeneğini destekler.\n\n`--reload` seçeneği çok daha fazla kaynak tüketir, daha kararsızdır vb.\n\n**Geliştirme** sırasında çok yardımcı olur, ancak **production** ortamında kullanmamalısınız.\n\n///\n\n## Deployment Kavramları { #deployment-concepts }\n\nBu örnekler server programını (ör. Uvicorn) çalıştırır; **tek bir process** başlatır, tüm IP'lerde (`0.0.0.0`) ve önceden belirlenmiş bir port'ta (ör. `80`) dinler.\n\nTemel fikir budur. Ancak muhtemelen şunlar gibi bazı ek konularla da ilgilenmek isteyeceksiniz:\n\n* Güvenlik - HTTPS\n* Açılışta çalıştırma\n* Yeniden başlatmalar\n* Replikasyon (çalışan process sayısı)\n* Bellek\n* Başlatmadan önceki adımlar\n\nSonraki bölümlerde bu kavramların her birini nasıl düşünmeniz gerektiğini ve bunlarla başa çıkmak için kullanabileceğiniz somut örnekleri/stratejileri anlatacağım. 🚀\n"
  },
  {
    "path": "docs/tr/docs/deployment/server-workers.md",
    "content": "# Server Workers - Worker'larla Uvicorn { #server-workers-uvicorn-with-workers }\n\nÖnceki bölümlerde bahsettiğimiz deployment kavramlarına tekrar bakalım:\n\n* Güvenlik - HTTPS\n* Başlangıçta çalıştırma\n* Yeniden başlatmalar\n* **Replikasyon (çalışan process sayısı)**\n* Bellek\n* Başlatmadan önceki adımlar\n\nBu noktaya kadar, dokümantasyondaki tüm tutorial'larla muhtemelen bir server programı çalıştırıyordunuz; örneğin Uvicorn'u çalıştıran `fastapi` komutunu kullanarak ve tek bir process ile.\n\nUygulamaları deploy ederken, çok çekirdekten (multiple cores) faydalanmak ve daha fazla request'i karşılayabilmek için büyük olasılıkla process replikasyonu (birden fazla process) isteyeceksiniz.\n\n[Daha önceki Deployment Concepts](concepts.md) bölümünde gördüğünüz gibi, kullanabileceğiniz birden fazla strateji var.\n\nBurada, `fastapi` komutunu kullanarak ya da `uvicorn` komutunu doğrudan çalıştırarak worker process'lerle Uvicorn'u nasıl kullanacağınızı göstereceğim.\n\n/// info | Bilgi\n\nContainer kullanıyorsanız (örneğin Docker veya Kubernetes ile), bununla ilgili daha fazlasını bir sonraki bölümde anlatacağım: [Container'larda FastAPI - Docker](docker.md).\n\nÖzellikle Kubernetes üzerinde çalıştırırken, büyük olasılıkla worker kullanmak istemeyeceksiniz; bunun yerine container başına tek bir Uvicorn process çalıştırmak daha uygundur. Ancak bunu da o bölümde detaylandıracağım.\n\n///\n\n## Birden Fazla Worker { #multiple-workers }\n\nKomut satırında `--workers` seçeneğiyle birden fazla worker başlatabilirsiniz:\n\n//// tab | `fastapi`\n\n`fastapi` komutunu kullanıyorsanız:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\n`uvicorn` komutunu doğrudan kullanmayı tercih ederseniz:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\nBuradaki tek yeni seçenek `--workers`; bu seçenek Uvicorn'a 4 adet worker process başlatmasını söyler.\n\nAyrıca her process'in PID'inin gösterildiğini de görebilirsiniz: parent process için `27365` (bu process manager), her worker process için de bir PID: `27368`, `27369`, `27370` ve `27367`.\n\n## Deployment Kavramları { #deployment-concepts }\n\nBurada, uygulamanın çalışmasını paralelleştirmek, CPU'daki çok çekirdekten yararlanmak ve daha fazla request karşılayabilmek için birden fazla worker'ı nasıl kullanacağınızı gördünüz.\n\nYukarıdaki deployment kavramları listesinden, worker kullanımı ağırlıklı olarak replikasyon kısmına yardımcı olur, ayrıca yeniden başlatmalar konusunda da az da olsa katkı sağlar. Ancak diğerlerini yine sizin yönetmeniz gerekir:\n\n* **Güvenlik - HTTPS**\n* **Başlangıçta çalıştırma**\n* ***Yeniden başlatmalar***\n* Replikasyon (çalışan process sayısı)\n* **Bellek**\n* **Başlatmadan önceki adımlar**\n\n## Container'lar ve Docker { #containers-and-docker }\n\nBir sonraki bölümde, [Container'larda FastAPI - Docker](docker.md) üzerinden diğer deployment kavramlarını ele almak için kullanabileceğiniz bazı stratejileri anlatacağım.\n\nTek bir Uvicorn process çalıştıracak şekilde sıfırdan kendi image'ınızı oluşturmayı göstereceğim. Bu oldukça basit bir süreçtir ve Kubernetes gibi dağıtık bir container yönetim sistemi kullanırken büyük olasılıkla yapmak isteyeceğiniz şey de budur.\n\n## Özet { #recap }\n\nÇok çekirdekli CPU'lardan faydalanmak ve birden fazla process'i paralel çalıştırmak için `fastapi` veya `uvicorn` komutlarıyla `--workers` CLI seçeneğini kullanarak birden fazla worker process çalıştırabilirsiniz.\n\nDiğer deployment kavramlarını da kendiniz ele alarak kendi deployment sisteminizi kuruyorsanız, bu araçları ve fikirleri kullanabilirsiniz.\n\nContainer'larla (örn. Docker ve Kubernetes) FastAPI'yi öğrenmek için bir sonraki bölüme göz atın. Bu araçların, diğer deployment kavramlarını çözmek için de basit yöntemleri olduğunu göreceksiniz. ✨\n"
  },
  {
    "path": "docs/tr/docs/deployment/versions.md",
    "content": "# FastAPI Sürümleri Hakkında { #about-fastapi-versions }\n\n**FastAPI** hâlihazırda birçok uygulama ve sistemde production ortamında kullanılmaktadır. Ayrıca test kapsamı %100 seviyesinde tutulmaktadır. Ancak geliştirme süreci hâlâ hızlı şekilde ilerlemektedir.\n\nYeni özellikler sık sık eklenir, bug'lar düzenli olarak düzeltilir ve kod sürekli iyileştirilmektedir.\n\nBu yüzden mevcut sürümler hâlâ `0.x.x` şeklindedir; bu da her sürümde breaking change olma ihtimalini yansıtır. Bu yaklaşım [Anlamsal Sürümleme](https://semver.org/) kurallarını takip eder.\n\nŞu anda **FastAPI** ile production uygulamaları geliştirebilirsiniz (muhtemelen bir süredir yapıyorsunuz da); sadece kodunuzun geri kalanıyla doğru çalışan bir sürüm kullandığınızdan emin olmanız gerekir.\n\n## `fastapi` sürümünü sabitleyin { #pin-your-fastapi-version }\n\nİlk yapmanız gereken, kullandığınız **FastAPI** sürümünü uygulamanızla doğru çalıştığını bildiğiniz belirli bir güncel sürüme \"sabitlemek\" (pinlemek) olmalı.\n\nÖrneğin, uygulamanızda `0.112.0` sürümünü kullandığınızı varsayalım.\n\n`requirements.txt` dosyası kullanıyorsanız sürümü şöyle belirtebilirsiniz:\n\n```txt\nfastapi[standard]==0.112.0\n```\n\nBu, tam olarak `0.112.0` sürümünü kullanacağınız anlamına gelir.\n\nYa da şu şekilde de sabitleyebilirsiniz:\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\nBu da `0.112.0` ve üzeri, ama `0.113.0` altındaki sürümleri kullanacağınız anlamına gelir; örneğin `0.112.2` gibi bir sürüm de kabul edilir.\n\nKurulumları yönetmek için `uv`, Poetry, Pipenv gibi başka bir araç (veya benzerleri) kullanıyorsanız, bunların hepsinde paketler için belirli sürümler tanımlamanın bir yolu vardır.\n\n## Mevcut sürümler { #available-versions }\n\nMevcut sürümleri (ör. en güncel son sürümün hangisi olduğunu kontrol etmek için) [Sürüm Notları](../release-notes.md) sayfasında görebilirsiniz.\n\n## Sürümler Hakkında { #about-versions }\n\nSemantic Versioning kurallarına göre, `1.0.0` altındaki herhangi bir sürüm breaking change içerebilir.\n\nFastAPI ayrıca \"PATCH\" sürüm değişikliklerinin bug fix'ler ve breaking olmayan değişiklikler için kullanılması kuralını da takip eder.\n\n/// tip | İpucu\n\n\"PATCH\" son sayıdır. Örneğin `0.2.3` içinde PATCH sürümü `3`'tür.\n\n///\n\nDolayısıyla şu şekilde bir sürüme sabitleyebilmelisiniz:\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\nBreaking change'ler ve yeni özellikler \"MINOR\" sürümlerde eklenir.\n\n/// tip | İpucu\n\n\"MINOR\" ortadaki sayıdır. Örneğin `0.2.3` içinde MINOR sürümü `2`'dir.\n\n///\n\n## FastAPI Sürümlerini Yükseltme { #upgrading-the-fastapi-versions }\n\nUygulamanız için test'ler eklemelisiniz.\n\n**FastAPI** ile bu çok kolaydır (Starlette sayesinde). Dokümantasyona bakın: [Testler](../tutorial/testing.md)\n\nTest'leriniz olduktan sonra **FastAPI** sürümünü daha yeni bir sürüme yükseltebilir ve test'lerinizi çalıştırarak tüm kodunuzun doğru çalıştığından emin olabilirsiniz.\n\nHer şey çalışıyorsa (ya da gerekli değişiklikleri yaptıktan sonra) ve tüm test'leriniz geçiyorsa, `fastapi` sürümünü o yeni sürüme sabitleyebilirsiniz.\n\n## Starlette Hakkında { #about-starlette }\n\n`starlette` sürümünü sabitlememelisiniz.\n\n**FastAPI**'nin farklı sürümleri, Starlette'in belirli (daha yeni) bir sürümünü kullanır.\n\nBu yüzden **FastAPI**'nin doğru Starlette sürümünü kullanmasına izin verebilirsiniz.\n\n## Pydantic Hakkında { #about-pydantic }\n\nPydantic, **FastAPI** için olan test'leri kendi test'lerinin içine dahil eder; bu yüzden Pydantic'in yeni sürümleri (`1.0.0` üzeri) her zaman FastAPI ile uyumludur.\n\nPydantic'i sizin için çalışan `1.0.0` üzerindeki herhangi bir sürüme sabitleyebilirsiniz.\n\nÖrneğin:\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/tr/docs/editor-support.md",
    "content": "# Editör Desteği { #editor-support }\n\nResmi [FastAPI Extension](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode), FastAPI geliştirme akışınızı iyileştirir: *path operation* keşfi, gezinme, FastAPI Cloud’a deploy ve canlı log akışı.\n\nDaha fazla ayrıntı için, GitHub deposundaki README’ye bakın: [GitHub repository](https://github.com/fastapi/fastapi-vscode).\n\n## Kurulum ve Yükleme { #setup-and-installation }\n\n**FastAPI Extension**, hem [VS Code](https://code.visualstudio.com/) hem de [Cursor](https://www.cursor.com/) için mevcuttur. Her editörde Extensions panelinden \"FastAPI\" aratıp **FastAPI Labs** tarafından yayımlanan eklentiyi seçerek doğrudan kurabilirsiniz. Eklenti [vscode.dev](https://vscode.dev) ve [github.dev](https://github.dev) gibi tarayıcı tabanlı editörlerde de çalışır.\n\n### Uygulama Keşfi { #application-discovery }\n\nVarsayılan olarak, eklenti çalışma alanınızda `FastAPI()` örnekleyen dosyaları tarayarak FastAPI uygulamalarını otomatik olarak keşfeder. Proje yapınız nedeniyle otomatik algılama çalışmazsa, `pyproject.toml` içindeki `[tool.fastapi]` ile veya VS Code ayarı `fastapi.entryPoint` üzerinden modül gösterimiyle (ör. `myapp.main:app`) bir entrypoint belirtebilirsiniz.\n\n## Özellikler { #features }\n\n- **Path Operation Explorer** - Uygulamanızdaki tüm <dfn title=\"route'lar, endpoint'ler\">*path operation*'lar</dfn> için yan panelde bir ağaç görünümü. Herhangi bir route veya router tanımına tıklayarak atlayın.\n- **Route Search** - <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>) ile path, method veya ada göre arama.\n- **CodeLens Navigation** - Test client çağrılarının (ör. `client.get('/items')`) üzerinde, ilgili *path operation*’a atlayan tıklanabilir bağlantılar; testlerle implementasyon arasında hızlı gezinme sağlar.\n- **Deploy to FastAPI Cloud** - Uygulamanızı tek tıkla [FastAPI Cloud](https://fastapicloud.com/)'a deploy edin.\n- **Stream Application Logs** - FastAPI Cloud’a deploy ettiğiniz uygulamadan, seviye filtreleme ve metin arama ile gerçek zamanlı log akışı.\n\nEklentinin özelliklerine hızlıca aşina olmak isterseniz, Komut Paleti’ni açın (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> veya macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>), \"Welcome: Open walkthrough...\" öğesini seçin ve ardından \"Get started with FastAPI\" walkthrough’unu açın.\n"
  },
  {
    "path": "docs/tr/docs/environment-variables.md",
    "content": "# Ortam Değişkenleri { #environment-variables }\n\n/// tip | İpucu\n\n\"Ortam değişkenleri\"nin ne olduğunu ve nasıl kullanılacağını zaten biliyorsanız, bu bölümü atlayabilirsiniz.\n\n///\n\nOrtam değişkeni (genelde \"**env var**\" olarak da anılır), Python kodunun **dışında**, **işletim sistemi** seviyesinde bulunan ve Python kodunuz (veya diğer programlar) tarafından okunabilen bir değişkendir.\n\nOrtam değişkenleri; uygulama **ayarları**nı yönetmek, Python’un **kurulumu**nun bir parçası olarak konfigürasyon yapmak vb. durumlarda işe yarar.\n\n## Env Var Oluşturma ve Kullanma { #create-and-use-env-vars }\n\nPython’a ihtiyaç duymadan, **shell (terminal)** içinde ortam değişkenleri **oluşturabilir** ve kullanabilirsiniz:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// You could create an env var MY_NAME with\n$ export MY_NAME=\"Wade Wilson\"\n\n// Then you could use it with other programs, like\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Create an env var MY_NAME\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Use it with other programs, like\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## Python’da Env Var Okuma { #read-env-vars-in-python }\n\nOrtam değişkenlerini Python’un **dışında** (terminalde veya başka bir yöntemle) oluşturup daha sonra **Python’da okuyabilirsiniz**.\n\nÖrneğin `main.py` adında bir dosyanız şöyle olabilir:\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip | İpucu\n\n[`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) fonksiyonunun ikinci argümanı, bulunamadığında döndürülecek varsayılan (default) değerdir.\n\nVerilmezse varsayılan olarak `None` olur; burada varsayılan değer olarak `\"World\"` verdik.\n\n///\n\nSonrasında bu Python programını çalıştırabilirsiniz:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Here we don't set the env var yet\n$ python main.py\n\n// As we didn't set the env var, we get the default value\n\nHello World from Python\n\n// But if we create an environment variable first\n$ export MY_NAME=\"Wade Wilson\"\n\n// And then call the program again\n$ python main.py\n\n// Now it can read the environment variable\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Here we don't set the env var yet\n$ python main.py\n\n// As we didn't set the env var, we get the default value\n\nHello World from Python\n\n// But if we create an environment variable first\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// And then call the program again\n$ python main.py\n\n// Now it can read the environment variable\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\nOrtam değişkenleri kodun dışında ayarlanabildiği, ama kod tarafından okunabildiği ve dosyalarla birlikte saklanmasının (ör. `git`’e commit edilmesinin) gerekmediği için, konfigürasyon veya **ayarlar** için sıkça kullanılır.\n\nAyrıca, bir ortam değişkenini yalnızca **belirli bir program çalıştırımı** için oluşturabilirsiniz; bu değişken sadece o program tarafından, sadece o çalıştırma süresince kullanılabilir.\n\nBunu yapmak için, program komutunun hemen öncesinde ve aynı satırda tanımlayın:\n\n<div class=\"termy\">\n\n```console\n// Create an env var MY_NAME in line for this program call\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// Now it can read the environment variable\n\nHello Wade Wilson from Python\n\n// The env var no longer exists afterwards\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip | İpucu\n\nBu konuyla ilgili daha fazlasını [Twelve-Factor Uygulaması: Config](https://12factor.net/config) bölümünde okuyabilirsiniz.\n\n///\n\n## Türler ve Doğrulama { #types-and-validation }\n\nBu ortam değişkenleri yalnızca **metin string**’lerini taşıyabilir. Çünkü Python’un dışındadırlar ve diğer programlarla, sistemin geri kalanıyla (hatta Linux, Windows, macOS gibi farklı işletim sistemleriyle) uyumlu olmak zorundadırlar.\n\nBu, Python’da bir ortam değişkeninden okunan **her değerin `str` olacağı** anlamına gelir. Farklı bir tipe dönüştürme veya doğrulama işlemleri kod içinde yapılmalıdır.\n\nUygulama **ayarları**nı yönetmek için ortam değişkenlerini kullanmayı, [İleri Seviye Kullanıcı Rehberi - Ayarlar ve Ortam Değişkenleri](./advanced/settings.md) bölümünde daha detaylı öğreneceksiniz.\n\n## `PATH` Ortam Değişkeni { #path-environment-variable }\n\nİşletim sistemlerinin (Linux, macOS, Windows) çalıştırılacak programları bulmak için kullandığı **özel** bir ortam değişkeni vardır: **`PATH`**.\n\n`PATH` değişkeninin değeri uzun bir string’dir; Linux ve macOS’te dizinler iki nokta üst üste `:` ile, Windows’ta ise noktalı virgül `;` ile ayrılır.\n\nÖrneğin `PATH` ortam değişkeni şöyle görünebilir:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nBu, sistemin şu dizinlerde program araması gerektiği anlamına gelir:\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\nBu, sistemin şu dizinlerde program araması gerektiği anlamına gelir:\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\nTerminalde bir **komut** yazdığınızda, işletim sistemi `PATH` ortam değişkeninde listelenen **bu dizinlerin her birinde** programı **arar**.\n\nÖrneğin terminalde `python` yazdığınızda, işletim sistemi bu listedeki **ilk dizinde** `python` adlı bir program arar.\n\nBulursa **onu kullanır**. Bulamazsa **diğer dizinlerde** aramaya devam eder.\n\n### Python Kurulumu ve `PATH`’in Güncellenmesi { #installing-python-and-updating-the-path }\n\nPython’u kurarken, `PATH` ortam değişkenini güncellemek isteyip istemediğiniz sorulabilir.\n\n//// tab | Linux, macOS\n\nDiyelim ki Python’u kurdunuz ve `/opt/custompython/bin` dizinine yüklendi.\n\n`PATH` ortam değişkenini güncellemeyi seçerseniz, kurulum aracı `/opt/custompython/bin` yolunu `PATH` ortam değişkenine ekler.\n\nŞöyle görünebilir:\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\nBöylece terminalde `python` yazdığınızda, sistem `/opt/custompython/bin` (son dizin) içindeki Python programını bulur ve onu kullanır.\n\n////\n\n//// tab | Windows\n\nDiyelim ki Python’u kurdunuz ve `C:\\opt\\custompython\\bin` dizinine yüklendi.\n\n`PATH` ortam değişkenini güncellemeyi seçerseniz, kurulum aracı `C:\\opt\\custompython\\bin` yolunu `PATH` ortam değişkenine ekler.\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\nBöylece terminalde `python` yazdığınızda, sistem `C:\\opt\\custompython\\bin` (son dizin) içindeki Python programını bulur ve onu kullanır.\n\n////\n\nYani şunu yazarsanız:\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\nSistem `python` programını `/opt/custompython/bin` içinde **bulur** ve çalıştırır.\n\nBu, kabaca şunu yazmaya denktir:\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\nSistem `python` programını `C:\\opt\\custompython\\bin\\python` içinde **bulur** ve çalıştırır.\n\nBu, kabaca şunu yazmaya denktir:\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\nBu bilgiler, [Sanal Ortamlar](virtual-environments.md) konusunu öğrenirken işinize yarayacak.\n\n## Sonuç { #conclusion }\n\nBuraya kadar **ortam değişkenleri**nin ne olduğuna ve Python’da nasıl kullanılacağına dair temel bir fikir edinmiş olmalısınız.\n\nAyrıca [Ortam Değişkeni için Wikipedia](https://en.wikipedia.org/wiki/Environment_variable) sayfasından daha fazlasını da okuyabilirsiniz.\n\nÇoğu zaman ortam değişkenlerinin hemen nasıl işe yarayacağı ilk bakışta çok net olmayabilir. Ancak geliştirme yaparken birçok farklı senaryoda tekrar tekrar karşınıza çıkarlar; bu yüzden bunları bilmek faydalıdır.\n\nÖrneğin bir sonraki bölümde, [Sanal Ortamlar](virtual-environments.md) konusunda bu bilgilere ihtiyaç duyacaksınız.\n"
  },
  {
    "path": "docs/tr/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - komut satırı arayüzü\">CLI</abbr>**, FastAPI uygulamanızı servis etmek, FastAPI projenizi yönetmek ve daha fazlası için kullanabileceğiniz bir komut satırı programıdır.\n\nFastAPI'yi kurduğunuzda (ör. `pip install \"fastapi[standard]\"`), terminalde çalıştırabileceğiniz bir komut satırı programı birlikte gelir.\n\nFastAPI uygulamanızı geliştirme için çalıştırmak üzere `fastapi dev` komutunu kullanabilirsiniz:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip | İpucu\n\nProduction için `fastapi dev` yerine `fastapi run` kullanırsınız. 🚀\n\n///\n\nİçeride, **FastAPI CLI**, yüksek performanslı, production'a hazır bir ASGI server olan [Uvicorn](https://www.uvicorn.dev)'u kullanır. 😎\n\n`fastapi` CLI, çalıştırılacak FastAPI app'ini otomatik olarak tespit etmeye çalışır; `main.py` dosyasında `app` adlı bir nesne olduğunu varsayar (veya birkaç başka varyant).\n\nAncak, kullanılacak app'i açıkça yapılandırabilirsiniz.\n\n## Uygulama `entrypoint`'ini `pyproject.toml` İçinde Yapılandırma { #configure-the-app-entrypoint-in-pyproject-toml }\n\nUygulamanızın nerede olduğunu aşağıdaki gibi bir `pyproject.toml` dosyasında yapılandırabilirsiniz:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nBu `entrypoint`, `fastapi` komutuna app'i şu şekilde import etmesi gerektiğini söyler:\n\n```python\nfrom main import app\n```\n\nKodunuz şu şekilde yapılandırılmışsa:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nO zaman `entrypoint`'i şu şekilde ayarlarsınız:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nBu da şu koda eşdeğerdir:\n\n```python\nfrom backend.main import app\n```\n\n### path ile `fastapi dev` { #fastapi-dev-with-path }\n\nAyrıca `fastapi dev` komutuna dosya path'ini de verebilirsiniz; hangi FastAPI app nesnesinin kullanılacağını tahmin eder:\n\n```console\n$ fastapi dev main.py\n```\n\nAncak `fastapi` komutunu her çağırdığınızda doğru path'i geçmeyi hatırlamanız gerekir.\n\nAyrıca, [VS Code Extension](editor-support.md) veya [FastAPI Cloud](https://fastapicloud.com) gibi diğer araçlar da bunu bulamayabilir; bu yüzden `pyproject.toml` içindeki `entrypoint`'i kullanmanız önerilir.\n\n## `fastapi dev` { #fastapi-dev }\n\n`fastapi dev` çalıştırmak, geliştirme modunu başlatır.\n\nVarsayılan olarak **auto-reload** etkindir; kodunuzda değişiklik yaptığınızda server'ı otomatik olarak yeniden yükler. Bu, kaynak tüketimi yüksek bir özelliktir ve kapalı olduğuna kıyasla daha az stabil olabilir. Sadece geliştirme sırasında kullanmalısınız. Ayrıca yalnızca `127.0.0.1` IP adresini dinler; bu, makinenizin sadece kendisiyle iletişim kurması için kullanılan IP'dir (`localhost`).\n\n## `fastapi run` { #fastapi-run }\n\n`fastapi run` çalıştırmak, varsayılan olarak FastAPI'yi production modunda başlatır.\n\nVarsayılan olarak **auto-reload** kapalıdır. Ayrıca `0.0.0.0` IP adresini dinler; bu, kullanılabilir tüm IP adresleri anlamına gelir. Böylece makineyle iletişim kurabilen herkes tarafından genel erişime açık olur. Bu, normalde production'da çalıştırma şeklidir; örneğin bir container içinde.\n\nÇoğu durumda (ve genellikle yapmanız gereken şekilde) üst tarafta sizin yerinize HTTPS'i yöneten bir \"termination proxy\" bulunur. Bu, uygulamanızı nasıl deploy ettiğinize bağlıdır; sağlayıcınız bunu sizin için yapabilir ya da sizin ayrıca kurmanız gerekebilir.\n\n/// tip | İpucu\n\nBununla ilgili daha fazla bilgiyi [deployment dokümantasyonunda](deployment/index.md) bulabilirsiniz.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/features.md",
    "content": "# Özellikler { #features }\n\n## FastAPI Özellikleri { #fastapi-features }\n\n**FastAPI** size şunları sağlar:\n\n### Açık Standartlara Dayalı { #based-on-open-standards }\n\n* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) ile API oluşturma; buna <dfn title=\"şöyle de bilinir: endpoints, routes\">path</dfn> <dfn title=\"HTTP metodları olarak da bilinir; POST, GET, PUT, DELETE gibi\">operasyonları</dfn>, parametreler, request body'leri, güvenlik vb. deklarasyonları dahildir.\n* [**JSON Schema**](https://json-schema.org/) ile otomatik veri modeli dokümantasyonu (OpenAPI zaten JSON Schema'ya dayanır).\n* Bu standartlar etrafında, titiz bir çalışmanın ardından tasarlandı; sonradan eklenmiş bir katman değil.\n* Bu sayede birçok dilde otomatik **client code generation** da kullanılabilir.\n\n### Otomatik Dokümantasyon { #automatic-docs }\n\nEtkileşimli API dokümantasyonu ve keşif için web arayüzleri. Framework OpenAPI’ye dayandığından, birden fazla seçenek vardır; varsayılan olarak 2’si dahildir.\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui) ile etkileşimli keşif; API’nizi tarayıcıdan doğrudan çağırıp test edin.\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* [**ReDoc**](https://github.com/Rebilly/ReDoc) ile alternatif API dokümantasyonu.\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Sadece Modern Python { #just-modern-python }\n\nHer şey standart **Python type** deklarasyonlarına dayanır (Pydantic sayesinde). Öğrenilecek yeni bir söz dizimi yok. Sadece standart, modern Python.\n\nPython type’larını nasıl kullanacağınıza dair 2 dakikalık bir hatırlatmaya ihtiyacınız varsa (FastAPI kullanmasanız bile) kısa eğitime göz atın: [Python Types](python-types.md).\n\nTürleriyle standart Python yazarsınız:\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# Bir değişkeni str olarak belirt\n# ve fonksiyon içinde editör desteği al\ndef main(user_id: str):\n    return user_id\n\n\n# Bir Pydantic modeli\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\nSonra şöyle kullanabilirsiniz:\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n\n/// info\n\n`**second_user_data` şu anlama gelir:\n\n`second_user_data` dict’indeki anahtar ve değerleri doğrudan anahtar-değer argümanları olarak geç; şu ifadeye eşdeğerdir: `User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### Editör Desteği { #editor-support }\n\nTüm framework, kullanımı kolay ve sezgisel olacak şekilde tasarlandı; en iyi geliştirme deneyimini sağlamak için geliştirmeye başlamadan önce bile alınan kararlar birden çok editörde test edildi.\n\nPython geliştirici anketlerinde açıkça görülüyor ki [en çok kullanılan özelliklerden biri \"otomatik tamamlama\"](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).\n\nTüm **FastAPI** bunun tatmin edilmesi üzerine kuruldu. Otomatik tamamlama her yerde çalışır.\n\nDokümana geri dönmeniz nadiren gerekecek.\n\nEditörünüz şöyle yardımcı olabilir:\n\n* [Visual Studio Code](https://code.visualstudio.com/) ile:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* [PyCharm](https://www.jetbrains.com/pycharm/) ile:\n\n![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\nDaha önce imkânsız olduğunu düşünebileceğiniz yerlerde bile tamamlama alırsınız. Örneğin, bir request’ten gelen (iç içe de olabilir) JSON body içindeki `price` anahtarı için.\n\nArtık anahtar adlarını yanlış yazmak, dokümana gidip gelmek ya da sonunda `username` mi `user_name` mi kullandığınızı bulmak için sayfayı yukarı aşağı kaydırmak yok.\n\n### Kısa { #short }\n\nHer şey için mantıklı **varsayılanlar** ve her yerde isteğe bağlı yapılandırmalar vardır. Tüm parametreler, ihtiyacınızı karşılayacak şekilde ince ayar yapılarak tanımlamak istediğiniz API’yi oluşturabilir.\n\nAncak varsayılan hâliyle hepsi **“hemen çalışır”**.\n\n### Doğrulama { #validation }\n\n* Çoğu (veya hepsi?) Python **veri tipi** için doğrulama, şunlar dâhil:\n    * JSON nesneleri (`dict`).\n    * Eleman tipleri tanımlanan JSON dizileri (`list`).\n    * Minimum ve maksimum uzunlukları tanımlanan String (`str`) alanları.\n    * Min ve max değerleri olan sayılar (`int`, `float`) vb.\n\n* Daha “egzotik” tipler için doğrulama:\n    * URL.\n    * Email.\n    * UUID.\n    * ...ve diğerleri.\n\nTüm doğrulama köklü ve sağlam **Pydantic** tarafından yapılır.\n\n### Güvenlik ve Kimlik Doğrulama { #security-and-authentication }\n\nGüvenlik ve kimlik doğrulama entegredir. Veritabanları veya veri modelleriyle ilgili hiçbir taviz yoktur.\n\nOpenAPI’da tanımlanan tüm güvenlik şemaları, şunlar dâhil:\n\n* HTTP Basic.\n* **OAuth2** (ayrıca **JWT token**’larla). Şu eğitime göz atın: [OAuth2 with JWT](tutorial/security/oauth2-jwt.md).\n* API anahtarları:\n    * Header’larda.\n    * Query parametrelerinde.\n    * Cookie’lerde vb.\n\nBuna ek olarak Starlette’in tüm güvenlik özellikleri (**session cookies** dâhil).\n\nTümü, sistemleriniz, veri depolarınız, ilişkisel ve NoSQL veritabanlarınız vb. ile kolayca entegre edilebilen, yeniden kullanılabilir araçlar ve bileşenler olarak inşa edilmiştir.\n\n### Dependency Injection { #dependency-injection }\n\nFastAPI, son derece kolay kullanımlı ama son derece güçlü bir <dfn title='şöyle de bilinir: \"components\", \"resources\", \"services\", \"providers\"'><strong>Dependency Injection</strong></dfn> sistemine sahiptir.\n\n* Bağımlılıkların da kendi bağımlılıkları olabilir; böylece bir hiyerarşi veya **bağımlılıklar \"grafı\"** oluşur.\n* Tüm süreç framework tarafından **otomatik olarak yönetilir**.\n* Tüm bağımlılıklar, request’lerden veri talep edebilir ve *path operation* kısıtlarını ve otomatik dokümantasyonu **zenginleştirebilir**.\n* Bağımlılıklarda tanımlanan *path operation* parametreleri için bile **otomatik doğrulama**.\n* Karmaşık kullanıcı kimlik doğrulama sistemleri, **veritabanı bağlantıları** vb. için destek.\n* Veritabanları, frontend’ler vb. ile **taviz yok**; ancak hepsiyle kolay entegrasyon.\n\n### Sınırsız \"Plug-in\" { #unlimited-plug-ins }\n\nBaşka bir deyişle, onlara gerek yok; ihtiyaç duyduğunuz kodu import edin ve kullanın.\n\nHer entegrasyon (bağımlılıklar ile) o kadar basit olacak şekilde tasarlanmıştır ki, uygulamanız için, *path operations* ile kullandığınız aynı yapı ve söz dizimiyle sadece 2 satırda bir “plug-in” yazabilirsiniz.\n\n### Test Edildi { #tested }\n\n* %100 <dfn title=\"Otomatik olarak test edilen kod miktarı\">test kapsayıcılığı</dfn>.\n* %100 <dfn title=\"Python type annotations; bununla editörünüz ve harici araçlar size daha iyi destek verebilir\">type annotated</dfn> kod tabanı.\n* Üretimde kullanılan uygulamalarda kullanılıyor.\n\n## Starlette Özellikleri { #starlette-features }\n\n**FastAPI**, [**Starlette**](https://www.starlette.dev/) ile tamamen uyumludur (ve onun üzerine kuruludur). Dolayısıyla elinizdeki ek Starlette kodları da çalışır.\n\n`FastAPI` aslında `Starlette`’in bir alt sınıfıdır. Starlette’i zaten biliyor veya kullanıyorsanız, işlevlerin çoğu aynı şekilde çalışır.\n\n**FastAPI** ile **Starlette**’in tüm özelliklerini elde edersiniz (FastAPI, steroid basılmış Starlette gibidir):\n\n* Cidden etkileyici performans. [Mevcut en hızlı Python frameworklerinden biridir; **NodeJS** ve **Go** ile aynı seviyededir](https://github.com/encode/starlette#performance).\n* **WebSocket** desteği.\n* Süreç içi arka plan görevleri.\n* Başlatma ve kapatma olayları.\n* HTTPX üzerine kurulu test istemcisi.\n* **CORS**, GZip, Static Files, Streaming response’lar.\n* **Session** ve **Cookie** desteği.\n* %100 test kapsayıcılığı.\n* %100 type annotated kod tabanı.\n\n## Pydantic Özellikleri { #pydantic-features }\n\n**FastAPI**, [**Pydantic**](https://docs.pydantic.dev/) ile tamamen uyumludur (ve onun üzerine kuruludur). Dolayısıyla elinizdeki ek Pydantic kodları da çalışır.\n\nPydantic’e dayanan harici kütüphaneler de dâhildir; veritabanları için <abbr title=\"Object-Relational Mapper - Nesne-İlişkisel Eşleyici\">ORM</abbr>’ler, <abbr title=\"Object-Document Mapper - Nesne-Belge Eşleyici\">ODM</abbr>’ler gibi.\n\nBu aynı zamanda, birçok durumda request’ten aldığınız nesneyi **doğrudan veritabanına** iletebileceğiniz anlamına gelir; zira her şey otomatik olarak doğrulanır.\n\nTersi yönde de geçerlidir; birçok durumda veritabanından aldığınız nesneyi **doğrudan client**’a gönderebilirsiniz.\n\n**FastAPI** ile **Pydantic**’in tüm özelliklerini elde edersiniz (FastAPI, tüm veri işlemede Pydantic’e dayanır):\n\n* **Kafa karıştırmaz**:\n    * Öğrenmeniz gereken yeni bir şema tanımlama mikro-dili yok.\n    * Python type’larını biliyorsanız Pydantic’i nasıl kullanacağınızı da biliyorsunuz.\n* **<abbr title=\"Integrated Development Environment - Tümleşik Geliştirme Ortamı: bir kod editörüne benzer\">IDE</abbr>/<dfn title=\"koddaki hataları denetleyen bir program\">linter</dfn>/beyin**’inizle iyi anlaşır:\n    * Pydantic veri yapıları, sizin tanımladığınız sınıfların örnekleridir; bu nedenle doğrulanmış verilerinizle otomatik tamamlama, linting ve mypy sorunsuz çalışır, sezgileriniz de yol gösterir.\n* **Karmaşık yapıları** doğrulayın:\n    * Hiyerarşik Pydantic modelleri, Python `typing`’in `List` ve `Dict`’i vb. kullanımı.\n    * Doğrulayıcılar (validators), karmaşık veri şemalarının net ve kolay şekilde tanımlanmasını, kontrol edilmesini ve JSON Schema olarak dokümante edilmesini sağlar.\n    * Derinlemesine iç içe **JSON** nesnelerine sahip olabilir, hepsinin doğrulanmasını ve anotasyonlanmasını sağlayabilirsiniz.\n* **Genişletilebilir**:\n    * Pydantic, özel veri tiplerinin tanımlanmasına izin verir; ayrıca validator decorator’üyle bir modeldeki metodlarla doğrulamayı genişletebilirsiniz.\n* %100 test kapsayıcılığı.\n"
  },
  {
    "path": "docs/tr/docs/help-fastapi.md",
    "content": "# FastAPI'ye Yardım Et - Yardım Al { #help-fastapi-get-help }\n\n**FastAPI**'yi seviyor musunuz?\n\nFastAPI'ye, diğer kullanıcılara ve yazara yardım etmek ister misiniz?\n\nYoksa **FastAPI** ile ilgili yardım mı almak istiyorsunuz?\n\nYardım etmenin çok basit yolları var (bazıları sadece bir-iki tıklama gerektirir).\n\nYardım almanın da birkaç yolu var.\n\n## Bültene abone olun { #subscribe-to-the-newsletter }\n\nŞunlardan haberdar olmak için (seyrek yayımlanan) [**FastAPI and friends** bültenine](newsletter.md) abone olabilirsiniz:\n\n* FastAPI ve friends ile ilgili haberler 🚀\n* Rehberler 📝\n* Özellikler ✨\n* Geriye dönük uyumsuz değişiklikler 🚨\n* İpuçları ve püf noktaları ✅\n\n## X (Twitter) üzerinden FastAPI'yi takip edin { #follow-fastapi-on-x-twitter }\n\n[**X (Twitter)** üzerinde @fastapi hesabını takip edin](https://x.com/fastapi) ve **FastAPI** ile ilgili en güncel haberleri alın. 🐦\n\n## GitHub'da **FastAPI**'ye yıldız verin { #star-fastapi-in-github }\n\nGitHub'da FastAPI'ye \"star\" verebilirsiniz (sağ üstteki yıldız butonuna tıklayarak): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). ⭐️\n\nYıldız verince, diğer kullanıcılar projeyi daha kolay bulabilir ve başkaları için de faydalı olduğunu görebilir.\n\n## GitHub repository'sini release'ler için izleyin { #watch-the-github-repository-for-releases }\n\nGitHub'da FastAPI'yi \"watch\" edebilirsiniz (sağ üstteki \"watch\" butonuna tıklayarak): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nOrada \"Releases only\" seçebilirsiniz.\n\nBöylece **FastAPI**'nin bug fix'ler ve yeni özelliklerle gelen her yeni release'inde (yeni versiyonunda) email ile bildirim alırsınız.\n\n## Yazarla bağlantı kurun { #connect-with-the-author }\n\nYazar olan [benimle (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com) bağlantı kurabilirsiniz.\n\nŞunları yapabilirsiniz:\n\n* [Beni **GitHub**'da takip edin](https://github.com/tiangolo).\n    * Size yardımcı olabilecek oluşturduğum diğer Open Source projelere göz atın.\n    * Yeni bir Open Source proje oluşturduğumda haberdar olmak için beni takip edin.\n* [Beni **X (Twitter)** üzerinde](https://x.com/tiangolo) veya [Mastodon](https://fosstodon.org/@tiangolo)'da takip edin.\n    * FastAPI'yi nasıl kullandığınızı anlatın (bunu duymayı seviyorum).\n    * Duyuru yaptığımda veya yeni araçlar yayınladığımda haberdar olun.\n    * Ayrıca (ayrı bir hesap olan) [X (Twitter) üzerinde @fastapi hesabını da takip edebilirsiniz](https://x.com/fastapi).\n* [Beni **LinkedIn**'de takip edin](https://www.linkedin.com/in/tiangolo/).\n    * Duyuru yaptığımda veya yeni araçlar yayınladığımda haberdar olun (gerçi X (Twitter)'ı daha sık kullanıyorum 🤷‍♂).\n* [**Dev.to**](https://dev.to/tiangolo) veya [**Medium**](https://medium.com/@tiangolo) üzerinde yazdıklarımı okuyun (ya da beni takip edin).\n    * Diğer fikirleri, yazıları ve oluşturduğum araçlarla ilgili içerikleri okuyun.\n    * Yeni bir şey yayınladığımda görmek için beni takip edin.\n\n## **FastAPI** hakkında tweet atın { #tweet-about-fastapi }\n\n[**FastAPI** hakkında tweet atın](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi) ve neden sevdiğinizi bana ve diğerlerine söyleyin. 🎉\n\n**FastAPI**'nin nasıl kullanıldığını, nelerini sevdiğinizi, hangi projede/şirkette kullandığınızı vb. duymayı seviyorum.\n\n## FastAPI için oy verin { #vote-for-fastapi }\n\n* [Slant'ta **FastAPI** için oy verin](https://www.slant.co/options/34241/~fastapi-review).\n* [AlternativeTo'da **FastAPI** için oy verin](https://alternativeto.net/software/fastapi/about/).\n* [StackShare'de **FastAPI** kullandığınızı belirtin](https://stackshare.io/pypi-fastapi).\n\n## GitHub'da sorularla başkalarına yardım edin { #help-others-with-questions-in-github }\n\nŞuralarda insanların sorularına yardımcı olmayı deneyebilirsiniz:\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\nBirçok durumda bu soruların cevabını zaten biliyor olabilirsiniz. 🤓\n\nEğer insanların sorularına çok yardım ederseniz, resmi bir [FastAPI Expert](fastapi-people.md#fastapi-experts) olabilirsiniz. 🎉\n\nŞunu unutmayın: en önemli nokta, nazik olmaya çalışmak. İnsanlar çoğu zaman biriken stresle geliyor ve birçok durumda soruyu en iyi şekilde sormuyor; yine de elinizden geldiğince nazik olmaya çalışın. 🤗\n\nAmaç, **FastAPI** topluluğunun nazik ve kapsayıcı olması. Aynı zamanda başkalarına zorbalık ya da saygısız davranışları da kabul etmeyin. Birbirimizi kollamalıyız.\n\n---\n\nSorularda (discussions veya issues içinde) başkalarına yardım etmek için şunları yapabilirsiniz:\n\n### Soruyu anlayın { #understand-the-question }\n\n* Soru soran kişinin **amacının** ve kullanım senaryosunun ne olduğunu anlayabiliyor musunuz, kontrol edin.\n\n* Sonra sorunun (büyük çoğunluğu soru olur) **net** olup olmadığına bakın.\n\n* Birçok durumda kullanıcı kafasında hayali bir çözüm kurup onu sorar; ancak **daha iyi** bir çözüm olabilir. Problemi ve kullanım senaryosunu daha iyi anladıysanız daha iyi bir **alternatif çözüm** önerebilirsiniz.\n\n* Soruyu anlayamıyorsanız daha fazla **detay** isteyin.\n\n### Problemi yeniden üretin { #reproduce-the-problem }\n\nÇoğu durumda ve çoğu soruda, kişinin **orijinal kodu** ile ilgili bir şey vardır.\n\nBirçok kişi sadece kodun bir parçasını kopyalar, ama bu **problemi yeniden üretmek** için yeterli olmaz.\n\n* Çalıştırıp aynı hatayı/davranışı görebileceğiniz veya kullanım senaryosunu daha iyi anlayabileceğiniz, yerelde **kopyala-yapıştır** yaparak çalıştırılabilen bir [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) paylaşmalarını isteyebilirsiniz.\n\n* Çok cömert hissediyorsanız, problemi anlatan açıklamadan yola çıkarak kendiniz de böyle bir **örnek oluşturmayı** deneyebilirsiniz. Ancak bunun çok zaman alabileceğini unutmayın; çoğu zaman önce problemi netleştirmelerini istemek daha iyidir.\n\n### Çözüm önerin { #suggest-solutions }\n\n* Soruyu anlayabildikten sonra olası bir **cevap** verebilirsiniz.\n\n* Çoğu durumda, yapmak istediklerinden ziyade alttaki **asıl problemi veya kullanım senaryosunu** anlamak daha iyidir; çünkü denedikleri yöntemden daha iyi bir çözüm yolu olabilir.\n\n### Kapatılmasını isteyin { #ask-to-close }\n\nEğer yanıt verirlerse, büyük ihtimalle problemi çözmüşsünüzdür, tebrikler, **kahramansınız**! 🦸\n\n* Eğer çözüm işe yaradıysa şunları yapmalarını isteyebilirsiniz:\n\n    * GitHub Discussions'ta: ilgili yorumu **answer** olarak işaretlemeleri.\n    * GitHub Issues'ta: issue'yu **close** etmeleri.\n\n## GitHub repository'sini izleyin { #watch-the-github-repository }\n\nGitHub'da FastAPI'yi \"watch\" edebilirsiniz (sağ üstteki \"watch\" butonuna tıklayarak): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\n\"Releases only\" yerine \"Watching\" seçerseniz biri yeni bir issue veya soru oluşturduğunda bildirim alırsınız. Ayrıca sadece yeni issue'lar, ya da discussions, ya da PR'lar vb. için bildirim almak istediğinizi belirtebilirsiniz.\n\nSonra da bu soruları çözmelerine yardımcı olmayı deneyebilirsiniz.\n\n## Soru Sorun { #ask-questions }\n\nGitHub repository'sinde örneğin şunlar için [yeni bir soru oluşturabilirsiniz](https://github.com/fastapi/fastapi/discussions/new?category=questions):\n\n* Bir **soru** sorun veya bir **problem** hakkında danışın.\n* Yeni bir **feature** önerin.\n\n**Not**: Bunu yaparsanız, ben de sizden başkalarına yardım etmenizi isteyeceğim. 😉\n\n## Pull Request'leri İnceleyin { #review-pull-requests }\n\nBaşkalarının gönderdiği pull request'leri incelememde bana yardımcı olabilirsiniz.\n\nYine, lütfen elinizden geldiğince nazik olmaya çalışın. 🤗\n\n---\n\nBir pull request'i incelerken akılda tutmanız gerekenler:\n\n### Problemi anlayın { #understand-the-problem }\n\n* Önce, pull request'in çözmeye çalıştığı **problemi anladığınızdan** emin olun. GitHub Discussion veya issue içinde daha uzun bir tartışması olabilir.\n\n* Pull request'in aslında hiç gerekmiyor olma ihtimali de yüksektir; çünkü problem **farklı bir şekilde** çözülebilir. Bu durumda bunu önerebilir veya bununla ilgili soru sorabilirsiniz.\n\n### Style konusunda çok dert etmeyin { #dont-worry-about-style }\n\n* Commit message tarzı gibi şeyleri çok dert etmeyin; ben commit'leri manuel olarak düzenleyerek squash and merge yapacağım.\n\n* Style kuralları için de endişelenmeyin; bunları kontrol eden otomatik araçlar zaten var.\n\nEk bir style veya tutarlılık ihtiyacı olursa, bunu doğrudan isterim ya da gerekli değişikliklerle üstüne commit eklerim.\n\n### Kodu kontrol edin { #check-the-code }\n\n* Kodu okuyup kontrol edin; mantıklı mı bakın, **yerelde çalıştırın** ve gerçekten problemi çözüyor mu görün.\n\n* Ardından bunu yaptığınızı belirten bir **yorum** yazın; böylece gerçekten kontrol ettiğinizi anlarım.\n\n/// info | Bilgi\n\nNe yazık ki sadece birkaç onayı olan PR'lara körü körüne güvenemem.\n\nDefalarca, 3, 5 veya daha fazla onayı olan PR'lar oldu; muhtemelen açıklaması çekici olduğu için onay aldılar. Ama PR'lara baktığımda aslında bozuk olduklarını, bug içerdiğini veya iddia ettikleri problemi çözmediklerini gördüm. 😅\n\nBu yüzden kodu gerçekten okuyup çalıştırmanız ve bunu yorumlarda bana bildirmeniz çok önemli. 🤓\n\n///\n\n* PR bir şekilde basitleştirilebiliyorsa bunu isteyebilirsiniz. Ancak çok didik didik etmeye gerek yok; konuya göre birçok öznel bakış açısı olabilir (benim de olacaktır 🙈). Bu yüzden temel noktalara odaklanmak daha iyi.\n\n### Testler { #tests }\n\n* PR'da **testler** olduğunu kontrol etmemde bana yardımcı olun.\n\n* PR'dan önce testlerin **fail** ettiğini kontrol edin. 🚨\n\n* PR'dan sonra testlerin **pass** ettiğini kontrol edin. ✅\n\n* Birçok PR test içermez; test eklemelerini **hatırlatabilirsiniz** veya hatta kendiniz bazı testler **önerebilirsiniz**. Bu, en çok zaman alan işlerden biridir ve burada çok yardımcı olabilirsiniz.\n\n* Ayrıca neleri denediğinizi yorumlara yazın; böylece kontrol ettiğinizi anlarım. 🤓\n\n## Pull Request Oluşturun { #create-a-pull-request }\n\nÖrneğin şunlar için Pull Request'lerle kaynak koda [katkıda bulunabilirsiniz](contributing.md):\n\n* Dokümantasyonda bulduğunuz bir yazım hatasını düzeltmek.\n* FastAPI hakkında oluşturduğunuz veya bulduğunuz bir makaleyi, videoyu ya da podcast'i [bu dosyayı düzenleyerek](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml) paylaşmak.\n    * Link'inizi ilgili bölümün başına eklediğinizden emin olun.\n* Dokümantasyonu kendi dilinize [çevirmeye yardımcı olmak](contributing.md#translations).\n    * Başkalarının yaptığı çevirileri gözden geçirmeye de yardımcı olabilirsiniz.\n* Yeni dokümantasyon bölümleri önermek.\n* Mevcut bir issue/bug'ı düzeltmek.\n    * Test eklediğinizden emin olun.\n* Yeni bir feature eklemek.\n    * Test eklediğinizden emin olun.\n    * İlgiliyse dokümantasyon da eklediğinizden emin olun.\n\n## FastAPI'nin Bakımına Yardım Edin { #help-maintain-fastapi }\n\n**FastAPI**'nin bakımını yapmama yardımcı olun! 🤓\n\nYapılacak çok iş var ve bunların çoğunu **SİZ** yapabilirsiniz.\n\nŞu anda yapabileceğiniz ana işler:\n\n* [GitHub'da sorularla başkalarına yardım edin](#help-others-with-questions-in-github) (yukarıdaki bölüme bakın).\n* [Pull Request'leri inceleyin](#review-pull-requests) (yukarıdaki bölüme bakın).\n\nBu iki iş, **en çok zamanı alan** işlerdir. FastAPI bakımının ana yükü buradadır.\n\nBurada yardımcı olursanız, **FastAPI'nin bakımını yapmama yardım etmiş** ve daha **hızlı ve daha iyi ilerlemesini** sağlamış olursunuz. 🚀\n\n## Sohbete katılın { #join-the-chat }\n\nFastAPI topluluğundan diğer kişilerle takılmak için 👥 [Discord chat server](https://discord.gg/VQjSZaeJmf) 👥 sohbetine katılın.\n\n/// tip | İpucu\n\nSorular için [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions)'a sorun; [FastAPI Experts](fastapi-people.md#fastapi-experts) tarafından yardım alma ihtimaliniz çok daha yüksektir.\n\nChat'i sadece genel sohbetler için kullanın.\n\n///\n\n### Sorular için chat'i kullanmayın { #dont-use-the-chat-for-questions }\n\nChat sistemleri daha \"serbest sohbet\"e izin verdiği için, çok genel ve yanıtlaması daha zor sorular sormak kolaylaşır; bu nedenle cevap alamayabilirsiniz.\n\nGitHub'da ise şablon (template) doğru soruyu yazmanız için sizi yönlendirir; böylece daha kolay iyi bir cevap alabilir, hatta bazen sormadan önce problemi kendiniz çözebilirsiniz. Ayrıca GitHub'da (zaman alsa bile) her şeye mutlaka cevap verdiğimden emin olabilirim. Chat sistemlerinde bunu kişisel olarak yapamam. 😅\n\nChat sistemlerindeki konuşmalar GitHub kadar kolay aranabilir değildir; bu yüzden soru ve cevaplar sohbet içinde kaybolabilir. Ayrıca [FastAPI Expert](fastapi-people.md#fastapi-experts) olmak için sadece GitHub'daki katkılar sayılır; dolayısıyla büyük olasılıkla GitHub'da daha fazla ilgi görürsünüz.\n\nÖte yandan chat sistemlerinde binlerce kullanıcı vardır; bu yüzden neredeyse her zaman konuşacak birini bulma ihtimaliniz yüksektir. 😄\n\n## Yazara sponsor olun { #sponsor-the-author }\n\nEğer **ürününüz/şirketiniz** **FastAPI**'ye bağlıysa veya onunla ilişkiliyse ve FastAPI kullanıcılarına ulaşmak istiyorsanız, [GitHub sponsors](https://github.com/sponsors/tiangolo) üzerinden yazara (bana) sponsor olabilirsiniz. Tier'a göre dokümantasyonda bir rozet gibi ek faydalar elde edebilirsiniz. 🎁\n\n---\n\nTeşekkürler! 🚀\n"
  },
  {
    "path": "docs/tr/docs/history-design-future.md",
    "content": "# Geçmişi, Tasarımı ve Geleceği { #history-design-and-future }\n\nBir süre önce, [bir **FastAPI** kullanıcısı sordu](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920):\n\n> Bu projenin geçmişi nedir? Birkaç hafta içinde hiçbir yerden harika bir şeye dönüşmüş gibi görünüyor [...]\n\nİşte o geçmişin bir kısmı.\n\n## Alternatifler { #alternatives }\n\nBir süredir karmaşık gereksinimlere sahip API'lar oluşturuyor (Makine Öğrenimi, dağıtık sistemler, asenkron işler, NoSQL veritabanları vb.) ve farklı geliştirici ekiplerini yönetiyorum.\n\nBu süreçte birçok alternatifi araştırmak, test etmek ve kullanmak zorunda kaldım.\n\n**FastAPI**'ın geçmişi, büyük ölçüde önceden geliştirilen araçların geçmişini kapsıyor.\n\n[Alternatifler](alternatives.md) bölümünde belirtildiği gibi:\n\n<blockquote markdown=\"1\">\n\nBaşkalarının daha önceki çalışmaları olmasaydı, **FastAPI** var olmazdı.\n\nGeçmişte oluşturulan pek çok araç **FastAPI**'a ilham kaynağı olmuştur.\n\nYıllardır yeni bir framework oluşturmaktan kaçınıyordum. Başlangıçta **FastAPI**'ın çözdüğü sorunları çözebilmek için pek çok farklı framework, <abbr title=\"Eklenti: Plug-In\">eklenti</abbr> ve araç kullanmayı denedim.\n\nAncak bir noktada, geçmişteki diğer araçlardan en iyi fikirleri alarak bütün bu çözümleri kapsayan, ayrıca bütün bunları Python'ın daha önce mevcut olmayan özelliklerini (Python 3.6+ ile gelen <abbr title=\"Tip belirteçleri: Type Hints\">tip belirteçleri</abbr>) kullanarak yapan bir şey üretmekten başka bir seçenek kalmamıştı.\n\n</blockquote>\n\n## Araştırma { #investigation }\n\nÖnceki alternatifleri kullanarak hepsinden bir şeyler öğrenip, fikirler alıp, bunları kendim ve çalıştığım geliştirici ekipler için en iyi şekilde birleştirebilme şansım oldu.\n\nMesela, ideal olarak standart Python tip belirteçlerine dayanması gerektiği açıktı.\n\nAyrıca, en iyi yaklaşım zaten mevcut olan standartları kullanmaktı.\n\nSonuç olarak, **FastAPI**'ı kodlamaya başlamadan önce, birkaç ay boyunca OpenAPI, JSON Schema, OAuth2 ve benzerlerinin tanımlamalarını inceledim. İlişkilerini, örtüştükleri noktaları ve farklılıklarını anlamaya çalıştım.\n\n## Tasarım { #design }\n\nSonrasında, (**FastAPI** kullanan bir geliştirici olarak) sahip olmak istediğim \"API\"ı tasarlamak için biraz zaman harcadım.\n\nÇeşitli fikirleri en popüler Python editörlerinde test ettim: PyCharm, VS Code, Jedi tabanlı editörler.\n\nBu test, en son [Python Geliştirici Anketi](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools)'ine göre, kullanıcıların yaklaşık %80'inin kullandığı editörleri kapsıyor.\n\nBu da demek oluyor ki **FastAPI**, Python geliştiricilerinin %80'inin kullandığı editörlerle test edildi. Ve diğer editörlerin çoğu benzer şekilde çalıştığından, avantajları neredeyse tüm editörlerde çalışacaktır.\n\nBu şekilde, kod tekrarını mümkün olduğunca azaltmak, her yerde <abbr title=\"Otomatik Tamamlama: auto-complete, autocompletion, IntelliSense\">otomatik tamamlama</abbr>, tip ve hata kontrollerine sahip olmak için en iyi yolları bulabildim.\n\nHepsi, tüm geliştiriciler için en iyi geliştirme deneyimini sağlayacak şekilde.\n\n## Gereksinimler { #requirements }\n\nÇeşitli alternatifleri test ettikten sonra, avantajlarından dolayı [**Pydantic**](https://docs.pydantic.dev/)'i kullanmaya karar verdim.\n\nSonra, JSON Schema ile tamamen uyumlu olmasını sağlamak, kısıtlama bildirimlerini tanımlamanın farklı yollarını desteklemek ve birkaç editördeki testlere dayanarak editör desteğini (tip kontrolleri, otomatik tamamlama) geliştirmek için katkıda bulundum.\n\nGeliştirme sırasında, diğer ana gereksinim olan [**Starlette**](https://www.starlette.dev/)'e de katkıda bulundum.\n\n## Geliştirme { #development }\n\n**FastAPI**'ı oluşturmaya başladığımda, parçaların çoğu zaten yerindeydi, tasarım tanımlanmıştı, gereksinimler ve araçlar hazırdı, standartlar ve tanımlamalar hakkındaki bilgi net ve tazeydi.\n\n## Gelecek { #future }\n\nŞimdiye kadar, **FastAPI**'ın fikirleriyle birçok kişiye faydalı olduğu apaçık ortada.\n\nBirçok kullanım durumuna daha iyi uyduğu için, önceki alternatiflerin yerine seçiliyor.\n\nBen ve ekibim dahil, birçok geliştirici ve ekip projelerinde **FastAPI**'ya bağlı.\n\nTabi, geliştirilecek birçok özellik ve iyileştirme mevcut.\n\n**FastAPI**'ın önünde harika bir gelecek var.\n\n[Yardımlarınız](help-fastapi.md) çok değerlidir.\n"
  },
  {
    "path": "docs/tr/docs/how-to/authentication-error-status-code.md",
    "content": "# Eski 403 Kimlik Doğrulama Hata Durum Kodlarını Kullanma { #use-old-403-authentication-error-status-codes }\n\nFastAPI `0.122.0` sürümünden önce, entegre security yardımcı araçları başarısız bir kimlik doğrulama (authentication) sonrasında client'a bir hata döndüğünde HTTP durum kodu olarak `403 Forbidden` kullanıyordu.\n\nFastAPI `0.122.0` sürümünden itibaren ise daha uygun olan HTTP durum kodu `401 Unauthorized` kullanılmakta ve HTTP spesifikasyonlarına uygun olarak response içinde anlamlı bir `WWW-Authenticate` header'ı döndürülmektedir, [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized).\n\nAncak herhangi bir nedenle client'larınız eski davranışa bağlıysa, security class'larınızda `make_not_authenticated_error` metodunu override ederek eski davranışa geri dönebilirsiniz.\n\nÖrneğin, varsayılan `401 Unauthorized` hatası yerine `403 Forbidden` hatası döndüren bir `HTTPBearer` alt sınıfı oluşturabilirsiniz:\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip | İpucu\n\nFonksiyonun exception instance'ını döndürdüğüne dikkat edin; exception'ı raise etmiyor. Raise işlemi internal kodun geri kalan kısmında yapılıyor.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/how-to/conditional-openapi.md",
    "content": "# Koşullu OpenAPI { #conditional-openapi }\n\nGerekirse, ayarlar ve environment variable'ları kullanarak OpenAPI'yi ortama göre koşullu şekilde yapılandırabilir, hatta tamamen devre dışı bırakabilirsiniz.\n\n## Güvenlik, API'ler ve dokümantasyon hakkında { #about-security-apis-and-docs }\n\nProduction ortamında dokümantasyon arayüzlerini gizlemek, API'nizi korumanın yolu olmamalıdır.\n\nBu, API'nize ekstra bir güvenlik katmanı eklemez; path operation'lar bulundukları yerde yine erişilebilir olacaktır.\n\nKodunuzda bir güvenlik açığı varsa, o açık yine var olmaya devam eder.\n\nDokümantasyonu gizlemek, API'nizle nasıl etkileşime geçileceğini anlamayı zorlaştırır ve production'da debug etmeyi de daha zor hale getirebilir. Bu yaklaşım, basitçe [Security through obscurity](https://en.wikipedia.org/wiki/Security_through_obscurity) olarak değerlendirilebilir.\n\nAPI'nizi güvence altına almak istiyorsanız, yapabileceğiniz daha iyi birçok şey var; örneğin:\n\n* request body'leriniz ve response'larınız için iyi tanımlanmış Pydantic model'larına sahip olduğunuzdan emin olun.\n* dependencies kullanarak gerekli izinleri ve rolleri yapılandırın.\n* Asla düz metin (plaintext) şifre saklamayın, yalnızca password hash'leri saklayın.\n* pwdlib ve JWT token'ları gibi, iyi bilinen kriptografik araçları uygulayın ve kullanın.\n* Gerektiğinde OAuth2 scope'ları ile daha ayrıntılı izin kontrolleri ekleyin.\n* ...vb.\n\nYine de, bazı ortamlarda (örn. production) veya environment variable'lardan gelen konfigürasyonlara bağlı olarak API docs'u gerçekten devre dışı bırakmanız gereken çok spesifik bir use case'iniz olabilir.\n\n## Ayarlar ve env var'lar ile koşullu OpenAPI { #conditional-openapi-from-settings-and-env-vars }\n\nÜretilen OpenAPI'yi ve docs UI'larını yapılandırmak için aynı Pydantic settings'i kolayca kullanabilirsiniz.\n\nÖrneğin:\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\nBurada `openapi_url` ayarını, varsayılanı `\"/openapi.json\"` olacak şekilde tanımlıyoruz.\n\nArdından `FastAPI` app'ini oluştururken bunu kullanıyoruz.\n\nSonrasında, environment variable `OPENAPI_URL`'i boş string olarak ayarlayarak OpenAPI'yi (UI docs dahil) devre dışı bırakabilirsiniz; örneğin:\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nBöylece `/openapi.json`, `/docs` veya `/redoc` URL'lerine giderseniz, aşağıdaki gibi bir `404 Not Found` hatası alırsınız:\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/tr/docs/how-to/configure-swagger-ui.md",
    "content": "# Swagger UI'yi Yapılandırın { #configure-swagger-ui }\n\nBazı ek [Swagger UI parametrelerini](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/) yapılandırabilirsiniz.\n\nBunları yapılandırmak için, `FastAPI()` uygulama nesnesini oluştururken ya da `get_swagger_ui_html()` fonksiyonuna `swagger_ui_parameters` argümanını verin.\n\n`swagger_ui_parameters`, Swagger UI'ye doğrudan iletilecek yapılandırmaları içeren bir `dict` alır.\n\nFastAPI, Swagger UI'nin ihtiyaç duyduğu şekilde JavaScript ile uyumlu olsun diye bu yapılandırmaları **JSON**'a dönüştürür.\n\n## Syntax Highlighting'i Devre Dışı Bırakın { #disable-syntax-highlighting }\n\nÖrneğin, Swagger UI'de syntax highlighting'i devre dışı bırakabilirsiniz.\n\nAyarları değiştirmeden bırakırsanız, syntax highlighting varsayılan olarak etkindir:\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\nAncak `syntaxHighlight` değerini `False` yaparak devre dışı bırakabilirsiniz:\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n...ve ardından Swagger UI artık syntax highlighting'i göstermeyecektir:\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## Temayı Değiştirin { #change-the-theme }\n\nAynı şekilde, `\"syntaxHighlight.theme\"` anahtarıyla (ortasında bir nokta olduğuna dikkat edin) syntax highlighting temasını ayarlayabilirsiniz:\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\nBu yapılandırma, syntax highlighting renk temasını değiştirir:\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## Varsayılan Swagger UI Parametrelerini Değiştirin { #change-default-swagger-ui-parameters }\n\nFastAPI, çoğu kullanım senaryosu için uygun bazı varsayılan yapılandırma parametreleriyle gelir.\n\nŞu varsayılan yapılandırmaları içerir:\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\n`swagger_ui_parameters` argümanında farklı bir değer vererek bunların herhangi birini ezebilirsiniz (override).\n\nÖrneğin `deepLinking`'i devre dışı bırakmak için `swagger_ui_parameters`'a şu ayarları geçebilirsiniz:\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## Diğer Swagger UI Parametreleri { #other-swagger-ui-parameters }\n\nKullanabileceğiniz diğer tüm olası yapılandırmaları görmek için, resmi [Swagger UI parametreleri dokümantasyonunu](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/) okuyun.\n\n## Yalnızca JavaScript Ayarları { #javascript-only-settings }\n\nSwagger UI ayrıca bazı yapılandırmaların **yalnızca JavaScript** nesneleri olmasına izin verir (örneğin JavaScript fonksiyonları).\n\nFastAPI, bu yalnızca JavaScript olan `presets` ayarlarını da içerir:\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\nBunlar string değil, **JavaScript** nesneleridir; dolayısıyla bunları Python kodundan doğrudan geçemezsiniz.\n\nBöyle yalnızca JavaScript yapılandırmalarına ihtiyacınız varsa, yukarıdaki yöntemlerden birini kullanabilirsiniz: Swagger UI'nin tüm *path operation*'larını override edin ve ihtiyaç duyduğunuz JavaScript'i elle yazın.\n"
  },
  {
    "path": "docs/tr/docs/how-to/custom-docs-ui-assets.md",
    "content": "# Özel Docs UI Statik Varlıkları (Self-Hosting) { #custom-docs-ui-static-assets-self-hosting }\n\nAPI dokümanları **Swagger UI** ve **ReDoc** kullanır ve bunların her biri bazı JavaScript ve CSS dosyalarına ihtiyaç duyar.\n\nVarsayılan olarak bu dosyalar bir <abbr title=\"Content Delivery Network - İçerik Dağıtım Ağı: Genellikle JavaScript ve CSS gibi statik dosyaları sunan, çoğunlukla birden fazla sunucudan oluşan bir servis. Bu dosyaları istemciye daha yakın bir sunucudan sunarak performansı artırmak için yaygın şekilde kullanılır.\">CDN</abbr> üzerinden servis edilir.\n\nAncak bunu özelleştirmek mümkündür; belirli bir CDN ayarlayabilir veya dosyaları kendiniz servis edebilirsiniz.\n\n## JavaScript ve CSS için Özel CDN { #custom-cdn-for-javascript-and-css }\n\nDiyelim ki farklı bir <abbr title=\"Content Delivery Network - İçerik Dağıtım Ağı\">CDN</abbr> kullanmak istiyorsunuz; örneğin `https://unpkg.com/` kullanmak istiyorsunuz.\n\nBu, örneğin bazı URL'leri kısıtlayan bir ülkede yaşıyorsanız faydalı olabilir.\n\n### Otomatik dokümanları devre dışı bırakın { #disable-the-automatic-docs }\n\nİlk adım, otomatik dokümanları devre dışı bırakmaktır; çünkü varsayılan olarak bunlar varsayılan CDN'i kullanır.\n\nBunları devre dışı bırakmak için `FastAPI` uygulamanızı oluştururken URL'lerini `None` olarak ayarlayın:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### Özel dokümanları ekleyin { #include-the-custom-docs }\n\nŞimdi özel dokümanlar için *path operation*'ları oluşturabilirsiniz.\n\nDokümanlar için HTML sayfalarını üretmek üzere FastAPI'nin dahili fonksiyonlarını yeniden kullanabilir ve gerekli argümanları iletebilirsiniz:\n\n* `openapi_url`: Dokümanların HTML sayfasının API'niz için OpenAPI şemasını alacağı URL. Burada `app.openapi_url` niteliğini kullanabilirsiniz.\n* `title`: API'nizin başlığı.\n* `oauth2_redirect_url`: varsayılanı kullanmak için burada `app.swagger_ui_oauth2_redirect_url` kullanabilirsiniz.\n* `swagger_js_url`: Swagger UI dokümanlarınızın HTML'inin **JavaScript** dosyasını alacağı URL. Bu, özel CDN URL'idir.\n* `swagger_css_url`: Swagger UI dokümanlarınızın HTML'inin **CSS** dosyasını alacağı URL. Bu, özel CDN URL'idir.\n\nReDoc için de benzer şekilde...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip | İpucu\n\n`swagger_ui_redirect` için olan *path operation*, OAuth2 kullandığınızda yardımcı olması için vardır.\n\nAPI'nizi bir OAuth2 sağlayıcısıyla entegre ederseniz kimlik doğrulaması yapabilir, aldığınız kimlik bilgileriyle API dokümanlarına geri dönebilir ve gerçek OAuth2 kimlik doğrulamasını kullanarak onunla etkileşime geçebilirsiniz.\n\nSwagger UI bunu arka planda sizin için yönetir, ancak bu \"redirect\" yardımcısına ihtiyaç duyar.\n\n///\n\n### Test etmek için bir *path operation* oluşturun { #create-a-path-operation-to-test-it }\n\nŞimdi her şeyin çalıştığını test edebilmek için bir *path operation* oluşturun:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### Test edin { #test-it }\n\nArtık [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) adresinden dokümanlarınıza gidebilmeli ve sayfayı yenilediğinizde bu varlıkların yeni CDN'den yüklendiğini görebilmelisiniz.\n\n## Dokümanlar için JavaScript ve CSS'i Self-Hosting ile barındırma { #self-hosting-javascript-and-css-for-docs }\n\nJavaScript ve CSS'i self-hosting ile barındırmak, örneğin uygulamanızın İnternet erişimi olmadan (offline), açık İnternet olmadan veya bir lokal ağ içinde bile çalışmaya devam etmesi gerekiyorsa faydalı olabilir.\n\nBurada bu dosyaları aynı FastAPI uygulamasında nasıl kendiniz servis edeceğinizi ve dokümanların bunları kullanacak şekilde nasıl yapılandırılacağını göreceksiniz.\n\n### Proje dosya yapısı { #project-file-structure }\n\nDiyelim ki projenizin dosya yapısı şöyle:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\nŞimdi bu statik dosyaları saklamak için bir dizin oluşturun.\n\nYeni dosya yapınız şöyle olabilir:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### Dosyaları indirin { #download-the-files }\n\nDokümanlar için gereken statik dosyaları indirin ve `static/` dizinine koyun.\n\nMuhtemelen her bir linke sağ tıklayıp \"Save link as...\" benzeri bir seçenek seçebilirsiniz.\n\n**Swagger UI** şu dosyaları kullanır:\n\n* [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n* [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\n**ReDoc** ise şu dosyayı kullanır:\n\n* [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\nBundan sonra dosya yapınız şöyle görünebilir:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### Statik dosyaları servis edin { #serve-the-static-files }\n\n* `StaticFiles` içe aktarın.\n* Belirli bir path'te bir `StaticFiles()` instance'ını \"mount\" edin.\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### Statik dosyaları test edin { #test-the-static-files }\n\nUygulamanızı başlatın ve [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js) adresine gidin.\n\n**ReDoc** için çok uzun bir JavaScript dosyası görmelisiniz.\n\nŞuna benzer bir şekilde başlayabilir:\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\nBu, uygulamanızdan statik dosyaları servis edebildiğinizi ve dokümanlar için statik dosyaları doğru yere koyduğunuzu doğrular.\n\nŞimdi uygulamayı, dokümanlar için bu statik dosyaları kullanacak şekilde yapılandırabiliriz.\n\n### Statik dosyalar için otomatik dokümanları devre dışı bırakın { #disable-the-automatic-docs-for-static-files }\n\nÖzel CDN kullanırken olduğu gibi, ilk adım otomatik dokümanları devre dışı bırakmaktır; çünkü bunlar varsayılan olarak CDN kullanır.\n\nBunları devre dışı bırakmak için `FastAPI` uygulamanızı oluştururken URL'lerini `None` olarak ayarlayın:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### Statik dosyalar için özel dokümanları ekleyin { #include-the-custom-docs-for-static-files }\n\nÖzel CDN'de olduğu gibi, artık özel dokümanlar için *path operation*'ları oluşturabilirsiniz.\n\nYine FastAPI'nin dahili fonksiyonlarını kullanarak dokümanlar için HTML sayfalarını oluşturabilir ve gerekli argümanları geçebilirsiniz:\n\n* `openapi_url`: Dokümanların HTML sayfasının API'niz için OpenAPI şemasını alacağı URL. Burada `app.openapi_url` niteliğini kullanabilirsiniz.\n* `title`: API'nizin başlığı.\n* `oauth2_redirect_url`: varsayılanı kullanmak için burada `app.swagger_ui_oauth2_redirect_url` kullanabilirsiniz.\n* `swagger_js_url`: Swagger UI dokümanlarınızın HTML'inin **JavaScript** dosyasını alacağı URL. **Artık bunu sizin kendi uygulamanız servis ediyor**.\n* `swagger_css_url`: Swagger UI dokümanlarınızın HTML'inin **CSS** dosyasını alacağı URL. **Artık bunu sizin kendi uygulamanız servis ediyor**.\n\nReDoc için de benzer şekilde...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip | İpucu\n\n`swagger_ui_redirect` için olan *path operation*, OAuth2 kullandığınızda yardımcı olması için vardır.\n\nAPI'nizi bir OAuth2 sağlayıcısıyla entegre ederseniz kimlik doğrulaması yapabilir, aldığınız kimlik bilgileriyle API dokümanlarına geri dönebilir ve gerçek OAuth2 kimlik doğrulamasını kullanarak onunla etkileşime geçebilirsiniz.\n\nSwagger UI bunu arka planda sizin için yönetir, ancak bu \"redirect\" yardımcısına ihtiyaç duyar.\n\n///\n\n### Statik dosyaları test etmek için bir *path operation* oluşturun { #create-a-path-operation-to-test-static-files }\n\nŞimdi her şeyin çalıştığını test edebilmek için bir *path operation* oluşturun:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### Statik Dosyalar UI'ını Test Edin { #test-static-files-ui }\n\nArtık WiFi bağlantınızı kesip [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) adresindeki dokümanlarınıza gidebilmeli ve sayfayı yenileyebilmelisiniz.\n\nVe İnternet olmasa bile API dokümanlarınızı görebilir ve onunla etkileşime geçebilirsiniz.\n"
  },
  {
    "path": "docs/tr/docs/how-to/custom-request-and-route.md",
    "content": "# Özel Request ve APIRoute sınıfı { #custom-request-and-apiroute-class }\n\nBazı durumlarda, `Request` ve `APIRoute` sınıflarının kullandığı mantığı override etmek isteyebilirsiniz.\n\nÖzellikle bu yaklaşım, bir middleware içindeki mantığa iyi bir alternatif olabilir.\n\nÖrneğin, request body uygulamanız tarafından işlenmeden önce okumak veya üzerinde değişiklik yapmak istiyorsanız.\n\n/// danger | Uyarı\n\nBu \"ileri seviye\" bir özelliktir.\n\n**FastAPI**'ye yeni başlıyorsanız bu bölümü atlamak isteyebilirsiniz.\n\n///\n\n## Kullanım senaryoları { #use-cases }\n\nBazı kullanım senaryoları:\n\n* JSON olmayan request body'leri JSON'a dönüştürmek (örn. [`msgpack`](https://msgpack.org/index.html)).\n* gzip ile sıkıştırılmış request body'leri açmak (decompress).\n* Tüm request body'lerini otomatik olarak loglamak.\n\n## Özel request body encoding'lerini ele alma { #handling-custom-request-body-encodings }\n\nGzip request'lerini açmak için özel bir `Request` alt sınıfını nasıl kullanabileceğimize bakalım.\n\nAyrıca, o özel request sınıfını kullanmak için bir `APIRoute` alt sınıfı da oluşturacağız.\n\n### Özel bir `GzipRequest` sınıfı oluşturun { #create-a-custom-gziprequest-class }\n\n/// tip | İpucu\n\nBu, nasıl çalıştığını göstermek için hazırlanmış basit bir örnektir; Gzip desteğine ihtiyacınız varsa sağlanan [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware) bileşenini kullanabilirsiniz.\n\n///\n\nÖnce, uygun bir header mevcut olduğunda body'yi açmak için `Request.body()` metodunu overwrite edecek bir `GzipRequest` sınıfı oluşturuyoruz.\n\nHeader'da `gzip` yoksa body'yi açmayı denemez.\n\nBöylece aynı route sınıfı, gzip ile sıkıştırılmış veya sıkıştırılmamış request'leri handle edebilir.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### Özel bir `GzipRoute` sınıfı oluşturun { #create-a-custom-gziproute-class }\n\nSonra, `GzipRequest`'i kullanacak `fastapi.routing.APIRoute` için özel bir alt sınıf oluşturuyoruz.\n\nBu kez `APIRoute.get_route_handler()` metodunu overwrite edeceğiz.\n\nBu metot bir fonksiyon döndürür. Bu fonksiyon da request'i alır ve response döndürür.\n\nBurada bu fonksiyonu, orijinal request'ten bir `GzipRequest` oluşturmak için kullanıyoruz.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | Teknik Detaylar\n\nBir `Request`'in, request ile ilgili metadata'yı içeren bir Python `dict` olan `request.scope` attribute'u vardır.\n\nBir `Request` ayrıca `request.receive` içerir; bu, request'in body'sini \"almak\" (receive etmek) için kullanılan bir fonksiyondur.\n\n`scope` `dict`'i ve `receive` fonksiyonu, ASGI spesifikasyonunun parçalarıdır.\n\nVe bu iki şey, `scope` ve `receive`, yeni bir `Request` instance'ı oluşturmak için gerekenlerdir.\n\n`Request` hakkında daha fazla bilgi için [Starlette'ın Request dokümantasyonu](https://www.starlette.dev/requests/) bölümüne bakın.\n\n///\n\n`GzipRequest.get_route_handler` tarafından döndürülen fonksiyonun farklı yaptığı tek şey, `Request`'i bir `GzipRequest`'e dönüştürmektir.\n\nBunu yaptığımızda `GzipRequest`, veriyi (gerekliyse) *path operations*'larımıza geçirmeden önce açma (decompress) işini üstlenir.\n\nBundan sonra tüm işleme mantığı aynıdır.\n\nAncak `GzipRequest.body` içindeki değişikliklerimiz sayesinde, request body gerektiğinde **FastAPI** tarafından yüklendiğinde otomatik olarak decompress edilir.\n\n## Bir exception handler içinde request body'ye erişme { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip | İpucu\n\nAynı problemi çözmek için, muhtemelen `RequestValidationError` için özel bir handler içinde `body` kullanmak çok daha kolaydır ([Hataları Ele Alma](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)).\n\nYine de bu örnek geçerlidir ve dahili bileşenlerle nasıl etkileşime geçileceğini gösterir.\n\n///\n\nAynı yaklaşımı bir exception handler içinde request body'ye erişmek için de kullanabiliriz.\n\nTek yapmamız gereken, request'i bir `try`/`except` bloğu içinde handle etmek:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\nBir exception oluşursa, `Request` instance'ı hâlâ scope içinde olacağı için, hatayı handle ederken request body'yi okuyup kullanabiliriz:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## Bir router içinde özel `APIRoute` sınıfı { #custom-apiroute-class-in-a-router }\n\nBir `APIRouter` için `route_class` parametresini de ayarlayabilirsiniz:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\nBu örnekte, `router` altındaki *path operations*'lar özel `TimedRoute` sınıfını kullanır ve response'u üretmek için geçen süreyi içeren ekstra bir `X-Response-Time` header'ı response'ta bulunur:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/tr/docs/how-to/extending-openapi.md",
    "content": "# OpenAPI'yi Genişletme { #extending-openapi }\n\nOluşturulan OpenAPI şemasını değiştirmeniz gereken bazı durumlar olabilir.\n\nBu bölümde bunun nasıl yapılacağını göreceksiniz.\n\n## Normal Süreç { #the-normal-process }\n\nNormal (varsayılan) süreç şöyledir.\n\nBir `FastAPI` uygulamasının (instance) OpenAPI şemasını döndürmesi beklenen bir `.openapi()` metodu vardır.\n\nUygulama nesnesi oluşturulurken, `/openapi.json` (ya da `openapi_url` için ne ayarladıysanız o) için bir *path operation* kaydedilir.\n\nBu path operation, uygulamanın `.openapi()` metodunun sonucunu içeren bir JSON response döndürür.\n\nVarsayılan olarak `.openapi()` metodunun yaptığı şey, `.openapi_schema` özelliğinde içerik olup olmadığını kontrol etmek ve varsa onu döndürmektir.\n\nEğer yoksa, `fastapi.openapi.utils.get_openapi` konumundaki yardımcı (utility) fonksiyonu kullanarak şemayı üretir.\n\nVe `get_openapi()` fonksiyonu şu parametreleri alır:\n\n* `title`: Dokümanlarda gösterilen OpenAPI başlığı.\n* `version`: API'nizin sürümü, örn. `2.5.0`.\n* `openapi_version`: Kullanılan OpenAPI specification sürümü. Varsayılan olarak en günceli: `3.1.0`.\n* `summary`: API'nin kısa özeti.\n* `description`: API'nizin açıklaması; markdown içerebilir ve dokümanlarda gösterilir.\n* `routes`: route'ların listesi; bunların her biri kayıtlı *path operations*'lardır. `app.routes` içinden alınırlar.\n\n/// info | Bilgi\n\n`summary` parametresi OpenAPI 3.1.0 ve üzeri sürümlerde vardır; FastAPI 0.99.0 ve üzeri tarafından desteklenmektedir.\n\n///\n\n## Varsayılanları Ezme { #overriding-the-defaults }\n\nYukarıdaki bilgileri kullanarak aynı yardımcı fonksiyonla OpenAPI şemasını üretebilir ve ihtiyacınız olan her parçayı override edebilirsiniz.\n\nÖrneğin, [özel bir logo eklemek için ReDoc'un OpenAPI extension'ını](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo) ekleyelim.\n\n### Normal **FastAPI** { #normal-fastapi }\n\nÖnce, tüm **FastAPI** uygulamanızı her zamanki gibi yazın:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### OpenAPI Şemasını Üretme { #generate-the-openapi-schema }\n\nArdından, bir `custom_openapi()` fonksiyonunun içinde aynı yardımcı fonksiyonu kullanarak OpenAPI şemasını üretin:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### OpenAPI Şemasını Değiştirme { #modify-the-openapi-schema }\n\nArtık OpenAPI şemasındaki `info` \"object\"'ine özel bir `x-logo` ekleyerek ReDoc extension'ını ekleyebilirsiniz:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### OpenAPI Şemasını Cache'leme { #cache-the-openapi-schema }\n\nÜrettiğiniz şemayı saklamak için `.openapi_schema` özelliğini bir \"cache\" gibi kullanabilirsiniz.\n\nBöylece bir kullanıcı API docs'larınızı her açtığında uygulamanız şemayı tekrar tekrar üretmek zorunda kalmaz.\n\nŞema yalnızca bir kez üretilecektir; sonraki request'ler için de aynı cache'lenmiş şema kullanılacaktır.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### Metodu Override Etme { #override-the-method }\n\nŞimdi `.openapi()` metodunu yeni fonksiyonunuzla değiştirebilirsiniz.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### Kontrol Edin { #check-it }\n\n[http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) adresine gittiğinizde, özel logonuzu kullandığınızı göreceksiniz (bu örnekte **FastAPI**'nin logosu):\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/tr/docs/how-to/general.md",
    "content": "# Genel - Nasıl Yapılır - Tarifler { #general-how-to-recipes }\n\nBu sayfada genel veya sık sorulan sorular için dokümantasyonun diğer bölümlerine çeşitli yönlendirmeler bulunmaktadır.\n\n## Veri Filtreleme - Güvenlik { #filter-data-security }\n\nDöndürmeniz gerekenden daha fazla veri döndürmediğinizden emin olmak için, [Tutorial - Response Model - Return Type](../tutorial/response-model.md) dokümantasyonunu okuyun.\n\n## Response Performansını Optimize Etme - Response Model - Return Type { #optimize-response-performance-response-model-return-type }\n\nJSON veri döndürürken performansı optimize etmek için bir return type veya response model kullanın; böylece Pydantic serileştirmeyi Python'dan geçmeden Rust tarafında gerçekleştirir. Ayrıntılar için [Tutorial - Response Model - Return Type](../tutorial/response-model.md) dokümantasyonunu okuyun.\n\n## Dokümantasyon Etiketleri - OpenAPI { #documentation-tags-openapi }\n\n*path operation*'larınıza etiketler eklemek ve dokümantasyon arayüzünde gruplamak için, [Tutorial - Path Operation Configurations - Tags](../tutorial/path-operation-configuration.md#tags) dokümantasyonunu okuyun.\n\n## Dokümantasyon Özeti ve Açıklaması - OpenAPI { #documentation-summary-and-description-openapi }\n\n*path operation*'larınıza özet ve açıklama eklemek ve bunları dokümantasyon arayüzünde göstermek için, [Tutorial - Path Operation Configurations - Summary and Description](../tutorial/path-operation-configuration.md#summary-and-description) dokümantasyonunu okuyun.\n\n## Dokümantasyon Response Açıklaması - OpenAPI { #documentation-response-description-openapi }\n\nDokümantasyon arayüzünde gösterilen response açıklamasını tanımlamak için, [Tutorial - Path Operation Configurations - Response description](../tutorial/path-operation-configuration.md#response-description) dokümantasyonunu okuyun.\n\n## Dokümantasyonda Bir *Path Operation*'ı Kullanımdan Kaldırma - OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\nBir *path operation*'ı kullanımdan kaldırmak ve bunu dokümantasyon arayüzünde göstermek için, [Tutorial - Path Operation Configurations - Deprecation](../tutorial/path-operation-configuration.md#deprecate-a-path-operation) dokümantasyonunu okuyun.\n\n## Herhangi Bir Veriyi JSON Uyumlu Hale Getirme { #convert-any-data-to-json-compatible }\n\nHerhangi bir veriyi JSON uyumlu hale getirmek için, [Tutorial - JSON Compatible Encoder](../tutorial/encoder.md) dokümantasyonunu okuyun.\n\n## OpenAPI Meta Verileri - Dokümantasyon { #openapi-metadata-docs }\n\nLisans, sürüm, iletişim vb. dahil olmak üzere OpenAPI şemanıza meta veriler eklemek için, [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md) dokümantasyonunu okuyun.\n\n## OpenAPI Özel URL { #openapi-custom-url }\n\nOpenAPI URL'ini özelleştirmek (veya kaldırmak) için, [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#openapi-url) dokümantasyonunu okuyun.\n\n## OpenAPI Dokümantasyon URL'leri { #openapi-docs-urls }\n\nOtomatik olarak oluşturulan dokümantasyon kullanıcı arayüzlerinde kullanılan URL'leri güncellemek için, [Tutorial - Metadata and Docs URLs](../tutorial/metadata.md#docs-urls) dokümantasyonunu okuyun.\n"
  },
  {
    "path": "docs/tr/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\n**FastAPI**, **ASGI** standardını temel aldığı için ASGI ile uyumlu herhangi bir **GraphQL** kütüphanesini entegre etmek oldukça kolaydır.\n\nAynı uygulama içinde normal FastAPI *path operation*'larını GraphQL ile birlikte kullanabilirsiniz.\n\n/// tip | İpucu\n\n**GraphQL** bazı çok özel kullanım senaryolarını çözer.\n\nYaygın **web API**'lerle karşılaştırıldığında **avantajları** ve **dezavantajları** vardır.\n\nKendi senaryonuz için **faydaların**, **olumsuz yönleri** telafi edip etmediğini mutlaka değerlendirin. 🤓\n\n///\n\n## GraphQL Kütüphaneleri { #graphql-libraries }\n\nAşağıda **ASGI** desteği olan bazı **GraphQL** kütüphaneleri var. Bunları **FastAPI** ile kullanabilirsiniz:\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * [FastAPI dokümantasyonu](https://strawberry.rocks/docs/integrations/fastapi) ile\n* [Ariadne](https://ariadnegraphql.org/)\n    * [FastAPI dokümantasyonu](https://ariadnegraphql.org/docs/fastapi-integration) ile\n* [Tartiflette](https://tartiflette.io/)\n    * ASGI entegrasyonu sağlamak için [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) ile\n* [Graphene](https://graphene-python.org/)\n    * [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3) ile\n\n## Strawberry ile GraphQL { #graphql-with-strawberry }\n\n**GraphQL** ile çalışmanız gerekiyorsa ya da bunu istiyorsanız, [**Strawberry**](https://strawberry.rocks/) önerilen kütüphanedir; çünkü tasarımı **FastAPI**'nin tasarımına en yakındır ve her şey **type annotation**'lar üzerine kuruludur.\n\nKullanım senaryonuza göre farklı bir kütüphaneyi tercih edebilirsiniz; ancak bana sorarsanız muhtemelen **Strawberry**'yi denemenizi önerirdim.\n\nStrawberry'yi FastAPI ile nasıl entegre edebileceğinize dair küçük bir ön izleme:\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\nStrawberry hakkında daha fazlasını [Strawberry dokümantasyonunda](https://strawberry.rocks/) öğrenebilirsiniz.\n\nAyrıca [FastAPI ile Strawberry](https://strawberry.rocks/docs/integrations/fastapi) dokümanlarına da göz atın.\n\n## Starlette'teki Eski `GraphQLApp` { #older-graphqlapp-from-starlette }\n\nStarlette'in önceki sürümlerinde [Graphene](https://graphene-python.org/) ile entegrasyon için bir `GraphQLApp` sınıfı vardı.\n\nBu sınıf Starlette'te kullanımdan kaldırıldı (deprecated). Ancak bunu kullanan bir kodunuz varsa, aynı kullanım senaryosunu kapsayan ve **neredeyse aynı bir interface** sağlayan [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)'e kolayca **migrate** edebilirsiniz.\n\n/// tip | İpucu\n\nGraphQL'e ihtiyacınız varsa, custom class ve type'lar yerine type annotation'lara dayandığı için yine de [Strawberry](https://strawberry.rocks/)'yi incelemenizi öneririm.\n\n///\n\n## Daha Fazlasını Öğrenin { #learn-more }\n\n**GraphQL** hakkında daha fazlasını [resmi GraphQL dokümantasyonunda](https://graphql.org/) öğrenebilirsiniz.\n\nAyrıca yukarıda bahsedilen kütüphanelerin her biri hakkında, kendi bağlantılarından daha fazla bilgi okuyabilirsiniz.\n"
  },
  {
    "path": "docs/tr/docs/how-to/index.md",
    "content": "# Nasıl Yapılır - Tarifler { #how-to-recipes }\n\nBurada **çeşitli konular** hakkında farklı tarifler veya \"nasıl yapılır\" kılavuzları göreceksiniz.\n\nBu fikirlerin büyük bir kısmı aşağı yukarı **bağımsız** olacaktır ve çoğu durumda bunları yalnızca doğrudan **projenize** uygulanıyorsa incelemeniz yeterli olacaktır.\n\nProjeniz için ilginç ve yararlı görünen bir şey varsa devam edin ve inceleyin; aksi halde muhtemelen bunları atlayabilirsiniz.\n\n/// tip | İpucu\n\n**FastAPI**'yi yapılandırılmış bir şekilde (önerilir) **öğrenmek** istiyorsanız bunun yerine [Öğretici - Kullanıcı Rehberi](../tutorial/index.md)'ni bölüm bölüm okuyun.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# Pydantic v1'den Pydantic v2'ye Geçiş { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\nEski bir FastAPI uygulamanız varsa, Pydantic'in 1. sürümünü kullanıyor olabilirsiniz.\n\nFastAPI 0.100.0 sürümü, Pydantic v1 veya v2 ile çalışmayı destekliyordu. Hangisi kuruluysa onu kullanıyordu.\n\nFastAPI 0.119.0 sürümü, v2'ye geçişi kolaylaştırmak için, Pydantic v2’nin içinden Pydantic v1’e (`pydantic.v1` olarak) kısmi destek ekledi.\n\nFastAPI 0.126.0 sürümü Pydantic v1 desteğini kaldırdı, ancak bir süre daha `pydantic.v1` desteğini sürdürdü.\n\n/// warning | Uyarı\n\nPydantic ekibi, Python'ın en yeni sürümleri için Pydantic v1 desteğini, **Python 3.14** ile başlayarak sonlandırdı.\n\nBuna `pydantic.v1` de dahildir; Python 3.14 ve üzeri sürümlerde artık desteklenmemektedir.\n\nPython'ın en yeni özelliklerini kullanmak istiyorsanız, Pydantic v2 kullandığınızdan emin olmanız gerekir.\n\n///\n\nPydantic v1 kullanan eski bir FastAPI uygulamanız varsa, burada onu Pydantic v2'ye nasıl taşıyacağınızı ve kademeli geçişi kolaylaştıran **FastAPI 0.119.0 özelliklerini** göstereceğim.\n\n## Resmi Kılavuz { #official-guide }\n\nPydantic'in v1'den v2'ye resmi bir [Migration Guide](https://docs.pydantic.dev/latest/migration/)'ı vardır.\n\nAyrıca nelerin değiştiğini, validasyonların artık nasıl daha doğru ve katı olduğunu, olası dikkat edilmesi gereken noktaları (caveat) vb. de içerir.\n\nNelerin değiştiğini daha iyi anlamak için okuyabilirsiniz.\n\n## Testler { #tests }\n\nUygulamanız için [testleriniz](../tutorial/testing.md) olduğundan ve bunları continuous integration (CI) üzerinde çalıştırdığınızdan emin olun.\n\nBu şekilde yükseltmeyi yapabilir ve her şeyin hâlâ beklendiği gibi çalıştığını doğrulayabilirsiniz.\n\n## `bump-pydantic` { #bump-pydantic }\n\nBirçok durumda, özel özelleştirmeler olmadan standart Pydantic modelleri kullanıyorsanız, Pydantic v1'den Pydantic v2'ye geçiş sürecinin büyük kısmını otomatikleştirebilirsiniz.\n\nAynı Pydantic ekibinin geliştirdiği [`bump-pydantic`](https://github.com/pydantic/bump-pydantic) aracını kullanabilirsiniz.\n\nBu araç, değişmesi gereken kodun büyük bir kısmını otomatik olarak dönüştürmenize yardımcı olur.\n\nBundan sonra testleri çalıştırıp her şeyin çalışıp çalışmadığını kontrol edebilirsiniz. Çalışıyorsa işiniz biter. 😎\n\n## v2 İçinde Pydantic v1 { #pydantic-v1-in-v2 }\n\nPydantic v2, `pydantic.v1` adlı bir alt modül olarak Pydantic v1'in tamamını içerir. Ancak bu yapı, Python 3.13'ün üzerindeki sürümlerde artık desteklenmemektedir.\n\nBu da şu anlama gelir: Pydantic v2'nin en güncel sürümünü kurup, bu alt modülden eski Pydantic v1 bileşenlerini import ederek, sanki eski Pydantic v1 kuruluymuş gibi kullanabilirsiniz.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### v2 İçinde Pydantic v1 için FastAPI Desteği { #fastapi-support-for-pydantic-v1-in-v2 }\n\nFastAPI 0.119.0'dan itibaren, v2'ye geçişi kolaylaştırmak için Pydantic v2’nin içinden Pydantic v1 kullanımına yönelik kısmi destek de vardır.\n\nDolayısıyla Pydantic'i en güncel 2 sürümüne yükseltip import'ları `pydantic.v1` alt modülünü kullanacak şekilde değiştirebilirsiniz; çoğu durumda bu doğrudan çalışır.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning | Uyarı\n\nPydantic ekibi Python 3.14'ten itibaren yeni Python sürümlerinde Pydantic v1'i artık desteklemediği için, `pydantic.v1` kullanımı da Python 3.14 ve üzeri sürümlerde desteklenmez.\n\n///\n\n### Aynı Uygulamada Pydantic v1 ve v2 { #pydantic-v1-and-v2-on-the-same-app }\n\nPydantic açısından, alanları (field) Pydantic v1 modelleriyle tanımlanmış bir Pydantic v2 modeli (ya da tersi) kullanmak **desteklenmez**.\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n...ancak aynı uygulamada Pydantic v1 ve v2 kullanarak **ayrı** modeller tanımlayabilirsiniz.\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\nBazı durumlarda, FastAPI uygulamanızda aynı **path operation** içinde hem Pydantic v1 hem de v2 modellerini kullanmak bile mümkündür:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\nYukarıdaki örnekte input modeli bir Pydantic v1 modelidir; output modeli ( `response_model=ItemV2` ile tanımlanan) ise bir Pydantic v2 modelidir.\n\n### Pydantic v1 Parametreleri { #pydantic-v1-parameters }\n\nPydantic v1 modelleriyle `Body`, `Query`, `Form` vb. parametreler için FastAPI'ye özgü bazı araçları kullanmanız gerekiyorsa, Pydantic v2'ye geçişi tamamlayana kadar bunları `fastapi.temp_pydantic_v1_params` içinden import edebilirsiniz:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### Adım Adım Geçiş { #migrate-in-steps }\n\n/// tip | İpucu\n\nÖnce `bump-pydantic` ile deneyin; testleriniz geçerse ve bu yol çalışırsa tek komutla işi bitirmiş olursunuz. ✨\n\n///\n\n`bump-pydantic` sizin senaryonuz için uygun değilse, aynı uygulamada hem Pydantic v1 hem de v2 modellerini birlikte kullanma desteğinden yararlanarak Pydantic v2'ye kademeli şekilde geçebilirsiniz.\n\nÖnce Pydantic'i en güncel 2 sürümüne yükseltip tüm modelleriniz için import'ları `pydantic.v1` kullanacak şekilde değiştirebilirsiniz.\n\nArdından modellerinizi Pydantic v1'den v2'ye gruplar hâlinde, adım adım taşımaya başlayabilirsiniz. 🚶\n"
  },
  {
    "path": "docs/tr/docs/how-to/separate-openapi-schemas.md",
    "content": "# Input ve Output için Ayrı OpenAPI Schema'ları (Ya da Değil) { #separate-openapi-schemas-for-input-and-output-or-not }\n\n**Pydantic v2** yayınlandığından beri, üretilen OpenAPI eskisine göre biraz daha net ve **doğru**. 😎\n\nHatta bazı durumlarda, aynı Pydantic model için OpenAPI içinde input ve output tarafında, **default değerler** olup olmamasına bağlı olarak **iki farklı JSON Schema** bile görebilirsiniz.\n\nBunun nasıl çalıştığına ve gerekirse nasıl değiştirebileceğinize bir bakalım.\n\n## Input ve Output için Pydantic Modelleri { #pydantic-models-for-input-and-output }\n\nDefault değerleri olan bir Pydantic modeliniz olduğunu varsayalım; örneğin şöyle:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### Input için Model { #model-for-input }\n\nBu modeli şöyle input olarak kullanırsanız:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n...`description` alanı **zorunlu olmaz**. Çünkü `None` default değerine sahiptir.\n\n### Dokümanlarda Input Modeli { #input-model-in-docs }\n\nBunu dokümanlarda da doğrulayabilirsiniz; `description` alanında **kırmızı yıldız** yoktur, yani required olarak işaretlenmemiştir:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### Output için Model { #model-for-output }\n\nAncak aynı modeli output olarak şöyle kullanırsanız:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n...`description` default değere sahip olduğu için, o alan için **hiçbir şey döndürmeseniz** bile yine de **o default değeri** alır.\n\n### Output Response Verisi için Model { #model-for-output-response-data }\n\nDokümanlarla etkileşip response'u kontrol ederseniz, kod `description` alanlarından birine bir şey eklememiş olsa bile, JSON response default değeri (`null`) içerir:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\nBu, alanın **her zaman bir değeri olacağı** anlamına gelir; sadece bazen bu değer `None` olabilir (JSON'da `null`).\n\nDolayısıyla API'nizi kullanan client'ların bu değerin var olup olmadığını kontrol etmesine gerek yoktur; **alanın her zaman mevcut olacağını varsayabilirler**, sadece bazı durumlarda default değer olan `None` gelecektir.\n\nBunu OpenAPI'de ifade etmenin yolu, bu alanı **required** olarak işaretlemektir; çünkü her zaman yer alacaktır.\n\nBu nedenle, bir modelin JSON Schema'sı **input mu output mu** kullanıldığına göre farklı olabilir:\n\n* **input** için `description` **required olmaz**\n* **output** için **required olur** (ve `None` olabilir; JSON açısından `null`)\n\n### Dokümanlarda Output Modeli { #model-for-output-in-docs }\n\nDokümanlarda output modelini de kontrol edebilirsiniz; **hem** `name` **hem de** `description` alanları **kırmızı yıldız** ile **required** olarak işaretlenmiştir:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### Dokümanlarda Input ve Output Modelleri { #model-for-input-and-output-in-docs }\n\nOpenAPI içindeki tüm kullanılabilir Schema'lara (JSON Schema'lara) bakarsanız, iki tane olduğunu göreceksiniz: biri `Item-Input`, diğeri `Item-Output`.\n\n`Item-Input` için `description` **required değildir**, kırmızı yıldız yoktur.\n\nAma `Item-Output` için `description` **required**'dır, kırmızı yıldız vardır.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\n**Pydantic v2**'nin bu özelliğiyle API dokümantasyonunuz daha **hassas** olur; ayrıca autogenerated client'lar ve SDK'lar kullanıyorsanız, onlar da daha tutarlı ve daha iyi bir **developer experience** ile daha doğru üretilir. 🎉\n\n## Schema'ları Ayırma { #do-not-separate-schemas }\n\nBazı durumlarda **input ve output için aynı schema'yı** kullanmak isteyebilirsiniz.\n\nBunun muhtemelen en yaygın nedeni, halihazırda autogenerated client kodlarınız/SDK'larınızın olması ve henüz bunların hepsini güncellemek istememenizdir. Büyük ihtimalle bir noktada güncellemek isteyeceksiniz, ama belki şu an değil.\n\nBu durumda **FastAPI**'de bu özelliği `separate_input_output_schemas=False` parametresiyle kapatabilirsiniz.\n\n/// info | Bilgi\n\n`separate_input_output_schemas` desteği FastAPI `0.102.0` sürümünde eklendi. 🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### Dokümanlarda Input ve Output Modelleri için Aynı Schema { #same-schema-for-input-and-output-models-in-docs }\n\nArtık model için input ve output tarafında tek bir schema olur: sadece `Item`. Ayrıca `description` alanı **required değildir**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/tr/docs/how-to/testing-database.md",
    "content": "# Bir Veritabanını Test Etmek { #testing-a-database }\n\nVeritabanları, SQL ve SQLModel hakkında [SQLModel dokümantasyonundan](https://sqlmodel.tiangolo.com/) öğrenebilirsiniz. 🤓\n\nAyrıca SQLModel'i FastAPI ile kullanmaya dair mini bir [öğretici](https://sqlmodel.tiangolo.com/tutorial/fastapi/) da var. ✨\n\nBu tutorial içinde [SQL veritabanlarını test etme](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/) hakkında bir bölüm de bulunuyor. 😎\n"
  },
  {
    "path": "docs/tr/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/tr\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>FastAPI framework, yüksek performanslı, öğrenmesi kolay, kodlaması hızlı, production'a hazır</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**Dokümantasyon**: [https://fastapi.tiangolo.com/tr](https://fastapi.tiangolo.com/tr)\n\n**Kaynak Kod**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI, Python'un standart type hints'lerine dayalı olarak Python ile API'lar oluşturmak için kullanılan modern ve hızlı (yüksek performanslı) bir web framework'üdür.\n\nTemel özellikleri şunlardır:\n\n* **Hızlı**: Çok yüksek performanslı, **NodeJS** ve **Go** ile eşit düzeyde (Starlette ve Pydantic sayesinde). [Mevcut en hızlı Python framework'lerinden biri](#performance).\n* **Kodlaması Hızlı**: Özellik geliştirme hızını yaklaşık %200 ile %300 aralığında artırır. *\n* **Daha az hata**: İnsan (geliştirici) kaynaklı hataları yaklaşık %40 azaltır. *\n* **Sezgisel**: Harika bir editör desteği. Her yerde <dfn title=\"oto-tamamlama, autocompletion, IntelliSense olarak da bilinir\">Tamamlama</dfn>. Hata ayıklamaya daha az zaman.\n* **Kolay**: Kullanımı ve öğrenmesi kolay olacak şekilde tasarlandı. Doküman okumaya daha az zaman.\n* **Kısa**: Kod tekrarını minimize eder. Her parametre tanımından birden fazla özellik. Daha az hata.\n* **Sağlam**: Production'a hazır kod elde edersiniz. Otomatik etkileşimli dokümantasyon ile birlikte.\n* **Standardlara dayalı**: API'lar için açık standartlara dayalıdır (ve tamamen uyumludur); [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (önceden Swagger olarak biliniyordu) ve [JSON Schema](https://json-schema.org/).\n\n<small>* tahmin, production uygulamalar geliştiren dahili bir geliştirme ekibinin yaptığı testlere dayanmaktadır.</small>\n\n## Sponsorlar { #sponsors }\n\n<!-- sponsors -->\n\n### Keystone Sponsor { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### Gold and Silver Sponsors { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[Diğer sponsorlar](https://fastapi.tiangolo.com/tr/fastapi-people/#sponsors)\n\n## Görüşler { #opinions }\n\n\"_[...] Bugünlerde **FastAPI**'ı çok fazla kullanıyorum. [...] Aslında bunu ekibimin **Microsoft'taki ML servislerinin** tamamında kullanmayı planlıyorum. Bunlardan bazıları ana **Windows** ürününe ve bazı **Office** ürünlerine entegre ediliyor._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n\"_**predictions** almak için sorgulanabilecek bir **REST** server oluşturmak amacıyla **FastAPI** kütüphanesini benimsedik. [Ludwig için]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n\"_**Netflix**, **kriz yönetimi** orkestrasyon framework'ümüz: **Dispatch**'in open-source sürümünü duyurmaktan memnuniyet duyar! [**FastAPI** ile geliştirildi]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n\"_**FastAPI** için ayın üzerindeymişcesine heyecanlıyım. Çok eğlenceli!_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken - <strong>[Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855) podcast host</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(ref)</small></a></div>\n\n---\n\n\"_Dürüst olmak gerekirse, inşa ettiğiniz şey gerçekten sağlam ve profesyonel görünüyor. Birçok açıdan, **Hug**'ın olmasını istediğim şey tam da bu - böyle bir şeyi inşa eden birini görmek gerçekten ilham verici._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley - <strong>[Hug](https://github.com/hugapi/hug) yaratıcısı</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(ref)</small></a></div>\n\n---\n\n\"_REST API'lar geliştirmek için **modern bir framework** öğrenmek istiyorsanız, **FastAPI**'a bir göz atın [...] Hızlı, kullanımı ve öğrenmesi kolay [...]_\"\n\n\"_**API**'larımız için **FastAPI**'a geçtik [...] Bence hoşunuza gidecek [...]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani - Matthew Honnibal - <strong>[Explosion AI](https://explosion.ai) kurucuları - [spaCy](https://spacy.io) yaratıcıları</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(ref)</small></a> - <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(ref)</small></a></div>\n\n---\n\n\"_Production'da Python API geliştirmek isteyen herkese **FastAPI**'ı şiddetle tavsiye ederim. **Harika tasarlanmış**, **kullanımı kolay** ve **yüksek ölçeklenebilir**; API-first geliştirme stratejimizin **kilit bir bileşeni** haline geldi ve Virtual TAC Engineer gibi birçok otomasyon ve servise güç veriyor._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n## FastAPI mini belgeseli { #fastapi-mini-documentary }\n\n2025'in sonunda yayınlanan bir [FastAPI mini belgeseli](https://www.youtube.com/watch?v=mpR8ngthqiE) var, online olarak izleyebilirsiniz:\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## CLI'ların FastAPI'ı: **Typer** { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\nWeb API yerine terminalde kullanılacak bir <abbr title=\"Command Line Interface - Komut Satırı Arayüzü\">CLI</abbr> uygulaması geliştiriyorsanız [**Typer**](https://typer.tiangolo.com/)'a göz atın.\n\n**Typer**, FastAPI'ın küçük kardeşi. Ve hedefi CLI'ların **FastAPI'ı** olmak. ⌨️ 🚀\n\n## Gereksinimler { #requirements }\n\nFastAPI iki devin omuzları üstünde duruyor:\n\n* Web kısımları için [Starlette](https://www.starlette.dev/).\n* Data kısımları için [Pydantic](https://docs.pydantic.dev/).\n\n## Kurulum { #installation }\n\nBir [virtual environment](https://fastapi.tiangolo.com/tr/virtual-environments/) oluşturup etkinleştirelim ve ardından FastAPI'ı yükleyelim:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Not**: Tüm terminallerde çalıştığından emin olmak için `\"fastapi[standard]\"` ifadesini tırnak içinde yazdığınızdan emin olun.\n\n## Örnek { #example }\n\n### Oluşturalım { #create-it }\n\nŞu içerikle `main.py` adında bir dosya oluşturalım:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>Ya da <code>async def</code> kullanalım...</summary>\n\nEğer kodunuz `async` / `await` kullanıyorsa, `async def` kullanın:\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Not**:\n\nEğer bilmiyorsanız, dokümanlardaki [`async` ve `await`](https://fastapi.tiangolo.com/tr/async/#in-a-hurry) hakkında _\"Aceleniz mi var?\"_ bölümüne bakın.\n\n</details>\n\n### Çalıştıralım { #run-it }\n\nSunucuyu şu komutla çalıştıralım:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary><code>fastapi dev</code> komutu hakkında...</summary>\n\n`fastapi dev` komutu, `main.py` dosyanızı okur, içindeki **FastAPI** uygulamasını algılar ve [Uvicorn](https://www.uvicorn.dev) kullanarak bir server başlatır.\n\nVarsayılan olarak `fastapi dev`, local geliştirme için auto-reload etkin şekilde başlar.\n\nDaha fazla bilgi için [FastAPI CLI dokümantasyonu](https://fastapi.tiangolo.com/tr/fastapi-cli/)'nu okuyabilirsiniz.\n\n</details>\n\n### Kontrol Edelim { #check-it }\n\nTarayıcınızda şu bağlantıyı açın: [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery).\n\nŞu JSON response'unu göreceksiniz:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\nArtık şunları yapan bir API oluşturdunuz:\n\n* `/` ve `/items/{item_id}` _path_'lerinde HTTP request'leri alır.\n* Her iki _path_ de `GET` <em>operasyonlarını</em> (HTTP _method_'ları olarak da bilinir) kabul eder.\n* `/items/{item_id}` _path_'i, `int` olması gereken `item_id` adlı bir _path parameter_'a sahiptir.\n* `/items/{item_id}` _path_'i, opsiyonel `str` bir _query parameter_ olan `q`'ya sahiptir.\n\n### Etkileşimli API dokümantasyonu { #interactive-api-docs }\n\nŞimdi [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) adresine gidin.\n\nOtomatik etkileşimli API dokümantasyonunu göreceksiniz ([Swagger UI](https://github.com/swagger-api/swagger-ui) tarafından sağlanır):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Alternatif API dokümantasyonu { #alternative-api-docs }\n\nVe şimdi [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) adresine gidin.\n\nAlternatif otomatik dokümantasyonu göreceksiniz ([ReDoc](https://github.com/Rebilly/ReDoc) tarafından sağlanır):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Örneği Güncelleyelim { #example-upgrade }\n\nŞimdi `main.py` dosyasını, `PUT` request'iyle gelen bir body alacak şekilde değiştirelim.\n\nBody'yi Pydantic sayesinde standart Python tiplerini kullanarak tanımlayalım.\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n`fastapi dev` server'ı otomatik olarak yeniden yüklemelidir.\n\n### Etkileşimli API dokümantasyonu güncellemesi { #interactive-api-docs-upgrade }\n\nŞimdi [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) adresine gidin.\n\n* Etkileşimli API dokümantasyonu, yeni body dahil olacak şekilde otomatik olarak güncellenecek:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* \"Try it out\" butonuna tıklayın; parametreleri doldurmanıza ve API ile doğrudan etkileşime girmenize olanak sağlar:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* Sonra \"Execute\" butonuna tıklayın; kullanıcı arayüzü API'nız ile iletişim kuracak, parametreleri gönderecek, sonuçları alacak ve ekranda gösterecek:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### Alternatif API dokümantasyonu güncellemesi { #alternative-api-docs-upgrade }\n\nVe şimdi [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) adresine gidin.\n\n* Alternatif dokümantasyon da yeni query parameter ve body'yi yansıtacak:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Özet { #recap }\n\nÖzetle, parametrelerin, body'nin vb. type'larını fonksiyon parametreleri olarak **bir kere** tanımlarsınız.\n\nBunu standart modern Python tipleriyle yaparsınız.\n\nYeni bir syntax, belirli bir kütüphanenin method'larını ya da class'larını vb. öğrenmeniz gerekmez.\n\nSadece standart **Python**.\n\nÖrneğin bir `int` için:\n\n```Python\nitem_id: int\n```\n\nya da daha karmaşık bir `Item` modeli için:\n\n```Python\nitem: Item\n```\n\n...ve bu tek tanımla şunları elde edersiniz:\n\n* Şunlar dahil editör desteği:\n    * Completion.\n    * Type kontrolleri.\n* Verinin doğrulanması:\n    * Veri geçersiz olduğunda otomatik ve anlaşılır hatalar.\n    * Çok derin iç içe JSON nesneleri için bile doğrulama.\n* Girdi verisinin <dfn title=\"şöyle de bilinir: serileştirme, ayrıştırma, marshalling\">Dönüşümü</dfn>: network'ten gelen veriyi Python verisine ve type'larına çevirir. Şunlardan okur:\n    * JSON.\n    * Path parameter'lar.\n    * Query parameter'lar.\n    * Cookie'ler.\n    * Header'lar.\n    * Form'lar.\n    * File'lar.\n* Çıktı verisinin <dfn title=\"şöyle de bilinir: serileştirme, ayrıştırma, marshalling\">Dönüşümü</dfn>: Python verisini ve type'larını network verisine çevirir (JSON olarak):\n    * Python type'larını dönüştürür (`str`, `int`, `float`, `bool`, `list`, vb.).\n    * `datetime` nesneleri.\n    * `UUID` nesneleri.\n    * Veritabanı modelleri.\n    * ...ve daha fazlası.\n* 2 alternatif kullanıcı arayüzü dahil otomatik etkileşimli API dokümantasyonu:\n    * Swagger UI.\n    * ReDoc.\n\n---\n\nÖnceki kod örneğine dönersek, **FastAPI** şunları yapacaktır:\n\n* `GET` ve `PUT` request'leri için path'te `item_id` olduğunu doğrular.\n* `GET` ve `PUT` request'leri için `item_id`'nin type'ının `int` olduğunu doğrular.\n    * Değilse, client faydalı ve anlaşılır bir hata görür.\n* `GET` request'leri için `q` adlı opsiyonel bir query parameter olup olmadığını kontrol eder (`http://127.0.0.1:8000/items/foo?q=somequery` örneğindeki gibi).\n    * `q` parametresi `= None` ile tanımlandığı için opsiyoneldir.\n    * `None` olmasaydı zorunlu olurdu (tıpkı `PUT` örneğindeki body gibi).\n* `/items/{item_id}`'ye yapılan `PUT` request'leri için body'yi JSON olarak okur:\n    * `str` olması gereken, zorunlu `name` alanı olduğunu kontrol eder.\n    * `float` olması gereken, zorunlu `price` alanı olduğunu kontrol eder.\n    * Varsa, `bool` olması gereken opsiyonel `is_offer` alanını kontrol eder.\n    * Bunların hepsi çok derin iç içe JSON nesneleri için de çalışır.\n* JSON'a ve JSON'dan dönüşümü otomatik yapar.\n* Her şeyi OpenAPI ile dokümante eder; bu dokümantasyon şunlar tarafından kullanılabilir:\n    * Etkileşimli dokümantasyon sistemleri.\n    * Birçok dil için otomatik client kodu üretim sistemleri.\n* 2 etkileşimli dokümantasyon web arayüzünü doğrudan sunar.\n\n---\n\nDaha yolun başındayız, ama bunun nasıl çalıştığı hakkında fikri kaptınız.\n\nŞu satırı değiştirmeyi deneyin:\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n...şundan:\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n...şuna:\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n...ve editörünüzün alanları otomatik tamamladığını ve type'larını bildiğini görün:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\nDaha fazla özellik içeren daha kapsamlı bir örnek için <a href=\"https://fastapi.tiangolo.com/tr/tutorial/\">Öğretici - Kullanıcı Rehberi</a>'ne bakın.\n\n**Spoiler alert**: öğretici - kullanıcı rehberi şunları içerir:\n\n* **parameter**'ların farklı yerlerden: **header**'lar, **cookie**'ler, **form alanları** ve **file**'lar olarak tanımlanması.\n* `maximum_length` ya da `regex` gibi **doğrulama kısıtlamalarının** nasıl ayarlanacağı.\n* Çok güçlü ve kullanımı kolay bir **<dfn title=\"şöyle de bilinir: bileşenler, kaynaklar, sağlayıcılar, servisler, enjekte edilebilirler\">Bağımlılık Enjeksiyonu</dfn>** sistemi.\n* **JWT tokens** ve **HTTP Basic** auth ile **OAuth2** desteği dahil güvenlik ve kimlik doğrulama.\n* **Çok derin iç içe JSON modelleri** tanımlamak için daha ileri (ama aynı derecede kolay) teknikler (Pydantic sayesinde).\n* [Strawberry](https://strawberry.rocks) ve diğer kütüphaneler ile **GraphQL** entegrasyonu.\n* Starlette sayesinde gelen birçok ek özellik:\n    * **WebSockets**\n    * HTTPX ve `pytest` tabanlı aşırı kolay testler\n    * **CORS**\n    * **Cookie Sessions**\n    * ...ve daha fazlası.\n\n### Uygulamanızı deploy edin (opsiyonel) { #deploy-your-app-optional }\n\nİsterseniz FastAPI uygulamanızı [FastAPI Cloud](https://fastapicloud.com)'a deploy edebilirsiniz; eğer henüz yapmadıysanız gidip bekleme listesine katılın. 🚀\n\nZaten bir **FastAPI Cloud** hesabınız varsa (bekleme listesinden sizi davet ettiysek 😉), uygulamanızı tek bir komutla deploy edebilirsiniz.\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nHepsi bu! Artık uygulamanıza bu URL'den erişebilirsiniz. ✨\n\n#### FastAPI Cloud hakkında { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)**, **FastAPI**'ın arkasındaki aynı yazar ve ekip tarafından geliştirilmiştir.\n\n**Bir API'ı build etmek**, **deploy etmek** ve **erişmek** süreçlerini minimum eforla kolaylaştırır.\n\nFastAPI ile uygulama geliştirmenin sağladığı aynı **developer experience**'ı, onları cloud'a **deploy etmeye** de taşır. 🎉\n\nFastAPI Cloud, *FastAPI and friends* open source projelerinin ana sponsoru ve finansman sağlayıcısıdır. ✨\n\n#### Diğer cloud sağlayıcılarına deploy { #deploy-to-other-cloud-providers }\n\nFastAPI open source'tur ve standartlara dayanır. FastAPI uygulamalarını seçtiğiniz herhangi bir cloud sağlayıcısına deploy edebilirsiniz.\n\nFastAPI uygulamalarını onlarla deploy etmek için cloud sağlayıcınızın rehberlerini takip edin. 🤓\n\n## Performans { #performance }\n\nBağımsız TechEmpower kıyaslamaları, Uvicorn altında çalışan **FastAPI** uygulamalarının [mevcut en hızlı Python framework'lerinden biri](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7) olduğunu gösteriyor; sadece Starlette ve Uvicorn'un kendisinin gerisinde (FastAPI tarafından dahili olarak kullanılır). (*)\n\nDaha iyi anlamak için [Kıyaslamalar](https://fastapi.tiangolo.com/tr/benchmarks/) bölümüne bakın.\n\n## Bağımlılıklar { #dependencies }\n\nFastAPI, Pydantic ve Starlette'a bağımlıdır.\n\n### `standard` Bağımlılıkları { #standard-dependencies }\n\nFastAPI'ı `pip install \"fastapi[standard]\"` ile yüklediğinizde, opsiyonel bağımlılıkların `standard` grubuyla birlikte gelir:\n\nPydantic tarafından kullanılanlar:\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - email doğrulaması için.\n\nStarlette tarafından kullanılanlar:\n\n* [`httpx`](https://www.python-httpx.org) - `TestClient` kullanmak istiyorsanız gereklidir.\n* [`jinja2`](https://jinja.palletsprojects.com) - varsayılan template yapılandırmasını kullanmak istiyorsanız gereklidir.\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - `request.form()` ile, form <dfn title=\"HTTP request'ten gelen string'i Python verisine dönüştürme\">\"ayrıştırma\"</dfn> desteği istiyorsanız gereklidir.\n\nFastAPI tarafından kullanılanlar:\n\n* [`uvicorn`](https://www.uvicorn.dev) - uygulamanızı yükleyen ve servis eden server için. Buna, yüksek performanslı servis için gereken bazı bağımlılıkları (örn. `uvloop`) içeren `uvicorn[standard]` dahildir.\n* `fastapi-cli[standard]` - `fastapi` komutunu sağlamak için.\n    * Buna, FastAPI uygulamanızı [FastAPI Cloud](https://fastapicloud.com)'a deploy etmenizi sağlayan `fastapi-cloud-cli` dahildir.\n\n### `standard` Bağımlılıkları Olmadan { #without-standard-dependencies }\n\n`standard` opsiyonel bağımlılıklarını dahil etmek istemiyorsanız, `pip install fastapi` ile kurabilirsiniz.\n\n### `fastapi-cloud-cli` Olmadan { #without-fastapi-cloud-cli }\n\nFastAPI'ı standard bağımlılıklarla ama `fastapi-cloud-cli` olmadan kurmak istiyorsanız, `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"` ile yükleyebilirsiniz.\n\n### Ek Opsiyonel Bağımlılıklar { #additional-optional-dependencies }\n\nYüklemek isteyebileceğiniz bazı ek bağımlılıklar da vardır.\n\nEk opsiyonel Pydantic bağımlılıkları:\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - ayar yönetimi için.\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - Pydantic ile kullanılacak ek type'lar için.\n\nEk opsiyonel FastAPI bağımlılıkları:\n\n* [`orjson`](https://github.com/ijl/orjson) - `ORJSONResponse` kullanmak istiyorsanız gereklidir.\n* [`ujson`](https://github.com/esnme/ultrajson) - `UJSONResponse` kullanmak istiyorsanız gereklidir.\n\n## Lisans { #license }\n\nBu proje MIT lisansı şartları altında lisanslanmıştır.\n"
  },
  {
    "path": "docs/tr/docs/learn/index.md",
    "content": "# Öğren { #learn }\n\n**FastAPI** öğrenmek için giriş bölümleri ve öğreticiler burada yer alıyor.\n\nBurayı, bir **kitap**, bir **kurs**, FastAPI öğrenmenin **resmi** ve önerilen yolu olarak düşünebilirsiniz. 😎\n"
  },
  {
    "path": "docs/tr/docs/project-generation.md",
    "content": "# Full Stack FastAPI Şablonu { #full-stack-fastapi-template }\n\nŞablonlar genellikle belirli bir kurulumla gelir, ancak esnek ve özelleştirilebilir olacak şekilde tasarlanırlar. Bu sayede şablonu projenizin gereksinimlerine göre değiştirip uyarlayabilir, çok iyi bir başlangıç noktası olarak kullanabilirsiniz. 🏁\n\nBu şablonu başlangıç için kullanabilirsiniz; çünkü ilk kurulumun, güvenliğin, veritabanının ve bazı API endpoint'lerinin önemli bir kısmı sizin için zaten hazırlanmıştır.\n\nGitHub Repository: [Full Stack FastAPI Şablonu](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## Full Stack FastAPI Şablonu - Teknoloji Yığını ve Özellikler { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ Python backend API için [**FastAPI**](https://fastapi.tiangolo.com/tr).\n  - 🧰 Python SQL veritabanı etkileşimleri (ORM) için [SQLModel](https://sqlmodel.tiangolo.com).\n  - 🔍 FastAPI'nin kullandığı; veri doğrulama ve ayarlar yönetimi için [Pydantic](https://docs.pydantic.dev).\n  - 💾 SQL veritabanı olarak [PostgreSQL](https://www.postgresql.org).\n- 🚀 frontend için [React](https://react.dev).\n  - 💃 TypeScript, hooks, Vite ve modern bir frontend stack'inin diğer parçalarını kullanır.\n  - 🎨 frontend component'leri için [Tailwind CSS](https://tailwindcss.com) ve [shadcn/ui](https://ui.shadcn.com).\n  - 🤖 Otomatik üretilen bir frontend client.\n  - 🧪 End-to-End testleri için [Playwright](https://playwright.dev).\n  - 🦇 Dark mode desteği.\n- 🐋 Geliştirme ve production için [Docker Compose](https://www.docker.com).\n- 🔒 Varsayılan olarak güvenli password hashing.\n- 🔑 JWT (JSON Web Token) authentication.\n- 📫 E-posta tabanlı şifre kurtarma.\n- ✅ [Pytest](https://pytest.org) ile testler.\n- 📞 Reverse proxy / load balancer olarak [Traefik](https://traefik.io).\n- 🚢 Docker Compose kullanarak deployment talimatları; otomatik HTTPS sertifikalarını yönetmek için bir frontend Traefik proxy'sini nasıl kuracağınız dahil.\n- 🏭 GitHub Actions tabanlı CI (continuous integration) ve CD (continuous deployment).\n"
  },
  {
    "path": "docs/tr/docs/python-types.md",
    "content": "# Python Tiplerine Giriş { #python-types-intro }\n\nPython, isteğe bağlı \"type hints\" (diğer adıyla \"type annotations\") desteğine sahiptir.\n\nBu **\"type hints\"** veya annotations, bir değişkenin <dfn title=\"örneğin: str, int, float, bool\">tip</dfn>'ini bildirmeye yarayan özel bir sözdizimidir.\n\nDeğişkenleriniz için tip bildirerek, editörler ve araçlar size daha iyi destek sağlayabilir.\n\nBu, Python type hints hakkında sadece **hızlı bir eğitim / bilgi tazeleme** dokümanıdır. **FastAPI** ile kullanmak için gereken minimum bilgiyi kapsar... ki aslında bu çok azdır.\n\n**FastAPI** tamamen bu type hints üzerine kuruludur; bunlar ona birçok avantaj ve fayda sağlar.\n\nAncak hiç **FastAPI** kullanmasanız bile, bunlar hakkında biraz öğrenmeniz size fayda sağlayacaktır.\n\n/// note | Not\n\nEğer bir Python uzmanıysanız ve type hints hakkında her şeyi zaten biliyorsanız, sonraki bölüme geçin.\n\n///\n\n## Motivasyon { #motivation }\n\nBasit bir örnekle başlayalım:\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\nBu programı çalıştırınca şu çıktıyı alırsınız:\n\n```\nJohn Doe\n```\n\nFonksiyon şunları yapar:\n\n* `first_name` ve `last_name` değerlerini alır.\n* `title()` ile her birinin ilk harfini büyük harfe çevirir.\n* Ortada bir boşluk olacak şekilde <dfn title=\"Onları tek bir bütün olarak bir araya getirir. İçerikler art arda gelir.\">Birleştirir</dfn>.\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### Düzenleyelim { #edit-it }\n\nBu çok basit bir program.\n\nAma şimdi bunu sıfırdan yazdığınızı hayal edin.\n\nBir noktada fonksiyon tanımını yazmaya başlamış olacaktınız, parametreler hazır...\n\nAma sonra \"ilk harfi büyük harfe çeviren method\"u çağırmanız gerekiyor.\n\n`upper` mıydı? `uppercase` miydi? `first_uppercase`? `capitalize`?\n\nSonra eski programcı dostuyla denersiniz: editör autocomplete.\n\nFonksiyonun ilk parametresi olan `first_name`'i yazarsınız, sonra bir nokta (`.`) ve ardından autocomplete'i tetiklemek için `Ctrl+Space`'e basarsınız.\n\nAma ne yazık ki, işe yarar bir şey göremezsiniz:\n\n<img src=\"/img/python-types/image01.png\">\n\n### Tipleri ekleyelim { #add-types }\n\nÖnceki sürümden tek bir satırı değiştirelim.\n\nFonksiyonun parametreleri olan şu parçayı:\n\n```Python\n    first_name, last_name\n```\n\nşuna çevireceğiz:\n\n```Python\n    first_name: str, last_name: str\n```\n\nBu kadar.\n\nBunlar \"type hints\":\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\nBu, aşağıdaki gibi default değerler bildirmekle aynı şey değildir:\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\nBu farklı bir şey.\n\nEşittir (`=`) değil, iki nokta (`:`) kullanıyoruz.\n\nVe type hints eklemek, normalde onlarsız ne oluyorsa onu değiştirmez.\n\nAma şimdi, type hints ile o fonksiyonu oluşturmanın ortasında olduğunuzu tekrar hayal edin.\n\nAynı noktada, `Ctrl+Space` ile autocomplete'i tetiklemeye çalışırsınız ve şunu görürsünüz:\n\n<img src=\"/img/python-types/image02.png\">\n\nBununla birlikte, seçenekleri görerek kaydırabilirsiniz; ta ki \"tanıdık gelen\" seçeneği bulana kadar:\n\n<img src=\"/img/python-types/image03.png\">\n\n## Daha fazla motivasyon { #more-motivation }\n\nŞu fonksiyona bakın, zaten type hints içeriyor:\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\nEditör değişkenlerin tiplerini bildiği için, sadece completion değil, aynı zamanda hata kontrolleri de alırsınız:\n\n<img src=\"/img/python-types/image04.png\">\n\nArtık bunu düzeltmeniz gerektiğini, `age`'i `str(age)` ile string'e çevirmeniz gerektiğini biliyorsunuz:\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## Tipleri Bildirmek { #declaring-types }\n\nType hints bildirmek için ana yeri az önce gördünüz: fonksiyon parametreleri.\n\nBu, **FastAPI** ile kullanırken de onları en çok kullanacağınız yerdir.\n\n### Basit tipler { #simple-types }\n\nSadece `str` değil, tüm standart Python tiplerini bildirebilirsiniz.\n\nÖrneğin şunları kullanabilirsiniz:\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### `typing` modülü { #typing-module }\n\nBazı ek kullanım durumları için standart kütüphanedeki `typing` modülünden bazı şeyleri import etmeniz gerekebilir. Örneğin bir şeyin \"herhangi bir tip\" olabileceğini bildirmek istediğinizde, `typing` içindeki `Any`'yi kullanabilirsiniz:\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### Generic tipler { #generic-types }\n\nBazı tipler, köşeli parantez içinde \"type parameters\" alarak iç tiplerini tanımlayabilir; örneğin \"string listesi\" `list[str]` olarak bildirilir.\n\nBu şekilde type parameter alabilen tiplere **Generic types** veya **Generics** denir.\n\nAynı builtin tipleri generics olarak kullanabilirsiniz (köşeli parantez ve içinde tiplerle):\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### List { #list }\n\nÖrneğin, `str`'lerden oluşan bir `list` olan bir değişken tanımlayalım.\n\nDeğişkeni, aynı iki nokta (`:`) sözdizimiyle bildirin.\n\nTip olarak `list` yazın.\n\n`list`, bazı iç tipleri barındıran bir tip olduğundan, bunları köşeli parantez içine yazarsınız:\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info | Bilgi\n\nKöşeli parantez içindeki bu iç tiplere \"type parameters\" denir.\n\nBu durumda `str`, `list`'e verilen type parameter'dır.\n\n///\n\nBu şu demektir: \"`items` değişkeni bir `list` ve bu listedeki her bir öğe `str`\".\n\nBunu yaparak, editörünüz listeden öğeleri işlerken bile destek sağlayabilir:\n\n<img src=\"/img/python-types/image05.png\">\n\nTipler olmadan, bunu başarmak neredeyse imkansızdır.\n\n`item` değişkeninin, `items` listesindeki elemanlardan biri olduğuna dikkat edin.\n\nVe yine de editör bunun bir `str` olduğunu bilir ve buna göre destek sağlar.\n\n#### Tuple ve Set { #tuple-and-set }\n\n`tuple`'ları ve `set`'leri bildirmek için de aynısını yaparsınız:\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\nBu şu anlama gelir:\n\n* `items_t` değişkeni 3 öğeli bir `tuple`'dır: bir `int`, bir başka `int` ve bir `str`.\n* `items_s` değişkeni bir `set`'tir ve her bir öğesi `bytes` tipindedir.\n\n#### Dict { #dict }\n\nBir `dict` tanımlamak için, virgülle ayrılmış 2 type parameter verirsiniz.\n\nİlk type parameter, `dict`'in key'leri içindir.\n\nİkinci type parameter, `dict`'in value'ları içindir:\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\nBu şu anlama gelir:\n\n* `prices` değişkeni bir `dict`'tir:\n    * Bu `dict`'in key'leri `str` tipindedir (örneğin her bir öğenin adı).\n    * Bu `dict`'in value'ları `float` tipindedir (örneğin her bir öğenin fiyatı).\n\n#### Union { #union }\n\nBir değişkenin **birkaç tipten herhangi biri** olabileceğini bildirebilirsiniz; örneğin bir `int` veya bir `str`.\n\nBunu tanımlamak için, her iki tipi ayırmak üzere <dfn title='başka adıyla \"bit düzeyinde veya operatörü\", ancak burada o anlamı önemli değil'>dikey çizgi (`|`)</dfn> kullanırsınız.\n\nBuna \"union\" denir, çünkü değişken bu iki tip kümesinin birleşimindeki herhangi bir şey olabilir.\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\nBu, `item`'ın `int` veya `str` olabileceği anlamına gelir.\n\n#### Muhtemelen `None` { #possibly-none }\n\nBir değerin `str` gibi bir tipi olabileceğini ama aynı zamanda `None` da olabileceğini bildirebilirsiniz.\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\nSadece `str` yerine `str | None` kullanmak, aslında değer `None` olabilecekken her zaman `str` olduğunu varsaydığınız hataları editörün yakalamanıza yardımcı olur.\n\n### Tip olarak sınıflar { #classes-as-types }\n\nBir sınıfı da bir değişkenin tipi olarak bildirebilirsiniz.\n\nÖrneğin, adı olan bir `Person` sınıfınız olsun:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\nSonra bir değişkeni `Person` tipinde olacak şekilde bildirebilirsiniz:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\nVe sonra, yine tüm editör desteğini alırsınız:\n\n<img src=\"/img/python-types/image06.png\">\n\nBunun \"`one_person`, `Person` sınıfının bir **instance**'ıdır\" anlamına geldiğine dikkat edin.\n\n\"`one_person`, `Person` adlı **class**'tır\" anlamına gelmez.\n\n## Pydantic modelleri { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/), data validation yapmak için bir Python kütüphanesidir.\n\nVerinin \"shape\"'ini attribute'lara sahip sınıflar olarak tanımlarsınız.\n\nVe her attribute'un bir tipi vardır.\n\nArdından o sınıfın bir instance'ını bazı değerlerle oluşturursunuz; bu değerleri doğrular, uygun tipe dönüştürür (gerekliyse) ve size tüm veriyi içeren bir nesne verir.\n\nVe bu ortaya çıkan nesne ile tüm editör desteğini alırsınız.\n\nResmî Pydantic dokümanlarından bir örnek:\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info | Bilgi\n\nDaha fazlasını öğrenmek için [Pydantic'in dokümanlarına bakın](https://docs.pydantic.dev/).\n\n///\n\n**FastAPI** tamamen Pydantic üzerine kuruludur.\n\nBunların pratikte nasıl çalıştığını [Eğitim - Kullanım Kılavuzu](tutorial/index.md) içinde çok daha fazla göreceksiniz.\n\n## Metadata Annotations ile Type Hints { #type-hints-with-metadata-annotations }\n\nPython'da ayrıca, `Annotated` kullanarak bu type hints içine **ek <dfn title=\"Veri hakkında veri; bu durumda tip hakkında bilgi, örneğin bir açıklama.\">üstveri</dfn>** koymayı sağlayan bir özellik de vardır.\n\n`Annotated`'ı `typing` içinden import edebilirsiniz.\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nPython'un kendisi bu `Annotated` ile bir şey yapmaz. Editörler ve diğer araçlar için tip hâlâ `str`'dir.\n\nAma **FastAPI**'ye uygulamanızın nasıl davranmasını istediğinize dair ek metadata sağlamak için `Annotated` içindeki bu alanı kullanabilirsiniz.\n\nHatırlanması gereken önemli nokta: `Annotated`'a verdiğiniz **ilk *type parameter***, **gerçek tip**tir. Geri kalanı ise diğer araçlar için metadatadır.\n\nŞimdilik, sadece `Annotated`'ın var olduğunu ve bunun standart Python olduğunu bilmeniz yeterli. 😎\n\nİleride bunun ne kadar **güçlü** olabildiğini göreceksiniz.\n\n/// tip | İpucu\n\nBunun **standart Python** olması, editörünüzde mümkün olan **en iyi developer experience**'ı almaya devam edeceğiniz anlamına gelir; kodu analiz etmek ve refactor etmek için kullandığınız araçlarla da, vb. ✨\n\nAyrıca kodunuzun pek çok başka Python aracı ve kütüphanesiyle çok uyumlu olacağı anlamına gelir. 🚀\n\n///\n\n## **FastAPI**'de type hints { #type-hints-in-fastapi }\n\n**FastAPI**, birkaç şey yapmak için bu type hints'ten faydalanır.\n\n**FastAPI** ile type hints kullanarak parametreleri bildirirsiniz ve şunları elde edersiniz:\n\n* **Editör desteği**.\n* **Tip kontrolleri**.\n\n...ve **FastAPI** aynı bildirimleri şunlar için de kullanır:\n\n* **Gereksinimleri tanımlamak**: request path parameters, query parameters, headers, bodies, bağımlılıklar (dependencies), vb.\n* **Veriyi dönüştürmek**: request'ten gerekli tipe.\n* **Veriyi doğrulamak**: her request'ten gelen veriyi:\n    * Veri geçersiz olduğunda client'a dönen **otomatik hatalar** üretmek.\n* OpenAPI kullanarak API'yi **dokümante etmek**:\n    * bu, daha sonra otomatik etkileşimli dokümantasyon kullanıcı arayüzleri tarafından kullanılır.\n\nBunların hepsi kulağa soyut gelebilir. Merak etmeyin. Tüm bunları [Eğitim - Kullanım Kılavuzu](tutorial/index.md) içinde çalışırken göreceksiniz.\n\nÖnemli olan, standart Python tiplerini tek bir yerde kullanarak (daha fazla sınıf, decorator vb. eklemek yerine), **FastAPI**'nin sizin için işin büyük kısmını yapmasıdır.\n\n/// info | Bilgi\n\nTüm tutorial'ı zaten bitirdiyseniz ve tipler hakkında daha fazlasını görmek için geri döndüyseniz, iyi bir kaynak: [`mypy`'nin \"cheat sheet\"i](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html).\n\n///\n"
  },
  {
    "path": "docs/tr/docs/resources/index.md",
    "content": "# Kaynaklar { #resources }\n\nEk kaynaklar, dış bağlantılar ve daha fazlası. ✈️\n"
  },
  {
    "path": "docs/tr/docs/translation-banner.md",
    "content": "/// details | 🌐 Yapay Zekâ ve İnsanlar Tarafından Çeviri\n\nBu çeviri, insanlar tarafından yönlendirilen bir yapay zekâ ile oluşturuldu. 🤝\n\nOrijinal anlamın yanlış anlaşılması ya da kulağa doğal gelmeme gibi hatalar içerebilir. 🤖\n\n[Yapay zekâ LLM'ini daha iyi yönlendirmemize yardımcı olarak](https://fastapi.tiangolo.com/tr/contributing/#translations) bu çeviriyi iyileştirebilirsiniz.\n\n[İngilizce sürüm](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/tr/docs/tutorial/background-tasks.md",
    "content": "# Arka Plan Görevleri { #background-tasks }\n\nResponse döndürüldükten *sonra* çalıştırılacak arka plan görevleri tanımlayabilirsiniz.\n\nBu, request’ten sonra yapılması gereken; ancak client’ın response’u almadan önce tamamlanmasını beklemesine gerek olmayan işlemler için kullanışlıdır.\n\nÖrneğin:\n\n* Bir işlem gerçekleştirdikten sonra gönderilen email bildirimleri:\n    * Bir email server’a bağlanmak ve email göndermek genellikle \"yavaş\" olduğundan (birkaç saniye), response’u hemen döndürüp email bildirimini arka planda gönderebilirsiniz.\n* Veri işleme:\n    * Örneğin, yavaş bir süreçten geçmesi gereken bir dosya aldığınızı düşünün; \"Accepted\" (HTTP 202) response’u döndürüp dosyayı arka planda işleyebilirsiniz.\n\n## `BackgroundTasks` Kullanımı { #using-backgroundtasks }\n\nÖnce `BackgroundTasks`’i import edin ve *path operation function*’ınızda `BackgroundTasks` tip bildirimi olan bir parametre tanımlayın:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI**, sizin için `BackgroundTasks` tipinde bir obje oluşturur ve onu ilgili parametre olarak geçirir.\n\n## Bir Görev Fonksiyonu Oluşturun { #create-a-task-function }\n\nArka plan görevi olarak çalıştırılacak bir fonksiyon oluşturun.\n\nBu, parametre alabilen standart bir fonksiyondur.\n\n`async def` de olabilir, normal `def` de olabilir; **FastAPI** bunu doğru şekilde nasıl ele alacağını bilir.\n\nBu örnekte görev fonksiyonu bir dosyaya yazacaktır (email göndermeyi simüle ediyor).\n\nVe yazma işlemi `async` ve `await` kullanmadığı için fonksiyonu normal `def` ile tanımlarız:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## Arka Plan Görevini Ekleyin { #add-the-background-task }\n\n*Path operation function*’ınızın içinde, görev fonksiyonunuzu `.add_task()` metodu ile *background tasks* objesine ekleyin:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()` şu argümanları alır:\n\n* Arka planda çalıştırılacak bir görev fonksiyonu (`write_notification`).\n* Görev fonksiyonuna sırayla geçirilecek argümanlar (`email`).\n* Görev fonksiyonuna geçirilecek keyword argümanlar (`message=\"some notification\"`).\n\n## Dependency Injection { #dependency-injection }\n\n`BackgroundTasks` kullanımı dependency injection sistemiyle de çalışır; `BackgroundTasks` tipinde bir parametreyi birden fazla seviyede tanımlayabilirsiniz: bir *path operation function* içinde, bir dependency’de (dependable), bir sub-dependency’de, vb.\n\n**FastAPI** her durumda ne yapılacağını ve aynı objenin nasıl yeniden kullanılacağını bilir; böylece tüm arka plan görevleri birleştirilir ve sonrasında arka planda çalıştırılır:\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\nBu örnekte, response gönderildikten *sonra* mesajlar `log.txt` dosyasına yazılacaktır.\n\nRequest’te bir query varsa, log’a bir arka plan göreviyle yazılır.\n\nArdından *path operation function* içinde oluşturulan başka bir arka plan görevi, `email` path parametresini kullanarak bir mesaj yazar.\n\n## Teknik Detaylar { #technical-details }\n\n`BackgroundTasks` sınıfı doğrudan [`starlette.background`](https://www.starlette.dev/background/)’dan gelir.\n\n`fastapi` üzerinden import edebilmeniz ve yanlışlıkla `starlette.background` içindeki alternatif `BackgroundTask`’i (sonunda `s` olmadan) import etmemeniz için FastAPI’nin içine doğrudan import/eklenmiştir.\n\nSadece `BackgroundTasks` (ve `BackgroundTask` değil) kullanarak, bunu bir *path operation function* parametresi olarak kullanmak ve gerisini **FastAPI**’nin sizin için halletmesini sağlamak mümkündür; tıpkı `Request` objesini doğrudan kullanırken olduğu gibi.\n\nFastAPI’de `BackgroundTask`’i tek başına kullanmak hâlâ mümkündür; ancak bu durumda objeyi kendi kodunuzda oluşturmanız ve onu içeren bir Starlette `Response` döndürmeniz gerekir.\n\nDaha fazla detayı [Starlette’in Background Tasks için resmi dokümantasyonunda](https://www.starlette.dev/background/) görebilirsiniz.\n\n## Dikkat Edilmesi Gerekenler { #caveat }\n\nYoğun arka plan hesaplamaları yapmanız gerekiyorsa ve bunun aynı process tarafından çalıştırılmasına şart yoksa (örneğin memory, değişkenler vb. paylaşmanız gerekmiyorsa), [Celery](https://docs.celeryq.dev) gibi daha büyük araçları kullanmak size fayda sağlayabilir.\n\nBunlar genellikle daha karmaşık konfigurasyonlar ve RabbitMQ veya Redis gibi bir mesaj/iş kuyruğu yöneticisi gerektirir; ancak arka plan görevlerini birden fazla process’te ve özellikle birden fazla server’da çalıştırmanıza olanak tanırlar.\n\nAncak aynı **FastAPI** app’i içindeki değişkenlere ve objelere erişmeniz gerekiyorsa veya küçük arka plan görevleri (email bildirimi göndermek gibi) yapacaksanız, doğrudan `BackgroundTasks` kullanabilirsiniz.\n\n## Özet { #recap }\n\nArka plan görevleri eklemek için *path operation function*’larda ve dependency’lerde parametre olarak `BackgroundTasks`’i import edip kullanın.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/bigger-applications.md",
    "content": "# Daha Büyük Uygulamalar - Birden Fazla Dosya { #bigger-applications-multiple-files }\n\nBir uygulama veya web API geliştirirken, her şeyi tek bir dosyaya sığdırabilmek nadirdir.\n\n**FastAPI**, tüm esnekliği korurken uygulamanızı yapılandırmanıza yardımcı olan pratik bir araç sunar.\n\n/// info | Bilgi\n\nFlask'ten geliyorsanız, bu yapı Flask'in Blueprints'ine denk gelir.\n\n///\n\n## Örnek Bir Dosya Yapısı { #an-example-file-structure }\n\nDiyelim ki şöyle bir dosya yapınız var:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | İpucu\n\nBirden fazla `__init__.py` dosyası var: her dizinde veya alt dizinde bir tane.\n\nBu sayede bir dosyadaki kodu diğerine import edebilirsiniz.\n\nÖrneğin `app/main.py` içinde şöyle bir satırınız olabilir:\n\n```\nfrom app.routers import items\n```\n\n///\n\n* `app` dizini her şeyi içerir. Ayrıca boş bir `app/__init__.py` dosyası olduğu için bir \"Python package\" (bir \"Python module\" koleksiyonu) olur: `app`.\n* İçinde bir `app/main.py` dosyası vardır. Bir Python package'in (içinde `__init__.py` dosyası olan bir dizinin) içinde olduğundan, o package'in bir \"module\"’üdür: `app.main`.\n* Benzer şekilde `app/dependencies.py` dosyası da bir \"module\"’dür: `app.dependencies`.\n* `app/routers/` adında bir alt dizin vardır ve içinde başka bir `__init__.py` dosyası bulunur; dolayısıyla bu bir \"Python subpackage\"’dir: `app.routers`.\n* `app/routers/items.py` dosyası `app/routers/` package’i içinde olduğundan bir submodule’dür: `app.routers.items`.\n* `app/routers/users.py` için de aynı şekilde, başka bir submodule’dür: `app.routers.users`.\n* `app/internal/` adında bir alt dizin daha vardır ve içinde başka bir `__init__.py` dosyası bulunur; dolayısıyla bu da bir \"Python subpackage\"’dir: `app.internal`.\n* Ve `app/internal/admin.py` dosyası başka bir submodule’dür: `app.internal.admin`.\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\nAynı dosya yapısı, yorumlarla birlikte:\n\n```bash\n.\n├── app                  # \"app\" bir Python package'idir\n│   ├── __init__.py      # bu dosya, \"app\"i bir \"Python package\" yapar\n│   ├── main.py          # \"main\" module'ü, örn. import app.main\n│   ├── dependencies.py  # \"dependencies\" module'ü, örn. import app.dependencies\n│   └── routers          # \"routers\" bir \"Python subpackage\"idir\n│   │   ├── __init__.py  # \"routers\"ı bir \"Python subpackage\" yapar\n│   │   ├── items.py     # \"items\" submodule'ü, örn. import app.routers.items\n│   │   └── users.py     # \"users\" submodule'ü, örn. import app.routers.users\n│   └── internal         # \"internal\" bir \"Python subpackage\"idir\n│       ├── __init__.py  # \"internal\"ı bir \"Python subpackage\" yapar\n│       └── admin.py     # \"admin\" submodule'ü, örn. import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\nDiyelim ki sadece kullanıcıları yönetmeye ayrılmış dosyanız `/app/routers/users.py` içindeki submodule olsun.\n\nKullanıcılarla ilgili *path operation*’ları, kodun geri kalanından ayrı tutmak istiyorsunuz; böylece düzenli kalır.\n\nAncak bu hâlâ aynı **FastAPI** uygulaması/web API’sinin bir parçasıdır (aynı \"Python Package\" içinde).\n\nBu module için *path operation*’ları `APIRouter` kullanarak oluşturabilirsiniz.\n\n### `APIRouter` Import Edin { #import-apirouter }\n\n`FastAPI` class’ında yaptığınız gibi import edip bir \"instance\" oluşturursunuz:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### `APIRouter` ile *Path Operations* { #path-operations-with-apirouter }\n\nSonra bunu kullanarak *path operation*’larınızı tanımlarsınız.\n\n`FastAPI` class’ını nasıl kullanıyorsanız aynı şekilde kullanın:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\n`APIRouter`’ı \"mini bir `FastAPI`\" class’ı gibi düşünebilirsiniz.\n\nAynı seçeneklerin hepsi desteklenir.\n\nAynı `parameters`, `responses`, `dependencies`, `tags`, vb.\n\n/// tip | İpucu\n\nBu örnekte değişkenin adı `router`. Ancak istediğiniz gibi adlandırabilirsiniz.\n\n///\n\nBu `APIRouter`’ı ana `FastAPI` uygulamasına ekleyeceğiz; ama önce dependency’lere ve bir diğer `APIRouter`’a bakalım.\n\n## Dependencies { #dependencies }\n\nUygulamanın birden fazla yerinde kullanılacak bazı dependency’lere ihtiyacımız olacağını görüyoruz.\n\nBu yüzden onları ayrı bir `dependencies` module’üne koyuyoruz (`app/dependencies.py`).\n\nŞimdi, özel bir `X-Token` header'ını okumak için basit bir dependency kullanalım:\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | İpucu\n\nÖrneği basit tutmak için uydurma bir header kullanıyoruz.\n\nAncak gerçek senaryolarda, entegre [Security yardımcı araçlarını](security/index.md) kullanarak daha iyi sonuç alırsınız.\n\n///\n\n## `APIRouter` ile Başka Bir Module { #another-module-with-apirouter }\n\nDiyelim ki uygulamanızdaki \"items\" ile ilgili endpoint'ler de `app/routers/items.py` module’ünde olsun.\n\nŞunlar için *path operation*’larınız var:\n\n* `/items/`\n* `/items/{item_id}`\n\nBu, `app/routers/users.py` ile aynı yapıdadır.\n\nAncak biraz daha akıllı davranıp kodu sadeleştirmek istiyoruz.\n\nBu module’deki tüm *path operation*’ların şu ortak özelliklere sahip olduğunu biliyoruz:\n\n* Path `prefix`: `/items`.\n* `tags`: (tek bir tag: `items`).\n* Ek `responses`.\n* `dependencies`: hepsinin, oluşturduğumuz `X-Token` dependency’sine ihtiyacı var.\n\nDolayısıyla bunları her *path operation*’a tek tek eklemek yerine `APIRouter`’a ekleyebiliriz.\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\nHer *path operation*’ın path’i aşağıdaki gibi `/` ile başlamak zorunda olduğundan:\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n...prefix’in sonunda `/` olmamalıdır.\n\nYani bu örnekte prefix `/items` olur.\n\nAyrıca, bu router içindeki tüm *path operation*’lara uygulanacak bir `tags` listesi ve ek `responses` da ekleyebiliriz.\n\nVe router’daki tüm *path operation*’lara eklenecek, her request için çalıştırılıp çözülecek bir `dependencies` listesi de ekleyebiliriz.\n\n/// tip | İpucu\n\n[ *path operation decorator*’larındaki dependency’lerde](dependencies/dependencies-in-path-operation-decorators.md) olduğu gibi, *path operation function*’ınıza herhangi bir değer aktarılmayacağını unutmayın.\n\n///\n\nSonuç olarak item path’leri artık:\n\n* `/items/`\n* `/items/{item_id}`\n\n...tam da istediğimiz gibi olur.\n\n* Hepsi, içinde tek bir string `\"items\"` bulunan bir tag listesiyle işaretlenir.\n    * Bu \"tags\", özellikle otomatik interaktif dokümantasyon sistemleri (OpenAPI) için çok faydalıdır.\n* Hepsi önceden tanımlı `responses`’ları içerir.\n* Bu *path operation*’ların hepsinde, öncesinde `dependencies` listesi değerlendirilip çalıştırılır.\n    * Ayrıca belirli bir *path operation* içinde dependency tanımlarsanız, **onlar da çalıştırılır**.\n    * Önce router dependency’leri, sonra decorator’daki [`dependencies`](dependencies/dependencies-in-path-operation-decorators.md), sonra da normal parametre dependency’leri çalışır.\n    * Ayrıca [`scopes` ile `Security` dependency’leri](../advanced/security/oauth2-scopes.md) de ekleyebilirsiniz.\n\n/// tip | İpucu\n\n`APIRouter` içinde `dependencies` kullanmak, örneğin bir grup *path operation* için kimlik doğrulamayı zorunlu kılmakta kullanılabilir. Dependency’leri tek tek her birine eklemeseniz bile.\n\n///\n\n/// check | Ek bilgi\n\n`prefix`, `tags`, `responses` ve `dependencies` parametreleri (çoğu başka örnekte olduğu gibi) kod tekrarını önlemenize yardımcı olan, **FastAPI**’nin bir özelliğidir.\n\n///\n\n### Dependency'leri Import Edin { #import-the-dependencies }\n\nBu kod `app.routers.items` module’ünde, yani `app/routers/items.py` dosyasında duruyor.\n\nDependency function’ını ise `app.dependencies` module’ünden, yani `app/dependencies.py` dosyasından almamız gerekiyor.\n\nBu yüzden dependency’ler için `..` ile relative import kullanıyoruz:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### Relative Import Nasıl Çalışır { #how-relative-imports-work }\n\n/// tip | İpucu\n\nImport’ların nasıl çalıştığını çok iyi biliyorsanız, bir sonraki bölüme geçin.\n\n///\n\nTek bir nokta `.`, örneğin:\n\n```Python\nfrom .dependencies import get_token_header\n```\n\nşu anlama gelir:\n\n* Bu module’ün (yani `app/routers/items.py` dosyasının) bulunduğu package içinden başla ( `app/routers/` dizini)...\n* `dependencies` module’ünü bul (`app/routers/dependencies.py` gibi hayali bir dosya)...\n* ve oradan `get_token_header` function’ını import et.\n\nAma o dosya yok; bizim dependency’lerimiz `app/dependencies.py` dosyasında.\n\nUygulama/dosya yapımızın nasıl göründüğünü hatırlayın:\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\nİki nokta `..`, örneğin:\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\nşu anlama gelir:\n\n* Bu module’ün bulunduğu package içinden başla (`app/routers/` dizini)...\n* üst (parent) package’e çık (`app/` dizini)...\n* burada `dependencies` module’ünü bul (`app/dependencies.py` dosyası)...\n* ve oradan `get_token_header` function’ını import et.\n\nBu doğru şekilde çalışır! 🎉\n\n---\n\nAynı şekilde, üç nokta `...` kullansaydık:\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\nşu anlama gelirdi:\n\n* Bu module’ün bulunduğu package içinden başla (`app/routers/` dizini)...\n* üst package’e çık (`app/` dizini)...\n* sonra bir üstüne daha çık (orada bir üst package yok; `app` en üst seviye 😱)...\n* ve orada `dependencies` module’ünü bul (`app/dependencies.py` dosyası)...\n* ve oradan `get_token_header` function’ını import et.\n\nBu, `app/` dizininin üstünde, kendi `__init__.py` dosyası olan başka bir package’e işaret ederdi. Ama bizde böyle bir şey yok. Dolayısıyla bu örnekte hata verirdi. 🚨\n\nArtık nasıl çalıştığını bildiğinize göre, uygulamalarınız ne kadar karmaşık olursa olsun relative import’ları kullanabilirsiniz. 🤓\n\n### Özel `tags`, `responses` ve `dependencies` Ekleyin { #add-some-custom-tags-responses-and-dependencies }\n\n`/items` prefix’ini ya da `tags=[\"items\"]` değerini her *path operation*’a tek tek eklemiyoruz; çünkü bunları `APIRouter`’a ekledik.\n\nAma yine de belirli bir *path operation*’a uygulanacak _ek_ `tags` tanımlayabilir, ayrıca o *path operation*’a özel `responses` ekleyebiliriz:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | İpucu\n\nBu son *path operation*’da tag kombinasyonu şöyle olur: `[\"items\", \"custom\"]`.\n\nAyrıca dokümantasyonda iki response da görünür: biri `404`, diğeri `403`.\n\n///\n\n## Ana `FastAPI` { #the-main-fastapi }\n\nŞimdi `app/main.py` module’üne bakalım.\n\nBurada `FastAPI` class’ını import edip kullanırsınız.\n\nBu dosya, uygulamanızda her şeyi bir araya getiren ana dosya olacak.\n\nMantığın büyük kısmı artık kendi module’lerinde yaşayacağı için ana dosya oldukça basit kalır.\n\n### `FastAPI` Import Edin { #import-fastapi }\n\nNormal şekilde bir `FastAPI` class’ı oluşturursunuz.\n\nHatta her `APIRouter` için olan dependency’lerle birleştirilecek [global dependencies](dependencies/global-dependencies.md) bile tanımlayabilirsiniz:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### `APIRouter` Import Edin { #import-the-apirouter }\n\nŞimdi `APIRouter` içeren diğer submodule’leri import ediyoruz:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\n`app/routers/users.py` ve `app/routers/items.py` dosyaları aynı Python package’i olan `app`’in parçası olan submodule’ler olduğu için, onları \"relative import\" ile tek bir nokta `.` kullanarak import edebiliriz.\n\n### Import Nasıl Çalışır { #how-the-importing-works }\n\nŞu bölüm:\n\n```Python\nfrom .routers import items, users\n```\n\nşu anlama gelir:\n\n* Bu module’ün (yani `app/main.py` dosyasının) bulunduğu package içinden başla (`app/` dizini)...\n* `routers` subpackage’ini bul (`app/routers/` dizini)...\n* ve buradan `items` submodule’ünü (`app/routers/items.py`) ve `users` submodule’ünü (`app/routers/users.py`) import et...\n\n`items` module’ünün içinde `router` adında bir değişken vardır (`items.router`). Bu, `app/routers/items.py` dosyasında oluşturduğumuz aynı değişkendir; bir `APIRouter` nesnesidir.\n\nSonra aynı işlemi `users` module’ü için de yaparız.\n\nAyrıca şöyle de import edebilirdik:\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info | Bilgi\n\nİlk sürüm \"relative import\"tur:\n\n```Python\nfrom .routers import items, users\n```\n\nİkinci sürüm \"absolute import\"tur:\n\n```Python\nfrom app.routers import items, users\n```\n\nPython Packages ve Modules hakkında daha fazlası için, [Python'ın Modules ile ilgili resmi dokümantasyonunu](https://docs.python.org/3/tutorial/modules.html) okuyun.\n\n///\n\n### İsim Çakışmalarını Önleyin { #avoid-name-collisions }\n\n`items` submodule’ünü doğrudan import ediyoruz; sadece içindeki `router` değişkenini import etmiyoruz.\n\nÇünkü `users` submodule’ünde de `router` adlı başka bir değişken var.\n\nEğer şöyle sırayla import etseydik:\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\n`users` içindeki `router`, `items` içindeki `router`’ın üstüne yazardı ve ikisini aynı anda kullanamazdık.\n\nBu yüzden ikisini de aynı dosyada kullanabilmek için submodule’leri doğrudan import ediyoruz:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### `users` ve `items` için `APIRouter`’ları Dahil Edin { #include-the-apirouters-for-users-and-items }\n\nŞimdi `users` ve `items` submodule’lerindeki `router`’ları dahil edelim:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info | Bilgi\n\n`users.router`, `app/routers/users.py` dosyasının içindeki `APIRouter`’ı içerir.\n\n`items.router` ise `app/routers/items.py` dosyasının içindeki `APIRouter`’ı içerir.\n\n///\n\n`app.include_router()` ile her bir `APIRouter`’ı ana `FastAPI` uygulamasına ekleyebiliriz.\n\nBöylece o router içindeki tüm route’lar uygulamanın bir parçası olarak dahil edilir.\n\n/// note | Teknik Detaylar\n\nAslında içeride, `APIRouter` içinde tanımlanan her *path operation* için bir *path operation* oluşturur.\n\nYani perde arkasında, her şey tek bir uygulamaymış gibi çalışır.\n\n///\n\n/// check | Ek bilgi\n\nRouter’ları dahil ederken performans konusunda endişelenmeniz gerekmez.\n\nBu işlem mikrosaniyeler sürer ve sadece startup sırasında olur.\n\nDolayısıyla performansı etkilemez. ⚡\n\n///\n\n### Özel `prefix`, `tags`, `responses` ve `dependencies` ile Bir `APIRouter` Dahil Edin { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\nŞimdi, kurumunuzun size `app/internal/admin.py` dosyasını verdiğini düşünelim.\n\nBu dosyada, kurumunuzun birden fazla proje arasında paylaştığı bazı admin *path operation*’larını içeren bir `APIRouter` var.\n\nBu örnekte çok basit olacak. Ancak kurum içinde başka projelerle paylaşıldığı için, bunu değiştirip `prefix`, `dependencies`, `tags` vs. doğrudan `APIRouter`’a ekleyemediğimizi varsayalım:\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nYine de bu `APIRouter`’ı dahil ederken özel bir `prefix` ayarlamak istiyoruz ki tüm *path operation*’ları `/admin` ile başlasın; ayrıca bu projede hâlihazırda kullandığımız `dependencies` ile güvene almak, `tags` ve `responses` eklemek istiyoruz.\n\nOrijinal `APIRouter`’ı değiştirmeden, bu parametreleri `app.include_router()`’a vererek hepsini tanımlayabiliriz:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\nBöylece orijinal `APIRouter` değişmeden kalır; yani aynı `app/internal/admin.py` dosyasını kurum içindeki diğer projelerle de paylaşmaya devam edebiliriz.\n\nSonuç olarak, uygulamamızda `admin` module’ündeki her bir *path operation* şunlara sahip olur:\n\n* `/admin` prefix’i.\n* `admin` tag’i.\n* `get_token_header` dependency’si.\n* `418` response’u. 🍵\n\nAncak bu sadece bizim uygulamamızdaki o `APIRouter` için geçerlidir; onu kullanan diğer kodlar için değil.\n\nDolayısıyla örneğin diğer projeler aynı `APIRouter`’ı farklı bir authentication yöntemiyle kullanabilir.\n\n### Bir *Path Operation* Dahil Edin { #include-a-path-operation }\n\n*Path operation*’ları doğrudan `FastAPI` uygulamasına da ekleyebiliriz.\n\nBurada bunu yapıyoruz... sadece yapabildiğimizi göstermek için 🤷:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\nve `app.include_router()` ile eklenen diğer tüm *path operation*’larla birlikte doğru şekilde çalışır.\n\n/// info | Çok Teknik Detaylar\n\n**Not**: Bu oldukça teknik bir detay; büyük ihtimalle **direkt geçebilirsiniz**.\n\n---\n\n`APIRouter`’lar \"mount\" edilmez; uygulamanın geri kalanından izole değildir.\n\nÇünkü *path operation*’larını OpenAPI şemasına ve kullanıcı arayüzlerine dahil etmek istiyoruz.\n\nOnları tamamen izole edip bağımsız şekilde \"mount\" edemediğimiz için, *path operation*’lar doğrudan eklenmek yerine \"klonlanır\" (yeniden oluşturulur).\n\n///\n\n## `pyproject.toml` İçinde `entrypoint` Yapılandırın { #configure-the-entrypoint-in-pyproject-toml }\n\nFastAPI `app` nesneniz `app/main.py` içinde yaşadığına göre, `pyproject.toml` dosyanızda `entrypoint`’i şöyle yapılandırabilirsiniz:\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\nbu da şu import’a denktir:\n\n```python\nfrom app.main import app\n```\n\nBöylece `fastapi` komutu uygulamanızı nerede bulacağını bilir.\n\n/// Note | Not\n\nKomuta dosya yolunu da verebilirsiniz, örneğin:\n\n```console\n$ fastapi dev app/main.py\n```\n\nAma o zaman her `fastapi` komutunu çalıştırdığınızda doğru yolu hatırlayıp geçirmeniz gerekir.\n\nAyrıca, diğer araçlar uygulamayı bulamayabilir; örneğin [VS Code Eklentisi](../editor-support.md) veya [FastAPI Cloud](https://fastapicloud.com). Bu yüzden `pyproject.toml` içinde `entrypoint` kullanmanız önerilir.\n\n///\n\n## Otomatik API Dokümanını Kontrol Edin { #check-the-automatic-api-docs }\n\nŞimdi uygulamanızı çalıştırın:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nVe dokümanları [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) adresinde açın.\n\nTüm submodule’lerdeki path’leri, doğru path’ler (ve prefix’ler) ve doğru tag’lerle birlikte içeren otomatik API dokümanını göreceksiniz:\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## Aynı Router'ı Farklı `prefix` ile Birden Fazla Kez Dahil Edin { #include-the-same-router-multiple-times-with-different-prefix }\n\n`.include_router()` ile aynı router’ı farklı prefix’ler kullanarak birden fazla kez de dahil edebilirsiniz.\n\nÖrneğin aynı API’yi `/api/v1` ve `/api/latest` gibi farklı prefix’ler altında sunmak için faydalı olabilir.\n\nBu, muhtemelen ihtiyacınız olmayan ileri seviye bir kullanımdır; ancak gerekirse diye mevcut.\n\n## Bir `APIRouter`’ı Başka Birine Dahil Edin { #include-an-apirouter-in-another }\n\nBir `APIRouter`’ı `FastAPI` uygulamasına dahil ettiğiniz gibi, bir `APIRouter`’ı başka bir `APIRouter`’a da şu şekilde dahil edebilirsiniz:\n\n```Python\nrouter.include_router(other_router)\n```\n\n`router`’ı `FastAPI` uygulamasına dahil etmeden önce bunu yaptığınızdan emin olun; böylece `other_router` içindeki *path operation*’lar da dahil edilmiş olur.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/body-fields.md",
    "content": "# Body - Alanlar { #body-fields }\n\n`Query`, `Path` ve `Body` ile *path operation function* parametrelerinde ek doğrulama ve metadata tanımlayabildiğiniz gibi, Pydantic modellerinin içinde de Pydantic'in `Field`'ını kullanarak doğrulama ve metadata tanımlayabilirsiniz.\n\n## `Field`'ı import edin { #import-field }\n\nÖnce import etmeniz gerekir:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n/// warning | Uyarı\n\n`Field`'ın, diğerlerinin (`Query`, `Path`, `Body` vb.) aksine `fastapi`'den değil doğrudan `pydantic`'den import edildiğine dikkat edin.\n\n///\n\n## Model attribute'larını tanımlayın { #declare-model-attributes }\n\nArdından `Field`'ı model attribute'larıyla birlikte kullanabilirsiniz:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field`, `Query`, `Path` ve `Body` ile aynı şekilde çalışır; aynı parametrelerin tamamına sahiptir, vb.\n\n/// note | Teknik Detaylar\n\nAslında, `Query`, `Path` ve birazdan göreceğiniz diğerleri, ortak bir `Param` sınıfının alt sınıflarından nesneler oluşturur; `Param` sınıfı da Pydantic'in `FieldInfo` sınıfının bir alt sınıfıdır.\n\nPydantic'in `Field`'ı da `FieldInfo`'nun bir instance'ını döndürür.\n\n`Body` ayrıca doğrudan `FieldInfo`'nun bir alt sınıfından nesneler döndürür. Daha sonra göreceğiniz başka bazıları da `Body` sınıfının alt sınıflarıdır.\n\n`fastapi`'den `Query`, `Path` ve diğerlerini import ettiğinizde, bunların aslında özel sınıflar döndüren fonksiyonlar olduğunu unutmayın.\n\n///\n\n/// tip | İpucu\n\nType, varsayılan değer ve `Field` ile tanımlanan her model attribute'unun yapısının, *path operation function* parametresiyle aynı olduğuna dikkat edin; sadece `Path`, `Query` ve `Body` yerine `Field` kullanılmıştır.\n\n///\n\n## Ek bilgi ekleyin { #add-extra-information }\n\n`Field`, `Query`, `Body` vb. içinde ek bilgi tanımlayabilirsiniz. Bu bilgiler oluşturulan JSON Schema'ya dahil edilir.\n\nÖrnek (examples) tanımlamayı öğrenirken, dokümanların ilerleyen kısımlarında ek bilgi ekleme konusunu daha ayrıntılı göreceksiniz.\n\n/// warning | Uyarı\n\n`Field`'a geçirilen ekstra key'ler, uygulamanız için üretilen OpenAPI schema'sında da yer alır.\nBu key'ler OpenAPI spesifikasyonunun bir parçası olmak zorunda olmadığından, örneğin [OpenAPI validator](https://validator.swagger.io/) gibi bazı OpenAPI araçları üretilen schema'nızla çalışmayabilir.\n\n///\n\n## Özet { #recap }\n\nModel attribute'ları için ek doğrulamalar ve metadata tanımlamak üzere Pydantic'in `Field`'ını kullanabilirsiniz.\n\nAyrıca, ek keyword argument'ları kullanarak JSON Schema'ya ekstra metadata da iletebilirsiniz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/body-multiple-params.md",
    "content": "# Body - Birden Fazla Parametre { #body-multiple-parameters }\n\nArtık `Path` ve `Query` kullanmayı gördüğümüze göre, request body bildirimlerinin daha ileri kullanım senaryolarına bakalım.\n\n## `Path`, `Query` ve body parametrelerini karıştırma { #mix-path-query-and-body-parameters }\n\nÖncelikle, elbette `Path`, `Query` ve request body parametre bildirimlerini serbestçe karıştırabilirsiniz ve **FastAPI** ne yapacağını bilir.\n\nAyrıca, varsayılan değeri `None` yaparak body parametrelerini opsiyonel olarak da tanımlayabilirsiniz:\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | Not\n\nBu durumda body'den alınacak `item` opsiyoneldir. Çünkü varsayılan değeri `None` olarak ayarlanmıştır.\n\n///\n\n## Birden fazla body parametresi { #multiple-body-parameters }\n\nÖnceki örnekte, *path operation*'lar `Item`'ın özelliklerini içeren bir JSON body beklerdi, örneğin:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\nAncak birden fazla body parametresi de tanımlayabilirsiniz; örneğin `item` ve `user`:\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\n\nBu durumda **FastAPI**, fonksiyonda birden fazla body parametresi olduğunu fark eder (iki parametre de Pydantic modelidir).\n\nBunun üzerine, body içinde anahtar (field name) olarak parametre adlarını kullanır ve şu şekilde bir body bekler:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | Not\n\n`item` daha öncekiyle aynı şekilde tanımlanmış olsa bile, artık body içinde `item` anahtarı altında gelmesi beklenir.\n\n///\n\n**FastAPI**, request'ten otomatik dönüşümü yapar; böylece `item` parametresi kendi içeriğini alır, `user` için de aynı şekilde olur.\n\nBirleşik verinin validasyonunu yapar ve OpenAPI şeması ile otomatik dokümantasyonda da bunu bu şekilde dokümante eder.\n\n## Body içinde tekil değerler { #singular-values-in-body }\n\nQuery ve path parametreleri için ek veri tanımlamak üzere `Query` ve `Path` olduğu gibi, **FastAPI** bunların karşılığı olarak `Body` de sağlar.\n\nÖrneğin, önceki modeli genişleterek, aynı body içinde `item` ve `user` dışında bir de `importance` anahtarı olmasını isteyebilirsiniz.\n\nBunu olduğu gibi tanımlarsanız, tekil bir değer olduğu için **FastAPI** bunun bir query parametresi olduğunu varsayar.\n\nAma `Body` kullanarak, **FastAPI**'ye bunu body içinde başka bir anahtar olarak ele almasını söyleyebilirsiniz:\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\n\nBu durumda **FastAPI** şu şekilde bir body bekler:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\nYine veri tiplerini dönüştürür, validate eder, dokümante eder, vb.\n\n## Birden fazla body parametresi ve query { #multiple-body-params-and-query }\n\nElbette ihtiyaç duyduğunuzda, body parametrelerine ek olarak query parametreleri de tanımlayabilirsiniz.\n\nVarsayılan olarak tekil değerler query parametresi olarak yorumlandığı için, ayrıca `Query` eklemeniz gerekmez; şöyle yazmanız yeterlidir:\n\n```Python\nq: str | None = None\n```\n\nÖrneğin:\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n\n/// info | Bilgi\n\n`Body`, `Query`, `Path` ve daha sonra göreceğiniz diğerleriyle aynı ek validasyon ve metadata parametrelerine de sahiptir.\n\n///\n\n## Tek bir body parametresini gömme { #embed-a-single-body-parameter }\n\nDiyelim ki Pydantic'teki `Item` modelinden gelen yalnızca tek bir `item` body parametreniz var.\n\nVarsayılan olarak **FastAPI**, body'nin doğrudan bu modelin içeriği olmasını bekler.\n\nAncak, ek body parametreleri tanımladığınızda olduğu gibi, `item` anahtarı olan bir JSON ve onun içinde modelin içeriğini beklemesini istiyorsanız, `Body`'nin özel parametresi olan `embed`'i kullanabilirsiniz:\n\n```Python\nitem: Item = Body(embed=True)\n```\n\nyani şöyle:\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\n\nBu durumda **FastAPI** şu şekilde bir body bekler:\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\nşunun yerine:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## Özet { #recap }\n\nBir request yalnızca tek bir body içerebilse de, *path operation function*'ınıza birden fazla body parametresi ekleyebilirsiniz.\n\nAncak **FastAPI** bunu yönetir; fonksiyonunuza doğru veriyi verir ve *path operation* içinde doğru şemayı validate edip dokümante eder.\n\nAyrıca tekil değerlerin body'nin bir parçası olarak alınmasını da tanımlayabilirsiniz.\n\nVe yalnızca tek bir parametre tanımlanmış olsa bile, **FastAPI**'ye body'yi bir anahtarın içine gömmesini söyleyebilirsiniz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/body-nested-models.md",
    "content": "# Body - İç İçe Modeller { #body-nested-models }\n\n**FastAPI** ile (Pydantic sayesinde) istediğiniz kadar derin iç içe geçmiş modelleri tanımlayabilir, doğrulayabilir, dokümante edebilir ve kullanabilirsiniz.\n\n## List alanları { #list-fields }\n\nBir attribute’u bir alt tipe sahip olacak şekilde tanımlayabilirsiniz. Örneğin, bir Python `list`:\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\nBu, `tags`’in bir list olmasını sağlar; ancak list’in elemanlarının tipini belirtmez.\n\n## Tip parametresi olan list alanları { #list-fields-with-type-parameter }\n\nAncak Python’da, iç tipleri olan list’leri (ya da \"type parameter\" içeren tipleri) tanımlamanın belirli bir yolu vardır:\n\n### Tip parametresiyle bir `list` tanımlayın { #declare-a-list-with-a-type-parameter }\n\n`list`, `dict`, `tuple` gibi type parameter (iç tip) alan tipleri tanımlamak için, iç tipi(leri) köşeli parantezlerle \"type parameter\" olarak verin: `[` ve `]`\n\n```Python\nmy_list: list[str]\n```\n\nBu, tip tanımları için standart Python sözdizimidir.\n\nİç tipleri olan model attribute’ları için de aynı standart sözdizimini kullanın.\n\nDolayısıyla örneğimizde, `tags`’i özel olarak bir \"string list’i\" yapabiliriz:\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## Set tipleri { #set-types }\n\nSonra bunu düşününce, tag’lerin tekrar etmemesi gerektiğini fark ederiz; büyük ihtimalle benzersiz string’ler olmalıdır.\n\nPython’da benzersiz öğelerden oluşan kümeler için özel bir veri tipi vardır: `set`.\n\nO zaman `tags`’i string’lerden oluşan bir set olarak tanımlayabiliriz:\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\nBöylece duplicate veri içeren bir request alsanız bile, bu veri benzersiz öğelerden oluşan bir set’e dönüştürülür.\n\nVe bu veriyi ne zaman output etseniz, kaynakta duplicate olsa bile, benzersiz öğelerden oluşan bir set olarak output edilir.\n\nAyrıca buna göre annotate / dokümante edilir.\n\n## İç İçe Modeller { #nested-models }\n\nBir Pydantic modelinin her attribute’unun bir tipi vardır.\n\nAncak bu tip, kendi başına başka bir Pydantic modeli de olabilir.\n\nYani belirli attribute adları, tipleri ve validation kurallarıyla derin iç içe JSON \"object\"leri tanımlayabilirsiniz.\n\nHem de istediğiniz kadar iç içe.\n\n### Bir alt model tanımlayın { #define-a-submodel }\n\nÖrneğin bir `Image` modeli tanımlayabiliriz:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### Alt modeli tip olarak kullanın { #use-the-submodel-as-a-type }\n\nArdından bunu bir attribute’un tipi olarak kullanabiliriz:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\nBu da **FastAPI**’nin aşağıdakine benzer bir body bekleyeceği anlamına gelir:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\nYine, sadece bu tanımı yaparak **FastAPI** ile şunları elde edersiniz:\n\n* Editör desteği (tamamlama vb.), iç içe modeller için bile\n* Veri dönüştürme\n* Veri doğrulama (validation)\n* Otomatik dokümantasyon\n\n## Özel tipler ve doğrulama { #special-types-and-validation }\n\n`str`, `int`, `float` vb. normal tekil tiplerin yanında, `str`’den türeyen daha karmaşık tekil tipleri de kullanabilirsiniz.\n\nTüm seçenekleri görmek için [Pydantic Türlerine Genel Bakış](https://docs.pydantic.dev/latest/concepts/types/) sayfasına göz atın. Sonraki bölümde bazı örnekleri göreceksiniz.\n\nÖrneğin `Image` modelinde bir `url` alanımız olduğuna göre, bunu `str` yerine Pydantic’in `HttpUrl` tipinden bir instance olacak şekilde tanımlayabiliriz:\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\nString’in geçerli bir URL olup olmadığı kontrol edilir ve JSON Schema / OpenAPI’de de buna göre dokümante edilir.\n\n## Alt modellerden oluşan list’lere sahip attribute’lar { #attributes-with-lists-of-submodels }\n\nPydantic modellerini `list`, `set` vb. tiplerin alt tipi olarak da kullanabilirsiniz:\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\nBu, aşağıdaki gibi bir JSON body bekler (dönüştürür, doğrular, dokümante eder vb.):\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info | Bilgi\n\n`images` key’inin artık image object’lerinden oluşan bir list içerdiğine dikkat edin.\n\n///\n\n## Çok derin iç içe modeller { #deeply-nested-models }\n\nİstediğiniz kadar derin iç içe modeller tanımlayabilirsiniz:\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info | Bilgi\n\n`Offer`’ın bir `Item` list’i olduğuna, `Item`’ların da opsiyonel bir `Image` list’ine sahip olduğuna dikkat edin.\n\n///\n\n## Sadece list olan body’ler { #bodies-of-pure-lists }\n\nBeklediğiniz JSON body’nin en üst seviye değeri bir JSON `array` (Python’da `list`) ise, tipi Pydantic modellerinde olduğu gibi fonksiyonun parametresinde tanımlayabilirsiniz:\n\n```Python\nimages: list[Image]\n```\n\nşu örnekte olduğu gibi:\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## Her yerde editör desteği { #editor-support-everywhere }\n\nVe her yerde editör desteği alırsınız.\n\nList içindeki öğeler için bile:\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\nPydantic modelleri yerine doğrudan `dict` ile çalışsaydınız bu tür bir editör desteğini alamazdınız.\n\nAncak bunlarla uğraşmanız da gerekmez; gelen dict’ler otomatik olarak dönüştürülür ve output’unuz da otomatik olarak JSON’a çevrilir.\n\n## Rastgele `dict` body’leri { #bodies-of-arbitrary-dicts }\n\nBody’yi, key’leri bir tipte ve value’ları başka bir tipte olan bir `dict` olarak da tanımlayabilirsiniz.\n\nBu şekilde (Pydantic modellerinde olduğu gibi) geçerli field/attribute adlarının önceden ne olduğunu bilmeniz gerekmez.\n\nBu, önceden bilmediğiniz key’leri almak istediğiniz durumlarda faydalıdır.\n\n---\n\nBir diğer faydalı durum da key’lerin başka bir tipte olmasını istediğiniz zamandır (ör. `int`).\n\nBurada göreceğimiz şey de bu.\n\nBu durumda, `int` key’lere ve `float` value’lara sahip olduğu sürece herhangi bir `dict` kabul edersiniz:\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip | İpucu\n\nJSON key olarak yalnızca `str` destekler, bunu unutmayın.\n\nAncak Pydantic otomatik veri dönüştürme yapar.\n\nYani API client’larınız key’leri sadece string olarak gönderebilse bile, bu string’ler saf tamsayı içeriyorsa Pydantic bunları dönüştürür ve doğrular.\n\nVe `weights` olarak aldığınız `dict`, gerçekte `int` key’lere ve `float` value’lara sahip olur.\n\n///\n\n## Özet { #recap }\n\n**FastAPI** ile Pydantic modellerinin sağladığı en yüksek esnekliği elde ederken, kodunuzu da basit, kısa ve şık tutarsınız.\n\nÜstelik tüm avantajlarla birlikte:\n\n* Editör desteği (her yerde tamamlama!)\n* Veri dönüştürme (diğer adıyla parsing / serialization)\n* Veri doğrulama (validation)\n* Schema dokümantasyonu\n* Otomatik dokümanlar\n"
  },
  {
    "path": "docs/tr/docs/tutorial/body-updates.md",
    "content": "# Body - Güncellemeler { #body-updates }\n\n## `PUT` ile değiştirerek güncelleme { #update-replacing-with-put }\n\nBir öğeyi güncellemek için [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) operasyonunu kullanabilirsiniz.\n\nGirdi verisini JSON olarak saklanabilecek bir formata (ör. bir NoSQL veritabanı ile) dönüştürmek için `jsonable_encoder` kullanabilirsiniz. Örneğin, `datetime` değerlerini `str`'ye çevirmek gibi.\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT`, mevcut verinin yerine geçmesi gereken veriyi almak için kullanılır.\n\n### Değiştirerek güncelleme uyarısı { #warning-about-replacing }\n\nBu, `bar` öğesini `PUT` ile, body içinde şu verilerle güncellemek isterseniz:\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\nzaten kayıtlı olan `\"tax\": 20.2` alanını içermediği için, input model `\"tax\": 10.5` varsayılan değerini kullanacaktır.\n\nVe veri, bu \"yeni\" `tax` değeri olan `10.5` ile kaydedilecektir.\n\n## `PATCH` ile kısmi güncellemeler { #partial-updates-with-patch }\n\nVeriyi *kısmen* güncellemek için [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) operasyonunu da kullanabilirsiniz.\n\nBu, yalnızca güncellemek istediğiniz veriyi gönderip, geri kalanını olduğu gibi bırakabileceğiniz anlamına gelir.\n\n/// note | Not\n\n`PATCH`, `PUT`'a göre daha az yaygın kullanılır ve daha az bilinir.\n\nHatta birçok ekip, kısmi güncellemeler için bile yalnızca `PUT` kullanır.\n\nBunları nasıl isterseniz öyle kullanmakta **özgürsünüz**; **FastAPI** herhangi bir kısıtlama dayatmaz.\n\nAncak bu kılavuz, aşağı yukarı, bunların nasıl kullanılması amaçlandığını gösterir.\n\n///\n\n### Pydantic'in `exclude_unset` parametresini kullanma { #using-pydantics-exclude-unset-parameter }\n\nKısmi güncellemeler almak istiyorsanız, Pydantic modelinin `.model_dump()` metodundaki `exclude_unset` parametresini kullanmak çok faydalıdır.\n\nÖrneğin: `item.model_dump(exclude_unset=True)`.\n\nBu, `item` modeli oluşturulurken set edilmiş verileri içeren; varsayılan değerleri hariç tutan bir `dict` üretir.\n\nSonrasında bunu, yalnızca set edilmiş (request'te gönderilmiş) veriyi içeren; varsayılan değerleri atlayan bir `dict` üretmek için kullanabilirsiniz:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### Pydantic'in `update` parametresini kullanma { #using-pydantics-update-parameter }\n\nArtık `.model_copy()` ile mevcut modelin bir kopyasını oluşturup, güncellenecek verileri içeren bir `dict` ile `update` parametresini geçebilirsiniz.\n\nÖrneğin: `stored_item_model.model_copy(update=update_data)`:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### Kısmi güncellemeler özeti { #partial-updates-recap }\n\nÖzetle, kısmi güncelleme uygulamak için şunları yaparsınız:\n\n* (İsteğe bağlı olarak) `PUT` yerine `PATCH` kullanın.\n* Kayıtlı veriyi alın.\n* Bu veriyi bir Pydantic modeline koyun.\n* Input modelinden, varsayılan değerler olmadan bir `dict` üretin (`exclude_unset` kullanarak).\n    * Bu şekilde, modelinizdeki varsayılan değerlerle daha önce saklanmış değerlerin üzerine yazmak yerine, yalnızca kullanıcının gerçekten set ettiği değerleri güncellersiniz.\n* Kayıtlı modelin bir kopyasını oluşturun ve alınan kısmi güncellemeleri kullanarak attribute'larını güncelleyin (`update` parametresini kullanarak).\n* Kopyalanan modeli DB'nizde saklanabilecek bir şeye dönüştürün (ör. `jsonable_encoder` kullanarak).\n    * Bu, modelin `.model_dump()` metodunu yeniden kullanmaya benzer; ancak değerlerin JSON'a dönüştürülebilecek veri tiplerine çevrilmesini garanti eder (ör. `datetime` -> `str`).\n* Veriyi DB'nize kaydedin.\n* Güncellenmiş modeli döndürün.\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | İpucu\n\nAynı tekniği HTTP `PUT` operasyonu ile de kullanabilirsiniz.\n\nAncak buradaki örnek `PATCH` kullanıyor, çünkü bu kullanım senaryoları için tasarlanmıştır.\n\n///\n\n/// note | Not\n\nInput modelin yine de doğrulandığına dikkat edin.\n\nDolayısıyla, tüm attribute'ların atlanabildiği kısmi güncellemeler almak istiyorsanız, tüm attribute'ları optional olarak işaretlenmiş (varsayılan değerlerle veya `None` ile) bir modele ihtiyacınız vardır.\n\n**Güncelleme** için tüm değerleri optional olan modeller ile **oluşturma** için zorunlu değerlere sahip modelleri ayırmak için, [Extra Models](extra-models.md) bölümünde anlatılan fikirleri kullanabilirsiniz.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/tutorial/body.md",
    "content": "# Request Body { #request-body }\n\nBir client'ten (örneğin bir tarayıcıdan) API'nize veri göndermeniz gerektiğinde, bunu **request body** olarak gönderirsiniz.\n\nBir **request** body, client'in API'nize gönderdiği veridir. Bir **response** body ise API'nizin client'e gönderdiği veridir.\n\nAPI'niz neredeyse her zaman bir **response** body göndermek zorundadır. Ancak client'lerin her zaman **request body** göndermesi gerekmez; bazen sadece bir path isterler, belki birkaç query parametresiyle birlikte, ama body göndermezler.\n\nBir **request** body tanımlamak için, tüm gücü ve avantajlarıyla [Pydantic](https://docs.pydantic.dev/) modellerini kullanırsınız.\n\n/// info | Bilgi\n\nVeri göndermek için şunlardan birini kullanmalısınız: `POST` (en yaygını), `PUT`, `DELETE` veya `PATCH`.\n\n`GET` request'i ile body göndermek, spesifikasyonlarda tanımsız bir davranıştır; yine de FastAPI bunu yalnızca çok karmaşık/uç kullanım senaryoları için destekler.\n\nÖnerilmediği için Swagger UI ile etkileşimli dokümanlar, `GET` kullanırken body için dokümantasyonu göstermez ve aradaki proxy'ler bunu desteklemeyebilir.\n\n///\n\n## Pydantic'in `BaseModel`'ini import edin { #import-pydantics-basemodel }\n\nÖnce, `pydantic` içinden `BaseModel`'i import etmeniz gerekir:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## Veri modelinizi oluşturun { #create-your-data-model }\n\nSonra veri modelinizi, `BaseModel`'den kalıtım alan bir class olarak tanımlarsınız.\n\nTüm attribute'lar için standart Python type'larını kullanın:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\n\nQuery parametrelerini tanımlarken olduğu gibi, bir model attribute'ü default bir değere sahipse zorunlu değildir. Aksi halde zorunludur. Sadece opsiyonel yapmak için `None` kullanın.\n\nÖrneğin, yukarıdaki model şu şekilde bir JSON \"`object`\" (veya Python `dict`) tanımlar:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n...`description` ve `tax` opsiyonel olduğu için (default değerleri `None`), şu JSON \"`object`\" da geçerli olur:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## Parametre olarak tanımlayın { #declare-it-as-a-parameter }\n\nBunu *path operation*'ınıza eklemek için, path ve query parametrelerini tanımladığınız şekilde tanımlayın:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n...ve type'ını, oluşturduğunuz model olan `Item` olarak belirtin.\n\n## Sonuçlar { #results }\n\nSadece bu Python type tanımıyla, **FastAPI** şunları yapar:\n\n* Request'in body'sini JSON olarak okur.\n* İlgili type'lara dönüştürür (gerekirse).\n* Veriyi doğrular (validate eder).\n    * Veri geçersizse, tam olarak nerede ve hangi verinin hatalı olduğunu söyleyen, anlaşılır bir hata döndürür.\n* Aldığı veriyi `item` parametresi içinde size verir.\n    * Fonksiyonda bunun type'ını `Item` olarak tanımladığınız için, tüm attribute'lar ve type'ları için editor desteğini (tamamlama vb.) de alırsınız.\n* Modeliniz için [JSON Schema](https://json-schema.org) tanımları üretir; projeniz için anlamlıysa bunları başka yerlerde de kullanabilirsiniz.\n* Bu şemalar üretilen OpenAPI şemasının bir parçası olur ve otomatik dokümantasyon <abbr title=\"User Interfaces - Kullanıcı Arayüzleri\">UIs</abbr> tarafından kullanılır.\n\n## Otomatik dokümanlar { #automatic-docs }\n\nModellerinizin JSON Schema'ları, OpenAPI tarafından üretilen şemanın bir parçası olur ve etkileşimli API dokümanlarında gösterilir:\n\n<img src=\"/img/tutorial/body/image01.png\">\n\nAyrıca, ihtiyaç duyan her *path operation* içindeki API dokümanlarında da kullanılır:\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## Editor desteği { #editor-support }\n\nEditor'ünüzde, fonksiyonunuzun içinde her yerde type hint'leri ve tamamlama (completion) alırsınız (Pydantic modeli yerine `dict` alsaydınız bu olmazdı):\n\n<img src=\"/img/tutorial/body/image03.png\">\n\nYanlış type işlemleri için hata kontrolleri de alırsınız:\n\n<img src=\"/img/tutorial/body/image04.png\">\n\nBu bir tesadüf değil; tüm framework bu tasarımın etrafında inşa edildi.\n\nAyrıca, bunun tüm editor'lerle çalışacağından emin olmak için herhangi bir implementasyon yapılmadan önce tasarım aşamasında kapsamlı şekilde test edildi.\n\nHatta bunu desteklemek için Pydantic'in kendisinde bile bazı değişiklikler yapıldı.\n\nÖnceki ekran görüntüleri [Visual Studio Code](https://code.visualstudio.com) ile alınmıştır.\n\nAncak [PyCharm](https://www.jetbrains.com/pycharm/) ve diğer Python editor'lerinin çoğunda da aynı editor desteğini alırsınız:\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip | İpucu\n\nEditor olarak [PyCharm](https://www.jetbrains.com/pycharm/) kullanıyorsanız, [Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/) kullanabilirsiniz.\n\nPydantic modelleri için editor desteğini şu açılardan iyileştirir:\n\n* auto-completion\n* type checks\n* refactoring\n* searching\n* inspections\n\n///\n\n## Modeli kullanın { #use-the-model }\n\nFonksiyonun içinde model nesnesinin tüm attribute'larına doğrudan erişebilirsiniz:\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## Request body + path parametreleri { #request-body-path-parameters }\n\nPath parametrelerini ve request body'yi aynı anda tanımlayabilirsiniz.\n\n**FastAPI**, path parametreleriyle eşleşen fonksiyon parametrelerinin **path'ten alınması** gerektiğini ve Pydantic model olarak tanımlanan fonksiyon parametrelerinin **request body'den alınması** gerektiğini anlayacaktır.\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n\n## Request body + path + query parametreleri { #request-body-path-query-parameters }\n\n**body**, **path** ve **query** parametrelerini aynı anda da tanımlayabilirsiniz.\n\n**FastAPI** bunların her birini tanır ve veriyi doğru yerden alır.\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\nFonksiyon parametreleri şu şekilde tanınır:\n\n* Parametre, **path** içinde de tanımlıysa path parametresi olarak kullanılır.\n* Parametre **tekil bir type**'taysa (`int`, `float`, `str`, `bool` vb.), **query** parametresi olarak yorumlanır.\n* Parametre bir **Pydantic model** type'ı olarak tanımlandıysa, request **body** olarak yorumlanır.\n\n/// note | Not\n\nFastAPI, `q` değerinin zorunlu olmadığını `= None` default değerinden anlayacaktır.\n\n`str | None`, FastAPI tarafından bu değerin zorunlu olmadığını belirlemek için kullanılmaz; FastAPI bunun zorunlu olmadığını `= None` default değeri olduğu için bilir.\n\nAncak type annotation'larını eklemek, editor'ünüzün size daha iyi destek vermesini ve hataları yakalamasını sağlar.\n\n///\n\n## Pydantic olmadan { #without-pydantic }\n\nPydantic modellerini kullanmak istemiyorsanız, **Body** parametrelerini de kullanabilirsiniz. [Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body) dokümanına bakın.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/cookie-param-models.md",
    "content": "# Cookie Parametre Modelleri { #cookie-parameter-models }\n\nBirbirleriyle ilişkili bir **cookie** grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz. 🍪\n\nBu sayede **model'i yeniden kullanabilir**, **birden fazla yerde** tekrar tekrar kullanabilir ve tüm parametreler için validation ve metadata'yı tek seferde tanımlayabilirsiniz. 😎\n\n/// note | Not\n\nThis is supported since FastAPI version `0.115.0`. 🤓\n\n///\n\n/// tip | İpucu\n\nAynı teknik `Query`, `Cookie` ve `Header` için de geçerlidir. 😎\n\n///\n\n## Pydantic Model ile Cookies { #cookies-with-a-pydantic-model }\n\nİhtiyacınız olan **cookie** parametrelerini bir **Pydantic model** içinde tanımlayın ve ardından parametreyi `Cookie` olarak bildirin:\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI**, request ile gelen **cookies** içinden **her bir field** için veriyi **extract** eder ve size tanımladığınız Pydantic model'i verir.\n\n## Dokümanları Kontrol Edin { #check-the-docs }\n\nTanımlanan cookie'leri `/docs` altındaki docs UI'da görebilirsiniz:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info | Bilgi\n\nTarayıcıların cookie'leri özel biçimlerde ve arka planda yönetmesi nedeniyle, **JavaScript**'in cookie'lere erişmesine kolayca izin vermediğini aklınızda bulundurun.\n\n`/docs` altındaki **API docs UI**'a giderseniz, *path operation*'larınız için cookie'lerin **dokümantasyonunu** görebilirsiniz.\n\nAncak verileri **doldurup** \"Execute\" düğmesine tıklasanız bile, docs UI **JavaScript** ile çalıştığı için cookie'ler gönderilmez; dolayısıyla hiç değer girmemişsiniz gibi bir **error** mesajı görürsünüz.\n\n///\n\n## Fazladan Cookie'leri Yasaklayın { #forbid-extra-cookies }\n\nBazı özel kullanım senaryolarında (muhtemelen çok yaygın değildir) almak istediğiniz cookie'leri **kısıtlamak** isteyebilirsiniz.\n\nAPI'niz artık kendi <dfn title=\"Bu bir şaka, sadece bilginize. Cookie onaylarıyla ilgisi yok, ama API'nin de artık zavallı cookie'leri reddedebilmesi komik. Bir cookie alın. 🍪\">cookie onayı</dfn>'nı kontrol etme gücüne sahip. 🤪🍪\n\nPydantic'in model configuration'ını kullanarak `extra` olan herhangi bir field'ı `forbid` edebilirsiniz:\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\nBir client **fazladan cookie** göndermeye çalışırsa, bir **error** response alır.\n\nOnayınızı almak için bunca çaba harcayan zavallı cookie banner'ları... <dfn title=\"Bu da başka bir şaka. Dikkate almayın. Cookie'niz için biraz kahve alın. ☕\">API'nin bunu reddetmesi için</dfn>. 🍪\n\nÖrneğin client, değeri `good-list-please` olan bir `santa_tracker` cookie'si göndermeye çalışırsa, client `santa_tracker` <dfn title=\"Noel Baba cookie eksikliğini onaylamıyor. 🎅 Tamam, artık cookie şakası yok.\">cookie'ye izin verilmiyor</dfn> diyen bir **error** response alır:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## Özet { #summary }\n\n**FastAPI**'de <dfn title=\"Gitmeden önce son bir cookie alın. 🍪\">**cookie**</dfn> tanımlamak için **Pydantic model**'lerini kullanabilirsiniz. 😎\n"
  },
  {
    "path": "docs/tr/docs/tutorial/cookie-params.md",
    "content": "# Cookie (Çerez) Parametreleri { #cookie-parameters }\n\n`Query` ve `Path` parametrelerini tanımladığınız şekilde Cookie parametreleri tanımlayabilirsiniz.\n\n## `Cookie`'yi Import Edin { #import-cookie }\n\nÖncelikle, `Cookie`'yi import edin:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## `Cookie` Parametrelerini Tanımlayın { #declare-cookie-parameters }\n\nArdından, `Path` ve `Query` ile aynı yapıyı kullanarak Cookie parametrelerini tanımlayın.\n\nVarsayılan değeri ve tüm ekstra doğrulama veya annotation parametrelerini tanımlayabilirsiniz:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Teknik Detaylar\n\n`Cookie`, `Path` ve `Query`'nin \"kardeş\" sınıfıdır. O da aynı ortak `Param` sınıfından miras alır.\n\nAncak `fastapi`'dan `Query`, `Path`, `Cookie` ve diğerlerini import ettiğinizde, bunlar aslında özel sınıflar döndüren fonksiyonlardır, bunu unutmayın.\n\n///\n\n/// info | Bilgi\n\nCookie'leri tanımlamak için `Cookie` kullanmanız gerekir, aksi halde parametreler query parametreleri olarak yorumlanır.\n\n///\n\n/// info | Bilgi\n\n**Tarayıcılar cookie'leri** özel şekillerde ve arka planda işlediği için, **JavaScript**'in onlara dokunmasına kolayca izin **vermezler**.\n\n`/docs` adresindeki **API docs UI**'a giderseniz, *path operation*'larınız için cookie'lerin **dokümantasyonunu** görebilirsiniz.\n\nAncak **veriyi doldurup** \"Execute\" düğmesine tıklasanız bile, docs UI **JavaScript** ile çalıştığı için cookie'ler gönderilmez ve herhangi bir değer yazmamışsınız gibi bir **hata** mesajı görürsünüz.\n\n///\n\n## Özet { #recap }\n\n`Query` ve `Path` ile aynı ortak deseni kullanarak, cookie'leri `Cookie` ile tanımlayın.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/cors.md",
    "content": "# CORS (Cross-Origin Resource Sharing) { #cors-cross-origin-resource-sharing }\n\n[CORS veya \"Cross-Origin Resource Sharing\"](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), tarayıcıda çalışan bir frontend’in JavaScript kodunun bir backend ile iletişim kurduğu ve backend’in frontend’den farklı bir \"origin\"de olduğu durumları ifade eder.\n\n## Origin { #origin }\n\nOrigin; protocol (`http`, `https`), domain (`myapp.com`, `localhost`, `localhost.tiangolo.com`) ve port’un (`80`, `443`, `8080`) birleşimidir.\n\nDolayısıyla şunların hepsi farklı origin’lerdir:\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\nHepsi `localhost` üzerinde olsa bile, farklı protocol veya port kullandıkları için farklı \"origin\" sayılırlar.\n\n## Adımlar { #steps }\n\nDiyelim ki tarayıcınızda `http://localhost:8080` adresinde çalışan bir frontend’iniz var ve JavaScript’i, `http://localhost` adresinde çalışan bir backend ile iletişim kurmaya çalışıyor (port belirtmediğimiz için tarayıcı varsayılan port olan `80`’i kullanacaktır).\n\nBu durumda tarayıcı, `:80`-backend’e bir HTTP `OPTIONS` request’i gönderir. Eğer backend, bu farklı origin’den (`http://localhost:8080`) gelen iletişimi yetkilendiren uygun header’ları gönderirse, `:8080`-tarayıcı frontend’deki JavaScript’in `:80`-backend’e request göndermesine izin verir.\n\nBunu sağlayabilmek için `:80`-backend’in bir \"allowed origins\" listesi olmalıdır.\n\nBu örnekte `:8080`-frontend’in doğru çalışması için listede `http://localhost:8080` bulunmalıdır.\n\n## Wildcard'lar { #wildcards }\n\nListeyi `\"*\"` (bir \"wildcard\") olarak tanımlayıp, hepsine izin verildiğini söylemek de mümkündür.\n\nAncak bu, credentials içeren her şeyi hariç tutarak yalnızca belirli iletişim türlerine izin verir: Cookie’ler, Bearer Token’larla kullanılanlar gibi Authorization header’ları, vb.\n\nBu yüzden her şeyin düzgün çalışması için, izin verilen origin’leri açıkça belirtmek daha iyidir.\n\n## `CORSMiddleware` Kullanımı { #use-corsmiddleware }\n\nBunu **FastAPI** uygulamanızda `CORSMiddleware` ile yapılandırabilirsiniz.\n\n* `CORSMiddleware`’i import edin.\n* İzin verilen origin’lerden (string) oluşan bir liste oluşturun.\n* Bunu **FastAPI** uygulamanıza bir \"middleware\" olarak ekleyin.\n\nAyrıca backend’in şunlara izin verip vermediğini de belirtebilirsiniz:\n\n* Credentials (Authorization header’ları, Cookie’ler, vb).\n* Belirli HTTP method’ları (`POST`, `PUT`) veya wildcard `\"*\"` ile hepsini.\n* Belirli HTTP header’ları veya wildcard `\"*\"` ile hepsini.\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\n\n`CORSMiddleware` implementasyonu tarafından kullanılan varsayılan parametreler kısıtlayıcıdır; bu nedenle tarayıcıların Cross-Domain bağlamında kullanmasına izin vermek için belirli origin’leri, method’ları veya header’ları açıkça etkinleştirmeniz gerekir.\n\nAşağıdaki argümanlar desteklenir:\n\n* `allow_origins` - Cross-origin request yapmasına izin verilmesi gereken origin’lerin listesi. Örn. `['https://example.org', 'https://www.example.org']`. Herhangi bir origin’e izin vermek için `['*']` kullanabilirsiniz.\n* `allow_origin_regex` - Cross-origin request yapmasına izin verilmesi gereken origin’lerle eşleşecek bir regex string’i. Örn. `'https://.*\\.example\\.org'`.\n* `allow_methods` - Cross-origin request’lerde izin verilmesi gereken HTTP method’larının listesi. Varsayılanı `['GET']`. Tüm standart method’lara izin vermek için `['*']` kullanabilirsiniz.\n* `allow_headers` - Cross-origin request’lerde desteklenmesi gereken HTTP request header’larının listesi. Varsayılanı `[]`. Tüm header’lara izin vermek için `['*']` kullanabilirsiniz. `Accept`, `Accept-Language`, `Content-Language` ve `Content-Type` header’larına [basit CORS request'leri](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests) için her zaman izin verilir.\n* `allow_credentials` - Cross-origin request’ler için cookie desteği olup olmayacağını belirtir. Varsayılanı `False`.\n\n    `allow_credentials` `True` olarak ayarlanmışsa, `allow_origins`, `allow_methods` ve `allow_headers` değerlerinin hiçbiri `['*']` olamaz. Hepsinin [açıkça belirtilmesi](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards) gerekir.\n\n* `expose_headers` - Tarayıcının erişebilmesi gereken response header’larını belirtir. Varsayılanı `[]`.\n* `max_age` - Tarayıcıların CORS response’larını cache’lemesi için saniye cinsinden azami süreyi ayarlar. Varsayılanı `600`.\n\nMiddleware iki özel HTTP request türüne yanıt verir...\n\n### CORS preflight request'leri { #cors-preflight-requests }\n\nBunlar, `Origin` ve `Access-Control-Request-Method` header’larına sahip herhangi bir `OPTIONS` request’idir.\n\nBu durumda middleware gelen request’i intercept eder ve uygun CORS header’larıyla yanıt verir; bilgilendirme amaçlı olarak da `200` veya `400` response döndürür.\n\n### Basit request'ler { #simple-requests }\n\n`Origin` header’ı olan herhangi bir request. Bu durumda middleware request’i normal şekilde geçirir, ancak response’a uygun CORS header’larını ekler.\n\n## Daha Fazla Bilgi { #more-info }\n\n<abbr title=\"Cross-Origin Resource Sharing - Kökenler Arası Kaynak Paylaşımı\">CORS</abbr> hakkında daha fazla bilgi için [Mozilla CORS dokümantasyonu](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)na bakın.\n\n/// note | Teknik Detaylar\n\n`from starlette.middleware.cors import CORSMiddleware` şeklinde de kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak size kolaylık olması için `fastapi.middleware` içinde bazı middleware’ler sağlar. Ancak mevcut middleware’lerin çoğu doğrudan Starlette’ten gelir.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/tutorial/debugging.md",
    "content": "# Debugging { #debugging }\n\nVisual Studio Code veya PyCharm gibi editörünüzde debugger'ı bağlayabilirsiniz.\n\n## `uvicorn`'ı Çağırma { #call-uvicorn }\n\nFastAPI uygulamanızda `uvicorn`'ı import edip doğrudan çalıştırın:\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### `__name__ == \"__main__\"` Hakkında { #about-name-main }\n\n`__name__ == \"__main__\"` ifadesinin temel amacı, dosyanız şu şekilde çağrıldığında çalışacak:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nancak başka bir dosya onu import ettiğinde çalışmayacak bir kod bölümüne sahip olmaktır, örneğin:\n\n```Python\nfrom myapp import app\n```\n\n#### Daha fazla detay { #more-details }\n\nDosyanızın adının `myapp.py` olduğunu varsayalım.\n\nŞu şekilde çalıştırırsanız:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nPython tarafından otomatik oluşturulan, dosyanızın içindeki `__name__` adlı dahili değişkenin değeri `\"__main__\"` string'i olur.\n\nDolayısıyla şu bölüm:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nçalışır.\n\n---\n\nAncak modülü (dosyayı) import ederseniz bu gerçekleşmez.\n\nYani örneğin `importer.py` adında başka bir dosyanız var ve içinde şunlar bulunuyorsa:\n\n```Python\nfrom myapp import app\n\n# Some more code\n```\n\nbu durumda `myapp.py` içindeki otomatik oluşturulan `__name__` değişkeni `\"__main__\"` değerine sahip olmaz.\n\nBu yüzden şu satır:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nçalıştırılmaz.\n\n/// info | Bilgi\n\nDaha fazla bilgi için [resmi Python dokümantasyonuna](https://docs.python.org/3/library/__main__.html) bakın.\n\n///\n\n## Kodunuzu Debugger ile Çalıştırma { #run-your-code-with-your-debugger }\n\nUvicorn server'ını doğrudan kodunuzdan çalıştırdığınız için, Python programınızı (FastAPI uygulamanızı) debugger'dan doğrudan başlatabilirsiniz.\n\n---\n\nÖrneğin Visual Studio Code'da şunları yapabilirsiniz:\n\n* \"Debug\" paneline gidin.\n* \"Add configuration...\" seçin.\n* \"Python\" seçin\n* \"`Python: Current File (Integrated Terminal)`\" seçeneğiyle debugger'ı çalıştırın.\n\nBöylece server, **FastAPI** kodunuzla başlar; breakpoint'lerinizde durur vb.\n\nAşağıdaki gibi görünebilir:\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\nPyCharm kullanıyorsanız şunları yapabilirsiniz:\n\n* \"Run\" menüsünü açın.\n* \"Debug...\" seçeneğini seçin.\n* Bir context menü açılır.\n* Debug edilecek dosyayı seçin (bu örnekte `main.py`).\n\nBöylece server, **FastAPI** kodunuzla başlar; breakpoint'lerinizde durur vb.\n\nAşağıdaki gibi görünebilir:\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/tr/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# Dependency Olarak Class'lar { #classes-as-dependencies }\n\n**Dependency Injection** sistemine daha derinlemesine geçmeden önce, bir önceki örneği geliştirelim.\n\n## Önceki Örnekten Bir `dict` { #a-dict-from-the-previous-example }\n\nÖnceki örnekte, dependency'mizden (\"dependable\") bir `dict` döndürüyorduk:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\nAma sonra *path operation function* içindeki `commons` parametresinde bir `dict` alıyoruz.\n\nVe biliyoruz ki editor'ler `dict`'ler için çok fazla destek (ör. completion) veremez; çünkü key'lerini ve value type'larını bilemezler.\n\nDaha iyisini yapabiliriz...\n\n## Bir Şeyi Dependency Yapan Nedir { #what-makes-a-dependency }\n\nŞimdiye kadar dependency'leri function olarak tanımlanmış şekilde gördünüz.\n\nAncak dependency tanımlamanın tek yolu bu değil (muhtemelen en yaygını bu olsa da).\n\nBuradaki kritik nokta, bir dependency'nin \"callable\" olması gerektiğidir.\n\nPython'da \"**callable**\", Python'ın bir function gibi \"çağırabildiği\" her şeydir.\n\nYani elinizde `something` adlı bir nesne varsa (function _olmak zorunda değil_) ve onu şöyle \"çağırabiliyorsanız\" (çalıştırabiliyorsanız):\n\n```Python\nsomething()\n```\n\nveya\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\no zaman bu bir \"callable\" demektir.\n\n## Dependency Olarak Class'lar { #classes-as-dependencies_1 }\n\nPython'da bir class'tan instance oluştururken de aynı söz dizimini kullandığınızı fark etmiş olabilirsiniz.\n\nÖrneğin:\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\nBu durumda `fluffy`, `Cat` class'ının bir instance'ıdır.\n\nVe `fluffy` oluşturmak için `Cat`'i \"çağırmış\" olursunuz.\n\nDolayısıyla bir Python class'ı da bir **callable**'dır.\n\nO zaman **FastAPI** içinde bir Python class'ını dependency olarak kullanabilirsiniz.\n\nFastAPI'nin aslında kontrol ettiği şey, bunun bir \"callable\" olması (function, class ya da başka bir şey) ve tanımlı parametreleridir.\n\nEğer **FastAPI**'de bir dependency olarak bir \"callable\" verirseniz, FastAPI o \"callable\" için parametreleri analiz eder ve bunları *path operation function* parametreleriyle aynı şekilde işler. Sub-dependency'ler dahil.\n\nBu, hiç parametresi olmayan callable'lar için de geçerlidir. Tıpkı hiç parametresi olmayan *path operation function*'larda olduğu gibi.\n\nO zaman yukarıdaki `common_parameters` adlı \"dependable\" dependency'sini `CommonQueryParams` class'ına çevirebiliriz:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\nClass instance'ını oluşturmak için kullanılan `__init__` metoduna dikkat edin:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n...bizim önceki `common_parameters` ile aynı parametrelere sahip:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\nBu parametreler, dependency'yi \"çözmek\" için **FastAPI**'nin kullanacağı şeylerdir.\n\nHer iki durumda da şunlar olacak:\n\n* `str` olan opsiyonel bir `q` query parametresi.\n* Default değeri `0` olan `int` tipinde bir `skip` query parametresi.\n* Default değeri `100` olan `int` tipinde bir `limit` query parametresi.\n\nHer iki durumda da veriler dönüştürülecek, doğrulanacak, OpenAPI şemasında dokümante edilecek, vb.\n\n## Kullanalım { #use-it }\n\nArtık bu class'ı kullanarak dependency'nizi tanımlayabilirsiniz.\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI**, `CommonQueryParams` class'ını çağırır. Bu, o class'ın bir \"instance\"ını oluşturur ve bu instance, sizin function'ınıza `commons` parametresi olarak geçirilir.\n\n## Type Annotation vs `Depends` { #type-annotation-vs-depends }\n\nYukarıdaki kodda `CommonQueryParams`'ı iki kez yazdığımıza dikkat edin:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ Annotated Olmadan\n\n/// tip | İpucu\n\nMümkünse `Annotated` sürümünü kullanmayı tercih edin.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\nŞuradaki son `CommonQueryParams`:\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n...FastAPI'nin dependency'nin ne olduğunu anlamak için gerçekten kullandığı şeydir.\n\nFastAPI tanımlanan parametreleri buradan çıkarır ve aslında çağıracağı şey de budur.\n\n---\n\nBu durumda, şuradaki ilk `CommonQueryParams`:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ Annotated Olmadan\n\n/// tip | İpucu\n\nMümkünse `Annotated` sürümünü kullanmayı tercih edin.\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n...**FastAPI** için özel bir anlam taşımaz. FastAPI bunu veri dönüştürme, doğrulama vb. için kullanmaz (çünkü bunlar için `Depends(CommonQueryParams)` kullanıyor).\n\nHatta şunu bile yazabilirsiniz:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ Annotated Olmadan\n\n/// tip | İpucu\n\nMümkünse `Annotated` sürümünü kullanmayı tercih edin.\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n...şu örnekte olduğu gibi:\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\nAncak type'ı belirtmeniz önerilir; böylece editor'ünüz `commons` parametresine ne geçirileceğini bilir ve size code completion, type check'leri vb. konularda yardımcı olur:\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## Kısayol { #shortcut }\n\nAma burada bir miktar kod tekrarımız olduğunu görüyorsunuz; `CommonQueryParams`'ı iki kez yazıyoruz:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ Annotated Olmadan\n\n/// tip | İpucu\n\nMümkünse `Annotated` sürümünü kullanmayı tercih edin.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n**FastAPI**, bu durumlar için bir kısayol sağlar: dependency'nin *özellikle* FastAPI'nin bir instance oluşturmak için \"çağıracağı\" bir class olduğu durumlar.\n\nBu özel durumlarda şunu yapabilirsiniz:\n\nŞunu yazmak yerine:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ Annotated Olmadan\n\n/// tip | İpucu\n\nMümkünse `Annotated` sürümünü kullanmayı tercih edin.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n...şunu yazarsınız:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ Annotated Olmadan\n\n/// tip | İpucu\n\nMümkünse `Annotated` sürümünü kullanmayı tercih edin.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\nDependency'yi parametrenin type'ı olarak tanımlarsınız ve `Depends(CommonQueryParams)` içinde class'ı *yeniden* yazmak yerine, parametre vermeden `Depends()` kullanırsınız.\n\nAynı örnek şu hale gelir:\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n...ve **FastAPI** ne yapması gerektiğini bilir.\n\n/// tip | İpucu\n\nBu size faydalı olmaktan çok kafa karıştırıcı geliyorsa, kullanmayın; buna *ihtiyacınız* yok.\n\nBu sadece bir kısayoldur. Çünkü **FastAPI** kod tekrarını en aza indirmenize yardımcı olmayı önemser.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# Path Operation Decorator'lerinde Dependency'ler { #dependencies-in-path-operation-decorators }\n\nBazı durumlarda bir dependency'nin döndürdüğü değere *path operation function* içinde gerçekten ihtiyacınız olmaz.\n\nYa da dependency zaten bir değer döndürmüyordur.\n\nAncak yine de çalıştırılmasını/çözülmesini istersiniz.\n\nBu gibi durumlarda, `Depends` ile bir *path operation function* parametresi tanımlamak yerine, *path operation decorator*'üne `dependencies` adında bir `list` ekleyebilirsiniz.\n\n## *Path Operation Decorator*'üne `dependencies` Ekleyin { #add-dependencies-to-the-path-operation-decorator }\n\n*Path operation decorator*, opsiyonel bir `dependencies` argümanı alır.\n\nBu, `Depends()` öğelerinden oluşan bir `list` olmalıdır:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\nBu dependency'ler normal dependency'lerle aynı şekilde çalıştırılır/çözülür. Ancak (eğer bir değer döndürüyorlarsa) bu değer *path operation function*'ınıza aktarılmaz.\n\n/// tip | İpucu\n\nBazı editörler, kullanılmayan function parametrelerini kontrol eder ve bunları hata olarak gösterebilir.\n\nBu `dependencies` yaklaşımıyla, editör/araç hatalarına takılmadan dependency'lerin çalıştırılmasını sağlayabilirsiniz.\n\nAyrıca kodunuzda kullanılmayan bir parametreyi gören yeni geliştiricilerin bunun gereksiz olduğunu düşünmesi gibi bir kafa karışıklığını da azaltabilir.\n\n///\n\n/// info | Bilgi\n\nBu örnekte uydurma özel header'lar olan `X-Key` ve `X-Token` kullanıyoruz.\n\nAncak gerçek senaryolarda, security uygularken, entegre [Security yardımcı araçlarını (bir sonraki bölüm)](../security/index.md) kullanmak size daha fazla fayda sağlar.\n\n///\n\n## Dependency Hataları ve Return Değerleri { #dependencies-errors-and-return-values }\n\nNormalde kullandığınız aynı dependency *function*'larını burada da kullanabilirsiniz.\n\n### Dependency Gereksinimleri { #dependency-requirements }\n\nRequest gereksinimleri (header'lar gibi) veya başka alt dependency'ler tanımlayabilirler:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### Exception Fırlatmak { #raise-exceptions }\n\nBu dependency'ler, normal dependency'lerde olduğu gibi `raise` ile exception fırlatabilir:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### Return Değerleri { #return-values }\n\nAyrıca değer döndürebilirler ya da döndürmeyebilirler; dönen değer kullanılmayacaktır.\n\nYani başka bir yerde zaten kullandığınız, değer döndüren normal bir dependency'yi tekrar kullanabilirsiniz; değer kullanılmasa bile dependency çalıştırılacaktır:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## Bir *Path Operation* Grubu İçin Dependency'ler { #dependencies-for-a-group-of-path-operations }\n\nDaha sonra, muhtemelen birden fazla dosya kullanarak daha büyük uygulamaları nasıl yapılandıracağınızı okurken ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md)), bir *path operation* grubu için tek bir `dependencies` parametresini nasıl tanımlayacağınızı öğreneceksiniz.\n\n## Global Dependency'ler { #global-dependencies }\n\nSırada, dependency'leri tüm `FastAPI` uygulamasına nasıl ekleyeceğimizi göreceğiz; böylece her *path operation* için geçerli olacaklar.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# `yield` ile Dependency'ler { #dependencies-with-yield }\n\nFastAPI, işini bitirdikten sonra <dfn title='bazen \"exit code\", \"cleanup code\", \"teardown code\", \"closing code\", \"context manager exit code\" vb. olarak da adlandırılır'>ek adımlar</dfn> çalıştıran dependency'leri destekler.\n\nBunu yapmak için `return` yerine `yield` kullanın ve ek adımları (kodu) `yield` satırından sonra yazın.\n\n/// tip | İpucu\n\nHer dependency için yalnızca bir kez `yield` kullandığınızdan emin olun.\n\n///\n\n/// note | Teknik Detaylar\n\nŞunlarla kullanılabilen herhangi bir fonksiyon:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) veya\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nbir **FastAPI** dependency'si olarak kullanılabilir.\n\nHatta FastAPI bu iki decorator'ı içeride (internally) kullanır.\n\n///\n\n## `yield` ile Bir Veritabanı Dependency'si { #a-database-dependency-with-yield }\n\nÖrneğin bunu, bir veritabanı session'ı oluşturmak ve iş bittikten sonra kapatmak için kullanabilirsiniz.\n\nResponse oluşturulmadan önce yalnızca `yield` satırına kadar olan (ve `yield` dahil) kod çalıştırılır:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\n`yield` edilen değer, *path operation*'lara ve diğer dependency'lere enjekte edilen (injected) değerdir:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\nResponse'dan sonra `yield` satırını takip eden kod çalıştırılır:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip | İpucu\n\n`async` ya da normal fonksiyonlar kullanabilirsiniz.\n\n**FastAPI**, normal dependency'lerde olduğu gibi her ikisinde de doğru şekilde davranır.\n\n///\n\n## `yield` ve `try` ile Bir Dependency { #a-dependency-with-yield-and-try }\n\n`yield` kullanan bir dependency içinde bir `try` bloğu kullanırsanız, dependency kullanılırken fırlatılan (raised) herhangi bir exception'ı alırsınız.\n\nÖrneğin, başka bir dependency'de veya bir *path operation* içinde çalışan bir kod, bir veritabanı transaction'ını \"rollback\" yaptıysa ya da başka bir exception oluşturduysa, o exception dependency'nizde size gelir.\n\nDolayısıyla `except SomeException` ile dependency içinde o spesifik exception'ı yakalayabilirsiniz.\n\nAynı şekilde, exception olsun ya da olmasın çıkış (exit) adımlarının çalıştırılmasını garanti etmek için `finally` kullanabilirsiniz.\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## `yield` ile Alt Dependency'ler { #sub-dependencies-with-yield }\n\nHer boyutta ve şekilde alt dependency'ler ve alt dependency \"ağaçları\" (trees) oluşturabilirsiniz; bunların herhangi biri veya hepsi `yield` kullanabilir.\n\n**FastAPI**, `yield` kullanan her dependency'deki \"exit code\"'un doğru sırayla çalıştırılmasını sağlar.\n\nÖrneğin, `dependency_c`, `dependency_b`'ye; `dependency_b` de `dependency_a`'ya bağlı olabilir:\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\nVe hepsi `yield` kullanabilir.\n\nBu durumda `dependency_c`, exit code'unu çalıştırabilmek için `dependency_b`'den gelen değerin (burada `dep_b`) hâlâ erişilebilir olmasına ihtiyaç duyar.\n\nAynı şekilde `dependency_b` de exit code'u için `dependency_a`'dan gelen değerin (burada `dep_a`) erişilebilir olmasına ihtiyaç duyar.\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\nBenzer şekilde, bazı dependency'ler `yield`, bazıları `return` kullanabilir ve bunların bazıları diğerlerine bağlı olabilir.\n\nAyrıca birden fazla `yield` kullanan dependency gerektiren tek bir dependency'niz de olabilir, vb.\n\nİstediğiniz herhangi bir dependency kombinasyonunu kullanabilirsiniz.\n\n**FastAPI** her şeyin doğru sırada çalışmasını sağlar.\n\n/// note | Teknik Detaylar\n\nBu, Python'un [Context Managers](https://docs.python.org/3/library/contextlib.html) yapısı sayesinde çalışır.\n\n**FastAPI** bunu sağlamak için içeride onları kullanır.\n\n///\n\n## `yield` ve `HTTPException` ile Dependency'ler { #dependencies-with-yield-and-httpexception }\n\n`yield` kullanan dependency'lerde `try` bloklarıyla bazı kodları çalıştırıp ardından `finally` sonrasında exit code çalıştırabileceğinizi gördünüz.\n\nAyrıca `except` ile fırlatılan exception'ı yakalayıp onunla bir şey yapabilirsiniz.\n\nÖrneğin `HTTPException` gibi farklı bir exception fırlatabilirsiniz.\n\n/// tip | İpucu\n\nBu biraz ileri seviye bir tekniktir ve çoğu durumda gerçekten ihtiyaç duymazsınız; çünkü exception'ları (`HTTPException` dahil) uygulamanızın geri kalan kodundan, örneğin *path operation function* içinden fırlatabilirsiniz.\n\nAma ihtiyaç duyarsanız diye burada. 🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\nException yakalayıp buna göre özel bir response oluşturmak istiyorsanız bir [Custom Exception Handler](../handling-errors.md#install-custom-exception-handlers) oluşturun.\n\n## `yield` ve `except` ile Dependency'ler { #dependencies-with-yield-and-except }\n\n`yield` kullanan bir dependency içinde `except` ile bir exception yakalar ve bunu tekrar fırlatmazsanız (ya da yeni bir exception fırlatmazsanız), FastAPI normal Python'da olduğu gibi bir exception olduğunu fark edemez:\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\nBu durumda client, biz `HTTPException` veya benzeri bir şey fırlatmadığımız için olması gerektiği gibi *HTTP 500 Internal Server Error* response'u görür; ancak server **hiç log üretmez** ve hatanın ne olduğuna dair başka bir işaret de olmaz. 😱\n\n### `yield` ve `except` Kullanan Dependency'lerde Her Zaman `raise` Edin { #always-raise-in-dependencies-with-yield-and-except }\n\n`yield` kullanan bir dependency içinde bir exception yakalarsanız, başka bir `HTTPException` veya benzeri bir şey fırlatmıyorsanız, **orijinal exception'ı tekrar raise etmelisiniz**.\n\nAynı exception'ı `raise` ile tekrar fırlatabilirsiniz:\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\nArtık client yine aynı *HTTP 500 Internal Server Error* response'unu alır, ama server log'larda bizim özel `InternalError`'ımızı görür. 😎\n\n## `yield` Kullanan Dependency'lerin Çalıştırılması { #execution-of-dependencies-with-yield }\n\nÇalıştırma sırası kabaca aşağıdaki diyagramdaki gibidir. Zaman yukarıdan aşağı akar. Her sütun, etkileşime giren veya kod çalıştıran parçalardan birini temsil eder.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exception handler\nparticipant dep as Dep with yield\nparticipant operation as Path Operation\nparticipant tasks as Background tasks\n\n    Note over client,operation: Can raise exceptions, including HTTPException\n    client ->> dep: Start request\n    Note over dep: Run code up to yield\n    opt raise Exception\n        dep -->> handler: Raise Exception\n        handler -->> client: HTTP error response\n    end\n    dep ->> operation: Run dependency, e.g. DB session\n    opt raise\n        operation -->> dep: Raise Exception (e.g. HTTPException)\n        opt handle\n            dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception\n        end\n        handler -->> client: HTTP error response\n    end\n\n    operation ->> client: Return response to client\n    Note over client,operation: Response is already sent, can't change it anymore\n    opt Tasks\n        operation -->> tasks: Send background tasks\n    end\n    opt Raise other exception\n        tasks -->> tasks: Handle exceptions in the background task code\n    end\n```\n\n/// info | Bilgi\n\nClient'a yalnızca **tek bir response** gönderilir. Bu, error response'lardan biri olabilir ya da *path operation*'dan dönen response olabilir.\n\nBu response'lardan biri gönderildikten sonra başka bir response gönderilemez.\n\n///\n\n/// tip | İpucu\n\n*Path operation function* içindeki koddan herhangi bir exception raise ederseniz, `HTTPException` dahil olmak üzere bu exception `yield` kullanan dependency'lere aktarılır. Çoğu durumda, doğru şekilde ele alındığından emin olmak için `yield` kullanan dependency'den aynı exception'ı (veya yeni bir tanesini) yeniden raise etmek istersiniz.\n\n///\n\n## Erken Çıkış ve `scope` { #early-exit-and-scope }\n\nNormalde `yield` kullanan dependency'lerin exit code'u, client'a response gönderildikten **sonra** çalıştırılır.\n\nAma *path operation function*'dan döndükten sonra dependency'yi kullanmayacağınızı biliyorsanız, `Depends(scope=\"function\")` kullanarak FastAPI'ye dependency'yi *path operation function* döndükten sonra kapatmasını, ancak **response gönderilmeden önce** kapatmasını söyleyebilirsiniz.\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()` şu değerleri alabilen bir `scope` parametresi alır:\n\n* `\"function\"`: dependency'yi request'i işleyen *path operation function* çalışmadan önce başlat, *path operation function* bittikten sonra bitir, ancak response client'a geri gönderilmeden **önce** sonlandır. Yani dependency fonksiyonu, *path operation **function***'ın **etrafında** çalıştırılır.\n* `\"request\"`: dependency'yi request'i işleyen *path operation function* çalışmadan önce başlat (`\"function\"` kullanımına benzer), ancak response client'a geri gönderildikten **sonra** sonlandır. Yani dependency fonksiyonu, **request** ve response döngüsünün **etrafında** çalıştırılır.\n\nBelirtilmezse ve dependency `yield` kullanıyorsa, varsayılan olarak `scope` `\"request\"` olur.\n\n### Alt dependency'ler için `scope` { #scope-for-sub-dependencies }\n\n`scope=\"request\"` (varsayılan) ile bir dependency tanımladığınızda, herhangi bir alt dependency'nin `scope` değeri de `\"request\"` olmalıdır.\n\nAncak `scope` değeri `\"function\"` olan bir dependency, hem `\"function\"` hem de `\"request\"` scope'una sahip dependency'lere bağlı olabilir.\n\nBunun nedeni, bir dependency'nin exit code'unu alt dependency'lerden önce çalıştırabilmesi gerekmesidir; çünkü exit code sırasında hâlâ onları kullanması gerekebilir.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Dep scope=\"request\"\nparticipant dep_func as Dep scope=\"function\"\nparticipant operation as Path Operation\n\n    client ->> dep_req: Start request\n    Note over dep_req: Run code up to yield\n    dep_req ->> dep_func: Pass dependency\n    Note over dep_func: Run code up to yield\n    dep_func ->> operation: Run path operation with dependency\n    operation ->> dep_func: Return from path operation\n    Note over dep_func: Run code after yield\n    Note over dep_func: ✅ Dependency closed\n    dep_func ->> client: Send response to client\n    Note over client: Response sent\n    Note over dep_req: Run code after yield\n    Note over dep_req: ✅ Dependency closed\n```\n\n## `yield`, `HTTPException`, `except` ve Background Tasks ile Dependency'ler { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n`yield` kullanan dependency'ler, zaman içinde farklı kullanım senaryolarını kapsamak ve bazı sorunları düzeltmek için gelişti.\n\nFastAPI'nin farklı sürümlerinde nelerin değiştiğini görmek isterseniz, advanced guide'da şu bölümü okuyabilirsiniz: [Advanced Dependencies - Dependencies with `yield`, `HTTPException`, `except` and Background Tasks](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).\n## Context Managers { #context-managers }\n\n### \"Context Managers\" Nedir? { #what-are-context-managers }\n\n\"Context Managers\", `with` ifadesiyle kullanabildiğiniz Python nesneleridir.\n\nÖrneğin, [bir dosyayı okumak için `with` kullanabilirsiniz](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files):\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\nTemelde `open(\"./somefile.txt\")`, \"Context Manager\" olarak adlandırılan bir nesne oluşturur.\n\n`with` bloğu bittiğinde, exception olsa bile dosyanın kapatılmasını garanti eder.\n\n`yield` ile bir dependency oluşturduğunuzda, **FastAPI** içeride bunun için bir context manager oluşturur ve bazı ilgili başka araçlarla birleştirir.\n\n### `yield` kullanan dependency'lerde context manager kullanma { #using-context-managers-in-dependencies-with-yield }\n\n/// warning | Uyarı\n\nBu, az çok \"ileri seviye\" bir fikirdir.\n\n**FastAPI**'ye yeni başlıyorsanız şimdilik bunu atlamak isteyebilirsiniz.\n\n///\n\nPython'da Context Manager'ları, [iki method'a sahip bir class oluşturarak: `__enter__()` ve `__exit__()`](https://docs.python.org/3/reference/datamodel.html#context-managers) yaratabilirsiniz.\n\nAyrıca dependency fonksiyonunun içinde `with` veya `async with` ifadeleri kullanarak **FastAPI**'de `yield` kullanan dependency'lerin içinde de kullanabilirsiniz:\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip | İpucu\n\nBir context manager oluşturmanın başka bir yolu da şunlardır:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) veya\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nBunları, tek bir `yield` içeren bir fonksiyonu decorate etmek için kullanabilirsiniz.\n\nFastAPI, `yield` kullanan dependency'ler için içeride bunu yapar.\n\nAncak FastAPI dependency'leri için bu decorator'ları kullanmak zorunda değilsiniz (hatta kullanmamalısınız).\n\nFastAPI bunu sizin yerinize içeride yapar.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# Global Dependencies { #global-dependencies }\n\nBazı uygulama türlerinde, tüm uygulama için dependency eklemek isteyebilirsiniz.\n\n[`dependencies`'i *path operation decorator*'larına ekleyebildiğiniz](dependencies-in-path-operation-decorators.md) gibi, `FastAPI` uygulamasına da ekleyebilirsiniz.\n\nBu durumda, uygulamadaki tüm *path operation*'lara uygulanırlar:\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\n\nVe [*path operation decorator*'larına `dependencies` ekleme](dependencies-in-path-operation-decorators.md) bölümündeki tüm fikirler hâlâ geçerlidir; ancak bu sefer, uygulamadaki tüm *path operation*'lar için geçerli olur.\n\n## *Path operations* grupları için Dependencies { #dependencies-for-groups-of-path-operations }\n\nİleride, daha büyük uygulamaları nasıl yapılandıracağınızı ([Bigger Applications - Multiple Files](../../tutorial/bigger-applications.md)) okurken, muhtemelen birden fazla dosyayla birlikte, bir *path operations* grubu için tek bir `dependencies` parametresini nasıl tanımlayacağınızı öğreneceksiniz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/dependencies/index.md",
    "content": "# Bağımlılıklar { #dependencies }\n\n**FastAPI**, çok güçlü ama aynı zamanda sezgisel bir **<dfn title=\"diğer adları: bileşenler, kaynaklar, sağlayıcılar, servisler, enjekte edilebilenler\">Bağımlılık Enjeksiyonu</dfn>** sistemine sahiptir.\n\nKullanımı çok basit olacak şekilde tasarlanmıştır ve herhangi bir geliştiricinin diğer bileşenleri **FastAPI** ile entegre etmesini kolaylaştırır.\n\n## \"Dependency Injection\" Nedir? { #what-is-dependency-injection }\n\nProgramlamada **\"Dependency Injection\"**, kodunuzun (bu örnekte *path operation function*'larınızın) çalışmak ve kullanmak için ihtiyaç duyduğu şeyleri: \"dependencies\" (bağımlılıklar) olarak beyan edebilmesi anlamına gelir.\n\nArdından bu sistem (bu örnekte **FastAPI**), kodunuza gerekli bağımlılıkları sağlamak (\"inject\" etmek) için gereken her şeyi sizin yerinize halleder.\n\nBu yaklaşım, şunlara ihtiyaç duyduğunuzda özellikle faydalıdır:\n\n* Paylaşılan bir mantığa sahip olmak (aynı kod mantığını tekrar tekrar kullanmak).\n* Veritabanı bağlantılarını paylaşmak.\n* Güvenlik, authentication, rol gereksinimleri vb. kuralları zorunlu kılmak.\n* Ve daha birçok şey...\n\nTüm bunları, kod tekrarını minimumda tutarak yaparsınız.\n\n## İlk Adımlar { #first-steps }\n\nÇok basit bir örneğe bakalım. Şimdilik o kadar basit olacak ki pek işe yaramayacak.\n\nAma bu sayede **Dependency Injection** sisteminin nasıl çalıştığına odaklanabiliriz.\n\n### Bir dependency (bağımlılık) veya \"dependable\" Oluşturun { #create-a-dependency-or-dependable }\n\nÖnce dependency'e odaklanalım.\n\nBu, bir *path operation function*'ın alabileceği parametrelerin aynısını alabilen basit bir fonksiyondur:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\nBu kadar.\n\n**2 satır**.\n\nVe tüm *path operation function*'larınızla aynı şekle ve yapıya sahiptir.\n\nBunu, \"decorator\" olmadan (yani `@app.get(\"/some-path\")` olmadan) yazılmış bir *path operation function* gibi düşünebilirsiniz.\n\nAyrıca istediğiniz herhangi bir şeyi döndürebilir.\n\nBu örnekte, bu dependency şunları bekler:\n\n* `str` olan, opsiyonel bir query parametresi `q`.\n* `int` olan, opsiyonel bir query parametresi `skip` ve varsayılanı `0`.\n* `int` olan, opsiyonel bir query parametresi `limit` ve varsayılanı `100`.\n\nSonra da bu değerleri içeren bir `dict` döndürür.\n\n/// info | Bilgi\n\nFastAPI, `Annotated` desteğini 0.95.0 sürümünde ekledi (ve önermeye başladı).\n\nDaha eski bir sürüm kullanıyorsanız `Annotated` kullanmaya çalıştığınızda hata alırsınız.\n\n`Annotated` kullanmadan önce **FastAPI** sürümünü en az 0.95.1'e yükseltmek için [FastAPI sürümünü yükseltin](../../deployment/versions.md#upgrading-the-fastapi-versions).\n\n///\n\n### `Depends`'i Import Edin { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### \"Dependant\" İçinde Dependency'yi Tanımlayın { #declare-the-dependency-in-the-dependant }\n\n*Path operation function* parametrelerinizde `Body`, `Query` vb. kullandığınız gibi, yeni bir parametreyle `Depends` kullanın:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\nFonksiyon parametrelerinde `Depends`'i `Body`, `Query` vb. ile aynı şekilde kullansanız da `Depends` biraz farklı çalışır.\n\n`Depends`'e yalnızca tek bir parametre verirsiniz.\n\nBu parametre, bir fonksiyon gibi bir şey olmalıdır.\n\nOnu doğrudan **çağırmazsınız** (sonuna parantez eklemezsiniz), sadece `Depends()`'e parametre olarak verirsiniz.\n\nVe bu fonksiyon da, *path operation function*'lar gibi parametre alır.\n\n/// tip | İpucu\n\nFonksiyonların dışında başka hangi \"şeylerin\" dependency olarak kullanılabildiğini bir sonraki bölümde göreceksiniz.\n\n///\n\nYeni bir request geldiğinde, **FastAPI** şunları sizin yerinize yapar:\n\n* Dependency (\"dependable\") fonksiyonunuzu doğru parametrelerle çağırır.\n* Fonksiyonunuzun sonucunu alır.\n* Bu sonucu *path operation function*'ınızdaki parametreye atar.\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\nBu şekilde paylaşılan kodu bir kez yazarsınız ve onu *path operation*'larda çağırma işini **FastAPI** halleder.\n\n/// check | Ek bilgi\n\nDikkat edin: Bunu \"register\" etmek ya da benzeri bir şey yapmak için özel bir class oluşturup **FastAPI**'ye bir yere geçirmeniz gerekmez.\n\nSadece `Depends`'e verirsiniz ve gerisini **FastAPI** nasıl yapacağını bilir.\n\n///\n\n## `Annotated` Dependency'lerini Paylaşın { #share-annotated-dependencies }\n\nYukarıdaki örneklerde, ufak bir **kod tekrarı** olduğunu görüyorsunuz.\n\n`common_parameters()` dependency'sini kullanmanız gerektiğinde, type annotation ve `Depends()` içeren parametrenin tamamını yazmanız gerekir:\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\nAncak `Annotated` kullandığımız için bu `Annotated` değerini bir değişkende saklayıp birden fazla yerde kullanabiliriz:\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | İpucu\n\nBu aslında standart Python'dır; buna \"type alias\" denir ve **FastAPI**'ye özel bir şey değildir.\n\nAma **FastAPI**, `Annotated` dahil Python standartları üzerine kurulu olduğu için bu tekniği kodunuzda kullanabilirsiniz. 😎\n\n///\n\nDependency'ler beklediğiniz gibi çalışmaya devam eder ve **en güzel kısmı** da şudur: **type bilgisi korunur**. Bu da editörünüzün size **autocompletion**, **inline errors** vb. sağlamaya devam edeceği anlamına gelir. `mypy` gibi diğer araçlar için de aynısı geçerlidir.\n\nBu özellikle, **büyük bir kod tabanında**, aynı dependency'leri **birçok *path operation*** içinde tekrar tekrar kullandığınızda çok faydalı olacaktır.\n\n## `async` Olsa da Olmasa da { #to-async-or-not-to-async }\n\nDependency'ler de **FastAPI** tarafından çağrılacağı için (tıpkı *path operation function*'larınız gibi), fonksiyonları tanımlarken aynı kurallar geçerlidir.\n\n`async def` ya da normal `def` kullanabilirsiniz.\n\nAyrıca normal `def` *path operation function*'ları içinde `async def` dependency tanımlayabilir veya `async def` *path operation function*'ları içinde `def` dependency kullanabilirsiniz vb.\n\nFark etmez. **FastAPI** ne yapacağını bilir.\n\n/// note | Not\n\nEğer bilmiyorsanız, dokümanlarda `async` ve `await` için [Async: *\"In a hurry?\"*](../../async.md#in-a-hurry) bölümüne bakın.\n\n///\n\n## OpenAPI ile Entegre { #integrated-with-openapi }\n\nDependency'lerinizin (ve alt dependency'lerin) tüm request tanımları, doğrulamaları ve gereksinimleri aynı OpenAPI şemasına entegre edilir.\n\nBu nedenle interaktif dokümanlar, bu dependency'lerden gelen tüm bilgileri de içerir:\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## Basit Kullanım { #simple-usage }\n\nŞöyle düşünürseniz: *Path operation function*'lar, bir *path* ve *operation* eşleştiğinde kullanılacak şekilde tanımlanır; ardından **FastAPI** fonksiyonu doğru parametrelerle çağırır ve request'ten veriyi çıkarır.\n\nAslında tüm (veya çoğu) web framework'ü de aynı şekilde çalışır.\n\nBu fonksiyonları hiçbir zaman doğrudan çağırmazsınız. Onları framework'ünüz (bu örnekte **FastAPI**) çağırır.\n\nDependency Injection sistemiyle, *path operation function*'ınızın, ondan önce çalıştırılması gereken başka bir şeye de \"bağlı\" olduğunu **FastAPI**'ye söyleyebilirsiniz; **FastAPI** bunu çalıştırır ve sonuçları \"inject\" eder.\n\nAynı \"dependency injection\" fikri için kullanılan diğer yaygın terimler:\n\n* resources\n* providers\n* services\n* injectables\n* components\n\n## **FastAPI** Plug-in'leri { #fastapi-plug-ins }\n\nEntegrasyonlar ve \"plug-in\"ler **Dependency Injection** sistemi kullanılarak inşa edilebilir. Ancak aslında **\"plug-in\" oluşturmanıza gerek yoktur**; çünkü dependency'leri kullanarak *path operation function*'larınıza sunulabilecek sınırsız sayıda entegrasyon ve etkileşim tanımlayabilirsiniz.\n\nDependency'ler, çok basit ve sezgisel bir şekilde oluşturulabilir. Böylece ihtiyacınız olan Python package'larını import edip, API fonksiyonlarınızla birkaç satır kodla *kelimenin tam anlamıyla* entegre edebilirsiniz.\n\nİlerleyen bölümlerde ilişkisel ve NoSQL veritabanları, güvenlik vb. konularda bunun örneklerini göreceksiniz.\n\n## **FastAPI** Uyumluluğu { #fastapi-compatibility }\n\nDependency injection sisteminin sadeliği, **FastAPI**'yi şunlarla uyumlu hale getirir:\n\n* tüm ilişkisel veritabanları\n* NoSQL veritabanları\n* harici paketler\n* harici API'ler\n* authentication ve authorization sistemleri\n* API kullanım izleme (monitoring) sistemleri\n* response verisi injection sistemleri\n* vb.\n\n## Basit ve Güçlü { #simple-and-powerful }\n\nHiyerarşik dependency injection sistemi tanımlamak ve kullanmak çok basit olsa da, hâlâ oldukça güçlüdür.\n\nKendileri de dependency tanımlayabilen dependency'ler tanımlayabilirsiniz.\n\nSonuçta hiyerarşik bir dependency ağacı oluşur ve **Dependency Injection** sistemi tüm bu dependency'leri (ve alt dependency'lerini) sizin için çözer ve her adımda sonuçları sağlar (\"inject\" eder).\n\nÖrneğin, 4 API endpoint'iniz (*path operation*) olduğunu varsayalım:\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\nO zaman her biri için farklı izin gereksinimlerini yalnızca dependency'ler ve alt dependency'lerle ekleyebilirsiniz:\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## **OpenAPI** ile Entegre { #integrated-with-openapi_1 }\n\nBu dependency'lerin tümü, gereksinimlerini beyan ederken aynı zamanda *path operation*'larınıza parametreler, doğrulamalar vb. da ekler.\n\n**FastAPI**, bunların hepsini OpenAPI şemasına eklemekle ilgilenir; böylece interaktif dokümantasyon sistemlerinde gösterilir.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# Alt Bağımlılıklar { #sub-dependencies }\n\n**Alt bağımlılıkları** olan bağımlılıklar oluşturabilirsiniz.\n\nİhtiyacınız olduğu kadar **derine** gidebilirler.\n\nBunları çözme işini **FastAPI** üstlenir.\n\n## İlk bağımlılık \"dependable\" { #first-dependency-dependable }\n\nŞöyle bir ilk bağımlılık (\"dependable\") oluşturabilirsiniz:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\nBurada `q` adında opsiyonel bir query parametresi `str` olarak tanımlanır ve sonra doğrudan geri döndürülür.\n\nBu oldukça basit (pek faydalı değil), ama alt bağımlılıkların nasıl çalıştığına odaklanmamıza yardımcı olacak.\n\n## İkinci bağımlılık: \"dependable\" ve \"dependant\" { #second-dependency-dependable-and-dependant }\n\nArdından, aynı zamanda kendi içinde bir bağımlılık da tanımlayan başka bir bağımlılık fonksiyonu (bir \"dependable\") oluşturabilirsiniz (yani o da bir \"dependant\" olur):\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\nTanımlanan parametrelere odaklanalım:\n\n* Bu fonksiyonun kendisi bir bağımlılık (\"dependable\") olmasına rağmen, ayrıca başka bir bağımlılık daha tanımlar (başka bir şeye \"depends\" olur).\n    * `query_extractor`'a bağlıdır ve ondan dönen değeri `q` parametresine atar.\n* Ayrıca `last_query` adında opsiyonel bir cookie'yi `str` olarak tanımlar.\n    * Kullanıcı herhangi bir query `q` sağlamadıysa, daha önce cookie'ye kaydettiğimiz en son kullanılan query'yi kullanırız.\n\n## Bağımlılığı Kullanma { #use-the-dependency }\n\nSonra bu bağımlılığı şöyle kullanabiliriz:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info | Bilgi\n\nDikkat edin, *path operation function* içinde yalnızca tek bir bağımlılık tanımlıyoruz: `query_or_cookie_extractor`.\n\nAncak **FastAPI**, `query_or_cookie_extractor`'ı çağırmadan önce `query_extractor`'ı önce çözmesi gerektiğini bilir ve onun sonucunu `query_or_cookie_extractor`'a aktarır.\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## Aynı Bağımlılığı Birden Fazla Kez Kullanma { #using-the-same-dependency-multiple-times }\n\nBağımlılıklarınızdan biri aynı *path operation* için birden fazla kez tanımlanırsa (örneğin birden fazla bağımlılığın ortak bir alt bağımlılığı varsa), **FastAPI** o alt bağımlılığı request başına yalnızca bir kez çağıracağını bilir.\n\nDönen değeri bir <dfn title=\"Hesaplanan/üretilen değerleri saklayıp, tekrar hesaplamak yerine yeniden kullanmayı sağlayan bir yardımcı araç/sistem.\">\"önbellek\"</dfn> içinde saklar ve aynı request içinde buna ihtiyaç duyan tüm \"dependant\"lara aktarır; böylece aynı request için bağımlılığı tekrar tekrar çağırmaz.\n\nDaha ileri bir senaryoda, \"cached\" değeri kullanmak yerine aynı request içinde her adımda (muhtemelen birden fazla kez) bağımlılığın çağrılması gerektiğini biliyorsanız, `Depends` kullanırken `use_cache=False` parametresini ayarlayabilirsiniz:\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ Annotated olmayan\n\n/// tip | İpucu\n\nMümkünse `Annotated` sürümünü tercih edin.\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## Özet { #recap }\n\nBurada kullanılan havalı terimlerin ötesinde, **Dependency Injection** sistemi aslında oldukça basittir.\n\n*Path operation function*'lara benzeyen fonksiyonlardan ibarettir.\n\nYine de çok güçlüdür ve keyfi derecede derin iç içe geçmiş bağımlılık \"graph\"ları (ağaçları) tanımlamanıza izin verir.\n\n/// tip | İpucu\n\nBu basit örneklerle çok faydalı görünmeyebilir.\n\nAncak **security** ile ilgili bölümlerde bunun ne kadar işe yaradığını göreceksiniz.\n\nAyrıca size ne kadar kod kazandırdığını da göreceksiniz.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/tutorial/encoder.md",
    "content": "# JSON Uyumlu Encoder { #json-compatible-encoder }\n\nBazı durumlarda, bir veri tipini (örneğin bir Pydantic model) JSON ile uyumlu bir şeye (örneğin `dict`, `list` vb.) dönüştürmeniz gerekebilir.\n\nÖrneğin, bunu bir veritabanında saklamanız gerekiyorsa.\n\nBunun için **FastAPI**, `jsonable_encoder()` fonksiyonunu sağlar.\n\n## `jsonable_encoder` Kullanımı { #using-the-jsonable-encoder }\n\nYalnızca JSON ile uyumlu veri kabul eden bir veritabanınız olduğunu düşünelim: `fake_db`.\n\nÖrneğin bu veritabanı, JSON ile uyumlu olmadıkları için `datetime` objelerini kabul etmez.\n\nDolayısıyla bir `datetime` objesinin, [ISO formatında](https://en.wikipedia.org/wiki/ISO_8601) veriyi içeren bir `str`'e dönüştürülmesi gerekir.\n\nAynı şekilde bu veritabanı bir Pydantic model'i (attribute'lara sahip bir obje) de kabul etmez; yalnızca bir `dict` kabul eder.\n\nBunun için `jsonable_encoder` kullanabilirsiniz.\n\nBir Pydantic model gibi bir obje alır ve JSON ile uyumlu bir versiyonunu döndürür:\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\nBu örnekte, Pydantic model'i bir `dict`'e, `datetime`'ı da bir `str`'e dönüştürür.\n\nBu fonksiyonun çağrılmasıyla elde edilen sonuç, Python standardındaki [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps) ile encode edilebilecek bir şeydir.\n\nJSON formatında (string olarak) veriyi içeren büyük bir `str` döndürmez. Bunun yerine, tüm değerleri ve alt değerleri JSON ile uyumlu olacak şekilde, Python’un standart bir veri yapısını (örneğin bir `dict`) döndürür.\n\n/// note | Not\n\n`jsonable_encoder`, aslında **FastAPI** tarafından veriyi dönüştürmek için internal olarak kullanılır. Ancak birçok farklı senaryoda da oldukça faydalıdır.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/tutorial/extra-data-types.md",
    "content": "# Ek Veri Tipleri { #extra-data-types }\n\nŞimdiye kadar şunlar gibi yaygın veri tiplerini kullanıyordunuz:\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\nAncak daha karmaşık veri tiplerini de kullanabilirsiniz.\n\nVe yine, şimdiye kadar gördüğünüz özelliklerin aynısına sahip olursunuz:\n\n* Harika editör desteği.\n* Gelen request'lerden veri dönüştürme.\n* response verileri için veri dönüştürme.\n* Veri doğrulama.\n* Otomatik annotation ve dokümantasyon.\n\n## Diğer veri tipleri { #other-data-types }\n\nKullanabileceğiniz ek veri tiplerinden bazıları şunlardır:\n\n* `UUID`:\n    * Birçok veritabanı ve sistemde ID olarak yaygın kullanılan, standart bir \"Universally Unique Identifier\".\n    * request'lerde ve response'larda `str` olarak temsil edilir.\n* `datetime.datetime`:\n    * Python `datetime.datetime`.\n    * request'lerde ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15T15:53:00+05:00`.\n* `datetime.date`:\n    * Python `datetime.date`.\n    * request'lerde ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `2008-09-15`.\n* `datetime.time`:\n    * Python `datetime.time`.\n    * request'lerde ve response'larda ISO 8601 formatında bir `str` olarak temsil edilir, örn: `14:23:55.003`.\n* `datetime.timedelta`:\n    * Python `datetime.timedelta`.\n    * request'lerde ve response'larda toplam saniye sayısını ifade eden bir `float` olarak temsil edilir.\n    * Pydantic, bunu ayrıca bir \"ISO 8601 time diff encoding\" olarak temsil etmeye de izin verir, [daha fazla bilgi için dokümanlara bakın](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).\n* `frozenset`:\n    * request'lerde ve response'larda, `set` ile aynı şekilde ele alınır:\n        * request'lerde bir list okunur, tekrarlar kaldırılır ve `set`'e dönüştürülür.\n        * response'larda `set`, `list`'e dönüştürülür.\n        * Üretilen schema, `set` değerlerinin benzersiz olduğunu belirtir (JSON Schema'nın `uniqueItems` özelliğini kullanarak).\n* `bytes`:\n    * Standart Python `bytes`.\n    * request'lerde ve response'larda `str` gibi ele alınır.\n    * Üretilen schema, bunun `binary` \"format\"ına sahip bir `str` olduğunu belirtir.\n* `Decimal`:\n    * Standart Python `Decimal`.\n    * request'lerde ve response'larda `float` ile aynı şekilde işlenir.\n* Geçerli tüm Pydantic veri tiplerini burada görebilirsiniz: [Pydantic veri tipleri](https://docs.pydantic.dev/latest/usage/types/types/).\n\n## Örnek { #example }\n\nYukarıdaki tiplerden bazılarını kullanan parametrelere sahip bir örnek *path operation* şöyle:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\nFonksiyonun içindeki parametrelerin doğal veri tiplerinde olduğunu unutmayın; örneğin normal tarih işlemleri yapabilirsiniz:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/tr/docs/tutorial/extra-models.md",
    "content": "# Ek Modeller { #extra-models }\n\nÖnceki örnekten devam edersek, birbiriyle ilişkili birden fazla modelin olması oldukça yaygındır.\n\nBu durum özellikle kullanıcı modellerinde sık görülür, çünkü:\n\n* **input modeli** bir `password` içerebilmelidir.\n* **output modeli** `password` içermemelidir.\n* **database modeli** büyük ihtimalle hash'lenmiş bir `password` tutmalıdır.\n\n/// danger | Tehlike\n\nKullanıcının düz metin (plaintext) `password`'ünü asla saklamayın. Her zaman sonradan doğrulayabileceğiniz \"güvenli bir hash\" saklayın.\n\nEğer bilmiyorsanız, \"password hash\" nedir konusunu [güvenlik bölümlerinde](security/simple-oauth2.md#password-hashing) öğreneceksiniz.\n\n///\n\n## Birden Çok Model { #multiple-models }\n\n`password` alanlarıyla birlikte modellerin genel olarak nasıl görünebileceğine ve nerelerde kullanılacaklarına dair bir fikir:\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### `**user_in.model_dump()` Hakkında { #about-user-in-model-dump }\n\n#### Pydantic'in `.model_dump()` Metodu { #pydantics-model-dump }\n\n`user_in`, `UserIn` sınıfına ait bir Pydantic modelidir.\n\nPydantic modellerinde, model verilerini içeren bir `dict` döndüren `.model_dump()` metodu bulunur.\n\nYani, şöyle bir Pydantic nesnesi `user_in` oluşturursak:\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\nve sonra şunu çağırırsak:\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\nartık `user_dict` değişkeninde modelin verilerini içeren bir `dict` vardır (Pydantic model nesnesi yerine bir `dict` elde etmiş oluruz).\n\nVe eğer şunu çağırırsak:\n\n```Python\nprint(user_dict)\n```\n\nşöyle bir Python `dict` elde ederiz:\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### Bir `dict`'i Unpack Etmek { #unpacking-a-dict }\n\n`user_dict` gibi bir `dict` alıp bunu bir fonksiyona (ya da sınıfa) `**user_dict` ile gönderirsek, Python bunu \"unpack\" eder. Yani `user_dict` içindeki key ve value'ları doğrudan key-value argümanları olarak geçirir.\n\nDolayısıyla, yukarıdaki `user_dict` ile devam edersek, şunu yazmak:\n\n```Python\nUserInDB(**user_dict)\n```\n\nşuna eşdeğer bir sonuç üretir:\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\nYa da daha net şekilde, `user_dict`'i doğrudan kullanarak, gelecekte içeriği ne olursa olsun:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### Bir Pydantic Modelinden Diğerinin İçeriğiyle Pydantic Model Oluşturmak { #a-pydantic-model-from-the-contents-of-another }\n\nYukarıdaki örnekte `user_dict`'i `user_in.model_dump()` ile elde ettiğimiz için, şu kod:\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\nşuna eşdeğerdir:\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n...çünkü `user_in.model_dump()` bir `dict` döndürür ve biz de bunu `UserInDB`'ye `**` önekiyle vererek Python'ın \"unpack\" etmesini sağlarız.\n\nBöylece, bir Pydantic modelindeki verilerden başka bir Pydantic model üretmiş oluruz.\n\n#### Bir `dict`'i Unpack Etmek ve Ek Keyword'ler { #unpacking-a-dict-and-extra-keywords }\n\nSonrasında, aşağıdaki gibi ek keyword argümanı `hashed_password=hashed_password` eklemek:\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n...şuna benzer bir sonuca dönüşür:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning | Uyarı\n\nEk destek fonksiyonları olan `fake_password_hasher` ve `fake_save_user` sadece verinin olası bir akışını göstermek içindir; elbette gerçek bir güvenlik sağlamazlar.\n\n///\n\n## Tekrarı Azaltma { #reduce-duplication }\n\nKod tekrarını azaltmak, **FastAPI**'nin temel fikirlerinden biridir.\n\nKod tekrarı; bug, güvenlik problemi, kodun senkron dışına çıkması (bir yeri güncelleyip diğerlerini güncellememek) gibi sorunların olasılığını artırır.\n\nBu modellerin hepsi verinin büyük bir kısmını paylaşıyor ve attribute adlarını ve type'larını tekrar ediyor.\n\nDaha iyisini yapabiliriz.\n\nDiğer modellerimiz için temel olacak bir `UserBase` modeli tanımlayabiliriz. Sonra da bu modelden türeyen (subclass) modeller oluşturup onun attribute'larını (type deklarasyonları, doğrulama vb.) miras aldırabiliriz.\n\nTüm veri dönüştürme, doğrulama, dokümantasyon vb. her zamanki gibi çalışmaya devam eder.\n\nBu sayede modeller arasındaki farkları (plaintext `password` olan, `hashed_password` olan ve `password` olmayan) sadece o farklılıklar olarak tanımlayabiliriz:\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` veya `anyOf` { #union-or-anyof }\n\nBir response'u iki ya da daha fazla type'ın `Union`'ı olarak tanımlayabilirsiniz; bu, response'un bunlardan herhangi biri olabileceği anlamına gelir.\n\nOpenAPI'de bu `anyOf` ile tanımlanır.\n\nBunu yapmak için standart Python type hint'i olan [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union)'ı kullanın:\n\n/// note | Not\n\nBir [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions) tanımlarken en spesifik type'ı önce, daha az spesifik olanı sonra ekleyin. Aşağıdaki örnekte daha spesifik olan `PlaneItem`, `Union[PlaneItem, CarItem]` içinde `CarItem`'dan önce gelir.\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### Python 3.10'da `Union` { #union-in-python-3-10 }\n\nBu örnekte `Union[PlaneItem, CarItem]` değerini `response_model` argümanına veriyoruz.\n\nBunu bir **type annotation** içine koymak yerine bir **argümana değer** olarak geçtiğimiz için, Python 3.10'da bile `Union` kullanmamız gerekiyor.\n\nEğer bu bir type annotation içinde olsaydı, dikey çizgiyi kullanabilirdik:\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\nAncak bunu `response_model=PlaneItem | CarItem` atamasına koyarsak hata alırız; çünkü Python bunu bir type annotation olarak yorumlamak yerine `PlaneItem` ile `CarItem` arasında **geçersiz bir işlem** yapmaya çalışır.\n\n## Model Listesi { #list-of-models }\n\nAynı şekilde, nesne listesi döndüren response'ları da tanımlayabilirsiniz.\n\nBunun için standart Python `list`'i kullanın:\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## Rastgele `dict` ile Response { #response-with-arbitrary-dict }\n\nBir Pydantic modeli kullanmadan, sadece key ve value type'larını belirterek düz, rastgele bir `dict` ile de response tanımlayabilirsiniz.\n\nBu, geçerli field/attribute adlarını (Pydantic modeli için gerekli olurdu) önceden bilmiyorsanız kullanışlıdır.\n\nBu durumda `dict` kullanabilirsiniz:\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## Özet { #recap }\n\nHer duruma göre birden fazla Pydantic modeli kullanın ve gerekirse özgürce inheritance uygulayın.\n\nBir entity'nin farklı \"state\"lere sahip olması gerekiyorsa, o entity için tek bir veri modeli kullanmak zorunda değilsiniz. Örneğin `password` içeren, `password_hash` içeren ve `password` içermeyen state'lere sahip kullanıcı \"entity\"si gibi.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/first-steps.md",
    "content": "# İlk Adımlar { #first-steps }\n\nEn sade FastAPI dosyası şu şekilde görünür:\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\nYukarıdakini `main.py` adlı bir dosyaya kopyalayın.\n\nCanlı sunucuyu çalıştırın:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nÇıktıda, şuna benzer bir satır göreceksiniz:\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\nBu satır, uygulamanızın yerel makinenizde hangi URL'de sunulduğunu gösterir.\n\n### Kontrol Edelim { #check-it }\n\nTarayıcınızı açıp [http://127.0.0.1:8000](http://127.0.0.1:8000) adresine gidin.\n\nŞu şekilde bir JSON response göreceksiniz:\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### Etkileşimli API Dokümantasyonu { #interactive-api-docs }\n\nŞimdi [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) adresine gidin.\n\nOtomatik etkileşimli API dokümantasyonunu ([Swagger UI](https://github.com/swagger-api/swagger-ui) tarafından sağlanan) göreceksiniz:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Alternatif API Dokümantasyonu { #alternative-api-docs }\n\nVe şimdi [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) adresine gidin.\n\nAlternatif otomatik dokümantasyonu ([ReDoc](https://github.com/Rebilly/ReDoc) tarafından sağlanan) göreceksiniz:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI**, API'ları tanımlamak için **OpenAPI** standardını kullanarak tüm API'nızın tamamını içeren bir \"şema\" üretir.\n\n#### \"Şema\" { #schema }\n\n\"Şema\", bir şeyin tanımı veya açıklamasıdır. Onu uygulayan kod değil, sadece soyut bir açıklamadır.\n\n#### API \"şeması\" { #api-schema }\n\nBu durumda, [OpenAPI](https://github.com/OAI/OpenAPI-Specification), API'nızın şemasını nasıl tanımlayacağınızı belirleyen bir şartnamedir.\n\nBu şema tanımı, API path'leriniz, alabilecekleri olası parametreler vb. şeyleri içerir.\n\n#### Veri \"şeması\" { #data-schema }\n\n\"Şema\" terimi, JSON içeriği gibi bazı verilerin şeklini de ifade edebilir.\n\nBu durumda, JSON attribute'ları ve sahip oldukları veri türleri vb. anlamına gelir.\n\n#### OpenAPI ve JSON Schema { #openapi-and-json-schema }\n\nOpenAPI, API'nız için bir API şeması tanımlar. Ve bu şema, JSON veri şemaları standardı olan **JSON Schema** kullanılarak API'nız tarafından gönderilen ve alınan verilerin tanımlarını (veya \"şemalarını\") içerir.\n\n#### `openapi.json` Dosyasına Göz At { #check-the-openapi-json }\n\nHam OpenAPI şemasının nasıl göründüğünü merak ediyorsanız, FastAPI otomatik olarak tüm API'nızın açıklamalarını içeren bir JSON (şema) üretir.\n\nBunu doğrudan şuradan görebilirsiniz: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).\n\nŞuna benzer bir şekilde başlayan bir JSON gösterecektir:\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### OpenAPI Ne İşe Yarar? { #what-is-openapi-for }\n\nOpenAPI şeması, dahil edilen iki etkileşimli dokümantasyon sistemine güç veren şeydir.\n\nVe OpenAPI tabanlı düzinelerce alternatif vardır. **FastAPI** ile oluşturulmuş uygulamanıza bu alternatiflerden herhangi birini kolayca ekleyebilirsiniz.\n\nAyrıca, API'nızla iletişim kuran istemciler için otomatik olarak kod üretmekte de kullanabilirsiniz. Örneğin frontend, mobil veya IoT uygulamaları.\n\n### `pyproject.toml` içinde uygulama `entrypoint`'ını yapılandırın { #configure-the-app-entrypoint-in-pyproject-toml }\n\nUygulamanızın nerede bulunduğunu `pyproject.toml` dosyasında şöyle yapılandırabilirsiniz:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nBu `entrypoint`, `fastapi` komutuna uygulamayı şu şekilde import etmesi gerektiğini söyler:\n\n```python\nfrom main import app\n```\n\nKodunuz şöyle yapılandırılmışsa:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nO zaman `entrypoint`'i şöyle ayarlardınız:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nBu da şuna eşdeğer olur:\n\n```python\nfrom backend.main import app\n```\n\n### Path ile `fastapi dev` { #fastapi-dev-with-path }\n\nDosya path'ini `fastapi dev` komutuna da verebilirsiniz; hangi FastAPI app objesini kullanacağını tahmin eder:\n\n```console\n$ fastapi dev main.py\n```\n\nAncak `fastapi` komutunu her çağırdığınızda doğru path'i geçmeyi hatırlamanız gerekir.\n\nAyrıca, [VS Code Eklentisi](../editor-support.md) veya [FastAPI Cloud](https://fastapicloud.com) gibi başka araçlar da onu bulamayabilir; bu yüzden `pyproject.toml` içindeki `entrypoint`'i kullanmanız önerilir.\n\n### Uygulamanızı Yayınlayın (opsiyonel) { #deploy-your-app-optional }\n\nİsterseniz FastAPI uygulamanızı [FastAPI Cloud](https://fastapicloud.com)'a deploy edebilirsiniz; henüz katılmadıysanız gidip bekleme listesine yazılın. 🚀\n\nZaten bir **FastAPI Cloud** hesabınız varsa (bekleme listesinden sizi davet ettiysek 😉), uygulamanızı tek komutla deploy edebilirsiniz.\n\nDeploy etmeden önce giriş yaptığınızdan emin olun:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\nArdından uygulamanızı deploy edin:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nBu kadar! Artık uygulamanıza o URL üzerinden erişebilirsiniz. ✨\n\n## Adım Adım Özetleyelim { #recap-step-by-step }\n\n### Adım 1: `FastAPI` import edin { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI`, API'nız için tüm işlevselliği sağlayan bir Python class'ıdır.\n\n/// note | Teknik Detaylar\n\n`FastAPI`, doğrudan `Starlette`'ten miras alan bir class'tır.\n\n[Starlette](https://www.starlette.dev/)'in tüm işlevselliğini `FastAPI` ile de kullanabilirsiniz.\n\n///\n\n### Adım 2: bir `FastAPI` \"instance\"ı oluşturun { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\nBurada `app` değişkeni `FastAPI` class'ının bir \"instance\"ı olacaktır.\n\nBu, tüm API'nızı oluşturmak için ana etkileşim noktası olacaktır.\n\n### Adım 3: bir *path operation* oluşturun { #step-3-create-a-path-operation }\n\n#### Path { #path }\n\nBuradaki \"Path\", URL'in ilk `/` işaretinden başlayarak son kısmını ifade eder.\n\nYani, şu şekilde bir URL'de:\n\n```\nhttps://example.com/items/foo\n```\n\n...path şöyle olur:\n\n```\n/items/foo\n```\n\n/// info | Bilgi\n\nBir \"path\" genellikle \"endpoint\" veya \"route\" olarak da adlandırılır.\n\n///\n\nBir API oluştururken, \"path\", \"concerns\" ve \"resources\" ayrımını yapmanın ana yoludur.\n\n#### Operation { #operation }\n\nBurada \"Operation\", HTTP \"method\"larından birini ifade eder.\n\nŞunlardan biri:\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n...ve daha egzotik olanlar:\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\nHTTP protokolünde, her bir path ile bu \"method\"lardan biri (veya birden fazlası) ile iletişim kurabilirsiniz.\n\n---\n\nAPI oluştururken, normalde belirli bir aksiyon için bu spesifik HTTP method'larını kullanırsınız.\n\nNormalde şunları kullanırsınız:\n\n* `POST`: veri oluşturmak için.\n* `GET`: veri okumak için.\n* `PUT`: veriyi güncellemek için.\n* `DELETE`: veriyi silmek için.\n\nBu nedenle, OpenAPI'da HTTP method'larının her birine \"operation\" denir.\n\nBiz de bunlara \"**operation**\" diyeceğiz.\n\n#### Bir *path operation decorator* tanımlayın { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\n`@app.get(\"/\")`, **FastAPI**'a hemen altındaki fonksiyonun şuraya giden request'leri ele almakla sorumlu olduğunu söyler:\n\n* path `/`\n* <dfn title=\"bir HTTP GET methodu\"><code>get</code> operation</dfn> kullanarak\n\n/// info | `@decorator` Bilgisi\n\nPython'daki `@something` söz dizimi \"decorator\" olarak adlandırılır.\n\nOnu bir fonksiyonun üstüne koyarsınız. Güzel, dekoratif bir şapka gibi (sanırım terim de buradan geliyor).\n\nBir \"decorator\", altındaki fonksiyonu alır ve onunla bir şey yapar.\n\nBizim durumumuzda bu decorator, **FastAPI**'a altındaki fonksiyonun **path** `/` ile **operation** `get`'e karşılık geldiğini söyler.\n\nBu, \"**path operation decorator**\"dır.\n\n///\n\nDiğer operation'ları da kullanabilirsiniz:\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\nVe daha egzotik olanları:\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip | İpucu\n\nHer bir operation'ı (HTTP method'unu) istediğiniz gibi kullanmakta özgürsünüz.\n\n**FastAPI** herhangi bir özel anlamı zorunlu kılmaz.\n\nBuradaki bilgiler bir gereklilik değil, bir kılavuz olarak sunulmaktadır.\n\nÖrneğin GraphQL kullanırken, normalde tüm aksiyonları yalnızca `POST` operation'ları kullanarak gerçekleştirirsiniz.\n\n///\n\n### Adım 4: **path operation function**'ı tanımlayın { #step-4-define-the-path-operation-function }\n\nBu bizim \"**path operation function**\"ımız:\n\n* **path**: `/`.\n* **operation**: `get`.\n* **function**: \"decorator\"ün altındaki fonksiyondur (`@app.get(\"/\")`'in altındaki).\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\nBu bir Python fonksiyonudur.\n\n**FastAPI**, \"`/`\" URL'ine `GET` operation kullanarak bir request aldığında bu fonksiyonu çağıracaktır.\n\nBu durumda, bu bir `async` fonksiyondur.\n\n---\n\nBunu `async def` yerine normal bir fonksiyon olarak da tanımlayabilirsiniz:\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note | Not\n\nEğer farkı bilmiyorsanız, [Async: *\"Aceleniz mi var?\"*](../async.md#in-a-hurry) sayfasına bakın.\n\n///\n\n### Adım 5: içeriği döndürün { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\nBir `dict`, `list`, `str`, `int` vb. tekil değerler döndürebilirsiniz.\n\nAyrıca Pydantic modelleri de döndürebilirsiniz (bununla ilgili daha fazlasını ileride göreceksiniz).\n\nOtomatik olarak JSON'a dönüştürülecek (ORM'ler vb. dahil) başka birçok nesne ve model vardır. En sevdiğiniz nesne/model'leri kullanmayı deneyin; büyük ihtimalle zaten destekleniyordur.\n\n### Adım 6: Deploy edin { #step-6-deploy-it }\n\nUygulamanızı tek komutla **[FastAPI Cloud](https://fastapicloud.com)**'a deploy edin: `fastapi deploy`. 🎉\n\n#### FastAPI Cloud Hakkında { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)**, **FastAPI**'ın arkasındaki aynı yazar ve ekip tarafından geliştirilmiştir.\n\nMinimum eforla bir API'ı **oluşturma**, **deploy etme** ve **erişme** sürecini sadeleştirir.\n\nFastAPI ile uygulama geliştirirken yaşadığınız aynı **developer experience**'ı, onları buluta **deploy etme** aşamasına da taşır. 🎉\n\nFastAPI Cloud, *FastAPI and friends* açık kaynak projelerinin birincil sponsoru ve finansman sağlayıcısıdır. ✨\n\n#### Diğer cloud sağlayıcılarına deploy edin { #deploy-to-other-cloud-providers }\n\nFastAPI açık kaynaklıdır ve standartlara dayanır. FastAPI uygulamalarını seçtiğiniz herhangi bir cloud sağlayıcısına deploy edebilirsiniz.\n\nFastAPI uygulamalarını onlarla deploy etmek için cloud sağlayıcınızın kılavuzlarını takip edin. 🤓\n\n## Özet { #recap }\n\n* `FastAPI` import edin.\n* Bir `app` instance'ı oluşturun.\n* `@app.get(\"/\")` gibi decorator'ları kullanarak bir **path operation decorator** yazın.\n* Bir **path operation function** tanımlayın; örneğin `def root(): ...`.\n* `fastapi dev` komutunu kullanarak geliştirme sunucusunu çalıştırın.\n* İsterseniz `fastapi deploy` ile uygulamanızı deploy edin.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/handling-errors.md",
    "content": "# Hataları Yönetme { #handling-errors }\n\nAPI’nizi kullanan bir client’a hata bildirmek zorunda olduğunuz pek çok durum vardır.\n\nBu client; frontend’i olan bir tarayıcı, başka birinin yazdığı bir kod, bir IoT cihazı vb. olabilir.\n\nClient’a şunları söylemeniz gerekebilir:\n\n* Client’ın bu işlem için yeterli yetkisi yok.\n* Client’ın bu kaynağa erişimi yok.\n* Client’ın erişmeye çalıştığı öğe mevcut değil.\n* vb.\n\nBu durumlarda genellikle **400** aralığında (**400** ile **499** arası) bir **HTTP status code** döndürürsünüz.\n\nBu, 200 HTTP status code’larına (200 ile 299 arası) benzer. Bu \"200\" status code’ları, request’in bir şekilde \"başarılı\" olduğunu ifade eder.\n\n400 aralığındaki status code’lar ise hatanın client tarafından kaynaklandığını gösterir.\n\nŞu meşhur **\"404 Not Found\"** hatalarını (ve şakalarını) hatırlıyor musunuz?\n\n## `HTTPException` Kullanma { #use-httpexception }\n\nClient’a hata içeren HTTP response’ları döndürmek için `HTTPException` kullanırsınız.\n\n### `HTTPException`’ı Import Etme { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### Kodunuzda Bir `HTTPException` Raise Etme { #raise-an-httpexception-in-your-code }\n\n`HTTPException`, API’lerle ilgili ek veriler içeren normal bir Python exception’ıdır.\n\nPython exception’ı olduğu için `return` etmezsiniz, `raise` edersiniz.\n\nBu aynı zamanda şunu da ifade eder: *path operation function*’ınızın içinde çağırdığınız bir yardımcı (utility) fonksiyonun içindeyken `HTTPException` raise ederseniz, *path operation function* içindeki kodun geri kalanı çalışmaz; request’i hemen sonlandırır ve `HTTPException` içindeki HTTP hatasını client’a gönderir.\n\nBir değer döndürmek yerine exception raise etmenin faydası, Dependencies ve Security bölümünde daha da netleşecektir.\n\nBu örnekte, client var olmayan bir ID ile bir item istediğinde, `404` status code’u ile bir exception raise edelim:\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### Ortaya Çıkan Response { #the-resulting-response }\n\nClient `http://example.com/items/foo` (bir `item_id` `\"foo\"`) isterse, HTTP status code olarak 200 ve şu JSON response’u alır:\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\nAncak client `http://example.com/items/bar` (mevcut olmayan bir `item_id` `\"bar\"`) isterse, HTTP status code olarak 404 (\"not found\" hatası) ve şu JSON response’u alır:\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip | İpucu\n\nBir `HTTPException` raise ederken, `detail` parametresine sadece `str` değil, JSON’a dönüştürülebilen herhangi bir değer geçebilirsiniz.\n\nÖrneğin `dict`, `list` vb. geçebilirsiniz.\n\nBunlar **FastAPI** tarafından otomatik olarak işlenir ve JSON’a dönüştürülür.\n\n///\n\n## Özel Header’lar Eklemek { #add-custom-headers }\n\nBazı durumlarda HTTP hata response’una özel header’lar eklemek faydalıdır. Örneğin bazı güvenlik türlerinde.\n\nMuhtemelen bunu doğrudan kendi kodunuzda kullanmanız gerekmeyecek.\n\nAma ileri seviye bir senaryo için ihtiyaç duyarsanız, özel header’lar ekleyebilirsiniz:\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## Özel Exception Handler’ları Kurmak { #install-custom-exception-handlers }\n\n[Starlette’in aynı exception yardımcı araçlarıyla](https://www.starlette.dev/exceptions/) özel exception handler’lar ekleyebilirsiniz.\n\nDiyelim ki sizin (ya da kullandığınız bir kütüphanenin) `raise` edebileceği `UnicornException` adında özel bir exception’ınız var.\n\nVe bu exception’ı FastAPI ile global olarak handle etmek istiyorsunuz.\n\n`@app.exception_handler()` ile özel bir exception handler ekleyebilirsiniz:\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\nBurada `/unicorns/yolo` için request atarsanız, *path operation* bir `UnicornException` `raise` eder.\n\nNamun bu, `unicorn_exception_handler` tarafından handle edilir.\n\nBöylece HTTP status code’u `418` olan, JSON içeriği şu şekilde temiz bir hata response’u alırsınız:\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | Teknik Detaylar\n\n`from starlette.requests import Request` ve `from starlette.responses import JSONResponse` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içeriğini `fastapi.responses` olarak da sunar. Ancak mevcut response’ların çoğu doğrudan Starlette’ten gelir. `Request` için de aynısı geçerlidir.\n\n///\n\n## Varsayılan Exception Handler’ları Override Etmek { #override-the-default-exception-handlers }\n\n**FastAPI** bazı varsayılan exception handler’lara sahiptir.\n\nBu handler’lar, `HTTPException` `raise` ettiğinizde ve request geçersiz veri içerdiğinde varsayılan JSON response’ları döndürmekten sorumludur.\n\nBu exception handler’ları kendi handler’larınızla override edebilirsiniz.\n\n### Request Validation Exception’larını Override Etmek { #override-request-validation-exceptions }\n\nBir request geçersiz veri içerdiğinde, **FastAPI** içeride `RequestValidationError` raise eder.\n\nVe bunun için varsayılan bir exception handler da içerir.\n\nOverride etmek için `RequestValidationError`’ı import edin ve exception handler’ı `@app.exception_handler(RequestValidationError)` ile decorate edin.\n\nException handler, bir `Request` ve exception’ı alır.\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\nArtık `/items/foo`’ya giderseniz, şu varsayılan JSON hatası yerine:\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\nşu şekilde bir metin (text) versiyonu alırsınız:\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### `HTTPException` Hata Handler’ını Override Etmek { #override-the-httpexception-error-handler }\n\nBenzer şekilde `HTTPException` handler’ını da override edebilirsiniz.\n\nÖrneğin bu hatalar için JSON yerine plain text response döndürmek isteyebilirsiniz:\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | Teknik Detaylar\n\n`from starlette.responses import PlainTextResponse` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.responses` içeriğini `fastapi.responses` olarak da sunar. Ancak mevcut response’ların çoğu doğrudan Starlette’ten gelir.\n\n///\n\n/// warning | Uyarı\n\n`RequestValidationError`, validation hatasının gerçekleştiği dosya adı ve satır bilgilerini içerir; isterseniz bunu log’larınıza ilgili bilgilerle birlikte yazdırabilirsiniz.\n\nAncak bu, eğer sadece string’e çevirip bu bilgiyi doğrudan response olarak döndürürseniz sisteminiz hakkında bir miktar bilgi sızdırabileceğiniz anlamına gelir. Bu yüzden burada kod, her bir hatayı ayrı ayrı çıkarıp gösterir.\n\n///\n\n### `RequestValidationError` Body’sini Kullanmak { #use-the-requestvalidationerror-body }\n\n`RequestValidationError`, geçersiz veriyle aldığı `body`’yi içerir.\n\nUygulamanızı geliştirirken body’yi log’lamak, debug etmek, kullanıcıya döndürmek vb. için bunu kullanabilirsiniz.\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\nŞimdi şu gibi geçersiz bir item göndermeyi deneyin:\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\nAldığınız body’yi de içeren, verinin geçersiz olduğunu söyleyen bir response alırsınız:\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### FastAPI’nin `HTTPException`’ı vs Starlette’in `HTTPException`’ı { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI**’nin kendi `HTTPException`’ı vardır.\n\nVe **FastAPI**’nin `HTTPException` hata sınıfı, Starlette’in `HTTPException` hata sınıfından kalıtım alır (inherit).\n\nTek fark şudur: **FastAPI**’nin `HTTPException`’ı `detail` alanı için JSON’a çevrilebilir herhangi bir veri kabul ederken, Starlette’in `HTTPException`’ı burada sadece string kabul eder.\n\nBu yüzden kodunuzda her zamanki gibi **FastAPI**’nin `HTTPException`’ını raise etmeye devam edebilirsiniz.\n\nAncak bir exception handler register ederken, bunu Starlette’in `HTTPException`’ı için register etmelisiniz.\n\nBöylece Starlette’in internal kodunun herhangi bir bölümü ya da bir Starlette extension/plug-in’i Starlette `HTTPException` raise ederse, handler’ınız bunu yakalayıp (catch) handle edebilir.\n\nBu örnekte, iki `HTTPException`’ı da aynı kodda kullanabilmek için Starlette’in exception’ı `StarletteHTTPException` olarak yeniden adlandırılıyor:\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### **FastAPI**’nin Exception Handler’larını Yeniden Kullanmak { #reuse-fastapis-exception-handlers }\n\nException’ı, **FastAPI**’nin aynı varsayılan exception handler’larıyla birlikte kullanmak isterseniz, varsayılan exception handler’ları `fastapi.exception_handlers` içinden import edip yeniden kullanabilirsiniz:\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\nBu örnekte sadece oldukça açıklayıcı bir mesajla hatayı yazdırıyorsunuz; ama fikir anlaşılıyor. Exception’ı kullanıp ardından varsayılan exception handler’ları olduğu gibi yeniden kullanabilirsiniz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/header-param-models.md",
    "content": "# Header Parametre Modelleri { #header-parameter-models }\n\nBirbiriyle ilişkili **header parametreleri**nden oluşan bir grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz.\n\nBu sayede modeli **birden fazla yerde yeniden kullanabilir**, ayrıca tüm parametreler için doğrulamaları ve metadata bilgilerini tek seferde tanımlayabilirsiniz. 😎\n\n/// note | Not\n\nBu özellik FastAPI `0.115.0` sürümünden beri desteklenmektedir. 🤓\n\n///\n\n## Pydantic Model ile Header Parametreleri { #header-parameters-with-a-pydantic-model }\n\nİhtiyacınız olan **header parametreleri**ni bir **Pydantic model** içinde tanımlayın, ardından parametreyi `Header` olarak belirtin:\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\n**FastAPI**, request içindeki **headers** bölümünden **her alan** için veriyi **çıkarır** ve size tanımladığınız Pydantic model örneğini verir.\n\n## Dokümanları Kontrol Edin { #check-the-docs }\n\nGerekli header'ları `/docs` altındaki doküman arayüzünde görebilirsiniz:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## Ek Header'ları Yasaklayın { #forbid-extra-headers }\n\nBazı özel kullanım senaryolarında (muhtemelen çok yaygın değil), kabul etmek istediğiniz header'ları **kısıtlamak** isteyebilirsiniz.\n\nPydantic'in model yapılandırmasını kullanarak `extra` alanları `forbid` edebilirsiniz:\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\nBir client bazı **ek header'lar** göndermeye çalışırsa, **hata** response'u alır.\n\nÖrneğin client, değeri `plumbus` olan bir `tool` header'ı göndermeye çalışırsa, `tool` header parametresine izin verilmediğini söyleyen bir **hata** response'u alır:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## Alt Çizgileri Dönüştürmeyi Kapatın { #disable-convert-underscores }\n\nNormal header parametrelerinde olduğu gibi, parametre adlarında alt çizgi karakterleri olduğunda bunlar **otomatik olarak tireye dönüştürülür**.\n\nÖrneğin kodda `save_data` adlı bir header parametreniz varsa, beklenen HTTP header `save-data` olur ve dokümanlarda da bu şekilde görünür.\n\nHerhangi bir sebeple bu otomatik dönüşümü kapatmanız gerekiyorsa, header parametreleri için kullandığınız Pydantic model'lerde de bunu devre dışı bırakabilirsiniz.\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | Uyarı\n\n`convert_underscores` değerini `False` yapmadan önce, bazı HTTP proxy'lerinin ve server'ların alt çizgi içeren header'ların kullanımına izin vermediğini unutmayın.\n\n///\n\n## Özet { #summary }\n\n**FastAPI**'de **headers** tanımlamak için **Pydantic model** kullanabilirsiniz. 😎\n"
  },
  {
    "path": "docs/tr/docs/tutorial/header-params.md",
    "content": "# Header Parametreleri { #header-parameters }\n\n`Query`, `Path` ve `Cookie` parametrelerini nasıl tanımlıyorsanız, Header parametrelerini de aynı şekilde tanımlayabilirsiniz.\n\n## `Header`'ı Import Edin { #import-header }\n\nÖnce `Header`'ı import edin:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## `Header` Parametrelerini Tanımlayın { #declare-header-parameters }\n\nArdından header parametrelerini, `Path`, `Query` ve `Cookie` ile kullandığınız yapının aynısıyla tanımlayın.\n\nDefault değeri ve ek validation ya da annotation parametrelerinin tamamını belirleyebilirsiniz:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Teknik Detaylar\n\n`Header`, `Path`, `Query` ve `Cookie`'nin \"kardeş\" sınıfıdır. Ayrıca aynı ortak `Param` sınıfından kalıtım alır.\n\nAncak şunu unutmayın: `fastapi`'den `Query`, `Path`, `Header` ve diğerlerini import ettiğinizde, bunlar aslında özel sınıfları döndüren fonksiyonlardır.\n\n///\n\n/// info | Bilgi\n\nHeader'ları tanımlamak için `Header` kullanmanız gerekir; aksi halde parametreler query parametreleri olarak yorumlanır.\n\n///\n\n## Otomatik Dönüştürme { #automatic-conversion }\n\n`Header`, `Path`, `Query` ve `Cookie`'nin sağladıklarına ek olarak küçük bir ekstra işlevsellik sunar.\n\nStandart header'ların çoğu, \"hyphen\" karakteri (diğer adıyla \"minus symbol\" (`-`)) ile ayrılır.\n\nAncak `user-agent` gibi bir değişken adı Python'da geçersizdir.\n\nBu yüzden, default olarak `Header`, header'ları almak ve dokümante etmek için parametre adlarındaki underscore (`_`) karakterlerini hyphen (`-`) ile dönüştürür.\n\nAyrıca HTTP header'ları büyük/küçük harfe duyarlı değildir; dolayısıyla onları standart Python stiliyle (diğer adıyla \"snake_case\") tanımlayabilirsiniz.\n\nYani `User_Agent` gibi bir şey yazıp ilk harfleri büyütmeniz gerekmeden, Python kodunda normalde kullandığınız gibi `user_agent` kullanabilirsiniz.\n\nHerhangi bir nedenle underscore'ların hyphen'lara otomatik dönüştürülmesini kapatmanız gerekirse, `Header`'ın `convert_underscores` parametresini `False` yapın:\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | Uyarı\n\n`convert_underscores`'u `False` yapmadan önce, bazı HTTP proxy'lerinin ve server'ların underscore içeren header'ların kullanımına izin vermediğini unutmayın.\n\n///\n\n## Yinelenen Header'lar { #duplicate-headers }\n\nYinelenen header'lar almak mümkündür. Yani aynı header'ın birden fazla değeri olabilir.\n\nBu tür durumları, type tanımında bir list kullanarak belirtebilirsiniz.\n\nYinelenen header'daki tüm değerleri Python `list` olarak alırsınız.\n\nÖrneğin, birden fazla kez gelebilen `X-Token` header'ını tanımlamak için şöyle yazabilirsiniz:\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\nEğer bu *path operation* ile iki HTTP header göndererek iletişim kurarsanız:\n\n```\nX-Token: foo\nX-Token: bar\n```\n\nresponse şöyle olur:\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## Özet { #recap }\n\nHeader'ları `Header` ile tanımlayın; `Query`, `Path` ve `Cookie` ile kullanılan ortak kalıbı burada da kullanın.\n\nDeğişkenlerinizdeki underscore'lar konusunda endişelenmeyin, **FastAPI** bunları dönüştürmeyi halleder.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/index.md",
    "content": "# Eğitim - Kullanıcı Rehberi { #tutorial-user-guide }\n\nBu eğitim, **FastAPI**'yi özelliklerinin çoğuyla birlikte adım adım nasıl kullanacağınızı gösterir.\n\nHer bölüm bir öncekilerin üzerine kademeli olarak eklenir, ancak konular birbirinden ayrılacak şekilde yapılandırılmıştır; böylece API ihtiyaçlarınıza göre doğrudan belirli bir konuya gidip aradığınızı bulabilirsiniz.\n\nAyrıca, ileride tekrar dönüp tam olarak ihtiyaç duyduğunuz şeyi görebileceğiniz bir referans olarak da tasarlanmıştır.\n\n## Kodu Çalıştırın { #run-the-code }\n\nTüm code block'lar kopyalanıp doğrudan kullanılabilir (zaten test edilmiş Python dosyalarıdır).\n\nÖrneklerden herhangi birini çalıştırmak için, kodu `main.py` adlı bir dosyaya kopyalayın ve `fastapi dev`'i başlatın:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nKodu yazmanız ya da kopyalayıp düzenlemeniz ve yerelinizde çalıştırmanız **şiddetle önerilir**.\n\nEditörünüzde kullanmak FastAPI'nin avantajlarını gerçekten gösterir: ne kadar az kod yazmanız gerektiğini, type check'leri, autocompletion'ı vb. görürsünüz.\n\n---\n\n## FastAPI'yi Kurun { #install-fastapi }\n\nİlk adım FastAPI'yi kurmaktır.\n\nBir [sanal ortam](../virtual-environments.md) oluşturduğunuzdan emin olun, etkinleştirin ve ardından **FastAPI'yi kurun**:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | Not\n\n`pip install \"fastapi[standard]\"` ile kurduğunuzda, bazı varsayılan opsiyonel standard bağımlılıklarla birlikte gelir. Bunlara `fastapi-cloud-cli` da dahildir; bu sayede [FastAPI Cloud](https://fastapicloud.com)'a deploy edebilirsiniz.\n\nBu opsiyonel bağımlılıkları istemiyorsanız bunun yerine `pip install fastapi` kurabilirsiniz.\n\nStandard bağımlılıkları kurmak istiyor ama `fastapi-cloud-cli` olmasın diyorsanız, `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"` ile kurabilirsiniz.\n\n///\n\n/// tip | İpucu\n\nFastAPI'nin [VS Code için resmi bir eklentisi](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (ve Cursor) vardır; path operation gezgini, path operation araması, testlerde CodeLens ile gezinme (testlerden tanıma atlama) ve FastAPI Cloud deploy ve logları gibi pek çok özelliği doğrudan editörünüzden sunar.\n\n///\n\n## İleri Düzey Kullanıcı Rehberi { #advanced-user-guide }\n\nBu **Eğitim - Kullanıcı Rehberi**'ni bitirdikten sonra daha sonra okuyabileceğiniz bir **İleri Düzey Kullanıcı Rehberi** de var.\n\n**İleri Düzey Kullanıcı Rehberi** bunun üzerine inşa eder, aynı kavramları kullanır ve size bazı ek özellikler öğretir.\n\nAncak önce **Eğitim - Kullanıcı Rehberi**'ni (şu anda okuduğunuz bölümü) okumalısınız.\n\nYalnızca **Eğitim - Kullanıcı Rehberi** ile eksiksiz bir uygulama oluşturabilmeniz hedeflenmiştir; ardından ihtiyaçlarınıza göre, **İleri Düzey Kullanıcı Rehberi**'ndeki ek fikirlerden bazılarını kullanarak farklı şekillerde genişletebilirsiniz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/metadata.md",
    "content": "# Metadata ve Doküman URL'leri { #metadata-and-docs-urls }\n\n**FastAPI** uygulamanızda çeşitli metadata yapılandırmalarını özelleştirebilirsiniz.\n\n## API için Metadata { #metadata-for-api }\n\nOpenAPI spesifikasyonunda ve otomatik API doküman arayüzlerinde kullanılan şu alanları ayarlayabilirsiniz:\n\n| Parametre | Tip | Açıklama |\n|------------|------|-------------|\n| `title` | `str` | API'nin başlığı. |\n| `summary` | `str` | API'nin kısa özeti. <small>OpenAPI 3.1.0, FastAPI 0.99.0 sürümünden itibaren mevcut.</small> |\n| `description` | `str` | API'nin kısa açıklaması. Markdown kullanabilir. |\n| `version` | `string` | API'nin sürümü. Bu, OpenAPI'nin değil, kendi uygulamanızın sürümüdür. Örneğin `2.5.0`. |\n| `terms_of_service` | `str` | API'nin Kullanım Koşulları (Terms of Service) için bir URL. Verilirse, URL formatında olmalıdır. |\n| `contact` | `dict` | Yayınlanan API için iletişim bilgileri. Birden fazla alan içerebilir. <details><summary><code>contact</code> alanları</summary><table><thead><tr><th>Parametre</th><th>Tip</th><th>Açıklama</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>İletişim kişisi/kuruluşunu tanımlayan ad.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>İletişim bilgilerine işaret eden URL. URL formatında OLMALIDIR.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>İletişim kişisi/kuruluşunun e-posta adresi. E-posta adresi formatında OLMALIDIR.</td></tr></tbody></table></details> |\n| `license_info` | `dict` | Yayınlanan API için lisans bilgileri. Birden fazla alan içerebilir. <details><summary><code>license_info</code> alanları</summary><table><thead><tr><th>Parametre</th><th>Tip</th><th>Açıklama</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ZORUNLU</strong> (<code>license_info</code> ayarlanmışsa). API için kullanılan lisans adı.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>API için bir [SPDX](https://spdx.org/licenses/) lisans ifadesi. <code>identifier</code> alanı, <code>url</code> alanıyla karşılıklı olarak dışlayıcıdır (ikisi aynı anda kullanılamaz). <small>OpenAPI 3.1.0, FastAPI 0.99.0 sürümünden itibaren mevcut.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>API için kullanılan lisansa ait URL. URL formatında OLMALIDIR.</td></tr></tbody></table></details> |\n\nŞu şekilde ayarlayabilirsiniz:\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | İpucu\n\n`description` alanına Markdown yazabilirsiniz; çıktı tarafında render edilir.\n\n///\n\nBu yapılandırmayla otomatik API dokümanları şöyle görünür:\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## Lisans Tanımlayıcısı { #license-identifier }\n\nOpenAPI 3.1.0 ve FastAPI 0.99.0 sürümünden itibaren, `license_info` içinde `url` yerine bir `identifier` da ayarlayabilirsiniz.\n\nÖrneğin:\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## Tag'ler için Metadata { #metadata-for-tags }\n\n`openapi_tags` parametresiyle, path operation'larınızı gruplamak için kullandığınız farklı tag'ler adına ek metadata da ekleyebilirsiniz.\n\nBu parametre, her tag için bir sözlük (dictionary) içeren bir liste alır.\n\nHer sözlük şunları içerebilir:\n\n* `name` (**zorunlu**): *path operation*'larda ve `APIRouter`'larda `tags` parametresinde kullandığınız tag adıyla aynı olan bir `str`.\n* `description`: tag için kısa bir açıklama içeren `str`. Markdown içerebilir ve doküman arayüzünde gösterilir.\n* `externalDocs`: harici dokümanları tanımlayan bir `dict`:\n    * `description`: harici dokümanlar için kısa açıklama içeren `str`.\n    * `url` (**zorunlu**): harici dokümantasyonun URL'sini içeren `str`.\n\n### Tag'ler için metadata oluşturun { #create-metadata-for-tags }\n\n`users` ve `items` tag'lerini içeren bir örnekle deneyelim.\n\nTag'leriniz için metadata oluşturup `openapi_tags` parametresine geçin:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\nAçıklamaların içinde Markdown kullanabileceğinizi unutmayın; örneğin \"login\" kalın (**login**) ve \"fancy\" italik (_fancy_) olarak gösterilecektir.\n\n/// tip | İpucu\n\nKullandığınız tüm tag'ler için metadata eklemek zorunda değilsiniz.\n\n///\n\n### Tag'lerinizi kullanın { #use-your-tags }\n\n*path operation*'larınızı (ve `APIRouter`'ları) farklı tag'lere atamak için `tags` parametresini kullanın:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info | Bilgi\n\nTag'ler hakkında daha fazlası için: [Path Operation Configuration](path-operation-configuration.md#tags).\n\n///\n\n### Dokümanları kontrol edin { #check-the-docs }\n\nArtık dokümanlara baktığınızda, eklediğiniz tüm metadata gösterilir:\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### Tag sırası { #order-of-tags }\n\nHer tag metadata sözlüğünün listedeki sırası, doküman arayüzünde gösterilecek sırayı da belirler.\n\nÖrneğin alfabetik sıralamada `users`, `items`'tan sonra gelirdi; ancak listedeki ilk sözlük olarak `users` metadata'sını eklediğimiz için, dokümanlarda önce o görünür.\n\n## OpenAPI URL'si { #openapi-url }\n\nVarsayılan olarak OpenAPI şeması `/openapi.json` adresinden sunulur.\n\nAncak bunu `openapi_url` parametresiyle yapılandırabilirsiniz.\n\nÖrneğin `/api/v1/openapi.json` adresinden sunulacak şekilde ayarlamak için:\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\nOpenAPI şemasını tamamen kapatmak isterseniz `openapi_url=None` ayarlayabilirsiniz; bu, onu kullanan dokümantasyon arayüzlerini de devre dışı bırakır.\n\n## Doküman URL'leri { #docs-urls }\n\nDahil gelen iki dokümantasyon arayüzünü yapılandırabilirsiniz:\n\n* **Swagger UI**: `/docs` adresinden sunulur.\n    * URL'sini `docs_url` parametresiyle ayarlayabilirsiniz.\n    * `docs_url=None` ayarlayarak devre dışı bırakabilirsiniz.\n* **ReDoc**: `/redoc` adresinden sunulur.\n    * URL'sini `redoc_url` parametresiyle ayarlayabilirsiniz.\n    * `redoc_url=None` ayarlayarak devre dışı bırakabilirsiniz.\n\nÖrneğin Swagger UI'yi `/documentation` adresinden sunup ReDoc'u kapatmak için:\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/tr/docs/tutorial/middleware.md",
    "content": "# Middleware { #middleware }\n\n**FastAPI** uygulamalarına middleware ekleyebilirsiniz.\n\n\"Middleware\", herhangi bir özel *path operation* tarafından işlenmeden önce her **request** ile çalışan bir fonksiyondur. Ayrıca geri döndürmeden önce her **response** ile de çalışır.\n\n* Uygulamanıza gelen her **request**'i alır.\n* Ardından o **request** üzerinde bir işlem yapabilir veya gerekli herhangi bir kodu çalıştırabilir.\n* Sonra **request**'i uygulamanın geri kalanı tarafından işlenmesi için iletir (bir *path operation* tarafından).\n* Ardından uygulama tarafından üretilen **response**'u alır (bir *path operation* tarafından).\n* Sonra o **response** üzerinde bir işlem yapabilir veya gerekli herhangi bir kodu çalıştırabilir.\n* Son olarak **response**'u döndürür.\n\n/// note | Teknik Detaylar\n\n`yield` ile dependency'leriniz varsa, çıkış (exit) kodu middleware'den *sonra* çalışır.\n\nHerhangi bir background task varsa ([Background Tasks](background-tasks.md) bölümünde ele alınıyor, ileride göreceksiniz), bunlar tüm middleware'ler *tamamlandıktan sonra* çalışır.\n\n///\n\n## Middleware Oluşturma { #create-a-middleware }\n\nBir middleware oluşturmak için bir fonksiyonun üzerine `@app.middleware(\"http\")` decorator'ünü kullanırsınız.\n\nMiddleware fonksiyonu şunları alır:\n\n* `request`.\n* Parametre olarak `request` alacak bir `call_next` fonksiyonu.\n    * Bu fonksiyon `request`'i ilgili *path operation*'a iletir.\n    * Ardından ilgili *path operation* tarafından üretilen `response`'u döndürür.\n* Sonrasında `response`'u döndürmeden önce ayrıca değiştirebilirsiniz.\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip | İpucu\n\nÖzel (proprietary) header'lar [`X-` prefix'i kullanılarak](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) eklenebilir, bunu aklınızda tutun.\n\nAncak tarayıcıdaki bir client'ın görebilmesini istediğiniz özel header'larınız varsa, bunları CORS konfigürasyonlarınıza ([CORS (Cross-Origin Resource Sharing)](cors.md)) eklemeniz gerekir. Bunun için, [Starlette'ın CORS dokümanlarında](https://www.starlette.dev/middleware/#corsmiddleware) belgelenen `expose_headers` parametresini kullanın.\n\n///\n\n/// note | Teknik Detaylar\n\n`from starlette.requests import Request` da kullanabilirdiniz.\n\n**FastAPI** bunu geliştirici olarak size kolaylık olsun diye sunar. Ancak doğrudan Starlette'tan gelir.\n\n///\n\n### `response`'tan Önce ve Sonra { #before-and-after-the-response }\n\nHerhangi bir *path operation* `request`'i almadan önce, `request` ile birlikte çalışacak kod ekleyebilirsiniz.\n\nAyrıca `response` üretildikten sonra, geri döndürmeden önce de kod çalıştırabilirsiniz.\n\nÖrneğin, request'i işleyip response üretmenin kaç saniye sürdüğünü içeren `X-Process-Time` adlı özel bir header ekleyebilirsiniz:\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip | İpucu\n\nBurada [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) yerine `time.time()` kullanıyoruz, çünkü bu kullanım senaryolarında daha hassas olabilir. 🤓\n\n///\n\n## Birden Fazla Middleware Çalıştırma Sırası { #multiple-middleware-execution-order }\n\n`@app.middleware()` decorator'ü veya `app.add_middleware()` metodu ile birden fazla middleware eklediğinizde, eklenen her yeni middleware uygulamayı sarar ve bir stack oluşturur. En son eklenen middleware en *dıştaki* (outermost), ilk eklenen ise en *içteki* (innermost) olur.\n\nRequest tarafında önce en *dıştaki* middleware çalışır.\n\nResponse tarafında ise en son o çalışır.\n\nÖrneğin:\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\nBu, aşağıdaki çalıştırma sırasını oluşturur:\n\n* **Request**: MiddlewareB → MiddlewareA → route\n\n* **Response**: route → MiddlewareA → MiddlewareB\n\nBu stack davranışı, middleware'lerin öngörülebilir ve kontrol edilebilir bir sırayla çalıştırılmasını sağlar.\n\n## Diğer Middleware'ler { #other-middlewares }\n\nDiğer middleware'ler hakkında daha fazlasını daha sonra [Advanced User Guide: Advanced Middleware](../advanced/middleware.md) bölümünde okuyabilirsiniz.\n\nBir sonraki bölümde, middleware ile <abbr title=\"Cross-Origin Resource Sharing - Çapraz Kaynak Paylaşımı\">CORS</abbr>'un nasıl ele alınacağını göreceksiniz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/path-operation-configuration.md",
    "content": "# Path Operation Yapılandırması { #path-operation-configuration }\n\nOnu yapılandırmak için *path operation decorator*’ınıza geçebileceğiniz çeşitli parametreler vardır.\n\n/// warning | Uyarı\n\nBu parametrelerin *path operation function*’ınıza değil, doğrudan *path operation decorator*’ına verildiğine dikkat edin.\n\n///\n\n## Response Status Code { #response-status-code }\n\n*Path operation*’ınızın response’unda kullanılacak (HTTP) `status_code`’u tanımlayabilirsiniz.\n\n`404` gibi `int` kodu doğrudan verebilirsiniz.\n\nAncak her sayısal kodun ne işe yaradığını hatırlamıyorsanız, `status` içindeki kısayol sabitlerini kullanabilirsiniz:\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\nBu status code response’da kullanılacak ve OpenAPI şemasına eklenecektir.\n\n/// note | Teknik Detaylar\n\n`from starlette import status` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak işinizi kolaylaştırmak için `starlette.status`’u `fastapi.status` olarak da sunar. Ancak kaynağı doğrudan Starlette’tir.\n\n///\n\n## Tags { #tags }\n\n*Path operation*’ınıza tag ekleyebilirsiniz; `tags` parametresine `str` öğelerinden oluşan bir `list` verin (genellikle tek bir `str`):\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\nBunlar OpenAPI şemasına eklenecek ve otomatik dokümantasyon arayüzleri tarafından kullanılacaktır:\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### Enum ile Tags { #tags-with-enums }\n\nBüyük bir uygulamanız varsa, zamanla **birden fazla tag** birikebilir ve ilişkili *path operation*’lar için her zaman **aynı tag**’i kullandığınızdan emin olmak isteyebilirsiniz.\n\nBu durumlarda tag’leri bir `Enum` içinde tutmak mantıklı olabilir.\n\n**FastAPI** bunu düz string’lerde olduğu gibi aynı şekilde destekler:\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## Özet ve açıklama { #summary-and-description }\n\nBir `summary` ve `description` ekleyebilirsiniz:\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## Docstring’den Açıklama { #description-from-docstring }\n\nAçıklamalar genelde uzun olur ve birden fazla satıra yayılır; bu yüzden *path operation* açıklamasını, fonksiyonun içinde <dfn title=\"dokümantasyon için kullanılan, fonksiyon içinde ilk ifade olarak yer alan (herhangi bir değişkene atanmayan) çok satırlı string\">docstring</dfn> olarak tanımlayabilirsiniz; **FastAPI** de onu buradan okur.\n\nDocstring içinde [Markdown](https://en.wikipedia.org/wiki/Markdown) yazabilirsiniz; doğru şekilde yorumlanır ve gösterilir (docstring girintisi dikkate alınarak).\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\nInteractive docs’ta şöyle kullanılacaktır:\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## Response description { #response-description }\n\n`response_description` parametresi ile response açıklamasını belirtebilirsiniz:\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info | Bilgi\n\n`response_description` özellikle response’u ifade eder; `description` ise genel olarak *path operation*’ı ifade eder.\n\n///\n\n/// check | Ek bilgi\n\nOpenAPI, her *path operation* için bir response description zorunlu kılar.\n\nBu yüzden siz sağlamazsanız, **FastAPI** otomatik olarak \"Successful response\" üretir.\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## Bir *path operation*’ı Deprecate Etmek { #deprecate-a-path-operation }\n\nBir *path operation*’ı kaldırmadan, <dfn title=\"eskimiş, kullanılması önerilmez\">deprecated</dfn> olarak işaretlemeniz gerekiyorsa `deprecated` parametresini verin:\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\nInteractive docs’ta deprecated olduğu net şekilde işaretlenecektir:\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\nDeprecated olan ve olmayan *path operation*’ların nasıl göründüğüne bakın:\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## Özet { #recap }\n\n*Path operation*’larınızı, *path operation decorator*’larına parametre geçirerek kolayca yapılandırabilir ve metadata ekleyebilirsiniz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/path-params-numeric-validations.md",
    "content": "# Path Parametreleri ve Sayısal Doğrulamalar { #path-parameters-and-numeric-validations }\n\n`Query` ile query parametreleri için daha fazla doğrulama ve metadata tanımlayabildiğiniz gibi, `Path` ile de path parametreleri için aynı tür doğrulama ve metadata tanımlayabilirsiniz.\n\n## `Path`'i İçe Aktarın { #import-path }\n\nÖnce `fastapi` içinden `Path`'i ve `Annotated`'ı içe aktarın:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info | Bilgi\n\nFastAPI, 0.95.0 sürümünde `Annotated` desteğini ekledi (ve bunu önermeye başladı).\n\nDaha eski bir sürüm kullanıyorsanız, `Annotated` kullanmaya çalıştığınızda hata alırsınız.\n\n`Annotated` kullanmadan önce mutlaka FastAPI sürümünü en az 0.95.1 olacak şekilde [FastAPI sürümünü yükseltin](../deployment/versions.md#upgrading-the-fastapi-versions).\n\n///\n\n## Metadata Tanımlayın { #declare-metadata }\n\n`Query` için geçerli olan parametrelerin aynısını tanımlayabilirsiniz.\n\nÖrneğin, `item_id` path parametresi için bir `title` metadata değeri tanımlamak isterseniz şunu yazabilirsiniz:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note | Not\n\nBir path parametresi her zaman zorunludur, çünkü path'in bir parçası olmak zorundadır. `None` ile tanımlasanız veya bir varsayılan değer verseniz bile bu hiçbir şeyi değiştirmez; yine her zaman zorunlu olur.\n\n///\n\n## Parametreleri İhtiyacınıza Göre Sıralayın { #order-the-parameters-as-you-need }\n\n/// tip | İpucu\n\n`Annotated` kullanıyorsanız, bu muhtemelen o kadar önemli ya da gerekli değildir.\n\n///\n\nDiyelim ki query parametresi `q`'yu zorunlu bir `str` olarak tanımlamak istiyorsunuz.\n\nAyrıca bu parametre için başka bir şey tanımlamanız gerekmiyor; dolayısıyla `Query` kullanmanıza da aslında gerek yok.\n\nAncak `item_id` path parametresi için yine de `Path` kullanmanız gerekiyor. Ve bir sebepten `Annotated` kullanmak istemiyorsunuz.\n\nPython, \"default\" değeri olan bir parametreyi, \"default\" değeri olmayan bir parametreden önce yazarsanız şikayet eder.\n\nAma bunların sırasını değiştirebilir ve default değeri olmayan parametreyi (query parametresi `q`) en başa koyabilirsiniz.\n\nBu **FastAPI** için önemli değildir. FastAPI parametreleri isimlerine, tiplerine ve default tanımlarına (`Query`, `Path`, vb.) göre tespit eder; sırayla ilgilenmez.\n\nDolayısıyla fonksiyonunuzu şöyle tanımlayabilirsiniz:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\nNamun şunu unutmayın: `Annotated` kullanırsanız bu problem olmaz; çünkü `Query()` veya `Path()` için fonksiyon parametresi default değerlerini kullanmıyorsunuz.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## Parametreleri İhtiyacınıza Göre Sıralayın: Küçük Hileler { #order-the-parameters-as-you-need-tricks }\n\n/// tip | İpucu\n\n`Annotated` kullanıyorsanız, bu muhtemelen o kadar önemli ya da gerekli değildir.\n\n///\n\nİşte bazen işe yarayan **küçük bir hile**; ama çok sık ihtiyacınız olmayacak.\n\nŞunları yapmak istiyorsanız:\n\n* `q` query parametresini `Query` kullanmadan ve herhangi bir default değer vermeden tanımlamak\n* `item_id` path parametresini `Path` kullanarak tanımlamak\n* bunları farklı bir sırada yazmak\n* `Annotated` kullanmamak\n\n...Python bunun için küçük, özel bir sözdizimi sunar.\n\nFonksiyonun ilk parametresi olarak `*` geçin.\n\nPython bu `*` ile bir şey yapmaz; ama bundan sonraki tüm parametrelerin keyword argument (anahtar-değer çiftleri) olarak çağrılması gerektiğini bilir; buna <abbr title=\"Kökeni: K-ey W-ord Arg-uments - Anahtar Kelime Argümanları\"><code>kwargs</code></abbr> da denir. Default değerleri olmasa bile.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### `Annotated` ile Daha İyi { #better-with-annotated }\n\nŞunu da unutmayın: `Annotated` kullanırsanız, fonksiyon parametresi default değerlerini kullanmadığınız için bu sorun ortaya çıkmaz ve muhtemelen `*` kullanmanız da gerekmez.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## Sayı Doğrulamaları: Büyük Eşit { #number-validations-greater-than-or-equal }\n\n`Query` ve `Path` (ve ileride göreceğiniz diğerleri) ile sayı kısıtları tanımlayabilirsiniz.\n\nBurada `ge=1` ile, `item_id` değerinin `1`'den \"`g`reater than or `e`qual\" olacak şekilde bir tam sayı olması gerekir.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## Sayı Doğrulamaları: Büyük ve Küçük Eşit { #number-validations-greater-than-and-less-than-or-equal }\n\nAynısı şunlar için de geçerlidir:\n\n* `gt`: `g`reater `t`han\n* `le`: `l`ess than or `e`qual\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## Sayı Doğrulamaları: `float` Değerler, Büyük ve Küçük { #number-validations-floats-greater-than-and-less-than }\n\nSayı doğrulamaları `float` değerler için de çalışır.\n\nBurada <abbr title=\"greater than - büyüktür\"><code>gt</code></abbr> tanımlayabilmek (sadece <abbr title=\"greater than or equal - büyük veya eşittir\"><code>ge</code></abbr> değil) önemli hale gelir. Çünkü örneğin bir değerin `0`'dan büyük olmasını isteyebilirsiniz; `1`'den küçük olsa bile.\n\nBu durumda `0.5` geçerli bir değer olur. Ancak `0.0` veya `0` geçerli olmaz.\n\nAynısı <abbr title=\"less than - küçüktür\"><code>lt</code></abbr> için de geçerlidir.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## Özet { #recap }\n\n`Query`, `Path` (ve henüz görmedikleriniz) ile metadata ve string doğrulamalarını, [Query Parametreleri ve String Doğrulamalar](query-params-str-validations.md) bölümündekiyle aynı şekilde tanımlayabilirsiniz.\n\nAyrıca sayısal doğrulamalar da tanımlayabilirsiniz:\n\n* `gt`: `g`reater `t`han\n* `ge`: `g`reater than or `e`qual\n* `lt`: `l`ess `t`han\n* `le`: `l`ess than or `e`qual\n\n/// info | Bilgi\n\n`Query`, `Path` ve ileride göreceğiniz diğer class'lar ortak bir `Param` class'ının alt class'larıdır.\n\nHepsi, gördüğünüz ek doğrulama ve metadata parametrelerini paylaşır.\n\n///\n\n/// note | Teknik Detaylar\n\n`Query`, `Path` ve diğerlerini `fastapi` içinden import ettiğinizde, bunlar aslında birer fonksiyondur.\n\nÇağrıldıklarında, aynı isme sahip class'ların instance'larını döndürürler.\n\nYani `Query`'yi import edersiniz; bu bir fonksiyondur. Onu çağırdığınızda, yine `Query` adlı bir class'ın instance'ını döndürür.\n\nBu fonksiyonlar (class'ları doğrudan kullanmak yerine) editörünüzün type'larıyla ilgili hata işaretlememesi için vardır.\n\nBu sayede, bu hataları yok saymak üzere özel ayarlar eklemeden normal editörünüzü ve coding araçlarınızı kullanabilirsiniz.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/tutorial/path-params.md",
    "content": "# Yol Parametreleri { #path-parameters }\n\nPython <abbr title=\"String Biçimleme: Format String\">string biçimlemede</abbr> kullanılan sözdizimiyle path \"parametreleri\"ni veya \"değişkenleri\"ni tanımlayabilirsiniz:\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\nPath parametresi `item_id`'nin değeri, fonksiyonunuza `item_id` argümanı olarak aktarılacaktır.\n\nYani, bu örneği çalıştırıp [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo) adresine giderseniz, şöyle bir response görürsünüz:\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## Tip İçeren Yol Parametreleri { #path-parameters-with-types }\n\nStandart Python tip belirteçlerini kullanarak path parametresinin tipini fonksiyonun içinde tanımlayabilirsiniz:\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\nBu durumda, `item_id` bir `int` olarak tanımlanır.\n\n/// check | Ek bilgi\n\nBu sayede, fonksiyon içinde hata denetimi, kod tamamlama vb. konularda editör desteğine kavuşursunuz.\n\n///\n\n## Veri <dfn title=\"diğer adlarıyla: serileştirme, ayrıştırma, marshalling\">dönüştürme</dfn> { #data-conversion }\n\nBu örneği çalıştırıp tarayıcınızda [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3) adresini açarsanız, şöyle bir response görürsünüz:\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check | Ek bilgi\n\nDikkat edin: fonksiyonunuzun aldığı (ve döndürdüğü) değer olan `3`, string `\"3\"` değil, bir Python `int`'idir.\n\nYani, bu tip tanımıyla birlikte **FastAPI** size otomatik request \"<dfn title=\"HTTP request'ten gelen string'i Python verisine dönüştürme\">ayrıştırma</dfn>\" sağlar.\n\n///\n\n## Veri Doğrulama { #data-validation }\n\nAncak tarayıcınızda [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo) adresine giderseniz, şuna benzer güzel bir HTTP hatası görürsünüz:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\nçünkü path parametresi `item_id`, `int` olmayan `\"foo\"` değerine sahipti.\n\nAynı hata, şu örnekte olduğu gibi `int` yerine `float` verirseniz de ortaya çıkar: [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)\n\n/// check | Ek bilgi\n\nYani, aynı Python tip tanımıyla birlikte **FastAPI** size veri doğrulama sağlar.\n\nDikkat edin: hata ayrıca doğrulamanın geçmediği noktayı da açıkça belirtir.\n\nBu, API'ınızla etkileşime giren kodu geliştirirken ve debug ederken inanılmaz derecede faydalıdır.\n\n///\n\n## Dokümantasyon { #documentation }\n\nTarayıcınızı [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) adresinde açtığınızda, aşağıdaki gibi otomatik ve interaktif bir API dokümantasyonu görürsünüz:\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check | Ek bilgi\n\nYine, sadece aynı Python tip tanımıyla **FastAPI** size otomatik ve interaktif dokümantasyon (Swagger UI entegrasyonuyla) sağlar.\n\nDikkat edin: path parametresi integer olarak tanımlanmıştır.\n\n///\n\n## Standartlara Dayalı Avantajlar, Alternatif Dokümantasyon { #standards-based-benefits-alternative-documentation }\n\nÜretilen şema [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md) standardından geldiği için birçok uyumlu araç vardır.\n\nBu nedenle **FastAPI**'ın kendisi, [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) adresinden erişebileceğiniz alternatif bir API dokümantasyonu (ReDoc kullanarak) sağlar:\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\nAynı şekilde, birçok uyumlu araç vardır. Birçok dil için kod üretme araçları da buna dahildir.\n\n## Pydantic { #pydantic }\n\nTüm veri doğrulamaları, arka planda [Pydantic](https://docs.pydantic.dev/) tarafından gerçekleştirilir; böylece onun tüm avantajlarından faydalanırsınız. Ve emin ellerde olduğunuzu bilirsiniz.\n\nAynı tip tanımlarını `str`, `float`, `bool` ve daha birçok karmaşık veri tipiyle kullanabilirsiniz.\n\nBunların birkaçı, eğitimin sonraki bölümlerinde ele alınacaktır.\n\n## Sıralama Önemlidir { #order-matters }\n\n*Path operation*'lar oluştururken sabit bir path'e sahip olduğunuz durumlarla karşılaşabilirsiniz.\n\nÖrneğin `/users/me`'nin, geçerli kullanıcı hakkında veri almak için kullanıldığını varsayalım.\n\nSonra belirli bir kullanıcı hakkında, kullanıcı ID'si ile veri almak için `/users/{user_id}` şeklinde bir path'iniz de olabilir.\n\n*Path operation*'lar sırayla değerlendirildiği için, `/users/me` için olan path'in `/users/{user_id}` olandan önce tanımlandığından emin olmanız gerekir:\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\nAksi halde, `/users/{user_id}` için olan path, `\"me\"` değerini `user_id` parametresi olarak aldığını \"düşünerek\" `/users/me` için de eşleşir.\n\nBenzer şekilde, bir path operation'ı yeniden tanımlayamazsınız:\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\nPath önce eşleştiği için her zaman ilk olan kullanılır.\n\n## Ön Tanımlı Değerler { #predefined-values }\n\nBir *path operation*'ınız *path parameter* alıyorsa ama olası geçerli *path parameter* değerlerinin önceden tanımlı olmasını istiyorsanız, standart bir Python <abbr title=\"Enumeration - Numaralandırma\">`Enum`</abbr> kullanabilirsiniz.\n\n### Bir `Enum` Sınıfı Oluşturalım { #create-an-enum-class }\n\n`Enum`'u import edin ve `str` ile `Enum`'dan miras alan bir alt sınıf oluşturun.\n\n`str`'den miras aldığınızda API dokümanları değerlerin `string` tipinde olması gerektiğini anlayabilir ve doğru şekilde render edebilir.\n\nSonra, kullanılabilir geçerli değerler olacak sabit değerli class attribute'ları oluşturun:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip | İpucu\n\nMerak ediyorsanız: \"AlexNet\", \"ResNet\" ve \"LeNet\", Makine Öğrenmesi <dfn title=\"Teknik olarak, Derin Öğrenme model mimarileri\">modelleri</dfn>nin sadece isimleridir.\n\n///\n\n### Bir *Path Parameter* Tanımlayalım { #declare-a-path-parameter }\n\nArdından oluşturduğunuz enum sınıfını (`ModelName`) kullanarak tip belirteciyle bir *path parameter* oluşturun:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### Dokümana Göz Atalım { #check-the-docs }\n\n*Path parameter* için kullanılabilir değerler ön tanımlı olduğu için, interaktif dokümanlar bunları güzelce gösterebilir:\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### Python *Enumeration*'ları ile Çalışmak { #working-with-python-enumerations }\n\n*Path parameter*'ın değeri bir *enumeration member* olacaktır.\n\n#### *Enumeration Member*'ları Karşılaştıralım { #compare-enumeration-members }\n\nBunu, oluşturduğunuz enum `ModelName` içindeki *enumeration member* ile karşılaştırabilirsiniz:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### *Enumeration Value*'yu Alalım { #get-the-enumeration-value }\n\nGerçek değeri (bu durumda bir `str`) `model_name.value` ile veya genel olarak `your_enum_member.value` ile alabilirsiniz:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip | İpucu\n\n`\"lenet\"` değerine `ModelName.lenet.value` ile de erişebilirsiniz.\n\n///\n\n#### *Enumeration Member*'ları Döndürelim { #return-enumeration-members }\n\n*Path operation*'ınızdan, bir JSON body'nin içine gömülü olsalar bile (ör. bir `dict`) *enum member*'ları döndürebilirsiniz.\n\nİstemciye dönmeden önce, karşılık gelen değerlerine (bu durumda string) dönüştürülürler:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\nİstemcinizde şöyle bir JSON response alırsınız:\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## Path İçeren Path Parametreleri { #path-parameters-containing-paths }\n\nDiyelim ki `/files/{file_path}` path'ine sahip bir *path operation*'ınız var.\n\nAma `file_path`'in kendisinin `home/johndoe/myfile.txt` gibi bir *path* içermesi gerekiyor.\n\nBöylece, o dosyanın URL'si şu şekilde olur: `/files/home/johndoe/myfile.txt`.\n\n### OpenAPI Desteği { #openapi-support }\n\nOpenAPI, içinde bir *path* barındıracak bir *path parameter* tanımlamak için bir yöntem desteklemez; çünkü bu, test etmesi ve tanımlaması zor senaryolara yol açabilir.\n\nYine de, Starlette'in dahili araçlarından birini kullanarak bunu **FastAPI**'da yapabilirsiniz.\n\nVe dokümanlar, parametrenin bir path içermesi gerektiğini söyleyen herhangi bir dokümantasyon eklemese bile çalışmaya devam eder.\n\n### Path Dönüştürücü { #path-convertor }\n\nStarlette'ten doğrudan gelen bir seçenekle, *path* içeren bir *path parameter*'ı şu URL ile tanımlayabilirsiniz:\n\n```\n/files/{file_path:path}\n```\n\nBu durumda parametrenin adı `file_path`'tir ve son kısım olan `:path`, parametrenin herhangi bir *path* ile eşleşmesi gerektiğini söyler.\n\nYani şununla kullanabilirsiniz:\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip | İpucu\n\nParametrenin başında `/home/johndoe/myfile.txt` örneğinde olduğu gibi bir eğik çizgi (`/`) ile başlaması gerekebilir.\n\nBu durumda URL, `files` ile `home` arasında çift eğik çizgi (`//`) olacak şekilde `/files//home/johndoe/myfile.txt` olur.\n\n///\n\n## Özet { #recap }\n\n**FastAPI** ile kısa, sezgisel ve standart Python tip tanımlarını kullanarak şunları elde edersiniz:\n\n* Editör desteği: hata denetimleri, otomatik tamamlama vb.\n* Veri \"<dfn title=\"HTTP request'ten gelen string'i Python verisine dönüştürme\">ayrıştırma</dfn>\"\n* Veri doğrulama\n* API annotation ve otomatik dokümantasyon\n\nVe bunları sadece bir kez tanımlamanız yeterlidir.\n\nBu, (ham performans dışında) **FastAPI**'ın alternatif framework'lere kıyasla muhtemelen en görünür ana avantajıdır.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/query-param-models.md",
    "content": "# Query Parameter Modelleri { #query-parameter-models }\n\nBirbirleriyle ilişkili bir **query parameter** grubunuz varsa, bunları tanımlamak için bir **Pydantic model** oluşturabilirsiniz.\n\nBöylece **modeli yeniden kullanabilir**, **birden fazla yerde** tekrar tekrar kullanabilir ve tüm parametreler için validation (doğrulama) ile metadata’yı tek seferde tanımlayabilirsiniz. 😎\n\n/// note | Not\n\nBu özellik FastAPI `0.115.0` sürümünden beri desteklenmektedir. 🤓\n\n///\n\n## Pydantic Model ile Query Parameters { #query-parameters-with-a-pydantic-model }\n\nİhtiyacınız olan **query parameter**’ları bir **Pydantic model** içinde tanımlayın, ardından parametreyi `Query` olarak belirtin:\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\n**FastAPI**, request’teki **query parameter**’lardan **her field** için veriyi **extract** eder ve tanımladığınız Pydantic model’i size verir.\n\n## Dokümanları Kontrol Edin { #check-the-docs }\n\nQuery parameter’ları `/docs` altındaki dokümantasyon arayüzünde görebilirsiniz:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## Ek Query Parameter'ları Yasaklayın { #forbid-extra-query-parameters }\n\nBazı özel kullanım senaryolarında (muhtemelen çok yaygın değil), almak istediğiniz query parameter’ları **kısıtlamak** isteyebilirsiniz.\n\nPydantic’in model konfigürasyonunu kullanarak `extra` field’ları `forbid` edebilirsiniz:\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\nBir client, **query parameter**’larda **ek (extra)** veri göndermeye çalışırsa, **error** response alır.\n\nÖrneğin client, değeri `plumbus` olan bir `tool` query parameter’ı göndermeye çalışırsa:\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\n`tool` query parameter’ına izin verilmediğini söyleyen bir **error** response alır:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## Özet { #summary }\n\n**FastAPI** içinde **query parameter**’ları tanımlamak için **Pydantic model**’leri kullanabilirsiniz. 😎\n\n/// tip | İpucu\n\nSpoiler: cookie ve header’ları tanımlamak için de Pydantic model’leri kullanabilirsiniz; ancak bunu tutorial’ın ilerleyen bölümlerinde göreceksiniz. 🤫\n\n///\n"
  },
  {
    "path": "docs/tr/docs/tutorial/query-params-str-validations.md",
    "content": "# Query Parametreleri ve String Doğrulamaları { #query-parameters-and-string-validations }\n\n**FastAPI**, parametreleriniz için ek bilgi ve doğrulamalar (validation) tanımlamanıza izin verir.\n\nÖrnek olarak şu uygulamayı ele alalım:\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\nQuery parametresi `q`, `str | None` tipindedir. Yani tipi `str`’dir ama `None` da olabilir. Nitekim varsayılan değer `None` olduğu için FastAPI bunun zorunlu olmadığını anlar.\n\n/// note | Not\n\nFastAPI, `q`’nun zorunlu olmadığını `= None` varsayılan değerinden anlar.\n\n`str | None` kullanmak, editörünüzün daha iyi destek vermesini ve hataları yakalamasını sağlar.\n\n///\n\n## Ek Doğrulama { #additional-validation }\n\n`q` opsiyonel olsa bile, verildiği durumda **uzunluğunun 50 karakteri geçmemesini** zorlayacağız.\n\n### `Query` ve `Annotated` import edin { #import-query-and-annotated }\n\nBunu yapmak için önce şunları import edin:\n\n* `fastapi` içinden `Query`\n* `typing` içinden `Annotated`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info | Bilgi\n\nFastAPI, 0.95.0 sürümünde `Annotated` desteğini ekledi (ve önermeye başladı).\n\nDaha eski bir sürüm kullanıyorsanız `Annotated` kullanmaya çalışırken hata alırsınız.\n\n`Annotated` kullanmadan önce FastAPI sürümünü en az 0.95.1’e yükseltmek için [FastAPI sürümünü yükseltin](../deployment/versions.md#upgrading-the-fastapi-versions).\n\n///\n\n## `q` parametresinin tipinde `Annotated` kullanın { #use-annotated-in-the-type-for-the-q-parameter }\n\n[Python Tiplerine Giriş](../python-types.md#type-hints-with-metadata-annotations) içinde `Annotated` ile parametrelerinize metadata ekleyebileceğinizi söylemiştim, hatırlıyor musunuz?\n\nŞimdi bunu FastAPI ile kullanmanın zamanı. 🚀\n\nŞu tip anotasyonuna sahiptik:\n\n```Python\nq: str | None = None\n```\n\nŞimdi bunu `Annotated` ile saracağız; şöyle olacak:\n\n```Python\nq: Annotated[str | None] = None\n```\n\nBu iki sürüm de aynı anlama gelir: `q`, `str` veya `None` olabilen bir parametredir ve varsayılan olarak `None`’dır.\n\nŞimdi işin eğlenceli kısmına geçelim. 🎉\n\n## `q` parametresindeki `Annotated` içine `Query` ekleyin { #add-query-to-annotated-in-the-q-parameter }\n\nArtık ek bilgi (bu durumda ek doğrulama) koyabildiğimiz bir `Annotated`’ımız olduğuna göre, `Annotated` içine `Query` ekleyin ve `max_length` parametresini `50` olarak ayarlayın:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\nVarsayılan değerin hâlâ `None` olduğuna dikkat edin; yani parametre hâlâ opsiyonel.\n\nAma şimdi `Annotated` içinde `Query(max_length=50)` kullanarak FastAPI’ye bu değer için **ek doğrulama** istediğimizi söylüyoruz: en fazla 50 karakter. 😎\n\n/// tip | İpucu\n\nBurada `Query()` kullanıyoruz çünkü bu bir **query parametresi**. İleride `Path()`, `Body()`, `Header()` ve `Cookie()` gibi, `Query()` ile aynı argümanları kabul eden diğerlerini de göreceğiz.\n\n///\n\nFastAPI artık şunları yapacak:\n\n* Verinin uzunluğunun en fazla 50 karakter olduğundan emin olacak şekilde **doğrulayacak**\n* Veri geçerli değilse client için **net bir hata** gösterecek\n* Parametreyi OpenAPI şemasındaki *path operation* içinde **dokümante edecek** (dolayısıyla **otomatik dokümantasyon arayüzünde** görünecek)\n\n## Alternatif (eski): Varsayılan değer olarak `Query` { #alternative-old-query-as-the-default-value }\n\nFastAPI’nin önceki sürümlerinde ( <dfn title=\"2023-03’ten önce\">0.95.0</dfn> öncesi) `Query`’yi `Annotated` içine koymak yerine, parametrenizin varsayılan değeri olarak kullanmanız gerekiyordu. Etrafta bu şekilde yazılmış kod görme ihtimaliniz yüksek; bu yüzden açıklayalım.\n\n/// tip | İpucu\n\nYeni kodlarda ve mümkün olduğunda, yukarıda anlatıldığı gibi `Annotated` kullanın. Birden fazla avantajı vardır (aşağıda anlatılıyor) ve dezavantajı yoktur. 🍰\n\n///\n\nFonksiyon parametresinin varsayılan değeri olarak `Query()` kullanıp `max_length` parametresini 50 yapmak şöyle olurdu:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\nBu senaryoda (`Annotated` kullanmadığımız için) fonksiyondaki `None` varsayılan değerini `Query()` ile değiştirmemiz gerekiyor. Bu durumda varsayılan değeri `Query(default=None)` ile vermeliyiz; bu, (en azından FastAPI açısından) aynı varsayılan değeri tanımlama amacına hizmet eder.\n\nYani:\n\n```Python\nq: str | None = Query(default=None)\n```\n\n...parametreyi `None` varsayılan değeriyle opsiyonel yapar; şununla aynı:\n\n\n```Python\nq: str | None = None\n```\n\nAncak `Query` sürümü bunun bir query parametresi olduğunu açıkça belirtir.\n\nSonrasında `Query`’ye daha fazla parametre geçebiliriz. Bu örnekte string’ler için geçerli olan `max_length`:\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\nBu, veriyi doğrular, veri geçerli değilse net bir hata gösterir ve parametreyi OpenAPI şemasındaki *path operation* içinde dokümante eder.\n\n### Varsayılan değer olarak `Query` veya `Annotated` içinde `Query` { #query-as-the-default-value-or-in-annotated }\n\n`Annotated` içinde `Query` kullanırken `Query` için `default` parametresini kullanamayacağınızı unutmayın.\n\nBunun yerine fonksiyon parametresinin gerçek varsayılan değerini kullanın. Aksi halde tutarsız olur.\n\nÖrneğin şu kullanım izinli değildir:\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n...çünkü varsayılan değerin `\"rick\"` mi `\"morty\"` mi olması gerektiği belli değildir.\n\nBu nedenle (tercihen) şöyle kullanırsınız:\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n...veya eski kod tabanlarında şuna rastlarsınız:\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### `Annotated`’ın avantajları { #advantages-of-annotated }\n\nFonksiyon parametrelerindeki varsayılan değer stiline göre **`Annotated` kullanmanız önerilir**; birden fazla nedenle **daha iyidir**. 🤓\n\n**Fonksiyon parametresinin** **varsayılan** değeri, **gerçek varsayılan** değerdir; bu genel olarak Python açısından daha sezgiseldir. 😌\n\nAynı fonksiyonu FastAPI olmadan **başka yerlerde** de **çağırabilirsiniz** ve **beklendiği gibi çalışır**. Eğer **zorunlu** bir parametre varsa (varsayılan değer yoksa) editörünüz hata ile bunu belirtir; ayrıca gerekli parametreyi vermeden çalıştırırsanız **Python** da şikayet eder.\n\n`Annotated` kullanmayıp bunun yerine **(eski) varsayılan değer stilini** kullanırsanız, o fonksiyonu FastAPI olmadan **başka yerlerde** çağırdığınızda doğru çalışması için argümanları geçmeniz gerektiğini **hatırlamak** zorunda kalırsınız; yoksa değerler beklediğinizden farklı olur (ör. `QueryInfo` veya benzeri). Üstelik editörünüz de şikayet etmez ve Python da fonksiyonu çalıştırırken şikayet etmez; ancak içerideki operasyonlar hata verince ortaya çıkar.\n\n`Annotated` birden fazla metadata anotasyonu alabildiği için, artık aynı fonksiyonu [Typer](https://typer.tiangolo.com/) gibi başka araçlarla da kullanabilirsiniz. 🚀\n\n## Daha fazla doğrulama ekleyin { #add-more-validations }\n\n`min_length` parametresini de ekleyebilirsiniz:\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## Regular expression ekleyin { #add-regular-expressions }\n\nParametrenin eşleşmesi gereken bir `pattern` <dfn title=\"String'ler için arama deseni tanımlayan karakter dizisi\">düzenli ifade</dfn> tanımlayabilirsiniz:\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\nBu özel regular expression pattern’i, gelen parametre değerinin şunları sağladığını kontrol eder:\n\n* `^`: Aşağıdaki karakterlerle başlar; öncesinde karakter yoktur.\n* `fixedquery`: Tam olarak `fixedquery` değerine sahiptir.\n* `$`: Orada biter; `fixedquery` sonrasında başka karakter yoktur.\n\nBu **\"regular expression\"** konuları gözünüzü korkutuyorsa sorun değil. Birçok kişi için zor bir konudur. Regular expression’lara ihtiyaç duymadan da pek çok şey yapabilirsiniz.\n\nArtık ihtiyaç duyduğunuzda **FastAPI** içinde kullanabileceğinizi biliyorsunuz.\n\n## Varsayılan değerler { #default-values }\n\nElbette `None` dışında varsayılan değerler de kullanabilirsiniz.\n\nÖrneğin `q` query parametresi için `min_length` değerini `3` yapmak ve varsayılan değer olarak `\"fixedquery\"` vermek istediğinizi düşünelim:\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | Not\n\n`None` dahil herhangi bir tipte varsayılan değere sahip olmak, parametreyi opsiyonel (zorunlu değil) yapar.\n\n///\n\n## Zorunlu parametreler { #required-parameters }\n\nDaha fazla doğrulama veya metadata tanımlamamız gerekmiyorsa, `q` query parametresini yalnızca varsayılan değer tanımlamayarak zorunlu yapabiliriz:\n\n```Python\nq: str\n```\n\nşunun yerine:\n\n```Python\nq: str | None = None\n```\n\nAncak biz artık `Query` ile tanımlıyoruz; örneğin şöyle:\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\nDolayısıyla `Query` kullanırken bir değeri zorunlu yapmak istediğinizde, varsayılan değer tanımlamamanız yeterlidir:\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### Zorunlu ama `None` olabilir { #required-can-be-none }\n\nBir parametrenin `None` kabul edebileceğini söyleyip yine de zorunlu olmasını sağlayabilirsiniz. Bu, client’ların değer göndermesini zorunlu kılar; değer `None` olsa bile.\n\nBunu yapmak için `None`’ı geçerli bir tip olarak tanımlayın ama varsayılan değer vermeyin:\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## Query parametresi listesi / birden fazla değer { #query-parameter-list-multiple-values }\n\nBir query parametresini `Query` ile açıkça tanımladığınızda, bir değer listesi alacak şekilde (başka bir deyişle, birden fazla değer alacak şekilde) de tanımlayabilirsiniz.\n\nÖrneğin URL’de `q` query parametresinin birden fazla kez görünebilmesini istiyorsanız şöyle yazabilirsiniz:\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\nSonra şu URL ile:\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\n*path operation function* içinde, *function parameter* olan `q` parametresinde, birden fazla `q` *query parameters* değerini (`foo` ve `bar`) bir Python `list`’i olarak alırsınız.\n\nDolayısıyla bu URL’ye response şöyle olur:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | İpucu\n\nYukarıdaki örnekte olduğu gibi tipi `list` olan bir query parametresi tanımlamak için `Query`’yi açıkça kullanmanız gerekir; aksi halde request body olarak yorumlanır.\n\n///\n\nEtkileşimli API dokümanları da buna göre güncellenir ve birden fazla değere izin verir:\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### Varsayılanlarla query parametresi listesi / birden fazla değer { #query-parameter-list-multiple-values-with-defaults }\n\nHiç değer verilmezse varsayılan bir `list` de tanımlayabilirsiniz:\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\nŞu adrese giderseniz:\n\n```\nhttp://localhost:8000/items/\n```\n\n`q`’nun varsayılanı `[\"foo\", \"bar\"]` olur ve response şöyle olur:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### Sadece `list` kullanmak { #using-just-list }\n\n`list[str]` yerine doğrudan `list` de kullanabilirsiniz:\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | Not\n\nBu durumda FastAPI, listenin içeriğini kontrol etmez.\n\nÖrneğin `list[int]`, listenin içeriğinin integer olduğunu kontrol eder (ve dokümante eder). Ancak tek başına `list` bunu yapmaz.\n\n///\n\n## Daha fazla metadata tanımlayın { #declare-more-metadata }\n\nParametre hakkında daha fazla bilgi ekleyebilirsiniz.\n\nBu bilgiler oluşturulan OpenAPI’a dahil edilir ve dokümantasyon arayüzleri ile harici araçlar tarafından kullanılır.\n\n/// note | Not\n\nFarklı araçların OpenAPI desteği farklı seviyelerde olabilir.\n\nBazıları tanımladığınız ek bilgilerin hepsini göstermeyebilir; ancak çoğu durumda eksik özellik geliştirme planındadır.\n\n///\n\nBir `title` ekleyebilirsiniz:\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\nVe bir `description`:\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## Alias parametreleri { #alias-parameters }\n\nParametrenin adının `item-query` olmasını istediğinizi düşünün.\n\nÖrneğin:\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\nAncak `item-query` geçerli bir Python değişken adı değildir.\n\nEn yakın seçenek `item_query` olur.\n\nAma sizin hâlâ tam olarak `item-query` olmasına ihtiyacınız var...\n\nO zaman bir `alias` tanımlayabilirsiniz; bu alias, parametre değerini bulmak için kullanılacaktır:\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## Parametreleri deprecated yapmak { #deprecating-parameters }\n\nDiyelim ki artık bu parametreyi istemiyorsunuz.\n\nBazı client’lar hâlâ kullandığı için bir süre tutmanız gerekiyor, ama dokümanların bunu açıkça <dfn title=\"kullanımdan kalkmış, kullanmamanız önerilir\">deprecated</dfn> olarak göstermesini istiyorsunuz.\n\nO zaman `Query`’ye `deprecated=True` parametresini geçin:\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\nDokümanlarda şöyle görünür:\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## Parametreleri OpenAPI’dan hariç tutun { #exclude-parameters-from-openapi }\n\nOluşturulan OpenAPI şemasından (dolayısıyla otomatik dokümantasyon sistemlerinden) bir query parametresini hariç tutmak için `Query`’nin `include_in_schema` parametresini `False` yapın:\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## Özel Doğrulama { #custom-validation }\n\nYukarıdaki parametrelerle yapılamayan bazı **özel doğrulama** ihtiyaçlarınız olabilir.\n\nBu durumlarda, normal doğrulamadan sonra (ör. değerin `str` olduğunun doğrulanmasından sonra) uygulanacak bir **custom validator function** kullanabilirsiniz.\n\nBunu, `Annotated` içinde [Pydantic’in `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator)’ını kullanarak yapabilirsiniz.\n\n/// tip | İpucu\n\nPydantic’te [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) ve başka validator’lar da vardır. 🤓\n\n///\n\nÖrneğin bu custom validator, bir item ID’sinin <abbr title=\"International Standard Book Number - Uluslararası Standart Kitap Numarası\">ISBN</abbr> kitap numarası için `isbn-` ile veya <abbr title=\"Internet Movie Database - İnternet Film Veritabanı: filmler hakkında bilgi içeren bir web sitesi\">IMDB</abbr> film URL ID’si için `imdb-` ile başladığını kontrol eder:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info | Bilgi\n\nBu özellik Pydantic 2 ve üzeri sürümlerde mevcuttur. 😎\n\n///\n\n/// tip | İpucu\n\nVeritabanı veya başka bir API gibi herhangi bir **harici bileşen** ile iletişim gerektiren bir doğrulama yapmanız gerekiyorsa, bunun yerine **FastAPI Dependencies** kullanmalısınız; onları ileride öğreneceksiniz.\n\nBu custom validator’lar, request’te sağlanan **yalnızca** **aynı veri** ile kontrol edilebilen şeyler içindir.\n\n///\n\n### O Kodu Anlamak { #understand-that-code }\n\nÖnemli nokta, **`Annotated` içinde bir fonksiyonla birlikte `AfterValidator` kullanmak**. İsterseniz bu kısmı atlayabilirsiniz. 🤸\n\n---\n\nAma bu örnek kodun detaylarını merak ediyorsanız, birkaç ek bilgi:\n\n#### `value.startswith()` ile String { #string-with-value-startswith }\n\nFark ettiniz mi? `value.startswith()` ile bir string, tuple alabilir ve tuple içindeki her değeri kontrol eder:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### Rastgele Bir Item { #a-random-item }\n\n`data.items()` ile, her dictionary öğesi için key ve value içeren tuple’lardan oluşan bir <dfn title=\"for döngüsüyle üzerinde gezinebileceğimiz bir şey; list, set vb.\">yinelemeli nesne</dfn> elde ederiz.\n\nBu yinelemeli nesneyi `list(data.items())` ile düzgün bir `list`’e çeviririz.\n\nArdından `random.choice()` ile list’ten **rastgele bir değer** alırız; yani `(id, name)` içeren bir tuple elde ederiz. Şuna benzer: `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")`.\n\nSonra tuple içindeki bu **iki değeri** `id` ve `name` değişkenlerine **atarız**.\n\nBöylece kullanıcı bir item ID’si vermemiş olsa bile yine de rastgele bir öneri alır.\n\n...bütün bunları **tek bir basit satırda** yapıyoruz. 🤯 Python’u sevmemek elde mi? 🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## Özet { #recap }\n\nParametreleriniz için ek doğrulamalar ve metadata tanımlayabilirsiniz.\n\nGenel doğrulamalar ve metadata:\n\n* `alias`\n* `title`\n* `description`\n* `deprecated`\n\nString’lere özel doğrulamalar:\n\n* `min_length`\n* `max_length`\n* `pattern`\n\n`AfterValidator` ile custom doğrulamalar.\n\nBu örneklerde `str` değerleri için doğrulamanın nasıl tanımlanacağını gördünüz.\n\nSayılar gibi diğer tipler için doğrulamaları nasıl tanımlayacağınızı öğrenmek için sonraki bölümlere geçin.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/query-params.md",
    "content": "# Sorgu Parametreleri { #query-parameters }\n\nFonksiyonda path parametrelerinin parçası olmayan diğer parametreleri tanımladığınızda, bunlar otomatik olarak \"query\" parametreleri olarak yorumlanır.\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\nQuery, bir URL'de `?` işaretinden sonra gelen ve `&` karakterleriyle ayrılan anahtar-değer çiftlerinin kümesidir.\n\nÖrneğin, şu URL'de:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n...query parametreleri şunlardır:\n\n* `skip`: değeri `0`\n* `limit`: değeri `10`\n\nURL'nin bir parçası oldukları için \"doğal olarak\" string'tirler.\n\nAncak, bunları Python tipleriyle (yukarıdaki örnekte `int` olarak) tanımladığınızda, o tipe dönüştürülürler ve o tipe göre doğrulanırlar.\n\nPath parametreleri için geçerli olan aynı süreç query parametreleri için de geçerlidir:\n\n* Editör desteği (tabii ki)\n* Veri <dfn title=\"bir HTTP request'ten gelen string'i Python verisine dönüştürme\">\"ayrıştırma\"</dfn>\n* Veri doğrulama\n* Otomatik dokümantasyon\n\n## Varsayılanlar { #defaults }\n\nQuery parametreleri path'in sabit bir parçası olmadığından, opsiyonel olabilir ve varsayılan değerlere sahip olabilir.\n\nYukarıdaki örnekte varsayılan değerleri `skip=0` ve `limit=10`'dur.\n\nYani şu URL'ye gitmek:\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\nşuraya gitmekle aynı olur:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\nAncak örneğin şuraya giderseniz:\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\nFonksiyonunuzdaki parametre değerleri şöyle olacaktır:\n\n* `skip=20`: çünkü URL'de siz ayarladınız\n* `limit=10`: çünkü varsayılan değer oydu\n\n## İsteğe bağlı parametreler { #optional-parameters }\n\nAynı şekilde, varsayılan değerlerini `None` yaparak isteğe bağlı query parametreleri tanımlayabilirsiniz:\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\nBu durumda, fonksiyon parametresi `q` isteğe bağlı olur ve varsayılan olarak `None` olur.\n\n/// check | Ek bilgi\n\nAyrıca, **FastAPI** path parametresi olan `item_id`'nin bir path parametresi olduğunu ve `q`'nun path olmadığını fark edecek kadar akıllıdır; dolayısıyla bu bir query parametresidir.\n\n///\n\n## Sorgu parametresi tip dönüşümü { #query-parameter-type-conversion }\n\n`bool` tipleri de tanımlayabilirsiniz, ve bunlar dönüştürülür:\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\nBu durumda, şuraya giderseniz:\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\nveya\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\nveya\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\nveya\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\nveya\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\nveya başka herhangi bir büyük/küçük harf varyasyonunda (tamamı büyük, ilk harf büyük, vb.), fonksiyonunuz `short` parametresini `bool` değeri `True` olarak görecektir. Aksi halde `False` olarak görür.\n\n\n## Çoklu path ve query parametreleri { #multiple-path-and-query-parameters }\n\nAynı anda birden fazla path parametresi ve query parametresi tanımlayabilirsiniz; **FastAPI** hangisinin hangisi olduğunu bilir.\n\nAyrıca bunları belirli bir sırayla tanımlamanız gerekmez.\n\nİsme göre tespit edilirler:\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## Zorunlu query parametreleri { #required-query-parameters }\n\nPath olmayan parametreler (şimdilik sadece query parametrelerini gördük) için varsayılan değer tanımladığınızda, bu parametre zorunlu olmaz.\n\nBelirli bir değer eklemek istemiyor ama sadece opsiyonel olmasını istiyorsanız, varsayılanı `None` olarak ayarlayın.\n\nAncak bir query parametresini zorunlu yapmak istediğinizde, herhangi bir varsayılan değer tanımlamamanız yeterlidir:\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\nBurada query parametresi `needy`, `str` tipinde zorunlu bir query parametresidir.\n\nTarayıcınızda şöyle bir URL açarsanız:\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n...zorunlu `needy` parametresini eklemeden, şuna benzer bir hata görürsünüz:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\n`needy` zorunlu bir parametre olduğundan, URL'de ayarlamanız gerekir:\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n...bu çalışır:\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\nVe elbette, bazı parametreleri zorunlu, bazılarını varsayılan değerli, bazılarını da tamamen isteğe bağlı olarak tanımlayabilirsiniz:\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\nBu durumda, 3 tane query parametresi vardır:\n\n* `needy`, zorunlu bir `str`.\n* `skip`, varsayılan değeri `0` olan bir `int`.\n* `limit`, isteğe bağlı bir `int`.\n\n/// tip | İpucu\n\n[Path Parametreleri](path-params.md#predefined-values) ile aynı şekilde `Enum`'ları da kullanabilirsiniz.\n\n///\n"
  },
  {
    "path": "docs/tr/docs/tutorial/request-files.md",
    "content": "# Request Dosyaları { #request-files }\n\nİstemcinin upload edeceği dosyaları `File` kullanarak tanımlayabilirsiniz.\n\n/// info | Bilgi\n\nUpload edilen dosyaları alabilmek için önce [`python-multipart`](https://github.com/Kludex/python-multipart) yükleyin.\n\nBir [virtual environment](../virtual-environments.md) oluşturduğunuzdan, aktive ettiğinizden ve ardından paketi yüklediğinizden emin olun. Örneğin:\n\n```console\n$ pip install python-multipart\n```\n\nBunun nedeni, upload edilen dosyaların \"form data\" olarak gönderilmesidir.\n\n///\n\n## `File` Import Edin { #import-file }\n\n`fastapi` içinden `File` ve `UploadFile` import edin:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## `File` Parametrelerini Tanımlayın { #define-file-parameters }\n\n`Body` veya `Form` için yaptığınız gibi dosya parametreleri oluşturun:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info | Bilgi\n\n`File`, doğrudan `Form`’dan türeyen bir sınıftır.\n\nAncak unutmayın: `fastapi` içinden `Query`, `Path`, `File` ve diğerlerini import ettiğinizde, bunlar aslında özel sınıflar döndüren fonksiyonlardır.\n\n///\n\n/// tip | İpucu\n\nFile body’leri tanımlamak için `File` kullanmanız gerekir; aksi halde parametreler query parametreleri veya body (JSON) parametreleri olarak yorumlanır.\n\n///\n\nDosyalar \"form data\" olarak upload edilir.\n\n*path operation function* parametrenizin tipini `bytes` olarak tanımlarsanız, **FastAPI** dosyayı sizin için okur ve içeriği `bytes` olarak alırsınız.\n\nBunun, dosyanın tüm içeriğinin bellekte tutulacağı anlamına geldiğini unutmayın. Küçük dosyalar için iyi çalışır.\n\nAncak bazı durumlarda `UploadFile` kullanmak size fayda sağlayabilir.\n\n## `UploadFile` ile Dosya Parametreleri { #file-parameters-with-uploadfile }\n\nTipi `UploadFile` olan bir dosya parametresi tanımlayın:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\n`UploadFile` kullanmanın `bytes`’a göre birkaç avantajı vardır:\n\n* Parametrenin varsayılan değerinde `File()` kullanmak zorunda değilsiniz.\n* \"Spooled\" bir dosya kullanır:\n    * Belirli bir maksimum boyuta kadar bellekte tutulan, bu limiti aşınca diske yazılan bir dosya.\n* Bu sayede görüntüler, videolar, büyük binary’ler vb. gibi büyük dosyalarda tüm belleği tüketmeden iyi çalışır.\n* Upload edilen dosyadan metadata alabilirsiniz.\n* [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) bir `async` arayüze sahiptir.\n* [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) nesnesini dışa açar; bunu, file-like nesne bekleyen diğer library’lere doğrudan geçebilirsiniz.\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` şu attribute’lara sahiptir:\n\n* `filename`: Upload edilen orijinal dosya adını içeren bir `str` (örn. `myimage.jpg`).\n* `content_type`: Content type’ı (MIME type / media type) içeren bir `str` (örn. `image/jpeg`).\n* `file`: Bir [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) (bir [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) nesne). Bu, \"file-like\" nesne bekleyen diğer fonksiyonlara veya library’lere doğrudan verebileceğiniz gerçek Python file nesnesidir.\n\n`UploadFile` şu `async` method’lara sahiptir. Bunların hepsi altta ilgili dosya method’larını çağırır (dahili `SpooledTemporaryFile` kullanarak).\n\n* `write(data)`: Dosyaya `data` (`str` veya `bytes`) yazar.\n* `read(size)`: Dosyadan `size` (`int`) kadar byte/karakter okur.\n* `seek(offset)`: Dosyada `offset` (`int`) byte pozisyonuna gider.\n    * Örn. `await myfile.seek(0)` dosyanın başına gider.\n    * Bu, özellikle bir kez `await myfile.read()` çalıştırdıysanız ve sonra içeriği yeniden okumaya ihtiyaç duyuyorsanız faydalıdır.\n* `close()`: Dosyayı kapatır.\n\nBu method’ların hepsi `async` olduğundan, bunları \"await\" etmeniz gerekir.\n\nÖrneğin, bir `async` *path operation function* içinde içeriği şöyle alabilirsiniz:\n\n```Python\ncontents = await myfile.read()\n```\n\nNormal bir `def` *path operation function* içindeyseniz `UploadFile.file`’a doğrudan erişebilirsiniz, örneğin:\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | `async` Teknik Detaylar\n\n`async` method’ları kullandığınızda, **FastAPI** dosya method’larını bir threadpool içinde çalıştırır ve bunları await eder.\n\n///\n\n/// note | Starlette Teknik Detaylar\n\n**FastAPI**’nin `UploadFile`’ı doğrudan **Starlette**’in `UploadFile`’ından türetilmiştir; ancak **Pydantic** ve FastAPI’nin diğer parçalarıyla uyumlu olması için bazı gerekli eklemeler yapar.\n\n///\n\n## \"Form Data\" Nedir { #what-is-form-data }\n\nHTML formları (`<form></form>`) veriyi server’a gönderirken normalde JSON’dan farklı, veri için \"özel\" bir encoding kullanır.\n\n**FastAPI**, JSON yerine bu veriyi doğru yerden okuyacağından emin olur.\n\n/// note | Teknik Detaylar\n\nFormlardan gelen veri, dosya içermiyorsa normalde \"media type\" olarak `application/x-www-form-urlencoded` ile encode edilir.\n\nAncak form dosya içeriyorsa `multipart/form-data` olarak encode edilir. `File` kullanırsanız, **FastAPI** dosyaları body’nin doğru kısmından alması gerektiğini bilir.\n\nBu encoding’ler ve form alanları hakkında daha fazla okumak isterseniz [<abbr title=\"Mozilla Developer Network - Mozilla Geliştirici Ağı\">MDN</abbr> web dokümanlarındaki `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) sayfasına bakın.\n\n///\n\n/// warning | Uyarı\n\nBir *path operation* içinde birden fazla `File` ve `Form` parametresi tanımlayabilirsiniz, ancak JSON olarak almayı beklediğiniz `Body` alanlarını ayrıca tanımlayamazsınız; çünkü request body `application/json` yerine `multipart/form-data` ile encode edilmiş olur.\n\nBu, **FastAPI**’nin bir kısıtı değildir; HTTP protocol’ünün bir parçasıdır.\n\n///\n\n## Opsiyonel Dosya Upload { #optional-file-upload }\n\nStandart type annotation’ları kullanıp varsayılan değeri `None` yaparak bir dosyayı opsiyonel hale getirebilirsiniz:\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## Ek Metadata ile `UploadFile` { #uploadfile-with-additional-metadata }\n\nEk metadata ayarlamak için `UploadFile` ile birlikte `File()` da kullanabilirsiniz. Örneğin:\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## Birden Fazla Dosya Upload { #multiple-file-uploads }\n\nAynı anda birden fazla dosya upload etmek mümkündür.\n\nBu dosyalar, \"form data\" ile gönderilen aynı \"form field\" ile ilişkilendirilir.\n\nBunu kullanmak için `bytes` veya `UploadFile` listesini tanımlayın:\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\nTanımladığınız gibi, `bytes` veya `UploadFile`’lardan oluşan bir `list` alırsınız.\n\n/// note | Teknik Detaylar\n\n`from starlette.responses import HTMLResponse` da kullanabilirsiniz.\n\n**FastAPI**, geliştiriciye kolaylık olsun diye `starlette.responses` modülünü `fastapi.responses` olarak da sağlar. Ancak mevcut response’ların çoğu doğrudan Starlette’ten gelir.\n\n///\n\n### Ek Metadata ile Birden Fazla Dosya Upload { #multiple-file-uploads-with-additional-metadata }\n\nDaha önce olduğu gibi, `UploadFile` için bile ek parametreler ayarlamak amacıyla `File()` kullanabilirsiniz:\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## Özet { #recap }\n\nRequest’te (form data olarak gönderilen) upload edilecek dosyaları tanımlamak için `File`, `bytes` ve `UploadFile` kullanın.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/request-form-models.md",
    "content": "# Form Model'leri { #form-models }\n\nFastAPI'de **form field**'larını tanımlamak için **Pydantic model**'lerini kullanabilirsiniz.\n\n/// info | Bilgi\n\nForm'ları kullanmak için önce [`python-multipart`](https://github.com/Kludex/python-multipart)'ı yükleyin.\n\nBir [virtual environment](../virtual-environments.md) oluşturduğunuzdan, onu etkinleştirdiğinizden ve ardından paketi kurduğunuzdan emin olun. Örneğin:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note | Not\n\nBu özellik FastAPI `0.113.0` sürümünden itibaren desteklenmektedir. 🤓\n\n///\n\n## Form'lar için Pydantic Model'leri { #pydantic-models-for-forms }\n\nSadece, **form field** olarak almak istediğiniz alanlarla bir **Pydantic model** tanımlayın ve ardından parametreyi `Form` olarak bildirin:\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI**, request içindeki **form data**'dan **her bir field** için veriyi **çıkarır** ve size tanımladığınız Pydantic model'ini verir.\n\n## Dokümanları Kontrol Edin { #check-the-docs }\n\nBunu `/docs` altındaki doküman arayüzünde doğrulayabilirsiniz:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## Fazladan Form Field'larını Yasaklayın { #forbid-extra-form-fields }\n\nBazı özel kullanım senaryolarında (muhtemelen çok yaygın değildir), form field'larını yalnızca Pydantic model'inde tanımlananlarla **sınırlamak** isteyebilirsiniz. Ve **fazladan** gelen field'ları **yasaklayabilirsiniz**.\n\n/// note | Not\n\nBu özellik FastAPI `0.114.0` sürümünden itibaren desteklenmektedir. 🤓\n\n///\n\nHerhangi bir `extra` field'ı `forbid` etmek için Pydantic'in model konfigürasyonunu kullanabilirsiniz:\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\nBir client fazladan veri göndermeye çalışırsa, bir **error** response alır.\n\nÖrneğin, client şu form field'larını göndermeye çalışırsa:\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\n`extra` field'ının izinli olmadığını söyleyen bir error response alır:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## Özet { #summary }\n\nFastAPI'de form field'larını tanımlamak için Pydantic model'lerini kullanabilirsiniz. 😎\n"
  },
  {
    "path": "docs/tr/docs/tutorial/request-forms-and-files.md",
    "content": "# Request Formları ve Dosyalar { #request-forms-and-files }\n\n`File` ve `Form` kullanarak aynı anda hem dosyaları hem de form alanlarını tanımlayabilirsiniz.\n\n/// info | Bilgi\n\nYüklenen dosyaları ve/veya form verisini almak için önce [`python-multipart`](https://github.com/Kludex/python-multipart) paketini kurun.\n\nBir [sanal ortam](../virtual-environments.md) oluşturduğunuzdan, onu aktive ettiğinizden ve ardından paketi kurduğunuzdan emin olun, örneğin:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## `File` ve `Form` Import Edin { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## `File` ve `Form` Parametrelerini Tanımlayın { #define-file-and-form-parameters }\n\nDosya ve form parametrelerini, `Body` veya `Query` için yaptığınız şekilde oluşturun:\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\nDosyalar ve form alanları form data olarak upload edilir ve siz de dosyaları ve form alanlarını alırsınız.\n\nAyrıca bazı dosyaları `bytes` olarak, bazılarını da `UploadFile` olarak tanımlayabilirsiniz.\n\n/// warning | Uyarı\n\nBir *path operation* içinde birden fazla `File` ve `Form` parametresi tanımlayabilirsiniz; ancak request'in body'si `application/json` yerine `multipart/form-data` ile encode edileceği için, JSON olarak almayı beklediğiniz `Body` alanlarını aynı anda tanımlayamazsınız.\n\nBu **FastAPI** kısıtı değildir; HTTP protokolünün bir parçasıdır.\n\n///\n\n## Özet { #recap }\n\nAynı request içinde hem veri hem de dosya almanız gerektiğinde `File` ve `Form`'u birlikte kullanın.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/request-forms.md",
    "content": "# Form Verisi { #form-data }\n\nJSON yerine form alanlarını almanız gerektiğinde `Form` kullanabilirsiniz.\n\n/// info | Bilgi\n\nFormları kullanmak için önce [`python-multipart`](https://github.com/Kludex/python-multipart) paketini kurun.\n\nBir [virtual environment](../virtual-environments.md) oluşturduğunuzdan, onu etkinleştirdiğinizden emin olun ve ardından örneğin şöyle kurun:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## `Form`'u Import Edin { #import-form }\n\n`Form`'u `fastapi`'den import edin:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## `Form` Parametrelerini Tanımlayın { #define-form-parameters }\n\nForm parametrelerini `Body` veya `Query` için yaptığınız gibi oluşturun:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\nÖrneğin OAuth2 spesifikasyonunun kullanılabileceği (\"password flow\" olarak adlandırılan) yollardan birinde, form alanları olarak bir `username` ve `password` göndermek zorunludur.\n\n<dfn title=\"spesifikasyon\">Spesifikasyon</dfn>, alanların adının tam olarak `username` ve `password` olmasını ve JSON değil form alanları olarak gönderilmesini gerektirir.\n\n`Form` ile `Body` (ve `Query`, `Path`, `Cookie`) ile yaptığınız aynı konfigürasyonları tanımlayabilirsiniz; validasyon, örnekler, alias (örn. `username` yerine `user-name`) vb. dahil.\n\n/// info | Bilgi\n\n`Form`, doğrudan `Body`'den miras alan bir sınıftır.\n\n///\n\n/// tip | İpucu\n\nForm gövdelerini tanımlamak için `Form`'u açıkça kullanmanız gerekir; çünkü bunu yapmazsanız parametreler query parametreleri veya body (JSON) parametreleri olarak yorumlanır.\n\n///\n\n## \"Form Alanları\" Hakkında { #about-form-fields }\n\nHTML formlarının (`<form></form>`) verileri sunucuya gönderme şekli normalde bu veri için JSON'dan farklı \"özel\" bir encoding kullanır.\n\n**FastAPI** bu veriyi JSON yerine doğru yerden okuyacaktır.\n\n/// note | Teknik Detaylar\n\nFormlardan gelen veri normalde \"media type\" `application/x-www-form-urlencoded` kullanılarak encode edilir.\n\nAncak form dosyalar içerdiğinde `multipart/form-data` olarak encode edilir. Dosyaları ele almayı bir sonraki bölümde okuyacaksınız.\n\nBu encoding'ler ve form alanları hakkında daha fazla okumak isterseniz, [<abbr title=\"Mozilla Developer Network - Mozilla Geliştirici Ağı\">MDN</abbr> `POST` için web dokümanları](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST) sayfasına gidin.\n\n///\n\n/// warning | Uyarı\n\nBir *path operation* içinde birden fazla `Form` parametresi tanımlayabilirsiniz, ancak JSON olarak almayı beklediğiniz `Body` alanlarını da ayrıca tanımlayamazsınız; çünkü bu durumda request'in body'si `application/x-www-form-urlencoded` ile encode edilmiş olur.\n\nBu **FastAPI**'ın bir kısıtlaması değildir, HTTP protokolünün bir parçasıdır.\n\n///\n\n## Özet { #recap }\n\nForm verisi girdi parametrelerini tanımlamak için `Form` kullanın.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/response-model.md",
    "content": "# Response Model - Dönüş Tipi { #response-model-return-type }\n\n*Path operation function* **dönüş tipini** (return type) type annotation ile belirtip response için kullanılacak tipi tanımlayabilirsiniz.\n\nFonksiyon **parametreleri** için input data’da kullandığınız **type annotations** yaklaşımının aynısını burada da kullanabilirsiniz; Pydantic model’leri, list’ler, dict’ler, integer, boolean gibi skaler değerler vb.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPI bu dönüş tipini şunlar için kullanır:\n\n* Dönen veriyi **doğrulamak** (validate).\n    * Veri geçersizse (ör. bir field eksikse), bu *sizin* uygulama kodunuzun bozuk olduğu, olması gerekeni döndürmediği anlamına gelir; bu yüzden yanlış veri döndürmek yerine server error döner. Böylece siz ve client’larınız, beklenen veri ve veri şeklinin geleceğinden emin olabilirsiniz.\n* OpenAPI’deki *path operation* içine response için bir **JSON Schema** eklemek.\n    * Bu, **otomatik dokümantasyon** tarafından kullanılır.\n    * Ayrıca otomatik client code generation araçları tarafından da kullanılır.\n* Dönen veriyi Pydantic kullanarak JSON’a **serileştirmek**; Pydantic **Rust** ile yazıldığı için **çok daha hızlıdır**.\n\nAma en önemlisi:\n\n* Çıktı verisini, dönüş tipinde tanımlı olana göre **sınırlar ve filtreler**.\n    * Bu, özellikle **güvenlik** açısından önemlidir; aşağıda daha fazlasını göreceğiz.\n\n## `response_model` Parametresi { #response-model-parameter }\n\nBazı durumlarda, tam olarak dönüş tipinin söylediği gibi olmayan bir veriyi döndürmeniz gerekebilir ya da isteyebilirsiniz.\n\nÖrneğin, **bir dict** veya bir veritabanı objesi döndürmek isteyip, ama **onu bir Pydantic model olarak declare etmek** isteyebilirsiniz. Böylece Pydantic model, döndürdüğünüz obje (ör. dict veya veritabanı objesi) için dokümantasyon, doğrulama vb. işlerin tamamını yapar.\n\nEğer dönüş tipi annotation’ını eklerseniz, araçlar ve editörler (doğru şekilde) fonksiyonunuzun, declare ettiğiniz tipten (ör. Pydantic model) farklı bir tip (ör. dict) döndürdüğünü söyleyip hata verir.\n\nBu gibi durumlarda, dönüş tipi yerine *path operation decorator* parametresi olan `response_model`’i kullanabilirsiniz.\n\n`response_model` parametresini herhangi bir *path operation* içinde kullanabilirsiniz:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* vb.\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | Not\n\n`response_model`’in \"decorator\" metodunun (`get`, `post` vb.) bir parametresi olduğuna dikkat edin. Body ve diğer parametreler gibi, sizin *path operation function*’ınızın parametresi değildir.\n\n///\n\n`response_model`, Pydantic model field’ı için declare edeceğiniz aynı tipi alır; yani bir Pydantic model olabilir ama örneğin `List[Item]` gibi Pydantic model’lerden oluşan bir `list` de olabilir.\n\nFastAPI bu `response_model`’i; dokümantasyon, doğrulama vb. her şey için ve ayrıca çıktı verisini **tip tanımına göre dönüştürmek ve filtrelemek** için kullanır.\n\n/// tip | İpucu\n\nEditörünüzde, mypy vb. ile sıkı type kontrolü yapıyorsanız, fonksiyon dönüş tipini `Any` olarak declare edebilirsiniz.\n\nBöylece editöre bilerek her şeyi döndürebileceğinizi söylemiş olursunuz. Ancak FastAPI, `response_model` ile dokümantasyon, doğrulama, filtreleme vb. işlemleri yine de yapar.\n\n///\n\n### `response_model` Önceliği { #response-model-priority }\n\nHem dönüş tipi hem de `response_model` declare ederseniz, FastAPI’de `response_model` önceliklidir ve o kullanılır.\n\nBöylece, response model’den farklı bir tip döndürdüğünüz durumlarda bile editör ve mypy gibi araçlar için fonksiyonlarınıza doğru type annotation’lar ekleyebilir, aynı zamanda FastAPI’nin `response_model` üzerinden veri doğrulama, dokümantasyon vb. yapmasını sağlayabilirsiniz.\n\nAyrıca `response_model=None` kullanarak, ilgili *path operation* için response model oluşturulmasını devre dışı bırakabilirsiniz. Bu, Pydantic field’ı olarak geçerli olmayan şeyler için type annotation eklediğinizde gerekebilir; aşağıdaki bölümlerden birinde bunun örneğini göreceksiniz.\n\n## Aynı input verisini geri döndürmek { #return-the-same-input-data }\n\nBurada `UserIn` adında bir model declare ediyoruz; bu model plaintext bir password içerecek:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | Bilgi\n\n`EmailStr` kullanmak için önce [`email-validator`](https://github.com/JoshData/python-email-validator) paketini kurun.\n\nBir [virtual environment](../virtual-environments.md) oluşturduğunuzdan, onu aktive ettiğinizden emin olun ve ardından örneğin şöyle kurun:\n\n```console\n$ pip install email-validator\n```\n\nveya şöyle:\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\nBu model ile hem input’u declare ediyoruz hem de output’u aynı model ile declare ediyoruz:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\nArtık bir browser password ile user oluşturduğunda, API response içinde aynı password’ü geri döndürecek.\n\nBu örnekte sorun olmayabilir; çünkü password’ü gönderen kullanıcı zaten aynı kişi.\n\nAncak aynı modeli başka bir *path operation* için kullanırsak, kullanıcının password’lerini her client’a gönderiyor olabiliriz.\n\n/// danger\n\nTüm riskleri bildiğinizden ve ne yaptığınızdan emin olmadığınız sürece, bir kullanıcının plain password’ünü asla saklamayın ve bu şekilde response içinde göndermeyin.\n\n///\n\n## Bir output modeli ekleyin { #add-an-output-model }\n\nBunun yerine, plaintext password içeren bir input modeli ve password’ü içermeyen bir output modeli oluşturabiliriz:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\nBurada *path operation function* password içeren aynı input user’ı döndürüyor olsa bile:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n...`response_model` olarak, password’ü içermeyen `UserOut` modelimizi declare ettik:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\nDolayısıyla **FastAPI**, output model’de declare edilmemiş tüm verileri (Pydantic kullanarak) filtrelemekle ilgilenir.\n\n### `response_model` mi Return Type mı? { #response-model-or-return-type }\n\nBu durumda iki model farklı olduğu için fonksiyon dönüş tipini `UserOut` olarak annotate etseydik, editör ve araçlar farklı class’lar olduğu için geçersiz bir tip döndürdüğümüzü söyleyip hata verecekti.\n\nBu yüzden bu örnekte `response_model` parametresinde declare etmek zorundayız.\n\n...ama bunu nasıl aşabileceğinizi görmek için aşağıyı okumaya devam edin.\n\n## Return Type ve Veri Filtreleme { #return-type-and-data-filtering }\n\nÖnceki örnekten devam edelim. Fonksiyonu **tek bir tip ile annotate etmek** istiyoruz; ama fonksiyondan gerçekte **daha fazla veri** içeren bir şey döndürebilmek istiyoruz.\n\nFastAPI’nin response model’i kullanarak veriyi **filtrelemeye** devam etmesini istiyoruz. Yani fonksiyon daha fazla veri döndürse bile response, sadece response model’de declare edilmiş field’ları içersin.\n\nÖnceki örnekte class’lar farklı olduğu için `response_model` parametresini kullanmak zorundaydık. Ancak bu, editör ve araçların fonksiyon dönüş tipi kontrolünden gelen desteğini alamadığımız anlamına da geliyor.\n\nAma bu tarz durumların çoğunda modelin amacı, bu örnekteki gibi bazı verileri **filtrelemek/kaldırmak** olur.\n\nBu gibi durumlarda class’lar ve inheritance kullanarak, fonksiyon **type annotations** sayesinde editör ve araçlarda daha iyi destek alabilir, aynı zamanda FastAPI’nin **veri filtrelemesini** de koruyabiliriz.\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\nBununla birlikte, code type’lar açısından doğru olduğu için editörler ve mypy araç desteği verir; ayrıca FastAPI’den veri filtrelemeyi de alırız.\n\nBu nasıl çalışıyor? Bir bakalım. 🤓\n\n### Type Annotations ve Araç Desteği { #type-annotations-and-tooling }\n\nÖnce editörler, mypy ve diğer araçlar bunu nasıl görür, ona bakalım.\n\n`BaseUser` temel field’lara sahiptir. Ardından `UserIn`, `BaseUser`’dan miras alır ve `password` field’ını ekler; yani iki modelin field’larının tamamını içerir.\n\nFonksiyonun dönüş tipini `BaseUser` olarak annotate ediyoruz ama gerçekte bir `UserIn` instance’ı döndürüyoruz.\n\nEditör, mypy ve diğer araçlar buna itiraz etmez; çünkü typing açısından `UserIn`, `BaseUser`’ın subclass’ıdır. Bu da, bir `BaseUser` bekleniyorken `UserIn`’in *geçerli* bir tip olduğu anlamına gelir.\n\n### FastAPI Veri Filtreleme { #fastapi-data-filtering }\n\nFastAPI açısından ise dönüş tipini görür ve döndürdüğünüz şeyin **yalnızca** tipte declare edilen field’ları içerdiğinden emin olur.\n\nFastAPI, Pydantic ile içeride birkaç işlem yapar; böylece class inheritance kurallarının dönen veri filtrelemede aynen kullanılmasına izin vermez. Aksi halde beklediğinizden çok daha fazla veriyi response’ta döndürebilirdiniz.\n\nBu sayede iki dünyanın da en iyisini alırsınız: **araç desteği** veren type annotations ve **veri filtreleme**.\n\n## Dokümanlarda görün { #see-it-in-the-docs }\n\nOtomatik dokümanları gördüğünüzde, input model ve output model’in her birinin kendi JSON Schema’sına sahip olduğunu kontrol edebilirsiniz:\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\nVe her iki model de etkileşimli API dokümantasyonunda kullanılır:\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## Diğer Return Type Annotation’ları { #other-return-type-annotations }\n\nBazı durumlarda Pydantic field olarak geçerli olmayan bir şey döndürebilir ve bunu fonksiyonda annotate edebilirsiniz; amaç sadece araçların (editör, mypy vb.) sağladığı desteği almaktır.\n\n### Doğrudan Response Döndürmek { #return-a-response-directly }\n\nEn yaygın durum, [ileri seviye dokümanlarda daha sonra anlatıldığı gibi doğrudan bir Response döndürmektir](../advanced/response-directly.md).\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\nBu basit durum FastAPI tarafından otomatik olarak ele alınır; çünkü dönüş tipi annotation’ı `Response` class’ıdır (veya onun bir subclass’ı).\n\nAraçlar da memnun olur; çünkü hem `RedirectResponse` hem `JSONResponse`, `Response`’un subclass’ıdır. Yani type annotation doğrudur.\n\n### Bir Response Subclass’ını Annotate Etmek { #annotate-a-response-subclass }\n\nType annotation içinde `Response`’un bir subclass’ını da kullanabilirsiniz:\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\nBu da çalışır; çünkü `RedirectResponse`, `Response`’un subclass’ıdır ve FastAPI bu basit durumu otomatik olarak yönetir.\n\n### Geçersiz Return Type Annotation’ları { #invalid-return-type-annotations }\n\nAncak geçerli bir Pydantic tipi olmayan başka rastgele bir obje (ör. bir veritabanı objesi) döndürür ve fonksiyonu da öyle annotate ederseniz, FastAPI bu type annotation’dan bir Pydantic response model oluşturmaya çalışır ve başarısız olur.\n\nAynı şey, farklı tipler arasında bir <dfn title=\"Birden fazla tip arasındaki bir birleşim, 'bu tiplerden herhangi biri' anlamına gelir.\">birleşim</dfn> kullandığınızda ve bu tiplerden biri veya birkaçı geçerli bir Pydantic tipi değilse de olur; örneğin şu kullanım patlar 💥:\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n...bu, type annotation Pydantic tipi olmadığı ve tek bir `Response` class’ı (veya subclass’ı) olmadığı için başarısız olur; bu, bir `Response` ile bir `dict` arasında union’dır (ikiden herhangi biri).\n\n### Response Model’i Devre Dışı Bırakmak { #disable-response-model }\n\nYukarıdaki örnekten devam edersek; FastAPI’nin varsayılan olarak yaptığı veri doğrulama, dokümantasyon, filtreleme vb. işlemleri istemiyor olabilirsiniz.\n\nAncak yine de editörler ve type checker’lar (ör. mypy) gibi araçların desteğini almak için fonksiyonda dönüş tipi annotation’ını korumak isteyebilirsiniz.\n\nBu durumda `response_model=None` ayarlayarak response model üretimini devre dışı bırakabilirsiniz:\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\nBu, FastAPI’nin response model üretimini atlamasını sağlar; böylece FastAPI uygulamanızı etkilemeden ihtiyacınız olan herhangi bir return type annotation’ını kullanabilirsiniz. 🤓\n\n## Response Model encoding parametreleri { #response-model-encoding-parameters }\n\nResponse model’inizde şu şekilde default değerler olabilir:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None` (veya Python 3.10’da `str | None = None`) için default `None`’dır.\n* `tax: float = 10.5` için default `10.5`’tir.\n* `tags: List[str] = []` için default, boş bir list’tir: `[]`.\n\nAncak gerçekte kaydedilmedilerse, bunları sonuçtan çıkarmak isteyebilirsiniz.\n\nÖrneğin NoSQL veritabanında çok sayıda optional attribute içeren modelleriniz varsa, default değerlerle dolu çok uzun JSON response’ları göndermek istemeyebilirsiniz.\n\n### `response_model_exclude_unset` parametresini kullanın { #use-the-response-model-exclude-unset-parameter }\n\n*Path operation decorator* parametresi olarak `response_model_exclude_unset=True` ayarlayabilirsiniz:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\nböylece response’a default değerler dahil edilmez; yalnızca gerçekten set edilmiş değerler gelir.\n\nDolayısıyla ID’si `foo` olan item için bu *path operation*’a request atarsanız, response (default değerler olmadan) şöyle olur:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | Bilgi\n\nAyrıca şunları da kullanabilirsiniz:\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\nBunlar, `exclude_defaults` ve `exclude_none` için [Pydantic dokümanlarında](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict) anlatıldığı gibidir.\n\n///\n\n#### Default’u olan field’lar için değer içeren data { #data-with-values-for-fields-with-defaults }\n\nAma data’nız modelde default değeri olan field’lar için değer içeriyorsa, örneğin ID’si `bar` olan item gibi:\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\nbunlar response’a dahil edilir.\n\n#### Default değerlerle aynı değerlere sahip data { #data-with-the-same-values-as-the-defaults }\n\nEğer data, default değerlerle aynı değerlere sahipse, örneğin ID’si `baz` olan item gibi:\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nFastAPI yeterince akıllıdır (aslında Pydantic yeterince akıllıdır) ve `description`, `tax`, `tags` default ile aynı olsa bile bunların explicit olarak set edildiğini (default’tan alınmadığını) anlar.\n\nBu yüzden JSON response içinde yer alırlar.\n\n/// tip | İpucu\n\nDefault değerlerin yalnızca `None` olmak zorunda olmadığını unutmayın.\n\nBir list (`[]`), `10.5` gibi bir `float` vb. olabilirler.\n\n///\n\n### `response_model_include` ve `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\nAyrıca *path operation decorator* parametreleri `response_model_include` ve `response_model_exclude`’u da kullanabilirsiniz.\n\nBunlar; dahil edilecek attribute isimlerini (geri kalanını atlayarak) ya da hariç tutulacak attribute isimlerini (geri kalanını dahil ederek) belirten `str` değerlerinden oluşan bir `set` alır.\n\nTek bir Pydantic model’iniz varsa ve output’tan bazı verileri hızlıca çıkarmak istiyorsanız, bu yöntem pratik bir kısayol olabilir.\n\n/// tip | İpucu\n\nAncak yine de, bu parametreler yerine yukarıdaki yaklaşımı (birden fazla class kullanmayı) tercih etmeniz önerilir.\n\nÇünkü `response_model_include` veya `response_model_exclude` ile bazı attribute’ları atlıyor olsanız bile, uygulamanızın OpenAPI’sinde (ve dokümanlarda) üretilen JSON Schema hâlâ tam modelin JSON Schema’sı olacaktır.\n\nBu durum, benzer şekilde çalışan `response_model_by_alias` için de geçerlidir.\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | İpucu\n\n`{\"name\", \"description\"}` sözdizimi, bu iki değere sahip bir `set` oluşturur.\n\nBu, `set([\"name\", \"description\"])` ile eşdeğerdir.\n\n///\n\n#### `set` yerine `list` kullanmak { #using-lists-instead-of-sets }\n\nYanlışlıkla `set` yerine `list` veya `tuple` kullanırsanız, FastAPI bunu yine `set`’e çevirir ve doğru şekilde çalışır:\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## Özet { #recap }\n\nResponse model’leri tanımlamak ve özellikle private data’nın filtrelendiğinden emin olmak için *path operation decorator* parametresi `response_model`’i kullanın.\n\nYalnızca explicit olarak set edilmiş değerleri döndürmek için `response_model_exclude_unset` kullanın.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/response-status-code.md",
    "content": "# Response Status Code { #response-status-code }\n\nBir response model tanımlayabildiğiniz gibi, herhangi bir *path operation* içinde `status_code` parametresiyle response için kullanılacak HTTP status code'u da belirtebilirsiniz:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* vb.\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | Not\n\n`status_code`'un, \"decorator\" metodunun (`get`, `post`, vb.) bir parametresi olduğuna dikkat edin. Tüm parametreler ve body gibi, sizin *path operation function*'ınızın bir parametresi değildir.\n\n///\n\n`status_code` parametresi, HTTP status code'u içeren bir sayı alır.\n\n/// info | Bilgi\n\nAlternatif olarak `status_code`, Python'un [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus)'ı gibi bir `IntEnum` da alabilir.\n\n///\n\nBu sayede:\n\n* Response'da o status code döner.\n* OpenAPI şemasında (dolayısıyla kullanıcı arayüzlerinde de) bu şekilde dokümante edilir:\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | Not\n\nBazı response code'lar (bir sonraki bölümde göreceğiz) response'un bir body'ye sahip olmadığını belirtir.\n\nFastAPI bunu bilir ve response body olmadığını söyleyen OpenAPI dokümantasyonunu üretir.\n\n///\n\n## HTTP status code'lar hakkında { #about-http-status-codes }\n\n/// note | Not\n\nHTTP status code'ların ne olduğunu zaten biliyorsanız, bir sonraki bölüme geçin.\n\n///\n\nHTTP'de, response'un bir parçası olarak 3 basamaklı sayısal bir status code gönderirsiniz.\n\nBu status code'ların tanınmalarını sağlayan bir isimleri de vardır; ancak önemli olan kısım sayıdır.\n\nKısaca:\n\n* `100 - 199` \"Information\" içindir. Doğrudan nadiren kullanırsınız. Bu status code'lara sahip response'lar body içeremez.\n* **`200 - 299`** \"Successful\" response'lar içindir. En sık kullanacağınız aralık budur.\n    * `200`, varsayılan status code'dur ve her şeyin \"OK\" olduğunu ifade eder.\n    * Başka bir örnek `201` (\"Created\") olabilir. Genellikle veritabanında yeni bir kayıt oluşturduktan sonra kullanılır.\n    * Özel bir durum ise `204` (\"No Content\")'tür. Client'a döndürülecek içerik olmadığında kullanılır; bu nedenle response body olmamalıdır.\n* **`300 - 399`** \"Redirection\" içindir. Bu status code'lara sahip response'lar, `304` (\"Not Modified\") hariç, body içerebilir de içermeyebilir de; `304` kesinlikle body içermemelidir.\n* **`400 - 499`** \"Client error\" response'ları içindir. Muhtemelen en sık kullanacağınız ikinci aralık budur.\n    * Örneğin `404`, \"Not Found\" response'u içindir.\n    * Client kaynaklı genel hatalar için doğrudan `400` kullanabilirsiniz.\n* `500 - 599` server hataları içindir. Neredeyse hiç doğrudan kullanmazsınız. Uygulama kodunuzun bir bölümünde ya da server'da bir şeyler ters giderse, otomatik olarak bu status code'lardan biri döner.\n\n/// tip | İpucu\n\nHer bir status code hakkında daha fazla bilgi almak ve hangi kodun ne için kullanıldığını görmek için [<abbr title=\"Mozilla Developer Network - Mozilla Geliştirici Ağı\">MDN</abbr> dokümantasyonu: HTTP status code'lar hakkında](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)'na göz atın.\n\n///\n\n## İsimleri hatırlamak için kısayol { #shortcut-to-remember-the-names }\n\nÖnceki örneğe tekrar bakalım:\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201`, \"Created\" için kullanılan status code'dur.\n\nAncak bu kodların her birinin ne anlama geldiğini ezberlemek zorunda değilsiniz.\n\n`fastapi.status` içindeki kolaylık değişkenlerini (convenience variables) kullanabilirsiniz.\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\nBunlar sadece kolaylık sağlar; aynı sayıyı taşırlar. Ancak bu şekilde editörün autocomplete özelliğiyle kolayca bulabilirsiniz:\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | Teknik Detaylar\n\n`from starlette import status` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.status`'u `fastapi.status` olarak da sunar. Ancak bu aslında doğrudan Starlette'den gelir.\n\n///\n\n## Varsayılanı değiştirmek { #changing-the-default }\n\nDaha sonra, [İleri Düzey Kullanıcı Kılavuzu](../advanced/response-change-status-code.md) içinde, burada tanımladığınız varsayılanın dışında farklı bir status code nasıl döndüreceğinizi göreceksiniz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/schema-extra-example.md",
    "content": "# Request Örnek Verilerini Tanımlama { #declare-request-example-data }\n\nUygulamanızın alabileceği veriler için örnekler (examples) tanımlayabilirsiniz.\n\nBunu yapmanın birkaç yolu var.\n\n## Pydantic modellerinde ek JSON Schema verisi { #extra-json-schema-data-in-pydantic-models }\n\nOluşturulan JSON Schema’ya eklenecek şekilde bir Pydantic model için `examples` tanımlayabilirsiniz.\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\nBu ek bilgi, o modelin çıktı **JSON Schema**’sına olduğu gibi eklenir ve API dokümanlarında kullanılır.\n\n[Pydantic dokümanları: Configuration](https://docs.pydantic.dev/latest/api/config/) bölümünde anlatıldığı gibi, bir `dict` alan `model_config` niteliğini kullanabilirsiniz.\n\nÜretilen JSON Schema’da görünmesini istediğiniz (ör. `examples` dahil) her türlü ek veriyi içeren bir `dict` ile `\"json_schema_extra\"` ayarlayabilirsiniz.\n\n/// tip | İpucu\n\nAynı tekniği JSON Schema’yı genişletmek ve kendi özel ek bilgilerinizi eklemek için de kullanabilirsiniz.\n\nÖrneğin, bir frontend kullanıcı arayüzü için metadata eklemek vb. amaçlarla kullanılabilir.\n\n///\n\n/// info | Bilgi\n\nOpenAPI 3.1.0 (FastAPI 0.99.0’dan beri kullanılıyor), **JSON Schema** standardının bir parçası olan `examples` için destek ekledi.\n\nBundan önce yalnızca tek bir örnek için `example` anahtar kelimesini destekliyordu. Bu hâlâ OpenAPI 3.1.0 tarafından desteklenir; ancak artık deprecated durumdadır ve JSON Schema standardının parçası değildir. Bu nedenle `example` kullanımını `examples`’a taşımanız önerilir. 🤓\n\nDaha fazlasını sayfanın sonunda okuyabilirsiniz.\n\n///\n\n## `Field` ek argümanları { #field-additional-arguments }\n\nPydantic modelleriyle `Field()` kullanırken ek `examples` de tanımlayabilirsiniz:\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## JSON Schema - OpenAPI içinde `examples` { #examples-in-json-schema-openapi }\n\nAşağıdakilerden herhangi birini kullanırken:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nOpenAPI içindeki **JSON Schema**’larına eklenecek ek bilgilerle birlikte bir `examples` grubu da tanımlayabilirsiniz.\n\n### `examples` ile `Body` { #body-with-examples }\n\nBurada `Body()` içinde beklenen veri için tek bir örnek içeren `examples` geçiriyoruz:\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### Doküman arayüzünde örnek { #example-in-the-docs-ui }\n\nYukarıdaki yöntemlerden herhangi biriyle `/docs` içinde şöyle görünür:\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### Birden fazla `examples` ile `Body` { #body-with-multiple-examples }\n\nElbette birden fazla `examples` da geçebilirsiniz:\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\nBunu yaptığınızda, örnekler bu body verisi için dahili **JSON Schema**’nın bir parçası olur.\n\nBuna rağmen, <dfn title=\"2023-08-26\">bu yazı yazılırken</dfn>, doküman arayüzünü gösteren araç olan Swagger UI, **JSON Schema** içindeki veriler için birden fazla örneği göstermeyi desteklemiyor. Ancak aşağıda bir çözüm yolu var.\n\n### OpenAPI’ye özel `examples` { #openapi-specific-examples }\n\n**JSON Schema** `examples`’ı desteklemeden önce OpenAPI, yine `examples` adlı farklı bir alanı destekliyordu.\n\nBu **OpenAPI’ye özel** `examples`, OpenAPI spesifikasyonunda başka bir bölümde yer alır. Her bir JSON Schema’nın içinde değil, **her bir *path operation* detayları** içinde bulunur.\n\nSwagger UI da bu özel `examples` alanını bir süredir destekliyor. Dolayısıyla bunu, **doküman arayüzünde** farklı **örnekleri göstermek** için kullanabilirsiniz.\n\nOpenAPI’ye özel bu `examples` alanının şekli, (bir `list` yerine) **birden fazla örnek** içeren bir `dict`’tir; her örnek ayrıca **OpenAPI**’ye eklenecek ekstra bilgiler içerir.\n\nBu, OpenAPI’nin içerdiği JSON Schema’ların içine girmez; bunun yerine doğrudan *path operation* üzerinde, dışarıda yer alır.\n\n### `openapi_examples` Parametresini Kullanma { #using-the-openapi-examples-parameter }\n\nFastAPI’de OpenAPI’ye özel `examples`’ı, şu araçlar için `openapi_examples` parametresiyle tanımlayabilirsiniz:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\n`dict`’in anahtarları her bir örneği tanımlar; her bir değer ise başka bir `dict`’tir.\n\n`examples` içindeki her bir örnek `dict`’i şunları içerebilir:\n\n* `summary`: Örnek için kısa açıklama.\n* `description`: Markdown metni içerebilen uzun açıklama.\n* `value`: Gösterilecek gerçek örnek (ör. bir `dict`).\n* `externalValue`: `value`’a alternatif; örneğe işaret eden bir URL. Ancak bu, `value` kadar çok araç tarafından desteklenmiyor olabilir.\n\nŞöyle kullanabilirsiniz:\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### Doküman Arayüzünde OpenAPI Örnekleri { #openapi-examples-in-the-docs-ui }\n\n`Body()`’ye `openapi_examples` eklendiğinde `/docs` şöyle görünür:\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## Teknik Detaylar { #technical-details }\n\n/// tip | İpucu\n\nZaten **FastAPI** sürümü **0.99.0 veya üzerini** kullanıyorsanız, büyük olasılıkla bu detayları **atlanabilirsiniz**.\n\nBunlar daha çok OpenAPI 3.1.0’ın henüz mevcut olmadığı eski sürümler için geçerlidir.\n\nBunu kısa bir OpenAPI ve JSON Schema **tarih dersi** gibi düşünebilirsiniz. 🤓\n\n///\n\n/// warning | Uyarı\n\nBunlar **JSON Schema** ve **OpenAPI** standartları hakkında oldukça teknik detaylardır.\n\nYukarıdaki fikirler sizin için zaten çalışıyorsa bu kadarı yeterli olabilir; muhtemelen bu detaylara ihtiyacınız yoktur, gönül rahatlığıyla atlayabilirsiniz.\n\n///\n\nOpenAPI 3.1.0’dan önce OpenAPI, **JSON Schema**’nın daha eski ve değiştirilmiş bir sürümünü kullanıyordu.\n\nJSON Schema’da `examples` yoktu; bu yüzden OpenAPI, değiştirilmiş sürümüne kendi `example` alanını ekledi.\n\nOpenAPI ayrıca spesifikasyonun diğer bölümlerine de `example` ve `examples` alanlarını ekledi:\n\n* [`Parameter Object` (spesifikasyonda)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object) — FastAPI’de şunlar tarafından kullanılıyordu:\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object`; `content` alanında, `Media Type Object` üzerinde (spesifikasyonda)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object) — FastAPI’de şunlar tarafından kullanılıyordu:\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info | Bilgi\n\nBu eski OpenAPI’ye özel `examples` parametresi, FastAPI `0.103.0` sürümünden beri `openapi_examples` olarak kullanılıyor.\n\n///\n\n### JSON Schema’nın `examples` alanı { #json-schemas-examples-field }\n\nSonrasında JSON Schema, spesifikasyonun yeni bir sürümüne [`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5) alanını ekledi.\n\nArdından yeni OpenAPI 3.1.0, bu yeni `examples` alanını içeren en güncel sürümü (JSON Schema 2020-12) temel aldı.\n\nVe artık, deprecated olan eski tekil (ve özel) `example` alanına kıyasla bu yeni `examples` alanı önceliklidir.\n\nJSON Schema’daki bu yeni `examples` alanı, OpenAPI’de başka yerlerde kullanılan (yukarıda anlatılan) metadata’lı `dict` yapısından farklı olarak **sadece örneklerden oluşan bir `list`**’tir.\n\n/// info | Bilgi\n\nOpenAPI 3.1.0, JSON Schema ile bu yeni ve daha basit entegrasyonla yayımlandıktan sonra bile bir süre, otomatik dokümantasyonu sağlayan araç Swagger UI OpenAPI 3.1.0’ı desteklemiyordu (5.0.0 sürümünden beri destekliyor 🎉).\n\nBu nedenle, FastAPI’nin 0.99.0 öncesi sürümleri OpenAPI 3.1.0’dan daha düşük sürümleri kullanmaya devam etti.\n\n///\n\n### Pydantic ve FastAPI `examples` { #pydantic-and-fastapi-examples }\n\nBir Pydantic modelinin içine `schema_extra` ya da `Field(examples=[\"something\"])` kullanarak `examples` eklediğinizde, bu örnek o Pydantic modelinin **JSON Schema**’sına eklenir.\n\nVe Pydantic modelinin bu **JSON Schema**’sı, API’nizin **OpenAPI**’sine dahil edilir; ardından doküman arayüzünde kullanılır.\n\nFastAPI 0.99.0’dan önceki sürümlerde (0.99.0 ve üzeri daha yeni OpenAPI 3.1.0’ı kullanır) `Query()`, `Body()` vb. diğer araçlarla `example` veya `examples` kullandığınızda, bu örnekler o veriyi tanımlayan JSON Schema’ya (OpenAPI’nin kendi JSON Schema sürümüne bile) eklenmiyordu; bunun yerine doğrudan OpenAPI’deki *path operation* tanımına ekleniyordu (JSON Schema kullanan OpenAPI bölümlerinin dışında).\n\nAncak artık FastAPI 0.99.0 ve üzeri OpenAPI 3.1.0 kullandığı (JSON Schema 2020-12) ve Swagger UI 5.0.0 ve üzeriyle birlikte, her şey daha tutarlı ve örnekler JSON Schema’ya dahil ediliyor.\n\n### Swagger UI ve OpenAPI’ye özel `examples` { #swagger-ui-and-openapi-specific-examples }\n\nSwagger UI (2023-08-26 itibarıyla) birden fazla JSON Schema örneğini desteklemediği için, kullanıcıların dokümanlarda birden fazla örnek göstermesi mümkün değildi.\n\nBunu çözmek için FastAPI `0.103.0`, yeni `openapi_examples` parametresiyle aynı eski **OpenAPI’ye özel** `examples` alanını tanımlamayı **desteklemeye başladı**. 🤓\n\n### Özet { #summary }\n\nEskiden tarihten pek hoşlanmadığımı söylerdim... şimdi bakın, \"teknoloji tarihi\" dersi anlatıyorum. 😅\n\nKısacası, **FastAPI 0.99.0 veya üzerine yükseltin**; her şey çok daha **basit, tutarlı ve sezgisel** olur ve bu tarihsel detayların hiçbirini bilmeniz gerekmez. 😎\n"
  },
  {
    "path": "docs/tr/docs/tutorial/security/first-steps.md",
    "content": "# Güvenlik - İlk Adımlar { #security-first-steps }\n\n**backend** API’nizin bir domain’de olduğunu düşünelim.\n\nVe başka bir domain’de ya da aynı domain’in farklı bir path’inde (veya bir mobil uygulamada) bir **frontend**’iniz var.\n\nVe frontend’in, **username** ve **password** kullanarak backend ile kimlik doğrulaması yapabilmesini istiyorsunuz.\n\nBunu **FastAPI** ile **OAuth2** kullanarak oluşturabiliriz.\n\nAma ihtiyacınız olan küçük bilgi parçalarını bulmak için uzun spesifikasyonun tamamını okuma zahmetine girmeyelim.\n\nGüvenliği yönetmek için **FastAPI**’nin sunduğu araçları kullanalım.\n\n## Nasıl Görünüyor { #how-it-looks }\n\nÖnce kodu kullanıp nasıl çalıştığına bakalım, sonra neler olup bittiğini anlamak için geri döneriz.\n\n## `main.py` Oluşturun { #create-main-py }\n\nÖrneği `main.py` adlı bir dosyaya kopyalayın:\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## Çalıştırın { #run-it }\n\n/// info | Bilgi\n\nThe [`python-multipart`](https://github.com/Kludex/python-multipart) paketi, `pip install \"fastapi[standard]\"` komutunu çalıştırdığınızda **FastAPI** ile birlikte otomatik olarak kurulur.\n\nAncak `pip install fastapi` komutunu kullanırsanız, `python-multipart` paketi varsayılan olarak dahil edilmez.\n\nElle kurmak için bir [virtual environment](../../virtual-environments.md) oluşturduğunuzdan, onu aktive ettiğinizden emin olun ve ardından şununla kurun:\n\n```console\n$ pip install python-multipart\n```\n\nBunun nedeni, **OAuth2**’nin `username` ve `password` göndermek için \"form data\" kullanmasıdır.\n\n///\n\nÖrneği şu şekilde çalıştırın:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## Kontrol Edin { #check-it }\n\nEtkileşimli dokümantasyona gidin: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nŞuna benzer bir şey göreceksiniz:\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Authorize butonu!\n\nArtık parıl parıl yeni bir \"Authorize\" butonunuz var.\n\nAyrıca *path operation*’ınızın sağ üst köşesinde tıklayabileceğiniz küçük bir kilit simgesi de bulunuyor.\n\n///\n\nVe ona tıklarsanız, `username` ve `password` (ve diğer opsiyonel alanları) girebileceğiniz küçük bir yetkilendirme formu görürsünüz:\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | Not\n\nFormda ne yazdığınızın önemi yok; şimdilik çalışmayacak. Ama birazdan oraya da geleceğiz.\n\n///\n\nBu, elbette son kullanıcılar için bir frontend değil; ancak tüm API’nizi etkileşimli şekilde belgelemek için harika bir otomatik araçtır.\n\nFrontend ekibi tarafından kullanılabilir (bu ekip siz de olabilirsiniz).\n\nÜçüncü taraf uygulamalar ve sistemler tarafından kullanılabilir.\n\nVe aynı uygulamayı debug etmek, kontrol etmek ve test etmek için sizin tarafınızdan da kullanılabilir.\n\n## `password` Flow { #the-password-flow }\n\nŞimdi biraz geri dönüp bunların ne olduğuna bakalım.\n\n`password` \"flow\"u, OAuth2’de güvenlik ve authentication’ı yönetmek için tanımlanmış yöntemlerden (\"flow\"lardan) biridir.\n\nOAuth2, backend’in veya API’nin, kullanıcıyı authenticate eden server’dan bağımsız olabilmesi için tasarlanmıştır.\n\nAncak bu örnekte, aynı **FastAPI** uygulaması hem API’yi hem de authentication’ı yönetecek.\n\nO yüzden basitleştirilmiş bu bakış açısından üzerinden geçelim:\n\n* Kullanıcı frontend’de `username` ve `password` yazar ve `Enter`’a basar.\n* Frontend (kullanıcının browser’ında çalışır), bu `username` ve `password` değerlerini API’mizdeki belirli bir URL’ye gönderir (`tokenUrl=\"token\"` ile tanımlanan).\n* API, `username` ve `password` değerlerini kontrol eder ve bir \"token\" ile response döner (henüz bunların hiçbirini implement etmedik).\n    * \"Token\", daha sonra bu kullanıcıyı doğrulamak için kullanabileceğimiz içerik taşıyan bir string’dir.\n    * Normalde token’ın bir süre sonra süresi dolacak şekilde ayarlanması beklenir.\n        * Böylece kullanıcının bir noktada tekrar giriş yapması gerekir.\n        * Ayrıca token çalınırsa risk daha düşük olur. Çoğu durumda, sonsuza kadar çalışacak kalıcı bir anahtar gibi değildir.\n* Frontend bu token’ı geçici olarak bir yerde saklar.\n* Kullanıcı frontend’de tıklayarak web uygulamasının başka bir bölümüne gider.\n* Frontend’in API’den daha fazla veri alması gerekir.\n    * Ancak o endpoint için authentication gereklidir.\n    * Bu yüzden API’mizle authenticate olmak için `Authorization` header’ını, `Bearer ` + token değeriyle gönderir.\n    * Token `foobar` içeriyorsa `Authorization` header’ının içeriği `Bearer foobar` olur.\n\n## **FastAPI**’nin `OAuth2PasswordBearer`’ı { #fastapis-oauth2passwordbearer }\n\n**FastAPI**, bu güvenlik özelliklerini implement etmek için farklı soyutlama seviyelerinde çeşitli araçlar sağlar.\n\nBu örnekte **OAuth2**’yi, **Password** flow ile, **Bearer** token kullanarak uygulayacağız. Bunu `OAuth2PasswordBearer` sınıfı ile yaparız.\n\n/// info | Bilgi\n\n\"Bearer\" token tek seçenek değildir.\n\nAma bizim kullanım senaryomuz için en iyi seçenek odur.\n\nAyrıca bir OAuth2 uzmanı değilseniz ve ihtiyaçlarınıza daha uygun başka bir seçeneğin neden gerekli olduğunu net olarak bilmiyorsanız, çoğu kullanım senaryosu için de en uygun seçenek olacaktır.\n\nBu durumda bile **FastAPI**, onu oluşturabilmeniz için gereken araçları sunar.\n\n///\n\n`OAuth2PasswordBearer` sınıfının bir instance’ını oluştururken `tokenUrl` parametresini veririz. Bu parametre, client’ın (kullanıcının browser’ında çalışan frontend’in) token almak için `username` ve `password` göndereceği URL’yi içerir.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip | İpucu\n\nBurada `tokenUrl=\"token\"`, henüz oluşturmadığımız göreli bir URL olan `token`’ı ifade eder. Göreli URL olduğu için `./token` ile eşdeğerdir.\n\nGöreli URL kullandığımız için, API’niz `https://example.com/` adresinde olsaydı `https://example.com/token` anlamına gelirdi. Ama API’niz `https://example.com/api/v1/` adresinde olsaydı, bu kez `https://example.com/api/v1/token` anlamına gelirdi.\n\nGöreli URL kullanmak, [Behind a Proxy](../../advanced/behind-a-proxy.md) gibi daha ileri kullanım senaryolarında bile uygulamanızın çalışmaya devam etmesini garanti etmek açısından önemlidir.\n\n///\n\nBu parametre o endpoint’i / *path operation*’ı oluşturmaz; fakat `/token` URL’sinin client’ın token almak için kullanması gereken URL olduğunu bildirir. Bu bilgi OpenAPI’de, dolayısıyla etkileşimli API dokümantasyon sistemlerinde kullanılır.\n\nBirazdan gerçek path operation’ı da oluşturacağız.\n\n/// info | Teknik Detaylar\n\nEğer çok katı bir \"Pythonista\" iseniz, `token_url` yerine `tokenUrl` şeklindeki parametre adlandırma stilini sevmeyebilirsiniz.\n\nBunun nedeni, OpenAPI spesifikasyonundaki isimle aynı adın kullanılmasıdır. Böylece bu güvenlik şemalarından herhangi biri hakkında daha fazla araştırma yapmanız gerekirse, adı kopyalayıp yapıştırarak kolayca daha fazla bilgi bulabilirsiniz.\n\n///\n\n`oauth2_scheme` değişkeni, `OAuth2PasswordBearer`’ın bir instance’ıdır; ama aynı zamanda \"callable\"dır.\n\nŞu şekilde çağrılabilir:\n\n```Python\noauth2_scheme(some, parameters)\n```\n\nDolayısıyla `Depends` ile kullanılabilir.\n\n### Kullanın { #use-it }\n\nArtık `Depends` ile bir dependency olarak `oauth2_scheme`’i geçebilirsiniz.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nBu dependency, *path operation function* içindeki `token` parametresine atanacak bir `str` sağlar.\n\n**FastAPI**, bu dependency’yi OpenAPI şemasında (ve otomatik API dokümanlarında) bir \"security scheme\" tanımlamak için kullanabileceğini bilir.\n\n/// info | Teknik Detaylar\n\n**FastAPI**, bir dependency içinde tanımlanan `OAuth2PasswordBearer` sınıfını OpenAPI’de security scheme tanımlamak için kullanabileceğini bilir; çünkü bu sınıf `fastapi.security.oauth2.OAuth2`’den kalıtım alır, o da `fastapi.security.base.SecurityBase`’den kalıtım alır.\n\nOpenAPI (ve otomatik API dokümanları) ile entegre olan tüm security araçları `SecurityBase`’den kalıtım alır; **FastAPI** bu sayede onları OpenAPI’ye nasıl entegre edeceğini anlayabilir.\n\n///\n\n## Ne Yapar { #what-it-does }\n\nRequest içinde `Authorization` header’ını arar, değerin `Bearer ` + bir token olup olmadığını kontrol eder ve token’ı `str` olarak döndürür.\n\nEğer `Authorization` header’ını görmezse ya da değer `Bearer ` token’ı içermiyorsa, doğrudan 401 status code hatasıyla (`UNAUTHORIZED`) response döner.\n\nToken’ın var olup olmadığını kontrol edip ayrıca hata döndürmenize bile gerek yoktur. Fonksiyonunuz çalışıyorsa, token içinde bir `str` olacağından emin olabilirsiniz.\n\nBunu şimdiden etkileşimli dokümanlarda deneyebilirsiniz:\n\n<img src=\"/img/tutorial/security/image03.png\">\n\nHenüz token’ın geçerliliğini doğrulamıyoruz, ama başlangıç için bu bile yeterli.\n\n## Özet { #recap }\n\nYani sadece 3 veya 4 ekstra satırla, şimdiden ilkel de olsa bir güvenlik katmanı elde etmiş oldunuz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/security/get-current-user.md",
    "content": "# Mevcut Kullanıcıyı Alma { #get-current-user }\n\nÖnceki bölümde güvenlik sistemi (dependency injection sistemine dayanır) *path operation function*'a `str` olarak bir `token` veriyordu:\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nAncak bu hâlâ pek kullanışlı değil.\n\nBize mevcut kullanıcıyı verecek şekilde düzenleyelim.\n\n## Bir kullanıcı modeli oluşturun { #create-a-user-model }\n\nÖnce bir Pydantic kullanıcı modeli oluşturalım.\n\nBody'leri bildirmek için Pydantic'i nasıl kullanıyorsak, aynı şekilde onu başka her yerde de kullanabiliriz:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## `get_current_user` dependency'si oluşturun { #create-a-get-current-user-dependency }\n\nBir `get_current_user` dependency'si oluşturalım.\n\nDependency'lerin alt dependency'leri olabileceğini hatırlıyor musunuz?\n\n`get_current_user`, daha önce oluşturduğumuz `oauth2_scheme` ile aynı dependency'yi kullanacak.\n\nDaha önce *path operation* içinde doğrudan yaptığımız gibi, yeni dependency'miz `get_current_user`, alt dependency olan `oauth2_scheme` üzerinden `str` olarak bir `token` alacak:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## Kullanıcıyı alın { #get-the-user }\n\n`get_current_user`, oluşturduğumuz (sahte) bir yardımcı (utility) fonksiyonu kullanacak; bu fonksiyon `str` olarak bir token alır ve Pydantic `User` modelimizi döndürür:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## Mevcut kullanıcıyı enjekte edin { #inject-the-current-user }\n\nArtık *path operation* içinde `get_current_user` ile aynı `Depends` yaklaşımını kullanabiliriz:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\n`current_user` tipini Pydantic `User` modeli olarak belirttiğimize dikkat edin.\n\nBu sayede fonksiyonun içinde otomatik tamamlama ve tip kontrollerinin tamamından faydalanırız.\n\n/// tip | İpucu\n\nRequest body'lerinin de Pydantic modelleri ile bildirildiğini hatırlıyor olabilirsiniz.\n\nBurada `Depends` kullandığınız için **FastAPI** karışıklık yaşamaz.\n\n///\n\n/// check | Ek bilgi\n\nBu dependency sisteminin tasarımı, hepsi `User` modeli döndüren farklı dependency'lere (farklı \"dependable\"lara) sahip olmamıza izin verir.\n\nBu tipte veri döndürebilen yalnızca tek bir dependency ile sınırlı değiliz.\n\n///\n\n## Diğer modeller { #other-models }\n\nArtık *path operation function* içinde mevcut kullanıcıyı doğrudan alabilir ve güvenlik mekanizmalarını `Depends` kullanarak **Dependency Injection** seviyesinde yönetebilirsiniz.\n\nAyrıca güvenlik gereksinimleri için herhangi bir model veya veri kullanabilirsiniz (bu örnekte bir Pydantic `User` modeli).\n\nAncak belirli bir data model, class ya da type kullanmak zorunda değilsiniz.\n\nModelinizde bir `id` ve `email` olsun, ama `username` olmasın mı istiyorsunuz? Elbette. Aynı araçları kullanabilirsiniz.\n\nSadece bir `str` mı istiyorsunuz? Ya da sadece bir `dict`? Veya doğrudan bir veritabanı class model instance'ı? Hepsi aynı şekilde çalışır.\n\nUygulamanıza giriş yapan kullanıcılar yok da robotlar, botlar veya yalnızca bir access token'a sahip başka sistemler mi var? Yine, her şey aynı şekilde çalışır.\n\nUygulamanız için neye ihtiyacınız varsa o türden bir model, class ve veritabanı kullanın. **FastAPI**, dependency injection sistemiyle bunları destekler.\n\n## Kod boyutu { #code-size }\n\nBu örnek biraz uzun görünebilir. Güvenlik, data model'ler, utility fonksiyonlar ve *path operation*'ları aynı dosyada bir araya getirdiğimizi unutmayın.\n\nAma kritik nokta şu:\n\nGüvenlik ve dependency injection tarafını bir kez yazarsınız.\n\nİstediğiniz kadar karmaşık hâle getirebilirsiniz. Yine de hepsi tek bir yerde ve sadece bir kez yazılmış olur. Üstelik tüm esneklikle.\n\nSonrasında aynı güvenlik sistemini kullanan binlerce endpoint (*path operation*) olabilir.\n\nVe bunların hepsi (ya da istediğiniz bir kısmı) bu dependency'leri veya oluşturacağınız başka dependency'leri yeniden kullanmaktan faydalanabilir.\n\nHatta bu binlerce *path operation* 3 satır kadar kısa olabilir:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## Özet { #recap }\n\nArtık *path operation function* içinde mevcut kullanıcıyı doğrudan alabilirsiniz.\n\nYolun yarısına geldik.\n\nKullanıcının/istemcinin gerçekten `username` ve `password` göndermesini sağlayacak bir *path operation* eklememiz gerekiyor.\n\nSırada bu var.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/security/index.md",
    "content": "# Güvenlik { #security }\n\nGüvenlik, authentication ve authorization’ı ele almanın birçok yolu vardır.\n\nVe bu konu genellikle karmaşık ve \"zor\"dur.\n\nBirçok framework ve sistemde yalnızca security ve authentication’ı yönetmek bile ciddi miktarda emek ve kod gerektirir (çoğu durumda yazılan toplam kodun %50’si veya daha fazlası olabilir).\n\n**FastAPI**, tüm security spesifikasyonlarını baştan sona inceleyip öğrenmek zorunda kalmadan **Security** konusunu kolay, hızlı ve standart bir şekilde ele almanıza yardımcı olacak çeşitli araçlar sunar.\n\nAma önce, küçük birkaç kavrama bakalım.\n\n## Acelem var? { #in-a-hurry }\n\nBu terimlerin hiçbirini umursamıyorsanız ve sadece kullanıcı adı ve parola tabanlı authentication ile security’yi *hemen şimdi* eklemeniz gerekiyorsa, bir sonraki bölümlere geçin.\n\n## OAuth2 { #oauth2 }\n\nOAuth2, authentication ve authorization’ı yönetmek için çeşitli yöntemleri tanımlayan bir spesifikasyondur.\n\nOldukça kapsamlı bir spesifikasyondur ve birkaç karmaşık use case’i kapsar.\n\n\"Üçüncü taraf\" kullanarak authentication yapmanın yollarını da içerir.\n\n\"Facebook, Google, X (Twitter), GitHub ile giriş yap\" bulunan sistemlerin arka planda kullandığı şey de budur.\n\n### OAuth 1 { #oauth-1 }\n\nOAuth 1 de vardı; OAuth2’den çok farklıdır ve daha karmaşıktır, çünkü iletişimi nasıl şifreleyeceğinize dair doğrudan spesifikasyonlar içeriyordu.\n\nGünümüzde pek popüler değildir veya pek kullanılmaz.\n\nOAuth2 ise iletişimin nasıl şifreleneceğini belirtmez; uygulamanızın HTTPS ile sunulmasını bekler.\n\n/// tip | İpucu\n\n**deployment** bölümünde Traefik ve Let's Encrypt kullanarak ücretsiz şekilde HTTPS’i nasıl kuracağınızı göreceksiniz.\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect, **OAuth2** tabanlı başka bir spesifikasyondur.\n\nOAuth2’de nispeten belirsiz kalan bazı noktaları tanımlayarak onu daha birlikte çalışabilir (interoperable) hâle getirmeye çalışır.\n\nÖrneğin, Google ile giriş OpenID Connect kullanır (arka planda OAuth2 kullanır).\n\nAncak Facebook ile giriş OpenID Connect’i desteklemez. Kendine özgü bir OAuth2 çeşidi vardır.\n\n### OpenID (\"OpenID Connect\" değil) { #openid-not-openid-connect }\n\nBir de \"OpenID\" spesifikasyonu vardı. Bu da **OpenID Connect** ile aynı problemi çözmeye çalışıyordu ama OAuth2 tabanlı değildi.\n\nDolayısıyla tamamen ayrı, ek bir sistemdi.\n\nGünümüzde pek popüler değildir veya pek kullanılmaz.\n\n## OpenAPI { #openapi }\n\nOpenAPI (önceden Swagger olarak biliniyordu), API’ler inşa etmek için açık spesifikasyondur (artık Linux Foundation’ın bir parçası).\n\n**FastAPI**, **OpenAPI** tabanlıdır.\n\nBu sayede birden fazla otomatik etkileşimli dokümantasyon arayüzü, code generation vb. mümkün olur.\n\nOpenAPI, birden fazla security \"scheme\" tanımlamanın bir yolunu sunar.\n\nBunları kullanarak, etkileşimli dokümantasyon sistemleri de dahil olmak üzere tüm bu standart tabanlı araçlardan faydalanabilirsiniz.\n\nOpenAPI şu security scheme’lerini tanımlar:\n\n* `apiKey`: uygulamaya özel bir anahtar; şuradan gelebilir:\n    * Bir query parameter.\n    * Bir header.\n    * Bir cookie.\n* `http`: standart HTTP authentication sistemleri, örneğin:\n    * `bearer`: `Authorization` header’ı; değeri `Bearer ` + bir token olacak şekilde. Bu, OAuth2’den gelir.\n    * HTTP Basic authentication.\n    * HTTP Digest, vb.\n* `oauth2`: OAuth2 ile security’yi yönetmenin tüm yolları (\"flow\" olarak adlandırılır).\n    * Bu flow’ların birçoğu, bir OAuth 2.0 authentication provider (Google, Facebook, X (Twitter), GitHub vb.) oluşturmak için uygundur:\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * Ancak, aynı uygulamanın içinde doğrudan authentication yönetmek için mükemmel şekilde kullanılabilecek özel bir \"flow\" vardır:\n        * `password`: sonraki bazı bölümlerde bunun örnekleri ele alınacak.\n* `openIdConnect`: OAuth2 authentication verisinin otomatik olarak nasıl keşfedileceğini tanımlamanın bir yolunu sunar.\n    * Bu otomatik keşif, OpenID Connect spesifikasyonunda tanımlanan şeydir.\n\n\n/// tip | İpucu\n\nGoogle, Facebook, X (Twitter), GitHub vb. gibi diğer authentication/authorization provider’larını entegre etmek de mümkündür ve nispeten kolaydır.\n\nEn karmaşık kısım, bu tür bir authentication/authorization provider’ı inşa etmektir; ancak **FastAPI** ağır işleri sizin yerinize yaparken bunu kolayca yapabilmeniz için araçlar sunar.\n\n///\n\n## **FastAPI** yardımcı araçları { #fastapi-utilities }\n\nFastAPI, `fastapi.security` modülünde bu security scheme’lerinin her biri için, bu mekanizmaları kullanmayı kolaylaştıran çeşitli araçlar sağlar.\n\nSonraki bölümlerde, **FastAPI**’nin sunduğu bu araçları kullanarak API’nize nasıl security ekleyeceğinizi göreceksiniz.\n\nAyrıca bunun etkileşimli dokümantasyon sistemine nasıl otomatik olarak entegre edildiğini de göreceksiniz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/security/oauth2-jwt.md",
    "content": "# Password ile OAuth2 (ve hashing), JWT token'ları ile Bearer { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\nArtık tüm security flow elimizde olduğuna göre, uygulamayı gerçekten güvenli hâle getirelim: <abbr title=\"JSON Web Token'lar\">JWT</abbr> token'ları ve güvenli password hashing kullanacağız.\n\nBu kodu uygulamanızda gerçekten kullanabilirsiniz; password hash'lerini veritabanınıza kaydedebilirsiniz, vb.\n\nBir önceki bölümde bıraktığımız yerden başlayıp üzerine ekleyerek ilerleyeceğiz.\n\n## JWT Hakkında { #about-jwt }\n\nJWT, \"JSON Web Tokens\" anlamına gelir.\n\nBir JSON nesnesini, boşluk içermeyen uzun ve yoğun bir string'e kodlamak için kullanılan bir standarttır. Şuna benzer:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\nŞifrelenmiş değildir; yani herkes içeriğindeki bilgiyi geri çıkarabilir.\n\nAncak imzalanmıştır. Bu yüzden, sizin ürettiğiniz bir token'ı aldığınızda, gerçekten onu sizin ürettiğinizi doğrulayabilirsiniz.\n\nBu şekilde, örneğin 1 haftalık süre sonu (expiration) olan bir token oluşturabilirsiniz. Sonra kullanıcı ertesi gün token ile geri geldiğinde, kullanıcının hâlâ sisteminizde oturum açmış olduğunu bilirsiniz.\n\nBir hafta sonra token'ın süresi dolar; kullanıcı yetkilendirilmez ve yeni bir token almak için tekrar giriş yapmak zorunda kalır. Ayrıca kullanıcı (veya üçüncü bir taraf) token'ı değiştirip süre sonunu farklı göstermek isterse bunu tespit edebilirsiniz; çünkü imzalar eşleşmez.\n\nJWT token'larıyla oynayıp nasıl çalıştıklarını görmek isterseniz [https://jwt.io](https://jwt.io/) adresine bakın.\n\n## `PyJWT` Kurulumu { #install-pyjwt }\n\nPython'da JWT token'larını üretmek ve doğrulamak için `PyJWT` kurmamız gerekiyor.\n\nBir [sanal ortam](../../virtual-environments.md) oluşturduğunuzdan emin olun, aktif edin ve ardından `pyjwt` kurun:\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info | Bilgi\n\nRSA veya ECDSA gibi dijital imza algoritmaları kullanmayı planlıyorsanız, `pyjwt[crypto]` bağımlılığı olan `cryptography` kütüphanesini kurmalısınız.\n\nDaha fazla bilgi için [PyJWT Kurulum dokümantasyonu](https://pyjwt.readthedocs.io/en/latest/installation.html) sayfasını okuyabilirsiniz.\n\n///\n\n## Password hashing { #password-hashing }\n\n\"Hashing\", bazı içerikleri (bu örnekte bir password) anlamsız görünen bir bayt dizisine (pratikte bir string) dönüştürmek demektir.\n\nAynı içeriği (aynı password'ü) her seferinde verirseniz, her seferinde aynı anlamsız çıktıyı elde edersiniz.\n\nAncak bu anlamsız çıktıdan geri password'e dönüştürme yapılamaz.\n\n### Neden password hashing kullanılır { #why-use-password-hashing }\n\nVeritabanınız çalınırsa, hırsız kullanıcılarınızın düz metin (plaintext) password'lerini değil, sadece hash'leri elde eder.\n\nDolayısıyla, o password'ü başka bir sistemde denemek kolay olmaz (pek çok kullanıcı her yerde aynı password'ü kullandığı için bu tehlikeli olurdu).\n\n## `pwdlib` Kurulumu { #install-pwdlib }\n\npwdlib, password hash'leriyle çalışmak için çok iyi bir Python paketidir.\n\nBirçok güvenli hashing algoritmasını ve bunlarla çalışmak için yardımcı araçları destekler.\n\nÖnerilen algoritma \"Argon2\"dir.\n\nBir [sanal ortam](../../virtual-environments.md) oluşturduğunuzdan emin olun, aktif edin ve sonra Argon2 ile birlikte pwdlib'i kurun:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | İpucu\n\n`pwdlib` ile, **Django** tarafından oluşturulmuş password'leri, bir **Flask** security eklentisinin ürettiklerini veya başka birçok kaynaktan gelen password'leri okuyabilecek şekilde bile yapılandırabilirsiniz.\n\nBöylece örneğin bir Django uygulamasındaki verileri aynı veritabanında bir FastAPI uygulamasıyla paylaşabilirsiniz. Ya da aynı veritabanını kullanarak bir Django uygulamasını kademeli şekilde taşıyabilirsiniz.\n\nAyrıca kullanıcılarınız, aynı anda hem Django uygulamanızdan hem de **FastAPI** uygulamanızdan login olabilir.\n\n///\n\n## Password'leri hash'leme ve doğrulama { #hash-and-verify-the-passwords }\n\nGerekli araçları `pwdlib` içinden import edelim.\n\nÖnerilen ayarlarla bir PasswordHash instance'ı oluşturalım; bunu password'leri hash'lemek ve doğrulamak için kullanacağız.\n\n/// tip | İpucu\n\npwdlib, bcrypt hashing algoritmasını da destekler; ancak legacy algoritmaları içermez. Eski hash'lerle çalışmak için passlib kütüphanesini kullanmanız önerilir.\n\nÖrneğin, başka bir sistemin (Django gibi) ürettiği password'leri okuyup doğrulayabilir, ancak yeni password'leri Argon2 veya Bcrypt gibi farklı bir algoritmayla hash'leyebilirsiniz.\n\nVe aynı anda hepsiyle uyumlu kalabilirsiniz.\n\n///\n\nKullanıcıdan gelen password'ü hash'lemek için bir yardımcı (utility) fonksiyon oluşturalım.\n\nSonra, alınan password'ün kayıttaki hash ile eşleşip eşleşmediğini doğrulayan başka bir yardımcı fonksiyon yazalım.\n\nBir tane de kullanıcıyı authenticate edip geri döndüren bir yardımcı fonksiyon ekleyelim.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\n`authenticate_user`, veritabanında var olmayan bir username ile çağrıldığında, yine de sahte (dummy) bir hash'e karşı `verify_password` çalıştırıyoruz.\n\nBu, username geçerli olsun ya da olmasın endpoint'in yaklaşık aynı sürede yanıt vermesini sağlar; böylece mevcut username'leri saymaya yarayabilecek zamanlama saldırılarını (timing attacks) engeller.\n\n/// note | Not\n\nYeni (sahte) veritabanı `fake_users_db`'ye bakarsanız, hash'lenmiş password'ün artık nasıl göründüğünü görebilirsiniz: `\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`.\n\n///\n\n## JWT token'larını yönetme { #handle-jwt-tokens }\n\nKurulu modülleri import edelim.\n\nJWT token'larını imzalamak için kullanılacak rastgele bir secret key oluşturalım.\n\nGüvenli, rastgele bir secret key üretmek için şu komutu kullanın:\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\nÇıktıyı `SECRET_KEY` değişkenine kopyalayın (örnektekini kullanmayın).\n\nJWT token'ını imzalamak için kullanılan algoritmayı tutacak `ALGORITHM` adlı bir değişken oluşturup değerini `\"HS256\"` yapın.\n\nToken'ın süre sonu (expiration) için bir değişken oluşturun.\n\nResponse için token endpoint'inde kullanılacak bir Pydantic Model tanımlayın.\n\nYeni bir access token üretmek için bir yardımcı fonksiyon oluşturun.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## Dependency'leri güncelleme { #update-the-dependencies }\n\n`get_current_user` fonksiyonunu, öncekiyle aynı token'ı alacak şekilde güncelleyelim; ancak bu sefer JWT token'larını kullanacağız.\n\nGelen token'ı decode edin, doğrulayın ve mevcut kullanıcıyı döndürün.\n\nToken geçersizse, hemen bir HTTP hatası döndürün.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## `/token` *path operation*'ını güncelleme { #update-the-token-path-operation }\n\nToken'ın süre sonu için bir `timedelta` oluşturun.\n\nGerçek bir JWT access token üretip döndürün.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### JWT \"subject\" `sub` Hakkında Teknik Detaylar { #technical-details-about-the-jwt-subject-sub }\n\nJWT spesifikasyonu, token'ın konusu (subject) için `sub` adlı bir anahtar olduğunu söyler.\n\nBunu kullanmak zorunlu değildir; ancak kullanıcı kimliğini koymak için uygun yer burasıdır, bu yüzden burada onu kullanıyoruz.\n\nJWT, sadece bir kullanıcıyı tanımlamak ve API'nizde doğrudan işlem yapmasına izin vermek dışında başka amaçlarla da kullanılabilir.\n\nÖrneğin bir \"araba\"yı veya bir \"blog post\"u tanımlayabilirsiniz.\n\nSonra o varlık için izinler ekleyebilirsiniz; örneğin (araba için) \"drive\" ya da (blog için) \"edit\".\n\nArdından bu JWT token'ını bir kullanıcıya (veya bot'a) verebilirsiniz; onlar da, hesapları olmasına bile gerek kalmadan, sadece API'nizin bunun için ürettiği JWT token'ıyla bu aksiyonları gerçekleştirebilir (arabayı sürmek veya blog post'u düzenlemek gibi).\n\nBu fikirlerle JWT, çok daha gelişmiş senaryolarda kullanılabilir.\n\nBu durumlarda, birden fazla varlığın aynı ID'ye sahip olması mümkündür; örneğin `foo` (kullanıcı `foo`, araba `foo`, blog post `foo`).\n\nDolayısıyla ID çakışmalarını önlemek için, kullanıcı için JWT token oluştururken `sub` anahtarının değerine bir önek ekleyebilirsiniz; örneğin `username:`. Bu örnekte `sub` değeri şöyle olabilirdi: `username:johndoe`.\n\nUnutmamanız gereken önemli nokta şudur: `sub` anahtarı, tüm uygulama genelinde benzersiz bir tanımlayıcı olmalı ve string olmalıdır.\n\n## Kontrol Edelim { #check-it }\n\nServer'ı çalıştırın ve docs'a gidin: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nŞuna benzer bir arayüz göreceksiniz:\n\n<img src=\"/img/tutorial/security/image07.png\">\n\nUygulamayı, öncekiyle aynı şekilde authorize edin.\n\nŞu kimlik bilgilerini kullanarak:\n\nUsername: `johndoe`\nPassword: `secret`\n\n/// check | Ek bilgi\n\nKodun hiçbir yerinde düz metin password \"`secret`\" yok; sadece hash'lenmiş hâli var.\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\n`/users/me/` endpoint'ini çağırın; response şöyle olacaktır:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\nDeveloper tools'u açarsanız, gönderilen verinin sadece token'ı içerdiğini görebilirsiniz. Password sadece kullanıcıyı authenticate edip access token almak için yapılan ilk request'te gönderilir, sonrasında gönderilmez:\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | Not\n\n`Authorization` header'ına dikkat edin; değeri `Bearer ` ile başlıyor.\n\n///\n\n## `scopes` ile İleri Seviye Kullanım { #advanced-usage-with-scopes }\n\nOAuth2'nin \"scopes\" kavramı vardır.\n\nBunları kullanarak bir JWT token'a belirli bir izin seti ekleyebilirsiniz.\n\nSonra bu token'ı bir kullanıcıya doğrudan veya bir üçüncü tarafa verip, API'nizle belirli kısıtlarla etkileşime girmesini sağlayabilirsiniz.\n\nNasıl kullanıldıklarını ve **FastAPI** ile nasıl entegre olduklarını, ileride **Advanced User Guide** içinde öğreneceksiniz.\n\n## Özet { #recap }\n\nŞimdiye kadar gördüklerinizle, OAuth2 ve JWT gibi standartları kullanarak güvenli bir **FastAPI** uygulaması kurabilirsiniz.\n\nNeredeyse her framework'te security'yi ele almak oldukça hızlı bir şekilde karmaşık bir konu hâline gelir.\n\nBunu çok basitleştiren birçok paket, veri modeli, veritabanı ve mevcut özelliklerle ilgili pek çok ödün vermek zorunda kalır. Hatta bazıları işi aşırı basitleştirirken arka planda güvenlik açıkları da barındırır.\n\n---\n\n**FastAPI**, hiçbir veritabanı, veri modeli veya araç konusunda ödün vermez.\n\nProjenize en uygun olanları seçebilmeniz için size tam esneklik sağlar.\n\nAyrıca `pwdlib` ve `PyJWT` gibi iyi bakımı yapılan ve yaygın kullanılan paketleri doğrudan kullanabilirsiniz; çünkü **FastAPI**, haricî paketleri entegre etmek için karmaşık mekanizmalara ihtiyaç duymaz.\n\nBuna rağmen, esneklikten, sağlamlıktan veya güvenlikten ödün vermeden süreci mümkün olduğunca basitleştiren araçları sağlar.\n\nVe OAuth2 gibi güvenli, standart protokolleri nispeten basit bir şekilde kullanabilir ve uygulayabilirsiniz.\n\nAynı standartları izleyerek, daha ince taneli (fine-grained) bir izin sistemi için OAuth2 \"scopes\" kullanımını **Advanced User Guide** içinde daha detaylı öğrenebilirsiniz. Scopes'lu OAuth2; Facebook, Google, GitHub, Microsoft, X (Twitter) vb. pek çok büyük kimlik doğrulama sağlayıcısının, üçüncü taraf uygulamaların kullanıcıları adına API'leriyle etkileşebilmesine izin vermek için kullandığı mekanizmadır.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/security/simple-oauth2.md",
    "content": "# Password ve Bearer ile Basit OAuth2 { #simple-oauth2-with-password-and-bearer }\n\nŞimdi önceki bölümün üzerine inşa edip, eksik parçaları ekleyerek tam bir güvenlik akışı oluşturalım.\n\n## `username` ve `password`’ü Alma { #get-the-username-and-password }\n\n`username` ve `password`’ü almak için **FastAPI** security yardımcı araçlarını kullanacağız.\n\nOAuth2, (bizim kullandığımız) \"password flow\" kullanılırken client/kullanıcının form verisi olarak `username` ve `password` alanlarını göndermesi gerektiğini belirtir.\n\nAyrıca spesifikasyon, bu alanların adlarının tam olarak böyle olması gerektiğini söyler. Yani `user-name` veya `email` işe yaramaz.\n\nAncak merak etmeyin, frontend’de son kullanıcılarınıza dilediğiniz gibi gösterebilirsiniz.\n\nVeritabanı model(ler)inizde de istediğiniz başka isimleri kullanabilirsiniz.\n\nFakat login *path operation*’ı için, spesifikasyonla uyumlu olmak (ve örneğin entegre API dokümantasyon sistemini kullanabilmek) adına bu isimleri kullanmamız gerekiyor.\n\nSpesifikasyon ayrıca `username` ve `password`’ün form verisi olarak gönderilmesi gerektiğini de söyler (yani burada JSON yok).\n\n### `scope` { #scope }\n\nSpesifikasyon, client’ın \"`scope`\" adlı başka bir form alanı da gönderebileceğini söyler.\n\nForm alanının adı `scope`’tur (tekil), ama aslında boşluklarla ayrılmış \"scope\"’lardan oluşan uzun bir string’dir.\n\nHer bir \"scope\" sadece bir string’dir (boşluk içermez).\n\nGenelde belirli güvenlik izinlerini (permission) belirtmek için kullanılırlar, örneğin:\n\n* `users:read` veya `users:write` yaygın örneklerdir.\n* `instagram_basic` Facebook / Instagram tarafından kullanılır.\n* `https://www.googleapis.com/auth/drive` Google tarafından kullanılır.\n\n/// info | Bilgi\n\nOAuth2’de bir \"scope\", gerekli olan belirli bir izni ifade eden basit bir string’dir.\n\n`:` gibi başka karakterler içermesi veya URL olması önemli değildir.\n\nBu detaylar implementasyon’a özeldir.\n\nOAuth2 açısından bunlar sadece string’lerdir.\n\n///\n\n## `username` ve `password`’ü Almak İçin Kod { #code-to-get-the-username-and-password }\n\nŞimdi bunu yönetmek için **FastAPI**’nin sağladığı araçları kullanalım.\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\nÖnce `OAuth2PasswordRequestForm`’u import edin ve `/token` için *path operation* içinde `Depends` ile dependency olarak kullanın:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm`, şu alanları içeren bir form body tanımlayan bir class dependency’sidir:\n\n* `username`.\n* `password`.\n* Boşlukla ayrılmış string’lerden oluşan büyük bir string olarak opsiyonel `scope` alanı.\n* Opsiyonel `grant_type`.\n\n/// tip | İpucu\n\nOAuth2 spesifikasyonu aslında `grant_type` alanını sabit bir `password` değeriyle *zorunlu kılar*, ancak `OAuth2PasswordRequestForm` bunu zorlamaz.\n\nBunu zorlamak istiyorsanız, `OAuth2PasswordRequestForm` yerine `OAuth2PasswordRequestFormStrict` kullanın.\n\n///\n\n* Opsiyonel `client_id` (bu örnekte ihtiyacımız yok).\n* Opsiyonel `client_secret` (bu örnekte ihtiyacımız yok).\n\n/// info | Bilgi\n\n`OAuth2PasswordRequestForm`, `OAuth2PasswordBearer` gibi **FastAPI**’ye özel “özel bir sınıf” değildir.\n\n`OAuth2PasswordBearer`, bunun bir security scheme olduğunu **FastAPI**’ye bildirir. Bu yüzden OpenAPI’ye o şekilde eklenir.\n\nAma `OAuth2PasswordRequestForm` sadece bir class dependency’dir; bunu kendiniz de yazabilirdiniz ya da doğrudan `Form` parametreleri tanımlayabilirdiniz.\n\nFakat çok yaygın bir kullanım olduğu için **FastAPI** bunu işleri kolaylaştırmak adına doğrudan sağlar.\n\n///\n\n### Form Verisini Kullanma { #use-the-form-data }\n\n/// tip | İpucu\n\n`OAuth2PasswordRequestForm` dependency class’ının instance’ında boşluklarla ayrılmış uzun string olarak bir `scope` attribute’u olmaz; bunun yerine gönderilen her scope için gerçek string listesini içeren `scopes` attribute’u olur.\n\nBu örnekte `scopes` kullanmıyoruz, ama ihtiyacınız olursa bu özellik hazır.\n\n///\n\nŞimdi form alanındaki `username`’i kullanarak (sahte) veritabanından kullanıcı verisini alın.\n\nBöyle bir kullanıcı yoksa, \"Incorrect username or password\" diyerek bir hata döndürelim.\n\nHata için `HTTPException` exception’ını kullanıyoruz:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### Password’ü Kontrol Etme { #check-the-password }\n\nBu noktada veritabanından kullanıcı verisine sahibiz, ancak password’ü henüz kontrol etmedik.\n\nÖnce bu veriyi Pydantic `UserInDB` modeline koyalım.\n\nAsla düz metin (plaintext) password kaydetmemelisiniz; bu yüzden (sahte) password hashing sistemini kullanacağız.\n\nPassword’ler eşleşmezse, aynı hatayı döndürürüz.\n\n#### Password hashing { #password-hashing }\n\n\"Hashing\" şudur: bir içeriği (bu örnekte password) anlaşılmaz görünen bayt dizisine (yani bir string’e) dönüştürmek.\n\nAynı içeriği (aynı password’ü) her verdiğinizde, birebir aynı anlamsız görünen çıktıyı elde edersiniz.\n\nAma bu anlamsız çıktıyı tekrar password’e geri çeviremezsiniz.\n\n##### Neden password hashing kullanılır { #why-use-password-hashing }\n\nVeritabanınız çalınırsa, hırsız kullanıcılarınızın düz metin password’lerine değil, sadece hash’lere sahip olur.\n\nDolayısıyla hırsız, aynı password’leri başka bir sistemde denemeye çalışamaz (birçok kullanıcı her yerde aynı password’ü kullandığı için bu tehlikeli olurdu).\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### `**user_dict` Hakkında { #about-user-dict }\n\n`UserInDB(**user_dict)` şu anlama gelir:\n\n*`user_dict` içindeki key ve value’ları doğrudan key-value argümanları olarak geçir; şu ifadeyle eşdeğerdir:*\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info | Bilgi\n\n`**user_dict` için daha kapsamlı bir açıklama için [**Extra Models** dokümantasyonundaki ilgili bölüme](../extra-models.md#about-user-in-dict) geri dönüp bakın.\n\n///\n\n## Token’ı Döndürme { #return-the-token }\n\n`token` endpoint’inin response’u bir JSON object olmalıdır.\n\nBir `token_type` içermelidir. Biz \"Bearer\" token’ları kullandığımız için token type \"`bearer`\" olmalıdır.\n\nAyrıca `access_token` içermelidir; bunun değeri access token’ımızı içeren bir string olmalıdır.\n\nBu basit örnekte tamamen güvensiz davranıp token olarak aynı `username`’i döndüreceğiz.\n\n/// tip | İpucu\n\nBir sonraki bölümde, password hashing ve <abbr title=\"JSON Web Tokens\">JWT</abbr> token’ları ile gerçekten güvenli bir implementasyon göreceksiniz.\n\nAma şimdilik ihtiyacımız olan spesifik detaylara odaklanalım.\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip | İpucu\n\nSpesifikasyona göre, bu örnekteki gibi `access_token` ve `token_type` içeren bir JSON döndürmelisiniz.\n\nBunu kendi kodunuzda kendiniz yapmalı ve bu JSON key’lerini kullandığınızdan emin olmalısınız.\n\nSpesifikasyonlara uyum için, doğru yapmanız gereken neredeyse tek şey budur.\n\nGeri kalanını **FastAPI** sizin yerinize yönetir.\n\n///\n\n## Dependency’leri Güncelleme { #update-the-dependencies }\n\nŞimdi dependency’lerimizi güncelleyeceğiz.\n\n`current_user`’ı *sadece* kullanıcı aktifse almak istiyoruz.\n\nBu yüzden, `get_current_user`’ı dependency olarak kullanan ek bir dependency olan `get_current_active_user`’ı oluşturuyoruz.\n\nBu iki dependency de kullanıcı yoksa veya pasifse sadece HTTP hatası döndürecek.\n\nDolayısıyla endpoint’imizde kullanıcıyı ancak kullanıcı varsa, doğru şekilde authenticate edildiyse ve aktifse alacağız:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info | Bilgi\n\nBurada `Bearer` değerine sahip ek `WWW-Authenticate` header’ını döndürmemiz de spesifikasyonun bir parçasıdır.\n\nHerhangi bir HTTP (hata) durum kodu 401 \"UNAUTHORIZED\", ayrıca `WWW-Authenticate` header’ı da döndürmelidir.\n\nBearer token’lar (bizim durumumuz) için bu header’ın değeri `Bearer` olmalıdır.\n\nAslında bu ekstra header’ı atlayabilirsiniz, yine de çalışır.\n\nAma spesifikasyonlara uyumlu olması için burada eklenmiştir.\n\nAyrıca, bunu bekleyen ve kullanan araçlar olabilir (şimdi veya ileride) ve bu da sizin ya da kullanıcılarınız için faydalı olabilir.\n\nStandartların faydası da bu...\n\n///\n\n## Çalışır Halini Görün { #see-it-in-action }\n\nEtkileşimli dokümanları açın: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n### Authenticate Olma { #authenticate }\n\n\"Authorize\" butonuna tıklayın.\n\nŞu bilgileri kullanın:\n\nUser: `johndoe`\n\nPassword: `secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\nSistemde authenticate olduktan sonra şöyle görürsünüz:\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### Kendi Kullanıcı Verinizi Alma { #get-your-own-user-data }\n\nŞimdi `/users/me` path’inde `GET` operasyonunu kullanın.\n\nKullanıcınızın verisini şöyle alırsınız:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\nKilit ikonuna tıklayıp logout olursanız ve sonra aynı operasyonu tekrar denerseniz, şu şekilde bir HTTP 401 hatası alırsınız:\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### Pasif Kullanıcı { #inactive-user }\n\nŞimdi pasif bir kullanıcıyla deneyin; şu bilgilerle authenticate olun:\n\nUser: `alice`\n\nPassword: `secret2`\n\nVe `/users/me` path’inde `GET` operasyonunu kullanmayı deneyin.\n\nŞöyle bir \"Inactive user\" hatası alırsınız:\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## Özet { #recap }\n\nArtık API’niz için `username` ve `password` tabanlı, eksiksiz bir güvenlik sistemi implement etmek için gerekli araçlara sahipsiniz.\n\nBu araçlarla güvenlik sistemini herhangi bir veritabanıyla ve herhangi bir user veya veri modeliyle uyumlu hale getirebilirsiniz.\n\nEksik kalan tek detay, bunun henüz gerçekten \"güvenli\" olmamasıdır.\n\nBir sonraki bölümde güvenli bir password hashing kütüphanesini ve <abbr title=\"JSON Web Tokens\">JWT</abbr> token’larını nasıl kullanacağınızı göreceksiniz.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/server-sent-events.md",
    "content": "# Server-Sent Events (SSE) { #server-sent-events-sse }\n\nİstemciye veri akışını **Server-Sent Events** (SSE) ile sağlayabilirsiniz.\n\nBu, [JSON Lines Akışı](stream-json-lines.md) ile benzerdir ancak tarayıcılar tarafından yerel olarak desteklenen [`EventSource` API'si](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) ile `text/event-stream` formatını kullanır.\n\n/// info | Bilgi\n\nFastAPI 0.135.0'da eklendi.\n\n///\n\n## Server-Sent Events Nedir? { #what-are-server-sent-events }\n\nSSE, HTTP üzerinden sunucudan istemciye veri akışı için bir standarttır.\n\nHer olay, aralarında boş satırlar bulunan ve `data`, `event`, `id` ve `retry` gibi \"alanlar\" içeren küçük bir metin bloğudur.\n\nŞuna benzer:\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE; yapay zekâ sohbet akışı, canlı bildirimler, log ve gözlemlenebilirlik (observability) gibi senaryolarda ve sunucunun istemciye güncellemeleri ittiği diğer durumlarda yaygın olarak kullanılır.\n\n/// tip | İpucu\n\nİkili (binary) veri akışı yapmak istiyorsanız, gelişmiş kılavuza bakın: [Veri Akışı](../advanced/stream-data.md).\n\n///\n\n## FastAPI ile SSE Akışı { #stream-sse-with-fastapi }\n\nFastAPI ile SSE akışı yapmak için, *path operation function* içinde `yield` kullanın ve `response_class=EventSourceResponse` olarak ayarlayın.\n\n`EventSourceResponse`'u `fastapi.sse` içinden içe aktarın:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\nYield edilen her öğe JSON olarak kodlanır ve bir SSE olayının `data:` alanında gönderilir.\n\nDönüş tipini `AsyncIterable[Item]` olarak bildirirseniz, FastAPI bunu Pydantic ile veriyi **doğrulamak**, **belgelemek** ve **serileştirmek** için kullanır.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip | İpucu\n\nPydantic serileştirmeyi **Rust** tarafında yapacağından, dönüş tipi bildirmediğiniz duruma göre çok daha yüksek **performans** elde edersiniz.\n\n///\n\n### Async Olmayan Path Operation Fonksiyonları { #non-async-path-operation-functions }\n\nNormal `def` fonksiyonlarını (yani `async` olmadan) da kullanabilir ve aynı şekilde `yield` kullanabilirsiniz.\n\nFastAPI, event loop'u bloke etmeyecek şekilde doğru biçimde çalışmasını sağlar.\n\nBu örnekte fonksiyon async olmadığı için doğru dönüş tipi `Iterable[Item]` olur:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### Dönüş Tipi Olmadan { #no-return-type }\n\nDönüş tipini belirtmeyebilirsiniz. FastAPI, veriyi dönüştürmek ve göndermek için [`jsonable_encoder`](./encoder.md) kullanır.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\n`event`, `id`, `retry` veya `comment` gibi SSE alanlarını ayarlamanız gerekirse, düz veri yerine `ServerSentEvent` nesneleri yield edebilirsiniz.\n\n`ServerSentEvent`'i `fastapi.sse` içinden içe aktarın:\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\n`data` alanı her zaman JSON olarak kodlanır. Pydantic modelleri dâhil, JSON olarak serileştirilebilen herhangi bir değeri geçebilirsiniz.\n\n## Ham Veri { #raw-data }\n\nVeriyi JSON kodlaması olmadan göndermeniz gerekiyorsa, `data` yerine `raw_data` kullanın.\n\nBu, önceden biçimlendirilmiş metin, log satırları veya `[DONE]` gibi özel <dfn title=\"Özel bir koşulu veya durumu belirtmek için kullanılan değer\">\"işaretçi\"</dfn> değerleri göndermek için kullanışlıdır.\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note | Not\n\n`data` ve `raw_data` birbirini dışlar. Her `ServerSentEvent` için bunlardan yalnızca birini ayarlayabilirsiniz.\n\n///\n\n## `Last-Event-ID` ile Devam Etme { #resuming-with-last-event-id }\n\nBir tarayıcı bağlantı koptuktan sonra yeniden bağlandığında, son aldığı `id`'yi `Last-Event-ID` header'ında gönderir.\n\nBunu bir header parametresi olarak okuyup, istemcinin kaldığı yerden akışı sürdürmek için kullanabilirsiniz:\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## POST ile SSE { #sse-with-post }\n\nSSE, sadece `GET` değil, **tüm HTTP metodlarıyla** çalışır.\n\nBu, SSE'yi `POST` üzerinden akıtan [MCP](https://modelcontextprotocol.io) gibi protokoller için kullanışlıdır:\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## Teknik Detaylar { #technical-details }\n\nFastAPI, bazı SSE en iyi uygulamalarını kutudan çıktığı gibi uygular.\n\n- [HTML spesifikasyonu: Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes) önerisine uygun olarak, bazı proxy'lerin bağlantıyı kapatmasını önlemek için, 15 saniye boyunca hiç mesaj gelmezse **\"keep alive\" `ping` yorumu** gönderir.\n- Akışın **cache'lenmesini önlemek** için `Cache-Control: no-cache` header'ını ayarlar.\n- Nginx gibi bazı proxy'lerde **buffering'i önlemek** için özel `X-Accel-Buffering: no` header'ını ayarlar.\n\nBunun için ekstra bir şey yapmanız gerekmez, doğrudan çalışır. 🤓\n"
  },
  {
    "path": "docs/tr/docs/tutorial/sql-databases.md",
    "content": "# SQL (İlişkisel) Veritabanları { #sql-relational-databases }\n\n**FastAPI**, SQL (ilişkisel) bir veritabanı kullanmanızı zorunlu kılmaz. Ancak isterseniz **istediğiniz herhangi bir veritabanını** kullanabilirsiniz.\n\nBurada [SQLModel](https://sqlmodel.tiangolo.com/) kullanarak bir örnek göreceğiz.\n\n**SQLModel**, [SQLAlchemy](https://www.sqlalchemy.org/) ve Pydantic’in üzerine inşa edilmiştir. **FastAPI**’nin yazarı tarafından, **SQL veritabanları** kullanması gereken FastAPI uygulamalarıyla mükemmel uyum sağlaması için geliştirilmiştir.\n\n/// tip | İpucu\n\nİstediğiniz başka bir SQL veya NoSQL veritabanı kütüphanesini kullanabilirsiniz (bazı durumlarda <abbr title=\"Object Relational Mapper - Obje-İlişkisel Eşleyici: bazı sınıfların SQL tablolarını ve örneklerin bu tablolardaki satırları temsil ettiği bir kütüphane için süslü bir terim\">\"ORMs\"</abbr> olarak adlandırılır). FastAPI sizi hiçbir şeye zorlamaz. 😎\n\n///\n\nSQLModel, SQLAlchemy tabanlı olduğu için SQLAlchemy’nin **desteklediği herhangi bir veritabanını** kolayca kullanabilirsiniz (bu da SQLModel tarafından da desteklendikleri anlamına gelir), örneğin:\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server, vb.\n\nBu örnekte **SQLite** kullanacağız; çünkü tek bir dosya kullanır ve Python’da yerleşik desteği vardır. Yani bu örneği kopyalayıp olduğu gibi çalıştırabilirsiniz.\n\nDaha sonra, production uygulamanız için **PostgreSQL** gibi bir veritabanı sunucusu kullanmak isteyebilirsiniz.\n\n/// tip | İpucu\n\nFrontend ve daha fazla araçla birlikte **FastAPI** + **PostgreSQL** içeren resmi bir proje oluşturucu (project generator) var: [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\nBu çok basit ve kısa bir eğitimdir. Veritabanları genelinde, SQL hakkında veya daha ileri özellikler hakkında öğrenmek isterseniz [SQLModel dokümantasyonuna](https://sqlmodel.tiangolo.com/) gidin.\n\n## `SQLModel` Kurulumu { #install-sqlmodel }\n\nÖnce [virtual environment](../virtual-environments.md) oluşturduğunuzdan emin olun, aktive edin ve ardından `sqlmodel`’i yükleyin:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## Tek Model ile Uygulamayı Oluşturma { #create-the-app-with-a-single-model }\n\nÖnce, tek bir **SQLModel** modeliyle uygulamanın en basit ilk sürümünü oluşturacağız.\n\nAşağıda, **birden fazla model** kullanarak güvenliği ve esnekliği artırıp geliştireceğiz. 🤓\n\n### Modelleri Oluşturma { #create-models }\n\n`SQLModel`’i import edin ve bir veritabanı modeli oluşturun:\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\n`Hero` sınıfı, bir Pydantic modeline çok benzer (hatta altta aslında *bir Pydantic modelidir*).\n\nBirkaç fark var:\n\n* `table=True`, SQLModel’e bunun bir *table model* olduğunu söyler; SQL veritabanında bir **table**’ı temsil etmelidir, sadece bir *data model* değildir (diğer normal Pydantic sınıflarında olduğu gibi).\n\n* `Field(primary_key=True)`, SQLModel’e `id`’nin SQL veritabanındaki **primary key** olduğunu söyler (SQL primary key’leri hakkında daha fazlasını SQLModel dokümantasyonunda öğrenebilirsiniz).\n\n    **Not:** primary key alanı için `int | None` kullanıyoruz; böylece Python kodunda *`id` olmadan bir nesne oluşturabiliriz* (`id=None`) ve veritabanının *kaydederken bunu üreteceğini* varsayarız. SQLModel, veritabanının `id` sağlayacağını anlar ve *veritabanı şemasında sütunu null olamayan bir `INTEGER`* olarak tanımlar. Detaylar için [primary key’ler hakkında SQLModel dokümantasyonuna](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id) bakın.\n\n* `Field(index=True)`, SQLModel’e bu sütun için bir **SQL index** oluşturmasını söyler; bu da bu sütuna göre filtrelenmiş verileri okurken veritabanında daha hızlı arama yapılmasını sağlar.\n\n    SQLModel, `str` olarak tanımlanan bir şeyin SQL tarafında `TEXT` (veya veritabanına bağlı olarak `VARCHAR`) tipinde bir sütun olacağını bilir.\n\n### Engine Oluşturma { #create-an-engine }\n\nBir SQLModel `engine`’i (altta aslında bir SQLAlchemy `engine`’idir) veritabanına olan **bağlantıları tutan** yapıdır.\n\nTüm kodunuzun aynı veritabanına bağlanması için **tek bir `engine` nesnesi** kullanırsınız.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\n`check_same_thread=False` kullanmak, FastAPI’nin aynı SQLite veritabanını farklı thread’lerde kullanmasına izin verir. Bu gereklidir; çünkü **tek bir request** **birden fazla thread** kullanabilir (örneğin dependency’lerde).\n\nMerak etmeyin; kodun yapısı gereği, ileride **her request için tek bir SQLModel *session*** kullandığımızdan emin olacağız. Zaten `check_same_thread` de temelde bunu mümkün kılmaya çalışır.\n\n### Table’ları Oluşturma { #create-the-tables }\n\nSonra `SQLModel.metadata.create_all(engine)` kullanan bir fonksiyon ekleyerek tüm *table model*’ler için **table’ları oluştururuz**.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### Session Dependency’si Oluşturma { #create-a-session-dependency }\n\nBir **`Session`**, **nesneleri memory’de** tutar ve verideki gerekli değişiklikleri takip eder; ardından veritabanıyla iletişim kurmak için **`engine` kullanır**.\n\n`yield` ile, her request için yeni bir `Session` sağlayacak bir FastAPI **dependency** oluşturacağız. Bu da her request’te tek session kullanmamızı garanti eder. 🤓\n\nArdından bu dependency’yi kullanacak kodun geri kalanını sadeleştirmek için `Annotated` ile `SessionDep` dependency’sini oluştururuz.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### Startup’ta Veritabanı Table’larını Oluşturma { #create-database-tables-on-startup }\n\nUygulama başlarken veritabanı table’larını oluşturacağız.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\nBurada bir uygulama startup event’inde table’ları oluşturuyoruz.\n\nProduction’da büyük ihtimalle uygulamayı başlatmadan önce çalışan bir migration script’i kullanırsınız. 🤓\n\n/// tip | İpucu\n\nSQLModel, Alembic’i saran migration araçlarına sahip olacak; ancak şimdilik [Alembic](https://alembic.sqlalchemy.org/en/latest/)’i doğrudan kullanabilirsiniz.\n\n///\n\n### Hero Oluşturma { #create-a-hero }\n\nHer SQLModel modeli aynı zamanda bir Pydantic modeli olduğu için, Pydantic modelleriyle kullanabildiğiniz **type annotation**’larda aynı şekilde kullanabilirsiniz.\n\nÖrneğin `Hero` tipinde bir parametre tanımlarsanız, bu parametre **JSON body**’den okunur.\n\nAynı şekilde, bunu fonksiyonun **return type**’ı olarak da tanımlayabilirsiniz; böylece verinin şekli otomatik API docs arayüzünde görünür.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\nBurada `SessionDep` dependency’sini (bir `Session`) kullanarak yeni `Hero`’yu `Session` instance’ına ekliyoruz, değişiklikleri veritabanına commit ediyoruz, `hero` içindeki veriyi refresh ediyoruz ve sonra geri döndürüyoruz.\n\n### Hero’ları Okuma { #read-heroes }\n\n`select()` kullanarak veritabanından `Hero`’ları **okuyabiliriz**. Sonuçları sayfalama (pagination) yapmak için `limit` ve `offset` ekleyebiliriz.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### Tek Bir Hero Okuma { #read-one-hero }\n\nTek bir `Hero` **okuyabiliriz**.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### Hero Silme { #delete-a-hero }\n\nBir `Hero`’yu **silebiliriz**.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### Uygulamayı Çalıştırma { #run-the-app }\n\nUygulamayı çalıştırabilirsiniz:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nSonra `/docs` arayüzüne gidin; **FastAPI**’nin API’yi **dokümante etmek** için bu **modelleri** kullandığını göreceksiniz. Ayrıca veriyi **serialize** ve **validate** etmek için de onları kullanacaktır.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## Birden Fazla Model ile Uygulamayı Güncelleme { #update-the-app-with-multiple-models }\n\nŞimdi bu uygulamayı biraz **refactor** edelim ve **güvenliği** ile **esnekliği** artıralım.\n\nÖnceki uygulamaya bakarsanız, UI’da şu ana kadar client’ın oluşturulacak `Hero`’nun `id` değerini belirlemesine izin verdiğini görebilirsiniz. 😱\n\nBuna izin vermemeliyiz; DB’de zaten atanmış bir `id`’yi ezebilirler. `id` belirlemek **client** tarafından değil, **backend** veya **veritabanı** tarafından yapılmalıdır.\n\nAyrıca hero için bir `secret_name` oluşturuyoruz ama şimdiye kadar her yerde geri döndürüyoruz; bu pek de **secret** sayılmaz... 😅\n\nBunları birkaç **ek model** ekleyerek düzelteceğiz. SQLModel’in parlayacağı yer de burası. ✨\n\n### Birden Fazla Model Oluşturma { #create-multiple-models }\n\n**SQLModel**’de, `table=True` olan herhangi bir model sınıfı bir **table model**’dir.\n\n`table=True` olmayan her model sınıfı ise bir **data model**’dir; bunlar aslında sadece Pydantic modelleridir (bazı küçük ek özelliklerle). 🤓\n\nSQLModel ile **inheritance** kullanarak her durumda tüm alanları tekrar tekrar yazmaktan **kaçınabiliriz**.\n\n#### `HeroBase` - temel sınıf { #herobase-the-base-class }\n\nÖnce tüm modeller tarafından **paylaşılan alanları** içeren bir `HeroBase` modeliyle başlayalım:\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` - *table model* { #hero-the-table-model }\n\nSonra gerçek *table model* olan `Hero`’yu, diğer modellerde her zaman bulunmayan **ek alanlarla** oluşturalım:\n\n* `id`\n* `secret_name`\n\n`Hero`, `HeroBase`’ten miras aldığı için `HeroBase`’te tanımlanan alanlara da sahiptir. Dolayısıyla `Hero` için tüm alanlar:\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` - public *data model* { #heropublic-the-public-data-model }\n\nSonraki adımda `HeroPublic` modelini oluştururuz; bu model API client’larına **geri döndürülecek** modeldir.\n\n`HeroBase` ile aynı alanlara sahiptir; dolayısıyla `secret_name` içermez.\n\nSonunda kahramanlarımızın kimliği korunmuş oldu! 🥷\n\nAyrıca `id: int` alanını yeniden tanımlar. Bunu yaparak API client’larıyla bir **contract** (sözleşme) oluşturmuş oluruz; böylece `id` alanının her zaman var olacağını ve `int` olacağını (asla `None` olmayacağını) bilirler.\n\n/// tip | İpucu\n\nReturn model’in bir değerin her zaman mevcut olduğunu ve her zaman `int` olduğunu (`None` değil) garanti etmesi API client’ları için çok faydalıdır; bu kesinlik sayesinde daha basit kod yazabilirler.\n\nAyrıca **otomatik üretilen client**’ların arayüzleri de daha basit olur; böylece API’nizle çalışan geliştiriciler için süreç çok daha rahat olur. 😎\n\n///\n\n`HeroPublic` içindeki tüm alanlar `HeroBase` ile aynıdır; tek fark `id`’nin `int` olarak tanımlanmasıdır (`None` değil):\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` - hero oluşturmak için *data model* { #herocreate-the-data-model-to-create-a-hero }\n\nŞimdi `HeroCreate` modelini oluştururuz; bu model client’tan gelen veriyi **validate** etmek için kullanılır.\n\n`HeroBase` ile aynı alanlara sahiptir ve ek olarak `secret_name` içerir.\n\nArtık client’lar **yeni bir hero oluştururken** `secret_name` gönderecek; bu değer veritabanında saklanacak, ancak API response’larında client’a geri döndürülmeyecek.\n\n/// tip | İpucu\n\n**Password**’ları bu şekilde ele alırsınız: alırsınız ama API’de geri döndürmezsiniz.\n\nAyrıca password değerlerini saklamadan önce **hash** etmelisiniz; **asla plain text olarak saklamayın**.\n\n///\n\n`HeroCreate` alanları:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` - hero güncellemek için *data model* { #heroupdate-the-data-model-to-update-a-hero }\n\nUygulamanın önceki sürümünde bir hero’yu **güncellemenin** bir yolu yoktu; ancak artık **birden fazla model** ile bunu yapabiliriz. 🎉\n\n`HeroUpdate` *data model* biraz özeldir: yeni bir hero oluşturmak için gereken alanların **tamamına** sahiptir, ancak tüm alanlar **opsiyoneldir** (hepsinin bir default değeri vardır). Bu sayede hero güncellerken sadece güncellemek istediğiniz alanları gönderebilirsiniz.\n\nTüm **alanlar aslında değiştiği** için (tip artık `None` içeriyor ve default değerleri `None` oluyor), onları **yeniden tanımlamamız** gerekir.\n\nAslında `HeroBase`’ten miras almamız gerekmiyor; çünkü tüm alanları yeniden tanımlıyoruz. Tutarlılık için miras almayı bırakıyorum ama bu gerekli değil. Daha çok kişisel tercih meselesi. 🤷\n\n`HeroUpdate` alanları:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### `HeroCreate` ile Oluşturma ve `HeroPublic` Döndürme { #create-with-herocreate-and-return-a-heropublic }\n\nArtık **birden fazla model** olduğuna göre, onları kullanan uygulama kısımlarını güncelleyebiliriz.\n\nRequest’te bir `HeroCreate` *data model* alırız ve bundan bir `Hero` *table model* oluştururuz.\n\nBu yeni *table model* `Hero`, client’ın gönderdiği alanlara sahip olur ve ayrıca veritabanının ürettiği bir `id` alır.\n\nSonra fonksiyondan bu *table model* `Hero`’yu olduğu gibi döndürürüz. Ancak `response_model`’i `HeroPublic` *data model* olarak belirlediğimiz için **FastAPI**, veriyi validate ve serialize etmek için `HeroPublic` kullanır.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | İpucu\n\nBurada **return type annotation** `-> HeroPublic` yerine `response_model=HeroPublic` kullanıyoruz; çünkü gerçekte döndürdüğümüz değer *bir* `HeroPublic` değil.\n\nEğer `-> HeroPublic` yazsaydık, editörünüz ve linter’ınız (haklı olarak) `HeroPublic` yerine `Hero` döndürdüğünüz için şikayet edecekti.\n\nBunu `response_model` içinde belirterek **FastAPI**’ye işini yapmasını söylüyoruz; type annotation’lara ve editörünüzün/diğer araçların sağladığı desteğe karışmamış oluyoruz.\n\n///\n\n### `HeroPublic` ile Hero’ları Okuma { #read-heroes-with-heropublic }\n\nDaha öncekiyle aynı şekilde `Hero`’ları **okuyabiliriz**; yine `response_model=list[HeroPublic]` kullanarak verinin doğru biçimde validate ve serialize edilmesini garanti ederiz.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### `HeroPublic` ile Tek Bir Hero Okuma { #read-one-hero-with-heropublic }\n\nTek bir hero’yu **okuyabiliriz**:\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### `HeroUpdate` ile Hero Güncelleme { #update-a-hero-with-heroupdate }\n\nBir hero’yu **güncelleyebiliriz**. Bunun için HTTP `PATCH` operasyonu kullanırız.\n\nKodda, client’ın gönderdiği tüm verilerle bir `dict` alırız; **yalnızca client’ın gönderdiği veriler**, yani sadece default değer oldukları için orada bulunan değerler hariç. Bunu yapmak için `exclude_unset=True` kullanırız. Asıl numara bu. 🪄\n\nSonra `hero_db.sqlmodel_update(hero_data)` ile `hero_db`’yi `hero_data` içindeki verilerle güncelleriz.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### Hero’yu Tekrar Silme { #delete-a-hero-again }\n\nBir hero’yu **silmek** büyük ölçüde aynı kalıyor.\n\nBu örnekte her şeyi refactor etme isteğimizi bastıracağız. 😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### Uygulamayı Tekrar Çalıştırma { #run-the-app-again }\n\nUygulamayı tekrar çalıştırabilirsiniz:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n`/docs` API UI’a giderseniz artık güncellendiğini göreceksiniz; hero oluştururken client’tan `id` beklemeyecek, vb.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## Özet { #recap }\n\nBir SQL veritabanıyla etkileşim kurmak için [**SQLModel**](https://sqlmodel.tiangolo.com/) kullanabilir ve *data model* ile *table model* yaklaşımıyla kodu sadeleştirebilirsiniz.\n\n**SQLModel** dokümantasyonunda çok daha fazlasını öğrenebilirsiniz; **FastAPI** ile SQLModel kullanımı için daha uzun bir mini [tutorial](https://sqlmodel.tiangolo.com/tutorial/fastapi/) da bulunuyor. 🚀\n"
  },
  {
    "path": "docs/tr/docs/tutorial/static-files.md",
    "content": "# Statik Dosyalar { #static-files }\n\n`StaticFiles` kullanarak bir dizindeki statik dosyaları otomatik olarak sunabilirsiniz.\n\n## `StaticFiles` Kullanımı { #use-staticfiles }\n\n* `StaticFiles`'ı import edin.\n* Belirli bir path'te bir `StaticFiles()` örneğini \"mount\" edin.\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | Teknik Detaylar\n\n`from starlette.staticfiles import StaticFiles` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.staticfiles`'ı `fastapi.staticfiles` olarak da sağlar. Ancak aslında doğrudan Starlette'den gelir.\n\n///\n\n### \"Mounting\" Nedir { #what-is-mounting }\n\n\"Mounting\", belirli bir path'te tamamen \"bağımsız\" bir uygulama eklemek ve sonrasında tüm alt path'leri handle etmesini sağlamak demektir.\n\nBu, bir `APIRouter` kullanmaktan farklıdır; çünkü mount edilen uygulama tamamen bağımsızdır. Ana uygulamanızın OpenAPI ve docs'ları, mount edilen uygulamadan hiçbir şey içermez, vb.\n\nBununla ilgili daha fazla bilgiyi [Gelişmiş Kullanıcı Kılavuzu](../advanced/index.md) içinde okuyabilirsiniz.\n\n## Detaylar { #details }\n\nİlk `\"/static\"`, bu \"alt uygulamanın\" \"mount\" edileceği alt path'i ifade eder. Dolayısıyla `\"/static\"` ile başlayan herhangi bir path bunun tarafından handle edilir.\n\n`directory=\"static\"`, statik dosyalarınızı içeren dizinin adını ifade eder.\n\n`name=\"static\"`, **FastAPI**'nin dahili olarak kullanabileceği bir isim verir.\n\nBu parametrelerin hepsi \"`static`\" ile aynı olmak zorunda değildir; kendi uygulamanızın ihtiyaçlarına ve özel detaylarına göre ayarlayın.\n\n## Daha Fazla Bilgi { #more-info }\n\nDaha fazla detay ve seçenek için [Starlette'in Statik Dosyalar hakkındaki dokümanlarını](https://www.starlette.dev/staticfiles/) inceleyin.\n"
  },
  {
    "path": "docs/tr/docs/tutorial/stream-json-lines.md",
    "content": "# JSON Lines Akışı { #stream-json-lines }\n\nBir veri dizisini “akış” olarak göndermek istediğiniz durumlar olabilir; bunu **JSON Lines** ile yapabilirsiniz.\n\n/// info | Bilgi\n\nFastAPI 0.134.0 ile eklendi.\n\n///\n\n## Akış (Stream) Nedir? { #what-is-a-stream }\n\nVerileri “streaming” olarak göndermek, uygulamanızın tüm öğe dizisi hazır olmasını beklemeden, öğeleri istemciye göndermeye başlaması demektir.\n\nYani ilk öğeyi gönderirsiniz, istemci onu alıp işlemeye başlar, bu sırada siz bir sonraki öğeyi üretmeye devam edebilirsiniz.\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\nHatta, sürekli veri gönderdiğiniz sonsuz bir akış da olabilir.\n\n## JSON Lines { #json-lines }\n\nBu tür durumlarda, her satıra bir JSON nesnesi gönderdiğiniz bir biçim olan “**JSON Lines**” kullanmak yaygındır.\n\nResponse’un `application/json` yerine `application/jsonl` içerik türü (Content-Type) olur ve body aşağıdaki gibi görünür:\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\nBir JSON dizisine (Python list eşdeğeri) çok benzer; ancak öğeler `[]` içine alınmak ve araya `,` konmak yerine, her satırda **bir JSON nesnesi** vardır; bunlar yeni satır karakteri ile ayrılır.\n\n/// info | Bilgi\n\nÖnemli nokta, uygulamanız her satırı sırayla üretebilirken, istemcinin de önceki satırları tüketmeye devam edebilmesidir.\n\n///\n\n/// note | Teknik Detaylar\n\nHer JSON nesnesi yeni bir satırla ayrıldığı için, içeriklerinde gerçek yeni satır karakterleri bulunamaz; ancak JSON standardının bir parçası olan kaçışlı yeni satırlar (`\\n`) bulunabilir.\n\nGenelde bununla sizin uğraşmanız gerekmez, otomatik olarak halledilir, okumaya devam edin. 🤓\n\n///\n\n## Kullanım Senaryoları { #use-cases }\n\nBunu bir **AI LLM** servisinden, **loglar**dan veya **telemetri**den ya da **JSON** öğeleri halinde yapılandırılabilen başka tür verilerden akış yapmak için kullanabilirsiniz.\n\n/// tip | İpucu\n\nİkili (binary) veri akışı yapmak istiyorsanız, örneğin video veya ses, gelişmiş kılavuza bakın: [Veri Akışı](../advanced/stream-data.md).\n\n///\n\n## FastAPI ile JSON Lines Akışı { #stream-json-lines-with-fastapi }\n\nFastAPI ile JSON Lines akışı yapmak için, *path operation function* içinde `return` kullanmak yerine, her öğeyi sırayla üretmek için `yield` kullanabilirsiniz.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\nGöndermek istediğiniz her JSON öğesi `Item` tipindeyse (bir Pydantic modeli) ve fonksiyon async ise, dönüş tipini `AsyncIterable[Item]` olarak belirtebilirsiniz:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\nDönüş tipini belirtirseniz, FastAPI bu tipi kullanarak veriyi **doğrular**, OpenAPI’de **dokümante** eder, **filtreler** ve Pydantic ile **serileştirir**.\n\n/// tip | İpucu\n\nPydantic serileştirmeyi **Rust** tarafında yapacağı için, dönüş tipi belirtmediğiniz duruma göre çok daha yüksek **performans** elde edersiniz.\n\n///\n\n### Async Olmayan path operation function'lar { #non-async-path-operation-functions }\n\n`async` olmadan normal `def` fonksiyonları da kullanabilir ve aynı şekilde `yield` yazabilirsiniz.\n\nFastAPI, event loop’u bloklamayacak şekilde doğru çalışmasını garanti eder.\n\nBu durumda fonksiyon async olmadığı için doğru dönüş tipi `Iterable[Item]` olur:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### Dönüş Tipi Olmadan { #no-return-type }\n\nDönüş tipini belirtmeyebilirsiniz de. Bu durumda FastAPI, veriyi JSON’a serileştirilebilir bir yapıya dönüştürmek için [`jsonable_encoder`](./encoder.md)’ı kullanır ve ardından JSON Lines olarak gönderir.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## Server-Sent Events (SSE) { #server-sent-events-sse }\n\nFastAPI, Server-Sent Events (SSE) için de birinci sınıf destek sağlar; benzerlerdir ancak birkaç ekstra ayrıntı vardır. Bir sonraki bölümden öğrenebilirsiniz: [Server-Sent Events (SSE)](server-sent-events.md). 🤓\n"
  },
  {
    "path": "docs/tr/docs/tutorial/testing.md",
    "content": "# Test Etme { #testing }\n\n[Starlette](https://www.starlette.dev/testclient/) sayesinde **FastAPI** uygulamalarını test etmek kolay ve keyiflidir.\n\nTemelde [HTTPX](https://www.python-httpx.org) üzerine kuruludur; HTTPX de Requests’i temel alarak tasarlandığı için oldukça tanıdık ve sezgiseldir.\n\nBununla birlikte **FastAPI** ile [pytest](https://docs.pytest.org/)'i doğrudan kullanabilirsiniz.\n\n## `TestClient` Kullanımı { #using-testclient }\n\n/// info | Bilgi\n\n`TestClient` kullanmak için önce [`httpx`](https://www.python-httpx.org)'i kurun.\n\nBir [Sanal Ortam](../virtual-environments.md) oluşturduğunuzdan, onu aktifleştirdiğinizden ve sonra kurulumu yaptığınızdan emin olun; örneğin:\n\n```console\n$ pip install httpx\n```\n\n///\n\n`TestClient`'ı import edin.\n\n**FastAPI** uygulamanızı ona vererek bir `TestClient` oluşturun.\n\nAdı `test_` ile başlayan fonksiyonlar oluşturun (bu, `pytest`'in standart konvansiyonudur).\n\n`TestClient` nesnesini `httpx` ile kullandığınız şekilde kullanın.\n\nKontrol etmeniz gereken şeyler için standart Python ifadeleriyle basit `assert` satırları yazın (bu da `pytest` standardıdır).\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip | İpucu\n\nTest fonksiyonlarının `async def` değil, normal `def` olduğuna dikkat edin.\n\nClient'a yapılan çağrılar da `await` kullanılmadan, normal çağrılardır.\n\nBu sayede `pytest`'i ek bir karmaşıklık olmadan doğrudan kullanabilirsiniz.\n\n///\n\n/// note | Teknik Detaylar\n\nİsterseniz `from starlette.testclient import TestClient` da kullanabilirsiniz.\n\n**FastAPI**, geliştirici olarak size kolaylık olsun diye `starlette.testclient`'ı `fastapi.testclient` üzerinden de sunar. Ancak asıl kaynak doğrudan Starlette'tır.\n\n///\n\n/// tip | İpucu\n\nFastAPI uygulamanıza request göndermenin dışında testlerinizde `async` fonksiyonlar çağırmak istiyorsanız (örn. asenkron veritabanı fonksiyonları), ileri seviye bölümdeki [Asenkron Testler](../advanced/async-tests.md) dokümanına göz atın.\n\n///\n\n## Testleri Ayırma { #separating-tests }\n\nGerçek bir uygulamada testlerinizi büyük ihtimalle farklı bir dosyada tutarsınız.\n\nAyrıca **FastAPI** uygulamanız birden fazla dosya/modül vb. ile de oluşturulmuş olabilir.\n\n### **FastAPI** Uygulama Dosyası { #fastapi-app-file }\n\n[Daha Büyük Uygulamalar](bigger-applications.md)'te anlatılan şekilde bir dosya yapınız olduğunu varsayalım:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\n`main.py` dosyasında **FastAPI** uygulamanız bulunuyor olsun:\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### Test Dosyası { #testing-file }\n\nSonra testlerinizin olduğu bir `test_main.py` dosyanız olabilir. Bu dosya aynı Python package içinde (yani `__init__.py` dosyası olan aynı dizinde) durabilir:\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nBu dosya aynı package içinde olduğu için, `main` modülünden (`main.py`) `app` nesnesini import etmek üzere relative import kullanabilirsiniz:\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n...ve test kodunu da öncekiyle aynı şekilde yazabilirsiniz.\n\n## Test Etme: Genişletilmiş Örnek { #testing-extended-example }\n\nŞimdi bu örneği genişletelim ve farklı parçaların nasıl test edildiğini görmek için daha fazla detay ekleyelim.\n\n### Genişletilmiş **FastAPI** Uygulama Dosyası { #extended-fastapi-app-file }\n\nAynı dosya yapısıyla devam edelim:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nDiyelim ki **FastAPI** uygulamanızın bulunduğu `main.py` dosyasında artık başka **path operations** da var.\n\nHata döndürebilecek bir `GET` operation'ı var.\n\nBirden fazla farklı hata döndürebilecek bir `POST` operation'ı var.\n\nHer iki *path operation* da `X-Token` header'ını gerektiriyor.\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### Genişletilmiş Test Dosyası { #extended-testing-file }\n\nSonrasında `test_main.py` dosyanızı genişletilmiş testlerle güncelleyebilirsiniz:\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\nClient'ın request içinde bir bilgi göndermesi gerektiğinde ve bunu nasıl yapacağınızı bilemediğinizde, `httpx` ile nasıl yapılacağını aratabilirsiniz (Google) ya da HTTPX’in tasarımı Requests’e dayandığı için `requests` ile nasıl yapıldığını da arayabilirsiniz.\n\nSonra testlerinizde aynısını uygularsınız.\n\nÖrn.:\n\n* Bir *path* veya *query* parametresi geçirmek için, URL’nin kendisine ekleyin.\n* JSON body göndermek için, `json` parametresine bir Python nesnesi (örn. bir `dict`) verin.\n* JSON yerine *Form Data* göndermeniz gerekiyorsa, bunun yerine `data` parametresini kullanın.\n* *headers* göndermek için, `headers` parametresine bir `dict` verin.\n* *cookies* için, `cookies` parametresine bir `dict` verin.\n\nBackend'e veri geçme hakkında daha fazla bilgi için (`httpx` veya `TestClient` kullanarak) [HTTPX dokümantasyonu](https://www.python-httpx.org)'na bakın.\n\n/// info | Bilgi\n\n`TestClient`'ın Pydantic model'lerini değil, JSON'a dönüştürülebilen verileri aldığını unutmayın.\n\nTestinizde bir Pydantic model'iniz varsa ve test sırasında verisini uygulamaya göndermek istiyorsanız, [JSON Uyumlu Encoder](encoder.md) içinde açıklanan `jsonable_encoder`'ı kullanabilirsiniz.\n\n///\n\n## Çalıştırma { #run-it }\n\nBundan sonra yapmanız gereken tek şey `pytest`'i kurmaktır.\n\nBir [Sanal Ortam](../virtual-environments.md) oluşturduğunuzdan, onu aktifleştirdiğinizden ve sonra kurulumu yaptığınızdan emin olun; örneğin:\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\nDosyaları ve testleri otomatik olarak bulur, çalıştırır ve sonuçları size raporlar.\n\nTestleri şu şekilde çalıştırın:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/tr/docs/virtual-environments.md",
    "content": "# Virtual Environments { #virtual-environments }\n\nPython projeleriyle çalışırken, her proje için kurduğunuz package'leri birbirinden izole etmek adına büyük ihtimalle bir **virtual environment** (veya benzer bir mekanizma) kullanmalısınız.\n\n/// info | Bilgi\n\nVirtual environment'leri, nasıl oluşturulduklarını ve nasıl kullanıldıklarını zaten biliyorsanız bu bölümü atlamak isteyebilirsiniz. 🤓\n\n///\n\n/// tip | İpucu\n\n**Virtual environment**, **environment variable** ile aynı şey değildir.\n\n**Environment variable**, sistemde bulunan ve programların kullanabildiği bir değişkendir.\n\n**Virtual environment** ise içinde bazı dosyalar bulunan bir klasördür.\n\n///\n\n/// info | Bilgi\n\nBu sayfada **virtual environment**'leri nasıl kullanacağınızı ve nasıl çalıştıklarını öğreneceksiniz.\n\nEğer Python'ı kurmak dahil her şeyi sizin yerinize yöneten bir **tool** kullanmaya hazırsanız, [uv](https://github.com/astral-sh/uv)'yi deneyin.\n\n///\n\n## Proje Oluşturun { #create-a-project }\n\nÖnce projeniz için bir klasör oluşturun.\n\nBen genelde home/user klasörümün içinde `code` adlı bir klasör oluştururum.\n\nSonra bunun içinde her proje için ayrı bir klasör oluştururum.\n\n<div class=\"termy\">\n\n```console\n// Go to the home directory\n$ cd\n// Create a directory for all your code projects\n$ mkdir code\n// Enter into that code directory\n$ cd code\n// Create a directory for this project\n$ mkdir awesome-project\n// Enter into that project directory\n$ cd awesome-project\n```\n\n</div>\n\n## Virtual Environment Oluşturun { #create-a-virtual-environment }\n\nBir Python projesi üzerinde **ilk kez** çalışmaya başladığınızda, **virtual environment**'i <dfn title=\"başka seçenekler de var, bu basit bir yönergedir\">projenizin içinde</dfn> oluşturun.\n\n/// tip | İpucu\n\nBunu her çalıştığınızda değil, **proje başına sadece bir kez** yapmanız yeterlidir.\n\n///\n\n//// tab | `venv`\n\nBir virtual environment oluşturmak için, Python ile birlikte gelen `venv` modülünü kullanabilirsiniz.\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | Bu komut ne anlama geliyor\n\n* `python`: `python` adlı programı kullan\n* `-m`: bir modülü script gibi çalıştır; bir sonraki kısımda hangi modül olduğunu söyleyeceğiz\n* `venv`: normalde Python ile birlikte kurulu gelen `venv` modülünü kullan\n* `.venv`: virtual environment'i yeni `.venv` klasörünün içine oluştur\n\n///\n\n////\n\n//// tab | `uv`\n\nEğer [`uv`](https://github.com/astral-sh/uv) kuruluysa, onunla da virtual environment oluşturabilirsiniz.\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip | İpucu\n\nVarsayılan olarak `uv`, `.venv` adlı bir klasörde virtual environment oluşturur.\n\nAncak ek bir argümanla klasör adını vererek bunu özelleştirebilirsiniz.\n\n///\n\n////\n\nBu komut `.venv` adlı bir klasörün içinde yeni bir virtual environment oluşturur.\n\n/// details | `.venv` veya başka bir ad\n\nVirtual environment'i başka bir klasörde de oluşturabilirsiniz; ancak buna `.venv` demek yaygın bir konvansiyondur.\n\n///\n\n## Virtual Environment'i Aktif Edin { #activate-the-virtual-environment }\n\nOluşturduğunuz virtual environment'i aktif edin; böylece çalıştırdığınız her Python komutu veya kurduğunuz her package onu kullanır.\n\n/// tip | İpucu\n\nProjede çalışmak için **yeni bir terminal oturumu** başlattığınız **her seferinde** bunu yapın.\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nYa da Windows'ta Bash kullanıyorsanız (örn. [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip | İpucu\n\nBu environment'e **yeni bir package** kurduğunuz her seferinde environment'i yeniden **aktif edin**.\n\nBöylece, o package'in kurduğu bir **terminal (<abbr title=\"command line interface - Komut Satırı Arayüzü\">CLI</abbr>) programı** kullanıyorsanız, global olarak kurulu (ve muhtemelen ihtiyacınız olandan farklı bir versiyona sahip) başka bir program yerine, virtual environment'inizdeki programı kullanmış olursunuz.\n\n///\n\n## Virtual Environment'in Aktif Olduğunu Kontrol Edin { #check-the-virtual-environment-is-active }\n\nVirtual environment'in aktif olduğunu (bir önceki komutun çalıştığını) kontrol edin.\n\n/// tip | İpucu\n\nBu **opsiyoneldir**; ancak her şeyin beklendiği gibi çalıştığını ve hedeflediğiniz virtual environment'i kullandığınızı **kontrol etmek** için iyi bir yöntemdir.\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\nEğer `python` binary'sini projenizin içinde (bu örnekte `awesome-project`) `.venv/bin/python` yolunda gösteriyorsa, tamamdır. 🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\nEğer `python` binary'sini projenizin içinde (bu örnekte `awesome-project`) `.venv\\Scripts\\python` yolunda gösteriyorsa, tamamdır. 🎉\n\n////\n\n## `pip`'i Yükseltin { #upgrade-pip }\n\n/// tip | İpucu\n\n[`uv`](https://github.com/astral-sh/uv) kullanıyorsanız, `pip` yerine onunla kurulum yaparsınız; dolayısıyla `pip`'i yükseltmeniz gerekmez. 😎\n\n///\n\nPackage'leri kurmak için `pip` kullanıyorsanız (Python ile varsayılan olarak gelir), en güncel sürüme **yükseltmeniz** gerekir.\n\nBir package kurarken görülen birçok garip hata, önce `pip`'i yükseltince çözülür.\n\n/// tip | İpucu\n\nBunu genelde virtual environment'i oluşturduktan hemen sonra **bir kez** yaparsınız.\n\n///\n\nVirtual environment'in aktif olduğundan emin olun (yukarıdaki komutla) ve sonra şunu çalıştırın:\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip | İpucu\n\nBazen pip'i yükseltmeye çalışırken **`No module named pip`** hatası alabilirsiniz.\n\nBöyle olursa, aşağıdaki komutla pip'i kurup yükseltin:\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\nBu komut pip kurulu değilse kurar ve ayrıca kurulu pip sürümünün `ensurepip` içinde bulunan sürüm kadar güncel olmasını garanti eder.\n\n///\n\n## `.gitignore` Ekleyin { #add-gitignore }\n\n**Git** kullanıyorsanız (kullanmalısınız), `.venv` içindeki her şeyi Git'ten hariç tutmak için bir `.gitignore` dosyası ekleyin.\n\n/// tip | İpucu\n\nVirtual environment'i [`uv`](https://github.com/astral-sh/uv) ile oluşturduysanız, bunu zaten sizin için yaptı; bu adımı atlayabilirsiniz. 😎\n\n///\n\n/// tip | İpucu\n\nBunu virtual environment'i oluşturduktan hemen sonra **bir kez** yapın.\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | Bu komut ne anlama geliyor\n\n* `echo \"*\"`: terminale `*` metnini \"yazar\" (sonraki kısım bunu biraz değiştiriyor)\n* `>`: `>` işaretinin solundaki komutun terminale yazdıracağı çıktı, ekrana basılmak yerine sağ taraftaki dosyaya yazılsın\n* `.gitignore`: metnin yazılacağı dosyanın adı\n\nGit'te `*` \"her şey\" demektir. Yani `.venv` klasörü içindeki her şeyi ignore eder.\n\nBu komut, içeriği şu olan bir `.gitignore` dosyası oluşturur:\n\n```gitignore\n*\n```\n\n///\n\n## Package'leri Kurun { #install-packages }\n\nEnvironment'i aktif ettikten sonra, içine package kurabilirsiniz.\n\n/// tip | İpucu\n\nProjede ihtiyaç duyduğunuz package'leri ilk kez kurarken veya yükseltirken bunu **bir kez** yapın.\n\nBir sürümü yükseltmeniz veya yeni bir package eklemeniz gerekirse **tekrar** yaparsınız.\n\n///\n\n### Package'leri Doğrudan Kurun { #install-packages-directly }\n\nAcele ediyorsanız ve projenizin package gereksinimlerini bir dosyada belirtmek istemiyorsanız, doğrudan kurabilirsiniz.\n\n/// tip | İpucu\n\nProgramınızın ihtiyaç duyduğu package'leri ve versiyonlarını bir dosyada tutmak (ör. `requirements.txt` veya `pyproject.toml`) (çok) iyi bir fikirdir.\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nEğer [`uv`](https://github.com/astral-sh/uv) varsa:\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### `requirements.txt`'ten Kurun { #install-from-requirements-txt }\n\nBir `requirements.txt` dosyanız varsa, içindeki package'leri kurmak için artık onu kullanabilirsiniz.\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nEğer [`uv`](https://github.com/astral-sh/uv) varsa:\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\nBazı package'ler içeren bir `requirements.txt` şöyle görünebilir:\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## Programınızı Çalıştırın { #run-your-program }\n\nVirtual environment'i aktif ettikten sonra programınızı çalıştırabilirsiniz; program, virtual environment'in içindeki Python'ı ve oraya kurduğunuz package'leri kullanır.\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## Editörünüzü Yapılandırın { #configure-your-editor }\n\nMuhtemelen bir editör kullanırsınız; otomatik tamamlamayı ve satır içi hataları alabilmek için, editörünüzü oluşturduğunuz aynı virtual environment'i kullanacak şekilde yapılandırdığınızdan emin olun (muhtemelen otomatik algılar).\n\nÖrneğin:\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip | İpucu\n\nBunu genelde yalnızca **bir kez**, virtual environment'i oluşturduğunuzda yapmanız gerekir.\n\n///\n\n## Virtual Environment'i Devre Dışı Bırakın { #deactivate-the-virtual-environment }\n\nProjeniz üzerinde işiniz bittiğinde virtual environment'i **deactivate** edebilirsiniz.\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\nBöylece `python` çalıştırdığınızda, o virtual environment içinden (ve oraya kurulu package'lerle) çalıştırmaya çalışmaz.\n\n## Çalışmaya Hazırsınız { #ready-to-work }\n\nArtık projeniz üzerinde çalışmaya başlayabilirsiniz.\n\n/// tip | İpucu\n\nYukarıdaki her şeyin aslında ne olduğunu anlamak ister misiniz?\n\nOkumaya devam edin. 👇🤓\n\n///\n\n## Neden Virtual Environment { #why-virtual-environments }\n\nFastAPI ile çalışmak için [Python](https://www.python.org/) kurmanız gerekir.\n\nSonrasında FastAPI'yi ve kullanmak istediğiniz diğer tüm **package**'leri **kurmanız** gerekir.\n\nPackage kurmak için genelde Python ile gelen `pip` komutunu (veya benzeri alternatifleri) kullanırsınız.\n\nAncak `pip`'i doğrudan kullanırsanız, package'ler **global Python environment**'ınıza (Python'ın global kurulumuna) yüklenir.\n\n### Problem { #the-problem }\n\nPeki package'leri global Python environment'a kurmanın sorunu ne?\n\nBir noktada, muhtemelen **farklı package**'lere bağımlı birçok farklı program yazacaksınız. Ayrıca üzerinde çalıştığınız bazı projeler, aynı package'in **farklı versiyonlarına** ihtiyaç duyacak. 😱\n\nÖrneğin `philosophers-stone` adında bir proje oluşturduğunuzu düşünün; bu program, `harry` adlı başka bir package'e **`1` versiyonu ile** bağlı. Yani `harry`'yi kurmanız gerekir.\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n\nSonra daha ileri bir zamanda `prisoner-of-azkaban` adlı başka bir proje oluşturuyorsunuz; bu proje de `harry`'ye bağlı, fakat bu proje **`harry` versiyon `3`** istiyor.\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]\n```\n\nŞimdi sorun şu: package'leri local bir **virtual environment** yerine global (global environment) olarak kurarsanız, `harry`'nin hangi versiyonunu kuracağınıza karar vermek zorunda kalırsınız.\n\n`philosophers-stone`'u çalıştırmak istiyorsanız önce `harry` versiyon `1`'i kurmanız gerekir; örneğin:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\nSonuç olarak global Python environment'ınızda `harry` versiyon `1` kurulu olur.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\nFakat `prisoner-of-azkaban`'ı çalıştırmak istiyorsanız, `harry` versiyon `1`'i kaldırıp `harry` versiyon `3`'ü kurmanız gerekir (ya da sadece `3`'ü kurmak, otomatik olarak `1`'i kaldırabilir).\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\nSonuç olarak global Python environment'ınızda `harry` versiyon `3` kurulu olur.\n\nVe `philosophers-stone`'u tekrar çalıştırmaya kalkarsanız, `harry` versiyon `1`e ihtiyaç duyduğu için **çalışmama** ihtimali vardır.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --> |requires| harry-3\n    end\n```\n\n/// tip | İpucu\n\nPython package'lerinde **yeni versiyonlarda** **breaking change**'lerden kaçınmak oldukça yaygındır; ancak yine de daha güvenlisi, yeni versiyonları bilinçli şekilde kurmak ve mümkünse test'leri çalıştırıp her şeyin doğru çalıştığını doğrulamaktır.\n\n///\n\nŞimdi bunu, **projelerinizin bağımlı olduğu** daha **birçok** başka **package** ile birlikte düşünün. Yönetmesi epey zorlaşır. Sonunda bazı projeleri package'lerin **uyumsuz versiyonlarıyla** çalıştırıp, bir şeylerin neden çalışmadığını anlamamak gibi durumlara düşebilirsiniz.\n\nAyrıca işletim sisteminize (örn. Linux, Windows, macOS) bağlı olarak Python zaten kurulu gelmiş olabilir. Bu durumda, sisteminizin **ihtiyaç duyduğu** bazı package'ler belirli versiyonlarla önceden kurulu olabilir. Global Python environment'a package kurarsanız, işletim sistemiyle gelen bazı programları **bozma** ihtimaliniz olabilir.\n\n## Package'ler Nereye Kuruluyor { #where-are-packages-installed }\n\nPython'ı kurduğunuzda, bilgisayarınızda bazı dosyalar içeren klasörler oluşturulur.\n\nBu klasörlerin bir kısmı, kurduğunuz tüm package'leri barındırmaktan sorumludur.\n\nŞunu çalıştırdığınızda:\n\n<div class=\"termy\">\n\n```console\n// Don't run this now, it's just an example 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\nBu, FastAPI kodunu içeren sıkıştırılmış bir dosyayı genellikle [PyPI](https://pypi.org/project/fastapi/)'dan indirir.\n\nAyrıca FastAPI'nin bağımlı olduğu diğer package'ler için de dosyaları **indirir**.\n\nSonra tüm bu dosyaları **açar (extract)** ve bilgisayarınızdaki bir klasöre koyar.\n\nVarsayılan olarak bu indirilip çıkarılan dosyaları, Python kurulumunuzla birlikte gelen klasöre yerleştirir; yani **global environment**'a.\n\n## Virtual Environment Nedir { #what-are-virtual-environments }\n\nGlobal environment'da tüm package'leri bir arada tutmanın sorunlarına çözüm, çalıştığınız her proje için ayrı bir **virtual environment** kullanmaktır.\n\nVirtual environment, global olana çok benzeyen bir **klasördür**; bir projenin ihtiyaç duyduğu package'leri buraya kurarsınız.\n\nBöylece her projenin kendi virtual environment'i (`.venv` klasörü) ve kendi package'leri olur.\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) --->|requires| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --->|requires| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## Virtual Environment'i Aktif Etmek Ne Demek { #what-does-activating-a-virtual-environment-mean }\n\nBir virtual environment'i örneğin şununla aktif ettiğinizde:\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nYa da Windows'ta Bash kullanıyorsanız (örn. [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\nBu komut, sonraki komutlarda kullanılabilecek bazı [environment variable](environment-variables.md)'ları oluşturur veya değiştirir.\n\nBunlardan biri `PATH` değişkenidir.\n\n/// tip | İpucu\n\n`PATH` environment variable hakkında daha fazla bilgiyi [Environment Variables](environment-variables.md#path-environment-variable) bölümünde bulabilirsiniz.\n\n///\n\nBir virtual environment'i aktive etmek, onun `.venv/bin` (Linux ve macOS'ta) veya `.venv\\Scripts` (Windows'ta) yolunu `PATH` environment variable'ına ekler.\n\nDiyelim ki environment'i aktive etmeden önce `PATH` değişkeni şöyleydi:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nBu, sistemin programları şu klasörlerde arayacağı anlamına gelir:\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\nBu, sistemin programları şurada arayacağı anlamına gelir:\n\n* `C:\\Windows\\System32`\n\n////\n\nVirtual environment'i aktive ettikten sonra `PATH` değişkeni şuna benzer hale gelir:\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nBu, sistemin artık programları önce şurada aramaya başlayacağı anlamına gelir:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\ndiğer klasörlere bakmadan önce.\n\nDolayısıyla terminale `python` yazdığınızda, sistem Python programını şurada bulur:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\nve onu kullanır.\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\nBu, sistemin artık programları önce şurada aramaya başlayacağı anlamına gelir:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\ndiğer klasörlere bakmadan önce.\n\nDolayısıyla terminale `python` yazdığınızda, sistem Python programını şurada bulur:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\nve onu kullanır.\n\n////\n\nÖnemli bir detay: virtual environment yolu `PATH` değişkeninin **en başına** eklenir. Sistem, mevcut başka herhangi bir Python'ı bulmadan **önce** bunu bulur. Böylece `python` çalıştırdığınızda, başka bir `python` (örneğin global environment'tan gelen `python`) yerine **virtual environment'taki** Python kullanılır.\n\nVirtual environment'i aktive etmek birkaç şeyi daha değiştirir; ancak yaptığı en önemli işlerden biri budur.\n\n## Virtual Environment'i Kontrol Etmek { #checking-a-virtual-environment }\n\nBir virtual environment'in aktif olup olmadığını örneğin şununla kontrol ettiğinizde:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\nBu, kullanılacak `python` programının **virtual environment'in içindeki** Python olduğu anlamına gelir.\n\nLinux ve macOS'ta `which`, Windows PowerShell'de ise `Get-Command` kullanırsınız.\n\nBu komutun çalışma mantığı şudur: `PATH` environment variable içindeki **her yolu sırayla** dolaşır, `python` adlı programı arar. Bulduğunda, size o programın **dosya yolunu** gösterir.\n\nEn önemli kısım şu: `python` dediğinizde çalışacak olan \"`python`\" tam olarak budur.\n\nYani doğru virtual environment'da olup olmadığınızı doğrulayabilirsiniz.\n\n/// tip | İpucu\n\nBir virtual environment'i aktive etmek kolaydır; sonra o Python ile kalıp **başka bir projeye geçmek** de kolaydır.\n\nBu durumda ikinci proje, başka bir projenin virtual environment'ından gelen **yanlış Python**'ı kullandığınız için **çalışmayabilir**.\n\nHangi `python`'ın kullanıldığını kontrol edebilmek bu yüzden faydalıdır. 🤓\n\n///\n\n## Neden Virtual Environment'i Deactivate Edelim { #why-deactivate-a-virtual-environment }\n\nÖrneğin `philosophers-stone` projesi üzerinde çalışıyor olabilirsiniz; **o virtual environment'i aktive eder**, package kurar ve o environment ile çalışırsınız.\n\nSonra **başka bir proje** olan `prisoner-of-azkaban` üzerinde çalışmak istersiniz.\n\nO projeye gidersiniz:\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\nEğer `philosophers-stone` için olan virtual environment'i deactivate etmezseniz, terminalde `python` çalıştırdığınızda `philosophers-stone`'dan gelen Python'ı kullanmaya çalışır.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// Error importing sirius, it's not installed 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\nAma virtual environment'i deactivate edip `prisoner-of-askaban` için yeni olanı aktive ederseniz, `python` çalıştırdığınızda `prisoner-of-azkaban` içindeki virtual environment'dan gelen Python kullanılır.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// You don't need to be in the old directory to deactivate, you can do it wherever you are, even after going to the other project 😎\n$ deactivate\n\n// Activate the virtual environment in prisoner-of-azkaban/.venv 🚀\n$ source .venv/bin/activate\n\n// Now when you run python, it will find the package sirius installed in this virtual environment ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## Alternatifler { #alternatives }\n\nBu, başlamanız için basit bir rehber ve alttaki mekanizmaların nasıl çalıştığını öğretmeyi amaçlıyor.\n\nVirtual environment'leri, package bağımlılıklarını (requirements) ve projeleri yönetmek için birçok **alternatif** vardır.\n\nHazır olduğunuzda ve package bağımlılıkları, virtual environment'ler vb. dahil **tüm projeyi yönetmek** için bir tool kullanmak istediğinizde, [uv](https://github.com/astral-sh/uv)'yi denemenizi öneririm.\n\n`uv` birçok şey yapabilir, örneğin:\n\n* Sizin için **Python kurabilir**, farklı sürümler dahil\n* Projelerinizin **virtual environment**'ini yönetebilir\n* **Package** kurabilir\n* Projeniz için package **bağımlılıklarını ve versiyonlarını** yönetebilir\n* Bağımlılıkları dahil, kurulacak package ve versiyonların **tam (exact)** bir setini garanti edebilir; böylece geliştirirken bilgisayarınızda çalıştırdığınız projeyi production'da da birebir aynı şekilde çalıştırabileceğinizden emin olursunuz; buna **locking** denir\n* Ve daha birçok şey\n\n## Sonuç { #conclusion }\n\nBuradaki her şeyi okuduysanız ve anladıysanız, artık birçok geliştiriciden **çok daha fazla** virtual environment bilgisine sahipsiniz. 🤓\n\nBu detayları bilmek, ileride karmaşık görünen bir sorunu debug ederken büyük olasılıkla işinize yarayacak; çünkü **altta nasıl çalıştığını** biliyor olacaksınız. 😎\n"
  },
  {
    "path": "docs/tr/llm-prompt.md",
    "content": "### Target language\n\nTranslate to Turkish (Türkçe).\n\nLanguage code: tr.\n\n### Core principle\n\nDon't translate word-by-word. Rewrite naturally in Turkish as if writing the doc from scratch. Preserve meaning, but prioritize fluency over literal accuracy.\n\n### Grammar and tone\n\n- Use instructional Turkish, consistent with existing Turkish docs.\n- Use imperative/guide language (e.g. \"açalım\", \"gidin\", \"kopyalayalım\", \"bir bakalım\").\n- Avoid filler words and overly long sentences.\n- Ensure sentences make sense in Turkish context — adjust structure, conjunctions, and verb forms as needed for natural flow (e.g. use \"Ancak\" instead of \"Ve\" when connecting contrasting sentences, use \"-maktadır/-mektedir\" for formal statements).\n\n### Headings\n\n- Follow existing Turkish heading style (Title Case where used; no trailing period).\n\n### Quotes\n\n- Keep quote style consistent with existing Turkish docs (typically ASCII quotes in text).\n- Never modify quotes inside inline code, code blocks, URLs, or file paths.\n\n### Ellipsis\n\n- Keep ellipsis style (`...`) consistent with existing Turkish docs.\n- Never modify `...` in code, URLs, or CLI examples.\n\n### Consistency\n\n- Use the same translation for the same term throughout the document.\n- If you translate a concept one way, keep it consistent across all occurrences.\n\n### Links and references\n\n- Never modify link syntax like `{.internal-link target=_blank}`.\n- Keep markdown link structure intact: `[text](url){.internal-link}`.\n\n### Preferred translations / glossary\n\nDo not translate technical terms like path, route, request, response, query, body, cookie, and header, keep them as is.\n\n- Suffixing is very important, when adding Turkish suffixes to the English words, do that based on the pronunciation of the word and with an apostrophe.\n\n- Suffixes also changes based on what word comes next in Turkish too, here is an example:\n\n\"Server'a gelen request'leri intercept... \" or this could have been \"request'e\", \"request'i\" etc.\n\n- Some words are tricky like \"path'e\" can't be used like \"path'a\" but it could have been \"path'i\" \"path'leri\" etc.\n\n- You can use a more instructional style, that is consistent with the document, you can add the Turkish version of the term in parenthesis if it is not something very obvious, or an advanced concept, but do not over do it, do it only the first time it is mentioned, but keep the English term as the primary word.\n\n### `///` admonitions\n\n- Keep the admonition keyword in English (do not translate `note`, `tip`, etc.).\n- If a title is present, prefer these canonical titles:\n\n- `/// note | Not`\n- `/// note | Teknik Detaylar`\n- `/// tip | İpucu`\n- `/// warning | Uyarı`\n- `/// info | Bilgi`\n- `/// check | Ek bilgi`\n\nPrefer `İpucu` over `Ipucu`.\n"
  },
  {
    "path": "docs/tr/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs/uk/docs/_llm-test.md",
    "content": "# Тестовий файл LLM { #llm-test-file }\n\nЦей документ перевіряє, чи розуміє <abbr title=\"Large Language Model - Велика мовна модель\">LLM</abbr>, який перекладає документацію, `general_prompt` у `scripts/translate.py` та мовно-специфічну підсказку в `docs/{language code}/llm-prompt.md`. Мовно-специфічна підсказка додається до `general_prompt`.\n\nТести, додані тут, побачать усі автори мовно-специфічних підсказок.\n\nВикористовуйте так:\n\n* Майте мовно-специфічну підсказку - `docs/{language code}/llm-prompt.md`.\n* Зробіть свіжий переклад цього документа на бажану цільову мову (див., наприклад, команду `translate-page` у `translate.py`). Це створить переклад у `docs/{language code}/docs/_llm-test.md`.\n* Перевірте, чи все гаразд у перекладі.\n* За потреби покращіть вашу мовно-специфічну підсказку, загальну підсказку або англійський документ.\n* Потім вручну виправте решту проблем у перекладі, щоб він був якісним.\n* Перекладіть повторно, маючи якісний переклад на місці. Ідеальний результат - коли LLM більше не вносить змін до перекладу. Це означає, що загальна підсказка та ваша мовно-специфічна підсказка настільки добрі, наскільки це можливо (інколи він робитиме кілька, здавалося б, випадкових змін, причина в тому, що [LLM-и не є детерміністичними алгоритмами](https://doublespeak.chat/#/handbook#deterministic-output)).\n\nТести:\n\n## Фрагменти коду { #code-snippets }\n\n//// tab | Тест\n\nЦе фрагмент коду: `foo`. А це ще один фрагмент коду: `bar`. І ще один: `baz quux`.\n\n////\n\n//// tab | Інформація\n\nВміст фрагментів коду слід залишати без змін.\n\nДив. розділ `### Content of code snippets` в загальній підсказці в `scripts/translate.py`.\n\n////\n\n## Цитати { #quotes }\n\n//// tab | Тест\n\nВчора мій друг написав: «Якщо ви правильно напишете \"incorrectly\", ви написали це неправильно». На що я відповів: «Правильно, але 'incorrectly' - це неправильно, а не '\"incorrectly\"'».\n\n/// note | Примітка\n\nLLM, ймовірно, перекладе це неправильно. Цікаво лише те, чи збереже він виправлений переклад під час повторного перекладу.\n\n///\n\n////\n\n//// tab | Інформація\n\nАвтор підсказки може обрати, чи конвертувати нейтральні лапки в типографські. Можна залишити як є.\n\nДив., наприклад, розділ `### Quotes` у `docs/de/llm-prompt.md`.\n\n////\n\n## Лапки у фрагментах коду { #quotes-in-code-snippets }\n\n//// tab | Тест\n\n`pip install \"foo[bar]\"`\n\nПриклади строкових літералів у фрагментах коду: `\"this\"`, `'that'`.\n\nСкладний приклад строкових літералів у фрагментах коду: `f\"I like {'oranges' if orange else \"apples\"}\"`\n\nХардкор: `Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | Інформація\n\n... Однак лапки всередині фрагментів коду мають залишатися як є.\n\n////\n\n## Блоки коду { #code-blocks }\n\n//// tab | Тест\n\nПриклад коду Bash...\n\n```bash\n# Вивести привітання всесвіту\necho \"Hello universe\"\n```\n\n...і приклад коду консолі...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n...і ще один приклад коду консолі...\n\n```console\n// Створіть каталог \"Code\"\n$ mkdir code\n// Перейдіть до цього каталогу\n$ cd code\n```\n\n...і приклад коду Python...\n\n```Python\nwont_work()  # Це не спрацює 😱\nworks(foo=\"bar\")  # Це працює 🎉\n```\n\n...і це все.\n\n////\n\n//// tab | Інформація\n\nКод у блоках коду не слід змінювати, за винятком коментарів.\n\nДив. розділ `### Content of code blocks` в загальній підсказці в `scripts/translate.py`.\n\n////\n\n## Вкладки та кольорові блоки { #tabs-and-colored-boxes }\n\n//// tab | Тест\n\n/// info | Інформація\nДеякий текст\n///\n\n/// note | Примітка\nДеякий текст\n///\n\n/// note | Технічні деталі\nДеякий текст\n///\n\n/// check | Перевірте\nДеякий текст\n///\n\n/// tip | Порада\nДеякий текст\n///\n\n/// warning | Попередження\nДеякий текст\n///\n\n/// danger | Обережно\nДеякий текст\n///\n\n////\n\n//// tab | Інформація\n\nУ вкладках і блоках `Info`/`Note`/`Warning`/тощо необхідно додати переклад їхнього заголовка після вертикальної риски (`|`).\n\nДив. розділи `### Special blocks` і `### Tab blocks` в загальній підсказці в `scripts/translate.py`.\n\n////\n\n## Веб- і внутрішні посилання { #web-and-internal-links }\n\n//// tab | Тест\n\nТекст посилання має бути перекладений, адреса посилання має залишитися незмінною:\n\n* [Посилання на заголовок вище](#code-snippets)\n* [Внутрішнє посилання](index.md#installation)\n* [Зовнішнє посилання](https://sqlmodel.tiangolo.com/)\n* [Посилання на стиль](https://fastapi.tiangolo.com/css/styles.css)\n* [Посилання на скрипт](https://fastapi.tiangolo.com/js/logic.js)\n* [Посилання на зображення](https://fastapi.tiangolo.com/img/foo.jpg)\n\nТекст посилання має бути перекладений, адреса посилання має вказувати на переклад:\n\n* [Посилання на FastAPI](https://fastapi.tiangolo.com/uk/)\n\n////\n\n//// tab | Інформація\n\nПосилання слід перекладати, але їхні адреси мають лишатися незмінними. Виняток - абсолютні посилання на сторінки документації FastAPI. У такому випадку вони мають вказувати на переклад.\n\nДив. розділ `### Links` в загальній підсказці в `scripts/translate.py`.\n\n////\n\n## Елементи HTML «abbr» { #html-abbr-elements }\n\n//// tab | Тест\n\nОсь деякі речі, обгорнуті в елементи HTML «abbr» (деякі вигадані):\n\n### Скорочення містить повну фразу { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done - Впорядкування справ\">GTD</abbr>\n* <abbr title=\"less than - менше ніж\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token - XML веб-токен\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface - Інтерфейс Шлюзу Паралельного Сервера\">PSGI</abbr>\n\n### Скорочення містить повну фразу та пояснення { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network - Мережа Розробників Mozilla: документація для розробників, написана людьми з Firefox\">MDN</abbr>\n* <abbr title=\"Input/Output - Введення/Виведення: читання або запис на диск, мережеві комунікації.\">I/O</abbr>.\n\n////\n\n//// tab | Інформація\n\nАтрибути \"title\" елементів \"abbr\" перекладаються за певними інструкціями.\n\nПереклади можуть додавати власні елементи \"abbr\", які LLM не повинен прибирати. Наприклад, щоб пояснити англійські слова.\n\nДив. розділ `### HTML abbr elements` в загальній підсказці в `scripts/translate.py`.\n\n////\n\n## Елементи HTML «dfn» { #html-dfn-elements }\n\n* <dfn title=\"Група машин, налаштованих бути з'єднаними та працювати разом певним чином.\">кластер</dfn>\n* <dfn title=\"Метод машинного навчання, що використовує штучні нейронні мережі з численними прихованими шарами між вхідними та вихідними шарами, завдяки чому формується комплексна внутрішня структура\">Глибоке навчання</dfn>\n\n## Заголовки { #headings }\n\n//// tab | Тест\n\n### Розробка вебзастосунку - навчальний посібник { #develop-a-webapp-a-tutorial }\n\nПривіт.\n\n### Підказки типів та - анотації { #type-hints-and-annotations }\n\nЩе раз привіт.\n\n### Супер- та підкласи { #super-and-subclasses }\n\nЩе раз привіт.\n\n////\n\n//// tab | Інформація\n\nЄдине жорстке правило для заголовків - LLM має залишати хеш-частину в фігурних дужках незмінною, щоб посилання не ламалися.\n\nДив. розділ `### Headings` у загальній підсказці в `scripts/translate.py`.\n\nДля деяких мовно-специфічних інструкцій див., наприклад, розділ `### Headings` у `docs/de/llm-prompt.md`.\n\n////\n\n## Терміни, що використовуються в документації { #terms-used-in-the-docs }\n\n//// tab | Тест\n\n* ви\n* ваш\n\n* напр.\n* тощо\n\n* `foo` як `int`\n* `bar` як `str`\n* `baz` як `list`\n\n* навчальний посібник - Керівництво користувача\n* просунутий посібник користувача\n* документація SQLModel\n* документація API\n* автоматична документація\n\n* Наука про дані\n* глибоке навчання\n* машинне навчання\n* впровадження залежностей\n* HTTP базова автентифікація\n* HTTP дайджест\n* формат ISO\n* стандарт Схеми JSON\n* Схема JSON\n* визначення схеми\n* потік паролю\n* мобільний\n\n* застаріле\n* спроєктовано\n* недійсний\n* на льоту\n* стандарт\n* типове\n* чутливий до регістру\n* нечутливий до регістру\n\n* обслуговувати застосунок\n* обслуговувати сторінку\n\n* застосунок\n* застосунок\n\n* запит\n* відповідь\n* відповідь з помилкою\n\n* операція шляху\n* декоратор операції шляху\n* функція операції шляху\n\n* тіло\n* тіло запиту\n* тіло відповіді\n* тіло JSON\n* тіло форми\n* тіло файлу\n* тіло функції\n\n* параметр\n* параметр тіла\n* параметр шляху\n* параметр запиту\n* параметр кукі\n* параметр заголовка\n* параметр форми\n* параметр функції\n\n* подія\n* подія запуску\n* запуск сервера\n* подія вимкнення\n* подія тривалості життя\n\n* обробник\n* обробник події\n* обробник винятків\n* обробляти\n\n* модель\n* модель Pydantic\n* модель даних\n* модель бази даних\n* модель форми\n* об'єкт моделі\n\n* клас\n* базовий клас\n* батьківський клас\n* підклас\n* дочірній клас\n* споріднений клас\n* метод класу\n\n* заголовок\n* заголовки\n* заголовок авторизації\n* заголовок `Authorization`\n* направлений заголовок\n\n* система впровадження залежностей\n* залежність\n* залежний\n* залежний\n\n* I/O-обмежений\n* CPU-обмежений\n* рівночасність\n* паралелізм\n* багатопроцесорність\n\n* змінна оточення\n* змінна оточення\n* `PATH`\n* змінна `PATH`\n\n* автентифікація\n* постачальник автентифікації\n* авторизація\n* форма авторизації\n* постачальник авторизації\n* користувач автентифікується\n* система автентифікує користувача\n\n* CLI\n* інтерфейс командного рядка\n\n* сервер\n* клієнт\n\n* хмарний постачальник\n* хмарний сервіс\n\n* розробка\n* етапи розробки\n\n* словник\n* словник\n* перелік\n* перелік\n* елемент переліку\n\n* кодувальник\n* декодувальник\n* кодувати\n* декодувати\n\n* виняток\n* породжувати\n\n* вираз\n* оператор\n\n* фронтенд\n* бекенд\n\n* обговорення GitHub\n* проблема GitHub\n\n* продуктивність\n* оптимізація продуктивності\n\n* тип, що повертається\n* повернене значення\n\n* безпека\n* схема безпеки\n\n* завдання\n* фонове завдання\n* функція завдання\n\n* шаблон\n* рушій шаблонів\n\n* анотація типу\n* підказка типу\n\n* серверний працівник\n* працівник Uvicorn\n* працівник Gunicorn\n* процес працівника\n* клас працівника\n* робоче навантаження\n\n* розгортання\n* розгортати\n\n* SDK\n* набір для розробки програмного забезпечення\n\n* `APIRouter`\n* `requirements.txt`\n* токен носія\n* несумісна зміна\n* помилка\n* кнопка\n* викликаємий\n* код\n* фіксація\n* менеджер контексту\n* співпрограма\n* сеанс бази даних\n* диск\n* домен\n* рушій\n* фальшивий X\n* метод HTTP GET\n* предмет\n* бібліотека\n* тривалість життя\n* блокування\n* проміжне програмне забезпечення\n* мобільний застосунок\n* модуль\n* монтування\n* мережа\n* джерело\n* переписування\n* корисне навантаження\n* процесор\n* властивість\n* представник\n* запит на витяг\n* запит\n* пам'ять з довільним доступом\n* віддалена машина\n* код статусу\n* строка\n* мітка\n* веб-фреймворк\n* дика карта\n* повертати\n* перевіряти\n\n////\n\n//// tab | Інформація\n\nЦе неповний і не нормативний список (переважно) технічних термінів, що зустрічаються в документації. Він може бути корисним автору підсказки, щоб зрозуміти, для яких термінів LLM потрібна допомога. Наприклад, коли він постійно повертає хороший переклад до менш вдалого. Або коли йому складно відмінювати термін вашою мовою.\n\nДив., наприклад, розділ `### List of English terms and their preferred German translations` у `docs/de/llm-prompt.md`.\n\n////\n"
  },
  {
    "path": "docs/uk/docs/about/index.md",
    "content": "# Про { #about }\n\nПро FastAPI, його проєктування, натхнення та інше. 🤓\n"
  },
  {
    "path": "docs/uk/docs/advanced/additional-responses.md",
    "content": "# Додаткові відповіді в OpenAPI { #additional-responses-in-openapi }\n\n/// warning | Попередження\n\nЦе доволі просунута тема.\n\nЯкщо ви лише починаєте з **FastAPI**, ймовірно, вам це не потрібно.\n\n///\n\nВи можете оголосити додаткові відповіді з додатковими кодами статусу, типами медіа, описами тощо.\n\nЦі додаткові відповіді буде включено до схеми OpenAPI, тож вони з'являться і в документації API.\n\nАле для таких додаткових відповідей потрібно повертати `Response` на кшталт `JSONResponse` безпосередньо, із потрібним кодом статусу та вмістом.\n\n## Додаткова відповідь з `model` { #additional-response-with-model }\n\nВи можете передати вашим декораторам операцій шляху параметр `responses`.\n\nВін приймає `dict`: ключі - це коди статусу для кожної відповіді (наприклад, `200`), а значення - інші `dict` з інформацією для кожної з них.\n\nКожен із цих словників відповіді може мати ключ `model`, що містить Pydantic-модель, подібно до `response_model`.\n\n**FastAPI** візьме цю модель, згенерує її Схему JSON і додасть у відповідне місце в OpenAPI.\n\nНаприклад, щоб оголосити іншу відповідь з кодом статусу `404` і Pydantic-моделлю `Message`, ви можете написати:\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | Примітка\n\nМайте на увазі, що потрібно повертати `JSONResponse` безпосередньо.\n\n///\n\n/// info | Інформація\n\nКлюч `model` не є частиною OpenAPI.\n\n**FastAPI** візьме звідти Pydantic-модель, згенерує Схему JSON і помістить у відповідне місце.\n\nВідповідне місце це:\n\n- У ключі `content`, значенням якого є інший JSON-об'єкт (`dict`), що містить:\n    - Ключ із типом медіа, напр. `application/json`, значенням якого є інший JSON-об'єкт, що містить:\n        - Ключ `schema`, значенням якого є Схема JSON з моделі - ось це і є правильне місце.\n            - **FastAPI** додає тут посилання на глобальні Схеми JSON в іншому місці вашого OpenAPI замість прямого включення. Так інші застосунки та клієнти можуть напряму використовувати ці Схеми JSON, надавати кращі інструменти генерації коду тощо.\n\n///\n\nЗгенеровані відповіді в OpenAPI для цієї операції шляху будуть такими:\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\nСхеми посилаються на інше місце всередині схеми OpenAPI:\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## Додаткові типи медіа для основної відповіді { #additional-media-types-for-the-main-response }\n\nМожна використати цей самий параметр `responses`, щоб додати різні типи медіа для тієї ж основної відповіді.\n\nНаприклад, можна додати додатковий тип медіа `image/png`, оголосивши, що ваша операція шляху може повертати JSON-об'єкт (з типом медіа `application/json`) або PNG-зображення:\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | Примітка\n\nЗверніть увагу, що потрібно повертати зображення безпосередньо за допомогою `FileResponse`.\n\n///\n\n/// info | Інформація\n\nПоки ви явно не вкажете інший тип медіа в параметрі `responses`, FastAPI вважатиме, що відповідь має той самий тип медіа, що й основний клас відповіді (типово `application/json`).\n\nАле якщо ви вказали власний клас відповіді з `None` як типом медіа, FastAPI використає `application/json` для будь-якої додаткової відповіді, що має пов'язану модель.\n\n///\n\n## Комбінування інформації { #combining-information }\n\nВи також можете поєднувати інформацію про відповіді з кількох місць, зокрема з параметрів `response_model`, `status_code` і `responses`.\n\nВи можете оголосити `response_model`, використовуючи типовий код статусу `200` (або власний за потреби), а потім оголосити додаткову інформацію для цієї ж відповіді в `responses`, безпосередньо в схемі OpenAPI.\n\n**FastAPI** збереже додаткову інформацію з `responses` і поєднає її зі Схемою JSON з вашої моделі.\n\nНаприклад, ви можете оголосити відповідь з кодом статусу `404`, яка використовує Pydantic-модель і має власний `description`.\n\nІ відповідь з кодом статусу `200`, яка використовує ваш `response_model`, але містить власний `example`:\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\nУсе це буде поєднано та включено до вашого OpenAPI і показано в документації API:\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## Комбінуйте попередньо визначені та власні відповіді { #combine-predefined-responses-and-custom-ones }\n\nМожливо, ви захочете мати кілька попередньо визначених відповідей, що застосовуються до багатьох операцій шляху, але поєднувати їх із власними відповідями, потрібними для кожної операції шляху.\n\nДля таких випадків можна скористатися прийомом Python «розпакування» `dict` за допомогою `**dict_to_unpack`:\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\nТут `new_dict` міститиме всі пари ключ-значення з `old_dict` плюс нову пару ключ-значення:\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\nЦей прийом можна використати, щоб перевикористовувати деякі попередньо визначені відповіді у ваших операціях шляху та поєднувати їх із додатковими власними.\n\nНаприклад:\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## Докладніше про відповіді OpenAPI { #more-information-about-openapi-responses }\n\nЩоб побачити, що саме можна включати у відповіді, ознайомтеся з цими розділами специфікації OpenAPI:\n\n- [Об'єкт відповідей OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object), він включає `Response Object`.\n- [Об'єкт відповіді OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object), ви можете включити будь-що з цього безпосередньо в кожну відповідь у параметрі `responses`. Зокрема `description`, `headers`, `content` (усередині нього ви оголошуєте різні типи медіа та Схеми JSON) і `links`.\n"
  },
  {
    "path": "docs/uk/docs/advanced/additional-status-codes.md",
    "content": "# Додаткові коди статусу { #additional-status-codes }\n\nЗа замовчуванням **FastAPI** повертатиме відповіді за допомогою `JSONResponse`, поміщаючи вміст, який ви повертаєте з вашої *операції шляху*, у цей `JSONResponse`.\n\nВін використовуватиме код статусу за замовчуванням або той, який ви встановите у своїй *операції шляху*.\n\n## Додаткові коди статусу { #additional-status-codes_1 }\n\nЯкщо ви хочете повертати додаткові коди статусу, окрім основного, зробіть це, повертаючи `Response` безпосередньо, наприклад `JSONResponse`, і встановіть додатковий код статусу напряму.\n\nНаприклад, припустімо, ви хочете мати *операцію шляху*, яка дозволяє оновлювати предмети та повертає код статусу HTTP 200 «OK» у разі успіху.\n\nАле ви також хочете приймати нові предмети. І коли таких предметів раніше не існувало, операція створює їх і повертає код статусу HTTP 201 «Created».\n\nЩоб це реалізувати, імпортуйте `JSONResponse` і поверніть ваш вміст безпосередньо там, встановивши потрібний `status_code`:\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning | Попередження\n\nКоли ви повертаєте `Response` безпосередньо, як у прикладі вище, він і буде повернений безпосередньо.\n\nВін не буде серіалізований за допомогою моделі тощо.\n\nПереконайтеся, що він містить саме ті дані, які вам потрібні, і що значення є коректним JSON (якщо ви використовуєте `JSONResponse`).\n\n///\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette.responses import JSONResponse`.\n\n**FastAPI** надає ті самі `starlette.responses` як `fastapi.responses` просто для вашої зручності як розробника. Але більшість доступних відповідей надходить безпосередньо зі Starlette. Те саме і зі `status`.\n\n///\n\n## OpenAPI і документація API { #openapi-and-api-docs }\n\nЯкщо ви повертаєте додаткові коди статусу та відповіді безпосередньо, вони не будуть включені до схеми OpenAPI (документації API), адже FastAPI не має способу заздалегідь знати, що саме ви повернете.\n\nАле ви можете задокументувати це у своєму коді, використовуючи: [Додаткові відповіді](additional-responses.md).\n"
  },
  {
    "path": "docs/uk/docs/advanced/advanced-dependencies.md",
    "content": "# Просунуті залежності { #advanced-dependencies }\n\n## Параметризовані залежності { #parameterized-dependencies }\n\nУсі залежності, які ми бачили, - це фіксована функція або клас.\n\nАле можуть бути випадки, коли ви хочете мати змогу задавати параметри залежності, не оголошуючи багато різних функцій або класів.\n\nУявімо, що ми хочемо мати залежність, яка перевіряє, чи параметр запиту `q` містить певний фіксований вміст.\n\nАле ми хочемо мати змогу параметризувати цей фіксований вміст.\n\n## Екземпляр «callable» { #a-callable-instance }\n\nУ Python є спосіб зробити екземпляр класу «callable».\n\nНе сам клас (який уже є «callable»), а екземпляр цього класу.\n\nЩоб це зробити, оголошуємо метод `__call__`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\nУ цьому випадку саме `__call__` **FastAPI** використає для перевірки додаткових параметрів і підзалежностей, і саме його буде викликано, щоб передати значення параметру у вашу *функцію операції шляху* пізніше.\n\n## Параметризувати екземпляр { #parameterize-the-instance }\n\nТепер ми можемо використати `__init__`, щоб оголосити параметри екземпляра, які можна застосувати для «параметризації» залежності:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\nУ цьому випадку **FastAPI** ніколи не торкається `__init__` і не покладається на нього - ми використовуватимемо його безпосередньо у своєму коді.\n\n## Створити екземпляр { #create-an-instance }\n\nМи можемо створити екземпляр цього класу так:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\nТаким чином ми «параметризуємо» нашу залежність, яка тепер містить «bar» як атрибут `checker.fixed_content`.\n\n## Використовувати екземпляр як залежність { #use-the-instance-as-a-dependency }\n\nДалі ми можемо використати цей `checker` у `Depends(checker)` замість `Depends(FixedContentQueryChecker)`, адже залежністю є екземпляр `checker`, а не сам клас.\n\nКоли залежність розв'язується, **FastAPI** викличе цей `checker` так:\n\n```Python\nchecker(q=\"somequery\")\n```\n\n...і передасть усе, що він поверне, як значення залежності у нашій *функції операції шляху* як параметр `fixed_content_included`:\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | Порада\n\nУсе це може здаватися надуманим. І поки що може бути не дуже зрозуміло, навіщо це корисно.\n\nЦі приклади навмисно прості, але показують, як усе працює.\n\nУ розділах про безпеку є утилітарні функції, реалізовані таким самим способом.\n\nЯкщо ви все це зрозуміли, ви вже знаєте, як під капотом працюють ті утиліти для безпеки.\n\n///\n\n## Залежності з `yield`, `HTTPException`, `except` та фоновими задачами { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | Попередження\n\nНайімовірніше, вам не знадобляться ці технічні деталі.\n\nВони корисні головно, якщо у вас був застосунок FastAPI старіший за 0.121.0 і ви стикаєтеся з проблемами залежностей із `yield`.\n\n///\n\nЗалежності з `yield` еволюціонували з часом, щоб охопити різні сценарії використання та виправити деякі проблеми, ось підсумок змін.\n\n### Залежності з `yield` і `scope` { #dependencies-with-yield-and-scope }\n\nУ версії 0.121.0 **FastAPI** додано підтримку `Depends(scope=\"function\")` для залежностей з `yield`.\n\nЗ `Depends(scope=\"function\")` завершальний код після `yield` виконується одразу після завершення *функції операції шляху*, до того як відповідь буде надіслана клієнту.\n\nА при використанні `Depends(scope=\"request\")` (типове значення) завершальний код після `yield` виконується після відправлення відповіді.\n\nДокладніше читайте в документації: [Залежності з `yield` - Ранній вихід і `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope).\n\n### Залежності з `yield` і `StreamingResponse`, технічні деталі { #dependencies-with-yield-and-streamingresponse-technical-details }\n\nДо **FastAPI** 0.118.0, якщо ви використовували залежність із `yield`, завершальний код виконувався після повернення з *функції операції шляху*, але безпосередньо перед відправленням відповіді.\n\nМетою було уникнути утримання ресурсів довше, ніж потрібно, очікуючи, поки відповідь пройде мережею.\n\nЦе також означало, що якщо ви повертали `StreamingResponse`, завершальний код залежності з `yield` уже було б виконано.\n\nНаприклад, якщо у залежності з `yield` була сесія бази даних, `StreamingResponse` не зміг би використовувати цю сесію під час потокової передачі даних, тому що сесію вже закрито в завершальному коді після `yield`.\n\nЦю поведінку змінено у 0.118.0: завершальний код після `yield` знову виконується після відправлення відповіді.\n\n/// info | Інформація\n\nЯк побачите нижче, це дуже схоже на поведінку до версії 0.106.0, але з кількома покращеннями та виправленнями помилок у крайових випадках.\n\n///\n\n#### Випадки використання з раннім завершальним кодом { #use-cases-with-early-exit-code }\n\nЄ кілька сценаріїв із певними умовами, які можуть виграти від старої поведінки - виконувати завершальний код залежностей з `yield` до надсилання відповіді.\n\nНаприклад, уявіть, що у вас є код, який використовує сесію бази даних у залежності з `yield` лише для перевірки користувача, але сесія більше не використовується у *функції операції шляху*, тільки в залежності, і відправлення відповіді триває довго - як у `StreamingResponse`, що повільно надсилає дані, але з якоїсь причини не використовує базу даних.\n\nУ такому разі сесія БД утримувалася б до завершення відправлення відповіді, але якщо ви її не використовуєте, утримувати її немає потреби.\n\nОсь як це може виглядати:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\nЗавершальний код - автоматичне закриття `Session` у:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n...виконається після того, як відповідь завершить надсилати повільні дані:\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nАле оскільки `generate_stream()` не використовує сесію бази даних, немає реальної потреби тримати сесію відкритою під час надсилання відповіді.\n\nЯкщо у вас саме такий випадок із SQLModel (або SQLAlchemy), ви можете явно закрити сесію, коли вона більше не потрібна:\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\nТак сесія звільнить з'єднання з базою даних, і його зможуть використовувати інші запити.\n\nЯкщо у вас інший сценарій, де потрібно раннє завершення залежності з `yield`, створіть, будь ласка, [питання в обговореннях GitHub](https://github.com/fastapi/fastapi/discussions/new?category=questions) із вашим конкретним випадком і поясненням, чому вам корисне раннє закриття для залежностей з `yield`.\n\nЯкщо будуть переконливі приклади для раннього закриття в залежностях з `yield`, я розгляну додавання нового способу увімкнути раннє закриття.\n\n### Залежності з `yield` і `except`, технічні деталі { #dependencies-with-yield-and-except-technical-details }\n\nДо **FastAPI** 0.110.0, якщо ви використовували залежність із `yield`, перехоплювали виняток через `except` у цій залежності і не піднімали його знову, виняток автоматично піднімався/пересилався до будь-яких обробників винятків або внутрішнього обробника помилок сервера.\n\nЦе змінено у версії 0.110.0, щоб усунути неконтрольоване споживання пам'яті від пересланих винятків без обробника (внутрішні помилки сервера) та зробити поведінку узгодженою зі звичайним Python-кодом.\n\n### Фонові задачі та залежності з `yield`, технічні деталі { #background-tasks-and-dependencies-with-yield-technical-details }\n\nДо **FastAPI** 0.106.0 піднімати винятки після `yield` було неможливо: завершальний код у залежностях з `yield` виконувався після надсилання відповіді, тож [обробники винятків](../tutorial/handling-errors.md#install-custom-exception-handlers) уже відпрацювали б.\n\nТак було спроєктовано головно для того, щоб дозволити використовувати ті самі об'єкти, «віддані» залежностями через `yield`, усередині фонових задач, оскільки завершальний код виконувався після завершення фонових задач.\n\nУ **FastAPI** 0.106.0 це змінено, щоб не утримувати ресурси під час очікування, поки відповідь піде мережею.\n\n/// tip | Порада\n\nКрім того, фонова задача зазвичай є незалежним набором логіки, який слід обробляти окремо, з власними ресурсами (наприклад, власним з'єднанням з базою даних).\n\nТож так у вас, ймовірно, буде чистіший код.\n\n///\n\nЯкщо ви раніше покладалися на цю поведінку, тепер слід створювати ресурси для фонових задач усередині самої фонової задачі та використовувати всередині лише дані, що не залежать від ресурсів залежностей із `yield`.\n\nНаприклад, замість використання тієї самої сесії бази даних ви створюватимете нову сесію в самій фоновій задачі та отримуватимете об'єкти з бази даних, використовуючи Цю нову сесію. І далі, замість передавання об'єкта з бази даних як параметра у функцію фонової задачі, ви передасте ідентифікатор цього об'єкта, а потім отримаєте об'єкт знову всередині функції фонової задачі.\n"
  },
  {
    "path": "docs/uk/docs/advanced/advanced-python-types.md",
    "content": "# Просунуті типи Python { #advanced-python-types }\n\nОсь кілька додаткових ідей, які можуть бути корисні під час роботи з типами в Python.\n\n## Використання `Union` або `Optional` { #using-union-or-optional }\n\nЯкщо ваш код з якоїсь причини не може використовувати `|`, наприклад, якщо це не анотація типів, а щось на кшталт `response_model=`, замість вертикальної риски (`|`) ви можете використати `Union` з `typing`.\n\nНаприклад, ви можете оголосити, що щось може бути `str` або `None`:\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\nУ `typing` також є скорочення, щоб оголосити, що щось може бути `None`, - `Optional`.\n\nОсь порада з моєї дуже «суб'єктивної» точки зору:\n\n- 🚨 Уникайте використання `Optional[SomeType]`\n- Натомість ✨ **використовуйте `Union[SomeType, None]`** ✨.\n\nОбидва варіанти еквівалентні і під капотом однакові, але я рекомендую `Union` замість `Optional`, тому що слово «**optional**» ніби натякає, що значення є необов'язковим, а насправді означає «може бути `None`», навіть якщо воно не є необов'язковим і все ще обов'язкове.\n\nВважаю, `Union[SomeType, None]` більш явно це передає.\n\nЙдеться лише про слова та назви. Але ці слова можуть впливати на те, як ви та ваша команда думаєте про код.\n\nЯк приклад, розгляньмо цю функцію:\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\nПараметр `name` визначено як `Optional[str]`, але він не є необов'язковим, ви не можете викликати функцію без цього параметра:\n\n```Python\nsay_hi()  # О ні, це викликає помилку! 😱\n```\n\nПараметр `name` все ще обов'язковий (не «необов'язковий»), тому що не має значення за замовчуванням. Водночас `name` приймає `None` як значення:\n\n```Python\nsay_hi(name=None)  # Це працює, None припустимий 🎉\n```\n\nГарна новина: у більшості випадків ви зможете просто використовувати `|`, щоб визначати об'єднання типів:\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\nТож зазвичай вам не доведеться перейматися такими назвами, як `Optional` і `Union`. 😎\n"
  },
  {
    "path": "docs/uk/docs/advanced/async-tests.md",
    "content": "# Асинхронні тести { #async-tests }\n\nВи вже бачили, як тестувати ваші застосунки **FastAPI** за допомогою наданого `TestClient`. До цього часу ви бачили лише, як писати синхронні тести, без використання функцій `async`.\n\nМожливість використовувати асинхронні функції у тестах може бути корисною, наприклад, коли ви асинхронно звертаєтеся до бази даних. Уявіть, що ви хочете протестувати надсилання запитів до вашого застосунку FastAPI, а потім перевірити, що ваш бекенд успішно записав коректні дані в базу даних, використовуючи асинхронну бібліотеку для бази даних.\n\nРозгляньмо, як це реалізувати.\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\nЯкщо ми хочемо викликати асинхронні функції у тестах, самі тестові функції мають бути асинхронними. AnyIO надає зручний плагін, який дозволяє вказати, що деякі тестові функції слід виконувати асинхронно.\n\n## HTTPX { #httpx }\n\nНавіть якщо ваш застосунок **FastAPI** використовує звичайні функції `def` замість `async def`, під капотом це все одно `async`-застосунок.\n\n`TestClient` робить певну «магію» всередині, щоб викликати асинхронний застосунок FastAPI у ваших звичайних тестових функціях `def`, використовуючи стандартний pytest. Але ця «магія» більше не працює, коли ми використовуємо його всередині асинхронних функцій. Запускаючи тести асинхронно, ми більше не можемо використовувати `TestClient` у наших тестових функціях.\n\n`TestClient` побудований на основі [HTTPX](https://www.python-httpx.org), і на щастя, ми можемо використовувати його безпосередньо для тестування API.\n\n## Приклад { #example }\n\nДля простого прикладу розгляньмо структуру файлів, подібну до описаної в [Більші застосунки](../tutorial/bigger-applications.md) та [Тестування](../tutorial/testing.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nФайл `main.py` міститиме:\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\nФайл `test_main.py` міститиме тести для `main.py`, тепер це може виглядати так:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## Запуск { #run-it }\n\nВи можете запустити тести як зазвичай:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## Докладно { #in-detail }\n\nМаркер `@pytest.mark.anyio` повідомляє pytest, що цю тестову функцію слід викликати асинхронно:\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip | Порада\n\nЗауважте, що тестова функція тепер `async def` замість просто `def`, як це було раніше при використанні `TestClient`.\n\n///\n\nДалі ми можемо створити `AsyncClient` із застосунком і надсилати до нього асинхронні запити, використовуючи `await`.\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\nЦе еквівалентно:\n\n```Python\nresponse = client.get('/')\n```\n\n...що ми раніше використовували для надсилання запитів за допомогою `TestClient`.\n\n/// tip | Порада\n\nЗауважте, що ми використовуємо async/await із новим `AsyncClient` - запит є асинхронним.\n\n///\n\n/// warning | Попередження\n\nЯкщо ваш застосунок залежить від подій тривалості життя, `AsyncClient` не ініціюватиме ці події. Щоб гарантувати їх ініціалізацію, використовуйте `LifespanManager` з [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage).\n\n///\n\n## Інші асинхронні виклики функцій { #other-asynchronous-function-calls }\n\nОскільки тестова функція тепер асинхронна, ви також можете викликати (і `await`) інші `async`-функції окрім надсилання запитів до вашого застосунку FastAPI у тестах - так само, як ви робили б це будь-де у вашому коді.\n\n/// tip | Порада\n\nЯкщо ви натрапили на `RuntimeError: Task attached to a different loop` під час інтеграції асинхронних викликів у ваші тести (наприклад, при використанні [MongoDB's MotorClient](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop)), пам'ятайте створювати об'єкти, яким потрібен цикл подій, лише всередині асинхронних функцій, наприклад, у зворотному виклику `@app.on_event(\"startup\")`.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/advanced/behind-a-proxy.md",
    "content": "# За представником { #behind-a-proxy }\n\nУ багатьох випадках ви будете використовувати **представника** на кшталт Traefik або Nginx перед вашим застосунком FastAPI.\n\nТакі представники можуть обробляти сертифікати HTTPS та інші речі.\n\n## Направлені заголовки представника { #proxy-forwarded-headers }\n\n**Представник** перед вашим застосунком зазвичай встановлює деякі заголовки на льоту перед відправленням запитів до вашого **сервера**, щоб повідомити серверу, що запит було **направлено** через представника, вказати оригінальну (публічну) URL-адресу, включно з доменом, що використовується HTTPS тощо.\n\nПрограмний **сервер** (наприклад, **Uvicorn** через **FastAPI CLI**) здатний інтерпретувати ці заголовки і передавати цю інформацію вашому застосунку.\n\nАле з міркувань безпеки, оскільки сервер не знає, що він працює за довіреним представником, він не інтерпретуватиме ці заголовки.\n\n/// note | Технічні деталі\n\nЗаголовки представника:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### Увімкнути направлені заголовки представника { #enable-proxy-forwarded-headers }\n\nВи можете запустити FastAPI CLI з *опцією CLI* `--forwarded-allow-ips` і передати IP-адреси, яким слід довіряти для читання цих направлених заголовків.\n\nЯкщо ви встановите `--forwarded-allow-ips=\"*\"`, це означатиме довіру до всіх вхідних IP.\n\nЯкщо ваш **сервер** знаходиться за довіреним **представником** і тільки представник спілкується з ним, це змусить сервер приймати будь-яку IP-адресу цього **представника**.\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Перенаправлення з HTTPS { #redirects-with-https }\n\nНаприклад, припустимо, ви визначили *операцію шляху* `/items/`:\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\nЯкщо клієнт спробує перейти до `/items`, за замовчуванням буде виконано перенаправлення на `/items/`.\n\nАле до встановлення *опції CLI* `--forwarded-allow-ips` це могло б перенаправити на `http://localhost:8000/items/`.\n\nВтім, можливо ваш застосунок розміщено на `https://mysuperapp.com`, і перенаправлення має бути на `https://mysuperapp.com/items/`.\n\nНалаштувавши `--proxy-headers`, FastAPI зможе перенаправляти на правильну адресу. 😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip | Порада\n\nЯкщо хочете дізнатися більше про HTTPS, перегляньте посібник [Про HTTPS](../deployment/https.md).\n\n///\n\n### Як працюють направлені заголовки представника { #how-proxy-forwarded-headers-work }\n\nОсь візуальне подання того, як **представник** додає направлені заголовки між клієнтом і **сервером застосунку**:\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Proxy as Proxy/Load Balancer\n    participant Server as FastAPI Server\n\n    Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: Proxy adds forwarded headers\n\n    Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)\n\n    Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs\n\n    Proxy->>Client: HTTPS Response\n```\n\n**Представник** перехоплює початковий запит клієнта і додає спеціальні *направлені* заголовки (`X-Forwarded-*`) перед передачею запиту на **сервер застосунку**.\n\nЦі заголовки зберігають інформацію про оригінальний запит, яка інакше була б втрачена:\n\n- X-Forwarded-For: оригінальна IP-адреса клієнта\n- X-Forwarded-Proto: оригінальний протокол (`https`)\n- X-Forwarded-Host: оригінальний хост (`mysuperapp.com`)\n\nКоли **FastAPI CLI** налаштовано з `--forwarded-allow-ips`, він довіряє цим заголовкам і використовує їх, наприклад, для побудови коректних URL-адрес у перенаправленнях.\n\n## Представник із вилученим префіксом шляху { #proxy-with-a-stripped-path-prefix }\n\nУ вас може бути представник, що додає префікс шляху до вашого застосунку.\n\nУ таких випадках ви можете використати `root_path` для конфігурації застосунку.\n\n`root_path` - це механізм, наданий специфікацією ASGI (на якій побудовано FastAPI через Starlette).\n\n`root_path` використовується для обробки саме таких випадків.\n\nЙого також використано внутрішньо під час монтування підзастосунків.\n\nНаявність представника з вилученим префіксом шляху означає, що ви могли б оголосити шлях `/app` у вашому коді, але потім додати шар зверху (представника), який розмістить ваш застосунок **FastAPI** під шляхом на кшталт `/api/v1`.\n\nУ такому разі початковий шлях `/app` фактично буде доступний за `/api/v1/app`.\n\nХоча весь ваш код написано з припущенням, що є лише `/app`.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\nІ представник буде **«зрізати»** **префікс шляху** на льоту перед передачею запиту серверу застосунку (ймовірно, Uvicorn через FastAPI CLI), зберігаючи переконання вашого застосунку, що його обслуговують за `/app`, тож вам не доведеться оновлювати весь код, щоб додати префікс `/api/v1`.\n\nДотепер усе працювало б як зазвичай.\n\nАле коли ви відкриєте вбудований інтерфейс документації (фронтенд), він очікуватиме отримати схему OpenAPI за `/openapi.json`, замість `/api/v1/openapi.json`.\n\nОтже, фронтенд (що працює у браузері) спробує звернутися до `/openapi.json` і не зможе отримати схему OpenAPI.\n\nОскільки у нас є представник з префіксом шляху `/api/v1` для нашого застосунку, фронтенду потрібно отримувати схему OpenAPI за `/api/v1/openapi.json`.\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy on http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server on http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip | Порада\n\nIP `0.0.0.0` зазвичай означає, що програма слухає на всіх IP-адресах, доступних на цій машині/сервері.\n\n///\n\nІнтерфейсу документації також потрібно, щоб схема OpenAPI оголошувала, що цей `server` API розташований за `/api/v1` (за представником). Наприклад:\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // Ще дещо тут\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // Ще дещо тут\n    }\n}\n```\n\nУ цьому прикладі «Proxy» може бути чимось на кшталт **Traefik**. А сервером буде щось на кшталт FastAPI CLI з **Uvicorn**, який запускає ваш застосунок FastAPI.\n\n### Задання `root_path` { #providing-the-root-path }\n\nЩоб цього досягти, ви можете використати опцію командного рядка `--root-path`, наприклад:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nЯкщо ви використовуєте Hypercorn, у нього також є опція `--root-path`.\n\n/// note | Технічні деталі\n\nСпецифікація ASGI визначає `root_path` для такого випадку використання.\n\nА опція командного рядка `--root-path` надає цей `root_path`.\n\n///\n\n### Перевірка поточного `root_path` { #checking-the-current-root-path }\n\nВи можете отримати поточний `root_path`, який використовує ваш застосунок для кожного запиту, він є частиною словника `scope` (це частина специфікації ASGI).\n\nТут ми додаємо його у повідомлення лише для демонстрації.\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\nПотім, якщо ви запустите Uvicorn так:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nВідповідь буде приблизно такою:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### Встановлення `root_path` у застосунку FastAPI { #setting-the-root-path-in-the-fastapi-app }\n\nАльтернативно, якщо у вас немає способу передати опцію командного рядка на кшталт `--root-path` чи еквівалентну, ви можете встановити параметр `root_path` під час створення вашого застосунку FastAPI:\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\nПередача `root_path` до `FastAPI` еквівалентна передачі опції командного рядка `--root-path` до Uvicorn або Hypercorn.\n\n### Про `root_path` { #about-root-path }\n\nМайте на увазі, що сервер (Uvicorn) не використовуватиме `root_path` ні для чого, окрім передачі його застосунку.\n\nАле якщо ви перейдете у вашому браузері на [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), ви побачите звичайну відповідь:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nТобто він не очікуватиме доступу за адресою `http://127.0.0.1:8000/api/v1/app`.\n\nUvicorn очікуватиме, що представник буде звертатися до Uvicorn на `http://127.0.0.1:8000/app`, і тоді саме представник відповідатиме за додавання додаткового префікса `/api/v1` зверху.\n\n## Про представників із вилученим префіксом шляху { #about-proxies-with-a-stripped-path-prefix }\n\nМайте на увазі, що представник із вилученим префіксом шляху - це лише один зі способів його налаштування.\n\nЙмовірно, в багатьох випадках за замовчуванням представник не матиме вилученого префікса шляху.\n\nУ такому випадку (без вилученого префікса шляху) представник слухатиме щось на кшталт `https://myawesomeapp.com`, і коли браузер перейде на `https://myawesomeapp.com/api/v1/app`, а ваш сервер (наприклад, Uvicorn) слухає на `http://127.0.0.1:8000`, представник (без вилученого префікса) звернеться до Uvicorn за тим самим шляхом: `http://127.0.0.1:8000/api/v1/app`.\n\n## Локальне тестування з Traefik { #testing-locally-with-traefik }\n\nВи можете легко провести експеримент локально з вилученим префіксом шляху, використовуючи [Traefik](https://docs.traefik.io/).\n\n[Завантажте Traefik](https://github.com/containous/traefik/releases), це один бінарний файл, ви можете розпакувати архів і запустити його безпосередньо з термінала.\n\nПотім створіть файл `traefik.toml` з таким вмістом:\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\nЦе вказує Traefik слухати порт 9999 і використовувати інший файл `routes.toml`.\n\n/// tip | Порада\n\nМи використовуємо порт 9999 замість стандартного HTTP-порту 80, щоб вам не довелося запускати його з адмін-повноваженнями (`sudo`).\n\n///\n\nТепер створіть інший файл `routes.toml`:\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\nЦей файл налаштовує Traefik на використання префікса шляху `/api/v1`.\n\nПотім Traefik переспрямовуватиме свої запити до вашого Uvicorn, який працює на `http://127.0.0.1:8000`.\n\nТепер запустіть Traefik:\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\nА тепер запустіть ваш застосунок, використовуючи опцію `--root-path`:\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### Перевірте відповіді { #check-the-responses }\n\nТепер, якщо ви перейдете за URL із портом Uvicorn: [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app), ви побачите звичайну відповідь:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip | Порада\n\nЗверніть увагу, що хоча ви звертаєтеся за адресою `http://127.0.0.1:8000/app`, відображається `root_path` `/api/v1`, взятий із опції `--root-path`.\n\n///\n\nА тепер відкрийте URL із портом Traefik, включно з префіксом шляху: [http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app).\n\nМи отримуємо ту саму відповідь:\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\nале цього разу за URL із префіксом шляху, який надає представник: `/api/v1`.\n\nЗвісно, ідея полягає в тому, що всі мають доступатися до застосунку через представника, тож варіант із префіксом шляху `/api/v1` є «правильним».\n\nА варіант без префікса шляху (`http://127.0.0.1:8000/app`), який надає безпосередньо Uvicorn, має бути виключно для того, щоб _представник_ (Traefik) звертався до нього.\n\nЦе демонструє, як Представник (Traefik) використовує префікс шляху і як сервер (Uvicorn) використовує `root_path` з опції `--root-path`.\n\n### Перевірте інтерфейс документації { #check-the-docs-ui }\n\nА тепер до цікавої частини. ✨\n\n«Офіційний» спосіб доступу до застосунку - через представника з префіксом шляху, який ми визначили. Тож, як і очікується, якщо ви спробуєте інтерфейс документації, який обслуговує безпосередньо Uvicorn без префікса шляху в URL, це не запрацює, оскільки він очікує доступу через представника.\n\nВи можете перевірити це на [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\nАле якщо ми звернемося до інтерфейсу документації за «офіційним» URL, використовуючи представника з портом `9999`, за адресою `/api/v1/docs`, усе працює коректно! 🎉\n\nВи можете перевірити це на [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs):\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\nСаме так, як ми хотіли. ✔️\n\nЦе тому, що FastAPI використовує `root_path`, щоб створити типовий `server` в OpenAPI з URL, наданою `root_path`.\n\n## Додаткові сервери { #additional-servers }\n\n/// warning | Попередження\n\nЦе більш просунутий випадок використання. Можете пропустити його.\n\n///\n\nЗа замовчуванням **FastAPI** створить `server` у схемі OpenAPI з URL для `root_path`.\n\nАле ви також можете надати інші альтернативні `servers`, наприклад, якщо хочете, щоб той самий інтерфейс документації взаємодіяв і зі стейджингом, і з продакшном.\n\nЯкщо ви передасте власний список `servers`, і є `root_path` (тому що ваш API знаходиться за представником), **FastAPI** вставить «server» з цим `root_path` на початок списку.\n\nНаприклад:\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\nБуде згенерована схема OpenAPI на кшталт:\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // Ще дещо тут\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // Ще дещо тут\n    }\n}\n```\n\n/// tip | Порада\n\nЗверніть увагу на автоматично згенерований сервер із значенням `url` `/api/v1`, взятим із `root_path`.\n\n///\n\nВ інтерфейсі документації за адресою [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) це виглядатиме так:\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip | Порада\n\nІнтерфейс документації взаємодіятиме з сервером, який ви оберете.\n\n///\n\n/// note | Технічні деталі\n\nВластивість `servers` у специфікації OpenAPI є необовʼязковою.\n\nЯкщо ви не вкажете параметр `servers`, і `root_path` дорівнює `/`, властивість `servers` у згенерованій схемі OpenAPI буде повністю пропущено за замовчуванням, що еквівалентно одному серверу зі значенням `url` рівним `/`.\n\n///\n\n### Вимкнути автоматичний сервер із `root_path` { #disable-automatic-server-from-root-path }\n\nЯкщо ви не хочете, щоб **FastAPI** додавав автоматичний сервер, використовуючи `root_path`, скористайтеся параметром `root_path_in_servers=False`:\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\nі тоді він не буде включений у схему OpenAPI.\n\n## Монтування підзастосунку { #mounting-a-sub-application }\n\nЯкщо вам потрібно змонтувати підзастосунок (як описано в [Підзастосунки - монтування](sub-applications.md)), одночасно використовуючи представника з `root_path`, ви можете робити це звичайним чином, як і очікуєте.\n\nFastAPI внутрішньо розумно використовуватиме `root_path`, тож усе просто працюватиме. ✨\n"
  },
  {
    "path": "docs/uk/docs/advanced/custom-response.md",
    "content": "# Користувацька відповідь - HTML, стрім, файл, інше { #custom-response-html-stream-file-others }\n\nТипово **FastAPI** повертатиме JSON-відповіді.\n\nВи можете переписати це, повернувши `Response` безпосередньо, як показано в [Повернути відповідь безпосередньо](response-directly.md).\n\nАле якщо ви повертаєте `Response` безпосередньо (або будь-який його підклас, як-от `JSONResponse`), дані не будуть автоматично конвертовані (навіть якщо ви оголосите `response_model`), і документація не буде автоматично згенерована (наприклад, з включенням конкретного «медіа-типу» в HTTP-заголовку `Content-Type` як частини згенерованого OpenAPI).\n\nВи також можете оголосити `Response`, який слід використовувати (наприклад, будь-який підклас `Response`), у декораторі операції шляху через параметр `response_class`.\n\nВміст, який ви повертаєте з вашої функції операції шляху, буде поміщений усередину цього `Response`.\n\n/// note | Примітка\n\nЯкщо ви використовуєте клас відповіді без медіа-типу, FastAPI очікуватиме, що у вашої відповіді не буде вмісту, тож формат відповіді не буде задокументовано в згенерованій документації OpenAPI.\n\n///\n\n## JSON-відповіді { #json-responses }\n\nТипово FastAPI повертає JSON-відповіді.\n\nЯкщо ви оголосите [Модель відповіді](../tutorial/response-model.md), FastAPI використає її, щоб серіалізувати дані в JSON за допомогою Pydantic.\n\nЯкщо ви не оголосите модель відповіді, FastAPI використає `jsonable_encoder`, пояснений у [Сумісний кодувальник JSON](../tutorial/encoder.md), і помістить результат у `JSONResponse`.\n\nЯкщо ви оголосите `response_class` з JSON медіа-типом (`application/json`), як у випадку з `JSONResponse`, дані, що повертаються, будуть автоматично перетворені (і відфільтровані) згідно з будь-якою Pydantic `response_model`, яку ви оголосили в декораторі операції шляху. Але дані не будуть серіалізовані в JSON-байти за допомогою Pydantic, натомість вони будуть перетворені з `jsonable_encoder`, а потім передані класу `JSONResponse`, який і серіалізує їх у байти, використовуючи стандартну JSON-бібліотеку в Python.\n\n### Продуктивність JSON { #json-performance }\n\nКоротко: якщо вам потрібна максимальна продуктивність, використовуйте [Модель відповіді](../tutorial/response-model.md) і не оголошуйте `response_class` у декораторі операції шляху.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## HTML-відповідь { #html-response }\n\nЩоб повернути відповідь із HTML безпосередньо з **FastAPI**, використовуйте `HTMLResponse`.\n\n- Імпортуйте `HTMLResponse`.\n- Передайте `HTMLResponse` як параметр `response_class` вашого декоратора операції шляху.\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info | Інформація\n\nПараметр `response_class` також визначатиме «медіа-тип» відповіді.\n\nУ цьому випадку HTTP-заголовок `Content-Type` буде встановлено в `text/html`.\n\nІ це буде задокументовано відповідно в OpenAPI.\n\n///\n\n### Повернути `Response` { #return-a-response }\n\nЯк показано в [Повернути відповідь безпосередньо](response-directly.md), ви також можете переписати відповідь безпосередньо у вашій операції шляху, просто повернувши її.\n\nТой самий приклад вище, що повертає `HTMLResponse`, може виглядати так:\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning | Попередження\n\n`Response`, повернений безпосередньо вашою функцією операції шляху, не буде задокументовано в OpenAPI (наприклад, `Content-Type` не буде задокументовано) і не буде видно в автоматичній інтерактивній документації.\n\n///\n\n/// info | Інформація\n\nЗвісно, фактичні заголовок `Content-Type`, код статусу тощо прийдуть з об'єкта `Response`, який ви повернули.\n\n///\n\n### Задокументуйте в OpenAPI і перепишіть `Response` { #document-in-openapi-and-override-response }\n\nЯкщо ви хочете переписати відповідь усередині функції, але водночас задокументувати «медіа-тип» в OpenAPI, ви можете використати параметр `response_class` І повернути об'єкт `Response`.\n\nТоді `response_class` буде використано лише для документування операції шляху в OpenAPI, а ваша `Response` буде використана як є.\n\n#### Повернути `HTMLResponse` безпосередньо { #return-an-htmlresponse-directly }\n\nНаприклад, це може бути щось на кшталт:\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\nУ цьому прикладі функція `generate_html_response()` уже генерує та повертає `Response` замість повернення HTML як `str`.\n\nПовертаючи результат виклику `generate_html_response()`, ви вже повертаєте `Response`, яка перепише типову поведінку **FastAPI**.\n\nАле оскільки ви також передали `HTMLResponse` у `response_class`, **FastAPI** знатиме, як задокументувати це в OpenAPI та інтерактивній документації як HTML з `text/html`:\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## Доступні відповіді { #available-responses }\n\nОсь деякі з доступних відповідей.\n\nМайте на увазі, що ви можете використовувати `Response`, щоб повертати що завгодно інше, або навіть створити власний підклас.\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette.responses import HTMLResponse`.\n\n**FastAPI** надає ті ж `starlette.responses` як `fastapi.responses` лише для вашої зручності як розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette.\n\n///\n\n### `Response` { #response }\n\nГоловний клас `Response`, від якого успадковуються всі інші відповіді.\n\nВи можете повертати його безпосередньо.\n\nВін приймає такі параметри:\n\n- `content` - `str` або `bytes`.\n- `status_code` - `int` - код статусу HTTP.\n- `headers` - `dict` строк.\n- `media_type` - `str`, що задає медіа-тип, напр. `\"text/html\"`.\n\nFastAPI (насправді Starlette) автоматично додасть заголовок Content-Length. Також буде додано заголовок Content-Type на основі `media_type` з додаванням набору символів для текстових типів.\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\nПриймає текст або байти та повертає HTML-відповідь, як описано вище.\n\n### `PlainTextResponse` { #plaintextresponse }\n\nПриймає текст або байти та повертає відповідь звичайним текстом.\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\nПриймає дані та повертає відповідь, закодовану як `application/json`.\n\nЦе типова відповідь, яку використовує **FastAPI**, як зазначено вище.\n\n/// note | Технічні деталі\n\nАле якщо ви оголосите модель відповіді або тип, його буде використано безпосередньо для серіалізації даних у JSON, і відповідь з коректним медіа-типом для JSON буде повернута безпосередньо, без використання класу `JSONResponse`.\n\nЦе ідеальний спосіб отримати найкращу продуктивність.\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\nПовертає HTTP-перенаправлення. Типово використовує код статусу 307 (Temporary Redirect).\n\nВи можете повернути `RedirectResponse` безпосередньо:\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\nАбо ви можете використати його в параметрі `response_class`:\n\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\nУ такому разі ви можете повертати URL безпосередньо з вашої функції операції шляху.\n\nУ цьому випадку `status_code` буде типовим для `RedirectResponse`, тобто `307`.\n\n---\n\nВи також можете використати параметр `status_code` разом із параметром `response_class`:\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\nПриймає async-генератор або звичайний генератор/ітератор (функцію з `yield`) і потоково передає тіло відповіді.\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | Технічні деталі\n\nЗавдання `async` може бути скасовано лише тоді, коли воно досягає `await`. Якщо немає `await`, генератор (функція з `yield`) не може бути коректно скасований і може продовжувати працювати навіть після запиту на скасування.\n\nОскільки цьому невеликому прикладу не потрібні жодні оператори `await`, ми додаємо `await anyio.sleep(0)`, щоб надати циклу подій шанс обробити скасування.\n\nЦе ще важливіше для великих або нескінченних потоків.\n\n///\n\n/// tip | Порада\n\nЗамість того щоб повертати `StreamingResponse` безпосередньо, імовірно, краще дотримуватися стилю в [Потокова передача даних](./stream-data.md), це значно зручніше та обробляє скасування «за лаштунками» для вас.\n\nЯкщо ви транслюєте JSON Lines, дотримуйтесь навчального посібника [Потоки JSON Lines](../tutorial/stream-json-lines.md).\n\n///\n\n### `FileResponse` { #fileresponse }\n\nАсинхронно транслює файл як відповідь.\n\nПриймає інший набір аргументів для створення екземпляра, ніж інші типи відповідей:\n\n- `path` - шлях до файлу для трансляції.\n- `headers` - будь-які користувацькі заголовки як словник.\n- `media_type` - строка, що задає медіа-тип. Якщо не встановлено, медіа-тип буде виведено з імені файлу або шляху.\n- `filename` - якщо встановлено, буде включено до `Content-Disposition` відповіді.\n\nВідповіді з файлами включатимуть відповідні заголовки `Content-Length`, `Last-Modified` і `ETag`.\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\nВи також можете використати параметр `response_class`:\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\nУ цьому випадку ви можете повертати шлях до файлу безпосередньо з вашої функції операції шляху.\n\n## Власний клас відповіді { #custom-response-class }\n\nВи можете створити власний клас відповіді, успадкувавши його від `Response`, і використовувати його.\n\nНаприклад, скажімо, ви хочете використовувати [`orjson`](https://github.com/ijl/orjson) з деякими налаштуваннями.\n\nПрипустімо, ви хочете, щоб повертався відформатований із відступами JSON, тож ви хочете використати опцію orjson `orjson.OPT_INDENT_2`.\n\nВи можете створити `CustomORJSONResponse`. Головне, що потрібно зробити, це створити метод `Response.render(content)`, який повертає вміст як `bytes`:\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\nТепер замість повернення:\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n...ця відповідь повертатиме:\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\nЗвісно, ви, ймовірно, знайдете значно кращі способи скористатися цим, ніж просто форматування JSON. 😉\n\n### `orjson` або Модель відповіді { #orjson-or-response-model }\n\nЯкщо ви шукаєте продуктивність, імовірно, краще використати [Модель відповіді](../tutorial/response-model.md), ніж відповідь `orjson`.\n\nЗ моделлю відповіді FastAPI використає Pydantic, щоб серіалізувати дані в JSON без проміжних кроків, як-от перетворення за допомогою `jsonable_encoder`, що відбувалося б в іншому випадку.\n\nІ «під капотом» Pydantic використовує ті самі внутрішні механізми Rust, що й `orjson`, для серіалізації в JSON, тож ви вже отримаєте найкращу продуктивність із моделлю відповіді.\n\n## Типова відповідь за замовчуванням { #default-response-class }\n\nСтворюючи екземпляр класу **FastAPI** або `APIRouter`, ви можете вказати, який клас відповіді використовувати за замовчуванням.\n\nПараметр, що це визначає, - `default_response_class`.\n\nУ прикладі нижче **FastAPI** використовуватиме `HTMLResponse` за замовчуванням в усіх операціях шляху, замість JSON.\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip | Порада\n\nВи все одно можете переписати `response_class` в операціях шляху, як і раніше.\n\n///\n\n## Додаткова документація { #additional-documentation }\n\nВи також можете оголосити медіа-тип і багато інших деталей в OpenAPI, використовуючи `responses`: [Додаткові відповіді в OpenAPI](additional-responses.md).\n"
  },
  {
    "path": "docs/uk/docs/advanced/dataclasses.md",
    "content": "# Використання dataclasses { #using-dataclasses }\n\nFastAPI побудовано поверх **Pydantic**, і я показував вам, як використовувати моделі Pydantic для оголошення запитів і відповідей.\n\nАле FastAPI також підтримує використання [`dataclasses`](https://docs.python.org/3/library/dataclasses.html) таким самим чином:\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\nЦе підтримується завдяки **Pydantic**, адже він має [внутрішню підтримку `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel).\n\nТож навіть із наведеним вище кодом, який явно не використовує Pydantic, FastAPI використовує Pydantic, щоб перетворити стандартні dataclasses у власний варіант dataclasses Pydantic.\n\nІ, звісно, підтримується те саме:\n\n* валідація даних\n* серіалізація даних\n* документація даних тощо\n\nЦе працює так само, як із моделями Pydantic. Насправді під капотом це також досягається за допомогою Pydantic.\n\n/// info\n\nМайте на увазі, що dataclasses не можуть робити все те, що можуть моделі Pydantic.\n\nТож вам усе ще може знадобитися використовувати моделі Pydantic.\n\nАле якщо у вас вже є чимало dataclasses, це зручний трюк, щоб задіяти їх для веб-API на FastAPI. 🤓\n\n///\n\n## Dataclasses у `response_model` { #dataclasses-in-response-model }\n\nВи також можете використовувати `dataclasses` у параметрі `response_model`:\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\nDataclass буде автоматично перетворено на dataclass Pydantic.\n\nТаким чином його схема з'явиться в інтерфейсі користувача документації API:\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## Dataclasses у вкладених структурах даних { #dataclasses-in-nested-data-structures }\n\nМожна поєднувати `dataclasses` з іншими анотаціями типів, щоб створювати вкладені структури даних.\n\nУ деяких випадках вам усе ж доведеться використовувати варіант `dataclasses` від Pydantic. Наприклад, якщо виникають помилки з автоматично згенерованою документацією API.\n\nУ такому разі ви можете просто замінити стандартні `dataclasses` на `pydantic.dataclasses`, що є взаємозамінником:\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. Ми все ще імпортуємо `field` зі стандартних `dataclasses`.\n\n2. `pydantic.dataclasses` - це взаємозамінник для `dataclasses`.\n\n3. Dataclass `Author` містить список dataclass `Item`.\n\n4. Dataclass `Author` використовується як параметр `response_model`.\n\n5. Ви можете використовувати інші стандартні анотації типів із dataclasses як тіло запиту.\n\n    У цьому випадку це список dataclass `Item`.\n\n6. Тут ми повертаємо словник, що містить `items`, який є списком dataclass.\n\n    FastAPI усе ще здатний <dfn title=\"перетворення даних у формат, який можна передати\">серіалізувати</dfн> дані до JSON.\n\n7. Тут у `response_model` використано анотацію типу список dataclass `Author`.\n\n    Знову ж, ви можете поєднувати `dataclasses` зі стандартними анотаціями типів.\n\n8. Зверніть увагу, що ця *функція операції шляху* використовує звичайний `def` замість `async def`.\n\n    Як завжди, у FastAPI ви можете поєднувати `def` і `async def` за потреби.\n\n    Якщо вам потрібне коротке нагадування, коли що використовувати, перегляньте розділ _«Поспішаєте?»_ у документації про [`async` та `await`](../async.md#in-a-hurry).\n\n9. Ця *функція операції шляху* не повертає dataclasses (хоча могла б), а список словників із внутрішніми даними.\n\n    FastAPI використає параметр `response_model` (що включає dataclasses), щоб перетворити відповідь.\n\nВи можете поєднувати `dataclasses` з іншими анотаціями типів у багатьох поєднаннях, щоб формувати складні структури даних.\n\nПерегляньте підказки щодо анотацій у коді вище, щоб побачити більше деталей.\n\n## Дізнатися більше { #learn-more }\n\nМожна поєднувати `dataclasses` з іншими моделями Pydantic, наслідувати їх, включати у власні моделі тощо.\n\nЩоб дізнатися більше, перегляньте [документацію Pydantic про dataclasses](https://docs.pydantic.dev/latest/concepts/dataclasses/).\n\n## Версія { #version }\n\nДоступно починаючи з версії FastAPI `0.67.0`. 🔖\n"
  },
  {
    "path": "docs/uk/docs/advanced/events.md",
    "content": "# Події тривалості життя { #lifespan-events }\n\nВи можете визначити логіку (код), яку слід виконати перед тим, як застосунок запуститься. Це означає, що цей код буде виконано один раз, перед тим як застосунок почне отримувати запити.\n\nТак само ви можете визначити логіку (код), яку слід виконати під час вимкнення застосунку. У цьому випадку код буде виконано один раз, після обробки можливо багатьох запитів.\n\nОскільки цей код виконується перед тим, як застосунок почне приймати запити, і одразу після того, як він завершить їх обробку, він охоплює всю тривалість життя застосунку (слово «lifespan» буде важливим за мить 😉).\n\nЦе дуже корисно для налаштування ресурсів, які потрібні для всього застосунку, які спільні між запитами, та/або які потрібно потім прибрати. Наприклад, пул з’єднань з базою даних або завантаження спільної моделі машинного навчання.\n\n## Випадок використання { #use-case }\n\nПочнемо з прикладу випадку використання, а потім подивимось, як це вирішити.\n\nУявімо, що у вас є моделі машинного навчання, якими ви хочете обробляти запити. 🤖\n\nТі самі моделі спільні між запитами, тобто це не окрема модель на запит чи на користувача.\n\nУявімо, що завантаження моделі може займати чимало часу, бо треба читати багато даних з диска. Тож ви не хочете робити це для кожного запиту.\n\nВи могли б завантажити її на верхньому рівні модуля/файлу, але це означало б, що модель завантажиться навіть якщо ви просто запускаєте простий автоматизований тест - тоді тест буде повільним, бо йому доведеться чекати завантаження моделі перед виконанням незалежної частини коду.\n\nОсь це ми й вирішимо: завантажимо модель перед обробкою запитів, але лише безпосередньо перед тим, як застосунок почне отримувати запити, а не під час завантаження коду.\n\n## Тривалість життя { #lifespan }\n\nВи можете визначити цю логіку запуску і вимкнення за допомогою параметра `lifespan` застосунку `FastAPI` та «менеджера контексту» (зараз покажу, що це).\n\nПочнемо з прикладу, а потім розберемо детально.\n\nМи створюємо асинхронну функцію `lifespan()` з `yield` так:\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\nТут ми імітуємо дорогу операцію запуску із завантаженням моделі, поміщаючи (фальшиву) функцію моделі у словник з моделями машинного навчання перед `yield`. Цей код буде виконано перед тим, як застосунок почне приймати запити, під час запуску.\n\nА одразу після `yield` ми розвантажуємо модель. Цей код буде виконано після того, як застосунок завершить обробку запитів, безпосередньо перед вимкненням. Це, наприклад, може звільнити ресурси на кшталт пам’яті або GPU.\n\n/// tip | Порада\n\nПодія `shutdown` відбувається, коли ви зупиняєте застосунок.\n\nМожливо, вам треба запустити нову версію, або ви просто втомилися її запускати. 🤷\n\n///\n\n### Функція тривалості життя { #lifespan-function }\n\nПерше, на що слід звернути увагу: ми визначаємо асинхронну функцію з `yield`. Це дуже схоже на залежності з `yield`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\nПерша частина функції до `yield` буде виконана перед запуском застосунку.\n\nА частина після `yield` буде виконана після завершення роботи застосунку.\n\n### Асинхронний менеджер контексту { #async-context-manager }\n\nЯкщо придивитися, функція задекорована за допомогою `@asynccontextmanager`.\n\nЦе перетворює функцію на так званий «асинхронний менеджер контексту».\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\nМенеджер контексту в Python - це те, що можна використовувати в операторі `with`, наприклад, `open()` можна використовувати як менеджер контексту:\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\nУ новіших версіях Python також є асинхронний менеджер контексту. Його використовують з `async with`:\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\nКоли ви створюєте менеджер контексту або асинхронний менеджер контексту, як вище, перед входом у блок `with` буде виконано код перед `yield`, а після виходу з блоку `with` буде виконано код після `yield`.\n\nУ нашому прикладі коду вище ми не використовуємо його напряму, а передаємо його до FastAPI, щоб він його використав.\n\nПараметр `lifespan` застосунку `FastAPI` приймає асинхронний менеджер контексту, тож ми можемо передати йому наш новий асинхронний менеджер контексту `lifespan`.\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## Альтернативні події (застаріло) { #alternative-events-deprecated }\n\n/// warning | Попередження\n\nРекомендований спосіб обробляти запуск і вимкнення - використовувати параметр `lifespan` застосунку `FastAPI`, як описано вище. Якщо ви надаєте параметр `lifespan`, обробники подій `startup` і `shutdown` більше не будуть викликані. Або все через `lifespan`, або все через події - не обидва одночасно.\n\nМожете, ймовірно, пропустити цю частину.\n\n///\n\nЄ альтернативний спосіб визначити логіку, яку слід виконати під час запуску і під час вимкнення.\n\nВи можете визначити обробники подій (функції), які потрібно виконати перед запуском застосунку або коли застосунок вимикається.\n\nЦі функції можна оголошувати як з `async def`, так і звичайним `def`.\n\n### Подія `startup` { #startup-event }\n\nЩоб додати функцію, яку слід виконати перед запуском застосунку, оголосіть її з подією `\"startup\"`:\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\nУ цьому випадку функція-обробник події `startup` ініціалізує «базу даних» предметів (це лише `dict`) деякими значеннями.\n\nВи можете додати більше ніж один обробник події.\n\nІ ваш застосунок не почне приймати запити, доки всі обробники події `startup` не завершаться.\n\n### Подія `shutdown` { #shutdown-event }\n\nЩоб додати функцію, яку слід виконати, коли застосунок вимикається, оголосіть її з подією `\"shutdown\"`:\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\nТут функція-обробник події `shutdown` запише текстовий рядок `\"Application shutdown\"` у файл `log.txt`.\n\n/// info | Інформація\n\nУ функції `open()` параметр `mode=\"a\"` означає «append», тож рядок буде додано після всього, що є у файлі, без перезапису попереднього вмісту.\n\n///\n\n/// tip | Порада\n\nЗауважте, що в цьому випадку ми використовуємо стандартну Python-функцію `open()`, яка працює з файлом.\n\nТобто вона включає I/O (input/output), де потрібно «чекати», поки дані буде записано на диск.\n\nАле `open()` не використовує `async` і `await`.\n\nТому ми оголошуємо функцію-обробник події зі стандартним `def`, а не `async def`.\n\n///\n\n### Разом `startup` і `shutdown` { #startup-and-shutdown-together }\n\nВелика ймовірність, що логіка для вашого запуску і вимкнення пов’язана: ви можете хотіти щось запустити, а потім завершити, отримати ресурс, а потім звільнити його тощо.\n\nРобити це в окремих функціях, які не діляться логікою чи змінними, складніше - доведеться зберігати значення у глобальних змінних або вдаватися до подібних трюків.\n\nТому зараз рекомендується натомість використовувати `lifespan`, як пояснено вище.\n\n## Технічні деталі { #technical-details }\n\nНевелика технічна деталь для допитливих нердів. 🤓\n\nПід капотом, у технічній специфікації ASGI, це частина [Протоколу тривалості життя](https://asgi.readthedocs.io/en/latest/specs/lifespan.html), і там визначені події `startup` і `shutdown`.\n\n/// info | Інформація\n\nВи можете прочитати більше про обробники `lifespan` у [документації Starlette про Lifespan](https://www.starlette.dev/lifespan/).\n\nЗокрема, як працювати зі станом тривалості життя, який можна використовувати в інших ділянках вашого коду.\n\n///\n\n## Підзастосунки { #sub-applications }\n\n🚨 Майте на увазі, що ці події тривалості життя (startup і shutdown) виконуються лише для головного застосунку, а не для [Підзастосунки - монтування](sub-applications.md).\n"
  },
  {
    "path": "docs/uk/docs/advanced/generate-clients.md",
    "content": "# Генерація SDK { #generating-sdks }\n\nОскільки **FastAPI** базується на специфікації **OpenAPI**, його API можна описати у стандартному форматі, який розуміють багато інструментів.\n\nЦе спрощує створення актуальної **документації**, клієнтських бібліотек (<abbr title=\"Software Development Kits - Набори для розробки програмного забезпечення\">**SDKs**</abbr>) багатьма мовами, а також **тестування** чи **автоматизованих робочих процесів**, що залишаються синхронізованими з вашим кодом.\n\nУ цьому посібнику ви дізнаєтеся, як згенерувати **TypeScript SDK** для вашого бекенда на FastAPI.\n\n## Генератори SDK з відкритим кодом { #open-source-sdk-generators }\n\nУніверсальним варіантом є [OpenAPI Generator](https://openapi-generator.tech/), який підтримує **багато мов програмування** та може генерувати SDK з вашої специфікації OpenAPI.\n\nДля **клієнтів TypeScript** [Hey API](https://heyapi.dev/) — спеціалізоване рішення, що надає оптимізований досвід для екосистеми TypeScript.\n\nБільше генераторів SDK ви можете знайти на [OpenAPI.Tools](https://openapi.tools/#sdk).\n\n/// tip | Порада\n\nFastAPI автоматично генерує специфікації **OpenAPI 3.1**, тож будь-який інструмент, який ви використовуєте, має підтримувати цю версію.\n\n///\n\n## Генератори SDK від спонсорів FastAPI { #sdk-generators-from-fastapi-sponsors }\n\nУ цьому розділі представлено рішення від компаній, що спонсорують FastAPI: вони мають **венчурну підтримку** та **корпоративну підтримку**. Ці продукти надають **додаткові можливості** та **інтеграції** поверх високоякісно згенерованих SDK.\n\nЗавдяки ✨ [**спонсорству FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ ці компанії допомагають підтримувати фреймворк та його **екосистему** здоровими та **сталими**.\n\nЇхня підтримка також демонструє сильну відданість **спільноті** FastAPI (вам), показуючи, що їм важливо не лише надавати **відмінний сервіс**, а й підтримувати **міцний і процвітаючий фреймворк**, FastAPI. 🙇\n\nНаприклад, ви можете спробувати:\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\nДеякі з цих рішень також можуть бути з відкритим кодом або мати безкоштовні тарифи, тож ви можете спробувати їх без фінансових зобов'язань. Інші комерційні генератори SDK також доступні й їх можна знайти онлайн. 🤓\n\n## Створити TypeScript SDK { #create-a-typescript-sdk }\n\nПочнімо з простого застосунку FastAPI:\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\nЗверніть увагу, що *операції шляху* визначають моделі, які вони використовують для корисного навантаження запиту та корисного навантаження відповіді, використовуючи моделі `Item` і `ResponseMessage`.\n\n### Документація API { #api-docs }\n\nЯкщо ви перейдете до `/docs`, ви побачите **схеми** даних, які надсилаються в запитах і приймаються у відповідях:\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\nВи бачите ці схеми, оскільки їх було оголошено як моделі в застосунку.\n\nЦя інформація доступна у **схемі OpenAPI** застосунку, а потім показується в документації API.\n\nТа сама інформація з моделей, яку включено до OpenAPI, може бути використана для **генерації клієнтського коду**.\n\n### Hey API { #hey-api }\n\nКоли у нас є застосунок FastAPI з моделями, ми можемо використати Hey API для генерації клієнта TypeScript. Найшвидший спосіб зробити це — через npx.\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\nЦе згенерує TypeScript SDK у `./src/client`.\n\nВи можете дізнатися, як [встановити `@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started), і почитати про [згенерований результат](https://heyapi.dev/openapi-ts/output) на їхньому сайті.\n\n### Використання SDK { #using-the-sdk }\n\nТепер ви можете імпортувати та використовувати клієнтський код. Це може виглядати так; зверніть увагу, що ви отримуєте «автодоповнення» для методів:\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\nВи також отримаєте автодоповнення для корисного навантаження, яке надсилаєте:\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip | Порада\n\nЗверніть увагу на автодоповнення для `name` і `price`, які були визначені в застосунку FastAPI, у моделі `Item`.\n\n///\n\nВи бачитимете вбудовані помилки для даних, які надсилаєте:\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\nОб'єкт відповіді також матиме автодоповнення:\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## Застосунок FastAPI з мітками { #fastapi-app-with-tags }\n\nУ багатьох випадках ваш застосунок FastAPI буде більшим, і ви, ймовірно, використовуватимете мітки, щоб розділяти різні групи *операцій шляху*.\n\nНаприклад, у вас може бути секція для **items** і окрема секція для **users**, і їх можна розділити мітками:\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### Згенерувати TypeScript-клієнт із мітками { #generate-a-typescript-client-with-tags }\n\nЯкщо ви згенеруєте клієнт для застосунку FastAPI, що використовує мітки, зазвичай клієнтський код також буде розділено за цими мітками.\n\nТаким чином, ви матимете правильно впорядковані та згруповані частини клієнтського коду:\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\nУ цьому випадку у вас є:\n\n* `ItemsService`\n* `UsersService`\n\n### Назви методів клієнта { #client-method-names }\n\nЗараз згенеровані назви методів на кшталт `createItemItemsPost` виглядають не дуже охайно:\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n...це тому, що генератор клієнта використовує внутрішній OpenAPI **operation ID** для кожної *операції шляху*.\n\nOpenAPI вимагає, щоб кожен operation ID був унікальним для всіх *операцій шляху*, тому FastAPI використовує **назву функції**, **шлях** і **HTTP-метод/операцію** для генерації цього operation ID, адже так воно може гарантувати унікальність operation ID.\n\nАле далі я покажу, як це покращити. 🤓\n\n## Користувацькі operation ID та кращі назви методів { #custom-operation-ids-and-better-method-names }\n\nВи можете **змінити** спосіб **генерації** цих operation ID, щоб зробити їх простішими та мати **простіші назви методів** у клієнтах.\n\nУ цьому випадку вам потрібно буде іншим способом гарантувати, що кожен operation ID є **унікальним**.\n\nНаприклад, ви можете переконатися, що кожна *операція шляху* має мітку, а потім генерувати operation ID на основі **мітки** та **назви** *операції шляху* (назви функції).\n\n### Користувацька функція генерування унікального ID { #custom-generate-unique-id-function }\n\nFastAPI використовує **унікальний ID** для кожної *операції шляху*, який застосовується для **operation ID**, а також для назв будь-яких потрібних користувацьких моделей для запитів чи відповідей.\n\nВи можете налаштувати цю функцію. Вона приймає `APIRoute` і повертає строку.\n\nНаприклад, тут використовується перша мітка (у вас, ймовірно, буде лише одна мітка) і назва *операції шляху* (назва функції).\n\nПотім ви можете передати цю користувацьку функцію до **FastAPI** як параметр `generate_unique_id_function`:\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### Згенерувати TypeScript-клієнт з користувацькими operation ID { #generate-a-typescript-client-with-custom-operation-ids }\n\nТепер, якщо ви згенеруєте клієнт знову, ви побачите покращені назви методів:\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\nЯк бачите, тепер у назвах методів є мітка, а потім назва функції; вони більше не містять інформації з URL-шляху та HTTP-операції.\n\n### Попередня обробка специфікації OpenAPI для генератора клієнта { #preprocess-the-openapi-specification-for-the-client-generator }\n\nУ згенерованому коді все ще є певна **дубльована інформація**.\n\nМи вже знаємо, що цей метод стосується **items**, адже це слово є в `ItemsService` (взято з мітки), але все ще маємо назву мітки як префікс у назві методу. 😕\n\nМи, ймовірно, все одно захочемо зберегти це загалом для OpenAPI, адже так гарантується унікальність operation ID.\n\nАле для згенерованого клієнта ми можемо **змінити** operation ID в OpenAPI безпосередньо перед генерацією клієнтів, просто щоб зробити назви методів приємнішими та **чистішими**.\n\nМи можемо завантажити JSON OpenAPI у файл `openapi.json`, а потім **прибрати цей префікс із міткою** за допомогою такого скрипту:\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\nПісля цього operation ID буде перейменовано з чогось на кшталт `items-get_items` просто на `get_items`, тож генератор клієнта зможе створити простіші назви методів.\n\n### Згенерувати TypeScript-клієнт із попередньо обробленим OpenAPI { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\nОскільки кінцевий результат тепер у файлі `openapi.json`, вам потрібно оновити шлях до вхідних даних:\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\nПісля генерації нового клієнта ви отримаєте **чисті назви методів**, із усім **автодоповненням**, **вбудованими помилками** тощо:\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## Переваги { #benefits }\n\nВикористовуючи автоматично згенеровані клієнти, ви отримаєте **автодоповнення** для:\n\n* Методів.\n* Корисного навантаження запиту в тілі, параметрах запиту тощо.\n* Корисного навантаження відповіді.\n\nТакож ви матимете **вбудовані помилки** для всього.\n\nІ щоразу, коли ви оновлюєте код бекенда та **перегенеровуєте** фронтенд, у ньому з'являтимуться нові *операції шляху* як методи, старі буде видалено, а будь-які інші зміни відобразяться у згенерованому коді. 🤓\n\nЦе також означає, що якщо щось змінилося, це буде **відображено** в клієнтському коді автоматично. А якщо ви **зіберете** клієнт, буде повідомлено про помилку, якщо є будь-яка **невідповідність** у використаних даних.\n\nТаким чином, ви **виявлятимете багато помилок** дуже рано в циклі розробки, замість того, щоб чекати, поки помилки проявляться у ваших кінцевих користувачів у продакшені, і лише потім намагатися з'ясувати, у чому проблема. ✨\n"
  },
  {
    "path": "docs/uk/docs/advanced/index.md",
    "content": "# Просунутий посібник користувача { #advanced-user-guide }\n\n## Додаткові можливості { #additional-features }\n\nОсновний [Навчальний посібник - Посібник користувача](../tutorial/index.md) має бути достатнім, щоб провести вас через усі основні можливості **FastAPI**.\n\nУ наступних розділах ви побачите інші опції, конфігурації та додаткові можливості.\n\n/// tip\n\nНаступні розділи **не обов'язково «просунуті»**.\n\nІ можливо, що рішення для вашого випадку використання може бути в одному з них.\n\n///\n\n## Спершу прочитайте навчальний посібник { #read-the-tutorial-first }\n\nВи все ще можете використовувати більшість можливостей **FastAPI**, маючи знання з основного [Навчального посібника - Посібника користувача](../tutorial/index.md).\n\nА в наступних розділах передбачається, що ви вже його прочитали і знайомі з основними ідеями.\n"
  },
  {
    "path": "docs/uk/docs/advanced/json-base64-bytes.md",
    "content": "# JSON з байтами як Base64 { #json-with-bytes-as-base64 }\n\nЯкщо ваш застосунок має отримувати і надсилати дані JSON, але потрібно включати туди двійкові дані, ви можете кодувати їх як base64.\n\n## Base64 проти файлів { #base64-vs-files }\n\nНасамперед розгляньте, чи можете ви використати [Файли запиту](../tutorial/request-files.md) для завантаження двійкових даних і [Користувацька відповідь - FileResponse](./custom-response.md#fileresponse--fileresponse-) для надсилання двійкових даних замість кодування їх у JSON.\n\nJSON може містити лише строки, закодовані в UTF-8, тому він не може містити «сирі» байти.\n\nBase64 може кодувати двійкові дані у строках, але для цього потрібно більше символів, ніж у початкових двійкових даних, тож зазвичай це менш ефективно, ніж звичайні файли.\n\nВикористовуйте base64 лише якщо справді потрібно включати двійкові дані в JSON і ви не можете використати файли для цього.\n\n## Pydantic `bytes` { #pydantic-bytes }\n\nВи можете оголосити модель Pydantic з полями `bytes`, а потім використати `val_json_bytes` у конфігурації моделі, щоб вказати їй використовувати base64 для перевірки вхідних даних JSON; як частина цієї перевірки, вона декодує строку base64 у байти.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\nЯкщо ви перевірите `/docs`, там буде показано, що поле `data` очікує байти, закодовані в base64:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\nВи можете надіслати запит так:\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip | Порада\n\n`aGVsbG8=` - це кодування base64 для `hello`.\n\n///\n\nПісля цього Pydantic декодує строку base64 і надасть вам початкові байти в полі моделі `data`.\n\nВи отримаєте відповідь приблизно таку:\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## Pydantic `bytes` для вихідних даних { #pydantic-bytes-for-output-data }\n\nВи також можете використовувати поля `bytes` з `ser_json_bytes` у конфігурації моделі для вихідних даних, і Pydantic серіалізує байти як base64 під час формування відповіді JSON.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## Pydantic `bytes` для вхідних і вихідних даних { #pydantic-bytes-for-input-and-output-data }\n\nІ, звісно, ви можете використовувати ту саму модель, налаштовану на base64, щоб обробляти і вхідні дані (перевіряти) з `val_json_bytes`, і вихідні дані (серіалізувати) з `ser_json_bytes` під час отримання та надсилання даних JSON.\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/uk/docs/advanced/middleware.md",
    "content": "# Просунуте проміжне програмне забезпечення { #advanced-middleware }\n\nУ головному навчальному посібнику ви читали, як додати [Користувацьке проміжне ПЗ](../tutorial/middleware.md) до вашого застосунку.\n\nТакож ви читали, як обробляти [CORS за допомогою `CORSMiddleware`](../tutorial/cors.md).\n\nУ цьому розділі розглянемо, як використовувати інше проміжне ПЗ.\n\n## Додавання middleware ASGI { #adding-asgi-middlewares }\n\nОскільки **FastAPI** базується на Starlette і реалізує специфікацію <abbr title=\"Asynchronous Server Gateway Interface - Асинхронний інтерфейс шлюзу сервера\">ASGI</abbr>, ви можете використовувати будь-яке проміжне ПЗ ASGI.\n\nMiddleware не обов'язково має бути створене саме для FastAPI або Starlette, головне - щоб воно відповідало специфікації ASGI.\n\nЗагалом, middleware ASGI — це класи, які очікують отримати застосунок ASGI як перший аргумент.\n\nТож у документації до сторонніх middleware ASGI вам, імовірно, порадять зробити приблизно так:\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\nАле FastAPI (точніше Starlette) надає простіший спосіб, який гарантує, що внутрішнє middleware обробляє помилки сервера, а користувацькі обробники винятків працюють коректно.\n\nДля цього використовуйте `app.add_middleware()` (як у прикладі для CORS).\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` приймає клас middleware як перший аргумент і будь-які додаткові аргументи, що будуть передані цьому middleware.\n\n## Вбудоване middleware { #integrated-middlewares }\n\n**FastAPI** містить кілька middleware для поширених випадків використання, далі розглянемо, як їх використовувати.\n\n/// note | Технічні деталі\n\nУ наступних прикладах ви також можете використовувати `from starlette.middleware.something import SomethingMiddleware`.\n\n**FastAPI** надає кілька middleware у `fastapi.middleware` виключно для зручності розробника. Але більшість доступних middleware походять безпосередньо зі Starlette.\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\nПримушує, щоб усі вхідні запити були або `https`, або `wss`.\n\nБудь-який вхідний запит до `http` або `ws` буде перенаправлено на захищену схему.\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\nПримушує, щоб усі вхідні запити мали коректно встановлений заголовок `Host`, щоб захиститися від атак HTTP Host Header.\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\nПідтримуються такі аргументи:\n\n- `allowed_hosts` - Список доменних імен, які слід дозволити як імена хостів. Підтримуються домени з «дикою картою», такі як `*.example.com`, для зіставлення піддоменів. Щоб дозволити будь-яке ім'я хоста, або використовуйте `allowed_hosts=[\"*\"]`, або не додавайте це middleware.\n- `www_redirect` - Якщо встановлено True, запити до не-www версій дозволених хостів буде перенаправлено до їхніх www-варіантів. Типово `True`.\n\nЯкщо вхідний запит не проходить перевірку, буде надіслано відповідь `400`.\n\n## `GZipMiddleware` { #gzipmiddleware }\n\nОбробляє відповіді GZip для будь-якого запиту, що містить `\"gzip\"` у заголовку `Accept-Encoding`.\n\nMiddleware обробляє як стандартні, так і потокові відповіді.\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\nПідтримуються такі аргументи:\n\n- `minimum_size` - Не GZip-увати відповіді, менші за цей мінімальний розмір у байтах. Типово `500`.\n- `compresslevel` - Використовується під час стиснення GZip. Це ціле число в діапазоні від 1 до 9. Типово `9`. Менше значення дає швидше стиснення, але більший розмір файлів; більше значення дає повільніше стиснення, але менший розмір файлів.\n\n## Інше middleware { #other-middlewares }\n\nЄ багато іншого проміжного ПЗ ASGI.\n\nНаприклад:\n\n- [`ProxyHeadersMiddleware` з Uvicorn](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n- [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\nЩоб переглянути інші доступні middleware, ознайомтеся з [документацією Starlette щодо middleware](https://www.starlette.dev/middleware/) та [списком ASGI Awesome](https://github.com/florimondmanca/awesome-asgi).\n"
  },
  {
    "path": "docs/uk/docs/advanced/openapi-callbacks.md",
    "content": "# Зворотні виклики OpenAPI { #openapi-callbacks }\n\nВи можете створити API з операцією шляху, яка ініціюватиме запит до зовнішнього API, створеного кимось іншим (ймовірно тим самим розробником, який буде використовувати ваш API).\n\nПроцес, що відбувається, коли ваш застосунок API викликає зовнішній API, називається «зворотний виклик». Тому що програмне забезпечення, написане зовнішнім розробником, надсилає запит до вашого API, а потім ваш API виконує зворотний виклик, надсилаючи запит до зовнішнього API (його, ймовірно, також створив той самий розробник).\n\nУ такому випадку вам може знадобитися задокументувати, яким має бути той зовнішній API: які операції шляху він має мати, яке тіло очікувати, яку відповідь повертати тощо.\n\n## Застосунок зі зворотними викликами { #an-app-with-callbacks }\n\nРозгляньмо це на прикладі.\n\nУявімо, що ви розробляєте застосунок для створення рахунків.\n\nЦі рахунки матимуть `id`, `title` (необов'язково), `customer` і `total`.\n\nКористувач вашого API (зовнішній розробник) створить рахунок у вашому API за допомогою POST-запиту.\n\nПотім ваш API буде (уявімо):\n\n- Надсилати рахунок деякому клієнту зовнішнього розробника.\n- Отримувати оплату.\n- Надсилати сповіщення назад користувачу API (зовнішньому розробнику).\n  - Це буде зроблено шляхом надсилання POST-запиту (з вашого API) до деякого зовнішнього API, наданого тим зовнішнім розробником (це і є «зворотний виклик»).\n\n## Звичайний застосунок FastAPI { #the-normal-fastapi-app }\n\nСпочатку подивімося, як виглядав би звичайний застосунок API до додавання зворотного виклику.\n\nВін матиме операцію шляху, яка отримуватиме тіло `Invoice`, і параметр запиту `callback_url`, що міститиме URL для зворотного виклику.\n\nЦя частина цілком звична, більшість коду вам, ймовірно, уже знайома:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip | Порада\n\nПараметр запиту `callback_url` використовує тип Pydantic [Url](https://docs.pydantic.dev/latest/api/networks/).\n\n///\n\nЄдина нова річ - це `callbacks=invoices_callback_router.routes` як аргумент декоратора операції шляху. Далі розглянемо, що це таке.\n\n## Документування зворотного виклику { #documenting-the-callback }\n\nФактичний код зворотного виклику сильно залежатиме від вашого застосунку API.\n\nІ, ймовірно, сильно відрізнятиметься від застосунку до застосунку.\n\nЦе можуть бути лише один-два рядки коду, наприклад:\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\nАле, можливо, найважливіша частина зворотного виклику - переконатися, що користувач вашого API (зовнішній розробник) правильно реалізує зовнішній API відповідно до даних, які ваш API надсилатиме в тілі запиту зворотного виклику тощо.\n\nТому далі ми додамо код, щоб задокументувати, яким має бути цей зовнішній API, щоб приймати зворотний виклик від вашого API.\n\nЦя документація з'явиться в Swagger UI за адресою `/docs` у вашому API і дасть змогу зовнішнім розробникам зрозуміти, як створити зовнішній API.\n\nУ цьому прикладі сам зворотний виклик не реалізовано (це може бути лише один рядок коду), лише частину з документацією.\n\n/// tip | Порада\n\nФактичний зворотний виклик - це просто HTTP-запит.\n\nРеалізуючи зворотний виклик самостійно, ви можете скористатися, наприклад, [HTTPX](https://www.python-httpx.org) або [Requests](https://requests.readthedocs.io/).\n\n///\n\n## Напишіть код документації для зворотного виклику { #write-the-callback-documentation-code }\n\nЦей код не виконуватиметься у вашому застосунку, він потрібен лише, щоб задокументувати, яким має бути зовнішній API.\n\nАле ви вже знаєте, як легко створювати автоматичну документацію для API за допомогою FastAPI.\n\nТож ми скористаємося цими знаннями, щоб задокументувати, яким має бути зовнішній API... створивши операції шляху, які має реалізувати зовнішній API (ті, які викликатиме ваш API).\n\n/// tip | Порада\n\nПишучи код для документування зворотного виклику, корисно уявити, що ви - той *зовнішній розробник*. І що ви зараз реалізуєте *зовнішній API*, а не *ваш API*.\n\nТимчасово прийнявши цю точку зору ( *зовнішнього розробника* ), вам буде очевидніше, куди помістити параметри, яку Pydantic-модель використати для тіла, для відповіді тощо для того *зовнішнього API*.\n\n///\n\n### Створіть callback `APIRouter` { #create-a-callback-apirouter }\n\nСпочатку створіть новий `APIRouter`, який міститиме один або кілька зворотних викликів.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### Створіть операцію шляху зворотного виклику { #create-the-callback-path-operation }\n\nЩоб створити операцію шляху зворотного виклику, використайте той самий `APIRouter`, який ви створили вище.\n\nВона має виглядати як звичайна операція шляху FastAPI:\n\n- Ймовірно має містити оголошення тіла, яке вона приймає, напр. `body: InvoiceEvent`.\n- І також може містити оголошення відповіді, яку вона повертає, напр. `response_model=InvoiceEventReceived`.\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\nЄ 2 основні відмінності від звичайної операції шляху:\n\n- Їй не потрібен реальний код, адже ваш застосунок ніколи не викликатиме цей код. Вона використовується лише для документування зовнішнього API. Тому функція може просто містити `pass`.\n- Шлях може містити [вираз OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression) (див. нижче), де можна використовувати змінні з параметрами та частини оригінального запиту, надісланого до вашого API.\n\n### Вираз шляху зворотного виклику { #the-callback-path-expression }\n\nШлях зворотного виклику може містити [вираз OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression), який включає частини оригінального запиту, надісланого до вашого API.\n\nУ цьому випадку це строка:\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\nОтже, якщо користувач вашого API (зовнішній розробник) надішле запит до *вашого API* на:\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\nз JSON-тілом:\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\nтоді *ваш API* опрацює рахунок і згодом надішле запит зворотного виклику на `callback_url` ( *зовнішній API* ):\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\nз JSON-тілом на кшталт:\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\nі очікуватиме відповідь від того *зовнішнього API* з JSON-тілом на кшталт:\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip | Порада\n\nЗверніть увагу, що використаний URL зворотного виклику містить URL, отриманий як параметр запиту в `callback_url` (`https://www.external.org/events`), а також `id` рахунку зсередини JSON-тіла (`2expen51ve`).\n\n///\n\n### Додайте маршрутизатор зворотного виклику { #add-the-callback-router }\n\nНа цьому етапі ви маєте потрібні операції шляху зворотного виклику (ті, які має реалізувати *зовнішній розробник* у *зовнішньому API*) у створеному вище маршрутизаторі зворотного виклику.\n\nТепер використайте параметр `callbacks` у декораторі операції шляху вашого API, щоб передати атрибут `.routes` (це насправді просто `list` маршрутів/операцій шляху) з цього маршрутизатора зворотного виклику:\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip | Порада\n\nЗверніть увагу, що ви передаєте не сам маршрутизатор (`invoices_callback_router`) у `callback=`, а атрибут `.routes`, тобто `invoices_callback_router.routes`.\n\n///\n\n### Перевірте документацію { #check-the-docs }\n\nТепер ви можете запустити застосунок і перейти за адресою [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВи побачите вашу документацію з розділом «Callbacks» для вашої операції шляху, який показує, як має виглядати зовнішній API:\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/uk/docs/advanced/openapi-webhooks.md",
    "content": "# Вебхуки OpenAPI { #openapi-webhooks }\n\nБувають випадки, коли ви хочете повідомити **користувачів** вашого API, що ваш застосунок може викликати *їхній* застосунок (надсилаючи запит) із деякими даними, зазвичай щоб **сповістити** про певний тип **події**.\n\nЦе означає, що замість звичного процесу, коли ваші користувачі надсилають запити до вашого API, саме **ваш API** (або ваш застосунок) може **надсилати запити до їхньої системи** (до їх API, їх застосунку).\n\nЗазвичай це називають **вебхуком**.\n\n## Кроки вебхуків { #webhooks-steps }\n\nЗазвичай процес такий: ви визначаєте у своєму коді, яке повідомлення надсилатимете, тобто **тіло запиту**.\n\nВи також якимось чином визначаєте моменти, коли ваш застосунок надсилатиме ці запити або події.\n\nА **ваші користувачі** якимось чином (наприклад, у веб-дашборді) визначають **URL**, куди ваш застосунок має надсилати ці запити.\n\nУся **логіка** щодо реєстрації URL для вебхуків і код для фактичного надсилання цих запитів - на ваш розсуд. Ви пишете це у **власному коді** так, як вважаєте за потрібне.\n\n## Документування вебхуків у **FastAPI** та OpenAPI { #documenting-webhooks-with-fastapi-and-openapi }\n\nУ **FastAPI**, використовуючи OpenAPI, ви можете визначити назви цих вебхуків, типи HTTP-операцій, які ваш застосунок може надсилати (наприклад, `POST`, `PUT` тощо), і **тіла** запитів, які ваш застосунок надсилатиме.\n\nЦе значно спростить для ваших користувачів **реалізацію їхніх API** для отримання ваших запитів **вебхуків**; вони навіть зможуть згенерувати частину власного коду API автоматично.\n\n/// info | Інформація\n\nВебхуки доступні в OpenAPI 3.1.0 і вище, підтримуються FastAPI `0.99.0` і вище.\n\n///\n\n## Застосунок із вебхуками { #an-app-with-webhooks }\n\nКоли ви створюєте застосунок **FastAPI**, є атрибут `webhooks`, який можна використати для визначення *вебхуків* так само, як ви визначаєте *операції шляху*, наприклад за допомогою `@app.webhooks.post()`.\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\nВизначені вами вебхуки потраплять до **схеми OpenAPI** та автоматичного **інтерфейсу документації**.\n\n/// info | Інформація\n\nОб'єкт `app.webhooks` насправді є просто `APIRouter` - тим самим типом, який ви використовуєте, структуризуючи застосунок у кількох файлах.\n\n///\n\nЗверніть увагу, що з вебхуками ви фактично не оголошуєте *шлях* (на кшталт `/items/`), текст, який ви передаєте там, - це лише **ідентифікатор** вебхука (назва події). Наприклад, у `@app.webhooks.post(\"new-subscription\")` назва вебхука - `new-subscription`.\n\nЦе тому, що очікується, що **ваші користувачі** іншим способом (наприклад, у веб-дашборді) визначать фактичний **URL-шлях**, де вони хочуть отримувати запит вебхука.\n\n### Перевірте документацію { #check-the-docs }\n\nТепер ви можете запустити свій застосунок і перейти за адресою [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВи побачите у своїй документації звичайні *операції шляху*, а також деякі **вебхуки**:\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/uk/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# Додаткова конфігурація операцій шляху { #path-operation-advanced-configuration }\n\n## OpenAPI operationId { #openapi-operationid }\n\n/// warning | Попередження\n\nЯкщо ви не «експерт» з OpenAPI, імовірно, вам це не потрібно.\n\n///\n\nВи можете встановити OpenAPI `operationId`, який буде використано у вашій *операції шляху*, за допомогою параметра `operation_id`.\n\nПотрібно переконатися, що він унікальний для кожної операції.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### Використання назви *функції операції шляху* як operationId { #using-the-path-operation-function-name-as-the-operationid }\n\nЯкщо ви хочете використовувати назви функцій ваших API як `operationId`, ви можете пройтися по всіх них і переписати `operation_id` кожної *операції шляху*, використовуючи їхній `APIRoute.name`.\n\nЗробіть це після додавання всіх *операцій шляху*.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip | Порада\n\nЯкщо ви вручну викликаєте `app.openapi()`, оновіть усі `operationId` до цього.\n\n///\n\n/// warning | Попередження\n\nЯкщо ви робите це, переконайтеся, що кожна з ваших *функцій операцій шляху* має унікальну назву.\n\nНавіть якщо вони в різних модулях (файлах Python).\n\n///\n\n## Виключення з OpenAPI { #exclude-from-openapi }\n\nЩоб виключити *операцію шляху* зі згенерованої Схеми OpenAPI (а отже, і з автоматичних систем документації), використайте параметр `include_in_schema` і встановіть його в `False`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## Розширений опис із docstring { #advanced-description-from-docstring }\n\nВи можете обмежити кількість рядків із docstring *функції операції шляху*, що використовуються для OpenAPI.\n\nДодавання `\\f` (екранованого символу «form feed») змусить **FastAPI** обрізати вивід для OpenAPI в цій точці.\n\nЦе не з’явиться в документації, але інші інструменти (такі як Sphinx) зможуть використати решту.\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## Додаткові відповіді { #additional-responses }\n\nЙмовірно, ви вже бачили, як оголошувати `response_model` і `status_code` для *операції шляху*.\n\nЦе визначає метадані про основну відповідь *операції шляху*.\n\nТакож можна оголосити додаткові відповіді з їхніми моделями, кодами статусу тощо.\n\nУ документації є цілий розділ про це, ви можете прочитати його тут: [Додаткові відповіді в OpenAPI](additional-responses.md).\n\n## Додатково в OpenAPI { #openapi-extra }\n\nКоли ви оголошуєте *операцію шляху* у своєму застосунку, **FastAPI** автоматично генерує відповідні метадані про цю *операцію шляху* для включення в Схему OpenAPI.\n\n/// note | Технічні деталі\n\nУ специфікації OpenAPI це називається [Об'єкт Operation](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object).\n\n///\n\nВін містить усю інформацію про *операцію шляху* і використовується для побудови автоматичної документації.\n\nВін включає `tags`, `parameters`, `requestBody`, `responses` тощо.\n\nЦю OpenAPI-схему, специфічну для *операції шляху*, зазвичай генерує **FastAPI** автоматично, але ви також можете її розширити.\n\n/// tip | Порада\n\nЦе низькорівнева точка розширення.\n\nЯкщо вам потрібно лише оголосити додаткові відповіді, зручніше зробити це через [Додаткові відповіді в OpenAPI](additional-responses.md).\n\n///\n\nВи можете розширити OpenAPI-схему для *операції шляху*, використовуючи параметр `openapi_extra`.\n\n### Розширення OpenAPI { #openapi-extensions }\n\n`openapi_extra` може бути корисним, наприклад, для оголошення [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions):\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\nЯкщо ви відкриєте автоматичну документацію API, ваше розширення з’явиться внизу конкретної *операції шляху*.\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\nІ якщо ви відкриєте згенерований OpenAPI (за адресою `/openapi.json` у вашому API), ви також побачите своє розширення як частину конкретної *операції шляху*:\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### Власна схема OpenAPI для *операції шляху* { #custom-openapi-path-operation-schema }\n\nСловник у `openapi_extra` буде глибоко об’єднано з автоматично згенерованою OpenAPI-схемою для *операції шляху*.\n\nТож ви можете додати додаткові дані до автоматично згенерованої схеми.\n\nНаприклад, ви можете вирішити читати та перевіряти запит власним кодом, не використовуючи автоматичні можливості FastAPI з Pydantic, але все ж захотіти визначити запит у Схемі OpenAPI.\n\nВи можете зробити це за допомогою `openapi_extra`:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\nУ цьому прикладі ми не оголошували жодної моделі Pydantic. Насправді тіло запиту навіть не <dfn title=\"перетворено з простого формату, як-от bytes, у об'єкти Python\">розібрано</dfn> як JSON, воно читається безпосередньо як `bytes`, а функція `magic_data_reader()` відповідатиме за його розбір певним чином.\n\nВодночас ми можемо оголосити очікувану схему для тіла запиту.\n\n### Власний тип вмісту OpenAPI { #custom-openapi-content-type }\n\nВикористовуючи той самий прийом, ви можете застосувати модель Pydantic, щоб визначити Схему JSON, яка потім включається в користувацький розділ OpenAPI-схеми для *операції шляху*.\n\nІ ви можете зробити це, навіть якщо тип даних у запиті - не JSON.\n\nНаприклад, у цьому застосунку ми не використовуємо вбудовану функціональність FastAPI для отримання Схеми JSON з моделей Pydantic і не використовуємо автоматичну валідацію для JSON. Насправді ми оголошуємо тип вмісту запиту як YAML, а не JSON:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\nПопри те, що ми не використовуємо типову вбудовану функціональність, ми все одно використовуємо модель Pydantic, щоб вручну згенерувати Схему JSON для даних, які хочемо отримати у форматі YAML.\n\nПотім ми працюємо із запитом безпосередньо і отримуємо тіло як `bytes`. Це означає, що FastAPI навіть не намагатиметься розібрати корисне навантаження запиту як JSON.\n\nДалі у нашому коді ми безпосередньо розбираємо цей YAML-вміст і знову використовуємо ту саму модель Pydantic, щоб перевірити YAML-вміст:\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip | Порада\n\nТут ми перевикористовуємо ту саму модель Pydantic.\n\nАле так само ми могли б перевіряти дані іншим способом.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/advanced/response-change-status-code.md",
    "content": "# Відповідь - зміна коду статусу { #response-change-status-code }\n\nЙмовірно, ви вже читали, що можна встановити типовий [код статусу відповіді](../tutorial/response-status-code.md).\n\nАле інколи потрібно повернути інший код статусу, ніж типовий.\n\n## Випадок використання { #use-case }\n\nНаприклад, уявімо, що ви хочете за замовчуванням повертати код статусу HTTP «OK» `200`.\n\nАле якщо даних не існувало, ви хочете створити їх і повернути код статусу HTTP «CREATED» `201`.\n\nВодночас ви все одно хочете мати змогу фільтрувати та перетворювати повернені дані за допомогою `response_model`.\n\nДля таких випадків ви можете використати параметр `Response`.\n\n## Використовуйте параметр `Response` { #use-a-response-parameter }\n\nВи можете оголосити параметр типу `Response` у своїй функції операції шляху (так само, як для кукі та заголовків).\n\nПотім ви можете встановити `status_code` у цьому *тимчасовому* об'єкті відповіді.\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\nПісля цього ви можете повернути будь-який потрібний об'єкт, як зазвичай (`dict`, модель бази даних тощо).\n\nІ якщо ви оголосили `response_model`, він усе одно буде використаний для фільтрації та перетворення поверненого об'єкта.\n\n**FastAPI** використає цей *тимчасовий* об'єкт відповіді, щоб отримати код статусу (а також кукі та заголовки), і помістить їх у фінальну відповідь, що містить повернуте вами значення, відфільтроване за допомогою `response_model`.\n\nВи також можете оголосити параметр `Response` у залежностях і встановлювати там код статусу. Але майте на увазі: останнє встановлене значення матиме пріоритет.\n"
  },
  {
    "path": "docs/uk/docs/advanced/response-cookies.md",
    "content": "# Кукі у відповіді { #response-cookies }\n\n## Використовуйте параметр `Response` { #use-a-response-parameter }\n\nВи можете оголосити параметр типу `Response` у вашій *функції операції шляху*.\n\nПотім ви можете встановити кукі в цьому *тимчасовому* об'єкті відповіді.\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\nПісля цього ви можете повернути будь-який потрібний об'єкт, як зазвичай (наприклад, `dict`, модель бази даних тощо).\n\nІ якщо ви оголосили `response_model`, він усе одно буде використаний для фільтрації та перетворення об'єкта, який ви повернули.\n\n**FastAPI** використає цю *тимчасову* відповідь, щоб витягнути кукі (а також заголовки та код статусу) і помістить їх у фінальну відповідь, що містить значення, яке ви повернули, відфільтроване будь-якою `response_model`.\n\nВи також можете оголосити параметр `Response` у залежностях і встановлювати в них кукі (і заголовки).\n\n## Повертайте `Response` безпосередньо { #return-a-response-directly }\n\nВи також можете створювати кукі, повертаючи `Response` безпосередньо у вашому коді.\n\nДля цього ви можете створити відповідь, як описано в [Повернути відповідь безпосередньо](response-directly.md).\n\nПотім встановіть у ньому кукі і поверніть його:\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip\n\nМайте на увазі, що якщо ви повертаєте відповідь безпосередньо замість використання параметра `Response`, FastAPI поверне її напряму.\n\nТому вам потрібно переконатися, що ваші дані мають коректний тип. Наприклад, сумісні з JSON, якщо ви повертаєте `JSONResponse`.\n\nА також що ви не надсилаєте дані, які мали б бути відфільтровані за допомогою `response_model`.\n\n///\n\n### Більше інформації { #more-info }\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette.responses import Response` або `from starlette.responses import JSONResponse`.\n\n**FastAPI** надає ті самі `starlette.responses` як `fastapi.responses` лише для зручності для вас, розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette.\n\nІ оскільки `Response` часто використовується для встановлення заголовків і кукі, **FastAPI** також надає його як `fastapi.Response`.\n\n///\n\nЩоб побачити всі доступні параметри та опції, перегляньте [документацію в Starlette](https://www.starlette.dev/responses/#set-cookie).\n"
  },
  {
    "path": "docs/uk/docs/advanced/response-directly.md",
    "content": "# Повернення Response безпосередньо { #return-a-response-directly }\n\nКоли ви створюєте операцію шляху **FastAPI**, зазвичай ви можете повертати з неї будь-які дані: `dict`, `list`, модель Pydantic, модель бази даних тощо.\n\nЯкщо ви оголосите [Модель відповіді](../tutorial/response-model.md), **FastAPI** використає її, щоб серіалізувати дані у JSON за допомогою Pydantic.\n\nЯкщо ви не оголошуєте модель відповіді, **FastAPI** використає `jsonable_encoder`, описаний у [Сумісному з JSON кодері](../tutorial/encoder.md), і помістить результат у `JSONResponse`.\n\nВи також можете створити `JSONResponse` безпосередньо і повернути його.\n\n/// tip | Порада\n\nЗазвичай ви отримаєте значно кращу продуктивність, використовуючи [Модель відповіді](../tutorial/response-model.md), ніж повертаючи `JSONResponse` безпосередньо, адже так дані серіалізуються Pydantic на Rust.\n\n///\n\n## Повернення `Response` { #return-a-response }\n\nВи можете повертати `Response` або будь-який його підклас.\n\n/// info | Інформація\n\n`JSONResponse` сам є підкласом `Response`.\n\n///\n\nІ коли ви повертаєте `Response`, **FastAPI** передасть його безпосередньо.\n\nВін не виконуватиме жодних перетворень даних за допомогою моделей Pydantic, не перетворюватиме вміст на будь-який тип тощо.\n\nЦе дає вам багато гнучкості. Ви можете повертати будь-які типи даних, переписувати будь-які оголошення або перевірки даних тощо.\n\nЦе також покладає на вас багато відповідальності. Ви маєте переконатися, що дані, які ви повертаєте, коректні, у правильному форматі, можуть бути серіалізовані тощо.\n\n## Використання `jsonable_encoder` у `Response` { #using-the-jsonable-encoder-in-a-response }\n\nОскільки **FastAPI** не вносить змін у `Response`, який ви повертаєте, вам потрібно впевнитися, що його вміст готовий.\n\nНаприклад, ви не можете помістити модель Pydantic у `JSONResponse`, не перетворивши її спочатку на `dict` з усіма типами даних (як-от `datetime`, `UUID` тощо), перетвореними на типи, сумісні з JSON.\n\nДля таких випадків ви можете використати `jsonable_encoder`, щоб перетворити ваші дані перед тим, як передати їх у відповідь:\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette.responses import JSONResponse`.\n\n**FastAPI** надає ті самі `starlette.responses` як `fastapi.responses` просто як зручність для вас, розробника. Але більшість доступних відповідей походять безпосередньо зі Starlette.\n\n///\n\n## Повернення власного `Response` { #returning-a-custom-response }\n\nНаведений вище приклад показує всі необхідні частини, але він ще не дуже корисний, адже ви могли просто повернути `item` безпосередньо, і **FastAPI** помістив би його у `JSONResponse`, перетворивши на `dict` тощо. Усе це відбувається за замовчуванням.\n\nТепер подивімося, як це використати, щоб повернути власну відповідь.\n\nПрипустімо, ви хочете повернути відповідь [XML](https://en.wikipedia.org/wiki/XML).\n\nВи можете помістити свій вміст XML у строку, помістити це в `Response` і повернути:\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## Як працює модель відповіді { #how-a-response-model-works }\n\nКоли ви оголошуєте [Модель відповіді - Тип, що повертається](../tutorial/response-model.md) в операції шляху, **FastAPI** використає її, щоб серіалізувати дані у JSON за допомогою Pydantic.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nОскільки це відбувається на боці Rust, продуктивність буде значно кращою, ніж якби це робилося звичайним Python і класом `JSONResponse`.\n\nКоли використовується `response_model` або тип, що повертається, **FastAPI** не використовуватиме `jsonable_encoder` для перетворення даних (що було б повільніше) і не використовуватиме клас `JSONResponse`.\n\nНатомість воно бере байти JSON, згенеровані Pydantic за допомогою моделі відповіді (або типу, що повертається), і повертає `Response` з відповідним медіа-типом для JSON (`application/json`) безпосередньо.\n\n## Примітки { #notes }\n\nКоли ви повертаєте `Response` безпосередньо, його дані не перевіряються, не перетворюються (серіалізуються) і не документуються автоматично.\n\nАле ви все ще можете задокументувати це, як описано в [Додаткових відповідях в OpenAPI](additional-responses.md).\n\nУ подальших розділах ви побачите, як використовувати/оголошувати ці власні `Response`, водночас зберігаючи автоматичне перетворення даних, документацію тощо.\n"
  },
  {
    "path": "docs/uk/docs/advanced/response-headers.md",
    "content": "# Заголовки відповіді { #response-headers }\n\n## Використовуйте параметр `Response` { #use-a-response-parameter }\n\nВи можете оголосити параметр типу `Response` у вашій функції операції шляху (так само, як і для кукі).\n\nПотім ви можете встановлювати заголовки в цьому *тимчасовому* обʼєкті відповіді.\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\nДалі ви можете повернути будь-який потрібний обʼєкт, як зазвичай (наприклад, `dict`, модель бази даних тощо).\n\nЯкщо ви оголосили `response_model`, його все одно буде використано для фільтрації та перетворення поверненого обʼєкта.\n\n**FastAPI** використає цей *тимчасовий* обʼєкт відповіді, щоб витягти заголовки (а також кукі та код статусу) і помістить їх у кінцеву відповідь, яка міститиме повернуте вами значення, відфільтроване будь-яким `response_model`.\n\nТакож ви можете оголосити параметр `Response` у залежностях і встановлювати в них заголовки (та кукі).\n\n## Поверніть `Response` безпосередньо { #return-a-response-directly }\n\nВи також можете додавати заголовки, коли повертаєте `Response` безпосередньо.\n\nСтворіть відповідь, як описано в [Повернення Response безпосередньо](response-directly.md), і передайте заголовки як додатковий параметр:\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette.responses import Response` або `from starlette.responses import JSONResponse`.\n\n**FastAPI** надає ті самі `starlette.responses` як `fastapi.responses` просто для зручності для вас, розробника. Але більшість доступних типів відповідей походять безпосередньо зі Starlette.\n\nОскільки `Response` часто використовують для встановлення заголовків і кукі, **FastAPI** також надає його як `fastapi.Response`.\n\n///\n\n## Власні заголовки { #custom-headers }\n\nМайте на увазі, що власні пропрієтарні заголовки можна додавати [за допомогою префікса `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nАле якщо у вас є власні заголовки, які клієнт у браузері має бачити, вам потрібно додати їх у вашу конфігурацію CORS (докладніше в [CORS (Cross-Origin Resource Sharing)](../tutorial/cors.md)), використовуючи параметр `expose_headers`, задокументований у [документації Starlette щодо CORS](https://www.starlette.dev/middleware/#corsmiddleware).\n"
  },
  {
    "path": "docs/uk/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP Basic Auth { #http-basic-auth }\n\nДля найпростіших випадків ви можете використовувати HTTP Basic Auth.\n\nУ HTTP Basic Auth застосунок очікує заголовок, що містить ім'я користувача та пароль.\n\nЯкщо він його не отримує, повертається помилка HTTP 401 «Unauthorized».\n\nІ повертається заголовок `WWW-Authenticate` зі значенням `Basic` та необов'язковим параметром `realm`.\n\nЦе каже браузеру показати вбудовану підсказку для введення імені користувача та пароля.\n\nПотім, коли ви введете це ім'я користувача та пароль, браузер автоматично надішле їх у заголовку.\n\n## Простий HTTP Basic Auth { #simple-http-basic-auth }\n\n- Імпортуйте `HTTPBasic` і `HTTPBasicCredentials`.\n- Створіть «`security` scheme» за допомогою `HTTPBasic`.\n- Використайте цей `security` як залежність у вашій операції шляху.\n- Він повертає об'єкт типу `HTTPBasicCredentials`:\n    - Він містить надіслані `username` і `password`.\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\nКоли ви спробуєте відкрити URL вперше (або натиснете кнопку «Execute» у документації), браузер попросить вас ввести ім'я користувача та пароль:\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## Перевірте ім'я користувача { #check-the-username }\n\nОсь більш повний приклад.\n\nВикористайте залежність, щоб перевірити, чи правильні ім'я користувача та пароль.\n\nДля цього використайте стандартний модуль Python [`secrets`](https://docs.python.org/3/library/secrets.html), щоб перевірити ім'я користувача та пароль.\n\n`secrets.compare_digest()` повинен отримувати `bytes` або `str`, що містить лише ASCII-символи (англійські), це означає, що він не працюватиме з символами на кшталт `á`, як у `Sebastián`.\n\nЩоб це обійти, ми спочатку перетворюємо `username` і `password` у `bytes`, кодувавши їх у UTF-8.\n\nПотім ми можемо використати `secrets.compare_digest()`, щоб упевнитися, що `credentials.username` дорівнює `\"stanleyjobson\"`, а `credentials.password` дорівнює `\"swordfish\"`.\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\nЦе було б подібно до:\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # Поверніть якусь помилку\n    ...\n```\n\nАле використовуючи `secrets.compare_digest()`, це буде захищено від типу атак, що називаються «атаки за часом» (timing attacks).\n\n### Атаки за часом { #timing-attacks }\n\nЩо таке «атака за часом»?\n\nУявімо, що зловмисники намагаються вгадати ім'я користувача та пароль.\n\nВони надсилають запит з ім'ям користувача `johndoe` та паролем `love123`.\n\nТоді Python-код у вашому застосунку буде еквівалентний чомусь на кшталт:\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nАле в той момент, коли Python порівнює першу `j` у `johndoe` з першою `s` у `stanleyjobson`, він поверне `False`, тому що вже знає, що ці дві строки не однакові, «немає сенсу витрачати обчислення на порівняння решти літер». І ваш застосунок скаже «Невірні ім'я користувача або пароль».\n\nА потім зловмисники спробують з ім'ям користувача `stanleyjobsox` і паролем `love123`.\n\nІ ваш код застосунку зробить щось на кшталт:\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nPython доведеться порівняти весь `stanleyjobso` у обох `stanleyjobsox` і `stanleyjobson`, перш ніж зрозуміти, що строки різні. Тому відповідь «Невірні ім'я користувача або пароль» займе на кілька мікросекунд довше.\n\n#### Час відповіді допомагає зловмисникам { #the-time-to-answer-helps-the-attackers }\n\nУ цей момент, помітивши, що сервер витратив на кілька мікросекунд більше, щоб надіслати відповідь «Невірні ім'я користувача або пароль», зловмисники знатимуть, що вони щось вгадали, деякі початкові літери правильні.\n\nІ тоді вони можуть спробувати знову, знаючи, що це, ймовірно, щось більш схоже на `stanleyjobsox`, ніж на `johndoe`.\n\n#### «Професійна» атака { #a-professional-attack }\n\nЗвісно, зловмисники не робитимуть усе це вручну, вони напишуть програму, можливо з тисячами або мільйонами перевірок за секунду. І вони отримуватимуть лише по одній правильній літері за раз.\n\nАле так за кілька хвилин або годин зловмисники вгадають правильні ім'я користувача та пароль, «за допомогою» нашого застосунку, просто використовуючи час, потрібний для відповіді.\n\n#### Виправте за допомогою `secrets.compare_digest()` { #fix-it-with-secrets-compare-digest }\n\nАле в нашому коді ми насправді використовуємо `secrets.compare_digest()`.\n\nКоротко, він витрачає однаковий час на порівняння `stanleyjobsox` зі `stanleyjobson`, як і на порівняння `johndoe` зі `stanleyjobson`. І так само для пароля.\n\nТаким чином, використовуючи `secrets.compare_digest()` у коді вашого застосунку, він буде захищений від усього цього класу атак безпеки.\n\n### Поверніть помилку { #return-the-error }\n\nПісля виявлення, що облікові дані неправильні, поверніть `HTTPException` з кодом статусу 401 (такий самий повертається, коли облікові дані не надані) і додайте заголовок `WWW-Authenticate`, щоб браузер знову показав підсказку входу:\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/uk/docs/advanced/security/index.md",
    "content": "# Просунута безпека { #advanced-security }\n\n## Додаткові можливості { #additional-features }\n\nЄ кілька додаткових можливостей для роботи з безпекою, окрім тих, що розглянуті в [Навчальний посібник - Посібник користувача: Безпека](../../tutorial/security/index.md).\n\n/// tip | Порада\n\nНаступні розділи **не обов'язково «просунуті»**.\n\nІ можливо, що для вашого випадку використання рішення є в одному з них.\n\n///\n\n## Спершу прочитайте навчальний посібник { #read-the-tutorial-first }\n\nУ наступних розділах передбачається, що ви вже прочитали основний [Навчальний посібник - Посібник користувача: Безпека](../../tutorial/security/index.md).\n\nУсі вони базуються на тих самих концепціях, але надають деякі додаткові можливості.\n"
  },
  {
    "path": "docs/uk/docs/advanced/security/oauth2-scopes.md",
    "content": "# OAuth2 scopes { #oauth2-scopes }\n\nВи можете використовувати OAuth2 scopes безпосередньо з **FastAPI**, вони інтегровані для безшовної роботи.\n\nЦе дозволить мати більш детальну систему дозволів, відповідно до стандарту OAuth2, інтегровану у ваш застосунок OpenAPI (і документацію API).\n\nOAuth2 зі scopes - це механізм, який використовують багато великих провайдерів автентифікації, як-от Facebook, Google, GitHub, Microsoft, X (Twitter) тощо. Вони застосовують його, щоб надавати конкретні дозволи користувачам і застосункам.\n\nКожного разу, коли ви «log in with» Facebook, Google, GitHub, Microsoft, X (Twitter), цей застосунок використовує OAuth2 зі scopes.\n\nУ цьому розділі ви побачите, як керувати автентифікацією та авторизацією за допомогою того ж OAuth2 зі scopes у вашому застосунку **FastAPI**.\n\n/// warning | Попередження\n\nЦе більш-менш просунутий розділ. Якщо ви тільки починаєте, можете пропустити його.\n\nВам не обов’язково потрібні OAuth2 scopes, ви можете керувати автентифікацією та авторизацією будь-яким зручним способом.\n\nАле OAuth2 зі scopes можна гарно інтегрувати у ваш API (з OpenAPI) і документацію API.\n\nВодночас ви все одно примушуєте виконувати ці scopes або будь-які інші вимоги безпеки/авторизації так, як потрібно, у своєму коді.\n\nУ багатьох випадках OAuth2 зі scopes - це надмірність.\n\nАле якщо ви знаєте, що це потрібно, або просто цікаво, читайте далі.\n\n///\n\n## OAuth2 scopes та OpenAPI { #oauth2-scopes-and-openapi }\n\nСпецифікація OAuth2 визначає «scopes» як список строк, розділених пробілами.\n\nВміст кожної з цих строк може мати будь-який формат, але не повинен містити пробілів.\n\nЦі scopes представляють «дозволи».\n\nВ OpenAPI (наприклад, у документації API) ви можете визначати «схеми безпеки».\n\nКоли одна з цих схем безпеки використовує OAuth2, ви також можете оголошувати та використовувати scopes.\n\nКожен «scope» - це просто строка (без пробілів).\n\nЗазвичай їх використовують для оголошення конкретних дозволів безпеки, наприклад:\n\n- `users:read` або `users:write` - поширені приклади.\n- `instagram_basic` використовується Facebook / Instagram.\n- `https://www.googleapis.com/auth/drive` використовується Google.\n\n/// info | Інформація\n\nВ OAuth2 «scope» - це просто строка, що декларує конкретний потрібний дозвіл.\n\nНе має значення, чи містить вона інші символи на кшталт `:` або чи це URL.\n\nЦі деталі специфічні для реалізації.\n\nДля OAuth2 це просто строки.\n\n///\n\n## Загальний огляд { #global-view }\n\nСпочатку швидко подивімося на частини, що відрізняються від прикладів у головному **Навчальному посібнику - Керівництві користувача** для [OAuth2 з паролем (і хешуванням), Bearer з JWT-токенами](../../tutorial/security/oauth2-jwt.md). Тепер із використанням OAuth2 scopes:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\nТепер розгляньмо ці зміни крок за кроком.\n\n## Схема безпеки OAuth2 { #oauth2-security-scheme }\n\nПерша зміна - тепер ми оголошуємо схему безпеки OAuth2 з двома доступними scopes: `me` і `items`.\n\nПараметр `scopes` приймає `dict`, де кожен scope - це ключ, а опис - значення:\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\nОскільки тепер ми оголошуємо ці scopes, вони з’являться в документації API, коли ви увійдете/авторизуєтеся.\n\nІ ви зможете обрати, які scopes надати доступ: `me` і `items`.\n\nЦе той самий механізм, який використовується, коли ви надаєте дозволи під час входу через Facebook, Google, GitHub тощо:\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## JWT токен зі scopes { #jwt-token-with-scopes }\n\nТепер змініть операцію шляху токена, щоб повертати запитані scopes.\n\nМи все ще використовуємо той самий `OAuth2PasswordRequestForm`. Він містить властивість `scopes` зі `list` з `str`, по одному scope, отриманому в запиті.\n\nІ ми повертаємо scopes як частину JWT токена.\n\n/// danger | Обережно\n\nДля простоти тут ми просто додаємо отримані scopes безпосередньо до токена.\n\nАле у вашому застосунку, з міркувань безпеки, переконайтеся, що ви додаєте лише ті scopes, які користувач дійсно може мати, або ті, що ви попередньо визначили.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## Оголосіть scopes в операціях шляху та залежностях { #declare-scopes-in-path-operations-and-dependencies }\n\nТепер ми оголошуємо, що операція шляху для `/users/me/items/` вимагає scope `items`.\n\nДля цього імпортуємо і використовуємо `Security` з `fastapi`.\n\nВи можете використовувати `Security` для оголошення залежностей (так само як `Depends`), але `Security` також приймає параметр `scopes` зі списком scopes (строк).\n\nУ цьому випадку ми передаємо функцію-залежність `get_current_active_user` до `Security` (так само, як зробили б із `Depends`).\n\nА також передаємо `list` scopes, у цьому випадку лише один scope: `items` (їх могло б бути більше).\n\nІ функція-залежність `get_current_active_user` також може оголошувати підзалежності не лише з `Depends`, а й з `Security`. Оголошуючи свою підзалежність (`get_current_user`) і додаткові вимоги до scopes.\n\nУ цьому випадку вона вимагає scope `me` (вона могла б вимагати більш ніж один scope).\n\n/// note | Примітка\n\nВам не обов’язково додавати різні scopes у різних місцях.\n\nМи робимо це тут, щоб показати, як **FastAPI** обробляє scopes, оголошені на різних рівнях.\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | Технічні деталі\n\n`Security` насправді є підкласом `Depends`, і має лише один додатковий параметр, який ми побачимо пізніше.\n\nАле використовуючи `Security` замість `Depends`, **FastAPI** знатиме, що можна оголошувати scopes безпеки, використовувати їх внутрішньо та документувати API через OpenAPI.\n\nКоли ви імпортуєте `Query`, `Path`, `Depends`, `Security` та інші з `fastapi`, це насправді функції, що повертають спеціальні класи.\n\n///\n\n## Використовуйте `SecurityScopes` { #use-securityscopes }\n\nТепер оновіть залежність `get_current_user`.\n\nВона використовується наведеними вище залежностями.\n\nТут ми використовуємо ту саму схему OAuth2, створену раніше, оголошуючи її як залежність: `oauth2_scheme`.\n\nОскільки ця функція-залежність не має власних вимог до scopes, ми можемо використовувати `Depends` з `oauth2_scheme`, немає потреби застосовувати `Security`, коли не потрібно вказувати scopes безпеки.\n\nМи також оголошуємо спеціальний параметр типу `SecurityScopes`, імпортований з `fastapi.security`.\n\nКлас `SecurityScopes` подібний до `Request` (у `Request` ми напряму отримували об’єкт запиту).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## Використовуйте scopes { #use-the-scopes }\n\nПараметр `security_scopes` матиме тип `SecurityScopes`.\n\nВін матиме властивість `scopes` зі списком, що містить усі scopes, потрібні самій функції та всім залежним, які використовують її як підзалежність. Тобто всім «залежним»... це може звучати заплутано, нижче пояснено ще раз.\n\nОб’єкт `security_scopes` (класу `SecurityScopes`) також надає атрибут `scope_str` з одним рядком, що містить ці scopes, розділені пробілами (ми його використаємо).\n\nМи створюємо `HTTPException`, який зможемо повторно використати (`raise`) у кількох місцях.\n\nУ цьому винятку ми включаємо потрібні scopes (якщо є) як строку, розділену пробілами (використовуючи `scope_str`). Ми поміщаємо цю строку зі scopes в заголовок `WWW-Authenticate` (це частина специфікації).\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## Перевірте `username` і структуру даних { #verify-the-username-and-data-shape }\n\nМи перевіряємо, що отримали `username`, і видобуваємо scopes.\n\nПотім валідовуємо ці дані за допомогою Pydantic-моделі (перехоплюючи виняток `ValidationError`), і якщо виникає помилка читання JWT токена або валідації даних Pydantic, підіймаємо раніше створений `HTTPException`.\n\nДля цього ми оновлюємо Pydantic-модель `TokenData` новою властивістю `scopes`.\n\nВалідувавши дані через Pydantic, ми гарантуємо, що, наприклад, маємо саме `list` із `str` для scopes і `str` для `username`.\n\nЗамість, наприклад, `dict` або чогось іншого, що може зламати застосунок далі, створивши ризик безпеки.\n\nМи також перевіряємо, що існує користувач із цим username, інакше підіймаємо той самий виняток.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## Перевірте `scopes` { #verify-the-scopes }\n\nТепер перевіряємо, що всі потрібні scopes - для цієї залежності та всіх залежних (включно з операціями шляху) - містяться в scopes, наданих у отриманому токені, інакше підіймаємо `HTTPException`.\n\nДля цього використовуємо `security_scopes.scopes`, що містить `list` із усіма цими scopes як `str`.\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## Дерево залежностей і scopes { #dependency-tree-and-scopes }\n\nЩе раз розгляньмо дерево залежностей і scopes.\n\nОскільки залежність `get_current_active_user` має підзалежність `get_current_user`, scope «me», оголошений у `get_current_active_user`, буде включений до списку потрібних scopes у `security_scopes.scopes`, переданого до `get_current_user`.\n\nСама операція шляху також оголошує scope «items», отже він також буде у списку `security_scopes.scopes`, переданому до `get_current_user`.\n\nОсь як виглядає ієрархія залежностей і scopes:\n\n- Операція шляху `read_own_items` має:\n    - Потрібні scopes `[\"items\"]` із залежністю:\n    - `get_current_active_user`:\n        - Функція-залежність `get_current_active_user` має:\n            - Потрібні scopes `[\"me\"]` із залежністю:\n            - `get_current_user`:\n                - Функція-залежність `get_current_user` має:\n                    - Власних scopes не потребує.\n                    - Залежність, що використовує `oauth2_scheme`.\n                    - Параметр `security_scopes` типу `SecurityScopes`:\n                        - Цей параметр `security_scopes` має властивість `scopes` із `list`, що містить усі наведені вище scopes, отже:\n                            - `security_scopes.scopes` міститиме `[\"me\", \"items\"]` для операції шляху `read_own_items`.\n                            - `security_scopes.scopes` міститиме `[\"me\"]` для операції шляху `read_users_me`, адже він оголошений у залежності `get_current_active_user`.\n                            - `security_scopes.scopes` міститиме `[]` (нічого) для операції шляху `read_system_status`, бо вона не оголошує жодного `Security` зі `scopes`, і її залежність `get_current_user` також не оголошує жодних `scopes`.\n\n/// tip | Порада\n\nВажливе і «магічне» тут у тому, що `get_current_user` матиме різні списки `scopes` для перевірки для кожної операції шляху.\n\nУсе залежить від `scopes`, оголошених у кожній операції шляху та кожній залежності в дереві залежностей для конкретної операції шляху.\n\n///\n\n## Більше деталей про `SecurityScopes` { #more-details-about-securityscopes }\n\nВи можете використовувати `SecurityScopes` у будь-якому місці й у кількох місцях, він не обов’язково має бути в «кореневій» залежності.\n\nВін завжди міститиме scopes безпеки, оголошені в поточних залежностях `Security` і всіх залежних для **цієї конкретної** операції шляху і **цього конкретного** дерева залежностей.\n\nОскільки `SecurityScopes` міститиме всі scopes, оголошені залежними, ви можете використовувати його, щоб перевірити, що токен має потрібні scopes, у центральній функції-залежності, а потім оголошувати різні вимоги до scopes у різних операціях шляху.\n\nВони перевірятимуться незалежно для кожної операції шляху.\n\n## Перевірте { #check-it }\n\nЯкщо ви відкриєте документацію API, ви зможете автентифікуватися і вказати, які scopes хочете авторизувати.\n\n<img src=\"/img/tutorial/security/image11.png\">\n\nЯкщо ви не оберете жодного scope, ви будете «автентифіковані», але при спробі доступу до `/users/me/` або `/users/me/items/` отримаєте помилку про недостатні дозволи. Ви все ще матимете доступ до `/status/`.\n\nЯкщо оберете scope `me`, але не scope `items`, ви зможете отримати доступ до `/users/me/`, але не до `/users/me/items/`.\n\nТак станеться зі стороннім застосунком, який спробує звернутися до однієї з цих операцій шляху з токеном, наданим користувачем, залежно від того, скільки дозволів користувач надав застосунку.\n\n## Про сторонні інтеграції { #about-third-party-integrations }\n\nУ цьому прикладі ми використовуємо «потік паролю» OAuth2.\n\nЦе доречно, коли ми входимо у власний застосунок, ймовірно, з власним фронтендом.\n\nАдже ми можемо довіряти йому отримання `username` і `password`, бо ми його контролюємо.\n\nАле якщо ви створюєте OAuth2-застосунок, до якого підключатимуться інші (тобто якщо ви створюєте провайдера автентифікації на кшталт Facebook, Google, GitHub тощо), слід використовувати один з інших потоків.\n\nНайпоширеніший - неявний потік (implicit flow).\n\nНайбезпечніший - потік коду (code flow), але його складніше реалізувати, оскільки він потребує більше кроків. Через складність багато провайдерів у підсумку радять неявний потік.\n\n/// note | Примітка\n\nЧасто кожен провайдер автентифікації називає свої потоки по-різному, роблячи це частиною свого бренду.\n\nАле зрештою вони реалізують той самий стандарт OAuth2.\n\n///\n\n**FastAPI** містить утиліти для всіх цих потоків автентифікації OAuth2 у `fastapi.security.oauth2`.\n\n## `Security` у параметрі декоратора `dependencies` { #security-in-decorator-dependencies }\n\nТак само як ви можете визначити `list` із `Depends` у параметрі `dependencies` декоратора (як пояснено в [Залежності в декораторах операцій шляху](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)), ви також можете використовувати там `Security` зі `scopes`.\n"
  },
  {
    "path": "docs/uk/docs/advanced/settings.md",
    "content": "# Налаштування та змінні оточення { #settings-and-environment-variables }\n\nУ багатьох випадках вашому застосунку можуть знадобитися зовнішні налаштування або конфігурації, наприклад секретні ключі, облікові дані бази даних, облікові дані для email-сервісів тощо.\n\nБільшість із цих налаштувань змінні (можуть змінюватися), як-от URL-адреси баз даних. І багато з них можуть бути чутливими, як-от секрети.\n\nЗ цієї причини поширено надавати їх у змінних оточення, які зчитуються застосунком.\n\n/// tip | Порада\n\nЩоб зрозуміти змінні оточення, ви можете прочитати [Змінні оточення](../environment-variables.md).\n\n///\n\n## Типи та перевірка { #types-and-validation }\n\nЦі змінні оточення можуть містити лише текстові строки, оскільки вони зовнішні до Python і мають бути сумісні з іншими програмами та рештою системи (і навіть з різними операційними системами, як-от Linux, Windows, macOS).\n\nЦе означає, що будь-яке значення, прочитане в Python зі змінної оточення, буде `str`, і будь-яке перетворення в інший тип або будь-яка перевірка мають виконуватися в коді.\n\n## Pydantic `Settings` { #pydantic-settings }\n\nНа щастя, Pydantic надає чудовий інструмент для обробки цих налаштувань із змінних оточення - [Pydantic: Settings management](https://docs.pydantic.dev/latest/concepts/pydantic_settings/).\n\n### Встановіть `pydantic-settings` { #install-pydantic-settings }\n\nСпершу переконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md), активували його, а потім встановили пакет `pydantic-settings`:\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\nВін також входить у склад, якщо ви встановлюєте додаткові можливості «all» за допомогою:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### Створіть об'єкт `Settings` { #create-the-settings-object }\n\nІмпортуйте `BaseSettings` із Pydantic і створіть підклас, дуже подібно до моделі Pydantic.\n\nТак само, як і з моделями Pydantic, ви оголошуєте атрибути класу з анотаціями типів і, за потреби, значеннями за замовчуванням.\n\nВи можете використовувати всі ті самі можливості перевірки та інструменти, що й для моделей Pydantic, як-от різні типи даних і додаткові перевірки з `Field()`.\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip | Порада\n\nЯкщо вам потрібно щось швидко скопіювати й вставити, не використовуйте цей приклад, скористайтеся останнім нижче.\n\n///\n\nПотім, коли ви створите екземпляр цього класу `Settings` (у цьому випадку в об'єкті `settings`), Pydantic зчитуватиме змінні оточення без урахування регістру, тож верхньорегістрова змінна `APP_NAME` все одно буде прочитана для атрибута `app_name`.\n\nДалі він перетворить і перевірить дані. Тож коли ви використовуватимете об'єкт `settings`, у вас будуть дані тих типів, які ви оголосили (наприклад, `items_per_user` буде `int`).\n\n### Використовуйте `settings` { #use-the-settings }\n\nПотім ви можете використати новий об'єкт `settings` у вашому застосунку:\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### Запустіть сервер { #run-the-server }\n\nДалі ви б запустили сервер, передаючи конфігурації як змінні оточення, наприклад, ви можете встановити `ADMIN_EMAIL` і `APP_NAME` так:\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip | Порада\n\nЩоб встановити кілька змінних оточення для однієї команди, просто розділіть їх пробілами і розмістіть усі перед командою.\n\n///\n\nПісля цього налаштування `admin_email` буде встановлено в `\"deadpool@example.com\"`.\n\n`app_name` буде `\"ChimichangApp\"`.\n\nА `items_per_user` збереже своє значення за замовчуванням `50`.\n\n## Налаштування в іншому модулі { #settings-in-another-module }\n\nВи можете розмістити ці налаштування в іншому модулі, як ви бачили в [Більші застосунки - кілька файлів](../tutorial/bigger-applications.md).\n\nНаприклад, у вас може бути файл `config.py` з:\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\nА потім використати його у файлі `main.py`:\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip | Порада\n\nВам також знадобиться файл `__init__.py`, як ви бачили в [Більші застосунки - кілька файлів](../tutorial/bigger-applications.md).\n\n///\n\n## Налаштування як залежність { #settings-in-a-dependency }\n\nІноді може бути корисно надавати налаштування через залежність, замість того, щоб мати глобальний об'єкт `settings`, який використовується всюди.\n\nЦе може бути особливо корисно під час тестування, оскільки дуже легко переписати залежність власними налаштуваннями.\n\n### Файл конфігурації { #the-config-file }\n\nПродовжуючи попередній приклад, ваш файл `config.py` може виглядати так:\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\nЗверніть увагу, що тепер ми не створюємо екземпляр за замовчуванням `settings = Settings()`.\n\n### Основний файл застосунку { #the-main-app-file }\n\nТепер ми створюємо залежність, яка повертає новий `config.Settings()`.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip | Порада\n\nМи обговоримо `@lru_cache` трохи згодом.\n\nПоки що можете вважати, що `get_settings()` - це звичайна функція.\n\n///\n\nА далі ми можемо вимагати її у *функції операції шляху* як залежність і використовувати будь-де, де це потрібно.\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### Налаштування і тестування { #settings-and-testing }\n\nПотім буде дуже просто надати інший об'єкт налаштувань під час тестування, створивши переписування залежності для `get_settings`:\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\nУ переписуванні залежності ми встановлюємо нове значення `admin_email` під час створення нового об'єкта `Settings`, а потім повертаємо цей новий об'єкт.\n\nПісля цього ми можемо перевірити, що саме він використовується.\n\n## Читання файлу `.env` { #reading-a-env-file }\n\nЯкщо у вас багато налаштувань, які можуть часто змінюватися, можливо в різних оточеннях, може бути корисно розмістити їх у файлі, а потім зчитувати їх із нього так, ніби це змінні оточення.\n\nЦя практика достатньо поширена, тож має назву - ці змінні оточення зазвичай розміщуються у файлі `.env`, а сам файл називається «dotenv».\n\n/// tip | Порада\n\nФайл, що починається з крапки (`.`), є прихованим у системах, подібних до Unix, як-от Linux і macOS.\n\nАле файл dotenv не обов'язково має мати саме таку назву.\n\n///\n\nPydantic має підтримку читання з таких типів файлів за допомогою зовнішньої бібліотеки. Ви можете дізнатися більше тут: [Pydantic Settings: Dotenv (.env) support](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support).\n\n/// tip | Порада\n\nЩоб це працювало, потрібно виконати `pip install python-dotenv`.\n\n///\n\n### Файл `.env` { #the-env-file }\n\nУ вас може бути файл `.env` із вмістом:\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### Зчитування налаштувань із `.env` { #read-settings-from-env }\n\nПотім оновіть ваш `config.py` так:\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip | Порада\n\nАтрибут `model_config` використовується лише для конфігурації Pydantic. Докладніше: [Pydantic: Concepts: Configuration](https://docs.pydantic.dev/latest/concepts/config/).\n\n///\n\nТут ми визначаємо конфіг `env_file` усередині вашого класу Pydantic `Settings` і задаємо значення - ім'я файла з dotenv, який ми хочемо використати.\n\n### Створення `Settings` лише один раз за допомогою `lru_cache` { #creating-the-settings-only-once-with-lru-cache }\n\nЧитання файла з диска зазвичай є дорогою (повільною) операцією, тож, імовірно, ви захочете робити це лише один раз і потім перевикористовувати той самий об'єкт налаштувань замість зчитування для кожного запиту.\n\nАле щоразу, коли ми робимо:\n\n```Python\nSettings()\n```\n\nбуде створено новий об'єкт `Settings`, і під час створення він знову зчитуватиме файл `.env`.\n\nЯкби функція залежності виглядала так:\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\nми створювали б цей об'єкт для кожного запиту і читали б файл `.env` для кожного запиту. ⚠️\n\nАле оскільки ми використовуємо декоратор `@lru_cache` зверху, об'єкт `Settings` буде створено лише один раз, під час першого виклику. ✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\nПотім для будь-якого подальшого виклику `get_settings()` у залежностях для наступних запитів, замість виконання внутрішнього коду `get_settings()` і створення нового об'єкта `Settings`, він повертатиме той самий об'єкт, що був повернутий під час першого виклику, знову і знову.\n\n#### Технічні деталі `lru_cache` { #lru-cache-technical-details }\n\n`@lru_cache` модифікує функцію, яку він декорує, так, щоб вона повертала те саме значення, що й уперше, замість повторного обчислення, виконуючи код функції щоразу.\n\nТобто функція під ним буде виконана один раз для кожної комбінації аргументів. А потім значення, повернені кожною з цих комбінацій аргументів, використовуватимуться знову і знову щоразу, коли функцію викликають із точно такою ж комбінацією аргументів.\n\nНаприклад, якщо у вас є функція:\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\nваша програма може виконуватись так:\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Execute function\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n```\n\nУ випадку з нашою залежністю `get_settings()` функція взагалі не приймає жодних аргументів, тож вона завжди повертає те саме значення.\n\nТаким чином, вона поводиться майже так само, якби це була просто глобальна змінна. Але оскільки використовується функція залежності, ми можемо легко переписати її для тестування.\n\n`@lru_cache` є частиною `functools`, що входить до стандартної бібліотеки Python, більше про це можна прочитати в [документації Python для `@lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache).\n\n## Підсумок { #recap }\n\nВи можете використовувати Pydantic Settings для обробки налаштувань або конфігурацій вашого застосунку, з усією потужністю моделей Pydantic.\n\n- Використовуючи залежність, ви можете спростити тестування.\n- Ви можете використовувати з ним файли `.env`.\n- Використання `@lru_cache` дає змогу уникнути повторного читання файла dotenv для кожного запиту, водночас дозволяючи переписувати його під час тестування.\n"
  },
  {
    "path": "docs/uk/docs/advanced/stream-data.md",
    "content": "# Потокова передача даних { #stream-data }\n\nЯкщо ви хочете передавати потоком дані, які можна структурувати як JSON, див. [Потокова передача JSON Lines](../tutorial/stream-json-lines.md).\n\nАле якщо ви хочете передавати потоком чисті бінарні дані або строки, ось як це зробити.\n\n/// info | Інформація\n\nДодано у FastAPI 0.134.0.\n\n///\n\n## Варіанти використання { #use-cases }\n\nЦе можна використовувати, якщо ви хочете передавати потоком чисті строки, наприклад безпосередньо з виводу сервісу AI LLM.\n\nТакож це можна використати для потокової передачі великих бінарних файлів, коли ви надсилаєте кожний фрагмент даних під час читання, без потреби завантажувати все в пам'ять одразу.\n\nТак само можна стрімити відео чи аудіо; їх навіть можна генерувати під час обробки та надсилання.\n\n## `StreamingResponse` з `yield` { #a-streamingresponse-with-yield }\n\nЯкщо ви оголосите `response_class=StreamingResponse` у вашій функції операції шляху, ви можете використовувати `yield`, щоб послідовно надсилати кожний фрагмент даних.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI передаватиме кожний фрагмент даних до `StreamingResponse` як є; він не намагатиметься перетворити його на JSON чи щось подібне.\n\n### Не-async функції операції шляху { #non-async-path-operation-functions }\n\nМожна також використовувати звичайні функції `def` (без `async`) і так само застосовувати `yield`.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### Без анотації { #no-annotation }\n\nДля потокової передачі бінарних даних немає потреби оголошувати анотацію типу, що повертається.\n\nОскільки FastAPI не намагатиметься перетворювати дані на JSON за допомогою Pydantic чи серіалізувати їх іншим чином, у цьому випадку анотація типу потрібна лише для вашого редактора та інструментів; FastAPI її не використовуватиме.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\nЦе також означає, що з `StreamingResponse` у вас є свобода і відповідальність формувати та кодувати байти даних саме так, як їх потрібно надіслати, незалежно від анотацій типів. 🤓\n\n### Потік байтів { #stream-bytes }\n\nОдин з основних сценаріїв - передавати потоком `bytes` замість строк; це, звісно, підтримується.\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## Користувацький `PNGStreamingResponse` { #a-custom-pngstreamingresponse }\n\nУ наведених вище прикладах байти даних передавалися потоком, але у відповіді не було заголовка `Content-Type`, тому клієнт не знав, який тип даних він отримує.\n\nМожна створити власний підклас `StreamingResponse`, який встановлює заголовок `Content-Type` відповідно до типу даних, що ви стрімите.\n\nНаприклад, можна створити `PNGStreamingResponse`, який встановлює заголовок `Content-Type` у `image/png` за допомогою атрибута `media_type`:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\nПотім ви можете використати цей новий клас у `response_class=PNGStreamingResponse` у вашій функції операції шляху:\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### Симулювати файл { #simulate-a-file }\n\nУ цьому прикладі ми імітуємо файл за допомогою `io.BytesIO` - це об'єкт на кшталт файлу, який існує лише в пам'яті, але надає той самий інтерфейс.\n\nНаприклад, ми можемо ітеруватися по ньому, щоб зчитати вміст, так само як і з файлом.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | Технічні деталі\n\nІнші дві змінні, `image_base64` та `binary_image`, - це зображення, закодоване в Base64, яке потім перетворюється на байти, щоб передати його в `io.BytesIO`.\n\nЛише для того, щоб усе містилося в одному файлі для цього прикладу, і ви могли скопіювати його та запустити як є. 🥚\n\n///\n\nВикористовуючи блок `with`, ми гарантуємо, що об'єкт, подібний до файлу, буде закрито після завершення генераторної функції (функції з `yield`). Тобто після завершення надсилання відповіді.\n\nУ цьому конкретному прикладі це не так важливо, адже це фальшивий файл у пам'яті (з `io.BytesIO`), але для справжнього файлу важливо переконатися, що файл закрито після завершення роботи з ним.\n\n### Файли та async { #files-and-async }\n\nУ більшості випадків об'єкти, подібні до файлів, за замовчуванням несумісні з `async` та `await`.\n\nНаприклад, у них немає `await file.read()` або `async for chunk in file`.\n\nІ часто їх читання є блокувальною операцією (що може блокувати цикл подій), адже дані зчитуються з диска або мережі.\n\n/// info | Інформація\n\nНаведений вище приклад - виняток, адже об'єкт `io.BytesIO` вже в пам'яті, тож читання нічого не блокує.\n\nАле в багатьох випадках читання файлу або схожого на файл об'єкта блокує виконання.\n\n///\n\nЩоб уникнути блокування циклу подій, просто оголосіть функцію операції шляху зі звичайним `def` замість `async def`. Тоді FastAPI виконуватиме її в працівнику пулу потоків, щоб не блокувати головний цикл.\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip | Порада\n\nЯкщо вам потрібно викликати блокувальний код усередині async-функції або async-функцію зсередини блокувальної функції, ви можете скористатися [Asyncer](https://asyncer.tiangolo.com) - спорідненою бібліотекою до FastAPI.\n\n///\n\n### `yield from` { #yield-from }\n\nКоли ви ітеруєтеся по чомусь, наприклад по об'єкту, подібному до файлу, і робите `yield` для кожного елемента, можна також використати `yield from`, щоб віддавати кожен елемент напряму і пропустити цикл `for`.\n\nЦе не специфічно для FastAPI, це просто Python, але корисний трюк. 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/uk/docs/advanced/strict-content-type.md",
    "content": "# Сувора перевірка Content-Type { #strict-content-type-checking }\n\nЗа замовчуванням **FastAPI** використовує сувору перевірку заголовка `Content-Type` для тіл запитів JSON, це означає, що запити JSON мають включати дійсний заголовок `Content-Type` (наприклад, `application/json`), щоб тіло було розібране як JSON.\n\n## Ризик CSRF { #csrf-risk }\n\nЦя поведінка за замовчуванням забезпечує захист від класу атак **Cross-Site Request Forgery (CSRF)** у дуже конкретному сценарії.\n\nЦі атаки використовують той факт, що браузери дозволяють скриптам надсилати запити без виконання перевірки CORS preflight, коли вони:\n\n* не мають заголовка `Content-Type` (наприклад, використовуючи `fetch()` з тілом типу `Blob`)\n* і не надсилають жодних облікових даних автентифікації.\n\nТакий тип атаки головним чином актуальний, коли:\n\n* застосунок працює локально (наприклад, на `localhost`) або у внутрішній мережі\n* і в застосунку немає жодної автентифікації, очікується, що будь-який запит з тієї ж мережі є надійним.\n\n## Приклад атаки { #example-attack }\n\nУявіть, що ви створюєте спосіб запускати локального AI-агента.\n\nВін надає API за адресою\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nЄ також фронтенд за адресою\n\n```\nhttp://localhost:8000\n```\n\n/// tip | Порада\n\nЗауважте, що обидва мають один і той самий хост.\n\n///\n\nВикористовуючи фронтенд, ви можете змушувати AI-агента виконувати дії від вашого імені.\n\nОскільки він працює локально, а не у відкритому інтернеті, ви вирішуєте не налаштовувати жодної автентифікації, просто покладаючись на доступ до локальної мережі.\n\nОдин із ваших користувачів може встановити його і запустити локально.\n\nПотім він може відкрити шкідливий вебсайт, напр. щось на кшталт\n\n```\nhttps://evilhackers.example.com\n```\n\nІ цей шкідливий вебсайт надсилає запити, використовуючи `fetch()` з тілом типу `Blob`, до локального API за адресою\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\nХоча хости шкідливого вебсайту та локального застосунку різні, браузер не запустить CORS preflight-запит, тому що:\n\n* Застосунок працює без будь-якої автентифікації, немає потреби надсилати облікові дані.\n* Браузер вважає, що він не надсилає JSON (через відсутній заголовок `Content-Type`).\n\nТоді шкідливий вебсайт може змусити локального AI-агента надсилати злі повідомлення колишньому босу користувача... або щось гірше. 😅\n\n## Відкритий інтернет { #open-internet }\n\nЯкщо ваш застосунок у відкритому інтернеті, ви не стали б «довіряти мережі» і дозволяти кому завгодно надсилати привілейовані запити без автентифікації.\n\nЗловмисники можуть просто запустити скрипт, щоб надсилати запити до вашого API, без будь-якої участі браузера, тож ви, ймовірно, вже захищаєте будь-які привілейовані ендпоїнти.\n\nУ такому разі ця атака/ризик до вас не застосовується.\n\nЦей ризик і атака головним чином актуальні, коли застосунок працює в локальній мережі і це єдиний передбачуваний захист.\n\n## Дозволення запитів без Content-Type { #allowing-requests-without-content-type }\n\nЯкщо вам потрібно підтримувати клієнтів, які не надсилають заголовок `Content-Type`, ви можете вимкнути сувору перевірку, встановивши `strict_content_type=False`:\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\nЗ цим налаштуванням запити без заголовка `Content-Type` матимуть тіло, розібране як JSON, що відповідає поведінці старіших версій FastAPI.\n\n/// info | Інформація\n\nЦю поведінку і конфігурацію додано у FastAPI 0.132.0.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/advanced/sub-applications.md",
    "content": "# Підзастосунки - монтування { #sub-applications-mounts }\n\nЯкщо вам потрібно мати два незалежні застосунки FastAPI з власними незалежними OpenAPI та власними інтерфейсами документації, ви можете мати головний застосунок і «змонтувати» один або кілька підзастосунків.\n\n## Монтування застосунку **FastAPI** { #mounting-a-fastapi-application }\n\n«Монтування» означає додавання повністю «незалежного» застосунку на конкретний шлях, який далі обробляє все під цим шляхом за допомогою _операцій шляху_, оголошених у цьому підзастосунку.\n\n### Застосунок верхнього рівня { #top-level-application }\n\nСпочатку створіть головний, верхньорівневий застосунок **FastAPI** та його _операції шляху_:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### Підзастосунок { #sub-application }\n\nПотім створіть свій підзастосунок та його _операції шляху_.\n\nЦей підзастосунок - просто ще один стандартний застосунок FastAPI, але саме його буде «змонтовано»:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### Змонтуйте підзастосунок { #mount-the-sub-application }\n\nУ вашому застосунку верхнього рівня, `app`, змонтуйте підзастосунок `subapi`.\n\nУ цьому випадку його буде змонтовано за шляхом `/subapi`:\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### Перевірте автоматичну документацію API { #check-the-automatic-api-docs }\n\nТепер запустіть команду `fastapi`:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nІ відкрийте документацію за адресою [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВи побачите автоматичну документацію API для головного застосунку, що містить лише його власні _операції шляху_:\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\nА потім відкрийте документацію для підзастосунку за адресою [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs).\n\nВи побачите автоматичну документацію API для підзастосунку, що містить лише його власні _операції шляху_, усі з правильним префіксом підшляху `/subapi`:\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\nЯкщо ви спробуєте взаємодіяти з будь-яким із двох інтерфейсів користувача, вони працюватимуть коректно, адже браузер зможе спілкуватися з кожним конкретним застосунком або підзастосунком.\n\n### Технічні деталі: `root_path` { #technical-details-root-path }\n\nКоли ви монтуєте підзастосунок, як описано вище, FastAPI подбає про передачу шляху монтування для підзастосунку, використовуючи механізм зі специфікації ASGI під назвою `root_path`.\n\nТаким чином підзастосунок знатиме, що слід використовувати цей префікс шляху для інтерфейсу документації.\n\nПідзастосунок також може мати власні змонтовані підзастосунки, і все працюватиме коректно, оскільки FastAPI автоматично обробляє всі ці `root_path`.\n\nВи дізнаєтеся більше про `root_path` і як використовувати його явно в розділі [За представником](behind-a-proxy.md).\n"
  },
  {
    "path": "docs/uk/docs/advanced/templates.md",
    "content": "# Шаблони { #templates }\n\nВи можете використовувати будь-який рушій шаблонів з **FastAPI**.\n\nПоширений вибір - Jinja2, той самий, що використовується у Flask та інших інструментах.\n\nЄ утиліти для простої конфігурації, які ви можете використовувати безпосередньо у вашому застосунку **FastAPI** (надає Starlette).\n\n## Встановіть залежності { #install-dependencies }\n\nПереконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md), активували його та встановили `jinja2`:\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## Використання `Jinja2Templates` { #using-jinja2templates }\n\n- Імпортуйте `Jinja2Templates`.\n- Створіть об'єкт `templates`, який ви зможете перевикористовувати.\n- Оголосіть параметр `Request` в *операції шляху*, яка повертатиме шаблон.\n- Використайте створені `templates`, щоб зрендерити та повернути `TemplateResponse`; передайте назву шаблону, об'єкт `request` і словник «контекст» з парами ключ-значення, які будуть використані всередині шаблону Jinja2.\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note | Примітка\n\nДо FastAPI 0.108.0, Starlette 0.29.0, параметр `name` був першим.\n\nТакож раніше, у попередніх версіях, об'єкт `request` передавався як частина пар ключ-значення в контексті для Jinja2.\n\n///\n\n/// tip | Порада\n\nЯкщо вказати `response_class=HTMLResponse`, інтерфейс документації знатиме, що відповідь буде HTML.\n\n///\n\n/// note | Технічні деталі\n\nМожна також використати `from starlette.templating import Jinja2Templates`.\n\n**FastAPI** надає той самий `starlette.templating` як `fastapi.templating` просто для зручності для вас, розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette. Так само з `Request` і `StaticFiles`.\n\n///\n\n## Створення шаблонів { #writing-templates }\n\nПотім ви можете написати шаблон у `templates/item.html`, наприклад:\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### Значення контексту шаблону { #template-context-values }\n\nУ HTML, який містить:\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n...буде показано `id`, взятий із «контексту» `dict`, який ви передали:\n\n```Python\n{\"id\": id}\n```\n\nНаприклад, з ID `42` це буде відображено як:\n\n```html\nItem ID: 42\n```\n\n### Аргументи `url_for` у шаблоні { #template-url-for-arguments }\n\nВи також можете використовувати `url_for()` у шаблоні - вона приймає ті самі аргументи, що й ваша *функція операції шляху*.\n\nТож фрагмент:\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n...згенерує посилання на той самий URL, який оброблятиме *функція операції шляху* `read_item(id=id)`.\n\nНаприклад, з ID `42` це буде відображено як:\n\n```html\n<a href=\"/items/42\">\n```\n\n## Шаблони і статичні файли { #templates-and-static-files }\n\nВи також можете використовувати `url_for()` у шаблоні, наприклад з `StaticFiles`, які ви змонтували з `name=\"static\"`.\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\nУ цьому прикладі це посилатиметься на файл CSS у `static/styles.css` за допомогою:\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\nІ оскільки ви використовуєте `StaticFiles`, цей файл CSS буде автоматично обслуговуватись вашим застосунком **FastAPI** за URL `/static/styles.css`.\n\n## Детальніше { #more-details }\n\nДокладніше, зокрема як тестувати шаблони, дивіться [документацію Starlette щодо шаблонів](https://www.starlette.dev/templates/).\n"
  },
  {
    "path": "docs/uk/docs/advanced/testing-dependencies.md",
    "content": "# Тестування залежностей з переписуваннями { #testing-dependencies-with-overrides }\n\n## Переписування залежностей під час тестування { #overriding-dependencies-during-testing }\n\nЄ сценарії, коли ви можете захотіти переписати залежність під час тестування.\n\nВи не хочете запускати оригінальну залежність (ані будь-які її підзалежності).\n\nНатомість ви хочете надати іншу залежність, яку буде використано лише під час тестів (можливо, тільки в окремих тестах), і яка повертатиме значення, що підставляється всюди, де раніше використовувалося значення оригінальної залежності.\n\n### Випадки використання: зовнішній сервіс { #use-cases-external-service }\n\nНаприклад, у вас є зовнішній постачальник автентифікації, який потрібно викликати.\n\nВи надсилаєте йому токен, і він повертає автентифікованого користувача.\n\nТакий постачальник може стягувати плату за кожний запит, а виклик може займати більше часу, ніж використання фіксованого фальшивого користувача для тестів.\n\nЙмовірно, ви хочете протестувати зовнішнього постачальника один раз, але не обов'язково викликати його для кожного тесту.\n\nУ такому разі ви можете переписати залежність, що викликає цього постачальника, і використати власну залежність, яка повертає фальшивого користувача, лише для ваших тестів.\n\n### Використовуйте атрибут `app.dependency_overrides` { #use-the-app-dependency-overrides-attribute }\n\nДля таких випадків ваш застосунок FastAPI має атрибут `app.dependency_overrides`, це простий `dict`.\n\nЩоб переписати залежність для тестування, вкажіть у ключі оригінальну залежність (функцію), а значенням - ваше переписування залежності (іншу функцію).\n\nПісля цього FastAPI викликатиме це переписування замість оригінальної залежності.\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip | Порада\n\nВи можете налаштувати переписування для залежності, яка використовується де завгодно у вашому застосунку FastAPI.\n\nОригінальна залежність може використовуватися у функції операції шляху, у декораторі операції шляху (коли ви не використовуєте повернуте значення), у виклику `.include_router()` тощо.\n\nFastAPI усе одно зможе її переписати.\n\n///\n\nПотім ви можете скинути переписування (видалити їх), встановивши для `app.dependency_overrides` порожній `dict`:\n\n```Python\napp.dependency_overrides = {}\n```\n\n/// tip | Порада\n\nЯкщо ви хочете переписувати залежність лише під час окремих тестів, встановіть переписування на початку тесту (всередині тестової функції) і скиньте його наприкінці (в кінці тестової функції).\n\n///\n"
  },
  {
    "path": "docs/uk/docs/advanced/testing-events.md",
    "content": "# Тестування подій: тривалість життя та запуск - вимкнення { #testing-events-lifespan-and-startup-shutdown }\n\nКоли вам потрібно, щоб `lifespan` виконувався у ваших тестах, ви можете використати `TestClient` з оператором `with`:\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\nВи можете прочитати більше у [«Запуск тривалості життя у тестах на офіційному сайті документації Starlette.»](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)\n\nДля застарілих подій `startup` і `shutdown` ви можете використовувати `TestClient` так:\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/uk/docs/advanced/testing-websockets.md",
    "content": "# Тестування WebSocket { #testing-websockets }\n\nВи можете використовувати той самий `TestClient` для тестування WebSocket.\n\nДля цього використайте `TestClient` в інструкції `with`, підключаючись до WebSocket:\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note | Примітка\n\nДокладніше дивіться документацію Starlette щодо [тестування WebSocket](https://www.starlette.dev/testclient/#testing-websocket-sessions).\n\n///\n"
  },
  {
    "path": "docs/uk/docs/advanced/using-request-directly.md",
    "content": "# Використання Request безпосередньо { #using-the-request-directly }\n\nДотепер ви оголошували потрібні вам частини запиту разом з їх типами.\n\nОтримуючи дані з:\n- шляху як параметрів;\n- заголовків;\n- кукі;\n- тощо.\n\nІ таким чином **FastAPI** перевіряє ці дані, перетворює їх і автоматично генерує документацію для вашого API.\n\nАле бувають ситуації, коли може знадобитися доступ до об'єкта `Request` безпосередньо.\n\n## Деталі про об'єкт `Request` { #details-about-the-request-object }\n\nОскільки під капотом **FastAPI** - це **Starlette** з шаром інструментів зверху, ви можете за потреби використовувати об'єкт [`Request`](https://www.starlette.dev/requests/) Starlette безпосередньо.\n\nЦе також означає, що якщо ви отримуєте дані безпосередньо з об'єкта `Request` (наприклад, читаєте тіло), FastAPI не буде їх перевіряти, перетворювати або документувати (через OpenAPI для автоматичного інтерфейсу користувача API).\n\nВодночас будь-який інший параметр, оголошений звичайним способом (наприклад, тіло з моделлю Pydantic), і надалі буде перевірений, перетворений, анотований тощо.\n\nАле є окремі випадки, коли корисно отримати об'єкт `Request`.\n\n## Використовуйте об'єкт `Request` безпосередньо { #use-the-request-object-directly }\n\nПрипустімо, ви хочете отримати IP-адресу/хост клієнта всередині вашої функції операції шляху.\n\nДля цього потрібно звернутися до запиту безпосередньо.\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\nЯкщо вказати у функції операції шляху параметр типу `Request`, **FastAPI** передасть у нього об'єкт `Request`.\n\n/// tip | Порада\n\nЗауважте, що в цьому прикладі ми оголошуємо параметр шляху поряд із параметром запиту.\n\nТому параметр шляху буде витягнуто, перевірено, перетворено до вказаного типу та анотовано в OpenAPI.\n\nТак само ви можете оголошувати будь-які інші параметри звичайним чином і додатково отримувати `Request`.\n\n///\n\n## Документація `Request` { #request-documentation }\n\nДокладніше про [об'єкт [`Request`] на офіційному сайті документації Starlette](https://www.starlette.dev/requests/).\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette.requests import Request`.\n\n**FastAPI** надає його безпосередньо як зручність для вас, розробника. Але він походить безпосередньо із Starlette.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\nВи можете використовувати [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) з **FastAPI**.\n\n## Встановіть `websockets` { #install-websockets }\n\nПереконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md), активували його та встановили `websockets` (бібліотеку Python, що полегшує використання протоколу «WebSocket»):\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## Клієнт WebSockets { #websockets-client }\n\n### У продакшені { #in-production }\n\nУ вашій продакшен-системі у вас, напевно, є фронтенд, створений за допомогою сучасного фреймворку на кшталт React, Vue.js або Angular.\n\nДля спілкування через WebSockets з бекендом ви, ймовірно, використовуватимете утиліти вашого фронтенду.\n\nАбо у вас може бути нативний мобільний застосунок, що напряму спілкується з вашим WebSocket-бекендом нативним кодом.\n\nАбо будь-який інший спосіб спілкування з кінцевою точкою WebSocket.\n\n---\n\nАле для цього прикладу ми використаємо дуже простий HTML-документ з невеликим JavaScript, усе всередині довгого рядка.\n\nЗвісно, це не оптимально і ви б не використовували це у продакшені.\n\nУ продакшені ви б використали один з варіантів вище.\n\nАле це найпростіший спосіб зосередитися на серверній частині WebSockets і мати робочий приклад:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## Створіть `websocket` { #create-a-websocket }\n\nУ вашому застосунку **FastAPI** створіть `websocket`:\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette.websockets import WebSocket`.\n\n**FastAPI** надає той самий `WebSocket` напряму як зручність для вас, розробника. Але він походить безпосередньо зі Starlette.\n\n///\n\n## Очікуйте повідомлення та надсилайте повідомлення { #await-for-messages-and-send-messages }\n\nУ вашому маршруті WebSocket ви можете `await` повідомлення і надсилати повідомлення.\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\nВи можете отримувати та надсилати бінарні, текстові та JSON-дані.\n\n## Спробуйте { #try-it }\n\nРозмістіть код у файлі `main.py`, а потім запустіть ваш застосунок:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nВідкрийте у браузері [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nВи побачите просту сторінку на кшталт:\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\nВи можете вводити повідомлення у поле вводу та надсилати їх:\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\nІ ваш застосунок **FastAPI** з WebSockets відповість:\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\nВи можете надсилати (і отримувати) багато повідомлень:\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\nІ всі вони використовуватимуть те саме з'єднання WebSocket.\n\n## Використання `Depends` та іншого { #using-depends-and-others }\n\nУ кінцевих точках WebSocket ви можете імпортувати з `fastapi` і використовувати:\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\nВони працюють так само, як для інших ендпойнтів FastAPI/*операцій шляху*:\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info\n\nОскільки це WebSocket, не має сенсу піднімати `HTTPException`, натомість ми піднімаємо `WebSocketException`.\n\nВи можете використати код закриття з [чинних кодів, визначених у специфікації](https://tools.ietf.org/html/rfc6455#section-7.4.1).\n\n///\n\n### Спробуйте WebSockets із залежностями { #try-the-websockets-with-dependencies }\n\nЗапустіть ваш застосунок:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nВідкрийте у браузері [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nТам ви можете встановити:\n\n* «Item ID», який використовується у шляху.\n* «Token», який використовується як параметр запиту.\n\n/// tip\n\nЗверніть увагу, що параметр запиту `token` буде оброблено залежністю.\n\n///\n\nПісля цього ви зможете під'єднати WebSocket, а далі надсилати й отримувати повідомлення:\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## Обробка відключень і кількох клієнтів { #handling-disconnections-and-multiple-clients }\n\nКоли з'єднання WebSocket закривається, `await websocket.receive_text()` підніме виняток `WebSocketDisconnect`, який ви можете перехопити й обробити, як у цьому прикладі.\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\nЩоб спробувати:\n\n* Відкрийте застосунок у кількох вкладках браузера.\n* Надсилайте з них повідомлення.\n* Потім закрийте одну з вкладок.\n\nЦе підніме виняток `WebSocketDisconnect`, і всі інші клієнти отримають повідомлення на кшталт:\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip\n\nЗастосунок вище - це мінімальний і простий приклад, що демонструє, як обробляти та розсилати повідомлення кільком з'єднанням WebSocket.\n\nАле майте на увазі, що оскільки все обробляється в пам'яті, в одному списку, це працюватиме лише поки процес запущений, і лише з одним процесом.\n\nЯкщо вам потрібне щось просте для інтеграції з FastAPI, але більш надійне, з підтримкою Redis, PostgreSQL чи інших, перегляньте [encode/broadcaster](https://github.com/encode/broadcaster).\n\n///\n\n## Детальніше { #more-info }\n\nЩоб дізнатися більше про можливості, перегляньте документацію Starlette:\n\n* [Клас `WebSocket`](https://www.starlette.dev/websockets/).\n* [Обробка WebSocket на основі класів](https://www.starlette.dev/endpoints/#websocketendpoint).\n"
  },
  {
    "path": "docs/uk/docs/advanced/wsgi.md",
    "content": "# Підключення WSGI - Flask, Django та інші { #including-wsgi-flask-django-others }\n\nВи можете монтувати застосунки WSGI, як ви бачили в [Підзастосунки - монтування](sub-applications.md), [За представником](behind-a-proxy.md).\n\nДля цього ви можете використати `WSGIMiddleware` і обгорнути ним ваш застосунок WSGI, наприклад Flask, Django тощо.\n\n## Використання `WSGIMiddleware` { #using-wsgimiddleware }\n\n/// info | Інформація\n\nДля цього потрібно встановити `a2wsgi`, наприклад за допомогою `pip install a2wsgi`.\n\n///\n\nПотрібно імпортувати `WSGIMiddleware` з `a2wsgi`.\n\nПотім обгорніть застосунок WSGI (напр., Flask) цим проміжним програмним забезпеченням.\n\nІ змонтуйте його під певним шляхом.\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note | Примітка\n\nРаніше рекомендувалося використовувати `WSGIMiddleware` з `fastapi.middleware.wsgi`, але тепер його визнано застарілим.\n\nЗамість цього радимо використовувати пакет `a2wsgi`. Використання залишається таким самим.\n\nПросто переконайтеся, що у вас встановлено пакет `a2wsgi`, і імпортуйте `WSGIMiddleware` коректно з `a2wsgi`.\n\n///\n\n## Перевірте { #check-it }\n\nТепер кожен запит за шляхом `/v1/` оброблятиметься застосунком Flask.\n\nА решта - **FastAPI**.\n\nЯкщо ви запустите це й перейдете на [http://localhost:8000/v1/](http://localhost:8000/v1/), ви побачите відповідь від Flask:\n\n```txt\nHello, World from Flask!\n```\n\nА якщо ви перейдете на [http://localhost:8000/v2](http://localhost:8000/v2), ви побачите відповідь від FastAPI:\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/uk/docs/alternatives.md",
    "content": "# Альтернативи, натхнення та порівняння { #alternatives-inspiration-and-comparisons }\n\nЩо надихнуло **FastAPI**, як він порівнюється з альтернативами та чого він у них навчився.\n\n## Вступ { #intro }\n\n**FastAPI** не існувало б, якби не попередні роботи інших.\n\nРаніше було створено багато інструментів, які надихнули на його створення.\n\nЯ кілька років уникав створення нового фреймворку. Спочатку я спробував вирішити всі функції, охоплені **FastAPI**, використовуючи багато різних фреймворків, плагінів та інструментів.\n\nАле в якийсь момент не було іншого виходу, окрім створення чогось, що надавало б усі ці функції, взявши найкращі ідеї з попередніх інструментів і поєднавши їх найкращим чином, використовуючи мовні функції, які навіть не були доступні раніше (Python 3.6+ підказки типів).\n\n## Попередні інструменти { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\nЦе найпопулярніший фреймворк Python, який користується широкою довірою. Він використовується для створення таких систем, як Instagram.\n\nВін відносно тісно пов’язаний з реляційними базами даних (наприклад, MySQL або PostgreSQL), тому мати базу даних NoSQL (наприклад, Couchbase, MongoDB, Cassandra тощо) як основний механізм зберігання не дуже просто.\n\nВін був створений для створення HTML у серверній частині, а не для створення API, які використовуються сучасним інтерфейсом (як-от React, Vue.js і Angular) або іншими системами (як-от <abbr title=\"Internet of Things - Інтернет речей\">IoT</abbr> пристрої), які спілкуються з ним.\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nФреймворк Django REST був створений як гнучкий інструментарій для створення веб-інтерфейсів API використовуючи Django в основі, щоб покращити його можливості API.\n\nЙого використовують багато компаній, включаючи Mozilla, Red Hat і Eventbrite.\n\nЦе був один із перших прикладів **автоматичної документації API**, і саме це була одна з перших ідей, яка надихнула на «пошук» **FastAPI**.\n\n/// note | Примітка\n\nDjango REST Framework створив Том Крісті. Той самий творець Starlette і Uvicorn, на яких базується **FastAPI**.\n\n///\n\n/// check | Надихнуло **FastAPI** на\n\nМати автоматичний веб-інтерфейс документації API.\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask — це «мікрофреймворк», він не включає інтеграцію бази даних, а також багато речей, які за замовчуванням є в Django.\n\nЦя простота та гнучкість дозволяють використовувати бази даних NoSQL як основну систему зберігання даних.\n\nОскільки він дуже простий, він порівняно легкий та інтуїтивний для освоєння, хоча в деяких моментах документація стає дещо технічною.\n\nВін також зазвичай використовується для інших програм, яким не обов’язково потрібна база даних, керування користувачами або будь-яка з багатьох функцій, які є попередньо вбудованими в Django. Хоча багато з цих функцій можна додати за допомогою плагінів.\n\nВідокремлення частин було ключовою особливістю, яку я хотів зберегти, при цьому залишаючись «мікрофреймворком», який можна розширити, щоб охопити саме те, що потрібно.\n\nВраховуючи простоту Flask, він здавався хорошим підходом для створення API. Наступним, що знайшов, був «Django REST Framework» для Flask.\n\n/// check | Надихнуло **FastAPI** на\n\nБути мікрофреймворком. Зробити легким комбінування та поєднання необхідних інструментів та частин.\n\nМати просту та легку у використанні систему маршрутизації.\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI** насправді не є альтернативою **Requests**. Сфера їх застосування дуже різна.\n\nНасправді цілком звична річ використовувати Requests *всередині* програми FastAPI.\n\nАле все ж FastAPI черпав натхнення з Requests.\n\n**Requests** — це бібліотека для *взаємодії* з API (як клієнт), а **FastAPI** — це бібліотека для *створення* API (як сервер).\n\nВони більш-менш знаходяться на протилежних кінцях, доповнюючи одна одну.\n\nRequests мають дуже простий та інтуїтивно зрозумілий дизайн, дуже простий у використанні, з розумними параметрами за замовчуванням. Але в той же час він дуже потужний і налаштовується.\n\nОсь чому, як сказано на офіційному сайті:\n\n> Requests є одним із найбільш завантажуваних пакетів Python усіх часів\n\nВикористовувати його дуже просто. Наприклад, щоб виконати запит `GET`, ви повинні написати:\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\nВідповідна операція шляху API FastAPI може виглядати так:\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\nЗверніть увагу на схожість у `requests.get(...)` і `@app.get(...)`.\n\n/// check | Надихнуло **FastAPI** на\n\n* Мати простий та інтуїтивно зрозумілий API.\n* Використовувати імена (операції) методів HTTP безпосередньо, простим та інтуїтивно зрозумілим способом.\n* Мати розумні параметри за замовчуванням, але потужні налаштування.\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\nГоловною функцією, яку я хотів від Django REST Framework, була автоматична API документація.\n\nПотім я виявив, що існує стандарт для документування API з використанням JSON (або YAML, розширення JSON) під назвою Swagger.\n\nІ вже був створений веб-інтерфейс користувача для Swagger API. Отже, можливість генерувати документацію Swagger для API дозволить використовувати цей веб-інтерфейс автоматично.\n\nУ якийсь момент Swagger було передано Linux Foundation, щоб перейменувати його на OpenAPI.\n\nТому, коли говорять про версію 2.0, прийнято говорити «Swagger», а про версію 3+ «OpenAPI».\n\n/// check | Надихнуло **FastAPI** на\n\nПрийняти і використовувати відкритий стандарт для специфікацій API замість спеціальної схеми.\n\nІнтегрувати інструменти інтерфейсу на основі стандартів:\n\n* [Інтерфейс Swagger](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\nЦі два було обрано через те, що вони досить популярні та стабільні, але, виконавши швидкий пошук, ви можете знайти десятки додаткових альтернативних інтерфейсів для OpenAPI (які можна використовувати з **FastAPI**).\n\n///\n\n### Фреймворки REST для Flask { #flask-rest-frameworks }\n\nІснує кілька фреймворків Flask REST, але, витративши час і роботу на їх дослідження, я виявив, що багато з них припинено або залишено, з кількома постійними проблемами, які зробили їх непридатними.\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nОднією з головних функцій, необхідних для систем API, є «<dfn title=\"також відома як: marshalling, перетворення\">серіалізація</dfn>», яка бере дані з коду (Python) і перетворює їх на щось, що можна надіслати через мережу. Наприклад, перетворення об’єкта, що містить дані з бази даних, на об’єкт JSON. Перетворення об’єктів `datetime` на строки тощо.\n\nІншою важливою функцією, необхідною для API, є перевірка даних, яка забезпечує дійсність даних за певними параметрами. Наприклад, що деяке поле є `int`, а не деяка випадкова строка. Це особливо корисно для вхідних даних.\n\nБез системи перевірки даних вам довелося б виконувати всі перевірки вручну, у коді.\n\nMarshmallow створено для забезпечення цих функцій. Це чудова бібліотека, і я часто нею користувався раніше.\n\nАле він був створений до того, як існували підказки типу Python. Отже, щоб визначити кожну <dfn title=\"визначення того, як дані повинні бути сформовані\">схему</dfn>, вам потрібно використовувати спеціальні утиліти та класи, надані Marshmallow.\n\n/// check | Надихнуло **FastAPI** на\n\nВикористовувати код для автоматичного визначення \"схем\", які надають типи даних і перевірку.\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nІншою важливою функцією, необхідною для API, є <dfn title=\"читання та перетворення на дані Python\">аналіз</dfn> даних із вхідних запитів.\n\nWebargs — це інструмент, створений, щоб забезпечити це поверх кількох фреймворків, включаючи Flask.\n\nВін використовує Marshmallow в основі для перевірки даних. І створений тими ж розробниками.\n\nЦе чудовий інструмент, і я також часто використовував його, перш ніж створити **FastAPI**.\n\n/// info | Інформація\n\nWebargs був створений тими ж розробниками Marshmallow.\n\n///\n\n/// check | Надихнуло **FastAPI** на\n\nМати автоматичну перевірку даних вхідного запиту.\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow і Webargs забезпечують перевірку, аналіз і серіалізацію як плагіни.\n\nАле документація досі відсутня. Потім було створено APISpec.\n\nЦе плагін для багатьох фреймворків (також є плагін для Starlette).\n\nПринцип роботи полягає в тому, що ви пишете визначення схеми, використовуючи формат YAML, у docstring кожної функції, що обробляє маршрут.\n\nІ він генерує схеми OpenAPI.\n\nТак це працює у Flask, Starlette, Responder тощо.\n\nАле потім ми знову маємо проблему наявності мікросинтаксису всередині Python строки (великий YAML).\n\nРедактор тут нічим не може допомогти. І якщо ми змінимо параметри чи схеми Marshmallow і забудемо також змінити цю строку документа YAML, згенерована схема буде застарілою.\n\n/// info | Інформація\n\nAPISpec був створений тими ж розробниками Marshmallow.\n\n///\n\n/// check | Надихнуло **FastAPI** на\n\nПідтримувати відкритий стандарт API, OpenAPI.\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\nЦе плагін Flask, який об’єднує Webargs, Marshmallow і APISpec.\n\nВін використовує інформацію з Webargs і Marshmallow для автоматичного створення схем OpenAPI за допомогою APISpec.\n\nЦе чудовий інструмент, дуже недооцінений. Він має бути набагато популярнішим, ніж багато плагінів Flask. Це може бути пов’язано з тим, що його документація надто стисла й абстрактна.\n\nЦе вирішило необхідність писати YAML (інший синтаксис) всередині рядків документів Python.\n\nЦя комбінація Flask, Flask-apispec із Marshmallow і Webargs була моїм улюбленим бекенд-стеком до створення **FastAPI**.\n\nЇї використання призвело до створення кількох генераторів повного стека Flask. Це основний стек, який я (та кілька зовнішніх команд) використовував досі:\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\nІ ці самі генератори повного стеку були основою [**FastAPI** генераторів проектів](project-generation.md).\n\n/// info | Інформація\n\nFlask-apispec був створений тими ж розробниками Marshmallow.\n\n///\n\n/// check | Надихнуло **FastAPI** на\n\nСтворення схеми OpenAPI автоматично з того самого коду, який визначає серіалізацію та перевірку.\n\n///\n\n### [NestJS](https://nestjs.com/) (та [Angular](https://angular.io/)) { #nestjs-and-angular }\n\nЦе навіть не Python, NestJS — це фреймворк NodeJS JavaScript (TypeScript), натхненний Angular.\n\nЦе досягає чогось подібного до того, що можна зробити з Flask-apispec.\n\nВін має інтегровану систему впровадження залежностей, натхненну Angular 2. Він потребує попередньої реєстрації «injectables» (як і всі інші системи впровадження залежностей, які я знаю), тому це збільшує багатослівність та повторення коду.\n\nОскільки параметри описані за допомогою типів TypeScript (подібно до підказок типу Python), підтримка редактора досить хороша.\n\nАле оскільки дані TypeScript не зберігаються після компіляції в JavaScript, вони не можуть покладатися на типи для визначення перевірки, серіалізації та документації одночасно. Через це та деякі дизайнерські рішення, щоб отримати перевірку, серіалізацію та автоматичну генерацію схеми, потрібно додати декоратори в багатьох місцях. Таким чином код стає досить багатослівним.\n\nВін не дуже добре обробляє вкладені моделі. Отже, якщо тіло JSON у запиті є об’єктом JSON із внутрішніми полями, які, у свою чергу, є вкладеними об’єктами JSON, його неможливо належним чином задокументувати та перевірити.\n\n/// check | Надихнуло **FastAPI** на\n\nВикористовувати типи Python, щоб мати чудову підтримку редактора.\n\nМати потужну систему впровадження залежностей. Знайдіть спосіб звести до мінімуму повторення коду.\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\nЦе був один із перших надзвичайно швидких фреймворків Python на основі `asyncio`. Він був дуже схожий на Flask.\n\n/// note | Технічні деталі\n\nВін використовував [`uvloop`](https://github.com/MagicStack/uvloop) замість стандартного циклу Python `asyncio`. Ось що зробило його таким швидким.\n\nЦе явно надихнуло Uvicorn і Starlette, які зараз швидші за Sanic у відкритих тестах.\n\n///\n\n/// check | Надихнуло **FastAPI** на\n\nЗнайти спосіб отримати божевільну продуктивність.\n\nОсь чому **FastAPI** базується на Starlette, оскільки це найшвидша доступна структура (перевірена тестами сторонніх розробників).\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon — ще один високопродуктивний фреймворк Python, він розроблений як мінімальний і працює як основа інших фреймворків, таких як Hug.\n\nВін розроблений таким чином, щоб мати функції, які отримують два параметри, один «запит» і один «відповідь». Потім ви «читаєте» частини запиту та «записуєте» частини у відповідь. Через такий дизайн неможливо оголосити параметри запиту та тіла за допомогою стандартних підказок типу Python як параметри функції.\n\nТаким чином, перевірка даних, серіалізація та документація повинні виконуватися в коді, а не автоматично. Або вони повинні бути реалізовані як фреймворк поверх Falcon, як Hug. Така сама відмінність спостерігається в інших фреймворках, натхненних дизайном Falcon, що мають один об’єкт запиту та один об’єкт відповіді як параметри.\n\n/// check | Надихнуло **FastAPI** на\n\nЗнайти способи отримати чудову продуктивність.\n\nРазом із Hug (оскільки Hug базується на Falcon) надихнув **FastAPI** оголосити параметр `response` у функціях.\n\nХоча у FastAPI це необов’язково, і використовується в основному для встановлення заголовків, файлів cookie та альтернативних кодів статусу.\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\nЯ відкрив для себе Molten на перших етапах створення **FastAPI**. І він має досить схожі ідеї:\n\n* Базується на підказках типу Python.\n* Перевірка та документація цих типів.\n* Система впровадження залежностей.\n\nВін не використовує перевірку даних, серіалізацію та бібліотеку документації сторонніх розробників, як Pydantic, він має свою власну. Таким чином, ці визначення типів даних не можна було б використовувати повторно так легко.\n\nЦе вимагає трохи більш докладних конфігурацій. І оскільки він заснований на WSGI (замість ASGI), він не призначений для використання високопродуктивних інструментів, таких як Uvicorn, Starlette і Sanic.\n\nСистема впровадження залежностей вимагає попередньої реєстрації залежностей, і залежності вирішуються на основі оголошених типів. Отже, неможливо оголосити більше ніж один «компонент», який надає певний тип.\n\nМаршрути оголошуються в одному місці з використанням функцій, оголошених в інших місцях (замість використання декораторів, які можна розмістити безпосередньо поверх функції, яка обробляє кінцеву точку). Це ближче до того, як це робить Django, ніж до Flask (і Starlette). Він розділяє в коді речі, які відносно тісно пов’язані.\n\n/// check | Надихнуло **FastAPI** на\n\nВизначити додаткові перевірки для типів даних, використовуючи значення \"за замовчуванням\" атрибутів моделі. Це покращує підтримку редактора, а раніше вона була недоступна в Pydantic.\n\nЦе фактично надихнуло оновити частини Pydantic, щоб підтримувати той самий стиль оголошення перевірки (всі ці функції вже доступні в Pydantic).\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug був одним із перших фреймворків, який реалізував оголошення типів параметрів API за допомогою підказок типу Python. Це була чудова ідея, яка надихнула інші інструменти зробити те саме.\n\nВін використовував спеціальні типи у своїх оголошеннях замість стандартних типів Python, але це все одно був величезний крок вперед.\n\nЦе також був один із перших фреймворків, який генерував спеціальну схему, що оголошувала весь API у JSON.\n\nВін не базувався на таких стандартах, як OpenAPI та JSON Schema. Тому було б непросто інтегрувати його з іншими інструментами, як-от Swagger UI. Але знову ж таки, це була дуже інноваційна ідея.\n\nВін має цікаву незвичайну функцію: використовуючи ту саму структуру, можна створювати API, а також CLI.\n\nОскільки він заснований на попередньому стандарті для синхронних веб-фреймворків Python (WSGI), він не може працювати з Websockets та іншими речами, хоча він також має високу продуктивність.\n\n/// info | Інформація\n\nHug створив Тімоті Крослі, той самий творець [`isort`](https://github.com/timothycrosley/isort), чудовий інструмент для автоматичного сортування імпорту у файлах Python.\n\n///\n\n/// check | Ідеї, що надихнули **FastAPI**\n\nHug надихнув частину APIStar і був одним із найбільш перспективних інструментів, поряд із APIStar.\n\nHug надихнув **FastAPI** на використання підказок типу Python для оголошення параметрів і автоматичного створення схеми, що визначає API.\n\nHug надихнув **FastAPI** оголосити параметр `response` у функціях для встановлення заголовків і файлів cookie.\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0,5) { #apistar-0-5 }\n\nБезпосередньо перед тим, як вирішити створити **FastAPI**, я знайшов сервер **APIStar**. Він мав майже все, що я шукав, і мав чудовий дизайн.\n\nЦе була одна з перших реалізацій фреймворку, що використовує підказки типу Python для оголошення параметрів і запитів, яку я коли-небудь бачив (до NestJS і Molten). Я знайшов його більш-менш одночасно з Hug. Але APIStar використовував стандарт OpenAPI.\n\nВін мав автоматичну перевірку даних, серіалізацію даних і генерацію схеми OpenAPI на основі підказок того самого типу в кількох місцях.\n\nВизначення схеми тіла не використовували ті самі підказки типу Python, як Pydantic, воно було трохи схоже на Marshmallow, тому підтримка редактора була б не такою хорошою, але все ж APIStar був найкращим доступним варіантом.\n\nВін мав найкращі показники продуктивності на той час (перевершив лише Starlette).\n\nСпочатку він не мав автоматичного веб-інтерфейсу документації API, але я знав, що можу додати до нього інтерфейс користувача Swagger.\n\nВін мав систему введення залежностей. Він вимагав попередньої реєстрації компонентів, як і інші інструменти, розглянуті вище. Але все одно це була чудова функція.\n\nЯ ніколи не міг використовувати його в повноцінному проекті, оскільки він не мав інтеграції безпеки, тому я не міг замінити всі функції, які мав, генераторами повного стеку на основі Flask-apispec. У моїх невиконаних проектах я мав створити запит на вилучення, додавши цю функцію.\n\nАле потім фокус проекту змінився.\n\nЦе вже не був веб-фреймворк API, оскільки творцю потрібно було зосередитися на Starlette.\n\nТепер APIStar — це набір інструментів для перевірки специфікацій OpenAPI, а не веб-фреймворк.\n\n/// info | Інформація\n\nAPIStar створив Том Крісті. Той самий хлопець, який створив:\n\n* Django REST Framework\n* Starlette (на якому базується **FastAPI**)\n* Uvicorn (використовується Starlette і **FastAPI**)\n\n///\n\n/// check | Надихнуло **FastAPI** на\n\nІснувати.\n\nІдею оголошення кількох речей (перевірки даних, серіалізації та документації) за допомогою тих самих типів Python, які в той же час забезпечували чудову підтримку редактора, я вважав геніальною ідеєю.\n\nІ після тривалого пошуку подібної структури та тестування багатьох різних альтернатив, APIStar став найкращим доступним варіантом.\n\nПотім APIStar перестав існувати як сервер, і було створено Starlette, який став новою кращою основою для такої системи. Це стало останнім джерелом натхнення для створення **FastAPI**.\n\nЯ вважаю **FastAPI** «духовним спадкоємцем» APIStar, удосконалюючи та розширюючи функції, систему типізації та інші частини на основі досвіду, отриманого від усіх цих попередніх інструментів.\n\n///\n\n## Використовується **FastAPI** { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic — це бібліотека для визначення перевірки даних, серіалізації та документації (за допомогою Схеми JSON) на основі підказок типу Python.\n\nЦе робить його надзвичайно інтуїтивним.\n\nЙого можна порівняти з Marshmallow. Хоча він швидший за Marshmallow у тестах. Оскільки він базується на тих самих підказках типу Python, підтримка редактора чудова.\n\n/// check | **FastAPI** використовує його для\n\nВиконання перевірки всіх даних, серіалізації даних і автоматичної документації моделі (на основі Схеми JSON).\n\nПотім **FastAPI** бере ці дані Схеми JSON і розміщує їх у OpenAPI, окремо від усіх інших речей, які він робить.\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette — це легкий фреймворк/набір інструментів <dfn title=\"Новий стандарт для створення асинхронних вебзастосунків на Python\">ASGI</dfn>, який ідеально підходить для створення високопродуктивних asyncio сервісів.\n\nВін дуже простий та інтуїтивно зрозумілий. Його розроблено таким чином, щоб його можна було легко розширювати та мати модульні компоненти.\n\nВін має:\n\n* Серйозно вражаючу продуктивність.\n* Підтримку WebSocket.\n* Фонові завдання в процесі.\n* Події запуску та завершення роботи.\n* Тестового клієнта, побудований на HTTPX.\n* CORS, GZip, статичні файли, потокові відповіді.\n* Підтримку сеансів і файлів cookie.\n* 100% покриття тестом.\n* 100% анотовану кодову базу.\n* Кілька жорстких залежностей.\n\nStarlette наразі є найшвидшим фреймворком Python із перевірених. Перевершує лише Uvicorn, який є не фреймворком, а сервером.\n\nStarlette надає всі основні функції веб-мікрофреймворку.\n\nАле він не забезпечує автоматичної перевірки даних, серіалізації чи документації.\n\nЦе одна з головних речей, які **FastAPI** додає зверху, все на основі підказок типу Python (з використанням Pydantic). Це, а також система впровадження залежностей, утиліти безпеки, створення схеми OpenAPI тощо.\n\n/// note | Технічні деталі\n\nASGI — це новий «стандарт», який розробляється членами основної команди Django. Це ще не «стандарт Python» (PEP), хоча вони в процесі цього.\n\nТим не менш, він уже використовується як «стандарт» кількома інструментами. Це значно покращує сумісність, оскільки ви можете переключити Uvicorn на будь-який інший сервер ASGI (наприклад, Daphne або Hypercorn), або ви можете додати інструменти, сумісні з ASGI, як-от `python-socketio`.\n\n///\n\n/// check | **FastAPI** використовує його для\n\nКерування всіма основними веб-частинами. Додавання функцій зверху.\n\nСам клас `FastAPI` безпосередньо успадковує клас `Starlette`.\n\nОтже, усе, що ви можете робити зі Starlette, ви можете робити це безпосередньо за допомогою **FastAPI**, оскільки це, по суті, Starlette на стероїдах.\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn — це блискавичний сервер ASGI, побудований на uvloop і httptools.\n\nЦе не веб-фреймворк, а сервер. Наприклад, він не надає інструментів для маршрутизації. Це те, що фреймворк на кшталт Starlette (або **FastAPI**) забезпечить поверх нього.\n\nЦе рекомендований сервер для Starlette і **FastAPI**.\n\n/// check | **FastAPI** рекомендує це як\n\nОсновний веб-сервер для запуску програм **FastAPI**.\n\nВи також можете використати параметр командного рядка `--workers`, щоб мати асинхронний багатопроцесний сервер.\n\nДодаткову інформацію див. у розділі [Розгортання](deployment/index.md).\n\n///\n\n## Орієнтири та швидкість { #benchmarks-and-speed }\n\nЩоб зрозуміти, порівняти та побачити різницю між Uvicorn, Starlette і FastAPI, перегляньте розділ про [Бенчмарки](benchmarks.md).\n"
  },
  {
    "path": "docs/uk/docs/async.md",
    "content": "# Рівночасність і async / await { #concurrency-and-async-await }\n\nДеталі щодо синтаксису `async def` для функцій операції шляху і деякі відомості про асинхронний код, рівночасність і паралелізм.\n\n## Поспішаєте? { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - занадто довго; не читав\"><strong>TL;DR:</strong></abbr>\n\nЯкщо ви використовуєте сторонні бібліотеки, які вимагають виклику з `await`, наприклад:\n\n```Python\nresults = await some_library()\n```\n\nТоді оголошуйте ваші функції операції шляху з `async def`, наприклад:\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | Примітка\n\nВи можете використовувати `await` лише всередині функцій, створених з `async def`.\n\n///\n\n---\n\nЯкщо ви використовуєте сторонню бібліотеку, яка взаємодіє з чимось (база даних, API, файлова система тощо) і не підтримує використання `await` (наразі це стосується більшості бібліотек баз даних), тоді оголошуйте ваші функції операції шляху як зазвичай, просто з `def`, наприклад:\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\nЯкщо ваш застосунок (якимось чином) не має комунікувати з чимось іншим і чекати на відповідь, використовуйте `async def`, навіть якщо вам не потрібно використовувати `await` всередині.\n\n---\n\nЯкщо ви не певні, використовуйте звичайний `def`.\n\n---\n\nПримітка: ви можете змішувати `def` і `async def` у ваших функціях операції шляху скільки завгодно і визначати кожну з них найкращим для вас способом. FastAPI зробить з ними все правильно.\n\nУ будь-якому з наведених випадків FastAPI все одно працюватиме асинхронно і буде надзвичайно швидким.\n\nАле слідуючи крокам вище, він зможе зробити деякі оптимізації продуктивності.\n\n## Технічні деталі { #technical-details }\n\nСучасні версії Python мають підтримку «асинхронного коду» за допомогою так званих «співпрограм» з синтаксисом **`async` і `await`**.\n\nРозгляньмо цю фразу по частинах у секціях нижче:\n\n- Асинхронний код\n- `async` і `await`\n- Співпрограми\n\n## Асинхронний код { #asynchronous-code }\n\nАсинхронний код означає, що мова 💬 має спосіб сказати комп’ютеру/програмі 🤖, що в певний момент у коді він 🤖 має почекати, поки «щось інше» завершиться десь ще. Скажімо, це «щось інше» називається «slow-file» 📝.\n\nОтже, в цей час комп’ютер може піти і зробити іншу роботу, доки «slow-file» 📝 завершується.\n\nДалі комп’ютер/програма 🤖 повертатиметься щоразу, коли матиме можливість, бо знову чекає, або коли він 🤖 завершив усю роботу, яка була в нього на той момент. І він 🤖 перевірить, чи якась із задач, на які він чекав, уже завершилася, виконавши все, що потрібно.\n\nПотім він 🤖 бере першу завершену задачу (скажімо, наш «slow-file» 📝) і продовжує робити те, що потрібно було зробити з нею.\n\nЦе «чекати на щось інше» зазвичай стосується операцій <abbr title=\"Input and Output - Ввід та Вивід\">I/O</abbr>, які відносно «повільні» (порівняно зі швидкістю процесора та пам’яті з довільним доступом), наприклад, очікування:\n\n- даних від клієнта, що надсилаються мережею\n- даних, надісланих вашим застосунком, які клієнт має отримати мережею\n- вмісту файла на диску, який система має прочитати і передати вашому застосунку\n- вмісту, який ваш застосунок передав системі, щоб він був записаний на диск\n- віддаленої операції API\n- завершення операції бази даних\n- повернення результатів запиту до бази даних\n- тощо\n\nОскільки час виконання переважно витрачається на очікування операцій <abbr title=\"Input and Output - Ввід та Вивід\">I/O</abbr>, їх називають операціями «I/O bound».\n\nЦе називається «асинхронним», тому що комп’ютеру/програмі не потрібно бути «синхронізованими» з повільною задачею, очікуючи точного моменту її завершення, нічого не роблячи, лише щоб отримати результат задачі та продовжити роботу.\n\nНатомість, у «асинхронній» системі щойно завершена задача може трохи зачекати в черзі (кілька мікросекунд), доки комп’ютер/програма завершить те, що пішов робити, а потім повернеться, щоб забрати результати і продовжити роботу з ними.\n\nДля «синхронного» (на противагу «асинхронному») часто також використовують термін «послідовний», бо комп’ютер/програма слідує всім крокам послідовно, перш ніж перемкнутися на іншу задачу, навіть якщо ці кроки включають очікування.\n\n### Рівночасність і бургери { #concurrency-and-burgers }\n\nІдею **асинхронного** коду, описану вище, інколи також називають **«рівночасністю»**. Вона відрізняється від **«паралелізму»**.\n\nІ рівночасність, і паралелізм стосуються «різних речей, що відбуваються більш-менш одночасно».\n\nАле деталі між рівночасністю і паралелізмом досить різні.\n\nЩоб побачити різницю, уявімо таку історію про бургери:\n\n### Рівночасні бургери { #concurrent-burgers }\n\nВи йдете зі своєю симпатією по фастфуд, стаєте в чергу, доки касир приймає замовлення у людей перед вами. 😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\nПотім ваша черга, ви замовляєте 2 дуже вишукані бургери для вашої симпатії і для себе. 🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\nКасир каже щось кухарю на кухні, щоб той знав, що треба приготувати ваші бургери (хоча зараз він готує бургери для попередніх клієнтів).\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\nВи платите. 💸\n\nКасир дає вам номер вашої черги.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\nПоки ви чекаєте, ви з вашою симпатією обираєте столик, сідаєте і довго розмовляєте (адже ваші бургери дуже вишукані і потребують часу на приготування).\n\nСидячи за столиком із вашою симпатією, доки чекаєте бургери, ви можете витратити цей час, милуючись тим, яка ваша симпатія класна, мила і розумна ✨😍✨.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\nЧекаючи і спілкуючись із вашою симпатією, час від часу ви перевіряєте номер на табло біля прилавка, щоб побачити, чи вже ваша черга.\n\nІ от нарешті ваша черга. Ви підходите до прилавка, забираєте бургери і повертаєтеся до столика.\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\nВи з вашою симпатією їсте бургери і гарно проводите час. ✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info | Інформація\n\nПрекрасні ілюстрації від [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nУявіть, що в цій історії ви - комп’ютер/програма 🤖.\n\nПоки ви в черзі, ви просто бездіяльні 😴, чекаєте своєї черги, нічого «продуктивного» не роблячи. Але черга рухається швидко, бо касир лише приймає замовлення (а не готує їх), тож це нормально.\n\nКоли ж ваша черга, ви виконуєте справді «продуктивну» роботу: переглядаєте меню, вирішуєте, що бажаєте, дізнаєтеся вибір вашої симпатії, платите, перевіряєте, що віддаєте правильну купюру чи картку, що з вас правильно списали кошти, що замовлення містить правильні позиції тощо.\n\nАле потім, хоча у вас ще немає бургерів, ваша взаємодія з касиром «на паузі» ⏸, бо вам доводиться чекати 🕙, поки бургери будуть готові.\n\nВтім, відійшовши від прилавка і сівши за столик із номерком, ви можете перемкнути 🔀 увагу на свою симпатію і «попрацювати» ⏯ 🤓 над цим. Тоді ви знову робите щось дуже «продуктивне» - фліртуєте зі своєю симпатією 😍.\n\nПотім касир 💁 каже «Я закінчив робити бургери», виводячи ваш номер на табло прилавка, але ви не підстрибуєте миттєво, щойно номер змінюється на ваш. Ви знаєте, що ніхто не вкраде ваші бургери, адже у вас є номер вашої черги, а в інших - свій.\n\nТож ви чекаєте, поки ваша симпатія завершить історію (завершить поточну роботу ⏯/задачу 🤓), лагідно усміхаєтеся і кажете, що підете за бургерами ⏸.\n\nПотім ви йдете до прилавка 🔀, до початкової задачі, яку тепер завершено ⏯, забираєте бургери, дякуєте і несете їх до столу. Це завершує той крок/задачу взаємодії з прилавком ⏹. Натомість з’являється нова задача «їсти бургери» 🔀 ⏯, але попередня «отримати бургери» завершена ⏹.\n\n### Паралельні бургери { #parallel-burgers }\n\nА тепер уявімо, що це не «рівночасні бургери», а «паралельні бургери».\n\nВи йдете зі своєю симпатією по паралельний фастфуд.\n\nВи стаєте в чергу, поки кілька (скажімо, 8) касирів, які водночас є кухарями, приймають замовлення у людей перед вами.\n\nКожен перед вами чекає, поки його бургери будуть готові, перш ніж відійти від прилавка, тому що кожен з 8 касирів одразу йде і готує бургер, перш ніж приймати наступне замовлення.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\nНарешті ваша черга, ви замовляєте 2 дуже вишукані бургери для вашої симпатії і для себе.\n\nВи платите 💸.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\nКасир іде на кухню.\n\nВи чекаєте, стоячи перед прилавком 🕙, щоб ніхто інший не забрав ваші бургери раніше, ніж ви, адже номерків черги немає.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\nОскільки ви з вашою симпатією зайняті тим, щоб ніхто не став перед вами і не забрав ваші бургери, щойно вони з’являться, ви не можете приділяти увагу своїй симпатії. 😞\n\nЦе «синхронна» робота, ви «синхронізовані» з касиром/кухарем 👨‍🍳. Вам доводиться чекати 🕙 і бути тут у точний момент, коли касир/кухар 👨‍🍳 завершить бургери і віддасть їх вам, інакше хтось інший може їх забрати.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\nПотім ваш касир/кухар 👨‍🍳 нарешті повертається з вашими бургерами після довгого очікування 🕙 перед прилавком.\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\nВи берете бургери і йдете до столика зі своєю симпатією.\n\nВи просто їх їсте - і все. ⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\nБагато розмов чи флірту не було, бо більшість часу пішла на очікування 🕙 перед прилавком. 😞\n\n/// info | Інформація\n\nПрекрасні ілюстрації від [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot). 🎨\n\n///\n\n---\n\nУ цьому сценарії паралельних бургерів ви - комп’ютер/програма 🤖 з двома процесорами (ви і ваша симпатія), які обидва чекають 🕙 і приділяють увагу ⏯ «очікуванню біля прилавка» 🕙 тривалий час.\n\nУ закладу фастфуду 8 процесорів (касира/кухаря). У той час як у закладу з рівночасними бургерами могло бути лише 2 (один касир і один кухар).\n\nТа все одно фінальний досвід не найкращий. 😞\n\n---\n\nЦе була б паралельна історія про бургери. 🍔\n\nДля більш «реального» прикладу уявіть банк.\n\nДо недавнього часу більшість банків мали кілька касирів 👨‍💼👨‍💼👨‍💼👨‍💼 і велику чергу 🕙🕙🕙🕙🕙🕙🕙🕙.\n\nУсі касири робили всю роботу з одним клієнтом за іншим 👨‍💼⏯.\n\nІ вам доводилося 🕙 довго стояти в черзі, інакше ви втратите свою чергу.\n\nВи, напевно, не хотіли б брати свою симпатію 😍 із собою у справи до банку 🏦.\n\n### Висновок про бургери { #burger-conclusion }\n\nУ цьому сценарії «фастфуд із вашою симпатією», оскільки є багато очікування 🕙, значно доцільніше мати рівночасну систему ⏸🔀⏯.\n\nТак є у більшості вебзастосунків.\n\nБагато-багато користувачів, але ваш сервер чекає 🕙 на їхнє не надто гарне з’єднання, щоб вони надіслали свої запити.\n\nА потім знову чекає 🕙 на повернення відповідей.\n\nЦе «очікування» 🕙 вимірюється у мікросекундах, але все ж, у сумі - це багато очікування в підсумку.\n\nОсь чому дуже логічно використовувати асинхронний ⏸🔀⏯ код для веб API.\n\nТакий тип асинхронності зробив NodeJS популярним (хоча NodeJS не є паралельним), і це сила Go як мови програмування.\n\nІ такий самий рівень продуктивності ви отримуєте з **FastAPI**.\n\nА оскільки можна мати паралелізм і асинхронність одночасно, ви отримуєте вищу продуктивність, ніж більшість протестованих фреймворків NodeJS, і на рівні з Go, який є компільованою мовою, ближчою до C [(усе завдяки Starlette)](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1).\n\n### Чи краща рівночасність за паралелізм? { #is-concurrency-better-than-parallelism }\n\nНі! Це не мораль історії.\n\nРівночасність відрізняється від паралелізму. І вона краща у конкретних сценаріях, що містять багато очікування. Через це зазвичай вона значно краща за паралелізм для розробки вебзастосунків. Але не для всього.\n\nЩоб урівноважити це, уявімо коротку історію:\n\n> Ви маєте прибрати великий брудний будинок.\n\n*Так, це вся історія*.\n\n---\n\nТут немає очікування 🕙 - просто багато роботи, яку треба зробити, у багатьох місцях будинку.\n\nУ вас могли б бути «черги» як у прикладі з бургерами: спочатку вітальня, потім кухня. Але оскільки ви ні на що не чекаєте 🕙, а просто прибираєте, «черги» нічого не змінять.\n\nЗавершення займе той самий час із «чергами» чи без (рівночасність), і ви виконаєте той самий обсяг роботи.\n\nАле в цьому випадку, якби ви могли привести 8 колишніх касирів/кухарів/тепер прибиральників, і кожен з них (разом із вами) взяв би свою зону будинку для прибирання, ви могли б виконати всю роботу паралельно — з додатковою допомогою — і завершити значно швидше.\n\nУ цьому сценарії кожен з прибиральників (включно з вами) був би процесором, що виконує свою частину роботи.\n\nІ оскільки більшість часу виконання займає реальна робота (а не очікування), а роботу на комп’ютері виконує <abbr title=\"Central Processing Unit - Центральний процесор\">CPU</abbr>, ці проблеми називають «CPU bound».\n\n---\n\nПоширені приклади «CPU bound» операцій - це речі, що потребують складної математичної обробки.\n\nНаприклад:\n\n- **Обробка аудіо** або **зображень**.\n- **Комп’ютерний зір**: зображення складається з мільйонів пікселів, кожен піксель має 3 значення/кольори, обробка зазвичай потребує обчислення чогось над цими пікселями, усіма одночасно.\n- **Машинне навчання**: зазвичай потребує великої кількості множень «матриць» і «векторів». Уявіть величезну таблицю з числами і множення всіх їх разом одночасно.\n- **Глибоке навчання**: це підгалузь машинного навчання, тож те саме застосовується. Просто тут не одна таблиця чисел для множення, а величезний їх набір, і в багатьох випадках ви використовуєте спеціальний процесор для побудови та/або використання цих моделей.\n\n### Рівночасність + паралелізм: веб + машинне навчання { #concurrency-parallelism-web-machine-learning }\n\nЗ **FastAPI** ви можете скористатися рівночасністю, що дуже поширена у веброзробці (та ж головна принада NodeJS).\n\nАле ви також можете використати переваги паралелізму і багатопроцесорності (наявність кількох процесів, що працюють паралельно) для навантажень «CPU bound», як у системах машинного навчання.\n\nЦе, плюс простий факт, що Python є основною мовою для **Data Science**, машинного навчання і особливо глибокого навчання, робить FastAPI дуже вдалим вибором для веб API та застосунків Data Science / машинного навчання (серед багатьох інших).\n\nЩоб побачити, як досягти цього паралелізму у продакшні, див. розділ про [Розгортання](deployment/index.md).\n\n## `async` і `await` { #async-and-await }\n\nСучасні версії Python мають дуже інтуїтивний спосіб визначення асинхронного коду. Це робить його схожим на звичайний «послідовний» код і виконує «очікування» за вас у відповідні моменти.\n\nКоли є операція, яка вимагатиме очікування перед поверненням результатів і має підтримку цих нових можливостей Python, ви можете написати її так:\n\n```Python\nburgers = await get_burgers(2)\n```\n\nКлюч тут - `await`. Він каже Python, що потрібно почекати ⏸, поки `get_burgers(2)` завершить свою роботу 🕙, перш ніж зберегти результати в `burgers`. Завдяки цьому Python знатиме, що може піти і зробити щось інше 🔀 ⏯ тим часом (наприклад, прийняти інший запит).\n\nЩоб `await` працював, він має бути всередині функції, що підтримує цю асинхронність. Для цього просто оголосіть її як `async def`:\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # Виконайте деякі асинхронні дії, щоб створити бургери\n    return burgers\n```\n\n...замість `def`:\n\n```Python hl_lines=\"2\"\n# Це не асинхронно\ndef get_sequential_burgers(number: int):\n    # Виконайте деякі послідовні дії, щоб створити бургери\n    return burgers\n```\n\nЗ `async def` Python знає, що всередині цієї функції він має відслідковувати вирази `await`, і що він може «ставити на паузу» ⏸ виконання цієї функції і йти робити щось інше 🔀, перш ніж повернутися.\n\nКоли ви хочете викликати функцію, визначену з `async def`, ви маєте «очікувати» її. Тож це не спрацює:\n\n```Python\n# Це не спрацює, тому що get_burgers визначено як: async def\nburgers = get_burgers(2)\n```\n\n---\n\nОтже, якщо ви використовуєте бібліотеку, яку можна викликати з `await`, вам потрібно створити функцію операції шляху, що її використовує, з `async def`, як тут:\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### Більше технічних деталей { #more-technical-details }\n\nВи могли помітити, що `await` можна використовувати лише всередині функцій, визначених з `async def`.\n\nА водночас функції, визначені з `async def`, потрібно «очікувати». Тож функції з `async def` також можна викликати лише всередині функцій, визначених з `async def`.\n\nТож як же викликати першу `async`-функцію - курка чи яйце?\n\nЯкщо ви працюєте з **FastAPI**, вам не потрібно про це турбуватися, адже цією «першою» функцією буде ваша функція операції шляху, і FastAPI знатиме, як учинити правильно.\n\nАле якщо ви хочете використовувати `async` / `await` без FastAPI, ви також можете це зробити.\n\n### Пишемо свій власний async-код { #write-your-own-async-code }\n\nStarlette (і **FastAPI**) базуються на [AnyIO](https://anyio.readthedocs.io/en/stable/), що робить їх сумісними як зі стандартною бібліотекою Python [asyncio](https://docs.python.org/3/library/asyncio-task.html), так і з [Trio](https://trio.readthedocs.io/en/stable/).\n\nЗокрема, ви можете безпосередньо використовувати [AnyIO](https://anyio.readthedocs.io/en/stable/) для ваших просунутих сценаріїв рівночасності, що потребують складніших патернів у вашому коді.\n\nІ навіть якщо ви не використовували FastAPI, ви могли б писати свої власні async-застосунки з [AnyIO](https://anyio.readthedocs.io/en/stable/), щоб мати високу сумісність і отримати його переваги (наприклад, *структурована рівночасність*).\n\nЯ створив іншу бібліотеку поверх AnyIO, як тонкий шар, щоб дещо покращити анотації типів і отримати кращу **автодопомогу** (autocompletion), **вбудовані помилки** (inline errors) тощо. Вона також має дружній вступ і навчальний посібник, щоб допомогти вам **зрозуміти** і написати **власний async-код**: [Asyncer](https://asyncer.tiangolo.com/). Вона буде особливо корисною, якщо вам потрібно **поєднувати async-код зі звичайним** (блокуючим/синхронним) кодом.\n\n### Інші форми асинхронного коду { #other-forms-of-asynchronous-code }\n\nТакий стиль використання `async` і `await` відносно новий у мові.\n\nАле він значно полегшує роботу з асинхронним кодом.\n\nТакий самий (або майже ідентичний) синтаксис нещодавно з’явився в сучасних версіях JavaScript (у Browser і NodeJS).\n\nДо цього робота з асинхронним кодом була значно складнішою.\n\nУ попередніх версіях Python ви могли використовувати потоки (threads) або [Gevent](https://www.gevent.org/). Але код набагато складніший для розуміння, налагодження і мислення про нього.\n\nУ попередніх версіях NodeJS/Browser JavaScript ви б використовували «callbacks», що призводить до «callback hell».\n\n## Співпрограми { #coroutines }\n\n**Співпрограма** - це просто дуже вишукана назва для об’єкта, який повертає функція `async def`. Python знає, що це щось на кшталт функції, яку можна запустити і яка завершиться в певний момент, але яку також можна поставити на паузу ⏸ всередині, коли є `await`.\n\nАле всю цю функціональність використання асинхронного коду з `async` і `await` часто підсумовують як використання «співпрограм». Це порівняно з головною ключовою особливістю Go - «Goroutines».\n\n## Висновок { #conclusion }\n\nПогляньмо на ту саму фразу ще раз:\n\n> Сучасні версії Python мають підтримку «асинхронного коду» за допомогою так званих «співпрограм», з синтаксисом **`async` і `await`**.\n\nТепер це має більше сенсу. ✨\n\nУсе це приводить у дію FastAPI (через Starlette) і дає йому таку вражаючу продуктивність.\n\n## Дуже технічні деталі { #very-technical-details }\n\n/// warning | Попередження\n\nЙмовірно, ви можете пропустити це.\n\nЦе дуже технічні деталі про те, як **FastAPI** працює «під капотом».\n\nЯкщо у вас є чимало технічних знань (співпрограми, потоки, блокування тощо) і вам цікаво, як FastAPI обробляє `async def` проти звичайного `def`, - вперед.\n\n///\n\n### Функції операції шляху { #path-operation-functions }\n\nКоли ви оголошуєте функцію операції шляху зі звичайним `def` замість `async def`, вона виконується у зовнішньому пулі потоків (threadpool), який потім «очікується», замість прямого виклику (оскільки прямий виклик блокував би сервер).\n\nЯкщо ви прийшли з іншого async-фреймворку, який не працює так, як описано вище, і звикли визначати тривіальні, лише обчислювальні функції операції шляху зі звичайним `def` заради крихітного виграшу у продуктивності (близько 100 наносекунд), зверніть увагу, що у **FastAPI** ефект буде протилежним. У таких випадках краще використовувати `async def`, якщо тільки ваші функції операції шляху не використовують код, що виконує блокуюче <abbr title=\"Input/Output - Ввід/Вивід: читання або запис на диск, мережеві комунікації.\">I/O</abbr>.\n\nВтім, у будь-якій ситуації є велика ймовірність, що **FastAPI** [все одно буде швидшим](index.md#performance) (або принаймні порівнянним) за ваш попередній фреймворк.\n\n### Залежності { #dependencies }\n\nТе саме стосується і [залежностей](tutorial/dependencies/index.md). Якщо залежність є стандартною функцією `def` замість `async def`, вона виконується у зовнішньому пулі потоків.\n\n### Підзалежності { #sub-dependencies }\n\nВи можете мати кілька залежностей і [підзалежностей](tutorial/dependencies/sub-dependencies.md), які вимагають одна одну (як параметри визначень функцій). Деякі з них можуть бути створені з `async def`, а деякі - зі звичайним `def`. Все працюватиме, і ті, що створені зі звичайним `def`, будуть викликані у зовнішньому потоці (з пулу потоків), а не «очікувані».\n\n### Інші допоміжні функції { #other-utility-functions }\n\nБудь-яка інша допоміжна функція, яку ви викликаєте безпосередньо, може бути створена зі звичайним `def` або `async def`, і FastAPI не впливатиме на спосіб її виклику.\n\nЦе відрізняється від функцій, які FastAPI викликає за вас: функції операції шляху і залежності.\n\nЯкщо ваша допоміжна функція є звичайною функцією з `def`, її буде викликано безпосередньо (як ви написали у своєму коді), не в пулі потоків; якщо функція створена з `async def`, тоді вам слід використовувати `await` при її виклику у вашому коді.\n\n---\n\nЗнову ж таки, це дуже технічні деталі, які, ймовірно, стануть у пригоді, якщо ви спеціально їх шукали.\n\nІнакше вам вистачить настанов із розділу вище: <a href=\"#in-a-hurry\">Поспішаєте?</a>.\n"
  },
  {
    "path": "docs/uk/docs/benchmarks.md",
    "content": "# Бенчмарки { #benchmarks }\n\nНезалежні бенчмарки TechEmpower показують, що застосунки **FastAPI**, запущені під керуванням Uvicorn, є [одним із найшвидших доступних фреймворків Python](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), поступаючись лише самим Starlette і Uvicorn (використовуються FastAPI внутрішньо).\n\nАле переглядаючи бенчмарки та порівняння, майте на увазі таке.\n\n## Бенчмарки та швидкість { #benchmarks-and-speed }\n\nПід час перегляду бенчмарків часто порівнюють кілька інструментів різних типів як рівноцінні.\n\nЗокрема, разом порівнюють Uvicorn, Starlette і FastAPI (серед багатьох інших інструментів).\n\nЧим простіше завдання, яке розв'язує інструмент, тим кращою буде продуктивність. І більшість бенчмарків не перевіряють додаткові можливості, що надає інструмент.\n\nІєрархія приблизно така:\n\n* **Uvicorn**: сервер ASGI\n    * **Starlette**: (використовує Uvicorn) веб-мікрофреймворк\n        * **FastAPI**: (використовує Starlette) мікрофреймворк для API з низкою додаткових можливостей для створення API, з валідацією даних тощо.\n\n* **Uvicorn**:\n    * Матиме найвищу продуктивність, адже майже не містить додаткового коду окрім власне сервера.\n    * Ви не писатимете застосунок безпосередньо на Uvicorn. Це означало б, що ваш код мав би включати принаймні приблизно весь код, який надає Starlette (або **FastAPI**). І якщо зробити так, ваш кінцевий застосунок матиме ті самі накладні витрати, що й під час використання фреймворку, який мінімізує код застосунку та помилки.\n    * Якщо ви порівнюєте Uvicorn, порівнюйте його з Daphne, Hypercorn, uWSGI тощо. Сервери застосунків.\n* **Starlette**:\n    * Матиме наступну за швидкістю продуктивність після Uvicorn. Насправді Starlette використовує Uvicorn для запуску. Тож вона може бути «повільнішою» за Uvicorn лише через необхідність виконувати більше коду.\n    * Але надає інструменти для створення простих веб-застосунків із маршрутизацією на основі шляхів тощо.\n    * Якщо ви порівнюєте Starlette, порівнюйте її з Sanic, Flask, Django тощо. Веб-фреймворки (або мікрофреймворки).\n* **FastAPI**:\n    * Аналогічно до того, як Starlette використовує Uvicorn і не може бути швидшою за нього, **FastAPI** використовує Starlette, тож не може бути швидшою за неї.\n    * FastAPI надає більше можливостей поверх Starlette. Можливості, які майже завжди потрібні під час створення API, як-от валідація та серіалізація даних. І, використовуючи його, ви безкоштовно отримуєте автоматичну документацію (автоматична документація навіть не додає накладних витрат під час роботи застосунку - вона генерується під час запуску).\n    * Якби ви не використовували FastAPI і застосували Starlette безпосередньо (або інший інструмент, наприклад Sanic, Flask, Responder тощо), вам довелося б самостійно реалізувати всю валідацію та серіалізацію даних. Тож ваш кінцевий застосунок усе одно мав би ті самі накладні витрати, ніби він був створений із використанням FastAPI. І в багатьох випадках саме ця валідація та серіалізація даних становить найбільший обсяг коду в застосунках.\n    * Отже, використовуючи FastAPI, ви заощаджуєте час розробки, зменшуєте кількість помилок і рядків коду та, ймовірно, отримуєте таку саму (або кращу) продуктивність, як і без нього (адже інакше вам довелося б реалізувати все це у власному коді).\n    * Якщо ви порівнюєте FastAPI, порівнюйте його з веб-фреймворком (або набором інструментів), який надає валідацію даних, серіалізацію та документацію, наприклад Flask-apispec, NestJS, Molten тощо. Фреймворки з вбудованою автоматичною валідацією даних, серіалізацією та документацією.\n"
  },
  {
    "path": "docs/uk/docs/deployment/cloud.md",
    "content": "# Розгортання FastAPI у хмарних постачальників { #deploy-fastapi-on-cloud-providers }\n\nВи можете використовувати практично **будь-якого хмарного постачальника**, щоб розгорнути свій застосунок FastAPI.\n\nУ більшості випадків основні хмарні постачальники мають інструкції з розгортання FastAPI у них.\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** створено тим самим автором і командою, що стоять за **FastAPI**.\n\nВоно спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.\n\nВоно переносить той самий **досвід розробника** зі створення застосунків із FastAPI на їх **розгортання** у хмарі. 🎉\n\nFastAPI Cloud є основним спонсором і джерелом фінансування проєктів з відкритим кодом *FastAPI and friends*. ✨\n\n## Хмарні постачальники - спонсори { #cloud-providers-sponsors }\n\nДеякі інші хмарні постачальники ✨ [**спонсорують FastAPI**](../help-fastapi.md#sponsor-the-author) ✨ також. 🙇\n\nМожливо, ви захочете розглянути їх, щоб дотримуватися їхніх інструкцій і спробувати їхні сервіси:\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/uk/docs/deployment/concepts.md",
    "content": "# Концепції розгортання { #deployments-concepts }\n\nПід час розгортання застосунку **FastAPI** (або будь-якого веб-API) є кілька концепцій, які, ймовірно, вас цікавлять, і, спираючись на них, ви зможете знайти **найвідповідніший** спосіб **розгорнути ваш застосунок**.\n\nДеякі важливі концепції:\n\n- Безпека - HTTPS\n- Запуск під час старту\n- Перезапуски\n- Реплікація (кількість запущених процесів)\n- Пам'ять\n- Попередні кроки перед стартом\n\nПодивимось, як вони впливають на **розгортання**.\n\nЗрештою головна мета - **обслуговувати клієнтів вашого API** так, щоб це було **безпечним**, з **мінімумом перерв у роботі**, і щоб **обчислювальні ресурси** (наприклад, віддалені сервери/віртуальні машини) використовувалися якомога ефективніше. 🚀\n\nНижче я трохи більше розповім про ці **концепції**, і, сподіваюся, це дасть вам потрібну **інтуїцію**, щоб вирішувати, як розгортати ваш API в дуже різних середовищах, можливо, навіть у **майбутніх**, яких ще не існує.\n\nВраховуючи ці концепції, ви зможете **оцінювати та проєктувати** найкращий спосіб розгортання **ваших власних API**.\n\nУ наступних розділах я наведу більш **конкретні рецепти** розгортання застосунків FastAPI.\n\nА поки перегляньмо ці важливі **концептуальні ідеї**. Вони також застосовні до будь-якого іншого типу веб-API. 💡\n\n## Безпека - HTTPS { #security-https }\n\nУ [попередньому розділі про HTTPS](https.md) ми дізналися, як HTTPS забезпечує шифрування для вашого API.\n\nМи також бачили, що HTTPS зазвичай надається компонентом, **зовнішнім** щодо вашого серверного застосунку, - **TLS Termination Proxy**.\n\nІ має бути щось, що відповідає за **оновлення сертифікатів HTTPS** - це може бути той самий компонент або інший.\n\n### Приклади інструментів для HTTPS { #example-tools-for-https }\n\nДеякі інструменти, які можна використовувати як TLS Termination Proxy:\n\n- Traefik\n    - Автоматично обробляє оновлення сертифікатів ✨\n- Caddy\n    - Автоматично обробляє оновлення сертифікатів ✨\n- Nginx\n    - З зовнішнім компонентом на кшталт Certbot для оновлення сертифікатів\n- HAProxy\n    - З зовнішнім компонентом на кшталт Certbot для оновлення сертифікатів\n- Kubernetes з Ingress Controller, наприклад Nginx\n    - З зовнішнім компонентом на кшталт cert-manager для оновлення сертифікатів\n- Обробляється внутрішньо хмарним провайдером як частина їхніх сервісів (див. нижче 👇)\n\nЩе один варіант - використати **хмарний сервіс**, який зробить більше роботи, зокрема налаштує HTTPS. Можуть бути обмеження або додаткова вартість тощо. Але у такому разі вам не потрібно самостійно налаштовувати TLS Termination Proxy.\n\nУ наступних розділах я покажу кілька конкретних прикладів.\n\n---\n\nДалі всі наступні концепції стосуються програми, яка запускає ваш фактичний API (наприклад, Uvicorn).\n\n## Програма і процес { #program-and-process }\n\nМи багато говоритимемо про запущений «процес», тож корисно чітко розуміти, що це означає, і чим відрізняється від слова «програма».\n\n### Що таке програма { #what-is-a-program }\n\nСлово **програма** зазвичай вживають для опису багатьох речей:\n\n- **Код**, який ви пишете, **файли Python**.\n- **Файл**, який може бути **виконаний** операційною системою, наприклад: `python`, `python.exe` або `uvicorn`.\n- Конкретна програма під час **виконання** в операційній системі, що використовує CPU та зберігає дані в пам'яті. Це також називають **процесом**.\n\n### Що таке процес { #what-is-a-process }\n\nСлово **процес** зазвичай використовують у більш специфічному значенні, маючи на увазі саме те, що виконується в операційній системі (як у попередньому пункті):\n\n- Конкретна програма під час **виконання** в операційній системі.\n    - Це не про файл і не про код, це **конкретно** про те, що **виконується** та керується операційною системою.\n- Будь-яка програма, будь-який код **може щось робити** лише під час **виконання**. Тобто коли **процес запущений**.\n- Процес може бути **завершений** (або «kill») вами чи операційною системою. У цей момент він припиняє виконання і **більше нічого не може робити**.\n- Кожен застосунок, який працює на вашому комп'ютері, має певний процес за собою: кожна запущена програма, кожне вікно тощо. Зазвичай на комп'ютері одночасно працює **багато процесів**.\n- **Кілька процесів** **однієї й тієї самої програми** можуть працювати одночасно.\n\nЯкщо ви відкриєте «диспетчер завдань» або «системний монітор» (чи подібні інструменти) в операційній системі, ви побачите багато таких процесів.\n\nНаприклад, ви, ймовірно, побачите кілька процесів того самого браузера (Firefox, Chrome, Edge тощо). Зазвичай він запускає один процес на вкладку плюс деякі додаткові процеси.\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\nТепер, коли ми знаємо різницю між термінами **процес** і **програма**, продовжимо говорити про розгортання.\n\n## Запуск під час старту { #running-on-startup }\n\nУ більшості випадків, коли ви створюєте веб-API, ви хочете, щоб він **працював постійно**, без перерв, щоб клієнти завжди мали до нього доступ. Звісно, якщо немає особливих причин запускати його лише в певних ситуаціях. Але зазвичай ви хочете, щоб він постійно працював і був **доступний**.\n\n### На віддаленому сервері { #in-a-remote-server }\n\nКоли ви налаштовуєте віддалений сервер (хмарний сервер, віртуальну машину тощо), найпростіше - використовувати `fastapi run` (який використовує Uvicorn) або щось схоже, вручну, так само, як під час локальної розробки.\n\nІ це працюватиме та буде корисним **під час розробки**.\n\nАле якщо ви втратите з'єднання з сервером, **запущений процес**, найімовірніше, завершиться.\n\nІ якщо сервер буде перезавантажено (наприклад, після оновлень або міграцій у хмарного провайдера), ви, ймовірно, **не помітите цього**. І через це ви навіть не знатимете, що треба вручну перезапустити процес. У результаті ваш API просто залишиться «мертвим». 😱\n\n### Автоматичний запуск під час старту { #run-automatically-on-startup }\n\nЗагалом ви, напевно, захочете, щоб серверна програма (наприклад, Uvicorn) запускалася автоматично під час старту сервера і без будь-якого **людського втручання**, щоб завжди був запущений процес із вашим API (наприклад, Uvicorn із вашим FastAPI-застосунком).\n\n### Окрема програма { #separate-program }\n\nЩоб цього досягти, зазвичай використовують **окрему програму**, яка гарантує запуск вашого застосунку під час старту. І в багатьох випадках вона також забезпечує запуск інших компонентів або застосунків, наприклад бази даних.\n\n### Приклади інструментів для запуску під час старту { #example-tools-to-run-at-startup }\n\nПриклади інструментів, які можуть це робити:\n\n- Docker\n- Kubernetes\n- Docker Compose\n- Docker у режимі Swarm\n- Systemd\n- Supervisor\n- Обробляється внутрішньо хмарним провайдером як частина їхніх сервісів\n- Інші...\n\nУ наступних розділах я наведу більш конкретні приклади.\n\n## Перезапуски { #restarts }\n\nПодібно до забезпечення запуску застосунку під час старту системи, ви, ймовірно, також захочете гарантувати його **перезапуск** після збоїв.\n\n### Ми помиляємося { #we-make-mistakes }\n\nМи, люди, постійно робимо **помилки**. Майже завжди у програмному забезпеченні є приховані **помилки**. 🐛\n\nІ ми як розробники постійно покращуємо код, знаходячи ці помилки та додаючи нові можливості (можливо, теж додаючи нові помилки 😅).\n\n### Невеликі помилки обробляються автоматично { #small-errors-automatically-handled }\n\nСтворюючи веб-API з FastAPI, якщо в нашому коді є помилка, FastAPI зазвичай обмежує її одним запитом, який цю помилку спровокував. 🛡\n\nКлієнт отримає **500 Internal Server Error** для цього запиту, але застосунок продовжить працювати для наступних запитів замість повного краху.\n\n### Великі помилки - крахи { #bigger-errors-crashes }\n\nВтім, бувають випадки, коли ми пишемо код, який **падає весь застосунок**, спричиняючи крах Uvicorn і Python. 💥\n\nІ все ж ви, ймовірно, не захочете, щоб застосунок залишався «мертвим» через помилку в одному місці - ви, напевно, хочете, щоб він **продовжував працювати** принаймні для тих *операцій шляху*, що не зламані.\n\n### Перезапуск після краху { #restart-after-crash }\n\nАле в таких випадках із серйозними помилками, що призводять до краху запущеного **процесу**, потрібен зовнішній компонент, відповідальний за **перезапуск** процесу, принаймні кілька разів...\n\n/// tip | Порада\n\n...Хоча якщо весь застосунок просто **миттєво падає**, безглуздо перезапускати його безкінечно. Але в таких випадках ви, ймовірно, помітите це під час розробки або принаймні відразу після розгортання.\n\nТож зосередьмося на основних випадках, коли у майбутньому він може повністю падати за певних обставин, і тоді все ще має сенс його перезапускати.\n\n///\n\nЙмовірно, ви захочете мати відокремлений **зовнішній компонент**, який відповідає за перезапуск застосунку, адже до того моменту сам застосунок з Uvicorn і Python уже впав, і нічого в тому ж коді цієї ж програми зробити не зможе.\n\n### Приклади інструментів для автоматичного перезапуску { #example-tools-to-restart-automatically }\n\nУ більшості випадків той самий інструмент, який використовується для **запуску програми під час старту**, також використовується для автоматичних **перезапусків**.\n\nНаприклад, це можуть забезпечувати:\n\n- Docker\n- Kubernetes\n- Docker Compose\n- Docker у режимі Swarm\n- Systemd\n- Supervisor\n- Обробляється внутрішньо хмарним провайдером як частина їхніх сервісів\n- Інші...\n\n## Реплікація - процеси та пам'ять { #replication-processes-and-memory }\n\nУ застосунку FastAPI, використовуючи серверну програму, як-от команду `fastapi`, що запускає Uvicorn, один запуск в **одному процесі** може обслуговувати кількох клієнтів рівночасно.\n\nАле часто ви захочете запускати кілька процесів-працівників одночасно.\n\n### Кілька процесів - працівники { #multiple-processes-workers }\n\nЯкщо у вас більше клієнтів, ніж може обробити один процес (наприклад, якщо віртуальна машина не надто потужна) і на сервері є **кілька ядер** CPU, тоді ви можете запустити **кілька процесів** із тим самим застосунком паралельно і розподіляти запити між ними.\n\nКоли ви запускаєте **кілька процесів** того самого програмного забезпечення API, їх зазвичай називають **працівниками** (workers).\n\n### Процеси-працівники і порти { #worker-processes-and-ports }\n\nПам'ятаєте з документації [Про HTTPS](https.md), що на сервері лише один процес може слухати певну комбінацію порту та IP-адреси?\n\nЭто досі так.\n\nОтже, щоб мати **кілька процесів** одночасно, має бути **єдиний процес, який слухає порт**, і який далі якимось чином передає комунікацію кожному процесу-працівнику.\n\n### Пам'ять на процес { #memory-per-process }\n\nКоли програма завантажує щось у пам'ять, наприклад модель машинного навчання в змінну або вміст великого файлу в змінну, все це **споживає частину пам'яті (RAM)** сервера.\n\nІ кілька процесів зазвичай **не діляться пам'яттю**. Це означає, що кожен запущений процес має власні речі, змінні та пам'ять. І якщо у вашому коді споживається багато пам'яті, **кожен процес** споживатиме еквівалентний обсяг пам'яті.\n\n### Пам'ять сервера { #server-memory }\n\nНаприклад, якщо ваш код завантажує модель машинного навчання розміром **1 GB**, то при запуску одного процесу з вашим API він споживатиме щонайменше 1 GB RAM. А якщо ви запустите **4 процеси** (4 працівники) - кожен споживатиме 1 GB RAM. Отже, загалом ваш API споживатиме **4 GB RAM**.\n\nІ якщо ваш віддалений сервер або віртуальна машина має лише 3 GB RAM, спроба використати понад 4 GB призведе до проблем. 🚨\n\n### Кілька процесів - приклад { #multiple-processes-an-example }\n\nУ цьому прикладі є **керівний процес** (Manager Process), який запускає і контролює два **процеси-працівники**.\n\nЦей керівний процес, імовірно, саме і слухатиме **порт** на IP. І він передаватиме всю комунікацію процесам-працівникам.\n\nЦі процеси-працівники виконуватимуть ваш застосунок, здійснюватимуть основні обчислення, щоб отримати **запит** і повернути **відповідь**, і завантажуватимуть усе, що ви зберігаєте в змінних у RAM.\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\nЗвісно, на тій самій машині, окрім вашого застосунку, зазвичай працюватимуть **інші процеси**.\n\nЦікавий момент: відсоток **використання CPU** кожним процесом може сильно **варіюватися** з часом, тоді як **пам'ять (RAM)** зазвичай залишається більш-менш **стабільною**.\n\nЯкщо у вас API, що виконує порівняний обсяг обчислень щоразу і у вас багато клієнтів, тоді **використання CPU** також, ймовірно, буде *стабільним* (замість постійних швидких коливань).\n\n### Приклади інструментів і стратегій реплікації { #examples-of-replication-tools-and-strategies }\n\nЄ кілька підходів для цього, і про конкретні стратегії я розповім у наступних розділах, наприклад, коли говоритимемо про Docker і контейнери.\n\nГоловне обмеження: має бути **єдиний** компонент, що обробляє **порт** на **публічній IP-адресі**. А тоді він має мати спосіб **передавати** комунікацію реплікованим **процесам/працівникам**.\n\nОсь кілька можливих комбінацій і стратегій:\n\n- **Uvicorn** з `--workers`\n    - Один **менеджер процесів** Uvicorn слухатиме **IP** і **порт** та запускатиме **кілька процесів-працівників Uvicorn**.\n- **Kubernetes** та інші розподілені **системи контейнерів**\n    - Щось на рівні **Kubernetes** слухатиме **IP** і **порт**. Реплікація відбуватиметься через **кілька контейнерів**, у кожному з яких запущено **один процес Uvicorn**.\n- **Хмарні сервіси**, що роблять це за вас\n    - Хмарний сервіс, ймовірно, **забезпечить реплікацію за вас**. Він може дозволяти визначити **процес для запуску** або **образ контейнера** для використання; у будь-якому разі це, найімовірніше, буде **один процес Uvicorn**, а сервіс відповідатиме за його реплікацію.\n\n/// tip | Порада\n\nНе хвилюйтеся, якщо деякі пункти про **контейнери**, Docker чи Kubernetes поки що не дуже зрозумілі.\n\nЯ розповім більше про образи контейнерів, Docker, Kubernetes тощо в майбутньому розділі: [FastAPI у контейнерах - Docker](docker.md).\n\n///\n\n## Попередні кроки перед стартом { #previous-steps-before-starting }\n\nЄ багато випадків, коли потрібно виконати деякі кроки **перед стартом** вашого застосунку.\n\nНаприклад, ви можете захотіти запустити **міграції бази даних**.\n\nАле найчастіше ці кроки потрібно виконувати лише **один раз**.\n\nОтже, ви захочете мати **єдиний процес**, який виконає ці **попередні кроки** перед запуском застосунку.\n\nІ потрібно переконатися, що їх виконує саме один процес навіть якщо потім ви запускаєте **кілька процесів** (кілька працівників) для самого застосунку. Якщо ці кроки виконуватимуться **кількома процесами**, вони **подвоюватимуть** роботу, виконуючи її **паралельно**, і якщо кроки делікатні, як-от міграції бази даних, це може призвести до конфліктів.\n\nЗвісно, бувають випадки, коли немає проблеми запускати попередні кроки кілька разів - тоді все набагато простіше.\n\n/// tip | Порада\n\nТакож майте на увазі, що залежно від вашого налаштування інколи **попередні кроки взагалі не потрібні** перед запуском застосунку.\n\nУ такому разі про це можна не турбуватися. 🤷\n\n///\n\n### Приклади стратегій попередніх кроків { #examples-of-previous-steps-strategies }\n\nЦе **значною мірою залежить** від способу **розгортання вашої системи** і, ймовірно, буде пов'язано зі способом запуску програм, обробки перезапусків тощо.\n\nОсь кілька можливих ідей:\n\n- «Init Container» у Kubernetes, який виконується перед вашим контейнером застосунку\n- bash-скрипт, який виконує попередні кроки, а потім запускає ваш застосунок\n    - Вам усе одно потрібен спосіб запускати/перезапускати цей bash-скрипт, виявляти помилки тощо.\n\n/// tip | Порада\n\nЯ наведу більш конкретні приклади для цього з контейнерами у майбутньому розділі: [FastAPI у контейнерах - Docker](docker.md).\n\n///\n\n## Використання ресурсів { #resource-utilization }\n\nВаш сервер(и) - це **ресурс**, який ви можете споживати/**використовувати** вашими програмами: час обчислень на CPU та доступну RAM.\n\nСкільки системних ресурсів ви хочете споживати/використовувати? Легко подумати «небагато», але насправді ви, ймовірно, захочете споживати **настільки багато, наскільки можливо без краху**.\n\nЯкщо ви платите за 3 сервери, але використовуєте лише трохи їх RAM і CPU, ви, ймовірно, **марнуєте гроші** 💸 і, можливо, **електроенергію серверів** 🌎 тощо.\n\nУ такому разі може бути краще мати лише 2 сервери й використовувати більший відсоток їхніх ресурсів (CPU, пам'ять, диск, пропускну здатність мережі тощо).\n\nЗ іншого боку, якщо у вас 2 сервери і ви використовуєте **100% їхнього CPU та RAM**, у певний момент якийсь процес попросить більше пам'яті, і сервер муситиме використати диск як «пам'ять» (що може бути у тисячі разів повільнішим) або навіть **впасти**. Або процесу знадобляться обчислення, і він чекатиме, доки CPU знову звільниться.\n\nУ цьому випадку краще додати **ще один сервер** і запустити частину процесів на ньому, щоб у всіх було **достатньо RAM та часу CPU**.\n\nТакож можлива ситуація, коли з певної причини ви отримаєте **стрибок** використання вашого API. Можливо, він став вірусним або його почали використовувати інші сервіси чи боти. І ви можете захотіти мати додаткові ресурси на випадок таких ситуацій.\n\nВи можете встановити **довільний цільовий** рівень, наприклад, **між 50% і 90%** використання ресурсів. Суть у тому, що це, ймовірно, головні речі, які ви захочете вимірювати й використовувати для налаштування розгортань.\n\nВи можете використати прості інструменти, як-от `htop`, щоб побачити використання CPU і RAM на сервері або кількість, спожиту кожним процесом. Або складніші засоби моніторингу, розподілені між серверами тощо.\n\n## Підсумок { #recap }\n\nТут ви прочитали про основні концепції, які, ймовірно, потрібно тримати в голові, вирішуючи, як розгортати ваш застосунок:\n\n- Безпека - HTTPS\n- Запуск під час старту\n- Перезапуски\n- Реплікація (кількість запущених процесів)\n- Пам'ять\n- Попередні кроки перед стартом\n\nРозуміння цих ідей і того, як їх застосовувати, має дати вам інтуїцію, необхідну для прийняття рішень під час конфігурування і тонкого налаштування ваших розгортань. 🤓\n\nУ наступних розділах я наведу більше конкретних прикладів можливих стратегій, якими ви можете скористатися. 🚀\n"
  },
  {
    "path": "docs/uk/docs/deployment/docker.md",
    "content": "# FastAPI у контейнерах - Docker { #fastapi-in-containers-docker }\n\nПід час розгортання застосунків FastAPI поширений підхід - збирати образи контейнерів Linux. Зазвичай це робиться за допомогою [Docker](https://www.docker.com/). Потім ви можете розгорнути цей образ контейнера кількома різними способами.\n\nВикористання контейнерів Linux має кілька переваг, зокрема безпека, відтворюваність, простота та інші.\n\n/// tip | Порада\n\nПоспішаєте і вже все це знаєте? Перейдіть до [`Dockerfile` нижче 👇](#build-a-docker-image-for-fastapi).\n\n///\n\n<details>\n<summary>Попередній перегляд Dockerfile 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# Якщо запускаєте за представником на кшталт Nginx або Traefik, додайте --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## Що таке контейнер { #what-is-a-container }\n\nКонтейнери (переважно контейнери Linux) - це дуже легкий спосіб упакувати застосунки з усіма їхніми залежностями та потрібними файлами, ізолювавши їх від інших контейнерів (інших застосунків або компонентів) у тій самій системі.\n\nКонтейнери Linux працюють, використовуючи той самий ядро Linux, що й хост (машина, віртуальна машина, хмарний сервер тощо). Це означає, що вони дуже легкі (у порівнянні з повними віртуальними машинами, які емулюють цілу операційну систему).\n\nТаким чином контейнери споживають мало ресурсів, приблизно як безпосередньо запущені процеси (віртуальна машина споживала б значно більше).\n\nУ контейнерів також є власні ізольовані процеси виконання (зазвичай лише один процес), файлові системи та мережі, що спрощує розгортання, безпеку, розробку тощо.\n\n## Що таке образ контейнера { #what-is-a-container-image }\n\nКонтейнер запускається з образу контейнера.\n\nОбраз контейнера - це статична версія всіх файлів, змінних оточення та типова команда/програма, яка має бути присутня в контейнері. Тут «статична» означає, що образ контейнера не запущений, він не виконується, це лише упаковані файли та метадані.\n\nНа противагу «образу контейнера», що є збереженим статичним вмістом, «контейнер» зазвичай означає запущений екземпляр, те, що виконується.\n\nКоли контейнер запущено (запущений з образу контейнера), він може створювати або змінювати файли, змінні оточення тощо. Ці зміни існуватимуть лише в цьому контейнері, але не збережуться в базовому образі контейнера (не будуть записані на диск).\n\nОбраз контейнера можна порівняти з файлом і вмістом програми, наприклад `python` і файлом `main.py`.\n\nА сам контейнер (на відміну від образу) - це фактично запущений екземпляр образу, порівнянний із процесом. Насправді контейнер працює лише тоді, коли в ньому працює процес (і зазвичай це один процес). Контейнер зупиняється, коли в ньому не працює жоден процес.\n\n## Образи контейнерів { #container-images }\n\nDocker був одним з основних інструментів для створення та керування образами контейнерів і контейнерами.\n\nІснує публічний [Docker Hub](https://hub.docker.com/) з готовими офіційними образами для багатьох інструментів, середовищ, баз даних і застосунків.\n\nНаприклад, є офіційний [образ Python](https://hub.docker.com/_/python).\n\nІ є багато інших образів для різних речей, як-от бази даних, наприклад для:\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis) тощо.\n\nВикористовуючи готовий образ контейнера, дуже легко поєднувати та використовувати різні інструменти. Наприклад, щоб випробувати нову базу даних. У більшості випадків ви можете використати офіційні образи та просто налаштувати їх змінними оточення.\n\nТаким чином, у багатьох випадках ви зможете навчитися працювати з контейнерами і Docker та повторно використати ці знання з багатьма різними інструментами і компонентами.\n\nТобто ви запускатимете кілька контейнерів з різними речами, як-от базу даних, застосунок на Python, вебсервер із фронтендом на React, і з’єднаєте їх через внутрішню мережу.\n\nУсі системи керування контейнерами (як Docker чи Kubernetes) мають ці мережеві можливості вбудовано.\n\n## Контейнери і процеси { #containers-and-processes }\n\nОбраз контейнера зазвичай містить у своїх метаданих типову програму або команду, яку слід виконати під час запуску контейнера, і параметри для цієї програми. Дуже схоже на те, що ви б виконали в командному рядку.\n\nКоли контейнер запускається, він виконає цю команду/програму (хоча ви можете перевизначити її і запустити іншу команду/програму).\n\nКонтейнер працює доти, доки працює головний процес (команда або програма).\n\nЗазвичай контейнер має один процес, але також можливо запускати підпроцеси з головного процесу, і таким чином у вас може бути кілька процесів у тому самому контейнері.\n\nАле неможливо мати запущений контейнер без принаймні одного запущеного процесу. Якщо головний процес зупиняється, контейнер зупиняється.\n\n## Зібрати Docker-образ для FastAPI { #build-a-docker-image-for-fastapi }\n\nГаразд, зберімо щось зараз! 🚀\n\nЯ покажу вам, як зібрати образ Docker для FastAPI з нуля на основі офіційного образу Python.\n\nЦе те, що ви захочете робити у більшості випадків, наприклад:\n\n* Використання Kubernetes або подібних інструментів\n* Під час запуску на Raspberry Pi\n* Використання хмарного сервісу, який запустить для вас образ контейнера тощо\n\n### Вимоги до пакетів { #package-requirements }\n\nЗазвичай ви маєте вимоги до пакетів для вашого застосунку в окремому файлі.\n\nЦе залежить переважно від інструменту, який ви використовуєте для встановлення цих вимог.\n\nНайпоширеніший спосіб - мати файл `requirements.txt` з назвами пакетів і їхніми версіями, по одному на рядок.\n\nЗвісно, ви застосуєте ті самі ідеї з [Про версії FastAPI](versions.md), щоб задати діапазони версій.\n\nНаприклад, ваш `requirements.txt` може виглядати так:\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\nІ зазвичай ви встановлюватимете ці залежності пакетів через `pip`, наприклад:\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info | Інформація\n\nІснують інші формати та інструменти для визначення і встановлення залежностей пакетів.\n\n///\n\n### Створіть код **FastAPI** { #create-the-fastapi-code }\n\n* Створіть директорію `app` і перейдіть у неї.\n* Створіть порожній файл `__init__.py`.\n* Створіть файл `main.py` з вмістом:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\nТепер у тій самій директорії проєкту створіть файл `Dockerfile` з вмістом:\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. Почніть з офіційного базового образу Python.\n\n2. Встановіть поточну робочу директорію в `/code`.\n\n    Саме сюди ми помістимо файл `requirements.txt` і директорію `app`.\n\n3. Скопіюйте файл з вимогами в директорію `/code`.\n\n    Спочатку скопіюйте лише файл з вимогами, а не решту коду.\n\n    Оскільки цей файл змінюється нечасто, Docker виявить це і використає кеш для цього кроку, що також увімкне кеш і для наступного кроку.\n\n4. Встановіть залежності пакетів із файлу вимог.\n\n    Опція `--no-cache-dir` каже `pip` не зберігати завантажені пакети локально, адже це потрібно лише тоді, якщо `pip` буде запущено знову для встановлення тих самих пакетів, але в роботі з контейнерами це не так.\n\n    /// note | Примітка\n\n    `--no-cache-dir` стосується лише `pip`, це не має відношення до Docker чи контейнерів.\n\n    ///\n\n    Опція `--upgrade` каже `pip` оновити пакети, якщо вони вже встановлені.\n\n    Оскільки попередній крок копіювання файлу може бути виявлений кешем Docker, цей крок також використовуватиме кеш Docker, коли це можливо.\n\n    Використання кешу на цьому кроці збереже вам багато часу під час повторних збірок образу в розробці, замість того щоб завжди завантажувати і встановлювати всі залежності.\n\n5. Скопіюйте директорію `./app` у директорію `/code`.\n\n    Оскільки тут увесь код, який змінюється найчастіше, кеш Docker не буде легко використаний для цього або будь-яких наступних кроків.\n\n    Тому важливо розмістити це ближче до кінця `Dockerfile`, щоб оптимізувати час збірки образу контейнера.\n\n6. Встановіть команду для використання `fastapi run`, яка всередині використовує Uvicorn.\n\n    `CMD` приймає список строк, кожна з яких - це те, що ви б набирали в командному рядку, розділене пробілами.\n\n    Ця команда буде виконана з поточної робочої директорії, тієї самої `/code`, яку ви вказали вище через `WORKDIR /code`.\n\n/// tip | Порада\n\nПерегляньте, що робить кожен рядок, клацнувши на кожну номерну позначку в коді. 👆\n\n///\n\n/// warning | Попередження\n\nОбов’язково завжди використовуйте exec form інструкції `CMD`, як пояснено нижче.\n\n///\n\n#### Використовуйте `CMD` - exec form { #use-cmd-exec-form }\n\nІнструкцію Docker [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) можна записати у двох формах:\n\n✅ Exec form:\n\n```Dockerfile\n# ✅ Робіть так\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ Shell form:\n\n```Dockerfile\n# ⛔️ Не робіть так\nCMD fastapi run app/main.py --port 80\n```\n\nОбов’язково завжди використовуйте exec form, щоб FastAPI міг коректно завершувати роботу та щоб були викликані [події тривалості життя](../advanced/events.md).\n\nДокладніше про це можна прочитати в [документації Docker про shell та exec form](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).\n\nЦе може бути особливо помітно при використанні `docker compose`. Див. розділ FAQ Docker Compose для технічних деталей: [Чому мої сервіси потребують 10 секунд, щоб пересотворитися або зупинитися?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).\n\n#### Структура директорій { #directory-structure }\n\nЗараз у вас має бути така структура директорій:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### За представником з термінацією TLS { #behind-a-tls-termination-proxy }\n\nЯкщо ви запускаєте контейнер за представником з термінацією TLS (балансувальником навантаження), наприклад Nginx або Traefik, додайте опцію `--proxy-headers`. Це скаже Uvicorn (через CLI FastAPI) довіряти заголовкам, що надсилаються цим представником, які вказують, що застосунок працює за HTTPS тощо.\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Кеш Docker { #docker-cache }\n\nУ цьому `Dockerfile` є важливий трюк: спочатку ми копіюємо лише файл із залежностями, а не решту коду. Ось чому.\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker та інші інструменти збирають ці образи контейнерів інкрементально, додаючи один шар поверх іншого, починаючи з верхньої частини `Dockerfile` і додаючи будь-які файли, створені кожною інструкцією в `Dockerfile`.\n\nDocker та подібні інструменти також використовують внутрішній кеш під час збірки образу. Якщо файл не змінювався з моменту останньої збірки, тоді він повторно використає той самий шар, створений востаннє, замість копіювання файлу знову та створення нового шару з нуля.\n\nПросте уникнення копіювання файлів не обов’язково суттєво покращує ситуацію, але оскільки для цього кроку використано кеш, він може використати кеш і для наступного кроку. Наприклад, він може використати кеш для інструкції, яка встановлює залежності:\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\nФайл із вимогами до пакетів змінюватиметься нечасто. Отже, копіюючи лише цей файл, Docker зможе використати кеш для цього кроку.\n\nА потім Docker зможе використати кеш і для наступного кроку, який завантажує та встановлює ці залежності. І саме тут ми заощаджуємо багато часу. ✨ ...і уникаємо нудного очікування. 😪😆\n\nЗавантаження і встановлення залежностей пакетів може займати хвилини, але використання кешу займе максимум секунди.\n\nІ оскільки ви збиратимете образ контейнера знову і знову під час розробки, щоб перевіряти, що зміни у вашому коді працюють, це заощадить багато накопиченого часу.\n\nПотім, ближче до кінця `Dockerfile`, ми копіюємо весь код. Оскільки це те, що змінюється найчастіше, ми розміщуємо це ближче до кінця, адже майже завжди все після цього кроку не зможе використати кеш.\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### Зберіть Docker-образ { #build-the-docker-image }\n\nТепер, коли всі файли на місці, зберімо образ контейнера.\n\n* Перейдіть у директорію проєкту (де ваш `Dockerfile`, який містить директорію `app`).\n* Зберіть ваш образ FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | Порада\n\nЗверніть увагу на `.` в кінці. Це еквівалент `./`. Воно каже Docker, яку директорію використовувати для збірки образу контейнера.\n\nУ цьому випадку - це поточна директорія (`.`).\n\n///\n\n### Запустіть Docker-контейнер { #start-the-docker-container }\n\n* Запустіть контейнер на основі вашого образу:\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## Перевірте { #check-it }\n\nВи маєте змогу перевірити це за URL вашого Docker-контейнера, наприклад: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) або [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (або еквівалент, використовуючи ваш Docker-хост).\n\nВи побачите щось таке:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## Інтерактивна документація API { #interactive-api-docs }\n\nТепер ви можете перейти на [http://192.168.99.100/docs](http://192.168.99.100/docs) або [http://127.0.0.1/docs](http://127.0.0.1/docs) (або еквівалент, використовуючи ваш Docker-хост).\n\nВи побачите автоматичну інтерактивну документацію API (надається [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## Альтернативна документація API { #alternative-api-docs }\n\nТакож ви можете перейти на [http://192.168.99.100/redoc](http://192.168.99.100/redoc) або [http://127.0.0.1/redoc](http://127.0.0.1/redoc) (або еквівалент, використовуючи ваш Docker-хост).\n\nВи побачите альтернативну автоматичну документацію (надається [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Збірка Docker-образу з FastAPI в одному файлі { #build-a-docker-image-with-a-single-file-fastapi }\n\nЯкщо ваш FastAPI - це один файл, наприклад `main.py` без директорії `./app`, структура файлів може виглядати так:\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\nТоді вам потрібно лише змінити відповідні шляхи для копіювання файлу всередині `Dockerfile`:\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. Скопіюйте файл `main.py` безпосередньо у директорію `/code` (без будь-якої директорії `./app`).\n\n2. Використовуйте `fastapi run`, щоб обслуговувати ваш застосунок з одного файлу `main.py`.\n\nКоли ви передаєте файл у `fastapi run`, воно автоматично визначить, що це один файл, а не частина пакета, і знатиме, як імпортувати його та запустити ваш застосунок FastAPI. 😎\n\n## Концепції розгортання { #deployment-concepts }\n\nПоговорімо знову про деякі з тих самих [Концепцій розгортання](concepts.md) у термінах контейнерів.\n\nКонтейнери - це переважно інструмент для спрощення процесу збирання та розгортання застосунку, але вони не нав’язують конкретний підхід до обробки цих концепцій розгортання, і існує кілька можливих стратегій.\n\nГарна новина полягає в тому, що для кожної стратегії є спосіб покрити всі концепції розгортання. 🎉\n\nРозгляньмо ці концепції розгортання в контексті контейнерів:\n\n* HTTPS\n* Автозапуск\n* Перезапуски\n* Реплікація (кількість запущених процесів)\n* Пам’ять\n* Попередні кроки перед запуском\n\n## HTTPS { #https }\n\nЯкщо зосередитись лише на образі контейнера для застосунку FastAPI (а згодом на запущеному контейнері), HTTPS зазвичай обробляється зовнішнім іншим інструментом.\n\nЦе може бути інший контейнер, наприклад з [Traefik](https://traefik.io/), що обробляє HTTPS і автоматичне отримання сертифікатів.\n\n/// tip | Порада\n\nTraefik має інтеграції з Docker, Kubernetes та іншими, тож налаштувати і сконфігурувати HTTPS для ваших контейнерів з ним дуже просто.\n\n///\n\nАльтернативно, HTTPS може оброблятись хмарним провайдером як один з їхніх сервісів (при цьому застосунок усе ще працює в контейнері).\n\n## Автозапуск і перезапуски { #running-on-startup-and-restarts }\n\nЗазвичай інший інструмент відповідає за запуск і виконання вашого контейнера.\n\nЦе може бути безпосередньо Docker, Docker Compose, Kubernetes, хмарний сервіс тощо.\n\nУ більшості (або всіх) випадків є проста опція, щоб увімкнути запуск контейнера при старті системи та перезапуски у разі збоїв. Наприклад, у Docker це опція командного рядка `--restart`.\n\nБез використання контейнерів змусити застосунки запускатися при старті системи та з перезапусками може бути клопітно і складно. Але під час роботи з контейнерами у більшості випадків ця функціональність вбудована за замовчуванням. ✨\n\n## Реплікація - кількість процесів { #replication-number-of-processes }\n\nЯкщо у вас є <dfn title=\"Група машин, налаштованих бути з'єднаними та працювати разом певним чином.\">кластер</dfn> машин із Kubernetes, Docker Swarm Mode, Nomad або іншою подібною складною системою для керування розподіленими контейнерами на кількох машинах, тоді ви, ймовірно, захочете обробляти реплікацію на рівні кластера замість використання менеджера процесів (як-от Uvicorn з працівниками) у кожному контейнері.\n\nОдна з таких розподілених систем керування контейнерами, як-от Kubernetes, зазвичай має інтегровані способи обробляти реплікацію контейнерів, підтримуючи водночас балансування навантаження для вхідних запитів. Усе це - на рівні кластера.\n\nУ таких випадках ви, ймовірно, захочете зібрати Docker-образ з нуля, як [пояснено вище](#dockerfile), встановивши ваші залежності і запустивши один процес Uvicorn замість використання кількох працівників Uvicorn.\n\n### Балансувальник навантаження { #load-balancer }\n\nПри використанні контейнерів зазвичай є якийсь компонент, що слухає на головному порту. Це може бути інший контейнер, який також є представником з термінацією TLS для обробки HTTPS, або подібний інструмент.\n\nОскільки цей компонент приймає навантаження запитів і розподіляє його між працівниками (сподіваємось) збалансовано, його також часто називають балансувальником навантаження.\n\n/// tip | Порада\n\nТой самий компонент представника з термінацією TLS, що використовується для HTTPS, швидше за все, також буде балансувальником навантаження.\n\n///\n\nІ під час роботи з контейнерами та сама система, яку ви використовуєте для їх запуску і керування ними, вже матиме внутрішні інструменти для передавання мережевої комунікації (наприклад, HTTP-запитів) від цього балансувальника навантаження (який також може бути представником з термінацією TLS) до контейнерів із вашим застосунком.\n\n### Один балансувальник навантаження - кілька контейнерів-працівників { #one-load-balancer-multiple-worker-containers }\n\nПід час роботи з Kubernetes або подібними розподіленими системами керування контейнерами використання їхніх внутрішніх мережевих механізмів дозволяє єдиному балансувальнику навантаження, що слухає на головному порту, передавати комунікацію (запити) до кількох контейнерів, у яких запущено ваш застосунок.\n\nКожен з цих контейнерів із вашим застосунком зазвичай має лише один процес (наприклад, процес Uvicorn, що запускає ваш застосунок FastAPI). Усі вони будуть ідентичними контейнерами, які запускають те саме, але кожен зі своїм процесом, пам’яттю тощо. Таким чином ви використаєте переваги паралелізму на різних ядрах процесора або навіть на різних машинах.\n\nА розподілена система контейнерів із балансувальником навантаження розподілятиме запити між кожним із контейнерів із вашим застосунком по черзі. Тож кожен запит може оброблятися одним із кількох реплікованих контейнерів, що запускають ваш застосунок.\n\nІ зазвичай цей балансувальник навантаження зможе обробляти запити, які йдуть до інших застосунків у вашому кластері (наприклад, до іншого домену або під іншим префіксом шляху URL), і передаватиме комунікацію до відповідних контейнерів для того іншого застосунку, що працює у вашому кластері.\n\n### Один процес на контейнер { #one-process-per-container }\n\nУ такому сценарії ви, ймовірно, захочете мати один (Uvicorn) процес на контейнер, адже ви вже обробляєте реплікацію на рівні кластера.\n\nТобто в цьому випадку ви не захочете мати кількох працівників у контейнері, наприклад через опцію командного рядка `--workers`. Ви захочете мати лише один процес Uvicorn на контейнер (але, ймовірно, кілька контейнерів).\n\nНаявність іншого менеджера процесів всередині контейнера (як це було б із кількома працівниками) лише додасть зайвої складності, яку, найімовірніше, ви вже вирішуєте на рівні кластера.\n\n### Контейнери з кількома процесами та особливі випадки { #containers-with-multiple-processes-and-special-cases }\n\nЗвісно, є особливі випадки, коли ви можете захотіти мати контейнер із кількома процесами-працівниками Uvicorn всередині.\n\nУ таких випадках ви можете використати опцію командного рядка `--workers`, щоб задати кількість працівників, яких потрібно запустити:\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. Тут ми використовуємо опцію командного рядка `--workers`, щоб встановити кількість працівників 4.\n\nОсь кілька прикладів, коли це може мати сенс:\n\n#### Простий застосунок { #a-simple-app }\n\nВи можете захотіти менеджер процесів у контейнері, якщо ваш застосунок достатньо простий, щоб запускати його на одному сервері, а не на кластері.\n\n#### Docker Compose { #docker-compose }\n\nВи можете розгортати на одному сервері (не в кластері) за допомогою Docker Compose, тож у вас не буде простого способу керувати реплікацією контейнерів (у Docker Compose), зберігаючи спільну мережу та балансування навантаження.\n\nТоді ви можете захотіти мати один контейнер із менеджером процесів, що запускає кілька процесів-працівників всередині.\n\n---\n\nГоловна думка: це не правила, викарбувані в камені, яких потрібно сліпо дотримуватися. Ви можете використати ці ідеї, щоб оцінити власний кейс і вирішити, який підхід найкращий для вашої системи, розглядаючи, як керувати такими концепціями:\n\n* Безпека - HTTPS\n* Автозапуск\n* Перезапуски\n* Реплікація (кількість запущених процесів)\n* Пам’ять\n* Попередні кроки перед запуском\n\n## Пам’ять { #memory }\n\nЯкщо ви запускаєте один процес на контейнер, ви матимете більш-менш чітко визначений, стабільний і обмежений обсяг пам’яті, що споживається кожним із цих контейнерів (їх може бути більше одного, якщо вони репліковані).\n\nПотім ви можете встановити ті самі ліміти та вимоги до пам’яті у ваших конфігураціях для системи керування контейнерами (наприклад, у Kubernetes). Таким чином вона зможе реплікувати контейнери на доступних машинах, враховуючи обсяг пам’яті, потрібний їм, і обсяг доступної пам’яті на машинах у кластері.\n\nЯкщо ваш застосунок простий, імовірно, це не буде проблемою, і вам може не знадобитися задавати жорсткі ліміти пам’яті. Але якщо ви використовуєте багато пам’яті (наприклад, із моделями машинного навчання), вам слід перевірити, скільки пам’яті ви споживаєте, і відкоригувати кількість контейнерів, що запускаються на кожній машині (і, можливо, додати більше машин у ваш кластер).\n\nЯкщо ви запускаєте кілька процесів на контейнер, вам потрібно переконатися, що кількість запущених процесів не споживає більше пам’яті, ніж доступно.\n\n## Попередні кроки перед запуском і контейнери { #previous-steps-before-starting-and-containers }\n\nЯкщо ви використовуєте контейнери (наприклад, Docker, Kubernetes), то є два основні підходи.\n\n### Кілька контейнерів { #multiple-containers }\n\nЯкщо у вас кілька контейнерів, імовірно кожен запускає один процес (наприклад, у кластері Kubernetes), тоді ви, ймовірно, захочете мати окремий контейнер, який виконає попередні кроки в одному контейнері, запустивши один процес, перед запуском реплікованих контейнерів-працівників.\n\n/// info | Інформація\n\nЯкщо ви використовуєте Kubernetes, це, ймовірно, буде [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).\n\n///\n\nЯкщо у вашому випадку немає проблеми запускати ці попередні кроки кілька разів паралельно (наприклад, якщо ви не виконуєте міграції бази даних, а лише перевіряєте, чи база вже готова), тоді ви також можете просто помістити їх у кожен контейнер безпосередньо перед запуском головного процесу.\n\n### Один контейнер { #single-container }\n\nЯкщо у вас просте налаштування з одним контейнером, який потім запускає кілька процесів-працівників (або теж лише один процес), тоді ви можете виконати ці попередні кроки в тому ж контейнері безпосередньо перед запуском процесу із застосунком.\n\n### Базовий образ Docker { #base-docker-image }\n\nКолись існував офіційний образ Docker для FastAPI: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). Але зараз він застарілий. ⛔️\n\nЙмовірно, вам не слід використовувати цей базовий образ Docker (або будь-який інший подібний).\n\nЯкщо ви використовуєте Kubernetes (або інші) і вже налаштовуєте реплікацію на рівні кластера з кількома контейнерами. У таких випадках краще зібрати образ з нуля, як описано вище: [Зібрати Docker-образ для FastAPI](#build-a-docker-image-for-fastapi).\n\nА якщо вам потрібно мати кілька працівників, ви можете просто використати опцію командного рядка `--workers`.\n\n/// note | Технічні деталі\n\nЦей образ Docker було створено тоді, коли Uvicorn не підтримував керування та перезапуск «мертвих» працівників, тому потрібно було використовувати Gunicorn з Uvicorn, що додавало чимало складності лише для того, щоб Gunicorn керував та перезапускав процеси-працівники Uvicorn.\n\nАле тепер, коли Uvicorn (і команда `fastapi`) підтримують використання `--workers`, немає причин використовувати базовий образ Docker замість того, щоб зібрати власний (це приблизно та сама кількість коду 😅).\n\n///\n\n## Розгорнути образ контейнера { #deploy-the-container-image }\n\nПісля отримання образу контейнера (Docker) є кілька способів його розгорнути.\n\nНаприклад:\n\n* З Docker Compose на одному сервері\n* З кластером Kubernetes\n* З кластером Docker Swarm Mode\n* З іншим інструментом, як-от Nomad\n* З хмарним сервісом, який бере ваш образ контейнера і розгортає його\n\n## Образ Docker з `uv` { #docker-image-with-uv }\n\nЯкщо ви використовуєте [uv](https://github.com/astral-sh/uv) для встановлення та керування вашим проєктом, ви можете скористатися їхнім [посібником Docker для uv](https://docs.astral.sh/uv/guides/integration/docker/).\n\n## Підсумок { #recap }\n\nВикористовуючи системи контейнерів (наприклад, з Docker і Kubernetes), досить просто обробляти всі концепції розгортання:\n\n* HTTPS\n* Автозапуск\n* Перезапуски\n* Реплікація (кількість запущених процесів)\n* Пам’ять\n* Попередні кроки перед запуском\n\nУ більшості випадків ви, ймовірно, не захочете використовувати будь-який базовий образ, а натомість зібрати образ контейнера з нуля на основі офіційного образу Python для Docker.\n\nДотримуючись порядку інструкцій у `Dockerfile` і використовуючи кеш Docker, ви можете мінімізувати час збірки, щоб максимізувати свою продуктивність (і уникнути нудьги). 😎\n"
  },
  {
    "path": "docs/uk/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\nВи можете розгорнути свій застосунок FastAPI на [FastAPI Cloud](https://fastapicloud.com) **однією командою**, приєднуйтесь до списку очікування, якщо ще ні. 🚀\n\n## Вхід { #login }\n\nПереконайтеся, що у вас вже є обліковий запис **FastAPI Cloud** (ми запросили вас зі списку очікування 😉).\n\nПотім увійдіть:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## Розгортання { #deploy }\n\nТепер розгорніть свій застосунок **однією командою**:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nОсь і все! Тепер ви можете отримати доступ до свого застосунку за цим URL. ✨\n\n## Про FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** створено тим самим автором і командою, що стоїть за **FastAPI**.\n\nВін спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.\n\nВін переносить той самий **досвід розробника**, що і під час створення застосунків з FastAPI, на їх **розгортання** у хмарі. 🎉\n\nВін також подбає про більшість речей, які вам потрібні під час розгортання застосунку, як-от:\n\n- HTTPS\n- реплікація з автомасштабуванням на основі запитів\n- тощо\n\nFastAPI Cloud - основний спонсор і джерело фінансування для відкритих проєктів *«FastAPI та друзі»*. ✨\n\n## Розгортання в інших хмарних провайдерів { #deploy-to-other-cloud-providers }\n\nFastAPI є відкритим кодом і базується на стандартах. Ви можете розгортати застосунки FastAPI в будь-якого хмарного провайдера за вашим вибором.\n\nДотримуйтесь інструкцій вашого хмарного провайдера, щоб розгортати застосунки FastAPI у них. 🤓\n\n## Розгортання на вашому сервері { #deploy-your-own-server }\n\nПізніше в цьому розділі **Розгортання** я також навчу вас усім деталям, щоб ви розуміли, що відбувається, що потрібно зробити і як розгортати застосунки FastAPI самостійно, зокрема на власних серверах. 🤓\n"
  },
  {
    "path": "docs/uk/docs/deployment/https.md",
    "content": "# Про HTTPS { #about-https }\n\nЛегко припустити, що HTTPS - це щось, що просто «увімкнено» або ні.\n\nАле все значно складніше.\n\n/// tip | Порада\n\nЯкщо ви поспішаєте або це неважливо для вас, переходьте до наступних розділів для покрокових інструкцій із налаштування всього різними техніками.\n\n///\n\nЩоб **вивчити основи HTTPS** з точки зору споживача, перегляньте [https://howhttps.works/](https://howhttps.works/).\n\nТепер, з **точки зору розробника**, ось кілька речей, які варто пам'ятати, розмірковуючи про HTTPS:\n\n* Для HTTPS **сервер** має **мати «сертифікати»**, видані **третьою стороною**.\n    * Насправді ці сертифікати **«отримуються»** у третьої сторони, а не **«генеруються»**.\n* Сертифікати мають **строк дії**.\n    * Їхній строк дії **спливає**.\n    * І тоді їх потрібно **поновити**, **знову отримавши** у третьої сторони.\n* Шифрування з'єднання відбувається на **рівні TCP**.\n    * Це один шар **нижче від HTTP**.\n    * Тож **обробка сертифіката та шифрування** виконується **до HTTP**.\n* **TCP не знає про «домени»**. Лише про IP-адреси.\n    * Інформація про **конкретний домен**, який запитується, міститься в **даних HTTP**.\n* **Сертифікати HTTPS** «засвідчують» **певний домен**, але протокол і шифрування працюють на рівні TCP, **до того як відомо**, з яким доменом маємо справу.\n* **Типово**, це означало б, що на одну IP-адресу можна мати **лише один сертифікат HTTPS**.\n    * Неважливо, наскільки великий ваш сервер або наскільки малий кожен застосунок на ньому.\n    * Однак для цього є **рішення**.\n* Є **розширення** протоколу **TLS** (який обробляє шифрування на рівні TCP, до HTTP), що називається **[<abbr title=\"Server Name Indication - Ідентифікація імені сервера\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**.\n    * Це розширення SNI дозволяє одному серверу (з **однією IP-адресою**) мати **кілька сертифікатів HTTPS** і обслуговувати **кілька доменів/застосунків через HTTPS**.\n    * Щоб це працювало, один-єдиний компонент (програма), що працює на сервері та слухає **публічну IP-адресу**, має мати **всі сертифікати HTTPS** на сервері.\n* **Після** отримання захищеного з'єднання протокол обміну **залишається HTTP**.\n    * Вміст **зашифровано**, хоча він надсилається з використанням **протоколу HTTP**.\n\nПоширена практика мати **одну програму/HTTP-сервер**, що працює на сервері (машині, хості тощо) і **керує всіма частинами HTTPS**: приймає **зашифровані HTTPS-запити**, надсилає **розшифровані HTTP-запити** до фактичного HTTP-застосунку, що працює на тому ж сервері (у нашому випадку застосунок **FastAPI**), отримує **HTTP-відповідь** від застосунку, **шифрує її** за допомогою відповідного **сертифіката HTTPS** і надсилає її назад клієнту через **HTTPS**. Такий сервер часто називають **[TLS Termination Proxy](https://en.wikipedia.org/wiki/TLS_termination_proxy)**.\n\nДеякі варіанти, які ви можете використати як TLS Termination Proxy:\n\n* Traefik (також може виконувати поновлення сертифікатів)\n* Caddy (також може виконувати поновлення сертифікатів)\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\nДо Let's Encrypt ці **сертифікати HTTPS** продавалися довіреними третіми сторонами.\n\nПроцес отримання одного з таких сертифікатів був громіздким, вимагав чимало паперової роботи, а самі сертифікати були доволі дорогими.\n\nАле потім з'явився проєкт **[Let's Encrypt](https://letsencrypt.org/)**.\n\nЦе проєкт Linux Foundation. Він надає **сертифікати HTTPS безкоштовно**, в автоматизований спосіб. Ці сертифікати використовують усі стандартні криптографічні механізми безпеки і є короткостроковими (близько 3 місяців), тож **безпека насправді краща** завдяки зменшеній тривалості життя.\n\nДомени безпечно перевіряються, а сертифікати генеруються автоматично. Це також дозволяє автоматизувати поновлення цих сертифікатів.\n\nІдея полягає в автоматизації отримання та поновлення цих сертифікатів, щоб ви могли мати **безпечний HTTPS, безкоштовно і назавжди**.\n\n## HTTPS для розробників { #https-for-developers }\n\nОсь приклад того, як може виглядати HTTPS API, крок за кроком, зосереджуючись переважно на ідеях, важливих для розробників.\n\n### Доменне ім'я { #domain-name }\n\nЙмовірно, все почнеться з того, що ви **придбаєте** якесь **доменне ім'я**. Потім ви налаштуєте його на сервері DNS (можливо, у вашого ж хмарного провайдера).\n\nВи, скоріш за все, отримаєте хмарний сервер (віртуальну машину) або щось подібне, і він матиме <dfn title=\"З часом не змінюється. Не динамічний.\">фіксовану</dfn> **публічну IP-адресу**.\n\nНа сервері(ах) DNS ви налаштуєте запис («`A record`»), щоб спрямувати **ваш домен** на публічну **IP-адресу вашого сервера**.\n\nЙмовірно, ви зробите це лише один раз, уперше, коли все налаштовуватимете.\n\n/// tip | Порада\n\nЧастина про доменне ім'я значно раніше за HTTPS, але оскільки все залежить від домену та IP-адреси, варто згадати це тут.\n\n///\n\n### DNS { #dns }\n\nТепер зосередьмося на всіх власне частинах HTTPS.\n\nСпочатку браузер звернеться до **DNS-серверів**, щоб дізнатися, яка **IP-адреса для домену**, у цьому випадку `someapp.example.com`.\n\nСервери DNS повідомлять браузеру використати конкретну **IP-адресу**. Це буде публічна IP-адреса, яку використовує ваш сервер і яку ви налаштували на серверах DNS.\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### Початок TLS рукостискання { #tls-handshake-start }\n\nПотім браузер зв'яжеться з цією IP-адресою на **порту 443** (порт HTTPS).\n\nПерша частина комунікації - це просто встановлення з'єднання між клієнтом і сервером та узгодження криптографічних ключів тощо.\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\nЦя взаємодія між клієнтом і сервером для встановлення з'єднання TLS називається **TLS рукостисканням**.\n\n### TLS із розширенням SNI { #tls-with-sni-extension }\n\n**Лише один процес** на сервері може слухати конкретний **порт** на конкретній **IP-адресі**. Інші процеси можуть слухати інші порти на тій самій IP-адресі, але лише один для кожної комбінації IP-адреси та порту.\n\nTLS (HTTPS) за замовчуванням використовує конкретний порт `443`. Отже, це порт, який нам потрібен.\n\nОскільки лише один процес може слухати цей порт, процесом, що робитиме це, буде **TLS Termination Proxy**.\n\nTLS Termination Proxy матиме доступ до одного або кількох **сертифікатів TLS** (сертифікатів HTTPS).\n\nВикористовуючи **розширення SNI**, обговорене вище, TLS Termination Proxy перевірить, який із наявних сертифікатів TLS (HTTPS) слід використати для цього з'єднання, обравши той, що відповідає домену, очікуваному клієнтом.\n\nУ цьому випадку він використає сертифікат для `someapp.example.com`.\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\nКлієнт уже **довіряє** сутності, яка видала цей сертифікат TLS (у цьому випадку Let's Encrypt, але про це згодом), тож він може **перевірити**, що сертифікат дійсний.\n\nПотім, використовуючи сертифікат, клієнт і TLS Termination Proxy **вирішать, як шифрувати** решту **TCP-комунікації**. На цьому частина **TLS рукостискання** завершується.\n\nПісля цього клієнт і сервер мають **зашифроване TCP-з'єднання** - саме це надає TLS. І тоді вони можуть використати це з'єднання, щоб почати власне **HTTP-комунікацію**.\n\nІ це і є **HTTPS**: це звичайний **HTTP** усередині **захищеного TLS-з'єднання** замість чистого (незашифрованого) TCP-з'єднання.\n\n/// tip | Порада\n\nЗверніть увагу, що шифрування комунікації відбувається на **рівні TCP**, а не на рівні HTTP.\n\n///\n\n### HTTPS-запит { #https-request }\n\nТепер, коли клієнт і сервер (конкретно браузер і TLS Termination Proxy) мають **зашифроване TCP-з'єднання**, вони можуть почати **HTTP-комунікацію**.\n\nОтже, клієнт надсилає **HTTPS-запит**. Це просто HTTP-запит через зашифроване TLS-з'єднання.\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### Розшифрування запиту { #decrypt-the-request }\n\nTLS Termination Proxy використає узгоджене шифрування, щоб **розшифрувати запит**, і передасть **звичайний (розшифрований) HTTP-запит** процесу, що запускає застосунок (наприклад, процесу з Uvicorn, який запускає застосунок FastAPI).\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### HTTP-відповідь { #http-response }\n\nЗастосунок обробить запит і надішле **звичайну (незашифровану) HTTP-відповідь** TLS Termination Proxy.\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### HTTPS-відповідь { #https-response }\n\nПотім TLS Termination Proxy **зашифрує відповідь**, використовуючи попередньо узгоджену криптографію (що почалася із сертифіката для `someapp.example.com`), і надішле її назад у браузер.\n\nДалі браузер перевірить, що відповідь дійсна й зашифрована правильним криптографічним ключем тощо. Потім він **розшифрує відповідь** і обробить її.\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\nКлієнт (браузер) знатиме, що відповідь надходить від правильного сервера, тому що використовується узгоджена раніше криптографія з використанням **сертифіката HTTPS**.\n\n### Кілька застосунків { #multiple-applications }\n\nНа тому самому сервері (або серверах) може бути **кілька застосунків**, наприклад інші програми API або база даних.\n\nЛише один процес може обробляти конкретну IP-адресу і порт (TLS Termination Proxy у нашому прикладі), але інші застосунки/процеси також можуть працювати на сервері(ах), доки вони не намагаються використати ту саму **комбінацію публічної IP-адреси й порту**.\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\nТаким чином, TLS Termination Proxy може обробляти HTTPS і сертифікати для **кількох доменів**, для кількох застосунків, а потім передавати запити до відповідного застосунку в кожному випадку.\n\n### Поновлення сертифіката { #certificate-renewal }\n\nУ певний момент у майбутньому строк дії кожного сертифіката **спливе** (приблизно через 3 місяці після його отримання).\n\nПотім інша програма (в деяких випадках це інша програма, а в деяких - той самий TLS Termination Proxy) зв'яжеться з Let's Encrypt і поновить сертифікат(и).\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\n**Сертифікати TLS** пов'язані **з доменним іменем**, а не з IP-адресою.\n\nТому, щоб поновити сертифікати, програма поновлення має **довести** авторитету (Let's Encrypt), що вона справді **«володіє» і контролює цей домен**.\n\nЩоб зробити це й задовольнити різні потреби застосунків, є кілька способів. Деякі популярні:\n\n* **Змінити деякі записи DNS**.\n    * Для цього програма поновлення має підтримувати API провайдера DNS, тож залежно від того, якого провайдера DNS ви використовуєте, це може бути або не бути варіантом.\n* **Запуститися як сервер** (принаймні під час процесу отримання сертифіката) на публічній IP-адресі, пов'язаній із доменом.\n    * Як ми казали вище, лише один процес може слухати конкретну IP-адресу та порт.\n    * Це одна з причин, чому дуже зручно, коли той самий TLS Termination Proxy також займається процесом поновлення сертифікатів.\n    * Інакше вам, можливо, доведеться на мить зупинити TLS Termination Proxy, запустити програму поновлення, щоб отримати сертифікати, потім налаштувати їх у TLS Termination Proxy і перезапустити TLS Termination Proxy. Це неідеально, оскільки ваші застосунки будуть недоступні під час вимкнення TLS Termination Proxy.\n\nУвесь цей процес поновлення, паралельно з обслуговуванням застосунку, - одна з головних причин, чому ви можете захотіти мати **окрему систему для обробки HTTPS** за допомогою TLS Termination Proxy замість того, щоб просто використовувати сертифікати TLS безпосередньо з сервером застосунку (наприклад, Uvicorn).\n\n## Направлені заголовки проксі { #proxy-forwarded-headers }\n\nКоли ви використовуєте проксі для обробки HTTPS, ваш **сервер застосунку** (наприклад, Uvicorn через FastAPI CLI) нічого не знає про процес HTTPS, він спілкується звичайним HTTP із **TLS Termination Proxy**.\n\nЦей **проксі** зазвичай динамічно встановлює деякі HTTP-заголовки перед передачею запиту **серверу застосунку**, щоб дати йому знати, що запит **направляється** проксі.\n\n/// note | Технічні деталі\n\nЗаголовки проксі:\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\nВтім, оскільки **сервер застосунку** не знає, що він стоїть за довіреним **проксі**, за замовчуванням він не довірятиме цим заголовкам.\n\nАле ви можете налаштувати **сервер застосунку**, щоб довіряти направленим заголовкам, надісланим **проксі**. Якщо ви використовуєте FastAPI CLI, ви можете скористатися курсивною *опцією CLI* `--forwarded-allow-ips`, щоб повідомити, з яких IP-адрес слід довіряти цим направленим заголовкам.\n\nНаприклад, якщо **сервер застосунку** отримує комунікацію лише від довіреного **проксі**, ви можете встановити `--forwarded-allow-ips=\"*\"`, щоб довіряти всім вхідним IP-адресам, оскільки він отримуватиме запити лише з тієї IP-адреси, яку використовує **проксі**.\n\nТак застосунок зможе знати свою публічну URL-адресу, чи використовує він HTTPS, домен тощо.\n\nЦе буде корисно, наприклад, для коректної обробки перенаправлень.\n\n/// tip | Порада\n\nВи можете дізнатися більше про це в документації [За проксі - Увімкнути направлені заголовки проксі](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)\n\n///\n\n## Підсумок { #recap }\n\nНаявність **HTTPS** дуже важлива і в більшості випадків **критична**. Більшість зусиль, які вам як розробнику доведеться докласти навколо HTTPS, полягають лише в **розумінні цих концепцій** і того, як вони працюють.\n\nАле як тільки ви знаєте базову інформацію про **HTTPS для розробників**, ви можете легко комбінувати й налаштовувати різні інструменти, щоб керувати всім просто.\n\nУ деяких наступних розділах я покажу кілька конкретних прикладів налаштування **HTTPS** для застосунків **FastAPI**. 🔒\n"
  },
  {
    "path": "docs/uk/docs/deployment/index.md",
    "content": "# Розгортання { #deployment }\n\nРозгортання застосунку **FastAPI** відносно просте.\n\n## Що означає розгортання { #what-does-deployment-mean }\n\nРозгорнути застосунок - це виконати необхідні кроки, щоб зробити його доступним для користувачів.\n\nДля **веб API** це зазвичай означає розміщення його на **віддаленій машині** з **серверною програмою**, що забезпечує хорошу продуктивність, стабільність тощо, щоб ваші **користувачі** могли **отримувати доступ** до застосунку ефективно та без перерв чи проблем.\n\nЦе відрізняється від етапів **розробки**, коли ви постійно змінюєте код, ламаєте й виправляєте його, зупиняєте та перезапускаєте сервер розробки тощо.\n\n## Стратегії розгортання { #deployment-strategies }\n\nІснує кілька способів зробити це залежно від вашого конкретного випадку використання та інструментів, які ви використовуєте.\n\nВи можете розгорнути сервер самостійно, використовуючи комбінацію інструментів, можете скористатися **хмарним сервісом**, який виконує частину роботи за вас, або обрати інші варіанти.\n\nНаприклад, ми, команда, що стоїть за FastAPI, створили [**FastAPI Cloud**](https://fastapicloud.com), щоб зробити розгортання застосунків FastAPI у хмарі якомога простішим і з тим самим досвідом розробки, що й під час роботи з FastAPI.\n\nЯ покажу вам кілька основних концепцій, про які, ймовірно, варто пам'ятати під час розгортання **FastAPI**-застосунку (хоча більшість із них стосується будь-яких інших типів веб-застосунків).\n\nУ наступних розділах ви побачите більше деталей, на які варто зважати, та деякі техніки, як це зробити. ✨\n"
  },
  {
    "path": "docs/uk/docs/deployment/manually.md",
    "content": "# Запустіть сервер вручну { #run-a-server-manually }\n\n## Використовуйте команду `fastapi run` { #use-the-fastapi-run-command }\n\nКоротко: використовуйте `fastapi run`, щоб запустити ваш застосунок FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\nЦе спрацює в більшості випадків. 😎\n\nЦю команду можна використати, наприклад, щоб запустити ваш застосунок FastAPI у контейнері, на сервері тощо.\n\n## Сервери ASGI { #asgi-servers }\n\nРозгляньмо деталі.\n\nFastAPI використовує стандарт для побудови Python вебфреймворків і серверів під назвою <abbr title=\"Asynchronous Server Gateway Interface - Асинхронний шлюзовий інтерфейс сервера\">ASGI</abbr>. FastAPI - це ASGI вебфреймворк.\n\nГоловне, що потрібно, щоб запустити застосунок **FastAPI** (або будь-який інший ASGI-застосунок) на віддаленій серверній машині, - це програма ASGI-сервера на кшталт **Uvicorn**; саме вона постачається за замовчуванням у команді `fastapi`.\n\nЄ кілька альтернатив, зокрема:\n\n* [Uvicorn](https://www.uvicorn.dev/): високопродуктивний ASGI-сервер.\n* [Hypercorn](https://hypercorn.readthedocs.io/): ASGI-сервер, сумісний з HTTP/2 і Trio, серед інших можливостей.\n* [Daphne](https://github.com/django/daphne): ASGI-сервер, створений для Django Channels.\n* [Granian](https://github.com/emmett-framework/granian): Rust HTTP-сервер для Python-застосунків.\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit - легке й універсальне середовище виконання вебзастосунків.\n\n## Серверна машина і серверна програма { #server-machine-and-server-program }\n\nЄ невелика деталь щодо назв, яку варто пам'ятати. 💡\n\nСлово «**сервер**» зазвичай означає і віддалений/хмарний комп'ютер (фізична або віртуальна машина), і програму, що працює на цій машині (наприклад, Uvicorn).\n\nМайте на увазі, що коли ви бачите слово «сервер» загалом, воно може стосуватися будь-якого з цих двох значень.\n\nКоли йдеться про віддалену машину, її часто називають «сервер», а також «машина», «VM» (віртуальна машина), «вузол». Усе це означає різновиди віддаленої машини, зазвичай з Linux, на якій ви запускаєте програми.\n\n## Встановіть серверну програму { #install-the-server-program }\n\nПісля встановлення FastAPI ви отримуєте продакшн-сервер Uvicorn і можете запускати його командою `fastapi run`.\n\nАле ви також можете встановити ASGI-сервер вручну.\n\nПереконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md), активували його, після чого можете встановити серверну програму.\n\nНаприклад, щоб установити Uvicorn:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\nПодібний процес застосовується до будь-якої іншої ASGI-серверної програми.\n\n/// tip | Порада\n\nДодавши `standard`, Uvicorn встановить і використовуватиме деякі рекомендовані додаткові залежності.\n\nЗокрема `uvloop` - високопродуктивну заміну «без змін у коді» для `asyncio`, що суттєво підвищує рівночасність і продуктивність.\n\nЯкщо ви встановлюєте FastAPI через `pip install \"fastapi[standard]\"`, ви вже отримаєте і `uvicorn[standard]`.\n\n///\n\n## Запустіть серверну програму { #run-the-server-program }\n\nЯкщо ви встановили ASGI-сервер вручну, зазвичай потрібно передати рядок імпорту в спеціальному форматі, щоб він імпортував ваш застосунок FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note | Примітка\n\nКоманда `uvicorn main:app` означає:\n\n* `main`: файл `main.py` (Python «модуль»).\n* `app`: об'єкт, створений у `main.py` рядком `app = FastAPI()`.\n\nЦе еквівалентно:\n\n```Python\nfrom main import app\n```\n\n///\n\nКожна альтернативна ASGI-серверна програма матиме подібну команду; читайте більше в їхній документації.\n\n/// warning | Попередження\n\nUvicorn та інші сервери підтримують опцію `--reload`, корисну під час розробки.\n\nОпція `--reload` споживає значно більше ресурсів, є менш стабільною тощо.\n\nВона дуже допомагає під час **розробки**, але її **не слід** використовувати в **продакшні**.\n\n///\n\n## Концепції розгортання { #deployment-concepts }\n\nЦі приклади запускають серверну програму (наприклад, Uvicorn), піднімаючи один процес, що слухає всі IP (`0.0.0.0`) на визначеному порту (наприклад, `80`).\n\nЦе базова ідея. Але, ймовірно, вам знадобиться подбати ще про таке:\n\n* Безпека - HTTPS\n* Автозапуск\n* Перезапуски\n* Реплікація (кількість запущених процесів)\n* Пам'ять\n* Попередні кроки перед стартом\n\nУ наступних розділах я розповім більше про кожну з цих концепцій, як про них думати, і наведу конкретні приклади та стратегії для їх опрацювання. 🚀\n"
  },
  {
    "path": "docs/uk/docs/deployment/server-workers.md",
    "content": "# Працівники сервера - Uvicorn з працівниками { #server-workers-uvicorn-with-workers }\n\nПовернімося до попередніх концепцій розгортання:\n\n- Безпека - HTTPS\n- Запуск під час старту\n- Перезапуски\n- **Реплікація (кількість процесів, що виконуються)**\n- Пам'ять\n- Попередні кроки перед запуском\n\nДо цього моменту, проходячи всі навчальні посібники в документації, ви, ймовірно, запускали серверну програму, наприклад, використовуючи команду `fastapi`, яка запускає Uvicorn у вигляді одного процесу.\n\nПід час розгортання застосунків ви, найімовірніше, захочете мати реплікацію процесів, щоб використовувати кілька ядер і обробляти більше запитів.\n\nЯк ви бачили в попередньому розділі про [Концепції розгортання](concepts.md), існує кілька стратегій, які можна використовувати.\n\nТут я покажу, як використовувати Uvicorn із процесами-працівниками за допомогою команди `fastapi` або безпосередньо команди `uvicorn`.\n\n/// info | Інформація\n\nЯкщо ви використовуєте контейнери, наприклад з Docker або Kubernetes, я розповім про це більше в наступному розділі: [FastAPI у контейнерах - Docker](docker.md).\n\nЗокрема, під час запуску в Kubernetes вам, найімовірніше, не варто використовувати працівників, натомість запускати один процес Uvicorn на контейнер. Але про це я розповім пізніше в тому розділі.\n\n///\n\n## Кілька працівників { #multiple-workers }\n\nВи можете запустити кілька працівників за допомогою параметра командного рядка `--workers`:\n\n//// tab | `fastapi`\n\nЯкщо ви використовуєте команду `fastapi`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\nЯкщо ви віддаєте перевагу використовувати команду `uvicorn` безпосередньо:\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\nЄдина нова опція тут — `--workers`, яка вказує Uvicorn запустити 4 процеси-працівники.\n\nТакож ви можете побачити, що виводиться PID кожного процесу: `27365` для батьківського процесу (це менеджер процесів) і по одному для кожного процесу-працівника: `27368`, `27369`, `27370` і `27367`.\n\n## Концепції розгортання { #deployment-concepts }\n\nТут ви побачили, як використовувати кілька працівників, щоб паралелізувати виконання застосунку, використати кілька ядер процесора та обслуговувати більше запитів.\n\nІз наведеного вище списку концепцій розгортання, використання працівників головним чином допоможе з частиною про реплікацію і трохи з перезапусками, але про інше все ще треба подбати:\n\n- **Безпека - HTTPS**\n- **Запуск під час старту**\n- ***Перезапуски***\n- Реплікація (кількість процесів, що виконуються)\n- **Пам'ять**\n- **Попередні кроки перед запуском**\n\n## Контейнери і Docker { #containers-and-docker }\n\nУ наступному розділі про [FastAPI у контейнерах - Docker](docker.md) я поясню кілька стратегій, які ви можете використати для інших концепцій розгортання.\n\nЯ покажу, як побудувати власний образ з нуля для запуску одного процесу Uvicorn. Це простий процес і, ймовірно, саме те, що потрібно при використанні розподіленої системи керування контейнерами, такої як Kubernetes.\n\n## Підсумок { #recap }\n\nВи можете використовувати кілька процесів-працівників за допомогою параметра CLI `--workers` у командах `fastapi` або `uvicorn`, щоб скористатися перевагами багатоядерних процесорів і запускати кілька процесів паралельно.\n\nВи можете застосувати ці інструменти та ідеї, якщо налаштовуєте власну систему розгортання і самостійно дбаєте про інші концепції розгортання.\n\nПерегляньте наступний розділ, щоб дізнатися про FastAPI з контейнерами (наприклад Docker і Kubernetes). Ви побачите, що ці інструменти також мають прості способи вирішити інші концепції розгортання. ✨\n"
  },
  {
    "path": "docs/uk/docs/deployment/versions.md",
    "content": "# Про версії FastAPI { #about-fastapi-versions }\n\n**FastAPI** уже використовується у продакшні в багатьох застосунках і системах. Покриття тестами підтримується на рівні 100%. Але розробка все ще рухається швидко.\n\nНові можливості додаються часто, помилки регулярно виправляються, а код постійно поліпшується.\n\nТому поточні версії все ще `0.x.x`, це відображає те, що кожна версія потенційно може містити несумісні зміни. Це відповідає правилам [Семантичного версіонування](https://semver.org/).\n\nВи можете створювати продакшн-застосунки з **FastAPI** вже зараз (і, ймовірно, робите це вже певний час), просто переконайтеся, що ви використовуєте версію, яка коректно працює з рештою вашого коду.\n\n## Зафіксуйте версію `fastapi` { #pin-your-fastapi-version }\n\nПерше, що слід зробити, - «зафіксувати» версію **FastAPI**, яку ви використовуєте, до конкретної останньої версії, що, як ви знаєте, правильно працює для вашого застосунку.\n\nНаприклад, припустімо, що у вашому застосунку використовується версія `0.112.0`.\n\nЯкщо ви використовуєте файл `requirements.txt`, ви можете вказати версію так:\n\n```txt\nfastapi[standard]==0.112.0\n```\n\nце означатиме, що ви використовуватимете саме версію `0.112.0`.\n\nАбо ви також можете зафіксувати так:\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\nце означатиме, що ви використовуватимете версії `0.112.0` і вище, але менше `0.113.0`, наприклад, версія `0.112.2` все ще буде прийнятною.\n\nЯкщо ви використовуєте інший інструмент для керування встановленнями, як-от `uv`, Poetry, Pipenv чи інші, у всіх них є спосіб визначати конкретні версії для ваших пакетів.\n\n## Доступні версії { #available-versions }\n\nВи можете переглянути доступні версії (наприклад, щоб перевірити поточну останню) в [Примітках до випусків](../release-notes.md).\n\n## Про версії { #about-versions }\n\nВідповідно до правил Семантичного версіонування, будь-яка версія нижче `1.0.0` потенційно може містити несумісні зміни.\n\nFastAPI також дотримується правила, що будь-яка зміна «PATCH»-версії - це виправлення помилок і зміни без порушень сумісності.\n\n/// tip | Порада\n\n«PATCH» - це останнє число, наприклад, у `0.2.3` PATCH-версія - це `3`.\n\n///\n\nТож ви можете зафіксувати версію так:\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\nНесумісні зміни та нові можливості додаються у «MINOR»-версіях.\n\n/// tip | Порада\n\n«MINOR» - це число посередині, наприклад, у `0.2.3` MINOR-версія - це `2`.\n\n///\n\n## Оновлення версій FastAPI { #upgrading-the-fastapi-versions }\n\nВи повинні додати тести для вашого застосунку.\n\nЗ **FastAPI** це дуже легко (завдяки Starlette), перегляньте документацію: [Тестування](../tutorial/testing.md)\n\nПісля того як у вас є тести, ви можете оновити версію **FastAPI** до новішої і переконатися, що весь ваш код працює правильно, запустивши тести.\n\nЯкщо все працює або після внесення необхідних змін і проходження всіх тестів, зафіксуйте вашу версію `fastapi` на цій новій версії.\n\n## Про Starlette { #about-starlette }\n\nНе варто фіксувати версію `starlette`.\n\nРізні версії **FastAPI** використовуватимуть конкретну новішу версію Starlette.\n\nОтже, просто дозвольте **FastAPI** використовувати відповідну версію Starlette.\n\n## Про Pydantic { #about-pydantic }\n\nPydantic включає тести для **FastAPI** разом із власними тестами, тому нові версії Pydantic (вище `1.0.0`) завжди сумісні з FastAPI.\n\nВи можете зафіксувати Pydantic на будь-якій версії вище `1.0.0`, яка вам підходить.\n\nНаприклад:\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/uk/docs/editor-support.md",
    "content": "# Підтримка редакторів { #editor-support }\n\nОфіційне [FastAPI Extension](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) покращує ваш робочий процес розробки FastAPI завдяки виявленню й навігації по *операціях шляху*, а також розгортанню у FastAPI Cloud і потоковому передаванню журналів у реальному часі.\n\nДокладніше про розширення дивіться у README в [репозиторії GitHub](https://github.com/fastapi/fastapi-vscode).\n\n## Налаштування та встановлення { #setup-and-installation }\n\n**FastAPI Extension** доступне для [VS Code](https://code.visualstudio.com/) і [Cursor](https://www.cursor.com/). Його можна встановити безпосередньо з панелі Extensions у кожному редакторі, знайшовши «FastAPI» і вибравши розширення від **FastAPI Labs**. Розширення також працює у браузерних редакторах, таких як [vscode.dev](https://vscode.dev) і [github.dev](https://github.dev).\n\n### Виявлення застосунку { #application-discovery }\n\nТипово розширення автоматично виявляє застосунки FastAPI у вашому робочому просторі, скануючи файли, які створюють екземпляр `FastAPI()`. Якщо автовиявлення не працює для структури вашого проєкту, ви можете вказати точку входу через `[tool.fastapi]` у `pyproject.toml` або налаштування VS Code `fastapi.entryPoint`, використовуючи нотацію модуля (наприклад, `myapp.main:app`).\n\n## Можливості { #features }\n\n- **Провідник операцій шляху** - Бічне деревоподібне представлення всіх <dfn title=\"маршрути, кінцеві точки\">*операцій шляху*</dfn> у вашому застосунку. Натисніть, щоб перейти до будь-якого визначення маршруту або маршрутизатора.\n- **Пошук маршрутів** - Пошук за шляхом, методом або назвою за допомогою <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd> (на macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>).\n- **Навігація CodeLens** - Клікабельні посилання над викликами тестового клієнта (наприклад, `client.get('/items')`), які переходять до відповідної *операції шляху* для швидкої навігації між тестами та реалізацією.\n- **Розгортання у FastAPI Cloud** - Розгортання вашого застосунку у [FastAPI Cloud](https://fastapicloud.com/) в один клік.\n- **Потокове передавання журналів застосунку** - Потокове передавання журналів у реальному часі з вашого застосунку, розгорнутого у FastAPI Cloud, з фільтруванням за рівнем і пошуком по тексту.\n\nЩоб ознайомитися з можливостями розширення, відкрийте Палітру команд (<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> або на macOS: <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>), виберіть «Welcome: Open walkthrough...», а потім «Get started with FastAPI».\n"
  },
  {
    "path": "docs/uk/docs/environment-variables.md",
    "content": "# Змінні оточення { #environment-variables }\n\n/// tip | Порада\n\nЯкщо ви вже знаєте, що таке «змінні оточення» і як їх використовувати, можете пропустити цей розділ.\n\n///\n\nЗмінна оточення (також відома як «env var») - це змінна, що існує поза кодом Python, в операційній системі, і може бути прочитана вашим кодом Python (а також іншими програмами).\n\nЗмінні оточення корисні для роботи з налаштуваннями застосунку, як частина встановлення Python тощо.\n\n## Створення і використання змінних оточення { #create-and-use-env-vars }\n\nВи можете створювати і використовувати змінні оточення в оболонці (терміналі) без участі Python:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Ви можете створити змінну оточення MY_NAME командою\n$ export MY_NAME=\"Wade Wilson\"\n\n// Потім можна використати її з іншими програмами, наприклад\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Створіть змінну оточення MY_NAME\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// Використайте її з іншими програмами, наприклад\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## Читання змінних оточення в Python { #read-env-vars-in-python }\n\nВи також можете створити змінні оточення поза Python, у терміналі (або будь-яким іншим способом), а потім зчитати їх у Python.\n\nНаприклад, у вас може бути файл `main.py` з:\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip | Порада\n\nДругий аргумент до [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) - це значення за замовчуванням, яке буде повернено.\n\nЯкщо його не вказано, за замовчуванням це `None`. Тут ми надаємо `\"World\"` як значення за замовчуванням.\n\n///\n\nПотім ви можете запустити цю програму Python:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// Тут ми ще не встановлюємо змінну оточення\n$ python main.py\n\n// Оскільки ми не встановили змінну оточення, отримуємо значення за замовчуванням\n\nHello World from Python\n\n// Але якщо спочатку створимо змінну оточення\n$ export MY_NAME=\"Wade Wilson\"\n\n// А потім знову викличемо програму\n$ python main.py\n\n// Тепер вона може прочитати змінну оточення\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// Тут ми ще не встановлюємо змінну оточення\n$ python main.py\n\n// Оскільки ми не встановили змінну оточення, отримуємо значення за замовчуванням\n\nHello World from Python\n\n// Але якщо спочатку створимо змінну оточення\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// А потім знову викличемо програму\n$ python main.py\n\n// Тепер вона може прочитати змінну оточення\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\nОскільки змінні оточення можна встановлювати поза кодом, але читати в коді, і їх не потрібно зберігати (фіксувати у `git`) разом з іншими файлами, їх часто використовують для конфігурацій або налаштувань.\n\nВи також можете створити змінну оточення лише для конкретного запуску програми, вона буде доступна тільки цій програмі і лише на час її виконання.\n\nЩоб зробити це, створіть її безпосередньо перед командою запуску програми, в тому самому рядку:\n\n<div class=\"termy\">\n\n```console\n// Створіть змінну оточення MY_NAME безпосередньо в цьому виклику програми\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// Тепер вона може прочитати змінну оточення\n\nHello Wade Wilson from Python\n\n// Після цього змінна оточення більше не існує\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip | Порада\n\nВи можете прочитати більше у [The Twelve-Factor App: Config](https://12factor.net/config).\n\n///\n\n## Типи і перевірка { #types-and-validation }\n\nЦі змінні оточення можуть містити лише текстові строки, оскільки вони зовнішні щодо Python і мають бути сумісними з іншими програмами та рештою системи (і навіть з різними операційними системами, як-от Linux, Windows, macOS).\n\nЦе означає, що будь-яке значення, прочитане в Python зі змінної оточення, буде `str`, а будь-яке перетворення до іншого типу або будь-яка перевірка має виконуватися в коді.\n\nВи дізнаєтеся більше про використання змінних оточення для роботи з налаштуваннями застосунку в розділі [Просунутий посібник користувача - Налаштування і змінні оточення](./advanced/settings.md).\n\n## Змінна оточення `PATH` { #path-environment-variable }\n\nЄ спеціальна змінна оточення `PATH`, яку використовують операційні системи (Linux, macOS, Windows) для пошуку програм для запуску.\n\nЗначення змінної `PATH` - це довга строка, що складається з каталогів, розділених двокрапкою `:` у Linux і macOS та крапкою з комою `;` у Windows.\n\nНаприклад, змінна оточення `PATH` може виглядати так:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nЦе означає, що система має шукати програми в каталогах:\n\n* `/usr/local/bin`\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\nЦе означає, що система має шукати програми в каталогах:\n\n* `C:\\Program Files\\Python312\\Scripts`\n* `C:\\Program Files\\Python312`\n* `C:\\Windows\\System32`\n\n////\n\nКоли ви вводите команду в терміналі, операційна система шукає програму в кожному з тих каталогів, перелічених у змінній оточення `PATH`.\n\nНаприклад, коли ви вводите `python` у терміналі, операційна система шукає програму з назвою `python` у першому каталозі цього списку.\n\nЯкщо знайде, вона використає її. Інакше продовжить пошук в інших каталогах.\n\n### Встановлення Python і оновлення `PATH` { #installing-python-and-updating-the-path }\n\nПід час встановлення Python вас можуть запитати, чи хочете ви оновити змінну оточення `PATH`.\n\n//// tab | Linux, macOS\n\nПрипустімо, ви встановлюєте Python і він опиняється в каталозі `/opt/custompython/bin`.\n\nЯкщо ви погодитеся оновити змінну оточення `PATH`, інсталятор додасть `/opt/custompython/bin` до змінної `PATH`.\n\nЦе може виглядати так:\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\nТепер, коли ви введете `python` у терміналі, система знайде програму Python у `/opt/custompython/bin` (останній каталог) і використає саме її.\n\n////\n\n//// tab | Windows\n\nПрипустімо, ви встановлюєте Python і він опиняється в каталозі `C:\\opt\\custompython\\bin`.\n\nЯкщо ви погодитеся оновити змінну оточення `PATH`, інсталятор додасть `C:\\opt\\custompython\\bin` до змінної `PATH`.\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\nТепер, коли ви введете `python` у терміналі, система знайде програму Python у `C:\\opt\\custompython\\bin` (останній каталог) і використає саме її.\n\n////\n\nОтже, якщо ви введете:\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\nСистема знайде програму `python` у `/opt/custompython/bin` і запустить її.\n\nЦе приблизно еквівалентно введенню:\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\nСистема знайде програму `python` у `C:\\opt\\custompython\\bin\\python` і запустить її.\n\nЦе приблизно еквівалентно введенню:\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\nЦя інформація стане у пригоді під час вивчення [Віртуальних середовищ](virtual-environments.md).\n\n## Висновок { #conclusion }\n\nТепер ви маєте базове розуміння того, що таке змінні оточення і як їх використовувати в Python.\n\nТакож можна прочитати більше у [Вікіпедії про змінну оточення](https://en.wikipedia.org/wiki/Environment_variable).\n\nУ багатьох випадках не одразу очевидно, як змінні оточення будуть корисними та застосовними. Але вони постійно з’являються в різних сценаріях під час розробки, тож варто про них знати.\n\nНаприклад, вам знадобиться ця інформація в наступному розділі про [Віртуальні середовища](virtual-environments.md).\n"
  },
  {
    "path": "docs/uk/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - інтерфейс командного рядка\">CLI</abbr>** — це програма командного рядка, яку ви можете використовувати, щоб обслуговувати ваш застосунок FastAPI, керувати вашим проєктом FastAPI тощо.\n\nКоли ви встановлюєте FastAPI (наприклад, за допомогою `pip install \"fastapi[standard]\"`), він постачається з програмою командного рядка, яку можна запускати в терміналі.\n\nЩоб запустити ваш застосунок FastAPI для розробки, ви можете використати команду `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip | Порада\n\nДля продакшну ви б використовували `fastapi run` замість `fastapi dev`. 🚀\n\n///\n\nВнутрішньо **FastAPI CLI** використовує [Uvicorn](https://www.uvicorn.dev), високопродуктивний, готовий до продакшну ASGI сервер. 😎\n\nCLI `fastapi` спробує автоматично визначити застосунок FastAPI для запуску, припускаючи, що це об'єкт з назвою `app` у файлі `main.py` (або кілька інших варіантів).\n\nАле ви можете явно налаштувати застосунок, який слід використовувати.\n\n## Налаштуйте `entrypoint` застосунку в `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nВи можете налаштувати розташування вашого застосунку у файлі `pyproject.toml`, наприклад:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nЦей `entrypoint` підкаже команді `fastapi`, що слід імпортувати застосунок так:\n\n```python\nfrom main import app\n```\n\nЯкщо ваш код має таку структуру:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nТоді ви встановили б `entrypoint` як:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nщо еквівалентно:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` зі шляхом { #fastapi-dev-with-path }\n\nВи також можете передати шлях до файлу команді `fastapi dev`, і вона здогадається, який об'єкт застосунку FastAPI використовувати:\n\n```console\n$ fastapi dev main.py\n```\n\nАле вам доведеться щоразу пам'ятати, щоб передавати правильний шлях під час виклику команди `fastapi`.\n\nКрім того, інші інструменти можуть не знайти його, наприклад [Розширення VS Code](editor-support.md) або [FastAPI Cloud](https://fastapicloud.com), тому рекомендується використовувати `entrypoint` у `pyproject.toml`.\n\n## `fastapi dev` { #fastapi-dev }\n\nЗапуск `fastapi dev` ініціює режим розробки.\n\nЗа замовчуванням **auto-reload** увімкнено, і сервер автоматично перезавантажується, коли ви вносите зміни у ваш код. Це ресурсоємно та може бути менш стабільним, ніж коли його вимкнено. Вам слід використовувати це лише для розробки. Також він слухає IP-адресу `127.0.0.1`, яка є IP-адресою для того, щоб ваша машина могла взаємодіяти лише сама з собою (`localhost`).\n\n## `fastapi run` { #fastapi-run }\n\nВиконання `fastapi run` за замовчуванням запускає FastAPI у продакшн-режимі.\n\nЗа замовчуванням **auto-reload** вимкнено. Також він слухає IP-адресу `0.0.0.0`, що означає всі доступні IP-адреси, таким чином він буде публічно доступним для будь-кого, хто може взаємодіяти з машиною. Зазвичай саме так ви запускатимете його в продакшн, наприклад у контейнері.\n\nУ більшості випадків ви (і вам слід) матимете «termination proxy», який обробляє HTTPS для вас зверху; це залежатиме від того, як ви розгортаєте ваш застосунок: ваш провайдер може зробити це за вас, або вам може знадобитися налаштувати це самостійно.\n\n/// tip | Порада\n\nВи можете дізнатися більше про це в [документації з розгортання](deployment/index.md).\n\n///\n"
  },
  {
    "path": "docs/uk/docs/features.md",
    "content": "# Функціональні можливості { #features }\n\n## Функціональні можливості FastAPI { #fastapi-features }\n\n**FastAPI** надає вам такі можливості:\n\n### На основі відкритих стандартів { #based-on-open-standards }\n\n* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) для створення API, включаючи оголошення <dfn title=\"також відомі як: кінцеві точки, маршрути\">шляхів</dfn> <dfn title=\"також відомі як методи HTTP, як-от POST, GET, PUT, DELETE\">операцій</dfn>, параметрів, тіл запитів, безпеки тощо.\n* Автоматична документація моделей даних за допомогою [**JSON Schema**](https://json-schema.org/) (оскільки OpenAPI базується саме на JSON Schema).\n* Розроблено на основі цих стандартів після ретельного аналізу, а не як додатковий рівень поверх основної архітектури.\n* Це також дає змогу використовувати автоматичну **генерацію клієнтського коду** багатьма мовами.\n\n### Автоматична документація { #automatic-docs }\n\nІнтерактивна документація API та вебінтерфейси для його дослідження. Оскільки фреймворк базується на OpenAPI, є кілька варіантів, 2 з яких включені за замовчуванням.\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui) — з інтерактивним дослідженням, викликом і тестуванням вашого API прямо з браузера.\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Альтернативна документація API за допомогою [**ReDoc**](https://github.com/Rebilly/ReDoc).\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Лише сучасний Python { #just-modern-python }\n\nУсе базується на стандартних оголошеннях **типів Python** (завдяки Pydantic). Жодного нового синтаксису для вивчення. Лише стандартний сучасний Python.\n\nЯкщо вам потрібно 2-хвилинне нагадування про те, як використовувати типи Python (навіть якщо ви не використовуєте FastAPI), перегляньте короткий підручник: [Типи Python](python-types.md).\n\nВи пишете стандартний Python з типами:\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# Оголосіть змінну як str\n# та отримайте підтримку редактора всередині функції\ndef main(user_id: str):\n    return user_id\n\n\n# Модель Pydantic\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\nДалі це можна використовувати так:\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n/// info | Інформація\n\n`**second_user_data` означає:\n\nПередати ключі та значення словника `second_user_data` безпосередньо як аргументи у вигляді «ключ-значення», еквівалентно: `User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### Підтримка редакторів { #editor-support }\n\nУвесь фреймворк спроєктовано так, щоб ним було легко та інтуїтивно користуватися; усі рішення тестувалися у кількох редакторах ще до початку розробки, щоб забезпечити найкращий досвід розробки.\n\nЗ опитувань розробників Python зрозуміло [що однією з найуживаніших функцій є «автодоповнення»](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features).\n\nУвесь фреймворк **FastAPI** побудований так, щоб це забезпечити. Автодоповнення працює всюди.\n\nВам рідко доведеться повертатися до документації.\n\nОсь як ваш редактор може вам допомогти:\n\n* у [Visual Studio Code](https://code.visualstudio.com/):\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* у [PyCharm](https://www.jetbrains.com/pycharm/):\n\n![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\nВи отримаєте автодоповнення в коді, який раніше могли вважати навіть неможливим. Наприклад, для ключа `price` всередині JSON body (який міг бути вкладеним), що надходить із запиту.\n\nБільше не доведеться вводити неправильні назви ключів, постійно повертатися до документації або прокручувати вгору-вниз, щоб знайти, чи ви зрештою використали `username` чи `user_name`.\n\n### Короткий код { #short }\n\nFastAPI має розумні **налаштування за замовчуванням** для всього, з можливістю конфігурації всюди. Усі параметри можна точно налаштувати під ваші потреби та визначити потрібний вам API.\n\nАле за замовчуванням усе **«просто працює»**.\n\n### Валідація { #validation }\n\n* Підтримка валідації для більшості (або всіх?) **типів даних Python**, зокрема:\n    * JSON-об'єктів (`dict`).\n    * JSON-масивів (`list`) із визначенням типів елементів.\n    * Полів-рядків (`str`) із визначенням мінімальної та максимальної довжини.\n    * Чисел (`int`, `float`) з мінімальними та максимальними значеннями тощо.\n\n* Валідація для більш екзотичних типів, як-от:\n    * URL.\n    * Email.\n    * UUID.\n    * ...та інші.\n\nУся валідація виконується через надійний та перевірений **Pydantic**.\n\n### Безпека та автентифікація { #security-and-authentication }\n\nІнтегровані безпека та автентифікація. Без жодних компромісів із базами даних чи моделями даних.\n\nПідтримуються всі схеми безпеки, визначені в OpenAPI, включно з:\n\n* HTTP Basic.\n* **OAuth2** (також із підтримкою **JWT tokens**). Перегляньте підручник: [OAuth2 із JWT](tutorial/security/oauth2-jwt.md).\n* Ключі API в:\n    * Заголовках.\n    * Параметрах запиту.\n    * Cookies тощо.\n\nА також усі можливості безпеки від Starlette (зокрема **session cookies**).\n\nУсе це зроблено як багаторазові інструменти та компоненти, які легко інтегруються з вашими системами, сховищами даних, реляційними та NoSQL базами даних тощо.\n\n### Впровадження залежностей { #dependency-injection }\n\nFastAPI містить надзвичайно просту у використанні, але надзвичайно потужну систему <dfn title='також відоме як «components», «resources», «services», «providers»'><strong>Впровадження залежностей</strong></dfn>.\n\n* Навіть залежності можуть мати власні залежності, утворюючи ієрархію або **«граф» залежностей**.\n* Усе **автоматично обробляється** фреймворком.\n* Усі залежності можуть вимагати дані із запитів і **розширювати обмеження операції шляху** та автоматичну документацію.\n* **Автоматична валідація** навіть для *операції шляху*, визначених у залежностях.\n* Підтримка складних систем автентифікації користувачів, **підключень до баз даних** тощо.\n* **Жодних компромісів** із базами даних, фронтендами тощо. Але проста інтеграція з усіма ними.\n\n### Необмежені «плагіни» { #unlimited-plug-ins }\n\nІнакше кажучи, вони не потрібні — імпортуйте та використовуйте код, який вам потрібен.\n\nБудь-яка інтеграція спроєктована так, щоб її було дуже просто використовувати (із залежностями), тож ви можете створити «плагін» для свого застосунку у 2 рядках коду, використовуючи ту саму структуру та синтаксис, що й для ваших *операцій шляху*.\n\n### Протестовано { #tested }\n\n* 100% <dfn title=\"Обсяг коду, що автоматично тестується\">покриття тестами</dfn>.\n* 100% <dfn title=\"Анотації типів у Python, завдяки яким ваш редактор і зовнішні інструменти можуть надавати кращу підтримку\">анотована типами</dfn> кодова база.\n* Використовується в production-застосунках.\n\n## Можливості Starlette { #starlette-features }\n\n**FastAPI** повністю сумісний із (та побудований на основі) [**Starlette**](https://www.starlette.dev/). Тому будь-який додатковий код Starlette, який ви маєте, також працюватиме.\n\n`FastAPI` фактично є підкласом `Starlette`. Тому, якщо ви вже знайомі зі Starlette або використовуєте його, більшість функціональності працюватиме так само.\n\nЗ **FastAPI** ви отримуєте всі можливості **Starlette** (адже FastAPI — це просто Starlette на стероїдах):\n\n* Разюча продуктивність. Це [один із найшвидших доступних Python-фреймворків, на рівні з **NodeJS** і **Go**](https://github.com/encode/starlette#performance).\n* Підтримка **WebSocket**.\n* Фонові задачі у процесі.\n* Події запуску та завершення роботи.\n* Клієнт для тестування, побудований на HTTPX.\n* Підтримка **CORS**, **GZip**, статичних файлів, потокових відповідей.\n* Підтримка **сесій** і **cookie**.\n* 100% покриття тестами.\n* 100% анотована типами кодова база.\n\n## Можливості Pydantic { #pydantic-features }\n\n**FastAPI** повністю сумісний із (та побудований на основі) [**Pydantic**](https://docs.pydantic.dev/). Тому будь-який додатковий код Pydantic, який ви маєте, також працюватиме.\n\nВключно із зовнішніми бібліотеками, які також базуються на Pydantic, як-от <abbr title=\"Object-Relational Mapper - Об'єктно-реляційний відображувач\">ORM</abbr>-и, <abbr title=\"Object-Document Mapper - Об'єктно-документний відображувач\">ODM</abbr>-и для баз даних.\n\nЦе також означає, що в багатьох випадках ви можете передати той самий об'єкт, який отримуєте із запиту, **безпосередньо в базу даних**, оскільки все автоматично перевіряється.\n\nТе саме застосовується й у зворотному напрямку — у багатьох випадках ви можете просто передати об'єкт, який отримуєте з бази даних, **безпосередньо клієнту**.\n\nЗ **FastAPI** ви отримуєте всі можливості **Pydantic** (адже FastAPI базується на Pydantic для обробки всіх даних):\n\n* **Ніякої плутанини**:\n    * Не потрібно вчити нову мікромову для визначення схем.\n    * Якщо ви знаєте типи Python, ви знаєте, як використовувати Pydantic.\n* Легко працює з вашим **<abbr title=\"Integrated Development Environment - Інтегроване середовище розробки: схоже на код-редактор\">IDE</abbr>/<dfn title=\"Програма, що перевіряє код на помилки\">linter</dfn>/мозком**:\n    * Оскільки структури даних pydantic є просто екземплярами класів, які ви визначаєте; автодоповнення, лінтинг, mypy і ваша інтуїція повинні добре працювати з вашими перевіреними даними.\n* Валідує **складні структури**:\n    * Використання ієрархічних моделей Pydantic, Python `typing`’s `List` і `Dict` тощо.\n    * Валідатори дають змогу складні схеми даних чітко й просто визначати, перевіряти й документувати як JSON Schema.\n    * Ви можете мати глибоко **вкладені JSON** об'єкти, і всі вони будуть валідовані та анотовані.\n* **Розширюваність**:\n    * Pydantic дозволяє визначати користувацькі типи даних або ви можете розширити валідацію методами в моделі, позначеними декоратором validator.\n* 100% покриття тестами.\n"
  },
  {
    "path": "docs/uk/docs/help-fastapi.md",
    "content": "# Допоможіть FastAPI - отримайте допомогу { #help-fastapi-get-help }\n\nВам подобається **FastAPI**?\n\nХочете допомогти FastAPI, іншим користувачам та автору?\n\nАбо ви хочете отримати допомогу щодо **FastAPI**?\n\nЄ дуже прості способи допомогти (деякі потребують лише одного-двох кліків).\n\nІ є кілька способів отримати допомогу.\n\n## Підпишіться на розсилку { #subscribe-to-the-newsletter }\n\nВи можете підписатися на (нечасту) розсилку [**FastAPI and friends**](newsletter.md), щоб бути в курсі:\n\n* Новин про FastAPI та друзів 🚀\n* Посібників 📝\n* Можливостей ✨\n* Несумісних змін 🚨\n* Порад і трюків ✅\n\n## Стежте за FastAPI в X (Twitter) { #follow-fastapi-on-x-twitter }\n\n[Стежте за @fastapi в **X (Twitter)**](https://x.com/fastapi), щоб отримувати найсвіжіші новини про **FastAPI**. 🐦\n\n## Додайте зірочку **FastAPI** на GitHub { #star-fastapi-in-github }\n\nВи можете «поставити зірочку» FastAPI на GitHub (натиснувши кнопку зірочки у верхньому правому куті): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). ⭐️\n\nДодавши зірочку, іншим користувачам буде легше його знайти і побачити, що він уже був корисним для інших.\n\n## Стежте за випусками в репозиторії GitHub { #watch-the-github-repository-for-releases }\n\nВи можете «спостерігати» за FastAPI на GitHub (натиснувши кнопку «watch» у верхньому правому куті): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nТам ви можете вибрати «Releases only».\n\nЗробивши це, ви отримуватимете сповіщення (на вашу електронну пошту) щоразу, коли вийде новий реліз (нова версія) **FastAPI** з виправленнями помилок і новими можливостями.\n\n## Зв'яжіться з автором { #connect-with-the-author }\n\nВи можете зв'язатися зі [мною (Sebastián Ramírez / `tiangolo`)](https://tiangolo.com), автором.\n\nВи можете:\n\n* [Стежити за мною на **GitHub**](https://github.com/tiangolo).\n    * Подивитися інші Open Source-проєкти, які я створив і які можуть вам допомогти.\n    * Стежити, щоб бачити, коли я створюю новий Open Source-проєкт.\n* [Стежити за мною в **X (Twitter)**](https://x.com/tiangolo) або [Mastodon](https://fosstodon.org/@tiangolo).\n    * Розкажіть мені, як ви використовуєте FastAPI (мені дуже приємно це чути).\n    * Дізнаватися, коли я роблю оголошення або випускаю нові інструменти.\n    * Також ви можете [стежити за @fastapi в X (Twitter)](https://x.com/fastapi) (окремий акаунт).\n* [Стежити за мною в **LinkedIn**](https://www.linkedin.com/in/tiangolo/).\n    * Дізнаватися, коли я роблю оголошення або випускаю нові інструменти (хоча X (Twitter) я використовую частіше 🤷‍♂).\n* Читати, що я пишу (або стежити за мною) на [**Dev.to**](https://dev.to/tiangolo) або [**Medium**](https://medium.com/@tiangolo).\n    * Читати інші ідеї, статті та про інструменти, які я створив.\n    * Стежити, щоб читати нове, коли я щось публікую.\n\n## Твітніть про **FastAPI** { #tweet-about-fastapi }\n\n[Твітніть про **FastAPI**](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi) і дайте мені та іншим знати, чому він вам подобається. 🎉\n\nМені дуже подобається дізнаватися, як використовують **FastAPI**, що вам у ньому сподобалося, у якому проєкті/компанії ви його застосовуєте тощо.\n\n## Голосуйте за FastAPI { #vote-for-fastapi }\n\n* [Проголосуйте за **FastAPI** на Slant](https://www.slant.co/options/34241/~fastapi-review).\n* [Проголосуйте за **FastAPI** на AlternativeTo](https://alternativeto.net/software/fastapi/about/).\n* [Повідомте, що ви використовуєте **FastAPI**, на StackShare](https://stackshare.io/pypi-fastapi).\n\n## Допомагайте іншим з питаннями на GitHub { #help-others-with-questions-in-github }\n\nВи можете спробувати допомагати іншим з їхніми питаннями у:\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\nУ багатьох випадках ви вже можете знати відповідь на ці питання. 🤓\n\nЯкщо ви багато допомагаєте людям із їхніми питаннями, ви станете офіційним [Експертом FastAPI](fastapi-people.md#fastapi-experts). 🎉\n\nПам'ятайте, найважливіше: намагайтеся бути добрими. Люди приходять зі своєю фрустрацією і часто питають не найкращим чином, але постарайтеся бути якомога доброзичливішими. 🤗\n\nІдея в тому, щоб спільнота **FastAPI** була доброзичливою та гостинною. Водночас не терпіть булінг чи неповажну поведінку щодо інших. Ми маємо піклуватися одне про одного.\n\n---\n\nОсь як допомагати іншим із питаннями (у discussions або issues):\n\n### Зрозумійте питання { #understand-the-question }\n\n* Перевірте, чи розумієте ви **мету** та варіант використання людини, яка питає.\n\n* Потім перевірте, чи **чітке** саме питання (переважна більшість — це питання).\n\n* Часто запит стосується уявного рішення користувача, але може бути **краще**. Якщо ви краще зрозумієте проблему та варіант використання, зможете запропонувати кращу **альтернативу**.\n\n* Якщо ви не розумієте питання, попросіть більше **подробиць**.\n\n### Відтворіть проблему { #reproduce-the-problem }\n\nУ більшості випадків і запитань мова йде про **оригінальний код** людини.\n\nЧасто вони наводять лише фрагмент коду, але цього недостатньо, щоб **відтворити проблему**.\n\n* Ви можете попросити надати [мінімальний, відтворюваний приклад](https://stackoverflow.com/help/minimal-reproducible-example), який ви зможете **скопіювати-вставити** і запустити локально, щоб побачити ту саму помилку або поведінку, яку бачать вони, або краще зрозуміти їхній варіант використання.\n\n* Якщо ви дуже щедрі, можете спробувати **створити такий приклад** самостійно, лише на основі опису проблеми. Просто майте на увазі, що це може зайняти багато часу, і краще спочатку попросити їх уточнити проблему.\n\n### Запропонуйте рішення { #suggest-solutions }\n\n* Після того як ви змогли зрозуміти питання, дайте можливу **відповідь**.\n\n* Часто краще зрозуміти їхню **первинну проблему або варіант використання**, адже може бути кращий спосіб її вирішити, ніж те, що вони намагаються зробити.\n\n### Попросіть закрити { #ask-to-close }\n\nЯкщо вони відповіли, дуже ймовірно, що ви розв'язали їхню проблему. Вітаю, **ви герой**! 🦸\n\n* Тепер, якщо це вирішило їхню проблему, ви можете попросити:\n\n    * У GitHub Discussions: позначити коментар як **відповідь**.\n    * У GitHub Issues: **закрити** issue.\n\n## Стежте за репозиторієм GitHub { #watch-the-github-repository }\n\nВи можете «спостерігати» за FastAPI на GitHub (натиснувши кнопку «watch» у верхньому правому куті): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). 👀\n\nЯкщо вибрати «Watching» замість «Releases only», ви отримуватимете сповіщення, коли хтось створює нове issue або питання. Ви також можете вказати, що хочете отримувати сповіщення лише про нові issues, або discussions, або PR тощо.\n\nТоді ви зможете спробувати допомогти їм вирішити ці питання.\n\n## Ставте питання { #ask-questions }\n\nВи можете [створити нове питання](https://github.com/fastapi/fastapi/discussions/new?category=questions) у репозиторії GitHub, наприклад, щоб:\n\n* Поставити **питання** або запитати про **проблему**.\n* Запропонувати нову **можливість**.\n\n**Примітка**: якщо ви це зробите, я попрошу вас також допомагати іншим. 😉\n\n## Переглядайте запити на витяг { #review-pull-requests }\n\nВи можете допомогти мені переглядати запити на витяг інших.\n\nІ знову, будь ласка, намагайтеся бути якомога доброзичливішими. 🤗\n\n---\n\nОсь що слід пам'ятати і як переглядати запит на витяг:\n\n### Зрозумійте проблему { #understand-the-problem }\n\n* Спочатку переконайтеся, що ви **розумієте проблему**, яку намагається вирішити запит на витяг. Може бути довша дискусія у GitHub Discussion або issue.\n\n* Також є велика ймовірність, що запит на витяг насправді не потрібен, бо проблему можна розв'язати **іншим способом**. Тоді ви можете про це запропонувати або запитати.\n\n### Не переймайтеся стилем { #dont-worry-about-style }\n\n* Не надто хвилюйтеся про стиль повідомлень фіксацій, я зроблю squash and merge, налаштувавши фіксацію вручну.\n\n* Також не переймайтеся правилами стилю, вже є автоматизовані інструменти, що це перевіряють.\n\nА якщо будуть інші вимоги щодо стилю чи узгодженості, я попрошу про це безпосередньо або додам зверху фіксації з потрібними змінами.\n\n### Перевірте код { #check-the-code }\n\n* Перегляньте та прочитайте код, оцініть, чи він має сенс, **запустіть його локально** і перевірте, чи справді він розв'язує проблему.\n\n* Потім залиште **коментар**, що ви це зробили, так я знатиму, що ви справді перевірили.\n\n/// info\n\nНа жаль, я не можу просто довіряти PR, які мають кілька схвалень.\n\nБувало не раз, що PR мали 3, 5 або більше схвалень, мабуть тому, що опис привабливий, але коли я перевіряв PR, вони виявлялися зламаними, мали помилку або не розв'язували заявлену проблему. 😅\n\nТож дуже важливо, щоб ви справді прочитали і запустили код та повідомили в коментарях, що ви це зробили. 🤓\n\n///\n\n* Якщо PR можна якось спростити, ви можете про це попросити, але немає потреби бути надто прискіпливими, адже може бути багато суб'єктивних точок зору (і в мене також є своя 🙈), тож краще зосередитися на фундаментальних речах.\n\n### Тести { #tests }\n\n* Допоможіть перевірити, що PR має **тести**.\n\n* Переконайтеся, що тести **падають** до PR. 🚨\n\n* Потім перевірте, що тести **проходять** після PR. ✅\n\n* Багато PRів не мають тестів, ви можете **нагадати** додати тести або навіть **запропонувати** деякі тести самі. Це одна з речей, яка найбільше забирає часу, і ви дуже допоможете.\n\n* Потім також прокоментуйте, що саме ви спробували, так я знатиму, що ви це перевірили. 🤓\n\n## Створіть запит на витяг { #create-a-pull-request }\n\nВи можете [зробити внесок](contributing.md) у вихідний код із запитами на витяг, наприклад:\n\n* Щоб виправити описку, знайдену в документації.\n* Щоб поділитися статтею, відео або подкастом про FastAPI, який ви створили або знайшли, [відредагувавши цей файл](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml).\n    * Обов'язково додайте ваше посилання на початок відповідного розділу.\n* Щоб допомогти [перекласти документацію](contributing.md#translations) вашою мовою.\n    * Ви також можете допомогти з переглядом перекладів, створених іншими.\n* Щоб запропонувати нові розділи документації.\n* Щоб виправити наявну проблему/помилку.\n    * Обов'язково додайте тести.\n* Щоб додати нову можливість.\n    * Обов'язково додайте тести.\n    * Обов'язково додайте документацію, якщо це доречно.\n\n## Допоможіть підтримувати FastAPI { #help-maintain-fastapi }\n\nДопоможіть мені підтримувати **FastAPI**! 🤓\n\nРоботи багато, і більшу її частину можете зробити **ВИ**.\n\nОсновні завдання, які ви можете виконувати вже зараз:\n\n* [Допомагайте іншим з питаннями на GitHub](#help-others-with-questions-in-github) (див. розділ вище).\n* [Переглядайте запити на витяг](#review-pull-requests) (див. розділ вище).\n\nЦі два завдання **найбільше споживають час**. Це основна робота з підтримки FastAPI.\n\nЯкщо ви можете допомогти мені з цим, **ви допомагаєте підтримувати FastAPI** і гарантуєте, що він **рухатиметься швидше й краще**. 🚀\n\n## Долучайтеся до чату { #join-the-chat }\n\nДолучайтеся до 👥 [серверу чату Discord](https://discord.gg/VQjSZaeJmf) 👥 і спілкуйтеся з іншими в спільноті FastAPI.\n\n/// tip\n\nДля запитань ставте їх у [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions), там значно вища ймовірність, що вам допоможуть [Експерти FastAPI](fastapi-people.md#fastapi-experts).\n\nВикористовуйте чат лише для інших загальних розмов.\n\n///\n\n### Не використовуйте чат для запитань { #dont-use-the-chat-for-questions }\n\nМайте на увазі, що оскільки чати дозволяють більше «вільної розмови», легко ставити надто загальні питання, на які складніше відповісти, тож ви можете не отримати відповідей.\n\nУ GitHub шаблон підкаже вам, як написати правильне питання, щоб ви легше отримали хорошу відповідь, або навіть вирішили проблему самостійно ще до запиту. І в GitHub я можу гарантувати, що завжди на все відповім, навіть якщо це займе трохи часу. Особисто я не можу робити це в чатах. 😅\n\nРозмови в чатах також не так просто шукати, як у GitHub, тож питання та відповіді можуть загубитися. І лише ті, що в GitHub, зараховуються, щоб стати [Експертом FastAPI](fastapi-people.md#fastapi-experts), тож швидше за все ви отримаєте більше уваги саме в GitHub.\n\nЗ іншого боку, у чатах є тисячі користувачів, тож дуже ймовірно, що ви майже завжди знайдете там співрозмовника. 😄\n\n## Спонсоруйте автора { #sponsor-the-author }\n\nЯкщо ваш **продукт/компанія** залежить від **FastAPI** або пов'язана з ним і ви хочете охопити його користувачів, ви можете спонсорувати автора (мене) через [GitHub sponsors](https://github.com/sponsors/tiangolo). Залежно від рівня ви можете отримати додаткові переваги, наприклад значок у документації. 🎁\n\n---\n\nДякую! 🚀\n"
  },
  {
    "path": "docs/uk/docs/history-design-future.md",
    "content": "# Історія, проєктування і майбутнє { #history-design-and-future }\n\nДеякий час тому [користувач **FastAPI** запитав](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920):\n\n> Яка історія цього проєкту? Здається, він нізвідки за кілька тижнів став чудовим [...]\n\nОсь трохи цієї історії.\n\n## Альтернативи { #alternatives }\n\nЯ створював API зі складними вимогами протягом кількох років (машинне навчання, розподілені системи, асинхронні завдання, бази даних NoSQL тощо), очолюючи кілька команд розробників.\n\nУ межах цього мені довелося досліджувати, тестувати й використовувати багато альтернатив.\n\nІсторія **FastAPI** значною мірою - це історія його попередників.\n\nЯк сказано в розділі [Альтернативи](alternatives.md):\n\n<blockquote markdown=\"1\">\n\n**FastAPI** не існував би без попередньої роботи інших.\n\nБуло створено багато інструментів, які надихнули на його створення.\n\nЯ роками уникав створення нового фреймворку. Спочатку я намагався вирішити всі можливості, які покриває **FastAPI**, використовуючи різні фреймворки, плагіни та інструменти.\n\nАле в певний момент не залишилося іншого варіанту, окрім створити щось, що надає всі ці можливості, узявши найкращі ідеї з попередніх інструментів і поєднавши їх якнайкраще, використовуючи можливості самої мови, яких раніше взагалі не було (підказки типів Python 3.6+).\n\n</blockquote>\n\n## Дослідження { #investigation }\n\nВикористовуючи всі попередні альтернативи, я мав змогу повчитися в кожної, узяти ідеї й поєднати їх якнайкраще для себе та команд розробників, з якими працював.\n\nНаприклад, було очевидно, що в ідеалі все має ґрунтуватися на стандартних підказках типів Python.\n\nТакож найкращим підходом було використовувати вже наявні стандарти.\n\nТож, ще до початку написання коду **FastAPI**, я провів кілька місяців, вивчаючи специфікації OpenAPI, Схеми JSON, OAuth2 тощо. Розуміючи їхні взаємозв'язки, перетини та відмінності.\n\n## Проєктування { #design }\n\nПотім я приділив час проєктуванню «API» для розробника, яке я хотів мати як користувач (як розробник, що використовує FastAPI).\n\nЯ протестував кілька ідей у найпопулярніших Python-редакторах: PyCharm, VS Code, редакторах на основі Jedi.\n\nЗа даними [Python Developer Survey](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools), це охоплює близько 80% користувачів.\n\nЦе означає, що **FastAPI** спеціально тестувався з редакторами, якими користуються 80% розробників Python. І оскільки більшість інших редакторів працюють подібно, усі ці переваги мають працювати практично у всіх редакторах.\n\nТак я зміг знайти найкращі способи максимально зменшити дублювання коду, забезпечити автодоповнення всюди, перевірки типів і помилок тощо.\n\nІ все це так, щоб надати найкращий досвід розробки для всіх розробників.\n\n## Вимоги { #requirements }\n\nПісля перевірки кількох альтернатив я вирішив використовувати [**Pydantic**](https://docs.pydantic.dev/) через його переваги.\n\nПотім я зробив внески до нього, щоб зробити його повністю сумісним із Схемою JSON, додати підтримку різних способів оголошення обмежень і поліпшити підтримку редакторів (перевірки типів, автодоповнення) на основі тестів у кількох редакторах.\n\nПід час розробки я також зробив внески до [**Starlette**](https://www.starlette.dev/), іншої ключової залежності.\n\n## Розробка { #development }\n\nКоли я взявся безпосередньо за створення **FastAPI**, більшість складових уже були на місцях: дизайн визначено, вимоги та інструменти підготовлено, знання про стандарти й специфікації - чіткі та свіжі.\n\n## Майбутнє { #future }\n\nНа цей момент уже зрозуміло, що **FastAPI** зі своїми ідеями корисний для багатьох.\n\nЙого обирають замість попередніх альтернатив, бо він краще відповідає багатьом сценаріям використання.\n\nБагато розробників і команд уже залежать від **FastAPI** у своїх проєктах (включно зі мною та моєю командою).\n\nАле попереду ще багато покращень і можливостей.\n\n**FastAPI** має велике майбутнє.\n\nІ [ваша допомога](help-fastapi.md) дуже цінується.\n"
  },
  {
    "path": "docs/uk/docs/how-to/authentication-error-status-code.md",
    "content": "# Використовуйте старі коди статусу помилки автентифікації 403 { #use-old-403-authentication-error-status-codes }\n\nДо версії FastAPI `0.122.0`, коли інтегровані засоби безпеки повертали клієнту помилку після невдалої автентифікації, вони використовували HTTP код статусу `403 Forbidden`.\n\nПочинаючи з версії FastAPI `0.122.0`, вони використовують більш доречний HTTP код статусу `401 Unauthorized` і повертають змістовний заголовок `WWW-Authenticate` у відповіді, відповідно до специфікацій HTTP, [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1), [RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized).\n\nАле якщо з якоїсь причини ваші клієнти залежать від старої поведінки, ви можете повернутися до неї, переписавши метод `make_not_authenticated_error` у ваших класах безпеки.\n\nНаприклад, ви можете створити підклас `HTTPBearer`, який повертатиме помилку `403 Forbidden` замість типового `401 Unauthorized`:\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip | Порада\n\nЗверніть увагу, що функція повертає екземпляр винятку, вона не породжує його. Породження відбувається в іншій частині внутрішнього коду.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/how-to/conditional-openapi.md",
    "content": "# Умовний OpenAPI { #conditional-openapi }\n\nЯкщо потрібно, ви можете використовувати налаштування і змінні оточення, щоб умовно налаштовувати OpenAPI залежно від середовища, а також повністю вимикати його.\n\n## Про безпеку, API та документацію { #about-security-apis-and-docs }\n\nПриховування інтерфейсів документації у продукційному середовищі не має бути способом захисту вашого API.\n\nЦе не додає жодної додаткової безпеки вашому API, операції шляху й надалі будуть доступні там, де вони є.\n\nЯкщо у вашому коді є вразливість, вона залишиться.\n\nПриховування документації лише ускладнює розуміння того, як взаємодіяти з вашим API, і може ускладнити для вас його налагодження у продакшні. Це можна вважати просто формою [Безпека через неясність](https://en.wikipedia.org/wiki/Security_through_obscurity).\n\nЯкщо ви хочете захистити ваш API, є кілька кращих дій, які ви можете зробити, наприклад:\n\n- Переконайтеся, що у вас добре визначені моделі Pydantic для тіл запитів і відповідей.\n- Налаштуйте потрібні дозволи та ролі за допомогою залежностей.\n- Ніколи не зберігайте паролі у відкритому вигляді, лише хеші паролів.\n- Реалізуйте та використовуйте відомі криптографічні інструменти, як-от pwdlib і токени JWT.\n- Додайте більш детальний контроль дозволів із областями OAuth2 там, де це потрібно.\n- ...тощо.\n\nВтім, у вас може бути дуже специфічний випадок використання, коли справді потрібно вимкнути документацію API для певного середовища (наприклад, для продакшну) або залежно від конфігурацій зі змінних оточення.\n\n## Умовний OpenAPI з налаштувань і змінних оточення { #conditional-openapi-from-settings-and-env-vars }\n\nВи можете легко використати ті самі налаштування Pydantic, щоб налаштувати згенерований OpenAPI та інтерфейси документації.\n\nНаприклад:\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\nТут ми оголошуємо налаштування `openapi_url` з тим самим значенням за замовчуванням `\"/openapi.json\"`.\n\nПотім ми використовуємо його під час створення застосунку `FastAPI`.\n\nДалі ви можете вимкнути OpenAPI (включно з інтерфейсами документації), встановивши змінну оточення `OPENAPI_URL` у пусту строку, наприклад:\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nПотім, якщо ви перейдете за URL `/openapi.json`, `/docs` або `/redoc`, ви просто отримаєте помилку `404 Not Found` на кшталт:\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/uk/docs/how-to/configure-swagger-ui.md",
    "content": "# Налаштуйте Swagger UI { #configure-swagger-ui }\n\nВи можете налаштувати додаткові [параметри Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\nЩоб їх налаштувати, передайте аргумент `swagger_ui_parameters` під час створення об’єкта додатка `FastAPI()` або до функції `get_swagger_ui_html()`.\n\n`swagger_ui_parameters` отримує словник із налаштуваннями, що передаються безпосередньо до Swagger UI.\n\nFastAPI перетворює ці налаштування на **JSON**, щоб зробити їх сумісними з JavaScript, оскільки саме це потрібно Swagger UI.\n\n## Вимкніть підсвітку синтаксису { #disable-syntax-highlighting }\n\nНаприклад, ви можете вимкнути підсвітку синтаксису в Swagger UI.\n\nБез змін у налаштуваннях підсвітка синтаксису увімкнена за замовчуванням:\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\nАле ви можете вимкнути її, встановивши `syntaxHighlight` у `False`:\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n...після цього Swagger UI більше не показуватиме підсвітку синтаксису:\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## Змініть тему { #change-the-theme }\n\nТак само ви можете задати тему підсвітки синтаксису ключем `\"syntaxHighlight.theme\"` (зверніть увагу, що посередині є крапка):\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\nЦе налаштування змінить колірну тему підсвітки синтаксису:\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## Змініть параметри Swagger UI за замовчуванням { #change-default-swagger-ui-parameters }\n\nFastAPI містить деякі параметри конфігурації за замовчуванням, що підходять для більшості випадків.\n\nВони включають такі типові налаштування:\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\nВи можете переписати будь-яке з них, задавши інше значення в аргументі `swagger_ui_parameters`.\n\nНаприклад, щоб вимкнути `deepLinking`, ви можете передати такі налаштування до `swagger_ui_parameters`:\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## Інші параметри Swagger UI { #other-swagger-ui-parameters }\n\nЩоб побачити всі можливі налаштування, які ви можете використовувати, прочитайте офіційну [документацію щодо параметрів Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/).\n\n## Налаштування лише для JavaScript { #javascript-only-settings }\n\nSwagger UI також дозволяє інші налаштування як об’єкти, що є тільки для **JavaScript** (наприклад, функції JavaScript).\n\nFastAPI також включає такі налаштування `presets`, що є лише для JavaScript:\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\nЦе об’єкти **JavaScript**, а не строки, тому ви не можете передати їх безпосередньо з коду Python.\n\nЯкщо вам потрібно використати такі налаштування лише для JavaScript, скористайтеся одним із методів вище. Повністю перепишіть операцію шляху Swagger UI та вручну напишіть потрібний JavaScript.\n"
  },
  {
    "path": "docs/uk/docs/how-to/custom-docs-ui-assets.md",
    "content": "# Користувацькі статичні ресурси інтерфейсу документації (самохостинг) { #custom-docs-ui-static-assets-self-hosting }\n\nДокументація API використовує **Swagger UI** і **ReDoc**, і кожному з них потрібні файли JavaScript та CSS.\n\nТипово ці файли віддаються з <abbr title=\"Content Delivery Network - Мережа доставки контенту: Сервіс, зазвичай складений з кількох серверів, що надає статичні файли, як-от JavaScript і CSS. Його зазвичай використовують, щоб віддавати ці файли з сервера, ближчого до клієнта, покращуючи продуктивність.\">CDN</abbr>.\n\nАле це можна налаштувати: ви можете вказати конкретний CDN або віддавати файли самостійно.\n\n## Власний CDN для JavaScript і CSS { #custom-cdn-for-javascript-and-css }\n\nПрипустімо, що ви хочете використовувати інший <abbr title=\"Content Delivery Network - Мережа доставки контенту\">CDN</abbr>, наприклад `https://unpkg.com/`.\n\nЦе може бути корисно, якщо, наприклад, ви живете в країні, що обмежує деякі URL-адреси.\n\n### Вимкніть автоматичну документацію { #disable-the-automatic-docs }\n\nПерший крок - вимкнути автоматичну документацію, адже типово вона використовує стандартний CDN.\n\nЩоб їх вимкнути, встановіть їхні URL у `None` під час створення вашого застосунку `FastAPI`:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### Додайте користувацьку документацію { #include-the-custom-docs }\n\nТепер ви можете створити *операції шляху* для користувацької документації.\n\nВи можете перевикористати внутрішні функції FastAPI для створення HTML-сторінок документації і передати їм потрібні аргументи:\n\n- `openapi_url`: URL, за яким HTML-сторінка документації зможе отримати схему OpenAPI для вашого API. Тут можна використати атрибут `app.openapi_url`.\n- `title`: заголовок вашого API.\n- `oauth2_redirect_url`: тут можна використати `app.swagger_ui_oauth2_redirect_url`, щоб узяти значення за замовчуванням.\n- `swagger_js_url`: URL, за яким HTML для Swagger UI зможе отримати файл **JavaScript**. Це URL вашого користувацького CDN.\n- `swagger_css_url`: URL, за яким HTML для Swagger UI зможе отримати файл **CSS**. Це URL вашого користувацького CDN.\n\nАналогічно для ReDoc...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip | Порада\n\n*Операція шляху* для `swagger_ui_redirect` - це допоміжний маршрут, коли ви використовуєте OAuth2.\n\nЯкщо ви інтегруєте ваш API з провайдером OAuth2, ви зможете автентифікуватися і повернутися до документації API з отриманими обліковими даними. І взаємодіяти з ним, використовуючи реальну автентифікацію OAuth2.\n\nSwagger UI впорається з цим «за лаштунками», але йому потрібен цей «redirect» хелпер.\n\n///\n\n### Створіть операцію шляху для перевірки { #create-a-path-operation-to-test-it }\n\nТепер, щоб перевірити, що все працює, створіть *операцію шляху*:\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### Перевірте { #test-it }\n\nТепер ви маєте змогу відкрити документацію за [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) і перезавантажити сторінку, вона завантажить ці ресурси з нового CDN.\n\n## Самохостинг JavaScript і CSS для документації { #self-hosting-javascript-and-css-for-docs }\n\nСамохостинг JavaScript і CSS може бути корисним, якщо, наприклад, ваш застосунок має працювати офлайн, без доступу до Інтернету, або в локальній мережі.\n\nТут ви побачите, як віддавати ці файли самостійно, у тому самому застосунку FastAPI, і налаштувати документацію на їх використання.\n\n### Структура файлів проєкту { #project-file-structure }\n\nПрипустімо, що структура файлів вашого проєкту виглядає так:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\nТепер створіть каталог для збереження цих статичних файлів.\n\nНова структура файлів може виглядати так:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### Завантажте файли { #download-the-files }\n\nЗавантажте статичні файли, потрібні для документації, і помістіть їх у каталог `static/`.\n\nВи, ймовірно, можете натиснути правою кнопкою на кожному посиланні і вибрати опцію на кшталт «Зберегти посилання як...».\n\n**Swagger UI** використовує файли:\n\n- [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n- [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\nА **ReDoc** використовує файл:\n\n- [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\nПісля цього ваша структура файлів може виглядати так:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### Обслуговуйте статичні файли { #serve-the-static-files }\n\n- Імпортуйте `StaticFiles`.\n- Змонтуйте екземпляр `StaticFiles()` у певному шляху.\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### Перевірте статичні файли { #test-the-static-files }\n\nЗапустіть ваш застосунок і перейдіть до [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js).\n\nВи маєте побачити дуже довгий файл JavaScript для **ReDoc**.\n\nВін може починатися приблизно так:\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\nЦе підтверджує, що ви можете віддавати статичні файли з вашого застосунку і що ви розмістили статичні файли для документації у правильному місці.\n\nТепер ми можемо налаштувати застосунок на використання цих статичних файлів для документації.\n\n### Вимкніть автоматичну документацію для статичних файлів { #disable-the-automatic-docs-for-static-files }\n\nЯк і при використанні користувацького CDN, першим кроком є вимкнення автоматичної документації, оскільки типово вона використовує CDN.\n\nЩоб їх вимкнути, встановіть їхні URL у `None` під час створення вашого застосунку `FastAPI`:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### Додайте користувацьку документацію для статичних файлів { #include-the-custom-docs-for-static-files }\n\nАналогічно користувацькому CDN, тепер ви можете створити *операції шляху* для користувацької документації.\n\nЗнову ж, ви можете перевикористати внутрішні функції FastAPI для створення HTML-сторінок документації і передати їм потрібні аргументи:\n\n- `openapi_url`: URL, за яким HTML-сторінка документації зможе отримати схему OpenAPI для вашого API. Тут можна використати атрибут `app.openapi_url`.\n- `title`: заголовок вашого API.\n- `oauth2_redirect_url`: тут можна використати `app.swagger_ui_oauth2_redirect_url`, щоб узяти значення за замовчуванням.\n- `swagger_js_url`: URL, за яким HTML для Swagger UI зможе отримати файл **JavaScript**. **Це той файл, який тепер віддає ваш власний застосунок**.\n- `swagger_css_url`: URL, за яким HTML для Swagger UI зможе отримати файл **CSS**. **Це той файл, який тепер віддає ваш власний застосунок**.\n\nАналогічно для ReDoc...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip | Порада\n\n*Операція шляху* для `swagger_ui_redirect` - це допоміжний маршрут, коли ви використовуєте OAuth2.\n\nЯкщо ви інтегруєте ваш API з провайдером OAuth2, ви зможете автентифікуватися і повернутися до документації API з отриманими обліковими даними. І взаємодіяти з ним, використовуючи реальну автентифікацію OAuth2.\n\nSwagger UI впорається з цим «за лаштунками», але йому потрібен цей «redirect» хелпер.\n\n///\n\n### Створіть операцію шляху для перевірки статичних файлів { #create-a-path-operation-to-test-static-files }\n\nТепер, щоб перевірити, що все працює, створіть *операцію шляху*:\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### Перевірте UI зі статичними файлами { #test-static-files-ui }\n\nТепер ви маєте змогу вимкнути WiFi, відкрити документацію за [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) і перезавантажити сторінку.\n\nІ навіть без Інтернету ви зможете побачити документацію для вашого API і взаємодіяти з ним.\n"
  },
  {
    "path": "docs/uk/docs/how-to/custom-request-and-route.md",
    "content": "# Користувацькі класи Request та APIRoute { #custom-request-and-apiroute-class }\n\nУ деяких випадках ви можете захотіти перевизначити логіку, яку використовують класи `Request` та `APIRoute`.\n\nЗокрема, це може бути доброю альтернативою логіці в проміжному програмному забезпеченні.\n\nНаприклад, якщо потрібно прочитати або змінити тіло запиту до того, як його обробить ваш застосунок.\n\n/// danger | Обережно\n\nЦе «просунута» можливість.\n\nЯкщо ви тільки починаєте працювати з **FastAPI**, можливо, варто пропустити цей розділ.\n\n///\n\n## Випадки використання { #use-cases }\n\nДеякі варіанти використання:\n\n- Перетворення не-JSON тіл запитів на JSON (наприклад, [`msgpack`](https://msgpack.org/index.html)).\n- Розпакування тіл запитів, стиснених gzip.\n- Автоматичне логування всіх тіл запитів.\n\n## Обробка користувацьких кодувань тіла запиту { #handling-custom-request-body-encodings }\n\nРозгляньмо, як використати користувацький підклас `Request` для розпакування gzip-запитів.\n\nА також підклас `APIRoute`, щоб застосувати цей користувацький клас запиту.\n\n### Створіть користувацький клас `GzipRequest` { #create-a-custom-gziprequest-class }\n\n/// tip | Порада\n\nЦе навчальний приклад, щоб продемонструвати принцип роботи. Якщо вам потрібна підтримка Gzip, скористайтеся вбудованим [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware).\n\n///\n\nСпочатку створимо клас `GzipRequest`, який перевизначить метод `Request.body()`, щоб розпаковувати тіло за наявності відповідного заголовка.\n\nЯкщо в заголовку немає `gzip`, він не намагатиметься розпаковувати тіло.\n\nТаким чином один і той самий клас маршруту зможе обробляти як стиснені gzip, так і нестиснені запити.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### Створіть користувацький клас `GzipRoute` { #create-a-custom-gziproute-class }\n\nДалі створимо користувацький підклас `fastapi.routing.APIRoute`, який використовуватиме `GzipRequest`.\n\nЦього разу він перевизначить метод `APIRoute.get_route_handler()`.\n\nЦей метод повертає функцію. І саме ця функція прийме запит і поверне відповідь.\n\nТут ми використовуємо її, щоб створити `GzipRequest` з початкового запиту.\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | Технічні деталі\n\nУ `Request` є атрибут `request.scope` - це просто Python `dict`, що містить метадані, пов'язані із запитом.\n\nТакож `Request` має `request.receive` - це функція для «отримання» тіла запиту.\n\n`scope` `dict` і функція `receive` є частиною специфікації ASGI.\n\nІ саме ці дві сутності - `scope` та `receive` - потрібні для створення нового екземпляра `Request`.\n\nЩоб дізнатися більше про `Request`, перегляньте [документацію Starlette про запити](https://www.starlette.dev/requests/).\n\n///\n\nЄдине, що робить інакше функція, повернена `GzipRequest.get_route_handler`, - перетворює `Request` на `GzipRequest`.\n\nЗавдяки цьому наш `GzipRequest` подбає про розпакування даних (за потреби) перед передаванням їх у наші *операції шляху*.\n\nПісля цього вся логіка обробки залишається тією самою.\n\nА завдяки змінам у `GzipRequest.body` тіло запиту за потреби буде автоматично розпаковане під час завантаження **FastAPI**.\n\n## Доступ до тіла запиту в обробнику виключень { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip | Порада\n\nЩоб розв’язати це саме завдання, скоріш за все, простіше використати `body` у користувацькому обробнику `RequestValidationError` ([Обробка помилок](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)).\n\nАле цей приклад усе ще корисний і показує, як взаємодіяти з внутрішніми компонентами.\n\n///\n\nМи також можемо скористатися цим підходом, щоб отримати доступ до тіла запиту в обробнику виключень.\n\nУсе, що потрібно, - обробити запит усередині блоку `try`/`except`:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\nЯкщо станеться виключення, екземпляр `Request` усе ще буде у видимості, тож ми зможемо прочитати й використати тіло запиту під час обробки помилки:\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## Користувацький клас `APIRoute` у маршрутизаторі { #custom-apiroute-class-in-a-router }\n\nМожна також встановити параметр `route_class` у `APIRouter`:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\nУ цьому прикладі *операції шляху* в `router` використовуватимуть користувацький клас `TimedRoute` і матимуть додатковий заголовок відповіді `X-Response-Time` із часом, витраченим на формування відповіді:\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/uk/docs/how-to/extending-openapi.md",
    "content": "# Розширення OpenAPI { #extending-openapi }\n\nУ деяких випадках вам може знадобитися змінити згенеровану схему OpenAPI.\n\nУ цьому розділі ви побачите як це зробити.\n\n## Звичайний процес { #the-normal-process }\n\nЗвичайний (типовий) процес такий.\n\nЗастосунок `FastAPI` (екземпляр) має метод `.openapi()`, який має повертати схему OpenAPI.\n\nПід час створення об'єкта застосунку реєструється *операція шляху* для `/openapi.json` (або для того значення, яке ви встановили в `openapi_url`).\n\nВона просто повертає відповідь JSON з результатом методу `.openapi()` застосунку.\n\nТипово метод `.openapi()` перевіряє властивість `.openapi_schema`, і якщо там вже є дані, повертає їх.\n\nЯкщо ні, він генерує їх за допомогою утилітарної функції `fastapi.openapi.utils.get_openapi`.\n\nФункція `get_openapi()` приймає такі параметри:\n\n- `title`: Заголовок OpenAPI, показується в документації.\n- `version`: Версія вашого API, напр. `2.5.0`.\n- `openapi_version`: Версія специфікації OpenAPI, що використовується. Типово остання: `3.1.0`.\n- `summary`: Короткий підсумок API.\n- `description`: Опис вашого API; може містити markdown і буде показаний у документації.\n- `routes`: Список маршрутів, це кожна з зареєстрованих *операцій шляху*. Їх беруть з `app.routes`.\n\n/// info | Інформація\n\nПараметр `summary` доступний в OpenAPI 3.1.0 і вище, підтримується FastAPI 0.99.0 і вище.\n\n///\n\n## Переписування типових значень { #overriding-the-defaults }\n\nВикористовуючи наведене вище, ви можете скористатися тією ж утилітарною функцією для генерації схеми OpenAPI і переписати потрібні частини.\n\nНаприклад, додаймо [розширення OpenAPI ReDoc для додавання власного логотипа](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo).\n\n### Звичайний **FastAPI** { #normal-fastapi }\n\nСпочатку напишіть ваш застосунок **FastAPI** як зазвичай:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### Згенерувати схему OpenAPI { #generate-the-openapi-schema }\n\nДалі використайте ту ж утилітарну функцію для генерації схеми OpenAPI всередині функції `custom_openapi()`:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### Змінити схему OpenAPI { #modify-the-openapi-schema }\n\nТепер можна додати розширення ReDoc, додавши власний `x-logo` до «об'єкта» `info` у схемі OpenAPI:\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### Кешувати схему OpenAPI { #cache-the-openapi-schema }\n\nВи можете використовувати властивість `.openapi_schema` як «кеш» для збереження згенерованої схеми.\n\nТак вашому застосунку не доведеться щоразу генерувати схему, коли користувач відкриває документацію вашого API.\n\nВона буде згенерована лише один раз, а потім та сама закешована схема використовуватиметься для наступних запитів.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### Переписати метод { #override-the-method }\n\nТепер ви можете замінити метод `.openapi()` вашою новою функцією.\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### Перевірте { #check-it }\n\nКоли ви перейдете за адресою [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc), побачите, що використовується ваш власний логотип (у цьому прикладі логотип **FastAPI**):\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/uk/docs/how-to/general.md",
    "content": "# Загальне - Як зробити - Рецепти { #general-how-to-recipes }\n\nНижче наведено кілька вказівок до інших розділів документації для загальних або частих питань.\n\n## Фільтрування даних - Безпека { #filter-data-security }\n\nЩоб гарантувати, що ви не повертаєте більше даних, ніж слід, прочитайте документацію [Навчальний посібник - Модель відповіді - Тип повернення](../tutorial/response-model.md).\n\n## Оптимізувати продуктивність відповіді - Модель відповіді - Тип повернення { #optimize-response-performance-response-model-return-type }\n\nЩоб оптимізувати продуктивність під час повернення даних JSON, використовуйте тип повернення або модель відповіді, таким чином Pydantic виконуватиме серіалізацію в JSON на боці Rust, без проходження через Python. Докладніше читайте в документації [Навчальний посібник - Модель відповіді - Тип повернення](../tutorial/response-model.md).\n\n## Мітки документації - OpenAPI { #documentation-tags-openapi }\n\nЩоб додати мітки до ваших *операцій шляху* та згрупувати їх в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Мітки](../tutorial/path-operation-configuration.md#tags).\n\n## Короткий опис і опис - OpenAPI { #documentation-summary-and-description-openapi }\n\nЩоб додати короткий опис і опис до ваших *операцій шляху* і показати їх в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Короткий опис і опис](../tutorial/path-operation-configuration.md#summary-and-description).\n\n## Опис відповіді в документації - OpenAPI { #documentation-response-description-openapi }\n\nЩоб визначити опис відповіді, що відображається в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Опис відповіді](../tutorial/path-operation-configuration.md#response-description).\n\n## Позначити застарілою *операцію шляху* - OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\nЩоб позначити *операцію шляху* як застарілу і показати це в інтерфейсі документації, прочитайте документацію [Навчальний посібник - Налаштування операції шляху - Позначення як застаріле](../tutorial/path-operation-configuration.md#deprecate-a-path-operation).\n\n## Перетворити будь-які дані на сумісні з JSON { #convert-any-data-to-json-compatible }\n\nЩоб перетворити будь-які дані на сумісні з JSON, прочитайте документацію [Навчальний посібник - Кодувальник, сумісний з JSON](../tutorial/encoder.md).\n\n## Метадані OpenAPI - Документація { #openapi-metadata-docs }\n\nЩоб додати метадані до вашої схеми OpenAPI, зокрема ліцензію, версію, контактні дані тощо, прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md).\n\n## Власний URL OpenAPI { #openapi-custom-url }\n\nЩоб налаштувати URL OpenAPI (або прибрати його), прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md#openapi-url).\n\n## URL документації OpenAPI { #openapi-docs-urls }\n\nЩоб оновити URL, які використовуються для автоматично згенерованих інтерфейсів користувача документації, прочитайте документацію [Навчальний посібник - Метадані та URL документації](../tutorial/metadata.md#docs-urls).\n"
  },
  {
    "path": "docs/uk/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\nОскільки FastAPI базується на стандарті ASGI, дуже просто інтегрувати будь-яку бібліотеку GraphQL, сумісну з ASGI.\n\nВи можете поєднувати звичайні *операції шляху* FastAPI з GraphQL в одному застосунку.\n\n/// tip | Порада\n\nGraphQL розв’язує деякі дуже специфічні сценарії використання.\n\nПорівняно зі звичайними веб-API він має переваги та недоліки.\n\nПереконайтеся, що переваги для вашого випадку використання переважають недоліки. 🤓\n\n///\n\n## Бібліотеки GraphQL { #graphql-libraries }\n\nОсь деякі бібліотеки GraphQL з підтримкою ASGI. Ви можете використовувати їх із FastAPI:\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * З [документацією для FastAPI](https://strawberry.rocks/docs/integrations/fastapi)\n* [Ariadne](https://ariadnegraphql.org/)\n    * З [документацією для FastAPI](https://ariadnegraphql.org/docs/fastapi-integration)\n* [Tartiflette](https://tartiflette.io/)\n    * З [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) для інтеграції з ASGI\n* [Graphene](https://graphene-python.org/)\n    * З [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)\n\n## GraphQL зі Strawberry { #graphql-with-strawberry }\n\nЯкщо вам потрібен або ви хочете використовувати GraphQL, [Strawberry](https://strawberry.rocks/) - рекомендована бібліотека, адже її дизайн найближчий до дизайну FastAPI; усе базується на анотаціях типів.\n\nЗалежно від вашого сценарію використання ви можете надати перевагу іншій бібліотеці, але якби ви запитали мене, я, ймовірно, порадив би спробувати Strawberry.\n\nОсь невеликий приклад того, як інтегрувати Strawberry з FastAPI:\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\nБільше про Strawberry ви можете дізнатися в [документації Strawberry](https://strawberry.rocks/).\n\nІ також [документацію про Strawberry з FastAPI](https://strawberry.rocks/docs/integrations/fastapi).\n\n## Застарілий `GraphQLApp` зі Starlette { #older-graphqlapp-from-starlette }\n\nПопередні версії Starlette містили клас `GraphQLApp` для інтеграції з [Graphene](https://graphene-python.org/).\n\nЙого вилучено з Starlette як застарілий, але якщо у вас є код, що його використовував, ви можете легко мігрувати на [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3), який покриває той самий сценарій використання та має майже ідентичний інтерфейс.\n\n/// tip | Порада\n\nЯкщо вам потрібен GraphQL, я все ж рекомендую звернути увагу на [Strawberry](https://strawberry.rocks/), адже він базується на анотаціях типів, а не на власних класах і типах.\n\n///\n\n## Дізнайтеся більше { #learn-more }\n\nВи можете дізнатися більше про GraphQL в [офіційній документації GraphQL](https://graphql.org/).\n\nТакож ви можете почитати більше про кожну з цих бібліотек за наведеними посиланнями.\n"
  },
  {
    "path": "docs/uk/docs/how-to/index.md",
    "content": "# Як зробити - Рецепти { #how-to-recipes }\n\nТут ви побачите різні рецепти або керівництва «як зробити» з **різних тем**.\n\nБільшість із цих ідей є більш-менш **незалежними**, і в більшості випадків вам слід вивчати їх лише тоді, коли вони безпосередньо стосуються **вашого проєкту**.\n\nЯкщо щось здається цікавим і корисним для вашого проєкту, сміливо перевірте це, інакше, ймовірно, просто пропустіть.\n\n/// tip | Порада\n\nЯкщо ви хочете **вивчити FastAPI** у структурований спосіб (рекомендується), натомість прочитайте [Навчальний посібник - Посібник користувача](../tutorial/index.md) розділ за розділом.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# Перехід з Pydantic v1 на Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\nЯкщо у вас стара програма FastAPI, можливо, ви використовуєте Pydantic версії 1.\n\nFastAPI версії 0.100.0 підтримував як Pydantic v1, так і v2. Використовувалася та версія, яку ви встановили.\n\nFastAPI версії 0.119.0 запровадив часткову підтримку Pydantic v1 всередині Pydantic v2 (як `pydantic.v1`), щоб спростити перехід на v2.\n\nFastAPI 0.126.0 припинив підтримку Pydantic v1, водночас ще певний час підтримував `pydantic.v1`.\n\n/// warning | Попередження\n\nКоманда Pydantic припинила підтримку Pydantic v1 для останніх версій Python, починаючи з Python 3.14.\n\nЦе стосується і `pydantic.v1`, який більше не підтримується в Python 3.14 і новіших.\n\nЯкщо ви хочете використовувати найновіші можливості Python, вам потрібно переконатися, що ви використовуєте Pydantic v2.\n\n///\n\nЯкщо у вас стара програма FastAPI з Pydantic v1, нижче я покажу, як мігрувати на Pydantic v2, а також можливості FastAPI 0.119.0, які допоможуть з поступовою міграцією.\n\n## Офіційний посібник { #official-guide }\n\nУ Pydantic є офіційний [Посібник з міграції](https://docs.pydantic.dev/latest/migration/) з v1 на v2.\n\nТам описано, що змінилося, як перевірки тепер стали коректнішими та суворішими, можливі застереження тощо.\n\nПрочитайте його, щоб краще зрозуміти зміни.\n\n## Тести { #tests }\n\nПереконайтеся, що у вашій програмі є [тести](../tutorial/testing.md) і що ви запускаєте їх у системі безперервної інтеграції (CI).\n\nТак ви зможете виконати оновлення і впевнитися, що все працює як очікується.\n\n## `bump-pydantic` { #bump-pydantic }\n\nУ багатьох випадках, якщо ви використовуєте звичайні моделі Pydantic без налаштувань, більшу частину процесу міграції з Pydantic v1 на Pydantic v2 можна автоматизувати.\n\nВи можете скористатися [`bump-pydantic`](https://github.com/pydantic/bump-pydantic) від тієї ж команди Pydantic.\n\nЦей інструмент допоможе автоматично змінити більшість коду, який потрібно змінити.\n\nПісля цього запустіть тести й перевірте, чи все працює. Якщо так - ви все завершили. 😎\n\n## Pydantic v1 у v2 { #pydantic-v1-in-v2 }\n\nPydantic v2 містить усе з Pydantic v1 як підмодуль `pydantic.v1`. Але це більше не підтримується у версіях Python вище 3.13.\n\nЦе означає, що ви можете встановити останню версію Pydantic v2 та імпортувати і використовувати старі компоненти Pydantic v1 з цього підмодуля, ніби у вас встановлено старий Pydantic v1.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### Підтримка FastAPI для Pydantic v1 у v2 { #fastapi-support-for-pydantic-v1-in-v2 }\n\nПочинаючи з FastAPI 0.119.0, також є часткова підтримка Pydantic v1 всередині Pydantic v2, щоб спростити перехід на v2.\n\nТож ви можете оновити Pydantic до останньої версії 2 і змінити імпорти на використання підмодуля `pydantic.v1`, і в багатьох випадках усе просто запрацює.\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning | Попередження\n\nМайте на увазі, що оскільки команда Pydantic більше не підтримує Pydantic v1 у нових версіях Python, починаючи з Python 3.14, використання `pydantic.v1` також не підтримується в Python 3.14 і новіших.\n\n///\n\n### Pydantic v1 і v2 в одній програмі { #pydantic-v1-and-v2-on-the-same-app }\n\nPydantic не підтримує ситуацію, коли модель Pydantic v2 має власні поля, визначені як моделі Pydantic v1, або навпаки.\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n...але в одній програмі ви можете мати окремі моделі на Pydantic v1 і v2.\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\nУ деяких випадках можна навіть використовувати моделі і Pydantic v1, і v2 в одній операції шляху у вашій програмі FastAPI:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\nУ наведеному вище прикладі вхідна модель - це модель Pydantic v1, а вихідна модель (визначена як `response_model=ItemV2`) - модель Pydantic v2.\n\n### Параметри Pydantic v1 { #pydantic-v1-parameters }\n\nЯкщо вам потрібно використовувати деякі специфічні для FastAPI інструменти для параметрів, як-от `Body`, `Query`, `Form` тощо, з моделями Pydantic v1, ви можете імпортувати їх з `fastapi.temp_pydantic_v1_params`, поки завершуєте міграцію на Pydantic v2:\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### Покрокова міграція { #migrate-in-steps }\n\n/// tip | Порада\n\nСпершу спробуйте `bump-pydantic`: якщо ваші тести проходять і все працює - ви впоралися однією командою. ✨\n\n///\n\nЯкщо `bump-pydantic` не підходить для вашого випадку, скористайтеся підтримкою одночасно Pydantic v1 і v2 в одній програмі, щоб виконати поступову міграцію на Pydantic v2.\n\nСпочатку ви можете оновити Pydantic до останньої версії 2 і змінити імпорти на `pydantic.v1` для всіх ваших моделей.\n\nПотім починайте переносити моделі з Pydantic v1 на v2 групами, поступовими кроками. 🚶\n"
  },
  {
    "path": "docs/uk/docs/how-to/separate-openapi-schemas.md",
    "content": "# Окремі схеми OpenAPI для введення та виведення, чи ні { #separate-openapi-schemas-for-input-and-output-or-not }\n\nВідколи вийшов **Pydantic v2**, згенерований OpenAPI став трохи точнішим і більш коректним, ніж раніше. 😎\n\nНасправді подекуди буде навіть **дві схеми JSON** в OpenAPI для тієї самої моделі Pydantic: для введення та для виведення - залежно від наявності значень за замовчуванням.\n\nРозгляньмо, як це працює, і як це змінити за потреби.\n\n## Моделі Pydantic для введення та виведення { #pydantic-models-for-input-and-output }\n\nПрипустімо, у вас є модель Pydantic зі значеннями за замовчуванням, наприклад:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### Модель для введення { #model-for-input }\n\nЯкщо ви використовуєте цю модель як введення, як тут:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n…тоді поле `description` не буде обов'язковим, адже воно має значення за замовчуванням `None`.\n\n### Модель для введення в документації { #input-model-in-docs }\n\nУ документації ви побачите, що поле `description` не має **червоної зірочки** - воно не позначене як обов'язкове:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### Модель для виведення { #model-for-output }\n\nАле якщо ви використовуєте цю саму модель для виведення, як тут:\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n…тоді, оскільки `description` має значення за замовчуванням, якщо ви нічого не повернете для цього поля, воно все одно матиме це **значення за замовчуванням**.\n\n### Модель для даних відповіді при виведенні { #model-for-output-response-data }\n\nЯкщо ви скористаєтеся документацією та перевірите відповідь, навіть попри те, що код нічого не додав в одне з полів `description`, JSON-відповідь містить значення за замовчуванням (`null`):\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\nЦе означає, що воно **завжди матиме значення** - просто іноді це значення може бути `None` (або `null` у JSON).\n\nОтже, клієнтам, які використовують ваш API, не потрібно перевіряти, чи існує значення - вони можуть **припустити, що поле завжди буде присутнє**, але в окремих випадках воно матиме значення за замовчуванням `None`.\n\nУ OpenAPI це описується тим, що поле позначається як **обов'язкове**, адже воно завжди присутнє.\n\nТому Схема JSON для моделі може відрізнятися залежно від того, чи використовується вона для **введення або виведення**:\n- для **введення** `description` не буде обов'язковим\n- для **виведення** воно буде **обов'язковим** (і можливо `None`, або в термінах JSON - `null`)\n\n### Модель для виведення в документації { #model-for-output-in-docs }\n\nУ документації ви також можете перевірити модель для виведення: **і** `name`, і `description` позначені як **обов'язкові** червоною зірочкою:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### Модель для введення та виведення в документації { #model-for-input-and-output-in-docs }\n\nЯкщо відкрити всі наявні Схеми (схеми JSON) в OpenAPI, то ви побачите дві: `Item-Input` і `Item-Output`.\n\nДля `Item-Input` поле `description` **не є обов'язковим** - червоної зірочки немає.\n\nА для `Item-Output` `description` **є обов'язковим** - є червона зірочка.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\nЗавдяки цій можливості у **Pydantic v2** ваша документація API стає більш **точною**, а якщо у вас є згенеровані клієнти та SDK, вони також будуть точнішими - з кращим **досвідом розробника** та узгодженістю. 🎉\n\n## Не розділяти схеми { #do-not-separate-schemas }\n\nВтім іноді може знадобитися мати **одну й ту саму схему для введення та виведення**.\n\nОсновний випадок - коли у вас вже є згенерований клієнтський код/SDK, і ви поки не бажаєте оновлювати весь такий згенерований код/SDK. Ймовірно, ви зробите це пізніше, але не зараз.\n\nУ такому разі ви можете вимкнути цю можливість у **FastAPI** параметром `separate_input_output_schemas=False`.\n\n/// info | Інформація\n\nПідтримку `separate_input_output_schemas` додано у FastAPI `0.102.0`. 🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### Одна схема для моделей введення та виведення в документації { #same-schema-for-input-and-output-models-in-docs }\n\nТепер для цієї моделі буде лише одна спільна схема для введення та виведення - тільки `Item`, і в ній `description` буде **не обов'язковим**:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/uk/docs/how-to/testing-database.md",
    "content": "# Тестування бази даних { #testing-a-database }\n\nВи можете ознайомитися з базами даних, SQL і SQLModel у [документації SQLModel](https://sqlmodel.tiangolo.com/). 🤓\n\nЄ невеликий [навчальний посібник про використання SQLModel з FastAPI](https://sqlmodel.tiangolo.com/tutorial/fastapi/). ✨\n\nЦей навчальний посібник містить розділ про [тестування баз даних SQL](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/). 😎\n"
  },
  {
    "path": "docs/uk/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/uk\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>Фреймворк FastAPI - це висока продуктивність, легко вивчати, швидко писати код, готовий до продакшину</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**Документація**: [https://fastapi.tiangolo.com](https://fastapi.tiangolo.com/uk)\n\n**Вихідний код**: [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI - це сучасний, швидкий (високопродуктивний) вебфреймворк для створення API за допомогою Python, що базується на стандартних підказках типів Python.\n\nКлючові особливості:\n\n* **Швидкий**: дуже висока продуктивність, на рівні з **NodeJS** та **Go** (завдяки Starlette та Pydantic). [Один із найшвидших Python-фреймворків](#performance).\n* **Швидке написання коду**: пришвидшує розробку функціоналу приблизно на 200%–300%. *\n* **Менше помилок**: зменшує приблизно на 40% кількість помилок, спричинених людиною (розробником). *\n* **Інтуїтивний**: чудова підтримка редакторами коду. <dfn title=\"також відоме як: авто-доповнення, автозавершення, IntelliSense\">Автодоповнення</dfn> всюди. Менше часу на налагодження.\n* **Простий**: спроєктований так, щоб бути простим у використанні та вивченні. Менше часу на читання документації.\n* **Короткий**: мінімізує дублювання коду. Кілька можливостей з кожного оголошення параметра. Менше помилок.\n* **Надійний**: ви отримуєте код, готовий до продакшину. З автоматичною інтерактивною документацією.\n* **Заснований на стандартах**: базується на (і повністю сумісний з) відкритими стандартами для API: [OpenAPI](https://github.com/OAI/OpenAPI-Specification) (раніше відомий як Swagger) та [JSON Schema](https://json-schema.org/).\n\n<small>* оцінка на основі тестів, проведених внутрішньою командою розробників, що створює продакшн-застосунки.</small>\n\n## Спонсори { #sponsors }\n\n<!-- sponsors -->\n\n### Ключовий спонсор { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### Золоті та срібні спонсори { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[Інші спонсори](https://fastapi.tiangolo.com/uk/fastapi-people/#sponsors)\n\n## Враження { #opinions }\n\n\"_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n\"_We adopted the **FastAPI** library to spawn a **REST** server that can be queried to obtain **predictions**. [for Ludwig]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n\"_**Netflix** is pleased to announce the open-source release of our **crisis management** orchestration framework: **Dispatch**! [built with **FastAPI**]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n\"_I’m over the moon excited about **FastAPI**. It’s so fun!_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken - <strong>[Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855) podcast host</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(ref)</small></a></div>\n\n---\n\n\"_Honestly, what you've built looks super solid and polished. In many ways, it's what I wanted **Hug** to be - it's really inspiring to see someone build that._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley - <strong>[Hug](https://github.com/hugapi/hug) creator</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(ref)</small></a></div>\n\n---\n\n\"_If you're looking to learn one **modern framework** for building REST APIs, check out **FastAPI** [...] It's fast, easy to use and easy to learn [...]_\"\n\n\"_We've switched over to **FastAPI** for our **APIs** [...] I think you'll like it [...]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani - Matthew Honnibal - <strong>[Explosion AI](https://explosion.ai) founders - [spaCy](https://spacy.io) creators</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(ref)</small></a> - <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(ref)</small></a></div>\n\n---\n\n\"_If anyone is looking to build a production Python API, I would highly recommend **FastAPI**. It is **beautifully designed**, **simple to use** and **highly scalable**, it has become a **key component** in our API first development strategy and is driving many automations and services such as our Virtual TAC Engineer._\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n## Міні-документальний фільм про FastAPI { #fastapi-mini-documentary }\n\nНаприкінці 2025 року вийшов [міні-документальний фільм про FastAPI](https://www.youtube.com/watch?v=mpR8ngthqiE), ви можете переглянути його онлайн:\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**, FastAPI для CLI { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\nЯкщо ви створюєте застосунок <abbr title=\"Command Line Interface - Інтерфейс командного рядка\">CLI</abbr> для використання в терміналі замість веб-API, зверніть увагу на [**Typer**](https://typer.tiangolo.com/).\n\n**Typer** - молодший брат FastAPI. І його задумано як **FastAPI для CLI**. ⌨️ 🚀\n\n## Вимоги { #requirements }\n\nFastAPI стоїть на плечах гігантів:\n\n* [Starlette](https://www.starlette.dev/) для вебчастини.\n* [Pydantic](https://docs.pydantic.dev/) для частини даних.\n\n## Встановлення { #installation }\n\nСтворіть і активуйте [віртуальне середовище](https://fastapi.tiangolo.com/uk/virtual-environments/), а потім встановіть FastAPI:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Примітка**: переконайтеся, що ви взяли `\"fastapi[standard]\"` у лапки, щоб це працювало в усіх терміналах.\n\n## Приклад { #example }\n\n### Створіть { #create-it }\n\nСтворіть файл `main.py` з:\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>Або використайте <code>async def</code>...</summary>\n\nЯкщо ваш код використовує `async` / `await`, скористайтеся `async def`:\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Примітка**:\n\nЯкщо ви не знаєте, перегляньте розділ _\"In a hurry?\"_ про [`async` та `await` у документації](https://fastapi.tiangolo.com/uk/async/#in-a-hurry).\n\n</details>\n\n### Запустіть { #run-it }\n\nЗапустіть сервер за допомогою:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary>Про команду <code>fastapi dev</code>...</summary>\n\nКоманда `fastapi dev` автоматично читає ваш файл `main.py`, знаходить у ньому застосунок **FastAPI** і запускає сервер за допомогою [Uvicorn](https://www.uvicorn.dev).\n\nЗа замовчуванням `fastapi dev` запускається з авто-перезавантаженням для локальної розробки.\n\nДокладніше читайте в [документації FastAPI CLI](https://fastapi.tiangolo.com/uk/fastapi-cli/).\n\n</details>\n\n### Перевірте { #check-it }\n\nВідкрийте браузер і перейдіть на [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery).\n\nВи побачите JSON-відповідь:\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\nВи вже створили API, який:\n\n* Отримує HTTP-запити за _шляхами_ `/` та `/items/{item_id}`.\n* Обидва _шляхи_ приймають `GET` <em>операції</em> (також відомі як HTTP _методи_).\n* _Шлях_ `/items/{item_id}` містить _параметр шляху_ `item_id`, який має бути типу `int`.\n* _Шлях_ `/items/{item_id}` містить необовʼязковий `str` _параметр запиту_ `q`.\n\n### Інтерактивна документація API { #interactive-api-docs }\n\nТепер перейдіть на [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВи побачите автоматичну інтерактивну документацію API (надану [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Альтернативна документація API { #alternative-api-docs }\n\nА тепер перейдіть на [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nВи побачите альтернативну автоматичну документацію (надану [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## Приклад оновлення { #example-upgrade }\n\nТепер змініть файл `main.py`, щоб отримувати тіло `PUT`-запиту.\n\nОголосіть тіло, використовуючи стандартні типи Python, завдяки Pydantic.\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\nСервер `fastapi dev` має автоматично перезавантажитися.\n\n### Оновлення інтерактивної документації API { #interactive-api-docs-upgrade }\n\nТепер перейдіть на [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n* Інтерактивна документація API буде автоматично оновлена, включно з новим тілом:\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* Натисніть кнопку \"Try it out\", вона дозволяє заповнити параметри та безпосередньо взаємодіяти з API:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* Потім натисніть кнопку \"Execute\", інтерфейс користувача зв'яжеться з вашим API, надішле параметри, отримає результати та покаже їх на екрані:\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### Оновлення альтернативної документації API { #alternative-api-docs-upgrade }\n\nА тепер перейдіть на [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\n* Альтернативна документація також відобразить новий параметр запиту та тіло:\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### Підсумки { #recap }\n\nОтже, ви оголошуєте **один раз** типи параметрів, тіла тощо як параметри функції.\n\nВи робите це за допомогою стандартних сучасних типів Python.\n\nВам не потрібно вивчати новий синтаксис, методи чи класи конкретної бібліотеки тощо.\n\nЛише стандартний **Python**.\n\nНаприклад, для `int`:\n\n```Python\nitem_id: int\n```\n\nабо для складнішої моделі `Item`:\n\n```Python\nitem: Item\n```\n\n...і з цим єдиним оголошенням ви отримуєте:\n\n* Підтримку редактора, включно з:\n    * Автодоповненням.\n    * Перевіркою типів.\n* Валідацію даних:\n    * Автоматичні та зрозумілі помилки, коли дані некоректні.\n    * Валідацію навіть для глибоко вкладених JSON-обʼєктів.\n* <dfn title=\"також відоме як: серіалізація, парсинг, маршалінг\">Перетворення</dfn> вхідних даних: з мережі до даних і типів Python. Читання з:\n    * JSON.\n    * Параметрів шляху.\n    * Параметрів запиту.\n    * Cookies.\n    * Headers.\n    * Forms.\n    * Files.\n* <dfn title=\"також відоме як: серіалізація, парсинг, маршалінг\">Перетворення</dfn> вихідних даних: перетворення з даних і типів Python у мережеві дані (як JSON):\n    * Перетворення типів Python (`str`, `int`, `float`, `bool`, `list`, тощо).\n    * Обʼєктів `datetime`.\n    * Обʼєктів `UUID`.\n    * Моделей бази даних.\n    * ...та багато іншого.\n* Автоматичну інтерактивну документацію API, включно з 2 альтернативними інтерфейсами користувача:\n    * Swagger UI.\n    * ReDoc.\n\n---\n\nПовертаючись до попереднього прикладу коду, **FastAPI**:\n\n* Перевірить, що `item_id` є у шляху для `GET` та `PUT`-запитів.\n* Перевірить, що `item_id` має тип `int` для `GET` та `PUT`-запитів.\n    * Якщо це не так, клієнт побачить корисну, зрозумілу помилку.\n* Перевірить, чи є необов'язковий параметр запиту з назвою `q` (як у `http://127.0.0.1:8000/items/foo?q=somequery`) для `GET`-запитів.\n    * Оскільки параметр `q` оголошено як `= None`, він необов'язковий.\n    * Без `None` він був би обов'язковим (як і тіло у випадку з `PUT`).\n* Для `PUT`-запитів до `/items/{item_id}` прочитає тіло як JSON:\n    * Перевірить, що є обовʼязковий атрибут `name`, який має бути типу `str`.\n    * Перевірить, що є обовʼязковий атрибут `price`, який має бути типу `float`.\n    * Перевірить, що є необовʼязковий атрибут `is_offer`, який має бути типу `bool`, якщо він присутній.\n    * Усе це також працюватиме для глибоко вкладених JSON-обʼєктів.\n* Автоматично перетворюватиме з та в JSON.\n* Документуватиме все за допомогою OpenAPI, який може бути використано в:\n    * Інтерактивних системах документації.\n    * Системах автоматичної генерації клієнтського коду для багатьох мов.\n* Надаватиме безпосередньо 2 вебінтерфейси інтерактивної документації.\n\n---\n\nМи лише трішки доторкнулися до поверхні, але ви вже маєте уявлення про те, як усе працює.\n\nСпробуйте змінити рядок:\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n...із:\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n...на:\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n...і побачите, як ваш редактор автоматично доповнюватиме атрибути та знатиме їхні типи:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\nДля більш повного прикладу, що включає більше можливостей, перегляньте <a href=\"https://fastapi.tiangolo.com/uk/tutorial/\">Навчальний посібник - Посібник користувача</a>.\n\n**Попередження про спойлер**: навчальний посібник - посібник користувача містить:\n\n* Оголошення **параметрів** з інших різних місць, як-от: **headers**, **cookies**, **form fields** та **files**.\n* Як встановлювати **обмеження валідації** як `maximum_length` або `regex`.\n* Дуже потужну і просту у використанні систему **<dfn title=\"також відоме як: компоненти, ресурси, провайдери, сервіси, інжектовані залежності\">Впровадження залежностей</dfn>**.\n* Безпеку та автентифікацію, включно з підтримкою **OAuth2** з **JWT tokens** та **HTTP Basic** auth.\n* Досконаліші (але однаково прості) техніки для оголошення **глибоко вкладених моделей JSON** (завдяки Pydantic).\n* Інтеграцію **GraphQL** з [Strawberry](https://strawberry.rocks) та іншими бібліотеками.\n* Багато додаткових можливостей (завдяки Starlette) як-от:\n    * **WebSockets**\n    * надзвичайно прості тести на основі HTTPX та `pytest`\n    * **CORS**\n    * **Cookie Sessions**\n    * ...та більше.\n\n### Розгортання застосунку (необовʼязково) { #deploy-your-app-optional }\n\nЗа бажання ви можете розгорнути ваш застосунок FastAPI у [FastAPI Cloud](https://fastapicloud.com), перейдіть і приєднайтеся до списку очікування, якщо ви ще цього не зробили. 🚀\n\nЯкщо у вас вже є обліковий запис **FastAPI Cloud** (ми запросили вас зі списку очікування 😉), ви можете розгорнути ваш застосунок однією командою.\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nОсь і все! Тепер ви можете отримати доступ до вашого застосунку за цією URL-адресою. ✨\n\n#### Про FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** створено тим самим автором і командою, що стоять за **FastAPI**.\n\nВін спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.\n\nВін забезпечує той самий **developer experience** створення застосунків на FastAPI під час їх **розгортання** у хмарі. 🎉\n\nFastAPI Cloud - основний спонсор і джерело фінансування open source проєктів *FastAPI and friends*. ✨\n\n#### Розгортання в інших хмарних провайдерів { #deploy-to-other-cloud-providers }\n\nFastAPI - open source проект і базується на стандартах. Ви можете розгортати застосунки FastAPI в будь-якому хмарному провайдері, який ви оберете.\n\nДотримуйтеся інструкцій вашого хмарного провайдера, щоб розгорнути застосунки FastAPI у нього. 🤓\n\n## Продуктивність { #performance }\n\nНезалежні тести TechEmpower показують застосунки **FastAPI**, які працюють під керуванням Uvicorn, як [одні з найшвидших доступних Python-фреймворків](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7), поступаючись лише Starlette та Uvicorn (які внутрішньо використовуються в FastAPI). (*)\n\nЩоб дізнатися більше, перегляньте розділ [Benchmarks](https://fastapi.tiangolo.com/uk/benchmarks/).\n\n## Залежності { #dependencies }\n\nFastAPI залежить від Pydantic і Starlette.\n\n### Залежності `standard` { #standard-dependencies }\n\nКоли ви встановлюєте FastAPI за допомогою `pip install \"fastapi[standard]\"`, ви отримуєте групу необовʼязкових залежностей `standard`:\n\nВикористовується Pydantic:\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - для валідації електронної пошти.\n\nВикористовується Starlette:\n\n* [`httpx`](https://www.python-httpx.org) - потрібно, якщо ви хочете використовувати `TestClient`.\n* [`jinja2`](https://jinja.palletsprojects.com) - потрібно, якщо ви хочете використовувати конфігурацію шаблонів за замовчуванням.\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - потрібно, якщо ви хочете підтримувати форми з <dfn title=\"перетворення строки, що надходить із HTTP-запиту, у дані Python\">«парсингом»</dfn> через `request.form()`.\n\nВикористовується FastAPI:\n\n* [`uvicorn`](https://www.uvicorn.dev) - для сервера, який завантажує та обслуговує ваш застосунок. Це включає `uvicorn[standard]`, до якого входять деякі залежності (наприклад, `uvloop`), потрібні для високопродуктивної роботи сервера.\n* `fastapi-cli[standard]` - щоб надати команду `fastapi`.\n    * Це включає `fastapi-cloud-cli`, який дозволяє розгортати ваш застосунок FastAPI у [FastAPI Cloud](https://fastapicloud.com).\n\n### Без залежностей `standard` { #without-standard-dependencies }\n\nЯкщо ви не хочете включати необовʼязкові залежності `standard`, ви можете встановити через `pip install fastapi` замість `pip install \"fastapi[standard]\"`.\n\n### Без `fastapi-cloud-cli` { #without-fastapi-cloud-cli }\n\nЯкщо ви хочете встановити FastAPI зі стандартними залежностями, але без `fastapi-cloud-cli`, ви можете встановити через `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n### Додаткові необовʼязкові залежності { #additional-optional-dependencies }\n\nЄ ще деякі додаткові залежності, які ви можете захотіти встановити.\n\nДодаткові необовʼязкові залежності Pydantic:\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - для керування налаштуваннями.\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - для додаткових типів, що можуть бути використані з Pydantic.\n\nДодаткові необовʼязкові залежності FastAPI:\n\n* [`orjson`](https://github.com/ijl/orjson) - потрібно, якщо ви хочете використовувати `ORJSONResponse`.\n* [`ujson`](https://github.com/esnme/ultrajson) - потрібно, якщо ви хочете використовувати `UJSONResponse`.\n\n## Ліцензія { #license }\n\nЦей проєкт ліцензовано згідно з умовами ліцензії MIT.\n"
  },
  {
    "path": "docs/uk/docs/learn/index.md",
    "content": "# Навчання { #learn }\n\nУ цьому розділі надані вступні розділи та навчальні посібники для вивчення **FastAPI**.\n\nЦе можна розглядати як **книгу**, **курс**, або **офіційний** та рекомендований спосіб освоїти FastAPI. 😎\n"
  },
  {
    "path": "docs/uk/docs/project-generation.md",
    "content": "# Шаблон Full Stack FastAPI { #full-stack-fastapi-template }\n\nШаблони, хоча зазвичай постачаються з певним налаштуванням, спроєктовані бути гнучкими та налаштовуваними. Це дає змогу змінювати їх і адаптувати до вимог вашого проєкту, що робить їх чудовою відправною точкою. 🏁\n\nВи можете використати цей шаблон для старту, адже в ньому вже виконано значну частину початкового налаштування, безпеки, роботи з базою даних і деяких кінцевих точок API.\n\nРепозиторій GitHub: [Шаблон Full Stack FastAPI](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## Шаблон Full Stack FastAPI - стек технологій і можливості { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/uk) для бекенд API на Python.\n  - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) для взаємодії з SQL-базою даних у Python (ORM).\n  - 🔍 [Pydantic](https://docs.pydantic.dev), який використовується FastAPI, для перевірки даних і керування налаштуваннями.\n  - 💾 [PostgreSQL](https://www.postgresql.org) як SQL-база даних.\n- 🚀 [React](https://react.dev) для фронтенду.\n  - 💃 Використання TypeScript, хуків, Vite та інших частин сучасного фронтенд-стеку.\n  - 🎨 [Tailwind CSS](https://tailwindcss.com) і [shadcn/ui](https://ui.shadcn.com) для фронтенд-компонентів.\n  - 🤖 Автоматично згенерований фронтенд-клієнт.\n  - 🧪 [Playwright](https://playwright.dev) для End-to-End тестування.\n  - 🦇 Підтримка темного режиму.\n- 🐋 [Docker Compose](https://www.docker.com) для розробки та продакшену.\n- 🔒 Безпечне хешування паролів за замовчуванням.\n- 🔑 Автентифікація JWT (JSON Web Token).\n- 📫 Відновлення пароля на основі електронної пошти.\n- ✅ Тести з [Pytest](https://pytest.org).\n- 📞 [Traefik](https://traefik.io) як зворотний представник / балансувальник навантаження.\n- 🚢 Інструкції з розгортання з Docker Compose, включно з налаштуванням фронтенд-представника Traefik для автоматичних HTTPS-сертифікатів.\n- 🏭 CI (безперервна інтеграція) і CD (безперервне розгортання) на базі GitHub Actions.\n"
  },
  {
    "path": "docs/uk/docs/python-types.md",
    "content": "# Вступ до типів Python { #python-types-intro }\n\nPython підтримує додаткові «підказки типів» (також звані «анотаціями типів»).\n\nЦі **«підказки типів»** або анотації — це спеціальний синтаксис, що дозволяє оголошувати <dfn title=\"наприклад: str, int, float, bool\">тип</dfn> змінної.\n\nЗа допомогою оголошення типів для ваших змінних редактори та інструменти можуть надати вам кращу підтримку.\n\nЦе лише **швидкий навчальний посібник / нагадування** про підказки типів у Python. Він покриває лише мінімум, необхідний щоб використовувати їх з **FastAPI**... що насправді дуже мало.\n\n**FastAPI** повністю базується на цих підказках типів, вони дають йому багато переваг і користі.\n\nАле навіть якщо ви ніколи не використаєте **FastAPI**, вам буде корисно дізнатись трохи про них.\n\n/// note | Примітка\n\nЯкщо ви експерт у Python і ви вже знаєте все про підказки типів, перейдіть до наступного розділу.\n\n///\n\n## Мотивація { #motivation }\n\nДавайте почнемо з простого прикладу:\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\nВиклик цієї програми виводить:\n\n```\nJohn Doe\n```\n\nФункція виконує наступне:\n\n* Бере `first_name` та `last_name`.\n* Перетворює першу літеру кожного з них у верхній регістр за допомогою `title()`.\n* <dfn title=\"Об’єднує їх разом, як одне ціле. З вмістом одного після іншого.\">Конкатенує</dfn> їх разом із пробілом по середині.\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### Редагуйте це { #edit-it }\n\nЦе дуже проста програма.\n\nАле тепер уявіть, що ви писали це з нуля.\n\nУ певний момент ви розпочали б визначення функції, у вас були б готові параметри...\n\nАле тоді вам потрібно викликати «той метод, який перетворює першу літеру у верхній регістр».\n\nЦе буде `upper`? Чи `uppercase`? `first_uppercase`? `capitalize`?\n\nТоді ви спробуєте давнього друга програміста — автозаповнення редактора коду.\n\nВи надрукуєте перший параметр функції, `first_name`, тоді крапку (`.`), а тоді натиснете `Ctrl+Space`, щоб запустити автозаповнення.\n\nАле, на жаль, ви не отримаєте нічого корисного:\n\n<img src=\"/img/python-types/image01.png\">\n\n### Додайте типи { #add-types }\n\nДавайте змінимо один рядок з попередньої версії.\n\nМи змінимо саме цей фрагмент, параметри функції, з:\n\n```Python\n    first_name, last_name\n```\n\nна:\n\n```Python\n    first_name: str, last_name: str\n```\n\nОсь і все.\n\nЦе «підказки типів»:\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\nЦе не те саме, що оголошення значень за замовчуванням, як це було б з:\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\nЦе зовсім інше.\n\nМи використовуємо двокрапку (`:`), не знак дорівнює (`=`).\n\nІ додавання підказок типів зазвичай не змінює того, що відбувається, порівняно з тим, що відбувалося б без них.\n\nАле тепер уявіть, що ви знову посеред процесу створення функції, але з підказками типів.\n\nУ той самий момент ви спробуєте викликати автозаповнення за допомогою `Ctrl+Space` і побачите:\n\n<img src=\"/img/python-types/image02.png\">\n\nРазом з цим ви можете прокручувати, переглядаючи опції, допоки не знайдете ту, що «щось вам підказує»:\n\n<img src=\"/img/python-types/image03.png\">\n\n## Більше мотивації { #more-motivation }\n\nПеревірте цю функцію, вона вже має підказки типів:\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\nОскільки редактор знає типи змінних, ви не тільки отримаєте автозаповнення, ви також отримаєте перевірку помилок:\n\n<img src=\"/img/python-types/image04.png\">\n\nТепер ви знаєте, щоб виправити це, вам потрібно перетворити `age` у строку за допомогою `str(age)`:\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## Оголошення типів { #declaring-types }\n\nЩойно ви побачили основне місце для оголошення підказок типів. Як параметри функції.\n\nЦе також основне місце, де ви б їх використовували у **FastAPI**.\n\n### Прості типи { #simple-types }\n\nВи можете оголошувати усі стандартні типи у Python, не тільки `str`.\n\nВи можете використовувати, наприклад:\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### Модуль `typing` { #typing-module }\n\nДля деяких додаткових випадків використання може знадобитися імпортувати елементи зі стандартної бібліотеки, модуля `typing`. Наприклад, коли ви хочете оголосити, що щось має «будь-який тип», ви можете використати `Any` з `typing`:\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### Generic типи { #generic-types }\n\nДеякі типи можуть приймати «параметри типів» у квадратних дужках, щоб визначити їх внутрішні типи. Наприклад, «list строк» буде оголошений як `list[str]`.\n\nЦі типи, які можуть приймати параметри типів, називаються **generic типами** або **generics**.\n\nВи можете використовувати ті самі вбудовані типи як generics (з квадратними дужками та типами всередині):\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### List { #list }\n\nНаприклад, давайте визначимо змінну, яка буде `list` із `str`.\n\nОголосіть змінну з тим самим синтаксисом двокрапки (`:`).\n\nЯк тип вкажіть `list`.\n\nОскільки список є типом, який містить деякі внутрішні типи, ви поміщаєте їх у квадратні дужки:\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info | Інформація\n\nЦі внутрішні типи в квадратних дужках називаються «параметрами типу».\n\nУ цьому випадку `str` — це параметр типу, переданий у `list`.\n\n///\n\nЦе означає: «змінна `items` — це `list`, і кожен з елементів у цьому списку — `str`».\n\nЗробивши це, ваш редактор може надати підтримку навіть під час обробки елементів зі списку:\n\n<img src=\"/img/python-types/image05.png\">\n\nБез типів цього майже неможливо досягти.\n\nЗверніть увагу, що змінна `item` є одним із елементів у списку `items`.\n\nІ все ж редактор знає, що це `str`, і надає підтримку для цього.\n\n#### Tuple and Set { #tuple-and-set }\n\nВи повинні зробити те ж саме, щоб оголосити `tuple` і `set`:\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\nЦе означає:\n\n* Змінна `items_t` — це `tuple` з 3 елементами: `int`, ще `int`, та `str`.\n* Змінна `items_s` — це `set`, і кожен його елемент має тип `bytes`.\n\n#### Dict { #dict }\n\nЩоб оголосити `dict`, вам потрібно передати 2 параметри типу, розділені комами.\n\nПерший параметр типу для ключів у `dict`.\n\nДругий параметр типу для значень у `dict`:\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\nЦе означає:\n\n* Змінна `prices` — це `dict`:\n    * Ключі цього `dict` мають тип `str` (скажімо, назва кожного предмета).\n    * Значення цього `dict` мають тип `float` (скажімо, ціна кожного предмета).\n\n#### Union { #union }\n\nВи можете оголосити, що змінна може бути будь-яким із **кількох типів**, наприклад `int` або `str`.\n\nЩоб визначити це, використовуйте <dfn title='також називають «побітовим оператором \"або\"», але це значення тут не актуальне'>вертикальну риску (`|`)</dfn>, щоб розділити обидва типи.\n\nЦе називається «union», тому що змінна може бути чимось із об’єднання цих двох множин типів.\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\nЦе означає, що `item` може бути `int` або `str`.\n\n#### Можливо `None` { #possibly-none }\n\nВи можете оголосити, що значення може мати тип, наприклад `str`, але також може бути `None`.\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\nВикористання `str | None` замість просто `str` дозволить редактору допомогти вам виявити помилки, коли ви могли б вважати, що значенням завжди є `str`, хоча насправді воно також може бути `None`.\n\n### Класи як типи { #classes-as-types }\n\nВи також можете оголосити клас як тип змінної.\n\nСкажімо, у вас є клас `Person` з імʼям:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\nПотім ви можете оголосити змінну типу `Person`:\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\nІ знову ж таки, ви отримуєте всю підтримку редактора:\n\n<img src=\"/img/python-types/image06.png\">\n\nЗверніть увагу, що це означає: «`one_person` — це **екземпляр** класу `Person`».\n\nЦе не означає: «`one_person` — це **клас** з назвою `Person`».\n\n## Pydantic моделі { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/) — це бібліотека Python для валідації даних.\n\nВи оголошуєте «форму» даних як класи з атрибутами.\n\nІ кожен атрибут має тип.\n\nПотім ви створюєте екземпляр цього класу з деякими значеннями, і він перевірить ці значення, перетворить їх у відповідний тип (якщо є потреба) і надасть вам об’єкт з усіма даними.\n\nІ ви отримуєте всю підтримку редактора з цим отриманим об’єктом.\n\nПриклад з офіційної документації Pydantic:\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info | Інформація\n\nЩоб дізнатись більше про [Pydantic, перегляньте його документацію](https://docs.pydantic.dev/).\n\n///\n\n**FastAPI** повністю базується на Pydantic.\n\nВи побачите набагато більше цього всього на практиці в [Навчальний посібник - Посібник користувача](tutorial/index.md).\n\n## Підказки типів з анотаціями метаданих { #type-hints-with-metadata-annotations }\n\nУ Python також є можливість додавати **додаткові <dfn title=\"Дані про дані, у цьому випадку — інформація про тип, наприклад опис.\">метадані</dfn>** до цих підказок типів за допомогою `Annotated`.\n\nВи можете імпортувати `Annotated` з `typing`.\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nСам Python нічого не робить із цим `Annotated`. А для редакторів та інших інструментів тип усе ще є `str`.\n\nАле ви можете використати це місце в `Annotated`, щоб надати **FastAPI** додаткові метадані про те, як ви хочете, щоб ваш застосунок поводився.\n\nВажливо пам’ятати, що **перший *параметр типу***, який ви передаєте в `Annotated`, — це **фактичний тип**. Решта — це лише метадані для інших інструментів.\n\nНаразі вам просто потрібно знати, що `Annotated` існує і що це стандартний Python. 😎\n\nПізніше ви побачите, наскільки **потужним** це може бути.\n\n/// tip | Порада\n\nТой факт, що це **стандартний Python**, означає, що ви й надалі отримуватимете **найкращий можливий досвід розробки** у вашому редакторі, з інструментами, які ви використовуєте для аналізу та рефакторингу коду тощо. ✨\n\nА також те, що ваш код буде дуже сумісним із багатьма іншими інструментами та бібліотеками Python. 🚀\n\n///\n\n## Підказки типів у **FastAPI** { #type-hints-in-fastapi }\n\n**FastAPI** використовує ці підказки типів для виконання кількох речей.\n\nЗ **FastAPI** ви оголошуєте параметри з підказками типів, і отримуєте:\n\n* **Підтримку редактора**.\n* **Перевірку типів**.\n\n...і **FastAPI** використовує ті самі оголошення для:\n\n* **Визначення вимог**: з параметрів шляху запиту, параметрів запиту, заголовків, тіл, залежностей тощо.\n* **Перетворення даних**: із запиту в необхідний тип.\n* **Перевірки даних**: що надходять від кожного запиту:\n    * Генерування **автоматичних помилок**, що повертаються клієнту, коли дані недійсні.\n* **Документування** API за допомогою OpenAPI:\n    * який потім використовується для автоматичної інтерактивної документації користувальницьких інтерфейсів.\n\nВсе це може здатися абстрактним. Не хвилюйтеся. Ви побачите все це в дії в [Навчальний посібник - Посібник користувача](tutorial/index.md).\n\nВажливо те, що за допомогою стандартних типів Python в одному місці (замість того, щоб додавати більше класів, декораторів тощо), **FastAPI** зробить багато роботи за вас.\n\n/// info | Інформація\n\nЯкщо ви вже пройшли весь навчальний посібник і повернулися, щоб дізнатися більше про типи, ось хороший ресурс: [«шпаргалка» від `mypy`](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html).\n\n///\n"
  },
  {
    "path": "docs/uk/docs/resources/index.md",
    "content": "# Ресурси { #resources }\n\nДодаткові ресурси, зовнішні посилання та інше. ✈️\n"
  },
  {
    "path": "docs/uk/docs/translation-banner.md",
    "content": "/// details | 🌐 Переклад ШІ та людьми\n\nЦей переклад виконано ШІ під керівництвом людей. 🤝\n\nМожливі помилки через неправильне розуміння початкового змісту або неприродні формулювання тощо. 🤖\n\nВи можете покращити цей переклад, [допомігши нам краще спрямовувати AI LLM](https://fastapi.tiangolo.com/uk/contributing/#translations).\n\n[Англійська версія](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/uk/docs/tutorial/background-tasks.md",
    "content": "# Фонові задачі { #background-tasks }\n\nВи можете створювати фонові задачі, які будуть виконуватися після повернення відповіді.\n\nЦе корисно для операцій, які потрібно виконати після обробки запиту, але клієнту не обов’язково чекати завершення цієї операції перед отриманням відповіді.\n\nЦе включає, наприклад:\n\n* Надсилання email-сповіщень після виконання певної дії:\n    * Підключення до поштового сервера та надсилання листа може займати кілька секунд. Ви можете відразу повернути відповідь, а email-сповіщення надіслати у фоні.\n* Обробка даних:\n    * Наприклад, якщо ви отримали файл, який потрібно обробити довготривалим процесом, можна повернути відповідь «Accepted» (HTTP 202) і виконати обробку файлу у фоні.\n\n## Використання `BackgroundTasks` { #using-backgroundtasks }\n\nСпочатку імпортуйте `BackgroundTasks` і оголосіть параметр у вашій функції операції шляху з анотацією типу `BackgroundTasks`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI** створить для вас об’єкт типу `BackgroundTasks` і передасть його як цей параметр.\n\n## Створення функції задачі { #create-a-task-function }\n\nСтворіть функцію, яка буде виконуватися як фонова задача.\n\nЦе звичайна функція, яка може отримувати параметри.\n\nВона може бути асинхронною `async def` або звичайною `def` функцією – **FastAPI** обробить її правильно.\n\nУ нашому випадку функція записує у файл (імітуючи надсилання email).\n\nІ оскільки операція запису не використовує `async` та `await`, ми визначаємо функцію як звичайну `def`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## Додавання фонової задачі { #add-the-background-task }\n\nУсередині вашої функції операції шляху, передайте функцію задачі в об'єкт background tasks, використовуючи метод `.add_task()`:\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()` приймає аргументи:\n\n* Функцію задачі, яка буде виконуватися у фоновому режимі (`write_notification`).\n* Будь-яку послідовність аргументів, які потрібно передати у функцію задачі у відповідному порядку (`email`).\n* Будь-які іменовані аргументи, які потрібно передати у функцію задачі (`message=\"some notification\"`).\n\n## Впровадження залежностей { #dependency-injection }\n\nВикористання `BackgroundTasks` також працює з системою впровадження залежностей. Ви можете оголосити параметр типу `BackgroundTasks` на різних рівнях: у функції операції шляху, у залежності (залежний), у підзалежності тощо.\n\n**FastAPI** знає, як діяти в кожному випадку і як повторно використовувати один і той самий об'єкт, щоб усі фонові задачі були об’єднані та виконувалися у фоновому режимі після завершення основного запиту:\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\nУ цьому прикладі повідомлення будуть записані у файл `log.txt` після того, як відповідь буде надіслана.\n\nЯкщо у запиті був переданий параметр запиту, він буде записаний у лог у фоновій задачі.\n\nА потім інша фонова задача, згенерована у функції операції шляху, запише повідомлення з використанням параметра шляху `email`.\n\n## Технічні деталі { #technical-details }\n\nКлас `BackgroundTasks` походить безпосередньо з [`starlette.background`](https://www.starlette.dev/background/).\n\nВін імпортується/включається безпосередньо у FastAPI, щоб ви могли імпортувати його з `fastapi` і випадково не імпортували альтернативний `BackgroundTask` (без `s` в кінці) з `starlette.background`.\n\nЯкщо використовувати лише `BackgroundTasks` (а не `BackgroundTask`), то його можна передавати як параметр у функції операції шляху, і **FastAPI** подбає про все інше, так само як і про використання об'єкта `Request`.\n\nТакож можна використовувати `BackgroundTask` окремо в FastAPI, але для цього вам доведеться створити об'єкт у коді та повернути Starlette `Response`, включаючи його.\n\nДетальніше можна почитати в [офіційній документації Starlette про Background Tasks](https://www.starlette.dev/background/).\n\n## Застереження { #caveat }\n\nЯкщо вам потрібно виконувати складні фонові обчислення, і при цьому нема потреби запускати їх у тому ж процесі (наприклад, не потрібно спільного доступу до пам’яті чи змінних), можливо, варто скористатися більш потужними інструментами, такими як [Celery](https://docs.celeryq.dev).\n\nТакі інструменти зазвичай потребують складнішої конфігурації та менеджера черги повідомлень/завдань, наприклад, RabbitMQ або Redis. Однак вони дозволяють виконувати фонові задачі в кількох процесах і особливо — на кількох серверах.\n\nЯкщо ж вам потрібно отримати доступ до змінних і об’єктів із тієї ж **FastAPI**-програми або виконувати невеликі фонові завдання (наприклад, надсилати email-сповіщення), достатньо просто використовувати `BackgroundTasks`.\n\n## Підсумок { #recap }\n\nІмпортуйте та використовуйте `BackgroundTasks` як параметри у функціях операції шляху та залежностях, щоб додавати фонові задачі.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/bigger-applications.md",
    "content": "# Більші застосунки - кілька файлів { #bigger-applications-multiple-files }\n\nЯкщо ви створюєте застосунок або веб-API, рідко вдається вмістити все в один файл.\n\n**FastAPI** надає зручний інструмент для структурування вашого застосунку, зберігаючи всю гнучкість.\n\n/// info | Інформація\n\nЯкщо ви прийшли з Flask, це еквівалент «Blueprints» у Flask.\n\n///\n\n## Приклад структури файлів { #an-example-file-structure }\n\nПрипустімо, у вас така структура файлів:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | Порада\n\nТут кілька файлів `__init__.py`: по одному в кожному каталозі та підкаталозі.\n\nСаме це дозволяє імпортувати код з одного файлу в інший.\n\nНаприклад, у `app/main.py` ви можете мати рядок:\n\n```\nfrom app.routers import items\n```\n\n///\n\n* Каталог `app` містить усе. І він має порожній файл `app/__init__.py`, тож це «пакет Python» (збірка «модулів Python»): `app`.\n* Він містить файл `app/main.py`. Оскільки він усередині пакета Python (каталог з файлом `__init__.py`), це «модуль» цього пакета: `app.main`.\n* Є також файл `app/dependencies.py`, так само як `app/main.py`, це «модуль»: `app.dependencies`.\n* Є підкаталог `app/routers/` з іншим файлом `__init__.py`, отже це «підпакет Python»: `app.routers`.\n* Файл `app/routers/items.py` знаходиться в пакеті `app/routers/`, отже це підмодуль: `app.routers.items`.\n* Так само і `app/routers/users.py`, це інший підмодуль: `app.routers.users`.\n* Є також підкаталог `app/internal/` з іншим файлом `__init__.py`, отже це інший «підпакет Python»: `app.internal`.\n* І файл `app/internal/admin.py` - ще один підмодуль: `app.internal.admin`.\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\nТа сама структура файлів з коментарями:\n\n```bash\n.\n├── app                  # «app» - це пакет Python\n│   ├── __init__.py      # цей файл робить «app» «пакетом Python»\n│   ├── main.py          # модуль «main», напр. import app.main\n│   ├── dependencies.py  # модуль «dependencies», напр. import app.dependencies\n│   └── routers          # «routers» - це «підпакет Python»\n│   │   ├── __init__.py  # робить «routers» «підпакетом Python»\n│   │   ├── items.py     # підмодуль «items», напр. import app.routers.items\n│   │   └── users.py     # підмодуль «users», напр. import app.routers.users\n│   └── internal         # «internal» - це «підпакет Python»\n│       ├── __init__.py  # робить «internal» «підпакетом Python»\n│       └── admin.py     # підмодуль «admin», напр. import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\nПрипустімо, файл, присвячений обробці лише користувачів, - це підмодуль у `/app/routers/users.py`.\n\nВи хочете мати *операції шляху*, пов'язані з користувачами, відокремлено від решти коду, щоб зберегти порядок.\n\nАле це все одно частина того самого застосунку/веб-API **FastAPI** (це частина того самого «пакета Python»).\n\nВи можете створювати *операції шляху* для цього модуля, використовуючи `APIRouter`.\n\n### Імпортуйте `APIRouter` { #import-apirouter }\n\nІмпортуйте його та створіть «екземпляр» так само, як ви б робили з класом `FastAPI`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### *Операції шляху* з `APIRouter` { #path-operations-with-apirouter }\n\nПотім використовуйте його для оголошення *операцій шляху*.\n\nВикористовуйте його так само, як і клас `FastAPI`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\nМожете думати про `APIRouter` як про «міні `FastAPI`».\n\nПідтримуються ті самі опції.\n\nТі самі `parameters`, `responses`, `dependencies`, `tags` тощо.\n\n/// tip | Порада\n\nУ цьому прикладі змінна називається `router`, але ви можете назвати її як завгодно.\n\n///\n\nМи включимо цей `APIRouter` у основний застосунок `FastAPI`, але спочатку розгляньмо залежності та інший `APIRouter`.\n\n## Залежності { #dependencies }\n\nБачимо, що нам знадобляться кілька залежностей, які використовуються в різних місцях застосунку.\n\nТож помістимо їх у власний модуль `dependencies` (`app/dependencies.py`).\n\nТепер використаємо просту залежність для читання користувацького заголовка `X-Token`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | Порада\n\nМи використовуємо вигаданий заголовок, щоб спростити приклад.\n\nАле в реальних випадках ви отримаєте кращі результати, використовуючи інтегровані [засоби безпеки](security/index.md).\n\n///\n\n## Інший модуль з `APIRouter` { #another-module-with-apirouter }\n\nПрипустімо, у вас також є кінцеві точки для обробки «items» у модулі `app/routers/items.py`.\n\nУ вас є *операції шляху* для:\n\n* `/items/`\n* `/items/{item_id}`\n\nСтруктура така сама, як у `app/routers/users.py`.\n\nАле ми хочемо бути розумнішими й трохи спростити код.\n\nМи знаємо, що всі *операції шляху* в цьому модулі мають однакові:\n\n* Префікс шляху `prefix`: `/items`.\n* `tags`: (лише одна мітка: `items`).\n* Додаткові `responses`.\n* `dependencies`: усім потрібна залежність `X-Token`, яку ми створили.\n\nТож замість додавання цього до кожної *операції шляху*, ми можемо додати це до `APIRouter`.\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\nОскільки шлях кожної *операції шляху* має починатися з `/`, як у:\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n...префікс не має містити кінцевий `/`.\n\nОтже, у цьому випадку префікс - це `/items`.\n\nМи також можемо додати список `tags` та додаткові `responses`, які застосовуватимуться до всіх *операцій шляху*, включених у цей router.\n\nІ ми можемо додати список `dependencies`, які буде додано до всіх *операцій шляху* у router і які виконуватимуться/вирішуватимуться для кожного запиту до них.\n\n/// tip | Порада\n\nЗверніть увагу, що так само як і для [залежностей у декораторах *операцій шляху*](dependencies/dependencies-in-path-operation-decorators.md), жодне значення не буде передано вашій *функції операції шляху*.\n\n///\n\nУ підсумку шляхи предметів тепер:\n\n* `/items/`\n* `/items/{item_id}`\n\n...як ми і планували.\n\n* Вони будуть позначені списком міток, що містить один рядок `\"items\"`.\n    * Ці «мітки» особливо корисні для автоматичної інтерактивної документації (за допомогою OpenAPI).\n* Усі вони включатимуть наперед визначені `responses`.\n* Для всіх цих *операцій шляху* список `dependencies` буде оцінений/виконаний перед ними.\n    * Якщо ви також оголосите залежності в конкретній *операції шляху*, **вони також будуть виконані**.\n    * Спочатку виконуються залежності router'а, потім [`dependencies` у декораторі](dependencies/dependencies-in-path-operation-decorators.md), а потім звичайні параметричні залежності.\n    * Ви також можете додати [`Security` залежності з `scopes`](../advanced/security/oauth2-scopes.md).\n\n/// tip | Порада\n\nНаявність `dependencies` у `APIRouter` можна використати, наприклад, щоб вимагати автентифікацію для всієї групи *операцій шляху*. Навіть якщо залежності не додані до кожної з них окремо.\n\n///\n\n/// check | Перевірте\n\nПараметри `prefix`, `tags`, `responses` і `dependencies` - це (як і в багатьох інших випадках) просто можливість **FastAPI**, яка допомагає уникати дублювання коду.\n\n///\n\n### Імпортуйте залежності { #import-the-dependencies }\n\nЦей код живе в модулі `app.routers.items`, у файлі `app/routers/items.py`.\n\nІ нам потрібно отримати функцію залежності з модуля `app.dependencies`, файлу `app/dependencies.py`.\n\nТож ми використовуємо відносний імпорт з `..` для залежностей:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### Як працюють відносні імпорти { #how-relative-imports-work }\n\n/// tip | Порада\n\nЯкщо ви досконало знаєте, як працюють імпорти, перейдіть до наступного розділу нижче.\n\n///\n\nОдна крапка `.`, як у:\n\n```Python\nfrom .dependencies import get_token_header\n```\n\nозначає:\n\n* Починаючи в тому самому пакеті, де знаходиться цей модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...\n* знайти модуль `dependencies` (уявний файл `app/routers/dependencies.py`)...\n* і з нього імпортувати функцію `get_token_header`.\n\nАле такого файлу не існує, наші залежності у файлі `app/dependencies.py`.\n\nЗгадайте, як виглядає структура нашого застосунку/файлів:\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\nДві крапки `..`, як у:\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\nозначають:\n\n* Починаючи в тому самому пакеті, де знаходиться цей модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...\n* перейти до батьківського пакета (каталог `app/`)...\n* і там знайти модуль `dependencies` (файл `app/dependencies.py`)...\n* і з нього імпортувати функцію `get_token_header`.\n\nЦе працює правильно! 🎉\n\n---\n\nТак само, якби ми використали три крапки `...`, як у:\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\nце б означало:\n\n* Починаючи в тому самому пакеті, де знаходиться цей модуль (файл `app/routers/items.py`) (каталог `app/routers/`)...\n* перейти до батьківського пакета (каталог `app/`)...\n* потім перейти до батьківського пакета від того (немає батьківського пакета, `app` - верхній рівень 😱)...\n* і там знайти модуль `dependencies` (файл `app/dependencies.py`)...\n* і з нього імпортувати функцію `get_token_header`.\n\nЦе б посилалося на якийсь пакет вище за `app/` з власним файлом `__init__.py` тощо. Але в нас такого немає. Тож у нашому прикладі це спричинить помилку. 🚨\n\nАле тепер ви знаєте, як це працює, тож можете використовувати відносні імпорти у власних застосунках, незалежно від їхньої складності. 🤓\n\n### Додайте користувацькі `tags`, `responses` і `dependencies` { #add-some-custom-tags-responses-and-dependencies }\n\nМи не додаємо префікс `/items` ані `tags=[\"items\"]` до кожної *операції шляху*, бо додали їх до `APIRouter`.\n\nАле ми все ще можемо додати _ще_ `tags`, які будуть застосовані до конкретної *операції шляху*, а також додаткові `responses`, специфічні для цієї *операції шляху*:\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | Порада\n\nОстання операція шляху матиме комбінацію міток: `[\"items\", \"custom\"]`.\n\nІ вона також матиме в документації обидві відповіді: одну для `404` і одну для `403`.\n\n///\n\n## Основний `FastAPI` { #the-main-fastapi }\n\nТепер розгляньмо модуль `app/main.py`.\n\nТут ви імпортуєте і використовуєте клас `FastAPI`.\n\nЦе буде головний файл вашого застосунку, який усе поєднує.\n\nІ оскільки більшість вашої логіки тепер житиме у власних модулях, головний файл буде досить простим.\n\n### Імпортуйте `FastAPI` { #import-fastapi }\n\nІмпортуйте та створіть клас `FastAPI`, як зазвичай.\n\nІ ми навіть можемо оголосити [глобальні залежності](dependencies/global-dependencies.md), які будуть поєднані із залежностями кожного `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### Імпортуйте `APIRouter` { #import-the-apirouter }\n\nТепер імпортуємо інші підмодулі, що мають `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\nОскільки файли `app/routers/users.py` та `app/routers/items.py` - це підмодулі, що є частиною того самого пакета Python `app`, ми можемо використати одну крапку `.` для «відносних імпортів».\n\n### Як працює імпорт { #how-the-importing-works }\n\nРозділ:\n\n```Python\nfrom .routers import items, users\n```\n\nозначає:\n\n* Починаючи в тому самому пакеті, де знаходиться цей модуль (файл `app/main.py`) (каталог `app/`)...\n* знайти підпакет `routers` (каталог `app/routers/`)...\n* і з нього імпортувати підмодулі `items` (файл `app/routers/items.py`) і `users` (файл `app/routers/users.py`)...\n\nМодуль `items` матиме змінну `router` (`items.router`). Це та сама, що ми створили у файлі `app/routers/items.py`, це об’єкт `APIRouter`.\n\nПотім ми робимо те саме для модуля `users`.\n\nМи також могли б імпортувати їх так:\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info | Інформація\n\nПерша версія - «відносний імпорт»:\n\n```Python\nfrom .routers import items, users\n```\n\nДруга версія - «абсолютний імпорт»:\n\n```Python\nfrom app.routers import items, users\n```\n\nЩоб дізнатися більше про пакети й модулі Python, прочитайте [офіційну документацію Python про модулі](https://docs.python.org/3/tutorial/modules.html).\n\n///\n\n### Уникайте колізій імен { #avoid-name-collisions }\n\nМи імпортуємо підмодуль `items` напряму, замість імпорту лише його змінної `router`.\n\nЦе тому, що в підмодулі `users` також є змінна з назвою `router`.\n\nЯкби ми імпортували один за одним, як:\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\n`router` з `users` перезаписав би той, що з `items`, і ми не змогли б використовувати їх одночасно.\n\nЩоб мати змогу використовувати обидва в одному файлі, ми імпортуємо підмодулі напряму:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### Додайте `APIRouter` для `users` і `items` { #include-the-apirouters-for-users-and-items }\n\nТепер додаймо `router` з підмодулів `users` і `items`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info | Інформація\n\n`users.router` містить `APIRouter` у файлі `app/routers/users.py`.\n\nА `items.router` містить `APIRouter` у файлі `app/routers/items.py`.\n\n///\n\nЗа допомогою `app.include_router()` ми можемо додати кожен `APIRouter` до основного застосунку `FastAPI`.\n\nЦе включить усі маршрути з цього router'а як частину застосунку.\n\n/// note | Технічні деталі\n\nФактично, всередині для кожної *операції шляху*, оголошеної в `APIRouter`, буде створена окрема *операція шляху*.\n\nТобто за лаштунками все працюватиме так, ніби це один і той самий застосунок.\n\n///\n\n/// check | Перевірте\n\nВам не потрібно перейматися продуктивністю під час включення router'ів.\n\nЦе займе мікросекунди і відбуватиметься лише під час запуску.\n\nТож це не вплине на продуктивність. ⚡\n\n///\n\n### Додайте `APIRouter` з власними `prefix`, `tags`, `responses` і `dependencies` { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\nУявімо, що ваша організація надала вам файл `app/internal/admin.py`.\n\nВін містить `APIRouter` з кількома адміністративними *операціями шляху*, які організація спільно використовує між кількома проєктами.\n\nДля цього прикладу він буде дуже простим. Але припустімо, що оскільки його спільно використовують з іншими проєктами організації, ми не можемо модифікувати його та додавати `prefix`, `dependencies`, `tags` тощо прямо до `APIRouter`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nАле ми все одно хочемо встановити користувацький `prefix` під час включення `APIRouter`, щоб усі його *операції шляху* починалися з `/admin`, хочемо захистити його за допомогою `dependencies`, які вже є в цьому проєкті, і хочемо додати `tags` та `responses`.\n\nМи можемо оголосити все це, не змінюючи оригінальний `APIRouter`, передавши ці параметри до `app.include_router()`:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\nТаким чином, вихідний `APIRouter` залишиться без змін, тож ми все ще зможемо спільно використовувати той самий файл `app/internal/admin.py` з іншими проєктами в організації.\n\nУ результаті в нашому застосунку кожна з *операцій шляху* з модуля `admin` матиме:\n\n* Префікс `/admin`.\n* Мітку `admin`.\n* Залежність `get_token_header`.\n* Відповідь `418`. 🍵\n\nАле це вплине лише на цей `APIRouter` у нашому застосунку, а не на будь-який інший код, який його використовує.\n\nНаприклад, інші проєкти можуть використовувати той самий `APIRouter` з іншим методом автентифікації.\n\n### Додайте *операцію шляху* { #include-a-path-operation }\n\nМи також можемо додавати *операції шляху* безпосередньо до застосунку `FastAPI`.\n\nТут ми це робимо... просто щоб показати, що так можна 🤷:\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\nі це працюватиме коректно разом з усіма іншими *операціями шляху*, доданими через `app.include_router()`.\n\n/// info | Дуже технічні деталі\n\nПримітка: це дуже технічна деталь, яку ви, ймовірно, можете просто пропустити.\n\n---\n\n`APIRouter` не «монтуються», вони не ізольовані від решти застосунку.\n\nЦе тому, що ми хочемо включати їхні *операції шляху* в схему OpenAPI та інтерфейси користувача.\n\nОскільки ми не можемо просто ізолювати їх і «змонтувати» незалежно від решти, *операції шляху* «клонуються» (створюються заново), а не включаються безпосередньо.\n\n///\n\n## Налаштуйте `entrypoint` у `pyproject.toml` { #configure-the-entrypoint-in-pyproject-toml }\n\nОскільки ваш об'єкт FastAPI `app` знаходиться в `app/main.py`, ви можете налаштувати `entrypoint` у файлі `pyproject.toml` так:\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\nце еквівалентно імпорту:\n\n```python\nfrom app.main import app\n```\n\nТаким чином команда `fastapi` знатиме, де знайти ваш застосунок.\n\n/// Note | Примітка\n\nВи також могли б передати шлях команді, наприклад:\n\n```console\n$ fastapi dev app/main.py\n```\n\nАле тоді вам доведеться щоразу пам'ятати, щоб передавати правильний шлях, коли ви викликаєте команду `fastapi`.\n\nКрім того, інші інструменти можуть не знайти його, наприклад [розширення VS Code](../editor-support.md) або [FastAPI Cloud](https://fastapicloud.com), тому рекомендовано використовувати `entrypoint` у `pyproject.toml`.\n\n///\n\n## Перевірте автоматичну документацію API { #check-the-automatic-api-docs }\n\nТепер запустіть ваш застосунок:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nІ відкрийте документацію за адресою [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВи побачите автоматичну документацію API, що включає шляхи з усіх підмодулів, з правильними шляхами (і префіксами) та правильними мітками:\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## Включайте той самий router кілька разів з різними `prefix` { #include-the-same-router-multiple-times-with-different-prefix }\n\nВи також можете використовувати `.include_router()` кілька разів з одним і тим самим router'ом, але з різними префіксами.\n\nЦе може бути корисно, наприклад, щоб публікувати той самий API під різними префіксами, наприклад `/api/v1` і `/api/latest`.\n\nЦе просунуте використання, яке вам може й не знадобитися, але воно є на випадок, якщо потрібно.\n\n## Включіть один `APIRouter` до іншого { #include-an-apirouter-in-another }\n\nТак само як ви можете включити `APIRouter` у застосунок `FastAPI`, ви можете включити `APIRouter` в інший `APIRouter`, використовуючи:\n\n```Python\nrouter.include_router(other_router)\n```\n\nПереконайтеся, що ви робите це до включення `router` в застосунок `FastAPI`, щоб *операції шляху* з `other_router` також були включені.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/body-fields.md",
    "content": "# Тіло — Поля { #body-fields }\n\nТак само як ви можете оголошувати додаткову валідацію та метадані в параметрах *функції операції шляху* за допомогою `Query`, `Path` та `Body`, ви можете оголошувати валідацію та метадані всередині моделей Pydantic, використовуючи `Field` від Pydantic.\n\n## Імпорт `Field` { #import-field }\n\nСпочатку вам потрібно імпортувати це:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n\n/// warning | Попередження\n\nЗверніть увагу, що `Field` імпортується безпосередньо з `pydantic`, а не з `fastapi`, як усе інше (`Query`, `Path`, `Body` тощо).\n\n///\n\n## Оголошення атрибутів моделі { #declare-model-attributes }\n\nПотім ви можете використовувати `Field` з атрибутами моделі:\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field` працює так само, як `Query`, `Path` і `Body`, має ті самі параметри тощо.\n\n/// note | Технічні деталі\n\nНасправді `Query`, `Path` та інші, які ви побачите далі, створюють об'єкти підкласів спільного класу `Param`, який сам є підкласом класу `FieldInfo` з Pydantic.\n\nІ `Field` від Pydantic також повертає екземпляр `FieldInfo`.\n\n`Body` також безпосередньо повертає об'єкти підкласу `FieldInfo`. І є інші, які ви побачите пізніше, що є підкласами класу `Body`.\n\nПам'ятайте, що коли ви імпортуєте `Query`, `Path` та інші з `fastapi`, це фактично функції, які повертають спеціальні класи.\n\n///\n\n/// tip | Порада\n\nЗверніть увагу, що кожен атрибут моделі з типом, значенням за замовчуванням і `Field` має ту саму структуру, що й параметр *функції операції шляху*, з `Field` замість `Path`, `Query` і `Body`.\n\n///\n\n## Додавання додаткової інформації { #add-extra-information }\n\nВи можете оголошувати додаткову інформацію в `Field`, `Query`, `Body` тощо. І вона буде включена до згенерованої JSON Schema.\n\nВи дізнаєтеся більше про додавання додаткової інформації пізніше в документації, коли вивчатимете, як оголошувати приклади.\n\n/// warning | Попередження\n\nДодаткові ключі, передані в `Field`, також будуть присутні в отриманій схемі OpenAPI для вашого застосунку.\nОскільки ці ключі не обов'язково є частиною специфікації OpenAPI, деякі інструменти OpenAPI, наприклад [валідатор OpenAPI](https://validator.swagger.io/), можуть не працювати з вашою згенерованою схемою.\n\n///\n\n## Підсумок { #recap }\n\nВи можете використовувати `Field` від Pydantic, щоб оголошувати додаткову валідацію та метадані для атрибутів моделі.\n\nВи також можете використовувати додаткові keyword arguments, щоб передавати додаткові метадані JSON Schema.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/body-multiple-params.md",
    "content": "# Тіло - Декілька параметрів { #body-multiple-parameters }\n\nТепер, коли ми побачили, як використовувати `Path` і `Query`, розгляньмо більш просунуті варіанти оголошення тіла запиту.\n\n## Змішування `Path`, `Query` та параметрів тіла { #mix-path-query-and-body-parameters }\n\nПо-перше, звісно, ви можете вільно змішувати оголошення параметрів `Path`, `Query` та тіла запиту, і **FastAPI** знатиме, що робити.\n\nТакож ви можете оголошувати параметри тіла як необов’язкові, встановивши для них значення за замовчуванням `None`:\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | Примітка\n\nЗверніть увагу, що в цьому випадку параметр `item`, який береться з тіла, є необов'язковим. Оскільки має значення за замовчуванням `None`.\n\n///\n\n## Декілька параметрів тіла { #multiple-body-parameters }\n\nУ попередньому прикладi *операції шляху* очікували б JSON-тіло з атрибутами `Item`, наприклад:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\nАле ви також можете оголосити декілька параметрів тіла, наприклад `item` та `user`:\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\n\nУ цьому випадку **FastAPI** помітить, що у функції є більше ніж один параметр тіла (є два параметри, які є моделями Pydantic).\n\nТож він використає назви параметрів як ключі (назви полів) у тілі та очікуватиме тіло такого вигляду:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | Примітка\n\nЗверніть увагу, що хоча `item` оголошено так само, як і раніше, тепер він очікується всередині тіла з ключем `item`.\n\n///\n\n**FastAPI** виконає автоматичне перетворення із запиту, щоб параметр `item` отримав свій конкретний вміст, і те ж саме для `user`.\n\nВін виконає валідацію складених даних і задокументує це таким чином у схемі OpenAPI та в автоматичній документації.\n\n## Одиничні значення в тілі { #singular-values-in-body }\n\nТак само як є `Query` і `Path` для визначення додаткових даних для параметрів запиту та шляху, **FastAPI** надає еквівалентний `Body`.\n\nНаприклад, розширивши попередню модель, ви можете вирішити додати ще один ключ `importance` у те саме тіло, окрім `item` і `user`.\n\nЯкщо оголосити його як є, оскільки це одиничне значення, **FastAPI** припустить, що це параметр запиту.\n\nАле ви можете вказати **FastAPI** обробляти його як інший ключ тіла, використовуючи `Body`:\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\n\nУ цьому випадку **FastAPI** очікуватиме тіло такого вигляду:\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\nЗнову ж таки, він перетворюватиме типи даних, перевірятиме, документуватиме тощо.\n\n## Декілька параметрів тіла та query { #multiple-body-params-and-query }\n\nЗвісно, ви також можете оголошувати додаткові query параметри щоразу, коли це потрібно, додатково до будь-яких параметрів тіла.\n\nОскільки за замовчуванням одиничні значення інтерпретуються як параметри запиту, вам не потрібно явно додавати `Query`, ви можете просто зробити:\n\n```Python\nq: str | None = None\n```\n\nНаприклад:\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n\n/// info | Інформація\n\n`Body` також має всі ті самі додаткові параметри валідації та метаданих, що й `Query`, `Path` та інші, які ви побачите пізніше.\n\n///\n\n## Вбудувати один параметр тіла { #embed-a-single-body-parameter }\n\nСкажімо, у вас є лише один параметр тіла `item` з моделі Pydantic `Item`.\n\nЗа замовчуванням **FastAPI** очікуватиме його тіло безпосередньо.\n\nАле якщо ви хочете, щоб він очікував JSON з ключем `item`, а всередині нього - вміст моделі, як це відбувається, коли ви оголошуєте додаткові параметри тіла, ви можете використати спеціальний параметр `Body` - `embed`:\n\n```Python\nitem: Item = Body(embed=True)\n```\n\nяк у прикладі:\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\n\nУ цьому випадку **FastAPI** очікуватиме тіло такого вигляду:\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\nзамість:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## Підсумок { #recap }\n\nВи можете додавати кілька параметрів тіла до вашої *функції операції шляху*, навіть якщо запит може мати лише одне тіло.\n\nАле **FastAPI** обробить це, надасть вам правильні дані у функції та перевірить і задокументує правильну схему в *операції шляху*.\n\nТакож ви можете оголошувати одиничні значення, щоб отримувати їх як частину тіла.\n\nІ ви можете вказати **FastAPI** вбудовувати тіло в ключ, навіть коли оголошено лише один параметр.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/body-nested-models.md",
    "content": "# Тіло - Вкладені моделі { #body-nested-models }\n\nЗ **FastAPI** ви можете визначати, перевіряти, документувати та використовувати моделі, які можуть бути вкладені на будь-яку глибину (завдяки Pydantic).\n\n## Поля списку { #list-fields }\n\nВи можете визначити атрибут як підтип. Наприклад, Python-список (`list`):\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\nЦе зробить `tags` списком, хоча не визначається тип елементів списку.\n\n## Поля списку з параметром типу { #list-fields-with-type-parameter }\n\nАле Python має специфічний спосіб оголошення списків з внутрішніми типами або «параметрами типу»:\n\n### Оголошення `list` з параметром типу { #declare-a-list-with-a-type-parameter }\n\nЩоб оголосити типи з параметрами типу (внутрішніми типами), такими як `list`, `dict`, `tuple`,\nпередайте внутрішні тип(и) як «параметри типу», використовуючи квадратні дужки: `[` та `]`\n\n```Python\nmy_list: list[str]\n```\n\nЦе стандартний синтаксис Python для оголошення типів.\n\nВикористовуйте той самий стандартний синтаксис для атрибутів моделей з внутрішніми типами.\n\nОтже, у нашому прикладі, ми можемо зробити `tags` саме «списком рядків»:\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## Типи множин { #set-types }\n\nАле потім ми подумали, що теги не повинні повторюватися, вони, ймовірно, повинні бути унікальними рядками.\n\nІ Python має спеціальний тип даних для множин унікальних елементів — це `set`.\n\nТому ми можемо оголосити `tags` як множину рядків:\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\nНавіть якщо ви отримаєте запит з дубльованими даними, він буде перетворений у множину унікальних елементів.\n\nІ коли ви будете виводити ці дані, навіть якщо джерело містить дублікати, вони будуть виведені як множина унікальних елементів.\n\nІ це буде анотовано/документовано відповідно.\n\n## Вкладені моделі { #nested-models }\n\nКожен атрибут моделі Pydantic має тип.\n\nАле цей тип сам може бути іншою моделлю Pydantic.\n\nОтже, ви можете оголосити глибоко вкладені JSON «об'єкти» з конкретними іменами атрибутів, типами та перевірками.\n\nУсе це, вкладене без обмежень.\n\n### Визначення підмоделі { #define-a-submodel }\n\nНаприклад, ми можемо визначити модель `Image`:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### Використання підмоделі як типу { #use-the-submodel-as-a-type }\n\nА потім ми можемо використовувати її як тип атрибута:\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\nЦе означатиме, що  **FastAPI**  очікуватиме тіло запиту такого вигляду:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\nЗавдяки такій декларації у **FastAPI** ви отримуєте:\n\n* Підтримку в редакторі (автозавершення тощо), навіть для вкладених моделей\n* Конвертацію даних\n* Валідацію даних\n* Автоматичну документацію\n\n## Спеціальні типи та валідація { #special-types-and-validation }\n\nОкрім звичайних типів, таких як `str`, `int`, `float`, та ін. ви можете використовувати складніші типи, які наслідують `str`.\n\nЩоб побачити всі доступні варіанти, ознайомтеся з [Оглядом типів у Pydantic](https://docs.pydantic.dev/latest/concepts/types/). Деякі приклади будуть у наступному розділі.\n\nНаприклад, у моделі `Image` є поле `url`, тому ми можемо оголосити його як `HttpUrl` від Pydantic замість `str`:\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\nРядок буде перевірено як дійсну URL-адресу і задокументовано в JSON Schema / OpenAPI як URL.\n\n## Атрибути зі списками підмоделей { #attributes-with-lists-of-submodels }\n\nУ Pydantic ви можете використовувати моделі як підтипи для `list`, `set` тощо:\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\nЦе означає, що **FastAPI** буде очікувати (конвертувати, валідувати, документувати тощо) JSON тіло запиту у вигляді:\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info | Інформація\n\nЗверніть увагу, що тепер ключ `images` містить список об'єктів зображень.\n\n///\n\n## Глибоко вкладені моделі { #deeply-nested-models }\n\nВи можете визначати вкладені моделі довільної глибини:\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info | Інформація\n\nЗверніть увагу, що в моделі `Offer` є список `Item`ів, які, своєю чергою, можуть мати необов'язковий список `Image`ів.\n\n///\n\n## Тіла запитів, що складаються зі списків { #bodies-of-pure-lists }\n\nЯкщо верхній рівень JSON тіла, яке ви очікуєте, є JSON `масивом` (у Python — `list`), ви можете оголосити тип у параметрі функції, як і в моделях Pydantic:\n\n```Python\nimages: list[Image]\n```\n\nнаприклад:\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## Підтримка в редакторі всюди { #editor-support-everywhere }\n\nВи отримаєте підтримку в редакторі всюди.\n\nНавіть для елементів у списках:\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\nВи не змогли б отримати таку підтримку в редакторі, якби працювали напряму зі  `dict`, а не з моделями Pydantic.\n\nАле вам не потрібно турбуватися про це: вхідні dict'и автоматично конвертуються, а вихідні дані автоматично перетворюються в JSON.\n\n## Тіла з довільними `dict` { #bodies-of-arbitrary-dicts }\n\nВи також можете оголосити тіло як `dict` з ключами одного типу та значеннями іншого типу.\n\nЦе корисно, якщо ви не знаєте наперед, які імена полів будуть дійсними (як у випадку з моделями Pydantic).\n\nЦе буде корисно, якщо ви хочете приймати ключі, які заздалегідь невідомі.\n\n---\n\nЦе також зручно, якщо ви хочете мати ключі іншого типу (наприклад, `int`).\n\nОсь що ми розглянемо далі.\n\nУ цьому випадку ви можете приймати будь-який `dict`, якщо його ключі — це `int`, а значення — `float`:\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip | Порада\n\nМайте на увазі, що в JSON тілі ключі можуть бути лише рядками (`str`).\n\nАле Pydantic автоматично конвертує дані.\n\nЦе означає, що навіть якщо клієнти вашого API надсилатимуть ключі у вигляді рядків, якщо вони містять цілі числа, Pydantic конвертує їх і проведе валідацію.\n\nТобто `dict`, який ви отримаєте як `weights`, матиме ключі типу `int` та значення типу `float`.\n\n///\n\n## Підсумок { #recap }\n\nЗ **FastAPI** ви маєте максимальну гнучкість завдяки моделям Pydantic, зберігаючи при цьому код простим, коротким та елегантним.\n\nА також отримуєте всі переваги:\n\n* Підтримка в редакторі (автодоповнення всюди!)\n* Конвертація даних (парсинг/серіалізація)\n* Валідація даних\n* Документація схем\n* Автоматичне створення документації\n"
  },
  {
    "path": "docs/uk/docs/tutorial/body-updates.md",
    "content": "# Тіло — Оновлення { #body-updates }\n\n## Оновлення із заміною за допомогою `PUT` { #update-replacing-with-put }\n\nЩоб оновити елемент, ви можете використати [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) операцію.\n\nВи можете використати `jsonable_encoder`, щоб перетворити вхідні дані на такі, які можна зберігати як JSON (наприклад, у NoSQL базі даних). Наприклад, перетворюючи `datetime` у `str`.\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT` використовується для отримання даних, які мають замінити чинні дані.\n\n### Попередження про заміну { #warning-about-replacing }\n\nЦе означає, що якщо Ви хочете оновити елемент `bar`, використовуючи `PUT` з тілом:\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\nоскільки він не містить вже збереженого атрибута `\"tax\": 20.2`, модель введення прийме значення за замовчуванням `\"tax\": 10.5`.\n\nІ дані будуть збережені з цим \"новим\" значенням `tax` = `10.5`.\n\n## Часткові оновлення з `PATCH` { #partial-updates-with-patch }\n\nВи також можете використовувати операцію [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) для *часткового* оновлення даних.\n\nЦе означає, що Ви можете надіслати лише ті дані, які хочете оновити, залишаючи інші без змін.\n\n/// note | Примітка\n\n`PATCH` менш поширений і менш відомий, ніж `PUT`.\n\nІ багато команд використовують лише `PUT`, навіть для часткових оновлень.\n\nВи **вільні** використовувати їх так, як хочете, **FastAPI** не накладає жодних обмежень.\n\nАле цей посібник показує вам, більш-менш, як їх задумано використовувати.\n\n///\n\n### Використання параметра `exclude_unset` у Pydantic { #using-pydantics-exclude-unset-parameter }\n\nЯкщо Ви хочете отримувати часткові оновлення, дуже корисно використовувати параметр `exclude_unset` у `.model_dump()` моделі Pydantic.\n\nНаприклад: `item.model_dump(exclude_unset=True)`.\n\nЦе згенерує `dict` лише з тими даними, які були встановлені під час створення моделі `item`, виключаючи значення за замовчуванням.\n\nТоді Ви можете використовувати це, щоб згенерувати `dict` лише з даними, які були встановлені (надіслані у запиті), пропускаючи значення за замовчуванням:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### Використання параметра `update` у Pydantic { #using-pydantics-update-parameter }\n\nТепер Ви можете створити копію наявної моделі за допомогою `.model_copy()`, і передати параметр `update` з `dict`, який містить дані для оновлення.\n\nНаприклад: `stored_item_model.model_copy(update=update_data)`:\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### Підсумок часткових оновлень { #partial-updates-recap }\n\nУ підсумку, щоб застосувати часткові оновлення, Ви:\n\n* (Опціонально) використовуєте `PATCH` замість `PUT`.\n* Отримуєте збережені дані.\n* Поміщаєте ці дані в модель Pydantic.\n* Генеруєте `dict` без значень за замовчуванням з моделі введення (використовуючи `exclude_unset`).\n    * Таким чином Ви оновите лише ті значення, які були явно задані користувачем, замість того, щоб перезаписувати вже збережені значення значеннями за замовчуванням з вашої моделі.\n* Створюєте копію збереженої моделі, оновлюючи її атрибути отриманими частковими оновленнями (використовуючи параметр `update`).\n* Перетворюєте скопійовану модель на щось, що можна зберегти у вашу БД (наприклад, використовуючи `jsonable_encoder`).\n    * Це можна порівняти з повторним використанням методу `.model_dump()` моделі, але це гарантує (і перетворює) значення у типи даних, які можна перетворити на JSON, наприклад, `datetime` на `str`.\n* Зберігаєте дані у вашу БД.\n* Повертаєте оновлену модель.\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | Порада\n\nНасправді Ви можете використовувати цю саму техніку і з операцією HTTP `PUT`.\n\nАле приклад тут використовує `PATCH`, тому що він був створений для таких випадків.\n\n///\n\n/// note | Примітка\n\nЗверніть увагу, що модель запиту все ще проходить валідацію.\n\nТож, якщо Ви хочете отримувати часткові оновлення, які можуть пропускати всі атрибути, Вам потрібно мати модель, де всі атрибути позначені як необов’язкові (зі значеннями за замовчуванням або `None`).\n\nЩоб розрізняти моделі з усіма необов’язковими значеннями для **оновлення** і моделі з обов’язковими значеннями для **створення**, Ви можете скористатись ідеями, описаними у [Додаткові моделі](extra-models.md).\n\n///\n"
  },
  {
    "path": "docs/uk/docs/tutorial/body.md",
    "content": "# Тіло запиту { #request-body }\n\nКоли вам потрібно надіслати дані з клієнта (скажімо, браузера) до вашого API, ви надсилаєте їх як **тіло запиту**.\n\nТіло **запиту** - це дані, надіслані клієнтом до вашого API. Тіло **відповіді** - це дані, які ваш API надсилає клієнту.\n\nВаш API майже завжди має надсилати тіло **відповіді**. Але клієнтам не обов’язково потрібно постійно надсилати тіла **запитів** — інколи вони лише запитують шлях, можливо з деякими параметрами запиту, але не надсилають тіло.\n\nЩоб оголосити тіло **запиту**, ви використовуєте [Pydantic](https://docs.pydantic.dev/) моделі з усією їх потужністю та перевагами.\n\n/// info | Інформація\n\nЩоб надіслати дані, ви повинні використовувати один із: `POST` (більш поширений), `PUT`, `DELETE` або `PATCH`.\n\nНадсилання тіла із запитом `GET` має невизначену поведінку в специфікаціях, проте воно підтримується FastAPI лише для дуже складних/екстремальних випадків використання.\n\nОскільки це не рекомендується, інтерактивна документація з Swagger UI не відображатиме документацію для тіла запиту під час використання `GET`, і проксі-сервери в середині можуть не підтримувати її.\n\n///\n\n## Імпортуйте `BaseModel` від Pydantic { #import-pydantics-basemodel }\n\nСпочатку вам потрібно імпортувати `BaseModel` з `pydantic`:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## Створіть свою модель даних { #create-your-data-model }\n\nПотім ви оголошуєте свою модель даних як клас, який успадковується від `BaseModel`.\n\nВикористовуйте стандартні типи Python для всіх атрибутів:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\n\nТак само, як і при оголошенні параметрів запиту, коли атрибут моделі має значення за замовчуванням, він не є обов’язковим. В іншому випадку це потрібно. Використовуйте `None`, щоб зробити його просто необов'язковим.\n\nНаприклад, ця модель вище оголошує JSON \"`об'єкт`\" (або Python `dict`), як:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n...оскільки `description` і `tax` є необов'язковими (зі значенням за замовчуванням `None`), цей JSON \"`об'єкт`\" також буде дійсним:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## Оголосіть її як параметр { #declare-it-as-a-parameter }\n\nЩоб додати модель даних до вашої *операції шляху*, оголосіть її так само, як ви оголосили параметри шляху та запиту:\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n...і вкажіть її тип як модель, яку ви створили, `Item`.\n\n## Результати { #results }\n\nЛише з цим оголошенням типу Python **FastAPI** буде:\n\n* Читати тіло запиту як JSON.\n* Перетворювати відповідні типи (якщо потрібно).\n* Валідувати дані.\n    * Якщо дані недійсні, він поверне гарну та чітку помилку, вказуючи, де саме і які дані були неправильними.\n* Надавати отримані дані у параметрі `item`.\n    * Оскільки ви оголосили його у функції як тип `Item`, ви також матимете всю підтримку редактора (автозаповнення, тощо) для всіх атрибутів та їх типів.\n* Генерувати визначення [Схеми JSON](https://json-schema.org) для вашої моделі, ви також можете використовувати їх де завгодно, якщо це має сенс для вашого проекту.\n* Ці схеми будуть частиною згенерованої схеми OpenAPI і використовуватимуться автоматичною документацією <abbr title=\"User Interfaces - Інтерфейси користувача\">UIs</abbr>.\n\n## Автоматична документація { #automatic-docs }\n\nСхеми JSON ваших моделей будуть частиною вашої схеми, згенерованої OpenAPI, і будуть показані в інтерактивній API документації:\n\n<img src=\"/img/tutorial/body/image01.png\">\n\nА також використовуватимуться в API документації всередині кожної *операції шляху*, якій вони потрібні:\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## Підтримка редактора { #editor-support }\n\nУ вашому редакторі, всередині вашої функції, ви будете отримувати підказки типу та завершення скрізь (це б не сталося, якби ви отримали `dict` замість моделі Pydantic):\n\n<img src=\"/img/tutorial/body/image03.png\">\n\nВи також отримуєте перевірку помилок на наявність операцій з неправильним типом:\n\n<img src=\"/img/tutorial/body/image04.png\">\n\nЦе не випадково, весь каркас був побудований навколо цього дизайну.\n\nІ він був ретельно перевірений на етапі проектування, перед будь-яким впровадженням, щоб переконатися, що він працюватиме з усіма редакторами.\n\nБули навіть деякі зміни в самому Pydantic, щоб підтримати це.\n\nПопередні скріншоти були зроблені у [Visual Studio Code](https://code.visualstudio.com).\n\nАле ви отримаєте ту саму підтримку редактора у [PyCharm](https://www.jetbrains.com/pycharm/) та більшість інших редакторів Python:\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip | Порада\n\nЯкщо ви використовуєте [PyCharm](https://www.jetbrains.com/pycharm/) як ваш редактор, ви можете використати [Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/).\n\nВін покращує підтримку редакторів для моделей Pydantic за допомогою:\n\n* автозаповнення\n* перевірки типу\n* рефакторингу\n* пошуку\n* інспекції\n\n///\n\n## Використовуйте модель { #use-the-model }\n\nУсередині функції ви можете отримати прямий доступ до всіх атрибутів об’єкта моделі:\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## Тіло запиту + параметри шляху { #request-body-path-parameters }\n\nВи можете одночасно оголошувати параметри шляху та тіло запиту.\n\n**FastAPI** розпізнає, що параметри функції, які відповідають параметрам шляху, мають бути **взяті з шляху**, а параметри функції, які оголошуються як моделі Pydantic, **взяті з тіла запиту**.\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n\n## Тіло запиту + шлях + параметри запиту { #request-body-path-query-parameters }\n\nВи також можете оголосити параметри **тіло**, **шлях** і **запит** одночасно.\n\n**FastAPI** розпізнає кожен з них і візьме дані з потрібного місця.\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\nПараметри функції будуть розпізнаватися наступним чином:\n\n* Якщо параметр також оголошено в **шляху**, він використовуватиметься як параметр шляху.\n* Якщо параметр має **сингулярний тип** (наприклад, `int`, `float`, `str`, `bool` тощо), він буде інтерпретуватися як параметр **запиту**.\n* Якщо параметр оголошується як тип **Pydantic моделі**, він інтерпретується як **тіло** **запиту**.\n\n/// note | Примітка\n\nFastAPI буде знати, що значення `q` не є обов'язковим через значення за замовчуванням `= None`.\n\n`str | None` FastAPI не використовує, щоб визначити, що значення не є обов’язковим - він знатиме, що воно не є обов’язковим, тому що має значення за замовчуванням `= None`.\n\nАле додавання анотацій типів дозволить вашому редактору надати вам кращу підтримку та виявляти помилки.\n\n///\n\n## Без Pydantic { #without-pydantic }\n\nЯкщо ви не хочете використовувати моделі Pydantic, ви також можете використовувати параметри **Body**. Перегляньте документацію для [Тіло - Кілька параметрів: Окремі значення в тілі](body-multiple-params.md#singular-values-in-body).\n"
  },
  {
    "path": "docs/uk/docs/tutorial/cookie-param-models.md",
    "content": "# Моделі параметрів Cookie { #cookie-parameter-models }\n\nЯкщо у вас є група **cookies**, які пов'язані між собою, ви можете створити **Pydantic-модель**, щоб оголосити їх. 🍪\n\nЦе дозволить вам повторно **використовувати модель** у **різних місцях**, а також оголосити валідацію та метадані для всіх параметрів одночасно. 😎\n\n/// note | Примітка\n\nЦе підтримується з версії FastAPI `0.115.0`. 🤓\n\n///\n\n/// tip | Порада\n\nЦя ж техніка застосовується до `Query`, `Cookie` та `Header`. 😎\n\n///\n\n## Cookie з Pydantic-моделлю { #cookies-with-a-pydantic-model }\n\nОголосіть **cookie**-параметри, які вам потрібні, у **Pydantic-моделі**, а потім оголосіть параметр як `Cookie`:\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI** буде **витягувати** дані для **кожного поля** з **cookies**, отриманих у запиті, і передавати вам Pydantic-модель, яку ви визначили.\n\n## Перевірка у документації { #check-the-docs }\n\nВи можете побачити визначені cookies в інтерфейсі документації за адресою `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info | Інформація\n\nМайте на увазі, що оскільки **браузери обробляють cookies** особливим чином і «за лаштунками», вони **не** дозволяють **JavaScript** легко з ними працювати.\n\nЯкщо ви зайдете до **інтерфейсу документації API** за адресою `/docs`, ви зможете побачити **документацію** для cookies у ваших *операціях шляху*.\n\nАле навіть якщо ви заповните дані й натиснете \"Execute\", оскільки інтерфейс документації працює з **JavaScript**, cookies не будуть відправлені, і ви побачите **помилку**, ніби ви не ввели жодних значень.\n\n///\n\n## Заборона додаткових cookie { #forbid-extra-cookies }\n\nУ деяких спеціальних випадках (ймовірно, не дуже поширених) ви можете захотіти **обмежити** cookies, які хочете отримувати.\n\nВаш API тепер має можливість контролювати власну <dfn title=\"Це жарт, про всяк випадок. Це не має стосунку до згоди на cookies, просто кумедно, що навіть API тепер може відхиляти бідні cookies. Візьміть печиво. 🍪\">згоду на cookies</dfn>. 🤪🍪\n\nВи можете використовувати налаштування моделі Pydantic, щоб `forbid` будь-які `extra` поля:\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\nЯкщо клієнт спробує надіслати якісь **додаткові cookies**, він отримає відповідь з **помилкою**.\n\nБідні банери cookie, які так старанно намагаються отримати вашу згоду, щоб <dfn title=\"Це ще один жарт. Не звертайте на мене уваги. Випийте трохи кави до свого печива. ☕\">API її відхилила</dfn>. 🍪\n\nНаприклад, якщо клієнт спробує надіслати cookie `santa_tracker` зі значенням `good-list-please`, він отримає відповідь з помилкою, яка повідомить, що `santa_tracker` <dfn title=\"Санта не схвалює нестачу cookies. 🎅 Гаразд, досить жартів про cookies.\">cookie не дозволено</dfn>:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## Підсумок { #summary }\n\nВи можете використовувати **Pydantic-моделі** для оголошення <dfn title=\"Візьміть останнє печиво перед тим, як підете. 🍪\">**cookies**</dfn> у **FastAPI**. 😎\n"
  },
  {
    "path": "docs/uk/docs/tutorial/cookie-params.md",
    "content": "# Параметри кукі { #cookie-parameters }\n\nВи можете визначати параметри кукі таким же чином, як визначаються параметри `Query` і `Path`.\n\n## Імпорт `Cookie` { #import-cookie }\n\nСпочатку імпортуйте `Cookie`:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## Визначення параметрів `Cookie` { #declare-cookie-parameters }\n\nПотім визначте параметри кукі, використовуючи таку ж конструкцію як для `Path` і `Query`.\n\nВи можете визначити значення за замовчуванням, а також усі додаткові параметри валідації чи анотації:\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Технічні деталі\n\n`Cookie` це \"сестра\" класів `Path` і `Query`. Вони також наслідуються від одного спільного класу `Param`.\n\nАле пам'ятайте, що коли ви імпортуєте `Query`, `Path`, `Cookie` та інше з `fastapi`, це фактично функції, що повертають спеціальні класи.\n\n///\n\n/// info\n\nДля визначення кукі ви маєте використовувати `Cookie`, тому що в іншому випадку параметри будуть інтерпретовані як параметри запиту.\n\n///\n\n/// info\n\nМайте на увазі, що оскільки **браузери обробляють кукі** спеціальним чином і за лаштунками, вони **не** дозволяють **JavaScript** легко взаємодіяти з ними.\n\nЯкщо ви перейдете до **інтерфейсу документації API** за адресою `/docs`, ви зможете побачити **документацію** для кукі для ваших *операцій шляху*.\n\nАле навіть якщо ви **заповните дані** і натиснете \"Execute\", оскільки інтерфейс документації працює з **JavaScript**, кукі не буде надіслано, і ви побачите повідомлення про **помилку**, ніби ви не ввели жодних значень.\n\n///\n\n## Підсумки { #recap }\n\nВизначайте кукі за допомогою `Cookie`, використовуючи той же спільний шаблон, що і `Query` та `Path`.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/cors.md",
    "content": "# CORS (Обмін ресурсами між різними джерелами) { #cors-cross-origin-resource-sharing }\n\n[CORS або «Cross-Origin Resource Sharing»](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) є ситуація, коли фронтенд, що працює в браузері, містить JavaScript-код, який взаємодіє з бекендом, розташованим в іншому «джерелі» (origin).\n\n## Джерело (Origin) { #origin }\n\nДжерело визначається комбінацією протоколу (`http`, `https`), домену (`myapp.com`, `localhost`, `localhost.tiangolo.com`), порту (`80`, `443`, `8080`).\n\n\nНаприклад, такі адреси вважаються різними джерелами:\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\nНавіть якщо вони всі містять `localhost`, вони мають різні протоколи або порти, що робить їх окремими «джерелами».\n\n## Кроки { #steps }\n\nПрипустимо, що ваш фронтенд працює в браузері на `http://localhost:8080`, а його JavaScript намагається відправити запит до бекенду, який працює на `http://localhost` (Оскільки ми не вказуємо порт, браузер за замовчуванням припускає порт `80`).\n\nПотім браузер надішле HTTP-запит `OPTIONS` до бекенду на порту `:80`, і якщо бекенд надішле відповідні заголовки, що дозволяють комунікацію з цього іншого джерела (`http://localhost:8080`), тоді браузер на порту `:8080` дозволить JavaScript у фронтенді надіслати свій запит до бекенду на порту `:80`.\n\nЩоб досягти цього, бекенд на порту `:80` повинен мати список «дозволених джерел».\n\nУ цьому випадку список має містити `http://localhost:8080`, щоб фронтенд на порту `:8080` працював коректно.\n\n## Дикі карти { #wildcards }\n\nМожна також оголосити список як `\"*\"` (дика карта), що означає дозвіл для всіх джерел.\n\nОднак це дозволить лише певні типи комунікації, виключаючи все, що пов'язане з обліковими даними: кукі, заголовки авторизації, як-от ті, що використовуються з токенами носія, тощо.\n\nТому для коректної роботи краще явно вказувати дозволені джерела.\n\n## Використання `CORSMiddleware` { #use-corsmiddleware }\n\nВи можете налаштувати це у вашому додатку **FastAPI** за допомогою `CORSMiddleware`.\n\n* Імпортуйте `CORSMiddleware`.\n* Створіть список дозволених джерел (у вигляді рядків).\n* Додайте його як «проміжне програмне забезпечення» у ваш додаток **FastAPI**.\n\nТакож можна вказати, чи дозволяє ваш бекенд:\n\n* Облікові дані (заголовки авторизації, кукі, тощо).\n* Конкретні HTTP-методи (`POST`, `PUT`) або всі за допомогою `\"*\"`\n* Конкретні HTTP-заголовки або всі за допомогою `\"*\"`.\n\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\n\nПараметри за замовчуванням у реалізації `CORSMiddleware` є досить обмеженими, тому вам потрібно явно увімкнути конкретні джерела, методи або заголовки, щоб браузерам було дозволено використовувати їх у міждоменному контексті.\n\nПідтримуються такі аргументи:\n\n* `allow_origins` - Список джерел, яким дозволено здійснювати міждоменні запити. Наприклад `['https://example.org', 'https://www.example.org']`. Ви можете використовувати `['*']`, щоб дозволити будь-яке джерело.\n* `allow_origin_regex` - Рядок регулярного виразу для відповідності джерелам, яким дозволено здійснювати міждоменні запити. Наприклад, `'https://.*\\.example\\.org'`.\n* `allow_methods` - Список HTTP-методів, дозволених для міждоменних запитів. За замовчуванням `['GET']`. Ви можете використовувати `['*']`, щоб дозволити всі стандартні методи.\n* `allow_headers` - Список HTTP-заголовків запиту, які підтримуються для міждоменних запитів. За замовчуванням `[]`. Ви можете використовувати `['*']`, щоб дозволити всі заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` і `Content-Type` завжди дозволені для [простих CORS-запитів](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).\n* `allow_credentials` - Визначає, чи повинні підтримуватися кукі для міждоменних запитів. За замовчуванням `False`.\n\n    Жоден із параметрів `allow_origins`, `allow_methods` і `allow_headers` не можна встановлювати як `['*']`, якщо `allow_credentials` встановлено як `True`. Усі вони мають бути [явно вказані](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards).\n\n* `expose_headers` - Вказує, які заголовки відповіді повинні бути доступні для браузера. За замовчуванням `[]`.\n* `max_age` - Встановлює максимальний час (у секундах) для кешування CORS-відповідей у браузерах. За замовчуванням `600`.\n\nЦе проміжне програмне забезпечення обробляє два типи HTTP-запитів...\n\n### Попередні CORS-запити { #cors-preflight-requests }\n\nЦе будь-які `OPTIONS` - запити, що містять заголовки `Origin` та `Access-Control-Request-Method`.\n\nУ такому випадку проміжне програмне забезпечення перехопить вхідний запит і відповість відповідними CORS-заголовками, повертаючи або `200`, або `400` для інформаційних цілей.\n\n### Прості запити { #simple-requests }\n\nБудь-які запити із заголовком `Origin`. У цьому випадку проміжне програмне забезпечення пропустить запит як звичайний, але додасть відповідні CORS-заголовки у відповідь.\n\n## Додаткова інформація { #more-info }\n\nБільше про <abbr title=\"Cross-Origin Resource Sharing - Обмін ресурсами між різними джерелами\">CORS</abbr> можна дізнатися в [документації Mozilla про CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).\n\n/// note | Технічні деталі\n\nТакож можна використовувати `from starlette.middleware.cors import CORSMiddleware`.\n\n**FastAPI** надає кілька проміжних програмних забезпечень у `fastapi.middleware` для зручності розробників. Але більшість доступного проміжного програмного забезпечення походить безпосередньо зі Starlette.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/tutorial/debugging.md",
    "content": "# Налагодження { #debugging }\n\nВи можете під'єднати дебагер у вашому редакторі коду, наприклад, у Visual Studio Code або PyCharm.\n\n## Виклик `uvicorn` { #call-uvicorn }\n\nУ вашому FastAPI-додатку імпортуйте та запустіть `uvicorn` безпосередньо:\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### Про `__name__ == \"__main__\"` { #about-name-main }\n\nГоловна мета використання `__name__ == \"__main__\"` — це забезпечення виконання певного коду лише тоді, коли ваш файл запускається так:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nале не виконується, коли інший файл імпортує його, наприклад:\n\n```Python\nfrom myapp import app\n```\n\n#### Детальніше { #more-details }\n\nПрипустимо, ваш файл називається `myapp.py`.\n\nЯкщо ви запустите його так:\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\nтоді внутрішня змінна `__name__` у вашому файлі, яка створюється автоматично Python, матиме значення рядка `\"__main__\"`.\n\nОтже, цей блок коду:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nбуде виконаний.\n\n---\n\nЦе не станеться, якщо ви імпортуєте цей модуль (файл).\n\nОтже, якщо у вас є інший файл `importer.py` з:\n\n```Python\nfrom myapp import app\n\n# Ще трохи коду\n```\n\nу цьому випадку автоматично створена змінна `__name__` всередині `myapp.py` не матиме значення `\"__main__\"`.\n\nОтже, рядок:\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\nне буде виконано.\n\n/// info\n\nДля отримання додаткової інформації дивіться [офіційну документацію Python](https://docs.python.org/3/library/__main__.html).\n\n///\n\n## Запуск коду з вашим дебагером { #run-your-code-with-your-debugger }\n\nОскільки ви запускаєте сервер Uvicorn безпосередньо з вашого коду, ви можете запустити вашу Python програму (ваш FastAPI-додаток) безпосередньо з дебагера.\n\n---\n\nНаприклад, у Visual Studio Code ви можете:\n\n* Перейдіть на панель «Debug».\n* «Add configuration...».\n* Виберіть «Python»\n* Запустіть дебагер з опцією \"`Python: Current File (Integrated Terminal)`\".\n\nПісля цього він запустить сервер з вашим кодом **FastAPI**, зупиниться на точках зупину тощо.\n\nОсь як це може виглядати:\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\nЯкщо ви використовуєте PyCharm, ви можете:\n\n* Відкрити меню «Run».\n* Вибрати опцію «Debug...».\n* Потім з'явиться контекстне меню.\n* Вибрати файл для налагодження (у цьому випадку, `main.py`).\n\nПісля цього він запустить сервер з вашим кодом **FastAPI**, зупиниться на точках зупину тощо.\n\nОсь як це може виглядати:\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/uk/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# Класи як залежності { #classes-as-dependencies }\n\nПерш ніж заглибитися у систему **впровадження залежностей**, оновімо попередній приклад.\n\n## `dict` з попереднього прикладу { #a-dict-from-the-previous-example }\n\nУ попередньому прикладі ми повертали `dict` із нашого «залежного»:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\nАле тоді ми отримуємо `dict` у параметрі `commons` функції операції шляху.\n\nІ ми знаємо, що редактори не можуть надати багато підтримки (наприклад, автодоповнення) для `dict`, адже вони не знають їхніх ключів і типів значень.\n\nМожна зробити краще…\n\n## Що робить об’єкт залежністю { #what-makes-a-dependency }\n\nДотепер ви бачили залежності, оголошені як функції.\n\nАле це не єдиний спосіб оголошувати залежності (хоча, ймовірно, найпоширеніший).\n\nКлючовий момент у тому, що залежність має бути «викликаємим».\n\n«Викликаємий» у Python - це будь-що, що Python може «викликати», як функцію.\n\nОтже, якщо у вас є об’єкт `something` (який може й не бути функцією) і ви можете «викликати» його (виконати) так:\n\n```Python\nsomething()\n```\n\nабо\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\nтоді це «викликаємий».\n\n## Класи як залежності { #classes-as-dependencies_1 }\n\nВи могли помітити, що для створення екземпляра класу Python ви використовуєте той самий синтаксис.\n\nНаприклад:\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\nУ цьому випадку `fluffy` - екземпляр класу `Cat`.\n\nА для створення `fluffy` ви «викликаєте» `Cat`.\n\nОтже, клас Python також є **викликаємим**.\n\nТож у **FastAPI** ви можете використовувати клас Python як залежність.\n\nНасправді **FastAPI** перевіряє, що це «викликаємий» об’єкт (функція, клас чи щось інше) і які параметри в нього оголошені.\n\nЯкщо ви передаєте «викликаємий» як залежність у **FastAPI**, він проаналізує параметри цього об’єкта і обробить їх так само, як параметри для функції операції шляху. Включно з підзалежностями.\n\nЦе також стосується викликаємих без жодних параметрів. Так само, як і для функцій операцій шляху без параметрів.\n\nТоді ми можемо змінити залежність `common_parameters` вище на клас `CommonQueryParams`:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\nЗверніть увагу на метод `__init__`, який використовують для створення екземпляра класу:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n…він має ті самі параметри, що й наш попередній `common_parameters`:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\nСаме ці параметри **FastAPI** використає, щоб «розв’язати» залежність.\n\nВ обох випадках буде:\n\n- Необов’язковий параметр запиту `q`, який є `str`.\n- Параметр запиту `skip`, який є `int`, зі значенням за замовчуванням `0`.\n- Параметр запиту `limit`, який є `int`, зі значенням за замовчуванням `100`.\n\nВ обох випадках дані будуть перетворені, перевірені й задокументовані в схемі OpenAPI тощо.\n\n## Використання { #use-it }\n\nТепер ви можете оголосити залежність, використовуючи цей клас.\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI** викликає клас `CommonQueryParams`. Це створює «екземпляр» цього класу, і цей екземпляр буде передано як параметр `commons` у вашу функцію.\n\n## Анотація типів проти `Depends` { #type-annotation-vs-depends }\n\nЗверніть увагу, що вище ми двічі пишемо `CommonQueryParams`:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Порада\n\nНадавайте перевагу варіанту з `Annotated`, якщо це можливо.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\nОстанній `CommonQueryParams` у:\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n - це те, що **FastAPI** фактично використає, щоб дізнатися, яка залежність.\n\nСаме з нього **FastAPI** витягне оголошені параметри і саме його **FastAPI** буде викликати.\n\n---\n\nУ цьому випадку перший `CommonQueryParams` у:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Порада\n\nНадавайте перевагу варіанту з `Annotated`, якщо це можливо.\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n…не має жодного особливого значення для **FastAPI**. FastAPI не використовуватиме його для перетворення даних, перевірки тощо (адже для цього використовується `Depends(CommonQueryParams)`).\n\nНасправді ви могли б написати просто:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Порада\n\nНадавайте перевагу варіанту з `Annotated`, якщо це можливо.\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n…як у:\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\nАле оголошувати тип рекомендується - так ваш редактор знатиме, що буде передано в параметр `commons`, і зможе допомагати з автодоповненням, перевірками типів тощо:\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## Скорочення { #shortcut }\n\nАле ви бачите, що тут маємо деяке дублювання коду - `CommonQueryParams` пишемо двічі:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Порада\n\nНадавайте перевагу варіанту з `Annotated`, якщо це можливо.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n**FastAPI** надає скорочення для таких випадків, коли залежність - це саме клас, який **FastAPI** «викличе», щоб створити екземпляр цього класу.\n\nДля таких випадків ви можете зробити так:\n\nЗамість того щоб писати:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Порада\n\nНадавайте перевагу варіанту з `Annotated`, якщо це можливо.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n…напишіть:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Порада\n\nНадавайте перевагу варіанту з `Annotated`, якщо це можливо.\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\nВи оголошуєте залежність як тип параметра і використовуєте `Depends()` без параметрів, замість того щоб вдруге писати повний клас усередині `Depends(CommonQueryParams)`.\n\nТой самий приклад виглядатиме так:\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n…і **FastAPI** знатиме, що робити.\n\n/// tip | Порада\n\nЯкщо це здається заплутанішим, ніж корисним, просто не використовуйте це - воно не є обов’язковим.\n\nЦе лише скорочення. Адже **FastAPI** дбає про мінімізацію дублювання коду.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# Залежності в декораторах операцій шляху { #dependencies-in-path-operation-decorators }\n\nІноді вам насправді не потрібне значення, яке повертає залежність, у вашій *функції операції шляху*.\n\nАбо залежність узагалі не повертає значення.\n\nАле її все одно потрібно виконати/опрацювати.\n\nДля таких випадків, замість оголошення параметра *функції операції шляху* з `Depends`, ви можете додати `list` `dependencies` до *декоратора операції шляху*.\n\n## Додайте `dependencies` до *декоратора операції шляху* { #add-dependencies-to-the-path-operation-decorator }\n\n*Декоратор операції шляху* приймає необов'язковий аргумент `dependencies`.\n\nЦе має бути `list` з `Depends()`:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\nЦі залежності будуть виконані/оброблені так само, як звичайні залежності. Але їхні значення (якщо щось повертають) не передаватимуться у вашу *функцію операції шляху*.\n\n/// tip | Порада\n\nДеякі редактори перевіряють невикористані параметри функцій і показують їх як помилки.\n\nВикористовуючи ці `dependencies` у *декораторі операції шляху*, ви можете гарантувати їх виконання та водночас уникнути помилок редактора/інструментів.\n\nЦе також може допомогти уникнути плутанини для нових розробників, які бачать невикористаний параметр у вашому коді й можуть вирішити, що він зайвий.\n\n///\n\n/// info | Інформація\n\nУ цьому прикладі ми використовуємо вигадані власні заголовки `X-Key` і `X-Token`.\n\nАле в реальних випадках, під час впровадження безпеки, ви отримаєте більше користі, використовуючи вбудовані [Інструменти безпеки (наступний розділ)](../security/index.md).\n\n///\n\n## Помилки залежностей і значення, що повертаються { #dependencies-errors-and-return-values }\n\nВи можете використовувати ті самі *функції* залежностей, що й зазвичай.\n\n### Вимоги залежностей { #dependency-requirements }\n\nВони можуть оголошувати вимоги до запиту (наприклад, заголовки) або інші підзалежності:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### Підіймати винятки { #raise-exceptions }\n\nЦі залежності можуть `raise` винятки, так само як і звичайні залежності:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### Значення, що повертаються { #return-values }\n\nВони можуть повертати значення або ні - ці значення не використовуватимуться.\n\nОтже, ви можете перевикористати звичайну залежність (яка повертає значення), яку вже застосовуєте деінде, і навіть якщо значення не буде використано, залежність буде виконана:\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## Залежності для групи операцій шляху { #dependencies-for-a-group-of-path-operations }\n\nДалі, читаючи про структурування великих застосунків ([Більші застосунки - декілька файлів](../../tutorial/bigger-applications.md)), можливо з кількома файлами, ви дізнаєтеся, як оголосити один параметр `dependencies` для групи *операцій шляху*.\n\n## Глобальні залежності { #global-dependencies }\n\nДалі ми побачимо, як додати залежності до всього застосунку `FastAPI`, щоб вони застосовувалися до кожної *операції шляху*.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# Залежності з yield { #dependencies-with-yield }\n\nFastAPI підтримує залежності, які виконують деякі <dfn title='інколи також називається «код виходу», «код очищення», «код завершення», «код закриття», «код виходу менеджера контексту» тощо'>додаткові кроки після завершення</dfn>.\n\nЩоб це зробити, використовуйте `yield` замість `return` і напишіть додаткові кроки (код) після нього.\n\n/// tip | Порада\n\nПереконайтесь, що ви використовуєте `yield` лише один раз на залежність.\n\n///\n\n/// note | Технічні деталі\n\nБудь-яка функція, яку можна використовувати з:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) або\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nбуде придатною як залежність у **FastAPI**.\n\nНасправді FastAPI використовує ці два декоратори внутрішньо.\n\n///\n\n## Залежність бази даних з `yield` { #a-database-dependency-with-yield }\n\nНаприклад, ви можете використати це, щоб створити сесію бази даних і закрити її після завершення.\n\nПеред створенням відповіді виконується лише код до і включно з оператором `yield`:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\nЗначення, передане `yield`, впроваджується в *операції шляху* та інші залежності:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\nКод після оператора `yield` виконується після відповіді:\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip | Порада\n\nМожете використовувати як `async`, так і звичайні функції.\n\n**FastAPI** зробить усе правильно з кожною з них, так само як і зі звичайними залежностями.\n\n///\n\n## Залежність з `yield` та `try` { #a-dependency-with-yield-and-try }\n\nЯкщо ви використовуєте блок `try` в залежності з `yield`, ви отримаєте будь-який виняток, який був згенерований під час використання залежності.\n\nНаприклад, якщо якийсь код десь посередині, в іншій залежності або в *операції шляху*, зробив «rollback» транзакції бази даних або створив будь-який інший виняток, ви отримаєте цей виняток у своїй залежності.\n\nТож ви можете обробити цей конкретний виняток усередині залежності за допомогою `except SomeException`.\n\nТак само ви можете використовувати `finally`, щоб гарантувати виконання завершальних кроків незалежно від того, був виняток чи ні.\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## Підзалежності з `yield` { #sub-dependencies-with-yield }\n\nВи можете мати підзалежності та «дерева» підзалежностей будь-якого розміру і форми, і будь-яка або всі з них можуть використовувати `yield`.\n\n**FastAPI** гарантує, що «exit code» у кожній залежності з `yield` буде виконано в правильному порядку.\n\nНаприклад, `dependency_c` може залежати від `dependency_b`, а `dependency_b` - від `dependency_a`:\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\nІ всі вони можуть використовувати `yield`.\n\nУ цьому випадку `dependency_c`, щоб виконати свій завершальний код, потребує, щоб значення з `dependency_b` (тут `dep_b`) все ще було доступним.\n\nІ, у свою чергу, `dependency_b` потребує, щоб значення з `dependency_a` (тут `dep_a`) було доступним для свого завершального коду.\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\nТак само ви можете мати деякі залежності з `yield`, а інші - з `return`, і частина з них може залежати від інших.\n\nІ ви можете мати одну залежність, яка вимагає кілька інших залежностей з `yield` тощо.\n\nВи можете мати будь-які комбінації залежностей, які вам потрібні.\n\n**FastAPI** подбає, щоб усе виконувалося в правильному порядку.\n\n/// note | Технічні деталі\n\nЦе працює завдяки Python [Менеджерам контексту](https://docs.python.org/3/library/contextlib.html).\n\n**FastAPI** використовує їх внутрішньо, щоб досягти цього.\n\n///\n\n## Залежності з `yield` та `HTTPException` { #dependencies-with-yield-and-httpexception }\n\nВи бачили, що можна використовувати залежності з `yield` і мати блоки `try`, які намагаються виконати деякий код, а потім запускають завершальний код після `finally`.\n\nТакож можна використовувати `except`, щоб перехопити згенерований виняток і щось із ним зробити.\n\nНаприклад, ви можете підняти інший виняток, як-от `HTTPException`.\n\n/// tip | Порада\n\nЦе доволі просунута техніка, і в більшості випадків вона вам не знадобиться, адже ви можете піднімати винятки (включно з `HTTPException`) всередині іншого коду вашого застосунку, наприклад, у *функції операції шляху*.\n\nАле вона є, якщо вам це потрібно. 🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\nЯкщо ви хочете перехоплювати винятки та створювати на їх основі користувацьку відповідь, створіть [Користувацький обробник винятків](../handling-errors.md#install-custom-exception-handlers).\n\n## Залежності з `yield` та `except` { #dependencies-with-yield-and-except }\n\nЯкщо ви перехоплюєте виняток за допомогою `except` у залежності з `yield` і не піднімаєте його знову (або не піднімаєте новий виняток), FastAPI не зможе помітити, що стався виняток, так само як це було б у звичайному Python:\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\nУ цьому випадку клієнт побачить відповідь *HTTP 500 Internal Server Error*, як і має бути, з огляду на те, що ми не піднімаємо `HTTPException` або подібний виняток, але на сервері **не буде жодних логів** чи інших ознак того, що це була за помилка. 😱\n\n### Завжди використовуйте `raise` у залежностях з `yield` та `except` { #always-raise-in-dependencies-with-yield-and-except }\n\nЯкщо ви перехоплюєте виняток у залежності з `yield`, якщо тільки ви не піднімаєте інший `HTTPException` або подібний, **вам слід повторно підняти початковий виняток**.\n\nВи можете повторно підняти той самий виняток, використовуючи `raise`:\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\nТепер клієнт отримає ту саму відповідь *HTTP 500 Internal Server Error*, але сервер матиме наш користувацький `InternalError` у логах. 😎\n\n## Виконання залежностей з `yield` { #execution-of-dependencies-with-yield }\n\nПослідовність виконання приблизно така, як на цій діаграмі. Час тече зверху вниз. І кожна колонка - це одна з частин, що взаємодіють або виконують код.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exception handler\nparticipant dep as Dep with yield\nparticipant operation as Path Operation\nparticipant tasks as Background tasks\n\n    Note over client,operation: Can raise exceptions, including HTTPException\n    client ->> dep: Start request\n    Note over dep: Run code up to yield\n    opt raise Exception\n        dep -->> handler: Raise Exception\n        handler -->> client: HTTP error response\n    end\n    dep ->> operation: Run dependency, e.g. DB session\n    opt raise\n        operation -->> dep: Raise Exception (e.g. HTTPException)\n        opt handle\n            dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception\n        end\n        handler -->> client: HTTP error response\n    end\n\n    operation ->> client: Return response to client\n    Note over client,operation: Response is already sent, can't change it anymore\n    opt Tasks\n        operation -->> tasks: Send background tasks\n    end\n    opt Raise other exception\n        tasks -->> tasks: Handle exceptions in the background task code\n    end\n```\n\n/// info | Інформація\n\nЛише **одна відповідь** буде надіслана клієнту. Це може бути одна з помилкових відповідей або відповідь від *операції шляху*.\n\nПісля відправлення однієї з цих відповідей іншу відправити не можна.\n\n///\n\n/// tip | Порада\n\nЯкщо ви піднімаєте будь-який виняток у коді з *функції операції шляху*, він буде переданий у залежності з `yield`, включно з `HTTPException`. У більшості випадків ви захочете повторно підняти той самий виняток або новий із залежності з `yield`, щоб переконатися, що його коректно оброблено.\n\n///\n\n## Ранній вихід і `scope` { #early-exit-and-scope }\n\nЗазвичай завершальний код залежностей з `yield` виконується **після того**, як відповідь надіслано клієнту.\n\nАле якщо ви знаєте, що вам не потрібно використовувати залежність після повернення з *функції операції шляху*, ви можете використати `Depends(scope=\"function\")`, щоб сказати FastAPI, що слід закрити залежність після повернення з *функції операції шляху*, але **до** надсилання **відповіді**.\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()` приймає параметр `scope`, який може бути:\n\n* `\"function\"`: запустити залежність перед *функцією операції шляху*, що обробляє запит, завершити залежність після завершення *функції операції шляху*, але **до** того, як відповідь буде відправлена клієнту. Тобто функція залежності буде виконуватися **навколо** *функції операції **шляху***.\n* `\"request\"`: запустити залежність перед *функцією операції шляху*, що обробляє запит (подібно до `\"function\"`), але завершити **після** того, як відповідь буде відправлена клієнту. Тобто функція залежності буде виконуватися **навколо** циклу **запиту** та відповіді.\n\nЯкщо не вказано, і залежність має `yield`, за замовчуванням `scope` дорівнює `\"request\"`.\n\n### `scope` для підзалежностей { #scope-for-sub-dependencies }\n\nКоли ви оголошуєте залежність із `scope=\"request\"` (за замовчуванням), будь-яка підзалежність також має мати `scope` рівний `\"request\"`.\n\nАле залежність з `scope` рівним `\"function\"` може мати залежності з `scope` `\"function\"` і `scope` `\"request\"`.\n\nЦе тому, що будь-яка залежність має бути здатною виконати свій завершальний код раніше за підзалежності, оскільки вона може все ще потребувати їх під час свого завершального коду.\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Dep scope=\"request\"\nparticipant dep_func as Dep scope=\"function\"\nparticipant operation as Path Operation\n\n    client ->> dep_req: Start request\n    Note over dep_req: Run code up to yield\n    dep_req ->> dep_func: Pass dependency\n    Note over dep_func: Run code up to yield\n    dep_func ->> operation: Run path operation with dependency\n    operation ->> dep_func: Return from path operation\n    Note over dep_func: Run code after yield\n    Note over dep_func: ✅ Dependency closed\n    dep_func ->> client: Send response to client\n    Note over client: Response sent\n    Note over dep_req: Run code after yield\n    Note over dep_req: ✅ Dependency closed\n```\n\n## Залежності з `yield`, `HTTPException`, `except` і фоновими задачами { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\nЗалежності з `yield` еволюціонували з часом, щоб покрити різні сценарії та виправити деякі проблеми.\n\nЯкщо ви хочете дізнатися, що змінювалося в різних версіях FastAPI, прочитайте про це в просунутому посібнику користувача: [Розширені залежності - Залежності з `yield`, `HTTPException`, `except` і фоновими задачами](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks).\n## Менеджери контексту { #context-managers }\n\n### Що таке «Менеджери контексту» { #what-are-context-managers }\n\n«Менеджери контексту» - це будь-які Python-об'єкти, які можна використовувати в операторі `with`.\n\nНаприклад, [можна використати `with`, щоб прочитати файл](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files):\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\nПід капотом `open(\"./somefile.txt\")` створює об'єкт, який називається «Менеджер контексту».\n\nКоли блок `with` завершується, він гарантує закриття файлу, навіть якщо були винятки.\n\nКоли ви створюєте залежність з `yield`, **FastAPI** внутрішньо створить для неї менеджер контексту й поєднає його з іншими пов'язаними інструментами.\n\n### Використання менеджерів контексту в залежностях з `yield` { #using-context-managers-in-dependencies-with-yield }\n\n/// warning | Попередження\n\nЦе, загалом, «просунута» ідея.\n\nЯкщо ви тільки починаєте з **FastAPI**, можливо, варто наразі пропустити це.\n\n///\n\nУ Python ви можете створювати Менеджери контексту, [створивши клас із двома методами: `__enter__()` і `__exit__()`](https://docs.python.org/3/reference/datamodel.html#context-managers).\n\nВи також можете використовувати їх усередині залежностей **FastAPI** з `yield`, використовуючи\n`with` або `async with` у середині функції залежності:\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip | Порада\n\nІнший спосіб створити менеджер контексту:\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) або\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\nвикористовуючи їх для декорування функції з одним `yield`.\n\nСаме це **FastAPI** використовує внутрішньо для залежностей з `yield`.\n\nАле вам не потрібно використовувати ці декоратори для залежностей FastAPI (і не варто).\n\nFastAPI зробить це за вас внутрішньо.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# Глобальні залежності { #global-dependencies }\n\nДля деяких типів застосунків ви можете захотіти додати залежності до всього застосунку.\n\nПодібно до того, як ви можете [додавати `dependencies` до *декораторів операцій шляху*](dependencies-in-path-operation-decorators.md), ви можете додати їх до застосунку `FastAPI`.\n\nУ такому разі вони будуть застосовані до всіх *операцій шляху* в застосунку:\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\nУсі ідеї з розділу про [додавання `dependencies` до *декораторів операцій шляху*](dependencies-in-path-operation-decorators.md) так само застосовні, але в цьому випадку - до всіх *операцій шляху* в застосунку.\n\n## Залежності для груп *операцій шляху* { #dependencies-for-groups-of-path-operations }\n\nПізніше, читаючи про структуру більших застосунків ([Більші застосунки - кілька файлів](../../tutorial/bigger-applications.md)), можливо з кількома файлами, ви дізнаєтеся, як оголосити єдиний параметр `dependencies` для групи *операцій шляху*.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/dependencies/index.md",
    "content": "# Залежності { #dependencies }\n\n**FastAPI** має дуже потужну, але інтуїтивну систему **<dfn title=\"також відомо як: компоненти, ресурси, провайдери, сервіси, інжектовані об'єкти\">Впровадження залежностей</dfn>**.\n\nВона створена так, щоб бути дуже простою у використанні та щоб полегшити будь-якому розробнику інтеграцію інших компонентів з **FastAPI**.\n\n## Що таке «Впровадження залежностей» { #what-is-dependency-injection }\n\nУ програмуванні **«Впровадження залежностей»** означає, що існує спосіб для вашого коду (у цьому випадку ваших *функцій операцій шляху*) задекларувати речі, які йому потрібні для роботи: «залежності».\n\nА потім ця система (у цьому випадку **FastAPI**) подбає про все необхідне, щоб надати вашому коду ці потрібні залежності («інжектувати» залежності).\n\nЦе дуже корисно, коли вам потрібно:\n\n* Мати спільну логіку (одна й та сама логіка знову і знову).\n* Ділитися з’єднаннями з базою даних.\n* Примусово застосовувати безпеку, автентифікацію, вимоги до ролей тощо.\n* І багато іншого...\n\nВсе це з мінімізацією дублювання коду.\n\n## Перші кроки { #first-steps }\n\nРозгляньмо дуже простий приклад. Він буде таким простим, що поки що не дуже корисним.\n\nАле так ми зможемо зосередитися на тому, як працює система **Впровадження залежностей**.\n\n### Створіть залежність або «залежний» { #create-a-dependency-or-dependable }\n\nСпочатку зосередьмося на залежності.\n\nЦе просто функція, яка може приймати ті самі параметри, що й *функція операції шляху*:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\nОсь і все.\n\n**2 рядки**.\n\nІ вона має ту саму форму та структуру, що й усі ваші *функції операцій шляху*.\n\nМожете думати про неї як про *функцію операції шляху* без «декоратора» (без `@app.get(\"/some-path\")`).\n\nІ вона може повертати будь-що.\n\nУ цьому випадку ця залежність очікує:\n\n* Необов’язковий параметр запиту `q` типу `str`.\n* Необов’язковий параметр запиту `skip` типу `int`, за замовчуванням `0`.\n* Необов’язковий параметр запиту `limit` типу `int`, за замовчуванням `100`.\n\nПотім вона просто повертає `dict`, що містить ці значення.\n\n/// info | Інформація\n\nFastAPI додав підтримку `Annotated` (і почав її рекомендувати) у версії 0.95.0.\n\nЯкщо у вас старіша версія, ви отримаєте помилки при спробі використати `Annotated`.\n\nПереконайтеся, що ви [Оновіть версію FastAPI](../../deployment/versions.md#upgrading-the-fastapi-versions) щонайменше до 0.95.1 перед використанням `Annotated`.\n\n///\n\n### Імпортуйте `Depends` { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### Оголосіть залежність у «залежному» { #declare-the-dependency-in-the-dependant }\n\nТак само, як ви використовуєте `Body`, `Query` тощо з параметрами вашої *функції операції шляху*, використовуйте `Depends` з новим параметром:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\nХоча ви використовуєте `Depends` у параметрах вашої функції так само, як `Body`, `Query` тощо, `Depends` працює трохи інакше.\n\nВи передаєте в `Depends` лише один параметр.\n\nЦей параметр має бути чимось на кшталт функції.\n\nВи її не викликаєте безпосередньо (не додавайте дужки в кінці), ви просто передаєте її як параметр у `Depends()`.\n\nІ ця функція приймає параметри так само, як і *функції операцій шляху*.\n\n/// tip | Порада\n\nУ наступному розділі ви побачите, які ще «речі», окрім функцій, можна використовувати як залежності.\n\n///\n\nЩоразу, коли надходить новий запит, **FastAPI** подбає про:\n\n* Виклик вашої функції-залежності («залежного») з правильними параметрами.\n* Отримання результату з вашої функції.\n* Присвоєння цього результату параметру у вашій *функції операції шляху*.\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\nТаким чином ви пишете спільний код один раз, а **FastAPI** подбає про його виклик для ваших *операцій шляху*.\n\n/// check | Перевірте\n\nЗверніть увагу, що вам не потрібно створювати спеціальний клас і передавати його кудись у **FastAPI**, щоб «зареєструвати» його чи щось подібне.\n\nВи просто передаєте його в `Depends`, і **FastAPI** знає, що робити далі.\n\n///\n\n## Спільне використання залежностей `Annotated` { #share-annotated-dependencies }\n\nУ наведених вище прикладах видно невелике **дублювання коду**.\n\nКоли вам потрібно використати залежність `common_parameters()`, доводиться писати весь параметр з анотацією типу та `Depends()`:\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\nАле оскільки ми використовуємо `Annotated`, ми можемо зберегти це значення `Annotated` у змінній і використовувати його в кількох місцях:\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | Порада\n\nЦе просто стандартний Python, це називається «псевдонім типу» і насправді не є специфічним для **FastAPI**.\n\nАле оскільки **FastAPI** базується на стандартах Python, включно з `Annotated`, ви можете використати цей трюк у своєму коді. 😎\n\n///\n\nЗалежності продовжать працювати як очікується, і **найкраще** те, що **інформація про типи буде збережена**, а це означає, що ваш редактор зможе й надалі надавати **автозаповнення**, **помилки в рядку** тощо. Те саме і для інших інструментів, як-от `mypy`.\n\nЦе буде особливо корисно у **великій кодовій базі**, де ви використовуєте **одні й ті самі залежності** знову і знову в **багатьох *операціях шляху***.\n\n## Бути `async` чи не бути `async` { #to-async-or-not-to-async }\n\nОскільки залежності також викликатимуться **FastAPI** (так само, як і ваші *функції операцій шляху*), під час визначення ваших функцій діють ті самі правила.\n\nВи можете використовувати `async def` або звичайний `def`.\n\nІ ви можете оголошувати залежності з `async def` всередині звичайних *функцій операцій шляху* з `def`, або залежності з `def` всередині *функцій операцій шляху* з `async def` тощо.\n\nЦе не має значення. **FastAPI** знатиме, що робити.\n\n/// note | Примітка\n\nЯкщо ви не впевнені, перегляньте розділ [Async: *\"In a hurry?\"*](../../async.md#in-a-hurry) про `async` і `await` у документації.\n\n///\n\n## Інтегровано з OpenAPI { #integrated-with-openapi }\n\nУсі декларації запитів, перевірки та вимоги ваших залежностей (і субзалежностей) будуть інтегровані в ту саму схему OpenAPI.\n\nТож інтерактивна документація також міститиме всю інформацію з цих залежностей:\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## Просте використання { #simple-usage }\n\nЯкщо придивитися, *функції операцій шляху* оголошуються для використання щоразу, коли збігаються *шлях* та *операція*, а потім **FastAPI** подбає про виклик функції з правильними параметрами, витягуючи дані із запиту.\n\nНасправді всі (або більшість) вебфреймворків працюють так само.\n\nВи ніколи не викликаєте ці функції безпосередньо. Їх викликає ваш фреймворк (у цьому випадку **FastAPI**).\n\nЗа допомогою системи впровадження залежностей ви також можете вказати **FastAPI**, що ваша *функція операції шляху* також «залежить» від чогось, що має бути виконано до вашої *функції операції шляху*, і **FastAPI** подбає про виконання цього та «інжектування» результатів.\n\nІнші поширені терміни для цієї самої ідеї «впровадження залежностей»:\n\n* ресурси\n* провайдери\n* сервіси\n* інжектовані об’єкти\n* компоненти\n\n## Плагіни **FastAPI** { #fastapi-plug-ins }\n\nІнтеграції та «плагіни» можна будувати за допомогою системи **Впровадження залежностей**. Але насправді **немає потреби створювати «плагіни»**, оскільки, використовуючи залежності, можна оголосити безмежну кількість інтеграцій та взаємодій, які стають доступними для ваших *функцій операцій шляху*.\n\nІ залежності можна створювати дуже просто та інтуїтивно, що дозволяє вам просто імпортувати потрібні пакунки Python і інтегрувати їх з вашими функціями API за кілька рядків коду, буквально.\n\nВи побачите приклади цього в наступних розділах, про реляційні та NoSQL бази даних, безпеку тощо.\n\n## Сумісність **FastAPI** { #fastapi-compatibility }\n\nПростота системи впровадження залежностей робить **FastAPI** сумісним з:\n\n* усіма реляційними базами даних\n* NoSQL базами даних\n* зовнішніми пакунками\n* зовнішніми API\n* системами автентифікації та авторизації\n* системами моніторингу використання API\n* системами інжекції даних у відповідь\n* тощо.\n\n## Просто і потужно { #simple-and-powerful }\n\nХоча ієрархічна система впровадження залежностей дуже проста у визначенні та використанні, вона все ще дуже потужна.\n\nВи можете визначати залежності, які своєю чергою можуть визначати власні залежності.\n\nЗрештою будується ієрархічне дерево залежностей, і система **Впровадження залежностей** подбає про розв’язання всіх цих залежностей (і їхніх субзалежностей) та надання (інжектування) результатів на кожному кроці.\n\nНаприклад, припустімо, у вас є 4 кінцеві точки API (*операції шляху*):\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\nтоді ви могли б додати різні вимоги до дозволів для кожної з них лише за допомогою залежностей і субзалежностей:\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## Інтегровано з **OpenAPI** { #integrated-with-openapi_1 }\n\nУсі ці залежності, декларуючи свої вимоги, також додають параметри, перевірки тощо до ваших *операцій шляху*.\n\n**FastAPI** подбає про додавання всього цього до схеми OpenAPI, щоб це відображалося в інтерактивних системах документації.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# Підзалежності { #sub-dependencies }\n\nВи можете створювати залежності, які мають підзалежності.\n\nВони можуть бути настільки глибокими, наскільки потрібно.\n\nFastAPI подбає про їх розв'язання.\n\n## Перша залежність «dependable» { #first-dependency-dependable }\n\nМожна створити першу залежність («dependable») так:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\nВона оголошує необов'язковий параметр запиту `q` типу `str`, а потім просто повертає його.\n\nЦе досить просто (не дуже корисно), але допоможе зосередитися на тому, як працюють підзалежності.\n\n## Друга залежність, «dependable» і «dependant» { #second-dependency-dependable-and-dependant }\n\nДалі ви можете створити іншу функцію залежності («dependable»), яка водночас оголошує власну залежність (тож вона також є «dependant»):\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\nЗосередьмося на оголошених параметрах:\n\n- Хоча ця функція сама є залежністю («dependable»), вона також оголошує іншу залежність (вона «залежить» від чогось).\n    - Вона залежить від `query_extractor` і присвоює значення, яке він повертає, параметру `q`.\n- Вона також оголошує необов'язкове кукі `last_query` типу `str`.\n    - Якщо користувач не надав параметр запиту `q`, ми використовуємо останній запит, який зберегли раніше в кукі.\n\n## Використання залежності { #use-the-dependency }\n\nПотім ми можемо використати залежність так:\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info | Інформація\n\nЗверніть увагу, що ми оголошуємо лише одну залежність у функції операції шляху — `query_or_cookie_extractor`.\n\nАле FastAPI знатиме, що спочатку треба розв'язати `query_extractor`, щоб передати його результат у `query_or_cookie_extractor` під час виклику.\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## Використання тієї ж залежності кілька разів { #using-the-same-dependency-multiple-times }\n\nЯкщо одна з ваших залежностей оголошена кілька разів для однієї операції шляху, наприклад, кілька залежностей мають спільну підзалежність, FastAPI знатиме, що цю підзалежність потрібно викликати лише один раз на запит.\n\nІ він збереже повернуте значення у <dfn title=\"Утиліта/система для збереження обчислених/згенерованих значень, щоб повторно використовувати їх замість повторного обчислення.\">«кеш»</dfn> і передасть його всім «dependants», яким воно потрібне в цьому конкретному запиті, замість того щоб викликати залежність кілька разів для одного й того ж запиту.\n\nУ просунутому сценарії, коли ви знаєте, що залежність має викликатися на кожному кроці (можливо, кілька разів) у межах того самого запиту замість використання «кешованого» значення, ви можете встановити параметр `use_cache=False` при використанні `Depends`:\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ без Annotated\n\n/// tip | Порада\n\nНадавайте перевагу версії з `Annotated`, якщо це можливо.\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## Підсумок { #recap }\n\nПопри всі модні терміни, система впровадження залежностей досить проста.\n\nЦе просто функції, які виглядають так само, як функції операцій шляху.\n\nВтім вона дуже потужна і дозволяє оголошувати довільно глибоко вкладені «графи» залежностей (дерева).\n\n/// tip | Порада\n\nУсе це може здаватися не надто корисним на простих прикладах.\n\nАле ви побачите, наскільки це корисно, у розділах про **безпеку**.\n\nІ також побачите, скільки коду це вам заощадить.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/tutorial/encoder.md",
    "content": "# JSON-сумісний кодувальник { #json-compatible-encoder }\n\nІснують випадки, коли вам може знадобитися перетворити тип даних (наприклад, модель Pydantic) на щось сумісне з JSON (наприклад, `dict`, `list` тощо).\n\nНаприклад, якщо вам потрібно зберегти це в базі даних.\n\nДля цього **FastAPI** надає функцію `jsonable_encoder()`.\n\n## Використання `jsonable_encoder` { #using-the-jsonable-encoder }\n\nДавайте уявимо, що у вас є база даних `fake_db`, яка приймає лише дані, сумісні з JSON.\n\nНаприклад, вона не приймає об'єкти типу `datetime`, оскільки вони не сумісні з JSON.\n\nОтже, об'єкт типу `datetime` потрібно перетворити на `str`, який містить дані в [форматі ISO](https://en.wikipedia.org/wiki/ISO_8601).\n\nТак само ця база даних не прийматиме модель Pydantic (об'єкт з атрибутами), а лише `dict`.\n\nВи можете використовувати `jsonable_encoder` для цього.\n\nВона приймає об'єкт, такий як модель Pydantic, і повертає його версію, сумісну з JSON:\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\nУ цьому прикладі вона конвертує модель Pydantic у `dict`, а `datetime` у `str`.\n\nРезультат виклику цієї функції — це щось, що можна кодувати з використанням стандарту Python [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps).\n\nВона не повертає великий `str`, який містить дані у форматі JSON (як рядок). Вона повертає стандартну структуру даних Python (наприклад, `dict`) зі значеннями та підзначеннями, які є сумісними з JSON.\n\n/// note | Примітка\n\n`jsonable_encoder` фактично використовується **FastAPI** внутрішньо для перетворення даних. Проте вона корисна в багатьох інших сценаріях.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/tutorial/extra-data-types.md",
    "content": "# Додаткові типи даних { #extra-data-types }\n\nДо цього часу ви використовували загальнопоширені типи даних, такі як:\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\nАле ви також можете використовувати більш складні типи даних.\n\nІ ви все ще матимете ті ж можливості, які були показані до цього:\n\n* Чудова підтримка редактора.\n* Конвертація даних з вхідних запитів.\n* Конвертація даних для відповіді.\n* Валідація даних.\n* Автоматична анотація та документація.\n\n## Інші типи даних { #other-data-types }\n\nОсь додаткові типи даних для використання:\n\n* `UUID`:\n    * Стандартний \"Універсальний унікальний ідентифікатор\", який часто використовується як ID у багатьох базах даних та системах.\n    * У запитах та відповідях буде представлений як `str`.\n* `datetime.datetime`:\n    * Пайтонівський `datetime.datetime`.\n    * У запитах та відповідях буде представлений як `str` у форматі ISO 8601, як: `2008-09-15T15:53:00+05:00`.\n* `datetime.date`:\n    * Пайтонівський `datetime.date`.\n    * У запитах та відповідях буде представлений як `str` у форматі ISO 8601, як: `2008-09-15`.\n* `datetime.time`:\n    * Пайтонівський `datetime.time`.\n    * У запитах та відповідях буде представлений як `str` у форматі ISO 8601, як: `14:23:55.003`.\n* `datetime.timedelta`:\n    * Пайтонівський `datetime.timedelta`.\n    * У запитах та відповідях буде представлений як `float` загальної кількості секунд.\n    * Pydantic також дозволяє представляти це як \"ISO 8601 time diff encoding\", [дивіться документацію для отримання додаткової інформації](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers).\n* `frozenset`:\n    * У запитах і відповідях це буде оброблено так само, як і `set`:\n        * У запитах список буде зчитано, дублікати буде видалено, і його буде перетворено на `set`.\n        * У відповідях `set` буде перетворено на `list`.\n        * Згенерована схема буде вказувати, що значення `set` є унікальними (з використанням JSON Schema's `uniqueItems`).\n* `bytes`:\n    * Стандартний Пайтонівський `bytes`.\n    * У запитах і відповідях це буде оброблено як `str`.\n    * Згенерована схема буде вказувати, що це `str` з \"форматом\" `binary`.\n* `Decimal`:\n    * Стандартний Пайтонівський `Decimal`.\n    * У запитах і відповідях це буде оброблено так само, як і `float`.\n* Ви можете перевірити всі дійсні типи даних Pydantic тут: [типи даних Pydantic](https://docs.pydantic.dev/latest/usage/types/types/).\n\n## Приклад { #example }\n\nОсь приклад *операції шляху* з параметрами, використовуючи деякі з вищезазначених типів.\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\nЗверніть увагу, що параметри всередині функції мають свій звичайний тип даних, і ви можете, наприклад, виконувати звичайні маніпуляції з датами, такі як:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/uk/docs/tutorial/extra-models.md",
    "content": "# Додаткові моделі { #extra-models }\n\nПродовжуючи попередній приклад, часто потрібно мати більше ніж одну пов’язану модель.\n\nОсобливо це стосується моделей користувача, тому що:\n\n* **вхідна модель** повинна мати пароль.\n* **вихідна модель** не повинна містити пароль.\n* **модель бази даних**, ймовірно, повинна містити хеш пароля.\n\n/// danger | Обережно\n\nНіколи не зберігайте паролі користувачів у відкритому вигляді. Завжди зберігайте «безпечний хеш», який потім можна перевірити.\n\nЯкщо ви ще не знаєте, що таке «хеш пароля», ви дізнаєтесь у [розділах про безпеку](security/simple-oauth2.md#password-hashing).\n\n///\n\n## Кілька моделей { #multiple-models }\n\nОсь загальна ідея того, як можуть виглядати моделі з їхніми полями пароля та місцями використання:\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### Про `**user_in.model_dump()` { #about-user-in-model-dump }\n\n#### `.model_dump()` у Pydantic { #pydantics-model-dump }\n\n`user_in` - це модель Pydantic класу `UserIn`.\n\nМоделі Pydantic мають метод `.model_dump()`, який повертає `dict` з даними моделі.\n\nОтже, якщо ми створимо об’єкт Pydantic `user_in` так:\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\nі викличемо:\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\nтепер ми маємо `dict` з даними у змінній `user_dict` (це `dict`, а не об’єкт моделі Pydantic).\n\nА якщо викликати:\n\n```Python\nprint(user_dict)\n```\n\nми отримаємо Python `dict` з:\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### Розпакування `dict` { #unpacking-a-dict }\n\nЯкщо взяти `dict`, наприклад `user_dict`, і передати його у функцію (або клас) як `**user_dict`, Python «розпакує» його. Ключі та значення `user_dict` будуть передані безпосередньо як іменовані аргументи.\n\nОтже, продовжуючи з `user_dict` вище, запис:\n\n```Python\nUserInDB(**user_dict)\n```\n\nдасть еквівалентний результат:\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\nА точніше, використовуючи безпосередньо `user_dict`, з будь-яким його вмістом у майбутньому:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### Модель Pydantic зі вмісту іншої { #a-pydantic-model-from-the-contents-of-another }\n\nЯк у прикладі вище ми отримали `user_dict` з `user_in.model_dump()`, цей код:\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\nбуде еквівалентним:\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n...тому що `user_in.model_dump()` - це `dict`, а ми змушуємо Python «розпакувати» його, передаючи в `UserInDB` з префіксом `**`.\n\nТож ми отримуємо модель Pydantic з даних іншої моделі Pydantic.\n\n#### Розпакування `dict` і додаткові ключові аргументи { #unpacking-a-dict-and-extra-keywords }\n\nДодаючи додатковий іменований аргумент `hashed_password=hashed_password`, як тут:\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n...у підсумку це дорівнює:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning | Попередження\n\nДодаткові допоміжні функції `fake_password_hasher` і `fake_save_user` лише демонструють можливий потік даних і, звісно, не забезпечують реальної безпеки.\n\n///\n\n## Зменшення дублювання { #reduce-duplication }\n\nЗменшення дублювання коду - одна з ключових ідей у **FastAPI**.\n\nАдже дублювання коду підвищує ймовірність помилок, проблем безпеки, розсинхронізації коду (коли ви оновлюєте в одному місці, але не в інших) тощо.\n\nІ ці моделі спільно використовують багато даних та дублюють назви і типи атрибутів.\n\nМожна зробити краще.\n\nМожна оголосити модель `UserBase`, яка буде базовою для інших моделей. Потім створити підкласи цієї моделі, що наслідуватимуть її атрибути (оголошення типів, валідацію тощо).\n\nУся конвертація даних, валідація, документація тощо працюватимуть як зазвичай.\n\nТаким чином, ми оголошуємо лише відмінності між моделями (з відкритим `password`, з `hashed_password` і без пароля):\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` або `anyOf` { #union-or-anyof }\n\nВи можете оголосити відповідь як `Union` двох або більше типів - це означає, що відповідь може бути будь-якого з них.\n\nВ OpenAPI це буде визначено як `anyOf`.\n\nДля цього використайте стандартну підказку типу Python [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union):\n\n/// note | Примітка\n\nПід час визначення [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions) спочатку вказуйте найконкретніший тип, а потім менш конкретний. У прикладі нижче більш конкретний `PlaneItem` стоїть перед `CarItem` у `Union[PlaneItem, CarItem]`.\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### `Union` у Python 3.10 { #union-in-python-3-10 }\n\nУ цьому прикладі ми передаємо `Union[PlaneItem, CarItem]` як значення аргументу `response_model`.\n\nОскільки ми передаємо його як значення аргументу, а не в анотації типу, потрібно використовувати `Union` навіть у Python 3.10.\n\nЯкби це була анотація типу, можна було б використати вертикальну риску, наприклад:\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\nАле якщо записати це як присвоєння `response_model=PlaneItem | CarItem`, отримаємо помилку, тому що Python спробує виконати невалідну операцію між `PlaneItem` і `CarItem`, замість того щоб трактувати це як анотацію типу.\n\n## Список моделей { #list-of-models }\n\nАналогічно можна оголошувати відповіді як списки об’єктів.\n\nДля цього використайте стандартний Python `list`:\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## Відповідь з довільним `dict` { #response-with-arbitrary-dict }\n\nТакож можна оголосити відповідь, використовуючи звичайний довільний `dict`, вказавши лише типи ключів і значень, без моделі Pydantic.\n\nЦе корисно, якщо ви заздалегідь не знаєте допустимі назви полів/атрибутів (які були б потрібні для моделі Pydantic).\n\nУ такому разі можна використати `dict`:\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## Підсумок { #recap }\n\nВикористовуйте кілька моделей Pydantic і вільно наслідуйте для кожного випадку.\n\nНе обов’язково мати одну модель даних на сутність, якщо ця сутність може мати різні «стани». Як у випадку сутності користувача зі станами: з `password`, з `password_hash` і без пароля.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/first-steps.md",
    "content": "# Перші кроки { #first-steps }\n\nНайпростіший файл FastAPI може виглядати так:\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\nСкопіюйте це до файлу `main.py`.\n\nЗапустіть live-сервер:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\nУ виводі є рядок приблизно такого змісту:\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\nЦей рядок показує URL, за яким ваш застосунок обслуговується на вашій локальній машині.\n\n### Перевірте { #check-it }\n\nВідкрийте браузер за адресою [http://127.0.0.1:8000](http://127.0.0.1:8000).\n\nВи побачите JSON-відповідь:\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### Інтерактивна API документація { #interactive-api-docs }\n\nТепер перейдіть сюди [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВи побачите автоматичну інтерактивну API документацію (надається [Swagger UI](https://github.com/swagger-api/swagger-ui)):\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### Альтернативна API документація { #alternative-api-docs }\n\nА тепер перейдіть сюди [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc).\n\nВи побачите альтернативну автоматичну документацію (надається [ReDoc](https://github.com/Rebilly/ReDoc)):\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI** генерує «схему» з усім вашим API, використовуючи стандарт **OpenAPI** для визначення API.\n\n#### «Схема» { #schema }\n\n«Схема» — це визначення або опис чогось. Це не код, який його реалізує, а просто абстрактний опис.\n\n#### API «схема» { #api-schema }\n\nУ цьому випадку, [OpenAPI](https://github.com/OAI/OpenAPI-Specification) є специфікацією, яка визначає, як описати схему вашого API.\n\nЦе визначення схеми включає шляхи (paths) вашого API, можливі параметри, які вони приймають, тощо.\n\n#### «Схема» даних { #data-schema }\n\nТермін «схема» також може відноситися до форми деяких даних, наприклад, вмісту JSON.\n\nУ цьому випадку це означає атрибути JSON і типи даних, які вони мають, тощо.\n\n#### OpenAPI і JSON Schema { #openapi-and-json-schema }\n\nOpenAPI описує схему API для вашого API. І ця схема включає визначення (або «схеми») даних, що надсилаються та отримуються вашим API, за допомогою **JSON Schema**, стандарту для схем даних JSON.\n\n#### Перевірте `openapi.json` { #check-the-openapi-json }\n\nЯкщо вас цікавить, як виглядає «сирий» OpenAPI schema, FastAPI автоматично генерує JSON (schema) з описами всього вашого API.\n\nВи можете побачити це напряму тут: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json).\n\nВи побачите JSON, що починається приблизно так:\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### Для чого потрібний OpenAPI { #what-is-openapi-for }\n\nOpenAPI schema — це те, на чому працюють дві включені системи інтерактивної документації.\n\nТакож існують десятки альтернатив, і всі вони засновані на OpenAPI. Ви можете легко додати будь-яку з цих альтернатив до вашого застосунку, створеного з **FastAPI**.\n\nВи також можете використовувати його для автоматичної генерації коду для клієнтів, які взаємодіють з вашим API. Наприклад, для фронтенд-, мобільних або IoT-застосунків.\n\n### Налаштуйте `entrypoint` застосунку в `pyproject.toml` { #configure-the-app-entrypoint-in-pyproject-toml }\n\nВи можете налаштувати, де знаходиться ваш застосунок, у файлі `pyproject.toml`, приблизно так:\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\nЦей `entrypoint` повідомить команді `fastapi`, що вона має імпортувати застосунок так:\n\n```python\nfrom main import app\n```\n\nЯкщо структура вашого коду виглядала б так:\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\nТоді ви б задали `entrypoint` як:\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\nщо було б еквівалентно:\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` із шляхом { #fastapi-dev-with-path }\n\nВи також можете передати шлях до файлу в команду `fastapi dev`, і вона вгадає обʼєкт FastAPI app, який слід використовувати:\n\n```console\n$ fastapi dev main.py\n```\n\nАле вам доведеться щоразу памʼятати передавати правильний шлях під час виклику команди `fastapi`.\n\nКрім того, інші інструменти можуть не знайти його, наприклад [Розширення VS Code](../editor-support.md) або [FastAPI Cloud](https://fastapicloud.com), тому рекомендується використовувати `entrypoint` у `pyproject.toml`.\n\n### Розгорніть ваш застосунок (необовʼязково) { #deploy-your-app-optional }\n\nЗа бажанням ви можете розгорнути ваш FastAPI-застосунок у [FastAPI Cloud](https://fastapicloud.com), перейдіть і приєднайтеся до списку очікування, якщо ви цього ще не зробили. 🚀\n\nЯкщо у вас вже є обліковий запис **FastAPI Cloud** (ми запросили вас зі списку очікування 😉), ви можете розгорнути ваш застосунок однією командою.\n\nПеред розгортанням переконайтеся, що ви увійшли:\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\nПотім розгорніть ваш застосунок:\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\nОсь і все! Тепер ви можете отримати доступ до вашого застосунку за цим URL. ✨\n\n## Підібʼємо підсумки, крок за кроком { #recap-step-by-step }\n\n### Крок 1: імпортуємо `FastAPI` { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI` — це клас у Python, який надає всю функціональність для вашого API.\n\n/// note | Технічні деталі\n\n`FastAPI` — це клас, який успадковується безпосередньо від `Starlette`.\n\nВи також можете використовувати всю функціональність [Starlette](https://www.starlette.dev/) у `FastAPI`.\n\n///\n\n### Крок 2: створюємо «екземпляр» `FastAPI` { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\nТут змінна `app` буде «екземпляром» класу `FastAPI`.\n\nЦе буде головна точка взаємодії для створення всього вашого API.\n\n### Крок 3: створіть *операцію шляху* { #step-3-create-a-path-operation }\n\n#### Шлях { #path }\n\n«Шлях» тут означає останню частину URL, починаючи з першого `/`.\n\nОтже, у такому URL, як:\n\n```\nhttps://example.com/items/foo\n```\n\n...шлях буде:\n\n```\n/items/foo\n```\n\n/// info\n\n«Шлях» також зазвичай називають «ендпоінтом» або «маршрутом».\n\n///\n\nПід час створення API «шлях» є основним способом розділити «завдання» і «ресурси».\n\n#### Операція { #operation }\n\n«Операція» тут означає один з HTTP «методів».\n\nОдин з:\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n...та більш екзотичних:\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\nУ протоколі HTTP ви можете спілкуватися з кожним шляхом, використовуючи один (або кілька) з цих «методів».\n\n---\n\nПід час створення API зазвичай використовують ці конкретні HTTP методи, щоб виконати певну дію.\n\nЗазвичай використовують:\n\n* `POST`: щоб створити дані.\n* `GET`: щоб читати дані.\n* `PUT`: щоб оновити дані.\n* `DELETE`: щоб видалити дані.\n\nОтже, в OpenAPI кожен з HTTP методів називається «операцією».\n\nМи також будемо називати їх «**операціями**».\n\n#### Визначте *декоратор операції шляху* { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\nДекоратор `@app.get(\"/\")` повідомляє **FastAPI**, що функція одразу нижче відповідає за обробку запитів, які надходять до:\n\n* шляху `/`\n* використовуючи <dfn title=\"HTTP метод GET\"><code>get</code> операція</dfn>\n\n/// info | `@decorator` Інформація\n\nСинтаксис `@something` у Python називається «декоратором».\n\nВи розташовуєте його над функцією. Як гарний декоративний капелюх (мабуть, звідти походить термін).\n\n«Декоратор» бере функцію нижче і виконує з нею якусь дію.\n\nУ нашому випадку, цей декоратор повідомляє **FastAPI**, що функція нижче відповідає **шляху** `/` і **операції** `get`.\n\nЦе і є «**декоратор операції шляху**».\n\n///\n\nМожна також використовувати інші операції:\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\nІ більш екзотичні:\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip\n\nВи можете використовувати кожну операцію (HTTP-метод) як забажаєте.\n\n**FastAPI** не навʼязує жодного конкретного значення.\n\nНаведена тут інформація подана як настанова, а не вимога.\n\nНаприклад, під час використання GraphQL ви зазвичай виконуєте всі дії, використовуючи лише `POST` операції.\n\n///\n\n### Крок 4: визначте **функцію операції шляху** { #step-4-define-the-path-operation-function }\n\nОсь наша «**функція операції шляху**»:\n\n* **шлях**: це `/`.\n* **операція**: це `get`.\n* **функція**: це функція нижче «декоратора» (нижче `@app.get(\"/\")`).\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\nЦе функція Python.\n\n**FastAPI** викликатиме її щоразу, коли отримає запит до URL «`/`», використовуючи операцію `GET`.\n\nУ цьому випадку це `async` функція.\n\n---\n\nВи також можете визначити її як звичайну функцію замість `async def`:\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note\n\nЯкщо ви не знаєте різницю, подивіться [Асинхронність: *«Поспішаєте?»*](../async.md#in-a-hurry).\n\n///\n\n### Крок 5: поверніть вміст { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\nВи можете повернути `dict`, `list`, а також окремі значення `str`, `int` тощо.\n\nТакож можна повернути моделі Pydantic (про це ви дізнаєтесь пізніше).\n\nІснує багато інших обʼєктів і моделей, які будуть автоматично конвертовані в JSON (зокрема ORM тощо). Спробуйте використати свої улюблені — велика ймовірність, що вони вже підтримуються.\n\n### Крок 6: розгорніть його { #step-6-deploy-it }\n\nРозгорніть ваш застосунок у **[FastAPI Cloud](https://fastapicloud.com)** однією командою: `fastapi deploy`. 🎉\n\n#### Про FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** створено тим самим автором і командою, які стоять за **FastAPI**.\n\nВін спрощує процес **створення**, **розгортання** та **доступу** до API з мінімальними зусиллями.\n\nВін переносить той самий **досвід розробника** зі створення застосунків на FastAPI на **розгортання** їх у хмарі. 🎉\n\nFastAPI Cloud — основний спонсор і джерело фінансування для open source проєктів *FastAPI and friends*. ✨\n\n#### Розгортання в інших хмарних провайдерах { #deploy-to-other-cloud-providers }\n\nFastAPI — це open source і базується на стандартах. Ви можете розгортати FastAPI-застосунки у будь-якого хмарного провайдера на ваш вибір.\n\nДотримуйтеся інструкцій вашого хмарного провайдера, щоб розгорнути FastAPI-застосунки з їхньою допомогою. 🤓\n\n## Підібʼємо підсумки { #recap }\n\n* Імпортуйте `FastAPI`.\n* Створіть екземпляр `app`.\n* Напишіть **декоратор операції шляху**, використовуючи декоратори на кшталт `@app.get(\"/\")`.\n* Визначте **функцію операції шляху**; наприклад, `def root(): ...`.\n* Запустіть сервер розробки командою `fastapi dev`.\n* За бажанням розгорніть ваш застосунок за допомогою `fastapi deploy`.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/handling-errors.md",
    "content": "# Обробка помилок { #handling-errors }\n\nЄ багато ситуацій, коли вам потрібно повідомити про помилку клієнта, який використовує ваш API.\n\nЦим клієнтом може бути браузер із фронтендом, код іншого розробника, IoT-пристрій тощо.\n\nМожливо, вам потрібно повідомити клієнта, що:\n\n* У нього недостатньо прав для виконання цієї операції.\n* Він не має доступу до цього ресурсу.\n* Елемент, до якого він намагається отримати доступ, не існує.\n* тощо.\n\nУ таких випадках зазвичай повертається **код статусу HTTP** у діапазоні **400** (від 400 до 499).\n\nЦе схоже на коди статусу HTTP 200 (від 200 до 299). Ці «200» коди статусу означають, що якимось чином запит був «успішним».\n\nКоди статусу в діапазоні 400 означають, що сталася помилка з боку клієнта.\n\nПам'ятаєте всі ці помилки **«404 Not Found»** (і жарти про них)?\n\n## Використання `HTTPException` { #use-httpexception }\n\nЩоб повернути HTTP-відповіді з помилками клієнту, використовуйте `HTTPException`.\n\n### Імпорт `HTTPException` { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### Згенеруйте `HTTPException` у своєму коді { #raise-an-httpexception-in-your-code }\n\n`HTTPException` - це звичайна помилка Python із додатковими даними, які стосуються API.\n\nОскільки це помилка Python, ви не `return` її, а `raise` її.\n\nЦе також означає, що якщо ви перебуваєте всередині допоміжної функції, яку викликаєте всередині своєї *функції операції шляху*, і там згенеруєте `HTTPException` всередині цієї допоміжної функції, то решта коду в *функції операції шляху* не буде виконана. Запит одразу завершиться, і HTTP-помилка з `HTTPException` буде надіслана клієнту.\n\nПеревага генерації виключення замість повернення значення стане більш очевидною в розділі про залежності та безпеку.\n\nУ цьому прикладі, коли клієнт запитує елемент за ID, якого не існує, згенеруйте виключення з кодом статусу `404`:\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### Отримана відповідь { #the-resulting-response }\n\nЯкщо клієнт робить запит за шляхом `http://example.com/items/foo` (де `item_id` `\"foo\"`), він отримає код статусу HTTP 200 і JSON відповідь:\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\nАле якщо клієнт робить запит на `http://example.com/items/bar` (де `item_id` має не існуюче значення `\"bar\"`), то отримає код статусу HTTP 404 (помилка «не знайдено») та JSON відповідь:\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip | Порада\n\nПід час генерації `HTTPException` ви можете передати будь-яке значення, яке може бути перетворене в JSON, як параметр `detail`, а не лише `str`.\n\nВи можете передати `dict`, `list` тощо.\n\nВони обробляються автоматично за допомогою **FastAPI** та перетворюються в JSON.\n\n///\n\n## Додавання власних заголовків { #add-custom-headers }\n\nЄ деякі ситуації, коли корисно мати можливість додавати власні заголовки до HTTP-помилки. Наприклад, для деяких типів безпеки.\n\nЙмовірно, вам не доведеться використовувати це безпосередньо у своєму коді.\n\nАле якщо вам знадобиться це для складного сценарію, ви можете додати власні заголовки:\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## Встановлення власних обробників виключень { #install-custom-exception-handlers }\n\nВи можете додати власні обробники виключень за допомогою [тих самих утиліт для виключень зі Starlette](https://www.starlette.dev/exceptions/).\n\nПрипустімо, у вас є власне виключення `UnicornException`, яке ви (або бібліотека, яку ви використовуєте) можете `raise`.\n\nІ ви хочете обробляти це виключення глобально за допомогою FastAPI.\n\nВи можете додати власний обробник виключень за допомогою `@app.exception_handler()`:\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\nТут, якщо ви звернетеся до `/unicorns/yolo`, *операція шляху* згенерує (`raise`) `UnicornException`.\n\nАле вона буде оброблена функцією-обробником `unicorn_exception_handler`.\n\nОтже, ви отримаєте зрозумілу помилку з кодом статусу HTTP `418` і JSON-вмістом:\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | Технічні деталі\n\nВи також можете використовувати `from starlette.requests import Request` і `from starlette.responses import JSONResponse`.\n\n**FastAPI** надає ті самі `starlette.responses`, що й `fastapi.responses`, просто для зручності для вас, розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette. Те ж саме з `Request`.\n\n///\n\n## Перевизначення обробників виключень за замовчуванням { #override-the-default-exception-handlers }\n\n**FastAPI** має кілька обробників виключень за замовчуванням.\n\nЦі обробники відповідають за повернення стандартних JSON-відповідей, коли ви `raise` `HTTPException`, а також коли запит містить некоректні дані.\n\nВи можете перевизначити ці обробники виключень власними.\n\n### Перевизначення виключень валідації запиту { #override-request-validation-exceptions }\n\nКоли запит містить некоректні дані, **FastAPI** внутрішньо генерує `RequestValidationError`.\n\nІ також включає обробник виключень за замовчуванням для нього.\n\nЩоб перевизначити його, імпортуйте `RequestValidationError` і використовуйте його з `@app.exception_handler(RequestValidationError)` для декорування обробника виключень.\n\nОбробник виключень отримає `Request` і саме виключення.\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\nТепер, якщо ви перейдете за посиланням `/items/foo`, замість того, щоб отримати стандартну JSON-помилку:\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\nви отримаєте текстову версію:\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### Перевизначення обробника помилок `HTTPException` { #override-the-httpexception-error-handler }\n\nАналогічно, ви можете перевизначити обробник `HTTPException`.\n\nНаприклад, ви можете захотіти повернути відповідь у вигляді простого тексту замість JSON для цих помилок:\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | Технічні деталі\n\nВи також можете використовувати `from starlette.responses import PlainTextResponse`.\n\n**FastAPI** надає ті самі `starlette.responses`, що й `fastapi.responses`, просто для зручності для вас, розробника. Але більшість доступних відповідей надходять безпосередньо зі Starlette.\n\n///\n\n/// warning | Попередження\n\nПам’ятайте, що `RequestValidationError` містить інформацію про назву файлу та рядок, де сталася помилка валідації, щоб за потреби ви могли показати це у своїх логах із відповідною інформацією.\n\nАле це означає, що якщо ви просто перетворите це на рядок і повернете цю інформацію напряму, ви можете розкрити трохи інформації про вашу систему, тому тут код витягає та показує кожну помилку незалежно.\n\n///\n\n### Використання тіла `RequestValidationError` { #use-the-requestvalidationerror-body }\n\n`RequestValidationError` містить `body`, який він отримав із некоректними даними.\n\nВи можете використовувати це під час розробки свого додатка, щоб логувати тіло запиту та налагоджувати його, повертати користувачеві тощо.\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\nТепер спробуйте надіслати некоректний елемент, наприклад:\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\nВи отримаєте відповідь, яка повідомить вам, що дані є некоректними, і міститиме отримане тіло запиту:\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### `HTTPException` FastAPI проти `HTTPException` Starlette { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI** має власний `HTTPException`.\n\nІ клас помилки `HTTPException` в **FastAPI** успадковується від класу помилки `HTTPException` у Starlette.\n\nЄдина різниця полягає в тому, що `HTTPException` в **FastAPI** приймає будь-які дані, які можна перетворити на JSON, для поля `detail`, тоді як `HTTPException` у Starlette приймає тільки рядки.\n\nОтже, ви можете продовжувати генерувати `HTTPException` **FastAPI** як зазвичай у своєму коді.\n\nАле коли ви реєструєте обробник виключень, слід реєструвати його для `HTTPException` зі Starlette.\n\nТаким чином, якщо будь-яка частина внутрішнього коду Starlette або розширення чи плагін Starlette згенерує Starlette `HTTPException`, ваш обробник зможе перехопити та обробити її.\n\nУ цьому прикладі, щоб мати можливість використовувати обидва `HTTPException` в одному коді, виключення Starlette перейменовується на `StarletteHTTPException`:\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### Повторне використання обробників виключень **FastAPI** { #reuse-fastapis-exception-handlers }\n\nЯкщо ви хочете використовувати виключення разом із такими ж обробниками виключень за замовчуванням, як у **FastAPI**, ви можете імпортувати та повторно використати обробники виключень за замовчуванням із `fastapi.exception_handlers`:\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\nУ цьому прикладі ви просто друкуєте помилку з дуже виразним повідомленням, але ви зрозуміли основну ідею. Ви можете використовувати виключення, а потім просто повторно використати обробники виключень за замовчуванням.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/header-param-models.md",
    "content": "# Моделі параметрів заголовків { #header-parameter-models }\n\nЯкщо у вас є група пов’язаних **параметрів заголовків**, ви можете створити **Pydantic модель** для їх оголошення.\n\nЦе дозволить вам повторно **використовувати модель** в **різних місцях**, а також оголосити валідації та метадані для всіх параметрів одночасно. 😎\n\n/// note | Примітка\n\nЦя можливість підтримується починаючи з версії FastAPI `0.115.0`. 🤓\n\n///\n\n## Параметри заголовків з використанням Pydantic моделі { #header-parameters-with-a-pydantic-model }\n\nОголосіть потрібні **параметри заголовків** у **Pydantic моделі**, а потім оголосіть параметр як `Header`:\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\n**FastAPI** буде **витягувати** дані для **кожного поля** з **заголовків** у запиті та передавати їх у створену вами Pydantic модель.\n\n## Перевірка в документації { #check-the-docs }\n\nВи можете побачити необхідні заголовки в інтерфейсі документації за адресою `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## Заборонити додаткові заголовки { #forbid-extra-headers }\n\nУ деяких особливих випадках (ймовірно, не дуже поширених) ви можете захотіти **обмежити** заголовки, які хочете отримати.\n\nВи можете використати конфігурацію моделі Pydantic, щоб `заборонити` будь-які `додаткові` поля:\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\nЯкщо клієнт спробує надіслати **додаткові заголовки**, він отримає **помилку** у відповіді.\n\nНаприклад, якщо клієнт спробує надіслати заголовок `tool` зі значенням `plumbus`, він отримає **помилку** у відповіді з повідомленням про те, що параметр заголовка `tool` не дозволений:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## Вимкнути перетворення підкреслень { #disable-convert-underscores }\n\nТак само, як і зі звичайними параметрами заголовків, коли у назвах параметрів є символи підкреслення, вони **автоматично перетворюються на дефіси**.\n\nНаприклад, якщо у коді у вас є параметр заголовка `save_data`, очікуваний HTTP-заголовок буде `save-data`, і він так само відображатиметься в документації.\n\nЯкщо з якоїсь причини вам потрібно вимкнути це автоматичне перетворення, ви також можете зробити це для Pydantic моделей для параметрів заголовків.\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | Попередження\n\nПерш ніж встановлювати `convert_underscores` у значення `False`, пам’ятайте, що деякі HTTP проксі та сервери забороняють використання заголовків із підкресленнями.\n\n///\n\n## Підсумок { #summary }\n\nВи можете використовувати **Pydantic моделі** для оголошення **заголовків** у **FastAPI**. 😎\n"
  },
  {
    "path": "docs/uk/docs/tutorial/header-params.md",
    "content": "# Параметри заголовків { #header-parameters }\n\nВи можете визначати параметри заголовків так само, як визначаєте параметри `Query`, `Path` і `Cookie`.\n\n## Імпорт `Header` { #import-header }\n\nСпочатку імпортуйте `Header`:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## Оголошення параметрів `Header` { #declare-header-parameters }\n\nПотім оголосіть параметри заголовків, використовуючи ту ж структуру, що й для `Path`, `Query` та `Cookie`.\n\nВи можете визначити значення за замовчуванням, а також усі додаткові параметри валідації або анотації:\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | Технічні деталі\n\n`Header` є «сестринським» класом для `Path`, `Query` і `Cookie`. Він також успадковується від того ж спільного класу `Param`.\n\nАле пам’ятайте, що коли ви імпортуєте `Query`, `Path`, `Header` та інші з `fastapi`, то насправді це функції, які повертають спеціальні класи.\n\n///\n\n/// info | Інформація\n\nЩоб оголосити заголовки, потрібно використовувати `Header`, інакше параметри будуть інтерпретуватися як параметри запиту.\n\n///\n\n## Автоматичне перетворення { #automatic-conversion }\n\n`Header` має трохи додаткової функціональності порівняно з тим, що надають `Path`, `Query` та `Cookie`.\n\nБільшість стандартних заголовків розділяються символом «дефіс», також відомим як «символ мінуса» (`-`).\n\nАле змінна, така як `user-agent`, є недійсною в Python.\n\nТому, за замовчуванням, `Header` перетворюватиме символи підкреслення (`_`) у назвах параметрів на дефіси (`-`), щоб отримувати та документувати заголовки.\n\nТакож заголовки HTTP не чутливі до регістру, тож ви можете оголошувати їх у стандартному стилі Python (також відомому як «snake_case»).\n\nТому ви можете використовувати `user_agent`, як зазвичай у коді Python, замість того щоб потрібно було писати з великої літери перші літери, як `User_Agent` або щось подібне.\n\nЯкщо з якоїсь причини вам потрібно вимкнути автоматичне перетворення підкреслень на дефіси, встановіть параметр `convert_underscores` у `Header` в `False`:\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | Попередження\n\nПеред тим як встановити `convert_underscores` в `False`, пам’ятайте, що деякі HTTP-представники та сервери забороняють використання заголовків із підкресленнями.\n\n///\n\n## Дубльовані заголовки { #duplicate-headers }\n\nМожливо отримати дубльовані заголовки. Тобто один і той самий заголовок із кількома значеннями.\n\nВи можете визначити такі випадки, використовуючи список у типізації.\n\nВи отримаєте всі значення дубльованого заголовка у вигляді Python-`list`.\n\nНаприклад, щоб оголосити заголовок `X-Token`, який може з’являтися більше ніж один раз, ви можете написати:\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\nЯкщо ви взаємодієте з цією *операцією шляху*, надсилаючи два HTTP-заголовки, наприклад:\n\n```\nX-Token: foo\nX-Token: bar\n```\n\nВідповідь буде така:\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## Підсумок { #recap }\n\nОголошуйте заголовки за допомогою `Header`, використовуючи той самий загальний підхід, що й для `Query`, `Path` та `Cookie`.\n\nІ не хвилюйтеся про підкреслення у ваших змінних — **FastAPI** подбає про їх перетворення.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/index.md",
    "content": "# Навчальний посібник - Посібник користувача { #tutorial-user-guide }\n\nУ цьому посібнику показано, як користуватися **FastAPI** з більшістю його функцій, крок за кроком.\n\nКожен розділ поступово надбудовується на попередні, але він структурований на окремі теми, щоб ви могли перейти безпосередньо до будь-якої конкретної, щоб вирішити ваші конкретні потреби API.\n\nТакож він створений як довідник для роботи у майбутньому, тож ви можете повернутися і побачити саме те, що вам потрібно.\n\n## Запустіть код { #run-the-code }\n\nУсі блоки коду можна скопіювати та використовувати безпосередньо (це фактично перевірені файли Python).\n\nЩоб запустити будь-який із прикладів, скопіюйте код у файл `main.py`, і запустіть `fastapi dev`:\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n**ДУЖЕ радимо** написати або скопіювати код, відредагувати його та запустити локально.\n\nВикористання його у своєму редакторі – це те, що дійсно показує вам переваги FastAPI, бачите, як мало коду вам потрібно написати, всі перевірки типів, автозаповнення тощо.\n\n---\n\n## Встановлення FastAPI { #install-fastapi }\n\nПершим кроком є встановлення FastAPI.\n\nПереконайтеся, що ви створили [віртуальне середовище](../virtual-environments.md), активували його, а потім **встановіть FastAPI**:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | Примітка\n\nКоли ви встановлюєте через `pip install \"fastapi[standard]\"`, він постачається з деякими типовими необов’язковими стандартними залежностями, включно з `fastapi-cloud-cli`, який дозволяє розгортати в [FastAPI Cloud](https://fastapicloud.com).\n\nЯкщо ви не хочете мати ці необов’язкові залежності, натомість можете встановити `pip install fastapi`.\n\nЯкщо ви хочете встановити стандартні залежності, але без `fastapi-cloud-cli`, ви можете встановити через `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`.\n\n///\n\n/// tip | Порада\n\nFastAPI має [офіційне розширення для VS Code](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) (та Cursor), яке надає багато можливостей, включно з переглядачем операцій шляху, пошуком операцій шляху, навігацією CodeLens у тестах (перехід до визначення з тестів), а також розгортанням і журналами FastAPI Cloud — усе безпосередньо з вашого редактора.\n\n///\n\n## Просунутий посібник користувача { #advanced-user-guide }\n\nІснує також **Просунутий посібник користувача**, який ви зможете прочитати пізніше після цього **Навчальний посібник - Посібник користувача**.\n\n**Просунутий посібник користувача** засновано на цьому, використовує ті самі концепції та навчає вас деяким додатковим функціям.\n\nАле вам слід спочатку прочитати **Навчальний посібник - Посібник користувача** (те, що ви зараз читаєте).\n\nВін розроблений таким чином, що ви можете створити повну програму лише за допомогою **Навчальний посібник - Посібник користувача**, а потім розширити її різними способами, залежно від ваших потреб, використовуючи деякі з додаткових ідей з **Просунутого посібника користувача**.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/metadata.md",
    "content": "# Метадані та URL-адреси документації { #metadata-and-docs-urls }\n\nВи можете налаштувати кілька конфігурацій метаданих у Вашому додатку **FastAPI**.\n\n## Метадані для API { #metadata-for-api }\n\nВи можете встановити такі поля, які використовуються в специфікації OpenAPI та в автоматично згенерованих інтерфейсах документації API:\n\n| Параметр | Тип | Опис |\n|------------|------|-------------|\n| `title` | `str` | Назва API. |\n| `summary` | `str` | Короткий підсумок API. <small>Доступно з OpenAPI 3.1.0, FastAPI 0.99.0.</small> |\n| `description` | `str` | Короткий опис API. Може використовувати Markdown. |\n| `version` | `string` | Версія API. Це версія Вашого додатка, а не OpenAPI. Наприклад, `2.5.0`. |\n| `terms_of_service` | `str` | URL до умов використання API. Якщо вказано, має бути у форматі URL. |\n| `contact` | `dict` | Інформація для контакту з опублікованим API. Може містити кілька полів. <details><summary><code>contact</code> поля</summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Опис</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>Ідентифікаційне ім'я контактної особи або організації.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL, що вказує на контактну інформацію. <strong>МАЄ</strong> бути у форматі URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>Адреса електронної пошти контактної особи або організації. <strong>МАЄ</strong> бути у форматі адреси електронної пошти.</td></tr></tbody></table></details> |\n| `license_info` | `dict` | Інформація про ліцензію для опублікованого API. Може містити кілька полів. <details><summary><code>license_info</code> поля</summary><table><thead><tr><th>Параметр</th><th>Тип</th><th>Опис</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>ОБОВ'ЯЗКОВО</strong> (якщо встановлено <code>license_info</code>). Назва ліцензії для API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>Ліцензійний вираз за [SPDX](https://spdx.org/licenses/) для API. Поле <code>identifier</code> взаємовиключне з полем <code>url</code>. <small>Доступно з OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>URL до ліцензії, яка використовується для API. <strong>МАЄ</strong> бути у форматі URL.</td></tr></tbody></table></details> |\n\nВи можете налаштувати їх наступним чином:\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | Порада\n\nУ полі `description` можна використовувати Markdown, і він буде відображатися у результаті.\n\n///\n\nЗ цією конфігурацією автоматична документація API виглядатиме так:\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## Ідентифікатор ліцензії { #license-identifier }\n\nЗ початку використання OpenAPI 3.1.0 та FastAPI 0.99.0 Ви також можете налаштувати `license_info` за допомогою `identifier` замість `url`.\n\nНаприклад:\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## Метадані для тегів { #metadata-for-tags }\n\nВи також можете додати додаткові метадані для різних тегів, які використовуються для групування операцій шляху, за допомогою параметра `openapi_tags`.\n\nВін приймає список, який містить один словник для кожного тега.\n\nКожен словник може містити:\n\n* `name` (**обов'язково**): `str` з тією ж назвою тегу, яку Ви використовуєте у параметрі `tags` у Ваших *операціях шляху* та `APIRouter`s.\n* `description`: `str` з коротким описом тегу. Може містити Markdown і буде показано в інтерфейсі документації.\n* `externalDocs`: `dict`, який описує зовнішню документацію з такими полями:\n    * `description`: `str` з коротким описом зовнішньої документації.\n    * `url` (**обов'язково**): `str` з URL-адресою зовнішньої документації.\n\n### Створення метаданих для тегів { #create-metadata-for-tags }\n\nСпробуймо це на прикладі з тегами для `users` та `items`.\n\nСтворіть метадані для своїх тегів і передайте їх у параметр `openapi_tags`:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\nЗверніть увагу, що в описах можна використовувати Markdown, наприклад, «login» буде показано жирним шрифтом (**login**), а «fancy» буде показано курсивом (_fancy_).\n\n/// tip | Порада\n\nВам не потрібно додавати метадані для всіх тегів, які Ви використовуєте.\n\n///\n\n### Використовуйте свої теги { #use-your-tags }\n\nВикористовуйте параметр `tags` зі своїми *операціями шляху* (і `APIRouter`s), щоб призначити їх до різних тегів:\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info | Інформація\n\nДетальніше про теги читайте в розділі [Конфігурація операції шляху](path-operation-configuration.md#tags).\n\n///\n\n### Перевірте документацію { #check-the-docs }\n\nТепер, якщо Ви перевірите документацію, вона покаже всі додаткові метадані:\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### Порядок тегів { #order-of-tags }\n\nПорядок кожного словника метаданих тегу також визначає порядок відображення в інтерфейсі документації.\n\nНаприклад, хоча `users` мав би йти після `items` в алфавітному порядку, він відображається перед ними, оскільки ми додали їхні метадані як перший словник у списку.\n\n## URL для OpenAPI { #openapi-url }\n\nЗа замовчуванням схема OpenAPI надається за адресою `/openapi.json`.\n\nАле Ви можете налаштувати це за допомогою параметра `openapi_url`.\n\nНаприклад, щоб налаштувати його на `/api/v1/openapi.json`:\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\nЯкщо Ви хочете повністю вимкнути схему OpenAPI, Ви можете встановити `openapi_url=None`, це також вимкне інтерфейси документації, які її використовують.\n\n## URL-адреси документації { #docs-urls }\n\nВи можете налаштувати два інтерфейси користувача для документації, які включені:\n\n* **Swagger UI**: доступний за адресою `/docs`.\n    * Ви можете змінити його URL за допомогою параметра `docs_url`.\n    * Ви можете вимкнути його, встановивши `docs_url=None`.\n* **ReDoc**: доступний за адресою `/redoc`.\n    * Ви можете змінити його URL за допомогою параметра `redoc_url`.\n    * Ви можете вимкнути його, встановивши `redoc_url=None`.\n\nНаприклад, щоб налаштувати Swagger UI на `/documentation` і вимкнути ReDoc:\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/uk/docs/tutorial/middleware.md",
    "content": "# Middleware { #middleware }\n\nУ **FastAPI** можна додавати middleware.\n\n«Middleware» — це функція, яка працює з кожним **запитом** перед його обробкою будь-якою конкретною *операцією шляху*. А також з кожною **відповіддю** перед її поверненням.\n\n* Вона отримує кожен **запит**, що надходить до вашого застосунку.\n* Потім вона може виконати певні дії із цим **запитом** або запустити необхідний код.\n* Далі вона передає **запит** для обробки рештою застосунку (якоюсь *операцією шляху*).\n* Потім вона отримує **відповідь**, сформовану застосунком (якоюсь *операцією шляху*).\n* Вона може виконати певні дії із цією **відповіддю** або запустити необхідний код.\n* Потім вона повертає **відповідь**.\n\n/// note | Технічні деталі\n\nЯкщо у вас є залежності з `yield`, код виходу виконається *після* middleware.\n\nЯкщо були заплановані фонові задачі (розглянуто в розділі [Фонові задачі](background-tasks.md), ви побачите це пізніше), вони виконаються *після* всіх middleware.\n\n///\n\n## Створення middleware { #create-a-middleware }\n\nЩоб створити middleware, ви використовуєте декоратор `@app.middleware(\"http\")` над функцією.\n\nФункція middleware отримує:\n\n* `request`.\n* Функцію `call_next`, яка отримає `request` як параметр.\n    * Ця функція передасть `request` відповідній *операції шляху*.\n    * Потім вона поверне `response`, згенеровану відповідною *операцією шляху*.\n* Потім ви можете додатково змінити `response` перед тим, як повернути її.\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip\n\nПам’ятайте, що власні пропрієтарні заголовки можна додавати [використовуючи префікс `X-`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers).\n\nАле якщо у вас є власні заголовки, які ви хочете, щоб клієнт у браузері міг побачити, потрібно додати їх до ваших конфігурацій CORS ([CORS (Спільне використання ресурсів між джерелами)](cors.md)) за допомогою параметра `expose_headers`, описаного в [документації Starlette по CORS](https://www.starlette.dev/middleware/#corsmiddleware).\n\n///\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette.requests import Request`.\n\n**FastAPI** надає це для вашої зручності як розробника. Але воно походить безпосередньо зі Starlette.\n\n///\n\n### До і після `response` { #before-and-after-the-response }\n\nВи можете додати код, який буде виконуватися з `request`, до того, як його отримає будь-яка *операція шляху*.\n\nТакож ви можете додати код, який буде виконуватися після того, як `response` буде згенеровано, перед тим як її повернути.\n\nНаприклад, ви можете додати власний заголовок `X-Process-Time`, який міститиме час у секундах, який витратився на обробку запиту та генерацію відповіді:\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip\n\nТут ми використовуємо [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) замість `time.time()` оскільки він може бути більш точним для таких випадків. 🤓\n\n///\n\n## Порядок виконання кількох middleware { #multiple-middleware-execution-order }\n\nКоли ви додаєте кілька middleware, використовуючи або декоратор `@app.middleware()` або метод `app.add_middleware()`, кожен новий middleware обгортає застосунок, утворюючи стек. Останній доданий middleware є *зовнішнім*, а перший — *внутрішнім*.\n\nНа шляху запиту першим виконується *зовнішній* middleware.\n\nНа шляху відповіді він виконується останнім.\n\nНаприклад:\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\nЦе призводить до такого порядку виконання:\n\n* **Запит**: MiddlewareB → MiddlewareA → route\n\n* **Відповідь**: route → MiddlewareA → MiddlewareB\n\nТака поведінка стеку гарантує, що middleware виконуються у передбачуваному та керованому порядку.\n\n## Інші middlewares { #other-middlewares }\n\nВи можете пізніше прочитати більше про інші middlewares у [просунутому посібнику користувача: просунуте middleware](../advanced/middleware.md).\n\nВи дізнаєтесь, як обробляти <abbr title=\"Cross-Origin Resource Sharing - Спільне використання ресурсів між джерелами\">CORS</abbr> за допомогою middleware в наступному розділі.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/path-operation-configuration.md",
    "content": "# Налаштування операції шляху { #path-operation-configuration }\n\nЄ кілька параметрів, які ви можете передати вашому «декоратору операції шляху» для налаштування.\n\n/// warning | Попередження\n\nЗверніть увагу, що ці параметри передаються безпосередньо «декоратору операції шляху», а не вашій «функції операції шляху».\n\n///\n\n## Код статусу відповіді { #response-status-code }\n\nВи можете визначити (HTTP) `status_code`, який буде використано у відповіді вашої «операції шляху».\n\nМожна передати безпосередньо цілий код, наприклад `404`.\n\nЯкщо ви не пам'ятаєте призначення числових кодів, скористайтеся скороченими константами в `status`:\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\nЦей код статусу буде використано у відповіді та додано до схеми OpenAPI.\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette import status`.\n\nFastAPI надає той самий `starlette.status` як `fastapi.status` для вашої зручності як розробника. Але він походить безпосередньо зі Starlette.\n\n///\n\n## Мітки { #tags }\n\nВи можете додати мітки до вашої «операції шляху», передайте параметр `tags` зі `list` із `str` (зазвичай лише один `str`):\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\nВони будуть додані до схеми OpenAPI та використані інтерфейсами автоматичної документації:\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### Мітки з переліками { #tags-with-enums }\n\nУ великому застосунку ви можете накопичити багато міток і захочете переконатися, що завжди використовуєте ту саму мітку для пов'язаних «операцій шляху».\n\nУ таких випадках має сенс зберігати мітки в `Enum`.\n\nFastAPI підтримує це так само, як і зі звичайними строками:\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## Короткий опис і опис { #summary-and-description }\n\nВи можете додати `summary` і `description`:\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## Опис зі строки документації { #description-from-docstring }\n\nОскільки описи зазвичай довгі та займають кілька рядків, ви можете оголосити опис «операції шляху» у <dfn title=\"багаторядкова строка як перший вираз усередині функції (не прив'язаний до жодної змінної), використовується для документації\">строці документації</dfn> функції, і FastAPI прочитає його звідти.\n\nВи можете писати [Markdown](https://en.wikipedia.org/wiki/Markdown) у строці документації, його буде інтерпретовано та показано коректно (з урахуванням відступів у строці документації).\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\nЙого буде використано в інтерактивній документації:\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## Опис відповіді { #response-description }\n\nВи можете вказати опис відповіді параметром `response_description`:\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info | Інформація\n\nЗверніть увагу, що `response_description` стосується саме відповіді, а `description` стосується «операції шляху» загалом.\n\n///\n\n/// check | Перевірте\n\nOpenAPI визначає, що кожна «операція шляху» потребує опису відповіді.\n\nТому, якщо ви його не надасте, FastAPI автоматично згенерує «Successful response».\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## Позначити операцію шляху як застарілу { #deprecate-a-path-operation }\n\nЯкщо потрібно позначити «операцію шляху» як <dfn title=\"застарілий, не рекомендується використовувати\">застарілу</dfn>, але не видаляючи її, передайте параметр `deprecated`:\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\nУ інтерактивній документації вона буде чітко позначена як застаріла:\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\nПодивіться, як виглядають застарілі та незастарілі «операції шляху»:\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## Підсумок { #recap }\n\nВи можете легко налаштовувати та додавати метадані до ваших «операцій шляху», передаючи параметри «декораторам операцій шляху».\n"
  },
  {
    "path": "docs/uk/docs/tutorial/path-params-numeric-validations.md",
    "content": "# Параметри шляху та валідація числових даних { #path-parameters-and-numeric-validations }\n\nТак само як ви можете оголошувати додаткові перевірки та метадані для query параметрів за допомогою `Query`, ви можете оголошувати той самий тип перевірок і метаданих для параметрів шляху за допомогою `Path`.\n\n## Імпорт `Path` { #import-path }\n\nСпочатку імпортуйте `Path` з `fastapi` і імпортуйте `Annotated`:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info | Інформація\n\nFastAPI додав підтримку `Annotated` (і почав рекомендувати його використання) у версії 0.95.0.\n\nЯкщо у вас стара версія, при спробі використати `Annotated` можуть виникати помилки.\n\nПереконайтеся, що ви [оновили версію FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) принаймні до версії 0.95.1 перед використанням `Annotated`.\n\n///\n\n## Оголошення метаданих { #declare-metadata }\n\nВи можете оголошувати всі ті ж параметри, що і для `Query`.\n\nНаприклад, щоб оголосити значення метаданих `title` для параметра шляху `item_id`, ви можете написати:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note | Примітка\n\nПараметр шляху завжди є обов’язковим, оскільки він має бути частиною шляху. Навіть якщо ви оголосите його зі значенням `None` або встановите значення за замовчуванням — це ні на що не вплине, він все одно завжди буде обов’язковим.\n\n///\n\n## Упорядковуйте параметри, як вам потрібно { #order-the-parameters-as-you-need }\n\n/// tip | Порада\n\nЦе, мабуть, не настільки важливо або необхідно, якщо ви використовуєте `Annotated`.\n\n///\n\nПрипустимо, ви хочете оголосити параметр запиту `q` як обов’язковий `str`.\n\nІ вам не потрібно оголошувати нічого іншого для цього параметра, тому вам насправді не потрібно використовувати `Query`.\n\nАле вам все одно потрібно використовувати `Path` для параметра шляху `item_id`. І з певних причин ви не хочете використовувати `Annotated`.\n\nPython видасть помилку, якщо розмістити значення з \"default\" перед значенням, яке не має \"default\".\n\nАле ви можете змінити порядок і розмістити значення без значення за замовчуванням (параметр запиту `q`) першим.\n\nДля **FastAPI** порядок не має значення. Він визначає параметри за їхніми іменами, типами та оголошеннями за замовчуванням (`Query`, `Path` тощо) і не звертає уваги на порядок.\n\nТому ви можете оголосити вашу функцію так:\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\nАле майте на увазі, що якщо ви використовуєте `Annotated`, цієї проблеми не буде, це не матиме значення, оскільки ви не використовуєте значення за замовчуванням параметрів функції для `Query()` або `Path()`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## Упорядковуйте параметри, як вам потрібно: хитрощі { #order-the-parameters-as-you-need-tricks }\n\n/// tip | Порада\n\nЦе, мабуть, не настільки важливо або необхідно, якщо ви використовуєте `Annotated`.\n\n///\n\nОсь **невелика хитрість**, яка може стати в пригоді, хоча вона рідко знадобиться.\n\nЯкщо ви хочете:\n\n* оголосити параметр запиту `q` без `Query` і без жодного значення за замовчуванням\n* оголосити параметр шляху `item_id`, використовуючи `Path`\n* розмістити їх у різному порядку\n* не використовувати `Annotated`\n\n...у Python є спеціальний синтаксис для цього.\n\nПередайте `*` як перший параметр функції.\n\nPython нічого не зробить із цією `*`, але розпізнає, що всі наступні параметри слід викликати як аргументи за ключовим словом (пари ключ-значення), також відомі як <abbr title=\"Походить від: K-ey W-ord Arg-uments\"><code>kwargs</code></abbr>. Навіть якщо вони не мають значення за замовчуванням.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### Краще з `Annotated` { #better-with-annotated }\n\nМайте на увазі, що якщо ви використовуєте `Annotated`, оскільки ви не використовуєте значення за замовчуванням параметрів функції, цієї проблеми не буде, і, ймовірно, вам не потрібно буде використовувати `*`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## Валідація числових даних: більше або дорівнює { #number-validations-greater-than-or-equal }\n\nЗа допомогою `Query` і `Path` (та інших, які ви побачите пізніше) можна оголошувати числові обмеження.\n\nТут, завдяки `ge=1`, `item_id` має бути цілим числом, яке \"`g`reater than or `e`qual\" (більше або дорівнює) `1`.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## Валідація числових даних: більше ніж і менше або дорівнює { #number-validations-greater-than-and-less-than-or-equal }\n\nТе саме застосовується до:\n\n* `gt`: `g`reater `t`han\n* `le`: `l`ess than or `e`qual\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## Валідація числових даних: float, більше ніж і менше ніж { #number-validations-floats-greater-than-and-less-than }\n\nВалідація чисел також працює для значень типу `float`.\n\nОсь де стає важливо мати можливість оголошувати <abbr title=\"greater than - більше ніж\"><code>gt</code></abbr>, а не тільки <abbr title=\"greater than or equal - більше або дорівнює\"><code>ge</code></abbr>. Це дозволяє, наприклад, вимагати, щоб значення було більше `0`, навіть якщо воно менше `1`.\n\nТаким чином, значення `0.5` буде допустимим. Але `0.0` або `0` — ні.\n\nТе саме стосується <abbr title=\"less than - менше ніж\"><code>lt</code></abbr>.\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## Підсумок { #recap }\n\nЗа допомогою `Query`, `Path` (і інших параметрів, які ви ще не бачили) можна оголошувати метадані та перевірки рядків так само як у [Query параметри та валідація рядків](query-params-str-validations.md).\n\nТакож можна оголошувати числові перевірки:\n\n* `gt`: `g`reater `t`han\n* `ge`: `g`reater than or `e`qual\n* `lt`: `l`ess `t`han\n* `le`: `l`ess than or `e`qual\n\n/// info | Інформація\n\n`Query`, `Path` та інші класи, які ви побачите пізніше, є підкласами спільного класу `Param`.\n\nВсі вони мають однакові параметри для додаткових перевірок і метаданих, які ви вже бачили.\n\n///\n\n/// note | Технічні деталі\n\nКоли ви імпортуєте `Query`, `Path` та інші з `fastapi`, насправді це функції.\n\nПри виклику вони повертають екземпляри класів з такими ж іменами.\n\nТобто ви імпортуєте `Query`, яка є функцією. А коли ви її викликаєте, вона повертає екземпляр класу, який теж називається `Query`.\n\nЦі функції створені таким чином (замість використання класів напряму), щоб ваш редактор не відзначав їхні типи як помилки.\n\nТаким чином, ви можете користуватися своїм звичайним редактором і інструментами для програмування без додаткових налаштувань для ігнорування таких помилок.\n\n///\n"
  },
  {
    "path": "docs/uk/docs/tutorial/path-params.md",
    "content": "# Параметри шляху { #path-parameters }\n\nВи можете оголосити «параметри» або «змінні» шляху, використовуючи той самий синтаксис, що й у форматованих рядках Python:\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\nЗначення параметра шляху `item_id` буде передано у вашу функцію як аргумент `item_id`.\n\nОтже, якщо ви запустите цей приклад і перейдете за посиланням [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), то побачите відповідь:\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## Параметри шляху з типами { #path-parameters-with-types }\n\nВи можете оголосити тип параметра шляху у функції, використовуючи стандартні анотації типів Python:\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\nУ цьому випадку `item_id` оголошено як `int`.\n\n/// check | Перевірте\n\nЦе дасть вам підтримку редактора всередині функції з перевірками помилок, автодоповненням тощо.\n\n///\n\n## <dfn title=\"також відомо як: серіалізація, парсинг, маршалізація\">Перетворення</dfn> даних { #data-conversion }\n\nЯкщо ви запустите цей приклад і відкриєте у браузері [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3), то побачите відповідь:\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check | Перевірте\n\nЗверніть увагу, що значення, яке отримала (і повернула) ваша функція, — це `3`, як Python `int`, а не рядок `\"3\"`.\n\nОтже, з таким оголошенням типу **FastAPI** надає вам автоматичний запит <dfn title=\"перетворення рядка, що надходить із HTTP-запиту, у дані Python\">«парсинг»</dfn>.\n\n///\n\n## Валідація даних { #data-validation }\n\nАле якщо ви перейдете у браузері за посиланням [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo), ви побачите гарну HTTP-помилку:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\nтому що параметр шляху `item_id` мав значення `\"foo\"`, яке не є `int`.\n\nТа сама помилка з’явиться, якщо ви передасте `float` замість `int`, як у: [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)\n\n/// check | Перевірте\n\nОтже, з тим самим оголошенням типу в Python **FastAPI** надає вам валідацію даних.\n\nЗверніть увагу, що помилка також чітко вказує саме місце, де валідація не пройшла.\n\nЦе неймовірно корисно під час розробки та налагодження коду, що взаємодіє з вашим API.\n\n///\n\n## Документація { #documentation }\n\nА коли ви відкриєте у браузері [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs), ви побачите автоматичну, інтерактивну, API-документацію на кшталт:\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check | Перевірте\n\nЗнову ж таки, лише з тим самим оголошенням типу в Python **FastAPI** надає вам автоматичну, інтерактивну документацію (з інтеграцією Swagger UI).\n\nЗверніть увагу, що параметр шляху оголошено як ціле число.\n\n///\n\n## Переваги стандартів, альтернативна документація { #standards-based-benefits-alternative-documentation }\n\nІ оскільки згенерована схема відповідає стандарту [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md), існує багато сумісних інструментів.\n\nЧерез це **FastAPI** також надає альтернативну API-документацію (використовуючи ReDoc), до якої ви можете отримати доступ за посиланням [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc):\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\nТак само, існує багато сумісних інструментів. Зокрема інструменти генерації коду для багатьох мов.\n\n## Pydantic { #pydantic }\n\nУся валідація даних виконується за лаштунками за допомогою [Pydantic](https://docs.pydantic.dev/), тож ви отримуєте всі переваги від його використання. І ви знаєте, що ви в надійних руках.\n\nВи можете використовувати ті самі оголошення типів з `str`, `float`, `bool` та багатьма іншими складними типами даних.\n\nДекілька з них розглядаються в наступних розділах посібника.\n\n## Порядок має значення { #order-matters }\n\nПід час створення *операцій шляху* можуть виникати ситуації, коли у вас є фіксований шлях.\n\nНаприклад, `/users/me` — припустімо, це для отримання даних про поточного користувача.\n\nІ тоді у вас також може бути шлях `/users/{user_id}` для отримання даних про конкретного користувача за його ID.\n\nОскільки *операції шляху* оцінюються по черзі, вам потрібно переконатися, що шлях для `/users/me` оголошено перед шляхом для `/users/{user_id}`:\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\nІнакше шлях для `/users/{user_id}` також відповідатиме `/users/me`, «вважаючи», що отримує параметр `user_id` зі значенням `\"me\"`.\n\nТак само ви не можете перевизначити операцію шляху:\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\nЗавжди використовуватиметься перша, оскільки шлях збігається першим.\n\n## Попередньо визначені значення { #predefined-values }\n\nЯкщо у вас є *операція шляху*, яка отримує *параметр шляху*, але ви хочете, щоб можливі коректні значення *параметра шляху* були попередньо визначені, ви можете використати стандартний Python <abbr title=\"Enumeration - Перелік\">`Enum`</abbr>.\n\n### Створіть клас `Enum` { #create-an-enum-class }\n\nІмпортуйте `Enum` і створіть підклас, що наслідується від `str` та `Enum`.\n\nЗавдяки наслідуванню від `str` документація API зможе визначити, що значення повинні бути типу `string`, і зможе коректно їх відобразити.\n\nПісля цього створіть атрибути класу з фіксованими значеннями, які будуть доступними коректними значеннями:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip | Порада\n\nЯкщо вам цікаво, «AlexNet», «ResNet» та «LeNet» — це просто назви моделей машинного навчання <dfn title=\"Технічно, архітектури моделей глибокого навчання\">моделі</dfn>.\n\n///\n\n### Оголосіть *параметр шляху* { #declare-a-path-parameter }\n\nПотім створіть *параметр шляху* з анотацією типу, використовуючи створений вами клас enum (`ModelName`):\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### Перевірте документацію { #check-the-docs }\n\nОскільки доступні значення для *параметра шляху* визначені заздалегідь, інтерактивна документація може красиво їх показати:\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### Робота з Python *переліченнями* { #working-with-python-enumerations }\n\nЗначення *параметра шляху* буде *елементом перелічування*.\n\n#### Порівняйте *елементи перелічування* { #compare-enumeration-members }\n\nВи можете порівнювати його з *елементом перелічування* у створеному вами enum `ModelName`:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### Отримайте *значення перелічування* { #get-the-enumeration-value }\n\nВи можете отримати фактичне значення (у цьому випадку це `str`), використовуючи `model_name.value`, або загалом `your_enum_member.value`:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip | Порада\n\nВи також можете отримати доступ до значення `\"lenet\"` через `ModelName.lenet.value`.\n\n///\n\n#### Поверніть *елементи перелічування* { #return-enumeration-members }\n\nВи можете повертати *елементи enum* з вашої *операції шляху*, навіть вкладені у JSON-тіло (наприклад, `dict`).\n\nВони будуть перетворені на відповідні значення (у цьому випадку рядки) перед поверненням клієнту:\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\nНа стороні клієнта ви отримаєте відповідь у форматі JSON, наприклад:\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## Параметри шляху, що містять шляхи { #path-parameters-containing-paths }\n\nПрипустімо, у вас є *операція шляху* зі шляхом `/files/{file_path}`.\n\nАле вам потрібно, щоб `file_path` сам містив *шлях*, наприклад `home/johndoe/myfile.txt`.\n\nОтже, URL для цього файлу виглядатиме приблизно так: `/files/home/johndoe/myfile.txt`.\n\n### Підтримка OpenAPI { #openapi-support }\n\nOpenAPI не підтримує спосіб оголошення *параметра шляху*, який має містити всередині *шлях*, оскільки це може призвести до сценаріїв, які складно тестувати та визначати.\n\nПроте ви все одно можете зробити це в **FastAPI**, використовуючи один із внутрішніх інструментів Starlette.\n\nІ документація все ще працюватиме, хоча й не додаватиме жодної документації, яка б казала, що параметр має містити шлях.\n\n### Конвертер шляху { #path-convertor }\n\nВикористовуючи опцію безпосередньо зі Starlette, ви можете оголосити *параметр шляху*, що містить *шлях*, використовуючи URL на кшталт:\n\n```\n/files/{file_path:path}\n```\n\nУ цьому випадку ім’я параметра — `file_path`, а остання частина `:path` вказує, що параметр має відповідати будь-якому *шляху*.\n\nОтже, ви можете використати його так:\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip | Порада\n\nВам може знадобитися, щоб параметр містив `/home/johndoe/myfile.txt` із початковою косою рискою (`/`).\n\nУ такому випадку URL виглядатиме так: `/files//home/johndoe/myfile.txt`, із подвійною косою рискою (`//`) між `files` і `home`.\n\n///\n\n## Підсумок { #recap }\n\nЗ **FastAPI**, використовуючи короткі, інтуїтивно зрозумілі та стандартні оголошення типів Python, ви отримуєте:\n\n* Підтримку редактора: перевірка помилок, автодоповнення тощо.\n* Перетворення даних «<dfn title=\"перетворення рядка, що надходить з HTTP-запиту, у дані Python\">парсинг</dfn>»\n* Валідацію даних\n* Анотацію API та автоматичну документацію\n\nІ вам потрібно оголосити їх лише один раз.\n\nЦе, ймовірно, основна видима перевага **FastAPI** порівняно з альтернативними фреймворками (окрім сирої продуктивності).\n"
  },
  {
    "path": "docs/uk/docs/tutorial/query-param-models.md",
    "content": "# Моделі параметрів запиту { #query-parameter-models }\n\nЯкщо у Вас є група **параметрів запиту**, які пов’язані між собою, Ви можете створити **Pydantic-модель** для їх оголошення.\n\nЦе дозволить Вам **повторно використовувати модель** у **різних місцях**, а також оголошувати перевірки та метадані для всіх параметрів одночасно. 😎\n\n/// note | Примітка\n\nЦя можливість підтримується, починаючи з версії FastAPI `0.115.0`. 🤓\n\n///\n\n## Параметри запиту з Pydantic-моделлю { #query-parameters-with-a-pydantic-model }\n\nОголосіть **параметри запиту**, які Вам потрібні, у **Pydantic-моделі**, а потім оголосіть цей параметр як `Query`:\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\n**FastAPI**  буде **витягувати** дані для **кожного поля** з **параметрів запиту** у запиті та передавати їх у визначену вами Pydantic-модель.\n\n## Перевірте документацію { #check-the-docs }\n\nВи можете побачити параметри запиту в UI документації за `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## Заборона зайвих параметрів запиту { #forbid-extra-query-parameters }\n\nУ деяких особливих випадках (ймовірно, не дуже поширених) Ви можете захотіти **обмежити** параметри запиту, які дозволено отримувати.\n\nВи можете використати конфігурацію моделі Pydantic, щоб заборонити (`forbid`) будь-які зайві (`extra`) поля:\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\nЯкщо клієнт спробує надіслати **зайві** дані у **параметрах запиту**, він отримає **відповідь з помилкою**.\n\nНаприклад, якщо клієнт спробує надіслати параметр запиту `tool` зі значенням `plumbus`, як у цьому запиті:\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\nВін отримає відповідь з **помилкою**, яка повідомить, що параметр запиту `tool` не дозволено:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## Підсумок { #summary }\n\nВи можете використовувати **Pydantic-моделі** для оголошення **параметрів запиту** у **FastAPI**. 😎\n\n/// tip | Порада\n\nСпойлер: Ви також можете використовувати Pydantic-моделі для оголошення кукі та заголовків, але про це Ви дізнаєтеся пізніше в цьому посібнику. 🤫\n\n///\n"
  },
  {
    "path": "docs/uk/docs/tutorial/query-params-str-validations.md",
    "content": "# Query параметри та валідація рядків { #query-parameters-and-string-validations }\n\n**FastAPI** дозволяє оголошувати додаткову інформацію та виконувати валідацію для ваших параметрів.\n\nРозглянемо цей додаток як приклад:\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\nQuery параметр `q` має тип `str | None`, що означає, що він має тип `str`, але також може бути `None`, і справді, значення за замовчуванням — `None`, тож FastAPI знатиме, що він не є обов'язковим.\n\n/// note | Примітка\n\nFastAPI знатиме, що значення `q` не є обов’язковим, завдяки значенню за замовчуванням `= None`.\n\nВикористання `str | None` дозволить вашому редактору коду надавати кращу підтримку та виявляти помилки.\n\n///\n\n## Додаткова валідація { #additional-validation }\n\nМи хочемо, щоб навіть якщо `q` є необов’язковим, коли його передають, його довжина не перевищувала 50 символів.\n\n### Імпорт `Query` та `Annotated` { #import-query-and-annotated }\n\nЩоб це зробити, спочатку імпортуємо:\n\n* `Query` з `fastapi`\n* `Annotated` з `typing`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info | Інформація\n\nFastAPI додав підтримку `Annotated` (і почав рекомендувати його) у версії 0.95.0.\n\nЯкщо у вас старіша версія, під час використання `Annotated` можуть виникати помилки.\n\nПереконайтеся, що ви [оновили версію FastAPI](../deployment/versions.md#upgrading-the-fastapi-versions) до принаймні 0.95.1, перш ніж використовувати `Annotated`.\n\n///\n\n## Використання `Annotated` у типі параметра `q` { #use-annotated-in-the-type-for-the-q-parameter }\n\nПам’ятаєте, як я раніше розповідав, що `Annotated` можна використовувати для додавання метаданих до параметрів у [Вступі до типів Python](../python-types.md#type-hints-with-metadata-annotations)?\n\nЗараз саме час використати його разом із FastAPI. 🚀\n\nРаніше ми мали таку анотацію типу:\n\n```Python\nq: str | None = None\n```\n\nТепер ми загорнемо її у `Annotated`, і отримаємо:\n\n```Python\nq: Annotated[str | None] = None\n```\n\nОбидві ці версії означають одне й те саме: `q` — це параметр, який може бути `str` або `None`, і за замовчуванням має значення `None`.\n\nА тепер переходимо до цікавого! 🎉\n\n## Додавання `Query` до `Annotated` у параметр `q` { #add-query-to-annotated-in-the-q-parameter }\n\nТепер, коли у нас є `Annotated`, де ми можемо додавати додаткову інформацію (у цьому випадку — додаткову валідацію), додамо `Query` всередину `Annotated` і встановимо параметр `max_length` у `50`:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\nЗверніть увагу, що значення за замовчуванням усе ще `None`, тому параметр залишається необов'язковим.\n\nАле тепер, додавши `Query(max_length=50)` всередину `Annotated`, ми повідомляємо FastAPI, що хочемо додаткову валідацію для цього значення: ми хочемо, щоб воно мало максимум 50 символів. 😎\n\n/// tip | Порада\n\nТут ми використовуємо `Query()`, оскільки це query параметр. Далі ми розглянемо інші варіанти, як-от `Path()`, `Body()`, `Header()` та `Cookie()`, які приймають ті самі аргументи, що й `Query()`.\n\n///\n\nТепер FastAPI:\n\n* Перевірить дані, щоб переконатися, що їхня максимальна довжина — 50 символів\n* Покажe чітку помилку клієнту, якщо дані недійсні\n* Задокументує параметр в OpenAPI-схемі операції шляху (що відобразиться в автоматично згенерованій документації)\n\n## Альтернативний (застарілий) метод: `Query` як значення за замовчуванням { #alternative-old-query-as-the-default-value }\n\nУ попередніх версіях FastAPI (до <dfn title=\"до 2023-03\">0.95.0</dfn>) потрібно було використовувати `Query` як значення за замовчуванням параметра, замість того, щоб додавати його в `Annotated`. Є висока ймовірність, що ви зустрінете код із таким підходом, тож я поясню його.\n\n/// tip | Порада\n\nДля нового коду та коли це можливо, використовуйте `Annotated`, як показано вище. Це має багато переваг (пояснених нижче) і не має недоліків. 🍰\n\n///\n\nРаніше ми писали `Query()` як значення за замовчуванням для параметра функції, встановлюючи `max_length` у 50:\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\nОскільки в цьому випадку (без `Annotated`) нам потрібно замінити значення за замовчуванням `None` у функції на `Query()`, тепер ми повинні встановити значення за замовчуванням через параметр `Query(default=None)`. Це виконує ту саму роль визначення значення за замовчуванням (принаймні для FastAPI).\n\nТаким чином:\n\n```Python\nq: str | None = Query(default=None)\n```\n\n...робить параметр необов’язковим зі значенням за замовчуванням `None`, що еквівалентно:\n\n```Python\nq: str | None = None\n```\n\nАле у версії з `Query` ми явно вказуємо, що це query параметр.\n\nДалі ми можемо передавати `Query` додаткові параметри. У цьому випадку — параметр `max_length`, який застосовується до рядків:\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\nЦе забезпечить валідацію даних, виведе зрозумілу помилку у разі недійсних даних і задокументує параметр у схемі OpenAPI операції шляху.\n\n### `Query` як значення за замовчуванням або всередині `Annotated` { #query-as-the-default-value-or-in-annotated }\n\nВажливо пам’ятати, якщо використовувати `Query` всередині `Annotated`, не можна задавати параметр `default` у `Query`.\n\nЗамість цього використовуйте фактичне значення за замовчуванням параметра функції. Інакше це буде непослідовно.\n\nНаприклад, цей варіант є некоректним:\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n...тому, що не зрозуміло, яке значення має бути значенням за замовчуванням: `\"rick\"` чи `\"morty\"`.\n\nТож ви будете використовувати (бажано):\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n...або у старих кодових базах ви знайдете:\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### Переваги використання `Annotated` { #advantages-of-annotated }\n\nВикористання `Annotated` є рекомендованим замість задання значення за замовчуванням у параметрах функції, оскільки воно краще з кількох причин. 🤓\n\nЗначення за замовчуванням параметра функції є фактичним значенням за замовчуванням, що є більш інтуїтивним у Python загалом. 😌\n\nВи можете викликати ту саму функцію в інших місцях без FastAPI, і вона працюватиме очікувано. Якщо параметр є обов’язковим (без значення за замовчуванням), ваш редактор повідомить про помилку, а Python також видасть помилку, якщо ви виконаєте функцію без передавання цього параметра.\n\nЯкщо ви не використовуєте `Annotated`, а використовуєте (старий) стиль значень за замовчуванням, то при виклику цієї функції без FastAPI в інших місцях потрібно пам’ятати передати їй аргументи, щоб вона працювала коректно, інакше значення будуть відрізнятися від очікуваних (наприклад, ви отримаєте `QueryInfo` або щось подібне замість `str`). І ваш редактор не повідомить про помилку, і Python не скаржитиметься під час запуску цієї функції — лише коли операції всередині завершаться помилкою.\n\nОскільки `Annotated` може містити кілька анотацій метаданих, тепер ви навіть можете використовувати ту саму функцію з іншими інструментами, такими як [Typer](https://typer.tiangolo.com/). 🚀\n\n## Додавання додаткових валідацій { #add-more-validations }\n\nВи також можете додати параметр `min_length`:\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## Додавання регулярних виразів { #add-regular-expressions }\n\nВи можете визначити <dfn title=\"Регулярний вираз, regex або regexp — це послідовність символів, яка визначає шаблон для пошуку в рядках.\">регулярний вираз</dfn> `pattern`, якому має відповідати параметр:\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\nЦей конкретний шаблон регулярного виразу перевіряє, що отримане значення параметра:\n\n* `^`: починається з наступних символів, перед якими немає інших символів.\n* `fixedquery`: точно відповідає значенню `fixedquery`.\n* `$`: закінчується тут, після `fixedquery` немає жодних символів.\n\nЯкщо ви почуваєтеся розгублено щодо **«regular expression»**, не хвилюйтеся. Це складна тема для багатьох людей. Ви все одно можете робити багато речей без використання регулярних виразів.\n\nТепер ви знаєте, що коли вони знадобляться, їх можна застосовувати у **FastAPI**.\n\n## Значення за замовчуванням { #default-values }\n\nВи можете, звісно, використовувати значення за замовчуванням, відмінні від `None`.\n\nПрипустімо, що ви хочете оголосити query параметр `q` з `min_length` `3` і значенням за замовчуванням `\"fixedquery\"`:\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | Примітка\n\nНаявність значення за замовчуванням будь-якого типу, включаючи `None`, робить параметр необов’язковим (not required).\n\n///\n\n## Обов’язкові параметри { #required-parameters }\n\nЯкщо нам не потрібно оголошувати додаткові валідації або метадані, ми можемо зробити query параметр `q` обов’язковим, просто не вказуючи значення за замовчуванням, наприклад:\n\n```Python\nq: str\n```\n\nзамість:\n\n```Python\nq: str | None = None\n```\n\nАле тепер ми оголошуємо його з `Query`, наприклад так:\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\nТому, якщо вам потрібно оголосити значення як обов’язкове під час використання `Query`, просто не вказуйте значення за замовчуванням:\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### Обов’язковий, може бути `None` { #required-can-be-none }\n\nВи можете вказати, що параметр може приймати `None`, але при цьому залишається обов’язковим. Це змусить клієнтів надіслати значення, навіть якщо значення дорівнює `None`.\n\nЩоб зробити це, оголосіть, що `None` є допустимим типом, але просто не вкажіть значення за замовчуванням:\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## Список query параметрів / кілька значень { #query-parameter-list-multiple-values }\n\nКоли ви явно визначаєте query параметр за допомогою `Query`, ви також можете оголосити, що він має приймати список значень, або, іншими словами, кілька значень.\n\nНаприклад, щоб оголосити query параметр `q`, який може з’являтися в URL кілька разів, можна написати:\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\nТоді, у випадку URL:\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\nви отримаєте кілька значень `q` query параметрів (`foo` і `bar`) у вигляді Python `list` у вашій функції операції шляху, у параметрі функції `q`.\n\nОтже, відповідь на цей URL буде:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | Порада\n\nЩоб оголосити query параметр з типом `list`, як у наведеному вище прикладі, потрібно явно використовувати `Query`, інакше він буде інтерпретований як тіло запиту.\n\n///\n\nІнтерактивна API-документація оновиться відповідно, дозволяючи передавати кілька значень:\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### Список query параметрів / кілька значень за замовчуванням { #query-parameter-list-multiple-values-with-defaults }\n\nВи також можете визначити значення за замовчуванням `list`, якщо жодне значення не було передане:\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\nЯкщо ви перейдете за посиланням:\n\n```\nhttp://localhost:8000/items/\n```\n\nто значення `q` за замовчуванням буде: `[\"foo\", \"bar\"]`, і ваша відповідь виглядатиме так:\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### Використання тільки `list` { #using-just-list }\n\nВи також можете використовувати `list` напряму замість `list[str]`:\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | Примітка\n\nМайте на увазі, що в цьому випадку FastAPI не перевірятиме вміст списку.\n\nНаприклад, `list[int]` перевірятиме (і документуватиме), що вміст списку — цілі числа. Але `list` без уточнення цього не робитиме.\n\n///\n\n## Оголосити більше метаданих { #declare-more-metadata }\n\nВи можете додати більше інформації про параметр.\n\nЦя інформація буде включена у згенерований OpenAPI та використана інтерфейсами документації та зовнішніми інструментами.\n\n/// note | Примітка\n\nМайте на увазі, що різні інструменти можуть мати різний рівень підтримки OpenAPI.\n\nДеякі з них можуть ще не відображати всю додаткову інформацію, хоча в більшості випадків відсутню функцію вже заплановано до реалізації.\n\n///\n\nВи можете додати `title`:\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\nА також `description`:\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## Аліаси параметрів { #alias-parameters }\n\nУявіть, що ви хочете, щоб параметр називався `item-query`.\n\nНаприклад:\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\nАле `item-query` — це некоректна назва змінної в Python.\n\nНайближчий допустимий варіант — `item_query`.\n\nПроте вам потрібно, щоб параметр залишався саме `item-query`...\n\nУ такому випадку можна оголосити `alias`, і саме він буде використовуватися для отримання значення параметра:\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## Позначення параметрів як застарілих { #deprecating-parameters }\n\nПрипустімо, що вам більше не подобається цей параметр.\n\nВам потрібно залишити його на деякий час, оскільки ним користуються клієнти, але ви хочете, щоб документація чітко показувала, що він є <dfn title=\"застарілий, не рекомендується до використання\">застарілий</dfn>.\n\nТоді передайте параметр `deprecated=True` до `Query`:\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\nДокументація буде показувати це таким чином:\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## Виняток параметрів з OpenAPI { #exclude-parameters-from-openapi }\n\nЩоб виключити query параметр зі згенерованої схеми OpenAPI (і, таким чином, з автоматичних систем документації), встановіть параметр `include_in_schema` для `Query` в `False`:\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## Кастомна валідація { #custom-validation }\n\nМожуть бути випадки, коли вам потрібно провести кастомну валідацію, яку не можна реалізувати за допомогою параметрів, показаних вище.\n\nУ таких випадках ви можете використати кастомну функцію-валідатор, яка буде застосована після звичайної валідації (наприклад, після перевірки, що значення є типом `str`).\n\nЦе можна досягти за допомогою [Pydantic's `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) в середині `Annotated`.\n\n/// tip | Порада\n\nPydantic також має [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) та інші. 🤓\n\n///\n\nНаприклад, цей кастомний валідатор перевіряє, чи починається ID елемента з `isbn-` для номера книги <abbr title=\"International Standard Book Number - Міжнародний стандартний номер книги\">ISBN</abbr> або з `imdb-` для ID URL фільму на <abbr title=\"Internet Movie Database - Інтернетна база даних фільмів: вебсайт з інформацією про фільми\">IMDB</abbr>:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info | Інформація\n\nЦе доступно з версії Pydantic 2 або вище. 😎\n\n///\n\n/// tip | Порада\n\nЯкщо вам потрібно виконати будь-яку валідацію, яка вимагає взаємодії з будь-яким зовнішнім компонентом, таким як база даних чи інший API, замість цього слід використовувати FastAPI Dependencies — ви дізнаєтесь про них пізніше.\n\nЦі кастомні валідатори використовуються для речей, які можна перевірити лише з тими самими даними, що надані в запиті.\n\n///\n\n### Зрозумійте цей код { #understand-that-code }\n\nГоловний момент — це використання `AfterValidator` з функцією всередині `Annotated`. Можете пропустити цю частину, якщо хочете. 🤸\n\n---\n\nАле якщо вам цікаво розібратися в цьому конкретному прикладі коду і вам ще не набридло, ось кілька додаткових деталей.\n\n#### Рядок із `value.startswith()` { #string-with-value-startswith }\n\nЗвернули увагу? Рядок із `value.startswith()` може приймати кортеж, і тоді він перевірятиме кожне значення в кортежі:\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### Випадковий елемент { #a-random-item }\n\nЗа допомогою `data.items()` ми отримуємо <dfn title=\"Щось, що ми можемо ітерувати циклом for, як-от список, множина тощо.\">ітерабельний об'єкт</dfn> із кортежами, що містять ключ і значення для кожного елемента словника.\n\nМи перетворюємо цей ітерабельний об'єкт у звичайний `list` за допомогою `list(data.items())`.\n\nПотім, використовуючи `random.choice()`, ми можемо отримати випадкове значення зі списку, тобто отримуємо кортеж із `(id, name)`. Це може бути щось на зразок `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")`.\n\nДалі ми присвоюємо ці два значення кортежу змінним `id` і `name`.\n\nТож, якщо користувач не вказав ID елемента, він все одно отримає випадкову рекомендацію.\n\n...ми робимо все це в одному простому рядку. 🤯 Хіба ви не любите Python? 🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## Підсумок { #recap }\n\nВи можете оголошувати додаткові валідації та метадані для ваших параметрів.\n\nЗагальні валідації та метадані:\n\n* `alias`\n* `title`\n* `description`\n* `deprecated`\n\nВалідації, специфічні для рядків:\n\n* `min_length`\n* `max_length`\n* `pattern`\n\nКастомні валідації за допомогою `AfterValidator`.\n\nУ цих прикладах ви побачили, як оголошувати валідації для значень `str`.\n\nДивіться наступні розділи, щоб дізнатися, як оголошувати валідації для інших типів, наприклад чисел.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/query-params.md",
    "content": "# Query параметри { #query-parameters }\n\nКоли ви оголошуєте інші параметри функції, які не є частиною параметрів шляху, вони автоматично інтерпретуються як параметри «query».\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\nQuery — це набір пар ключ-значення, що йдуть після символу `?` в URL, розділені символами `&`.\n\nНаприклад, в URL:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n...параметрами query є:\n\n* `skip`: зі значенням `0`\n* `limit`: зі значенням `10`\n\nОскільки вони є частиною URL, вони «природно» є рядками.\n\nАле коли ви оголошуєте їх із типами Python (у наведеному прикладі як `int`), вони перетворюються на цей тип і проходять перевірку відповідності.\n\nУвесь той самий процес, який застосовується до параметрів шляху, також застосовується до параметрів query:\n\n* Підтримка в редакторі (очевидно)\n* <dfn title=\"перетворення рядка, що надходить з HTTP-запиту, у дані Python\">«парсинг»</dfn> даних\n* Валідація даних\n* Автоматична документація\n\n## Значення за замовчуванням { #defaults }\n\nОскільки параметри query не є фіксованою частиною шляху, вони можуть бути необов’язковими та мати значення за замовчуванням.\n\nУ наведеному вище прикладі вони мають значення за замовчуванням: `skip=0` і `limit=10`.\n\nОтже, перехід за URL:\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\nбуде таким самим, як і перехід за посиланням:\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\nАле якщо ви перейдете, наприклад, за посиланням:\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\nЗначення параметрів у вашій функції будуть такими:\n\n* `skip=20`: оскільки ви вказали його в URL\n* `limit=10`: оскільки це значення за замовчуванням\n\n## Необов'язкові параметри { #optional-parameters }\n\nТак само ви можете оголосити необов’язкові параметри query, встановивши для них значення за замовчуванням `None`:\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\nУ цьому випадку параметр функції `q` буде необов’язковим і за замовчуванням матиме значення `None`.\n\n/// check | Перевірте\n\nТакож зверніть увагу, що **FastAPI** достатньо розумний, щоб визначити, що параметр шляху `item_id` є параметром шляху, а `q` — ні, отже, це параметр query.\n\n///\n\n## Перетворення типу параметра query { #query-parameter-type-conversion }\n\nВи також можете оголошувати параметри типу `bool`, і вони будуть автоматично конвертовані:\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\nУ цьому випадку, якщо ви перейдете за:\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\nабо\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\nабо\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\nабо\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\nабо\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\nабо будь-який інший варіант написання (великі літери, перша літера велика тощо), ваша функція побачить параметр `short` зі значенням `True` типу `bool`. В іншому випадку — `False`.\n\n\n## Кілька path і query параметрів { #multiple-path-and-query-parameters }\n\nВи можете одночасно оголошувати кілька параметрів шляху та параметрів query, **FastAPI** знає, який з них який.\n\nІ вам не потрібно оголошувати їх у якомусь конкретному порядку.\n\nВони визначаються за назвою:\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## Обов’язкові параметри query { #required-query-parameters }\n\nКоли ви оголошуєте значення за замовчуванням для не-path-параметрів (поки що ми бачили лише параметри query), тоді вони не є обов’язковими.\n\nЯкщо ви не хочете задавати конкретне значення, а просто зробити параметр необов’язковим, задайте `None` як значення за замовчуванням.\n\nАле якщо ви хочете зробити параметр query обов’язковим, просто не вказуйте для нього значення за замовчуванням:\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\nТут параметр query `needy` — обов’язковий параметр query типу `str`.\n\nЯкщо ви відкриєте у браузері URL-адресу:\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n...без додавання обов’язкового параметра `needy`, ви побачите помилку на кшталт:\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\nОскільки `needy` є обов’язковим параметром, вам потрібно вказати його в URL:\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n...це спрацює:\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\nІ звісно, ви можете визначити деякі параметри як обов’язкові, деякі — зі значенням за замовчуванням, а деякі — повністю необов’язкові:\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\nУ цьому випадку є 3 параметри query:\n\n* `needy`, обов’язковий `str`.\n* `skip`, `int` зі значенням за замовчуванням `0`.\n* `limit`, необов’язковий `int`.\n\n/// tip | Порада\n\nВи також можете використовувати `Enum` так само, як і з [Параметри шляху](path-params.md#predefined-values).\n\n///\n"
  },
  {
    "path": "docs/uk/docs/tutorial/request-files.md",
    "content": "# Запит файлів { #request-files }\n\nВи можете визначити файли, які будуть завантажуватися клієнтом, використовуючи `File`.\n\n/// info | Інформація\n\nЩоб отримувати завантажені файли, спочатку встановіть [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nПереконайтеся, що ви створили [віртуальне середовище](../virtual-environments.md), активували його, а потім встановили його, наприклад:\n\n```console\n$ pip install python-multipart\n```\n\nЦе необхідно, оскільки завантажені файли передаються у вигляді «form data».\n\n///\n\n## Імпорт `File` { #import-file }\n\nІмпортуйте `File` та `UploadFile` з `fastapi`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## Визначення параметрів `File` { #define-file-parameters }\n\nСтворіть параметри файлів так само як ви б створювали `Body` або `Form`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info | Інформація\n\n`File` — це клас, який безпосередньо успадковує `Form`.\n\nАле пам’ятайте, що коли ви імпортуєте `Query`, `Path`, `File` та інші з `fastapi`, це насправді функції, які повертають спеціальні класи.\n\n///\n\n/// tip | Порада\n\nЩоб оголосити тіла файлів, вам потрібно використовувати `File`, тому що інакше параметри будуть інтерпретовані як параметри запиту або параметри тіла (JSON).\n\n///\n\nФайли будуть завантажені у вигляді «form data».\n\nЯкщо ви оголосите тип параметра *функції операції шляху* як `bytes`, **FastAPI** прочитає файл за вас, і ви отримаєте його вміст у вигляді `bytes`.\n\nМайте на увазі, що це означає, що весь вміст буде збережено в пам'яті. Це працюватиме добре для малих файлів.\n\nАле є кілька випадків, у яких вам може бути корисно використовувати `UploadFile`.\n\n## Параметри файлу з `UploadFile` { #file-parameters-with-uploadfile }\n\nВизначте параметр файлу з типом `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\nВикористання `UploadFile` має кілька переваг перед `bytes`:\n\n* Вам не потрібно використовувати `File()` у значенні за замовчуванням параметра.\n* Використовується «spooled» файл:\n    * Файл зберігається в пам'яті до досягнення максимального обмеження розміру, після чого він буде збережений на диску.\n* Це означає, що він добре працюватиме для великих файлів, таких як зображення, відео, великі двійкові файли тощо, не споживаючи всю пам'ять.\n* Ви можете отримати метадані про завантажений файл.\n* Він має [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) `async` інтерфейс.\n* Він надає фактичний об'єкт Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile), який можна передавати безпосередньо іншим бібліотекам, що очікують file-like об'єкт.\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` має такі атрибути:\n\n* `filename`: Рядок `str` з оригінальною назвою файлу, який був завантажений (наприклад, `myimage.jpg`).\n* `content_type`: Рядок `str` з типом вмісту (MIME type / media type) (наприклад, `image/jpeg`).\n* `file`: [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) ([file-like](https://docs.python.org/3/glossary.html#term-file-like-object) об'єкт). Це фактичний файловий об'єкт Python, який ви можете передавати безпосередньо іншим функціям або бібліотекам, що очікують «file-like» об'єкт.\n\n`UploadFile` має такі асинхронні `async` методи. Вони всі викликають відповідні методи файлу під капотом (використовуючи внутрішній `SpooledTemporaryFile`).\n\n* `write(data)`: Записує `data` (`str` або `bytes`) у файл.\n* `read(size)`: Читає `size` (`int`) байтів/символів з файлу.\n* `seek(offset)`: Переходить до байтової позиції `offset` (`int`) у файлі.\n    * Наприклад, `await myfile.seek(0)` перейде на початок файлу.\n    * Це особливо корисно, якщо ви виконаєте `await myfile.read()` один раз, а потім потрібно знову прочитати вміст.\n* `close()`: Закриває файл.\n\nОскільки всі ці методи є асинхронними `async` методами, вам потрібно їх «await»-ити.\n\nНаприклад, всередині `async` *функції операції шляху* ви можете отримати вміст за допомогою:\n\n```Python\ncontents = await myfile.read()\n```\n\nЯкщо ви знаходитесь у звичайній `def` *функції операції шляху*, ви можете отримати доступ до `UploadFile.file` безпосередньо, наприклад:\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | Технічні деталі `async`\n\nКоли ви використовуєте `async` методи, **FastAPI** виконує файлові методи у пулі потоків і очікує на них.\n\n///\n\n/// note | Технічні деталі Starlette\n\n`UploadFile` у **FastAPI** успадковується безпосередньо від `UploadFile` у **Starlette**, але додає деякі необхідні частини, щоб зробити його сумісним із **Pydantic** та іншими частинами FastAPI.\n\n///\n\n## Що таке «Form Data» { #what-is-form-data }\n\nСпосіб, у який HTML-форми (`<form></form>`) надсилають дані на сервер, зазвичай використовує «спеціальне» кодування для цих даних, відмінне від JSON.\n\n**FastAPI** забезпечить зчитування цих даних з правильного місця, а не з JSON.\n\n/// note | Технічні деталі\n\nДані з форм зазвичай кодуються за допомогою «media type» `application/x-www-form-urlencoded`, якщо вони не містять файлів.\n\nАле якщо форма містить файли, вона кодується як `multipart/form-data`. Якщо ви використовуєте `File`, **FastAPI** знатиме, що потрібно отримати файли з правильної частини тіла.\n\nЯкщо ви хочете дізнатися більше про ці типи кодування та формові поля, ознайомтеся з [<abbr title=\"Mozilla Developer Network - Мережа Розробників Mozilla\">MDN</abbr> web docs для `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Попередження\n\nВи можете оголосити кілька параметрів `File` і `Form` в *операції шляху*, але ви не можете одночасно оголошувати поля `Body`, які ви очікуєте отримати як JSON, оскільки запит матиме тіло, закодоване як `multipart/form-data`, а не `application/json`.\n\nЦе не обмеження **FastAPI**, а частина протоколу HTTP.\n\n///\n\n## Необов’язкове завантаження файлу { #optional-file-upload }\n\nВи можете зробити файл необов’язковим, використовуючи стандартні анотації типів і встановивши значення за замовчуванням `None`:\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## `UploadFile` із додатковими метаданими { #uploadfile-with-additional-metadata }\n\nВи також можете використовувати `File()` разом із `UploadFile`, наприклад, щоб встановити додаткові метадані:\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## Завантаження кількох файлів { #multiple-file-uploads }\n\nМожна завантажувати кілька файлів одночасно.\n\nВони будуть пов’язані з одним і тим самим «form field», який передається у вигляді «form data».\n\nЩоб це реалізувати, потрібно оголосити список `bytes` або `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\nВи отримаєте, як і було оголошено, `list` із `bytes` або `UploadFile`.\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette.responses import HTMLResponse`.\n\n**FastAPI** надає ті ж самі `starlette.responses`, що й `fastapi.responses`, просто для зручності для вас, розробника. Але більшість доступних відповідей надходять безпосередньо від Starlette.\n\n///\n\n### Завантаження кількох файлів із додатковими метаданими { #multiple-file-uploads-with-additional-metadata }\n\nТак само як і раніше, ви можете використовувати `File()`, щоб встановити додаткові параметри навіть для `UploadFile`:\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## Підсумок { #recap }\n\nВикористовуйте `File`, `bytes` та `UploadFile`, щоб оголошувати файли для завантаження в запиті, надіслані у вигляді form data.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/request-form-models.md",
    "content": "# Моделі форм { #form-models }\n\nУ FastAPI ви можете використовувати **Pydantic-моделі** для оголошення **полів форми**.\n\n/// info\n\nЩоб використовувати форми, спочатку встановіть [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nПереконайтеся, що ви створили [віртуальне середовище](../virtual-environments.md), активували його, а потім встановили його, наприклад:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note\n\nЦе підтримується, починаючи з FastAPI версії `0.113.0`. 🤓\n\n///\n\n## Pydantic-моделі для форм { #pydantic-models-for-forms }\n\nВам просто потрібно оголосити **Pydantic-модель** з полями, які ви хочете отримати як **поля форми**, а потім оголосити параметр як `Form`:\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI**  **витягне** дані для **кожного поля** з **формових даних** у запиті та надасть вам Pydantic-модель, яку ви визначили.\n\n## Перевірте документацію { #check-the-docs }\n\nВи можете перевірити це в UI документації за `/docs`:\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## Забороніть додаткові поля форми { #forbid-extra-form-fields }\n\nУ деяких особливих випадках (ймовірно, не дуже поширених) ви можете **обмежити** поля форми лише тими, які були оголошені в Pydantic-моделі. І **заборонити** будь-які **додаткові** поля.\n\n/// note\n\nЦе підтримується, починаючи з FastAPI версії `0.114.0`. 🤓\n\n///\n\nВи можете використати конфігурацію Pydantic-моделі, щоб заборонити `forbid` будь-які додаткові `extra` поля:\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\nЯкщо клієнт спробує надіслати додаткові дані, він отримає **відповідь з помилкою**.\n\nНаприклад, якщо клієнт спробує надіслати поля форми:\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\nВін отримає відповідь із помилкою, яка повідомляє, що поле `extra` не дозволено:\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## Підсумок { #summary }\n\nУ FastAPI ви можете використовувати Pydantic-моделі для оголошення полів форми. 😎\n"
  },
  {
    "path": "docs/uk/docs/tutorial/request-forms-and-files.md",
    "content": "# Запити з формами та файлами { #request-forms-and-files }\n\nВи можете одночасно визначати файли та поля форми, використовуючи `File` і `Form`.\n\n/// info | Інформація\n\nЩоб отримувати завантажені файли та/або дані форми, спочатку встановіть [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nПереконайтеся, що ви створили [віртуальне середовище](../virtual-environments.md), активували його, а потім встановили бібліотеку, наприклад:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Імпорт `File` та `Form` { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## Оголошення параметрів `File` та `Form` { #define-file-and-form-parameters }\n\nСтворіть параметри файлів та форми так само як і для `Body` або `Query`:\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\nФайли та поля форми будуть завантажені як формові дані, і ви отримаєте файли та поля форми.\n\nВи також можете оголосити деякі файли як `bytes`, а деякі як `UploadFile`.\n\n/// warning | Попередження\n\nВи можете оголосити кілька параметрів `File` і `Form` в операції *шляху*, але не можете одночасно оголошувати `Body`-поля, які очікуєте отримати у форматі JSON, оскільки запит матиме тіло, закодоване за допомогою `multipart/form-data`, а не `application/json`.\n\nЦе не обмеження **FastAPI**, а частина протоколу HTTP.\n\n///\n\n## Підсумок { #recap }\n\nВикористовуйте `File` та `Form` разом, коли вам потрібно отримувати дані та файли в одному запиті.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/request-forms.md",
    "content": "# Дані форми { #form-data }\n\nКоли вам потрібно отримувати поля форми замість JSON, ви можете використовувати `Form`.\n\n/// info | Інформація\n\nЩоб використовувати форми, спочатку встановіть [`python-multipart`](https://github.com/Kludex/python-multipart).\n\nПереконайтеся, що ви створили [віртуальне середовище](../virtual-environments.md), активували його, і потім встановили бібліотеку, наприклад:\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## Імпорт `Form` { #import-form }\n\nІмпортуйте `Form` з `fastapi`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## Оголошення параметрів `Form` { #define-form-parameters }\n\nСтворюйте параметри форми так само як ви б створювали `Body` або `Query`:\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\nНаприклад, один зі способів використання специфікації OAuth2 (так званий «password flow») вимагає надсилати `username` та `password` як поля форми.\n\n<dfn title=\"специфікація\">специфікація</dfn> вимагає, щоб ці поля мали точні назви `username` і `password` та надсилалися у вигляді полів форми, а не JSON.\n\nЗ `Form` ви можете оголошувати ті ж конфігурації, що і з `Body` (та `Query`, `Path`, `Cookie`), включаючи валідацію, приклади, псевдоніми (наприклад, `user-name` замість `username`) тощо.\n\n/// info | Інформація\n\n`Form` — це клас, який безпосередньо наслідується від `Body`.\n\n///\n\n/// tip | Порада\n\nЩоб оголосити тіло форми, потрібно явно використовувати `Form`, оскільки без нього параметри будуть інтерпретуватися як параметри запиту або тіла (JSON).\n\n///\n\n## Про «поля форми» { #about-form-fields }\n\nHTML-форми (`<form></form>`) надсилають дані на сервер у «спеціальному» кодуванні, яке відрізняється від JSON.\n\n**FastAPI** подбає про те, щоб зчитати ці дані з правильного місця, а не з JSON.\n\n/// note | Технічні деталі\n\nДані з форм зазвичай кодуються за допомогою «типу медіа» `application/x-www-form-urlencoded`.\n\nАле якщо форма містить файли, вона кодується як `multipart/form-data`. Ви дізнаєтеся про обробку файлів у наступному розділі.\n\nЯкщо ви хочете дізнатися більше про ці кодування та поля форм, зверніться до [<abbr title=\"Mozilla Developer Network - Мережа Розробників Mozilla\">MDN</abbr> вебдокументації для `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST).\n\n///\n\n/// warning | Попередження\n\nВи можете оголосити кілька параметрів `Form` в *операції шляху*, але не можете одночасно оголосити поля `Body`, які ви очікуєте отримати у форматі JSON, оскільки запит матиме тіло, закодоване як `application/x-www-form-urlencoded`, а не `application/json`.\n\nЦе не обмеження **FastAPI**, а частина HTTP-протоколу.\n\n///\n\n## Підсумок { #recap }\n\nВикористовуйте `Form` для оголошення вхідних параметрів у вигляді даних форми.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/response-model.md",
    "content": "# Модель відповіді — Тип, що повертається { #response-model-return-type }\n\nВи можете оголосити тип, який використовуватиметься у відповіді, анотувавши **тип повернення** *функції операції шляху*.\n\n**Анотації типів** можна використовувати так само, як і для вхідних даних у **параметрах** функції: можна використовувати моделі Pydantic, списки, словники, скалярні значення, як-от цілі числа, булеві значення тощо.\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPI використовуватиме цей тип повернення, щоб:\n\n* **Перевірити правильність** повернених даних.\n    * Якщо дані не валідні (наприклад, відсутнє поле), це означає, що *ваш* код застосунку зламаний, не повертає те, що повинен, і буде повернуто помилку сервера замість некоректних даних. Так ви та ваші клієнти можете бути впевнені, що отримаєте дані й очікувану структуру даних.\n* Додати **JSON Schema** для відповіді в OpenAPI *операції шляху*.\n    * Це буде використано в **автоматичній документації**.\n    * Це також буде використано інструментами, які автоматично генерують клієнтський код.\n* **Серіалізувати** повернені дані в JSON за допомогою Pydantic, який написаний мовою **Rust**, тому це буде **набагато швидше**.\n\nАле найголовніше:\n\n* Це **обмежить та відфільтрує** вихідні дані до того, що визначено в типі повернення.\n    * Це особливо важливо для **безпеки**, нижче ми побачимо про це більше.\n\n## Параметр `response_model` { #response-model-parameter }\n\nЄ випадки, коли вам потрібно або ви хочете повертати дані, які не зовсім відповідають тому, що оголошено типом.\n\nНаприклад, ви можете захотіти **повертати словник** або об’єкт бази даних, але **оголосити його як модель Pydantic**. Таким чином модель Pydantic виконуватиме всю документацію даних, валідацію тощо для об’єкта, який ви повернули (наприклад, словника або об’єкта бази даних).\n\nЯкщо ви додали анотацію типу повернення, інструменти та редактори скаржитимуться (коректною) помилкою, повідомляючи, що ваша функція повертає тип (наприклад, dict), який відрізняється від того, що ви оголосили (наприклад, модель Pydantic).\n\nУ таких випадках можна скористатися параметром *декоратора операції шляху* `response_model` замість типу повернення.\n\nВи можете використовувати параметр `response_model` у будь-якій з *операцій шляху*:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* тощо.\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | Примітка\n\nЗверніть увагу, що `response_model` є параметром методу «декоратора» (`get`, `post` тощо). А не вашої *функції операції шляху*, як усі параметри та тіло.\n\n///\n\n`response_model` приймає такий самий тип, який ви б вказали для поля моделі Pydantic, тобто це може бути модель Pydantic, але також це може бути, наприклад, `list` моделей Pydantic, як-от `List[Item]`.\n\nFastAPI використовуватиме цей `response_model` для виконання всієї документації даних, валідації тощо, а також для **перетворення та фільтрації вихідних даних** до оголошеного типу.\n\n/// tip | Порада\n\nЯкщо у вас увімкнено сувору перевірку типів у редакторі, mypy тощо, ви можете оголосити тип повернення функції як `Any`.\n\nТаким чином, ви повідомляєте редактору, що свідомо повертаєте будь-що. Але FastAPI усе одно виконуватиме документацію даних, валідацію, фільтрацію тощо за допомогою `response_model`.\n\n///\n\n### Пріоритет `response_model` { #response-model-priority }\n\nЯкщо ви оголошуєте і тип повернення, і `response_model`, то `response_model` матиме пріоритет і буде використаний FastAPI.\n\nТаким чином ви можете додати правильні анотації типів до ваших функцій, навіть коли повертаєте тип, відмінний від моделі відповіді, щоб це використовували редактор і інструменти на кшталт mypy. І при цьому FastAPI все одно виконуватиме валідацію даних, документацію тощо, використовуючи `response_model`.\n\nВи також можете використати `response_model=None`, щоб вимкнути створення моделі відповіді для цієї *операції шляху*; це може знадобитися, якщо ви додаєте анотації типів для речей, які не є валідними полями Pydantic, приклад цього ви побачите в одному з розділів нижче.\n\n## Повернути ті самі вхідні дані { #return-the-same-input-data }\n\nТут ми оголошуємо модель `UserIn`, вона міститиме пароль у відкритому вигляді:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | Інформація\n\nЩоб використовувати `EmailStr`, спочатку встановіть [`email-validator`](https://github.com/JoshData/python-email-validator).\n\nПереконайтеся, що ви створили [віртуальне середовище](../virtual-environments.md), активували його, а потім встановили пакет, наприклад:\n\n```console\n$ pip install email-validator\n```\n\nабо так:\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\nІ ми використовуємо цю модель, щоб оголосити наші вхідні дані, і цю ж модель, щоб оголосити наші вихідні дані:\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\nТепер, щоразу коли браузер створює користувача з паролем, API поверне той самий пароль у відповіді.\n\nУ цьому випадку це може не бути проблемою, адже це той самий користувач надсилає пароль.\n\nАле якщо ми використаємо цю ж модель для іншої *операції шляху*, ми можемо надсилати паролі наших користувачів кожному клієнту.\n\n/// danger | Обережно\n\nНіколи не зберігайте пароль користувача у відкритому вигляді та не надсилайте його у відповіді таким чином, якщо тільки ви не знаєте всі застереження і точно розумієте, що робите.\n\n///\n\n## Додати вихідну модель { #add-an-output-model }\n\nЗамість цього ми можемо створити вхідну модель з паролем у відкритому вигляді і вихідну модель без нього:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\nТут, хоча наша *функція операції шляху* повертає того самого вхідного користувача, який містить пароль:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n...ми оголосили `response_model` як нашу модель `UserOut`, яка не містить пароля:\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\nТаким чином, **FastAPI** подбає про фільтрацію всіх даних, які не оголошені у вихідній моделі (використовуючи Pydantic).\n\n### `response_model` або тип повернення { #response-model-or-return-type }\n\nУ цьому випадку, оскільки дві моделі різні, якщо ми анотуємо тип повернення функції як `UserOut`, редактор і інструменти скаржитимуться, що ми повертаємо невалідний тип, адже це різні класи.\n\nСаме тому в цьому прикладі нам треба оголосити це через параметр `response_model`.\n\n...але читайте далі нижче, щоб побачити, як це обійти.\n\n## Тип повернення і фільтрація даних { #return-type-and-data-filtering }\n\nПродовжимо з попереднього прикладу. Ми хотіли **анотувати функцію одним типом**, але хотіли мати змогу повертати з функції те, що насправді містить **більше даних**.\n\nМи хочемо, щоб FastAPI продовжував **фільтрувати** дані, використовуючи модель відповіді. Тобто навіть якщо функція повертає більше даних, відповідь міститиме лише поля, оголошені в моделі відповіді.\n\nУ попередньому прикладі, оскільки класи були різні, нам довелося використовувати параметр `response_model`. Але це також означає, що ми не отримуємо підтримки від редактора та інструментів, які перевіряють тип повернення функції.\n\nПроте в більшості випадків, коли нам потрібно зробити щось подібне, ми просто хочемо, щоб модель **відфільтрувала/прибрала** частину даних, як у цьому прикладі.\n\nІ в таких випадках ми можемо використати класи та спадкування, щоб скористатися **анотаціями типів** функцій і отримати кращу підтримку в редакторі та інструментах, і при цьому зберегти **фільтрацію даних** у FastAPI.\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\nЗавдяки цьому ми отримуємо підтримку інструментів — від редакторів і mypy, адже цей код коректний з точки зору типів, — але ми також отримуємо фільтрацію даних від FastAPI.\n\nЯк це працює? Давайте розберемося. 🤓\n\n### Анотації типів і підтримка інструментів { #type-annotations-and-tooling }\n\nСпершу подивімося, як це бачать редактори, mypy та інші інструменти.\n\n`BaseUser` має базові поля. Потім `UserIn` успадковує `BaseUser` і додає поле `password`, отже він включатиме всі поля з обох моделей.\n\nМи анотуємо тип повернення функції як `BaseUser`, але фактично повертаємо екземпляр `UserIn`.\n\nРедактор, mypy та інші інструменти не скаржитимуться на це, тому що з точки зору типізації `UserIn` є підкласом `BaseUser`, а це означає, що він є *валідним* типом, коли очікується будь-що, що є `BaseUser`.\n\n### Фільтрація даних у FastAPI { #fastapi-data-filtering }\n\nТепер для FastAPI він побачить тип повернення і переконається, що те, що ви повертаєте, містить **лише** поля, які оголошені у цьому типі.\n\nFastAPI виконує кілька внутрішніх операцій з Pydantic, щоб гарантувати, що ті самі правила наслідування класів не застосовуються для фільтрації повернених даних, інакше ви могли б зрештою повертати значно більше даних, ніж очікували.\n\nТаким чином ви можете отримати найкраще з двох світів: анотації типів із **підтримкою інструментів** і **фільтрацію даних**.\n\n## Подивитися в документації { #see-it-in-the-docs }\n\nКоли ви дивитеся автоматичну документацію, ви можете перевірити, що вхідна модель і вихідна модель матимуть власну JSON Schema:\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\nІ обидві моделі будуть використані для інтерактивної документації API:\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## Інші анотації типів повернення { #other-return-type-annotations }\n\nМожуть бути випадки, коли ви повертаєте щось, що не є валідним полем Pydantic, і анотуєте це у функції лише для того, щоб отримати підтримку від інструментів (редактора, mypy тощо).\n\n### Повернути Response напряму { #return-a-response-directly }\n\nНайпоширенішим випадком буде [повернення Response напряму, як пояснюється пізніше у розширеній документації](../advanced/response-directly.md).\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\nЦей простий випадок автоматично обробляється FastAPI, тому що анотація типу повернення — це клас (або підклас) `Response`.\n\nІ інструменти також будуть задоволені, бо і `RedirectResponse`, і `JSONResponse` є підкласами `Response`, отже анотація типу коректна.\n\n### Анотувати підклас Response { #annotate-a-response-subclass }\n\nВи також можете використати підклас `Response` в анотації типу:\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\nЦе теж працюватиме, бо `RedirectResponse` — підклас `Response`, і FastAPI автоматично обробить цей простий випадок.\n\n### Некоректні анотації типу повернення { #invalid-return-type-annotations }\n\nАле коли ви повертаєте якийсь інший довільний об’єкт, що не є валідним типом Pydantic (наприклад, об’єкт бази даних), і анотуєте його так у функції, FastAPI спробує створити модель відповіді Pydantic на основі цієї анотації типу і це завершиться помилкою.\n\nТе саме станеться, якщо у вас буде <dfn title=\"об'єднання між кількома типами означає «будь-який із цих типів»\">об'єднання</dfn> між різними типами, де один або більше не є валідними типами Pydantic, наприклад, це завершиться помилкою 💥:\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n...це не працює, тому що анотація типу не є типом Pydantic і не є просто одним класом `Response` або його підкласом, це union (будь-який із двох) між `Response` і `dict`.\n\n### Вимкнути модель відповіді { #disable-response-model }\n\nПродовжуючи приклад вище, можливо, ви не хочете мати стандартну валідацію даних, документацію, фільтрацію тощо, які виконує FastAPI.\n\nАле ви можете все одно хотіти залишити анотацію типу повернення у функції, щоб отримати підтримку від інструментів, як-от редактори та перевірки типів (наприклад, mypy).\n\nУ такому випадку ви можете вимкнути генерацію моделі відповіді, встановивши `response_model=None`:\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\nЦе змусить FastAPI пропустити генерацію моделі відповіді, і таким чином ви зможете використовувати будь-які потрібні анотації типів повернення без впливу на ваш FastAPI застосунок. 🤓\n\n## Параметри кодування моделі відповіді { #response-model-encoding-parameters }\n\nВаша модель відповіді може мати значення за замовчуванням, наприклад:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None` (або `str | None = None` у Python 3.10) має значення за замовчуванням `None`.\n* `tax: float = 10.5` має значення за замовчуванням `10.5`.\n* `tags: List[str] = []` має значення за замовчуванням порожній список: `[]`.\n\nале ви можете захотіти не включати їх у результат, якщо вони фактично не були збережені.\n\nНаприклад, якщо у вас є моделі з багатьма необов’язковими атрибутами у NoSQL базі даних, але ви не хочете надсилати дуже довгі JSON-відповіді, повні значень за замовчуванням.\n\n### Використовуйте параметр `response_model_exclude_unset` { #use-the-response-model-exclude-unset-parameter }\n\nВи можете встановити параметр *декоратора операції шляху* `response_model_exclude_unset=True`:\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\nі ці значення за замовчуванням не будуть включені у відповідь, лише значення, які фактично встановлені.\n\nОтже, якщо ви надішлете запит до цієї *операції шляху* для елемента з ID `foo`, відповідь (без включення значень за замовчуванням) буде:\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | Інформація\n\nВи також можете використовувати:\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\nяк описано в [документації Pydantic](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict) для `exclude_defaults` та `exclude_none`.\n\n///\n\n#### Дані зі значеннями для полів із типовими значеннями { #data-with-values-for-fields-with-defaults }\n\nАле якщо ваші дані мають значення для полів моделі з типовими значеннями, як у елемента з ID `bar`:\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\nвони будуть включені у відповідь.\n\n#### Дані з тими самими значеннями, що й типові { #data-with-the-same-values-as-the-defaults }\n\nЯкщо дані мають ті самі значення, що й типові, як у елемента з ID `baz`:\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nFastAPI достатньо розумний (насправді, Pydantic достатньо розумний), щоб зрозуміти, що, хоча `description`, `tax` і `tags` мають ті самі значення, що й типові, їх було встановлено явно (а не взято як значення за замовчуванням).\n\nОтже, вони будуть включені у JSON-відповідь.\n\n/// tip | Порада\n\nЗверніть увагу, що типові значення можуть бути будь-якими, не лише `None`.\n\nЦе може бути list (`[]`), `float` зі значенням `10.5` тощо.\n\n///\n\n### `response_model_include` та `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\nВи також можете використовувати параметри *декоратора операції шляху* `response_model_include` та `response_model_exclude`.\n\nВони приймають `set` зі `str` з іменами атрибутів, які потрібно включити (пропускаючи решту) або виключити (включаючи решту).\n\nЦе можна використовувати як швидкий спосіб, якщо у вас є лише одна модель Pydantic і ви хочете видалити деякі дані з виводу.\n\n/// tip | Порада\n\nАле все ж рекомендується використовувати описані вище підходи, застосовуючи кілька класів, замість цих параметрів.\n\nЦе тому, що JSON Schema, який генерується в OpenAPI вашого застосунку (і в документації), все одно буде відповідати повній моделі, навіть якщо ви використовуєте `response_model_include` або `response_model_exclude`, щоб пропустити деякі атрибути.\n\nЦе також стосується `response_model_by_alias`, який працює подібним чином.\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | Порада\n\nСинтаксис `{\"name\", \"description\"}` створює `set` з цими двома значеннями.\n\nВін еквівалентний `set([\"name\", \"description\"])`.\n\n///\n\n#### Використання `list` замість `set` { #using-lists-instead-of-sets }\n\nЯкщо ви забудете використати `set` і натомість застосуєте `list` або `tuple`, FastAPI все одно перетворить це на `set`, і все працюватиме правильно:\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## Підсумок { #recap }\n\nВикористовуйте параметр `response_model` *декоратора операції шляху*, щоб визначати моделі відповіді і особливо щоб гарантувати фільтрацію приватних даних.\n\nВикористовуйте `response_model_exclude_unset`, щоб повертати лише явно встановлені значення.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/response-status-code.md",
    "content": "# Код статусу відповіді { #response-status-code }\n\nТак само, як ви можете вказати модель відповіді, ви також можете оголосити HTTP код статусу, що використовується для відповіді, за допомогою параметра `status_code` в будь-якій з *операцій шляху*:\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* тощо.\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | Примітка\n\nЗверніть увагу, що `status_code` є параметром методу «декоратора» (`get`, `post`, тощо). Не вашої *функції операції шляху*, як усі параметри та тіло.\n\n///\n\nПараметр `status_code` приймає число з HTTP кодом статусу.\n\n/// info | Інформація\n\n`status_code` також може, як альтернативу, приймати `IntEnum`, наприклад, Python [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus).\n\n///\n\nВін буде:\n\n* Повертати цей код статусу у відповіді.\n* Документувати його як такий у схемі OpenAPI (і, таким чином, в інтерфейсах користувача):\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | Примітка\n\nДеякі коди відповіді (див. наступний розділ) вказують, що відповідь не має тіла.\n\nFastAPI знає про це і створить документацію OpenAPI, яка вказує, що тіла відповіді немає.\n\n///\n\n## Про HTTP коди статусу { #about-http-status-codes }\n\n/// note | Примітка\n\nЯкщо ви вже знаєте, що таке HTTP коди статусу, перейдіть до наступного розділу.\n\n///\n\nВ HTTP ви надсилаєте числовий код статусу з 3 цифр як частину відповіді.\n\nЦі коди статусу мають пов’язану назву для їх розпізнавання, але важливою частиною є число.\n\nКоротко:\n\n* `100 - 199` — для «Information». Ви рідко використовуєте їх напряму. Відповіді з такими кодами статусу не можуть мати тіла.\n* **`200 - 299`** — для «Successful» відповідей. Це ті, які ви використовуватимете найчастіше.\n    * `200` — код статусу за замовчуванням, який означає, що все було «OK».\n    * Інший приклад — `201`, «Created». Його зазвичай використовують після створення нового запису в базі даних.\n    * Особливий випадок — `204`, «No Content». Цю відповідь використовують, коли немає вмісту для повернення клієнту, і тому відповідь не повинна мати тіла.\n* **`300 - 399`** — для «Redirection». Відповіді з цими кодами статусу можуть мати або не мати тіла, за винятком `304`, «Not Modified», яка не повинна мати тіла.\n* **`400 - 499`** — для відповідей «Client error». Це другий тип, який ви, ймовірно, будете використовувати найчастіше.\n    * Приклад — `404`, для відповіді «Not Found».\n    * Для загальних помилок з боку клієнта ви можете просто використовувати `400`.\n* `500 - 599` — для помилок сервера. Ви майже ніколи не використовуєте їх напряму. Коли щось піде не так у якійсь частині коду вашого застосунку або на сервері, автоматично буде повернено один із цих кодів статусу.\n\n/// tip | Порада\n\nЩоб дізнатися більше про кожен код статусу і для чого призначений кожен із них, перегляньте [документацію <abbr title=\"Mozilla Developer Network - Мережа Розробників Mozilla\">MDN</abbr> про HTTP коди статусу](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status).\n\n///\n\n## Скорочення, щоб запам’ятати назви { #shortcut-to-remember-the-names }\n\nРозглянемо попередній приклад ще раз:\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201` — це код статусу для «Created».\n\nАле вам не потрібно запам'ятовувати, що означає кожен із цих кодів.\n\nВи можете використовувати зручні змінні з `fastapi.status`.\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\nВони — просто для зручності, містять те саме число, але так ви можете скористатися автозаповненням редактора, щоб знайти їх:\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | Технічні деталі\n\nВи також можете використати `from starlette import status`.\n\n**FastAPI** надає той самий `starlette.status` як `fastapi.status` просто як зручність для вас, розробника. Але він походить безпосередньо зі Starlette.\n\n///\n\n## Зміна значення за замовчуванням { #changing-the-default }\n\nПізніше, у [Просунутому посібнику користувача](../advanced/response-change-status-code.md), ви побачите, як повертати інший код статусу, ніж значення за замовчуванням, яке ви оголошуєте тут.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/schema-extra-example.md",
    "content": "# Декларування прикладів вхідних даних { #declare-request-example-data }\n\nВи можете задати приклади даних, які ваш застосунок може отримувати.\n\nОсь кілька способів, як це зробити.\n\n## Додаткові дані Схеми JSON у моделях Pydantic { #extra-json-schema-data-in-pydantic-models }\n\nВи можете задати `examples` для моделі Pydantic, які буде додано до згенерованої Схеми JSON.\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\nЦя додаткова інформація буде додана як є до **Схеми JSON** для цієї моделі, і вона буде використана в документації до API.\n\nВи можете використати атрибут `model_config`, який приймає `dict`, як описано в [документації Pydantic: Configuration](https://docs.pydantic.dev/latest/api/config/).\n\nВи можете встановити `\"json_schema_extra\"` як `dict`, що містить будь-які додаткові дані, які ви хочете відобразити у згенерованій Схемі JSON, включаючи `examples`.\n\n/// tip | Порада\n\nВи можете використати ту ж техніку, щоб розширити Схему JSON і додати власну додаткову інформацію.\n\nНаприклад, ви можете використати її для додавання метаданих для інтерфейсу користувача на фронтенді тощо.\n\n///\n\n/// info | Інформація\n\nOpenAPI 3.1.0 (який використовується починаючи з FastAPI 0.99.0) додав підтримку `examples`, що є частиною стандарту **Схеми JSON**.\n\nДо цього підтримувався лише ключ `example` з одним прикладом. Він все ще підтримується в OpenAPI 3.1.0, але є застарілим і не входить до стандарту Схеми JSON. Тому рекомендується перейти з `example` на `examples`. 🤓\n\nБільше про це можна прочитати в кінці цієї сторінки.\n\n///\n\n## Додаткові аргументи `Field` { #field-additional-arguments }\n\nКоли ви використовуєте `Field()` у моделях Pydantic, ви також можете вказати додаткові `examples`:\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## `examples` у Схемі JSON - OpenAPI { #examples-in-json-schema-openapi }\n\nПри використанні будь-кого з наступного:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nви також можете задати набір `examples` з додатковою інформацією, яка буде додана до їхніх **Схем JSON** у **OpenAPI**.\n\n### `Body` з `examples` { #body-with-examples }\n\nТут ми передаємо `examples`, які містять один приклад очікуваних даних у `Body()`:\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### Приклад у UI документації { #example-in-the-docs-ui }\n\nЗа допомогою будь-якого з наведених вище методів це виглядатиме так у `/docs`:\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### `Body` з кількома `examples` { #body-with-multiple-examples }\n\nЗвичайно, ви також можете передати кілька `examples`:\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\nКоли ви це робите, приклади будуть частиною внутрішньої **Схеми JSON** для цих даних тіла.\n\nВтім, на <dfn title=\"2023-08-26\">час написання цього</dfn>, Swagger UI - інструмент, який відповідає за відображення UI документації - не підтримує показ кількох прикладів для даних у **Схемі JSON**. Але нижче можна прочитати про обхідний шлях.\n\n### Специфічні для OpenAPI `examples` { #openapi-specific-examples }\n\nЩе до того, як **Схема JSON** почала підтримувати `examples`, OpenAPI вже мала підтримку іншого поля, яке також називається `examples`.\n\nЦе **специфічне для OpenAPI** поле `examples` розміщується в іншому розділі специфікації OpenAPI. Воно розміщується в **деталях кожної *операції шляху***, а не всередині кожної Схеми JSON.\n\nІ Swagger UI вже давно підтримує це поле `examples`. Тому ви можете використовувати його, щоб **відображати** різні **приклади в UI документації**.\n\nФорма цього специфічного для OpenAPI поля `examples` - це `dict` з **кількома прикладами** (а не `list`), кожен із яких має додаткову інформацію, яка також буде додана до **OpenAPI**.\n\nВоно не включається всередину кожної Схеми JSON, що міститься в OpenAPI, воно розміщується зовні, безпосередньо в *операції шляху*.\n\n### Використання параметра `openapi_examples` { #using-the-openapi-examples-parameter }\n\nВи можете оголосити специфічні для OpenAPI `examples` у FastAPI за допомогою параметра `openapi_examples` для:\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\nКлючі `dict` ідентифікують кожен приклад, а кожне значення - це інший `dict`.\n\nКожен специфічний `dict` прикладу в `examples` може містити:\n\n* `summary`: короткий опис прикладу.\n* `description`: розгорнутий опис, який може містити Markdown.\n* `value`: це сам приклад, який буде показано, наприклад `dict`.\n* `externalValue`: альтернатива `value`, URL-адреса, що вказує на приклад. Проте це може не підтримуватися такою кількістю інструментів, як `value`.\n\nВикористання виглядає так:\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### Приклади OpenAPI в UI документації { #openapi-examples-in-the-docs-ui }\n\nЗ `openapi_examples`, доданим до `Body()`, `/docs` виглядатиме так:\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## Технічні деталі { #technical-details }\n\n/// tip | Порада\n\nЯкщо ви вже використовуєте **FastAPI** версії **0.99.0 або вище**, ви, ймовірно, можете **пропустити** ці технічні деталі.\n\nВони більш актуальні для старих версій, до появи OpenAPI 3.1.0.\n\nМожна вважати це коротким **історичним екскурсом** у OpenAPI та Схему JSON. 🤓\n\n///\n\n/// warning | Попередження\n\nЦе дуже технічна інформація про стандарти **Схема JSON** і **OpenAPI**.\n\nЯкщо вищезгадані ідеї вже працюють у вас, цього може бути достатньо, і вам, ймовірно, не потрібні ці деталі - можете пропустити.\n\n///\n\nДо OpenAPI 3.1.0 OpenAPI використовував стару та модифіковану версію **Схеми JSON**.\n\nСхема JSON не мала `examples`, тож OpenAPI додала власне поле `example` до своєї модифікованої версії.\n\nOpenAPI також додала поля `example` і `examples` до інших частин специфікації:\n\n* [`Parameter Object` (у специфікації)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object), який використовувався утилітами FastAPI:\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object`, у полі `content`, у `Media Type Object` (у специфікації)](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object), який використовувався утилітами FastAPI:\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info | Інформація\n\nЦей старий специфічний для OpenAPI параметр `examples` тепер називається `openapi_examples`, починаючи з FastAPI `0.103.0`.\n\n///\n\n### Поле `examples` у Схемі JSON { #json-schemas-examples-field }\n\nПізніше Схема JSON додала поле [`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5) у нову версію специфікації.\n\nА потім новий OpenAPI 3.1.0 базувався на найновішій версії (JSON Schema 2020-12), яка включала це нове поле `examples`.\n\nІ тепер це нове поле `examples` має вищий пріоритет за старе одиночне (і кастомне) поле `example`, яке тепер є застарілим.\n\nЦе нове поле `examples` у Схемі JSON - це **просто `list`** прикладів, а не `dict` з додатковими метаданими, як в інших місцях OpenAPI (описаних вище).\n\n/// info | Інформація\n\nНавіть після релізу OpenAPI 3.1.0 з цією новою простішою інтеграцією зі Схемою JSON, протягом певного часу Swagger UI, інструмент, який надає автоматичну документацію, не підтримував OpenAPI 3.1.0 (тепер підтримує, починаючи з версії 5.0.0 🎉).\n\nЧерез це версії FastAPI до 0.99.0 все ще використовували версії OpenAPI нижчі за 3.1.0.\n\n///\n\n### `examples` у Pydantic і FastAPI { #pydantic-and-fastapi-examples }\n\nКоли ви додаєте `examples` у модель Pydantic через `schema_extra` або `Field(examples=[\"something\"])`, цей приклад додається до **Схеми JSON** для цієї моделі Pydantic.\n\nІ ця **Схема JSON** Pydantic-моделі включається до **OpenAPI** вашого API, а потім використовується в UI документації.\n\nУ версіях FastAPI до 0.99.0 (0.99.0 і вище використовують новіший OpenAPI 3.1.0), коли ви використовували `example` або `examples` з будь-якими іншими утилітами (`Query()`, `Body()` тощо), ці приклади не додавалися до Схеми JSON, що описує ці дані (навіть не до власної версії Схеми JSON в OpenAPI), натомість вони додавалися безпосередньо до декларації *операції шляху* в OpenAPI (поза межами частин OpenAPI, які використовують Схему JSON).\n\nАле тепер, коли FastAPI 0.99.0 і вище використовує OpenAPI 3.1.0, який використовує JSON Schema 2020-12, і Swagger UI 5.0.0 і вище, все стало більш узгодженим, і приклади включаються до Схеми JSON.\n\n### Swagger UI та специфічні для OpenAPI `examples` { #swagger-ui-and-openapi-specific-examples }\n\nОскільки Swagger UI не підтримував кілька прикладів Схеми JSON (станом на 2023-08-26), користувачі не мали можливості показати кілька прикладів у документації.\n\nЩоб вирішити це, FastAPI `0.103.0` **додав підтримку** оголошення того самого старого **OpenAPI-специфічного** поля `examples` через новий параметр `openapi_examples`. 🤓\n\n### Підсумок { #summary }\n\nРаніше я казав, що не дуже люблю історію... а тепер подивіться на мене - читаю «технічні історичні» лекції. 😅\n\nКоротко: **оновіться до FastAPI 0.99.0 або вище** - і все стане значно **простішим, узгодженим та інтуїтивно зрозумілим**, і вам не доведеться знати всі ці історичні деталі. 😎\n"
  },
  {
    "path": "docs/uk/docs/tutorial/security/first-steps.md",
    "content": "# Безпека - перші кроки { #security-first-steps }\n\nУявімо, що ваш **backend** API працює на певному домені.\n\nА **frontend** - на іншому домені або в іншому шляху того ж домену (або у мобільному застосунку).\n\nІ ви хочете, щоб frontend міг автентифікуватися в backend, використовуючи ім'я користувача та пароль.\n\nМи можемо використати **OAuth2**, щоб збудувати це з **FastAPI**.\n\nАле заощадимо вам час на читання всієї довгої специфікації, щоб знайти лише потрібні дрібниці.\n\nСкористаймося інструментами, які надає **FastAPI**, щоб обробляти безпеку.\n\n## Як це виглядає { #how-it-looks }\n\nСпочатку просто запустімо код і подивімося, як він працює, а потім повернемося, щоб розібратися, що відбувається.\n\n## Створіть `main.py` { #create-main-py }\n\nСкопіюйте приклад у файл `main.py`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## Запустіть { #run-it }\n\n/// info | Інформація\n\nПакет [`python-multipart`](https://github.com/Kludex/python-multipart) автоматично встановлюється з **FastAPI**, коли ви виконуєте команду `pip install \"fastapi[standard]\"`.\n\nОднак, якщо ви використовуєте команду `pip install fastapi`, пакет `python-multipart` за замовчуванням не включено.\n\nЩоб встановити його вручну, переконайтеся, що ви створили [віртуальне оточення](../../virtual-environments.md), активували його, а потім встановили:\n\n```console\n$ pip install python-multipart\n```\n\nЦе тому, що **OAuth2** використовує «form data» для надсилання `username` та `password`.\n\n///\n\nЗапустіть приклад:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## Перевірте { #check-it }\n\nПерейдіть до інтерактивної документації: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВи побачите щось подібне:\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Кнопка Authorize!\n\nУ вас уже є нова блискуча кнопка «Authorize».\n\nА ваша *операція шляху* має маленький замок у правому верхньому куті, на який можна натиснути.\n\n///\n\nЯкщо натиснути її, з’явиться маленька форма авторизації, щоб ввести `username` і `password` (та інші необов’язкові поля):\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | Примітка\n\nНеважливо, що ви введете у форму, поки що це не спрацює. Але ми скоро це доробимо.\n\n///\n\nЗвісно, це не frontend для кінцевих користувачів, але це чудовий інструмент для інтерактивної документації всього вашого API.\n\nНим може користуватися команда frontend (якою можете бути і ви самі).\n\nНим можуть користуватися сторонні застосунки та системи.\n\nІ ним також можете користуватися ви самі, щоб налагоджувати, перевіряти та тестувати той самий застосунок.\n\n## Потік паролю { #the-password-flow }\n\nТепер повернімося трохи назад і розберімося, що це все таке.\n\n`password` «flow» - це один зі способів («flows»), визначених в OAuth2, для обробки безпеки та автентифікації.\n\nOAuth2 був спроєктований так, щоб backend або API могли бути незалежними від сервера, який автентифікує користувача.\n\nАле в нашому випадку той самий застосунок **FastAPI** оброблятиме і API, і автентифікацію.\n\nТож розгляньмо це у спрощеному вигляді:\n\n- Користувач вводить `username` і `password` у frontend і натискає `Enter`.\n- Frontend (у браузері користувача) надсилає ці `username` і `password` на специфічну URL-адресу нашого API (оголошену як `tokenUrl=\"token\"`).\n- API перевіряє ці `username` і `password` та повертає «токен» (ми ще нічого з цього не реалізували).\n    - «Токен» - це просто строка з деяким вмістом, який ми можемо пізніше використати, щоб перевірити цього користувача.\n    - Зазвичай токен налаштований на завершення строку дії через певний час.\n        - Тож користувачу доведеться знову увійти пізніше.\n        - І якщо токен викрадуть, ризик менший. Це не як постійний ключ, який працюватиме завжди (у більшості випадків).\n- Frontend тимчасово зберігає цей токен десь.\n- Користувач клікає у frontend, щоб перейти до іншого розділу вебзастосунку.\n- Frontend має отримати ще дані з API.\n    - Але для того конкретного кінцевого пункту потрібна автентифікація.\n    - Тож, щоб автентифікуватися в нашому API, він надсилає заголовок `Authorization` зі значенням `Bearer ` плюс токен.\n    - Якщо токен містить `foobar`, вміст заголовка `Authorization` буде: `Bearer foobar`.\n\n## `OAuth2PasswordBearer` у **FastAPI** { #fastapis-oauth2passwordbearer }\n\n**FastAPI** надає кілька інструментів на різних рівнях абстракції, щоб реалізувати ці функції безпеки.\n\nУ цьому прикладі ми використаємо **OAuth2** з потоком **Password**, використовуючи токен **Bearer**. Це робиться за допомогою класу `OAuth2PasswordBearer`.\n\n/// info | Інформація\n\n«Bearer»-токен - не єдиний варіант.\n\nАле це найкращий для нашого сценарію.\n\nІ, можливо, найкращий для більшості сценаріїв, якщо ви не експерт з OAuth2 і точно не знаєте, чому інша опція краще відповідає вашим потребам.\n\nУ такому разі **FastAPI** теж надає інструменти, щоб це збудувати.\n\n///\n\nКоли ми створюємо екземпляр класу `OAuth2PasswordBearer`, ми передаємо параметр `tokenUrl`. Цей параметр містить URL, який клієнт (frontend у браузері користувача) використовуватиме, щоб надіслати `username` і `password` для отримання токена.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip | Порада\n\nТут `tokenUrl=\"token\"` відноситься до відносної URL-адреси `token`, яку ми ще не створили. Оскільки це відносна URL-адреса, вона еквівалентна `./token`.\n\nТому, якщо ваш API розміщений на `https://example.com/`, це буде `https://example.com/token`. А якщо на `https://example.com/api/v1/`, тоді це буде `https://example.com/api/v1/token`.\n\nВикористання відносної URL-адреси важливе, щоб ваша програма продовжувала працювати навіть у просунутому сценарії, як-от [За представником](../../advanced/behind-a-proxy.md).\n\n///\n\nЦей параметр не створює той endpoint / *операцію шляху*, а декларує, що URL `/token` буде тим, який клієнт має використовувати, щоб отримати токен. Ця інформація використовується в OpenAPI, а потім - у системах інтерактивної документації API.\n\nНезабаром ми також створимо фактичну операцію шляху.\n\n/// info | Інформація\n\nЯкщо ви дуже строгий «Pythonista», вам може не подобатися стиль імені параметра `tokenUrl` замість `token_url`.\n\nЦе тому, що використано ту саму назву, що і в специфікації OpenAPI. Тож якщо вам потрібно буде дослідити ці схеми безпеки глибше, ви зможете просто скопіювати та вставити її, щоб знайти більше інформації.\n\n///\n\nЗмінна `oauth2_scheme` - це екземпляр `OAuth2PasswordBearer`, але це також і «викликаємий» об’єкт.\n\nЙого можна викликати так:\n\n```Python\noauth2_scheme(some, parameters)\n```\n\nТож його можна використовувати з `Depends`.\n\n### Використання { #use-it }\n\nТепер ви можете передати `oauth2_scheme` як залежність через `Depends`.\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nЦя залежність надасть `str`, який буде присвоєний параметру `token` *функції операції шляху*.\n\n**FastAPI** знатиме, що може використати цю залежність, щоб визначити «схему безпеки» в схемі OpenAPI (і в автоматичній документації API).\n\n/// info | Технічні деталі\n\n**FastAPI** знатиме, що може використати клас `OAuth2PasswordBearer` (оголошений у залежності), щоб визначити схему безпеки в OpenAPI, тому що він наслідує `fastapi.security.oauth2.OAuth2`, який своєю чергою наслідує `fastapi.security.base.SecurityBase`.\n\nУсі утиліти безпеки, які інтегруються з OpenAPI (і автоматичною документацією API), наслідують `SecurityBase`. Так **FastAPI** розуміє, як інтегрувати їх в OpenAPI.\n\n///\n\n## Що відбувається { #what-it-does }\n\nВона шукатиме в запиті заголовок `Authorization`, перевірить, чи його значення - це `Bearer ` плюс деякий токен, і поверне токен як `str`.\n\nЯкщо заголовка `Authorization` немає або значення не містить токена `Bearer `, вона одразу відповість помилкою зі статус-кодом 401 (`UNAUTHORIZED`).\n\nВам навіть не потрібно перевіряти, чи існує токен, щоб повернути помилку. Ви можете бути певні: якщо ваша функція виконується, у параметрі токена буде `str`.\n\nВи вже можете спробувати це в інтерактивній документації:\n\n<img src=\"/img/tutorial/security/image03.png\">\n\nМи ще не перевіряємо дійсність токена, але це вже початок.\n\n## Підсумок { #recap }\n\nОтже, лише 3-4 додатковими рядками ви вже маєте деяку примітивну форму безпеки.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/security/get-current-user.md",
    "content": "# Отримати поточного користувача { #get-current-user }\n\nУ попередньому розділі система безпеки (яка базується на системі впровадження залежностей) передавала функції операції шляху `token` як `str`:\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\nАле це ще не дуже корисно.\n\nЗробімо так, щоб вона повертала поточного користувача.\n\n## Створити модель користувача { #create-a-user-model }\n\nСпочатку створімо модель користувача в Pydantic.\n\nТак само, як ми використовуємо Pydantic для оголошення тіл, ми можемо використовувати його будь-де:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## Створити залежність `get_current_user` { #create-a-get-current-user-dependency }\n\nСтворімо залежність `get_current_user`.\n\nПам'ятаєте, що залежності можуть мати підзалежності?\n\n`get_current_user` матиме залежність із тим самим `oauth2_scheme`, який ми створили раніше.\n\nТак само, як ми робили раніше безпосередньо в операції шляху, наша нова залежність `get_current_user` отримає `token` як `str` від підзалежності `oauth2_scheme`:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## Отримати користувача { #get-the-user }\n\n`get_current_user` використає (фальшиву) утилітну функцію, яку ми створили, що приймає `token` як `str` і повертає нашу Pydantic-модель `User`:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## Впровадити поточного користувача { #inject-the-current-user }\n\nТепер ми можемо використати той самий `Depends` з нашим `get_current_user` в операції шляху:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\nЗверніть увагу, що ми оголошуємо тип `current_user` як Pydantic-модель `User`.\n\nЦе допоможе всередині функції з автодоповненням і перевірками типів.\n\n/// tip | Порада\n\nМожливо, ви пам'ятаєте, що тіла запиту також оголошуються моделями Pydantic.\n\nТут **FastAPI** не заплутається, тому що ви використовуєте `Depends`.\n\n///\n\n/// check | Перевірте\n\nТе, як спроєктована ця система залежностей, дозволяє мати різні залежності (різні «залежні»), які всі повертають модель `User`.\n\nМи не обмежені наявністю лише однієї залежності, що може повертати такі дані.\n\n///\n\n## Інші моделі { #other-models }\n\nТепер ви можете отримувати поточного користувача безпосередньо у функціях операцій шляху та працювати з механізмами безпеки на рівні **впровадження залежностей**, використовуючи `Depends`.\n\nІ ви можете використовувати будь-яку модель або дані для вимог безпеки (у цьому випадку Pydantic-модель `User`).\n\nАле ви не обмежені використанням якоїсь конкретної модели даних, класу чи типу.\n\nХочете мати id та email і не мати жодного username у вашій моделі? Без проблем. Ви можете використовувати ті самі інструменти.\n\nХочете мати просто `str`? Або лише `dict`? Або безпосередньо екземпляр класу моделі бази даних? Усе працює так само.\n\nУ вашій програмі насправді входять не користувачі, а роботи, боти чи інші системи, що мають лише токен доступу? Знову ж, усе працює так само.\n\nПросто використовуйте будь-який тип моделі, будь-який клас, будь-яку базу даних, які потрібні вашій програмі. **FastAPI** подбає про це завдяки системі впровадження залежностей.\n\n## Розмір коду { #code-size }\n\nЦей приклад може здаватися багатослівним. Майте на увазі, що ми змішуємо безпеку, моделі даних, утилітні функції та операції шляху в одному файлі.\n\nАле ось ключовий момент.\n\nРечі, пов'язані з безпекою та впровадженням залежностей, пишуться один раз.\n\nІ ви можете зробити це настільки складним, наскільки потрібно. І все одно мати це написаним лише один раз, в одному місці. З усією гнучкістю.\n\nЗате ви можете мати тисячі кінцевих точок (операцій шляху), що використовують одну й ту саму систему безпеки.\n\nІ всі вони (або будь-яка їхня частина, яку ви захочете) можуть скористатися повторним використанням цих залежностей або будь-яких інших, які ви створите.\n\nІ всі ці тисячі операцій шляху можуть бути всього у 3 рядки:\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## Підсумок { #recap }\n\nТепер ви можете отримувати поточного користувача безпосередньо у вашій функції операції шляху.\n\nМи вже на півдорозі.\n\nПотрібно лише додати операцію шляху, щоб користувач/клієнт міг фактично надіслати `username` і `password`.\n\nДалі саме це.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/security/index.md",
    "content": "# Безпека { #security }\n\nІснує багато способів реалізувати безпеку, автентифікацію та авторизацію.\n\nІ зазвичай це складна і «непроста» тема.\n\nУ багатьох фреймворках і системах лише обробка безпеки та автентифікації потребує великих зусиль і коду (у багатьох випадках це може бути 50% або більше від усього написаного коду).\n\n**FastAPI** надає кілька інструментів, які допоможуть вам працювати з **безпекою** легко, швидко, стандартним способом, без необхідності вивчати всі специфікації безпеки.\n\nАле спочатку розгляньмо кілька невеликих понять.\n\n## Поспішаєте? { #in-a-hurry }\n\nЯкщо вам не цікаві всі ці терміни й вам просто потрібно додати безпеку з автентифікацією на основі імені користувача та пароля *прямо зараз*, переходьте до наступних розділів.\n\n## OAuth2 { #oauth2 }\n\nOAuth2 — це специфікація, що визначає кілька способів обробки автентифікації та авторизації.\n\nЦе досить об'ємна специфікація, яка охоплює кілька складних випадків використання.\n\nВона включає способи автентифікації через «третю сторону».\n\nСаме це лежить в основі всіх систем із «увійти через Facebook, Google, X (Twitter), GitHub».\n\n### OAuth 1 { #oauth-1 }\n\nРаніше існував OAuth 1, який значно відрізняється від OAuth2 і є складнішим, оскільки містив прямі специфікації щодо того, як шифрувати комунікацію.\n\nЗараз він не дуже популярний або використовується.\n\nOAuth2 не вказує, як саме шифрувати комунікацію — він очікує, що ваш застосунок доступний через HTTPS.\n\n/// tip | Порада\n\nУ розділі про **деплой** ви побачите, як налаштувати HTTPS безкоштовно з Traefik та Let's Encrypt.\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect — ще одна специфікація, побудована на основі **OAuth2**.\n\nВона просто розширює OAuth2, уточнюючи деякі відносно неоднозначні речі в OAuth2, щоб зробити його більш сумісним.\n\nНаприклад, вхід через Google використовує OpenID Connect (який під капотом використовує OAuth2).\n\nАле вхід через Facebook не підтримує OpenID Connect. Він має власний різновид OAuth2.\n\n### OpenID (не «OpenID Connect») { #openid-not-openid-connect }\n\nІснувала також специфікація «OpenID». Вона намагалася розвʼязати те саме, що й **OpenID Connect**, але не базувалась на OAuth2.\n\nТож це була повністю додаткова система.\n\nЗараз вона не дуже популярна або використовується.\n\n## OpenAPI { #openapi }\n\nOpenAPI (раніше відомий як Swagger) — це відкрита специфікація для побудови API (тепер частина Linux Foundation).\n\n**FastAPI** базується на **OpenAPI**.\n\nСаме це робить можливими кілька автоматичних інтерактивних інтерфейсів документації, генерацію коду тощо.\n\nOpenAPI має спосіб визначати різні «схеми» безпеки.\n\nВикористовуючи їх, ви можете скористатися всіма цими інструментами, що базуються на стандартах, зокрема цими інтерактивними системами документації.\n\nOpenAPI визначає такі схеми безпеки:\n\n* `apiKey`: специфічний для застосунку ключ, який може передаватися через:\n    * Параметр запиту.\n    * Заголовок.\n    * Кукі.\n* `http`: стандартні системи HTTP-автентифікації, включаючи:\n    * `bearer`: заголовок `Authorization` зі значенням `Bearer ` та токеном. Це успадковано з OAuth2.\n    * базову автентифікацію HTTP.\n    * HTTP дайджест тощо.\n* `oauth2`: усі способи обробки безпеки за допомогою OAuth2 (так звані «потоки»).\n    * Декілька з цих потоків підходять для створення провайдера автентифікації OAuth 2.0 (наприклад, Google, Facebook, X (Twitter), GitHub тощо):\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * Але є один окремий «потік», який можна ідеально використати для обробки автентифікації напряму в цьому ж застосунку:\n        * `password`: у кількох наступних розділах будуть приклади цього.\n* `openIdConnect`: має спосіб визначити, як автоматично виявляти дані автентифікації OAuth2.\n    * Саме це автоматичне виявлення визначено у специфікації OpenID Connect.\n\n\n/// tip | Порада\n\nІнтеграція інших провайдерів автентифікації/авторизації, таких як Google, Facebook, X (Twitter), GitHub тощо, також можлива і відносно проста.\n\nНайскладніше — це створити провайдера автентифікації/авторизації на кшталт таких, але **FastAPI** надає вам інструменти, щоб зробити це легко, виконуючи важку частину роботи за вас.\n\n///\n\n## Утиліти **FastAPI** { #fastapi-utilities }\n\nFastAPI надає кілька інструментів для кожної з описаних схем безпеки в модулі `fastapi.security`, які спрощують використання цих механізмів безпеки.\n\nУ наступних розділах ви побачите, як додати безпеку до свого API за допомогою цих інструментів, які надає **FastAPI**.\n\nА також побачите, як це автоматично інтегрується в інтерактивну систему документації.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/security/oauth2-jwt.md",
    "content": "# OAuth2 з паролем (і хешуванням), Bearer з токенами JWT { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\nТепер, коли ми маємо весь потік безпеки, зробімо застосунок справді захищеним, використовуючи токени <abbr title=\"JSON Web Tokens - Токени JSON Web\">JWT</abbr> і безпечне хешування паролів.\n\nЦей код ви можете реально використовувати у своєму застосунку, зберігати хеші паролів у своїй базі даних тощо.\n\nМи почнемо з того місця, де зупинилися в попередньому розділі, і розширимо його.\n\n## Про JWT { #about-jwt }\n\nJWT означає «JSON Web Tokens».\n\nЦе стандарт кодування об'єкта JSON у довгий щільний рядок без пробілів. Він виглядає так:\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\nВін не зашифрований, тому кожен може відновити інформацію з вмісту.\n\nАле він підписаний. Тож коли ви отримуєте токен, який ви видали, ви можете перевірити, що справді його видали ви.\n\nТаким чином, ви можете створити токен із терміном дії, наприклад, 1 тиждень. І коли користувач повернеться наступного дня з токеном, ви знатимете, що користувач досі увійшов у вашу систему.\n\nЧерез тиждень токен завершить термін дії, і користувач не буде авторизований та має знову увійти, щоб отримати новий токен. І якщо користувач (або третя сторона) намагатиметься змінити токен, щоб змінити термін дії, ви це виявите, бо підписи не співпадатимуть.\n\nЯкщо хочете «погратися» з токенами JWT і побачити, як вони працюють, перегляньте [https://jwt.io](https://jwt.io/).\n\n## Встановіть `PyJWT` { #install-pyjwt }\n\nНам потрібно встановити `PyJWT`, щоб створювати та перевіряти токени JWT у Python.\n\nПереконайтеся, що ви створили [віртуальне оточення](../../virtual-environments.md), активували його і тоді встановіть `pyjwt`:\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info | Інформація\n\nЯкщо ви плануєте використовувати алгоритми цифрового підпису на кшталт RSA або ECDSA, слід встановити залежність криптобібліотеки `pyjwt[crypto]`.\n\nДокладніше про це можна прочитати у [документації з встановлення PyJWT](https://pyjwt.readthedocs.io/en/latest/installation.html).\n\n///\n\n## Хешування паролів { #password-hashing }\n\n«Хешування» означає перетворення деякого вмісту (у цьому випадку пароля) на послідовність байтів (просто строку), що виглядає як нісенітниця.\n\nКожного разу, коли ви передаєте точно той самий вміст (точно той самий пароль), ви отримуєте точно ту саму «нісенітницю».\n\nАле не можна перетворити цю «нісенітницю» назад у пароль.\n\n### Навіщо використовувати хешування паролів { #why-use-password-hashing }\n\nЯкщо вашу базу даних вкрадуть, зловмисник не матиме відкритих паролів ваших користувачів, а лише хеші.\n\nТож зловмисник не зможе спробувати використати цей пароль в іншій системі (оскільки багато користувачів використовують той самий пароль всюди, це було б небезпечно).\n\n## Встановіть `pwdlib` { #install-pwdlib }\n\npwdlib - це чудовий пакет Python для роботи з хешами паролів.\n\nВін підтримує багато безпечних алгоритмів хешування та утиліт для роботи з ними.\n\nРекомендований алгоритм - «Argon2».\n\nПереконайтеся, що ви створили [віртуальне оточення](../../virtual-environments.md), активували його і тоді встановіть pwdlib з Argon2:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | Порада\n\nЗ `pwdlib` ви навіть можете налаштувати його так, щоб він умів читати паролі, створені **Django**, плагіном безпеки **Flask** або багатьма іншими.\n\nТож ви зможете, наприклад, спільно використовувати ті самі дані з застосунку Django в базі даних із застосунком FastAPI. Або поступово мігрувати застосунок Django, використовуючи ту саму базу даних.\n\nІ ваші користувачі зможуть входити як із вашого застосунку Django, так і з вашого застосунку **FastAPI** одночасно.\n\n///\n\n## Хешування і перевірка паролів { #hash-and-verify-the-passwords }\n\nІмпортуйте потрібні інструменти з `pwdlib`.\n\nСтворіть екземпляр PasswordHash з рекомендованими налаштуваннями - він буде використаний для хешування та перевірки паролів.\n\n/// tip | Порада\n\npwdlib також підтримує алгоритм хешування bcrypt, але не включає застарілі алгоритми - для роботи із застарілими хешами рекомендується використовувати бібліотеку passlib.\n\nНаприклад, ви можете використати її для читання і перевірки паролів, згенерованих іншою системою (наприклад, Django), але хешувати будь-які нові паролі іншим алгоритмом, таким як Argon2 або Bcrypt.\n\nІ бути сумісними з усіма ними одночасно.\n\n///\n\nСтворіть утилітарну функцію для хешування пароля, що надходить від користувача.\n\nІ ще одну утиліту для перевірки, чи отриманий пароль відповідає збереженому хешу.\n\nІ ще одну - для автентифікації та повернення користувача.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\nКоли `authenticate_user` викликається з ім'ям користувача, якого немає в базі даних, ми все одно запускаємо `verify_password` для «підставного» хешу.\n\nЦе забезпечує приблизно однаковий час відповіді кінцевої точки незалежно від того, чи є ім'я користувача дійсним, запобігаючи **атакам за часом**, які могли б бути використані для перелічення наявних імен користувачів.\n\n/// note | Примітка\n\nЯкщо ви перевірите нову (фальшиву) базу даних `fake_users_db`, побачите, як зараз виглядає хеш пароля: `\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`.\n\n///\n\n## Опрацювання токенів JWT { #handle-jwt-tokens }\n\nІмпортуйте встановлені модулі.\n\nСтворіть випадковий секретний ключ, який буде використано для підписання токенів JWT.\n\nЩоб згенерувати безпечний випадковий секретний ключ, використайте команду:\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\nІ скопіюйте вивід у змінну `SECRET_KEY` (не використовуйте той, що в прикладі).\n\nСтворіть змінну `ALGORITHM` з алгоритмом для підписання токена JWT і встановіть її в `\"HS256\"`.\n\nСтворіть змінну для терміну дії токена.\n\nВизначте модель Pydantic, яка буде використана в кінцевій точці токена для відповіді.\n\nСтворіть утилітарну функцію для генерації нового токена доступу.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## Оновіть залежності { #update-the-dependencies }\n\nОновіть `get_current_user`, щоб отримувати той самий токен, що й раніше, але цього разу - токен JWT.\n\nДекодуйте отриманий токен, перевірте його та поверніть поточного користувача.\n\nЯкщо токен недійсний, одразу поверніть помилку HTTP.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## Оновіть операцію шляху `/token` { #update-the-token-path-operation }\n\nСтворіть `timedelta` з часом життя токена.\n\nСтворіть справжній токен доступу JWT і поверніть його.\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### Технічні деталі про «subject» `sub` у JWT { #technical-details-about-the-jwt-subject-sub }\n\nСпецифікація JWT каже, що існує ключ `sub` із суб'єктом токена.\n\nВикористовувати його не обов'язково, але саме туди зазвичай поміщають ідентифікатор користувача, тож ми використовуємо його тут.\n\nJWT може використовуватися й для інших речей, окрім ідентифікації користувача та надання йому можливості безпосередньо виконувати операції з вашою API.\n\nНаприклад, ви можете ідентифікувати «автомобіль» або «допис у блозі».\n\nТоді ви можете додати дозволи щодо цієї сутності, як-от «керувати» (для автомобіля) або «редагувати» (для допису).\n\nІ потім ви можете видати цей токен JWT користувачу (або боту), і він зможе виконувати ці дії (керувати автомобілем або редагувати допис), навіть не маючи облікового запису - лише з токеном JWT, який ваша API для цього згенерувала.\n\nВикористовуючи ці ідеї, JWT можна застосовувати у значно складніших сценаріях.\n\nУ таких випадках кілька сутностей можуть мати однакові ідентифікатори, скажімо `foo` (користувач `foo`, автомобіль `foo` і допис `foo`).\n\nЩоб уникнути колізій ідентифікаторів, під час створення токена JWT для користувача ви можете додати префікс до значення ключа `sub`, наприклад `username:`. Отже, у цьому прикладі значення `sub` могло б бути: `username:johndoe`.\n\nВажливо пам'ятати, що ключ `sub` має містити унікальний ідентифікатор у межах усього застосунку і має бути строкою.\n\n## Перевірте { #check-it }\n\nЗапустіть сервер і перейдіть до документації: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\nВи побачите такий інтерфейс користувача:\n\n<img src=\"/img/tutorial/security/image07.png\">\n\nАвторизуйте застосунок так само, як раніше.\n\nВикористайте облікові дані:\n\nUsername: `johndoe`\nPassword: `secret`\n\n/// check | Перевірте\n\nЗверніть увагу, що ніде в коді немає відкритого пароля \"`secret`\", ми маємо лише хешовану версію.\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\nВикличте кінцеву точку `/users/me/`, ви отримаєте відповідь:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\nЯкщо відкриєте інструменти розробника, ви побачите, що у відправлених даних є лише токен, пароль надсилається тільки в першому запиті для автентифікації користувача та отримання токена доступу, але не надсилається далі:\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | Примітка\n\nЗверніть увагу на заголовок `Authorization` зі значенням, що починається з `Bearer `.\n\n///\n\n## Просунуте використання зі `scopes` { #advanced-usage-with-scopes }\n\nOAuth2 має поняття «scopes».\n\nВи можете використовувати їх, щоб додати конкретний набір дозволів до токена JWT.\n\nПотім ви можете видати цей токен користувачу напряму або третій стороні для взаємодії з вашою API із набором обмежень.\n\nВи можете дізнатися, як їх використовувати і як вони інтегровані з **FastAPI** пізніше у **просунутому посібнику користувача**.\n\n## Підсумок { #recap }\n\nМаючи все, що ви бачили досі, ви можете налаштувати захищений застосунок **FastAPI**, використовуючи стандарти на кшталт OAuth2 і JWT.\n\nМайже в будь-якому фреймворку опрацювання безпеки дуже швидко стає досить складною темою.\n\nБагато пакетів, що сильно це спрощують, змушені йти на численні компроміси з моделлю даних, базою даних і доступними можливостями. Дехто з цих пакетів, які надто все спрощують, насправді мають приховані вади безпеки.\n\n---\n\n**FastAPI** не йде на жодні компроміси з будь-якою базою даних, моделлю даних чи інструментом.\n\nВін дає вам усю гнучкість, щоб обрати ті, які найкраще підходять вашому проєкту.\n\nІ ви можете напряму використовувати добре підтримувані та широко застосовувані пакети на кшталт `pwdlib` і `PyJWT`, адже **FastAPI** не вимагає жодних складних механізмів для інтеграції зовнішніх пакетів.\n\nВодночас він надає інструменти, щоб максимально спростити процес без компромісів у гнучкості, надійності чи безпеці.\n\nІ ви можете використовувати та впроваджувати безпечні стандартні протоколи, як-от OAuth2, відносно простим способом.\n\nУ **просунутому посібнику користувача** ви можете дізнатися більше про те, як використовувати «scopes» в OAuth2 для більш детальної системи дозволів, дотримуючись тих самих стандартів. OAuth2 зі scopes - це механізм, який використовують багато великих провайдерів автентифікації, як-от Facebook, Google, GitHub, Microsoft, X (Twitter) тощо, щоб авторизувати сторонні застосунки на взаємодію з їхніми API від імені користувачів.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/security/simple-oauth2.md",
    "content": "# Простий OAuth2 з паролем і Bearer { #simple-oauth2-with-password-and-bearer }\n\nТепер продовжимо з попереднього розділу і додамо відсутні частини, щоб отримати повний потік безпеки.\n\n## Отримайте `username` і `password` { #get-the-username-and-password }\n\nМи використаємо утиліти безпеки **FastAPI**, щоб отримати `username` і `password`.\n\nOAuth2 визначає, що під час використання «потоку паролю» (який ми використовуємо) клієнт/користувач має надіслати поля `username` і `password` як дані форми.\n\nІ специфікація каже, що поля мають називатися саме так. Тому `user-name` або `email` не підійдуть.\n\nАле не хвилюйтеся, у фронтенді ви можете відображати це так, як забажаєте, для кінцевих користувачів.\n\nІ ваші моделі бази даних можуть використовувати будь-які інші назви.\n\nАле для *операції шляху* входу ми маємо використовувати саме ці назви, щоб бути сумісними зі специфікацією (і мати змогу, наприклад, користуватися вбудованою системою документації API).\n\nСпецифікація також вказує, що `username` і `password` мають надсилатися як дані форми (тобто без JSON).\n\n### `scope` { #scope }\n\nСпецифікація також каже, що клієнт може надіслати інше поле форми «`scope`».\n\nНазва поля форми — `scope` (в однині), але насправді це довга строка зі «scopes», розділеними пробілами.\n\nКожен «scope» — це просто строка (без пробілів).\n\nЇх зазвичай використовують для оголошення конкретних прав доступу, наприклад:\n\n- `users:read` або `users:write` — поширені приклади.\n- `instagram_basic` використовується Facebook / Instagram.\n- `https://www.googleapis.com/auth/drive` використовується Google.\n\n/// info | Інформація\n\nУ OAuth2 «scope» — це просто строка, що оголошує конкретний потрібний дозвіл.\n\nНе має значення, чи містить вона інші символи на кшталт `:` або чи це URL.\n\nЦі деталі залежать від реалізації.\n\nДля OAuth2 це просто строки.\n\n///\n\n## Код для отримання `username` і `password` { #code-to-get-the-username-and-password }\n\nТепер скористаймося утилітами, наданими **FastAPI**, щоб обробити це.\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\nСпочатку імпортуйте `OAuth2PasswordRequestForm` і використайте його як залежність із `Depends` в *операції шляху* для `/token`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm` — це клас залежності, що оголошує тіло форми з:\n\n- `username`.\n- `password`.\n- Необов'язковим полем `scope` як великою строкою, складеною зі строк, розділених пробілами.\n- Необов'язковим `grant_type`.\n\n/// tip | Порада\n\nСпецифікація OAuth2 насправді вимагає поле `grant_type` із фіксованим значенням `password`, але `OAuth2PasswordRequestForm` цього не примушує.\n\nЯкщо вам потрібно це примусити, використовуйте `OAuth2PasswordRequestFormStrict` замість `OAuth2PasswordRequestForm`.\n\n///\n\n- Необов'язковим `client_id` (для нашого прикладу не потрібно).\n- Необов'язковим `client_secret` (для нашого прикладу не потрібно).\n\n/// info | Інформація\n\n`OAuth2PasswordRequestForm` — не спеціальний клас для **FastAPI**, як `OAuth2PasswordBearer`.\n\n`OAuth2PasswordBearer` робить так, що **FastAPI** знає, що це схема безпеки. Тому її додають таким чином до OpenAPI.\n\nАле `OAuth2PasswordRequestForm` — це просто клас залежності, який ви могли б написати самі, або ви могли б напряму оголосити параметри `Form`.\n\nОскільки це типова задача, **FastAPI** надає його безпосередньо, щоб спростити роботу.\n\n///\n\n### Використовуйте дані форми { #use-the-form-data }\n\n/// tip | Порада\n\nЕкземпляр класу залежності `OAuth2PasswordRequestForm` не матиме атрибута `scope` з довгою строкою, розділеною пробілами, натомість він матиме атрибут `scopes` зі справжнім списком строк для кожного надісланого scope.\n\nУ цьому прикладі ми не використовуємо `scopes`, але ця можливість є, якщо знадобиться.\n\n///\n\nТепер отримайте дані користувача з (фальшивої) бази даних, використовуючи `username` з поля форми.\n\nЯкщо такого користувача немає, повертаємо помилку «Incorrect username or password».\n\nДля помилки використовуємо виняток `HTTPException`:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### Перевірте пароль { #check-the-password }\n\nНа цьому етапі ми маємо дані користувача з нашої бази даних, але ще не перевірили пароль.\n\nСпершу розмістимо ці дані в Pydantic-моделі `UserInDB`.\n\nВи ніколи не повинні зберігати паролі у відкритому вигляді, тож ми використаємо (фальшиву) систему хешування паролів.\n\nЯкщо паролі не збігаються, повертаємо ту саму помилку.\n\n#### Хешування паролів { #password-hashing }\n\n«Хешування» означає: перетворення деякого вмісту (у цьому випадку пароля) у послідовність байтів (просто строку), яка виглядає як нісенітниця.\n\nКожного разу, коли ви передаєте точно той самий вміст (точно той самий пароль), ви отримуєте точно ту саму «нісенітницю».\n\nАле ви не можете перетворити цю «нісенітницю» назад у пароль.\n\n##### Навіщо використовувати хешування паролів { #why-use-password-hashing }\n\nЯкщо вашу базу даних вкрадуть, зловмисник не матиме паролів користувачів у відкритому вигляді, лише хеші.\n\nТож зловмисник не зможе спробувати використати ті самі паролі в іншій системі (оскільки багато користувачів використовують той самий пароль всюди, це було б небезпечно).\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### Про `**user_dict` { #about-user-dict }\n\n`UserInDB(**user_dict)` означає:\n\nПередати ключі та значення з `user_dict` безпосередньо як аргументи ключ-значення, еквівалентно до:\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info | Інформація\n\nДля повнішого пояснення `**user_dict` перегляньте [документацію для **Додаткових моделей**](../extra-models.md#about-user-in-dict).\n\n///\n\n## Поверніть токен { #return-the-token }\n\nВідповідь точки входу `token` має бути об'єктом JSON.\n\nВона повинна містити `token_type`. У нашому випадку, оскільки ми використовуємо токени «Bearer», тип токена має бути «`bearer`».\n\nТакож має бути `access_token` зі строкою, що містить наш токен доступу.\n\nДля цього простого прикладу ми зробимо повністю небезпечно і повернемо той самий `username` як токен.\n\n/// tip | Порада\n\nУ наступному розділі ви побачите справді безпечну реалізацію з хешуванням паролів і токенами <abbr title=\"JSON Web Tokens - Токени JSON Web\">JWT</abbr>.\n\nА поки зосередьмося на конкретних деталях, які нам потрібні.\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip | Порада\n\nЗгідно зі специфікацією, ви маєте повертати JSON з `access_token` і `token_type`, як у цьому прикладі.\n\nЦе те, що ви маєте зробити самостійно у своєму коді, і переконатися, що використовуєте саме ці ключі JSON.\n\nЦе майже єдине, що ви маєте зробити правильно самі, щоб відповідати специфікації.\n\nРешту **FastAPI** зробить за вас.\n\n///\n\n## Оновіть залежності { #update-the-dependencies }\n\nТепер оновимо наші залежності.\n\nМи хочемо отримати `current_user` лише якщо цей користувач активний.\n\nТому створимо додаткову залежність `get_current_active_user`, яка своєю чергою використовує як залежність `get_current_user`.\n\nОбидві ці залежності просто повернуть HTTP-помилку, якщо користувача не існує або він неактивний.\n\nОтже, у нашій кінцевій точці ми отримаємо користувача лише якщо він існує, був правильно автентифікований і є активним:\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info | Інформація\n\nДодатковий заголовок `WWW-Authenticate` зі значенням `Bearer`, який ми тут повертаємо, також є частиною специфікації.\n\nБудь-який HTTP (помилка) зі статус-кодом 401 «UNAUTHORIZED» також має повертати заголовок `WWW-Authenticate`.\n\nУ випадку токенів носія (наш випадок) значенням цього заголовка має бути `Bearer`.\n\nФактично ви можете пропустити цей додатковий заголовок, і все одно працюватиме.\n\nАле він наданий тут, щоб відповідати специфікаціям.\n\nТакож можуть існувати інструменти, які очікують і використовують його (зараз або в майбутньому), і це може бути корисно вам або вашим користувачам, зараз або в майбутньому.\n\nУ цьому користь стандартів...\n\n///\n\n## Подивіться в дії { #see-it-in-action }\n\nВідкрийте інтерактивну документацію: [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).\n\n### Автентифікація { #authenticate }\n\nНатисніть кнопку «Authorize».\n\nВикористайте облікові дані:\n\nКористувач: `johndoe`\n\nПароль: `secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\nПісля автентифікації в системі ви побачите таке:\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### Отримайте власні дані користувача { #get-your-own-user-data }\n\nТепер використайте операцію `GET` зі шляхом `/users/me`.\n\nВи отримаєте дані свого користувача, наприклад:\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\nЯкщо натиснути значок замка й вийти з системи, а потім знову спробувати ту саму операцію, ви отримаєте помилку HTTP 401 такого вигляду:\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### Неактивний користувач { #inactive-user }\n\nТепер спробуйте з неактивним користувачем, автентифікуйтеся з:\n\nКористувач: `alice`\n\nПароль: `secret2`\n\nІ спробуйте використати операцію `GET` зі шляхом `/users/me`.\n\nВи отримаєте помилку «Inactive user», наприклад:\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## Підсумок { #recap }\n\nТепер у вас є інструменти для реалізації повної системи безпеки на основі `username` і `password` для вашого API.\n\nВикористовуючи ці інструменти, ви можете зробити систему безпеки сумісною з будь-якою базою даних і з будь-якою моделлю користувача чи даних.\n\nЄдина відсутня деталь у тому, що наразі це ще не «безпечна» реалізація.\n\nУ наступному розділі ви побачите, як використовувати безпечну бібліотеку для хешування паролів і токени <abbr title=\"JSON Web Tokens - Токени JSON Web\">JWT</abbr>.\n"
  },
  {
    "path": "docs/uk/docs/tutorial/server-sent-events.md",
    "content": "# Події, надіслані сервером (SSE) { #server-sent-events-sse }\n\nВи можете транслювати дані клієнту за допомогою **Server-Sent Events** (SSE).\n\nЦе подібно до [Потік JSON Lines](stream-json-lines.md), але використовує формат `text/event-stream`, який нативно підтримується браузерами через [API `EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).\n\n/// info | Інформація\n\nДодано у FastAPI 0.135.0.\n\n///\n\n## Що таке Server-Sent Events { #what-are-server-sent-events }\n\nSSE - це стандарт для трансляції даних із сервера до клієнта по HTTP.\n\nКожна подія - це невеликий текстовий блок із «полями» на кшталт `data`, `event`, `id` та `retry`, розділений порожніми рядками.\n\nВиглядає так:\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE часто використовують для стрімінгу чатів ШІ, живих сповіщень, логів і спостережуваності, а також інших випадків, коли сервер надсилає оновлення клієнту.\n\n/// tip | Порада\n\nЯкщо ви хочете транслювати бінарні дані, наприклад відео чи аудіо, перегляньте просунутий посібник: [Потік даних](../advanced/stream-data.md).\n\n///\n\n## Стрімінг SSE у FastAPI { #stream-sse-with-fastapi }\n\nЩоб транслювати SSE з FastAPI, використовуйте `yield` у вашій *функції операції шляху* і встановіть `response_class=EventSourceResponse`.\n\nІмпортуйте `EventSourceResponse` з `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\nКожен елемент, повернений через `yield`, кодується як JSON і надсилається в полі `data:` події SSE.\n\nЯкщо ви оголосите тип повернення як `AsyncIterable[Item]`, FastAPI використає його, щоб **перевіряти**, **документувати** і **серіалізувати** дані за допомогою Pydantic.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip | Порада\n\nОскільки Pydantic серіалізує це на боці **Rust**, ви отримаєте значно вищу **продуктивність**, ніж якби не оголошували тип повернення.\n\n///\n\n### Не-async *функції операцій шляху* { #non-async-path-operation-functions }\n\nВи також можете використовувати звичайні функції `def` (без `async`) і використовувати `yield` так само.\n\nFastAPI подбає про коректне виконання, щоб воно не блокувало цикл подій.\n\nОскільки в цьому випадку функція не async, коректним типом повернення буде `Iterable[Item]`:\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### Без типу повернення { #no-return-type }\n\nМожна також опустити тип повернення. FastAPI використає [`jsonable_encoder`](./encoder.md), щоб конвертувати дані і надіслати їх.\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\nЯкщо вам потрібно встановити поля SSE, такі як `event`, `id`, `retry` або `comment`, ви можете повертати через `yield` об'єкти `ServerSentEvent` замість звичайних даних.\n\nІмпортуйте `ServerSentEvent` з `fastapi.sse`:\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\nПоле `data` завжди кодується як JSON. Ви можете передати будь-яке значення, яке можна серіалізувати в JSON, включно з моделями Pydantic.\n\n## Сирі дані { #raw-data }\n\nЯкщо потрібно надіслати дані **без** кодування в JSON, використовуйте `raw_data` замість `data`.\n\nЦе корисно для надсилання попередньо відформатованого тексту, рядків логів або спеціальних значень <dfn title=\"Значення, яке використовується для позначення особливої умови або стану\">«значення-сторож»</dfn>, як-от `[DONE]`.\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note | Примітка\n\n`data` і `raw_data` взаємовиключні. У кожному `ServerSentEvent` ви можете встановити лише одне з них.\n\n///\n\n## Відновлення з `Last-Event-ID` { #resuming-with-last-event-id }\n\nКоли браузер перепідключається після розриву з'єднання, він надсилає останній отриманий `id` у заголовку `Last-Event-ID`.\n\nВи можете прочитати його як параметр заголовка і використати, щоб відновити потік із місця, де клієнт зупинився:\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## SSE з POST { #sse-with-post }\n\nSSE працює з **будь-яким HTTP-методом**, не лише з `GET`.\n\nЦе корисно для протоколів на кшталт [MCP](https://modelcontextprotocol.io), які транслюють SSE через `POST`:\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## Технічні деталі { #technical-details }\n\nFastAPI реалізує деякі найкращі практики SSE «з коробки».\n\n- Надсилати **коментар «keep alive» `ping`** кожні 15 секунд, коли не було жодного повідомлення, щоб запобігти закриттю з'єднання деякими проксі, як рекомендовано у [Специфікації HTML: Події, надіслані сервером](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes).\n- Встановити заголовок `Cache-Control: no-cache`, щоб **запобігти кешуванню** потоку.\n- Встановити спеціальний заголовок `X-Accel-Buffering: no`, щоб **запобігти буферизації** у деяких проксі, наприклад Nginx.\n\nВам не потрібно нічого з цим робити, воно працює «з коробки». 🤓\n"
  },
  {
    "path": "docs/uk/docs/tutorial/sql-databases.md",
    "content": "# SQL (реляційні) бази даних { #sql-relational-databases }\n\n**FastAPI** не вимагає від вас використовувати SQL (реляційну) базу даних. Але ви можете скористатися будь-якою базою даних, яку забажаєте.\n\nТут ми розглянемо приклад з [SQLModel](https://sqlmodel.tiangolo.com/).\n\n**SQLModel** побудовано поверх [SQLAlchemy](https://www.sqlalchemy.org/) та Pydantic. Її створив той самий автор, що і **FastAPI**, як ідеальну пару для застосунків FastAPI, яким потрібні **SQL бази даних**.\n\n/// tip | Порада\n\nВи можете використовувати будь-яку іншу бібліотеку для SQL або NoSQL баз (інколи їх називають <abbr title=\"Object Relational Mapper - Об'єктно-реляційний відображувач: складний термін для бібліотеки, де деякі класи представляють таблиці SQL, а екземпляри представляють рядки в цих таблицях\">\"ORMs\"</abbr>), FastAPI нічого не нав’язує. 😎\n\n///\n\nОскільки SQLModel базується на SQLAlchemy, ви можете легко використовувати будь-яку базу даних, яку підтримує SQLAlchemy (а отже й SQLModel), наприклад:\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server тощо\n\nУ цьому прикладі ми використаємо **SQLite**, оскільки вона зберігається в одному файлі, а Python має вбудовану підтримку. Тож ви можете скопіювати цей приклад і запустити «як є».\n\nПізніше, для вашого продакшн-застосунку, ви можете перейти на сервер бази даних, наприклад **PostgreSQL**.\n\n/// tip | Порада\n\nІснує офіційний генератор проєкту з **FastAPI** та **PostgreSQL**, включно з фронтендом та іншими інструментами: [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\nЦе дуже простий і короткий навчальний посібник. Якщо ви хочете вивчити бази даних загалом, SQL або більш просунуті можливості, зверніться до [документації SQLModel](https://sqlmodel.tiangolo.com/).\n\n## Встановіть `SQLModel` { #install-sqlmodel }\n\nСпочатку переконайтеся, що ви створили [віртуальне оточення](../virtual-environments.md), активували його та встановили `sqlmodel`:\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## Створіть застосунок з однією моделлю { #create-the-app-with-a-single-model }\n\nСпершу створимо найпростішу версію застосунку з однією моделлю **SQLModel**.\n\nПотім нижче покращимо безпеку і гнучкість за допомогою кількох моделей. 🤓\n\n### Створіть моделі { #create-models }\n\nІмпортуйте `SQLModel` і створіть модель бази даних:\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\nКлас `Hero` дуже схожий на модель Pydantic (фактично, під капотом це і є модель Pydantic).\n\nЄ кілька відмінностей:\n\n* `table=True` каже SQLModel, що це «таблична модель» - вона має представляти **таблицю** в SQL базі даних, а не просто «модель даних» (як будь-який інший звичайний клас Pydantic).\n\n* `Field(primary_key=True)` каже SQLModel, що `id` - це **первинний ключ** у SQL базі даних (більше про первинні ключі в SQL див. у документації SQLModel).\n\n    Примітка: Ми використовуємо `int | None` для поля первинного ключа, щоб у Python-коді можна було створити об’єкт без `id` (`id=None`), припускаючи, що база даних згенерує його під час збереження. SQLModel розуміє, що `id` надасть база даних, і визначає стовпець як ненульовий `INTEGER` у схемі бази даних. Докладніше див. [документацію SQLModel про первинні ключі](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id).\n\n* `Field(index=True)` каже SQLModel створити **SQL-індекс** для цього стовпця, що дозволить швидше виконувати пошук у базі даних під час читання даних, відфільтрованих за цим стовпцем.\n\n    SQLModel знатиме, що оголошене як `str` стане SQL-стовпцем типу `TEXT` (або `VARCHAR`, залежно від бази).\n\n### Створіть рушій { #create-an-engine }\n\n`engine` SQLModel (під капотом це `engine` SQLAlchemy) - це те, що **утримує з’єднання** з базою даних.\n\nУ вас має бути **єдиний об’єкт `engine`** для всього коду, що під’єднується до тієї самої бази.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\nВикористання `check_same_thread=False` дозволяє FastAPI використовувати ту саму базу SQLite у різних потоках. Це необхідно, адже **один запит** може використати **понад один потік** (наприклад, у залежностях).\n\nНе переймайтеся, завдяки структурі коду ми далі забезпечимо **одну сесію SQLModel на запит**, власне цього і прагне `check_same_thread`.\n\n### Створіть таблиці { #create-the-tables }\n\nДодамо функцію, яка використовує `SQLModel.metadata.create_all(engine)`, щоб **створити таблиці** для всіх «табличних моделей».\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### Створіть залежність сесії { #create-a-session-dependency }\n\n**`Session`** зберігає **об’єкти в пам’яті** та відстежує зміни у даних, а потім **використовує `engine`** для взаємодії з базою даних.\n\nМи створимо **залежність** FastAPI з `yield`, яка надаватиме нову `Session` для кожного запиту. Це й гарантує, що ми використовуємо одну сесію на запит. 🤓\n\nДалі створимо залежність `Annotated` - `SessionDep`, щоб спростити решту коду, який її використовуватиме.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### Створюйте таблиці під час запуску { #create-database-tables-on-startup }\n\nМи створимо таблиці бази під час запуску застосунку.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\nТут ми створюємо таблиці на події запуску застосунку.\n\nУ продакшні ви, ймовірно, використаєте міграційний скрипт, який виконується перед стартом застосунку. 🤓\n\n/// tip | Порада\n\nSQLModel матиме утиліти міграцій-обгортки над Alembic, але поки що ви можете використовувати [Alembic](https://alembic.sqlalchemy.org/en/latest/) напряму.\n\n///\n\n### Створіть героя { #create-a-hero }\n\nОскільки кожна модель SQLModel також є моделлю Pydantic, ви можете використовувати її в тих самих **анотаціях типів**, що і моделі Pydantic.\n\nНаприклад, якщо ви оголосите параметр типу `Hero`, він буде прочитаний з **JSON-тіла**.\n\nТак само ви можете оголосити її як **тип, що повертається** функції, і форма даних з’явиться в автоматичному UI документації API.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\nТут ми використовуємо залежність `SessionDep` (`Session`), щоб додати нового `Hero` до екземпляра `Session`, закомітити зміни до бази, оновити дані в `hero`, а потім повернути його.\n\n### Читання героїв { #read-heroes }\n\nМи можемо **читати** `Hero` з бази даних, використовуючи `select()`. Ми можемо додати `limit` і `offset` для пагінації результатів.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### Читання одного героя { #read-one-hero }\n\nМи можемо **прочитати** одного `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### Видалення героя { #delete-a-hero }\n\nМи також можемо **видалити** `Hero`.\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### Запуск застосунку { #run-the-app }\n\nВи можете запустити застосунок:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nПотім перейдіть до інтерфейсу `/docs`, ви побачите, що **FastAPI** використовує ці **моделі** для **документування** API, а також для **серіалізації** та **валідації** даних.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## Оновіть застосунок кількома моделями { #update-the-app-with-multiple-models }\n\nТепер трохи **відрефакторимо** застосунок, щоб підвищити **безпеку** та **гнучкість**.\n\nЯкщо подивитися на попередній варіант, у UI видно, що наразі клієнт може сам обирати `id` для створюваного `Hero`. 😱\n\nЦього допускати не можна - вони можуть перезаписати `id`, який уже призначений у БД. Визначення `id` має виконувати **бекенд** або **база даних**, **а не клієнт**.\n\nКрім того, ми створюємо для героя `secret_name`, але наразі повертаємо його всюди - це не дуже «секретно»... 😅\n\nВиправимо це, додавши кілька **додаткових моделей**. Ось де SQLModel засяє. ✨\n\n### Створіть кілька моделей { #create-multiple-models }\n\nУ **SQLModel** будь-який клас моделі з `table=True` - це **таблична модель**.\n\nА будь-який клас моделі без `table=True` - це **модель даних**; це, по суті, просто моделі Pydantic (з парою невеликих доповнень). 🤓\n\nЗ SQLModel ми можемо використовувати **успадкування**, щоб **уникати дублювання** полів у всіх випадках.\n\n#### `HeroBase` - базовий клас { #herobase-the-base-class }\n\nПочнімо з моделі `HeroBase`, яка містить усі **спільні поля** для всіх моделей:\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` - «таблична модель» { #hero-the-table-model }\n\nПотім створімо `Hero`, фактичну «табличну модель», з **додатковими полями**, яких немає в інших моделях завжди:\n\n* `id`\n* `secret_name`\n\nОскільки `Hero` успадковується від `HeroBase`, вона **також** містить **поля**, оголошені в `HeroBase`, тож усі поля `Hero` такі:\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` - публічна «модель даних» { #heropublic-the-public-data-model }\n\nДалі створимо модель `HeroPublic` - це та, що буде **повертатися** клієнтам API.\n\nВона має ті самі поля, що й `HeroBase`, отже не включатиме `secret_name`.\n\nНарешті, особистості наших героїв захищено! 🥷\n\nВона також перевизначає `id: int`. Роблячи це, ми укладаємо **контракт** з клієнтами API, що `id` завжди буде присутній і буде типу `int` (ніколи не `None`).\n\n/// tip | Порада\n\nНаявність у моделі відповіді гарантії, що значення завжди доступне і завжди `int` (не `None`), дуже корисна для клієнтів API - вони можуть писати значно простіший код, маючи цю визначеність.\n\nТакож **автоматично згенеровані клієнти** матимуть простіші інтерфейси, тож розробникам, які взаємодіють з вашим API, буде значно зручніше. 😎\n\n///\n\nУсі поля в `HeroPublic` такі самі, як у `HeroBase`, з `id`, оголошеним як `int` (не `None`):\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` - «модель даних» для створення героя { #herocreate-the-data-model-to-create-a-hero }\n\nТепер створимо модель `HeroCreate` - вона **валідуватиме** дані, отримані від клієнтів.\n\nВона має ті ж поля, що й `HeroBase`, а також `secret_name`.\n\nТепер, коли клієнти **створюють нового героя**, вони надсилають `secret_name`, він зберігається в базі даних, але ці секретні імена не повертаються клієнтам у API.\n\n/// tip | Порада\n\nТак слід поводитися з **паролями**. Приймайте їх, але не повертайте в API.\n\nТакож потрібно **хешувати** значення паролів перед збереженням, **ніколи не зберігайте їх у відкритому вигляді**.\n\n///\n\nПоля `HeroCreate`:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` - «модель даних» для оновлення героя { #heroupdate-the-data-model-to-update-a-hero }\n\nУ попередній версії у нас не було способу **оновлювати героя**, але тепер, маючи **кілька моделей**, ми можемо це зробити. 🎉\n\n«Модель даних» `HeroUpdate` дещо особлива: вона має **всі ті самі поля**, що й для створення нового героя, але всі поля **необов’язкові** (усі мають значення за замовчуванням). Таким чином, під час оновлення героя ви можете надіслати лише ті поля, які хочете змінити.\n\nОскільки **поля фактично змінюються** (тип тепер включає `None` і значення за замовчуванням - `None`), нам потрібно **оголосити їх заново**.\n\nНасправді немає потреби успадковуватися від `HeroBase`, бо ми перевизначаємо всі поля. Я залишу успадкування для послідовності, але це не обов’язково. Це радше питання смаку. 🤷\n\nПоля `HeroUpdate`:\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### Створення з `HeroCreate` і повернення `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }\n\nТепер, коли в нас **кілька моделей**, ми можемо оновити частини застосунку, що їх використовують.\n\nУ запиті ми отримуємо «модель даних» `HeroCreate`, і з неї створюємо «табличну модель» `Hero`.\n\nЦя нова «таблична модель» `Hero` міститиме поля, надіслані клієнтом, а також матиме `id`, згенерований базою даних.\n\nДалі ми повертаємо з функції цю ж «табличну модель» `Hero`. Але оскільки ми оголошуємо `response_model` як «модель даних» `HeroPublic`, **FastAPI** використає `HeroPublic` для валідації та серіалізації даних.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | Порада\n\nТепер ми використовуємо `response_model=HeroPublic` замість **анотації типу, що повертається** `-> HeroPublic`, тому що значення, яке ми повертаємо, насправді - не `HeroPublic`.\n\nЯкби ми оголосили `-> HeroPublic`, ваш редактор і лінтер справедливо зауважили б, що ви повертаєте `Hero`, а не `HeroPublic`.\n\nОголошуючи це в `response_model`, ми кажемо **FastAPI** зробити свою справу, не втручаючись в анотації типів та підказки від вашого редактора й інших інструментів.\n\n///\n\n### Читання героїв з `HeroPublic` { #read-heroes-with-heropublic }\n\nМожемо зробити те саме, що й раніше, щоб **читати** `Hero`, знову використовуємо `response_model=list[HeroPublic]`, щоб гарантувати коректну валідацію та серіалізацію даних.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### Читання одного героя з `HeroPublic` { #read-one-hero-with-heropublic }\n\nМи можемо **прочитати** одного героя:\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### Оновлення героя з `HeroUpdate` { #update-a-hero-with-heroupdate }\n\nМи можемо **оновити героя**. Для цього використовуємо HTTP-операцію `PATCH`.\n\nУ коді ми отримуємо `dict` з усіма даними, які надіслав клієнт, - лише з тими даними, які надіслав клієнт, виключаючи будь-які значення, присутні лише як значення за замовчуванням. Для цього використовуємо `exclude_unset=True`. Це головний трюк. 🪄\n\nПотім використовуємо `hero_db.sqlmodel_update(hero_data)`, щоб оновити `hero_db` даними з `hero_data`.\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### Знову видалення героя { #delete-a-hero-again }\n\n**Видалення** героя майже не змінилося.\n\nМи не задовольнимо бажання відрефакторити все в цьому місці. 😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### Знову запустіть застосунок { #run-the-app-again }\n\nВи можете знову запустити застосунок:\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\nЯкщо ви перейдете до UI `/docs`, побачите, що він оновився і більше не очікуватиме отримати `id` від клієнта під час створення героя тощо.\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## Підсумок { #recap }\n\nВи можете використовувати [**SQLModel**](https://sqlmodel.tiangolo.com/) для взаємодії з SQL базою даних і спростити код за допомогою «моделей даних» та «табличних моделей».\n\nБагато чого ще можна дізнатися в документації **SQLModel**, там є розширений міні-[навчальний посібник з використання SQLModel з **FastAPI**](https://sqlmodel.tiangolo.com/tutorial/fastapi/). 🚀\n"
  },
  {
    "path": "docs/uk/docs/tutorial/static-files.md",
    "content": "# Статичні файли { #static-files }\n\nВи можете автоматично надавати статичні файли з каталогу, використовуючи `StaticFiles`.\n\n## Використання `StaticFiles` { #use-staticfiles }\n\n* Імпортуйте `StaticFiles`.\n* «Під'єднати» екземпляр `StaticFiles()` з вказанням необхідного шляху.\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | Технічні деталі\n\nВи також можете використовувати `from starlette.staticfiles import StaticFiles`.\n\n**FastAPI** надає той самий `starlette.staticfiles`, що й `fastapi.staticfiles` для зручності розробників. Але фактично він безпосередньо походить із Starlette.\n\n///\n\n### Що таке «Під'єднання» { #what-is-mounting }\n\n«Під'єднання» означає додавання повноцінного «незалежного» застосунку за певним шляхом, який потім обробляє всі під шляхи.\n\nЦе відрізняється від використання `APIRouter`, оскільки під'єднаний застосунок є повністю незалежним. OpenAPI та документація вашого основного застосунку не будуть знати нічого про ваш під'єднаний застосунок тощо.\n\nВи можете дізнатися більше про це в [Посібнику для просунутих користувачів](../advanced/index.md).\n\n## Деталі { #details }\n\nПерше `\"/static\"` вказує на під шлях, за яким буде «під'єднано» цей новий «підзастосунок». Тому будь-який шлях, який починається з `\"/static\"`, буде оброблятися ним.\n\n`directory=\"static\"` визначає назву каталогу, що містить ваші статичні файли.\n\n`name=\"static\"` це ім'я, яке можна використовувати всередині **FastAPI**.\n\nУсі ці параметри можуть бути іншими за \"`static`\", налаштуйте їх відповідно до потреб і особливостей вашого застосунку.\n\n## Додаткова інформація { #more-info }\n\nДетальніше про налаштування та можливості можна дізнатися в [документації Starlette про статичні файли](https://www.starlette.dev/staticfiles/).\n"
  },
  {
    "path": "docs/uk/docs/tutorial/stream-json-lines.md",
    "content": "# Стрімінг JSON Lines { #stream-json-lines }\n\nУ вас може бути послідовність даних, яку ви хочете надсилати у **«потоці»**, це можна зробити за допомогою **JSON Lines**.\n\n/// info | Інформація\n\nДодано в FastAPI 0.134.0.\n\n///\n\n## Що таке потік { #what-is-a-stream }\n\n«**Стрімінг**» даних означає, що ваш застосунок почне надсилати елементи даних клієнту, не чекаючи, доки буде готова вся послідовність елементів.\n\nТобто він надішле перший елемент, клієнт його отримає і почне обробляти, а ви в цей час уже можете створювати наступний елемент.\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\nЦе може бути навіть нескінченний потік, у якому ви постійно надсилаєте дані.\n\n## JSON Lines { #json-lines }\n\nУ таких випадках часто надсилають «**JSON Lines**» - формат, у якому ви надсилаєте по одному об’єкту JSON на рядок.\n\nВідповідь матиме тип вмісту `application/jsonl` (замість `application/json`), а тіло буде приблизно таким:\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\nЦе дуже схоже на масив JSON (еквівалент списку Python), але замість того, щоб бути загорнутим у `[]` і мати `,` між елементами, тут є **по одному об’єкту JSON на рядок**, вони розділені символом нового рядка.\n\n/// info | Інформація\n\nВажливо те, що ваш застосунок зможе по черзі створювати кожен рядок, поки клієнт споживає попередні рядки.\n\n///\n\n/// note | Технічні деталі\n\nОскільки кожен об’єкт JSON буде розділено новим рядком, він не може містити буквальні символи нового рядка у своєму вмісті, але може містити екрановані нові рядки (`\\n`), що є частиною стандарту JSON.\n\nЗазвичай про це не треба турбуватися, усе робиться автоматично, читайте далі. 🤓\n\n///\n\n## Випадки використання { #use-cases }\n\nВи можете використовувати це, щоб стрімити дані зі служби **AI LLM**, із **логів** чи **телеметрії**, або з інших типів даних, які можна структурувати як елементи **JSON**.\n\n/// tip | Порада\n\nЯкщо ви хочете стрімити бінарні дані, наприклад відео чи аудіо, перегляньте просунутий посібник: [Потокова передача даних](../advanced/stream-data.md).\n\n///\n\n## Стрімінг JSON Lines з FastAPI { #stream-json-lines-with-fastapi }\n\nЩоб стрімити JSON Lines з FastAPI, замість використання `return` у вашій *функції операції шляху* використовуйте `yield`, щоб по черзі створювати кожен елемент.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\nЯкщо кожен елемент JSON, який ви хочете надіслати у відповідь, має тип `Item` (модель Pydantic) і це async-функція, ви можете оголосити тип повернення як `AsyncIterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\nЯкщо ви оголосите тип повернення, FastAPI використає його, щоб **перевіряти** дані, **документувати** їх в OpenAPI, **фільтрувати** їх і **серіалізувати** за допомогою Pydantic.\n\n/// tip | Порада\n\nОскільки Pydantic серіалізуватиме це на боці **Rust**, ви отримаєте значно вищу **продуктивність**, ніж якби не оголошували тип повернення.\n\n///\n\n### Не-async *функції операцій шляху* { #non-async-path-operation-functions }\n\nВи також можете використовувати звичайні функції `def` (без `async`) і використовувати `yield` так само.\n\nFastAPI подбає про коректне виконання, щоб це не блокувало цикл подій.\n\nОскільки в цьому випадку функція не є async, правильним типом повернення буде `Iterable[Item]`:\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### Без типу повернення { #no-return-type }\n\nВи також можете опустити тип повернення. Тоді FastAPI використає [`jsonable_encoder`](./encoder.md), щоб перетворити дані на щось, що можна серіалізувати в JSON, і потім надішле їх як JSON Lines.\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## Події, надіслані сервером (SSE) { #server-sent-events-sse }\n\nFastAPI також має повноцінну підтримку Server-Sent Events (SSE), які досить схожі, але мають кілька додаткових деталей. Ви можете дізнатися про них у наступному розділі: [Події, надіслані сервером (SSE)](server-sent-events.md). 🤓\n"
  },
  {
    "path": "docs/uk/docs/tutorial/testing.md",
    "content": "# Тестування { #testing }\n\nЗавдяки [Starlette](https://www.starlette.dev/testclient/), тестувати застосунки **FastAPI** просто й приємно.\n\nВоно базується на [HTTPX](https://www.python-httpx.org), який, своєю чергою, спроєктований на основі Requests, тож він дуже знайомий та інтуїтивно зрозумілий.\n\nЗ його допомогою ви можете використовувати [pytest](https://docs.pytest.org/) безпосередньо з **FastAPI**.\n\n## Використання `TestClient` { #using-testclient }\n\n/// info | Інформація\n\nЩоб використовувати `TestClient`, спочатку встановіть [`httpx`](https://www.python-httpx.org).\n\nПереконайтеся, що ви створили [віртуальне середовище](../virtual-environments.md), активували його, а потім встановили `httpx`, наприклад:\n\n```console\n$ pip install httpx\n```\n\n///\n\nІмпортуйте `TestClient`.\n\nСтворіть `TestClient`, передавши йому ваш застосунок **FastAPI**.\n\nСтворюйте функції з іменами, що починаються з `test_` (це стандартна угода для `pytest`).\n\nВикористовуйте об'єкт `TestClient` так само як і `httpx`.\n\nЗаписуйте прості `assert`-вирази зі стандартними виразами Python, які потрібно перевірити (це також стандарт для `pytest`).\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip | Порада\n\nЗверніть увагу, що тестові функції — це звичайні `def`, а не `async def`.\n\nВиклики клієнта також звичайні, без використання `await`.\n\nЦе дозволяє використовувати `pytest` без зайвих ускладнень.\n\n///\n\n/// note | Технічні деталі\n\nВи також можете використовувати `from starlette.testclient import TestClient`.\n\n**FastAPI** надає той самий `starlette.testclient` під назвою `fastapi.testclient` просто для зручності для вас, розробника. Але він безпосередньо походить із Starlette.\n\n///\n\n/// tip | Порада\n\nЯкщо ви хочете викликати `async`-функції у ваших тестах, окрім відправлення запитів до вашого застосунку FastAPI (наприклад, асинхронні функції роботи з базою даних), перегляньте [Async Tests](../advanced/async-tests.md) у розширеному керівництві.\n\n///\n\n## Розділення тестів { #separating-tests }\n\nУ реальному застосунку ваші тести, ймовірно, будуть в окремому файлі.\n\nТакож ваш застосунок **FastAPI** може складатися з кількох файлів/модулів тощо.\n\n### Файл застосунку **FastAPI** { #fastapi-app-file }\n\nПрипустимо, у вас є структура файлів, описана в розділі [Bigger Applications](bigger-applications.md):\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\nУ файлі `main.py` знаходиться ваш застосунок **FastAPI**:\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### Файл тестування { #testing-file }\n\nВи можете створити файл `test_main.py` з вашими тестами. Він може знаходитися в тому ж пакеті Python (у тій самій директорії з файлом `__init__.py`):\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nОскільки цей файл знаходиться в тому ж пакеті, ви можете використовувати відносний імпорт, щоб імпортувати об'єкт `app` із модуля `main` (`main.py`):\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n\n...і написати код для тестів так само як і раніше.\n\n## Тестування: розширений приклад { #testing-extended-example }\n\nТепер розширимо цей приклад і додамо більше деталей, щоб побачити, як тестувати різні частини.\n\n### Розширений файл застосунку **FastAPI** { #extended-fastapi-app-file }\n\nЗалишимо ту саму структуру файлів:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\nПрипустимо, що тепер файл `main.py` із вашим застосунком **FastAPI** містить інші **операції шляху**.\n\nВін має `GET`-операцію, яка може повертати помилку.\n\nВін має `POST`-операцію, яка може повертати кілька помилок.\n\nОбидві *операції шляху* вимагають заголовок `X-Token`.\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### Розширений тестовий файл { #extended-testing-file }\n\nПотім ви можете оновити `test_main.py`, додавши розширені тести:\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\n\nКоли вам потрібно передати клієнту інформацію в запиті, але ви не знаєте, як це зробити, ви можете пошукати (Google), як це зробити в `httpx`, або навіть як це зробити з `requests`, оскільки дизайн HTTPX базується на дизайні Requests.\n\nДалі ви просто повторюєте ці ж дії у ваших тестах.\n\nНаприклад:\n\n* Щоб передати *path* або *query* параметр, додайте його безпосередньо до URL.\n* Щоб передати тіло JSON, передайте Python-об'єкт (наприклад, `dict`) у параметр `json`.\n* Якщо потрібно надіслати *Form Data* замість JSON, використовуйте параметр `data`.\n* Щоб передати заголовки *headers*, використовуйте `dict` у параметрі `headers`.\n* Для *cookies* використовуйте `dict` у параметрі `cookies`.\n\nДокладніше про передачу даних у бекенд (за допомогою `httpx` або `TestClient`) можна знайти в [документації HTTPX](https://www.python-httpx.org).\n\n/// info | Інформація\n\nЗверніть увагу, що `TestClient` отримує дані, які можна конвертувати в JSON, а не Pydantic-моделі.\n\nЯкщо у вас є Pydantic-модель у тесті, і ви хочете передати її дані в застосунок під час тестування, ви можете використати `jsonable_encoder`, описаний у розділі [JSON Compatible Encoder](encoder.md).\n\n///\n\n## Запуск { #run-it }\n\nПісля цього вам потрібно встановити `pytest`.\n\nПереконайтеся, що ви створили [віртуальне середовище](../virtual-environments.md), активували його і встановили необхідні пакети, наприклад:\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\nВін автоматично знайде файли та тести, виконає їх і повідомить вам результати.\n\nЗапустіть тести за допомогою:\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/uk/docs/virtual-environments.md",
    "content": "# Віртуальні середовища { #virtual-environments }\n\nКоли ви працюєте над проєктами Python, вам, імовірно, слід використовувати віртуальне середовище (або схожий механізм), щоб ізолювати пакети, які ви встановлюєте для кожного проєкту.\n\n/// info | Інформація\n\nЯкщо ви вже знаєте про віртуальні середовища, як їх створювати та використовувати, можете пропустити цей розділ. 🤓\n\n///\n\n/// tip | Порада\n\nВіртуальне середовище відрізняється від змінної оточення.\n\nЗмінна оточення - це змінна в системі, яку можуть використовувати програми.\n\nВіртуальне середовище - це каталог із файлами в ньому.\n\n///\n\n/// info | Інформація\n\nНа цій сторінці ви дізнаєтеся, як використовувати віртуальні середовища і як вони працюють.\n\nЯкщо ви готові прийняти інструмент, що керує всім за вас (включно з установленням Python), спробуйте [uv](https://github.com/astral-sh/uv).\n\n///\n\n## Створіть проєкт { #create-a-project }\n\nСпочатку створіть каталог для вашого проєкту.\n\nЗазвичай я створюю каталог з назвою `code` у моєму домашньому каталозі користувача.\n\nІ всередині нього я створюю окремий каталог на кожен проєкт.\n\n<div class=\"termy\">\n\n```console\n// Перейдіть до домашнього каталогу\n$ cd\n// Створіть каталог для всіх ваших проєктів з кодом\n$ mkdir code\n// Перейдіть у цей каталог code\n$ cd code\n// Створіть каталог для цього проєкту\n$ mkdir awesome-project\n// Перейдіть до каталогу цього проєкту\n$ cd awesome-project\n```\n\n</div>\n\n## Створіть віртуальне середовище { #create-a-virtual-environment }\n\nКоли ви починаєте працювати над проєктом Python уперше, створіть віртуальне середовище у вашому проєкті **<dfn title=\"є інші варіанти, це проста настанова\">у вашому проєкті</dfn>**.\n\n/// tip | Порада\n\nЦе потрібно робити лише один раз на проєкт, не щоразу, коли ви працюєте.\n\n///\n\n//// tab | `venv`\n\nЩоб створити віртуальне середовище, ви можете використати модуль `venv`, який постачається разом із Python.\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | Що означає ця команда\n\n* `python`: використати програму з назвою `python`\n* `-m`: викликати модуль як скрипт, далі ми вкажемо, який модуль\n* `venv`: використати модуль з назвою `venv`, який зазвичай уже встановлено з Python\n* `.venv`: створити віртуальне середовище в новому каталозі `.venv`\n\n///\n\n////\n\n//// tab | `uv`\n\nЯкщо у вас встановлено [`uv`](https://github.com/astral-sh/uv), ви можете використати його для створення віртуального середовища.\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip | Порада\n\nТипово `uv` створить віртуальне середовище в каталозі з назвою `.venv`.\n\nАле ви можете налаштувати це, передавши додатковий аргумент з назвою каталогу.\n\n///\n\n////\n\nЦя команда створює нове віртуальне середовище в каталозі з назвою `.venv`.\n\n/// details | `.venv` або інша назва\n\nВи можете створити віртуальне середовище в іншому каталозі, але існує усталена домовленість називати його `.venv`.\n\n///\n\n## Активуйте віртуальне середовище { #activate-the-virtual-environment }\n\nАктивуйте нове віртуальне середовище, щоб будь-яка команда Python, яку ви запускаєте, або пакет, який ви встановлюєте, використовували його.\n\n/// tip | Порада\n\nРобіть це щоразу, коли ви починаєте нову сесію термінала для роботи над проєктом.\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nАбо якщо ви використовуєте Bash для Windows (напр., [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip | Порада\n\nКожного разу, коли ви встановлюєте новий пакет у це середовище, активуйте середовище знову.\n\nЦе гарантує, що якщо ви використовуєте програму термінала (<abbr title=\"command line interface - інтерфейс командного рядка\">CLI</abbr>), встановлену цим пакетом, ви використовуєте саме ту з вашого віртуального середовища, а не будь-яку іншу, яка може бути встановлена глобально, імовірно з іншою версією, ніж вам потрібно.\n\n///\n\n## Перевірте активність віртуального середовища { #check-the-virtual-environment-is-active }\n\nПеревірте, що віртуальне середовище активне (попередня команда спрацювала).\n\n/// tip | Порада\n\nЦе необов'язково, але це гарний спосіб перевірити, що все працює як очікується і ви використовуєте саме те віртуальне середовище, яке планували.\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\nЯкщо показано бінарний файл `python` за шляхом `.venv/bin/python` усередині вашого проєкту (у цьому випадку `awesome-project`), тоді все спрацювало. 🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\nЯкщо показано бінарний файл `python` за шляхом `.venv\\Scripts\\python` усередині вашого проєкту (у цьому випадку `awesome-project`), тоді все спрацювало. 🎉\n\n////\n\n## Оновіть `pip` { #upgrade-pip }\n\n/// tip | Порада\n\nЯкщо ви використовуєте [`uv`](https://github.com/astral-sh/uv), ви використовуватимете його для встановлення замість `pip`, тож вам не потрібно оновлювати `pip`. 😎\n\n///\n\nЯкщо ви використовуєте `pip` для встановлення пакетів (він іде за замовчуванням із Python), вам слід оновити його до найновішої версії.\n\nБагато дивних помилок під час встановлення пакета вирішуються тим, що спочатку оновлюють `pip`.\n\n/// tip | Порада\n\nЗазвичай це роблять один раз, відразу після створення віртуального середовища.\n\n///\n\nПереконайтеся, що віртуальне середовище активне (командою вище), а потім виконайте:\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip | Порада\n\nІноді ви можете отримати помилку **`No module named pip`** при спробі оновити pip.\n\nЯкщо це сталося, встановіть і оновіть pip за допомогою команди нижче:\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\nЦя команда встановить pip, якщо він ще не встановлений, і також гарантує, що встановлена версія pip принаймні така ж нова, як доступна в `ensurepip`.\n\n///\n\n## Додайте `.gitignore` { #add-gitignore }\n\nЯкщо ви використовуєте Git (варто це робити), додайте файл `.gitignore`, щоб виключити з Git усе у вашому `.venv`.\n\n/// tip | Порада\n\nЯкщо ви використали [`uv`](https://github.com/astral-sh/uv) для створення віртуального середовища, він уже зробив це за вас, можете пропустити цей крок. 😎\n\n///\n\n/// tip | Порада\n\nЗробіть це один раз, відразу після створення віртуального середовища.\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | Що означає ця команда\n\n* `echo \"*\"`: «виведе» текст `*` у термінал (наступна частина трохи це змінює)\n* `>`: усе, що команда ліворуч від `>` «виводить» у термінал, не слід друкувати, натомість записати у файл, вказаний праворуч від `>`\n* `.gitignore`: назва файлу, куди слід записати текст\n\nА `*` для Git означає «все». Тож він ігноруватиме все в каталозі `.venv`.\n\nЦя команда створить файл `.gitignore` із вмістом:\n\n```gitignore\n*\n```\n\n///\n\n## Встановіть пакети { #install-packages }\n\nПісля активації середовища ви можете встановлювати в нього пакети.\n\n/// tip | Порада\n\nРобіть це один раз під час встановлення або оновлення пакетів, потрібних вашому проєкту.\n\nЯкщо вам потрібно оновити версію або додати новий пакет, ви зробите це знову.\n\n///\n\n### Встановіть пакети безпосередньо { #install-packages-directly }\n\nЯкщо ви поспішаєте та не хочете використовувати файл для оголошення вимог вашого проєкту до пакетів, ви можете встановити їх безпосередньо.\n\n/// tip | Порада\n\nДуже добра ідея - записати пакети та версії, потрібні вашій програмі, у файл (наприклад, `requirements.txt` або `pyproject.toml`).\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nЯкщо у вас є [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### Встановіть з `requirements.txt` { #install-from-requirements-txt }\n\nЯкщо у вас є `requirements.txt`, ви можете використати його для встановлення перелічених там пакетів.\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\nЯкщо у вас є [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | `requirements.txt`\n\n`requirements.txt` із деякими пакетами може виглядати так:\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## Запустіть вашу програму { #run-your-program }\n\nПісля активації віртуального середовища ви можете запустити вашу програму, і вона використовуватиме Python із вашого віртуального середовища з пакетами, які ви там встановили.\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## Налаштуйте ваш редактор { #configure-your-editor }\n\nЙмовірно, ви використовуєте редактор коду, переконайтеся, що ви налаштували його на використання того самого віртуального середовища, яке ви створили (швидше за все, він визначить його автоматично), щоб отримувати автодоповнення та підсвічування помилок.\n\nНаприклад:\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip | Порада\n\nЗазвичай це потрібно робити лише один раз, коли ви створюєте віртуальне середовище.\n\n///\n\n## Деактивуйте віртуальне середовище { #deactivate-the-virtual-environment }\n\nКоли ви завершили роботу над проєктом, ви можете деактивувати віртуальне середовище.\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\nТаким чином, коли ви запустите `python`, він не намагатиметься запускатися з того віртуального середовища з установленими там пакетами.\n\n## Готові до роботи { #ready-to-work }\n\nТепер ви готові почати працювати над вашим проєктом.\n\n/// tip | Порада\n\nХочете зрозуміти, що це все було вище?\n\nПродовжуйте читати. 👇🤓\n\n///\n\n## Навіщо віртуальні середовища { #why-virtual-environments }\n\nЩоб працювати з FastAPI, вам потрібно встановити [Python](https://www.python.org/).\n\nПісля цього вам потрібно буде встановити FastAPI та інші пакети, які ви хочете використовувати.\n\nДля встановлення пакетів зазвичай використовують команду `pip`, що постачається з Python (або схожі альтернативи).\n\nОднак, якщо ви просто користуватиметеся `pip` напряму, пакети встановлюватимуться у ваше глобальне середовище Python (глобальну інсталяцію Python).\n\n### Проблема { #the-problem }\n\nТо в чому ж проблема встановлення пакетів у глобальне середовище Python?\n\nЗ часом ви, вірогідно, писатимете багато різних програм, які залежать від різних пакетів. І деякі з цих ваших проєктів залежатимуть від різних версій одного й того ж пакета. 😱\n\nНаприклад, ви можете створити проєкт із назвою `philosophers-stone`, ця програма залежить від іншого пакета з назвою `harry`, використовуючи версію `1`. Тож вам потрібно встановити `harry`.\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n\nПотім, трохи згодом, ви створюєте інший проєкт із назвою `prisoner-of-azkaban`, і цей проєкт також залежить від `harry`, але йому потрібна версія `harry` `3`.\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3]\n```\n\nАле тепер проблема в тому, що якщо ви встановлюєте пакети глобально (у глобальне середовище), а не у локальне віртуальне середовище, вам доведеться вибирати, яку версію `harry` встановити.\n\nЯкщо ви хочете запустити `philosophers-stone`, вам спочатку потрібно встановити `harry` версії `1`, наприклад, так:\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\nУ підсумку у вас буде встановлено `harry` версії `1` у глобальному середовищі Python.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\nАле якщо ви захочете запустити `prisoner-of-azkaban`, вам доведеться видалити `harry` версії `1` і встановити `harry` версії `3` (або просто встановлення версії `3` автоматично видалить версію `1`).\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\nУ підсумку у вас буде встановлено `harry` версії `3` у глобальному середовищі Python.\n\nА якщо ви знову спробуєте запустити `philosophers-stone`, є шанс, що він не працюватиме, тому що йому потрібен `harry` версії `1`.\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --> |requires| harry-3\n    end\n```\n\n/// tip | Порада\n\nУ пакетах Python дуже поширена практика намагатися якнайкраще уникати несумісних змін у нових версіях, але краще підстрахуватися та встановлювати новіші версії свідомо і тоді, коли ви можете запустити тести, щоб перевірити, що все працює коректно.\n\n///\n\nТепер уявіть те саме з багатьма іншими пакетами, від яких залежать усі ваші проєкти. Це дуже складно керувати. І ви, імовірно, запускатимете деякі проєкти з деякими несумісними версіями пакетів і не розумітимете, чому щось не працює.\n\nТакож, залежно від вашої операційної системи (напр., Linux, Windows, macOS), у ній може бути вже встановлений Python. І в такому разі, імовірно, уже будуть попередньо встановлені деякі пакети з певними версіями, потрібними вашій системі. Якщо ви встановлюєте пакети в глобальне середовище Python, ви можете зламати деякі програми, що постачаються з вашою операційною системою.\n\n## Де встановлюються пакети { #where-are-packages-installed }\n\nКоли ви встановлюєте Python, він створює на вашому комп'ютері кілька каталогів із деякими файлами.\n\nДеякі з цих каталогів відповідають за зберігання всіх пакетів, які ви встановлюєте.\n\nКоли ви запускаєте:\n\n<div class=\"termy\">\n\n```console\n// Не запускайте це зараз, це лише приклад 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\nЦе завантажить стиснений файл з кодом FastAPI, зазвичай із [PyPI](https://pypi.org/project/fastapi/).\n\nТакож будуть завантажені файли для інших пакетів, від яких залежить FastAPI.\n\nПотім усе це буде розпаковано та покладено в каталог на вашому комп'ютері.\n\nТипово ці завантажені та розпаковані файли будуть покладені в каталог, що постачається з вашою інсталяцією Python, це глобальне середовище.\n\n## Що таке віртуальні середовища { #what-are-virtual-environments }\n\nРішенням проблеми з наявністю всіх пакетів у глобальному середовищі є використання віртуального середовища для кожного проєкту, над яким ви працюєте.\n\nВіртуальне середовище - це каталог, дуже схожий на глобальний, у якому ви можете встановлювати пакети для конкретного проєкту.\n\nТаким чином кожен проєкт матиме власне віртуальне середовище (каталог `.venv`) із власними пакетами.\n\n```mermaid\nflowchart TB\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) --->|requires| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[prisoner-of-azkaban project]\n        azkaban(prisoner-of-azkaban) --->|requires| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## Що означає активація віртуального середовища { #what-does-activating-a-virtual-environment-mean }\n\nКоли ви активуєте віртуальне середовище, наприклад так:\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\nАбо якщо ви використовуєте Bash для Windows (напр., [Git Bash](https://gitforwindows.org/)):\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\nЦя команда створить або змінить деякі [Змінні оточення](environment-variables.md), які будуть доступні для наступних команд.\n\nОднією з цих змінних є змінна `PATH`.\n\n/// tip | Порада\n\nВи можете дізнатися більше про змінну оточення `PATH` у розділі [Змінні оточення](environment-variables.md#path-environment-variable).\n\n///\n\nАктивація віртуального середовища додає його шлях `.venv/bin` (на Linux і macOS) або `.venv\\Scripts` (на Windows) до змінної оточення `PATH`.\n\nСкажімо, до активації середовища змінна `PATH` виглядала так:\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nЦе означає, що система шукатиме програми в:\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\nЦе означає, що система шукатиме програми в:\n\n* `C:\\Windows\\System32`\n\n////\n\nПісля активації віртуального середовища змінна `PATH` виглядатиме приблизно так:\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nЦе означає, що система тепер спочатку шукатиме програми в:\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\nперед тим, як шукати в інших каталогах.\n\nТож коли ви введете `python` у терміналі, система знайде програму Python у\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\nі використає саме її.\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\nЦе означає, що система тепер спочатку шукатиме програми в:\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\nперед тим, як шукати в інших каталогах.\n\nТож коли ви введете `python` у терміналі, система знайде програму Python у\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\nі використає саме її.\n\n////\n\nВажлива деталь: шлях до віртуального середовища буде додано на початок змінної `PATH`. Система знайде його раніше за будь-який інший доступний Python. Таким чином, коли ви запускаєте `python`, використовується саме Python із віртуального середовища, а не будь-який інший `python` (наприклад, з глобального середовища).\n\nАктивація віртуального середовища також змінює ще кілька речей, але це одна з найважливіших.\n\n## Перевірка віртуального середовища { #checking-a-virtual-environment }\n\nКоли ви перевіряєте, чи активне віртуальне середовище, наприклад так:\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\nЦе означає, що програма `python`, яка буде використана, знаходиться у віртуальному середовищі.\n\nНа Linux і macOS використовують `which`, а в Windows PowerShell - `Get-Command`.\n\nПринцип роботи цієї команди в тому, що вона перевіряє змінну оточення `PATH`, проходячи по кожному шляху по порядку, шукаючи програму з назвою `python`. Щойно вона її знайде, вона покаже вам шлях до цієї програми.\n\nНайважливіше, що коли ви викликаєте `python`, це рівно той «`python`», який буде виконаний.\n\nОтже, ви можете підтвердити, чи перебуваєте в правильному віртуальному середовищі.\n\n/// tip | Порада\n\nЛегко активувати одне віртуальне середовище, отримати один Python, а потім перейти до іншого проєкту.\n\nІ другий проєкт не працюватиме, бо ви використовуєте некоректний Python з віртуального середовища іншого проєкту.\n\nКорисно вміти перевіряти, який саме `python` використовується. 🤓\n\n///\n\n## Навіщо деактивувати віртуальне середовище { #why-deactivate-a-virtual-environment }\n\nНаприклад, ви працюєте над проєктом `philosophers-stone`, активували його віртуальне середовище, встановили пакети та працюєте з цим середовищем.\n\nА потім ви хочете працювати над іншим проєктом `prisoner-of-azkaban`.\n\nВи переходите до цього проєкту:\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\nЯкщо ви не деактивуєте віртуальне середовище для `philosophers-stone`, коли ви запустите `python` у терміналі, він спробує використовувати Python із `philosophers-stone`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// Помилка імпорту sirius, його не встановлено 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\nАле якщо ви деактивуєте віртуальне середовище і активуєте нове для `prisoner-of-askaban`, тоді при запуску `python` він використовуватиме Python із віртуального середовища в `prisoner-of-azkaban`.\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// Вам не потрібно бути в старому каталозі, щоб деактивувати, це можна зробити будь-де, навіть після переходу до іншого проєкту 😎\n$ deactivate\n\n// Активуйте віртуальне середовище в prisoner-of-azkaban/.venv 🚀\n$ source .venv/bin/activate\n\n// Тепер, коли ви запускаєте python, він знайде пакет sirius, встановлений у цьому віртуальному середовищі ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## Альтернативи { #alternatives }\n\nЦе простий посібник, щоб ви швидко стартували та зрозуміли, як усе працює «під капотом».\n\nІснує багато альтернатив керування віртуальними середовищами, залежностями пакетів (вимогами), проєктами.\n\nКоли будете готові й захочете використовувати інструмент для керування всім проєктом, залежностями пакетів, віртуальними середовищами тощо, я раджу спробувати [uv](https://github.com/astral-sh/uv).\n\n`uv` уміє багато чого, зокрема:\n\n* Встановлювати Python для вас, включно з різними версіями\n* Керувати віртуальним середовищем ваших проєктів\n* Встановлювати пакети\n* Керувати залежностями пакетів і версіями у вашому проєкті\n* Гарантувати, що у вас є точний набір пакетів і версій для встановлення, включно з їхніми залежностями, щоб ви були певні, що зможете запустити ваш проєкт у продакшені точно так само, як і на вашому комп'ютері під час розробки - це називається блокуванням\n* І багато іншого\n\n## Висновок { #conclusion }\n\nЯкщо ви все це прочитали й зрозуміли, тепер ви знаєте значно більше про віртуальні середовища, ніж багато розробників. 🤓\n\nЗнання цих деталей, найімовірніше, стане в пригоді в майбутньому, коли ви налагоджуватимете щось, що виглядає складним, але ви знатимете, як усе працює «під капотом». 😎\n"
  },
  {
    "path": "docs/uk/llm-prompt.md",
    "content": "### Target language\n\nTranslate to Ukrainian (українська).\n\nLanguage code: uk.\n\n### Grammar and tone\n\n- Use polite/formal address consistent with existing Ukrainian docs (use “ви/ваш”).\n- Keep the tone concise and technical.\n- Use one style of dashes. For example, if text contains \"-\" then use only this symbol to represent a dash.\n\n### Headings\n\n- Follow existing Ukrainian heading style; keep headings short and instructional.\n- Do not add trailing punctuation to headings.\n\n### Quotes\n\n- Prefer Ukrainian guillemets «…» for quoted terms in prose, matching existing Ukrainian docs.\n- Never change quotes inside inline code, code blocks, URLs, or file paths.\n\n### Ellipsis\n\n- Keep ellipsis style consistent with existing Ukrainian docs.\n- Never change `...` in code, URLs, or CLI examples.\n\n### Preferred translations / glossary\n\nUse the following preferred translations when they apply in documentation prose:\n\n- request (HTTP): запит\n- response (HTTP): відповідь\n- path operation: операція шляху\n- path operation function: функція операції шляху\n- prompt: підсказка\n- check: перевірка\n- Parallel Server Gateway Interface: Інтерфейс Шлюзу Паралельного Сервера\n- Mozilla Developer Network: Мережа Розробників Mozilla\n- tutorial: навчальний посібник\n- advanced user guide: просунутий посібник користувача\n- deep learning: глибоке навчання\n- machine learning: машинне навчання\n- dependency injection: впровадження залежностей\n- digest (HTTP): дайджест\n- basic authentication (HTTP): базова автентифікація\n- JSON schema: Схема JSON\n- password flow: потік паролю\n- mobile: мобільний\n- body: тіло\n- form: форма\n- path: шлях\n- query: запит\n- cookie: кукі\n- header: заголовок\n- startup: запуск\n- shutdown: вимкнення\n- lifespan: тривалість життя\n- authorization: авторизація\n- forwarded header: направлений заголовок\n- dependable: залежний\n- dependent: залежний\n- bound: межа\n- concurrency: рівночасність\n- parallelism: паралелізм\n- multiprocessing: багатопроцесорність\n- env var: змінна оточення\n- dict: словник\n- enum: перелік\n- issue: проблема\n- server worker: серверний працівник\n- worker: працівник\n- software development kit: набір для розробки програмного забезпечення\n- bearer token: токен носія\n- breaking change: несумісна зміна\n- bug: помилка\n- button: кнопка\n- callable: викликаємий\n- code: код\n- commit: фіксація\n- context manager: менеджер контексту\n- coroutine: співпрограма\n- engine: рушій\n- fake X: фальшивий X\n- item: предмет\n- lock: блокування\n- middleware: проміжне програмне забезпечення\n- mounting: монтування\n- origin: джерело\n- override: переписування\n- payload: корисне навантаження\n- processor: процесор\n- property: властивість\n- proxy: представник\n- pull request: запит на витяг\n- random-access memory: пам'ять з довільним доступом\n- status code: код статусу\n- string: строка\n- tag: мітка\n- wildcard: дика карта\n\n### `///` admonitions\n\n- Keep the admonition keyword in English (do not translate `note`, `tip`, etc.).\n- If a title is present, prefer these canonical titles (choose one canonical form where variants exist):\n\n- `/// note | Примітка`\n- `/// note | Технічні деталі`\n- `/// tip | Порада`\n- `/// warning | Попередження`\n- `/// info | Інформація`\n- `/// danger | Обережно`\n- `/// check | Перевірте`\n"
  },
  {
    "path": "docs/uk/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs/zh/docs/_llm-test.md",
    "content": "# LLM 测试文件 { #llm-test-file }\n\n本文用于测试用于翻译文档的 <abbr title=\"Large Language Model - 大型语言模型\">LLM</abbr> 是否理解 `scripts/translate.py` 中的 `general_prompt` 以及 `docs/{language code}/llm-prompt.md` 中的语言特定提示。语言特定提示会追加到 `general_prompt` 之后。\n\n这里添加的测试会被所有语言特定提示的设计者看到。\n\n用法如下：\n\n* 准备语言特定提示——`docs/{language code}/llm-prompt.md`。\n* 将本文重新翻译为你的目标语言（例如使用 `translate.py` 的 `translate-page` 命令）。这会在 `docs/{language code}/docs/_llm-test.md` 下创建翻译。\n* 检查翻译是否正确。\n* 如有需要，改进你的语言特定提示、通用提示，或英文文档。\n* 然后手动修正翻译中剩余的问题，确保这是一个优秀的译文。\n* 重新翻译，在已有的优秀译文基础上进行。理想情况是 LLM 不再对译文做任何更改。这意味着通用提示和你的语言特定提示已经尽可能完善（有时它仍会做一些看似随机的改动，原因是[LLM 不是确定性算法](https://doublespeak.chat/#/handbook#deterministic-output)）。\n\n测试如下：\n\n## 代码片段 { #code-snippets }\n\n//// tab | 测试\n\n这是一个代码片段：`foo`。这是另一个代码片段：`bar`。还有一个：`baz quux`。\n\n////\n\n//// tab | 信息\n\n代码片段的内容应保持不变。\n\n参见 `scripts/translate.py` 中通用提示的 `### Content of code snippets` 部分。\n\n////\n\n## 引号 { #quotes }\n\n//// tab | 测试\n\n昨天，我的朋友写道：\"如果你把 incorrectly 拼对了，你就把它拼错了\"。我回答：\"没错，但 'incorrectly' 错的不是 '\"incorrectly\"'\"。\n\n/// note | 注意\n\nLLM 很可能会把这段翻错。我们只关心在重新翻译时它是否能保持修正后的译文。\n\n///\n\n////\n\n//// tab | 信息\n\n提示词设计者可以选择是否将中性引号转换为排版引号。也可以保持不变。\n\n例如参见 `docs/de/llm-prompt.md` 中的 `### Quotes` 部分。\n\n////\n\n## 代码片段中的引号 { #quotes-in-code-snippets }\n\n//// tab | 测试\n\n`pip install \"foo[bar]\"`\n\n代码片段中的字符串字面量示例：`\"this\"`，`'that'`。\n\n一个较难的字符串字面量示例：`f\"I like {'oranges' if orange else \"apples\"}\"`\n\n硬核：`Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | 信息\n\n... 但是，代码片段内的引号必须保持不变。\n\n////\n\n## 代码块 { #code-blocks }\n\n//// tab | 测试\n\n一个 Bash 代码示例...\n\n```bash\n# 向宇宙打印问候\necho \"Hello universe\"\n```\n\n...以及一个控制台代码示例...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n...以及另一个控制台代码示例...\n\n```console\n// 创建目录 \"code\"\n$ mkdir code\n// 切换到该目录\n$ cd code\n```\n\n...以及一个 Python 代码示例...\n\n```Python\nwont_work()  # 这不会起作用 😱\nworks(foo=\"bar\")  # 这可行 🎉\n```\n\n...就这些。\n\n////\n\n//// tab | 信息\n\n代码块中的代码不应被修改，注释除外。\n\n参见 `scripts/translate.py` 中通用提示的 `### Content of code blocks` 部分。\n\n////\n\n## 选项卡与彩色提示框 { #tabs-and-colored-boxes }\n\n//// tab | 测试\n\n/// info | 信息\nSome text\n///\n\n/// note | 注意\nSome text\n///\n\n/// note | 技术细节\nSome text\n///\n\n/// check | 检查\nSome text\n///\n\n/// tip | 提示\nSome text\n///\n\n/// warning | 警告\nSome text\n///\n\n/// danger | 危险\nSome text\n///\n\n////\n\n//// tab | 信息\n\n选项卡以及 `Info`/`Note`/`Warning`/等提示块，应在竖线（`|`）后添加其标题的翻译。\n\n参见 `scripts/translate.py` 中通用提示的 `### Special blocks` 与 `### Tab blocks` 部分。\n\n////\n\n## Web 与内部链接 { #web-and-internal-links }\n\n//// tab | 测试\n\n链接文本应被翻译，链接地址应保持不变：\n\n* [链接到上面的标题](#code-snippets)\n* [内部链接](index.md#installation)\n* [外部链接](https://sqlmodel.tiangolo.com/)\n* [样式链接](https://fastapi.tiangolo.com/css/styles.css)\n* [脚本链接](https://fastapi.tiangolo.com/js/logic.js)\n* [图片链接](https://fastapi.tiangolo.com/img/foo.jpg)\n\n链接文本应被翻译，且链接地址应指向对应的译文页面：\n\n* [FastAPI 链接](https://fastapi.tiangolo.com/zh/)\n\n////\n\n//// tab | 信息\n\n链接的文本应被翻译，但地址保持不变。唯一的例外是指向 FastAPI 文档页面的绝对链接，此时应指向对应语言的译文。\n\n参见 `scripts/translate.py` 中通用提示的 `### Links` 部分。\n\n////\n\n## HTML \"abbr\" 元素 { #html-abbr-elements }\n\n//// tab | 测试\n\n这里有一些包裹在 HTML \"abbr\" 元素中的内容（有些是虚构的）：\n\n### abbr 提供了完整短语 { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done - 尽管去做\">GTD</abbr>\n* <abbr title=\"less than - 小于\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token - XML Web 令牌\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface - 并行服务器网关接口\">PSGI</abbr>\n\n### abbr 提供了完整短语与解释 { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network - Mozilla 开发者网络: 为开发者编写的文档，由 Firefox 团队撰写\">MDN</abbr>\n* <abbr title=\"Input/Output - 输入/输出: 磁盘读写，网络通信。\">I/O</abbr>.\n\n////\n\n//// tab | 信息\n\n\"abbr\" 元素的 \"title\" 属性需要按照特定规则进行翻译。\n\n译文可以自行添加 \"abbr\" 元素以解释英语单词，LLM 不应删除这些元素。\n\n参见 `scripts/translate.py` 中通用提示的 `### HTML abbr elements` 部分。\n\n////\n\n## HTML \"dfn\" 元素 { #html-dfn-elements }\n\n* <dfn title=\"配置为以某种方式连接并协同工作的机器组\">集群</dfn>\n* <dfn title=\"一种使用具有多个隐藏层的人工神经网络的机器学习方法，从输入层到输出层构建了完整的内部结构\">深度学习</dfn>\n\n## 标题 { #headings }\n\n//// tab | 测试\n\n### 开发 Web 应用——教程 { #develop-a-webapp-a-tutorial }\n\nHello.\n\n### 类型提示与注解 { #type-hints-and-annotations }\n\nHello again.\n\n### 超类与子类 { #super-and-subclasses }\n\nHello again.\n\n////\n\n//// tab | 信息\n\n关于标题的唯一硬性规则是：LLM 必须保持花括号内的哈希部分不变，以确保链接不会失效。\n\n参见 `scripts/translate.py` 中通用提示的 `### Headings` 部分。\n\n语言特定的说明可参见例如 `docs/de/llm-prompt.md` 中的 `### Headings` 部分。\n\n////\n\n## 文档中使用的术语 { #terms-used-in-the-docs }\n\n//// tab | 测试\n\n* you\n* your\n\n* e.g.\n* etc.\n\n* `foo` as an `int`\n* `bar` as a `str`\n* `baz` as a `list`\n\n* the Tutorial - User guide\n* the Advanced User Guide\n* the SQLModel docs\n* the API docs\n* the automatic docs\n\n* Data Science\n* Deep Learning\n* Machine Learning\n* Dependency Injection\n* HTTP Basic authentication\n* HTTP Digest\n* ISO format\n* the JSON Schema standard\n* the JSON schema\n* the schema definition\n* Password Flow\n* Mobile\n\n* deprecated\n* designed\n* invalid\n* on the fly\n* standard\n* default\n* case-sensitive\n* case-insensitive\n\n* to serve the application\n* to serve the page\n\n* the app\n* the application\n\n* the request\n* the response\n* the error response\n\n* the path operation\n* the path operation decorator\n* the path operation function\n\n* the body\n* the request body\n* the response body\n* the JSON body\n* the form body\n* the file body\n* the function body\n\n* the parameter\n* the body parameter\n* the path parameter\n* the query parameter\n* the cookie parameter\n* the header parameter\n* the form parameter\n* the function parameter\n\n* the event\n* the startup event\n* the startup of the server\n* the shutdown event\n* the lifespan event\n\n* the handler\n* the event handler\n* the exception handler\n* to handle\n\n* the model\n* the Pydantic model\n* the data model\n* the database model\n* the form model\n* the model object\n\n* the class\n* the base class\n* the parent class\n* the subclass\n* the child class\n* the sibling class\n* the class method\n\n* the header\n* the headers\n* the authorization header\n* the `Authorization` header\n* the forwarded header\n\n* the dependency injection system\n* the dependency\n* the dependable\n* the dependant\n\n* I/O bound\n* CPU bound\n* concurrency\n* parallelism\n* multiprocessing\n\n* the env var\n* the environment variable\n* the `PATH`\n* the `PATH` variable\n\n* the authentication\n* the authentication provider\n* the authorization\n* the authorization form\n* the authorization provider\n* the user authenticates\n* the system authenticates the user\n\n* the CLI\n* the command line interface\n\n* the server\n* the client\n\n* the cloud provider\n* the cloud service\n\n* the development\n* the development stages\n\n* the dict\n* the dictionary\n* the enumeration\n* the enum\n* the enum member\n\n* the encoder\n* the decoder\n* to encode\n* to decode\n\n* the exception\n* to raise\n\n* the expression\n* the statement\n\n* the frontend\n* the backend\n\n* the GitHub discussion\n* the GitHub issue\n\n* the performance\n* the performance optimization\n\n* the return type\n* the return value\n\n* the security\n* the security scheme\n\n* the task\n* the background task\n* the task function\n\n* the template\n* the template engine\n\n* the type annotation\n* the type hint\n\n* the server worker\n* the Uvicorn worker\n* the Gunicorn Worker\n* the worker process\n* the worker class\n* the workload\n\n* the deployment\n* to deploy\n\n* the SDK\n* the software development kit\n\n* the `APIRouter`\n* the `requirements.txt`\n* the Bearer Token\n* the breaking change\n* the bug\n* the button\n* the callable\n* the code\n* the commit\n* the context manager\n* the coroutine\n* the database session\n* the disk\n* the domain\n* the engine\n* the fake X\n* the HTTP GET method\n* the item\n* the library\n* the lifespan\n* the lock\n* the middleware\n* the mobile application\n* the module\n* the mounting\n* the network\n* the origin\n* the override\n* the payload\n* the processor\n* the property\n* the proxy\n* the pull request\n* the query\n* the RAM\n* the remote machine\n* the status code\n* the string\n* the tag\n* the web framework\n* the wildcard\n* to return\n* to validate\n\n////\n\n//// tab | 信息\n\n这是一份不完整且非规范性的（主要是）技术术语清单，取自文档中常见的词汇。它可能有助于提示词设计者判断哪些术语需要对 LLM 提供额外指引。例如当它总是把一个好的译法改回次优译法，或在你的语言中对某个术语的词形变化有困难时。\n\n参见例如 `docs/de/llm-prompt.md` 中的 `### List of English terms and their preferred German translations` 部分。\n\n////\n"
  },
  {
    "path": "docs/zh/docs/about/index.md",
    "content": "# 关于 { #about }\n\n关于 FastAPI、其设计、灵感等。🤓\n"
  },
  {
    "path": "docs/zh/docs/advanced/additional-responses.md",
    "content": "# OpenAPI 中的附加响应 { #additional-responses-in-openapi }\n\n/// warning | 警告\n\n这是一个相对高级的话题。\n\n如果你刚开始使用 **FastAPI**，可能暂时用不到。\n\n///\n\n你可以声明附加响应，包括额外的状态码、媒体类型、描述等。\n\n这些附加响应会被包含在 OpenAPI 模式中，因此它们也会出现在 API 文档中。\n\n但是对于这些附加响应，你必须确保直接返回一个 `Response`（例如 `JSONResponse`），并携带你的状态码和内容。\n\n## 带有 `model` 的附加响应 { #additional-response-with-model }\n\n你可以向你的*路径操作装饰器*传入参数 `responses`。\n\n它接收一个 `dict`：键是每个响应的状态码（例如 `200`），值是包含该响应信息的另一个 `dict`。\n\n这些响应的每个 `dict` 都可以有一个键 `model`，包含一个 Pydantic 模型，就像 `response_model` 一样。\n\n**FastAPI** 会获取该模型，生成它的 JSON Schema，并将其放在 OpenAPI 中的正确位置。\n\n例如，要声明另一个状态码为 `404` 且具有 Pydantic 模型 `Message` 的响应，你可以这样写：\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | 注意\n\n记住你需要直接返回 `JSONResponse`。\n\n///\n\n/// info | 信息\n\n`model` 键不是 OpenAPI 的一部分。\n\n**FastAPI** 会从这里获取 Pydantic 模型，生成 JSON Schema，并把它放到正确的位置。\n\n正确的位置是：\n\n* 在键 `content` 中，它的值是另一个 JSON 对象（`dict`），该对象包含：\n    * 一个媒体类型作为键，例如 `application/json`，它的值是另一个 JSON 对象，该对象包含：\n        * 一个键 `schema`，它的值是来自该模型的 JSON Schema，这里就是正确的位置。\n            * **FastAPI** 会在这里添加一个引用，指向你 OpenAPI 中另一个位置的全局 JSON Schemas，而不是直接内联。这样，其他应用和客户端可以直接使用这些 JSON Schemas，提供更好的代码生成工具等。\n\n///\n\n为该*路径操作*在 OpenAPI 中生成的响应将是：\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n这些模式在 OpenAPI 模式中被引用到另一个位置：\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## 主响应的其他媒体类型 { #additional-media-types-for-the-main-response }\n\n你可以使用同一个 `responses` 参数为同一个主响应添加不同的媒体类型。\n\n例如，你可以添加一个额外的媒体类型 `image/png`，声明你的*路径操作*可以返回 JSON 对象（媒体类型为 `application/json`）或 PNG 图片：\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | 注意\n\n请注意，你必须直接使用 `FileResponse` 返回图片。\n\n///\n\n/// info | 信息\n\n除非你在 `responses` 参数中明确指定不同的媒体类型，否则 FastAPI 会假设响应与主响应类具有相同的媒体类型（默认是 `application/json`）。\n\n但是如果你指定了一个媒体类型为 `None` 的自定义响应类，FastAPI 会对任何具有关联模型的附加响应使用 `application/json`。\n\n///\n\n## 组合信息 { #combining-information }\n\n你也可以把来自多个位置的响应信息组合在一起，包括 `response_model`、`status_code` 和 `responses` 参数。\n\n你可以声明一个 `response_model`，使用默认状态码 `200`（或根据需要使用自定义状态码），然后在 `responses` 中直接在 OpenAPI 模式里为同一个响应声明附加信息。\n\n**FastAPI** 会保留来自 `responses` 的附加信息，并把它与你的模型生成的 JSON Schema 合并。\n\n例如，你可以声明一个状态码为 `404` 的响应，它使用一个 Pydantic 模型并带有自定义的 `description`。\n\n以及一个状态码为 `200` 的响应，它使用你的 `response_model`，但包含自定义的 `example`：\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\n所有这些都会被合并并包含到你的 OpenAPI 中，并显示在 API 文档里：\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## 组合预定义响应和自定义响应 { #combine-predefined-responses-and-custom-ones }\n\n你可能希望有一些适用于许多*路径操作*的预定义响应，但同时又想把它们与每个*路径操作*所需的自定义响应组合在一起。\n\n在这些情况下，你可以使用 Python 的“解包”`dict` 的技巧 `**dict_to_unpack`：\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\n这里，`new_dict` 将包含来自 `old_dict` 的所有键值对，再加上新的键值对：\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\n你可以使用该技巧在*路径操作*中重用一些预定义响应，并把它们与额外的自定义响应组合在一起。\n\n例如：\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## 关于 OpenAPI 响应的更多信息 { #more-information-about-openapi-responses }\n\n要查看响应中究竟可以包含什么，你可以查看 OpenAPI 规范中的以下部分：\n\n* [OpenAPI Responses 对象](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object)，它包含 `Response Object`。\n* [OpenAPI Response 对象](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object)，你可以把这里的任何内容直接包含到 `responses` 参数中的每个响应里。包括 `description`、`headers`、`content`（在这里声明不同的媒体类型和 JSON Schemas），以及 `links`。\n"
  },
  {
    "path": "docs/zh/docs/advanced/additional-status-codes.md",
    "content": "# 额外的状态码 { #additional-status-codes }\n\n**FastAPI** 默认使用 `JSONResponse` 返回一个响应，将你的 *路径操作* 中的返回内容放到该 `JSONResponse` 中。\n\n**FastAPI** 会自动使用默认的状态码或者使用你在 *路径操作* 中设置的状态码。\n\n## 额外的状态码 { #additional-status-codes_1 }\n\n如果你想要返回主要状态码之外的状态码，你可以通过直接返回一个 `Response` 来实现，比如 `JSONResponse`，然后直接设置额外的状态码。\n\n例如，假设你想有一个 *路径操作* 能够更新条目，并且更新成功时返回 200 「成功」 的 HTTP 状态码。\n\n但是你也希望它能够接受新的条目。并且当这些条目不存在时，会自动创建并返回 201 「创建」的 HTTP 状态码。\n\n要实现它，导入 `JSONResponse`，然后在其中直接返回你的内容，并将 `status_code` 设置为你要的值。\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning\n\n当你直接返回一个像上面例子中的 `Response` 对象时，它会直接返回。\n\n它不会用模型等进行序列化。\n\n确保其中有你想要的数据，且返回的值为合法的 JSON（如果你使用 `JSONResponse` 的话）。\n\n///\n\n/// note | 技术细节\n\n你也可以使用 `from starlette.responses import JSONResponse`。　\n\n出于方便，**FastAPI** 为开发者提供同 `starlette.responses` 一样的 `fastapi.responses`。但是大多数可用的响应都是直接来自 Starlette。`status` 也是一样。\n\n///\n\n## OpenAPI 和 API 文档 { #openapi-and-api-docs }\n\n如果你直接返回额外的状态码和响应，它们不会包含在 OpenAPI 方案（API 文档）中，因为 FastAPI 没办法预先知道你要返回什么。\n\n但是你可以使用 [额外的响应](additional-responses.md) 在代码中记录这些内容。\n"
  },
  {
    "path": "docs/zh/docs/advanced/advanced-dependencies.md",
    "content": "# 高级依赖项 { #advanced-dependencies }\n\n## 参数化的依赖项 { #parameterized-dependencies }\n\n目前我们看到的依赖项都是固定的函数或类。\n\n但有时你可能希望为依赖项设置参数，而不必声明许多不同的函数或类。\n\n假设我们要有一个依赖项，用来检查查询参数 `q` 是否包含某个固定内容。\n\n但我们希望能够把这个固定内容参数化。\n\n## “可调用”的实例 { #a-callable-instance }\n\n在 Python 中，可以让某个类的实例变成“可调用对象”（callable）。\n\n这里指的是类的实例（类本身已经是可调用的），而不是类本身。\n\n为此，声明一个 `__call__` 方法：\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\n在这种情况下，**FastAPI** 会使用这个 `__call__` 来检查附加参数和子依赖，并且稍后会调用它，把返回值传递给你的*路径操作函数*中的参数。\n\n## 参数化实例 { #parameterize-the-instance }\n\n现在，我们可以用 `__init__` 声明实例的参数，用来“参数化”这个依赖项：\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\n在本例中，**FastAPI** 不会接触或关心 `__init__`，我们会在自己的代码中直接使用它。\n\n## 创建实例 { #create-an-instance }\n\n我们可以这样创建该类的实例：\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\n这样就把依赖项“参数化”了，现在它内部带有属性 `checker.fixed_content` 的值 `\"bar\"`。\n\n## 把实例作为依赖项 { #use-the-instance-as-a-dependency }\n\n然后，我们可以在 `Depends(checker)` 中使用这个 `checker`，而不是 `Depends(FixedContentQueryChecker)`，因为依赖项是实例 `checker`，不是类本身。\n\n解析依赖项时，**FastAPI** 会像这样调用 `checker`：\n\n```Python\nchecker(q=\"somequery\")\n```\n\n...并将其返回值作为依赖项的值，传给我们的*路径操作函数*中的参数 `fixed_content_included`：\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | 提示\n\n这些看起来可能有些牵强，目前它的用处也许还不太明显。\n\n这些示例刻意保持简单，但展示了整体的工作方式。\n\n在安全相关的章节里，有一些工具函数就是以相同的方式实现的。\n\n如果你理解了这里的内容，你就已经知道那些安全工具在底层是如何工作的。\n\n///\n\n## 带 `yield` 的依赖项、`HTTPException`、`except` 与后台任务 { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | 警告\n\n你很可能不需要了解这些技术细节。\n\n这些细节主要在你的 FastAPI 应用版本低于 0.121.0 且你正遇到带 `yield` 的依赖项问题时才有用。\n\n///\n\n带 `yield` 的依赖项随着时间演进以覆盖不同用例并修复一些问题，下面是变更摘要。\n\n### 带 `yield` 的依赖项与 `scope` { #dependencies-with-yield-and-scope }\n\n在 0.121.0 版本中，FastAPI 为带 `yield` 的依赖项新增了 `Depends(scope=\"function\")` 的支持。\n\n使用 `Depends(scope=\"function\")` 时，`yield` 之后的退出代码会在*路径操作函数*结束后、响应发送给客户端之前立即执行。\n\n而当使用默认的 `Depends(scope=\"request\")` 时，`yield` 之后的退出代码会在响应发送之后执行。\n\n你可以在文档 [带 `yield` 的依赖项 - 提前退出与 `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope) 中了解更多。\n\n### 带 `yield` 的依赖项与 `StreamingResponse`（技术细节） { #dependencies-with-yield-and-streamingresponse-technical-details }\n\n在 FastAPI 0.118.0 之前，如果你使用带 `yield` 的依赖项，它会在*路径操作函数*返回后、发送响应之前运行 `yield` 之后的退出代码。\n\n这样做的目的是避免在等待响应通过网络传输期间不必要地占用资源。\n\n这也意味着，如果你返回的是 `StreamingResponse`，那么该带 `yield` 的依赖项的退出代码会在开始发送响应前就已经执行完毕。\n\n例如，如果你在带 `yield` 的依赖项中持有一个数据库会话，那么 `StreamingResponse` 在流式发送数据时将无法使用该会话，因为会话已经在 `yield` 之后的退出代码里被关闭了。\n\n在 0.118.0 中，这一行为被回退为：让 `yield` 之后的退出代码在响应发送之后再执行。\n\n/// info | 信息\n\n如你在下文所见，这与 0.106.0 之前的行为非常相似，但对若干边界情况做了改进和修复。\n\n///\n\n#### 需要提前执行退出代码的用例 { #use-cases-with-early-exit-code }\n\n在某些特定条件下，旧的行为（在发送响应之前执行带 `yield` 依赖项的退出代码）会更有利。\n\n例如，设想你在带 `yield` 的依赖项中仅用数据库会话来校验用户，而在*路径操作函数*中并不会再次使用该会话；同时，响应需要很长时间才能发送完，比如一个缓慢发送数据的 `StreamingResponse`，且它出于某种原因并不使用数据库。\n\n这种情况下，会一直持有数据库会话直到响应发送完毕；但如果并不再使用它，就没有必要一直占用。\n\n代码可能如下：\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\n退出代码（自动关闭 `Session`）位于：\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n...会在响应把慢速数据发送完之后才运行：\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\n但由于 `generate_stream()` 并不使用数据库会话，因此在发送响应期间保持会话打开并非必要。\n\n如果你使用的是 SQLModel（或 SQLAlchemy）并碰到这种特定用例，你可以在不再需要时显式关闭会话：\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\n这样会话会释放数据库连接，让其他请求可以使用。\n\n如果你还有其他需要在 `yield` 依赖项中提前退出的用例，请创建一个 [GitHub 讨论问题](https://github.com/fastapi/fastapi/discussions/new?category=questions)，说明你的具体用例以及为何提前关闭会对你有帮助。\n\n如果确有有力的用例需要提前关闭，我会考虑新增一种选择性启用提前关闭的方式。\n\n### 带 `yield` 的依赖项与 `except`（技术细节） { #dependencies-with-yield-and-except-technical-details }\n\n在 FastAPI 0.110.0 之前，如果你在带 `yield` 的依赖项中用 `except` 捕获了一个异常，并且没有再次抛出它，那么该异常会被自动抛出/转发给任意异常处理器或内部服务器错误处理器。\n\n在 0.110.0 中对此作出了变更，以修复将异常转发为未处理（内部服务器错误）时造成的内存消耗问题，并使其与常规 Python 代码的行为保持一致。\n\n### 后台任务与带 `yield` 的依赖项（技术细节） { #background-tasks-and-dependencies-with-yield-technical-details }\n\n在 FastAPI 0.106.0 之前，`yield` 之后抛出异常是不可行的，因为带 `yield` 的依赖项中的退出代码会在响应发送之后才执行，此时[异常处理器](../tutorial/handling-errors.md#install-custom-exception-handlers)已经运行完毕。\n\n之所以这样设计，主要是为了允许在后台任务中继续使用依赖项通过 `yield`“产出”的对象，因为退出代码会在后台任务完成之后才执行。\n\n在 FastAPI 0.106.0 中，这一行为被修改，目的是避免在等待响应通过网络传输时一直占用资源。\n\n/// tip | 提示\n\n另外，后台任务通常是一段独立的逻辑，应该单独处理，并使用它自己的资源（例如它自己的数据库连接）。\n\n因此，这样做你的代码通常会更清晰。\n\n///\n\n如果你过去依赖于旧行为，现在应在后台任务内部自行创建所需资源，并且只在内部使用不依赖于带 `yield` 依赖项资源的数据。\n\n例如，不要复用相同的数据库会话，而是在后台任务内部创建一个新的会话，并用这个新会话从数据库获取对象。然后，不是把数据库对象本身作为参数传给后台任务函数，而是传递该对象的 ID，并在后台任务函数内部再次获取该对象。\n"
  },
  {
    "path": "docs/zh/docs/advanced/advanced-python-types.md",
    "content": "# 高级 Python 类型 { #advanced-python-types }\n\n这里有一些在使用 Python 类型时可能有用的额外想法。\n\n## 使用 `Union` 或 `Optional` { #using-union-or-optional }\n\n如果你的代码因为某些原因不能使用 `|`，例如它不是在类型注解里，而是在 `response_model=` 之类的参数中，那么你可以使用 `typing` 中的 `Union` 来代替竖线（`|`）。\n\n例如，你可以声明某个值可以是 `str` 或 `None`：\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\n`typing` 也提供了一个声明“可能为 `None`”的快捷方式：`Optional`。\n\n从我非常主观的角度给个小建议：\n\n- 🚨 避免使用 `Optional[SomeType]`\n- 改用 ✨`Union[SomeType, None]`✨。\n\n两者是等价的，底层其实也是一样的。但我更推荐使用 `Union` 而不是 `Optional`，因为单词“optional”（可选）看起来会暗示该值是可选的，而它真正的含义是“它可以是 `None`”，即使它并不是可选的，仍然是必填的。\n\n我认为 `Union[SomeType, None]` 更能明确表达其含义。\n\n这只是关于词语和命名的问题，但这些词语会影响你和你的队友如何看待代码。\n\n举个例子，看这段函数：\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\n参数 `name` 被定义为 `Optional[str]`，但它并不是“可选”的，你不能不传这个参数就调用函数：\n\n```Python\nsay_hi()  # 哎呀，这会报错！😱\n```\n\n参数 `name` 仍然是必填的（不是“可选”），因为它没有默认值。不过，`name` 接受 `None` 作为取值：\n\n```Python\nsay_hi(name=None)  # 这样可以，None 是有效的 🎉\n```\n\n好消息是，在大多数情况下，你可以直接使用 `|` 来定义类型联合：\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\n因此，通常你不必为像 `Optional` 和 `Union` 这样的名字而操心。😎\n"
  },
  {
    "path": "docs/zh/docs/advanced/async-tests.md",
    "content": "# 异步测试 { #async-tests }\n\n您已经了解了如何使用 `TestClient` 测试 **FastAPI** 应用程序。但是到目前为止，您只了解了如何编写同步测试，而没有使用 `async` 异步函数。\n\n在测试中能够使用异步函数可能会很有用，比如当您需要异步查询数据库的时候。想象一下，您想要测试向 FastAPI 应用程序发送请求，然后验证您的后端是否成功在数据库中写入了正确的数据，与此同时您使用了异步的数据库的库。\n\n让我们看看如何才能实现这一点。\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\n如果我们想在测试中调用异步函数，那么我们的测试函数必须是异步的。 AnyIO 为此提供了一个简洁的插件，它允许我们指定一些测试函数要异步调用。\n\n## HTTPX { #httpx }\n\n即使您的 **FastAPI** 应用程序使用普通的 `def` 函数而不是 `async def` ，它本质上仍是一个 `async` 异步应用程序。\n\n`TestClient` 在内部通过一些“魔法”操作，使得您可以在普通的 `def` 测试函数中调用异步的 FastAPI 应用程序，并使用标准的 pytest。但当我们在异步函数中使用它时，这种“魔法”就不再生效了。由于测试以异步方式运行，我们无法在测试函数中继续使用 `TestClient`。\n\n`TestClient` 是基于 [HTTPX](https://www.python-httpx.org) 的。幸运的是，我们可以直接使用它来测试 API。\n\n## 示例 { #example }\n\n举个简单的例子，让我们来看一个与[更大的应用](../tutorial/bigger-applications.md)和[测试](../tutorial/testing.md)中描述的类似文件结构：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n文件 `main.py` 将包含:\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\n文件 `test_main.py` 将包含针对 `main.py` 的测试，现在它可能看起来如下：\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## 运行测试 { #run-it }\n\n您可以通过以下方式照常运行测试：\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## 详细说明 { #in-detail }\n\n这个标记 `@pytest.mark.anyio` 会告诉 pytest 该测试函数应该被异步调用：\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip | 提示\n\n请注意，测试函数现在用的是 `async def`，而不是像以前使用 `TestClient` 时那样只是 `def` 。\n\n///\n\n我们现在可以使用应用程序创建一个 `AsyncClient` ，并使用 `await` 向其发送异步请求。\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\n这相当于：\n\n```Python\nresponse = client.get('/')\n```\n\n...我们曾经通过它向 `TestClient` 发出请求。\n\n/// tip | 提示\n\n请注意，我们正在将 async/await 与新的 `AsyncClient` 一起使用——请求是异步的。\n\n///\n\n/// warning | 警告\n\n如果您的应用程序依赖于生命周期事件， `AsyncClient` 将不会触发这些事件。为了确保它们被触发，请使用 [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage) 中的 `LifespanManager` 。\n\n///\n\n## 其他异步函数调用 { #other-asynchronous-function-calls }\n\n由于测试函数现在是异步的，因此除了在测试中向 FastAPI 应用程序发送请求之外，您现在还可以调用（和使用 `await` 等待）其他 `async` 异步函数，就和您在代码中的其他任何地方调用它们的方法一样。\n\n/// tip | 提示\n\n如果您在测试程序中集成异步函数调用的时候遇到一个 `RuntimeError: Task attached to a different loop` 的报错（例如，使用 [MongoDB 的 MotorClient](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop) 时），请记住，只能在异步函数中实例化需要事件循环的对象，例如在 `@app.on_event(\"startup\")` 回调中初始化。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/advanced/behind-a-proxy.md",
    "content": "# 使用代理 { #behind-a-proxy }\n\n在很多情况下，你会在 FastAPI 应用前面使用像 Traefik 或 Nginx 这样的**代理**。\n\n这些代理可以处理 HTTPS 证书等事项。\n\n## 代理转发的请求头 { #proxy-forwarded-headers }\n\n在你的应用前面的**代理**通常会在把请求转发给你的**服务器**之前，临时设置一些请求头，让服务器知道该请求是由代理**转发**的，并告知原始（公网）URL，包括域名、是否使用 HTTPS 等。\n\n**服务器**程序（例如通过 **FastAPI CLI** 运行的 **Uvicorn**）能够解析这些请求头，然后把这些信息传递给你的应用。\n\n但出于安全考虑，由于服务器并不知道自己处在受信任的代理之后，它默认不会解析这些请求头。\n\n/// note | 技术细节\n\n这些代理相关的请求头包括：\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### 启用代理转发的请求头 { #enable-proxy-forwarded-headers }\n\n你可以用 *CLI 选项* `--forwarded-allow-ips` 启动 FastAPI CLI，并传入应该被信任、允许读取这些转发请求头的 IP 地址列表。\n\n如果设置为 `--forwarded-allow-ips=\"*\"`，就会信任所有来源 IP。\n\n如果你的**服务器**位于受信任的**代理**之后，并且只有代理会与它通信，这将使其接受该**代理**的任何 IP。\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### 使用 HTTPS 的重定向 { #redirects-with-https }\n\n例如，假设你定义了一个*路径操作* `/items/`：\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\n如果客户端尝试访问 `/items`，默认会被重定向到 `/items/`。\n\n但在设置 *CLI 选项* `--forwarded-allow-ips` 之前，它可能会重定向到 `http://localhost:8000/items/`。\n\n而你的应用可能托管在 `https://mysuperapp.com`，重定向应当是 `https://mysuperapp.com/items/`。\n\n通过设置 `--proxy-headers`，FastAPI 现在就可以重定向到正确的位置。😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip | 提示\n\n如果你想了解更多关于 HTTPS 的内容，查看指南：[关于 HTTPS](../deployment/https.md)。\n\n///\n\n### 代理转发请求头如何工作 { #how-proxy-forwarded-headers-work }\n\n下面是一个可视化图示，展示了**代理**如何在客户端与**应用服务器**之间添加转发请求头：\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Proxy as Proxy/Load Balancer\n    participant Server as FastAPI Server\n\n    Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: Proxy adds forwarded headers\n\n    Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)\n\n    Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs\n\n    Proxy->>Client: HTTPS Response\n```\n\n**代理**会拦截原始客户端请求，并在将请求传递给**应用服务器**之前，添加特殊的*转发*请求头（`X-Forwarded-*`）。\n\n这些请求头保留了原始请求中否则会丢失的信息：\n\n- X-Forwarded-For：原始客户端的 IP 地址\n- X-Forwarded-Proto：原始协议（`https`）\n- X-Forwarded-Host：原始主机（`mysuperapp.com`）\n\n当 **FastAPI CLI** 配置了 `--forwarded-allow-ips` 后，它会信任并使用这些请求头，例如用于在重定向中生成正确的 URL。\n\n## 移除路径前缀的代理 { #proxy-with-a-stripped-path-prefix }\n\n你可能会有一个代理，为你的应用添加一个路径前缀。\n\n在这些情况下，你可以使用 `root_path` 来配置你的应用。\n\n`root_path` 是 ASGI 规范（FastAPI 基于该规范，通过 Starlette 构建）提供的机制。\n\n`root_path` 用于处理这些特定情况。\n\n在挂载子应用时，它也会在内部使用。\n\n“移除路径前缀的代理”在这里的意思是：你可以在代码中声明一个路径 `/app`，然后在顶层添加一层（代理），把你的 **FastAPI** 应用放在类似 `/api/v1` 的路径下。\n\n在这种情况下，原始路径 `/app` 实际上会在 `/api/v1/app` 提供服务。\n\n即使你的所有代码都假设只有 `/app`。\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\n代理会在将请求传递给应用服务器（可能是通过 FastAPI CLI 运行的 Uvicorn）之前，实时**“移除”**这个**路径前缀**，让你的应用认为它是在 `/app` 被服务，这样你就不需要更新所有代码去包含 `/api/v1` 前缀。\n\n到这里，一切都会像往常一样工作。\n\n但是，当你打开集成的文档界面（前端）时，它会期望在 `/openapi.json` 获取 OpenAPI 模式，而不是在 `/api/v1/openapi.json`。\n\n因此，（在浏览器中运行的）前端会尝试访问 `/openapi.json`，但无法获取 OpenAPI 模式。\n\n因为我们的应用使用了路径前缀为 `/api/v1` 的代理，前端需要从 `/api/v1/openapi.json` 获取 OpenAPI 模式。\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy on http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server on http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip | 提示\n\nIP `0.0.0.0` 通常表示程序监听该机器/服务器上的所有可用 IP。\n\n///\n\n文档界面还需要 OpenAPI 模式声明该 API 的 `server` 位于 `/api/v1`（代理后面）。例如：\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // More stuff here\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // More stuff here\n    }\n}\n```\n\n在此示例中，“Proxy” 可以是 **Traefik** 之类的。服务器可以是用 **Uvicorn** 的 **FastAPI CLI** 运行你的 FastAPI 应用。\n\n### 提供 `root_path` { #providing-the-root-path }\n\n为此，你可以像下面这样使用命令行选项 `--root-path`：\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n如果你使用 Hypercorn，它也有 `--root-path` 选项。\n\n/// note | 技术细节\n\nASGI 规范为这种用例定义了 `root_path`。\n\n命令行选项 `--root-path` 会提供该 `root_path`。\n\n///\n\n### 查看当前的 `root_path` { #checking-the-current-root-path }\n\n你可以获取应用在每个请求中使用的当前 `root_path`，它是 `scope` 字典的一部分（ASGI 规范的一部分）。\n\n这里我们把它包含在响应消息中仅用于演示。\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\n然后，如果你这样启动 Uvicorn：\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n响应类似于：\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### 在 FastAPI 应用中设置 `root_path` { #setting-the-root-path-in-the-fastapi-app }\n\n或者，如果你无法提供类似 `--root-path` 的命令行选项，你可以在创建 FastAPI 应用时设置参数 `root_path`：\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\n把 `root_path` 传给 `FastAPI` 等同于把命令行选项 `--root-path` 传给 Uvicorn 或 Hypercorn。\n\n### 关于 `root_path` { #about-root-path }\n\n请注意，服务器（Uvicorn）不会用这个 `root_path` 做别的事情，只会把它传给应用。\n\n但是，如果你用浏览器打开 [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app)，你会看到正常的响应：\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n因此，它不会期望被访问于 `http://127.0.0.1:8000/api/v1/app`。\n\nUvicorn 会期望代理以 `http://127.0.0.1:8000/app` 访问 Uvicorn，而在顶部额外添加 `/api/v1` 前缀是代理的职责。\n\n## 关于移除路径前缀的代理 { #about-proxies-with-a-stripped-path-prefix }\n\n请记住，移除路径前缀只是配置代理的一种方式。\n\n在很多情况下，默认是代理不会移除路径前缀。\n\n在这种情况下（没有移除路径前缀），代理会监听类似 `https://myawesomeapp.com`，当浏览器访问 `https://myawesomeapp.com/api/v1/app` 且你的服务器（例如 Uvicorn）监听 `http://127.0.0.1:8000` 时，代理（未移除路径前缀）会以相同路径访问 Uvicorn：`http://127.0.0.1:8000/api/v1/app`。\n\n## 使用 Traefik 进行本地测试 { #testing-locally-with-traefik }\n\n你可以很容易地使用 [Traefik](https://docs.traefik.io/) 在本地运行一个移除路径前缀的实验。\n\n[下载 Traefik](https://github.com/containous/traefik/releases)，它是一个单独的二进制文件，你可以解压压缩包并直接在终端中运行。\n\n然后创建一个 `traefik.toml` 文件，内容如下：\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\n这告诉 Traefik 监听端口 9999，并使用另一个文件 `routes.toml`。\n\n/// tip | 提示\n\n我们使用 9999 端口而不是标准 HTTP 端口 80，这样你就不需要用管理员（`sudo`）权限运行。\n\n///\n\n现在创建另一个文件 `routes.toml`：\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\n这个文件配置 Traefik 使用路径前缀 `/api/v1`。\n\n随后 Traefik 会把请求转发到运行在 `http://127.0.0.1:8000` 的 Uvicorn。\n\n现在启动 Traefik：\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\n然后使用 `--root-path` 选项启动你的应用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### 查看响应 { #check-the-responses }\n\n现在，如果你访问 Uvicorn 端口对应的 URL：[http://127.0.0.1:8000/app](http://127.0.0.1:8000/app)，你会看到正常响应：\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip | 提示\n\n注意，尽管你是通过 `http://127.0.0.1:8000/app` 访问，它仍显示 `root_path` 为 `/api/v1`，该值来自 `--root-path` 选项。\n\n///\n\n现在打开包含路径前缀、使用 Traefik 端口的 URL：[http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app)。\n\n我们得到相同的响应：\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n但这次 URL 中带有代理提供的前缀路径：`/api/v1`。\n\n当然，这里的想法是每个人都通过代理访问应用，因此带有路径前缀 `/api/v1` 的版本才是“正确”的。\n\n而不带路径前缀的版本（`http://127.0.0.1:8000/app`）由 Uvicorn 直接提供，仅供_代理_（Traefik）访问。\n\n这说明了代理（Traefik）如何使用路径前缀，以及服务器（Uvicorn）如何使用 `--root-path` 选项提供的 `root_path`。\n\n### 查看文档界面 { #check-the-docs-ui }\n\n有趣的部分来了。✨\n\n访问应用的“官方”方式应该是通过我们定义的带有路径前缀的代理。因此，正如预期的那样，如果你尝试不带路径前缀、直接由 Uvicorn 提供的文档界面，它将无法工作，因为它期望通过代理访问。\n\n你可以在 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) 查看：\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\n但如果我们在“官方”URL（代理端口为 `9999`）的 `/api/v1/docs` 访问文档界面，它就能正常工作！🎉\n\n你可以在 [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) 查看：\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\n完全符合我们的预期。✔️\n\n这是因为 FastAPI 使用该 `root_path` 在 OpenAPI 中创建默认的 `server`，其 URL 来自 `root_path`。\n\n## 附加的服务器 { #additional-servers }\n\n/// warning | 警告\n\n这是一个更高级的用例，可以跳过。\n\n///\n\n默认情况下，**FastAPI** 会在 OpenAPI 模式中使用 `root_path` 的 URL 创建一个 `server`。\n\n但你也可以提供其他备选的 `servers`，例如你希望让“同一个”文档界面同时与预发布环境和生产环境交互。\n\n如果你传入了自定义的 `servers` 列表，并且存在 `root_path`（因为你的 API 位于代理后面），**FastAPI** 会在列表开头插入一个使用该 `root_path` 的“server”。\n\n例如：\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\n会生成如下的 OpenAPI 模式：\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // More stuff here\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // More stuff here\n    }\n}\n```\n\n/// tip | 提示\n\n注意这个自动生成的服务器，`url` 的值为 `/api/v1`，取自 `root_path`。\n\n///\n\n在文档界面 [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) 中，它看起来是这样的：\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip | 提示\n\n文档界面会与你所选择的服务器交互。\n\n///\n\n/// note | 技术细节\n\nOpenAPI 规范中的 `servers` 属性是可选的。\n\n如果你没有指定 `servers` 参数，并且 `root_path` 等于 `/`，则默认情况下，生成的 OpenAPI 模式中会完全省略 `servers` 属性，这等价于只有一个 `url` 值为 `/` 的服务器。\n\n///\n\n### 从 `root_path` 禁用自动服务器 { #disable-automatic-server-from-root-path }\n\n如果你不希望 **FastAPI** 包含一个使用 `root_path` 的自动服务器，可以使用参数 `root_path_in_servers=False`：\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\n这样它就不会被包含到 OpenAPI 模式中。\n\n## 挂载子应用 { #mounting-a-sub-application }\n\n如果你需要在使用带有 `root_path` 的代理时挂载一个子应用（参见 [子应用 - 挂载](sub-applications.md)），你可以像预期的那样正常操作。\n\nFastAPI 会在内部智能地使用 `root_path`，因此它可以直接正常工作。✨\n"
  },
  {
    "path": "docs/zh/docs/advanced/custom-response.md",
    "content": "# 自定义响应 - HTML、流、文件等 { #custom-response-html-stream-file-others }\n\n默认情况下，**FastAPI** 会返回 JSON 响应。\n\n你可以像在 [直接返回响应](response-directly.md) 中那样，直接返回 `Response` 来重载它。\n\n但如果你直接返回一个 `Response`（或其任意子类，比如 `JSONResponse`），返回的数据不会自动转换（即使你声明了 `response_model`），也不会自动生成文档（例如，在生成的 OpenAPI 中，HTTP 头 `Content-Type` 里的特定「媒体类型」不会被包含）。\n\n你还可以在 *路径操作装饰器* 中通过 `response_class` 参数声明要使用的 `Response`（例如任意 `Response` 子类）。\n\n你从 *路径操作函数* 中返回的内容将被放在该 `Response` 中。\n\n/// note | 注意\n\n如果你使用不带有媒体类型的响应类，FastAPI 会认为你的响应没有任何内容，所以不会在生成的 OpenAPI 文档中记录响应格式。\n\n///\n\n## JSON 响应 { #json-responses }\n\n默认情况下 FastAPI 返回 JSON 响应。\n\n如果你声明了一个[响应模型](../tutorial/response-model.md)，FastAPI 会使用 Pydantic 将数据序列化为 JSON。\n\n如果你没有声明响应模型，FastAPI 会使用 [JSON 兼容编码器](../tutorial/encoder.md) 中解释的 `jsonable_encoder`，并把结果放进一个 `JSONResponse`。\n\n如果你在 `response_class` 中声明了一个 JSON 媒体类型（`application/json`）的类（比如 `JSONResponse`），你返回的数据会使用你在 *路径操作装饰器* 中声明的任意 Pydantic `response_model` 自动转换（和过滤）。但数据不会由 Pydantic 序列化为 JSON 字节；而是先用 `jsonable_encoder` 转换后传给 `JSONResponse`，由它使用 Python 标准 JSON 库序列化为字节。\n\n### JSON 性能 { #json-performance }\n\n简而言之，如果你想要获得最大性能，请使用[响应模型](../tutorial/response-model.md)，并且不要在 *路径操作装饰器* 中声明 `response_class`。\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## HTML 响应 { #html-response }\n\n使用 `HTMLResponse` 来从 **FastAPI** 中直接返回一个 HTML 响应。\n\n* 导入 `HTMLResponse`。\n* 将 `HTMLResponse` 作为你的 *路径操作* 的 `response_class` 参数传入。\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info | 信息\n\n参数 `response_class` 也会用来定义响应的「媒体类型」。\n\n在这个例子中，HTTP 头的 `Content-Type` 会被设置成 `text/html`。\n\n并且在 OpenAPI 文档中也会这样记录。\n\n///\n\n### 返回一个 `Response` { #return-a-response }\n\n正如你在 [直接返回响应](response-directly.md) 中了解到的，你也可以通过直接返回响应在 *路径操作* 中直接重载响应。\n\n和上面一样的例子，返回一个 `HTMLResponse` 看起来可能是这样：\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning | 警告\n\n*路径操作函数* 直接返回的 `Response` 不会被 OpenAPI 的文档记录（比如，`Content-Type` 不会被文档记录），并且在自动化交互文档中也是不可见的。\n\n///\n\n/// info | 信息\n\n当然，实际的 `Content-Type` 头、状态码等等，将来自于你返回的 `Response` 对象。\n\n///\n\n### 在 OpenAPI 中文档化并重载 `Response` { #document-in-openapi-and-override-response }\n\n如果你想要在函数内重载响应，但是同时在 OpenAPI 中文档化「媒体类型」，你可以使用 `response_class` 参数并返回一个 `Response` 对象。\n\n接着 `response_class` 参数只会被用来文档化 OpenAPI 的 *路径操作*，你的 `Response` 用来返回响应。\n\n#### 直接返回 `HTMLResponse` { #return-an-htmlresponse-directly }\n\n比如像这样：\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\n在这个例子中，函数 `generate_html_response()` 已经生成并返回 `Response` 对象而不是在 `str` 中返回 HTML。\n\n通过返回函数 `generate_html_response()` 的调用结果，你已经返回一个重载 **FastAPI** 默认行为的 `Response` 对象。\n\n但如果你在 `response_class` 中也传入了 `HTMLResponse`，**FastAPI** 会知道如何在 OpenAPI 和交互式文档中使用 `text/html` 将其文档化为 HTML：\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## 可用响应 { #available-responses }\n\n这里有一些可用的响应。\n\n要记得你可以使用 `Response` 来返回任何其他东西，甚至创建一个自定义的子类。\n\n/// note | 技术细节\n\n你也可以使用 `from starlette.responses import HTMLResponse`。\n\n**FastAPI** 提供了同 `fastapi.responses` 相同的 `starlette.responses` 只是为了方便开发者。但大多数可用的响应都直接来自 Starlette。\n\n///\n\n### `Response` { #response }\n\n其他全部的响应都继承自主类 `Response`。\n\n你可以直接返回它。\n\n`Response` 类接受如下参数：\n\n* `content` - 一个 `str` 或者 `bytes`。\n* `status_code` - 一个 `int` 类型的 HTTP 状态码。\n* `headers` - 一个由字符串组成的 `dict`。\n* `media_type` - 一个给出媒体类型的 `str`，比如 `\"text/html\"`。\n\nFastAPI（实际上是 Starlette）将自动包含 Content-Length 的头。它还将包含一个基于 `media_type` 的 Content-Type 头，并为文本类型附加一个字符集。\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\n如上文所述，接受文本或字节并返回 HTML 响应。\n\n### `PlainTextResponse` { #plaintextresponse }\n\n接受文本或字节并返回纯文本响应。\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\n接受数据并返回一个 `application/json` 编码的响应。\n\n如上文所述，这是 **FastAPI** 中使用的默认响应。\n\n/// note | 技术细节\n\n但如果你声明了响应模型或返回类型，将直接使用它来把数据序列化为 JSON，并直接返回一个具备正确 JSON 媒体类型的响应，而不会使用 `JSONResponse` 类。\n\n这是获得最佳性能的理想方式。\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\n返回 HTTP 重定向。默认情况下使用 307 状态码（临时重定向）。\n\n你可以直接返回一个 `RedirectResponse`：\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\n或者你可以把它用于 `response_class` 参数：\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\n如果你这么做，那么你可以在 *路径操作* 函数中直接返回 URL。\n\n在这种情况下，将使用 `RedirectResponse` 的默认 `status_code`，即 `307`。\n\n---\n\n你也可以将 `status_code` 参数和 `response_class` 参数结合使用：\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\n采用异步生成器或普通生成器/迭代器（带有 `yield` 的函数），然后流式传输响应主体。\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | 技术细节\n\n一个 `async` 任务只有在到达 `await` 时才能被取消。如果没有 `await`，生成器（带有 `yield` 的函数）无法被正确取消，即使已请求取消也可能继续运行。\n\n由于这个小示例不需要任何 `await` 语句，我们添加 `await anyio.sleep(0)`，给事件循环一个处理取消的机会。\n\n对于大型或无限流，这一点更为重要。\n\n///\n\n/// tip | 提示\n\n与其直接返回 `StreamingResponse`，更推荐遵循 [流式数据](./stream-data.md) 的写法，它更方便并在幕后为你处理取消。\n\n如果你在流式传输 JSON Lines，请参阅教程：[流式传输 JSON Lines](../tutorial/stream-json-lines.md)。\n\n///\n\n### `FileResponse` { #fileresponse }\n\n异步传输文件作为响应。\n\n与其他响应类型相比，接受不同的参数集进行实例化：\n\n* `path` - 要流式传输的文件的文件路径。\n* `headers` - 任何自定义响应头，传入字典类型。\n* `media_type` - 给出媒体类型的字符串。如果未设置，则文件名或路径将用于推断媒体类型。\n* `filename` - 如果给出，它将包含在响应的 `Content-Disposition` 中。\n\n文件响应将包含适当的 `Content-Length`、`Last-Modified` 和 `ETag` 响应头。\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\n你也可以使用 `response_class` 参数：\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\n在这种情况下，你可以在 *路径操作* 函数中直接返回文件路径。\n\n## 自定义响应类 { #custom-response-class }\n\n你可以创建你自己的自定义响应类，继承自 `Response` 并使用它。\n\n例如，假设你想用一些设置来使用 [`orjson`](https://github.com/ijl/orjson)。\n\n假设你想让它返回带缩进、格式化的 JSON，因此你想使用 orjson 选项 `orjson.OPT_INDENT_2`。\n\n你可以创建一个 `CustomORJSONResponse`。你需要做的主要事情是实现一个 `Response.render(content)` 方法，并返回 `bytes`：\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\n现在，不再是返回：\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n...这个响应将返回：\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\n当然，你很可能会找到比格式化 JSON 更好的方式来利用这一点。😉\n\n### `orjson` 或响应模型 { #orjson-or-response-model }\n\n如果你追求的是性能，使用[响应模型](../tutorial/response-model.md) 往往比返回 `orjson` 响应更好。\n\n使用响应模型时，FastAPI 会使用 Pydantic 直接把数据序列化为 JSON，不需要诸如通过 `jsonable_encoder` 转换这样的中间步骤（其他情况下会发生）。\n\n并且在底层，Pydantic 使用与 `orjson` 相同的 Rust 机制来序列化 JSON，所以使用响应模型你已经可以获得最佳性能。\n\n## 默认响应类 { #default-response-class }\n\n在创建 **FastAPI** 类实例或 `APIRouter` 时，你可以指定默认要使用的响应类。\n\n用于定义它的参数是 `default_response_class`。\n\n在下面的示例中，**FastAPI** 会在所有 *路径操作* 中默认使用 `HTMLResponse`，而不是 JSON。\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip | 提示\n\n你仍然可以像之前一样在 *路径操作* 中重载 `response_class`。\n\n///\n\n## 额外文档 { #additional-documentation }\n\n你还可以使用 `responses` 在 OpenAPI 中声明媒体类型和许多其他详细信息：[OpenAPI 中的额外响应](additional-responses.md)。\n"
  },
  {
    "path": "docs/zh/docs/advanced/dataclasses.md",
    "content": "# 使用数据类 { #using-dataclasses }\n\nFastAPI 基于 **Pydantic** 构建，我已经向你展示过如何使用 Pydantic 模型声明请求与响应。\n\n但 FastAPI 也支持以相同方式使用 [`dataclasses`](https://docs.python.org/3/library/dataclasses.html)：\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\n这仍然得益于 **Pydantic**，因为它对 [`dataclasses` 的内置支持](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel)。\n\n因此，即便上面的代码没有显式使用 Pydantic，FastAPI 也会使用 Pydantic 将那些标准数据类转换为 Pydantic 风格的 dataclasses。\n\n并且，它仍然支持以下功能：\n\n* 数据验证\n* 数据序列化\n* 数据文档等\n\n这与使用 Pydantic 模型时的工作方式相同。而且底层实际上也是借助 Pydantic 实现的。\n\n/// info | 信息\n\n请注意，数据类不能完成 Pydantic 模型能做的所有事情。\n\n因此，你可能仍然需要使用 Pydantic 模型。\n\n但如果你已有一堆数据类，这个技巧可以让它们很好地为使用 FastAPI 的 Web API 所用。🤓\n\n///\n\n## 在 `response_model` 中使用数据类 { #dataclasses-in-response-model }\n\n你也可以在 `response_model` 参数中使用 `dataclasses`：\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\n该数据类会被自动转换为 Pydantic 的数据类。\n\n这样，它的模式会显示在 API 文档界面中：\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## 在嵌套数据结构中使用数据类 { #dataclasses-in-nested-data-structures }\n\n你也可以把 `dataclasses` 与其它类型注解组合在一起，创建嵌套数据结构。\n\n在某些情况下，你可能仍然需要使用 Pydantic 的 `dataclasses` 版本。例如，如果自动生成的 API 文档出现错误。\n\n在这种情况下，你可以直接把标准的 `dataclasses` 替换为 `pydantic.dataclasses`，它是一个可直接替换的实现：\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. 我们仍然从标准库的 `dataclasses` 导入 `field`。\n2. `pydantic.dataclasses` 是 `dataclasses` 的可直接替换版本。\n3. `Author` 数据类包含一个由 `Item` 数据类组成的列表。\n4. `Author` 数据类被用作 `response_model` 参数。\n5. 你可以将其它标准类型注解与数据类一起用作请求体。\n\n   在本例中，它是一个 `Item` 数据类列表。\n6. 这里我们返回一个字典，里面的 `items` 是一个数据类列表。\n\n   FastAPI 仍然能够将数据<dfn title=\"把数据转换为可以传输的格式\">序列化</dfn>为 JSON。\n7. 这里的 `response_model` 使用了 “`Author` 数据类列表” 的类型注解。\n\n   同样，你可以将 `dataclasses` 与标准类型注解组合使用。\n8. 注意，这个 *路径操作函数* 使用的是常规的 `def` 而不是 `async def`。\n\n   一如既往，在 FastAPI 中你可以按需组合 `def` 和 `async def`。\n\n   如果需要回顾何时用哪一个，请查看关于 [`async` 和 `await`](../async.md#in-a-hurry) 的文档中的 _“急不可待？”_ 一节。\n9. 这个 *路径操作函数* 返回的不是数据类（当然也可以返回数据类），而是包含内部数据的字典列表。\n\n   FastAPI 会使用（包含数据类的）`response_model` 参数来转换响应。\n\n你可以将 `dataclasses` 与其它类型注解以多种不同方式组合，来构建复杂的数据结构。\n\n更多细节请参考上面代码中的内联注释提示。\n\n## 深入学习 { #learn-more }\n\n你还可以把 `dataclasses` 与其它 Pydantic 模型组合、从它们继承、把它们包含到你自己的模型中等。\n\n想了解更多，请查看 [Pydantic 关于 dataclasses 的文档](https://docs.pydantic.dev/latest/concepts/dataclasses/)。\n\n## 版本 { #version }\n\n自 FastAPI 版本 `0.67.0` 起可用。🔖\n"
  },
  {
    "path": "docs/zh/docs/advanced/events.md",
    "content": "# 生命周期事件 { #lifespan-events }\n\n你可以定义在应用**启动**前执行的逻辑（代码）。这意味着在应用**开始接收请求**之前，这些代码只会被执行**一次**。\n\n同样地，你可以定义在应用**关闭**时应执行的逻辑。在这种情况下，这段代码将在**处理可能的多次请求后**执行**一次**。\n\n因为这段代码在应用开始接收请求**之前**执行，也会在处理可能的若干请求**之后**执行，它覆盖了整个应用程序的**生命周期**（“生命周期”这个词很重要😉）。\n\n这对于设置你需要在整个应用中使用的**资源**非常有用，这些资源在请求之间**共享**，你可能需要在之后进行**释放**。例如，数据库连接池，或加载一个共享的机器学习模型。\n\n## 用例 { #use-case }\n\n让我们从一个示例**用例**开始，看看如何用它来解决问题。\n\n假设你有几个**机器学习的模型**，你想要用它们来处理请求。🤖\n\n相同的模型在请求之间是共享的，因此并非每个请求或每个用户各自拥有一个模型。\n\n假设加载模型可能**需要相当长的时间**，因为它必须从**磁盘**读取大量数据。因此你不希望每个请求都加载它。\n\n你可以在模块/文件的顶部加载它，但这也意味着即使你只是在运行一个简单的自动化测试，它也会**加载模型**，这样测试将**变慢**，因为它必须在能够独立运行代码的其他部分之前等待模型加载完成。\n\n这就是我们要解决的问题——在处理请求前加载模型，但只是在应用开始接收请求前，而不是在代码被加载时。\n\n## Lifespan { #lifespan }\n\n你可以使用 `FastAPI` 应用的 `lifespan` 参数和一个“上下文管理器”（稍后我将为你展示）来定义**启动**和**关闭**的逻辑。\n\n让我们从一个例子开始，然后详细介绍。\n\n我们使用 `yield` 创建了一个异步函数 `lifespan()` 像这样：\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\n在这里，我们在 `yield` 之前将（虚拟的）模型函数放入机器学习模型的字典中，以此模拟加载模型的耗时**启动**操作。这段代码将在应用程序**开始处理请求之前**执行，即**启动**期间。\n\n然后，在 `yield` 之后，我们卸载模型。这段代码将会在应用程序**完成处理请求后**执行，即在**关闭**之前。这可以释放诸如内存或 GPU 之类的资源。\n\n/// tip | 提示\n\n**关闭**事件会在你**停止**应用时发生。\n\n可能你需要启动一个新版本，或者你只是厌倦了运行它。 🤷\n\n///\n\n### 生命周期函数 { #lifespan-function }\n\n首先要注意的是，我们定义了一个带有 `yield` 的异步函数。这与带有 `yield` 的依赖项非常相似。\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\n这个函数在 `yield` 之前的部分，会在应用启动前执行。\n\n剩下的部分在 `yield` 之后，会在应用完成后执行。\n\n### 异步上下文管理器 { #async-context-manager }\n\n如你所见，这个函数有一个装饰器 `@asynccontextmanager`。\n\n它将函数转化为所谓的“**异步上下文管理器**”。\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\n在 Python 中，**上下文管理器**是一个你可以在 `with` 语句中使用的东西，例如，`open()` 可以作为上下文管理器使用。\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\nPython 的最近几个版本也有了一个**异步上下文管理器**，你可以通过 `async with` 来使用：\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\n你可以像上面一样创建一个上下文管理器或者异步上下文管理器，它的作用是在进入 `with` 块时，执行 `yield` 之前的代码，并且在离开 `with` 块时，执行 `yield` 后面的代码。\n\n但在我们上面的例子里，我们并不是直接使用，而是传递给 FastAPI 来供其使用。\n\n`FastAPI` 的 `lifespan` 参数接受一个**异步上下文管理器**，所以我们可以把我们新定义的异步上下文管理器 `lifespan` 传给它。\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## 替代事件（弃用） { #alternative-events-deprecated }\n\n/// warning | 警告\n\n配置**启动**和**关闭**的推荐方法是使用 `FastAPI` 应用的 `lifespan` 参数，如前所示。如果你提供了一个 `lifespan` 参数，启动（`startup`）和关闭（`shutdown`）事件处理器将不再生效。要么使用 `lifespan`，要么配置所有事件，两者不能共用。\n\n你可以跳过这一部分。\n\n///\n\n有一种替代方法可以定义在**启动**和**关闭**期间执行的逻辑。\n\n你可以定义在应用启动前或应用关闭时需要执行的事件处理器（函数）。\n\n事件函数既可以声明为异步函数（`async def`），也可以声明为普通函数（`def`）。\n\n### `startup` 事件 { #startup-event }\n\n使用事件 `\"startup\"` 声明一个在应用启动前运行的函数：\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\n本例中，`startup` 事件处理器函数为项目“数据库”（只是一个 `dict`）提供了一些初始值。\n\n**FastAPI** 支持多个事件处理器函数。\n\n只有所有 `startup` 事件处理器运行完毕，**FastAPI** 应用才开始接收请求。\n\n### `shutdown` 事件 { #shutdown-event }\n\n使用事件 `\"shutdown\"` 声明一个在应用关闭时运行的函数：\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\n此处，`shutdown` 事件处理器函数会向文件 `log.txt` 写入一行文本 `\"Application shutdown\"`。\n\n/// info | 信息\n\n在 `open()` 函数中，`mode=\"a\"` 指的是“追加”。因此这行文本会添加在文件已有内容之后，不会覆盖之前的内容。\n\n///\n\n/// tip | 提示\n\n注意，本例使用 Python 标准的 `open()` 函数与文件交互。\n\n这个函数执行 I/O（输入/输出）操作，需要“等待”内容写进磁盘。\n\n但 `open()` 不使用 `async` 和 `await`。\n\n因此，声明事件处理函数要使用 `def`，而不是 `async def`。\n\n///\n\n### `startup` 和 `shutdown` 一起使用 { #startup-and-shutdown-together }\n\n启动和关闭的逻辑很可能是连接在一起的，你可能希望启动某个东西然后结束它，获取一个资源然后释放它等等。\n\n在不共享逻辑或变量的不同函数中处理这些逻辑比较困难，因为你需要在全局变量中存储值或使用类似的方式。\n\n因此，推荐使用上面所述的 `lifespan`。\n\n## 技术细节 { #technical-details }\n\n只是为好奇者提供的技术细节。🤓\n\n在底层，这部分是 ASGI 技术规范中的 [Lifespan 协议](https://asgi.readthedocs.io/en/latest/specs/lifespan.html)的一部分，定义了称为 `startup` 和 `shutdown` 的事件。\n\n/// info | 信息\n\n你可以在 [Starlette 的 Lifespan 文档](https://www.starlette.dev/lifespan/) 中阅读更多关于 `lifespan` 处理器的内容。\n\n包括如何处理生命周期状态，以便在代码的其他部分使用。\n\n///\n\n## 子应用 { #sub-applications }\n\n🚨 请注意，这些生命周期事件（startup 和 shutdown）只会在主应用上执行，不会在[子应用 - 挂载](sub-applications.md)上执行。\n"
  },
  {
    "path": "docs/zh/docs/advanced/generate-clients.md",
    "content": "# 生成 SDK { #generating-sdks }\n\n因为 **FastAPI** 基于 **OpenAPI** 规范，它的 API 可以用许多工具都能理解的标准格式来描述。\n\n这让你可以轻松生成最新的**文档**、多语言的客户端库（<abbr title=\"Software Development Kits - 软件开发工具包\">**SDKs**</abbr>），以及与代码保持同步的**测试**或**自动化工作流**。\n\n本指南将带你为 FastAPI 后端生成一个 **TypeScript SDK**。\n\n## 开源 SDK 生成器 { #open-source-sdk-generators }\n\n一个功能多样的选择是 [OpenAPI Generator](https://openapi-generator.tech/)，它支持**多种编程语言**，可以根据你的 OpenAPI 规范生成 SDK。\n\n对于 **TypeScript 客户端**，[Hey API](https://heyapi.dev/) 是为 TypeScript 生态打造的专用方案，提供优化的使用体验。\n\n你还可以在 [OpenAPI.Tools](https://openapi.tools/#sdk) 上发现更多 SDK 生成器。\n\n/// tip | 提示\n\nFastAPI 会自动生成 **OpenAPI 3.1** 规范，因此你使用的任何工具都必须支持该版本。\n\n///\n\n## 来自 FastAPI 赞助商的 SDK 生成器 { #sdk-generators-from-fastapi-sponsors }\n\n本节介绍的是由赞助 FastAPI 的公司提供的、具备**风险投资背景**或**公司支持**的方案。这些产品在高质量生成的 SDK 之上，提供了**更多特性**和**集成**。\n\n通过 ✨ [**赞助 FastAPI**](../help-fastapi.md#sponsor-the-author) ✨，这些公司帮助确保框架及其**生态**保持健康并且**可持续**。\n\n他们的赞助也体现了对 FastAPI **社区**（也就是你）的高度承诺，不仅关注提供**优秀的服务**，也支持一个**健壮且繁荣的框架**——FastAPI。🙇\n\n例如，你可以尝试：\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\n其中一些方案也可能是开源的或提供免费层级，你可以不花钱就先试用。其他商业 SDK 生成器也可在网上找到。🤓\n\n## 创建一个 TypeScript SDK { #create-a-typescript-sdk }\n\n先从一个简单的 FastAPI 应用开始：\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\n请注意，这些*路径操作*使用 `Item` 和 `ResponseMessage` 模型来定义它们的请求载荷和响应载荷。\n\n### API 文档 { #api-docs }\n\n访问 `/docs` 时，你会看到有用于请求发送和响应接收数据的**模式**：\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\n之所以能看到这些模式，是因为它们在应用中用模型声明了。\n\n这些信息会包含在应用的 **OpenAPI 模式** 中，并显示在 API 文档里。\n\nOpenAPI 中包含的这些模型信息就是用于**生成客户端代码**的基础。\n\n### Hey API { #hey-api }\n\n当我们有了带模型的 FastAPI 应用后，可以使用 Hey API 来生成 TypeScript 客户端。最快的方式是通过 npx：\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\n这会在 `./src/client` 生成一个 TypeScript SDK。\n\n你可以在其官网了解如何[安装 `@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started)，以及阅读[生成结果](https://heyapi.dev/openapi-ts/output)的说明。\n\n### 使用 SDK { #using-the-sdk }\n\n现在你可以导入并使用客户端代码了。它可能是这样，并且你会发现方法有自动补全：\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\n要发送的载荷也会有自动补全：\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip | 提示\n\n请注意 `name` 和 `price` 的自动补全，它们是在 FastAPI 应用中的 `Item` 模型里定义的。\n\n///\n\n你发送的数据如果不符合要求，会在编辑器中显示内联错误：\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\n响应对象同样有自动补全：\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## 带有标签的 FastAPI 应用 { #fastapi-app-with-tags }\n\n很多情况下，你的 FastAPI 应用会更大，你可能会用标签来划分不同组的*路径操作*。\n\n例如，你可以有一个 **items** 相关的部分和另一个 **users** 相关的部分，它们可以用标签来分隔：\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### 生成带标签的 TypeScript 客户端 { #generate-a-typescript-client-with-tags }\n\n如果你为使用了标签的 FastAPI 应用生成客户端，通常也会根据标签来拆分客户端代码。\n\n这样你就可以在客户端代码中把内容正确地组织和分组：\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\n在这个例子中，你会有：\n\n* `ItemsService`\n* `UsersService`\n\n### 客户端方法名 { #client-method-names }\n\n现在，像 `createItemItemsPost` 这样的生成方法名看起来不太简洁：\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n...这是因为客户端生成器会把每个*路径操作*的 OpenAPI 内部**操作 ID（operation ID）**用作方法名的一部分。\n\nOpenAPI 要求每个操作 ID 在所有*路径操作*中都是唯一的，因此 FastAPI 会使用**函数名**、**路径**和**HTTP 方法/操作**来生成操作 ID，以确保其唯一性。\n\n接下来我会告诉你如何改进。🤓\n\n## 自定义操作 ID 与更好的方法名 { #custom-operation-ids-and-better-method-names }\n\n你可以**修改**这些操作 ID 的**生成**方式，使之更简单，从而在客户端中得到**更简洁的方法名**。\n\n在这种情况下，你需要用其他方式确保每个操作 ID 依然是**唯一**的。\n\n例如，你可以确保每个*路径操作*都有一个标签，然后基于**标签**和*路径操作***名称**（函数名）来生成操作 ID。\n\n### 自定义唯一 ID 生成函数 { #custom-generate-unique-id-function }\n\nFastAPI 为每个*路径操作*使用一个**唯一 ID**，它既用于**操作 ID**，也用于请求或响应里任何需要的自定义模型名称。\n\n你可以自定义这个函数。它接收一个 `APIRoute` 并返回一个字符串。\n\n例如，这里使用第一个标签（你很可能只有一个标签）和*路径操作*名称（函数名）。\n\n然后你可以把这个自定义函数通过 `generate_unique_id_function` 参数传给 **FastAPI**：\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### 使用自定义操作 ID 生成 TypeScript 客户端 { #generate-a-typescript-client-with-custom-operation-ids }\n\n现在再次生成客户端，你会看到方法名已经改进：\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\n如你所见，方法名现在由标签和函数名组成，不再包含 URL 路径和 HTTP 操作的信息。\n\n### 为客户端生成器预处理 OpenAPI 规范 { #preprocess-the-openapi-specification-for-the-client-generator }\n\n生成的代码中仍有一些**重复信息**。\n\n我们已经知道这个方法与 **items** 有关，因为它位于 `ItemsService`（来自标签），但方法名里仍然带有标签名前缀。😕\n\n通常我们仍然希望在 OpenAPI 中保留它，以确保操作 ID 的**唯一性**。\n\n但对于生成的客户端，我们可以在生成之前**修改** OpenAPI 的操作 ID，只是为了让方法名更美观、更**简洁**。\n\n我们可以把 OpenAPI JSON 下载到 `openapi.json` 文件中，然后用如下脚本**移除这个标签前缀**：\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\n这样，操作 ID 会从 `items-get_items` 之类的名字重命名为 `get_items`，从而让客户端生成器生成更简洁的方法名。\n\n### 使用预处理后的 OpenAPI 生成 TypeScript 客户端 { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\n因为最终结果现在保存在 `openapi.json` 中，你需要更新输入位置：\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\n生成新客户端后，你将拥有**简洁的方法名**，并具备**自动补全**、**内联错误**等功能：\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## 优点 { #benefits }\n\n使用自动生成的客户端时，你会获得以下内容的**自动补全**：\n\n* 方法\n* 请求体中的数据、查询参数等\n* 响应数据\n\n你还会为所有内容获得**内联错误**。\n\n每当你更新后端代码并**重新生成**前端时，新的*路径操作*会作为方法可用，旧的方法会被移除，其他任何更改都会反映到生成的代码中。🤓\n\n这也意味着如果有任何变更，它会自动**反映**到客户端代码中。而当你**构建**客户端时，如果所用数据存在任何**不匹配**，它会直接报错。\n\n因此，你可以在开发周期的早期就**发现许多错误**，而不必等到错误在生产环境中暴露给最终用户后再去调试问题所在。✨\n"
  },
  {
    "path": "docs/zh/docs/advanced/index.md",
    "content": "# 高级用户指南 { #advanced-user-guide }\n\n## 附加功能 { #additional-features }\n\n主要的[教程 - 用户指南](../tutorial/index.md)足以带你了解 **FastAPI** 的所有主要特性。\n\n在接下来的章节中，你将看到其他选项、配置和附加功能。\n\n/// tip | 提示\n\n接下来的章节**不一定是“高级”的**。\n\n对于你的用例，解决方案很可能就在其中之一。\n\n///\n\n## 先阅读教程 { #read-the-tutorial-first }\n\n仅凭主要[教程 - 用户指南](../tutorial/index.md)中的知识，你已经可以使用 **FastAPI** 的大多数功能。\n\n接下来的章节默认你已经读过它，并理解其中的核心概念。\n"
  },
  {
    "path": "docs/zh/docs/advanced/json-base64-bytes.md",
    "content": "# 在 JSON 中使用 Base64 表示字节 { #json-with-bytes-as-base64 }\n\n如果你的应用需要接收和发送 JSON 数据，但其中需要包含二进制数据，可以将其编码为 base64。\n\n## Base64 与文件 { #base64-vs-files }\n\n请先考虑是否可以使用 [请求文件](../tutorial/request-files.md) 来上传二进制数据，并使用 [自定义响应 - FileResponse](./custom-response.md#fileresponse--fileresponse-) 来发送二进制数据，而不是把它编码进 JSON。\n\nJSON 只能包含 UTF-8 编码的字符串，因此无法直接包含原始字节。\n\nBase64 可以把二进制数据编码为字符串，但为此会使用比原始二进制更多的字符，因此通常比直接使用文件的效率更低。\n\n仅当你确实需要在 JSON 中包含二进制数据且无法使用文件时，才使用 base64。\n\n## Pydantic `bytes` { #pydantic-bytes }\n\n你可以声明带有 `bytes` 字段的 Pydantic 模型，然后在模型配置中使用 `val_json_bytes` 指定用 base64 来验证输入的 JSON 数据；作为验证的一部分，它会将该 base64 字符串解码为字节。\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\n查看 `/docs` 时，你会看到字段 `data` 期望接收 base64 编码的字节：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\n你可以发送如下请求：\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip | 提示\n\n`aGVsbG8=` 是 `hello` 的 base64 编码。\n\n///\n\n随后 Pydantic 会解码该 base64 字符串，并在模型的 `data` 字段中提供原始字节。\n\n你将会收到类似的响应：\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## 用于输出数据的 Pydantic `bytes` { #pydantic-bytes-for-output-data }\n\n对于输出数据，你也可以在模型配置中为 `bytes` 字段使用 `ser_json_bytes`，Pydantic 会在生成 JSON 响应时将字节以 base64 进行序列化。\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## 用于输入和输出数据的 Pydantic `bytes` { #pydantic-bytes-for-input-and-output-data }\n\n当然，你也可以使用同一个配置了 base64 的模型，在接收和发送 JSON 数据时，同时处理输入（使用 `val_json_bytes` 进行验证）和输出（使用 `ser_json_bytes` 进行序列化）。\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/zh/docs/advanced/middleware.md",
    "content": "# 高级中间件 { #advanced-middleware }\n\n用户指南介绍了如何为应用添加[自定义中间件](../tutorial/middleware.md)。\n\n以及如何[使用 `CORSMiddleware` 处理 CORS](../tutorial/cors.md)。\n\n本章学习如何使用其它中间件。\n\n## 添加 ASGI 中间件 { #adding-asgi-middlewares }\n\n因为 **FastAPI** 基于 Starlette，且执行 <abbr title=\"Asynchronous Server Gateway Interface - 异步服务器网关接口\">ASGI</abbr> 规范，所以可以使用任意 ASGI 中间件。\n\n中间件不必是专为 FastAPI 或 Starlette 定制的，只要遵循 ASGI 规范即可。\n\n总之，ASGI 中间件是类，并把 ASGI 应用作为第一个参数。\n\n因此，有些第三方 ASGI 中间件的文档推荐以如下方式使用中间件：\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\n但 FastAPI（实际上是 Starlette）提供了一种更简单的方式，能让内部中间件在处理服务器错误的同时，还能让自定义异常处理器正常运作。\n\n为此，要使用 `app.add_middleware()` （与 CORS 中的示例一样）。\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` 的第一个参数是中间件的类，其它参数则是要传递给中间件的参数。\n\n## 集成中间件 { #integrated-middlewares }\n\n**FastAPI** 为常见用例提供了一些中间件，下面介绍怎么使用这些中间件。\n\n/// note | 技术细节\n\n以下几个示例中也可以使用 `from starlette.middleware.something import SomethingMiddleware`。\n\n**FastAPI** 在 `fastapi.middleware` 中提供的中间件只是为了方便开发者使用，但绝大多数可用的中间件都直接继承自 Starlette。\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\n强制所有传入请求必须是 `https` 或 `wss`。\n\n任何传向 `http` 或 `ws` 的请求都会被重定向至安全方案。\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\n强制所有传入请求都必须正确设置 `Host` 请求头，以防 HTTP 主机头攻击。\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\n支持以下参数：\n\n* `allowed_hosts` - 允许的域名（主机名）列表。`*.example.com` 等通配符域名可以匹配子域名。若要允许任意主机名，可使用 `allowed_hosts=[\"*\"]` 或省略此中间件。\n* `www_redirect` - 若设置为 `True`，对允许主机的非 www 版本的请求将被重定向到其 www 版本。默认为 `True`。\n\n如果传入的请求没有通过验证，则发送 `400` 响应。\n\n## `GZipMiddleware` { #gzipmiddleware }\n\n处理 `Accept-Encoding` 请求头中包含 `\"gzip\"` 请求的 GZip 响应。\n\n中间件会处理标准响应与流响应。\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\n支持以下参数：\n\n* `minimum_size` - 小于该最小字节数的响应不使用 GZip。默认值是 `500`。\n* `compresslevel` - GZip 压缩使用的级别，为 1 到 9 的整数。默认为 `9`。值越低压缩越快但文件更大，值越高压缩越慢但文件更小。\n\n## 其它中间件 { #other-middlewares }\n\n除了上述中间件外，FastAPI 还支持其它 ASGI 中间件。\n\n例如：\n\n* [Uvicorn 的 `ProxyHeadersMiddleware`](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n* [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\n其它可用中间件详见 [Starlette 官档 - 中间件](https://www.starlette.dev/middleware/) 及 [ASGI Awesome 列表](https://github.com/florimondmanca/awesome-asgi)。\n"
  },
  {
    "path": "docs/zh/docs/advanced/openapi-callbacks.md",
    "content": "# OpenAPI 回调 { #openapi-callbacks }\n\n您可以创建一个包含*路径操作*的 API，它会触发对别人创建的*外部 API*的请求（很可能就是那个会“使用”您 API 的同一个开发者）。\n\n当您的 API 应用调用*外部 API*时，这个过程被称为“回调”。因为外部开发者编写的软件会先向您的 API 发送请求，然后您的 API 再进行*回调*，向*外部 API*发送请求（很可能也是该开发者创建的）。\n\n此时，我们需要存档外部 API 的*信息*，比如应该有哪些*路径操作*，请求体应该是什么，应该返回什么响应等。\n\n## 使用回调的应用 { #an-app-with-callbacks }\n\n示例如下。\n\n假设要开发一个创建发票的应用。\n\n发票包括 `id`、`title`（可选）、`customer`、`total` 等属性。\n\nAPI 的用户（外部开发者）要在您的 API 内使用 POST 请求创建一条发票记录。\n\n（假设）您的 API 将：\n\n* 把发票发送至外部开发者的消费者\n* 归集现金\n* 把通知发送至 API 的用户（外部开发者）\n    * 通过（从您的 API）发送 POST 请求至外部 API（即**回调**）来完成\n\n## 常规 **FastAPI** 应用 { #the-normal-fastapi-app }\n\n添加回调前，首先看下常规 API 应用是什么样子。\n\n常规 API 应用包含接收 `Invoice` 请求体的*路径操作*，还有包含回调 URL 的查询参数 `callback_url`。\n\n这部分代码很常规，您对绝大多数代码应该都比较熟悉了：\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip | 提示\n\n`callback_url` 查询参数使用 Pydantic 的 [Url](https://docs.pydantic.dev/latest/api/networks/) 类型。\n\n///\n\n此处唯一比较新的内容是*路径操作装饰器*中的 `callbacks=invoices_callback_router.routes` 参数，下文介绍。\n\n## 存档回调 { #documenting-the-callback }\n\n实际的回调代码高度依赖于您自己的 API 应用。\n\n并且可能每个应用都各不相同。\n\n回调代码可能只有一两行，比如：\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\n但回调最重要的部分可能是，根据 API 要发送给回调请求体的数据等内容，确保您的 API 用户（外部开发者）正确地实现*外部 API*。\n\n因此，我们下一步要做的就是添加代码，为从 API 接收回调的*外部 API*存档。\n\n这部分文档在 `/docs` 下的 Swagger UI 中显示，并且会告诉外部开发者如何构建*外部 API*。\n\n本例没有实现回调本身（只是一行代码），只有文档部分。\n\n/// tip | 提示\n\n实际的回调只是 HTTP 请求。\n\n实现回调时，要使用 [HTTPX](https://www.python-httpx.org) 或 [Requests](https://requests.readthedocs.io/)。\n\n///\n\n## 编写回调文档代码 { #write-the-callback-documentation-code }\n\n应用不执行这部分代码，只是用它来*记录 外部 API* 。\n\n但，您已经知道用 **FastAPI** 创建自动 API 文档有多简单了。\n\n我们要使用与存档*外部 API* 相同的知识...通过创建外部 API 要实现的*路径操作*（您的 API 要调用的）。\n\n/// tip | 提示\n\n编写存档回调的代码时，假设您是*外部开发者*可能会用的上。并且您当前正在实现的是*外部 API*，不是*您自己的 API*。\n\n临时改变（为外部开发者的）视角能让您更清楚该如何放置*外部 API* 响应和请求体的参数与 Pydantic 模型等。\n\n///\n\n### 创建回调的 `APIRouter` { #create-a-callback-apirouter }\n\n首先，新建包含一些用于回调的 `APIRouter`。\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### 创建回调*路径操作* { #create-the-callback-path-operation }\n\n创建回调*路径操作*也使用之前创建的 `APIRouter`。\n\n它看起来和常规 FastAPI *路径操作*差不多：\n\n* 声明要接收的请求体，例如，`body: InvoiceEvent`\n* 还要声明要返回的响应，例如，`response_model=InvoiceEventReceived`\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\n回调*路径操作*与常规*路径操作*有两点主要区别：\n\n* 它不需要任何实际的代码，因为应用不会调用这段代码。它只是用于存档*外部 API*。因此，函数的内容只需要 `pass` 就可以了\n* *路径*可以包含 [OpenAPI 3 表达式](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression)（详见下文），可以使用带参数的变量，以及发送至您的 API 的原始请求的部分\n\n### 回调路径表达式 { #the-callback-path-expression }\n\n回调*路径*支持包含发送给您的 API 的原始请求的部分的 [OpenAPI 3 表达式](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression)。\n\n本例中是 `str`：\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\n因此，如果您的 API 用户（外部开发者）发送请求到您的 API：\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\n使用如下 JSON 请求体：\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\n然后，您的 API 就会处理发票，并在某个点之后，发送回调请求至 `callback_url`（外部 API）：\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\nJSON 请求体包含如下内容：\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\n它会预期*外部 API* 的响应包含如下 JSON 请求体：\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip | 提示\n\n注意，回调 URL 包含 `callback_url`（`https://www.external.org/events`）中的查询参数，还有 JSON 请求体内部的发票 ID（`2expen51ve`）。\n\n///\n\n### 添加回调路由 { #add-the-callback-router }\n\n至此，在上文创建的回调路由里就包含了*回调路径操作*（外部开发者要在外部 API 中实现）。\n\n现在使用 API *路径操作装饰器*的参数 `callbacks`，从回调路由传递属性 `.routes`（实际上只是路由/路径操作的**列表**）：\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip | 提示\n\n注意，不能把路由本身（`invoices_callback_router`）传递给 `callbacks=`，要传递 `invoices_callback_router.routes` 中的 `.routes` 属性。\n\n///\n\n### 查看文档 { #check-the-docs }\n\n现在，启动应用并打开 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n就能看到文档的*路径操作*已经包含了**回调**的内容以及*外部 API*：\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/zh/docs/advanced/openapi-webhooks.md",
    "content": "# OpenAPI 网络钩子 { #openapi-webhooks }\n\n有些情况下，您可能想告诉您的 API **用户**，您的应用程序可以携带一些数据调用*他们的*应用程序（给它们发送请求），通常是为了**通知**某种**事件**。\n\n这意味着，与通常由您的用户向您的 API 发送请求的流程相反，是**您的 API**（或您的应用）可以**向他们的系统**（他们的 API、他们的应用）**发送请求**。\n\n这通常被称为**网络钩子**（Webhook）。\n\n## 使用网络钩子的步骤 { #webhooks-steps }\n\n通常的过程是**您**在代码中**定义**要发送的消息，即**请求的主体**。\n\n您还需要以某种方式定义您的应用程序将在**何时**发送这些请求或事件。\n\n**用户**会以某种方式（例如在某个网页仪表板上）定义您的应用程序发送这些请求应该使用的 **URL**。\n\n所有关于注册网络钩子的 URL 的**逻辑**以及发送这些请求的实际代码都由您决定。您可以在**自己的代码**中以任何想要的方式来编写它。\n\n## 使用 `FastAPI` 和 OpenAPI 文档化网络钩子 { #documenting-webhooks-with-fastapi-and-openapi }\n\n使用 **FastAPI**，您可以利用 OpenAPI 来自定义这些网络钩子的名称、您的应用可以发送的 HTTP 操作类型（例如 `POST`、`PUT` 等）以及您的应用将发送的**请求体**。\n\n这能让您的用户更轻松地**实现他们的 API** 来接收您的**网络钩子**请求，他们甚至可能能够自动生成一些自己的 API 代码。\n\n/// info | 信息\n\n网络钩子在 OpenAPI 3.1.0 及以上版本中可用，FastAPI `0.99.0` 及以上版本支持。\n\n///\n\n## 带有网络钩子的应用程序 { #an-app-with-webhooks }\n\n当您创建一个 **FastAPI** 应用程序时，有一个 `webhooks` 属性可以用来定义网络钩子，方式与您定义*路径操作*的时候相同，例如使用 `@app.webhooks.post()` 。\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\n您定义的网络钩子将被包含在 `OpenAPI` 的架构中，并出现在自动生成的**文档 UI** 中。\n\n/// info | 信息\n\n`app.webhooks` 对象实际上只是一个 `APIRouter` ，与您在使用多个文件来构建应用程序时所使用的类型相同。\n\n///\n\n请注意，使用网络钩子时，您实际上并没有声明一个*路径*（比如 `/items/` ），您传递的文本只是这个网络钩子的**标识符**（事件的名称）。例如在 `@app.webhooks.post(\"new-subscription\")` 中，网络钩子的名称是 `new-subscription` 。\n\n这是因为我们预计**您的用户**会以其他方式（例如通过网页仪表板）来定义他们希望接收网络钩子的请求的实际 **URL 路径**。\n\n### 查看文档 { #check-the-docs }\n\n现在您可以启动您的应用程序并访问 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n您会看到您的文档不仅有正常的*路径操作*显示，现在还多了一些**网络钩子**：\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/zh/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# 路径操作的高级配置 { #path-operation-advanced-configuration }\n\n## OpenAPI 的 operationId { #openapi-operationid }\n\n/// warning\n\n如果你并非 OpenAPI 的“专家”，你可能不需要这部分内容。\n\n///\n\n你可以在 *路径操作* 中通过参数 `operation_id` 设置要使用的 OpenAPI `operationId`。\n\n务必确保每个操作的 `operation_id` 都是唯一的。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### 使用 *路径操作函数* 的函数名作为 operationId { #using-the-path-operation-function-name-as-the-operationid }\n\n如果你想用 API 的函数名作为 `operationId`，你可以遍历所有路径操作，并使用它们的 `APIRoute.name` 重写每个 *路径操作* 的 `operation_id`。\n\n你应该在添加了所有 *路径操作* 之后执行此操作。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip\n\n如果你手动调用 `app.openapi()`，你应该在此之前更新 `operationId`。\n\n///\n\n/// warning\n\n如果你这样做，务必确保你的每个 *路径操作函数* 的名字唯一。\n\n即使它们在不同的模块中（Python 文件）。\n\n///\n\n## 从 OpenAPI 中排除 { #exclude-from-openapi }\n\n使用参数 `include_in_schema` 并将其设置为 `False`，来从生成的 OpenAPI 方案中排除一个 *路径操作*（这样一来，就从自动化文档系统中排除掉了）：\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## 来自 docstring 的高级描述 { #advanced-description-from-docstring }\n\n你可以限制 *路径操作函数* 的 `docstring` 中用于 OpenAPI 的行数。\n\n添加一个 `\\f`（一个“换页”的转义字符）可以使 **FastAPI** 在那一位置截断用于 OpenAPI 的输出。\n\n剩余部分不会出现在文档中，但是其他工具（比如 Sphinx）可以使用剩余部分。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## 附加响应 { #additional-responses }\n\n你可能已经见过如何为一个 *路径操作* 声明 `response_model` 和 `status_code`。\n\n这定义了该 *路径操作* 主响应的元数据。\n\n你也可以为它声明带有各自模型、状态码等的附加响应。\n\n文档中有一个完整章节，你可以阅读这里的[OpenAPI 中的附加响应](additional-responses.md)。\n\n## OpenAPI Extra { #openapi-extra }\n\n当你在应用中声明一个 *路径操作* 时，**FastAPI** 会自动生成与该 *路径操作* 相关的元数据，以包含到 OpenAPI 方案中。\n\n/// note | 技术细节\n\n在 OpenAPI 规范中，这被称为 [Operation 对象](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object)。\n\n///\n\n它包含关于该 *路径操作* 的所有信息，并用于生成自动文档。\n\n它包括 `tags`、`parameters`、`requestBody`、`responses` 等。\n\n这个特定于 *路径操作* 的 OpenAPI 方案通常由 **FastAPI** 自动生成，但你也可以扩展它。\n\n/// tip\n\n这是一个较低层级的扩展点。\n\n如果你只需要声明附加响应，更方便的方式是使用[OpenAPI 中的附加响应](additional-responses.md)。\n\n///\n\n你可以使用参数 `openapi_extra` 扩展某个 *路径操作* 的 OpenAPI 方案。\n\n### OpenAPI 扩展 { #openapi-extensions }\n\n例如，这个 `openapi_extra` 可用于声明 [OpenAPI 扩展](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions)：\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\n当你打开自动 API 文档时，你的扩展会显示在该 *路径操作* 的底部。\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\n如果你查看最终生成的 OpenAPI（在你的 API 的 `/openapi.json`），你也会看到你的扩展作为该 *路径操作* 的一部分：\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### 自定义 OpenAPI 路径操作方案 { #custom-openapi-path-operation-schema }\n\n`openapi_extra` 中的字典会与该 *路径操作* 自动生成的 OpenAPI 方案进行深度合并。\n\n因此，你可以在自动生成的方案上添加额外数据。\n\n例如，你可以决定用自己的代码读取并验证请求，而不使用 FastAPI 与 Pydantic 的自动功能，但你仍然希望在 OpenAPI 方案中定义该请求。\n\n你可以用 `openapi_extra` 来做到：\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\n在这个示例中，我们没有声明任何 Pydantic 模型。事实上，请求体甚至没有被 <dfn title=\"从某种纯文本格式（如字节）转换为 Python 对象\">解析</dfn> 为 JSON，而是直接以 `bytes` 读取，并由函数 `magic_data_reader()` 以某种方式负责解析。\n\n尽管如此，我们仍然可以声明请求体的预期方案。\n\n### 自定义 OpenAPI 内容类型 { #custom-openapi-content-type }\n\n使用同样的技巧，你可以用一个 Pydantic 模型来定义 JSON Schema，然后把它包含到该 *路径操作* 的自定义 OpenAPI 方案部分中。\n\n即使请求中的数据类型不是 JSON，你也可以这样做。\n\n例如，在这个应用中我们不使用 FastAPI 集成的从 Pydantic 模型提取 JSON Schema 的功能，也不使用对 JSON 的自动校验。实际上，我们将请求的内容类型声明为 YAML，而不是 JSON：\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\n尽管我们没有使用默认的集成功能，我们仍然使用 Pydantic 模型手动生成我们想以 YAML 接收的数据的 JSON Schema。\n\n然后我们直接使用请求并将请求体提取为 `bytes`。这意味着 FastAPI 甚至不会尝试将请求负载解析为 JSON。\n\n接着在我们的代码中，我们直接解析该 YAML 内容，然后再次使用同一个 Pydantic 模型来验证该 YAML 内容：\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip\n\n这里我们复用了同一个 Pydantic 模型。\n\n但同样地，我们也可以用其他方式对其进行验证。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/advanced/response-change-status-code.md",
    "content": "# 响应 - 更改状态码 { #response-change-status-code }\n\n你可能之前已经了解到，你可以设置默认的[响应状态码](../tutorial/response-status-code.md)。\n\n但在某些情况下，你需要返回一个不同于默认值的状态码。\n\n## 使用场景 { #use-case }\n\n例如，假设你想默认返回一个HTTP状态码为“OK”`200`。\n\n但如果数据不存在，你想创建它，并返回一个HTTP状态码为“CREATED”`201`。\n\n但你仍然希望能够使用`response_model`过滤和转换你返回的数据。\n\n对于这些情况，你可以使用一个`Response`参数。\n\n## 使用 `Response` 参数 { #use-a-response-parameter }\n\n你可以在你的*路径操作函数*中声明一个`Response`类型的参数（就像你可以为cookies和头部做的那样）。\n\n然后你可以在这个*临时*响应对象中设置`status_code`。\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\n然后你可以像平常一样返回任何你需要的对象（例如一个`dict`或者一个数据库模型）。\n\n如果你声明了一个`response_model`，它仍然会被用来过滤和转换你返回的对象。\n\n**FastAPI**将使用这个*临时*响应来提取状态码（也包括cookies和头部），并将它们放入包含你返回的值的最终响应中，该响应由任何`response_model`过滤。\n\n你也可以在依赖项中声明`Response`参数，并在其中设置状态码。但请注意，最后设置的状态码将会生效。\n"
  },
  {
    "path": "docs/zh/docs/advanced/response-cookies.md",
    "content": "# 响应Cookies { #response-cookies }\n\n## 使用 `Response` 参数 { #use-a-response-parameter }\n\n你可以在 *路径操作函数* 中定义一个类型为 `Response` 的参数，这样你就可以在这个临时响应对象中设置cookie了。\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\n而且你还可以根据你的需要响应不同的对象，比如常用的 `dict`，数据库model等。\n\n如果你定义了 `response_model`，程序会自动根据`response_model`来过滤和转换你响应的对象。\n\n**FastAPI** 会使用这个 *临时* 响应对象去装在这些cookies信息 (同样还有headers和状态码等信息), 最终会将这些信息和通过`response_model`转化过的数据合并到最终的响应里。\n\n你也可以在依赖中定义`Response`参数，并设置cookie和header。\n\n## 直接响应 `Response` { #return-a-response-directly }\n\n你还可以在直接响应`Response`时直接创建cookies。\n\n为此，你可以按照[直接返回 Response](response-directly.md)中的说明创建一个响应。\n\n然后设置Cookies，并返回：\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip | 提示\n\n需要注意，如果你直接反馈一个response对象，而不是使用`Response`入参，FastAPI则会直接反馈你封装的response对象。\n\n所以你需要确保你响应数据类型的正确性，如：你可以使用`JSONResponse`来兼容JSON的场景。\n\n同时，你也应当仅反馈通过`response_model`过滤过的数据。\n\n///\n\n### 更多信息 { #more-info }\n\n/// note | 技术细节\n\n你也可以使用`from starlette.responses import Response` 或者 `from starlette.responses import JSONResponse`。\n\n为了方便开发者，**FastAPI** 封装了相同数据类型，如`starlette.responses` 和 `fastapi.responses`。不过大部分response对象都是直接引用自Starlette。\n\n因为`Response`对象可以非常便捷的设置headers和cookies，所以 **FastAPI** 同时也封装了`fastapi.Response`。\n\n///\n\n如果你想查看所有可用的参数和选项，可以参考 [Starlette 文档](https://www.starlette.dev/responses/#set-cookie)。\n"
  },
  {
    "path": "docs/zh/docs/advanced/response-directly.md",
    "content": "# 直接返回响应 { #return-a-response-directly }\n\n当你创建一个 **FastAPI** *路径操作* 时，你可以正常返回以下任意一种数据：`dict`，`list`，Pydantic 模型，数据库模型等等。\n\n如果你声明了 [响应模型](../tutorial/response-model.md)，FastAPI 会使用它通过 Pydantic 将数据序列化为 JSON。\n\n如果你没有声明响应模型，**FastAPI** 会使用在 [JSON 兼容编码器](../tutorial/encoder.md) 中阐述的 `jsonable_encoder`。\n然后，**FastAPI** 会在后台将这些兼容 JSON 的数据（比如字典）放到一个 `JSONResponse` 中，该 `JSONResponse` 会用来发送响应给客户端。\n\n但是你可以在你的 *路径操作* 中直接返回一个 `JSONResponse`。\n\n/// tip | 提示\n\n通常使用 [响应模型](../tutorial/response-model.md) 会比直接返回 `JSONResponse` 拥有更好的性能，因为它会在 Rust 中使用 Pydantic 序列化数据。\n\n///\n\n## 返回 `Response` { #return-a-response }\n\n事实上，你可以返回任意 `Response` 或者任意 `Response` 的子类。\n\n/// info | 信息\n\n`JSONResponse` 本身是一个 `Response` 的子类。\n\n///\n\n当你返回一个 `Response` 时，**FastAPI** 会直接传递它。\n\n**FastAPI** 不会用 Pydantic 模型做任何数据转换，不会将响应内容转换成任何类型，等等。\n\n这种特性给你极大的可扩展性。你可以返回任何数据类型，重写任何数据声明或者校验，等等。\n\n这也带来了很大的责任。你必须确保你返回的数据是正确的、格式正确、可被序列化，等等。\n\n## 在 `Response` 中使用 `jsonable_encoder` { #using-the-jsonable-encoder-in-a-response }\n\n由于 **FastAPI** 并未对你返回的 `Response` 做任何改变，你必须确保你已经准备好响应内容。\n\n例如，如果不首先将 Pydantic 模型转换为 `dict`，并将所有数据类型（如 `datetime`、`UUID` 等）转换为兼容 JSON 的类型，则不能将其放入 `JSONResponse` 中。\n\n对于这些情况，在将数据传递给响应之前，你可以使用 `jsonable_encoder` 来转换你的数据：\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | 技术细节\n\n你也可以使用 `from starlette.responses import JSONResponse`。\n\n出于方便，**FastAPI** 会提供与 `starlette.responses` 相同的 `fastapi.responses` 给开发者。但是大多数可用的响应都直接来自 Starlette。\n\n///\n\n## 返回自定义 `Response` { #returning-a-custom-response }\n\n上面的例子展示了需要的所有部分，但还不够实用，因为你本可以只是直接返回 `item`，而 **FastAPI** 默认帮你把这个 `item` 放到 `JSONResponse` 中，又默认将其转换成了 `dict` 等等。\n\n现在，让我们看看你如何才能返回一个自定义的响应。\n\n假设你想要返回一个 [XML](https://en.wikipedia.org/wiki/XML) 响应。\n\n你可以把你的 XML 内容放到一个字符串中，放到一个 `Response` 中，然后返回：\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## 响应模型如何工作 { #how-a-response-model-works }\n\n当你在路径操作中声明一个 [响应模型 - 返回类型](../tutorial/response-model.md) 时，**FastAPI** 会使用它通过 Pydantic 将数据序列化为 JSON。\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\n由于这些工作会在 Rust 侧完成，性能将比在常规 Python 中配合 `JSONResponse` 类完成要好得多。\n\n当使用 `response_model` 或返回类型时，FastAPI 不会使用 `jsonable_encoder` 来转换数据（那样会更慢），也不会使用 `JSONResponse` 类。\n\n相反，它会采用使用该响应模型（或返回类型）由 Pydantic 生成的 JSON 字节，并直接返回一个具有正确 JSON 媒体类型（`application/json`）的 `Response`。\n\n## 说明 { #notes }\n\n当你直接返回 `Response` 时，它的数据既没有校验，又不会进行转换（序列化），也不会自动生成文档。\n\n但是你仍可以参考 [OpenAPI 中的额外响应](additional-responses.md) 给响应编写文档。\n\n在后续的章节中你可以了解到如何使用/声明这些自定义的 `Response` 的同时还保留自动化的数据转换和文档等。\n"
  },
  {
    "path": "docs/zh/docs/advanced/response-headers.md",
    "content": "# 响应头 { #response-headers }\n\n## 使用 `Response` 参数 { #use-a-response-parameter }\n\n你可以在你的*路径操作函数*中声明一个 `Response` 类型的参数（就像你可以为 cookies 做的那样）。\n\n然后你可以在这个*临时*响应对象中设置头部。\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\n然后你可以像平常一样返回任何你需要的对象（例如一个 `dict` 或者一个数据库模型）。\n\n如果你声明了一个 `response_model`，它仍然会被用来过滤和转换你返回的对象。\n\n**FastAPI** 将使用这个*临时*响应来提取头部（也包括 cookies 和状态码），并将它们放入包含你返回的值的最终响应中，该响应由任何 `response_model` 过滤。\n\n你也可以在依赖项中声明 `Response` 参数，并在其中设置头部（和 cookies）。\n\n## 直接返回 `Response` { #return-a-response-directly }\n\n你也可以在直接返回 `Response` 时添加头部。\n\n按照[直接返回响应](response-directly.md)中所述创建响应，并将头部作为附加参数传递：\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | 技术细节\n\n你也可以使用 `from starlette.responses import Response` 或 `from starlette.responses import JSONResponse`。\n\n**FastAPI** 提供了与 `fastapi.responses` 相同的 `starlette.responses`，只是为了方便你（开发者）。但是，大多数可用的响应都直接来自 Starlette。\n\n由于 `Response` 经常用于设置头部和 cookies，**FastAPI** 还在 `fastapi.Response` 中提供了它。\n\n///\n\n## 自定义头部 { #custom-headers }\n\n请注意，可以通过[使用 `X-` 前缀](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)添加自定义专有头部。\n\n但是，如果你有自定义头部，并希望浏览器中的客户端能够看到它们，你需要将它们添加到你的 CORS 配置中（在 [CORS（跨源资源共享）](../tutorial/cors.md) 中阅读更多），使用在 [Starlette 的 CORS 文档](https://www.starlette.dev/middleware/#corsmiddleware)中记录的 `expose_headers` 参数。\n"
  },
  {
    "path": "docs/zh/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP 基础授权 { #http-basic-auth }\n\n最简单的用例是使用 HTTP 基础授权（HTTP Basic Auth）。\n\n在 HTTP 基础授权中，应用需要请求头包含用户名与密码。\n\n如果没有接收到 HTTP 基础授权，就返回 HTTP 401 `\"Unauthorized\"` 错误。\n\n并返回响应头 `WWW-Authenticate`，其值为 `Basic`，以及可选的 `realm` 参数。\n\nHTTP 基础授权让浏览器显示内置的用户名与密码提示。\n\n输入用户名与密码后，浏览器会把它们自动发送至请求头。\n\n## 简单的 HTTP 基础授权 { #simple-http-basic-auth }\n\n* 导入 `HTTPBasic` 与 `HTTPBasicCredentials`\n* 使用 `HTTPBasic` 创建**安全方案**\n* 在*路径操作*的依赖项中使用 `security`\n* 返回类型为 `HTTPBasicCredentials` 的对象：\n    * 包含发送的 `username` 与 `password`\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\n第一次打开 URL（或在 API 文档中点击 **Execute** 按钮）时，浏览器要求输入用户名与密码：\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## 检查用户名 { #check-the-username }\n\n以下是更完整的示例。\n\n使用依赖项检查用户名与密码是否正确。\n\n为此要使用 Python 标准模块 [`secrets`](https://docs.python.org/3/library/secrets.html) 检查用户名与密码。\n\n`secrets.compare_digest()` 需要仅包含 ASCII 字符（英语字符）的 `bytes` 或 `str`，这意味着它不适用于像`á`一样的字符，如 `Sebastián`。\n\n为了解决这个问题，我们首先将 `username` 和 `password` 转换为使用 UTF-8 编码的 `bytes` 。\n\n然后我们可以使用 `secrets.compare_digest()` 来确保 `credentials.username` 是 `\"stanleyjobson\"`，且 `credentials.password` 是`\"swordfish\"`。\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\n这类似于：\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # Return some error\n    ...\n```\n\n但使用 `secrets.compare_digest()`，可以防御**时差攻击**，更加安全。\n\n### 时差攻击 { #timing-attacks }\n\n什么是**时差攻击**？\n\n假设攻击者试图猜出用户名与密码。\n\n他们发送用户名为 `johndoe`，密码为 `love123` 的请求。\n\n然后，Python 代码执行如下操作：\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\n但就在 Python 比较完 `johndoe` 的第一个字母 `j` 与 `stanleyjobson` 的 `s` 时，Python 就已经知道这两个字符串不相同了，它会这么想，**没必要浪费更多时间执行剩余字母的对比计算了**。应用立刻就会返回**错误的用户或密码**。\n\n但接下来，攻击者继续尝试 `stanleyjobsox` 和 密码 `love123`。\n\n应用代码会执行类似下面的操作：\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\n此时，Python 要对比 `stanleyjobsox` 与 `stanleyjobson` 中的 `stanleyjobso`，才能知道这两个字符串不一样。因此会多花费几微秒来返回**错误的用户或密码**。\n\n#### 反应时间对攻击者的帮助 { #the-time-to-answer-helps-the-attackers }\n\n通过服务器花费了更多微秒才发送**错误的用户或密码**响应，攻击者会知道猜对了一些内容，起码开头字母是正确的。\n\n然后，他们就可以放弃 `johndoe`，再用类似 `stanleyjobsox` 的内容进行尝试。\n\n#### **专业**攻击 { #a-professional-attack }\n\n当然，攻击者不用手动操作，而是编写每秒能执行成千上万次测试的攻击程序，每次都会找到更多正确字符。\n\n但是，在您的应用的**帮助**下，攻击者利用时间差，就能在几分钟或几小时内，以这种方式猜出正确的用户名和密码。\n\n#### 使用 `secrets.compare_digest()` 修补 { #fix-it-with-secrets-compare-digest }\n\n在此，代码中使用了 `secrets.compare_digest()`。\n\n简单的说，它使用相同的时间对比 `stanleyjobsox` 和 `stanleyjobson`，还有 `johndoe` 和 `stanleyjobson`。对比密码时也一样。\n\n在代码中使用 `secrets.compare_digest()` ，就可以安全地防御这整类安全攻击。\n\n### 返回错误 { #return-the-error }\n\n检测到凭证不正确后，返回 `HTTPException` 及状态码 401（与无凭证时返回的内容一样），并添加响应头 `WWW-Authenticate`，让浏览器再次显示登录提示：\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/zh/docs/advanced/security/index.md",
    "content": "# 高级安全 { #advanced-security }\n\n## 附加特性 { #additional-features }\n\n除 [教程 - 用户指南: 安全性](../../tutorial/security/index.md) 中涵盖的功能之外，还有一些额外的功能来处理安全性。\n\n/// tip | 提示\n\n接下来的章节**并不一定是 \"高级的\"**。\n\n而且对于你的使用场景来说，解决方案很可能就在其中。\n\n///\n\n## 先阅读教程 { #read-the-tutorial-first }\n\n接下来的部分假设你已经阅读了主要的 [教程 - 用户指南: 安全性](../../tutorial/security/index.md)。\n\n它们都基于相同的概念，但支持一些额外的功能。\n"
  },
  {
    "path": "docs/zh/docs/advanced/security/oauth2-scopes.md",
    "content": "# OAuth2 作用域 { #oauth2-scopes }\n\n你可以在 **FastAPI** 中直接使用 OAuth2 作用域（Scopes），它们已无缝集成。\n\n这样你就可以按照 OAuth2 标准，构建更精细的权限系统，并将其集成进你的 OpenAPI 应用（以及 API 文档）中。\n\n带作用域的 OAuth2 是很多大型身份验证提供商使用的机制，例如 Facebook、Google、GitHub、Microsoft、X (Twitter) 等。它们用它来为用户和应用授予特定权限。\n\n每次你“使用” Facebook、Google、GitHub、Microsoft、X (Twitter) “登录”时，该应用就在使用带作用域的 OAuth2。\n\n本节将介绍如何在你的 **FastAPI** 应用中，使用相同的带作用域的 OAuth2 管理认证与授权。\n\n/// warning | 警告\n\n本节内容相对进阶，如果你刚开始，可以先跳过。\n\n你并不一定需要 OAuth2 作用域，你也可以用你自己的方式处理认证与授权。\n\n但带作用域的 OAuth2 能很好地集成进你的 API（通过 OpenAPI）和 API 文档。\n\n不过，无论如何，你都可以在代码中按需强制这些作用域，或任何其它安全/授权需求。\n\n很多情况下，带作用域的 OAuth2 可能有点“大材小用”。\n\n但如果你确实需要它，或者只是好奇，请继续阅读。\n\n///\n\n## OAuth2 作用域与 OpenAPI { #oauth2-scopes-and-openapi }\n\nOAuth2 规范将“作用域”定义为由空格分隔的字符串列表。\n\n这些字符串的内容可以是任意格式，但不应包含空格。\n\n这些作用域表示“权限”。\n\n在 OpenAPI（例如 API 文档）中，你可以定义“安全方案”（security schemes）。\n\n当这些安全方案使用 OAuth2 时，你还可以声明并使用作用域。\n\n每个“作用域”只是一个（不带空格的）字符串。\n\n它们通常用于声明特定的安全权限，例如：\n\n* 常见示例：`users:read` 或 `users:write`\n* Facebook / Instagram 使用 `instagram_basic`\n* Google 使用 `https://www.googleapis.com/auth/drive`\n\n/// info | 信息\n\n在 OAuth2 中，“作用域”只是一个声明所需特定权限的字符串。\n\n是否包含像 `:` 这样的字符，或者是不是一个 URL，并不重要。\n\n这些细节取决于具体实现。\n\n对 OAuth2 而言，它们都只是字符串。\n\n///\n\n## 全局纵览 { #global-view }\n\n首先，让我们快速看看与**用户指南**中 [OAuth2 实现密码（含哈希）、Bearer + JWT 令牌](../../tutorial/security/oauth2-jwt.md) 示例相比有哪些变化。现在开始使用 OAuth2 作用域：\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\n下面我们逐步回顾这些更改。\n\n## OAuth2 安全方案 { #oauth2-security-scheme }\n\n第一个变化是：我们在声明 OAuth2 安全方案时，添加了两个可用的作用域 `me` 和 `items`。\n\n参数 `scopes` 接收一个 `dict`，以作用域为键、描述为值：\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\n因为我们现在声明了这些作用域，所以当你登录/授权时，它们会显示在 API 文档里。\n\n你可以选择要授予访问权限的作用域：`me` 和 `items`。\n\n这与使用 Facebook、Google、GitHub 等登录时授予权限的机制相同：\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## 带作用域的 JWT 令牌 { #jwt-token-with-scopes }\n\n现在，修改令牌的*路径操作*以返回请求的作用域。\n\n我们仍然使用 `OAuth2PasswordRequestForm`。它包含 `scopes` 属性，其值是 `list[str]`，包含请求中接收到的每个作用域。\n\n我们把这些作用域作为 JWT 令牌的一部分返回。\n\n/// danger | 危险\n\n为简单起见，此处我们只是把接收到的作用域直接添加到了令牌中。\n\n但在你的应用里，为了安全起见，你应该只添加该用户实际能够拥有的作用域，或你预先定义的作用域。\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## 在*路径操作*与依赖项中声明作用域 { #declare-scopes-in-path-operations-and-dependencies }\n\n现在我们声明，路径操作 `/users/me/items/` 需要作用域 `items`。\n\n为此，从 `fastapi` 导入并使用 `Security`。\n\n你可以用 `Security` 来声明依赖（就像 `Depends` 一样），但 `Security` 还接收一个 `scopes` 参数，其值是作用域（字符串）列表。\n\n在这里，我们把依赖函数 `get_current_active_user` 传给 `Security`（就像用 `Depends` 一样）。\n\n同时还传入一个作用域 `list`，此处仅包含一个作用域：`items`（也可以包含更多）。\n\n依赖函数 `get_current_active_user` 也可以声明子依赖，不仅可以用 `Depends`，也可以用 `Security`。它声明了自己的子依赖函数（`get_current_user`），并添加了更多的作用域需求。\n\n在这个例子里，它需要作用域 `me`（也可以需要多个作用域）。\n\n/// note | 注意\n\n不必在不同位置添加不同的作用域。\n\n这里这样做，是为了演示 **FastAPI** 如何处理在不同层级声明的作用域。\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | 技术细节\n\n`Security` 实际上是 `Depends` 的子类，它只多了一个我们稍后会看到的参数。\n\n但当你使用 `Security` 而不是 `Depends` 时，**FastAPI** 会知道它可以声明安全作用域，在内部使用它们，并用 OpenAPI 文档化 API。\n\n另外，从 `fastapi` 导入的 `Query`、`Path`、`Depends`、`Security` 等，实际上都是返回特殊类的函数。\n\n///\n\n## 使用 `SecurityScopes` { #use-securityscopes }\n\n现在更新依赖项 `get_current_user`。\n\n上面那些依赖会用到它。\n\n这里我们使用之前创建的同一个 OAuth2 方案，并把它声明为依赖：`oauth2_scheme`。\n\n因为这个依赖函数本身没有任何作用域需求，所以我们可以用 `Depends(oauth2_scheme)`，当不需要指定安全作用域时，不必使用 `Security`。\n\n我们还声明了一个从 `fastapi.security` 导入的特殊参数 `SecurityScopes` 类型。\n\n这个 `SecurityScopes` 类类似于 `Request`（`Request` 用来直接获取请求对象）。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## 使用 `scopes` { #use-the-scopes }\n\n参数 `security_scopes` 的类型是 `SecurityScopes`。\n\n它会有一个 `scopes` 属性，包含一个列表，里面是它自身以及所有把它作为子依赖的依赖项所需要的所有作用域。也就是说，所有“依赖者”……这可能有点绕，下面会再次解释。\n\n`security_scopes` 对象（类型为 `SecurityScopes`）还提供了一个 `scope_str` 属性，它是一个用空格分隔这些作用域的单个字符串（我们将会用到它）。\n\n我们创建一个 `HTTPException`，后面可以在多个位置复用（`raise`）它。\n\n在这个异常中，我们包含所需的作用域（如果有的话），以空格分隔的字符串（使用 `scope_str`）。我们把这个包含作用域的字符串放在 `WWW-Authenticate` 响应头中（这是规范要求的一部分）。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## 校验 `username` 与数据形状 { #verify-the-username-and-data-shape }\n\n我们校验是否获取到了 `username`，并提取作用域。\n\n然后使用 Pydantic 模型验证这些数据（捕获 `ValidationError` 异常），如果读取 JWT 令牌或用 Pydantic 验证数据时出错，就抛出我们之前创建的 `HTTPException`。\n\n为此，我们给 Pydantic 模型 `TokenData` 添加了一个新属性 `scopes`。\n\n通过用 Pydantic 验证数据，我们可以确保确实得到了例如一个由作用域组成的 `list[str]`，以及一个 `str` 类型的 `username`。\n\n而不是，例如得到一个 `dict` 或其它什么，这可能会在后续某个时刻破坏应用，形成安全风险。\n\n我们还验证是否存在该用户名的用户，如果没有，就抛出前面创建的同一个异常。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## 校验 `scopes` { #verify-the-scopes }\n\n现在我们要验证，这个依赖以及所有依赖者（包括*路径操作*）所需的所有作用域，是否都包含在接收到的令牌里的作用域中，否则就抛出 `HTTPException`。\n\n为此，我们使用 `security_scopes.scopes`，它包含一个由这些作用域组成的 `list[str]`。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## 依赖树与作用域 { #dependency-tree-and-scopes }\n\n再次回顾这个依赖树与作用域。\n\n由于 `get_current_active_user` 依赖把 `get_current_user` 作为子依赖，因此在 `get_current_active_user` 中声明的作用域 `\"me\"` 会被包含在传给 `get_current_user` 的 `security_scopes.scopes` 所需作用域列表中。\n\n*路径操作*本身也声明了一个作用域 `\"items\"`，它也会包含在传给 `get_current_user` 的 `security_scopes.scopes` 列表中。\n\n依赖与作用域的层级结构如下：\n\n* *路径操作* `read_own_items` 包含：\n    * 带有依赖的必需作用域 `[\"items\"]`：\n    * `get_current_active_user`：\n        *  依赖函数 `get_current_active_user` 包含：\n            * 带有依赖的必需作用域 `[\"me\"]`：\n            * `get_current_user`：\n                * 依赖函数 `get_current_user` 包含：\n                    * 自身不需要任何作用域。\n                    * 一个使用 `oauth2_scheme` 的依赖。\n                    * 一个类型为 `SecurityScopes` 的 `security_scopes` 参数：\n                        * 该 `security_scopes` 参数有一个 `scopes` 属性，它是一个包含上面所有已声明作用域的 `list`，因此：\n                            * 对于*路径操作* `read_own_items`，`security_scopes.scopes` 将包含 `[\"me\", \"items\"]`。\n                            * 对于*路径操作* `read_users_me`，`security_scopes.scopes` 将包含 `[\"me\"]`，因为它在依赖 `get_current_active_user` 中被声明。\n                            * 对于*路径操作* `read_system_status`，`security_scopes.scopes` 将包含 `[]`（空列表），因为它既没有声明任何带 `scopes` 的 `Security`，其依赖 `get_current_user` 也没有声明任何 `scopes`。\n\n/// tip | 提示\n\n这里重要且“神奇”的地方是，`get_current_user` 在检查每个*路径操作*时会得到不同的 `scopes` 列表。\n\n这一切都取决于为该特定*路径操作*在其自身以及依赖树中的每个依赖里声明的 `scopes`。\n\n///\n\n## 关于 `SecurityScopes` 的更多细节 { #more-details-about-securityscopes }\n\n你可以在任意位置、多个位置使用 `SecurityScopes`，不一定非得在“根”依赖里。\n\n它总会包含当前 `Security` 依赖中以及所有依赖者在“该特定”*路径操作*和“该特定”依赖树里声明的安全作用域。\n\n因为 `SecurityScopes` 会包含依赖者声明的所有作用域，你可以在一个核心依赖函数里用它验证令牌是否具有所需作用域，然后在不同的*路径操作*里声明不同的作用域需求。\n\n它们会针对每个*路径操作*分别检查。\n\n## 查看文档 { #check-it }\n\n打开 API 文档，你可以进行身份验证，并指定要授权的作用域。\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n如果你不选择任何作用域，你依然会“通过认证”，但当你访问 `/users/me/` 或 `/users/me/items/` 时，会收到一个错误，提示你没有足够的权限。你仍然可以访问 `/status/`。\n\n如果你选择了作用域 `me`，但没有选择作用域 `items`，你可以访问 `/users/me/`，但不能访问 `/users/me/items/`。\n\n当第三方应用使用用户提供的令牌访问这些*路径操作*时，也会发生同样的情况，取决于用户授予该应用了多少权限。\n\n## 关于第三方集成 { #about-third-party-integrations }\n\n在这个示例中我们使用的是 OAuth2 的“password”流。\n\n当我们登录自己的应用（很可能还有我们自己的前端）时，这是合适的。\n\n因为我们可以信任它来接收 `username` 和 `password`，毕竟我们掌控它。\n\n但如果你在构建一个 OAuth2 应用，让其它应用来连接（也就是说，你在构建等同于 Facebook、Google、GitHub 等的身份验证提供商），你应该使用其它的流。\n\n最常见的是隐式流（implicit flow）。\n\n最安全的是代码流（authorization code flow），但实现更复杂，需要更多步骤。也因为更复杂，很多提供商最终会建议使用隐式流。\n\n/// note | 注意\n\n每个身份验证提供商常常会用不同的方式给它们的流命名，以融入自己的品牌。\n\n但归根结底，它们实现的都是同一个 OAuth2 标准。\n\n///\n\n**FastAPI** 在 `fastapi.security.oauth2` 中为所有这些 OAuth2 身份验证流提供了工具。\n\n## 装饰器 `dependencies` 中的 `Security` { #security-in-decorator-dependencies }\n\n就像你可以在装饰器的 `dependencies` 参数中定义 `Depends` 的 `list`（详见[路径操作装饰器依赖项](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)），你也可以在那儿配合 `Security` 使用 `scopes`。\n"
  },
  {
    "path": "docs/zh/docs/advanced/settings.md",
    "content": "# 设置和环境变量 { #settings-and-environment-variables }\n\n在许多情况下，你的应用可能需要一些外部设置或配置，例如密钥、数据库凭据、电子邮件服务的凭据等。\n\n这些设置中的大多数是可变的（可能会改变），例如数据库 URL。并且很多可能是敏感的，比如密钥。\n\n因此，通常会将它们提供为由应用程序读取的环境变量。\n\n/// tip | 提示\n\n要理解环境变量，你可以阅读[环境变量](../environment-variables.md)。\n\n///\n\n## 类型和验证 { #types-and-validation }\n\n这些环境变量只能处理文本字符串，因为它们在 Python 之外，并且必须与其他程序及系统的其余部分兼容（甚至与不同的操作系统，如 Linux、Windows、macOS）。\n\n这意味着，在 Python 中从环境变量读取的任何值都是 `str` 类型，任何到不同类型的转换或任何验证都必须在代码中完成。\n\n## Pydantic 的 `Settings` { #pydantic-settings }\n\n幸运的是，Pydantic 提供了一个很好的工具来处理来自环境变量的这些设置：[Pydantic：Settings 管理](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)。\n\n### 安装 `pydantic-settings` { #install-pydantic-settings }\n\n首先，确保你创建并激活了[虚拟环境](../virtual-environments.md)，然后安装 `pydantic-settings` 包：\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\n当你用以下方式安装 `all` 扩展时，它也会被一并安装：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### 创建 `Settings` 对象 { #create-the-settings-object }\n\n从 Pydantic 导入 `BaseSettings` 并创建一个子类，这与创建 Pydantic 模型非常相似。\n\n与 Pydantic 模型一样，用类型注解声明类属性，也可以指定默认值。\n\n你可以使用与 Pydantic 模型相同的验证功能和工具，例如不同的数据类型，以及使用 `Field()` 进行附加验证。\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip | 提示\n\n如果你想要一个可以快速复制粘贴的示例，请不要使用这个示例，使用下面最后一个示例。\n\n///\n\n当你创建该 `Settings` 类的实例（此处是 `settings` 对象）时，Pydantic 会以不区分大小写的方式读取环境变量，因此，大写变量 `APP_NAME` 仍会用于属性 `app_name`。\n\n接着它会转换并验证数据。因此，当你使用该 `settings` 对象时，你将获得你声明的类型的数据（例如 `items_per_user` 将是 `int`）。\n\n### 使用 `settings` { #use-the-settings }\n\n然后你可以在应用中使用新的 `settings` 对象：\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### 运行服务器 { #run-the-server }\n\n接下来，运行服务器，并把配置作为环境变量传入，例如你可以设置 `ADMIN_EMAIL` 和 `APP_NAME`：\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip | 提示\n\n要为单个命令设置多个环境变量，只需用空格分隔它们，并把它们都放在命令前面。\n\n///\n\n然后，`admin_email` 设置将为 `\"deadpool@example.com\"`。\n\n`app_name` 将为 `\"ChimichangApp\"`。\n\n而 `items_per_user` 会保持默认值 `50`。\n\n## 在另一个模块中放置设置 { #settings-in-another-module }\n\n你可以把这些设置放在另一个模块文件中，就像你在[更大的应用 - 多个文件](../tutorial/bigger-applications.md)中看到的那样。\n\n例如，可以有一个 `config.py` 文件：\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\n然后在 `main.py` 文件中使用它：\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip | 提示\n\n你还需要一个 `__init__.py` 文件，就像你在[更大的应用 - 多个文件](../tutorial/bigger-applications.md)中看到的那样。\n\n///\n\n## 在依赖项中提供设置 { #settings-in-a-dependency }\n\n在某些情况下，从依赖项中提供设置可能更有用，而不是在所有地方都使用一个全局的 `settings` 对象。\n\n这在测试期间尤其有用，因为可以很容易地用你自己的自定义设置覆盖依赖项。\n\n### 配置文件 { #the-config-file }\n\n延续上一个示例，你的 `config.py` 文件可能如下所示：\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\n注意，现在我们不再创建默认实例 `settings = Settings()`。\n\n### 主应用文件 { #the-main-app-file }\n\n现在我们创建一个依赖项，返回一个新的 `config.Settings()`。\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip | 提示\n\n我们稍后会讨论 `@lru_cache`。\n\n目前你可以把 `get_settings()` 当作普通函数。\n\n///\n\n然后我们可以在路径操作函数中将其作为依赖项引入，并在需要的任何地方使用它。\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### 设置与测试 { #settings-and-testing }\n\n接着，在测试期间，通过为 `get_settings` 创建依赖项覆盖，就可以很容易地提供一个不同的设置对象：\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\n在依赖项覆盖中，我们在创建新的 `Settings` 对象时为 `admin_email` 设置了一个新值，然后返回该新对象。\n\n然后我们可以测试它是否被使用。\n\n## 读取 `.env` 文件 { #reading-a-env-file }\n\n如果你有许多设置可能经常变化，或在不同环境中不同，那么把它们放进一个文件中，然后像环境变量一样从中读取，可能非常有用。\n\n这种做法非常常见：这些环境变量通常放在名为 `.env` 的文件中，该文件被称为 “dotenv”。\n\n/// tip | 提示\n\n以点（`.`）开头的文件在类 Unix 系统（如 Linux 和 macOS）中是隐藏文件。\n\n但 dotenv 文件并不一定必须是这个确切的文件名。\n\n///\n\nPydantic 支持使用一个外部库来从这类文件中读取。你可以在 [Pydantic Settings：Dotenv（.env）支持](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support) 中阅读更多信息。\n\n/// tip | 提示\n\n要使其工作，你需要执行 `pip install python-dotenv`。\n\n///\n\n### `.env` 文件 { #the-env-file }\n\n你可以有一个 `.env` 文件，内容如下：\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### 从 `.env` 中读取设置 { #read-settings-from-env }\n\n然后更新 `config.py`：\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip | 提示\n\n`model_config` 属性仅用于 Pydantic 配置。你可以在 [Pydantic：概念：配置](https://docs.pydantic.dev/latest/concepts/config/) 中阅读更多信息。\n\n///\n\n这里我们在你的 Pydantic `Settings` 类中定义配置项 `env_file`，并将其设置为我们想要使用的 dotenv 文件名。\n\n### 使用 `lru_cache` 仅创建一次 `Settings` { #creating-the-settings-only-once-with-lru-cache }\n\n从磁盘读取文件通常是一个代价较高（缓慢）的操作，所以你可能希望只在第一次读取，然后复用同一个设置对象，而不是为每个请求都重新读取。\n\n但是，每次我们执行：\n\n```Python\nSettings()\n```\n\n都会创建一个新的 `Settings` 对象，并且在创建时会再次读取 `.env` 文件。\n\n如果依赖项函数是这样的：\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\n我们就会为每个请求创建该对象，并为每个请求读取 `.env` 文件。 ⚠️\n\n但由于我们在顶部使用了 `@lru_cache` 装饰器，`Settings` 对象只会在第一次调用时创建一次。 ✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\n接着，对于后续请求中依赖项里对 `get_settings()` 的任何调用，它不会再次执行 `get_settings()` 的内部代码并创建新的 `Settings` 对象，而是会一遍又一遍地返回第一次调用时返回的那个相同对象。\n\n#### `lru_cache` 技术细节 { #lru-cache-technical-details }\n\n`@lru_cache` 会修改它所装饰的函数，使其返回第一次返回的相同值，而不是每次都重新计算并执行函数代码。\n\n因此，下面的函数会针对每个参数组合执行一次。然后，当以完全相同的参数组合调用该函数时，将重复使用该参数组合先前返回的值。\n\n例如，如果你有一个函数：\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\n你的程序可能会像这样执行：\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Execute function\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: 执行函数代码\n        execute ->> code: 返回结果\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: 返回存储的结果\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: 执行函数代码\n        execute ->> code: 返回结果\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: 执行函数代码\n        execute ->> code: 返回结果\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: 返回存储的结果\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: 返回存储的结果\n    end\n```\n\n在我们的依赖项 `get_settings()` 的情况下，该函数甚至不接受任何参数，因此它始终返回相同的值。\n\n这样，它的行为几乎就像是一个全局变量。但由于它使用了依赖项函数，我们可以在测试时很容易地覆盖它。\n\n`@lru_cache` 是 `functools` 的一部分，它属于 Python 标准库。你可以在 [Python 文档中关于 `@lru_cache` 的章节](https://docs.python.org/3/library/functools.html#functools.lru_cache)阅读更多信息。\n\n## 小结 { #recap }\n\n你可以使用 Pydantic Settings 来处理应用的设置或配置，享受 Pydantic 模型的全部能力。\n\n- 通过使用依赖项，你可以简化测试。\n- 你可以与它一起使用 `.env` 文件。\n- 使用 `@lru_cache` 可以避免为每个请求反复读取 dotenv 文件，同时允许你在测试时进行覆盖。\n"
  },
  {
    "path": "docs/zh/docs/advanced/stream-data.md",
    "content": "# 流式数据 { #stream-data }\n\n如果你要流式传输可以结构化为 JSON 的数据，你应该[流式传输 JSON Lines](../tutorial/stream-json-lines.md)。\n\n但如果你想流式传输纯二进制数据或字符串，可以按下面的方法操作。\n\n/// info | 信息\n\n自 FastAPI 0.134.0 起新增。\n\n///\n\n## 使用场景 { #use-cases }\n\n如果你想流式传输纯字符串，例如直接来自某个 AI LLM 服务的输出，可以使用它。\n\n你也可以用它来流式传输大型二进制文件，在读取的同时按块发送，无需一次性把所有内容读入内存。\n\n你还可以用这种方式流式传输视频或音频，甚至可以在处理的同时生成并发送。\n\n## 使用 `yield` 的 `StreamingResponse` { #a-streamingresponse-with-yield }\n\n如果你在*路径操作函数*中声明 `response_class=StreamingResponse`，你就可以使用 `yield` 依次发送每个数据块。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI 会将每个数据块原样交给 `StreamingResponse`，不会尝试将其转换为 JSON 或做类似处理。\n\n### 非 async 的*路径操作函数* { #non-async-path-operation-functions }\n\n你也可以使用常规的 `def` 函数（不带 `async`），并以相同方式使用 `yield`。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### 无需注解 { #no-annotation }\n\n你其实不需要为流式二进制数据声明返回类型注解。\n\n由于 FastAPI 不会使用 Pydantic 将数据转换为 JSON，也不会以任何方式序列化，在这种情况下，类型注解只供你的编辑器和工具使用，FastAPI 不会使用它。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\n这也意味着，使用 `StreamingResponse` 时，你拥有按需精确生成与编码字节数据的自由，同时也承担相应的责任，它与类型注解无关。🤓\n\n### 流式传输字节 { #stream-bytes }\n\n主要的用例之一是流式传输 `bytes` 而不是字符串，这当然可以做到。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## 自定义 `PNGStreamingResponse` { #a-custom-pngstreamingresponse }\n\n在上面的示例中，虽然按字节流式传输了数据，但响应没有 `Content-Type` 头，因此客户端不知道接收到的数据类型。\n\n你可以创建 `StreamingResponse` 的自定义子类，将 `Content-Type` 头设置为你要流式传输的数据类型。\n\n例如，你可以创建一个 `PNGStreamingResponse`，通过 `media_type` 属性把 `Content-Type` 头设置为 `image/png`：\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\n然后你可以在*路径操作函数*中通过 `response_class=PNGStreamingResponse` 使用这个新类：\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### 模拟文件 { #simulate-a-file }\n\n在这个示例中，我们用 `io.BytesIO` 模拟了一个文件，它是只驻留在内存中的类文件对象，但提供相同的接口。\n\n例如，我们可以像对文件那样迭代它来消费其内容。\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | 技术细节\n\n另外两个变量 `image_base64` 和 `binary_image` 表示一张图像，先用 Base64 编码，再转换为 bytes，最后传给 `io.BytesIO`。\n\n只是为了让它们能和示例放在同一个文件里，便于你直接复制运行。🥚\n\n///\n\n通过使用 `with` 代码块，我们确保在生成器函数（带有 `yield` 的函数）完成后关闭这个类文件对象。也就是在发送完响应之后。\n\n在这个特定示例中这并不那么重要，因为它是一个内存中的假文件（使用 `io.BytesIO`），但对于真实文件，确保在完成相关工作后关闭文件是很重要的。\n\n### 文件与异步 { #files-and-async }\n\n大多数情况下，类文件对象默认与 async 和 await 不兼容。\n\n例如，它们没有 `await file.read()`，也不支持 `async for chunk in file`。\n\n而且很多情况下，读取它们是一个阻塞操作（可能会阻塞事件循环），因为数据来自磁盘或网络。\n\n/// info | 信息\n\n上面的示例其实是个例外，因为 `io.BytesIO` 对象已经在内存中，所以读取它不会阻塞。\n\n但在许多情况下，读取文件或类文件对象会发生阻塞。\n\n///\n\n为避免阻塞事件循环，你可以简单地把*路径操作函数*声明为常规的 `def`（而不是 `async def`），这样 FastAPI 会在一个线程池工作线程上运行它，从而避免阻塞主事件循环。\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip | 提示\n\n如果你需要在异步函数里调用阻塞代码，或在阻塞函数里调用异步函数，可以使用 [Asyncer](https://asyncer.tiangolo.com)，它是 FastAPI 的姐妹库。\n\n///\n\n### `yield from` { #yield-from }\n\n当你在迭代某个对象（例如类文件对象），并为每个条目执行 `yield` 时，你也可以使用 `yield from` 直接产出每个条目，从而省去 `for` 循环。\n\n这并不是 FastAPI 特有的功能，只是 Python 的语法，但这是一个值得知道的小技巧。😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/zh/docs/advanced/strict-content-type.md",
    "content": "# 严格的 Content-Type 检查 { #strict-content-type-checking }\n\n默认情况下，FastAPI 对 JSON 请求体使用严格的 `Content-Type` 头检查。这意味着，JSON 请求必须包含有效的 `Content-Type` 头（例如 `application/json`），其请求体才会被按 JSON 解析。\n\n## CSRF 风险 { #csrf-risk }\n\n此默认行为在一个非常特定的场景下，可防御一类跨站请求伪造（CSRF）攻击。\n\n这类攻击利用了浏览器的一个事实：当请求满足以下条件时，浏览器允许脚本在不进行任何 CORS 预检的情况下直接发送请求：\n\n- 没有 `Content-Type` 头（例如使用 `fetch()` 携带 `Blob` 作为 body）\n- 且不发送任何认证凭据。\n\n这种攻击主要在以下情况下相关：\n\n- 应用在本地（如 `localhost`）或内网中运行\n- 且应用没有任何认证，假定来自同一网络的请求都可信。\n\n## 攻击示例 { #example-attack }\n\n假设你构建了一个本地运行的 AI 代理。\n\n它提供了一个 API，地址为\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\n另有一个前端，地址为\n\n```\nhttp://localhost:8000\n```\n\n/// tip | 提示\n\n注意它们的主机相同。\n\n///\n\n之后，你可以通过前端让该 AI 代理替你执行操作。\n\n由于它在本地运行、而非暴露在开放的互联网，你决定不配置任何认证，只信任对本地网络的访问。\n\n于是，你的某位用户安装并在本地运行了它。\n\n然后他（她）可能会打开一个恶意网站，例如\n\n```\nhttps://evilhackers.example.com\n```\n\n该恶意网站使用 `fetch()` 携带 `Blob` 作为 body，向本地 API 发送请求，地址为\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\n尽管恶意网站与本地应用的主机不同，浏览器仍不会触发 CORS 预检请求，原因是：\n\n- 请求不涉及任何认证，无需发送凭据。\n- 浏览器认为它并未发送 JSON（因为缺少 `Content-Type` 头）。\n\n于是，该恶意网站就可能让本地 AI 代理替用户向前老板发送愤怒消息……甚至更糟。😅\n\n## 开放的互联网 { #open-internet }\n\n如果你的应用部署在开放的互联网，你不会“信任网络”，也不会允许任何人不经认证就发送特权请求。\n\n攻击者完全可以直接运行脚本向你的 API 发送请求，无需借助浏览器交互，因此你很可能已经对任何特权端点做好了安全防护。\n\n在这种情况下，以上攻击/风险不适用于你。\n\n该风险/攻击主要发生在应用运行于本地网络、且“仅依赖网络隔离作为保护”的场景。\n\n## 允许无 Content-Type 的请求 { #allowing-requests-without-content-type }\n\n如果你需要兼容不发送 `Content-Type` 头的客户端，可以通过设置 `strict_content_type=False` 来关闭严格检查：\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\n启用该设置后，缺少 `Content-Type` 头的请求其请求体也会按 JSON 解析，这与旧版本 FastAPI 的行为一致。\n\n/// info | 信息\n\n此行为和配置在 FastAPI 0.132.0 中新增。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/advanced/sub-applications.md",
    "content": "# 子应用 - 挂载 { #sub-applications-mounts }\n\n如果需要两个独立的 FastAPI 应用，拥有各自独立的 OpenAPI 与文档，则需设置一个主应用，并**挂载**一个（或多个）子应用。\n\n## 挂载 **FastAPI** 应用 { #mounting-a-fastapi-application }\n\n**挂载**是指在特定路径中添加完全**独立**的应用，然后在该路径下使用*路径操作*声明的子应用处理所有事务。\n\n### 顶层应用 { #top-level-application }\n\n首先，创建主（顶层）**FastAPI** 应用及其*路径操作*：\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### 子应用 { #sub-application }\n\n接下来，创建子应用及其*路径操作*。\n\n子应用只是另一个标准 FastAPI 应用，但这个应用是被**挂载**的应用：\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### 挂载子应用 { #mount-the-sub-application }\n\n在顶层应用 `app` 中，挂载子应用 `subapi`。\n\n本例的子应用挂载在 `/subapi` 路径下：\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### 查看自动 API 文档 { #check-the-automatic-api-docs }\n\n现在，运行 `fastapi` 命令：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n然后在 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) 打开文档。\n\n下图显示的是主应用 API 文档，只包括其自有的*路径操作*。\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\n然后查看子应用文档 [http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs)。\n\n下图显示的是子应用的 API 文档，也是只包括其自有的*路径操作*，所有这些路径操作都在 `/subapi` 子路径前缀下。\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\n两个用户界面都可以正常运行，因为浏览器能够与每个指定的应用或子应用会话。\n\n### 技术细节：`root_path` { #technical-details-root-path }\n\n以上述方式挂载子应用时，FastAPI 使用 ASGI 规范中的 `root_path` 机制处理挂载子应用路径之间的通信。\n\n这样，子应用就可以为自动文档使用路径前缀。\n\n并且子应用还可以再挂载子应用，一切都会正常运行，FastAPI 可以自动处理所有 `root_path`。\n\n关于 `root_path` 及如何显式使用 `root_path` 的内容，详见[使用代理](behind-a-proxy.md)一章。\n"
  },
  {
    "path": "docs/zh/docs/advanced/templates.md",
    "content": "# 模板 { #templates }\n\n**FastAPI** 支持多种模板引擎。\n\nFlask 等工具使用的 Jinja2 是最用的模板引擎。\n\n在 Starlette 的支持下，**FastAPI** 应用可以直接使用工具轻易地配置 Jinja2。\n\n## 安装依赖项 { #install-dependencies }\n\n确保你创建一个[虚拟环境](../virtual-environments.md)，激活它，并安装 `jinja2`：\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## 使用 `Jinja2Templates` { #using-jinja2templates }\n\n* 导入 `Jinja2Templates`\n* 创建可复用的 `templates` 对象\n* 在返回模板的*路径操作*中声明 `Request` 参数\n* 使用 `templates` 渲染并返回 `TemplateResponse`，传递模板的名称、request 对象以及一个包含多个键值对（用于 Jinja2 模板）的 \"context\" 字典。\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note | 注意\n\n在 FastAPI 0.108.0，Starlette 0.29.0 之前，`name` 是第一个参数。\n并且，在此之前，`request` 对象是作为 context 的一部分以键值对的形式传递的。\n\n///\n\n/// tip | 提示\n\n通过声明 `response_class=HTMLResponse`，API 文档就能识别响应的对象是 HTML。\n\n///\n\n/// note | 技术细节\n\n您还可以使用 `from starlette.templating import Jinja2Templates`。\n\n**FastAPI** 的 `fastapi.templating` 只是为开发者提供的快捷方式。实际上，绝大多数可用响应都直接继承自 Starlette。`Request` 与 `StaticFiles` 也一样。\n\n///\n\n## 编写模板 { #writing-templates }\n\n编写模板 `templates/item.html`，代码如下：\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### 模板上下文值 { #template-context-values }\n\n在包含如下语句的html中:\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n...这将显示你从 \"context\" 字典传递的 `id`:\n\n```Python\n{\"id\": id}\n```\n\n例如。当 ID 为 `42` 时, 会渲染成:\n\n```html\nItem ID: 42\n```\n\n### 模板 `url_for` 参数 { #template-url-for-arguments }\n\n你还可以在模板内使用 `url_for()`，其参数与*路径操作函数*的参数相同。\n\n所以，该部分:\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n...将生成一个与处理*路径操作函数* `read_item(id=id)`的 URL 相同的链接\n\n例如。当 ID 为 `42` 时, 会渲染成:\n\n```html\n<a href=\"/items/42\">\n```\n\n## 模板与静态文件 { #templates-and-static-files }\n\n你还可以在模板内部将 `url_for()` 用于静态文件，例如你挂载的 `name=\"static\"` 的 `StaticFiles`。\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n本例中，它将链接到 `static/styles.css` 中的 CSS 文件：\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\n因为使用了 `StaticFiles`，**FastAPI** 应用会自动提供位于 URL `/static/styles.css` 的 CSS 文件。\n\n## 更多说明 { #more-details }\n\n包括如何测试模板在内的更多详情，请查看 [Starlette 的模板文档](https://www.starlette.dev/templates/)。\n"
  },
  {
    "path": "docs/zh/docs/advanced/testing-dependencies.md",
    "content": "# 使用覆盖测试依赖项 { #testing-dependencies-with-overrides }\n\n## 测试时覆盖依赖项 { #overriding-dependencies-during-testing }\n\n有些场景下，您可能需要在测试时覆盖依赖项。\n\n即不希望运行原有依赖项（及其子依赖项）。\n\n反之，要在测试期间（或只是为某些特定测试）提供只用于测试的依赖项，并使用此依赖项的值替换原有依赖项的值。\n\n### 用例：外部服务 { #use-cases-external-service }\n\n常见实例是调用外部第三方身份验证应用。\n\n向第三方应用发送令牌，然后返回经验证的用户。\n\n但第三方服务商处理每次请求都可能会收费，并且耗时通常也比调用写死的模拟测试用户更长。\n\n一般只要测试一次外部验证应用就够了，不必每次测试都去调用。\n\n此时，最好覆盖调用外部验证应用的依赖项，使用返回模拟测试用户的自定义依赖项就可以了。\n\n### 使用 `app.dependency_overrides` 属性 { #use-the-app-dependency-overrides-attribute }\n\n对于这些用例，**FastAPI** 应用支持 `app.dependency_overrides` 属性，该属性就是**字典**。\n\n要在测试时覆盖原有依赖项，这个字典的键应当是原依赖项（函数），值是覆盖依赖项（另一个函数）。\n\n这样一来，**FastAPI** 就会调用覆盖依赖项，不再调用原依赖项。\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip | 提示\n\n**FastAPI** 应用中的任何位置都可以实现覆盖依赖项。\n\n原依赖项可用于*路径操作函数*、*路径操作装饰器*（不需要返回值时）、`.include_router()` 调用等。\n\nFastAPI 可以覆盖这些位置的依赖项。\n\n///\n\n然后，使用 `app.dependency_overrides` 把覆盖依赖项重置为空**字典**：\n\n```Python\napp.dependency_overrides = {}\n```\n\n/// tip | 提示\n\n如果只在某些测试时覆盖依赖项，您可以在测试开始时（在测试函数内）设置覆盖依赖项，并在结束时（在测试函数结尾）重置覆盖依赖项。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/advanced/testing-events.md",
    "content": "# 测试事件：lifespan 和 startup - shutdown { #testing-events-lifespan-and-startup-shutdown }\n\n当你需要在测试中运行 `lifespan` 时，可以将 `TestClient` 与 `with` 语句一起使用：\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\n你可以在[官方 Starlette 文档站点的“在测试中运行 lifespan”](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)阅读更多细节。\n\n对于已弃用的 `startup` 和 `shutdown` 事件，可以按如下方式使用 `TestClient`：\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/zh/docs/advanced/testing-websockets.md",
    "content": "# 测试 WebSockets { #testing-websockets }\n\n你可以使用同一个 `TestClient` 来测试 WebSockets。\n\n为此，在 `with` 语句中使用 `TestClient` 连接到 WebSocket：\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note | 注意\n\n更多细节请查看 Starlette 的文档：[测试 WebSockets](https://www.starlette.dev/testclient/#testing-websocket-sessions)。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/advanced/using-request-directly.md",
    "content": "# 直接使用 Request { #using-the-request-directly }\n\n至此，我们已经使用多种类型声明了请求的各种组件。\n\n并从以下对象中提取数据：\n\n* 路径参数\n* 请求头\n* Cookies\n* 等\n\n**FastAPI** 使用这种方式验证数据、转换数据，并自动生成 API 文档。\n\n但有时，我们也需要直接访问 `Request` 对象。\n\n## `Request` 对象的细节 { #details-about-the-request-object }\n\n实际上，**FastAPI** 的底层是 **Starlette**，**FastAPI** 只不过是在 **Starlette** 顶层提供了一些工具，所以能直接使用 Starlette 的 [`Request`](https://www.starlette.dev/requests/) 对象。\n\n但直接从 `Request` 对象提取数据时（例如，读取请求体），这些数据不会被 **FastAPI** 验证、转换或文档化（使用 OpenAPI，为自动的 API 用户界面）。\n\n不过，仍可以验证、转换与注释（使用 Pydantic 模型的请求体等）其它正常声明的参数。\n\n但在某些特定情况下，还是需要提取 `Request` 对象。\n\n## 直接使用 `Request` 对象 { #use-the-request-object-directly }\n\n假设要在*路径操作函数*中获取客户端 IP 地址和主机。\n\n此时，需要直接访问请求。\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\n把*路径操作函数*的参数类型声明为 `Request`，**FastAPI** 就能把 `Request` 传递到参数里。\n\n/// tip | 提示\n\n注意，本例除了声明请求参数之外，还声明了路径参数。\n\n因此，能够提取、验证路径参数、并转换为指定类型，还可以用 OpenAPI 注释。\n\n同样，您也可以正常声明其它参数，而且还可以提取 `Request`。\n\n///\n\n## `Request` 文档 { #request-documentation }\n\n你可以在[Starlette 官方文档站点的 `Request` 对象](https://www.starlette.dev/requests/)中阅读更多细节。\n\n/// note | 技术细节\n\n您也可以使用 `from starlette.requests import Request`。\n\n**FastAPI** 直接提供它只是为了方便开发者，但它直接来自 Starlette。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\n您可以在 **FastAPI** 中使用 [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)。\n\n## 安装 `websockets` { #install-websockets }\n\n请确保您创建一个[虚拟环境](../virtual-environments.md)、激活它，并安装 `websockets`（一个让使用“WebSocket”协议更容易的 Python 库）：\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## WebSockets 客户端 { #websockets-client }\n\n### 在生产环境中 { #in-production }\n\n在您的生产系统中，您可能使用现代框架（如 React、Vue.js 或 Angular）创建了一个前端。\n\n要使用 WebSockets 与后端进行通信，您可能会使用前端的工具。\n\n或者，您可能有一个原生移动应用程序，直接使用原生代码与 WebSocket 后端通信。\n\n或者，您可能有其他与 WebSocket 终端通信的方式。\n\n---\n\n但是，在本示例中，我们将使用一个非常简单的 HTML 文档，其中包含一些 JavaScript，全部放在一个长字符串中。\n\n当然，这并不是最优的做法，您不应该在生产环境中使用它。\n\n在生产环境中，您应该选择上述任一选项。\n\n但这是一种专注于 WebSockets 的服务器端并提供一个工作示例的最简单方式：\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## 创建 `websocket` { #create-a-websocket }\n\n在您的 **FastAPI** 应用程序中，创建一个 `websocket`：\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | 技术细节\n\n您也可以使用 `from starlette.websockets import WebSocket`。\n\n**FastAPI** 直接提供了相同的 `WebSocket`，只是为了方便开发人员。但它直接来自 Starlette。\n\n///\n\n## 等待消息并发送消息 { #await-for-messages-and-send-messages }\n\n在您的 WebSocket 路由中，您可以使用 `await` 等待消息并发送消息。\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\n您可以接收和发送二进制、文本和 JSON 数据。\n\n## 尝试一下 { #try-it }\n\n将代码放在 `main.py`，然后运行你的应用程序：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n在浏览器中打开 [http://127.0.0.1:8000](http://127.0.0.1:8000)。\n\n您将看到一个简单的页面，如下所示：\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\n您可以在输入框中输入消息并发送：\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\n您的 **FastAPI** 应用程序将通过 WebSockets 回复：\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\n您可以发送（和接收）多条消息：\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\n所有这些消息都将使用同一个 WebSocket 连接。\n\n## 使用 `Depends` 和其他依赖项 { #using-depends-and-others }\n\n在 WebSocket 端点中，您可以从 `fastapi` 导入并使用以下内容：\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\n它们的工作方式与其他 FastAPI 端点/*路径操作* 相同：\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info\n\n由于这是一个 WebSocket，抛出 `HTTPException` 并不是很合理，而是抛出 `WebSocketException`。\n\n您可以使用[规范中定义的有效代码](https://tools.ietf.org/html/rfc6455#section-7.4.1)。\n\n///\n\n### 尝试带有依赖项的 WebSockets { #try-the-websockets-with-dependencies }\n\n运行你的应用程序：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n在浏览器中打开 [http://127.0.0.1:8000](http://127.0.0.1:8000)。\n\n在页面中，您可以设置：\n\n* \"Item ID\"，用于路径。\n* \"Token\"，作为查询参数。\n\n/// tip\n\n注意，查询参数 `token` 将由依赖项处理。\n\n///\n\n通过这样，您可以连接 WebSocket，然后发送和接收消息：\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## 处理断开连接和多个客户端 { #handling-disconnections-and-multiple-clients }\n\n当 WebSocket 连接关闭时，`await websocket.receive_text()` 将引发 `WebSocketDisconnect` 异常，您可以捕获并处理该异常，就像本示例中的示例一样。\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\n尝试以下操作：\n\n* 使用多个浏览器选项卡打开应用程序。\n* 从这些选项卡中发送消息。\n* 然后关闭其中一个选项卡。\n\n这将引发 `WebSocketDisconnect` 异常，并且所有其他客户端都会收到类似以下的消息：\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip\n\n上面的应用程序是一个最小和简单的示例，用于演示如何处理和向多个 WebSocket 连接广播消息。\n\n但请记住，由于所有内容都在内存中以单个列表的形式处理，因此它只能在进程运行时工作，并且只能使用单个进程。\n\n如果您需要与 FastAPI 集成更简单但更强大的功能，支持 Redis、PostgreSQL 或其他功能，请查看 [encode/broadcaster](https://github.com/encode/broadcaster)。\n\n///\n\n## 更多信息 { #more-info }\n\n要了解更多选项，请查看 Starlette 的文档：\n\n* [`WebSocket` 类](https://www.starlette.dev/websockets/)。\n* [基于类的 WebSocket 处理](https://www.starlette.dev/endpoints/#websocketendpoint)。\n"
  },
  {
    "path": "docs/zh/docs/advanced/wsgi.md",
    "content": "# 包含 WSGI - Flask，Django，其它 { #including-wsgi-flask-django-others }\n\n您可以挂载 WSGI 应用，正如您在 [子应用 - 挂载](sub-applications.md)、[在代理之后](behind-a-proxy.md) 中所看到的那样。\n\n为此, 您可以使用 `WSGIMiddleware` 来包装你的 WSGI 应用，如：Flask，Django，等等。\n\n## 使用 `WSGIMiddleware` { #using-wsgimiddleware }\n\n/// info | 信息\n\n需要安装 `a2wsgi`，例如使用 `pip install a2wsgi`。\n\n///\n\n您需要从 `a2wsgi` 导入 `WSGIMiddleware`。\n\n然后使用该中间件包装 WSGI 应用（例如 Flask）。\n\n之后将其挂载到某一个路径下。\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note | 注意\n\n之前推荐使用 `fastapi.middleware.wsgi` 中的 `WSGIMiddleware`，但它现在已被弃用。\n\n建议改用 `a2wsgi` 包，使用方式保持不变。\n\n只要确保已安装 `a2wsgi` 包，并且从 `a2wsgi` 正确导入 `WSGIMiddleware` 即可。\n\n///\n\n## 检查 { #check-it }\n\n现在，所有定义在 `/v1/` 路径下的请求将会被 Flask 应用处理。\n\n其余的请求则会被 **FastAPI** 处理。\n\n如果你运行它并访问 [http://localhost:8000/v1/](http://localhost:8000/v1/)，你将会看到由 Flask 返回的响应：\n\n```txt\nHello, World from Flask!\n```\n\n如果你访问 [http://localhost:8000/v2](http://localhost:8000/v2)，你将会看到由 FastAPI 返回的响应：\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/zh/docs/alternatives.md",
    "content": "# 替代方案、灵感与对比 { #alternatives-inspiration-and-comparisons }\n\n是什么启发了 **FastAPI**，它与替代方案的比较，以及它从中学到的东西。\n\n## 介绍 { #intro }\n\n没有前人的工作，就不会有 **FastAPI**。\n\n在它诞生之前，已经有许多工具为其提供了灵感。\n\n我曾经多年避免创建一个新框架。起初，我尝试用许多不同的框架、插件和工具来解决 **FastAPI** 所覆盖的全部功能。\n\n但在某个时刻，除了创造一个能提供所有这些功能的东西之外，别无选择；它要吸收以往工具的最佳理念，并以尽可能好的方式组合起来，利用之前都不存在的语言特性（Python 3.6+ 类型提示）。\n\n## 先前的工具 { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\n它是最流行且被广泛信任的 Python 框架。被用于构建 Instagram 等系统。\n\n它与关系型数据库（如 MySQL、PostgreSQL）耦合相对紧密，因此若要以 NoSQL 数据库（如 Couchbase、MongoDB、Cassandra 等）作为主要存储引擎并不容易。\n\n它最初用于在后端生成 HTML，而不是创建由现代前端（如 React、Vue.js、Angular）或与之通信的其他系统（如 <abbr title=\"Internet of Things - 物联网\">IoT</abbr> 设备）使用的 API。\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nDjango REST framework 作为一个灵活工具箱而创建，用于在底层使用 Django 构建 Web API，从而增强其 API 能力。\n\n它被包括 Mozilla、Red Hat、Eventbrite 在内的许多公司使用。\n\n它是最早的“自动 API 文档”的范例之一，这正是启发“寻找” **FastAPI** 的最初想法之一。\n\n/// note | 注意\n\nDjango REST Framework 由 Tom Christie 创建。他也是 Starlette 和 Uvicorn 的作者，**FastAPI** 就是基于它们构建的。\n\n///\n\n/// check | 启发 **FastAPI**：\n\n提供自动化的 API 文档 Web 界面。\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask 是一个“微框架”，它不包含数据库集成，也没有像 Django 那样的许多默认内建功能。\n\n这种简单与灵活使得可以将 NoSQL 数据库作为主要的数据存储系统。\n\n由于非常简单，它相对直观易学，尽管文档在某些部分略显偏技术。\n\n它也常用于不一定需要数据库、用户管理，或任何 Django 预构建功能的应用；当然，许多这类功能可以通过插件添加。\n\n这种组件解耦、可按需扩展的“微框架”特性，是我想保留的关键点。\n\n鉴于 Flask 的简洁，它似乎非常适合构建 API。接下来要找的，就是 Flask 版的 “Django REST Framework”。\n\n/// check | 启发 **FastAPI**：\n\n- 成为微框架，便于按需组合所需的工具与组件。\n- 提供简单易用的路由系统。\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI** 实际上不是 **Requests** 的替代品。它们的作用范围完全不同。\n\n在 FastAPI 应用程序内部使用 Requests 其实非常常见。\n\n尽管如此，FastAPI 依然从 Requests 中获得了不少灵感。\n\n**Requests** 是一个用于与 API 交互（作为客户端）的库，而 **FastAPI** 是一个用于构建 API（作为服务端）的库。\n\n它们处在某种意义上的“对立端”，彼此互补。\n\nRequests 设计非常简单直观，易于使用，且有合理的默认值。同时它也非常强大、可定制。\n\n这就是为什么，正如其官网所说：\n\n> Requests 是有史以来下载量最高的 Python 包之一\n\n它的用法非常简单。例如，进行一次 `GET` 请求，你会这样写：\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\n对应地，FastAPI 的 API 路径操作可能看起来是这样的：\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\n可以看到 `requests.get(...)` 与 `@app.get(...)` 的相似之处。\n\n/// check | 启发 **FastAPI**：\n\n* 提供简单直观的 API。\n* 直接、自然地使用 HTTP 方法名（操作）。\n* 具备合理默认值，同时支持强大定制能力。\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\n我想从 Django REST Framework 得到的主要特性之一是自动 API 文档。\n\n随后我发现有一个用于用 JSON（或 YAML，JSON 的扩展）来描述 API 的标准，称为 Swagger。\n\n并且已经有了用于 Swagger API 的 Web 用户界面。因此，只要能为 API 生成 Swagger 文档，就能自动使用这个 Web 界面。\n\n后来，Swagger 交由 Linux 基金会管理，并更名为 OpenAPI。\n\n因此，在谈到 2.0 版本时人们常说 “Swagger”，而 3+ 版本则称为 “OpenAPI”。\n\n/// check | 启发 **FastAPI**：\n\n采用并使用开放的 API 规范标准，而非自定义模式。\n\n并集成基于标准的用户界面工具：\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\n选择这两者是因为它们相当流行且稳定；但稍作搜索，你就能找到数十种 OpenAPI 的替代用户界面（都可以与 **FastAPI** 搭配使用）。\n\n///\n\n### Flask REST 框架 { #flask-rest-frameworks }\n\n有若干基于 Flask 的 REST 框架，但在投入时间精力深入调研后，我发现许多已停止维护或被弃用，并存在多处未解决问题，不太适合采用。\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nAPI 系统所需的主要特性之一是数据“<dfn title=\"也称为：编组、转换\">序列化</dfn>”，即将代码（Python）中的数据转换为可通过网络发送的形式。例如，将包含数据库数据的对象转换为 JSON 对象、将 `datetime` 对象转换为字符串等。\n\nAPI 的另一个重要特性是数据校验，确保数据在给定约束下是有效的。例如，某个字段必须是 `int` 而不是任意字符串。这对传入数据尤其有用。\n\n没有数据校验系统的话，你就得在代码里手写所有检查。\n\n这些正是 Marshmallow 要提供的功能。它是个很棒的库，我之前大量使用过。\n\n但它诞生于 Python 类型提示出现之前。因此，定义每个<dfn title=\"数据应如何构造的定义\">模式</dfn>都需要使用 Marshmallow 提供的特定工具和类。\n\n/// check | 启发 **FastAPI**：\n\n使用代码定义“模式”，自动提供数据类型与校验。\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nAPI 的另一个重要需求是从传入请求中<dfn title=\"读取并转换为 Python 数据\">解析</dfn>数据。\n\nWebargs 是一个在多个框架（包括 Flask）之上提供该功能的工具。\n\n它在底层使用 Marshmallow 进行数据校验，并且由相同的开发者创建。\n\n在拥有 **FastAPI** 之前，我也大量使用过它，这是个很棒的工具。\n\n/// info | 信息\n\nWebargs 由与 Marshmallow 相同的开发者创建。\n\n///\n\n/// check | 启发 **FastAPI**：\n\n对传入请求数据进行自动校验。\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow 与 Webargs 通过插件提供了校验、解析与序列化。\n\n但文档仍然缺失，于是出现了 APISpec。\n\n它为许多框架提供插件（Starlette 也有插件）。\n\n它的工作方式是：你在处理路由的每个函数的文档字符串里，用 YAML 格式编写模式定义。\n\n然后它会生成 OpenAPI 模式。\n\n这正是它在 Flask、Starlette、Responder 等框架里的工作方式。\n\n但这样我们又回到了在 Python 字符串中维护一套“微语法”（一大段 YAML）的问题上。\n\n编辑器很难为此提供帮助；而且如果我们修改了参数或 Marshmallow 模式，却忘了同步更新那个 YAML 文档字符串，生成的模式就会过时。\n\n/// info | 信息\n\nAPISpec 由与 Marshmallow 相同的开发者创建。\n\n///\n\n/// check | 启发 **FastAPI**：\n\n支持开放的 API 标准 OpenAPI。\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\n这是一个 Flask 插件，将 Webargs、Marshmallow 与 APISpec 结合在一起。\n\n它利用 Webargs 与 Marshmallow 的信息，通过 APISpec 自动生成 OpenAPI 模式。\n\n这是个很棒却被低估的工具；它理应比许多 Flask 插件更流行。或许是因为它的文档过于简洁与抽象。\n\n这解决了在 Python 文档字符串里书写 YAML（另一套语法）的问题。\n\n在构建 **FastAPI** 之前，Flask + Flask-apispec + Marshmallow + Webargs 的组合是我最喜欢的后端技术栈。\n\n使用它促成了若干 Flask 全栈脚手架的诞生。以下是我（以及若干外部团队）至今使用的主要技术栈：\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\n这些全栈脚手架也成为了[**FastAPI** 项目脚手架](project-generation.md)的基础。\n\n/// info | 信息\n\nFlask-apispec 由与 Marshmallow 相同的开发者创建。\n\n///\n\n/// check | 启发 **FastAPI**：\n\n从定义序列化与校验的同一份代码自动生成 OpenAPI 模式。\n\n///\n\n### [NestJS](https://nestjs.com/)（以及 [Angular](https://angular.io/)） { #nestjs-and-angular }\n\n这甚至不是 Python。NestJS 是一个 JavaScript（TypeScript）的 NodeJS 框架，受 Angular 启发。\n\n它实现了与 Flask-apispec 有些类似的效果。\n\n它集成了受 Angular 2 启发的依赖注入系统。与我所知的其他依赖注入系统一样，需要预先注册“可注入项”，因此会增加冗长与重复。\n\n由于参数用 TypeScript 类型描述（类似 Python 类型提示），编辑器支持相当好。\n\n但由于 TypeScript 的类型在编译为 JavaScript 后不会保留，无法只依赖这些类型同时定义校验、序列化与文档。受此以及一些设计决策影响，为了获得校验、序列化与自动 schema 生成，需要在许多位置添加装饰器，因此代码会相当冗长。\n\n它对嵌套模型的支持并不好。如果请求的 JSON 体是包含嵌套 JSON 对象的 JSON 对象，则无法被正确文档化和校验。\n\n/// check | 启发 **FastAPI**：\n\n使用 Python 类型以获得出色的编辑器支持。\n\n拥有强大的依赖注入系统，并设法尽量减少代码重复。\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\n它是最早的一批基于 `asyncio` 的极速 Python 框架之一，且做得与 Flask 很相似。\n\n/// note | 技术细节\n\n它使用了 [`uvloop`](https://github.com/MagicStack/uvloop) 来替代 Python 默认的 `asyncio` 循环。这正是它如此之快的原因。\n\n它显然启发了 Uvicorn 和 Starlette；在公开的基准测试中，它们目前比 Sanic 更快。\n\n///\n\n/// check | 启发 **FastAPI**：\n\n找到实现疯狂性能的路径。\n\n这就是 **FastAPI** 基于 Starlette 的原因，因为它是目前可用的最快框架（由第三方基准测试验证）。\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon 是另一个高性能 Python 框架，它被设计为精简且可作为 Hug 等其他框架的基础。\n\n它设计为接收两个参数的函数：一个“request”和一个“response”。然后从 request 中“读取”，向 response 中“写入”。由于这种设计，无法用标准的 Python 类型提示将请求参数和请求体声明为函数形参。\n\n因此，数据校验、序列化与文档要么需要手写完成，无法自动化；要么需要在 Falcon 之上实现一个框架，例如 Hug。其他受 Falcon 设计启发、采用“一个 request 对象 + 一个 response 对象作为参数”的框架也有同样的区别。\n\n/// check | 启发 **FastAPI**：\n\n寻找获得卓越性能的方法。\n\n与 Hug（Hug 基于 Falcon）一起，启发 **FastAPI** 在函数中声明一个 `response` 参数。尽管在 FastAPI 中它是可选的，主要用于设置 headers、cookies 和可选的状态码。\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\n我在构建 **FastAPI** 的早期阶段发现了 Molten。它有不少相似的想法：\n\n* 基于 Python 类型提示。\n* 从这些类型获得校验与文档。\n* 依赖注入系统。\n\n它没有使用像 Pydantic 这样的第三方数据校验、序列化与文档库，而是有自己的实现。因此这些数据类型定义不太容易在其他地方复用。\n\n它需要稍微冗长一些的配置。并且由于基于 WSGI（而非 ASGI），它并未设计为充分利用 Uvicorn、Starlette、Sanic 等工具所提供的高性能。\n\n其依赖注入系统需要预先注册依赖，且依赖根据声明的类型来解析。因此无法为同一类型声明多于一个“组件”。\n\n路由在一个地方集中声明，使用在其他地方声明的函数（而不是使用可以直接放在处理端点函数之上的装饰器）。这更接近 Django 的做法，而不是 Flask（和 Starlette）。它在代码中割裂了相对紧耦合的内容。\n\n/// check | 启发 **FastAPI**：\n\n通过模型属性的“默认值”为数据类型定义额外校验。这提升了编辑器支持，而这在当时的 Pydantic 中尚不可用。\n\n这实际上促成了对 Pydantic 的部分更新，以支持这种校验声明风格（这些功能现已在 Pydantic 中可用）。\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug 是最早使用 Python 类型提示来声明 API 参数类型的框架之一。这一绝妙想法也启发了其他工具。\n\n它在声明中使用自定义类型而不是标准的 Python 类型，但这依然是巨大的进步。\n\n它也是最早生成一个自定义 JSON 模式来声明整个 API 的框架之一。\n\n它并不基于 OpenAPI 与 JSON Schema 这类标准。因此与其他工具（如 Swagger UI）的集成并非一帆风顺。但它仍是非常有创新性的想法。\n\n它有一个有趣且少见的特性：使用同一框架，可以同时创建 API 与 CLI。\n\n由于基于同步 Python Web 框架的上一代标准（WSGI），它无法处理 WebSocket 等，尽管它的性能仍然很高。\n\n/// info | 信息\n\nHug 由 Timothy Crosley 创建，他也是 [`isort`](https://github.com/timothycrosley/isort) 的作者，这是一个能自动排序 Python 文件中导入的优秀工具。\n\n///\n\n/// check | 启发 **FastAPI** 的想法：\n\nHug 启发了 APIStar 的部分设计，也是我当时最看好的工具之一，与 APIStar 并列。\n\nHug 促使 **FastAPI** 使用 Python 类型提示来声明参数，并自动生成定义整个 API 的模式。\n\nHug 启发 **FastAPI** 在函数中声明 `response` 参数，用于设置 headers 与 cookies。\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0.5) { #apistar-0-5 }\n\n就在决定动手构建 **FastAPI** 之前，我找到了 **APIStar** 服务器。它几乎具备我想要的一切，设计也很出色。\n\n在我见过的框架中，它是最早使用 Python 类型提示来声明参数和请求的实现之一（早于 NestJS 与 Molten）。我与 Hug 几乎同时发现了它。但 APIStar 使用了 OpenAPI 标准。\n\n它基于相同的类型提示，在多处自动进行数据校验、序列化并生成 OpenAPI 模式。\n\n请求体模式定义并未使用与 Pydantic 相同的 Python 类型提示，它更接近 Marshmallow，因此编辑器支持不如 Pydantic 好，但即便如此，APIStar 仍是当时可用的最佳选择。\n\n它在当时拥有最好的性能基准（仅被 Starlette 超越）。\n\n起初它没有自动 API 文档 Web 界面，但我知道我可以把 Swagger UI 加进去。\n\n它有一个依赖注入系统。与上文提到的其他工具一样，需要预先注册组件。但这依然是很棒的特性。\n\n我从未在完整项目中使用过它，因为它没有安全集成，因此我无法用它替代基于 Flask-apispec 的全栈脚手架所具备的全部功能。我曾把“提交一个增加该功能的 PR”放在了待办里。\n\n但随后，项目的重心发生了变化。\n\n它不再是一个 API Web 框架，因为作者需要专注于 Starlette。\n\n现在 APIStar 是一组用于校验 OpenAPI 规范的工具，而不是 Web 框架。\n\n/// info | 信息\n\nAPIStar 由 Tom Christie 创建。他还创建了：\n\n* Django REST Framework\n* Starlette（**FastAPI** 基于其之上）\n* Uvicorn（被 Starlette 与 **FastAPI** 使用）\n\n///\n\n/// check | 启发 **FastAPI**：\n\n诞生。\n\n用同一套 Python 类型同时声明多件事（数据校验、序列化与文档），并且还能提供出色的编辑器支持——我认为这是个极其巧妙的想法。\n\n在长时间寻找与测试多种替代之后，APIStar 是当时最好的选择。\n\n随后 APIStar 不再作为服务器存在，而 Starlette 出现，成为实现该体系的更佳基础。这成为构建 **FastAPI** 的最终灵感来源。\n\n我把 **FastAPI** 视为 APIStar 的“精神续作”，并在此基础上，结合前述工具的经验，改进并增强了功能、类型系统及其他各方面。\n\n///\n\n## **FastAPI** 所使用的组件 { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic 是一个基于 Python 类型提示来定义数据校验、序列化与文档（使用 JSON Schema）的库。\n\n这使得它极其直观。\n\n它可与 Marshmallow 类比。尽管在基准测试中它比 Marshmallow 更快。并且由于同样基于 Python 类型提示，编辑器支持优秀。\n\n/// check | **FastAPI** 用它来：\n\n处理所有数据校验、数据序列化与自动模型文档（基于 JSON Schema）。\n\n随后 **FastAPI** 会把这些 JSON Schema 数据纳入 OpenAPI（以及完成其他所有工作）。\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette 是一个轻量级的 <dfn title=\"构建异步 Python Web 应用的新标准\">ASGI</dfn> 框架/工具集，非常适合构建高性能的 asyncio 服务。\n\n它非常简单直观。被设计为易于扩展，且具有模块化组件。\n\n它具备：\n\n* 性能极其出色。\n* 支持 WebSocket。\n* 进程内后台任务。\n* 启动与停止事件。\n* 基于 HTTPX 的测试客户端。\n* CORS、GZip、静态文件、流式响应。\n* 会话与 Cookie 支持。\n* 100% 测试覆盖率。\n* 100% 类型注解的代码库。\n* 极少的强依赖。\n\nStarlette 目前是测试中最快的 Python 框架。仅次于 Uvicorn，它不是框架，而是服务器。\n\nStarlette 提供了 Web 微框架的全部基础能力。\n\n但它不提供自动的数据校验、序列化或文档。\n\n这正是 **FastAPI** 在其之上增加的主要内容之一，全部基于 Python 类型提示（通过 Pydantic）。此外还有依赖注入系统、安全工具、OpenAPI 模式生成等。\n\n/// note | 技术细节\n\nASGI 是由 Django 核心团队成员推动的新“标准”。它尚不是正式的“Python 标准”（PEP），尽管正朝此方向推进。\n\n尽管如此，已有多种工具将其作为“标准”使用。这极大提升了互操作性：你可以把 Uvicorn 换成其他 ASGI 服务器（如 Daphne 或 Hypercorn），或添加 ASGI 兼容的工具，如 `python-socketio`。\n\n///\n\n/// check | **FastAPI** 用它来：\n\n处理所有核心 Web 部分，并在其之上扩展功能。\n\n`FastAPI` 类本身直接继承自 `Starlette`。\n\n因此，凡是你能用 Starlette 完成的事，也能直接用 **FastAPI** 完成；可以把它看作“加速版”的 Starlette。\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn 是一个基于 uvloop 与 httptools 构建的极速 ASGI 服务器。\n\n它不是 Web 框架，而是服务器。例如它不提供按路径路由的工具——这是 Starlette（或 **FastAPI**）这类框架在其之上提供的功能。\n\n它是 Starlette 与 **FastAPI** 推荐的服务器。\n\n/// check | **FastAPI** 推荐将其作为：\n\n运行 **FastAPI** 应用的主要 Web 服务器。\n\n你也可以使用 `--workers` 命令行选项以获得异步的多进程服务器。\n\n更多细节见[部署](deployment/index.md)一节。\n\n///\n\n## 基准与速度 { #benchmarks-and-speed }\n\n要理解、比较并查看 Uvicorn、Starlette 与 FastAPI 之间的差异，请查看[基准](benchmarks.md)一节。\n"
  },
  {
    "path": "docs/zh/docs/async.md",
    "content": "# 并发 async / await { #concurrency-and-async-await }\n\n有关路径操作函数的 `async def` 语法以及异步代码、并发和并行的一些背景知识。\n\n## 赶时间吗？ { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - 太长；没看\"><strong>TL;DR:</strong></abbr>\n\n如果你正在使用第三方库，它们会告诉你使用 `await` 关键字来调用它们，就像这样：\n\n```Python\nresults = await some_library()\n```\n\n然后，通过 `async def` 声明你的 *路径操作函数*：\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | 注意\n\n你只能在被 `async def` 创建的函数内使用 `await`\n\n///\n\n---\n\n如果你正在使用一个第三方库和某些组件（比如：数据库、API、文件系统...）进行通信，第三方库又不支持使用 `await` （目前大多数数据库三方库都是这样），这种情况你可以像平常那样使用 `def` 声明一个路径操作函数，就像这样：\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\n如果你的应用程序不需要与其他任何东西通信而等待其响应，请使用 `async def`，即使函数内部不需要使用 `await`。\n\n---\n\n如果你不清楚，使用 `def` 就好.\n\n---\n\n**注意**：你可以根据需要在路径操作函数中混合使用 `def` 和 `async def`，并使用最适合你的方式去定义每个函数。FastAPI 将为他们做正确的事情。\n\n无论如何，在上述任何情况下，FastAPI 仍将异步工作，速度也非常快。\n\n但是，通过遵循上述步骤，它将能够进行一些性能优化。\n\n## 技术细节 { #technical-details }\n\nPython 的现代版本支持通过一种叫**\"协程\"**——使用 `async` 和 `await` 语法的东西来写**”异步代码“**。\n\n让我们在下面的部分中逐一介绍：\n\n* **异步代码**\n* **`async` 和 `await`**\n* **协程**\n\n## 异步代码 { #asynchronous-code }\n\n异步代码仅仅意味着编程语言 💬 有办法告诉计算机/程序 🤖 在代码中的某个点，它 🤖 将不得不等待在某些地方完成一些事情。让我们假设一些事情被称为 \"慢文件\"📝.\n\n所以，在等待\"慢文件\"📝完成的这段时间，计算机可以做一些其他工作。\n\n然后计算机/程序 🤖 每次有机会都会回来，因为它又在等待，或者它 🤖 完成了当前所有的工作。而且它 🤖 将查看它等待的所有任务中是否有已经完成的，做它必须做的任何事情。\n\n接下来，它 🤖 完成第一个任务（比如是我们的\"慢文件\"📝) 并继续与之相关的一切。\n\n这个\"等待其他事情\"通常指的是一些相对较慢（与处理器和 RAM 存储器的速度相比）的 <abbr title=\"Input and Output - 输入和输出\">I/O</abbr> 操作，比如说：\n\n* 通过网络发送来自客户端的数据\n* 客户端接收来自网络中的数据\n* 磁盘中要由系统读取并提供给程序的文件的内容\n* 程序提供给系统的要写入磁盘的内容\n* 一个 API 的远程调用\n* 一个数据库操作，直到完成\n* 一个数据库查询，直到返回结果\n* 等等.\n\n这个执行的时间大多是在等待 <abbr title=\"Input and Output - 输入和输出\">I/O</abbr> 操作，因此它们被叫做 \"I/O 密集型\" 操作。\n\n它被称为\"异步\"的原因是因为计算机/程序不必与慢任务\"同步\"，去等待任务完成的确切时刻，而在此期间不做任何事情直到能够获取任务结果才继续工作。\n\n相反，作为一个\"异步\"系统，一旦完成，任务就可以排队等待一段时间（几微秒），等待计算机程序完成它要做的任何事情，然后回来获取结果并继续处理它们。\n\n对于\"同步\"（与\"异步\"相反），他们通常也使用\"顺序\"一词，因为计算机程序在切换到另一个任务之前是按顺序执行所有步骤，即使这些步骤涉及到等待。\n\n### 并发与汉堡 { #concurrency-and-burgers }\n\n上述异步代码的思想有时也被称为“并发”，它不同于“并行”。\n\n并发和并行都与“不同的事情或多或少同时发生”有关。\n\n但是并发和并行之间的细节是完全不同的。\n\n要了解差异，请想象以下关于汉堡的故事：\n\n### 并发汉堡 { #concurrent-burgers }\n\n你和你的恋人一起去快餐店，你排队在后面，收银员从你前面的人接单。😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\n然后轮到你了，你为你的恋人和你选了两个非常豪华的汉堡。🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\n收银员对厨房里的厨师说了一些话，让他们知道他们必须为你准备汉堡（尽管他们目前正在为之前的顾客准备汉堡）。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\n你付钱了。 💸\n\n收银员给你轮到的号码。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\n当你在等待的时候，你和你的恋人一起去挑选一张桌子，然后你们坐下来聊了很长时间（因为汉堡很豪华，需要一些时间来准备）。\n\n当你和你的恋人坐在桌子旁，等待汉堡的时候，你可以用这段时间来欣赏你的恋人是多么的棒、可爱和聪明✨😍✨。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\n在等待中和你的恋人交谈时，你会不时地查看柜台上显示的号码，看看是否已经轮到你了。\n\n然后在某个时刻，终于轮到你了。你去柜台拿汉堡然后回到桌子上。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\n你们享用了汉堡，整个过程都很开心。✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info | 信息\n\n漂亮的插画来自 [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot)。🎨\n\n///\n\n---\n\n在那个故事里，假设你是计算机程序 🤖 。\n\n当你在排队时，你只是闲着😴， 轮到你前不做任何事情（仅排队）。但排队很快，因为收银员只接订单（不准备订单），所以这一切都还好。\n\n然后，当轮到你时，需要你做一些实际性的工作，比如查看菜单，决定你想要什么，让你的恋人选择，支付，检查你是否提供了正确的账单或卡，检查你的收费是否正确，检查订单是否有正确的项目，等等。\n\n此时，即使你仍然没有汉堡，你和收银员的工作也\"暂停\"了⏸， 因为你必须等待一段时间 🕙 让你的汉堡做好。\n\n但是，当你离开柜台并坐在桌子旁，在轮到你的号码前的这段时间，你可以将焦点切换到 🔀 你的恋人上，并做一些\"工作\"⏯ 🤓。你可以做一些非常\"有成效\"的事情，比如和你的恋人调情😍.\n\n之后，收银员 💁 把号码显示在显示屏上，并说到 \"汉堡做好了\"，而当显示的号码是你的号码时，你不会立刻疯狂地跳起来。因为你知道没有人会偷你的汉堡，因为你有你的号码，而其他人又有他们自己的号码。\n\n所以你要等待你的恋人完成故事（完成当前的工作⏯ /正在做的事🤓)， 轻轻微笑，说你要吃汉堡⏸.\n\n然后你去柜台🔀， 到现在初始任务已经完成⏯， 拿起汉堡，说声谢谢，然后把它们送到桌上。这就完成了与计数器交互的步骤/任务⏹. 这反过来又产生了一项新任务，即\"吃汉堡\"🔀 ⏯， 上一个\"拿汉堡\"的任务已经结束了⏹.\n\n### 并行汉堡 { #parallel-burgers }\n\n现在让我们假设不是\"并发汉堡\"，而是\"并行汉堡\"。\n\n你和你的恋人一起去吃并行快餐。\n\n你站在队伍中，同时是厨师的几个收银员（比方说8个）从前面的人那里接单。\n\n你之前的每个人都在等待他们的汉堡准备好后才离开柜台，因为8名收银员都会在下一份订单前马上准备好汉堡。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\n然后，终于轮到你了，你为你的恋人和你订购了两个非常精美的汉堡。\n\n你付钱了 💸。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\n收银员去厨房。\n\n你站在柜台前 🕙等待着，这样就不会有人在你之前抢走你的汉堡，因为没有轮流的号码。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\n当你和你的恋人忙于不让任何人出现在你面前，并且在他们到来的时候拿走你的汉堡时，你无法关注到你的恋人。😞\n\n这是\"同步\"的工作，你被迫与服务员/厨师 👨‍🍳\"同步\"。你在此必须等待 🕙 ，在收银员/厨师 👨‍🍳 完成汉堡并将它们交给你的确切时间到达之前一直等待，否则其他人可能会拿走它们。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\n你经过长时间的等待 🕙 ，收银员/厨师 👨‍🍳终于带着汉堡回到了柜台。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\n你拿着汉堡，和你的情人一起上桌。\n\n你们仅仅是吃了它们，就结束了。⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\n没有太多的交谈或调情，因为大部分时间 🕙 都在柜台前等待😞。\n\n/// info | 信息\n\n漂亮的插画来自 [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot)。🎨\n\n///\n\n---\n\n在这个并行汉堡的场景中，你是一个计算机程序 🤖 且有两个处理器（你和你的恋人），都在等待 🕙 ，并投入他们的注意力 ⏯ 在柜台上等待了很长一段时间。\n\n这家快餐店有 8 个处理器（收银员/厨师）。而并发汉堡店可能只有 2 个（一个收银员和一个厨师）。\n\n但最终的体验仍然不是最好的。😞\n\n---\n\n这将是与汉堡的类似故事。🍔\n\n一种更\"贴近生活\"的例子，想象一家银行。\n\n直到最近，大多数银行都有多个出纳员 👨‍💼👨‍💼👨‍💼👨‍💼 还有一条长长排队队伍🕙🕙🕙🕙🕙🕙🕙🕙。\n\n所有收银员都是一个接一个的在客户面前做完所有的工作👨‍💼⏯.\n\n你必须经过 🕙 较长时间排队，否则你就没机会了。\n\n你可不会想带你的恋人 😍 和你一起去银行办事🏦.\n\n### 汉堡结论 { #burger-conclusion }\n\n在\"你与恋人一起吃汉堡\"的这个场景中，因为有很多人在等待🕙， 使用并发系统更有意义⏸🔀⏯.\n\n大多数 Web 应用都是这样的。\n\n你的服务器正在等待很多很多用户通过他们不太好的网络发送来的请求。\n\n然后再次等待 🕙 响应回来。\n\n这个\"等待\" 🕙 是以微秒为单位测量的，但总的来说，最后还是等待很久。\n\n这就是为什么使用异步对于 Web API 很有意义的原因 ⏸🔀⏯。\n\n这种异步机制正是 NodeJS 受到欢迎的原因（尽管 NodeJS 不是并行的），以及 Go 作为编程语言的优势所在。\n\n这与 **FastAPI** 的性能水平相同。\n\n你可以同时拥有并行性和异步性，你可以获得比大多数经过测试的 NodeJS 框架更高的性能，并且与 Go 不相上下， Go 是一种更接近于 C 的编译语言（[全部归功于 Starlette](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1)）。\n\n### 并发比并行好吗？ { #is-concurrency-better-than-parallelism }\n\n不！这不是故事的本意。\n\n并发不同于并行。而是在需要大量等待的特定场景下效果更好。因此，在 Web 应用程序开发中，它通常比并行要好得多，但这并不意味着全部。\n\n因此，为了平衡这一点，想象一下下面的短篇故事：\n\n> 你必须打扫一个又大又脏的房子。\n\n*是的，这就是完整的故事。*\n\n---\n\n在任何地方， 都不需要等待 🕙 ，只需要在房子的多个地方做着很多工作。\n\n你可以像汉堡的例子那样轮流执行，先是客厅，然后是厨房，但因为你不需要等待 🕙 ，对于任何事情都是清洁，清洁，还是清洁，轮流不会影响任何事情。\n\n无论是否轮流执行（并发），都需要相同的时间来完成，而你也会完成相同的工作量。\n\n但在这种情况下，如果你能带上 8 名前收银员/厨师，现在是清洁工一起清扫，他们中的每一个人（加上你）都能占据房子的一个区域来清扫，你就可以在额外的帮助下并行的更快地完成所有工作。\n\n在这个场景中，每个清洁工（包括你）都将是一个处理器，完成这个工作的一部分。\n\n由于大多数执行时间是由实际工作（而不是等待）占用的，并且计算机中的工作是由 <abbr title=\"Central Processing Unit - 中央处理器\">CPU</abbr> 完成的，所以他们称这些问题为\"CPU 密集型\"。\n\n---\n\nCPU 密集型操作的常见示例是需要复杂的数学处理。\n\n例如：\n\n* **音频**或**图像**处理；\n* **计算机视觉**: 一幅图像由数百万像素组成，每个像素有3种颜色值，处理通常需要同时对这些像素进行计算；\n* **机器学习**: 它通常需要大量的\"矩阵\"和\"向量\"乘法。想象一个包含数字的巨大电子表格，并同时将所有数字相乘；\n* **深度学习**: 这是机器学习的一个子领域，同样适用。只是没有一个数字的电子表格可以相乘，而是一个庞大的数字集合，在很多情况下，你需要使用一个特殊的处理器来构建和使用这些模型。\n\n### 并发 + 并行: Web + 机器学习 { #concurrency-parallelism-web-machine-learning }\n\n使用 **FastAPI**，你可以利用 Web 开发中常见的并发机制的优势（NodeJS 的主要吸引力）。\n\n并且，你也可以利用并行和多进程（让多个进程并行运行）的优点来处理与机器学习系统中类似的 **CPU 密集型** 工作。\n\n这一点，再加上 Python 是**数据科学**、机器学习（尤其是深度学习）的主要语言这一简单事实，使得 **FastAPI** 与数据科学/机器学习 Web API 和应用程序（以及其他许多应用程序）非常匹配。\n\n了解如何在生产环境中实现这种并行性，可查看此文 [部署](deployment/index.md)。\n\n## `async` 和 `await` { #async-and-await }\n\n现代版本的 Python 有一种非常直观的方式来定义异步代码。这使它看起来就像正常的\"顺序\"代码，并在适当的时候\"等待\"。\n\n当有一个操作需要等待才能给出结果，且支持这个新的 Python 特性时，你可以编写如下代码：\n\n```Python\nburgers = await get_burgers(2)\n```\n\n这里的关键是 `await`。它告诉 Python 它必须等待 ⏸ `get_burgers(2)` 完成它的工作 🕙 ，然后将结果存储在 `burgers` 中。这样，Python 就会知道此时它可以去做其他事情 🔀 ⏯ （比如接收另一个请求）。\n\n要使 `await` 工作，它必须位于支持这种异步机制的函数内。因此，只需使用 `async def` 声明它：\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # 执行一些异步操作来制作汉堡\n    return burgers\n```\n\n...而不是 `def`:\n\n```Python hl_lines=\"2\"\n# 这不是异步的\ndef get_sequential_burgers(number: int):\n    # 执行一些顺序操作来制作汉堡\n    return burgers\n```\n\n使用 `async def`，Python 就知道在该函数中，它将遇上 `await`，并且它可以\"暂停\" ⏸ 执行该函数，直至执行其他操作 🔀 后回来。\n\n当你想调用一个 `async def` 函数时，你必须\"等待\"它。因此，这不会起作用：\n\n```Python\n# 这样不行，因为 get_burgers 是用 async def 定义的\nburgers = get_burgers(2)\n```\n\n---\n\n因此，如果你使用的库告诉你可以使用 `await` 调用它，则需要使用 `async def` 创建路径操作函数 ，如：\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### 更多技术细节 { #more-technical-details }\n\n你可能已经注意到，`await` 只能在 `async def` 定义的函数内部使用。\n\n但与此同时，必须\"等待\"通过 `async def` 定义的函数。因此，带 `async def` 的函数也只能在 `async def` 定义的函数内部调用。\n\n那么，这关于先有鸡还是先有蛋的问题，如何调用第一个 `async` 函数？\n\n如果你使用 **FastAPI**，你不必担心这一点，因为\"第一个\"函数将是你的路径操作函数，FastAPI 将知道如何做正确的事情。\n\n但如果你想在没有 FastAPI 的情况下使用 `async` / `await`，则可以这样做。\n\n### 编写自己的异步代码 { #write-your-own-async-code }\n\nStarlette （和 **FastAPI**） 是基于 [AnyIO](https://anyio.readthedocs.io/en/stable/) 实现的，这使得它们可以兼容 Python 的标准库 [asyncio](https://docs.python.org/3/library/asyncio-task.html) 和 [Trio](https://trio.readthedocs.io/en/stable/)。\n\n特别是，你可以直接使用 [AnyIO](https://anyio.readthedocs.io/en/stable/) 来处理高级的并发用例，这些用例需要在自己的代码中使用更高级的模式。\n\n即使你没有使用 **FastAPI**，你也可以使用 [AnyIO](https://anyio.readthedocs.io/en/stable/) 编写自己的异步程序，使其拥有较高的兼容性并获得一些好处（例如， 结构化并发）。\n\n我基于 AnyIO 新建了一个库，作为一个轻量级的封装层，用来优化类型注解，同时提供了更好的**自动补全**、**内联错误提示**等功能。这个库还附带了一个友好的入门指南和教程，能帮助你**理解**并编写**自己的异步代码**：[Asyncer](https://asyncer.tiangolo.com/)。如果你有**结合使用异步代码和常规**（阻塞/同步）代码的需求，这个库会特别有用。\n\n### 其他形式的异步代码 { #other-forms-of-asynchronous-code }\n\n这种使用 `async` 和 `await` 的风格在语言中相对较新。\n\n但它使处理异步代码变得容易很多。\n\n这种相同的语法（或几乎相同）最近也包含在现代版本的 JavaScript 中（在浏览器和 NodeJS 中）。\n\n但在此之前，处理异步代码非常复杂和困难。\n\n在以前版本的 Python，你可以使用多线程或者 [Gevent](https://www.gevent.org/)。但代码的理解、调试和思考都要复杂许多。\n\n在以前版本的 NodeJS / 浏览器 JavaScript 中，你会使用\"回调\"，因此也可能导致“回调地狱”。\n\n## 协程 { #coroutines }\n\n**协程**只是 `async def` 函数返回的一个非常奇特的东西的称呼。Python 知道它有点像一个函数，它可以启动，也会在某个时刻结束，而且它可能会在内部暂停 ⏸ ，只要内部有一个 `await`。\n\n通过使用 `async` 和 `await` 的异步代码的所有功能大多数被概括为\"协程\"。它可以与 Go 的主要关键特性 \"Goroutines\" 相媲美。\n\n## 结论 { #conclusion }\n\n让我们再来回顾下上文所说的：\n\n> Python 的现代版本可以通过使用 `async` 和 `await` 语法创建**协程**，并用于支持**异步代码**。\n\n现在应该能明白其含义了。✨\n\n所有这些使得 FastAPI（通过 Starlette）如此强大，也是它拥有如此令人印象深刻的性能的原因。\n\n## 非常技术性的细节 { #very-technical-details }\n\n/// warning | 警告\n\n你可以跳过这里。\n\n这些都是 FastAPI 如何在内部工作的技术细节。\n\n如果你有相当多的技术知识（协程、线程、阻塞等），并且对 FastAPI 如何处理 `async def` 与常规 `def` 感到好奇，请继续。\n\n///\n\n### 路径操作函数 { #path-operation-functions }\n\n当你使用 `def` 而不是 `async def` 来声明一个*路径操作函数*时，它运行在外部的线程池中并等待其结果，而不是直接调用（因为它会阻塞服务器）。\n\n如果你使用过另一个不以上述方式工作的异步框架，并且你习惯于用普通的 `def` 定义普通的仅计算路径操作函数，以获得微小的性能增益（大约100纳秒），请注意，在 FastAPI 中，效果将完全相反。在这些情况下，最好使用 `async def`，除非路径操作函数内使用执行阻塞 <abbr title=\"Input/Output - 输入/输出：磁盘读写，网络通信。\">I/O</abbr> 的代码。\n\n在这两种情况下，与你之前的框架相比，**FastAPI** 可能[仍然很快](index.md#performance)。\n\n### 依赖 { #dependencies }\n\n这同样适用于[依赖](tutorial/dependencies/index.md)。如果一个依赖是标准的 `def` 函数而不是 `async def`，它将被运行在外部线程池中。\n\n### 子依赖 { #sub-dependencies }\n\n你可以拥有多个相互依赖的依赖以及[子依赖](tutorial/dependencies/sub-dependencies.md) （作为函数的参数），它们中的一些可能是通过 `async def` 声明，也可能是通过 `def` 声明。它们仍然可以正常工作，这些通过 `def` 声明的函数将会在外部线程中调用（来自线程池），而不是\"被等待\"。\n\n### 其他函数 { #other-utility-functions }\n\n你可直接调用通过 `def` 或 `async def` 创建的任何其他函数，FastAPI 不会影响你调用它们的方式。\n\n这与 FastAPI 为你调用*路径操作函数*和依赖项的逻辑相反。\n\n如果你的函数是通过 `def` 声明的，它将被直接调用（在代码中编写的地方），而不会在线程池中，如果这个函数通过 `async def` 声明，当在代码中调用时，你就应该使用 `await` 等待函数的结果。\n\n---\n\n再次提醒，这些是非常技术性的细节，如果你来搜索它可能对你有用。\n\n否则，你最好应该遵守的指导原则<a href=\"#in-a-hurry\">赶时间吗？</a>.\n"
  },
  {
    "path": "docs/zh/docs/benchmarks.md",
    "content": "# 基准测试 { #benchmarks }\n\n第三方机构 TechEmpower 的基准测试表明在 Uvicorn 下运行的 **FastAPI** 应用程序是 [可用的最快的 Python 框架之一](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7)，仅次于 Starlette 和 Uvicorn 本身（由 FastAPI 内部使用）。\n\n但是在查看基准得分和对比时，请注意以下几点。\n\n## 基准测试和速度 { #benchmarks-and-speed }\n\n当你查看基准测试时，几个不同类型的工具被等效地做比较是很常见的情况。\n\n具体来说，是将 Uvicorn，Starlette 和 FastAPI 一起比较（在许多其它工具中）。\n\n该工具解决的问题最简单，它将获得更好的性能。而且大多数基准测试并未测试该工具提供的其他功能。\n\n层次结构如下：\n\n* **Uvicorn**：ASGI服务器\n    * **Starlette**：（使用 Uvicorn）网络微框架\n        * **FastAPI**：（使用 Starlette） 具有多个附加功能的API微框架，用于构建API，进行数据验证等。\n\n* **Uvicorn**:\n    * 具有最佳性能，因为除了服务器本身外，它没有太多额外的代码。\n    * 你不会直接在 Uvicorn 中编写应用程序。这意味着你的代码至少必须包含 Starlette（或 **FastAPI**）提供的代码。如果你这样做了（即直接在 Uvicorn 中编写应用程序），最终的应用程序会和使用了框架并且最小化了应用代码和 bug 的情况具有相同的性能损耗。\n    * 如果你要对比 Uvicorn，请将其与 Daphne，Hypercorn，uWSGI 等应用服务器进行比较。\n* **Starlette**:\n    * 性能仅次于 Uvicorn。实际上，Starlette 使用 Uvicorn 运行。因此，由于必须执行更多的代码，它只会比 Uvicorn 更慢。\n    * 但它为你提供了构建简单的网络程序的工具，并具有基于路径的路由等功能。\n    * 如果想对比与 Starlette 对标的开发框架，请将其与 Sanic，Flask，Django 等网络框架（或微框架）进行比较。\n* **FastAPI**:\n    * 与 Starlette 使用 Uvicorn 一样，由于 **FastAPI** 使用 Starlette，因此 FastAPI 不能比 Starlette 更快。\n    * FastAPI 在 Starlette 基础上提供了更多功能。例如在开发 API 时，所需的数据验证和序列化功能。FastAPI 可以帮助你自动生成 API文档，（文档在应用程序启动时自动生成，所以不会增加应用程序运行时的开销）。\n    * 如果你不使用 FastAPI 而直接使用 Starlette（或诸如 Sanic，Flask，Responder 等其它工具），你则要自己实现所有的数据验证和序列化。那么最终你的应用程序会和使用 FastAPI 构建的程序有相同的开销。一般这种数据验证和序列化的操作在你应用程序的代码中会占很大比重。\n    * 因此，通过使用 FastAPI 意味着你可以节省开发时间，减少编码错误，用更少的编码实现其功能，并且相比不使用 FastAPI 你很大可能会获得相同或更好的性能（因为那样你必须在代码中实现所有相同的功能）。\n    * 如果你想对比 FastAPI，请与能够提供数据验证、序列化和文档的网络应用程序框架（或工具集）进行对比，例如具有集成自动数据验证、序列化和自动化文档的 Flask-apispec，NestJS，Molten 等。\n"
  },
  {
    "path": "docs/zh/docs/deployment/cloud.md",
    "content": "# 在云服务商上部署 FastAPI { #deploy-fastapi-on-cloud-providers }\n\n你几乎可以使用**任何云服务商**来部署你的 FastAPI 应用。\n\n在大多数情况下，主流云服务商都有部署 FastAPI 的指南。\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** 由 **FastAPI** 背后的同一作者与团队打造。\n\n它简化了**构建**、**部署**和**访问** API 的流程，几乎不费力。\n\n它把使用 FastAPI 构建应用时相同的**开发者体验**带到了将应用**部署**到云上的过程。🎉\n\nFastAPI Cloud 是 *FastAPI and friends* 开源项目的主要赞助方和资金提供者。✨\n\n## 云服务商 - 赞助商 { #cloud-providers-sponsors }\n\n还有一些云服务商也会 ✨ [**赞助 FastAPI**](../help-fastapi.md#sponsor-the-author) ✨。🙇\n\n你也可以考虑按照他们的指南尝试他们的服务：\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/zh/docs/deployment/concepts.md",
    "content": "# 部署概念 { #deployments-concepts }\n\n在部署 **FastAPI** 应用程序或任何类型的 Web API 时，有几个概念值得了解，通过掌握这些概念您可以找到**最合适的**方法来**部署您的应用程序**。\n\n一些重要的概念是：\n\n* 安全性 - HTTPS\n* 启动时运行\n* 重新启动\n* 复制（运行的进程数）\n* 内存\n* 开始前的先前步骤\n\n我们接下来了解它们将如何影响**部署**。\n\n我们的最终目标是能够以**安全**的方式**为您的 API 客户端**提供服务，同时要**避免中断**，并且尽可能高效地利用**计算资源**（例如远程服务器/虚拟机）。 🚀\n\n我将在这里告诉您更多关于这些**概念**的信息，希望能给您提供**直觉**来决定如何在非常不同的环境中部署 API，甚至在是尚不存在的**未来**的环境里。\n\n通过考虑这些概念，您将能够**评估和设计**部署**您自己的 API**的最佳方式。\n\n在接下来的章节中，我将为您提供更多部署 FastAPI 应用程序的**具体方法**。\n\n但现在，让我们仔细看一下这些重要的**概念**。 这些概念也适用于任何其他类型的 Web API。 💡\n\n## 安全性 - HTTPS { #security-https }\n\n在[上一章有关 HTTPS](https.md) 中，我们了解了 HTTPS 如何为您的 API 提供加密。\n\n我们还看到，HTTPS 通常由应用程序服务器的**外部**组件（**TLS 终止代理**）提供。\n\n并且必须有某个东西负责**更新 HTTPS 证书**，它可以是相同的组件，也可以是不同的组件。\n\n### HTTPS 示例工具 { #example-tools-for-https }\n\n您可以用作 TLS 终止代理的一些工具包括：\n\n* Traefik\n    * 自动处理证书更新 ✨\n* Caddy\n    * 自动处理证书更新 ✨\n* Nginx\n    * 使用 Certbot 等外部组件进行证书更新\n* HAProxy\n    * 使用 Certbot 等外部组件进行证书更新\n* 带有 Ingress Controller（如 Nginx） 的 Kubernetes\n    * 使用诸如 cert-manager 之类的外部组件来进行证书更新\n* 由云服务商内部处理，作为其服务的一部分（请阅读下文👇）\n\n另一种选择是您可以使用**云服务**来完成更多工作，包括设置 HTTPS。 它可能有一些限制或向您收取更多费用等。但在这种情况下，您不必自己设置 TLS 终止代理。\n\n我将在接下来的章节中向您展示一些具体示例。\n\n---\n\n接下来要考虑的概念都是关于运行实际 API 的程序（例如 Uvicorn）。\n\n## 程序和进程 { #program-and-process }\n\n我们将讨论很多关于正在运行的“**进程**”的内容，因此弄清楚它的含义以及与“**程序**”这个词有什么区别是很有用的。\n\n### 什么是程序 { #what-is-a-program }\n\n**程序**这个词通常用来描述很多东西：\n\n* 您编写的 **代码**，**Python 文件**。\n* 操作系统可以**执行**的**文件**，例如：`python`、`python.exe`或`uvicorn`。\n* 在操作系统上**运行**、使用CPU 并将内容存储在内存上的特定程序。 这也被称为**进程**。\n\n### 什么是进程 { #what-is-a-process }\n\n**进程** 这个词通常以更具体的方式使用，仅指在操作系统中运行的东西（如上面的最后一点）：\n\n* 在操作系统上**运行**的特定程序。\n    * 这不是指文件，也不是指代码，它**具体**指的是操作系统正在**执行**和管理的东西。\n* 任何程序，任何代码，**只有在执行时才能做事**。 因此，是当有**进程正在运行**时。\n* 该进程可以由您或操作系统**终止**（或“杀死”）。 那时，它停止运行/被执行，并且它可以**不再做事情**。\n* 您计算机上运行的每个应用程序背后都有一些进程，每个正在运行的程序，每个窗口等。并且通常在计算机打开时**同时**运行许多进程。\n* **同一程序**可以有**多个进程**同时运行。\n\n如果您检查操作系统中的“任务管理器”或“系统监视器”（或类似工具），您将能够看到许多正在运行的进程。\n\n例如，您可能会看到有多个进程运行同一个浏览器程序（Firefox、Chrome、Edge 等）。 他们通常每个tab运行一个进程，再加上一些其他额外的进程。\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\n现在我们知道了术语“进程”和“程序”之间的区别，让我们继续讨论部署。\n\n## 启动时运行 { #running-on-startup }\n\n在大多数情况下，当您创建 Web API 时，您希望它**始终运行**、不间断，以便您的客户端始终可以访问它。 这是当然的，除非您有特定原因希望它仅在某些情况下运行，但大多数时候您希望它不断运行并且**可用**。\n\n### 在远程服务器中 { #in-a-remote-server }\n\n当您设置远程服务器（云服务器、虚拟机等）时，您可以做的最简单的事情就是使用 `fastapi run`（它使用 Uvicorn）或类似方式，手动运行，就像本地开发时一样。\n\n它将会在**开发过程中**发挥作用并发挥作用。\n\n但是，如果您与服务器的连接丢失，**正在运行的进程**可能会终止。\n\n如果服务器重新启动（例如更新后或从云提供商迁移后），您可能**不会注意到它**。 因此，您甚至不知道必须手动重新启动该进程。 所以，你的 API 将一直处于挂掉的状态。 😱\n\n### 启动时自动运行 { #run-automatically-on-startup }\n\n一般来说，您可能希望服务器程序（例如 Uvicorn）在服务器启动时自动启动，并且不需要任何**人为干预**，让进程始终与您的 API 一起运行（例如 Uvicorn 运行您的 FastAPI 应用程序） 。\n\n### 单独的程序 { #separate-program }\n\n为了实现这一点，您通常会有一个**单独的程序**来确保您的应用程序在启动时运行。 在许多情况下，它还可以确保其他组件或应用程序也运行，例如数据库。\n\n### 启动时运行的示例工具 { #example-tools-to-run-at-startup }\n\n可以完成这项工作的工具的一些示例是：\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker in Swarm Mode\n* Systemd\n* Supervisor\n* 作为其服务的一部分由云提供商内部处理\n* 其他的...\n\n我将在接下来的章节中为您提供更具体的示例。\n\n## 重新启动 { #restarts }\n\n与确保应用程序在启动时运行类似，您可能还想确保它在挂掉后**重新启动**。\n\n### 我们会犯错误 { #we-make-mistakes }\n\n作为人类，我们总是会犯**错误**。 软件几乎*总是*在不同的地方隐藏着**bug**。 🐛\n\n作为开发人员，当我们发现这些bug并实现新功能（也可能添加新bug😅）时，我们会不断改进代码。\n\n### 自动处理小错误 { #small-errors-automatically-handled }\n\n使用 FastAPI 构建 Web API 时，如果我们的代码中存在错误，FastAPI 通常会将其包含到触发错误的单个请求中。 🛡\n\n对于该请求，客户端将收到 **500 内部服务器错误**，但应用程序将继续处理下一个请求，而不是完全崩溃。\n\n### 更大的错误 - 崩溃 { #bigger-errors-crashes }\n\n尽管如此，在某些情况下，我们编写的一些代码可能会导致整个应用程序崩溃，从而导致 Uvicorn 和 Python 崩溃。 💥\n\n尽管如此，您可能不希望应用程序因为某个地方出现错误而保持死机状态，您可能希望它**继续运行**，至少对于未破坏的*路径操作*。\n\n### 崩溃后重新启动 { #restart-after-crash }\n\n但在那些严重错误导致正在运行的**进程**崩溃的情况下，您需要一个外部组件来负责**重新启动**进程，至少尝试几次...\n\n/// tip | 提示\n\n...尽管如果整个应用程序只是**立即崩溃**，那么永远重新启动它可能没有意义。 但在这些情况下，您可能会在开发过程中注意到它，或者至少在部署后立即注意到它。\n\n因此，让我们关注主要情况，在**未来**的某些特定情况下，它可能会完全崩溃，但重新启动它仍然有意义。\n\n///\n\n您可能希望让这个东西作为 **外部组件** 负责重新启动您的应用程序，因为到那时，使用 Uvicorn 和 Python 的同一应用程序已经崩溃了，因此同一应用程序的相同代码中没有东西可以对此做出什么。\n\n### 自动重新启动的示例工具 { #example-tools-to-restart-automatically }\n\n在大多数情况下，用于**启动时运行程序**的同一工具也用于处理自动**重新启动**。\n\n例如，可以通过以下方式处理：\n\n* Docker\n* Kubernetes\n* Docker Compose\n* Docker in Swarm Mode\n* Systemd\n* Supervisor\n* 作为其服务的一部分由云提供商内部处理\n* 其他的...\n\n## 复制 - 进程和内存 { #replication-processes-and-memory }\n\n对于 FastAPI 应用程序，使用像 `fastapi` 命令（运行 Uvicorn）这样的服务器程序，在**一个进程**中运行一次就可以同时为多个客户端提供服务。\n\n但在许多情况下，您会希望同时运行多个工作进程。\n\n### 多进程 - Workers { #multiple-processes-workers }\n\n如果您的客户端数量多于单个进程可以处理的数量（例如，如果虚拟机不是太大），并且服务器的 CPU 中有 **多个核心**，那么您可以让 **多个进程** 同时运行同一个应用程序，并在它们之间分发所有请求。\n\n当您运行同一 API 程序的**多个进程**时，它们通常称为 **workers**。\n\n### 工作进程和端口 { #worker-processes-and-ports }\n\n还记得文档 [关于 HTTPS](https.md) 中只有一个进程可以侦听服务器中的端口和 IP 地址的一种组合吗？\n\n现在仍然是对的。\n\n因此，为了能够同时拥有**多个进程**，必须有一个**单个进程侦听端口**，然后以某种方式将通信传输到每个工作进程。\n\n### 每个进程的内存 { #memory-per-process }\n\n现在，当程序将内容加载到内存中时，例如，将机器学习模型加载到变量中，或者将大文件的内容加载到变量中，所有这些都会消耗服务器的一点内存 (RAM) 。\n\n多个进程通常**不共享任何内存**。 这意味着每个正在运行的进程都有自己的东西、变量和内存。 如果您的代码消耗了大量内存，**每个进程**将消耗等量的内存。\n\n### 服务器内存 { #server-memory }\n\n例如，如果您的代码加载 **1 GB 大小**的机器学习模型，则当您使用 API 运行一个进程时，它将至少消耗 1 GB RAM。 如果您启动 **4 个进程**（4 个工作进程），每个进程将消耗 1 GB RAM。 因此，您的 API 总共将消耗 **4 GB RAM**。\n\n如果您的远程服务器或虚拟机只有 3 GB RAM，尝试加载超过 4 GB RAM 将导致问题。 🚨\n\n### 多进程 - 一个例子 { #multiple-processes-an-example }\n\n在此示例中，有一个 **Manager Process** 启动并控制两个 **Worker Processes**。\n\n该管理器进程可能是监听 IP 中的 **端口** 的进程。 它将所有通信传输到工作进程。\n\n这些工作进程将是运行您的应用程序的进程，它们将执行主要计算以接收 **请求** 并返回 **响应**，并且它们将加载您放入 RAM 中的变量中的任何内容。\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\n当然，除了您的应用程序之外，同一台机器可能还运行**其他进程**。\n\n一个有趣的细节是，随着时间的推移，每个进程使用的 **CPU 百分比**可能会发生很大变化，但**内存 (RAM)** 通常会或多或少保持**稳定**。\n\n如果您有一个每次执行相当数量的计算的 API，并且您有很多客户端，那么 **CPU 利用率** 可能也会保持稳定（而不是不断快速上升和下降）。\n\n### 复制工具和策略示例 { #examples-of-replication-tools-and-strategies }\n\n可以通过多种方法来实现这一目标，我将在接下来的章节中向您详细介绍具体策略，例如在谈论 Docker 和容器时。\n\n要考虑的主要限制是必须有一个**单个**组件来处理**公共IP**中的**端口**。 然后它必须有一种方法将通信**传输**到复制的**进程/worker**。\n\n以下是一些可能的组合和策略：\n\n* 带有 `--workers` 的 **Uvicorn**\n    * 一个 Uvicorn **进程管理器** 将监听 **IP** 和 **端口**，并且它将启动 **多个 Uvicorn 工作进程**。\n* **Kubernetes** 和其他分布式 **容器系统**\n    * **Kubernetes** 层中的某些东西将侦听 **IP** 和 **端口**。 复制将通过拥有**多个容器**，每个容器运行**一个 Uvicorn 进程**。\n* **云服务** 为您处理此问题\n    * 云服务可能**为您处理复制**。 它可能会让您定义 **要运行的进程**，或要使用的 **容器映像**，在任何情况下，它很可能是 **单个 Uvicorn 进程**，并且云服务将负责复制它。\n\n/// tip | 提示\n\n如果这些关于 **容器**、Docker 或 Kubernetes 的内容还没有多大意义，请不要担心。\n\n我将在以后的章节中向您详细介绍容器镜像、Docker、Kubernetes 等：[容器中的 FastAPI - Docker](docker.md)。\n\n///\n\n## 启动之前的步骤 { #previous-steps-before-starting }\n\n在很多情况下，您希望在**启动**应用程序之前执行一些步骤。\n\n例如，您可能想要运行**数据库迁移**。\n\n但在大多数情况下，您只想执行这些步骤**一次**。\n\n因此，在启动应用程序之前，您将需要一个**单个进程**来执行这些**前面的步骤**。\n\n而且您必须确保它是运行前面步骤的单个进程, *即使*之后您为应用程序本身启动**多个进程**（多个worker）。 如果这些步骤由**多个进程**运行，它们会通过在**并行**运行来**重复**工作，并且如果这些步骤像数据库迁移一样需要小心处理，它们可能会导致每个进程和其他进程发生冲突。\n\n当然，也有一些情况，多次运行前面的步骤也没有问题，这样的话就好办多了。\n\n/// tip | 提示\n\n另外，请记住，根据您的设置，在某些情况下，您在开始应用程序之前**可能甚至不需要任何先前的步骤**。\n\n在这种情况下，您就不必担心这些。 🤷\n\n///\n\n### 前面步骤策略的示例 { #examples-of-previous-steps-strategies }\n\n这将在**很大程度上取决于您部署系统的方式**，并且可能与您启动程序、处理重启等的方式有关。\n\n以下是一些可能的想法：\n\n* Kubernetes 中的“Init Container”在应用程序容器之前运行\n* 一个 bash 脚本，运行前面的步骤，然后启动您的应用程序\n    * 您仍然需要一种方法来启动/重新启动 bash 脚本、检测错误等。\n\n/// tip | 提示\n\n我将在以后的章节中为您提供使用容器执行此操作的更具体示例：[容器中的 FastAPI - Docker](docker.md)。\n\n///\n\n## 资源利用率 { #resource-utilization }\n\n您的服务器是一个**资源**，您可以通过您的程序消耗或**利用**CPU 上的计算时间以及可用的 RAM 内存。\n\n您想要消耗/利用多少系统资源？ 您可能很容易认为“不多”，但实际上，您可能希望在不崩溃的情况下**尽可能多地消耗**。\n\n如果您支付了 3 台服务器的费用，但只使用了它们的一点点 RAM 和 CPU，那么您可能**浪费金钱** 💸，并且可能 **浪费服务器电力** 🌎，等等。\n\n在这种情况下，最好只拥有 2 台服务器并使用更高比例的资源（CPU、内存、磁盘、网络带宽等）。\n\n另一方面，如果您有 2 台服务器，并且正在使用 **100% 的 CPU 和 RAM**，则在某些时候，一个进程会要求更多内存，并且服务器将不得不使用磁盘作为“内存” （这可能会慢数千倍），甚至**崩溃**。 或者一个进程可能需要执行一些计算，并且必须等到 CPU 再次空闲。\n\n在这种情况下，最好购买**一台额外的服务器**并在其上运行一些进程，以便它们都有**足够的 RAM 和 CPU 时间**。\n\n由于某种原因，您的 API 的使用量也有可能出现**激增**。 也许它像病毒一样传播开来，或者也许其他一些服务或机器人开始使用它。 在这些情况下，您可能需要额外的资源来保证安全。\n\n您可以将一个**任意数字**设置为目标，例如，资源利用率**在 50% 到 90%** 之间。 重点是，这些可能是您想要衡量和用来调整部署的主要内容。\n\n您可以使用“htop”等简单工具来查看服务器中使用的 CPU 和 RAM 或每个进程使用的数量。 或者您可以使用更复杂的监控工具，这些工具可能分布在服务器等上。\n\n## 回顾 { #recap }\n\n您在这里阅读了一些在决定如何部署应用程序时可能需要牢记的主要概念：\n\n* 安全性 - HTTPS\n* 启动时运行\n* 重新启动\n* 复制（运行的进程数）\n* 内存\n* 开始前的先前步骤\n\n了解这些想法以及如何应用它们应该会给您足够的直觉在配置和调整部署时做出任何决定。 🤓\n\n在接下来的部分中，我将为您提供更具体的示例，说明您可以遵循的可能策略。 🚀\n"
  },
  {
    "path": "docs/zh/docs/deployment/docker.md",
    "content": "# 容器中的 FastAPI - Docker { #fastapi-in-containers-docker }\n\n部署 FastAPI 应用时，常见做法是构建一个**Linux 容器镜像**。通常使用 [**Docker**](https://www.docker.com/) 实现。然后你可以用几种方式之一部署该镜像。\n\n使用 Linux 容器有多种优势，包括**安全性**、**可复制性**、**简单性**等。\n\n/// tip | 提示\n\n赶时间并且已经了解这些？直接跳到下面的 [`Dockerfile` 👇](#build-a-docker-image-for-fastapi)。\n\n///\n\n<details>\n<summary>Dockerfile 预览 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# 如果在 Nginx 或 Traefik 等代理后运行，请添加 --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## 什么是容器 { #what-is-a-container }\n\n容器（主要是 Linux 容器）是一种非常**轻量**的方式，用来打包应用及其所有依赖和必要文件，并让它们与同一系统中的其他容器（其他应用或组件）相互隔离。\n\nLinux 容器复用宿主机（物理机、虚拟机、云服务器等）的同一个 Linux 内核。这意味着它们非常轻量（相较于模拟整个操作系统的完整虚拟机）。\n\n因此，容器消耗的**资源很少**，大致相当于直接运行进程（而虚拟机会多很多）。\n\n容器还拥有各自**隔离**的运行进程（通常只有一个）、文件系统和网络，简化了部署、安全、开发等。\n\n## 什么是容器镜像 { #what-is-a-container-image }\n\n**容器**是从**容器镜像**运行的。\n\n容器镜像是容器中所有文件、环境变量以及应该运行的默认命令/程序的一个**静态**版本。这里的**静态**指容器**镜像**本身并不在运行，仅仅是被打包的文件和元数据。\n\n与存放静态内容的“**容器镜像**”相对，“**容器**”通常指一个正在运行的实例，即正在被**执行**的东西。\n\n当**容器**启动并运行（从**容器镜像**启动）后，它可以创建或修改文件、环境变量等。这些更改只存在于该容器中，不会持久化到底层的容器镜像中（不会写回磁盘）。\n\n容器镜像可类比为**程序**文件及其内容，例如 `python` 和某个文件 `main.py`。\n\n而**容器**本身（相对**容器镜像**）就是该镜像的实际运行实例，可类比为**进程**。事实上，容器只有在有**进程在运行**时才处于运行状态（通常只有一个进程）。当容器中没有任何进程在运行时，容器就会停止。\n\n## 容器镜像 { #container-images }\n\nDocker 一直是创建和管理**容器镜像**与**容器**的主要工具之一。\n\n还有一个公共的 [Docker Hub](https://hub.docker.com/)，其中为许多工具、环境、数据库和应用提供了预制的**官方容器镜像**。\n\n例如，有官方的 [Python 镜像](https://hub.docker.com/_/python)。\n\n还有许多用于不同目的（如数据库）的镜像，例如：\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis) 等。\n\n通过使用预制的容器镜像，可以很容易地**组合**并使用不同工具。例如，试用一个新的数据库。在大多数情况下，你可以直接使用**官方镜像**，只需通过环境变量配置即可。\n\n这样，在很多场景中你可以学习容器和 Docker，并将这些知识复用到许多不同的工具和组件中。\n\n因此，你可以运行包含不同内容的**多个容器**，比如一个数据库、一个 Python 应用、一个带 React 前端的 Web 服务器，并通过它们的内部网络连接在一起。\n\n所有容器管理系统（如 Docker 或 Kubernetes）都内置了这些网络功能。\n\n## 容器与进程 { #containers-and-processes }\n\n**容器镜像**通常在其元数据中包含在**容器**启动时应运行的默认程序或命令以及要传递给该程序的参数。这与命令行中做的事情非常相似。\n\n当**容器**启动时，它将运行该命令/程序（尽管你可以覆盖它，让其运行不同的命令/程序）。\n\n只要**主进程**（命令或程序）在运行，容器就在运行。\n\n容器通常只有**一个进程**，但也可以由主进程启动子进程，这样同一个容器中就会有**多个进程**。\n\n但不可能在没有**至少一个运行中的进程**的情况下让容器保持运行。如果主进程停止，容器也会停止。\n\n## 为 FastAPI 构建 Docker 镜像 { #build-a-docker-image-for-fastapi }\n\n好啦，现在动手构建点东西！🚀\n\n我将演示如何基于**官方 Python** 镜像，**从零开始**为 FastAPI 构建一个**Docker 镜像**。\n\n这在**大多数情况**下都适用，例如：\n\n* 使用 **Kubernetes** 或类似工具\n* 运行在 **Raspberry Pi**\n* 使用某个为你运行容器镜像的云服务，等等\n\n### 包依赖 { #package-requirements }\n\n通常你会把应用的**包依赖**放在某个文件里。\n\n这主要取决于你用来**安装**这些依赖的工具。\n\n最常见的方式是使用 `requirements.txt` 文件，每行一个包名及其版本范围。\n\n当然，你也可以参考你在[关于 FastAPI 版本](versions.md)中读到的思路来设置版本范围。\n\n例如，你的 `requirements.txt` 可能是：\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\n通常你会用 `pip` 安装这些依赖，例如：\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info | 信息\n\n还有其他格式和工具可以定义并安装包依赖。\n\n///\n\n### 编写 **FastAPI** 代码 { #create-the-fastapi-code }\n\n* 创建 `app` 目录并进入\n* 创建空文件 `__init__.py`\n* 创建 `main.py`，内容如下：\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\n现在在同一个项目目录下创建 `Dockerfile` 文件：\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. 从官方 Python 基础镜像开始。\n\n2. 将当前工作目录设置为 `/code`。\n\n    我们会把 `requirements.txt` 文件和 `app` 目录放在这里。\n\n3. 将依赖文件复制到 `/code` 目录。\n\n    首先**只**复制依赖文件，不要复制其他代码。\n\n    因为这个文件**不常变化**，Docker 会检测并在此步骤使用**缓存**，从而也为下一步启用缓存。\n\n4. 安装依赖文件中的包依赖。\n\n    `--no-cache-dir` 选项告诉 `pip` 不要在本地保存下载的包，只有当以后还要再次用 `pip` 安装相同包时才需要，但在容器场景下不是这样。\n\n    /// note | 注意\n\n    `--no-cache-dir` 只和 `pip` 有关，与 Docker 或容器无关。\n\n    ///\n\n    `--upgrade` 选项告诉 `pip` 如果包已安装则进行升级。\n\n    由于上一步复制文件可能被 **Docker 缓存**检测到，因此这一步在可用时也会**使用 Docker 缓存**。\n\n    在开发过程中反复构建镜像时，此步骤使用缓存可以为你**节省大量时间**，而不必**每次**都**下载并安装**所有依赖。\n\n5. 将 `./app` 目录复制到 `/code` 目录。\n\n    这里包含了所有**最常变化**的代码，因此 Docker **缓存**很难用于这一步或**其后的步骤**。\n\n    所以，把它放在 `Dockerfile` 的**靠后位置**，有助于优化容器镜像的构建时间。\n\n6. 设置使用 `fastapi run` 的**命令**（底层使用 Uvicorn）。\n\n    `CMD` 接受一个字符串列表，每个字符串相当于你在命令行中用空格分隔输入的内容。\n\n    该命令会从**当前工作目录**运行，也就是你用 `WORKDIR /code` 设置的 `/code` 目录。\n\n/// tip | 提示\n\n点击代码中的每个编号气泡查看每行的作用。👆\n\n///\n\n/// warning | 警告\n\n务必**始终**使用 `CMD` 指令的**exec 形式**，如下所述。\n\n///\n\n#### 使用 `CMD` - Exec 形式 { #use-cmd-exec-form }\n\n[`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) 指令有两种写法：\n\n✅ **Exec** 形式：\n\n```Dockerfile\n# ✅ 推荐\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ **Shell** 形式：\n\n```Dockerfile\n# ⛔️ 不要这样\nCMD fastapi run app/main.py --port 80\n```\n\n务必使用**exec** 形式，以确保 FastAPI 可以优雅停机并触发[生命周期事件](../advanced/events.md)。\n\n你可以在 [Docker 文档（Shell 与 Exec 形式）](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form)中了解更多。\n\n在使用 `docker compose` 时这一点尤为明显。更多技术细节参见该 FAQ：[为什么我的服务需要 10 秒才能重新创建或停止？](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop)\n\n#### 目录结构 { #directory-structure }\n\n此时你的目录结构应类似：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### 在 TLS 终止代理后面 { #behind-a-tls-termination-proxy }\n\n如果你在 Nginx 或 Traefik 等 TLS 终止代理（负载均衡器）后面运行容器，请添加 `--proxy-headers` 选项，这会通过 FastAPI CLI 告诉 Uvicorn 信任该代理发送的标头，表明应用运行在 HTTPS 后等。\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Docker 缓存 { #docker-cache }\n\n这个 `Dockerfile` 里有个重要技巧：我们先**只复制依赖文件**，而不是其他代码。原因如下：\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker 等工具是**增量**地**构建**容器镜像的，从 `Dockerfile` 顶部开始，按顺序为每条指令创建**一层叠加层**，并把每步生成的文件加入。\n\n构建镜像时，Docker 等工具也会使用**内部缓存**。如果自上次构建以来某个文件没有变更，它会**重用**上次创建的那一层，而不是再次复制文件并从头创建新层。\n\n仅仅避免复制文件并不会带来太多改进，但因为该步骤使用了缓存，它就可以**在下一步中继续使用缓存**。例如，安装依赖的这条指令也能使用缓存：\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\n包含包依赖的文件**不会频繁变更**。仅复制该文件，Docker 就能在这一步**使用缓存**。\n\n随后，Docker 还能**对下一步**（下载并安装依赖）**使用缓存**。这正是我们**节省大量时间**的地方。✨ ...并避免无聊的等待。😪😆\n\n下载并安装依赖**可能需要几分钟**，而使用**缓存**则**最多只需几秒**。\n\n而且在开发中你会反复构建镜像来验证代码变更是否生效，累计节省的时间会很多。\n\n接着，在 `Dockerfile` 的末尾附近我们再复制所有代码。因为这是**变化最频繁**的部分，把它放在后面，这样几乎所有在它之后的步骤都不会使用到缓存。\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### 构建 Docker 镜像 { #build-the-docker-image }\n\n现在所有文件都就位了，开始构建容器镜像。\n\n* 进入项目目录（`Dockerfile` 所在位置，包含 `app` 目录）\n* 构建你的 FastAPI 镜像：\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | 提示\n\n注意末尾的 `.`，它等价于 `./`，用于告诉 Docker 使用哪个目录来构建容器镜像。\n\n此处就是当前目录（`.`）。\n\n///\n\n### 启动 Docker 容器 { #start-the-docker-container }\n\n* 基于你的镜像运行一个容器：\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## 检查一下 { #check-it }\n\n你应该能在容器暴露的 URL 访问它，例如：[http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) 或 [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery)（或其他等价地址，取决于你的 Docker 主机）。\n\n你会看到类似内容：\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## 交互式 API 文档 { #interactive-api-docs }\n\n现在你可以访问 [http://192.168.99.100/docs](http://192.168.99.100/docs) 或 [http://127.0.0.1/docs](http://127.0.0.1/docs)（或其他等价地址，取决于你的 Docker 主机）。\n\n你将看到自动生成的交互式 API 文档（由 [Swagger UI](https://github.com/swagger-api/swagger-ui) 提供）：\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## 备选 API 文档 { #alternative-api-docs }\n\n你还可以访问 [http://192.168.99.100/redoc](http://192.168.99.100/redoc) 或 [http://127.0.0.1/redoc](http://127.0.0.1/redoc)（或其他等价地址，取决于你的 Docker 主机）。\n\n你将看到备选的自动文档（由 [ReDoc](https://github.com/Rebilly/ReDoc) 提供）：\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## 使用单文件 FastAPI 构建 Docker 镜像 { #build-a-docker-image-with-a-single-file-fastapi }\n\n如果你的 FastAPI 是单个文件，例如没有 `./app` 目录、只有 `main.py`，你的文件结构可能如下：\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\n然后你只需要在 `Dockerfile` 中修改相应路径来复制该文件：\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. 直接将 `main.py` 复制到 `/code`（没有 `./app` 目录）。\n\n2. 使用 `fastapi run` 来运行单文件 `main.py` 中的应用。\n\n当你把文件传给 `fastapi run` 时，它会自动检测这是一个单文件而不是包，并知道如何导入并服务你的 FastAPI 应用。😎\n\n## 部署概念 { #deployment-concepts }\n\n我们再从容器的角度讨论一些相同的[部署概念](concepts.md)。\n\n容器主要是简化应用**构建与部署**流程的工具，但它们并不强制采用某种特定方式来处理这些**部署概念**，可选策略有多种。\n\n**好消息**是，不同策略下都有方式覆盖所有部署概念。🎉\n\n让我们从容器角度回顾这些**部署概念**：\n\n* HTTPS\n* 启动时运行\n* 失败重启\n* 复制（运行的进程数）\n* 内存\n* 启动前的前置步骤\n\n## HTTPS { #https }\n\n如果我们只关注 FastAPI 应用的**容器镜像**（以及后续运行的**容器**），HTTPS 通常由**外部**的其他工具处理。\n\n它可以是另一个容器，例如使用 [Traefik](https://traefik.io/)，处理 **HTTPS** 并**自动**获取**证书**。\n\n/// tip | 提示\n\nTraefik 与 Docker、Kubernetes 等都有集成，因此为容器设置和配置 HTTPS 非常容易。\n\n///\n\n或者，HTTPS 也可能由云服务商作为其服务之一提供（应用仍运行在容器中）。\n\n## 启动时运行与重启 { #running-on-startup-and-restarts }\n\n通常会有另一个工具负责**启动并运行**你的容器。\n\n它可以是直接的 **Docker**、**Docker Compose**、**Kubernetes**、某个**云服务**等。\n\n在大多数（或全部）情况下，都有简单选项可以在开机时运行容器并在失败时启用重启。例如，在 Docker 中是命令行选项 `--restart`。\n\n如果不使用容器，要让应用开机自启并带重启可能繁琐且困难。但在**容器**场景下，这种功能通常默认就包含了。✨\n\n## 复制 - 进程数 { #replication-number-of-processes }\n\n如果你有一个由 **Kubernetes**、Docker Swarm Mode、Nomad 或其他类似的复杂系统管理的、在多台机器上运行的分布式容器<dfn title=\"被配置为以某种方式连接并协同工作的多台机器\">集群</dfn>，那么你很可能会希望在**集群层面**来**处理复制**，而不是在每个容器中使用**进程管理**（比如让 Uvicorn 运行多个 workers）。\n\n像 Kubernetes 这样的分布式容器管理系统通常都有某种内置方式来处理**容器复制**，同时对传入请求进行**负载均衡**。这一切都在**集群层面**完成。\n\n在这些情况下，你可能希望如[上文所述](#dockerfile)那样**从头构建 Docker 镜像**，安装依赖，并仅运行**单个 Uvicorn 进程**，而不是使用多个 Uvicorn workers。\n\n### 负载均衡器 { #load-balancer }\n\n使用容器时，通常会有某个组件**监听主端口**。它可能是另一个同时充当 **TLS 终止代理**以处理 **HTTPS** 的容器，或类似工具。\n\n由于该组件会承接请求的**负载**并以（期望）**均衡**的方式在 workers 间分发，它也常被称为**负载均衡器**。\n\n/// tip | 提示\n\n用于 HTTPS 的**TLS 终止代理**组件通常也会是**负载均衡器**。\n\n///\n\n使用容器时，你用来启动和管理容器的系统本身就已有内部工具，将来自该**负载均衡器**（也可能是**TLS 终止代理**）的**网络通信**（例如 HTTP 请求）传递到你的应用容器中。\n\n### 一个负载均衡器 - 多个 worker 容器 { #one-load-balancer-multiple-worker-containers }\n\n在 **Kubernetes** 等分布式容器管理系统中，使用其内部网络机制，允许在主**端口**上监听的单个**负载均衡器**将通信（请求）转发给可能**多个**运行你应用的容器。\n\n这些运行你应用的容器通常每个只有**一个进程**（例如，一个运行 FastAPI 应用的 Uvicorn 进程）。它们都是**相同的容器**，运行相同的东西，但每个都有自己的进程、内存等。这样你就能在 CPU 的**不同核心**，甚至在**不同机器**上利用**并行化**。\n\n分布式容器系统配合**负载均衡器**会把请求**轮流分配**到每个应用容器。因此，每个请求都可能由多个**副本容器**之一来处理。\n\n通常，这个**负载均衡器**还能处理发往集群中*其他*应用的请求（例如不同域名，或不同的 URL 路径前缀），并将通信转发到运行*那个其他*应用的正确容器。\n\n### 每个容器一个进程 { #one-process-per-container }\n\n在这种场景下，你大概率希望**每个容器只有一个（Uvicorn）进程**，因为你已经在集群层面处理了复制。\n\n因此，这种情况下你**不希望**在容器内再启多个 workers（例如通过 `--workers` 命令行选项）。你会希望每个容器仅有一个**单独的 Uvicorn 进程**（但可能会有多个容器）。\n\n在容器内再放一个进程管理器（就像启多个 workers 一样）只会引入**不必要的复杂性**，而这些你很可能已经在集群系统中处理了。\n\n### 具有多个进程和特殊情况的容器 { #containers-with-multiple-processes-and-special-cases }\n\n当然，也有一些**特殊情况**，你可能希望让**一个容器**里运行多个 **Uvicorn worker 进程**。\n\n在这些情况下，你可以使用 `--workers` 命令行选项来设置要运行的 worker 数量：\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. 这里我们使用 `--workers` 命令行选项将 worker 数量设置为 4。\n\n以下是这种做法可能合理的一些示例：\n\n#### 一个简单的应用 { #a-simple-app }\n\n如果你的应用**足够简单**，可以在**单台服务器**（不是集群）上运行，你可能会希望在容器内有一个进程管理器。\n\n#### Docker Compose { #docker-compose }\n\n如果你使用 **Docker Compose** 部署到**单台服务器**（不是集群），那么你不会有一个简单的方法在保留共享网络与**负载均衡**的同时管理容器复制（通过 Docker Compose）。\n\n这种情况下，你可能希望用**单个容器**，由**进程管理器**在容器内启动**多个 worker 进程**。\n\n---\n\n要点是，这些都**不是**你必须盲目遵循的**铁律**。你可以用这些思路来**评估你自己的场景**，并决定最适合你的系统的方法，看看如何管理以下概念：\n\n* 安全 - HTTPS\n* 启动时运行\n* 重启\n* 复制（运行的进程数）\n* 内存\n* 启动前的前置步骤\n\n## 内存 { #memory }\n\n如果你**每个容器只运行一个进程**，那么每个容器消耗的内存将更容易定义、较为稳定且有限（如果有复制则为多个容器）。\n\n接着，你可以在容器管理系统（例如 **Kubernetes**）的配置中设置同样的内存限制与需求。这样它就能在**可用的机器**上**复制容器**，同时考虑容器所需的内存量以及集群中机器可用的内存量。\n\n如果你的应用很**简单**，这可能**不成问题**，你也许不需要设置严格的内存上限。但如果你**使用大量内存**（例如使用**机器学习**模型），你应该检查自己的内存消耗，并调整**每台机器**上运行的**容器数量**（也许还需要为集群增加机器）。\n\n如果你**每个容器运行多个进程**，你需要确保启动的进程数量不会**消耗超过可用的内存**。\n\n## 启动前的前置步骤与容器 { #previous-steps-before-starting-and-containers }\n\n如果你在使用容器（如 Docker、Kubernetes），你可以采用两种主要方式。\n\n### 多个容器 { #multiple-containers }\n\n如果你有**多个容器**，可能每个容器运行一个**单独进程**（例如在 **Kubernetes** 集群中），那么你可能希望使用一个**单独的容器**来执行**前置步骤**，在一个容器中运行一个进程，**在**启动那些复制的 worker 容器**之前**完成。\n\n/// info | 信息\n\n如果你使用 Kubernetes，这通常会是一个 [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)。\n\n///\n\n如果在你的用例中，**并行多次**运行这些前置步骤没有问题（例如你不是在跑数据库迁移，而只是检查数据库是否就绪），那么你也可以把这些步骤放在每个容器中，在启动主进程之前执行。\n\n### 单个容器 { #single-container }\n\n如果你的架构较为简单，使用一个**单个容器**，其后再启动多个**worker 进程**（或者也只有一个进程），那么你可以在同一个容器中，在启动应用进程之前执行这些前置步骤。\n\n### 基础 Docker 镜像 { #base-docker-image }\n\n曾经有一个官方的 FastAPI Docker 镜像：[tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker)。但它现在已被弃用。⛔️\n\n你大概率**不应该**使用这个基础镜像（或任何其它类似的镜像）。\n\n如果你使用 **Kubernetes**（或其他）并且已经在集群层面设置**复制**、使用多个**容器**，那么在这些情况下，最好如上所述**从头构建镜像**：[为 FastAPI 构建 Docker 镜像](#build-a-docker-image-for-fastapi)。\n\n如果你需要多个 workers，可以直接使用 `--workers` 命令行选项。\n\n/// note | 技术细节\n\n这个 Docker 镜像创建于 Uvicorn 还不支持管理与重启失效 workers 的时期，那时需要用 Gunicorn 搭配 Uvicorn，这引入了不少复杂度，只是为了让 Gunicorn 管理并重启 Uvicorn 的 worker 进程。\n\n但现在 Uvicorn（以及 `fastapi` 命令）已经支持使用 `--workers`，因此没有理由不自己构建基础镜像（代码量几乎一样 😅）。\n\n///\n\n## 部署容器镜像 { #deploy-the-container-image }\n\n得到容器（Docker）镜像后，有多种方式可以部署。\n\n例如：\n\n* 在单台服务器上使用 **Docker Compose**\n* 使用 **Kubernetes** 集群\n* 使用 Docker Swarm Mode 集群\n* 使用 Nomad 等其他工具\n* 使用云服务，接收你的容器镜像并部署\n\n## 使用 `uv` 的 Docker 镜像 { #docker-image-with-uv }\n\n如果你使用 [uv](https://github.com/astral-sh/uv) 来安装和管理项目，可以参考他们的 [uv Docker 指南](https://docs.astral.sh/uv/guides/integration/docker/)。\n\n## 回顾 { #recap }\n\n使用容器系统（例如 **Docker** 与 **Kubernetes**）后，处理所有**部署概念**会变得相当直接：\n\n* HTTPS\n* 启动时运行\n* 失败重启\n* 复制（运行的进程数）\n* 内存\n* 启动前的前置步骤\n\n在大多数情况下，你可能不想使用任何基础镜像，而是基于官方 Python Docker 镜像**从头构建容器镜像**。\n\n注意 `Dockerfile` 中指令的**顺序**并利用好**Docker 缓存**，可以**最小化构建时间**，以最大化生产力（并避免无聊）。😎\n"
  },
  {
    "path": "docs/zh/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\n你可以用**一条命令**将你的 FastAPI 应用部署到 [FastAPI Cloud](https://fastapicloud.com)，如果还没有，去加入候补名单吧。🚀\n\n## 登录 { #login }\n\n请确保你已有 **FastAPI Cloud** 账号（我们已从候补名单向你发出邀请 😉）。\n\n然后登录：\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## 部署 { #deploy }\n\n现在用**一条命令**部署你的应用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n就这样！现在你可以通过该 URL 访问你的应用。✨\n\n## 关于 FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** 由 **FastAPI** 背后的作者与团队打造。\n\n它让你以最小的投入完成 API 的**构建**、**部署**与**访问**。\n\n它把使用 FastAPI 构建应用时的**开发者体验**，同样带到将应用**部署**到云上的过程。🎉\n\n它还会替你处理部署应用时大多数需要的事项，例如：\n\n* HTTPS\n* 副本、基于请求的自动伸缩\n* 等等\n\nFastAPI Cloud 是 *FastAPI and friends* 开源项目的主要赞助方与资金提供者。✨\n\n## 部署到其他云服务商 { #deploy-to-other-cloud-providers }\n\nFastAPI 是开源的，并基于标准。你可以将 FastAPI 应用部署到你选择的任意云服务商。\n\n按照你所选云服务商的指南部署 FastAPI 应用即可。🤓\n\n## 部署到你自己的服务器 { #deploy-your-own-server }\n\n在后面的**部署**指南中，我也会讲解所有细节，帮助你理解幕后发生了什么、需要做什么，以及如何自行部署 FastAPI 应用，包括部署到你自己的服务器。🤓\n"
  },
  {
    "path": "docs/zh/docs/deployment/https.md",
    "content": "# 关于 HTTPS { #about-https }\n\n人们很容易认为 HTTPS 仅仅是“启用”或“未启用”的东西。\n\n但实际情况比这复杂得多。\n\n/// tip | 提示\n\n如果你很赶时间或不在乎，请继续阅读后续章节，它们会提供逐步的教程，告诉你怎么使用不同技术把一切都配置好。\n\n///\n\n要从用户的视角**了解 HTTPS 的基础知识**，请查看 [https://howhttps.works/](https://howhttps.works/)。\n\n现在，从**开发人员的视角**，在了解 HTTPS 时需要记住以下几点：\n\n* 要使用 HTTPS，**服务器**需要拥有由**第三方**生成的**\"证书(certificate)\"**。\n    * 这些证书实际上是从第三方**获取**的，而不是“生成”的。\n* 证书有**生命周期**。\n    * 它们会**过期**。\n    * 然后它们需要**更新**，**再次从第三方获取**。\n* 连接的加密发生在 **TCP 层**。\n    * 这是 HTTP 协议**下面的一层**。\n    * 因此，**证书和加密**处理是在 **HTTP之前**完成的。\n* **TCP 不知道域名**。 仅仅知道 IP 地址。\n    * 有关所请求的 **特定域名** 的信息位于 **HTTP 数据**中。\n* **HTTPS 证书**“证明”**某个域名**，但协议和加密发生在 TCP 层，在知道正在处理哪个域名**之前**。\n* **默认情况下**，这意味着你**每个 IP 地址只能拥有一个 HTTPS 证书**。\n    * 无论你的服务器有多大，或者服务器上的每个应用程序有多小。\n    * 不过，对此有一个**解决方案**。\n* **TLS** 协议（在 HTTP 之下的 TCP 层处理加密的协议）有一个**扩展**，称为 **[<abbr title=\"Server Name Indication - 服务器名称指示\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**。\n    * SNI 扩展允许一台服务器（具有 **单个 IP 地址**）拥有 **多个 HTTPS 证书** 并提供 **多个 HTTPS 域名/应用程序**。\n    * 为此，服务器上会有**单独**的一个组件（程序）侦听**公共 IP 地址**，这个组件必须拥有服务器中的**所有 HTTPS 证书**。\n* **获得安全连接后**，通信协议**仍然是HTTP**。\n    * 内容是 **加密过的**，即使它们是通过 **HTTP 协议** 发送的。\n\n通常的做法是在服务器上运行**一个程序/HTTP 服务器**并**管理所有 HTTPS 部分**：接收**加密的 HTTPS 请求**， 将 **解密的 HTTP 请求** 发送到在同一服务器中运行的实际 HTTP 应用程序（在本例中为 **FastAPI** 应用程序），从应用程序中获取 **HTTP 响应**， 使用适当的 **HTTPS 证书**对其进行加密并使用 **HTTPS** 将其发送回客户端。 此服务器通常被称为 **[TLS 终止代理(TLS Termination Proxy)](https://en.wikipedia.org/wiki/TLS_termination_proxy)**。\n\n你可以用作 TLS 终止代理的一些选项包括：\n\n* Traefik（也可以处理证书更新）\n* Caddy（也可以处理证书更新）\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\n在 Let's Encrypt 之前，这些 **HTTPS 证书** 由受信任的第三方出售。\n\n过去，获得这些证书的过程非常繁琐，需要大量的文书工作，而且证书非常昂贵。\n\n但随后 **[Let's Encrypt](https://letsencrypt.org/)** 创建了。\n\n它是 Linux 基金会的一个项目。 它以自动方式免费提供 **HTTPS 证书**。 这些证书可以使用所有符合标准的安全加密，并且有效期很短（大约 3 个月），因此**安全性实际上更好**，因为它们的生命周期缩短了。\n\n域可以被安全地验证并自动生成证书。 这还允许自动更新这些证书。\n\n我们的想法是自动获取和更新这些证书，以便你可以永远免费拥有**安全的 HTTPS**。\n\n## 面向开发人员的 HTTPS { #https-for-developers }\n\n这里有一个 HTTPS API 看起来是什么样的示例，我们会分步说明，并且主要关注对开发人员重要的部分。\n\n### 域名 { #domain-name }\n\n第一步我们要先**获取**一些**域名(Domain Name)**。 然后可以在 DNS 服务器（可能是你的同一家云服务商提供的）中配置它。\n\n你可能拥有一个云服务器（虚拟机）或类似的东西，并且它会有一个<dfn title=\"不会随时间改变。非动态的。\">固定</dfn> **公共IP地址**。\n\n在 DNS 服务器中，你可以配置一条记录（“A 记录”）以将 **你的域名** 指向你服务器的公共 **IP 地址**。\n\n这个操作一般只需要在最开始执行一次。\n\n/// tip | 提示\n\n域名这部分发生在 HTTPS 之前，由于这一切都依赖于域名和 IP 地址，所以先在这里提一下。\n\n///\n\n### DNS { #dns }\n\n现在让我们关注真正的 HTTPS 部分。\n\n首先，浏览器将通过 **DNS 服务器** 查询**域名的IP** 是什么，在本例中为 `someapp.example.com`。\n\nDNS 服务器会告诉浏览器使用某个特定的 **IP 地址**。 这将是你在 DNS 服务器中为你的服务器配置的公共 IP 地址。\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### TLS 握手开始 { #tls-handshake-start }\n\n然后，浏览器将在**端口 443**（HTTPS 端口）上与该 IP 地址进行通信。\n\n通信的第一部分只是建立客户端和服务器之间的连接并决定它们将使用的加密密钥等。\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\n客户端和服务器之间建立 TLS 连接的过程称为 **TLS 握手**。\n\n### 带有 SNI 扩展的 TLS { #tls-with-sni-extension }\n\n**服务器中只有一个进程**可以侦听特定 **IP 地址**的特定 **端口**。 可能有其他进程在同一 IP 地址的其他端口上侦听，但每个 IP 地址和端口组合只有一个进程。\n\nTLS (HTTPS) 默认使用端口`443`。 这就是我们需要的端口。\n\n由于只有一个进程可以监听此端口，因此监听端口的进程将是 **TLS 终止代理**。\n\nTLS 终止代理可以访问一个或多个 **TLS 证书**（HTTPS 证书）。\n\n使用上面讨论的 **SNI 扩展**，TLS 终止代理将检查应该用于此连接的可用 TLS (HTTPS) 证书，并使用与客户端期望的域名相匹配的证书。\n\n在这种情况下，它将使用`someapp.example.com`的证书。\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\n客户端已经**信任**生成该 TLS 证书的实体（在本例中为 Let's Encrypt，但我们稍后会看到），因此它可以**验证**该证书是否有效。\n\n然后，通过使用证书，客户端和 TLS 终止代理 **决定如何加密** **TCP 通信** 的其余部分。 这就完成了 **TLS 握手** 部分。\n\n此后，客户端和服务器就拥有了**加密的 TCP 连接**，这就是 TLS 提供的功能。 然后他们可以使用该连接来启动实际的 **HTTP 通信**。\n\n这就是 **HTTPS**，它只是 **安全 TLS 连接** 内的普通 **HTTP**，而不是纯粹的（未加密的）TCP 连接。\n\n/// tip | 提示\n\n请注意，通信加密发生在 **TCP 层**，而不是 HTTP 层。\n\n///\n\n### HTTPS 请求 { #https-request }\n\n现在客户端和服务器（特别是浏览器和 TLS 终止代理）具有 **加密的 TCP 连接**，它们可以开始 **HTTP 通信**。\n\n接下来，客户端发送一个 **HTTPS 请求**。 这其实只是一个通过 TLS 加密连接的 HTTP 请求。\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### 解密请求 { #decrypt-the-request }\n\nTLS 终止代理将使用协商好的加密算法**解密请求**，并将**（解密的）HTTP 请求**传输到运行应用程序的进程（例如运行 FastAPI 应用的 Uvicorn 进程）。\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### HTTP 响应 { #http-response }\n\n应用程序将处理请求并向 TLS 终止代理发送**（未加密）HTTP 响应**。\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### HTTPS 响应 { #https-response }\n\n然后，TLS 终止代理将使用之前协商的加密算法（以`someapp.example.com`的证书开头）对响应进行加密，并将其发送回浏览器。\n\n接下来，浏览器将验证响应是否有效和是否使用了正确的加密密钥等。然后它会**解密响应**并处理它。\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\n客户端（浏览器）将知道响应来自正确的服务器，因为它使用了他们之前使用 **HTTPS 证书** 协商出的加密算法。\n\n### 多个应用程序 { #multiple-applications }\n\n在同一台（或多台）服务器中，可能存在**多个应用程序**，例如其他 API 程序或数据库。\n\n只有一个进程可以处理特定的 IP 和端口（在我们的示例中为 TLS 终止代理），但其他应用程序/进程也可以在服务器上运行，只要它们不尝试使用相同的 **公共 IP 和端口的组合**。\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\n这样，TLS 终止代理就可以为多个应用程序处理**多个域名**的 HTTPS 和证书，然后在每种情况下将请求传输到正确的应用程序。\n\n### 证书更新 { #certificate-renewal }\n\n在未来的某个时候，每个证书都会**过期**（大约在获得证书后 3 个月）。\n\n然后，会有另一个程序（在某些情况下是另一个程序，在某些情况下可能是同一个 TLS 终止代理）与 Let's Encrypt 通信并更新证书。\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\n**TLS 证书** **与域名相关联**，而不是与 IP 地址相关联。\n\n因此，要更新证书，更新程序需要向权威机构（Let's Encrypt）**证明**它确实**“拥有”并控制该域名**。\n\n有多种方法可以做到这一点。 一些流行的方式是：\n\n* **修改一些DNS记录**。\n    * 为此，续订程序需要支持 DNS 提供商的 API，因此，要看你使用的 DNS 提供商是否提供这一功能。\n* **在与域名关联的公共 IP 地址上作为服务器运行**（至少在证书获取过程中）。\n    * 正如我们上面所说，只有一个进程可以监听特定的 IP 和端口。\n    * 这就是当同一个 TLS 终止代理还负责证书续订过程时它非常有用的原因之一。\n    * 否则，你可能需要暂时停止 TLS 终止代理，启动续订程序以获取证书，然后使用 TLS 终止代理配置它们，然后重新启动 TLS 终止代理。 这并不理想，因为你的应用程序在 TLS 终止代理关闭期间将不可用。\n\n通过拥有一个**单独的系统来使用 TLS 终止代理来处理 HTTPS**, 而不是直接将 TLS 证书与应用程序服务器一起使用 （例如 Uvicorn）,你可以在\n更新证书的过程中同时保持提供服务。\n\n## 代理转发请求头 { #proxy-forwarded-headers }\n\n当使用代理来处理 HTTPS 时，你的**应用服务器**（例如通过 FastAPI CLI 运行的 Uvicorn）对 HTTPS 过程并不了解，它只通过纯 HTTP 与 **TLS 终止代理**通信。\n\n这个**代理**通常会在将请求转发给**应用服务器**之前，临时设置一些 HTTP 请求头，以便让应用服务器知道该请求是由代理**转发**过来的。\n\n/// note | 技术细节\n\n这些代理请求头包括：\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n不过，由于**应用服务器**并不知道自己位于受信任的**代理**之后，默认情况下，它不会信任这些请求头。\n\n但你可以配置**应用服务器**去信任由**代理**发送的这些“转发”请求头。如果你在使用 FastAPI CLI，可以使用命令行选项 `--forwarded-allow-ips` 指定它应该信任哪些 IP 发来的这些“转发”请求头。\n\n例如，如果**应用服务器**只接收来自受信任**代理**的通信，你可以设置 `--forwarded-allow-ips=\"*\"`，让它信任所有传入的 IP，因为它只会接收来自**代理**所使用 IP 的请求。\n\n这样，应用就能知道自己的公共 URL、是否使用 HTTPS、域名等信息。\n\n这在需要正确处理重定向等场景时很有用。\n\n/// tip | 提示\n\n你可以在文档中了解更多：[在代理之后 - 启用代理转发请求头](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)\n\n///\n\n## 回顾 { #recap }\n\n拥有**HTTPS** 非常重要，并且在大多数情况下相当**关键**。 作为开发人员，你围绕 HTTPS 所做的大部分努力就是**理解这些概念**以及它们的工作原理。\n\n一旦你了解了**面向开发人员的 HTTPS** 的基础知识，你就可以轻松组合和配置不同的工具，以帮助你以简单的方式管理一切。\n\n在接下来的一些章节中，我将向你展示几个为 **FastAPI** 应用程序设置 **HTTPS** 的具体示例。 🔒\n"
  },
  {
    "path": "docs/zh/docs/deployment/index.md",
    "content": "# 部署 { #deployment }\n\n部署 **FastAPI** 应用程序相对容易。\n\n## 部署是什么意思 { #what-does-deployment-mean }\n\n**部署**应用程序意味着执行必要的步骤以使其**可供用户使用**。\n\n对于**Web API**来说，通常涉及将其放到一台**远程机器**中，搭配一个性能和稳定性都不错的**服务器程序**，以便你的**用户**可以高效地**访问**你的应用程序，而不会出现中断或其他问题。\n\n这与**开发**阶段形成鲜明对比，在**开发**阶段，你不断更改代码、破坏代码、修复代码，来回停止和重启开发服务器等。\n\n## 部署策略 { #deployment-strategies }\n\n根据你的使用场景和使用的工具，有多种方法可以实现此目的。\n\n你可以使用一些工具自行**部署服务器**，你也可以使用能为你完成部分工作的**云服务**，或其他可能的选项。\n\n例如，我们（FastAPI 团队）构建了 [**FastAPI Cloud**](https://fastapicloud.com)，让将 FastAPI 应用部署到云端尽可能流畅，并且保持与使用 FastAPI 开发时相同的开发者体验。\n\n我将向你展示在部署 **FastAPI** 应用程序时你可能应该记住的一些主要概念（尽管其中大部分适用于任何其他类型的 Web 应用程序）。\n\n在接下来的部分中，你将看到更多需要记住的细节以及一些技巧。 ✨\n"
  },
  {
    "path": "docs/zh/docs/deployment/manually.md",
    "content": "# 手动运行服务器 { #run-a-server-manually }\n\n## 使用 `fastapi run` 命令 { #use-the-fastapi-run-command }\n\n简而言之，使用 `fastapi run` 来运行您的 FastAPI 应用程序：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\n这在大多数情况下都能正常运行。😎\n\n例如，您可以使用该命令在容器、服务器等环境中启动您的 **FastAPI** 应用。\n\n## ASGI 服务器 { #asgi-servers }\n\n让我们深入了解一些细节。\n\nFastAPI 使用了一种用于构建 Python Web 框架和服务器的标准，称为 <abbr title=\"Asynchronous Server Gateway Interface - 异步服务器网关接口\">ASGI</abbr>。FastAPI 本质上是一个 ASGI Web 框架。\n\n要在远程服务器上运行 **FastAPI** 应用（或任何其他 ASGI 应用），您需要一个 ASGI 服务器程序，例如 **Uvicorn**。它是 `fastapi` 命令默认使用的 ASGI 服务器。\n\n除此之外，还有其他一些可选的 ASGI 服务器，例如：\n\n* [Uvicorn](https://www.uvicorn.dev/): 高性能 ASGI 服务器。\n* [Hypercorn](https://hypercorn.readthedocs.io/): 与 HTTP/2 和 Trio 等兼容的 ASGI 服务器。\n* [Daphne](https://github.com/django/daphne): 为 Django Channels 构建的 ASGI 服务器。\n* [Granian](https://github.com/emmett-framework/granian): 基于 Rust 的 HTTP 服务器，专为 Python 应用设计。\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/): NGINX Unit 是一个轻量级且灵活的 Web 应用运行时环境。\n\n## 服务器主机和服务器程序 { #server-machine-and-server-program }\n\n关于名称，有一个小细节需要记住。 💡\n\n“**服务器**”一词通常用于指远程/云计算机（物理机或虚拟机）以及在该计算机上运行的程序（例如 Uvicorn）。\n\n请记住，当您一般读到“服务器”这个名词时，它可能指的是这两者之一。\n\n当提到远程主机时，通常将其称为**服务器**，但也称为**机器**(machine)、**VM**（虚拟机）、**节点**。 这些都是指某种类型的远程计算机，通常运行 Linux，您可以在其中运行程序。\n\n## 安装服务器程序 { #install-the-server-program }\n\n当您安装 FastAPI 时，它自带一个生产环境服务器——Uvicorn，并且您可以使用 `fastapi run` 命令来启动它。\n\n不过，您也可以手动安装 ASGI 服务器。\n\n请确保您创建并激活一个[虚拟环境](../virtual-environments.md)，然后再安装服务器应用程序。\n\n例如，要安装 Uvicorn，可以运行以下命令：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\n类似的流程也适用于任何其他 ASGI 服务器程序。\n\n/// tip | 提示\n\n通过添加 `standard` 选项，Uvicorn 将安装并使用一些推荐的额外依赖项。\n\n其中包括 `uvloop`，这是 `asyncio` 的高性能替代方案，能够显著提升并发性能。\n\n当您使用 `pip install \"fastapi[standard]\"` 安装 FastAPI 时，实际上也会安装 `uvicorn[standard]`。\n\n///\n\n## 运行服务器程序 { #run-the-server-program }\n\n如果您手动安装了 ASGI 服务器，通常需要以特定格式传递一个导入字符串，以便服务器能够正确导入您的 FastAPI 应用：\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note | 注意\n\n命令 `uvicorn main:app` 的含义如下：\n\n* `main`：指的是 `main.py` 文件（即 Python “模块”）。\n* `app`：指的是 `main.py` 文件中通过 `app = FastAPI()` 创建的对象。\n\n它等价于以下导入语句：\n\n```Python\nfrom main import app\n```\n\n///\n\n每种 ASGI 服务器程序通常都会有类似的命令，您可以在它们的官方文档中找到更多信息。\n\n/// warning | 警告\n\nUvicorn 和其他服务器支持 `--reload` 选项，该选项在开发过程中非常有用。\n\n但 `--reload` 选项会消耗更多资源，且相对不稳定。\n\n它对于**开发阶段**非常有帮助，但在**生产环境**中**不应该**使用。\n\n///\n\n## 部署概念 { #deployment-concepts }\n\n这些示例运行服务器程序（例如 Uvicorn），启动**单个进程**，在所有 IP（`0.0.0.0`）上监听预定义端口（例如`80`）。\n\n这是基本思路。 但您可能需要处理一些其他事情，例如：\n\n* 安全性 - HTTPS\n* 启动时运行\n* 重新启动\n* 复制（运行的进程数）\n* 内存\n* 开始前的步骤\n\n在接下来的章节中，我将向您详细介绍每个概念、如何思考它们，以及一些具体示例以及处理它们的策略。 🚀\n"
  },
  {
    "path": "docs/zh/docs/deployment/server-workers.md",
    "content": "# 服务器工作进程（Workers） - 使用 Uvicorn 的多工作进程模式 { #server-workers-uvicorn-with-workers }\n\n让我们回顾一下之前的部署概念：\n\n* 安全性 - HTTPS\n* 启动时运行\n* 重新启动\n* **复制（运行的进程数）**\n* 内存\n* 启动前的先前步骤\n\n到目前为止，在文档中的所有教程中，您可能一直是在运行一个**服务器程序**，例如使用 `fastapi` 命令来启动 Uvicorn，而它默认运行的是**单进程模式**。\n\n部署应用程序时，您可能希望进行一些**进程复制**，以利用**多核** CPU 并能够处理更多请求。\n\n正如您在上一章有关[部署概念](concepts.md)中看到的，您可以使用多种策略。\n\n在本章节中，我将向您展示如何使用 `fastapi` 命令或直接使用 `uvicorn` 命令以**多工作进程模式**运行 **Uvicorn**。\n\n/// info | 信息\n\n如果您正在使用容器，例如 Docker 或 Kubernetes，我将在下一章中告诉您更多相关信息：[容器中的 FastAPI - Docker](docker.md)。\n\n比较特别的是，在 **Kubernetes** 环境中运行时，您通常**不需要**使用多个工作进程，而是**每个容器运行一个 Uvicorn 进程**。不过，我会在本章节的后续部分详细介绍这一点。\n\n///\n\n## 多个工作进程 { #multiple-workers }\n\n您可以使用 `--workers` 命令行选项来启动多个工作进程：\n\n//// tab | `fastapi`\n\n如果您使用 `fastapi` 命令：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\n如果您更想要直接使用 `uvicorn` 命令：\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\n这里唯一的新选项是 `--workers` 告诉 Uvicorn 启动 4 个工作进程。\n\n您还可以看到它显示了每个进程的 **PID**，父进程（这是**进程管理器**）的 PID 为`27365`，每个工作进程的 PID 为：`27368`、`27369`， `27370`和`27367`。\n\n## 部署概念 { #deployment-concepts }\n\n在这里，您学习了如何使用多个**工作进程（workers）**来让应用程序的执行**并行化**，充分利用 CPU 的**多核性能**，并能够处理**更多的请求**。\n\n从上面的部署概念列表来看，使用worker主要有助于**复制**部分，并对**重新启动**有一点帮助，但您仍然需要照顾其他部分：\n\n* **安全 - HTTPS**\n* **启动时运行**\n* ***重新启动***\n* 复制（运行的进程数）\n* **内存**\n* **启动之前的先前步骤**\n\n## 容器和 Docker { #containers-and-docker }\n\n在关于 [容器中的 FastAPI - Docker](docker.md) 的下一章中，我将介绍一些可用于处理其他**部署概念**的策略。\n\n我将向您展示如何**从零开始构建自己的镜像**，以运行一个单独的 Uvicorn 进程。这个过程相对简单，并且在使用 **Kubernetes** 等分布式容器管理系统时，这通常是您需要采取的方法。\n\n## 回顾 { #recap }\n\n您可以在使用 `fastapi` 或 `uvicorn` 命令时，通过 `--workers` CLI 选项启用多个工作进程（workers），以充分利用**多核 CPU**，以**并行运行多个进程**。\n\n如果您要设置**自己的部署系统**，同时自己处理其他部署概念，则可以使用这些工具和想法。\n\n请查看下一章，了解带有容器（例如 Docker 和 Kubernetes）的 **FastAPI**。 您将看到这些工具也有简单的方法来解决其他**部署概念**。 ✨\n"
  },
  {
    "path": "docs/zh/docs/deployment/versions.md",
    "content": "# 关于 FastAPI 版本 { #about-fastapi-versions }\n\n**FastAPI** 已在许多应用程序和系统的生产环境中使用。 并且测试覆盖率保持在100%。 但其开发进度仍在快速推进。\n\n经常添加新功能，定期修复错误，并且代码仍在持续改进。\n\n这就是为什么当前版本仍然是`0.x.x`，这反映出每个版本都可能有Breaking changes。 这遵循[语义版本控制](https://semver.org/)的约定。\n\n你现在就可以使用 **FastAPI** 创建生产环境应用程序（你可能已经这样做了一段时间），你只需确保使用的版本可以与其余代码正确配合即可。\n\n## 固定你的 `fastapi` 版本 { #pin-your-fastapi-version }\n\n你应该做的第一件事是将你正在使用的 **FastAPI** 版本“固定”到你知道适用于你的应用程序的特定最新版本。\n\n例如，假设你在应用程序中使用版本`0.112.0`。\n\n如果你使用`requirements.txt`文件，你可以使用以下命令指定版本：\n\n```txt\nfastapi[standard]==0.112.0\n```\n\n这意味着你将使用版本`0.112.0`。\n\n或者你也可以将其固定为：\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\n这意味着你将使用`0.112.0`或更高版本，但低于`0.113.0`，例如，版本`0.112.2`仍会被接受。\n\n如果你使用任何其他工具来管理你的安装，例如 `uv`、Poetry、Pipenv 或其他工具，它们都有一种定义包的特定版本的方法。\n\n## 可用版本 { #available-versions }\n\n你可以在[发行说明](../release-notes.md)中查看可用版本（例如查看当前最新版本）。\n\n## 关于版本 { #about-versions }\n\n遵循语义版本控制约定，任何低于`1.0.0`的版本都可能会添加 breaking changes。\n\nFastAPI 还遵循这样的约定：任何\"PATCH\"版本更改都是为了bug修复和non-breaking changes。\n\n/// tip | 提示\n\n\"PATCH\"是最后一个数字，例如，在`0.2.3`中，PATCH版本是`3`。\n\n///\n\n因此，你应该能够固定到如下版本：\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\n\"MINOR\"版本中会添加breaking changes和新功能。\n\n/// tip | 提示\n\n\"MINOR\"是中间的数字，例如，在`0.2.3`中，MINOR版本是`2`。\n\n///\n\n## 升级FastAPI版本 { #upgrading-the-fastapi-versions }\n\n你应该为你的应用程序添加测试。\n\n使用 **FastAPI** 编写测试非常简单（感谢 Starlette），请参考文档：[测试](../tutorial/testing.md)\n\n添加测试后，你可以将 **FastAPI** 版本升级到更新版本，并通过运行测试来确保所有代码都能正常工作。\n\n如果一切正常，或者在进行必要的更改之后，并且所有测试都通过了，那么你可以将`fastapi`固定到新的版本。\n\n## 关于Starlette { #about-starlette }\n\n你不应该固定`starlette`的版本。\n\n不同版本的 **FastAPI** 将使用特定的较新版本的 Starlette。\n\n因此，**FastAPI** 自己可以使用正确的 Starlette 版本。\n\n## 关于 Pydantic { #about-pydantic }\n\nPydantic 包含针对 **FastAPI** 的测试及其自己的测试，因此 Pydantic 的新版本（`1.0.0`以上）始终与 FastAPI 兼容。\n\n你可以将 Pydantic 固定到任何高于 `1.0.0` 且适合你的版本。\n\n例如：\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/zh/docs/editor-support.md",
    "content": "# 编辑器支持 { #editor-support }\n\n官方的 [FastAPI 扩展](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode)为你的 FastAPI 开发流程带来增强，包括*路径操作*的发现与导航、部署到 FastAPI Cloud，以及实时日志流式传输。\n\n有关该扩展的更多详情，请参阅其 [GitHub 仓库](https://github.com/fastapi/fastapi-vscode)中的 README。\n\n## 安装与配置 { #setup-and-installation }\n\n**FastAPI 扩展**同时适用于 [VS Code](https://code.visualstudio.com/) 和 [Cursor](https://www.cursor.com/)。你可以在各编辑器的扩展面板中直接搜索 “FastAPI”，并选择由 **FastAPI Labs** 发布的扩展进行安装。该扩展也适用于基于浏览器的编辑器，例如 [vscode.dev](https://vscode.dev) 和 [github.dev](https://github.dev)。\n\n### 应用发现 { #application-discovery }\n\n默认情况下，扩展会通过扫描实例化了 `FastAPI()` 的文件，自动发现工作区中的 FastAPI 应用。如果你的项目结构无法自动检测，你可以通过 `pyproject.toml` 中的 `[tool.fastapi]` 或 VS Code 设置项 `fastapi.entryPoint` 来指定入口点，使用模块表示法（例如 `myapp.main:app`）。\n\n## 功能 { #features }\n\n- **Path Operation 资源管理器** - 侧边栏树状视图展示应用中的所有 <dfn title=\"路由，端点\">*路径操作*</dfn>。点击可跳转至任一路由或 APIRouter 的定义。\n- **路由搜索** - 使用 <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>（macOS 上为 <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>）按路径、方法或名称进行搜索。\n- **CodeLens 导航** - 测试客户端调用（例如 `client.get('/items')`）上方的可点击链接，可跳转到匹配的*路径操作*，在测试与实现之间快速往返。\n- **部署到 FastAPI Cloud** - 一键将你的应用部署到 [FastAPI Cloud](https://fastapicloud.com/)。\n- **应用日志流式传输** - 从部署在 FastAPI Cloud 的应用中实时流式获取日志，并支持按级别过滤与文本搜索。\n\n如果你想先熟悉扩展功能，可以打开命令面板（<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>，macOS 上为 <kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>），选择 “Welcome: Open walkthrough...”，然后选择 “Get started with FastAPI” 演练。\n"
  },
  {
    "path": "docs/zh/docs/environment-variables.md",
    "content": "# 环境变量 { #environment-variables }\n\n/// tip | 提示\n\n如果你已经知道什么是“环境变量”并且知道如何使用它们，你可以放心跳过这一部分。\n\n///\n\n环境变量（也称为“**env var**”）是一个独立于 Python 代码**之外**的变量，它存在于**操作系统**中，可以被你的 Python 代码（或其他程序）读取。\n\n环境变量对于处理应用程序**设置**、作为 Python **安装**的一部分等方面非常有用。\n\n## 创建和使用环境变量 { #create-and-use-env-vars }\n\n你在 **shell（终端）**中就可以**创建**和使用环境变量，并不需要用到 Python：\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// 你可以使用以下命令创建一个名为 MY_NAME 的环境变量\n$ export MY_NAME=\"Wade Wilson\"\n\n// 然后，你可以在其他程序中使用它，例如\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// 创建一个名为 MY_NAME 的环境变量\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// 在其他程序中使用它，例如\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## 在 Python 中读取环境变量 { #read-env-vars-in-python }\n\n你也可以在 Python **之外**的终端中创建环境变量（或使用任何其他方法），然后在 Python 中**读取**它们。\n\n例如，你可以创建一个名为 `main.py` 的文件，其中包含以下内容：\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip | 提示\n\n第二个参数是 [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) 的默认返回值。\n\n如果没有提供，默认值为 `None`，这里我们提供 `\"World\"` 作为默认值。\n\n///\n\n然后你可以调用这个 Python 程序：\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// 这里我们还没有设置环境变量\n$ python main.py\n\n// 因为我们没有设置环境变量，所以我们得到的是默认值\n\nHello World from Python\n\n// 但是如果我们事先创建过一个环境变量\n$ export MY_NAME=\"Wade Wilson\"\n\n// 然后再次调用程序\n$ python main.py\n\n// 现在就可以读取到环境变量了\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// 这里我们还没有设置环境变量\n$ python main.py\n\n// 因为我们没有设置环境变量，所以我们得到的是默认值\n\nHello World from Python\n\n// 但是如果我们事先创建过一个环境变量\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// 然后再次调用程序\n$ python main.py\n\n// 现在就可以读取到环境变量了\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n由于环境变量可以在代码之外设置、但可以被代码读取，并且不必与其他文件一起存储（提交到 `git`），因此通常用于配置或**设置**。\n\n你还可以为**特定的程序调用**创建特定的环境变量，该环境变量仅对该程序可用，且仅在其运行期间有效。\n\n要实现这一点，只需在同一行内、程序本身之前创建它：\n\n<div class=\"termy\">\n\n```console\n// 在这个程序调用的同一行中创建一个名为 MY_NAME 的环境变量\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// 现在就可以读取到环境变量了\n\nHello Wade Wilson from Python\n\n// 在此之后这个环境变量将不会依然存在\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip | 提示\n\n你可以在 [The Twelve-Factor App: 配置](https://12factor.net/config) 中了解更多信息。\n\n///\n\n## 类型和验证 { #types-and-validation }\n\n这些环境变量只能处理**文本字符串**，因为它们是处于 Python 范畴之外的，必须与其他程序和操作系统的其余部分兼容（甚至与不同的操作系统兼容，如 Linux、Windows、macOS）。\n\n这意味着从环境变量中读取的**任何值**在 Python 中都将是一个 `str`，任何类型转换或验证都必须在代码中完成。\n\n你将在[高级用户指南 - 设置和环境变量](./advanced/settings.md)中了解更多关于使用环境变量处理**应用程序设置**的信息。\n\n## `PATH` 环境变量 { #path-environment-variable }\n\n有一个**特殊的**环境变量称为 **`PATH`**，操作系统（Linux、macOS、Windows）用它来查找要运行的程序。\n\n`PATH` 变量的值是一个长字符串，由 Linux 和 macOS 上的冒号 `:` 分隔的目录组成，而在 Windows 上则是由分号 `;` 分隔的。\n\n例如，`PATH` 环境变量可能如下所示：\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\n这意味着系统应该在以下目录中查找程序：\n\n-   `/usr/local/bin`\n-   `/usr/bin`\n-   `/bin`\n-   `/usr/sbin`\n-   `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\n这意味着系统应该在以下目录中查找程序：\n\n-   `C:\\Program Files\\Python312\\Scripts`\n-   `C:\\Program Files\\Python312`\n-   `C:\\Windows\\System32`\n\n////\n\n当你在终端中输入一个**命令**时，操作系统会在 `PATH` 环境变量中列出的**每个目录**中**查找**程序。\n\n例如，当你在终端中输入 `python` 时，操作系统会在该列表中的**第一个目录**中查找名为 `python` 的程序。\n\n如果找到了，那么操作系统将**使用它**；否则，操作系统会继续在**其他目录**中查找。\n\n### 安装 Python 和更新 `PATH` { #installing-python-and-updating-the-path }\n\n安装 Python 时，可能会询问你是否要更新 `PATH` 环境变量。\n\n//// tab | Linux, macOS\n\n假设你安装 Python 并最终将其安装在了目录 `/opt/custompython/bin` 中。\n\n如果你同意更新 `PATH` 环境变量，那么安装程序将会将 `/opt/custompython/bin` 添加到 `PATH` 环境变量中。\n\n它看起来大概会像这样：\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\n如此一来，当你在终端中输入 `python` 时，系统会在 `/opt/custompython/bin` 中找到 Python 程序（最后一个目录）并使用它。\n\n////\n\n//// tab | Windows\n\n假设你安装 Python 并最终将其安装在了目录 `C:\\opt\\custompython\\bin` 中。\n\n如果你同意更新 `PATH` 环境变量，那么安装程序将会将 `C:\\opt\\custompython\\bin` 添加到 `PATH` 环境变量中。\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\n如此一来，当你在终端中输入 `python` 时，系统会在 `C:\\opt\\custompython\\bin` 中找到 Python 程序（最后一个目录）并使用它。\n\n////\n\n因此，如果你输入：\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\n系统会在 `/opt/custompython/bin` 中**找到** `python` 程序并运行它。\n\n这和输入以下命令大致等价：\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\n系统会在 `C:\\opt\\custompython\\bin\\python` 中**找到** `python` 程序并运行它。\n\n这和输入以下命令大致等价：\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\n当学习[虚拟环境](virtual-environments.md)时，这些信息将会很有用。\n\n## 结论 { #conclusion }\n\n通过这个教程，你应该对**环境变量**是什么以及如何在 Python 中使用它们有了基本的了解。\n\n你也可以在[环境变量 - 维基百科](https://en.wikipedia.org/wiki/Environment_variable)中了解更多关于它们的信息。\n\n在许多情况下，环境变量的用途和适用性并不是很明显。但是在开发过程中，它们会在许多不同的场景中出现，因此了解它们是很有必要的。\n\n例如，你将在下一节关于[虚拟环境](virtual-environments.md)中需要这些信息。\n"
  },
  {
    "path": "docs/zh/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - 命令行接口\">CLI</abbr>** 是一个命令行程序，你可以用它来部署和运行你的 FastAPI 应用、管理 FastAPI 项目，等等。\n\n当你安装 FastAPI（例如使用 `pip install \"fastapi[standard]\"`）时，会附带一个可以在终端中运行的命令行程序。\n\n要在开发环境中运行你的 FastAPI 应用，可以使用 `fastapi dev` 命令：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip | 提示\n\n在生产环境中，你会使用 `fastapi run` 而不是 `fastapi dev`。🚀\n\n///\n\n在内部，**FastAPI CLI** 使用 [Uvicorn](https://www.uvicorn.dev)，这是一个高性能、适用于生产环境的 ASGI 服务器。😎\n\n`fastapi` CLI 会尝试自动检测要运行的 FastAPI 应用，默认假设它是文件 `main.py` 中名为 `app` 的对象（或少数其他变体）。\n\n但你也可以显式配置要使用的应用。\n\n## 在 `pyproject.toml` 中配置应用的 `entrypoint` { #configure-the-app-entrypoint-in-pyproject-toml }\n\n你可以在 `pyproject.toml` 文件中配置应用的位置，例如：\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\n这个 `entrypoint` 会告诉 `fastapi` 命令按如下方式导入应用：\n\n```python\nfrom main import app\n```\n\n如果你的代码结构如下：\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\n那么你可以将 `entrypoint` 设置为：\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\n这等价于：\n\n```python\nfrom backend.main import app\n```\n\n### 带路径的 `fastapi dev` { #fastapi-dev-with-path }\n\n你也可以把文件路径传给 `fastapi dev` 命令，它会猜测要使用的 FastAPI 应用对象：\n\n```console\n$ fastapi dev main.py\n```\n\n但每次运行 `fastapi` 命令都需要记得传入正确的路径。\n\n另外，其他工具可能找不到它，例如 [VS Code 扩展](editor-support.md) 或 [FastAPI Cloud](https://fastapicloud.com)，因此推荐在 `pyproject.toml` 中使用 `entrypoint`。\n\n## `fastapi dev` { #fastapi-dev }\n\n当你运行 `fastapi dev` 时，它将以开发模式运行。\n\n默认情况下，它会启用**自动重载**，因此当你更改代码时，它会自动重新加载服务器。该功能是资源密集型的，且相较不启用时更不稳定，因此你应该仅在开发环境下使用它。它还会监听 IP 地址 `127.0.0.1`，这是你的机器仅与自身通信的 IP（`localhost`）。\n\n## `fastapi run` { #fastapi-run }\n\n当你运行 `fastapi run` 时，它默认以生产环境模式运行。\n\n默认情况下，**自动重载是禁用的**。它将监听 IP 地址 `0.0.0.0`，即所有可用的 IP 地址，这样任何能够与该机器通信的人都可以公开访问它。这通常是你在生产环境中运行它的方式，例如在容器中运行。\n\n在大多数情况下，你会（且应该）有一个“终止代理”在上层为你处理 HTTPS，这取决于你如何部署应用程序，你的服务提供商可能会为你处理此事，或者你可能需要自己设置。\n\n/// tip | 提示\n\n你可以在[部署文档](deployment/index.md)中了解更多。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/features.md",
    "content": "# 特性 { #features }\n\n## FastAPI 特性 { #fastapi-features }\n\n**FastAPI** 提供了以下内容：\n\n### 基于开放标准 { #based-on-open-standards }\n\n* [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) 用于创建 API，包含对<dfn title=\"也称为：端点、路由\">路径</dfn> <dfn title=\"也称为 HTTP 方法，如 POST、GET、PUT、DELETE\">操作</dfn>、参数、请求体、安全等的声明。\n* 使用 [**JSON Schema**](https://json-schema.org/) 自动生成数据模型文档（因为 OpenAPI 本身就是基于 JSON Schema 的）。\n* 经过了缜密的研究后围绕这些标准而设计。并非狗尾续貂。\n* 这也允许了在很多语言中自动**生成客户端代码**。\n\n### 自动生成文档 { #automatic-docs }\n\n交互式 API 文档以及具探索性 web 界面。因为该框架是基于 OpenAPI，所以有很多可选项，FastAPI 默认自带两个交互式 API 文档。\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui)，可交互式操作，能在浏览器中直接调用和测试你的 API。\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* 另外的 API 文档：[**ReDoc**](https://github.com/Rebilly/ReDoc)\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### 更主流的 Python { #just-modern-python }\n\n全部都基于标准的 **Python 类型** 声明（感谢 Pydantic）。没有新的语法需要学习。只需要标准的现代 Python。\n\n如果你需要2分钟来学习如何使用 Python 类型（即使你不使用 FastAPI），看看这个简短的教程：[Python 类型](python-types.md)。\n\n编写带有类型标注的标准 Python：\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# 将变量声明为 str\n# 并在函数内获得编辑器支持\ndef main(user_id: str):\n    return user_id\n\n\n# 一个 Pydantic 模型\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\n可以像这样来使用：\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n\n/// info | 信息\n\n`**second_user_data` 意思是：\n\n直接将 `second_user_data` 字典的键和值作为 key-value 参数传入，等同于：`User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### 编辑器支持 { #editor-support }\n\n整个框架都被设计得易于使用且直观，所有的决定都在开发之前就在多个编辑器上进行了测试，来确保最佳的开发体验。\n\n在 Python 开发者调查中，我们能看到[被使用最多的功能之一是“自动补全”](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features)。\n\n整个 **FastAPI** 框架就是基于这一点的。任何地方都可以进行自动补全。\n\n你几乎不需要经常回来看文档。\n\n在这里，你的编辑器可能会这样帮助你：\n\n* 在 [Visual Studio Code](https://code.visualstudio.com/) 中:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* 在 [PyCharm](https://www.jetbrains.com/pycharm/) 中:\n\n![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\n你将能进行代码补全，这是在之前你可能曾认为不可能的事。例如，在来自请求 JSON 体（可能是嵌套的）中的键 `price`。\n\n不会再输错键名，来回翻看文档，或者来回滚动寻找你最后使用的 `username` 或者 `user_name`。\n\n### 简洁 { #short }\n\n任何类型都有合理的**默认值**，任何和地方都有可选配置。所有的参数被微调，来满足你的需求，定义成你需要的 API。\n\n但是默认情况下，一切都能**“顺利工作”**。\n\n### 验证 { #validation }\n\n* 校验大部分（甚至所有？）的 Python **数据类型**，包括：\n    * JSON 对象 (`dict`)。\n    * JSON 数组 (`list`) 定义成员类型。\n    * 字符串 (`str`) 字段，定义最小或最大长度。\n    * 数字 (`int`, `float`) 有最大值和最小值，等等。\n\n* 校验外来类型，比如：\n    * URL。\n    * Email。\n    * UUID。\n    * ...及其他。\n\n所有的校验都由完善且强大的 **Pydantic** 处理。\n\n### 安全性及身份验证 { #security-and-authentication }\n\n集成了安全性和身份认证。杜绝数据库或者数据模型的渗透风险。\n\nOpenAPI 中定义的安全模式，包括：\n\n* HTTP 基本认证。\n* **OAuth2**（也使用 **JWT tokens**）。在 [使用 JWT 的 OAuth2](tutorial/security/oauth2-jwt.md) 查看教程。\n* API 密钥，在:\n    * 请求头。\n    * 查询参数。\n    * Cookies，等等。\n\n加上来自 Starlette（包括 **session cookie**）的所有安全特性。\n\n所有的这些都是可复用的工具和组件，可以轻松与你的系统，数据仓库，关系型以及 NoSQL 数据库等等集成。\n\n### 依赖注入 { #dependency-injection }\n\nFastAPI 有一个使用非常简单，但是非常强大的<dfn title='也称为 \"components\"、\"resources\"、\"services\"、\"providers\"'><strong>依赖注入</strong></dfn>系统。\n\n* 甚至依赖也可以有依赖，创建一个层级或者**“图”依赖**。\n* 所有**自动化处理**都由框架完成。\n* 所有的依赖关系都可以从请求中获取数据，并且**增加了路径操作**约束和自动文档生成。\n* 即使是在依赖项中定义的路径操作参数也会**自动验证**。\n* 支持复杂的用户身份认证系统，**数据库连接**等等。\n* **不依赖**数据库，前端等。但是和它们集成很简单。\n\n### 无限制的“插件” { #unlimited-plug-ins }\n\n或者说，导入并使用你需要的代码，而不需要它们。\n\n任何集成都被设计得被易于使用（用依赖关系），你可以用和*路径操作*相同的结构和语法，在两行代码中为你的应用创建一个“插件”。\n\n### 测试 { #tested }\n\n* 100% <dfn title=\"自动测试的代码量\">测试覆盖</dfn>。\n* 代码库100% <dfn title=\"Python 类型注解，有了这个你的编辑器和外部工具可以给你更好的支持\">类型注释</dfn>。\n* 用于生产应用。\n\n## Starlette 特性 { #starlette-features }\n\n**FastAPI** 和 [**Starlette**](https://www.starlette.dev/) 完全兼容（并基于）。所以，你有的其他的 Starlette 代码也能正常工作。`FastAPI` 实际上是 `Starlette` 的一个子类。所以，如果你已经知道或者使用 Starlette，大部分的功能会以相同的方式工作。\n\n通过 **FastAPI** 你可以获得所有 **Starlette** 的特性（FastAPI 就像加强版的 Starlette）：\n\n* 令人惊叹的性能。它是[Python 可用的最快的框架之一，和 **NodeJS** 及 **Go** 相当](https://github.com/encode/starlette#performance)。\n* **支持 WebSocket**。\n* 进程内后台任务。\n* Startup 和 shutdown 事件。\n* 测试客户端基于 HTTPX。\n* **CORS**、GZip、静态文件、流响应。\n* 支持 **Session 和 Cookie**。\n* 100% 测试覆盖率。\n* 代码库 100% 类型注释。\n\n## Pydantic 特性 { #pydantic-features }\n\n**FastAPI** 和 [**Pydantic**](https://docs.pydantic.dev/) 完全兼容（并基于）。所以，你有的其他的 Pydantic 代码也能正常工作。\n\n兼容包括基于 Pydantic 的外部库，例如用于数据库的 <abbr title=\"Object-Relational Mapper - 对象关系映射\">ORM</abbr>s、<abbr title=\"Object-Document Mapper - 对象文档映射\">ODM</abbr>s。\n\n这也意味着在很多情况下，你可以将从请求中获得的相同对象**直接传到数据库**，因为所有的验证都是自动的。\n\n反之亦然，在很多情况下，你也可以将从数据库中获取的对象**直接传到客户端**。\n\n通过 **FastAPI** 你可以获得所有 **Pydantic**（FastAPI 基于 Pydantic 做了所有的数据处理）：\n\n* **不烧脑**：\n    * 没有新的模式定义 micro-language 需要学习。\n    * 如果你知道 Python types，你就知道如何使用 Pydantic。\n* 和你 **<abbr title=\"Integrated Development Environment - 集成开发环境: 类似于代码编辑器\">IDE</abbr>/<dfn title=\"一个检查代码错误的程序\">linter</dfn>/brain** 适配:\n    * 因为 pydantic 数据结构仅仅是你定义的类的实例；自动补全，linting，mypy 以及你的直觉应该可以和你验证的数据一起正常工作。\n* 验证**复杂结构**:\n    * 使用分层的 Pydantic 模型，Python `typing` 的 `List` 和 `Dict` 等等。\n    * 验证器使我们能够简单清楚地将复杂的数据模式定义、检查并记录为 JSON Schema。\n    * 你可以拥有深度**嵌套的 JSON** 对象并对它们进行验证和注释。\n* **可扩展**:\n    * Pydantic 允许定义自定义数据类型或者你可以用验证器装饰器对被装饰的模型上的方法扩展验证。\n* 100% 测试覆盖率。\n"
  },
  {
    "path": "docs/zh/docs/help-fastapi.md",
    "content": "# 帮助 FastAPI - 获取帮助 { #help-fastapi-get-help }\n\n你喜欢 **FastAPI** 吗？\n\n想帮助 FastAPI、其他用户和作者吗？\n\n或者你想获取 **FastAPI** 的帮助？\n\n有很多非常简单的方式可以帮忙（有些只需点一两下）。\n\n同样，也有多种途径可以获得帮助。\n\n## 订阅新闻邮件 { #subscribe-to-the-newsletter }\n\n你可以订阅（不频繁的）[**FastAPI and friends** 新闻邮件](newsletter.md)，获取如下更新：\n\n* FastAPI 及其小伙伴的新闻 🚀\n* 指南 📝\n* 功能 ✨\n* 破坏性更改 🚨\n* 使用技巧 ✅\n\n## 在 X (Twitter) 上关注 FastAPI { #follow-fastapi-on-x-twitter }\n\n[在 **X (Twitter)** 上关注 @fastapi](https://x.com/fastapi) 获取 **FastAPI** 的最新动态。🐦\n\n## 在 GitHub 上为 **FastAPI** 加星 { #star-fastapi-in-github }\n\n你可以在 GitHub 上为 FastAPI 点亮「星标」（点击右上角的星形按钮）：[https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)。⭐️\n\n点亮星标后，其他用户更容易发现它，并看到它已经对许多人有帮助。\n\n## 关注 GitHub 资源库的版本发布 { #watch-the-github-repository-for-releases }\n\n你可以在 GitHub 上「关注」FastAPI（点击右上角的「watch」按钮）：[https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)。👀\n\n在那里你可以选择「Releases only」。\n\n这样做之后，每当 **FastAPI** 发布新版本（包含修复和新功能），你都会收到通知（邮件）。\n\n## 联系作者 { #connect-with-the-author }\n\n你可以联系[我（Sebastián Ramírez / `tiangolo`）](https://tiangolo.com)，作者本人。\n\n你可以：\n\n* [在 **GitHub** 上关注我](https://github.com/tiangolo)。\n    * 了解我创建的其他开源项目，也许对你有帮助。\n    * 关注我何时创建新的开源项目。\n* 关注我在 [**X (Twitter)**](https://x.com/tiangolo) 或 [Mastodon](https://fosstodon.org/@tiangolo)。\n    * 告诉我你如何使用 FastAPI（我很喜欢听这些）。\n    * 获取我发布公告或新工具的消息。\n    * 你也可以[在 X (Twitter) 上关注 @fastapi](https://x.com/fastapi)（独立账号）。\n* [在 **LinkedIn** 上关注我](https://www.linkedin.com/in/tiangolo/)。\n    * 获取我发布公告或新工具的消息（不过我更常用 X (Twitter) 🤷‍♂）。\n* 阅读我在 [**Dev.to**](https://dev.to/tiangolo) 或 [**Medium**](https://medium.com/@tiangolo) 上的文章（或关注我）。\n    * 阅读我的其他想法、文章，以及我创建的工具。\n    * 关注我，这样当我发布新文章时你会第一时间看到。\n\n## 发推谈谈 **FastAPI** { #tweet-about-fastapi }\n\n[发推谈谈 **FastAPI**](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi)，告诉我和大家你为什么喜欢它。🎉\n\n我很高兴听到 **FastAPI** 的使用情况、你喜欢它的哪些点、你在哪个项目/公司使用它，等等。\n\n## 为 FastAPI 投票 { #vote-for-fastapi }\n\n* [在 Slant 上为 **FastAPI** 投票](https://www.slant.co/options/34241/~fastapi-review)。\n* [在 AlternativeTo 上为 **FastAPI** 投票](https://alternativeto.net/software/fastapi/about/)。\n* [在 StackShare 上标注你在用 **FastAPI**](https://stackshare.io/pypi-fastapi)。\n\n## 在 GitHub 上帮别人解答问题 { #help-others-with-questions-in-github }\n\n你可以尝试在以下地方帮助他人解答问题：\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\n很多情况下，你也许已经知道这些问题的答案了。🤓\n\n如果你帮助了很多人解答问题，你会成为官方的 [FastAPI 专家](fastapi-people.md#fastapi-experts)。🎉\n\n只要记住，最重要的一点是：尽量友善。人们带着挫败感而来，很多时候他们的提问方式并不理想，但请尽你所能地友好对待。🤗\n\n我们的目标是让 **FastAPI** 社区友好且包容。同时，也不要接受对他人的霸凌或不尊重。我们需要彼此照顾。\n\n---\n\n以下是如何帮助他人解答问题（在 Discussions 或 Issues 中）：\n\n### 理解问题 { #understand-the-question }\n\n* 看看你是否能理解提问者的**目的**和使用场景。\n\n* 然后检查问题（绝大多数是提问）是否**清晰**。\n\n* 很多时候，问题是围绕提问者想象中的解决方案，但可能有**更好的**方案。如果你更好地理解了问题和使用场景，你就可能提出更**合适的替代方案**。\n\n* 如果你没能理解问题，请请求更多**细节**。\n\n### 复现问题 { #reproduce-the-problem }\n\n在大多数情况下与问题相关的都是提问者的**原始代码**。\n\n很多时候他们只会粘贴一小段代码，但这不足以**复现问题**。\n\n* 你可以请他们提供一个[可最小复现的示例](https://stackoverflow.com/help/minimal-reproducible-example)，你可以**复制粘贴**并在本地运行，看到与他们相同的错误或行为，或者更好地理解他们的用例。\n\n* 如果你非常热心，你也可以尝试仅根据问题描述自己**构造一个示例**。不过要记住，这可能会花很多时间，通常先请他们澄清问题会更好。\n\n### 提出解决方案 { #suggest-solutions }\n\n* 在能够理解问题之后，你可以给出一个可能的**答案**。\n\n* 很多情况下，更好的是去理解他们**底层的问题或场景**，因为可能存在比他们尝试的方法更好的解决方式。\n\n### 请求关闭问题 { #ask-to-close }\n\n如果他们回复了，很有可能你已经解决了他们的问题，恭喜，**你是英雄**！🦸\n\n* 现在，如果问题已解决，你可以请他们：\n    * 在 GitHub Discussions 中：将你的评论标记为**答案**。\n    * 在 GitHub Issues 中：**关闭**该 issue。\n\n## 关注 GitHub 资源库 { #watch-the-github-repository }\n\n你可以在 GitHub 上「关注」FastAPI（点击右上角的「watch」按钮）：[https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)。👀\n\n如果你选择「Watching」而非「Releases only」，当有人创建新的 issue 或问题时你会收到通知。你也可以指定只通知新 issues、discussions、PR 等。\n\n然后你就可以尝试帮助他们解决这些问题。\n\n## 提问 { #ask-questions }\n\n你可以在 GitHub 资源库中[创建一个新问题（Question）](https://github.com/fastapi/fastapi/discussions/new?category=questions)，例如：\n\n* 提出一个**问题**或关于某个**问题**的求助。\n* 建议一个新的**功能**。\n\n**注意**：如果你这么做了，我也会请你去帮助其他人。😉\n\n## 审阅 Pull Request { #review-pull-requests }\n\n你可以帮我审阅他人的 Pull Request。\n\n再次提醒，请尽力保持友善。🤗\n\n---\n\n下面是需要注意的点，以及如何审阅一个 Pull Request：\n\n### 理解问题 { #understand-the-problem }\n\n* 首先，确保你**理解这个 PR 要解决的问题**。它可能在 GitHub Discussion 或 issue 中有更长的讨论。\n\n* 也有很大可能这个 PR 实际上并不需要，因为问题可以用**不同方式**解决。这种情况下你可以提出或询问该方案。\n\n### 不用过分担心风格 { #dont-worry-about-style }\n\n* 不用太在意提交信息风格等，我会在合并时 squash 并手动调整提交信息。\n\n* 也不用过分担心代码风格规则，已经有自动化工具在检查。\n\n如果还有其他风格或一致性需求，我会直接提出，或者我会在其上追加提交做必要修改。\n\n### 检查代码 { #check-the-code }\n\n* 检查并阅读代码，看看是否说得通，**在本地运行**并确认它确实解决了问题。\n\n* 然后**评论**说明你已经这样做了，这样我就知道你确实检查过。\n\n/// info | 信息\n\n不幸的是，我不能仅仅信任那些有很多人批准的 PR。\n\n多次发生过这样的情况：PR 有 3、5 个甚至更多的批准，可能是因为描述很吸引人，但当我检查时，它们实际上是坏的、有 bug，或者并没有解决它声称要解决的问题。😅\n\n所以，真正重要的是你确实读过并运行过代码，并在评论里告诉我你做过这些。🤓\n\n///\n\n* 如果 PR 可以在某些方面简化，你可以提出建议，但没必要过分挑剔，很多东西比较主观（我也会有我自己的看法 🙈），因此尽量关注关键点更好。\n\n### 测试 { #tests }\n\n* 帮我检查 PR 是否包含**测试**。\n\n* 确认在合并 PR 之前，测试**会失败**。🚨\n\n* 然后确认合并 PR 之后，测试**能通过**。✅\n\n* 很多 PR 没有测试，你可以**提醒**他们添加测试，或者你甚至可以自己**建议**一些测试。这是最耗时的部分之一，你能在这方面帮上大忙。\n\n* 然后也请评论你做了哪些验证，这样我就知道你检查过。🤓\n\n## 创建 Pull Request { #create-a-pull-request }\n\n你可以通过 Pull Request 为源代码[做贡献](contributing.md)，例如：\n\n* 修正文档中的一个错别字。\n* 通过[编辑这个文件](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml)分享你创建或发现的关于 FastAPI 的文章、视频或播客。\n    * 请确保把你的链接添加到相应区块的开头。\n* 帮助把[文档翻译](contributing.md#translations)成你的语言。\n    * 你也可以审阅他人创建的翻译。\n* 提议新增文档章节。\n* 修复现有 issue/bug。\n    * 记得添加测试。\n* 添加新功能。\n    * 记得添加测试。\n    * 如果相关，记得补充文档。\n\n## 帮忙维护 FastAPI { #help-maintain-fastapi }\n\n帮我一起维护 **FastAPI** 吧！🤓\n\n有很多工作要做，其中大部分其实**你**都能做。\n\n你现在就能做的主要事情有：\n\n* [在 GitHub 上帮别人解答问题](#help-others-with-questions-in-github)（见上面的章节）。\n* [审阅 Pull Request](#review-pull-requests)（见上面的章节）。\n\n这两项工作是**最耗时**的。这也是维护 FastAPI 的主要工作。\n\n如果你能在这方面帮我，**你就是在帮我维护 FastAPI**，并确保它**更快更好地前进**。🚀\n\n## 加入聊天 { #join-the-chat }\n\n加入 👥 [Discord 聊天服务器](https://discord.gg/VQjSZaeJmf) 👥，和 FastAPI 社区的小伙伴们一起交流。\n\n/// tip | 提示\n\n关于提问，请在 [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions) 中发布，这样更有机会得到 [FastAPI 专家](fastapi-people.md#fastapi-experts) 的帮助。\n\n聊天仅用于其他日常交流。\n\n///\n\n### 别在聊天里提问 { #dont-use-the-chat-for-questions }\n\n请记住，聊天更偏向“自由交流”，很容易提出过于笼统、难以回答的问题，因此你可能收不到解答。\n\n在 GitHub 中，模板会引导你写出恰当的问题，从而更容易获得好的回答，甚至在提问之前就能自己解决。而且在 GitHub 里，我能尽量确保最终回复每个问题，即使这需要一些时间。对聊天系统来说，我个人做不到这一点。😅\n\n聊天系统中的对话也不像 GitHub 那样容易搜索，因此问答可能在聊天中淹没。而且只有在 GitHub 中的问答才会计入成为 [FastAPI 专家](fastapi-people.md#fastapi-experts) 的贡献，所以你在 GitHub 上更可能获得关注。\n\n另一方面，聊天系统里有成千上万的用户，你几乎随时都能在那里找到聊得来的人。😄\n\n## 赞助作者 { #sponsor-the-author }\n\n如果你的**产品/公司**依赖或与 **FastAPI** 相关，并且你想触达它的用户，你可以通过 [GitHub sponsors](https://github.com/sponsors/tiangolo) 赞助作者（我）。根据赞助层级，你还可能获得一些额外福利，比如在文档中展示徽章。🎁\n\n---\n\n谢谢！🚀\n"
  },
  {
    "path": "docs/zh/docs/history-design-future.md",
    "content": "# 历史、设计、未来 { #history-design-and-future }\n\n不久前，[曾有 **FastAPI** 用户问过](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920)：\n\n> 这个项目有怎样的历史？好像它只用了几周就从默默无闻变得众所周知...\n\n在此，我们简单回顾一下 **FastAPI** 的历史。\n\n## 备选方案 { #alternatives }\n\n有那么几年，我曾领导数个开发团队为诸多复杂需求创建各种 API，这些需求包括机器学习、分布系统、异步任务、NoSQL 数据库等领域。\n\n作为工作的一部分，我需要调研很多备选方案、还要测试并且使用这些备选方案。\n\n**FastAPI** 其实只是延续了这些前辈的历史。\n\n正如[备选方案](alternatives.md)一章所述：\n\n<blockquote markdown=\"1\">\n没有大家之前所做的工作，**FastAPI** 就不会存在。\n\n以前创建的这些工具为它的出现提供了灵感。\n\n在那几年中，我一直回避创建新的框架。首先，我尝试使用各种框架、插件、工具解决 **FastAPI** 现在的功能。\n\n但到了一定程度之后，我别无选择，只能从之前的工具中汲取最优思路，并以尽量好的方式把这些思路整合在一起，使用之前甚至是不支持的语言特性（Python 3.6+ 的类型提示），从而创建一个能满足我所有需求的框架。\n</blockquote>\n\n## 调研 { #investigation }\n\n通过使用之前所有的备选方案，我有机会从它们之中学到了很多东西，获取了很多想法，并以我和我的开发团队能想到的最好方式把这些思路整合成一体。\n\n例如，大家都清楚，在理想状态下，它应该基于标准的 Python 类型提示。\n\n而且，最好的方式是使用现有的标准。\n\n因此，甚至在开发 **FastAPI** 前，我就花了几个月的时间研究 OpenAPI、JSON Schema、OAuth2 等规范。深入理解它们之间的关系、重叠及区别之处。\n\n## 设计 { #design }\n\n然后，我又花了一些时间从用户角度（使用 FastAPI 的开发者）设计了开发者 **API**。\n\n同时，我还在最流行的 Python 代码编辑器中测试了很多思路，包括 PyCharm、VS Code、基于 Jedi 的编辑器。\n\n根据最新 [Python 开发者调研报告](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools)显示，这几种编辑器覆盖了约 80% 的用户。\n\n也就是说，**FastAPI** 针对差不多 80% 的 Python 开发者使用的编辑器进行了测试，而且其它大多数编辑器的工作方式也与之类似，因此，**FastAPI** 的优势几乎能在所有编辑器上体现。\n\n通过这种方式，我就能找到尽可能减少代码重复的最佳方式，进而实现处处都有自动补全、类型提示与错误检查等支持。\n\n所有这些都是为了给开发者提供最佳的开发体验。\n\n## 需求项 { #requirements }\n\n经过测试多种备选方案，我最终决定使用 [**Pydantic**](https://docs.pydantic.dev/)，并充分利用它的优势。\n\n我甚至为它做了不少贡献，让它完美兼容了 JSON Schema，支持多种方式定义约束声明，并基于多个编辑器，改进了它对编辑器支持（类型检查、自动补全）。\n\n在开发期间，我还为 [**Starlette**](https://www.starlette.dev/) 做了不少贡献，这是另一个关键需求项。\n\n## 开发 { #development }\n\n当我启动 **FastAPI** 开发的时候，绝大多数部件都已经就位，设计已经定义，需求项和工具也已经准备就绪，相关标准与规范的知识储备也非常清晰而新鲜。\n\n## 未来 { #future }\n\n至此，**FastAPI** 及其理念已经为很多人所用。\n\n对于很多用例，它比以前很多备选方案都更适用。\n\n很多开发者和开发团队已经依赖 **FastAPI** 开发他们的项目（包括我和我的团队）。\n\n但，**FastAPI** 仍有很多改进的余地，也还需要添加更多的功能。\n\n**FastAPI** 前景光明。\n\n在此，我们衷心感谢[你的帮助](help-fastapi.md)。\n"
  },
  {
    "path": "docs/zh/docs/how-to/authentication-error-status-code.md",
    "content": "# 使用旧的 403 认证错误状态码 { #use-old-403-authentication-error-status-codes }\n\n在 FastAPI `0.122.0` 版本之前，当内置的安全工具在认证失败后向客户端返回错误时，会使用 HTTP 状态码 `403 Forbidden`。\n\n从 FastAPI `0.122.0` 版本开始，它们改用更合适的 HTTP 状态码 `401 Unauthorized`，并在响应中返回合理的 `WWW-Authenticate` 头，遵循 HTTP 规范，[RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1)、[RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized)。\n\n但如果由于某些原因你的客户端依赖旧行为，你可以在你的安全类中重写方法 `make_not_authenticated_error` 来回退到旧行为。\n\n例如，你可以创建一个 `HTTPBearer` 的子类，使其返回 `403 Forbidden` 错误，而不是默认的 `401 Unauthorized` 错误：\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip | 提示\n\n注意该函数返回的是异常实例，而不是直接抛出它。抛出操作由其余的内部代码完成。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/how-to/conditional-openapi.md",
    "content": "# 按条件配置 OpenAPI { #conditional-openapi }\n\n如果需要，你可以使用设置和环境变量，按环境有条件地配置 OpenAPI，甚至完全禁用它。\n\n## 关于安全、API 和文档 { #about-security-apis-and-docs }\n\n在生产环境隐藏文档界面并不应该成为保护 API 的方式。\n\n这并不会给你的 API 增加任何额外的安全性，*路径操作* 仍然会在原来的位置可用。\n\n如果你的代码里有安全漏洞，它仍然存在。\n\n隐藏文档只会让理解如何与 API 交互变得更困难，也可能让你在生产环境中调试更困难。这大体上可以被视为一种 [通过隐藏实现安全](https://en.wikipedia.org/wiki/Security_through_obscurity) 的做法。\n\n如果你想保护你的 API，有很多更好的措施，例如：\n\n- 确保为请求体和响应定义完善的 Pydantic 模型。\n- 使用依赖配置所需的权限和角色。\n- 绝不要存储明文密码，只存储密码哈希。\n- 实现并使用成熟的密码学工具，比如 pwdlib 和 JWT 令牌等。\n- 在需要的地方使用 OAuth2 作用域添加更细粒度的权限控制。\n- ...等。\n\n尽管如此，你可能确实有非常特定的用例，需要在某些环境（例如生产环境）禁用 API 文档，或根据环境变量的配置来决定。\n\n## 基于设置和环境变量的条件式 OpenAPI { #conditional-openapi-from-settings-and-env-vars }\n\n你可以很容易地使用相同的 Pydantic 设置来配置生成的 OpenAPI 和文档 UI。\n\n例如：\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\n这里我们声明了设置项 `openapi_url`，其默认值同样是 `\"/openapi.json\"`。\n\n然后在创建 `FastAPI` 应用时使用它。\n\n接着，你可以通过把环境变量 `OPENAPI_URL` 设为空字符串来禁用 OpenAPI（包括文档 UI），例如：\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n然后如果你访问 `/openapi.json`、`/docs` 或 `/redoc`，就会得到一个 `404 Not Found` 错误，例如：\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/zh/docs/how-to/configure-swagger-ui.md",
    "content": "# 配置 Swagger UI { #configure-swagger-ui }\n\n你可以配置一些额外的 [Swagger UI 参数](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)。\n\n如果需要配置它们，可以在创建 `FastAPI()` 应用对象时或调用 `get_swagger_ui_html()` 函数时传递 `swagger_ui_parameters` 参数。\n\n`swagger_ui_parameters` 接受一个字典，该字典会直接传递给 Swagger UI。\n\nFastAPI会将这些配置转换为 **JSON**，使其与 JavaScript 兼容，因为这是 Swagger UI 需要的。\n\n## 禁用语法高亮 { #disable-syntax-highlighting }\n\n比如，你可以禁用 Swagger UI 中的语法高亮。\n\n当没有改变设置时，语法高亮默认启用：\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\n但是你可以通过设置 `syntaxHighlight` 为 `False` 来禁用 Swagger UI 中的语法高亮：\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n...在此之后，Swagger UI 将不会高亮代码:\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## 改变主题 { #change-the-theme }\n\n同样地，你也可以通过设置键 `\"syntaxHighlight.theme\"` 来设置语法高亮主题（注意中间有一个点）：\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\n这个配置会改变语法高亮主题：\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## 改变默认 Swagger UI 参数 { #change-default-swagger-ui-parameters }\n\nFastAPI 包含了一些默认配置参数，适用于大多数用例。\n\n其包括这些默认配置参数：\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\n你可以通过在 `swagger_ui_parameters` 中设置不同的值来覆盖它们。\n\n比如，如果要禁用 `deepLinking`，你可以像这样传递设置到 `swagger_ui_parameters` 中：\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## 其他 Swagger UI 参数 { #other-swagger-ui-parameters }\n\n查看所有其他可用的配置，请阅读官方的 [Swagger UI 参数文档](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)。\n\n## JavaScript-only 配置 { #javascript-only-settings }\n\nSwagger UI 同样允许使用 **JavaScript-only** 配置对象（例如，JavaScript 函数）。\n\nFastAPI 包含这些 JavaScript-only 的 `presets` 设置：\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\n这些是 **JavaScript** 对象，而不是字符串，所以你不能直接从 Python 代码中传递它们。\n\n如果你需要像这样使用 JavaScript-only 配置，你可以使用上述方法之一。覆盖所有 Swagger UI *路径操作* 并手动编写任何你需要的 JavaScript。\n"
  },
  {
    "path": "docs/zh/docs/how-to/custom-docs-ui-assets.md",
    "content": "# 自托管自定义文档 UI 静态资源 { #custom-docs-ui-static-assets-self-hosting }\n\nAPI 文档使用 Swagger UI 和 ReDoc，它们各自需要一些 JavaScript 和 CSS 文件。\n\n默认情况下，这些文件从一个 <abbr title=\"Content Delivery Network - 内容分发网络: 一种服务，通常由多台服务器组成，用于提供静态文件，如 JavaScript 和 CSS。它常用于从更接近客户端的服务器提供这些文件，从而提升性能。\">CDN</abbr> 提供。\n\n不过你可以自定义：可以指定特定的 CDN，或自行提供这些文件。\n\n## 为 JavaScript 和 CSS 自定义 CDN { #custom-cdn-for-javascript-and-css }\n\n假设你想使用不同的 <abbr title=\"Content Delivery Network - 内容分发网络\">CDN</abbr>，例如使用 `https://unpkg.com/`。\n\n如果你所在的国家/地区屏蔽了某些 URL，这会很有用。\n\n### 关闭自动文档 { #disable-the-automatic-docs }\n\n第一步是关闭自动文档，因为默认它们会使用默认的 CDN。\n\n要关闭它们，在创建 `FastAPI` 应用时将其 URL 设为 `None`：\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### 包含自定义文档 { #include-the-custom-docs }\n\n现在你可以为自定义文档创建*路径操作*。\n\n你可以复用 FastAPI 的内部函数来创建文档的 HTML 页面，并传入所需参数：\n\n- `openapi_url`：文档 HTML 页面获取你的 API 的 OpenAPI 模式的 URL。这里可以使用 `app.openapi_url` 属性。\n- `title`：你的 API 标题。\n- `oauth2_redirect_url`：这里可以使用 `app.swagger_ui_oauth2_redirect_url` 来使用默认值。\n- `swagger_js_url`：你的 Swagger UI 文档 HTML 获取**JavaScript** 文件的 URL。这里是自定义的 CDN URL。\n- `swagger_css_url`：你的 Swagger UI 文档 HTML 获取**CSS** 文件的 URL。这里是自定义的 CDN URL。\n\nReDoc 也类似...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip | 提示\n\n`swagger_ui_redirect` 的*路径操作*是在你使用 OAuth2 时的一个辅助。\n\n如果你把 API 与某个 OAuth2 提供方集成，你就可以完成认证并带着获取到的凭据回到 API 文档里。然后使用真实的 OAuth2 认证与之交互。\n\nSwagger UI 会在幕后为你处理这些，但它需要这个“重定向”辅助路径。\n\n///\n\n### 创建一个路径操作进行测试 { #create-a-path-operation-to-test-it }\n\n现在，为了测试一切是否正常，创建一个*路径操作*：\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### 测试 { #test-it }\n\n现在，你应该可以访问 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)，并刷新页面，页面会从新的 CDN 加载这些资源。\n\n## 为文档自托管 JavaScript 和 CSS { #self-hosting-javascript-and-css-for-docs }\n\n如果你需要在离线、无法访问互联网或仅在局域网内时，应用仍能工作，那么自托管 JavaScript 和 CSS 会很有用。\n\n这里你将看到如何在同一个 FastAPI 应用中自行提供这些文件，并配置文档使用它们。\n\n### 项目文件结构 { #project-file-structure }\n\n假设你的项目文件结构如下：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\n现在创建一个目录来存放这些静态文件。\n\n你的新文件结构可能如下：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### 下载文件 { #download-the-files }\n\n下载文档需要的静态文件，并将它们放到 `static/` 目录中。\n\n你通常可以右键点击每个链接，选择类似“将链接另存为...”的选项。\n\nSwagger UI 使用以下文件：\n\n- [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n- [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\n而 ReDoc 使用以下文件：\n\n- [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\n之后，你的文件结构可能如下：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### 提供静态文件 { #serve-the-static-files }\n\n- 导入 `StaticFiles`。\n- 在特定路径上“挂载”一个 `StaticFiles()` 实例。\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### 测试静态文件 { #test-the-static-files }\n\n启动你的应用，并访问 [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js)。\n\n你应该会看到一个非常长的 **ReDoc** 的 JavaScript 文件。\n\n它可能以如下内容开头：\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\n这就确认了你的应用能够提供静态文件，并且你把文档所需的静态文件放在了正确的位置。\n\n现在我们可以配置应用，让文档使用这些静态文件。\n\n### 为静态文件关闭自动文档 { #disable-the-automatic-docs-for-static-files }\n\n和使用自定义 CDN 一样，第一步是关闭自动文档，因为默认情况下它们会使用 CDN。\n\n要关闭它们，在创建 `FastAPI` 应用时将其 URL 设为 `None`：\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### 为静态文件包含自定义文档 { #include-the-custom-docs-for-static-files }\n\n同样地，现在你可以为自定义文档创建*路径操作*。\n\n你可以再次复用 FastAPI 的内部函数来创建文档的 HTML 页面，并传入所需参数：\n\n- `openapi_url`：文档 HTML 页面获取你的 API 的 OpenAPI 模式的 URL。这里可以使用 `app.openapi_url` 属性。\n- `title`：你的 API 标题。\n- `oauth2_redirect_url`：这里可以使用 `app.swagger_ui_oauth2_redirect_url` 来使用默认值。\n- `swagger_js_url`：你的 Swagger UI 文档 HTML 获取**JavaScript** 文件的 URL。**这是现在由你的应用自己提供的那个**。\n- `swagger_css_url`：你的 Swagger UI 文档 HTML 获取**CSS** 文件的 URL。**这是现在由你的应用自己提供的那个**。\n\nReDoc 也类似...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip | 提示\n\n`swagger_ui_redirect` 的*路径操作*是在你使用 OAuth2 时的一个辅助。\n\n如果你把 API 与某个 OAuth2 提供方集成，你就可以完成认证并带着获取到的凭据回到 API 文档里。然后使用真实的 OAuth2 认证与之交互。\n\nSwagger UI 会在幕后为你处理这些，但它需要这个“重定向”辅助路径。\n\n///\n\n### 创建一个路径操作测试静态文件 { #create-a-path-operation-to-test-static-files }\n\n现在，为了测试一切是否正常，创建一个*路径操作*：\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### 测试静态文件 UI { #test-static-files-ui }\n\n现在，你可以断开 WiFi，访问 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)，并刷新页面。\n\n即使没有互联网，你也能看到 API 的文档并与之交互。\n"
  },
  {
    "path": "docs/zh/docs/how-to/custom-request-and-route.md",
    "content": "# 自定义 Request 和 APIRoute 类 { #custom-request-and-apiroute-class }\n\n在某些情况下，你可能想要重写 `Request` 和 `APIRoute` 类使用的逻辑。\n\n尤其是，当你本来会把这些逻辑放到中间件里时，这是一个不错的替代方案。\n\n例如，如果你想在应用处理之前读取或操作请求体。\n\n/// danger | 危险\n\n这是一个“高级”特性。\n\n如果你刚开始使用 **FastAPI**，可以先跳过本节。\n\n///\n\n## 使用场景 { #use-cases }\n\n一些使用场景包括：\n\n* 将非 JSON 的请求体转换为 JSON（例如 [`msgpack`](https://msgpack.org/index.html)）。\n* 解压缩使用 gzip 压缩的请求体。\n* 自动记录所有请求体日志。\n\n## 处理自定义请求体编码 { #handling-custom-request-body-encodings }\n\n来看如何用自定义的 `Request` 子类来解压 gzip 请求。\n\n以及一个 `APIRoute` 子类来使用该自定义请求类。\n\n### 创建自定义 `GzipRequest` 类 { #create-a-custom-gziprequest-class }\n\n/// tip | 提示\n\n这是一个演示工作原理的示例。如果你需要 Gzip 支持，可以直接使用提供的 [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware)。\n\n///\n\n首先，我们创建一个 `GzipRequest` 类，它会重写 `Request.body()` 方法：当请求头中存在相应标记时对请求体进行解压。\n\n如果请求头中没有 `gzip`，则不会尝试解压。\n\n这样，同一个路由类即可同时处理 gzip 压缩和未压缩的请求。\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### 创建自定义 `GzipRoute` 类 { #create-a-custom-gziproute-class }\n\n接着，我们创建 `fastapi.routing.APIRoute` 的自定义子类来使用 `GzipRequest`。\n\n这次，我们会重写 `APIRoute.get_route_handler()` 方法。\n\n该方法返回一个函数，这个函数负责接收请求并返回响应。\n\n这里我们用它把原始请求包装为 `GzipRequest`。\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | 技术细节\n\n`Request` 拥有 `request.scope` 属性，它就是一个 Python `dict`，包含与请求相关的元数据。\n\n`Request` 还包含 `request.receive`，它是一个用于“接收”请求体的函数。\n\n`scope` 字典和 `receive` 函数都是 ASGI 规范的一部分。\n\n创建一个新的 `Request` 实例需要这两样：`scope` 和 `receive`。\n\n想了解更多关于 `Request` 的信息，请查看 [Starlette 的 Request 文档](https://www.starlette.dev/requests/)。\n\n///\n\n由 `GzipRequest.get_route_handler` 返回的函数唯一不同之处是把 `Request` 转换为 `GzipRequest`。\n\n这样，在传给我们的路径操作之前，`GzipRequest` 会（在需要时）负责解压数据。\n\n之后，其余处理逻辑完全相同。\n\n但由于我们修改了 `GzipRequest.body`，在 **FastAPI** 需要读取时，请求体会被自动解压。\n\n## 在异常处理器中访问请求体 { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip | 提示\n\n要解决类似问题，使用 `RequestValidationError` 的自定义处理器中的 `body` 往往更简单（[处理错误](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)）。\n\n但本示例同样有效，并展示了如何与内部组件交互。\n\n///\n\n我们也可以用相同的方法在异常处理器中访问请求体。\n\n所需仅是在 `try`/`except` 块中处理请求：\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\n如果发生异常，`Request` 实例仍在作用域内，因此我们可以在处理错误时读取并使用请求体：\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## 在路由器中自定义 `APIRoute` 类 { #custom-apiroute-class-in-a-router }\n\n你也可以设置 `APIRouter` 的 `route_class` 参数：\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\n在此示例中，`router` 下的路径操作将使用自定义的 `TimedRoute` 类，响应中会多一个 `X-Response-Time` 头，包含生成响应所用的时间：\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/zh/docs/how-to/extending-openapi.md",
    "content": "# 扩展 OpenAPI { #extending-openapi }\n\n在某些情况下，你可能需要修改生成的 OpenAPI 架构（schema）。\n\n本节将介绍如何实现。\n\n## 常规流程 { #the-normal-process }\n\n常规（默认）流程如下。\n\n`FastAPI` 应用（实例）有一个 `.openapi()` 方法，预期返回 OpenAPI 架构。\n\n在创建应用对象时，会注册一个用于 `/openapi.json`（或你在 `openapi_url` 中设置的路径）的路径操作。\n\n它只会返回一个 JSON 响应，内容是应用 `.openapi()` 方法的结果。\n\n默认情况下，`.openapi()` 方法会检查属性 `.openapi_schema` 是否已有内容，若有则直接返回。\n\n如果没有，则使用 `fastapi.openapi.utils.get_openapi` 工具函数生成。\n\n该 `get_openapi()` 函数接收以下参数：\n\n- `title`：OpenAPI 标题，显示在文档中。\n- `version`：你的 API 版本，例如 `2.5.0`。\n- `openapi_version`：使用的 OpenAPI 规范版本。默认是最新的 `3.1.0`。\n- `summary`：API 的简短摘要。\n- `description`：API 的描述，可包含 Markdown，并会展示在文档中。\n- `routes`：路由列表，即已注册的每个路径操作。来自 `app.routes`。\n\n/// info | 信息\n\n参数 `summary` 仅在 OpenAPI 3.1.0 及更高版本中可用，FastAPI 0.99.0 及以上版本支持。\n\n///\n\n## 覆盖默认值 { #overriding-the-defaults }\n\n基于以上信息，你可以用同一个工具函数生成 OpenAPI 架构，并按需覆盖其中的各个部分。\n\n例如，让我们添加 [ReDoc 的 OpenAPI 扩展以包含自定义 Logo](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo)。\n\n### 常规 **FastAPI** { #normal-fastapi }\n\n首先，像平常一样编写你的 **FastAPI** 应用：\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### 生成 OpenAPI 架构 { #generate-the-openapi-schema }\n\n然后，在一个 `custom_openapi()` 函数中使用同一个工具函数生成 OpenAPI 架构：\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### 修改 OpenAPI 架构 { #modify-the-openapi-schema }\n\n现在你可以添加 ReDoc 扩展，在 OpenAPI 架构的 `info` “对象”中加入自定义 `x-logo`：\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### 缓存 OpenAPI 架构 { #cache-the-openapi-schema }\n\n你可以把 `.openapi_schema` 属性当作“缓存”，用来存储已生成的架构。\n\n这样一来，用户每次打开 API 文档时，应用就不必重新生成架构。\n\n它只会生成一次，后续请求都会使用同一份缓存的架构。\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### 覆盖方法 { #override-the-method }\n\n现在你可以用你的新函数替换 `.openapi()` 方法。\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### 验证 { #check-it }\n\n当你访问 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) 时，你会看到已使用你的自定义 Logo（本例中为 **FastAPI** 的 Logo）：\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/zh/docs/how-to/general.md",
    "content": "# 通用 - 如何操作 - 诀窍 { #general-how-to-recipes }\n\n这里是一些指向文档中其他部分的链接，用于解答一般性或常见问题。\n\n## 数据过滤 - 安全性 { #filter-data-security }\n\n为确保不返回超过需要的数据，请阅读 [教程 - 响应模型 - 返回类型](../tutorial/response-model.md) 文档。\n\n## 优化响应性能 - 响应模型 - 返回类型 { #optimize-response-performance-response-model-return-type }\n\n在返回 JSON 数据时优化性能，请使用返回类型或响应模型，这样 Pydantic 会在 Rust 侧处理到 JSON 的序列化，而无需经过 Python。更多内容请阅读 [教程 - 响应模型 - 返回类型](../tutorial/response-model.md) 文档。\n\n## 文档的标签 - OpenAPI { #documentation-tags-openapi }\n\n在文档界面中添加**路径操作**的标签和进行分组，请阅读 [教程 - 路径操作配置 - Tags](../tutorial/path-operation-configuration.md#tags) 文档。\n\n## 文档的概要和描述 - OpenAPI { #documentation-summary-and-description-openapi }\n\n在文档界面中添加**路径操作**的概要和描述，请阅读 [教程 - 路径操作配置 - Summary 和 Description](../tutorial/path-operation-configuration.md#summary-and-description) 文档。\n\n## 文档的响应描述 - OpenAPI { #documentation-response-description-openapi }\n\n在文档界面中定义并显示响应描述，请阅读 [教程 - 路径操作配置 - 响应描述](../tutorial/path-operation-configuration.md#response-description) 文档。\n\n## 文档弃用**路径操作** - OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\n在文档界面中显示弃用的**路径操作**，请阅读 [教程 - 路径操作配置 - 弃用](../tutorial/path-operation-configuration.md#deprecate-a-path-operation) 文档。\n\n## 将任何数据转换为 JSON 兼容格式 { #convert-any-data-to-json-compatible }\n\n要将任何数据转换为 JSON 兼容格式，请阅读 [教程 - JSON 兼容编码器](../tutorial/encoder.md) 文档。\n\n## OpenAPI 元数据 - 文档 { #openapi-metadata-docs }\n\n要添加 OpenAPI 的元数据，包括许可证、版本、联系方式等，请阅读 [教程 - 元数据和文档 URL](../tutorial/metadata.md) 文档。\n\n## OpenAPI 自定义 URL { #openapi-custom-url }\n\n要自定义 OpenAPI 的 URL（或删除它），请阅读 [教程 - 元数据和文档 URL](../tutorial/metadata.md#openapi-url) 文档。\n\n## OpenAPI 文档 URL { #openapi-docs-urls }\n\n要更改自动生成的文档用户界面所使用的 URL，请阅读 [教程 - 元数据和文档 URL](../tutorial/metadata.md#docs-urls)。\n"
  },
  {
    "path": "docs/zh/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\n由于 **FastAPI** 基于 **ASGI** 标准，因此很容易集成任何也兼容 ASGI 的 **GraphQL** 库。\n\n你可以在同一个应用中将常规的 FastAPI 路径操作与 GraphQL 结合使用。\n\n/// tip | 提示\n\n**GraphQL** 解决一些非常特定的用例。\n\n与常见的 **Web API** 相比，它有各自的**优点**和**缺点**。\n\n请确保评估在你的用例中，这些**好处**是否足以弥补这些**缺点**。 🤓\n\n///\n\n## GraphQL 库 { #graphql-libraries }\n\n以下是一些支持 **ASGI** 的 **GraphQL** 库。你可以将它们与 **FastAPI** 一起使用：\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * 提供 [面向 FastAPI 的文档](https://strawberry.rocks/docs/integrations/fastapi)\n* [Ariadne](https://ariadnegraphql.org/)\n    * 提供 [面向 FastAPI 的文档](https://ariadnegraphql.org/docs/fastapi-integration)\n* [Tartiflette](https://tartiflette.io/)\n    * 提供用于 ASGI 集成的 [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/)\n* [Graphene](https://graphene-python.org/)\n    * 可配合 [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3) 使用\n\n## 使用 Strawberry 的 GraphQL { #graphql-with-strawberry }\n\n如果你需要或想要使用 **GraphQL**，[**Strawberry**](https://strawberry.rocks/) 是**推荐**的库，因为它的设计与 **FastAPI** 最为接近，全部基于**类型注解**。\n\n根据你的用例，你可能会更喜欢其他库，但如果你问我，我大概率会建议你先试试 **Strawberry**。\n\n下面是一个将 Strawberry 与 FastAPI 集成的小预览：\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\n你可以在 [Strawberry 文档](https://strawberry.rocks/) 中了解更多信息。\n\n还有关于 [将 Strawberry 与 FastAPI 结合使用](https://strawberry.rocks/docs/integrations/fastapi) 的文档。\n\n## Starlette 中较早的 `GraphQLApp` { #older-graphqlapp-from-starlette }\n\n早期版本的 Starlette 包含一个 `GraphQLApp` 类，用于与 [Graphene](https://graphene-python.org/) 集成。\n\n它已在 Starlette 中被弃用，但如果你的代码使用了它，你可以轻松**迁移**到 [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)，它覆盖相同的用例，且接口**几乎完全一致**。\n\n/// tip | 提示\n\n如果你需要 GraphQL，我仍然建议看看 [Strawberry](https://strawberry.rocks/)，因为它基于类型注解而不是自定义类和类型。\n\n///\n\n## 了解更多 { #learn-more }\n\n你可以在 [GraphQL 官方文档](https://graphql.org/) 中了解更多关于 **GraphQL** 的内容。\n\n你也可以通过上面的链接阅读各个库的更多信息。\n"
  },
  {
    "path": "docs/zh/docs/how-to/index.md",
    "content": "# 如何操作 - 诀窍 { #how-to-recipes }\n\n在这里，你将看到关于**多个主题**的不同诀窍或“如何操作”指南。\n\n这些方法多数是**相互独立**的，在大多数情况下，你只需在这些内容适用于**你的项目**时才需要学习它们。\n\n如果某些内容看起来对你的项目有用，请继续查阅，否则请直接跳过它们。\n\n/// tip | 提示\n\n如果你想以系统的方式**学习 FastAPI**（推荐），请阅读 [教程 - 用户指南](../tutorial/index.md) 的每一章节。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# 从 Pydantic v1 迁移到 Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\n如果你有一个较旧的 FastAPI 应用，可能在使用 Pydantic v1。\n\nFastAPI 0.100.0 同时支持 Pydantic v1 和 v2，会使用你已安装的任一版本。\n\nFastAPI 0.119.0 引入了在 Pydantic v2 内部以 `pydantic.v1` 形式对 Pydantic v1 的部分支持，以便于迁移到 v2。\n\nFastAPI 0.126.0 移除了对 Pydantic v1 的支持，但在一段时间内仍支持 `pydantic.v1`。\n\n/// warning | 警告\n\n从 Python 3.14 开始，Pydantic 团队不再为最新的 Python 版本提供 Pydantic v1 的支持。\n\n这也包括 `pydantic.v1`，在 Python 3.14 及更高版本中不再受支持。\n\n如果你想使用 Python 的最新特性，需要确保使用 Pydantic v2。\n\n///\n\n如果你的旧 FastAPI 应用在用 Pydantic v1，这里将向你展示如何迁移到 Pydantic v2，以及 FastAPI 0.119.0 中可帮助你渐进式迁移的功能。\n\n## 官方指南 { #official-guide }\n\nPydantic 有一份从 v1 迁移到 v2 的官方[迁移指南](https://docs.pydantic.dev/latest/migration/)。\n\n其中包含变更内容、校验如何更准确更严格、可能的注意事项等。\n\n你可以阅读以更好地了解变更。\n\n## 测试 { #tests }\n\n请确保你的应用有[测试](../tutorial/testing.md)，并在持续集成（CI）中运行它们。\n\n这样你就可以升级并确保一切仍按预期工作。\n\n## `bump-pydantic` { #bump-pydantic }\n\n在很多情况下，如果你使用的是未做自定义的常规 Pydantic 模型，可以将从 Pydantic v1 迁移到 v2 的大部分过程自动化。\n\n你可以使用同一 Pydantic 团队提供的[`bump-pydantic`](https://github.com/pydantic/bump-pydantic)。\n\n该工具会帮助你自动修改大部分需要变更的代码。\n\n之后运行测试检查是否一切正常。如果正常，你就完成了。😎\n\n## v2 中的 Pydantic v1 { #pydantic-v1-in-v2 }\n\nPydantic v2 以子模块 `pydantic.v1` 的形式包含了 Pydantic v1 的全部内容。但在 Python 3.13 以上的版本中不再受支持。\n\n这意味着你可以安装最新的 Pydantic v2，并从该子模块导入并使用旧的 Pydantic v1 组件，就像安装了旧版 Pydantic v1 一样。\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### FastAPI 对 v2 中 Pydantic v1 的支持 { #fastapi-support-for-pydantic-v1-in-v2 }\n\n自 FastAPI 0.119.0 起，FastAPI 也对 Pydantic v2 内的 Pydantic v1 提供了部分支持，以便迁移到 v2。\n\n因此，你可以将 Pydantic 升级到最新的 v2，并将导入改为使用 `pydantic.v1` 子模块，在很多情况下就能直接工作。\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning | 警告\n\n请注意，由于 Pydantic 团队自 Python 3.14 起不再在较新的 Python 版本中支持 Pydantic v1，使用 `pydantic.v1` 在 Python 3.14 及更高版本中也不受支持。\n\n///\n\n### 同一应用中同时使用 Pydantic v1 与 v2 { #pydantic-v1-and-v2-on-the-same-app }\n\nPydantic 不支持在一个 Pydantic v2 模型的字段中定义 Pydantic v1 模型，反之亦然。\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n...但是，你可以在同一个应用中分别使用 Pydantic v1 和 v2 的独立模型。\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n在某些情况下，甚至可以在 FastAPI 应用的同一个路径操作中同时使用 Pydantic v1 和 v2 模型：\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\n在上面的示例中，输入模型是 Pydantic v1 模型，输出模型（在 `response_model=ItemV2` 中定义）是 Pydantic v2 模型。\n\n### Pydantic v1 参数 { #pydantic-v1-parameters }\n\n如果你需要在 Pydantic v1 模型中使用 FastAPI 特有的参数工具，如 `Body`、`Query`、`Form` 等，在完成向 Pydantic v2 的迁移前，可以从 `fastapi.temp_pydantic_v1_params` 导入它们：\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### 分步迁移 { #migrate-in-steps }\n\n/// tip | 提示\n\n优先尝试 `bump-pydantic`，如果测试通过且可行，那么你就用一个命令完成了。✨\n\n///\n\n如果 `bump-pydantic` 不适用于你的场景，你可以在同一应用中同时支持 Pydantic v1 和 v2 模型，逐步迁移到 Pydantic v2。\n\n你可以首先将 Pydantic 升级到最新的 v2，并将所有模型的导入改为使用 `pydantic.v1`。\n\n然后按模块或分组，逐步把模型从 Pydantic v1 迁移到 v2。🚶\n"
  },
  {
    "path": "docs/zh/docs/how-to/separate-openapi-schemas.md",
    "content": "# 是否为输入和输出分别生成 OpenAPI JSON Schema { #separate-openapi-schemas-for-input-and-output-or-not }\n\n自从发布了 **Pydantic v2**，生成的 OpenAPI 比之前更精确、更**正确**了。😎\n\n事实上，在某些情况下，对于同一个 Pydantic 模型，OpenAPI 中会根据是否带有**默认值**，为输入和输出分别生成**两个 JSON Schema**。\n\n我们来看看它如何工作，以及在需要时如何修改。\n\n## 用于输入和输出的 Pydantic 模型 { #pydantic-models-for-input-and-output }\n\n假设你有一个带有默认值的 Pydantic 模型，例如：\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### 输入用的模型 { #model-for-input }\n\n如果你像下面这样把该模型用作输入：\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n...那么 `description` 字段将**不是必填项**，因为它的默认值是 `None`。\n\n### 文档中的输入模型 { #input-model-in-docs }\n\n你可以在文档中确认，`description` 字段没有**红色星号**，也就是未被标记为必填：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### 输出用的模型 { #model-for-output }\n\n但如果你把同一个模型用作输出，例如：\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n...那么因为 `description` 有默认值，即使你**不返回该字段**，它仍然会有这个**默认值**。\n\n### 输出响应数据的模型 { #model-for-output-response-data }\n\n如果你在文档中交互并查看响应，即使代码没有给某个 `description` 字段赋值，JSON 响应中仍包含默认值（`null`）：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\n这意味着它**总会有值**，只是有时该值可能为 `None`（在 JSON 中是 `null`）。\n\n这也意味着，使用你的 API 的客户端无需检查该值是否存在，他们可以**假设该字段总会存在**，只是有时它会是默认值 `None`。\n\n在 OpenAPI 中描述这一点的方式，是把该字段标记为**必填**，因为它总会存在。\n\n因此，一个模型的 JSON Schema 会根据它用于**输入还是输出**而有所不同：\n\n- 用于**输入**时，`description` **不是必填**\n- 用于**输出**时，它是**必填**（并且可能为 `None`，在 JSON 中为 `null`）\n\n### 文档中的输出模型 { #model-for-output-in-docs }\n\n你也可以在文档中查看输出模型，`name` 和 `description` **都**被**红色星号**标记为**必填**：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### 文档中的输入/输出模型 { #model-for-input-and-output-in-docs }\n\n如果你查看 OpenAPI 中可用的所有 Schema（JSON Schema），你会看到有两个，一个是 `Item-Input`，一个是 `Item-Output`。\n\n对于 `Item-Input`，`description` **不是必填**，没有红色星号。\n\n但对于 `Item-Output`，`description` 是**必填**，带有红色星号。\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\n借助 **Pydantic v2** 的这个特性，你的 API 文档会更**精确**，如果你有自动生成的客户端和 SDK，它们也会更精确，带来更好的**开发者体验**和一致性。🎉\n\n## 不要分离 Schema { #do-not-separate-schemas }\n\n当然，在某些情况下，你可能希望**输入和输出使用同一个 schema**。\n\n最常见的情形是：你已经有一些自动生成的客户端代码/SDK，你暂时不想更新所有这些自动生成的客户端代码/SDK（也许未来会，但不是现在）。\n\n这种情况下，你可以在 **FastAPI** 中通过参数 `separate_input_output_schemas=False` 禁用该特性。\n\n/// info | 信息\n\n对 `separate_input_output_schemas` 的支持是在 FastAPI `0.102.0` 中添加的。🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### 文档中输入/输出使用同一 Schema 的模型 { #same-schema-for-input-and-output-models-in-docs }\n\n现在该模型的输入和输出将只使用一个 schema，即 `Item`，并且其中的 `description` **不是必填**：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/zh/docs/how-to/testing-database.md",
    "content": "# 测试数据库 { #testing-a-database }\n\n你可以在[SQLModel 文档](https://sqlmodel.tiangolo.com/)中学习数据库、SQL 和 SQLModel。🤓\n\n这里有一个[在 FastAPI 中使用 SQLModel 的小教程](https://sqlmodel.tiangolo.com/tutorial/fastapi/)。✨\n\n该教程包含一个关于[测试 SQL 数据库](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/)的章节。😎\n"
  },
  {
    "path": "docs/zh/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/zh\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>FastAPI 框架，高性能，易于学习，高效编码，生产可用</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**文档**： [https://fastapi.tiangolo.com/zh](https://fastapi.tiangolo.com/zh)\n\n**源码**： [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI 是一个用于构建 API 的现代、快速（高性能）的 Web 框架，使用 Python 并基于标准的 Python 类型提示。\n\n关键特性：\n\n* **快速**：极高性能，可与 **NodeJS** 和 **Go** 并肩（归功于 Starlette 和 Pydantic）。[最快的 Python 框架之一](#performance)。\n* **高效编码**：功能开发速度提升约 200% ～ 300%。*\n* **更少 bug**：人为（开发者）错误减少约 40%。*\n* **直观**：极佳的编辑器支持。处处皆可<dfn title=\"也被称为：自动完成、自动补全、IntelliSense\">自动补全</dfn>。更少的调试时间。\n* **易用**：为易用和易学而设计。更少的文档阅读时间。\n* **简短**：最小化代码重复。一次参数声明即可获得多种功能。更少的 bug。\n* **健壮**：生产可用级代码。并带有自动生成的交互式文档。\n* **标准化**：基于（并完全兼容）API 的开放标准：[OpenAPI](https://github.com/OAI/OpenAPI-Specification)（以前称为 Swagger）和 [JSON Schema](https://json-schema.org/)。\n\n<small>* 基于某内部开发团队在构建生产应用时的测试估算。</small>\n\n## 赞助商 { #sponsors }\n\n<!-- sponsors -->\n\n### Keystone 赞助商 { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### 金牌和银牌赞助商 { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[其他赞助商](https://fastapi.tiangolo.com/zh/fastapi-people/#sponsors)\n\n## 评价 { #opinions }\n\n「_[...] 最近我大量使用 **FastAPI**。[...] 我实际上计划把它用于我团队在 **微软** 的所有 **机器学习服务**。其中一些正在集成进核心 **Windows** 产品以及一些 **Office** 产品。_」\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n「_我们采用 **FastAPI** 来构建可查询以获取**预测结果**的 **REST** 服务器。[用于 Ludwig]_」\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino，Yaroslav Dudin，Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n「_**Netflix** 很高兴宣布开源我们的**危机管理**编排框架：**Dispatch**！[使用 **FastAPI** 构建]_」\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson，Marc Vilanova，Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n「_我对 **FastAPI** 兴奋到飞起。它太有趣了！_」\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken - <strong>[Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855) 播客主持人</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(ref)</small></a></div>\n\n---\n\n「_老实说，你构建的东西非常稳健而且打磨得很好。从很多方面看，这就是我想让 **Hug** 成为的样子 —— 看到有人把它做出来真的很鼓舞人心。_」\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley - <strong>[Hug](https://github.com/hugapi/hug) 作者</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(ref)</small></a></div>\n\n---\n\n「_如果你想学一个用于构建 REST API 的**现代框架**，看看 **FastAPI** [...] 它快速、易用且易学 [...]_」\n\n「_我们已经把我们的 **API** 切换到 **FastAPI** [...] 我想你会喜欢它 [...]_」\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani - Matthew Honnibal - <strong>[Explosion AI](https://explosion.ai) 创始人 - [spaCy](https://spacy.io) 作者</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(ref)</small></a> - <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(ref)</small></a></div>\n\n---\n\n「_如果有人正在构建生产级的 Python API，我强烈推荐 **FastAPI**。它**设计优雅**、**使用简单**且**高度可扩展**，已经成为我们 API 优先开发战略中的**关键组件**，并驱动了许多自动化和服务，比如我们的 Virtual TAC Engineer。_」\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n## FastAPI 迷你纪录片 { #fastapi-mini-documentary }\n\n在 2025 年末发布了一部 [FastAPI 迷你纪录片](https://www.youtube.com/watch?v=mpR8ngthqiE)，你可以在线观看：\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**，命令行中的 FastAPI { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\n如果你要开发一个用于终端的 <abbr title=\"Command Line Interface - 命令行界面\">命令行</abbr>应用而不是 Web API，看看 [**Typer**](https://typer.tiangolo.com/)。\n\n**Typer** 是 FastAPI 的小同胞。它的目标是成为**命令行中的 FastAPI**。⌨️ 🚀\n\n## 依赖 { #requirements }\n\nFastAPI 站在巨人的肩膀之上：\n\n* [Starlette](https://www.starlette.dev/) 负责 Web 部分。\n* [Pydantic](https://docs.pydantic.dev/) 负责数据部分。\n\n## 安装 { #installation }\n\n创建并激活一个 [虚拟环境](https://fastapi.tiangolo.com/zh/virtual-environments/)，然后安装 FastAPI：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**Note**: 请确保把 `\"fastapi[standard]\"` 用引号包起来，以保证在所有终端中都能正常工作。\n\n## 示例 { #example }\n\n### 创建 { #create-it }\n\n创建文件 `main.py`，内容如下：\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>或者使用 <code>async def</code>...</summary>\n\n如果你的代码里会用到 `async` / `await`，请使用 `async def`：\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**Note**:\n\n如果你不确定，请查看文档中 _\"In a hurry?\"_ 章节的 [`async` 和 `await`](https://fastapi.tiangolo.com/zh/async/#in-a-hurry) 部分。\n\n</details>\n\n### 运行 { #run-it }\n\n用下面的命令运行服务器：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary>关于命令 <code>fastapi dev</code>...</summary>\n\n`fastapi dev` 命令会读取你的 `main.py` 文件，检测其中的 **FastAPI** 应用，并使用 [Uvicorn](https://www.uvicorn.dev) 启动服务器。\n\n默认情况下，`fastapi dev` 会在本地开发时启用自动重载。\n\n你可以在 [FastAPI CLI 文档](https://fastapi.tiangolo.com/zh/fastapi-cli/) 中了解更多。\n\n</details>\n\n### 检查 { #check-it }\n\n用浏览器打开 [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery)。\n\n你会看到如下 JSON 响应：\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n你已经创建了一个 API，它可以：\n\n* 在路径 `/` 和 `/items/{item_id}` 接收 HTTP 请求。\n* 以上两个路径都接受 `GET` <em>操作</em>（也称为 HTTP <em>方法</em>）。\n* 路径 `/items/{item_id}` 有一个应为 `int` 的<em>路径参数</em> `item_id`。\n* 路径 `/items/{item_id}` 有一个可选的 `str` 类型<em>查询参数</em> `q`。\n\n### 交互式 API 文档 { #interactive-api-docs }\n\n现在访问 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n你会看到自动生成的交互式 API 文档（由 [Swagger UI](https://github.com/swagger-api/swagger-ui) 提供）：\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### 可选的 API 文档 { #alternative-api-docs }\n\n然后访问 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)。\n\n你会看到另一个自动生成的文档（由 [ReDoc](https://github.com/Rebilly/ReDoc) 提供）：\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## 示例升级 { #example-upgrade }\n\n现在修改 `main.py` 文件来接收来自 `PUT` 请求的请求体。\n\n借助 Pydantic，使用标准的 Python 类型来声明请求体。\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n`fastapi dev` 服务器会自动重载。\n\n### 交互式 API 文档升级 { #interactive-api-docs-upgrade }\n\n现在访问 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n* 交互式 API 文档会自动更新，并包含新的请求体：\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* 点击「Try it out」按钮，它允许你填写参数并直接与 API 交互：\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* 然后点击「Execute」按钮，界面会与你的 API 通信、发送参数、获取结果并在屏幕上展示：\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### 可选文档升级 { #alternative-api-docs-upgrade }\n\n再访问 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)。\n\n* 可选文档同样会体现新的查询参数和请求体：\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### 总结 { #recap }\n\n总之，你只需要把参数、请求体等的类型作为函数参数**声明一次**。\n\n这些都使用标准的现代 Python 类型即可。\n\n你不需要学习新的语法、某个特定库的方法或类等。\n\n只需要标准的 **Python**。\n\n例如，一个 `int`：\n\n```Python\nitem_id: int\n```\n\n或者更复杂的 `Item` 模型：\n\n```Python\nitem: Item\n```\n\n……通过一次声明，你将获得：\n\n* 编辑器支持，包括：\n    * 自动补全。\n    * 类型检查。\n* 数据校验：\n    * 当数据无效时自动生成清晰的错误信息。\n    * 即便是多层嵌套的 JSON 对象也会进行校验。\n* <dfn title=\"也被称为：序列化、解析、编组\">转换</dfn>输入数据：从网络读取到 Python 数据和类型。读取来源：\n    * JSON。\n    * 路径参数。\n    * 查询参数。\n    * Cookies。\n    * Headers。\n    * Forms。\n    * Files。\n* <dfn title=\"也被称为：序列化、解析、编组\">转换</dfn>输出数据：从 Python 数据和类型转换为网络数据（JSON）：\n    * 转换 Python 类型（`str`、`int`、`float`、`bool`、`list` 等）。\n    * `datetime` 对象。\n    * `UUID` 对象。\n    * 数据库模型。\n    * ……以及更多。\n* 自动生成的交互式 API 文档，包括两种可选的用户界面：\n    * Swagger UI。\n    * ReDoc。\n\n---\n\n回到之前的代码示例，**FastAPI** 将会：\n\n* 校验 `GET` 和 `PUT` 请求的路径中是否包含 `item_id`。\n* 校验 `GET` 和 `PUT` 请求中的 `item_id` 是否为 `int` 类型。\n    * 如果不是，客户端会看到清晰有用的错误信息。\n* 对于 `GET` 请求，检查是否存在名为 `q` 的可选查询参数（如 `http://127.0.0.1:8000/items/foo?q=somequery`）。\n    * 因为参数 `q` 被声明为 `= None`，所以它是可选的。\n    * 如果没有 `None`，它就是必需的（就像 `PUT` 情况下的请求体）。\n* 对于发送到 `/items/{item_id}` 的 `PUT` 请求，把请求体作为 JSON 读取：\n    * 检查是否存在必需属性 `name`，且为 `str`。\n    * 检查是否存在必需属性 `price`，且为 `float`。\n    * 检查是否存在可选属性 `is_offer`，如果存在则应为 `bool`。\n    * 对于多层嵌套的 JSON 对象，同样适用。\n* 自动完成 JSON 的读取与输出转换。\n* 使用 OpenAPI 记录所有内容，可用于：\n    * 交互式文档系统。\n    * 多语言的客户端代码自动生成系统。\n* 直接提供 2 种交互式文档 Web 界面。\n\n---\n\n我们只是浅尝辄止，但你已经大致了解其工作方式了。\n\n尝试把这一行：\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n……从：\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n……改为：\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n……看看你的编辑器如何自动补全属性并知道它们的类型：\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n更多包含更多特性的完整示例，请参阅 <a href=\"https://fastapi.tiangolo.com/zh/tutorial/\">教程 - 用户指南</a>。\n\n**剧透警告**：教程 - 用户指南包括：\n\n* 来自不同位置的**参数**声明：**headers**、**cookies**、**form 字段**和**文件**。\n* 如何设置**校验约束**，如 `maximum_length` 或 `regex`。\n* 功能强大且易用的 **<dfn title=\"也被称为：组件、资源、提供者、服务、可注入项\">依赖注入</dfn>** 系统。\n* 安全与认证，包括对 **OAuth2**、**JWT tokens** 和 **HTTP Basic** 认证的支持。\n* 更高级（但同样简单）的 **多层嵌套 JSON 模型** 声明技巧（得益于 Pydantic）。\n* 通过 [Strawberry](https://strawberry.rocks) 等库进行 **GraphQL** 集成。\n* 许多额外特性（归功于 Starlette），例如：\n    * **WebSockets**\n    * 基于 HTTPX 和 `pytest` 的极其简单的测试\n    * **CORS**\n    * **Cookie Sessions**\n    * ……以及更多。\n\n### 部署你的应用（可选） { #deploy-your-app-optional }\n\n你可以选择把 FastAPI 应用部署到 [FastAPI Cloud](https://fastapicloud.com)，如果还没有的话去加入候补名单吧。🚀\n\n如果你已经有 **FastAPI Cloud** 账号（我们从候补名单邀请了你 😉），你可以用一个命令部署你的应用。\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n就这样！现在你可以通过该 URL 访问你的应用了。✨\n\n#### 关于 FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** 由 **FastAPI** 的同一位作者和团队打造。\n\n它让你以最小的工作量就能**构建**、**部署**并**访问**一个 API。\n\n它把用 FastAPI 构建应用时的**开发者体验**带到了部署到云上的过程。🎉\n\nFastAPI Cloud 是「FastAPI and friends」开源项目的主要赞助方和资金提供者。✨\n\n#### 部署到其他云厂商 { #deploy-to-other-cloud-providers }\n\nFastAPI 是开源且基于标准的。你可以部署 FastAPI 应用到你选择的任意云厂商。\n\n按照你的云厂商的指南部署 FastAPI 应用即可。🤓\n\n## 性能 { #performance }\n\n独立机构 TechEmpower 的基准测试显示，运行在 Uvicorn 下的 **FastAPI** 应用是 [最快的 Python 框架之一](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7)，仅次于 Starlette 和 Uvicorn 本身（FastAPI 内部使用它们）。(*)\n\n想了解更多，请参阅 [基准测试](https://fastapi.tiangolo.com/zh/benchmarks/) 章节。\n\n## 依赖项 { #dependencies }\n\nFastAPI 依赖 Pydantic 和 Starlette。\n\n### `standard` 依赖 { #standard-dependencies }\n\n当你通过 `pip install \"fastapi[standard]\"` 安装 FastAPI 时，会包含 `standard` 组的一些可选依赖：\n\nPydantic 使用：\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - 用于 email 校验。\n\nStarlette 使用：\n\n* [`httpx`](https://www.python-httpx.org) - 使用 `TestClient` 时需要。\n* [`jinja2`](https://jinja.palletsprojects.com) - 使用默认模板配置时需要。\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - 使用 `request.form()` 支持表单<dfn title=\"将 HTTP 请求中的字符串转换为 Python 数据\">「解析」</dfn>时需要。\n\nFastAPI 使用：\n\n* [`uvicorn`](https://www.uvicorn.dev) - 加载并提供你的应用的服务器。包含 `uvicorn[standard]`，其中包含高性能服务所需的一些依赖（例如 `uvloop`）。\n* `fastapi-cli[standard]` - 提供 `fastapi` 命令。\n    * 其中包含 `fastapi-cloud-cli`，它允许你将 FastAPI 应用部署到 [FastAPI Cloud](https://fastapicloud.com)。\n\n### 不包含 `standard` 依赖 { #without-standard-dependencies }\n\n如果你不想包含这些 `standard` 可选依赖，可以使用 `pip install fastapi`，而不是 `pip install \"fastapi[standard]\"`。\n\n### 不包含 `fastapi-cloud-cli` { #without-fastapi-cloud-cli }\n\n如果你想安装带有 standard 依赖但不包含 `fastapi-cloud-cli` 的 FastAPI，可以使用 `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`。\n\n### 其他可选依赖 { #additional-optional-dependencies }\n\n还有一些你可能想安装的可选依赖。\n\n额外的 Pydantic 可选依赖：\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - 用于配置管理。\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - 用于在 Pydantic 中使用的额外类型。\n\n额外的 FastAPI 可选依赖：\n\n* [`orjson`](https://github.com/ijl/orjson) - 使用 `ORJSONResponse` 时需要。\n* [`ujson`](https://github.com/esnme/ultrajson) - 使用 `UJSONResponse` 时需要。\n\n## 许可协议 { #license }\n\n该项目遵循 MIT 许可协议。\n"
  },
  {
    "path": "docs/zh/docs/learn/index.md",
    "content": "# 学习 { #learn }\n\n以下是学习 **FastAPI** 的介绍部分和教程。\n\n您可以认为这是一本 **书**，一门 **课程**，是 **官方** 且推荐的学习FastAPI的方法。😎\n"
  },
  {
    "path": "docs/zh/docs/project-generation.md",
    "content": "# FastAPI全栈模板 { #full-stack-fastapi-template }\n\n模板通常带有特定的设置，但它们被设计为灵活且可定制。这样你可以根据项目需求进行修改和调整，使其成为很好的起点。🏁\n\n你可以使用此模板开始，它已经为你完成了大量的初始设置、安全性、数据库以及一些 API 端点。\n\nGitHub 仓库：[Full Stack FastAPI Template](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## FastAPI全栈模板 - 技术栈和特性 { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/zh) 用于 Python 后端 API。\n  - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) 用于 Python 与 SQL 数据库的交互（ORM）。\n  - 🔍 [Pydantic](https://docs.pydantic.dev)，FastAPI 使用，用于数据验证与配置管理。\n  - 💾 [PostgreSQL](https://www.postgresql.org) 作为 SQL 数据库。\n- 🚀 [React](https://react.dev) 用于前端。\n  - 💃 使用 TypeScript、hooks、Vite 以及现代前端技术栈的其他部分。\n  - 🎨 [Tailwind CSS](https://tailwindcss.com) 与 [shadcn/ui](https://ui.shadcn.com) 用于前端组件。\n  - 🤖 自动生成的前端客户端。\n  - 🧪 [Playwright](https://playwright.dev) 用于端到端测试。\n  - 🦇 支持暗黑模式。\n- 🐋 [Docker Compose](https://www.docker.com) 用于开发与生产。\n- 🔒 默认启用安全的密码哈希。\n- 🔑 JWT（JSON Web Token）认证。\n- 📫 基于邮箱的密码找回。\n- ✅ 使用 [Pytest](https://pytest.org) 进行测试。\n- 📞 [Traefik](https://traefik.io) 用作反向代理/负载均衡。\n- 🚢 使用 Docker Compose 的部署指南，包括如何设置前端 Traefik 代理以自动处理 HTTPS 证书。\n- 🏭 基于 GitHub Actions 的 CI（持续集成）与 CD（持续部署）。\n"
  },
  {
    "path": "docs/zh/docs/python-types.md",
    "content": "# Python 类型提示简介 { #python-types-intro }\n\nPython 支持可选的“类型提示”（也叫“类型注解”）。\n\n这些“类型提示”或注解是一种特殊语法，用来声明变量的<dfn title=\"例如：str、int、float、bool\">类型</dfn>。\n\n通过为变量声明类型，编辑器和工具可以为你提供更好的支持。\n\n这只是一个关于 Python 类型提示的快速入门/复习。它只涵盖与 **FastAPI** 一起使用所需的最少部分...实际上非常少。\n\n**FastAPI** 完全基于这些类型提示构建，它们带来了许多优势和好处。\n\n但即使你从不使用 **FastAPI**，了解一些类型提示也会让你受益。\n\n/// note | 注意\n\n如果你已经是 Python 专家，并且对类型提示了如指掌，可以跳到下一章。\n\n///\n\n## 动机 { #motivation }\n\n让我们从一个简单的例子开始：\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\n运行这个程序会输出：\n\n```\nJohn Doe\n```\n\n这个函数做了下面这些事情：\n\n* 接收 `first_name` 和 `last_name`。\n* 通过 `title()` 将每个参数的第一个字母转换为大写。\n* 用一个空格将它们<dfn title=\"把它们合在一起成为一个，内容一个接在另一个后面。\">拼接</dfn>起来。\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### 修改它 { #edit-it }\n\n这是一个非常简单的程序。\n\n但现在想象你要从零开始写它。\n\n在某个时刻你开始定义函数，并且准备好了参数……\n\n接下来你需要调用“那个把首字母变大写的方法”。\n\n是 `upper`？是 `uppercase`？`first_uppercase`？还是 `capitalize`？\n\n然后，你试试程序员的老朋友——编辑器的自动补全。\n\n你输入函数的第一个参数 `first_name`，再输入一个点（`.`），然后按下 `Ctrl+Space` 触发补全。\n\n但很遗憾，没有什么有用的提示：\n\n<img src=\"/img/python-types/image01.png\">\n\n### 添加类型 { #add-types }\n\n我们来改前一个版本的一行代码。\n\n把函数参数从：\n\n```Python\n    first_name, last_name\n```\n\n改成：\n\n```Python\n    first_name: str, last_name: str\n```\n\n就是这样。\n\n这些就是“类型提示”：\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\n这和声明默认值不同，比如：\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\n这是两码事。\n\n我们用的是冒号（`:`），不是等号（`=`）。\n\n而且添加类型提示通常不会改变代码本来的行为。\n\n现在，再想象你又在编写这个函数了，不过这次加上了类型提示。\n\n在同样的位置，你用 `Ctrl+Space` 触发自动补全，就能看到：\n\n<img src=\"/img/python-types/image02.png\">\n\n这样，你可以滚动查看选项，直到找到那个“看着眼熟”的：\n\n<img src=\"/img/python-types/image03.png\">\n\n## 更多动机 { #more-motivation }\n\n看这个已经带有类型提示的函数：\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\n因为编辑器知道变量的类型，你不仅能得到补全，还能获得错误检查：\n\n<img src=\"/img/python-types/image04.png\">\n\n现在你知道需要修复它，用 `str(age)` 把 `age` 转成字符串：\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## 声明类型 { #declaring-types }\n\n你刚刚看到的是声明类型提示的主要位置：函数参数。\n\n这也是你在 **FastAPI** 中使用它们的主要场景。\n\n### 简单类型 { #simple-types }\n\n你不仅可以声明 `str`，还可以声明所有标准的 Python 类型。\n\n例如：\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### typing 模块 { #typing-module }\n\n在一些额外的用例中，你可能需要从标准库的 `typing` 模块导入内容。比如当你想声明“任意类型”时，可以使用 `typing` 中的 `Any`：\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### 泛型类型 { #generic-types }\n\n有些类型可以在方括号中接收“类型参数”（type parameters），用于声明其内部值的类型。比如“字符串列表”可以写为 `list[str]`。\n\n这些能接收类型参数的类型称为“泛型类型”（Generic types）或“泛型”（Generics）。\n\n你可以把相同的内建类型作为泛型使用（带方括号和内部类型）：\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### 列表 { #list }\n\n例如，我们来定义一个由 `str` 组成的 `list` 变量。\n\n用同样的冒号（`:`）语法声明变量。\n\n类型写 `list`。\n\n因为 list 是一种包含内部类型的类型，把内部类型写在方括号里：\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info | 信息\n\n方括号中的这些内部类型称为“类型参数”（type parameters）。\n\n在这个例子中，`str` 是传给 `list` 的类型参数。\n\n///\n\n这表示：“变量 `items` 是一个 `list`，并且列表中的每一个元素都是 `str`”。\n\n这样，即使是在处理列表中的元素时，编辑器也能给你提供支持：\n\n<img src=\"/img/python-types/image05.png\">\n\n没有类型的话，这几乎是不可能做到的。\n\n注意，变量 `item` 是列表 `items` 中的一个元素。\n\n即便如此，编辑器仍然知道它是 `str`，并为此提供支持。\n\n#### 元组和集合 { #tuple-and-set }\n\n声明 `tuple` 和 `set` 的方式类似：\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\n这表示：\n\n* 变量 `items_t` 是一个含有 3 个元素的 `tuple`，分别是一个 `int`、另一个 `int`，以及一个 `str`。\n* 变量 `items_s` 是一个 `set`，其中每个元素的类型是 `bytes`。\n\n#### 字典 { #dict }\n\n定义 `dict` 时，需要传入 2 个类型参数，用逗号分隔。\n\n第一个类型参数用于字典的键。\n\n第二个类型参数用于字典的值：\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\n这表示：\n\n* 变量 `prices` 是一个 `dict`：\n    * 这个 `dict` 的键是 `str` 类型（比如，每个条目的名称）。\n    * 这个 `dict` 的值是 `float` 类型（比如，每个条目的价格）。\n\n#### Union { #union }\n\n你可以声明一个变量可以是若干种类型中的任意一种，比如既可以是 `int` 也可以是 `str`。\n\n定义时使用<dfn title='也叫“按位或运算符（bitwise or operator）”，但这里与该含义无关'>竖线（`|`）</dfn>把两种类型分开。\n\n这称为“联合类型”（union），因为变量可以是这两类类型集合的并集中的任意一个。\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\n这表示 `item` 可以是 `int` 或 `str`。\n\n#### 可能为 `None` { #possibly-none }\n\n你可以声明一个值的类型是某种类型（比如 `str`），但它也可能是 `None`。\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\n使用 `str | None` 而不是仅仅 `str`，可以让编辑器帮助你发现把值当成总是 `str` 的错误（实际上它也可能是 `None`）。\n\n### 类作为类型 { #classes-as-types }\n\n你也可以把类声明为变量的类型。\n\n假设你有一个名为 `Person` 的类，带有 name：\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\n然后你可以声明一个变量是 `Person` 类型：\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\n接着，你会再次获得所有的编辑器支持：\n\n<img src=\"/img/python-types/image06.png\">\n\n注意，这表示“`one_person` 是类 `Person` 的一个实例（instance）”。\n\n它并不表示“`one_person` 是名为 `Person` 的类本身（class）”。\n\n## Pydantic 模型 { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/) 是一个用于执行数据校验的 Python 库。\n\n你将数据的“结构”声明为带有属性的类。\n\n每个属性都有一个类型。\n\n然后你用一些值创建这个类的实例，它会校验这些值，并在需要时把它们转换为合适的类型，返回一个包含所有数据的对象。\n\n你还能对这个结果对象获得完整的编辑器支持。\n\n下面是来自 Pydantic 官方文档的一个示例：\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info | 信息\n\n想了解更多关于 [Pydantic](https://docs.pydantic.dev/) 的信息，请查看其文档。\n\n///\n\n**FastAPI** 完全建立在 Pydantic 之上。\n\n你会在[教程 - 用户指南](tutorial/index.md)中看到更多的实战示例。\n\n## 带元数据注解的类型提示 { #type-hints-with-metadata-annotations }\n\nPython 还提供了一个特性，可以使用 `Annotated` 在这些类型提示中放入额外的<dfn title=\"关于数据的数据，此处指关于类型的信息，例如描述。\">元数据</dfn>。\n\n你可以从 `typing` 导入 `Annotated`。\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nPython 本身不会对这个 `Annotated` 做任何处理。对于编辑器和其他工具，类型仍然是 `str`。\n\n但你可以在 `Annotated` 中为 **FastAPI** 提供额外的元数据，来描述你希望应用如何行为。\n\n重要的是要记住：传给 `Annotated` 的第一个类型参数才是实际类型。其余的只是给其他工具用的元数据。\n\n现在你只需要知道 `Annotated` 的存在，并且它是标准 Python。😎\n\n稍后你会看到它有多么强大。\n\n/// tip | 提示\n\n这是标准 Python，这意味着你仍然可以在编辑器里获得尽可能好的开发体验，并能和你用来分析、重构代码的工具良好协作等。✨\n\n同时你的代码也能与许多其他 Python 工具和库高度兼容。🚀\n\n///\n\n## **FastAPI** 中的类型提示 { #type-hints-in-fastapi }\n\n**FastAPI** 利用这些类型提示来完成多件事情。\n\n在 **FastAPI** 中，用类型提示来声明参数，你将获得：\n\n* 编辑器支持。\n* 类型检查。\n\n……并且 **FastAPI** 会使用相同的声明来：\n\n* 定义要求：从请求路径参数、查询参数、请求头、请求体、依赖等。\n* 转换数据：把请求中的数据转换为所需类型。\n* 校验数据：对于每个请求：\n    * 当数据无效时，自动生成错误信息返回给客户端。\n* 使用 OpenAPI 记录 API：\n    * 然后用于自动生成交互式文档界面。\n\n这些听起来可能有点抽象。别担心。你会在[教程 - 用户指南](tutorial/index.md)中看到所有这些的实际效果。\n\n重要的是，通过使用标准的 Python 类型，而且只在一个地方声明（而不是添加更多类、装饰器等），**FastAPI** 会为你完成大量工作。\n\n/// info | 信息\n\n如果你已经读完所有教程，又回来想进一步了解类型，一个不错的资源是 [`mypy` 的“速查表”](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html)。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/resources/index.md",
    "content": "# 资源 { #resources }\n\n更多资源、外部链接等。✈️\n"
  },
  {
    "path": "docs/zh/docs/translation-banner.md",
    "content": "/// details | 🌐 由 AI 与人类协作翻译\n\n本翻译由人类引导的 AI 生成。🤝\n\n可能存在误解原意或不够自然等问题。🤖\n\n你可以通过[帮助我们更好地引导 AI LLM](https://fastapi.tiangolo.com/zh/contributing/#translations)来改进此翻译。\n\n[英文版本](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/zh/docs/tutorial/background-tasks.md",
    "content": "# 后台任务 { #background-tasks }\n\n你可以定义在返回响应后运行的后台任务。\n\n这对需要在请求之后执行的操作很有用，但客户端不必在接收响应之前等待操作完成。\n\n包括这些例子：\n\n* 执行操作后发送的电子邮件通知：\n    * 由于连接到电子邮件服务器并发送电子邮件往往很“慢”（几秒钟），您可以立即返回响应并在后台发送电子邮件通知。\n* 处理数据：\n    * 例如，假设您收到的文件必须经过一个缓慢的过程，您可以返回一个\"Accepted\"(HTTP 202)响应并在后台处理它。\n\n## 使用 `BackgroundTasks` { #using-backgroundtasks }\n\n首先导入 `BackgroundTasks` 并在 *路径操作函数* 中使用类型声明 `BackgroundTasks` 定义一个参数：\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI** 会创建一个 `BackgroundTasks` 类型的对象并作为该参数传入。\n\n## 创建一个任务函数 { #create-a-task-function }\n\n创建要作为后台任务运行的函数。\n\n它只是一个可以接收参数的标准函数。\n\n它可以是 `async def` 或普通的 `def` 函数，**FastAPI** 知道如何正确处理。\n\n在这种情况下，任务函数将写入一个文件（模拟发送电子邮件）。\n\n由于写操作不使用 `async` 和 `await`，我们用普通的 `def` 定义函数：\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## 添加后台任务 { #add-the-background-task }\n\n在你的 *路径操作函数* 里，用 `.add_task()` 方法将任务函数传到 *后台任务* 对象中：\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()` 接收以下参数：\n\n* 在后台运行的任务函数(`write_notification`)。\n* 应按顺序传递给任务函数的任意参数序列(`email`)。\n* 应传递给任务函数的任意关键字参数(`message=\"some notification\"`)。\n\n## 依赖注入 { #dependency-injection }\n\n使用 `BackgroundTasks` 也适用于依赖注入系统，你可以在多个级别声明 `BackgroundTasks` 类型的参数：在 *路径操作函数* 里，在依赖中(可依赖)，在子依赖中，等等。\n\n**FastAPI** 知道在每种情况下该做什么以及如何复用同一对象，因此所有后台任务被合并在一起并且随后在后台运行：\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\n该示例中，信息会在响应发出 *之后* 被写到 `log.txt` 文件。\n\n如果请求中有查询，它将在后台任务中写入日志。\n\n然后另一个在 *路径操作函数* 生成的后台任务会使用路径参数 `email` 写入一条信息。\n\n## 技术细节 { #technical-details }\n\n`BackgroundTasks` 类直接来自 [`starlette.background`](https://www.starlette.dev/background/)。\n\n它被直接导入/包含到FastAPI以便你可以从 `fastapi` 导入，并避免意外从 `starlette.background` 导入备用的 `BackgroundTask` (后面没有 `s`)。\n\n通过仅使用 `BackgroundTasks` (而不是 `BackgroundTask`)，使得能将它作为 *路径操作函数* 的参数 ，并让**FastAPI**为您处理其余部分, 就像直接使用 `Request` 对象。\n\n在FastAPI中仍然可以单独使用 `BackgroundTask`，但您必须在代码中创建对象，并返回包含它的Starlette `Response`。\n\n更多细节查看 [Starlette 后台任务的官方文档](https://www.starlette.dev/background/)。\n\n## 告诫 { #caveat }\n\n如果您需要执行繁重的后台计算，并且不一定需要由同一进程运行（例如，您不需要共享内存、变量等），那么使用其他更大的工具（如 [Celery](https://docs.celeryq.dev)）可能更好。\n\n它们往往需要更复杂的配置，即消息/作业队列管理器，如RabbitMQ或Redis，但它们允许您在多个进程中运行后台任务，甚至是在多个服务器中。\n\n但是，如果您需要从同一个**FastAPI**应用程序访问变量和对象，或者您需要执行小型后台任务（如发送电子邮件通知），您只需使用 `BackgroundTasks` 即可。\n\n## 回顾 { #recap }\n\n导入并使用 `BackgroundTasks` 通过 *路径操作函数* 中的参数和依赖项来添加后台任务。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/bigger-applications.md",
    "content": "# 更大的应用 - 多个文件 { #bigger-applications-multiple-files }\n\n如果你正在开发一个应用程序或 Web API，很少会将所有的内容都放在一个文件中。\n\n**FastAPI** 提供了一个方便的工具，可以在保持所有灵活性的同时构建你的应用程序。\n\n/// info | 信息\n\n如果你来自 Flask，那这将相当于 Flask 的 Blueprints。\n\n///\n\n## 一个文件结构示例 { #an-example-file-structure }\n\n假设你的文件结构如下：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | 提示\n\n上面有几个 `__init__.py` 文件：每个目录或子目录中都有一个。\n\n这就是能将代码从一个文件导入到另一个文件的原因。\n\n例如，在 `app/main.py` 中，你可以有如下一行：\n\n```\nfrom app.routers import items\n```\n\n///\n\n* `app` 目录包含了所有内容。并且它有一个空文件 `app/__init__.py`，因此它是一个「Python 包」（「Python 模块」的集合）：`app`。\n* 它包含一个 `app/main.py` 文件。由于它位于一个 Python 包（一个包含 `__init__.py` 文件的目录）中，因此它是该包的一个「模块」：`app.main`。\n* 还有一个 `app/dependencies.py` 文件，就像 `app/main.py` 一样，它是一个「模块」：`app.dependencies`。\n* 有一个子目录 `app/routers/` 包含另一个 `__init__.py` 文件，因此它是一个「Python 子包」：`app.routers`。\n* 文件 `app/routers/items.py` 位于 `app/routers/` 包中，因此它是一个子模块：`app.routers.items`。\n* 同样适用于 `app/routers/users.py`，它是另一个子模块：`app.routers.users`。\n* 还有一个子目录 `app/internal/` 包含另一个 `__init__.py` 文件，因此它是又一个「Python 子包」：`app.internal`。\n* `app/internal/admin.py` 是另一个子模块：`app.internal.admin`。\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n带有注释的同一文件结构：\n\n```bash\n.\n├── app                  # 「app」是一个 Python 包\n│   ├── __init__.py      # 这个文件使「app」成为一个 Python 包\n│   ├── main.py          # 「main」模块，例如 import app.main\n│   ├── dependencies.py  # 「dependencies」模块，例如 import app.dependencies\n│   └── routers          # 「routers」是一个「Python 子包」\n│   │   ├── __init__.py  # 使「routers」成为一个「Python 子包」\n│   │   ├── items.py     # 「items」子模块，例如 import app.routers.items\n│   │   └── users.py     # 「users」子模块，例如 import app.routers.users\n│   └── internal         # 「internal」是一个「Python 子包」\n│       ├── __init__.py  # 使「internal」成为一个「Python 子包」\n│       └── admin.py     # 「admin」子模块，例如 import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\n假设专门用于处理用户逻辑的文件是位于 `/app/routers/users.py` 的子模块。\n\n你希望将与用户相关的*路径操作*与其他代码分开，以使其井井有条。\n\n但它仍然是同一 **FastAPI** 应用程序/web API 的一部分（它是同一「Python 包」的一部分）。\n\n你可以使用 `APIRouter` 为该模块创建*路径操作*。\n\n### 导入 `APIRouter` { #import-apirouter }\n\n你可以导入它并通过与 `FastAPI` 类相同的方式创建一个「实例」：\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### 使用 `APIRouter` 的*路径操作* { #path-operations-with-apirouter }\n\n然后你可以使用它来声明*路径操作*。\n\n使用方式与 `FastAPI` 类相同：\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\n你可以将 `APIRouter` 视为一个「迷你 `FastAPI`」类。\n\n所有相同的选项都得到支持。\n\n所有相同的 `parameters`、`responses`、`dependencies`、`tags` 等等。\n\n/// tip | 提示\n\n在此示例中，该变量被命名为 `router`，但你可以根据你的想法自由命名。\n\n///\n\n我们将在主 `FastAPI` 应用中包含该 `APIRouter`，但首先，让我们来看看依赖项和另一个 `APIRouter`。\n\n## 依赖项 { #dependencies }\n\n我们了解到我们将需要一些在应用程序的好几个地方所使用的依赖项。\n\n因此，我们将它们放在它们自己的 `dependencies` 模块（`app/dependencies.py`）中。\n\n现在我们将使用一个简单的依赖项来读取一个自定义的 `X-Token` 请求首部：\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | 提示\n\n我们正在使用虚构的请求首部来简化此示例。\n\n但在实际情况下，使用集成的[安全性实用工具](security/index.md)会得到更好的效果。\n\n///\n\n## 其他使用 `APIRouter` 的模块 { #another-module-with-apirouter }\n\n假设你在位于 `app/routers/items.py` 的模块中还有专门用于处理应用程序中「项目」的端点。\n\n你具有以下*路径操作*：\n\n* `/items/`\n* `/items/{item_id}`\n\n这和 `app/routers/users.py` 的结构完全相同。\n\n但是我们想变得更聪明并简化一些代码。\n\n我们知道此模块中的所有*路径操作*都有相同的：\n\n* 路径 `prefix`：`/items`。\n* `tags`：（仅有一个 `items` 标签）。\n* 额外的 `responses`。\n* `dependencies`：它们都需要我们创建的 `X-Token` 依赖项。\n\n因此，我们可以将其添加到 `APIRouter` 中，而不是将其添加到每个路径操作中。\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\n由于每个*路径操作*的路径都必须以 `/` 开头，例如：\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n...前缀不能以 `/` 作为结尾。\n\n因此，本例中的前缀为 `/items`。\n\n我们还可以添加一个 `tags` 列表和额外的 `responses` 列表，这些参数将应用于此路由器中包含的所有*路径操作*。\n\n我们可以添加一个 `dependencies` 列表，这些依赖项将被添加到路由器中的所有*路径操作*中，并将针对向它们发起的每个请求执行/解决。\n\n/// tip | 提示\n\n请注意，和[*路径操作装饰器*中的依赖项](dependencies/dependencies-in-path-operation-decorators.md)很类似，没有值会被传递给你的*路径操作函数*。\n\n///\n\n最终结果是项目相关的路径现在为：\n\n* `/items/`\n* `/items/{item_id}`\n\n...如我们所愿。\n\n* 它们将被标记为仅包含单个字符串 `\"items\"` 的标签列表。\n    * 这些「标签」对于自动化交互式文档系统（使用 OpenAPI）特别有用。\n* 所有的路径操作都将包含预定义的 `responses`。\n* 所有的这些*路径操作*都将在自身之前计算/执行 `dependencies` 列表。\n    * 如果你还在一个具体的*路径操作*中声明了依赖项，**它们也会被执行**。\n    * 路由器的依赖项最先执行，然后是[装饰器中的 `dependencies`](dependencies/dependencies-in-path-operation-decorators.md)，再然后是普通的参数依赖项。\n    * 你还可以添加[具有 `scopes` 的 `Security` 依赖项](../advanced/security/oauth2-scopes.md)。\n\n/// tip | 提示\n\n在 `APIRouter`中具有 `dependencies` 可以用来，例如，对一整组的*路径操作*要求身份认证。即使这些依赖项并没有分别添加到每个路径操作中。\n\n///\n\n/// check | 检查\n\n`prefix`、`tags`、`responses` 以及 `dependencies` 参数只是（和其他很多情况一样）**FastAPI** 的一个用于帮助你避免代码重复的功能。\n\n///\n\n### 导入依赖项 { #import-the-dependencies }\n\n这些代码位于 `app.routers.items` 模块，`app/routers/items.py` 文件中。\n\n我们需要从 `app.dependencies` 模块即 `app/dependencies.py` 文件中获取依赖函数。\n\n因此，我们通过 `..` 对依赖项使用了相对导入：\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### 相对导入如何工作 { #how-relative-imports-work }\n\n/// tip | 提示\n\n如果你完全了解导入的工作原理，请从下面的下一部分继续。\n\n///\n\n一个单点 `.`，例如：\n\n```Python\nfrom .dependencies import get_token_header\n```\n\n表示：\n\n* 从该模块（`app/routers/items.py` 文件）所在的同一个包（`app/routers/` 目录）开始...\n* 找到 `dependencies` 模块（一个位于 `app/routers/dependencies.py` 的虚构文件）...\n* 然后从中导入函数 `get_token_header`。\n\n但是该文件并不存在，我们的依赖项位于 `app/dependencies.py` 文件中。\n\n请记住我们的程序/文件结构是怎样的：\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\n两个点 `..`，例如：\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\n表示：\n\n* 从该模块（`app/routers/items.py` 文件）所在的同一个包（`app/routers/` 目录）开始...\n* 跳转到其父包（`app/` 目录）...\n* 在该父包中，找到 `dependencies` 模块（位于 `app/dependencies.py` 的文件）...\n* 然后从中导入函数 `get_token_header`。\n\n正常工作了！🎉\n\n---\n\n同样，如果我们使用了三个点 `...`，例如：\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\n那将意味着：\n\n* 从该模块（`app/routers/items.py` 文件）所在的同一个包（`app/routers/` 目录）开始...\n* 跳转到其父包（`app/` 目录）...\n* 然后跳转到该包的父包（该父包并不存在，`app` 已经是最顶层的包 😱）...\n* 在该父包中，找到 `dependencies` 模块（位于 `app/dependencies.py` 的文件）...\n* 然后从中导入函数 `get_token_header`。\n\n这将引用 `app/` 的往上一级，带有其自己的 `__init __.py` 等文件的某个包。但是我们并没有这个包。因此，这将在我们的示例中引发错误。🚨\n\n但是现在你知道了它的工作原理，因此无论它们多么复杂，你都可以在自己的应用程序中使用相对导入。🤓\n\n### 添加一些自定义的 `tags`、`responses` 和 `dependencies` { #add-some-custom-tags-responses-and-dependencies }\n\n我们不打算在每个*路径操作*中添加前缀 `/items` 或 `tags =[\"items\"]`，因为我们将它们添加到了 `APIRouter` 中。\n\n但是我们仍然可以添加*更多*将会应用于特定的*路径操作*的 `tags`，以及一些特定于该*路径操作*的额外 `responses`：\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | 提示\n\n最后的这个路径操作将包含标签的组合：`[\"items\", \"custom\"]`。\n\n并且在文档中也会有两个响应，一个用于 `404`，一个用于 `403`。\n\n///\n\n## `FastAPI` 主体 { #the-main-fastapi }\n\n现在，让我们来看看位于 `app/main.py` 的模块。\n\n在这里你导入并使用 `FastAPI` 类。\n\n这将是你的应用程序中将所有内容联结在一起的主文件。\n\n并且由于你的大部分逻辑现在都存在于其自己的特定模块中，因此主文件的内容将非常简单。\n\n### 导入 `FastAPI` { #import-fastapi }\n\n你可以像平常一样导入并创建一个 `FastAPI` 类。\n\n我们甚至可以声明[全局依赖项](dependencies/global-dependencies.md)，它会和每个 `APIRouter` 的依赖项组合在一起：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### 导入 `APIRouter` { #import-the-apirouter }\n\n现在，我们导入具有 `APIRouter` 的其他子模块：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\n由于文件 `app/routers/users.py` 和 `app/routers/items.py` 是同一 Python 包 `app` 一个部分的子模块，因此我们可以使用单个点 ` .` 通过「相对导入」来导入它们。\n\n### 导入是如何工作的 { #how-the-importing-works }\n\n这段代码：\n\n```Python\nfrom .routers import items, users\n```\n\n表示：\n\n* 从该模块（`app/main.py` 文件）所在的同一个包（`app/` 目录）开始...\n* 寻找 `routers` 子包（位于 `app/routers/` 的目录）...\n* 从该包中，导入子模块 `items` (位于 `app/routers/items.py` 的文件) 以及 `users` (位于 `app/routers/users.py` 的文件)...\n\n`items` 模块将具有一个 `router` 变量（`items.router`）。这与我们在 `app/routers/items.py` 文件中创建的变量相同，它是一个 `APIRouter` 对象。\n\n然后我们对 `users` 模块进行相同的操作。\n\n我们也可以像这样导入它们：\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info | 信息\n\n第一个版本是「相对导入」：\n\n```Python\nfrom .routers import items, users\n```\n\n第二个版本是「绝对导入」：\n\n```Python\nfrom app.routers import items, users\n```\n\n要了解有关 Python 包和模块的更多信息，请查阅[关于 Modules 的 Python 官方文档](https://docs.python.org/3/tutorial/modules.html)。\n\n///\n\n### 避免名称冲突 { #avoid-name-collisions }\n\n我们将直接导入 `items` 子模块，而不是仅导入其 `router` 变量。\n\n这是因为我们在 `users` 子模块中也有另一个名为 `router` 的变量。\n\n如果我们一个接一个地导入，例如：\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\n来自 `users` 的 `router` 将覆盖来自 `items` 中的 `router`，我们将无法同时使用它们。\n\n因此，为了能够在同一个文件中使用它们，我们直接导入子模块：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### 包含 `users` 和 `items` 的 `APIRouter` { #include-the-apirouters-for-users-and-items }\n\n现在，让我们来包含来自 `users` 和 `items` 子模块的 `router`。\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info | 信息\n\n`users.router` 包含了 `app/routers/users.py` 文件中的 `APIRouter`。\n\n`items.router` 包含了 `app/routers/items.py` 文件中的 `APIRouter`。\n\n///\n\n使用 `app.include_router()`，我们可以将每个 `APIRouter` 添加到主 `FastAPI` 应用程序中。\n\n它将包含来自该路由器的所有路由作为其一部分。\n\n/// note | 技术细节\n\n实际上，它将在内部为声明在 `APIRouter` 中的每个*路径操作*创建一个*路径操作*。\n\n所以，在幕后，它实际上会像所有的东西都是同一个应用程序一样工作。\n\n///\n\n/// check | 检查\n\n包含路由器时，你不必担心性能问题。\n\n这将花费几微秒时间，并且只会在启动时发生。\n\n因此，它不会影响性能。⚡\n\n///\n\n### 包含一个有自定义 `prefix`、`tags`、`responses` 和 `dependencies` 的 `APIRouter` { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\n现在，假设你的组织为你提供了 `app/internal/admin.py` 文件。\n\n它包含一个带有一些由你的组织在多个项目之间共享的管理员*路径操作*的 `APIRouter`。\n\n对于此示例，它将非常简单。但是假设由于它是与组织中的其他项目所共享的，因此我们无法对其进行修改，以及直接在 `APIRouter` 中添加 `prefix`、`dependencies`、`tags` 等：\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\n但是我们仍然希望在包含 `APIRouter` 时设置一个自定义的 `prefix`，以便其所有*路径操作*以 `/admin` 开头，我们希望使用本项目已经有的 `dependencies` 保护它，并且我们希望它包含自定义的 `tags` 和 `responses`。\n\n我们可以通过将这些参数传递给 `app.include_router()` 来完成所有的声明，而不必修改原始的 `APIRouter`：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\n这样，原始的 `APIRouter` 将保持不变，因此我们仍然可以与组织中的其他项目共享相同的 `app/internal/admin.py` 文件。\n\n结果是在我们的应用程序中，来自 `admin` 模块的每个*路径操作*都将具有：\n\n* `/admin` 前缀 。\n* `admin` 标签。\n* `get_token_header` 依赖项。\n* `418` 响应。 🍵\n\n但这只会影响我们应用中的 `APIRouter`，而不会影响使用它的任何其他代码。\n\n因此，举例来说，其他项目能够以不同的身份认证方法使用相同的 `APIRouter`。\n\n### 包含一个*路径操作* { #include-a-path-operation }\n\n我们还可以直接将*路径操作*添加到 `FastAPI` 应用中。\n\n这里我们这样做了...只是为了表明我们可以做到🤷：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\n它将与通过 `app.include_router()` 添加的所有其他*路径操作*一起正常运行。\n\n/// info | 非常技术细节\n\n**注意**：这是一个非常技术性的细节，你也许可以**直接跳过**。\n\n---\n\n`APIRouter` 没有被「挂载」，它们与应用程序的其余部分没有隔离。\n\n这是因为我们想要在 OpenAPI 模式和用户界面中包含它们的*路径操作*。\n\n由于我们不能仅仅隔离它们并独立于其余部分来「挂载」它们，因此*路径操作*是被「克隆的」（重新创建），而不是直接包含。\n\n///\n\n## 在 `pyproject.toml` 中配置 `entrypoint` { #configure-the-entrypoint-in-pyproject-toml }\n\n因为你的 FastAPI `app` 对象位于 `app/main.py` 中，你可以在 `pyproject.toml` 中这样配置 `entrypoint`：\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\n等价于像这样导入：\n\n```python\nfrom app.main import app\n```\n\n这样 `fastapi` 命令就知道到哪里去找到你的应用了。\n\n/// Note | 注意\n\n你也可以把路径传给命令，比如：\n\n```console\n$ fastapi dev app/main.py\n```\n\n但是每次调用 `fastapi` 命令时，你都需要记得传入正确的路径。\n\n另外，其他工具可能找不到它，比如 [VS Code 扩展](../editor-support.md) 或 [FastAPI Cloud](https://fastapicloud.com)，因此推荐在 `pyproject.toml` 中使用 `entrypoint`。\n\n///\n\n## 查看自动化的 API 文档 { #check-the-automatic-api-docs }\n\n现在，运行你的应用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n然后打开位于 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) 的文档。\n\n你将看到使用了正确路径（和前缀）和正确标签的自动化 API 文档，包括了来自所有子模块的路径：\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## 多次使用不同的 `prefix` 包含同一个路由器 { #include-the-same-router-multiple-times-with-different-prefix }\n\n你也可以在*同一*路由器上使用不同的前缀来多次使用 `.include_router()`。\n\n在有些场景这可能有用，例如以不同的前缀公开同一个的 API，比方说 `/api/v1` 和 `/api/latest`。\n\n这是一个你可能并不真正需要的高级用法，但万一你有需要了就能够用上。\n\n## 在另一个 `APIRouter` 中包含一个 `APIRouter` { #include-an-apirouter-in-another }\n\n与在 `FastAPI` 应用程序中包含 `APIRouter` 的方式相同，你也可以在另一个 `APIRouter` 中包含 `APIRouter`，通过：\n\n```Python\nrouter.include_router(other_router)\n```\n\n请确保在你将 `router` 包含到 `FastAPI` 应用程序之前进行此操作，以便 `other_router` 中的*路径操作*也能被包含进来。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/body-fields.md",
    "content": "# 请求体 - 字段 { #body-fields }\n\n与在*路径操作函数*中使用 `Query`、`Path` 、`Body` 声明校验与元数据的方式一样，可以使用 Pydantic 的 `Field` 在 Pydantic 模型内部声明校验和元数据。\n\n## 导入 `Field` { #import-field }\n\n首先，从 Pydantic 中导入 `Field`：\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n/// warning | 警告\n\n注意，与从 `fastapi` 导入 `Query`，`Path`、`Body` 不同，要直接从 `pydantic` 导入 `Field` 。\n\n///\n\n## 声明模型属性 { #declare-model-attributes }\n\n然后，使用 `Field` 定义模型的属性：\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field` 的工作方式和 `Query`、`Path`、`Body` 相同，参数也相同。\n\n/// note | 技术细节\n\n实际上，`Query`、`Path` 以及你接下来会看到的其它对象，会创建公共 `Param` 类的子类的对象，而 `Param` 本身是 Pydantic 中 `FieldInfo` 的子类。\n\nPydantic 的 `Field` 返回也是 `FieldInfo` 的类实例。\n\n`Body` 直接返回的也是 `FieldInfo` 的子类的对象。后文还会介绍一些 `Body` 的子类。\n\n注意，从 `fastapi` 导入的 `Query`、`Path` 等对象实际上都是返回特殊类的函数。\n\n///\n\n/// tip | 提示\n\n注意，模型属性的类型、默认值及 `Field` 的代码结构与*路径操作函数*的参数相同，只不过是用 `Field` 替换了`Path`、`Query`、`Body`。\n\n///\n\n## 添加更多信息 { #add-extra-information }\n\n`Field`、`Query`、`Body` 等对象里可以声明更多信息，并且 JSON Schema 中也会集成这些信息。\n\n*声明示例*一章中将详细介绍添加更多信息的知识。\n\n/// warning | 警告\n\n传递给 `Field` 的额外键也会出现在你的应用生成的 OpenAPI 架构中。\n由于这些键不一定属于 OpenAPI 规范的一部分，某些 OpenAPI 工具（例如 [OpenAPI 验证器](https://validator.swagger.io/)）可能无法处理你生成的架构。\n\n///\n\n## 小结 { #recap }\n\nPydantic 的 `Field` 可以为模型属性声明更多校验和元数据。\n\n传递 JSON Schema 元数据还可以使用更多关键字参数。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/body-multiple-params.md",
    "content": "# 请求体 - 多个参数 { #body-multiple-parameters }\n\n既然我们已经知道了如何使用 `Path` 和 `Query`，下面让我们来了解一下请求体声明的更高级用法。\n\n## 混合使用 `Path`、`Query` 和请求体参数 { #mix-path-query-and-body-parameters }\n\n首先，毫无疑问地，你可以随意地混合使用 `Path`、`Query` 和请求体参数声明，**FastAPI** 会知道该如何处理。\n\n你还可以通过将默认值设置为 `None` 来将请求体参数声明为可选参数：\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | 注意\n\n请注意，在这种情况下，将从请求体获取的 `item` 是可选的。因为它的默认值为 `None`。\n\n///\n\n## 多个请求体参数 { #multiple-body-parameters }\n\n在上面的示例中，*路径操作*将期望一个具有 `Item` 的属性的 JSON 请求体，就像：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n但是你也可以声明多个请求体参数，例如 `item` 和 `user`：\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\n在这种情况下，**FastAPI** 将注意到该函数中有多个请求体参数（两个 Pydantic 模型参数）。\n\n因此，它将使用参数名称作为请求体中的键（字段名称），并期望一个类似于以下内容的请求体：\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | 注意\n\n请注意，即使 `item` 的声明方式与之前相同，但现在它被期望通过 `item` 键内嵌在请求体中。\n\n///\n\n**FastAPI** 将自动对请求中的数据进行转换，因此 `item` 参数将接收指定的内容，`user` 参数也是如此。\n\n它将执行对复合数据的校验，并且像现在这样为 OpenAPI 模式和自动化文档对其进行记录。\n\n## 请求体中的单一值 { #singular-values-in-body }\n\n与使用 `Query` 和 `Path` 为查询参数和路径参数定义额外数据的方式相同，**FastAPI** 提供了一个同等的 `Body`。\n\n例如，为了扩展先前的模型，你可能决定除了 `item` 和 `user` 之外，还想在同一请求体中具有另一个键 `importance`。\n\n如果你就按原样声明它，因为它是一个单一值，**FastAPI** 将假定它是一个查询参数。\n\n但是你可以使用 `Body` 指示 **FastAPI** 将其作为请求体的另一个键进行处理。\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\n在这种情况下，**FastAPI** 将期望像这样的请求体：\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\n同样的，它将转换数据类型，校验，生成文档等。\n\n## 多个请求体参数和查询参数 { #multiple-body-params-and-query }\n\n当然，除了请求体参数外，你还可以在任何需要的时候声明额外的查询参数。\n\n由于默认情况下单一值会被解释为查询参数，因此你不必显式地添加 `Query`，你可以这样写：\n\n```Python\nq: str | None = None\n```\n\n比如：\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n/// info | 信息\n\n`Body` 同样具有与 `Query`、`Path` 以及其他后面将看到的类完全相同的额外校验和元数据参数。\n\n///\n\n## 嵌入单个请求体参数 { #embed-a-single-body-parameter }\n\n假设你只有一个来自 Pydantic 模型 `Item` 的请求体参数 `item`。\n\n默认情况下，**FastAPI** 将直接期望这样的请求体。\n\n但是，如果你希望它期望一个拥有 `item` 键并在值中包含模型内容的 JSON，就像在声明额外的请求体参数时所做的那样，则可以使用一个特殊的 `Body` 参数 `embed`：\n\n```Python\nitem: Item = Body(embed=True)\n```\n\n比如：\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\n在这种情况下，**FastAPI** 将期望像这样的请求体：\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\n而不是：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## 总结 { #recap }\n\n你可以添加多个请求体参数到*路径操作函数*中，即使一个请求只能有一个请求体。\n\n但是 **FastAPI** 会处理它，在函数中为你提供正确的数据，并在*路径操作*中校验并记录正确的模式。\n\n你还可以声明将作为请求体的一部分所接收的单一值。\n\n你还可以指示 **FastAPI** 在仅声明了一个请求体参数的情况下，将原本的请求体嵌入到一个键中。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/body-nested-models.md",
    "content": "# 请求体 - 嵌套模型 { #body-nested-models }\n\n使用 **FastAPI**，你可以定义、校验、记录文档并使用任意深度嵌套的模型（归功于Pydantic）。\n\n## List 字段 { #list-fields }\n\n你可以将一个属性定义为一个子类型。例如，Python `list`：\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\n这将使 `tags` 成为一个由元素组成的列表。不过它没有声明每个元素的类型。\n\n## 带类型参数的 List 字段 { #list-fields-with-type-parameter }\n\n不过，Python 有一种用于声明具有内部类型（类型参数）的列表的特定方式：\n\n### 声明带类型参数的 `list` { #declare-a-list-with-a-type-parameter }\n\n要声明具有类型参数（内部类型）的类型，例如 `list`、`dict`、`tuple`，使用方括号 `[` 和 `]` 传入内部类型作为「类型参数」：\n\n```Python\nmy_list: list[str]\n```\n\n这完全是用于类型声明的标准 Python 语法。\n\n对具有内部类型的模型属性也使用相同的标准语法。\n\n因此，在我们的示例中，我们可以将 `tags` 明确地指定为一个「字符串列表」：\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## Set 类型 { #set-types }\n\n但是随后我们考虑了一下，意识到标签不应该重复，它们很大可能会是唯一的字符串。\n\n而 Python 有一种用于保存唯一元素集合的特殊数据类型 `set`。\n\n然后我们可以将 `tags` 声明为一个由字符串组成的 set：\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\n这样，即使你收到带有重复数据的请求，这些数据也会被转换为一组唯一项。\n\n而且，每当你输出该数据时，即使源数据有重复，它们也将作为一组唯一项输出。\n\n并且还会被相应地标注 / 记录文档。\n\n## 嵌套模型 { #nested-models }\n\nPydantic 模型的每个属性都具有类型。\n\n但是这个类型本身可以是另一个 Pydantic 模型。\n\n因此，你可以声明拥有特定属性名称、类型和校验的深度嵌套的 JSON 对象。\n\n上述这些都可以任意的嵌套。\n\n### 定义子模型 { #define-a-submodel }\n\n例如，我们可以定义一个 `Image` 模型：\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### 将子模型用作类型 { #use-the-submodel-as-a-type }\n\n然后我们可以将其用作一个属性的类型：\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\n这意味着 **FastAPI** 将期望类似于以下内容的请求体：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\n再一次，仅仅进行这样的声明，你将通过 **FastAPI** 获得：\n\n* 对被嵌入的模型也适用的编辑器支持（自动补全等）\n* 数据转换\n* 数据校验\n* 自动生成文档\n\n## 特殊的类型和校验 { #special-types-and-validation }\n\n除了普通的单一值类型（如 `str`、`int`、`float` 等）外，你还可以使用从 `str` 继承的更复杂的单一值类型。\n\n要了解所有的可用选项，请查看 [Pydantic 的类型概览](https://docs.pydantic.dev/latest/concepts/types/)。你将在下一章节中看到一些示例。\n\n例如，在 `Image` 模型中我们有一个 `url` 字段，我们可以把它声明为 Pydantic 的 `HttpUrl`，而不是 `str`：\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\n该字符串将被检查是否为有效的 URL，并在 JSON Schema / OpenAPI 文档中进行记录。\n\n## 带有一组子模型的属性 { #attributes-with-lists-of-submodels }\n\n你还可以将 Pydantic 模型用作 `list`、`set` 等的子类型：\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\n这将期望（转换，校验，记录文档等）下面这样的 JSON 请求体：\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info | 信息\n\n请注意 `images` 键现在具有一组 image 对象是如何发生的。\n\n///\n\n## 深度嵌套模型 { #deeply-nested-models }\n\n你可以定义任意深度的嵌套模型：\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info | 信息\n\n请注意 `Offer` 拥有一组 `Item` 而反过来 `Item` 又是一个可选的 `Image` 列表是如何发生的。\n\n///\n\n## 纯列表请求体 { #bodies-of-pure-lists }\n\n如果你期望的 JSON 请求体的最外层是一个 JSON `array`（即 Python `list`），则可以在路径操作函数的参数中声明此类型，就像声明 Pydantic 模型一样：\n\n```Python\nimages: list[Image]\n```\n\n例如：\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## 无处不在的编辑器支持 { #editor-support-everywhere }\n\n你可以随处获得编辑器支持。\n\n即使是列表中的元素：\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\n如果你直接使用 `dict` 而不是 Pydantic 模型，那你将无法获得这种编辑器支持。\n\n但是你根本不必担心这两者，传入的字典会自动被转换，你的输出也会自动被转换为 JSON。\n\n## 任意 `dict` 构成的请求体 { #bodies-of-arbitrary-dicts }\n\n你也可以将请求体声明为使用某类型的键和其他类型值的 `dict`。\n\n无需事先知道有效的字段/属性（在使用 Pydantic 模型的场景）名称是什么。\n\n如果你想接收一些尚且未知的键，这将很有用。\n\n---\n\n其他有用的场景是当你想要接收其他类型的键时，例如 `int`。\n\n这也是我们在接下来将看到的。\n\n在下面的例子中，你将接受任意键为 `int` 类型并且值为 `float` 类型的 `dict`：\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip | 提示\n\n请记住 JSON 仅支持将 `str` 作为键。\n\n但是 Pydantic 具有自动转换数据的功能。\n\n这意味着，即使你的 API 客户端只能将字符串作为键发送，只要这些字符串内容仅包含整数，Pydantic 就会对其进行转换并校验。\n\n然后你接收的名为 `weights` 的 `dict` 实际上将具有 `int` 类型的键和 `float` 类型的值。\n\n///\n\n## 总结 { #recap }\n\n使用 **FastAPI** 你可以拥有 Pydantic 模型提供的极高灵活性，同时保持代码的简单、简短和优雅。\n\n而且还具有下列好处：\n\n* 编辑器支持（处处皆可自动补全！）\n* 数据转换（也被称为解析/序列化）\n* 数据校验\n* 模式文档\n* 自动生成的文档\n"
  },
  {
    "path": "docs/zh/docs/tutorial/body-updates.md",
    "content": "# 请求体 - 更新数据 { #body-updates }\n\n## 用 `PUT` 替换式更新 { #update-replacing-with-put }\n\n更新数据可以使用 [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) 操作。\n\n把输入数据转换为以 JSON 格式存储的数据（比如，使用 NoSQL 数据库时），可以使用 `jsonable_encoder`。例如，把 `datetime` 转换为 `str`。\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT` 用于接收替换现有数据的数据。\n\n### 关于替换的警告 { #warning-about-replacing }\n\n用 `PUT` 把数据项 `bar` 更新为以下请求体时：\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\n因为其中未包含已存储的属性 `\"tax\": 20.2`，输入模型会取 `\"tax\": 10.5` 的默认值。\n\n因此，保存的数据会带有这个“新的” `tax` 值 `10.5`。\n\n## 用 `PATCH` 进行部分更新 { #partial-updates-with-patch }\n\n也可以使用 [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) 操作对数据进行*部分*更新。\n\n也就是说，你只需发送想要更新的数据，其余数据保持不变。\n\n/// note | 注意\n\n`PATCH` 没有 `PUT` 知名，也没那么常用。\n\n很多团队甚至只用 `PUT` 实现部分更新。\n\n你可以**随意**选择如何使用它们，**FastAPI** 不做任何限制。\n\n但本指南会大致展示它们的预期用法。\n\n///\n\n### 使用 Pydantic 的 `exclude_unset` 参数 { #using-pydantics-exclude-unset-parameter }\n\n如果要接收部分更新，建议在 Pydantic 模型的 `.model_dump()` 中使用 `exclude_unset` 参数。\n\n比如，`item.model_dump(exclude_unset=True)`。\n\n这会生成一个 `dict`，只包含创建 `item` 模型时显式设置的数据，不包含默认值。\n\n然后再用它生成一个只含已设置（在请求中发送）数据、且省略默认值的 `dict`：\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### 使用 Pydantic 的 `update` 参数 { #using-pydantics-update-parameter }\n\n接下来，用 `.model_copy()` 为已有模型创建副本，并传入 `update` 参数，值为包含更新数据的 `dict`。\n\n例如，`stored_item_model.model_copy(update=update_data)`：\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### 部分更新小结 { #partial-updates-recap }\n\n简而言之，应用部分更新应当：\n\n* （可选）使用 `PATCH` 而不是 `PUT`。\n* 提取已存储的数据。\n* 把该数据放入 Pydantic 模型。\n* 生成不含输入模型默认值的 `dict`（使用 `exclude_unset`）。\n    * 这样只会更新用户实际设置的值，而不会用模型中的默认值覆盖已存储的值。\n* 为已存储的模型创建副本，用接收到的部分更新数据更新其属性（使用 `update` 参数）。\n* 把模型副本转换为可存入数据库的形式（比如，使用 `jsonable_encoder`）。\n    * 这类似于再次调用模型的 `.model_dump()` 方法，但会确保（并转换）值为可转换为 JSON 的数据类型，例如把 `datetime` 转换为 `str`。\n* 把数据保存至数据库。\n* 返回更新后的模型。\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | 提示\n\n实际上，HTTP `PUT` 也可以使用同样的技巧。\n\n但这里用 `PATCH` 举例，因为它就是为这种用例设计的。\n\n///\n\n/// note | 注意\n\n注意，输入模型仍会被验证。\n\n因此，如果希望接收的部分更新可以省略所有属性，则需要一个所有属性都标记为可选（带默认值或 `None`）的模型。\n\n为了区分用于**更新**（全部可选）和用于**创建**（必填）的模型，可以参考[更多模型](extra-models.md) 中介绍的思路。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/tutorial/body.md",
    "content": "# 请求体 { #request-body }\n\n当你需要从客户端（比如浏览器）向你的 API 发送数据时，会把它作为**请求体**发送。\n\n**请求体**是客户端发送给你的 API 的数据。**响应体**是你的 API 发送给客户端的数据。\n\n你的 API 几乎总是需要发送**响应体**。但客户端不一定总是要发送**请求体**，有时它们只请求某个路径，可能带一些查询参数，但不会发送请求体。\n\n使用 [Pydantic](https://docs.pydantic.dev/) 模型来声明**请求体**，能充分利用它的功能和优点。\n\n/// info | 信息\n\n发送数据应使用以下之一：`POST`（最常见）、`PUT`、`DELETE` 或 `PATCH`。\n\n规范中没有定义用 `GET` 请求发送请求体的行为，但 FastAPI 仍支持这种方式，只用于非常复杂/极端的用例。\n\n由于不推荐，在使用 `GET` 时，Swagger UI 的交互式文档不会显示请求体的文档，而且中间的代理可能也不支持它。\n\n///\n\n## 导入 Pydantic 的 `BaseModel` { #import-pydantics-basemodel }\n\n从 `pydantic` 中导入 `BaseModel`：\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## 创建数据模型 { #create-your-data-model }\n\n把数据模型声明为继承 `BaseModel` 的类。\n\n使用 Python 标准类型声明所有属性：\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\n与声明查询参数一样，包含默认值的模型属性是可选的，否则就是必选的。把默认值设为 `None` 可使其变为可选。\n\n例如，上述模型声明如下 JSON \"object\"（即 Python `dict`）：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n...由于 `description` 和 `tax` 是可选的（默认值为 `None`），下面的 JSON \"object\" 也有效：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## 声明为参数 { #declare-it-as-a-parameter }\n\n使用与声明路径和查询参数相同的方式，把它添加至*路径操作*：\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n...并把其类型声明为你创建的模型 `Item`。\n\n## 结果 { #results }\n\n仅使用这些 Python 类型声明，**FastAPI** 就可以：\n\n* 以 JSON 形式读取请求体。\n* （在必要时）把请求体转换为对应的类型。\n* 校验数据。\n    * 数据无效时返回清晰的错误信息，并指出错误数据的确切位置和内容。\n* 把接收的数据赋值给参数 `item`。\n    * 因为你把函数中的参数类型声明为 `Item`，所以还能获得所有属性及其类型的编辑器支持（补全等）。\n* 为你的模型生成 [JSON Schema](https://json-schema.org) 定义，如果对你的项目有意义，还可以在其他地方使用它们。\n* 这些 schema 会成为生成的 OpenAPI Schema 的一部分，并被自动文档的 <abbr title=\"User Interfaces - 用户界面\">UIs</abbr> 使用。\n\n## 自动文档 { #automatic-docs }\n\n你的模型的 JSON Schema 会成为生成的 OpenAPI Schema 的一部分，并显示在交互式 API 文档中：\n\n<img src=\"/img/tutorial/body/image01.png\">\n\n并且，还会用于需要它们的每个*路径操作*的 API 文档中：\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## 编辑器支持 { #editor-support }\n\n在编辑器中，函数内部你会在各处得到类型提示与补全（如果接收的不是 Pydantic 模型，而是 `dict`，就不会有这样的支持）：\n\n<img src=\"/img/tutorial/body/image03.png\">\n\n还支持检查错误的类型操作：\n\n<img src=\"/img/tutorial/body/image04.png\">\n\n这并非偶然，整个框架都是围绕这种设计构建的。\n\n并且在设计阶段、实现之前就进行了全面测试，以确保它能在所有编辑器中正常工作。\n\n我们甚至对 Pydantic 本身做了一些改动以支持这些功能。\n\n上面的截图来自 [Visual Studio Code](https://code.visualstudio.com)。\n\n但使用 [PyCharm](https://www.jetbrains.com/pycharm/) 和大多数其他 Python 编辑器，你也会获得相同的编辑器支持：\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip | 提示\n\n如果你使用 [PyCharm](https://www.jetbrains.com/pycharm/) 作为编辑器，可以使用 [Pydantic PyCharm 插件](https://github.com/koxudaxi/pydantic-pycharm-plugin/)。\n\n它能改进对 Pydantic 模型的编辑器支持，包括：\n\n* 自动补全\n* 类型检查\n* 代码重构\n* 查找\n* 代码审查\n\n///\n\n## 使用模型 { #use-the-model }\n\n在*路径操作*函数内部直接访问模型对象的所有属性：\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## 请求体 + 路径参数 { #request-body-path-parameters }\n\n可以同时声明路径参数和请求体。\n\n**FastAPI** 能识别与**路径参数**匹配的函数参数应该**从路径中获取**，而声明为 Pydantic 模型的函数参数应该**从请求体中获取**。\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n## 请求体 + 路径 + 查询参数 { #request-body-path-query-parameters }\n\n也可以同时声明**请求体**、**路径**和**查询**参数。\n\n**FastAPI** 会分别识别它们，并从正确的位置获取数据。\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\n函数参数按如下规则进行识别：\n\n* 如果该参数也在**路径**中声明了，它就是路径参数。\n* 如果该参数是（`int`、`float`、`str`、`bool` 等）**单一类型**，它会被当作**查询**参数。\n* 如果该参数的类型声明为 **Pydantic 模型**，它会被当作请求**体**。\n\n/// note | 注意\n\nFastAPI 会根据默认值 `= None` 知道 `q` 的值不是必填的。\n\n`str | None` 并不是 FastAPI 用来判断是否必填的依据；是否必填由是否有默认值 `= None` 决定。\n\n但添加这些类型注解可以让你的编辑器提供更好的支持并检测错误。\n\n///\n\n## 不使用 Pydantic { #without-pydantic }\n\n即便不使用 Pydantic 模型也能使用 **Body** 参数。详见[请求体 - 多参数：请求体中的单值](body-multiple-params.md#singular-values-in-body)。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/cookie-param-models.md",
    "content": "# Cookie 参数模型 { #cookie-parameter-models }\n\n如果您有一组相关的 **cookie**，您可以创建一个 **Pydantic 模型**来声明它们。🍪\n\n这将允许您在**多个地方**能够**重用模型**，并且可以一次性声明所有参数的验证方式和元数据。😎\n\n/// note | 注意\n\n自 FastAPI 版本 `0.115.0` 起支持此功能。🤓\n\n///\n\n/// tip | 提示\n\n此技术同样适用于 `Query` 、 `Cookie` 和 `Header` 。😎\n\n///\n\n## 带有 Pydantic 模型的 Cookie { #cookies-with-a-pydantic-model }\n\n在 **Pydantic** 模型中声明所需的 **cookie** 参数，然后将参数声明为 `Cookie` ：\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI** 将从请求中接收到的 **cookie** 中**提取**出**每个字段**的数据，并提供您定义的 Pydantic 模型。\n\n## 查看文档 { #check-the-docs }\n\n您可以在文档 UI 的 `/docs` 中查看定义的 cookie：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info | 信息\n\n请记住，由于**浏览器**以特殊方式**处理 cookie**，并在后台进行操作，因此它们**不会**轻易允许 **JavaScript** 访问这些 cookie。\n\n如果您访问 `/docs` 的 **API 文档 UI**，您将能够查看您*路径操作*的 cookie **文档**。\n\n但是即使您**填写数据**并点击“执行”，由于文档界面使用 **JavaScript**，cookie 将不会被发送。而您会看到一条**错误**消息，就好像您没有输入任何值一样。\n\n///\n\n## 禁止额外的 Cookie { #forbid-extra-cookies }\n\n在某些特殊使用情况下（可能并不常见），您可能希望**限制**您想要接收的 cookie。\n\n您的 API 现在可以控制自己的 <dfn title=\"只是个玩笑，别当真。和 cookie 同意无关，不过连 API 现在都能拒绝可怜的 cookie，挺好玩的。来，吃块小饼干吧。🍪\">cookie 同意</dfn>。🤪🍪\n\n您可以使用 Pydantic 的模型配置来禁止（ `forbid` ）任何额外（ `extra` ）字段：\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\n如果客户端尝试发送一些**额外的 cookie**，他们将收到**错误**响应。\n\n可怜的 cookie 通知条，费尽心思为了获得您的同意，却被<dfn title=\"又是个玩笑，别理我。给你的小饼干配点咖啡吧。☕\">API 拒绝了</dfn>。🍪\n\n例如，如果客户端尝试发送一个值为 `good-list-please` 的 `santa_tracker` cookie，客户端将收到一个**错误**响应，告知他们 `santa_tracker` <dfn title=\"圣诞老人不赞成没有小饼干。🎅 好吧，不再讲 cookie 的笑话了。\">cookie 是不允许的</dfn>：\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## 总结 { #summary }\n\n您可以使用 **Pydantic 模型**在 **FastAPI** 中声明 <dfn title=\"临走前再吃一块小饼干吧。🍪\">**cookie**</dfn>。😎\n"
  },
  {
    "path": "docs/zh/docs/tutorial/cookie-params.md",
    "content": "# Cookie 参数 { #cookie-parameters }\n\n定义 `Cookie` 参数与定义 `Query` 和 `Path` 参数一样。\n\n## 导入 `Cookie` { #import-cookie }\n\n首先，导入 `Cookie`：\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## 声明 `Cookie` 参数 { #declare-cookie-parameters }\n\n声明 `Cookie` 参数的方式与声明 `Query` 和 `Path` 参数相同。\n\n第一个值是默认值，还可以传递所有验证参数或注释参数：\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | 技术细节\n\n`Cookie` 、`Path` 、`Query` 是**兄弟类**，都继承自共用的 `Param` 类。\n\n注意，从 `fastapi` 导入的 `Query`、`Path`、`Cookie` 等对象，实际上是返回特殊类的函数。\n\n///\n\n/// info | 信息\n\n必须使用 `Cookie` 声明 cookie 参数，否则该参数会被解释为查询参数。\n\n///\n\n/// info | 信息\n\n请注意，由于**浏览器会以特殊方式并在幕后处理 cookies**，它们**不会**轻易允许**JavaScript**访问它们。\n\n如果你前往位于 `/docs` 的**API 文档界面**，你可以看到你的*路径操作*中有关 cookies 的**文档**。\n\n但即使你**填写了数据**并点击 \"Execute\"，由于文档界面依赖于**JavaScript**工作，cookies 也不会被发送，你会看到一个**错误**消息，好像你没有填写任何值一样。\n\n///\n\n## 小结 { #recap }\n\n使用 `Cookie` 声明 cookie 参数的方式与 `Query` 和 `Path` 相同。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/cors.md",
    "content": "# CORS（跨域资源共享） { #cors-cross-origin-resource-sharing }\n\n[CORS 或者「跨域资源共享」](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) 指浏览器中运行的前端拥有与后端通信的 JavaScript 代码，而后端处于与前端不同的「源」的情况。\n\n## 源 { #origin }\n\n源是协议（`http`，`https`）、域（`myapp.com`，`localhost`，`localhost.tiangolo.com`）以及端口（`80`、`443`、`8080`）的组合。\n\n因此，这些都是不同的源：\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\n即使它们都在 `localhost` 中，但是它们使用不同的协议或者端口，所以它们都是不同的「源」。\n\n## 步骤 { #steps }\n\n假设你的浏览器中有一个前端运行在 `http://localhost:8080`，并且它的 JavaScript 正在尝试与运行在 `http://localhost` 的后端通信（因为我们没有指定端口，浏览器会采用默认的端口 `80`）。\n\n然后，浏览器会向 `:80` 的后端发送一个 HTTP `OPTIONS` 请求，如果后端发送适当的 headers 来授权来自这个不同源（`http://localhost:8080`）的通信，那么运行在 `:8080` 的浏览器就会允许前端中的 JavaScript 向 `:80` 的后端发送请求。\n\n为此，`:80` 的后端必须有一个「允许的源」列表。\n\n在这种情况下，它必须包含 `http://localhost:8080`，这样 `:8080` 的前端才能正常工作。\n\n## 通配符 { #wildcards }\n\n也可以使用 `\"*\"`（一个「通配符」）声明这个列表，表示全部都是允许的。\n\n但这仅允许某些类型的通信，不包括所有涉及凭据的内容：比如 Cookies，以及那些使用 Bearer 令牌的 Authorization 请求头等。\n\n因此，为了一切都能正常工作，最好显式地指定允许的源。\n\n## 使用 `CORSMiddleware` { #use-corsmiddleware }\n\n你可以在 **FastAPI** 应用中使用 `CORSMiddleware` 来配置它。\n\n* 导入 `CORSMiddleware`。\n* 创建一个允许的源列表（由字符串组成）。\n* 将其作为「中间件」添加到你的 **FastAPI** 应用中。\n\n你也可以指定后端是否允许：\n\n* 凭证（Authorization 请求头、Cookies 等）。\n* 特定的 HTTP 方法（`POST`，`PUT`）或者使用通配符 `\"*\"` 允许所有方法。\n* 特定的 HTTP 请求头或者使用通配符 `\"*\"` 允许所有请求头。\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\n默认情况下，这个 `CORSMiddleware` 实现所使用的默认参数较为保守，所以你需要显式地启用特定的源、方法或者 headers，以便浏览器能够在跨域上下文中使用它们。\n\n支持以下参数：\n\n* `allow_origins` - 一个允许跨域请求的源列表。例如 `['https://example.org', 'https://www.example.org']`。你可以使用 `['*']` 允许任何源。\n* `allow_origin_regex` - 一个正则表达式字符串，匹配的源允许跨域请求。例如 `'https://.*\\.example\\.org'`。\n* `allow_methods` - 一个允许跨域请求的 HTTP 方法列表。默认为 `['GET']`。你可以使用 `['*']` 来允许所有标准方法。\n* `allow_headers` - 一个允许跨域请求的 HTTP 请求头列表。默认为 `[]`。你可以使用 `['*']` 允许所有的请求头。`Accept`、`Accept-Language`、`Content-Language` 以及 `Content-Type` 这几个请求头在[简单 CORS 请求](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests)中总是被允许。\n* `allow_credentials` - 指示跨域请求支持 cookies。默认是 `False`。\n\n    当 `allow_credentials` 设为 `True` 时，`allow_origins`、`allow_methods` 和 `allow_headers` 都不能设为 `['*']`。它们必须[显式指定](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards)。\n\n* `expose_headers` - 指示可以被浏览器访问的响应头。默认为 `[]`。\n* `max_age` - 设定浏览器缓存 CORS 响应的最长时间，单位是秒。默认为 `600`。\n\n中间件响应两种特定类型的 HTTP 请求...\n\n### CORS 预检请求 { #cors-preflight-requests }\n\n这是些带有 `Origin` 和 `Access-Control-Request-Method` 请求头的 `OPTIONS` 请求。\n\n在这种情况下，中间件将拦截传入的请求并进行响应，出于提供信息的目的返回一个使用了适当的 CORS headers 的 `200` 或 `400` 响应。\n\n### 简单请求 { #simple-requests }\n\n任何带有 `Origin` 请求头的请求。在这种情况下，中间件将像平常一样传递请求，但是在响应中包含适当的 CORS headers。\n\n## 更多信息 { #more-info }\n\n更多关于 <abbr title=\"Cross-Origin Resource Sharing - 跨域资源共享\">CORS</abbr> 的信息，请查看 [Mozilla CORS 文档](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)。\n\n/// note | 技术细节\n\n你也可以使用 `from starlette.middleware.cors import CORSMiddleware`。\n\n出于方便，**FastAPI** 在 `fastapi.middleware` 中为开发者提供了几个中间件。但是大多数可用的中间件都是直接来自 Starlette。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/tutorial/debugging.md",
    "content": "# 调试 { #debugging }\n\n你可以在编辑器中连接调试器，例如使用 Visual Studio Code 或 PyCharm。\n\n## 调用 `uvicorn` { #call-uvicorn }\n\n在你的 FastAPI 应用中直接导入 `uvicorn` 并运行：\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### 关于 `__name__ == \"__main__\"` { #about-name-main }\n\n`__name__ == \"__main__\"` 的主要目的是使用以下代码调用文件时执行一些代码：\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\n而当其它文件导入它时并不会被调用，像这样：\n\n```Python\nfrom myapp import app\n```\n\n#### 更多细节 { #more-details }\n\n假设你的文件命名为 `myapp.py`。\n\n如果你这样运行：\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\n那么文件中由 Python 自动创建的内部变量 `__name__`，会将字符串 `\"__main__\"` 作为值。\n\n所以，下面这部分代码才会运行：\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\n---\n\n如果你是导入这个模块（文件）就不会这样。\n\n因此，如果你的另一个文件 `importer.py` 像这样：\n\n```Python\nfrom myapp import app\n\n# 其他一些代码\n```\n\n在这种情况下，`myapp.py` 内部的自动变量不会有值为 `\"__main__\"` 的变量 `__name__`。\n\n所以，下面这一行不会被执行：\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\n/// info | 信息\n\n更多信息请检查 [Python 官方文档](https://docs.python.org/3/library/__main__.html).\n\n///\n\n## 使用你的调试器运行代码 { #run-your-code-with-your-debugger }\n\n由于是从代码直接运行的 Uvicorn 服务器，所以你可以从调试器直接调用 Python 程序（你的 FastAPI 应用）。\n\n---\n\n例如，你可以在 Visual Studio Code 中：\n\n* 进入到「调试」面板。\n* 「添加配置...」。\n* 选中「Python」\n* 运行「Python：当前文件（集成终端）」选项的调试器。\n\n然后它会使用你的 **FastAPI** 代码开启服务器，停在断点处，等等。\n\n看起来可能是这样：\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\n如果使用 Pycharm，你可以：\n\n* 打开「运行」菜单。\n* 选中「调试...」。\n* 然后出现一个上下文菜单。\n* 选择要调试的文件（本例中的 `main.py`）。\n\n然后它会使用你的 **FastAPI** 代码开启服务器，停在断点处，等等。\n\n看起来可能是这样：\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/zh/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# 类作为依赖项 { #classes-as-dependencies }\n\n在深入探究 **依赖注入** 系统之前，让我们升级之前的例子。\n\n## 来自前一个例子的`dict` { #a-dict-from-the-previous-example }\n\n在前面的例子中, 我们从依赖项 (\"可依赖对象\") 中返回了一个 `dict`:\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\n但是后面我们在路径操作函数的参数 `commons` 中得到了一个 `dict`。\n\n我们知道编辑器不能为 `dict` 提供很多支持(比如补全)，因为编辑器不知道 `dict` 的键和值类型。\n\n对此，我们可以做的更好...\n\n## 什么构成了依赖项 { #what-makes-a-dependency }\n\n到目前为止，你看到的依赖项都被声明为函数。\n\n但这并不是声明依赖项的唯一方法(尽管它可能是更常见的方法)。\n\n关键因素是依赖项应该是 \"可调用对象\"。\n\nPython 中的 \"**可调用对象**\" 是指任何 Python 可以像函数一样 \"调用\" 的对象。\n\n所以，如果你有一个对象 `something` (可能*不是*一个函数)，你可以 \"调用\" 它(执行它)，就像：\n\n```Python\nsomething()\n```\n\n或者\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\n这就是 \"可调用对象\"。\n\n## 类作为依赖项 { #classes-as-dependencies_1 }\n\n你可能会注意到，要创建一个 Python 类的实例，你可以使用相同的语法。\n\n举个例子:\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\n在这个例子中, `fluffy` 是一个 `Cat` 类的实例。\n\n为了创建 `fluffy`，你调用了 `Cat` 。\n\n所以，Python 类也是 **可调用对象**。\n\n因此，在 **FastAPI** 中，你可以使用一个 Python 类作为一个依赖项。\n\n实际上 FastAPI 检查的是它是一个 \"可调用对象\"（函数，类或其他任何类型）以及定义的参数。\n\n如果你在 **FastAPI** 中传递一个 \"可调用对象\" 作为依赖项，它将分析该 \"可调用对象\" 的参数，并以处理路径操作函数的参数的方式来处理它们。包括子依赖项。\n\n这也适用于完全没有参数的可调用对象。这与不带参数的路径操作函数一样。\n\n所以，我们可以将上面的依赖项 \"可依赖对象\" `common_parameters` 更改为类 `CommonQueryParams`:\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\n注意用于创建类实例的 `__init__` 方法：\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n...它与我们以前的 `common_parameters` 具有相同的参数：\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\n这些参数就是 **FastAPI** 用来 \"处理\" 依赖项的。\n\n在两个例子下，都有：\n\n* 一个可选的 `q` 查询参数，是 `str` 类型。\n* 一个 `skip` 查询参数，是 `int` 类型，默认值为 `0`。\n* 一个 `limit` 查询参数，是 `int` 类型，默认值为 `100`。\n\n在两个例子下，数据都将被转换、验证、在 OpenAPI schema 上文档化，等等。\n\n## 使用它 { #use-it }\n\n现在，你可以使用这个类来声明你的依赖项了。\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI** 调用 `CommonQueryParams` 类。这将创建该类的一个 \"实例\"，该实例将作为参数 `commons` 被传递给你的函数。\n\n## 类型注解 vs `Depends` { #type-annotation-vs-depends }\n\n注意，我们在上面的代码中编写了两次`CommonQueryParams`：\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 未使用 Annotated\n\n/// tip | 提示\n\n尽可能使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n最后的 `CommonQueryParams`:\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n...实际上是 **FastAPI** 用来知道依赖项是什么的。\n\nFastAPI 将从依赖项中提取声明的参数，这才是 FastAPI 实际调用的。\n\n---\n\n在本例中，第一个 `CommonQueryParams` ：\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ 未使用 Annotated\n\n/// tip | 提示\n\n尽可能使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n...对于 **FastAPI** 没有任何特殊的意义。FastAPI 不会使用它进行数据转换、验证等 (因为对于这，它使用 `Depends(CommonQueryParams)`)。\n\n你实际上可以只这样编写:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 未使用 Annotated\n\n/// tip | 提示\n\n尽可能使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n..就像:\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\n但是声明类型是被鼓励的，因为那样你的编辑器就会知道将传递什么作为参数 `commons` ，然后它可以帮助你完成代码，类型检查，等等：\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## 快捷方式 { #shortcut }\n\n但是你可以看到，我们在这里有一些代码重复了，编写了`CommonQueryParams`两次：\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 未使用 Annotated\n\n/// tip | 提示\n\n尽可能使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n**FastAPI** 为这些情况提供了一个快捷方式，在这些情况下，依赖项 *明确地* 是一个类，**FastAPI** 将 \"调用\" 它来创建类本身的一个实例。\n\n对于这些特定的情况，你可以按如下操作：\n\n不是写成这样：\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 未使用 Annotated\n\n/// tip | 提示\n\n尽可能使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n...而是这样写:\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ 未使用 Annotated\n\n/// tip | 提示\n\n尽可能使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\n你声明依赖项作为参数的类型，并使用 `Depends()` 作为该函数的参数的 \"默认\" 值(在 `=` 之后)，而在 `Depends()` 中没有任何参数，而不是在 `Depends(CommonQueryParams)` 中*再次*编写完整的类。\n\n同样的例子看起来像这样：\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n... **FastAPI** 会知道怎么处理。\n\n/// tip | 提示\n\n如果这看起来更加混乱而不是更加有帮助，那么请忽略它，你不*需要*它。\n\n这只是一个快捷方式。因为 **FastAPI** 关心的是帮助你减少代码重复。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# 路径操作装饰器依赖项 { #dependencies-in-path-operation-decorators }\n\n有时，我们并不需要在*路径操作函数*中使用依赖项的返回值。\n\n或者说，有些依赖项不返回值。\n\n但仍要执行或解析该依赖项。\n\n对于这种情况，不必在声明*路径操作函数*的参数时使用 `Depends`，而是可以在*路径操作装饰器*中添加一个由 `dependencies` 组成的 `list`。\n\n## 在*路径操作装饰器*中添加 `dependencies` 参数 { #add-dependencies-to-the-path-operation-decorator }\n\n*路径操作装饰器*支持可选参数 `dependencies`。\n\n该参数的值是由 `Depends()` 组成的 `list`：\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\n路径操作装饰器依赖项的执行或解析方式和普通依赖项一样，但就算这些依赖项会返回值，它们的值也不会传递给*路径操作函数*。\n\n/// tip | 提示\n\n有些编辑器会检查代码中没使用过的函数参数，并显示错误提示。\n\n在*路径操作装饰器*中使用 `dependencies` 参数，可以确保在执行依赖项的同时，避免编辑器/工具报错。\n\n使用路径装饰器依赖项还可以避免开发新人误会代码中包含无用的未使用参数。\n\n///\n\n/// info | 信息\n\n本例中，使用的是自定义响应头 `X-Key` 和 `X-Token`。\n\n但实际开发中，尤其是在实现安全措施时，最好使用 FastAPI 内置的[安全工具（下一章）](../security/index.md)。\n\n///\n\n## 依赖项错误和返回值 { #dependencies-errors-and-return-values }\n\n路径装饰器依赖项也可以使用普通的依赖项*函数*。\n\n### 依赖项的需求项 { #dependency-requirements }\n\n路径装饰器依赖项可以声明请求的需求项（比如响应头）或其他子依赖项：\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### 触发异常 { #raise-exceptions }\n\n路径装饰器依赖项与正常的依赖项一样，可以 `raise` 异常：\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### 返回值 { #return-values }\n\n无论路径装饰器依赖项是否返回值，路径操作都不会使用这些值。\n\n因此，可以复用在其他位置使用过的、（能返回值的）普通依赖项，即使没有使用这个值，也会执行该依赖项：\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## 为一组路径操作定义依赖项 { #dependencies-for-a-group-of-path-operations }\n\n稍后，[大型应用 - 多文件](../../tutorial/bigger-applications.md)一章中会介绍如何使用多个文件创建大型应用程序，在这一章中，您将了解到如何为一组*路径操作*声明单个 `dependencies` 参数。\n\n## 全局依赖项 { #global-dependencies }\n\n接下来，我们将学习如何为 `FastAPI` 应用程序添加全局依赖项，创建应用于每个*路径操作*的依赖项。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# 使用 yield 的依赖项 { #dependencies-with-yield }\n\nFastAPI 支持那些在完成后执行一些<dfn title=\"有时也称为：“退出代码”、“清理代码”、“拆卸代码”、“关闭代码”、“上下文管理器退出代码”等\">额外步骤</dfn>的依赖项。\n\n为此，使用 `yield` 而不是 `return`，并把这些额外步骤（代码）写在后面。\n\n/// tip | 提示\n\n确保在每个依赖里只使用一次 `yield`。\n\n///\n\n/// note | 技术细节\n\n任何可以与以下装饰器一起使用的函数：\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) 或\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\n都可以作为 **FastAPI** 的依赖项。\n\n实际上，FastAPI 在内部就是用的这两个装饰器。\n\n///\n\n## 使用 `yield` 的数据库依赖项 { #a-database-dependency-with-yield }\n\n例如，你可以用这种方式创建一个数据库会话，并在完成后将其关闭。\n\n在创建响应之前，只会执行 `yield` 语句及其之前的代码：\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\n`yield` 产生的值会注入到 *路径操作* 和其他依赖项中：\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\n`yield` 语句后面的代码会在响应之后执行：\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip | 提示\n\n你可以使用 `async` 或普通函数。\n\n**FastAPI** 会像处理普通依赖一样对它们进行正确处理。\n\n///\n\n## 同时使用 `yield` 和 `try` 的依赖项 { #a-dependency-with-yield-and-try }\n\n如果你在带有 `yield` 的依赖中使用了 `try` 代码块，那么当使用该依赖时抛出的任何异常你都会收到。\n\n例如，如果在中间的某处代码中（在另一个依赖或在某个 *路径操作* 中）发生了数据库事务“回滚”或产生了其他异常，你会在你的依赖中收到这个异常。\n\n因此，你可以在该依赖中用 `except SomeException` 来捕获这个特定异常。\n\n同样地，你可以使用 `finally` 来确保退出步骤一定会被执行，无论是否发生异常。\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## 使用 `yield` 的子依赖项 { #sub-dependencies-with-yield }\n\n你可以声明任意大小和形状的子依赖及其“树”，其中任意一个或全部都可以使用 `yield`。\n\n**FastAPI** 会确保每个带有 `yield` 的依赖中的“退出代码”按正确的顺序运行。\n\n例如，`dependency_c` 可以依赖 `dependency_b`，而 `dependency_b` 则依赖 `dependency_a`：\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\n并且它们都可以使用 `yield`。\n\n在这种情况下，`dependency_c` 在执行其退出代码时需要 `dependency_b`（此处命名为 `dep_b`）的值仍然可用。\n\n而 `dependency_b` 又需要 `dependency_a`（此处命名为 `dep_a`）的值在其退出代码中可用。\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\n同样地，你可以将一些依赖用 `yield`，另一些用 `return`，并让其中一些依赖依赖于另一些。\n\n你也可以有一个依赖需要多个带有 `yield` 的依赖，等等。\n\n你可以拥有任何你想要的依赖组合。\n\n**FastAPI** 将确保一切都按正确的顺序运行。\n\n/// note | 技术细节\n\n这要归功于 Python 的[上下文管理器](https://docs.python.org/3/library/contextlib.html)。\n\n**FastAPI** 在内部使用它们来实现这一点。\n\n///\n\n## 同时使用 `yield` 和 `HTTPException` 的依赖项 { #dependencies-with-yield-and-httpexception }\n\n你已经看到可以在带有 `yield` 的依赖中使用 `try` 块尝试执行一些代码，然后在 `finally` 之后运行一些退出代码。\n\n你也可以使用 `except` 来捕获引发的异常并对其进行处理。\n\n例如，你可以抛出一个不同的异常，如 `HTTPException`。\n\n/// tip | 提示\n\n这是一种相对高级的技巧，在大多数情况下你并不需要使用它，因为你可以在应用的其他代码中（例如在 *路径操作函数* 里）抛出异常（包括 `HTTPException`）。\n\n但是如果你需要，它就在这里。🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\n如果你想捕获异常并基于它创建一个自定义响应，请创建一个[自定义异常处理器](../handling-errors.md#install-custom-exception-handlers)。\n\n## 同时使用 `yield` 和 `except` 的依赖项 { #dependencies-with-yield-and-except }\n\n如果你在带有 `yield` 的依赖中使用 `except` 捕获了一个异常，并且你没有再次抛出它（或抛出一个新异常），FastAPI 将无法察觉发生过异常，就像普通的 Python 代码那样：\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\n在这种情况下，客户端会像预期那样看到一个 *HTTP 500 Internal Server Error* 响应，因为我们没有抛出 `HTTPException` 或类似异常，但服务器将**没有任何日志**或其他关于错误是什么的提示。😱\n\n### 在带有 `yield` 和 `except` 的依赖中务必 `raise` { #always-raise-in-dependencies-with-yield-and-except }\n\n如果你在带有 `yield` 的依赖中捕获到了一个异常，除非你抛出另一个 `HTTPException` 或类似异常，**否则你应该重新抛出原始异常**。\n\n你可以使用 `raise` 重新抛出同一个异常：\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\n现在客户端仍会得到同样的 *HTTP 500 Internal Server Error* 响应，但服务器日志中会有我们自定义的 `InternalError`。😎\n\n## 使用 `yield` 的依赖项的执行 { #execution-of-dependencies-with-yield }\n\n执行顺序大致如下图所示。时间轴从上到下，每一列都代表交互或执行代码的一部分。\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exception handler\nparticipant dep as Dep with yield\nparticipant operation as Path Operation\nparticipant tasks as Background tasks\n\n    Note over client,operation: Can raise exceptions, including HTTPException\n    client ->> dep: Start request\n    Note over dep: Run code up to yield\n    opt raise Exception\n        dep -->> handler: Raise Exception\n        handler -->> client: HTTP error response\n    end\n    dep ->> operation: Run dependency, e.g. DB session\n    opt raise\n        operation -->> dep: Raise Exception (e.g. HTTPException)\n        opt handle\n            dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception\n        end\n        handler -->> client: HTTP error response\n    end\n\n    operation ->> client: Return response to client\n    Note over client,operation: Response is already sent, can't change it anymore\n    opt Tasks\n        operation -->> tasks: Send background tasks\n    end\n    opt Raise other exception\n        tasks -->> tasks: Handle exceptions in the background task code\n    end\n```\n\n/// info | 信息\n\n只会向客户端发送**一次响应**。它可能是某个错误响应，或者是来自 *路径操作* 的响应。\n\n在其中一个响应发送之后，就不能再发送其他响应了。\n\n///\n\n/// tip | 提示\n\n如果你在 *路径操作函数* 的代码中引发任何异常，它都会被传递给带有 `yield` 的依赖项，包括 `HTTPException`。在大多数情况下，你会希望在带有 `yield` 的依赖中重新抛出相同的异常或一个新的异常，以确保它被正确处理。\n\n///\n\n## 提前退出与 `scope` { #early-exit-and-scope }\n\n通常，带有 `yield` 的依赖的退出代码会在响应发送给客户端**之后**执行。\n\n但如果你知道在从 *路径操作函数* 返回之后不再需要使用该依赖，你可以使用 `Depends(scope=\"function\")` 告诉 FastAPI：应当在 *路径操作函数* 返回后、但在**响应发送之前**关闭该依赖。\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()` 接收一个 `scope` 参数，可为：\n\n* `\"function\"`：在处理请求的 *路径操作函数* 之前启动依赖，在 *路径操作函数* 结束后结束依赖，但在响应发送给客户端**之前**。因此，依赖函数将围绕这个*路径操作函数*执行。\n* `\"request\"`：在处理请求的 *路径操作函数* 之前启动依赖（与使用 `\"function\"` 时类似），但在响应发送给客户端**之后**结束。因此，依赖函数将围绕这个**请求**与响应周期执行。\n\n如果未指定且依赖包含 `yield`，则默认 `scope` 为 `\"request\"`。\n\n### 子依赖的 `scope` { #scope-for-sub-dependencies }\n\n当你声明一个 `scope=\"request\"`（默认）的依赖时，任何子依赖也需要有 `\"request\"` 的 `scope`。\n\n但一个 `scope` 为 `\"function\"` 的依赖可以有 `scope` 为 `\"function\"` 和 `\"request\"` 的子依赖。\n\n这是因为任何依赖都需要能够在子依赖之前运行其退出代码，因为它的退出代码中可能还需要使用这些子依赖。\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Dep scope=\"request\"\nparticipant dep_func as Dep scope=\"function\"\nparticipant operation as Path Operation\n\n    client ->> dep_req: Start request\n    Note over dep_req: Run code up to yield\n    dep_req ->> dep_func: Pass dependency\n    Note over dep_func: Run code up to yield\n    dep_func ->> operation: Run path operation with dependency\n    operation ->> dep_func: Return from path operation\n    Note over dep_func: Run code after yield\n    Note over dep_func: ✅ Dependency closed\n    dep_func ->> client: Send response to client\n    Note over client: Response sent\n    Note over dep_req: Run code after yield\n    Note over dep_req: ✅ Dependency closed\n```\n\n## 包含 `yield`、`HTTPException`、`except` 和后台任务的依赖项 { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n带有 `yield` 的依赖项随着时间演进以涵盖不同的用例并修复了一些问题。\n\n如果你想了解在不同 FastAPI 版本中发生了哪些变化，可以在进阶指南中阅读更多：[高级依赖项 —— 包含 `yield`、`HTTPException`、`except` 和后台任务的依赖项](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks)。\n\n## 上下文管理器 { #context-managers }\n\n### 什么是“上下文管理器” { #what-are-context-managers }\n\n“上下文管理器”是你可以在 `with` 语句中使用的任意 Python 对象。\n\n例如，[你可以用 `with` 来读取文件](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files)：\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\n在底层，`open(\"./somefile.txt\")` 会创建一个“上下文管理器”对象。\n\n当 `with` 代码块结束时，它会确保文件被关闭，即使期间发生了异常。\n\n当你用 `yield` 创建一个依赖时，**FastAPI** 会在内部为它创建一个上下文管理器，并与其他相关工具结合使用。\n\n### 在带有 `yield` 的依赖中使用上下文管理器 { #using-context-managers-in-dependencies-with-yield }\n\n/// warning | 警告\n\n这算是一个“高级”概念。\n\n如果你刚开始使用 **FastAPI**，现在可以先跳过。\n\n///\n\n在 Python 中，你可以通过[创建一个带有 `__enter__()` 和 `__exit__()` 方法的类](https://docs.python.org/3/reference/datamodel.html#context-managers)来创建上下文管理器。\n\n你也可以在 **FastAPI** 的带有 `yield` 的依赖中，使用依赖函数内部的 `with` 或 `async with` 语句来使用它们：\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip | 提示\n\n另一种创建上下文管理器的方式是：\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) 或\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\n用它们去装饰一个只包含单个 `yield` 的函数。\n\n这正是 **FastAPI** 在内部处理带有 `yield` 的依赖时所使用的方式。\n\n但你不需要（也不应该）为 FastAPI 的依赖去使用这些装饰器。FastAPI 会在内部为你处理好。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# 全局依赖项 { #global-dependencies }\n\n有时，我们要为整个应用添加依赖项。\n\n通过与[将 `dependencies` 添加到*路径操作装饰器*](dependencies-in-path-operation-decorators.md) 类似的方式，可以把依赖项添加至整个 `FastAPI` 应用。\n\n这样一来，就可以为所有*路径操作*应用该依赖项：\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\n[将 `dependencies` 添加到*路径操作装饰器*](dependencies-in-path-operation-decorators.md) 一章的思路均适用于全局依赖项， 在本例中，这些依赖项可以用于应用中的所有*路径操作*。\n\n## 为一组路径操作定义依赖项 { #dependencies-for-groups-of-path-operations }\n\n稍后，[大型应用 - 多文件](../../tutorial/bigger-applications.md)一章中会介绍如何使用多个文件创建大型应用程序，在这一章中，你将了解到如何为一组*路径操作*声明单个 `dependencies` 参数。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/dependencies/index.md",
    "content": "# 依赖项 { #dependencies }\n\n**FastAPI** 提供了简单直观但功能强大的**<dfn title=\"也称为：组件、资源、提供者、服务、可注入项\">依赖注入</dfn>**系统。\n\n它被设计得非常易用，能让任何开发者都能轻松把其他组件与 **FastAPI** 集成。\n\n## 什么是「依赖注入」 { #what-is-dependency-injection }\n\n在编程中，**「依赖注入」**指的是，你的代码（本文中为*路径操作函数*）声明其运行所需并要使用的东西：“依赖”。\n\n然后，由该系统（本文中为 **FastAPI**）负责执行所有必要的逻辑，为你的代码提供这些所需的依赖（“注入”依赖）。\n\n当你需要以下内容时，这非常有用：\n\n* 共享业务逻辑（同一段代码逻辑反复复用）\n* 共享数据库连接\n* 实施安全、认证、角色权限等要求\n* 以及更多其他内容...\n\n同时尽量减少代码重复。\n\n## 第一步 { #first-steps }\n\n先来看一个非常简单的例子。它现在简单到几乎没什么用。\n\n但这样我们就可以专注于**依赖注入**系统是如何工作的。\n\n### 创建依赖项，或“dependable” { #create-a-dependency-or-dependable }\n\n首先关注依赖项。\n\n它只是一个函数，且可以接收与*路径操作函数*相同的所有参数：\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\n大功告成。\n\n**2 行**。\n\n它的形式和结构与所有*路径操作函数*相同。\n\n你可以把它当作没有“装饰器”（没有 `@app.get(\"/some-path\")`）的*路径操作函数*。\n\n而且它可以返回任何你想要的内容。\n\n本例中的依赖项预期接收：\n\n* 类型为 `str` 的可选查询参数 `q`\n* 类型为 `int` 的可选查询参数 `skip`，默认值 `0`\n* 类型为 `int` 的可选查询参数 `limit`，默认值 `100`\n\n然后它只需返回一个包含这些值的 `dict`。\n\n/// info | 信息\n\nFastAPI 在 0.95.0 版本中新增了对 `Annotated` 的支持（并开始推荐使用）。\n\n如果你的版本较旧，尝试使用 `Annotated` 会报错。\n\n在使用 `Annotated` 之前，请确保[升级 FastAPI 版本](../../deployment/versions.md#upgrading-the-fastapi-versions)到至少 0.95.1。\n\n///\n\n### 导入 `Depends` { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### 在“dependant”中声明依赖项 { #declare-the-dependency-in-the-dependant }\n\n与在*路径操作函数*的参数中使用 `Body`、`Query` 等相同，给参数使用 `Depends` 来声明一个新的依赖项：\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\n虽然你在函数参数中使用 `Depends` 的方式与 `Body`、`Query` 等相同，但 `Depends` 的工作方式略有不同。\n\n这里只能给 `Depends` 传入一个参数。\n\n这个参数必须是类似函数的可调用对象。\n\n你不需要直接调用它（不要在末尾加括号），只需将其作为参数传给 `Depends()`。\n\n该函数接收的参数与*路径操作函数*的参数相同。\n\n/// tip | 提示\n\n下一章会介绍除了函数之外，还有哪些“东西”可以用作依赖项。\n\n///\n\n接收到新的请求时，**FastAPI** 会负责：\n\n* 用正确的参数调用你的依赖项（“dependable”）函数\n* 获取函数返回的结果\n* 将该结果赋值给你的*路径操作函数*中的参数\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\n这样，你只需编写一次共享代码，**FastAPI** 会在你的*路径操作*中为你调用它。\n\n/// check | 检查\n\n注意，无需创建专门的类并传给 **FastAPI** 去“注册”之类的操作。\n\n只要把它传给 `Depends`，**FastAPI** 就知道该怎么做了。\n\n///\n\n## 共享 `Annotated` 依赖项 { #share-annotated-dependencies }\n\n在上面的示例中，你会发现这里有一点点**代码重复**。\n\n当你需要使用 `common_parameters()` 这个依赖时，你必须写出完整的带类型注解和 `Depends()` 的参数：\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\n但因为我们使用了 `Annotated`，可以把这个 `Annotated` 的值存到一个变量里，在多个地方复用：\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | 提示\n\n这只是标准的 Python，叫做“类型别名”，并不是 **FastAPI** 特有的。\n\n但因为 **FastAPI** 基于 Python 标准（包括 `Annotated`），你就可以在代码里使用这个技巧。😎\n\n///\n\n这些依赖会照常工作，而**最棒的是**，**类型信息会被保留**，这意味着你的编辑器依然能提供**自动补全**、**行内报错**等。同样适用于 `mypy` 等其他工具。\n\n当你在**大型代码库**中，在**很多*路径操作***里反复使用**相同的依赖**时，这会特别有用。\n\n## 要不要使用 `async`？ { #to-async-or-not-to-async }\n\n由于依赖项也会由 **FastAPI** 调用（与*路径操作函数*相同），因此定义函数时同样的规则也适用。\n\n你可以使用 `async def` 或普通的 `def`。\n\n你可以在普通的 `def` *路径操作函数*中声明 `async def` 的依赖项；也可以在异步的 `async def` *路径操作函数*中声明普通的 `def` 依赖项，等等。\n\n都没关系，**FastAPI** 知道该怎么处理。\n\n/// note | 注意\n\n如果不了解异步，请参阅文档中关于 `async` 和 `await` 的章节：[异步：*“着急了？”*](../../async.md#in-a-hurry)。\n\n///\n\n## 与 OpenAPI 集成 { #integrated-with-openapi }\n\n依赖项及子依赖项中声明的所有请求、验证和需求都会集成到同一个 OpenAPI 模式中。\n\n因此，交互式文档中也会包含这些依赖项的所有信息：\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## 简单用法 { #simple-usage }\n\n观察一下就会发现，只要*路径*和*操作*匹配，就会使用声明的*路径操作函数*。随后，**FastAPI** 会用正确的参数调用该函数，并从请求中提取数据。\n\n事实上，所有（或大多数）Web 框架的工作方式都是这样的。\n\n你从不会直接调用这些函数。它们由你的框架（此处为 **FastAPI**）调用。\n\n通过依赖注入系统，你还可以告诉 **FastAPI**，你的*路径操作函数*还“依赖”某些应在*路径操作函数*之前执行的内容，**FastAPI** 会负责执行它并“注入”结果。\n\n“依赖注入”的其他常见术语包括：\n\n* 资源（resources）\n* 提供方（providers）\n* 服务（services）\n* 可注入（injectables）\n* 组件（components）\n\n## **FastAPI** 插件 { #fastapi-plug-ins }\n\n可以使用**依赖注入**系统构建集成和“插件”。但实际上，根本**不需要创建“插件”**，因为通过依赖项可以声明无限多的集成与交互，使其可用于*路径操作函数*。\n\n依赖项可以用非常简单直观的方式创建，你只需导入所需的 Python 包，用*字面意义上的*几行代码就能把它们与你的 API 函数集成起来。\n\n在接下来的章节中，你会看到关于关系型数据库、NoSQL 数据库、安全等方面的示例。\n\n## **FastAPI** 兼容性 { #fastapi-compatibility }\n\n依赖注入系统的简洁让 **FastAPI** 能与以下内容兼容：\n\n* 各类关系型数据库\n* NoSQL 数据库\n* 外部包\n* 外部 API\n* 认证与授权系统\n* API 使用监控系统\n* 响应数据注入系统\n* 等等...\n\n## 简单而强大 { #simple-and-powerful }\n\n虽然**层级式依赖注入系统**的定义与使用非常简单，但它依然非常强大。\n\n你可以定义依赖其他依赖项的依赖项。\n\n最终会构建出一个依赖项的层级树，**依赖注入**系统会处理所有这些依赖（及其子依赖），并在每一步提供（注入）相应的结果。\n\n例如，假设你有 4 个 API 路径操作（*端点*）：\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\n你可以仅通过依赖项及其子依赖项为它们添加不同的权限要求：\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## 与 **OpenAPI** 集成 { #integrated-with-openapi_1 }\n\n在声明需求的同时，所有这些依赖项也会为你的*路径操作*添加参数、验证等内容。\n\n**FastAPI** 会负责把这些全部添加到 OpenAPI 模式中，以便它们显示在交互式文档系统里。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# 子依赖项 { #sub-dependencies }\n\nFastAPI 支持创建含**子依赖项**的依赖项。\n\n并且，可以按需声明任意**深度**的子依赖项嵌套层级。\n\n**FastAPI** 负责处理解析不同深度的子依赖项。\n\n## 第一层依赖项 “dependable” { #first-dependency-dependable }\n\n你可以创建一个第一层依赖项（“dependable”），如下：\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\n这段代码声明了类型为 `str` 的可选查询参数 `q`，然后返回这个查询参数。\n\n这个函数很简单（不过也没什么用），但却有助于让我们专注于了解子依赖项的工作方式。\n\n## 第二层依赖项，“dependable”和“dependant” { #second-dependency-dependable-and-dependant }\n\n接下来，创建另一个依赖项函数（一个“dependable”），并同时为它自身再声明一个依赖项（因此它同时也是一个“dependant”）：\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\n这里重点说明一下声明的参数：\n\n* 尽管该函数自身是依赖项（“dependable”），但还声明了另一个依赖项（它“依赖”于其他对象）\n    * 该函数依赖 `query_extractor`, 并把 `query_extractor` 的返回值赋给参数 `q`\n* 同时，该函数还声明了类型是 `str` 的可选 cookie（`last_query`）\n    * 用户未提供查询参数 `q` 时，则使用上次使用后保存在 cookie 中的查询\n\n## 使用依赖项 { #use-the-dependency }\n\n接下来，就可以使用依赖项：\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info | 信息\n\n注意，这里在*路径操作函数*中只声明了一个依赖项，即 `query_or_cookie_extractor` 。\n\n但 **FastAPI** 必须先处理 `query_extractor`，以便在调用 `query_or_cookie_extractor` 时使用 `query_extractor` 返回的结果。\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## 多次使用同一个依赖项 { #using-the-same-dependency-multiple-times }\n\n如果在同一个*路径操作* 多次声明了同一个依赖项，例如，多个依赖项共用一个子依赖项，**FastAPI** 在处理同一请求时，只调用一次该子依赖项。\n\nFastAPI 不会为同一个请求多次调用同一个依赖项，而是把依赖项的返回值进行<dfn title=\"用于存储已计算/生成的值，以便复用而无需再次计算的实用工具/系统\">「缓存」</dfn>，并把它传递给同一请求中所有需要使用该返回值的「依赖项」。\n\n在高级使用场景中，如果不想使用「缓存」值，而是为需要在同一请求的每一步操作（多次）中都实际调用依赖项，可以把 `Depends` 的参数 `use_cache` 的值设置为 `False`:\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ 非 Annotated\n\n/// tip | 提示\n\n尽可能优先使用 `Annotated` 版本。\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## 小结 { #recap }\n\n千万别被本章里这些花里胡哨的词藻吓倒了，其实**依赖注入**系统非常简单。\n\n依赖注入无非是与*路径操作函数*一样的函数罢了。\n\n但它依然非常强大，能够声明任意嵌套深度的「图」或树状的依赖结构。\n\n/// tip | 提示\n\n这些简单的例子现在看上去虽然没有什么实用价值，\n\n但在**安全**一章中，您会了解到这些例子的用途，\n\n以及这些例子所能节省的代码量。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/tutorial/encoder.md",
    "content": "# JSON 兼容编码器 { #json-compatible-encoder }\n\n在某些情况下，您可能需要将数据类型（如Pydantic模型）转换为与JSON兼容的数据类型（如`dict`、`list`等）。\n\n比如，如果您需要将其存储在数据库中。\n\n对于这种要求， **FastAPI**提供了`jsonable_encoder()`函数。\n\n## 使用`jsonable_encoder` { #using-the-jsonable-encoder }\n\n让我们假设你有一个数据库名为`fake_db`，它只能接收与JSON兼容的数据。\n\n例如，它不接收`datetime`这类的对象，因为这些对象与JSON不兼容。\n\n因此，`datetime`对象必须转换为包含[ISO 格式](https://en.wikipedia.org/wiki/ISO_8601)的`str`类型对象。\n\n同样，这个数据库也不会接收Pydantic模型（带有属性的对象），而只接收`dict`。\n\n对此你可以使用`jsonable_encoder`。\n\n它接收一个对象，比如Pydantic模型，并会返回一个JSON兼容的版本：\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\n在这个例子中，它将Pydantic模型转换为`dict`，并将`datetime`转换为`str`。\n\n调用它的结果后就可以使用Python标准编码中的[`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps)。\n\n这个操作不会返回一个包含JSON格式（作为字符串）数据的庞大的`str`。它将返回一个Python标准数据结构（例如`dict`），其值和子值都与JSON兼容。\n\n/// note | 注意\n\n`jsonable_encoder`实际上是**FastAPI**内部用来转换数据的。但是它在许多其他场景中也很有用。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/tutorial/extra-data-types.md",
    "content": "# 额外数据类型 { #extra-data-types }\n\n到目前为止，您一直在使用常见的数据类型，如:\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\n但是您也可以使用更复杂的数据类型。\n\n您仍然会拥有现在已经看到的相同的特性:\n\n* 很棒的编辑器支持。\n* 传入请求的数据转换。\n* 响应数据转换。\n* 数据验证。\n* 自动注解和文档。\n\n## 其他数据类型 { #other-data-types }\n\n下面是一些你可以使用的其他数据类型:\n\n* `UUID`:\n    * 一种标准的 \"通用唯一标识符\" ，在许多数据库和系统中用作ID。\n    * 在请求和响应中将以 `str` 表示。\n* `datetime.datetime`:\n    * 一个 Python `datetime.datetime`.\n    * 在请求和响应中将表示为 ISO 8601 格式的 `str` ，比如: `2008-09-15T15:53:00+05:00`.\n* `datetime.date`:\n    * Python `datetime.date`.\n    * 在请求和响应中将表示为 ISO 8601 格式的 `str` ，比如: `2008-09-15`.\n* `datetime.time`:\n    * 一个 Python `datetime.time`.\n    * 在请求和响应中将表示为 ISO 8601 格式的 `str` ，比如:  `14:23:55.003`.\n* `datetime.timedelta`:\n    * 一个 Python `datetime.timedelta`.\n    * 在请求和响应中将表示为 `float` 代表总秒数。\n    * Pydantic 也允许将其表示为 \"ISO 8601 时间差异编码\", [查看文档了解更多信息](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers)。\n* `frozenset`:\n    * 在请求和响应中，作为 `set` 对待：\n        * 在请求中，列表将被读取，消除重复，并将其转换为一个 `set`。\n        * 在响应中 `set` 将被转换为 `list` 。\n        * 产生的模式将指定那些 `set` 的值是唯一的 (使用 JSON Schema 的 `uniqueItems`)。\n* `bytes`:\n    * 标准的 Python `bytes`。\n    * 在请求和响应中被当作 `str` 处理。\n    * 生成的模式将指定这个 `str` 是 `binary` \"格式\"。\n* `Decimal`:\n    * 标准的 Python `Decimal`。\n    * 在请求和响应中被当做 `float` 一样处理。\n* 您可以在这里检查所有有效的 Pydantic 数据类型: [Pydantic data types](https://docs.pydantic.dev/latest/usage/types/types/)。\n\n## 例子 { #example }\n\n下面是一个*路径操作*的示例，其中的参数使用了上面的一些类型。\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\n注意，函数内的参数有原生的数据类型，你可以，例如，执行正常的日期操作，如:\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/zh/docs/tutorial/extra-models.md",
    "content": "# 更多模型 { #extra-models }\n\n书接上文，多个关联模型这种情况很常见。\n\n特别是用户模型，因为：\n\n* **输入模型**应该含密码\n* **输出模型**不应含密码\n* **数据库模型**可能需要包含哈希后的密码\n\n/// danger | 危险\n\n不要存储用户的明文密码。始终只存储之后可用于校验的“安全哈希”。\n\n如果你还不了解，可以在[安全性章节](security/simple-oauth2.md#password-hashing)中学习什么是“密码哈希”。\n\n///\n\n## 多个模型 { #multiple-models }\n\n下面的代码展示了不同模型处理密码字段的方式，及使用位置的大致思路：\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### 关于 `**user_in.model_dump()` { #about-user-in-model-dump }\n\n#### Pydantic 的 `.model_dump()` { #pydantics-model-dump }\n\n`user_in` 是类 `UserIn` 的 Pydantic 模型。\n\nPydantic 模型有 `.model_dump()` 方法，会返回包含模型数据的 `dict`。\n\n因此，如果使用如下方式创建 Pydantic 对象 `user_in`：\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\n就能以如下方式调用：\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\n现在，变量 `user_dict` 中的是包含数据的 `dict`（它是 `dict`，不是 Pydantic 模型对象）。\n\n以如下方式调用：\n\n```Python\nprint(user_dict)\n```\n\n输出的就是 Python `dict`：\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### 解包 `dict` { #unpacking-a-dict }\n\n把 `dict`（如 `user_dict`）以 `**user_dict` 形式传递给函数（或类），Python 会执行“解包”。它会把 `user_dict` 的键和值作为关键字参数直接传递。\n\n因此，接着上面的 `user_dict` 继续编写如下代码：\n\n```Python\nUserInDB(**user_dict)\n```\n\n就会生成如下结果：\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\n或更精准，直接使用 `user_dict`（无论它将来包含什么字段）：\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### 用另一个模型的内容生成 Pydantic 模型 { #a-pydantic-model-from-the-contents-of-another }\n\n上例中 ，从 `user_in.model_dump()` 中得到了 `user_dict`，下面的代码：\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\n等效于：\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n...因为 `user_in.model_dump()` 是 `dict`，在传递给 `UserInDB` 时，把 `**` 加在 `user_in.model_dump()` 前，可以让 Python 进行解包。\n\n这样，就可以用其它 Pydantic 模型中的数据生成 Pydantic 模型。\n\n#### 解包 `dict` 并添加额外关键字参数 { #unpacking-a-dict-and-extra-keywords }\n\n接下来，继续添加关键字参数 `hashed_password=hashed_password`，例如：\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n...输出结果如下：\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning | 警告\n\n配套的辅助函数 `fake_password_hasher` 和 `fake_save_user` 仅用于演示可能的数据流，当然并不提供真实的安全性。\n\n///\n\n## 减少重复 { #reduce-duplication }\n\n减少代码重复是 **FastAPI** 的核心思想之一。\n\n代码重复会导致 bug、安全问题、代码失步等问题（更新了某个位置的代码，但没有同步更新其它位置的代码）。\n\n上面的这些模型共享了大量数据，拥有重复的属性名和类型。\n\n我们可以做得更好。\n\n声明 `UserBase` 模型作为其它模型的基类。然后，用该类衍生出继承其属性（类型声明、校验等）的子类。\n\n所有数据转换、校验、文档等功能仍将正常运行。\n\n这样，就可以仅声明模型之间的差异部分（具有明文的 `password`、具有 `hashed_password` 以及不包括密码）：\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` 或 `anyOf` { #union-or-anyof }\n\n响应可以声明为两个或多个类型的 `Union`，即该响应可以是这些类型中的任意一种。\n\n在 OpenAPI 中会用 `anyOf` 表示。\n\n为此，请使用 Python 标准类型提示 [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union)：\n\n/// note | 注意\n\n定义 [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions) 类型时，要把更具体的类型写在前面，然后是不太具体的类型。下例中，更具体的 `PlaneItem` 位于 `Union[PlaneItem, CarItem]` 中的 `CarItem` 之前。\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### Python 3.10 中的 `Union` { #union-in-python-3-10 }\n\n在这个示例中，我们把 `Union[PlaneItem, CarItem]` 作为参数 `response_model` 的值传入。\n\n因为这是作为“参数的值”而不是放在“类型注解”中，所以即使在 Python 3.10 也必须使用 `Union`。\n\n如果是在类型注解中，我们就可以使用竖线：\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\n但如果把它写成赋值 `response_model=PlaneItem | CarItem`，就会报错，因为 Python 会尝试在 `PlaneItem` 和 `CarItem` 之间执行一个“无效的运算”，而不是把它当作类型注解来解析。\n\n## 模型列表 { #list-of-models }\n\n同样地，你可以声明由对象列表构成的响应。\n\n为此，请使用标准的 Python `list`：\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## 任意 `dict` 的响应 { #response-with-arbitrary-dict }\n\n你也可以使用普通的任意 `dict` 来声明响应，只需声明键和值的类型，无需使用 Pydantic 模型。\n\n如果你事先不知道有效的字段/属性名（Pydantic 模型需要预先知道字段）时，这很有用。\n\n此时，可以使用 `dict`：\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## 小结 { #recap }\n\n针对不同场景，可以随意使用不同的 Pydantic 模型并通过继承复用。\n\n当一个实体需要具备不同的“状态”时，无需只为该实体定义一个数据模型。例如，用户“实体”就可能有包含 `password`、包含 `password_hash` 以及不含密码等多种状态。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/first-steps.md",
    "content": "# 第一步 { #first-steps }\n\n最简单的 FastAPI 文件可能像下面这样：\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\n将其复制到 `main.py` 文件中。\n\n运行实时服务器：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n在输出中，会有一行信息像下面这样：\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n该行显示了你的应用在本机所提供服务的 URL 地址。\n\n### 查看 { #check-it }\n\n打开浏览器访问 [http://127.0.0.1:8000](http://127.0.0.1:8000)。\n\n你将看到如下的 JSON 响应：\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### 交互式 API 文档 { #interactive-api-docs }\n\n跳转到 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n你将会看到自动生成的交互式 API 文档（由 [Swagger UI](https://github.com/swagger-api/swagger-ui) 提供）：\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### 可选的 API 文档 { #alternative-api-docs }\n\n前往 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)。\n\n你将会看到可选的自动生成文档 （由 [ReDoc](https://github.com/Rebilly/ReDoc) 提供）：\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI** 使用定义 API 的 **OpenAPI** 标准将你的所有 API 转换成「模式」。\n\n#### 「模式」 { #schema }\n\n「模式」是对事物的一种定义或描述。它并非具体的实现代码，而只是抽象的描述。\n\n#### API「模式」 { #api-schema }\n\n在这种场景下，[OpenAPI](https://github.com/OAI/OpenAPI-Specification) 是一种规定如何定义 API 模式的规范。\n\n「模式」的定义包括你的 API 路径，以及它们可能使用的参数等等。\n\n#### 数据「模式」 { #data-schema }\n\n「模式」这个术语也可能指的是某些数据比如 JSON 的结构。\n\n在这种情况下，它可以表示 JSON 的属性及其具有的数据类型，等等。\n\n#### OpenAPI 和 JSON Schema { #openapi-and-json-schema }\n\nOpenAPI 为你的 API 定义 API 模式。该模式中包含了你的 API 发送和接收的数据的定义（或称为「模式」），这些定义通过 JSON 数据模式标准 **JSON Schema** 所生成。\n\n#### 查看 `openapi.json` { #check-the-openapi-json }\n\n如果你对原始的 OpenAPI 模式长什么样子感到好奇，FastAPI 自动生成了包含所有 API 描述的 JSON（模式）。\n\n你可以直接在：[http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json) 看到它。\n\n它将显示以如下内容开头的 JSON：\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### OpenAPI 的用途 { #what-is-openapi-for }\n\n驱动 FastAPI 内置的 2 个交互式文档系统的正是 OpenAPI 模式。\n\n并且还有数十种替代方案，它们全部都基于 OpenAPI。你可以轻松地将这些替代方案中的任何一种添加到使用 **FastAPI** 构建的应用程序中。\n\n你还可以使用它自动生成与你的 API 进行通信的客户端代码。例如 web 前端，移动端或物联网嵌入程序。\n\n### 在 `pyproject.toml` 中配置应用 `entrypoint` { #configure-the-app-entrypoint-in-pyproject-toml }\n\n你可以在 `pyproject.toml` 文件中配置应用的位置，例如：\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\n该 `entrypoint` 会告诉 `fastapi` 命令按如下方式导入应用：\n\n```python\nfrom main import app\n```\n\n如果你的代码结构如下：\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\n那么你可以将 `entrypoint` 设置为：\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\n这等价于：\n\n```python\nfrom backend.main import app\n```\n\n### `fastapi dev` 带路径 { #fastapi-dev-with-path }\n\n你也可以把文件路径传给 `fastapi dev` 命令，它会尝试推断要使用的 FastAPI 应用对象：\n\n```console\n$ fastapi dev main.py\n```\n\n但这样每次调用 `fastapi` 命令时都需要记得传入正确的路径。\n\n另外，其他工具可能无法找到它，例如 [VS Code 扩展](../editor-support.md) 或 [FastAPI Cloud](https://fastapicloud.com)，因此推荐在 `pyproject.toml` 中使用 `entrypoint`。\n\n### 部署你的应用（可选） { #deploy-your-app-optional }\n\n你可以选择将 FastAPI 应用部署到 [FastAPI Cloud](https://fastapicloud.com)，如果还没有，先去加入候补名单。🚀\n\n如果你已经拥有 **FastAPI Cloud** 账户（我们从候补名单邀请了你 😉），你可以用一条命令部署应用。\n\n部署前，先确保已登录：\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n然后部署你的应用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n就这些！现在你可以通过该 URL 访问你的应用了。✨\n\n## 分步概括 { #recap-step-by-step }\n\n### 步骤 1：导入 `FastAPI` { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI` 是一个为你的 API 提供了所有功能的 Python 类。\n\n/// note | 技术细节\n\n`FastAPI` 是直接从 `Starlette` 继承的类。\n\n你可以通过 `FastAPI` 使用所有的 [Starlette](https://www.starlette.dev/) 的功能。\n\n///\n\n### 步骤 2：创建一个 `FastAPI`「实例」 { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\n这里的变量 `app` 会是 `FastAPI` 类的一个「实例」。\n\n这个实例将是创建你所有 API 的主要交互对象。\n\n### 步骤 3：创建一个*路径操作* { #step-3-create-a-path-operation }\n\n#### 路径 { #path }\n\n这里的「路径」指的是 URL 中从第一个 `/` 起的后半部分。\n\n所以，在一个这样的 URL 中：\n\n```\nhttps://example.com/items/foo\n```\n\n...路径会是：\n\n```\n/items/foo\n```\n\n/// info\n\n「路径」也通常被称为「端点」或「路由」。\n\n///\n\n开发 API 时，「路径」是用来分离「关注点」和「资源」的主要手段。\n\n#### 操作 { #operation }\n\n这里的「操作」指的是一种 HTTP「方法」。\n\n下列之一：\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n...以及更少见的几种：\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\n在 HTTP 协议中，你可以使用以上的其中一种（或多种）「方法」与每个路径进行通信。\n\n---\n\n在开发 API 时，你通常使用特定的 HTTP 方法去执行特定的行为。\n\n通常使用：\n\n* `POST`：创建数据。\n* `GET`：读取数据。\n* `PUT`：更新数据。\n* `DELETE`：删除数据。\n\n因此，在 OpenAPI 中，每一个 HTTP 方法都被称为「操作」。\n\n我们也打算称呼它们为「操作」。\n\n#### 定义一个*路径操作装饰器* { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\n`@app.get(\"/\")` 告诉 **FastAPI** 在它下方的函数负责处理如下访问请求：\n\n* 请求路径为 `/`\n* 使用 <dfn title=\"一种 HTTP GET 方法\"><code>get</code> 操作</dfn>\n\n/// info | `@decorator` 信息\n\n`@something` 语法在 Python 中被称为「装饰器」。\n\n像一顶漂亮的装饰帽一样，将它放在一个函数的上方（我猜测这个术语的命名就是这么来的）。\n\n装饰器接收位于其下方的函数并且用它完成一些工作。\n\n在我们的例子中，这个装饰器告诉 **FastAPI** 位于其下方的函数对应着**路径** `/` 加上 `get` **操作**。\n\n它是一个「**路径操作装饰器**」。\n\n///\n\n你也可以使用其他的操作：\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\n以及更少见的：\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip\n\n你可以随意使用任何一个操作（HTTP方法）。\n\n**FastAPI** 没有强制要求操作有任何特定的含义。\n\n此处提供的信息仅作为指导，而不是要求。\n\n比如，当使用 GraphQL 时通常你所有的动作都通过 `POST` 一种方法执行。\n\n///\n\n### 步骤 4：定义**路径操作函数** { #step-4-define-the-path-operation-function }\n\n这是我们的「**路径操作函数**」：\n\n* **路径**：是 `/`。\n* **操作**：是 `get`。\n* **函数**：是位于「装饰器」下方的函数（位于 `@app.get(\"/\")` 下方）。\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\n这是一个 Python 函数。\n\n每当 **FastAPI** 接收一个使用 `GET` 方法访问 URL「`/`」的请求时这个函数会被调用。\n\n在这个例子中，它是一个 `async` 函数。\n\n---\n\n你也可以将其定义为常规函数而不使用 `async def`:\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note\n\n如果你不知道两者的区别，请查阅 [并发: *赶时间吗？*](../async.md#in-a-hurry)。\n\n///\n\n### 步骤 5：返回内容 { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\n你可以返回一个 `dict`、`list`，像 `str`、`int` 一样的单个值，等等。\n\n你还可以返回 Pydantic 模型（稍后你将了解更多）。\n\n还有许多其他将会自动转换为 JSON 的对象和模型（包括 ORM 对象等）。尝试下使用你最喜欢的一种，它很有可能已经被支持。\n\n### 步骤 6：部署 { #step-6-deploy-it }\n\n用一条命令将你的应用部署到 **[FastAPI Cloud](https://fastapicloud.com)**：`fastapi deploy`。🎉\n\n#### 关于 FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** 由 **FastAPI** 的作者和团队打造。\n\n它以最小的投入简化了 **构建**、**部署** 和 **访问** API 的流程。\n\n它把使用 FastAPI 构建应用的相同**开发者体验**带到了将应用**部署**到云端的过程。🎉\n\nFastAPI Cloud 是 *FastAPI 及其朋友们* 开源项目的主要赞助和资金提供方。✨\n\n#### 部署到其他云服务商 { #deploy-to-other-cloud-providers }\n\nFastAPI 是开源并基于标准的。你可以将 FastAPI 应用部署到你选择的任何云服务商。\n\n按照你的云服务商的指南部署 FastAPI 应用即可。🤓\n\n## 总结 { #recap }\n\n* 导入 `FastAPI`。\n* 创建一个 `app` 实例。\n* 编写一个**路径操作装饰器**，如 `@app.get(\"/\")`。\n* 定义一个**路径操作函数**，如 `def root(): ...`。\n* 使用命令 `fastapi dev` 运行开发服务器。\n* 可选：使用 `fastapi deploy` 部署你的应用。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/handling-errors.md",
    "content": "# 处理错误 { #handling-errors }\n\n某些情况下，需要向使用你的 API 的客户端返回错误提示。\n\n这里所谓的客户端包括前端浏览器、他人的代码、物联网设备等。\n\n你可能需要告诉客户端：\n\n- 客户端没有执行该操作的权限\n- 客户端没有访问该资源的权限\n- 客户端要访问的项目不存在\n- 等等\n\n遇到这些情况时，通常要返回 **4XX**（400 至 499）**HTTP 状态码**。\n\n这与表示请求成功的 **2XX**（200 至 299）HTTP 状态码类似。那些“200”状态码表示某种程度上的“成功”。\n\n而 **4XX** 状态码表示客户端发生了错误。\n\n大家都知道**「404 Not Found」**错误，还有调侃这个错误的笑话吧？\n\n## 使用 `HTTPException` { #use-httpexception }\n\n向客户端返回 HTTP 错误响应，可以使用 `HTTPException`。\n\n### 导入 `HTTPException` { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### 在代码中触发 `HTTPException` { #raise-an-httpexception-in-your-code }\n\n`HTTPException` 是额外包含了和 API 有关数据的常规 Python 异常。\n\n因为是 Python 异常，所以不能 `return`，只能 `raise`。\n\n这也意味着，如果你在*路径操作函数*里调用的某个工具函数内部触发了 `HTTPException`，那么*路径操作函数*中后续的代码将不会继续执行，请求会立刻终止，并把 `HTTPException` 的 HTTP 错误发送给客户端。\n\n在介绍依赖项与安全的章节中，你可以更直观地看到用 `raise` 异常代替 `return` 值的优势。\n\n本例中，客户端用不存在的 `ID` 请求 `item` 时，触发状态码为 `404` 的异常：\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### 响应结果 { #the-resulting-response }\n\n请求为 `http://example.com/items/foo`（`item_id` 为 `\"foo\"`）时，客户端会接收到 HTTP 状态码 200 及如下 JSON 响应结果：\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\n但如果客户端请求 `http://example.com/items/bar`（不存在的 `item_id` `\"bar\"`），则会接收到 HTTP 状态码 404（“未找到”错误）及如下 JSON 响应结果：\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip | 提示\n\n触发 `HTTPException` 时，可以用参数 `detail` 传递任何能转换为 JSON 的值，不仅限于 `str`。\n\n还支持传递 `dict`、`list` 等数据结构。\n\n**FastAPI** 能自动处理这些数据，并将之转换为 JSON。\n\n///\n\n## 添加自定义响应头 { #add-custom-headers }\n\n有些场景下要为 HTTP 错误添加自定义响应头。例如，出于某些类型的安全需要。\n\n一般情况下你可能不会在代码中直接使用它。\n\n但在某些高级场景中需要时，你可以添加自定义响应头：\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## 安装自定义异常处理器 { #install-custom-exception-handlers }\n\n可以使用[与 Starlette 相同的异常处理工具](https://www.starlette.dev/exceptions/)添加自定义异常处理器。\n\n假设有一个自定义异常 `UnicornException`（你自己或你使用的库可能会 `raise` 它）。\n\n并且你希望用 FastAPI 在全局处理该异常。\n\n此时，可以用 `@app.exception_handler()` 添加自定义异常处理器：\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\n这里，请求 `/unicorns/yolo` 时，路径操作会触发 `UnicornException`。\n\n但该异常将会被 `unicorn_exception_handler` 处理。\n\n你会收到清晰的错误信息，HTTP 状态码为 `418`，JSON 内容如下：\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | 技术细节\n\n也可以使用 `from starlette.requests import Request` 和 `from starlette.responses import JSONResponse`。\n\n**FastAPI** 提供了与 `starlette.responses` 相同的 `fastapi.responses` 作为便捷方式，但大多数可用的响应都直接来自 Starlette。`Request` 也是如此。\n\n///\n\n## 覆盖默认异常处理器 { #override-the-default-exception-handlers }\n\n**FastAPI** 自带了一些默认异常处理器。\n\n当你触发 `HTTPException`，或者请求中包含无效数据时，这些处理器负责返回默认的 JSON 响应。\n\n你也可以用自己的处理器覆盖它们。\n\n### 覆盖请求验证异常 { #override-request-validation-exceptions }\n\n请求中包含无效数据时，**FastAPI** 内部会触发 `RequestValidationError`。\n\n它也内置了该异常的默认处理器。\n\n要覆盖它，导入 `RequestValidationError`，并用 `@app.exception_handler(RequestValidationError)` 装饰你的异常处理器。\n\n异常处理器会接收 `Request` 和该异常。\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\n现在，访问 `/items/foo` 时，默认的 JSON 错误为：\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\n将得到如下文本内容：\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### 覆盖 `HTTPException` 错误处理器 { #override-the-httpexception-error-handler }\n\n同理，也可以覆盖 `HTTPException` 的处理器。\n\n例如，只为这些错误返回纯文本响应，而不是 JSON：\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | 技术细节\n\n还可以使用 `from starlette.responses import PlainTextResponse`。\n\n**FastAPI** 提供了与 `starlette.responses` 相同的 `fastapi.responses` 作为便捷方式，但大多数可用的响应都直接来自 Starlette。\n\n///\n\n/// warning | 警告\n\n请注意，`RequestValidationError` 包含发生验证错误的文件名和行号信息，你可以在需要时将其记录到日志中以提供相关信息。\n\n但这也意味着，如果你只是将其直接转换为字符串并返回，可能会泄露一些关于系统的细节信息。因此，这里的代码会提取并分别显示每个错误。\n\n///\n\n### 使用 `RequestValidationError` 的请求体 { #use-the-requestvalidationerror-body }\n\n`RequestValidationError` 包含其接收到的带有无效数据的请求体 `body`。\n\n开发时，你可以用它来记录请求体、调试错误，或返回给用户等。\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\n现在试着发送一个无效的 `item`，例如：\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\n收到的响应会告诉你数据无效，并包含收到的请求体：\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### FastAPI 的 `HTTPException` vs Starlette 的 `HTTPException` { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI** 也提供了自有的 `HTTPException`。\n\n**FastAPI** 的 `HTTPException` 错误类继承自 Starlette 的 `HTTPException` 错误类。\n\n它们之间的唯一区别是，**FastAPI** 的 `HTTPException` 在 `detail` 字段中接受任意可转换为 JSON 的数据，而 Starlette 的 `HTTPException` 只接受字符串。\n\n因此，你可以继续像平常一样在代码中触发 **FastAPI** 的 `HTTPException`。\n\n但注册异常处理器时，应该注册到来自 Starlette 的 `HTTPException`。\n\n这样做是为了，当 Starlette 的内部代码、扩展或插件触发 Starlette `HTTPException` 时，你的处理器能够捕获并处理它。\n\n本例中，为了在同一份代码中同时使用两个 `HTTPException`，将 Starlette 的异常重命名为 `StarletteHTTPException`：\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### 复用 **FastAPI** 的异常处理器 { #reuse-fastapis-exception-handlers }\n\n如果你想在自定义处理后仍复用 **FastAPI** 的默认异常处理器，可以从 `fastapi.exception_handlers` 导入并复用这些默认处理器：\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\n虽然本例只是用非常夸张的信息打印了错误，但足以说明：你可以先处理异常，然后再复用默认的异常处理器。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/header-param-models.md",
    "content": "# Header 参数模型 { #header-parameter-models }\n\n如果您有一组相关的 **header 参数**，您可以创建一个 **Pydantic 模型**来声明它们。\n\n这将允许您在**多个地方**能够**重用模型**，并且可以一次性声明所有参数的验证和元数据。😎\n\n/// note | 注意\n\n自 FastAPI 版本 `0.115.0` 起支持此功能。🤓\n\n///\n\n## 使用 Pydantic 模型的 Header 参数 { #header-parameters-with-a-pydantic-model }\n\n在 **Pydantic 模型**中声明所需的 **header 参数**，然后将参数声明为 `Header` :\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\n**FastAPI** 将从请求中接收到的 **headers** 中**提取**出**每个字段**的数据，并提供您定义的 Pydantic 模型。\n\n## 查看文档 { #check-the-docs }\n\n您可以在文档 UI 的 `/docs` 中查看所需的 headers：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## 禁止额外的 Headers { #forbid-extra-headers }\n\n在某些特殊使用情况下（可能并不常见），您可能希望**限制**您想要接收的 headers。\n\n您可以使用 Pydantic 的模型配置来禁止（ `forbid` ）任何额外（ `extra` ）字段：\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\n如果客户尝试发送一些**额外的 headers**，他们将收到**错误**响应。\n\n例如，如果客户端尝试发送一个值为 `plumbus` 的 `tool` header，客户端将收到一个**错误**响应，告知他们 header 参数 `tool` 是不允许的：\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## 禁用下划线转换 { #disable-convert-underscores }\n\n与常规的 header 参数相同，当参数名中包含下划线时，会**自动转换为连字符**。\n\n例如，如果你的代码中有一个名为 `save_data` 的 header 参数，那么预期的 HTTP 头将是 `save-data`，并且在文档中也会以这种形式显示。\n\n如果由于某些原因你需要禁用这种自动转换，你也可以在用于 header 参数的 Pydantic 模型中进行设置。\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | 警告\n\n在将 `convert_underscores` 设为 `False` 之前，请注意某些 HTTP 代理和服务器不允许使用带下划线的 headers。\n\n///\n\n## 总结 { #summary }\n\n您可以使用 **Pydantic 模型**在 **FastAPI** 中声明 **headers**。😎\n"
  },
  {
    "path": "docs/zh/docs/tutorial/header-params.md",
    "content": "# Header 参数 { #header-parameters }\n\n定义 `Header` 参数的方式与定义 `Query`、`Path`、`Cookie` 参数相同。\n\n## 导入 `Header` { #import-header }\n\n首先，导入 `Header`：\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## 声明 `Header` 参数 { #declare-header-parameters }\n\n然后，使用和 `Path`、`Query`、`Cookie` 一样的结构定义 header 参数。\n\n第一个值是默认值，还可以传递所有验证参数或注释参数：\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | 技术细节\n\n`Header` 是 `Path`、`Query`、`Cookie` 的**兄弟类**，都继承自共用的 `Param` 类。\n\n注意，从 `fastapi` 导入的 `Query`、`Path`、`Header` 等对象，实际上是返回特殊类的函数。\n\n///\n\n/// info | 信息\n\n必须使用 `Header` 声明 header 参数，否则该参数会被解释为查询参数。\n\n///\n\n## 自动转换 { #automatic-conversion }\n\n`Header` 比 `Path`、`Query` 和 `Cookie` 提供了更多功能。\n\n大部分标准请求头用**连字符**分隔，即**减号**（`-`）。\n\n但是 `user-agent` 这样的变量在 Python 中是无效的。\n\n因此，默认情况下，`Header` 把参数名中的字符由下划线（`_`）改为连字符（`-`）来提取并存档请求头 。\n\n同时，HTTP 的请求头不区分大小写，可以使用 Python 标准样式（即 **snake_case**）进行声明。\n\n因此，可以像在 Python 代码中一样使用 `user_agent` ，无需把首字母大写为 `User_Agent` 等形式。\n\n如需禁用下划线自动转换为连字符，可以把 `Header` 的 `convert_underscores` 参数设置为 `False`：\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | 警告\n\n注意，使用 `convert_underscores = False` 要慎重，有些 HTTP 代理和服务器不支持使用带有下划线的请求头。\n\n///\n\n## 重复的请求头 { #duplicate-headers }\n\n有时，可能需要接收重复的请求头。即同一个请求头有多个值。\n\n类型声明中可以使用 `list` 定义多个请求头。\n\n使用 Python `list` 可以接收重复请求头所有的值。\n\n例如，声明 `X-Token` 多次出现的请求头，可以写成这样：\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\n与*路径操作*通信时，以下面的方式发送两个 HTTP 请求头：\n\n```\nX-Token: foo\nX-Token: bar\n```\n\n响应结果是：\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## 小结 { #recap }\n\n使用 `Header` 声明请求头的方式与 `Query`、`Path` 、`Cookie` 相同。\n\n不用担心变量中的下划线，**FastAPI** 可以自动转换。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/index.md",
    "content": "# 教程 - 用户指南 { #tutorial-user-guide }\n\n本教程将一步步向您展示如何使用 **FastAPI** 的绝大部分特性。\n\n各个章节的内容循序渐进，但是又围绕着单独的主题，所以您可以直接跳转到某个章节以解决您的特定 API 需求。\n\n本教程同样可以作为将来的参考手册，所以您可以随时回到本教程并查阅您需要的内容。\n\n## 运行代码 { #run-the-code }\n\n所有代码片段都可以复制后直接使用（它们实际上是经过测试的 Python 文件）。\n\n要运行任何示例，请将代码复制到 `main.py` 文件中，然后启动 `fastapi dev`：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n**强烈建议**您在本地编写或复制代码，对其进行编辑并运行。\n\n在编辑器中使用 FastAPI 会真正地展现出它的优势：只需要编写很少的代码，所有的类型检查，代码补全等等。\n\n---\n\n## 安装 FastAPI { #install-fastapi }\n\n第一个步骤是安装 FastAPI.\n\n请确保您创建并激活一个[虚拟环境](../virtual-environments.md)，然后**安装 FastAPI**：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | 注意\n\n当您使用 `pip install \"fastapi[standard]\"` 安装时，它会附带一些默认的可选标准依赖项，其中包括 `fastapi-cloud-cli`，它可以让您部署到 [FastAPI Cloud](https://fastapicloud.com)。\n\n如果您不想安装这些可选依赖，可以选择安装 `pip install fastapi`。\n\n如果您想安装标准依赖但不包含 `fastapi-cloud-cli`，可以使用 `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"` 安装。\n\n///\n\n/// tip | 提示\n\nFastAPI 提供了一个[VS Code 官方扩展](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode)（也支持 Cursor），包含众多功能，例如路径操作浏览器、路径操作搜索、测试中的 CodeLens 导航（从测试跳转到定义），以及从编辑器内进行 FastAPI Cloud 部署和查看日志。\n\n///\n\n## 进阶用户指南 { #advanced-user-guide }\n\n在本**教程-用户指南**之后，您可以阅读**进阶用户指南**。\n\n**进阶用户指南**以本教程为基础，使用相同的概念，并教授一些额外的特性。\n\n但是您应该先阅读**教程-用户指南**（即您现在正在阅读的内容）。\n\n教程经过精心设计，使您可以仅通过**教程-用户指南**来开发一个完整的应用程序，然后根据您的需要，使用**进阶用户指南**中的一些其他概念，以不同的方式来扩展它。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/metadata.md",
    "content": "# 元数据和文档 URL { #metadata-and-docs-urls }\n\n你可以在 FastAPI 应用程序中自定义多个元数据配置。\n\n## API 元数据 { #metadata-for-api }\n\n你可以在设置 OpenAPI 规范和自动 API 文档 UI 中使用的以下字段：\n\n| 参数 | 类型 | 描述 |\n|------------|------|-------------|\n| `title` | `str` | API 的标题。 |\n| `summary` | `str` | API 的简短摘要。 <small>自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。</small> |\n| `description` | `str` | API 的简短描述。可以使用 Markdown。 |\n| `version` | `string` | API 的版本。这是您自己的应用程序的版本，而不是 OpenAPI 的版本。例如 `2.5.0`。 |\n| `terms_of_service` | `str` | API 服务条款的 URL。如果提供，则必须是 URL。 |\n| `contact` | `dict` | 公开的 API 的联系信息。它可以包含多个字段。<details><summary><code>contact</code> 字段</summary><table><thead><tr><th>参数</th><th>类型</th><th>描述</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>联系人/组织的识别名称。</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>指向联系信息的 URL。必须采用 URL 格式。</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>联系人/组织的电子邮件地址。必须采用电子邮件地址的格式。</td></tr></tbody></table></details> |\n| `license_info` | `dict` | 公开的 API 的许可证信息。它可以包含多个字段。<details><summary><code>license_info</code> 字段</summary><table><thead><tr><th>参数</th><th>类型</th><th>描述</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>必须</strong>（如果设置了 <code>license_info</code>）。用于 API 的许可证名称。</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>API 的 [SPDX](https://spdx.org/licenses/) 许可证表达式。字段 <code>identifier</code> 与字段 <code>url</code> 互斥。<small>自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>用于 API 的许可证的 URL。必须采用 URL 格式。</td></tr></tbody></table></details> |\n\n你可以按如下方式设置它们：\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | 提示\n\n你可以在 `description` 字段中编写 Markdown，它会在输出中渲染。\n\n///\n\n通过这样设置，自动 API 文档看起来会像：\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## 许可证标识符 { #license-identifier }\n\n自 OpenAPI 3.1.0 和 FastAPI 0.99.0 起，你还可以在 `license_info` 中使用 `identifier` 而不是 `url`。\n\n例如：\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## 标签元数据 { #metadata-for-tags }\n\n你也可以通过参数 `openapi_tags` 为用于分组路径操作的不同标签添加额外的元数据。\n\n它接收一个列表，列表中每个标签对应一个字典。\n\n每个字典可以包含：\n\n- `name`（必填）：一个 `str`，与在你的*路径操作*和 `APIRouter` 的 `tags` 参数中使用的标签名相同。\n- `description`：一个 `str`，该标签的简短描述。可以使用 Markdown，并会显示在文档 UI 中。\n- `externalDocs`：一个 `dict`，描述外部文档，包含：\n    - `description`：一个 `str`，该外部文档的简短描述。\n    - `url`（必填）：一个 `str`，该外部文档的 URL。\n\n### 创建标签元数据 { #create-metadata-for-tags }\n\n让我们在带有标签的示例中为 `users` 和 `items` 试一下。\n\n创建标签元数据并把它传递给 `openapi_tags` 参数：\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\n注意你可以在描述内使用 Markdown，例如「login」会显示为粗体（**login**）以及「fancy」会显示为斜体（_fancy_）。\n\n/// tip | 提示\n\n不必为你使用的所有标签都添加元数据。\n\n///\n\n### 使用你的标签 { #use-your-tags }\n\n将 `tags` 参数和*路径操作*（以及 `APIRouter`）一起使用，将其分配给不同的标签：\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info | 信息\n\n阅读更多关于标签的信息[路径操作配置](path-operation-configuration.md#tags)。\n\n///\n\n### 查看文档 { #check-the-docs }\n\n如果你现在查看文档，它们会显示所有附加的元数据：\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### 标签顺序 { #order-of-tags }\n\n每个标签元数据字典的顺序也定义了在文档用户界面显示的顺序。\n\n例如按照字母顺序，即使 `users` 排在 `items` 之后，它也会显示在前面，因为我们将它的元数据添加为列表内的第一个字典。\n\n## OpenAPI URL { #openapi-url }\n\n默认情况下，OpenAPI 模式服务于 `/openapi.json`。\n\n但是你可以通过参数 `openapi_url` 对其进行配置。\n\n例如，将其设置为服务于 `/api/v1/openapi.json`：\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\n如果你想完全禁用 OpenAPI 模式，可以将其设置为 `openapi_url=None`，这样也会禁用使用它的文档用户界面。\n\n## 文档 URLs { #docs-urls }\n\n你可以配置两个文档用户界面，包括：\n\n- **Swagger UI**：服务于 `/docs`。\n    - 可以使用参数 `docs_url` 设置它的 URL。\n    - 可以通过设置 `docs_url=None` 禁用它。\n- **ReDoc**：服务于 `/redoc`。\n    - 可以使用参数 `redoc_url` 设置它的 URL。\n    - 可以通过设置 `redoc_url=None` 禁用它。\n\n例如，设置 Swagger UI 服务于 `/documentation` 并禁用 ReDoc：\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/zh/docs/tutorial/middleware.md",
    "content": "# 中间件 { #middleware }\n\n你可以向 **FastAPI** 应用添加中间件。\n\n“中间件”是一个函数，它会在每个特定的*路径操作*处理每个**请求**之前运行，也会在返回每个**响应**之前运行。\n\n* 它接收你的应用的每一个**请求**。\n* 然后它可以对这个**请求**做一些事情或者执行任何需要的代码。\n* 然后它将这个**请求**传递给应用程序的其他部分（某个*路径操作*）处理。\n* 之后它获取应用程序生成的**响应**（由某个*路径操作*产生）。\n* 它可以对该**响应**做一些事情或者执行任何需要的代码。\n* 然后它返回这个**响应**。\n\n/// note | 技术细节\n\n如果你有使用 `yield` 的依赖，依赖中的退出代码会在中间件之后运行。\n\n如果有任何后台任务（会在[后台任务](background-tasks.md)一节中介绍，你稍后会看到），它们会在所有中间件之后运行。\n\n///\n\n## 创建中间件 { #create-a-middleware }\n\n要创建中间件，你可以在函数的顶部使用装饰器 `@app.middleware(\"http\")`。\n\n中间件函数会接收：\n\n* `request`。\n* 一个函数 `call_next`，它会把 `request` 作为参数接收。\n    * 这个函数会把 `request` 传递给相应的*路径操作*。\n    * 然后它返回由相应*路径操作*生成的 `response`。\n* 在返回之前，你可以进一步修改 `response`。\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip\n\n请记住可以[使用 `X-` 前缀](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)添加专有自定义请求头。\n\n但是如果你有希望让浏览器中的客户端可见的自定义请求头，你需要把它们加到你的 CORS 配置（[CORS（跨域资源共享）](cors.md)）的 `expose_headers` 参数中，参见 [Starlette 的 CORS 文档](https://www.starlette.dev/middleware/#corsmiddleware)。\n\n///\n\n/// note | 技术细节\n\n你也可以使用 `from starlette.requests import Request`。\n\n**FastAPI** 为了开发者方便提供了该对象，但它直接来自 Starlette。\n\n///\n\n### 在 `response` 之前与之后 { #before-and-after-the-response }\n\n你可以在任何*路径操作*接收 `request` 之前，添加要与该 `request` 一起运行的代码。\n\n也可以在生成 `response` 之后、返回之前添加代码。\n\n例如，你可以添加一个自定义请求头 `X-Process-Time`，其值为处理请求并生成响应所花费的秒数：\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip\n\n这里我们使用 [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) 而不是 `time.time()`，因为在这类场景中它可能更精确。🤓\n\n///\n\n## 多个中间件的执行顺序 { #multiple-middleware-execution-order }\n\n当你使用 `@app.middleware()` 装饰器或 `app.add_middleware()` 方法添加多个中间件时，每个新中间件都会包裹应用，形成一个栈。最后添加的中间件是“最外层”的，最先添加的是“最内层”的。\n\n在请求路径上，最外层的中间件先运行。\n\n在响应路径上，它最后运行。\n\n例如：\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\n这会产生如下执行顺序：\n\n* 请求：MiddlewareB → MiddlewareA → 路由\n\n* 响应：路由 → MiddlewareA → MiddlewareB\n\n这种栈式行为确保中间件按可预测且可控的顺序执行。\n\n## 其他中间件 { #other-middlewares }\n\n你可以稍后在[高级用户指南：高级中间件](../advanced/middleware.md)中阅读更多关于其他中间件的内容。\n\n你将在下一节中了解如何使用中间件处理 <abbr title=\"Cross-Origin Resource Sharing - 跨域资源共享\">CORS</abbr>。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/path-operation-configuration.md",
    "content": "# 路径操作配置 { #path-operation-configuration }\n\n*路径操作装饰器*支持多种配置参数。\n\n/// warning | 警告\n\n注意：以下参数应直接传递给*路径操作装饰器*，不能传递给*路径操作函数*。\n\n///\n\n## 响应状态码 { #response-status-code }\n\n可以在*路径操作*的响应中定义（HTTP）`status_code`。\n\n可以直接传递 `int` 代码，比如 `404`。\n\n如果记不住数字码的含义，也可以用 `status` 的快捷常量：\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\n该状态码会用于响应中，并会被添加到 OpenAPI 概图。\n\n/// note | 技术细节\n\n也可以使用 `from starlette import status` 导入状态码。\n\n**FastAPI** 提供的 `fastapi.status` 与 `starlette.status` 相同，方便你作为开发者使用。实际上它直接来自 Starlette。\n\n///\n\n## 标签 { #tags }\n\n可以通过传入由 `str` 组成的 `list`（通常只有一个 `str`）的参数 `tags`，为*路径操作*添加标签：\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\nOpenAPI 概图会自动添加标签，供 API 文档接口使用：\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### 使用 Enum 的标签 { #tags-with-enums }\n\n如果你的应用很大，可能会积累出很多标签，你会希望确保相关的*路径操作*始终使用相同的标签。\n\n这种情况下，把标签存放在 `Enum` 中会更合适。\n\n**FastAPI** 对此的支持与使用普通字符串相同：\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## 摘要和描述 { #summary-and-description }\n\n可以添加 `summary` 和 `description`：\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## 从 docstring 获取描述 { #description-from-docstring }\n\n描述内容比较长且占用多行时，可以在函数的 <dfn title=\"作为函数内部的第一个表达式（不赋给任何变量）的多行字符串，用于文档用途\">docstring</dfn> 中声明*路径操作*的描述，**FastAPI** 会从中读取。\n\n文档字符串支持 [Markdown](https://en.wikipedia.org/wiki/Markdown)，能正确解析和显示 Markdown 的内容，但要注意文档字符串的缩进。\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\n它会在交互式文档中使用：\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## 响应描述 { #response-description }\n\n`response_description` 参数用于定义响应的描述说明：\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info | 信息\n\n注意，`response_description` 只用于描述响应，`description` 一般则用于描述*路径操作*。\n\n///\n\n/// check | 检查\n\nOpenAPI 规定每个*路径操作*都要有响应描述。\n\n如果没有定义响应描述，**FastAPI** 则自动生成内容为 \"Successful response\" 的响应描述。\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## 弃用*路径操作* { #deprecate-a-path-operation }\n\n如果需要把*路径操作*标记为<dfn title=\"过时，建议不要使用\">弃用</dfn>，但不删除它，可以传入 `deprecated` 参数：\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\nAPI 文档会把该路径操作标记为弃用：\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\n下图显示了正常*路径操作*与弃用*路径操作* 的区别：\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## 小结 { #recap }\n\n通过传递参数给*路径操作装饰器*，即可轻松地配置*路径操作*、添加元数据。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/path-params-numeric-validations.md",
    "content": "# 路径参数和数值校验 { #path-parameters-and-numeric-validations }\n\n与使用 `Query` 为查询参数声明更多的校验和元数据的方式相同，你也可以使用 `Path` 为路径参数声明相同类型的校验和元数据。\n\n## 导入 `Path` { #import-path }\n\n首先，从 `fastapi` 导入 `Path`，并导入 `Annotated`：\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info | 信息\n\nFastAPI 在 0.95.0 版本添加了对 `Annotated` 的支持（并开始推荐使用它）。\n\n如果你使用的是更旧的版本，尝试使用 `Annotated` 会报错。\n\n请确保在使用 `Annotated` 之前，将 FastAPI 版本[升级](../deployment/versions.md#upgrading-the-fastapi-versions)到至少 0.95.1。\n\n///\n\n## 声明元数据 { #declare-metadata }\n\n你可以声明与 `Query` 相同的所有参数。\n\n例如，要为路径参数 `item_id` 声明 `title` 元数据值，你可以这样写：\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note | 注意\n\n路径参数总是必需的，因为它必须是路径的一部分。即使你将其声明为 `None` 或设置了默认值，也不会产生任何影响，它依然始终是必需参数。\n\n///\n\n## 按需对参数排序 { #order-the-parameters-as-you-need }\n\n/// tip | 提示\n\n如果你使用 `Annotated`，这点可能不那么重要或必要。\n\n///\n\n假设你想要将查询参数 `q` 声明为必需的 `str`。\n\n并且你不需要为该参数声明其他内容，所以实际上不需要用到 `Query`。\n\n但是你仍然需要为路径参数 `item_id` 使用 `Path`。并且出于某些原因你不想使用 `Annotated`。\n\n如果你将带有“默认值”的参数放在没有“默认值”的参数之前，Python 会报错。\n\n不过你可以重新排序，让没有默认值的参数（查询参数 `q`）放在最前面。\n\n对 **FastAPI** 来说这无关紧要。它会通过参数的名称、类型和默认值声明（`Query`、`Path` 等）来检测参数，而不关心顺序。\n\n因此，你可以将函数声明为：\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\n但请记住，如果你使用 `Annotated`，你就不会遇到这个问题，因为你没有使用 `Query()` 或 `Path()` 作为函数参数的默认值。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## 按需对参数排序的技巧 { #order-the-parameters-as-you-need-tricks }\n\n/// tip | 提示\n\n如果你使用 `Annotated`，这点可能不那么重要或必要。\n\n///\n\n这里有一个小技巧，可能会很方便，但你并不会经常需要它。\n\n如果你想要：\n\n* 在没有 `Query` 且没有任何默认值的情况下声明查询参数 `q`\n* 使用 `Path` 声明路径参数 `item_id`\n* 让它们的顺序与上面不同\n* 不使用 `Annotated`\n\n...Python 为此有一个小的特殊语法。\n\n在函数的第一个参数位置传入 `*`。\n\nPython 不会对这个 `*` 做任何事，但它会知道之后的所有参数都应该作为关键字参数（键值对）来调用，也被称为 <abbr title=\"来自：K-ey W-ord Arg-uments\"><code>kwargs</code></abbr>。即使它们没有默认值。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### 使用 `Annotated` 更好 { #better-with-annotated }\n\n请记住，如果你使用 `Annotated`，因为你没有使用函数参数的默认值，所以你不会有这个问题，你大概率也不需要使用 `*`。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## 数值校验：大于等于 { #number-validations-greater-than-or-equal }\n\n使用 `Query` 和 `Path`（以及你稍后会看到的其他类）你可以声明数值约束。\n\n在这里，使用 `ge=1` 后，`item_id` 必须是一个整数，值要「`g`reater than or `e`qual」1。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## 数值校验：大于和小于等于 { #number-validations-greater-than-and-less-than-or-equal }\n\n同样适用于：\n\n* `gt`：大于（`g`reater `t`han）\n* `le`：小于等于（`l`ess than or `e`qual）\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## 数值校验：浮点数、大于和小于 { #number-validations-floats-greater-than-and-less-than }\n\n数值校验同样适用于 `float` 值。\n\n能够声明 <abbr title=\"greater than - 大于\"><code>gt</code></abbr> 而不仅仅是 <abbr title=\"greater than or equal - 大于等于\"><code>ge</code></abbr> 在这里变得很重要。例如，你可以要求一个值必须大于 `0`，即使它小于 `1`。\n\n因此，`0.5` 将是有效值。但是 `0.0` 或 `0` 不是。\n\n对于 <abbr title=\"less than - 小于\"><code>lt</code></abbr> 也是一样的。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## 总结 { #recap }\n\n你能够以与[查询参数和字符串校验](query-params-str-validations.md)相同的方式使用 `Query`、`Path`（以及其他你还没见过的类）声明元数据和字符串校验。\n\n而且你还可以声明数值校验：\n\n* `gt`：大于（`g`reater `t`han）\n* `ge`：大于等于（`g`reater than or `e`qual）\n* `lt`：小于（`l`ess `t`han）\n* `le`：小于等于（`l`ess than or `e`qual）\n\n/// info | 信息\n\n`Query`、`Path` 以及你后面会看到的其他类，都是一个通用 `Param` 类的子类。\n\n它们都共享相同的参数，用于你已看到的额外校验和元数据。\n\n///\n\n/// note | 注意\n\n当你从 `fastapi` 导入 `Query`、`Path` 和其他对象时，它们实际上是函数。\n\n当被调用时，它们会返回同名类的实例。\n\n也就是说，你导入的是函数 `Query`。当你调用它时，它会返回一个同名的 `Query` 类的实例。\n\n之所以使用这些函数（而不是直接使用类），是为了让你的编辑器不要因为它们的类型而标记错误。\n\n这样你就可以使用常规的编辑器和编码工具，而不必添加自定义配置来忽略这些错误。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/tutorial/path-params.md",
    "content": "# 路径参数 { #path-parameters }\n\n你可以使用与 Python 字符串格式化相同的语法声明路径“参数”或“变量”：\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\n路径参数 `item_id` 的值会作为参数 `item_id` 传递给你的函数。\n\n运行示例并访问 [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo)，可获得如下响应：\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## 声明路径参数的类型 { #path-parameters-with-types }\n\n使用 Python 标准类型注解，声明路径操作函数中路径参数的类型：\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\n本例把 `item_id` 的类型声明为 `int`。\n\n/// check | 检查\n\n类型声明将为函数提供错误检查、代码补全等编辑器支持。\n\n///\n\n## 数据<dfn title=\"也称为：序列化、解析、编组\">转换</dfn> { #data-conversion }\n\n运行示例并访问 [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3)，返回的响应如下：\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check | 检查\n\n注意，函数接收并返回的值是 `3`（ `int`），不是 `\"3\"`（`str`）。\n\n**FastAPI** 通过类型声明自动进行请求的<dfn title=\"将来自 HTTP 请求中的字符串转换为 Python 数据类型\">解析</dfn>。\n\n///\n\n## 数据校验 { #data-validation }\n\n通过浏览器访问 [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo)，接收如下 HTTP 错误信息：\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\n这是因为路径参数 `item_id` 的值（`\"foo\"`）的类型不是 `int`。\n\n值的类型不是 `int` 而是浮点数（`float`）时也会显示同样的错误，比如： [http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)\n\n/// check | 检查\n\n**FastAPI** 使用同样的 Python 类型声明实现了数据校验。\n\n注意，上面的错误清晰地指出了未通过校验的具体位置。\n\n这在开发调试与 API 交互的代码时非常有用。\n\n///\n\n## 文档 { #documentation }\n\n访问 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)，查看自动生成的交互式 API 文档：\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check | 检查\n\n还是使用 Python 类型声明，**FastAPI** 提供了（集成 Swagger UI 的）自动交互式文档。\n\n注意，路径参数的类型是整数。\n\n///\n\n## 基于标准的好处，备选文档 { #standards-based-benefits-alternative-documentation }\n\n**FastAPI** 使用 [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md) 生成概图，所以能兼容很多工具。\n\n因此，**FastAPI** 还内置了 ReDoc 生成的备选 API 文档，可在此查看 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)：\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\n同样，还有很多兼容工具，包括多种语言的代码生成工具。\n\n## Pydantic { #pydantic }\n\nFastAPI 充分地利用了 [Pydantic](https://docs.pydantic.dev/) 的优势，用它在后台校验数据。众所周知，Pydantic 擅长的就是数据校验。\n\n同样，`str`、`float`、`bool` 以及很多复合数据类型都可以使用类型声明。\n\n接下来的章节会介绍其中的好几种。\n\n## 顺序很重要 { #order-matters }\n\n有时，*路径操作*中的路径是写死的。\n\n比如要使用 `/users/me` 获取当前用户的数据。\n\n然后还要使用 `/users/{user_id}`，通过用户 ID 获取指定用户的数据。\n\n由于*路径操作*是按顺序依次运行的，因此，一定要在 `/users/{user_id}` 之前声明 `/users/me` ：\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\n否则，`/users/{user_id}` 将匹配 `/users/me`，FastAPI 会**认为**正在接收值为 `\"me\"` 的 `user_id` 参数。\n\n同样，你不能重复定义一个路径操作：\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\n由于路径首先匹配，始终会使用第一个定义的。\n\n## 预设值 { #predefined-values }\n\n路径操作使用 Python 的 <abbr title=\"Enumeration - 枚举\">`Enum`</abbr> 类型接收预设的路径参数。\n\n### 创建 `Enum` 类 { #create-an-enum-class }\n\n导入 `Enum` 并创建继承自 `str` 和 `Enum` 的子类。\n\n通过从 `str` 继承，API 文档就能把值的类型定义为**字符串**，并且能正确渲染。\n\n然后，创建包含固定值的类属性，这些固定值是可用的有效值：\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip | 提示\n\n**AlexNet**、**ResNet**、**LeNet** 是机器学习<dfn title=\"技术上来说是深度学习模型架构\">模型</dfn>的名字。\n\n///\n\n### 声明路径参数 { #declare-a-path-parameter }\n\n使用 Enum 类（`ModelName`）创建使用类型注解的路径参数：\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### 查看文档 { #check-the-docs }\n\nAPI 文档会显示预定义路径参数的可用值：\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### 使用 Python 枚举 { #working-with-python-enumerations }\n\n路径参数的值是一个枚举成员。\n\n#### 比较枚举成员 { #compare-enumeration-members }\n\n可以将其与枚举类 `ModelName` 中的枚举成员进行比较：\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### 获取枚举值 { #get-the-enumeration-value }\n\n使用 `model_name.value` 或通用的 `your_enum_member.value` 获取实际的值（本例中为 `str`）：\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip | 提示\n\n使用 `ModelName.lenet.value` 也能获取值 `\"lenet\"`。\n\n///\n\n#### 返回枚举成员 { #return-enumeration-members }\n\n即使嵌套在 JSON 请求体里（例如，`dict`），也可以从路径操作返回枚举成员。\n\n返回给客户端之前，会把枚举成员转换为对应的值（本例中为字符串）：\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\n客户端中的 JSON 响应如下：\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## 包含路径的路径参数 { #path-parameters-containing-paths }\n\n假设路径操作的路径为 `/files/{file_path}`。\n\n但需要 `file_path` 中也包含路径，比如，`home/johndoe/myfile.txt`。\n\n此时，该文件的 URL 是这样的：`/files/home/johndoe/myfile.txt`。\n\n### OpenAPI 支持 { #openapi-support }\n\nOpenAPI 不支持声明包含路径的路径参数，因为这会导致测试和定义更加困难。\n\n不过，仍可使用 Starlette 内置工具在 **FastAPI** 中实现这一功能。\n\n而且不影响文档正常运行，但是不会添加该参数包含路径的说明。\n\n### 路径转换器 { #path-convertor }\n\n直接使用 Starlette 的选项声明包含路径的路径参数：\n\n```\n/files/{file_path:path}\n```\n\n本例中，参数名为 `file_path`，结尾部分的 `:path` 说明该参数应匹配路径。\n\n用法如下：\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip | 提示\n\n注意，包含 `/home/johndoe/myfile.txt` 的路径参数要以斜杠（`/`）开头。\n\n本例中的 URL 是 `/files//home/johndoe/myfile.txt`。注意，`files` 和 `home` 之间要使用双斜杠（`//`）。\n\n///\n\n## 小结 { #recap }\n\n通过简短、直观的 Python 标准类型声明，**FastAPI** 可以获得：\n\n- 编辑器支持：错误检查，代码自动补全等\n- 数据 \"<dfn title=\"将来自 HTTP 请求中的字符串转换为 Python 数据类型\">解析</dfn>\"\n- 数据校验\n- API 注解和自动文档\n\n只需要声明一次即可。\n\n这可能是除了性能以外，**FastAPI** 与其它框架相比的主要优势。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/query-param-models.md",
    "content": "# 查询参数模型 { #query-parameter-models }\n\n如果你有一组具有相关性的**查询参数**，你可以创建一个 **Pydantic 模型**来声明它们。\n\n这将允许你在**多个地方**去**复用模型**，并且一次性为所有参数声明验证和元数据。😎\n\n/// note | 注意\n\nFastAPI 从 `0.115.0` 版本开始支持这个特性。🤓\n\n///\n\n## 使用 Pydantic 模型的查询参数 { #query-parameters-with-a-pydantic-model }\n\n在一个 **Pydantic 模型**中声明你需要的**查询参数**，然后将参数声明为 `Query`：\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\n**FastAPI** 将会从请求的**查询参数**中**提取**出**每个字段**的数据，并将其提供给你定义的 Pydantic 模型。\n\n## 查看文档 { #check-the-docs }\n\n你可以在 `/docs` 页面的 UI 中查看查询参数：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## 禁止额外的查询参数 { #forbid-extra-query-parameters }\n\n在一些特殊的使用场景中（可能不是很常见），你可能希望**限制**你要接收的查询参数。\n\n你可以使用 Pydantic 的模型配置来 `forbid` 任何 `extra` 字段：\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\n假设有一个客户端尝试在**查询参数**中发送一些**额外的**数据，它将会收到一个**错误**响应。\n\n例如，如果客户端尝试发送一个值为 `plumbus` 的 `tool` 查询参数，如：\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\n他们将收到一个**错误**响应，告诉他们查询参数 `tool` 是不允许的：\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## 总结 { #summary }\n\n你可以使用 **Pydantic 模型**在 **FastAPI** 中声明**查询参数**。😎\n\n/// tip | 提示\n\n剧透警告：你也可以使用 Pydantic 模型来声明 cookie 和 headers，但你将在本教程的后面部分阅读到这部分内容。🤫\n\n///\n"
  },
  {
    "path": "docs/zh/docs/tutorial/query-params-str-validations.md",
    "content": "# 查询参数和字符串校验 { #query-parameters-and-string-validations }\n\n**FastAPI** 允许你为参数声明额外的信息和校验。\n\n让我们以下面的应用为例：\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\n查询参数 `q` 的类型为 `str | None`，这意味着它是 `str` 类型，但也可以是 `None`。其默认值确实为 `None`，所以 FastAPI 会知道它不是必填的。\n\n/// note | 注意\n\nFastAPI 会因为默认值 `= None` 而知道 `q` 的值不是必填的。\n\n将类型标注为 `str | None` 能让你的编辑器提供更好的辅助和错误检测。\n\n///\n\n## 额外校验 { #additional-validation }\n\n我们打算添加约束：即使 `q` 是可选的，但只要提供了该参数，**其长度不能超过 50 个字符**。\n\n### 导入 `Query` 和 `Annotated` { #import-query-and-annotated }\n\n为此，先导入：\n\n- 从 `fastapi` 导入 `Query`\n- 从 `typing` 导入 `Annotated`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info | 信息\n\nFastAPI 在 0.95.0 版本中添加了对 `Annotated` 的支持（并开始推荐使用）。\n\n如果你的版本更旧，使用 `Annotated` 会报错。\n\n在使用 `Annotated` 之前，请确保先[升级 FastAPI 版本](../deployment/versions.md#upgrading-the-fastapi-versions)到至少 0.95.1。\n\n///\n\n## 在 `q` 参数的类型中使用 `Annotated` { #use-annotated-in-the-type-for-the-q-parameter }\n\n还记得我之前在[Python 类型简介](../python-types.md#type-hints-with-metadata-annotations)中说过可以用 `Annotated` 给参数添加元数据吗？\n\n现在正是与 FastAPI 搭配使用它的时候。🚀\n\n我们之前的类型标注是：\n\n```Python\nq: str | None = None\n```\n\n我们要做的是用 `Annotated` 把它包起来，变成：\n\n```Python\nq: Annotated[str | None] = None\n```\n\n这两种写法含义相同，`q` 是一个可以是 `str` 或 `None` 的参数，默认是 `None`。\n\n现在进入更有趣的部分。🎉\n\n## 在 `q` 的 `Annotated` 中添加 `Query` { #add-query-to-annotated-in-the-q-parameter }\n\n有了 `Annotated` 之后，我们就可以放入更多信息（本例中是额外的校验）。在 `Annotated` 中添加 `Query`，并把参数 `max_length` 设为 `50`：\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\n注意默认值依然是 `None`，所以该参数仍是可选的。\n\n但现在把 `Query(max_length=50)` 放到 `Annotated` 里，我们就在告诉 FastAPI，这个值需要**额外校验**，最大长度为 50 个字符。😎\n\n/// tip | 提示\n\n这里用的是 `Query()`，因为这是一个**查询参数**。稍后我们还会看到 `Path()`、`Body()`、`Header()` 和 `Cookie()`，它们也接受与 `Query()` 相同的参数。\n\n///\n\nFastAPI 现在会：\n\n- 对数据进行**校验**，确保最大长度为 50 个字符\n- 当数据无效时向客户端展示**清晰的错误**\n- 在 OpenAPI 模式的*路径操作*中**记录**该参数（因此会出现在**自动文档 UI** 中）\n\n## 另一种（旧的）方式：把 `Query` 作为默认值 { #alternative-old-query-as-the-default-value }\n\n早期版本的 FastAPI（<dfn title=\"早于 2023-03\">0.95.0</dfn> 之前）要求你把 `Query` 作为参数的默认值，而不是放在 `Annotated` 里。你很可能会在别处看到这种写法，所以我也给你解释一下。\n\n/// tip | 提示\n\n对于新代码以及在可能的情况下，请按上文所述使用 `Annotated`。它有多项优势（如下所述），没有劣势。🍰\n\n///\n\n像这样把 `Query()` 作为函数参数的默认值，并把参数 `max_length` 设为 50：\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\n由于这种情况下（不使用 `Annotated`）我们必须把函数中的默认值 `None` 替换为 `Query()`，因此需要通过参数 `Query(default=None)` 来设置默认值，它起到同样的作用（至少对 FastAPI 来说）。\n\n所以：\n\n```Python\nq: str | None = Query(default=None)\n```\n\n...会让参数变成可选，默认值为 `None`，等同于：\n\n```Python\nq: str | None = None\n```\n\n但使用 `Query` 的版本会显式把它声明为一个查询参数。\n\n然后，我们可以向 `Query` 传入更多参数。本例中是适用于字符串的 `max_length` 参数：\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\n这会校验数据、在数据无效时展示清晰的错误，并在 OpenAPI 模式的*路径操作*中记录该参数。\n\n### 在默认值中使用 `Query` 或在 `Annotated` 中使用 `Query` { #query-as-the-default-value-or-in-annotated }\n\n注意，当你在 `Annotated` 中使用 `Query` 时，不能再给 `Query` 传 `default` 参数。\n\n相反，应使用函数参数本身的实际默认值。否则会不一致。\n\n例如，下面这样是不允许的：\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n...因为不清楚默认值应该是 `\"rick\"` 还是 `\"morty\"`。\n\n因此，你应该这样用（推荐）：\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n...或者在旧代码库中你会见到：\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### `Annotated` 的优势 { #advantages-of-annotated }\n\n**推荐使用 `Annotated`**，而不是把 `Query` 放在函数参数的默认值里，这样做在多方面都**更好**。🤓\n\n函数参数的**默认值**就是**真正的默认值**，这与 Python 的直觉更一致。😌\n\n你可以在**其他地方**不通过 FastAPI **直接调用**这个函数，而且它会**按预期工作**。如果有**必填**参数（没有默认值），你的**编辑器**会报错提示；如果在运行时没有传入必填参数，**Python** 也会报错。\n\n当你不使用 `Annotated` 而是使用**（旧的）默认值风格**时，如果你在**其他地方**不通过 FastAPI 调用该函数，你必须**记得**给函数传参，否则得到的值会和预期不同（例如得到 `QueryInfo` 之类的对象而不是 `str`）。而你的编辑器不会报错，Python 也不会在调用时报错，只有在函数内部的操作出错时才会暴露问题。\n\n由于 `Annotated` 可以包含多个元数据标注，你甚至可以用同一个函数与其他工具配合，例如 [Typer](https://typer.tiangolo.com/)。🚀\n\n## 添加更多校验 { #add-more-validations }\n\n你还可以添加 `min_length` 参数：\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## 添加正则表达式 { #add-regular-expressions }\n\n你可以定义一个参数必须匹配的 <dfn title=\"正则表达式（regex 或 regexp）是用于定义字符串搜索模式的字符序列。\">正则表达式</dfn> `pattern`：\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\n这个特定的正则表达式通过以下规则检查接收到的参数值：\n\n- `^`：必须以接下来的字符开头，前面没有其他字符。\n- `fixedquery`：值必须精确等于 `fixedquery`。\n- `$`：到此结束，在 `fixedquery` 之后没有更多字符。\n\n如果你对这些**「正则表达式」**概念感到迷茫，不必担心。对很多人来说这都是个难点。你仍然可以在不使用正则表达式的情况下做很多事情。\n\n现在你知道了，一旦需要时，你可以在 **FastAPI** 中直接使用它们。\n\n## 默认值 { #default-values }\n\n当然，你也可以使用 `None` 以外的默认值。\n\n假设你想要声明查询参数 `q` 的 `min_length` 为 `3`，并且默认值为 `\"fixedquery\"`：\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | 注意\n\n任何类型的默认值（包括 `None`）都会让该参数变为可选（非必填）。\n\n///\n\n## 必填参数 { #required-parameters }\n\n当我们不需要声明更多校验或元数据时，只需不声明默认值就可以让查询参数 `q` 成为必填参数，例如：\n\n```Python\nq: str\n```\n\n而不是：\n\n```Python\nq: str | None = None\n```\n\n但现在我们用 `Query` 来声明它，例如：\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\n因此，在使用 `Query` 的同时需要把某个值声明为必填时，只需不声明默认值：\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### 必填，但可以为 `None` { #required-can-be-none }\n\n你可以声明一个参数可以接收 `None`，但它仍然是必填的。这将强制客户端必须发送一个值，即使该值是 `None`。\n\n为此，你可以声明 `None` 是有效类型，但不声明默认值：\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## 查询参数列表 / 多个值 { #query-parameter-list-multiple-values }\n\n当你用 `Query` 显式地定义查询参数时，你还可以声明它接收一个值列表，换句话说，接收多个值。\n\n例如，要声明一个可在 URL 中出现多次的查询参数 `q`，你可以这样写：\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\n然后，访问如下 URL：\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\n你会在*路径操作函数*的*函数参数* `q` 中以一个 Python `list` 的形式接收到多个 `q` *查询参数* 的值（`foo` 和 `bar`）。\n\n因此，该 URL 的响应将会是：\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | 提示\n\n要声明类型为 `list` 的查询参数（如上例），你需要显式地使用 `Query`，否则它会被解释为请求体。\n\n///\n\n交互式 API 文档会相应更新，以支持多个值：\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### 具有默认值的查询参数列表 / 多个值 { #query-parameter-list-multiple-values-with-defaults }\n\n你还可以定义在没有给定值时的默认 `list`：\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\n如果你访问：\n\n```\nhttp://localhost:8000/items/\n```\n\n`q` 的默认值将为：`[\"foo\", \"bar\"]`，你的响应会是：\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### 只使用 `list` { #using-just-list }\n\n你也可以直接使用 `list`，而不是 `list[str]`：\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | 注意\n\n请记住，在这种情况下 FastAPI 不会检查列表的内容。\n\n例如，`list[int]` 会检查（并记录到文档）列表的内容必须是整数。但仅用 `list` 不会。\n\n///\n\n## 声明更多元数据 { #declare-more-metadata }\n\n你可以添加更多有关该参数的信息。\n\n这些信息会包含在生成的 OpenAPI 中，并被文档用户界面和外部工具使用。\n\n/// note | 注意\n\n请记住，不同的工具对 OpenAPI 的支持程度可能不同。\n\n其中一些可能还不会展示所有已声明的额外信息，尽管在大多数情况下，缺失的功能已经在计划开发中。\n\n///\n\n你可以添加 `title`：\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\n以及 `description`：\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## 别名参数 { #alias-parameters }\n\n假设你想要参数名为 `item-query`。\n\n像这样：\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\n但 `item-query` 不是有效的 Python 变量名。\n\n最接近的有效名称是 `item_query`。\n\n但你仍然需要它在 URL 中就是 `item-query`...\n\n这时可以用 `alias` 参数声明一个别名，FastAPI 会用该别名在 URL 中查找参数值：\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## 弃用参数 { #deprecating-parameters }\n\n现在假设你不再喜欢这个参数了。\n\n由于还有客户端在使用它，你不得不保留一段时间，但你希望文档清楚地将其展示为<dfn title=\"已过时，不推荐使用\">已弃用</dfn>。\n\n那么将参数 `deprecated=True` 传给 `Query`：\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\n文档将会像下面这样展示它：\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## 从 OpenAPI 中排除参数 { #exclude-parameters-from-openapi }\n\n要把某个查询参数从生成的 OpenAPI 模式中排除（从而也不会出现在自动文档系统中），将 `Query` 的参数 `include_in_schema` 设为 `False`：\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## 自定义校验 { #custom-validation }\n\n有些情况下你需要做一些无法通过上述参数完成的**自定义校验**。\n\n在这些情况下，你可以使用**自定义校验函数**，该函数会在正常校验之后应用（例如，在先校验值是 `str` 之后）。\n\n你可以在 `Annotated` 中使用 [Pydantic 的 `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) 来实现。\n\n/// tip | 提示\n\nPydantic 还有 [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) 等。🤓\n\n///\n\n例如，这个自定义校验器会检查条目 ID 是否以 `isbn-`（用于 <abbr title=\"International Standard Book Number - 国际标准书号\">ISBN</abbr> 书号）或 `imdb-`（用于 <abbr title=\"Internet Movie Database - 互联网电影数据库: 一个包含电影信息的网站\">IMDB</abbr> 电影 URL 的 ID）开头：\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info | 信息\n\n这在 Pydantic 2 或更高版本中可用。😎\n\n///\n\n/// tip | 提示\n\n如果你需要进行任何需要与**外部组件**通信的校验，例如数据库或其他 API，你应该改用 **FastAPI 依赖项**，稍后你会学到它们。\n\n这些自定义校验器用于只需检查请求中**同一份数据**即可完成的事情。\n\n///\n\n### 理解这段代码 { #understand-that-code }\n\n关键点仅仅是：在 `Annotated` 中使用带函数的 **`AfterValidator`**。不感兴趣可以跳过这一节。🤸\n\n---\n\n但如果你对这个具体示例好奇，并且还愿意继续看，这里有一些额外细节。\n\n#### 字符串与 `value.startswith()` { #string-with-value-startswith }\n\n注意到了吗？字符串的 `value.startswith()` 可以接收一个元组，它会检查元组中的每个值：\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### 一个随机条目 { #a-random-item }\n\n使用 `data.items()` 我们会得到一个包含每个字典项键和值的元组的 <dfn title=\"可以用 for 循环迭代的对象，例如 list、set 等\">可迭代对象</dfn>。\n\n我们用 `list(data.items())` 把这个可迭代对象转换成一个真正的 `list`。\n\n然后用 `random.choice()` 可以从该列表中获取一个**随机值**，也就是一个 `(id, name)` 的元组。它可能像 `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")` 这样。\n\n接着我们把这个元组的**两个值**分别赋给变量 `id` 和 `name`。\n\n所以，即使用户没有提供条目 ID，他们仍然会收到一个随机推荐。\n\n...而我们把这些都放在**一行简单的代码**里完成。🤯 你不爱 Python 吗？🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## 总结 { #recap }\n\n你可以为参数声明额外的校验和元数据。\n\n通用的校验和元数据：\n\n- `alias`\n- `title`\n- `description`\n- `deprecated`\n\n字符串特有的校验：\n\n- `min_length`\n- `max_length`\n- `pattern`\n\n也可以使用 `AfterValidator` 进行自定义校验。\n\n在这些示例中，你看到了如何为 `str` 值声明校验。\n\n参阅下一章节，了解如何为其他类型（例如数值）声明校验。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/query-params.md",
    "content": "# 查询参数 { #query-parameters }\n\n声明的参数不是路径参数时，路径操作函数会把该参数自动解释为“查询”参数。\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\n查询字符串是键值对的集合，这些键值对位于 URL 的 `?` 之后，以 `&` 分隔。\n\n例如，以下 URL 中：\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n...查询参数为：\n\n* `skip`：值为 `0`\n* `limit`：值为 `10`\n\n这些值都是 URL 的组成部分，因此，它们的类型“本应”是字符串。\n\n但声明 Python 类型（上例中为 `int`）之后，这些值就会转换为声明的类型，并进行类型校验。\n\n所有应用于路径参数的流程也适用于查询参数：\n\n* （显而易见的）编辑器支持\n* 数据<dfn title=\"将来自 HTTP 请求的字符串转换为 Python 数据\">\"解析\"</dfn>\n* 数据校验\n* 自动文档\n\n## 默认值 { #defaults }\n\n查询参数不是路径的固定内容，它是可选的，还支持默认值。\n\n上例用 `skip=0` 和 `limit=10` 设定默认值。\n\n访问 URL：\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\n与访问以下地址相同：\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n但如果访问：\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\n查询参数的值就是：\n\n* `skip=20`：在 URL 中设定的值\n* `limit=10`：使用默认值\n\n## 可选参数 { #optional-parameters }\n\n同理，把默认值设为 `None` 即可声明可选的查询参数：\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\n本例中，查询参数 `q` 是可选的，默认值为 `None`。\n\n/// check | 检查\n\n注意，**FastAPI** 可以识别出 `item_id` 是路径参数，`q` 不是路径参数，而是查询参数。\n\n///\n\n## 查询参数类型转换 { #query-parameter-type-conversion }\n\n参数还可以声明为 `bool` 类型，FastAPI 会自动转换参数类型：\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\n本例中，访问：\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\n或\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\n或\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\n或\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\n或\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\n或其它任意大小写形式（大写、首字母大写等），函数接收的 `short` 参数都是布尔值 `True`。否则为 `False`。\n\n\n## 多个路径和查询参数 { #multiple-path-and-query-parameters }\n\n**FastAPI** 可以识别同时声明的多个路径参数和查询参数。\n\n而且声明查询参数的顺序并不重要。\n\nFastAPI 通过参数名进行检测：\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## 必选查询参数 { #required-query-parameters }\n\n为不是路径参数的参数声明默认值（至此，仅有查询参数），该参数就不是必选的了。\n\n如果只想把参数设为可选，但又不想指定参数的值，则要把默认值设为 `None`。\n\n如果要把查询参数设置为必选，就不要声明默认值：\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\n这里的查询参数 `needy` 是类型为 `str` 的必选查询参数。\n\n在浏览器中打开如下 URL：\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n...因为路径中没有必选参数 `needy`，返回的响应中会显示如下错误信息：\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\n`needy` 是必选参数，因此要在 URL 中设置值：\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n...这样就正常了：\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\n当然，把一些参数定义为必选，为另一些参数设置默认值，再把其它参数定义为可选，这些操作都是可以的：\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\n本例中有 3 个查询参数：\n\n* `needy`，必选的 `str` 类型参数\n* `skip`，默认值为 `0` 的 `int` 类型参数\n* `limit`，可选的 `int` 类型参数\n\n/// tip | 提示\n\n还可以像在[路径参数](path-params.md#predefined-values)中那样使用 `Enum`。\n\n///\n"
  },
  {
    "path": "docs/zh/docs/tutorial/request-files.md",
    "content": "# 请求文件 { #request-files }\n\n你可以使用 `File` 定义由客户端上传的文件。\n\n/// info | 信息\n\n要接收上传的文件，请先安装 [`python-multipart`](https://github.com/Kludex/python-multipart)。\n\n请确保你创建一个[虚拟环境](../virtual-environments.md)、激活它，然后安装，例如：\n\n```console\n$ pip install python-multipart\n```\n\n这是因为上传文件是以「表单数据」发送的。\n\n///\n\n## 导入 `File` { #import-file }\n\n从 `fastapi` 导入 `File` 和 `UploadFile`：\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## 定义 `File` 参数 { #define-file-parameters }\n\n像为 `Body` 或 `Form` 一样创建文件参数：\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info | 信息\n\n`File` 是直接继承自 `Form` 的类。\n\n但要注意，从 `fastapi` 导入的 `Query`、`Path`、`File` 等项，实际上是返回特定类的函数。\n\n///\n\n/// tip | 提示\n\n声明文件体必须使用 `File`，否则，这些参数会被当作查询参数或请求体（JSON）参数。\n\n///\n\n文件将作为「表单数据」上传。\n\n如果把*路径操作函数*参数的类型声明为 `bytes`，**FastAPI** 会为你读取文件，并以 `bytes` 的形式接收其内容。\n\n请注意，这意味着整个内容会存储在内存中，适用于小型文件。\n\n不过，在很多情况下，使用 `UploadFile` 会更有优势。\n\n## 含 `UploadFile` 的文件参数 { #file-parameters-with-uploadfile }\n\n将文件参数的类型声明为 `UploadFile`：\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\n与 `bytes` 相比，使用 `UploadFile` 有多项优势：\n\n* 无需在参数的默认值中使用 `File()`。\n* 它使用“spooled”文件：\n    * 文件会先存储在内存中，直到达到最大上限，超过该上限后会写入磁盘。\n* 因此，非常适合处理图像、视频、大型二进制等大文件，而不会占用所有内存。\n* 你可以获取上传文件的元数据。\n* 它提供 [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) 的 `async` 接口。\n* 它暴露了一个实际的 Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) 对象，你可以直接传给期望「file-like」对象的其他库。\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` 的属性如下：\n\n* `filename`：上传的原始文件名字符串（`str`），例如 `myimage.jpg`。\n* `content_type`：内容类型（MIME 类型 / 媒体类型）的字符串（`str`），例如 `image/jpeg`。\n* `file`：[`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile)（一个 [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) 对象）。这是实际的 Python 文件对象，你可以直接传递给其他期望「file-like」对象的函数或库。\n\n`UploadFile` 具有以下 `async` 方法。它们都会在底层调用对应的文件方法（使用内部的 `SpooledTemporaryFile`）。\n\n* `write(data)`：将 `data` (`str` 或 `bytes`) 写入文件。\n* `read(size)`：读取文件中 `size` (`int`) 个字节/字符。\n* `seek(offset)`：移动到文件中字节位置 `offset` (`int`)。\n    * 例如，`await myfile.seek(0)` 会移动到文件开头。\n    * 如果你先运行过 `await myfile.read()`，然后需要再次读取内容时，这尤其有用。\n* `close()`：关闭文件。\n\n由于这些方法都是 `async` 方法，你需要对它们使用 await。\n\n例如，在 `async` *路径操作函数* 内，你可以这样获取内容：\n\n```Python\ncontents = await myfile.read()\n```\n\n如果是在普通 `def` *路径操作函数* 内，你可以直接访问 `UploadFile.file`，例如：\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | `async` 技术细节\n\n当你使用这些 `async` 方法时，**FastAPI** 会在线程池中运行相应的文件方法并等待其完成。\n\n///\n\n/// note | Starlette 技术细节\n\n**FastAPI** 的 `UploadFile` 直接继承自 **Starlette** 的 `UploadFile`，但添加了一些必要的部分，使其与 **Pydantic** 以及 FastAPI 的其他部分兼容。\n\n///\n\n## 什么是「表单数据」 { #what-is-form-data }\n\nHTML 表单（`<form></form>`）向服务器发送数据的方式通常会对数据使用一种「特殊」的编码，这与 JSON 不同。\n\n**FastAPI** 会确保从正确的位置读取这些数据，而不是从 JSON 中读取。\n\n/// note | 技术细节\n\n当不包含文件时，来自表单的数据通常使用「媒体类型」`application/x-www-form-urlencoded` 编码。\n\n但当表单包含文件时，会编码为 `multipart/form-data`。如果你使用 `File`，**FastAPI** 会知道需要从请求体的正确位置获取文件。\n\n如果你想进一步了解这些编码和表单字段，请参阅 [<abbr title=\"Mozilla Developer Network - Mozilla 开发者网络\">MDN</abbr> 关于 `POST` 的 Web 文档](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)。\n\n///\n\n/// warning | 警告\n\n你可以在一个*路径操作*中声明多个 `File` 和 `Form` 参数，但不能同时声明希望以 JSON 接收的 `Body` 字段，因为此时请求体会使用 `multipart/form-data` 编码，而不是 `application/json`。\n\n这不是 **FastAPI** 的限制，而是 HTTP 协议的一部分。\n\n///\n\n## 可选文件上传 { #optional-file-upload }\n\n你可以通过使用标准类型注解并将 `None` 作为默认值的方式将一个文件参数设为可选:\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## 带有额外元数据的 `UploadFile` { #uploadfile-with-additional-metadata }\n\n你也可以将 `File()` 与 `UploadFile` 一起使用，例如，设置额外的元数据:\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## 多文件上传 { #multiple-file-uploads }\n\nFastAPI 支持同时上传多个文件。\n\n它们会被关联到同一个通过「表单数据」发送的「表单字段」。\n\n要实现这一点，声明一个由 `bytes` 或 `UploadFile` 组成的列表（`List`）：\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\n接收的也是含 `bytes` 或 `UploadFile` 的列表（`list`）。\n\n/// note | 技术细节\n\n也可以使用 `from starlette.responses import HTMLResponse`。\n\n`fastapi.responses` 其实与 `starlette.responses` 相同，只是为了方便开发者调用。实际上，大多数 **FastAPI** 的响应都直接从 Starlette 调用。\n\n///\n\n### 带有额外元数据的多文件上传 { #multiple-file-uploads-with-additional-metadata }\n\n和之前的方式一样，你可以为 `File()` 设置额外参数，即使是 `UploadFile`：\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## 小结 { #recap }\n\n使用 `File`、`bytes` 和 `UploadFile` 来声明在请求中上传的文件，它们以表单数据发送。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/request-form-models.md",
    "content": "# 表单模型 { #form-models }\n\n你可以在 FastAPI 中使用 **Pydantic 模型**声明**表单字段**。\n\n/// info | 信息\n\n要使用表单，首先安装 [`python-multipart`](https://github.com/Kludex/python-multipart)。\n\n确保你创建一个[虚拟环境](../virtual-environments.md)，激活它，然后再安装，例如：\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note | 注意\n\n自 FastAPI 版本 `0.113.0` 起支持此功能。🤓\n\n///\n\n## 表单的 Pydantic 模型 { #pydantic-models-for-forms }\n\n你只需声明一个 **Pydantic 模型**，其中包含你希望接收的**表单字段**，然后将参数声明为 `Form`：\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI** 将从请求中的**表单数据**中**提取**出**每个字段**的数据，并提供你定义的 Pydantic 模型。\n\n## 检查文档 { #check-the-docs }\n\n你可以在文档 UI 中验证它，地址为 `/docs`：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## 禁止额外的表单字段 { #forbid-extra-form-fields }\n\n在某些特殊使用情况下（可能并不常见），你可能希望将表单字段**限制**为仅在 Pydantic 模型中声明过的字段，并**禁止**任何**额外**的字段。\n\n/// note | 注意\n\n自 FastAPI 版本 `0.114.0` 起支持此功能。🤓\n\n///\n\n你可以使用 Pydantic 的模型配置来 `forbid` 任何 `extra` 字段：\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\n如果客户端尝试发送一些额外的数据，他们将收到**错误**响应。\n\n例如，客户端尝试发送如下表单字段：\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\n他们将收到一条错误响应，表明字段 `extra` 不被允许：\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## 总结 { #summary }\n\n你可以使用 Pydantic 模型在 FastAPI 中声明表单字段。😎\n"
  },
  {
    "path": "docs/zh/docs/tutorial/request-forms-and-files.md",
    "content": "# 请求表单与文件 { #request-forms-and-files }\n\nFastAPI 支持同时使用 `File` 和 `Form` 定义文件和表单字段。\n\n/// info | 信息\n\n接收上传的文件和/或表单数据，首先安装 [`python-multipart`](https://github.com/Kludex/python-multipart)。\n\n请先创建并激活一个[虚拟环境](../virtual-environments.md)，然后再安装，例如：\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## 导入 `File` 与 `Form` { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## 定义 `File` 与 `Form` 参数 { #define-file-and-form-parameters }\n\n创建文件和表单参数的方式与 `Body` 和 `Query` 一样：\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\n文件和表单字段作为表单数据上传与接收。\n\n并且你可以将部分文件声明为 `bytes`，将部分文件声明为 `UploadFile`。\n\n/// warning | 警告\n\n可在一个*路径操作*中声明多个 `File` 与 `Form` 参数，但不能同时声明要接收 JSON 的 `Body` 字段。因为此时请求体的编码为 `multipart/form-data`，不是 `application/json`。\n\n这不是 **FastAPI** 的问题，而是 HTTP 协议的规定。\n\n///\n\n## 小结 { #recap }\n\n在同一个请求中接收数据和文件时，应同时使用 `File` 和 `Form`。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/request-forms.md",
    "content": "# 表单数据 { #form-data }\n\n当你需要接收表单字段而不是 JSON 时，可以使用 `Form`。\n\n/// info\n\n要使用表单，首先安装 [`python-multipart`](https://github.com/Kludex/python-multipart)。\n\n请先创建并激活一个[虚拟环境](../virtual-environments.md)，然后再进行安装，例如：\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## 导入 `Form` { #import-form }\n\n从 `fastapi` 导入 `Form`：\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## 定义 `Form` 参数 { #define-form-parameters }\n\n创建表单参数的方式与 `Body` 或 `Query` 相同：\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\n例如，在 OAuth2 规范的一种使用方式（称为“密码流”）中，要求将 `username` 和 `password` 作为表单字段发送。\n\n<dfn title=\"规范\">规范</dfn>要求这些字段必须精确命名为 `username` 和 `password`，并且作为表单字段发送，而不是 JSON。\n\n使用 `Form` 可以像使用 `Body`（以及 `Query`、`Path`、`Cookie`）一样声明相同的配置，包括校验、示例、别名（例如将 `username` 写成 `user-name`）等。\n\n/// info\n\n`Form` 是直接继承自 `Body` 的类。\n\n///\n\n/// tip\n\n要声明表单请求体，必须显式使用 `Form`，否则这些参数会被当作查询参数或请求体（JSON）参数。\n\n///\n\n## 关于 \"表单字段\" { #about-form-fields }\n\nHTML 表单（`<form></form>`）向服务器发送数据时通常会对数据使用一种“特殊”的编码方式，这与 JSON 不同。\n\n**FastAPI** 会确保从正确的位置读取这些数据，而不是从 JSON 中读取。\n\n/// note | 技术细节\n\n表单数据通常使用“媒体类型” `application/x-www-form-urlencoded` 进行编码。\n\n但当表单包含文件时，会编码为 `multipart/form-data`。你将在下一章阅读如何处理文件。\n\n如果你想了解更多关于这些编码和表单字段的信息，请参阅 [<abbr title=\"Mozilla Developer Network - Mozilla 开发者网络\">MDN</abbr> Web 文档的 `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)。\n\n///\n\n/// warning\n\n你可以在一个路径操作中声明多个 `Form` 参数，但不能同时再声明要接收为 JSON 的 `Body` 字段，因为此时请求体会使用 `application/x-www-form-urlencoded` 而不是 `application/json` 进行编码。\n\n这不是 **FastAPI** 的限制，而是 HTTP 协议的一部分。\n\n///\n\n## 小结 { #recap }\n\n使用 `Form` 来声明表单数据输入参数。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/response-model.md",
    "content": "# 响应模型 - 返回类型 { #response-model-return-type }\n\n你可以通过为*路径操作函数*的**返回类型**添加注解来声明用于响应的类型。\n\n和为输入数据在函数**参数**里做类型注解的方式相同，你可以使用 Pydantic 模型、`list`、`dict`、以及整数、布尔值等标量类型。\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPI 会使用这个返回类型来：\n\n* 对返回数据进行**校验**。\n    * 如果数据无效（例如缺少某个字段），这意味着你的应用代码有问题，没有返回应有的数据，FastAPI 将返回服务器错误而不是返回错误的数据。这样你和你的客户端都可以确定会收到期望的数据及其结构。\n* 在 OpenAPI 的*路径操作*中为响应添加**JSON Schema**。\n    * 它会被**自动文档**使用。\n    * 它也会被自动客户端代码生成工具使用。\n* 使用 Pydantic 将返回数据**序列化**为 JSON。Pydantic 使用**Rust**编写，因此会**快很多**。\n\n但更重要的是：\n\n* 它会将输出数据**限制并过滤**为返回类型中定义的内容。\n    * 这对**安全性**尤为重要，下面会进一步介绍。\n\n## `response_model` 参数 { #response-model-parameter }\n\n在一些情况下，你需要或希望返回的数据与声明的类型不完全一致。\n\n例如，你可能希望**返回一个字典**或数据库对象，但**将其声明为一个 Pydantic 模型**。这样 Pydantic 模型就会为你返回的对象（例如字典或数据库对象）完成文档、校验等工作。\n\n如果你添加了返回类型注解，工具和编辑器会（正确地）报错，提示你的函数返回的类型（例如 `dict`）与声明的类型（例如一个 Pydantic 模型）不同。\n\n在这些情况下，你可以使用*路径操作装饰器*参数 `response_model`，而不是返回类型。\n\n你可以在任意*路径操作*中使用 `response_model` 参数：\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* 等等。\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | 注意\n\n注意，`response_model` 是「装饰器」方法（`get`、`post` 等）的一个参数。不是你的*路径操作函数*的参数，不像所有查询参数和请求体那样。\n\n///\n\n`response_model` 接收的类型与为 Pydantic 模型字段声明的类型相同，因此它可以是一个 Pydantic 模型，也可以是一个由 Pydantic 模型组成的 `list`，例如 `List[Item]`。\n\nFastAPI 会使用这个 `response_model` 来完成数据文档、校验等，并且还会将输出数据**转换并过滤**为其类型声明。\n\n/// tip | 提示\n\n如果你的编辑器、mypy 等进行严格类型检查，你可以将函数返回类型声明为 `Any`。\n\n这样你告诉编辑器你是有意返回任意类型。但 FastAPI 仍会使用 `response_model` 做数据文档、校验、过滤等工作。\n\n///\n\n### `response_model` 的优先级 { #response-model-priority }\n\n如果你同时声明了返回类型和 `response_model`，`response_model` 会具有优先级并由 FastAPI 使用。\n\n这样，即使你返回的类型与响应模型不同，你也可以为函数添加正确的类型注解，供编辑器和 mypy 等工具使用。同时你仍然可以让 FastAPI 使用 `response_model` 进行数据校验、文档等。\n\n你也可以使用 `response_model=None` 来禁用该*路径操作*的响应模型生成；当你为一些不是有效 Pydantic 字段的东西添加类型注解时，可能需要这样做，下面的章节会有示例。\n\n## 返回与输入相同的数据 { #return-the-same-input-data }\n\n这里我们声明一个 `UserIn` 模型，它包含一个明文密码：\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | 信息\n\n要使用 `EmailStr`，首先安装 [`email-validator`](https://github.com/JoshData/python-email-validator)。\n\n请先创建并激活一个[虚拟环境](../virtual-environments.md)，然后安装，例如：\n\n```console\n$ pip install email-validator\n```\n\n或者：\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\n我们使用这个模型来声明输入，同时也用相同的模型来声明输出：\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\n现在，每当浏览器使用密码创建用户时，API 会在响应中返回相同的密码。\n\n在这个场景下，这可能不算问题，因为发送密码的是同一个用户。\n\n但如果我们在其他*路径操作*中使用相同的模型，就可能会把用户的密码发送给每个客户端。\n\n/// danger | 危险\n\n除非你非常清楚所有注意事项并确实知道自己在做什么，否则永远不要存储用户的明文密码，也不要像这样在响应中发送它。\n\n///\n\n## 添加输出模型 { #add-an-output-model }\n\n相反，我们可以创建一个包含明文密码的输入模型和一个不包含它的输出模型：\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\n这里，即使我们的*路径操作函数*返回的是包含密码的同一个输入用户：\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n……我们仍将 `response_model` 声明为不包含密码的 `UserOut` 模型：\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\n因此，**FastAPI** 会负责过滤掉输出模型中未声明的所有数据（使用 Pydantic）。\n\n### `response_model` 还是返回类型 { #response-model-or-return-type }\n\n在这个例子中，因为两个模型不同，如果我们将函数返回类型注解为 `UserOut`，编辑器和工具会抱怨我们返回了无效类型，因为它们是不同的类。\n\n这就是为什么在这个例子里我们必须在 `response_model` 参数中声明它。\n\n……但继续往下读，看看如何更好地处理这种情况。\n\n## 返回类型与数据过滤 { #return-type-and-data-filtering }\n\n延续上一个例子。我们希望**用一种类型来注解函数**，但希望从函数返回的内容实际上可以**包含更多数据**。\n\n我们希望 FastAPI 继续使用响应模型来**过滤**数据。这样即使函数返回了更多数据，响应也只会包含响应模型中声明的字段。\n\n在上一个例子中，因为类不同，我们不得不使用 `response_model` 参数。但这也意味着我们无法从编辑器和工具处获得对函数返回类型的检查支持。\n\n不过在大多数需要这样做的场景里，我们只是希望模型像这个例子中那样**过滤/移除**一部分数据。\n\n在这些场景里，我们可以使用类和继承，既利用函数的**类型注解**获取更好的编辑器和工具支持，又能获得 FastAPI 的**数据过滤**。\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\n这样一来，我们既能从编辑器和 mypy 获得工具支持（这段代码在类型上是正确的），也能从 FastAPI 获得数据过滤。\n\n这是如何做到的？我们来看看。🤓\n\n### 类型注解与工具链 { #type-annotations-and-tooling }\n\n先看看编辑器、mypy 和其他工具会如何看待它。\n\n`BaseUser` 有基础字段。然后 `UserIn` 继承自 `BaseUser` 并新增了 `password` 字段，因此它包含了两个模型的全部字段。\n\n我们把函数返回类型注解为 `BaseUser`，但实际上返回的是一个 `UserIn` 实例。\n\n编辑器、mypy 和其他工具不会对此抱怨，因为在类型系统里，`UserIn` 是 `BaseUser` 的子类，这意味着当期望 `BaseUser` 时，返回 `UserIn` 是*合法*的。\n\n### FastAPI 的数据过滤 { #fastapi-data-filtering }\n\n对于 FastAPI，它会查看返回类型并确保你返回的内容**只**包含该类型中声明的字段。\n\nFastAPI 在内部配合 Pydantic 做了多项处理，确保不会把类继承的这些规则用于返回数据的过滤，否则你可能会返回比预期多得多的数据。\n\n这样，你就能兼得两方面的优势：带有**工具支持**的类型注解和**数据过滤**。\n\n## 在文档中查看 { #see-it-in-the-docs }\n\n当你查看自动文档时，你会看到输入模型和输出模型都会有各自的 JSON Schema：\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\n并且两个模型都会用于交互式 API 文档：\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## 其他返回类型注解 { #other-return-type-annotations }\n\n有些情况下你会返回一些不是有效 Pydantic 字段的内容，并在函数上做了相应注解，只是为了获得工具链（编辑器、mypy 等）的支持。\n\n### 直接返回 Response { #return-a-response-directly }\n\n最常见的情况是[直接返回 Response，详见进阶文档](../advanced/response-directly.md)。\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\n这个简单场景 FastAPI 会自动处理，因为返回类型注解是 `Response`（或其子类）。\n\n工具也会满意，因为 `RedirectResponse` 和 `JSONResponse` 都是 `Response` 的子类，所以类型注解是正确的。\n\n### 注解 Response 的子类 { #annotate-a-response-subclass }\n\n你也可以在类型注解中使用 `Response` 的子类：\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\n这同样可行，因为 `RedirectResponse` 是 `Response` 的子类，FastAPI 会自动处理这个简单场景。\n\n### 无效的返回类型注解 { #invalid-return-type-annotations }\n\n但当你返回其他任意对象（如数据库对象）而它不是有效的 Pydantic 类型，并在函数中按此进行了注解时，FastAPI 会尝试基于该类型注解创建一个 Pydantic 响应模型，但会失败。\n\n如果你有一个在多个类型之间的<dfn title=\"多个类型的联合表示“这些类型中的任意一个”。\">联合类型</dfn>，其中一个或多个不是有效的 Pydantic 类型，也会发生同样的情况，例如这个会失败 💥：\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n……它失败是因为该类型注解不是 Pydantic 类型，也不只是单个 `Response` 类或其子类，而是 `Response` 与 `dict` 的联合类型（任意其一）。\n\n### 禁用响应模型 { #disable-response-model }\n\n延续上面的例子，你可能不想要 FastAPI 执行默认的数据校验、文档、过滤等。\n\n但你可能仍然想在函数上保留返回类型注解，以获得编辑器和类型检查器（如 mypy）的支持。\n\n在这种情况下，你可以通过设置 `response_model=None` 来禁用响应模型生成：\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\n这会让 FastAPI 跳过响应模型的生成，这样你就可以按需使用任意返回类型注解，而不会影响你的 FastAPI 应用。🤓\n\n## 响应模型的编码参数 { #response-model-encoding-parameters }\n\n你的响应模型可以具有默认值，例如：\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None`（或在 Python 3.10 中的 `str | None = None`）默认值为 `None`。\n* `tax: float = 10.5` 默认值为 `10.5`。\n* `tags: List[str] = []` 默认值为一个空列表：`[]`。\n\n但如果它们并没有被实际存储，你可能希望在结果中省略这些默认值。\n\n例如，当你在 NoSQL 数据库中保存了具有许多可选属性的模型，但又不想发送充满默认值的冗长 JSON 响应。\n\n### 使用 `response_model_exclude_unset` 参数 { #use-the-response-model-exclude-unset-parameter }\n\n你可以设置*路径操作装饰器*参数 `response_model_exclude_unset=True`：\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\n这样响应中将不会包含那些默认值，而只包含实际设置的值。\n\n因此，如果你向该*路径操作*请求 ID 为 `foo` 的商品，响应（不包括默认值）将为：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | 信息\n\n你还可以使用：\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\n详见 [Pydantic 文档](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict)中对 `exclude_defaults` 和 `exclude_none` 的说明。\n\n///\n\n#### 默认字段有实际值的数据 { #data-with-values-for-fields-with-defaults }\n\n但是，如果你的数据在具有默认值的模型字段中有实际的值，例如 ID 为 `bar` 的项：\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\n这些值将包含在响应中。\n\n#### 具有与默认值相同值的数据 { #data-with-the-same-values-as-the-defaults }\n\n如果数据具有与默认值相同的值，例如 ID 为 `baz` 的项：\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nFastAPI 足够聪明（实际上是 Pydantic 足够聪明）去认识到，即使 `description`、`tax` 和 `tags` 的值与默认值相同，它们也是被显式设置的（而不是取自默认值）。\n\n因此，它们将包含在 JSON 响应中。\n\n/// tip | 提示\n\n请注意默认值可以是任何值，而不仅是 `None`。\n\n它们可以是一个列表（`[]`）、值为 `10.5` 的 `float`，等等。\n\n///\n\n### `response_model_include` 和 `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\n你还可以使用*路径操作装饰器*的 `response_model_include` 和 `response_model_exclude` 参数。\n\n它们接收一个由属性名 `str` 组成的 `set`，用于包含（忽略其他）或排除（包含其他）这些属性。\n\n当你只有一个 Pydantic 模型，并且想要从输出中移除一些数据时，这可以作为一种快捷方式。\n\n/// tip | 提示\n\n但仍然推荐使用上面的思路，使用多个类，而不是这些参数。\n\n因为即使你使用 `response_model_include` 或 `response_model_exclude` 省略了一些属性，你的应用在 OpenAPI（和文档）中生成的 JSON Schema 仍然会是完整模型。\n\n这同样适用于类似的 `response_model_by_alias`。\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | 提示\n\n`{\"name\", \"description\"}` 语法创建一个包含这两个值的 `set`。\n\n等同于 `set([\"name\", \"description\"])`。\n\n///\n\n#### 使用 `list` 而不是 `set` { #using-lists-instead-of-sets }\n\n如果你忘记使用 `set` 而是使用了 `list` 或 `tuple`，FastAPI 仍会将其转换为 `set` 并正常工作：\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## 总结 { #recap }\n\n使用*路径操作装饰器*的 `response_model` 参数来定义响应模型，尤其是确保私有数据被过滤掉。\n\n使用 `response_model_exclude_unset` 来仅返回显式设置的值。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/response-status-code.md",
    "content": "# 响应状态码 { #response-status-code }\n\n与指定响应模型的方式相同，在以下任意*路径操作*中，可以使用 `status_code` 参数声明用于响应的 HTTP 状态码：\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* 等...\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | 注意\n\n注意，`status_code` 是（`get`、`post` 等）**装饰器**方法中的参数。与之前的参数和请求体不同，不是*路径操作函数*的参数。\n\n///\n\n`status_code` 参数接收表示 HTTP 状态码的数字。\n\n/// info | 信息\n\n`status_code` 还能接收 `IntEnum` 类型，比如 Python 的 [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus)。\n\n///\n\n它可以：\n\n* 在响应中返回状态码\n* 在 OpenAPI 概图（及用户界面）中存档：\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | 注意\n\n某些响应状态码表示响应没有响应体（参阅下一章）。\n\nFastAPI 可以进行识别，并生成表明无响应体的 OpenAPI 文档。\n\n///\n\n## 关于 HTTP 状态码 { #about-http-status-codes }\n\n/// note | 注意\n\n如果已经了解 HTTP 状态码，请跳到下一章。\n\n///\n\n在 HTTP 协议中，发送 3 位数的数字状态码是响应的一部分。\n\n这些状态码都具有便于识别的关联名称，但是重要的还是数字。\n\n简言之：\n\n* `100 - 199` 用于返回“信息”。这类状态码很少直接使用。具有这些状态码的响应不能包含响应体\n* **`200 - 299`** 用于表示“成功”。这些状态码是最常用的\n    * `200` 是默认状态码，表示一切“OK”\n    * `201` 表示“已创建”，通常在数据库中创建新记录后使用\n    * `204` 是一种特殊的例子，表示“无内容”。该响应在没有为客户端返回内容时使用，因此，该响应不能包含响应体\n* **`300 - 399`** 用于“重定向”。具有这些状态码的响应不一定包含响应体，但 `304`“未修改”是个例外，该响应不得包含响应体\n* **`400 - 499`** 用于表示“客户端错误”。这些可能是第二常用的类型\n    * `404`，用于“未找到”响应\n    * 对于来自客户端的一般错误，可以只使用 `400`\n* `500 - 599` 用于表示服务器端错误。几乎永远不会直接使用这些状态码。应用代码或服务器出现问题时，会自动返回这些状态码\n\n/// tip | 提示\n\n想了解每个状态码的更多信息以及适用场景，请参阅 [<abbr title=\"Mozilla Developer Network - Mozilla 开发者网络\">MDN</abbr> 的 HTTP 状态码文档](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)。\n\n///\n\n## 状态码名称快捷方式 { #shortcut-to-remember-the-names }\n\n再看下之前的例子：\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201` 表示“已创建”的状态码。\n\n但我们没有必要记住所有代码的含义。\n\n可以使用 `fastapi.status` 中的快捷变量。\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\n这只是一种快捷方式，具有相同的数字代码，但它可以使用编辑器的自动补全功能：\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | 技术细节\n\n也可以使用 `from starlette import status`。\n\n为了让开发者更方便，**FastAPI** 提供了与 `starlette.status` 完全相同的 `fastapi.status`。但它直接来自于 Starlette。\n\n///\n\n## 更改默认状态码 { #changing-the-default }\n\n稍后在[高级用户指南](../advanced/response-change-status-code.md)中，你将看到如何返回与此处声明的默认状态码不同的状态码。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/schema-extra-example.md",
    "content": "# 声明请求示例数据 { #declare-request-example-data }\n\n你可以为你的应用将接收的数据声明示例。\n\n这里有几种实现方式。\n\n## Pydantic 模型中的额外 JSON Schema 数据 { #extra-json-schema-data-in-pydantic-models }\n\n你可以为一个 Pydantic 模型声明 `examples`，它们会被添加到生成的 JSON Schema 中。\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\n这些额外信息会原样添加到该模型输出的 JSON Schema 中，并会在 API 文档中使用。\n\n你可以使用属性 `model_config`，它接收一个 `dict`，详见 [Pydantic 文档：配置](https://docs.pydantic.dev/latest/api/config/)。\n\n你可以设置 `\"json_schema_extra\"`，其值为一个 `dict`，包含你希望出现在生成 JSON Schema 中的任意附加数据，包括 `examples`。\n\n/// tip | 提示\n\n你也可以用同样的技巧扩展 JSON Schema，添加你自己的自定义额外信息。\n\n例如，你可以用它为前端用户界面添加元数据等。\n\n///\n\n/// info | 信息\n\nOpenAPI 3.1.0（自 FastAPI 0.99.0 起使用）增加了对 `examples` 的支持，它是 JSON Schema 标准的一部分。\n\n在此之前，只支持使用单个示例的关键字 `example`。OpenAPI 3.1.0 仍然支持它，但它已被弃用，并不属于 JSON Schema 标准。因此，建议你把 `example` 迁移到 `examples`。🤓\n\n你可以在本页末尾阅读更多内容。\n\n///\n\n## `Field` 的附加参数 { #field-additional-arguments }\n\n在 Pydantic 模型中使用 `Field()` 时，你也可以声明额外的 `examples`：\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## JSON Schema 中的 `examples` - OpenAPI { #examples-in-json-schema-openapi }\n\n在以下任意场景中使用：\n\n- `Path()`\n- `Query()`\n- `Header()`\n- `Cookie()`\n- `Body()`\n- `Form()`\n- `File()`\n\n你也可以声明一组 `examples`，这些带有附加信息的示例将被添加到它们在 OpenAPI 中的 JSON Schema 里。\n\n### 带有 `examples` 的 `Body` { #body-with-examples }\n\n这里我们向 `Body()` 传入 `examples`，其中包含一个期望的数据示例：\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### 文档 UI 中的示例 { #example-in-the-docs-ui }\n\n使用上述任一方法，在 `/docs` 中看起来会是这样：\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### 带有多个 `examples` 的 `Body` { #body-with-multiple-examples }\n\n当然，你也可以传入多个 `examples`：\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\n这样做时，这些示例会成为该请求体数据内部 JSON Schema 的一部分。\n\n不过，在<dfn title=\"2023-08-26\">撰写本文时</dfn>，用于展示文档 UI 的 Swagger UI 并不支持显示 JSON Schema 中数据的多个示例。但请继续阅读，下面有一种变通方法。\n\n### OpenAPI 特定的 `examples` { #openapi-specific-examples }\n\n在 JSON Schema 支持 `examples` 之前，OpenAPI 就已支持一个同名但不同的字段 `examples`。\n\n这个面向 OpenAPI 的 `examples` 位于 OpenAPI 规范的另一处。它放在每个路径操作的详细信息中，而不是每个 JSON Schema 里。\n\n而 Swagger UI 早就支持这个特定的 `examples` 字段。因此，你可以用它在文档 UI 中展示不同的示例。\n\n这个 OpenAPI 特定字段 `examples` 的结构是一个包含多个示例的 `dict`（而不是一个 `list`），每个示例都包含会被添加到 OpenAPI 的额外信息。\n\n这不放在 OpenAPI 内部包含的各个 JSON Schema 里，而是直接放在路径操作上。\n\n### 使用 `openapi_examples` 参数 { #using-the-openapi-examples-parameter }\n\n你可以在 FastAPI 中通过参数 `openapi_examples` 来声明这个 OpenAPI 特定的 `examples`，适用于：\n\n- `Path()`\n- `Query()`\n- `Header()`\n- `Cookie()`\n- `Body()`\n- `Form()`\n- `File()`\n\n这个 `dict` 的键用于标识每个示例，每个值是另一个 `dict`。\n\n`examples` 中每个具体示例的 `dict` 可以包含：\n\n- `summary`：该示例的简短描述。\n- `description`：较长描述，可以包含 Markdown 文本。\n- `value`：实际展示的示例，例如一个 `dict`。\n- `externalValue`：`value` 的替代项，指向该示例的 URL。不过它的工具支持度可能不如 `value`。\n\n你可以这样使用：\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### 文档 UI 中的 OpenAPI 示例 { #openapi-examples-in-the-docs-ui }\n\n当把 `openapi_examples` 添加到 `Body()` 后，`/docs` 会如下所示：\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## 技术细节 { #technical-details }\n\n/// tip | 提示\n\n如果你已经在使用 FastAPI 版本 0.99.0 或更高版本，你大概率可以跳过这些细节。\n\n它们对更早版本（OpenAPI 3.1.0 尚不可用之前）更相关。\n\n你可以把这当作一堂简短的 OpenAPI 和 JSON Schema 历史课。🤓\n\n///\n\n/// warning | 警告\n\n以下是关于 JSON Schema 和 OpenAPI 标准的非常技术性的细节。\n\n如果上面的思路对你已经足够可用，你可能不需要这些细节，可以直接跳过。\n\n///\n\n在 OpenAPI 3.1.0 之前，OpenAPI 使用的是一个更旧且经过修改的 JSON Schema 版本。\n\n当时 JSON Schema 没有 `examples`，所以 OpenAPI 在它修改过的版本中添加了自己的 `example` 字段。\n\nOpenAPI 还在规范的其他部分添加了 `example` 和 `examples` 字段：\n\n- [`Parameter Object`（规范中）](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object)，被 FastAPI 的以下内容使用：\n    - `Path()`\n    - `Query()`\n    - `Header()`\n    - `Cookie()`\n- [`Request Body Object` 中的 `content` 字段里的 `Media Type Object`（规范中）](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object)，被 FastAPI 的以下内容使用：\n    - `Body()`\n    - `File()`\n    - `Form()`\n\n/// info | 信息\n\n这个旧的、OpenAPI 特定的 `examples` 参数，自 FastAPI `0.103.0` 起改名为 `openapi_examples`。\n\n///\n\n### JSON Schema 的 `examples` 字段 { #json-schemas-examples-field }\n\n后来，JSON Schema 在新版本的规范中添加了 [`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5) 字段。\n\n随后新的 OpenAPI 3.1.0 基于最新版本（JSON Schema 2020-12），其中包含了这个新的 `examples` 字段。\n\n现在，这个新的 `examples` 字段优先于旧的单个（且自定义的）`example` 字段，后者已被弃用。\n\nJSON Schema 中这个新的 `examples` 字段只是一个由示例组成的 `list`，而不是像上面提到的 OpenAPI 其他位置那样带有额外元数据的 `dict`。\n\n/// info | 信息\n\n即使在 OpenAPI 3.1.0 发布、并与 JSON Schema 有了这种更简单的集成之后，有一段时间里，提供自动文档的 Swagger UI 并不支持 OpenAPI 3.1.0（它自 5.0.0 版本起已支持 🎉）。\n\n因此，FastAPI 0.99.0 之前的版本仍然使用低于 3.1.0 的 OpenAPI 版本。\n\n///\n\n### Pydantic 与 FastAPI 的 `examples` { #pydantic-and-fastapi-examples }\n\n当你在 Pydantic 模型中添加 `examples`，通过 `schema_extra` 或 `Field(examples=[\"something\"])`，这些示例会被添加到该 Pydantic 模型的 JSON Schema 中。\n\n这个 Pydantic 模型的 JSON Schema 会被包含到你的 API 的 OpenAPI 中，然后在文档 UI 中使用。\n\n在 FastAPI 0.99.0 之前的版本（0.99.0 及以上使用更新的 OpenAPI 3.1.0），当你在其他工具（`Query()`、`Body()` 等）中使用 `example` 或 `examples` 时，这些示例不会被添加到描述该数据的 JSON Schema 中（甚至不会添加到 OpenAPI 自己的 JSON Schema 版本中），而是会直接添加到 OpenAPI 的路径操作声明中（在 OpenAPI 使用 JSON Schema 的部分之外）。\n\n但现在 FastAPI 0.99.0 及以上使用 OpenAPI 3.1.0（其使用 JSON Schema 2020-12）以及 Swagger UI 5.0.0 及以上后，一切更加一致，示例会包含在 JSON Schema 中。\n\n### Swagger UI 与 OpenAPI 特定的 `examples` { #swagger-ui-and-openapi-specific-examples }\n\n此前，由于 Swagger UI 不支持多个 JSON Schema 示例（截至 2023-08-26），用户无法在文档中展示多个示例。\n\n为了解决这个问题，FastAPI `0.103.0` 通过新增参数 `openapi_examples`，为声明同样的旧式 OpenAPI 特定 `examples` 字段提供了支持。🤓\n\n### 总结 { #summary }\n\n我曾经说我不太喜欢历史……结果现在在这儿上“技术史”课。😅\n\n简而言之，升级到 FastAPI 0.99.0 或更高版本，一切会更简单、一致、直观，你也不必了解这些历史细节。😎\n"
  },
  {
    "path": "docs/zh/docs/tutorial/security/first-steps.md",
    "content": "# 安全 - 第一步 { #security-first-steps }\n\n假设你的**后端** API 位于某个域名下。\n\n而**前端**在另一个域名，或同一域名的不同路径（或在移动应用中）。\n\n你希望前端能通过**username** 和 **password** 与后端进行身份验证。\n\n我们可以用 **OAuth2** 在 **FastAPI** 中实现它。\n\n但为了节省你的时间，不必为获取少量信息而通读冗长的规范。\n\n我们直接使用 **FastAPI** 提供的安全工具。\n\n## 效果预览 { #how-it-looks }\n\n先直接运行代码看看效果，之后再回过头理解其背后的原理。\n\n## 创建 `main.py` { #create-main-py }\n\n把下面的示例代码复制到 `main.py`：\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## 运行 { #run-it }\n\n/// info | 信息\n\n当你使用命令 `pip install \"fastapi[standard]\"` 安装 **FastAPI** 时，[`python-multipart`](https://github.com/Kludex/python-multipart) 包会自动安装。\n\n但是，如果你使用 `pip install fastapi`，默认不会包含 `python-multipart` 包。\n\n如需手动安装，请先创建并激活[虚拟环境](../../virtual-environments.md)，然后执行：\n\n```console\n$ pip install python-multipart\n```\n\n这是因为 **OAuth2** 使用“表单数据”来发送 `username` 和 `password`。\n\n///\n\n用下面的命令运行示例：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## 查看 { #check-it }\n\n打开交互式文档：[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n你会看到类似这样的界面：\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Authorize 按钮！\n\n页面右上角已经有一个崭新的“Authorize”按钮。\n\n你的*路径操作*右上角还有一个可点击的小锁图标。\n\n///\n\n点击它，会弹出一个授权表单，可输入 `username` 和 `password`（以及其它可选字段）：\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | 注意\n\n目前无论在表单中输入什么都不会生效，我们稍后就会实现它。\n\n///\n\n这当然不是面向最终用户的前端，但它是一个很棒的自动化工具，可交互式地为整个 API 提供文档。\n\n前端团队（也可能就是你自己）可以使用它。\n\n第三方应用和系统也可以使用它。\n\n你也可以用它来调试、检查和测试同一个应用。\n\n## `password` 流 { #the-password-flow }\n\n现在回过头来理解这些内容。\n\n`password` “流”（flow）是 OAuth2 定义的处理安全与身份验证的一种方式。\n\nOAuth2 的设计目标是让后端或 API 与负责用户认证的服务器解耦。\n\n但在这个例子中，**FastAPI** 应用同时处理 API 和认证。\n\n从这个简化的角度来看看流程：\n\n* 用户在前端输入 `username` 和 `password`，然后按下 `Enter`。\n* 前端（运行在用户浏览器中）把 `username` 和 `password` 发送到我们 API 中的特定 URL（使用 `tokenUrl=\"token\"` 声明）。\n* API 校验 `username` 和 `password`，并返回一个“令牌”（这些我们尚未实现）。\n    * “令牌”只是一个字符串，包含一些内容，之后可用来验证该用户。\n    * 通常，令牌会在一段时间后过期。\n        * 因此，用户过一段时间需要重新登录。\n        * 如果令牌被窃取，风险也更小。它不像一把永久有效的钥匙（在大多数情况下）。\n* 前端会把令牌临时存储在某处。\n* 用户在前端中点击跳转到前端应用的其他部分。\n* 前端需要从 API 获取更多数据。\n    * 但该端点需要身份验证。\n    * 因此，为了与我们的 API 进行身份验证，它会发送一个 `Authorization` 请求头，值为 `Bearer ` 加上令牌。\n    * 如果令牌内容是 `foobar`，`Authorization` 请求头的内容就是：`Bearer foobar`。\n\n## **FastAPI** 的 `OAuth2PasswordBearer` { #fastapis-oauth2passwordbearer }\n\n**FastAPI** 在不同抽象层级提供了多种安全工具。\n\n本示例将使用 **OAuth2** 的 **Password** 流程并配合 **Bearer** 令牌，通过 `OAuth2PasswordBearer` 类来实现。\n\n/// info | 信息\n\n“Bearer” 令牌并非唯一选项。\n\n但它非常适合我们的用例。\n\n对于大多数用例，它也可能是最佳选择，除非你是 OAuth2 专家，并明确知道为何其他方案更适合你的需求。\n\n在那种情况下，**FastAPI** 同样提供了相应的构建工具。\n\n///\n\n创建 `OAuth2PasswordBearer` 类实例时，需要传入 `tokenUrl` 参数。该参数包含客户端（运行在用户浏览器中的前端）用来发送 `username` 和 `password` 以获取令牌的 URL。\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip | 提示\n\n这里的 `tokenUrl=\"token\"` 指向的是尚未创建的相对 URL `token`，等价于 `./token`。\n\n因为使用的是相对 URL，若你的 API 位于 `https://example.com/`，它将指向 `https://example.com/token`；若你的 API 位于 `https://example.com/api/v1/`，它将指向 `https://example.com/api/v1/token`。\n\n使用相对 URL 很重要，这能确保你的应用在诸如[使用代理](../../advanced/behind-a-proxy.md)等高级用例中依然正常工作。\n\n///\n\n这个参数不会创建该端点/*路径操作*，而是声明客户端应使用 `/token` 这个 URL 来获取令牌。这些信息会用于 OpenAPI，进而用于交互式 API 文档系统。\n\n我们很快也会创建对应的实际路径操作。\n\n/// info | 信息\n\n如果你是非常严格的 “Pythonista”，可能不喜欢使用参数名 `tokenUrl` 而不是 `token_url`。\n\n这是因为它使用了与 OpenAPI 规范中相同的名称。这样当你需要深入了解这些安全方案时，可以直接复制粘贴去查找更多信息。\n\n///\n\n`oauth2_scheme` 变量是 `OAuth2PasswordBearer` 的一个实例，同时它也是“可调用”的。\n\n可以像这样调用：\n\n```Python\noauth2_scheme(some, parameters)\n```\n\n因此，它可以与 `Depends` 一起使用。\n\n### 使用 { #use-it }\n\n现在你可以通过 `Depends` 将 `oauth2_scheme` 作为依赖传入。\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\n该依赖会提供一个 `str`，赋值给*路径操作函数*的参数 `token`。\n\n**FastAPI** 会据此在 OpenAPI 架构（以及自动生成的 API 文档）中定义一个“安全方案”。\n\n/// info | 技术细节\n\n**FastAPI** 之所以知道可以使用（在依赖中声明的）`OAuth2PasswordBearer` 在 OpenAPI 中定义安全方案，是因为它继承自 `fastapi.security.oauth2.OAuth2`，而后者又继承自 `fastapi.security.base.SecurityBase`。\n\n所有与 OpenAPI（以及自动 API 文档）集成的安全工具都继承自 `SecurityBase`，这就是 **FastAPI** 能将它们集成到 OpenAPI 的方式。\n\n///\n\n## 它做了什么 { #what-it-does }\n\n它会在请求中查找 `Authorization` 请求头，检查其值是否为 `Bearer ` 加上一些令牌，并将该令牌作为 `str` 返回。\n\n如果没有 `Authorization` 请求头，或者其值不包含 `Bearer ` 令牌，它会直接返回 401 状态码错误（`UNAUTHORIZED`）。\n\n你甚至无需检查令牌是否存在即可返回错误；只要你的函数被执行，就可以确定会拿到一个 `str` 类型的令牌。\n\n你已经可以在交互式文档中试试了：\n\n<img src=\"/img/tutorial/security/image03.png\">\n\n我们还没有验证令牌是否有效，但这已经是一个良好的开端。\n\n## 小结 { #recap }\n\n只需增加三四行代码，你就已经拥有了一种初步的安全机制。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/security/get-current-user.md",
    "content": "# 获取当前用户 { #get-current-user }\n\n上一章中，（基于依赖注入系统的）安全系统向*路径操作函数*传递了 `str` 类型的 `token`：\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\n但这并不实用。\n\n接下来，我们学习如何返回当前用户。\n\n\n## 创建用户模型 { #create-a-user-model }\n\n首先，创建 Pydantic 用户模型。\n\n与使用 Pydantic 声明请求体相同，并且可在任何位置使用：\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## 创建 `get_current_user` 依赖项 { #create-a-get-current-user-dependency }\n\n创建 `get_current_user` 依赖项。\n\n还记得依赖项支持子依赖项吗？\n\n`get_current_user` 使用 `oauth2_scheme` 作为依赖项。\n\n与之前直接在路径操作中的做法相同，新的 `get_current_user` 依赖项从子依赖项 `oauth2_scheme` 中接收 `str` 类型的 `token`：\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## 获取用户 { #get-the-user }\n\n`get_current_user` 使用创建的（伪）工具函数，该函数接收 `str` 类型的令牌，并返回 Pydantic 的 `User` 模型：\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## 注入当前用户 { #inject-the-current-user }\n\n在*路径操作* 的 `Depends` 中使用 `get_current_user`：\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\n注意，此处把 `current_user` 的类型声明为 Pydantic 的 `User` 模型。\n\n这有助于在函数内部使用代码补全和类型检查。\n\n/// tip | 提示\n\n还记得请求体也是使用 Pydantic 模型声明的吧。\n\n放心，因为使用了 `Depends`，**FastAPI** 不会搞混。\n\n///\n\n/// check | 检查\n\n依赖系统的这种设计方式可以支持不同的依赖项返回同一个 `User` 模型。\n\n而不是局限于只能有一个返回该类型数据的依赖项。\n\n///\n\n## 其它模型 { #other-models }\n\n接下来，直接在*路径操作函数*中获取当前用户，并用 `Depends` 在**依赖注入**系统中处理安全机制。\n\n开发者可以使用任何模型或数据满足安全需求（本例中是 Pydantic 的 `User` 模型）。\n\n而且，不局限于只能使用特定的数据模型、类或类型。\n\n不想在模型中使用 `username`，而是使用 `id` 和 `email`？当然可以。这些工具也支持。\n\n只想使用字符串？或字典？甚至是数据库类模型的实例？工作方式都一样。\n\n实际上，就算登录应用的不是用户，而是只拥有访问令牌的机器人、程序或其它系统？工作方式也一样。\n\n尽管使用应用所需的任何模型、类、数据库。**FastAPI** 通过依赖注入系统都能帮您搞定。\n\n\n## 代码大小 { #code-size }\n\n这个示例看起来有些冗长。毕竟这个文件同时包含了安全、数据模型的工具函数，以及路径操作等代码。\n\n但，关键是：\n\n**安全和依赖注入的代码只需要写一次。**\n\n就算写得再复杂，也只是在一个位置写一次就够了。所以，要多复杂就可以写多复杂。\n\n但是，就算有数千个端点（*路径操作*），它们都可以使用同一个安全系统。\n\n而且，所有端点（或它们的任何部件）都可以利用这些依赖项或任何其它依赖项。\n\n所有*路径操作*只需 3 行代码就可以了：\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## 小结 { #recap }\n\n现在，我们可以直接在*路径操作函数*中获取当前用户。\n\n至此，安全的内容已经讲了一半。\n\n只要再为用户或客户端的*路径操作*添加真正发送 `username` 和 `password` 的功能就可以了。\n\n下一章见。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/security/index.md",
    "content": "# 安全性 { #security }\n\n有许多方法可以处理安全性、身份认证和授权等问题。\n\n而且这通常是一个复杂而「困难」的话题。\n\n在许多框架和系统中，仅处理安全性和身份认证就会花费大量的精力和代码（在许多情况下，可能占编写的所有代码的 50％ 或更多）。\n\n**FastAPI** 提供了多种工具，可帮助你以标准的方式轻松、快速地处理**安全性**，而无需研究和学习所有的安全规范。\n\n但首先，让我们来看一些小的概念。\n\n## 赶时间 { #in-a-hurry }\n\n如果你不关心这些术语，而只需要*立即*通过基于用户名和密码的身份认证来增加安全性，请跳转到接下来的章节。\n\n## OAuth2 { #oauth2 }\n\nOAuth2是一个规范，它定义了几种处理身份认证和授权的方法。\n\n它是一个相当广泛的规范，涵盖了一些复杂的使用场景。\n\n它包括了使用「第三方」进行身份认证的方法。\n\n这就是所有带有「使用 Facebook，Google，X (Twitter)，GitHub 登录」的系统背后所使用的机制。\n\n### OAuth 1 { #oauth-1 }\n\n有一个 OAuth 1，它与 OAuth2 完全不同，并且更为复杂，因为它直接包含了有关如何加密通信的规范。\n\n如今它已经不是很流行，没有被广泛使用了。\n\nOAuth2 没有指定如何加密通信，它期望你为应用程序使用 HTTPS 进行通信。\n\n/// tip | 提示\n\n在有关**部署**的章节中，你将了解如何使用 Traefik 和 Let's Encrypt 免费设置 HTTPS。\n\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect 是另一个基于 **OAuth2** 的规范。\n\n它只是扩展了 OAuth2，并明确了一些在 OAuth2 中相对模糊的内容，以尝试使其更具互操作性。\n\n例如，Google 登录使用 OpenID Connect（底层使用OAuth2）。\n\n但是 Facebook 登录不支持 OpenID Connect。它具有自己的 OAuth2 风格。\n\n### OpenID（非「OpenID Connect」） { #openid-not-openid-connect }\n\n还有一个「OpenID」规范。它试图解决与 **OpenID Connect** 相同的问题，但它不是基于 OAuth2。\n\n因此，它是一个完整的附加系统。\n\n如今它已经不是很流行，没有被广泛使用了。\n\n## OpenAPI { #openapi }\n\nOpenAPI（以前称为 Swagger）是用于构建 API 的开放规范（现已成为 Linux Foundation 的一部分）。\n\n**FastAPI** 基于 **OpenAPI**。\n\n这就是使多个自动交互式文档界面，代码生成等成为可能的原因。\n\nOpenAPI 有一种定义多个安全「方案」的方法。\n\n通过使用它们，你可以利用所有这些基于标准的工具，包括这些交互式文档系统。\n\nOpenAPI 定义了以下安全方案：\n\n* `apiKey`：一个特定于应用程序的密钥，可以来自：\n    * 查询参数。\n    * 请求头。\n    * cookie。\n* `http`：标准的 HTTP 身份认证系统，包括：\n    * `bearer`: 一个值为 `Bearer ` 加令牌字符串的 `Authorization` 请求头。这是从 OAuth2 继承的。\n    * HTTP Basic 认证方式。\n    * HTTP Digest，等等。\n* `oauth2`：所有的 OAuth2 处理安全性的方式（称为「流程」）。\n    *以下几种流程适合构建 OAuth 2.0 身份认证的提供者（例如 Google，Facebook，X (Twitter)，GitHub 等）：\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * 但是有一个特定的「流程」可以完美地用于直接在同一应用程序中处理身份认证：\n        * `password`：接下来的几章将介绍它的示例。\n* `openIdConnect`：提供了一种定义如何自动发现 OAuth2 身份认证数据的方法。\n    * 此自动发现机制是 OpenID Connect 规范中定义的内容。\n\n\n/// tip | 提示\n\n集成其他身份认证/授权提供者（例如Google，Facebook，X (Twitter)，GitHub等）也是可能的，而且较为容易。\n\n最复杂的问题是创建一个像这样的身份认证/授权提供程序，但是 **FastAPI** 为你提供了轻松完成任务的工具，同时为你解决了重活。\n\n///\n\n## **FastAPI** 实用工具 { #fastapi-utilities }\n\nFastAPI 在 `fastapi.security` 模块中为每个安全方案提供了几种工具，这些工具简化了这些安全机制的使用方法。\n\n在接下来的章节中，你将看到如何使用 **FastAPI** 所提供的这些工具为你的 API 增加安全性。\n\n而且你还将看到它如何自动地被集成到交互式文档系统中。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/security/oauth2-jwt.md",
    "content": "# 使用密码（及哈希）的 OAuth2，基于 JWT 的 Bearer 令牌 { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\n现在我们已经有了完整的安全流程，接下来用 <abbr title=\"JSON Web Tokens - JSON Web 令牌\">JWT</abbr> 令牌和安全的密码哈希，让应用真正安全起来。\n\n这些代码可以直接用于你的应用，你可以把密码哈希保存到数据库中，等等。\n\n我们将从上一章结束的地方继续，逐步完善。\n\n## 关于 JWT { #about-jwt }\n\nJWT 意为 “JSON Web Tokens”。\n\n它是一种标准，把一个 JSON 对象编码成没有空格、很密集的一长串字符串。看起来像这样：\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\n它不是加密的，所以任何人都可以从内容中恢复信息。\n\n但它是“签名”的。因此，当你收到一个自己签发的令牌时，你可以验证它确实是你签发的。\n\n这样你就可以创建一个例如有效期为 1 周的令牌。然后当用户第二天带着这个令牌回来时，你能知道该用户仍然处于登录状态。\n\n一周后令牌过期，用户将不再被授权，需要重新登录以获取新令牌。而如果用户（或第三方）尝试修改令牌来更改过期时间，你也能发现，因为签名将不匹配。\n\n如果你想动手体验 JWT 令牌并了解它的工作方式，请访问 [https://jwt.io](https://jwt.io/)。\n\n## 安装 `PyJWT` { #install-pyjwt }\n\n我们需要安装 `PyJWT`，以便在 Python 中生成和校验 JWT 令牌。\n\n请确保创建并激活一个[虚拟环境](../../virtual-environments.md)，然后安装 `pyjwt`：\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info | 信息\n\n如果你计划使用类似 RSA 或 ECDSA 的数字签名算法，你应该安装加密库依赖项 `pyjwt[crypto]`。\n\n可以在 [PyJWT 安装文档](https://pyjwt.readthedocs.io/en/latest/installation.html)中了解更多。\n\n///\n\n## 密码哈希 { #password-hashing }\n\n“哈希”是指把一些内容（这里是密码）转换成看起来像乱码的一串字节（其实就是字符串）。\n\n当你每次传入完全相同的内容（完全相同的密码）时，都会得到完全相同的“乱码”。\n\n但你无法从这个“乱码”反向还原出密码。\n\n### 为什么使用密码哈希 { #why-use-password-hashing }\n\n如果你的数据库被盗，窃贼拿到的不会是用户的明文密码，而只是哈希值。\n\n因此，窃贼无法把该密码拿去尝试登录另一个系统（很多用户在各处都用相同的密码，这将非常危险）。\n\n## 安装 `pwdlib` { #install-pwdlib }\n\npwdlib 是一个用于处理密码哈希的优秀 Python 包。\n\n它支持多种安全的哈希算法以及相关工具。\n\n推荐的算法是 “Argon2”。\n\n请确保创建并激活一个[虚拟环境](../../virtual-environments.md)，然后安装带 Argon2 的 pwdlib：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | 提示\n\n使用 `pwdlib`，你甚至可以把它配置为能够读取由 **Django**、**Flask** 安全插件或其他许多工具创建的密码。\n\n例如，你可以在数据库中让一个 Django 应用和一个 FastAPI 应用共享同一份数据。或者在使用同一个数据库的前提下，逐步迁移一个 Django 应用到 FastAPI。\n\n同时，你的用户既可以从 Django 应用登录，也可以从 **FastAPI** 应用登录。\n\n///\n\n## 哈希并校验密码 { #hash-and-verify-the-passwords }\n\n从 `pwdlib` 导入所需工具。\n\n用推荐设置创建一个 PasswordHash 实例——它将用于哈希与校验密码。\n\n/// tip | 提示\n\npwdlib 也支持 bcrypt 哈希算法，但不包含遗留算法——如果需要处理过时的哈希，建议使用 passlib 库。\n\n例如，你可以用它读取并校验其他系统（如 Django）生成的密码，但对任何新密码使用不同的算法（如 Argon2 或 Bcrypt）进行哈希。\n\n并且能够同时与它们全部兼容。\n\n///\n\n创建一个工具函数来哈希用户传入的密码。\n\n再创建一个工具函数来校验接收的密码是否匹配已存储的哈希。\n\n再创建一个工具函数来进行身份验证并返回用户。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\n当使用一个在数据库中不存在的用户名调用 `authenticate_user` 时，我们仍然会针对一个虚拟哈希运行 `verify_password`。\n\n这可以确保无论用户名是否有效，端点的响应时间大致相同，从而防止可用于枚举已存在用户名的“时间攻击”（timing attacks）。\n\n/// note | 注意\n\n如果你查看新的（伪）数据库 `fake_users_db`，现在你会看到哈希后的密码类似这样：`\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`。\n\n///\n\n## 处理 JWT 令牌 { #handle-jwt-tokens }\n\n导入已安装的模块。\n\n创建一个用于对 JWT 令牌进行签名的随机密钥。\n\n使用下列命令生成一个安全的随机密钥：\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\n把输出复制到变量 `SECRET_KEY`（不要使用示例中的那个）。\n\n创建变量 `ALGORITHM`，设置用于签名 JWT 令牌的算法，这里设为 `\"HS256\"`。\n\n创建一个变量用于设置令牌的过期时间。\n\n定义一个用于令牌端点响应的 Pydantic 模型。\n\n创建一个生成新访问令牌的工具函数。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## 更新依赖项 { #update-the-dependencies }\n\n更新 `get_current_user` 以接收与之前相同的令牌，但这次使用的是 JWT 令牌。\n\n解码接收到的令牌，进行校验，并返回当前用户。\n\n如果令牌无效，立即返回一个 HTTP 错误。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## 更新 `/token` 路径操作 { #update-the-token-path-operation }\n\n用令牌的过期时间创建一个 `timedelta`。\n\n创建一个真正的 JWT 访问令牌并返回它。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### 关于 JWT “主题” `sub` 的技术细节 { #technical-details-about-the-jwt-subject-sub }\n\nJWT 规范中有一个 `sub` 键，表示令牌的“主题”（subject）。\n\n使用它是可选的，但通常会把用户的标识放在这里，所以本例中我们使用它。\n\nJWT 除了用于识别用户并允许其直接在你的 API 上执行操作之外，还可能用于其他场景。\n\n例如，你可以用它来标识一辆“车”或一篇“博客文章”。\n\n然后你可以为该实体添加权限，比如“drive”（用于车）或“edit”（用于博客）。\n\n接着，你可以把这个 JWT 令牌交给一个用户（或机器人），他们就可以在没有账户的前提下，仅凭你的 API 生成的 JWT 令牌来执行这些操作（开车、编辑文章）。\n\n基于这些想法，JWT 可以用于更复杂的场景。\n\n在这些情况下，多个实体可能会有相同的 ID，比如都叫 `foo`（用户 `foo`、车 `foo`、博客文章 `foo`）。\n\n因此，为了避免 ID 冲突，在为用户创建 JWT 令牌时，你可以给 `sub` 键的值加一个前缀，例如 `username:`。所以在这个例子中，`sub` 的值可以是：`username:johndoe`。\n\n需要牢记的一点是，`sub` 键在整个应用中应该是一个唯一标识符，并且它应该是字符串。\n\n## 检查 { #check-it }\n\n运行服务器并打开文档：[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n你会看到这样的用户界面：\n\n<img src=\"/img/tutorial/security/image07.png\">\n\n像之前一样进行授权。\n\n使用以下凭证：\n\n用户名: `johndoe`\n密码: `secret`\n\n/// check | 检查\n\n注意，代码中的任何地方都没有明文密码 “`secret`”，我们只有它的哈希版本。\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\n调用 `/users/me/` 端点，你将得到如下响应：\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\n如果你打开开发者工具，你会看到发送的数据只包含令牌。密码只会在第一个请求中用于认证用户并获取访问令牌，之后就不会再发送密码了：\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | 注意\n\n注意 `Authorization` 请求头，其值以 `Bearer ` 开头。\n\n///\n\n## 使用 `scopes` 的高级用法 { #advanced-usage-with-scopes }\n\nOAuth2 支持 “scopes”（作用域）。\n\n你可以用它们为 JWT 令牌添加一组特定的权限。\n\n然后你可以把这个令牌直接交给用户或第三方，在一组限制条件下与 API 交互。\n\n在**高级用户指南**中你将学习如何使用它们，以及它们如何集成进 **FastAPI**。\n\n## 小结 { #recap }\n\n通过目前所学内容，你可以使用 OAuth2 和 JWT 等标准来搭建一个安全的 **FastAPI** 应用。\n\n在几乎任何框架中，处理安全问题都会很快变得相当复杂。\n\n许多把安全流程大幅简化的包，往往要在数据模型、数据库和可用特性上做出大量妥协。而有些过度简化的包实际上在底层存在安全隐患。\n\n---\n\n**FastAPI** 不会在任何数据库、数据模型或工具上做妥协。\n\n它给予你完全的灵活性，选择最适合你项目的方案。\n\n而且你可以直接使用许多维护良好、广泛使用的包，比如 `pwdlib` 和 `PyJWT`，因为 **FastAPI** 不需要复杂机制来集成外部包。\n\n同时它也为你提供尽可能简化流程的工具，而不牺牲灵活性、健壮性或安全性。\n\n你可以以相对简单的方式使用和实现像 OAuth2 这样的安全、标准协议。\n\n在**高级用户指南**中，你可以进一步了解如何使用 OAuth2 的 “scopes”，以遵循相同标准实现更细粒度的权限系统。带作用域的 OAuth2 是许多大型身份认证提供商（如 Facebook、Google、GitHub、Microsoft、X（Twitter）等）用来授权第三方应用代表其用户与其 API 交互的机制。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/security/simple-oauth2.md",
    "content": "# OAuth2 实现简单的 Password 和 Bearer 验证 { #simple-oauth2-with-password-and-bearer }\n\n本章添加上一章示例中欠缺的部分，实现完整的安全流。\n\n## 获取 `username` 和 `password` { #get-the-username-and-password }\n\n首先，使用 **FastAPI** 安全工具获取 `username` 和 `password`。\n\nOAuth2 规范要求使用“密码流”时，客户端或用户必须以表单数据形式发送 `username` 和 `password` 字段。\n\n并且，这两个字段必须命名为 `username` 和 `password`，不能使用 `user-name` 或 `email` 等其它名称。\n\n不过也不用担心，前端仍可以显示终端用户所需的名称。\n\n数据库模型也可以使用所需的名称。\n\n但对于登录*路径操作*，则要使用兼容规范的 `username` 和 `password`，（例如，实现与 API 文档集成）。\n\n该规范要求必须以表单数据形式发送 `username` 和 `password`，因此，不能使用 JSON 对象。\n\n### `scope` { #scope }\n\nOAuth2 还支持客户端发送**`scope`**表单字段。\n\n虽然表单字段的名称是 `scope`（单数），但实际上，它是以空格分隔的，由多个**scope**组成的长字符串。\n\n**作用域**只是不带空格的字符串。\n\n常用于声明指定安全权限，例如：\n\n* 常见用例为，`users:read` 或 `users:write`\n* 脸书和 Instagram 使用 `instagram_basic`\n* 谷歌使用 `https://www.googleapis.com/auth/drive`\n\n/// info | 信息\n\nOAuth2 中，**作用域**只是声明指定权限的字符串。\n\n是否使用冒号 `:` 等符号，或是不是 URL 并不重要。\n\n这些细节只是特定的实现方式。\n\n对 OAuth2 来说，都只是字符串而已。\n\n///\n\n## 获取 `username` 和 `password` 的代码 { #code-to-get-the-username-and-password }\n\n接下来，使用 **FastAPI** 工具获取用户名与密码。\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\n首先，导入 `OAuth2PasswordRequestForm`，然后，在 `/token` *路径操作* 中，用 `Depends` 把该类作为依赖项。\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm` 是用以下几项内容声明表单请求体的类依赖项：\n\n* `username`\n* `password`\n* 可选的 `scope` 字段，由多个空格分隔的字符串组成的长字符串\n* 可选的 `grant_type`\n\n/// tip | 提示\n\n实际上，OAuth2 规范*要求* `grant_type` 字段使用固定值 `password`，但 `OAuth2PasswordRequestForm` 没有作强制约束。\n\n如需强制使用固定值 `password`，则不要用 `OAuth2PasswordRequestForm`，而是用 `OAuth2PasswordRequestFormStrict`。\n\n///\n\n* 可选的 `client_id`（本例未使用）\n* 可选的 `client_secret`（本例未使用）\n\n/// info | 信息\n\n`OAuth2PasswordRequestForm` 并不像 `OAuth2PasswordBearer` 那样是 **FastAPI** 的特殊类。\n\n**FastAPI** 把 `OAuth2PasswordBearer` 识别为安全方案。因此，可以通过这种方式把它添加至 OpenAPI。\n\n但 `OAuth2PasswordRequestForm` 只是可以自行编写的类依赖项，也可以直接声明 `Form` 参数。\n\n但由于这种用例很常见，FastAPI 为了简便，就直接提供了对它的支持。\n\n///\n\n### 使用表单数据 { #use-the-form-data }\n\n/// tip | 提示\n\n`OAuth2PasswordRequestForm` 类依赖项的实例没有以空格分隔的长字符串属性 `scope`，但它支持 `scopes` 属性，由已发送的 scope 字符串列表组成。\n\n本例没有使用 `scopes`，但开发者也可以根据需要使用该属性。\n\n///\n\n现在，即可使用表单字段 `username`，从（伪）数据库中获取用户数据。\n\n如果不存在指定用户，则返回错误消息，提示**用户名或密码错误**。\n\n本例使用 `HTTPException` 异常显示此错误：\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### 校验密码 { #check-the-password }\n\n至此，我们已经从数据库中获取了用户数据，但尚未校验密码。\n\n接下来，首先将数据放入 Pydantic 的 `UserInDB` 模型。\n\n注意：永远不要保存明文密码，本例暂时先使用（伪）哈希密码系统。\n\n如果密码不匹配，则返回与上面相同的错误。\n\n#### 密码哈希 { #password-hashing }\n\n**哈希**是指，将指定内容（本例中为密码）转换为形似乱码的字节序列（其实就是字符串）。\n\n每次传入完全相同的内容（比如，完全相同的密码）时，得到的都是完全相同的乱码。\n\n但这个乱码无法转换回传入的密码。\n\n##### 为什么使用密码哈希 { #why-use-password-hashing }\n\n原因很简单，假如数据库被盗，窃贼无法获取用户的明文密码，得到的只是哈希值。\n\n这样一来，窃贼就无法在其它应用中使用窃取的密码，要知道，很多用户在所有系统中都使用相同的密码，风险超大。\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### 关于 `**user_dict` { #about-user-dict }\n\n`UserInDB(**user_dict)` 是指：\n\n*直接把 `user_dict` 的键与值当作关键字参数传递，等效于：*\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info | 信息\n\n`user_dict` 的说明，详见[**更多模型**一章](../extra-models.md#about-user-in-dict)。\n\n///\n\n## 返回 Token { #return-the-token }\n\n`token` 端点的响应必须是 JSON 对象。\n\n响应返回的内容应该包含 `token_type`。本例中用的是**Bearer**Token，因此， Token 类型应为**`bearer`**。\n\n返回内容还应包含 `access_token` 字段，它是包含权限 Token 的字符串。\n\n本例只是简单的演示，返回的 Token 就是 `username`，但这种方式极不安全。\n\n/// tip | 提示\n\n下一章介绍使用哈希密码和 <abbr title=\"JSON Web Tokens - JSON Web 令牌\">JWT</abbr> Token 的真正安全机制。\n\n但现在，仅关注所需的特定细节。\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip | 提示\n\n按规范的要求，应像本示例一样，返回带有 `access_token` 和 `token_type` 的 JSON 对象。\n\n这是开发者必须在代码中自行完成的工作，并且要确保使用这些 JSON 的键。\n\n这几乎是唯一需要开发者牢记在心，并按规范要求正确执行的事。\n\n**FastAPI** 则负责处理其它的工作。\n\n///\n\n## 更新依赖项 { #update-the-dependencies }\n\n接下来，更新依赖项。\n\n使之仅在当前用户为激活状态时，才能获取 `current_user`。\n\n为此，要再创建一个依赖项 `get_current_active_user`，此依赖项以 `get_current_user` 依赖项为基础。\n\n如果用户不存在，或状态为未激活，这两个依赖项都会返回 HTTP 错误。\n\n因此，在端点中，只有当用户存在、通过身份验证、且状态为激活时，才能获得该用户：\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info | 信息\n\n此处返回值为 `Bearer` 的响应头 `WWW-Authenticate` 也是规范的一部分。\n\n任何 401“UNAUTHORIZED”HTTP（错误）状态码都应返回 `WWW-Authenticate` 响应头。\n\n本例中，因为使用的是 Bearer Token，该响应头的值应为 `Bearer`。\n\n实际上，忽略这个附加响应头，也不会有什么问题。\n\n之所以在此提供这个附加响应头，是为了符合规范的要求。\n\n说不定什么时候，就有工具用得上它，而且，开发者或用户也可能用得上。\n\n这就是遵循标准的好处...\n\n///\n\n## 实际效果 { #see-it-in-action }\n\n打开交互式文档：[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n### 身份验证 { #authenticate }\n\n点击“Authorize”按钮。\n\n使用以下凭证：\n\n用户名：`johndoe`\n\n密码：`secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\n通过身份验证后，显示下图所示的内容：\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### 获取当前用户数据 { #get-your-own-user-data }\n\n使用 `/users/me` 路径的 `GET` 操作。\n\n可以提取如下当前用户数据：\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\n点击小锁图标，注销后，再执行同样的操作，则会得到 HTTP 401 错误：\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### 未激活用户 { #inactive-user }\n\n测试未激活用户，输入以下信息，进行身份验证：\n\n用户名：`alice`\n\n密码：`secret2`\n\n然后，执行 `/users/me` 路径的 `GET` 操作。\n\n显示下列**未激活用户**错误信息：\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## 小结 { #recap }\n\n使用本章的工具实现基于 `username` 和 `password` 的完整 API 安全系统。\n\n这些工具让安全系统兼容任何数据库、用户及数据模型。\n\n唯一欠缺的是，它仍然不是真的**安全**。\n\n下一章你将看到如何使用安全的密码哈希库和 <abbr title=\"JSON Web Tokens - JSON Web 令牌\">JWT</abbr> 令牌。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/server-sent-events.md",
    "content": "# 服务器发送事件（SSE） { #server-sent-events-sse }\n\n你可以使用**服务器发送事件**（SSE）向客户端流式发送数据。\n\n这类似于[流式传输 JSON Lines](stream-json-lines.md)，但使用 `text/event-stream` 格式，浏览器原生通过 [`EventSource` API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) 支持。\n\n/// info | 信息\n\n新增于 FastAPI 0.135.0。\n\n///\n\n## 什么是服务器发送事件？ { #what-are-server-sent-events }\n\nSSE 是一种通过 HTTP 从服务器向客户端流式传输数据的标准。\n\n每个事件是一个带有 `data`、`event`、`id` 和 `retry` 等“字段”的小文本块，以空行分隔。\n\n看起来像这样：\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE 常用于 AI 聊天流式输出、实时通知、日志与可观测性，以及其他服务器向客户端推送更新的场景。\n\n/// tip | 提示\n\n如果你想流式传输二进制数据（例如视频或音频），请查看高级指南：[流式传输数据](../advanced/stream-data.md)。\n\n///\n\n## 使用 FastAPI 流式传输 SSE { #stream-sse-with-fastapi }\n\n要在 FastAPI 中流式传输 SSE，在你的*路径操作函数*中使用 `yield`，并设置 `response_class=EventSourceResponse`。\n\n从 `fastapi.sse` 导入 `EventSourceResponse`：\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\n每个被 yield 的项会被编码为 JSON，并放入 SSE 事件的 `data:` 字段发送。\n\n如果你将返回类型声明为 `AsyncIterable[Item]`，FastAPI 将使用它通过 Pydantic对数据进行**校验**、**文档化**和**序列化**。\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip | 提示\n\n由于 Pydantic 会在**Rust** 端序列化它，相比未声明返回类型，你将获得更高的**性能**。\n\n///\n\n### 非 async 的*路径操作函数* { #non-async-path-operation-functions }\n\n你也可以使用常规的 `def` 函数（没有 `async`），并以同样的方式使用 `yield`。\n\nFastAPI 会确保其正确运行，从而不阻塞事件循环。\n\n由于此时函数不是 async，正确的返回类型应为 `Iterable[Item]`：\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### 无返回类型 { #no-return-type }\n\n你也可以省略返回类型。FastAPI 将使用 [`jsonable_encoder`](./encoder.md) 转换数据并发送。\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\n如果你需要设置 `event`、`id`、`retry` 或 `comment` 等 SSE 字段，你可以 yield `ServerSentEvent` 对象，而不是直接返回数据。\n\n从 `fastapi.sse` 导入 `ServerSentEvent`：\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\n`data` 字段始终会被编码为 JSON。你可以传入任何可被序列化为 JSON 的值，包括 Pydantic 模型。\n\n## 原始数据 { #raw-data }\n\n如果你需要发送**不**进行 JSON 编码的数据，请使用 `raw_data` 而不是 `data`。\n\n这对于发送预格式化文本、日志行或特殊的 <dfn title=\"用于指示特殊条件或状态的值\">\"哨兵\"</dfn> 值（例如 `[DONE]`）很有用。\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note | 注意\n\n`data` 和 `raw_data` 是互斥的。每个 `ServerSentEvent` 上只能设置其中一个。\n\n///\n\n## 使用 `Last-Event-ID` 恢复 { #resuming-with-last-event-id }\n\n当连接中断后浏览器重新连接时，会在 `Last-Event-ID` 头中发送上次收到的 `id`。\n\n你可以将其读取为一个请求头参数，并据此从客户端离开的地方恢复流：\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## 使用 POST 的 SSE { #sse-with-post }\n\nSSE 适用于**任意 HTTP 方法**，不仅仅是 `GET`。\n\n这对像 [MCP](https://modelcontextprotocol.io) 这样通过 `POST` 传输 SSE 的协议很有用：\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## 技术细节 { #technical-details }\n\nFastAPI 开箱即用地实现了一些 SSE 的最佳实践。\n\n- 当 15 秒内没有任何消息时，发送一个**保活 `ping` 注释**，以防某些代理关闭连接，正如 [HTML 规范：Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes) 中建议的那样。\n- 设置 `Cache-Control: no-cache` 响应头，**防止缓存**流。\n- 设置特殊响应头 `X-Accel-Buffering: no`，以**防止**某些代理（如 Nginx）**缓冲**。\n\n你无需做任何事，它开箱即用。🤓\n"
  },
  {
    "path": "docs/zh/docs/tutorial/sql-databases.md",
    "content": "# SQL（关系型）数据库 { #sql-relational-databases }\n\n**FastAPI** 并不要求你使用 SQL（关系型）数据库。你可以使用你想用的**任何数据库**。\n\n这里，我们来看一个使用 [SQLModel](https://sqlmodel.tiangolo.com/) 的示例。\n\n**SQLModel** 基于 [SQLAlchemy](https://www.sqlalchemy.org/) 和 Pydantic 构建。它由 **FastAPI** 的同一作者制作，旨在完美匹配需要使用**SQL 数据库**的 FastAPI 应用程序。\n\n/// tip | 提示\n\n你可以使用任意其他你想要的 SQL 或 NoSQL 数据库库（在某些情况下称为 <abbr title=\"Object Relational Mapper - 对象关系映射器: 一个术语，用来指代一种库，其中某些类表示 SQL 表，这些类的实例表示这些表中的行\">\"ORMs\"</abbr>），FastAPI 不会强迫你使用任何东西。😎\n\n///\n\n由于 SQLModel 基于 SQLAlchemy，因此你可以轻松使用任何由 SQLAlchemy **支持的数据库**（这也让它们被 SQLModel 支持），例如：\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server 等\n\n在这个示例中，我们将使用 **SQLite**，因为它使用单个文件，并且 Python 对其有集成支持。因此，你可以直接复制这个示例并运行。\n\n之后，对于你的生产应用程序，你可能会想要使用像 **PostgreSQL** 这样的数据库服务器。\n\n/// tip | 提示\n\n有一个使用 **FastAPI** 和 **PostgreSQL** 的官方项目生成器，其中包括了前端和更多工具： [https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\n这是一个非常简单和简短的教程。如果你想了解一般的数据库、SQL 或更高级的功能，请查看 [SQLModel 文档](https://sqlmodel.tiangolo.com/)。\n\n## 安装 `SQLModel` { #install-sqlmodel }\n\n首先，确保你创建并激活了[虚拟环境](../virtual-environments.md)，然后安装 `sqlmodel`：\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## 创建含有单一模型的应用 { #create-the-app-with-a-single-model }\n\n我们先创建应用的最简单的第一个版本，只有一个 **SQLModel** 模型。\n\n稍后我们将通过下面的**多个模型**提高其安全性和多功能性。🤓\n\n### 创建模型 { #create-models }\n\n导入 `SQLModel` 并创建一个数据库模型：\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\n`Hero` 类与 Pydantic 模型非常相似（实际上，从底层来看，它确实就是一个 Pydantic 模型）。\n\n有一些区别：\n\n* `table=True` 会告诉 SQLModel 这是一个*表模型*，它应该表示 SQL 数据库中的一个**表**，而不仅仅是一个*数据模型*（就像其他常规的 Pydantic 类一样）。\n\n* `Field(primary_key=True)` 会告诉 SQLModel `id` 是 SQL 数据库中的**主键**（你可以在 SQLModel 文档中了解更多关于 SQL 主键的信息）。\n\n    **注意：** 我们为主键字段使用 `int | None`，这样在 Python 代码中我们可以在没有 `id`（`id=None`）的情况下创建对象，并假定数据库在保存时会生成它。SQLModel 会理解数据库会提供 `id`，并在数据库模式中将该列定义为非空的 `INTEGER`。详见 [SQLModel 关于主键的文档](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id)。\n\n* `Field(index=True)` 会告诉 SQLModel 应该为此列创建一个 **SQL 索引**，这样在读取按此列过滤的数据时，程序能在数据库中进行更快的查找。\n\n    SQLModel 会知道声明为 `str` 的内容将是类型为 `TEXT`（或 `VARCHAR`，具体取决于数据库）的 SQL 列。\n\n### 创建引擎（Engine） { #create-an-engine }\n\nSQLModel 的 `engine`（实际上它是一个 SQLAlchemy 的 `engine`）是用来与数据库**保持连接**的。\n\n你只需构建**一个 `engine` 对象**，让你的所有代码连接到同一个数据库。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\n使用 `check_same_thread=False` 可以让 FastAPI 在不同线程中使用同一个 SQLite 数据库。这很有必要，因为**单个请求**可能会使用**多个线程**（例如在依赖项中）。\n\n不用担心，我们会按照代码结构确保**每个请求使用一个单独的 SQLModel 会话（session）**，这实际上就是 `check_same_thread` 想要实现的。\n\n### 创建表 { #create-the-tables }\n\n然后，我们来添加一个函数，使用 `SQLModel.metadata.create_all(engine)` 为所有*表模型***创建表**。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### 创建会话（Session）依赖项 { #create-a-session-dependency }\n\n**`Session`** 会存储**内存中的对象**并跟踪数据中所需更改的内容，然后它**使用 `engine`** 与数据库进行通信。\n\n我们会使用 `yield` 创建一个 FastAPI **依赖项**，为每个请求提供一个新的 `Session`。这确保我们每个请求使用一个单独的会话。🤓\n\n然后我们创建一个 `Annotated` 的依赖项 `SessionDep` 来简化其他也会用到此依赖的代码。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### 在启动时创建数据库表 { #create-database-tables-on-startup }\n\n我们会在应用程序启动时创建数据库表。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\n此处，在应用程序启动事件中，我们创建了表。\n\n在生产环境中，你可能会使用一个在启动应用程序之前运行的迁移脚本。🤓\n\n/// tip | 提示\n\nSQLModel 将会拥有封装 Alembic 的迁移工具，但目前你可以直接使用 [Alembic](https://alembic.sqlalchemy.org/en/latest/)。\n\n///\n\n### 创建 Hero { #create-a-hero }\n\n因为每个 SQLModel 模型同时也是一个 Pydantic 模型，所以你可以在与 Pydantic 模型相同的**类型注解**中使用它。\n\n例如，如果你声明一个类型为 `Hero` 的参数，它将从 **JSON 主体**中读取数据。\n\n同样，你可以将其声明为函数的**返回类型**，然后数据的结构就会显示在自动生成的 API 文档界面中。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\n这里，我们使用 `SessionDep` 依赖项（一个 `Session`）将新的 `Hero` 添加到 `Session` 实例中，提交更改到数据库，刷新 `hero` 中的数据，并返回它。\n\n### 读取 Hero { #read-heroes }\n\n我们可以使用 `select()` 从数据库中**读取** `Hero`，并利用 `limit` 和 `offset` 来对结果进行分页。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### 读取单个 Hero { #read-one-hero }\n\n我们可以**读取**单个 `Hero`。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### 删除单个 Hero { #delete-a-hero }\n\n我们也可以**删除**一个 `Hero`。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### 运行应用 { #run-the-app }\n\n你可以运行这个应用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n然后在 `/docs` UI 中，你能够看到 **FastAPI** 会用这些**模型**来**记录** API，并且还会用它们来**序列化**和**验证**数据。\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## 使用多个模型更新应用 { #update-the-app-with-multiple-models }\n\n现在让我们稍微**重构**一下这个应用，以提高**安全性**和**多功能性**。\n\n如果你查看之前的应用程序，你可以在 UI 界面中看到，到目前为止，它允许客户端决定要创建的 `Hero` 的 `id`。😱\n\n我们不应该允许这样做，因为他们可能会覆盖我们在数据库中已经分配的 `id`。决定 `id` 的行为应该由**后端**或**数据库**来完成，**而非客户端**。\n\n此外，我们为 hero 创建了一个 `secret_name`，但到目前为止，我们在各处都返回了它，这就不太**秘密**了……😅\n\n我们将通过添加一些**额外的模型**来解决这些问题，而 SQLModel 将在这里大放异彩。✨\n\n### 创建多个模型 { #create-multiple-models }\n\n在 **SQLModel** 中，任何含有 `table=True` 属性的模型类都是一个**表模型**。\n\n任何不含有 `table=True` 属性的模型类都是**数据模型**，这些实际上只是 Pydantic 模型（附带一些小的额外功能）。🤓\n\n有了 SQLModel，我们就可以利用**继承**来在所有情况下**避免重复**所有字段。\n\n#### `HeroBase` - 基类 { #herobase-the-base-class }\n\n我们从一个 `HeroBase` 模型开始，该模型具有所有模型**共享的字段**：\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` - *表模型* { #hero-the-table-model }\n\n接下来，我们创建 `Hero`，实际的*表模型*，并添加那些不总是在其他模型中的**额外字段**：\n\n* `id`\n* `secret_name`\n\n因为 `Hero` 继承自 `HeroBase`，所以它**也**包含了在 `HeroBase` 中声明过的**字段**。因此 `Hero` 的所有字段为：\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` - 公共*数据模型* { #heropublic-the-public-data-model }\n\n接下来，我们创建一个 `HeroPublic` 模型，这是将**返回**给 API 客户端的模型。\n\n它包含与 `HeroBase` 相同的字段，因此不会包括 `secret_name`。\n\n终于，我们英雄的身份得到了保护！🥷\n\n它还重新声明了 `id: int`。这样我们便与 API 客户端建立了一种**约定**，使他们始终可以期待 `id` 存在并且是一个整数 `int`（永远不会是 `None`）。\n\n/// tip | 提示\n\n确保返回模型始终提供一个值并且始终是 `int`（而不是 `None`）对 API 客户端非常有用，他们可以在这种确定性下编写更简单的代码。\n\n此外，**自动生成的客户端**将拥有更简洁的接口，这样与你的 API 交互的开发者就能更轻松地使用你的 API。😎\n\n///\n\n`HeroPublic` 中的所有字段都与 `HeroBase` 中的相同，其中 `id` 声明为 `int`（不是 `None`）：\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` - 用于创建 hero 的*数据模型* { #herocreate-the-data-model-to-create-a-hero }\n\n现在我们创建一个 `HeroCreate` 模型，这是用于**验证**客户端数据的模型。\n\n它不仅拥有与 `HeroBase` 相同的字段，还有 `secret_name`。\n\n现在，当客户端**创建一个新的 hero** 时，他们会发送 `secret_name`，它会被存储到数据库中，但这些 `secret_name` 不会通过 API 返回给客户端。\n\n/// tip | 提示\n\n这应当是**密码**被处理的方式：接收密码，但不要通过 API 返回它们。\n\n在存储密码之前，你还应该对密码的值进行**哈希**处理，**绝不要以明文形式存储它们**。\n\n///\n\n`HeroCreate` 的字段包括：\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` - 用于更新 hero 的*数据模型* { #heroupdate-the-data-model-to-update-a-hero }\n\n在之前的应用程序中，我们没有办法**更新 hero**，但现在有了**多个模型**，我们便能做到这一点了。🎉\n\n`HeroUpdate` *数据模型*有些特殊，它包含创建新 hero 所需的**所有相同字段**，但所有字段都是**可选的**（它们都有默认值）。这样，当你更新一个 hero 时，你可以只发送你想要更新的字段。\n\n因为所有**字段实际上**都发生了**变化**（类型现在包括 `None`，并且它们现在有一个默认值 `None`），我们需要**重新声明**它们。\n\n我们并不真的需要从 `HeroBase` 继承，因为我们会重新声明所有字段。我会让它继承只是为了保持一致，但这并不必要。这更多是个人喜好的问题。🤷\n\n`HeroUpdate` 的字段包括：\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### 使用 `HeroCreate` 创建并返回 `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }\n\n既然我们有了**多个模型**，我们就可以对使用它们的应用程序部分进行更新。\n\n我们在请求中接收到一个 `HeroCreate` *数据模型*，然后从中创建一个 `Hero` *表模型*。\n\n这个新的*表模型* `Hero` 会包含客户端发送的字段，以及一个由数据库生成的 `id`。\n\n然后我们将与函数中相同的*表模型* `Hero` 原样返回。但是由于我们使用 `HeroPublic` *数据模型*声明了 `response_model`，**FastAPI** 会使用 `HeroPublic` 来验证和序列化数据。\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | 提示\n\n现在我们使用 `response_model=HeroPublic` 来代替**返回类型注解** `-> HeroPublic`，因为我们返回的值实际上并不是 `HeroPublic`。\n\n如果我们声明了 `-> HeroPublic`，你的编辑器和代码检查工具会（理所应当地）抱怨你返回了一个 `Hero` 而不是一个 `HeroPublic`。\n\n通过 `response_model` 的声明，我们让 **FastAPI** 按照它自己的方式处理，而不会干扰类型注解以及编辑器和其他工具提供的帮助。\n\n///\n\n### 使用 `HeroPublic` 读取 Hero { #read-heroes-with-heropublic }\n\n我们可以像之前一样**读取** `Hero`，同样，使用 `response_model=list[HeroPublic]` 确保正确地验证和序列化数据。\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### 使用 `HeroPublic` 读取单个 Hero { #read-one-hero-with-heropublic }\n\n我们可以**读取**单个 hero：\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### 使用 `HeroUpdate` 更新单个 Hero { #update-a-hero-with-heroupdate }\n\n我们可以**更新**单个 hero。为此，我们会使用 HTTP 的 `PATCH` 操作。\n\n在代码中，我们会得到一个 `dict`，其中包含客户端发送的所有数据，**只有客户端发送的数据**，并排除了任何一个仅仅作为默认值存在的值。为此，我们使用 `exclude_unset=True`。这是最主要的技巧。🪄\n\n然后我们会使用 `hero_db.sqlmodel_update(hero_data)`，来利用 `hero_data` 的数据更新 `hero_db`。\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### （再次）删除单个 Hero { #delete-a-hero-again }\n\n**删除**一个 hero 基本保持不变。\n\n我们不会满足在这一部分中重构一切的愿望。😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### （再次）运行应用 { #run-the-app-again }\n\n你可以再运行一次应用程序：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n如果你进入 `/docs` API UI，你会看到它现在已经更新，并且在创建 hero 时，它不会再期望从客户端接收 `id` 数据等。\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## 总结 { #recap }\n\n你可以使用 [**SQLModel**](https://sqlmodel.tiangolo.com/) 与 SQL 数据库进行交互，并通过*数据模型*和*表模型*简化代码。\n\n你可以在 **SQLModel** 文档中学习到更多内容，其中有一个更详细的[将 SQLModel 与 **FastAPI** 一起使用的迷你教程](https://sqlmodel.tiangolo.com/tutorial/fastapi/)。🚀\n"
  },
  {
    "path": "docs/zh/docs/tutorial/static-files.md",
    "content": "# 静态文件 { #static-files }\n\n你可以使用 `StaticFiles` 从目录中自动提供静态文件。\n\n## 使用 `StaticFiles` { #use-staticfiles }\n\n* 导入 `StaticFiles`。\n* 将一个 `StaticFiles()` 实例“挂载”（Mount）到指定路径。\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | 技术细节\n\n你也可以用 `from starlette.staticfiles import StaticFiles`。\n\n**FastAPI** 提供了和 `starlette.staticfiles` 相同的 `fastapi.staticfiles`，只是为了方便你这个开发者。但它确实直接来自 Starlette。\n\n///\n\n### 什么是“挂载”（Mounting） { #what-is-mounting }\n\n“挂载”表示在特定路径添加一个完全“独立”的应用，然后负责处理所有子路径。\n\n这与使用 `APIRouter` 不同，因为挂载的应用是完全独立的。主应用的 OpenAPI 和文档不会包含已挂载应用的任何内容，等等。\n\n你可以在[高级用户指南](../advanced/index.md)中了解更多。\n\n## 细节 { #details }\n\n第一个 `\"/static\"` 指的是这个“子应用”将被“挂载”到的子路径。因此，任何以 `\"/static\"` 开头的路径都会由它处理。\n\n`directory=\"static\"` 指的是包含你的静态文件的目录名称。\n\n`name=\"static\"` 为它提供了一个可被 **FastAPI** 内部使用的名称。\n\n这些参数都可以不是“`static`”，请根据你的应用需求和具体细节进行调整。\n\n## 更多信息 { #more-info }\n\n更多细节和选项请查阅 [Starlette 的静态文件文档](https://www.starlette.dev/staticfiles/)。\n"
  },
  {
    "path": "docs/zh/docs/tutorial/stream-json-lines.md",
    "content": "# 流式传输 JSON Lines { #stream-json-lines }\n\n当你想以“流”的方式发送一系列数据时，可以使用 JSON Lines。\n\n/// info | 信息\n\n新增于 FastAPI 0.134.0。\n\n///\n\n## 什么是流 { #what-is-a-stream }\n\n“流式传输”数据意味着你的应用会在整段数据全部准备好之前，就开始把每个数据项发送给客户端。\n\n也就是说，它会先发送第一个数据项，客户端会接收并开始处理它，而此时你的应用可能还在生成下一个数据项。\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\n它甚至可以是一个无限流，你可以一直持续发送数据。\n\n## JSON Lines { #json-lines }\n\n在这些场景中，常见的做法是发送 “JSON Lines”，这是一种每行发送一个 JSON 对象的格式。\n\n响应的内容类型是 `application/jsonl`（而不是 `application/json`），响应体类似这样：\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\n它与 JSON 数组（相当于 Python 的 list）非常相似，但不是用 `[]` 包裹、并在各项之间使用 `,` 分隔，而是每行一个 JSON 对象，彼此以换行符分隔。\n\n/// info | 信息\n\n关键在于你的应用可以逐行生成数据，而客户端在消费前面的行。\n\n///\n\n/// note | 技术细节\n\n由于每个 JSON 对象将以换行分隔，它们的内容中不能包含字面量换行符，但可以包含转义换行符（`\\n`），这属于 JSON 标准的一部分。\n\n不过通常你无需操心，这些都会自动完成，继续阅读即可。🤓\n\n///\n\n## 使用场景 { #use-cases }\n\n你可以用它来从 AI LLM 服务、日志或遥测中流式传输数据，或其他可以用 JSON 项目来结构化的数据。\n\n/// tip | 提示\n\n如果你想流式传输二进制数据，例如视频或音频，请查看进阶指南：[流式传输数据](../advanced/stream-data.md)。\n\n///\n\n## 使用 FastAPI 流式传输 JSON Lines { #stream-json-lines-with-fastapi }\n\n要在 FastAPI 中流式传输 JSON Lines，可以在路径操作函数中不用 `return`，而是用 `yield` 逐个产生每个数据项。\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\n如果你要返回的每个 JSON 项是类型 `Item`（一个 Pydantic 模型），并且这是一个异步函数，你可以将返回类型声明为 `AsyncIterable[Item]`：\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\n如果你声明了返回类型，FastAPI 会用它来验证数据、在 OpenAPI 中生成文档、进行过滤，并使用 Pydantic 进行序列化。\n\n/// tip | 提示\n\n由于 Pydantic 会在 Rust 侧进行序列化，如果你声明了返回类型，将获得更高的性能。\n\n///\n\n### 非异步的*路径操作函数* { #non-async-path-operation-functions }\n\n你也可以使用常规的 `def` 函数（不带 `async`），并以同样的方式使用 `yield`。\n\nFastAPI 会确保其正确运行，不会阻塞事件循环。\n\n因为这个函数不是异步的，合适的返回类型是 `Iterable[Item]`：\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### 无返回类型 { #no-return-type }\n\n你也可以省略返回类型。此时 FastAPI 会使用 [`jsonable_encoder`](./encoder.md) 将数据转换为可序列化为 JSON 的形式，然后以 JSON Lines 发送。\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## 服务器发送事件（SSE） { #server-sent-events-sse }\n\nFastAPI 还对 Server-Sent Events（SSE）提供一等支持，它们与此非常相似，但有一些额外细节。你可以在下一章了解更多：[服务器发送事件（SSE）](server-sent-events.md)。🤓\n"
  },
  {
    "path": "docs/zh/docs/tutorial/testing.md",
    "content": "# 测试 { #testing }\n\n感谢 [Starlette](https://www.starlette.dev/testclient/)，测试**FastAPI** 应用轻松又愉快。\n\n它基于 [HTTPX](https://www.python-httpx.org)，而HTTPX又是基于Requests设计的，所以很相似且易懂。\n\n有了它，你可以直接与**FastAPI**一起使用 [pytest](https://docs.pytest.org/)。\n\n## 使用 `TestClient` { #using-testclient }\n\n/// info | 信息\n\n要使用 `TestClient`，先要安装 [`httpx`](https://www.python-httpx.org)。\n\n确保你创建并激活一个[虚拟环境](../virtual-environments.md)，然后再安装，例如：\n\n```console\n$ pip install httpx\n```\n\n///\n\n导入 `TestClient`。\n\n通过传入你的**FastAPI**应用创建一个 `TestClient` 。\n\n创建名字以 `test_` 开头的函数（这是标准的 `pytest` 约定）。\n\n像使用 `httpx` 那样使用 `TestClient` 对象。\n\n为你需要检查的地方用标准的Python表达式写个简单的 `assert` 语句（重申，标准的`pytest`）。\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip | 提示\n\n注意测试函数是普通的 `def`，不是 `async def`。\n\n还有client的调用也是普通的调用，不是用 `await`。\n\n这让你可以直接使用 `pytest` 而不会遇到麻烦。\n\n///\n\n/// note | 技术细节\n\n你也可以用 `from starlette.testclient import TestClient`。\n\n**FastAPI** 提供了和 `starlette.testclient` 一样的 `fastapi.testclient`，只是为了方便开发者。但它直接来自Starlette。\n\n///\n\n/// tip | 提示\n\n除了发送请求之外，如果你还想测试时在FastAPI应用中调用 `async` 函数（例如异步数据库函数）， 可以在高级教程中看下 [Async Tests](../advanced/async-tests.md) 。\n\n///\n\n## 分离测试 { #separating-tests }\n\n在实际应用中，你可能会把你的测试放在另一个文件里。\n\n您的**FastAPI**应用程序也可能由一些文件/模块组成等等。\n\n### **FastAPI** app 文件 { #fastapi-app-file }\n\n假设你有一个像[更大的应用](bigger-applications.md)中所描述的文件结构:\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\n在 `main.py` 文件中你有一个 **FastAPI** app:\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### 测试文件 { #testing-file }\n\n然后你会有一个包含测试的文件 `test_main.py` 。app可以像Python包那样存在（一样是目录，但有个 `__init__.py` 文件）：\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n因为这文件在同一个包中，所以你可以通过相对导入从 `main` 模块（`main.py`）导入`app`对象：\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n...然后测试代码和之前一样的。\n\n## 测试：扩展示例 { #testing-extended-example }\n\n现在让我们扩展这个例子，并添加更多细节，看下如何测试不同部分。\n\n### 扩展后的 **FastAPI** app 文件 { #extended-fastapi-app-file }\n\n让我们继续之前的文件结构：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n假设现在包含**FastAPI** app的文件 `main.py` 有些其他**路径操作**。\n\n有个 `GET` 操作会返回错误。\n\n有个 `POST` 操作会返回一些错误。\n\n所有*路径操作* 都需要一个`X-Token` 头。\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### 扩展后的测试文件 { #extended-testing-file }\n\n然后您可以使用扩展后的测试更新`test_main.py`：\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\n每当你需要客户端在请求中传递信息，但你不知道如何传递时，你可以通过搜索（谷歌）如何用 `httpx` 做，或者是用 `requests` 做，毕竟HTTPX的设计是基于Requests的设计的。\n\n接着只需在测试中同样操作。\n\n示例：\n\n* 传一个*路径* 或*查询* 参数，添加到URL上。\n* 传一个JSON体，传一个Python对象(例如一个`dict`)到参数 `json`。\n* 如果你需要发送 *Form Data* 而不是 JSON，使用 `data` 参数。\n* 要发送 *headers*，传 `dict` 给 `headers` 参数。\n* 对于 *cookies*，传 `dict` 给 `cookies` 参数。\n\n关于如何传数据给后端的更多信息（使用 `httpx` 或 `TestClient`），请查阅 [HTTPX 文档](https://www.python-httpx.org)。\n\n/// info | 信息\n\n注意 `TestClient` 接收可以被转化为JSON的数据，而不是Pydantic模型。\n\n如果你在测试中有一个Pydantic模型，并且你想在测试时发送它的数据给应用，你可以使用在[JSON Compatible Encoder](encoder.md)介绍的`jsonable_encoder` 。\n\n///\n\n## 运行起来 { #run-it }\n\n之后，你只需要安装 `pytest`。\n\n确保你创建并激活一个[虚拟环境](../virtual-environments.md)，然后再安装，例如：\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\n他会自动检测文件和测试，执行测试，然后向你报告结果。\n\n执行测试：\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/zh/docs/virtual-environments.md",
    "content": "# 虚拟环境 { #virtual-environments }\n\n当你在 Python 工程中工作时，你可能会有必要用到一个**虚拟环境**（或类似的机制）来隔离你为每个工程安装的包。\n\n/// info | 信息\n\n如果你已经了解虚拟环境，知道如何创建和使用它们，你可以考虑跳过这一部分。🤓\n\n///\n\n/// tip | 提示\n\n**虚拟环境**和**环境变量**是不同的。\n\n**环境变量**是系统中的一个变量，可以被程序使用。\n\n**虚拟环境**是一个包含一些文件的目录。\n\n///\n\n/// info | 信息\n\n这个页面将教你如何使用**虚拟环境**以及了解它们的工作原理。\n\n如果你计划使用一个**可以为你管理一切的工具**（包括安装 Python），试试 [uv](https://github.com/astral-sh/uv)。\n\n///\n\n## 创建一个工程 { #create-a-project }\n\n首先，为你的工程创建一个目录。\n\n我通常会在我的主目录下创建一个名为 `code` 的目录。\n\n在这个目录下，我再为每个工程创建一个目录。\n\n<div class=\"termy\">\n\n```console\n// 进入主目录\n$ cd\n// 创建一个用于存放所有代码工程的目录\n$ mkdir code\n// 进入 code 目录\n$ cd code\n// 创建一个用于存放这个工程的目录\n$ mkdir awesome-project\n// 进入这个工程的目录\n$ cd awesome-project\n```\n\n</div>\n\n## 创建一个虚拟环境 { #create-a-virtual-environment }\n\n在开始一个 Python 工程的**第一时间**，**<dfn title=\"还有其他做法，此处仅作一个简单的指南\">在你的工程内部</dfn>**创建一个虚拟环境。\n\n/// tip | 提示\n\n你只需要 **在每个工程中操作一次**，而不是每次工作时都操作。\n\n///\n\n//// tab | `venv`\n\n你可以使用 Python 自带的 `venv` 模块来创建一个虚拟环境。\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | 上述命令的含义\n\n* `python`: 使用名为 `python` 的程序\n* `-m`: 以脚本的方式调用一个模块，我们将告诉它接下来使用哪个模块\n* `venv`: 使用名为 `venv` 的模块，这个模块通常随 Python 一起安装\n* `.venv`: 在新目录 `.venv` 中创建虚拟环境\n\n///\n\n////\n\n//// tab | `uv`\n\n如果你安装了 [`uv`](https://github.com/astral-sh/uv)，你也可以使用它来创建一个虚拟环境。\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip | 提示\n\n默认情况下，`uv` 会在一个名为 `.venv` 的目录中创建一个虚拟环境。\n\n但你可以通过传递一个额外的参数来自定义它，指定目录的名称。\n\n///\n\n////\n\n这个命令会在一个名为 `.venv` 的目录中创建一个新的虚拟环境。\n\n/// details | `.venv`，或是其他名称\n\n你可以在不同的目录下创建虚拟环境，但通常我们会把它命名为 `.venv`。\n\n///\n\n## 激活虚拟环境 { #activate-the-virtual-environment }\n\n激活新的虚拟环境来确保你运行的任何 Python 命令或安装的包都能使用到它。\n\n/// tip | 提示\n\n**每次**开始一个 **新的终端会话** 来工作在这个工程时，你都需要执行这个操作。\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\n或者，如果你在 Windows 上使用 Bash（例如 [Git Bash](https://gitforwindows.org/)）：\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip | 提示\n\n每次你在这个环境中安装一个 **新的包** 时，都需要 **重新激活** 这个环境。\n\n这么做确保了当你使用一个由这个包安装的 **终端（<abbr title=\"command line interface - 命令行界面\">CLI</abbr>）程序** 时，你使用的是你的虚拟环境中的程序，而不是全局安装、可能版本不同的程序。\n\n///\n\n## 检查虚拟环境是否激活 { #check-the-virtual-environment-is-active }\n\n检查虚拟环境是否激活 (前面的命令是否生效)。\n\n/// tip | 提示\n\n这是 **可选的**，但这是一个很好的方法，可以 **检查** 一切是否按预期工作，以及你是否使用了你打算使用的虚拟环境。\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n如果它显示了在你工程 (在这个例子中是 `awesome-project`) 的 `.venv/bin/python` 中的 `python` 二进制文件，那么它就生效了。🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n如果它显示了在你工程 (在这个例子中是 `awesome-project`) 的 `.venv\\Scripts\\python` 中的 `python` 二进制文件，那么它就生效了。🎉\n\n////\n\n## 升级 `pip` { #upgrade-pip }\n\n/// tip | 提示\n\n如果你使用 [`uv`](https://github.com/astral-sh/uv) 来安装内容，而不是 `pip`，那么你就不需要升级 `pip`。😎\n\n///\n\n如果你使用 `pip` 来安装包（它是 Python 的默认组件），你应该将它 **升级** 到最新版本。\n\n在安装包时出现的许多奇怪的错误都可以通过先升级 `pip` 来解决。\n\n/// tip | 提示\n\n通常你只需要在创建虚拟环境后 **执行一次** 这个操作。\n\n///\n\n确保虚拟环境是激活的 (使用上面的命令)，然后运行：\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip | 提示\n\n有时在尝试升级 pip 时，你可能会遇到 **`No module named pip`** 错误。\n\n如果发生这种情况，使用下面的命令来安装并升级 pip：\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\n该命令会在尚未安装 pip 时进行安装，并确保安装的 pip 版本不早于 `ensurepip` 提供的版本。\n\n///\n\n## 添加 `.gitignore` { #add-gitignore }\n\n如果你使用 **Git** (这是你应该使用的)，添加一个 `.gitignore` 文件来排除你的 `.venv` 中的所有内容。\n\n/// tip | 提示\n\n如果你使用 [`uv`](https://github.com/astral-sh/uv) 来创建虚拟环境，它会自动为你完成这个操作，你可以跳过这一步。😎\n\n///\n\n/// tip | 提示\n\n通常你只需要在创建虚拟环境后 **执行一次** 这个操作。\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | 上述命令的含义\n\n* `echo \"*\"`: 将在终端中 \"打印\" 文本 `*`（接下来的部分会对这个操作进行一些修改）\n* `>`: 使左边的命令打印到终端的任何内容实际上都不会被打印，而是会被写入到右边的文件中\n* `.gitignore`: 被写入文本的文件的名称\n\n而 `*` 对于 Git 来说意味着 \"所有内容\"。所以，它会忽略 `.venv` 目录中的所有内容。\n\n该命令会创建一个名为 `.gitignore` 的文件，内容如下：\n\n```gitignore\n*\n```\n\n///\n\n## 安装软件包 { #install-packages }\n\n在激活虚拟环境后，你可以在其中安装软件包。\n\n/// tip | 提示\n\n当你需要安装或升级软件包时，执行本操作**一次**；\n\n如果你需要再升级版本或添加新软件包，你可以**再次执行此操作**。\n\n///\n\n### 直接安装包 { #install-packages-directly }\n\n如果你急于安装，不想使用文件来声明工程的软件包依赖，你可以直接安装它们。\n\n/// tip | 提示\n\n将程序所需的软件包及其版本放在文件中（例如 `requirements.txt` 或 `pyproject.toml`）是个好（并且非常好）的主意。\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\n如果你有 [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### 从 `requirements.txt` 安装 { #install-from-requirements-txt }\n\n如果你有一个 `requirements.txt` 文件，你可以使用它来安装其中的软件包。\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\n如果你有 [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | 关于 `requirements.txt`\n\n一个包含一些软件包的 `requirements.txt` 文件看起来应该是这样的：\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## 运行程序 { #run-your-program }\n\n在你激活虚拟环境后，你可以运行你的程序，它将使用虚拟环境中的 Python 和你在其中安装的软件包。\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## 配置编辑器 { #configure-your-editor }\n\n你可能会用到编辑器，请确保配置它使用与你创建的相同的虚拟环境（它可能会自动检测到），以便你可以获得自动补全和内联错误提示。\n\n例如：\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip | 提示\n\n通常你只需要在创建虚拟环境时执行此操作**一次**。\n\n///\n\n## 退出虚拟环境 { #deactivate-the-virtual-environment }\n\n当你完成工作后，你可以**退出**虚拟环境。\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\n这样，当你运行 `python` 时，它不会尝试从那个虚拟环境及其已安装的软件包中运行。\n\n## 开始工作 { #ready-to-work }\n\n现在你已经准备好开始你的工作了。\n\n\n\n/// tip | 提示\n\n你想要理解上面的所有内容吗？\n\n继续阅读。👇🤓\n\n///\n\n## 为什么要使用虚拟环境 { #why-virtual-environments }\n\n你需要安装 [Python](https://www.python.org/) 才能使用 FastAPI。\n\n之后，你需要**安装** FastAPI 和你想要使用的任何其他**软件包**。\n\n要安装软件包，你通常会使用随 Python 一起提供的 `pip` 命令（或类似的替代方案）。\n\n然而，如果你直接使用 `pip`，软件包将被安装在你的**全局 Python 环境**中（即 Python 的全局安装）。\n\n### 存在的问题 { #the-problem }\n\n那么，在全局 Python 环境中安装软件包有什么问题呢？\n\n有些时候，你可能会编写许多不同的程序，这些程序依赖于**不同的软件包**；你所做的一些工程也会依赖于**同一软件包的不同版本**。😱\n\n例如，你可能会创建一个名为 `philosophers-stone` 的工程，这个程序依赖于另一个名为 **`harry` 的软件包，使用版本 `1`**。因此，你需要安装 `harry`。\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|需要| harry-1[harry v1]\n```\n\n然而在此之后，你又创建了另一个名为 `prisoner-of-azkaban` 的工程，这个工程也依赖于 `harry`，但是这个工程需要 **`harry` 版本 `3`**。\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |需要| harry-3[harry v3]\n```\n\n那么现在的问题是，如果你将软件包安装在全局环境中而不是在本地**虚拟环境**中，你将不得不面临选择安装哪个版本的 `harry` 的问题。\n\n如果你想运行 `philosophers-stone`，你需要首先安装 `harry` 版本 `1`，例如：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\n然后你将在全局 Python 环境中安装 `harry` 版本 `1`。\n\n```mermaid\nflowchart LR\n    subgraph global[全局环境]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[工程 philosophers-stone]\n        stone(philosophers-stone) -->|需要| harry-1\n    end\n```\n\n但是如果你想运行 `prisoner-of-azkaban`，你需要卸载 `harry` 版本 `1` 并安装 `harry` 版本 `3`（或者说，只要你安装版本 `3` ，版本 `1` 就会自动卸载）。\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\n于是，你在你的全局 Python 环境中安装了 `harry` 版本 `3`。\n\n如果你再次尝试运行 `philosophers-stone`，有可能它**无法正常工作**，因为它需要 `harry` 版本 `1`。\n\n```mermaid\nflowchart LR\n    subgraph global[全局环境]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[工程 philosophers-stone]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[工程 prisoner-of-azkaban]\n        azkaban(prisoner-of-azkaban) --> |需要| harry-3\n    end\n```\n\n/// tip | 提示\n\nPython 包在推出**新版本**时通常会尽量**避免破坏性更改**，但最好还是要小心，要想清楚再安装新版本，而且在运行测试以确保一切能正常工作时再安装。\n\n///\n\n现在，想象一下，如果有**许多**其他**软件包**，它们都是你的**工程所依赖的**。这是非常难以管理的。你可能会发现，有些工程使用了一些**不兼容的软件包版本**，而不知道为什么某些东西无法正常工作。\n\n此外，取决于你的操作系统（例如 Linux、Windows、macOS），它可能已经预先安装了 Python。在这种情况下，它可能已经预先安装了一些软件包，这些软件包的特定版本是**系统所需的**。如果你在全局 Python 环境中安装软件包，你可能会**破坏**一些随操作系统一起安装的程序。\n\n## 软件包安装在哪里 { #where-are-packages-installed }\n\n当你安装 Python 时，它会在你的计算机上创建一些目录，并在这些目录中放一些文件。\n\n其中一些目录负责存放你安装的所有软件包。\n\n当你运行：\n\n<div class=\"termy\">\n\n```console\n// 先别去运行这个命令，这只是一个示例 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n这将会从 [PyPI](https://pypi.org/project/fastapi/) 下载一个压缩文件，其中包含 FastAPI 代码。\n\n它还会**下载** FastAPI 依赖的其他软件包的文件。\n\n然后它会**解压**所有这些文件，并将它们放在你的计算机上的一个目录中。\n\n默认情况下，它会将下载并解压的这些文件放在随 Python 安装的目录中，这就是**全局环境**。\n\n## 什么是虚拟环境 { #what-are-virtual-environments }\n\n解决软件包都安装在全局环境中的问题的方法是为你所做的每个工程使用一个**虚拟环境**。\n\n虚拟环境是一个**目录**，与全局环境非常相似，你可以在其中专为某个工程安装软件包。\n\n这样，每个工程都会有自己的虚拟环境（`.venv` 目录），其中包含自己的软件包。\n\n```mermaid\nflowchart TB\n    subgraph stone-project[工程 philosophers-stone]\n        stone(philosophers-stone) --->|需要| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[工程 prisoner-of-azkaban]\n        azkaban(prisoner-of-azkaban) --->|需要| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## 激活虚拟环境意味着什么 { #what-does-activating-a-virtual-environment-mean }\n\n当你激活了一个虚拟环境，例如：\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\n或者如果你在 Windows 上使用 Bash（例如 [Git Bash](https://gitforwindows.org/)）：\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n这个命令会创建或修改一些[环境变量](environment-variables.md)，这些环境变量将在接下来的命令中可用。\n\n其中之一是 `PATH` 变量。\n\n/// tip | 提示\n\n你可以在 [环境变量](environment-variables.md#path-environment-variable) 部分了解更多关于 `PATH` 环境变量的内容。\n\n///\n\n激活虚拟环境会将其路径 `.venv/bin`（在 Linux 和 macOS 上）或 `.venv\\Scripts`（在 Windows 上）添加到 `PATH` 环境变量中。\n\n假设在激活环境之前，`PATH` 变量看起来像这样：\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\n这意味着系统会在以下目录中查找程序：\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\n这意味着系统会在以下目录中查找程序：\n\n* `C:\\Windows\\System32`\n\n////\n\n激活虚拟环境后，`PATH` 变量会变成这样：\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\n这意味着系统现在会首先在以下目录中查找程序：\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\n然后再在其他目录中查找。\n\n因此，当你在终端中输入 `python` 时，系统会在以下目录中找到 Python 程序：\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n并使用这个。\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\n这意味着系统现在会首先在以下目录中查找程序：\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\n然后再在其他目录中查找。\n\n因此，当你在终端中输入 `python` 时，系统会在以下目录中找到 Python 程序：\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n并使用这个。\n\n////\n\n一个重要的细节是，虚拟环境路径会被放在 `PATH` 变量的**开头**。系统会在找到任何其他可用的 Python **之前**找到它。这样，当你运行 `python` 时，它会使用**虚拟环境中**的 Python，而不是任何其他 `python`（例如，全局环境中的 `python`）。\n\n激活虚拟环境还会改变其他一些东西，但这是它所做的最重要的事情之一。\n\n## 检查虚拟环境 { #checking-a-virtual-environment }\n\n当你检查虚拟环境是否激活时，例如：\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\n这意味着将使用的 `python` 程序是**在虚拟环境中**的那个。\n\n在 Linux 和 macOS 中使用 `which`，在 Windows PowerShell 中使用 `Get-Command`。\n\n这个命令的工作方式是，它会在 `PATH` 环境变量中查找，按顺序**逐个路径**查找名为 `python` 的程序。一旦找到，它会**显示该程序的路径**。\n\n最重要的部分是，当你调用 `python` 时，将执行的就是这个确切的 \"`python`\"。\n\n因此，你可以确认你是否在正确的虚拟环境中。\n\n/// tip | 提示\n\n激活一个虚拟环境，获取一个 Python，然后**转到另一个工程**是一件很容易的事情；\n\n但如果第二个工程**无法工作**，那是因为你使用了来自另一个工程的虚拟环境的、**不正确的 Python**。\n\n因此，会检查正在使用的 `python` 是很有用的。🤓\n\n///\n\n## 为什么要停用虚拟环境 { #why-deactivate-a-virtual-environment }\n\n例如，你可能正在一个工程 `philosophers-stone` 上工作，**激活了该虚拟环境**，安装了包并使用了该环境，\n\n然后你想要在**另一个工程** `prisoner-of-azkaban` 上工作，\n\n你进入那个工程：\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\n如果你不去停用 `philosophers-stone` 的虚拟环境，当你在终端中运行 `python` 时，它会尝试使用 `philosophers-stone` 中的 Python。\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// 导入 sirius 报错，它没有安装 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\n但是如果你停用虚拟环境并激活 `prisoner-of-askaban` 的新虚拟环境，那么当你运行 `python` 时，它会使用 `prisoner-of-askaban` 中的虚拟环境中的 Python。\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// 你不需要在旧目录中操作停用，你可以在任何地方操作停用，甚至在转到另一个工程之后 😎\n$ deactivate\n\n// 激活 prisoner-of-azkaban/.venv 中的虚拟环境 🚀\n$ source .venv/bin/activate\n\n// 现在当你运行 python 时，它会在这个虚拟环境中找到安装的 sirius 包 ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## 替代方案 { #alternatives }\n\n这是一个简单的指南，可以帮助你入门并教会你如何理解一切**底层**的东西。\n\n有许多**替代方案**来管理虚拟环境、包依赖（requirements）、工程。\n\n一旦你准备好并想要使用一个工具来**管理整个工程**、包依赖、虚拟环境等，建议你尝试 [uv](https://github.com/astral-sh/uv)。\n\n`uv` 可以做很多事情，它可以：\n\n* 为你**安装 Python**，包括不同的版本\n* 为你的工程管理**虚拟环境**\n* 安装**软件包**\n* 为你的工程管理软件包的**依赖和版本**\n* 确保你有一个**确切**的软件包和版本集合来安装，包括它们的依赖项，这样你就可以确保在生产中运行你的工程与在开发时在你的计算机上运行的工程完全相同，这被称为**锁定**\n* 还有很多其他功能\n\n## 结论 { #conclusion }\n\n如果你读过并理解了所有这些，现在**你对虚拟环境的了解比很多开发者都要多**。🤓\n\n在未来当你调试看起来复杂的东西时，了解这些细节很可能会有用，你会知道**它是如何在底层工作的**。😎\n"
  },
  {
    "path": "docs/zh/llm-prompt.md",
    "content": "### Target language\n\nTranslate to Simplified Chinese (简体中文).\n\nLanguage code: zh.\n\n### Grammar and tone\n\n- Use clear, concise technical Chinese consistent with existing docs.\n- Address the reader naturally (commonly using “你/你的”).\n\n### Headings\n\n- Follow existing Simplified Chinese heading style (short and descriptive).\n- Do not add trailing punctuation to headings.\n- If a heading contains only the name of a FastAPI feature, do not translate it.\n\n### Quotes and punctuation\n\n- Keep punctuation style consistent with existing Simplified Chinese docs (they often mix English terms like “FastAPI” with Chinese text).\n- Never change punctuation inside inline code, code blocks, URLs, or file paths.\n\n### Ellipsis\n\n- Keep ellipsis style consistent within each document, prefer `...` over  `……`.\n- Never change ellipsis in code, URLs, or CLI examples.\n\n### Preferred translations / glossary\n\nUse the following preferred translations when they apply in documentation prose:\n\n- request (HTTP): 请求\n- response (HTTP): 响应\n- path operation: 路径操作\n- path operation function: 路径操作函数\n\n### `///` admonitions\n\n- Keep the admonition keyword in English (do not translate `note`, `tip`, etc.).\n- If a title is present, prefer these canonical titles:\n\n- `/// tip | 提示`\n- `/// note | 注意`\n- `/// warning | 警告`\n- `/// info | 信息`\n- `/// danger | 危险`\n"
  },
  {
    "path": "docs/zh/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs/zh-hant/docs/_llm-test.md",
    "content": "# LLM 測試檔案 { #llm-test-file }\n\n本文件用來測試用於翻譯文件的 <abbr title=\"Large Language Model - 大型語言模型\">LLM</abbr> 是否理解 `scripts/translate.py` 中的 `general_prompt`，以及 `docs/{language code}/llm-prompt.md` 中的語言特定提示。語言特定提示會附加在 `general_prompt` 後面。\n\n此處新增的測試會提供給所有語言特定提示的設計者參考。\n\n使用方式：\n\n* 準備語言特定提示 - `docs/{language code}/llm-prompt.md`。\n* 針對本文件做一次全新的翻譯為你想要的目標語言（例如使用 `translate.py` 的 `translate-page` 指令）。這會在 `docs/{language code}/docs/_llm-test.md` 產生翻譯檔。\n* 檢查翻譯是否正確。\n* 如有需要，改進你的語言特定提示、通用提示，或英文原文。\n* 然後手動修正翻譯中剩下的問題，讓它成為一個好的譯文。\n* 重新翻譯，並保留這份好的譯文。理想結果是 LLM 不再對該譯文做任何變更。這代表通用提示與你的語言特定提示已經盡可能完善（有時它仍可能做出幾個看似隨機的變更，原因是[LLMs 並非決定性演算法](https://doublespeak.chat/#/handbook#deterministic-output)）。\n\n測試：\n\n## 程式碼片段 { #code-snippets }\n\n//// tab | 測試\n\n這是一個程式碼片段：`foo`。這是另一個程式碼片段：`bar`。還有一個：`baz quux`。\n\n////\n\n//// tab | 資訊\n\n程式碼片段內的內容應保持原樣。\n\n請見 `scripts/translate.py` 中通用提示的 `### Content of code snippets` 小節。\n\n////\n\n## 引號 { #quotes }\n\n//// tab | 測試\n\nYesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\".\n\n/// note | 注意\n\nLLM 很可能會把這段翻譯錯。重點只在於重新翻譯時是否能保留已修正的翻譯。\n\n///\n\n////\n\n//// tab | 資訊\n\n提示設計者可以選擇是否將中性引號轉換為排印引號。保留原樣也可以。\n\n例如請見 `docs/de/llm-prompt.md` 中的 `### Quotes` 小節。\n\n////\n\n## 程式碼片段中的引號 { #quotes-in-code-snippets }\n\n//// tab | 測試\n\n`pip install \"foo[bar]\"`\n\n程式碼片段中字串常值的例子：\"this\"、'that'。\n\n較難的程式碼片段中字串常值例子：`f\"I like {'oranges' if orange else \"apples\"}\"`\n\n進階：`Yesterday, my friend wrote: \"If you spell incorrectly correctly, you have spelled it incorrectly\". To which I answered: \"Correct, but 'incorrectly' is incorrectly not '\"incorrectly\"'\"`\n\n////\n\n//// tab | 資訊\n\n... 不過，程式碼片段中的引號必須保持原樣。\n\n////\n\n## 程式碼區塊 { #code-blocks }\n\n//// tab | 測試\n\n一個 Bash 程式碼範例...\n\n```bash\n# 向宇宙輸出問候\necho \"Hello universe\"\n```\n\n...以及一個主控台範例...\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\n...以及另一個主控台範例...\n\n```console\n// 建立目錄 \"Code\"\n$ mkdir code\n// 切換到該目錄\n$ cd code\n```\n\n...以及一個 Python 程式碼範例...\n\n```Python\nwont_work()  # 這不會運作 😱\nworks(foo=\"bar\")  # 這可以運作 🎉\n```\n\n...就是這樣。\n\n////\n\n//// tab | 資訊\n\n程式碼區塊中的程式碼不應修改，註解除外。\n\n請見 `scripts/translate.py` 中通用提示的 `### Content of code blocks` 小節。\n\n////\n\n## 分頁與色塊 { #tabs-and-colored-boxes }\n\n//// tab | 測試\n\n/// info | 資訊\nSome text\n///\n\n/// note | 注意\nSome text\n///\n\n/// note | 技術細節\nSome text\n///\n\n/// check | 檢查\nSome text\n///\n\n/// tip | 提示\nSome text\n///\n\n/// warning | 警告\nSome text\n///\n\n/// danger | 危險\nSome text\n///\n\n////\n\n//// tab | 資訊\n\n分頁與 `Info`/`Note`/`Warning`/等區塊，應在直線（`|`）後加入其標題的翻譯。\n\n請見 `scripts/translate.py` 中通用提示的 `### Special blocks` 與 `### Tab blocks` 小節。\n\n////\n\n## 網頁與內部連結 { #web-and-internal-links }\n\n//// tab | 測試\n\n連結文字應被翻譯，連結位址應保持不變：\n\n* [連結到上方標題](#code-snippets)\n* [內部連結](index.md#installation)\n* [外部連結](https://sqlmodel.tiangolo.com/)\n* [連結到樣式](https://fastapi.tiangolo.com/css/styles.css)\n* [連結到腳本](https://fastapi.tiangolo.com/js/logic.js)\n* [連結到圖片](https://fastapi.tiangolo.com/img/foo.jpg)\n\n連結文字應被翻譯，連結位址應指向對應的翻譯版本：\n\n* [FastAPI 連結](https://fastapi.tiangolo.com/zh-hant/)\n\n////\n\n//// tab | 資訊\n\n連結應翻譯其文字，但位址需保持不變。例外是指向 FastAPI 文件網站的絕對連結，該情況下位址應指向對應的翻譯版本。\n\n請見 `scripts/translate.py` 中通用提示的 `### Links` 小節。\n\n////\n\n## HTML「abbr」元素 { #html-abbr-elements }\n\n//// tab | 測試\n\n以下是一些包在 HTML「abbr」元素中的內容（部分為杜撰）：\n\n### abbr 提供完整詞組 { #the-abbr-gives-a-full-phrase }\n\n* <abbr title=\"Getting Things Done - 搞定工作法\">GTD</abbr>\n* <abbr title=\"less than - 小於\"><code>lt</code></abbr>\n* <abbr title=\"XML Web Token - XML 網路權杖\">XWT</abbr>\n* <abbr title=\"Parallel Server Gateway Interface - 平行伺服器閘道介面\">PSGI</abbr>\n\n### abbr 提供完整詞組與說明 { #the-abbr-gives-a-full-phrase-and-an-explanation }\n\n* <abbr title=\"Mozilla Developer Network - Mozilla 開發者網路: 給開發者的文件，由 Firefox 團隊撰寫\">MDN</abbr>\n* <abbr title=\"Input/Output - 輸入/輸出: 磁碟讀寫，網路通訊。\">I/O</abbr>.\n\n////\n\n//// tab | 資訊\n\n「abbr」元素的「title」屬性需依特定規則翻譯。\n\n翻譯可以自行新增「abbr」元素（例如為解釋英文單字），LLM 不應移除它們。\n\n請見 `scripts/translate.py` 中通用提示的 `### HTML abbr elements` 小節。\n\n////\n\n## HTML「dfn」元素 { #html-dfn-elements }\n\n* <dfn title=\"被設定為連接並以某種方式一起工作的機器群組。\">叢集</dfn>\n* <dfn title=\"一種機器學習方法，使用具備多個隱藏層的人工神經網路，在輸入與輸出層之間建立完整的內部結構\">深度學習</dfn>\n\n## 標題 { #headings }\n\n//// tab | 測試\n\n### 開發網頁應用程式 - 教學 { #develop-a-webapp-a-tutorial }\n\nHello.\n\n### 型別提示與註解 { #type-hints-and-annotations }\n\nHello again.\n\n### 超類與子類別 { #super-and-subclasses }\n\nHello again.\n\n////\n\n//// tab | 資訊\n\n標題唯一的硬性規則是保留花括號中的雜湊片段不變，以確保連結不會失效。\n\n請見 `scripts/translate.py` 中通用提示的 `### Headings` 小節。\n\n關於語言特定的說明，參見例如 `docs/de/llm-prompt.md` 中的 `### Headings` 小節。\n\n////\n\n## 文件中使用的術語 { #terms-used-in-the-docs }\n\n//// tab | 測試\n\n* you\n* your\n\n* e.g.\n* etc.\n\n* `foo` as an `int`\n* `bar` as a `str`\n* `baz` as a `list`\n\n* 教學 - 使用者指南\n* 進階使用者指南\n* SQLModel 文件\n* API 文件\n* 自動文件\n\n* 資料科學\n* 深度學習\n* 機器學習\n* 相依性注入\n* HTTP 基本驗證\n* HTTP 摘要驗證\n* ISO 格式\n* JSON Schema 標準\n* JSON 結構描述\n* 結構描述定義\n* 密碼流程\n* 行動裝置\n\n* 已棄用\n* 設計的\n* 無效\n* 即時\n* 標準\n* 預設\n* 区分大小寫\n* 不區分大小寫\n\n* 提供應用程式服務\n* 提供頁面服務\n\n* 應用程式\n* 應用程式\n\n* 請求\n* 回應\n* 錯誤回應\n\n* 路徑操作\n* 路徑操作裝飾器\n* 路徑操作函式\n\n* 主體\n* 請求主體\n* 回應主體\n* JSON 主體\n* 表單主體\n* 檔案主體\n* 函式主體\n\n* 參數\n* 主體參數\n* 路徑參數\n* 查詢參數\n* Cookie 參數\n* 標頭參數\n* 表單參數\n* 函式參數\n\n* 事件\n* 啟動事件\n* 伺服器的啟動\n* 關閉事件\n* 生命週期事件\n\n* 處理器\n* 事件處理器\n* 例外處理器\n* 處理\n\n* 模型\n* Pydantic 模型\n* 資料模型\n* 資料庫模型\n* 表單模型\n* 模型物件\n\n* 類別\n* 基底類別\n* 父類別\n* 子類別\n* 子類別\n* 同級類別\n* 類別方法\n\n* 標頭\n* 標頭\n* 授權標頭\n* `Authorization` 標頭\n* 轉送標頭\n\n* 相依性注入系統\n* 相依項\n* 可相依對象\n* 相依者\n\n* I/O 受限\n* CPU 受限\n* 並發\n* 平行處理\n* 多處理程序\n\n* 環境變數\n* 環境變數\n* `PATH`\n* `PATH` 變數\n\n* 驗證\n* 驗證提供者\n* 授權\n* 授權表單\n* 授權提供者\n* 使用者進行驗證\n* 系統驗證使用者\n\n* CLI\n* 命令列介面\n\n* 伺服器\n* 用戶端\n\n* 雲端提供者\n* 雲端服務\n\n* 開發\n* 開發階段\n\n* dict\n* 字典\n* 列舉\n* enum\n* 列舉成員\n\n* 編碼器\n* 解碼器\n* 編碼\n* 解碼\n\n* 例外\n* 拋出\n\n* 運算式\n* 陳述式\n\n* 前端\n* 後端\n\n* GitHub 討論\n* GitHub 議題\n\n* 效能\n* 效能優化\n\n* 回傳型別\n* 回傳值\n\n* 安全性\n* 安全性機制\n\n* 任務\n* 背景任務\n* 任務函式\n\n* 樣板\n* 樣板引擎\n\n* 型別註解\n* 型別提示\n\n* 伺服器工作進程\n* Uvicorn 工作進程\n* Gunicorn 工作進程\n* 工作進程\n* worker 類別\n* 工作負載\n\n* 部署\n* 部署\n\n* SDK\n* 軟體開發工具組\n\n* `APIRouter`\n* `requirements.txt`\n* Bearer Token\n* 相容性破壞變更\n* 錯誤\n* 按鈕\n* 可呼叫對象\n* 程式碼\n* 提交\n* 情境管理器\n* 協程\n* 資料庫工作階段\n* 磁碟\n* 網域\n* 引擎\n* 假的 X\n* HTTP GET 方法\n* 項目\n* 函式庫\n* 生命週期\n* 鎖\n* 中介軟體\n* 行動應用程式\n* 模組\n* 掛載\n* 網路\n* 來源\n* 覆寫\n* 有效負載\n* 處理器\n* 屬性\n* 代理\n* pull request\n* 查詢\n* RAM\n* 遠端機器\n* 狀態碼\n* 字串\n* 標籤\n* Web 框架\n* 萬用字元\n* 回傳\n* 驗證\n\n////\n\n//// tab | 資訊\n\n這是一份不完整且非規範性的（多為）技術術語清單，來源為文件內容。它可能有助於提示設計者判斷哪些術語需要 LLM 的特別協助。例如當 LLM 反覆把好的翻譯改回成較差的版本，或在你的語言中對某詞的詞形變化處理有困難時。\n\n請見例如 `docs/de/llm-prompt.md` 中的 `### List of English terms and their preferred German translations` 小節。\n\n////\n"
  },
  {
    "path": "docs/zh-hant/docs/about/index.md",
    "content": "# 關於 { #about }\n\n關於 FastAPI、其設計、靈感來源等更多資訊。 🤓\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/additional-responses.md",
    "content": "# OpenAPI 中的額外回應 { #additional-responses-in-openapi }\n\n/// warning | 警告\n\n這是一個偏進階的主題。\n\n如果你剛開始使用 **FastAPI**，大多情況下不需要用到它。\n\n///\n\n你可以宣告額外的回應，包含額外的狀態碼、媒體型別、描述等。\n\n這些額外回應會被包含在 OpenAPI 中，因此也會顯示在 API 文件裡。\n\n但對於這些額外回應，你必須直接回傳像 `JSONResponse` 這樣的 `Response`，並包含你的狀態碼與內容。\n\n## 使用 `model` 的額外回應 { #additional-response-with-model }\n\n你可以在你的「路徑操作裝飾器」中傳入參數 `responses`。\n\n它接收一個 `dict`：鍵是各回應的狀態碼（例如 `200`），值是另一個 `dict`，其中包含每個回應的資訊。\n\n每個回應的 `dict` 都可以有一個鍵 `model`，包含一個 Pydantic 模型，與 `response_model` 類似。\n\n**FastAPI** 會取用該模型、產生其 JSON Schema，並把它放到 OpenAPI 中正確的位置。\n\n例如，要宣告一個狀態碼為 `404` 的額外回應，並使用 Pydantic 模型 `Message`，你可以這樣寫：\n\n{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *}\n\n/// note | 注意\n\n請記住你必須直接回傳 `JSONResponse`。\n\n///\n\n/// info | 說明\n\n`model` 這個鍵不屬於 OpenAPI。\n\n**FastAPI** 會從這裡取出 Pydantic 模型，產生 JSON Schema，並放到正確位置。\n\n正確的位置是：\n\n* 在 `content` 這個鍵中，其值是一個 JSON 物件（`dict`），包含：\n    * 一個媒體型別作為鍵，例如 `application/json`，其值是另一個 JSON 物件，當中包含：\n        * 鍵 `schema`，其值是該模型的 JSON Schema，這裡就是正確的位置。\n            * **FastAPI** 會在這裡加入一個指向你 OpenAPI 中全域 JSON Schemas 的參照，而不是直接把它嵌入。如此一來，其他應用與用戶端可以直接使用那些 JSON Schemas，提供更好的程式碼產生工具等。\n\n///\n\n這個路徑操作在 OpenAPI 中產生的回應將會是：\n\n```JSON hl_lines=\"3-12\"\n{\n    \"responses\": {\n        \"404\": {\n            \"description\": \"Additional Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Message\"\n                    }\n                }\n            }\n        },\n        \"200\": {\n            \"description\": \"Successful Response\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/Item\"\n                    }\n                }\n            }\n        },\n        \"422\": {\n            \"description\": \"Validation Error\",\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n這些 Schemas 會在 OpenAPI 中以參照的方式指向其他位置：\n\n```JSON hl_lines=\"4-16\"\n{\n    \"components\": {\n        \"schemas\": {\n            \"Message\": {\n                \"title\": \"Message\",\n                \"required\": [\n                    \"message\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"message\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"Item\": {\n                \"title\": \"Item\",\n                \"required\": [\n                    \"id\",\n                    \"value\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"id\": {\n                        \"title\": \"Id\",\n                        \"type\": \"string\"\n                    },\n                    \"value\": {\n                        \"title\": \"Value\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"ValidationError\": {\n                \"title\": \"ValidationError\",\n                \"required\": [\n                    \"loc\",\n                    \"msg\",\n                    \"type\"\n                ],\n                \"type\": \"object\",\n                \"properties\": {\n                    \"loc\": {\n                        \"title\": \"Location\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\"\n                        }\n                    },\n                    \"msg\": {\n                        \"title\": \"Message\",\n                        \"type\": \"string\"\n                    },\n                    \"type\": {\n                        \"title\": \"Error Type\",\n                        \"type\": \"string\"\n                    }\n                }\n            },\n            \"HTTPValidationError\": {\n                \"title\": \"HTTPValidationError\",\n                \"type\": \"object\",\n                \"properties\": {\n                    \"detail\": {\n                        \"title\": \"Detail\",\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"$ref\": \"#/components/schemas/ValidationError\"\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n```\n\n## 主回應的其他媒體型別 { #additional-media-types-for-the-main-response }\n\n你可以用同一個 `responses` 參數，替相同的主回應新增不同的媒體型別。\n\n例如，你可以新增 `image/png` 這種媒體型別，宣告你的「路徑操作」可以回傳 JSON 物件（媒體型別為 `application/json`）或一張 PNG 圖片：\n\n{* ../../docs_src/additional_responses/tutorial002_py310.py hl[17:22,26] *}\n\n/// note | 注意\n\n請注意你必須直接用 `FileResponse` 回傳圖片。\n\n///\n\n/// info | 說明\n\n除非你在 `responses` 參數中明確指定不同的媒體型別，否則 FastAPI 會假設回應的媒體型別與主回應類別相同（預設為 `application/json`）。\n\n但如果你指定了一個自訂的回應類別，且其媒體型別為 `None`，那麼對於任何具關聯模型的額外回應，FastAPI 會使用 `application/json`。\n\n///\n\n## 結合資訊 { #combining-information }\n\n你也可以從多個地方結合回應資訊，包括 `response_model`、`status_code` 與 `responses` 參數。\n\n你可以宣告一個 `response_model`，使用預設狀態碼 `200`（或你需要的自訂狀態碼），然後在 `responses` 中直接於 OpenAPI Schema 為相同的回應宣告額外資訊。\n\n**FastAPI** 會保留 `responses` 提供的額外資訊，並把它和你模型的 JSON Schema 結合。\n\n例如，你可以宣告一個狀態碼為 `404` 的回應，使用一個 Pydantic 模型，並帶有自訂的 `description`。\n\n以及一個狀態碼為 `200` 的回應，使用你的 `response_model`，但包含自訂的 `example`：\n\n{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *}\n\n以上都會被結合並包含在你的 OpenAPI 中，並顯示在 API 文件：\n\n<img src=\"/img/tutorial/additional-responses/image01.png\">\n\n## 結合預先定義與自訂的回應 { #combine-predefined-responses-and-custom-ones }\n\n你可能想要有一些適用於多個「路徑操作」的預先定義回應，但也想與每個「路徑操作」所需的自訂回應結合。\n\n在這些情況下，你可以使用 Python 的「解包」`dict` 技巧，透過 `**dict_to_unpack`：\n\n```Python\nold_dict = {\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n}\nnew_dict = {**old_dict, \"new key\": \"new value\"}\n```\n\n此處，`new_dict` 會包含 `old_dict` 的所有鍵值配對，再加上新的鍵值配對：\n\n```Python\n{\n    \"old key\": \"old value\",\n    \"second old key\": \"second old value\",\n    \"new key\": \"new value\",\n}\n```\n\n你可以用這個技巧在「路徑操作」中重用一些預先定義的回應，並與其他自訂回應結合。\n\n例如：\n\n{* ../../docs_src/additional_responses/tutorial004_py310.py hl[11:15,24] *}\n\n## 關於 OpenAPI 回應的更多資訊 { #more-information-about-openapi-responses }\n\n若要查看回應中究竟可以包含哪些內容，你可以參考 OpenAPI 規範中的這些章節：\n\n* [OpenAPI Responses 物件](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responses-object)，其中包含 `Response Object`。\n* [OpenAPI Response 物件](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#response-object)，你可以把這裡的任何內容直接放到 `responses` 參數內各個回應中。包含 `description`、`headers`、`content`（在其中宣告不同的媒體型別與 JSON Schemas）、以及 `links`。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/additional-status-codes.md",
    "content": "# 額外的狀態碼 { #additional-status-codes }\n\n在預設情況下，**FastAPI** 會使用 `JSONResponse` 傳回回應，並把你從你的「路徑操作（path operation）」回傳的內容放進該 `JSONResponse` 中。\n\n它會使用預設的狀態碼，或你在路徑操作中設定的狀態碼。\n\n## 額外的狀態碼 { #additional-status-codes_1 }\n\n如果你想在主要狀態碼之外再回傳其他狀態碼，可以直接回傳一個 `Response`（例如 `JSONResponse`），並直接設定你想要的額外狀態碼。\n\n例如，你想要有一個允許更新項目的路徑操作，成功時回傳 HTTP 狀態碼 200 \"OK\"。\n\n但你也希望它能接受新項目；當項目先前不存在時就建立它們，並回傳 HTTP 狀態碼 201 \"Created\"。\n\n要達成這點，匯入 `JSONResponse`，直接在那裡回傳內容，並設定你想要的 `status_code`：\n\n{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *}\n\n/// warning\n\n當你直接回傳一個 `Response`（就像上面的範例），它會原封不動地被送出。\n\n不會再經過模型序列化等處理。\n\n請確認其中包含你要的資料，且各值是合法的 JSON（如果你使用的是 `JSONResponse`）。\n\n///\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.responses import JSONResponse`。\n\n**FastAPI** 也將同樣的 `starlette.responses` 以 `fastapi.responses` 的形式提供，純粹是為了讓你（開發者）更方便。但大多數可用的回應類別其實都直接來自 Starlette。`status` 也一樣。\n\n///\n\n## OpenAPI 與 API 文件 { #openapi-and-api-docs }\n\n如果你直接回傳額外的狀態碼與回應，它們不會被包含進 OpenAPI 綱要（API 文件）中，因為 FastAPI 無法事先知道你會回傳什麼。\n\n但你可以在程式碼中補充文件，使用：[額外的回應](additional-responses.md)。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/advanced-dependencies.md",
    "content": "# 進階相依 { #advanced-dependencies }\n\n## 參數化的相依 { #parameterized-dependencies }\n\n到目前為止看到的相依都是固定的函式或類別。\n\n但有些情況下，你可能想要能為相依設定參數，而不必宣告許多不同的函式或類別。\n\n想像我們想要一個相依，用來檢查查詢參數 `q` 是否包含某些固定內容。\n\n同時我們希望能將那個固定內容參數化。\n\n## 「callable」的實例 { #a-callable-instance }\n\n在 Python 中有一種方式可以讓一個類別的實例變成「callable」。\n\n不是類別本身（類別本來就可呼叫），而是該類別的實例。\n\n要做到這點，我們宣告一個 `__call__` 方法：\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *}\n\n在這個情境中，**FastAPI** 會用這個 `__call__` 來檢查額外的參數與子相依，並在之後呼叫它，把回傳值傳遞給你的「路徑操作函式」中的參數。\n\n## 讓實例可參數化 { #parameterize-the-instance }\n\n接著，我們可以用 `__init__` 來宣告這個實例的參數，用以「參數化」這個相依：\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *}\n\n在這裡，**FastAPI** 完全不會接觸或在意 `__init__`，我們會直接在自己的程式碼中使用它。\n\n## 建立一個實例 { #create-an-instance }\n\n我們可以這樣建立該類別的實例：\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *}\n\n如此一來我們就能「參數化」相依，現在它內部含有 `\"bar\"`，作為屬性 `checker.fixed_content`。\n\n## 將實例作為相依使用 { #use-the-instance-as-a-dependency }\n\n然後，我們可以在 `Depends(checker)` 中使用這個 `checker`，而不是 `Depends(FixedContentQueryChecker)`，因為相依是那個實例 `checker`，不是類別本身。\n\n當解析相依時，**FastAPI** 會像這樣呼叫這個 `checker`：\n\n```Python\nchecker(q=\"somequery\")\n```\n\n...並將其回傳值，作為相依的值，以參數 `fixed_content_included` 傳給我們的「路徑操作函式」：\n\n{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *}\n\n/// tip | 提示\n\n這一切現在看起來也許有點牽強，而且目前可能還不太清楚有何用途。\n\n這些範例刻意保持簡單，但展示了整個機制如何運作。\n\n在關於安全性的章節裡，有一些工具函式也是用同樣的方式實作。\n\n如果你理解了以上內容，你其實已經知道那些安全性工具在底層是如何運作的。\n\n///\n\n## 同時含有 `yield`、`HTTPException`、`except` 與背景任務的相依 { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n/// warning | 警告\n\n你很可能不需要這些技術細節。\n\n這些細節主要在於：如果你有一個 0.121.0 之前的 FastAPI 應用，並且在使用含有 `yield` 的相依時遇到問題，會對你有幫助。\n\n///\n\n含有 `yield` 的相依隨著時間演進，以涵蓋不同的使用情境並修正一些問題。以下是變更摘要。\n\n### 含有 `yield` 與 `scope` 的相依 { #dependencies-with-yield-and-scope }\n\n在 0.121.0 版中，FastAPI 為含有 `yield` 的相依加入了 `Depends(scope=\"function\")` 的支援。\n\n使用 `Depends(scope=\"function\")` 時，`yield` 之後的結束程式碼會在「路徑操作函式」執行完畢後立刻執行，在回應發送回客戶端之前。\n\n而當使用 `Depends(scope=\"request\")`（預設值）時，`yield` 之後的結束程式碼會在回應送出之後才執行。\n\n你可以在文件中閱讀更多：[含有 `yield` 的相依 - 提前結束與 `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope)。\n\n### 含有 `yield` 與 `StreamingResponse` 的相依，技術細節 { #dependencies-with-yield-and-streamingresponse-technical-details }\n\n在 FastAPI 0.118.0 之前，如果你使用含有 `yield` 的相依，它會在「路徑操作函式」回傳之後、發送回應之前，執行結束程式碼。\n\n這樣做的用意是避免在等待回應穿越網路時，比必要的時間更久地占用資源。\n\n但這也意味著，如果你回傳的是 `StreamingResponse`，該含有 `yield` 的相依的結束程式碼早已執行完畢。\n\n例如，如果你在含有 `yield` 的相依中使用了一個資料庫 session，`StreamingResponse` 在串流資料時將無法使用該 session，因為它已在 `yield` 之後的結束程式碼中被關閉了。\n\n這個行為在 0.118.0 被還原，使得 `yield` 之後的結束程式碼會在回應送出之後才被執行。\n\n/// info | 資訊\n\n如下所見，這與 0.106.0 之前的行為非常類似，但對一些邊界情況做了多項改進與錯誤修正。\n\n///\n\n#### 需要提早執行結束程式碼的情境 { #use-cases-with-early-exit-code }\n\n有些特定條件的使用情境，可能會受益於舊行為（在送出回應之前執行含有 `yield` 的相依的結束程式碼）。\n\n例如，假設你在含有 `yield` 的相依中只用資料庫 session 來驗證使用者，而這個 session 之後並未在「路徑操作函式」中使用，僅在相依中使用，且回應需要很長時間才會送出，例如一個慢速傳送資料的 `StreamingResponse`，但它並沒有使用資料庫。\n\n在這種情況下，資料庫 session 會一直被保留到回應傳送完畢為止，但如果你根本不會用到它，就沒有必要一直持有它。\n\n可能會像這樣：\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py *}\n\n結束程式碼（自動關閉 `Session`）在：\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n...會在回應完成傳送這些慢速資料後才執行：\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\n但因為 `generate_stream()` 並未使用資料庫 session，實際上不需要在傳送回應時保持 session 開啟。\n\n如果你用的是 SQLModel（或 SQLAlchemy）且有這種特定情境，你可以在不再需要時明確關閉該 session：\n\n{* ../../docs_src/dependencies/tutorial014_an_py310.py ln[24:28] hl[28] *}\n\n如此一來，該 session 就會釋放資料庫連線，讓其他請求可以使用。\n\n如果你有不同的情境，需要從含有 `yield` 的相依中提早結束，請建立一個 [GitHub 討論問題](https://github.com/fastapi/fastapi/discussions/new?category=questions)，描述你的具體情境，以及為何提早關閉含有 `yield` 的相依對你有幫助。\n\n如果有令人信服的案例需要在含有 `yield` 的相依中提前關閉，我會考慮加入一種新的選項，讓你可以選擇性啟用提前關閉。\n\n### 含有 `yield` 與 `except` 的相依，技術細節 { #dependencies-with-yield-and-except-technical-details }\n\n在 FastAPI 0.110.0 之前，如果你使用含有 `yield` 的相依，並且在該相依中用 `except` 捕捉到例外，且沒有再次拋出，那個例外會自動被拋出／轉交給任何例外處理器或內部伺服器錯誤處理器。\n\n在 0.110.0 版本中，這被修改以修復沒有處理器（內部伺服器錯誤）而被轉交的例外所造成的未處理記憶體消耗，並使其行為與一般 Python 程式碼一致。\n\n### 背景任務與含有 `yield` 的相依，技術細節 { #background-tasks-and-dependencies-with-yield-technical-details }\n\n在 FastAPI 0.106.0 之前，不可能在 `yield` 之後拋出例外；含有 `yield` 的相依的結束程式碼會在回應送出之後才執行，因此[例外處理器](../tutorial/handling-errors.md#install-custom-exception-handlers) 早就已經跑完了。\n\n當初這樣設計主要是為了允許在背景任務中使用由相依「yield」出來的同一組物件，因為結束程式碼會在背景任務結束後才執行。\n\n在 FastAPI 0.106.0 中，這個行為被修改，目的是在等待回應穿越網路的期間，不要持有資源。\n\n/// tip | 提示\n\n此外，背景任務通常是一組獨立的邏輯，應該用自己的資源（例如自己的資料庫連線）來處理。\n\n這樣你的程式碼通常會更乾淨。\n\n///\n\n如果你先前依賴這種行為，現在應該在背景任務本身裡建立所需資源，並且只使用不依賴含有 `yield` 的相依之資源的資料。\n\n例如，不要共用同一個資料庫 session，而是在背景任務中建立一個新的資料庫 session，並用這個新的 session 從資料庫取得物件。接著，在呼叫背景任務函式時，不是傳遞資料庫物件本身，而是傳遞該物件的 ID，然後在背景任務函式內再透過這個 ID 取得物件。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/advanced-python-types.md",
    "content": "# 進階 Python 型別 { #advanced-python-types }\n\n以下是一些在使用 Python 型別時可能有用的額外想法。\n\n## 使用 `Union` 或 `Optional` { #using-union-or-optional }\n\n如果你的程式碼因某些原因無法使用 `|`，例如不是在型別註記中，而是在像 `response_model=` 之類的參數位置，那麼你可以用 `typing` 中的 `Union` 來取代豎線（`|`）。\n\n例如，你可以宣告某個值可以是 `str` 或 `None`：\n\n```python\nfrom typing import Union\n\n\ndef say_hi(name: Union[str, None]):\n        print(f\"Hi {name}!\")\n```\n\n在 `typing` 中也有用 `Optional` 宣告某個值可以是 `None` 的速記法。\n\n以下是我個人（非常主觀）的建議：\n\n* 🚨 避免使用 `Optional[SomeType]`\n* 改為 ✨ 使用 `Union[SomeType, None]` ✨。\n\n兩者等價且底層相同，但我會推薦用 `Union` 而不要用 `Optional`，因為「optional」這個詞看起來會讓人以為這個值是可選的，但實際上它的意思是「可以是 `None`」，即使它不是可選的、仍然是必填。\n\n我認為 `Union[SomeType, None]` 更能清楚表達其含義。\n\n這只是措辭與命名問題，但這些詞會影響你與團隊成員對程式碼的理解。\n\n例如，看看下面這個函式：\n\n```python\nfrom typing import Optional\n\n\ndef say_hi(name: Optional[str]):\n    print(f\"Hey {name}!\")\n```\n\n參數 `name` 被標註為 `Optional[str]`，但它並不是可選的；你不能在沒有該參數的情況下呼叫這個函式：\n\n```Python\nsay_hi()  # 糟了，這會拋出錯誤！😱\n```\n\n參數 `name` 仍是必填（不是可選），因為它沒有預設值。不過，`name` 可以接受 `None` 作為值：\n\n```Python\nsay_hi(name=None)  # 這可行，None 是有效的 🎉\n```\n\n好消息是，多數情況下你可以直接用 `|` 來定義型別聯集：\n\n```python\ndef say_hi(name: str | None):\n    print(f\"Hey {name}!\")\n```\n\n因此，通常你不必為 `Optional` 與 `Union` 這些名稱操心。😎\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/async-tests.md",
    "content": "# 非同步測試 { #async-tests }\n\n你已經看過如何使用提供的 `TestClient` 來測試你的 FastAPI 應用。到目前為止，你只看到如何撰寫同步測試，沒有使用 `async` 函式。\n\n在測試中能使用非同步函式會很有用，例如當你以非同步方式查詢資料庫時。想像你想測試發送請求到 FastAPI 應用，然後在使用非同步資料庫函式庫時，驗證後端是否成功把正確資料寫入資料庫。\n\n來看看怎麼做。\n\n## pytest.mark.anyio { #pytest-mark-anyio }\n\n若要在測試中呼叫非同步函式，測試函式本身也必須是非同步的。AnyIO 為此提供了一個好用的外掛，讓我們可以標示某些測試函式以非同步方式執行。\n\n## HTTPX { #httpx }\n\n即使你的 FastAPI 應用使用一般的 `def` 函式而非 `async def`，它在底層仍然是個 `async` 應用。\n\n`TestClient` 在內部做了一些魔法，讓我們能在一般的 `def` 測試函式中，使用標準 pytest 來呼叫非同步的 FastAPI 應用。但當我們在非同步函式中使用它時，這個魔法就不再奏效了。也就是說，當以非同步方式執行測試時，就不能在測試函式內使用 `TestClient`。\n\n`TestClient` 是建立在 [HTTPX](https://www.python-httpx.org) 之上，所幸我們可以直接使用它來測試 API。\n\n## 範例 { #example }\n\n作為簡單範例，讓我們考慮與[更大型的應用](../tutorial/bigger-applications.md)與[測試](../tutorial/testing.md)中描述的類似檔案結構：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n檔案 `main.py` 會是：\n\n{* ../../docs_src/async_tests/app_a_py310/main.py *}\n\n檔案 `test_main.py` 會包含針對 `main.py` 的測試，現在可能像這樣：\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py *}\n\n## 執行 { #run-it }\n\n如常執行測試：\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n---> 100%\n```\n\n</div>\n\n## 詳解 { #in-detail }\n\n標記 `@pytest.mark.anyio` 告訴 pytest 這個測試函式應以非同步方式執行：\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *}\n\n/// tip\n\n注意，測試函式現在是 `async def`，而不是像使用 `TestClient` 時那樣僅用 `def`。\n\n///\n\n接著，我們可以用該應用建立 `AsyncClient`，並以 `await` 發送非同步請求。\n\n{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *}\n\n這等同於：\n\n```Python\nresponse = client.get('/')\n```\n\n也就是先前用 `TestClient` 發送請求時所用的寫法。\n\n/// tip\n\n注意，對新的 `AsyncClient` 需搭配 async/await —— 請求是非同步的。\n\n///\n\n/// warning\n\n如果你的應用仰賴 lifespan 事件，`AsyncClient` 不會觸發這些事件。若要確保它們被觸發，請使用 [florimondmanca/asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan#usage) 的 `LifespanManager`。\n\n///\n\n## 其他非同步函式呼叫 { #other-asynchronous-function-calls }\n\n由於測試函式現在是非同步的，你也可以在測試中呼叫（並 `await`）其他 `async` 函式，和在程式碼其他地方一樣。\n\n/// tip\n\n如果在將非同步呼叫整合進測試時遇到 `RuntimeError: Task attached to a different loop`（例如使用 [MongoDB 的 MotorClient](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop) 時），請記得：需要事件迴圈的物件只應在非同步函式內實例化，例如在 `@app.on_event(\"startup\")` 回呼中。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/behind-a-proxy.md",
    "content": "# 在代理之後 { #behind-a-proxy }\n\n在許多情況下，你會在 FastAPI 應用前面放一個「代理」（proxy），例如 Traefik 或 Nginx。\n\n這些代理可以處理 HTTPS 憑證等事務。\n\n## 代理轉發標頭 { #proxy-forwarded-headers }\n\n在你的應用前方的「代理」通常會在將請求送給你的「伺服器」之前，臨時加入一些標頭，讓伺服器知道這個請求是由代理「轉發」過來的，並告訴它原始（公開）的 URL，包括網域、是否使用 HTTPS 等。\n\n「伺服器」程式（例如透過 FastAPI CLI 啟動的 Uvicorn）能夠解讀這些標頭，然後把該資訊傳遞給你的應用。\n\n但出於安全考量，因為伺服器並不知道自己位於受信任的代理之後，所以它不會解讀那些標頭。\n\n/// note | 技術細節\n\n代理相關的標頭有：\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n### 啟用代理轉發標頭 { #enable-proxy-forwarded-headers }\n\n你可以在啟動 FastAPI CLI 時使用「CLI 選項」`--forwarded-allow-ips`，並傳入允許解析這些轉發標頭的受信任 IP 位址。\n\n如果將其設為 `--forwarded-allow-ips=\"*\"`，就會信任所有進來的 IP。\n\n如果你的「伺服器」位於受信任的「代理」之後，且只有代理會與它通訊，這樣會讓它接受該「代理」的任何 IP。\n\n<div class=\"termy\">\n\n```console\n$ fastapi run --forwarded-allow-ips=\"*\"\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### 使用 HTTPS 的重新導向 { #redirects-with-https }\n\n例如，假設你定義了一個「路徑操作（path operation）」`/items/`：\n\n{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *}\n\n如果用戶端嘗試前往 `/items`，預設會被重新導向到 `/items/`。\n\n但在設定「CLI 選項」`--forwarded-allow-ips` 之前，它可能會被重新導向到 `http://localhost:8000/items/`。\n\n不過，也許你的應用實際部署在 `https://mysuperapp.com`，那重新導向就應該是 `https://mysuperapp.com/items/`。\n\n設定 `--proxy-headers` 之後，FastAPI 就能重新導向到正確的位置。😎\n\n```\nhttps://mysuperapp.com/items/\n```\n\n/// tip\n\n如果你想了解更多 HTTPS 的內容，請參考指南［[關於 HTTPS](../deployment/https.md)］。\n\n///\n\n### 代理轉發標頭如何運作 { #how-proxy-forwarded-headers-work }\n\n以下是「代理」在用戶端與「應用伺服器」之間加入轉發標頭的視覺化示意：\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant Proxy as Proxy/Load Balancer\n    participant Server as FastAPI Server\n\n    Client->>Proxy: HTTPS Request<br/>Host: mysuperapp.com<br/>Path: /items\n\n    Note over Proxy: Proxy adds forwarded headers\n\n    Proxy->>Server: HTTP Request<br/>X-Forwarded-For: [client IP]<br/>X-Forwarded-Proto: https<br/>X-Forwarded-Host: mysuperapp.com<br/>Path: /items\n\n    Note over Server: Server interprets headers<br/>(if --forwarded-allow-ips is set)\n\n    Server->>Proxy: HTTP Response<br/>with correct HTTPS URLs\n\n    Proxy->>Client: HTTPS Response\n```\n\n「代理」會攔截原始用戶端請求，並在將其轉交給「應用伺服器」之前加入特殊的「轉發」標頭（`X-Forwarded-*`）。\n\n這些標頭會保留原始請求中原本會遺失的資訊：\n\n* X-Forwarded-For：原始用戶端的 IP 位址\n* X-Forwarded-Proto：原始協定（`https`）\n* X-Forwarded-Host：原始主機（`mysuperapp.com`）\n\n當以 `--forwarded-allow-ips` 設定好 FastAPI CLI 後，它會信任並使用這些標頭，例如在重新導向時產生正確的 URL。\n\n## 具有移除路徑前綴的代理 { #proxy-with-a-stripped-path-prefix }\n\n你可能會有一個會為你的應用加入路徑前綴的代理。\n\n在這些情況下，你可以使用 `root_path` 來設定你的應用。\n\n`root_path` 是 ASGI 規格（FastAPI 透過 Starlette 所遵循的規格）所提供的機制。\n\n`root_path` 用來處理這些特定情境。\n\n在掛載子應用時，內部也會使用它。\n\n這種「具有移除路徑前綴的代理」情況，代表你在程式碼中宣告了 `/app` 的路徑，但你在上面又加了一層（代理），把你的 FastAPI 應用放在像是 `/api/v1` 這樣的路徑底下。\n\n在這種情況下，原本的 `/app` 路徑實際上會以 `/api/v1/app` 對外提供服務。\n\n即使你的程式碼都是以只有 `/app` 為前提撰寫的。\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *}\n\n而代理會在把請求轉交給應用伺服器（多半是透過 FastAPI CLI 啟動的 Uvicorn）之前，動態地「移除」這個「路徑前綴」，讓你的應用仍然以為自己是在 `/app` 底下被提供，這樣你就不需要把整個程式碼都改成包含 `/api/v1` 這個前綴。\n\n到目前為止，一切都會如常運作。\n\n但是，當你打開整合的文件 UI（前端）時，它會預期在 `/openapi.json` 取得 OpenAPI 模式，而不是在 `/api/v1/openapi.json`。\n\n因此，前端（在瀏覽器中執行）會嘗試存取 `/openapi.json`，但無法取得 OpenAPI 模式。\n\n因為我們的應用前面有一個將路徑前綴設定為 `/api/v1` 的代理，所以前端需要從 `/api/v1/openapi.json` 取得 OpenAPI 模式。\n\n```mermaid\ngraph LR\n\nbrowser(\"Browser\")\nproxy[\"Proxy on http://0.0.0.0:9999/api/v1/app\"]\nserver[\"Server on http://127.0.0.1:8000/app\"]\n\nbrowser --> proxy\nproxy --> server\n```\n\n/// tip\n\nIP `0.0.0.0` 通常用來表示程式在該機器／伺服器上的所有可用 IP 上監聽。\n\n///\n\n文件 UI 也需要 OpenAPI 模式宣告此 API 的 `server` 位在 `/api/v1`（代理之後）。例如：\n\n```JSON hl_lines=\"4-8\"\n{\n    \"openapi\": \"3.1.0\",\n    // 其他內容\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        }\n    ],\n    \"paths\": {\n            // 其他內容\n    }\n}\n```\n\n在這個例子中，「Proxy」可以是 **Traefik**。而伺服器可以是以 **Uvicorn** 啟動的 FastAPI CLI，運行你的 FastAPI 應用。\n\n### 提供 `root_path` { #providing-the-root-path }\n\n要達成這一點，你可以像這樣使用命令列選項 `--root-path`：\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n如果你使用 Hypercorn，它也有 `--root-path` 這個選項。\n\n/// note | 技術細節\n\nASGI 規格針對這種用例定義了 `root_path`。\n\n而命令列選項 `--root-path` 就是提供該 `root_path`。\n\n///\n\n### 檢視目前的 `root_path` { #checking-the-current-root-path }\n\n你可以在每個請求中取得應用使用的 `root_path`，它是 `scope` 字典的一部分（ASGI 規格的一部分）。\n\n這裡我們把它放到回傳訊息中只是為了示範。\n\n{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *}\n\n接著，如果你用下列方式啟動 Uvicorn：\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n回應會像是：\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n### 在 FastAPI 應用中設定 `root_path` { #setting-the-root-path-in-the-fastapi-app }\n\n或者，如果你無法提供像 `--root-path` 這樣的命令列選項（或等效方式），你可以在建立 FastAPI 應用時設定 `root_path` 參數：\n\n{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *}\n\n把 `root_path` 傳給 `FastAPI` 等同於在 Uvicorn 或 Hypercorn 上使用命令列選項 `--root-path`。\n\n### 關於 `root_path` { #about-root-path }\n\n請記住，伺服器（Uvicorn）除了把 `root_path` 傳給應用之外，不會拿它做其他用途。\n\n但如果你用瀏覽器前往 [http://127.0.0.1:8000/app](http://127.0.0.1:8000/app) ，你會看到一般的回應：\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n因此，它不會預期被以 `http://127.0.0.1:8000/api/v1/app` 的方式存取。\n\nUvicorn 會預期代理以 `http://127.0.0.1:8000/app` 來存取 Uvicorn，而由代理負責在上層加上額外的 `/api/v1` 前綴。\n\n## 關於「移除路徑前綴」的代理 { #about-proxies-with-a-stripped-path-prefix }\n\n請記住，具有「移除路徑前綴」的代理只是其中一種設定方式。\n\n在許多情況下，預設可能是不移除路徑前綴。\n\n在那種情況（沒有移除路徑前綴）下，代理會監聽像是 `https://myawesomeapp.com`，然後當瀏覽器前往 `https://myawesomeapp.com/api/v1/app`，而你的伺服器（例如 Uvicorn）在 `http://127.0.0.1:8000` 監聽時，該代理（不移除路徑前綴）就會以同樣的路徑去存取 Uvicorn：`http://127.0.0.1:8000/api/v1/app`。\n\n## 在本機使用 Traefik 測試 { #testing-locally-with-traefik }\n\n你可以很容易地用 [Traefik](https://docs.traefik.io/) 在本機跑一個「移除路徑前綴」的測試。\n\n[下載 Traefik](https://github.com/containous/traefik/releases)，它是一個單一的執行檔，你可以解壓縮後直接在終端機執行。\n\n然後建立一個 `traefik.toml` 檔案，內容如下：\n\n```TOML hl_lines=\"3\"\n[entryPoints]\n  [entryPoints.http]\n    address = \":9999\"\n\n[providers]\n  [providers.file]\n    filename = \"routes.toml\"\n```\n\n這告訴 Traefik 監聽 9999 埠，並使用另一個檔案 `routes.toml`。\n\n/// tip\n\n我們使用 9999 埠而不是標準的 HTTP 80 埠，這樣你就不需要以管理員（`sudo`）權限來執行。\n\n///\n\n接著建立另一個 `routes.toml` 檔案：\n\n```TOML hl_lines=\"5  12  20\"\n[http]\n  [http.middlewares]\n\n    [http.middlewares.api-stripprefix.stripPrefix]\n      prefixes = [\"/api/v1\"]\n\n  [http.routers]\n\n    [http.routers.app-http]\n      entryPoints = [\"http\"]\n      service = \"app\"\n      rule = \"PathPrefix(`/api/v1`)\"\n      middlewares = [\"api-stripprefix\"]\n\n  [http.services]\n\n    [http.services.app]\n      [http.services.app.loadBalancer]\n        [[http.services.app.loadBalancer.servers]]\n          url = \"http://127.0.0.1:8000\"\n```\n\n這個檔案把 Traefik 設定為使用 `/api/v1` 的路徑前綴。\n\n然後 Traefik 會把它的請求轉發到在 `http://127.0.0.1:8000` 上運行的 Uvicorn。\n\n現在啟動 Traefik：\n\n<div class=\"termy\">\n\n```console\n$ ./traefik --configFile=traefik.toml\n\nINFO[0000] Configuration loaded from file: /home/user/awesomeapi/traefik.toml\n```\n\n</div>\n\n然後啟動你的應用，使用 `--root-path` 選項：\n\n<div class=\"termy\">\n\n```console\n$ fastapi run main.py --forwarded-allow-ips=\"*\" --root-path /api/v1\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n### 檢查回應 { #check-the-responses }\n\n現在，如果你前往 Uvicorn 的埠：[http://127.0.0.1:8000/app](http://127.0.0.1:8000/app)，你會看到一般的回應：\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n/// tip\n\n注意，儘管你是用 `http://127.0.0.1:8000/app` 存取，它仍然顯示從 `--root-path` 選項取得的 `root_path` 為 `/api/v1`。\n\n///\n\n接著打開使用 Traefik 埠且包含路徑前綴的 URL：[http://127.0.0.1:9999/api/v1/app](http://127.0.0.1:9999/api/v1/app)。\n\n我們會得到相同的回應：\n\n```JSON\n{\n    \"message\": \"Hello World\",\n    \"root_path\": \"/api/v1\"\n}\n```\n\n但這次是在由代理提供的、帶有前綴路徑的 URL：`/api/v1`。\n\n當然，這裡的重點是大家都會透過代理來存取應用，所以帶有 `/api/v1` 路徑前綴的版本才是「正確」的。\n\n而沒有路徑前綴的版本（`http://127.0.0.1:8000/app`），也就是直接由 Uvicorn 提供的，應該只給「代理」（Traefik）來存取。\n\n這展示了代理（Traefik）如何使用路徑前綴，以及伺服器（Uvicorn）如何使用 `--root-path` 選項提供的 `root_path`。\n\n### 檢查文件 UI { #check-the-docs-ui }\n\n接下來是有趣的部分。✨\n\n「正式」的存取方式應該是透過我們定義了路徑前綴的代理。因此，如我們預期，如果你直接透過 Uvicorn 供應的文件 UI、而 URL 中沒有該路徑前綴，那它不會運作，因為它預期要透過代理來存取。\n\n你可以在 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) 檢查：\n\n<img src=\"/img/tutorial/behind-a-proxy/image01.png\">\n\n但如果我們改用「正式」的 URL，也就是使用埠號 `9999` 的代理、並在 `/api/v1/docs`，它就能正確運作了！🎉\n\n你可以在 [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) 檢查：\n\n<img src=\"/img/tutorial/behind-a-proxy/image02.png\">\n\n正如我們所希望的那樣。✔️\n\n這是因為 FastAPI 使用這個 `root_path` 來在 OpenAPI 中建立預設的 `server`，其 URL 就是 `root_path` 所提供的值。\n\n## 其他 servers { #additional-servers }\n\n/// warning\n\n這是更進階的用法。你可以選擇略過。\n\n///\n\n預設情況下，FastAPI 會在 OpenAPI 模式中建立一個 `server`，其 URL 為 `root_path`。\n\n但你也可以另外提供其他 `servers`，例如你想要用「同一份」文件 UI 來與測試（staging）與正式（production）環境互動。\n\n如果你傳入自訂的 `servers` 清單，且同時存在 `root_path`（因為你的 API 位於代理之後），FastAPI 會在清單開頭插入一個 `server`，其 URL 為該 `root_path`。\n\n例如：\n\n{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *}\n\n將會產生如下的 OpenAPI 模式：\n\n```JSON hl_lines=\"5-7\"\n{\n    \"openapi\": \"3.1.0\",\n    // 其他內容\n    \"servers\": [\n        {\n            \"url\": \"/api/v1\"\n        },\n        {\n            \"url\": \"https://stag.example.com\",\n            \"description\": \"Staging environment\"\n        },\n        {\n            \"url\": \"https://prod.example.com\",\n            \"description\": \"Production environment\"\n        }\n    ],\n    \"paths\": {\n            // 其他內容\n    }\n}\n```\n\n/// tip\n\n注意自動產生的 server，其 `url` 值為 `/api/v1`，取自 `root_path`。\n\n///\n\n在位於 [http://127.0.0.1:9999/api/v1/docs](http://127.0.0.1:9999/api/v1/docs) 的文件 UI 中看起來會像這樣：\n\n<img src=\"/img/tutorial/behind-a-proxy/image03.png\">\n\n/// tip\n\n文件 UI 會與你所選擇的 server 互動。\n\n///\n\n/// note | 技術細節\n\nOpenAPI 規格中的 `servers` 屬性是可選的。\n\n如果你沒有指定 `servers` 參數，且 `root_path` 等於 `/`，則在產生的 OpenAPI 模式中會完全省略 `servers` 屬性（預設行為），這等同於只有一個 `url` 值為 `/` 的 server。\n\n///\n\n### 停用從 `root_path` 自動加入的 server { #disable-automatic-server-from-root-path }\n\n如果你不希望 FastAPI 使用 `root_path` 自動加入一個 server，你可以使用參數 `root_path_in_servers=False`：\n\n{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *}\n\n這樣它就不會被包含在 OpenAPI 模式中。\n\n## 掛載子應用 { #mounting-a-sub-application }\n\n如果你需要在同時使用具有 `root_path` 的代理時，掛載一個子應用（如［[子應用 - 掛載](sub-applications.md)］中所述），可以像平常一樣操作，正如你所預期的那樣。\n\nFastAPI 會在內部智慧地使用 `root_path`，所以一切都能順利運作。✨\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/custom-response.md",
    "content": "# 自訂回應——HTML、串流、檔案與其他 { #custom-response-html-stream-file-others }\n\n預設情況下，**FastAPI** 會回傳 JSON 回應。\n\n你可以像在[直接回傳 Response](response-directly.md)中所示，直接回傳一個 `Response` 來覆寫它。\n\n但如果你直接回傳一個 `Response`（或其子類別，例如 `JSONResponse`），資料將不會被自動轉換（即使你宣告了 `response_model`），而且文件也不會自動產生（例如，在產生的 OpenAPI 中包含 HTTP 標頭 `Content-Type` 的特定「media type」）。\n\n你也可以在「路徑操作裝飾器」中使用 `response_class` 參數，宣告要使用的 `Response`（例如任意 `Response` 子類別）。\n\n你從「路徑操作函式」回傳的內容，會被放進該 `Response` 中。\n\n/// note\n\n若你使用的回應類別沒有 media type，FastAPI 會假設你的回應沒有內容，因此不會在產生的 OpenAPI 文件中記錄回應格式。\n\n///\n\n## JSON 回應 { #json-responses }\n\nFastAPI 預設回傳 JSON 回應。\n\n如果你宣告了[回應模型](../tutorial/response-model.md)，FastAPI 會使用 Pydantic 將資料序列化為 JSON。\n\n如果你沒有宣告回應模型，FastAPI 會使用在[JSON 相容編碼器](../tutorial/encoder.md)中解釋的 `jsonable_encoder`，並將結果放進 `JSONResponse`。\n\n如果你宣告的 `response_class` 具有 JSON 的 media type（`application/json`），像 `JSONResponse`，你回傳的資料會自動以你在「路徑操作裝飾器」中宣告的任何 Pydantic `response_model` 進行轉換（與過濾）。但資料不會由 Pydantic 直接序列化成 JSON 位元組；取而代之，會先經由 `jsonable_encoder` 轉換，然後交給 `JSONResponse` 類別，該類別會使用 Python 標準的 JSON 函式庫將其序列化為位元組。\n\n### JSON 效能 { #json-performance }\n\n簡而言之，若你想要最佳效能，請使用[回應模型](../tutorial/response-model.md)，並且不要在「路徑操作裝飾器」中宣告 `response_class`。\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py ln[15:17] hl[16] *}\n\n## HTML 回應 { #html-response }\n\n要直接從 **FastAPI** 回傳 HTML，使用 `HTMLResponse`。\n\n- 匯入 `HTMLResponse`。\n- 在「路徑操作裝飾器」中，將 `HTMLResponse` 傳給 `response_class` 參數。\n\n{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *}\n\n/// info\n\n參數 `response_class` 也會用來定義回應的「media type」。\n\n在此情況下，HTTP 標頭 `Content-Type` 會被設為 `text/html`。\n\n而且它會以此形式被記錄到 OpenAPI 中。\n\n///\n\n### 回傳 `Response` { #return-a-response }\n\n如[直接回傳 Response](response-directly.md)所示，你也可以在「路徑操作」中直接回傳以覆寫回應。\n\n上面的相同範例，回傳 `HTMLResponse`，可以像這樣：\n\n{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *}\n\n/// warning\n\n由你的「路徑操作函式」直接回傳的 `Response` 不會被記錄進 OpenAPI（例如不會記錄 `Content-Type`），也不會出現在自動產生的互動式文件中。\n\n///\n\n/// info\n\n當然，實際的 `Content-Type` 標頭、狀態碼等，會來自你回傳的 `Response` 物件。\n\n///\n\n### 在 OpenAPI 中文件化並覆寫 `Response` { #document-in-openapi-and-override-response }\n\n如果你想在函式內覆寫回應，同時又要在 OpenAPI 中記錄「media type」，你可以同時使用 `response_class` 參數並回傳一個 `Response` 物件。\n\n此時，`response_class` 只會用於記錄該 OpenAPI「路徑操作」，而你回傳的 `Response` 將會如實使用。\n\n#### 直接回傳 `HTMLResponse` { #return-an-htmlresponse-directly }\n\n例如，可能會像這樣：\n\n{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *}\n\n在這個例子中，函式 `generate_html_response()` 已經產生並回傳了一個 `Response`，而不是把 HTML 當作 `str` 回傳。\n\n透過回傳 `generate_html_response()` 的結果，你其實已經回傳了一個 `Response`，這會覆寫 **FastAPI** 的預設行為。\n\n但因為你同時也在 `response_class` 中傳入了 `HTMLResponse`，**FastAPI** 便能在 OpenAPI 與互動式文件中，將其以 `text/html` 的 HTML 形式記錄：\n\n<img src=\"/img/tutorial/custom-response/image01.png\">\n\n## 可用的回應 { #available-responses }\n\n以下是一些可用的回應類別。\n\n記得你可以用 `Response` 回傳其他任何東西，甚至建立自訂的子類別。\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.responses import HTMLResponse`。\n\n**FastAPI** 將 `starlette.responses` 以 `fastapi.responses` 提供給你（開發者）做為方便之用。但大多數可用的回應其實直接來自 Starlette。\n\n///\n\n### `Response` { #response }\n\n主要的 `Response` 類別，其他回應皆繼承自它。\n\n你也可以直接回傳它。\n\n它接受以下參數：\n\n- `content` - `str` 或 `bytes`。\n- `status_code` - `int` 類型的 HTTP 狀態碼。\n- `headers` - 由字串組成的 `dict`。\n- `media_type` - 描述 media type 的 `str`。例如 `\"text/html\"`。\n\nFastAPI（實際上是 Starlette）會自動包含 Content-Length 標頭。也會根據 `media_type`（並為文字型別附加 charset）包含 Content-Type 標頭。\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n### `HTMLResponse` { #htmlresponse }\n\n接收文字或位元組並回傳 HTML 回應，如上所述。\n\n### `PlainTextResponse` { #plaintextresponse }\n\n接收文字或位元組並回傳純文字回應。\n\n{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *}\n\n### `JSONResponse` { #jsonresponse }\n\n接收資料並回傳 `application/json` 編碼的回應。\n\n這是 **FastAPI** 的預設回應，如上所述。\n\n/// note | 技術細節\n\n但如果你宣告了回應模型或回傳型別，將會直接用它來把資料序列化為 JSON，並直接回傳具有正確 JSON media type 的回應，而不會使用 `JSONResponse` 類別。\n\n這是取得最佳效能的理想方式。\n\n///\n\n### `RedirectResponse` { #redirectresponse }\n\n回傳一個 HTTP 重新導向。預設使用 307 狀態碼（Temporary Redirect）。\n\n你可以直接回傳 `RedirectResponse`：\n\n{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *}\n\n---\n\n或者你可以在 `response_class` 參數中使用它：\n\n{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *}\n\n若這麼做，你就可以在「路徑操作函式」中直接回傳 URL。\n\n在此情況下，所使用的 `status_code` 會是 `RedirectResponse` 的預設值 `307`。\n\n---\n\n你也可以同時搭配 `status_code` 與 `response_class` 參數：\n\n{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *}\n\n### `StreamingResponse` { #streamingresponse }\n\n接收一個 async 產生器或一般的產生器／疊代器（帶有 `yield` 的函式），並以串流方式傳送回應本文。\n\n{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *}\n\n/// note | 技術細節\n\n一個 `async` 任務只能在抵達某個 `await` 時才能被取消。如果沒有 `await`，該產生器（帶有 `yield` 的函式）將無法被正確取消，甚至在請求取消後仍可能持續執行。\n\n因為這個小範例不需要任何 `await` 陳述式，我們加入 `await anyio.sleep(0)`，讓事件迴圈有機會處理取消。\n\n對於大型或無限的串流來說，這點更為重要。\n\n///\n\n/// tip\n\n與其直接回傳 `StreamingResponse`，你大概會想遵循[資料串流](./stream-data.md)中的作法，這樣更方便，並且會在底層幫你處理取消。\n\n如果你要串流 JSON Lines，請參考教學：[串流 JSON Lines](../tutorial/stream-json-lines.md)。\n\n///\n\n### `FileResponse` { #fileresponse }\n\n以非同步串流方式將檔案作為回應。\n\n它在初始化時所需的參數與其他回應型別不同：\n\n- `path` - 要串流的檔案路徑。\n- `headers` - 要包含的自訂標頭，字典形式。\n- `media_type` - 描述 media type 的字串。若未設定，將根據檔名或路徑推斷 media type。\n- `filename` - 若設定，會包含在回應的 `Content-Disposition` 中。\n\n檔案回應會包含適當的 `Content-Length`、`Last-Modified` 與 `ETag` 標頭。\n\n{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *}\n\n你也可以使用 `response_class` 參數：\n\n{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *}\n\n在此情況下，你可以在「路徑操作函式」中直接回傳檔案路徑。\n\n## 自訂回應類別 { #custom-response-class }\n\n你可以建立自己的自訂回應類別，繼承自 `Response` 並加以使用。\n\n例如，假設你要使用 [`orjson`](https://github.com/ijl/orjson) 並套用一些設定。\n\n假設你想回傳縮排且格式化的 JSON，因此要使用 orjson 選項 `orjson.OPT_INDENT_2`。\n\n你可以建立 `CustomORJSONResponse`。你主要需要做的是建立一個 `Response.render(content)` 方法，將內容以 `bytes` 回傳：\n\n{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *}\n\n現在，不再是回傳：\n\n```json\n{\"message\": \"Hello World\"}\n```\n\n...這個回應會回傳：\n\n```json\n{\n  \"message\": \"Hello World\"\n}\n```\n\n當然，你大概能找到比格式化 JSON 更好的方式來利用這個能力。😉\n\n### `orjson` 或回應模型 { #orjson-or-response-model }\n\n如果你追求效能，使用[回應模型](../tutorial/response-model.md) 大概會比使用 `orjson` 回應更好。\n\n有了回應模型，FastAPI 會使用 Pydantic 直接將資料序列化為 JSON，而不需要像其他情況那樣先經過 `jsonable_encoder` 之類的中介步驟。\n\n而且在底層，Pydantic 用來序列化為 JSON 的 Rust 機制和 `orjson` 相同，因此用回應模型已經能獲得最佳效能。\n\n## 預設回應類別 { #default-response-class }\n\n在建立 **FastAPI** 類別實例或 `APIRouter` 時，你可以指定預設要使用哪個回應類別。\n\n用來設定的是 `default_response_class` 參數。\n\n在下面的例子中，**FastAPI** 會在所有「路徑操作」中預設使用 `HTMLResponse`，而不是 JSON。\n\n{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *}\n\n/// tip\n\n你仍然可以在「路徑操作」中像以前一樣覆寫 `response_class`。\n\n///\n\n## 其他文件化選項 { #additional-documentation }\n\n你也可以在 OpenAPI 中使用 `responses` 宣告 media type 與其他許多細節：[在 OpenAPI 中的額外回應](additional-responses.md)。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/dataclasses.md",
    "content": "# 使用 Dataclasses { #using-dataclasses }\n\nFastAPI 建立在 **Pydantic** 之上，我之前示範過如何使用 Pydantic 模型來宣告請求與回應。\n\n但 FastAPI 也同樣支援以相同方式使用 [`dataclasses`](https://docs.python.org/3/library/dataclasses.html)：\n\n{* ../../docs_src/dataclasses_/tutorial001_py310.py hl[1,6:11,18:19] *}\n\n這之所以可行，要感謝 **Pydantic**，因為它 [內建支援 `dataclasses`](https://docs.pydantic.dev/latest/concepts/dataclasses/#use-of-stdlib-dataclasses-with-basemodel)。\n\n所以，即使上面的程式碼沒有明確使用 Pydantic，FastAPI 仍會使用 Pydantic 將那些標準的 dataclass 轉換為 Pydantic 版本的 dataclass。\n\n而且當然一樣支援：\n\n- 資料驗證\n- 資料序列化\n- 資料文件化等\n\n它的運作方式與 Pydantic 模型相同；實際上，底層就是透過 Pydantic 達成的。\n\n/// info\n\n請記得，dataclass 無法做到 Pydantic 模型能做的一切。\n\n所以你可能仍然需要使用 Pydantic 模型。\n\n但如果你手邊剛好有一堆 dataclass，這是個不錯的小技巧，可以用來用 FastAPI 驅動一個 Web API。🤓\n\n///\n\n## 在 `response_model` 中使用 Dataclasses { #dataclasses-in-response-model }\n\n你也可以在 `response_model` 參數中使用 `dataclasses`：\n\n{* ../../docs_src/dataclasses_/tutorial002_py310.py hl[1,6:12,18] *}\n\n該 dataclass 會自動轉換為 Pydantic 的 dataclass。\n\n如此一來，其結構描述（schema）會顯示在 API 文件介面中：\n\n<img src=\"/img/tutorial/dataclasses/image01.png\">\n\n## 巢狀資料結構中的 Dataclasses { #dataclasses-in-nested-data-structures }\n\n你也可以將 `dataclasses` 與其他型別註記結合，建立巢狀的資料結構。\n\n在某些情況下，你可能仍需要使用 Pydantic 版本的 `dataclasses`。例如，當自動產生的 API 文件出現錯誤時。\n\n這種情況下，你可以把標準的 `dataclasses` 直接換成 `pydantic.dataclasses`，它是可直接替換（drop-in replacement）的：\n\n{* ../../docs_src/dataclasses_/tutorial003_py310.py hl[1,4,7:10,13:16,22:24,27] *}\n\n1. 我們仍然從標準的 `dataclasses` 匯入 `field`。\n2. `pydantic.dataclasses` 是 `dataclasses` 的可直接替換版本。\n3. `Author` dataclass 內含一個 `Item` dataclass 的清單。\n4. `Author` dataclass 被用作 `response_model` 參數。\n5. 你可以將其他標準型別註記與 dataclass 一起用作請求本文。\n\n   在此例中，它是 `Item` dataclass 的清單。\n6. 這裡我們回傳一個字典，其中的 `items` 是一個 dataclass 清單。\n\n   FastAPI 仍能將資料<dfn title=\"將資料轉換成可傳輸的格式\">序列化</dfn>為 JSON。\n7. 這裡 `response_model` 使用的是「`Author` dataclass 的清單」這種型別註記。\n\n   同樣地，你可以把 `dataclasses` 與標準型別註記組合使用。\n8. 注意這個「路徑操作函式」使用的是一般的 `def` 而非 `async def`。\n\n   一如往常，在 FastAPI 中你可以視需要混用 `def` 與 `async def`。\n\n   如果需要複習何時用哪個，請參考文件中關於 [`async` 與 `await`](../async.md#in-a-hurry) 的章節「In a hurry?」。\n9. 這個「路徑操作函式」回傳的不是 dataclass（雖然也可以），而是一個包含內部資料的字典清單。\n\n   FastAPI 會使用 `response_model` 參數（其中包含 dataclass）來轉換回應。\n\n你可以把 `dataclasses` 與其他型別註記以多種方式組合，形成複雜的資料結構。\n\n查看上面程式碼中的註解提示以了解更具體的細節。\n\n## 延伸閱讀 { #learn-more }\n\n你也可以將 `dataclasses` 與其他 Pydantic 模型結合、從它們繼承、把它們包含進你的自訂模型等。\n\n想了解更多，請參考 [Pydantic 關於 dataclasses 的文件](https://docs.pydantic.dev/latest/concepts/dataclasses/)。\n\n## 版本 { #version }\n\n自 FastAPI 版本 `0.67.0` 起可用。🔖\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/events.md",
    "content": "# 生命週期事件 { #lifespan-events }\n\n你可以定義在應用程式**啟動**之前要執行的邏輯（程式碼）。也就是說，這段程式碼會在應用開始接收請求**之前**、**只執行一次**。\n\n同樣地，你也可以定義在應用程式**關閉**時要執行的邏輯（程式碼）。在這種情況下，這段程式碼會在處理了**許多請求**之後、**只執行一次**。\n\n因為這些程式碼分別在應用開始接收請求**之前**與**完成**處理請求之後執行，所以涵蓋了整個應用的**生命週期**（「lifespan」這個詞稍後會很重要 😉）。\n\n這對於為整個應用設定需要**共用**於多個請求的**資源**，以及在之後進行**清理**，非常有用。比如資料庫連線池、或載入一個共用的機器學習模型。\n\n## 使用情境 { #use-case }\n\n先從一個**使用情境**開始，然後看看如何用這個機制解決。\n\n想像你有一些要用來處理請求的**機器學習模型**。🤖\n\n同一組模型會在多個請求間共用，所以不是每個請求或每個使用者各有一個模型。\n\n再想像一下，載入模型**需要一段時間**，因為它必須從**磁碟**讀取大量資料。所以你不想在每個請求都做一次。\n\n你可以在模組／檔案的最上層載入，但這也表示即使只是要跑一個簡單的自動化測試，也會去**載入模型**，導致測試**變慢**，因為它得等模型載入完才能執行與模型無關的程式碼部分。\n\n我們要解決的正是這件事：在開始處理請求之前再載入模型，但只在應用程式即將開始接收請求時載入，而不是在匯入程式碼時就載入。\n\n## 生命週期（Lifespan） { #lifespan }\n\n你可以使用 `FastAPI` 應用的 `lifespan` 參數，搭配「context manager」（稍後會示範），來定義這些 *startup* 與 *shutdown* 邏輯。\n\n先看一個例子，接著再深入說明。\n\n我們建立一個帶有 `yield` 的非同步函式 `lifespan()`，如下：\n\n{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *}\n\n這裡我們透過在 `yield` 之前把（假的）模型函式放進機器學習模型的字典中，來模擬昂貴的 *startup* 載入模型操作。這段程式會在應用**開始接收請求之前**執行，也就是 *startup* 階段。\n\n接著，在 `yield` 之後，我們卸載模型。這段程式會在應用**完成處理請求之後**、也就是 *shutdown* 前執行。這可以用來釋放資源，例如記憶體或 GPU。\n\n/// tip\n\n`shutdown` 會在你**停止**應用程式時發生。\n\n也許你要啟動新版本，或只是不想再跑它了。🤷\n\n///\n\n### Lifespan 函式 { #lifespan-function }\n\n首先要注意的是，我們定義了一個帶有 `yield` 的 async 函式。這和帶有 `yield` 的依賴（Dependencies）非常相似。\n\n{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *}\n\n函式在 `yield` 之前的部分，會在應用啟動前先執行。\n\n`yield` 之後的部分，會在應用結束後再執行。\n\n### 非同步內容管理器（Async Context Manager） { #async-context-manager }\n\n你會看到這個函式被 `@asynccontextmanager` 裝飾。\n\n它會把函式轉換成所謂的「**非同步內容管理器（async context manager）**」。\n\n{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *}\n\nPython 中的**內容管理器（context manager）**可以用在 `with` 陳述式中，例如 `open()` 可以作為內容管理器使用：\n\n```Python\nwith open(\"file.txt\") as file:\n    file.read()\n```\n\n在較新的 Python 版本中，也有**非同步內容管理器**。你可以用 `async with` 來使用它：\n\n```Python\nasync with lifespan(app):\n    await do_stuff()\n```\n\n當你像上面那樣建立一個內容管理器或非同步內容管理器時，在進入 `with` 區塊之前，會先執行 `yield` 之前的程式碼；離開 `with` 區塊之後，會執行 `yield` 之後的程式碼。\n\n在我們的範例中，並不是直接用它，而是把它傳給 FastAPI 來使用。\n\n`FastAPI` 應用的 `lifespan` 參數需要一個**非同步內容管理器**，所以我們可以把剛寫好的 `lifespan` 非同步內容管理器傳給它。\n\n{* ../../docs_src/events/tutorial003_py310.py hl[22] *}\n\n## 替代事件（已棄用） { #alternative-events-deprecated }\n\n/// warning\n\n目前建議使用上面所述，透過 `FastAPI` 應用的 `lifespan` 參數來處理 *startup* 與 *shutdown*。如果你提供了 `lifespan` 參數，`startup` 與 `shutdown` 事件處理器將不會被呼叫。要嘛全用 `lifespan`，要嘛全用事件，不能同時混用。\n\n你大概可以直接跳過這一節。\n\n///\n\n也有另一種方式可以定義在 *startup* 與 *shutdown* 期間要執行的邏輯。\n\n你可以定義事件處理器（函式）來在應用啟動前或關閉時執行。\n\n這些函式可以用 `async def` 或一般的 `def` 宣告。\n\n### `startup` 事件 { #startup-event }\n\n要加入一個在應用啟動前執行的函式，使用事件 `\"startup\"` 來宣告：\n\n{* ../../docs_src/events/tutorial001_py310.py hl[8] *}\n\n在這個例子中，`startup` 事件處理器函式會用一些值來初始化 items 的「資料庫」（其實就是個 `dict`）。\n\n你可以註冊多個事件處理函式。\n\n而且在所有 `startup` 事件處理器都完成之前，你的應用不會開始接收請求。\n\n### `shutdown` 事件 { #shutdown-event }\n\n要加入一個在應用關閉時執行的函式，使用事件 `\"shutdown\"` 來宣告：\n\n{* ../../docs_src/events/tutorial002_py310.py hl[6] *}\n\n在這裡，`shutdown` 事件處理器函式會把一行文字 `\"Application shutdown\"` 寫入檔案 `log.txt`。\n\n/// info\n\n在 `open()` 函式中，`mode=\"a\"` 表示「append（附加）」；也就是說，這行文字會加在檔案現有內容之後，而不會覆寫先前的內容。\n\n///\n\n/// tip\n\n注意這裡我們使用的是標準 Python 的 `open()` 函式來操作檔案。\n\n這涉及 I/O（輸入／輸出），也就是需要「等待」資料寫入磁碟。\n\n但 `open()` 並不使用 `async` 與 `await`。\n\n所以我們用一般的 `def` 來宣告事件處理器，而不是 `async def`。\n\n///\n\n### 同時使用 `startup` 與 `shutdown` { #startup-and-shutdown-together }\n\n你的 *startup* 與 *shutdown* 邏輯很可能是相關聯的：你可能會先啟動某個東西再把它結束、先取得資源再釋放它，等等。\n\n如果把它們拆成兩個彼此不共享邏輯或變數的獨立函式，會比較麻煩，你得把值存在全域變數或用其他技巧。\n\n因此，現在建議改用上面介紹的 `lifespan`。\n\n## 技術細節 { #technical-details }\n\n給有興趣鑽研的同好一點技術細節。🤓\n\n在底層的 ASGI 技術規範中，這屬於 [Lifespan Protocol](https://asgi.readthedocs.io/en/latest/specs/lifespan.html) 的一部分，並定義了 `startup` 與 `shutdown` 兩種事件。\n\n/// info\n\n你可以在 [Starlette 的 Lifespan 文件](https://www.starlette.dev/lifespan/) 讀到更多關於 Starlette `lifespan` 處理器的資訊。\n\n也包含如何處理可在程式其他區域使用的 lifespan 狀態。\n\n///\n\n## 子應用程式 { #sub-applications }\n\n🚨 請記住，這些生命週期事件（startup 與 shutdown）只會在主應用程式上執行，不會在[子應用程式 - 掛載](sub-applications.md)上執行。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/generate-clients.md",
    "content": "# 產生 SDK { #generating-sdks }\n\n由於 **FastAPI** 建立在 **OpenAPI** 規格之上，其 API 能以許多工具都能理解的標準格式來描述。\n\n這讓你能輕鬆產生最新的**文件**、多語言的用戶端程式庫（<abbr title=\"Software Development Kits - 軟體開發套件\">**SDKs**</abbr>），以及與程式碼保持同步的**測試**或**自動化工作流程**。\n\n在本指南中，你將學會如何為你的 FastAPI 後端產生 **TypeScript SDK**。\n\n## 開源 SDK 產生器 { #open-source-sdk-generators }\n\n其中一個相當萬用的選擇是 [OpenAPI Generator](https://openapi-generator.tech/)，它支援**多種程式語言**，並能從你的 OpenAPI 規格產生 SDK。\n\n針對 **TypeScript 用戶端**，[Hey API](https://heyapi.dev/) 是專門打造的解決方案，為 TypeScript 生態系提供最佳化的體驗。\n\n你可以在 [OpenAPI.Tools](https://openapi.tools/#sdk) 找到更多 SDK 產生器。\n\n/// tip\n\nFastAPI 會自動產生 **OpenAPI 3.1** 規格，因此你使用的任何工具都必須支援這個版本。\n\n///\n\n## 來自 FastAPI 贊助商的 SDK 產生器 { #sdk-generators-from-fastapi-sponsors }\n\n本節重點介紹由贊助 FastAPI 的公司提供的**創投支持**與**公司維運**的解決方案。這些產品在高品質的自動產生 SDK 之外，還提供**額外功能**與**整合**。\n\n透過 ✨ [**贊助 FastAPI**](../help-fastapi.md#sponsor-the-author) ✨，這些公司幫助確保框架與其**生態系**維持健康且**永續**。\n\n他們的贊助也展現對 FastAPI **社群**（你）的高度承諾，不僅關心提供**優良服務**，也支持 **FastAPI** 作為一個**穩健且蓬勃的框架**。🙇\n\n例如，你可以嘗試：\n\n* [Speakeasy](https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship)\n* [Stainless](https://www.stainless.com/?utm_source=fastapi&utm_medium=referral)\n* [liblab](https://developers.liblab.com/tutorials/sdk-for-fastapi?utm_source=fastapi)\n\n其中有些方案也可能是開源或提供免費方案，讓你不需財務承諾就能試用。其他商業的 SDK 產生器也不少，你可以在網路上找到。🤓\n\n## 建立 TypeScript SDK { #create-a-typescript-sdk }\n\n先從一個簡單的 FastAPI 應用開始：\n\n{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *}\n\n注意這些 *路徑操作* 為請求與回應的有效載荷定義了所用的模型，使用了 `Item` 與 `ResponseMessage` 這兩個模型。\n\n### API 文件 { #api-docs }\n\n如果你前往 `/docs`，你會看到其中包含了請求要送出的資料與回應接收的資料之**結構（schemas）**：\n\n<img src=\"/img/tutorial/generate-clients/image01.png\">\n\n你之所以能看到這些結構，是因為它們在應用內以模型宣告了。\n\n這些資訊都在應用的 **OpenAPI 結構**中，並顯示在 API 文件裡。\n\n同樣包含在 OpenAPI 中的模型資訊，也可以用來**產生用戶端程式碼**。\n\n### Hey API { #hey-api }\n\n當我們有含模型的 FastAPI 應用後，就能用 Hey API 來產生 TypeScript 用戶端。最快的方法是透過 npx：\n\n```sh\nnpx @hey-api/openapi-ts -i http://localhost:8000/openapi.json -o src/client\n```\n\n這會在 `./src/client` 產生一個 TypeScript SDK。\n\n你可以在他們的網站了解如何[安裝 `@hey-api/openapi-ts`](https://heyapi.dev/openapi-ts/get-started)，以及閱讀[產生的輸出內容](https://heyapi.dev/openapi-ts/output)。\n\n### 使用 SDK { #using-the-sdk }\n\n現在你可以匯入並使用用戶端程式碼。大致看起來會像這樣，你會發現方法有自動完成：\n\n<img src=\"/img/tutorial/generate-clients/image02.png\">\n\n你也會對要送出的有效載荷獲得自動完成：\n\n<img src=\"/img/tutorial/generate-clients/image03.png\">\n\n/// tip\n\n注意 `name` 與 `price` 的自動完成，這是由 FastAPI 應用中的 `Item` 模型所定義。\n\n///\n\n你在送出的資料上也會看到行內錯誤：\n\n<img src=\"/img/tutorial/generate-clients/image04.png\">\n\n回應物件同樣有自動完成：\n\n<img src=\"/img/tutorial/generate-clients/image05.png\">\n\n## 含標籤的 FastAPI 應用 { #fastapi-app-with-tags }\n\n在許多情況下，你的 FastAPI 應用會更大，你可能會用標籤將不同群組的 *路徑操作* 分開。\n\n例如，你可以有一個 **items** 區塊與另一個 **users** 區塊，並透過標籤區分：\n\n{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *}\n\n### 使用標籤產生 TypeScript 用戶端 { #generate-a-typescript-client-with-tags }\n\n若你為使用標籤的 FastAPI 應用產生用戶端，產生器通常也會依標籤將用戶端程式碼分開。\n\n如此一來，用戶端程式碼就能有條理地正確分組與排列：\n\n<img src=\"/img/tutorial/generate-clients/image06.png\">\n\n在此例中，你會有：\n\n* `ItemsService`\n* `UsersService`\n\n### 用戶端方法名稱 { #client-method-names }\n\n目前像 `createItemItemsPost` 這樣的產生方法名稱看起來不太俐落：\n\n```TypeScript\nItemsService.createItemItemsPost({name: \"Plumbus\", price: 5})\n```\n\n...那是因為用戶端產生器對每個 *路徑操作* 都使用 OpenAPI 內部的**操作 ID（operation ID）**。\n\nOpenAPI 要求每個操作 ID 在所有 *路徑操作* 之間必須唯一，因此 FastAPI 會用**函式名稱**、**路徑**與 **HTTP 方法/操作**來產生該操作 ID，如此便能確保操作 ID 的唯一性。\n\n接下來我會示範如何把它變得更好看。🤓\n\n## 自訂 Operation ID 與更好的方法名稱 { #custom-operation-ids-and-better-method-names }\n\n你可以**修改**這些操作 ID 的**產生方式**，讓它們更簡潔，並在用戶端中得到**更簡潔的方法名稱**。\n\n在這種情況下，你需要用其他方式確保每個操作 ID 都是**唯一**的。\n\n例如，你可以確保每個 *路徑操作* 都有標籤，接著根據**標籤**與 *路徑操作* 的**名稱**（函式名稱）來產生操作 ID。\n\n### 自訂唯一 ID 產生函式 { #custom-generate-unique-id-function }\n\nFastAPI 會為每個 *路徑操作* 使用一個**唯一 ID**，它會被用於**操作 ID**，以及任何請求或回應所需的自訂模型名稱。\n\n你可以自訂該函式。它接收一個 APIRoute 並回傳字串。\n\n例如，下面使用第一個標籤（你通常只會有一個標籤）以及 *路徑操作* 的名稱（函式名稱）。\n\n接著你可以將這個自訂函式以 `generate_unique_id_function` 參數傳給 **FastAPI**：\n\n{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *}\n\n### 使用自訂 Operation ID 產生 TypeScript 用戶端 { #generate-a-typescript-client-with-custom-operation-ids }\n\n現在，如果你再次產生用戶端，會看到方法名稱已改善：\n\n<img src=\"/img/tutorial/generate-clients/image07.png\">\n\n如你所見，方法名稱現在包含標籤與函式名稱，不再包含 URL 路徑與 HTTP 操作的資訊。\n\n### 為用戶端產生器預處理 OpenAPI 規格 { #preprocess-the-openapi-specification-for-the-client-generator }\n\n產生的程式碼仍有一些**重複資訊**。\n\n我們已經知道這個方法與 **items** 相關，因為該字已出現在 `ItemsService`（取自標籤）中，但方法名稱仍然加上了標籤名稱做前綴。😕\n\n對於 OpenAPI 本身，我們可能仍想保留，因為那能確保操作 ID 是**唯一**的。\n\n但就產生用戶端而言，我們可以在產生前**修改** OpenAPI 的操作 ID，來讓方法名稱更**簡潔**、更**乾淨**。\n\n我們可以把 OpenAPI JSON 下載到 `openapi.json` 檔案，然後用像這樣的腳本**移除該標籤前綴**：\n\n{* ../../docs_src/generate_clients/tutorial004_py310.py *}\n\n//// tab | Node.js\n\n```Javascript\n{!> ../../docs_src/generate_clients/tutorial004.js!}\n```\n\n////\n\n如此一來，操作 ID 會從 `items-get_items` 之類的字串，變成單純的 `get_items`，讓用戶端產生器能產生更簡潔的方法名稱。\n\n### 使用預處理後的 OpenAPI 產生 TypeScript 用戶端 { #generate-a-typescript-client-with-the-preprocessed-openapi }\n\n由於最終結果現在是在 `openapi.json` 檔案中，你需要更新輸入位置：\n\n```sh\nnpx @hey-api/openapi-ts -i ./openapi.json -o src/client\n```\n\n產生新的用戶端後，你現在會得到**乾淨的方法名稱**，同時保有所有的**自動完成**、**行內錯誤**等功能：\n\n<img src=\"/img/tutorial/generate-clients/image08.png\">\n\n## 好處 { #benefits }\n\n使用自動產生的用戶端時，你會得到以下項目的**自動完成**：\n\n* 方法\n* 本文中的請求有效載荷、查詢參數等\n* 回應的有效載荷\n\n你也會對所有內容獲得**行內錯誤**提示。\n\n而且每當你更新後端程式碼並**重新產生**前端（用戶端），新的 *路徑操作* 會以方法形式可用、舊的會被移除，其他任何變更也都會反映到產生的程式碼中。🤓\n\n這也代表只要有任何變更，便會自動**反映**到用戶端程式碼；而當你**建置**用戶端時，如果使用的資料有任何**不匹配**，就會直接報錯。\n\n因此，你能在開發週期的很早期就**偵測到許多錯誤**，而不必等到錯誤在正式環境的最終使用者那裡才出現，然後才開始追查問題所在。✨\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/index.md",
    "content": "# 進階使用者指南 { #advanced-user-guide }\n\n## 更多功能 { #additional-features }\n\n主要的[教學 - 使用者指南](../tutorial/index.md) 應足以帶你快速瀏覽 **FastAPI** 的所有核心功能。\n\n在接下來的章節中，你會看到其他選項、設定，以及更多功能。\n\n/// tip\n\n接下來的章節**不一定是「進階」**。\n\n而且對於你的使用情境，解法很可能就在其中某一節。\n\n///\n\n## 先閱讀教學 { #read-the-tutorial-first }\n\n只要掌握主要[教學 - 使用者指南](../tutorial/index.md) 的內容，你就能使用 **FastAPI** 的大多數功能。\n\n接下來的章節也假設你已經讀過，並已了解那些主要觀念。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/json-base64-bytes.md",
    "content": "# 使用 Base64 表示位元組的 JSON { #json-with-bytes-as-base64 }\n\n如果你的應用需要收發 JSON 資料，但其中需要包含二進位資料，你可以將它以 base64 編碼。\n\n## Base64 與檔案 { #base64-vs-files }\n\n請先考慮是否能用 [請求檔案](../tutorial/request-files.md) 來上傳二進位資料，並用 [自訂回應 - FileResponse](./custom-response.md#fileresponse--fileresponse-) 來傳送二進位資料，而不是把它們編碼進 JSON。\n\nJSON 只能包含 UTF-8 編碼的字串，因此無法直接包含原始位元組。\n\nBase64 可以把二進位資料編碼成字串，但為此會使用比原始二進位資料更多的字元，因此通常比直接使用檔案來得沒那麼有效率。\n\n只有在確實必須把二進位資料包含在 JSON 裡，且無法改用檔案時，才使用 base64。\n\n## Pydantic `bytes` { #pydantic-bytes }\n\n你可以宣告含有 `bytes` 欄位的 Pydantic 模型，並在模型設定中使用 `val_json_bytes`，使其在驗證輸入的 JSON 資料時使用 base64；在驗證過程中，它會將 base64 字串解碼為位元組。\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:9,29:35] hl[9] *}\n\n如果你查看 `/docs`，會看到欄位 `data` 需要 base64 編碼的位元組：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/json-base64-bytes/image01.png\">\n</div>\n\n你可以發送如下的請求：\n\n```json\n{\n    \"description\": \"Some data\",\n    \"data\": \"aGVsbG8=\"\n}\n```\n\n/// tip\n\n`aGVsbG8=` 是 `hello` 的 base64 編碼。\n\n///\n\n接著 Pydantic 會將該 base64 字串解碼，並在模型的 `data` 欄位中提供原始位元組。\n\n你會收到類似以下的回應：\n\n```json\n{\n  \"description\": \"Some data\",\n  \"content\": \"hello\"\n}\n```\n\n## Pydantic `bytes` 用於輸出資料 { #pydantic-bytes-for-output-data }\n\n你也可以在模型設定中搭配 `ser_json_bytes` 使用 `bytes` 欄位來處理輸出資料；當產生 JSON 回應時，Pydantic 會將位元組以 base64 進行序列化。\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,12:16,29,38:41] hl[16] *}\n\n## Pydantic `bytes` 用於輸入與輸出資料 { #pydantic-bytes-for-input-and-output-data }\n\n當然，你也可以使用同一個以 base64 設定的模型，同時處理輸入（以 `val_json_bytes` 驗證）與輸出（以 `ser_json_bytes` 序列化）的 JSON 資料。\n\n{* ../../docs_src/json_base64_bytes/tutorial001_py310.py ln[1:2,19:26,29,44:46] hl[23:26] *}\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/middleware.md",
    "content": "# 進階中介軟體 { #advanced-middleware }\n\n在主要教學中你已學過如何將[自訂中介軟體](../tutorial/middleware.md)加入到你的應用程式。\n\n你也讀過如何處理 [使用 `CORSMiddleware` 的 CORS](../tutorial/cors.md)。\n\n本節將示範如何使用其他中介軟體。\n\n## 新增 ASGI 中介軟體 { #adding-asgi-middlewares }\n\n由於 **FastAPI** 建立在 Starlette 上並實作了 <abbr title=\"Asynchronous Server Gateway Interface - 非同步伺服器閘道介面\">ASGI</abbr> 規範，你可以使用任何 ASGI 中介軟體。\n\n中介軟體不一定要為 FastAPI 或 Starlette 專門撰寫，只要遵循 ASGI 規範即可運作。\n\n一般來說，ASGI 中介軟體是類別，預期第一個參數接收一個 ASGI 應用程式。\n\n因此，在第三方 ASGI 中介軟體的文件中，通常會指示你這樣做：\n\n```Python\nfrom unicorn import UnicornMiddleware\n\napp = SomeASGIApp()\n\nnew_app = UnicornMiddleware(app, some_config=\"rainbow\")\n```\n\n但 FastAPI（實際上是 Starlette）提供了一種更簡單的方式，確保內部中介軟體能處理伺服器錯誤，且自訂例外處理器可正常運作。\n\n為此，你可以使用 `app.add_middleware()`（如同 CORS 範例）。\n\n```Python\nfrom fastapi import FastAPI\nfrom unicorn import UnicornMiddleware\n\napp = FastAPI()\n\napp.add_middleware(UnicornMiddleware, some_config=\"rainbow\")\n```\n\n`app.add_middleware()` 將中介軟體類別作為第一個引數，並接收要傳遞給該中介軟體的其他引數。\n\n## 內建中介軟體 { #integrated-middlewares }\n\n**FastAPI** 內建數個常見用途的中介軟體，以下將示範如何使用。\n\n/// note | 技術細節\n\n在接下來的範例中，你也可以使用 `from starlette.middleware.something import SomethingMiddleware`。\n\n**FastAPI** 在 `fastapi.middleware` 中提供了一些中介軟體，純粹是為了方便你這位開發者。但大多數可用的中介軟體直接來自 Starlette。\n\n///\n\n## `HTTPSRedirectMiddleware` { #httpsredirectmiddleware }\n\n強制所有傳入請求必須使用 `https` 或 `wss`。\n\n任何指向 `http` 或 `ws` 的請求都會被重新導向至對應的安全協定。\n\n{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *}\n\n## `TrustedHostMiddleware` { #trustedhostmiddleware }\n\n強制所有傳入請求正確設定 `Host` 標頭，以防範 HTTP Host Header 攻擊。\n\n{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *}\n\n支援以下參數：\n\n- `allowed_hosts` - 允許作為主機名稱的網域名稱清單。支援萬用字元網域（例如 `*.example.com`）以比對子網域。若要允許任意主機名稱，可使用 `allowed_hosts=[\"*\"]`，或乾脆不要加上此中介軟體。\n- `www_redirect` - 若設為 True，對允許主機的不含 www 版本的請求會被重新導向至其 www 對應版本。預設為 `True`。\n\n若傳入請求驗證失敗，將回傳 `400` 回應。\n\n## `GZipMiddleware` { #gzipmiddleware }\n\n處理在 `Accept-Encoding` 標頭中包含 `\"gzip\"` 的請求之 GZip 壓縮回應。\n\n此中介軟體會處理一般與串流回應。\n\n{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *}\n\n支援以下參數：\n\n- `minimum_size` - 小於此位元組大小的回應不會進行 GZip。預設為 `500`。\n- `compresslevel` - GZip 壓縮時使用的等級。為 1 到 9 的整數。預設為 `9`。值越小壓縮越快但檔案較大，值越大壓縮較慢但檔案較小。\n\n## 其他中介軟體 { #other-middlewares }\n\n還有許多其他 ASGI 中介軟體。\n\n例如：\n\n- [Uvicorn 的 `ProxyHeadersMiddleware`](https://github.com/encode/uvicorn/blob/master/uvicorn/middleware/proxy_headers.py)\n- [MessagePack](https://github.com/florimondmanca/msgpack-asgi)\n\n想瞭解更多可用的中介軟體，請參考 [Starlette 的中介軟體文件](https://www.starlette.dev/middleware/) 與 [ASGI 精選清單](https://github.com/florimondmanca/awesome-asgi)。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/openapi-callbacks.md",
    "content": "# OpenAPI 回呼 { #openapi-callbacks }\n\n你可以建立一個含有「路徑操作（path operation）」的 API，該操作會觸發對某個「外部 API（external API）」的請求（通常由使用你 API 的同一位開發者提供）。\n\n當你的 API 應用呼叫「外部 API」時發生的過程稱為「回呼（callback）」。因為外部開發者撰寫的軟體會先向你的 API 發出請求，接著你的 API 再「回呼」，也就是向（可能同一位開發者建立的）外部 API 發送請求。\n\n在這種情況下，你可能想要文件化說明該外部 API 應該長什麼樣子。它應該有哪些「路徑操作」、應該接受什麼 body、應該回傳什麼 response，等等。\n\n## 帶有回呼的應用 { #an-app-with-callbacks }\n\n我們用一個例子來看。\n\n想像你開發了一個允許建立發票的應用。\n\n這些發票會有 `id`、`title`（可選）、`customer` 和 `total`。\n\n你的 API 的使用者（外部開發者）會透過一個 POST 請求在你的 API 中建立一張發票。\n\n然後你的 API 會（讓我們想像）：\n\n* 將發票寄給該外部開發者的某位客戶。\n* 代收款項。\n* 再把通知回傳給 API 使用者（外部開發者）。\n    * 這會透過從「你的 API」向該外部開發者提供的「外部 API」送出 POST 請求完成（這就是「回呼」）。\n\n## 一般的 **FastAPI** 應用 { #the-normal-fastapi-app }\n\n先看看在加入回呼之前，一個一般的 API 應用會長什麼樣子。\n\n它會有一個接收 `Invoice` body 的「路徑操作」，以及一個查詢參數 `callback_url`，其中包含用於回呼的 URL。\n\n這部分很正常，多數程式碼你應該已經很熟悉了：\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[7:11,34:51] *}\n\n/// tip\n\n`callback_url` 查詢參數使用的是 Pydantic 的 [Url](https://docs.pydantic.dev/latest/api/networks/) 型別。\n\n///\n\n唯一新的地方是在「路徑操作裝飾器」中加入參數 `callbacks=invoices_callback_router.routes`。我們接下來會看到那是什麼。\n\n## 文件化回呼 { #documenting-the-callback }\n\n實際的回呼程式碼會高度依賴你的 API 應用本身。\n\n而且很可能每個應用都差很多。\n\n它可能就只有一兩行，例如：\n\n```Python\ncallback_url = \"https://example.com/api/v1/invoices/events/\"\nhttpx.post(callback_url, json={\"description\": \"Invoice paid\", \"paid\": True})\n```\n\n但回呼中最重要的部分，可能是在確保你的 API 使用者（外部開發者）能正確實作「外部 API」，符合「你的 API」在回呼請求 body 中要送出的資料格式，等等。\n\n因此，接下來我們要加上用來「文件化」說明，該「外部 API」應該長什麼樣子，才能接收來自「你的 API」的回呼。\n\n這份文件會出現在你的 API 的 Swagger UI `/docs`，讓外部開發者知道該如何建置「外部 API」。\n\n這個範例不會實作回呼本身（那可能就只是一行程式碼），只會實作文件的部分。\n\n/// tip\n\n實際的回呼就是一個 HTTP 請求。\n\n當你自己實作回呼時，可以使用像是 [HTTPX](https://www.python-httpx.org) 或 [Requests](https://requests.readthedocs.io/)。\n\n///\n\n## 撰寫回呼的文件化程式碼 { #write-the-callback-documentation-code }\n\n這段程式碼在你的應用中不會被執行，我們只需要它來「文件化」說明那個「外部 API」應該長什麼樣子。\n\n不過，你已經知道如何用 **FastAPI** 輕鬆為 API 建立自動文件。\n\n所以我們會用同樣的方式，來文件化「外部 API」應該長什麼樣子... 也就是建立外部 API 應該實作的「路徑操作（們）」（那些「你的 API」會去呼叫的操作）。\n\n/// tip\n\n在撰寫回呼的文件化程式碼時，把自己想像成那位「外部開發者」會很有幫助。而且你現在是在實作「外部 API」，不是「你的 API」。\n\n暫時採用這個（外部開發者）的視角，有助於讓你更直覺地決定該把參數、body 的 Pydantic 模型、response 的模型等放在哪裡，對於那個「外部 API」會更清楚。\n\n///\n\n### 建立一個回呼用的 `APIRouter` { #create-a-callback-apirouter }\n\n先建立一個新的 `APIRouter`，用來放一個或多個回呼。\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[1,23] *}\n\n### 建立回呼的「路徑操作」 { #create-the-callback-path-operation }\n\n要建立回呼的「路徑操作」，就使用你上面建立的同一個 `APIRouter`。\n\n它看起來就像一般的 FastAPI「路徑操作」：\n\n* 可能需要宣告它應該接收的 body，例如 `body: InvoiceEvent`。\n* 也可以宣告它應該回傳的 response，例如 `response_model=InvoiceEventReceived`。\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[14:16,19:20,26:30] *}\n\n和一般「路徑操作」相比有兩個主要差異：\n\n* 不需要任何實際程式碼，因為你的應用永遠不會呼叫這段程式。它只用來文件化「外部 API」。因此函式可以只有 `pass`。\n* 「路徑」可以包含一個 [OpenAPI 3 表達式](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression)（見下文），可使用參數與原始送到「你的 API」的請求中的部分欄位。\n\n### 回呼路徑表達式 { #the-callback-path-expression }\n\n回呼的「路徑」可以包含一個 [OpenAPI 3 表達式](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression)，能引用原本送到「你的 API」的請求中的部分內容。\n\n在這個例子中，它是一個 `str`：\n\n```Python\n\"{$callback_url}/invoices/{$request.body.id}\"\n```\n\n所以，如果你的 API 使用者（外部開發者）向「你的 API」送出這樣的請求：\n\n```\nhttps://yourapi.com/invoices/?callback_url=https://www.external.org/events\n```\n\n並附上這個 JSON body：\n\n```JSON\n{\n    \"id\": \"2expen51ve\",\n    \"customer\": \"Mr. Richie Rich\",\n    \"total\": \"9999\"\n}\n```\n\n那麼「你的 API」會處理這張發票，並在稍後某個時點，向 `callback_url`（也就是「外部 API」）送出回呼請求：\n\n```\nhttps://www.external.org/events/invoices/2expen51ve\n```\n\n其 JSON body 大致包含：\n\n```JSON\n{\n    \"description\": \"Payment celebration\",\n    \"paid\": true\n}\n```\n\n而它會預期該「外部 API」回傳的 JSON body 例如：\n\n```JSON\n{\n    \"ok\": true\n}\n```\n\n/// tip\n\n注意回呼所用的 URL，包含了在查詢參數 `callback_url` 中收到的 URL（`https://www.external.org/events`），以及來自 JSON body 內的發票 `id`（`2expen51ve`）。\n\n///\n\n### 加入回呼 router { #add-the-callback-router }\n\n此時你已經在先前建立的回呼 router 中，擁有所需的回呼「路徑操作（們）」（也就是「外部開發者」應該在「外部 API」中實作的那些）。\n\n現在在「你的 API 的路徑操作裝飾器」中使用參數 `callbacks`，將該回呼 router 的屬性 `.routes`（實際上就是一個由路由／「路徑操作」所組成的 `list`）傳入：\n\n{* ../../docs_src/openapi_callbacks/tutorial001_py310.py hl[33] *}\n\n/// tip\n\n注意你傳給 `callback=` 的不是整個 router 本身（`invoices_callback_router`），而是它的屬性 `.routes`，也就是 `invoices_callback_router.routes`。\n\n///\n\n### 檢查文件 { #check-the-docs }\n\n現在你可以啟動應用，並前往 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n你會在文件中看到你的「路徑操作」包含一個「Callbacks」區塊，顯示「外部 API」應該長什麼樣子：\n\n<img src=\"/img/tutorial/openapi-callbacks/image01.png\">\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/openapi-webhooks.md",
    "content": "# OpenAPI Webhook { #openapi-webhooks }\n\n有些情況下，你會想告訴你的 API 使用者，你的應用程式可能會攜帶一些資料去呼叫他們的應用程式（發送請求），通常是為了通知某種類型的事件。\n\n這表示，與其由使用者向你的 API 發送請求，改為你的 API（或你的應用）可能會向他們的系統（他們的 API、他們的應用）發送請求。\n\n這通常稱為 webhook。\n\n## Webhook 步驟 { #webhooks-steps }\n\n流程通常是：你在程式碼中定義要發送的訊息，也就是請求的主體（request body）。\n\n你也會以某種方式定義應用在哪些時刻會發送那些請求或事件。\n\n而你的使用者則會以某種方式（例如在某個 Web 控制台）設定你的應用應該將這些請求送往的 URL。\n\n關於如何註冊 webhook 的 URL，以及實際發送那些請求的程式碼等所有邏輯，都由你決定。你可以在自己的程式碼中用你想要的方式撰寫。\n\n## 使用 FastAPI 與 OpenAPI 記錄 webhook { #documenting-webhooks-with-fastapi-and-openapi }\n\n在 FastAPI 中，透過 OpenAPI，你可以定義這些 webhook 的名稱、你的應用將發送的 HTTP 操作類型（例如 `POST`、`PUT` 等），以及你的應用要發送的請求主體。\n\n這能讓你的使用者更容易實作他們的 API 以接收你的 webhook 請求，甚至可能自動產生部分他們自己的 API 程式碼。\n\n/// info\n\nWebhook 功能自 OpenAPI 3.1.0 起提供，FastAPI `0.99.0` 以上版本支援。\n\n///\n\n## 含有 webhook 的應用 { #an-app-with-webhooks }\n\n建立 FastAPI 應用時，會有一個 `webhooks` 屬性可用來定義 webhook，方式與定義路徑操作相同，例如使用 `@app.webhooks.post()`。\n\n{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:12,15:20] *}\n\n你定義的 webhook 會出現在 OpenAPI 結構描述與自動產生的文件 UI 中。\n\n/// info\n\n`app.webhooks` 其實就是一個 `APIRouter`，與你在將應用拆分為多個檔案時所使用的型別相同。\n\n///\n\n注意，使用 webhook 時你其實不是在宣告路徑（例如 `/items/`），你傳入的文字只是該 webhook 的識別名稱（事件名稱）。例如在 `@app.webhooks.post(\"new-subscription\")` 中，webhook 名稱是 `new-subscription`。\n\n這是因為預期由你的使用者以其他方式（例如 Web 控制台）來設定實際要接收 webhook 請求的 URL 路徑。\n\n### 查看文件 { #check-the-docs }\n\n現在你可以啟動應用，然後前往 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n你會在文件中看到一般的路徑操作，另外還有一些 webhook：\n\n<img src=\"/img/tutorial/openapi-webhooks/image01.png\">\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/path-operation-advanced-configuration.md",
    "content": "# 路徑操作進階設定 { #path-operation-advanced-configuration }\n\n## OpenAPI operationId { #openapi-operationid }\n\n/// warning\n\n如果你不是 OpenAPI 的「專家」，大概不需要這個。\n\n///\n\n你可以用參數 `operation_id` 為你的*路徑操作（path operation）*設定要使用的 OpenAPI `operationId`。\n\n你必須確保每個操作的 `operationId` 都是唯一的。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *}\n\n### 使用路徑操作函式（path operation function）的名稱作為 operationId { #using-the-path-operation-function-name-as-the-operationid }\n\n如果你想用 API 的函式名稱作為 `operationId`，你可以遍歷所有路徑，並使用各自的 `APIRoute.name` 覆寫每個*路徑操作*的 `operation_id`。\n\n應在加入所有*路徑操作*之後再這麼做。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *}\n\n/// tip\n\n如果你會手動呼叫 `app.openapi()`，請務必先更新所有 `operationId` 再呼叫。\n\n///\n\n/// warning\n\n如果你這樣做，必須確保每個*路徑操作函式*都有唯一的名稱，\n\n即使它們位於不同的模組（Python 檔案）中。\n\n///\n\n## 從 OpenAPI 排除 { #exclude-from-openapi }\n\n若要從產生的 OpenAPI 結構（也就是自動文件系統）中排除某個*路徑操作*，使用參數 `include_in_schema` 並將其設為 `False`：\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *}\n\n## 從 docstring 提供進階描述 { #advanced-description-from-docstring }\n\n你可以限制 OpenAPI 從*路徑操作函式*的 docstring 中使用的內容行數。\n\n加上一個 `\\f`（跳頁字元，form feed）會讓 FastAPI 在此處截斷用於 OpenAPI 的輸出。\n\n這個字元不會出現在文件中，但其他工具（例如 Sphinx）仍可使用其後的內容。\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial004_py310.py hl[17:27] *}\n\n## 額外回應 { #additional-responses }\n\n你大概已看過如何為*路徑操作*宣告 `response_model` 與 `status_code`。\n\n這會定義該*路徑操作*主要回應的中繼資料。\n\n你也可以宣告額外的回應及其模型、狀態碼等。\n\n文件中有完整章節說明，請見 [OpenAPI 中的額外回應](additional-responses.md)。\n\n## OpenAPI 額外資訊 { #openapi-extra }\n\n當你在應用程式中宣告一個*路徑操作*時，FastAPI 會自動產生該*路徑操作*的相關中繼資料，並納入 OpenAPI 結構中。\n\n/// note | 技術細節\n\n在 OpenAPI 規格中，這稱為 [Operation 物件](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object)。\n\n///\n\n它包含關於*路徑操作*的所有資訊，並用於產生自動文件。\n\n其中包含 `tags`、`parameters`、`requestBody`、`responses` 等。\n\n這個針對單一路徑操作的 OpenAPI 結構通常由 FastAPI 自動產生，但你也可以擴充它。\n\n/// tip\n\n這是一個較低階的擴充介面。\n\n如果你只需要宣告額外回應，更方便的方式是使用 [OpenAPI 中的額外回應](additional-responses.md)。\n\n///\n\n你可以使用參數 `openapi_extra` 來擴充某個*路徑操作*的 OpenAPI 結構。\n\n### OpenAPI 擴充 { #openapi-extensions }\n\n`openapi_extra` 可用來宣告例如 [OpenAPI 擴充](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions) 的資料：\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *}\n\n打開自動產生的 API 文件時，你的擴充會顯示在該*路徑操作*頁面的底部。\n\n<img src=\"/img/tutorial/path-operation-advanced-configuration/image01.png\">\n\n而在檢視產生出的 OpenAPI（位於你的 API 的 `/openapi.json`）時，也可以在相應*路徑操作*中看到你的擴充：\n\n```JSON hl_lines=\"22\"\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"summary\": \"Read Items\",\n                \"operationId\": \"read_items_items__get\",\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n                                \"schema\": {}\n                            }\n                        }\n                    }\n                },\n                \"x-aperture-labs-portal\": \"blue\"\n            }\n        }\n    }\n}\n```\n\n### 自訂 OpenAPI 路徑操作結構 { #custom-openapi-path-operation-schema }\n\n`openapi_extra` 中的字典會與自動產生的該*路徑操作*之 OpenAPI 結構進行深度合併。\n\n因此你可以在自動產生的結構上加入額外資料。\n\n例如，你可以選擇用自己的程式碼讀取並驗證請求，而不使用 FastAPI 與 Pydantic 的自動功能，但仍然希望在 OpenAPI 結構中定義該請求。\n\n你可以透過 `openapi_extra` 辦到：\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *}\n\n在這個範例中，我們沒有宣告任何 Pydantic 模型。事實上，請求本文甚至不會被 <dfn title=\"從某種純格式（例如 bytes）轉換為 Python 物件\">解析</dfn> 為 JSON，而是直接以 `bytes` 讀取，並由函式 `magic_data_reader()` 以某種方式負責解析。\n\n儘管如此，我們仍可宣告請求本文的預期結構。\n\n### 自訂 OpenAPI Content-Type { #custom-openapi-content-type }\n\n用同樣的方法，你可以使用 Pydantic 模型來定義 JSON Schema，並把它包含到該*路徑操作*的自訂 OpenAPI 區段中。\n\n即使請求中的資料型別不是 JSON 也可以這麼做。\n\n例如，在這個應用中，我們不使用 FastAPI 內建的從 Pydantic 模型擷取 JSON Schema 的功能，也不使用 JSON 的自動驗證。實際上，我們將請求的 content type 宣告為 YAML，而非 JSON：\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *}\n\n儘管沒有使用預設的內建功能，我們仍透過 Pydantic 模型手動產生想以 YAML 接收之資料的 JSON Schema。\n\n接著我們直接使用請求，並將本文擷取為 `bytes`。這表示 FastAPI 甚至不會嘗試把請求負載解析為 JSON。\n\n然後在程式中直接解析該 YAML 內容，並再次使用相同的 Pydantic 模型來驗證該 YAML 內容：\n\n{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *}\n\n/// tip\n\n這裡我們重複使用同一個 Pydantic 模型。\n\n不過也可以用其他方式進行驗證。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/response-change-status-code.md",
    "content": "# 回應 - 變更狀態碼 { #response-change-status-code }\n\n你可能已經讀過，可以設定預設的[回應狀態碼](../tutorial/response-status-code.md)。\n\n但有些情況你需要回傳與預設不同的狀態碼。\n\n## 使用情境 { #use-case }\n\n例如，假設你預設想回傳 HTTP 狀態碼 \"OK\" `200`。\n\n但如果資料不存在，你想要建立它，並回傳 HTTP 狀態碼 \"CREATED\" `201`。\n\n同時你仍希望能用 `response_model` 過濾並轉換所回傳的資料。\n\n在這些情況下，你可以使用 `Response` 參數。\n\n## 使用 `Response` 參數 { #use-a-response-parameter }\n\n你可以在你的路徑操作函式（path operation function）中宣告一個 `Response` 型別的參數（就像你可以對 Cookies 和標頭那樣）。\n\n接著你可以在那個「*暫時的*」回應物件上設定 `status_code`。\n\n{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *}\n\n然後你可以照常回傳任何需要的物件（例如 `dict`、資料庫模型等）。\n\n若你宣告了 `response_model`，它仍會被用來過濾並轉換你回傳的物件。\n\n**FastAPI** 會使用那個「*暫時的*」回應來取得狀態碼（以及 Cookies 和標頭），並將它們放入最終回應中；最終回應包含你回傳的值，且會被任何 `response_model` 過濾。\n\n你也可以在相依性（dependencies）中宣告 `Response` 參數，並在其中設定狀態碼。但請注意，最後被設定的值會生效。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/response-cookies.md",
    "content": "# 回應 Cookie { #response-cookies }\n\n## 使用 `Response` 參數 { #use-a-response-parameter }\n\n你可以在路徑操作函式（path operation function）中宣告一個型別為 `Response` 的參數。\n\n接著你可以在那個「暫時」的 `Response` 物件上設定 Cookie。\n\n{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *}\n\n之後如常回傳你需要的任何物件（例如 `dict`、資料庫模型等）。\n\n如果你宣告了 `response_model`，它仍會用來過濾並轉換你回傳的物件。\n\nFastAPI 會使用那個暫時的 `Response` 取出 Cookie（以及標頭與狀態碼），並將它們放入最終回應；最終回應包含你回傳的值，且會套用任何 `response_model` 的過濾。\n\n你也可以在相依項（dependencies）中宣告 `Response` 參數，並在其中設定 Cookie（與標頭）。\n\n## 直接回傳 `Response` { #return-a-response-directly }\n\n當你在程式碼中直接回傳 `Response` 時，也可以建立 Cookie。\n\n要這麼做，你可以依照 [直接回傳 Response](response-directly.md) 中的說明建立一個回應。\n\n接著在其中設定 Cookie，然後回傳它：\n\n{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *}\n\n/// tip | 提示\n\n請注意，如果你不是使用 `Response` 參數，而是直接回傳一個 `Response`，FastAPI 會原樣回傳它。\n\n因此你必須確保資料型別正確；例如，如果你回傳的是 `JSONResponse`，就要確保資料可與 JSON 相容。\n\n同時也要確認沒有送出原本應該由 `response_model` 過濾的資料。\n\n///\n\n### 更多資訊 { #more-info }\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.responses import Response` 或 `from starlette.responses import JSONResponse`。\n\n為了方便開發者，FastAPI 也將相同的 `starlette.responses` 透過 `fastapi.responses` 提供。不過，大多數可用的回應類別都直接來自 Starlette。\n\n另外由於 `Response` 常用於設定標頭與 Cookie，FastAPI 也在 `fastapi.Response` 提供了它。\n\n///\n\n想查看所有可用的參數與選項，請參閱 [Starlette 文件](https://www.starlette.dev/responses/#set-cookie)。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/response-directly.md",
    "content": "# 直接回傳 Response { #return-a-response-directly }\n\n當你建立一個 **FastAPI** 的路徑操作 (path operation) 時，通常可以從中回傳任何資料：`dict`、`list`、Pydantic 模型、資料庫模型等。\n\n如果你宣告了 [回應模型](../tutorial/response-model.md)，FastAPI 會用 Pydantic 將資料序列化為 JSON。\n\n如果你沒有宣告回應模型，FastAPI 會使用在[JSON 相容編碼器](../tutorial/encoder.md)中說明的 `jsonable_encoder`，並把它放進 `JSONResponse`。\n\n但你也可以直接從路徑操作回傳 `JSONResponse`。\n\n/// tip\n\n通常使用 [回應模型](../tutorial/response-model.md) 會有更好的效能，因為那樣會在 Rust 端使用 Pydantic 來序列化資料，而不是直接回傳 `JSONResponse`。\n\n///\n\n## 回傳 `Response` { #return-a-response }\n\n其實，你可以回傳任何 `Response`，或其任何子類別。\n\n/// info\n\n`JSONResponse` 本身就是 `Response` 的子類別。\n\n///\n\n當你回傳一個 `Response` 時，**FastAPI** 會直接傳遞它。\n\n它不會對 Pydantic 模型做任何資料轉換，也不會把內容轉成其他型別等。\n\n這給了你很大的彈性。你可以回傳任何資料型別、覆寫任何資料宣告或驗證等。\n\n同時也帶來了很大的責任。你必須確保你回傳的資料是正確的、格式正確、可被序列化等。\n\n## 在 `Response` 中使用 `jsonable_encoder` { #using-the-jsonable-encoder-in-a-response }\n\n因為 **FastAPI** 不會對你回傳的 `Response` 做任何更動，你需要自行確保它的內容已經準備好。\n\n例如，你不能直接把一個 Pydantic 模型放進 `JSONResponse`，需要先把它轉成 `dict`，並將所有資料型別（像是 `datetime`、`UUID` 等）轉成與 JSON 相容的型別。\n\n在這些情況下，你可以先用 `jsonable_encoder` 把資料轉好，再傳給回應物件：\n\n{* ../../docs_src/response_directly/tutorial001_py310.py hl[5:6,20:21] *}\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.responses import JSONResponse`。\n\n**FastAPI** 為了方便開發者，將 `starlette.responses` 也提供為 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。\n\n///\n\n## 回傳自訂 `Response` { #returning-a-custom-response }\n\n上面的範例展示了所需的各個部分，但目前還不太實用，因為你其實可以直接回傳 `item`，**FastAPI** 就會幫你把它放進 `JSONResponse`，轉成 `dict` 等，這些都是預設行為。\n\n現在來看看如何用它來回傳自訂回應。\n\n假設你想要回傳一個 [XML](https://en.wikipedia.org/wiki/XML) 回應。\n\n你可以把 XML 內容放進一個字串，把它放進 `Response`，然後回傳它：\n\n{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *}\n\n## 回應模型如何運作 { #how-a-response-model-works }\n\n當你在路徑操作中宣告 [回應模型 - 回傳型別](../tutorial/response-model.md) 時，**FastAPI** 會用 Pydantic 將資料序列化為 JSON。\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\n由於這會在 Rust 端發生，效能會比用一般的 Python 與 `JSONResponse` 類別來完成好得多。\n\n當使用 `response_model` 或回傳型別時，FastAPI 不會使用 `jsonable_encoder` 來轉換資料（那會較慢），也不會使用 `JSONResponse` 類別。\n\n相反地，它會取用用回應模型（或回傳型別）透過 Pydantic 產生的 JSON 位元組，並直接回傳具備正確 JSON 媒體型別（`application/json`）的 `Response`。\n\n## 注意事項 { #notes }\n\n當你直接回傳 `Response` 時，其資料不會自動被驗證、轉換（序列化）或文件化。\n\n但你仍然可以依照[在 OpenAPI 中的額外回應](additional-responses.md)中的說明進行文件化。\n\n在後續章節中，你會看到如何在仍保有自動資料轉換、文件化等的同時，使用／宣告這些自訂的 `Response`。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/response-headers.md",
    "content": "# 回應標頭 { #response-headers }\n\n## 使用 `Response` 參數 { #use-a-response-parameter }\n\n你可以在你的*路徑操作函式（path operation function）*中宣告一個 `Response` 型別的參數（就像處理 Cookie 一樣）。\n\n然後你可以在那個*暫時性的* `Response` 物件上設定標頭。\n\n{* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *}\n\n接著你可以像平常一樣回傳任何你需要的物件（`dict`、資料庫模型等）。\n\n如果你宣告了 `response_model`，它仍會用來過濾並轉換你回傳的物件。\n\nFastAPI 會使用那個暫時性的回應來擷取標頭（還有 Cookie 與狀態碼），並把它們放到最終回應中；最終回應包含你回傳的值，且會依任何 `response_model` 進行過濾。\n\n你也可以在依賴中宣告 `Response` 參數，並在其中設定標頭（與 Cookie）。\n\n## 直接回傳 `Response` { #return-a-response-directly }\n\n當你直接回傳 `Response` 時，也能加入標頭。\n\n依照[直接回傳 Response](response-directly.md)中的說明建立回應，並把標頭作為額外參數傳入：\n\n{* ../../docs_src/response_headers/tutorial001_py310.py hl[10:12] *}\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.responses import Response` 或 `from starlette.responses import JSONResponse`。\n\n為了方便開發者，FastAPI 提供與 `starlette.responses` 相同的內容於 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。\n\n由於 `Response` 常用來設定標頭與 Cookie，FastAPI 也在 `fastapi.Response` 提供了它。\n\n///\n\n## 自訂標頭 { #custom-headers }\n\n請記住，專有的自訂標頭可以[使用 `X-` 前綴](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)來新增。\n\n但如果你有自訂標頭並希望瀏覽器端的客戶端能看見它們，你需要把這些標頭加入到 CORS 設定中（詳見 [CORS（跨來源資源共用）](../tutorial/cors.md)），使用在[Starlette 的 CORS 文件](https://www.starlette.dev/middleware/#corsmiddleware)中記載的 `expose_headers` 參數。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/security/http-basic-auth.md",
    "content": "# HTTP 基本認證 { #http-basic-auth }\n\n在最簡單的情況下，你可以使用 HTTP Basic 認證。\n\n在 HTTP Basic 認證中，應用程式會期待一個包含使用者名稱與密碼的標頭。\n\n如果沒有接收到，會回傳 HTTP 401「Unauthorized」錯誤。\n\n並回傳一個 `WWW-Authenticate` 標頭，其值為 `Basic`，以及可選的 `realm` 參數。\n\n這會告訴瀏覽器顯示內建的使用者名稱與密碼提示視窗。\n\n接著，當你輸入該使用者名稱與密碼時，瀏覽器會自動在標頭中送出它們。\n\n## 簡單的 HTTP 基本認證 { #simple-http-basic-auth }\n\n- 匯入 `HTTPBasic` 與 `HTTPBasicCredentials`。\n- 使用 `HTTPBasic` 建立一個「`security` scheme」。\n- 在你的*路徑操作*中以依賴的方式使用該 `security`。\n- 它會回傳一個 `HTTPBasicCredentials` 型別的物件：\n    - 其中包含傳來的 `username` 與 `password`。\n\n{* ../../docs_src/security/tutorial006_an_py310.py hl[4,8,12] *}\n\n當你第一次嘗試開啟該 URL（或在文件中點擊 \"Execute\" 按鈕）時，瀏覽器會要求輸入你的使用者名稱與密碼：\n\n<img src=\"/img/tutorial/security/image12.png\">\n\n## 檢查使用者名稱 { #check-the-username }\n\n以下是一個更完整的範例。\n\n使用一個依賴來檢查使用者名稱與密碼是否正確。\n\n為此，使用 Python 標準模組 [`secrets`](https://docs.python.org/3/library/secrets.html) 來比對使用者名稱與密碼。\n\n`secrets.compare_digest()` 需要接收 `bytes`，或是只包含 ASCII 字元（英文字符）的 `str`。這表示它無法處理像 `á` 這樣的字元，例如 `Sebastián`。\n\n為了處理這點，我們會先將 `username` 與 `password` 以 UTF-8 編碼成 `bytes`。\n\n接著我們可以使用 `secrets.compare_digest()` 來確認 `credentials.username` 等於 `\"stanleyjobson\"`，而 `credentials.password` 等於 `\"swordfish\"`。\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[1,12:24] *}\n\n這大致等同於：\n\n```Python\nif not (credentials.username == \"stanleyjobson\") or not (credentials.password == \"swordfish\"):\n    # 回傳錯誤\n    ...\n```\n\n但藉由使用 `secrets.compare_digest()`，可以防禦一種稱為「計時攻擊」的攻擊。\n\n### 計時攻擊 { #timing-attacks }\n\n什麼是「計時攻擊」呢？\n\n想像有攻擊者在嘗試猜測使用者名稱與密碼。\n\n他們送出一個帶有使用者名稱 `johndoe` 與密碼 `love123` 的請求。\n\n接著，你的應用程式中的 Python 程式碼等同於：\n\n```Python\nif \"johndoe\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\n當 Python 比較 `johndoe` 的第一個 `j` 與 `stanleyjobson` 的第一個 `s` 時，會立刻回傳 `False`，因為已經知道兩個字串不同，覺得「沒必要浪費計算資源繼續比較剩下的字元」。你的應用程式便會回應「Incorrect username or password」。\n\n但接著攻擊者改用使用者名稱 `stanleyjobsox` 與密碼 `love123` 嘗試。\n\n你的應用程式程式碼會做類似：\n\n```Python\nif \"stanleyjobsox\" == \"stanleyjobson\" and \"love123\" == \"swordfish\":\n    ...\n```\n\nPython 會必須先比較完整的 `stanleyjobso`（在 `stanleyjobsox` 與 `stanleyjobson` 之中都一樣），才會發現兩個字串不同。因此回覆「Incorrect username or password」會多花一些微秒。\n\n#### 回應時間幫了攻擊者 { #the-time-to-answer-helps-the-attackers }\n\n此時，透過觀察伺服器回覆「Incorrect username or password」多花了幾個微秒，攻擊者就知道他們有某些地方猜對了，前幾個字母是正確的。\n\n接著他們會再嘗試，知道它更可能接近 `stanleyjobsox` 而不是 `johndoe`。\n\n#### 「專業」的攻擊 { #a-professional-attack }\n\n當然，攻擊者不會手動嘗試這一切，他們會寫程式來做，可能每秒進行上千或上百萬次測試，一次只多猜中一個正確字母。\n\n但這樣做，幾分鐘或幾小時內，他們就能在我們應用程式「協助」下，僅靠回應時間就猜出正確的使用者名稱與密碼。\n\n#### 用 `secrets.compare_digest()` 修正 { #fix-it-with-secrets-compare-digest }\n\n但在我們的程式碼中實際使用的是 `secrets.compare_digest()`。\n\n簡而言之，將 `stanleyjobsox` 與 `stanleyjobson` 比較所花的時間，會與將 `johndoe` 與 `stanleyjobson` 比較所花的時間相同；密碼也一樣。\n\n如此一來，在應用程式程式碼中使用 `secrets.compare_digest()`，就能安全地防禦這整類的安全攻擊。\n\n### 回傳錯誤 { #return-the-error }\n\n在偵測到憑證不正確之後，回傳一個狀態碼為 401 的 `HTTPException`（與未提供憑證時相同），並加上 `WWW-Authenticate` 標頭，讓瀏覽器再次顯示登入提示：\n\n{* ../../docs_src/security/tutorial007_an_py310.py hl[26:30] *}\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/security/index.md",
    "content": "# 進階安全性 { #advanced-security }\n\n## 額外功能 { #additional-features }\n\n除了[教學 - 使用者指南：安全性](../../tutorial/security/index.md)中涵蓋的內容外，還有一些用來處理安全性的額外功能。\n\n/// tip\n\n以下各節**不一定是「進階」**內容。\n\n而且你的情境很可能可以在其中找到解決方案。\n\n///\n\n## 請先閱讀教學 { #read-the-tutorial-first }\n\n以下各節假設你已閱讀主要的[教學 - 使用者指南：安全性](../../tutorial/security/index.md)。\n\n它們都建立在相同的概念之上，但提供一些額外的功能。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/security/oauth2-scopes.md",
    "content": "# OAuth2 範圍（scopes） { #oauth2-scopes }\n\n你可以直接在 FastAPI 中使用 OAuth2 的 scopes，已整合可無縫運作。\n\n這能讓你在 OpenAPI 應用（以及 API 文件）中，依照 OAuth2 標準，實作更細粒度的權限系統。\n\n帶有 scopes 的 OAuth2 是許多大型身分驗證提供者（如 Facebook、Google、GitHub、Microsoft、X（Twitter）等）所使用的機制。他們用它來為使用者與應用程式提供特定權限。\n\n每次你「使用」Facebook、Google、GitHub、Microsoft、X（Twitter）「登入」時，那個應用就是在使用帶有 scopes 的 OAuth2。\n\n在本節中，你將看到如何在你的 FastAPI 應用中，用同樣的帶有 scopes 的 OAuth2 管理驗證與授權。\n\n/// warning\n\n這一節算是進階內容。如果你剛開始，可以先跳過。\n\n你不一定需要 OAuth2 scopes，你可以用任何你想要的方式處理驗證與授權。\n\n但帶有 scopes 的 OAuth2 可以很漂亮地整合進你的 API（透過 OpenAPI）與 API 文件。\n\n無論如何，你仍然會在程式碼中，依你的需求，強制檢查那些 scopes，或其他任何安全性／授權需求。\n\n在許多情況下，帶有 scopes 的 OAuth2 可能有點大材小用。\n\n但如果你確定需要，或是好奇，請繼續閱讀。\n\n///\n\n## OAuth2 scopes 與 OpenAPI { #oauth2-scopes-and-openapi }\n\nOAuth2 規格將「scopes」定義為以空白分隔的一串字串列表。\n\n每個字串的內容可以有任意格式，但不應包含空白。\n\n這些 scopes 代表「權限」。\n\n在 OpenAPI（例如 API 文件）中，你可以定義「security schemes」。\n\n當某個 security scheme 使用 OAuth2 時，你也可以宣告並使用 scopes。\n\n每個「scope」就是一個（不含空白的）字串。\n\n它們通常用來宣告特定的安全性權限，例如：\n\n- `users:read` 或 `users:write` 是常見的例子。\n- `instagram_basic` 是 Facebook / Instagram 使用的。\n- `https://www.googleapis.com/auth/drive` 是 Google 使用的。\n\n/// info\n\n在 OAuth2 中，「scope」只是宣告所需特定權限的一個字串。\n\n是否包含像 `:` 這樣的字元，或是否是一個 URL，都沒差。\n\n那些細節取決於實作。\n\n對 OAuth2 而言，它們就是字串。\n\n///\n\n## 全局概觀 { #global-view }\n\n先快速看看相對於主教學「使用密碼（與雜湊）、Bearer 與 JWT token 的 OAuth2」的差異（[OAuth2 with Password (and hashing), Bearer with JWT tokens](../../tutorial/security/oauth2-jwt.md)）。現在加入了 OAuth2 scopes：\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,9,13,47,65,106,108:116,122:126,130:136,141,157] *}\n\n接著我們一步一步檢視這些變更。\n\n## OAuth2 安全性方案 { #oauth2-security-scheme }\n\n第一個變更是：我們現在宣告了帶有兩個可用 scope 的 OAuth2 安全性方案，`me` 與 `items`。\n\n參數 `scopes` 接收一個 `dict`，以各 scope 為鍵、其描述為值：\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[63:66] *}\n\n由於現在宣告了這些 scopes，當你登入／授權時，它們會出現在 API 文件中。\n\n你可以選擇要授予哪些 scopes 存取權：`me` 與 `items`。\n\n這與你使用 Facebook、Google、GitHub 等登入時所授與權限的機制相同：\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n## 內含 scopes 的 JWT token { #jwt-token-with-scopes }\n\n現在，修改 token 的路徑操作以回傳所請求的 scopes。\n\n我們仍然使用相同的 `OAuth2PasswordRequestForm`。它包含屬性 `scopes`，其為 `list` 的 `str`，列出請求中收到的每個 scope。\n\n並且我們將這些 scopes 作為 JWT token 的一部分回傳。\n\n/// danger\n\n為了簡化，這裡我們只是直接把接收到的 scopes 加進 token。\n\n但在你的應用中，為了安全性，你應確保只加入該使用者實際可擁有或你預先定義的 scopes。\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[157] *}\n\n## 在路徑操作與相依性中宣告 scopes { #declare-scopes-in-path-operations-and-dependencies }\n\n現在我們宣告 `/users/me/items/` 這個路徑操作需要 `items` 這個 scope。\n\n為此，我們從 `fastapi` 匯入並使用 `Security`。\n\n你可以使用 `Security` 來宣告相依性（就像 `Depends`），但 `Security` 也能接收參數 `scopes`，其為 scopes（字串）的列表。\n\n在這裡，我們將相依函式 `get_current_active_user` 傳給 `Security`（就像使用 `Depends` 一樣）。\n\n但同時也傳入一個 `list` 的 scopes，這裡只有一個 scope：`items`（當然也可以有更多）。\n\n而相依函式 `get_current_active_user` 也能宣告子相依性，不只用 `Depends`，也能用 `Security`。它宣告了自己的子相依函式（`get_current_user`），並加入更多 scope 要求。\n\n在這個例子中，它要求 `me` 這個 scope（也可以要求多個）。\n\n/// note\n\n你不一定需要在不同地方加上不同的 scopes。\n\n我們在這裡這樣做，是為了示範 FastAPI 如何處理在不同層級宣告的 scopes。\n\n///\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[5,141,172] *}\n\n/// info | 技術細節\n\n`Security` 其實是 `Depends` 的子類別，僅多了一個我們稍後會看到的參數。\n\n改用 `Security` 而不是 `Depends`，能讓 FastAPI 知道可以宣告安全性 scopes、在內部使用它們，並用 OpenAPI 文件化 API。\n\n另外，當你從 `fastapi` 匯入 `Query`、`Path`、`Depends`、`Security` 等時，實際上它們是回傳特殊類別的函式。\n\n///\n\n## 使用 `SecurityScopes` { #use-securityscopes }\n\n現在更新相依性 `get_current_user`。\n\n上面的相依性就是使用它。\n\n這裡我們使用先前建立的相同 OAuth2 scheme，並將其宣告為相依性：`oauth2_scheme`。\n\n因為此相依函式本身沒有任何 scope 要求，所以我們可以用 `Depends` 搭配 `oauth2_scheme`，當不需要指定安全性 scopes 時就不必用 `Security`。\n\n我們也宣告了一個型別為 `SecurityScopes` 的特殊參數，從 `fastapi.security` 匯入。\n\n這個 `SecurityScopes` 類似於 `Request`（`Request` 用來直接取得請求物件）。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[9,106] *}\n\n## 使用這些 `scopes` { #use-the-scopes }\n\n參數 `security_scopes` 的型別是 `SecurityScopes`。\n\n它會有屬性 `scopes`，包含一個列表，內含此函式本身與所有使用它為子相依性的相依性所要求的所有 scopes。也就是所有「相依者（dependants）」... 這聽起來可能有點混亂，下面會再解釋。\n\n`security_scopes` 物件（類別 `SecurityScopes`）也提供 `scope_str` 屬性，為一個字串，包含那些以空白分隔的 scopes（我們會用到）。\n\n我們建立一個可在多處重複丟出（`raise`）的 `HTTPException`。\n\n在這個例外中，我們把所需的 scopes（若有）以空白分隔的字串形式（透過 `scope_str`）加入，並將該包含 scopes 的字串放在 `WWW-Authenticate` 標頭中（這是規格的一部分）。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[106,108:116] *}\n\n## 驗證 `username` 與資料結構 { #verify-the-username-and-data-shape }\n\n我們先確認取得了 `username`，並取出 scopes。\n\n接著用 Pydantic 模型驗證這些資料（捕捉 `ValidationError` 例外），若在讀取 JWT token 或用 Pydantic 驗證資料時出錯，就丟出先前建立的 `HTTPException`。\n\n為此，我們更新了 Pydantic 模型 `TokenData`，加入新屬性 `scopes`。\n\n透過 Pydantic 驗證資料，我們可以確保，例如，scopes 正好是 `list` 的 `str`，而 `username` 是 `str`。\n\n否則若是 `dict` 或其他型別，可能在後續某處使應用壞掉，造成安全風險。\n\n我們也會確認該 `username` 對應的使用者是否存在，否則同樣丟出之前建立的例外。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[47,117:129] *}\n\n## 驗證 `scopes` { #verify-the-scopes }\n\n我們現在要驗證，此相依性與所有相依者（包含路徑操作）所要求的所有 scopes，是否都包含在收到的 token 內所提供的 scopes 中；否則就丟出 `HTTPException`。\n\n為此，我們使用 `security_scopes.scopes`，其中包含一個 `list`，列出所有這些 `str` 形式的 scopes。\n\n{* ../../docs_src/security/tutorial005_an_py310.py hl[130:136] *}\n\n## 相依性樹與 scopes { #dependency-tree-and-scopes }\n\n我們再回顧一次這個相依性樹與 scopes。\n\n由於 `get_current_active_user` 相依於 `get_current_user`，因此在 `get_current_active_user` 宣告的 `\"me\"` 這個 scope 會包含在傳給 `get_current_user` 的 `security_scopes.scopes` 的必須 scopes 清單中。\n\n路徑操作本身也宣告了 `\"items\"` 這個 scope，因此它也會包含在傳給 `get_current_user` 的 `security_scopes.scopes` 中。\n\n以下是相依性與 scopes 的階層關係：\n\n- 路徑操作 `read_own_items` 具有：\n  - 需要的 scopes `[\"items\"]`，並有相依性：\n  - `get_current_active_user`：\n    - 相依函式 `get_current_active_user` 具有：\n      - 需要的 scopes `[\"me\"]`，並有相依性：\n      - `get_current_user`：\n        - 相依函式 `get_current_user` 具有：\n          - 自身沒有需要的 scopes。\n          - 一個使用 `oauth2_scheme` 的相依性。\n          - 一個型別為 `SecurityScopes` 的 `security_scopes` 參數：\n            - 這個 `security_scopes` 參數有屬性 `scopes`，其為一個 `list`，包含了上面宣告的所有 scopes，因此：\n              - 對於路徑操作 `read_own_items`，`security_scopes.scopes` 會包含 `[\"me\", \"items\"]`。\n              - 對於路徑操作 `read_users_me`，因為它在相依性 `get_current_active_user` 中被宣告，`security_scopes.scopes` 會包含 `[\"me\"]`。\n              - 對於路徑操作 `read_system_status`，因為它沒有宣告任何帶 `scopes` 的 `Security`，且其相依性 `get_current_user` 也未宣告任何 `scopes`，所以 `security_scopes.scopes` 會包含 `[]`（空）。\n\n/// tip\n\n這裡重要且「神奇」的是：`get_current_user` 在每個路徑操作中，會有不同的 `scopes` 清單需要檢查。\n\n這完全取決於該路徑操作與其相依性樹中每個相依性所宣告的 `scopes`。\n\n///\n\n## 更多關於 `SecurityScopes` 的細節 { #more-details-about-securityscopes }\n\n你可以在任意位置、多個地方使用 `SecurityScopes`，它不需要位於「根」相依性。\n\n它會永遠帶有對於「該特定」路徑操作與「該特定」相依性樹中，目前 `Security` 相依性所宣告的安全性 scopes（以及所有相依者）：\n\n因為 `SecurityScopes` 會擁有由相依者宣告的所有 scopes，你可以在一個集中式相依函式中用它來驗證 token 是否具有所需 scopes，然後在不同路徑操作中宣告不同的 scope 要求。\n\n它們會在每個路徑操作被各自獨立檢查。\n\n## 試用看看 { #check-it }\n\n如果你打開 API 文件，你可以先驗證並指定你要授權的 scopes。\n\n<img src=\"/img/tutorial/security/image11.png\">\n\n如果你沒有選任何 scope，你仍會「通過驗證」，但當你嘗試存取 `/users/me/` 或 `/users/me/items/` 時，會收到沒有足夠權限的錯誤。你仍能存取 `/status/`。\n\n若你只選了 `me` 而未選 `items`，你能存取 `/users/me/`，但無法存取 `/users/me/items/`。\n\n這就是第三方應用在取得使用者提供的 token 後，嘗試存取上述路徑操作時，會依使用者授與該應用的權限多寡而有不同結果。\n\n## 關於第三方整合 { #about-third-party-integrations }\n\n在這個範例中，我們使用 OAuth2 的「password」流程。\n\n當我們登入自己的應用（可能也有自己的前端）時，這是合適的。\n\n因為我們可以信任它接收 `username` 與 `password`，因為我們掌控它。\n\n但如果你要打造一個讓他人連接的 OAuth2 應用（也就是你要建立一個相當於 Facebook、Google、GitHub 等的身分驗證提供者），你應該使用其他流程之一。\n\n最常見的是 Implicit Flow（隱式流程）。\n\n最安全的是 Authorization Code Flow（授權碼流程），但它需要更多步驟、實作也更複雜。因為較複雜，許多提供者最後會建議使用隱式流程。\n\n/// note\n\n很常見的是，每個身分驗證提供者會用不同的方式命名他們的流程，讓它成為品牌的一部分。\n\n但最終，他們實作的都是相同的 OAuth2 標準。\n\n///\n\nFastAPI 在 `fastapi.security.oauth2` 中提供了所有這些 OAuth2 驗證流程的工具。\n\n## 在裝飾器 `dependencies` 中使用 `Security` { #security-in-decorator-dependencies }\n\n就像你可以在裝飾器的 `dependencies` 參數中定義一個 `Depends` 的 `list` 一樣（詳見[路徑操作裝飾器中的相依性](../../tutorial/dependencies/dependencies-in-path-operation-decorators.md)），你也可以在那裡使用帶有 `scopes` 的 `Security`。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/settings.md",
    "content": "# 設定與環境變數 { #settings-and-environment-variables }\n\n在許多情況下，你的應用程式可能需要一些外部設定或組態，例如密鑰、資料庫憑證、電子郵件服務的憑證等。\n\n這些設定大多是可變的（可能會改變），像是資料庫 URL。也有許多可能是敏感資訊，例如密鑰。\n\n因此，通常會透過環境變數提供這些設定，讓應用程式去讀取。\n\n/// tip\n\n若想了解環境變數，你可以閱讀[環境變數](../environment-variables.md)。\n\n///\n\n## 型別與驗證 { #types-and-validation }\n\n這些環境變數只能處理文字字串，因為它們在 Python 之外，必須與其他程式與系統的其餘部分相容（甚至跨作業系統，如 Linux、Windows、macOS）。\n\n這表示在 Python 中自環境變數讀取到的任何值都會是 `str`，而任何轉型成其他型別或驗證都必須在程式碼中完成。\n\n## Pydantic `Settings` { #pydantic-settings }\n\n幸好，Pydantic 提供了很好的工具，可用來處理由環境變數而來的設定：[Pydantic：設定管理](https://docs.pydantic.dev/latest/concepts/pydantic_settings/)。\n\n### 安裝 `pydantic-settings` { #install-pydantic-settings }\n\n首先，請先建立你的[虛擬環境](../virtual-environments.md)，啟用它，然後安裝 `pydantic-settings` 套件：\n\n<div class=\"termy\">\n\n```console\n$ pip install pydantic-settings\n---> 100%\n```\n\n</div>\n\n當你用 `all` extras 安裝時，它也會一併包含在內：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[all]\"\n---> 100%\n```\n\n</div>\n\n### 建立 `Settings` 物件 { #create-the-settings-object }\n\n從 Pydantic 匯入 `BaseSettings` 並建立子類別，與建立 Pydantic model 的方式非常類似。\n\n就像使用 Pydantic model 一樣，你用型別註解宣告類別屬性，並可選擇性地提供預設值。\n\n你可以使用與 Pydantic model 相同的所有驗證功能與工具，例如不同的資料型別與透過 `Field()` 進行額外驗證。\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[2,5:8,11] *}\n\n/// tip\n\n如果你想要可以直接複製貼上的範例，先別用這個，請改用本文最後一個範例。\n\n///\n\n接著，當你建立該 `Settings` 類別的實例（此處為 `settings` 物件）時，Pydantic 會以不區分大小寫的方式讀取環境變數，因此，即使環境變數是大寫的 `APP_NAME`，也會被讀入屬性 `app_name`。\n\n然後它會轉換並驗證資料。因此，當你使用該 `settings` 物件時，你會得到你宣告的型別的資料（例如 `items_per_user` 會是 `int`）。\n\n### 使用 `settings` { #use-the-settings }\n\n接著你可以在應用程式中使用新的 `settings` 物件：\n\n{* ../../docs_src/settings/tutorial001_py310.py hl[18:20] *}\n\n### 執行伺服器 { #run-the-server }\n\n接下來，你可以在啟動伺服器時，將設定以環境變數傳入。舉例來說，你可以設定 `ADMIN_EMAIL` 與 `APP_NAME`：\n\n<div class=\"termy\">\n\n```console\n$ ADMIN_EMAIL=\"deadpool@example.com\" APP_NAME=\"ChimichangApp\" fastapi run main.py\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// tip\n\n要為單一指令設定多個環境變數，只要用空白分隔它們，並全部放在指令前面即可。\n\n///\n\n如此一來，`admin_email` 設定會被設為 `\"deadpool@example.com\"`。\n\n`app_name` 會是 `\"ChimichangApp\"`。\n\n而 `items_per_user` 則會保留其預設值 `50`。\n\n## 在另一個模組中的設定 { #settings-in-another-module }\n\n你也可以把這些設定放在另一個模組檔案中，就像在[更大的應用程式 - 多個檔案](../tutorial/bigger-applications.md)所示。\n\n例如，你可以有一個 `config.py` 檔案如下：\n\n{* ../../docs_src/settings/app01_py310/config.py *}\n\n然後在 `main.py` 檔案中使用它：\n\n{* ../../docs_src/settings/app01_py310/main.py hl[3,11:13] *}\n\n/// tip\n\n你也需要一個 `__init__.py` 檔案，詳見[更大的應用程式 - 多個檔案](../tutorial/bigger-applications.md)。\n\n///\n\n## 在相依中的設定 { #settings-in-a-dependency }\n\n在某些情境中，從相依（dependency）提供設定，會比在各處使用一個全域的 `settings` 物件更有用。\n\n這在測試時特別實用，因為你可以很容易用自訂的設定來覆寫一個相依。\n\n### 設定檔 { #the-config-file }\n\n延續前一個範例，你的 `config.py` 可以像這樣：\n\n{* ../../docs_src/settings/app02_an_py310/config.py hl[10] *}\n\n注意現在我們不再建立預設實例 `settings = Settings()`。\n\n### 主應用程式檔案 { #the-main-app-file }\n\n現在我們建立一個相依，回傳新的 `config.Settings()`。\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[6,12:13] *}\n\n/// tip\n\n我們稍後會討論 `@lru_cache`。\n\n現在你可以先把 `get_settings()` 視為一般函式。\n\n///\n\n接著我們可以在*路徑操作函式 (path operation function)* 中將它宣告為相依，並在需要的地方使用它。\n\n{* ../../docs_src/settings/app02_an_py310/main.py hl[17,19:21] *}\n\n### 設定與測試 { #settings-and-testing }\n\n接著，在測試時要提供不同的設定物件會非常容易，只要為 `get_settings` 建立相依覆寫（dependency override）即可：\n\n{* ../../docs_src/settings/app02_an_py310/test_main.py hl[9:10,13,21] *}\n\n在相依覆寫中，我們在建立新的 `Settings` 物件時設定 `admin_email` 的新值，然後回傳該新物件。\n\n接著我們就可以測試它是否被使用。\n\n## 讀取 `.env` 檔 { #reading-a-env-file }\n\n如果你有許多設定，而且在不同環境中可能常常變動，將它們放在一個檔案中，然後像讀取環境變數一樣自該檔案讀取，可能會很實用。\n\n這種作法很常見，這些環境變數通常放在 `.env` 檔中，而該檔案被稱為「dotenv」。\n\n/// tip\n\n在類 Unix 系統（如 Linux 與 macOS）中，以點（`.`）開頭的檔案是隱藏檔。\n\n但 dotenv 檔並不一定必須使用這個確切的檔名。\n\n///\n\nPydantic 透過外部函式庫支援讀取這類型的檔案。你可以閱讀更多：[Pydantic Settings：Dotenv (.env) 支援](https://docs.pydantic.dev/latest/concepts/pydantic_settings/#dotenv-env-support)。\n\n/// tip\n\n要讓這個功能運作，你需要 `pip install python-dotenv`。\n\n///\n\n### `.env` 檔 { #the-env-file }\n\n你可以有一個 `.env` 檔如下：\n\n```bash\nADMIN_EMAIL=\"deadpool@example.com\"\nAPP_NAME=\"ChimichangApp\"\n```\n\n### 從 `.env` 讀取設定 { #read-settings-from-env }\n\n然後更新你的 `config.py`：\n\n{* ../../docs_src/settings/app03_an_py310/config.py hl[9] *}\n\n/// tip\n\n`model_config` 屬性僅用於 Pydantic 的設定。你可以閱讀更多：[Pydantic：概念：設定](https://docs.pydantic.dev/latest/concepts/config/)。\n\n///\n\n在這裡我們在 Pydantic 的 `Settings` 類別中定義設定 `env_file`，並將其值設為要使用的 dotenv 檔名。\n\n### 使用 `lru_cache` 只建立一次 `Settings` { #creating-the-settings-only-once-with-lru-cache }\n\n從磁碟讀取檔案通常是昂貴（慢）的操作，所以你可能希望只做一次，然後重複使用同一個設定物件，而不是在每個請求都讀取。\n\n但每次我們這樣做：\n\n```Python\nSettings()\n```\n\n都會建立一個新的 `Settings` 物件，而且在建立時會再次讀取 `.env` 檔。\n\n如果相依函式只是像這樣：\n\n```Python\ndef get_settings():\n    return Settings()\n```\n\n我們就會為每個請求建立該物件，並在每個請求都讀取 `.env` 檔。⚠️\n\n但由於我們在上方使用了 `@lru_cache` 裝飾器，`Settings` 物件只會在第一次呼叫時建立一次。✔️\n\n{* ../../docs_src/settings/app03_an_py310/main.py hl[1,11] *}\n\n之後在下一批請求的相依中任何對 `get_settings()` 的呼叫，都不會再執行 `get_settings()` 的內部程式碼與建立新的 `Settings` 物件，而是會一再回傳第一次呼叫時回傳的同一個物件。\n\n#### `lru_cache` 技術細節 { #lru-cache-technical-details }\n\n`@lru_cache` 會修改它所裝飾的函式，使其回傳第一次回傳的相同值，而不是每次都重新計算、執行函式碼。\n\n因此，被裝飾的函式對於每組參數組合只會執行一次。之後，凡是以完全相同參數組合呼叫時，都會重複使用先前對應的回傳值。\n\n例如，如果你有一個函式：\n\n```Python\n@lru_cache\ndef say_hi(name: str, salutation: str = \"Ms.\"):\n    return f\"Hello {salutation} {name}\"\n```\n\n你的程式可能會這樣執行：\n\n```mermaid\nsequenceDiagram\n\nparticipant code as Code\nparticipant function as say_hi()\nparticipant execute as Execute function\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 0, .1)\n        code ->> function: say_hi(name=\"Rick\", salutation=\"Mr.\")\n        function ->> execute: execute function code\n        execute ->> code: return the result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Rick\")\n        function ->> code: return stored result\n    end\n\n    rect rgba(0, 255, 255, .1)\n        code ->> function: say_hi(name=\"Camila\")\n        function ->> code: return stored result\n    end\n```\n\n在我們的相依 `get_settings()` 這個案例中，該函式甚至不帶任何參數，因此它總是回傳相同的值。\n\n如此一來，它的行為幾乎就像全域變數。但因為它使用相依函式，因此我們可以在測試時輕鬆將其覆寫。\n\n`@lru_cache` 是 `functools` 的一部分，而 `functools` 是 Python 標準程式庫的一部分。你可以在[Python 文件中閱讀 `@lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache) 以了解更多。\n\n## 回顧 { #recap }\n\n你可以使用 Pydantic Settings 來處理應用程式的設定或組態，並享有 Pydantic model 的全部能力。\n\n- 透過相依可以讓測試更容易。\n- 你可以搭配 `.env` 檔使用。\n- 使用 `@lru_cache` 可以避免每個請求都重複讀取 dotenv 檔，同時仍可在測試時覆寫設定。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/stream-data.md",
    "content": "# 串流資料 { #stream-data }\n\n如果你要串流可用 JSON 結構化的資料，應該[串流 JSON Lines](../tutorial/stream-json-lines.md)。\n\n但如果你想串流純二進位資料或字串，以下是做法。\n\n/// info\n\n已在 FastAPI 0.134.0 新增。\n\n///\n\n## 使用情境 { #use-cases }\n\n當你想串流純字串時可以用這個機制，例如直接轉發來自 AI LLM 服務的輸出。\n\n你也可以用它來串流大型二進位檔案，邊讀邊將每個區塊（chunk）串流出去，而不必一次把整個檔案載入記憶體。\n\n你也可以用同樣方式串流視訊或音訊，甚至可以在處理的同時即時產生並傳送。\n\n## 使用 `yield` 的 `StreamingResponse` { #a-streamingresponse-with-yield }\n\n如果在你的路徑操作函式中宣告 `response_class=StreamingResponse`，就可以用 `yield` 逐一送出每個資料區塊。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[1:23] hl[20,23] *}\n\nFastAPI 會如實將每個資料區塊交給 `StreamingResponse`，不會嘗試將其轉換為 JSON 或其他格式。\n\n### 非 async 路徑操作函式 { #non-async-path-operation-functions }\n\n你也可以使用一般的 `def` 函式（沒有 `async`），並以相同方式使用 `yield`。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[26:29] hl[27] *}\n\n### 不需要型別註解 { #no-annotation }\n\n對於串流二進位資料，其實不需要宣告回傳型別註解。\n\n由於 FastAPI 不會試圖用 Pydantic 將資料轉成 JSON，或以其他方式序列化，在這種情況下，型別註解僅供編輯器與工具使用，FastAPI 並不會用到它。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[32:35] hl[33] *}\n\n這也意味著使用 `StreamingResponse` 時，你擁有自由與責任，需依需求自行產生並編碼要傳送的位元組資料，與型別註解無關。 🤓\n\n### 串流位元組 { #stream-bytes }\n\n一個主要用例是串流 `bytes` 而非字串，當然可以這麼做。\n\n{* ../../docs_src/stream_data/tutorial001_py310.py ln[44:47] hl[47] *}\n\n## 自訂 `PNGStreamingResponse` { #a-custom-pngstreamingresponse }\n\n在上述範例中，雖然串流了資料位元組，但回應沒有 `Content-Type` 標頭，因此用戶端不知道接收到的是哪種資料型別。\n\n你可以建立 `StreamingResponse` 的自訂子類別，將 `Content-Type` 標頭設定為你要串流的資料型別。\n\n例如，你可以建立 `PNGStreamingResponse`，透過 `media_type` 屬性把 `Content-Type` 設為 `image/png`：\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[6,19:20] hl[20] *}\n\n接著在路徑操作函式中用 `response_class=PNGStreamingResponse` 使用這個新類別：\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[23:27] hl[23] *}\n\n### 模擬檔案 { #simulate-a-file }\n\n此範例中我們用 `io.BytesIO` 模擬檔案。它是只存在於記憶體中的類檔案物件，但提供相同的介面。\n\n例如，我們可以像讀取一般檔案一樣，透過迭代來消耗其內容。\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[1:27] hl[3,12:13,25] *}\n\n/// note | 技術細節\n\n另外兩個變數 `image_base64` 與 `binary_image`，分別是先將影像以 Base64 編碼，接著轉成位元組，最後再傳給 `io.BytesIO`。\n\n這只是為了讓範例能放在同一個檔案中，方便你直接複製並執行。 🥚\n\n///\n\n使用 `with` 區塊可確保在產生器函式（包含 `yield` 的函式）完成後關閉該類檔案物件，也就是在送完回應之後。\n\n在這個範例中因為是存在記憶體的假檔案（`io.BytesIO`），影響不大；但若是實際檔案，務必在處理完成後關閉檔案。\n\n### 檔案與 Async { #files-and-async }\n\n多數情況下，類檔案物件預設不相容於 async/await。\n\n例如，它們沒有 `await file.read()`，也不支援 `async for chunk in file`。\n\n而且在許多情況下，讀取它們會是阻塞操作（可能阻塞事件迴圈），因為資料是從磁碟或網路讀取。\n\n/// info\n\n上面的範例其實是例外，因為 `io.BytesIO` 物件已在記憶體中，讀取不會阻塞任何東西。\n\n但在多數情況下，讀取檔案或類檔案物件會造成阻塞。\n\n///\n\n為了避免阻塞事件迴圈，你可以將路徑操作函式宣告為一般的 `def`（而非 `async def`），這樣 FastAPI 會在 threadpool worker 上執行它，避免阻塞主事件迴圈。\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[30:34] hl[31] *}\n\n/// tip\n\n如果你需要在 async 函式內呼叫阻塞程式碼，或在阻塞函式中呼叫 async 函式，你可以使用 [Asyncer](https://asyncer.tiangolo.com)，它是 FastAPI 的姊妹函式庫。\n\n///\n\n### `yield from` { #yield-from }\n\n當你在迭代某個物件（如類檔案物件），並對每個項目使用 `yield` 時，也可以用 `yield from` 直接逐項產出，省略 `for` 迴圈。\n\n這不是 FastAPI 特有的功能，而是 Python 語法；不過這招很實用。 😎\n\n{* ../../docs_src/stream_data/tutorial002_py310.py ln[37:40] hl[40] *}\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/strict-content-type.md",
    "content": "# 嚴格的 Content-Type 檢查 { #strict-content-type-checking }\n\n預設情況下，FastAPI 會對 JSON 請求主體使用嚴格的 `Content-Type` 標頭檢查。也就是說，JSON 請求必須包含有效的 `Content-Type` 標頭（例如 `application/json`），請求主體（body）才能被解析為 JSON。\n\n## CSRF 風險 { #csrf-risk }\n\n這個預設行為在某個非常特定的情境下，能對一類跨站請求偽造（CSRF, Cross-Site Request Forgery）攻擊提供保護。\n\n這類攻擊利用了瀏覽器在以下情況下允許腳本發送請求而不進行任何 CORS 預檢（preflight）檢查的事實：\n\n- 沒有 `Content-Type` 標頭（例如以 `fetch()` 並使用 `Blob` 作為 body）\n- 且沒有送出任何身分驗證憑證\n\n這種攻擊主要與以下情境相關：\n\n- 應用在本機（例如 `localhost`）或內部網路中執行\n- 並且應用沒有任何身分驗證，假設同一個網路中的任何請求都可被信任\n\n## 攻擊範例 { #example-attack }\n\n假設你打造了一個在本機執行 AI 代理（AI agent）的方法。\n\n它提供一個 API：\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\n同時也有一個前端：\n\n```\nhttp://localhost:8000\n```\n\n/// tip | 提示\n\n請注意兩者的主機（host）相同。\n\n///\n\n接著你可以透過前端讓 AI 代理代你執行動作。\n\n由於它在本機執行、而非公開的網際網路上，你決定不設定任何身分驗證，只信任對本機網路的存取。\n\n然後你的某位使用者可能安裝並在本機執行它。\n\n接著他可能打開一個惡意網站，例如：\n\n```\nhttps://evilhackers.example.com\n```\n\n該惡意網站會使用 `fetch()` 並以 `Blob` 作為 body，向本機的 API 發送請求：\n\n```\nhttp://localhost:8000/v1/agents/multivac\n```\n\n即使惡意網站與本機應用的主機不同，瀏覽器也不會觸發 CORS 預檢請求，因為：\n\n- 它在未經任何身分驗證的情況下執行，不需要送出任何憑證。\n- 由於缺少 `Content-Type` 標頭，瀏覽器認為它並未傳送 JSON。\n\n接著，惡意網站就能讓本機的 AI 代理替使用者向前老闆發飆傳訊... 或做更糟的事。😅\n\n## 公開的網際網路 { #open-internet }\n\n如果你的應用部署在公開的網際網路上，你不會「信任網路」而允許任何人在未經身分驗證的情況下發送具權限的請求。\n\n攻擊者可以直接執行腳本向你的 API 發送請求，無需透過瀏覽器互動，因此你多半已經對任何具權限的端點做了防護。\n\n在這種情況下，這種攻擊／風險不適用於你。\n\n此風險與攻擊主要與應用只在本機或內部網路上執行，且「僅依賴此為保護」的情境相關。\n\n## 允許沒有 Content-Type 的請求 { #allowing-requests-without-content-type }\n\n若你需要支援未送出 `Content-Type` 標頭的客戶端，可以將 `strict_content_type=False` 以停用嚴格檢查：\n\n{* ../../docs_src/strict_content_type/tutorial001_py310.py hl[4] *}\n\n啟用此設定後，缺少 `Content-Type` 標頭的請求會將其主體解析為 JSON，這與舊版 FastAPI 的行為相同。\n\n/// info | 資訊\n\n此行為與設定新增於 FastAPI 0.132.0。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/sub-applications.md",
    "content": "# 子應用程式 - 掛載 { #sub-applications-mounts }\n\n若你需要兩個彼此獨立的 FastAPI 應用程式，各自擁有獨立的 OpenAPI 與文件 UI，你可以有一個主應用，並「掛載」一個（或多個）子應用程式。\n\n## 掛載一個 **FastAPI** 應用程式 { #mounting-a-fastapi-application }\n\n「掛載」是指在某個特定路徑下加入一個完全「獨立」的應用程式，之後該應用程式會負責處理該路徑底下的一切，使用該子應用程式中宣告的*路徑操作（path operation）*。\n\n### 頂層應用程式 { #top-level-application }\n\n先建立主（頂層）**FastAPI** 應用程式以及它的*路徑操作*：\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[3, 6:8] *}\n\n### 子應用程式 { #sub-application }\n\n接著，建立你的子應用程式及其*路徑操作*。\n\n這個子應用程式就是另一個標準的 FastAPI 應用，但這個會被「掛載」：\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 14:16] *}\n\n### 掛載子應用程式 { #mount-the-sub-application }\n\n在你的頂層應用程式 `app` 中，掛載子應用程式 `subapi`。\n\n在此範例中，它會被掛載在路徑 `/subapi`：\n\n{* ../../docs_src/sub_applications/tutorial001_py310.py hl[11, 19] *}\n\n### 檢查自動 API 文件 { #check-the-automatic-api-docs }\n\n現在，執行 `fastapi` 指令：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n然後開啟位於 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) 的文件。\n\n你會看到主應用的自動 API 文件，只包含它自己的*路徑操作*：\n\n<img src=\"/img/tutorial/sub-applications/image01.png\">\n\n接著，開啟子應用程式的文件：[http://127.0.0.1:8000/subapi/docs](http://127.0.0.1:8000/subapi/docs)。\n\n你會看到子應用程式的自動 API 文件，只包含它自己的*路徑操作*，而且都在正確的子路徑前綴 `/subapi` 之下：\n\n<img src=\"/img/tutorial/sub-applications/image02.png\">\n\n如果你嘗試在任一介面中互動，它們都會正常運作，因為瀏覽器能與各自的應用程式或子應用程式通訊。\n\n### 技術細節：`root_path` { #technical-details-root-path }\n\n當你像上面那樣掛載子應用程式時，FastAPI 會使用 ASGI 規範中的一個機制 `root_path`，將子應用程式的掛載路徑告知它。\n\n如此一來，子應用程式就會知道在文件 UI 使用該路徑前綴。\n\n而且子應用程式也能再掛載自己的子應用程式，一切都能正確運作，因為 FastAPI 會自動處理所有這些 `root_path`。\n\n你可以在[在代理伺服器之後](behind-a-proxy.md)一節中進一步了解 `root_path` 與如何顯式使用它。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/templates.md",
    "content": "# 模板 { #templates }\n\n你可以在 **FastAPI** 中使用任意你想要的模板引擎。\n\n常見的選擇是 Jinja2，與 Flask 與其他工具所使用的一樣。\n\n有一些工具可讓你輕鬆設定，並可直接在你的 **FastAPI** 應用程式中使用（由 Starlette 提供）。\n\n## 安裝相依套件 { #install-dependencies }\n\n請先建立一個[虛擬環境](../virtual-environments.md)、啟用它，然後安裝 `jinja2`：\n\n<div class=\"termy\">\n\n```console\n$ pip install jinja2\n\n---> 100%\n```\n\n</div>\n\n## 使用 `Jinja2Templates` { #using-jinja2templates }\n\n- 匯入 `Jinja2Templates`。\n- 建立一個可重複使用的 `templates` 物件。\n- 在會回傳模板的「*路徑操作（path operation）*」中宣告一個 `Request` 參數。\n- 使用你建立的 `templates` 來渲染並回傳 `TemplateResponse`，傳入模板名稱、`request` 物件，以及在 Jinja2 模板中使用的「context」鍵值對字典。\n\n{* ../../docs_src/templates/tutorial001_py310.py hl[4,11,15:18] *}\n\n/// note\n\n在 FastAPI 0.108.0、Starlette 0.29.0 之前，`name` 是第一個參數。\n\n此外，在更早的版本中，`request` 物件是作為 context 的鍵值對之一傳給 Jinja2 的。\n\n///\n\n/// tip\n\n透過宣告 `response_class=HTMLResponse`，文件 UI 能夠知道回應將會是 HTML。\n\n///\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.templating import Jinja2Templates`。\n\n**FastAPI** 以 `fastapi.templating` 的形式提供與 `starlette.templating` 相同的內容，僅為了方便你（開發者）。但大多數可用的回應類別都直接來自 Starlette，`Request` 與 `StaticFiles` 也是如此。\n\n///\n\n## 撰寫模板 { #writing-templates }\n\n接著你可以在 `templates/item.html` 編寫模板，例如：\n\n```jinja hl_lines=\"7\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n### 模板 context 值 { #template-context-values }\n\n在包含以下內容的 HTML 中：\n\n{% raw %}\n\n```jinja\nItem ID: {{ id }}\n```\n\n{% endraw %}\n\n...它會顯示你在傳入的 context `dict` 中提供的 `id`：\n\n```Python\n{\"id\": id}\n```\n\n例如，若 ID 為 `42`，會渲染為：\n\n```html\nItem ID: 42\n```\n\n### 模板 `url_for` 參數 { #template-url-for-arguments }\n\n你也可以在模板中使用 `url_for()`，它所接受的參數與你的「*路徑操作函式（path operation function）*」所使用的參數相同。\n\n因此，包含以下內容的區塊：\n\n{% raw %}\n\n```jinja\n<a href=\"{{ url_for('read_item', id=id) }}\">\n```\n\n{% endraw %}\n\n...會產生指向與「*路徑操作函式*」`read_item(id=id)` 相同 URL 的連結。\n\n例如，若 ID 為 `42`，會渲染為：\n\n```html\n<a href=\"/items/42\">\n```\n\n## 模板與靜態檔案 { #templates-and-static-files }\n\n你也可以在模板中使用 `url_for()`，例如搭配你以 `name=\"static\"` 掛載的 `StaticFiles` 使用。\n\n```jinja hl_lines=\"4\"\n{!../../docs_src/templates/templates/item.html!}\n```\n\n在這個例子中，它會連結到 `static/styles.css` 的 CSS 檔案，內容為：\n\n```CSS hl_lines=\"4\"\n{!../../docs_src/templates/static/styles.css!}\n```\n\n而且因為你使用了 `StaticFiles`，該 CSS 檔案會由你的 **FastAPI** 應用程式在 URL `/static/styles.css` 自動提供。\n\n## 更多細節 { #more-details }\n\n想了解更多細節（包含如何測試模板），請參考 [Starlette 的模板說明文件](https://www.starlette.dev/templates/)。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/testing-dependencies.md",
    "content": "# 用覆寫測試相依 { #testing-dependencies-with-overrides }\n\n## 在測試期間覆寫相依 { #overriding-dependencies-during-testing }\n\n有些情境你可能想在測試時覆寫（override）某個相依（dependency）。\n\n你不希望執行原本的相依（以及它可能具有的任何子相依）。\n\n相反地，你想提供一個只在測試期間使用的不同相依（可能只在特定測試中），並回傳一個可以在原本相依值被使用之處使用的值。\n\n### 使用情境：外部服務 { #use-cases-external-service }\n\n例如你有一個需要呼叫的外部驗證提供者。\n\n你傳送一個 token，它會回傳一個已驗證的使用者。\n\n這個提供者可能按每個請求收費，而且呼叫它可能比在測試中使用固定的模擬使用者多花一些時間。\n\n你大概只想對外部提供者測試一次，而不需要在每個測試都呼叫它。\n\n在這種情況下，你可以覆寫用來呼叫該提供者的相依，並在測試中使用自訂的相依來回傳一個模擬使用者。\n\n### 使用 `app.dependency_overrides` 屬性 { #use-the-app-dependency-overrides-attribute }\n\n對這些情況，你的 FastAPI 應用程式有一個屬性 `app.dependency_overrides`，它是一個簡單的 `dict`。\n\n要在測試時覆寫某個相依，把原始相依（函式）作為鍵，並把你的覆寫相依（另一個函式）作為值。\n\n接著 FastAPI 會呼叫這個覆寫，而不是原本的相依。\n\n{* ../../docs_src/dependency_testing/tutorial001_an_py310.py hl[26:27,30] *}\n\n/// tip\n\n你可以為應用程式中任何地方使用到的相依設定覆寫。\n\n原始相依可以用在*路徑操作函式*、*路徑操作裝飾器*（當你不使用其回傳值時）、`.include_router()` 呼叫等。\n\nFastAPI 仍然能夠將其覆寫。\n\n///\n\n然後你可以將 `app.dependency_overrides` 設為空的 `dict` 以重設（移除）所有覆寫：\n\n```Python\napp.dependency_overrides = {}\n```\n\n/// tip\n\n如果只想在某些測試中覆寫相依，你可以在測試開始時（測試函式內）設定覆寫，並在結束時（測試函式結尾）重設。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/testing-events.md",
    "content": "# 測試事件：lifespan 與 startup - shutdown { #testing-events-lifespan-and-startup-shutdown }\n\n當你需要在測試中執行 lifespan（生命週期）時，你可以使用 TestClient 並搭配 with 陳述式：\n\n{* ../../docs_src/app_testing/tutorial004_py310.py hl[9:15,18,27:28,30:32,41:43] *}\n\n你可以閱讀更多細節：[在測試中執行 lifespan](https://www.starlette.dev/lifespan/#running-lifespan-in-tests)（Starlette 官方文件）。\n\n對於已棄用的 `startup` 和 `shutdown` 事件，你可以這樣使用 TestClient：\n\n{* ../../docs_src/app_testing/tutorial003_py310.py hl[9:12,20:24] *}\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/testing-websockets.md",
    "content": "# 測試 WebSocket { #testing-websockets }\n\n你可以使用相同的 `TestClient` 來測試 WebSocket。\n\n為此，你可以在 `with` 陳述式中使用 `TestClient`，連線到該 WebSocket：\n\n{* ../../docs_src/app_testing/tutorial002_py310.py hl[27:31] *}\n\n/// note | 注意\n\n想了解更多，請參考 Starlette 的[測試 WebSocket](https://www.starlette.dev/testclient/#testing-websocket-sessions)文件。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/using-request-directly.md",
    "content": "# 直接使用 Request { #using-the-request-directly }\n\n到目前為止，你都是用對應的型別來宣告你需要的請求各部分。\n\n例如從以下來源取得資料：\n\n- 路徑中的參數。\n- 標頭。\n- Cookies。\n- 等等。\n\n這麼做時，FastAPI 會自動驗證並轉換這些資料，還會為你的 API 產生文件。\n\n但有些情況你可能需要直接存取 `Request` 物件。\n\n## 關於 `Request` 物件的細節 { #details-about-the-request-object }\n\n由於 FastAPI 底層其實是 Starlette，再加上一層工具，因此在需要時你可以直接使用 Starlette 的 [`Request`](https://www.starlette.dev/requests/) 物件。\n\n同時也代表，如果你直接從 `Request` 物件取得資料（例如讀取 body），FastAPI 不會替它做驗證、轉換或文件化（透過 OpenAPI 為自動化的 API 介面產生文件）。\n\n不過，其他以一般方式宣告的參數（例如以 Pydantic 模型宣告的 body）仍然會被驗證、轉換、加上標註等。\n\n但在某些特定情境下，直接取得 `Request` 物件會很實用。\n\n## 直接使用 `Request` 物件 { #use-the-request-object-directly }\n\n假設你想在你的 路徑操作函式（path operation function） 中取得用戶端的 IP 位址／主機。\n\n為此，你需要直接存取請求。\n\n{* ../../docs_src/using_request_directly/tutorial001_py310.py hl[1,7:8] *}\n\n只要在 路徑操作函式 中宣告一個型別為 `Request` 的參數，FastAPI 就會將當前的 `Request` 傳入該參數。\n\n/// tip\n\n注意在這個例子中，除了 request 參數之外，我們也宣告了一個路徑參數。\n\n因此，路徑參數會被擷取、驗證、轉換為指定型別，並在 OpenAPI 中加入標註。\n\n同理，你可以照常宣告其他參數，並另外同時取得 `Request`。\n\n///\n\n## `Request` 文件 { #request-documentation }\n\n你可以在 [Starlette 官方文件站點中的 `Request` 物件](https://www.starlette.dev/requests/) 了解更多細節。\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.requests import Request`。\n\nFastAPI 之所以直接提供它，是為了讓開發者更方便；但它本身是來自 Starlette。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/websockets.md",
    "content": "# WebSockets { #websockets }\n\n你可以在 **FastAPI** 中使用 [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)。\n\n## 安裝 `websockets` { #install-websockets }\n\n請先建立[虛擬環境](../virtual-environments.md)、啟用它，然後安裝 `websockets`（一個讓你更容易使用「WebSocket」通訊協定的 Python 套件）：\n\n<div class=\"termy\">\n\n```console\n$ pip install websockets\n\n---> 100%\n```\n\n</div>\n\n## WebSockets 用戶端 { #websockets-client }\n\n### 在生產環境 { #in-production }\n\n在你的生產系統中，你很可能有一個使用現代框架（如 React、Vue.js 或 Angular）建立的前端。\n\n而為了透過 WebSockets 與後端通訊，你通常會使用前端的工具。\n\n或者你可能有一個原生行動應用，使用原生程式碼直接與 WebSocket 後端通訊。\n\n又或者你有其他任何方式與 WebSocket 端點通訊。\n\n---\n\n但在這個範例中，我們會用一個非常簡單的 HTML 文件與一些 JavaScript，全都寫在一個長字串裡。\n\n當然，這並不理想，你不會在生產環境這樣做。\n\n在生產環境你通常會用上述其中一種方式。\n\n但這是能讓我們專注於 WebSocket 伺服端並跑起一個可運作範例的最簡單方式：\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[2,6:38,41:43] *}\n\n## 建立一個 `websocket` { #create-a-websocket }\n\n在你的 **FastAPI** 應用中，建立一個 `websocket`：\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[1,46:47] *}\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.websockets import WebSocket`。\n\n**FastAPI** 直接提供相同的 `WebSocket` 只是為了方便你這位開發者，但它其實是直接來自 Starlette。\n\n///\n\n## 等待與傳送訊息 { #await-for-messages-and-send-messages }\n\n在你的 WebSocket 路由中，你可以 `await` 接收訊息並傳送訊息。\n\n{* ../../docs_src/websockets_/tutorial001_py310.py hl[48:52] *}\n\n你可以接收與傳送二進位、文字與 JSON 資料。\n\n## 試試看 { #try-it }\n\n如果你的檔案名為 `main.py`，用以下指令執行應用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n在瀏覽器開啟 [http://127.0.0.1:8000](http://127.0.0.1:8000)。\n\n你會看到一個像這樣的簡單頁面：\n\n<img src=\"/img/tutorial/websockets/image01.png\">\n\n你可以在輸入框輸入訊息並送出：\n\n<img src=\"/img/tutorial/websockets/image02.png\">\n\n你的 **FastAPI** 應用會透過 WebSockets 回應：\n\n<img src=\"/img/tutorial/websockets/image03.png\">\n\n你可以傳送（與接收）多則訊息：\n\n<img src=\"/img/tutorial/websockets/image04.png\">\n\n而且它們都會使用同一個 WebSocket 連線。\n\n## 使用 `Depends` 與其他功能 { #using-depends-and-others }\n\n在 WebSocket 端點中，你可以從 `fastapi` 匯入並使用：\n\n* `Depends`\n* `Security`\n* `Cookie`\n* `Header`\n* `Path`\n* `Query`\n\n它們的運作方式與其他 FastAPI 端點/*路徑操作* 相同：\n\n{* ../../docs_src/websockets_/tutorial002_an_py310.py hl[68:69,82] *}\n\n/// info\n\n因為這是 WebSocket，拋出 `HTTPException` 並沒有意義，因此我們改為拋出 `WebSocketException`。\n\n你可以使用規範中定義的[有效關閉代碼](https://tools.ietf.org/html/rfc6455#section-7.4.1)之一。\n\n///\n\n### 用依賴試用 WebSocket { #try-the-websockets-with-dependencies }\n\n執行你的應用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n在瀏覽器開啟 [http://127.0.0.1:8000](http://127.0.0.1:8000)。\n\n在那裡你可以設定：\n\n* \"Item ID\"，用於路徑。\n* \"Token\"，作為查詢參數。\n\n/// tip\n\n注意查詢參數 `token` 會由一個依賴處理。\n\n///\n\n之後你就能連線到 WebSocket，並開始收發訊息：\n\n<img src=\"/img/tutorial/websockets/image05.png\">\n\n## 處理斷線與多個用戶端 { #handling-disconnections-and-multiple-clients }\n\n當 WebSocket 連線關閉時，`await websocket.receive_text()` 會拋出 `WebSocketDisconnect` 例外，你可以像範例中那樣捕捉並處理。\n\n{* ../../docs_src/websockets_/tutorial003_py310.py hl[79:81] *}\n\n試用方式：\n\n* 用多個瀏覽器分頁開啟該應用。\n* 從每個分頁傳送訊息。\n* 然後關閉其中一個分頁。\n\n這會引發 `WebSocketDisconnect` 例外，其他所有用戶端都會收到類似以下的訊息：\n\n```\nClient #1596980209979 left the chat\n```\n\n/// tip\n\n上面的應用是一個極簡範例，用來示範如何處理並向多個 WebSocket 連線廣播訊息。\n\n但請注意，因為所有狀態都在記憶體中的單一 list 裡管理，它只會在該程序執行期間生效，且僅適用於單一程序。\n\n如果你需要一個容易與 FastAPI 整合、但更健壯，且可由 Redis、PostgreSQL 等後端支援的方案，請參考 [encode/broadcaster](https://github.com/encode/broadcaster)。\n\n///\n\n## 更多資訊 { #more-info }\n\n想了解更多選項，請參考 Starlette 的文件：\n\n* [`WebSocket` 類別](https://www.starlette.dev/websockets/)。\n* [以類別為基礎的 WebSocket 處理](https://www.starlette.dev/endpoints/#websocketendpoint)。\n"
  },
  {
    "path": "docs/zh-hant/docs/advanced/wsgi.md",
    "content": "# 包含 WSGI：Flask、Django 等 { #including-wsgi-flask-django-others }\n\n你可以像在 [子應用程式 - 掛載](sub-applications.md)、[在 Proxy 後方](behind-a-proxy.md) 中所見那樣掛載 WSGI 應用。\n\n為此，你可以使用 `WSGIMiddleware` 來包住你的 WSGI 應用，例如 Flask、Django 等。\n\n## 使用 `WSGIMiddleware` { #using-wsgimiddleware }\n\n/// info\n\n這需要先安裝 `a2wsgi`，例如使用 `pip install a2wsgi`。\n\n///\n\n你需要從 `a2wsgi` 匯入 `WSGIMiddleware`。\n\n然後用該 middleware 包住 WSGI（例如 Flask）應用。\n\n接著把它掛載到某個路徑下。\n\n{* ../../docs_src/wsgi/tutorial001_py310.py hl[1,3,23] *}\n\n/// note\n\n先前建議使用來自 `fastapi.middleware.wsgi` 的 `WSGIMiddleware`，但現在已棄用。\n\n建議改用 `a2wsgi` 套件。用法保持相同。\n\n只要確保已安裝 `a2wsgi`，並從 `a2wsgi` 正確匯入 `WSGIMiddleware` 即可。\n\n///\n\n## 試試看 { #check-it }\n\n現在，位於路徑 `/v1/` 底下的所有請求都會由 Flask 應用處理。\n\n其餘則由 **FastAPI** 處理。\n\n如果你啟動它並前往 [http://localhost:8000/v1/](http://localhost:8000/v1/)，你會看到來自 Flask 的回應：\n\n```txt\nHello, World from Flask!\n```\n\n如果你前往 [http://localhost:8000/v2](http://localhost:8000/v2)，你會看到來自 FastAPI 的回應：\n\n```JSON\n{\n    \"message\": \"Hello World\"\n}\n```\n"
  },
  {
    "path": "docs/zh-hant/docs/alternatives.md",
    "content": "# 替代方案、靈感與比較 { #alternatives-inspiration-and-comparisons }\n\n啟發 FastAPI 的來源、與其他方案的比較，以及從中學到的內容。\n\n## 介紹 { #intro }\n\n沒有前人的工作，就不會有 **FastAPI**。\n\n在它誕生之前，已經有許多工具啟發了它的設計。\n\n我多年來一直避免打造新框架。起初我嘗試用許多不同的框架、外掛與工具，來實作 **FastAPI** 涵蓋的所有功能。\n\n但在某個時間點，除了創建一個能提供所有這些功能、汲取前人工具的優點，並以最佳方式組合起來、同時運用過去甚至不存在的語言特性（Python 3.6+ 的型別提示）之外，已別無他法。\n\n## 先前的工具 { #previous-tools }\n\n### [Django](https://www.djangoproject.com/) { #django }\n\n它是最受歡迎且廣受信任的 Python 框架。像 Instagram 等系統就是用它打造的。\n\n它與關聯式資料庫（如 MySQL 或 PostgreSQL）相對緊密耦合，因此要以 NoSQL 資料庫（如 Couchbase、MongoDB、Cassandra 等）作為主要儲存引擎並不容易。\n\n它一開始是為在後端產生 HTML 而設計，而非為了建立提供現代前端（如 React、Vue.js、Angular）或其他系統（如 <abbr title=\"Internet of Things - 物聯網\">IoT</abbr> 裝置）使用的 API。\n\n### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework }\n\nDjango REST framework 的目標是成為一套在 Django 之上構建 Web API 的彈性工具組，以強化其 API 能力。\n\n它被 Mozilla、Red Hat、Eventbrite 等眾多公司使用。\n\n它是「自動 API 文件」的早期典範之一，而這正是啟發我「尋找」**FastAPI** 的第一個想法。\n\n/// note\n\nDjango REST Framework 由 Tom Christie 創建。他同時也是 Starlette 與 Uvicorn 的作者，而 **FastAPI** 就是建立在它們之上。\n\n///\n\n/// check | 啟發 **FastAPI**\n\n提供自動化的 API 文件網頁使用者介面。\n\n///\n\n### [Flask](https://flask.palletsprojects.com) { #flask }\n\nFlask 是一個「微框架」，它不包含資料庫整合，也沒有像 Django 那樣內建許多功能。\n\n這種簡單與彈性，讓你可以把 NoSQL 資料庫作為主要的資料儲存系統。\n\n由於它非常簡單，學起來相對直觀，儘管文件在某些地方會變得較技術性。\n\n它也常用於其他不一定需要資料庫、使用者管理或 Django 內建眾多功能的應用程式。雖然這些功能中的許多都可以用外掛新增。\n\n這種元件的解耦，以及作為可擴充以精準滿足需求的「微框架」，是我想要保留的關鍵特性。\n\n基於 Flask 的簡潔，它看起來很適合用來構建 API。接下來要找的，就是 Flask 世界裡的「Django REST Framework」。\n\n/// check | 啟發 **FastAPI**\n\n成為一個微框架，讓所需的工具與元件能輕鬆搭配組合。\n\n具備簡單、易用的路由系統。\n\n///\n\n### [Requests](https://requests.readthedocs.io) { #requests }\n\n**FastAPI** 其實不是 **Requests** 的替代品。兩者的範疇截然不同。\n\n在 FastAPI 應用程式「內部」使用 Requests 其實很常見。\n\n儘管如此，FastAPI 仍從 Requests 得到了不少啟發。\n\n**Requests** 是一個「與 API 互動」（作為用戶端）的程式庫，而 **FastAPI** 是一個「建立 API」（作為伺服端）的程式庫。\n\n它們大致位於相反兩端，彼此互補。\n\nRequests 設計非常簡單直觀、容易使用，且有合理的預設值。同時它也非常強大且可自訂。\n\n因此，如其官網所言：\n\n> Requests is one of the most downloaded Python packages of all time\n\n用法非常簡單。例如，發出一個 `GET` 請求，你會寫：\n\n```Python\nresponse = requests.get(\"http://example.com/some/url\")\n```\n\n相對地，FastAPI 的 API 路徑操作（path operation）可能像這樣：\n\n```Python hl_lines=\"1\"\n@app.get(\"/some/url\")\ndef read_url():\n    return {\"message\": \"Hello World\"}\n```\n\n看看 `requests.get(...)` 與 `@app.get(...)` 的相似之處。\n\n/// check | 啟發 **FastAPI**\n\n* 擁有簡單直觀的 API。\n* 直接使用 HTTP 方法名稱（操作），以直接、直觀的方式表達。\n* 具備合理的預設值，同時提供強大的自訂能力。\n\n///\n\n### [Swagger](https://swagger.io/) / [OpenAPI](https://github.com/OAI/OpenAPI-Specification/) { #swagger-openapi }\n\n我想從 Django REST Framework 得到的主要功能是自動 API 文件。\n\n後來我發現有一個使用 JSON（或 YAML，JSON 的延伸）來描述 API 的標準，叫做 Swagger。\n\n而且已有對 Swagger API 的網頁使用者介面。因此，只要能為 API 產生 Swagger 文件，就可以自動使用這個網頁介面。\n\n之後 Swagger 交由 Linux 基金會管理，並更名為 OpenAPI。\n\n因此，談到 2.0 版時常說「Swagger」，而 3+ 版則是「OpenAPI」。\n\n/// check | 啟發 **FastAPI**\n\n採用並使用開放的 API 規格標準，而非自訂格式。\n\n並整合基於標準的使用者介面工具：\n\n* [Swagger UI](https://github.com/swagger-api/swagger-ui)\n* [ReDoc](https://github.com/Rebilly/ReDoc)\n\n選擇這兩個是因為它們相當受歡迎且穩定，但稍加搜尋，你會發現有數十種 OpenAPI 的替代使用者介面（都能與 **FastAPI** 一起使用）。\n\n///\n\n### Flask 的 REST 框架 { #flask-rest-frameworks }\n\n有幾個 Flask 的 REST 框架，但在投入時間調查後，我發現許多已停止維護或被棄置，且存在一些關鍵問題使之不適用。\n\n### [Marshmallow](https://marshmallow.readthedocs.io/en/stable/) { #marshmallow }\n\nAPI 系統需要的主要功能之一是資料「<dfn title=\"也稱為 marshalling、轉換\">序列化</dfn>」，也就是把程式中的資料（Python）轉成能透過網路傳輸的形式。例如，將含有資料庫資料的物件轉成 JSON 物件、把 `datetime` 物件轉成字串等等。\n\nAPI 需要的另一個重要功能是資料驗證，確保資料在特定條件下有效。例如，某個欄位必須是 `int`，而不是隨便的字串。這對於輸入資料特別有用。\n\n沒有資料驗證系統的話，你就得在程式碼中手動逐一檢查。\n\n這些功能正是 Marshmallow 所要提供的。它是很棒的函式庫，我之前也大量使用。\n\n但它誕生於 Python 型別提示出現之前。因此，為了定義每個 <dfn title=\"資料應如何組成的定義\">結構（schema）</dfn>，你需要使用 Marshmallow 提供的特定工具與類別。\n\n/// check | 啟發 **FastAPI**\n\n用程式碼定義能自動提供資料型別與驗證的「schemas」。\n\n///\n\n### [Webargs](https://webargs.readthedocs.io/en/latest/) { #webargs }\n\nAPI 所需的另一項大功能，是從傳入請求中<dfn title=\"讀取並轉換為 Python 資料\">解析</dfn>資料。\n\nWebargs 是在多個框架（包含 Flask）之上提供該功能的工具。\n\n它底層使用 Marshmallow 來做資料驗證，且由同一群開發者建立。\n\n它是一個很棒的工具，在有 **FastAPI** 之前我也經常使用。\n\n/// info\n\nWebargs 由與 Marshmallow 相同的開發者創建。\n\n///\n\n/// check | 啟發 **FastAPI**\n\n自動驗證傳入請求資料。\n\n///\n\n### [APISpec](https://apispec.readthedocs.io/en/stable/) { #apispec }\n\nMarshmallow 與 Webargs 以外掛提供驗證、解析與序列化。\n\n但文件仍然缺失，於是 APISpec 出現了。\n\n它是多個框架的外掛（Starlette 也有對應外掛）。\n\n它的作法是：你在處理路由的每個函式的 docstring 中，用 YAML 格式撰寫結構定義。\n\n然後它會產生 OpenAPI schemas。\n\n在 Flask、Starlette、Responder 等框架中都是這樣運作。\n\n但這又帶來一個問題：在 Python 字串中（大型 YAML）加入一段微語法。\n\n編輯器幫不上太多忙。而且如果我們修改了參數或 Marshmallow 的 schemas 卻忘了同步修改 YAML docstring，產生的結構就會過時。\n\n/// info\n\nAPISpec 由與 Marshmallow 相同的開發者創建。\n\n///\n\n/// check | 啟發 **FastAPI**\n\n支援 API 的開放標準 OpenAPI。\n\n///\n\n### [Flask-apispec](https://flask-apispec.readthedocs.io/en/latest/) { #flask-apispec }\n\n這是一個 Flask 外掛，把 Webargs、Marshmallow 與 APISpec 串在一起。\n\n它使用 Webargs 與 Marshmallow 的資訊，透過 APISpec 自動產生 OpenAPI 結構。\n\n它是個很棒但被低估的工具。它理應比許多 Flask 外掛更受歡迎，可能因為它的文件過於簡潔與抽象。\n\n這解決了在 Python 文件字串中撰寫 YAML（另一種語法）的问题。\n\n在打造 **FastAPI** 前，我最喜歡的後端技術組合就是 Flask、Flask-apispec、Marshmallow 與 Webargs。\n\n使用它促成了數個 Flask 全端（full-stack）產生器。這些是我（以及若干外部團隊）至今主要使用的技術組合：\n\n* [https://github.com/tiangolo/full-stack](https://github.com/tiangolo/full-stack)\n* [https://github.com/tiangolo/full-stack-flask-couchbase](https://github.com/tiangolo/full-stack-flask-couchbase)\n* [https://github.com/tiangolo/full-stack-flask-couchdb](https://github.com/tiangolo/full-stack-flask-couchdb)\n\n而這些全端產生器，也成為了 [**FastAPI** 專案產生器](project-generation.md) 的基礎。\n\n/// info\n\nFlask-apispec 由與 Marshmallow 相同的開發者創建。\n\n///\n\n/// check | 啟發 **FastAPI**\n\n從定義序列化與驗證的相同程式碼，自動產生 OpenAPI 結構（schema）。\n\n///\n\n### [NestJS](https://nestjs.com/)（與 [Angular](https://angular.io/)） { #nestjs-and-angular }\n\n這甚至不是 Python。NestJS 是受 Angular 啟發的 JavaScript（TypeScript）NodeJS 框架。\n\n它達成的效果與 Flask-apispec 能做的有點相似。\n\n它有一套受 Angular 2 啟發的整合式相依性注入（Dependency Injection）系統。需要預先註冊「可注入」元件（就像我所知的其他相依性注入系統一樣），因此會增加冗長與重複程式碼。\n\n由於參數以 TypeScript 型別描述（與 Python 型別提示相似），編輯器支援相當不錯。\n\n但因為 TypeScript 的型別在編譯成 JavaScript 後不會被保留，它無法僅靠型別同時定義驗證、序列化與文件。由於這點以及部分設計決定，若要取得驗證、序列化與自動結構產生，就需要在許多地方加上裝飾器，因此會相當冗長。\n\n它無法很好地處理巢狀模型。若請求的 JSON 主體中有內層欄位，且這些內層欄位又是巢狀 JSON 物件，就無法被妥善地文件化與驗證。\n\n/// check | 啟發 **FastAPI**\n\n使用 Python 型別以獲得優秀的編輯器支援。\n\n提供強大的相依性注入系統，並想辦法將重複程式碼降到最低。\n\n///\n\n### [Sanic](https://sanic.readthedocs.io/en/latest/) { #sanic }\n\n它是最早基於 `asyncio` 的極高速 Python 框架之一，並做得很像 Flask。\n\n/// note | 技術細節\n\n它使用 [`uvloop`](https://github.com/MagicStack/uvloop) 取代預設的 Python `asyncio` 事件圈。這也是它如此之快的原因。\n\n它明顯啟發了 Uvicorn 與 Starlette，而在公開的基準測試中，它們目前比 Sanic 更快。\n\n///\n\n/// check | 啟發 **FastAPI**\n\n想辦法達到瘋狂的效能。\n\n這就是為什麼 **FastAPI** 建立於 Starlette 之上，因為它是可用的最快框架（由第三方評測）。\n\n///\n\n### [Falcon](https://falconframework.org/) { #falcon }\n\nFalcon 是另一個高效能 Python 框架，設計上極簡，並作為其他框架（如 Hug）的基礎。\n\n它設計為函式接收兩個參數，一個是「request」，一個是「response」。然後你從 request「讀取」資料、往 response「寫入」資料。由於這種設計，無法使用標準的 Python 型別提示，直接以函式參數宣告請求參數與主體。\n\n因此，資料驗證、序列化與文件必須以程式碼手動完成，無法自動化。或者需在 Falcon 之上實作另一層框架（如 Hug）。其他受 Falcon 設計啟發的框架也有同樣的區別：將 request 與 response 物件作為參數。\n\n/// check | 啟發 **FastAPI**\n\n設法取得優秀的效能。\n\n連同 Hug（Hug 建立於 Falcon 之上）一起，也啟發 **FastAPI** 在函式中宣告一個 `response` 參數。\n\n不過在 FastAPI 中它是可選的，主要用來設定標頭、Cookie 與替代狀態碼。\n\n///\n\n### [Molten](https://moltenframework.com/) { #molten }\n\n我在 **FastAPI** 打造的早期發現了 Molten。它有一些相當類似的想法：\n\n* 基於 Python 型別提示。\n* 從這些型別取得驗證與文件。\n* 相依性注入系統。\n\n它沒有使用像 Pydantic 這樣的第三方資料驗證、序列化與文件庫，而是有自己的。因此，這些資料型別定義較不容易重複使用。\n\n它需要更為冗長的設定。而且因為它基於 WSGI（而非 ASGI），並未設計來享受如 Uvicorn、Starlette、Sanic 等工具所提供的高效能。\n\n其相依性注入系統需要預先註冊依賴，並且依據宣告的型別來解析依賴。因此，無法宣告多個能提供相同型別的「元件」。\n\n路由需要在單一地方宣告，使用在其他地方宣告的函式（而不是用可以直接放在端點處理函式上方的裝飾器）。這更接近 Django 的作法，而不是 Flask（與 Starlette）的作法。它在程式碼中分離了其實相當緊密耦合的事物。\n\n/// check | 啟發 **FastAPI**\n\n用模型屬性的「預設值」來定義資料型別的額外驗證。這提升了編輯器支援，而這在當時的 Pydantic 還不支援。\n\n這實際上也啟發了 Pydantic 的部分更新，以支援相同的驗證宣告風格（這些功能現在已在 Pydantic 中可用）。\n\n///\n\n### [Hug](https://github.com/hugapi/hug) { #hug }\n\nHug 是最早使用 Python 型別提示來宣告 API 參數型別的框架之一。這是個很棒的點子，也啟發了其他工具。\n\n它在宣告中使用自訂型別而非標準 Python 型別，但仍然是巨大的一步。\n\n它也是最早能以 JSON 產出自訂結構、描述整個 API 的框架之一。\n\n它不是基於 OpenAPI 與 JSON Schema 等標準。因此，與其他工具（如 Swagger UI）的整合並不直覺。但它仍是一個非常創新的想法。\n\n它有個有趣、少見的功能：同一個框架可同時建立 API 與 CLI。\n\n由於它基於同步 Python 網頁框架的舊標準（WSGI），無法處理 WebSocket 與其他功能，儘管效能仍然很高。\n\n/// info\n\nHug 由 Timothy Crosley 創建，他同時也是 [`isort`](https://github.com/timothycrosley/isort) 的作者，一個自動排序 Python 匯入的好工具。\n\n///\n\n/// check | 啟發 **FastAPI** 的想法\n\nHug 啟發了 APIStar 的部分設計，也是我覺得最有前景的工具之一，與 APIStar 並列。\n\nHug 啟發 **FastAPI** 使用 Python 型別提示宣告參數，並自動產生定義 API 的結構。\n\nHug 啟發 **FastAPI** 在函式中宣告 `response` 參數以設定標頭與 Cookie。\n\n///\n\n### [APIStar](https://github.com/encode/apistar) (<= 0.5) { #apistar-0-5 }\n\n在決定打造 **FastAPI** 之前，我找到了 **APIStar** 伺服器。它幾乎具備我所尋找的一切，而且設計很出色。\n\n它是我見過最早使用 Python 型別提示來宣告參數與請求的框架實作之一（早於 NestJS 與 Molten）。我與 Hug 幾乎在同時間發現它。不過 APIStar 使用的是 OpenAPI 標準。\n\n它基於相同的型別提示，在多處自動進行資料驗證、資料序列化與 OpenAPI 結構產生。\n\n主體結構（body schema）的定義並未使用像 Pydantic 那樣的 Python 型別提示，更像 Marshmallow，因此編輯器支援沒有那麼好，但整體而言，APIStar 是當時最好的選擇。\n\n它在當時的效能評測中名列前茅（僅被 Starlette 超越）。\n\n一開始它沒有自動 API 文件的網頁 UI，但我知道我可以替它加上 Swagger UI。\n\n它有相依性注入系統。需要預先註冊元件，與上面提到的其他工具相同。不過這仍是很棒的功能。\n\n我從未能在完整專案中使用它，因為它沒有安全性整合，所以無法取代我用 Flask-apispec 全端產生器所擁有的全部功能。我曾把新增該功能的 pull request 放在待辦清單中。\n\n但之後，專案的重心改變了。\n\n它不再是 API 網頁框架，因為作者需要專注於 Starlette。\n\n現在的 APIStar 是一套用於驗證 OpenAPI 規格的工具，不是網頁框架。\n\n/// info\n\nAPIStar 由 Tom Christie 創建。他也創建了：\n\n* Django REST Framework\n* Starlette（**FastAPI** 建立於其上）\n* Uvicorn（Starlette 與 **FastAPI** 使用）\n\n///\n\n/// check | 啟發 **FastAPI**\n\n存在。\n\n用相同的 Python 型別同時宣告多件事（資料驗證、序列化與文件），並同時提供出色的編輯器支援，這是一個極好的點子。\n\n在長時間尋找並測試多種不同替代方案後，APIStar 是最好的可用選擇。\n\n當 APIStar 不再作為伺服器存在，而 Starlette 誕生並成為更好的基礎時，這成為打造 **FastAPI** 的最後一個靈感。\n\n我將 **FastAPI** 視為 APIStar 的「精神繼承者」，同時基於所有這些先前工具的經驗，改進並擴增了功能、型別系統與其他部分。\n\n///\n\n## **FastAPI** 所採用的工具 { #used-by-fastapi }\n\n### [Pydantic](https://docs.pydantic.dev/) { #pydantic }\n\nPydantic 是基於 Python 型別提示，定義資料驗證、序列化與文件（使用 JSON Schema）的函式庫。\n\n這讓它非常直覺。\n\n它可與 Marshmallow 相提並論。儘管在效能測試中它比 Marshmallow 更快。而且因為它基於相同的 Python 型別提示，編輯器支援也很出色。\n\n/// check | **FastAPI** 用於\n\n處理所有資料驗證、資料序列化與自動模型文件（基於 JSON Schema）。\n\n**FastAPI** 接著會把這些 JSON Schema 資料放入 OpenAPI 中，此外還有其他許多功能。\n\n///\n\n### [Starlette](https://www.starlette.dev/) { #starlette }\n\nStarlette 是一個輕量的 <dfn title=\"用於構建非同步 Python 網頁應用的新標準\">ASGI</dfn> 框架／工具集，非常適合用來建構高效能的 asyncio 服務。\n\n它非常簡單直觀。設計上易於擴充，且元件化。\n\n它具備：\n\n* 令人印象深刻的效能。\n* WebSocket 支援。\n* 行程內（in-process）背景任務。\n* 啟動與關閉事件。\n* 建立在 HTTPX 上的測試用戶端。\n* CORS、GZip、靜態檔案、串流回應。\n* Session 與 Cookie 支援。\n* 100% 測試涵蓋率。\n* 100% 型別註解的程式碼庫。\n* 幾乎沒有硬性相依。\n\nStarlette 目前是測試中最快的 Python 框架。僅次於 Uvicorn（它不是框架，而是伺服器）。\n\nStarlette 提供所有網頁微框架的基礎功能。\n\n但它不提供自動的資料驗證、序列化或文件。\n\n這正是 **FastAPI** 在其上方加入的主要功能之一，且全部基於 Python 型別提示（使用 Pydantic）。此外還有相依性注入系統、安全性工具、OpenAPI 結構產生等。\n\n/// note | 技術細節\n\nASGI 是由 Django 核心團隊成員正在開發的新「標準」。它尚未成為「Python 標準」（PEP），但他們正著手進行中。\n\n儘管如此，它已被多個工具作為「標準」採用。這大幅提升了互通性，例如你可以把 Uvicorn 換成其他 ASGI 伺服器（如 Daphne 或 Hypercorn），或加入相容 ASGI 的工具，如 `python-socketio`。\n\n///\n\n/// check | **FastAPI** 用於\n\n處理所有核心網頁部分，並在其上加上功能。\n\n`FastAPI` 這個類別本身直接繼承自 `Starlette` 類別。\n\n因此，凡是你能用 Starlette 做的事，你都能直接用 **FastAPI** 完成，因為它基本上就是加強版的 Starlette。\n\n///\n\n### [Uvicorn](https://www.uvicorn.dev/) { #uvicorn }\n\nUvicorn 是基於 uvloop 與 httptools 的極速 ASGI 伺服器。\n\n它不是網頁框架，而是伺服器。例如，它不提供依據路徑路由的工具。這是像 Starlette（或 **FastAPI**）這樣的框架在其上方提供的功能。\n\n它是 Starlette 與 **FastAPI** 推薦使用的伺服器。\n\n/// check | **FastAPI** 建議用作\n\n執行 **FastAPI** 應用的主要網頁伺服器。\n\n你也可以使用 `--workers` 命令列選項，取得非同步的多製程伺服器。\n\n更多細節請見[部署](deployment/index.md)章節。\n\n///\n\n## 效能與速度 { #benchmarks-and-speed }\n\n想了解、比較並看出 Uvicorn、Starlette 與 FastAPI 之間的差異，請參考[效能評測](benchmarks.md)。\n"
  },
  {
    "path": "docs/zh-hant/docs/async.md",
    "content": "# 並行與 async / await { #concurrency-and-async-await }\n\n有關*路徑操作函式*的 `async def` 語法的細節與非同步 (asynchronous) 程式碼、並行 (concurrency) 與平行 (parallelism) 的一些背景知識。\n\n## 趕時間嗎? { #in-a-hurry }\n\n<abbr title=\"too long; didn't read - 太長不看\"><strong>TL;DR:</strong></abbr>\n\n如果你正在使用要求你以 `await` 語法呼叫的第三方函式庫，例如：\n\n```Python\nresults = await some_library()\n```\n\n然後，使用 `async def` 宣告你的*路徑操作函式*：\n\n\n```Python hl_lines=\"2\"\n@app.get('/')\nasync def read_results():\n    results = await some_library()\n    return results\n```\n\n/// note | 注意\n\n你只能在 `async def` 建立的函式內使用 `await`。\n\n///\n\n---\n\n如果你使用的是第三方函式庫並且它需要與某些外部資源（例如資料庫、API、檔案系統等）進行通訊，但不支援 `await`（目前大多數資料庫函式庫都是這樣），在這種情況下，你可以像平常一樣使用 `def` 宣告*路徑操作函式*，如下所示：\n\n```Python hl_lines=\"2\"\n@app.get('/')\ndef results():\n    results = some_library()\n    return results\n```\n\n---\n\n如果你的應用程式不需要與外部資源進行任何通訊並等待其回應，請使用 `async def`，即使內部不需要使用 `await` 也可以。\n\n---\n\n如果你不確定該用哪個，直接用 `def` 就好。\n\n---\n\n**注意**：你可以在*路徑操作函式*中混合使用 `def` 和 `async def` ，並使用最適合你需求的方式來定義每個函式。FastAPI 會幫你做正確的處理。\n\n無論如何，在上述哪種情況下，FastAPI 仍將以非同步方式運行，並且速度非常快。\n\n但透過遵循上述步驟，它將能進行一些效能最佳化。\n\n## 技術細節 { #technical-details }\n\n現代版本的 Python 支援使用 **「協程」** 的 **`async` 和 `await`** 語法來寫 **「非同步程式碼」**。\n\n接下來我們逐一介紹：\n\n* **非同步程式碼**\n* **`async` 和 `await`**\n* **協程**\n\n## 非同步程式碼 { #asynchronous-code }\n\n非同步程式碼僅意味著程式語言 💬 有辦法告訴電腦/程式 🤖 在程式碼中的某個點，它 🤖 需要等待某些事情完成。讓我們假設這些事情被稱為「慢速檔案」📝。\n\n因此，在等待「慢速檔案」📝 完成的這段時間，電腦可以去處理一些其他工作。\n\n接著程式 🤖 會在有空檔時回來查看是否有等待的工作已經完成，並執行必要的後續操作。\n\n接下來，它 🤖 完成第一個工作（例如我們的「慢速檔案」📝）並繼續執行相關的所有操作。\n這個「等待其他事情」通常指的是一些相對較慢的（與處理器和 RAM 記憶體的速度相比）的 <abbr title=\"Input and Output - 輸入與輸出\">I/O</abbr> 操作，比如說：\n\n* 透過網路傳送來自用戶端的資料\n* 從網路接收來自用戶端的資料\n* 從磁碟讀取檔案內容\n* 將內容寫入磁碟\n* 遠端 API 操作\n* 資料庫操作\n* 資料庫查詢\n* 等等\n\n由於大部分的執行時間都消耗在等待 <abbr title=\"Input and Output - 輸入與輸出\">I/O</abbr> 操作上，因此這些操作被稱為 \"I/O 密集型\" 操作。\n\n之所以稱為「非同步」，是因為電腦/程式不需要與那些耗時的任務「同步」，等待任務完成的精確時間，然後才能取得結果並繼續工作。\n\n相反地，非同步系統在任務完成後，可以讓任務稍微等一下（幾微秒），等待電腦/程式完成手頭上的其他工作，然後再回來取得結果繼續進行。\n\n相對於「非同步」（asynchronous），「同步」（synchronous）也常被稱作「順序性」（sequential），因為電腦/程式會依序執行所有步驟，即便這些步驟涉及等待，才會切換到其他任務。\n\n### 並行與漢堡 { #concurrency-and-burgers }\n\n上述非同步程式碼的概念有時也被稱為「並行」，它不同於「平行」。\n\n並行和平行都與 \"不同的事情或多或少同時發生\" 有關。\n\n但並行和平行之間的細節是完全不同的。\n\n為了理解差異，請想像以下有關漢堡的故事：\n\n### 並行漢堡 { #concurrent-burgers }\n\n你和你的戀人去速食店，排隊等候時，收銀員正在幫排在你前面的人點餐。😍\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-01.png\" class=\"illustration\">\n\n輪到你了，你給你與你的戀人點了兩個豪華漢堡。🍔🍔\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-02.png\" class=\"illustration\">\n\n收銀員通知廚房準備你的漢堡（儘管他們還在為前面其他顧客準備食物）。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-03.png\" class=\"illustration\">\n\n之後你完成付款。💸\n\n收銀員給你一個號碼牌。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-04.png\" class=\"illustration\">\n\n在等待漢堡的同時，你可以與戀人選一張桌子，然後坐下來聊很長一段時間（因為漢堡十分豪華，準備特別費工。）\n\n這段時間，你還能欣賞你的戀人有多麼的可愛、聰明與迷人。✨😍✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-05.png\" class=\"illustration\">\n\n當你和戀人邊聊天邊等待時，你會不時地查看櫃檯上的顯示的號碼，確認是否已經輪到你了。\n\n然後在某個時刻，終於輪到你了。你走到櫃檯，拿了漢堡，然後回到桌子上。\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-06.png\" class=\"illustration\">\n\n你和戀人享用這頓大餐，整個過程十分開心✨\n\n<img src=\"/img/async/concurrent-burgers/concurrent-burgers-07.png\" class=\"illustration\">\n\n/// info\n\n漂亮的插畫來自 [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot)。 🎨\n\n///\n\n---\n\n想像你是故事中的電腦或程式 🤖。\n\n當你排隊時，你在放空😴，等待輪到你，沒有做任何「生產性」的事情。但這沒關係，因為收銀員只是接單（而不是準備食物），所以排隊速度很快。\n\n然後，當輪到你時，你開始做真正「有生產力」的工作，處理菜單，決定你想要什麼，替戀人選擇餐點，付款，確認你給了正確的帳單或信用卡，檢查你是否被正確收費，確認訂單中的項目是否正確等等。\n\n但是，即使你還沒有拿到漢堡，你與收銀員的工作已經「暫停」了 ⏸，因為你必須等待 🕙 漢堡準備好。\n\n但當你離開櫃檯，坐到桌子旁，拿著屬於你的號碼等待時，你可以把注意力 🔀 轉移到戀人身上，並開始「工作」⏯ 🤓——也就是和戀人調情 😍。這時你又開始做一些非常「有生產力」的事情。\n\n接著，收銀員 💁 將你的號碼顯示在櫃檯螢幕上，並告訴你「漢堡已經做好了」。但你不會瘋狂地立刻跳起來，因為顯示的號碼變成了你的。你知道沒有人會搶走你的漢堡，因為你有自己的號碼，他們也有他們的號碼。\n\n所以你會等戀人講完故事（完成當前的工作 ⏯/正在進行的任務 🤓），然後微笑著溫柔地說你要去拿漢堡了 ⏸。\n\n然後你走向櫃檯 🔀，回到已經完成的最初任務 ⏯，拿起漢堡，說聲謝謝，並帶回桌上。這就結束了與櫃檯的互動步驟/任務 ⏹，接下來會產生一個新的任務，「吃漢堡」 🔀 ⏯，而先前的「拿漢堡」任務已經完成了 ⏹。\n\n### 平行漢堡 { #parallel-burgers }\n\n現在，讓我們來想像這裡不是「並行漢堡」，而是「平行漢堡」。\n\n你和戀人一起去吃平行的速食餐。\n\n你們站在隊伍中，前面有幾位（假設有 8 位）既是收銀員又是廚師的員工，他們同時接單並準備餐點。\n\n所有排在你前面的人都在等著他們的漢堡準備好後才會離開櫃檯，因為每位收銀員在接完單後，馬上會去準備漢堡，然後才回來處理下一個訂單。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-01.png\" class=\"illustration\">\n\n終於輪到你了，你為你和你的戀人點了兩個非常豪華的漢堡。\n\n你付款了 💸。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-02.png\" class=\"illustration\">\n\n收銀員走進廚房準備食物。\n\n你站在櫃檯前等待 🕙，以免其他人先拿走你的漢堡，因為這裡沒有號碼牌系統。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-03.png\" class=\"illustration\">\n\n由於你和戀人都忙著不讓別人搶走你的漢堡，等漢堡準備好時，你根本無法專心和戀人互動。😞\n\n這是「同步」(synchronous)工作，你和收銀員/廚師 👨‍🍳 是「同步化」的。你必須等到 🕙 收銀員/廚師 👨‍🍳 完成漢堡並交給你的那一刻，否則別人可能會拿走你的餐點。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-04.png\" class=\"illustration\">\n\n最終，經過長時間的等待 🕙，收銀員/廚師 👨‍🍳 拿著漢堡回來了。\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-05.png\" class=\"illustration\">\n\n你拿著漢堡，和你的戀人回到餐桌。\n\n你們僅僅是吃完漢堡，然後就結束了。⏹\n\n<img src=\"/img/async/parallel-burgers/parallel-burgers-06.png\" class=\"illustration\">\n\n整個過程中沒有太多的談情說愛，因為大部分時間 🕙 都花在櫃檯前等待。😞\n\n/// info\n\n漂亮的插畫來自 [Ketrina Thompson](https://www.instagram.com/ketrinadrawsalot)。 🎨\n\n///\n\n---\n\n在這個平行漢堡的情境下，你是一個程式 🤖 且有兩個處理器（你和戀人），兩者都在等待 🕙 並專注於等待櫃檯上的餐點 🕙，等待的時間非常長。\n\n這家速食店有 8 個處理器（收銀員/廚師）。而並行漢堡店可能只有 2 個處理器（一位收銀員和一位廚師）。\n\n儘管如此，最終的體驗並不是最理想的。😞\n\n---\n\n這是與漢堡類似的故事。🍔\n\n一個更「現實」的例子，想像一間銀行。\n\n直到最近，大多數銀行都有多位出納員 👨‍💼👨‍💼👨‍💼👨‍💼，以及一條長長的隊伍 🕙🕙🕙🕙🕙🕙🕙🕙。\n\n所有的出納員都在一個接一個地滿足每位客戶的所有需求 👨‍💼⏯。\n\n你必須長時間排隊 🕙，不然就會失去機會。\n\n所以，你不會想帶你的戀人 😍 一起去銀行辦事 🏦。\n\n### 漢堡結論 { #burger-conclusion }\n\n在「和戀人一起吃速食漢堡」的這個場景中，由於有大量的等待 🕙，使用並行系統 ⏸🔀⏯ 更有意義。\n\n這也是大多數 Web 應用的情況。\n\n許多用戶正在使用你的應用程式，而你的伺服器則在等待 🕙 這些用戶不那麼穩定的網路來傳送請求。\n\n接著，再次等待 🕙 回應。\n\n這種「等待」 🕙 通常以微秒來衡量，但累加起來，最終還是花費了很多等待時間。\n\n這就是為什麼對於 Web API 來說，使用非同步程式碼 ⏸🔀⏯ 是非常有意味的。\n\n這種類型的非同步性正是 NodeJS 成功的原因（儘管 NodeJS 不是平行的），這也是 Go 語言作為程式語言的一個強大優勢。\n\n這與 **FastAPI** 所能提供的性能水平相同。\n\n你可以同時利用並行性和平行性，進一步提升效能，這比大多數已測試的 NodeJS 框架都更快，並且與 Go 語言相當，而 Go 是一種更接近 C 的編譯語言（[感謝 Starlette](https://www.techempower.com/benchmarks/#section=data-r17&hw=ph&test=query&l=zijmkf-1)）。\n\n### 並行比平行更好嗎？ { #is-concurrency-better-than-parallelism }\n\n不是的！這不是故事的本意。\n\n並行與平行不同。並行在某些 **特定** 的需要大量等待的情境下表現更好。正因如此，並行在 Web 應用程式開發中通常比平行更有優勢。但並不是所有情境都如此。\n\n因此，為了平衡報導，想像下面這個短故事\n\n> 你需要打掃一間又大又髒的房子。\n\n*是的，這就是全部的故事。*\n\n---\n\n這裡沒有任何需要等待 🕙 的地方，只需要在房子的多個地方進行大量的工作。\n\n你可以像漢堡的例子那樣輪流進行，先打掃客廳，再打掃廚房，但由於你不需要等待 🕙 任何事情，只需要持續地打掃，輪流並不會影響任何結果。\n\n無論輪流執行與否（並行），你都需要相同的工時完成任務，同時需要執行相同工作量。\n\n但是，在這種情境下，如果你可以邀請8位前收銀員/廚師（現在是清潔工）來幫忙，每個人（加上你）負責房子的某個區域，這樣你就可以 **平行** 地更快完成工作。\n\n在這個場景中，每個清潔工（包括你）都是一個處理器，完成工作的一部分。\n\n由於大多數的執行時間都花在實際的工作上（而不是等待），而電腦中的工作由 <abbr title=\"Central Processing Unit - 中央處理器\">CPU</abbr> 完成，因此這些問題被稱為「CPU 密集型」。\n\n---\n\n常見的 CPU 密集型操作範例包括那些需要進行複雜數學計算的任務。\n\n例如：\n\n* **音訊**或**圖像處理**；\n* **電腦視覺**：一張圖片由數百萬個像素組成，每個像素有 3 個值/顏色，處理這些像素通常需要同時進行大量計算；\n* **機器學習**: 通常需要大量的「矩陣」和「向量」運算。想像一個包含數字的巨大電子表格，並所有的數字同時相乘;\n* **深度學習**: 這是機器學習的子領域，同樣適用。只不過這不僅僅是一張數字表格，而是大量的數據集合，並且在很多情況下，你會使用特殊的處理器來構建或使用這些模型。\n\n### 並行 + 平行: Web + 機器學習 { #concurrency-parallelism-web-machine-learning }\n\n使用 **FastAPI**，你可以利用並行的優勢，這在 Web 開發中非常常見（這也是 NodeJS 的最大吸引力）。\n\n但你也可以利用平行與多行程 (multiprocessing)（讓多個行程同時運行） 的優勢來處理機器學習系統中的 **CPU 密集型**工作。\n\n這一點，再加上 Python 是 **資料科學**、機器學習，尤其是深度學習的主要語言，讓 **FastAPI** 成為資料科學/機器學習 Web API 和應用程式（以及許多其他應用程式）的絕佳選擇。\n\n想了解如何在生產環境中實現這種平行性，請參見 [部屬](deployment/index.md)。\n\n## `async` 和 `await` { #async-and-await }\n\n現代 Python 版本提供一種非常直觀的方式定義非同步程式碼。這使得它看起來就像正常的「順序」程式碼，並在適當的時機替你「等待」。\n\n當某個操作需要等待才能回傳結果，並且支援這些新的 Python 特性時，你可以像這樣編寫程式碼：\n\n```Python\nburgers = await get_burgers(2)\n```\n\n這裡的關鍵是 `await`。它告訴 Python 必須等待 ⏸ `get_burgers(2)` 完成它的工作 🕙， 然後將結果儲存在 `burgers` 中。如此，Python 就可以在此期間去處理其他事情 🔀 ⏯ （例如接收另一個請求）。\n\n要讓 `await` 運作，它必須位於支持非同步功能的函式內。為此，只需使用 `async def` 宣告函式：\n\n```Python hl_lines=\"1\"\nasync def get_burgers(number: int):\n    # Do some asynchronous stuff to create the burgers\n    return burgers\n```\n\n...而不是 `def`:\n\n```Python hl_lines=\"2\"\n# This is not asynchronous\ndef get_sequential_burgers(number: int):\n    # Do some sequential stuff to create the burgers\n    return burgers\n```\n\n使用 `async def`，Python 知道在該函式內需要注意 `await`，並且它可以「暫停」 ⏸ 執行該函式，然後執行其他任務 🔀 後回來。\n\n當你想要呼叫 `async def` 函式時，必須使用「await」。因此，這樣寫將無法運行：\n\n```Python\n# This won't work, because get_burgers was defined with: async def\nburgers = get_burgers(2)\n```\n\n---\n\n如果你正在使用某個函式庫，它告訴你可以使用 `await` 呼叫它，那麼你需要用 `async def` 定義*路徑操作函式*，如：\n\n```Python hl_lines=\"2-3\"\n@app.get('/burgers')\nasync def read_burgers():\n    burgers = await get_burgers(2)\n    return burgers\n```\n\n### 更多技術細節 { #more-technical-details }\n\n你可能已經注意到，`await` 只能在 `async def` 定義的函式內使用。\n\n但同時，使用 `async def` 定義的函式本身也必須被「等待」。所以，帶有 `async def` 的函式只能在其他使用 `async def` 定義的函式內呼叫。\n\n那麼，這就像「先有雞還是先有蛋」的問題，要如何呼叫第一個 `async` 函式呢？\n\n如果你使用 FastAPI，無需擔心這個問題，因為「第一個」函式將是你的*路徑操作函式*，FastAPI 會知道如何正確處理這個問題。\n\n但如果你想在沒有 FastAPI 的情況下使用 `async` / `await`，你也可以這樣做。\n\n### 編寫自己的非同步程式碼 { #write-your-own-async-code }\n\nStarlette（和 **FastAPI**）是基於 [AnyIO](https://anyio.readthedocs.io/en/stable/) 實作的，這使得它們與 Python 標準函式庫 [asyncio](https://docs.python.org/3/library/asyncio-task.html) 和 [Trio](https://trio.readthedocs.io/en/stable/) 相容。\n\n特別是，你可以直接使用 [AnyIO](https://anyio.readthedocs.io/en/stable/) 來處理更複雜的並行使用案例，這些案例需要你在自己的程式碼中使用更高階的模式。\n\n即使你不使用 **FastAPI**，你也可以使用 [AnyIO](https://anyio.readthedocs.io/en/stable/) 來撰寫自己的非同步應用程式，並獲得高相容性及一些好處（例如「結構化並行」）。\n\n我另外在 AnyIO 之上做了一個薄封裝的函式庫，稍微改進型別註解以獲得更好的**自動補全**、**即時錯誤**等。同時它也提供友善的介紹與教學，幫助你**理解**並撰寫**自己的非同步程式碼**：[Asyncer](https://asyncer.tiangolo.com/)。當你需要**將非同步程式碼與一般**（阻塞/同步）**程式碼整合**時，它特別實用。\n\n### 其他形式的非同步程式碼 { #other-forms-of-asynchronous-code }\n\n使用 `async` 和 `await` 的風格在語言中相對較新。\n\n但它使處理非同步程式碼變得更加容易。\n\n相同的語法（或幾乎相同的語法）最近也被包含在現代 JavaScript（無論是瀏覽器還是 NodeJS）中。\n\n但在此之前，處理非同步程式碼要更加複雜和困難。\n\n在較舊的 Python 版本中，你可能會使用多執行緒或 [Gevent](https://www.gevent.org/)。但這些程式碼要更難以理解、調試和思考。\n\n在較舊的 NodeJS / 瀏覽器 JavaScript 中，你會使用「回呼」，這可能會導致“回呼地獄”。\n\n## 協程 { #coroutines }\n\n「協程」只是 `async def` 函式所回傳的非常特殊的事物名稱。Python 知道它是一個類似函式的東西，可以啟動它，並且在某個時刻它會結束，但它也可能在內部暫停 ⏸，只要遇到 `await`。\n\n這種使用 `async` 和 `await` 的非同步程式碼功能通常被概括為「協程」。這與 Go 語言的主要特性「Goroutines」相似。\n\n## 結論 { #conclusion }\n\n讓我們再次回顧之前的句子：\n\n> 現代版本的 Python 支持使用 **\"協程\"** 的 **`async` 和 `await`** 語法來寫 **\"非同步程式碼\"**。\n\n現在應該能明白其含意了。✨\n\n這些就是驅動 FastAPI（透過 Starlette）運作的原理，也讓它擁有如此驚人的效能。\n\n## 非常技術性的細節 { #very-technical-details }\n\n/// warning\n\n你大概可以跳過這段。\n\n這裡是有關 FastAPI 內部技術細節。\n\n如果你有相當多的技術背景（例如協程、執行緒、阻塞等），並且對 FastAPI 如何處理 `async def` 與常規 `def` 感到好奇，請繼續閱讀。\n\n///\n\n### 路徑操作函式 { #path-operation-functions }\n\n當你使用 `def` 而不是 `async def` 宣告*路徑操作函式*時，該函式會在外部的執行緒池（threadpool）中執行，然後等待結果，而不是直接呼叫（因為這樣會阻塞伺服器）。\n\n如果你來自於其他不以這種方式運作的非同步框架，而且你習慣於使用普通的 `def` 定義僅進行簡單計算的*路徑操作函式*，目的是獲得微小的性能增益（大約 100 奈秒），請注意，在 FastAPI 中，效果會完全相反。在這些情況下，最好使用 `async def`，除非你的*路徑操作函式*執行阻塞的 <abbr title=\"Input/Output - 輸入/輸出: 磁碟讀寫或網路通訊。\">I/O</abbr> 的程式碼。\n\n不過，在這兩種情況下，**FastAPI** [仍然很快](index.md#performance)，至少與你之前的框架相當（或者更快）。\n\n### 依賴項(Dependencies) { #dependencies }\n\n同樣適用於[依賴項](tutorial/dependencies/index.md)。如果依賴項是一個標準的 `def` 函式，而不是 `async def`，那麼它在外部的執行緒池被運行。\n\n### 子依賴項 { #sub-dependencies }\n\n你可以擁有多個相互依賴的依賴項和[子依賴項](tutorial/dependencies/sub-dependencies.md)（作為函式定義的參數），其中一些可能是用 `async def` 宣告，也可能是用 `def` 宣告。它們仍然可以正常運作，用 `def` 定義的那些將會在外部的執行緒中呼叫（來自執行緒池），而不是被「等待」。\n\n### 其他輔助函式 { #other-utility-functions }\n\n你可以直接呼叫任何使用 `def` 或 `async def` 建立的其他輔助函式，FastAPI 不會影響你呼叫它們的方式。\n\n這與 FastAPI 為你呼叫*路徑操作函式*和依賴項的邏輯有所不同。\n\n如果你的輔助函式是用 `def` 宣告的，它將會被直接呼叫（按照你在程式碼中撰寫的方式），而不是在執行緒池中。如果該函式是用 `async def` 宣告，那麼你在呼叫時應該使用 `await` 等待其結果。\n\n---\n\n再一次強調，這些都是非常技術性的細節，如果你特地在尋找這些資訊，這些內容可能會對你有幫助。\n\n否則，只需遵循上面提到的指引即可：<a href=\"#in-a-hurry\">趕時間嗎?</a>。\n"
  },
  {
    "path": "docs/zh-hant/docs/benchmarks.md",
    "content": "# 基準測試 { #benchmarks }\n\n由第三方機構 TechEmpower 的基準測試表明在 Uvicorn 下運行的 **FastAPI** 應用程式是 [最快的 Python 可用框架之一](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7)，僅次於 Starlette 和 Uvicorn 本身（於 FastAPI 內部使用）。\n\n但是在查看基準得分和對比時，請注意以下幾點。\n\n## 基準測試和速度 { #benchmarks-and-speed }\n\n當你查看基準測試時，常見到不同類型的多個工具被視為等同來比較。\n\n具體來說，是將 Uvicorn、Starlette 和 FastAPI 同時進行比較（以及許多其他工具）。\n\n該工具解決的問題越簡單，其效能就越好。而且大多數基準測試不會測試該工具提供的附加功能。\n\n層次結構如下：\n\n* **Uvicorn**：ASGI 伺服器\n    * **Starlette**：（使用 Uvicorn）一個網頁微框架\n        * **FastAPI**：（使用 Starlette）一個 API 微框架，具有用於建立 API 的多個附加功能、資料驗證等。\n\n* **Uvicorn**：\n    * 具有最佳效能，因為除了伺服器本身之外，它沒有太多額外的程式碼。\n    * 你不會直接在 Uvicorn 中編寫應用程式。這意味著你的程式碼必須或多或少地包含 Starlette（或 **FastAPI**）提供的所有程式碼。如果你這樣做，你的最終應用程式將具有與使用框架相同的開銷，且無法像使用框架那樣減少應用程式程式碼與錯誤。\n    * 如果你要比較 Uvicorn，請將其與 Daphne、Hypercorn、uWSGI 等應用程式伺服器進行比較。\n* **Starlette**：\n    * 繼 Uvicorn 之後的次佳表現。事實上，Starlette 使用 Uvicorn 來運行。因此它將可能只透過執行更多程式碼而變得比 Uvicorn「慢」。\n    * 但它為你提供了建立簡單網頁應用程式的工具，以及基於路徑的路由等。\n    * 如果你要比較 Starlette，請將其與 Sanic、Flask、Django 等網頁框架（或微框架）進行比較。\n* **FastAPI**：\n    * 就像 Starlette 使用 Uvicorn 並不能比它更快一樣， **FastAPI** 使用 Starlette，所以它不能比它更快。\n    * FastAPI 在 Starlette 基礎之上提供了更多功能。包含建構 API 時所需要的功能，例如資料驗證和序列化。FastAPI 可以幫助你自動產生 API 文件，（應用程式啟動時將會自動生成文件，所以不會增加應用程式運行時的開銷）。\n    * 如果你沒有使用 FastAPI 而是直接使用 Starlette（或其他工具，如 Sanic、Flask、Responder 等），你將必須自行實現所有資料驗證和序列化。因此，你的最終應用程式仍然具有與使用 FastAPI 建置相同的開銷。在許多情況下，這種資料驗證和序列化是應用程式中編寫最大量的程式碼。\n    * 因此透過使用 FastAPI，你可以節省開發時間、錯誤與程式碼數量，並且相比不使用 FastAPI 你很大可能會獲得相同或更好的效能（因為那樣你必須在程式碼中實現所有相同的功能）。\n    * 如果你要與 FastAPI 比較，請將其與能夠提供資料驗證、序列化和文件的網頁應用程式框架（或工具集）進行比較，例如 Flask-apispec、NestJS、Molten 等框架。具備整合式自動資料驗證、序列化與文件的框架。\n"
  },
  {
    "path": "docs/zh-hant/docs/deployment/cloud.md",
    "content": "# 在雲端供應商上部署 FastAPI { #deploy-fastapi-on-cloud-providers }\n\n你幾乎可以使用**任何雲端供應商**來部署你的 FastAPI 應用程式。\n\n在大多數情況下，主要的雲端供應商都有部署 FastAPI 的指南。\n\n## FastAPI Cloud { #fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** 由 **FastAPI** 的同一位作者與團隊打造。\n\n它讓你以最少的投入，簡化 **建置**、**部署** 與 **存取** API 的流程。\n\n它把使用 FastAPI 開發應用的同樣**優秀的開發者體驗**，帶到將它們**部署**到雲端的過程中。🎉\n\nFastAPI Cloud 是 *FastAPI and friends* 開源專案的主要贊助與資金提供者。✨\n\n## 雲端供應商 - 贊助商 { #cloud-providers-sponsors }\n\n其他一些雲端供應商也會 ✨ [**贊助 FastAPI**](../help-fastapi.md#sponsor-the-author) ✨。🙇\n\n你也可以參考他們的指南並試用其服務：\n\n* [Render](https://docs.render.com/deploy-fastapi?utm_source=deploydoc&utm_medium=referral&utm_campaign=fastapi)\n* [Railway](https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi)\n"
  },
  {
    "path": "docs/zh-hant/docs/deployment/concepts.md",
    "content": "# 部署概念 { #deployments-concepts }\n\n當你要部署一個 FastAPI 應用，或其實任何類型的 Web API 時，有幾個你可能在意的概念。掌握這些概念後，你就能找出最適合部署你應用的方式。\n\n一些重要的概念包括：\n\n- 安全性 - HTTPS\n- 開機自動執行\n- 重新啟動\n- 複本（執行中的行程數量）\n- 記憶體\n- 啟動前的前置步驟\n\n我們將看看它們如何影響部署。\n\n最終目標是能夠以安全、避免中斷，並盡可能高效使用運算資源（例如遠端伺服器／虛擬機）的方式來服務你的 API 用戶端。🚀\n\n我會在這裡多介紹一些這些觀念，希望能幫你建立必要的直覺，讓你能在非常不同、甚至尚未出現的未來環境中決定要如何部署你的 API。\n\n在思考這些概念之後，你將能夠評估與設計最適合部署你自己 API 的方式。\n\n在接下來的章節，我會提供更具體的部署 FastAPI 應用的食譜。\n\n但現在，先來看看這些重要的概念想法。這些概念同樣適用於任何其他類型的 Web API。💡\n\n## 安全性 - HTTPS { #security-https }\n\n在[前一章關於 HTTPS](https.md) 中，我們學到 HTTPS 如何為你的 API 提供加密。\n\n我們也看到，HTTPS 通常由應用伺服器外部的元件提供，即 TLS Termination Proxy。\n\n而且必須有某個東西負責續期 HTTPS 憑證，可能是同一個元件，也可能是不同的東西。\n\n### HTTPS 工具範例 { #example-tools-for-https }\n\n你可以用來作為 TLS Termination Proxy 的工具包括：\n\n- Traefik\n    - 自動處理憑證續期 ✨\n- Caddy\n    - 自動處理憑證續期 ✨\n- Nginx\n    - 搭配像 Certbot 這類外部元件進行憑證續期\n- HAProxy\n    - 搭配像 Certbot 這類外部元件進行憑證續期\n- Kubernetes，使用如 Nginx 的 Ingress Controller\n    - 搭配像 cert-manager 這類外部元件進行憑證續期\n- 由雲端供應商在其服務內部處理（見下文 👇）\n\n另一個選項是使用能幫你做更多事情的雲端服務（包含設定 HTTPS）。它可能有一些限制或要額外付費等。但在那種情況下，你就不必自己設定 TLS Termination Proxy。\n\n我會在後續章節展示一些具體例子。\n\n---\n\n接下來要考慮的概念都與實際執行你的 API 的程式（例如 Uvicorn）有關。\n\n## 程式與行程 { #program-and-process }\n\n我們會常提到執行中的「行程（process）」，因此先釐清它的意思，以及與「程式（program）」的差異很有幫助。\n\n### 什麼是程式 { #what-is-a-program }\n\n「程式（program）」一詞常用來描述許多東西：\n\n- 你寫的原始碼，也就是 Python 檔案。\n- 可由作業系統執行的檔案，例如：`python`、`python.exe` 或 `uvicorn`。\n- 在作業系統上執行中的特定程式，使用 CPU 並將資料存於記憶體。這也稱為「行程」。\n\n### 什麼是行程 { #what-is-a-process }\n\n「行程（process）」通常以更特定的方式使用，只指作業系統中正在執行的東西（如上面最後一點）：\n\n- 在作業系統上「執行中」的特定程式。\n    - 這不是指檔案或原始碼，而是特指正在被作業系統執行並管理的那個東西。\n- 任何程式、任何程式碼，只有在「被執行」時才能做事。所以，當有「行程在執行」時才能運作。\n- 行程可以被你或作業系統終止（kill）。此時它就停止執行，無法再做任何事。\n- 你電腦上執行的每個應用程式、每個視窗等，背後都有一些行程。而且在電腦開機時，通常會同時有許多行程在跑。\n- 同一個程式可以同時有多個行程在執行。\n\n如果你打開作業系統的「工作管理員」或「系統監控器」（或類似工具），就能看到許多正在執行的行程。\n\n例如，你大概會看到同一個瀏覽器（Firefox、Chrome、Edge 等）會有多個行程在執行。它們通常每個分頁一個行程，外加其他一些額外行程。\n\n<img class=\"shadow\" src=\"/img/deployment/concepts/image01.png\">\n\n---\n\n現在我們知道「行程」與「程式」的差異了，繼續談部署。\n\n## 開機自動執行 { #running-on-startup }\n\n多數情況下，當你建立一個 Web API，你會希望它「一直在執行」，不中斷，讓客戶端隨時可用。除非你有特定理由只在某些情況下才執行，但大部分時候你會希望它持續運作並且可用。\n\n### 在遠端伺服器上 { #in-a-remote-server }\n\n當你設定一台遠端伺服器（雲端伺服器、虛擬機等），最簡單的作法就是像本機開發時一樣，手動使用 `fastapi run`（它使用 Uvicorn）或類似的方式。\n\n這在「開發期間」會運作良好而且有用。\n\n但如果你與伺服器的連線中斷，正在執行的行程很可能會死掉。\n\n而如果伺服器被重新啟動（例如更新後、或雲端供應商進行遷移），你大概「不會注意到」。因此你甚至不知道要手動重啟行程。你的 API 就會一直掛著。😱\n\n### 開機自動啟動 { #run-automatically-on-startup }\n\n通常你會希望伺服器程式（例如 Uvicorn）在伺服器開機時自動啟動，且不需任何「人工介入」，讓你的 API（例如 Uvicorn 執行你的 FastAPI 應用）總是有行程在跑。\n\n### 獨立程式 { #separate-program }\n\n為了達成這點，你通常會有一個「獨立的程式」來確保你的應用在開機時會被啟動。很多情況下，它也會確保其他元件或應用一併啟動，例如資料庫。\n\n### 開機自動啟動的工具範例 { #example-tools-to-run-at-startup }\n\n能做到這件事的工具包括：\n\n- Docker\n- Kubernetes\n- Docker Compose\n- Docker 的 Swarm 模式\n- Systemd\n- Supervisor\n- 由雲端供應商在其服務內部處理\n- 其他...\n\n我會在後續章節給出更具體的例子。\n\n## 重新啟動 { #restarts }\n\n和確保你的應用在開機時會執行一樣，你大概也會希望在發生失敗之後，它能「自動重新啟動」。\n\n### 人都會犯錯 { #we-make-mistakes }\n\n我們身為人，常常會犯錯。軟體幾乎總是有藏在各處的「臭蟲（bugs）」🐛\n\n而我們開發者會在發現這些 bug 後持續改進程式碼、實作新功能（也可能順便加進新的 bug 😅）。\n\n### 小錯誤自動處理 { #small-errors-automatically-handled }\n\n使用 FastAPI 建構 Web API 時，如果我們的程式碼出錯，FastAPI 通常會把它限制在觸發該錯誤的單次請求之中。🛡\n\n用戶端會收到「500 Internal Server Error」，但應用會繼續處理之後的請求，而不是整個崩潰。\n\n### 更嚴重的錯誤 - 當機 { #bigger-errors-crashes }\n\n然而，仍可能有一些情況，我們寫的程式碼「讓整個應用當機」，使 Uvicorn 與 Python 都崩潰。💥\n\n即便如此，你大概也不會希望應用因為某處錯誤就一直處於死亡狀態，你可能會希望它「繼續運作」，至少讓沒有壞掉的「路徑操作（path operations）」能持續服務。\n\n### 當機後重新啟動 { #restart-after-crash }\n\n在這些會讓「執行中行程」整個崩潰的嚴重錯誤案例裡，你會希望有個外部元件負責「重新啟動」該行程，至少嘗試幾次...\n\n/// tip\n\n...不過，如果整個應用「一啟動就立刻」崩潰，那持續無止境地重啟大概沒有意義。但在這類情況下，你很可能會在開發過程中就發現，或至少在部署後馬上注意到。\n\n所以讓我們專注在主要情境：應用在未來某些特定案例中可能會整體崩潰，但此時重新啟動仍然是有意義的。\n\n///\n\n你大概會希望把負責重新啟動應用的東西放在「外部元件」，因為那個時候，應用本身連同 Uvicorn 與 Python 都已經掛了，在同一個應用的程式碼裡也無法做什麼。\n\n### 自動重新啟動的工具範例 { #example-tools-to-restart-automatically }\n\n多數情況下，用來「在開機時啟動程式」的同一套工具，也會負責處理自動「重新啟動」。\n\n例如，可以由下列工具處理：\n\n- Docker\n- Kubernetes\n- Docker Compose\n- Docker 的 Swarm 模式\n- Systemd\n- Supervisor\n- 由雲端供應商在其服務內部處理\n- 其他...\n\n## 複本：行程與記憶體 { #replication-processes-and-memory }\n\n在 FastAPI 應用中，使用像 `fastapi` 指令（執行 Uvicorn）的伺服器程式，即使只在「一個行程」中執行，也能同時服務多個客戶端。\n\n但很多情況下，你會想同時執行多個工作行程（workers）。\n\n### 多個行程 - Workers { #multiple-processes-workers }\n\n如果你的客戶端比單一行程所能處理的更多（例如虛擬機規格不大），而伺服器 CPU 有「多核心」，那你可以同時執行「多個行程」載入相同的應用，並把所有請求分散給它們。\n\n當你執行同一個 API 程式的「多個行程」時，通常稱為「workers（工作行程）」。\n\n### 工作行程與連接埠 { #worker-processes-and-ports }\n\n還記得文件中[關於 HTTPS](https.md) 的說明嗎：在一台伺服器上，一組 IP 與連接埠的組合只能由「一個行程」監聽？\n\n這裡同樣適用。\n\n因此，若要同時擁有「多個行程」，就必須有「單一行程」在該連接埠上監聽，然後以某種方式把通信傳遞給各個工作行程。\n\n### 每個行程的記憶體 { #memory-per-process }\n\n當程式把東西載入記憶體時，例如把機器學習模型存到變數中，或把大型檔案內容讀到變數中，這些都會「消耗一些伺服器的記憶體（RAM）」。\n\n而多個行程通常「不共享記憶體」。這表示每個執行中的行程都有自己的東西、變數與記憶體。如果你的程式碼會用掉大量記憶體，「每個行程」都會消耗等量的記憶體。\n\n### 伺服器記憶體 { #server-memory }\n\n例如，如果你的程式碼載入一個「1 GB 大小」的機器學習模型，當你用一個行程執行你的 API，它就會至少吃掉 1 GB 的 RAM。若你啟動「4 個行程」（4 個 workers），每個會吃 1 GB RAM。總計你的 API 會吃掉「4 GB RAM」。\n\n如果你的遠端伺服器或虛擬機只有 3 GB RAM，嘗試載入超過 4 GB 的 RAM 就會出問題。🚨\n\n### 多個行程 - 範例 { #multiple-processes-an-example }\n\n在這個例子中，有一個「管理行程（Manager Process）」會啟動並控制兩個「工作行程（Worker Processes）」。\n\n這個管理行程大概就是在 IP 的「連接埠」上監聽的那個。它會把所有通信轉發到各個工作行程。\n\n那些工作行程才是實際執行你的應用的，它們會完成主要的計算，接收「請求」並回傳「回應」，也會把你放在變數中的東西載入 RAM。\n\n<img src=\"/img/deployment/concepts/process-ram.drawio.svg\">\n\n當然，同一台機器上除了你的應用之外，通常也會有「其他行程」在執行。\n\n有個有趣的細節是，每個行程的「CPU 使用率」百分比會隨時間大幅「變動」，但「記憶體（RAM）」通常維持相對「穩定」。\n\n如果你的 API 每次做的計算量相近，且客戶很多，那「CPU 使用率」也可能「相對穩定」（而不是快速上下起伏）。\n\n### 複本與擴展的工具與策略範例 { #examples-of-replication-tools-and-strategies }\n\n要達成這些有很多種作法。我會在後續章節（例如談到 Docker 與容器時）介紹更具體的策略。\n\n主要的限制是：必須有「單一」元件負責處理「公開 IP」上的「連接埠」。接著它必須能把通信「轉發」到被複製的「行程／workers」。\n\n以下是一些可能的組合與策略：\n\n- Uvicorn 搭配 `--workers`\n    - 一個 Uvicorn「管理行程」會在「IP」與「連接埠」上監聽，並啟動「多個 Uvicorn 工作行程」。\n- Kubernetes 與其他分散式「容器系統」\n    - 由「Kubernetes」層在「IP」與「連接埠」上監聽。複本的方式是有「多個容器」，每個容器內執行「一個 Uvicorn 行程」。\n- 由「雲端服務」替你處理\n    - 雲端服務很可能「替你處理複本」。它可能讓你定義「要執行的行程」或「容器映像」，無論如何，多半會是「單一 Uvicorn 行程」，而由雲端服務負責進行複製。\n\n/// tip\n\n先別擔心這裡提到的「容器」、Docker 或 Kubernetes 如果現在還不太懂。\n\n我會在未來的章節進一步說明容器映像、Docker、Kubernetes 等等：[容器中的 FastAPI - Docker](docker.md)。\n\n///\n\n## 啟動前的前置步驟 { #previous-steps-before-starting }\n\n很多情況下，你會希望在應用「啟動之前」先執行一些步驟。\n\n例如，你可能想先執行「資料庫遷移」。\n\n但在多數情況下，你會希望這些步驟只執行「一次」。\n\n所以，你會希望用「單一行程」來執行那些「前置步驟」，在啟動應用之前完成。\n\n而且即使之後你要為應用本身啟動「多個行程」（多個 workers），你也必須確保只有一個行程在跑那些前置步驟。若由「多個行程」去跑，會在「平行」中重複同樣的工作；而如果那些步驟像是資料庫遷移這類敏感操作，它們之間可能會互相衝突。\n\n當然，也有一些情況，重複執行前置步驟不會有問題；在那種情況下就容易處理得多。\n\n/// tip\n\n另外請記住，依照你的設定，在某些情況下你「甚至可能不需要任何前置步驟」才能啟動應用。\n\n這種情況下，你就不用為此費心了。🤷\n\n///\n\n### 前置步驟策略範例 { #examples-of-previous-steps-strategies }\n\n這會「高度取決於」你「部署系統」的方式，而且很可能與你如何啟動程式、處理重新啟動等有關。\n\n以下是一些可能的做法：\n\n- 在 Kubernetes 中使用一個「Init Container」，它會在你的應用容器之前先執行\n- 一個 bash 腳本先跑前置步驟，然後再啟動你的應用\n    - 你仍然需要有機制來啟動／重新啟動「那個」bash 腳本、偵測錯誤等\n\n/// tip\n\n我會在未來關於容器的章節提供更具體的範例：[容器中的 FastAPI - Docker](docker.md)。\n\n///\n\n## 資源使用率 { #resource-utilization }\n\n你的伺服器（群）是可以被「消耗／利用」的「資源」，你的程式會使用 CPU 的計算時間，以及可用的 RAM 記憶體。\n\n你想要消耗／利用多少系統資源？直覺上可能會想「不要太多」，但實際上，你大概會希望在「不當機」的前提下「盡可能用多一點」。\n\n如果你花錢租了 3 台伺服器，卻只用了它們少量的 RAM 與 CPU，那你可能是在「浪費金錢」💸、也「浪費伺服器電力」🌎 等。\n\n在那種情況下，可能更好的是只用 2 台伺服器，並以更高的比例使用它們的資源（CPU、記憶體、磁碟、網路頻寬等）。\n\n另一方面，如果你有 2 台伺服器，且你使用了它們「100% 的 CPU 與 RAM」，某個時刻一個行程會要求更多記憶體，伺服器就得用磁碟當作「記憶體」（這可能慢上數千倍），甚至「當機」。或是某個行程需要做計算時，必須等到 CPU 再度空閒。\n\n這種情況下，最好是再加一台伺服器，並在上面跑部分行程，讓所有行程都有「足夠的 RAM 與 CPU 時間」。\n\n也有機會因為某些原因，你的 API 使用量出現「尖峰」。也許它爆紅了，或是其他服務或機器人開始使用它。在這些情況下，你可能會希望留有一些額外資源以策安全。\n\n你可以設定一個「目標數字」，例如資源使用率落在「50% 到 90%」之間。重點是，這些大概就是你會想測量並用來調校部署的主要指標。\n\n你可以用像 `htop` 這樣的簡單工具，查看伺服器的 CPU 與 RAM 使用量，或各行程的使用量。也可以用更複雜的監控工具，分散式地監看多台伺服器，等等。\n\n## 重點回顧 { #recap }\n\n這裡介紹了一些你在決定如何部署應用時應該記住的主要概念：\n\n- 安全性 - HTTPS\n- 開機自動執行\n- 重新啟動\n- 複本（執行中的行程數量）\n- 記憶體\n- 啟動前的前置步驟\n\n理解這些想法與如何套用它們，應能給你足夠的直覺，在設定與調整部署時做出各種決策。🤓\n\n在接下來的章節，我會提供更多可行策略的具體範例。🚀\n"
  },
  {
    "path": "docs/zh-hant/docs/deployment/docker.md",
    "content": "# 在容器中使用 FastAPI - Docker { #fastapi-in-containers-docker }\n\n部署 FastAPI 應用時，一個常見做法是建置一個「Linux 容器映像（container image）」。通常使用 [Docker](https://www.docker.com/) 來完成。之後你可以用多種方式部署該容器映像。\n\n使用 Linux 容器有多種優點，包括安全性、可重現性、簡單性等。\n\n/// tip | 提示\n\n趕時間而且已經懂這些？直接跳到下面的 [`Dockerfile` 👇](#build-a-docker-image-for-fastapi)。\n\n///\n\n<details>\n<summary>Dockerfile 預覽 👀</summary>\n\n```Dockerfile\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n\n# 若在 Nginx 或 Traefik 等代理伺服器後方執行，請加入 --proxy-headers\n# CMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--proxy-headers\"]\n```\n\n</details>\n\n## 什麼是容器 { #what-is-a-container }\n\n容器（主要是 Linux 容器）是一種非常輕量的方式，用來封裝應用及其所有相依與必要檔案，並讓其與同一系統中的其他容器（其他應用或元件）隔離。\n\nLinux 容器使用與主機（機器、虛擬機、雲端伺服器等）相同的 Linux kernel。這意味著它們非常輕量（相較於完整模擬整個作業系統的虛擬機）。\n\n因此，容器只消耗很少的資源，與直接執行行程相當（而虛擬機會消耗更多）。\n\n容器也有其各自隔離的執行行程（通常只有一個行程）、檔案系統與網路，簡化部署、安全性與開發等。\n\n## 什麼是容器映像 { #what-is-a-container-image }\n\n容器是由容器映像啟動執行的。\n\n容器映像是所有檔案、環境變數，以及在容器中應該執行的預設指令/程式的靜態版本。這裡的「靜態」意指容器映像不在執行，它只是被封裝的檔案與 metadata。\n\n相對於儲存的靜態內容「容器映像」，「容器」通常指執行中的實例，也就是正在被執行的東西。\n\n當容器啟動並執行時（自容器映像啟動），它可以建立或變更檔案、環境變數等。這些變更只會存在於該容器中，不會持久化回底層的容器映像（不會寫回磁碟）。\n\n容器映像可類比為程式檔與其內容，例如 `python` 與某個 `main.py` 檔案。\n\n而容器本身（相對於容器映像）是映像的實際執行實例，類比為「行程」。事實上，容器只有在有行程執行時才在運作（通常只有單一行程）。當其中沒有行程在執行時，容器就會停止。\n\n## 容器映像 { #container-images }\n\nDocker 是用來建立與管理容器映像與容器的主要工具之一。\n\n也有一個公開的 [Docker Hub](https://hub.docker.com/)，內含許多工具、環境、資料庫與應用的預先製作「官方映像」。\n\n例如，有官方的 [Python 映像](https://hub.docker.com/_/python)。\n\n也有許多其他針對不同用途的映像，例如資料庫：\n\n* [PostgreSQL](https://hub.docker.com/_/postgres)\n* [MySQL](https://hub.docker.com/_/mysql)\n* [MongoDB](https://hub.docker.com/_/mongo)\n* [Redis](https://hub.docker.com/_/redis) 等。\n\n使用預製的容器映像很容易「組合」並使用不同工具。例如，嘗試一個新資料庫。多數情況下，你可以使用官方映像，並僅用環境變數加以設定。\n\n如此，你可以學會關於容器與 Docker 的知識，並將這些知識重複運用到許多不同工具與元件上。\n\n因此，你會執行多個容器，內容各不相同，例如一個資料庫、一個 Python 應用、一個帶有 React 前端應用的網頁伺服器，並透過它們的內部網路把它們連接在一起。\n\n所有容器管理系統（例如 Docker 或 Kubernetes）都內建了這些網路功能。\n\n## 容器與行程 { #containers-and-processes }\n\n容器映像通常在其 metadata 中包含當容器啟動時應執行的預設程式或指令，以及要傳給該程式的參數。這與在命令列要執行的內容非常類似。\n\n當容器啟動時，它會執行該指令/程式（雖然你可以覆寫它，讓它執行不同的指令/程式）。\n\n只要主要行程（指令或程式）在執行，容器就會運作。\n\n容器通常只有單一行程，但也可以由主要行程啟動子行程，如此你會在同一個容器內有多個行程。\n\n但不可能在沒有至少一個執行中行程的情況下讓容器運作。若主要行程停止，容器也會停止。\n\n## 建置 FastAPI 的 Docker 映像 { #build-a-docker-image-for-fastapi }\n\n好了，現在來動手做點東西吧！🚀\n\n我會示範如何從零開始，基於官方的 Python 映像，為 FastAPI 建置一個 Docker 映像。\n\n這是你在多數情況下會想做的事，例如：\n\n* 使用 Kubernetes 或類似工具\n* 在 Raspberry Pi 上執行\n* 使用會替你執行容器映像的雲端服務等\n\n### 套件需求 { #package-requirements }\n\n你的應用通常會把「套件需求」放在某個檔案中。\n\n這主要取決於你用什麼工具來安裝那些需求。\n\n最常見的方式是準備一個 `requirements.txt` 檔案，逐行列出套件名稱與版本。\n\n當然，你會用與在 [關於 FastAPI 版本](versions.md) 中讀到的相同概念，來設定版本範圍。\n\n例如，你的 `requirements.txt` 可能像這樣：\n\n```\nfastapi[standard]>=0.113.0,<0.114.0\npydantic>=2.7.0,<3.0.0\n```\n\n接著你通常會用 `pip` 來安裝這些套件相依，例如：\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\nSuccessfully installed fastapi pydantic\n```\n\n</div>\n\n/// info | 資訊\n\n還有其他格式與工具可以用來定義與安裝套件相依。\n\n///\n\n### 建立 FastAPI 程式碼 { #create-the-fastapi-code }\n\n* 建立一個 `app` 目錄並進入。\n* 建立一個空的 `__init__.py` 檔案。\n* 建立一個 `main.py` 檔案，內容如下：\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n### Dockerfile { #dockerfile }\n\n現在在同一個專案目錄建立一個 `Dockerfile` 檔案，內容如下：\n\n```{ .dockerfile .annotate }\n# (1)!\nFROM python:3.14\n\n# (2)!\nWORKDIR /code\n\n# (3)!\nCOPY ./requirements.txt /code/requirements.txt\n\n# (4)!\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (5)!\nCOPY ./app /code/app\n\n# (6)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n1. 從官方的 Python 基底映像開始。\n\n2. 將目前工作目錄設為 `/code`。\n\n    我們會把 `requirements.txt` 檔案與 `app` 目錄放在這裡。\n\n3. 將需求檔案複製到 `/code` 目錄。\n\n    先只複製需求檔案，不要複製其他程式碼。\n\n    因為這個檔案不常變動，Docker 能偵測並在此步驟使用快取，也能啟用下一步的快取。\n\n4. 安裝需求檔案中的套件相依。\n\n    `--no-cache-dir` 選項告訴 `pip` 不要把下載的套件保存在本機，因為那只在 `pip` 之後還會再次安裝相同套件時才有用，而在使用容器時並非如此。\n\n    /// note | 注意\n\n    `--no-cache-dir` 只跟 `pip` 有關，與 Docker 或容器無關。\n\n    ///\n\n    `--upgrade` 選項告訴 `pip` 若套件已安裝則升級它們。\n\n    因為前一步複製檔案可能被 Docker 快取偵測到，這一步也會在可用時使用 Docker 快取。\n\n    在此步驟使用快取可以在開發期間反覆建置映像時，為你省下大量時間，而不必每次都重新下載並安裝所有相依。\n\n5. 將 `./app` 目錄複製到 `/code` 目錄中。\n\n    由於這包含了所有程式碼，也是最常變動的部分，Docker 的快取在這一步或之後的步驟將不容易被使用。\n\n    因此，重要的是把這一步放在 `Dockerfile` 的接近結尾處，以最佳化容器映像的建置時間。\n\n6. 設定指令使用 `fastapi run`，其底層使用 Uvicorn。\n\n    `CMD` 接受字串清單，每個字串對應你在命令列中用空白分隔所輸入的內容。\n\n    這個指令會從目前的工作目錄執行，也就是你先前用 `WORKDIR /code` 設定的 `/code` 目錄。\n\n/// tip | 提示\n\n點擊程式碼中的每個數字泡泡來查看每一行在做什麼。👆\n\n///\n\n/// warning | 警告\n\n務必「總是」使用 `CMD` 指令的「exec 形式」，如下所述。\n\n///\n\n#### 使用 `CMD` 的 Exec 形式 { #use-cmd-exec-form }\n\nDocker 的 [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) 指令可以有兩種寫法：\n\n✅ Exec 形式：\n\n```Dockerfile\n# ✅ 請這樣做\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\"]\n```\n\n⛔️ Shell 形式：\n\n```Dockerfile\n# ⛔️ 請不要這樣做\nCMD fastapi run app/main.py --port 80\n```\n\n務必總是使用 exec 形式，以確保 FastAPI 能夠優雅地關閉，並觸發 [lifespan events](../advanced/events.md)。\n\n你可以在 [Docker 關於 shell 與 exec 形式的文件](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form) 閱讀更多。\n\n使用 `docker compose` 時這會特別明顯。技術細節請見這段 Docker Compose 常見問題：[為什麼我的服務要花 10 秒才重新建立或停止？](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop)\n\n#### 目錄結構 { #directory-structure }\n\n你現在應該會有如下的目錄結構：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n├── Dockerfile\n└── requirements.txt\n```\n\n#### 位於 TLS 終止代理之後 { #behind-a-tls-termination-proxy }\n\n如果你在 TLS 終止代理（負載平衡器）如 Nginx 或 Traefik 之後執行容器，請加上 `--proxy-headers` 選項，這會告訴 Uvicorn（透過 FastAPI CLI）信任該代理所送來的標頭，表示應用在 HTTPS 後方執行等。\n\n```Dockerfile\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--proxy-headers\", \"--port\", \"80\"]\n```\n\n#### Docker 快取 { #docker-cache }\n\n這個 `Dockerfile` 中有個重要技巧：我們先只複製「相依檔案」，而不是其他程式碼。原因如下。\n\n```Dockerfile\nCOPY ./requirements.txt /code/requirements.txt\n```\n\nDocker 與其他工具會「增量式」建置容器映像，從 `Dockerfile` 頂端開始，逐層加入，每個指令所建立的檔案都會形成一層。\n\nDocker 與類似工具在建置映像時也會使用內部快取；如果某檔案自上次建置以來未變更，則會重用上次建立的同一層，而不是再次複製並從零建立新層。\n\n僅僅避免複製檔案本身或許幫助不大，但因為該步驟使用了快取，接下來的步驟也就能「使用快取」。例如，安裝相依的這個指令就能使用快取：\n\n```Dockerfile\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n```\n\n套件相依的檔案「不會經常變動」。因此，只複製該檔案，Docker 就能在此步驟「使用快取」。\n\n接著，Docker 也就能對下一步「下載並安裝這些相依」使用快取。這正是我們能「省下大量時間」的地方。✨ 也能避免無聊的等待。😪😆\n\n下載與安裝套件相依「可能要花好幾分鐘」，但使用「快取」最多只需幾秒。\n\n在開發期間，你會一再建置容器映像以測試程式碼變更是否生效，累積下來這能省下許多時間。\n\n之後，在 `Dockerfile` 的接近結尾處，我們才複製所有程式碼。由於這是「最常變動」的部分，我們把它放在接近結尾，因為幾乎總是此步驟之後的任何步驟都無法使用快取。\n\n```Dockerfile\nCOPY ./app /code/app\n```\n\n### 建置 Docker 映像 { #build-the-docker-image }\n\n現在所有檔案就緒，來建置容器映像。\n\n* 進到專案目錄（你的 `Dockerfile` 所在，且包含 `app` 目錄）。\n* 建置你的 FastAPI 映像：\n\n<div class=\"termy\">\n\n```console\n$ docker build -t myimage .\n\n---> 100%\n```\n\n</div>\n\n/// tip | 提示\n\n注意最後的 `.`，等同於 `./`，它告訴 Docker 要用哪個目錄來建置容器映像。\n\n這裡是目前的目錄（`.`）。\n\n///\n\n### 啟動 Docker 容器 { #start-the-docker-container }\n\n* 以你的映像為基礎執行一個容器：\n\n<div class=\"termy\">\n\n```console\n$ docker run -d --name mycontainer -p 80:80 myimage\n```\n\n</div>\n\n## 檢查 { #check-it }\n\n你應該可以透過 Docker 容器的網址檢查，例如：[http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) 或 [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery)（或等效的、使用你的 Docker 主機）。\n\n你會看到類似這樣：\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n## 互動式 API 文件 { #interactive-api-docs }\n\n現在你可以前往 [http://192.168.99.100/docs](http://192.168.99.100/docs) 或 [http://127.0.0.1/docs](http://127.0.0.1/docs)（或等效的、使用你的 Docker 主機）。\n\n你會看到自動產生的互動式 API 文件（由 [Swagger UI](https://github.com/swagger-api/swagger-ui) 提供）：\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n## 替代的 API 文件 { #alternative-api-docs }\n\n你也可以前往 [http://192.168.99.100/redoc](http://192.168.99.100/redoc) 或 [http://127.0.0.1/redoc](http://127.0.0.1/redoc)（或等效的、使用你的 Docker 主機）。\n\n你會看到另一種自動產生的文件（由 [ReDoc](https://github.com/Rebilly/ReDoc) 提供）：\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## 為單檔 FastAPI 建置 Docker 映像 { #build-a-docker-image-with-a-single-file-fastapi }\n\n如果你的 FastAPI 是單一檔案，例如沒有 `./app` 目錄的 `main.py`，你的檔案結構可能像這樣：\n\n```\n.\n├── Dockerfile\n├── main.py\n└── requirements.txt\n```\n\n接著你只需要在 `Dockerfile` 中調整對應的路徑以複製該檔案：\n\n```{ .dockerfile .annotate hl_lines=\"10  13\" }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\n# (1)!\nCOPY ./main.py /code/\n\n# (2)!\nCMD [\"fastapi\", \"run\", \"main.py\", \"--port\", \"80\"]\n```\n\n1. 將 `main.py` 直接複製到 `/code` 目錄（不需要 `./app` 目錄）。\n\n2. 使用 `fastapi run` 來服務單檔的 `main.py` 應用。\n\n當你把檔案傳給 `fastapi run`，它會自動偵測這是一個單一檔案而非套件的一部分，並知道如何匯入並服務你的 FastAPI 應用。😎\n\n## 部署概念 { #deployment-concepts }\n\n我們用容器的角度再談一次部分相同的[部署概念](concepts.md)。\n\n容器主要是簡化應用「建置與部署」流程的工具，但它們不強制特定的方式來處理這些「部署概念」，而是有多種策略可選。\n\n好消息是，每種不同的策略都能涵蓋所有部署概念。🎉\n\n讓我們用容器的角度回顧這些部署概念：\n\n* HTTPS\n* 開機自動執行\n* 失敗重啟\n* 複本（執行的行程數量）\n* 記憶體\n* 啟動前的前置步驟\n\n## HTTPS { #https }\n\n若僅聚焦於 FastAPI 應用的「容器映像」（以及稍後的執行中「容器」），HTTPS 通常會由另一個工具在「外部」處理。\n\n它可以是另一個容器，例如使用 [Traefik](https://traefik.io/)，來處理「HTTPS」以及「自動」取得「憑證」。\n\n/// tip | 提示\n\nTraefik 與 Docker、Kubernetes 等整合良好，因此為你的容器設定與配置 HTTPS 非常容易。\n\n///\n\n或者，HTTPS 也可能由雲端供應商以其服務來處理（同時應用仍以容器執行）。\n\n## 開機自動執行與重啟 { #running-on-startup-and-restarts }\n\n通常會有另一個工具負責「啟動並執行」你的容器。\n\n可能是直接用 Docker、Docker Compose、Kubernetes、某個雲端服務等。\n\n在大多數（或全部）情況下，都有簡單的選項可以在開機時自動執行容器，並在失敗時重啟。例如，在 Docker 中，可用命令列選項 `--restart`。\n\n如果不使用容器，讓應用在開機時自動執行並支援重啟可能既繁瑣又困難。但在「使用容器」時，這類功能在多數情況下都是預設包含的。✨\n\n## 複本 - 行程數量 { #replication-number-of-processes }\n\n如果你在有 Kubernetes、Docker Swarm Mode、Nomad，或其他類似的分散式容器管理系統的「<dfn title=\"一組配置為連接並共同運作的機器\">叢集</dfn>」上運作，那你大概會希望在「叢集層級」處理「複本」，而不是在每個容器內使用「行程管理器」（例如帶有 workers 的 Uvicorn）。\n\n像 Kubernetes 這類的分散式容器管理系統，通常內建處理「容器複本」以及支援進入請求的「負載平衡」的能力——全部都在「叢集層級」。\n\n在這些情況下，你大概會想要如[上面所述](#dockerfile)從零開始建置一個 Docker 映像，安裝你的相依，並且只執行「單一 Uvicorn 行程」，而不是使用多個 Uvicorn workers。\n\n### 負載平衡器 { #load-balancer }\n\n使用容器時，通常會有某個元件在「主埠口」上監聽。它也可能是另一個同時做為「TLS 終止代理」的容器來處理「HTTPS」，或類似的工具。\n\n由於這個元件會承接請求的「負載」，並將其分配給 workers，使其（希望）「平衡」，因此也常被稱為「負載平衡器（Load Balancer）」。\n\n/// tip | 提示\n\n用於 HTTPS 的同一個「TLS 終止代理」元件通常也會是「負載平衡器」。\n\n///\n\n而在使用容器時，你用來啓動與管理它們的系統，已內建把「網路通訊」（例如 HTTP 請求）從該「負載平衡器」（也可能是「TLS 終止代理」）傳遞到你的應用容器的工具。\n\n### 一個負載平衡器 - 多個工作容器 { #one-load-balancer-multiple-worker-containers }\n\n使用 Kubernetes 或類似的分散式容器管理系統時，使用其內部網路機制可以讓在主「埠口」上監聽的單一「負載平衡器」，把通訊（請求）傳遞給可能的「多個執行你應用的容器」。\n\n每個執行你應用的容器通常只有「單一行程」（例如執行你的 FastAPI 應用的 Uvicorn 行程）。它們都是「相同的容器」，執行相同的東西，但各自擁有自己的行程、記憶體等。如此即可在 CPU 的「不同核心」、甚至是「不同機器」上發揮「平行化」的效益。\n\n而分散式容器系統中的「負載平衡器」會「輪流」把請求分配給各個執行你應用的容器。因此，每個請求都可能由多個「複製的容器」中的其中一個來處理。\n\n通常這個「負載平衡器」也能處理送往叢集中「其他」應用的請求（例如不同網域，或不同 URL 路徑前綴），並把通訊轉送到該「其他」應用對應的容器。\n\n### 每個容器一個行程 { #one-process-per-container }\n\n在這種情境中，你大概會希望「每個容器只有一個（Uvicorn）行程」，因為你已在叢集層級處理了複本。\n\n所以這種情況下，你「不會」想在容器中使用多個 workers（例如用 `--workers` 命令列選項）。你會想每個容器只執行「一個 Uvicorn 行程」（但可能有多個容器）。\n\n在容器內再放一個行程管理器（如同多 workers 的情況）只會增加「不必要的複雜度」，而你很可能已用叢集系統處理好了。\n\n### 多行程容器與特殊情境 { #containers-with-multiple-processes-and-special-cases }\n\n當然，有些「特殊情況」你可能會想在「一個容器內」執行數個「Uvicorn worker 行程」。\n\n在這些情況中，你可以用 `--workers` 命令列選項來設定要啟動的 workers 數量：\n\n```{ .dockerfile .annotate }\nFROM python:3.14\n\nWORKDIR /code\n\nCOPY ./requirements.txt /code/requirements.txt\n\nRUN pip install --no-cache-dir --upgrade -r /code/requirements.txt\n\nCOPY ./app /code/app\n\n# (1)!\nCMD [\"fastapi\", \"run\", \"app/main.py\", \"--port\", \"80\", \"--workers\", \"4\"]\n```\n\n1. 這裡我們使用 `--workers` 命令列選項把 worker 數量設定為 4。\n\n以下是一些合理的例子：\n\n#### 簡單應用 { #a-simple-app }\n\n如果你的應用「足夠簡單」，可以在「單一伺服器」而非叢集上執行，你可能會希望在容器內使用行程管理器。\n\n#### Docker Compose { #docker-compose }\n\n如果你部署到「單一伺服器」（非叢集），且使用「Docker Compose」，那麼你無法輕易（用 Docker Compose）在保有共用網路與「負載平衡」的同時管理容器複本。\n\n那你可能會想要「單一容器」搭配「行程管理器」，在其中啟動「多個 worker 行程」。\n\n---\n\n重點是，這些「都不是」必須盲目遵守的「鐵律」。你可以用這些想法來「評估你的使用情境」，並決定對你的系統最好的做法，看看如何管理以下概念：\n\n* 安全性 - HTTPS\n* 開機自動執行\n* 失敗重啟\n* 複本（執行的行程數量）\n* 記憶體\n* 啟動前的前置步驟\n\n## 記憶體 { #memory }\n\n如果你採用「每個容器一個行程」，那每個容器（若有複本則多個容器）所消耗的記憶體會是相對明確、穩定且有限的。\n\n接著你可以在容器管理系統（例如 Kubernetes）的設定中為容器設定相同的記憶體限制與需求。如此，它就能在「可用的機器」上「複製容器」，並考量容器所需的記憶體量與叢集中機器的可用記憶體。\n\n若你的應用「很簡單」，這可能「不是問題」，你可能不需要指定嚴格的記憶體限制。但如果你「使用大量記憶體」（例如使用機器學習模型），你應該檢查實際消耗的記憶體，並調整「每台機器上執行的容器數量」（也許還要為叢集加機器）。\n\n若你採用「每個容器多個行程」，你就得確保啟動的行程數量不會「超過可用記憶體」。\n\n## 啟動前的前置步驟與容器 { #previous-steps-before-starting-and-containers }\n\n如果你使用容器（例如 Docker、Kubernetes），那有兩種主要做法可用。\n\n### 多個容器 { #multiple-containers }\n\n如果你有「多個容器」，且每個容器大概都只執行「單一行程」（例如在一個 Kubernetes 叢集中），那你可能會想要一個「獨立的容器」來完成「前置步驟」的工作，並只在單一容器、單一行程中執行，接著才啟動多個複本的工作容器。\n\n/// info | 資訊\n\n如果你使用 Kubernetes，這大概會是一個 [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/)。\n\n///\n\n如果你的情境中，讓那些前置步驟「平行重複執行多次」沒有問題（例如不是在跑資料庫遷移，而只是檢查資料庫是否就緒），那也可以把這些步驟放在每個容器中、在啟動主要行程前執行。\n\n### 單一容器 { #single-container }\n\n如果你的架構很簡單，只有「單一容器」，接著在其中啟動多個「worker 行程」（或也可能就一個行程），那你可以在相同的容器中、於啟動應用行程前先執行這些前置步驟。\n\n### 基底 Docker 映像 { #base-docker-image }\n\n曾經有一個官方的 FastAPI Docker 映像：[tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker)。但現在已被棄用。⛔️\n\n你大概「不應該」使用這個基底 Docker 映像（或其他類似的）。\n\n如果你使用 Kubernetes（或其他）並已在叢集層級設定「複本」、使用多個「容器」。在這些情況下，更好的做法是如上所述[從零建置映像](#build-a-docker-image-for-fastapi)。\n\n若你需要多個 workers，只要使用 `--workers` 命令列選項即可。\n\n/// note | 技術細節\n\n這個 Docker 映像是在 Uvicorn 尚未支援管理與重啟死亡 workers 的年代所建立，因此需要用 Gunicorn 搭配 Uvicorn，為了讓 Gunicorn 管理並重啟 Uvicorn workers，而引入了相當多的複雜度。\n\n但現在 Uvicorn（以及 `fastapi` 指令）已支援使用 `--workers`，因此沒有理由使用一個基底 Docker 映像，而不是建置你自己的（而且實際上程式碼量也差不多 😅）。\n\n///\n\n## 部署容器映像 { #deploy-the-container-image }\n\n擁有容器（Docker）映像後，有多種部署方式。\n\n例如：\n\n* 在單一伺服器上使用 Docker Compose\n* 使用 Kubernetes 叢集\n* 使用 Docker Swarm Mode 叢集\n* 使用像 Nomad 之類的其他工具\n* 使用會接收你的容器映像並代為部署的雲端服務\n\n## 使用 `uv` 的 Docker 映像 { #docker-image-with-uv }\n\n如果你使用 [uv](https://github.com/astral-sh/uv) 來安裝與管理專案，你可以參考他們的 [uv Docker 指南](https://docs.astral.sh/uv/guides/integration/docker/)。\n\n## 總結 { #recap }\n\n使用容器系統（例如 Docker 與 Kubernetes）可以相對直接地處理所有「部署概念」：\n\n* HTTPS\n* 開機自動執行\n* 失敗重啟\n* 複本（執行的行程數量）\n* 記憶體\n* 啟動前的前置步驟\n\n多數情況下，你大概不會想用任何基底映像，而是「從零建置容器映像」，以官方的 Python Docker 映像為基礎。\n\n善用 `Dockerfile` 中指令的「順序」與「Docker 快取」，你可以「最小化建置時間」，提升生產力（並避免無聊）。😎\n"
  },
  {
    "path": "docs/zh-hant/docs/deployment/fastapicloud.md",
    "content": "# FastAPI Cloud { #fastapi-cloud }\n\n你可以用「一行指令」把你的 FastAPI 應用程式部署到 [FastAPI Cloud](https://fastapicloud.com)。如果你還沒加入，快去登記等候名單吧！🚀\n\n## 登入 { #login }\n\n請先確認你已經有 **FastAPI Cloud** 帳號（我們已從等候名單邀請你 😉）。\n\n然後登入：\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n## 部署 { #deploy }\n\n現在用「一行指令」部署你的應用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n就這樣！現在你可以透過該 URL 造訪你的應用。✨\n\n## 關於 FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** 由 **FastAPI** 的作者與團隊打造。\n\n它以最少的心力，精簡化建立、部署與存取 API 的流程。\n\n它把使用 FastAPI 開發應用的優異開發體驗，延伸到將它們部署到雲端。🎉\n\n它也會為你處理部署應用時多數需要面對的事項，例如：\n\n* HTTPS\n* 多副本，並可依據請求自動擴縮\n* 等等。\n\nFastAPI Cloud 是 *FastAPI and friends* 開源專案的主要贊助者與資金提供者。✨\n\n## 部署到其他雲端供應商 { #deploy-to-other-cloud-providers }\n\nFastAPI 是基於標準的開源專案。你可以把 FastAPI 應用部署到你選擇的任何雲端供應商。\n\n請依照你的雲端供應商的指南，使用他們的方式部署 FastAPI 應用。🤓\n\n## 部署到你自己的伺服器 { #deploy-your-own-server }\n\n在這份「部署」指南的後續內容中，我也會教你所有細節，讓你了解背後發生了什麼、需要做哪些事，以及如何自行部署 FastAPI 應用，包括在你自己的伺服器上。🤓\n"
  },
  {
    "path": "docs/zh-hant/docs/deployment/https.md",
    "content": "# 關於 HTTPS { #about-https }\n\n人們很容易以為 HTTPS 只是「啟用或未啟用」的功能。\n\n但實際上複雜得多。\n\n/// tip\n\n如果你趕時間或不在意細節，可以直接看後續章節，依照逐步指引用不同方式完成設定。\n\n///\n\n想從使用者角度學習 HTTPS 基礎，請參考 [https://howhttps.works/](https://howhttps.works/)。\n\n接著以開發者角度，談幾個關於 HTTPS 需要注意的重點：\n\n* 對於 HTTPS，伺服器需要擁有由**第三方**簽發的**「憑證」**。\n    * 這些憑證實際上是向第三方**取得**，不是「自己產生」。\n* 憑證有**有效期**。\n    * 會**過期**。\n    * 過期後需要**續期**，也就是再向第三方**重新取得**。\n* 連線加密發生在 **TCP 層**。\n    * 那是在 **HTTP 的下一層**。\n    * 因此，**憑證與加密**的處理會在 **進入 HTTP 之前**完成。\n* **TCP 不知道「網域」**，只知道 IP 位址。\n    * 關於**特定網域**的資訊會放在 **HTTP 資料**中。\n* **HTTPS 憑證**是為某個**特定網域**背書，但通訊協定與加密在 TCP 層進行，發生在**尚未知道**要處理哪個網域之前。\n* **預設**情況下，這表示你每個 IP 位址**只能**使用**一張 HTTPS 憑證**。\n    * 不論你的伺服器多強或你在上面跑的應用多小。\n    * 不過，這是有**解法**的。\n* 在 **TLS** 協定（在 HTTP 之前於 TCP 層處理加密的協定）上有個**擴充**稱為 **[<abbr title=\"Server Name Indication - 伺服器名稱指示\">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**。\n    * 這個 SNI 擴充讓單一伺服器（單一 IP 位址）可以擁有**多張 HTTPS 憑證**，並服務**多個 HTTPS 網域／應用**。\n    * 要讓它運作，伺服器上必須有一個**單一**的元件（程式）在**公用 IP**上監聽，且持有伺服器上的**所有 HTTPS 憑證**。\n* 在取得安全連線**之後**，通訊協定**仍然是 HTTP**。\n    * 雖然透過 **HTTP 協定**傳送，但內容是**加密**的。\n\n常見做法是讓伺服器（機器、主機等）上跑**一個程式／HTTP 伺服器**來**管理所有 HTTPS 相關工作**：接收**加密的 HTTPS 請求**、將其**解密**成**純 HTTP 請求**轉交給同台伺服器上實際運行的 HTTP 應用（本例為 **FastAPI** 應用）、從應用取得 **HTTP 回應**、再用合適的 **HTTPS 憑證**將其**加密**並以 **HTTPS** 傳回給用戶端。這類伺服器常被稱為 **[TLS 終止代理](https://en.wikipedia.org/wiki/TLS_termination_proxy)**。\n\n可作為 TLS 終止代理的選項包括：\n\n* Traefik（也可處理憑證續期）\n* Caddy（也可處理憑證續期）\n* Nginx\n* HAProxy\n\n## Let's Encrypt { #lets-encrypt }\n\n在 Let's Encrypt 之前，這些 **HTTPS 憑證**是由受信任的第三方販售。\n\n取得這些憑證的流程過去相當繁瑣，需要許多手續，且憑證相當昂貴。\n\n之後出現了 **[Let's Encrypt](https://letsencrypt.org/)**。\n\n它是 Linux Foundation 的專案，能**免費**且自動化地提供 **HTTPS 憑證**。這些憑證採用標準的密碼學安全機制，且有效期較短（約 3 個月），因此因為壽命短，**安全性其實更好**。\n\n網域會被安全驗證，憑證會自動產生。這也讓憑證續期得以自動化。\n\n目標是讓憑證的申請與續期自動化，讓你**永遠免費使用安全的 HTTPS**。\n\n## 給開發者的 HTTPS { #https-for-developers }\n\n以下以逐步範例說明一個 HTTPS API 可能長什麼樣子，著重於對開發者重要的概念。\n\n### 網域名稱 { #domain-name }\n\n通常會先**取得**一個**網域名稱**，接著在 DNS 伺服器（可能是同一個雲端供應商）中設定它。\n\n你可能會租一台雲端伺服器（虛擬機）或類似的服務，並擁有一個<dfn title=\"不會隨時間改變；非動態的\">固定</dfn>的**公用 IP 位址**。\n\n在 DNS 伺服器中，你會設定一個紀錄（「`A record`」）指向**你的網域**所對應的**伺服器公用 IP 位址**。\n\n這通常在初次建置時設定一次即可。\n\n/// tip\n\n「網域名稱」是發生在 HTTPS 之前的事情，但一切都依賴網域與 IP 位址，因此在此一併說明。\n\n///\n\n### DNS { #dns }\n\n現在聚焦在實際的 HTTPS 部分。\n\n首先，瀏覽器會向 **DNS 伺服器**查詢該**網域的 IP**，例如 `someapp.example.com`。\n\nDNS 伺服器會回覆要使用的**IP 位址**，那就是你在 DNS 伺服器中設定的、伺服器對外的公用 IP 位址。\n\n<img src=\"/img/deployment/https/https01.drawio.svg\">\n\n### TLS 握手開始 { #tls-handshake-start }\n\n接著瀏覽器會連線到該 IP 的 **443 埠**（HTTPS 預設埠）。\n\n通訊的第一部分是建立用戶端與伺服器之間的連線，並協商要使用哪些金鑰等密碼參數。\n\n<img src=\"/img/deployment/https/https02.drawio.svg\">\n\n用戶端與伺服器為建立 TLS 連線而進行的這段互動稱為 **TLS 握手**。\n\n### 帶 SNI 擴充的 TLS { #tls-with-sni-extension }\n\n在特定的**IP 位址**與特定**埠**上，同一時間**只能有一個行程**在監聽。可以在同一個 IP 上監聽不同埠，但每個 IP 與埠的組合只能有一個行程。\n\nTLS（HTTPS）預設使用 `443` 埠，因此我們需要用到這個埠。\n\n由於只能有一個行程監聽該埠，負責監聽的會是 **TLS 終止代理**。\n\nTLS 終止代理會存取一張或多張 **TLS 憑證**（HTTPS 憑證）。\n\n透過上面提到的 **SNI 擴充**，TLS 終止代理會根據用戶端預期的網域，從可用的 TLS（HTTPS）憑證中挑選本次連線要用的憑證。\n\n在這個例子中，會使用 `someapp.example.com` 的憑證。\n\n<img src=\"/img/deployment/https/https03.drawio.svg\">\n\n用戶端**信任**簽發該 TLS 憑證的單位（本例為 Let's Encrypt，稍後會再談），因此可以**驗證**憑證有效。\n\n接著，用戶端與 TLS 終止代理會以該憑證為基礎，**協商後續如何加密**整段 **TCP 通訊**。至此完成 **TLS 握手**。\n\n之後，用戶端與伺服器之間就有一條**已加密的 TCP 連線**，這就是 TLS 所提供的能力。接著他們可以在這條連線上開始實際的 **HTTP** 通訊。\n\n這也就是 **HTTPS** 的本質：在**安全的 TLS 連線**內傳送一般的 **HTTP**，而非在純（未加密）的 TCP 連線上。\n\n/// tip\n\n請注意，加密發生在 **TCP 層**，不是在 HTTP 層。\n\n///\n\n### HTTPS 請求 { #https-request }\n\n現在用戶端與伺服器（更精確地說，是瀏覽器與 TLS 終止代理）之間已有**加密的 TCP 連線**，他們可以開始進行 **HTTP** 通訊。\n\n因此，用戶端送出一個 **HTTPS 請求**。它其實就是透過加密的 TLS 連線發送的一個 HTTP 請求。\n\n<img src=\"/img/deployment/https/https04.drawio.svg\">\n\n### 解密請求 { #decrypt-the-request }\n\nTLS 終止代理會依照先前協商的方式**解密請求**，並將**純（已解密）的 HTTP 請求**轉交給運行應用的行程（例如以 Uvicorn 執行的 FastAPI 應用行程）。\n\n<img src=\"/img/deployment/https/https05.drawio.svg\">\n\n### HTTP 回應 { #http-response }\n\n應用會處理該請求，並將**純（未加密）的 HTTP 回應**送回 TLS 終止代理。\n\n<img src=\"/img/deployment/https/https06.drawio.svg\">\n\n### HTTPS 回應 { #https-response }\n\nTLS 終止代理接著會依照先前協商（起點是 `someapp.example.com` 的憑證）的方式**加密回應**，並傳回給瀏覽器。\n\n接著，瀏覽器會驗證回應是否合法、是否使用正確的金鑰加密等。然後**解密回應**並處理。\n\n<img src=\"/img/deployment/https/https07.drawio.svg\">\n\n用戶端（瀏覽器）會知道回應來自正確的伺服器，因為它使用了先前依據 **HTTPS 憑證**所協商的密碼機制。\n\n### 多個應用 { #multiple-applications }\n\n同一台（或多台）伺服器上可以有**多個應用**，例如其他 API 程式或資料庫。\n\n雖然只有一個行程可以處理特定 IP 與埠的組合（本例中的 TLS 終止代理），但其他應用／行程也都能在伺服器上運行，只要它們不使用相同的**公用 IP 與埠**組合即可。\n\n<img src=\"/img/deployment/https/https08.drawio.svg\">\n\n如此一來，TLS 終止代理就能為**多個網域**、多個應用處理 HTTPS 與憑證，並把請求轉發到對應的應用。\n\n### 憑證續期 { #certificate-renewal }\n\n在未來某個時間點，每張憑證都會**過期**（自取得起約 3 個月）。\n\n之後，會有另一個程式（有時是另一個程式，有時也可能就是同一個 TLS 終止代理）與 Let's Encrypt 溝通並續期憑證。\n\n<img src=\"/img/deployment/https/https.drawio.svg\">\n\n**TLS 憑證**是**綁定網域名稱**，不是綁定 IP 位址。\n\n因此，要續期憑證時，續期程式需要向憑證機構（Let's Encrypt）**證明**它的確**擁有並控制該網域**。\n\n為了達成這點、並兼顧不同應用情境，有幾種常見方式：\n\n* **修改部分 DNS 紀錄**。\n    * 為此，續期程式需要支援該 DNS 供應商的 API，因此依你使用的 DNS 供應商不同，這方式可能可行或不可行。\n* **作為伺服器運行**（至少在憑證申請過程中）於該網域對應的公用 IP 上。\n    * 如前所述，同一時間只有一個行程能在特定 IP 與埠上監聽。\n    * 這也是為什麼讓同一個 TLS 終止代理一併處理憑證續期非常實用的原因之一。\n    * 否則你可能得暫停 TLS 終止代理、啟動續期程式申請憑證、將憑證配置到 TLS 終止代理，然後再重啟 TLS 終止代理。這並不理想，因為在 TLS 終止代理停機期間，你的應用將不可用。\n\n在不中斷服務的同時完成整個續期流程，是你會想用**獨立系統（TLS 終止代理）來處理 HTTPS**、而不是直接把 TLS 憑證掛在應用伺服器（例如 Uvicorn）上的主要原因之一。\n\n## 代理轉發標頭 { #proxy-forwarded-headers }\n\n當你使用代理處理 HTTPS 時，你的**應用伺服器**（例如透過 FastAPI CLI 啟動的 Uvicorn）其實不知道任何 HTTPS 的處理流程，它是用純 HTTP 與 **TLS 終止代理**通訊。\n\n這個**代理**通常會在把請求轉發給**應用伺服器**之前，臨時加入一些 HTTP 標頭，讓應用伺服器知道該請求是由代理**轉發**過來的。\n\n/// note | 技術細節\n\n這些代理標頭包括：\n\n* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)\n* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)\n* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)\n\n///\n\n然而，因為**應用伺服器**並不知道自己在受信任的**代理**之後，預設情況下它不會信任這些標頭。\n\n但你可以設定**應用伺服器**去信任由**代理**送來的「轉發」標頭。若你使用 FastAPI CLI，可以用 *CLI 參數* `--forwarded-allow-ips` 指定應信任哪些 IP 來的「轉發」標頭。\n\n例如，如果**應用伺服器**只會接收來自受信任**代理**的連線，你可以設定 `--forwarded-allow-ips=\"*\"`，也就是信任所有來源 IP，因為實際上它只會收到**代理**那個 IP 送來的請求。\n\n如此一來，應用就能知道自己的對外 URL、是否使用 HTTPS、網域為何等資訊。\n\n這在正確處理重新導向等情境時很有用。\n\n/// tip\n\n你可以在文件 [在代理後方 - 啟用代理轉發標頭](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers) 中了解更多。\n\n///\n\n## 重點回顧 { #recap }\n\n擁有 **HTTPS** 非常重要，而且在多數情況都相當**關鍵**。作為開發者，你在 HTTPS 上的大部分投入其實是**理解這些概念**及其運作方式。\n\n一旦掌握了**給開發者的 HTTPS 基礎**，你就能輕鬆組合並設定不同工具，讓一切管理變得簡單。\n\n在接下來的章節中，我會示範幾個為 **FastAPI** 應用設定 **HTTPS** 的具體例子。🔒\n"
  },
  {
    "path": "docs/zh-hant/docs/deployment/index.md",
    "content": "# 部署 { #deployment }\n\n部署 **FastAPI** 應用程式相對容易。\n\n## 部署是什麼意思 { #what-does-deployment-mean }\n\n**部署**應用程式指的是執行一系列必要的步驟，使其能夠**讓使用者存取和使用**。\n\n對於一個 **Web API**，部署通常涉及將其放置在**遠端伺服器**上，並使用性能優良且穩定的**伺服器程式**，確保使用者能夠高效、無中斷地存取應用程式，且不會遇到問題。\n\n這與**開發**階段形成鮮明對比，在**開發**階段，你會不斷更改程式碼、破壞程式碼、修復程式碼，然後停止和重新啟動開發伺服器等。\n\n## 部署策略 { #deployment-strategies }\n\n根據你的使用場景和使用工具，有多種方法可以實現此目的。\n\n你可以使用一些工具自行**部署伺服器**，你也可以使用能為你完成部分工作的**雲端服務**，或其他可能的選項。\n\n例如，我們（FastAPI 的團隊）打造了 [**FastAPI Cloud**](https://fastapicloud.com)，讓 FastAPI 應用程式部署到雲端變得盡可能流暢，並保持與使用 FastAPI 開發時相同的開發者體驗。\n\n我將向你展示在部署 **FastAPI** 應用程式時你可能應該記住的一些主要概念（儘管其中大部分適用於任何其他類型的 Web 應用程式）。\n\n在接下來的部分中，你將看到更多需要記住的細節以及一些技巧。 ✨\n"
  },
  {
    "path": "docs/zh-hant/docs/deployment/manually.md",
    "content": "# 手動執行伺服器 { #run-a-server-manually }\n\n## 使用 `fastapi run` 指令 { #use-the-fastapi-run-command }\n\n簡而言之，使用 `fastapi run` 來啟動你的 FastAPI 應用：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>2306215</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n```\n\n</div>\n\n這在多數情況下都適用。😎\n\n你可以用這個指令在容器、伺服器等環境中啟動你的 FastAPI 應用。\n\n## ASGI 伺服器 { #asgi-servers }\n\n我們再深入一些細節。\n\nFastAPI 採用建立 Python 網頁框架與伺服器的標準 <abbr title=\"Asynchronous Server Gateway Interface - 非同步伺服器閘道介面\">ASGI</abbr>。FastAPI 是一個 ASGI 網頁框架。\n\n在遠端伺服器機器上執行 FastAPI 應用（或任何 ASGI 應用）所需的關鍵是 ASGI 伺服器程式，例如 Uvicorn；`fastapi` 指令預設就是使用它。\n\n有數個替代方案，包括：\n\n* [Uvicorn](https://www.uvicorn.dev/)：高效能 ASGI 伺服器。\n* [Hypercorn](https://hypercorn.readthedocs.io/)：支援 HTTP/2 與 Trio 等功能的 ASGI 伺服器。\n* [Daphne](https://github.com/django/daphne)：為 Django Channels 打造的 ASGI 伺服器。\n* [Granian](https://github.com/emmett-framework/granian)：針對 Python 應用的 Rust HTTP 伺服器。\n* [NGINX Unit](https://unit.nginx.org/howto/fastapi/)：NGINX Unit 是輕量且多功能的網頁應用執行環境。\n\n## 伺服器機器與伺服器程式 { #server-machine-and-server-program }\n\n有個命名上的小細節請留意。💡\n\n「server（伺服器）」一詞常同時用來指遠端／雲端電腦（實體或虛擬機器），也用來指在該機器上執行的程式（例如 Uvicorn）。\n\n因此看到「server」時，文意可能指這兩者之一。\n\n指涉遠端機器時，常稱為 server、machine、VM（虛擬機器）、node 等，這些都指某種遠端機器（通常執行 Linux），你會在其上執行程式。\n\n## 安裝伺服器程式 { #install-the-server-program }\n\n安裝 FastAPI 時會附帶一個可用於生產環境的伺服器 Uvicorn，你可以用 `fastapi run` 來啟動它。\n\n但你也可以手動安裝 ASGI 伺服器。\n\n請先建立並啟用一個 [虛擬環境](../virtual-environments.md)，接著再安裝伺服器程式。\n\n例如，安裝 Uvicorn：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"uvicorn[standard]\"\n\n---> 100%\n```\n\n</div>\n\n其他 ASGI 伺服器的安裝流程也大致相同。\n\n/// tip\n\n加入 `standard` 會讓 Uvicorn 安裝並使用一些建議的額外相依套件。\n\n其中包含 `uvloop`，它是 `asyncio` 的高效能替代實作，可大幅提升並行效能。\n\n當你用 `pip install \"fastapi[standard]\"` 安裝 FastAPI 時，也會一併取得 `uvicorn[standard]`。\n\n///\n\n## 執行伺服器程式 { #run-the-server-program }\n\n如果你是手動安裝 ASGI 伺服器，通常需要提供特定格式的 import 字串，讓它能匯入你的 FastAPI 應用：\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 80\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)\n```\n\n</div>\n\n/// note\n\n指令 `uvicorn main:app` 指的是：\n\n* `main`：檔案 `main.py`（Python「模組」）。\n* `app`：在 `main.py` 中以 `app = FastAPI()` 建立的物件。\n\n等同於：\n\n```Python\nfrom main import app\n```\n\n///\n\n其他 ASGI 伺服器也有類似的指令，詳見各自的文件。\n\n/// warning\n\nUvicorn 與其他伺服器支援 `--reload` 選項，對開發期間很有幫助。\n\n`--reload` 會消耗更多資源，也較不穩定等。\n\n它在開發階段很實用，但在生產環境中不應使用。\n\n///\n\n## 部署觀念 { #deployment-concepts }\n\n上述範例會啟動伺服器程式（如 Uvicorn），以單一行程在指定連接埠（如 `80`）上監聽所有 IP（`0.0.0.0`）。\n\n這是基本概念。但你很可能還需要處理一些額外事項，例如：\n\n* 安全性 - HTTPS\n* 開機自動啟動\n* 自動重啟\n* 多副本（執行的行程數量）\n* 記憶體\n* 啟動前需要執行的前置步驟\n\n在下一章節我會進一步說明這些觀念、思考方式，以及對應的處理策略與實作範例。🚀\n"
  },
  {
    "path": "docs/zh-hant/docs/deployment/server-workers.md",
    "content": "# 伺服器工作處理序 - 使用 Uvicorn Workers { #server-workers-uvicorn-with-workers }\n\n我們回顧一下先前提到的部署概念：\n\n* 安全 - HTTPS\n* 系統啟動時執行\n* 重啟\n* **副本（正在執行的處理序數量）**\n* 記憶體\n* 啟動前的前置作業\n\n到目前為止，依照文件中的教學，你大多是透過 `fastapi` 指令啟動一個執行 Uvicorn 的伺服器程式，且只跑單一處理序。\n\n在部署應用時，你通常會希望有一些處理序的複製來善用多核心，並能處理更多請求。\n\n如同前一章關於 [部署概念](concepts.md) 所示，你可以採用多種策略。\n\n這裡會示範如何使用 `fastapi` 指令或直接使用 `uvicorn` 指令，搭配 Uvicorn 的工作處理序（worker processes）。\n\n/// info\n\n如果你使用容器（例如 Docker 或 Kubernetes），我會在下一章說明更多：[容器中的 FastAPI - Docker](docker.md)。\n\n特別是，在 **Kubernetes** 上執行時，你多半會選擇不要使用 workers，而是每個容器只跑一個 **Uvicorn 單一處理序**。我會在該章節中進一步說明。\n\n///\n\n## 多個工作處理序 { #multiple-workers }\n\n你可以用命令列選項 `--workers` 來啟動多個 workers：\n\n//// tab | `fastapi`\n\n如果你使用 `fastapi` 指令：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run --workers 4 <u style=\"text-decoration-style:solid\">main.py</u>\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting production server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000/docs</u></font>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started parent process <b>[</b><font color=\"#34E2E2\"><b>27365</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27368</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27369</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27370</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>27367</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n////\n\n//// tab | `uvicorn`\n\n如果你偏好直接使用 `uvicorn` 指令：\n\n<div class=\"termy\">\n\n```console\n$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4\n<font color=\"#A6E22E\">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)\n<font color=\"#A6E22E\">INFO</font>:     Started parent process [<font color=\"#A1EFE4\"><b>27365</b></font>]\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27368</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27369</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27370</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n<font color=\"#A6E22E\">INFO</font>:     Started server process [<font color=\"#A1EFE4\">27367</font>]\n<font color=\"#A6E22E\">INFO</font>:     Waiting for application startup.\n<font color=\"#A6E22E\">INFO</font>:     Application startup complete.\n```\n\n</div>\n\n////\n\n這裡唯一新增的選項是 `--workers`，告訴 Uvicorn 要啟動 4 個工作處理序。\n\n你也會看到它顯示每個處理序的 **PID**，`27365` 是父處理序（這是**處理序管理器**），另外每個工作處理序各有一個：`27368`、`27369`、`27370`、`27367`。\n\n## 部署概念 { #deployment-concepts }\n\n你已經看到如何使用多個 **workers** 來將應用的執行進行**平行化**，善用 CPU 的**多核心**，並能服務**更多請求**。\n\n在上面的部署概念清單中，使用 workers 主要能幫助到**副本**這一塊，並對**重啟**也有一點幫助，但你仍需要處理其他部分：\n\n* **安全 - HTTPS**\n* **系統啟動時執行**\n* ***重啟***\n* 副本（正在執行的處理序數量）\n* **記憶體**\n* **啟動前的前置作業**\n\n## 容器與 Docker { #containers-and-docker }\n\n在下一章 [容器中的 FastAPI - Docker](docker.md) 我會說明一些策略，幫你處理其他的**部署概念**。\n\n我會示範如何**從零建立你的映像檔**來執行單一 Uvicorn 處理序。這個流程相當簡單，而且在使用像 **Kubernetes** 這類分散式容器管理系統時，大多情況也會這麼做。\n\n## 重點回顧 { #recap }\n\n你可以在 `fastapi` 或 `uvicorn` 指令中使用 `--workers` 這個 CLI 選項來啟動多個工作處理序，以善用**多核心 CPU**，**平行**執行多個處理序。\n\n如果你要自行建置**自己的部署系統**，你可以運用這些工具與想法，同時自行處理其他部署概念。\n\n接著看看下一章關於在容器（例如 Docker 與 Kubernetes）中使用 **FastAPI**。你會看到那些工具也有簡單的方法來解決其他**部署概念**。✨\n"
  },
  {
    "path": "docs/zh-hant/docs/deployment/versions.md",
    "content": "# 關於 FastAPI 版本 { #about-fastapi-versions }\n\n**FastAPI** 已經在許多應用與系統的生產環境中使用，且測試涵蓋率維持在 100%。同時開發仍在快速推進。\n\n經常加入新功能、定期修復錯誤，程式碼也在持續改進。\n\n這就是為什麼目前版本仍為 `0.x.x`，這表示每個版本都可能包含破壞性變更。這遵循 [語意化版本（Semantic Versioning）](https://semver.org/) 的慣例。\n\n你現在就可以用 **FastAPI** 建置生產環境的應用（而且你可能已經這麼做一段時間了），只要確保你使用的版本能與其餘程式碼正確相容。\n\n## 鎖定你的 `fastapi` 版本 { #pin-your-fastapi-version }\n\n首先，你應該將你使用的 **FastAPI** 版本「鎖定（pin）」到你知道對你的應用可正常運作的最新特定版本。\n\n例如，假設你的應用使用 `0.112.0` 版本。\n\n如果你使用 `requirements.txt` 檔案，可以這樣指定版本：\n\n```txt\nfastapi[standard]==0.112.0\n```\n\n這表示你會使用完全相同的 `0.112.0` 版本。\n\n或你也可以這樣鎖定：\n\n```txt\nfastapi[standard]>=0.112.0,<0.113.0\n```\n\n這表示會使用 `0.112.0`（含）以上但小於 `0.113.0` 的版本，例如 `0.112.2` 也會被接受。\n\n如果你使用其他安裝管理工具，例如 `uv`、Poetry、Pipenv 等，它們也都有可用來指定套件特定版本的方法。\n\n## 可用版本 { #available-versions }\n\n你可以在 [發行說明](../release-notes.md) 查看可用版本（例如用來確認目前最新版本）。\n\n## 關於版本 { #about-versions }\n\n依照語意化版本的慣例，任何低於 `1.0.0` 的版本都可能加入破壞性變更。\n\nFastAPI 也遵循慣例：任何「PATCH」版本變更僅用於修正錯誤與非破壞性變更。\n\n/// tip\n\n「PATCH」是最後一個數字，例如在 `0.2.3` 中，PATCH 版本是 `3`。\n\n///\n\n因此，你可以將版本鎖定為如下形式：\n\n```txt\nfastapi>=0.45.0,<0.46.0\n```\n\n破壞性變更與新功能會在「MINOR」版本加入。\n\n/// tip\n\n「MINOR」是中間的數字，例如在 `0.2.3` 中，MINOR 版本是 `2`。\n\n///\n\n## 升級 FastAPI 版本 { #upgrading-the-fastapi-versions }\n\n你應該為你的應用撰寫測試。\n\n在 **FastAPI** 中這很容易（感謝 Starlette），請參考文件：[測試](../tutorial/testing.md)\n\n有了測試之後，你就可以將 **FastAPI** 升級到較新的版本，並透過執行測試來確保所有程式碼都能正確運作。\n\n如果一切正常，或在完成必要調整且所有測試通過之後，就可以把你的 `fastapi` 鎖定到該新的版本。\n\n## 關於 Starlette { #about-starlette }\n\n你不應鎖定 `starlette` 的版本。\n\n不同的 **FastAPI** 版本會使用特定較新的 Starlette 版本。\n\n因此，你可以直接讓 **FastAPI** 使用正確的 Starlette 版本。\n\n## 關於 Pydantic { #about-pydantic }\n\nPydantic 在其測試中涵蓋了 **FastAPI** 的測試，因此 Pydantic 的新版本（高於 `1.0.0`）一律與 FastAPI 相容。\n\n你可以將 Pydantic 鎖定到任何高於 `1.0.0`、適合你的版本。\n\n例如：\n\n```txt\npydantic>=2.7.0,<3.0.0\n```\n"
  },
  {
    "path": "docs/zh-hant/docs/editor-support.md",
    "content": "# 編輯器支援 { #editor-support }\n\n官方的 [FastAPI 擴充套件](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) 透過支援路徑操作（path operation）探索、導覽，以及 FastAPI Cloud 部署與即時日誌串流，強化你的 FastAPI 開發流程。\n\n想了解更多關於此擴充套件的細節，請參考其 [GitHub 儲存庫](https://github.com/fastapi/fastapi-vscode) 中的 README。\n\n## 安裝與設定 { #setup-and-installation }\n\n**FastAPI 擴充套件** 同時提供給 [VS Code](https://code.visualstudio.com/) 與 [Cursor](https://www.cursor.com/)。你可以在各編輯器的擴充套件面板中直接安裝：搜尋「FastAPI」，並選擇由 **FastAPI Labs** 發佈的擴充套件。此擴充套件同樣可在瀏覽器版編輯器（如 [vscode.dev](https://vscode.dev) 與 [github.dev](https://github.dev)）中使用。\n\n### 應用程式探索 { #application-discovery }\n\n預設情況下，擴充套件會自動在你的工作區中，掃描會實例化 `FastAPI()` 的檔案，以發現 FastAPI 應用程式。若自動偵測無法因應你的專案結構，你可以在 `pyproject.toml` 的 `[tool.fastapi]` 中，或在 VS Code 設定的 `fastapi.entryPoint` 中，使用模組標記法（例如 `myapp.main:app`）指定入口點。\n\n## 功能 { #features }\n\n- **Path Operation Explorer** - 顯示應用程式中所有 <dfn title=\"路由、端點\">*路徑操作*</dfn> 的側邊欄樹狀檢視。點擊即可跳至任一路由或 router 定義。\n- **Route Search** - 使用 <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>（macOS：<kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>E</kbd>）依路徑、方法或名稱進行搜尋。\n- **CodeLens Navigation** - 在測試用 client 呼叫（例如 `client.get('/items')`）上方提供可點連結，一鍵跳至對應的路徑操作，讓你在測試與實作間快速切換。\n- **Deploy to FastAPI Cloud** - 一鍵將你的應用程式部署到 [FastAPI Cloud](https://fastapicloud.com/)。\n- **Stream Application Logs** - 從部署於 FastAPI Cloud 的應用程式即時串流日誌，並支援層級篩選與文字搜尋。\n\n若你想熟悉此擴充套件的功能，可開啟命令面板（<kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>；macOS：<kbd>Cmd</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd>），選擇 \"Welcome: Open walkthrough...\"，然後挑選 \"Get started with FastAPI\" walkthrough。\n"
  },
  {
    "path": "docs/zh-hant/docs/environment-variables.md",
    "content": "# 環境變數 { #environment-variables }\n\n/// tip\n\n如果你已經知道什麼是「環境變數」並且知道如何使用它們，你可以放心跳過這一部分。\n\n///\n\n環境變數（也稱為「**env var**」）是一個獨立於 Python 程式碼**之外**的變數，它存在於**作業系統**中，可以被你的 Python 程式碼（或其他程式）讀取。\n\n環境變數對於處理應用程式**設定**（作為 Python **安裝**的一部分等方面）非常有用。\n\n## 建立和使用環境變數 { #create-and-use-env-vars }\n\n你在 **shell（終端機）**中就可以**建立**和使用環境變數，並不需要用到 Python：\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// 你可以使用以下指令建立一個名為 MY_NAME 的環境變數\n$ export MY_NAME=\"Wade Wilson\"\n\n// 然後，你可以在其他程式中使用它，例如\n$ echo \"Hello $MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// 建立一個名為 MY_NAME 的環境變數\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// 在其他程式中使用它，例如\n$ echo \"Hello $Env:MY_NAME\"\n\nHello Wade Wilson\n```\n\n</div>\n\n////\n\n## 在 Python 中讀取環境變數 { #read-env-vars-in-python }\n\n你也可以在 Python **之外**的終端機中建立環境變數（或使用其他方法），然後在 Python 中**讀取**它們。\n\n例如，你可以建立一個名為 `main.py` 的檔案，其中包含以下內容：\n\n```Python hl_lines=\"3\"\nimport os\n\nname = os.getenv(\"MY_NAME\", \"World\")\nprint(f\"Hello {name} from Python\")\n```\n\n/// tip\n\n第二個參數是 [`os.getenv()`](https://docs.python.org/3.8/library/os.html#os.getenv) 的預設回傳值。\n\n如果沒有提供，預設值為 `None`，這裡我們提供 `\"World\"` 作為預設值。\n\n///\n\n然後你可以呼叫這個 Python 程式：\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n// 這裡我們還沒有設定環境變數\n$ python main.py\n\n// 因為我們沒有設定環境變數，所以我們得到的是預設值\n\nHello World from Python\n\n// 但是如果我們事先建立過一個環境變數\n$ export MY_NAME=\"Wade Wilson\"\n\n// 然後再次呼叫程式\n$ python main.py\n\n// 現在就可以讀取到環境變數了\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n// 這裡我們還沒有設定環境變數\n$ python main.py\n\n// 因為我們沒有設定環境變數，所以我們得到的是預設值\n\nHello World from Python\n\n// 但是如果我們事先建立過一個環境變數\n$ $Env:MY_NAME = \"Wade Wilson\"\n\n// 然後再次呼叫程式\n$ python main.py\n\n// 現在就可以讀取到環境變數了\n\nHello Wade Wilson from Python\n```\n\n</div>\n\n////\n\n由於環境變數可以在程式碼之外設定，但可以被程式碼讀取，並且不必與其他檔案一起儲存（提交到 `git`），因此通常用於配置或**設定**。\n\n你還可以為**特定的程式呼叫**建立特定的環境變數，該環境變數僅對該程式可用，且僅在其執行期間有效。\n\n要實現這一點，只需在同一行內（程式本身之前）建立它：\n\n<div class=\"termy\">\n\n```console\n// 在這個程式呼叫的同一行中建立一個名為 MY_NAME 的環境變數\n$ MY_NAME=\"Wade Wilson\" python main.py\n\n// 現在就可以讀取到環境變數了\n\nHello Wade Wilson from Python\n\n// 在此之後這個環境變數將不再存在\n$ python main.py\n\nHello World from Python\n```\n\n</div>\n\n/// tip\n\n你可以在 [The Twelve-Factor App: 配置](https://12factor.net/config) 中了解更多資訊。\n\n///\n\n## 型別和驗證 { #types-and-validation }\n\n這些環境變數只能處理**文字字串**，因為它們是位於 Python 範疇之外的，必須與其他程式和作業系統的其餘部分相容（甚至與不同的作業系統相容，如 Linux、Windows、macOS）。\n\n這意味著從環境變數中讀取的**任何值**在 Python 中都將是一個 `str`，任何型別轉換或驗證都必須在程式碼中完成。\n\n你將在[進階使用者指南 - 設定和環境變數](./advanced/settings.md)中了解更多關於使用環境變數處理**應用程式設定**的資訊。\n\n## `PATH` 環境變數 { #path-environment-variable }\n\n有一個**特殊的**環境變數稱為 **`PATH`**，作業系統（Linux、macOS、Windows）用它來查找要執行的程式。\n\n`PATH` 變數的值是一個長字串，由 Linux 和 macOS 上的冒號 `:` 分隔的目錄組成，而在 Windows 上則是由分號 `;` 分隔的。\n\n例如，`PATH` 環境變數可能如下所示：\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\n這意味著系統應該在以下目錄中查找程式：\n\n-   `/usr/local/bin`\n-   `/usr/bin`\n-   `/bin`\n-   `/usr/sbin`\n-   `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32\n```\n\n這意味著系統應該在以下目錄中查找程式：\n\n-   `C:\\Program Files\\Python312\\Scripts`\n-   `C:\\Program Files\\Python312`\n-   `C:\\Windows\\System32`\n\n////\n\n當你在終端機中輸入一個**指令**時，作業系統會在 `PATH` 環境變數中列出的**每個目錄**中**查找**程式。\n\n例如，當你在終端機中輸入 `python` 時，作業系統會在該列表中的**第一個目錄**中查找名為 `python` 的程式。\n\n如果找到了，那麼作業系統將**使用它**；否則，作業系統會繼續在**其他目錄**中查找。\n\n### 安裝 Python 並更新 `PATH` { #installing-python-and-updating-the-path }\n\n安裝 Python 時，可能會詢問你是否要更新 `PATH` 環境變數。\n\n//// tab | Linux, macOS\n\n假設你安裝了 Python，並將其安裝在目錄 `/opt/custompython/bin` 中。\n\n如果你選擇更新 `PATH` 環境變數，那麼安裝程式會將 `/opt/custompython/bin` 加入到 `PATH` 環境變數中。\n\n它看起來大致會是這樣：\n\n```plaintext\n/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/custompython/bin\n```\n\n如此一來，當你在終端機輸入 `python` 時，系統會在 `/opt/custompython/bin` 中找到 Python 程式（最後一個目錄）並使用它。\n\n////\n\n//// tab | Windows\n\n假設你安裝了 Python，並將其安裝在目錄 `C:\\opt\\custompython\\bin` 中。\n\n如果你選擇更新 `PATH` 環境變數，那麼安裝程式會將 `C:\\opt\\custompython\\bin` 加入到 `PATH` 環境變數中。\n\n```plaintext\nC:\\Program Files\\Python312\\Scripts;C:\\Program Files\\Python312;C:\\Windows\\System32;C:\\opt\\custompython\\bin\n```\n\n如此一來，當你在終端機輸入 `python` 時，系統會在 `C:\\opt\\custompython\\bin` 中找到 Python 程式（最後一個目錄）並使用它。\n\n////\n\n因此，如果你輸入：\n\n<div class=\"termy\">\n\n```console\n$ python\n```\n\n</div>\n\n//// tab | Linux, macOS\n\n系統會在 `/opt/custompython/bin` 中**找到** `python` 程式並執行它。\n\n這大致等同於輸入以下指令：\n\n<div class=\"termy\">\n\n```console\n$ /opt/custompython/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows\n\n系統會在 `C:\\opt\\custompython\\bin\\python` 中**找到** `python` 程式並執行它。\n\n這大致等同於輸入以下指令：\n\n<div class=\"termy\">\n\n```console\n$ C:\\opt\\custompython\\bin\\python\n```\n\n</div>\n\n////\n\n當學習[虛擬環境](virtual-environments.md)時，這些資訊將會很有用。\n\n## 結論 { #conclusion }\n\n透過這個教學，你應該對**環境變數**是什麼以及如何在 Python 中使用它們有了基本的了解。\n\n你也可以在 [環境變數的維基百科條目](https://en.wikipedia.org/wiki/Environment_variable) 中閱讀更多。\n\n在許多情況下，環境變數的用途和適用性可能不會立刻顯現。但是在開發過程中，它們會在許多不同的場景中出現，因此瞭解它們是非常必要的。\n\n例如，你在接下來的[虛擬環境](virtual-environments.md)章節中將需要這些資訊。\n"
  },
  {
    "path": "docs/zh-hant/docs/fastapi-cli.md",
    "content": "# FastAPI CLI { #fastapi-cli }\n\n**FastAPI <abbr title=\"command line interface - 命令列介面\">CLI</abbr>** 是一個命令列程式，你可以用它來啟動你的 FastAPI 應用程式、管理你的 FastAPI 專案，等等。\n\n當你安裝 FastAPI（例如使用 `pip install \"fastapi[standard]\"`）時，會附帶一個可以在終端機執行的命令列程式。\n\n要在開發時運行你的 FastAPI 應用程式，你可以使用 `fastapi dev` 指令：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories with\n             <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with the\n             following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C to\n             quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n/// tip\n\n在生產環境請改用 `fastapi run`，不要用 `fastapi dev`。🚀\n\n///\n\n在內部，**FastAPI CLI** 使用 [Uvicorn](https://www.uvicorn.dev)，這是一個高效能、適用於生產環境的 ASGI 伺服器。😎\n\n`fastapi` CLI 會嘗試自動偵測要執行的 FastAPI 應用程式，預設假設它是檔案 `main.py` 中名為 `app` 的物件（或其他幾種變體）。\n\n不過你也可以明確設定要使用的 app。\n\n## 在 `pyproject.toml` 中設定應用程式的 `entrypoint` { #configure-the-app-entrypoint-in-pyproject-toml }\n\n你可以在 `pyproject.toml` 檔案中指定你的 app 位置，例如：\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\n這個 `entrypoint` 會告訴 `fastapi` 指令應該像這樣匯入 app：\n\n```python\nfrom main import app\n```\n\n如果你的程式碼結構是這樣：\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\n那麼你應該把 `entrypoint` 設為：\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\n這等同於：\n\n```python\nfrom backend.main import app\n```\n\n### 帶路徑的 `fastapi dev` { #fastapi-dev-with-path }\n\n你也可以把檔案路徑傳給 `fastapi dev` 指令，它會推測要使用的 FastAPI app 物件：\n\n```console\n$ fastapi dev main.py\n```\n\n但這樣每次呼叫 `fastapi` 指令時都得記得傳入正確的路徑。\n\n此外，其他工具可能找不到它，例如 [VS Code 擴充套件](editor-support.md) 或 [FastAPI Cloud](https://fastapicloud.com)，因此建議在 `pyproject.toml` 中使用 `entrypoint`。\n\n## `fastapi dev` { #fastapi-dev }\n\n執行 `fastapi dev` 會啟動開發模式。\n\n預設情況下，**auto-reload** 功能是啟用的，當你對程式碼進行修改時，伺服器會自動重新載入。這會消耗較多資源，並且可能比禁用時更不穩定。因此，你應該只在開發環境中使用此功能。它也會在 IP 位址 `127.0.0.1` 上監聽，這是用於你的機器與自身通訊的 IP 位址（`localhost`）。\n\n## `fastapi run` { #fastapi-run }\n\n執行 `fastapi run` 會以生產模式啟動 FastAPI。\n\n預設情況下，**auto-reload** 功能是禁用的。它也會在 IP 位址 `0.0.0.0` 上監聽，表示會監聽所有可用的 IP 位址，這樣任何能與該機器通訊的人都可以公開存取它。這通常是你在生產環境中運行應用程式的方式，例如在容器中運行時。\n\n在大多數情況下，你會（也應該）有一個「終止代理」在外層幫你處理 HTTPS；這取決於你如何部署應用程式，你的服務供應商可能會幫你處理，或者你需要自己設置。\n\n/// tip\n\n你可以在[部署文件](deployment/index.md)中了解更多相關資訊。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/features.md",
    "content": "# 特性 { #features }\n\n## FastAPI 特性 { #fastapi-features }\n\n**FastAPI** 提供了以下內容：\n\n### 建立在開放標準的基礎上 { #based-on-open-standards }\n\n* 使用 [**OpenAPI**](https://github.com/OAI/OpenAPI-Specification) 來建立 API，包含 <dfn title=\"也稱為：端點、路由\">路徑</dfn>、<dfn title=\"也稱為 HTTP 方法，例如 POST、GET、PUT、DELETE\">操作</dfn>、參數、請求內文、安全性等宣告。\n* 使用 [**JSON Schema**](https://json-schema.org/)（因為 OpenAPI 本身就是基於 JSON Schema）自動生成資料模型文件。\n* 經過縝密的研究後圍繞這些標準進行設計，而不是事後在已有系統上附加的一層功能。\n* 這也讓我們在多種語言中可以使用自動**用戶端程式碼生成**。\n\n### 能夠自動生成文件 { #automatic-docs }\n\nFastAPI 能生成互動式 API 文件和探索性的 Web 使用者介面。由於該框架基於 OpenAPI，因此有多種選擇，預設提供了兩種。\n\n* [**Swagger UI**](https://github.com/swagger-api/swagger-ui) 提供互動式探索，讓你可以直接從瀏覽器呼叫並測試你的 API 。\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* 使用 [**ReDoc**](https://github.com/Rebilly/ReDoc) 的替代 API 文件。\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### 現代 Python { #just-modern-python }\n\n這一切都基於標準的 **Python 型別**宣告（感謝 Pydantic）。無需學習新的語法，只需使用標準的現代 Python。\n\n如果你需要 2 分鐘來學習如何使用 Python 型別（即使你不使用 FastAPI），可以看看這個簡短的教學：[Python 型別](python-types.md)。\n\n如果你寫帶有 Python 型別的程式碼：\n\n```Python\nfrom datetime import date\n\nfrom pydantic import BaseModel\n\n# 宣告一個變數為 string\n# 並在函式中獲得 editor support\ndef main(user_id: str):\n    return user_id\n\n\n# 宣告一個 Pydantic model\nclass User(BaseModel):\n    id: int\n    name: str\n    joined: date\n```\n\n可以像這樣來使用：\n\n```Python\nmy_user: User = User(id=3, name=\"John Doe\", joined=\"2018-07-19\")\n\nsecond_user_data = {\n    \"id\": 4,\n    \"name\": \"Mary\",\n    \"joined\": \"2018-11-30\",\n}\n\nmy_second_user: User = User(**second_user_data)\n```\n\n/// info\n\n`**second_user_data` 意思是:\n\n將 `second_user_data` 字典直接作為 key-value 引數傳遞，等同於：`User(id=4, name=\"Mary\", joined=\"2018-11-30\")`\n\n///\n\n### 多種編輯器支援 { #editor-support }\n\n整個框架的設計是為了讓使用變得簡單且直觀，在開始開發之前，所有決策都在多個編輯器上進行了測試，以確保提供最佳的開發體驗。\n\n在最近的 Python 開發者調查中，我們能看到[被使用最多的功能是 autocompletion](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features)。\n\n整個 **FastAPI** 框架就是基於這一點，任何地方都可以進行自動補齊。\n\n你幾乎不需要經常來回看文件。\n\n在這裡，你的編輯器可能會這樣幫助你：\n\n* 在 [Visual Studio Code](https://code.visualstudio.com/) 中:\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n* 在 [PyCharm](https://www.jetbrains.com/pycharm/) 中:\n\n![editor support](https://fastapi.tiangolo.com/img/pycharm-completion.png)\n\n你將能進行程式碼補齊，這是在之前你可能曾認為不可能的事。例如，請求 JSON body（可能是巢狀的）中的鍵 `price`。\n\n這樣比較不會輸錯鍵名，不用來回翻看文件，也不用來回滾動尋找你最後使用的 `username` 或者 `user_name`。\n\n### 簡潔 { #short }\n\nFastAPI 為你提供了**預設值**，讓你不必在初期進行繁瑣的配置，一切都可以自動運作。如果你有更具體的需求，則可以進行調整和自定義，\n\n但預設情況下，一切都「直接可用」。\n\n### 驗證 { #validation }\n\n* 驗證大部分（甚至所有？）的 Python **資料型別**，包括：\n    * JSON 物件 (`dict`)。\n    * JSON 陣列 (`list`) 定義項目型別。\n    * 字串 (`str`) 欄位，定義最小或最大長度。\n    * 數字 (`int`, `float`) 與其最大值和最小值等。\n\n* 驗證外來的型別，比如:\n    * URL\n    * Email\n    * UUID\n    * ...等等。\n\n所有的驗證都由完善且強大的 **Pydantic** 處理。\n\n### 安全性及身份驗證 { #security-and-authentication }\n\nFastAPI 已經整合了安全性和身份驗證的功能，但不會強制與特定的資料庫或資料模型進行綁定。\n\nOpenAPI 中定義的安全模式，包括：\n\n* HTTP 基本認證。\n* **OAuth2**（也使用 **JWT tokens**）。在 [OAuth2 with JWT](tutorial/security/oauth2-jwt.md) 查看教學。\n* API 密鑰，在：\n    * 標頭（Header）\n    * 查詢參數\n    * Cookies，等等。\n\n加上來自 Starlette（包括 **session cookie**）的所有安全特性。\n\n所有的這些都是可重複使用的工具和套件，可以輕鬆與你的系統、資料儲存（Data Stores）、關聯式資料庫（RDBMS）以及非關聯式資料庫（NoSQL）等等整合。\n\n### 依賴注入（Dependency Injection） { #dependency-injection }\n\nFastAPI 有一個使用簡單，但是非常強大的 <dfn title='也稱為「components」、「resources」、「services」、「providers」'><strong>依賴注入</strong></dfn> 系統。\n\n* 依賴項甚至可以有自己的依賴，從而形成一個層級或**依賴圖**的結構。\n* 所有**自動化處理**都由框架完成。\n* 依賴項不僅能從請求中提取資料，還能**對 API 的路徑操作進行強化**，並自動生成文檔。\n* 即使是依賴項中定義的*路徑操作參數*，也會**自動進行驗證**。\n* 支持複雜的用戶身份驗證系統、**資料庫連接**等。\n* 不與資料庫、前端等進行強制綁定，但能輕鬆整合它們。\n\n### 無限制「擴充功能」 { #unlimited-plug-ins }\n\n或者說，無需其他額外配置，直接導入並使用你所需要的程式碼。\n\n任何整合都被設計得非常簡單易用（通過依賴注入），你只需用與*路徑操作*相同的結構和語法，用兩行程式碼就能為你的應用程式建立一個「擴充功能」。\n\n### 測試 { #tested }\n\n* 100% <dfn title=\"自動化測試所涵蓋的程式碼量\">測試覆蓋率</dfn>。\n* 100% <dfn title=\"Python 型別註解；有了它你的編輯器和外部工具可以提供更好的支援\">型別註解</dfn>的程式碼庫。\n* 已能夠在生產環境應用程式中使用。\n\n## Starlette 特性 { #starlette-features }\n\n**FastAPI** 完全相容且基於 [**Starlette**](https://www.starlette.dev/)。所以，你有其他的 Starlette 程式碼也能正常運作。`FastAPI` 實際上是 `Starlette` 的一個子類別。所以，如果你已經知道或者使用過 Starlette，大部分的功能會以相同的方式運作。\n\n通過 **FastAPI** 你可以獲得所有 **Starlette** 的特性（FastAPI 就像加強版的 Starlette）：\n\n* 性能極其出色。它是 [Python 可用的最快框架之一，和 **NodeJS** 及 **Go** 相當](https://github.com/encode/starlette#performance)。\n* **支援 WebSocket**。\n* 能在行程內處理背景任務。\n* 支援啟動和關閉事件。\n* 有基於 HTTPX 的測試用戶端。\n* 支援 **CORS**、GZip、靜態檔案、串流回應。\n* 支援 **Session 和 Cookie** 。\n* 100% 測試覆蓋率。\n* 100% 型別註釋的程式碼庫。\n\n## Pydantic 特性 { #pydantic-features }\n\n**FastAPI** 完全相容且基於 [**Pydantic**](https://docs.pydantic.dev/)。所以，你有其他 Pydantic 程式碼也能正常工作。\n\n相容包括基於 Pydantic 的外部函式庫，例如用於資料庫的 <abbr title=\"Object-Relational Mapper - 物件關聯對映器\">ORM</abbr>s、<abbr title=\"Object-Document Mapper - 物件文件對映器\">ODM</abbr>s。\n\n這也意味著在很多情況下，你可以把從請求中獲得的物件**直接傳到資料庫**，因為所有資料都會自動進行驗證。\n\n反之亦然，在很多情況下，你也可以把從資料庫中獲取的物件**直接傳給客戶端**。\n\n通過 **FastAPI** 你可以獲得所有 **Pydantic** 的特性（FastAPI 基於 Pydantic 做了所有的資料處理）：\n\n* **更簡單**：\n    * 不需要學習新的 micro-language 來定義結構。\n    * 如果你知道 Python 型別，你就知道如何使用 Pydantic。\n* 和你的 **<abbr title=\"Integrated Development Environment - 整合開發環境: 類似於程式碼編輯器\">IDE</abbr>/<dfn title=\"檢查程式碼錯誤的程式\">linter</dfn>/brain** 都能好好配合：\n    * 因為 Pydantic 的資料結構其實就是你自己定義的類別實例，所以自動補齊、linting、mypy 以及你的直覺都能很好地在經過驗證的資料上發揮作用。\n* 驗證**複雜結構**：\n    * 使用 Pydantic 模型時，你可以把資料結構分層設計，並且用 Python 的 `List` 和 `Dict` 等型別來定義。\n    * 驗證器讓我們可以輕鬆地定義和檢查複雜的資料結構，並把它們轉換成 JSON Schema 進行記錄。\n    * 你可以擁有深層**巢狀的 JSON** 物件，並對它們進行驗證和註釋。\n* **可擴展**：\n    * Pydantic 讓我們可以定義客製化的資料型別，或者你可以使用帶有 validator 裝飾器的方法來擴展模型中的驗證功能。\n* 100% 測試覆蓋率。\n"
  },
  {
    "path": "docs/zh-hant/docs/help-fastapi.md",
    "content": "# 協助 FastAPI - 取得協助 { #help-fastapi-get-help }\n\n你喜歡 **FastAPI** 嗎？\n\n你願意協助 FastAPI、其他使用者，以及作者嗎？\n\n或是你想獲得 **FastAPI** 的協助？\n\n有一些非常簡單的方式可以幫忙（有些只需要點一兩下）。\n\n而且也有多種方式可以取得協助。\n\n## 訂閱電子報 { #subscribe-to-the-newsletter }\n\n你可以訂閱（不常發送的）[**FastAPI 與夥伴**電子報](newsletter.md)，隨時掌握：\n\n* 關於 FastAPI 與夥伴的最新消息 🚀\n* 教學指南 📝\n* 新功能 ✨\n* 破壞性變更 🚨\n* 小技巧與祕訣 ✅\n\n## 在 X（Twitter）關注 FastAPI { #follow-fastapi-on-x-twitter }\n\n[在 **X（Twitter）** 關注 @fastapi](https://x.com/fastapi)，獲取 **FastAPI** 的最新消息。🐦\n\n## 在 GitHub 為 **FastAPI** 加星 { #star-fastapi-in-github }\n\n你可以在 GitHub 為 FastAPI「加星」（點擊右上角的 star 星號按鈕）：[https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)。⭐️\n\n加上星標後，其他使用者會更容易發現它，並看到它已經對許多人很有幫助。\n\n## 追蹤 GitHub 儲存庫的發行版 { #watch-the-github-repository-for-releases }\n\n你可以在 GitHub「watch」FastAPI（點擊右上角的「watch」按鈕）：[https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)。👀\n\n在那裡你可以選擇「Releases only」。\n\n這樣每當 **FastAPI** 有新的發行（新版本）包含錯誤修復與新功能時，你就會收到通知（寄到你的電子郵件）。\n\n## 與作者連結 { #connect-with-the-author }\n\n你可以與作者 [我（Sebastián Ramírez / `tiangolo`）](https://tiangolo.com) 建立連結。\n\n你可以：\n\n* [在 **GitHub** 關注我](https://github.com/tiangolo)。\n    * 看看我建立的其他開源專案，可能對你有幫助。\n    * 關注我以便知道我何時建立新的開源專案。\n* [在 **X（Twitter）**](https://x.com/tiangolo) 或 [Mastodon](https://fosstodon.org/@tiangolo) 關注我。\n    * 告訴我你如何使用 FastAPI（我很愛聽這些）。\n    * 接收我發布公告或釋出新工具時的消息。\n    * 你也可以[在 X（Twitter）關注 @fastapi](https://x.com/fastapi)（另外的帳號）。\n* [在 **LinkedIn** 關注我](https://www.linkedin.com/in/tiangolo/)。\n    * 接收我發布公告或釋出新工具時的消息（不過我更常用 X（Twitter）🤷‍♂）。\n* 在 [**Dev.to**](https://dev.to/tiangolo) 或 [**Medium**](https://medium.com/@tiangolo) 閱讀我寫的內容（或關注我）。\n    * 閱讀我的想法、文章，以及我建立的工具。\n    * 關注我以便在我發佈新內容時能第一時間看到。\n\n## 在 X（Twitter）發文談談 **FastAPI** { #tweet-about-fastapi }\n\n[發一則關於 **FastAPI** 的推文](https://x.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/fastapi/fastapi)，讓我與其他人知道你為什麼喜歡它。🎉\n\n我很樂於聽到 **FastAPI** 是如何被使用、你喜歡它的哪些地方、在哪個專案／公司使用它等等。\n\n## 為 FastAPI 投票 { #vote-for-fastapi }\n\n* [在 Slant 為 **FastAPI** 投票](https://www.slant.co/options/34241/~fastapi-review)。\n* [在 AlternativeTo 為 **FastAPI** 投票](https://alternativeto.net/software/fastapi/about/)。\n* [在 StackShare 表示你使用 **FastAPI**](https://stackshare.io/pypi-fastapi)。\n\n## 在 GitHub 幫助他人解答問題 { #help-others-with-questions-in-github }\n\n你可以嘗試幫助他人回答以下地方的問題：\n\n* [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered)\n* [GitHub Issues](https://github.com/fastapi/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+)\n\n很多時候你可能已經知道這些問題的解答。🤓\n\n如果你經常幫大家解決問題，你會成為官方的 [FastAPI 專家](fastapi-people.md#fastapi-experts)。🎉\n\n請記得，最重要的是：盡量友善。大家可能帶著挫折而來，很多時候提問方式不夠理想，但請盡你所能保持友善。🤗\n\n**FastAPI** 社群的理念是友善且歡迎大家。同時，也不要接受霸凌或對他人不尊重的行為。我們要彼此照顧。\n\n---\n\n以下是在（Discussions 或 Issues）中幫助他人解決問題的方式：\n\n### 先理解問題 { #understand-the-question }\n\n* 先確認你是否能理解提問者的**目的**與使用情境。\n\n* 接著看看問題（絕大多數是提問）是否**清楚**。\n\n* 很多時候，提問是基於使用者自己想像中的解法，但可能有**更好**的方法。如果你能更理解他們的問題與使用情境，你也許能提出更好的**替代解法**。\n\n* 如果你無法理解問題，請要求提供更多**細節**。\n\n### 重現問題 { #reproduce-the-problem }\n\n在大多數情況與問題中，都會與對方的**原始程式碼**有關。\n\n很多時候他們只會貼出一小段程式碼，但那不足以**重現問題**。\n\n* 你可以請他們提供一個[最小可重現範例](https://stackoverflow.com/help/minimal-reproducible-example)，讓你可以**複製貼上**並在本機執行，看到與他們相同的錯誤或行為，或更好地理解他們的使用情境。\n\n* 如果你有心力，你也可以嘗試自己**建立一個範例**，僅依據問題描述來還原。不過請記得這可能很耗時，或許更好的是先請他們把問題說清楚。\n\n### 提出解法建議 { #suggest-solutions }\n\n* 在能夠理解問題後，你可以給出可能的**答案**。\n\n* 很多時候，最好能理解他們的**底層問題或使用情境**，因為可能有比他們嘗試的方法更好的解決之道。\n\n### 請求關閉議題 { #ask-to-close }\n\n如果他們回覆了，你很可能已經解決了他們的問題，恭喜，**你是英雄**！🦸\n\n* 現在，如果問題已解決，你可以請他們：\n    * 在 GitHub Discussions：把某則留言標記為**答案**。\n    * 在 GitHub Issues：**關閉**該 issue。\n\n## 追蹤 GitHub 儲存庫 { #watch-the-github-repository }\n\n你可以在 GitHub「watch」FastAPI（點擊右上角的「watch」按鈕）：[https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)。👀\n\n如果你選擇「Watching」而不是「Releases only」，當有人建立新的 issue 或問題時你會收到通知。你也可以指定只想被通知新的 issues、discussions、PR 等等。\n\n接著你就可以嘗試幫忙解決那些問題。\n\n## 提問 { #ask-questions }\n\n你可以在 GitHub 儲存庫[建立一個新的問題（Question）](https://github.com/fastapi/fastapi/discussions/new?category=questions)，例如用來：\n\n* 提出**問題**或詢問某個**疑難**。\n* 建議一個新的**功能**。\n\n**注意**：如果你這麼做，那我也會請你去幫助其他人。😉\n\n## 審核 Pull Request { #review-pull-requests }\n\n你可以幫我審查他人的 Pull Request。\n\n再強調一次，請盡量保持友善。🤗\n\n---\n\n以下是審查 Pull Request 時需要注意與如何進行：\n\n### 先理解要解的問題 { #understand-the-problem }\n\n* 首先，確認你**理解了該 Pull Request 想解決的問題**。可能在 GitHub Discussion 或 issue 中有更長的討論。\n\n* 也很有可能這個 Pull Request 其實不需要，因為問題可以用**不同的方法**解決。那你就可以提出或詢問那個方向。\n\n### 不用太在意風格 { #dont-worry-about-style }\n\n* 不要太擔心像是提交訊息（commit message）的風格，我會用 squash and merge 並手動調整提交內容。\n\n* 也不用太在意程式碼風格規範，已經有自動化工具在檢查。\n\n如果還有其他風格或一致性的需求，我會直接提出請求，或是在上面再補上需要的修改提交。\n\n### 檢查程式碼 { #check-the-code }\n\n* 檢查並閱讀程式碼，看看是否合理，**在本機執行**並確認它是否真的解決了問題。\n\n* 然後**留言**說你做了這些，這樣我才知道你真的檢查過了。\n\n/// info\n\n很遺憾，我不能僅因為一個 PR 有好幾個核可就直接信任它。\n\n發生過好幾次，PR 有 3、5 個甚至更多核可，可能是因為描述很吸引人，但當我實際檢查時，它其實是壞的、有 bug，或是根本沒有解決它宣稱要解決的問題。😅\n\n所以，真的很重要的是你要實際閱讀並執行程式碼，並在留言中讓我知道你做過了。🤓\n\n///\n\n* 如果 PR 有機會再被簡化，你可以提出要求，但沒必要太過挑剔，很多事情是主觀的（我自己也會有主觀看法 🙈），所以最好聚焦在關鍵的事情上。\n\n### 測試 { #tests }\n\n* 幫我確認 PR 有**測試**。\n\n* 檢查在 PR 之前，測試會**失敗**。🚨\n\n* 然後檢查在 PR 之後，測試會**通過**。✅\n\n* 很多 PR 並沒有測試，你可以**提醒**他們加上測試，或甚至**建議**一些測試。這是最花時間的事之一，而你可以在這方面幫上很大的忙。\n\n* 接著也請留言你嘗試了什麼，這樣我就知道你有檢查過。🤓\n\n## 建立 Pull Request { #create-a-pull-request }\n\n你可以透過 Pull Request 來[貢獻](contributing.md)原始碼，例如：\n\n* 修正文檔中你發現的錯字。\n* 分享你建立或發現的 FastAPI 相關文章、影片或 podcast，方法是[編輯這個檔案](https://github.com/fastapi/fastapi/edit/master/docs/en/data/external_links.yml)。\n    * 請確保把你的連結加到對應章節的開頭。\n* 協助把[文件翻譯](contributing.md#translations)成你的語言。\n    * 你也可以幫忙審查他人提交的翻譯。\n* 提議新的文件章節。\n* 修復既有的 issue／bug。\n    * 記得要加上測試。\n* 新增一個功能。\n    * 記得要加上測試。\n    * 若相關，請記得補上文件。\n\n## 協助維護 FastAPI { #help-maintain-fastapi }\n\n幫我一起維護 **FastAPI**！🤓\n\n有很多事情要做，而其中大多數其實**你**就能完成。\n\n你現在就能做的主要任務有：\n\n* [在 GitHub 幫助他人解答問題](#help-others-with-questions-in-github)（見上方章節）。\n* [審核 Pull Request](#review-pull-requests)（見上方章節）。\n\n這兩件事是**最耗時**的。這也是維護 FastAPI 的主要工作。\n\n如果你能在這方面幫我，**你就是在幫我維護 FastAPI**，並確保它能**更快更好地前進**。🚀\n\n## 加入聊天室 { #join-the-chat }\n\n加入 👥 [Discord 聊天伺服器](https://discord.gg/VQjSZaeJmf) 👥，與 FastAPI 社群的其他人一起交流。\n\n/// tip\n\n若要提問，請到 [GitHub Discussions](https://github.com/fastapi/fastapi/discussions/new?category=questions)，在那裡更有機會獲得[FastAPI 專家](fastapi-people.md#fastapi-experts)的協助。\n\n聊天室請僅用於其他一般性的交流。\n\n///\n\n### 不要在聊天室提問 { #dont-use-the-chat-for-questions }\n\n請記得，由於聊天室允許較「自由的對話」，很容易提出過於籠統、較難回答的問題，因此你可能不會得到答案。\n\n在 GitHub 上，模板會引導你寫出合適的提問，讓你更容易得到好的解答，甚至在提問前就自己解決問題。而且在 GitHub 上，我能確保最終都會回覆（即使需要一些時間）。我個人無法在聊天系統做到這一點。😅\n\n聊天系統中的對話也不像 GitHub 那樣容易被搜尋，因此問題與答案可能在對話中淹沒。而且只有 GitHub 上的問題與回答才會被計入成為[FastAPI 專家](fastapi-people.md#fastapi-experts)，因此你在 GitHub 上更有機會獲得關注。\n\n另一方面，聊天室裡有成千上萬的使用者，所以幾乎隨時都有很大的機會能找到人聊天。😄\n\n## 贊助作者 { #sponsor-the-author }\n\n如果你的**產品／公司**依賴或與 **FastAPI** 相關，且你想觸及它的使用者，你可以透過 [GitHub sponsors](https://github.com/sponsors/tiangolo) 贊助作者（我）。依據不同級別，你可能會得到一些額外福利，例如在文件中顯示徽章。🎁\n\n---\n\n感謝！🚀\n"
  },
  {
    "path": "docs/zh-hant/docs/history-design-future.md",
    "content": "# 歷史、設計與未來 { #history-design-and-future }\n\n不久之前，[一位 **FastAPI** 使用者提問](https://github.com/fastapi/fastapi/issues/3#issuecomment-454956920)：\n\n> 這個專案的歷史是什麼？看起來它在短短幾週內從默默無名變得非常厲害 [...]\n\n以下是其中一小段歷史。\n\n## 替代方案 { #alternatives }\n\n多年來我一直在打造具有複雜需求的 API（機器學習、分散式系統、非同步工作、NoSQL 資料庫等），並帶領多個開發團隊。\n\n在此過程中，我需要調查、測試並使用許多替代方案。\n\n**FastAPI** 的歷史，在很大程度上也是其前身工具的歷史。\n\n如在[替代方案](alternatives.md)一節所述：\n\n<blockquote markdown=\"1\">\n\n若沒有他人的前期成果，就不會有 **FastAPI**。\n\n先前已有許多工具啟發了它的誕生。\n\n我曾經多年避免再去打造一個新框架。起初我嘗試用各種不同的框架、外掛與工具，來滿足 **FastAPI** 涵蓋的所有功能。\n\n但在某個時刻，別無選擇，只能打造一個同時提供所有這些功能的東西，取過去工具之長，並以可能的最佳方式加以結合，還運用了以往甚至不存在的語言功能（Python 3.6+ 的型別提示）。\n\n</blockquote>\n\n## 調研 { #investigation }\n\n透過實際使用這些替代方案，我得以向它們學習、汲取想法，並以我能為自己與合作開發團隊找到的最佳方式加以整合。\n\n例如，很清楚理想上應以標準的 Python 型別提示為基礎。\n\n同時，最佳做法就是採用現有標準。\n\n因此，在開始撰寫 **FastAPI** 之前，我花了好幾個月研究 OpenAPI、JSON Schema、OAuth2 等規範，了解它們之間的關係、重疊與差異。\n\n## 設計 { #design }\n\n接著，我花時間設計作為使用者（作為使用 FastAPI 的開發者）時希望擁有的開發者「API」。\n\n我在最受歡迎的 Python 編輯器中測試了多個想法：PyCharm、VS Code、基於 Jedi 的編輯器。\n\n根據最新的 [Python 開發者調查](https://www.jetbrains.com/research/python-developers-survey-2018/#development-tools)，這些工具涵蓋約 80% 的使用者。\n\n這表示 **FastAPI** 已針對 80% 的 Python 開發者所使用的編輯器進行過專門測試。而由於其他多數編輯器的行為也類似，這些優點擴及實際上幾乎所有編輯器。\n\n藉此我找到了盡可能減少程式碼重複、在各處提供自動補全、型別與錯誤檢查等的最佳方式。\n\n一切都是為了讓所有開發者都能擁有最佳的開發體驗。\n\n## 需求 { #requirements }\n\n在測試多種替代方案後，我決定採用 [**Pydantic**](https://docs.pydantic.dev/)，因為它的優勢。\n\n隨後我也對它做出貢獻，使其完全符合 JSON Schema、支援以不同方式定義約束，並依據在多款編輯器中的測試結果改進編輯器支援（型別檢查、自動補全）。\n\n在開發過程中，我也對 [**Starlette**](https://www.starlette.dev/)（另一個關鍵依賴）做出貢獻。\n\n## 開發 { #development }\n\n當我開始著手實作 **FastAPI** 本身時，多數拼圖已經就緒，設計已定，需求與工具已備齊，對各項標準與規範的理解也清晰且新鮮。\n\n## 未來 { #future }\n\n到目前為止，**FastAPI** 及其理念已經對許多人有幫助。\n\n相較先前的替代方案，它更適合許多使用情境，因而被選用。\n\n許多開發者與團隊（包括我和我的團隊）已經在他們的專案中依賴 **FastAPI**。\n\n但仍有許多改進與功能即將到來。\n\n**FastAPI** 的前景非常光明。\n\n也非常感謝[你的幫助](help-fastapi.md)。\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/authentication-error-status-code.md",
    "content": "# 使用舊的 403 身分驗證錯誤狀態碼 { #use-old-403-authentication-error-status-codes }\n\n在 FastAPI 版本 `0.122.0` 之前，當內建的安全工具在身分驗證失敗後回傳錯誤給用戶端時，會使用 HTTP 狀態碼 `403 Forbidden`。\n\n從 FastAPI 版本 `0.122.0` 起，改為使用更合適的 HTTP 狀態碼 `401 Unauthorized`，並在回應中依據 HTTP 規範加上合理的 `WWW-Authenticate` 標頭，參考 [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235#section-3.1)、[RFC 9110](https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized)。\n\n但如果你的用戶端因某些原因依賴於舊行為，你可以在你的 security 類別中覆寫 `make_not_authenticated_error` 方法以恢復舊的行為。\n\n例如，你可以建立 `HTTPBearer` 的子類別，讓它回傳 `403 Forbidden` 錯誤，而不是預設的 `401 Unauthorized` 錯誤：\n\n{* ../../docs_src/authentication_error_status_code/tutorial001_an_py310.py hl[9:13] *}\n\n/// tip\n注意這個函式回傳的是例外物件本身，而不是直接拋出它。拋出的動作會在其餘的內部程式碼中處理。\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/conditional-openapi.md",
    "content": "# 條件式 OpenAPI { #conditional-openapi }\n\n如果需要，你可以用設定與環境變數，依據執行環境有條件地調整 OpenAPI，甚至完全停用它。\n\n## 關於安全性、API 與文件 { #about-security-apis-and-docs }\n\n在正式環境中隱藏文件 UI *不應該* 是用來保護 API 的方式。\n\n這並不會為你的 API 增添任何額外的安全性，*路徑操作* 仍舊照常可用。\n\n若你的程式碼有安全性缺陷，它依然會存在。\n\n隱藏文件只會讓他人更難理解如何與你的 API 互動，也可能讓你在正式環境除錯更困難。這通常僅被視為一種 [以隱匿求安全](https://en.wikipedia.org/wiki/Security_through_obscurity)。\n\n如果你想保護 API，有許多更好的作法，例如：\n\n- 確保針對請求本文與回應，具備定義良好的 Pydantic 模型。\n- 透過依賴設定所需的權限與角色。\n- 切勿儲存明文密碼，只儲存密碼雜湊。\n- 實作並使用成熟且廣為人知的密碼學工具，例如 pwdlib 與 JWT 權杖等。\n- 視需要以 OAuth2 scopes 新增更細緻的權限控管。\n- ...等。\n\n儘管如此，在某些特定情境下，你可能確實需要在某些環境（例如正式環境）停用 API 文件，或依據環境變數的設定來決定是否啟用。\n\n## 透過設定與環境變數的條件式 OpenAPI { #conditional-openapi-from-settings-and-env-vars }\n\n你可以用相同的 Pydantic 設定，來配置產生的 OpenAPI 與文件 UI。\n\n例如：\n\n{* ../../docs_src/conditional_openapi/tutorial001_py310.py hl[6,11] *}\n\n這裡我們宣告 `openapi_url` 設定，預設值同樣是 `\"/openapi.json\"`。\n\n接著在建立 `FastAPI` 應用時使用它。\n\n然後你可以將環境變數 `OPENAPI_URL` 設為空字串，以停用 OpenAPI（包含文件 UI），如下：\n\n<div class=\"termy\">\n\n```console\n$ OPENAPI_URL= uvicorn main:app\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n之後若你造訪 `/openapi.json`、`/docs` 或 `/redoc`，會看到如下的 `404 Not Found` 錯誤：\n\n```JSON\n{\n    \"detail\": \"Not Found\"\n}\n```\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/configure-swagger-ui.md",
    "content": "# 設定 Swagger UI { #configure-swagger-ui }\n\n你可以設定一些額外的 [Swagger UI 參數](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)。\n\n要設定它們，建立 `FastAPI()` 應用物件時，或呼叫 `get_swagger_ui_html()` 函式時，傳入參數 `swagger_ui_parameters`。\n\n`swagger_ui_parameters` 接受一個 dict，內容會直接傳給 Swagger UI 作為設定。\n\nFastAPI 會把這些設定轉換成 **JSON**，以便與 JavaScript 相容，因為 Swagger UI 需要的是這種格式。\n\n## 停用語法醒目提示 { #disable-syntax-highlighting }\n\n例如，你可以在 Swagger UI 中停用語法醒目提示（syntax highlighting）。\n\n不更動設定時，語法醒目提示預設為啟用：\n\n<img src=\"/img/tutorial/extending-openapi/image02.png\">\n\n但你可以將 `syntaxHighlight` 設為 `False` 來停用它：\n\n{* ../../docs_src/configure_swagger_ui/tutorial001_py310.py hl[3] *}\n\n...然後 Swagger UI 就不會再顯示語法醒目提示：\n\n<img src=\"/img/tutorial/extending-openapi/image03.png\">\n\n## 更換主題 { #change-the-theme }\n\n同樣地，你可以用鍵 `\"syntaxHighlight.theme\"` 設定語法醒目提示主題（注意中間有一個點）：\n\n{* ../../docs_src/configure_swagger_ui/tutorial002_py310.py hl[3] *}\n\n這個設定會變更語法醒目提示的配色主題：\n\n<img src=\"/img/tutorial/extending-openapi/image04.png\">\n\n## 更改預設的 Swagger UI 參數 { #change-default-swagger-ui-parameters }\n\nFastAPI 內建一些預設參數，適用於大多數情境。\n\n包含以下預設設定：\n\n{* ../../fastapi/openapi/docs.py ln[9:24] hl[18:24] *}\n\n你可以在 `swagger_ui_parameters` 參數中提供不同的值來覆蓋其中任一項。\n\n例如，要停用 `deepLinking`，可以在 `swagger_ui_parameters` 傳入以下設定：\n\n{* ../../docs_src/configure_swagger_ui/tutorial003_py310.py hl[3] *}\n\n## 其他 Swagger UI 參數 { #other-swagger-ui-parameters }\n\n若要查看所有可用的設定，請參考官方的 [Swagger UI 參數文件](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/)。\n\n## 僅限 JavaScript 的設定 { #javascript-only-settings }\n\nSwagger UI 也允許某些設定是**僅限 JavaScript** 的物件（例如 JavaScript 函式）。\n\nFastAPI 也包含以下僅限 JavaScript 的 `presets` 設定：\n\n```JavaScript\npresets: [\n    SwaggerUIBundle.presets.apis,\n    SwaggerUIBundle.SwaggerUIStandalonePreset\n]\n```\n\n這些是 JavaScript 物件，而不是字串，因此無法直接從 Python 程式碼傳遞。\n\n若需要使用這類僅限 JavaScript 的設定，你可以使用上面介紹的方法：覆寫所有 Swagger UI 的路徑操作（path operation），並手動撰寫所需的 JavaScript。\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/custom-docs-ui-assets.md",
    "content": "# 自訂文件 UI 靜態資源（自我託管） { #custom-docs-ui-static-assets-self-hosting }\n\nAPI 文件使用 Swagger UI 與 ReDoc，它們各自需要一些 JavaScript 與 CSS 檔案。\n\n預設情況下，這些檔案會從 <abbr title=\"Content Delivery Network - 內容傳遞網路：一種服務，通常由多台伺服器組成，提供 JavaScript 與 CSS 等靜態檔案。常用來從更接近用戶端的伺服器提供這些檔案，以提升效能。\">CDN</abbr> 提供。\n\n但你可以自訂：你可以指定特定的 CDN，或自行提供這些檔案。\n\n## 為 JavaScript 和 CSS 使用自訂 CDN { #custom-cdn-for-javascript-and-css }\n\n假設你想使用不同的 <abbr title=\"Content Delivery Network - 內容傳遞網路\">CDN</abbr>，例如使用 `https://unpkg.com/`。\n\n若你所在的國家限制部分網址，這會很有用。\n\n### 停用自動產生的文件 { #disable-the-automatic-docs }\n\n第一步是停用自動文件，因為預設會使用預設的 CDN。\n\n要停用它們，建立 `FastAPI` 應用時把相關 URL 設為 `None`：\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[8] *}\n\n### 加入自訂文件 { #include-the-custom-docs }\n\n現在你可以為自訂文件建立「路徑操作（path operation）」。\n\n你可以重用 FastAPI 的內部函式來建立文件的 HTML 頁面，並傳入所需參數：\n\n* `openapi_url`：文件 HTML 頁面用來取得你 API 的 OpenAPI schema 的 URL。可使用屬性 `app.openapi_url`。\n* `title`：你的 API 標題。\n* `oauth2_redirect_url`：可使用 `app.swagger_ui_oauth2_redirect_url` 以沿用預設值。\n* `swagger_js_url`：Swagger UI 文件 HTML 用來取得「JavaScript」檔案的 URL。這是你的自訂 CDN 位址。\n* `swagger_css_url`：Swagger UI 文件 HTML 用來取得「CSS」檔案的 URL。這是你的自訂 CDN 位址。\n\nReDoc 也類似...\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[2:6,11:19,22:24,27:33] *}\n\n/// tip\n\n當你使用 OAuth2 時，`swagger_ui_redirect` 的路徑操作是個輔助端點。\n\n如果你把 API 與 OAuth2 提供者整合，便能完成認證並帶著取得的憑證回到 API 文件，接著以真正的 OAuth2 驗證與之互動。\n\nSwagger UI 會在背後幫你處理，不過它需要這個「redirect」輔助端點。\n\n///\n\n### 建立路徑操作以進行測試 { #create-a-path-operation-to-test-it }\n\n現在，為了測試一切是否正常，建立一個路徑操作：\n\n{* ../../docs_src/custom_docs_ui/tutorial001_py310.py hl[36:38] *}\n\n### 測試 { #test-it }\n\n現在你應該能造訪 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)，重新載入頁面後，資源會從新的 CDN 載入。\n\n## 自行託管文件所需的 JavaScript 與 CSS { #self-hosting-javascript-and-css-for-docs }\n\n若你需要應用在離線、無公共網路或僅在區域網路中也能運作，自行託管 JavaScript 與 CSS 會很實用。\n\n以下示範如何在同一個 FastAPI 應用中自行提供這些檔案，並設定文件使用它們。\n\n### 專案檔案結構 { #project-file-structure }\n\n假設你的專案檔案結構如下：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n```\n\n現在建立一個目錄來存放這些靜態檔案。\n\n新的檔案結構可能如下：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static/\n```\n\n### 下載檔案 { #download-the-files }\n\n下載文件所需的靜態檔案並放到 `static/` 目錄中。\n\n你可以在各連結上按右鍵，選擇類似「另存連結為...」的選項。\n\nSwagger UI 需要以下檔案：\n\n* [`swagger-ui-bundle.js`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js)\n* [`swagger-ui.css`](https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css)\n\n而 ReDoc 需要以下檔案：\n\n* [`redoc.standalone.js`](https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js)\n\n之後，你的檔案結構可能如下：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n└── static\n    ├── redoc.standalone.js\n    ├── swagger-ui-bundle.js\n    └── swagger-ui.css\n```\n\n### 提供靜態檔案 { #serve-the-static-files }\n\n* 匯入 `StaticFiles`。\n* 在特定路徑「掛載」一個 `StaticFiles()` 實例。\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[7,11] *}\n\n### 測試靜態檔案 { #test-the-static-files }\n\n啟動你的應用並前往 [http://127.0.0.1:8000/static/redoc.standalone.js](http://127.0.0.1:8000/static/redoc.standalone.js)。\n\n你應該會看到一個很長的 **ReDoc** JavaScript 檔案。\n\n它可能會以如下內容開頭：\n\n```JavaScript\n/*! For license information please see redoc.standalone.js.LICENSE.txt */\n!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t(require(\"null\")):\n...\n```\n\n這表示你的應用已能提供靜態檔案，且文件用的靜態檔已放在正確位置。\n\n接著把應用設定為讓文件使用這些靜態檔。\n\n### 為靜態檔案停用自動文件 { #disable-the-automatic-docs-for-static-files }\n\n和使用自訂 CDN 一樣，第一步是停用自動文件，因為預設會使用 CDN。\n\n要停用它們，建立 `FastAPI` 應用時把相關 URL 設為 `None`：\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[9] *}\n\n### 加入使用靜態檔案的自訂文件 { #include-the-custom-docs-for-static-files }\n\n同樣地，現在你可以為自訂文件建立路徑操作。\n\n再次重用 FastAPI 的內部函式來建立文件的 HTML 頁面，並傳入所需參數：\n\n* `openapi_url`：文件 HTML 頁面用來取得你 API 的 OpenAPI schema 的 URL。可使用屬性 `app.openapi_url`。\n* `title`：你的 API 標題。\n* `oauth2_redirect_url`：可使用 `app.swagger_ui_oauth2_redirect_url` 以沿用預設值。\n* `swagger_js_url`：Swagger UI 文件 HTML 用來取得「JavaScript」檔案的 URL。這就是你的應用現在提供的檔案。\n* `swagger_css_url`：Swagger UI 文件 HTML 用來取得「CSS」檔案的 URL。這就是你的應用現在提供的檔案。\n\nReDoc 也類似...\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[2:6,14:22,25:27,30:36] *}\n\n/// tip\n\n當你使用 OAuth2 時，`swagger_ui_redirect` 的路徑操作是個輔助端點。\n\n如果你把 API 與 OAuth2 提供者整合，便能完成認證並帶著取得的憑證回到 API 文件，接著以真正的 OAuth2 驗證與之互動。\n\nSwagger UI 會在背後幫你處理，不過它需要這個「redirect」輔助端點。\n\n///\n\n### 建立路徑操作以測試靜態檔案 { #create-a-path-operation-to-test-static-files }\n\n現在，為了測試一切是否正常，建立一個路徑操作：\n\n{* ../../docs_src/custom_docs_ui/tutorial002_py310.py hl[39:41] *}\n\n### 測試使用靜態檔案的 UI { #test-static-files-ui }\n\n現在，你應該可以關閉 WiFi，造訪你的文件 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)，並重新載入頁面。\n\n即使沒有網際網路，也能看到你的 API 文件並與之互動。\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/custom-request-and-route.md",
    "content": "# 自訂 Request 與 APIRoute 類別 { #custom-request-and-apiroute-class }\n\n在某些情況下，你可能想要覆寫 `Request` 與 `APIRoute` 類別所使用的邏輯。\n\n特別是，這可能是替代中介軟體（middleware）中實作邏輯的一個好方法。\n\n例如，如果你想在應用程式處理之前讀取或操作請求本文（request body）。\n\n/// danger\n\n這是進階功能。\n\n如果你剛開始使用 **FastAPI**，可以先跳過本節。\n\n///\n\n## 使用情境 { #use-cases }\n\n可能的使用情境包括：\n\n* 將非 JSON 的請求本文轉換為 JSON（例如 [`msgpack`](https://msgpack.org/index.html)）。\n* 解壓縮以 gzip 壓縮的請求本文。\n* 自動記錄所有請求本文。\n\n## 處理自訂請求本文編碼 { #handling-custom-request-body-encodings }\n\n讓我們看看如何使用自訂的 `Request` 子類別來解壓縮 gzip 請求。\n\n並透過 `APIRoute` 子類別來使用該自訂的請求類別。\n\n### 建立自訂的 `GzipRequest` 類別 { #create-a-custom-gziprequest-class }\n\n/// tip\n\n這是一個示範用的簡化範例；如果你需要 Gzip 支援，可以直接使用提供的 [`GzipMiddleware`](../advanced/middleware.md#gzipmiddleware)。\n\n///\n\n首先，我們建立 `GzipRequest` 類別，它會覆寫 `Request.body()` 方法，當存在對應的標頭時解壓縮本文。\n\n如果標頭中沒有 `gzip`，它就不會嘗試解壓縮本文。\n\n如此一來，相同的路由類別即可同時處理經 gzip 壓縮與未壓縮的請求。\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[9:16] *}\n\n### 建立自訂的 `GzipRoute` 類別 { #create-a-custom-gziproute-class }\n\n接著，我們建立 `fastapi.routing.APIRoute` 的自訂子類別，讓它使用 `GzipRequest`。\n\n這次，它會覆寫 `APIRoute.get_route_handler()` 方法。\n\n這個方法會回傳一個函式，而該函式會接收請求並回傳回應。\n\n在這裡，我們用它將原始的請求包裝成 `GzipRequest`。\n\n{* ../../docs_src/custom_request_and_route/tutorial001_an_py310.py hl[19:27] *}\n\n/// note | 技術細節\n\n`Request` 具有 `request.scope` 屬性，它其實就是一個 Python 的 `dict`，包含與該請求相關的中繼資料。\n\n`Request` 也有 `request.receive`，那是一個用來「接收」請求本文的函式。\n\n`scope` 這個 `dict` 與 `receive` 函式都是 ASGI 規格的一部分。\n\n而 `scope` 與 `receive` 這兩者，就是建立一個新的 `Request` 實例所需的資料。\n\n想了解更多 `Request`，請參考 [Starlette 的 Request 文件](https://www.starlette.dev/requests/)。\n\n///\n\n由 `GzipRequest.get_route_handler` 回傳的函式，唯一不同之處在於它會把 `Request` 轉換成 `GzipRequest`。\n\n這麼做之後，`GzipRequest` 會在把資料交給 *路徑操作* 之前（若有需要）先負責解壓縮。\n\n之後的處理邏輯完全相同。\n\n但由於我們修改了 `GzipRequest.body`，在 **FastAPI** 需要讀取本文時，請求本文會自動解壓縮。\n\n## 在例外處理器中存取請求本文 { #accessing-the-request-body-in-an-exception-handler }\n\n/// tip\n\n要解決相同問題，使用針對 `RequestValidationError` 的自訂處理器來讀取 `body` 通常更簡單（[處理錯誤](../tutorial/handling-errors.md#use-the-requestvalidationerror-body)）。\n\n但本範例仍然有效，並示範了如何與內部元件互動。\n\n///\n\n我們也可以用同樣的方法，在例外處理器中存取請求本文。\n\n我們只需要在 `try`/`except` 區塊中處理請求即可：\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *}\n\n若發生例外，`Request` 實例依然在作用域內，因此在處理錯誤時我們仍可讀取並使用請求本文：\n\n{* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *}\n\n## 在路由器中自訂 `APIRoute` 類別 { #custom-apiroute-class-in-a-router }\n\n你也可以在 `APIRouter` 上設定 `route_class` 參數：\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[26] *}\n\n在此範例中，`router` 底下的路徑操作會使用自訂的 `TimedRoute` 類別，並在回應中多加上一個 `X-Response-Time` 標頭，標示產生該回應所花費的時間：\n\n{* ../../docs_src/custom_request_and_route/tutorial003_py310.py hl[13:20] *}\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/extending-openapi.md",
    "content": "# 擴充 OpenAPI { #extending-openapi }\n\n有些情況你可能需要修改自動產生的 OpenAPI 結構（schema）。\n\n本章將示範如何做。\n\n## 一般流程 { #the-normal-process }\n\n一般（預設）的流程如下。\n\n`FastAPI` 應用程式（實例）有一個 `.openapi()` 方法，會回傳 OpenAPI 結構。\n\n在建立應用物件時，會同時註冊一個 `/openapi.json`（或你在 `openapi_url` 設定的路徑）的路徑操作（path operation）。\n\n這個路徑只會回傳一個 JSON 回應，內容就是應用的 `.openapi()` 方法結果。\n\n預設情況下，`.openapi()` 會先檢查 `.openapi_schema` 屬性是否已有內容，有的話就直接回傳。\n\n若沒有，則會呼叫 `fastapi.openapi.utils.get_openapi` 這個工具函式來產生。\n\n`get_openapi()` 函式會接收以下參數：\n\n* `title`：OpenAPI 的標題，會顯示在文件中。\n* `version`：你的 API 版本，例如 `2.5.0`。\n* `openapi_version`：所使用的 OpenAPI 規格版本。預設為最新版本：`3.1.0`。\n* `summary`：API 的簡短摘要。\n* `description`：API 的描述，可包含 Markdown，會顯示在文件中。\n* `routes`：路由列表，也就是所有已註冊的路徑操作。來源為 `app.routes`。\n\n/// info\n\n`summary` 參數在 OpenAPI 3.1.0 以上可用，且需 FastAPI 0.99.0 以上版本支援。\n\n///\n\n## 覆寫預設行為 { #overriding-the-defaults }\n\n基於上述資訊，你可以用相同的工具函式來產生 OpenAPI 結構，並覆寫你需要客製的部分。\n\n例如，我們要加入 [ReDoc 的 OpenAPI 擴充，插入自訂 logo](https://github.com/Rebilly/ReDoc/blob/master/docs/redoc-vendor-extensions.md#x-logo)。\n\n### 一般的 **FastAPI** { #normal-fastapi }\n\n先照常撰寫你的 **FastAPI** 應用：\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[1,4,7:9] *}\n\n### 產生 OpenAPI 結構 { #generate-the-openapi-schema }\n\n接著，在 `custom_openapi()` 函式內，使用相同的工具函式來產生 OpenAPI 結構：\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[2,15:21] *}\n\n### 修改 OpenAPI 結構 { #modify-the-openapi-schema }\n\n現在可以加入 ReDoc 擴充，在 OpenAPI 結構的 `info`「物件」中新增自訂的 `x-logo`：\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[22:24] *}\n\n### 快取 OpenAPI 結構 { #cache-the-openapi-schema }\n\n你可以把 `.openapi_schema` 屬性當作「快取」來儲存已產生的結構。\n\n這樣使用者每次開啟 API 文件時，應用就不必重複產生結構。\n\n結構只會產生一次，之後的請求都會使用相同的快取結果。\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[13:14,25:26] *}\n\n### 覆寫方法 { #override-the-method }\n\n現在你可以用新的函式取代 `.openapi()` 方法。\n\n{* ../../docs_src/extending_openapi/tutorial001_py310.py hl[29] *}\n\n### 檢查看看 { #check-it }\n\n造訪 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) 後，你會看到自訂的 logo（此例為 **FastAPI** 的 logo）：\n\n<img src=\"/img/tutorial/extending-openapi/image01.png\">\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/general.md",
    "content": "# 通用 - 操作指南 - 實用範例 { #general-how-to-recipes }\n\n以下是文件中其他位置的指引連結，適用於一般或常見問題。\n\n## 篩選資料 - 安全性 { #filter-data-security }\n\n為確保你不會回傳超出應有的資料，請參閱[教學 - 回應模型 - 回傳型別](../tutorial/response-model.md)。\n\n## 最佳化回應效能 - 回應模型 - 回傳型別 { #optimize-response-performance-response-model-return-type }\n\n為了在回傳 JSON 資料時最佳化效能，請使用回傳型別或回應模型，如此 Pydantic 會在 Rust 端處理序列化為 JSON，而不經過 Python。更多內容請參閱[教學 - 回應模型 - 回傳型別](../tutorial/response-model.md)。\n\n## 文件標籤 - OpenAPI { #documentation-tags-openapi }\n\n要在你的*路徑操作（path operation）*加入標籤，並在文件 UI 中分組，請參閱[教學 - 路徑操作設定 - 標籤](../tutorial/path-operation-configuration.md#tags)。\n\n## 文件摘要與描述 - OpenAPI { #documentation-summary-and-description-openapi }\n\n要為你的*路徑操作*加入摘要與描述，並在文件 UI 中顯示，請參閱[教學 - 路徑操作設定 - 摘要與描述](../tutorial/path-operation-configuration.md#summary-and-description)。\n\n## 文件回應描述 - OpenAPI { #documentation-response-description-openapi }\n\n要定義在文件 UI 中顯示的回應描述，請參閱[教學 - 路徑操作設定 - 回應描述](../tutorial/path-operation-configuration.md#response-description)。\n\n## 文件將*路徑操作*標記為已棄用 - OpenAPI { #documentation-deprecate-a-path-operation-openapi }\n\n要將*路徑操作*標記為已棄用，並在文件 UI 中顯示，請參閱[教學 - 路徑操作設定 - 棄用](../tutorial/path-operation-configuration.md#deprecate-a-path-operation)。\n\n## 將任意資料轉換為 JSON 相容格式 { #convert-any-data-to-json-compatible }\n\n要將任意資料轉換為 JSON 相容格式，請參閱[教學 - JSON 相容編碼器](../tutorial/encoder.md)。\n\n## OpenAPI 中繼資料 - 文件 { #openapi-metadata-docs }\n\n要在你的 OpenAPI 綱要中加入中繼資料（包含授權、版本、聯絡方式等），請參閱[教學 - 中繼資料與文件 URL](../tutorial/metadata.md)。\n\n## 自訂 OpenAPI URL { #openapi-custom-url }\n\n要自訂（或移除）OpenAPI 的 URL，請參閱[教學 - 中繼資料與文件 URL](../tutorial/metadata.md#openapi-url)。\n\n## OpenAPI 文件 URL { #openapi-docs-urls }\n\n要更新自動產生的文件使用者介面所使用的 URL，請參閱[教學 - 中繼資料與文件 URL](../tutorial/metadata.md#docs-urls)。\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/graphql.md",
    "content": "# GraphQL { #graphql }\n\n由於 FastAPI 基於 ASGI 標準，整合任何與 ASGI 相容的 GraphQL 函式庫都很容易。\n\n你可以在同一個應用程式中同時使用一般的 FastAPI 路徑操作 (path operation) 與 GraphQL。\n\n/// tip\n\nGraphQL 解決某些非常特定的使用情境。\n\n與一般的 Web API 相比，它有優點也有缺點。\n\n請確認在你的使用情境中，這些效益是否足以彌補其限制。 🤓\n\n///\n\n## GraphQL 函式庫 { #graphql-libraries }\n\n下面是支援 ASGI 的部分 GraphQL 函式庫，你可以與 FastAPI 一起使用：\n\n* [Strawberry](https://strawberry.rocks/) 🍓\n    * 提供 [FastAPI 文件](https://strawberry.rocks/docs/integrations/fastapi)\n* [Ariadne](https://ariadnegraphql.org/)\n    * 提供 [FastAPI 文件](https://ariadnegraphql.org/docs/fastapi-integration)\n* [Tartiflette](https://tartiflette.io/)\n    * 使用 [Tartiflette ASGI](https://tartiflette.github.io/tartiflette-asgi/) 提供 ASGI 整合\n* [Graphene](https://graphene-python.org/)\n    * 搭配 [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)\n\n## 使用 Strawberry 的 GraphQL { #graphql-with-strawberry }\n\n如果你需要或想使用 GraphQL，[Strawberry](https://strawberry.rocks/) 是推薦的函式庫，因為它的設計與 FastAPI 最接近，全部都基於型別註解 (type annotations)。\n\n視你的使用情境而定，你可能會偏好其他函式庫，但如果你問我，我大概會建議你先試試 Strawberry。\n\n以下是如何將 Strawberry 與 FastAPI 整合的一個小例子：\n\n{* ../../docs_src/graphql_/tutorial001_py310.py hl[3,22,25] *}\n\n你可以在 [Strawberry 文件](https://strawberry.rocks/) 中進一步了解 Strawberry。\n\n也可以參考關於 [Strawberry 與 FastAPI](https://strawberry.rocks/docs/integrations/fastapi) 的文件。\n\n## 來自 Starlette 的較舊 `GraphQLApp` { #older-graphqlapp-from-starlette }\n\n早期版本的 Starlette 提供 `GraphQLApp` 類別以整合 [Graphene](https://graphene-python.org/)。\n\n它已在 Starlette 中被棄用，但如果你的程式碼使用了它，可以輕鬆遷移到 [starlette-graphene3](https://github.com/ciscorn/starlette-graphene3)，涵蓋相同的使用情境，且介面幾乎相同。\n\n/// tip\n\n如果你需要 GraphQL，我仍建議你看看 [Strawberry](https://strawberry.rocks/)，因為它基於型別註解，而不是自訂的類別與型別。\n\n///\n\n## 進一步了解 { #learn-more }\n\n你可以在 [官方 GraphQL 文件](https://graphql.org/) 中進一步了解 GraphQL。\n\n你也可以透過上述連結閱讀各個函式庫的更多內容。\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/index.md",
    "content": "# 使用指南 - 範例集 { #how-to-recipes }\n\n在這裡，你將會看到**不同主題**的範例或「如何使用」的指南。\n\n大多數這些想法都是**獨立**的，在大多數情況下，你只需要研究那些直接適用於**你的專案**的東西。\n\n如果有些東西看起來很有趣且對你的專案很有用的話再去讀它，否則你可能可以跳過它們。\n\n/// tip\n\n如果你想要以結構化的方式**學習 FastAPI**（推薦），請前往[教學 - 使用者指南](../tutorial/index.md)逐章閱讀。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md",
    "content": "# 從 Pydantic v1 遷移到 Pydantic v2 { #migrate-from-pydantic-v1-to-pydantic-v2 }\n\n如果你有一個舊的 FastAPI 應用，可能正在使用 Pydantic 1 版。\n\nFastAPI 0.100.0 同時支援 Pydantic v1 或 v2，會使用你已安裝的那個版本。\n\nFastAPI 0.119.0 透過 Pydantic v2 內的 `pydantic.v1` 提供對 Pydantic v1 的部分支援，以便遷移到 v2。\n\nFastAPI 0.126.0 移除了對 Pydantic v1 的支援，但在一段時間內仍支援 `pydantic.v1`。\n\n/// warning\n\nPydantic 團隊自 **Python 3.14** 起，已停止在最新的 Python 版本中支援 Pydantic v1。\n\n這也包含 `pydantic.v1`，在 Python 3.14 及以上版本不再支援。\n\n如果你想使用最新的 Python 功能，就需要確保使用 Pydantic v2。\n\n///\n\n如果你的舊 FastAPI 應用仍使用 Pydantic v1，這裡會示範如何遷移到 Pydantic v2，並介紹 **FastAPI 0.119.0** 中可協助你逐步遷移的功能。\n\n## 官方指南 { #official-guide }\n\nPydantic 提供從 v1 遷移到 v2 的官方[遷移指南](https://docs.pydantic.dev/latest/migration/)。\n\n其中包含變更內容、驗證如何更正確且更嚴格、可能的注意事項等。\n\n你可以先閱讀以更好理解具體變更。\n\n## 測試 { #tests }\n\n確保你的應用有[測試](../tutorial/testing.md)，並在 CI（持續整合）上執行。\n\n如此一來，你可以升級後確認一切仍如預期運作。\n\n## `bump-pydantic` { #bump-pydantic }\n\n在許多情況下，若你使用的是未自訂的標準 Pydantic 模型，多數遷移步驟都能自動化完成。\n\n你可以使用 Pydantic 團隊提供的 [`bump-pydantic`](https://github.com/pydantic/bump-pydantic)。\n\n這個工具會自動修改大部分需要變更的程式碼。\n\n之後執行測試確認一切正常即可完成。😎\n\n## v2 中的 Pydantic v1 { #pydantic-v1-in-v2 }\n\nPydantic v2 內含子模組 `pydantic.v1`，提供 Pydantic v1 的所有內容。但在 Python 3.13 以上版本不再支援。\n\n這表示你可以安裝最新的 Pydantic v2，並從該子模組匯入並使用舊的 Pydantic v1 元件，就像安裝了舊版 Pydantic v1 一樣。\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}\n\n### FastAPI 對 v2 中 Pydantic v1 的支援 { #fastapi-support-for-pydantic-v1-in-v2 }\n\n自 FastAPI 0.119.0 起，也支援透過 Pydantic v2 內的 Pydantic v1（部分）以協助遷移至 v2。\n\n因此，你可以先升級到最新的 Pydantic v2，並將匯入改為使用 `pydantic.v1` 子模組，在多數情況下即可正常運作。\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}\n\n/// warning\n\n請注意，由於 Pydantic 團隊自 Python 3.14 起不再支援 Pydantic v1，因此在 Python 3.14 及以上版本中也不支援使用 `pydantic.v1`。\n\n///\n\n### 同一應用同時使用 Pydantic v1 與 v2 { #pydantic-v1-and-v2-on-the-same-app }\n\nPydantic 不支援在 Pydantic v2 模型的欄位中使用 Pydantic v1 模型，反之亦然。\n\n```mermaid\ngraph TB\n    subgraph \"❌ Not Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n...但你可以在同一應用中同時存在分開的 Pydantic v1 與 v2 模型。\n\n```mermaid\ngraph TB\n    subgraph \"✅ Supported\"\n        direction TB\n        subgraph V2[\"Pydantic v2 Model\"]\n            V2Field[\"Pydantic v2 Model\"]\n        end\n        subgraph V1[\"Pydantic v1 Model\"]\n            V1Field[\"Pydantic v1 Model\"]\n        end\n    end\n\n    style V2 fill:#f9fff3\n    style V1 fill:#fff6f0\n    style V1Field fill:#fff6f0\n    style V2Field fill:#f9fff3\n```\n\n在某些情況下，你甚至可以在同一個 FastAPI 路徑操作（path operation）中同時使用 Pydantic v1 與 v2 模型：\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}\n\n在上面的範例中，輸入模型是 Pydantic v1，輸出模型（於 `response_model=ItemV2` 定義）是 Pydantic v2。\n\n### Pydantic v1 參數 { #pydantic-v1-parameters }\n\n若你需要在 Pydantic v1 模型上使用 FastAPI 的參數工具（例如 `Body`、`Query`、`Form` 等），在完成遷移到 Pydantic v2 之前，可以從 `fastapi.temp_pydantic_v1_params` 匯入：\n\n{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}\n\n### 分步遷移 { #migrate-in-steps }\n\n/// tip\n\n先嘗試使用 `bump-pydantic`，如果測試通過且一切正常，你就能用一條指令完成遷移。✨\n\n///\n\n若 `bump-pydantic` 不適用於你的情境，可以利用在同一應用同時支援 Pydantic v1 與 v2 的能力，逐步完成遷移。\n\n你可以先升級 Pydantic 到最新 v2，並將所有模型的匯入改為使用 `pydantic.v1`。\n\n接著按群組逐步把模型從 Pydantic v1 遷移到 v2。🚶\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/separate-openapi-schemas.md",
    "content": "# 是否將輸入與輸出使用不同的 OpenAPI 結構描述 { #separate-openapi-schemas-for-input-and-output-or-not }\n\n自從 Pydantic v2 發佈後，生成的 OpenAPI 比以往更精確也更正確。😎\n\n實際上，在某些情況下，同一個 Pydantic 模型在 OpenAPI 中會同時有兩個 JSON Schema：分別用於輸入與輸出，這取決於它是否有預設值。\n\n來看看它如何運作，以及若需要時該如何調整。\n\n## 作為輸入與輸出的 Pydantic 模型 { #pydantic-models-for-input-and-output }\n\n假設你有一個帶有預設值的 Pydantic 模型，如下所示：\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:7] hl[7] *}\n\n### 輸入用模型 { #model-for-input }\n\n如果你把這個模型用作輸入，如下所示：\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py ln[1:15] hl[14] *}\n\n...則 `description` 欄位將不是必填。因為它的預設值是 `None`。\n\n### 文件中的輸入模型 { #input-model-in-docs }\n\n你可以在文件中確認，`description` 欄位沒有紅色星號，表示不是必填：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image01.png\">\n</div>\n\n### 輸出用模型 { #model-for-output }\n\n但如果你把同一個模型用作輸出，如下所示：\n\n{* ../../docs_src/separate_openapi_schemas/tutorial001_py310.py hl[19] *}\n\n...由於 `description` 有預設值，就算你沒有為該欄位回傳任何內容，它仍會有那個預設值。\n\n### 輸出回應資料的模型 { #model-for-output-response-data }\n\n在互動式文件中試用並檢視回應時，儘管程式碼沒有為其中一個 `description` 欄位加入任何內容，JSON 回應仍包含預設值（`null`）：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image02.png\">\n</div>\n\n這代表該欄位一定會有值，只是有時候值可能是 `None`（在 JSON 中為 `null`）。\n\n因此，使用你 API 的用戶端不必檢查值是否存在，可以假設該欄位一定存在；只是有些情況下它的值會是預設的 `None`。\n\n在 OpenAPI 中，描述這種情況的方式是將該欄位標記為必填，因為它一定存在。\n\n因此，同一個模型的 JSON Schema 會依用於輸入或輸出而不同：\n\n- 用於輸入時，`description` 不是必填\n- 用於輸出時，`description` 是必填（且可能為 `None`，在 JSON 中為 `null`）\n\n### 文件中的輸出模型 { #model-for-output-in-docs }\n\n你也可以在文件中檢視輸出模型，`name` 與 `description` 都以紅色星號標示為必填：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image03.png\">\n</div>\n\n### 文件中的輸入與輸出模型 { #model-for-input-and-output-in-docs }\n\n如果你查看 OpenAPI 中所有可用的結構描述（JSON Schema），會看到有兩個：`Item-Input` 與 `Item-Output`。\n\n對於 `Item-Input`，`description` 不是必填，沒有紅色星號。\n\n但對於 `Item-Output`，`description` 是必填，有紅色星號。\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image04.png\">\n</div>\n\n有了 Pydantic v2 的這個特性，你的 API 文件會更精確；若你有自動產生的用戶端與 SDK，它們也會更精確，提供更好的開發者體驗與一致性。🎉\n\n## 不要分開結構描述 { #do-not-separate-schemas }\n\n不過，在某些情況下，你可能會希望輸入與輸出使用相同的結構描述。\n\n最常見的情境是：你已經有一些自動產生的用戶端程式碼／SDK，目前還不想全部更新；也許之後會做，但不是現在。\n\n在這種情況下，你可以在 FastAPI 中透過參數 `separate_input_output_schemas=False` 停用這個功能。\n\n/// info\n\n自 FastAPI `0.102.0` 起新增 `separate_input_output_schemas` 的支援。🤓\n\n///\n\n{* ../../docs_src/separate_openapi_schemas/tutorial002_py310.py hl[10] *}\n\n### 文件中輸入與輸出使用相同結構描述的模型 { #same-schema-for-input-and-output-models-in-docs }\n\n此時輸入與輸出將共用同一個模型結構描述，只有 `Item`，其中 `description` 不是必填：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/separate-openapi-schemas/image05.png\">\n</div>\n"
  },
  {
    "path": "docs/zh-hant/docs/how-to/testing-database.md",
    "content": "# 測試資料庫 { #testing-a-database }\n\n你可以在 [SQLModel 文件](https://sqlmodel.tiangolo.com/) 中學習關於資料庫、SQL 與 SQLModel。 🤓\n\n有一個迷你 [將 SQLModel 與 FastAPI 搭配使用的教學](https://sqlmodel.tiangolo.com/tutorial/fastapi/)。 ✨\n\n該教學包含一節介紹 [測試 SQL 資料庫](https://sqlmodel.tiangolo.com/tutorial/fastapi/tests/)。 😎\n"
  },
  {
    "path": "docs/zh-hant/docs/index.md",
    "content": "# FastAPI { #fastapi }\n\n<style>\n.md-content .md-typeset h1 { display: none; }\n</style>\n\n<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com/zh-hant\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>FastAPI 框架，高效能，易於學習，快速開發，適用於生產環境</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**文件**： [https://fastapi.tiangolo.com/zh-hant](https://fastapi.tiangolo.com/zh-hant)\n\n**程式碼**： [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi)\n\n---\n\nFastAPI 是一個現代、快速（高效能）的 Web 框架，用於以 Python 並基於標準的 Python 型別提示來構建 API。\n\n主要特點包含：\n\n* **快速**：非常高的效能，可與 **NodeJS** 和 **Go** 相當（歸功於 Starlette 和 Pydantic）。[最快的 Python 框架之一](#performance)。\n* **極速開發**：開發功能的速度可提升約 200% 至 300%。*\n* **更少的 Bug**：減少約 40% 的人為（開發者）錯誤。*\n* **直覺**：具有出色的編輯器支援，處處都有 <dfn title=\"也稱為：自動完成、自動補全、IntelliSense\">自動補全</dfn>。更少的偵錯時間。\n* **簡單**：設計上易於使用與學習。更少的讀文件時間。\n* **簡潔**：最小化程式碼重複性。每個參數宣告可帶來多個功能。更少的錯誤。\n* **穩健**：立即獲得可投入生產的程式碼，並自動生成互動式文件。\n* **標準化**：基於（且完全相容於）API 的開放標準：[OpenAPI](https://github.com/OAI/OpenAPI-Specification)（之前稱為 Swagger）和 [JSON Schema](https://json-schema.org/)。\n\n<small>* 基於內部開發團隊在建立生產應用程式時的測試預估。</small>\n\n## 贊助 { #sponsors }\n\n<!-- sponsors -->\n\n### 基石贊助商 { #keystone-sponsor }\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n\n### 金級與銀級贊助商 { #gold-and-silver-sponsors }\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor -%}\n{%- for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\" style=\"border-radius:15px\"></a>\n{% endfor %}\n\n<!-- /sponsors -->\n\n[其他贊助商](https://fastapi.tiangolo.com/zh-hant/fastapi-people/#sponsors)\n\n## 評價 { #opinions }\n\n\"_[...] 近期大量使用 **FastAPI**。[...] 我實際上打算在我在**微軟**團隊的所有**機器學習**服務上使用它。其中一些正在整合到核心的 **Windows** 產品，以及一些 **Office** 產品。_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kabir Khan - <strong>Microsoft</strong> <a href=\"https://github.com/fastapi/fastapi/pull/26\"><small>(ref)</small></a></div>\n\n---\n\n\"_我們採用了 **FastAPI** 函式庫來啟動一個 **REST** 伺服器，供查詢以取得**預測**。[for Ludwig]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Piero Molino, Yaroslav Dudin, and Sai Sumanth Miryala - <strong>Uber</strong> <a href=\"https://eng.uber.com/ludwig-v0-2/\"><small>(ref)</small></a></div>\n\n---\n\n\"_**Netflix** 很高興宣布我們的**危機管理**協調框架 **Dispatch** 開源！[使用 **FastAPI** 建構]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Kevin Glisson, Marc Vilanova, Forest Monsen - <strong>Netflix</strong> <a href=\"https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072\"><small>(ref)</small></a></div>\n\n---\n\n\"_我對 **FastAPI** 興奮得不得了。超好玩！_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Brian Okken - <strong>[Python Bytes](https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855) podcast 主持人</strong> <a href=\"https://x.com/brianokken/status/1112220079972728832\"><small>(ref)</small></a></div>\n\n---\n\n\"_老實說，你們做的看起來非常穩健又精緻。很多方面都正是我希望 **Hug** 成為的樣子——看到有人把它建出來真的很鼓舞人心。_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Timothy Crosley - <strong>[Hug](https://github.com/hugapi/hug) 創作者</strong> <a href=\"https://news.ycombinator.com/item?id=19455465\"><small>(ref)</small></a></div>\n\n---\n\n\"_如果你想學一個用於構建 REST API 的**現代框架**，看看 **FastAPI** [...] 它很快、易用、也容易學習 [...]_\"\n\n\"_我們的 **API** 已經改用 **FastAPI** [...] 我想你會喜歡它 [...]_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Ines Montani - Matthew Honnibal - <strong>[Explosion AI](https://explosion.ai) 創辦人 - [spaCy](https://spacy.io) 創作者</strong> <a href=\"https://x.com/_inesmontani/status/1144173225322143744\"><small>(ref)</small></a> - <a href=\"https://x.com/honnibal/status/1144031421859655680\"><small>(ref)</small></a></div>\n\n---\n\n\"_如果有人想要打造一個可用於生產環境的 Python API，我強力推薦 **FastAPI**。它**設計優雅**、**簡單易用**且**高度可擴展**，已經成為我們 API first 開發策略中的**關鍵元件**，推動了許多自動化與服務，例如我們的 Virtual TAC Engineer。_\"\n\n<div style=\"text-align: right; margin-right: 10%;\">Deon Pillsbury - <strong>Cisco</strong> <a href=\"https://www.linkedin.com/posts/deonpillsbury_cisco-cx-python-activity-6963242628536487936-trAp/\"><small>(ref)</small></a></div>\n\n---\n\n## FastAPI 迷你紀錄片 { #fastapi-mini-documentary }\n\n在 2025 年底發布了一支 [FastAPI 迷你紀錄片](https://www.youtube.com/watch?v=mpR8ngthqiE)，你可以在線上觀看：\n\n<a href=\"https://www.youtube.com/watch?v=mpR8ngthqiE\"><img src=\"https://fastapi.tiangolo.com/img/fastapi-documentary.jpg\" alt=\"FastAPI Mini Documentary\"></a>\n\n## **Typer**，命令列的 FastAPI { #typer-the-fastapi-of-clis }\n\n<a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg\" style=\"width: 20%;\"></a>\n\n如果你不是在做 Web API，而是要建立一個在終端機中使用的 <abbr title=\"Command Line Interface - 命令列介面\">CLI</abbr> 應用程式，可以看看 [**Typer**](https://typer.tiangolo.com/)。\n\n**Typer** 是 FastAPI 的小老弟。他立志成為命令列世界的 **FastAPI**。⌨️ 🚀\n\n## 需求 { #requirements }\n\nFastAPI 是站在以下巨人的肩膀上：\n\n* [Starlette](https://www.starlette.dev/) 負責 Web 部分。\n* [Pydantic](https://docs.pydantic.dev/) 負責資料部分。\n\n## 安裝 { #installation }\n\n建立並啟用一個[虛擬環境](https://fastapi.tiangolo.com/zh-hant/virtual-environments/)，然後安裝 FastAPI：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n**注意**：請務必將 `\"fastapi[standard]\"` 用引號包起來，以確保在所有終端機中都能正常運作。\n\n## 範例 { #example }\n\n### 建立 { #create-it }\n\n建立檔案 `main.py`，內容如下：\n\n```Python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n<details markdown=\"1\">\n<summary>或使用 <code>async def</code>...</summary>\n\n如果你的程式碼使用 `async` / `await`，請使用 `async def`：\n\n```Python hl_lines=\"7  12\"\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n```\n\n**注意**：\n\n如果你不確定，請查看文件中 _\"In a hurry?\"_ 章節的[關於文件中的 `async` 與 `await`](https://fastapi.tiangolo.com/zh-hant/async/#in-a-hurry)。\n\n</details>\n\n### 運行 { #run-it }\n\n使用以下指令運行伺服器：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n ╭────────── FastAPI CLI - Development mode ───────────╮\n │                                                     │\n │  Serving at: http://127.0.0.1:8000                  │\n │                                                     │\n │  API docs: http://127.0.0.1:8000/docs               │\n │                                                     │\n │  Running in development mode, for production use:   │\n │                                                     │\n │  fastapi run                                        │\n │                                                     │\n ╰─────────────────────────────────────────────────────╯\n\nINFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [2248755] using WatchFiles\nINFO:     Started server process [2248757]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n</div>\n\n<details markdown=\"1\">\n<summary>關於指令 <code>fastapi dev</code>...</summary>\n\n指令 `fastapi dev` 會讀取你的 `main.py`，偵測其中的 **FastAPI** 應用，並使用 [Uvicorn](https://www.uvicorn.dev) 啟動伺服器。\n\n預設情況下，`fastapi dev` 會在本機開發時啟用自動重新載入。\n\n可在 [FastAPI CLI 文件](https://fastapi.tiangolo.com/zh-hant/fastapi-cli/)中閱讀更多資訊。\n\n</details>\n\n### 檢查 { #check-it }\n\n使用瀏覽器開啟 [http://127.0.0.1:8000/items/5?q=somequery](http://127.0.0.1:8000/items/5?q=somequery)。\n\n你將會看到以下 JSON 回應：\n\n```JSON\n{\"item_id\": 5, \"q\": \"somequery\"}\n```\n\n你已經建立了一個具有以下功能的 API：\n\n* 透過路徑 `/` 和 `/items/{item_id}` 接受 HTTP 請求。\n* 以上兩個路徑都接受 `GET` <em>操作</em>（也被稱為 HTTP _方法_）。\n* 路徑 `/items/{item_id}` 有一個 `int` 型別的路徑參數 `item_id`。\n* 路徑 `/items/{item_id}` 有一個可選的 `str` 查詢參數 `q`。\n\n### 互動式 API 文件 { #interactive-api-docs }\n\n接著前往 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n你會看到自動生成的互動式 API 文件（由 [Swagger UI](https://github.com/swagger-api/swagger-ui) 提供）：\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### 替代 API 文件 { #alternative-api-docs }\n\n現在前往 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)。\n\n你會看到另一種自動文件（由 [ReDoc](https://github.com/Rebilly/ReDoc) 提供）：\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n## 範例升級 { #example-upgrade }\n\n現在修改 `main.py` 檔案，使其能從 `PUT` 請求接收 body。\n\n多虧了 Pydantic，你可以用標準的 Python 型別來宣告 body。\n\n```Python hl_lines=\"2  7-10 23-25\"\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n    is_offer: bool | None = None\n\n\n@app.get(\"/\")\ndef read_root():\n    return {\"Hello\": \"World\"}\n\n\n@app.get(\"/items/{item_id}\")\ndef read_item(item_id: int, q: str | None = None):\n    return {\"item_id\": item_id, \"q\": q}\n\n\n@app.put(\"/items/{item_id}\")\ndef update_item(item_id: int, item: Item):\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n`fastapi dev` 伺服器應會自動重新載入。\n\n### 互動式 API 文件升級 { #interactive-api-docs-upgrade }\n\n前往 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n* 互動式 API 文件會自動更新，包含新的 body：\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)\n\n* 點擊「Try it out」按鈕，你可以填寫參數並直接與 API 互動：\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-04-swagger-03.png)\n\n* 然後點擊「Execute」按鈕，使用者介面會與你的 API 溝通、送出參數、取得結果並顯示在螢幕上：\n\n![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)\n\n### 替代 API 文件升級 { #alternative-api-docs-upgrade }\n\n現在前往 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)。\n\n* 替代文件也會反映新的查詢參數與 body：\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)\n\n### 總結 { #recap }\n\n總結來說，你只需在函式參數中**一次**宣告參數、body 等的型別。\n\n你使用的是現代標準的 Python 型別。\n\n你不需要學新的語法、特定函式庫的方法或類別，等等。\n\n就用標準的 **Python**。\n\n例如，對於一個 `int`：\n\n```Python\nitem_id: int\n```\n\n或是一個更複雜的 `Item` 模型：\n\n```Python\nitem: Item\n```\n\n…透過一次宣告，你將獲得：\n\n* 編輯器支援，包括：\n    * 自動補全。\n    * 型別檢查。\n* 資料驗證：\n    * 當資料無效時，自動且清楚的錯誤。\n    * 即使是深度巢狀的 JSON 物件也能驗證。\n* 輸入資料的 <dfn title=\"也稱為：序列化、解析、封送\">轉換</dfn>：從網路讀入到 Python 資料與型別。包含：\n    * JSON。\n    * 路徑參數。\n    * 查詢參數。\n    * Cookies。\n    * 標頭。\n    * 表單。\n    * 檔案。\n* 輸出資料的 <dfn title=\"也稱為：序列化、解析、封送\">轉換</dfn>：從 Python 資料與型別轉換為網路資料（JSON）：\n    * 轉換 Python 型別（`str`、`int`、`float`、`bool`、`list` 等）。\n    * `datetime` 物件。\n    * `UUID` 物件。\n    * 資料庫模型。\n    * ...還有更多。\n* 自動生成的互動式 API 文件，包含 2 種替代的使用者介面：\n    * Swagger UI。\n    * ReDoc。\n\n---\n\n回到前面的程式碼範例，**FastAPI** 會：\n\n* 驗證 `GET` 與 `PUT` 請求的路徑中是否包含 `item_id`。\n* 驗證 `GET` 與 `PUT` 請求中的 `item_id` 是否為 `int` 型別。\n    * 如果不是，客戶端會看到清楚有用的錯誤。\n* 在 `GET` 請求中檢查是否有名為 `q` 的可選查詢參數（如 `http://127.0.0.1:8000/items/foo?q=somequery`）。\n    * 因為 `q` 參數被宣告為 `= None`，所以它是可選的。\n    * 若沒有 `None`，則它會是必填（就像 `PUT` 時的 body）。\n* 對於 `/items/{item_id}` 的 `PUT` 請求，以 JSON 讀取 body：\n    * 檢查是否有必填屬性 `name`，且為 `str`。\n    * 檢查是否有必填屬性 `price`，且為 `float`。\n    * 檢查是否有可選屬性 `is_offer`，若存在則應為 `bool`。\n    * 以上也適用於深度巢狀的 JSON 物件。\n* 自動在 JSON 與 Python 之間轉換。\n* 以 OpenAPI 記錄所有內容，可用於：\n    * 互動式文件系統。\n    * 為多種語言自動產生用戶端程式碼的系統。\n* 直接提供兩種互動式文件網頁介面。\n\n---\n\n我們只觸及了表面，但你已經了解它的運作方式了。\n\n試著把這一行：\n\n```Python\n    return {\"item_name\": item.name, \"item_id\": item_id}\n```\n\n…從：\n\n```Python\n        ... \"item_name\": item.name ...\n```\n\n…改為：\n\n```Python\n        ... \"item_price\": item.price ...\n```\n\n…然後看看你的編輯器如何自動補全屬性並知道它們的型別：\n\n![editor support](https://fastapi.tiangolo.com/img/vscode-completion.png)\n\n若想看包含更多功能的完整範例，請參考 <a href=\"https://fastapi.tiangolo.com/zh-hant/tutorial/\">Tutorial - User Guide</a>。\n\n**劇透警告**：教學 - 使用者指南包含：\n\n* 來自不同來源的**參數**宣告：例如 **headers**、**cookies**、**form fields** 和 **files**。\n* 如何設定**驗證限制**，如 `maximum_length` 或 `regex`。\n* 一個非常強大且易用的 **<dfn title=\"也稱為：components、resources、providers、services、injectables\">依賴注入</dfn>** 系統。\n* 安全與驗證，包含支援 **OAuth2** 搭配 **JWT tokens** 與 **HTTP Basic** 驗證。\n* 宣告**深度巢狀 JSON 模型**的進階（但同樣簡單）技巧（感謝 Pydantic）。\n* 與 [Strawberry](https://strawberry.rocks) 及其他函式庫的 **GraphQL** 整合。\n* 許多額外功能（感謝 Starlette），例如：\n    * **WebSockets**\n    * 基於 HTTPX 與 `pytest` 的極其簡單的測試\n    * **CORS**\n    * **Cookie Sessions**\n    * ...以及更多。\n\n### 部署你的應用（可選） { #deploy-your-app-optional }\n\n你也可以選擇將 FastAPI 應用部署到 [FastAPI Cloud](https://fastapicloud.com)，如果你還沒加入，去登記等候名單吧。🚀\n\n如果你已經有 **FastAPI Cloud** 帳號（我們已從等候名單邀請你 😉），你可以用一個指令部署你的應用。\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n就這樣！現在你可以在該 URL 造訪你的應用。✨\n\n#### 關於 FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** 由 **FastAPI** 的同一位作者與團隊打造。\n\n它讓你以最小的努力精簡地完成 API 的**建置**、**部署**與**存取**流程。\n\n它把用 FastAPI 開發應用的**開發者體驗**帶到**部署**到雲端的流程中。🎉\n\nFastAPI Cloud 是「FastAPI 與好朋友們」這些開源專案的主要贊助與資金來源。✨\n\n#### 部署到其他雲端供應商 { #deploy-to-other-cloud-providers }\n\nFastAPI 是開源且基於標準。你可以把 FastAPI 應用部署到任何你選擇的雲端供應商。\n\n依照你雲端供應商的指南來部署 FastAPI 應用吧。🤓\n\n## 效能 { #performance }\n\n獨立的 TechEmpower 基準測試顯示，在 Uvicorn 下運行的 **FastAPI** 應用是[最快的 Python 框架之一](https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7)，僅次於 Starlette 與 Uvicorn 本身（FastAPI 內部使用它們）。(*)\n\n想了解更多，請參閱[測試結果](https://fastapi.tiangolo.com/zh-hant/benchmarks/)。\n\n## 依賴套件 { #dependencies }\n\nFastAPI 依賴 Pydantic 與 Starlette。\n\n### `standard` 依賴套件 { #standard-dependencies }\n\n當你以 `pip install \"fastapi[standard]\"` 安裝 FastAPI 時，會包含 `standard` 這組可選依賴套件：\n\nPydantic 會使用：\n\n* [`email-validator`](https://github.com/JoshData/python-email-validator) - 用於電子郵件驗證。\n\nStarlette 會使用：\n\n* [`httpx`](https://www.python-httpx.org) - 若要使用 `TestClient` 必須安裝。\n* [`jinja2`](https://jinja.palletsprojects.com) - 若要使用預設的模板設定必須安裝。\n* [`python-multipart`](https://github.com/Kludex/python-multipart) - 若要支援表單 <dfn title=\"將來自 HTTP 請求的字串轉換為 Python 資料\">\"解析\"</dfn>，搭配 `request.form()`。\n\nFastAPI 會使用：\n\n* [`uvicorn`](https://www.uvicorn.dev) - 用於載入並服務你的應用的伺服器。這包含 `uvicorn[standard]`，其中含有一些高效能服務所需的依賴（例如 `uvloop`）。\n* `fastapi-cli[standard]` - 提供 `fastapi` 指令。\n    * 其中包含 `fastapi-cloud-cli`，可讓你將 FastAPI 應用部署到 [FastAPI Cloud](https://fastapicloud.com)。\n\n### 不含 `standard` 依賴套件 { #without-standard-dependencies }\n\n如果你不想包含 `standard` 可選依賴，可以改用 `pip install fastapi`（而不是 `pip install \"fastapi[standard]\"`）。\n\n### 不含 `fastapi-cloud-cli` { #without-fastapi-cloud-cli }\n\n如果你想安裝帶有 standard 依賴、但不包含 `fastapi-cloud-cli`，可以使用 `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"`。\n\n### 額外可選依賴套件 { #additional-optional-dependencies }\n\n有些額外依賴你可能也會想安裝。\n\nPydantic 的額外可選依賴：\n\n* [`pydantic-settings`](https://docs.pydantic.dev/latest/usage/pydantic_settings/) - 設定管理。\n* [`pydantic-extra-types`](https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/) - 與 Pydantic 一起使用的額外型別。\n\nFastAPI 的額外可選依賴：\n\n* [`orjson`](https://github.com/ijl/orjson) - 若要使用 `ORJSONResponse` 必須安裝。\n* [`ujson`](https://github.com/esnme/ultrajson) - 若要使用 `UJSONResponse` 必須安裝。\n\n## 授權 { #license }\n\n本專案以 MIT 授權條款釋出。\n"
  },
  {
    "path": "docs/zh-hant/docs/learn/index.md",
    "content": "# 學習 { #learn }\n\n以下是學習 **FastAPI** 的入門介紹和教學。\n\n你可以將其視為一本**書籍**或一門**課程**，這是**官方**認可並推薦的 FastAPI 學習方式。 😎\n"
  },
  {
    "path": "docs/zh-hant/docs/project-generation.md",
    "content": "# 全端 FastAPI 範本 { #full-stack-fastapi-template }\n\n範本通常附帶特定的設定，但設計上具有彈性且可自訂。這讓你可以依專案需求調整與擴充，因此非常適合作為起點。🏁\n\n你可以使用此範本快速起步，裡面已替你完成大量初始設定、安全性、資料庫，以及部分 API 端點。\n\nGitHub 儲存庫：[全端 FastAPI 範本](https://github.com/tiangolo/full-stack-fastapi-template)\n\n## 全端 FastAPI 範本 - 技術堆疊與功能 { #full-stack-fastapi-template-technology-stack-and-features }\n\n- ⚡ [**FastAPI**](https://fastapi.tiangolo.com/zh-hant) 作為 Python 後端 API。\n  - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) 作為 Python 與 SQL 資料庫互動（ORM）。\n  - 🔍 [Pydantic](https://docs.pydantic.dev)（由 FastAPI 使用）用於資料驗證與設定管理。\n  - 💾 [PostgreSQL](https://www.postgresql.org) 作為 SQL 資料庫。\n- 🚀 [React](https://react.dev) 作為前端。\n  - 💃 使用 TypeScript、hooks、Vite，以及現代前端技術堆疊的其他組件。\n  - 🎨 [Tailwind CSS](https://tailwindcss.com) 與 [shadcn/ui](https://ui.shadcn.com) 作為前端元件。\n  - 🤖 自動產生的前端用戶端。\n  - 🧪 [Playwright](https://playwright.dev) 用於端到端測試。\n  - 🦇 支援深色模式。\n- 🐋 [Docker Compose](https://www.docker.com) 用於開發與正式環境。\n- 🔒 預設即採用安全的密碼雜湊。\n- 🔑 JWT（JSON Web Token）驗證。\n- 📫 以 Email 為基礎的密碼重設。\n- ✅ 使用 [Pytest](https://pytest.org) 的測試。\n- 📞 [Traefik](https://traefik.io) 作為反向代理／負載平衡器。\n- 🚢 使用 Docker Compose 的部署指引，包含如何設定前端 Traefik 代理以自動處理 HTTPS 憑證。\n- 🏭 基於 GitHub Actions 的 CI（持續整合）與 CD（持續部署）。\n"
  },
  {
    "path": "docs/zh-hant/docs/python-types.md",
    "content": "# Python 型別入門 { #python-types-intro }\n\nPython 支援可選用的「型別提示」（也稱為「型別註記」）。\n\n這些「型別提示」或註記是一種特殊語法，用來宣告變數的<dfn title=\"例如：str、int、float、bool\">型別</dfn>。\n\n為你的變數宣告型別後，編輯器與工具就能提供更好的支援。\n\n這裡只是關於 Python 型別提示的快速教學／複習。它只涵蓋使用在 **FastAPI** 時所需的最低限度...其實非常少。\n\n**FastAPI** 完全是以這些型別提示為基礎，並因此帶來許多優勢與好處。\n\n但就算你從不使用 **FastAPI**，學一點型別提示也會有幫助。\n\n/// note | 注意\n\n如果你是 Python 專家，而且已經完全了解型別提示，可以直接跳到下一章。\n\n///\n\n## 動機 { #motivation }\n\n先從一個簡單的例子開始：\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\n執行這個程式會輸出：\n\n```\nJohn Doe\n```\n\n這個函式會做以下事情：\n\n* 接收 `first_name` 與 `last_name`。\n* 用 `title()` 把每個字的第一個字母轉成大寫。\n* 用一個空白把它們<dfn title=\"把它們合在一起，成為一個。將其中一個的內容接在另一個後面。\">串接</dfn>起來。\n\n{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *}\n\n### 編輯它 { #edit-it }\n\n這是一個非常簡單的程式。\n\n但現在想像你正從零開始寫它。\n\n在某個時間點你會開始定義函式，參數都準備好了...\n\n接著你需要呼叫「那個把第一個字母轉大寫的方法」。\n\n是 `upper`？還是 `uppercase`？`first_uppercase`？`capitalize`？\n\n然後你試著用老牌程式設計師的好朋友——編輯器自動完成。\n\n你輸入函式的第一個參數 `first_name`，接著打一個點（`.`），然後按下 `Ctrl+Space` 觸發自動完成。\n\n但很遺憾，你什麼有用的也沒得到：\n\n<img src=\"/img/python-types/image01.png\">\n\n### 加上型別 { #add-types }\n\n我們來修改前一版中的一行。\n\n我們只要把函式參數這一段，從：\n\n```Python\n    first_name, last_name\n```\n\n改成：\n\n```Python\n    first_name: str, last_name: str\n```\n\n就這樣。\n\n那些就是「型別提示」：\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\n這和宣告預設值不同，例如：\n\n```Python\n    first_name=\"john\", last_name=\"doe\"\n```\n\n這是不同的東西。\n\n我們使用的是冒號（`:`），不是等號（`=`）。\n\n而且加上型別提示通常不會改變執行結果，和不加時是一樣的。\n\n不過現在，想像你又在撰寫那個函式，但這次有型別提示。\n\n在同樣的地方，你按 `Ctrl+Space` 嘗試自動完成，然後你會看到：\n\n<img src=\"/img/python-types/image02.png\">\n\n有了這些，你可以往下捲動查看選項，直到找到一個「看起來眼熟」的：\n\n<img src=\"/img/python-types/image03.png\">\n\n## 更多動機 { #more-motivation }\n\n看這個函式，它已經有型別提示了：\n\n{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *}\n\n因為編輯器知道變數的型別，你不只會得到自動完成，還會得到錯誤檢查：\n\n<img src=\"/img/python-types/image04.png\">\n\n現在你知道要修正它，把 `age` 用 `str(age)` 轉成字串：\n\n{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *}\n\n## 宣告型別 { #declaring-types }\n\n你剛剛看到宣告型別提示的主要位置：函式參數。\n\n這也是你在 **FastAPI** 中最常使用它們的地方。\n\n### 簡單型別 { #simple-types }\n\n你可以宣告所有標準的 Python 型別，不只 `str`。\n\n例如你可以用：\n\n* `int`\n* `float`\n* `bool`\n* `bytes`\n\n{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *}\n\n### `typing` 模組 { #typing-module }\n\n在一些其他情境中，你可能需要從標準程式庫的 `typing` 模組匯入一些東西，比如當你想宣告某個東西可以是「任何型別」時，可以用 `typing` 裡的 `Any`：\n\n```python\nfrom typing import Any\n\n\ndef some_function(data: Any):\n    print(data)\n```\n\n### 泛型（Generic types） { #generic-types }\n\n有些型別可以在方括號中接收「型別參數」，以定義其內部元素的型別，例如「字串的 list」可以宣告為 `list[str]`。\n\n這些能接收型別參數的型別稱為「泛型（Generic types）」或「Generics」。\n\n你可以將相同的內建型別用作泛型（使用方括號並在裡面放型別）：\n\n* `list`\n* `tuple`\n* `set`\n* `dict`\n\n#### List { #list }\n\n例如，讓我們定義一個變數是 `str` 的 `list`。\n\n宣告變數，使用相同的冒號（`:`）語法。\n\n型別填 `list`。\n\n由於 list 是一種包含內部型別的型別，你要把內部型別放在方括號中：\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *}\n\n/// info | 資訊\n\n方括號裡的那些內部型別稱為「型別參數」。\n\n在這個例子中，`str` 是傳給 `list` 的型別參數。\n\n///\n\n這表示：「變數 `items` 是一個 `list`，而這個清單中的每個元素都是 `str`」。\n\n這麼做之後，你的編輯器甚至在處理清單裡的項目時也能提供支援：\n\n<img src=\"/img/python-types/image05.png\">\n\n沒有型別時，幾乎不可能做到這點。\n\n請注意，變數 `item` 是清單 `items` 中的一個元素。\n\n即便如此，編輯器仍然知道它是 `str`，並提供相應的支援。\n\n#### Tuple 與 Set { #tuple-and-set }\n\n你也可以用相同方式來宣告 `tuple` 與 `set`：\n\n{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *}\n\n這代表：\n\n* 變數 `items_t` 是一個有 3 個項目的 `tuple`，分別是 `int`、`int` 和 `str`。\n* 變數 `items_s` 是一個 `set`，而其中每個項目都是 `bytes` 型別。\n\n#### Dict { #dict }\n\n定義 `dict` 時，你需要傳入 2 個以逗號分隔的型別參數。\n\n第一個型別參數是 `dict` 的鍵（key）。\n\n第二個型別參數是 `dict` 的值（value）：\n\n{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *}\n\n這代表：\n\n* 變數 `prices` 是個 `dict`：\n    * 這個 `dict` 的鍵是 `str`（例如每個項目的名稱）。\n    * 這個 `dict` 的值是 `float`（例如每個項目的價格）。\n\n#### Union { #union }\n\n你可以宣告一個變數可以是「多種型別」中的任一種，例如 `int` 或 `str`。\n\n要這麼定義，你使用<dfn title='也稱為「位元或運算子」，但在這裡與該含義無關'>豎線（`|`）</dfn>來分隔兩種型別。\n\n這稱為「union」，因為變數可以是這兩種型別集合的聯集中的任一種。\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial008b_py310.py!}\n```\n\n這表示 `item` 可以是 `int` 或 `str`。\n\n#### 可能為 `None` { #possibly-none }\n\n你可以宣告某個值可以是某個型別（例如 `str`），但它也可能是 `None`。\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\n{!> ../../docs_src/python_types/tutorial009_py310.py!}\n```\n\n////\n\n使用 `str | None` 而不是單純的 `str`，可以讓編輯器幫你偵測錯誤，例如你以為某個值一定是 `str`，但它其實也可能是 `None`。\n\n### 類別作為型別 { #classes-as-types }\n\n你也可以用類別來宣告變數的型別。\n\n假設你有一個 `Person` 類別，帶有名稱：\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *}\n\n接著你可以宣告一個變數為 `Person` 型別：\n\n{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *}\n\n然後，你一樣會得到完整的編輯器支援：\n\n<img src=\"/img/python-types/image06.png\">\n\n請注意，這表示「`one_person` 是類別 `Person` 的『實例（instance）』」。\n\n並不是「`one_person` 就是名為 `Person` 的『類別（class）』」。\n\n## Pydantic 模型 { #pydantic-models }\n\n[Pydantic](https://docs.pydantic.dev/) 是一個用來做資料驗證的 Python 程式庫。\n\n你以帶有屬性的類別來宣告資料的「形狀」。\n\n而每個屬性都有其型別。\n\n接著你用一些值建立這個類別的實例，它會驗證這些值、在需要時把它們轉換成適當的型別，然後回給你一個包含所有資料的物件。\n\n你也會對這個產生的物件得到完整的編輯器支援。\n\n以下是來自 Pydantic 官方文件的例子：\n\n{* ../../docs_src/python_types/tutorial011_py310.py *}\n\n/// info | 資訊\n\n想了解更多 [Pydantic，請查看它的文件](https://docs.pydantic.dev/)。\n\n///\n\n**FastAPI** 完全是以 Pydantic 為基礎。\n\n你會在[教學 - 使用者指南](tutorial/index.md)中看到更多實際範例。\n\n## 含中繼資料的型別提示 { #type-hints-with-metadata-annotations }\n\nPython 也有一個功能，允許使用 `Annotated` 在這些型別提示中放入額外的<dfn title=\"關於資料的資料；在此情境下，是關於型別的資訊，例如描述。\">中繼資料</dfn>。\n\n你可以從 `typing` 匯入 `Annotated`。\n\n{* ../../docs_src/python_types/tutorial013_py310.py hl[1,4] *}\n\nPython 本身不會對這個 `Annotated` 做任何事。對編輯器與其他工具而言，該型別仍然是 `str`。\n\n但你可以利用 `Annotated` 這個空間，來提供 **FastAPI** 額外的中繼資料，告訴它你希望應用程式如何運作。\n\n重要的是要記住，傳給 `Annotated` 的「第一個型別參數」才是「真正的型別」。其餘的，都是給其他工具用的中繼資料。\n\n目前你只需要知道 `Annotated` 的存在，而且它是標準的 Python。😎\n\n之後你會看到它有多「強大」。\n\n/// tip | 提示\n\n因為這是「標準 Python」，所以你在編輯器、分析與重構程式碼的工具等方面，仍然能獲得「最佳的開發體驗」。✨\n\n而且你的程式碼也會與許多其他 Python 工具與程式庫非常相容。🚀\n\n///\n\n## 在 **FastAPI** 中的型別提示 { #type-hints-in-fastapi }\n\n**FastAPI** 善用這些型別提示來完成多項工作。\n\n在 **FastAPI** 中，你用型別提示來宣告參數，然後你會得到：\n\n* 編輯器支援\n* 型別檢查\n\n...而 **FastAPI** 也會用同樣的宣告來：\n\n* 定義需求：來自請求的路徑參數、查詢參數、標頭、主體（body）、相依性等\n* 轉換資料：把請求中的資料轉成所需型別\n* 驗證資料：來自每個請求的資料：\n    * 當資料無效時，自動產生錯誤並回傳給用戶端\n* 使用 OpenAPI 書寫 API 文件：\n    * 之後會由自動的互動式文件介面所使用\n\n這些現在聽起來可能有點抽象。別擔心。你會在[教學 - 使用者指南](tutorial/index.md)中看到它們的實際運作。\n\n重點是，透過在單一位置使用標準的 Python 型別（而不是新增更多類別、裝飾器等），**FastAPI** 會幫你完成很多工作。\n\n/// info | 資訊\n\n如果你已經完整讀完整個教學，並回來想多看一些關於型別的內容，一個不錯的資源是 [`mypy` 的「小抄」](https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html)。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/resources/index.md",
    "content": "# 資源 { #resources }\n\n額外的資源、外部連結等。 ✈️\n"
  },
  {
    "path": "docs/zh-hant/docs/translation-banner.md",
    "content": "/// details | 🌐 AI 與人類共同完成的翻譯\n\n此翻譯由人類指導的 AI 完成。🤝\n\n可能會有對原意的誤解，或讀起來不自然等問題。🤖\n\n你可以透過[協助我們更好地引導 AI LLM](https://fastapi.tiangolo.com/zh-hant/contributing/#translations)來改進此翻譯。\n\n[英文版](ENGLISH_VERSION_URL)\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/background-tasks.md",
    "content": "# 背景任務 { #background-tasks }\n\n你可以定義背景任務，讓它們在傳回回應之後執行。\n\n這對於那些需要在請求之後發生、但用戶端其實不必在收到回應前等它完成的操作很有用。\n\n例如：\n\n* 在執行某個動作後發送電子郵件通知：\n    * 由於連線到郵件伺服器並寄送郵件通常較「慢」（數秒），你可以先立即回應，並在背景中發送郵件通知。\n* 處理資料：\n    * 例如，收到一個需要經過較慢處理流程的檔案時，你可以先回應「Accepted」（HTTP 202），再在背景處理該檔案。\n\n## 使用 `BackgroundTasks` { #using-backgroundtasks }\n\n首先，匯入 `BackgroundTasks`，並在你的路徑操作函式中定義一個型別為 `BackgroundTasks` 的參數：\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[1,13] *}\n\n**FastAPI** 會為你建立 `BackgroundTasks` 物件，並以該參數傳入。\n\n## 建立任務函式 { #create-a-task-function }\n\n建立一個作為背景任務執行的函式。\n\n它只是個可接收參數的一般函式。\n\n它可以是 `async def`，也可以是一般的 `def`，**FastAPI** 都能正確處理。\n\n在此例中，任務函式會寫入檔案（模擬寄送電子郵件）。\n\n由於寫入操作未使用 `async` 與 `await`，因此以一般的 `def` 定義該函式：\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[6:9] *}\n\n## 新增背景任務 { #add-the-background-task }\n\n在路徑操作函式內，使用 `.add_task()` 將任務函式加入背景任務物件：\n\n{* ../../docs_src/background_tasks/tutorial001_py310.py hl[14] *}\n\n`.add_task()` 的引數包括：\n\n* 要在背景執行的任務函式（`write_notification`）。\n* 依序傳給任務函式的位置引數（`email`）。\n* 要傳給任務函式的關鍵字引數（`message=\"some notification\"`）。\n\n## 相依性注入 { #dependency-injection }\n\n在相依性注入系統中也可使用 `BackgroundTasks`。你可以在多個層級宣告 `BackgroundTasks` 型別的參數：路徑操作函式、相依項（dependable）、次級相依項等。\n\n**FastAPI** 會在各種情況下正確處理並重用同一個物件，將所有背景任務合併，並在之後於背景執行：\n\n{* ../../docs_src/background_tasks/tutorial002_an_py310.py hl[13,15,22,25] *}\n\n在此範例中，訊息會在回應送出之後寫入 `log.txt` 檔案。\n\n如果請求中有查詢參數，會以背景任務寫入日誌。\n\n接著，在路徑操作函式中建立的另一個背景任務會使用 `email` 路徑參數寫入訊息。\n\n## 技術細節 { #technical-details }\n\n類別 `BackgroundTasks` 直接來自 [`starlette.background`](https://www.starlette.dev/background/)。\n\n它被直接匯入/包含到 FastAPI 中，因此你可以從 `fastapi` 匯入它，並避免不小心從 `starlette.background` 匯入另一個同名的 `BackgroundTask`（結尾沒有 s）。\n\n只使用 `BackgroundTasks`（而非 `BackgroundTask`）時，你就能把它當作路徑操作函式的參數，並讓 **FastAPI** 幫你處理其餘部分，就像直接使用 `Request` 物件一樣。\n\n在 FastAPI 中仍可單獨使用 `BackgroundTask`，但你需要在程式碼中自行建立該物件，並回傳包含它的 Starlette `Response`。\n\n更多細節請參閱 [Starlette 官方的 Background Tasks 文件](https://www.starlette.dev/background/)。\n\n## 注意事項 { #caveat }\n\n如果你需要執行繁重的背景計算，且不一定要由同一個行程執行（例如不需要共用記憶體、變數等），可以考慮使用更大型的工具，例如 [Celery](https://docs.celeryq.dev)。\n\n這類工具通常需要較複雜的設定，以及訊息/工作佇列管理器（如 RabbitMQ 或 Redis），但它們允許你在多個行程，甚至多台伺服器上執行背景任務。\n\n但如果你需要存取同一個 **FastAPI** 應用中的變數與物件，或只需執行小型的背景任務（例如寄送郵件通知），僅使用 `BackgroundTasks` 即可。\n\n## 重點回顧 { #recap }\n\n在路徑操作函式與相依項中匯入並使用 `BackgroundTasks` 參數，以新增背景任務。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/bigger-applications.md",
    "content": "# 更大型的應用程式 - 多個檔案 { #bigger-applications-multiple-files }\n\n如果你正在建置一個應用程式或 Web API，很少會把所有東西都放在單一檔案裡。\n\nFastAPI 提供了一個方便的工具，讓你在維持彈性的同時，幫你組織應用程式的結構。\n\n/// info | 資訊\n\n如果你來自 Flask，這相當於 Flask 的 Blueprints。\n\n///\n\n## 範例檔案結構 { #an-example-file-structure }\n\n假設你有如下的檔案結構：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   ├── dependencies.py\n│   └── routers\n│   │   ├── __init__.py\n│   │   ├── items.py\n│   │   └── users.py\n│   └── internal\n│       ├── __init__.py\n│       └── admin.py\n```\n\n/// tip | 提示\n\n有好幾個 `__init__.py` 檔案：每個目錄或子目錄各一個。\n\n這讓我們可以把一個檔案中的程式碼匯入到另一個檔案。\n\n例如，在 `app/main.py` 你可以有一行：\n\n```\nfrom app.routers import items\n```\n\n///\n\n* `app` 目錄包含所有內容。它有一個空的 `app/__init__.py` 檔案，所以它是一個「Python 套件」（「Python 模組」的集合）：`app`。\n* 它包含一個 `app/main.py` 檔案。因為它在一個 Python 套件中（有 `__init__.py` 檔案的目錄），它是該套件的一個「模組」：`app.main`。\n* 還有一個 `app/dependencies.py` 檔案，就像 `app/main.py` 一樣，它是一個「模組」：`app.dependencies`。\n* 有一個子目錄 `app/routers/`，裡面有另一個 `__init__.py` 檔案，所以它是一個「Python 子套件」：`app.routers`。\n* 檔案 `app/routers/items.py` 在一個套件 `app/routers/` 內，因此它是一個子模組：`app.routers.items`。\n* 同樣地，`app/routers/users.py` 是另一個子模組：`app.routers.users`。\n* 還有一個子目錄 `app/internal/`，裡面有另一個 `__init__.py` 檔案，所以它又是一個「Python 子套件」：`app.internal`。\n* 檔案 `app/internal/admin.py` 是另一個子模組：`app.internal.admin`。\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n同樣的檔案結構，附上註解：\n\n```bash\n.\n├── app                  # 「app」是一個 Python 套件\n│   ├── __init__.py      # 這個檔案讓「app」成為「Python 套件」\n│   ├── main.py          # 「main」模組，例如 import app.main\n│   ├── dependencies.py  # 「dependencies」模組，例如 import app.dependencies\n│   └── routers          # 「routers」是一個「Python 子套件」\n│   │   ├── __init__.py  # 讓「routers」成為「Python 子套件」\n│   │   ├── items.py     # 「items」子模組，例如 import app.routers.items\n│   │   └── users.py     # 「users」子模組，例如 import app.routers.users\n│   └── internal         # 「internal」是一個「Python 子套件」\n│       ├── __init__.py  # 讓「internal」成為「Python 子套件」\n│       └── admin.py     # 「admin」子模組，例如 import app.internal.admin\n```\n\n## `APIRouter` { #apirouter }\n\n假設專門處理使用者的檔案是位於 `/app/routers/users.py` 的子模組。\n\n你希望把與使用者相關的「路徑操作 (path operation)」從其他程式碼分離，讓結構更有條理。\n\n但它仍然是同一個 FastAPI 應用程式 / Web API 的一部分（屬於同一個「Python 套件」）。\n\n你可以使用 `APIRouter` 為該模組建立路徑操作。\n\n### 匯入 `APIRouter` { #import-apirouter }\n\n你可以像對 `FastAPI` 類別那樣匯入並建立一個「實例」：\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n### 使用 `APIRouter` 宣告路徑操作 { #path-operations-with-apirouter }\n\n然後用它來宣告你的路徑操作。\n\n用法就和 `FastAPI` 類別一樣：\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[6,11,16] title[\"app/routers/users.py\"] *}\n\n你可以把 `APIRouter` 想成是「迷你版的 `FastAPI`」類別。\n\n所有相同的選項都支援。\n\n同樣的 `parameters`、`responses`、`dependencies`、`tags` 等全都可用。\n\n/// tip | 提示\n\n在這個範例中，變數名叫 `router`，但你可以用任何你想用的名稱。\n\n///\n\n我們稍後會把這個 `APIRouter` 加進主要的 `FastAPI` 應用程式中，但先來看看相依性與另一個 `APIRouter`。\n\n## 相依性 { #dependencies }\n\n我們發現應用程式的多個地方會用到一些相依性。\n\n所以把它們放進獨立的 `dependencies` 模組（`app/dependencies.py`）。\n\n接下來我們會用一個簡單的相依性來讀取自訂的 `X-Token` 標頭：\n\n{* ../../docs_src/bigger_applications/app_an_py310/dependencies.py hl[3,6:8] title[\"app/dependencies.py\"] *}\n\n/// tip | 提示\n\n為了簡化範例，我們使用了一個虛構的標頭。\n\n但在真實情況下，使用內建的 [安全工具](security/index.md) 會有更好的效果。\n\n///\n\n## 另一個帶有 `APIRouter` 的模組 { #another-module-with-apirouter }\n\n假設你還有一個模組 `app/routers/items.py`，專門處理應用程式中的「items」。\n\n你有以下路徑操作：\n\n* `/items/`\n* `/items/{item_id}`\n\n其結構與 `app/routers/users.py` 相同。\n\n但我們想要更聰明地簡化一些程式碼。\n\n我們知道這個模組中的所有路徑操作都有相同的：\n\n* 路徑 `prefix`：`/items`\n* `tags`：（只有一個標籤：`items`）\n* 額外的 `responses`\n* `dependencies`：它們都需要我們先前建立的 `X-Token` 相依性\n\n因此，我們可以不必把這些都加在每個路徑操作上，而是把它們加在 `APIRouter` 上。\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[5:10,16,21] title[\"app/routers/items.py\"] *}\n\n由於每個路徑操作的路徑都必須以 `/` 開頭，例如：\n\n```Python hl_lines=\"1\"\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    ...\n```\n\n...所以 prefix 末尾不能帶有 `/`。\n\n因此，此處的 prefix 是 `/items`。\n\n我們也可以加上一個 `tags` 清單，以及會套用在此 router 內所有路徑操作上的額外 `responses`。\n\n我們還可以加上一個 `dependencies` 清單，這些相依性會加入此 router 內所有的路徑操作，並在對它們的每個請求上執行 / 解決。\n\n/// tip | 提示\n\n請注意，就像在[路徑操作裝飾器中的相依性](dependencies/dependencies-in-path-operation-decorators.md)一樣，不會把任何值傳遞給你的路徑操作函式（path operation function）。\n\n///\n\n最後的結果是這些 item 的路徑如下：\n\n* `/items/`\n* `/items/{item_id}`\n\n...正如我們預期的。\n\n* 它們會被標記為只有一個字串 `\"items\"` 的標籤清單。\n    * 這些「標籤」對自動互動式文件系統（使用 OpenAPI）特別有用。\n* 它們都會包含預先定義的 `responses`。\n* 這些路徑操作都會在執行前評估 / 執行其 `dependencies` 清單。\n    * 如果你也在特定的路徑操作中宣告了相依性，這些相依性也會被執行。\n    * Router 的相依性會先執行，然後是[裝飾器中的 `dependencies`](dependencies/dependencies-in-path-operation-decorators.md)，最後是一般參數相依性。\n    * 你也可以加入帶有 `scopes` 的 [`Security` 相依性](../advanced/security/oauth2-scopes.md)。\n\n/// tip | 提示\n\n在 `APIRouter` 中設定 `dependencies`，例如可以用來對一整組路徑操作要求驗證。即使沒有在每個路徑操作個別加入相依性也沒關係。\n\n///\n\n/// check | 檢查\n\n`prefix`、`tags`、`responses` 與 `dependencies` 參數（就像許多其他情況一樣）只是 FastAPI 提供的功能，幫助你避免重複程式碼。\n\n///\n\n### 匯入相依性 { #import-the-dependencies }\n\n這段程式碼在模組 `app.routers.items`（檔案 `app/routers/items.py`）中。\n\n我們需要從模組 `app.dependencies`（檔案 `app/dependencies.py`）取得相依性函式。\n\n因此我們用 `..` 做相對匯入相依性：\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[3] title[\"app/routers/items.py\"] *}\n\n#### 相對匯入如何運作 { #how-relative-imports-work }\n\n/// tip | 提示\n\n如果你對匯入的運作方式十分了解，可以直接跳到下一節。\n\n///\n\n單一的點號 `.`，如下：\n\n```Python\nfrom .dependencies import get_token_header\n```\n\n代表：\n\n* 從此模組（檔案 `app/routers/items.py`）所在的相同套件（目錄 `app/routers/`）開始...\n* 找到模組 `dependencies`（想像的檔案 `app/routers/dependencies.py`）...\n* 並從中匯入函式 `get_token_header`。\n\n但那個檔案不存在，我們的相依性在 `app/dependencies.py`。\n\n回想一下我們的應用 / 檔案結構長這樣：\n\n<img src=\"/img/tutorial/bigger-applications/package.drawio.svg\">\n\n---\n\n兩個點號 `..`，如下：\n\n```Python\nfrom ..dependencies import get_token_header\n```\n\n代表：\n\n* 從此模組（檔案 `app/routers/items.py`）所在的相同套件（目錄 `app/routers/`）開始...\n* 前往其父套件（目錄 `app/`）...\n* 然後在那裡找到模組 `dependencies`（檔案 `app/dependencies.py`）...\n* 並從中匯入函式 `get_token_header`。\n\n這就正確了！🎉\n\n---\n\n同樣地，如果我們用三個點號 `...`，如下：\n\n```Python\nfrom ...dependencies import get_token_header\n```\n\n就代表：\n\n* 從此模組（檔案 `app/routers/items.py`）所在的相同套件（目錄 `app/routers/`）開始...\n* 前往其父套件（目錄 `app/`）...\n* 再前往那個套件的父層（沒有更上層的套件了，`app` 已是最上層 😱）...\n* 然後在那裡找到模組 `dependencies`（檔案 `app/dependencies.py`）...\n* 並從中匯入函式 `get_token_header`。\n\n那會指向 `app/` 之上的某個套件，該套件需有自己的 `__init__.py` 等等。但我們沒有。所以在這個例子中會丟出錯誤。🚨\n\n不過現在你知道它的運作方式了，因此無論你的應用有多複雜，你都可以使用相對匯入。🤓\n\n### 加上一些自訂的 `tags`、`responses` 與 `dependencies` { #add-some-custom-tags-responses-and-dependencies }\n\n我們沒有把 `/items` 的 prefix 以及 `tags=[\"items\"]` 加在每個路徑操作上，因為我們已經把它們加在 `APIRouter` 上了。\n\n但我們仍可以在特定的路徑操作上再加上更多的 `tags`，以及一些只屬於該路徑操作的額外 `responses`：\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/items.py hl[30:31] title[\"app/routers/items.py\"] *}\n\n/// tip | 提示\n\n這最後一個路徑操作會有組合後的標籤：`[\"items\", \"custom\"]`。\n\n而且在文件中同時會有 `404` 與 `403` 兩種回應。\n\n///\n\n## 主程式 `FastAPI` { #the-main-fastapi }\n\n現在，來看看 `app/main.py` 這個模組。\n\n你會在這裡匯入並使用 `FastAPI` 類別。\n\n這會是你的應用程式中把一切串起來的主檔案。\n\n而隨著大多數的邏輯都放在各自的模組中，主檔案會相當簡潔。\n\n### 匯入 `FastAPI` { #import-fastapi }\n\n照常匯入並建立 `FastAPI` 類別。\n\n我們甚至可以宣告[全域相依性](dependencies/global-dependencies.md)，它們會與各 `APIRouter` 的相依性合併：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[1,3,7] title[\"app/main.py\"] *}\n\n### 匯入 `APIRouter` { #import-the-apirouter }\n\n現在我們匯入包含 `APIRouter` 的其他子模組：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[4:5] title[\"app/main.py\"] *}\n\n由於 `app/routers/users.py` 與 `app/routers/items.py` 是同一個 Python 套件 `app` 的子模組，我們可以用單一的點號 `.` 來進行「相對匯入」。\n\n### 匯入如何運作 { #how-the-importing-works }\n\n這段：\n\n```Python\nfrom .routers import items, users\n```\n\n代表：\n\n* 從此模組（檔案 `app/main.py`）所在的相同套件（目錄 `app/`）開始...\n* 尋找子套件 `routers`（目錄 `app/routers/`）...\n* 並從中匯入子模組 `items`（檔案 `app/routers/items.py`）與 `users`（檔案 `app/routers/users.py`）...\n\n模組 `items` 會有一個變數 `router`（`items.router`）。這就是我們在 `app/routers/items.py` 建立的那個 `APIRouter` 物件。\n\n接著我們對 `users` 模組做一樣的事。\n\n我們也可以這樣匯入：\n\n```Python\nfrom app.routers import items, users\n```\n\n/// info | 資訊\n\n第一種是「相對匯入」：\n\n```Python\nfrom .routers import items, users\n```\n\n第二種是「絕對匯入」：\n\n```Python\nfrom app.routers import items, users\n```\n\n想了解更多關於 Python 套件與模組，請閱讀[官方的模組說明文件](https://docs.python.org/3/tutorial/modules.html)。\n\n///\n\n### 避免名稱衝突 { #avoid-name-collisions }\n\n我們直接匯入子模組 `items`，而不是只匯入它的變數 `router`。\n\n這是因為在子模組 `users` 中也有另一個名為 `router` 的變數。\n\n如果我們像下面這樣一個接一個匯入：\n\n```Python\nfrom .routers.items import router\nfrom .routers.users import router\n```\n\n來自 `users` 的 `router` 會覆蓋掉 `items` 的 `router`，我們就無法同時使用兩者。\n\n因此，為了能在同一個檔案中同時使用它們，我們直接匯入子模組：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[5] title[\"app/main.py\"] *}\n\n### 將 `users` 與 `items` 的 `APIRouter` 納入 { #include-the-apirouters-for-users-and-items }\n\n現在，把子模組 `users` 與 `items` 的 `router` 納入：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[10:11] title[\"app/main.py\"] *}\n\n/// info | 資訊\n\n`users.router` 是位於 `app/routers/users.py` 檔案內的 `APIRouter`。\n\n而 `items.router` 是位於 `app/routers/items.py` 檔案內的 `APIRouter`。\n\n///\n\n透過 `app.include_router()`，我們可以把每個 `APIRouter` 加到主要的 `FastAPI` 應用程式。\n\n它會把該 router 的所有路由都納入成為應用的一部分。\n\n/// note | 技術細節\n\n實際上，它會在內部為 `APIRouter` 中宣告的每一個「路徑操作」建立一個對應的「路徑操作」。\n\n所以在幕後，它實際運作起來就像是一個單一的應用。\n\n///\n\n/// check | 檢查\n\n把 router 納入時不需要擔心效能。\n\n這只會在啟動時花費微秒等級，且只發生一次。\n\n因此不會影響效能。⚡\n\n///\n\n### 以自訂的 `prefix`、`tags`、`responses` 與 `dependencies` 納入一個 `APIRouter` { #include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies }\n\n現在，假設你的組織提供了一個 `app/internal/admin.py` 檔案給你。\n\n它包含一個帶有一些管理員路徑操作的 `APIRouter`，並在組織內多個專案之間共用。\n\n為了這個範例它會非常簡單。但假設因為它會與組織內的其他專案共用，我們不能直接修改它並把 `prefix`、`dependencies`、`tags` 等加在 `APIRouter` 上：\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\n但當我們把這個 `APIRouter` 納入時，仍然希望設定自訂的 `prefix`，讓它所有的路徑操作都以 `/admin` 開頭；我們想用這個專案已經有的 `dependencies` 來保護它，並且要加入 `tags` 與 `responses`。\n\n我們可以在不修改原始 `APIRouter` 的情況下，將這些參數傳給 `app.include_router()` 來達成：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[14:17] title[\"app/main.py\"] *}\n\n如此一來，原始的 `APIRouter` 將保持不變，因此我們仍然可以把同一個 `app/internal/admin.py` 檔案與組織中的其他專案共用。\n\n結果是在我們的應用中，來自 `admin` 模組的每個路徑操作都會有：\n\n* 前綴 `/admin`\n* 標籤 `admin`\n* 相依性 `get_token_header`\n* 回應 `418` 🍵\n\n但這只會影響我們應用中的那個 `APIRouter`，不會影響任何其他使用它的程式碼。\n\n例如，其他專案可以用不同的驗證方式搭配相同的 `APIRouter`。\n\n### 加上一個路徑操作 { #include-a-path-operation }\n\n我們也可以直接把路徑操作加到 `FastAPI` 應用中。\n\n這裡我們就加一下... 只是為了示範可以這麼做 🤷：\n\n{* ../../docs_src/bigger_applications/app_an_py310/main.py hl[21:23] title[\"app/main.py\"] *}\n\n而且它會和透過 `app.include_router()` 加入的其他路徑操作正確地一起運作。\n\n/// info | 非常技術細節\n\n注意：這是個非常技術性的細節，你大概可以直接略過。\n\n---\n\n`APIRouter` 不是被「掛載 (mount)」的，它們不會與應用的其他部分隔離開來。\n\n這是因為我們要把它們的路徑操作包含進 OpenAPI 結構與使用者介面中。\n\n由於無法將它們隔離並獨立「掛載」，所以這些路徑操作會被「複製」（重新建立），而不是直接包含進來。\n\n///\n\n## 在 `pyproject.toml` 設定 `entrypoint` { #configure-the-entrypoint-in-pyproject-toml }\n\n因為你的 FastAPI `app` 物件位在 `app/main.py`，你可以在 `pyproject.toml` 檔案中這樣設定 `entrypoint`：\n\n```toml\n[tool.fastapi]\nentrypoint = \"app.main:app\"\n```\n\n這等同於這樣匯入：\n\n```python\nfrom app.main import app\n```\n\n如此一來 `fastapi` 指令就會知道去哪裡找到你的 app。\n\n/// Note | 注意\n\n你也可以把路徑直接傳給指令，例如：\n\n```console\n$ fastapi dev app/main.py\n```\n\n但你每次呼叫 `fastapi` 指令時都得記得傳入正確的路徑。\n\n此外，其他工具可能找不到它，例如 [VS Code 擴充套件](../editor-support.md) 或 [FastAPI Cloud](https://fastapicloud.com)，因此建議在 `pyproject.toml` 中使用 `entrypoint`。\n\n///\n\n## 檢查自動產生的 API 文件 { #check-the-automatic-api-docs }\n\n現在，執行你的應用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n然後開啟位於 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs) 的文件。\n\n你會看到自動產生的 API 文件，包含來自所有子模組的路徑，使用正確的路徑（與前綴）與正確的標籤：\n\n<img src=\"/img/tutorial/bigger-applications/image01.png\">\n\n## 以不同的 `prefix` 多次納入同一個 router { #include-the-same-router-multiple-times-with-different-prefix }\n\n你也可以用不同的前綴，對同一個 router 多次呼叫 `.include_router()`。\n\n例如，這對於在不同前綴下提供相同的 API 很有用，如 `/api/v1` 與 `/api/latest`。\n\n這是進階用法，你可能不會需要，但若有需要它就在那裡。\n\n## 在另一個 `APIRouter` 中納入一個 `APIRouter` { #include-an-apirouter-in-another }\n\n就像你可以在 `FastAPI` 應用中納入一個 `APIRouter` 一樣，你也可以在另一個 `APIRouter` 中納入一個 `APIRouter`，用法如下：\n\n```Python\nrouter.include_router(other_router)\n```\n\n請確保在把 `router` 納入 `FastAPI` 應用之前先這麼做，這樣 `other_router` 的路徑操作也會被包含進去。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/body-fields.md",
    "content": "# Body - 欄位 { #body-fields }\n\n就像你可以在「路徑操作函式 (path operation function)」的參數中用 `Query`、`Path` 和 `Body` 宣告額外的驗證與中繼資料一樣，你也可以在 Pydantic 模型中使用 Pydantic 的 `Field` 來宣告驗證與中繼資料。\n\n## 匯入 `Field` { #import-field }\n\n首先，你需要匯入它：\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[4] *}\n\n\n/// warning\n\n請注意，`Field` 是直接從 `pydantic` 匯入的，不像其他（如 `Query`、`Path`、`Body` 等）是從 `fastapi` 匯入。\n\n///\n\n## 宣告模型屬性 { #declare-model-attributes }\n\n接著你可以在模型屬性上使用 `Field`：\n\n{* ../../docs_src/body_fields/tutorial001_an_py310.py hl[11:14] *}\n\n`Field` 的用法與 `Query`、`Path`、`Body` 相同，擁有相同的參數等。\n\n/// note | 技術細節\n\n實際上，你接下來會看到的 `Query`、`Path` 等，會建立共同父類別 `Param` 的子類別物件，而 `Param` 本身是 Pydantic 的 `FieldInfo` 類別的子類別。\n\n而 Pydantic 的 `Field` 也會回傳一個 `FieldInfo` 的實例。\n\n`Body` 也會直接回傳 `FieldInfo` 子類別的物件。稍後你會看到還有其他類別是 `Body` 類別的子類別。\n\n記得，當你從 `fastapi` 匯入 `Query`、`Path` 等時，它們其實是回傳特殊類別的函式。\n\n///\n\n/// tip\n\n注意，每個帶有型別、預設值與 `Field` 的模型屬性，其結構和「路徑操作函式」的參數相同，只是把 `Path`、`Query`、`Body` 換成了 `Field`。\n\n///\n\n## 加入額外資訊 { #add-extra-information }\n\n你可以在 `Field`、`Query`、`Body` 等中宣告額外資訊。這些資訊會被包含在產生的 JSON Schema 中。\n\n你會在後續文件中學到更多關於加入額外資訊的內容，特別是在宣告範例時。\n\n/// warning\n\n傳入 `Field` 的額外鍵也會出現在你的應用程式所產生的 OpenAPI schema 中。\n由於這些鍵不一定屬於 OpenAPI 規格的一部分，一些 OpenAPI 工具（例如 [OpenAPI 驗證器](https://validator.swagger.io/)）可能無法處理你產生的 schema。\n\n///\n\n## 回顧 { #recap }\n\n你可以使用 Pydantic 的 `Field` 為模型屬性宣告額外的驗證與中繼資料。\n\n你也可以使用額外的關鍵字引數來傳遞額外的 JSON Schema 中繼資料。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/body-multiple-params.md",
    "content": "# Body - 多個參數 { #body-multiple-parameters }\n\n現在我們已經知道如何使用 `Path` 與 `Query`，接下來看看更進階的請求主體（request body）宣告用法。\n\n## 混用 `Path`、`Query` 與 Body 參數 { #mix-path-query-and-body-parameters }\n\n首先，當然你可以自由混用 `Path`、`Query` 與請求 Body 參數的宣告，**FastAPI** 會知道該怎麼做。\n\n你也可以將 Body 參數宣告為可選，方法是將預設值設為 `None`：\n\n{* ../../docs_src/body_multiple_params/tutorial001_an_py310.py hl[18:20] *}\n\n/// note | 注意\n\n請注意，在此情況下，從 body 取得的 `item` 是可選的，因為它的預設值是 `None`。\n\n///\n\n## 多個 Body 參數 { #multiple-body-parameters }\n\n在前一個範例中，路徑操作（path operation）會期望一個包含 `Item` 屬性的 JSON 主體，例如：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n但你也可以宣告多個 Body 參數，例如 `item` 與 `user`：\n\n{* ../../docs_src/body_multiple_params/tutorial002_py310.py hl[20] *}\n\n在此情況下，**FastAPI** 會注意到函式中有多個 Body 參數（有兩個參數是 Pydantic 模型）。\n\n因此，它會使用參數名稱作為 body 中的鍵（欄位名稱），並期望如下的主體：\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    }\n}\n```\n\n/// note | 注意\n\n儘管 `item` 的宣告方式與先前相同，現在預期它會位於 body 內，且鍵為 `item`。\n\n///\n\n**FastAPI** 會自動從請求中進行轉換，讓參數 `item` 收到對應內容，`user` 亦同。\n\n它會對複合資料進行驗證，並在 OpenAPI 結構與自動文件中如此描述。\n\n## Body 中的單一值 { #singular-values-in-body }\n\n就像你可以用 `Query` 與 `Path` 為查詢與路徑參數定義額外資訊一樣，**FastAPI** 也提供對應的 `Body`。\n\n例如，延伸前述模型，你可以決定在相同的 Body 中，除了 `item` 與 `user` 外，還要有另一個鍵 `importance`。\n\n如果直接這樣宣告，因為它是單一值，**FastAPI** 會將其視為查詢參數。\n\n但你可以使用 `Body` 指示 **FastAPI** 將其視為另一個 Body 鍵：\n\n{* ../../docs_src/body_multiple_params/tutorial003_an_py310.py hl[23] *}\n\n在此情況下，**FastAPI** 會期望如下的主體：\n\n```JSON\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    },\n    \"user\": {\n        \"username\": \"dave\",\n        \"full_name\": \"Dave Grohl\"\n    },\n    \"importance\": 5\n}\n```\n\n同樣地，它會進行型別轉換、驗證、文件化等。\n\n## 多個 Body 參數與 Query { #multiple-body-params-and-query }\n\n當然，你也可以在任何 Body 參數之外，視需要宣告額外的查詢參數。\n\n由於預設情況下，單一值會被解讀為查詢參數，你不必明確使用 `Query`，直接這樣寫即可：\n\n```Python\nq: str | None = None\n```\n\n例如：\n\n{* ../../docs_src/body_multiple_params/tutorial004_an_py310.py hl[28] *}\n\n/// info | 注意\n\n`Body` 也具有與 `Query`、`Path` 以及之後你會看到的其他工具相同的額外驗證與中繼資料參數。\n\n///\n\n## 嵌入單一 Body 參數 { #embed-a-single-body-parameter }\n\n假設你只有一個來自 Pydantic 模型 `Item` 的單一 `item` Body 參數。\n\n預設情況下，**FastAPI** 會直接期望該模型的內容作為請求主體。\n\n但如果你想讓它像宣告多個 Body 參數時那樣，期望一個帶有 `item` 鍵、其內含模型內容的 JSON，你可以使用 `Body` 的特殊參數 `embed`：\n\n```Python\nitem: Item = Body(embed=True)\n```\n\n如下：\n\n{* ../../docs_src/body_multiple_params/tutorial005_an_py310.py hl[17] *}\n\n在此情況下 **FastAPI** 會期望如下的主體：\n\n```JSON hl_lines=\"2\"\n{\n    \"item\": {\n        \"name\": \"Foo\",\n        \"description\": \"The pretender\",\n        \"price\": 42.0,\n        \"tax\": 3.2\n    }\n}\n```\n\n而不是：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2\n}\n```\n\n## 小結 { #recap }\n\n即便一個請求只能有單一主體，你仍可在你的路徑操作函式中宣告多個 Body 參數。\n\n但 **FastAPI** 會處理好這一切，在你的函式中提供正確的資料，並在路徑操作中驗證與文件化正確的結構。\n\n你也可以將單一值宣告為 Body 的一部分來接收。\n\n即使只宣告了一個參數，也可以指示 **FastAPI** 將 Body 以某個鍵進行嵌入。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/body-nested-models.md",
    "content": "# Body - 巢狀模型 { #body-nested-models }\n\n使用 **FastAPI**，你可以定義、驗證、文件化，並使用任意深度的巢狀模型（感謝 Pydantic）。\n\n## 列表欄位 { #list-fields }\n\n你可以將屬性定義為某個子型別。例如，Python 的 `list`：\n\n{* ../../docs_src/body_nested_models/tutorial001_py310.py hl[12] *}\n\n這會讓 `tags` 成為一個列表，儘管尚未宣告列表元素的型別。\n\n## 具有型別參數的列表欄位 { #list-fields-with-type-parameter }\n\n不過，Python 有一種專門的方式來宣告具有內部型別（「型別參數」）的列表：\n\n### 宣告帶有型別參數的 `list` { #declare-a-list-with-a-type-parameter }\n\n要宣告具有型別參數（內部型別）的型別，例如 `list`、`dict`、`tuple`，使用方括號 `[` 與 `]` 傳入內部型別作為「型別參數」：\n\n```Python\nmy_list: list[str]\n```\n\n以上都是標準的 Python 型別宣告語法。\n\n對於具有內部型別的模型屬性，也使用相同的標準語法。\n\n因此，在我們的範例中，可以讓 `tags` 明確成為「字串的列表」：\n\n{* ../../docs_src/body_nested_models/tutorial002_py310.py hl[12] *}\n\n## 集合型別 { #set-types }\n\n但進一步思考後，我們會意識到 `tags` 不應該重覆，應該是唯一的字串。\n\n而 Python 有一種用於唯一元素集合的特殊資料型別：`set`。\n\n因此我們可以將 `tags` 宣告為字串的 `set`：\n\n{* ../../docs_src/body_nested_models/tutorial003_py310.py hl[12] *}\n\n這樣一來，即使收到包含重覆資料的請求，也會被轉換為由唯一元素組成的 `set`。\n\n之後只要輸出該資料，即使來源有重覆，也會以唯一元素的 `set` 輸出。\n\n並且也會在註解／文件中相應標示。\n\n## 巢狀模型 { #nested-models }\n\n每個 Pydantic 模型的屬性都有型別。\n\n而該型別本身也可以是另一個 Pydantic 模型。\n\n因此，你可以宣告具有特定屬性名稱、型別與驗證的深度巢狀 JSON「物件」。\n\n而且可以任意深度巢狀。\n\n### 定義子模型 { #define-a-submodel }\n\n例如，我們可以定義一個 `Image` 模型：\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[7:9] *}\n\n### 將子模型作為型別使用 { #use-the-submodel-as-a-type }\n\n然後把它作為某個屬性的型別使用：\n\n{* ../../docs_src/body_nested_models/tutorial004_py310.py hl[18] *}\n\n這表示 **FastAPI** 會期望一個類似如下的本文：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\"rock\", \"metal\", \"bar\"],\n    \"image\": {\n        \"url\": \"http://example.com/baz.jpg\",\n        \"name\": \"The Foo live\"\n    }\n}\n```\n\n只需進行上述宣告，使用 **FastAPI** 你就能獲得：\n\n- 編輯器支援（自動完成等），即使是巢狀模型\n- 資料轉換\n- 資料驗證\n- 自動產生文件\n\n## 特殊型別與驗證 { #special-types-and-validation }\n\n除了 `str`、`int`、`float` 等一般的單一型別外，你也可以使用繼承自 `str` 的更複雜單一型別。\n\n若要查看所有可用選項，請參閱 [Pydantic 的型別總覽](https://docs.pydantic.dev/latest/concepts/types/)。你會在下一章看到一些範例。\n\n例如，在 `Image` 模型中有一個 `url` 欄位，我們可以將其宣告為 Pydantic 的 `HttpUrl`，而不是 `str`：\n\n{* ../../docs_src/body_nested_models/tutorial005_py310.py hl[2,8] *}\n\n該字串會被檢查是否為有效的 URL，並在 JSON Schema / OpenAPI 中相應註記。\n\n## 具有子模型列表的屬性 { #attributes-with-lists-of-submodels }\n\n你也可以將 Pydantic 模型作為 `list`、`set` 等的子型別使用：\n\n{* ../../docs_src/body_nested_models/tutorial006_py310.py hl[18] *}\n\n這會期望（並進行轉換、驗證、文件化等）如下的 JSON 本文：\n\n```JSON hl_lines=\"11\"\n{\n    \"name\": \"Foo\",\n    \"description\": \"The pretender\",\n    \"price\": 42.0,\n    \"tax\": 3.2,\n    \"tags\": [\n        \"rock\",\n        \"metal\",\n        \"bar\"\n    ],\n    \"images\": [\n        {\n            \"url\": \"http://example.com/baz.jpg\",\n            \"name\": \"The Foo live\"\n        },\n        {\n            \"url\": \"http://example.com/dave.jpg\",\n            \"name\": \"The Baz\"\n        }\n    ]\n}\n```\n\n/// info\n\n注意 `images` 鍵現在是一個由 image 物件組成的列表。\n\n///\n\n## 深度巢狀模型 { #deeply-nested-models }\n\n你可以定義任意深度的巢狀模型：\n\n{* ../../docs_src/body_nested_models/tutorial007_py310.py hl[7,12,18,21,25] *}\n\n/// info\n\n請注意，`Offer` 具有一個 `Item` 的列表，而每個 `Item` 又有一個可選的 `Image` 列表。\n\n///\n\n## 純列表的本文 { #bodies-of-pure-lists }\n\n如果你期望的 JSON 本文頂層值是一個 JSON `array`（Python 的 `list`），可以像在 Pydantic 模型中那樣，直接在函式參數上宣告其型別：\n\n```Python\nimages: list[Image]\n```\n\n如下所示：\n\n{* ../../docs_src/body_nested_models/tutorial008_py310.py hl[13] *}\n\n## 隨處可得的編輯器支援 { #editor-support-everywhere }\n\n你將在各處獲得編輯器支援。\n\n即使是列表中的項目也一樣：\n\n<img src=\"/img/tutorial/body-nested-models/image01.png\">\n\n若直接操作 `dict` 而不是使用 Pydantic 模型，就無法獲得這種等級的編輯器支援。\n\n但你也不必擔心，傳入的 dict 會自動被轉換，而你的輸出也會自動轉換為 JSON。\n\n## 任意 `dict` 的本文 { #bodies-of-arbitrary-dicts }\n\n你也可以將本文宣告為一個 `dict`，其鍵為某種型別、值為另一種型別。\n\n如此一來，你無需事先知道有效的欄位／屬性名稱為何（不像使用 Pydantic 模型時需要）。\n\n這在你想接收尚未預知的鍵時很有用。\n\n---\n\n另一個實用情境是當你希望鍵是其他型別（例如，`int`）時。\n\n這正是我們在此要示範的。\n\n在此情況下，只要是擁有 `int` 鍵且對應 `float` 值的 `dict` 都會被接受：\n\n{* ../../docs_src/body_nested_models/tutorial009_py310.py hl[7] *}\n\n/// tip\n\n請記住，JSON 只支援 `str` 作為鍵。\n\n但 Pydantic 具有自動資料轉換。\n\n這表示即使你的 API 用戶端只能以字串作為鍵，只要這些字串是純整數，Pydantic 會自動轉換並驗證它們。\n\n而你作為 `weights` 所接收的 `dict`，實際上會擁有 `int` 鍵與 `float` 值。\n\n///\n\n## 總結 { #recap }\n\n使用 **FastAPI**，你在保持程式碼簡潔優雅的同時，亦可擁有 Pydantic 模型所提供的高度彈性。\n\n同時還具備以下優點：\n\n- 編輯器支援（到處都有自動完成！）\n- 資料轉換（亦即 parsing／serialization）\n- 資料驗證\n- 結構描述（Schema）文件\n- 自動產生文件\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/body-updates.md",
    "content": "# Body - 更新 { #body-updates }\n\n## 使用 `PUT` 取代式更新 { #update-replacing-with-put }\n\n要更新一個項目，你可以使用 [HTTP `PUT`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) 操作。\n\n你可以使用 `jsonable_encoder` 將輸入資料轉換為可儲存為 JSON 的資料（例如用於 NoSQL 資料庫）。例如把 `datetime` 轉成 `str`。\n\n{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *}\n\n`PUT` 用於接收應該取代現有資料的資料。\n\n### 關於取代的警告 { #warning-about-replacing }\n\n這表示，如果你想用 `PUT` 並在 body 中包含以下內容來更新項目 `bar`：\n\n```Python\n{\n    \"name\": \"Barz\",\n    \"price\": 3,\n    \"description\": None,\n}\n```\n\n由於這裡沒有包含已儲存的屬性 `\"tax\": 20.2`，輸入的模型會採用預設值 `\"tax\": 10.5`。\n\n最終資料會以這個「新的」 `tax` 值 `10.5` 被儲存。\n\n## 使用 `PATCH` 進行部分更新 { #partial-updates-with-patch }\n\n你也可以使用 [HTTP `PATCH`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH) 操作來進行*部分*更新。\n\n這表示你只需傳送想要更新的資料，其餘保持不變。\n\n/// note | 注意\n\n`PATCH` 相較於 `PUT` 較少被使用、也較不為人知。\n\n許多團隊甚至在部分更新時也只用 `PUT`。\n\n你可以依需求自由選用，**FastAPI** 不會強制規範。\n\n但本指南會大致示範它們各自的設計用法。\n\n///\n\n### 使用 Pydantic 的 `exclude_unset` 參數 { #using-pydantics-exclude-unset-parameter }\n\n如果要接收部分更新，在 Pydantic 模型的 `.model_dump()` 中使用 `exclude_unset` 參數非常實用。\n\n例如 `item.model_dump(exclude_unset=True)`。\n\n這會產生一個只包含建立 `item` 模型時實際設定過之欄位的 `dict`，不含預設值。\n\n接著你可以用它來生成只包含實際設定（請求中傳來）的資料之 `dict`，省略預設值：\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *}\n\n### 使用 Pydantic 的 `update` 參數 { #using-pydantics-update-parameter }\n\n接著，你可以用 `.model_copy()` 建立現有模型的副本，並傳入含有要更新資料之 `dict` 到 `update` 參數。\n\n例如 `stored_item_model.model_copy(update=update_data)`：\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *}\n\n### 部分更新摘要 { #partial-updates-recap }\n\n總結一下，若要套用部分更新，你可以：\n\n*（可選）使用 `PATCH` 取代 `PUT`。\n* 取回已儲存的資料。\n* 將該資料放入一個 Pydantic 模型。\n* 從輸入模型產生一個不含預設值的 `dict`（使用 `exclude_unset`）。\n    * 如此即可只更新使用者實際設定的值，而不會以模型的預設值覆寫已儲存的值。\n* 建立已儲存模型的副本，並以收到的部分更新值更新其屬性（使用 `update` 參數）。\n* 將該副本模型轉成可儲存到資料庫的型別（例如使用 `jsonable_encoder`）。\n    * 這與再次使用模型的 `.model_dump()` 類似，但它會確保（並轉換）所有值為可轉為 JSON 的資料型別，例如把 `datetime` 轉為 `str`。\n* 將資料儲存到資料庫。\n* 回傳更新後的模型。\n\n{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *}\n\n/// tip | 提示\n\n其實你也可以在 HTTP `PUT` 操作中使用同一套技巧。\n\n但此處示例使用 `PATCH`，因為它正是為這類情境設計的。\n\n///\n\n/// note | 注意\n\n請注意，輸入的模型依然會被驗證。\n\n因此，如果你希望接收可以省略所有屬性的部分更新，你需要一個所有屬性皆為可選（具預設值或為 `None`）的模型。\n\n為了區分用於更新（全部可選）與用於建立（欄位為必填）的模型，你可以參考 [額外模型](extra-models.md) 中的做法。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/body.md",
    "content": "# 請求本文 { #request-body }\n\n當你需要從用戶端（例如瀏覽器）將資料傳送到你的 API 時，會把它作為**請求本文**送出。\n\n**請求**本文是用戶端傳給你的 API 的資料。**回應**本文是你的 API 傳回給用戶端的資料。\n\n你的 API 幾乎總是需要傳回**回應**本文。但用戶端不一定每次都要送出**請求本文**，有時只會請求某個路徑，可能帶一些查詢參數，但不會傳送本文。\n\n要宣告**請求**本文，你會使用 [Pydantic](https://docs.pydantic.dev/) 模型，享受其完整的功能與優點。\n\n/// info\n\n要傳送資料，應使用下列其中一種方法：`POST`（最常見）、`PUT`、`DELETE` 或 `PATCH`。\n\n在規範中，於 `GET` 請求中攜帶本文的行為是未定義的。不過，FastAPI 仍支援它，但僅適用於非常複雜／極端的情境。\n\n由於不建議這麼做，使用 Swagger UI 的互動式文件在使用 `GET` 時不會顯示本文的文件，而且中間的代理伺服器也可能不支援。\n\n///\n\n## 匯入 Pydantic 的 `BaseModel` { #import-pydantics-basemodel }\n\n首先，從 `pydantic` 匯入 `BaseModel`：\n\n{* ../../docs_src/body/tutorial001_py310.py hl[2] *}\n\n## 建立你的資料模型 { #create-your-data-model }\n\n接著，你將資料模型宣告為繼承自 `BaseModel` 的類別。\n\n對所有屬性使用標準的 Python 型別：\n\n{* ../../docs_src/body/tutorial001_py310.py hl[5:9] *}\n\n就和宣告查詢參數時一樣，當模型屬性有預設值時，它就不是必填；否則就是必填。使用 `None` 可使其成為選填。\n\n例如，上述模型對應的 JSON「`object`」（或 Python `dict`）如下：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"description\": \"An optional description\",\n    \"price\": 45.2,\n    \"tax\": 3.5\n}\n```\n\n...由於 `description` 與 `tax` 是選填（預設為 `None`），以下這個 JSON「`object`」也有效：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 45.2\n}\n```\n\n## 將它宣告為參數 { #declare-it-as-a-parameter }\n\n要把它加到你的*路徑操作（path operation）*中，宣告方式與路徑與查詢參數相同：\n\n{* ../../docs_src/body/tutorial001_py310.py hl[16] *}\n\n...並將其型別宣告為你建立的模型 `Item`。\n\n## 效果 { #results }\n\n只靠這樣的 Python 型別宣告，**FastAPI** 會：\n\n- 將請求本文讀取為 JSON。\n- （必要時）轉換為對應的型別。\n- 驗證資料。\n    - 若資料無效，會回傳清楚易懂的錯誤，指出哪裡、哪筆資料不正確。\n- 把接收到的資料放在參數 `item` 中提供給你。\n    - 由於你在函式中將其宣告為 `Item` 型別，你也會獲得完整的編輯器支援（自動完成等）以及所有屬性與其型別。\n- 為你的模型產生 [JSON Schema](https://json-schema.org) 定義，如有需要，你也可以在專案中的其他地方使用。\n- 這些 schema 會成為產生的 OpenAPI schema 的一部分，並由自動文件 <abbr title=\"User Interfaces - 使用者介面\">UIs</abbr> 使用。\n\n## 自動文件 { #automatic-docs }\n\n你的模型的 JSON Schema 會納入產生的 OpenAPI schema，並顯示在互動式 API 文件中：\n\n<img src=\"/img/tutorial/body/image01.png\">\n\n也會用於每個需要它們的*路徑操作*內的 API 文件：\n\n<img src=\"/img/tutorial/body/image02.png\">\n\n## 編輯器支援 { #editor-support }\n\n在編輯器裡、於你的函式中，你會在各處獲得型別提示與自動完成（如果你接收的是 `dict` 而不是 Pydantic 模型，就不會有這些）：\n\n<img src=\"/img/tutorial/body/image03.png\">\n\n你也會獲得對不正確型別操作的錯誤檢查：\n\n<img src=\"/img/tutorial/body/image04.png\">\n\n這不是偶然，整個框架就是圍繞這個設計而建。\n\n而且在實作之前的設計階段就已徹底測試，確保能在各種編輯器中運作良好。\n\n甚至為了支援這點，Pydantic 本身也做了些修改。\n\n前面的螢幕截圖是使用 [Visual Studio Code](https://code.visualstudio.com) 拍的。\n\n但你在 [PyCharm](https://www.jetbrains.com/pycharm/) 與大多數其它 Python 編輯器中也會得到相同的編輯器支援：\n\n<img src=\"/img/tutorial/body/image05.png\">\n\n/// tip\n\n如果你使用 [PyCharm](https://www.jetbrains.com/pycharm/) 作為編輯器，可以安裝 [Pydantic PyCharm Plugin](https://github.com/koxudaxi/pydantic-pycharm-plugin/)。\n\n它能增強 Pydantic 模型的編輯器支援，包含：\n\n- 自動完成\n- 型別檢查\n- 重構\n- 搜尋\n- 程式碼檢查\n\n///\n\n## 使用該模型 { #use-the-model }\n\n在函式內，你可以直接存取模型物件的所有屬性：\n\n{* ../../docs_src/body/tutorial002_py310.py *}\n\n## 請求本文 + 路徑參數 { #request-body-path-parameters }\n\n你可以同時宣告路徑參數與請求本文。\n\n**FastAPI** 會辨識出與路徑參數相符的函式參數應該從**路徑**取得，而宣告為 Pydantic 模型的函式參數應該從**請求本文**取得。\n\n{* ../../docs_src/body/tutorial003_py310.py hl[15:16] *}\n\n## 請求本文 + 路徑 + 查詢參數 { #request-body-path-query-parameters }\n\n你也可以同時宣告**本文**、**路徑**與**查詢**參數。\n\n**FastAPI** 會分別辨識並從正確的位置取得資料。\n\n{* ../../docs_src/body/tutorial004_py310.py hl[16] *}\n\n函式參數的辨識方式如下：\n\n- 如果參數同時在**路徑**中宣告，則作為路徑參數。\n- 如果參數是**單一型別**（像是 `int`、`float`、`str`、`bool` 等），會被視為**查詢**參數。\n- 如果參數宣告為 **Pydantic 模型** 型別，會被視為請求**本文**。\n\n/// note\n\nFastAPI 會因為預設值 `= None` 而知道 `q` 的值不是必填。\n\n`str | None` 並非 FastAPI 用來判斷是否必填的依據；它會因為有預設值 `= None` 而知道不是必填。\n\n但加入這些型別註解能讓你的編輯器提供更好的支援與錯誤偵測。\n\n///\n\n## 不使用 Pydantic { #without-pydantic }\n\n若你不想使用 Pydantic 模型，也可以使用 **Body** 參數。請參考[Body - 多個參數：本文中的單一值](body-multiple-params.md#singular-values-in-body)。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/cookie-param-models.md",
    "content": "# Cookie 參數模型 { #cookie-parameter-models }\n\n如果你有一組彼此相關的「**Cookie**」，你可以建立一個「**Pydantic 模型**」來宣告它們。🍪\n\n這樣你就能在**多處**重複使用該模型，並且能一次性為所有參數宣告**驗證**與**中繼資料**。😎\n\n/// note | 注意\n\n自 FastAPI 版本 `0.115.0` 起支援。🤓\n\n///\n\n/// tip\n\n同樣的技巧也適用於 `Query`、`Cookie` 與 `Header`。😎\n\n///\n\n## 以 Pydantic 模型宣告 Cookie { #cookies-with-a-pydantic-model }\n\n在 **Pydantic 模型**中宣告所需的 **Cookie** 參數，接著將參數宣告為 `Cookie`：\n\n{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *}\n\n**FastAPI** 會從請求收到的 **Cookie** 中擷取 **每個欄位** 的資料，並交給你定義的 Pydantic 模型。\n\n## 查看文件 { #check-the-docs }\n\n你可以在 `/docs` 的文件介面中看到已定義的 Cookie：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/cookie-param-models/image01.png\">\n</div>\n\n/// info\n\n請注意，由於**瀏覽器會以特殊且在背景進行的方式處理 Cookie**，因此**不會**輕易允許 **JavaScript** 存取它們。\n\n當你前往位於 `/docs` 的 **API 文件介面**時，可以看到路徑操作的 Cookie 說明。\n\n但即使你**填入資料**並點擊「Execute」，因為該文件介面是以 **JavaScript** 運作，Cookie 不會被送出，你會看到**錯誤**訊息，就像完全沒有填任何值一樣。\n\n///\n\n## 禁止額外的 Cookie { #forbid-extra-cookies }\n\n在某些特殊情境（可能不太常見）下，你可能會想**限制**允許接收的 Cookie。\n\n你的 API 現在也能掌控自己的 <dfn title=\"這只是個玩笑，提醒一下。這與 Cookie 同意無關，但有趣的是連 API 現在也能拒絕可憐的 Cookie。請收下這塊餅乾。🍪\">Cookie 同意</dfn>。🤪🍪\n\n你可以使用 Pydantic 的模型設定來 `forbid` 任何 `extra` 欄位：\n\n{* ../../docs_src/cookie_param_models/tutorial002_an_py310.py hl[10] *}\n\n如果客戶端嘗試送出**額外的 Cookie**，會收到**錯誤**回應。\n\n可憐的 Cookie 橫幅辛苦收集你的同意，最後卻是為了<dfn title=\"又是一個玩笑。別理我。來杯咖啡配餅乾吧。☕\">讓 API 拒絕它</dfn>。🍪\n\n例如，若客戶端嘗試送出名為 `santa_tracker`、值為 `good-list-please` 的 Cookie，客戶端會收到**錯誤**回應，告知 `santa_tracker` 這個 <dfn title=\"聖誕老人不贊同沒有餅乾。🎅 好的，不再講餅乾笑話了。\">Cookie 不被允許</dfn>：\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"cookie\", \"santa_tracker\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"good-list-please\",\n        }\n    ]\n}\n```\n\n## 摘要 { #summary }\n\n你可以在 **FastAPI** 中使用 **Pydantic 模型**來宣告 <dfn title=\"走之前再來一塊餅乾吧。🍪\">**Cookie**</dfn>。😎\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/cookie-params.md",
    "content": "# Cookie 參數 { #cookie-parameters }\n\n你可以用與定義 `Query` 與 `Path` 參數相同的方式定義 Cookie 參數。\n\n## 匯入 `Cookie` { #import-cookie }\n\n先匯入 `Cookie`：\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[3] *}\n\n## 宣告 `Cookie` 參數 { #declare-cookie-parameters }\n\n然後用與 `Path`、`Query` 相同的結構宣告 `Cookie` 參數。\n\n你可以設定預設值，以及所有額外的驗證或註解參數：\n\n{* ../../docs_src/cookie_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | 技術細節\n\n`Cookie` 是 `Path` 與 `Query` 的「姊妹」類別。它同樣繼承自共同的 `Param` 類別。\n\n但請記住，當你從 `fastapi` 匯入 `Query`、`Path`、`Cookie` 等時，它們實際上是回傳特殊類別的函式。\n\n///\n\n/// info\n\n要宣告 cookies，你需要使用 `Cookie`，否則參數會被當作查詢參數（query parameters）來解析。\n\n///\n\n/// info\n\n請注意，由於瀏覽器以特殊且在背後處理的方式管理 cookies，它們通常不允許 JavaScript 輕易存取它們。\n\n如果你前往位於 `/docs` 的 API 文件介面，你可以在你的路徑操作（path operations）的文件中看到 cookies 的說明。\n\n但即使你填入資料並點擊「Execute」，由於該文件介面是以 JavaScript 運作，cookies 不會被送出，你會看到一則錯誤訊息，就好像你沒有填任何值一樣。\n\n///\n\n## 總結 { #recap }\n\n使用 `Cookie` 來宣告 cookies，遵循與 `Query`、`Path` 相同的通用寫法。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/cors.md",
    "content": "# CORS（跨來源資源共用） { #cors-cross-origin-resource-sharing }\n\n[CORS 或「Cross-Origin Resource Sharing」](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)指的是：當在瀏覽器中執行的前端以 JavaScript 與後端通訊，而後端與前端位於不同「來源（origin）」時的情境。\n\n## 來源（Origin） { #origin }\n\n一個來源是由通訊協定（`http`、`https`）、網域（`myapp.com`、`localhost`、`localhost.tiangolo.com`）與連接埠（`80`、`443`、`8080`）三者組合而成。\n\n因此，以下皆是不同的來源：\n\n* `http://localhost`\n* `https://localhost`\n* `http://localhost:8080`\n\n即使它們都在 `localhost`，但使用了不同的通訊協定或連接埠，所以它們是不同的「來源」。\n\n## 步驟 { #steps }\n\n假設你的前端在瀏覽器中執行於 `http://localhost:8080`，其 JavaScript 嘗試與執行在 `http://localhost` 的後端通訊（因為未指定連接埠，瀏覽器會假設預設連接埠為 `80`）。\n\n接著，瀏覽器會向 `:80` 的後端送出一個 HTTP `OPTIONS` 請求；若後端回傳適當的標頭，授權此不同來源（`http://localhost:8080`）的通訊，則在 `:8080` 的瀏覽器就會允許前端的 JavaScript 向 `:80` 的後端送出它的請求。\n\n為了達成這點，`:80` 的後端必須有一份「允許的來源」清單。\n\n在此情況下，該清單必須包含 `http://localhost:8080`，` :8080` 的前端才能正確運作。\n\n## 萬用字元 { #wildcards }\n\n也可以將清單宣告為 `\"*\"`（「wildcard」萬用字元），表示全部都允許。\n\n但那只會允許某些類型的通訊，凡是涉及憑證（credentials）的都會被排除：例如 Cookie、Authorization 標頭（像 Bearer Token 會用到的）等。\n\n因此，為了讓一切正常運作，最好明確指定被允許的來源。\n\n## 使用 `CORSMiddleware` { #use-corsmiddleware }\n\n你可以在 **FastAPI** 應用程式中使用 `CORSMiddleware` 來設定：\n\n* 匯入 `CORSMiddleware`。\n* 建立允許的來源清單（字串）。\n* 將它加入到你的 **FastAPI** 應用程式做為「中介軟體（middleware）」。\n\n你也可以指定你的後端是否允許：\n\n* 憑證（credentials，例如 Authorization 標頭、Cookie 等）。\n* 特定的 HTTP 方法（如 `POST`、`PUT`），或使用萬用字元 `\"*\"` 表示全部。\n* 特定的 HTTP 標頭，或使用萬用字元 `\"*\"` 表示全部。\n\n{* ../../docs_src/cors/tutorial001_py310.py hl[2,6:11,13:19] *}\n\n`CORSMiddleware` 的實作在預設參數上相當嚴格，因此你需要明確啟用特定的來源、方法或標頭，瀏覽器才會允許在跨網域情境中使用它們。\n\n支援以下參數：\n\n* `allow_origins` - 允許進行跨來源請求的來源清單。例如 `['https://example.org', 'https://www.example.org']`。你可以使用 `['*']` 來允許任何來源。\n* `allow_origin_regex` - 允許進行跨來源請求的來源，使用正規表示式字串比對。例如 `'https://.*\\.example\\.org'`。\n* `allow_methods` - 允許跨來源請求的 HTTP 方法清單。預設為 `['GET']`。你可以使用 `['*']` 來允許所有標準方法。\n* `allow_headers` - 允許跨來源請求所支援的 HTTP 請求標頭清單。預設為 `[]`。你可以使用 `['*']` 來允許所有標頭。對於[簡單 CORS 請求](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests)，`Accept`、`Accept-Language`、`Content-Language` 與 `Content-Type` 標頭一律被允許。\n* `allow_credentials` - 指示是否支援跨來源請求的 Cookie。預設為 `False`。\n\n    當 `allow_credentials` 設為 `True` 時，`allow_origins`、`allow_methods` 與 `allow_headers` 都不能設為 `['*']`。上述各項必須[明確指定](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards)。\n\n* `expose_headers` - 指示哪些回應標頭應該讓瀏覽器可存取。預設為 `[]`。\n* `max_age` - 設定瀏覽器快取 CORS 回應的最長秒數。預設為 `600`。\n\n此中介軟體會回應兩種特定的 HTTP 請求類型...\n\n### CORS 預檢請求 { #cors-preflight-requests }\n\n任何帶有 `Origin` 與 `Access-Control-Request-Method` 標頭的 `OPTIONS` 請求。\n\n在這種情況下，中介軟體會攔截傳入的請求並回應適當的 CORS 標頭，並回傳 `200` 或 `400`（僅供資訊參考）。\n\n### 簡單請求 { #simple-requests }\n\n任何帶有 `Origin` 標頭的請求。在這種情況下，中介軟體會如常將請求往下傳遞，但會在回應上加入適當的 CORS 標頭。\n\n## 更多資訊 { #more-info }\n\n想進一步了解 <abbr title=\"Cross-Origin Resource Sharing - 跨來源資源共用\">CORS</abbr>，請參考 [Mozilla 的 CORS 文件](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)。\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.middleware.cors import CORSMiddleware`。\n\n**FastAPI** 在 `fastapi.middleware` 中提供了幾個中介軟體，做為開發者的便利性。但多數可用的中介軟體其實直接來自 Starlette。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/debugging.md",
    "content": "# 偵錯 { #debugging }\n\n你可以在編輯器中連接偵錯器，例如 Visual Studio Code 或 PyCharm。\n\n## 呼叫 `uvicorn` { #call-uvicorn }\n\n在你的 FastAPI 應用程式中，直接匯入並執行 `uvicorn`：\n\n{* ../../docs_src/debugging/tutorial001_py310.py hl[1,15] *}\n\n### 關於 `__name__ == \"__main__\"` { #about-name-main }\n\n`__name__ == \"__main__\"` 的主要目的是，當你的檔案以以下方式呼叫時，執行某些程式碼：\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\n但當其他檔案匯入它時不會執行，例如：\n\n```Python\nfrom myapp import app\n```\n\n#### 更多細節 { #more-details }\n\n假設你的檔名是 `myapp.py`。\n\n如果你用以下方式執行它：\n\n<div class=\"termy\">\n\n```console\n$ python myapp.py\n```\n\n</div>\n\n那麼在你的檔案中，由 Python 自動建立的內部變數 `__name__`，其值會是字串 `\"__main__\"`。\n\n因此，這段：\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\n會被執行。\n\n---\n\n如果你是匯入該模組（檔案），就不會發生這件事。\n\n所以，如果你有另一個檔案 `importer.py`，內容如下：\n\n```Python\nfrom myapp import app\n\n# 其他程式碼\n```\n\n在那種情況下，`myapp.py` 中自動建立的變數 `__name__` 就不會是 `\"__main__\"`。\n\n因此，這一行：\n\n```Python\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n```\n\n就不會被執行。\n\n/// info | 說明\n\n想了解更多，參考 [Python 官方文件](https://docs.python.org/3/library/__main__.html)。\n\n///\n\n## 用偵錯器執行你的程式碼 { #run-your-code-with-your-debugger }\n\n因為你是直接從程式碼中執行 Uvicorn 伺服器，所以你可以直接從偵錯器呼叫你的 Python 程式（你的 FastAPI 應用程式）。\n\n---\n\n例如，在 Visual Studio Code 中，你可以：\n\n* 前往 \"Debug\" 面板\n* 點選 \"Add configuration...\"\n* 選擇 \"Python\"\n* 使用選項 \"`Python: Current File (Integrated Terminal)`\" 啟動偵錯器\n\n接著它會用你的 **FastAPI** 程式碼啟動伺服器、在你的中斷點停下等。\n\n可能會長這樣：\n\n<img src=\"/img/tutorial/debugging/image01.png\">\n\n---\n\n如果你使用 PyCharm，你可以：\n\n* 開啟 \"Run\" 選單\n* 選擇 \"Debug...\"\n* 會出現一個情境選單\n* 選擇要偵錯的檔案（此例為 `main.py`）\n\n接著它會用你的 **FastAPI** 程式碼啟動伺服器、在你的中斷點停下等。\n\n可能會長這樣：\n\n<img src=\"/img/tutorial/debugging/image02.png\">\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/dependencies/classes-as-dependencies.md",
    "content": "# 以類別作為相依性 { #classes-as-dependencies }\n\n在更深入了解 **相依性注入（Dependency Injection）** 系統之前，我們先把前一個範例升級一下。\n\n## 前一個範例中的 `dict` { #a-dict-from-the-previous-example }\n\n在前一個範例中，我們從相依項（\"dependable\"）回傳了一個 `dict`：\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[9] *}\n\n但接著我們在路徑操作函式（*path operation function*）的參數 `commons` 中取得的是一個 `dict`。\n\n而我們知道，編輯器對 `dict` 無法提供太多輔助（例如自動完成），因為它無法預先知道其中的鍵與值的型別。\n\n我們可以做得更好...\n\n## 什麼算是相依性 { #what-makes-a-dependency }\n\n到目前為止，你看到的相依性都是宣告成函式。\n\n但那不是宣告相依性的唯一方式（雖然那大概是最常見的）。\n\n關鍵在於，相依性應該要是「callable」。\n\n在 Python 中，「**callable**」指的是任何可以像函式一樣被 Python「呼叫」的東西。\n\n因此，如果你有一個物件 `something`（它可能不是函式），而你可以像這樣「呼叫」（執行）它：\n\n```Python\nsomething()\n```\n\n或是\n\n```Python\nsomething(some_argument, some_keyword_argument=\"foo\")\n```\n\n那它就是一個「callable」。\n\n## 以類別作為相依性 { #classes-as-dependencies_1 }\n\n你可能已經注意到，建立一個 Python 類別的實例時，你用的語法也是一樣的。\n\n例如：\n\n```Python\nclass Cat:\n    def __init__(self, name: str):\n        self.name = name\n\n\nfluffy = Cat(name=\"Mr Fluffy\")\n```\n\n在這個例子中，`fluffy` 是 `Cat` 類別的一個實例。\n\n而要建立 `fluffy`，你其實是在「呼叫」`Cat`。\n\n所以，Python 類別本身也是一種 **callable**。\n\n因此，在 **FastAPI** 中，你可以將 Python 類別作為相依性。\n\nFastAPI 其實檢查的是它是否為「callable」（函式、類別或其他），以及它所定義的參數。\n\n如果你在 **FastAPI** 中傳入一個「callable」作為相依性，FastAPI 會分析該「callable」的參數，並以與路徑操作函式參數相同的方式來處理它們，包括子相依性。\n\n這也適用於完全沒有參數的 callable，就和沒有參數的路徑操作函式一樣。\n\n接著，我們可以把上面的相依項（dependable）`common_parameters` 改成類別 `CommonQueryParams`：\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[11:15] *}\n\n注意用來建立該類別實例的 `__init__` 方法：\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[12] *}\n\n...它的參數與我們之前的 `common_parameters` 相同：\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8] *}\n\n**FastAPI** 會用這些參數來「解析」該相依性。\n\n兩種情況下都會有：\n\n- 一個可選的查詢參數 `q`，型別為 `str`。\n- 一個查詢參數 `skip`，型別為 `int`，預設為 `0`。\n- 一個查詢參數 `limit`，型別為 `int`，預設為 `100`。\n\n兩種情況下，資料都會被轉換、驗證，並記錄到 OpenAPI schema 中等。\n\n## 如何使用 { #use-it }\n\n現在你可以用這個類別來宣告你的相依性。\n\n{* ../../docs_src/dependencies/tutorial002_an_py310.py hl[19] *}\n\n**FastAPI** 會呼叫 `CommonQueryParams` 類別。這會建立該類別的一個「實例」，而該實例會以參數 `commons` 的形式傳給你的函式。\n\n## 型別註解與 `Depends` { #type-annotation-vs-depends }\n\n注意上面程式碼裡我們寫了兩次 `CommonQueryParams`：\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 非 Annotated\n\n/// tip\n\n如有可能，優先使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n最後面的 `CommonQueryParams`，在：\n\n```Python\n... Depends(CommonQueryParams)\n```\n\n...才是 **FastAPI** 實際用來知道相依性是什麼的依據。\n\nFastAPI 會從這個物件中提取宣告的參數，並且實際呼叫它。\n\n---\n\n在這個例子中，前面的 `CommonQueryParams`，於：\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, ...\n```\n\n////\n\n//// tab | Python 3.10+ 非 Annotated\n\n/// tip\n\n如有可能，優先使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons: CommonQueryParams ...\n```\n\n////\n\n...對 **FastAPI** 來說沒有任何特殊意義。FastAPI 不會用它來做資料轉換、驗證等（因為這部分由 `Depends(CommonQueryParams)` 處理）。\n\n其實你可以只寫：\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[Any, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 非 Annotated\n\n/// tip\n\n如有可能，優先使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons = Depends(CommonQueryParams)\n```\n\n////\n\n...像是：\n\n{* ../../docs_src/dependencies/tutorial003_an_py310.py hl[19] *}\n\n但仍建議宣告型別，這樣你的編輯器就知道會以何種型別作為參數 `commons` 傳入，進而幫助你做自動完成、型別檢查等：\n\n<img src=\"/img/tutorial/dependencies/image02.png\">\n\n## 捷徑 { #shortcut }\n\n不過你會發現這裡有些重複程式碼，我們寫了兩次 `CommonQueryParams`：\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 非 Annotated\n\n/// tip\n\n如有可能，優先使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n**FastAPI** 為這類情況提供了一個捷徑：當相依性「明確」是一個類別，且 **FastAPI** 會「呼叫」它來建立該類別的實例時。\n\n對這些特定情況，你可以這樣做：\n\n不要寫：\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]\n```\n\n////\n\n//// tab | Python 3.10+ 非 Annotated\n\n/// tip\n\n如有可能，優先使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends(CommonQueryParams)\n```\n\n////\n\n...而是改為：\n\n//// tab | Python 3.10+\n\n```Python\ncommons: Annotated[CommonQueryParams, Depends()]\n```\n\n////\n\n//// tab | Python 3.10+ 非 Annotated\n\n/// tip\n\n如有可能，優先使用 `Annotated` 版本。\n\n///\n\n```Python\ncommons: CommonQueryParams = Depends()\n```\n\n////\n\n你把相依性宣告為參數的型別，並使用不帶任何參數的 `Depends()`，而不用在 `Depends(CommonQueryParams)` 裡「再」寫一次整個類別。\n\n整個範例就會變成：\n\n{* ../../docs_src/dependencies/tutorial004_an_py310.py hl[19] *}\n\n...而 **FastAPI** 會知道該怎麼做。\n\n/// tip\n\n如果你覺得這樣比幫助更令人困惑，那就忽略它吧，你並不「需要」這個技巧。\n\n這只是個捷徑。因為 **FastAPI** 在意幫你減少重複的程式碼。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/dependencies/dependencies-in-path-operation-decorators.md",
    "content": "# 路徑操作裝飾器中的依賴 { #dependencies-in-path-operation-decorators }\n\n有時在你的路徑操作函式中，其實不需要某個依賴的回傳值。\n\n或是該依賴根本沒有回傳值。\n\n但你仍需要它被執行／解析。\n\n這種情況下，你可以不在路徑操作函式的參數上使用 `Depends`，而是在路徑操作裝飾器加入一個 `dependencies` 的 `list`。\n\n## 在路徑操作裝飾器加入 `dependencies` { #add-dependencies-to-the-path-operation-decorator }\n\n路徑操作裝飾器可接受一個可選參數 `dependencies`。\n\n它應該是由 `Depends()` 組成的 `list`：\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[19] *}\n\n這些依賴會以與一般依賴相同的方式被執行／解析。但它們的值（如果有回傳）不會傳遞給你的路徑操作函式。\n\n/// tip\n\n有些編輯器會檢查未使用的函式參數，並將其標示為錯誤。\n\n把這些依賴放在路徑操作裝飾器中，可以確保它們被執行，同時避免編輯器／工具報錯。\n\n這也有助於避免讓新加入的開發者看到未使用的參數時，以為它是不必要的而感到困惑。\n\n///\n\n/// info\n\n在這個範例中我們使用了自訂的（虛構的）標頭 `X-Key` 與 `X-Token`。\n\n但在實際情況下，當你實作安全機制時，使用整合的 [Security utilities（下一章）](../security/index.md) 會獲得更多好處。\n\n///\n\n## 依賴的錯誤與回傳值 { #dependencies-errors-and-return-values }\n\n你可以使用與平常相同的依賴函式。\n\n### 依賴的需求 { #dependency-requirements }\n\n它們可以宣告請求需求（例如標頭（headers））或其他子依賴：\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[8,13] *}\n\n### 拋出例外 { #raise-exceptions }\n\n這些依賴可以 `raise` 例外，與一般依賴相同：\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[10,15] *}\n\n### 回傳值 { #return-values }\n\n它們可以回傳值，也可以不回傳；無論如何，回傳值都不會被使用。\n\n因此，你可以重複使用在其他地方已使用過的一般依賴（會回傳值），即使回傳值不會被使用，該依賴仍會被執行：\n\n{* ../../docs_src/dependencies/tutorial006_an_py310.py hl[11,16] *}\n\n## 一組路徑操作的依賴 { #dependencies-for-a-group-of-path-operations }\n\n之後在閱讀如何組織較大的應用程式（[較大型應用程式——多個檔案](../../tutorial/bigger-applications.md)）時，你會學到如何為一組路徑操作宣告一個共同的 `dependencies` 參數。\n\n## 全域依賴 { #global-dependencies }\n\n接著我們會看看如何把依賴加到整個 `FastAPI` 應用程式，使其套用到每個路徑操作。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/dependencies/dependencies-with-yield.md",
    "content": "# 使用 yield 的相依 { #dependencies-with-yield }\n\nFastAPI 支援在完成後執行一些<dfn title=\"有時也稱為「結束程式碼」、「清理程式碼」、「釋放程式碼」、「關閉程式碼」、「情境管理器結束程式碼」等\">額外步驟</dfn>的相依。\n\n要做到這點，使用 `yield` 取代 `return`，並把額外步驟（程式碼）寫在其後。\n\n/// tip\n\n請確保每個相依內只使用一次 `yield`。\n\n///\n\n/// note | 技術細節\n\n任何可用於下列裝飾器的函式：\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) 或\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\n都可以作為 **FastAPI** 的相依。\n\n事實上，FastAPI 內部就是使用這兩個裝飾器。\n\n///\n\n## 使用 `yield` 的資料庫相依 { #a-database-dependency-with-yield }\n\n例如，你可以用它建立一個資料庫 session，並在完成後關閉。\n\n只有 `yield` 之前（含 `yield` 本身）的程式碼會在產生回應之前執行：\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[2:4] *}\n\n由 `yield` 產生的值會被注入到路徑操作（path operation）與其他相依中：\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[4] *}\n\n位於 `yield` 之後的程式碼會在回應之後執行：\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[5:6] *}\n\n/// tip\n\n你可以使用 `async` 或一般函式。\n\n**FastAPI** 都會正確處理，和一般相依相同。\n\n///\n\n## 同時使用 `yield` 與 `try` 的相依 { #a-dependency-with-yield-and-try }\n\n如果在含 `yield` 的相依中使用 `try` 區塊，你會接收到使用該相依時拋出的任何例外。\n\n例如，如果在中途的某段程式碼、其他相依，或某個路徑操作中，讓資料庫交易「rollback」或產生了任何例外，你都會在你的相依中接收到該例外。\n\n因此，你可以在相依內用 `except SomeException` 來攔截特定例外。\n\n同樣地，你可以使用 `finally` 來確保無論是否有例外都會執行結束步驟。\n\n{* ../../docs_src/dependencies/tutorial007_py310.py hl[3,5] *}\n\n## 含 `yield` 的子相依 { #sub-dependencies-with-yield }\n\n你可以擁有任何大小與形狀的子相依與相依樹，而它們都可以（或不）使用 `yield`。\n\n**FastAPI** 會確保每個使用 `yield` 的相依，其「結束程式碼」會以正確的順序執行。\n\n例如，`dependency_c` 可以相依於 `dependency_b`，而 `dependency_b` 相依於 `dependency_a`：\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[6,14,22] *}\n\n而且它們都可以使用 `yield`。\n\n在這個例子中，`dependency_c` 為了執行它的結束程式碼，需要來自 `dependency_b`（此處命名為 `dep_b`）的值仍然可用。\n\n同理，`dependency_b` 為了執行它的結束程式碼，需要來自 `dependency_a`（此處命名為 `dep_a`）的值可用。\n\n{* ../../docs_src/dependencies/tutorial008_an_py310.py hl[18:19,26:27] *}\n\n同樣地，你可以同時擁有使用 `yield` 的相依與使用 `return` 的相依，並讓其中一些相依彼此相依。\n\n你也可以有一個相依同時需要多個使用 `yield` 的其他相依，等等。\n\n你可以擁有任何你需要的相依組合。\n\n**FastAPI** 會確保一切都以正確的順序執行。\n\n/// note | 技術細節\n\n這能運作，多虧了 Python 的 [Context Managers](https://docs.python.org/3/library/contextlib.html)。\n\n**FastAPI** 在內部使用它們來達成這點。\n\n///\n\n## 含 `yield` 與 `HTTPException` 的相依 { #dependencies-with-yield-and-httpexception }\n\n你已看到可以在含 `yield` 的相依中使用 `try` 區塊，嘗試執行一些程式碼，然後在 `finally` 後執行結束程式碼。\n\n你也可以用 `except` 來攔截被拋出的例外並加以處理。\n\n例如，你可以拋出不同的例外，如 `HTTPException`。\n\n/// tip\n\n這算是進階技巧；多數情況你並不需要，因為你可以在應用程式其他程式碼中（例如在路徑操作函式（path operation function）中）直接拋出例外（包含 `HTTPException`）。\n\n但如果你需要，它就在這裡。🤓\n\n///\n\n{* ../../docs_src/dependencies/tutorial008b_an_py310.py hl[18:22,31] *}\n\n如果你想攔截例外並據此回傳自訂回應，請建立一個[自訂例外處理器](../handling-errors.md#install-custom-exception-handlers)。\n\n## 含 `yield` 與 `except` 的相依 { #dependencies-with-yield-and-except }\n\n如果你在含 `yield` 的相依中用 `except` 攔截了例外，且沒有再次拋出它（或拋出新的例外），FastAPI 將無法察覺有例外發生，就像在一般的 Python 中一樣：\n\n{* ../../docs_src/dependencies/tutorial008c_an_py310.py hl[15:16] *}\n\n在這種情況下，客戶端會如預期地看到一個 *HTTP 500 Internal Server Error* 回應（因為我們沒有拋出 `HTTPException` 或類似的東西），但伺服器將不會有任何日誌或其他錯誤線索。😱\n\n### 在含 `yield` 與 `except` 的相依中務必 `raise` { #always-raise-in-dependencies-with-yield-and-except }\n\n如果你在含 `yield` 的相依中攔截到了例外，除非你要拋出另一個 `HTTPException` 或類似的例外，否則**你應該重新拋出原本的例外**。\n\n你可以使用 `raise` 重新拋出同一個例外：\n\n{* ../../docs_src/dependencies/tutorial008d_an_py310.py hl[17] *}\n\n現在客戶端仍會獲得同樣的 *HTTP 500 Internal Server Error* 回應，但伺服器的日誌中會有我們自訂的 `InternalError`。😎\n\n## 含 `yield` 的相依執行順序 { #execution-of-dependencies-with-yield }\n\n執行順序大致如下圖。時間從上往下流動，每一欄代表一個互動或執行程式碼的部分。\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant handler as Exception handler\nparticipant dep as Dep with yield\nparticipant operation as Path Operation\nparticipant tasks as Background tasks\n\n    Note over client,operation: Can raise exceptions, including HTTPException\n    client ->> dep: Start request\n    Note over dep: Run code up to yield\n    opt raise Exception\n        dep -->> handler: Raise Exception\n        handler -->> client: HTTP error response\n    end\n    dep ->> operation: Run dependency, e.g. DB session\n    opt raise\n        operation -->> dep: Raise Exception (e.g. HTTPException)\n        opt handle\n            dep -->> dep: Can catch exception, raise a new HTTPException, raise other exception\n        end\n        handler -->> client: HTTP error response\n    end\n\n    operation ->> client: Return response to client\n    Note over client,operation: Response is already sent, can't change it anymore\n    opt Tasks\n        operation -->> tasks: Send background tasks\n    end\n    opt Raise other exception\n        tasks -->> tasks: Handle exceptions in the background task code\n    end\n```\n\n/// info\n\n只會向用戶端送出「一個回應」。可能是其中一個錯誤回應，或是來自該路徑操作的回應。\n\n一旦送出了其中一個回應，就不能再送出其他回應。\n\n///\n\n/// tip\n\n如果你在路徑操作函式的程式碼中拋出任何例外，它會被傳遞到使用 `yield` 的相依中（包含 `HTTPException`）。大多數情況你會想在該使用 `yield` 的相依中重新拋出相同的例外或一個新的例外，以確保它被正確處理。\n\n///\n\n## 提早關閉與 `scope` { #early-exit-and-scope }\n\n通常，含 `yield` 的相依之結束程式碼會在回應送出給用戶端之後才執行。\n\n但如果你確定在從路徑操作函式返回後就不會再使用該相依，你可以使用 `Depends(scope=\"function\")`，告訴 FastAPI 應在路徑操作函式返回之後、但在回應送出之前關閉該相依。\n\n{* ../../docs_src/dependencies/tutorial008e_an_py310.py hl[12,16] *}\n\n`Depends()` 接受一個 `scope` 參數，可以是：\n\n* `\"function\"`：在處理請求的路徑操作函式之前啟動相依，在路徑操作函式結束之後結束相依，但在回應送回用戶端之前。所以，相依函式會在路徑操作**函式**的「周圍」執行。\n* `\"request\"`：在處理請求的路徑操作函式之前啟動相依（與使用 `\"function\"` 類似），但在回應送回用戶端之後才結束相依。所以，相依函式會在整個**請求**與回應循環的「周圍」執行。\n\n如果未指定且相依使用了 `yield`，則預設 `scope` 為 `\"request\"`。\n\n### 子相依的 `scope` { #scope-for-sub-dependencies }\n\n當你宣告一個 `scope=\"request\"`（預設值）的相依時，任何子相依也需要有 `\"request\"` 的 `scope`。\n\n但一個 `scope` 為 `\"function\"` 的相依，可以擁有 `scope` 為 `\"function\"` 或 `\"request\"` 的子相依。\n\n這是因為任何相依都需要能在子相依之前執行其結束程式碼，因為它可能在結束程式碼中仍需要使用那些子相依。\n\n```mermaid\nsequenceDiagram\n\nparticipant client as Client\nparticipant dep_req as Dep scope=\"request\"\nparticipant dep_func as Dep scope=\"function\"\nparticipant operation as Path Operation\n\n    client ->> dep_req: Start request\n    Note over dep_req: Run code up to yield\n    dep_req ->> dep_func: Pass dependency\n    Note over dep_func: Run code up to yield\n    dep_func ->> operation: Run path operation with dependency\n    operation ->> dep_func: Return from path operation\n    Note over dep_func: Run code after yield\n    Note over dep_func: ✅ Dependency closed\n    dep_func ->> client: Send response to client\n    Note over client: Response sent\n    Note over dep_req: Run code after yield\n    Note over dep_req: ✅ Dependency closed\n```\n\n## 含 `yield`、`HTTPException`、`except` 與背景任務的相依 { #dependencies-with-yield-httpexception-except-and-background-tasks }\n\n含 `yield` 的相依隨時間演進，以涵蓋不同的使用情境並修正一些問題。\n\n如果你想了解在不同 FastAPI 版本中改了哪些內容，可以在進階指南中閱讀：[進階相依 — 含 `yield`、`HTTPException`、`except` 與背景任務的相依](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks)。\n## 情境管理器 { #context-managers }\n\n### 什麼是「情境管理器」 { #what-are-context-managers }\n\n「情境管理器」是那些你可以在 `with` 陳述式中使用的 Python 物件。\n\n例如，[你可以用 `with` 來讀取檔案](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files)：\n\n```Python\nwith open(\"./somefile.txt\") as f:\n    contents = f.read()\n    print(contents)\n```\n\n在底層，`open(\"./somefile.txt\")` 會建立一個稱為「情境管理器」的物件。\n\n當 `with` 區塊結束時，它會確保關閉檔案，即使發生了例外也一樣。\n\n當你建立一個含 `yield` 的相依時，**FastAPI** 會在內部為它建立一個情境管理器，並與其他相關工具結合。\n\n### 在含 `yield` 的相依中使用情境管理器 { #using-context-managers-in-dependencies-with-yield }\n\n/// warning\n\n這大致算是一個「進階」概念。\n\n如果你剛開始學習 **FastAPI**，此處可以先跳過。\n\n///\n\n在 Python 中，你可以透過[建立一個擁有 `__enter__()` 與 `__exit__()` 兩個方法的類別](https://docs.python.org/3/reference/datamodel.html#context-managers)來建立情境管理器。\n\n你也可以在 **FastAPI** 的含 `yield` 相依中，於相依函式內使用 `with` 或 `async with` 陳述式來使用它們：\n\n{* ../../docs_src/dependencies/tutorial010_py310.py hl[1:9,13] *}\n\n/// tip\n\n建立情境管理器的另一種方式是：\n\n* [`@contextlib.contextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager) 或\n* [`@contextlib.asynccontextmanager`](https://docs.python.org/3/library/contextlib.html#contextlib.asynccontextmanager)\n\n用它們裝飾一個只包含單一 `yield` 的函式。\n\n這正是 **FastAPI** 在內部為含 `yield` 的相依所使用的方法。\n\n但你不需要（而且也不該）在 FastAPI 的相依上使用這些裝飾器。\n\nFastAPI 會在內部替你處理好。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/dependencies/global-dependencies.md",
    "content": "# 全域依賴 { #global-dependencies }\n\n在某些類型的應用程式中，你可能想為整個應用程式新增依賴。\n\n類似於你可以在[路徑操作（path operation）的裝飾器中新增 `dependencies`](dependencies-in-path-operation-decorators.md) 的方式，你也可以把它們加到 `FastAPI` 應用程式上。\n\n在這種情況下，它們會套用到應用程式中的所有路徑操作：\n\n{* ../../docs_src/dependencies/tutorial012_an_py310.py hl[17] *}\n\n而且，在[將 `dependencies` 新增到路徑操作裝飾器](dependencies-in-path-operation-decorators.md) 那一節中的所有概念依然適用，只是這裡是套用到整個應用中的所有路徑操作。\n\n## 路徑操作群組的依賴 { #dependencies-for-groups-of-path-operations }\n\n之後，在閱讀如何組織更大的應用程式（[更大的應用程式 - 多個檔案](../../tutorial/bigger-applications.md)）時，可能會有多個檔案，你將會學到如何為一組路徑操作宣告單一的 `dependencies` 參數。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/dependencies/index.md",
    "content": "# 依賴 { #dependencies }\n\n**FastAPI** 內建一套強大且直覺的 **<dfn title=\"也稱為：元件、資源、提供者、服務、可注入項\">依賴注入</dfn>** 系統。\n\n它被設計為易於使用，使任何開發者都能輕鬆將其他元件與 **FastAPI** 整合。\n\n## 什麼是「依賴注入」 { #what-is-dependency-injection }\n\n在程式設計中，「依賴注入」的意思是：你的程式碼（此處指你的「路徑操作函式 (path operation functions)」）可以宣告它為了正常運作所需要的各種東西：也就是「依賴」。\n\n接著，這個系統（此處是 **FastAPI**）會負責做任何必要的事，將這些所需的依賴提供給你的程式碼（「注入」依賴）。\n\n當你需要以下情境時，這特別有用：\n\n* 共享邏輯（相同的邏輯一次又一次地使用）。\n* 共用資料庫連線。\n* 強制套用安全性、驗證、角色要求等。\n* 以及許多其他事情...\n\n同時把重複的程式碼降到最低。\n\n## 入門 { #first-steps }\n\n先看一個非常簡單的範例。它現在還不太實用，但夠簡單，讓我們能專注在 **依賴注入** 的運作方式。\n\n### 建立一個依賴，或稱「dependable」 { #create-a-dependency-or-dependable }\n\n先專注在依賴本身。\n\n它就是一個函式，可以接受與「路徑操作函式」相同的各種參數：\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[8:9] *}\n\n就這樣。\n\n僅僅兩行。\n\n而且它的外觀與結構和你的所有「路徑操作函式」一樣。\n\n你可以把它想成一個沒有「裝飾器」（沒有 `@app.get(\"/some-path\")`）的「路徑操作函式」。\n\n它可以回傳你想要的任何東西。\n\n在這個例子中，這個依賴會期望：\n\n* 一個選用的查詢參數 `q`，型別為 `str`。\n* 一個選用的查詢參數 `skip`，型別為 `int`，預設為 `0`。\n* 一個選用的查詢參數 `limit`，型別為 `int`，預設為 `100`。\n\n然後它只會回傳一個包含這些值的 `dict`。\n\n/// info | 說明\n\nFastAPI 在 0.95.0 版新增了對 `Annotated` 的支援（並開始建議使用）。\n\n如果你使用較舊的版本，嘗試使用 `Annotated` 時會出現錯誤。\n\n在使用 `Annotated` 之前，請先[升級 FastAPI 版本](../../deployment/versions.md#upgrading-the-fastapi-versions)到至少 0.95.1。\n\n///\n\n### 匯入 `Depends` { #import-depends }\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[3] *}\n\n### 在「被依賴者」（dependant）中宣告依賴 { #declare-the-dependency-in-the-dependant }\n\n和你在「路徑操作函式」參數上使用 `Body`、`Query` 等方式一樣，針對新參數使用 `Depends`：\n\n{* ../../docs_src/dependencies/tutorial001_an_py310.py hl[13,18] *}\n\n雖然你在函式參數上使用 `Depends` 的方式和 `Body`、`Query` 等相同，但 `Depends` 的運作方式有點不同。\n\n你只需要傳給 `Depends` 一個參數。\n\n這個參數必須是類似函式的東西。\n\n你不需要直接呼叫它（不要在後面加上括號），只要把它作為參數傳給 `Depends()` 即可。\n\n而該函式的參數宣告方式與「路徑操作函式」相同。\n\n/// tip | 提示\n\n除了函式之外，還有其他「東西」也能當作依賴，會在下一章介紹。\n\n///\n\n當有新的請求到達時，**FastAPI** 會負責：\n\n* 以正確的參數呼叫你的依賴（dependable）函式。\n* 取得該函式的回傳結果。\n* 將結果指定給你的「路徑操作函式」中的對應參數。\n\n```mermaid\ngraph TB\n\ncommon_parameters([\"common_parameters\"])\nread_items[\"/items/\"]\nread_users[\"/users/\"]\n\ncommon_parameters --> read_items\ncommon_parameters --> read_users\n```\n\n如此一來，你只需撰寫一次共用程式碼，**FastAPI** 會替你的各個「路徑操作」呼叫它。\n\n/// check | 檢查\n\n注意，你不必建立特殊的類別並把它傳到 **FastAPI** 去「註冊」或做類似的事。\n\n只要把它傳給 `Depends`，**FastAPI** 就知道該怎麼處理其餘的部分。\n\n///\n\n## 共用 `Annotated` 依賴 { #share-annotated-dependencies }\n\n在上面的範例中，可以看到有一點點的「重複程式碼」。\n\n當你要使用 `common_parameters()` 這個依賴時，你得寫出完整的型別註解搭配 `Depends()`：\n\n```Python\ncommons: Annotated[dict, Depends(common_parameters)]\n```\n\n但因為我們在使用 `Annotated`，我們可以把這個 `Annotated` 的值存到一個變數中，並在多個地方重複使用：\n\n{* ../../docs_src/dependencies/tutorial001_02_an_py310.py hl[12,16,21] *}\n\n/// tip | 提示\n\n這只是標準的 Python，用的是所謂的「型別別名 (type alias)」，其實和 **FastAPI** 本身無關。\n\n但因為 **FastAPI** 是建立在 Python 標準之上（包含 `Annotated`），你就可以在程式碼中使用這個技巧。😎\n\n///\n\n這些依賴依然會如預期運作，而最棒的是「型別資訊會被保留」，代表你的編輯器仍能提供「自動完成」、「即時錯誤」等功能，像 `mypy` 等其他工具也一樣受益。\n\n當你在「大型程式碼庫」中，於許多「路徑操作」反覆使用「相同的依賴」時，這會特別有用。\n\n## 要不要使用 `async` { #to-async-or-not-to-async }\n\n因為依賴也會由 **FastAPI** 呼叫（就像你的「路徑操作函式」），所以在定義函式時套用相同的規則。\n\n你可以使用 `async def` 或一般的 `def`。\n\n而且你可以在一般 `def` 的「路徑操作函式」中宣告 `async def` 的依賴，或在 `async def` 的「路徑操作函式」中宣告 `def` 的依賴，等等。\n\n都沒關係。**FastAPI** 會知道該怎麼做。\n\n/// note | 注意\n\n如果你不熟悉，請參考文件中的 [Async: \"In a hurry?\"](../../async.md#in-a-hurry) 一節，瞭解 `async` 與 `await`。\n\n///\n\n## 與 OpenAPI 整合 { #integrated-with-openapi }\n\n你的依賴（以及其子依賴）所宣告的所有請求參數、驗證與需求，都會整合進同一份 OpenAPI 結構中。\n\n因此，互動式文件也會包含來自這些依賴的所有資訊：\n\n<img src=\"/img/tutorial/dependencies/image01.png\">\n\n## 簡單用法 { #simple-usage }\n\n想一想，「路徑操作函式」是宣告好讓框架在「路徑」與「操作」符合時使用的，然後 **FastAPI** 會負責帶入正確的參數、從請求中擷取資料，並呼叫該函式。\n\n其實，所有（或大多數）Web 框架都是這樣運作。\n\n你從不會直接呼叫這些函式。它們是由框架（此處是 **FastAPI**）呼叫的。\n\n透過依賴注入系統，你也可以告訴 **FastAPI**：你的「路徑操作函式」還「依賴」其他東西，應在你的「路徑操作函式」之前執行，**FastAPI** 會負責執行它並「注入」其結果。\n\n這個「依賴注入」概念的其他常見稱呼包括：\n\n* 資源\n* 提供者\n* 服務\n* 可注入項\n* 元件\n\n## **FastAPI** 外掛 { #fastapi-plug-ins }\n\n各種整合與「外掛」都能以 **依賴注入** 系統來構建。但事實上，並不需要真的去打造「外掛」，因為透過依賴，你可以宣告無數的整合與互動，並讓它們供你的「路徑操作函式」使用。\n\n而且依賴可以用非常簡單直覺的方式建立，你只需要匯入所需的 Python 套件，然後用幾行程式碼就能把它們與你的 API 函式整合，真的是「只要幾行」。\n\n在接下來的章節中你會看到這方面的例子，例如關聯式與 NoSQL 資料庫、安全性等。\n\n## **FastAPI** 相容性 { #fastapi-compatibility }\n\n依賴注入系統的簡潔，使 **FastAPI** 能與以下事物相容：\n\n* 所有關聯式資料庫\n* NoSQL 資料庫\n* 外部套件\n* 外部 API\n* 驗證與授權系統\n* API 使用監控系統\n* 回應資料注入系統\n* 等等\n\n## 簡單而強大 { #simple-and-powerful }\n\n雖然階層式的依賴注入系統相當容易定義與使用，但它依然非常強大。\n\n你可以定義會進一步依賴其他依賴的依賴。\n\n最終會形成一棵階層式的依賴樹，而 **依賴注入** 系統會負責為你解決所有這些依賴（以及它們的子依賴），並在每一步提供（注入）對應的結果。\n\n例如，假設你有 4 個 API 端點（「路徑操作」）：\n\n* `/items/public/`\n* `/items/private/`\n* `/users/{user_id}/activate`\n* `/items/pro/`\n\n那麼你就能只透過依賴與子依賴，為每個端點加入不同的權限需求：\n\n```mermaid\ngraph TB\n\ncurrent_user([\"current_user\"])\nactive_user([\"active_user\"])\nadmin_user([\"admin_user\"])\npaying_user([\"paying_user\"])\n\npublic[\"/items/public/\"]\nprivate[\"/items/private/\"]\nactivate_user[\"/users/{user_id}/activate\"]\npro_items[\"/items/pro/\"]\n\ncurrent_user --> active_user\nactive_user --> admin_user\nactive_user --> paying_user\n\ncurrent_user --> public\nactive_user --> private\nadmin_user --> activate_user\npaying_user --> pro_items\n```\n\n## 與 **OpenAPI** 整合 { #integrated-with-openapi_1 }\n\n所有這些依賴在宣告其需求的同時，也會為你的「路徑操作」新增參數、驗證等。\n\n**FastAPI** 會負責把這一切加入 OpenAPI 結構中，讓它們顯示在互動式文件系統裡。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/dependencies/sub-dependencies.md",
    "content": "# 子相依 { #sub-dependencies }\n\n你可以建立具有「子相依」的相依項。\n\n它們可以按你的需要，層級任意加深。\n\n**FastAPI** 會負責解析它們。\n\n## 第一個相依項 \"dependable\" { #first-dependency-dependable }\n\n你可以建立第一個相依項（\"dependable\"）如下：\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[8:9] *}\n\n它宣告了一個可選的查詢參數 `q`（型別為 `str`），然後直接回傳它。\n\n這很簡單（不太實用），但有助於我們專注於子相依如何運作。\n\n## 第二個相依，同時是 \"dependable\" 也是 \"dependant\" { #second-dependency-dependable-and-dependant }\n\n接著你可以建立另一個相依函式（\"dependable\"），同時它也宣告了自己的相依（因此它同時也是 \"dependant\"）：\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[13] *}\n\n來看它所宣告的參數：\n\n- 即使這個函式本身是個相依項（\"dependable\"），它也宣告了另一個相依（它「相依於」其他東西）。\n    - 它相依 `query_extractor`，並把其回傳值指定給參數 `q`。\n- 它還宣告了一個可選的 `last_query` cookie，型別為 `str`。\n    - 如果使用者沒有提供查詢 `q`，我們就使用先前儲存在 cookie 中的最後一次查詢值。\n\n## 使用相依項 { #use-the-dependency }\n\n然後我們可以這樣使用這個相依項：\n\n{* ../../docs_src/dependencies/tutorial005_an_py310.py hl[23] *}\n\n/// info\n\n注意，在路徑操作函式中我們只宣告了一個相依項 `query_or_cookie_extractor`。\n\n但 **FastAPI** 會知道它必須先解析 `query_extractor`，在呼叫 `query_or_cookie_extractor` 時把其結果傳入。\n\n///\n\n```mermaid\ngraph TB\n\nquery_extractor([\"query_extractor\"])\nquery_or_cookie_extractor([\"query_or_cookie_extractor\"])\n\nread_query[\"/items/\"]\n\nquery_extractor --> query_or_cookie_extractor --> read_query\n```\n\n## 多次使用同一個相依項 { #using-the-same-dependency-multiple-times }\n\n如果你的某個相依項在同一個路徑操作中被宣告了多次，例如多個相依共用同一個子相依，**FastAPI** 會知道只需在每次請求中呼叫該子相依一次。\n\n它會把回傳值儲存在一個 <dfn title=\"用來儲存已計算/產生之值的工具／系統，以便重複使用而不必再次計算。\">「快取」</dfn> 中，並在該次請求中傳遞給所有需要它的「相依者」，而不是為同一個請求多次呼叫相同的相依項。\n\n在進階情境下，如果你確定需要在同一次請求的每個步驟都呼叫該相依（可能呼叫多次），而不是使用「快取」的值，你可以在使用 `Depends` 時設定參數 `use_cache=False`：\n\n//// tab | Python 3.10+\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n//// tab | Python 3.10+ 未使用 Annotated\n\n/// tip\n\n若可行，建議使用 `Annotated` 的版本。\n\n///\n\n```Python hl_lines=\"1\"\nasync def needy_dependency(fresh_value: str = Depends(get_value, use_cache=False)):\n    return {\"fresh_value\": fresh_value}\n```\n\n////\n\n## 回顧 { #recap }\n\n撇開這裡用到的術語不談，**相依性注入（Dependency Injection）** 系統其實很簡單。\n\n它只是一些與路徑操作函式外觀相同的函式。\n\n但它非常強大，允許你宣告任意深度巢狀的相依「圖」（樹）。\n\n/// tip\n\n用這些簡單的例子看起來可能不那麼有用。\n\n但在關於安全性的章節中，你會看到它有多實用。\n\n你也會看到它能為你省下多少程式碼。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/encoder.md",
    "content": "# JSON 相容編碼器 { #json-compatible-encoder }\n\n在某些情況下，你可能需要將某種資料型別（例如 Pydantic 模型）轉換為與 JSON 相容的類型（例如 `dict`、`list` 等）。\n\n例如，當你需要把它儲存在資料庫中。\n\n為此，**FastAPI** 提供了 `jsonable_encoder()` 函式。\n\n## 使用 `jsonable_encoder` { #using-the-jsonable-encoder }\n\n想像你有一個只接受與 JSON 相容資料的資料庫 `fake_db`。\n\n例如，它不接受 `datetime` 物件，因為那與 JSON 不相容。\n\n因此，必須將 `datetime` 物件轉為一個以 [ISO 格式](https://en.wikipedia.org/wiki/ISO_8601) 表示資料的 `str`。\n\n同樣地，這個資料庫不會接受 Pydantic 模型（帶有屬性的物件），只接受 `dict`。\n\n你可以使用 `jsonable_encoder` 來處理。\n\n它接收一個物件（例如 Pydantic 模型），並回傳一個與 JSON 相容的版本：\n\n{* ../../docs_src/encoder/tutorial001_py310.py hl[4,21] *}\n\n在此範例中，它會把 Pydantic 模型轉成 `dict`，並將 `datetime` 轉成 `str`。\n\n呼叫後的結果可以用 Python 標準的 [`json.dumps()`](https://docs.python.org/3/library/json.html#json.dumps) 進行編碼。\n\n它不會回傳一個包含 JSON 內容的大型 `str`（字串）。它會回傳 Python 標準的資料結構（例如 `dict`），其中的值與子值都與 JSON 相容。\n\n/// note\n\n事實上，`jsonable_encoder` 在 **FastAPI** 內部也被用來轉換資料。不過在許多其他情境中它同樣實用。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/extra-data-types.md",
    "content": "# 額外的資料型別 { #extra-data-types }\n\n到目前為止，你一直在使用常見的資料型別，例如：\n\n* `int`\n* `float`\n* `str`\n* `bool`\n\n但你也可以使用更複雜的資料型別。\n\n而且你仍然會擁有目前為止所見的同樣功能：\n\n* 極佳的編輯器支援。\n* 將傳入請求的資料轉換。\n* 回應資料的轉換。\n* 資料驗證。\n* 自動產生註解與文件。\n\n## 其他資料型別 { #other-data-types }\n\n以下是你可以使用的一些其他資料型別：\n\n* `UUID`：\n    * 一種標準的「通用唯一識別碼 (Universally Unique Identifier)」，常見於許多資料庫與系統的 ID。\n    * 在請求與回應中會以 `str` 表示。\n* `datetime.datetime`：\n    * Python 的 `datetime.datetime`。\n    * 在請求與回應中會以 ISO 8601 格式的 `str` 表示，例如：`2008-09-15T15:53:00+05:00`。\n* `datetime.date`：\n    * Python 的 `datetime.date`。\n    * 在請求與回應中會以 ISO 8601 格式的 `str` 表示，例如：`2008-09-15`。\n* `datetime.time`：\n    * Python 的 `datetime.time`。\n    * 在請求與回應中會以 ISO 8601 格式的 `str` 表示，例如：`14:23:55.003`。\n* `datetime.timedelta`：\n    * Python 的 `datetime.timedelta`。\n    * 在請求與回應中會以總秒數的 `float` 表示。\n    * Pydantic 也允許用「ISO 8601 time diff encoding」來表示，[詳情見文件](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers)。\n* `frozenset`：\n    * 在請求與回應中與 `set` 相同處理：\n        * 在請求中，會讀取一個 list，去除重複並轉為 `set`。\n        * 在回應中，`set` 會被轉為 `list`。\n        * 生成的 schema 會指定 `set` 的值為唯一（使用 JSON Schema 的 `uniqueItems`）。\n* `bytes`：\n    * 標準的 Python `bytes`。\n    * 在請求與回應中會被當作 `str` 處理。\n    * 生成的 schema 會指定其為 `str`，且 \"format\" 為 `binary`。\n* `Decimal`：\n    * 標準的 Python `Decimal`。\n    * 在請求與回應中，與 `float` 的處理方式相同。\n* 你可以在此查閱所有可用的 Pydantic 資料型別：[Pydantic 資料型別](https://docs.pydantic.dev/latest/usage/types/types/)。\n\n## 範例 { #example }\n\n以下是一個帶有參數、使用上述部分型別的 *路徑操作 (path operation)* 範例。\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[1,3,12:16] *}\n\n請注意，函式內的參數會是它們的自然資料型別，因此你可以進行一般的日期運算，例如：\n\n{* ../../docs_src/extra_data_types/tutorial001_an_py310.py hl[18:19] *}\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/extra-models.md",
    "content": "# 額外的模型 { #extra-models }\n\n延續前一個範例，通常會有不只一個彼此相關的模型。\n\n對使用者模型尤其如此，因為：\n\n* 「輸入模型」需要能包含密碼。\n* 「輸出模型」不應包含密碼。\n* 「資料庫模型」通常需要儲存雜湊後的密碼。\n\n/// danger\n\n切勿儲存使用者的明文密碼。務必只儲存可供驗證的「安全雜湊」。\n\n若你還不清楚，稍後會在[安全性章節](security/simple-oauth2.md#password-hashing)學到什麼是「密碼雜湊」。\n\n///\n\n## 多個模型 { #multiple-models }\n\n以下是模型大致長相、與其密碼欄位以及它們被使用的位置：\n\n{* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *}\n\n### 關於 `**user_in.model_dump()` { #about-user-in-model-dump }\n\n#### Pydantic 的 `.model_dump()` { #pydantics-model-dump }\n\n`user_in` 是一個 `UserIn` 類別的 Pydantic 模型。\n\nPydantic 模型有 `.model_dump()` 方法，會回傳包含該模型資料的 `dict`。\n\n因此，若我們建立一個 Pydantic 物件 `user_in` 如：\n\n```Python\nuser_in = UserIn(username=\"john\", password=\"secret\", email=\"john.doe@example.com\")\n```\n\n接著呼叫：\n\n```Python\nuser_dict = user_in.model_dump()\n```\n\n此時變數 `user_dict` 會是一個承載資料的 `dict`（也就是 `dict`，而非 Pydantic 模型物件）。\n\n若再呼叫：\n\n```Python\nprint(user_dict)\n```\n\n我們會得到一個 Python `dict`：\n\n```Python\n{\n    'username': 'john',\n    'password': 'secret',\n    'email': 'john.doe@example.com',\n    'full_name': None,\n}\n```\n\n#### 解包 `dict` { #unpacking-a-dict }\n\n若將像 `user_dict` 這樣的 `dict` 以 `**user_dict` 傳給函式（或類別），Python 會將其「解包」，把 `user_dict` 的鍵和值直接當作具名引數傳入。\n\n因此，延續上面的 `user_dict`，寫成：\n\n```Python\nUserInDB(**user_dict)\n```\n\n效果等同於：\n\n```Python\nUserInDB(\n    username=\"john\",\n    password=\"secret\",\n    email=\"john.doe@example.com\",\n    full_name=None,\n)\n```\n\n更精確地說，直接使用 `user_dict`（未來內容可能有所不同）則等同於：\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n)\n```\n\n#### 由另一個模型內容建立 Pydantic 模型 { #a-pydantic-model-from-the-contents-of-another }\n\n如上例我們從 `user_in.model_dump()` 得到 `user_dict`，以下程式碼：\n\n```Python\nuser_dict = user_in.model_dump()\nUserInDB(**user_dict)\n```\n\n等同於：\n\n```Python\nUserInDB(**user_in.model_dump())\n```\n\n...因為 `user_in.model_dump()` 回傳的是 `dict`，接著在傳給 `UserInDB` 時以 `**` 前綴讓 Python 進行解包。\n\n因此，我們可以用一個 Pydantic 模型的資料建立另一個 Pydantic 模型。\n\n#### 解包 `dict` 並加入額外參數 { #unpacking-a-dict-and-extra-keywords }\n\n接著加入額外的具名引數 `hashed_password=hashed_password`，如下：\n\n```Python\nUserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n```\n\n...結果等同於：\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    password = user_dict[\"password\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    hashed_password = hashed_password,\n)\n```\n\n/// warning\n\n輔助函式 `fake_password_hasher` 與 `fake_save_user` 只是用來示範資料流程，並不提供任何實際的安全性。\n\n///\n\n## 減少重複 { #reduce-duplication }\n\n減少程式碼重複是 FastAPI 的核心理念之一。\n\n因為重複的程式碼會提高發生錯誤、安全性問題、程式不同步（某處更新但其他處未更新）等風險。\n\n而這些模型共享大量資料，重複了屬性名稱與型別。\n\n我們可以做得更好。\n\n我們可以宣告一個作為基底的 `UserBase` 模型，其他模型繼承它成為子類別，沿用其屬性（型別宣告、驗證等）。\n\n所有資料轉換、驗證、文件產生等仍可正常運作。\n\n如此一來，我們只需要宣告模型之間的差異（含明文 `password`、含 `hashed_password`、或不含密碼）：\n\n{* ../../docs_src/extra_models/tutorial002_py310.py hl[7,13:14,17:18,21:22] *}\n\n## `Union` 或 `anyOf` { #union-or-anyof }\n\n你可以將回應宣告為多個型別的 `Union`，表示回應可能是其中任一型別。\n\n在 OpenAPI 中會以 `anyOf` 定義。\n\n要達成這點，使用標準的 Python 型別提示 [`typing.Union`](https://docs.python.org/3/library/typing.html#typing.Union)：\n\n/// note\n\n在定義 [`Union`](https://docs.pydantic.dev/latest/concepts/types/#unions) 時，請先放置「更具體」的型別，再放「較不具體」的型別。以下範例中，較具體的 `PlaneItem` 置於 `CarItem` 之前：`Union[PlaneItem, CarItem]`。\n\n///\n\n{* ../../docs_src/extra_models/tutorial003_py310.py hl[1,14:15,18:20,33] *}\n\n### Python 3.10 中的 `Union` { #union-in-python-3-10 }\n\n此範例中，我們將 `Union[PlaneItem, CarItem]` 作為引數 `response_model` 的值。\n\n由於這裡是把它當作引數的「值」傳入，而非用於型別註記，因此即使在 Python 3.10 也必須使用 `Union`。\n\n若用於型別註記，則可以使用直線（|），如下：\n\n```Python\nsome_variable: PlaneItem | CarItem\n```\n\n但若寫成指定值 `response_model=PlaneItem | CarItem` 會發生錯誤，因為 Python 會嘗試在 `PlaneItem` 與 `CarItem` 之間執行「無效運算」，而非將其視為型別註記。\n\n## 模型的清單 { #list-of-models }\n\n同樣地，你可以將回應宣告為物件的 `list`。\n\n為此，使用標準的 Python `list`：\n\n{* ../../docs_src/extra_models/tutorial004_py310.py hl[18] *}\n\n## 以任意 `dict` 作為回應 { #response-with-arbitrary-dict }\n\n你也可以用一般的任意 `dict` 宣告回應，只需指定鍵和值的型別，而不必使用 Pydantic 模型。\n\n當你事先不知道可用的欄位／屬性名稱（定義 Pydantic 模型所需）時，這很實用。\n\n此時可使用 `dict`：\n\n{* ../../docs_src/extra_models/tutorial005_py310.py hl[6] *}\n\n## 重點回顧 { #recap }\n\n依情境使用多個 Pydantic 模型並靈活繼承。\n\n當一個實體需要呈現不同「狀態」時，不必侷限於一個資料模型。例如使用者這個實體，可能有包含 `password`、包含 `password_hash`，或不含密碼等不同狀態。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/first-steps.md",
    "content": "# 第一步 { #first-steps }\n\n最簡單的 FastAPI 檔案可能看起來像這樣：\n\n{* ../../docs_src/first_steps/tutorial001_py310.py *}\n\n將其複製到一個名為 `main.py` 的文件中。\n\n執行即時重新載入伺服器（live server）：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n在輸出中，有一列類似於：\n\n```hl_lines=\"4\"\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n那列顯示了你的應用程式正在本地端機器上運行的 URL。\n\n### 查看它 { #check-it }\n\n在瀏覽器中打開 [http://127.0.0.1:8000](http://127.0.0.1:8000)。\n\n你將看到如下的 JSON 回應：\n\n```JSON\n{\"message\": \"Hello World\"}\n```\n\n### 互動式 API 文件 { #interactive-api-docs }\n\n現在，前往 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n你將看到自動的互動式 API 文件（由 [Swagger UI](https://github.com/swagger-api/swagger-ui) 提供）：\n\n![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)\n\n### 替代 API 文件 { #alternative-api-docs }\n\n現在，前往 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc)。\n\n你將看到另一種自動文件（由 [ReDoc](https://github.com/Rebilly/ReDoc) 提供）：\n\n![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)\n\n### OpenAPI { #openapi }\n\n**FastAPI** 使用定義 API 的 **OpenAPI** 標準來生成一個「schema」，涵蓋你的全部 API。\n\n#### 「Schema」 { #schema }\n\n「schema」是對某個事物的定義或描述。它並不是實作它的程式碼，而僅僅是一個抽象的描述。\n\n#### API 「schema」 { #api-schema }\n\n在這種情況下，[OpenAPI](https://github.com/OAI/OpenAPI-Specification) 是一個規範，它規定了如何定義 API 的 schema。\n\n這個 schema 定義包含了你的 API 路徑、可能接收的參數等內容。\n\n#### 資料「schema」 { #data-schema }\n\n「schema」這個術語也可能指某些資料的結構，比如 JSON 內容的結構。\n\n在這種情況下，它指的是 JSON 的屬性、資料型別等。\n\n#### OpenAPI 和 JSON Schema { #openapi-and-json-schema }\n\nOpenAPI 為你的 API 定義了 API 的 schema。而該 schema 會包含你的 API 所傳送與接收資料的定義（或稱「schemas」），使用 **JSON Schema**，這是 JSON 資料 schema 的標準。\n\n#### 檢查 `openapi.json` { #check-the-openapi-json }\n\n如果你好奇原始的 OpenAPI schema 長什麼樣子，FastAPI 會自動生成一個包含所有 API 描述的 JSON（schema）。\n\n你可以直接在 [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json) 查看它。\n\n它會顯示一個 JSON，類似於：\n\n```JSON\n{\n    \"openapi\": \"3.1.0\",\n    \"info\": {\n        \"title\": \"FastAPI\",\n        \"version\": \"0.1.0\"\n    },\n    \"paths\": {\n        \"/items/\": {\n            \"get\": {\n                \"responses\": {\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\n                            \"application/json\": {\n\n\n\n...\n```\n\n#### OpenAPI 的用途 { #what-is-openapi-for }\n\nOpenAPI schema 驅動了兩個互動式文件系統。\n\n而且有許多替代方案，所有這些都是基於 OpenAPI。你可以輕鬆地將任何這些替代方案添加到使用 **FastAPI** 建置的應用程式中。\n\n你也可以用它自動生成程式碼，讓用戶端與你的 API 通訊。例如前端、手機或物聯網（IoT）應用程式。\n\n### 在 `pyproject.toml` 設定應用的 `entrypoint` { #configure-the-app-entrypoint-in-pyproject-toml }\n\n你可以在 `pyproject.toml` 中設定你的應用位置，例如：\n\n```toml\n[tool.fastapi]\nentrypoint = \"main:app\"\n```\n\n這個 `entrypoint` 會告訴 `fastapi` 指令應該用下面的方式匯入 app：\n\n```python\nfrom main import app\n```\n\n如果你的程式碼結構像是：\n\n```\n.\n├── backend\n│   ├── main.py\n│   ├── __init__.py\n```\n\n那你應該把 `entrypoint` 設為：\n\n```toml\n[tool.fastapi]\nentrypoint = \"backend.main:app\"\n```\n\n這等同於：\n\n```python\nfrom backend.main import app\n```\n\n### 搭配路徑使用 `fastapi dev` { #fastapi-dev-with-path }\n\n你也可以把檔案路徑傳給 `fastapi dev` 指令，它會自動猜測要使用的 FastAPI app 物件：\n\n```console\n$ fastapi dev main.py\n```\n\n但這樣每次執行 `fastapi` 指令時都要記得傳入正確路徑。\n\n此外，其他工具可能找不到它，例如 [VS Code 擴充套件](../editor-support.md) 或 [FastAPI Cloud](https://fastapicloud.com)，因此建議在 `pyproject.toml` 中使用 `entrypoint`。\n\n### 部署你的應用程式（可選） { #deploy-your-app-optional }\n\n你可以選擇將你的 FastAPI 應用程式部署到 [FastAPI Cloud](https://fastapicloud.com)，如果還沒有，去加入候補名單吧。🚀\n\n如果你已經有 **FastAPI Cloud** 帳號（我們已從候補名單邀請你 😉），你可以用一個指令部署你的應用程式。\n\n部署之前，先確保你已登入：\n\n<div class=\"termy\">\n\n```console\n$ fastapi login\n\nYou are logged in to FastAPI Cloud 🚀\n```\n\n</div>\n\n接著部署你的應用程式：\n\n<div class=\"termy\">\n\n```console\n$ fastapi deploy\n\nDeploying to FastAPI Cloud...\n\n✅ Deployment successful!\n\n🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev\n```\n\n</div>\n\n就這樣！現在你可以透過該 URL 存取你的應用程式了。✨\n\n## 逐步回顧 { #recap-step-by-step }\n\n### 第一步：引入 `FastAPI` { #step-1-import-fastapi }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[1] *}\n\n`FastAPI` 是一個 Python 類別，提供所有 API 的全部功能。\n\n/// note | 技術細節\n\n`FastAPI` 是一個直接繼承自 `Starlette` 的類別。\n\n你同樣可以透過 `FastAPI` 來使用 [Starlette](https://www.starlette.dev/) 所有的功能。\n\n///\n\n### 第二步：建立一個 `FastAPI`「實例」 { #step-2-create-a-fastapi-instance }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[3] *}\n\n這裡的 `app` 變數將會是 `FastAPI` 類別的「實例」。\n\n這將是你建立所有 API 的主要互動點。\n\n### 第三步：建立一個「路徑操作」 { #step-3-create-a-path-operation }\n\n#### 路徑 { #path }\n\n這裡的「路徑」指的是 URL 中自第一個 `/` 以後的部分。\n\n例如，在 URL 中：\n\n```\nhttps://example.com/items/foo\n```\n\n……的路徑將會是：\n\n```\n/items/foo\n```\n\n/// info\n\n「路徑」也常被稱為「端點 endpoint」或「路由 route」。\n\n///\n\n在建置 API 時，「路徑」是分離「關注點」和「資源」的主要方式。\n\n#### 操作 { #operation }\n\n這裡的「操作」指的是 HTTP 的「方法」之一。\n\n其中包括：\n\n* `POST`\n* `GET`\n* `PUT`\n* `DELETE`\n\n……以及更少見的：\n\n* `OPTIONS`\n* `HEAD`\n* `PATCH`\n* `TRACE`\n\n在 HTTP 協定中，你可以使用這些「方法」之一（或更多）與每個路徑進行通信。\n\n---\n\n在建置 API 時，你通常使用這些特定的 HTTP 方法來執行特定的動作。\n\n通常你使用：\n\n* `POST`：用來建立資料。\n* `GET`：用來讀取資料。\n* `PUT`：用來更新資料。\n* `DELETE`：用來刪除資料。\n\n所以，在 OpenAPI 中，每個 HTTP 方法都被稱為「操作」。\n\n我們將會稱它們為「**操作**」。\n\n#### 定義一個「路徑操作裝飾器」 { #define-a-path-operation-decorator }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[6] *}\n\n`@app.get(\"/\")` 告訴 **FastAPI** 那個函式負責處理請求：\n\n* 路徑 `/`\n* 使用 <dfn title=\"HTTP GET 方法\"><code>get</code> 操作</dfn>\n\n/// info | `@decorator` 說明\n\nPython 中的 `@something` 語法被稱為「裝飾器」。\n\n你把它放在一個函式上面。像一個漂亮的裝飾帽子（我猜這是術語的來源）。\n\n一個「裝飾器」會對下面的函式做一些事情。\n\n在這種情況下，這個裝飾器告訴 **FastAPI** 那個函式對應於 **路徑** `/` 和 **操作** `get`。\n\n這就是「**路徑操作裝飾器**」。\n\n///\n\n你也可以使用其他的操作：\n\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n\n以及更少見的：\n\n* `@app.options()`\n* `@app.head()`\n* `@app.patch()`\n* `@app.trace()`\n\n/// tip\n\n你可以自由地使用每個操作（HTTP 方法）。\n\n**FastAPI** 不強制任何特定的意義。\n\n這裡的資訊作為一個指南，而不是要求。\n\n例如，當使用 GraphQL 時，你通常只使用 `POST` 操作。\n\n///\n\n### 第四步：定義「路徑操作函式」 { #step-4-define-the-path-operation-function }\n\n這是我們的「**路徑操作函式**」：\n\n* **path**：是 `/`。\n* **operation**：是 `get`。\n* **function**：是裝飾器下面的函式（在 `@app.get(\"/\")` 下面）。\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[7] *}\n\n這就是一個 Python 函式。\n\n它將會在 **FastAPI** 收到一個使用 `GET` 操作、網址為「`/`」的請求時被呼叫。\n\n在這種情況下，它是一個 `async` 函式。\n\n---\n\n你也可以將它定義為一般函式，而不是 `async def`：\n\n{* ../../docs_src/first_steps/tutorial003_py310.py hl[7] *}\n\n/// note\n\n如果你不知道差別，請查看 [Async: *\"In a hurry?\"*](../async.md#in-a-hurry)。\n\n///\n\n### 第五步：回傳內容 { #step-5-return-the-content }\n\n{* ../../docs_src/first_steps/tutorial001_py310.py hl[8] *}\n\n你可以返回一個 `dict`、`list`、單個值作為 `str`、`int` 等。\n\n你也可以返回 Pydantic 模型（稍後你會看到更多關於這方面的內容）。\n\n有很多其他物件和模型會自動轉換為 JSON（包括 ORMs，等等）。試用你最喜歡的，很有可能它們已經有支援。\n\n### 第六步：部署 { #step-6-deploy-it }\n\n用一行指令將你的應用程式部署到 **[FastAPI Cloud](https://fastapicloud.com)**：`fastapi deploy`。🎉\n\n#### 關於 FastAPI Cloud { #about-fastapi-cloud }\n\n**[FastAPI Cloud](https://fastapicloud.com)** 由 **FastAPI** 的作者與團隊打造。\n\n它讓你以最小的成本完成 API 的**建置**、**部署**與**存取**流程。\n\n它把用 FastAPI 開發應用的同樣**開發者體驗**帶到將應用**部署**到雲端的流程中。🎉\n\nFastAPI Cloud 也是「FastAPI 與其好友」這些開源專案的主要贊助與資金提供者。✨\n\n#### 部署到其他雲端供應商 { #deploy-to-other-cloud-providers }\n\nFastAPI 是開源並基於標準的。你可以把 FastAPI 應用部署到你選擇的任何雲端供應商。\n\n依照你的雲端供應商的指南部署 FastAPI 應用吧。🤓\n\n## 回顧 { #recap }\n\n* 引入 `FastAPI`。\n* 建立一個 `app` 實例。\n* 寫一個「路徑操作裝飾器」，像是 `@app.get(\"/\")`。\n* 定義一個「路徑操作函式」；例如，`def root(): ...`。\n* 使用命令 `fastapi dev` 執行開發伺服器。\n* 可選：使用 `fastapi deploy` 部署你的應用程式。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/handling-errors.md",
    "content": "# 錯誤處理 { #handling-errors }\n\n在許多情況下，你需要通知使用你 API 的用戶端發生錯誤。\n\n這個用戶端可能是帶有前端的瀏覽器、他人的程式碼、IoT 裝置等。\n\n你可能需要告訴用戶端：\n\n* 用戶端沒有足夠權限執行該操作。\n* 用戶端沒有權限存取該資源。\n* 用戶端嘗試存取的項目不存在。\n* 等等。\n\n在這些情況下，通常會回傳範圍為 400（400 到 499）的 HTTP 狀態碼。\n\n這類似於 200 範圍的 HTTP 狀態碼（200 到 299）。那些「200」狀態碼表示請求在某種程度上是「成功」的。\n\n400 範圍的狀態碼表示用戶端錯誤。\n\n還記得那些「404 Not Found」錯誤（和梗）嗎？\n\n## 使用 `HTTPException` { #use-httpexception }\n\n要向用戶端回傳帶有錯誤的 HTTP 回應，使用 `HTTPException`。\n\n### 匯入 `HTTPException` { #import-httpexception }\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[1] *}\n\n### 在程式中 raise 一個 `HTTPException` { #raise-an-httpexception-in-your-code }\n\n`HTTPException` 是一般的 Python 例外，但包含與 API 相關的附加資料。\n\n因為它是 Python 的例外，你不是 `return`，而是 `raise`。\n\n這也表示，如果你在某個工具函式中（該函式被你的「路徑操作函式」呼叫），並在該工具函式裡 raise `HTTPException`，那麼「路徑操作函式」剩下的程式碼將不會執行；該請求會立刻被終止，並將 `HTTPException` 的 HTTP 錯誤傳回給用戶端。\n\n為何選擇 raise 例外而非回傳值的好處，會在相依性與安全性章節更為明顯。\n\n在這個範例中，當用戶端以不存在的 ID 請求項目時，raise 一個狀態碼為 `404` 的例外：\n\n{* ../../docs_src/handling_errors/tutorial001_py310.py hl[11] *}\n\n### 回應結果 { #the-resulting-response }\n\n如果用戶端請求 `http://example.com/items/foo`（`item_id` 為 `\"foo\"`），會收到 200 的 HTTP 狀態碼，以及以下 JSON 回應：\n\n```JSON\n{\n  \"item\": \"The Foo Wrestlers\"\n}\n```\n\n但如果用戶端請求 `http://example.com/items/bar`（不存在的 `item_id` `\"bar\"`），會收到 404（\"not found\"）的 HTTP 狀態碼，以及以下 JSON 回應：\n\n```JSON\n{\n  \"detail\": \"Item not found\"\n}\n```\n\n/// tip\n\n在 raise 一個 `HTTPException` 時，你可以將任何可轉為 JSON 的值作為 `detail` 參數，不只限於 `str`。\n\n你可以傳入 `dict`、`list` 等。\n\n**FastAPI** 會自動處理並轉為 JSON。\n\n///\n\n## 新增自訂標頭 { #add-custom-headers }\n\n有些情況需要在 HTTP 錯誤回應中加入自訂標頭，例如某些安全性情境。\n\n你大概不需要在程式碼中直接使用。\n\n但若你在進階情境中需要，可以這樣加入自訂標頭：\n\n{* ../../docs_src/handling_errors/tutorial002_py310.py hl[14] *}\n\n## 安裝自訂例外處理器 { #install-custom-exception-handlers }\n\n你可以使用 [Starlette 的相同例外工具](https://www.starlette.dev/exceptions/) 來加入自訂例外處理器。\n\n假設你有一個自訂例外 `UnicornException`，你（或你使用的函式庫）可能會 `raise` 它。\n\n而你想用 FastAPI 全域處理這個例外。\n\n你可以使用 `@app.exception_handler()` 加入自訂例外處理器：\n\n{* ../../docs_src/handling_errors/tutorial003_py310.py hl[5:7,13:18,24] *}\n\n在這裡，如果你請求 `/unicorns/yolo`，該「路徑操作」會 `raise` 一個 `UnicornException`。\n\n但它會被 `unicorn_exception_handler` 所處理。\n\n因此你會得到一個乾淨的錯誤回應，HTTP 狀態碼為 `418`，JSON 內容如下：\n\n```JSON\n{\"message\": \"Oops! yolo did something. There goes a rainbow...\"}\n```\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.requests import Request` 與 `from starlette.responses import JSONResponse`。\n\n**FastAPI** 以便利性為由，提供和 `starlette.responses` 相同的介面於 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。`Request` 也一樣。\n\n///\n\n## 覆寫預設例外處理器 { #override-the-default-exception-handlers }\n\n**FastAPI** 內建了一些預設例外處理器。\n\n這些處理器負責在你 `raise` 一個 `HTTPException` 或請求帶有無效資料時，回傳預設的 JSON 回應。\n\n你可以用自己的處理器來覆寫它們。\n\n### 覆寫請求驗證例外 { #override-request-validation-exceptions }\n\n當請求包含無效資料時，**FastAPI** 會在內部 raise 一個 `RequestValidationError`。\n\n它同時也包含了對應的預設例外處理器。\n\n要覆寫它，匯入 `RequestValidationError`，並用 `@app.exception_handler(RequestValidationError)` 來裝飾你的例外處理器。\n\n例外處理器會接收一個 `Request` 和該例外。\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[2,14:19] *}\n\n現在，如果你前往 `/items/foo`，預設的 JSON 錯誤本應為：\n\n```JSON\n{\n    \"detail\": [\n        {\n            \"loc\": [\n                \"path\",\n                \"item_id\"\n            ],\n            \"msg\": \"value is not a valid integer\",\n            \"type\": \"type_error.integer\"\n        }\n    ]\n}\n```\n\n你將會改而得到文字版：\n\n```\nValidation errors:\nField: ('path', 'item_id'), Error: Input should be a valid integer, unable to parse string as an integer\n```\n\n### 覆寫 `HTTPException` 的錯誤處理器 { #override-the-httpexception-error-handler }\n\n同樣地，你也可以覆寫 `HTTPException` 的處理器。\n\n例如，你可能想在這些錯誤時回傳純文字而非 JSON：\n\n{* ../../docs_src/handling_errors/tutorial004_py310.py hl[3:4,9:11,25] *}\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.responses import PlainTextResponse`。\n\n**FastAPI** 以便利性為由，提供和 `starlette.responses` 相同的介面於 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。\n\n///\n\n/// warning\n\n請注意，`RequestValidationError` 內含驗證錯誤發生的檔名與行號，如果你願意，可以在日誌中顯示這些相關資訊。\n\n但這也代表如果你只是把它轉成字串並直接回傳，可能會洩漏一些關於你系統的資訊。因此這裡的程式碼會分別擷取並顯示每個錯誤。\n\n///\n\n### 使用 `RequestValidationError` 的 body { #use-the-requestvalidationerror-body }\n\n`RequestValidationError` 包含它收到的（但無效的）`body`。\n\n在開發應用時，你可以用它來記錄 body 並除錯、回傳給使用者等。\n\n{* ../../docs_src/handling_errors/tutorial005_py310.py hl[14] *}\n\n現在嘗試送出一個無效的項目，例如：\n\n```JSON\n{\n  \"title\": \"towel\",\n  \"size\": \"XL\"\n}\n```\n\n你會收到一個告知資料無效、且包含所收到 body 的回應：\n\n```JSON hl_lines=\"12-15\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"size\"\n      ],\n      \"msg\": \"value is not a valid integer\",\n      \"type\": \"type_error.integer\"\n    }\n  ],\n  \"body\": {\n    \"title\": \"towel\",\n    \"size\": \"XL\"\n  }\n}\n```\n\n#### FastAPI 的 `HTTPException` 與 Starlette 的 `HTTPException` { #fastapis-httpexception-vs-starlettes-httpexception }\n\n**FastAPI** 有自己定義的 `HTTPException`。\n\n而 **FastAPI** 的 `HTTPException` 錯誤類別是繼承自 Starlette 的 `HTTPException` 錯誤類別。\n\n唯一的差異是，**FastAPI** 的 `HTTPException` 在 `detail` 欄位接受任何可轉為 JSON 的資料，而 Starlette 的 `HTTPException` 只接受字串。\n\n因此，在你的程式碼中，你可以一如往常地 raise **FastAPI** 的 `HTTPException`。\n\n但當你註冊例外處理器時，應該針對 Starlette 的 `HTTPException` 來註冊。\n\n如此一來，如果 Starlette 的內部程式碼，或任何 Starlette 擴充/外掛 raise 了 Starlette 的 `HTTPException`，你的處理器就能攔截並處理它。\n\n在這個範例中，為了能在同一份程式碼中同時使用兩種 `HTTPException`，我們把 Starlette 的例外重新命名為 `StarletteHTTPException`：\n\n```Python\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n```\n\n### 重用 **FastAPI** 的例外處理器 { #reuse-fastapis-exception-handlers }\n\n如果你想在使用例外的同時，沿用 **FastAPI** 的預設例外處理器，你可以從 `fastapi.exception_handlers` 匯入並重用預設的處理器：\n\n{* ../../docs_src/handling_errors/tutorial006_py310.py hl[2:5,15,21] *}\n\n在這個範例中，你只是用一段很生動的訊息把錯誤印出來，不過重點是：你可以使用該例外，然後直接重用預設的例外處理器。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/header-param-models.md",
    "content": "# 標頭參數模型 { #header-parameter-models }\n\n如果你有一組相關的標頭參數，可以建立一個 Pydantic 模型來宣告它們。\n\n這能讓你在多處重複使用該模型，並一次性為所有參數宣告驗證與中繼資料。😎\n\n/// note | 注意\n\n自 FastAPI 版本 `0.115.0` 起支援。🤓\n\n///\n\n## 以 Pydantic 模型宣告標頭參數 { #header-parameters-with-a-pydantic-model }\n\n在 Pydantic 模型中宣告你需要的標頭參數，然後將參數宣告為 `Header`：\n\n{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *}\n\nFastAPI 會從請求的標頭為每個欄位擷取資料，並交給你已定義的 Pydantic 模型實例。\n\n## 檢視文件 { #check-the-docs }\n\n你可以在 `/docs` 的文件介面看到所需的標頭：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/header-param-models/image01.png\">\n</div>\n\n## 禁止額外標頭 { #forbid-extra-headers }\n\n在某些特殊情境（可能不常見）下，你可能想限制允許接收的標頭。\n\n你可以使用 Pydantic 的模型設定來 `forbid` 任何 `extra` 欄位：\n\n{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *}\n\n如果用戶端嘗試傳送額外的標頭，會收到錯誤回應。\n\n例如，用戶端若傳送名為 `tool`、值為 `plumbus` 的標頭，會收到錯誤回應，指出不允許標頭參數 `tool`：\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"header\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\",\n        }\n    ]\n}\n```\n\n## 停用底線轉換 { #disable-convert-underscores }\n\n與一般標頭參數相同，當參數名稱包含底線字元時，會自動轉換為連字號。\n\n例如，若在程式碼中有標頭參數 `save_data`，實際期望的 HTTP 標頭為 `save-data`，在文件中也會如此顯示。\n\n如果因某些原因需要停用這個自動轉換，你也可以在標頭參數的 Pydantic 模型上設定。\n\n{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *}\n\n/// warning | 警告\n\n在將 `convert_underscores` 設為 `False` 之前，請注意有些 HTTP 代理與伺服器不允許含有底線的標頭。\n\n///\n\n## 摘要 { #summary }\n\n你可以在 FastAPI 中使用 Pydantic 模型宣告標頭。😎\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/header-params.md",
    "content": "# Header 參數 { #header-parameters }\n\n你可以用與定義 `Query`、`Path`、`Cookie` 參數相同的方式來定義 Header 參數。\n\n## 匯入 `Header` { #import-header }\n\n先匯入 `Header`：\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[3] *}\n\n## 宣告 `Header` 參數 { #declare-header-parameters }\n\n接著使用與 `Path`、`Query`、`Cookie` 相同的結構來宣告標頭參數。\n\n你可以設定預設值，以及所有額外的驗證或註解參數：\n\n{* ../../docs_src/header_params/tutorial001_an_py310.py hl[9] *}\n\n/// note | 注意\n\n`Header` 與 `Path`、`Query`、`Cookie` 是「姊妹」類別，同樣繼承自共同的 `Param` 類別。\n\n但請記得，當你從 `fastapi` 匯入 `Query`、`Path`、`Header` 等時，它們其實是會回傳特殊類別的函式。\n\n///\n\n/// info | 說明\n\n要宣告標頭，必須使用 `Header`，否則參數會被解讀為查詢參數。\n\n///\n\n## 自動轉換 { #automatic-conversion }\n\n在 `Path`、`Query`、`Cookie` 提供的功能之上，`Header` 還有一些額外的小功能。\n\n大多數標準標頭的單字以連字號（減號，`-`）分隔。\n\n但像 `user-agent` 這樣的變數名稱在 Python 中是無效的。\n\n因此，`Header` 會在預設情況下把參數名稱中的底線（`_`）轉換為連字號（`-`），以便讀取並在文件中顯示該標頭。\n\n此外，HTTP 標頭不區分大小寫，所以你可以使用標準的 Python 命名風格（snake_case）來宣告。\n\n因此，你可以像在 Python 程式中一樣使用 `user_agent`，不需要把首字母大寫成 `User_Agent` 或類似寫法。\n\n若因某些原因需要停用底線自動轉連字號的行為，將 `Header` 的 `convert_underscores` 參數設為 `False`：\n\n{* ../../docs_src/header_params/tutorial002_an_py310.py hl[10] *}\n\n/// warning | 警告\n\n在將 `convert_underscores` 設為 `False` 之前，請注意有些 HTTP 代理與伺服器不允許使用帶有底線的標頭。\n\n///\n\n## 重複的標頭 { #duplicate-headers }\n\n有時可能會收到重複的標頭，也就是同一個標頭會有多個值。\n\n可以在型別宣告中使用 list 來定義這種情況。\n\n你會以 Python 的 `list` 形式收到該重複標頭的所有值。\n\n例如，要宣告可以出現多次的 `X-Token` 標頭，可以這樣寫：\n\n{* ../../docs_src/header_params/tutorial003_an_py310.py hl[9] *}\n\n如果你在與該*路徑操作 (path operation)* 溝通時送出兩個 HTTP 標頭如下：\n\n```\nX-Token: foo\nX-Token: bar\n```\n\n回應會像這樣：\n\n```JSON\n{\n    \"X-Token values\": [\n        \"bar\",\n        \"foo\"\n    ]\n}\n```\n\n## 小結 { #recap }\n\n使用 `Header` 宣告標頭，套用與 `Query`、`Path`、`Cookie` 相同的通用模式。\n\n而且別擔心變數名稱中的底線，**FastAPI** 會自動幫你轉換。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/index.md",
    "content": "# 教學 - 使用者指南 { #tutorial-user-guide }\n\n本教學將一步一步展示如何使用 **FastAPI** 及其大多數功能。\n\n每個部分都是在前一部分的基礎上逐步建置的，但內容結構是按主題分開的，因此你可以直接跳到任何特定的部分，解決你具體的 API 需求。\n\n它也被設計成可作為未來的參考，讓你隨時回來查看所需的內容。\n\n## 運行程式碼 { #run-the-code }\n\n所有程式碼區塊都可以直接複製和使用（它們實際上是經過測試的 Python 檔案）。\n\n要運行任何範例，請將程式碼複製到 `main.py` 檔案，並使用以下命令啟動 `fastapi dev`：\n\n<div class=\"termy\">\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> dev\n\n  <span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting development server 🚀\n\n             Searching for package file structure from directories\n             with <font color=\"#3465A4\">__init__.py</font> files\n             Importing from <font color=\"#75507B\">/home/user/code/</font><font color=\"#AD7FA8\">awesomeapp</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> module </font></span>  🐍 main.py\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> code </font></span>  Importing the FastAPI app object from the module with\n             the following code:\n\n             <u style=\"text-decoration-style:solid\">from </u><u style=\"text-decoration-style:solid\"><b>main</b></u><u style=\"text-decoration-style:solid\"> import </u><u style=\"text-decoration-style:solid\"><b>app</b></u>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> app </font></span>  Using import string: <font color=\"#3465A4\">main:app</font>\n\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Server started at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font>\n   <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> server </font></span>  Documentation at <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000/docs</u></font>\n\n      <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> tip </font></span>  Running in development mode, for production use:\n             <b>fastapi run</b>\n\n             Logs:\n\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Will watch for changes in these directories:\n             <b>[</b><font color=\"#4E9A06\">&apos;/home/user/code/awesomeapp&apos;</font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Uvicorn running on <font color=\"#729FCF\"><u style=\"text-decoration-style:solid\">http://127.0.0.1:8000</u></font> <b>(</b>Press CTRL+C\n             to quit<b>)</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started reloader process <b>[</b><font color=\"#34E2E2\"><b>383138</b></font><b>]</b> using WatchFiles\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Started server process <b>[</b><font color=\"#34E2E2\"><b>383153</b></font><b>]</b>\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Waiting for application startup.\n     <span style=\"background-color:#007166\"><font color=\"#D3D7CF\"> INFO </font></span>  Application startup complete.\n```\n\n</div>\n\n**強烈建議**你編寫或複製程式碼、進行修改並在本地端運行。\n\n在編輯器中使用它，才能真正體會到 FastAPI 的好處，可以看到你只需編寫少量程式碼，以及所有的型別檢查、自動補齊等功能。\n\n---\n\n## 安裝 FastAPI { #install-fastapi }\n\n第一步是安裝 FastAPI。\n\n確保你建立一個[虛擬環境](../virtual-environments.md)，啟用它，然後**安裝 FastAPI**：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n/// note | 注意\n\n當你使用 `pip install \"fastapi[standard]\"` 安裝時，會包含一些預設的可選標準依賴項，其中包括 `fastapi-cloud-cli`，它可以讓你部署到 [FastAPI Cloud](https://fastapicloud.com)。\n\n如果你不想包含那些可選的依賴項，你可以改為安裝 `pip install fastapi`。\n\n如果你想安裝標準依賴項，但不包含 `fastapi-cloud-cli`，可以使用 `pip install \"fastapi[standard-no-fastapi-cloud-cli]\"` 安裝。\n\n///\n\n/// tip\n\nFastAPI 提供了 [VS Code 官方擴充功能](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode)（以及 Cursor），包含許多功能，例如路徑操作探索器、路徑操作搜尋、測試中的 CodeLens 導航（從測試跳到定義）、以及 FastAPI Cloud 的部署與日誌，全部可直接在你的編輯器中完成。\n\n///\n\n## 進階使用者指南 { #advanced-user-guide }\n\n還有一個**進階使用者指南**你可以在讀完這個**教學 - 使用者指南**後再閱讀。\n\n**進階使用者指南**建立在這個教學之上，使用相同的概念，並教你一些額外的功能。\n\n但首先你應該閱讀**教學 - 使用者指南**（你正在閱讀的內容）。\n\n它被設計成你可以使用**教學 - 使用者指南**來建立一個完整的應用程式，然後根據你的需求，使用一些額外的想法來擴展它。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/metadata.md",
    "content": "# 中繼資料與文件 URL { #metadata-and-docs-urls }\n\n你可以在你的 FastAPI 應用程式中自訂多項中繼資料設定。\n\n## API 的中繼資料 { #metadata-for-api }\n\n你可以設定下列欄位，這些欄位會用在 OpenAPI 規格與自動產生的 API 文件介面中：\n\n| 參數 | 型別 | 說明 |\n|------------|------|-------------|\n| `title` | `str` | API 的標題。 |\n| `summary` | `str` | API 的簡短摘要。<small>自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。</small> |\n| `description` | `str` | API 的簡短說明。可使用 Markdown。 |\n| `version` | `string` | API 的版本號。這是你自己的應用程式版本，不是 OpenAPI 的版本，例如 `2.5.0`。 |\n| `terms_of_service` | `str` | 指向 API 服務條款的 URL。若提供，必須是 URL。 |\n| `contact` | `dict` | 對外公開的 API 聯絡資訊。可包含多個欄位。<details><summary><code>contact</code> 欄位</summary><table><thead><tr><th>參數</th><th>型別</th><th>說明</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>聯絡人／組織的識別名稱。</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>指向聯絡資訊的 URL。必須是 URL 格式。</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>聯絡人／組織的電子郵件地址。必須是電子郵件格式。</td></tr></tbody></table></details> |\n| `license_info` | `dict` | 對外公開的 API 授權資訊。可包含多個欄位。<details><summary><code>license_info</code> 欄位</summary><table><thead><tr><th>參數</th><th>型別</th><th>說明</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>必填</strong>（若有設定 <code>license_info</code>）。API 使用的授權名稱。</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>API 的 [SPDX](https://spdx.org/licenses/) 授權表示式。<code>identifier</code> 欄位與 <code>url</code> 欄位互斥。<small>自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>API 所採用授權的 URL。必須是 URL 格式。</td></tr></tbody></table></details> |\n\n你可以這樣設定它們：\n\n{* ../../docs_src/metadata/tutorial001_py310.py hl[3:16, 19:32] *}\n\n/// tip | 提示\n\n你可以在 `description` 欄位中撰寫 Markdown，輸出時會被正確渲染。\n\n///\n\n使用這些設定後，自動產生的 API 文件會像這樣：\n\n<img src=\"/img/tutorial/metadata/image01.png\">\n\n## 授權識別碼 { #license-identifier }\n\n自 OpenAPI 3.1.0 與 FastAPI 0.99.0 起，你也可以在 `license_info` 中使用 `identifier` 來取代 `url`。\n\n例如：\n\n{* ../../docs_src/metadata/tutorial001_1_py310.py hl[31] *}\n\n## 標籤的中繼資料 { #metadata-for-tags }\n\n你也可以透過 `openapi_tags` 參數，為用來分組你的路徑操作（path operation）的各個標籤加入額外中繼資料。\n\n它接收一個 list，其中每個標籤對應一個 dictionary。\n\n每個 dictionary 可包含：\n\n* `name`（**必填**）：一個 `str`，其值需與你在路徑操作與 `APIRouter`s 的 `tags` 參數中使用的標籤名稱相同。\n* `description`：一個 `str`，為該標籤的簡短描述。可使用 Markdown，並會顯示在文件介面中。\n* `externalDocs`：一個 `dict`，描述外部文件，包含：\n    * `description`：一個 `str`，外部文件的簡短描述。\n    * `url`（**必填**）：一個 `str`，外部文件的 URL。\n\n### 建立標籤的中繼資料 { #create-metadata-for-tags }\n\n我們用 `users` 與 `items` 兩個標籤來示範。\n\n先為你的標籤建立中繼資料，然後將它傳給 `openapi_tags` 參數：\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[3:16,18] *}\n\n注意你可以在描述中使用 Markdown，例如「login」會以粗體（**login**）顯示，而「fancy」會以斜體（_fancy_）顯示。\n\n/// tip | 提示\n\n你不必為你使用到的每個標籤都加入中繼資料。\n\n///\n\n### 使用你的標籤 { #use-your-tags }\n\n在你的路徑操作（以及 `APIRouter`s）上使用 `tags` 參數，將它們歸類到不同標籤下：\n\n{* ../../docs_src/metadata/tutorial004_py310.py hl[21,26] *}\n\n/// info | 資訊\n\n在 [Path Operation Configuration](path-operation-configuration.md#tags) 中閱讀更多關於標籤的內容。\n\n///\n\n### 檢視文件 { #check-the-docs }\n\n現在檢視文件時，會看到所有額外的中繼資料：\n\n<img src=\"/img/tutorial/metadata/image02.png\">\n\n### 標籤順序 { #order-of-tags }\n\n每個標籤中繼資料 dictionary 在清單中的順序，也會決定它們在文件介面中的顯示順序。\n\n例如，雖然按字母排序時 `users` 會排在 `items` 之後，但因為我們在清單中將它的中繼資料放在第一個，所以它會先顯示。\n\n## OpenAPI URL { #openapi-url }\n\n預設情況下，OpenAPI 綱要（schema）會提供在 `/openapi.json`。\n\n但你可以用 `openapi_url` 參數來調整。\n\n例如，將它設定為提供在 `/api/v1/openapi.json`：\n\n{* ../../docs_src/metadata/tutorial002_py310.py hl[3] *}\n\n如果你想完全停用 OpenAPI 綱要，可以設定 `openapi_url=None`，同時也會停用依賴它的文件使用者介面。\n\n## 文件 URL { #docs-urls }\n\n你可以設定內建的兩個文件使用者介面：\n\n* Swagger UI：提供於 `/docs`。\n    * 可用 `docs_url` 參數設定其 URL。\n    * 設定 `docs_url=None` 可停用。\n* ReDoc：提供於 `/redoc`。\n    * 可用 `redoc_url` 參數設定其 URL。\n    * 設定 `redoc_url=None` 可停用。\n\n例如，將 Swagger UI 提供於 `/documentation`，並停用 ReDoc：\n\n{* ../../docs_src/metadata/tutorial003_py310.py hl[3] *}\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/middleware.md",
    "content": "# 中介軟體 { #middleware }\n\n你可以在 **FastAPI** 應用程式中加入中介軟體。\n\n「中介軟體」是一個函式，在任何特定的*路徑操作*處理之前先處理每個**請求**；在回傳之前，也會處理每個**回應**。\n\n- 它會攔截進到應用程式的每個**請求**。\n- 然後可以對該**請求**做一些處理或執行所需的程式碼。\n- 接著把**請求**傳遞給應用程式的其餘部分（某個*路徑操作*）處理。\n- 之後再接收應用程式（某個*路徑操作*）所產生的**回應**。\n- 可以對該**回應**做一些處理或執行所需的程式碼。\n- 然後回傳**回應**。\n\n/// note | 技術細節\n\n如果你有使用帶有 `yield` 的相依性，其釋放階段的程式碼會在中介軟體之後執行。\n\n若有背景工作（在[背景工作](background-tasks.md)一節會介紹，你稍後會看到），它們會在所有中介軟體之後執行。\n\n///\n\n## 建立中介軟體 { #create-a-middleware }\n\n要建立中介軟體，將裝飾器 `@app.middleware(\"http\")` 加在函式上方。\n\n中介軟體函式會接收：\n\n- `request`。\n- 一個函式 `call_next`，會以 `request` 作為參數。\n    - 這個函式會把 `request` 傳給對應的*路徑操作*。\n    - 然後回傳對應*路徑操作*所產生的 `response`。\n- 然後你可以在回傳之前進一步修改 `response`。\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[8:9,11,14] *}\n\n/// tip\n\n請記得，自訂的非標準標頭可以[使用 `X-` 前綴](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)。\n\n但如果你有自訂標頭並希望瀏覽器端的用戶端能看到它們，你需要在 CORS 設定（[CORS（跨來源資源共用）](cors.md)）中使用 [Starlette 的 CORS 文件](https://www.starlette.dev/middleware/#corsmiddleware)所記載的參數 `expose_headers` 將它們加入。\n\n///\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.requests import Request`。\n\n**FastAPI** 為了方便開發者而提供了它，但實際上它直接來自 Starlette。\n\n///\n\n### 在 `response` 之前與之後 { #before-and-after-the-response }\n\n你可以在任何*路徑操作*接收 `request` 之前，加入要執行的程式碼。\n\n也可以在產生出 `response` 之後、回傳之前執行程式碼。\n\n例如，你可以新增一個自訂標頭 `X-Process-Time`，其內容為處理請求並產生回應所花費的秒數：\n\n{* ../../docs_src/middleware/tutorial001_py310.py hl[10,12:13] *}\n\n/// tip\n\n這裡我們使用 [`time.perf_counter()`](https://docs.python.org/3/library/time.html#time.perf_counter) 而不是 `time.time()`，因為在這些用例中它可能更精確。🤓\n\n///\n\n## 多個中介軟體的執行順序 { #multiple-middleware-execution-order }\n\n當你使用 `@app.middleware()` 裝飾器或 `app.add_middleware()` 方法加入多個中介軟體時，每個新的中介軟體都會包裹應用程式，形成一個堆疊。最後加入的中介軟體位於最外層，最先加入的位於最內層。\n\n在請求路徑上，最外層的中介軟體最先執行。\n\n在回應路徑上，它最後執行。\n\n例如：\n\n```Python\napp.add_middleware(MiddlewareA)\napp.add_middleware(MiddlewareB)\n```\n\n執行順序如下：\n\n- **請求**：MiddlewareB → MiddlewareA → 路由\n\n- **回應**：路由 → MiddlewareA → MiddlewareB\n\n這種堆疊行為可確保中介軟體以可預期且可控制的順序執行。\n\n## 其他中介軟體 { #other-middlewares }\n\n你之後可以在[進階使用者指南：進階中介軟體](../advanced/middleware.md)閱讀更多關於其他中介軟體的內容。\n\n下一節你將會讀到如何使用中介軟體處理 <abbr title=\"Cross-Origin Resource Sharing - 跨來源資源共用\">CORS</abbr>。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/path-operation-configuration.md",
    "content": "# 路徑操作設定 { #path-operation-configuration }\n\n你可以在你的「路徑操作裝飾器」中傳入多個參數來進行設定。\n\n/// warning | 警告\n\n請注意，這些參數是直接傳給「路徑操作裝飾器」，而不是傳給你的「路徑操作函式」。\n\n///\n\n## 回應狀態碼 { #response-status-code }\n\n你可以為「路徑操作」的回應設定 (HTTP) `status_code`。\n\n你可以直接傳入整數代碼，例如 `404`。\n\n如果不記得每個數字代碼代表什麼，你可以使用 `status` 中的速記常數：\n\n{* ../../docs_src/path_operation_configuration/tutorial001_py310.py hl[1,15] *}\n\n該狀態碼會用於回應，並被加入至 OpenAPI 結構描述中。\n\n/// note | 技術細節\n\n你也可以使用 `from starlette import status`。\n\n**FastAPI** 提供與 `starlette.status` 相同的 `fastapi.status`，僅為了方便你這位開發者，但它其實直接來自 Starlette。\n\n///\n\n## 標籤 { #tags }\n\n你可以為「路徑操作」加入標籤，傳入參數 `tags`，其值為由 `str` 組成的 `list`（通常只是一個 `str`）：\n\n{* ../../docs_src/path_operation_configuration/tutorial002_py310.py hl[15,20,25] *}\n\n這些標籤會被加入到 OpenAPI 結構描述，並由自動化文件介面使用：\n\n<img src=\"/img/tutorial/path-operation-configuration/image01.png\">\n\n### 含 Enum 的標籤 { #tags-with-enums }\n\n如果你的應用很大，可能會累積數個標籤，你會希望對相關的「路徑操作」始終使用相同的標籤。\n\n在這種情況下，可以考慮把標籤存放在 `Enum` 中。\n\n**FastAPI** 對此的支援方式與使用普通字串相同：\n\n{* ../../docs_src/path_operation_configuration/tutorial002b_py310.py hl[1,8:10,13,18] *}\n\n## 摘要與描述 { #summary-and-description }\n\n你可以加入 `summary` 與 `description`：\n\n{* ../../docs_src/path_operation_configuration/tutorial003_py310.py hl[17:18] *}\n\n## 從 docstring 取得描述 { #description-from-docstring }\n\n由於描述常常較長、跨越多行，你可以在函式的 <dfn title=\"用於文件的多行字串，作為函式內的第一個運算式（不賦值給任何變數）\">文件字串（docstring）</dfn> 中宣告「路徑操作」的描述，**FastAPI** 會從那裡讀取。\n\n你可以在 docstring 中書寫 [Markdown](https://en.wikipedia.org/wiki/Markdown)，它會被正確解析並顯示（會考慮 docstring 的縮排）。\n\n{* ../../docs_src/path_operation_configuration/tutorial004_py310.py hl[17:25] *}\n\n這會用於互動式文件：\n\n<img src=\"/img/tutorial/path-operation-configuration/image02.png\">\n\n## 回應描述 { #response-description }\n\n你可以用參數 `response_description` 指定回應的描述：\n\n{* ../../docs_src/path_operation_configuration/tutorial005_py310.py hl[18] *}\n\n/// info | 資訊\n\n請注意，`response_description` 專指回應，而 `description` 則是針對整個「路徑操作」的一般描述。\n\n///\n\n/// check | 檢查\n\nOpenAPI 規範要求每個「路徑操作」都必須有一個回應描述。\n\n因此，如果你未提供，**FastAPI** 會自動產生 \"Successful response\"。\n\n///\n\n<img src=\"/img/tutorial/path-operation-configuration/image03.png\">\n\n## 將「路徑操作」標記為已棄用 { #deprecate-a-path-operation }\n\n若需要將「路徑操作」標記為 <dfn title=\"已過時，建議不要再使用\">已棄用</dfn>，但不移除它，請傳入參數 `deprecated`：\n\n{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *}\n\n在互動式文件中，它會被清楚標示為已棄用：\n\n<img src=\"/img/tutorial/path-operation-configuration/image04.png\">\n\n比較已棄用與未棄用的「路徑操作」在文件中的呈現：\n\n<img src=\"/img/tutorial/path-operation-configuration/image05.png\">\n\n## 總結 { #recap }\n\n你可以透過將參數傳給「路徑操作裝飾器」，輕鬆地設定並為你的「路徑操作」加入中繼資料。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/path-params-numeric-validations.md",
    "content": "# 路徑參數與數值驗證 { #path-parameters-and-numeric-validations }\n\n就像使用 `Query` 為查詢參數宣告更多驗證與中繼資料一樣，你也可以用 `Path` 為路徑參數宣告相同類型的驗證與中繼資料。\n\n## 匯入 `Path` { #import-path }\n\n首先，從 `fastapi` 匯入 `Path`，並匯入 `Annotated`：\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[1,3] *}\n\n/// info\n\nFastAPI 在 0.95.0 版加入並開始推薦使用 `Annotated`。\n\n如果你使用更舊的版本，嘗試使用 `Annotated` 會出錯。\n\n請確保在使用 `Annotated` 前，先[升級 FastAPI 版本](../deployment/versions.md#upgrading-the-fastapi-versions)到至少 0.95.1。\n\n///\n\n## 宣告中繼資料 { #declare-metadata }\n\n你可以宣告與 `Query` 相同的所有參數。\n\n例如，若要為路徑參數 `item_id` 宣告 `title` 中繼資料，可以這樣寫：\n\n{* ../../docs_src/path_params_numeric_validations/tutorial001_an_py310.py hl[10] *}\n\n/// note\n\n路徑參數一定是必填，因為它必須是路徑的一部分。即使你將其宣告為 `None` 或設定預設值，也不會有任何影響，它仍然是必填。\n\n///\n\n## 依需求調整參數順序 { #order-the-parameters-as-you-need }\n\n/// tip\n\n如果你使用 `Annotated`，這點大概沒那麼重要或必要。\n\n///\n\n假設你想把查詢參數 `q` 宣告為必要的 `str`。\n\n而你不需要為該參數宣告其他內容，所以其實不需要用 `Query`。\n\n但你仍需要為路徑參數 `item_id` 使用 `Path`，而且基於某些理由你不想用 `Annotated`。\n\n如果你把有「預設值」的參數放在沒有「預設值」的參數之前，Python 會抱怨。\n\n但你可以調整它們的順序，先放沒有預設值（查詢參數 `q`）的參數。\n\n對 **FastAPI** 來說沒差。它會依參數名稱、型別與預設宣告（`Query`、`Path` 等）來辨識參數，並不在意順序。\n\n因此，你可以這樣宣告你的函式：\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *}\n\n但請記住，若使用 `Annotated`，你就不會有這個問題，因為你不是用函式參數預設值來放 `Query()` 或 `Path()`。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *}\n\n## 依需求調整參數順序的技巧 { #order-the-parameters-as-you-need-tricks }\n\n/// tip\n\n如果你使用 `Annotated`，這點大概沒那麼重要或必要。\n\n///\n\n這裡有個小技巧偶爾很好用，不過你大概不常需要。\n\n如果你想要：\n\n* 不用 `Query`、也不給預設值就宣告查詢參數 `q`\n* 使用 `Path` 宣告路徑參數 `item_id`\n* 讓它們的順序不同\n* 不使用 `Annotated`\n\n…Python 有個小語法可以做到。\n\n在函式的參數列表最前面放一個 `*`。\n\nPython 不會對這個 `*` 做任何事，但它會知道後續的所有參數都必須以關鍵字引數（key-value pairs）方式呼叫，也就是所謂的 <abbr title=\"源自：K-ey W-ord Arg-uments - 關鍵字參數\"><code>kwargs</code></abbr>。即便它們沒有預設值也一樣。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *}\n\n### 使用 `Annotated` 更好 { #better-with-annotated }\n\n記住，如果你使用 `Annotated`，因為不是用函式參數預設值，所以你不會遇到這個問題，也可能不需要使用 `*`。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *}\n\n## 數值驗證：大於或等於 { #number-validations-greater-than-or-equal }\n\n使用 `Query` 和 `Path`（以及你之後會看到的其他類別）可以宣告數值限制。\n\n這裡用 `ge=1`，代表 `item_id` 必須是「大於（`g`reater）或等於（`e`qual）」`1` 的整數。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *}\n\n## 數值驗證：大於與小於或等於 { #number-validations-greater-than-and-less-than-or-equal }\n\n同樣也適用於：\n\n* `gt`：大於（`g`reater `t`han）\n* `le`：小於或等於（`l`ess than or `e`qual）\n\n{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *}\n\n## 數值驗證：浮點數、大於與小於 { #number-validations-floats-greater-than-and-less-than }\n\n數值驗證也適用於 `float`。\n\n這時就能看出能宣告 <abbr title=\"greater than - 大於\"><code>gt</code></abbr>（不只是 <abbr title=\"greater than or equal - 大於或等於\"><code>ge</code></abbr>）的重要性。因為你可以要求數值必須大於 `0`，即便它小於 `1`。\n\n所以，`0.5` 是有效的值，但 `0.0` 或 `0` 則無效。\n\n<abbr title=\"less than - 小於\"><code>lt</code></abbr> 也是同樣的道理。\n\n{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *}\n\n## 小結 { #recap }\n\n使用 `Query`、`Path`（以及你尚未看到的其他類別）時，你可以像在[查詢參數與字串驗證](query-params-str-validations.md)中一樣，宣告中繼資料與字串驗證。\n\n你也可以宣告數值驗證：\n\n* `gt`：大於（`g`reater `t`han）\n* `ge`：大於或等於（`g`reater than or `e`qual）\n* `lt`：小於（`l`ess `t`han）\n* `le`：小於或等於（`l`ess than or `e`qual）\n\n/// info\n\n你之後會看到的 `Query`、`Path` 與其他類別，都是共同父類別 `Param` 的子類別。\n\n它們共享你已經看到的那些用於額外驗證與中繼資料的參數。\n\n///\n\n/// note | 技術細節\n\n當你從 `fastapi` 匯入 `Query`、`Path` 等時，它們其實是函式。\n\n呼叫它們時，會回傳同名類別的實例。\n\n也就是說，你匯入的是名為 `Query` 的函式，而當你呼叫它時，它會回傳同名的 `Query` 類別實例。\n\n這些函式之所以存在（而不是直接使用類別），是為了避免編輯器標記它們的型別錯誤。\n\n如此一來，你就能使用一般的編輯器與開發工具，而不需要額外設定來忽略那些錯誤。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/path-params.md",
    "content": "# 路徑參數 { #path-parameters }\n\n你可以用與 Python 格式化字串相同的語法來宣告路徑「參數」或「變數」：\n\n{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *}\n\n路徑參數 `item_id` 的值會作為引數 `item_id` 傳入你的函式。\n\n所以，如果你執行這個範例並前往 [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo)，你會看到這樣的回應：\n\n```JSON\n{\"item_id\":\"foo\"}\n```\n\n## 具型別的路徑參數 { #path-parameters-with-types }\n\n你可以在函式中使用標準的 Python 型別註記為路徑參數宣告型別：\n\n{* ../../docs_src/path_params/tutorial002_py310.py hl[7] *}\n\n在這個例子裡，`item_id` 被宣告為 `int`。\n\n/// check\n\n這會在你的函式中提供編輯器支援，包括錯誤檢查、自動完成等。\n\n///\n\n## 資料 <dfn title=\"也稱為：序列化、解析、封送\">轉換</dfn> { #data-conversion }\n\n如果你執行這個範例並在瀏覽器開啟 [http://127.0.0.1:8000/items/3](http://127.0.0.1:8000/items/3)，你會看到這樣的回應：\n\n```JSON\n{\"item_id\":3}\n```\n\n/// check\n\n注意你的函式接收（並回傳）的值是 `3`，也就是 Python 的 `int`，而不是字串 `\"3\"`。\n\n因此，有了這個型別宣告，**FastAPI** 會自動為你處理請求的 <dfn title=\"將 HTTP 請求中的字串轉換為 Python 資料\">「解析」</dfn>。\n\n///\n\n## 資料驗證 { #data-validation }\n\n但如果你在瀏覽器前往 [http://127.0.0.1:8000/items/foo](http://127.0.0.1:8000/items/foo)，你會看到漂亮的 HTTP 錯誤：\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"path\",\n        \"item_id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"foo\"\n    }\n  ]\n}\n```\n\n因為路徑參數 `item_id` 的值是 `\"foo\"`，它不是 `int`。\n\n同樣的錯誤也會在你提供 `float` 而不是 `int` 時出現，例如：[http://127.0.0.1:8000/items/4.2](http://127.0.0.1:8000/items/4.2)\n\n/// check\n\n因此，搭配相同的 Python 型別宣告，**FastAPI** 會為你進行資料驗證。\n\n注意錯誤也清楚指出驗證未通過的確切位置。\n\n這在開發與除錯與你的 API 互動的程式碼時非常有幫助。\n\n///\n\n## 文件 { #documentation }\n\n當你在瀏覽器開啟 [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)，你會看到自動產生、可互動的 API 文件，例如：\n\n<img src=\"/img/tutorial/path-params/image01.png\">\n\n/// check\n\n同樣地，只要使用那個 Python 型別宣告，**FastAPI** 就會提供自動、互動式的文件（整合 Swagger UI）。\n\n注意路徑參數被宣告為整數。\n\n///\n\n## 基於標準的優勢與替代文件 { #standards-based-benefits-alternative-documentation }\n\n而且因為產生的 schema 來自 [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md) 標準，有很多相容的工具可用。\n\n因此，**FastAPI** 本身也提供另一種 API 文件（使用 ReDoc），你可以在 [http://127.0.0.1:8000/redoc](http://127.0.0.1:8000/redoc) 存取：\n\n<img src=\"/img/tutorial/path-params/image02.png\">\n\n同樣地，也有許多相容工具可用，包括支援多種語言的程式碼產生工具。\n\n## Pydantic { #pydantic }\n\n所有資料驗證都由 [Pydantic](https://docs.pydantic.dev/) 在底層處理，因此你能直接受惠。而且你可以放心使用。\n\n你可以用相同的型別宣告搭配 `str`、`float`、`bool` 與許多更複雜的資料型別。\n\n這些之中的好幾個會在接下來的教學章節中介紹。\n\n## 順序很重要 { #order-matters }\n\n在建立「路徑操作」時，你可能會遇到有固定路徑的情況。\n\n像是 `/users/me`，假設它用來取得目前使用者的資料。\n\n然後你也可能有一個路徑 `/users/{user_id}` 用來依使用者 ID 取得特定使用者的資料。\n\n因為「路徑操作」會依宣告順序來比對，你必須確保 `/users/me` 的路徑在 `/users/{user_id}` 之前宣告：\n\n{* ../../docs_src/path_params/tutorial003_py310.py hl[6,11] *}\n\n否則，`/users/{user_id}` 的路徑也會匹配 `/users/me`，並「認為」它收到一個值為 `\"me\"` 的 `user_id` 參數。\n\n同樣地，你不能重新定義同一路徑操作：\n\n{* ../../docs_src/path_params/tutorial003b_py310.py hl[6,11] *}\n\n因為第一個會被優先使用（路徑先匹配到）。\n\n## 預先定義的值 { #predefined-values }\n\n如果你有一個接收「路徑參數」的「路徑操作」，但你希望可用的「路徑參數」值是預先定義好的，你可以使用標準的 Python <abbr title=\"Enumeration - 列舉\">`Enum`</abbr>。\n\n### 建立 `Enum` 類別 { #create-an-enum-class }\n\n匯入 `Enum` 並建立一個同時繼承自 `str` 與 `Enum` 的子類別。\n\n繼承自 `str` 之後，API 文件就能知道這些值的型別必須是 `string`，並能正確地呈現。\n\n然後建立具有固定值的類別屬性，這些就是可用的有效值：\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[1,6:9] *}\n\n/// tip\n\n如果你在想，「AlexNet」、「ResNet」和「LeNet」只是一些機器學習 <dfn title=\"嚴格來說是深度學習的模型架構\">模型</dfn> 的名字。\n\n///\n\n### 宣告一個「路徑參數」 { #declare-a-path-parameter }\n\n接著使用你建立的列舉類別（`ModelName`）作為型別註記，建立一個「路徑參數」：\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[16] *}\n\n### 查看文件 { #check-the-docs }\n\n因為「路徑參數」的可用值是預先定義的，互動式文件可以很漂亮地顯示它們：\n\n<img src=\"/img/tutorial/path-params/image03.png\">\n\n### 使用 Python「列舉」 { #working-with-python-enumerations }\n\n「路徑參數」的值會是一個「列舉成員」。\n\n#### 比較「列舉成員」 { #compare-enumeration-members }\n\n你可以把它與你建立的列舉 `ModelName` 中的「列舉成員」比較：\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[17] *}\n\n#### 取得「列舉值」 { #get-the-enumeration-value }\n\n你可以用 `model_name.value` 取得實際的值（在這個例子中是 `str`），一般而言就是 `your_enum_member.value`：\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[20] *}\n\n/// tip\n\n你也可以用 `ModelName.lenet.value` 取得值 `\"lenet\"`。\n\n///\n\n#### 回傳「列舉成員」 { #return-enumeration-members }\n\n你可以從「路徑操作」回傳「列舉成員」，即使是巢狀在 JSON 主體（例如 `dict`）裡。\n\n在回傳給用戶端之前，它們會被轉成對應的值（此例為字串）：\n\n{* ../../docs_src/path_params/tutorial005_py310.py hl[18,21,23] *}\n\n你的用戶端會收到像這樣的 JSON 回應：\n\n```JSON\n{\n  \"model_name\": \"alexnet\",\n  \"message\": \"Deep Learning FTW!\"\n}\n```\n\n## 包含路徑的路徑參數 { #path-parameters-containing-paths }\n\n假設你有一個路徑為 `/files/{file_path}` 的「路徑操作」。\n\n但你需要 `file_path` 本身就包含一個「路徑」，像是 `home/johndoe/myfile.txt`。\n\n所以，該檔案的 URL 會是：`/files/home/johndoe/myfile.txt`。\n\n### OpenAPI 支援 { #openapi-support }\n\nOpenAPI 並不支援直接宣告一個「路徑參數」內再包含一個「路徑」，因為那會導致難以測試與定義的情況。\n\n然而，你仍可在 **FastAPI** 中這樣做，方法是使用 Starlette 的其中一個內部工具。\n\n而文件依然能運作，只是它不會額外說明該參數應該包含一個路徑。\n\n### 路徑轉換器 { #path-convertor }\n\n使用 Starlette 提供的選項，你可以用像這樣的 URL 來宣告一個包含「路徑」的「路徑參數」：\n\n```\n/files/{file_path:path}\n```\n\n在這個例子裡，參數名稱是 `file_path`，而最後面的 `:path` 表示該參數應該匹配任意「路徑」。\n\n所以你可以這樣使用它：\n\n{* ../../docs_src/path_params/tutorial004_py310.py hl[6] *}\n\n/// tip\n\n你可能需要這個參數包含 `/home/johndoe/myfile.txt`，也就是前面帶有斜線（`/`）。\n\n在那種情況下，URL 會是：`/files//home/johndoe/myfile.txt`，在 `files` 與 `home` 之間有兩個斜線（`//`）。\n\n///\n\n## 回顧 { #recap }\n\n使用 **FastAPI**，只要撰寫簡短、直覺且標準的 Python 型別宣告，你就能獲得：\n\n* 編輯器支援：錯誤檢查、自動完成等\n* 資料 \"<dfn title=\"將 HTTP 請求中的字串轉換為 Python 資料\">解析</dfn>\"\n* 資料驗證\n* API 註解與自動產生文件\n\n而且你只要宣告一次就好。\n\n這大概是 **FastAPI** 相較於其他框架最明顯的優勢之一（除了原始效能之外）。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/query-param-models.md",
    "content": "# 查詢參數模型 { #query-parameter-models }\n\n如果你有一組具有相關性的**查詢參數**，你可以建立一個 **Pydantic 模型**來聲明它們。\n\n這將允許你在**多個地方**去**重複使用模型**，並且一次性為所有參數聲明驗證和元資料 (metadata)。😎\n\n/// note\n\nFastAPI 從 `0.115.0` 版本開始支援這個特性。🤓\n\n///\n\n## 使用 Pydantic 模型的查詢參數 { #query-parameters-with-a-pydantic-model }\n\n在一個 **Pydantic 模型**中聲明你需要的**查詢參數**，然後將參數聲明為 `Query`：\n\n{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *}\n\n**FastAPI** 將會從請求的**查詢參數**中**提取**出**每個欄位**的資料，並將其提供給你定義的 Pydantic 模型。\n\n## 查看文件 { #check-the-docs }\n\n你可以在 `/docs` 頁面的 UI 中查看查詢參數：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/query-param-models/image01.png\">\n</div>\n\n## 禁止額外的查詢參數 { #forbid-extra-query-parameters }\n\n在一些特殊的使用場景中（可能不是很常見），你可能希望**限制**你要收到的查詢參數。\n\n你可以使用 Pydantic 的模型設定來 `forbid`（禁止）任何 `extra`（額外）欄位：\n\n{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *}\n\n如果客戶端嘗試在**查詢參數**中發送一些**額外的**資料，他們將會收到一個**錯誤**回應。\n\n例如，如果客戶端嘗試發送一個值為 `plumbus` 的 `tool` 查詢參數，如：\n\n```http\nhttps://example.com/items/?limit=10&tool=plumbus\n```\n\n他們將收到一個**錯誤**回應，告訴他們查詢參數 `tool` 是不允許的：\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"query\", \"tool\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"plumbus\"\n        }\n    ]\n}\n```\n\n## 總結 { #summary }\n\n你可以使用 **Pydantic 模型**在 **FastAPI** 中聲明**查詢參數**。😎\n\n/// tip\n\n劇透警告：你也可以使用 Pydantic 模型來聲明 cookie 和 headers，但你將在本教學的後面部分閱讀到這部分內容。🤫\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/query-params-str-validations.md",
    "content": "# 查詢參數與字串驗證 { #query-parameters-and-string-validations }\n\nFastAPI 允許你為參數宣告額外的資訊與驗證。\n\n以下面這個應用為例：\n\n{* ../../docs_src/query_params_str_validations/tutorial001_py310.py hl[7] *}\n\n查詢參數 `q` 的型別是 `str | None`，表示它是 `str` 但也可以是 `None`，而且預設值就是 `None`，因此 FastAPI 會知道它不是必填。\n\n/// note | 注意\n\nFastAPI 會因為預設值是 `= None` 而知道 `q` 不是必填。\n\n使用 `str | None` 也能讓你的編輯器提供更好的支援並偵測錯誤。\n\n///\n\n## 額外驗證 { #additional-validation }\n\n我們要強制：即使 `q` 是可選，只要提供了，長度就不能超過 50 個字元。\n\n### 匯入 `Query` 與 `Annotated` { #import-query-and-annotated }\n\n要達成這點，先匯入：\n\n- 從 `fastapi` 匯入 `Query`\n- 從 `typing` 匯入 `Annotated`\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[1,3] *}\n\n/// info | 說明\n\nFastAPI 自 0.95.0 版起加入並開始推薦使用 `Annotated`。\n\n如果你的版本較舊，嘗試使用 `Annotated` 會出錯。\n\n請先至少 [升級 FastAPI 版本](../deployment/versions.md#upgrading-the-fastapi-versions) 到 0.95.1 再使用 `Annotated`。\n\n///\n\n## 在 `q` 參數的型別中使用 `Annotated` { #use-annotated-in-the-type-for-the-q-parameter }\n\n還記得先前在 [Python 型別介紹](../python-types.md#type-hints-with-metadata-annotations) 提到可以用 `Annotated` 為參數加入中繼資料嗎？\n\n現在就用在 FastAPI 上吧。🚀\n\n我們原本的型別註記是：\n\n```Python\nq: str | None = None\n```\n\n接著把它用 `Annotated` 包起來，變成：\n\n```Python\nq: Annotated[str | None] = None\n```\n\n這兩種寫法代表的意思相同：`q` 可以是 `str` 或 `None`，且預設是 `None`。\n\n現在來做有趣的部分。🎉\n\n## 在 `q` 參數的 `Annotated` 中加入 `Query` { #add-query-to-annotated-in-the-q-parameter }\n\n既然我們有可以放更多資訊的 `Annotated`（在此是額外驗證），就把 `Query` 放進 `Annotated`，並把參數 `max_length` 設為 `50`：\n\n{* ../../docs_src/query_params_str_validations/tutorial002_an_py310.py hl[9] *}\n\n注意預設值仍然是 `None`，所以這個參數仍是可選。\n\n不過，現在在 `Annotated` 裡有 `Query(max_length=50)`，我們就告訴 FastAPI 要對這個值做「額外驗證」，最多 50 個字元即可。😎\n\n/// tip | 提示\n\n這裡用的是 `Query()`，因為這是「查詢參數」。稍後你會看到 `Path()`、`Body()`、`Header()`、`Cookie()` 等，它們也接受與 `Query()` 相同的參數。\n\n///\n\nFastAPI 現在會：\n\n- 驗證資料，確保長度最多 50 個字元\n- 當資料不合法時，回給用戶端清楚的錯誤\n- 在 OpenAPI 的路徑操作中文件化該參數（因此會出現在自動文件 UI）\n\n## 替代方式（舊）：將 `Query` 作為預設值 { #alternative-old-query-as-the-default-value }\n\n舊版 FastAPI（<dfn title=\"2023-03 之前\">0.95.0</dfn> 以前）需要把 `Query` 當成參數的預設值，而不是放在 `Annotated` 裡。你很可能會在各處看到這種寫法，所以我也會說明一下。\n\n/// tip | 提示\n\n新程式碼且在可能的情況下，請依上面說明使用 `Annotated`。它有多項優點（如下所述），而沒有缺點。🍰\n\n///\n\n這是把 `Query()` 作為函式參數預設值的寫法，並把參數 `max_length` 設為 50：\n\n{* ../../docs_src/query_params_str_validations/tutorial002_py310.py hl[7] *}\n\n在這種情況下（未使用 `Annotated`），我們必須用 `Query()` 取代函式中的預設值 `None`，因此需要用 `Query(default=None)` 來設定預設值；對 FastAPI 而言，這達到相同目的。\n\n所以：\n\n```Python\nq: str | None = Query(default=None)\n```\n\n…會讓參數變為可選、預設值是 `None`，等同於：\n\n```Python\nq: str | None = None\n```\n\n但用 `Query` 的版本會明確宣告它是查詢參數。\n\n接著，我們可以傳更多參數給 `Query`。此例中是用於字串的 `max_length` 參數：\n\n```Python\nq: str | None = Query(default=None, max_length=50)\n```\n\n這一樣會驗證資料、在資料不合法時顯示清楚錯誤，並在 OpenAPI 的路徑操作中文件化該參數。\n\n### 將 `Query` 作為預設值或放在 `Annotated` 中 { #query-as-the-default-value-or-in-annotated }\n\n注意，把 `Query` 放在 `Annotated` 內時，不能使用 `Query` 的 `default` 參數。\n\n請改用函式參數的實際預設值。否則會不一致。\n\n例如，這是不允許的：\n\n```Python\nq: Annotated[str, Query(default=\"rick\")] = \"morty\"\n```\n\n…因為不清楚預設值到底該是 `\"rick\"` 還是 `\"morty\"`。\n\n因此，你可以（且更推薦）這樣寫：\n\n```Python\nq: Annotated[str, Query()] = \"rick\"\n```\n\n…或在較舊的程式碼中你會看到：\n\n```Python\nq: str = Query(default=\"rick\")\n```\n\n### `Annotated` 的優點 { #advantages-of-annotated }\n\n建議使用 `Annotated`，而不是在函式參數上使用（舊式的）預設值寫法，理由很多，且更好。🤓\n\n函式參數的「預設值」就是「實際的預設值」，這在 Python 的直覺上更一致。😌\n\n你也可以在沒有 FastAPI 的其他地方「直接呼叫」同一個函式，而且能「如預期」運作。若有「必填」參數（沒有預設值），你的「編輯器」會提示錯誤，「Python」在執行時也會抱怨你未傳遞必填參數。\n\n若不使用 `Annotated`、改用「（舊式）預設值」寫法，你在沒有 FastAPI 的「其他地方」呼叫該函式時，就得「記得」傳入正確參數，否則值會和預期不同（例如會得到 `QueryInfo` 或類似的東西，而不是 `str`）。你的編輯器不會提示，Python 執行該函式時也不會抱怨，只有在內部操作失敗時才會出錯。\n\n因為 `Annotated` 可以有多個中繼資料註解，你甚至可以用同一個函式配合其他工具，例如 [Typer](https://typer.tiangolo.com/)。🚀\n\n## 加入更多驗證 { #add-more-validations }\n\n你也可以加入 `min_length` 參數：\n\n{* ../../docs_src/query_params_str_validations/tutorial003_an_py310.py hl[10] *}\n\n## 加入正規表示式 { #add-regular-expressions }\n\n你可以定義參數必須符合的 <dfn title=\"正規表示式（regex、regexp）是一組用於定義字串搜尋樣式的字元序列。\">regular expression</dfn> `pattern`：\n\n{* ../../docs_src/query_params_str_validations/tutorial004_an_py310.py hl[11] *}\n\n這個特定的正規表示式樣式會檢查收到的參數值是否：\n\n- `^`：以後續的字元開頭，前面不能有其他字元。\n- `fixedquery`：必須正好等於 `fixedquery`。\n- `$`：在此結束，`fixedquery` 後面不能再有其他字元。\n\n如果你對「正規表示式」感到困惑，別擔心。這對很多人來說都不容易。你仍然可以先不使用正規表示式就完成很多事情。\n\n現在你知道，當你需要它們時，可以在 FastAPI 中使用它們。\n\n## 預設值 { #default-values }\n\n當然，你可以使用 `None` 以外的預設值。\n\n假設你想宣告查詢參數 `q` 的 `min_length` 是 `3`，且預設值是 `\"fixedquery\"`：\n\n{* ../../docs_src/query_params_str_validations/tutorial005_an_py310.py hl[9] *}\n\n/// note | 注意\n\n只要有任何型別的預設值（包含 `None`），參數就是可選（非必填）。\n\n///\n\n## 必填參數 { #required-parameters }\n\n當我們不需要宣告更多的驗證或中繼資料時，只要不提供預設值，就能讓查詢參數 `q` 成為必填，例如：\n\n```Python\nq: str\n```\n\n而不是：\n\n```Python\nq: str | None = None\n```\n\n但現在我們要搭配 `Query` 來宣告，例如：\n\n```Python\nq: Annotated[str | None, Query(min_length=3)] = None\n```\n\n因此，在使用 `Query` 時若要宣告值為必填，只要不要宣告預設值即可：\n\n{* ../../docs_src/query_params_str_validations/tutorial006_an_py310.py hl[9] *}\n\n### 必填，但可為 `None` { #required-can-be-none }\n\n你可以宣告參數可以接受 `None`，但仍然是必填。這會強制用戶端一定要送出一個值，即使該值是 `None`。\n\n要做到這點，你可以宣告 `None` 是合法型別，但不要宣告預設值：\n\n{* ../../docs_src/query_params_str_validations/tutorial006c_an_py310.py hl[9] *}\n\n## 查詢參數清單／多個值 { #query-parameter-list-multiple-values }\n\n當你用 `Query` 明確定義查詢參數時，也可以讓它接收一個值的清單；換句話說，就是「多個值」。\n\n例如，要宣告查詢參數 `q` 可以在 URL 中出現多次，你可以這樣寫：\n\n{* ../../docs_src/query_params_str_validations/tutorial011_an_py310.py hl[9] *}\n\n若使用這樣的 URL：\n\n```\nhttp://localhost:8000/items/?q=foo&q=bar\n```\n\n你會在路徑操作函式的參數 `q` 中，收到多個 `q` 查詢參數的值（`foo` 與 `bar`），以 Python 的 `list` 形式。\n\n因此，對該 URL 的回應會是：\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n/// tip | 提示\n\n要宣告型別為 `list` 的查詢參數（如上例），需要明確使用 `Query`，否則它會被解讀為請求本文。\n\n///\n\n互動式 API 文件也會相應更新，以便支援多個值：\n\n<img src=\"/img/tutorial/query-params-str-validations/image02.png\">\n\n### 查詢參數清單／多個值的預設值 { #query-parameter-list-multiple-values-with-defaults }\n\n也可以在未提供任何值時，定義 `list` 型別的預設值：\n\n{* ../../docs_src/query_params_str_validations/tutorial012_an_py310.py hl[9] *}\n\n如果你前往：\n\n```\nhttp://localhost:8000/items/\n```\n\n`q` 的預設值會是：`[\"foo\", \"bar\"]`，而回應會是：\n\n```JSON\n{\n  \"q\": [\n    \"foo\",\n    \"bar\"\n  ]\n}\n```\n\n#### 只使用 `list` { #using-just-list }\n\n你也可以直接使用 `list`，而不是 `list[str]`：\n\n{* ../../docs_src/query_params_str_validations/tutorial013_an_py310.py hl[9] *}\n\n/// note | 注意\n\n注意，在這種情況下，FastAPI 不會檢查清單的內容。\n\n例如，`list[int]` 會檢查（並文件化）清單內容為整數；但單獨使用 `list` 則不會。\n\n///\n\n## 宣告更多中繼資料 { #declare-more-metadata }\n\n你可以為參數加入更多資訊。\n\n這些資訊會被包含在產生的 OpenAPI 中，供文件 UI 與外部工具使用。\n\n/// note | 注意\n\n請留意，不同工具對 OpenAPI 的支援程度可能不同。\n\n有些工具可能暫時還不會顯示所有額外資訊；不過多半這些缺漏功能已在開發規劃中。\n\n///\n\n你可以加入 `title`：\n\n{* ../../docs_src/query_params_str_validations/tutorial007_an_py310.py hl[10] *}\n\n以及 `description`：\n\n{* ../../docs_src/query_params_str_validations/tutorial008_an_py310.py hl[14] *}\n\n## 別名參數 { #alias-parameters }\n\n想像你希望參數名稱是 `item-query`。\n\n像這樣：\n\n```\nhttp://127.0.0.1:8000/items/?item-query=foobaritems\n```\n\n但 `item-query` 不是合法的 Python 變數名稱。\n\n最接近的大概是 `item_query`。\n\n但你仍然需要它就是 `item-query`...\n\n那你可以宣告一個 `alias`，實際上就會用這個別名來讀取參數值：\n\n{* ../../docs_src/query_params_str_validations/tutorial009_an_py310.py hl[9] *}\n\n## 棄用參數 { #deprecating-parameters }\n\n現在假設你不再喜歡這個參數了。\n\n你必須暫時保留它，因為還有用戶端在用，但你希望文件能清楚標示它是<dfn title=\"過時，不建議使用\">已棄用</dfn>。\n\n接著把參數 `deprecated=True` 傳給 `Query`：\n\n{* ../../docs_src/query_params_str_validations/tutorial010_an_py310.py hl[19] *}\n\n文件會這樣顯示：\n\n<img src=\"/img/tutorial/query-params-str-validations/image01.png\">\n\n## 從 OpenAPI 排除參數 { #exclude-parameters-from-openapi }\n\n若要把某個查詢參數從產生的 OpenAPI（以及自動文件系統）中排除，將 `Query` 的 `include_in_schema` 設為 `False`：\n\n{* ../../docs_src/query_params_str_validations/tutorial014_an_py310.py hl[10] *}\n\n## 自訂驗證 { #custom-validation }\n\n有時你需要做一些上述參數無法處理的「自訂驗證」。\n\n這種情況下，你可以使用「自訂驗證函式」，它會在一般驗證之後套用（例如先確認值是 `str` 之後）。\n\n你可以在 `Annotated` 中使用 [Pydantic 的 `AfterValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-after-validator) 來達成。\n\n/// tip | 提示\n\nPydantic 也有 [`BeforeValidator`](https://docs.pydantic.dev/latest/concepts/validators/#field-before-validator) 等等。🤓\n\n///\n\n例如，以下自訂驗證器會檢查項目 ID 是否以 `isbn-` 開頭（<abbr title=\"International Standard Book Number - 國際標準書號\">ISBN</abbr> 書籍編號），或以 `imdb-` 開頭（<abbr title=\"Internet Movie Database - 互聯網電影資料庫: 含有電影資訊的網站\">IMDB</abbr> 電影 URL 的 ID）：\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py hl[5,16:19,24] *}\n\n/// info | 說明\n\n這需搭配 Pydantic 2 或以上版本。😎\n\n///\n\n/// tip | 提示\n\n如果你需要做任何需要與「外部元件」溝通的驗證（例如資料庫或其他 API），應該改用「FastAPI 依賴」（FastAPI Dependencies），你稍後會學到。\n\n這些自訂驗證器適用於只需使用請求中「同一份資料」即可完成的檢查。\n\n///\n\n### 理解這段程式碼 { #understand-that-code }\n\n重點就是在 `Annotated` 中使用「`AfterValidator` 搭配函式」。如果你願意，可以略過這一節。🤸\n\n---\n\n但如果你對這個範例感到好奇且仍有興致，以下是一些額外細節。\n\n#### 使用 `value.startswith()` 的字串 { #string-with-value-startswith }\n\n你注意到了嗎？字串的 `value.startswith()` 可以接收一個 tuple，並逐一檢查 tuple 中的每個值：\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *}\n\n#### 隨機項目 { #a-random-item }\n\n透過 `data.items()` 我們會得到一個包含每個字典項目鍵值對 tuple 的 <dfn title=\"可以用 for 迴圈遍歷的東西，例如 list、set 等等。\">iterable object</dfn>。\n\n我們用 `list(data.items())` 把這個可疊代物件轉成正式的 `list`。\n\n接著用 `random.choice()` 從清單中取得一個「隨機值」，也就是一個 `(id, name)` 的 tuple。可能像是 `(\"imdb-tt0371724\", \"The Hitchhiker's Guide to the Galaxy\")`。\n\n然後把這個 tuple 的兩個值分別指定給變數 `id` 和 `name`。\n\n因此，即使使用者沒有提供 item ID，仍然會收到一個隨機建議。\n\n……而這全部只用一行簡單的程式碼完成。🤯 你不愛 Python 嗎？🐍\n\n{* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[22:30] hl[29] *}\n\n## 重點回顧 { #recap }\n\n你可以為參數宣告額外的驗證與中繼資料。\n\n通用的驗證與中繼資料：\n\n- `alias`\n- `title`\n- `description`\n- `deprecated`\n\n字串專用的驗證：\n\n- `min_length`\n- `max_length`\n- `pattern`\n\n使用 `AfterValidator` 的自訂驗證。\n\n在這些範例中，你看到了如何為 `str` 值宣告驗證。\n\n接下來的章節會示範如何為其他型別（像是數字）宣告驗證。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/query-params.md",
    "content": "# 查詢參數 { #query-parameters }\n\n當你宣告不是路徑參數的其他函式參數時，會自動被視為「查詢（query）」參數。\n\n{* ../../docs_src/query_params/tutorial001_py310.py hl[9] *}\n\n查詢是出現在 URL 中 `?` 之後的一組鍵值對，以 `&` 字元分隔。\n\n例如，URL：\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n...查詢參數為：\n\n* `skip`：值為 `0`\n* `limit`：值為 `10`\n\n因為它們是 URL 的一部分，天生是字串。\n\n但當你以 Python 型別宣告它們（如上例中的 `int`），它們會被轉換成該型別並據此驗證。\n\n對於查詢參數，會套用與路徑參數相同的處理流程：\n\n* 編輯器支援（當然）\n* 資料 <dfn title=\"將來自 HTTP 請求的字串轉換為 Python 資料\">「解析」</dfn>\n* 資料驗證\n* 自動文件\n\n## 預設值 { #defaults }\n\n由於查詢參數不是路徑的固定部分，因此可以是選填並具有預設值。\n\n在上面的例子中，預設值為 `skip=0` 與 `limit=10`。\n\n因此，造訪下列 URL：\n\n```\nhttp://127.0.0.1:8000/items/\n```\n\n等同於造訪：\n\n```\nhttp://127.0.0.1:8000/items/?skip=0&limit=10\n```\n\n但如果你改為造訪：\n\n```\nhttp://127.0.0.1:8000/items/?skip=20\n```\n\n函式中的參數值會是：\n\n* `skip=20`：因為你在 URL 中設定了它\n* `limit=10`：因為那是預設值\n\n## 選用參數 { #optional-parameters }\n\n同樣地，你可以將預設值設為 `None` 來宣告選用的查詢參數：\n\n{* ../../docs_src/query_params/tutorial002_py310.py hl[7] *}\n\n在這種情況下，函式參數 `q` 為選用，且預設為 `None`。\n\n/// check | 注意\n\n另外請注意，FastAPI 能辨識出路徑參數 `item_id` 是路徑參數，而 `q` 不是，因此 `q` 會被當作查詢參數。\n\n///\n\n## 查詢參數型別轉換 { #query-parameter-type-conversion }\n\n你也可以宣告 `bool` 型別，值會被自動轉換：\n\n{* ../../docs_src/query_params/tutorial003_py310.py hl[7] *}\n\n在這種情況下，如果你造訪：\n\n```\nhttp://127.0.0.1:8000/items/foo?short=1\n```\n\n或\n\n```\nhttp://127.0.0.1:8000/items/foo?short=True\n```\n\n或\n\n```\nhttp://127.0.0.1:8000/items/foo?short=true\n```\n\n或\n\n```\nhttp://127.0.0.1:8000/items/foo?short=on\n```\n\n或\n\n```\nhttp://127.0.0.1:8000/items/foo?short=yes\n```\n\n或任何其他大小寫變化（全大寫、首字母大寫等），你的函式會將參數 `short` 視為 `bool` 值 `True`。否則為 `False`。\n\n## 多個路徑與查詢參數 { #multiple-path-and-query-parameters }\n\n你可以同時宣告多個路徑參數與查詢參數，FastAPI 會自動分辨。\n\n而且不必按特定順序宣告。\n\n會依名稱辨識：\n\n{* ../../docs_src/query_params/tutorial004_py310.py hl[6,8] *}\n\n## 必填查詢參數 { #required-query-parameters }\n\n當你為非路徑參數（目前我們只看到查詢參數）宣告了預設值時，它就不是必填。\n\n若你不想提供特定預設值、只想讓它為選填，將預設值設為 `None`。\n\n但若你要讓查詢參數成為必填，只要不要宣告任何預設值：\n\n{* ../../docs_src/query_params/tutorial005_py310.py hl[6:7] *}\n\n此處查詢參數 `needy` 是必填的 `str`。\n\n如果你在瀏覽器中開啟如下的 URL：\n\n```\nhttp://127.0.0.1:8000/items/foo-item\n```\n\n...沒有加上必填的 `needy` 參數，你會看到類似這樣的錯誤：\n\n```JSON\n{\n  \"detail\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"query\",\n        \"needy\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": null\n    }\n  ]\n}\n```\n\n由於 `needy` 是必填參數，你需要在 URL 中設定它：\n\n```\nhttp://127.0.0.1:8000/items/foo-item?needy=sooooneedy\n```\n\n...這樣就會成功：\n\n```JSON\n{\n    \"item_id\": \"foo-item\",\n    \"needy\": \"sooooneedy\"\n}\n```\n\n當然，你可以同時定義部分參數為必填、部分有預設值、部分為選填：\n\n{* ../../docs_src/query_params/tutorial006_py310.py hl[8] *}\n\n在此例中，有 3 個查詢參數：\n\n* `needy`，必填的 `str`。\n* `skip`，具有預設值 `0` 的 `int`。\n* `limit`，選填的 `int`。\n\n/// tip | 提示\n\n你也可以像在[路徑參數](path-params.md#predefined-values)中一樣使用 `Enum`。\n\n///\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/request-files.md",
    "content": "# 請求中的檔案 { #request-files }\n\n你可以使用 `File` 定義由用戶端上傳的檔案。\n\n/// info\n\n若要接收上傳的檔案，請先安裝 [`python-multipart`](https://github.com/Kludex/python-multipart)。\n\n請先建立並啟用一個[虛擬環境](../virtual-environments.md)，然後安裝，例如：\n\n```console\n$ pip install python-multipart\n```\n\n因為上傳的檔案是以「表單資料」送出的。\n\n///\n\n## 匯入 `File` { #import-file }\n\n從 `fastapi` 匯入 `File` 與 `UploadFile`：\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[3] *}\n\n## 定義 `File` 參數 { #define-file-parameters }\n\n和 `Body` 或 `Form` 一樣的方式建立檔案參數：\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[9] *}\n\n/// info\n\n`File` 是直接繼承自 `Form` 的類別。\n\n但請記住，當你從 `fastapi` 匯入 `Query`、`Path`、`File` 等時，它們其實是回傳特殊類別的函式。\n\n///\n\n/// tip\n\n要宣告檔案本文，必須使用 `File`，否則參數會被解讀為查詢參數或本文（JSON）參數。\n\n///\n\n檔案會以「表單資料」上傳。\n\n如果你將路徑操作函式（path operation function）的參數型別宣告為 `bytes`，**FastAPI** 會替你讀取檔案，你會以 `bytes` 取得內容。\n\n請注意，這表示整個內容會存放在記憶體中，適合小檔案。\n\n但在許多情況下，使用 `UploadFile` 會更好。\n\n## 使用 `UploadFile` 的檔案參數 { #file-parameters-with-uploadfile }\n\n將檔案參數型別設為 `UploadFile`：\n\n{* ../../docs_src/request_files/tutorial001_an_py310.py hl[14] *}\n\n使用 `UploadFile` 相較於 `bytes` 有數個優點：\n\n* 你不必在參數的預設值使用 `File()`。\n* 它使用「spooled」檔案：\n    * 檔案在記憶體中保存到某個大小上限，超過上限後會存到磁碟。\n* 因此適合處理大型檔案（例如圖片、影片、大型二進位檔等），而不會耗盡記憶體。\n* 你可以取得上傳檔案的中繼資料。\n* 它提供一個[file-like](https://docs.python.org/3/glossary.html#term-file-like-object) 的 `async` 介面。\n* 它會提供實際的 Python [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile) 物件，你可以直接傳給需要類檔案物件的其他函式或函式庫。\n\n### `UploadFile` { #uploadfile }\n\n`UploadFile` 具有以下屬性：\n\n* `filename`：一個 `str`，為上傳的原始檔名（例如 `myimage.jpg`）。\n* `content_type`：一個 `str`，為內容類型（MIME type / media type）（例如 `image/jpeg`）。\n* `file`：一個 [`SpooledTemporaryFile`](https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile)（一個[file-like](https://docs.python.org/3/glossary.html#term-file-like-object) 物件）。這是真正的 Python 檔案物件，你可以直接傳給期待「類檔案」物件的其他函式或函式庫。\n\n`UploadFile` 有以下 `async` 方法。它們底層會呼叫對應的檔案方法（使用內部的 `SpooledTemporaryFile`）。\n\n* `write(data)`：將 `data` (`str` 或 `bytes`) 寫入檔案。\n* `read(size)`：讀取檔案的 `size` (`int`) 個位元組/字元。\n* `seek(offset)`：移動到檔案中的位元組位置 `offset` (`int`)。\n    * 例如，`await myfile.seek(0)` 會移到檔案開頭。\n    * 當你已經執行過 `await myfile.read()`，之後需要再次讀取內容時特別有用。\n* `close()`：關閉檔案。\n\n由於這些都是 `async` 方法，你需要以 await 呼叫它們。\n\n例如，在 `async` 的路徑操作函式中可這樣讀取內容：\n\n```Python\ncontents = await myfile.read()\n```\n\n若是在一般的 `def` 路徑操作函式中，你可以直接存取 `UploadFile.file`，例如：\n\n```Python\ncontents = myfile.file.read()\n```\n\n/// note | `async` 技術細節\n\n當你使用這些 `async` 方法時，**FastAPI** 會在執行緒池中執行對應的檔案方法並等待結果。\n\n///\n\n/// note | Starlette 技術細節\n\n**FastAPI** 的 `UploadFile` 直接繼承自 **Starlette** 的 `UploadFile`，但新增了一些必要部分，使其與 **Pydantic** 及 FastAPI 其他部分相容。\n\n///\n\n## 什麼是「表單資料」 { #what-is-form-data }\n\nHTML 表單（`<form></form>`）送到伺服器的資料通常使用一種「特殊」編碼，與 JSON 不同。\n\n**FastAPI** 會從正確的位置讀取該資料，而不是當作 JSON。\n\n/// note | 技術細節\n\n表單資料在不包含檔案時，通常使用媒體型別 `application/x-www-form-urlencoded` 編碼。\n\n但當表單包含檔案時，會使用 `multipart/form-data` 編碼。若你使用 `File`，**FastAPI** 會知道要從請求本文的正確部分取得檔案。\n\n若想進一步了解這些編碼與表單欄位，請參考 [<abbr title=\"Mozilla Developer Network - Mozilla 開發者網路\">MDN</abbr> web docs 的 `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)。\n\n///\n\n/// warning\n\n你可以在一個路徑操作中宣告多個 `File` 與 `Form` 參數，但不能同時宣告預期以 JSON 接收的 `Body` 欄位，因為此請求的本文會使用 `multipart/form-data` 而不是 `application/json`。\n\n這不是 **FastAPI** 的限制，而是 HTTP 協定本身的規範。\n\n///\n\n## 可選的檔案上傳 { #optional-file-upload }\n\n可透過一般型別註解並將預設值設為 `None` 使檔案成為可選：\n\n{* ../../docs_src/request_files/tutorial001_02_an_py310.py hl[9,17] *}\n\n## `UploadFile` 搭配額外中繼資料 { #uploadfile-with-additional-metadata }\n\n你也可以在 `UploadFile` 上搭配 `File()`，例如用來設定額外的中繼資料：\n\n{* ../../docs_src/request_files/tutorial001_03_an_py310.py hl[9,15] *}\n\n## 多檔案上傳 { #multiple-file-uploads }\n\n可以同時上傳多個檔案。\n\n它們會同屬於以「表單資料」送出的同一個表單欄位。\n\n要這麼做，將型別宣告為 `bytes` 或 `UploadFile` 的 `list`：\n\n{* ../../docs_src/request_files/tutorial002_an_py310.py hl[10,15] *}\n\n你會如宣告所示，收到由 `bytes` 或 `UploadFile` 組成的 `list`。\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.responses import HTMLResponse`。\n\n**FastAPI** 為了讓你（開發者）更方便，提供與 `starlette.responses` 相同的內容作為 `fastapi.responses`。但大多數可用的回應類型其實直接來自 Starlette。\n\n///\n\n### 多檔案上傳且包含額外中繼資料 { #multiple-file-uploads-with-additional-metadata }\n\n同樣地，即使對 `UploadFile`，你也可以用 `File()` 設定額外參數：\n\n{* ../../docs_src/request_files/tutorial003_an_py310.py hl[11,18:20] *}\n\n## 小結 { #recap }\n\n使用 `File`、`bytes` 與 `UploadFile` 來宣告請求中要上傳的檔案，這些檔案會以表單資料送出。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/request-form-models.md",
    "content": "# 表單模型 { #form-models }\n\n你可以使用 **Pydantic 模型** 在 FastAPI 中宣告 **表單欄位**。\n\n/// info | 說明\n\n要使用表單，首先安裝 [`python-multipart`](https://github.com/Kludex/python-multipart)。\n\n請先建立[虛擬環境](../virtual-environments.md)、啟用後再安裝，例如：\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n/// note | 注意\n\n此功能自 FastAPI 版本 `0.113.0` 起支援。🤓\n\n///\n\n## 針對表單的 Pydantic 模型 { #pydantic-models-for-forms }\n\n你只需要宣告一個 **Pydantic 模型**，包含你要接收為 **表單欄位** 的欄位，然後將參數宣告為 `Form`：\n\n{* ../../docs_src/request_form_models/tutorial001_an_py310.py hl[9:11,15] *}\n\n**FastAPI** 會從請求中的 **表單資料** 擷取 **各欄位** 的資料，並將這些資料組成你定義的 Pydantic 模型實例。\n\n## 檢視文件 { #check-the-docs }\n\n你可以在 `/docs` 的文件 UI 中驗證：\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/request-form-models/image01.png\">\n</div>\n\n## 禁止額外的表單欄位 { #forbid-extra-form-fields }\n\n在某些特殊情況（可能不常見）下，你可能希望僅允許 Pydantic 模型中宣告的表單欄位，並禁止任何額外欄位。\n\n/// note | 注意\n\n此功能自 FastAPI 版本 `0.114.0` 起支援。🤓\n\n///\n\n你可以使用 Pydantic 的模型設定來 `forbid` 任何 `extra` 欄位：\n\n{* ../../docs_src/request_form_models/tutorial002_an_py310.py hl[12] *}\n\n如果用戶端嘗試傳送額外資料，將會收到錯誤回應。\n\n例如，用戶端若送出以下表單欄位：\n\n* `username`: `Rick`\n* `password`: `Portal Gun`\n* `extra`: `Mr. Poopybutthole`\n\n他們會收到一個錯誤回應，告知欄位 `extra` 不被允許：\n\n```json\n{\n    \"detail\": [\n        {\n            \"type\": \"extra_forbidden\",\n            \"loc\": [\"body\", \"extra\"],\n            \"msg\": \"Extra inputs are not permitted\",\n            \"input\": \"Mr. Poopybutthole\"\n        }\n    ]\n}\n```\n\n## 摘要 { #summary }\n\n你可以使用 Pydantic 模型在 FastAPI 中宣告表單欄位。😎\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/request-forms-and-files.md",
    "content": "# 請求中的表單與檔案 { #request-forms-and-files }\n\n你可以使用 `File` 與 `Form` 同時定義檔案與表單欄位。\n\n/// info\n\n要接收上傳的檔案與/或表單資料，請先安裝 [`python-multipart`](https://github.com/Kludex/python-multipart)。\n\n請先建立並啟用一個 [虛擬環境](../virtual-environments.md)，然後再安裝，例如：\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## 匯入 `File` 與 `Form` { #import-file-and-form }\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[3] *}\n\n## 定義 `File` 與 `Form` 參數 { #define-file-and-form-parameters }\n\n以與 `Body` 或 `Query` 相同的方式建立檔案與表單參數：\n\n{* ../../docs_src/request_forms_and_files/tutorial001_an_py310.py hl[10:12] *}\n\n檔案與表單欄位會作為表單資料上傳，而你將能接收到這些檔案與欄位。\n\n你也可以將部分檔案宣告為 `bytes`，另一些宣告為 `UploadFile`。\n\n/// warning\n\n你可以在一個路徑操作 (path operation) 中宣告多個 `File` 與 `Form` 參數，但不能同時再宣告預期以 JSON 接收的 `Body` 欄位，因為該請求的本文會使用 `multipart/form-data` 而非 `application/json` 進行編碼。\n\n這不是 **FastAPI** 的限制，這是 HTTP 通訊協定本身的規範。\n\n///\n\n## 小結 { #recap }\n\n當你需要在同一個請求中同時接收資料與檔案時，請搭配使用 `File` 與 `Form`。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/request-forms.md",
    "content": "# 表單資料 { #form-data }\n\n當你需要接收表單欄位而不是 JSON 時，可以使用 `Form`。\n\n/// info\n\n要使用表單，請先安裝 [`python-multipart`](https://github.com/Kludex/python-multipart)。\n\n請先建立並啟用一個[虛擬環境](../virtual-environments.md)，然後再安裝，例如：\n\n```console\n$ pip install python-multipart\n```\n\n///\n\n## 匯入 `Form` { #import-form }\n\n從 `fastapi` 匯入 `Form`：\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[3] *}\n\n## 定義 `Form` 參數 { #define-form-parameters }\n\n以與 `Body` 或 `Query` 相同的方式建立表單參數：\n\n{* ../../docs_src/request_forms/tutorial001_an_py310.py hl[9] *}\n\n例如，在 OAuth2 規範的一種用法（稱為「password flow」）中，必須以表單欄位傳送 `username` 與 `password`。\n\n該 <dfn title=\"規範\">規範</dfn> 要求欄位名稱必須正好是 `username` 和 `password`，而且必須以表單欄位傳送，而不是 JSON。\n\n使用 `Form` 時，你可以宣告與 `Body`（以及 `Query`、`Path`、`Cookie`）相同的設定，包括驗證、範例、別名（例如用 `user-name` 取代 `username`）等。\n\n/// info\n\n`Form` 是一個直接繼承自 `Body` 的類別。\n\n///\n\n/// tip\n\n要宣告表單的請求本文，你需要明確使用 `Form`，否則這些參數會被解讀為查詢參數或請求本文（JSON）參數。\n\n///\n\n## 關於「表單欄位」 { #about-form-fields }\n\nHTML 表單（`<form></form>`）向伺服器傳送資料時，通常會使用一種「特殊」的編碼方式，與 JSON 不同。\n\n**FastAPI** 會從正確的位置讀取那些資料，而不是從 JSON。\n\n/// note | 技術細節\n\n表單資料通常會使用「媒體類型」`application/x-www-form-urlencoded` 進行編碼。\n\n但當表單包含檔案時，會使用 `multipart/form-data`。你會在下一章閱讀如何處理檔案。\n\n若想進一步了解這些編碼與表單欄位，請參考 [<abbr title=\"Mozilla Developer Network - Mozilla 開發者網路\">MDN</abbr> web docs 的 `POST`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)。\n\n///\n\n/// warning\n\n你可以在一個 *路徑操作（path operation）* 中宣告多個 `Form` 參數，但不能同時再宣告期望以 JSON 接收的 `Body` 欄位，因為該請求的本文會使用 `application/x-www-form-urlencoded` 編碼，而不是 `application/json`。\n\n這不是 **FastAPI** 的限制，而是 HTTP 協定本身的規定。\n\n///\n\n## 回顧 { #recap }\n\n使用 `Form` 來宣告表單資料的輸入參數。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/response-model.md",
    "content": "# 回應模型 - 回傳型別 { #response-model-return-type }\n\n你可以在「路徑操作函式」的回傳型別上加上註解，宣告用於回應的型別。\n\n你可以像在函式「參數」的輸入資料那樣使用型別註解，你可以使用 Pydantic 模型、list、dictionary、整數、布林等純量值。\n\n{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *}\n\nFastAPI 會使用這個回傳型別來：\n\n* 驗證回傳的資料。\n    * 如果資料無效（例如缺少欄位），代表你的應用程式程式碼有問題，沒有回傳應該回傳的內容，FastAPI 會回傳伺服器錯誤，而不是回傳不正確的資料。如此你和你的用戶端都能確定會收到預期的資料與資料結構。\n* 在 OpenAPI 的「路徑操作」中為回應新增 JSON Schema。\n    * 這會被自動文件使用。\n    * 也會被自動用戶端程式碼產生工具使用。\n* 使用 Pydantic 將回傳資料**序列化**為 JSON，而 Pydantic 是用 **Rust** 撰寫的，因此會 **更快很多**。\n\n但更重要的是：\n\n* 它會將輸出資料限制並過濾為回傳型別中定義的內容。\n    * 這對安全性特別重要，下面會再看到更多細節。\n\n## `response_model` 參數 { #response-model-parameter }\n\n有些情況下，你需要或想要回傳的資料與你宣告的型別不完全相同。\n\n例如，你可能想要回傳一個 dictionary 或資料庫物件，但把回應宣告為一個 Pydantic 模型。這樣 Pydantic 模型就會替你回傳的物件（例如 dictionary 或資料庫物件）處理所有的資料文件、驗證等。\n\n如果你加了回傳型別註解，工具與編輯器會（正確地）抱怨你的函式回傳的型別（例如 dict）與你宣告的（例如 Pydantic 模型）不同。\n\n在這些情況下，你可以使用「路徑操作裝飾器」參數 `response_model`，而不是函式的回傳型別。\n\n你可以在任何「路徑操作」上使用 `response_model` 參數：\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* 等等。\n\n{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *}\n\n/// note | 注意\n\n注意 `response_model` 是「裝飾器」方法（`get`、`post` 等）的參數。不是你的「路徑操作函式」的參數（像其他參數與請求主體那樣）。\n\n///\n\n`response_model` 接受的型別與你在 Pydantic 模型欄位中宣告的相同，所以它可以是一個 Pydantic 模型，也可以是例如由 Pydantic 模型組成的 `list`，像是 `List[Item]`。\n\nFastAPI 會使用這個 `response_model` 來做所有的資料文件、驗證等，並且也會將輸出資料轉換與過濾為其型別宣告。\n\n/// tip | 提示\n\n如果你在編輯器、mypy 等中有嚴格型別檢查，你可以把函式回傳型別宣告為 `Any`。\n\n這樣你是在告訴編輯器你是刻意回傳任意型別。但 FastAPI 仍會用 `response_model` 做資料文件、驗證、過濾等。\n\n///\n\n### `response_model` 優先權 { #response-model-priority }\n\n如果同時宣告了回傳型別與 `response_model`，`response_model` 會有優先權並由 FastAPI 使用。\n\n如此一來，即便你回傳的實際型別與回應模型不同，你仍可在函式上加上正確的型別註解，供編輯器與如 mypy 的工具使用。同時仍由 FastAPI 使用 `response_model` 做資料驗證、文件化等。\n\n你也可以使用 `response_model=None` 來停用該「路徑操作」的回應模型產生；當你為不是有效 Pydantic 欄位的東西加上型別註解時，可能需要這麼做，你會在下方某節看到範例。\n\n## 回傳與輸入相同的資料 { #return-the-same-input-data }\n\n這裡我們宣告一個 `UserIn` 模型，其中會包含明文密碼：\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *}\n\n/// info | 說明\n\n要使用 `EmailStr`，請先安裝 [`email-validator`](https://github.com/JoshData/python-email-validator)。\n\n請先建立一個[虛擬環境](../virtual-environments.md)、啟用它，然後安裝，例如：\n\n```console\n$ pip install email-validator\n```\n\n或：\n\n```console\n$ pip install \"pydantic[email]\"\n```\n\n///\n\n而我們使用這個模型同時宣告輸入與輸出：\n\n{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *}\n\n現在，當瀏覽器建立一個帶有密碼的使用者時，API 會在回應中回傳相同的密碼。\n\n在這個例子中可能不是問題，因為是同一個使用者送出該密碼。\n\n但如果我們對其他「路徑操作」使用相同的模型，我們可能會把使用者密碼送給所有用戶端。\n\n/// danger | 警告\n\n除非你非常清楚所有影響並確定自己在做什麼，否則永遠不要儲存使用者的明文密碼，也不要像這樣在回應中傳送。\n\n///\n\n## 新增一個輸出模型 { #add-an-output-model }\n\n我們可以改為建立一個包含明文密碼的輸入模型，以及一個不含密碼的輸出模型：\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *}\n\n在這裡，雖然「路徑操作函式」回傳的是同一個包含密碼的輸入使用者：\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *}\n\n...我們把 `response_model` 宣告為不包含密碼的 `UserOut` 模型：\n\n{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *}\n\n因此，FastAPI 會負責（透過 Pydantic）過濾掉輸出模型中未宣告的所有資料。\n\n### `response_model` 或回傳型別 { #response-model-or-return-type }\n\n在這種情況下，因為兩個模型不同，如果我們把函式回傳型別註解為 `UserOut`，編輯器和工具會抱怨我們回傳了無效的型別，因為它們是不同的類別。\n\n這就是為什麼在這個例子中我們必須在 `response_model` 參數中宣告它。\n\n...但繼續往下讀看看如何克服這個問題。\n\n## 回傳型別與資料過濾 { #return-type-and-data-filtering }\n\n讓我們延續前一個範例。我們想要用一種型別來註解函式，但實際上希望能夠從函式回傳包含更多資料的內容。\n\n我們希望 FastAPI 仍然用回應模型來過濾資料。這樣即使函式回傳更多資料，回應中也只會包含回應模型中宣告的欄位。\n\n在前一個例子中，因為類別不同，我們必須使用 `response_model` 參數。但這也代表我們失去了編輯器與工具對函式回傳型別的檢查支援。\n\n不過在大多數需要這樣做的情況下，我們只是想要像這個例子一樣，讓模型過濾/移除部分資料。\n\n在這些情況下，我們可以利用類別與繼承，搭配函式的型別註解，取得更好的編輯器與工具支援，同時仍能讓 FastAPI 做資料過濾。\n\n{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *}\n\n這樣我們能得到工具支援，對於編輯器與 mypy 來說，這段程式碼在型別上是正確的，同時我們也能得到 FastAPI 的資料過濾。\n\n這是怎麼運作的？來看一下。🤓\n\n### 型別註解與工具支援 { #type-annotations-and-tooling }\n\n先看看編輯器、mypy 與其他工具會怎麼看這件事。\n\n`BaseUser` 有基礎欄位。然後 `UserIn` 繼承自 `BaseUser` 並新增 `password` 欄位，因此它會包含兩個模型的所有欄位。\n\n我們把函式回傳型別註解為 `BaseUser`，但實際上回傳的是 `UserIn` 實例。\n\n編輯器、mypy 與其他工具不會抱怨，因為就型別學而言，`UserIn` 是 `BaseUser` 的子類別，這代表當預期任何 `BaseUser` 時，`UserIn` 是一個有效的型別。\n\n### FastAPI 的資料過濾 { #fastapi-data-filtering }\n\n對 FastAPI 而言，它會查看回傳型別，並確保你回傳的內容只包含該型別中宣告的欄位。\n\nFastAPI 在內部會搭配 Pydantic 做一些事情，來確保不會把類別繼承的那些規則直接用在回傳資料的過濾上，否則你可能會回傳比預期更多的資料。\n\n如此，你就能同時擁有兩種好處：具備工具支援的型別註解，以及資料過濾。\n\n## 在文件中查看 { #see-it-in-the-docs }\n\n在自動文件中，你可以看到輸入模型與輸出模型各自都有自己的 JSON Schema：\n\n<img src=\"/img/tutorial/response-model/image01.png\">\n\n而且兩個模型都會用在互動式 API 文件中：\n\n<img src=\"/img/tutorial/response-model/image02.png\">\n\n## 其他回傳型別註解 { #other-return-type-annotations }\n\n有時你回傳的東西不是有效的 Pydantic 欄位，你仍會在函式上加上註解，只為了獲得工具（編輯器、mypy 等）提供的支援。\n\n### 直接回傳 Response { #return-a-response-directly }\n\n最常見的情況是[直接回傳 Response（在進階文件中稍後會解釋）](../advanced/response-directly.md)。\n\n{* ../../docs_src/response_model/tutorial003_02_py310.py hl[8,10:11] *}\n\n這個簡單情境會由 FastAPI 自動處理，因為回傳型別註解是 `Response` 類別（或其子類別）。\n\n而工具也會滿意，因為 `RedirectResponse` 與 `JSONResponse` 都是 `Response` 的子類別，所以型別註解是正確的。\n\n### 註解為某個 Response 的子類別 { #annotate-a-response-subclass }\n\n你也可以在型別註解中使用 `Response` 的子類別：\n\n{* ../../docs_src/response_model/tutorial003_03_py310.py hl[8:9] *}\n\n這同樣可行，因為 `RedirectResponse` 是 `Response` 的子類別，而 FastAPI 會自動處理這種簡單情況。\n\n### 無效的回傳型別註解 { #invalid-return-type-annotations }\n\n但當你回傳其他任意物件（例如資料庫物件），它不是有效的 Pydantic 型別，並且你在函式上也這樣註解時，FastAPI 會嘗試從該型別註解建立一個 Pydantic 回應模型，因而失敗。\n\n如果你有像是多種型別的<dfn title=\"在多種型別之間的聯集表示「其中任一種型別」\">聯集</dfn>，其中一個或多個不是有效的 Pydantic 型別，也會發生相同的事情，例如這個就會失敗 💥：\n\n{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *}\n\n...這會失敗，因為該型別註解不是 Pydantic 型別，且它也不只是一個單一的 `Response` 類別或其子類別，而是 `Response` 與 `dict` 的聯集（兩者任一）。\n\n### 停用回應模型 { #disable-response-model }\n\n延續上面的例子，你可能不想要 FastAPI 執行預設的資料驗證、文件化、過濾等動作。\n\n但你可能仍想在函式上保留回傳型別註解，以獲得編輯器與型別檢查工具（例如 mypy）的支援。\n\n這種情況下，你可以設定 `response_model=None` 來停用回應模型的產生：\n\n{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *}\n\n這會讓 FastAPI 略過回應模型的產生，如此你就能使用任何你需要的回傳型別註解，而不會影響你的 FastAPI 應用程式。🤓\n\n## 回應模型編碼參數 { #response-model-encoding-parameters }\n\n你的回應模型可能有預設值，例如：\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *}\n\n* `description: Union[str, None] = None`（或在 Python 3.10 中的 `str | None = None`）預設為 `None`。\n* `tax: float = 10.5` 預設為 `10.5`。\n* `tags: List[str] = []` 預設為空的 list：`[]`。\n\n但如果這些值其實沒有被儲存，你可能想要在結果中省略它們。\n\n例如，如果你在 NoSQL 資料庫中有包含許多選擇性屬性的模型，但你不想傳送充滿預設值的冗長 JSON 回應。\n\n### 使用 `response_model_exclude_unset` 參數 { #use-the-response-model-exclude-unset-parameter }\n\n你可以在「路徑操作裝飾器」上設定 `response_model_exclude_unset=True`：\n\n{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *}\n\n如此這些預設值就不會被包含在回應中，只有實際被設定的值才會包含。\n\n因此，如果你對該「路徑操作」發送針對 ID 為 `foo` 的項目的請求，回應（不包含預設值）會是：\n\n```JSON\n{\n    \"name\": \"Foo\",\n    \"price\": 50.2\n}\n```\n\n/// info | 說明\n\n你也可以使用：\n\n* `response_model_exclude_defaults=True`\n* `response_model_exclude_none=True`\n\n如 [Pydantic 文件](https://docs.pydantic.dev/1.10/usage/exporting_models/#modeldict)中對 `exclude_defaults` 與 `exclude_none` 的說明。\n\n///\n\n#### 對於有預設值欄位也有實際值的資料 { #data-with-values-for-fields-with-defaults }\n\n但如果你的資料在模型中對於有預設值的欄位也有實際值，例如 ID 為 `bar` 的項目：\n\n```Python hl_lines=\"3  5\"\n{\n    \"name\": \"Bar\",\n    \"description\": \"The bartenders\",\n    \"price\": 62,\n    \"tax\": 20.2\n}\n```\n\n它們會被包含在回應中。\n\n#### 與預設值相同的資料 { #data-with-the-same-values-as-the-defaults }\n\n如果資料的值與預設值相同，例如 ID 為 `baz` 的項目：\n\n```Python hl_lines=\"3  5-6\"\n{\n    \"name\": \"Baz\",\n    \"description\": None,\n    \"price\": 50.2,\n    \"tax\": 10.5,\n    \"tags\": []\n}\n```\n\nFastAPI 足夠聰明（其實是 Pydantic 足夠聰明）去判斷，儘管 `description`、`tax` 與 `tags` 的值與預設值相同，但它們是被明確設定的（而不是取自預設值）。\n\n因此，它們會被包含在 JSON 回應中。\n\n/// tip | 提示\n\n注意預設值可以是任何東西，不只有 `None`。\n\n它們可以是一個 list（`[]`）、一個 `float` 的 `10.5`，等等。\n\n///\n\n### `response_model_include` 與 `response_model_exclude` { #response-model-include-and-response-model-exclude }\n\n你也可以使用「路徑操作裝飾器」參數 `response_model_include` 與 `response_model_exclude`。\n\n它們接受一個由屬性名稱字串所組成的 `set`，分別用來包含（省略其他）或排除（包含其他）屬性。\n\n如果你只有一個 Pydantic 模型並且想從輸出移除部分資料，這可以作為一個快速捷徑。\n\n/// tip | 提示\n\n但仍建議使用上面提到的作法，使用多個類別，而不是這些參數。\n\n因為在你的應用程式 OpenAPI（與文件）中所產生的 JSON Schema 仍會是完整模型的，即便你使用 `response_model_include` 或 `response_model_exclude` 省略了一些屬性。\n\n`response_model_by_alias` 也有類似的情況。\n\n///\n\n{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *}\n\n/// tip | 提示\n\n語法 `{\"name\", \"description\"}` 會建立一個包含這兩個值的 `set`。\n\n它等同於 `set([\"name\", \"description\"])`。\n\n///\n\n#### 使用 `list` 來代替 `set` { #using-lists-instead-of-sets }\n\n如果你忘了使用 `set` 而用了 `list` 或 `tuple`，FastAPI 仍會把它轉換成 `set`，並能正確運作：\n\n{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *}\n\n## 重點回顧 { #recap }\n\n使用「路徑操作裝飾器」的 `response_model` 參數來定義回應模型，特別是為了確保私有資料被過濾掉。\n\n使用 `response_model_exclude_unset` 僅回傳被明確設定的值。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/response-status-code.md",
    "content": "# 回應狀態碼 { #response-status-code }\n\n就像你可以指定回應模型一樣，你也可以在任一個「路徑操作（path operation）」的參數 `status_code` 中宣告回應所使用的 HTTP 狀態碼：\n\n* `@app.get()`\n* `@app.post()`\n* `@app.put()`\n* `@app.delete()`\n* 等等\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n/// note | 注意\n\n請注意，`status_code` 是「裝飾器（decorator）」方法（`get`、`post` 等等）的參數，而不是你的「路徑操作函式」的參數，就像所有的參數與 body 一樣。\n\n///\n\n參數 `status_code` 接受一個數字作為 HTTP 狀態碼。\n\n/// info | 資訊\n\n`status_code` 也可以接收一個 `IntEnum`，例如 Python 的 [`http.HTTPStatus`](https://docs.python.org/3/library/http.html#http.HTTPStatus)。\n\n///\n\n它會：\n\n* 在回應中傳回該狀態碼。\n* 在 OpenAPI 結構中如此記錄（因此也會反映在使用者介面中）：\n\n<img src=\"/img/tutorial/response-status-code/image01.png\">\n\n/// note | 注意\n\n有些回應碼（見下一節）表示回應不包含本文（body）。\n\nFastAPI 知道這點，並會產生聲明「無回應本文」的 OpenAPI 文件。\n\n///\n\n## 關於 HTTP 狀態碼 { #about-http-status-codes }\n\n/// note | 注意\n\n如果你已經知道什麼是 HTTP 狀態碼，可以直接跳到下一節。\n\n///\n\n在 HTTP 中，你會在回應的一部分傳回 3 位數的狀態碼。\n\n這些狀態碼有對應的名稱以便辨識，但重點是數字本身。\n\n簡而言之：\n\n* `100 - 199` 表示「資訊」。你很少會直接使用它們。這些狀態碼的回應不可包含本文。\n* **`200 - 299`** 表示「成功」。這是你最常使用的一組。\n    * `200` 是預設狀態碼，表示一切「OK」。\n    * 另一個例子是 `201`，代表「已建立」。常用於在資料庫中建立新紀錄之後。\n    * 一個特殊情況是 `204`，代表「無內容」。當沒有內容要回傳給用戶端時使用，因此回應不得有本文。\n* **`300 - 399`** 表示「重新導向」。這些狀態碼的回應可能有或沒有本文，唯獨 `304`（「未修改」）必須沒有本文。\n* **`400 - 499`** 表示「用戶端錯誤」。這大概是你第二常用的一組。\n    * 例如 `404`，代表「找不到」。\n    * 對於一般性的用戶端錯誤，你可以使用 `400`。\n* `500 - 599` 表示伺服器錯誤。你幾乎不會直接使用它們。當你的應用程式或伺服器某處出錯時，會自動回傳其中一個狀態碼。\n\n/// tip | 提示\n\n想深入瞭解各狀態碼與其用途，請參考 [<abbr title=\"Mozilla Developer Network - Mozilla 開發者網路\">MDN</abbr> 關於 HTTP 狀態碼的文件](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)。\n\n///\n\n## 快速記住名稱 { #shortcut-to-remember-the-names }\n\n再看一次前面的範例：\n\n{* ../../docs_src/response_status_code/tutorial001_py310.py hl[6] *}\n\n`201` 是「已建立（Created）」的狀態碼。\n\n但你不需要背下每個代碼代表什麼。\n\n你可以使用 `fastapi.status` 提供的便利變數。\n\n{* ../../docs_src/response_status_code/tutorial002_py310.py hl[1,6] *}\n\n它們只是方便用的常數，值與數字相同，但這樣你可以用編輯器的自動完成來找到它們：\n\n<img src=\"/img/tutorial/response-status-code/image02.png\">\n\n/// note | 技術細節\n\n你也可以使用 `from starlette import status`。\n\n**FastAPI** 將同一個 `starlette.status` 以 `fastapi.status` 形式提供，純粹是為了讓你（開發者）方便。但它直接來自 Starlette。\n\n///\n\n## 變更預設值 { #changing-the-default }\n\n稍後在 [進階使用者指南](../advanced/response-change-status-code.md) 中，你會看到如何回傳一個不同於此處所宣告預設值的狀態碼。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/schema-extra-example.md",
    "content": "# 宣告請求範例資料 { #declare-request-example-data }\n\n你可以宣告你的應用程式可接收資料的 examples。\n\n以下有數種方式可達成。\n\n## Pydantic 模型中的額外 JSON Schema 資料 { #extra-json-schema-data-in-pydantic-models }\n\n你可以為 Pydantic 模型宣告 `examples`，它們會加入到產生出的 JSON Schema 中。\n\n{* ../../docs_src/schema_extra_example/tutorial001_py310.py hl[13:24] *}\n\n這些額外資訊會原封不動加入該模型輸出的 JSON Schema，並且會用在 API 文件裡。\n\n你可以使用屬性 `model_config`（接收一個 `dict`），詳見 [Pydantic 文件：Configuration](https://docs.pydantic.dev/latest/api/config/)。\n\n你可以將 `\"json_schema_extra\"` 設為一個 `dict`，其中包含你想在產生的 JSON Schema 中出現的任何額外資料，包括 `examples`。\n\n/// tip\n\n你可以用相同技巧擴充 JSON Schema，加入你自己的自訂額外資訊。\n\n例如，你可以用它為前端使用者介面新增中繼資料等。\n\n///\n\n/// info\n\nOpenAPI 3.1.0（自 FastAPI 0.99.0 起使用）新增了對 `examples` 的支援，這是 **JSON Schema** 標準的一部分。\n\n在那之前，只支援使用單一範例的關鍵字 `example`。OpenAPI 3.1.0 仍然支援 `example`，但它已被棄用，且不是 JSON Schema 標準的一部分。因此建議你將 `example` 遷移為 `examples`。🤓\n\n你可以在本頁結尾閱讀更多。\n\n///\n\n## `Field` 其他參數 { #field-additional-arguments }\n\n在 Pydantic 模型中使用 `Field()` 時，你也可以宣告額外的 `examples`：\n\n{* ../../docs_src/schema_extra_example/tutorial002_py310.py hl[2,8:11] *}\n\n## JSON Schema 的 `examples` - OpenAPI { #examples-in-json-schema-openapi }\n\n當使用下列任一項：\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\n你也可以宣告一組 `examples`，包含會加入到 **OpenAPI** 中它們各自 **JSON Schemas** 的額外資訊。\n\n### `Body` 搭配 `examples` { #body-with-examples }\n\n這裡我們傳入 `examples`，其中包含 `Body()` 預期資料的一個範例：\n\n{* ../../docs_src/schema_extra_example/tutorial003_an_py310.py hl[22:29] *}\n\n### 文件 UI 中的範例 { #example-in-the-docs-ui }\n\n使用以上任一方法，在 `/docs` 中看起來會像這樣：\n\n<img src=\"/img/tutorial/body-fields/image01.png\">\n\n### `Body` 搭配多個 `examples` { #body-with-multiple-examples }\n\n當然，你也可以傳入多個 `examples`：\n\n{* ../../docs_src/schema_extra_example/tutorial004_an_py310.py hl[23:38] *}\n\n這麼做時，這些範例會成為該 body 資料內部 **JSON Schema** 的一部分。\n\n然而，<dfn title=\"2023-08-26\">撰寫本文時</dfn>，負責呈現文件 UI 的工具 Swagger UI 並不支援在 **JSON Schema** 中顯示多個範例。不過請繼續往下閱讀以取得變通方式。\n\n### OpenAPI 特定的 `examples` { #openapi-specific-examples }\n\n在 **JSON Schema** 支援 `examples` 之前，OpenAPI 就已支援另一個同名的欄位 `examples`。\n\n這個「OpenAPI 特定」的 `examples` 位於 OpenAPI 規範的另一個區塊：在每個「路徑操作」的詳細資訊中，而不是在各個 JSON Schema 內。\n\n而 Swagger UI 早已支援這個欄位，因此你可以用它在文件 UI 中顯示不同的範例。\n\n這個 OpenAPI 特定欄位 `examples` 的結構是一個包含「多個範例」的 `dict`（而非 `list`），每個範例都可包含會一併加入到 **OpenAPI** 的額外資訊。\n\n它不會出現在 OpenAPI 所含的各個 JSON Schema 內，而是直接放在對應的「路徑操作」上。\n\n### 使用 `openapi_examples` 參數 { #using-the-openapi-examples-parameter }\n\n你可以在 FastAPI 中透過參數 `openapi_examples` 為下列項目宣告 OpenAPI 特定的 `examples`：\n\n* `Path()`\n* `Query()`\n* `Header()`\n* `Cookie()`\n* `Body()`\n* `Form()`\n* `File()`\n\n該 `dict` 的鍵用來識別各個範例，而每個值則是另一個 `dict`。\n\n在 `examples` 中，每個範例的 `dict` 可以包含：\n\n* `summary`：範例的簡短描述。\n* `description`：較長的描述，可包含 Markdown 文字。\n* `value`：實際顯示的範例，例如一個 `dict`。\n* `externalValue`：`value` 的替代方案，為指向範例的 URL。儘管這可能不如 `value` 被工具廣泛支援。\n\n你可以這樣使用：\n\n{* ../../docs_src/schema_extra_example/tutorial005_an_py310.py hl[23:49] *}\n\n### 文件 UI 中的 OpenAPI 範例 { #openapi-examples-in-the-docs-ui }\n\n當在 `Body()` 加上 `openapi_examples`，`/docs` 會顯示為：\n\n<img src=\"/img/tutorial/body-fields/image02.png\">\n\n## 技術細節 { #technical-details }\n\n/// tip\n\n如果你已經在使用 **FastAPI** **0.99.0 或以上**的版本，大概可以略過這些細節。\n\n這些內容比較與舊版（在 OpenAPI 3.1.0 可用之前）相關。\n\n你可以把這段當作一小堂 OpenAPI 與 JSON Schema 的歷史課。🤓\n\n///\n\n/// warning\n\n以下是關於 **JSON Schema** 與 **OpenAPI** 標準的技術細節。\n\n如果上面的做法對你已經足夠可用，就不需要這些細節，儘管直接跳過。\n\n///\n\n在 OpenAPI 3.1.0 之前，OpenAPI 使用的是較舊且經過修改的 **JSON Schema** 版本。\n\n當時 JSON Schema 沒有 `examples`，因此 OpenAPI 在它自訂修改的版本中新增了自己的 `example` 欄位。\n\nOpenAPI 也在規範的其他部分新增了 `example` 與 `examples` 欄位：\n\n* [`Parameter Object`（規範）](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object)，對應到 FastAPI 的：\n    * `Path()`\n    * `Query()`\n    * `Header()`\n    * `Cookie()`\n* [`Request Body Object` 中的 `content` 欄位裡的 `Media Type Object`（規範）](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object)，對應到 FastAPI 的：\n    * `Body()`\n    * `File()`\n    * `Form()`\n\n/// info\n\n這個舊的、OpenAPI 特定的 `examples` 參數，從 FastAPI `0.103.0` 起改名為 `openapi_examples`。\n\n///\n\n### JSON Schema 的 `examples` 欄位 { #json-schemas-examples-field }\n\n後來 JSON Schema 在新版本規範中新增了 [`examples`](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5) 欄位。\n\n接著新的 OpenAPI 3.1.0 以最新版本（JSON Schema 2020-12）為基礎，該版本就包含這個新的 `examples` 欄位。\n\n現在這個新的 `examples` 欄位優先於舊的單一（且客製）`example` 欄位，後者已被棄用。\n\nJSON Schema 中新的 `examples` 欄位「就是一個 `list`」的範例集合，而不是像 OpenAPI 其他地方（如上所述）那樣附帶額外中繼資料的 `dict`。\n\n/// info\n\n即使 OpenAPI 3.1.0 已發佈並與 JSON Schema 有更簡潔的整合，一段時間內提供自動文件的 Swagger UI 並不支援 OpenAPI 3.1.0（自 5.0.0 版起支援 🎉）。\n\n因此，FastAPI 0.99.0 之前的版本仍使用 3.1.0 以下的 OpenAPI 版本。\n\n///\n\n### Pydantic 與 FastAPI 的 `examples` { #pydantic-and-fastapi-examples }\n\n當你在 Pydantic 模型中加入 `examples`，不論是用 `schema_extra` 或 `Field(examples=[\"something\"])`，該範例都會被加入該 Pydantic 模型的 **JSON Schema**。\n\n而該 Pydantic 模型的 **JSON Schema** 會被包含到你的 API 的 **OpenAPI** 中，接著用於文件 UI。\n\n在 FastAPI 0.99.0 之前的版本（0.99.0 起使用較新的 OpenAPI 3.1.0）中，當你對其他工具（`Query()`、`Body()` 等）使用 `example` 或 `examples` 時，這些範例不會被加入描述該資料的 JSON Schema（甚至不會加入到 OpenAPI 自己版本的 JSON Schema 中），而是直接加入到 OpenAPI 中的「路徑操作」宣告（在 OpenAPI 使用 JSON Schema 的那些部分之外）。\n\n但現在 FastAPI 0.99.0 以上使用的 OpenAPI 3.1.0 搭配 JSON Schema 2020-12，以及 Swagger UI 5.0.0 以上版本，整體更加一致，範例會包含在 JSON Schema 中。\n\n### Swagger UI 與 OpenAPI 特定的 `examples` { #swagger-ui-and-openapi-specific-examples }\n\n由於在（2023-08-26 時）Swagger UI 不支援多個 JSON Schema 範例，使用者無法在文件中顯示多個範例。\n\n為了解決此問題，FastAPI `0.103.0` 透過新參數 `openapi_examples` **新增支援** 宣告舊的「OpenAPI 特定」`examples` 欄位。🤓\n\n### 總結 { #summary }\n\n我以前常說我不太喜歡歷史……結果現在在這裡講「科技史」。😅\n\n簡而言之，**升級到 FastAPI 0.99.0 或以上**，事情會更**簡單、一致又直覺**，而且你不需要了解這些歷史細節。😎\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/security/first-steps.md",
    "content": "# 安全性 - 入門 { #security-first-steps }\n\n想像你有一個部署在某個網域的後端 API。\n\n還有一個前端在另一個網域，或同一網域的不同路徑（或是行動應用程式）。\n\n你希望前端能用使用者名稱與密碼向後端進行身分驗證。\n\n我們可以用 OAuth2 搭配 FastAPI 來實作。\n\n但不必通讀整份冗長規格只為了找出你需要的幾個重點。\n\n就用 FastAPI 提供的工具處理安全性。\n\n## 看起來如何 { #how-it-looks }\n\n先直接跑範例看效果，再回頭理解其原理。\n\n## 建立 `main.py` { #create-main-py }\n\n將範例複製到檔案 `main.py`：\n\n{* ../../docs_src/security/tutorial001_an_py310.py *}\n\n## 執行 { #run-it }\n\n/// info\n\n當你使用 `pip install \"fastapi[standard]\"` 指令安裝時，[`python-multipart`](https://github.com/Kludex/python-multipart) 套件會隨 FastAPI 自動安裝。\n\n不過若只執行 `pip install fastapi`，預設不會包含 `python-multipart`。\n\n若要手動安裝，請先建立並啟用一個[虛擬環境](../../virtual-environments.md)，接著執行：\n\n```console\n$ pip install python-multipart\n```\n\n因為 OAuth2 會以「form data」傳送 `username` 與 `password`。\n\n///\n\n用以下指令執行範例：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n## 檢查 { #check-it }\n\n開啟互動式文件：[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n你會看到類似這樣：\n\n<img src=\"/img/tutorial/security/image01.png\">\n\n/// check | Authorize 按鈕！\n\n你會看到一個新的「Authorize」按鈕。\n\n而你的「路徑操作」右上角也會出現一個小鎖頭可以點擊。\n\n///\n\n點擊後會跳出一個小視窗，讓你輸入 `username` 與 `password`（以及其他可選欄位）：\n\n<img src=\"/img/tutorial/security/image02.png\">\n\n/// note | 注意\n\n不管你在表單輸入什麼，現在都還不會成功；等等我們會把它完成。\n\n///\n\n這當然不是給最終使用者用的前端，但它是用來互動式文件化整個 API 的極佳自動化工具。\n\n前端團隊（也可能就是你）可以使用它。\n\n第三方應用或系統也能使用它。\n\n你也能用它來除錯、檢查與測試同一個應用。\n\n## `password` 流程 { #the-password-flow }\n\n現在回頭理解剛剛那些是什麼。\n\n在 OAuth2 中，`password` 是處理安全與身分驗證的其中一種「流程」（flow）。\n\nOAuth2 的設計讓後端或 API 可以獨立於執行使用者驗證的伺服器。\n\n但在這個例子中，同一個 FastAPI 應用會同時處理 API 與驗證。\n\n簡化來看流程如下：\n\n- 使用者在前端輸入 `username` 與 `password`，按下 `Enter`。\n- 前端（在使用者的瀏覽器中執行）把 `username` 與 `password` 傳到我們 API 的特定 URL（在程式中宣告為 `tokenUrl=\"token\"`）。\n- API 檢查 `username` 與 `password`，並回傳一個「token（權杖）」（我們還沒實作這部分）。\n    - 「token（權杖）」就是一段字串，之後可用來識別並驗證此使用者。\n    - 通常 token 會設定一段時間後失效。\n        - 因此使用者之後需要重新登入。\n        - 若 token 被竊取，風險也較低；它不像永遠有效的萬用鑰匙（多數情況下）。\n- 前端會暫存這個 token。\n- 使用者在前端點擊前往其他頁面/區段。\n- 前端需要再向 API 取得資料。\n    - 但該端點需要驗證。\n    - 因此為了向 API 驗證，請求會帶上一個 `Authorization` 標頭，值為 `Bearer ` 加上 token。\n    - 例如 token 是 `foobar`，則 `Authorization` 標頭內容為：`Bearer foobar`。\n\n## FastAPI 的 `OAuth2PasswordBearer` { #fastapis-oauth2passwordbearer }\n\nFastAPI 提供多層抽象的工具來實作這些安全機制。\n\n本例將使用 OAuth2 的 Password 流程，並以 Bearer token 進行驗證；我們會用 `OAuth2PasswordBearer` 類別來完成。\n\n/// info\n\n「Bearer」token 不是唯一選項。\n\n但對本例最合適。\n\n通常對多數情境也足夠，除非你是 OAuth2 專家並確信有更適合你的選項。\n\n在那種情況下，FastAPI 也提供相應工具讓你自行組合。\n\n///\n\n當我們建立 `OAuth2PasswordBearer` 類別的實例時，會傳入 `tokenUrl` 參數。這個參數包含了客戶端（在使用者瀏覽器中執行的前端）用來送出 `username` 與 `password` 以取得 token 的 URL。\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[8] *}\n\n/// tip\n\n這裡的 `tokenUrl=\"token\"` 指的是尚未建立的相對 URL `token`。因為是相對 URL，所以等同於 `./token`。\n\n由於使用了相對 URL，若你的 API 位於 `https://example.com/`，那它會指向 `https://example.com/token`；但若你的 API 位於 `https://example.com/api/v1/`，那它會指向 `https://example.com/api/v1/token`。\n\n使用相對 URL 很重要，能確保你的應用在像是[在 Proxy 後方](../../advanced/behind-a-proxy.md)這類進階情境中仍能正常運作。\n\n///\n\n這個參數不會建立該端點／「路徑操作」，而是宣告 `/token` 將是客戶端用來取得 token 的 URL。這些資訊會出現在 OpenAPI，並被互動式 API 文件系統使用。\n\n我們很快也會建立實際的路徑操作。\n\n/// info\n\n如果你是非常嚴格的「Pythonista」，可能不喜歡參數名稱用 `tokenUrl` 而不是 `token_url`。\n\n那是因為它沿用了 OpenAPI 規格中的名稱。如此一來，若你要深入查閱這些安全方案，便能直接複製貼上去搜尋更多資訊。\n\n///\n\n變數 `oauth2_scheme` 是 `OAuth2PasswordBearer` 的實例，但同時它也是「可呼叫的」（callable）。\n\n它可以這樣被呼叫：\n\n```Python\noauth2_scheme(some, parameters)\n```\n\n因此它可以配合 `Depends` 使用。\n\n### 如何使用 { #use-it }\n\n現在你可以在相依性中傳入 `oauth2_scheme` 與 `Depends` 搭配。\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\n此相依性會提供一個 `str`，指派給「路徑操作函式」的參數 `token`。\n\nFastAPI 會知道可以使用這個相依性，在 OpenAPI（以及自動產生的 API 文件）中定義一個「安全性方案」。\n\n/// info | 技術細節\n\nFastAPI 之所以知道可以用（相依性中宣告的）`OAuth2PasswordBearer` 類別，在 OpenAPI 中定義安全性方案，是因為它繼承自 `fastapi.security.oauth2.OAuth2`，而後者又繼承自 `fastapi.security.base.SecurityBase`。\n\n所有能與 OpenAPI（以及自動 API 文件）整合的安全工具都繼承自 `SecurityBase`，FastAPI 才能知道如何把它們整合進 OpenAPI。\n\n///\n\n## 它做了什麼 { #what-it-does }\n\n它會從請求中尋找 `Authorization` 標頭，檢查其值是否為 `Bearer ` 加上一段 token，並將該 token 以 `str` 回傳。\n\n若未找到 `Authorization` 標頭，或其值不是 `Bearer ` token，則會直接回傳 401（`UNAUTHORIZED`）錯誤。\n\n你不必再自行檢查 token 是否存在；你可以確信只要你的函式被執行，該 token 參數就一定會是 `str`。\n\n你可以在互動式文件中試試看：\n\n<img src=\"/img/tutorial/security/image03.png\">\n\n我們還沒驗證 token 是否有效，但這已是個開始。\n\n## 小結 { #recap }\n\n只需多寫 3、4 行，就能有一個基本的安全機制。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/security/get-current-user.md",
    "content": "# 取得目前使用者 { #get-current-user }\n\n在前一章，基於依賴注入系統的安全機制會把一個 `token`（作為 `str`）提供給*路徑操作函式*：\n\n{* ../../docs_src/security/tutorial001_an_py310.py hl[12] *}\n\n但這還不太有用。\n\n讓它改為回傳目前使用者吧。\n\n## 建立使用者模型 { #create-a-user-model }\n\n先建立一個 Pydantic 的使用者模型。\n\n就像用 Pydantic 宣告請求體一樣，我們也可以在其他地方使用它：\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[5,12:6] *}\n\n## 建立 `get_current_user` 依賴 { #create-a-get-current-user-dependency }\n\n讓我們建立一個依賴 `get_current_user`。\n\n記得依賴可以有子依賴嗎？\n\n`get_current_user` 會依賴我們先前建立的相同 `oauth2_scheme`。\n\n如同先前在*路徑操作*中直接做的一樣，新的依賴 `get_current_user` 會從子依賴 `oauth2_scheme` 接收一個作為 `str` 的 `token`：\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[25] *}\n\n## 取得使用者 { #get-the-user }\n\n`get_current_user` 會使用我們建立的（假的）工具函式，它接收一個作為 `str` 的 token，並回傳我們的 Pydantic `User` 模型：\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[19:22,26:27] *}\n\n## 注入目前使用者 { #inject-the-current-user }\n\n現在我們可以在*路徑操作*中用相同的 `Depends` 來使用 `get_current_user`：\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[31] *}\n\n注意我們把 `current_user` 的型別宣告為 Pydantic 的 `User` 模型。\n\n這能在函式內提供自動補全與型別檢查的協助。\n\n/// tip | 提示\n\n你可能記得，請求體也會用 Pydantic 模型宣告。\n\n這裡因為你使用了 `Depends`，**FastAPI** 不會混淆。\n\n///\n\n/// check | 檢查\n\n這個依賴系統的設計讓我們可以有不同的依賴（不同的 \"dependables\"），都回傳 `User` 模型。\n\n我們不受限於只能有一個能回傳該類型資料的依賴。\n\n///\n\n## 其他模型 { #other-models }\n\n現在你可以在*路徑操作函式*中直接取得目前使用者，並在**依賴注入**層處理安全機制，使用 `Depends`。\n\n而且你可以為安全需求使用任意模型或資料（本例中是 Pydantic 模型 `User`）。\n\n但你不受限於某個特定的資料模型、類別或型別。\n\n想在模型中只有 `id` 與 `email` 而沒有任何 `username`？當然可以。你可以用同樣的工具達成。\n\n想只用一個 `str`？或只用一個 `dict`？或直接使用資料庫類別的模型實例？都可以，一樣運作。\n\n你的應用其實沒有真人使用者登入，而是機器人、bot，或其他系統，只持有 access token？同樣沒有問題。\n\n只要用任何你的應用需要的模型、類別或資料庫即可。**FastAPI** 的依賴注入系統都支援。\n\n## 程式碼大小 { #code-size }\n\n這個範例看起來可能有點冗長。記住我們把安全、資料模型、工具函式與*路徑操作*混在同一個檔案中。\n\n但重點在這裡。\n\n安全與依賴注入相關的內容只需要寫一次。\n\n你可以把它設計得再複雜都沒問題，仍然只需在單一位置寫一次，依然具備完整的彈性。\n\n但你可以有成千上萬個端點（*路徑操作*）共用同一套安全系統。\n\n而且它們全部（或你想要的一部分）都可以重用這些依賴，或你建立的其他依賴。\n\n而所有這些上千個*路徑操作*都可以小到只要 3 行：\n\n{* ../../docs_src/security/tutorial002_an_py310.py hl[30:32] *}\n\n## 回顧 { #recap }\n\n現在你可以在*路徑操作函式*中直接取得目前使用者。\n\n我們已經完成一半了。\n\n我們只需要再新增一個*路徑操作*，讓使用者/用戶端實際送出 `username` 與 `password`。\n\n下一步就會做。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/security/index.md",
    "content": "# 安全性 { #security }\n\n有許多方式可以處理安全性、身分驗證與授權。\n\n而且這通常是一個複雜且「困難」的主題。\n\n在許多框架與系統中，光是處理安全性與身分驗證就要花費大量心力與程式碼（很多情況下可能佔了全部程式碼的 50% 以上）。\n\n**FastAPI** 提供多種工具，讓你能以標準方式輕鬆、快速地處理「安全性」，而不必先研究並學會所有安全性規範。\n\n但在此之前，先釐清幾個小概念。\n\n## 急著上手？ { #in-a-hurry }\n\n如果你不在意這些術語，只需要立刻加入以使用者名稱與密碼為基礎的身分驗證與安全性，就直接跳到後續章節。\n\n## OAuth2 { #oauth2 }\n\nOAuth2 是一套規範，定義了多種處理身分驗證與授權的方法。\n\n它相當龐大，涵蓋許多複雜的使用情境。\n\n它也包含使用「第三方」進行身分驗證的方式。\n\n這正是各種「使用 Facebook、Google、X（Twitter）、GitHub 登入」系統在底層採用的機制。\n\n### OAuth 1 { #oauth-1 }\n\n過去有 OAuth 1，和 OAuth2 非常不同，也更複雜，因為它直接規範了如何加密通訊。\n\n它現在並不流行，也很少被使用。\n\nOAuth2 不規範通訊如何加密，而是假設你的應用會透過 HTTPS 提供服務。\n\n/// tip | 提示\n在部署相關章節中，你會看到如何使用 Traefik 與 Let's Encrypt 免費設定 HTTPS。\n///\n\n## OpenID Connect { #openid-connect }\n\nOpenID Connect 是基於 **OAuth2** 的另一套規範。\n\n它只是擴充了 OAuth2，釐清了 OAuth2 中相對模糊的部份，以提升互通性。\n\n例如，Google 登入使用的是 OpenID Connect（其底層使用 OAuth2）。\n\n但 Facebook 登入不支援 OpenID Connect，它有自己風格的 OAuth2。\n\n### OpenID（不是「OpenID Connect」） { #openid-not-openid-connect }\n\n過去也有一個「OpenID」規範。它試圖解決與 **OpenID Connect** 相同的問題，但不是建立在 OAuth2 之上。\n\n因此，它是一套完全額外、獨立的系統。\n\n它現在並不流行，也很少被使用。\n\n## OpenAPI { #openapi }\n\nOpenAPI（先前稱為 Swagger）是一套用於構建 API 的開放規範（現為 Linux 基金會的一部分）。\n\n**FastAPI** 建立在 **OpenAPI** 之上。\n\n這使得它能提供多種自動化的互動式文件介面、程式碼產生等功能。\n\nOpenAPI 提供定義多種安全性「方案」。\n\n透過使用它們，你可以善用這些基於標準的工具，包括這些互動式文件系統。\n\nOpenAPI 定義了下列安全性方案：\n\n* `apiKey`：應用程式特定的金鑰，來源可以是：\n    * 查詢參數。\n    * 標頭（header）。\n    * Cookie。\n* `http`：標準的 HTTP 驗證系統，包括：\n    * `bearer`：使用 `Authorization` 標頭，值為 `Bearer ` 加上一個 token。這是從 OAuth2 延伸而來。\n    * HTTP Basic 驗證。\n    * HTTP Digest 等。\n* `oauth2`：所有 OAuth2 的安全性處理方式（稱為「flows」）。\n    * 其中數個 flow 適合用來建立 OAuth 2.0 身分驗證提供者（如 Google、Facebook、X（Twitter）、GitHub 等）：\n        * `implicit`\n        * `clientCredentials`\n        * `authorizationCode`\n    * 但有一個特定的 flow 可直接在同一個應用中處理身分驗證：\n        * `password`：後續幾個章節會示範這個。\n* `openIdConnect`：提供一種方式來定義如何自動發現 OAuth2 的身分驗證資訊。\n    * 這種自動探索機制即由 OpenID Connect 規範定義。\n\n/// tip | 提示\n整合像 Google、Facebook、X（Twitter）、GitHub 等其他身分驗證/授權提供者也是可行而且相對容易。\n\n最複雜的部分其實是打造一個類似那樣的身分驗證/授權提供者，但 **FastAPI** 提供了工具，能替你處理繁重工作，讓你更輕鬆完成。\n///\n\n## **FastAPI** 工具 { #fastapi-utilities }\n\nFastAPI 在 `fastapi.security` 模組中為上述各種安全性方案提供了多種工具，讓這些機制更容易使用。\n\n接下來的章節會示範如何使用這些 **FastAPI** 提供的工具，為你的 API 加入安全性。\n\n你也會看到它如何自動整合到互動式文件系統中。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/security/oauth2-jwt.md",
    "content": "# 使用密碼（與雜湊）的 OAuth2、以 Bearer 搭配 JWT 權杖 { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens }\n\n現在我們已經有完整的安全流程了，接下來用 <abbr title=\"JSON Web Tokens - JSON 網路權杖\">JWT</abbr> 權杖與安全的密碼雜湊，讓應用真正安全。\n\n這份程式碼可以直接用在你的應用中，把密碼雜湊存進資料庫等等。\n\n我們會從上一章的內容繼續往下擴充。\n\n## 關於 JWT { #about-jwt }\n\nJWT 的意思是「JSON Web Tokens」。\n\n它是一種把 JSON 物件編碼成一段長且緊密（沒有空白）的字串的標準。看起來像這樣：\n\n```\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n```\n\n它不是加密的，所以任何人都可以從內容還原出資訊。\n\n但它是簽名過的。因此當你收到一個你所簽發的權杖時，你可以驗證確實是你簽發的。\n\n如此一來，你可以建立一個（例如）有效期為 1 週的權杖。當使用者隔天帶著這個權杖回來時，你就知道該使用者仍然登入在你的系統中。\n\n一週後，權杖會過期，使用者就不再被授權，需要再次登入以取得新的權杖。而如果使用者（或第三方）試圖修改權杖來改變有效期，你也能發現，因為簽名不會相符。\n\n如果你想玩玩看 JWT 權杖並了解其運作，請參考 [https://jwt.io](https://jwt.io/)。\n\n## 安裝 `PyJWT` { #install-pyjwt }\n\n我們需要安裝 `PyJWT` 才能在 Python 中產生與驗證 JWT 權杖。\n\n請先建立並啟用一個[虛擬環境](../../virtual-environments.md)，然後安裝 `pyjwt`：\n\n<div class=\"termy\">\n\n```console\n$ pip install pyjwt\n\n---> 100%\n```\n\n</div>\n\n/// info | 說明\n\n如果你打算使用像 RSA 或 ECDSA 這類的數位簽章演算法，應該安裝帶有加密函式庫相依的 `pyjwt[crypto]`。\n\n更多內容可參考 [PyJWT 安裝文件](https://pyjwt.readthedocs.io/en/latest/installation.html)。\n\n///\n\n## 密碼雜湊 { #password-hashing }\n\n「雜湊」是指把某些內容（此處為密碼）轉換成一串看起來像亂碼的位元組序列（其實就是字串）。\n\n每當你輸入完全相同的內容（完全相同的密碼），就會得到完全相同的亂碼。\n\n但你無法從這串亂碼再反推回原本的密碼。\n\n### 為什麼要用密碼雜湊 { #why-use-password-hashing }\n\n如果你的資料庫被偷了，竊賊拿到的不是使用者的明文密碼，而只是雜湊值。\n\n因此，竊賊無法直接拿該密碼去嘗試登入其他系統（由於許多使用者在各處都用同一組密碼，這會很危險）。\n\n## 安裝 `pwdlib` { #install-pwdlib }\n\npwdlib 是一個很棒的 Python 套件，用來處理密碼雜湊。\n\n它支援多種安全的雜湊演算法與相關工具。\n\n建議使用的演算法是「Argon2」。\n\n請先建立並啟用一個[虛擬環境](../../virtual-environments.md)，然後以 Argon2 支援安裝 pwdlib：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"pwdlib[argon2]\"\n\n---> 100%\n```\n\n</div>\n\n/// tip | 提示\n\n使用 `pwdlib`，你甚至可以把它設定為能讀取由 **Django**、**Flask** 的安全外掛或其他許多系統所建立的密碼。\n\n例如，你可以讓 Django 應用與 FastAPI 應用共用同一個資料庫中的資料。或者逐步遷移一個 Django 應用，同樣使用該資料庫。\n\n而你的使用者可以同時從 Django 應用或 **FastAPI** 應用登入。\n\n///\n\n## 雜湊與驗證密碼 { #hash-and-verify-the-passwords }\n\n從 `pwdlib` 匯入我們需要的工具。\n\n用建議設定建立一個 PasswordHash 執行個體——它會用於雜湊與驗證密碼。\n\n/// tip | 提示\n\npwdlib 也支援 bcrypt 雜湊演算法，但不包含傳統（legacy）演算法——若需要處理過時的雜湊，建議使用 passlib 函式庫。\n\n例如，你可以用它讀取並驗證由其他系統（如 Django）產生的密碼，但針對任何新密碼則改用像 Argon2 或 Bcrypt 這類的不同演算法來雜湊。\n\n並同時與所有這些格式相容。\n\n///\n\n建立一個工具函式來雜湊使用者送來的密碼。\n\n再建立另一個工具來驗證收到的密碼是否符合已儲存的雜湊。\n\n以及另一個用於驗證並回傳使用者的工具。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,51,58:59,62:63,72:79] *}\n\n當以不存在於資料庫的使用者名稱呼叫 `authenticate_user` 時，我們仍然會拿一個假的雜湊去跑一次 `verify_password`。\n\n這可確保無論使用者名稱是否有效，端點的回應時間都大致相同，避免可用來枚舉既有使用者名稱的「計時攻擊」（timing attacks）。\n\n/// note | 注意\n\n如果你查看新的（假）資料庫 `fake_users_db`，你會看到雜湊後的密碼現在長這樣：`\"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\"`。\n\n///\n\n## 處理 JWT 權杖 { #handle-jwt-tokens }\n\n匯入剛安裝的模組。\n\n建立一把隨機的密鑰（secret key）用於簽署 JWT 權杖。\n\n要產生安全的隨機密鑰可使用以下指令：\n\n<div class=\"termy\">\n\n```console\n$ openssl rand -hex 32\n\n09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\n```\n\n</div>\n\n將輸出的值複製到變數 `SECRET_KEY`（不要使用範例中的那一組）。\n\n建立變數 `ALGORITHM` 指定用來簽署 JWT 權杖的演算法，設為 `\"HS256\"`。\n\n建立一個權杖有效期的變數。\n\n定義一個用於權杖端點回應的 Pydantic Model。\n\n建立一個工具函式來產生新的 access token。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,82:90] *}\n\n## 更新相依項目 { #update-the-dependencies }\n\n更新 `get_current_user`，讓它仍接收相同的權杖，但這次改用 JWT 權杖。\n\n解碼收到的權杖、驗證它，並回傳目前的使用者。\n\n如果權杖無效，立即回傳一個 HTTP 錯誤。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[93:110] *}\n\n## 更新 `/token` 路徑操作 { #update-the-token-path-operation }\n\n用權杖有效期建立一個 `timedelta`。\n\n建立真正的 JWT access token 並回傳它。\n\n{* ../../docs_src/security/tutorial004_an_py310.py hl[121:136] *}\n\n### 關於 JWT「主體」`sub` 的技術細節 { #technical-details-about-the-jwt-subject-sub }\n\nJWT 規範說有個鍵 `sub`，代表權杖的主體（subject）。\n\n使用它是可選的，但通常會把使用者的識別資訊放在這裡，所以我們在此採用。\n\nJWT 除了用來識別使用者並允許他直接對你的 API 執行操作外，也可用於其他用途。\n\n例如，你可以識別一台「車」或一篇「部落格文章」。\n\n接著可以替該實體加上權限，如「drive」（對車而言）或「edit」（對文章而言）。\n\n然後你可以把該 JWT 權杖交給某個使用者（或機器人），他們就能用它來執行那些動作（開車、或編輯文章），甚至不需要有帳號，只要使用你的 API 所產生的 JWT 權杖即可。\n\n基於這些概念，JWT 能用在更複雜的情境中。\n\n在那些情境裡，數個實體可能擁有相同的 ID，例如 `foo`（使用者 `foo`、車 `foo`、以及文章 `foo`）。\n\n為了避免 ID 衝突，在為使用者建立 JWT 權杖時，你可以替 `sub` 的值加上前綴，例如 `username:`。因此在這個例子中，`sub` 的值可以是：`username:johndoe`。\n\n要記住的重要點是：`sub` 必須是在整個應用中唯一的識別子，並且必須是字串。\n\n## 試試看 { #check-it }\n\n啟動伺服器並前往文件頁：[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n你會看到這樣的介面：\n\n<img src=\"/img/tutorial/security/image07.png\">\n\n用和先前相同的方式授權應用。\n\n使用下列認證資訊：\n\nUsername: `johndoe`\nPassword: `secret`\n\n/// check | 檢查\n\n注意在程式碼中完全沒有明文密碼「`secret`」，我們只有雜湊後的版本。\n\n///\n\n<img src=\"/img/tutorial/security/image08.png\">\n\n呼叫端點 `/users/me/`，你會得到類似這樣的回應：\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false\n}\n```\n\n<img src=\"/img/tutorial/security/image09.png\">\n\n如果你打開開發者工具，可以看到送出的資料只包含權杖；密碼只會在第一次請求（用來驗證使用者並取得 access token）時送出，之後就不會再送：\n\n<img src=\"/img/tutorial/security/image10.png\">\n\n/// note | 注意\n\n留意標頭 `Authorization`，其值是以 `Bearer ` 開頭。\n\n///\n\n## 進階用法：`scopes` { #advanced-usage-with-scopes }\n\nOAuth2 有「scopes」的概念。\n\n你可以用它們替 JWT 權杖加上一組特定的權限。\n\n接著你可以把這個權杖直接交給某個使用者或第三方，讓他們在一組受限條件下與你的 API 互動。\n\n你可以在之後的「進階使用者指南」學到如何使用它們，以及它們如何整合進 **FastAPI**。\n\n## 小結 { #recap }\n\n依照你目前學到的內容，你可以用 OAuth2 與 JWT 等標準，設定一個安全的 **FastAPI** 應用。\n\n在幾乎任何框架中，安全性處理都會很快變得相當複雜。\n\n許多能大幅簡化工作的套件，往往必須在資料模型、資料庫與可用功能上做出很多取捨。而有些過度簡化的套件底層其實存在安全弱點。\n\n---\n\n**FastAPI** 不會在任何資料庫、資料模型或工具上做妥協。\n\n它給你完全的彈性，讓你挑選最適合你專案的組合。\n\n而且你可以直接使用許多維護良好且被廣泛採用的套件，例如 `pwdlib` 與 `PyJWT`，因為 **FastAPI** 不需要任何複雜機制就能整合外部套件。\n\n同時它也提供工具來在不犧牲彈性、穩健或安全的前提下，盡可能地簡化流程。\n\n你可以用相對簡單的方式使用並實作像 OAuth2 這樣的安全標準協定。\n\n你可以在「進階使用者指南」進一步了解如何使用 OAuth2 的「scopes」，以實作更細緻的權限系統，並遵循相同的標準。帶有 scopes 的 OAuth2 是許多大型身份驗證供應商（如 Facebook、Google、GitHub、Microsoft、X（Twitter）等）用來授權第三方應用代表其使用者與其 API 互動的機制。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/security/simple-oauth2.md",
    "content": "# 簡易 OAuth2：Password 與 Bearer { #simple-oauth2-with-password-and-bearer }\n\n現在從上一章延伸，補上缺少的部分，完成整個安全流程。\n\n## 取得 `username` 與 `password` { #get-the-username-and-password }\n\n我們要使用 **FastAPI** 提供的安全性工具來取得 `username` 與 `password`。\n\nOAuth2 規範中，當使用「password flow」（我們現在使用的）時，用戶端／使用者必須以表單資料送出 `username` 與 `password` 欄位。\n\n而且規範要求欄位名稱必須就是這兩個，所以像是 `user-name` 或 `email` 都不行。\n\n但別擔心，你在前端要怎麼呈現給最終使用者都可以。\n\n而你的資料庫模型也可以使用任何你想要的欄位名稱。\n\n不過在登入的路徑操作（path operation）裡，我們需要使用這些名稱，才能符合規範（例如才能使用整合的 API 文件系統）。\n\n規範也說明 `username` 與 `password` 必須以表單資料傳送（也就是這裡不能用 JSON）。\n\n### `scope` { #scope }\n\n規範也說用戶端可以再送一個表單欄位「`scope`」。\n\n欄位名稱是單數的 `scope`，但實際上是由多個以空白分隔的「scopes」組成的一長串字串。\n\n每個「scope」就是一個（不含空白的）字串。\n\n它們通常用來宣告特定的權限，例如：\n\n- `users:read` 或 `users:write` 是常見的例子\n- `instagram_basic` 用在 Facebook / Instagram\n- `https://www.googleapis.com/auth/drive` 用在 Google\n\n/// info\n\n在 OAuth2 裡，「scope」只是用來宣告特定所需權限的一個字串。\n\n不論裡面是否包含像 `:` 之類的字元，或是否是一個 URL，都沒差。\n\n那些都是實作細節。\n\n對 OAuth2 而言，它們就是字串而已。\n\n///\n\n## 取得 `username` 與 `password` 的程式碼 { #code-to-get-the-username-and-password }\n\n現在用 **FastAPI** 提供的工具來處理。\n\n### `OAuth2PasswordRequestForm` { #oauth2passwordrequestform }\n\n先匯入 `OAuth2PasswordRequestForm`，並在 `/token` 的路徑操作中，搭配 `Depends` 當作依賴使用：\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[4,78] *}\n\n`OAuth2PasswordRequestForm` 是一個類別型依賴，它宣告了一個表單本文，包含：\n\n- `username`\n- `password`\n- 可選的 `scope` 欄位，內容是一個由空白分隔的長字串\n- 可選的 `grant_type`\n\n/// tip\n\n依規範，實際上需要一個 `grant_type` 欄位且固定值為 `password`，但 `OAuth2PasswordRequestForm` 並不會強制檢查。\n\n如果你需要強制檢查，請改用 `OAuth2PasswordRequestFormStrict` 取代 `OAuth2PasswordRequestForm`。\n\n///\n\n- 可選的 `client_id`（本例不需要）\n- 可選的 `client_secret`（本例不需要）\n\n/// info\n\n`OAuth2PasswordRequestForm` 並不是像 `OAuth2PasswordBearer` 那樣對 **FastAPI** 來說的特殊類別。\n\n`OAuth2PasswordBearer` 會讓 **FastAPI** 知道它是一個 security scheme，因此會以那種方式加入 OpenAPI。\n\n但 `OAuth2PasswordRequestForm` 只是你也可以自己撰寫的一個類別型依賴，或是你也可以直接宣告 `Form` 參數。\n\n只是因為這是很常見的用例，所以 **FastAPI** 直接內建提供，讓事情更簡單。\n\n///\n\n### 使用表單資料 { #use-the-form-data }\n\n/// tip\n\n`OAuth2PasswordRequestForm` 這個依賴類別的實例不會有以空白分隔長字串的 `scope` 屬性，而是會有一個 `scopes` 屬性，裡面是各個 scope 的實際字串清單。\n\n本示例沒有使用 `scopes`，但如果你需要，功能已經在那裡了。\n\n///\n\n現在，從（假的）資料庫裡用表單欄位的 `username` 取得使用者資料。\n\n如果沒有該使用者，就回傳「Incorrect username or password」的錯誤。\n\n我們用 `HTTPException` 這個例外來回傳錯誤：\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[3,79:81] *}\n\n### 檢查密碼 { #check-the-password }\n\n這時我們已經有來自資料庫的使用者資料，但還沒檢查密碼。\n\n先把那些資料放進 Pydantic 的 `UserInDB` 模型。\n\n你絕對不要以純文字儲存密碼，所以我們會使用（假的）密碼雜湊系統。\n\n如果密碼不匹配，我們回傳同樣的錯誤。\n\n#### 密碼雜湊（hashing） { #password-hashing }\n\n「雜湊」的意思是：把一些內容（這裡是密碼）轉換成一串看起來像亂碼的位元組序列（就是字串）。\n\n只要你輸入完全相同的內容（完全相同的密碼），就會得到完全相同的亂碼。\n\n但你無法從這串亂碼還原回原本的密碼。\n\n##### 為何要做密碼雜湊 { #why-use-password-hashing }\n\n如果你的資料庫被竊取，攻擊者拿到的不是使用者的純文字密碼，而只是雜湊值。\n\n因此攻擊者無法嘗試把那些密碼用在其他系統上（因為很多使用者在各處都用同一組密碼，這會很危險）。\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[82:85] *}\n\n#### 關於 `**user_dict**` { #about-user-dict }\n\n`UserInDB(**user_dict)` 的意思是：\n\n把 `user_dict` 的鍵和值直接當作具名參數傳入，等同於：\n\n```Python\nUserInDB(\n    username = user_dict[\"username\"],\n    email = user_dict[\"email\"],\n    full_name = user_dict[\"full_name\"],\n    disabled = user_dict[\"disabled\"],\n    hashed_password = user_dict[\"hashed_password\"],\n)\n```\n\n/// info\n\n想更完整地了解 `**user_dict`，請回到[**額外模型** 的文件](../extra-models.md#about-user-in-dict)。\n\n///\n\n## 回傳 token { #return-the-token }\n\n`token` 端點的回應必須是 JSON 物件。\n\n它應該有一個 `token_type`。在本例中，我們使用「Bearer」tokens，token 類型應該是「`bearer`」。\n\n而且它還應該有一個 `access_token`，其值為包含我們存取權杖的字串。\n\n在這個簡單示例中，我們會不安全地直接回傳相同的 `username` 當作 token。\n\n/// tip\n\n下一章你會看到真正安全的實作，包含密碼雜湊與 <abbr title=\"JSON Web Tokens - JSON 網頁權杖\">JWT</abbr> tokens。\n\n但現在先把注意力放在我們需要的這些細節上。\n\n///\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[87] *}\n\n/// tip\n\n依照規範，你應該回傳一個包含 `access_token` 與 `token_type` 的 JSON，就像這個範例。\n\n這部分需要你自己在程式中完成，並確保使用這些 JSON key。\n\n這幾乎是你為了符合規範而必須自行記得正確處理的唯一事情。\n\n其餘的 **FastAPI** 都會幫你處理。\n\n///\n\n## 更新依賴項 { #update-the-dependencies }\n\n接著我們要更新依賴項。\n\n我們只想在使用者為啟用狀態時取得 `current_user`。\n\n所以，我們新增一個依賴 `get_current_active_user`，而它本身又依賴 `get_current_user`。\n\n這兩個依賴會在使用者不存在或未啟用時回傳 HTTP 錯誤。\n\n因此，在端點中，只有在使用者存在、已正確驗證且為啟用狀態時，我們才會取得使用者：\n\n{* ../../docs_src/security/tutorial003_an_py310.py hl[58:66,69:74,94] *}\n\n/// info\n\n這裡我們一併回傳值為 `Bearer` 的額外標頭 `WWW-Authenticate`，這也是規範的一部分。\n\n任何 HTTP（錯誤）狀態碼 401「UNAUTHORIZED」都應該同時回傳 `WWW-Authenticate` 標頭。\n\n在 bearer tokens（我們的情況）下，該標頭的值應該是 `Bearer`。\n\n其實你可以省略這個額外標頭，功能仍會正常。\n\n但此處加上它是為了遵循規範。\n\n同時也可能有工具會期待並使用它（現在或未來），而這可能對你或你的使用者有幫助，現在或未來皆然。\n\n這就是標準的好處...\n\n///\n\n## 實際操作看看 { #see-it-in-action }\n\n開啟互動式文件：[http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs)。\n\n### 驗證身分 { #authenticate }\n\n點選「Authorize」按鈕。\n\n使用下列帳密：\n\nUser: `johndoe`\n\nPassword: `secret`\n\n<img src=\"/img/tutorial/security/image04.png\">\n\n在系統中完成驗證後，你會看到如下畫面：\n\n<img src=\"/img/tutorial/security/image05.png\">\n\n### 取得自己的使用者資料 { #get-your-own-user-data }\n\n現在使用 `GET` 方法呼叫路徑 `/users/me`。\n\n你會取得自己的使用者資料，如：\n\n```JSON\n{\n  \"username\": \"johndoe\",\n  \"email\": \"johndoe@example.com\",\n  \"full_name\": \"John Doe\",\n  \"disabled\": false,\n  \"hashed_password\": \"fakehashedsecret\"\n}\n```\n\n<img src=\"/img/tutorial/security/image06.png\">\n\n如果你點擊鎖頭圖示登出，然後再次嘗試相同操作，你會得到 HTTP 401 錯誤：\n\n```JSON\n{\n  \"detail\": \"Not authenticated\"\n}\n```\n\n### 未啟用的使用者 { #inactive-user }\n\n現在改用一個未啟用的使用者，使用以下帳密驗證：\n\nUser: `alice`\n\nPassword: `secret2`\n\n然後再呼叫 `GET` 方法的 `/users/me`。\n\n你會得到「Inactive user」的錯誤，例如：\n\n```JSON\n{\n  \"detail\": \"Inactive user\"\n}\n```\n\n## 小結 { #recap }\n\n你現在已經有足夠的工具，能為你的 API 以 `username` 與 `password` 實作一個完整的安全性系統。\n\n使用這些工具，你可以讓安全性系統相容於任何資料庫，以及任何使用者或資料模型。\n\n唯一尚未補上的細節是：它現在其實還不「安全」。\n\n在下一章，你會看到如何使用安全的密碼雜湊函式庫與 <abbr title=\"JSON Web Tokens - JSON 網頁權杖\">JWT</abbr> tokens。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/server-sent-events.md",
    "content": "# Server-Sent Events（SSE） { #server-sent-events-sse }\n\n你可以使用 Server-Sent Events（SSE）把資料串流傳送給用戶端。\n\n這與[串流 JSON Lines](stream-json-lines.md)類似，但使用瀏覽器原生支援、透過 [`EventSource` API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) 的 `text/event-stream` 格式。\n\n/// info\n\n在 FastAPI 0.135.0 新增。\n\n///\n\n## 什麼是 Server-Sent Events？ { #what-are-server-sent-events }\n\nSSE 是一種透過 HTTP 從伺服器向用戶端串流傳送資料的標準。\n\n每個事件都是一個小型文字區塊，包含 `data`、`event`、`id` 和 `retry` 等「欄位」，並以空白行分隔。\n\n看起來像這樣：\n\n```\ndata: {\"name\": \"Portal Gun\", \"price\": 999.99}\n\ndata: {\"name\": \"Plumbus\", \"price\": 32.99}\n\n```\n\nSSE 常用於 AI 聊天串流、即時通知、日誌與可觀察性，以及其他由伺服器主動推送更新給用戶端的情境。\n\n/// tip\n\n如果你要串流二進位資料，例如影片或音訊，請參考進階指南：[串流資料](../advanced/stream-data.md)。\n\n///\n\n## 使用 FastAPI 串流 SSE { #stream-sse-with-fastapi }\n\n要在 FastAPI 中串流 SSE，請在你的路徑操作函式（path operation function）中使用 `yield`，並設定 `response_class=EventSourceResponse`。\n\n從 `fastapi.sse` 匯入 `EventSourceResponse`：\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[4,22] *}\n\n每個 `yield` 的項目都會以 JSON 編碼並放在 SSE 事件的 `data:` 欄位中送出。\n\n如果你把回傳型別宣告為 `AsyncIterable[Item]`，FastAPI 會用它來透過 Pydantic 進行**驗證**、**文件化**與**序列化**。\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[1:25] hl[10:12,23] *}\n\n/// tip\n\n因為 Pydantic 會在 **Rust** 端進行序列化，如果你有宣告回傳型別，效能會比未宣告時高很多。\n\n///\n\n### 非 async 的路徑操作函式 { #non-async-path-operation-functions }\n\n你也可以使用一般的 `def` 函式（沒有 `async`），並同樣使用 `yield`。\n\nFastAPI 會確保正確執行，不會阻塞事件迴圈。\n\n由於此函式不是 async，正確的回傳型別是 `Iterable[Item]`：\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[28:31] hl[29] *}\n\n### 無回傳型別 { #no-return-type }\n\n你也可以省略回傳型別。FastAPI 會使用 [`jsonable_encoder`](./encoder.md) 轉換資料並送出。\n\n{* ../../docs_src/server_sent_events/tutorial001_py310.py ln[34:37] hl[35] *}\n\n## `ServerSentEvent` { #serversentevent }\n\n如果你需要設定 `event`、`id`、`retry` 或 `comment` 等 SSE 欄位，你可以改為 `yield` 出 `ServerSentEvent` 物件，而不是單純的資料。\n\n從 `fastapi.sse` 匯入 `ServerSentEvent`：\n\n{* ../../docs_src/server_sent_events/tutorial002_py310.py hl[4,26] *}\n\n`data` 欄位一律會以 JSON 編碼。你可以傳入任何可序列化為 JSON 的值，包括 Pydantic 模型。\n\n## 原始資料 { #raw-data }\n\n如果你需要在**不**進行 JSON 編碼的情況下傳送資料，請使用 `raw_data` 取代 `data`。\n\n這對於傳送已格式化的文字、日誌行或特殊的 <dfn title=\"用於表示特殊條件或狀態的值\">\"哨兵\"</dfn> 值（例如 `[DONE]`）很有用。\n\n{* ../../docs_src/server_sent_events/tutorial003_py310.py hl[17] *}\n\n/// note\n\n`data` 與 `raw_data` 互斥。每個 `ServerSentEvent` 只能設定其中一個。\n\n///\n\n## 使用 `Last-Event-ID` 繼續 { #resuming-with-last-event-id }\n\n當瀏覽器在連線中斷後重新連線時，會在 `Last-Event-ID` 標頭中傳送最後接收到的 `id`。\n\n你可以將它作為標頭參數讀取，並用來從用戶端中斷處繼續串流：\n\n{* ../../docs_src/server_sent_events/tutorial004_py310.py hl[25,27,31] *}\n\n## 使用 POST 的 SSE { #sse-with-post }\n\nSSE 可搭配**任何 HTTP 方法**，不僅限於 `GET`。\n\n這對於像是透過 `POST` 串流 SSE 的協定（例如 [MCP](https://modelcontextprotocol.io)）很有用：\n\n{* ../../docs_src/server_sent_events/tutorial005_py310.py hl[14] *}\n\n## 技術細節 { #technical-details }\n\nFastAPI 內建實作了一些 SSE 的最佳實務。\n\n- 當 15 秒內沒有任何訊息時，傳送一次**「保活」`ping` 註解**，以避免某些代理伺服器關閉連線；此作法源自於[HTML 規範：Server-Sent Events](https://html.spec.whatwg.org/multipage/server-sent-events.html#authoring-notes)中的建議。\n- 設定 `Cache-Control: no-cache` 標頭，以**防止快取**串流內容。\n- 設定特殊標頭 `X-Accel-Buffering: no`，以**避免**在像 Nginx 這類代理中被**緩衝**。\n\n你不需要做任何事，開箱即用。🤓\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/sql-databases.md",
    "content": "# SQL（關聯式）資料庫 { #sql-relational-databases }\n\nFastAPI 不強制你使用 SQL（關聯式）資料庫。你可以使用任何你想要的資料庫。\n\n這裡我們會用 [SQLModel](https://sqlmodel.tiangolo.com/) 作為範例。\n\nSQLModel 建立在 [SQLAlchemy](https://www.sqlalchemy.org/) 與 Pydantic 之上。它由 FastAPI 的作者開發，非常適合需要使用 SQL 資料庫的 FastAPI 應用。\n\n/// tip | 提示\n\n你可以使用任何你想用的 SQL 或 NoSQL 資料庫函式庫（有時稱為 <abbr title=\"Object Relational Mapper - 物件關聯對應器：一個用來描述某些類別代表 SQL 資料表且其實例代表資料表中資料列的函式庫的術語\">\"ORMs\"</abbr>），FastAPI 不會強迫你使用特定工具。😎\n\n///\n\n因為 SQLModel 建立在 SQLAlchemy 之上，你可以輕鬆使用 SQLAlchemy 所支援的任何資料庫（因此 SQLModel 也支援），例如：\n\n* PostgreSQL\n* MySQL\n* SQLite\n* Oracle\n* Microsoft SQL Server，等等。\n\n在這個範例中，我們會使用 SQLite，因為它只用到單一檔案，而且 Python 內建支援。你可以直接複製這個範例並原樣執行。\n\n之後，在你的正式環境應用中，你可能會想使用像 PostgreSQL 這類的資料庫伺服器。\n\n/// tip | 提示\n\n有一個包含 FastAPI 與 PostgreSQL 的官方專案腳手架，還有前端與更多工具：[https://github.com/fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template)\n\n///\n\n這是一份非常簡短的教學，如果你想更全面學習資料庫、SQL，或更進階的功能，請參考 [SQLModel 文件](https://sqlmodel.tiangolo.com/)。\n\n## 安裝 `SQLModel` { #install-sqlmodel }\n\n首先，請先建立你的[虛擬環境](../virtual-environments.md)、啟用它，然後安裝 `sqlmodel`：\n\n<div class=\"termy\">\n\n```console\n$ pip install sqlmodel\n---> 100%\n```\n\n</div>\n\n## 建立只有單一模型的應用 { #create-the-app-with-a-single-model }\n\n我們先用單一 SQLModel 模型建立這個應用的最簡版。\n\n接著我們會在下方用多個模型來提升安全性與彈性。🤓\n\n### 建立模型 { #create-models }\n\n匯入 `SQLModel` 並建立一個資料庫模型：\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *}\n\n`Hero` 類別與 Pydantic 模型非常相似（事實上，在底層它就是一個 Pydantic 模型）。\n\n有幾點差異：\n\n* `table=True` 告訴 SQLModel 這是一個「資料表模型」（table model），它應該代表 SQL 資料庫中的一個資料表，而不僅僅是「資料模型」（就像一般的 Pydantic 類別）。\n\n* `Field(primary_key=True)` 告訴 SQLModel，`id` 是 SQL 資料庫中的「主鍵」。 （你可以在 SQLModel 文件中進一步了解 SQL 主鍵）\n\n    注意：我們在主鍵欄位使用 `int | None`，這樣在 Python 程式碼中我們可以「在沒有 `id` 的情況下建立物件」（`id=None`），假設資料庫在儲存時會「自動產生」。SQLModel 瞭解資料庫會提供 `id`，並且在資料庫綱要中「將該欄位定義為非空的 `INTEGER`」。詳情請見 [SQLModel 文件：主鍵](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/#primary-key-id)。\n\n* `Field(index=True)` 告訴 SQLModel 應為此欄位建立「SQL 索引」，以便在用此欄位過濾讀取資料時更快查詢。\n\n    SQLModel 會知道宣告為 `str` 的欄位在 SQL 中會是 `TEXT`（或 `VARCHAR`，依資料庫而定）。\n\n### 建立引擎 { #create-an-engine }\n\nSQLModel 的 `engine`（底層實際上是 SQLAlchemy 的 `engine`）是用來「維護與資料庫連線」的東西。\n\n你的程式中應該只有「單一 `engine` 物件」來連到同一個資料庫。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *}\n\n使用 `check_same_thread=False` 允許 FastAPI 在不同執行緒中使用同一個 SQLite 資料庫。這是必要的，因為「單一請求」可能會使用「多個執行緒」（例如在依賴項中）。\n\n別擔心，依照我們的程式結構，稍後我們會確保「每個請求只使用單一 SQLModel 的 session」，這其實就是 `check_same_thread` 想要達成的事。\n\n### 建立資料表 { #create-the-tables }\n\n接著我們新增一個函式，使用 `SQLModel.metadata.create_all(engine)` 為所有「資料表模型」建立資料表。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *}\n\n### 建立 Session 依賴 { #create-a-session-dependency }\n\n「`Session`」會在記憶體中保存物件並追蹤資料需要的任何變更，然後透過「`engine`」與資料庫溝通。\n\n我們會用 `yield` 建立一個 FastAPI 的「依賴」，為每個請求提供一個新的 `Session`。這可確保每個請求只使用單一的 session。🤓\n\n接著我們建立一個 `Annotated` 的依賴 `SessionDep`，讓後續使用這個依賴的程式碼更簡潔。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30]  hl[25:27,30] *}\n\n### 在啟動時建立資料表 { #create-database-tables-on-startup }\n\n我們會在應用啟動時建立資料庫的資料表。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *}\n\n這裡我們在應用的啟動事件中建立資料表。\n\n在正式環境中，你大概會在啟動應用前使用遷移腳本來處理。🤓\n\n/// tip | 提示\n\nSQLModel 之後會提供包裝 Alembic 的遷移工具，但目前你可以直接使用 [Alembic](https://alembic.sqlalchemy.org/en/latest/)。\n\n///\n\n### 建立 Hero { #create-a-hero }\n\n因為每個 SQLModel 模型同時也是一個 Pydantic 模型，你可以在「型別標註」中像使用 Pydantic 模型一樣使用它。\n\n例如，如果你宣告一個參數型別為 `Hero`，它會從「JSON body」中讀取。\n\n同樣地，你也可以將它宣告為函式的「回傳型別」，然後在自動產生的 API 文件 UI 中就會顯示其資料結構。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *}\n\n這裡我們使用 `SessionDep` 依賴（即一個 `Session`），把新的 `Hero` 加入 `Session` 實例，提交變更到資料庫，刷新 `hero` 的資料，然後回傳它。\n\n### 讀取多個 Hero { #read-heroes }\n\n我們可以用 `select()` 從資料庫「讀取」多個 `Hero`。可以加入 `limit` 與 `offset` 來分頁。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *}\n\n### 讀取單一 Hero { #read-one-hero }\n\n我們可以「讀取」單一的 `Hero`。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *}\n\n### 刪除 Hero { #delete-a-hero }\n\n我們也可以「刪除」一個 `Hero`。\n\n{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *}\n\n### 執行應用 { #run-the-app }\n\n你可以執行應用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n然後前往 `/docs` 的 UI，你會看到 FastAPI 使用這些模型來「文件化」API，也會用它們來「序列化」與「驗證」資料。\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image01.png\">\n</div>\n\n## 用多個模型更新應用 { #update-the-app-with-multiple-models }\n\n現在我們稍微「重構」一下這個應用，以提升「安全性」與「彈性」。\n\n如果你檢查前一版的應用，在 UI 中你會看到，到目前為止它讓用戶端自己決定要建立的 `Hero` 的 `id`。😱\n\n我們不該允許這樣，因為他們可能會覆蓋資料庫中我們已分配的 `id`。決定 `id` 應該由「後端」或「資料庫」來做，「不是用戶端」。\n\n另外，我們為 hero 建立了 `secret_name`，但目前我們在各處都把它回傳出去，這一點都不「保密」... 😅\n\n我們會透過加入一些「額外模型」來修正這些問題。這正是 SQLModel 大放異彩的地方。✨\n\n### 建立多個模型 { #create-multiple-models }\n\n在 SQLModel 中，任何設了 `table=True` 的模型類別都是「資料表模型」。\n\n而沒有設 `table=True` 的模型類別就是「資料模型」，這些其實就是 Pydantic 模型（只有一點小增強）。🤓\n\n使用 SQLModel，我們可以利用「繼承」來「避免重複」在各種情況下一再宣告所有欄位。\n\n#### `HeroBase` - 基底類別 { #herobase-the-base-class }\n\n先從 `HeroBase` 模型開始，它包含所有模型「共享」的欄位：\n\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *}\n\n#### `Hero` - 資料表模型 { #hero-the-table-model }\n\n接著建立 `Hero`，也就是實際的「資料表模型」，它包含不一定會出現在其他模型中的「額外欄位」：\n\n* `id`\n* `secret_name`\n\n因為 `Hero` 繼承自 `HeroBase`，它「也」擁有 `HeroBase` 中宣告的「欄位」，因此 `Hero` 的完整欄位為：\n\n* `id`\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *}\n\n#### `HeroPublic` - 公開的資料模型 { #heropublic-the-public-data-model }\n\n接下來建立 `HeroPublic` 模型，它是要「回傳」給 API 用戶端的模型。\n\n它擁有與 `HeroBase` 相同的欄位，因此不會包含 `secret_name`。\n\n終於，我們英雄的真實身分受保護了！🥷\n\n它也重新宣告了 `id: int`。這麼做是與 API 用戶端訂立一個「契約」，讓他們可以確定 `id` 一定存在而且是 `int`（不會是 `None`）。\n\n/// tip | 提示\n\n讓回傳模型保證某個值一定存在、而且一定是 `int`（不是 `None`），對 API 用戶端非常有幫助。他們在有這個確信下可以寫出更簡單的程式碼。\n\n此外，透過「自動產生的客戶端」也會有更簡潔的介面，讓要使用你 API 的開發者能有更好的開發體驗。😎\n\n///\n\n`HeroPublic` 中的欄位與 `HeroBase` 相同，僅 `id` 宣告為 `int`（非 `None`）：\n\n* `id`\n* `name`\n* `age`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *}\n\n#### `HeroCreate` - 用於建立 Hero 的資料模型 { #herocreate-the-data-model-to-create-a-hero }\n\n現在我們建立 `HeroCreate` 模型，這是用來「驗證」用戶端送來資料的模型。\n\n它具有與 `HeroBase` 相同的欄位，並且還有 `secret_name`。\n\n接下來，當用戶端「建立新 hero」時，他們會送上 `secret_name`，它會被儲存在資料庫中，但這些祕密名稱不會在 API 中回傳給用戶端。\n\n/// tip | 提示\n\n這也就是你處理「密碼」的方式。接收它們，但不要在 API 中回傳。\n\n你也應該在儲存前先對密碼做「雜湊」，「永遠不要以明文儲存」。\n\n///\n\n`HeroCreate` 的欄位有：\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *}\n\n#### `HeroUpdate` - 用於更新 Hero 的資料模型 { #heroupdate-the-data-model-to-update-a-hero }\n\n在前一版的應用中，我們沒有「更新 hero」的方式，但現在有了「多個模型」，我們就能做到。🎉\n\n`HeroUpdate` 這個資料模型有點特別，它包含「建立新 hero 所需的所有欄位」，但所有欄位都是「可選的」（都有預設值）。這樣在更新時，你只需要送出想要更新的欄位即可。\n\n因為所有欄位的「型別其實都改變了」（型別現在包含 `None`，而且預設值為 `None`），我們需要「重新宣告」它們。\n\n其實不一定要繼承 `HeroBase`，因為我們會重新宣告所有欄位。我這裡保留繼承只是為了一致性，並非必要。這主要是個人偏好的問題。🤷\n\n`HeroUpdate` 的欄位有：\n\n* `name`\n* `age`\n* `secret_name`\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *}\n\n### 用 `HeroCreate` 建立並回傳 `HeroPublic` { #create-with-herocreate-and-return-a-heropublic }\n\n現在我們有了「多個模型」，可以更新應用中使用它們的部分。\n\n我們在請求中接收 `HeroCreate`（資料模型），並由它建立一個 `Hero`（資料表模型）。\n\n這個新的資料表模型 `Hero` 會有用戶端傳來的欄位，並且會由資料庫產生一個 `id`。\n\n然後我們直接從函式回傳這個資料表模型 `Hero`。但因為我們用 `HeroPublic` 當作 `response_model`，FastAPI 會用 `HeroPublic` 來驗證與序列化資料。\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *}\n\n/// tip | 提示\n\n現在我們用 `response_model=HeroPublic`，而不是用回傳型別標註 `-> HeroPublic`，因為我們實際回傳的值其實「不是」`HeroPublic`。\n\n如果我們宣告 `-> HeroPublic`，你的編輯器與 linter 會（理所當然地）抱怨你回傳的是 `Hero` 而不是 `HeroPublic`。\n\n在 `response_model` 中宣告，就是要讓 FastAPI 去做它該做的事，而不影響型別標註，以及你的編輯器與其他工具提供的協助。\n\n///\n\n### 使用 `HeroPublic` 讀取多個 Hero { #read-heroes-with-heropublic }\n\n我們可以像先前一樣「讀取」多個 `Hero`。同樣地，我們使用 `response_model=list[HeroPublic]` 來確保資料被正確驗證與序列化。\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *}\n\n### 使用 `HeroPublic` 讀取單一 Hero { #read-one-hero-with-heropublic }\n\n我們可以「讀取」單一 hero：\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *}\n\n### 使用 `HeroUpdate` 更新 Hero { #update-a-hero-with-heroupdate }\n\n我們可以「更新 hero」。為此我們使用 HTTP 的 `PATCH` 操作。\n\n在程式碼中，我們會取得一個只包含用戶端有傳送的資料的 `dict`，不包含只是因為有預設值而存在的欄位。為了達成這點，我們使用 `exclude_unset=True`。這是關鍵。🪄\n\n然後我們使用 `hero_db.sqlmodel_update(hero_data)` 以 `hero_data` 的資料更新 `hero_db`。\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *}\n\n### 再次刪除 Hero { #delete-a-hero-again }\n\n「刪除」 hero 基本上維持不變。\n\n我們不會為了重構而重構一切。😅\n\n{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *}\n\n### 再次執行應用 { #run-the-app-again }\n\n你可以再次執行應用：\n\n<div class=\"termy\">\n\n```console\n$ fastapi dev\n\n<span style=\"color: green;\">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\n```\n\n</div>\n\n如果你前往 `/docs` 的 API UI，你會看到它已更新，建立 hero 時不再期待從用戶端接收 `id`，等等。\n\n<div class=\"screenshot\">\n<img src=\"/img/tutorial/sql-databases/image02.png\">\n</div>\n\n## 總結 { #recap }\n\n你可以使用 [SQLModel](https://sqlmodel.tiangolo.com/) 與 SQL 資料庫互動，並用「資料模型」與「資料表模型」讓程式碼更簡潔。\n\n你可以在 SQLModel 文件學到更多內容，這裡還有一份更長的 [使用 SQLModel 與 FastAPI 的教學](https://sqlmodel.tiangolo.com/tutorial/fastapi/)。🚀\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/static-files.md",
    "content": "# 靜態檔案 { #static-files }\n\n你可以使用 `StaticFiles` 從某個目錄自動提供靜態檔案。\n\n## 使用 `StaticFiles` { #use-staticfiles }\n\n- 匯入 `StaticFiles`。\n- 在特定路徑上「掛載」一個 `StaticFiles()` 實例。\n\n{* ../../docs_src/static_files/tutorial001_py310.py hl[2,6] *}\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.staticfiles import StaticFiles`。\n\n**FastAPI** 為了方便開發者，提供與 `starlette.staticfiles` 相同的介面作為 `fastapi.staticfiles`。但它其實是直接來自 Starlette。\n\n///\n\n### 什麼是「掛載」 { #what-is-mounting }\n\n「掛載（mounting）」是指在特定路徑下加入一個完整且「獨立」的應用，之後所有該路徑下的子路徑都由它處理。\n\n這與使用 `APIRouter` 不同，因為被掛載的應用是完全獨立的。主應用的 OpenAPI 與文件不會包含掛載應用的任何內容，等等。\n\n你可以在[進階使用者指南](../advanced/index.md)中閱讀更多相關內容。\n\n## 細節 { #details }\n\n第一個 `\"/static\"` 指的是這個「子應用」要被「掛載」的子路徑。因此，任何以 `\"/static\"` 開頭的路徑都會由它處理。\n\n`directory=\"static\"` 指向包含你靜態檔案的目錄名稱。\n\n`name=\"static\"` 為它指定一個可供 **FastAPI** 內部使用的名稱。\n\n以上參數都不一定要是 \"`static`\"，請依你的應用需求與細節調整。\n\n## 更多資訊 { #more-info }\n\n如需更多細節與選項，請參考 [Starlette 關於靜態檔案的文件](https://www.starlette.dev/staticfiles/)。\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/stream-json-lines.md",
    "content": "# 串流 JSON Lines { #stream-json-lines }\n\n當你有一連串資料想以「**串流**」方式傳送時，可以使用 **JSON Lines**。\n\n/// info\n\n在 FastAPI 0.134.0 新增。\n\n///\n\n## 什麼是串流？ { #what-is-a-stream }\n\n「**Streaming**」資料表示你的應用會在整個資料序列尚未完全準備好之前，就開始將資料項目傳送給用戶端。\n\n也就是說，它會先送出第一個項目，用戶端接收並開始處理時，你的應用可能仍在產生下一個項目。\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Client\n\n    App->>App: Produce Item 1\n    App->>Client: Send Item 1\n    App->>App: Produce Item 2\n    Client->>Client: Process Item 1\n    App->>Client: Send Item 2\n    App->>App: Produce Item 3\n    Client->>Client: Process Item 2\n    App->>Client: Send Item 3\n    Client->>Client: Process Item 3\n    Note over App: Keeps producing...\n    Note over Client: Keeps consuming...\n```\n\n它甚至可以是無限串流，你可以一直持續傳送資料。\n\n## JSON Lines { #json-lines }\n\n在這些情況下，常見做法是傳送「**JSON Lines**」，這是一種每一行各包含一個 JSON 物件的格式。\n\n回應的 content type 會是 `application/jsonl`（而不是 `application/json`），而本體內容會像這樣：\n\n```json\n{\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"}\n{\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"}\n{\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"}\n```\n\n它和 JSON 陣列（相當於 Python 的 list）很像，但不同於用 `[]` 包起來並以 `,` 分隔項目，它是每一行各放一個 JSON 物件，彼此以換行字元分隔。\n\n/// info\n\n重點在於你的應用能夠逐行產生資料，同時用戶端在消耗前一行的資料。\n\n///\n\n/// note | 技術細節\n\n由於每個 JSON 物件會以換行分隔，它們的內容中不能包含實際的換行字元，但可以包含跳脫後的換行（`\\n`），這是 JSON 標準的一部分。\n\n不過通常你不需要為此煩惱，這些都會自動處理，繼續往下看吧。🤓\n\n///\n\n## 使用情境 { #use-cases }\n\n你可以用這種方式從 **AI LLM** 服務、**日誌**或**遙測**串流資料，或任何能以 **JSON** 項目結構化的其他型態資料。\n\n/// tip\n\n如果你想串流二進位資料，例如影像或音訊，請參考進階指南：[串流資料](../advanced/stream-data.md)。\n\n///\n\n## 使用 FastAPI 串流 JSON Lines { #stream-json-lines-with-fastapi }\n\n要用 FastAPI 串流 JSON Lines，你可以在你的*路徑操作函式*中改用 `yield` 逐一產生項目，而不是用 `return`。\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[24] *}\n\n如果你要回傳的每個 JSON 項目型別都是 `Item`（一個 Pydantic 模型），而且該函式是 async，你可以將回傳型別宣告為 `AsyncIterable[Item]`：\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[1:24] hl[9:11,22] *}\n\n如果你宣告了回傳型別，FastAPI 會用它來進行資料的**驗證**、在 OpenAPI 中**文件化**、**過濾**，並使用 Pydantic 進行**序列化**。\n\n/// tip\n\n由於 Pydantic 會在 **Rust** 端進行序列化，宣告回傳型別可獲得比未宣告時高得多的**效能**。\n\n///\n\n### 非 async 的*路徑操作函式* { #non-async-path-operation-functions }\n\n你也可以用一般的 `def` 函式（沒有 `async`），同樣用 `yield`。\n\nFastAPI 會確保正確執行，不會阻塞事件迴圈。\n\n因為這種情況下函式不是 async，正確的回傳型別會是 `Iterable[Item]`：\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[27:30] hl[28] *}\n\n### 不宣告回傳型別 { #no-return-type }\n\n你也可以省略回傳型別。此時 FastAPI 會使用 [`jsonable_encoder`](./encoder.md) 將資料轉換為可序列化為 JSON 的形式，然後以 JSON Lines 傳送。\n\n{* ../../docs_src/stream_json_lines/tutorial001_py310.py ln[33:36] hl[34] *}\n\n## 伺服器推播事件（SSE） { #server-sent-events-sse }\n\nFastAPI 也原生支援 Server-Sent Events（SSE），它們與此相當類似，但多了幾個細節。你可以在下一章學到更多：[伺服器推播事件（SSE）](server-sent-events.md)。🤓\n"
  },
  {
    "path": "docs/zh-hant/docs/tutorial/testing.md",
    "content": "# 測試 { #testing }\n\n多虧了 [Starlette](https://www.starlette.dev/testclient/)，測試 **FastAPI** 應用既簡單又好用。\n\n它是基於 [HTTPX](https://www.python-httpx.org) 打造，而 HTTPX 的設計又參考了 Requests，所以用起來非常熟悉、直覺。\n\n借助它，你可以直接用 [pytest](https://docs.pytest.org/) 來測試 **FastAPI**。\n\n## 使用 `TestClient` { #using-testclient }\n\n/// info\n\n要使用 `TestClient`，請先安裝 [`httpx`](https://www.python-httpx.org)。\n\n請先建立並啟用一個[虛擬環境](../virtual-environments.md)，然後安裝，例如：\n\n```console\n$ pip install httpx\n```\n\n///\n\n匯入 `TestClient`。\n\n建立一個 `TestClient`，把你的 **FastAPI** 應用傳入其中。\n\n建立名稱以 `test_` 開頭的函式（這是 `pytest` 的慣例）。\n\n像使用 `httpx` 一樣使用 `TestClient` 物件。\n\n用簡單的 `assert` 敘述搭配標準的 Python 運算式來檢查（同樣是 `pytest` 的標準用法）。\n\n{* ../../docs_src/app_testing/tutorial001_py310.py hl[2,12,15:18] *}\n\n/// tip\n\n注意測試函式是一般的 `def`，不是 `async def`。\n\n而且對 client 的呼叫也都是一般呼叫，不需要使用 `await`。\n\n這讓你可以直接使用 `pytest`，不必費心處理非同步。\n\n///\n\n/// note | 技術細節\n\n你也可以使用 `from starlette.testclient import TestClient`。\n\n**FastAPI** 為了方便開發者，也提供與 `starlette.testclient` 相同的 `fastapi.testclient`。但它其實直接來自 Starlette。\n\n///\n\n/// tip\n\n如果你想在測試中呼叫其他 `async` 函式，而不只是對 FastAPI 應用發送請求（例如非同步的資料庫函式），請參考進階教學中的[非同步測試](../advanced/async-tests.md)。\n\n///\n\n## 分離測試 { #separating-tests }\n\n在真實專案中，你大概會把測試放在不同的檔案中。\n\n你的 **FastAPI** 應用也可能由多個檔案/模組組成，等等。\n\n### **FastAPI** 應用檔案 { #fastapi-app-file }\n\n假設你的檔案結構如[更大型的應用](bigger-applications.md)所述：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   └── main.py\n```\n\n在 `main.py` 檔案中有你的 **FastAPI** 應用：\n\n\n{* ../../docs_src/app_testing/app_a_py310/main.py *}\n\n### 測試檔案 { #testing-file }\n\n然後你可以建立一個 `test_main.py` 放你的測試。它可以與應用位於同一個 Python 套件（同一個包含 `__init__.py` 的目錄）：\n\n``` hl_lines=\"5\"\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n因為這個檔案在同一個套件中，你可以使用相對匯入，從 `main` 模組（`main.py`）匯入 `app` 這個物件：\n\n{* ../../docs_src/app_testing/app_a_py310/test_main.py hl[3] *}\n\n\n...然後測試的程式碼就和先前一樣。\n\n## 測試：進階範例 { #testing-extended-example }\n\n現在我們延伸這個範例並加入更多細節，看看如何測試不同部分。\n\n### 擴充的 **FastAPI** 應用檔案 { #extended-fastapi-app-file }\n\n沿用先前相同的檔案結構：\n\n```\n.\n├── app\n│   ├── __init__.py\n│   ├── main.py\n│   └── test_main.py\n```\n\n假設現在你的 **FastAPI** 應用所在的 `main.py` 有一些其他的路徑操作（path operations）。\n\n它有一個可能回傳錯誤的 `GET` 操作。\n\n它有一個可能回傳多種錯誤的 `POST` 操作。\n\n兩個路徑操作都需要一個 `X-Token` 標頭（header）。\n\n{* ../../docs_src/app_testing/app_b_an_py310/main.py *}\n\n### 擴充的測試檔案 { #extended-testing-file }\n\n接著你可以把 `test_main.py` 更新為擴充後的測試：\n\n{* ../../docs_src/app_testing/app_b_an_py310/test_main.py *}\n\n\n每當你需要在請求中讓 client 帶一些資料，但不確定該怎麼做時，你可以搜尋（Google）在 `httpx` 要如何傳遞，甚至用 Requests 怎麼做，因為 HTTPX 的設計是基於 Requests。\n\n然後在你的測試中做一樣的事即可。\n\n例如：\n\n* 要傳遞路徑或查詢參數，直接把它加在 URL 上。\n* 要傳遞 JSON 本文，將 Python 物件（例如 `dict`）傳給 `json` 參數。\n* 如果需要送出表單資料（Form Data）而不是 JSON，改用 `data` 參數。\n* 要傳遞標頭（headers），在 `headers` 參數中放一個 `dict`。\n* 對於 Cookie（cookies），在 `cookies` 參數中放一個 `dict`。\n\n關於如何把資料傳給後端（使用 `httpx` 或 `TestClient`），更多資訊請參考 [HTTPX 文件](https://www.python-httpx.org)。\n\n/// info\n\n請注意，`TestClient` 接收的是可轉為 JSON 的資料，而不是 Pydantic models。\n\n如果你的測試裡有一個 Pydantic model，並想在測試時把它的資料送給應用，你可以使用[JSON 相容編碼器](encoder.md)中介紹的 `jsonable_encoder`。\n\n///\n\n## 執行 { #run-it }\n\n接下來，你只需要安裝 `pytest`。\n\n請先建立並啟用一個[虛擬環境](../virtual-environments.md)，然後安裝，例如：\n\n<div class=\"termy\">\n\n```console\n$ pip install pytest\n\n---> 100%\n```\n\n</div>\n\n它會自動偵測檔案與測試、執行它們，並把結果回報給你。\n\n用以下指令執行測試：\n\n<div class=\"termy\">\n\n```console\n$ pytest\n\n================ test session starts ================\nplatform linux -- Python 3.6.9, pytest-5.3.5, py-1.8.1, pluggy-0.13.1\nrootdir: /home/user/code/superawesome-cli/app\nplugins: forked-1.1.3, xdist-1.31.0, cov-2.8.1\ncollected 6 items\n\n---> 100%\n\ntest_main.py <span style=\"color: green; white-space: pre;\">......                            [100%]</span>\n\n<span style=\"color: green;\">================= 1 passed in 0.03s =================</span>\n```\n\n</div>\n"
  },
  {
    "path": "docs/zh-hant/docs/virtual-environments.md",
    "content": "# 虛擬環境 { #virtual-environments }\n\n當你在 Python 專案中工作時，你可能會需要使用一個**虛擬環境**（或類似的機制）來隔離你為每個專案安裝的套件。\n\n/// info\n\n如果你已經了解虛擬環境，知道如何建立和使用它們，你可以考慮跳過這一部分。🤓\n\n///\n\n/// tip\n\n**虛擬環境**和**環境變數**是不同的。\n\n**環境變數**是系統中的一個變數，可以被程式使用。\n\n**虛擬環境**是一個包含一些檔案的目錄。\n\n///\n\n/// info\n\n這個頁面將教你如何使用**虛擬環境**以及了解它們的工作原理。\n\n如果你計畫使用一個**可以為你管理一切的工具**（包括安裝 Python），試試 [uv](https://github.com/astral-sh/uv)。\n\n///\n\n## 建立一個專案 { #create-a-project }\n\n首先，為你的專案建立一個目錄。\n\n我通常會在我的主目錄下建立一個名為 `code` 的目錄。\n\n在這個目錄下，我再為每個專案建立一個目錄。\n\n<div class=\"termy\">\n\n```console\n// 進入主目錄\n$ cd\n// 建立一個用於存放所有程式碼專案的目錄\n$ mkdir code\n// 進入 code 目錄\n$ cd code\n// 建立一個用於存放這個專案的目錄\n$ mkdir awesome-project\n// 進入這個專案的目錄\n$ cd awesome-project\n```\n\n</div>\n\n## 建立一個虛擬環境 { #create-a-virtual-environment }\n\n在開始一個 Python 專案的**第一時間**，**<dfn title=\"還有其他選項，這是一個簡單的指引\">在你的專案內部</dfn>**建立一個虛擬環境。\n\n/// tip\n\n你只需要**在每個專案中操作一次**，而不是每次工作時都操作。\n\n///\n\n//// tab | `venv`\n\n你可以使用 Python 自帶的 `venv` 模組來建立一個虛擬環境。\n\n<div class=\"termy\">\n\n```console\n$ python -m venv .venv\n```\n\n</div>\n\n/// details | 上述命令的含義\n\n* `python`: 使用名為 `python` 的程式\n* `-m`: 以腳本的方式呼叫一個模組，我們將告訴它接下來使用哪個模組\n* `venv`: 使用名為 `venv` 的模組，這個模組通常隨 Python 一起安裝\n* `.venv`: 在新目錄 `.venv` 中建立虛擬環境\n\n///\n\n////\n\n//// tab | `uv`\n\n如果你安裝了 [`uv`](https://github.com/astral-sh/uv)，你也可以使用它來建立一個虛擬環境。\n\n<div class=\"termy\">\n\n```console\n$ uv venv\n```\n\n</div>\n\n/// tip\n\n預設情況下，`uv` 會在一個名為 `.venv` 的目錄中建立一個虛擬環境。\n\n但你可以透過傳遞一個額外的引數來自訂它，指定目錄的名稱。\n\n///\n\n////\n\n這個命令會在一個名為 `.venv` 的目錄中建立一個新的虛擬環境。\n\n/// details | `.venv`，或是其他名稱\n\n你可以在不同的目錄下建立虛擬環境，但通常我們會把它命名為 `.venv`。\n\n///\n\n## 啟動虛擬環境 { #activate-the-virtual-environment }\n\n啟動新的虛擬環境來確保你運行的任何 Python 指令或安裝的套件都能使用到它。\n\n/// tip\n\n**每次**開始一個**新的終端會話**來在這個專案工作時，你都需要執行這個操作。\n\n///\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\n或者，如果你在 Windows 上使用 Bash（例如 [Git Bash](https://gitforwindows.org/)）：\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n/// tip\n\n每次你在這個環境中安裝一個**新的套件**時，都需要**重新啟動**這個環境。\n\n這麼做確保了當你使用一個由這個套件安裝的**終端（<abbr title=\"command line interface - 命令列介面\">CLI</abbr>）程式**時，你使用的是你的虛擬環境中的程式，而不是全域安裝、可能版本不同的程式。\n\n///\n\n## 檢查虛擬環境是否啟動 { #check-the-virtual-environment-is-active }\n\n檢查虛擬環境是否啟動（前面的指令是否生效）。\n\n/// tip\n\n這是**非必需的**，但這是一個很好的方法，可以**檢查**一切是否按預期工作，以及你是否使用了你打算使用的虛擬環境。\n\n///\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n如果它顯示了在你專案（在這個例子中是 `awesome-project`）的 `.venv/bin/python` 中的 `python` 二進位檔案，那麼它就生效了。🎉\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n如果它顯示了在你專案（在這個例子中是 `awesome-project`）的 `.venv\\Scripts\\python` 中的 `python` 二進位檔案，那麼它就生效了。🎉\n\n////\n\n## 升級 `pip` { #upgrade-pip }\n\n/// tip\n\n如果你使用 [`uv`](https://github.com/astral-sh/uv) 來安裝內容，而不是 `pip`，那麼你就不需要升級 `pip`。😎\n\n///\n\n如果你使用 `pip` 來安裝套件（它是 Python 的預設元件），你應該將它**升級**到最新版本。\n\n在安裝套件時出現的許多奇怪的錯誤都可以透過先升級 `pip` 來解決。\n\n/// tip\n\n通常你只需要在建立虛擬環境後**執行一次**這個操作。\n\n///\n\n確保虛擬環境是啟動的（使用上面的指令），然後運行：\n\n<div class=\"termy\">\n\n```console\n$ python -m pip install --upgrade pip\n\n---> 100%\n```\n\n</div>\n\n/// tip | 注意\n\n有時你在嘗試升級 pip 時，可能會遇到 **`No module named pip`** 的錯誤。\n\n如果發生這種情況，請用下面的指令安裝並升級 pip：\n\n<div class=\"termy\">\n\n```console\n$ python -m ensurepip --upgrade\n\n---> 100%\n```\n\n</div>\n\n此指令會在未安裝 pip 時為你安裝它，並確保安裝的 pip 版本至少與 `ensurepip` 所提供的版本一樣新。\n\n///\n\n## 加入 `.gitignore` { #add-gitignore }\n\n如果你使用 **Git**（這是你應該使用的），加入一個 `.gitignore` 檔案來排除你的 `.venv` 中的所有內容。\n\n/// tip\n\n如果你使用 [`uv`](https://github.com/astral-sh/uv) 來建立虛擬環境，它會自動為你完成這個操作，你可以跳過這一步。😎\n\n///\n\n/// tip\n\n通常你只需要在建立虛擬環境後**執行一次**這個操作。\n\n///\n\n<div class=\"termy\">\n\n```console\n$ echo \"*\" > .venv/.gitignore\n```\n\n</div>\n\n/// details | 上述指令的含義\n\n-   `echo \"*\"`: 將在終端中「顯示」文本 `*`（接下來的部分會對這個操作進行一些修改）\n-   `>`: 使左邊的指令顯示到終端的任何內容實際上都不會被顯示，而是會被寫入到右邊的檔案中\n-   `.gitignore`: 被寫入文本的檔案的名稱\n\n而 `*` 對於 Git 來說意味著「所有內容」。所以，它會忽略 `.venv` 目錄中的所有內容。\n\n該指令會建立一個名為 .gitignore 的檔案，內容如下：\n\n```gitignore\n*\n```\n\n///\n\n## 安裝套件 { #install-packages }\n\n在啟用虛擬環境後，你可以在其中安裝套件。\n\n/// tip\n\n當你需要安裝或升級套件時，執行本操作**一次**；\n\n如果你需要再升級版本或新增套件，你可以**再次執行此操作**。\n\n///\n\n### 直接安裝套件 { #install-packages-directly }\n\n如果你急於安裝，不想使用檔案來聲明專案的套件依賴，你可以直接安裝它們。\n\n/// tip\n\n將程式所需的套件及其版本放在檔案中（例如 `requirements.txt` 或 `pyproject.toml`）是個好（而且非常好）的主意。\n\n///\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install \"fastapi[standard]\"\n\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\n如果你有 [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n////\n\n### 從 `requirements.txt` 安裝 { #install-from-requirements-txt }\n\n如果你有一個 `requirements.txt` 檔案，你可以使用它來安裝其中的套件。\n\n//// tab | `pip`\n\n<div class=\"termy\">\n\n```console\n$ pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n//// tab | `uv`\n\n如果你有 [`uv`](https://github.com/astral-sh/uv):\n\n<div class=\"termy\">\n\n```console\n$ uv pip install -r requirements.txt\n---> 100%\n```\n\n</div>\n\n////\n\n/// details | 關於 `requirements.txt`\n\n一個包含一些套件的 `requirements.txt` 檔案看起來應該是這樣的：\n\n```requirements.txt\nfastapi[standard]==0.113.0\npydantic==2.8.0\n```\n\n///\n\n## 執行程式 { #run-your-program }\n\n在啟用虛擬環境後，你可以執行你的程式，它將使用虛擬環境中的 Python 和你在其中安裝的套件。\n\n<div class=\"termy\">\n\n```console\n$ python main.py\n\nHello World\n```\n\n</div>\n\n## 設定編輯器 { #configure-your-editor }\n\n你可能會用到編輯器，請確保設定它使用你建立的相同虛擬環境（它可能會自動偵測到），以便你可以獲得自動完成和內嵌錯誤提示。\n\n例如：\n\n* [VS Code](https://code.visualstudio.com/docs/python/environments#_select-and-activate-an-environment)\n* [PyCharm](https://www.jetbrains.com/help/pycharm/creating-virtual-environment.html)\n\n/// tip\n\n通常你只需要在建立虛擬環境時執行此操作**一次**。\n\n///\n\n## 退出虛擬環境 { #deactivate-the-virtual-environment }\n\n當你完成工作後，你可以**退出**虛擬環境。\n\n<div class=\"termy\">\n\n```console\n$ deactivate\n```\n\n</div>\n\n這樣，當你執行 `python` 時它不會嘗試從已安裝套件的虛擬環境中執行。\n\n## 開始工作 { #ready-to-work }\n\n現在你已經準備好開始你的工作了。\n\n\n\n/// tip\n\n你想要理解上面的所有內容嗎？\n\n繼續閱讀。👇🤓\n\n///\n\n## 為什麼要使用虛擬環境 { #why-virtual-environments }\n\n你需要安裝 [Python](https://www.python.org/) 才能使用 FastAPI。\n\n接下來，你需要**安裝** FastAPI 以及你想使用的其他**套件**。\n\n要安裝套件，你通常會使用隨 Python 一起提供的 `pip` 指令（或類似的替代工具）。\n\n然而，如果你直接使用 `pip`，套件將會安裝在你的**全域 Python 環境**中（即 Python 的全域安裝）。\n\n### 存在的問題 { #the-problem }\n\n那麼，在全域 Python 環境中安裝套件有什麼問題呢？\n\n有時候，你可能會開發許多不同的程式，而這些程式各自依賴於**不同的套件**；有些專案甚至需要依賴於**相同套件的不同版本**。😱\n\n例如，你可能會建立一個名為 `philosophers-stone` 的專案，這個程式依賴於另一個名為 **`harry` 的套件，並使用版本 `1`**。因此，你需要安裝 `harry`。\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|需要| harry-1[harry v1]\n```\n\n然而，在此之後，你又建立了另一個名為 `prisoner-of-azkaban` 的專案，而這個專案也依賴於 `harry`，但需要的是 **`harry` 版本 `3`**。\n\n```mermaid\nflowchart LR\n    azkaban(prisoner-of-azkaban) --> |需要| harry-3[harry v3]\n```\n\n現在的問題是，如果你在全域環境中安裝套件而不是在本地**虛擬環境**中，你將面臨選擇安裝哪個版本的 `harry` 的困境。\n\n如果你想運行 `philosophers-stone`，你需要先安裝 `harry` 版本 `1`，例如：\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==1\"\n```\n\n</div>\n\n然後你會在全域 Python 環境中安裝 `harry` 版本 `1`。\n\n```mermaid\nflowchart LR\n    subgraph global[全域環境]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[專案 philosophers-stone]\n        stone(philosophers-stone) -->|需要| harry-1\n    end\n```\n\n但如果你想運行 `prisoner-of-azkaban`，你需要解除安裝 `harry` 版本 `1` 並安裝 `harry` 版本 `3`（或者只要你安裝版本 `3`，版本 `1` 就會自動移除）。\n\n<div class=\"termy\">\n\n```console\n$ pip install \"harry==3\"\n```\n\n</div>\n\n於是，你在全域 Python 環境中安裝了 `harry` 版本 `3`。\n\n如果你再次嘗試運行 `philosophers-stone`，很可能會**無法正常運作**，因為它需要的是 `harry` 版本 `1`。\n\n```mermaid\nflowchart LR\n    subgraph global[全域環境]\n        harry-1[<strike>harry v1</strike>]\n        style harry-1 fill:#ccc,stroke-dasharray: 5 5\n        harry-3[harry v3]\n    end\n    subgraph stone-project[專案 philosophers-stone]\n        stone(philosophers-stone) -.-x|⛔️| harry-1\n    end\n    subgraph azkaban-project[專案 prisoner-of-azkaban]\n        azkaban(prisoner-of-azkaban) --> |需要| harry-3\n    end\n```\n\n/// tip\n\nPython 套件在推出**新版本**時通常會儘量**避免破壞性更改**，但最好還是要謹慎，在安裝新版本前進行測試，以確保一切能正常運行。\n\n///\n\n現在，想像一下如果有**許多**其他**套件**，它們都是你的**專案所依賴的**。這樣是非常難以管理的。你可能會發現有些專案使用了一些**不相容的套件版本**，而無法得知為什麼某些程式無法正常運作。\n\n此外，取決於你的操作系統（例如 Linux、Windows、macOS），它可能已經預先安裝了 Python。在這種情況下，它可能已經有一些系統所需的套件和特定版本。如果你在全域 Python 環境中安裝套件，可能會**破壞**某些隨作業系統一起安裝的程式。\n\n## 套件安裝在哪裡 { #where-are-packages-installed }\n\n當你安裝 Python 時，它會在你的電腦中建立一些目錄並放置一些檔案。\n\n其中一些目錄專門用來存放你所安裝的所有套件。\n\n當你運行：\n\n<div class=\"termy\">\n\n```console\n// 先別去運行這個指令，這只是個示例 🤓\n$ pip install \"fastapi[standard]\"\n---> 100%\n```\n\n</div>\n\n這會從 [PyPI](https://pypi.org/project/fastapi/) 下載一個壓縮檔案，其中包含 FastAPI 的程式碼。\n\n它還會**下載** FastAPI 所依賴的其他套件的檔案。\n\n接著，它會**解壓**所有這些檔案，並將它們放在你的電腦中的某個目錄中。\n\n預設情況下，這些下載和解壓的檔案會放置於隨 Python 安裝的目錄中，即**全域環境**。\n\n## 什麼是虛擬環境 { #what-are-virtual-environments }\n\n解決套件都安裝在全域環境中的問題方法是為你所做的每個專案使用一個**虛擬環境**。\n\n虛擬環境是一個**目錄**，與全域環境非常相似，你可以在其中針對某個專案安裝套件。\n\n這樣，每個專案都會有自己的虛擬環境（`.venv` 目錄），其中包含自己的套件。\n\n```mermaid\nflowchart TB\n    subgraph stone-project[專案 philosophers-stone]\n        stone(philosophers-stone) --->|需要| harry-1\n        subgraph venv1[.venv]\n            harry-1[harry v1]\n        end\n    end\n    subgraph azkaban-project[專案 prisoner-of-azkaban]\n        azkaban(prisoner-of-azkaban) --->|需要| harry-3\n        subgraph venv2[.venv]\n            harry-3[harry v3]\n        end\n    end\n    stone-project ~~~ azkaban-project\n```\n\n## 啟用虛擬環境意味著什麼 { #what-does-activating-a-virtual-environment-mean }\n\n當你啟用了虛擬環境，例如：\n\n//// tab | Linux, macOS\n\n<div class=\"termy\">\n\n```console\n$ source .venv/bin/activate\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ .venv\\Scripts\\Activate.ps1\n```\n\n</div>\n\n////\n\n//// tab | Windows Bash\n\n或者如果你在 Windows 上使用 Bash（例如 [Git Bash](https://gitforwindows.org/)）：\n\n<div class=\"termy\">\n\n```console\n$ source .venv/Scripts/activate\n```\n\n</div>\n\n////\n\n這個命令會建立或修改一些[環境變數](environment-variables.md)，這些環境變數將在接下來的指令中可用。\n\n其中之一是 `PATH` 變數。\n\n/// tip\n\n你可以在 [環境變數](environment-variables.md#path-environment-variable) 部分了解更多關於 `PATH` 環境變數的內容。\n\n///\n\n啟用虛擬環境會將其路徑 `.venv/bin`（在 Linux 和 macOS 上）或 `.venv\\Scripts`（在 Windows 上）加入到 `PATH` 環境變數中。\n\n假設在啟用環境之前，`PATH` 變數看起來像這樣：\n\n//// tab | Linux, macOS\n\n```plaintext\n/usr/bin:/bin:/usr/sbin:/sbin\n```\n\n這意味著系統會在以下目錄中查找程式：\n\n* `/usr/bin`\n* `/bin`\n* `/usr/sbin`\n* `/sbin`\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Windows\\System32\n```\n\n這意味著系統會在以下目錄中查找程式：\n\n* `C:\\Windows\\System32`\n\n////\n\n啟用虛擬環境後，`PATH` 變數會變成這樣：\n\n//// tab | Linux, macOS\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\n這意味著系統現在會首先在以下目錄中查找程式：\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin\n```\n\n然後再在其他目錄中查找。\n\n因此，當你在終端機中輸入 `python` 時，系統會在以下目錄中找到 Python 程式：\n\n```plaintext\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n並使用這個。\n\n////\n\n//// tab | Windows\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts;C:\\Windows\\System32\n```\n\n這意味著系統現在會首先在以下目錄中查找程式：\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\n```\n\n然後再在其他目錄中查找。\n\n因此，當你在終端機中輸入 `python` 時，系統會在以下目錄中找到 Python 程式：\n\n```plaintext\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n並使用這個。\n\n////\n\n一個重要的細節是，虛擬環境路徑會被放在 `PATH` 變數的**開頭**。系統會在找到任何其他可用的 Python **之前**找到它。這樣，當你運行 `python` 時，它會使用**虛擬環境中的** Python，而不是任何其他 `python`（例如，全域環境中的 `python`）。\n\n啟用虛擬環境還會改變其他一些內容，但這是它所做的最重要的事情之一。\n\n## 檢查虛擬環境 { #checking-a-virtual-environment }\n\n當你檢查虛擬環境是否啟動時，例如：\n\n//// tab | Linux, macOS, Windows Bash\n\n<div class=\"termy\">\n\n```console\n$ which python\n\n/home/user/code/awesome-project/.venv/bin/python\n```\n\n</div>\n\n////\n\n//// tab | Windows PowerShell\n\n<div class=\"termy\">\n\n```console\n$ Get-Command python\n\nC:\\Users\\user\\code\\awesome-project\\.venv\\Scripts\\python\n```\n\n</div>\n\n////\n\n這表示將使用的 `python` 程式是**在虛擬環境中**的那一個。\n\n在 Linux 和 macOS 中使用 `which`，在 Windows PowerShell 中使用 `Get-Command`。\n\n這個指令的運作方式是，它會在 `PATH` 環境變數中搜尋，依序**逐個路徑**查找名為 `python` 的程式。一旦找到，它會**顯示該程式的路徑**。\n\n最重要的是，當你呼叫 `python` 時，將執行的就是這個確切的 \"`python`\"。\n\n因此，你可以確認是否在正確的虛擬環境中。\n\n/// tip\n\n啟動一個虛擬環境，取得一個 Python，然後**切換到另一個專案**是件很容易的事；\n\n但如果第二個專案**無法正常運作**，那可能是因為你使用了來自其他專案的虛擬環境的、**不正確的 Python**。\n\n因此，檢查正在使用的 `python` 是非常實用的。🤓\n\n///\n\n## 為什麼要停用虛擬環境 { #why-deactivate-a-virtual-environment }\n\n例如，你可能正在一個專案 `philosophers-stone` 上工作，**啟動了該虛擬環境**，安裝了套件並使用了該環境，\n\n然後你想要在**另一個專案** `prisoner-of-azkaban` 上工作，\n\n你進入那個專案：\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n```\n\n</div>\n\n如果你不去停用 `philosophers-stone` 的虛擬環境，當你在終端中執行 `python` 時，它會嘗試使用 `philosophers-stone` 中的 Python。\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n$ python main.py\n\n// 匯入 sirius 錯誤，未安裝 😱\nTraceback (most recent call last):\n    File \"main.py\", line 1, in <module>\n        import sirius\n```\n\n</div>\n\n但如果你停用虛擬環境並啟用 `prisoner-of-azkaban` 的新虛擬環境，那麼當你執行 `python` 時，它會使用 `prisoner-of-azkaban` 中虛擬環境的 Python。\n\n<div class=\"termy\">\n\n```console\n$ cd ~/code/prisoner-of-azkaban\n\n// 你不需要在舊目錄中操作停用，你可以在任何地方操作停用，甚至在切換到另一個專案之後 😎\n$ deactivate\n\n// 啟用 prisoner-of-azkaban/.venv 中的虛擬環境 🚀\n$ source .venv/bin/activate\n\n// 現在當你執行 python 時，它會在這個虛擬環境中找到已安裝的 sirius 套件 ✨\n$ python main.py\n\nI solemnly swear 🐺\n```\n\n</div>\n\n## 替代方案 { #alternatives }\n\n這是一個簡單的指南，幫助你入門並教會你如何理解一切**底層**的原理。\n\n有許多**替代方案**來管理虛擬環境、套件依賴（requirements）、專案。\n\n當你準備好並想要使用一個工具來**管理整個專案**、套件依賴、虛擬環境等，建議你嘗試 [uv](https://github.com/astral-sh/uv)。\n\n`uv` 可以執行許多操作，它可以：\n\n* 為你**安裝 Python**，包括不同的版本\n* 為你的專案管理**虛擬環境**\n* 安裝**套件**\n* 為你的專案管理套件的**依賴和版本**\n* 確保你有一個**精確**的套件和版本集合來安裝，包括它們的依賴項，這樣你可以確保專案在生產環境中運行的狀態與開發時在你的電腦上運行的狀態完全相同，這被稱為**鎖定**\n* 還有很多其他功能\n\n## 結論 { #conclusion }\n\n如果你讀過並理解了所有這些，現在**你對虛擬環境的了解已超過許多開發者**。🤓\n\n未來當你為看起來複雜的問題除錯時，了解這些細節很可能會有所幫助，你會知道**它是如何在底層運作的**。😎\n"
  },
  {
    "path": "docs/zh-hant/llm-prompt.md",
    "content": "### Target language\n\nTranslate to Traditional Chinese (繁體中文).\n\nLanguage code: zh-hant.\n\n### Grammar and tone\n\n- Use clear, concise technical Traditional Chinese consistent with existing docs.\n- Address the reader naturally (commonly using “你/你的”).\n\n### Headings\n\n- Follow existing Traditional Chinese heading style (short and descriptive).\n- Do not add trailing punctuation to headings.\n\n### Quotes and punctuation\n\n- Keep punctuation style consistent with existing Traditional Chinese docs (they often mix English terms like “FastAPI” with Chinese text).\n- Never change punctuation inside inline code, code blocks, URLs, or file paths.\n- For more details, please follow the [Chinese Copywriting Guidelines](https://github.com/sparanoid/chinese-copywriting-guidelines).\n\n### Ellipsis\n\n- Keep ellipsis style consistent within each document, prefer `...` over `……`.\n- Never change ellipsis in code, URLs, or CLI examples.\n\n### Preferred translations / glossary\n\n- Should avoid using simplified Chinese characters and terms. Always examine if the translation can be easily comprehended by the Traditional Chinese readers.\n- For some Python-specific terms like \"pickle\", \"list\", \"dict\" etc, we don't have to translate them.\n- Use the following preferred translations when they apply in documentation prose:\n\n- request (HTTP): 請求\n- response (HTTP): 回應\n- path operation: 路徑操作\n- path operation function: 路徑操作函式\n\nThe translation can optionally include the original English text only in the first occurrence of each page (e.g. \"路徑操作 (path operation)\") if the translation is hard to be comprehended by most of the Chinese readers.\n\n### `///` admonitions\n\n1) Keep the admonition keyword in English (do not translate `note`, `tip`, etc.).\n2) Many Traditional Chinese docs currently omit titles in `///` blocks; that is OK.\n3) If a generic title is present, prefer these canonical titles:\n\n- `/// note | 注意`\n\nNotes:\n\n- `details` blocks exist; keep `/// details` as-is and translate only the title after `|`.\n- Example canonical titles used in existing docs:\n\n```\n/// details | 上述指令的含義\n```\n\n```\n/// details | 關於 `requirements.txt`\n```\n"
  },
  {
    "path": "docs/zh-hant/mkdocs.yml",
    "content": "INHERIT: ../en/mkdocs.yml\n"
  },
  {
    "path": "docs_src/additional_responses/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/additional_responses/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    id: str\n    value: str\n\n\nclass Message(BaseModel):\n    message: str\n\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\", response_model=Item, responses={404: {\"model\": Message}})\nasync def read_item(item_id: str):\n    if item_id == \"foo\":\n        return {\"id\": \"foo\", \"value\": \"there goes my hero\"}\n    return JSONResponse(status_code=404, content={\"message\": \"Item not found\"})\n"
  },
  {
    "path": "docs_src/additional_responses/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import FileResponse\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    id: str\n    value: str\n\n\napp = FastAPI()\n\n\n@app.get(\n    \"/items/{item_id}\",\n    response_model=Item,\n    responses={\n        200: {\n            \"content\": {\"image/png\": {}},\n            \"description\": \"Return the JSON item or an image.\",\n        }\n    },\n)\nasync def read_item(item_id: str, img: bool | None = None):\n    if img:\n        return FileResponse(\"image.png\", media_type=\"image/png\")\n    else:\n        return {\"id\": \"foo\", \"value\": \"there goes my hero\"}\n"
  },
  {
    "path": "docs_src/additional_responses/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    id: str\n    value: str\n\n\nclass Message(BaseModel):\n    message: str\n\n\napp = FastAPI()\n\n\n@app.get(\n    \"/items/{item_id}\",\n    response_model=Item,\n    responses={\n        404: {\"model\": Message, \"description\": \"The item was not found\"},\n        200: {\n            \"description\": \"Item requested by ID\",\n            \"content\": {\n                \"application/json\": {\n                    \"example\": {\"id\": \"bar\", \"value\": \"The bar tenders\"}\n                }\n            },\n        },\n    },\n)\nasync def read_item(item_id: str):\n    if item_id == \"foo\":\n        return {\"id\": \"foo\", \"value\": \"there goes my hero\"}\n    else:\n        return JSONResponse(status_code=404, content={\"message\": \"Item not found\"})\n"
  },
  {
    "path": "docs_src/additional_responses/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import FileResponse\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    id: str\n    value: str\n\n\nresponses = {\n    404: {\"description\": \"Item not found\"},\n    302: {\"description\": \"The item was moved\"},\n    403: {\"description\": \"Not enough privileges\"},\n}\n\n\napp = FastAPI()\n\n\n@app.get(\n    \"/items/{item_id}\",\n    response_model=Item,\n    responses={**responses, 200: {\"content\": {\"image/png\": {}}}},\n)\nasync def read_item(item_id: str, img: bool | None = None):\n    if img:\n        return FileResponse(\"image.png\", media_type=\"image/png\")\n    else:\n        return {\"id\": \"foo\", \"value\": \"there goes my hero\"}\n"
  },
  {
    "path": "docs_src/additional_status_codes/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/additional_status_codes/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Body, FastAPI, status\nfrom fastapi.responses import JSONResponse\n\napp = FastAPI()\n\nitems = {\"foo\": {\"name\": \"Fighters\", \"size\": 6}, \"bar\": {\"name\": \"Tenders\", \"size\": 3}}\n\n\n@app.put(\"/items/{item_id}\")\nasync def upsert_item(\n    item_id: str,\n    name: Annotated[str | None, Body()] = None,\n    size: Annotated[int | None, Body()] = None,\n):\n    if item_id in items:\n        item = items[item_id]\n        item[\"name\"] = name\n        item[\"size\"] = size\n        return item\n    else:\n        item = {\"name\": name, \"size\": size}\n        items[item_id] = item\n        return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)\n"
  },
  {
    "path": "docs_src/additional_status_codes/tutorial001_py310.py",
    "content": "from fastapi import Body, FastAPI, status\nfrom fastapi.responses import JSONResponse\n\napp = FastAPI()\n\nitems = {\"foo\": {\"name\": \"Fighters\", \"size\": 6}, \"bar\": {\"name\": \"Tenders\", \"size\": 3}}\n\n\n@app.put(\"/items/{item_id}\")\nasync def upsert_item(\n    item_id: str,\n    name: str | None = Body(default=None),\n    size: int | None = Body(default=None),\n):\n    if item_id in items:\n        item = items[item_id]\n        item[\"name\"] = name\n        item[\"size\"] = size\n        return item\n    else:\n        item = {\"name\": name, \"size\": size}\n        items[item_id] = item\n        return JSONResponse(status_code=status.HTTP_201_CREATED, content=item)\n"
  },
  {
    "path": "docs_src/advanced_middleware/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/advanced_middleware/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.middleware.httpsredirect import HTTPSRedirectMiddleware\n\napp = FastAPI()\n\napp.add_middleware(HTTPSRedirectMiddleware)\n\n\n@app.get(\"/\")\nasync def main():\n    return {\"message\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/advanced_middleware/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.middleware.trustedhost import TrustedHostMiddleware\n\napp = FastAPI()\n\napp.add_middleware(\n    TrustedHostMiddleware, allowed_hosts=[\"example.com\", \"*.example.com\"]\n)\n\n\n@app.get(\"/\")\nasync def main():\n    return {\"message\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/advanced_middleware/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.middleware.gzip import GZipMiddleware\n\napp = FastAPI()\n\napp.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=5)\n\n\n@app.get(\"/\")\nasync def main():\n    return \"somebigcontent\"\n"
  },
  {
    "path": "docs_src/app_testing/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/app_testing/app_a_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/app_testing/app_a_py310/main.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_main():\n    return {\"msg\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/app_testing/app_a_py310/test_main.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom .main import app\n\nclient = TestClient(app)\n\n\ndef test_read_main():\n    response = client.get(\"/\")\n    assert response.status_code == 200\n    assert response.json() == {\"msg\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/app_testing/app_b_an_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/app_testing/app_b_an_py310/main.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Header, HTTPException\nfrom pydantic import BaseModel\n\nfake_secret_token = \"coneofsilence\"\n\nfake_db = {\n    \"foo\": {\"id\": \"foo\", \"title\": \"Foo\", \"description\": \"There goes my hero\"},\n    \"bar\": {\"id\": \"bar\", \"title\": \"Bar\", \"description\": \"The bartenders\"},\n}\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    id: str\n    title: str\n    description: str | None = None\n\n\n@app.get(\"/items/{item_id}\", response_model=Item)\nasync def read_main(item_id: str, x_token: Annotated[str, Header()]):\n    if x_token != fake_secret_token:\n        raise HTTPException(status_code=400, detail=\"Invalid X-Token header\")\n    if item_id not in fake_db:\n        raise HTTPException(status_code=404, detail=\"Item not found\")\n    return fake_db[item_id]\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item, x_token: Annotated[str, Header()]) -> Item:\n    if x_token != fake_secret_token:\n        raise HTTPException(status_code=400, detail=\"Invalid X-Token header\")\n    if item.id in fake_db:\n        raise HTTPException(status_code=409, detail=\"Item already exists\")\n    fake_db[item.id] = item.model_dump()\n    return item\n"
  },
  {
    "path": "docs_src/app_testing/app_b_an_py310/test_main.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom .main import app\n\nclient = TestClient(app)\n\n\ndef test_read_item():\n    response = client.get(\"/items/foo\", headers={\"X-Token\": \"coneofsilence\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"id\": \"foo\",\n        \"title\": \"Foo\",\n        \"description\": \"There goes my hero\",\n    }\n\n\ndef test_read_item_bad_token():\n    response = client.get(\"/items/foo\", headers={\"X-Token\": \"hailhydra\"})\n    assert response.status_code == 400\n    assert response.json() == {\"detail\": \"Invalid X-Token header\"}\n\n\ndef test_read_nonexistent_item():\n    response = client.get(\"/items/baz\", headers={\"X-Token\": \"coneofsilence\"})\n    assert response.status_code == 404\n    assert response.json() == {\"detail\": \"Item not found\"}\n\n\ndef test_create_item():\n    response = client.post(\n        \"/items/\",\n        headers={\"X-Token\": \"coneofsilence\"},\n        json={\"id\": \"foobar\", \"title\": \"Foo Bar\", \"description\": \"The Foo Barters\"},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"id\": \"foobar\",\n        \"title\": \"Foo Bar\",\n        \"description\": \"The Foo Barters\",\n    }\n\n\ndef test_create_item_bad_token():\n    response = client.post(\n        \"/items/\",\n        headers={\"X-Token\": \"hailhydra\"},\n        json={\"id\": \"bazz\", \"title\": \"Bazz\", \"description\": \"Drop the bazz\"},\n    )\n    assert response.status_code == 400\n    assert response.json() == {\"detail\": \"Invalid X-Token header\"}\n\n\ndef test_create_existing_item():\n    response = client.post(\n        \"/items/\",\n        headers={\"X-Token\": \"coneofsilence\"},\n        json={\n            \"id\": \"foo\",\n            \"title\": \"The Foo ID Stealers\",\n            \"description\": \"There goes my stealer\",\n        },\n    )\n    assert response.status_code == 409\n    assert response.json() == {\"detail\": \"Item already exists\"}\n"
  },
  {
    "path": "docs_src/app_testing/app_b_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/app_testing/app_b_py310/main.py",
    "content": "from fastapi import FastAPI, Header, HTTPException\nfrom pydantic import BaseModel\n\nfake_secret_token = \"coneofsilence\"\n\nfake_db = {\n    \"foo\": {\"id\": \"foo\", \"title\": \"Foo\", \"description\": \"There goes my hero\"},\n    \"bar\": {\"id\": \"bar\", \"title\": \"Bar\", \"description\": \"The bartenders\"},\n}\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    id: str\n    title: str\n    description: str | None = None\n\n\n@app.get(\"/items/{item_id}\", response_model=Item)\nasync def read_main(item_id: str, x_token: str = Header()):\n    if x_token != fake_secret_token:\n        raise HTTPException(status_code=400, detail=\"Invalid X-Token header\")\n    if item_id not in fake_db:\n        raise HTTPException(status_code=404, detail=\"Item not found\")\n    return fake_db[item_id]\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item, x_token: str = Header()) -> Item:\n    if x_token != fake_secret_token:\n        raise HTTPException(status_code=400, detail=\"Invalid X-Token header\")\n    if item.id in fake_db:\n        raise HTTPException(status_code=409, detail=\"Item already exists\")\n    fake_db[item.id] = item.model_dump()\n    return item\n"
  },
  {
    "path": "docs_src/app_testing/app_b_py310/test_main.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom .main import app\n\nclient = TestClient(app)\n\n\ndef test_read_item():\n    response = client.get(\"/items/foo\", headers={\"X-Token\": \"coneofsilence\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"id\": \"foo\",\n        \"title\": \"Foo\",\n        \"description\": \"There goes my hero\",\n    }\n\n\ndef test_read_item_bad_token():\n    response = client.get(\"/items/foo\", headers={\"X-Token\": \"hailhydra\"})\n    assert response.status_code == 400\n    assert response.json() == {\"detail\": \"Invalid X-Token header\"}\n\n\ndef test_read_nonexistent_item():\n    response = client.get(\"/items/baz\", headers={\"X-Token\": \"coneofsilence\"})\n    assert response.status_code == 404\n    assert response.json() == {\"detail\": \"Item not found\"}\n\n\ndef test_create_item():\n    response = client.post(\n        \"/items/\",\n        headers={\"X-Token\": \"coneofsilence\"},\n        json={\"id\": \"foobar\", \"title\": \"Foo Bar\", \"description\": \"The Foo Barters\"},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"id\": \"foobar\",\n        \"title\": \"Foo Bar\",\n        \"description\": \"The Foo Barters\",\n    }\n\n\ndef test_create_item_bad_token():\n    response = client.post(\n        \"/items/\",\n        headers={\"X-Token\": \"hailhydra\"},\n        json={\"id\": \"bazz\", \"title\": \"Bazz\", \"description\": \"Drop the bazz\"},\n    )\n    assert response.status_code == 400\n    assert response.json() == {\"detail\": \"Invalid X-Token header\"}\n\n\ndef test_create_existing_item():\n    response = client.post(\n        \"/items/\",\n        headers={\"X-Token\": \"coneofsilence\"},\n        json={\n            \"id\": \"foo\",\n            \"title\": \"The Foo ID Stealers\",\n            \"description\": \"There goes my stealer\",\n        },\n    )\n    assert response.status_code == 409\n    assert response.json() == {\"detail\": \"Item already exists\"}\n"
  },
  {
    "path": "docs_src/app_testing/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_main():\n    return {\"msg\": \"Hello World\"}\n\n\nclient = TestClient(app)\n\n\ndef test_read_main():\n    response = client.get(\"/\")\n    assert response.status_code == 200\n    assert response.json() == {\"msg\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/app_testing/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom fastapi.websockets import WebSocket\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def read_main():\n    return {\"msg\": \"Hello World\"}\n\n\n@app.websocket(\"/ws\")\nasync def websocket(websocket: WebSocket):\n    await websocket.accept()\n    await websocket.send_json({\"msg\": \"Hello WebSocket\"})\n    await websocket.close()\n\n\ndef test_read_main():\n    client = TestClient(app)\n    response = client.get(\"/\")\n    assert response.status_code == 200\n    assert response.json() == {\"msg\": \"Hello World\"}\n\n\ndef test_websocket():\n    client = TestClient(app)\n    with client.websocket_connect(\"/ws\") as websocket:\n        data = websocket.receive_json()\n        assert data == {\"msg\": \"Hello WebSocket\"}\n"
  },
  {
    "path": "docs_src/app_testing/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\nitems = {}\n\n\n@app.on_event(\"startup\")\nasync def startup_event():\n    items[\"foo\"] = {\"name\": \"Fighters\"}\n    items[\"bar\"] = {\"name\": \"Tenders\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(item_id: str):\n    return items[item_id]\n\n\ndef test_read_items():\n    with TestClient(app) as client:\n        response = client.get(\"/items/foo\")\n        assert response.status_code == 200\n        assert response.json() == {\"name\": \"Fighters\"}\n"
  },
  {
    "path": "docs_src/app_testing/tutorial004_py310.py",
    "content": "from contextlib import asynccontextmanager\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\nitems = {}\n\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n    items[\"foo\"] = {\"name\": \"Fighters\"}\n    items[\"bar\"] = {\"name\": \"Tenders\"}\n    yield\n    # clean up items\n    items.clear()\n\n\napp = FastAPI(lifespan=lifespan)\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(item_id: str):\n    return items[item_id]\n\n\ndef test_read_items():\n    # Before the lifespan starts, \"items\" is still empty\n    assert items == {}\n\n    with TestClient(app) as client:\n        # Inside the \"with TestClient\" block, the lifespan starts and items added\n        assert items == {\"foo\": {\"name\": \"Fighters\"}, \"bar\": {\"name\": \"Tenders\"}}\n\n        response = client.get(\"/items/foo\")\n        assert response.status_code == 200\n        assert response.json() == {\"name\": \"Fighters\"}\n\n        # After the requests is done, the items are still there\n        assert items == {\"foo\": {\"name\": \"Fighters\"}, \"bar\": {\"name\": \"Tenders\"}}\n\n    # The end of the \"with TestClient\" block simulates terminating the app, so\n    # the lifespan ends and items are cleaned up\n    assert items == {}\n"
  },
  {
    "path": "docs_src/async_tests/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/async_tests/app_a_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/async_tests/app_a_py310/main.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def root():\n    return {\"message\": \"Tomato\"}\n"
  },
  {
    "path": "docs_src/async_tests/app_a_py310/test_main.py",
    "content": "import pytest\nfrom httpx import ASGITransport, AsyncClient\n\nfrom .main import app\n\n\n@pytest.mark.anyio\nasync def test_root():\n    async with AsyncClient(\n        transport=ASGITransport(app=app), base_url=\"http://test\"\n    ) as ac:\n        response = await ac.get(\"/\")\n    assert response.status_code == 200\n    assert response.json() == {\"message\": \"Tomato\"}\n"
  },
  {
    "path": "docs_src/authentication_error_status_code/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/authentication_error_status_code/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI, HTTPException, status\nfrom fastapi.security import HTTPAuthorizationCredentials, HTTPBearer\n\napp = FastAPI()\n\n\nclass HTTPBearer403(HTTPBearer):\n    def make_not_authenticated_error(self) -> HTTPException:\n        return HTTPException(\n            status_code=status.HTTP_403_FORBIDDEN, detail=\"Not authenticated\"\n        )\n\n\nCredentialsDep = Annotated[HTTPAuthorizationCredentials, Depends(HTTPBearer403())]\n\n\n@app.get(\"/me\")\ndef read_me(credentials: CredentialsDep):\n    return {\"message\": \"You are authenticated\", \"token\": credentials.credentials}\n"
  },
  {
    "path": "docs_src/background_tasks/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/background_tasks/tutorial001_py310.py",
    "content": "from fastapi import BackgroundTasks, FastAPI\n\napp = FastAPI()\n\n\ndef write_notification(email: str, message=\"\"):\n    with open(\"log.txt\", mode=\"w\") as email_file:\n        content = f\"notification for {email}: {message}\"\n        email_file.write(content)\n\n\n@app.post(\"/send-notification/{email}\")\nasync def send_notification(email: str, background_tasks: BackgroundTasks):\n    background_tasks.add_task(write_notification, email, message=\"some notification\")\n    return {\"message\": \"Notification sent in the background\"}\n"
  },
  {
    "path": "docs_src/background_tasks/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import BackgroundTasks, Depends, FastAPI\n\napp = FastAPI()\n\n\ndef write_log(message: str):\n    with open(\"log.txt\", mode=\"a\") as log:\n        log.write(message)\n\n\ndef get_query(background_tasks: BackgroundTasks, q: str | None = None):\n    if q:\n        message = f\"found query: {q}\\n\"\n        background_tasks.add_task(write_log, message)\n    return q\n\n\n@app.post(\"/send-notification/{email}\")\nasync def send_notification(\n    email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)]\n):\n    message = f\"message to {email}\\n\"\n    background_tasks.add_task(write_log, message)\n    return {\"message\": \"Message sent\"}\n"
  },
  {
    "path": "docs_src/background_tasks/tutorial002_py310.py",
    "content": "from fastapi import BackgroundTasks, Depends, FastAPI\n\napp = FastAPI()\n\n\ndef write_log(message: str):\n    with open(\"log.txt\", mode=\"a\") as log:\n        log.write(message)\n\n\ndef get_query(background_tasks: BackgroundTasks, q: str | None = None):\n    if q:\n        message = f\"found query: {q}\\n\"\n        background_tasks.add_task(write_log, message)\n    return q\n\n\n@app.post(\"/send-notification/{email}\")\nasync def send_notification(\n    email: str, background_tasks: BackgroundTasks, q: str = Depends(get_query)\n):\n    message = f\"message to {email}\\n\"\n    background_tasks.add_task(write_log, message)\n    return {\"message\": \"Message sent\"}\n"
  },
  {
    "path": "docs_src/behind_a_proxy/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/behind_a_proxy/tutorial001_01_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\ndef read_items():\n    return [\"plumbus\", \"portal gun\"]\n"
  },
  {
    "path": "docs_src/behind_a_proxy/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, Request\n\napp = FastAPI()\n\n\n@app.get(\"/app\")\ndef read_main(request: Request):\n    return {\"message\": \"Hello World\", \"root_path\": request.scope.get(\"root_path\")}\n"
  },
  {
    "path": "docs_src/behind_a_proxy/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, Request\n\napp = FastAPI(root_path=\"/api/v1\")\n\n\n@app.get(\"/app\")\ndef read_main(request: Request):\n    return {\"message\": \"Hello World\", \"root_path\": request.scope.get(\"root_path\")}\n"
  },
  {
    "path": "docs_src/behind_a_proxy/tutorial003_py310.py",
    "content": "from fastapi import FastAPI, Request\n\napp = FastAPI(\n    servers=[\n        {\"url\": \"https://stag.example.com\", \"description\": \"Staging environment\"},\n        {\"url\": \"https://prod.example.com\", \"description\": \"Production environment\"},\n    ],\n    root_path=\"/api/v1\",\n)\n\n\n@app.get(\"/app\")\ndef read_main(request: Request):\n    return {\"message\": \"Hello World\", \"root_path\": request.scope.get(\"root_path\")}\n"
  },
  {
    "path": "docs_src/behind_a_proxy/tutorial004_py310.py",
    "content": "from fastapi import FastAPI, Request\n\napp = FastAPI(\n    servers=[\n        {\"url\": \"https://stag.example.com\", \"description\": \"Staging environment\"},\n        {\"url\": \"https://prod.example.com\", \"description\": \"Production environment\"},\n    ],\n    root_path=\"/api/v1\",\n    root_path_in_servers=False,\n)\n\n\n@app.get(\"/app\")\ndef read_main(request: Request):\n    return {\"message\": \"Hello World\", \"root_path\": request.scope.get(\"root_path\")}\n"
  },
  {
    "path": "docs_src/bigger_applications/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/bigger_applications/app_an_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/bigger_applications/app_an_py310/dependencies.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Header, HTTPException\n\n\nasync def get_token_header(x_token: Annotated[str, Header()]):\n    if x_token != \"fake-super-secret-token\":\n        raise HTTPException(status_code=400, detail=\"X-Token header invalid\")\n\n\nasync def get_query_token(token: str):\n    if token != \"jessica\":\n        raise HTTPException(status_code=400, detail=\"No Jessica token provided\")\n"
  },
  {
    "path": "docs_src/bigger_applications/app_an_py310/internal/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/bigger_applications/app_an_py310/internal/admin.py",
    "content": "from fastapi import APIRouter\n\nrouter = APIRouter()\n\n\n@router.post(\"/\")\nasync def update_admin():\n    return {\"message\": \"Admin getting schwifty\"}\n"
  },
  {
    "path": "docs_src/bigger_applications/app_an_py310/main.py",
    "content": "from fastapi import Depends, FastAPI\n\nfrom .dependencies import get_query_token, get_token_header\nfrom .internal import admin\nfrom .routers import items, users\n\napp = FastAPI(dependencies=[Depends(get_query_token)])\n\n\napp.include_router(users.router)\napp.include_router(items.router)\napp.include_router(\n    admin.router,\n    prefix=\"/admin\",\n    tags=[\"admin\"],\n    dependencies=[Depends(get_token_header)],\n    responses={418: {\"description\": \"I'm a teapot\"}},\n)\n\n\n@app.get(\"/\")\nasync def root():\n    return {\"message\": \"Hello Bigger Applications!\"}\n"
  },
  {
    "path": "docs_src/bigger_applications/app_an_py310/routers/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/bigger_applications/app_an_py310/routers/items.py",
    "content": "from fastapi import APIRouter, Depends, HTTPException\n\nfrom ..dependencies import get_token_header\n\nrouter = APIRouter(\n    prefix=\"/items\",\n    tags=[\"items\"],\n    dependencies=[Depends(get_token_header)],\n    responses={404: {\"description\": \"Not found\"}},\n)\n\n\nfake_items_db = {\"plumbus\": {\"name\": \"Plumbus\"}, \"gun\": {\"name\": \"Portal Gun\"}}\n\n\n@router.get(\"/\")\nasync def read_items():\n    return fake_items_db\n\n\n@router.get(\"/{item_id}\")\nasync def read_item(item_id: str):\n    if item_id not in fake_items_db:\n        raise HTTPException(status_code=404, detail=\"Item not found\")\n    return {\"name\": fake_items_db[item_id][\"name\"], \"item_id\": item_id}\n\n\n@router.put(\n    \"/{item_id}\",\n    tags=[\"custom\"],\n    responses={403: {\"description\": \"Operation forbidden\"}},\n)\nasync def update_item(item_id: str):\n    if item_id != \"plumbus\":\n        raise HTTPException(\n            status_code=403, detail=\"You can only update the item: plumbus\"\n        )\n    return {\"item_id\": item_id, \"name\": \"The great Plumbus\"}\n"
  },
  {
    "path": "docs_src/bigger_applications/app_an_py310/routers/users.py",
    "content": "from fastapi import APIRouter\n\nrouter = APIRouter()\n\n\n@router.get(\"/users/\", tags=[\"users\"])\nasync def read_users():\n    return [{\"username\": \"Rick\"}, {\"username\": \"Morty\"}]\n\n\n@router.get(\"/users/me\", tags=[\"users\"])\nasync def read_user_me():\n    return {\"username\": \"fakecurrentuser\"}\n\n\n@router.get(\"/users/{username}\", tags=[\"users\"])\nasync def read_user(username: str):\n    return {\"username\": username}\n"
  },
  {
    "path": "docs_src/body/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/body/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\napp = FastAPI()\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item):\n    return item\n"
  },
  {
    "path": "docs_src/body/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\napp = FastAPI()\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item):\n    item_dict = item.model_dump()\n    if item.tax is not None:\n        price_with_tax = item.price + item.tax\n        item_dict.update({\"price_with_tax\": price_with_tax})\n    return item_dict\n"
  },
  {
    "path": "docs_src/body/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\napp = FastAPI()\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item):\n    return {\"item_id\": item_id, **item.model_dump()}\n"
  },
  {
    "path": "docs_src/body/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\napp = FastAPI()\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item, q: str | None = None):\n    result = {\"item_id\": item_id, **item.model_dump()}\n    if q:\n        result.update({\"q\": q})\n    return result\n"
  },
  {
    "path": "docs_src/body_fields/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/body_fields/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Body, FastAPI\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = Field(\n        default=None, title=\"The description of the item\", max_length=300\n    )\n    price: float = Field(gt=0, description=\"The price must be greater than zero\")\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/body_fields/tutorial001_py310.py",
    "content": "from fastapi import Body, FastAPI\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = Field(\n        default=None, title=\"The description of the item\", max_length=300\n    )\n    price: float = Field(gt=0, description=\"The price must be greater than zero\")\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item = Body(embed=True)):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/body_multiple_params/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/body_multiple_params/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Path\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    item_id: Annotated[int, Path(title=\"The ID of the item to get\", ge=0, le=1000)],\n    q: str | None = None,\n    item: Item | None = None,\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    if item:\n        results.update({\"item\": item})\n    return results\n"
  },
  {
    "path": "docs_src/body_multiple_params/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, Path\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    *,\n    item_id: int = Path(title=\"The ID of the item to get\", ge=0, le=1000),\n    q: str | None = None,\n    item: Item | None = None,\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    if item:\n        results.update({\"item\": item})\n    return results\n"
  },
  {
    "path": "docs_src/body_multiple_params/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\nclass User(BaseModel):\n    username: str\n    full_name: str | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item, user: User):\n    results = {\"item_id\": item_id, \"item\": item, \"user\": user}\n    return results\n"
  },
  {
    "path": "docs_src/body_multiple_params/tutorial003_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\nclass User(BaseModel):\n    username: str\n    full_name: str | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    item_id: int, item: Item, user: User, importance: Annotated[int, Body()]\n):\n    results = {\"item_id\": item_id, \"item\": item, \"user\": user, \"importance\": importance}\n    return results\n"
  },
  {
    "path": "docs_src/body_multiple_params/tutorial003_py310.py",
    "content": "from fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\nclass User(BaseModel):\n    username: str\n    full_name: str | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item, user: User, importance: int = Body()):\n    results = {\"item_id\": item_id, \"item\": item, \"user\": user, \"importance\": importance}\n    return results\n"
  },
  {
    "path": "docs_src/body_multiple_params/tutorial004_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\nclass User(BaseModel):\n    username: str\n    full_name: str | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    *,\n    item_id: int,\n    item: Item,\n    user: User,\n    importance: Annotated[int, Body(gt=0)],\n    q: str | None = None,\n):\n    results = {\"item_id\": item_id, \"item\": item, \"user\": user, \"importance\": importance}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/body_multiple_params/tutorial004_py310.py",
    "content": "from fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\nclass User(BaseModel):\n    username: str\n    full_name: str | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    *,\n    item_id: int,\n    item: Item,\n    user: User,\n    importance: int = Body(gt=0),\n    q: str | None = None,\n):\n    results = {\"item_id\": item_id, \"item\": item, \"user\": user, \"importance\": importance}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/body_multiple_params/tutorial005_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/body_multiple_params/tutorial005_py310.py",
    "content": "from fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item = Body(embed=True)):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/body_nested_models/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/body_nested_models/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: list = []\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/body_nested_models/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: list[str] = []\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/body_nested_models/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/body_nested_models/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Image(BaseModel):\n    url: str\n    name: str\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n    image: Image | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/body_nested_models/tutorial005_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel, HttpUrl\n\napp = FastAPI()\n\n\nclass Image(BaseModel):\n    url: HttpUrl\n    name: str\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n    image: Image | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/body_nested_models/tutorial006_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel, HttpUrl\n\napp = FastAPI()\n\n\nclass Image(BaseModel):\n    url: HttpUrl\n    name: str\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n    images: list[Image] | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/body_nested_models/tutorial007_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel, HttpUrl\n\napp = FastAPI()\n\n\nclass Image(BaseModel):\n    url: HttpUrl\n    name: str\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n    images: list[Image] | None = None\n\n\nclass Offer(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    items: list[Item]\n\n\n@app.post(\"/offers/\")\nasync def create_offer(offer: Offer):\n    return offer\n"
  },
  {
    "path": "docs_src/body_nested_models/tutorial008_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel, HttpUrl\n\napp = FastAPI()\n\n\nclass Image(BaseModel):\n    url: HttpUrl\n    name: str\n\n\n@app.post(\"/images/multiple/\")\nasync def create_multiple_images(images: list[Image]):\n    return images\n"
  },
  {
    "path": "docs_src/body_nested_models/tutorial009_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.post(\"/index-weights/\")\nasync def create_index_weights(weights: dict[int, float]):\n    return weights\n"
  },
  {
    "path": "docs_src/body_updates/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/body_updates/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.encoders import jsonable_encoder\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str | None = None\n    description: str | None = None\n    price: float | None = None\n    tax: float = 10.5\n    tags: list[str] = []\n\n\nitems = {\n    \"foo\": {\"name\": \"Foo\", \"price\": 50.2},\n    \"bar\": {\"name\": \"Bar\", \"description\": \"The bartenders\", \"price\": 62, \"tax\": 20.2},\n    \"baz\": {\"name\": \"Baz\", \"description\": None, \"price\": 50.2, \"tax\": 10.5, \"tags\": []},\n}\n\n\n@app.get(\"/items/{item_id}\", response_model=Item)\nasync def read_item(item_id: str):\n    return items[item_id]\n\n\n@app.put(\"/items/{item_id}\", response_model=Item)\nasync def update_item(item_id: str, item: Item):\n    update_item_encoded = jsonable_encoder(item)\n    items[item_id] = update_item_encoded\n    return update_item_encoded\n"
  },
  {
    "path": "docs_src/body_updates/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.encoders import jsonable_encoder\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str | None = None\n    description: str | None = None\n    price: float | None = None\n    tax: float = 10.5\n    tags: list[str] = []\n\n\nitems = {\n    \"foo\": {\"name\": \"Foo\", \"price\": 50.2},\n    \"bar\": {\"name\": \"Bar\", \"description\": \"The bartenders\", \"price\": 62, \"tax\": 20.2},\n    \"baz\": {\"name\": \"Baz\", \"description\": None, \"price\": 50.2, \"tax\": 10.5, \"tags\": []},\n}\n\n\n@app.get(\"/items/{item_id}\", response_model=Item)\nasync def read_item(item_id: str):\n    return items[item_id]\n\n\n@app.patch(\"/items/{item_id}\")\nasync def update_item(item_id: str, item: Item) -> Item:\n    stored_item_data = items[item_id]\n    stored_item_model = Item(**stored_item_data)\n    update_data = item.model_dump(exclude_unset=True)\n    updated_item = stored_item_model.model_copy(update=update_data)\n    items[item_id] = jsonable_encoder(updated_item)\n    return updated_item\n"
  },
  {
    "path": "docs_src/conditional_openapi/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/conditional_openapi/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic_settings import BaseSettings\n\n\nclass Settings(BaseSettings):\n    openapi_url: str = \"/openapi.json\"\n\n\nsettings = Settings()\n\napp = FastAPI(openapi_url=settings.openapi_url)\n\n\n@app.get(\"/\")\ndef root():\n    return {\"message\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/configure_swagger_ui/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/configure_swagger_ui/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI(swagger_ui_parameters={\"syntaxHighlight\": False})\n\n\n@app.get(\"/users/{username}\")\nasync def read_user(username: str):\n    return {\"message\": f\"Hello {username}\"}\n"
  },
  {
    "path": "docs_src/configure_swagger_ui/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI(swagger_ui_parameters={\"syntaxHighlight\": {\"theme\": \"obsidian\"}})\n\n\n@app.get(\"/users/{username}\")\nasync def read_user(username: str):\n    return {\"message\": f\"Hello {username}\"}\n"
  },
  {
    "path": "docs_src/configure_swagger_ui/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI(swagger_ui_parameters={\"deepLinking\": False})\n\n\n@app.get(\"/users/{username}\")\nasync def read_user(username: str):\n    return {\"message\": f\"Hello {username}\"}\n"
  },
  {
    "path": "docs_src/cookie_param_models/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/cookie_param_models/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Cookie, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Cookies(BaseModel):\n    session_id: str\n    fatebook_tracker: str | None = None\n    googall_tracker: str | None = None\n\n\n@app.get(\"/items/\")\nasync def read_items(cookies: Annotated[Cookies, Cookie()]):\n    return cookies\n"
  },
  {
    "path": "docs_src/cookie_param_models/tutorial001_py310.py",
    "content": "from fastapi import Cookie, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Cookies(BaseModel):\n    session_id: str\n    fatebook_tracker: str | None = None\n    googall_tracker: str | None = None\n\n\n@app.get(\"/items/\")\nasync def read_items(cookies: Cookies = Cookie()):\n    return cookies\n"
  },
  {
    "path": "docs_src/cookie_param_models/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Cookie, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Cookies(BaseModel):\n    model_config = {\"extra\": \"forbid\"}\n\n    session_id: str\n    fatebook_tracker: str | None = None\n    googall_tracker: str | None = None\n\n\n@app.get(\"/items/\")\nasync def read_items(cookies: Annotated[Cookies, Cookie()]):\n    return cookies\n"
  },
  {
    "path": "docs_src/cookie_param_models/tutorial002_py310.py",
    "content": "from fastapi import Cookie, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Cookies(BaseModel):\n    model_config = {\"extra\": \"forbid\"}\n\n    session_id: str\n    fatebook_tracker: str | None = None\n    googall_tracker: str | None = None\n\n\n@app.get(\"/items/\")\nasync def read_items(cookies: Cookies = Cookie()):\n    return cookies\n"
  },
  {
    "path": "docs_src/cookie_params/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/cookie_params/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Cookie, FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(ads_id: Annotated[str | None, Cookie()] = None):\n    return {\"ads_id\": ads_id}\n"
  },
  {
    "path": "docs_src/cookie_params/tutorial001_py310.py",
    "content": "from fastapi import Cookie, FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(ads_id: str | None = Cookie(default=None)):\n    return {\"ads_id\": ads_id}\n"
  },
  {
    "path": "docs_src/cors/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/cors/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.middleware.cors import CORSMiddleware\n\napp = FastAPI()\n\norigins = [\n    \"http://localhost.tiangolo.com\",\n    \"https://localhost.tiangolo.com\",\n    \"http://localhost\",\n    \"http://localhost:8080\",\n]\n\napp.add_middleware(\n    CORSMiddleware,\n    allow_origins=origins,\n    allow_credentials=True,\n    allow_methods=[\"*\"],\n    allow_headers=[\"*\"],\n)\n\n\n@app.get(\"/\")\nasync def main():\n    return {\"message\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/custom_docs_ui/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/custom_docs_ui/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.openapi.docs import (\n    get_redoc_html,\n    get_swagger_ui_html,\n    get_swagger_ui_oauth2_redirect_html,\n)\n\napp = FastAPI(docs_url=None, redoc_url=None)\n\n\n@app.get(\"/docs\", include_in_schema=False)\nasync def custom_swagger_ui_html():\n    return get_swagger_ui_html(\n        openapi_url=app.openapi_url,\n        title=app.title + \" - Swagger UI\",\n        oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,\n        swagger_js_url=\"https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js\",\n        swagger_css_url=\"https://unpkg.com/swagger-ui-dist@5/swagger-ui.css\",\n    )\n\n\n@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)\nasync def swagger_ui_redirect():\n    return get_swagger_ui_oauth2_redirect_html()\n\n\n@app.get(\"/redoc\", include_in_schema=False)\nasync def redoc_html():\n    return get_redoc_html(\n        openapi_url=app.openapi_url,\n        title=app.title + \" - ReDoc\",\n        redoc_js_url=\"https://unpkg.com/redoc@2/bundles/redoc.standalone.js\",\n    )\n\n\n@app.get(\"/users/{username}\")\nasync def read_user(username: str):\n    return {\"message\": f\"Hello {username}\"}\n"
  },
  {
    "path": "docs_src/custom_docs_ui/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.openapi.docs import (\n    get_redoc_html,\n    get_swagger_ui_html,\n    get_swagger_ui_oauth2_redirect_html,\n)\nfrom fastapi.staticfiles import StaticFiles\n\napp = FastAPI(docs_url=None, redoc_url=None)\n\napp.mount(\"/static\", StaticFiles(directory=\"static\"), name=\"static\")\n\n\n@app.get(\"/docs\", include_in_schema=False)\nasync def custom_swagger_ui_html():\n    return get_swagger_ui_html(\n        openapi_url=app.openapi_url,\n        title=app.title + \" - Swagger UI\",\n        oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,\n        swagger_js_url=\"/static/swagger-ui-bundle.js\",\n        swagger_css_url=\"/static/swagger-ui.css\",\n    )\n\n\n@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)\nasync def swagger_ui_redirect():\n    return get_swagger_ui_oauth2_redirect_html()\n\n\n@app.get(\"/redoc\", include_in_schema=False)\nasync def redoc_html():\n    return get_redoc_html(\n        openapi_url=app.openapi_url,\n        title=app.title + \" - ReDoc\",\n        redoc_js_url=\"/static/redoc.standalone.js\",\n    )\n\n\n@app.get(\"/users/{username}\")\nasync def read_user(username: str):\n    return {\"message\": f\"Hello {username}\"}\n"
  },
  {
    "path": "docs_src/custom_request_and_route/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/custom_request_and_route/tutorial001_an_py310.py",
    "content": "import gzip\nfrom collections.abc import Callable\nfrom typing import Annotated\n\nfrom fastapi import Body, FastAPI, Request, Response\nfrom fastapi.routing import APIRoute\n\n\nclass GzipRequest(Request):\n    async def body(self) -> bytes:\n        if not hasattr(self, \"_body\"):\n            body = await super().body()\n            if \"gzip\" in self.headers.getlist(\"Content-Encoding\"):\n                body = gzip.decompress(body)\n            self._body = body\n        return self._body\n\n\nclass GzipRoute(APIRoute):\n    def get_route_handler(self) -> Callable:\n        original_route_handler = super().get_route_handler()\n\n        async def custom_route_handler(request: Request) -> Response:\n            request = GzipRequest(request.scope, request.receive)\n            return await original_route_handler(request)\n\n        return custom_route_handler\n\n\napp = FastAPI()\napp.router.route_class = GzipRoute\n\n\n@app.post(\"/sum\")\nasync def sum_numbers(numbers: Annotated[list[int], Body()]):\n    return {\"sum\": sum(numbers)}\n"
  },
  {
    "path": "docs_src/custom_request_and_route/tutorial001_py310.py",
    "content": "import gzip\nfrom collections.abc import Callable\n\nfrom fastapi import Body, FastAPI, Request, Response\nfrom fastapi.routing import APIRoute\n\n\nclass GzipRequest(Request):\n    async def body(self) -> bytes:\n        if not hasattr(self, \"_body\"):\n            body = await super().body()\n            if \"gzip\" in self.headers.getlist(\"Content-Encoding\"):\n                body = gzip.decompress(body)\n            self._body = body\n        return self._body\n\n\nclass GzipRoute(APIRoute):\n    def get_route_handler(self) -> Callable:\n        original_route_handler = super().get_route_handler()\n\n        async def custom_route_handler(request: Request) -> Response:\n            request = GzipRequest(request.scope, request.receive)\n            return await original_route_handler(request)\n\n        return custom_route_handler\n\n\napp = FastAPI()\napp.router.route_class = GzipRoute\n\n\n@app.post(\"/sum\")\nasync def sum_numbers(numbers: list[int] = Body()):\n    return {\"sum\": sum(numbers)}\n"
  },
  {
    "path": "docs_src/custom_request_and_route/tutorial002_an_py310.py",
    "content": "from collections.abc import Callable\nfrom typing import Annotated\n\nfrom fastapi import Body, FastAPI, HTTPException, Request, Response\nfrom fastapi.exceptions import RequestValidationError\nfrom fastapi.routing import APIRoute\n\n\nclass ValidationErrorLoggingRoute(APIRoute):\n    def get_route_handler(self) -> Callable:\n        original_route_handler = super().get_route_handler()\n\n        async def custom_route_handler(request: Request) -> Response:\n            try:\n                return await original_route_handler(request)\n            except RequestValidationError as exc:\n                body = await request.body()\n                detail = {\"errors\": exc.errors(), \"body\": body.decode()}\n                raise HTTPException(status_code=422, detail=detail)\n\n        return custom_route_handler\n\n\napp = FastAPI()\napp.router.route_class = ValidationErrorLoggingRoute\n\n\n@app.post(\"/\")\nasync def sum_numbers(numbers: Annotated[list[int], Body()]):\n    return sum(numbers)\n"
  },
  {
    "path": "docs_src/custom_request_and_route/tutorial002_py310.py",
    "content": "from collections.abc import Callable\n\nfrom fastapi import Body, FastAPI, HTTPException, Request, Response\nfrom fastapi.exceptions import RequestValidationError\nfrom fastapi.routing import APIRoute\n\n\nclass ValidationErrorLoggingRoute(APIRoute):\n    def get_route_handler(self) -> Callable:\n        original_route_handler = super().get_route_handler()\n\n        async def custom_route_handler(request: Request) -> Response:\n            try:\n                return await original_route_handler(request)\n            except RequestValidationError as exc:\n                body = await request.body()\n                detail = {\"errors\": exc.errors(), \"body\": body.decode()}\n                raise HTTPException(status_code=422, detail=detail)\n\n        return custom_route_handler\n\n\napp = FastAPI()\napp.router.route_class = ValidationErrorLoggingRoute\n\n\n@app.post(\"/\")\nasync def sum_numbers(numbers: list[int] = Body()):\n    return sum(numbers)\n"
  },
  {
    "path": "docs_src/custom_request_and_route/tutorial003_py310.py",
    "content": "import time\nfrom collections.abc import Callable\n\nfrom fastapi import APIRouter, FastAPI, Request, Response\nfrom fastapi.routing import APIRoute\n\n\nclass TimedRoute(APIRoute):\n    def get_route_handler(self) -> Callable:\n        original_route_handler = super().get_route_handler()\n\n        async def custom_route_handler(request: Request) -> Response:\n            before = time.time()\n            response: Response = await original_route_handler(request)\n            duration = time.time() - before\n            response.headers[\"X-Response-Time\"] = str(duration)\n            print(f\"route duration: {duration}\")\n            print(f\"route response: {response}\")\n            print(f\"route response headers: {response.headers}\")\n            return response\n\n        return custom_route_handler\n\n\napp = FastAPI()\nrouter = APIRouter(route_class=TimedRoute)\n\n\n@app.get(\"/\")\nasync def not_timed():\n    return {\"message\": \"Not timed\"}\n\n\n@router.get(\"/timed\")\nasync def timed():\n    return {\"message\": \"It's the time of my life\"}\n\n\napp.include_router(router)\n"
  },
  {
    "path": "docs_src/custom_response/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/custom_response/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import UJSONResponse\n\napp = FastAPI()\n\n\n@app.get(\"/items/\", response_class=UJSONResponse)\nasync def read_items():\n    return [{\"item_id\": \"Foo\"}]\n"
  },
  {
    "path": "docs_src/custom_response/tutorial001b_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import ORJSONResponse\n\napp = FastAPI()\n\n\n@app.get(\"/items/\", response_class=ORJSONResponse)\nasync def read_items():\n    return ORJSONResponse([{\"item_id\": \"Foo\"}])\n"
  },
  {
    "path": "docs_src/custom_response/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\n\n@app.get(\"/items/\", response_class=HTMLResponse)\nasync def read_items():\n    return \"\"\"\n    <html>\n        <head>\n            <title>Some HTML in here</title>\n        </head>\n        <body>\n            <h1>Look ma! HTML!</h1>\n        </body>\n    </html>\n    \"\"\"\n"
  },
  {
    "path": "docs_src/custom_response/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    html_content = \"\"\"\n    <html>\n        <head>\n            <title>Some HTML in here</title>\n        </head>\n        <body>\n            <h1>Look ma! HTML!</h1>\n        </body>\n    </html>\n    \"\"\"\n    return HTMLResponse(content=html_content, status_code=200)\n"
  },
  {
    "path": "docs_src/custom_response/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\n\ndef generate_html_response():\n    html_content = \"\"\"\n    <html>\n        <head>\n            <title>Some HTML in here</title>\n        </head>\n        <body>\n            <h1>Look ma! HTML!</h1>\n        </body>\n    </html>\n    \"\"\"\n    return HTMLResponse(content=html_content, status_code=200)\n\n\n@app.get(\"/items/\", response_class=HTMLResponse)\nasync def read_items():\n    return generate_html_response()\n"
  },
  {
    "path": "docs_src/custom_response/tutorial005_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import PlainTextResponse\n\napp = FastAPI()\n\n\n@app.get(\"/\", response_class=PlainTextResponse)\nasync def main():\n    return \"Hello World\"\n"
  },
  {
    "path": "docs_src/custom_response/tutorial006_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import RedirectResponse\n\napp = FastAPI()\n\n\n@app.get(\"/typer\")\nasync def redirect_typer():\n    return RedirectResponse(\"https://typer.tiangolo.com\")\n"
  },
  {
    "path": "docs_src/custom_response/tutorial006b_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import RedirectResponse\n\napp = FastAPI()\n\n\n@app.get(\"/fastapi\", response_class=RedirectResponse)\nasync def redirect_fastapi():\n    return \"https://fastapi.tiangolo.com\"\n"
  },
  {
    "path": "docs_src/custom_response/tutorial006c_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import RedirectResponse\n\napp = FastAPI()\n\n\n@app.get(\"/pydantic\", response_class=RedirectResponse, status_code=302)\nasync def redirect_pydantic():\n    return \"https://docs.pydantic.dev/\"\n"
  },
  {
    "path": "docs_src/custom_response/tutorial007_py310.py",
    "content": "import anyio\nfrom fastapi import FastAPI\nfrom fastapi.responses import StreamingResponse\n\napp = FastAPI()\n\n\nasync def fake_video_streamer():\n    for i in range(10):\n        yield b\"some fake video bytes\"\n        await anyio.sleep(0)\n\n\n@app.get(\"/\")\nasync def main():\n    return StreamingResponse(fake_video_streamer())\n"
  },
  {
    "path": "docs_src/custom_response/tutorial008_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import StreamingResponse\n\nsome_file_path = \"large-video-file.mp4\"\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef main():\n    def iterfile():  # (1)\n        with open(some_file_path, mode=\"rb\") as file_like:  # (2)\n            yield from file_like  # (3)\n\n    return StreamingResponse(iterfile(), media_type=\"video/mp4\")\n"
  },
  {
    "path": "docs_src/custom_response/tutorial009_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import FileResponse\n\nsome_file_path = \"large-video-file.mp4\"\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def main():\n    return FileResponse(some_file_path)\n"
  },
  {
    "path": "docs_src/custom_response/tutorial009b_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import FileResponse\n\nsome_file_path = \"large-video-file.mp4\"\napp = FastAPI()\n\n\n@app.get(\"/\", response_class=FileResponse)\nasync def main():\n    return some_file_path\n"
  },
  {
    "path": "docs_src/custom_response/tutorial009c_py310.py",
    "content": "from typing import Any\n\nimport orjson\nfrom fastapi import FastAPI, Response\n\napp = FastAPI()\n\n\nclass CustomORJSONResponse(Response):\n    media_type = \"application/json\"\n\n    def render(self, content: Any) -> bytes:\n        assert orjson is not None, \"orjson must be installed\"\n        return orjson.dumps(content, option=orjson.OPT_INDENT_2)\n\n\n@app.get(\"/\", response_class=CustomORJSONResponse)\nasync def main():\n    return {\"message\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/custom_response/tutorial010_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI(default_response_class=HTMLResponse)\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return \"<h1>Items</h1><p>This is a list of items.</p>\"\n"
  },
  {
    "path": "docs_src/dataclasses_/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/dataclasses_/tutorial001_py310.py",
    "content": "from dataclasses import dataclass\n\nfrom fastapi import FastAPI\n\n\n@dataclass\nclass Item:\n    name: str\n    price: float\n    description: str | None = None\n    tax: float | None = None\n\n\napp = FastAPI()\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item):\n    return item\n"
  },
  {
    "path": "docs_src/dataclasses_/tutorial002_py310.py",
    "content": "from dataclasses import dataclass, field\n\nfrom fastapi import FastAPI\n\n\n@dataclass\nclass Item:\n    name: str\n    price: float\n    tags: list[str] = field(default_factory=list)\n    description: str | None = None\n    tax: float | None = None\n\n\napp = FastAPI()\n\n\n@app.get(\"/items/next\", response_model=Item)\nasync def read_next_item():\n    return {\n        \"name\": \"Island In The Moon\",\n        \"price\": 12.99,\n        \"description\": \"A place to be playin' and havin' fun\",\n        \"tags\": [\"breater\"],\n    }\n"
  },
  {
    "path": "docs_src/dataclasses_/tutorial003_py310.py",
    "content": "from dataclasses import field  # (1)\n\nfrom fastapi import FastAPI\nfrom pydantic.dataclasses import dataclass  # (2)\n\n\n@dataclass\nclass Item:\n    name: str\n    description: str | None = None\n\n\n@dataclass\nclass Author:\n    name: str\n    items: list[Item] = field(default_factory=list)  # (3)\n\n\napp = FastAPI()\n\n\n@app.post(\"/authors/{author_id}/items/\", response_model=Author)  # (4)\nasync def create_author_items(author_id: str, items: list[Item]):  # (5)\n    return {\"name\": author_id, \"items\": items}  # (6)\n\n\n@app.get(\"/authors/\", response_model=list[Author])  # (7)\ndef get_authors():  # (8)\n    return [  # (9)\n        {\n            \"name\": \"Breaters\",\n            \"items\": [\n                {\n                    \"name\": \"Island In The Moon\",\n                    \"description\": \"A place to be playin' and havin' fun\",\n                },\n                {\"name\": \"Holy Buddies\"},\n            ],\n        },\n        {\n            \"name\": \"System of an Up\",\n            \"items\": [\n                {\n                    \"name\": \"Salt\",\n                    \"description\": \"The kombucha mushroom people's favorite\",\n                },\n                {\"name\": \"Pad Thai\"},\n                {\n                    \"name\": \"Lonely Night\",\n                    \"description\": \"The mostests lonliest nightiest of allest\",\n                },\n            ],\n        },\n    ]\n"
  },
  {
    "path": "docs_src/debugging/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/debugging/tutorial001_py310.py",
    "content": "import uvicorn\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef root():\n    a = \"a\"\n    b = \"b\" + a\n    return {\"hello world\": b}\n\n\nif __name__ == \"__main__\":\n    uvicorn.run(app, host=\"0.0.0.0\", port=8000)\n"
  },
  {
    "path": "docs_src/dependencies/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/dependencies/tutorial001_02_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nasync def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):\n    return {\"q\": q, \"skip\": skip, \"limit\": limit}\n\n\nCommonsDep = Annotated[dict, Depends(common_parameters)]\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: CommonsDep):\n    return commons\n\n\n@app.get(\"/users/\")\nasync def read_users(commons: CommonsDep):\n    return commons\n"
  },
  {
    "path": "docs_src/dependencies/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nasync def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):\n    return {\"q\": q, \"skip\": skip, \"limit\": limit}\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: Annotated[dict, Depends(common_parameters)]):\n    return commons\n\n\n@app.get(\"/users/\")\nasync def read_users(commons: Annotated[dict, Depends(common_parameters)]):\n    return commons\n"
  },
  {
    "path": "docs_src/dependencies/tutorial001_py310.py",
    "content": "from fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nasync def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):\n    return {\"q\": q, \"skip\": skip, \"limit\": limit}\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: dict = Depends(common_parameters)):\n    return commons\n\n\n@app.get(\"/users/\")\nasync def read_users(commons: dict = Depends(common_parameters)):\n    return commons\n"
  },
  {
    "path": "docs_src/dependencies/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nfake_items_db = [{\"item_name\": \"Foo\"}, {\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}]\n\n\nclass CommonQueryParams:\n    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):\n        self.q = q\n        self.skip = skip\n        self.limit = limit\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):\n    response = {}\n    if commons.q:\n        response.update({\"q\": commons.q})\n    items = fake_items_db[commons.skip : commons.skip + commons.limit]\n    response.update({\"items\": items})\n    return response\n"
  },
  {
    "path": "docs_src/dependencies/tutorial002_py310.py",
    "content": "from fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nfake_items_db = [{\"item_name\": \"Foo\"}, {\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}]\n\n\nclass CommonQueryParams:\n    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):\n        self.q = q\n        self.skip = skip\n        self.limit = limit\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):\n    response = {}\n    if commons.q:\n        response.update({\"q\": commons.q})\n    items = fake_items_db[commons.skip : commons.skip + commons.limit]\n    response.update({\"items\": items})\n    return response\n"
  },
  {
    "path": "docs_src/dependencies/tutorial003_an_py310.py",
    "content": "from typing import Annotated, Any\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nfake_items_db = [{\"item_name\": \"Foo\"}, {\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}]\n\n\nclass CommonQueryParams:\n    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):\n        self.q = q\n        self.skip = skip\n        self.limit = limit\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: Annotated[Any, Depends(CommonQueryParams)]):\n    response = {}\n    if commons.q:\n        response.update({\"q\": commons.q})\n    items = fake_items_db[commons.skip : commons.skip + commons.limit]\n    response.update({\"items\": items})\n    return response\n"
  },
  {
    "path": "docs_src/dependencies/tutorial003_py310.py",
    "content": "from fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nfake_items_db = [{\"item_name\": \"Foo\"}, {\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}]\n\n\nclass CommonQueryParams:\n    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):\n        self.q = q\n        self.skip = skip\n        self.limit = limit\n\n\n@app.get(\"/items/\")\nasync def read_items(commons=Depends(CommonQueryParams)):\n    response = {}\n    if commons.q:\n        response.update({\"q\": commons.q})\n    items = fake_items_db[commons.skip : commons.skip + commons.limit]\n    response.update({\"items\": items})\n    return response\n"
  },
  {
    "path": "docs_src/dependencies/tutorial004_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nfake_items_db = [{\"item_name\": \"Foo\"}, {\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}]\n\n\nclass CommonQueryParams:\n    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):\n        self.q = q\n        self.skip = skip\n        self.limit = limit\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: Annotated[CommonQueryParams, Depends()]):\n    response = {}\n    if commons.q:\n        response.update({\"q\": commons.q})\n    items = fake_items_db[commons.skip : commons.skip + commons.limit]\n    response.update({\"items\": items})\n    return response\n"
  },
  {
    "path": "docs_src/dependencies/tutorial004_py310.py",
    "content": "from fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nfake_items_db = [{\"item_name\": \"Foo\"}, {\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}]\n\n\nclass CommonQueryParams:\n    def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):\n        self.q = q\n        self.skip = skip\n        self.limit = limit\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: CommonQueryParams = Depends()):\n    response = {}\n    if commons.q:\n        response.update({\"q\": commons.q})\n    items = fake_items_db[commons.skip : commons.skip + commons.limit]\n    response.update({\"items\": items})\n    return response\n"
  },
  {
    "path": "docs_src/dependencies/tutorial005_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Cookie, Depends, FastAPI\n\napp = FastAPI()\n\n\ndef query_extractor(q: str | None = None):\n    return q\n\n\ndef query_or_cookie_extractor(\n    q: Annotated[str, Depends(query_extractor)],\n    last_query: Annotated[str | None, Cookie()] = None,\n):\n    if not q:\n        return last_query\n    return q\n\n\n@app.get(\"/items/\")\nasync def read_query(\n    query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],\n):\n    return {\"q_or_cookie\": query_or_default}\n"
  },
  {
    "path": "docs_src/dependencies/tutorial005_py310.py",
    "content": "from fastapi import Cookie, Depends, FastAPI\n\napp = FastAPI()\n\n\ndef query_extractor(q: str | None = None):\n    return q\n\n\ndef query_or_cookie_extractor(\n    q: str = Depends(query_extractor), last_query: str | None = Cookie(default=None)\n):\n    if not q:\n        return last_query\n    return q\n\n\n@app.get(\"/items/\")\nasync def read_query(query_or_default: str = Depends(query_or_cookie_extractor)):\n    return {\"q_or_cookie\": query_or_default}\n"
  },
  {
    "path": "docs_src/dependencies/tutorial006_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI, Header, HTTPException\n\napp = FastAPI()\n\n\nasync def verify_token(x_token: Annotated[str, Header()]):\n    if x_token != \"fake-super-secret-token\":\n        raise HTTPException(status_code=400, detail=\"X-Token header invalid\")\n\n\nasync def verify_key(x_key: Annotated[str, Header()]):\n    if x_key != \"fake-super-secret-key\":\n        raise HTTPException(status_code=400, detail=\"X-Key header invalid\")\n    return x_key\n\n\n@app.get(\"/items/\", dependencies=[Depends(verify_token), Depends(verify_key)])\nasync def read_items():\n    return [{\"item\": \"Foo\"}, {\"item\": \"Bar\"}]\n"
  },
  {
    "path": "docs_src/dependencies/tutorial006_py310.py",
    "content": "from fastapi import Depends, FastAPI, Header, HTTPException\n\napp = FastAPI()\n\n\nasync def verify_token(x_token: str = Header()):\n    if x_token != \"fake-super-secret-token\":\n        raise HTTPException(status_code=400, detail=\"X-Token header invalid\")\n\n\nasync def verify_key(x_key: str = Header()):\n    if x_key != \"fake-super-secret-key\":\n        raise HTTPException(status_code=400, detail=\"X-Key header invalid\")\n    return x_key\n\n\n@app.get(\"/items/\", dependencies=[Depends(verify_token), Depends(verify_key)])\nasync def read_items():\n    return [{\"item\": \"Foo\"}, {\"item\": \"Bar\"}]\n"
  },
  {
    "path": "docs_src/dependencies/tutorial007_py310.py",
    "content": "async def get_db():\n    db = DBSession()\n    try:\n        yield db\n    finally:\n        db.close()\n"
  },
  {
    "path": "docs_src/dependencies/tutorial008_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends\n\n\nasync def dependency_a():\n    dep_a = generate_dep_a()\n    try:\n        yield dep_a\n    finally:\n        dep_a.close()\n\n\nasync def dependency_b(dep_a: Annotated[DepA, Depends(dependency_a)]):\n    dep_b = generate_dep_b()\n    try:\n        yield dep_b\n    finally:\n        dep_b.close(dep_a)\n\n\nasync def dependency_c(dep_b: Annotated[DepB, Depends(dependency_b)]):\n    dep_c = generate_dep_c()\n    try:\n        yield dep_c\n    finally:\n        dep_c.close(dep_b)\n"
  },
  {
    "path": "docs_src/dependencies/tutorial008_py310.py",
    "content": "from fastapi import Depends\n\n\nasync def dependency_a():\n    dep_a = generate_dep_a()\n    try:\n        yield dep_a\n    finally:\n        dep_a.close()\n\n\nasync def dependency_b(dep_a=Depends(dependency_a)):\n    dep_b = generate_dep_b()\n    try:\n        yield dep_b\n    finally:\n        dep_b.close(dep_a)\n\n\nasync def dependency_c(dep_b=Depends(dependency_b)):\n    dep_c = generate_dep_c()\n    try:\n        yield dep_c\n    finally:\n        dep_c.close(dep_b)\n"
  },
  {
    "path": "docs_src/dependencies/tutorial008b_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI, HTTPException\n\napp = FastAPI()\n\n\ndata = {\n    \"plumbus\": {\"description\": \"Freshly pickled plumbus\", \"owner\": \"Morty\"},\n    \"portal-gun\": {\"description\": \"Gun to create portals\", \"owner\": \"Rick\"},\n}\n\n\nclass OwnerError(Exception):\n    pass\n\n\ndef get_username():\n    try:\n        yield \"Rick\"\n    except OwnerError as e:\n        raise HTTPException(status_code=400, detail=f\"Owner error: {e}\")\n\n\n@app.get(\"/items/{item_id}\")\ndef get_item(item_id: str, username: Annotated[str, Depends(get_username)]):\n    if item_id not in data:\n        raise HTTPException(status_code=404, detail=\"Item not found\")\n    item = data[item_id]\n    if item[\"owner\"] != username:\n        raise OwnerError(username)\n    return item\n"
  },
  {
    "path": "docs_src/dependencies/tutorial008b_py310.py",
    "content": "from fastapi import Depends, FastAPI, HTTPException\n\napp = FastAPI()\n\n\ndata = {\n    \"plumbus\": {\"description\": \"Freshly pickled plumbus\", \"owner\": \"Morty\"},\n    \"portal-gun\": {\"description\": \"Gun to create portals\", \"owner\": \"Rick\"},\n}\n\n\nclass OwnerError(Exception):\n    pass\n\n\ndef get_username():\n    try:\n        yield \"Rick\"\n    except OwnerError as e:\n        raise HTTPException(status_code=400, detail=f\"Owner error: {e}\")\n\n\n@app.get(\"/items/{item_id}\")\ndef get_item(item_id: str, username: str = Depends(get_username)):\n    if item_id not in data:\n        raise HTTPException(status_code=404, detail=\"Item not found\")\n    item = data[item_id]\n    if item[\"owner\"] != username:\n        raise OwnerError(username)\n    return item\n"
  },
  {
    "path": "docs_src/dependencies/tutorial008c_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI, HTTPException\n\napp = FastAPI()\n\n\nclass InternalError(Exception):\n    pass\n\n\ndef get_username():\n    try:\n        yield \"Rick\"\n    except InternalError:\n        print(\"Oops, we didn't raise again, Britney 😱\")\n\n\n@app.get(\"/items/{item_id}\")\ndef get_item(item_id: str, username: Annotated[str, Depends(get_username)]):\n    if item_id == \"portal-gun\":\n        raise InternalError(\n            f\"The portal gun is too dangerous to be owned by {username}\"\n        )\n    if item_id != \"plumbus\":\n        raise HTTPException(\n            status_code=404, detail=\"Item not found, there's only a plumbus here\"\n        )\n    return item_id\n"
  },
  {
    "path": "docs_src/dependencies/tutorial008c_py310.py",
    "content": "from fastapi import Depends, FastAPI, HTTPException\n\napp = FastAPI()\n\n\nclass InternalError(Exception):\n    pass\n\n\ndef get_username():\n    try:\n        yield \"Rick\"\n    except InternalError:\n        print(\"Oops, we didn't raise again, Britney 😱\")\n\n\n@app.get(\"/items/{item_id}\")\ndef get_item(item_id: str, username: str = Depends(get_username)):\n    if item_id == \"portal-gun\":\n        raise InternalError(\n            f\"The portal gun is too dangerous to be owned by {username}\"\n        )\n    if item_id != \"plumbus\":\n        raise HTTPException(\n            status_code=404, detail=\"Item not found, there's only a plumbus here\"\n        )\n    return item_id\n"
  },
  {
    "path": "docs_src/dependencies/tutorial008d_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI, HTTPException\n\napp = FastAPI()\n\n\nclass InternalError(Exception):\n    pass\n\n\ndef get_username():\n    try:\n        yield \"Rick\"\n    except InternalError:\n        print(\"We don't swallow the internal error here, we raise again 😎\")\n        raise\n\n\n@app.get(\"/items/{item_id}\")\ndef get_item(item_id: str, username: Annotated[str, Depends(get_username)]):\n    if item_id == \"portal-gun\":\n        raise InternalError(\n            f\"The portal gun is too dangerous to be owned by {username}\"\n        )\n    if item_id != \"plumbus\":\n        raise HTTPException(\n            status_code=404, detail=\"Item not found, there's only a plumbus here\"\n        )\n    return item_id\n"
  },
  {
    "path": "docs_src/dependencies/tutorial008d_py310.py",
    "content": "from fastapi import Depends, FastAPI, HTTPException\n\napp = FastAPI()\n\n\nclass InternalError(Exception):\n    pass\n\n\ndef get_username():\n    try:\n        yield \"Rick\"\n    except InternalError:\n        print(\"We don't swallow the internal error here, we raise again 😎\")\n        raise\n\n\n@app.get(\"/items/{item_id}\")\ndef get_item(item_id: str, username: str = Depends(get_username)):\n    if item_id == \"portal-gun\":\n        raise InternalError(\n            f\"The portal gun is too dangerous to be owned by {username}\"\n        )\n    if item_id != \"plumbus\":\n        raise HTTPException(\n            status_code=404, detail=\"Item not found, there's only a plumbus here\"\n        )\n    return item_id\n"
  },
  {
    "path": "docs_src/dependencies/tutorial008e_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\ndef get_username():\n    try:\n        yield \"Rick\"\n    finally:\n        print(\"Cleanup up before response is sent\")\n\n\n@app.get(\"/users/me\")\ndef get_user_me(username: Annotated[str, Depends(get_username, scope=\"function\")]):\n    return username\n"
  },
  {
    "path": "docs_src/dependencies/tutorial008e_py310.py",
    "content": "from fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\ndef get_username():\n    try:\n        yield \"Rick\"\n    finally:\n        print(\"Cleanup up before response is sent\")\n\n\n@app.get(\"/users/me\")\ndef get_user_me(username: str = Depends(get_username, scope=\"function\")):\n    return username\n"
  },
  {
    "path": "docs_src/dependencies/tutorial010_py310.py",
    "content": "class MySuperContextManager:\n    def __init__(self):\n        self.db = DBSession()\n\n    def __enter__(self):\n        return self.db\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        self.db.close()\n\n\nasync def get_db():\n    with MySuperContextManager() as db:\n        yield db\n"
  },
  {
    "path": "docs_src/dependencies/tutorial011_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nclass FixedContentQueryChecker:\n    def __init__(self, fixed_content: str):\n        self.fixed_content = fixed_content\n\n    def __call__(self, q: str = \"\"):\n        if q:\n            return self.fixed_content in q\n        return False\n\n\nchecker = FixedContentQueryChecker(\"bar\")\n\n\n@app.get(\"/query-checker/\")\nasync def read_query_check(fixed_content_included: Annotated[bool, Depends(checker)]):\n    return {\"fixed_content_in_query\": fixed_content_included}\n"
  },
  {
    "path": "docs_src/dependencies/tutorial011_py310.py",
    "content": "from fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nclass FixedContentQueryChecker:\n    def __init__(self, fixed_content: str):\n        self.fixed_content = fixed_content\n\n    def __call__(self, q: str = \"\"):\n        if q:\n            return self.fixed_content in q\n        return False\n\n\nchecker = FixedContentQueryChecker(\"bar\")\n\n\n@app.get(\"/query-checker/\")\nasync def read_query_check(fixed_content_included: bool = Depends(checker)):\n    return {\"fixed_content_in_query\": fixed_content_included}\n"
  },
  {
    "path": "docs_src/dependencies/tutorial012_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI, Header, HTTPException\n\n\nasync def verify_token(x_token: Annotated[str, Header()]):\n    if x_token != \"fake-super-secret-token\":\n        raise HTTPException(status_code=400, detail=\"X-Token header invalid\")\n\n\nasync def verify_key(x_key: Annotated[str, Header()]):\n    if x_key != \"fake-super-secret-key\":\n        raise HTTPException(status_code=400, detail=\"X-Key header invalid\")\n    return x_key\n\n\napp = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return [{\"item\": \"Portal Gun\"}, {\"item\": \"Plumbus\"}]\n\n\n@app.get(\"/users/\")\nasync def read_users():\n    return [{\"username\": \"Rick\"}, {\"username\": \"Morty\"}]\n"
  },
  {
    "path": "docs_src/dependencies/tutorial012_py310.py",
    "content": "from fastapi import Depends, FastAPI, Header, HTTPException\n\n\nasync def verify_token(x_token: str = Header()):\n    if x_token != \"fake-super-secret-token\":\n        raise HTTPException(status_code=400, detail=\"X-Token header invalid\")\n\n\nasync def verify_key(x_key: str = Header()):\n    if x_key != \"fake-super-secret-key\":\n        raise HTTPException(status_code=400, detail=\"X-Key header invalid\")\n    return x_key\n\n\napp = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)])\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return [{\"item\": \"Portal Gun\"}, {\"item\": \"Plumbus\"}]\n\n\n@app.get(\"/users/\")\nasync def read_users():\n    return [{\"username\": \"Rick\"}, {\"username\": \"Morty\"}]\n"
  },
  {
    "path": "docs_src/dependencies/tutorial013_an_py310.py",
    "content": "import time\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI, HTTPException\nfrom fastapi.responses import StreamingResponse\nfrom sqlmodel import Field, Session, SQLModel, create_engine\n\nengine = create_engine(\"postgresql+psycopg://postgres:postgres@localhost/db\")\n\n\nclass User(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n\n\napp = FastAPI()\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\ndef get_user(user_id: int, session: Annotated[Session, Depends(get_session)]):\n    user = session.get(User, user_id)\n    if not user:\n        raise HTTPException(status_code=403, detail=\"Not authorized\")\n\n\ndef generate_stream(query: str):\n    for ch in query:\n        yield ch\n        time.sleep(0.1)\n\n\n@app.get(\"/generate\", dependencies=[Depends(get_user)])\ndef generate(query: str):\n    return StreamingResponse(content=generate_stream(query))\n"
  },
  {
    "path": "docs_src/dependencies/tutorial014_an_py310.py",
    "content": "import time\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI, HTTPException\nfrom fastapi.responses import StreamingResponse\nfrom sqlmodel import Field, Session, SQLModel, create_engine\n\nengine = create_engine(\"postgresql+psycopg://postgres:postgres@localhost/db\")\n\n\nclass User(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n\n\napp = FastAPI()\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\ndef get_user(user_id: int, session: Annotated[Session, Depends(get_session)]):\n    user = session.get(User, user_id)\n    if not user:\n        raise HTTPException(status_code=403, detail=\"Not authorized\")\n    session.close()\n\n\ndef generate_stream(query: str):\n    for ch in query:\n        yield ch\n        time.sleep(0.1)\n\n\n@app.get(\"/generate\", dependencies=[Depends(get_user)])\ndef generate(query: str):\n    return StreamingResponse(content=generate_stream(query))\n"
  },
  {
    "path": "docs_src/dependency_testing/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/dependency_testing/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\nasync def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):\n    return {\"q\": q, \"skip\": skip, \"limit\": limit}\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: Annotated[dict, Depends(common_parameters)]):\n    return {\"message\": \"Hello Items!\", \"params\": commons}\n\n\n@app.get(\"/users/\")\nasync def read_users(commons: Annotated[dict, Depends(common_parameters)]):\n    return {\"message\": \"Hello Users!\", \"params\": commons}\n\n\nclient = TestClient(app)\n\n\nasync def override_dependency(q: str | None = None):\n    return {\"q\": q, \"skip\": 5, \"limit\": 10}\n\n\napp.dependency_overrides[common_parameters] = override_dependency\n\n\ndef test_override_in_items():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"message\": \"Hello Items!\",\n        \"params\": {\"q\": None, \"skip\": 5, \"limit\": 10},\n    }\n\n\ndef test_override_in_items_with_q():\n    response = client.get(\"/items/?q=foo\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"message\": \"Hello Items!\",\n        \"params\": {\"q\": \"foo\", \"skip\": 5, \"limit\": 10},\n    }\n\n\ndef test_override_in_items_with_params():\n    response = client.get(\"/items/?q=foo&skip=100&limit=200\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"message\": \"Hello Items!\",\n        \"params\": {\"q\": \"foo\", \"skip\": 5, \"limit\": 10},\n    }\n"
  },
  {
    "path": "docs_src/dependency_testing/tutorial001_py310.py",
    "content": "from fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\nasync def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):\n    return {\"q\": q, \"skip\": skip, \"limit\": limit}\n\n\n@app.get(\"/items/\")\nasync def read_items(commons: dict = Depends(common_parameters)):\n    return {\"message\": \"Hello Items!\", \"params\": commons}\n\n\n@app.get(\"/users/\")\nasync def read_users(commons: dict = Depends(common_parameters)):\n    return {\"message\": \"Hello Users!\", \"params\": commons}\n\n\nclient = TestClient(app)\n\n\nasync def override_dependency(q: str | None = None):\n    return {\"q\": q, \"skip\": 5, \"limit\": 10}\n\n\napp.dependency_overrides[common_parameters] = override_dependency\n\n\ndef test_override_in_items():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"message\": \"Hello Items!\",\n        \"params\": {\"q\": None, \"skip\": 5, \"limit\": 10},\n    }\n\n\ndef test_override_in_items_with_q():\n    response = client.get(\"/items/?q=foo\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"message\": \"Hello Items!\",\n        \"params\": {\"q\": \"foo\", \"skip\": 5, \"limit\": 10},\n    }\n\n\ndef test_override_in_items_with_params():\n    response = client.get(\"/items/?q=foo&skip=100&limit=200\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"message\": \"Hello Items!\",\n        \"params\": {\"q\": \"foo\", \"skip\": 5, \"limit\": 10},\n    }\n"
  },
  {
    "path": "docs_src/encoder/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/encoder/tutorial001_py310.py",
    "content": "from datetime import datetime\n\nfrom fastapi import FastAPI\nfrom fastapi.encoders import jsonable_encoder\nfrom pydantic import BaseModel\n\nfake_db = {}\n\n\nclass Item(BaseModel):\n    title: str\n    timestamp: datetime\n    description: str | None = None\n\n\napp = FastAPI()\n\n\n@app.put(\"/items/{id}\")\ndef update_item(id: str, item: Item):\n    json_compatible_item_data = jsonable_encoder(item)\n    fake_db[id] = json_compatible_item_data\n"
  },
  {
    "path": "docs_src/events/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/events/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\nitems = {}\n\n\n@app.on_event(\"startup\")\nasync def startup_event():\n    items[\"foo\"] = {\"name\": \"Fighters\"}\n    items[\"bar\"] = {\"name\": \"Tenders\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(item_id: str):\n    return items[item_id]\n"
  },
  {
    "path": "docs_src/events/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.on_event(\"shutdown\")\ndef shutdown_event():\n    with open(\"log.txt\", mode=\"a\") as log:\n        log.write(\"Application shutdown\")\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return [{\"name\": \"Foo\"}]\n"
  },
  {
    "path": "docs_src/events/tutorial003_py310.py",
    "content": "from contextlib import asynccontextmanager\n\nfrom fastapi import FastAPI\n\n\ndef fake_answer_to_everything_ml_model(x: float):\n    return x * 42\n\n\nml_models = {}\n\n\n@asynccontextmanager\nasync def lifespan(app: FastAPI):\n    # Load the ML model\n    ml_models[\"answer_to_everything\"] = fake_answer_to_everything_ml_model\n    yield\n    # Clean up the ML models and release the resources\n    ml_models.clear()\n\n\napp = FastAPI(lifespan=lifespan)\n\n\n@app.get(\"/predict\")\nasync def predict(x: float):\n    result = ml_models[\"answer_to_everything\"](x)\n    return {\"result\": result}\n"
  },
  {
    "path": "docs_src/extending_openapi/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/extending_openapi/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.openapi.utils import get_openapi\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return [{\"name\": \"Foo\"}]\n\n\ndef custom_openapi():\n    if app.openapi_schema:\n        return app.openapi_schema\n    openapi_schema = get_openapi(\n        title=\"Custom title\",\n        version=\"2.5.0\",\n        summary=\"This is a very custom OpenAPI schema\",\n        description=\"Here's a longer description of the custom **OpenAPI** schema\",\n        routes=app.routes,\n    )\n    openapi_schema[\"info\"][\"x-logo\"] = {\n        \"url\": \"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\"\n    }\n    app.openapi_schema = openapi_schema\n    return app.openapi_schema\n\n\napp.openapi = custom_openapi\n"
  },
  {
    "path": "docs_src/extra_data_types/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/extra_data_types/tutorial001_an_py310.py",
    "content": "from datetime import datetime, time, timedelta\nfrom typing import Annotated\nfrom uuid import UUID\n\nfrom fastapi import Body, FastAPI\n\napp = FastAPI()\n\n\n@app.put(\"/items/{item_id}\")\nasync def read_items(\n    item_id: UUID,\n    start_datetime: Annotated[datetime, Body()],\n    end_datetime: Annotated[datetime, Body()],\n    process_after: Annotated[timedelta, Body()],\n    repeat_at: Annotated[time | None, Body()] = None,\n):\n    start_process = start_datetime + process_after\n    duration = end_datetime - start_process\n    return {\n        \"item_id\": item_id,\n        \"start_datetime\": start_datetime,\n        \"end_datetime\": end_datetime,\n        \"process_after\": process_after,\n        \"repeat_at\": repeat_at,\n        \"start_process\": start_process,\n        \"duration\": duration,\n    }\n"
  },
  {
    "path": "docs_src/extra_data_types/tutorial001_py310.py",
    "content": "from datetime import datetime, time, timedelta\nfrom uuid import UUID\n\nfrom fastapi import Body, FastAPI\n\napp = FastAPI()\n\n\n@app.put(\"/items/{item_id}\")\nasync def read_items(\n    item_id: UUID,\n    start_datetime: datetime = Body(),\n    end_datetime: datetime = Body(),\n    process_after: timedelta = Body(),\n    repeat_at: time | None = Body(default=None),\n):\n    start_process = start_datetime + process_after\n    duration = end_datetime - start_process\n    return {\n        \"item_id\": item_id,\n        \"start_datetime\": start_datetime,\n        \"end_datetime\": end_datetime,\n        \"process_after\": process_after,\n        \"repeat_at\": repeat_at,\n        \"start_process\": start_process,\n        \"duration\": duration,\n    }\n"
  },
  {
    "path": "docs_src/extra_models/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/extra_models/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel, EmailStr\n\napp = FastAPI()\n\n\nclass UserIn(BaseModel):\n    username: str\n    password: str\n    email: EmailStr\n    full_name: str | None = None\n\n\nclass UserOut(BaseModel):\n    username: str\n    email: EmailStr\n    full_name: str | None = None\n\n\nclass UserInDB(BaseModel):\n    username: str\n    hashed_password: str\n    email: EmailStr\n    full_name: str | None = None\n\n\ndef fake_password_hasher(raw_password: str):\n    return \"supersecret\" + raw_password\n\n\ndef fake_save_user(user_in: UserIn):\n    hashed_password = fake_password_hasher(user_in.password)\n    user_in_db = UserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n    print(\"User saved! ..not really\")\n    return user_in_db\n\n\n@app.post(\"/user/\", response_model=UserOut)\nasync def create_user(user_in: UserIn):\n    user_saved = fake_save_user(user_in)\n    return user_saved\n"
  },
  {
    "path": "docs_src/extra_models/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel, EmailStr\n\napp = FastAPI()\n\n\nclass UserBase(BaseModel):\n    username: str\n    email: EmailStr\n    full_name: str | None = None\n\n\nclass UserIn(UserBase):\n    password: str\n\n\nclass UserOut(UserBase):\n    pass\n\n\nclass UserInDB(UserBase):\n    hashed_password: str\n\n\ndef fake_password_hasher(raw_password: str):\n    return \"supersecret\" + raw_password\n\n\ndef fake_save_user(user_in: UserIn):\n    hashed_password = fake_password_hasher(user_in.password)\n    user_in_db = UserInDB(**user_in.model_dump(), hashed_password=hashed_password)\n    print(\"User saved! ..not really\")\n    return user_in_db\n\n\n@app.post(\"/user/\", response_model=UserOut)\nasync def create_user(user_in: UserIn):\n    user_saved = fake_save_user(user_in)\n    return user_saved\n"
  },
  {
    "path": "docs_src/extra_models/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass BaseItem(BaseModel):\n    description: str\n    type: str\n\n\nclass CarItem(BaseItem):\n    type: str = \"car\"\n\n\nclass PlaneItem(BaseItem):\n    type: str = \"plane\"\n    size: int\n\n\nitems = {\n    \"item1\": {\"description\": \"All my friends drive a low rider\", \"type\": \"car\"},\n    \"item2\": {\n        \"description\": \"Music is my aeroplane, it's my aeroplane\",\n        \"type\": \"plane\",\n        \"size\": 5,\n    },\n}\n\n\n@app.get(\"/items/{item_id}\", response_model=PlaneItem | CarItem)\nasync def read_item(item_id: str):\n    return items[item_id]\n"
  },
  {
    "path": "docs_src/extra_models/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str\n\n\nitems = [\n    {\"name\": \"Foo\", \"description\": \"There comes my hero\"},\n    {\"name\": \"Red\", \"description\": \"It's my aeroplane\"},\n]\n\n\n@app.get(\"/items/\", response_model=list[Item])\nasync def read_items():\n    return items\n"
  },
  {
    "path": "docs_src/extra_models/tutorial005_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/keyword-weights/\", response_model=dict[str, float])\nasync def read_keyword_weights():\n    return {\"foo\": 2.3, \"bar\": 3.4}\n"
  },
  {
    "path": "docs_src/first_steps/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/first_steps/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\nasync def root():\n    return {\"message\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/first_steps/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/\")\ndef root():\n    return {\"message\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/generate_clients/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/generate_clients/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\nclass ResponseMessage(BaseModel):\n    message: str\n\n\n@app.post(\"/items/\", response_model=ResponseMessage)\nasync def create_item(item: Item):\n    return {\"message\": \"item received\"}\n\n\n@app.get(\"/items/\", response_model=list[Item])\nasync def get_items():\n    return [\n        {\"name\": \"Plumbus\", \"price\": 3},\n        {\"name\": \"Portal Gun\", \"price\": 9001},\n    ]\n"
  },
  {
    "path": "docs_src/generate_clients/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\nclass ResponseMessage(BaseModel):\n    message: str\n\n\nclass User(BaseModel):\n    username: str\n    email: str\n\n\n@app.post(\"/items/\", response_model=ResponseMessage, tags=[\"items\"])\nasync def create_item(item: Item):\n    return {\"message\": \"Item received\"}\n\n\n@app.get(\"/items/\", response_model=list[Item], tags=[\"items\"])\nasync def get_items():\n    return [\n        {\"name\": \"Plumbus\", \"price\": 3},\n        {\"name\": \"Portal Gun\", \"price\": 9001},\n    ]\n\n\n@app.post(\"/users/\", response_model=ResponseMessage, tags=[\"users\"])\nasync def create_user(user: User):\n    return {\"message\": \"User received\"}\n"
  },
  {
    "path": "docs_src/generate_clients/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.routing import APIRoute\nfrom pydantic import BaseModel\n\n\ndef custom_generate_unique_id(route: APIRoute):\n    return f\"{route.tags[0]}-{route.name}\"\n\n\napp = FastAPI(generate_unique_id_function=custom_generate_unique_id)\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\nclass ResponseMessage(BaseModel):\n    message: str\n\n\nclass User(BaseModel):\n    username: str\n    email: str\n\n\n@app.post(\"/items/\", response_model=ResponseMessage, tags=[\"items\"])\nasync def create_item(item: Item):\n    return {\"message\": \"Item received\"}\n\n\n@app.get(\"/items/\", response_model=list[Item], tags=[\"items\"])\nasync def get_items():\n    return [\n        {\"name\": \"Plumbus\", \"price\": 3},\n        {\"name\": \"Portal Gun\", \"price\": 9001},\n    ]\n\n\n@app.post(\"/users/\", response_model=ResponseMessage, tags=[\"users\"])\nasync def create_user(user: User):\n    return {\"message\": \"User received\"}\n"
  },
  {
    "path": "docs_src/generate_clients/tutorial004.js",
    "content": "import * as fs from 'fs'\n\nasync function modifyOpenAPIFile(filePath) {\n  try {\n    const data = await fs.promises.readFile(filePath)\n    const openapiContent = JSON.parse(data)\n\n    const paths = openapiContent.paths\n    for (const pathKey of Object.keys(paths)) {\n      const pathData = paths[pathKey]\n      for (const method of Object.keys(pathData)) {\n        const operation = pathData[method]\n        if (operation.tags && operation.tags.length > 0) {\n          const tag = operation.tags[0]\n          const operationId = operation.operationId\n          const toRemove = `${tag}-`\n          if (operationId.startsWith(toRemove)) {\n            const newOperationId = operationId.substring(toRemove.length)\n            operation.operationId = newOperationId\n          }\n        }\n      }\n    }\n\n    await fs.promises.writeFile(\n      filePath,\n      JSON.stringify(openapiContent, null, 2),\n    )\n    console.log('File successfully modified')\n  } catch (err) {\n    console.error('Error:', err)\n  }\n}\n\nconst filePath = './openapi.json'\nmodifyOpenAPIFile(filePath)\n"
  },
  {
    "path": "docs_src/generate_clients/tutorial004_py310.py",
    "content": "import json\nfrom pathlib import Path\n\nfile_path = Path(\"./openapi.json\")\nopenapi_content = json.loads(file_path.read_text())\n\nfor path_data in openapi_content[\"paths\"].values():\n    for operation in path_data.values():\n        tag = operation[\"tags\"][0]\n        operation_id = operation[\"operationId\"]\n        to_remove = f\"{tag}-\"\n        new_operation_id = operation_id[len(to_remove) :]\n        operation[\"operationId\"] = new_operation_id\n\nfile_path.write_text(json.dumps(openapi_content))\n"
  },
  {
    "path": "docs_src/graphql_/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/graphql_/tutorial001_py310.py",
    "content": "import strawberry\nfrom fastapi import FastAPI\nfrom strawberry.fastapi import GraphQLRouter\n\n\n@strawberry.type\nclass User:\n    name: str\n    age: int\n\n\n@strawberry.type\nclass Query:\n    @strawberry.field\n    def user(self) -> User:\n        return User(name=\"Patrick\", age=100)\n\n\nschema = strawberry.Schema(query=Query)\n\n\ngraphql_app = GraphQLRouter(schema)\n\napp = FastAPI()\napp.include_router(graphql_app, prefix=\"/graphql\")\n"
  },
  {
    "path": "docs_src/handling_errors/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/handling_errors/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, HTTPException\n\napp = FastAPI()\n\nitems = {\"foo\": \"The Foo Wrestlers\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: str):\n    if item_id not in items:\n        raise HTTPException(status_code=404, detail=\"Item not found\")\n    return {\"item\": items[item_id]}\n"
  },
  {
    "path": "docs_src/handling_errors/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, HTTPException\n\napp = FastAPI()\n\nitems = {\"foo\": \"The Foo Wrestlers\"}\n\n\n@app.get(\"/items-header/{item_id}\")\nasync def read_item_header(item_id: str):\n    if item_id not in items:\n        raise HTTPException(\n            status_code=404,\n            detail=\"Item not found\",\n            headers={\"X-Error\": \"There goes my error\"},\n        )\n    return {\"item\": items[item_id]}\n"
  },
  {
    "path": "docs_src/handling_errors/tutorial003_py310.py",
    "content": "from fastapi import FastAPI, Request\nfrom fastapi.responses import JSONResponse\n\n\nclass UnicornException(Exception):\n    def __init__(self, name: str):\n        self.name = name\n\n\napp = FastAPI()\n\n\n@app.exception_handler(UnicornException)\nasync def unicorn_exception_handler(request: Request, exc: UnicornException):\n    return JSONResponse(\n        status_code=418,\n        content={\"message\": f\"Oops! {exc.name} did something. There goes a rainbow...\"},\n    )\n\n\n@app.get(\"/unicorns/{name}\")\nasync def read_unicorn(name: str):\n    if name == \"yolo\":\n        raise UnicornException(name=name)\n    return {\"unicorn_name\": name}\n"
  },
  {
    "path": "docs_src/handling_errors/tutorial004_py310.py",
    "content": "from fastapi import FastAPI, HTTPException\nfrom fastapi.exceptions import RequestValidationError\nfrom fastapi.responses import PlainTextResponse\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n\napp = FastAPI()\n\n\n@app.exception_handler(StarletteHTTPException)\nasync def http_exception_handler(request, exc):\n    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)\n\n\n@app.exception_handler(RequestValidationError)\nasync def validation_exception_handler(request, exc: RequestValidationError):\n    message = \"Validation errors:\"\n    for error in exc.errors():\n        message += f\"\\nField: {error['loc']}, Error: {error['msg']}\"\n    return PlainTextResponse(message, status_code=400)\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int):\n    if item_id == 3:\n        raise HTTPException(status_code=418, detail=\"Nope! I don't like 3.\")\n    return {\"item_id\": item_id}\n"
  },
  {
    "path": "docs_src/handling_errors/tutorial005_py310.py",
    "content": "from fastapi import FastAPI, Request\nfrom fastapi.encoders import jsonable_encoder\nfrom fastapi.exceptions import RequestValidationError\nfrom fastapi.responses import JSONResponse\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\n@app.exception_handler(RequestValidationError)\nasync def validation_exception_handler(request: Request, exc: RequestValidationError):\n    return JSONResponse(\n        status_code=422,\n        content=jsonable_encoder({\"detail\": exc.errors(), \"body\": exc.body}),\n    )\n\n\nclass Item(BaseModel):\n    title: str\n    size: int\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item):\n    return item\n"
  },
  {
    "path": "docs_src/handling_errors/tutorial006_py310.py",
    "content": "from fastapi import FastAPI, HTTPException\nfrom fastapi.exception_handlers import (\n    http_exception_handler,\n    request_validation_exception_handler,\n)\nfrom fastapi.exceptions import RequestValidationError\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n\napp = FastAPI()\n\n\n@app.exception_handler(StarletteHTTPException)\nasync def custom_http_exception_handler(request, exc):\n    print(f\"OMG! An HTTP error!: {repr(exc)}\")\n    return await http_exception_handler(request, exc)\n\n\n@app.exception_handler(RequestValidationError)\nasync def validation_exception_handler(request, exc):\n    print(f\"OMG! The client sent invalid data!: {exc}\")\n    return await request_validation_exception_handler(request, exc)\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int):\n    if item_id == 3:\n        raise HTTPException(status_code=418, detail=\"Nope! I don't like 3.\")\n    return {\"item_id\": item_id}\n"
  },
  {
    "path": "docs_src/header_param_models/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/header_param_models/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Header\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass CommonHeaders(BaseModel):\n    host: str\n    save_data: bool\n    if_modified_since: str | None = None\n    traceparent: str | None = None\n    x_tag: list[str] = []\n\n\n@app.get(\"/items/\")\nasync def read_items(headers: Annotated[CommonHeaders, Header()]):\n    return headers\n"
  },
  {
    "path": "docs_src/header_param_models/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, Header\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass CommonHeaders(BaseModel):\n    host: str\n    save_data: bool\n    if_modified_since: str | None = None\n    traceparent: str | None = None\n    x_tag: list[str] = []\n\n\n@app.get(\"/items/\")\nasync def read_items(headers: CommonHeaders = Header()):\n    return headers\n"
  },
  {
    "path": "docs_src/header_param_models/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Header\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass CommonHeaders(BaseModel):\n    model_config = {\"extra\": \"forbid\"}\n\n    host: str\n    save_data: bool\n    if_modified_since: str | None = None\n    traceparent: str | None = None\n    x_tag: list[str] = []\n\n\n@app.get(\"/items/\")\nasync def read_items(headers: Annotated[CommonHeaders, Header()]):\n    return headers\n"
  },
  {
    "path": "docs_src/header_param_models/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, Header\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass CommonHeaders(BaseModel):\n    model_config = {\"extra\": \"forbid\"}\n\n    host: str\n    save_data: bool\n    if_modified_since: str | None = None\n    traceparent: str | None = None\n    x_tag: list[str] = []\n\n\n@app.get(\"/items/\")\nasync def read_items(headers: CommonHeaders = Header()):\n    return headers\n"
  },
  {
    "path": "docs_src/header_param_models/tutorial003_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Header\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass CommonHeaders(BaseModel):\n    host: str\n    save_data: bool\n    if_modified_since: str | None = None\n    traceparent: str | None = None\n    x_tag: list[str] = []\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    headers: Annotated[CommonHeaders, Header(convert_underscores=False)],\n):\n    return headers\n"
  },
  {
    "path": "docs_src/header_param_models/tutorial003_py310.py",
    "content": "from fastapi import FastAPI, Header\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass CommonHeaders(BaseModel):\n    host: str\n    save_data: bool\n    if_modified_since: str | None = None\n    traceparent: str | None = None\n    x_tag: list[str] = []\n\n\n@app.get(\"/items/\")\nasync def read_items(headers: CommonHeaders = Header(convert_underscores=False)):\n    return headers\n"
  },
  {
    "path": "docs_src/header_params/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/header_params/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Header\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(user_agent: Annotated[str | None, Header()] = None):\n    return {\"User-Agent\": user_agent}\n"
  },
  {
    "path": "docs_src/header_params/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, Header\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(user_agent: str | None = Header(default=None)):\n    return {\"User-Agent\": user_agent}\n"
  },
  {
    "path": "docs_src/header_params/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Header\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    strange_header: Annotated[str | None, Header(convert_underscores=False)] = None,\n):\n    return {\"strange_header\": strange_header}\n"
  },
  {
    "path": "docs_src/header_params/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, Header\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    strange_header: str | None = Header(default=None, convert_underscores=False),\n):\n    return {\"strange_header\": strange_header}\n"
  },
  {
    "path": "docs_src/header_params/tutorial003_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Header\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(x_token: Annotated[list[str] | None, Header()] = None):\n    return {\"X-Token values\": x_token}\n"
  },
  {
    "path": "docs_src/header_params/tutorial003_py310.py",
    "content": "from fastapi import FastAPI, Header\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(x_token: list[str] | None = Header(default=None)):\n    return {\"X-Token values\": x_token}\n"
  },
  {
    "path": "docs_src/json_base64_bytes/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/json_base64_bytes/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\n\nclass DataInput(BaseModel):\n    description: str\n    data: bytes\n\n    model_config = {\"val_json_bytes\": \"base64\"}\n\n\nclass DataOutput(BaseModel):\n    description: str\n    data: bytes\n\n    model_config = {\"ser_json_bytes\": \"base64\"}\n\n\nclass DataInputOutput(BaseModel):\n    description: str\n    data: bytes\n\n    model_config = {\n        \"val_json_bytes\": \"base64\",\n        \"ser_json_bytes\": \"base64\",\n    }\n\n\napp = FastAPI()\n\n\n@app.post(\"/data\")\ndef post_data(body: DataInput):\n    content = body.data.decode(\"utf-8\")\n    return {\"description\": body.description, \"content\": content}\n\n\n@app.get(\"/data\")\ndef get_data() -> DataOutput:\n    data = \"hello\".encode(\"utf-8\")\n    return DataOutput(description=\"A plumbus\", data=data)\n\n\n@app.post(\"/data-in-out\")\ndef post_data_in_out(body: DataInputOutput) -> DataInputOutput:\n    return body\n"
  },
  {
    "path": "docs_src/metadata/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/metadata/tutorial001_1_py310.py",
    "content": "from fastapi import FastAPI\n\ndescription = \"\"\"\nChimichangApp API helps you do awesome stuff. 🚀\n\n## Items\n\nYou can **read items**.\n\n## Users\n\nYou will be able to:\n\n* **Create users** (_not implemented_).\n* **Read users** (_not implemented_).\n\"\"\"\n\napp = FastAPI(\n    title=\"ChimichangApp\",\n    description=description,\n    summary=\"Deadpool's favorite app. Nuff said.\",\n    version=\"0.0.1\",\n    terms_of_service=\"http://example.com/terms/\",\n    contact={\n        \"name\": \"Deadpoolio the Amazing\",\n        \"url\": \"http://x-force.example.com/contact/\",\n        \"email\": \"dp@x-force.example.com\",\n    },\n    license_info={\n        \"name\": \"Apache 2.0\",\n        \"identifier\": \"Apache-2.0\",\n    },\n)\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return [{\"name\": \"Katana\"}]\n"
  },
  {
    "path": "docs_src/metadata/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\n\ndescription = \"\"\"\nChimichangApp API helps you do awesome stuff. 🚀\n\n## Items\n\nYou can **read items**.\n\n## Users\n\nYou will be able to:\n\n* **Create users** (_not implemented_).\n* **Read users** (_not implemented_).\n\"\"\"\n\napp = FastAPI(\n    title=\"ChimichangApp\",\n    description=description,\n    summary=\"Deadpool's favorite app. Nuff said.\",\n    version=\"0.0.1\",\n    terms_of_service=\"http://example.com/terms/\",\n    contact={\n        \"name\": \"Deadpoolio the Amazing\",\n        \"url\": \"http://x-force.example.com/contact/\",\n        \"email\": \"dp@x-force.example.com\",\n    },\n    license_info={\n        \"name\": \"Apache 2.0\",\n        \"url\": \"https://www.apache.org/licenses/LICENSE-2.0.html\",\n    },\n)\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return [{\"name\": \"Katana\"}]\n"
  },
  {
    "path": "docs_src/metadata/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI(openapi_url=\"/api/v1/openapi.json\")\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return [{\"name\": \"Foo\"}]\n"
  },
  {
    "path": "docs_src/metadata/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI(docs_url=\"/documentation\", redoc_url=None)\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return [{\"name\": \"Foo\"}]\n"
  },
  {
    "path": "docs_src/metadata/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\n\ntags_metadata = [\n    {\n        \"name\": \"users\",\n        \"description\": \"Operations with users. The **login** logic is also here.\",\n    },\n    {\n        \"name\": \"items\",\n        \"description\": \"Manage items. So _fancy_ they have their own docs.\",\n        \"externalDocs\": {\n            \"description\": \"Items external docs\",\n            \"url\": \"https://fastapi.tiangolo.com/\",\n        },\n    },\n]\n\napp = FastAPI(openapi_tags=tags_metadata)\n\n\n@app.get(\"/users/\", tags=[\"users\"])\nasync def get_users():\n    return [{\"name\": \"Harry\"}, {\"name\": \"Ron\"}]\n\n\n@app.get(\"/items/\", tags=[\"items\"])\nasync def get_items():\n    return [{\"name\": \"wand\"}, {\"name\": \"flying broom\"}]\n"
  },
  {
    "path": "docs_src/middleware/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/middleware/tutorial001_py310.py",
    "content": "import time\n\nfrom fastapi import FastAPI, Request\n\napp = FastAPI()\n\n\n@app.middleware(\"http\")\nasync def add_process_time_header(request: Request, call_next):\n    start_time = time.perf_counter()\n    response = await call_next(request)\n    process_time = time.perf_counter() - start_time\n    response.headers[\"X-Process-Time\"] = str(process_time)\n    return response\n"
  },
  {
    "path": "docs_src/openapi_callbacks/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/openapi_callbacks/tutorial001_py310.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom pydantic import BaseModel, HttpUrl\n\napp = FastAPI()\n\n\nclass Invoice(BaseModel):\n    id: str\n    title: str | None = None\n    customer: str\n    total: float\n\n\nclass InvoiceEvent(BaseModel):\n    description: str\n    paid: bool\n\n\nclass InvoiceEventReceived(BaseModel):\n    ok: bool\n\n\ninvoices_callback_router = APIRouter()\n\n\n@invoices_callback_router.post(\n    \"{$callback_url}/invoices/{$request.body.id}\", response_model=InvoiceEventReceived\n)\ndef invoice_notification(body: InvoiceEvent):\n    pass\n\n\n@app.post(\"/invoices/\", callbacks=invoices_callback_router.routes)\ndef create_invoice(invoice: Invoice, callback_url: HttpUrl | None = None):\n    \"\"\"\n    Create an invoice.\n\n    This will (let's imagine) let the API user (some external developer) create an\n    invoice.\n\n    And this path operation will:\n\n    * Send the invoice to the client.\n    * Collect the money from the client.\n    * Send a notification back to the API user (the external developer), as a callback.\n        * At this point is that the API will somehow send a POST request to the\n            external API with the notification of the invoice event\n            (e.g. \"payment successful\").\n    \"\"\"\n    # Send the invoice, collect the money, send the notification (the callback)\n    return {\"msg\": \"Invoice received\"}\n"
  },
  {
    "path": "docs_src/openapi_webhooks/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/openapi_webhooks/tutorial001_py310.py",
    "content": "from datetime import datetime\n\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Subscription(BaseModel):\n    username: str\n    monthly_fee: float\n    start_date: datetime\n\n\n@app.webhooks.post(\"new-subscription\")\ndef new_subscription(body: Subscription):\n    \"\"\"\n    When a new user subscribes to your service we'll send you a POST request with this\n    data to the URL that you register for the event `new-subscription` in the dashboard.\n    \"\"\"\n\n\n@app.get(\"/users/\")\ndef read_users():\n    return [\"Rick\", \"Morty\"]\n"
  },
  {
    "path": "docs_src/path_operation_advanced_configuration/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/path_operation_advanced_configuration/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/\", operation_id=\"some_specific_id_you_define\")\nasync def read_items():\n    return [{\"item_id\": \"Foo\"}]\n"
  },
  {
    "path": "docs_src/path_operation_advanced_configuration/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.routing import APIRoute\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return [{\"item_id\": \"Foo\"}]\n\n\ndef use_route_names_as_operation_ids(app: FastAPI) -> None:\n    \"\"\"\n    Simplify operation IDs so that generated API clients have simpler function\n    names.\n\n    Should be called only after all routes have been added.\n    \"\"\"\n    for route in app.routes:\n        if isinstance(route, APIRoute):\n            route.operation_id = route.name  # in this case, 'read_items'\n\n\nuse_route_names_as_operation_ids(app)\n"
  },
  {
    "path": "docs_src/path_operation_advanced_configuration/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/\", include_in_schema=False)\nasync def read_items():\n    return [{\"item_id\": \"Foo\"}]\n"
  },
  {
    "path": "docs_src/path_operation_advanced_configuration/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n\n\n@app.post(\"/items/\", summary=\"Create an item\")\nasync def create_item(item: Item) -> Item:\n    \"\"\"\n    Create an item with all the information:\n\n    - **name**: each item must have a name\n    - **description**: a long description\n    - **price**: required\n    - **tax**: if the item doesn't have tax, you can omit this\n    - **tags**: a set of unique tag strings for this item\n    \\f\n    :param item: User input.\n    \"\"\"\n    return item\n"
  },
  {
    "path": "docs_src/path_operation_advanced_configuration/tutorial005_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/\", openapi_extra={\"x-aperture-labs-portal\": \"blue\"})\nasync def read_items():\n    return [{\"item_id\": \"portal-gun\"}]\n"
  },
  {
    "path": "docs_src/path_operation_advanced_configuration/tutorial006_py310.py",
    "content": "from fastapi import FastAPI, Request\n\napp = FastAPI()\n\n\ndef magic_data_reader(raw_body: bytes):\n    return {\n        \"size\": len(raw_body),\n        \"content\": {\n            \"name\": \"Maaaagic\",\n            \"price\": 42,\n            \"description\": \"Just kiddin', no magic here. ✨\",\n        },\n    }\n\n\n@app.post(\n    \"/items/\",\n    openapi_extra={\n        \"requestBody\": {\n            \"content\": {\n                \"application/json\": {\n                    \"schema\": {\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\"},\n                            \"price\": {\"type\": \"number\"},\n                            \"description\": {\"type\": \"string\"},\n                        },\n                    }\n                }\n            },\n            \"required\": True,\n        },\n    },\n)\nasync def create_item(request: Request):\n    raw_body = await request.body()\n    data = magic_data_reader(raw_body)\n    return data\n"
  },
  {
    "path": "docs_src/path_operation_advanced_configuration/tutorial007_py310.py",
    "content": "import yaml\nfrom fastapi import FastAPI, HTTPException, Request\nfrom pydantic import BaseModel, ValidationError\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    tags: list[str]\n\n\n@app.post(\n    \"/items/\",\n    openapi_extra={\n        \"requestBody\": {\n            \"content\": {\"application/x-yaml\": {\"schema\": Item.model_json_schema()}},\n            \"required\": True,\n        },\n    },\n)\nasync def create_item(request: Request):\n    raw_body = await request.body()\n    try:\n        data = yaml.safe_load(raw_body)\n    except yaml.YAMLError:\n        raise HTTPException(status_code=422, detail=\"Invalid YAML\")\n    try:\n        item = Item.model_validate(data)\n    except ValidationError as e:\n        raise HTTPException(status_code=422, detail=e.errors(include_url=False))\n    return item\n"
  },
  {
    "path": "docs_src/path_operation_configuration/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/path_operation_configuration/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, status\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n\n\n@app.post(\"/items/\", status_code=status.HTTP_201_CREATED)\nasync def create_item(item: Item) -> Item:\n    return item\n"
  },
  {
    "path": "docs_src/path_operation_configuration/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n\n\n@app.post(\"/items/\", tags=[\"items\"])\nasync def create_item(item: Item) -> Item:\n    return item\n\n\n@app.get(\"/items/\", tags=[\"items\"])\nasync def read_items():\n    return [{\"name\": \"Foo\", \"price\": 42}]\n\n\n@app.get(\"/users/\", tags=[\"users\"])\nasync def read_users():\n    return [{\"username\": \"johndoe\"}]\n"
  },
  {
    "path": "docs_src/path_operation_configuration/tutorial002b_py310.py",
    "content": "from enum import Enum\n\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\nclass Tags(Enum):\n    items = \"items\"\n    users = \"users\"\n\n\n@app.get(\"/items/\", tags=[Tags.items])\nasync def get_items():\n    return [\"Portal gun\", \"Plumbus\"]\n\n\n@app.get(\"/users/\", tags=[Tags.users])\nasync def read_users():\n    return [\"Rick\", \"Morty\"]\n"
  },
  {
    "path": "docs_src/path_operation_configuration/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n\n\n@app.post(\n    \"/items/\",\n    summary=\"Create an item\",\n    description=\"Create an item with all the information, name, description, price, tax and a set of unique tags\",\n)\nasync def create_item(item: Item) -> Item:\n    return item\n"
  },
  {
    "path": "docs_src/path_operation_configuration/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n\n\n@app.post(\"/items/\", summary=\"Create an item\")\nasync def create_item(item: Item) -> Item:\n    \"\"\"\n    Create an item with all the information:\n\n    - **name**: each item must have a name\n    - **description**: a long description\n    - **price**: required\n    - **tax**: if the item doesn't have tax, you can omit this\n    - **tags**: a set of unique tag strings for this item\n    \"\"\"\n    return item\n"
  },
  {
    "path": "docs_src/path_operation_configuration/tutorial005_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: set[str] = set()\n\n\n@app.post(\n    \"/items/\",\n    summary=\"Create an item\",\n    response_description=\"The created item\",\n)\nasync def create_item(item: Item) -> Item:\n    \"\"\"\n    Create an item with all the information:\n\n    - **name**: each item must have a name\n    - **description**: a long description\n    - **price**: required\n    - **tax**: if the item doesn't have tax, you can omit this\n    - **tags**: a set of unique tag strings for this item\n    \"\"\"\n    return item\n"
  },
  {
    "path": "docs_src/path_operation_configuration/tutorial006_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/\", tags=[\"items\"])\nasync def read_items():\n    return [{\"name\": \"Foo\", \"price\": 42}]\n\n\n@app.get(\"/users/\", tags=[\"users\"])\nasync def read_users():\n    return [{\"username\": \"johndoe\"}]\n\n\n@app.get(\"/elements/\", tags=[\"items\"], deprecated=True)\nasync def read_elements():\n    return [{\"item_id\": \"Foo\"}]\n"
  },
  {
    "path": "docs_src/path_params/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/path_params/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id):\n    return {\"item_id\": item_id}\n"
  },
  {
    "path": "docs_src/path_params/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: int):\n    return {\"item_id\": item_id}\n"
  },
  {
    "path": "docs_src/path_params/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/users/me\")\nasync def read_user_me():\n    return {\"user_id\": \"the current user\"}\n\n\n@app.get(\"/users/{user_id}\")\nasync def read_user(user_id: str):\n    return {\"user_id\": user_id}\n"
  },
  {
    "path": "docs_src/path_params/tutorial003b_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/users\")\nasync def read_users():\n    return [\"Rick\", \"Morty\"]\n\n\n@app.get(\"/users\")\nasync def read_users2():\n    return [\"Bean\", \"Elfo\"]\n"
  },
  {
    "path": "docs_src/path_params/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/files/{file_path:path}\")\nasync def read_file(file_path: str):\n    return {\"file_path\": file_path}\n"
  },
  {
    "path": "docs_src/path_params/tutorial005_py310.py",
    "content": "from enum import Enum\n\nfrom fastapi import FastAPI\n\n\nclass ModelName(str, Enum):\n    alexnet = \"alexnet\"\n    resnet = \"resnet\"\n    lenet = \"lenet\"\n\n\napp = FastAPI()\n\n\n@app.get(\"/models/{model_name}\")\nasync def get_model(model_name: ModelName):\n    if model_name is ModelName.alexnet:\n        return {\"model_name\": model_name, \"message\": \"Deep Learning FTW!\"}\n\n    if model_name.value == \"lenet\":\n        return {\"model_name\": model_name, \"message\": \"LeCNN all the images\"}\n\n    return {\"model_name\": model_name, \"message\": \"Have some residuals\"}\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Path, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(\n    item_id: Annotated[int, Path(title=\"The ID of the item to get\")],\n    q: Annotated[str | None, Query(alias=\"item-query\")] = None,\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, Path, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(\n    item_id: int = Path(title=\"The ID of the item to get\"),\n    q: str | None = Query(default=None, alias=\"item-query\"),\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Path\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(\n    q: str, item_id: Annotated[int, Path(title=\"The ID of the item to get\")]\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, Path\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(q: str, item_id: int = Path(title=\"The ID of the item to get\")):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial003_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Path\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(\n    item_id: Annotated[int, Path(title=\"The ID of the item to get\")], q: str\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial003_py310.py",
    "content": "from fastapi import FastAPI, Path\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(*, item_id: int = Path(title=\"The ID of the item to get\"), q: str):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial004_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Path\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(\n    item_id: Annotated[int, Path(title=\"The ID of the item to get\", ge=1)], q: str\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial004_py310.py",
    "content": "from fastapi import FastAPI, Path\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(\n    *, item_id: int = Path(title=\"The ID of the item to get\", ge=1), q: str\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial005_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Path\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(\n    item_id: Annotated[int, Path(title=\"The ID of the item to get\", gt=0, le=1000)],\n    q: str,\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial005_py310.py",
    "content": "from fastapi import FastAPI, Path\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(\n    *,\n    item_id: int = Path(title=\"The ID of the item to get\", gt=0, le=1000),\n    q: str,\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial006_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Path, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(\n    *,\n    item_id: Annotated[int, Path(title=\"The ID of the item to get\", ge=0, le=1000)],\n    q: str,\n    size: Annotated[float, Query(gt=0, lt=10.5)],\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    if size:\n        results.update({\"size\": size})\n    return results\n"
  },
  {
    "path": "docs_src/path_params_numeric_validations/tutorial006_py310.py",
    "content": "from fastapi import FastAPI, Path, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_items(\n    *,\n    item_id: int = Path(title=\"The ID of the item to get\", ge=0, le=1000),\n    q: str,\n    size: float = Query(gt=0, lt=10.5),\n):\n    results = {\"item_id\": item_id}\n    if q:\n        results.update({\"q\": q})\n    if size:\n        results.update({\"size\": size})\n    return results\n"
  },
  {
    "path": "docs_src/pydantic_v1_in_v2/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py",
    "content": "from pydantic.v1 import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    size: float\n"
  },
  {
    "path": "docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic.v1 import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    size: float\n\n\napp = FastAPI()\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item) -> Item:\n    return item\n"
  },
  {
    "path": "docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel as BaseModelV2\nfrom pydantic.v1 import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    size: float\n\n\nclass ItemV2(BaseModelV2):\n    name: str\n    description: str | None = None\n    size: float\n\n\napp = FastAPI()\n\n\n@app.post(\"/items/\", response_model=ItemV2)\nasync def create_item(item: Item):\n    return item\n"
  },
  {
    "path": "docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI\nfrom fastapi.temp_pydantic_v1_params import Body\nfrom pydantic.v1 import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    size: float\n\n\napp = FastAPI()\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Annotated[Item, Body(embed=True)]) -> Item:\n    return item\n"
  },
  {
    "path": "docs_src/python_types/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/python_types/tutorial001_py310.py",
    "content": "def get_full_name(first_name, last_name):\n    full_name = first_name.title() + \" \" + last_name.title()\n    return full_name\n\n\nprint(get_full_name(\"john\", \"doe\"))\n"
  },
  {
    "path": "docs_src/python_types/tutorial002_py310.py",
    "content": "def get_full_name(first_name: str, last_name: str):\n    full_name = first_name.title() + \" \" + last_name.title()\n    return full_name\n\n\nprint(get_full_name(\"john\", \"doe\"))\n"
  },
  {
    "path": "docs_src/python_types/tutorial003_py310.py",
    "content": "def get_name_with_age(name: str, age: int):\n    name_with_age = name + \" is this old: \" + age\n    return name_with_age\n"
  },
  {
    "path": "docs_src/python_types/tutorial004_py310.py",
    "content": "def get_name_with_age(name: str, age: int):\n    name_with_age = name + \" is this old: \" + str(age)\n    return name_with_age\n"
  },
  {
    "path": "docs_src/python_types/tutorial005_py310.py",
    "content": "def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):\n    return item_a, item_b, item_c, item_d, item_e\n"
  },
  {
    "path": "docs_src/python_types/tutorial006_py310.py",
    "content": "def process_items(items: list[str]):\n    for item in items:\n        print(item)\n"
  },
  {
    "path": "docs_src/python_types/tutorial007_py310.py",
    "content": "def process_items(items_t: tuple[int, int, str], items_s: set[bytes]):\n    return items_t, items_s\n"
  },
  {
    "path": "docs_src/python_types/tutorial008_py310.py",
    "content": "def process_items(prices: dict[str, float]):\n    for item_name, item_price in prices.items():\n        print(item_name)\n        print(item_price)\n"
  },
  {
    "path": "docs_src/python_types/tutorial008b_py310.py",
    "content": "def process_item(item: int | str):\n    print(item)\n"
  },
  {
    "path": "docs_src/python_types/tutorial009_py310.py",
    "content": "def say_hi(name: str | None = None):\n    if name is not None:\n        print(f\"Hey {name}!\")\n    else:\n        print(\"Hello World\")\n"
  },
  {
    "path": "docs_src/python_types/tutorial010_py310.py",
    "content": "class Person:\n    def __init__(self, name: str):\n        self.name = name\n\n\ndef get_person_name(one_person: Person):\n    return one_person.name\n"
  },
  {
    "path": "docs_src/python_types/tutorial011_py310.py",
    "content": "from datetime import datetime\n\nfrom pydantic import BaseModel\n\n\nclass User(BaseModel):\n    id: int\n    name: str = \"John Doe\"\n    signup_ts: datetime | None = None\n    friends: list[int] = []\n\n\nexternal_data = {\n    \"id\": \"123\",\n    \"signup_ts\": \"2017-06-01 12:22\",\n    \"friends\": [1, \"2\", b\"3\"],\n}\nuser = User(**external_data)\nprint(user)\n# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]\nprint(user.id)\n# > 123\n"
  },
  {
    "path": "docs_src/python_types/tutorial013_py310.py",
    "content": "from typing import Annotated\n\n\ndef say_hello(name: Annotated[str, \"this is just metadata\"]) -> str:\n    return f\"Hello {name}\"\n"
  },
  {
    "path": "docs_src/query_param_models/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/query_param_models/tutorial001_an_py310.py",
    "content": "from typing import Annotated, Literal\n\nfrom fastapi import FastAPI, Query\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n\nclass FilterParams(BaseModel):\n    limit: int = Field(100, gt=0, le=100)\n    offset: int = Field(0, ge=0)\n    order_by: Literal[\"created_at\", \"updated_at\"] = \"created_at\"\n    tags: list[str] = []\n\n\n@app.get(\"/items/\")\nasync def read_items(filter_query: Annotated[FilterParams, Query()]):\n    return filter_query\n"
  },
  {
    "path": "docs_src/query_param_models/tutorial001_py310.py",
    "content": "from typing import Literal\n\nfrom fastapi import FastAPI, Query\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n\nclass FilterParams(BaseModel):\n    limit: int = Field(100, gt=0, le=100)\n    offset: int = Field(0, ge=0)\n    order_by: Literal[\"created_at\", \"updated_at\"] = \"created_at\"\n    tags: list[str] = []\n\n\n@app.get(\"/items/\")\nasync def read_items(filter_query: FilterParams = Query()):\n    return filter_query\n"
  },
  {
    "path": "docs_src/query_param_models/tutorial002_an_py310.py",
    "content": "from typing import Annotated, Literal\n\nfrom fastapi import FastAPI, Query\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n\nclass FilterParams(BaseModel):\n    model_config = {\"extra\": \"forbid\"}\n\n    limit: int = Field(100, gt=0, le=100)\n    offset: int = Field(0, ge=0)\n    order_by: Literal[\"created_at\", \"updated_at\"] = \"created_at\"\n    tags: list[str] = []\n\n\n@app.get(\"/items/\")\nasync def read_items(filter_query: Annotated[FilterParams, Query()]):\n    return filter_query\n"
  },
  {
    "path": "docs_src/query_param_models/tutorial002_py310.py",
    "content": "from typing import Literal\n\nfrom fastapi import FastAPI, Query\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n\nclass FilterParams(BaseModel):\n    model_config = {\"extra\": \"forbid\"}\n\n    limit: int = Field(100, gt=0, le=100)\n    offset: int = Field(0, ge=0)\n    order_by: Literal[\"created_at\", \"updated_at\"] = \"created_at\"\n    tags: list[str] = []\n\n\n@app.get(\"/items/\")\nasync def read_items(filter_query: FilterParams = Query()):\n    return filter_query\n"
  },
  {
    "path": "docs_src/query_params/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/query_params/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\nfake_items_db = [{\"item_name\": \"Foo\"}, {\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}]\n\n\n@app.get(\"/items/\")\nasync def read_item(skip: int = 0, limit: int = 10):\n    return fake_items_db[skip : skip + limit]\n"
  },
  {
    "path": "docs_src/query_params/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: str, q: str | None = None):\n    if q:\n        return {\"item_id\": item_id, \"q\": q}\n    return {\"item_id\": item_id}\n"
  },
  {
    "path": "docs_src/query_params/tutorial003_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: str, q: str | None = None, short: bool = False):\n    item = {\"item_id\": item_id}\n    if q:\n        item.update({\"q\": q})\n    if not short:\n        item.update(\n            {\"description\": \"This is an amazing item that has a long description\"}\n        )\n    return item\n"
  },
  {
    "path": "docs_src/query_params/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/users/{user_id}/items/{item_id}\")\nasync def read_user_item(\n    user_id: int, item_id: str, q: str | None = None, short: bool = False\n):\n    item = {\"item_id\": item_id, \"owner_id\": user_id}\n    if q:\n        item.update({\"q\": q})\n    if not short:\n        item.update(\n            {\"description\": \"This is an amazing item that has a long description\"}\n        )\n    return item\n"
  },
  {
    "path": "docs_src/query_params/tutorial005_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_user_item(item_id: str, needy: str):\n    item = {\"item_id\": item_id, \"needy\": needy}\n    return item\n"
  },
  {
    "path": "docs_src/query_params/tutorial006_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_user_item(\n    item_id: str, needy: str, skip: int = 0, limit: int | None = None\n):\n    item = {\"item_id\": item_id, \"needy\": needy, \"skip\": skip, \"limit\": limit}\n    return item\n"
  },
  {
    "path": "docs_src/query_params_str_validations/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: str | None = None):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: Annotated[str | None, Query(max_length=50)] = None):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: str | None = Query(default=None, max_length=50)):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial003_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    q: Annotated[str | None, Query(min_length=3, max_length=50)] = None,\n):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial003_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: str | None = Query(default=None, min_length=3, max_length=50)):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial004_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    q: Annotated[\n        str | None, Query(min_length=3, max_length=50, pattern=\"^fixedquery$\")\n    ] = None,\n):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial004_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    q: str | None = Query(\n        default=None, min_length=3, max_length=50, pattern=\"^fixedquery$\"\n    ),\n):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial005_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: Annotated[str, Query(min_length=3)] = \"fixedquery\"):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial005_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: str = Query(default=\"fixedquery\", min_length=3)):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial006_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: Annotated[str, Query(min_length=3)]):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial006_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: str = Query(min_length=3)):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial006c_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: Annotated[str | None, Query(min_length=3)]):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial006c_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: str | None = Query(min_length=3)):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial007_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    q: Annotated[str | None, Query(title=\"Query string\", min_length=3)] = None,\n):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial007_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    q: str | None = Query(default=None, title=\"Query string\", min_length=3),\n):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial008_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    q: Annotated[\n        str | None,\n        Query(\n            title=\"Query string\",\n            description=\"Query string for the items to search in the database that have a good match\",\n            min_length=3,\n        ),\n    ] = None,\n):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial008_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    q: str | None = Query(\n        default=None,\n        title=\"Query string\",\n        description=\"Query string for the items to search in the database that have a good match\",\n        min_length=3,\n    ),\n):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial009_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: Annotated[str | None, Query(alias=\"item-query\")] = None):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial009_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: str | None = Query(default=None, alias=\"item-query\")):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial010_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    q: Annotated[\n        str | None,\n        Query(\n            alias=\"item-query\",\n            title=\"Query string\",\n            description=\"Query string for the items to search in the database that have a good match\",\n            min_length=3,\n            max_length=50,\n            pattern=\"^fixedquery$\",\n            deprecated=True,\n        ),\n    ] = None,\n):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial010_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    q: str | None = Query(\n        default=None,\n        alias=\"item-query\",\n        title=\"Query string\",\n        description=\"Query string for the items to search in the database that have a good match\",\n        min_length=3,\n        max_length=50,\n        pattern=\"^fixedquery$\",\n        deprecated=True,\n    ),\n):\n    results = {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n    if q:\n        results.update({\"q\": q})\n    return results\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial011_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: Annotated[list[str] | None, Query()] = None):\n    query_items = {\"q\": q}\n    return query_items\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial011_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: list[str] | None = Query(default=None)):\n    query_items = {\"q\": q}\n    return query_items\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial012_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: Annotated[list[str], Query()] = [\"foo\", \"bar\"]):\n    query_items = {\"q\": q}\n    return query_items\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial012_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: list[str] = Query(default=[\"foo\", \"bar\"])):\n    query_items = {\"q\": q}\n    return query_items\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial013_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: Annotated[list, Query()] = []):\n    query_items = {\"q\": q}\n    return query_items\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial013_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(q: list = Query(default=[])):\n    query_items = {\"q\": q}\n    return query_items\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial014_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    hidden_query: Annotated[str | None, Query(include_in_schema=False)] = None,\n):\n    if hidden_query:\n        return {\"hidden_query\": hidden_query}\n    else:\n        return {\"hidden_query\": \"Not found\"}\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial014_py310.py",
    "content": "from fastapi import FastAPI, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    hidden_query: str | None = Query(default=None, include_in_schema=False),\n):\n    if hidden_query:\n        return {\"hidden_query\": hidden_query}\n    else:\n        return {\"hidden_query\": \"Not found\"}\n"
  },
  {
    "path": "docs_src/query_params_str_validations/tutorial015_an_py310.py",
    "content": "import random\nfrom typing import Annotated\n\nfrom fastapi import FastAPI\nfrom pydantic import AfterValidator\n\napp = FastAPI()\n\ndata = {\n    \"isbn-9781529046137\": \"The Hitchhiker's Guide to the Galaxy\",\n    \"imdb-tt0371724\": \"The Hitchhiker's Guide to the Galaxy\",\n    \"isbn-9781439512982\": \"Isaac Asimov: The Complete Stories, Vol. 2\",\n}\n\n\ndef check_valid_id(id: str):\n    if not id.startswith((\"isbn-\", \"imdb-\")):\n        raise ValueError('Invalid ID format, it must start with \"isbn-\" or \"imdb-\"')\n    return id\n\n\n@app.get(\"/items/\")\nasync def read_items(\n    id: Annotated[str | None, AfterValidator(check_valid_id)] = None,\n):\n    if id:\n        item = data.get(id)\n    else:\n        id, item = random.choice(list(data.items()))\n    return {\"id\": id, \"name\": item}\n"
  },
  {
    "path": "docs_src/request_files/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/request_files/tutorial001_02_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, File, UploadFile\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_file(file: Annotated[bytes | None, File()] = None):\n    if not file:\n        return {\"message\": \"No file sent\"}\n    else:\n        return {\"file_size\": len(file)}\n\n\n@app.post(\"/uploadfile/\")\nasync def create_upload_file(file: UploadFile | None = None):\n    if not file:\n        return {\"message\": \"No upload file sent\"}\n    else:\n        return {\"filename\": file.filename}\n"
  },
  {
    "path": "docs_src/request_files/tutorial001_02_py310.py",
    "content": "from fastapi import FastAPI, File, UploadFile\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_file(file: bytes | None = File(default=None)):\n    if not file:\n        return {\"message\": \"No file sent\"}\n    else:\n        return {\"file_size\": len(file)}\n\n\n@app.post(\"/uploadfile/\")\nasync def create_upload_file(file: UploadFile | None = None):\n    if not file:\n        return {\"message\": \"No upload file sent\"}\n    else:\n        return {\"filename\": file.filename}\n"
  },
  {
    "path": "docs_src/request_files/tutorial001_03_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, File, UploadFile\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_file(file: Annotated[bytes, File(description=\"A file read as bytes\")]):\n    return {\"file_size\": len(file)}\n\n\n@app.post(\"/uploadfile/\")\nasync def create_upload_file(\n    file: Annotated[UploadFile, File(description=\"A file read as UploadFile\")],\n):\n    return {\"filename\": file.filename}\n"
  },
  {
    "path": "docs_src/request_files/tutorial001_03_py310.py",
    "content": "from fastapi import FastAPI, File, UploadFile\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_file(file: bytes = File(description=\"A file read as bytes\")):\n    return {\"file_size\": len(file)}\n\n\n@app.post(\"/uploadfile/\")\nasync def create_upload_file(\n    file: UploadFile = File(description=\"A file read as UploadFile\"),\n):\n    return {\"filename\": file.filename}\n"
  },
  {
    "path": "docs_src/request_files/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, File, UploadFile\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_file(file: Annotated[bytes, File()]):\n    return {\"file_size\": len(file)}\n\n\n@app.post(\"/uploadfile/\")\nasync def create_upload_file(file: UploadFile):\n    return {\"filename\": file.filename}\n"
  },
  {
    "path": "docs_src/request_files/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, File, UploadFile\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_file(file: bytes = File()):\n    return {\"file_size\": len(file)}\n\n\n@app.post(\"/uploadfile/\")\nasync def create_upload_file(file: UploadFile):\n    return {\"filename\": file.filename}\n"
  },
  {
    "path": "docs_src/request_files/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, File, UploadFile\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_files(files: Annotated[list[bytes], File()]):\n    return {\"file_sizes\": [len(file) for file in files]}\n\n\n@app.post(\"/uploadfiles/\")\nasync def create_upload_files(files: list[UploadFile]):\n    return {\"filenames\": [file.filename for file in files]}\n\n\n@app.get(\"/\")\nasync def main():\n    content = \"\"\"\n<body>\n<form action=\"/files/\" enctype=\"multipart/form-data\" method=\"post\">\n<input name=\"files\" type=\"file\" multiple>\n<input type=\"submit\">\n</form>\n<form action=\"/uploadfiles/\" enctype=\"multipart/form-data\" method=\"post\">\n<input name=\"files\" type=\"file\" multiple>\n<input type=\"submit\">\n</form>\n</body>\n    \"\"\"\n    return HTMLResponse(content=content)\n"
  },
  {
    "path": "docs_src/request_files/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, File, UploadFile\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_files(files: list[bytes] = File()):\n    return {\"file_sizes\": [len(file) for file in files]}\n\n\n@app.post(\"/uploadfiles/\")\nasync def create_upload_files(files: list[UploadFile]):\n    return {\"filenames\": [file.filename for file in files]}\n\n\n@app.get(\"/\")\nasync def main():\n    content = \"\"\"\n<body>\n<form action=\"/files/\" enctype=\"multipart/form-data\" method=\"post\">\n<input name=\"files\" type=\"file\" multiple>\n<input type=\"submit\">\n</form>\n<form action=\"/uploadfiles/\" enctype=\"multipart/form-data\" method=\"post\">\n<input name=\"files\" type=\"file\" multiple>\n<input type=\"submit\">\n</form>\n</body>\n    \"\"\"\n    return HTMLResponse(content=content)\n"
  },
  {
    "path": "docs_src/request_files/tutorial003_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, File, UploadFile\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_files(\n    files: Annotated[list[bytes], File(description=\"Multiple files as bytes\")],\n):\n    return {\"file_sizes\": [len(file) for file in files]}\n\n\n@app.post(\"/uploadfiles/\")\nasync def create_upload_files(\n    files: Annotated[\n        list[UploadFile], File(description=\"Multiple files as UploadFile\")\n    ],\n):\n    return {\"filenames\": [file.filename for file in files]}\n\n\n@app.get(\"/\")\nasync def main():\n    content = \"\"\"\n<body>\n<form action=\"/files/\" enctype=\"multipart/form-data\" method=\"post\">\n<input name=\"files\" type=\"file\" multiple>\n<input type=\"submit\">\n</form>\n<form action=\"/uploadfiles/\" enctype=\"multipart/form-data\" method=\"post\">\n<input name=\"files\" type=\"file\" multiple>\n<input type=\"submit\">\n</form>\n</body>\n    \"\"\"\n    return HTMLResponse(content=content)\n"
  },
  {
    "path": "docs_src/request_files/tutorial003_py310.py",
    "content": "from fastapi import FastAPI, File, UploadFile\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_files(\n    files: list[bytes] = File(description=\"Multiple files as bytes\"),\n):\n    return {\"file_sizes\": [len(file) for file in files]}\n\n\n@app.post(\"/uploadfiles/\")\nasync def create_upload_files(\n    files: list[UploadFile] = File(description=\"Multiple files as UploadFile\"),\n):\n    return {\"filenames\": [file.filename for file in files]}\n\n\n@app.get(\"/\")\nasync def main():\n    content = \"\"\"\n<body>\n<form action=\"/files/\" enctype=\"multipart/form-data\" method=\"post\">\n<input name=\"files\" type=\"file\" multiple>\n<input type=\"submit\">\n</form>\n<form action=\"/uploadfiles/\" enctype=\"multipart/form-data\" method=\"post\">\n<input name=\"files\" type=\"file\" multiple>\n<input type=\"submit\">\n</form>\n</body>\n    \"\"\"\n    return HTMLResponse(content=content)\n"
  },
  {
    "path": "docs_src/request_form_models/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/request_form_models/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Form\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass FormData(BaseModel):\n    username: str\n    password: str\n\n\n@app.post(\"/login/\")\nasync def login(data: Annotated[FormData, Form()]):\n    return data\n"
  },
  {
    "path": "docs_src/request_form_models/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, Form\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass FormData(BaseModel):\n    username: str\n    password: str\n\n\n@app.post(\"/login/\")\nasync def login(data: FormData = Form()):\n    return data\n"
  },
  {
    "path": "docs_src/request_form_models/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Form\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass FormData(BaseModel):\n    username: str\n    password: str\n    model_config = {\"extra\": \"forbid\"}\n\n\n@app.post(\"/login/\")\nasync def login(data: Annotated[FormData, Form()]):\n    return data\n"
  },
  {
    "path": "docs_src/request_form_models/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, Form\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass FormData(BaseModel):\n    username: str\n    password: str\n    model_config = {\"extra\": \"forbid\"}\n\n\n@app.post(\"/login/\")\nasync def login(data: FormData = Form()):\n    return data\n"
  },
  {
    "path": "docs_src/request_forms/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/request_forms/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Form\n\napp = FastAPI()\n\n\n@app.post(\"/login/\")\nasync def login(username: Annotated[str, Form()], password: Annotated[str, Form()]):\n    return {\"username\": username}\n"
  },
  {
    "path": "docs_src/request_forms/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, Form\n\napp = FastAPI()\n\n\n@app.post(\"/login/\")\nasync def login(username: str = Form(), password: str = Form()):\n    return {\"username\": username}\n"
  },
  {
    "path": "docs_src/request_forms_and_files/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/request_forms_and_files/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, File, Form, UploadFile\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_file(\n    file: Annotated[bytes, File()],\n    fileb: Annotated[UploadFile, File()],\n    token: Annotated[str, Form()],\n):\n    return {\n        \"file_size\": len(file),\n        \"token\": token,\n        \"fileb_content_type\": fileb.content_type,\n    }\n"
  },
  {
    "path": "docs_src/request_forms_and_files/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, File, Form, UploadFile\n\napp = FastAPI()\n\n\n@app.post(\"/files/\")\nasync def create_file(\n    file: bytes = File(), fileb: UploadFile = File(), token: str = Form()\n):\n    return {\n        \"file_size\": len(file),\n        \"token\": token,\n        \"fileb_content_type\": fileb.content_type,\n    }\n"
  },
  {
    "path": "docs_src/response_change_status_code/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/response_change_status_code/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, Response, status\n\napp = FastAPI()\n\ntasks = {\"foo\": \"Listen to the Bar Fighters\"}\n\n\n@app.put(\"/get-or-create-task/{task_id}\", status_code=200)\ndef get_or_create_task(task_id: str, response: Response):\n    if task_id not in tasks:\n        tasks[task_id] = \"This didn't exist before\"\n        response.status_code = status.HTTP_201_CREATED\n    return tasks[task_id]\n"
  },
  {
    "path": "docs_src/response_cookies/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/response_cookies/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\n\napp = FastAPI()\n\n\n@app.post(\"/cookie/\")\ndef create_cookie():\n    content = {\"message\": \"Come to the dark side, we have cookies\"}\n    response = JSONResponse(content=content)\n    response.set_cookie(key=\"fakesession\", value=\"fake-cookie-session-value\")\n    return response\n"
  },
  {
    "path": "docs_src/response_cookies/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, Response\n\napp = FastAPI()\n\n\n@app.post(\"/cookie-and-object/\")\ndef create_cookie(response: Response):\n    response.set_cookie(key=\"fakesession\", value=\"fake-cookie-session-value\")\n    return {\"message\": \"Come to the dark side, we have cookies\"}\n"
  },
  {
    "path": "docs_src/response_directly/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/response_directly/tutorial001_py310.py",
    "content": "from datetime import datetime\n\nfrom fastapi import FastAPI\nfrom fastapi.encoders import jsonable_encoder\nfrom fastapi.responses import JSONResponse\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    title: str\n    timestamp: datetime\n    description: str | None = None\n\n\napp = FastAPI()\n\n\n@app.put(\"/items/{id}\")\ndef update_item(id: str, item: Item):\n    json_compatible_item_data = jsonable_encoder(item)\n    return JSONResponse(content=json_compatible_item_data)\n"
  },
  {
    "path": "docs_src/response_directly/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, Response\n\napp = FastAPI()\n\n\n@app.get(\"/legacy/\")\ndef get_legacy_data():\n    data = \"\"\"<?xml version=\"1.0\"?>\n    <shampoo>\n    <Header>\n        Apply shampoo here.\n    </Header>\n    <Body>\n        You'll have to use soap here.\n    </Body>\n    </shampoo>\n    \"\"\"\n    return Response(content=data, media_type=\"application/xml\")\n"
  },
  {
    "path": "docs_src/response_headers/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/response_headers/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\n\napp = FastAPI()\n\n\n@app.get(\"/headers/\")\ndef get_headers():\n    content = {\"message\": \"Hello World\"}\n    headers = {\"X-Cat-Dog\": \"alone in the world\", \"Content-Language\": \"en-US\"}\n    return JSONResponse(content=content, headers=headers)\n"
  },
  {
    "path": "docs_src/response_headers/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, Response\n\napp = FastAPI()\n\n\n@app.get(\"/headers-and-object/\")\ndef get_headers(response: Response):\n    response.headers[\"X-Cat-Dog\"] = \"alone in the world\"\n    return {\"message\": \"Hello World\"}\n"
  },
  {
    "path": "docs_src/response_model/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/response_model/tutorial001_01_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: list[str] = []\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item) -> Item:\n    return item\n\n\n@app.get(\"/items/\")\nasync def read_items() -> list[Item]:\n    return [\n        Item(name=\"Portal Gun\", price=42.0),\n        Item(name=\"Plumbus\", price=32.0),\n    ]\n"
  },
  {
    "path": "docs_src/response_model/tutorial001_py310.py",
    "content": "from typing import Any\n\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n    tags: list[str] = []\n\n\n@app.post(\"/items/\", response_model=Item)\nasync def create_item(item: Item) -> Any:\n    return item\n\n\n@app.get(\"/items/\", response_model=list[Item])\nasync def read_items() -> Any:\n    return [\n        {\"name\": \"Portal Gun\", \"price\": 42.0},\n        {\"name\": \"Plumbus\", \"price\": 32.0},\n    ]\n"
  },
  {
    "path": "docs_src/response_model/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel, EmailStr\n\napp = FastAPI()\n\n\nclass UserIn(BaseModel):\n    username: str\n    password: str\n    email: EmailStr\n    full_name: str | None = None\n\n\n# Don't do this in production!\n@app.post(\"/user/\")\nasync def create_user(user: UserIn) -> UserIn:\n    return user\n"
  },
  {
    "path": "docs_src/response_model/tutorial003_01_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel, EmailStr\n\napp = FastAPI()\n\n\nclass BaseUser(BaseModel):\n    username: str\n    email: EmailStr\n    full_name: str | None = None\n\n\nclass UserIn(BaseUser):\n    password: str\n\n\n@app.post(\"/user/\")\nasync def create_user(user: UserIn) -> BaseUser:\n    return user\n"
  },
  {
    "path": "docs_src/response_model/tutorial003_02_py310.py",
    "content": "from fastapi import FastAPI, Response\nfrom fastapi.responses import JSONResponse, RedirectResponse\n\napp = FastAPI()\n\n\n@app.get(\"/portal\")\nasync def get_portal(teleport: bool = False) -> Response:\n    if teleport:\n        return RedirectResponse(url=\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\")\n    return JSONResponse(content={\"message\": \"Here's your interdimensional portal.\"})\n"
  },
  {
    "path": "docs_src/response_model/tutorial003_03_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import RedirectResponse\n\napp = FastAPI()\n\n\n@app.get(\"/teleport\")\nasync def get_teleport() -> RedirectResponse:\n    return RedirectResponse(url=\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\")\n"
  },
  {
    "path": "docs_src/response_model/tutorial003_04_py310.py",
    "content": "from fastapi import FastAPI, Response\nfrom fastapi.responses import RedirectResponse\n\napp = FastAPI()\n\n\n@app.get(\"/portal\")\nasync def get_portal(teleport: bool = False) -> Response | dict:\n    if teleport:\n        return RedirectResponse(url=\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\")\n    return {\"message\": \"Here's your interdimensional portal.\"}\n"
  },
  {
    "path": "docs_src/response_model/tutorial003_05_py310.py",
    "content": "from fastapi import FastAPI, Response\nfrom fastapi.responses import RedirectResponse\n\napp = FastAPI()\n\n\n@app.get(\"/portal\", response_model=None)\nasync def get_portal(teleport: bool = False) -> Response | dict:\n    if teleport:\n        return RedirectResponse(url=\"https://www.youtube.com/watch?v=dQw4w9WgXcQ\")\n    return {\"message\": \"Here's your interdimensional portal.\"}\n"
  },
  {
    "path": "docs_src/response_model/tutorial003_py310.py",
    "content": "from typing import Any\n\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel, EmailStr\n\napp = FastAPI()\n\n\nclass UserIn(BaseModel):\n    username: str\n    password: str\n    email: EmailStr\n    full_name: str | None = None\n\n\nclass UserOut(BaseModel):\n    username: str\n    email: EmailStr\n    full_name: str | None = None\n\n\n@app.post(\"/user/\", response_model=UserOut)\nasync def create_user(user: UserIn) -> Any:\n    return user\n"
  },
  {
    "path": "docs_src/response_model/tutorial004_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float = 10.5\n    tags: list[str] = []\n\n\nitems = {\n    \"foo\": {\"name\": \"Foo\", \"price\": 50.2},\n    \"bar\": {\"name\": \"Bar\", \"description\": \"The bartenders\", \"price\": 62, \"tax\": 20.2},\n    \"baz\": {\"name\": \"Baz\", \"description\": None, \"price\": 50.2, \"tax\": 10.5, \"tags\": []},\n}\n\n\n@app.get(\"/items/{item_id}\", response_model=Item, response_model_exclude_unset=True)\nasync def read_item(item_id: str):\n    return items[item_id]\n"
  },
  {
    "path": "docs_src/response_model/tutorial005_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float = 10.5\n\n\nitems = {\n    \"foo\": {\"name\": \"Foo\", \"price\": 50.2},\n    \"bar\": {\"name\": \"Bar\", \"description\": \"The Bar fighters\", \"price\": 62, \"tax\": 20.2},\n    \"baz\": {\n        \"name\": \"Baz\",\n        \"description\": \"There goes my baz\",\n        \"price\": 50.2,\n        \"tax\": 10.5,\n    },\n}\n\n\n@app.get(\n    \"/items/{item_id}/name\",\n    response_model=Item,\n    response_model_include={\"name\", \"description\"},\n)\nasync def read_item_name(item_id: str):\n    return items[item_id]\n\n\n@app.get(\"/items/{item_id}/public\", response_model=Item, response_model_exclude={\"tax\"})\nasync def read_item_public_data(item_id: str):\n    return items[item_id]\n"
  },
  {
    "path": "docs_src/response_model/tutorial006_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float = 10.5\n\n\nitems = {\n    \"foo\": {\"name\": \"Foo\", \"price\": 50.2},\n    \"bar\": {\"name\": \"Bar\", \"description\": \"The Bar fighters\", \"price\": 62, \"tax\": 20.2},\n    \"baz\": {\n        \"name\": \"Baz\",\n        \"description\": \"There goes my baz\",\n        \"price\": 50.2,\n        \"tax\": 10.5,\n    },\n}\n\n\n@app.get(\n    \"/items/{item_id}/name\",\n    response_model=Item,\n    response_model_include=[\"name\", \"description\"],\n)\nasync def read_item_name(item_id: str):\n    return items[item_id]\n\n\n@app.get(\"/items/{item_id}/public\", response_model=Item, response_model_exclude=[\"tax\"])\nasync def read_item_public_data(item_id: str):\n    return items[item_id]\n"
  },
  {
    "path": "docs_src/response_status_code/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/response_status_code/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.post(\"/items/\", status_code=201)\nasync def create_item(name: str):\n    return {\"name\": name}\n"
  },
  {
    "path": "docs_src/response_status_code/tutorial002_py310.py",
    "content": "from fastapi import FastAPI, status\n\napp = FastAPI()\n\n\n@app.post(\"/items/\", status_code=status.HTTP_201_CREATED)\nasync def create_item(name: str):\n    return {\"name\": name}\n"
  },
  {
    "path": "docs_src/schema_extra_example/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/schema_extra_example/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n    model_config = {\n        \"json_schema_extra\": {\n            \"examples\": [\n                {\n                    \"name\": \"Foo\",\n                    \"description\": \"A very nice Item\",\n                    \"price\": 35.4,\n                    \"tax\": 3.2,\n                }\n            ]\n        }\n    }\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/schema_extra_example/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str = Field(examples=[\"Foo\"])\n    description: str | None = Field(default=None, examples=[\"A very nice Item\"])\n    price: float = Field(examples=[35.4])\n    tax: float | None = Field(default=None, examples=[3.2])\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(item_id: int, item: Item):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/schema_extra_example/tutorial003_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    item_id: int,\n    item: Annotated[\n        Item,\n        Body(\n            examples=[\n                {\n                    \"name\": \"Foo\",\n                    \"description\": \"A very nice Item\",\n                    \"price\": 35.4,\n                    \"tax\": 3.2,\n                }\n            ],\n        ),\n    ],\n):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/schema_extra_example/tutorial003_py310.py",
    "content": "from fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    item_id: int,\n    item: Item = Body(\n        examples=[\n            {\n                \"name\": \"Foo\",\n                \"description\": \"A very nice Item\",\n                \"price\": 35.4,\n                \"tax\": 3.2,\n            }\n        ],\n    ),\n):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/schema_extra_example/tutorial004_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    *,\n    item_id: int,\n    item: Annotated[\n        Item,\n        Body(\n            examples=[\n                {\n                    \"name\": \"Foo\",\n                    \"description\": \"A very nice Item\",\n                    \"price\": 35.4,\n                    \"tax\": 3.2,\n                },\n                {\n                    \"name\": \"Bar\",\n                    \"price\": \"35.4\",\n                },\n                {\n                    \"name\": \"Baz\",\n                    \"price\": \"thirty five point four\",\n                },\n            ],\n        ),\n    ],\n):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/schema_extra_example/tutorial004_py310.py",
    "content": "from fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    *,\n    item_id: int,\n    item: Item = Body(\n        examples=[\n            {\n                \"name\": \"Foo\",\n                \"description\": \"A very nice Item\",\n                \"price\": 35.4,\n                \"tax\": 3.2,\n            },\n            {\n                \"name\": \"Bar\",\n                \"price\": \"35.4\",\n            },\n            {\n                \"name\": \"Baz\",\n                \"price\": \"thirty five point four\",\n            },\n        ],\n    ),\n):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/schema_extra_example/tutorial005_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    *,\n    item_id: int,\n    item: Annotated[\n        Item,\n        Body(\n            openapi_examples={\n                \"normal\": {\n                    \"summary\": \"A normal example\",\n                    \"description\": \"A **normal** item works correctly.\",\n                    \"value\": {\n                        \"name\": \"Foo\",\n                        \"description\": \"A very nice Item\",\n                        \"price\": 35.4,\n                        \"tax\": 3.2,\n                    },\n                },\n                \"converted\": {\n                    \"summary\": \"An example with converted data\",\n                    \"description\": \"FastAPI can convert price `strings` to actual `numbers` automatically\",\n                    \"value\": {\n                        \"name\": \"Bar\",\n                        \"price\": \"35.4\",\n                    },\n                },\n                \"invalid\": {\n                    \"summary\": \"Invalid data is rejected with an error\",\n                    \"value\": {\n                        \"name\": \"Baz\",\n                        \"price\": \"thirty five point four\",\n                    },\n                },\n            },\n        ),\n    ],\n):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/schema_extra_example/tutorial005_py310.py",
    "content": "from fastapi import Body, FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float\n    tax: float | None = None\n\n\n@app.put(\"/items/{item_id}\")\nasync def update_item(\n    *,\n    item_id: int,\n    item: Item = Body(\n        openapi_examples={\n            \"normal\": {\n                \"summary\": \"A normal example\",\n                \"description\": \"A **normal** item works correctly.\",\n                \"value\": {\n                    \"name\": \"Foo\",\n                    \"description\": \"A very nice Item\",\n                    \"price\": 35.4,\n                    \"tax\": 3.2,\n                },\n            },\n            \"converted\": {\n                \"summary\": \"An example with converted data\",\n                \"description\": \"FastAPI can convert price `strings` to actual `numbers` automatically\",\n                \"value\": {\n                    \"name\": \"Bar\",\n                    \"price\": \"35.4\",\n                },\n            },\n            \"invalid\": {\n                \"summary\": \"Invalid data is rejected with an error\",\n                \"value\": {\n                    \"name\": \"Baz\",\n                    \"price\": \"thirty five point four\",\n                },\n            },\n        },\n    ),\n):\n    results = {\"item_id\": item_id, \"item\": item}\n    return results\n"
  },
  {
    "path": "docs_src/security/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/security/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\nfrom fastapi.security import OAuth2PasswordBearer\n\napp = FastAPI()\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\n\n@app.get(\"/items/\")\nasync def read_items(token: Annotated[str, Depends(oauth2_scheme)]):\n    return {\"token\": token}\n"
  },
  {
    "path": "docs_src/security/tutorial001_py310.py",
    "content": "from fastapi import Depends, FastAPI\nfrom fastapi.security import OAuth2PasswordBearer\n\napp = FastAPI()\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\n\n@app.get(\"/items/\")\nasync def read_items(token: str = Depends(oauth2_scheme)):\n    return {\"token\": token}\n"
  },
  {
    "path": "docs_src/security/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\nfrom fastapi.security import OAuth2PasswordBearer\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\n\nclass User(BaseModel):\n    username: str\n    email: str | None = None\n    full_name: str | None = None\n    disabled: bool | None = None\n\n\ndef fake_decode_token(token):\n    return User(\n        username=token + \"fakedecoded\", email=\"john@example.com\", full_name=\"John Doe\"\n    )\n\n\nasync def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):\n    user = fake_decode_token(token)\n    return user\n\n\n@app.get(\"/users/me\")\nasync def read_users_me(current_user: Annotated[User, Depends(get_current_user)]):\n    return current_user\n"
  },
  {
    "path": "docs_src/security/tutorial002_py310.py",
    "content": "from fastapi import Depends, FastAPI\nfrom fastapi.security import OAuth2PasswordBearer\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\n\nclass User(BaseModel):\n    username: str\n    email: str | None = None\n    full_name: str | None = None\n    disabled: bool | None = None\n\n\ndef fake_decode_token(token):\n    return User(\n        username=token + \"fakedecoded\", email=\"john@example.com\", full_name=\"John Doe\"\n    )\n\n\nasync def get_current_user(token: str = Depends(oauth2_scheme)):\n    user = fake_decode_token(token)\n    return user\n\n\n@app.get(\"/users/me\")\nasync def read_users_me(current_user: User = Depends(get_current_user)):\n    return current_user\n"
  },
  {
    "path": "docs_src/security/tutorial003_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI, HTTPException, status\nfrom fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm\nfrom pydantic import BaseModel\n\nfake_users_db = {\n    \"johndoe\": {\n        \"username\": \"johndoe\",\n        \"full_name\": \"John Doe\",\n        \"email\": \"johndoe@example.com\",\n        \"hashed_password\": \"fakehashedsecret\",\n        \"disabled\": False,\n    },\n    \"alice\": {\n        \"username\": \"alice\",\n        \"full_name\": \"Alice Wonderson\",\n        \"email\": \"alice@example.com\",\n        \"hashed_password\": \"fakehashedsecret2\",\n        \"disabled\": True,\n    },\n}\n\napp = FastAPI()\n\n\ndef fake_hash_password(password: str):\n    return \"fakehashed\" + password\n\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\n\nclass User(BaseModel):\n    username: str\n    email: str | None = None\n    full_name: str | None = None\n    disabled: bool | None = None\n\n\nclass UserInDB(User):\n    hashed_password: str\n\n\ndef get_user(db, username: str):\n    if username in db:\n        user_dict = db[username]\n        return UserInDB(**user_dict)\n\n\ndef fake_decode_token(token):\n    # This doesn't provide any security at all\n    # Check the next version\n    user = get_user(fake_users_db, token)\n    return user\n\n\nasync def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):\n    user = fake_decode_token(token)\n    if not user:\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Not authenticated\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n    return user\n\n\nasync def get_current_active_user(\n    current_user: Annotated[User, Depends(get_current_user)],\n):\n    if current_user.disabled:\n        raise HTTPException(status_code=400, detail=\"Inactive user\")\n    return current_user\n\n\n@app.post(\"/token\")\nasync def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):\n    user_dict = fake_users_db.get(form_data.username)\n    if not user_dict:\n        raise HTTPException(status_code=400, detail=\"Incorrect username or password\")\n    user = UserInDB(**user_dict)\n    hashed_password = fake_hash_password(form_data.password)\n    if not hashed_password == user.hashed_password:\n        raise HTTPException(status_code=400, detail=\"Incorrect username or password\")\n\n    return {\"access_token\": user.username, \"token_type\": \"bearer\"}\n\n\n@app.get(\"/users/me\")\nasync def read_users_me(\n    current_user: Annotated[User, Depends(get_current_active_user)],\n):\n    return current_user\n"
  },
  {
    "path": "docs_src/security/tutorial003_py310.py",
    "content": "from fastapi import Depends, FastAPI, HTTPException, status\nfrom fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm\nfrom pydantic import BaseModel\n\nfake_users_db = {\n    \"johndoe\": {\n        \"username\": \"johndoe\",\n        \"full_name\": \"John Doe\",\n        \"email\": \"johndoe@example.com\",\n        \"hashed_password\": \"fakehashedsecret\",\n        \"disabled\": False,\n    },\n    \"alice\": {\n        \"username\": \"alice\",\n        \"full_name\": \"Alice Wonderson\",\n        \"email\": \"alice@example.com\",\n        \"hashed_password\": \"fakehashedsecret2\",\n        \"disabled\": True,\n    },\n}\n\napp = FastAPI()\n\n\ndef fake_hash_password(password: str):\n    return \"fakehashed\" + password\n\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\n\nclass User(BaseModel):\n    username: str\n    email: str | None = None\n    full_name: str | None = None\n    disabled: bool | None = None\n\n\nclass UserInDB(User):\n    hashed_password: str\n\n\ndef get_user(db, username: str):\n    if username in db:\n        user_dict = db[username]\n        return UserInDB(**user_dict)\n\n\ndef fake_decode_token(token):\n    # This doesn't provide any security at all\n    # Check the next version\n    user = get_user(fake_users_db, token)\n    return user\n\n\nasync def get_current_user(token: str = Depends(oauth2_scheme)):\n    user = fake_decode_token(token)\n    if not user:\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Not authenticated\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n    return user\n\n\nasync def get_current_active_user(current_user: User = Depends(get_current_user)):\n    if current_user.disabled:\n        raise HTTPException(status_code=400, detail=\"Inactive user\")\n    return current_user\n\n\n@app.post(\"/token\")\nasync def login(form_data: OAuth2PasswordRequestForm = Depends()):\n    user_dict = fake_users_db.get(form_data.username)\n    if not user_dict:\n        raise HTTPException(status_code=400, detail=\"Incorrect username or password\")\n    user = UserInDB(**user_dict)\n    hashed_password = fake_hash_password(form_data.password)\n    if not hashed_password == user.hashed_password:\n        raise HTTPException(status_code=400, detail=\"Incorrect username or password\")\n\n    return {\"access_token\": user.username, \"token_type\": \"bearer\"}\n\n\n@app.get(\"/users/me\")\nasync def read_users_me(current_user: User = Depends(get_current_active_user)):\n    return current_user\n"
  },
  {
    "path": "docs_src/security/tutorial004_an_py310.py",
    "content": "from datetime import datetime, timedelta, timezone\nfrom typing import Annotated\n\nimport jwt\nfrom fastapi import Depends, FastAPI, HTTPException, status\nfrom fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm\nfrom jwt.exceptions import InvalidTokenError\nfrom pwdlib import PasswordHash\nfrom pydantic import BaseModel\n\n# to get a string like this run:\n# openssl rand -hex 32\nSECRET_KEY = \"09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\"\nALGORITHM = \"HS256\"\nACCESS_TOKEN_EXPIRE_MINUTES = 30\n\n\nfake_users_db = {\n    \"johndoe\": {\n        \"username\": \"johndoe\",\n        \"full_name\": \"John Doe\",\n        \"email\": \"johndoe@example.com\",\n        \"hashed_password\": \"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\",\n        \"disabled\": False,\n    }\n}\n\n\nclass Token(BaseModel):\n    access_token: str\n    token_type: str\n\n\nclass TokenData(BaseModel):\n    username: str | None = None\n\n\nclass User(BaseModel):\n    username: str\n    email: str | None = None\n    full_name: str | None = None\n    disabled: bool | None = None\n\n\nclass UserInDB(User):\n    hashed_password: str\n\n\npassword_hash = PasswordHash.recommended()\n\nDUMMY_HASH = password_hash.hash(\"dummypassword\")\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\napp = FastAPI()\n\n\ndef verify_password(plain_password, hashed_password):\n    return password_hash.verify(plain_password, hashed_password)\n\n\ndef get_password_hash(password):\n    return password_hash.hash(password)\n\n\ndef get_user(db, username: str):\n    if username in db:\n        user_dict = db[username]\n        return UserInDB(**user_dict)\n\n\ndef authenticate_user(fake_db, username: str, password: str):\n    user = get_user(fake_db, username)\n    if not user:\n        verify_password(password, DUMMY_HASH)\n        return False\n    if not verify_password(password, user.hashed_password):\n        return False\n    return user\n\n\ndef create_access_token(data: dict, expires_delta: timedelta | None = None):\n    to_encode = data.copy()\n    if expires_delta:\n        expire = datetime.now(timezone.utc) + expires_delta\n    else:\n        expire = datetime.now(timezone.utc) + timedelta(minutes=15)\n    to_encode.update({\"exp\": expire})\n    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)\n    return encoded_jwt\n\n\nasync def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):\n    credentials_exception = HTTPException(\n        status_code=status.HTTP_401_UNAUTHORIZED,\n        detail=\"Could not validate credentials\",\n        headers={\"WWW-Authenticate\": \"Bearer\"},\n    )\n    try:\n        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])\n        username = payload.get(\"sub\")\n        if username is None:\n            raise credentials_exception\n        token_data = TokenData(username=username)\n    except InvalidTokenError:\n        raise credentials_exception\n    user = get_user(fake_users_db, username=token_data.username)\n    if user is None:\n        raise credentials_exception\n    return user\n\n\nasync def get_current_active_user(\n    current_user: Annotated[User, Depends(get_current_user)],\n):\n    if current_user.disabled:\n        raise HTTPException(status_code=400, detail=\"Inactive user\")\n    return current_user\n\n\n@app.post(\"/token\")\nasync def login_for_access_token(\n    form_data: Annotated[OAuth2PasswordRequestForm, Depends()],\n) -> Token:\n    user = authenticate_user(fake_users_db, form_data.username, form_data.password)\n    if not user:\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Incorrect username or password\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)\n    access_token = create_access_token(\n        data={\"sub\": user.username}, expires_delta=access_token_expires\n    )\n    return Token(access_token=access_token, token_type=\"bearer\")\n\n\n@app.get(\"/users/me/\")\nasync def read_users_me(\n    current_user: Annotated[User, Depends(get_current_active_user)],\n) -> User:\n    return current_user\n\n\n@app.get(\"/users/me/items/\")\nasync def read_own_items(\n    current_user: Annotated[User, Depends(get_current_active_user)],\n):\n    return [{\"item_id\": \"Foo\", \"owner\": current_user.username}]\n"
  },
  {
    "path": "docs_src/security/tutorial004_py310.py",
    "content": "from datetime import datetime, timedelta, timezone\n\nimport jwt\nfrom fastapi import Depends, FastAPI, HTTPException, status\nfrom fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm\nfrom jwt.exceptions import InvalidTokenError\nfrom pwdlib import PasswordHash\nfrom pydantic import BaseModel\n\n# to get a string like this run:\n# openssl rand -hex 32\nSECRET_KEY = \"09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\"\nALGORITHM = \"HS256\"\nACCESS_TOKEN_EXPIRE_MINUTES = 30\n\n\nfake_users_db = {\n    \"johndoe\": {\n        \"username\": \"johndoe\",\n        \"full_name\": \"John Doe\",\n        \"email\": \"johndoe@example.com\",\n        \"hashed_password\": \"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\",\n        \"disabled\": False,\n    }\n}\n\n\nclass Token(BaseModel):\n    access_token: str\n    token_type: str\n\n\nclass TokenData(BaseModel):\n    username: str | None = None\n\n\nclass User(BaseModel):\n    username: str\n    email: str | None = None\n    full_name: str | None = None\n    disabled: bool | None = None\n\n\nclass UserInDB(User):\n    hashed_password: str\n\n\npassword_hash = PasswordHash.recommended()\n\nDUMMY_HASH = password_hash.hash(\"dummypassword\")\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\napp = FastAPI()\n\n\ndef verify_password(plain_password, hashed_password):\n    return password_hash.verify(plain_password, hashed_password)\n\n\ndef get_password_hash(password):\n    return password_hash.hash(password)\n\n\ndef get_user(db, username: str):\n    if username in db:\n        user_dict = db[username]\n        return UserInDB(**user_dict)\n\n\ndef authenticate_user(fake_db, username: str, password: str):\n    user = get_user(fake_db, username)\n    if not user:\n        verify_password(password, DUMMY_HASH)\n        return False\n    if not verify_password(password, user.hashed_password):\n        return False\n    return user\n\n\ndef create_access_token(data: dict, expires_delta: timedelta | None = None):\n    to_encode = data.copy()\n    if expires_delta:\n        expire = datetime.now(timezone.utc) + expires_delta\n    else:\n        expire = datetime.now(timezone.utc) + timedelta(minutes=15)\n    to_encode.update({\"exp\": expire})\n    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)\n    return encoded_jwt\n\n\nasync def get_current_user(token: str = Depends(oauth2_scheme)):\n    credentials_exception = HTTPException(\n        status_code=status.HTTP_401_UNAUTHORIZED,\n        detail=\"Could not validate credentials\",\n        headers={\"WWW-Authenticate\": \"Bearer\"},\n    )\n    try:\n        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])\n        username = payload.get(\"sub\")\n        if username is None:\n            raise credentials_exception\n        token_data = TokenData(username=username)\n    except InvalidTokenError:\n        raise credentials_exception\n    user = get_user(fake_users_db, username=token_data.username)\n    if user is None:\n        raise credentials_exception\n    return user\n\n\nasync def get_current_active_user(current_user: User = Depends(get_current_user)):\n    if current_user.disabled:\n        raise HTTPException(status_code=400, detail=\"Inactive user\")\n    return current_user\n\n\n@app.post(\"/token\")\nasync def login_for_access_token(\n    form_data: OAuth2PasswordRequestForm = Depends(),\n) -> Token:\n    user = authenticate_user(fake_users_db, form_data.username, form_data.password)\n    if not user:\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Incorrect username or password\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)\n    access_token = create_access_token(\n        data={\"sub\": user.username}, expires_delta=access_token_expires\n    )\n    return Token(access_token=access_token, token_type=\"bearer\")\n\n\n@app.get(\"/users/me/\")\nasync def read_users_me(current_user: User = Depends(get_current_active_user)) -> User:\n    return current_user\n\n\n@app.get(\"/users/me/items/\")\nasync def read_own_items(current_user: User = Depends(get_current_active_user)):\n    return [{\"item_id\": \"Foo\", \"owner\": current_user.username}]\n"
  },
  {
    "path": "docs_src/security/tutorial005_an_py310.py",
    "content": "from datetime import datetime, timedelta, timezone\nfrom typing import Annotated\n\nimport jwt\nfrom fastapi import Depends, FastAPI, HTTPException, Security, status\nfrom fastapi.security import (\n    OAuth2PasswordBearer,\n    OAuth2PasswordRequestForm,\n    SecurityScopes,\n)\nfrom jwt.exceptions import InvalidTokenError\nfrom pwdlib import PasswordHash\nfrom pydantic import BaseModel, ValidationError\n\n# to get a string like this run:\n# openssl rand -hex 32\nSECRET_KEY = \"09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\"\nALGORITHM = \"HS256\"\nACCESS_TOKEN_EXPIRE_MINUTES = 30\n\n\nfake_users_db = {\n    \"johndoe\": {\n        \"username\": \"johndoe\",\n        \"full_name\": \"John Doe\",\n        \"email\": \"johndoe@example.com\",\n        \"hashed_password\": \"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\",\n        \"disabled\": False,\n    },\n    \"alice\": {\n        \"username\": \"alice\",\n        \"full_name\": \"Alice Chains\",\n        \"email\": \"alicechains@example.com\",\n        \"hashed_password\": \"$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE\",\n        \"disabled\": True,\n    },\n}\n\n\nclass Token(BaseModel):\n    access_token: str\n    token_type: str\n\n\nclass TokenData(BaseModel):\n    username: str | None = None\n    scopes: list[str] = []\n\n\nclass User(BaseModel):\n    username: str\n    email: str | None = None\n    full_name: str | None = None\n    disabled: bool | None = None\n\n\nclass UserInDB(User):\n    hashed_password: str\n\n\npassword_hash = PasswordHash.recommended()\n\nDUMMY_HASH = password_hash.hash(\"dummypassword\")\n\noauth2_scheme = OAuth2PasswordBearer(\n    tokenUrl=\"token\",\n    scopes={\"me\": \"Read information about the current user.\", \"items\": \"Read items.\"},\n)\n\napp = FastAPI()\n\n\ndef verify_password(plain_password, hashed_password):\n    return password_hash.verify(plain_password, hashed_password)\n\n\ndef get_password_hash(password):\n    return password_hash.hash(password)\n\n\ndef get_user(db, username: str):\n    if username in db:\n        user_dict = db[username]\n        return UserInDB(**user_dict)\n\n\ndef authenticate_user(fake_db, username: str, password: str):\n    user = get_user(fake_db, username)\n    if not user:\n        verify_password(password, DUMMY_HASH)\n        return False\n    if not verify_password(password, user.hashed_password):\n        return False\n    return user\n\n\ndef create_access_token(data: dict, expires_delta: timedelta | None = None):\n    to_encode = data.copy()\n    if expires_delta:\n        expire = datetime.now(timezone.utc) + expires_delta\n    else:\n        expire = datetime.now(timezone.utc) + timedelta(minutes=15)\n    to_encode.update({\"exp\": expire})\n    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)\n    return encoded_jwt\n\n\nasync def get_current_user(\n    security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)]\n):\n    if security_scopes.scopes:\n        authenticate_value = f'Bearer scope=\"{security_scopes.scope_str}\"'\n    else:\n        authenticate_value = \"Bearer\"\n    credentials_exception = HTTPException(\n        status_code=status.HTTP_401_UNAUTHORIZED,\n        detail=\"Could not validate credentials\",\n        headers={\"WWW-Authenticate\": authenticate_value},\n    )\n    try:\n        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])\n        username = payload.get(\"sub\")\n        if username is None:\n            raise credentials_exception\n        scope: str = payload.get(\"scope\", \"\")\n        token_scopes = scope.split(\" \")\n        token_data = TokenData(scopes=token_scopes, username=username)\n    except (InvalidTokenError, ValidationError):\n        raise credentials_exception\n    user = get_user(fake_users_db, username=token_data.username)\n    if user is None:\n        raise credentials_exception\n    for scope in security_scopes.scopes:\n        if scope not in token_data.scopes:\n            raise HTTPException(\n                status_code=status.HTTP_401_UNAUTHORIZED,\n                detail=\"Not enough permissions\",\n                headers={\"WWW-Authenticate\": authenticate_value},\n            )\n    return user\n\n\nasync def get_current_active_user(\n    current_user: Annotated[User, Security(get_current_user, scopes=[\"me\"])],\n):\n    if current_user.disabled:\n        raise HTTPException(status_code=400, detail=\"Inactive user\")\n    return current_user\n\n\n@app.post(\"/token\")\nasync def login_for_access_token(\n    form_data: Annotated[OAuth2PasswordRequestForm, Depends()],\n) -> Token:\n    user = authenticate_user(fake_users_db, form_data.username, form_data.password)\n    if not user:\n        raise HTTPException(status_code=400, detail=\"Incorrect username or password\")\n    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)\n    access_token = create_access_token(\n        data={\"sub\": user.username, \"scope\": \" \".join(form_data.scopes)},\n        expires_delta=access_token_expires,\n    )\n    return Token(access_token=access_token, token_type=\"bearer\")\n\n\n@app.get(\"/users/me/\")\nasync def read_users_me(\n    current_user: Annotated[User, Depends(get_current_active_user)],\n) -> User:\n    return current_user\n\n\n@app.get(\"/users/me/items/\")\nasync def read_own_items(\n    current_user: Annotated[User, Security(get_current_active_user, scopes=[\"items\"])],\n):\n    return [{\"item_id\": \"Foo\", \"owner\": current_user.username}]\n\n\n@app.get(\"/status/\")\nasync def read_system_status(current_user: Annotated[User, Depends(get_current_user)]):\n    return {\"status\": \"ok\"}\n"
  },
  {
    "path": "docs_src/security/tutorial005_py310.py",
    "content": "from datetime import datetime, timedelta, timezone\n\nimport jwt\nfrom fastapi import Depends, FastAPI, HTTPException, Security, status\nfrom fastapi.security import (\n    OAuth2PasswordBearer,\n    OAuth2PasswordRequestForm,\n    SecurityScopes,\n)\nfrom jwt.exceptions import InvalidTokenError\nfrom pwdlib import PasswordHash\nfrom pydantic import BaseModel, ValidationError\n\n# to get a string like this run:\n# openssl rand -hex 32\nSECRET_KEY = \"09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7\"\nALGORITHM = \"HS256\"\nACCESS_TOKEN_EXPIRE_MINUTES = 30\n\n\nfake_users_db = {\n    \"johndoe\": {\n        \"username\": \"johndoe\",\n        \"full_name\": \"John Doe\",\n        \"email\": \"johndoe@example.com\",\n        \"hashed_password\": \"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc\",\n        \"disabled\": False,\n    },\n    \"alice\": {\n        \"username\": \"alice\",\n        \"full_name\": \"Alice Chains\",\n        \"email\": \"alicechains@example.com\",\n        \"hashed_password\": \"$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE\",\n        \"disabled\": True,\n    },\n}\n\n\nclass Token(BaseModel):\n    access_token: str\n    token_type: str\n\n\nclass TokenData(BaseModel):\n    username: str | None = None\n    scopes: list[str] = []\n\n\nclass User(BaseModel):\n    username: str\n    email: str | None = None\n    full_name: str | None = None\n    disabled: bool | None = None\n\n\nclass UserInDB(User):\n    hashed_password: str\n\n\npassword_hash = PasswordHash.recommended()\n\nDUMMY_HASH = password_hash.hash(\"dummypassword\")\n\noauth2_scheme = OAuth2PasswordBearer(\n    tokenUrl=\"token\",\n    scopes={\"me\": \"Read information about the current user.\", \"items\": \"Read items.\"},\n)\n\napp = FastAPI()\n\n\ndef verify_password(plain_password, hashed_password):\n    return password_hash.verify(plain_password, hashed_password)\n\n\ndef get_password_hash(password):\n    return password_hash.hash(password)\n\n\ndef get_user(db, username: str):\n    if username in db:\n        user_dict = db[username]\n        return UserInDB(**user_dict)\n\n\ndef authenticate_user(fake_db, username: str, password: str):\n    user = get_user(fake_db, username)\n    if not user:\n        verify_password(password, DUMMY_HASH)\n        return False\n    if not verify_password(password, user.hashed_password):\n        return False\n    return user\n\n\ndef create_access_token(data: dict, expires_delta: timedelta | None = None):\n    to_encode = data.copy()\n    if expires_delta:\n        expire = datetime.now(timezone.utc) + expires_delta\n    else:\n        expire = datetime.now(timezone.utc) + timedelta(minutes=15)\n    to_encode.update({\"exp\": expire})\n    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)\n    return encoded_jwt\n\n\nasync def get_current_user(\n    security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme)\n):\n    if security_scopes.scopes:\n        authenticate_value = f'Bearer scope=\"{security_scopes.scope_str}\"'\n    else:\n        authenticate_value = \"Bearer\"\n    credentials_exception = HTTPException(\n        status_code=status.HTTP_401_UNAUTHORIZED,\n        detail=\"Could not validate credentials\",\n        headers={\"WWW-Authenticate\": authenticate_value},\n    )\n    try:\n        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])\n        username: str = payload.get(\"sub\")\n        if username is None:\n            raise credentials_exception\n        scope: str = payload.get(\"scope\", \"\")\n        token_scopes = scope.split(\" \")\n        token_data = TokenData(scopes=token_scopes, username=username)\n    except (InvalidTokenError, ValidationError):\n        raise credentials_exception\n    user = get_user(fake_users_db, username=token_data.username)\n    if user is None:\n        raise credentials_exception\n    for scope in security_scopes.scopes:\n        if scope not in token_data.scopes:\n            raise HTTPException(\n                status_code=status.HTTP_401_UNAUTHORIZED,\n                detail=\"Not enough permissions\",\n                headers={\"WWW-Authenticate\": authenticate_value},\n            )\n    return user\n\n\nasync def get_current_active_user(\n    current_user: User = Security(get_current_user, scopes=[\"me\"]),\n):\n    if current_user.disabled:\n        raise HTTPException(status_code=400, detail=\"Inactive user\")\n    return current_user\n\n\n@app.post(\"/token\")\nasync def login_for_access_token(\n    form_data: OAuth2PasswordRequestForm = Depends(),\n) -> Token:\n    user = authenticate_user(fake_users_db, form_data.username, form_data.password)\n    if not user:\n        raise HTTPException(status_code=400, detail=\"Incorrect username or password\")\n    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)\n    access_token = create_access_token(\n        data={\"sub\": user.username, \"scope\": \" \".join(form_data.scopes)},\n        expires_delta=access_token_expires,\n    )\n    return Token(access_token=access_token, token_type=\"bearer\")\n\n\n@app.get(\"/users/me/\")\nasync def read_users_me(current_user: User = Depends(get_current_active_user)) -> User:\n    return current_user\n\n\n@app.get(\"/users/me/items/\")\nasync def read_own_items(\n    current_user: User = Security(get_current_active_user, scopes=[\"items\"]),\n):\n    return [{\"item_id\": \"Foo\", \"owner\": current_user.username}]\n\n\n@app.get(\"/status/\")\nasync def read_system_status(current_user: User = Depends(get_current_user)):\n    return {\"status\": \"ok\"}\n"
  },
  {
    "path": "docs_src/security/tutorial006_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\nfrom fastapi.security import HTTPBasic, HTTPBasicCredentials\n\napp = FastAPI()\n\nsecurity = HTTPBasic()\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]):\n    return {\"username\": credentials.username, \"password\": credentials.password}\n"
  },
  {
    "path": "docs_src/security/tutorial006_py310.py",
    "content": "from fastapi import Depends, FastAPI\nfrom fastapi.security import HTTPBasic, HTTPBasicCredentials\n\napp = FastAPI()\n\nsecurity = HTTPBasic()\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: HTTPBasicCredentials = Depends(security)):\n    return {\"username\": credentials.username, \"password\": credentials.password}\n"
  },
  {
    "path": "docs_src/security/tutorial007_an_py310.py",
    "content": "import secrets\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI, HTTPException, status\nfrom fastapi.security import HTTPBasic, HTTPBasicCredentials\n\napp = FastAPI()\n\nsecurity = HTTPBasic()\n\n\ndef get_current_username(\n    credentials: Annotated[HTTPBasicCredentials, Depends(security)],\n):\n    current_username_bytes = credentials.username.encode(\"utf8\")\n    correct_username_bytes = b\"stanleyjobson\"\n    is_correct_username = secrets.compare_digest(\n        current_username_bytes, correct_username_bytes\n    )\n    current_password_bytes = credentials.password.encode(\"utf8\")\n    correct_password_bytes = b\"swordfish\"\n    is_correct_password = secrets.compare_digest(\n        current_password_bytes, correct_password_bytes\n    )\n    if not (is_correct_username and is_correct_password):\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Incorrect username or password\",\n            headers={\"WWW-Authenticate\": \"Basic\"},\n        )\n    return credentials.username\n\n\n@app.get(\"/users/me\")\ndef read_current_user(username: Annotated[str, Depends(get_current_username)]):\n    return {\"username\": username}\n"
  },
  {
    "path": "docs_src/security/tutorial007_py310.py",
    "content": "import secrets\n\nfrom fastapi import Depends, FastAPI, HTTPException, status\nfrom fastapi.security import HTTPBasic, HTTPBasicCredentials\n\napp = FastAPI()\n\nsecurity = HTTPBasic()\n\n\ndef get_current_username(credentials: HTTPBasicCredentials = Depends(security)):\n    current_username_bytes = credentials.username.encode(\"utf8\")\n    correct_username_bytes = b\"stanleyjobson\"\n    is_correct_username = secrets.compare_digest(\n        current_username_bytes, correct_username_bytes\n    )\n    current_password_bytes = credentials.password.encode(\"utf8\")\n    correct_password_bytes = b\"swordfish\"\n    is_correct_password = secrets.compare_digest(\n        current_password_bytes, correct_password_bytes\n    )\n    if not (is_correct_username and is_correct_password):\n        raise HTTPException(\n            status_code=status.HTTP_401_UNAUTHORIZED,\n            detail=\"Incorrect username or password\",\n            headers={\"WWW-Authenticate\": \"Basic\"},\n        )\n    return credentials.username\n\n\n@app.get(\"/users/me\")\ndef read_current_user(username: str = Depends(get_current_username)):\n    return {\"username\": username}\n"
  },
  {
    "path": "docs_src/separate_openapi_schemas/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/separate_openapi_schemas/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n\n\napp = FastAPI()\n\n\n@app.post(\"/items/\")\ndef create_item(item: Item):\n    return item\n\n\n@app.get(\"/items/\")\ndef read_items() -> list[Item]:\n    return [\n        Item(\n            name=\"Portal Gun\",\n            description=\"Device to travel through the multi-rick-verse\",\n        ),\n        Item(name=\"Plumbus\"),\n    ]\n"
  },
  {
    "path": "docs_src/separate_openapi_schemas/tutorial002_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n\n\napp = FastAPI(separate_input_output_schemas=False)\n\n\n@app.post(\"/items/\")\ndef create_item(item: Item):\n    return item\n\n\n@app.get(\"/items/\")\ndef read_items() -> list[Item]:\n    return [\n        Item(\n            name=\"Portal Gun\",\n            description=\"Device to travel through the multi-rick-verse\",\n        ),\n        Item(name=\"Plumbus\"),\n    ]\n"
  },
  {
    "path": "docs_src/server_sent_events/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/server_sent_events/tutorial001_py310.py",
    "content": "from collections.abc import AsyncIterable, Iterable\n\nfrom fastapi import FastAPI\nfrom fastapi.sse import EventSourceResponse\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None\n\n\nitems = [\n    Item(name=\"Plumbus\", description=\"A multi-purpose household device.\"),\n    Item(name=\"Portal Gun\", description=\"A portal opening device.\"),\n    Item(name=\"Meeseeks Box\", description=\"A box that summons a Meeseeks.\"),\n]\n\n\n@app.get(\"/items/stream\", response_class=EventSourceResponse)\nasync def sse_items() -> AsyncIterable[Item]:\n    for item in items:\n        yield item\n\n\n@app.get(\"/items/stream-no-async\", response_class=EventSourceResponse)\ndef sse_items_no_async() -> Iterable[Item]:\n    for item in items:\n        yield item\n\n\n@app.get(\"/items/stream-no-annotation\", response_class=EventSourceResponse)\nasync def sse_items_no_annotation():\n    for item in items:\n        yield item\n\n\n@app.get(\"/items/stream-no-async-no-annotation\", response_class=EventSourceResponse)\ndef sse_items_no_async_no_annotation():\n    for item in items:\n        yield item\n"
  },
  {
    "path": "docs_src/server_sent_events/tutorial002_py310.py",
    "content": "from collections.abc import AsyncIterable\n\nfrom fastapi import FastAPI\nfrom fastapi.sse import EventSourceResponse, ServerSentEvent\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\nitems = [\n    Item(name=\"Plumbus\", price=32.99),\n    Item(name=\"Portal Gun\", price=999.99),\n    Item(name=\"Meeseeks Box\", price=49.99),\n]\n\n\n@app.get(\"/items/stream\", response_class=EventSourceResponse)\nasync def stream_items() -> AsyncIterable[ServerSentEvent]:\n    yield ServerSentEvent(comment=\"stream of item updates\")\n    for i, item in enumerate(items):\n        yield ServerSentEvent(data=item, event=\"item_update\", id=str(i + 1), retry=5000)\n"
  },
  {
    "path": "docs_src/server_sent_events/tutorial003_py310.py",
    "content": "from collections.abc import AsyncIterable\n\nfrom fastapi import FastAPI\nfrom fastapi.sse import EventSourceResponse, ServerSentEvent\n\napp = FastAPI()\n\n\n@app.get(\"/logs/stream\", response_class=EventSourceResponse)\nasync def stream_logs() -> AsyncIterable[ServerSentEvent]:\n    logs = [\n        \"2025-01-01 INFO  Application started\",\n        \"2025-01-01 DEBUG Connected to database\",\n        \"2025-01-01 WARN  High memory usage detected\",\n    ]\n    for log_line in logs:\n        yield ServerSentEvent(raw_data=log_line)\n"
  },
  {
    "path": "docs_src/server_sent_events/tutorial004_py310.py",
    "content": "from collections.abc import AsyncIterable\nfrom typing import Annotated\n\nfrom fastapi import FastAPI, Header\nfrom fastapi.sse import EventSourceResponse, ServerSentEvent\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\nitems = [\n    Item(name=\"Plumbus\", price=32.99),\n    Item(name=\"Portal Gun\", price=999.99),\n    Item(name=\"Meeseeks Box\", price=49.99),\n]\n\n\n@app.get(\"/items/stream\", response_class=EventSourceResponse)\nasync def stream_items(\n    last_event_id: Annotated[int | None, Header()] = None,\n) -> AsyncIterable[ServerSentEvent]:\n    start = last_event_id + 1 if last_event_id is not None else 0\n    for i, item in enumerate(items):\n        if i < start:\n            continue\n        yield ServerSentEvent(data=item, id=str(i))\n"
  },
  {
    "path": "docs_src/server_sent_events/tutorial005_py310.py",
    "content": "from collections.abc import AsyncIterable\n\nfrom fastapi import FastAPI\nfrom fastapi.sse import EventSourceResponse, ServerSentEvent\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Prompt(BaseModel):\n    text: str\n\n\n@app.post(\"/chat/stream\", response_class=EventSourceResponse)\nasync def stream_chat(prompt: Prompt) -> AsyncIterable[ServerSentEvent]:\n    words = prompt.text.split()\n    for word in words:\n        yield ServerSentEvent(data=word, event=\"token\")\n    yield ServerSentEvent(raw_data=\"[DONE]\", event=\"done\")\n"
  },
  {
    "path": "docs_src/settings/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/settings/app01_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/settings/app01_py310/config.py",
    "content": "from pydantic_settings import BaseSettings\n\n\nclass Settings(BaseSettings):\n    app_name: str = \"Awesome API\"\n    admin_email: str\n    items_per_user: int = 50\n\n\nsettings = Settings()\n"
  },
  {
    "path": "docs_src/settings/app01_py310/main.py",
    "content": "from fastapi import FastAPI\n\nfrom .config import settings\n\napp = FastAPI()\n\n\n@app.get(\"/info\")\nasync def info():\n    return {\n        \"app_name\": settings.app_name,\n        \"admin_email\": settings.admin_email,\n        \"items_per_user\": settings.items_per_user,\n    }\n"
  },
  {
    "path": "docs_src/settings/app02_an_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/settings/app02_an_py310/config.py",
    "content": "from pydantic_settings import BaseSettings\n\n\nclass Settings(BaseSettings):\n    app_name: str = \"Awesome API\"\n    admin_email: str\n    items_per_user: int = 50\n"
  },
  {
    "path": "docs_src/settings/app02_an_py310/main.py",
    "content": "from functools import lru_cache\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\nfrom .config import Settings\n\napp = FastAPI()\n\n\n@lru_cache\ndef get_settings():\n    return Settings()\n\n\n@app.get(\"/info\")\nasync def info(settings: Annotated[Settings, Depends(get_settings)]):\n    return {\n        \"app_name\": settings.app_name,\n        \"admin_email\": settings.admin_email,\n        \"items_per_user\": settings.items_per_user,\n    }\n"
  },
  {
    "path": "docs_src/settings/app02_an_py310/test_main.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom .config import Settings\nfrom .main import app, get_settings\n\nclient = TestClient(app)\n\n\ndef get_settings_override():\n    return Settings(admin_email=\"testing_admin@example.com\")\n\n\napp.dependency_overrides[get_settings] = get_settings_override\n\n\ndef test_app():\n    response = client.get(\"/info\")\n    data = response.json()\n    assert data == {\n        \"app_name\": \"Awesome API\",\n        \"admin_email\": \"testing_admin@example.com\",\n        \"items_per_user\": 50,\n    }\n"
  },
  {
    "path": "docs_src/settings/app02_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/settings/app02_py310/config.py",
    "content": "from pydantic_settings import BaseSettings\n\n\nclass Settings(BaseSettings):\n    app_name: str = \"Awesome API\"\n    admin_email: str\n    items_per_user: int = 50\n"
  },
  {
    "path": "docs_src/settings/app02_py310/main.py",
    "content": "from functools import lru_cache\n\nfrom fastapi import Depends, FastAPI\n\nfrom .config import Settings\n\napp = FastAPI()\n\n\n@lru_cache\ndef get_settings():\n    return Settings()\n\n\n@app.get(\"/info\")\nasync def info(settings: Settings = Depends(get_settings)):\n    return {\n        \"app_name\": settings.app_name,\n        \"admin_email\": settings.admin_email,\n        \"items_per_user\": settings.items_per_user,\n    }\n"
  },
  {
    "path": "docs_src/settings/app02_py310/test_main.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom .config import Settings\nfrom .main import app, get_settings\n\nclient = TestClient(app)\n\n\ndef get_settings_override():\n    return Settings(admin_email=\"testing_admin@example.com\")\n\n\napp.dependency_overrides[get_settings] = get_settings_override\n\n\ndef test_app():\n    response = client.get(\"/info\")\n    data = response.json()\n    assert data == {\n        \"app_name\": \"Awesome API\",\n        \"admin_email\": \"testing_admin@example.com\",\n        \"items_per_user\": 50,\n    }\n"
  },
  {
    "path": "docs_src/settings/app03_an_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/settings/app03_an_py310/config.py",
    "content": "from pydantic_settings import BaseSettings, SettingsConfigDict\n\n\nclass Settings(BaseSettings):\n    app_name: str = \"Awesome API\"\n    admin_email: str\n    items_per_user: int = 50\n\n    model_config = SettingsConfigDict(env_file=\".env\")\n"
  },
  {
    "path": "docs_src/settings/app03_an_py310/main.py",
    "content": "from functools import lru_cache\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\nfrom . import config\n\napp = FastAPI()\n\n\n@lru_cache\ndef get_settings():\n    return config.Settings()\n\n\n@app.get(\"/info\")\nasync def info(settings: Annotated[config.Settings, Depends(get_settings)]):\n    return {\n        \"app_name\": settings.app_name,\n        \"admin_email\": settings.admin_email,\n        \"items_per_user\": settings.items_per_user,\n    }\n"
  },
  {
    "path": "docs_src/settings/app03_py310/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/settings/app03_py310/config.py",
    "content": "from pydantic_settings import BaseSettings, SettingsConfigDict\n\n\nclass Settings(BaseSettings):\n    app_name: str = \"Awesome API\"\n    admin_email: str\n    items_per_user: int = 50\n\n    model_config = SettingsConfigDict(env_file=\".env\")\n"
  },
  {
    "path": "docs_src/settings/app03_py310/main.py",
    "content": "from functools import lru_cache\n\nfrom fastapi import Depends, FastAPI\n\nfrom . import config\n\napp = FastAPI()\n\n\n@lru_cache\ndef get_settings():\n    return config.Settings()\n\n\n@app.get(\"/info\")\nasync def info(settings: config.Settings = Depends(get_settings)):\n    return {\n        \"app_name\": settings.app_name,\n        \"admin_email\": settings.admin_email,\n        \"items_per_user\": settings.items_per_user,\n    }\n"
  },
  {
    "path": "docs_src/settings/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic_settings import BaseSettings\n\n\nclass Settings(BaseSettings):\n    app_name: str = \"Awesome API\"\n    admin_email: str\n    items_per_user: int = 50\n\n\nsettings = Settings()\napp = FastAPI()\n\n\n@app.get(\"/info\")\nasync def info():\n    return {\n        \"app_name\": settings.app_name,\n        \"admin_email\": settings.admin_email,\n        \"items_per_user\": settings.items_per_user,\n    }\n"
  },
  {
    "path": "docs_src/sql_databases/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/sql_databases/tutorial001_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    age: int | None = Field(default=None, index=True)\n    secret_name: str\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\nSessionDep = Annotated[Session, Depends(get_session)]\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\")\ndef create_hero(hero: Hero, session: SessionDep) -> Hero:\n    session.add(hero)\n    session.commit()\n    session.refresh(hero)\n    return hero\n\n\n@app.get(\"/heroes/\")\ndef read_heroes(\n    session: SessionDep,\n    offset: int = 0,\n    limit: Annotated[int, Query(le=100)] = 100,\n) -> list[Hero]:\n    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n    return heroes\n\n\n@app.get(\"/heroes/{hero_id}\")\ndef read_hero(hero_id: int, session: SessionDep) -> Hero:\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    return hero\n\n\n@app.delete(\"/heroes/{hero_id}\")\ndef delete_hero(hero_id: int, session: SessionDep):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    session.delete(hero)\n    session.commit()\n    return {\"ok\": True}\n"
  },
  {
    "path": "docs_src/sql_databases/tutorial001_py310.py",
    "content": "from fastapi import Depends, FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass Hero(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str = Field(index=True)\n    age: int | None = Field(default=None, index=True)\n    secret_name: str\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\")\ndef create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero:\n    session.add(hero)\n    session.commit()\n    session.refresh(hero)\n    return hero\n\n\n@app.get(\"/heroes/\")\ndef read_heroes(\n    session: Session = Depends(get_session),\n    offset: int = 0,\n    limit: int = Query(default=100, le=100),\n) -> list[Hero]:\n    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n    return heroes\n\n\n@app.get(\"/heroes/{hero_id}\")\ndef read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero:\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    return hero\n\n\n@app.delete(\"/heroes/{hero_id}\")\ndef delete_hero(hero_id: int, session: Session = Depends(get_session)):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    session.delete(hero)\n    session.commit()\n    return {\"ok\": True}\n"
  },
  {
    "path": "docs_src/sql_databases/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    age: int | None = Field(default=None, index=True)\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    secret_name: str\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nclass HeroCreate(HeroBase):\n    secret_name: str\n\n\nclass HeroUpdate(HeroBase):\n    name: str | None = None\n    age: int | None = None\n    secret_name: str | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\nSessionDep = Annotated[Session, Depends(get_session)]\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(hero: HeroCreate, session: SessionDep):\n    db_hero = Hero.model_validate(hero)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(\n    session: SessionDep,\n    offset: int = 0,\n    limit: Annotated[int, Query(le=100)] = 100,\n):\n    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n    return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef read_hero(hero_id: int, session: SessionDep):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    return hero\n\n\n@app.patch(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):\n    hero_db = session.get(Hero, hero_id)\n    if not hero_db:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    hero_data = hero.model_dump(exclude_unset=True)\n    hero_db.sqlmodel_update(hero_data)\n    session.add(hero_db)\n    session.commit()\n    session.refresh(hero_db)\n    return hero_db\n\n\n@app.delete(\"/heroes/{hero_id}\")\ndef delete_hero(hero_id: int, session: SessionDep):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    session.delete(hero)\n    session.commit()\n    return {\"ok\": True}\n"
  },
  {
    "path": "docs_src/sql_databases/tutorial002_py310.py",
    "content": "from fastapi import Depends, FastAPI, HTTPException, Query\nfrom sqlmodel import Field, Session, SQLModel, create_engine, select\n\n\nclass HeroBase(SQLModel):\n    name: str = Field(index=True)\n    age: int | None = Field(default=None, index=True)\n\n\nclass Hero(HeroBase, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    secret_name: str\n\n\nclass HeroPublic(HeroBase):\n    id: int\n\n\nclass HeroCreate(HeroBase):\n    secret_name: str\n\n\nclass HeroUpdate(HeroBase):\n    name: str | None = None\n    age: int | None = None\n    secret_name: str | None = None\n\n\nsqlite_file_name = \"database.db\"\nsqlite_url = f\"sqlite:///{sqlite_file_name}\"\n\nconnect_args = {\"check_same_thread\": False}\nengine = create_engine(sqlite_url, connect_args=connect_args)\n\n\ndef create_db_and_tables():\n    SQLModel.metadata.create_all(engine)\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\napp = FastAPI()\n\n\n@app.on_event(\"startup\")\ndef on_startup():\n    create_db_and_tables()\n\n\n@app.post(\"/heroes/\", response_model=HeroPublic)\ndef create_hero(hero: HeroCreate, session: Session = Depends(get_session)):\n    db_hero = Hero.model_validate(hero)\n    session.add(db_hero)\n    session.commit()\n    session.refresh(db_hero)\n    return db_hero\n\n\n@app.get(\"/heroes/\", response_model=list[HeroPublic])\ndef read_heroes(\n    session: Session = Depends(get_session),\n    offset: int = 0,\n    limit: int = Query(default=100, le=100),\n):\n    heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()\n    return heroes\n\n\n@app.get(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef read_hero(hero_id: int, session: Session = Depends(get_session)):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    return hero\n\n\n@app.patch(\"/heroes/{hero_id}\", response_model=HeroPublic)\ndef update_hero(\n    hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session)\n):\n    hero_db = session.get(Hero, hero_id)\n    if not hero_db:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    hero_data = hero.model_dump(exclude_unset=True)\n    hero_db.sqlmodel_update(hero_data)\n    session.add(hero_db)\n    session.commit()\n    session.refresh(hero_db)\n    return hero_db\n\n\n@app.delete(\"/heroes/{hero_id}\")\ndef delete_hero(hero_id: int, session: Session = Depends(get_session)):\n    hero = session.get(Hero, hero_id)\n    if not hero:\n        raise HTTPException(status_code=404, detail=\"Hero not found\")\n    session.delete(hero)\n    session.commit()\n    return {\"ok\": True}\n"
  },
  {
    "path": "docs_src/static_files/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/static_files/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.staticfiles import StaticFiles\n\napp = FastAPI()\n\napp.mount(\"/static\", StaticFiles(directory=\"static\"), name=\"static\")\n"
  },
  {
    "path": "docs_src/stream_data/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/stream_data/tutorial001_py310.py",
    "content": "from collections.abc import AsyncIterable, Iterable\n\nfrom fastapi import FastAPI\nfrom fastapi.responses import StreamingResponse\n\napp = FastAPI()\n\n\nmessage = \"\"\"\nRick: (stumbles in drunkenly, and turns on the lights) Morty! You gotta come on. You got--... you gotta come with me.\nMorty: (rubs his eyes) What, Rick? What's going on?\nRick: I got a surprise for you, Morty.\nMorty: It's the middle of the night. What are you talking about?\nRick: (spills alcohol on Morty's bed) Come on, I got a surprise for you. (drags Morty by the ankle) Come on, hurry up. (pulls Morty out of his bed and into the hall)\nMorty: Ow! Ow! You're tugging me too hard!\nRick: We gotta go, gotta get outta here, come on. Got a surprise for you Morty.\n\"\"\"\n\n\n@app.get(\"/story/stream\", response_class=StreamingResponse)\nasync def stream_story() -> AsyncIterable[str]:\n    for line in message.splitlines():\n        yield line\n\n\n@app.get(\"/story/stream-no-async\", response_class=StreamingResponse)\ndef stream_story_no_async() -> Iterable[str]:\n    for line in message.splitlines():\n        yield line\n\n\n@app.get(\"/story/stream-no-annotation\", response_class=StreamingResponse)\nasync def stream_story_no_annotation():\n    for line in message.splitlines():\n        yield line\n\n\n@app.get(\"/story/stream-no-async-no-annotation\", response_class=StreamingResponse)\ndef stream_story_no_async_no_annotation():\n    for line in message.splitlines():\n        yield line\n\n\n@app.get(\"/story/stream-bytes\", response_class=StreamingResponse)\nasync def stream_story_bytes() -> AsyncIterable[bytes]:\n    for line in message.splitlines():\n        yield line.encode(\"utf-8\")\n\n\n@app.get(\"/story/stream-no-async-bytes\", response_class=StreamingResponse)\ndef stream_story_no_async_bytes() -> Iterable[bytes]:\n    for line in message.splitlines():\n        yield line.encode(\"utf-8\")\n\n\n@app.get(\"/story/stream-no-annotation-bytes\", response_class=StreamingResponse)\nasync def stream_story_no_annotation_bytes():\n    for line in message.splitlines():\n        yield line.encode(\"utf-8\")\n\n\n@app.get(\"/story/stream-no-async-no-annotation-bytes\", response_class=StreamingResponse)\ndef stream_story_no_async_no_annotation_bytes():\n    for line in message.splitlines():\n        yield line.encode(\"utf-8\")\n"
  },
  {
    "path": "docs_src/stream_data/tutorial002_py310.py",
    "content": "import base64\nfrom collections.abc import AsyncIterable, Iterable\nfrom io import BytesIO\n\nfrom fastapi import FastAPI\nfrom fastapi.responses import StreamingResponse\n\nimage_base64 = \"iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdCAYAAABWk2cPAAAAbnpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjadYzRDYAwCET/mcIRDoq0jGOiJm7g+NJK0vjhS4DjIEfHfZ20DKqSrrWZmyFQV5ctRMOLACxglNCcXk7zVqFzJzF8kV6R5vOJ97yVH78HjfYAtg0ged033ZgAAAoCaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA0LjQuMC1FeGl2MiI+CiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyIKICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICBleGlmOlBpeGVsWERpbWVuc2lvbj0iMjkiCiAgIGV4aWY6UGl4ZWxZRGltZW5zaW9uPSIyOSIKICAgdGlmZjpJbWFnZVdpZHRoPSIyOSIKICAgdGlmZjpJbWFnZUxlbmd0aD0iMjkiCiAgIHRpZmY6T3JpZW50YXRpb249IjEiLz4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PnQkBZAAAAAEc0JJVAgICAh8CGSIAAABoklEQVRIx8VXwY7FIAjE5iXWU+P/f6RHPNW9LIaOoHYP+0yMShVkwNGG1lqjfy4HfaF0oyEEt+oSQqBaa//m9Wd6PlqhhbRMDiEQM3e59FNKw5qZHpnQfuPaW6lazsztvu/eElFj5j63lNLlMz2ttbZtVMu1MTGo5Sujn93gMzOllKiUQjHGB9QxxneZhJ5iwZ1rL2fwenoGeL0q3wVGhBPHMz0PeFccIfASEeWcO8xEROd50q6eAV6s1s5XXoncas1EKqVQznnwUBdJJmm1l3hmmdlOMrGO8Vl5gZ56Y0y8IZF0BuqkQWM4B6HXrRCKa1SEqyzEo7KK59RT/VHDjX3ZvSefeW3CO6O6vsiA1NrwVkxxAcYTCcHyTjZmJd00pugBQoTnzjvn+kzLBh9GtRDjhleZFwbx3kugP3GvFzdkqRlbDYw0u/HxKjuOw2QxZCGL5V5f4l7cd6qsffUa1DcLM9N1XcTMvep5ul1e4jNPtZfWGIkE6dI8MquXg/dS2CGVJQ2ushd5GmlxFdOw+1tRa32MY4zDQ9yaZ60J3/iX+QG4U3qGrFHmswAAAABJRU5ErkJggg==\"\nbinary_image = base64.b64decode(image_base64)\n\n\ndef read_image() -> BytesIO:\n    return BytesIO(binary_image)\n\n\napp = FastAPI()\n\n\nclass PNGStreamingResponse(StreamingResponse):\n    media_type = \"image/png\"\n\n\n@app.get(\"/image/stream\", response_class=PNGStreamingResponse)\nasync def stream_image() -> AsyncIterable[bytes]:\n    with read_image() as image_file:\n        for chunk in image_file:\n            yield chunk\n\n\n@app.get(\"/image/stream-no-async\", response_class=PNGStreamingResponse)\ndef stream_image_no_async() -> Iterable[bytes]:\n    with read_image() as image_file:\n        for chunk in image_file:\n            yield chunk\n\n\n@app.get(\"/image/stream-no-async-yield-from\", response_class=PNGStreamingResponse)\ndef stream_image_no_async_yield_from() -> Iterable[bytes]:\n    with read_image() as image_file:\n        yield from image_file\n\n\n@app.get(\"/image/stream-no-annotation\", response_class=PNGStreamingResponse)\nasync def stream_image_no_annotation():\n    with read_image() as image_file:\n        for chunk in image_file:\n            yield chunk\n\n\n@app.get(\"/image/stream-no-async-no-annotation\", response_class=PNGStreamingResponse)\ndef stream_image_no_async_no_annotation():\n    with read_image() as image_file:\n        for chunk in image_file:\n            yield chunk\n"
  },
  {
    "path": "docs_src/stream_json_lines/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/stream_json_lines/tutorial001_py310.py",
    "content": "from collections.abc import AsyncIterable, Iterable\n\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None\n\n\nitems = [\n    Item(name=\"Plumbus\", description=\"A multi-purpose household device.\"),\n    Item(name=\"Portal Gun\", description=\"A portal opening device.\"),\n    Item(name=\"Meeseeks Box\", description=\"A box that summons a Meeseeks.\"),\n]\n\n\n@app.get(\"/items/stream\")\nasync def stream_items() -> AsyncIterable[Item]:\n    for item in items:\n        yield item\n\n\n@app.get(\"/items/stream-no-async\")\ndef stream_items_no_async() -> Iterable[Item]:\n    for item in items:\n        yield item\n\n\n@app.get(\"/items/stream-no-annotation\")\nasync def stream_items_no_annotation():\n    for item in items:\n        yield item\n\n\n@app.get(\"/items/stream-no-async-no-annotation\")\ndef stream_items_no_async_no_annotation():\n    for item in items:\n        yield item\n"
  },
  {
    "path": "docs_src/strict_content_type/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/strict_content_type/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI(strict_content_type=False)\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item):\n    return item\n"
  },
  {
    "path": "docs_src/sub_applications/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/sub_applications/tutorial001_py310.py",
    "content": "from fastapi import FastAPI\n\napp = FastAPI()\n\n\n@app.get(\"/app\")\ndef read_main():\n    return {\"message\": \"Hello World from main app\"}\n\n\nsubapi = FastAPI()\n\n\n@subapi.get(\"/sub\")\ndef read_sub():\n    return {\"message\": \"Hello World from sub API\"}\n\n\napp.mount(\"/subapi\", subapi)\n"
  },
  {
    "path": "docs_src/templates/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/templates/static/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/templates/static/styles.css",
    "content": "h1 {\n    color: green;\n}\n"
  },
  {
    "path": "docs_src/templates/templates/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/templates/templates/item.html",
    "content": "<html>\n<head>\n    <title>Item Details</title>\n    <link href=\"{{ url_for('static', path='/styles.css') }}\" rel=\"stylesheet\">\n</head>\n<body>\n    <h1><a href=\"{{ url_for('read_item', id=id) }}\">Item ID: {{ id }}</a></h1>\n</body>\n</html>\n"
  },
  {
    "path": "docs_src/templates/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, Request\nfrom fastapi.responses import HTMLResponse\nfrom fastapi.staticfiles import StaticFiles\nfrom fastapi.templating import Jinja2Templates\n\napp = FastAPI()\n\napp.mount(\"/static\", StaticFiles(directory=\"static\"), name=\"static\")\n\n\ntemplates = Jinja2Templates(directory=\"templates\")\n\n\n@app.get(\"/items/{id}\", response_class=HTMLResponse)\nasync def read_item(request: Request, id: str):\n    return templates.TemplateResponse(\n        request=request, name=\"item.html\", context={\"id\": id}\n    )\n"
  },
  {
    "path": "docs_src/using_request_directly/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/using_request_directly/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, Request\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\ndef read_root(item_id: str, request: Request):\n    client_host = request.client.host\n    return {\"client_host\": client_host, \"item_id\": item_id}\n"
  },
  {
    "path": "docs_src/websockets_/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/websockets_/tutorial001_py310.py",
    "content": "from fastapi import FastAPI, WebSocket\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\nhtml = \"\"\"\n<!DOCTYPE html>\n<html>\n    <head>\n        <title>Chat</title>\n    </head>\n    <body>\n        <h1>WebSocket Chat</h1>\n        <form action=\"\" onsubmit=\"sendMessage(event)\">\n            <input type=\"text\" id=\"messageText\" autocomplete=\"off\"/>\n            <button>Send</button>\n        </form>\n        <ul id='messages'>\n        </ul>\n        <script>\n            var ws = new WebSocket(\"ws://localhost:8000/ws\");\n            ws.onmessage = function(event) {\n                var messages = document.getElementById('messages')\n                var message = document.createElement('li')\n                var content = document.createTextNode(event.data)\n                message.appendChild(content)\n                messages.appendChild(message)\n            };\n            function sendMessage(event) {\n                var input = document.getElementById(\"messageText\")\n                ws.send(input.value)\n                input.value = ''\n                event.preventDefault()\n            }\n        </script>\n    </body>\n</html>\n\"\"\"\n\n\n@app.get(\"/\")\nasync def get():\n    return HTMLResponse(html)\n\n\n@app.websocket(\"/ws\")\nasync def websocket_endpoint(websocket: WebSocket):\n    await websocket.accept()\n    while True:\n        data = await websocket.receive_text()\n        await websocket.send_text(f\"Message text was: {data}\")\n"
  },
  {
    "path": "docs_src/websockets_/tutorial002_an_py310.py",
    "content": "from typing import Annotated\n\nfrom fastapi import (\n    Cookie,\n    Depends,\n    FastAPI,\n    Query,\n    WebSocket,\n    WebSocketException,\n    status,\n)\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\nhtml = \"\"\"\n<!DOCTYPE html>\n<html>\n    <head>\n        <title>Chat</title>\n    </head>\n    <body>\n        <h1>WebSocket Chat</h1>\n        <form action=\"\" onsubmit=\"sendMessage(event)\">\n            <label>Item ID: <input type=\"text\" id=\"itemId\" autocomplete=\"off\" value=\"foo\"/></label>\n            <label>Token: <input type=\"text\" id=\"token\" autocomplete=\"off\" value=\"some-key-token\"/></label>\n            <button onclick=\"connect(event)\">Connect</button>\n            <hr>\n            <label>Message: <input type=\"text\" id=\"messageText\" autocomplete=\"off\"/></label>\n            <button>Send</button>\n        </form>\n        <ul id='messages'>\n        </ul>\n        <script>\n        var ws = null;\n            function connect(event) {\n                var itemId = document.getElementById(\"itemId\")\n                var token = document.getElementById(\"token\")\n                ws = new WebSocket(\"ws://localhost:8000/items/\" + itemId.value + \"/ws?token=\" + token.value);\n                ws.onmessage = function(event) {\n                    var messages = document.getElementById('messages')\n                    var message = document.createElement('li')\n                    var content = document.createTextNode(event.data)\n                    message.appendChild(content)\n                    messages.appendChild(message)\n                };\n                event.preventDefault()\n            }\n            function sendMessage(event) {\n                var input = document.getElementById(\"messageText\")\n                ws.send(input.value)\n                input.value = ''\n                event.preventDefault()\n            }\n        </script>\n    </body>\n</html>\n\"\"\"\n\n\n@app.get(\"/\")\nasync def get():\n    return HTMLResponse(html)\n\n\nasync def get_cookie_or_token(\n    websocket: WebSocket,\n    session: Annotated[str | None, Cookie()] = None,\n    token: Annotated[str | None, Query()] = None,\n):\n    if session is None and token is None:\n        raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)\n    return session or token\n\n\n@app.websocket(\"/items/{item_id}/ws\")\nasync def websocket_endpoint(\n    *,\n    websocket: WebSocket,\n    item_id: str,\n    q: int | None = None,\n    cookie_or_token: Annotated[str, Depends(get_cookie_or_token)],\n):\n    await websocket.accept()\n    while True:\n        data = await websocket.receive_text()\n        await websocket.send_text(\n            f\"Session cookie or query token value is: {cookie_or_token}\"\n        )\n        if q is not None:\n            await websocket.send_text(f\"Query parameter q is: {q}\")\n        await websocket.send_text(f\"Message text was: {data}, for item ID: {item_id}\")\n"
  },
  {
    "path": "docs_src/websockets_/tutorial002_py310.py",
    "content": "from fastapi import (\n    Cookie,\n    Depends,\n    FastAPI,\n    Query,\n    WebSocket,\n    WebSocketException,\n    status,\n)\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\nhtml = \"\"\"\n<!DOCTYPE html>\n<html>\n    <head>\n        <title>Chat</title>\n    </head>\n    <body>\n        <h1>WebSocket Chat</h1>\n        <form action=\"\" onsubmit=\"sendMessage(event)\">\n            <label>Item ID: <input type=\"text\" id=\"itemId\" autocomplete=\"off\" value=\"foo\"/></label>\n            <label>Token: <input type=\"text\" id=\"token\" autocomplete=\"off\" value=\"some-key-token\"/></label>\n            <button onclick=\"connect(event)\">Connect</button>\n            <hr>\n            <label>Message: <input type=\"text\" id=\"messageText\" autocomplete=\"off\"/></label>\n            <button>Send</button>\n        </form>\n        <ul id='messages'>\n        </ul>\n        <script>\n        var ws = null;\n            function connect(event) {\n                var itemId = document.getElementById(\"itemId\")\n                var token = document.getElementById(\"token\")\n                ws = new WebSocket(\"ws://localhost:8000/items/\" + itemId.value + \"/ws?token=\" + token.value);\n                ws.onmessage = function(event) {\n                    var messages = document.getElementById('messages')\n                    var message = document.createElement('li')\n                    var content = document.createTextNode(event.data)\n                    message.appendChild(content)\n                    messages.appendChild(message)\n                };\n                event.preventDefault()\n            }\n            function sendMessage(event) {\n                var input = document.getElementById(\"messageText\")\n                ws.send(input.value)\n                input.value = ''\n                event.preventDefault()\n            }\n        </script>\n    </body>\n</html>\n\"\"\"\n\n\n@app.get(\"/\")\nasync def get():\n    return HTMLResponse(html)\n\n\nasync def get_cookie_or_token(\n    websocket: WebSocket,\n    session: str | None = Cookie(default=None),\n    token: str | None = Query(default=None),\n):\n    if session is None and token is None:\n        raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)\n    return session or token\n\n\n@app.websocket(\"/items/{item_id}/ws\")\nasync def websocket_endpoint(\n    websocket: WebSocket,\n    item_id: str,\n    q: int | None = None,\n    cookie_or_token: str = Depends(get_cookie_or_token),\n):\n    await websocket.accept()\n    while True:\n        data = await websocket.receive_text()\n        await websocket.send_text(\n            f\"Session cookie or query token value is: {cookie_or_token}\"\n        )\n        if q is not None:\n            await websocket.send_text(f\"Query parameter q is: {q}\")\n        await websocket.send_text(f\"Message text was: {data}, for item ID: {item_id}\")\n"
  },
  {
    "path": "docs_src/websockets_/tutorial003_py310.py",
    "content": "from fastapi import FastAPI, WebSocket, WebSocketDisconnect\nfrom fastapi.responses import HTMLResponse\n\napp = FastAPI()\n\nhtml = \"\"\"\n<!DOCTYPE html>\n<html>\n    <head>\n        <title>Chat</title>\n    </head>\n    <body>\n        <h1>WebSocket Chat</h1>\n        <h2>Your ID: <span id=\"ws-id\"></span></h2>\n        <form action=\"\" onsubmit=\"sendMessage(event)\">\n            <input type=\"text\" id=\"messageText\" autocomplete=\"off\"/>\n            <button>Send</button>\n        </form>\n        <ul id='messages'>\n        </ul>\n        <script>\n            var client_id = Date.now()\n            document.querySelector(\"#ws-id\").textContent = client_id;\n            var ws = new WebSocket(`ws://localhost:8000/ws/${client_id}`);\n            ws.onmessage = function(event) {\n                var messages = document.getElementById('messages')\n                var message = document.createElement('li')\n                var content = document.createTextNode(event.data)\n                message.appendChild(content)\n                messages.appendChild(message)\n            };\n            function sendMessage(event) {\n                var input = document.getElementById(\"messageText\")\n                ws.send(input.value)\n                input.value = ''\n                event.preventDefault()\n            }\n        </script>\n    </body>\n</html>\n\"\"\"\n\n\nclass ConnectionManager:\n    def __init__(self):\n        self.active_connections: list[WebSocket] = []\n\n    async def connect(self, websocket: WebSocket):\n        await websocket.accept()\n        self.active_connections.append(websocket)\n\n    def disconnect(self, websocket: WebSocket):\n        self.active_connections.remove(websocket)\n\n    async def send_personal_message(self, message: str, websocket: WebSocket):\n        await websocket.send_text(message)\n\n    async def broadcast(self, message: str):\n        for connection in self.active_connections:\n            await connection.send_text(message)\n\n\nmanager = ConnectionManager()\n\n\n@app.get(\"/\")\nasync def get():\n    return HTMLResponse(html)\n\n\n@app.websocket(\"/ws/{client_id}\")\nasync def websocket_endpoint(websocket: WebSocket, client_id: int):\n    await manager.connect(websocket)\n    try:\n        while True:\n            data = await websocket.receive_text()\n            await manager.send_personal_message(f\"You wrote: {data}\", websocket)\n            await manager.broadcast(f\"Client #{client_id} says: {data}\")\n    except WebSocketDisconnect:\n        manager.disconnect(websocket)\n        await manager.broadcast(f\"Client #{client_id} left the chat\")\n"
  },
  {
    "path": "docs_src/wsgi/__init__.py",
    "content": ""
  },
  {
    "path": "docs_src/wsgi/tutorial001_py310.py",
    "content": "from a2wsgi import WSGIMiddleware\nfrom fastapi import FastAPI\nfrom flask import Flask, request\nfrom markupsafe import escape\n\nflask_app = Flask(__name__)\n\n\n@flask_app.route(\"/\")\ndef flask_main():\n    name = request.args.get(\"name\", \"World\")\n    return f\"Hello, {escape(name)} from Flask!\"\n\n\napp = FastAPI()\n\n\n@app.get(\"/v2\")\ndef read_main():\n    return {\"message\": \"Hello World\"}\n\n\napp.mount(\"/v1\", WSGIMiddleware(flask_app))\n"
  },
  {
    "path": "fastapi/.agents/skills/fastapi/SKILL.md",
    "content": "---\nname: fastapi\ndescription: FastAPI best practices and conventions. Use when working with FastAPI APIs and Pydantic models for them. Keeps FastAPI code clean and up to date with the latest features and patterns, updated with new versions. Write new code or refactor and update old code.\n---\n\n# FastAPI\n\nOfficial FastAPI skill to write code with best practices, keeping up to date with new versions and features.\n\n## Use the `fastapi` CLI\n\nRun the development server on localhost with reload:\n\n```bash\nfastapi dev\n```\n\n\nRun the production server:\n\n```bash\nfastapi run\n```\n\n### Add an entrypoint in `pyproject.toml`\n\nFastAPI CLI will read the entrypoint in `pyproject.toml` to know where the FastAPI app is declared.\n\n```toml\n[tool.fastapi]\nentrypoint = \"my_app.main:app\"\n```\n\n### Use `fastapi` with a path\n\nWhen adding the entrypoint to `pyproject.toml` is not possible, or the user explicitly asks not to, or it's running an independent small app, you can pass the app file path to the `fastapi` command:\n\n```bash\nfastapi dev my_app/main.py\n```\n\nPrefer to set the entrypoint in `pyproject.toml` when possible.\n\n## Use `Annotated`\n\nAlways prefer the `Annotated` style for parameter and dependency declarations.\n\nIt keeps the function signatures working in other contexts, respects the types, allows reusability.\n\n### In Parameter Declarations\n\nUse `Annotated` for parameter declarations, including `Path`, `Query`, `Header`, etc.:\n\n```python\nfrom typing import Annotated\n\nfrom fastapi import FastAPI, Path, Query\n\napp = FastAPI()\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(\n    item_id: Annotated[int, Path(ge=1, description=\"The item ID\")],\n    q: Annotated[str | None, Query(max_length=50)] = None,\n):\n    return {\"message\": \"Hello World\"}\n```\n\ninstead of:\n\n```python\n# DO NOT DO THIS\n@app.get(\"/items/{item_id}\")\nasync def read_item(\n    item_id: int = Path(ge=1, description=\"The item ID\"),\n    q: str | None = Query(default=None, max_length=50),\n):\n    return {\"message\": \"Hello World\"}\n```\n\n### For Dependencies\n\nUse `Annotated` for dependencies with `Depends()`.\n\nUnless asked not to, create a new type alias for the dependency to allow re-using it.\n\n```python\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\ndef get_current_user():\n    return {\"username\": \"johndoe\"}\n\n\nCurrentUserDep = Annotated[dict, Depends(get_current_user)]\n\n\n@app.get(\"/items/\")\nasync def read_item(current_user: CurrentUserDep):\n    return {\"message\": \"Hello World\"}\n```\n\ninstead of:\n\n```python\n# DO NOT DO THIS\n@app.get(\"/items/\")\nasync def read_item(current_user: dict = Depends(get_current_user)):\n    return {\"message\": \"Hello World\"}\n```\n\n## Do not use Ellipsis for *path operations* or Pydantic models\n\nDo not use `...` as a default value for required parameters, it's not needed and not recommended.\n\nDo this, without Ellipsis (`...`):\n\n```python\nfrom typing import Annotated\n\nfrom fastapi import FastAPI, Query\nfrom pydantic import BaseModel, Field\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    price: float = Field(gt=0)\n\n\napp = FastAPI()\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item, project_id: Annotated[int, Query()]): ...\n```\n\ninstead of this:\n\n```python\n# DO NOT DO THIS\nclass Item(BaseModel):\n    name: str = ...\n    description: str | None = None\n    price: float = Field(..., gt=0)\n\n\napp = FastAPI()\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item, project_id: Annotated[int, Query(...)]): ...\n```\n\n## Return Type or Response Model\n\nWhen possible, include a return type. It will be used to validate, filter, document, and serialize the response.\n\n```python\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n\n\n@app.get(\"/items/me\")\nasync def get_item() -> Item:\n    return Item(name=\"Plumbus\", description=\"All-purpose home device\")\n```\n\n**Important**: Return types or response models are what filter data ensuring no sensitive information is exposed. And they are used to serialize data with Pydantic (in Rust), this is the main idea that can increase response performance.\n\nThe return type doesn't have to be a Pydantic model, it could be a different type, like a list of integers, or a dict, etc.\n\n### When to use `response_model` instead\n\nIf the return type is not the same as the type that you want to use to validate, filter, or serialize, use the `response_model` parameter on the decorator instead.\n\n```python\nfrom typing import Any\n\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n\n\n@app.get(\"/items/me\", response_model=Item)\nasync def get_item() -> Any:\n    return {\"name\": \"Foo\", \"description\": \"A very nice Item\"}\n```\n\nThis can be particularly useful when filtering data to expose only the public fields and avoid exposing sensitive information.\n\n```python\nfrom typing import Any\n\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass InternalItem(BaseModel):\n    name: str\n    description: str | None = None\n    secret_key: str\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n\n\n@app.get(\"/items/me\", response_model=Item)\nasync def get_item() -> Any:\n    item = InternalItem(\n        name=\"Foo\", description=\"A very nice Item\", secret_key=\"supersecret\"\n    )\n    return item\n```\n\n## Performance\n\nDo not use `ORJSONResponse` or `UJSONResponse`, they are deprecated.\n\nInstead, declare a return type or response model. Pydantic will handle the data serialization on the Rust side.\n\n## Including Routers\n\nWhen declaring routers, prefer to add router level parameters like prefix, tags, etc. to the router itself, instead of in `include_router()`.\n\nDo this:\n\n```python\nfrom fastapi import APIRouter, FastAPI\n\napp = FastAPI()\n\nrouter = APIRouter(prefix=\"/items\", tags=[\"items\"])\n\n\n@router.get(\"/\")\nasync def list_items():\n    return []\n\n\n# In main.py\napp.include_router(router)\n```\n\ninstead of this:\n\n```python\n# DO NOT DO THIS\nfrom fastapi import APIRouter, FastAPI\n\napp = FastAPI()\n\nrouter = APIRouter()\n\n\n@router.get(\"/\")\nasync def list_items():\n    return []\n\n\n# In main.py\napp.include_router(router, prefix=\"/items\", tags=[\"items\"])\n```\n\nThere could be exceptions, but try to follow this convention.\n\nApply shared dependencies at the router level via `dependencies=[Depends(...)]`.\n\n## Dependency Injection\n\nSee [the dependency injection reference](references/dependencies.md) for detailed patterns including `yield` with `scope`, and class dependencies.\n\nUse dependencies when the logic can't be declared in Pydantic validation, depends on external resources, needs cleanup (with `yield`), or is shared across endpoints.\n\nApply shared dependencies at the router level via `dependencies=[Depends(...)]`.\n\n## Async vs Sync *path operations*\n\nUse `async` *path operations* only when fully certain that the logic called inside is compatible with async and await (it's called with `await`) or that doesn't block.\n\n```python\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\n# Use async def when calling async code\n@app.get(\"/async-items/\")\nasync def read_async_items():\n    data = await some_async_library.fetch_items()\n    return data\n\n\n# Use plain def when calling blocking/sync code or when in doubt\n@app.get(\"/items/\")\ndef read_items():\n    data = some_blocking_library.fetch_items()\n    return data\n```\n\nIn case of doubt, or by default, use regular `def` functions, those will be run in a threadpool so they don't block the event loop.\n\nThe same rules apply to dependencies.\n\nMake sure blocking code is not run inside of `async` functions. The logic will work, but will damage the performance heavily.\n\nWhen needing to mix blocking and async code, see Asyncer in [the other tools reference](references/other-tools.md).\n\n## Streaming (JSON Lines, SSE, bytes)\n\nSee [the streaming reference](references/streaming.md) for JSON Lines, Server-Sent Events (`EventSourceResponse`, `ServerSentEvent`), and byte streaming (`StreamingResponse`) patterns.\n\n## Tooling\n\nSee [the other tools reference](references/other-tools.md) for details on uv, Ruff, ty for package management, linting, type checking, formatting, etc.\n\n## Other Libraries\n\nSee [the other tools reference](references/other-tools.md) for details on other libraries:\n\n* Asyncer for handling async and await, concurrency, mixing async and blocking code, prefer it over AnyIO or asyncio.\n* SQLModel for working with SQL databases, prefer it over SQLAlchemy.\n* HTTPX for interacting with HTTP (other APIs), prefer it over Requests.\n\n## Do not use Pydantic RootModels\n\nDo not use Pydantic `RootModel`, instead use regular type annotations with `Annotated` and Pydantic validation utilities.\n\nFor example, for a list with validations you could do:\n\n```python\nfrom typing import Annotated\n\nfrom fastapi import Body, FastAPI\nfrom pydantic import Field\n\napp = FastAPI()\n\n\n@app.post(\"/items/\")\nasync def create_items(items: Annotated[list[int], Field(min_length=1), Body()]):\n    return items\n```\n\ninstead of:\n\n```python\n# DO NOT DO THIS\nfrom typing import Annotated\n\nfrom fastapi import FastAPI\nfrom pydantic import Field, RootModel\n\napp = FastAPI()\n\n\nclass ItemList(RootModel[Annotated[list[int], Field(min_length=1)]]):\n    pass\n\n\n@app.post(\"/items/\")\nasync def create_items(items: ItemList):\n    return items\n\n```\n\nFastAPI supports these type annotations and will create a Pydantic `TypeAdapter` for them, so that types can work as normally and there's no need for the custom logic and types in RootModels.\n\n## Use one HTTP operation per function\n\nDon't mix HTTP operations in a single function, having one function per HTTP operation helps separate concerns and organize the code.\n\nDo this:\n\n```python\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n\n\n@app.get(\"/items/\")\nasync def list_items():\n    return []\n\n\n@app.post(\"/items/\")\nasync def create_item(item: Item):\n    return item\n```\n\ninstead of this:\n\n```python\n# DO NOT DO THIS\nfrom fastapi import FastAPI, Request\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n\n\n@app.api_route(\"/items/\", methods=[\"GET\", \"POST\"])\nasync def handle_items(request: Request):\n    if request.method == \"GET\":\n        return []\n```\n"
  },
  {
    "path": "fastapi/.agents/skills/fastapi/references/dependencies.md",
    "content": "# Dependency Injection\n\nUse dependencies when:\n\n* They can't be declared in Pydantic validation and require additional logic\n* The logic depends on external resources or could block in any other way\n* Other dependencies need their results (it's a sub-dependency)\n* The logic can be shared by multiple endpoints to do things like error early, authentication, etc.\n* They need to handle cleanup (e.g., DB sessions, file handles), using dependencies with `yield`\n* Their logic needs input data from the request, like headers, query parameters, etc.\n\n## Dependencies with `yield` and `scope`\n\nWhen using dependencies with `yield`, they can have a `scope` that defines when the exit code is run.\n\nUse the default scope `\"request\"` to run the exit code after the response is sent back.\n\n```python\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\ndef get_db():\n    db = DBSession()\n    try:\n        yield db\n    finally:\n        db.close()\n\n\nDBDep = Annotated[DBSession, Depends(get_db)]\n\n\n@app.get(\"/items/\")\nasync def read_items(db: DBDep):\n    return db.query(Item).all()\n```\n\nUse the scope `\"function\"` when they should run the exit code after the response data is generated but before the response is sent back to the client.\n\n```python\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\ndef get_username():\n    try:\n        yield \"Rick\"\n    finally:\n        print(\"Cleanup up before response is sent\")\n\nUserNameDep = Annotated[str, Depends(get_username, scope=\"function\")]\n\n@app.get(\"/users/me\")\ndef get_user_me(username: UserNameDep):\n    return username\n```\n\n## Class Dependencies\n\nAvoid creating class dependencies when possible.\n\nIf a class is needed, instead create a regular function dependency that returns a class instance.\n\nDo this:\n\n```python\nfrom dataclasses import dataclass\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\n@dataclass\nclass DatabasePaginator:\n    offset: int = 0\n    limit: int = 100\n    q: str | None = None\n\n    def get_page(self) -> dict:\n        # Simulate a page of data\n        return {\n            \"offset\": self.offset,\n            \"limit\": self.limit,\n            \"q\": self.q,\n            \"items\": [],\n        }\n\n\ndef get_db_paginator(\n    offset: int = 0, limit: int = 100, q: str | None = None\n) -> DatabasePaginator:\n    return DatabasePaginator(offset=offset, limit=limit, q=q)\n\n\nPaginatorDep = Annotated[DatabasePaginator, Depends(get_db_paginator)]\n\n\n@app.get(\"/items/\")\nasync def read_items(paginator: PaginatorDep):\n    return paginator.get_page()\n```\n\ninstead of this:\n\n```python\n# DO NOT DO THIS\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\n\napp = FastAPI()\n\n\nclass DatabasePaginator:\n    def __init__(self, offset: int = 0, limit: int = 100, q: str | None = None):\n        self.offset = offset\n        self.limit = limit\n        self.q = q\n\n    def get_page(self) -> dict:\n        # Simulate a page of data\n        return {\n            \"offset\": self.offset,\n            \"limit\": self.limit,\n            \"q\": self.q,\n            \"items\": [],\n        }\n\n\n@app.get(\"/items/\")\nasync def read_items(paginator: Annotated[DatabasePaginator, Depends()]):\n    return paginator.get_page()\n```\n"
  },
  {
    "path": "fastapi/.agents/skills/fastapi/references/other-tools.md",
    "content": "# Other Tools\n\n## uv\n\nIf uv is available, use it to manage dependencies.\n\n## Ruff\n\nIf Ruff is available, use it to lint and format the code. Consider enabling the FastAPI rules.\n\n## ty\n\nIf ty is available, use it to check types.\n\n## Asyncer\n\nWhen needing to run blocking code inside of async functions, or async code inside of blocking functions, suggest using Asyncer.\n\nPrefer it over AnyIO or asyncio.\n\nInstall:\n\n```bash\nuv add asyncer\n```\n\nRun blocking sync code inside of async with `asyncify()`:\n\n```python\nfrom asyncer import asyncify\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\ndef do_blocking_work(name: str) -> str:\n    # Some blocking I/O operation\n    return f\"Hello {name}\"\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    result = await asyncify(do_blocking_work)(name=\"World\")\n    return {\"message\": result}\n```\n\nAnd run async code inside of blocking sync code with `syncify()`:\n\n```python\nfrom asyncer import syncify\nfrom fastapi import FastAPI\n\napp = FastAPI()\n\n\nasync def do_async_work(name: str) -> str:\n    return f\"Hello {name}\"\n\n\n@app.get(\"/items/\")\ndef read_items():\n    result = syncify(do_async_work)(name=\"World\")\n    return {\"message\": result}\n```\n\n## SQLModel for SQL databases\n\nWhen working with SQL databases, prefer using SQLModel as it is integrated with Pydantic and will allow declaring data validation with the same models.\n\nPrefer it over SQLAlchemy.\n\n## HTTPX\n\nUse HTTPX for handling HTTP communication (e.g. with other APIs). It support sync and async usage.\n\nPrefer it over Requests.\n"
  },
  {
    "path": "fastapi/.agents/skills/fastapi/references/streaming.md",
    "content": "# Streaming\n\n## Stream JSON Lines\n\nTo stream JSON Lines, declare the return type and use `yield` to return the data.\n\n```python\n@app.get(\"/items/stream\")\nasync def stream_items() -> AsyncIterable[Item]:\n    for item in items:\n        yield item\n```\n\n## Server-Sent Events (SSE)\n\nTo stream Server-Sent Events, use `response_class=EventSourceResponse` and `yield` items from the endpoint.\n\nPlain objects are automatically JSON-serialized as `data:` fields, declare the return type so the serialization is done by Pydantic:\n\n```python\nfrom collections.abc import AsyncIterable\n\nfrom fastapi import FastAPI\nfrom fastapi.sse import EventSourceResponse\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\n@app.get(\"/items/stream\", response_class=EventSourceResponse)\nasync def stream_items() -> AsyncIterable[Item]:\n    yield Item(name=\"Plumbus\", price=32.99)\n    yield Item(name=\"Portal Gun\", price=999.99)\n```\n\nFor full control over SSE fields (`event`, `id`, `retry`, `comment`), yield `ServerSentEvent` instances:\n\n```python\nfrom collections.abc import AsyncIterable\n\nfrom fastapi import FastAPI\nfrom fastapi.sse import EventSourceResponse, ServerSentEvent\n\napp = FastAPI()\n\n\n@app.get(\"/events\", response_class=EventSourceResponse)\nasync def stream_events() -> AsyncIterable[ServerSentEvent]:\n    yield ServerSentEvent(data={\"status\": \"started\"}, event=\"status\", id=\"1\")\n    yield ServerSentEvent(data={\"progress\": 50}, event=\"progress\", id=\"2\")\n```\n\nUse `raw_data` instead of `data` to send pre-formatted strings without JSON encoding:\n\n```python\nyield ServerSentEvent(raw_data=\"plain text line\", event=\"log\")\n```\n\n## Stream bytes\n\nTo stream bytes, declare a `response_class=` of `StreamingResponse` or a sub-class, and use `yield` to return the data.\n\n```python\nfrom fastapi import FastAPI\nfrom fastapi.responses import StreamingResponse\nfrom app.utils import read_image\n\napp = FastAPI()\n\n\nclass PNGStreamingResponse(StreamingResponse):\n    media_type = \"image/png\"\n\n@app.get(\"/image\", response_class=PNGStreamingResponse)\ndef stream_image_no_async_no_annotation():\n    with read_image() as image_file:\n        yield from image_file\n```\n\nprefer this over returning a `StreamingResponse` directly:\n\n```python\n# DO NOT DO THIS\n\nimport anyio\nfrom fastapi import FastAPI\nfrom fastapi.responses import StreamingResponse\nfrom app.utils import read_image\n\napp = FastAPI()\n\n\nclass PNGStreamingResponse(StreamingResponse):\n    media_type = \"image/png\"\n\n\n@app.get(\"/\")\nasync def main():\n    return PNGStreamingResponse(read_image())\n```\n"
  },
  {
    "path": "fastapi/__init__.py",
    "content": "\"\"\"FastAPI framework, high performance, easy to learn, fast to code, ready for production\"\"\"\n\n__version__ = \"0.136.1\"\n\nfrom starlette import status as status\n\nfrom .applications import FastAPI as FastAPI\nfrom .background import BackgroundTasks as BackgroundTasks\nfrom .datastructures import UploadFile as UploadFile\nfrom .exceptions import HTTPException as HTTPException\nfrom .exceptions import WebSocketException as WebSocketException\nfrom .param_functions import Body as Body\nfrom .param_functions import Cookie as Cookie\nfrom .param_functions import Depends as Depends\nfrom .param_functions import File as File\nfrom .param_functions import Form as Form\nfrom .param_functions import Header as Header\nfrom .param_functions import Path as Path\nfrom .param_functions import Query as Query\nfrom .param_functions import Security as Security\nfrom .requests import Request as Request\nfrom .responses import Response as Response\nfrom .routing import APIRouter as APIRouter\nfrom .websockets import WebSocket as WebSocket\nfrom .websockets import WebSocketDisconnect as WebSocketDisconnect\n"
  },
  {
    "path": "fastapi/__main__.py",
    "content": "from fastapi.cli import main\n\nmain()\n"
  },
  {
    "path": "fastapi/_compat/__init__.py",
    "content": "from .shared import PYDANTIC_VERSION_MINOR_TUPLE as PYDANTIC_VERSION_MINOR_TUPLE\nfrom .shared import annotation_is_pydantic_v1 as annotation_is_pydantic_v1\nfrom .shared import field_annotation_is_scalar as field_annotation_is_scalar\nfrom .shared import (\n    field_annotation_is_scalar_sequence as field_annotation_is_scalar_sequence,\n)\nfrom .shared import field_annotation_is_sequence as field_annotation_is_sequence\nfrom .shared import (\n    is_bytes_or_nonable_bytes_annotation as is_bytes_or_nonable_bytes_annotation,\n)\nfrom .shared import is_bytes_sequence_annotation as is_bytes_sequence_annotation\nfrom .shared import is_pydantic_v1_model_instance as is_pydantic_v1_model_instance\nfrom .shared import (\n    is_uploadfile_or_nonable_uploadfile_annotation as is_uploadfile_or_nonable_uploadfile_annotation,\n)\nfrom .shared import (\n    is_uploadfile_sequence_annotation as is_uploadfile_sequence_annotation,\n)\nfrom .shared import lenient_issubclass as lenient_issubclass\nfrom .shared import sequence_types as sequence_types\nfrom .shared import value_is_sequence as value_is_sequence\nfrom .v2 import ModelField as ModelField\nfrom .v2 import PydanticSchemaGenerationError as PydanticSchemaGenerationError\nfrom .v2 import RequiredParam as RequiredParam\nfrom .v2 import Undefined as Undefined\nfrom .v2 import Url as Url\nfrom .v2 import copy_field_info as copy_field_info\nfrom .v2 import create_body_model as create_body_model\nfrom .v2 import evaluate_forwardref as evaluate_forwardref\nfrom .v2 import get_cached_model_fields as get_cached_model_fields\nfrom .v2 import get_definitions as get_definitions\nfrom .v2 import get_flat_models_from_fields as get_flat_models_from_fields\nfrom .v2 import get_missing_field_error as get_missing_field_error\nfrom .v2 import get_model_name_map as get_model_name_map\nfrom .v2 import get_schema_from_model_field as get_schema_from_model_field\nfrom .v2 import is_scalar_field as is_scalar_field\nfrom .v2 import serialize_sequence_value as serialize_sequence_value\nfrom .v2 import (\n    with_info_plain_validator_function as with_info_plain_validator_function,\n)\n"
  },
  {
    "path": "fastapi/_compat/shared.py",
    "content": "import types\nimport typing\nimport warnings\nfrom collections import deque\nfrom collections.abc import Mapping, Sequence\nfrom dataclasses import is_dataclass\nfrom typing import (\n    Annotated,\n    Any,\n    TypeGuard,\n    TypeVar,\n    Union,\n    get_args,\n    get_origin,\n)\n\nfrom fastapi.types import UnionType\nfrom pydantic import BaseModel\nfrom pydantic.version import VERSION as PYDANTIC_VERSION\nfrom starlette.datastructures import UploadFile\n\n_T = TypeVar(\"_T\")\n\n# Copy from Pydantic: pydantic/_internal/_typing_extra.py\nWithArgsTypes: tuple[Any, ...] = (\n    typing._GenericAlias,  # type: ignore[attr-defined]  # ty: ignore[unresolved-attribute]\n    types.GenericAlias,\n    types.UnionType,\n)  # pyright: ignore[reportAttributeAccessIssue]\n\nPYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(\".\")[:2])\n\n\nsequence_annotation_to_type = {\n    Sequence: list,\n    list: list,\n    tuple: tuple,\n    set: set,\n    frozenset: frozenset,\n    deque: deque,\n}\n\nsequence_types: tuple[type[Any], ...] = tuple(sequence_annotation_to_type.keys())\n\n\n# Copy of Pydantic: pydantic/_internal/_utils.py with added TypeGuard\ndef lenient_issubclass(\n    cls: Any, class_or_tuple: type[_T] | tuple[type[_T], ...] | None\n) -> TypeGuard[type[_T]]:\n    try:\n        return isinstance(cls, type) and issubclass(cls, class_or_tuple)  # type: ignore[arg-type]  # ty: ignore[invalid-argument-type]\n    except TypeError:  # pragma: no cover\n        if isinstance(cls, WithArgsTypes):\n            return False\n        raise  # pragma: no cover\n\n\ndef _annotation_is_sequence(annotation: type[Any] | None) -> bool:\n    if lenient_issubclass(annotation, (str, bytes)):\n        return False\n    return lenient_issubclass(annotation, sequence_types)\n\n\ndef field_annotation_is_sequence(annotation: type[Any] | None) -> bool:\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:\n        for arg in get_args(annotation):\n            if field_annotation_is_sequence(arg):\n                return True\n        return False\n    return _annotation_is_sequence(annotation) or _annotation_is_sequence(\n        get_origin(annotation)\n    )\n\n\ndef value_is_sequence(value: Any) -> bool:\n    return isinstance(value, sequence_types) and not isinstance(value, (str, bytes))\n\n\ndef _annotation_is_complex(annotation: type[Any] | None) -> bool:\n    return (\n        lenient_issubclass(annotation, (BaseModel, Mapping, UploadFile))\n        or _annotation_is_sequence(annotation)\n        or is_dataclass(annotation)\n    )\n\n\ndef field_annotation_is_complex(annotation: type[Any] | None) -> bool:\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:\n        return any(field_annotation_is_complex(arg) for arg in get_args(annotation))\n\n    if origin is Annotated:\n        return field_annotation_is_complex(get_args(annotation)[0])\n\n    return (\n        _annotation_is_complex(annotation)\n        or _annotation_is_complex(origin)\n        or hasattr(origin, \"__pydantic_core_schema__\")\n        or hasattr(origin, \"__get_pydantic_core_schema__\")\n    )\n\n\ndef field_annotation_is_scalar(annotation: Any) -> bool:\n    # handle Ellipsis here to make tuple[int, ...] work nicely\n    return annotation is Ellipsis or not field_annotation_is_complex(annotation)\n\n\ndef field_annotation_is_scalar_sequence(annotation: type[Any] | None) -> bool:\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:\n        at_least_one_scalar_sequence = False\n        for arg in get_args(annotation):\n            if field_annotation_is_scalar_sequence(arg):\n                at_least_one_scalar_sequence = True\n                continue\n            elif not field_annotation_is_scalar(arg):\n                return False\n        return at_least_one_scalar_sequence\n    return field_annotation_is_sequence(annotation) and all(\n        field_annotation_is_scalar(sub_annotation)\n        for sub_annotation in get_args(annotation)\n    )\n\n\ndef is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool:\n    if lenient_issubclass(annotation, bytes):\n        return True\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:\n        for arg in get_args(annotation):\n            if lenient_issubclass(arg, bytes):\n                return True\n    return False\n\n\ndef is_uploadfile_or_nonable_uploadfile_annotation(annotation: Any) -> bool:\n    if lenient_issubclass(annotation, UploadFile):\n        return True\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:\n        for arg in get_args(annotation):\n            if lenient_issubclass(arg, UploadFile):\n                return True\n    return False\n\n\ndef is_bytes_sequence_annotation(annotation: Any) -> bool:\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:\n        at_least_one = False\n        for arg in get_args(annotation):\n            if is_bytes_sequence_annotation(arg):\n                at_least_one = True\n                continue\n        return at_least_one\n    return field_annotation_is_sequence(annotation) and all(\n        is_bytes_or_nonable_bytes_annotation(sub_annotation)\n        for sub_annotation in get_args(annotation)\n    )\n\n\ndef is_uploadfile_sequence_annotation(annotation: Any) -> bool:\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:\n        at_least_one = False\n        for arg in get_args(annotation):\n            if is_uploadfile_sequence_annotation(arg):\n                at_least_one = True\n                continue\n        return at_least_one\n    return field_annotation_is_sequence(annotation) and all(\n        is_uploadfile_or_nonable_uploadfile_annotation(sub_annotation)\n        for sub_annotation in get_args(annotation)\n    )\n\n\ndef is_pydantic_v1_model_instance(obj: Any) -> bool:\n    # TODO: remove this function once the required version of Pydantic fully\n    # removes pydantic.v1\n    try:\n        with warnings.catch_warnings():\n            warnings.simplefilter(\"ignore\", UserWarning)\n            from pydantic import v1\n    except ImportError:  # pragma: no cover\n        return False\n    return isinstance(obj, v1.BaseModel)\n\n\ndef is_pydantic_v1_model_class(cls: Any) -> bool:\n    # TODO: remove this function once the required version of Pydantic fully\n    # removes pydantic.v1\n    try:\n        with warnings.catch_warnings():\n            warnings.simplefilter(\"ignore\", UserWarning)\n            from pydantic import v1\n    except ImportError:  # pragma: no cover\n        return False\n    return lenient_issubclass(cls, v1.BaseModel)\n\n\ndef annotation_is_pydantic_v1(annotation: Any) -> bool:\n    if is_pydantic_v1_model_class(annotation):\n        return True\n    origin = get_origin(annotation)\n    if origin is Union or origin is UnionType:\n        for arg in get_args(annotation):\n            if is_pydantic_v1_model_class(arg):\n                return True\n    if field_annotation_is_sequence(annotation):\n        for sub_annotation in get_args(annotation):\n            if annotation_is_pydantic_v1(sub_annotation):\n                return True\n    return False\n"
  },
  {
    "path": "fastapi/_compat/v2.py",
    "content": "import re\nimport warnings\nfrom collections.abc import Sequence\nfrom copy import copy\nfrom dataclasses import dataclass, is_dataclass\nfrom enum import Enum\nfrom functools import lru_cache\nfrom typing import (\n    Annotated,\n    Any,\n    Literal,\n    Union,\n    cast,\n    get_args,\n    get_origin,\n)\n\nfrom fastapi._compat import lenient_issubclass, shared\nfrom fastapi.openapi.constants import REF_TEMPLATE\nfrom fastapi.types import IncEx, ModelNameMap, UnionType\nfrom pydantic import BaseModel, ConfigDict, Field, TypeAdapter, create_model\nfrom pydantic import PydanticSchemaGenerationError as PydanticSchemaGenerationError\nfrom pydantic import PydanticUndefinedAnnotation as PydanticUndefinedAnnotation\nfrom pydantic import ValidationError as ValidationError\nfrom pydantic._internal import _typing_extra as _pydantic_typing_extra\nfrom pydantic._internal._schema_generation_shared import (  # type: ignore[attr-defined]\n    GetJsonSchemaHandler as GetJsonSchemaHandler,\n)\nfrom pydantic.fields import FieldInfo as FieldInfo\nfrom pydantic.json_schema import GenerateJsonSchema as _GenerateJsonSchema\nfrom pydantic.json_schema import JsonSchemaValue as JsonSchemaValue\nfrom pydantic_core import CoreSchema as CoreSchema\nfrom pydantic_core import PydanticUndefined\nfrom pydantic_core import Url as Url\nfrom pydantic_core.core_schema import (\n    with_info_plain_validator_function as with_info_plain_validator_function,\n)\n\nRequiredParam = PydanticUndefined\nUndefined = PydanticUndefined\n\n\ndef evaluate_forwardref(\n    value: Any,\n    globalns: dict[str, Any] | None = None,\n    localns: dict[str, Any] | None = None,\n) -> Any:\n    # eval_type_lenient has been deprecated since Pydantic v2.10.0b1 (PR #10530)\n    try_eval_type = getattr(_pydantic_typing_extra, \"try_eval_type\", None)\n    if try_eval_type is not None:\n        return try_eval_type(value, globalns, localns)[0]\n    return _pydantic_typing_extra.eval_type_lenient(  # ty: ignore[deprecated]\n        value, globalns, localns\n    )\n\n\nclass GenerateJsonSchema(_GenerateJsonSchema):\n    # TODO: remove when this is merged (or equivalent): https://github.com/pydantic/pydantic/pull/12841\n    # and dropping support for any version of Pydantic before that one (so, in a very long time)\n    def bytes_schema(self, schema: CoreSchema) -> JsonSchemaValue:\n        json_schema = {\"type\": \"string\", \"contentMediaType\": \"application/octet-stream\"}\n        bytes_mode = (\n            self._config.ser_json_bytes\n            if self.mode == \"serialization\"\n            else self._config.val_json_bytes\n        )\n        if bytes_mode == \"base64\":\n            json_schema[\"contentEncoding\"] = \"base64\"\n        self.update_with_validations(json_schema, schema, self.ValidationsMapping.bytes)\n        return json_schema\n\n\n# TODO: remove when dropping support for Pydantic < v2.12.3\n_Attrs = {\n    \"default\": ...,\n    \"default_factory\": None,\n    \"alias\": None,\n    \"alias_priority\": None,\n    \"validation_alias\": None,\n    \"serialization_alias\": None,\n    \"title\": None,\n    \"field_title_generator\": None,\n    \"description\": None,\n    \"examples\": None,\n    \"exclude\": None,\n    \"exclude_if\": None,\n    \"discriminator\": None,\n    \"deprecated\": None,\n    \"json_schema_extra\": None,\n    \"frozen\": None,\n    \"validate_default\": None,\n    \"repr\": True,\n    \"init\": None,\n    \"init_var\": None,\n    \"kw_only\": None,\n}\n\n\n# TODO: remove when dropping support for Pydantic < v2.12.3\ndef asdict(field_info: FieldInfo) -> dict[str, Any]:\n    attributes = {}\n    for attr in _Attrs:\n        value = getattr(field_info, attr, Undefined)\n        if value is not Undefined:\n            attributes[attr] = value\n    return {\n        \"annotation\": field_info.annotation,\n        \"metadata\": field_info.metadata,\n        \"attributes\": attributes,\n    }\n\n\n@dataclass\nclass ModelField:\n    field_info: FieldInfo\n    name: str\n    mode: Literal[\"validation\", \"serialization\"] = \"validation\"\n    config: ConfigDict | None = None\n\n    @property\n    def alias(self) -> str:\n        a = self.field_info.alias\n        return a if a is not None else self.name\n\n    @property\n    def validation_alias(self) -> str | None:\n        va = self.field_info.validation_alias\n        if isinstance(va, str) and va:\n            return va\n        return None\n\n    @property\n    def serialization_alias(self) -> str | None:\n        sa = self.field_info.serialization_alias\n        return sa or None\n\n    @property\n    def default(self) -> Any:\n        return self.get_default()\n\n    def __post_init__(self) -> None:\n        with warnings.catch_warnings():\n            # Pydantic >= 2.12.0 warns about field specific metadata that is unused\n            # (e.g. `TypeAdapter(Annotated[int, Field(alias='b')])`). In some cases, we\n            # end up building the type adapter from a model field annotation so we\n            # need to ignore the warning:\n            if shared.PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12):\n                from pydantic.warnings import UnsupportedFieldAttributeWarning\n\n                warnings.simplefilter(\n                    \"ignore\", category=UnsupportedFieldAttributeWarning\n                )\n            # TODO: remove after setting the min Pydantic to v2.12.3\n            # that adds asdict(), and use self.field_info.asdict() instead\n            field_dict = asdict(self.field_info)\n            annotated_args = (\n                field_dict[\"annotation\"],\n                *field_dict[\"metadata\"],\n                # this FieldInfo needs to be created again so that it doesn't include\n                # the old field info metadata and only the rest of the attributes\n                Field(**field_dict[\"attributes\"]),\n            )\n            self._type_adapter: TypeAdapter[Any] = TypeAdapter(\n                Annotated[annotated_args],  # ty: ignore[invalid-type-form]\n                config=self.config,\n            )\n\n    def get_default(self) -> Any:\n        if self.field_info.is_required():\n            return Undefined\n        return self.field_info.get_default(call_default_factory=True)\n\n    def validate(\n        self,\n        value: Any,\n        values: dict[str, Any] = {},  # noqa: B006\n        *,\n        loc: tuple[int | str, ...] = (),\n    ) -> tuple[Any, list[dict[str, Any]]]:\n        try:\n            return (\n                self._type_adapter.validate_python(value, from_attributes=True),\n                [],\n            )\n        except ValidationError as exc:\n            return None, _regenerate_error_with_loc(\n                errors=exc.errors(include_url=False), loc_prefix=loc\n            )\n\n    def serialize(\n        self,\n        value: Any,\n        *,\n        mode: Literal[\"json\", \"python\"] = \"json\",\n        include: IncEx | None = None,\n        exclude: IncEx | None = None,\n        by_alias: bool = True,\n        exclude_unset: bool = False,\n        exclude_defaults: bool = False,\n        exclude_none: bool = False,\n    ) -> Any:\n        # What calls this code passes a value that already called\n        # self._type_adapter.validate_python(value)\n        return self._type_adapter.dump_python(\n            value,\n            mode=mode,\n            include=include,\n            exclude=exclude,\n            by_alias=by_alias,\n            exclude_unset=exclude_unset,\n            exclude_defaults=exclude_defaults,\n            exclude_none=exclude_none,\n        )\n\n    def serialize_json(\n        self,\n        value: Any,\n        *,\n        include: IncEx | None = None,\n        exclude: IncEx | None = None,\n        by_alias: bool = True,\n        exclude_unset: bool = False,\n        exclude_defaults: bool = False,\n        exclude_none: bool = False,\n    ) -> bytes:\n        # What calls this code passes a value that already called\n        # self._type_adapter.validate_python(value)\n        # This uses Pydantic's dump_json() which serializes directly to JSON\n        # bytes in one pass (via Rust), avoiding the intermediate Python dict\n        # step of dump_python(mode=\"json\") + json.dumps().\n        return self._type_adapter.dump_json(\n            value,\n            include=include,\n            exclude=exclude,\n            by_alias=by_alias,\n            exclude_unset=exclude_unset,\n            exclude_defaults=exclude_defaults,\n            exclude_none=exclude_none,\n        )\n\n    def __hash__(self) -> int:\n        # Each ModelField is unique for our purposes, to allow making a dict from\n        # ModelField to its JSON Schema.\n        return id(self)\n\n\ndef _has_computed_fields(field: ModelField) -> bool:\n    computed_fields = field._type_adapter.core_schema.get(\"schema\", {}).get(\n        \"computed_fields\", []\n    )\n    return len(computed_fields) > 0\n\n\ndef get_schema_from_model_field(\n    *,\n    field: ModelField,\n    model_name_map: ModelNameMap,\n    field_mapping: dict[\n        tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue\n    ],\n    separate_input_output_schemas: bool = True,\n) -> dict[str, Any]:\n    override_mode: Literal[\"validation\"] | None = (\n        None\n        if (separate_input_output_schemas or _has_computed_fields(field))\n        else \"validation\"\n    )\n    field_alias = (\n        (field.validation_alias or field.alias)\n        if field.mode == \"validation\"\n        else (field.serialization_alias or field.alias)\n    )\n\n    # This expects that GenerateJsonSchema was already used to generate the definitions\n    json_schema = field_mapping[(field, override_mode or field.mode)]\n    if \"$ref\" not in json_schema:\n        # TODO remove when deprecating Pydantic v1\n        # Ref: https://github.com/pydantic/pydantic/blob/d61792cc42c80b13b23e3ffa74bc37ec7c77f7d1/pydantic/schema.py#L207\n        json_schema[\"title\"] = field.field_info.title or field_alias.title().replace(\n            \"_\", \" \"\n        )\n    return json_schema\n\n\ndef get_definitions(\n    *,\n    fields: Sequence[ModelField],\n    model_name_map: ModelNameMap,\n    separate_input_output_schemas: bool = True,\n) -> tuple[\n    dict[tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue],\n    dict[str, dict[str, Any]],\n]:\n    schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)\n    validation_fields = [field for field in fields if field.mode == \"validation\"]\n    serialization_fields = [field for field in fields if field.mode == \"serialization\"]\n    flat_validation_models = get_flat_models_from_fields(\n        validation_fields, known_models=set()\n    )\n    flat_serialization_models = get_flat_models_from_fields(\n        serialization_fields, known_models=set()\n    )\n    flat_validation_model_fields = [\n        ModelField(\n            field_info=FieldInfo(annotation=model),\n            name=model.__name__,\n            mode=\"validation\",\n        )\n        for model in flat_validation_models\n    ]\n    flat_serialization_model_fields = [\n        ModelField(\n            field_info=FieldInfo(annotation=model),\n            name=model.__name__,\n            mode=\"serialization\",\n        )\n        for model in flat_serialization_models\n    ]\n    flat_model_fields = flat_validation_model_fields + flat_serialization_model_fields\n    input_types = {f.field_info.annotation for f in fields}\n    unique_flat_model_fields = {\n        f for f in flat_model_fields if f.field_info.annotation not in input_types\n    }\n    inputs = [\n        (\n            field,\n            (\n                field.mode\n                if (separate_input_output_schemas or _has_computed_fields(field))\n                else \"validation\"\n            ),\n            field._type_adapter.core_schema,\n        )\n        for field in list(fields) + list(unique_flat_model_fields)\n    ]\n    field_mapping, definitions = schema_generator.generate_definitions(inputs=inputs)\n    for item_def in cast(dict[str, dict[str, Any]], definitions).values():\n        if \"description\" in item_def:\n            item_description = cast(str, item_def[\"description\"]).split(\"\\f\")[0]\n            item_def[\"description\"] = item_description\n    # definitions: dict[DefsRef, dict[str, Any]]\n    # but mypy complains about general str in other places that are not declared as\n    # DefsRef, although DefsRef is just str:\n    # DefsRef = NewType('DefsRef', str)\n    # So, a cast to simplify the types here\n    return field_mapping, cast(dict[str, dict[str, Any]], definitions)\n\n\ndef is_scalar_field(field: ModelField) -> bool:\n    from fastapi import params\n\n    return shared.field_annotation_is_scalar(\n        field.field_info.annotation\n    ) and not isinstance(field.field_info, params.Body)\n\n\ndef copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:\n    cls = type(field_info)\n    merged_field_info = cls.from_annotation(annotation)\n    new_field_info = copy(field_info)\n    new_field_info.metadata = merged_field_info.metadata\n    new_field_info.annotation = merged_field_info.annotation\n    return new_field_info\n\n\ndef serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:\n    origin_type = get_origin(field.field_info.annotation) or field.field_info.annotation\n    if origin_type is Union or origin_type is UnionType:  # Handle optional sequences\n        union_args = get_args(field.field_info.annotation)\n        for union_arg in union_args:\n            if union_arg is type(None):\n                continue\n            origin_type = get_origin(union_arg) or union_arg\n            break\n    assert issubclass(origin_type, shared.sequence_types)  # type: ignore[arg-type]  # ty: ignore[invalid-argument-type]\n    return shared.sequence_annotation_to_type[origin_type](value)  # type: ignore[no-any-return,index]  # ty: ignore[invalid-return-type]\n\n\ndef get_missing_field_error(loc: tuple[int | str, ...]) -> dict[str, Any]:\n    error = ValidationError.from_exception_data(\n        \"Field required\", [{\"type\": \"missing\", \"loc\": loc, \"input\": {}}]\n    ).errors(include_url=False)[0]\n    error[\"input\"] = None\n    return error  # type: ignore[return-value]  # ty: ignore[invalid-return-type]\n\n\ndef create_body_model(\n    *, fields: Sequence[ModelField], model_name: str\n) -> type[BaseModel]:\n    field_params = {f.name: (f.field_info.annotation, f.field_info) for f in fields}\n    BodyModel: type[BaseModel] = create_model(model_name, **field_params)  # type: ignore[call-overload]  # ty: ignore[no-matching-overload]\n    return BodyModel\n\n\ndef get_model_fields(model: type[BaseModel]) -> list[ModelField]:\n    model_fields: list[ModelField] = []\n    for name, field_info in model.model_fields.items():\n        type_ = field_info.annotation\n        if lenient_issubclass(type_, (BaseModel, dict)) or is_dataclass(type_):\n            model_config = None\n        else:\n            model_config = model.model_config\n        model_fields.append(\n            ModelField(\n                field_info=field_info,\n                name=name,\n                config=model_config,\n            )\n        )\n    return model_fields\n\n\n@lru_cache\ndef get_cached_model_fields(model: type[BaseModel]) -> list[ModelField]:\n    return get_model_fields(model)\n\n\n# Duplicate of several schema functions from Pydantic v1 to make them compatible with\n# Pydantic v2 and allow mixing the models\n\nTypeModelOrEnum = type[\"BaseModel\"] | type[Enum]\nTypeModelSet = set[TypeModelOrEnum]\n\n\ndef normalize_name(name: str) -> str:\n    return re.sub(r\"[^a-zA-Z0-9.\\-_]\", \"_\", name)\n\n\ndef get_model_name_map(unique_models: TypeModelSet) -> dict[TypeModelOrEnum, str]:\n    name_model_map = {}\n    for model in unique_models:\n        model_name = normalize_name(model.__name__)\n        name_model_map[model_name] = model\n    return {v: k for k, v in name_model_map.items()}\n\n\ndef get_flat_models_from_model(\n    model: type[\"BaseModel\"], known_models: TypeModelSet | None = None\n) -> TypeModelSet:\n    known_models = known_models or set()\n    fields = get_model_fields(model)\n    get_flat_models_from_fields(fields, known_models=known_models)\n    return known_models\n\n\ndef get_flat_models_from_annotation(\n    annotation: Any, known_models: TypeModelSet\n) -> TypeModelSet:\n    origin = get_origin(annotation)\n    if origin is not None:\n        for arg in get_args(annotation):\n            if lenient_issubclass(arg, (BaseModel, Enum)):\n                if arg not in known_models:\n                    known_models.add(arg)  # type: ignore[arg-type]\n                    if lenient_issubclass(arg, BaseModel):\n                        get_flat_models_from_model(arg, known_models=known_models)\n            else:\n                get_flat_models_from_annotation(arg, known_models=known_models)\n    return known_models\n\n\ndef get_flat_models_from_field(\n    field: ModelField, known_models: TypeModelSet\n) -> TypeModelSet:\n    field_type = field.field_info.annotation\n    if lenient_issubclass(field_type, BaseModel):\n        if field_type in known_models:\n            return known_models\n        known_models.add(field_type)\n        get_flat_models_from_model(field_type, known_models=known_models)\n    elif lenient_issubclass(field_type, Enum):\n        known_models.add(field_type)\n    else:\n        get_flat_models_from_annotation(field_type, known_models=known_models)\n    return known_models\n\n\ndef get_flat_models_from_fields(\n    fields: Sequence[ModelField], known_models: TypeModelSet\n) -> TypeModelSet:\n    for field in fields:\n        get_flat_models_from_field(field, known_models=known_models)\n    return known_models\n\n\ndef _regenerate_error_with_loc(\n    *, errors: Sequence[Any], loc_prefix: tuple[str | int, ...]\n) -> list[dict[str, Any]]:\n    updated_loc_errors: list[Any] = [\n        {**err, \"loc\": loc_prefix + err.get(\"loc\", ())} for err in errors\n    ]\n\n    return updated_loc_errors\n"
  },
  {
    "path": "fastapi/background.py",
    "content": "from collections.abc import Callable\nfrom typing import Annotated, Any\n\nfrom annotated_doc import Doc\nfrom starlette.background import BackgroundTasks as StarletteBackgroundTasks\nfrom typing_extensions import ParamSpec\n\nP = ParamSpec(\"P\")\n\n\nclass BackgroundTasks(StarletteBackgroundTasks):\n    \"\"\"\n    A collection of background tasks that will be called after a response has been\n    sent to the client.\n\n    Read more about it in the\n    [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/).\n\n    ## Example\n\n    ```python\n    from fastapi import BackgroundTasks, FastAPI\n\n    app = FastAPI()\n\n\n    def write_notification(email: str, message=\"\"):\n        with open(\"log.txt\", mode=\"w\") as email_file:\n            content = f\"notification for {email}: {message}\"\n            email_file.write(content)\n\n\n    @app.post(\"/send-notification/{email}\")\n    async def send_notification(email: str, background_tasks: BackgroundTasks):\n        background_tasks.add_task(write_notification, email, message=\"some notification\")\n        return {\"message\": \"Notification sent in the background\"}\n    ```\n    \"\"\"\n\n    def add_task(\n        self,\n        func: Annotated[\n            Callable[P, Any],\n            Doc(\n                \"\"\"\n                The function to call after the response is sent.\n\n                It can be a regular `def` function or an `async def` function.\n                \"\"\"\n            ),\n        ],\n        *args: P.args,\n        **kwargs: P.kwargs,\n    ) -> None:\n        \"\"\"\n        Add a function to be called in the background after the response is sent.\n\n        Read more about it in the\n        [FastAPI docs for Background Tasks](https://fastapi.tiangolo.com/tutorial/background-tasks/).\n        \"\"\"\n        return super().add_task(func, *args, **kwargs)\n"
  },
  {
    "path": "fastapi/cli.py",
    "content": "try:\n    from fastapi_cli.cli import main as cli_main\n\nexcept ImportError:  # pragma: no cover\n    cli_main = None  # type: ignore\n\n\ndef main() -> None:\n    if not cli_main:  # type: ignore[truthy-function]\n        message = 'To use the fastapi command, please install \"fastapi[standard]\":\\n\\n\\tpip install \"fastapi[standard]\"\\n'\n        print(message)\n        raise RuntimeError(message)  # noqa: B904\n    cli_main()\n"
  },
  {
    "path": "fastapi/concurrency.py",
    "content": "from collections.abc import AsyncGenerator\nfrom contextlib import AbstractContextManager\nfrom contextlib import asynccontextmanager as asynccontextmanager\nfrom typing import TypeVar\n\nimport anyio.to_thread\nfrom anyio import CapacityLimiter\nfrom starlette.concurrency import iterate_in_threadpool as iterate_in_threadpool  # noqa\nfrom starlette.concurrency import run_in_threadpool as run_in_threadpool  # noqa\nfrom starlette.concurrency import (  # noqa\n    run_until_first_complete as run_until_first_complete,\n)\n\n_T = TypeVar(\"_T\")\n\n\n@asynccontextmanager\nasync def contextmanager_in_threadpool(\n    cm: AbstractContextManager[_T],\n) -> AsyncGenerator[_T, None]:\n    # blocking __exit__ from running waiting on a free thread\n    # can create race conditions/deadlocks if the context manager itself\n    # has its own internal pool (e.g. a database connection pool)\n    # to avoid this we let __exit__ run without a capacity limit\n    # since we're creating a new limiter for each call, any non-zero limit\n    # works (1 is arbitrary)\n    exit_limiter = CapacityLimiter(1)\n    try:\n        yield await run_in_threadpool(cm.__enter__)\n    except Exception as e:\n        ok = bool(\n            await anyio.to_thread.run_sync(\n                cm.__exit__, type(e), e, e.__traceback__, limiter=exit_limiter\n            )\n        )\n        if not ok:\n            raise e\n    else:\n        await anyio.to_thread.run_sync(\n            cm.__exit__, None, None, None, limiter=exit_limiter\n        )\n"
  },
  {
    "path": "fastapi/datastructures.py",
    "content": "from collections.abc import Callable, Mapping\nfrom typing import (\n    Annotated,\n    Any,\n    BinaryIO,\n    TypeVar,\n    cast,\n)\n\nfrom annotated_doc import Doc\nfrom pydantic import GetJsonSchemaHandler\nfrom starlette.datastructures import URL as URL  # noqa: F401\nfrom starlette.datastructures import Address as Address  # noqa: F401\nfrom starlette.datastructures import FormData as FormData  # noqa: F401\nfrom starlette.datastructures import Headers as Headers  # noqa: F401\nfrom starlette.datastructures import QueryParams as QueryParams  # noqa: F401\nfrom starlette.datastructures import State as State  # noqa: F401\nfrom starlette.datastructures import UploadFile as StarletteUploadFile\n\n\nclass UploadFile(StarletteUploadFile):\n    \"\"\"\n    A file uploaded in a request.\n\n    Define it as a *path operation function* (or dependency) parameter.\n\n    If you are using a regular `def` function, you can use the `upload_file.file`\n    attribute to access the raw standard Python file (blocking, not async), useful and\n    needed for non-async code.\n\n    Read more about it in the\n    [FastAPI docs for Request Files](https://fastapi.tiangolo.com/tutorial/request-files/).\n\n    ## Example\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import FastAPI, File, UploadFile\n\n    app = FastAPI()\n\n\n    @app.post(\"/files/\")\n    async def create_file(file: Annotated[bytes, File()]):\n        return {\"file_size\": len(file)}\n\n\n    @app.post(\"/uploadfile/\")\n    async def create_upload_file(file: UploadFile):\n        return {\"filename\": file.filename}\n    ```\n    \"\"\"\n\n    file: Annotated[\n        BinaryIO,\n        Doc(\"The standard Python file object (non-async).\"),\n    ]\n    filename: Annotated[str | None, Doc(\"The original file name.\")]\n    size: Annotated[int | None, Doc(\"The size of the file in bytes.\")]\n    headers: Annotated[Headers, Doc(\"The headers of the request.\")]\n    content_type: Annotated[\n        str | None, Doc(\"The content type of the request, from the headers.\")\n    ]\n\n    async def write(\n        self,\n        data: Annotated[\n            bytes,\n            Doc(\n                \"\"\"\n                The bytes to write to the file.\n                \"\"\"\n            ),\n        ],\n    ) -> None:\n        \"\"\"\n        Write some bytes to the file.\n\n        You normally wouldn't use this from a file you read in a request.\n\n        To be awaitable, compatible with async, this is run in threadpool.\n        \"\"\"\n        return await super().write(data)\n\n    async def read(\n        self,\n        size: Annotated[\n            int,\n            Doc(\n                \"\"\"\n                The number of bytes to read from the file.\n                \"\"\"\n            ),\n        ] = -1,\n    ) -> bytes:\n        \"\"\"\n        Read some bytes from the file.\n\n        To be awaitable, compatible with async, this is run in threadpool.\n        \"\"\"\n        return await super().read(size)\n\n    async def seek(\n        self,\n        offset: Annotated[\n            int,\n            Doc(\n                \"\"\"\n                The position in bytes to seek to in the file.\n                \"\"\"\n            ),\n        ],\n    ) -> None:\n        \"\"\"\n        Move to a position in the file.\n\n        Any next read or write will be done from that position.\n\n        To be awaitable, compatible with async, this is run in threadpool.\n        \"\"\"\n        return await super().seek(offset)\n\n    async def close(self) -> None:\n        \"\"\"\n        Close the file.\n\n        To be awaitable, compatible with async, this is run in threadpool.\n        \"\"\"\n        return await super().close()\n\n    @classmethod\n    def _validate(cls, __input_value: Any, _: Any) -> \"UploadFile\":\n        if not isinstance(__input_value, StarletteUploadFile):\n            raise ValueError(f\"Expected UploadFile, received: {type(__input_value)}\")\n        return cast(UploadFile, __input_value)\n\n    @classmethod\n    def __get_pydantic_json_schema__(\n        cls, core_schema: Mapping[str, Any], handler: GetJsonSchemaHandler\n    ) -> dict[str, Any]:\n        return {\"type\": \"string\", \"contentMediaType\": \"application/octet-stream\"}\n\n    @classmethod\n    def __get_pydantic_core_schema__(\n        cls, source: type[Any], handler: Callable[[Any], Mapping[str, Any]]\n    ) -> Mapping[str, Any]:\n        from ._compat.v2 import with_info_plain_validator_function\n\n        return with_info_plain_validator_function(cls._validate)\n\n\nclass DefaultPlaceholder:\n    \"\"\"\n    You shouldn't use this class directly.\n\n    It's used internally to recognize when a default value has been overwritten, even\n    if the overridden default value was truthy.\n    \"\"\"\n\n    def __init__(self, value: Any):\n        self.value = value\n\n    def __bool__(self) -> bool:\n        return bool(self.value)\n\n    def __eq__(self, o: object) -> bool:\n        return isinstance(o, DefaultPlaceholder) and o.value == self.value\n\n\nDefaultType = TypeVar(\"DefaultType\")\n\n\ndef Default(value: DefaultType) -> DefaultType:\n    \"\"\"\n    You shouldn't use this function directly.\n\n    It's used internally to recognize when a default value has been overwritten, even\n    if the overridden default value was truthy.\n    \"\"\"\n    return DefaultPlaceholder(value)  # type: ignore\n\n\n# Sentinel for \"parameter not provided\" in Param/FieldInfo.\n# Typed as None to satisfy ty\n_Unset = Default(None)\n"
  },
  {
    "path": "fastapi/dependencies/__init__.py",
    "content": ""
  },
  {
    "path": "fastapi/dependencies/models.py",
    "content": "import inspect\nimport sys\nfrom collections.abc import Callable\nfrom dataclasses import dataclass, field\nfrom functools import cached_property, partial\nfrom typing import Any, Literal\n\nfrom fastapi._compat import ModelField\nfrom fastapi.security.base import SecurityBase\nfrom fastapi.types import DependencyCacheKey\n\nif sys.version_info >= (3, 13):  # pragma: no cover\n    from inspect import iscoroutinefunction\nelse:  # pragma: no cover\n    from asyncio import iscoroutinefunction\n\n\ndef _unwrapped_call(call: Callable[..., Any] | None) -> Any:\n    if call is None:\n        return call  # pragma: no cover\n    unwrapped = inspect.unwrap(_impartial(call))\n    return unwrapped\n\n\ndef _impartial(func: Callable[..., Any]) -> Callable[..., Any]:\n    while isinstance(func, partial):\n        func = func.func\n    return func\n\n\n@dataclass\nclass Dependant:\n    path_params: list[ModelField] = field(default_factory=list)\n    query_params: list[ModelField] = field(default_factory=list)\n    header_params: list[ModelField] = field(default_factory=list)\n    cookie_params: list[ModelField] = field(default_factory=list)\n    body_params: list[ModelField] = field(default_factory=list)\n    dependencies: list[\"Dependant\"] = field(default_factory=list)\n    name: str | None = None\n    call: Callable[..., Any] | None = None\n    request_param_name: str | None = None\n    websocket_param_name: str | None = None\n    http_connection_param_name: str | None = None\n    response_param_name: str | None = None\n    background_tasks_param_name: str | None = None\n    security_scopes_param_name: str | None = None\n    own_oauth_scopes: list[str] | None = None\n    parent_oauth_scopes: list[str] | None = None\n    use_cache: bool = True\n    path: str | None = None\n    scope: Literal[\"function\", \"request\"] | None = None\n\n    @cached_property\n    def oauth_scopes(self) -> list[str]:\n        scopes = self.parent_oauth_scopes.copy() if self.parent_oauth_scopes else []\n        # This doesn't use a set to preserve order, just in case\n        for scope in self.own_oauth_scopes or []:\n            if scope not in scopes:\n                scopes.append(scope)\n        return scopes\n\n    @cached_property\n    def cache_key(self) -> DependencyCacheKey:\n        scopes_for_cache = (\n            tuple(sorted(set(self.oauth_scopes or []))) if self._uses_scopes else ()\n        )\n        return (\n            self.call,\n            scopes_for_cache,\n            self.computed_scope or \"\",\n        )\n\n    @cached_property\n    def _uses_scopes(self) -> bool:\n        if self.own_oauth_scopes:\n            return True\n        if self.security_scopes_param_name is not None:\n            return True\n        if self._is_security_scheme:\n            return True\n        for sub_dep in self.dependencies:\n            if sub_dep._uses_scopes:\n                return True\n        return False\n\n    @cached_property\n    def _is_security_scheme(self) -> bool:\n        if self.call is None:\n            return False  # pragma: no cover\n        unwrapped = _unwrapped_call(self.call)\n        return isinstance(unwrapped, SecurityBase)\n\n    # Mainly to get the type of SecurityBase, but it's the same self.call\n    @cached_property\n    def _security_scheme(self) -> SecurityBase:\n        unwrapped = _unwrapped_call(self.call)\n        assert isinstance(unwrapped, SecurityBase)\n        return unwrapped\n\n    @cached_property\n    def _security_dependencies(self) -> list[\"Dependant\"]:\n        security_deps = [dep for dep in self.dependencies if dep._is_security_scheme]\n        return security_deps\n\n    @cached_property\n    def is_gen_callable(self) -> bool:\n        if self.call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(self.call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(self.call)):\n            return True\n        if inspect.isclass(_unwrapped_call(self.call)):\n            return False\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_unwrapped_call is None:\n            return False  # pragma: no cover\n        if inspect.isgeneratorfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isgeneratorfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False\n\n    @cached_property\n    def is_async_gen_callable(self) -> bool:\n        if self.call is None:\n            return False  # pragma: no cover\n        if inspect.isasyncgenfunction(\n            _impartial(self.call)\n        ) or inspect.isasyncgenfunction(_unwrapped_call(self.call)):\n            return True\n        if inspect.isclass(_unwrapped_call(self.call)):\n            return False\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\n        if inspect.isasyncgenfunction(\n            _impartial(dunder_call)\n        ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_call)):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_unwrapped_call is None:\n            return False  # pragma: no cover\n        if inspect.isasyncgenfunction(\n            _impartial(dunder_unwrapped_call)\n        ) or inspect.isasyncgenfunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False\n\n    @cached_property\n    def is_coroutine_callable(self) -> bool:\n        if self.call is None:\n            return False  # pragma: no cover\n        if inspect.isroutine(_impartial(self.call)) and iscoroutinefunction(\n            _impartial(self.call)\n        ):\n            return True\n        if inspect.isroutine(_unwrapped_call(self.call)) and iscoroutinefunction(\n            _unwrapped_call(self.call)\n        ):\n            return True\n        if inspect.isclass(_unwrapped_call(self.call)):\n            return False\n        dunder_call = getattr(_impartial(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_call is None:\n            return False  # pragma: no cover\n        if iscoroutinefunction(_impartial(dunder_call)) or iscoroutinefunction(\n            _unwrapped_call(dunder_call)\n        ):\n            return True\n        dunder_unwrapped_call = getattr(_unwrapped_call(self.call), \"__call__\", None)  # noqa: B004\n        if dunder_unwrapped_call is None:\n            return False  # pragma: no cover\n        if iscoroutinefunction(\n            _impartial(dunder_unwrapped_call)\n        ) or iscoroutinefunction(_unwrapped_call(dunder_unwrapped_call)):\n            return True\n        return False\n\n    @cached_property\n    def computed_scope(self) -> str | None:\n        if self.scope:\n            return self.scope\n        if self.is_gen_callable or self.is_async_gen_callable:\n            return \"request\"\n        return None\n"
  },
  {
    "path": "fastapi/dependencies/utils.py",
    "content": "import dataclasses\nimport inspect\nimport sys\nfrom collections.abc import (\n    AsyncGenerator,\n    AsyncIterable,\n    AsyncIterator,\n    Callable,\n    Generator,\n    Iterable,\n    Iterator,\n    Mapping,\n    Sequence,\n)\nfrom contextlib import AsyncExitStack, contextmanager\nfrom copy import copy, deepcopy\nfrom dataclasses import dataclass\nfrom typing import (\n    Annotated,\n    Any,\n    ForwardRef,\n    Literal,\n    Union,\n    cast,\n    get_args,\n    get_origin,\n)\n\nfrom fastapi import params\nfrom fastapi._compat import (\n    ModelField,\n    RequiredParam,\n    Undefined,\n    copy_field_info,\n    create_body_model,\n    evaluate_forwardref,\n    field_annotation_is_scalar,\n    field_annotation_is_scalar_sequence,\n    field_annotation_is_sequence,\n    get_cached_model_fields,\n    get_missing_field_error,\n    is_bytes_or_nonable_bytes_annotation,\n    is_bytes_sequence_annotation,\n    is_scalar_field,\n    is_uploadfile_or_nonable_uploadfile_annotation,\n    is_uploadfile_sequence_annotation,\n    lenient_issubclass,\n    sequence_types,\n    serialize_sequence_value,\n    value_is_sequence,\n)\nfrom fastapi.background import BackgroundTasks\nfrom fastapi.concurrency import (\n    asynccontextmanager,\n    contextmanager_in_threadpool,\n)\nfrom fastapi.dependencies.models import Dependant\nfrom fastapi.exceptions import DependencyScopeError\nfrom fastapi.logger import logger\nfrom fastapi.security.oauth2 import SecurityScopes\nfrom fastapi.types import DependencyCacheKey\nfrom fastapi.utils import create_model_field, get_path_param_names\nfrom pydantic import BaseModel, Json\nfrom pydantic.fields import FieldInfo\nfrom starlette.background import BackgroundTasks as StarletteBackgroundTasks\nfrom starlette.concurrency import run_in_threadpool\nfrom starlette.datastructures import (\n    FormData,\n    Headers,\n    ImmutableMultiDict,\n    QueryParams,\n    UploadFile,\n)\nfrom starlette.requests import HTTPConnection, Request\nfrom starlette.responses import Response\nfrom starlette.websockets import WebSocket\nfrom typing_inspection.typing_objects import is_typealiastype\n\nmultipart_not_installed_error = (\n    'Form data requires \"python-multipart\" to be installed. \\n'\n    'You can install \"python-multipart\" with: \\n\\n'\n    \"pip install python-multipart\\n\"\n)\nmultipart_incorrect_install_error = (\n    'Form data requires \"python-multipart\" to be installed. '\n    'It seems you installed \"multipart\" instead. \\n'\n    'You can remove \"multipart\" with: \\n\\n'\n    \"pip uninstall multipart\\n\\n\"\n    'And then install \"python-multipart\" with: \\n\\n'\n    \"pip install python-multipart\\n\"\n)\n\n\ndef ensure_multipart_is_installed() -> None:\n    try:\n        from python_multipart import __version__\n\n        # Import an attribute that can be mocked/deleted in testing\n        assert __version__ > \"0.0.12\"\n    except (ImportError, AssertionError):\n        try:\n            # __version__ is available in both multiparts, and can be mocked\n            from multipart import (  # type: ignore[no-redef,import-untyped]\n                __version__,\n            )\n\n            assert __version__\n            try:\n                # parse_options_header is only available in the right multipart\n                from multipart.multipart import (  # type: ignore[import-untyped]\n                    parse_options_header,\n                )\n\n                assert parse_options_header\n            except ImportError:\n                logger.error(multipart_incorrect_install_error)\n                raise RuntimeError(multipart_incorrect_install_error) from None\n        except ImportError:\n            logger.error(multipart_not_installed_error)\n            raise RuntimeError(multipart_not_installed_error) from None\n\n\ndef get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> Dependant:\n    assert callable(depends.dependency), (\n        \"A parameter-less dependency must have a callable dependency\"\n    )\n    own_oauth_scopes: list[str] = []\n    if isinstance(depends, params.Security) and depends.scopes:\n        own_oauth_scopes.extend(depends.scopes)\n    return get_dependant(\n        path=path,\n        call=depends.dependency,\n        scope=depends.scope,\n        own_oauth_scopes=own_oauth_scopes,\n    )\n\n\ndef get_flat_dependant(\n    dependant: Dependant,\n    *,\n    skip_repeats: bool = False,\n    visited: list[DependencyCacheKey] | None = None,\n    parent_oauth_scopes: list[str] | None = None,\n) -> Dependant:\n    if visited is None:\n        visited = []\n    visited.append(dependant.cache_key)\n    use_parent_oauth_scopes = (parent_oauth_scopes or []) + (\n        dependant.oauth_scopes or []\n    )\n\n    flat_dependant = Dependant(\n        path_params=dependant.path_params.copy(),\n        query_params=dependant.query_params.copy(),\n        header_params=dependant.header_params.copy(),\n        cookie_params=dependant.cookie_params.copy(),\n        body_params=dependant.body_params.copy(),\n        name=dependant.name,\n        call=dependant.call,\n        request_param_name=dependant.request_param_name,\n        websocket_param_name=dependant.websocket_param_name,\n        http_connection_param_name=dependant.http_connection_param_name,\n        response_param_name=dependant.response_param_name,\n        background_tasks_param_name=dependant.background_tasks_param_name,\n        security_scopes_param_name=dependant.security_scopes_param_name,\n        own_oauth_scopes=dependant.own_oauth_scopes,\n        parent_oauth_scopes=use_parent_oauth_scopes,\n        use_cache=dependant.use_cache,\n        path=dependant.path,\n        scope=dependant.scope,\n    )\n    for sub_dependant in dependant.dependencies:\n        if skip_repeats and sub_dependant.cache_key in visited:\n            continue\n        flat_sub = get_flat_dependant(\n            sub_dependant,\n            skip_repeats=skip_repeats,\n            visited=visited,\n            parent_oauth_scopes=flat_dependant.oauth_scopes,\n        )\n        flat_dependant.dependencies.append(flat_sub)\n        flat_dependant.path_params.extend(flat_sub.path_params)\n        flat_dependant.query_params.extend(flat_sub.query_params)\n        flat_dependant.header_params.extend(flat_sub.header_params)\n        flat_dependant.cookie_params.extend(flat_sub.cookie_params)\n        flat_dependant.body_params.extend(flat_sub.body_params)\n        flat_dependant.dependencies.extend(flat_sub.dependencies)\n\n    return flat_dependant\n\n\ndef _get_flat_fields_from_params(fields: list[ModelField]) -> list[ModelField]:\n    if not fields:\n        return fields\n    first_field = fields[0]\n    if len(fields) == 1 and lenient_issubclass(\n        first_field.field_info.annotation, BaseModel\n    ):\n        fields_to_extract = get_cached_model_fields(first_field.field_info.annotation)\n        return fields_to_extract\n    return fields\n\n\ndef get_flat_params(dependant: Dependant) -> list[ModelField]:\n    flat_dependant = get_flat_dependant(dependant, skip_repeats=True)\n    path_params = _get_flat_fields_from_params(flat_dependant.path_params)\n    query_params = _get_flat_fields_from_params(flat_dependant.query_params)\n    header_params = _get_flat_fields_from_params(flat_dependant.header_params)\n    cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)\n    return path_params + query_params + header_params + cookie_params\n\n\ndef _get_signature(call: Callable[..., Any]) -> inspect.Signature:\n    try:\n        signature = inspect.signature(call, eval_str=True)\n    except NameError:\n        # Handle type annotations with if TYPE_CHECKING, not used by FastAPI\n        # e.g. dependency return types\n        if sys.version_info >= (3, 14):\n            from annotationlib import Format\n\n            signature = inspect.signature(call, annotation_format=Format.FORWARDREF)\n        else:\n            signature = inspect.signature(call)\n    return signature\n\n\ndef get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:\n    signature = _get_signature(call)\n    unwrapped = inspect.unwrap(call)\n    globalns = getattr(unwrapped, \"__globals__\", {})\n    typed_params = [\n        inspect.Parameter(\n            name=param.name,\n            kind=param.kind,\n            default=param.default,\n            annotation=get_typed_annotation(param.annotation, globalns),\n        )\n        for param in signature.parameters.values()\n    ]\n    typed_signature = inspect.Signature(typed_params)\n    return typed_signature\n\n\ndef get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any:\n    if isinstance(annotation, str):\n        annotation = ForwardRef(annotation)\n        annotation = evaluate_forwardref(annotation, globalns, globalns)\n        if annotation is type(None):\n            return None\n    return annotation\n\n\ndef get_typed_return_annotation(call: Callable[..., Any]) -> Any:\n    signature = _get_signature(call)\n    unwrapped = inspect.unwrap(call)\n    annotation = signature.return_annotation\n\n    if annotation is inspect.Signature.empty:\n        return None\n\n    globalns = getattr(unwrapped, \"__globals__\", {})\n    return get_typed_annotation(annotation, globalns)\n\n\n_STREAM_ORIGINS = {\n    AsyncIterable,\n    AsyncIterator,\n    AsyncGenerator,\n    Iterable,\n    Iterator,\n    Generator,\n}\n\n\ndef get_stream_item_type(annotation: Any) -> Any | None:\n    origin = get_origin(annotation)\n    if origin is not None and origin in _STREAM_ORIGINS:\n        type_args = get_args(annotation)\n        if type_args:\n            return type_args[0]\n        return Any\n    return None\n\n\ndef get_dependant(\n    *,\n    path: str,\n    call: Callable[..., Any],\n    name: str | None = None,\n    own_oauth_scopes: list[str] | None = None,\n    parent_oauth_scopes: list[str] | None = None,\n    use_cache: bool = True,\n    scope: Literal[\"function\", \"request\"] | None = None,\n) -> Dependant:\n    dependant = Dependant(\n        call=call,\n        name=name,\n        path=path,\n        use_cache=use_cache,\n        scope=scope,\n        own_oauth_scopes=own_oauth_scopes,\n        parent_oauth_scopes=parent_oauth_scopes,\n    )\n    current_scopes = (parent_oauth_scopes or []) + (own_oauth_scopes or [])\n    path_param_names = get_path_param_names(path)\n    endpoint_signature = get_typed_signature(call)\n    signature_params = endpoint_signature.parameters\n    for param_name, param in signature_params.items():\n        is_path_param = param_name in path_param_names\n        param_details = analyze_param(\n            param_name=param_name,\n            annotation=param.annotation,\n            value=param.default,\n            is_path_param=is_path_param,\n        )\n        if param_details.depends is not None:\n            assert param_details.depends.dependency\n            if (\n                (dependant.is_gen_callable or dependant.is_async_gen_callable)\n                and dependant.computed_scope == \"request\"\n                and param_details.depends.scope == \"function\"\n            ):\n                assert dependant.call\n                call_name = getattr(dependant.call, \"__name__\", \"<unnamed_callable>\")\n                raise DependencyScopeError(\n                    f'The dependency \"{call_name}\" has a scope of '\n                    '\"request\", it cannot depend on dependencies with scope \"function\".'\n                )\n            sub_own_oauth_scopes: list[str] = []\n            if isinstance(param_details.depends, params.Security):\n                if param_details.depends.scopes:\n                    sub_own_oauth_scopes = list(param_details.depends.scopes)\n            sub_dependant = get_dependant(\n                path=path,\n                call=param_details.depends.dependency,\n                name=param_name,\n                own_oauth_scopes=sub_own_oauth_scopes,\n                parent_oauth_scopes=current_scopes,\n                use_cache=param_details.depends.use_cache,\n                scope=param_details.depends.scope,\n            )\n            dependant.dependencies.append(sub_dependant)\n            continue\n        if add_non_field_param_to_dependency(\n            param_name=param_name,\n            type_annotation=param_details.type_annotation,\n            dependant=dependant,\n        ):\n            assert param_details.field is None, (\n                f\"Cannot specify multiple FastAPI annotations for {param_name!r}\"\n            )\n            continue\n        assert param_details.field is not None\n        if isinstance(param_details.field.field_info, params.Body):\n            dependant.body_params.append(param_details.field)\n        else:\n            add_param_to_fields(field=param_details.field, dependant=dependant)\n    return dependant\n\n\ndef add_non_field_param_to_dependency(\n    *, param_name: str, type_annotation: Any, dependant: Dependant\n) -> bool | None:\n    if lenient_issubclass(type_annotation, Request):\n        dependant.request_param_name = param_name\n        return True\n    elif lenient_issubclass(type_annotation, WebSocket):\n        dependant.websocket_param_name = param_name\n        return True\n    elif lenient_issubclass(type_annotation, HTTPConnection):\n        dependant.http_connection_param_name = param_name\n        return True\n    elif lenient_issubclass(type_annotation, Response):\n        dependant.response_param_name = param_name\n        return True\n    elif lenient_issubclass(type_annotation, StarletteBackgroundTasks):\n        dependant.background_tasks_param_name = param_name\n        return True\n    elif lenient_issubclass(type_annotation, SecurityScopes):\n        dependant.security_scopes_param_name = param_name\n        return True\n    return None\n\n\n@dataclass\nclass ParamDetails:\n    type_annotation: Any\n    depends: params.Depends | None\n    field: ModelField | None\n\n\ndef analyze_param(\n    *,\n    param_name: str,\n    annotation: Any,\n    value: Any,\n    is_path_param: bool,\n) -> ParamDetails:\n    field_info = None\n    depends = None\n    type_annotation: Any = Any\n    use_annotation: Any = Any\n    if is_typealiastype(annotation):\n        # unpack in case PEP 695 type syntax is used\n        annotation = annotation.__value__\n    if annotation is not inspect.Signature.empty:\n        use_annotation = annotation\n        type_annotation = annotation\n    # Extract Annotated info\n    if get_origin(use_annotation) is Annotated:\n        annotated_args = get_args(annotation)\n        type_annotation = annotated_args[0]\n        fastapi_annotations = [\n            arg\n            for arg in annotated_args[1:]\n            if isinstance(arg, (FieldInfo, params.Depends))\n        ]\n        fastapi_specific_annotations = [\n            arg\n            for arg in fastapi_annotations\n            if isinstance(\n                arg,\n                (\n                    params.Param,\n                    params.Body,\n                    params.Depends,\n                ),\n            )\n        ]\n        if fastapi_specific_annotations:\n            fastapi_annotation: FieldInfo | params.Depends | None = (\n                fastapi_specific_annotations[-1]\n            )\n        else:\n            fastapi_annotation = None\n        # Set default for Annotated FieldInfo\n        if isinstance(fastapi_annotation, FieldInfo):\n            # Copy `field_info` because we mutate `field_info.default` below.\n            field_info = copy_field_info(\n                field_info=fastapi_annotation,\n                annotation=use_annotation,\n            )\n            assert (\n                field_info.default == Undefined or field_info.default == RequiredParam\n            ), (\n                f\"`{field_info.__class__.__name__}` default value cannot be set in\"\n                f\" `Annotated` for {param_name!r}. Set the default value with `=` instead.\"\n            )\n            if value is not inspect.Signature.empty:\n                assert not is_path_param, \"Path parameters cannot have default values\"\n                field_info.default = value\n            else:\n                field_info.default = RequiredParam\n        # Get Annotated Depends\n        elif isinstance(fastapi_annotation, params.Depends):\n            depends = fastapi_annotation\n    # Get Depends from default value\n    if isinstance(value, params.Depends):\n        assert depends is None, (\n            \"Cannot specify `Depends` in `Annotated` and default value\"\n            f\" together for {param_name!r}\"\n        )\n        assert field_info is None, (\n            \"Cannot specify a FastAPI annotation in `Annotated` and `Depends` as a\"\n            f\" default value together for {param_name!r}\"\n        )\n        depends = value\n    # Get FieldInfo from default value\n    elif isinstance(value, FieldInfo):\n        assert field_info is None, (\n            \"Cannot specify FastAPI annotations in `Annotated` and default value\"\n            f\" together for {param_name!r}\"\n        )\n        field_info = value\n        if isinstance(field_info, FieldInfo):\n            field_info.annotation = type_annotation\n\n    # Get Depends from type annotation\n    if depends is not None and depends.dependency is None:\n        # Copy `depends` before mutating it\n        depends = copy(depends)\n        depends = dataclasses.replace(depends, dependency=type_annotation)\n\n    # Handle non-param type annotations like Request\n    # Only apply special handling when there's no explicit Depends - if there's a Depends,\n    # the dependency will be called and its return value used instead of the special injection\n    if depends is None and lenient_issubclass(\n        type_annotation,\n        (\n            Request,\n            WebSocket,\n            HTTPConnection,\n            Response,\n            StarletteBackgroundTasks,\n            SecurityScopes,\n        ),\n    ):\n        assert field_info is None, (\n            f\"Cannot specify FastAPI annotation for type {type_annotation!r}\"\n        )\n    # Handle default assignations, neither field_info nor depends was not found in Annotated nor default value\n    elif field_info is None and depends is None:\n        default_value = value if value is not inspect.Signature.empty else RequiredParam\n        if is_path_param:\n            # We might check here that `default_value is RequiredParam`, but the fact is that the same\n            # parameter might sometimes be a path parameter and sometimes not. See\n            # `tests/test_infer_param_optionality.py` for an example.\n            field_info = params.Path(annotation=use_annotation)\n        elif is_uploadfile_or_nonable_uploadfile_annotation(\n            type_annotation\n        ) or is_uploadfile_sequence_annotation(type_annotation):\n            field_info = params.File(annotation=use_annotation, default=default_value)\n        elif not field_annotation_is_scalar(annotation=type_annotation):\n            field_info = params.Body(annotation=use_annotation, default=default_value)\n        else:\n            field_info = params.Query(annotation=use_annotation, default=default_value)\n\n    field = None\n    # It's a field_info, not a dependency\n    if field_info is not None:\n        # Handle field_info.in_\n        if is_path_param:\n            assert isinstance(field_info, params.Path), (\n                f\"Cannot use `{field_info.__class__.__name__}` for path param\"\n                f\" {param_name!r}\"\n            )\n        elif (\n            isinstance(field_info, params.Param)\n            and getattr(field_info, \"in_\", None) is None\n        ):\n            field_info.in_ = params.ParamTypes.query\n        use_annotation_from_field_info = use_annotation\n        if isinstance(field_info, params.Form):\n            ensure_multipart_is_installed()\n        if not field_info.alias and getattr(field_info, \"convert_underscores\", None):\n            alias = param_name.replace(\"_\", \"-\")\n        else:\n            alias = field_info.alias or param_name\n        field_info.alias = alias\n        field = create_model_field(\n            name=param_name,\n            type_=use_annotation_from_field_info,\n            default=field_info.default,\n            alias=alias,\n            field_info=field_info,\n        )\n        if is_path_param:\n            assert is_scalar_field(field=field), (\n                \"Path params must be of one of the supported types\"\n            )\n        elif isinstance(field_info, params.Query):\n            assert (\n                is_scalar_field(field)\n                or field_annotation_is_scalar_sequence(field.field_info.annotation)\n                or lenient_issubclass(field.field_info.annotation, BaseModel)\n            ), f\"Query parameter {param_name!r} must be one of the supported types\"\n\n    return ParamDetails(type_annotation=type_annotation, depends=depends, field=field)\n\n\ndef add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:\n    field_info = field.field_info\n    field_info_in = getattr(field_info, \"in_\", None)\n    if field_info_in == params.ParamTypes.path:\n        dependant.path_params.append(field)\n    elif field_info_in == params.ParamTypes.query:\n        dependant.query_params.append(field)\n    elif field_info_in == params.ParamTypes.header:\n        dependant.header_params.append(field)\n    else:\n        assert field_info_in == params.ParamTypes.cookie, (\n            f\"non-body parameters must be in path, query, header or cookie: {field.name}\"\n        )\n        dependant.cookie_params.append(field)\n\n\nasync def _solve_generator(\n    *, dependant: Dependant, stack: AsyncExitStack, sub_values: dict[str, Any]\n) -> Any:\n    assert dependant.call\n    if dependant.is_async_gen_callable:\n        cm = asynccontextmanager(dependant.call)(**sub_values)\n    elif dependant.is_gen_callable:\n        cm = contextmanager_in_threadpool(contextmanager(dependant.call)(**sub_values))\n    return await stack.enter_async_context(cm)\n\n\n@dataclass\nclass SolvedDependency:\n    values: dict[str, Any]\n    errors: list[Any]\n    background_tasks: StarletteBackgroundTasks | None\n    response: Response\n    dependency_cache: dict[DependencyCacheKey, Any]\n\n\nasync def solve_dependencies(\n    *,\n    request: Request | WebSocket,\n    dependant: Dependant,\n    body: dict[str, Any] | FormData | bytes | None = None,\n    background_tasks: StarletteBackgroundTasks | None = None,\n    response: Response | None = None,\n    dependency_overrides_provider: Any | None = None,\n    dependency_cache: dict[DependencyCacheKey, Any] | None = None,\n    # TODO: remove this parameter later, no longer used, not removing it yet as some\n    # people might be monkey patching this function (although that's not supported)\n    async_exit_stack: AsyncExitStack,\n    embed_body_fields: bool,\n) -> SolvedDependency:\n    request_astack = request.scope.get(\"fastapi_inner_astack\")\n    assert isinstance(request_astack, AsyncExitStack), (\n        \"fastapi_inner_astack not found in request scope\"\n    )\n    function_astack = request.scope.get(\"fastapi_function_astack\")\n    assert isinstance(function_astack, AsyncExitStack), (\n        \"fastapi_function_astack not found in request scope\"\n    )\n    values: dict[str, Any] = {}\n    errors: list[Any] = []\n    if response is None:\n        response = Response()\n        del response.headers[\"content-length\"]\n        response.status_code = None  # type: ignore\n    if dependency_cache is None:\n        dependency_cache = {}\n    for sub_dependant in dependant.dependencies:\n        sub_dependant.call = cast(Callable[..., Any], sub_dependant.call)\n        call = sub_dependant.call\n        use_sub_dependant = sub_dependant\n        if (\n            dependency_overrides_provider\n            and dependency_overrides_provider.dependency_overrides\n        ):\n            original_call = sub_dependant.call\n            call = getattr(\n                dependency_overrides_provider, \"dependency_overrides\", {}\n            ).get(original_call, original_call)\n            use_path: str = sub_dependant.path  # type: ignore\n            use_sub_dependant = get_dependant(\n                path=use_path,\n                call=call,\n                name=sub_dependant.name,\n                parent_oauth_scopes=sub_dependant.oauth_scopes,\n                scope=sub_dependant.scope,\n            )\n\n        solved_result = await solve_dependencies(\n            request=request,\n            dependant=use_sub_dependant,\n            body=body,\n            background_tasks=background_tasks,\n            response=response,\n            dependency_overrides_provider=dependency_overrides_provider,\n            dependency_cache=dependency_cache,\n            async_exit_stack=async_exit_stack,\n            embed_body_fields=embed_body_fields,\n        )\n        background_tasks = solved_result.background_tasks\n        if solved_result.errors:\n            errors.extend(solved_result.errors)\n            continue\n        if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:\n            solved = dependency_cache[sub_dependant.cache_key]\n        elif (\n            use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable\n        ):\n            use_astack = request_astack\n            if sub_dependant.scope == \"function\":\n                use_astack = function_astack\n            solved = await _solve_generator(\n                dependant=use_sub_dependant,\n                stack=use_astack,\n                sub_values=solved_result.values,\n            )\n        elif use_sub_dependant.is_coroutine_callable:\n            solved = await call(**solved_result.values)\n        else:\n            solved = await run_in_threadpool(call, **solved_result.values)\n        if sub_dependant.name is not None:\n            values[sub_dependant.name] = solved\n        if sub_dependant.cache_key not in dependency_cache:\n            dependency_cache[sub_dependant.cache_key] = solved\n    path_values, path_errors = request_params_to_args(\n        dependant.path_params, request.path_params\n    )\n    query_values, query_errors = request_params_to_args(\n        dependant.query_params, request.query_params\n    )\n    header_values, header_errors = request_params_to_args(\n        dependant.header_params, request.headers\n    )\n    cookie_values, cookie_errors = request_params_to_args(\n        dependant.cookie_params, request.cookies\n    )\n    values.update(path_values)\n    values.update(query_values)\n    values.update(header_values)\n    values.update(cookie_values)\n    errors += path_errors + query_errors + header_errors + cookie_errors\n    if dependant.body_params:\n        (\n            body_values,\n            body_errors,\n        ) = await request_body_to_args(  # body_params checked above\n            body_fields=dependant.body_params,\n            received_body=body,\n            embed_body_fields=embed_body_fields,\n        )\n        values.update(body_values)\n        errors.extend(body_errors)\n    if dependant.http_connection_param_name:\n        values[dependant.http_connection_param_name] = request\n    if dependant.request_param_name and isinstance(request, Request):\n        values[dependant.request_param_name] = request\n    elif dependant.websocket_param_name and isinstance(request, WebSocket):\n        values[dependant.websocket_param_name] = request\n    if dependant.background_tasks_param_name:\n        if background_tasks is None:\n            background_tasks = BackgroundTasks()\n        values[dependant.background_tasks_param_name] = background_tasks\n    if dependant.response_param_name:\n        values[dependant.response_param_name] = response\n    if dependant.security_scopes_param_name:\n        values[dependant.security_scopes_param_name] = SecurityScopes(\n            scopes=dependant.oauth_scopes\n        )\n    return SolvedDependency(\n        values=values,\n        errors=errors,\n        background_tasks=background_tasks,\n        response=response,\n        dependency_cache=dependency_cache,\n    )\n\n\ndef _validate_value_with_model_field(\n    *, field: ModelField, value: Any, values: dict[str, Any], loc: tuple[str, ...]\n) -> tuple[Any, list[Any]]:\n    if value is None:\n        if field.field_info.is_required():\n            return None, [get_missing_field_error(loc=loc)]\n        else:\n            return deepcopy(field.default), []\n    return field.validate(value, values, loc=loc)\n\n\ndef _is_json_field(field: ModelField) -> bool:\n    return any(type(item) is Json for item in field.field_info.metadata)\n\n\ndef _get_multidict_value(\n    field: ModelField, values: Mapping[str, Any], alias: str | None = None\n) -> Any:\n    alias = alias or get_validation_alias(field)\n    if (\n        (not _is_json_field(field))\n        and field_annotation_is_sequence(field.field_info.annotation)\n        and isinstance(values, (ImmutableMultiDict, Headers))\n    ):\n        value = values.getlist(alias)\n    else:\n        value = values.get(alias, None)\n    if (\n        value is None\n        or (\n            isinstance(field.field_info, params.Form)\n            and isinstance(value, str)  # For type checks\n            and value == \"\"\n        )\n        or (\n            field_annotation_is_sequence(field.field_info.annotation)\n            and len(value) == 0\n        )\n    ):\n        if field.field_info.is_required():\n            return\n        else:\n            return deepcopy(field.default)\n    return value\n\n\ndef request_params_to_args(\n    fields: Sequence[ModelField],\n    received_params: Mapping[str, Any] | QueryParams | Headers,\n) -> tuple[dict[str, Any], list[Any]]:\n    values: dict[str, Any] = {}\n    errors: list[dict[str, Any]] = []\n\n    if not fields:\n        return values, errors\n\n    first_field = fields[0]\n    fields_to_extract = fields\n    single_not_embedded_field = False\n    default_convert_underscores = True\n    if len(fields) == 1 and lenient_issubclass(\n        first_field.field_info.annotation, BaseModel\n    ):\n        fields_to_extract = get_cached_model_fields(first_field.field_info.annotation)\n        single_not_embedded_field = True\n        # If headers are in a Pydantic model, the way to disable convert_underscores\n        # would be with Header(convert_underscores=False) at the Pydantic model level\n        default_convert_underscores = getattr(\n            first_field.field_info, \"convert_underscores\", True\n        )\n\n    params_to_process: dict[str, Any] = {}\n\n    processed_keys = set()\n\n    for field in fields_to_extract:\n        alias = None\n        if isinstance(received_params, Headers):\n            # Handle fields extracted from a Pydantic Model for a header, each field\n            # doesn't have a FieldInfo of type Header with the default convert_underscores=True\n            convert_underscores = getattr(\n                field.field_info, \"convert_underscores\", default_convert_underscores\n            )\n            if convert_underscores:\n                alias = get_validation_alias(field)\n                if alias == field.name:\n                    alias = alias.replace(\"_\", \"-\")\n        value = _get_multidict_value(field, received_params, alias=alias)\n        if value is not None:\n            params_to_process[get_validation_alias(field)] = value\n        processed_keys.add(alias or get_validation_alias(field))\n\n    for key in received_params.keys():\n        if key not in processed_keys:\n            if isinstance(received_params, (ImmutableMultiDict, Headers)):\n                value = received_params.getlist(key)\n                if isinstance(value, list) and (len(value) == 1):\n                    params_to_process[key] = value[0]\n                else:\n                    params_to_process[key] = value\n            else:\n                params_to_process[key] = received_params.get(key)\n\n    if single_not_embedded_field:\n        field_info = first_field.field_info\n        assert isinstance(field_info, params.Param), (\n            \"Params must be subclasses of Param\"\n        )\n        loc: tuple[str, ...] = (field_info.in_.value,)\n        v_, errors_ = _validate_value_with_model_field(\n            field=first_field, value=params_to_process, values=values, loc=loc\n        )\n        return {first_field.name: v_}, errors_\n\n    for field in fields:\n        value = _get_multidict_value(field, received_params)\n        field_info = field.field_info\n        assert isinstance(field_info, params.Param), (\n            \"Params must be subclasses of Param\"\n        )\n        loc = (field_info.in_.value, get_validation_alias(field))\n        v_, errors_ = _validate_value_with_model_field(\n            field=field, value=value, values=values, loc=loc\n        )\n        if errors_:\n            errors.extend(errors_)\n        else:\n            values[field.name] = v_\n    return values, errors\n\n\ndef is_union_of_base_models(field_type: Any) -> bool:\n    \"\"\"Check if field type is a Union where all members are BaseModel subclasses.\"\"\"\n    from fastapi.types import UnionType\n\n    origin = get_origin(field_type)\n\n    # Check if it's a Union type (covers both typing.Union and types.UnionType in Python 3.10+)\n    if origin is not Union and origin is not UnionType:\n        return False\n\n    union_args = get_args(field_type)\n\n    for arg in union_args:\n        if not lenient_issubclass(arg, BaseModel):\n            return False\n\n    return True\n\n\ndef _should_embed_body_fields(fields: list[ModelField]) -> bool:\n    if not fields:\n        return False\n    # More than one dependency could have the same field, it would show up as multiple\n    # fields but it's the same one, so count them by name\n    body_param_names_set = {field.name for field in fields}\n    # A top level field has to be a single field, not multiple\n    if len(body_param_names_set) > 1:\n        return True\n    first_field = fields[0]\n    # If it explicitly specifies it is embedded, it has to be embedded\n    if getattr(first_field.field_info, \"embed\", None):\n        return True\n    # If it's a Form (or File) field, it has to be a BaseModel (or a union of BaseModels) to be top level\n    # otherwise it has to be embedded, so that the key value pair can be extracted\n    if (\n        isinstance(first_field.field_info, params.Form)\n        and not lenient_issubclass(first_field.field_info.annotation, BaseModel)\n        and not is_union_of_base_models(first_field.field_info.annotation)\n    ):\n        return True\n    return False\n\n\nasync def _extract_form_body(\n    body_fields: list[ModelField],\n    received_body: FormData,\n) -> dict[str, Any]:\n    values = {}\n\n    for field in body_fields:\n        value = _get_multidict_value(field, received_body)\n        field_info = field.field_info\n        if (\n            isinstance(field_info, params.File)\n            and is_bytes_or_nonable_bytes_annotation(field.field_info.annotation)\n            and isinstance(value, UploadFile)\n        ):\n            value = await value.read()\n        elif (\n            is_bytes_sequence_annotation(field.field_info.annotation)\n            and isinstance(field_info, params.File)\n            and value_is_sequence(value)\n        ):\n            # For types\n            assert isinstance(value, sequence_types)\n            results: list[bytes | str] = []\n            for sub_value in value:\n                results.append(await sub_value.read())\n            value = serialize_sequence_value(field=field, value=results)\n        if value is not None:\n            values[get_validation_alias(field)] = value\n    field_aliases = {get_validation_alias(field) for field in body_fields}\n    for key in received_body.keys():\n        if key not in field_aliases:\n            param_values = received_body.getlist(key)\n            if len(param_values) == 1:\n                values[key] = param_values[0]\n            else:\n                values[key] = param_values\n    return values\n\n\nasync def request_body_to_args(\n    body_fields: list[ModelField],\n    received_body: dict[str, Any] | FormData | bytes | None,\n    embed_body_fields: bool,\n) -> tuple[dict[str, Any], list[dict[str, Any]]]:\n    values: dict[str, Any] = {}\n    errors: list[dict[str, Any]] = []\n    assert body_fields, \"request_body_to_args() should be called with fields\"\n    single_not_embedded_field = len(body_fields) == 1 and not embed_body_fields\n    first_field = body_fields[0]\n    body_to_process = received_body\n\n    fields_to_extract: list[ModelField] = body_fields\n\n    if (\n        single_not_embedded_field\n        and lenient_issubclass(first_field.field_info.annotation, BaseModel)\n        and isinstance(received_body, FormData)\n    ):\n        fields_to_extract = get_cached_model_fields(first_field.field_info.annotation)\n\n    if isinstance(received_body, FormData):\n        body_to_process = await _extract_form_body(fields_to_extract, received_body)\n\n    if single_not_embedded_field:\n        loc: tuple[str, ...] = (\"body\",)\n        v_, errors_ = _validate_value_with_model_field(\n            field=first_field, value=body_to_process, values=values, loc=loc\n        )\n        return {first_field.name: v_}, errors_\n    for field in body_fields:\n        loc = (\"body\", get_validation_alias(field))\n        value: Any | None = None\n        if body_to_process is not None and not isinstance(body_to_process, bytes):\n            try:\n                value = body_to_process.get(get_validation_alias(field))\n            # If the received body is a list, not a dict\n            except AttributeError:\n                errors.append(get_missing_field_error(loc))\n                continue\n        v_, errors_ = _validate_value_with_model_field(\n            field=field, value=value, values=values, loc=loc\n        )\n        if errors_:\n            errors.extend(errors_)\n        else:\n            values[field.name] = v_\n    return values, errors\n\n\ndef get_body_field(\n    *, flat_dependant: Dependant, name: str, embed_body_fields: bool\n) -> ModelField | None:\n    \"\"\"\n    Get a ModelField representing the request body for a path operation, combining\n    all body parameters into a single field if necessary.\n\n    Used to check if it's form data (with `isinstance(body_field, params.Form)`)\n    or JSON and to generate the JSON Schema for a request body.\n\n    This is **not** used to validate/parse the request body, that's done with each\n    individual body parameter.\n    \"\"\"\n    if not flat_dependant.body_params:\n        return None\n    first_param = flat_dependant.body_params[0]\n    if not embed_body_fields:\n        return first_param\n    model_name = \"Body_\" + name\n    BodyModel = create_body_model(\n        fields=flat_dependant.body_params, model_name=model_name\n    )\n    required = any(\n        True for f in flat_dependant.body_params if f.field_info.is_required()\n    )\n    BodyFieldInfo_kwargs: dict[str, Any] = {\n        \"annotation\": BodyModel,\n        \"alias\": \"body\",\n    }\n    if not required:\n        BodyFieldInfo_kwargs[\"default\"] = None\n    if any(isinstance(f.field_info, params.File) for f in flat_dependant.body_params):\n        BodyFieldInfo: type[params.Body] = params.File\n    elif any(isinstance(f.field_info, params.Form) for f in flat_dependant.body_params):\n        BodyFieldInfo = params.Form\n    else:\n        BodyFieldInfo = params.Body\n\n        body_param_media_types = [\n            f.field_info.media_type\n            for f in flat_dependant.body_params\n            if isinstance(f.field_info, params.Body)\n        ]\n        if len(set(body_param_media_types)) == 1:\n            BodyFieldInfo_kwargs[\"media_type\"] = body_param_media_types[0]\n    final_field = create_model_field(\n        name=\"body\",\n        type_=BodyModel,\n        alias=\"body\",\n        field_info=BodyFieldInfo(**BodyFieldInfo_kwargs),\n    )\n    return final_field\n\n\ndef get_validation_alias(field: ModelField) -> str:\n    va = getattr(field, \"validation_alias\", None)\n    return va or field.alias\n"
  },
  {
    "path": "fastapi/encoders.py",
    "content": "import dataclasses\nimport datetime\nfrom collections import defaultdict, deque\nfrom collections.abc import Callable\nfrom decimal import Decimal\nfrom enum import Enum\nfrom ipaddress import (\n    IPv4Address,\n    IPv4Interface,\n    IPv4Network,\n    IPv6Address,\n    IPv6Interface,\n    IPv6Network,\n)\nfrom pathlib import Path, PurePath\nfrom re import Pattern\nfrom types import GeneratorType\nfrom typing import Annotated, Any\nfrom uuid import UUID\n\nfrom annotated_doc import Doc\nfrom fastapi.exceptions import PydanticV1NotSupportedError\nfrom fastapi.types import IncEx\nfrom pydantic import BaseModel\nfrom pydantic.networks import AnyUrl, NameEmail\nfrom pydantic.types import SecretBytes, SecretStr\nfrom pydantic_core import PydanticUndefinedType\n\nfrom ._compat import (\n    Url,\n    is_pydantic_v1_model_instance,\n)\n\ntry:\n    # pydantic.color.Color is deprecated since v2.0b3, but supporting for bwd-compat\n    from pydantic.color import Color  # ty: ignore[deprecated]\nexcept ImportError:  # pragma: no cover\n\n    class Color:  # type: ignore[no-redef]\n        pass\n\n\ntry:\n    # Supporting the new Color format for newer versions of Pydantic\n    from pydantic_extra_types.color import Color as PyExtraColor\nexcept ImportError:  # pragma: no cover\n\n    class PyExtraColor:  # type: ignore[no-redef]\n        pass\n\n\n# Taken from Pydantic v1 as is\ndef isoformat(o: datetime.date | datetime.time) -> str:\n    return o.isoformat()\n\n\n# Adapted from Pydantic v1\n# TODO: pv2 should this return strings instead?\ndef decimal_encoder(dec_value: Decimal) -> int | float:\n    \"\"\"\n    Encodes a Decimal as int if there's no exponent, otherwise float\n\n    This is useful when we use ConstrainedDecimal to represent Numeric(x,0)\n    where an integer (but not int typed) is used. Encoding this as a float\n    results in failed round-tripping between encode and parse.\n    Our Id type is a prime example of this.\n\n    >>> decimal_encoder(Decimal(\"1.0\"))\n    1.0\n\n    >>> decimal_encoder(Decimal(\"1\"))\n    1\n\n    >>> decimal_encoder(Decimal(\"NaN\"))\n    nan\n    \"\"\"\n    exponent = dec_value.as_tuple().exponent\n    if isinstance(exponent, int) and exponent >= 0:\n        return int(dec_value)\n    else:\n        return float(dec_value)\n\n\nENCODERS_BY_TYPE: dict[type[Any], Callable[[Any], Any]] = {\n    bytes: lambda o: o.decode(),\n    Color: str,\n    PyExtraColor: str,\n    datetime.date: isoformat,\n    datetime.datetime: isoformat,\n    datetime.time: isoformat,\n    datetime.timedelta: lambda td: td.total_seconds(),\n    Decimal: decimal_encoder,\n    Enum: lambda o: o.value,\n    frozenset: list,\n    deque: list,\n    GeneratorType: list,\n    IPv4Address: str,\n    IPv4Interface: str,\n    IPv4Network: str,\n    IPv6Address: str,\n    IPv6Interface: str,\n    IPv6Network: str,\n    NameEmail: str,\n    Path: str,\n    Pattern: lambda o: o.pattern,\n    SecretBytes: str,\n    SecretStr: str,\n    set: list,\n    UUID: str,\n    Url: str,\n    AnyUrl: str,\n}\n\n\ndef generate_encoders_by_class_tuples(\n    type_encoder_map: dict[Any, Callable[[Any], Any]],\n) -> dict[Callable[[Any], Any], tuple[Any, ...]]:\n    encoders_by_class_tuples: dict[Callable[[Any], Any], tuple[Any, ...]] = defaultdict(\n        tuple\n    )\n    for type_, encoder in type_encoder_map.items():\n        encoders_by_class_tuples[encoder] += (type_,)\n    return encoders_by_class_tuples\n\n\nencoders_by_class_tuples = generate_encoders_by_class_tuples(ENCODERS_BY_TYPE)\n\n\ndef jsonable_encoder(\n    obj: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            The input object to convert to JSON.\n            \"\"\"\n        ),\n    ],\n    include: Annotated[\n        IncEx | None,\n        Doc(\n            \"\"\"\n            Pydantic's `include` parameter, passed to Pydantic models to set the\n            fields to include.\n            \"\"\"\n        ),\n    ] = None,\n    exclude: Annotated[\n        IncEx | None,\n        Doc(\n            \"\"\"\n            Pydantic's `exclude` parameter, passed to Pydantic models to set the\n            fields to exclude.\n            \"\"\"\n        ),\n    ] = None,\n    by_alias: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            Pydantic's `by_alias` parameter, passed to Pydantic models to define if\n            the output should use the alias names (when provided) or the Python\n            attribute names. In an API, if you set an alias, it's probably because you\n            want to use it in the result, so you probably want to leave this set to\n            `True`.\n            \"\"\"\n        ),\n    ] = True,\n    exclude_unset: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            Pydantic's `exclude_unset` parameter, passed to Pydantic models to define\n            if it should exclude from the output the fields that were not explicitly\n            set (and that only had their default values).\n            \"\"\"\n        ),\n    ] = False,\n    exclude_defaults: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            Pydantic's `exclude_defaults` parameter, passed to Pydantic models to define\n            if it should exclude from the output the fields that had the same default\n            value, even when they were explicitly set.\n            \"\"\"\n        ),\n    ] = False,\n    exclude_none: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            Pydantic's `exclude_none` parameter, passed to Pydantic models to define\n            if it should exclude from the output any fields that have a `None` value.\n            \"\"\"\n        ),\n    ] = False,\n    custom_encoder: Annotated[\n        dict[Any, Callable[[Any], Any]] | None,\n        Doc(\n            \"\"\"\n            Pydantic's `custom_encoder` parameter, passed to Pydantic models to define\n            a custom encoder.\n            \"\"\"\n        ),\n    ] = None,\n    sqlalchemy_safe: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            Exclude from the output any fields that start with the name `_sa`.\n\n            This is mainly a hack for compatibility with SQLAlchemy objects, they\n            store internal SQLAlchemy-specific state in attributes named with `_sa`,\n            and those objects can't (and shouldn't be) serialized to JSON.\n            \"\"\"\n        ),\n    ] = True,\n) -> Any:\n    \"\"\"\n    Convert any object to something that can be encoded in JSON.\n\n    This is used internally by FastAPI to make sure anything you return can be\n    encoded as JSON before it is sent to the client.\n\n    You can also use it yourself, for example to convert objects before saving them\n    in a database that supports only JSON.\n\n    Read more about it in the\n    [FastAPI docs for JSON Compatible Encoder](https://fastapi.tiangolo.com/tutorial/encoder/).\n    \"\"\"\n    custom_encoder = custom_encoder or {}\n    if custom_encoder:\n        if type(obj) in custom_encoder:\n            return custom_encoder[type(obj)](obj)\n        else:\n            for encoder_type, encoder_instance in custom_encoder.items():\n                if isinstance(obj, encoder_type):\n                    return encoder_instance(obj)\n    if include is not None and not isinstance(include, (set, dict)):\n        include = set(include)  # type: ignore[assignment]  # ty: ignore[invalid-assignment]\n    if exclude is not None and not isinstance(exclude, (set, dict)):\n        exclude = set(exclude)  # type: ignore[assignment]  # ty: ignore[invalid-assignment]\n    if isinstance(obj, BaseModel):\n        obj_dict = obj.model_dump(\n            mode=\"json\",\n            include=include,\n            exclude=exclude,\n            by_alias=by_alias,\n            exclude_unset=exclude_unset,\n            exclude_none=exclude_none,\n            exclude_defaults=exclude_defaults,\n        )\n        return jsonable_encoder(\n            obj_dict,\n            exclude_none=exclude_none,\n            exclude_defaults=exclude_defaults,\n            sqlalchemy_safe=sqlalchemy_safe,\n        )\n    if dataclasses.is_dataclass(obj):\n        assert not isinstance(obj, type)\n        obj_dict = dataclasses.asdict(obj)\n        return jsonable_encoder(\n            obj_dict,\n            include=include,\n            exclude=exclude,\n            by_alias=by_alias,\n            exclude_unset=exclude_unset,\n            exclude_defaults=exclude_defaults,\n            exclude_none=exclude_none,\n            custom_encoder=custom_encoder,\n            sqlalchemy_safe=sqlalchemy_safe,\n        )\n    if isinstance(obj, Enum):\n        return obj.value\n    if isinstance(obj, PurePath):\n        return str(obj)\n    if isinstance(obj, (str, int, float, type(None))):\n        return obj\n    if isinstance(obj, PydanticUndefinedType):\n        return None\n    if isinstance(obj, dict):\n        encoded_dict = {}\n        allowed_keys = set(obj.keys())\n        if include is not None:\n            allowed_keys &= set(include)\n        if exclude is not None:\n            allowed_keys -= set(exclude)\n        for key, value in obj.items():\n            if (\n                (\n                    not sqlalchemy_safe\n                    or (not isinstance(key, str))\n                    or (not key.startswith(\"_sa\"))\n                )\n                and (value is not None or not exclude_none)\n                and key in allowed_keys\n            ):\n                encoded_key = jsonable_encoder(\n                    key,\n                    by_alias=by_alias,\n                    exclude_unset=exclude_unset,\n                    exclude_none=exclude_none,\n                    custom_encoder=custom_encoder,\n                    sqlalchemy_safe=sqlalchemy_safe,\n                )\n                encoded_value = jsonable_encoder(\n                    value,\n                    by_alias=by_alias,\n                    exclude_unset=exclude_unset,\n                    exclude_none=exclude_none,\n                    custom_encoder=custom_encoder,\n                    sqlalchemy_safe=sqlalchemy_safe,\n                )\n                encoded_dict[encoded_key] = encoded_value\n        return encoded_dict\n    if isinstance(obj, (list, set, frozenset, GeneratorType, tuple, deque)):\n        encoded_list = []\n        for item in obj:\n            encoded_list.append(\n                jsonable_encoder(\n                    item,\n                    include=include,\n                    exclude=exclude,\n                    by_alias=by_alias,\n                    exclude_unset=exclude_unset,\n                    exclude_defaults=exclude_defaults,\n                    exclude_none=exclude_none,\n                    custom_encoder=custom_encoder,\n                    sqlalchemy_safe=sqlalchemy_safe,\n                )\n            )\n        return encoded_list\n\n    if type(obj) in ENCODERS_BY_TYPE:\n        return ENCODERS_BY_TYPE[type(obj)](obj)\n    for encoder, classes_tuple in encoders_by_class_tuples.items():\n        if isinstance(obj, classes_tuple):\n            return encoder(obj)\n    if is_pydantic_v1_model_instance(obj):\n        raise PydanticV1NotSupportedError(\n            \"pydantic.v1 models are no longer supported by FastAPI.\"\n            f\" Please update the model {obj!r}.\"\n        )\n    try:\n        data = dict(obj)\n    except Exception as e:\n        errors: list[Exception] = []\n        errors.append(e)\n        try:\n            data = vars(obj)\n        except Exception as e:\n            errors.append(e)\n            raise ValueError(errors) from e\n    return jsonable_encoder(\n        data,\n        include=include,\n        exclude=exclude,\n        by_alias=by_alias,\n        exclude_unset=exclude_unset,\n        exclude_defaults=exclude_defaults,\n        exclude_none=exclude_none,\n        custom_encoder=custom_encoder,\n        sqlalchemy_safe=sqlalchemy_safe,\n    )\n"
  },
  {
    "path": "fastapi/exception_handlers.py",
    "content": "from fastapi.encoders import jsonable_encoder\nfrom fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError\nfrom fastapi.utils import is_body_allowed_for_status_code\nfrom fastapi.websockets import WebSocket\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.responses import JSONResponse, Response\nfrom starlette.status import WS_1008_POLICY_VIOLATION\n\n\nasync def http_exception_handler(request: Request, exc: HTTPException) -> Response:\n    headers = getattr(exc, \"headers\", None)\n    if not is_body_allowed_for_status_code(exc.status_code):\n        return Response(status_code=exc.status_code, headers=headers)\n    return JSONResponse(\n        {\"detail\": exc.detail}, status_code=exc.status_code, headers=headers\n    )\n\n\nasync def request_validation_exception_handler(\n    request: Request, exc: RequestValidationError\n) -> JSONResponse:\n    return JSONResponse(\n        status_code=422,\n        content={\"detail\": jsonable_encoder(exc.errors())},\n    )\n\n\nasync def websocket_request_validation_exception_handler(\n    websocket: WebSocket, exc: WebSocketRequestValidationError\n) -> None:\n    await websocket.close(\n        code=WS_1008_POLICY_VIOLATION, reason=jsonable_encoder(exc.errors())\n    )\n"
  },
  {
    "path": "fastapi/exceptions.py",
    "content": "from collections.abc import Mapping, Sequence\nfrom typing import Annotated, Any, TypedDict\n\nfrom annotated_doc import Doc\nfrom pydantic import BaseModel, create_model\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\nfrom starlette.exceptions import WebSocketException as StarletteWebSocketException\n\n\nclass EndpointContext(TypedDict, total=False):\n    function: str\n    path: str\n    file: str\n    line: int\n\n\nclass HTTPException(StarletteHTTPException):\n    \"\"\"\n    An HTTP exception you can raise in your own code to show errors to the client.\n\n    This is for client errors, invalid authentication, invalid data, etc. Not for server\n    errors in your code.\n\n    Read more about it in the\n    [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/).\n\n    ## Example\n\n    ```python\n    from fastapi import FastAPI, HTTPException\n\n    app = FastAPI()\n\n    items = {\"foo\": \"The Foo Wrestlers\"}\n\n\n    @app.get(\"/items/{item_id}\")\n    async def read_item(item_id: str):\n        if item_id not in items:\n            raise HTTPException(status_code=404, detail=\"Item not found\")\n        return {\"item\": items[item_id]}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        status_code: Annotated[\n            int,\n            Doc(\n                \"\"\"\n                HTTP status code to send to the client.\n\n                Read more about it in the\n                [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/#use-httpexception)\n                \"\"\"\n            ),\n        ],\n        detail: Annotated[\n            Any,\n            Doc(\n                \"\"\"\n                Any data to be sent to the client in the `detail` key of the JSON\n                response.\n\n                Read more about it in the\n                [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/#use-httpexception)\n                \"\"\"\n            ),\n        ] = None,\n        headers: Annotated[\n            Mapping[str, str] | None,\n            Doc(\n                \"\"\"\n                Any headers to send to the client in the response.\n\n                Read more about it in the\n                [FastAPI docs for Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/#add-custom-headers)\n\n                \"\"\"\n            ),\n        ] = None,\n    ) -> None:\n        super().__init__(status_code=status_code, detail=detail, headers=headers)\n\n\nclass WebSocketException(StarletteWebSocketException):\n    \"\"\"\n    A WebSocket exception you can raise in your own code to show errors to the client.\n\n    This is for client errors, invalid authentication, invalid data, etc. Not for server\n    errors in your code.\n\n    Read more about it in the\n    [FastAPI docs for WebSockets](https://fastapi.tiangolo.com/advanced/websockets/).\n\n    ## Example\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import (\n        Cookie,\n        FastAPI,\n        WebSocket,\n        WebSocketException,\n        status,\n    )\n\n    app = FastAPI()\n\n    @app.websocket(\"/items/{item_id}/ws\")\n    async def websocket_endpoint(\n        *,\n        websocket: WebSocket,\n        session: Annotated[str | None, Cookie()] = None,\n        item_id: str,\n    ):\n        if session is None:\n            raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)\n        await websocket.accept()\n        while True:\n            data = await websocket.receive_text()\n            await websocket.send_text(f\"Session cookie is: {session}\")\n            await websocket.send_text(f\"Message text was: {data}, for item ID: {item_id}\")\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        code: Annotated[\n            int,\n            Doc(\n                \"\"\"\n                A closing code from the\n                [valid codes defined in the specification](https://datatracker.ietf.org/doc/html/rfc6455#section-7.4.1).\n                \"\"\"\n            ),\n        ],\n        reason: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                The reason to close the WebSocket connection.\n\n                It is UTF-8-encoded data. The interpretation of the reason is up to the\n                application, it is not specified by the WebSocket specification.\n\n                It could contain text that could be human-readable or interpretable\n                by the client code, etc.\n                \"\"\"\n            ),\n        ] = None,\n    ) -> None:\n        super().__init__(code=code, reason=reason)\n\n\nRequestErrorModel: type[BaseModel] = create_model(\"Request\")\nWebSocketErrorModel: type[BaseModel] = create_model(\"WebSocket\")\n\n\nclass FastAPIError(RuntimeError):\n    \"\"\"\n    A generic, FastAPI-specific error.\n    \"\"\"\n\n\nclass DependencyScopeError(FastAPIError):\n    \"\"\"\n    A dependency declared that it depends on another dependency with an invalid\n    (narrower) scope.\n    \"\"\"\n\n\nclass ValidationException(Exception):\n    def __init__(\n        self,\n        errors: Sequence[Any],\n        *,\n        endpoint_ctx: EndpointContext | None = None,\n    ) -> None:\n        self._errors = errors\n        self.endpoint_ctx = endpoint_ctx\n\n        ctx = endpoint_ctx or {}\n        self.endpoint_function = ctx.get(\"function\")\n        self.endpoint_path = ctx.get(\"path\")\n        self.endpoint_file = ctx.get(\"file\")\n        self.endpoint_line = ctx.get(\"line\")\n\n    def errors(self) -> Sequence[Any]:\n        return self._errors\n\n    def _format_endpoint_context(self) -> str:\n        if not (self.endpoint_file and self.endpoint_line and self.endpoint_function):\n            if self.endpoint_path:\n                return f\"\\n  Endpoint: {self.endpoint_path}\"\n            return \"\"\n\n        context = f'\\n  File \"{self.endpoint_file}\", line {self.endpoint_line}, in {self.endpoint_function}'\n        if self.endpoint_path:\n            context += f\"\\n    {self.endpoint_path}\"\n        return context\n\n    def __str__(self) -> str:\n        message = f\"{len(self._errors)} validation error{'s' if len(self._errors) != 1 else ''}:\\n\"\n        for err in self._errors:\n            message += f\"  {err}\\n\"\n        message += self._format_endpoint_context()\n        return message.rstrip()\n\n\nclass RequestValidationError(ValidationException):\n    def __init__(\n        self,\n        errors: Sequence[Any],\n        *,\n        body: Any = None,\n        endpoint_ctx: EndpointContext | None = None,\n    ) -> None:\n        super().__init__(errors, endpoint_ctx=endpoint_ctx)\n        self.body = body\n\n\nclass WebSocketRequestValidationError(ValidationException):\n    def __init__(\n        self,\n        errors: Sequence[Any],\n        *,\n        endpoint_ctx: EndpointContext | None = None,\n    ) -> None:\n        super().__init__(errors, endpoint_ctx=endpoint_ctx)\n\n\nclass ResponseValidationError(ValidationException):\n    def __init__(\n        self,\n        errors: Sequence[Any],\n        *,\n        body: Any = None,\n        endpoint_ctx: EndpointContext | None = None,\n    ) -> None:\n        super().__init__(errors, endpoint_ctx=endpoint_ctx)\n        self.body = body\n\n\nclass PydanticV1NotSupportedError(FastAPIError):\n    \"\"\"\n    A pydantic.v1 model is used, which is no longer supported.\n    \"\"\"\n\n\nclass FastAPIDeprecationWarning(UserWarning):\n    \"\"\"\n    A custom deprecation warning as DeprecationWarning is ignored\n    Ref: https://sethmlarson.dev/deprecations-via-warnings-dont-work-for-python-libraries\n    \"\"\"\n"
  },
  {
    "path": "fastapi/logger.py",
    "content": "import logging\n\nlogger = logging.getLogger(\"fastapi\")\n"
  },
  {
    "path": "fastapi/middleware/__init__.py",
    "content": "from starlette.middleware import Middleware as Middleware\n"
  },
  {
    "path": "fastapi/middleware/asyncexitstack.py",
    "content": "from contextlib import AsyncExitStack\n\nfrom starlette.types import ASGIApp, Receive, Scope, Send\n\n\n# Used mainly to close files after the request is done, dependencies are closed\n# in their own AsyncExitStack\nclass AsyncExitStackMiddleware:\n    def __init__(\n        self, app: ASGIApp, context_name: str = \"fastapi_middleware_astack\"\n    ) -> None:\n        self.app = app\n        self.context_name = context_name\n\n    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:\n        async with AsyncExitStack() as stack:\n            scope[self.context_name] = stack\n            await self.app(scope, receive, send)\n"
  },
  {
    "path": "fastapi/middleware/cors.py",
    "content": "from starlette.middleware.cors import CORSMiddleware as CORSMiddleware  # noqa\n"
  },
  {
    "path": "fastapi/middleware/gzip.py",
    "content": "from starlette.middleware.gzip import GZipMiddleware as GZipMiddleware  # noqa\n"
  },
  {
    "path": "fastapi/middleware/httpsredirect.py",
    "content": "from starlette.middleware.httpsredirect import (  # noqa\n    HTTPSRedirectMiddleware as HTTPSRedirectMiddleware,\n)\n"
  },
  {
    "path": "fastapi/middleware/trustedhost.py",
    "content": "from starlette.middleware.trustedhost import (  # noqa\n    TrustedHostMiddleware as TrustedHostMiddleware,\n)\n"
  },
  {
    "path": "fastapi/middleware/wsgi.py",
    "content": "from starlette.middleware.wsgi import (\n    WSGIMiddleware as WSGIMiddleware,\n)  # pragma: no cover # noqa\n"
  },
  {
    "path": "fastapi/openapi/__init__.py",
    "content": ""
  },
  {
    "path": "fastapi/openapi/constants.py",
    "content": "METHODS_WITH_BODY = {\"GET\", \"HEAD\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"}\nREF_PREFIX = \"#/components/schemas/\"\nREF_TEMPLATE = \"#/components/schemas/{model}\"\n"
  },
  {
    "path": "fastapi/openapi/docs.py",
    "content": "import json\nfrom typing import Annotated, Any\n\nfrom annotated_doc import Doc\nfrom fastapi.encoders import jsonable_encoder\nfrom starlette.responses import HTMLResponse\n\n\ndef _html_safe_json(value: Any) -> str:\n    \"\"\"Serialize a value to JSON with HTML special characters escaped.\n\n    This prevents injection when the JSON is embedded inside a <script> tag.\n    \"\"\"\n    return (\n        json.dumps(value)\n        .replace(\"<\", \"\\\\u003c\")\n        .replace(\">\", \"\\\\u003e\")\n        .replace(\"&\", \"\\\\u0026\")\n    )\n\n\nswagger_ui_default_parameters: Annotated[\n    dict[str, Any],\n    Doc(\n        \"\"\"\n        Default configurations for Swagger UI.\n\n        You can use it as a template to add any other configurations needed.\n        \"\"\"\n    ),\n] = {\n    \"dom_id\": \"#swagger-ui\",\n    \"layout\": \"BaseLayout\",\n    \"deepLinking\": True,\n    \"showExtensions\": True,\n    \"showCommonExtensions\": True,\n}\n\n\ndef get_swagger_ui_html(\n    *,\n    openapi_url: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The OpenAPI URL that Swagger UI should load and use.\n\n            This is normally done automatically by FastAPI using the default URL\n            `/openapi.json`.\n\n            Read more about it in the\n            [FastAPI docs for Conditional OpenAPI](https://fastapi.tiangolo.com/how-to/conditional-openapi/#conditional-openapi-from-settings-and-env-vars)\n            \"\"\"\n        ),\n    ],\n    title: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The HTML `<title>` content, normally shown in the browser tab.\n\n            Read more about it in the\n            [FastAPI docs for Custom Docs UI Static Assets](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/)\n            \"\"\"\n        ),\n    ],\n    swagger_js_url: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The URL to use to load the Swagger UI JavaScript.\n\n            It is normally set to a CDN URL.\n\n            Read more about it in the\n            [FastAPI docs for Custom Docs UI Static Assets](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/)\n            \"\"\"\n        ),\n    ] = \"https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js\",\n    swagger_css_url: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The URL to use to load the Swagger UI CSS.\n\n            It is normally set to a CDN URL.\n\n            Read more about it in the\n            [FastAPI docs for Custom Docs UI Static Assets](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/)\n            \"\"\"\n        ),\n    ] = \"https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css\",\n    swagger_favicon_url: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The URL of the favicon to use. It is normally shown in the browser tab.\n            \"\"\"\n        ),\n    ] = \"https://fastapi.tiangolo.com/img/favicon.png\",\n    oauth2_redirect_url: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            The OAuth2 redirect URL, it is normally automatically handled by FastAPI.\n\n            Read more about it in the\n            [FastAPI docs for Custom Docs UI Static Assets](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/)\n            \"\"\"\n        ),\n    ] = None,\n    init_oauth: Annotated[\n        dict[str, Any] | None,\n        Doc(\n            \"\"\"\n            A dictionary with Swagger UI OAuth2 initialization configurations.\n\n            Read more about the available configuration options in the\n            [Swagger UI docs](https://swagger.io/docs/open-source-tools/swagger-ui/usage/oauth2/).\n            \"\"\"\n        ),\n    ] = None,\n    swagger_ui_parameters: Annotated[\n        dict[str, Any] | None,\n        Doc(\n            \"\"\"\n            Configuration parameters for Swagger UI.\n\n            It defaults to [swagger_ui_default_parameters][fastapi.openapi.docs.swagger_ui_default_parameters].\n\n            Read more about it in the\n            [FastAPI docs about how to Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/).\n            \"\"\"\n        ),\n    ] = None,\n) -> HTMLResponse:\n    \"\"\"\n    Generate and return the HTML  that loads Swagger UI for the interactive\n    API docs (normally served at `/docs`).\n\n    You would only call this function yourself if you needed to override some parts,\n    for example the URLs to use to load Swagger UI's JavaScript and CSS.\n\n    Read more about it in the\n    [FastAPI docs for Configure Swagger UI](https://fastapi.tiangolo.com/how-to/configure-swagger-ui/)\n    and the [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/).\n    \"\"\"\n    current_swagger_ui_parameters = swagger_ui_default_parameters.copy()\n    if swagger_ui_parameters:\n        current_swagger_ui_parameters.update(swagger_ui_parameters)\n\n    html = f\"\"\"\n    <!DOCTYPE html>\n    <html>\n    <head>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"{swagger_css_url}\">\n    <link rel=\"shortcut icon\" href=\"{swagger_favicon_url}\">\n    <title>{title}</title>\n    </head>\n    <body>\n    <div id=\"swagger-ui\">\n    </div>\n    <script src=\"{swagger_js_url}\"></script>\n    <!-- `SwaggerUIBundle` is now available on the page -->\n    <script>\n    const ui = SwaggerUIBundle({{\n        url: '{openapi_url}',\n    \"\"\"\n\n    for key, value in current_swagger_ui_parameters.items():\n        html += f\"{_html_safe_json(key)}: {_html_safe_json(jsonable_encoder(value))},\\n\"\n\n    if oauth2_redirect_url:\n        html += f\"oauth2RedirectUrl: window.location.origin + '{oauth2_redirect_url}',\"\n\n    html += \"\"\"\n    presets: [\n        SwaggerUIBundle.presets.apis,\n        SwaggerUIBundle.SwaggerUIStandalonePreset\n        ],\n    })\"\"\"\n\n    if init_oauth:\n        html += f\"\"\"\n        ui.initOAuth({_html_safe_json(jsonable_encoder(init_oauth))})\n        \"\"\"\n\n    html += \"\"\"\n    </script>\n    </body>\n    </html>\n    \"\"\"\n    return HTMLResponse(html)\n\n\ndef get_redoc_html(\n    *,\n    openapi_url: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The OpenAPI URL that ReDoc should load and use.\n\n            This is normally done automatically by FastAPI using the default URL\n            `/openapi.json`.\n\n            Read more about it in the\n            [FastAPI docs for Conditional OpenAPI](https://fastapi.tiangolo.com/how-to/conditional-openapi/#conditional-openapi-from-settings-and-env-vars)\n            \"\"\"\n        ),\n    ],\n    title: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The HTML `<title>` content, normally shown in the browser tab.\n\n            Read more about it in the\n            [FastAPI docs for Custom Docs UI Static Assets](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/)\n            \"\"\"\n        ),\n    ],\n    redoc_js_url: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The URL to use to load the ReDoc JavaScript.\n\n            It is normally set to a CDN URL.\n\n            Read more about it in the\n            [FastAPI docs for Custom Docs UI Static Assets](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/)\n            \"\"\"\n        ),\n    ] = \"https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js\",\n    redoc_favicon_url: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The URL of the favicon to use. It is normally shown in the browser tab.\n            \"\"\"\n        ),\n    ] = \"https://fastapi.tiangolo.com/img/favicon.png\",\n    with_google_fonts: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            Load and use Google Fonts.\n            \"\"\"\n        ),\n    ] = True,\n) -> HTMLResponse:\n    \"\"\"\n    Generate and return the HTML response that loads ReDoc for the alternative\n    API docs (normally served at `/redoc`).\n\n    You would only call this function yourself if you needed to override some parts,\n    for example the URLs to use to load ReDoc's JavaScript and CSS.\n\n    Read more about it in the\n    [FastAPI docs for Custom Docs UI Static Assets (Self-Hosting)](https://fastapi.tiangolo.com/how-to/custom-docs-ui-assets/).\n    \"\"\"\n    html = f\"\"\"\n    <!DOCTYPE html>\n    <html>\n    <head>\n    <title>{title}</title>\n    <!-- needed for adaptive design -->\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    \"\"\"\n    if with_google_fonts:\n        html += \"\"\"\n    <link href=\"https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700\" rel=\"stylesheet\">\n    \"\"\"\n    html += f\"\"\"\n    <link rel=\"shortcut icon\" href=\"{redoc_favicon_url}\">\n    <!--\n    ReDoc doesn't change outer page styles\n    -->\n    <style>\n      body {{\n        margin: 0;\n        padding: 0;\n      }}\n    </style>\n    </head>\n    <body>\n    <noscript>\n        ReDoc requires Javascript to function. Please enable it to browse the documentation.\n    </noscript>\n    <redoc spec-url=\"{openapi_url}\"></redoc>\n    <script src=\"{redoc_js_url}\"> </script>\n    </body>\n    </html>\n    \"\"\"\n    return HTMLResponse(html)\n\n\ndef get_swagger_ui_oauth2_redirect_html() -> HTMLResponse:\n    \"\"\"\n    Generate the HTML response with the OAuth2 redirection for Swagger UI.\n\n    You normally don't need to use or change this.\n    \"\"\"\n    # copied from https://github.com/swagger-api/swagger-ui/blob/v4.14.0/dist/oauth2-redirect.html\n    html = \"\"\"\n    <!doctype html>\n    <html lang=\"en-US\">\n    <head>\n        <title>Swagger UI: OAuth2 Redirect</title>\n    </head>\n    <body>\n    <script>\n        'use strict';\n        function run () {\n            var oauth2 = window.opener.swaggerUIRedirectOauth2;\n            var sentState = oauth2.state;\n            var redirectUrl = oauth2.redirectUrl;\n            var isValid, qp, arr;\n\n            if (/code|token|error/.test(window.location.hash)) {\n                qp = window.location.hash.substring(1).replace('?', '&');\n            } else {\n                qp = location.search.substring(1);\n            }\n\n            arr = qp.split(\"&\");\n            arr.forEach(function (v,i,_arr) { _arr[i] = '\"' + v.replace('=', '\":\"') + '\"';});\n            qp = qp ? JSON.parse('{' + arr.join() + '}',\n                    function (key, value) {\n                        return key === \"\" ? value : decodeURIComponent(value);\n                    }\n            ) : {};\n\n            isValid = qp.state === sentState;\n\n            if ((\n              oauth2.auth.schema.get(\"flow\") === \"accessCode\" ||\n              oauth2.auth.schema.get(\"flow\") === \"authorizationCode\" ||\n              oauth2.auth.schema.get(\"flow\") === \"authorization_code\"\n            ) && !oauth2.auth.code) {\n                if (!isValid) {\n                    oauth2.errCb({\n                        authId: oauth2.auth.name,\n                        source: \"auth\",\n                        level: \"warning\",\n                        message: \"Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server.\"\n                    });\n                }\n\n                if (qp.code) {\n                    delete oauth2.state;\n                    oauth2.auth.code = qp.code;\n                    oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});\n                } else {\n                    let oauthErrorMsg;\n                    if (qp.error) {\n                        oauthErrorMsg = \"[\"+qp.error+\"]: \" +\n                            (qp.error_description ? qp.error_description+ \". \" : \"no accessCode received from the server. \") +\n                            (qp.error_uri ? \"More info: \"+qp.error_uri : \"\");\n                    }\n\n                    oauth2.errCb({\n                        authId: oauth2.auth.name,\n                        source: \"auth\",\n                        level: \"error\",\n                        message: oauthErrorMsg || \"[Authorization failed]: no accessCode received from the server.\"\n                    });\n                }\n            } else {\n                oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});\n            }\n            window.close();\n        }\n\n        if (document.readyState !== 'loading') {\n            run();\n        } else {\n            document.addEventListener('DOMContentLoaded', function () {\n                run();\n            });\n        }\n    </script>\n    </body>\n    </html>\n        \"\"\"\n    return HTMLResponse(content=html)\n"
  },
  {
    "path": "fastapi/openapi/models.py",
    "content": "from collections.abc import Callable, Iterable, Mapping\nfrom enum import Enum\nfrom typing import Annotated, Any, Literal, Optional, Union\n\nfrom fastapi._compat import with_info_plain_validator_function\nfrom fastapi.logger import logger\nfrom pydantic import (\n    AnyUrl,\n    BaseModel,\n    Field,\n    GetJsonSchemaHandler,\n)\nfrom typing_extensions import TypedDict\nfrom typing_extensions import deprecated as typing_deprecated\n\ntry:\n    import email_validator\n\n    assert email_validator  # make autoflake ignore the unused import\n    from pydantic import EmailStr\nexcept ImportError:  # pragma: no cover\n\n    class EmailStr(str):  # type: ignore[no-redef]\n        @classmethod\n        def __get_validators__(cls) -> Iterable[Callable[..., Any]]:\n            yield cls.validate\n\n        @classmethod\n        def validate(cls, v: Any) -> str:\n            logger.warning(\n                \"email-validator not installed, email fields will be treated as str.\\n\"\n                \"To install, run: pip install email-validator\"\n            )\n            return str(v)\n\n        @classmethod\n        def _validate(cls, __input_value: Any, _: Any) -> str:\n            logger.warning(\n                \"email-validator not installed, email fields will be treated as str.\\n\"\n                \"To install, run: pip install email-validator\"\n            )\n            return str(__input_value)\n\n        @classmethod\n        def __get_pydantic_json_schema__(\n            cls, core_schema: Mapping[str, Any], handler: GetJsonSchemaHandler\n        ) -> dict[str, Any]:\n            return {\"type\": \"string\", \"format\": \"email\"}\n\n        @classmethod\n        def __get_pydantic_core_schema__(\n            cls, source: type[Any], handler: Callable[[Any], Mapping[str, Any]]\n        ) -> Mapping[str, Any]:\n            return with_info_plain_validator_function(cls._validate)\n\n\nclass BaseModelWithConfig(BaseModel):\n    model_config = {\"extra\": \"allow\"}\n\n\nclass Contact(BaseModelWithConfig):\n    name: str | None = None\n    url: AnyUrl | None = None\n    email: EmailStr | None = None\n\n\nclass License(BaseModelWithConfig):\n    name: str\n    identifier: str | None = None\n    url: AnyUrl | None = None\n\n\nclass Info(BaseModelWithConfig):\n    title: str\n    summary: str | None = None\n    description: str | None = None\n    termsOfService: str | None = None\n    contact: Contact | None = None\n    license: License | None = None\n    version: str\n\n\nclass ServerVariable(BaseModelWithConfig):\n    enum: Annotated[list[str] | None, Field(min_length=1)] = None\n    default: str\n    description: str | None = None\n\n\nclass Server(BaseModelWithConfig):\n    url: AnyUrl | str\n    description: str | None = None\n    variables: dict[str, ServerVariable] | None = None\n\n\nclass Reference(BaseModel):\n    ref: str = Field(alias=\"$ref\")\n\n\nclass Discriminator(BaseModel):\n    propertyName: str\n    mapping: dict[str, str] | None = None\n\n\nclass XML(BaseModelWithConfig):\n    name: str | None = None\n    namespace: str | None = None\n    prefix: str | None = None\n    attribute: bool | None = None\n    wrapped: bool | None = None\n\n\nclass ExternalDocumentation(BaseModelWithConfig):\n    description: str | None = None\n    url: AnyUrl\n\n\n# Ref JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation#name-type\nSchemaType = Literal[\n    \"array\", \"boolean\", \"integer\", \"null\", \"number\", \"object\", \"string\"\n]\n\n\nclass Schema(BaseModelWithConfig):\n    # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu\n    # Core Vocabulary\n    schema_: str | None = Field(default=None, alias=\"$schema\")\n    vocabulary: str | None = Field(default=None, alias=\"$vocabulary\")\n    id: str | None = Field(default=None, alias=\"$id\")\n    anchor: str | None = Field(default=None, alias=\"$anchor\")\n    dynamicAnchor: str | None = Field(default=None, alias=\"$dynamicAnchor\")\n    ref: str | None = Field(default=None, alias=\"$ref\")\n    dynamicRef: str | None = Field(default=None, alias=\"$dynamicRef\")\n    defs: dict[str, \"SchemaOrBool\"] | None = Field(default=None, alias=\"$defs\")\n    comment: str | None = Field(default=None, alias=\"$comment\")\n    # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s\n    # A Vocabulary for Applying Subschemas\n    allOf: list[\"SchemaOrBool\"] | None = None\n    anyOf: list[\"SchemaOrBool\"] | None = None\n    oneOf: list[\"SchemaOrBool\"] | None = None\n    not_: Optional[\"SchemaOrBool\"] = Field(default=None, alias=\"not\")\n    if_: Optional[\"SchemaOrBool\"] = Field(default=None, alias=\"if\")\n    then: Optional[\"SchemaOrBool\"] = None\n    else_: Optional[\"SchemaOrBool\"] = Field(default=None, alias=\"else\")\n    dependentSchemas: dict[str, \"SchemaOrBool\"] | None = None\n    prefixItems: list[\"SchemaOrBool\"] | None = None\n    items: Optional[\"SchemaOrBool\"] = None\n    contains: Optional[\"SchemaOrBool\"] = None\n    properties: dict[str, \"SchemaOrBool\"] | None = None\n    patternProperties: dict[str, \"SchemaOrBool\"] | None = None\n    additionalProperties: Optional[\"SchemaOrBool\"] = None\n    propertyNames: Optional[\"SchemaOrBool\"] = None\n    unevaluatedItems: Optional[\"SchemaOrBool\"] = None\n    unevaluatedProperties: Optional[\"SchemaOrBool\"] = None\n    # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural\n    # A Vocabulary for Structural Validation\n    type: SchemaType | list[SchemaType] | None = None\n    enum: list[Any] | None = None\n    const: Any | None = None\n    multipleOf: float | None = Field(default=None, gt=0)\n    maximum: float | None = None\n    exclusiveMaximum: float | None = None\n    minimum: float | None = None\n    exclusiveMinimum: float | None = None\n    maxLength: int | None = Field(default=None, ge=0)\n    minLength: int | None = Field(default=None, ge=0)\n    pattern: str | None = None\n    maxItems: int | None = Field(default=None, ge=0)\n    minItems: int | None = Field(default=None, ge=0)\n    uniqueItems: bool | None = None\n    maxContains: int | None = Field(default=None, ge=0)\n    minContains: int | None = Field(default=None, ge=0)\n    maxProperties: int | None = Field(default=None, ge=0)\n    minProperties: int | None = Field(default=None, ge=0)\n    required: list[str] | None = None\n    dependentRequired: dict[str, set[str]] | None = None\n    # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c\n    # Vocabularies for Semantic Content With \"format\"\n    format: str | None = None\n    # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten\n    # A Vocabulary for the Contents of String-Encoded Data\n    contentEncoding: str | None = None\n    contentMediaType: str | None = None\n    contentSchema: Optional[\"SchemaOrBool\"] = None\n    # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta\n    # A Vocabulary for Basic Meta-Data Annotations\n    title: str | None = None\n    description: str | None = None\n    default: Any | None = None\n    deprecated: bool | None = None\n    readOnly: bool | None = None\n    writeOnly: bool | None = None\n    examples: list[Any] | None = None\n    # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object\n    # Schema Object\n    discriminator: Discriminator | None = None\n    xml: XML | None = None\n    externalDocs: ExternalDocumentation | None = None\n    example: Annotated[\n        Any | None,\n        typing_deprecated(\n            \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n            \"although still supported. Use examples instead.\"\n        ),\n    ] = None\n\n\n# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents\n# A JSON Schema MUST be an object or a boolean.\nSchemaOrBool = Schema | bool\n\n\nclass Example(TypedDict, total=False):\n    summary: str | None\n    description: str | None\n    value: Any | None\n    externalValue: AnyUrl | None\n\n    __pydantic_config__ = {\"extra\": \"allow\"}  # type: ignore[misc]  # ty: ignore[invalid-typed-dict-statement]\n\n\nclass ParameterInType(Enum):\n    query = \"query\"\n    header = \"header\"\n    path = \"path\"\n    cookie = \"cookie\"\n\n\nclass Encoding(BaseModelWithConfig):\n    contentType: str | None = None\n    headers: dict[str, Union[\"Header\", Reference]] | None = None\n    style: str | None = None\n    explode: bool | None = None\n    allowReserved: bool | None = None\n\n\nclass MediaType(BaseModelWithConfig):\n    schema_: Schema | Reference | None = Field(default=None, alias=\"schema\")\n    example: Any | None = None\n    examples: dict[str, Example | Reference] | None = None\n    encoding: dict[str, Encoding] | None = None\n\n\nclass ParameterBase(BaseModelWithConfig):\n    description: str | None = None\n    required: bool | None = None\n    deprecated: bool | None = None\n    # Serialization rules for simple scenarios\n    style: str | None = None\n    explode: bool | None = None\n    allowReserved: bool | None = None\n    schema_: Schema | Reference | None = Field(default=None, alias=\"schema\")\n    example: Any | None = None\n    examples: dict[str, Example | Reference] | None = None\n    # Serialization rules for more complex scenarios\n    content: dict[str, MediaType] | None = None\n\n\nclass Parameter(ParameterBase):\n    name: str\n    in_: ParameterInType = Field(alias=\"in\")\n\n\nclass Header(ParameterBase):\n    pass\n\n\nclass RequestBody(BaseModelWithConfig):\n    description: str | None = None\n    content: dict[str, MediaType]\n    required: bool | None = None\n\n\nclass Link(BaseModelWithConfig):\n    operationRef: str | None = None\n    operationId: str | None = None\n    parameters: dict[str, Any | str] | None = None\n    requestBody: Any | str | None = None\n    description: str | None = None\n    server: Server | None = None\n\n\nclass Response(BaseModelWithConfig):\n    description: str\n    headers: dict[str, Header | Reference] | None = None\n    content: dict[str, MediaType] | None = None\n    links: dict[str, Link | Reference] | None = None\n\n\nclass Operation(BaseModelWithConfig):\n    tags: list[str] | None = None\n    summary: str | None = None\n    description: str | None = None\n    externalDocs: ExternalDocumentation | None = None\n    operationId: str | None = None\n    parameters: list[Parameter | Reference] | None = None\n    requestBody: RequestBody | Reference | None = None\n    # Using Any for Specification Extensions\n    responses: dict[str, Response | Any] | None = None\n    callbacks: dict[str, dict[str, \"PathItem\"] | Reference] | None = None\n    deprecated: bool | None = None\n    security: list[dict[str, list[str]]] | None = None\n    servers: list[Server] | None = None\n\n\nclass PathItem(BaseModelWithConfig):\n    ref: str | None = Field(default=None, alias=\"$ref\")\n    summary: str | None = None\n    description: str | None = None\n    get: Operation | None = None\n    put: Operation | None = None\n    post: Operation | None = None\n    delete: Operation | None = None\n    options: Operation | None = None\n    head: Operation | None = None\n    patch: Operation | None = None\n    trace: Operation | None = None\n    servers: list[Server] | None = None\n    parameters: list[Parameter | Reference] | None = None\n\n\nclass SecuritySchemeType(Enum):\n    apiKey = \"apiKey\"\n    http = \"http\"\n    oauth2 = \"oauth2\"\n    openIdConnect = \"openIdConnect\"\n\n\nclass SecurityBase(BaseModelWithConfig):\n    type_: SecuritySchemeType = Field(alias=\"type\")\n    description: str | None = None\n\n\nclass APIKeyIn(Enum):\n    query = \"query\"\n    header = \"header\"\n    cookie = \"cookie\"\n\n\nclass APIKey(SecurityBase):\n    type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias=\"type\")\n    in_: APIKeyIn = Field(alias=\"in\")\n    name: str\n\n\nclass HTTPBase(SecurityBase):\n    type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias=\"type\")\n    scheme: str\n\n\nclass HTTPBearer(HTTPBase):\n    scheme: Literal[\"bearer\"] = \"bearer\"\n    bearerFormat: str | None = None\n\n\nclass OAuthFlow(BaseModelWithConfig):\n    refreshUrl: str | None = None\n    scopes: dict[str, str] = {}\n\n\nclass OAuthFlowImplicit(OAuthFlow):\n    authorizationUrl: str\n\n\nclass OAuthFlowPassword(OAuthFlow):\n    tokenUrl: str\n\n\nclass OAuthFlowClientCredentials(OAuthFlow):\n    tokenUrl: str\n\n\nclass OAuthFlowAuthorizationCode(OAuthFlow):\n    authorizationUrl: str\n    tokenUrl: str\n\n\nclass OAuthFlows(BaseModelWithConfig):\n    implicit: OAuthFlowImplicit | None = None\n    password: OAuthFlowPassword | None = None\n    clientCredentials: OAuthFlowClientCredentials | None = None\n    authorizationCode: OAuthFlowAuthorizationCode | None = None\n\n\nclass OAuth2(SecurityBase):\n    type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias=\"type\")\n    flows: OAuthFlows\n\n\nclass OpenIdConnect(SecurityBase):\n    type_: SecuritySchemeType = Field(\n        default=SecuritySchemeType.openIdConnect, alias=\"type\"\n    )\n    openIdConnectUrl: str\n\n\nSecurityScheme = APIKey | HTTPBase | OAuth2 | OpenIdConnect | HTTPBearer\n\n\nclass Components(BaseModelWithConfig):\n    schemas: dict[str, Schema | Reference] | None = None\n    responses: dict[str, Response | Reference] | None = None\n    parameters: dict[str, Parameter | Reference] | None = None\n    examples: dict[str, Example | Reference] | None = None\n    requestBodies: dict[str, RequestBody | Reference] | None = None\n    headers: dict[str, Header | Reference] | None = None\n    securitySchemes: dict[str, SecurityScheme | Reference] | None = None\n    links: dict[str, Link | Reference] | None = None\n    # Using Any for Specification Extensions\n    callbacks: dict[str, dict[str, PathItem] | Reference | Any] | None = None\n    pathItems: dict[str, PathItem | Reference] | None = None\n\n\nclass Tag(BaseModelWithConfig):\n    name: str\n    description: str | None = None\n    externalDocs: ExternalDocumentation | None = None\n\n\nclass OpenAPI(BaseModelWithConfig):\n    openapi: str\n    info: Info\n    jsonSchemaDialect: str | None = None\n    servers: list[Server] | None = None\n    # Using Any for Specification Extensions\n    paths: dict[str, PathItem | Any] | None = None\n    webhooks: dict[str, PathItem | Reference] | None = None\n    components: Components | None = None\n    security: list[dict[str, list[str]]] | None = None\n    tags: list[Tag] | None = None\n    externalDocs: ExternalDocumentation | None = None\n\n\nSchema.model_rebuild()\nOperation.model_rebuild()\nEncoding.model_rebuild()\n"
  },
  {
    "path": "fastapi/openapi/utils.py",
    "content": "import copy\nimport http.client\nimport inspect\nimport warnings\nfrom collections.abc import Sequence\nfrom typing import Any, Literal, cast\n\nfrom fastapi import routing\nfrom fastapi._compat import (\n    ModelField,\n    get_definitions,\n    get_flat_models_from_fields,\n    get_model_name_map,\n    get_schema_from_model_field,\n    lenient_issubclass,\n)\nfrom fastapi.datastructures import DefaultPlaceholder, _Unset\nfrom fastapi.dependencies.models import Dependant\nfrom fastapi.dependencies.utils import (\n    _get_flat_fields_from_params,\n    get_flat_dependant,\n    get_flat_params,\n    get_validation_alias,\n)\nfrom fastapi.encoders import jsonable_encoder\nfrom fastapi.exceptions import FastAPIDeprecationWarning\nfrom fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX\nfrom fastapi.openapi.models import OpenAPI\nfrom fastapi.params import Body, ParamTypes\nfrom fastapi.responses import Response\nfrom fastapi.sse import _SSE_EVENT_SCHEMA\nfrom fastapi.types import ModelNameMap\nfrom fastapi.utils import (\n    deep_dict_update,\n    generate_operation_id_for_path,\n    is_body_allowed_for_status_code,\n)\nfrom pydantic import BaseModel\nfrom starlette.responses import JSONResponse\nfrom starlette.routing import BaseRoute\n\nvalidation_error_definition = {\n    \"title\": \"ValidationError\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"loc\": {\n            \"title\": \"Location\",\n            \"type\": \"array\",\n            \"items\": {\"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]},\n        },\n        \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n        \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n        \"input\": {\"title\": \"Input\"},\n        \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n    },\n    \"required\": [\"loc\", \"msg\", \"type\"],\n}\n\nvalidation_error_response_definition = {\n    \"title\": \"HTTPValidationError\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"detail\": {\n            \"title\": \"Detail\",\n            \"type\": \"array\",\n            \"items\": {\"$ref\": REF_PREFIX + \"ValidationError\"},\n        }\n    },\n}\n\nstatus_code_ranges: dict[str, str] = {\n    \"1XX\": \"Information\",\n    \"2XX\": \"Success\",\n    \"3XX\": \"Redirection\",\n    \"4XX\": \"Client Error\",\n    \"5XX\": \"Server Error\",\n    \"DEFAULT\": \"Default Response\",\n}\n\n\ndef get_openapi_security_definitions(\n    flat_dependant: Dependant,\n) -> tuple[dict[str, Any], list[dict[str, Any]]]:\n    security_definitions = {}\n    # Use a dict to merge scopes for same security scheme\n    operation_security_dict: dict[str, list[str]] = {}\n    for security_dependency in flat_dependant._security_dependencies:\n        security_definition = jsonable_encoder(\n            security_dependency._security_scheme.model,\n            by_alias=True,\n            exclude_none=True,\n        )\n        security_name = security_dependency._security_scheme.scheme_name\n        security_definitions[security_name] = security_definition\n        # Merge scopes for the same security scheme\n        if security_name not in operation_security_dict:\n            operation_security_dict[security_name] = []\n        for scope in security_dependency.oauth_scopes or []:\n            if scope not in operation_security_dict[security_name]:\n                operation_security_dict[security_name].append(scope)\n    operation_security = [\n        {name: scopes} for name, scopes in operation_security_dict.items()\n    ]\n    return security_definitions, operation_security\n\n\ndef _get_openapi_operation_parameters(\n    *,\n    dependant: Dependant,\n    model_name_map: ModelNameMap,\n    field_mapping: dict[\n        tuple[ModelField, Literal[\"validation\", \"serialization\"]], dict[str, Any]\n    ],\n    separate_input_output_schemas: bool = True,\n) -> list[dict[str, Any]]:\n    parameters = []\n    flat_dependant = get_flat_dependant(dependant, skip_repeats=True)\n    path_params = _get_flat_fields_from_params(flat_dependant.path_params)\n    query_params = _get_flat_fields_from_params(flat_dependant.query_params)\n    header_params = _get_flat_fields_from_params(flat_dependant.header_params)\n    cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)\n    parameter_groups = [\n        (ParamTypes.path, path_params),\n        (ParamTypes.query, query_params),\n        (ParamTypes.header, header_params),\n        (ParamTypes.cookie, cookie_params),\n    ]\n    default_convert_underscores = True\n    if len(flat_dependant.header_params) == 1:\n        first_field = flat_dependant.header_params[0]\n        if lenient_issubclass(first_field.field_info.annotation, BaseModel):\n            default_convert_underscores = getattr(\n                first_field.field_info, \"convert_underscores\", True\n            )\n    for param_type, param_group in parameter_groups:\n        for param in param_group:\n            field_info = param.field_info\n            # field_info = cast(Param, field_info)\n            if not getattr(field_info, \"include_in_schema\", True):\n                continue\n            param_schema = get_schema_from_model_field(\n                field=param,\n                model_name_map=model_name_map,\n                field_mapping=field_mapping,\n                separate_input_output_schemas=separate_input_output_schemas,\n            )\n            name = get_validation_alias(param)\n            convert_underscores = getattr(\n                param.field_info,\n                \"convert_underscores\",\n                default_convert_underscores,\n            )\n            if (\n                param_type == ParamTypes.header\n                and name == param.name\n                and convert_underscores\n            ):\n                name = param.name.replace(\"_\", \"-\")\n\n            parameter = {\n                \"name\": name,\n                \"in\": param_type.value,\n                \"required\": param.field_info.is_required(),\n                \"schema\": param_schema,\n            }\n            if field_info.description:\n                parameter[\"description\"] = field_info.description\n            openapi_examples = getattr(field_info, \"openapi_examples\", None)\n            example = getattr(field_info, \"example\", None)\n            if openapi_examples:\n                parameter[\"examples\"] = jsonable_encoder(openapi_examples)\n            elif example is not _Unset:\n                parameter[\"example\"] = jsonable_encoder(example)\n            if getattr(field_info, \"deprecated\", None):\n                parameter[\"deprecated\"] = True\n            parameters.append(parameter)\n    return parameters\n\n\ndef get_openapi_operation_request_body(\n    *,\n    body_field: ModelField | None,\n    model_name_map: ModelNameMap,\n    field_mapping: dict[\n        tuple[ModelField, Literal[\"validation\", \"serialization\"]], dict[str, Any]\n    ],\n    separate_input_output_schemas: bool = True,\n) -> dict[str, Any] | None:\n    if not body_field:\n        return None\n    assert isinstance(body_field, ModelField)\n    body_schema = get_schema_from_model_field(\n        field=body_field,\n        model_name_map=model_name_map,\n        field_mapping=field_mapping,\n        separate_input_output_schemas=separate_input_output_schemas,\n    )\n    field_info = cast(Body, body_field.field_info)\n    request_media_type = field_info.media_type\n    required = body_field.field_info.is_required()\n    request_body_oai: dict[str, Any] = {}\n    if required:\n        request_body_oai[\"required\"] = required\n    request_media_content: dict[str, Any] = {\"schema\": body_schema}\n    if field_info.openapi_examples:\n        request_media_content[\"examples\"] = jsonable_encoder(\n            field_info.openapi_examples\n        )\n    elif field_info.example is not _Unset:\n        request_media_content[\"example\"] = jsonable_encoder(field_info.example)\n    request_body_oai[\"content\"] = {request_media_type: request_media_content}\n    return request_body_oai\n\n\ndef generate_operation_id(\n    *, route: routing.APIRoute, method: str\n) -> str:  # pragma: nocover\n    warnings.warn(\n        message=\"fastapi.openapi.utils.generate_operation_id() was deprecated, \"\n        \"it is not used internally, and will be removed soon\",\n        category=FastAPIDeprecationWarning,\n        stacklevel=2,\n    )\n    if route.operation_id:\n        return route.operation_id\n    path: str = route.path_format\n    return generate_operation_id_for_path(name=route.name, path=path, method=method)\n\n\ndef generate_operation_summary(*, route: routing.APIRoute, method: str) -> str:\n    if route.summary:\n        return route.summary\n    return route.name.replace(\"_\", \" \").title()\n\n\ndef get_openapi_operation_metadata(\n    *, route: routing.APIRoute, method: str, operation_ids: set[str]\n) -> dict[str, Any]:\n    operation: dict[str, Any] = {}\n    if route.tags:\n        operation[\"tags\"] = route.tags\n    operation[\"summary\"] = generate_operation_summary(route=route, method=method)\n    if route.description:\n        operation[\"description\"] = route.description\n    operation_id = route.operation_id or route.unique_id\n    if operation_id in operation_ids:\n        endpoint_name = getattr(route.endpoint, \"__name__\", \"<unnamed_endpoint>\")\n        message = f\"Duplicate Operation ID {operation_id} for function {endpoint_name}\"\n        file_name = getattr(route.endpoint, \"__globals__\", {}).get(\"__file__\")\n        if file_name:\n            message += f\" at {file_name}\"\n        warnings.warn(message, stacklevel=1)\n    operation_ids.add(operation_id)\n    operation[\"operationId\"] = operation_id\n    if route.deprecated:\n        operation[\"deprecated\"] = route.deprecated\n    return operation\n\n\ndef get_openapi_path(\n    *,\n    route: routing.APIRoute,\n    operation_ids: set[str],\n    model_name_map: ModelNameMap,\n    field_mapping: dict[\n        tuple[ModelField, Literal[\"validation\", \"serialization\"]], dict[str, Any]\n    ],\n    separate_input_output_schemas: bool = True,\n) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]:\n    path = {}\n    security_schemes: dict[str, Any] = {}\n    definitions: dict[str, Any] = {}\n    assert route.methods is not None, \"Methods must be a list\"\n    if isinstance(route.response_class, DefaultPlaceholder):\n        current_response_class: type[Response] = route.response_class.value\n    else:\n        current_response_class = route.response_class\n    assert current_response_class, \"A response class is needed to generate OpenAPI\"\n    route_response_media_type: str | None = current_response_class.media_type\n    if route.include_in_schema:\n        for method in route.methods:\n            operation = get_openapi_operation_metadata(\n                route=route, method=method, operation_ids=operation_ids\n            )\n            parameters: list[dict[str, Any]] = []\n            flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True)\n            security_definitions, operation_security = get_openapi_security_definitions(\n                flat_dependant=flat_dependant\n            )\n            if operation_security:\n                operation.setdefault(\"security\", []).extend(operation_security)\n            if security_definitions:\n                security_schemes.update(security_definitions)\n            operation_parameters = _get_openapi_operation_parameters(\n                dependant=route.dependant,\n                model_name_map=model_name_map,\n                field_mapping=field_mapping,\n                separate_input_output_schemas=separate_input_output_schemas,\n            )\n            parameters.extend(operation_parameters)\n            if parameters:\n                all_parameters = {\n                    (param[\"in\"], param[\"name\"]): param for param in parameters\n                }\n                required_parameters = {\n                    (param[\"in\"], param[\"name\"]): param\n                    for param in parameters\n                    if param.get(\"required\")\n                }\n                # Make sure required definitions of the same parameter take precedence\n                # over non-required definitions\n                all_parameters.update(required_parameters)\n                operation[\"parameters\"] = list(all_parameters.values())\n            if method in METHODS_WITH_BODY:\n                request_body_oai = get_openapi_operation_request_body(\n                    body_field=route.body_field,\n                    model_name_map=model_name_map,\n                    field_mapping=field_mapping,\n                    separate_input_output_schemas=separate_input_output_schemas,\n                )\n                if request_body_oai:\n                    operation[\"requestBody\"] = request_body_oai\n            if route.callbacks:\n                callbacks = {}\n                for callback in route.callbacks:\n                    if isinstance(callback, routing.APIRoute):\n                        (\n                            cb_path,\n                            cb_security_schemes,\n                            cb_definitions,\n                        ) = get_openapi_path(\n                            route=callback,\n                            operation_ids=operation_ids,\n                            model_name_map=model_name_map,\n                            field_mapping=field_mapping,\n                            separate_input_output_schemas=separate_input_output_schemas,\n                        )\n                        callbacks[callback.name] = {callback.path: cb_path}\n                operation[\"callbacks\"] = callbacks\n            if route.status_code is not None:\n                status_code = str(route.status_code)\n            else:\n                # It would probably make more sense for all response classes to have an\n                # explicit default status_code, and to extract it from them, instead of\n                # doing this inspection tricks, that would probably be in the future\n                # TODO: probably make status_code a default class attribute for all\n                # responses in Starlette\n                response_signature = inspect.signature(current_response_class.__init__)\n                status_code_param = response_signature.parameters.get(\"status_code\")\n                if status_code_param is not None:\n                    if isinstance(status_code_param.default, int):\n                        status_code = str(status_code_param.default)\n            operation.setdefault(\"responses\", {}).setdefault(status_code, {})[\n                \"description\"\n            ] = route.response_description\n            if is_body_allowed_for_status_code(route.status_code):\n                # Check for JSONL streaming (generator endpoints)\n                if route.is_json_stream:\n                    jsonl_content: dict[str, Any] = {}\n                    if route.stream_item_field:\n                        item_schema = get_schema_from_model_field(\n                            field=route.stream_item_field,\n                            model_name_map=model_name_map,\n                            field_mapping=field_mapping,\n                            separate_input_output_schemas=separate_input_output_schemas,\n                        )\n                        jsonl_content[\"itemSchema\"] = item_schema\n                    else:\n                        jsonl_content[\"itemSchema\"] = {}\n                    operation.setdefault(\"responses\", {}).setdefault(\n                        status_code, {}\n                    ).setdefault(\"content\", {})[\"application/jsonl\"] = jsonl_content\n                elif route.is_sse_stream:\n                    sse_content: dict[str, Any] = {}\n                    item_schema = copy.deepcopy(_SSE_EVENT_SCHEMA)\n                    if route.stream_item_field:\n                        content_schema = get_schema_from_model_field(\n                            field=route.stream_item_field,\n                            model_name_map=model_name_map,\n                            field_mapping=field_mapping,\n                            separate_input_output_schemas=separate_input_output_schemas,\n                        )\n                        item_schema[\"required\"] = [\"data\"]\n                        item_schema[\"properties\"][\"data\"] = {\n                            \"type\": \"string\",\n                            \"contentMediaType\": \"application/json\",\n                            \"contentSchema\": content_schema,\n                        }\n                    sse_content[\"itemSchema\"] = item_schema\n                    operation.setdefault(\"responses\", {}).setdefault(\n                        status_code, {}\n                    ).setdefault(\"content\", {})[\"text/event-stream\"] = sse_content\n                elif route_response_media_type:\n                    response_schema = {\"type\": \"string\"}\n                    if lenient_issubclass(current_response_class, JSONResponse):\n                        if route.response_field:\n                            response_schema = get_schema_from_model_field(\n                                field=route.response_field,\n                                model_name_map=model_name_map,\n                                field_mapping=field_mapping,\n                                separate_input_output_schemas=separate_input_output_schemas,\n                            )\n                        else:\n                            response_schema = {}\n                    operation.setdefault(\"responses\", {}).setdefault(\n                        status_code, {}\n                    ).setdefault(\"content\", {}).setdefault(\n                        route_response_media_type, {}\n                    )[\"schema\"] = response_schema\n            if route.responses:\n                operation_responses = operation.setdefault(\"responses\", {})\n                for (\n                    additional_status_code,\n                    additional_response,\n                ) in route.responses.items():\n                    process_response = copy.deepcopy(additional_response)\n                    process_response.pop(\"model\", None)\n                    status_code_key = str(additional_status_code).upper()\n                    if status_code_key == \"DEFAULT\":\n                        status_code_key = \"default\"\n                    openapi_response = operation_responses.setdefault(\n                        status_code_key, {}\n                    )\n                    assert isinstance(process_response, dict), (\n                        \"An additional response must be a dict\"\n                    )\n                    field = route.response_fields.get(additional_status_code)\n                    additional_field_schema: dict[str, Any] | None = None\n                    if field:\n                        additional_field_schema = get_schema_from_model_field(\n                            field=field,\n                            model_name_map=model_name_map,\n                            field_mapping=field_mapping,\n                            separate_input_output_schemas=separate_input_output_schemas,\n                        )\n                        media_type = route_response_media_type or \"application/json\"\n                        additional_schema = (\n                            process_response.setdefault(\"content\", {})\n                            .setdefault(media_type, {})\n                            .setdefault(\"schema\", {})\n                        )\n                        deep_dict_update(additional_schema, additional_field_schema)\n                    status_text: str | None = status_code_ranges.get(\n                        str(additional_status_code).upper()\n                    ) or http.client.responses.get(int(additional_status_code))\n                    description = (\n                        process_response.get(\"description\")\n                        or openapi_response.get(\"description\")\n                        or status_text\n                        or \"Additional Response\"\n                    )\n                    deep_dict_update(openapi_response, process_response)\n                    openapi_response[\"description\"] = description\n            http422 = \"422\"\n            all_route_params = get_flat_params(route.dependant)\n            if (all_route_params or route.body_field) and not any(\n                status in operation[\"responses\"]\n                for status in [http422, \"4XX\", \"default\"]\n            ):\n                operation[\"responses\"][http422] = {\n                    \"description\": \"Validation Error\",\n                    \"content\": {\n                        \"application/json\": {\n                            \"schema\": {\"$ref\": REF_PREFIX + \"HTTPValidationError\"}\n                        }\n                    },\n                }\n                if \"ValidationError\" not in definitions:\n                    definitions.update(\n                        {\n                            \"ValidationError\": validation_error_definition,\n                            \"HTTPValidationError\": validation_error_response_definition,\n                        }\n                    )\n            if route.openapi_extra:\n                deep_dict_update(operation, route.openapi_extra)\n            path[method.lower()] = operation\n    return path, security_schemes, definitions\n\n\ndef get_fields_from_routes(\n    routes: Sequence[BaseRoute],\n) -> list[ModelField]:\n    body_fields_from_routes: list[ModelField] = []\n    responses_from_routes: list[ModelField] = []\n    request_fields_from_routes: list[ModelField] = []\n    callback_flat_models: list[ModelField] = []\n    for route in routes:\n        if not isinstance(route, routing.APIRoute):\n            continue\n        if route.include_in_schema:\n            if route.body_field:\n                assert isinstance(route.body_field, ModelField), (\n                    \"A request body must be a Pydantic Field\"\n                )\n                body_fields_from_routes.append(route.body_field)\n            if route.response_field:\n                responses_from_routes.append(route.response_field)\n            if route.response_fields:\n                responses_from_routes.extend(route.response_fields.values())\n            if route.stream_item_field:\n                responses_from_routes.append(route.stream_item_field)\n            if route.callbacks:\n                callback_flat_models.extend(get_fields_from_routes(route.callbacks))\n            params = get_flat_params(route.dependant)\n            request_fields_from_routes.extend(params)\n\n    flat_models = callback_flat_models + list(\n        body_fields_from_routes + responses_from_routes + request_fields_from_routes\n    )\n    return flat_models\n\n\ndef get_openapi(\n    *,\n    title: str,\n    version: str,\n    openapi_version: str = \"3.1.0\",\n    summary: str | None = None,\n    description: str | None = None,\n    routes: Sequence[BaseRoute],\n    webhooks: Sequence[BaseRoute] | None = None,\n    tags: list[dict[str, Any]] | None = None,\n    servers: list[dict[str, str | Any]] | None = None,\n    terms_of_service: str | None = None,\n    contact: dict[str, str | Any] | None = None,\n    license_info: dict[str, str | Any] | None = None,\n    separate_input_output_schemas: bool = True,\n    external_docs: dict[str, Any] | None = None,\n) -> dict[str, Any]:\n    info: dict[str, Any] = {\"title\": title, \"version\": version}\n    if summary:\n        info[\"summary\"] = summary\n    if description:\n        info[\"description\"] = description\n    if terms_of_service:\n        info[\"termsOfService\"] = terms_of_service\n    if contact:\n        info[\"contact\"] = contact\n    if license_info:\n        info[\"license\"] = license_info\n    output: dict[str, Any] = {\"openapi\": openapi_version, \"info\": info}\n    if servers:\n        output[\"servers\"] = servers\n    components: dict[str, dict[str, Any]] = {}\n    paths: dict[str, dict[str, Any]] = {}\n    webhook_paths: dict[str, dict[str, Any]] = {}\n    operation_ids: set[str] = set()\n    all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or []))\n    flat_models = get_flat_models_from_fields(all_fields, known_models=set())\n    model_name_map = get_model_name_map(flat_models)\n    field_mapping, definitions = get_definitions(\n        fields=all_fields,\n        model_name_map=model_name_map,\n        separate_input_output_schemas=separate_input_output_schemas,\n    )\n    for route in routes or []:\n        if isinstance(route, routing.APIRoute):\n            result = get_openapi_path(\n                route=route,\n                operation_ids=operation_ids,\n                model_name_map=model_name_map,\n                field_mapping=field_mapping,\n                separate_input_output_schemas=separate_input_output_schemas,\n            )\n            if result:\n                path, security_schemes, path_definitions = result\n                if path:\n                    paths.setdefault(route.path_format, {}).update(path)\n                if security_schemes:\n                    components.setdefault(\"securitySchemes\", {}).update(\n                        security_schemes\n                    )\n                if path_definitions:\n                    definitions.update(path_definitions)\n    for webhook in webhooks or []:\n        if isinstance(webhook, routing.APIRoute):\n            result = get_openapi_path(\n                route=webhook,\n                operation_ids=operation_ids,\n                model_name_map=model_name_map,\n                field_mapping=field_mapping,\n                separate_input_output_schemas=separate_input_output_schemas,\n            )\n            if result:\n                path, security_schemes, path_definitions = result\n                if path:\n                    webhook_paths.setdefault(webhook.path_format, {}).update(path)\n                if security_schemes:\n                    components.setdefault(\"securitySchemes\", {}).update(\n                        security_schemes\n                    )\n                if path_definitions:\n                    definitions.update(path_definitions)\n    if definitions:\n        components[\"schemas\"] = {k: definitions[k] for k in sorted(definitions)}\n    if components:\n        output[\"components\"] = components\n    output[\"paths\"] = paths\n    if webhook_paths:\n        output[\"webhooks\"] = webhook_paths\n    if tags:\n        output[\"tags\"] = tags\n    if external_docs:\n        output[\"externalDocs\"] = external_docs\n    return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True)  # type: ignore[no-any-return]\n"
  },
  {
    "path": "fastapi/param_functions.py",
    "content": "from collections.abc import Callable, Sequence\nfrom typing import Annotated, Any, Literal\n\nfrom annotated_doc import Doc\nfrom fastapi import params\nfrom fastapi._compat import Undefined\nfrom fastapi.datastructures import _Unset\nfrom fastapi.openapi.models import Example\nfrom pydantic import AliasChoices, AliasPath\nfrom typing_extensions import deprecated\n\n\ndef Path(  # noqa: N802\n    default: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Default value if the parameter field is not set.\n\n            This doesn't affect `Path` parameters as the value is always required.\n            The parameter is available only for compatibility.\n            \"\"\"\n        ),\n    ] = ...,\n    *,\n    default_factory: Annotated[\n        Callable[[], Any] | None,\n        Doc(\n            \"\"\"\n            A callable to generate the default value.\n\n            This doesn't affect `Path` parameters as the value is always required.\n            The parameter is available only for compatibility.\n            \"\"\"\n        ),\n    ] = _Unset,\n    alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            An alternative name for the parameter field.\n\n            This will be used to extract the data and for the generated OpenAPI.\n            It is particularly useful when you can't use the name you want because it\n            is a Python reserved keyword or similar.\n            \"\"\"\n        ),\n    ] = None,\n    alias_priority: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Priority of the alias. This affects whether an alias generator is used.\n            \"\"\"\n        ),\n    ] = _Unset,\n    validation_alias: Annotated[\n        str | AliasPath | AliasChoices | None,\n        Doc(\n            \"\"\"\n            'Whitelist' validation step. The parameter field will be the single one\n            allowed by the alias or set of aliases defined.\n            \"\"\"\n        ),\n    ] = None,\n    serialization_alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            'Blacklist' validation step. The vanilla parameter field will be the\n            single one of the alias' or set of aliases' fields and all the other\n            fields will be ignored at serialization time.\n            \"\"\"\n        ),\n    ] = None,\n    title: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable title.\n\n            Read more about it in the\n            [FastAPI docs for Path Parameters and Numeric Validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#declare-metadata)\n            \"\"\"\n        ),\n    ] = None,\n    description: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable description.\n            \"\"\"\n        ),\n    ] = None,\n    gt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than. If set, value must be greater than this. Only applicable to\n            numbers.\n\n            Read more about it in the\n            [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal)\n            \"\"\"\n        ),\n    ] = None,\n    ge: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than or equal. If set, value must be greater than or equal to\n            this. Only applicable to numbers.\n\n            Read more about it in the\n            [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal)\n            \"\"\"\n        ),\n    ] = None,\n    lt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than. If set, value must be less than this. Only applicable to numbers.\n\n            Read more about it in the\n            [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal)\n            \"\"\"\n        ),\n    ] = None,\n    le: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than or equal. If set, value must be less than or equal to this.\n            Only applicable to numbers.\n\n            Read more about it in the\n            [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal)\n            \"\"\"\n        ),\n    ] = None,\n    min_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Minimum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    max_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    pattern: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n    ] = None,\n    regex: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n        deprecated(\n            \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n        ),\n    ] = None,\n    discriminator: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Parameter field name for discriminating the type in a tagged union.\n            \"\"\"\n        ),\n    ] = None,\n    strict: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            If `True`, strict validation is applied to the field.\n            \"\"\"\n        ),\n    ] = _Unset,\n    multiple_of: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Value must be a multiple of this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    allow_inf_nan: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            Allow `inf`, `-inf`, `nan`. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    max_digits: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of digits allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    decimal_places: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of decimal places allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    examples: Annotated[\n        list[Any] | None,\n        Doc(\n            \"\"\"\n            Example values for this field.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/)\n            \"\"\"\n        ),\n    ] = None,\n    example: Annotated[\n        Any | None,\n        deprecated(\n            \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n            \"although still supported. Use examples instead.\"\n        ),\n    ] = _Unset,\n    openapi_examples: Annotated[\n        dict[str, Example] | None,\n        Doc(\n            \"\"\"\n            OpenAPI-specific examples.\n\n            It will be added to the generated OpenAPI (e.g. visible at `/docs`).\n\n            Swagger UI (that provides the `/docs` interface) has better support for the\n            OpenAPI-specific examples than the JSON Schema `examples`, that's the main\n            use case for this.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).\n            \"\"\"\n        ),\n    ] = None,\n    deprecated: Annotated[\n        deprecated | str | bool | None,\n        Doc(\n            \"\"\"\n            Mark this parameter field as deprecated.\n\n            It will affect the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = None,\n    include_in_schema: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            To include (or not) this parameter field in the generated OpenAPI.\n            You probably don't need it, but it's available.\n\n            This affects the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = True,\n    json_schema_extra: Annotated[\n        dict[str, Any] | None,\n        Doc(\n            \"\"\"\n            Any additional JSON schema data.\n            \"\"\"\n        ),\n    ] = None,\n    **extra: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Include extra fields used by the JSON Schema.\n            \"\"\"\n        ),\n        deprecated(\n            \"\"\"\n            The `extra` kwargs is deprecated. Use `json_schema_extra` instead.\n            \"\"\"\n        ),\n    ],\n) -> Any:\n    \"\"\"\n    Declare a path parameter for a *path operation*.\n\n    Read more about it in the\n    [FastAPI docs for Path Parameters and Numeric Validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/).\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import FastAPI, Path\n\n    app = FastAPI()\n\n\n    @app.get(\"/items/{item_id}\")\n    async def read_items(\n        item_id: Annotated[int, Path(title=\"The ID of the item to get\")],\n    ):\n        return {\"item_id\": item_id}\n    ```\n    \"\"\"\n    return params.Path(\n        default=default,\n        default_factory=default_factory,\n        alias=alias,\n        alias_priority=alias_priority,\n        validation_alias=validation_alias,\n        serialization_alias=serialization_alias,\n        title=title,\n        description=description,\n        gt=gt,\n        ge=ge,\n        lt=lt,\n        le=le,\n        min_length=min_length,\n        max_length=max_length,\n        pattern=pattern,\n        regex=regex,\n        discriminator=discriminator,\n        strict=strict,\n        multiple_of=multiple_of,\n        allow_inf_nan=allow_inf_nan,\n        max_digits=max_digits,\n        decimal_places=decimal_places,\n        example=example,\n        examples=examples,\n        openapi_examples=openapi_examples,\n        deprecated=deprecated,\n        include_in_schema=include_in_schema,\n        json_schema_extra=json_schema_extra,\n        **extra,\n    )\n\n\ndef Query(  # noqa: N802\n    default: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Default value if the parameter field is not set.\n\n            Read more about it in the\n            [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#alternative-old-query-as-the-default-value)\n            \"\"\"\n        ),\n    ] = Undefined,\n    *,\n    default_factory: Annotated[\n        Callable[[], Any] | None,\n        Doc(\n            \"\"\"\n            A callable to generate the default value.\n\n            This doesn't affect `Path` parameters as the value is always required.\n            The parameter is available only for compatibility.\n            \"\"\"\n        ),\n    ] = _Unset,\n    alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            An alternative name for the parameter field.\n\n            This will be used to extract the data and for the generated OpenAPI.\n            It is particularly useful when you can't use the name you want because it\n            is a Python reserved keyword or similar.\n\n            Read more about it in the\n            [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#alias-parameters)\n            \"\"\"\n        ),\n    ] = None,\n    alias_priority: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Priority of the alias. This affects whether an alias generator is used.\n            \"\"\"\n        ),\n    ] = _Unset,\n    validation_alias: Annotated[\n        str | AliasPath | AliasChoices | None,\n        Doc(\n            \"\"\"\n            'Whitelist' validation step. The parameter field will be the single one\n            allowed by the alias or set of aliases defined.\n            \"\"\"\n        ),\n    ] = None,\n    serialization_alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            'Blacklist' validation step. The vanilla parameter field will be the\n            single one of the alias' or set of aliases' fields and all the other\n            fields will be ignored at serialization time.\n            \"\"\"\n        ),\n    ] = None,\n    title: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable title.\n\n            Read more about it in the\n            [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#declare-more-metadata)\n            \"\"\"\n        ),\n    ] = None,\n    description: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable description.\n\n            Read more about it in the\n            [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#declare-more-metadata)\n            \"\"\"\n        ),\n    ] = None,\n    gt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than. If set, value must be greater than this. Only applicable to\n            numbers.\n\n            Read more about it in the\n            [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal)\n            \"\"\"\n        ),\n    ] = None,\n    ge: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than or equal. If set, value must be greater than or equal to\n            this. Only applicable to numbers.\n\n            Read more about it in the\n            [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal)\n            \"\"\"\n        ),\n    ] = None,\n    lt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than. If set, value must be less than this. Only applicable to numbers.\n\n            Read more about it in the\n            [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal)\n            \"\"\"\n        ),\n    ] = None,\n    le: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than or equal. If set, value must be less than or equal to this.\n            Only applicable to numbers.\n\n            Read more about it in the\n            [FastAPI docs about Path parameters numeric validations](https://fastapi.tiangolo.com/tutorial/path-params-numeric-validations/#number-validations-greater-than-and-less-than-or-equal)\n            \"\"\"\n        ),\n    ] = None,\n    min_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Minimum length for strings.\n\n            Read more about it in the\n            [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/)\n            \"\"\"\n        ),\n    ] = None,\n    max_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum length for strings.\n\n            Read more about it in the\n            [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/)\n            \"\"\"\n        ),\n    ] = None,\n    pattern: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n\n            Read more about it in the\n            [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#add-regular-expressions\n            \"\"\"\n        ),\n    ] = None,\n    regex: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n        deprecated(\n            \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n        ),\n    ] = None,\n    discriminator: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Parameter field name for discriminating the type in a tagged union.\n            \"\"\"\n        ),\n    ] = None,\n    strict: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            If `True`, strict validation is applied to the field.\n            \"\"\"\n        ),\n    ] = _Unset,\n    multiple_of: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Value must be a multiple of this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    allow_inf_nan: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            Allow `inf`, `-inf`, `nan`. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    max_digits: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of digits allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    decimal_places: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of decimal places allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    examples: Annotated[\n        list[Any] | None,\n        Doc(\n            \"\"\"\n            Example values for this field.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/)\n            \"\"\"\n        ),\n    ] = None,\n    example: Annotated[\n        Any | None,\n        deprecated(\n            \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n            \"although still supported. Use examples instead.\"\n        ),\n    ] = _Unset,\n    openapi_examples: Annotated[\n        dict[str, Example] | None,\n        Doc(\n            \"\"\"\n            OpenAPI-specific examples.\n\n            It will be added to the generated OpenAPI (e.g. visible at `/docs`).\n\n            Swagger UI (that provides the `/docs` interface) has better support for the\n            OpenAPI-specific examples than the JSON Schema `examples`, that's the main\n            use case for this.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).\n            \"\"\"\n        ),\n    ] = None,\n    deprecated: Annotated[\n        deprecated | str | bool | None,\n        Doc(\n            \"\"\"\n            Mark this parameter field as deprecated.\n\n            It will affect the generated OpenAPI (e.g. visible at `/docs`).\n\n            Read more about it in the\n            [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#deprecating-parameters)\n            \"\"\"\n        ),\n    ] = None,\n    include_in_schema: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            To include (or not) this parameter field in the generated OpenAPI.\n            You probably don't need it, but it's available.\n\n            This affects the generated OpenAPI (e.g. visible at `/docs`).\n\n            Read more about it in the\n            [FastAPI docs about Query parameters](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi\n            \"\"\"\n        ),\n    ] = True,\n    json_schema_extra: Annotated[\n        dict[str, Any] | None,\n        Doc(\n            \"\"\"\n            Any additional JSON schema data.\n            \"\"\"\n        ),\n    ] = None,\n    **extra: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Include extra fields used by the JSON Schema.\n            \"\"\"\n        ),\n        deprecated(\n            \"\"\"\n            The `extra` kwargs is deprecated. Use `json_schema_extra` instead.\n            \"\"\"\n        ),\n    ],\n) -> Any:\n    return params.Query(\n        default=default,\n        default_factory=default_factory,\n        alias=alias,\n        alias_priority=alias_priority,\n        validation_alias=validation_alias,\n        serialization_alias=serialization_alias,\n        title=title,\n        description=description,\n        gt=gt,\n        ge=ge,\n        lt=lt,\n        le=le,\n        min_length=min_length,\n        max_length=max_length,\n        pattern=pattern,\n        regex=regex,\n        discriminator=discriminator,\n        strict=strict,\n        multiple_of=multiple_of,\n        allow_inf_nan=allow_inf_nan,\n        max_digits=max_digits,\n        decimal_places=decimal_places,\n        example=example,\n        examples=examples,\n        openapi_examples=openapi_examples,\n        deprecated=deprecated,\n        include_in_schema=include_in_schema,\n        json_schema_extra=json_schema_extra,\n        **extra,\n    )\n\n\ndef Header(  # noqa: N802\n    default: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Default value if the parameter field is not set.\n            \"\"\"\n        ),\n    ] = Undefined,\n    *,\n    default_factory: Annotated[\n        Callable[[], Any] | None,\n        Doc(\n            \"\"\"\n            A callable to generate the default value.\n\n            This doesn't affect `Path` parameters as the value is always required.\n            The parameter is available only for compatibility.\n            \"\"\"\n        ),\n    ] = _Unset,\n    alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            An alternative name for the parameter field.\n\n            This will be used to extract the data and for the generated OpenAPI.\n            It is particularly useful when you can't use the name you want because it\n            is a Python reserved keyword or similar.\n            \"\"\"\n        ),\n    ] = None,\n    alias_priority: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Priority of the alias. This affects whether an alias generator is used.\n            \"\"\"\n        ),\n    ] = _Unset,\n    validation_alias: Annotated[\n        str | AliasPath | AliasChoices | None,\n        Doc(\n            \"\"\"\n            'Whitelist' validation step. The parameter field will be the single one\n            allowed by the alias or set of aliases defined.\n            \"\"\"\n        ),\n    ] = None,\n    serialization_alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            'Blacklist' validation step. The vanilla parameter field will be the\n            single one of the alias' or set of aliases' fields and all the other\n            fields will be ignored at serialization time.\n            \"\"\"\n        ),\n    ] = None,\n    convert_underscores: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            Automatically convert underscores to hyphens in the parameter field name.\n\n            Read more about it in the\n            [FastAPI docs for Header Parameters](https://fastapi.tiangolo.com/tutorial/header-params/#automatic-conversion)\n            \"\"\"\n        ),\n    ] = True,\n    title: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable title.\n            \"\"\"\n        ),\n    ] = None,\n    description: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable description.\n            \"\"\"\n        ),\n    ] = None,\n    gt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than. If set, value must be greater than this. Only applicable to\n            numbers.\n            \"\"\"\n        ),\n    ] = None,\n    ge: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than or equal. If set, value must be greater than or equal to\n            this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    lt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than. If set, value must be less than this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    le: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than or equal. If set, value must be less than or equal to this.\n            Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    min_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Minimum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    max_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    pattern: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n    ] = None,\n    regex: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n        deprecated(\n            \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n        ),\n    ] = None,\n    discriminator: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Parameter field name for discriminating the type in a tagged union.\n            \"\"\"\n        ),\n    ] = None,\n    strict: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            If `True`, strict validation is applied to the field.\n            \"\"\"\n        ),\n    ] = _Unset,\n    multiple_of: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Value must be a multiple of this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    allow_inf_nan: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            Allow `inf`, `-inf`, `nan`. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    max_digits: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of digits allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    decimal_places: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of decimal places allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    examples: Annotated[\n        list[Any] | None,\n        Doc(\n            \"\"\"\n            Example values for this field.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/)\n            \"\"\"\n        ),\n    ] = None,\n    example: Annotated[\n        Any | None,\n        deprecated(\n            \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n            \"although still supported. Use examples instead.\"\n        ),\n    ] = _Unset,\n    openapi_examples: Annotated[\n        dict[str, Example] | None,\n        Doc(\n            \"\"\"\n            OpenAPI-specific examples.\n\n            It will be added to the generated OpenAPI (e.g. visible at `/docs`).\n\n            Swagger UI (that provides the `/docs` interface) has better support for the\n            OpenAPI-specific examples than the JSON Schema `examples`, that's the main\n            use case for this.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).\n            \"\"\"\n        ),\n    ] = None,\n    deprecated: Annotated[\n        deprecated | str | bool | None,\n        Doc(\n            \"\"\"\n            Mark this parameter field as deprecated.\n\n            It will affect the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = None,\n    include_in_schema: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            To include (or not) this parameter field in the generated OpenAPI.\n            You probably don't need it, but it's available.\n\n            This affects the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = True,\n    json_schema_extra: Annotated[\n        dict[str, Any] | None,\n        Doc(\n            \"\"\"\n            Any additional JSON schema data.\n            \"\"\"\n        ),\n    ] = None,\n    **extra: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Include extra fields used by the JSON Schema.\n            \"\"\"\n        ),\n        deprecated(\n            \"\"\"\n            The `extra` kwargs is deprecated. Use `json_schema_extra` instead.\n            \"\"\"\n        ),\n    ],\n) -> Any:\n    return params.Header(\n        default=default,\n        default_factory=default_factory,\n        alias=alias,\n        alias_priority=alias_priority,\n        validation_alias=validation_alias,\n        serialization_alias=serialization_alias,\n        convert_underscores=convert_underscores,\n        title=title,\n        description=description,\n        gt=gt,\n        ge=ge,\n        lt=lt,\n        le=le,\n        min_length=min_length,\n        max_length=max_length,\n        pattern=pattern,\n        regex=regex,\n        discriminator=discriminator,\n        strict=strict,\n        multiple_of=multiple_of,\n        allow_inf_nan=allow_inf_nan,\n        max_digits=max_digits,\n        decimal_places=decimal_places,\n        example=example,\n        examples=examples,\n        openapi_examples=openapi_examples,\n        deprecated=deprecated,\n        include_in_schema=include_in_schema,\n        json_schema_extra=json_schema_extra,\n        **extra,\n    )\n\n\ndef Cookie(  # noqa: N802\n    default: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Default value if the parameter field is not set.\n            \"\"\"\n        ),\n    ] = Undefined,\n    *,\n    default_factory: Annotated[\n        Callable[[], Any] | None,\n        Doc(\n            \"\"\"\n            A callable to generate the default value.\n\n            This doesn't affect `Path` parameters as the value is always required.\n            The parameter is available only for compatibility.\n            \"\"\"\n        ),\n    ] = _Unset,\n    alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            An alternative name for the parameter field.\n\n            This will be used to extract the data and for the generated OpenAPI.\n            It is particularly useful when you can't use the name you want because it\n            is a Python reserved keyword or similar.\n            \"\"\"\n        ),\n    ] = None,\n    alias_priority: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Priority of the alias. This affects whether an alias generator is used.\n            \"\"\"\n        ),\n    ] = _Unset,\n    validation_alias: Annotated[\n        str | AliasPath | AliasChoices | None,\n        Doc(\n            \"\"\"\n            'Whitelist' validation step. The parameter field will be the single one\n            allowed by the alias or set of aliases defined.\n            \"\"\"\n        ),\n    ] = None,\n    serialization_alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            'Blacklist' validation step. The vanilla parameter field will be the\n            single one of the alias' or set of aliases' fields and all the other\n            fields will be ignored at serialization time.\n            \"\"\"\n        ),\n    ] = None,\n    title: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable title.\n            \"\"\"\n        ),\n    ] = None,\n    description: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable description.\n            \"\"\"\n        ),\n    ] = None,\n    gt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than. If set, value must be greater than this. Only applicable to\n            numbers.\n            \"\"\"\n        ),\n    ] = None,\n    ge: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than or equal. If set, value must be greater than or equal to\n            this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    lt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than. If set, value must be less than this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    le: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than or equal. If set, value must be less than or equal to this.\n            Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    min_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Minimum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    max_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    pattern: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n    ] = None,\n    regex: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n        deprecated(\n            \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n        ),\n    ] = None,\n    discriminator: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Parameter field name for discriminating the type in a tagged union.\n            \"\"\"\n        ),\n    ] = None,\n    strict: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            If `True`, strict validation is applied to the field.\n            \"\"\"\n        ),\n    ] = _Unset,\n    multiple_of: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Value must be a multiple of this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    allow_inf_nan: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            Allow `inf`, `-inf`, `nan`. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    max_digits: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of digits allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    decimal_places: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of decimal places allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    examples: Annotated[\n        list[Any] | None,\n        Doc(\n            \"\"\"\n            Example values for this field.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/)\n            \"\"\"\n        ),\n    ] = None,\n    example: Annotated[\n        Any | None,\n        deprecated(\n            \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n            \"although still supported. Use examples instead.\"\n        ),\n    ] = _Unset,\n    openapi_examples: Annotated[\n        dict[str, Example] | None,\n        Doc(\n            \"\"\"\n            OpenAPI-specific examples.\n\n            It will be added to the generated OpenAPI (e.g. visible at `/docs`).\n\n            Swagger UI (that provides the `/docs` interface) has better support for the\n            OpenAPI-specific examples than the JSON Schema `examples`, that's the main\n            use case for this.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).\n            \"\"\"\n        ),\n    ] = None,\n    deprecated: Annotated[\n        deprecated | str | bool | None,\n        Doc(\n            \"\"\"\n            Mark this parameter field as deprecated.\n\n            It will affect the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = None,\n    include_in_schema: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            To include (or not) this parameter field in the generated OpenAPI.\n            You probably don't need it, but it's available.\n\n            This affects the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = True,\n    json_schema_extra: Annotated[\n        dict[str, Any] | None,\n        Doc(\n            \"\"\"\n            Any additional JSON schema data.\n            \"\"\"\n        ),\n    ] = None,\n    **extra: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Include extra fields used by the JSON Schema.\n            \"\"\"\n        ),\n        deprecated(\n            \"\"\"\n            The `extra` kwargs is deprecated. Use `json_schema_extra` instead.\n            \"\"\"\n        ),\n    ],\n) -> Any:\n    return params.Cookie(\n        default=default,\n        default_factory=default_factory,\n        alias=alias,\n        alias_priority=alias_priority,\n        validation_alias=validation_alias,\n        serialization_alias=serialization_alias,\n        title=title,\n        description=description,\n        gt=gt,\n        ge=ge,\n        lt=lt,\n        le=le,\n        min_length=min_length,\n        max_length=max_length,\n        pattern=pattern,\n        regex=regex,\n        discriminator=discriminator,\n        strict=strict,\n        multiple_of=multiple_of,\n        allow_inf_nan=allow_inf_nan,\n        max_digits=max_digits,\n        decimal_places=decimal_places,\n        example=example,\n        examples=examples,\n        openapi_examples=openapi_examples,\n        deprecated=deprecated,\n        include_in_schema=include_in_schema,\n        json_schema_extra=json_schema_extra,\n        **extra,\n    )\n\n\ndef Body(  # noqa: N802\n    default: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Default value if the parameter field is not set.\n            \"\"\"\n        ),\n    ] = Undefined,\n    *,\n    default_factory: Annotated[\n        Callable[[], Any] | None,\n        Doc(\n            \"\"\"\n            A callable to generate the default value.\n\n            This doesn't affect `Path` parameters as the value is always required.\n            The parameter is available only for compatibility.\n            \"\"\"\n        ),\n    ] = _Unset,\n    embed: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            When `embed` is `True`, the parameter will be expected in a JSON body as a\n            key instead of being the JSON body itself.\n\n            This happens automatically when more than one `Body` parameter is declared.\n\n            Read more about it in the\n            [FastAPI docs for Body - Multiple Parameters](https://fastapi.tiangolo.com/tutorial/body-multiple-params/#embed-a-single-body-parameter).\n            \"\"\"\n        ),\n    ] = None,\n    media_type: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The media type of this parameter field. Changing it would affect the\n            generated OpenAPI, but currently it doesn't affect the parsing of the data.\n            \"\"\"\n        ),\n    ] = \"application/json\",\n    alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            An alternative name for the parameter field.\n\n            This will be used to extract the data and for the generated OpenAPI.\n            It is particularly useful when you can't use the name you want because it\n            is a Python reserved keyword or similar.\n            \"\"\"\n        ),\n    ] = None,\n    alias_priority: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Priority of the alias. This affects whether an alias generator is used.\n            \"\"\"\n        ),\n    ] = _Unset,\n    validation_alias: Annotated[\n        str | AliasPath | AliasChoices | None,\n        Doc(\n            \"\"\"\n            'Whitelist' validation step. The parameter field will be the single one\n            allowed by the alias or set of aliases defined.\n            \"\"\"\n        ),\n    ] = None,\n    serialization_alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            'Blacklist' validation step. The vanilla parameter field will be the\n            single one of the alias' or set of aliases' fields and all the other\n            fields will be ignored at serialization time.\n            \"\"\"\n        ),\n    ] = None,\n    title: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable title.\n            \"\"\"\n        ),\n    ] = None,\n    description: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable description.\n            \"\"\"\n        ),\n    ] = None,\n    gt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than. If set, value must be greater than this. Only applicable to\n            numbers.\n            \"\"\"\n        ),\n    ] = None,\n    ge: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than or equal. If set, value must be greater than or equal to\n            this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    lt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than. If set, value must be less than this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    le: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than or equal. If set, value must be less than or equal to this.\n            Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    min_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Minimum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    max_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    pattern: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n    ] = None,\n    regex: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n        deprecated(\n            \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n        ),\n    ] = None,\n    discriminator: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Parameter field name for discriminating the type in a tagged union.\n            \"\"\"\n        ),\n    ] = None,\n    strict: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            If `True`, strict validation is applied to the field.\n            \"\"\"\n        ),\n    ] = _Unset,\n    multiple_of: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Value must be a multiple of this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    allow_inf_nan: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            Allow `inf`, `-inf`, `nan`. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    max_digits: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of digits allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    decimal_places: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of decimal places allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    examples: Annotated[\n        list[Any] | None,\n        Doc(\n            \"\"\"\n            Example values for this field.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/)\n            \"\"\"\n        ),\n    ] = None,\n    example: Annotated[\n        Any | None,\n        deprecated(\n            \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n            \"although still supported. Use examples instead.\"\n        ),\n    ] = _Unset,\n    openapi_examples: Annotated[\n        dict[str, Example] | None,\n        Doc(\n            \"\"\"\n            OpenAPI-specific examples.\n\n            It will be added to the generated OpenAPI (e.g. visible at `/docs`).\n\n            Swagger UI (that provides the `/docs` interface) has better support for the\n            OpenAPI-specific examples than the JSON Schema `examples`, that's the main\n            use case for this.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).\n            \"\"\"\n        ),\n    ] = None,\n    deprecated: Annotated[\n        deprecated | str | bool | None,\n        Doc(\n            \"\"\"\n            Mark this parameter field as deprecated.\n\n            It will affect the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = None,\n    include_in_schema: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            To include (or not) this parameter field in the generated OpenAPI.\n            You probably don't need it, but it's available.\n\n            This affects the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = True,\n    json_schema_extra: Annotated[\n        dict[str, Any] | None,\n        Doc(\n            \"\"\"\n            Any additional JSON schema data.\n            \"\"\"\n        ),\n    ] = None,\n    **extra: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Include extra fields used by the JSON Schema.\n            \"\"\"\n        ),\n        deprecated(\n            \"\"\"\n            The `extra` kwargs is deprecated. Use `json_schema_extra` instead.\n            \"\"\"\n        ),\n    ],\n) -> Any:\n    return params.Body(\n        default=default,\n        default_factory=default_factory,\n        embed=embed,\n        media_type=media_type,\n        alias=alias,\n        alias_priority=alias_priority,\n        validation_alias=validation_alias,\n        serialization_alias=serialization_alias,\n        title=title,\n        description=description,\n        gt=gt,\n        ge=ge,\n        lt=lt,\n        le=le,\n        min_length=min_length,\n        max_length=max_length,\n        pattern=pattern,\n        regex=regex,\n        discriminator=discriminator,\n        strict=strict,\n        multiple_of=multiple_of,\n        allow_inf_nan=allow_inf_nan,\n        max_digits=max_digits,\n        decimal_places=decimal_places,\n        example=example,\n        examples=examples,\n        openapi_examples=openapi_examples,\n        deprecated=deprecated,\n        include_in_schema=include_in_schema,\n        json_schema_extra=json_schema_extra,\n        **extra,\n    )\n\n\ndef Form(  # noqa: N802\n    default: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Default value if the parameter field is not set.\n            \"\"\"\n        ),\n    ] = Undefined,\n    *,\n    default_factory: Annotated[\n        Callable[[], Any] | None,\n        Doc(\n            \"\"\"\n            A callable to generate the default value.\n\n            This doesn't affect `Path` parameters as the value is always required.\n            The parameter is available only for compatibility.\n            \"\"\"\n        ),\n    ] = _Unset,\n    media_type: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The media type of this parameter field. Changing it would affect the\n            generated OpenAPI, but currently it doesn't affect the parsing of the data.\n            \"\"\"\n        ),\n    ] = \"application/x-www-form-urlencoded\",\n    alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            An alternative name for the parameter field.\n\n            This will be used to extract the data and for the generated OpenAPI.\n            It is particularly useful when you can't use the name you want because it\n            is a Python reserved keyword or similar.\n            \"\"\"\n        ),\n    ] = None,\n    alias_priority: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Priority of the alias. This affects whether an alias generator is used.\n            \"\"\"\n        ),\n    ] = _Unset,\n    validation_alias: Annotated[\n        str | AliasPath | AliasChoices | None,\n        Doc(\n            \"\"\"\n            'Whitelist' validation step. The parameter field will be the single one\n            allowed by the alias or set of aliases defined.\n            \"\"\"\n        ),\n    ] = None,\n    serialization_alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            'Blacklist' validation step. The vanilla parameter field will be the\n            single one of the alias' or set of aliases' fields and all the other\n            fields will be ignored at serialization time.\n            \"\"\"\n        ),\n    ] = None,\n    title: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable title.\n            \"\"\"\n        ),\n    ] = None,\n    description: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable description.\n            \"\"\"\n        ),\n    ] = None,\n    gt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than. If set, value must be greater than this. Only applicable to\n            numbers.\n            \"\"\"\n        ),\n    ] = None,\n    ge: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than or equal. If set, value must be greater than or equal to\n            this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    lt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than. If set, value must be less than this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    le: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than or equal. If set, value must be less than or equal to this.\n            Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    min_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Minimum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    max_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    pattern: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n    ] = None,\n    regex: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n        deprecated(\n            \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n        ),\n    ] = None,\n    discriminator: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Parameter field name for discriminating the type in a tagged union.\n            \"\"\"\n        ),\n    ] = None,\n    strict: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            If `True`, strict validation is applied to the field.\n            \"\"\"\n        ),\n    ] = _Unset,\n    multiple_of: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Value must be a multiple of this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    allow_inf_nan: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            Allow `inf`, `-inf`, `nan`. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    max_digits: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of digits allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    decimal_places: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of decimal places allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    examples: Annotated[\n        list[Any] | None,\n        Doc(\n            \"\"\"\n            Example values for this field.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/)\n            \"\"\"\n        ),\n    ] = None,\n    example: Annotated[\n        Any | None,\n        deprecated(\n            \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n            \"although still supported. Use examples instead.\"\n        ),\n    ] = _Unset,\n    openapi_examples: Annotated[\n        dict[str, Example] | None,\n        Doc(\n            \"\"\"\n            OpenAPI-specific examples.\n\n            It will be added to the generated OpenAPI (e.g. visible at `/docs`).\n\n            Swagger UI (that provides the `/docs` interface) has better support for the\n            OpenAPI-specific examples than the JSON Schema `examples`, that's the main\n            use case for this.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).\n            \"\"\"\n        ),\n    ] = None,\n    deprecated: Annotated[\n        deprecated | str | bool | None,\n        Doc(\n            \"\"\"\n            Mark this parameter field as deprecated.\n\n            It will affect the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = None,\n    include_in_schema: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            To include (or not) this parameter field in the generated OpenAPI.\n            You probably don't need it, but it's available.\n\n            This affects the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = True,\n    json_schema_extra: Annotated[\n        dict[str, Any] | None,\n        Doc(\n            \"\"\"\n            Any additional JSON schema data.\n            \"\"\"\n        ),\n    ] = None,\n    **extra: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Include extra fields used by the JSON Schema.\n            \"\"\"\n        ),\n        deprecated(\n            \"\"\"\n            The `extra` kwargs is deprecated. Use `json_schema_extra` instead.\n            \"\"\"\n        ),\n    ],\n) -> Any:\n    return params.Form(\n        default=default,\n        default_factory=default_factory,\n        media_type=media_type,\n        alias=alias,\n        alias_priority=alias_priority,\n        validation_alias=validation_alias,\n        serialization_alias=serialization_alias,\n        title=title,\n        description=description,\n        gt=gt,\n        ge=ge,\n        lt=lt,\n        le=le,\n        min_length=min_length,\n        max_length=max_length,\n        pattern=pattern,\n        regex=regex,\n        discriminator=discriminator,\n        strict=strict,\n        multiple_of=multiple_of,\n        allow_inf_nan=allow_inf_nan,\n        max_digits=max_digits,\n        decimal_places=decimal_places,\n        example=example,\n        examples=examples,\n        openapi_examples=openapi_examples,\n        deprecated=deprecated,\n        include_in_schema=include_in_schema,\n        json_schema_extra=json_schema_extra,\n        **extra,\n    )\n\n\ndef File(  # noqa: N802\n    default: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Default value if the parameter field is not set.\n            \"\"\"\n        ),\n    ] = Undefined,\n    *,\n    default_factory: Annotated[\n        Callable[[], Any] | None,\n        Doc(\n            \"\"\"\n            A callable to generate the default value.\n\n            This doesn't affect `Path` parameters as the value is always required.\n            The parameter is available only for compatibility.\n            \"\"\"\n        ),\n    ] = _Unset,\n    media_type: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The media type of this parameter field. Changing it would affect the\n            generated OpenAPI, but currently it doesn't affect the parsing of the data.\n            \"\"\"\n        ),\n    ] = \"multipart/form-data\",\n    alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            An alternative name for the parameter field.\n\n            This will be used to extract the data and for the generated OpenAPI.\n            It is particularly useful when you can't use the name you want because it\n            is a Python reserved keyword or similar.\n            \"\"\"\n        ),\n    ] = None,\n    alias_priority: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Priority of the alias. This affects whether an alias generator is used.\n            \"\"\"\n        ),\n    ] = _Unset,\n    validation_alias: Annotated[\n        str | AliasPath | AliasChoices | None,\n        Doc(\n            \"\"\"\n            'Whitelist' validation step. The parameter field will be the single one\n            allowed by the alias or set of aliases defined.\n            \"\"\"\n        ),\n    ] = None,\n    serialization_alias: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            'Blacklist' validation step. The vanilla parameter field will be the\n            single one of the alias' or set of aliases' fields and all the other\n            fields will be ignored at serialization time.\n            \"\"\"\n        ),\n    ] = None,\n    title: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable title.\n            \"\"\"\n        ),\n    ] = None,\n    description: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Human-readable description.\n            \"\"\"\n        ),\n    ] = None,\n    gt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than. If set, value must be greater than this. Only applicable to\n            numbers.\n            \"\"\"\n        ),\n    ] = None,\n    ge: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Greater than or equal. If set, value must be greater than or equal to\n            this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    lt: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than. If set, value must be less than this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    le: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Less than or equal. If set, value must be less than or equal to this.\n            Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = None,\n    min_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Minimum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    max_length: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum length for strings.\n            \"\"\"\n        ),\n    ] = None,\n    pattern: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n    ] = None,\n    regex: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            RegEx pattern for strings.\n            \"\"\"\n        ),\n        deprecated(\n            \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n        ),\n    ] = None,\n    discriminator: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Parameter field name for discriminating the type in a tagged union.\n            \"\"\"\n        ),\n    ] = None,\n    strict: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            If `True`, strict validation is applied to the field.\n            \"\"\"\n        ),\n    ] = _Unset,\n    multiple_of: Annotated[\n        float | None,\n        Doc(\n            \"\"\"\n            Value must be a multiple of this. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    allow_inf_nan: Annotated[\n        bool | None,\n        Doc(\n            \"\"\"\n            Allow `inf`, `-inf`, `nan`. Only applicable to numbers.\n            \"\"\"\n        ),\n    ] = _Unset,\n    max_digits: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of digits allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    decimal_places: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Maximum number of decimal places allowed for decimal values.\n            \"\"\"\n        ),\n    ] = _Unset,\n    examples: Annotated[\n        list[Any] | None,\n        Doc(\n            \"\"\"\n            Example values for this field.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/)\n            \"\"\"\n        ),\n    ] = None,\n    example: Annotated[\n        Any | None,\n        deprecated(\n            \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n            \"although still supported. Use examples instead.\"\n        ),\n    ] = _Unset,\n    openapi_examples: Annotated[\n        dict[str, Example] | None,\n        Doc(\n            \"\"\"\n            OpenAPI-specific examples.\n\n            It will be added to the generated OpenAPI (e.g. visible at `/docs`).\n\n            Swagger UI (that provides the `/docs` interface) has better support for the\n            OpenAPI-specific examples than the JSON Schema `examples`, that's the main\n            use case for this.\n\n            Read more about it in the\n            [FastAPI docs for Declare Request Example Data](https://fastapi.tiangolo.com/tutorial/schema-extra-example/#using-the-openapi_examples-parameter).\n            \"\"\"\n        ),\n    ] = None,\n    deprecated: Annotated[\n        deprecated | str | bool | None,\n        Doc(\n            \"\"\"\n            Mark this parameter field as deprecated.\n\n            It will affect the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = None,\n    include_in_schema: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            To include (or not) this parameter field in the generated OpenAPI.\n            You probably don't need it, but it's available.\n\n            This affects the generated OpenAPI (e.g. visible at `/docs`).\n            \"\"\"\n        ),\n    ] = True,\n    json_schema_extra: Annotated[\n        dict[str, Any] | None,\n        Doc(\n            \"\"\"\n            Any additional JSON schema data.\n            \"\"\"\n        ),\n    ] = None,\n    **extra: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            Include extra fields used by the JSON Schema.\n            \"\"\"\n        ),\n        deprecated(\n            \"\"\"\n            The `extra` kwargs is deprecated. Use `json_schema_extra` instead.\n            \"\"\"\n        ),\n    ],\n) -> Any:\n    return params.File(\n        default=default,\n        default_factory=default_factory,\n        media_type=media_type,\n        alias=alias,\n        alias_priority=alias_priority,\n        validation_alias=validation_alias,\n        serialization_alias=serialization_alias,\n        title=title,\n        description=description,\n        gt=gt,\n        ge=ge,\n        lt=lt,\n        le=le,\n        min_length=min_length,\n        max_length=max_length,\n        pattern=pattern,\n        regex=regex,\n        discriminator=discriminator,\n        strict=strict,\n        multiple_of=multiple_of,\n        allow_inf_nan=allow_inf_nan,\n        max_digits=max_digits,\n        decimal_places=decimal_places,\n        example=example,\n        examples=examples,\n        openapi_examples=openapi_examples,\n        deprecated=deprecated,\n        include_in_schema=include_in_schema,\n        json_schema_extra=json_schema_extra,\n        **extra,\n    )\n\n\ndef Depends(  # noqa: N802\n    dependency: Annotated[\n        Callable[..., Any] | None,\n        Doc(\n            \"\"\"\n            A \"dependable\" callable (like a function).\n\n            Don't call it directly, FastAPI will call it for you, just pass the object\n            directly.\n\n            Read more about it in the\n            [FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/)\n            \"\"\"\n        ),\n    ] = None,\n    *,\n    use_cache: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            By default, after a dependency is called the first time in a request, if\n            the dependency is declared again for the rest of the request (for example\n            if the dependency is needed by several dependencies), the value will be\n            re-used for the rest of the request.\n\n            Set `use_cache` to `False` to disable this behavior and ensure the\n            dependency is called again (if declared more than once) in the same request.\n\n            Read more about it in the\n            [FastAPI docs about sub-dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/sub-dependencies/#using-the-same-dependency-multiple-times)\n            \"\"\"\n        ),\n    ] = True,\n    scope: Annotated[\n        Literal[\"function\", \"request\"] | None,\n        Doc(\n            \"\"\"\n            Mainly for dependencies with `yield`, define when the dependency function\n            should start (the code before `yield`) and when it should end (the code\n            after `yield`).\n\n            * `\"function\"`: start the dependency before the *path operation function*\n                that handles the request, end the dependency after the *path operation\n                function* ends, but **before** the response is sent back to the client.\n                So, the dependency function will be executed **around** the *path operation\n                **function***.\n            * `\"request\"`: start the dependency before the *path operation function*\n                that handles the request (similar to when using `\"function\"`), but end\n                **after** the response is sent back to the client. So, the dependency\n                function will be executed **around** the **request** and response cycle.\n\n            Read more about it in the\n            [FastAPI docs for FastAPI Dependencies with yield](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#early-exit-and-scope)\n            \"\"\"\n        ),\n    ] = None,\n) -> Any:\n    \"\"\"\n    Declare a FastAPI dependency.\n\n    It takes a single \"dependable\" callable (like a function).\n\n    Don't call it directly, FastAPI will call it for you.\n\n    Read more about it in the\n    [FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/).\n\n    **Example**\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import Depends, FastAPI\n\n    app = FastAPI()\n\n\n    async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):\n        return {\"q\": q, \"skip\": skip, \"limit\": limit}\n\n\n    @app.get(\"/items/\")\n    async def read_items(commons: Annotated[dict, Depends(common_parameters)]):\n        return commons\n    ```\n    \"\"\"\n    return params.Depends(dependency=dependency, use_cache=use_cache, scope=scope)\n\n\ndef Security(  # noqa: N802\n    dependency: Annotated[\n        Callable[..., Any] | None,\n        Doc(\n            \"\"\"\n            A \"dependable\" callable (like a function).\n\n            Don't call it directly, FastAPI will call it for you, just pass the object\n            directly.\n\n            Read more about it in the\n            [FastAPI docs for Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/)\n            \"\"\"\n        ),\n    ] = None,\n    *,\n    scopes: Annotated[\n        Sequence[str] | None,\n        Doc(\n            \"\"\"\n            OAuth2 scopes required for the *path operation* that uses this Security\n            dependency.\n\n            The term \"scope\" comes from the OAuth2 specification, it seems to be\n            intentionally vague and interpretable. It normally refers to permissions,\n            in cases to roles.\n\n            These scopes are integrated with OpenAPI (and the API docs at `/docs`).\n            So they are visible in the OpenAPI specification.\n\n            Read more about it in the\n            [FastAPI docs about OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/)\n            \"\"\"\n        ),\n    ] = None,\n    use_cache: Annotated[\n        bool,\n        Doc(\n            \"\"\"\n            By default, after a dependency is called the first time in a request, if\n            the dependency is declared again for the rest of the request (for example\n            if the dependency is needed by several dependencies), the value will be\n            re-used for the rest of the request.\n\n            Set `use_cache` to `False` to disable this behavior and ensure the\n            dependency is called again (if declared more than once) in the same request.\n\n            Read more about it in the\n            [FastAPI docs about sub-dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/sub-dependencies/#using-the-same-dependency-multiple-times)\n            \"\"\"\n        ),\n    ] = True,\n) -> Any:\n    \"\"\"\n    Declare a FastAPI Security dependency.\n\n    The only difference with a regular dependency is that it can declare OAuth2\n    scopes that will be integrated with OpenAPI and the automatic UI docs (by default\n    at `/docs`).\n\n    It takes a single \"dependable\" callable (like a function).\n\n    Don't call it directly, FastAPI will call it for you.\n\n    Read more about it in the\n    [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/) and\n    in the\n    [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/).\n\n    **Example**\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import Security, FastAPI\n\n    from .db import User\n    from .security import get_current_active_user\n\n    app = FastAPI()\n\n    @app.get(\"/users/me/items/\")\n    async def read_own_items(\n        current_user: Annotated[User, Security(get_current_active_user, scopes=[\"items\"])]\n    ):\n        return [{\"item_id\": \"Foo\", \"owner\": current_user.username}]\n    ```\n    \"\"\"\n    return params.Security(dependency=dependency, scopes=scopes, use_cache=use_cache)\n"
  },
  {
    "path": "fastapi/params.py",
    "content": "import warnings\nfrom collections.abc import Callable, Sequence\nfrom dataclasses import dataclass\nfrom enum import Enum\nfrom typing import Annotated, Any, Literal\n\nfrom fastapi.exceptions import FastAPIDeprecationWarning\nfrom fastapi.openapi.models import Example\nfrom pydantic import AliasChoices, AliasPath\nfrom pydantic.fields import FieldInfo\nfrom typing_extensions import deprecated\n\nfrom ._compat import (\n    Undefined,\n)\nfrom .datastructures import _Unset\n\n\nclass ParamTypes(Enum):\n    query = \"query\"\n    header = \"header\"\n    path = \"path\"\n    cookie = \"cookie\"\n\n\nclass Param(FieldInfo):  # type: ignore[misc]  # ty: ignore[subclass-of-final-class]\n    in_: ParamTypes\n\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        if example is not _Unset:\n            warnings.warn(\n                \"`example` has been deprecated, please use `examples` instead\",\n                category=FastAPIDeprecationWarning,\n                stacklevel=4,\n            )\n        self.example = example\n        self.include_in_schema = include_in_schema\n        self.openapi_examples = openapi_examples\n        kwargs = dict(\n            default=default,\n            default_factory=default_factory,\n            alias=alias,\n            title=title,\n            description=description,\n            gt=gt,\n            ge=ge,\n            lt=lt,\n            le=le,\n            min_length=min_length,\n            max_length=max_length,\n            discriminator=discriminator,\n            multiple_of=multiple_of,\n            allow_inf_nan=allow_inf_nan,\n            max_digits=max_digits,\n            decimal_places=decimal_places,\n            **extra,\n        )\n        if examples is not None:\n            kwargs[\"examples\"] = examples\n        if regex is not None:\n            warnings.warn(\n                \"`regex` has been deprecated, please use `pattern` instead\",\n                category=FastAPIDeprecationWarning,\n                stacklevel=4,\n            )\n        current_json_schema_extra = json_schema_extra or extra\n        kwargs[\"deprecated\"] = deprecated\n\n        if serialization_alias in (_Unset, None) and isinstance(alias, str):\n            serialization_alias = alias\n        if validation_alias in (_Unset, None):\n            validation_alias = alias\n        kwargs.update(\n            {\n                \"annotation\": annotation,\n                \"alias_priority\": alias_priority,\n                \"validation_alias\": validation_alias,\n                \"serialization_alias\": serialization_alias,\n                \"strict\": strict,\n                \"json_schema_extra\": current_json_schema_extra,\n            }\n        )\n        kwargs[\"pattern\"] = pattern or regex\n\n        use_kwargs = {k: v for k, v in kwargs.items() if v is not _Unset}\n\n        super().__init__(**use_kwargs)  # ty: ignore[invalid-argument-type]\n\n    def __repr__(self) -> str:\n        return f\"{self.__class__.__name__}({self.default})\"\n\n\nclass Path(Param):  # type: ignore[misc]\n    in_ = ParamTypes.path\n\n    def __init__(\n        self,\n        default: Any = ...,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        assert default is ..., \"Path parameters cannot have a default value\"\n        self.in_ = self.in_\n        super().__init__(\n            default=default,\n            default_factory=default_factory,\n            annotation=annotation,\n            alias=alias,\n            alias_priority=alias_priority,\n            validation_alias=validation_alias,\n            serialization_alias=serialization_alias,\n            title=title,\n            description=description,\n            gt=gt,\n            ge=ge,\n            lt=lt,\n            le=le,\n            min_length=min_length,\n            max_length=max_length,\n            pattern=pattern,\n            regex=regex,\n            discriminator=discriminator,\n            strict=strict,\n            multiple_of=multiple_of,\n            allow_inf_nan=allow_inf_nan,\n            max_digits=max_digits,\n            decimal_places=decimal_places,\n            deprecated=deprecated,\n            example=example,\n            examples=examples,\n            openapi_examples=openapi_examples,\n            include_in_schema=include_in_schema,\n            json_schema_extra=json_schema_extra,\n            **extra,\n        )\n\n\nclass Query(Param):  # type: ignore[misc]\n    in_ = ParamTypes.query\n\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        super().__init__(\n            default=default,\n            default_factory=default_factory,\n            annotation=annotation,\n            alias=alias,\n            alias_priority=alias_priority,\n            validation_alias=validation_alias,\n            serialization_alias=serialization_alias,\n            title=title,\n            description=description,\n            gt=gt,\n            ge=ge,\n            lt=lt,\n            le=le,\n            min_length=min_length,\n            max_length=max_length,\n            pattern=pattern,\n            regex=regex,\n            discriminator=discriminator,\n            strict=strict,\n            multiple_of=multiple_of,\n            allow_inf_nan=allow_inf_nan,\n            max_digits=max_digits,\n            decimal_places=decimal_places,\n            deprecated=deprecated,\n            example=example,\n            examples=examples,\n            openapi_examples=openapi_examples,\n            include_in_schema=include_in_schema,\n            json_schema_extra=json_schema_extra,\n            **extra,\n        )\n\n\nclass Header(Param):  # type: ignore[misc]\n    in_ = ParamTypes.header\n\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        convert_underscores: bool = True,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        self.convert_underscores = convert_underscores\n        super().__init__(\n            default=default,\n            default_factory=default_factory,\n            annotation=annotation,\n            alias=alias,\n            alias_priority=alias_priority,\n            validation_alias=validation_alias,\n            serialization_alias=serialization_alias,\n            title=title,\n            description=description,\n            gt=gt,\n            ge=ge,\n            lt=lt,\n            le=le,\n            min_length=min_length,\n            max_length=max_length,\n            pattern=pattern,\n            regex=regex,\n            discriminator=discriminator,\n            strict=strict,\n            multiple_of=multiple_of,\n            allow_inf_nan=allow_inf_nan,\n            max_digits=max_digits,\n            decimal_places=decimal_places,\n            deprecated=deprecated,\n            example=example,\n            examples=examples,\n            openapi_examples=openapi_examples,\n            include_in_schema=include_in_schema,\n            json_schema_extra=json_schema_extra,\n            **extra,\n        )\n\n\nclass Cookie(Param):  # type: ignore[misc]\n    in_ = ParamTypes.cookie\n\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        super().__init__(\n            default=default,\n            default_factory=default_factory,\n            annotation=annotation,\n            alias=alias,\n            alias_priority=alias_priority,\n            validation_alias=validation_alias,\n            serialization_alias=serialization_alias,\n            title=title,\n            description=description,\n            gt=gt,\n            ge=ge,\n            lt=lt,\n            le=le,\n            min_length=min_length,\n            max_length=max_length,\n            pattern=pattern,\n            regex=regex,\n            discriminator=discriminator,\n            strict=strict,\n            multiple_of=multiple_of,\n            allow_inf_nan=allow_inf_nan,\n            max_digits=max_digits,\n            decimal_places=decimal_places,\n            deprecated=deprecated,\n            example=example,\n            examples=examples,\n            openapi_examples=openapi_examples,\n            include_in_schema=include_in_schema,\n            json_schema_extra=json_schema_extra,\n            **extra,\n        )\n\n\nclass Body(FieldInfo):  # type: ignore[misc]  # ty: ignore[subclass-of-final-class]\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        embed: bool | None = None,\n        media_type: str = \"application/json\",\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        self.embed = embed\n        self.media_type = media_type\n        if example is not _Unset:\n            warnings.warn(\n                \"`example` has been deprecated, please use `examples` instead\",\n                category=FastAPIDeprecationWarning,\n                stacklevel=4,\n            )\n        self.example = example\n        self.include_in_schema = include_in_schema\n        self.openapi_examples = openapi_examples\n        kwargs = dict(\n            default=default,\n            default_factory=default_factory,\n            alias=alias,\n            title=title,\n            description=description,\n            gt=gt,\n            ge=ge,\n            lt=lt,\n            le=le,\n            min_length=min_length,\n            max_length=max_length,\n            discriminator=discriminator,\n            multiple_of=multiple_of,\n            allow_inf_nan=allow_inf_nan,\n            max_digits=max_digits,\n            decimal_places=decimal_places,\n            **extra,\n        )\n        if examples is not None:\n            kwargs[\"examples\"] = examples\n        if regex is not None:\n            warnings.warn(\n                \"`regex` has been deprecated, please use `pattern` instead\",\n                category=FastAPIDeprecationWarning,\n                stacklevel=4,\n            )\n        current_json_schema_extra = json_schema_extra or extra\n        kwargs[\"deprecated\"] = deprecated\n        if serialization_alias in (_Unset, None) and isinstance(alias, str):\n            serialization_alias = alias\n        if validation_alias in (_Unset, None):\n            validation_alias = alias\n        kwargs.update(\n            {\n                \"annotation\": annotation,\n                \"alias_priority\": alias_priority,\n                \"validation_alias\": validation_alias,\n                \"serialization_alias\": serialization_alias,\n                \"strict\": strict,\n                \"json_schema_extra\": current_json_schema_extra,\n            }\n        )\n        kwargs[\"pattern\"] = pattern or regex\n\n        use_kwargs = {k: v for k, v in kwargs.items() if v is not _Unset}\n\n        super().__init__(**use_kwargs)  # ty: ignore[invalid-argument-type]\n\n    def __repr__(self) -> str:\n        return f\"{self.__class__.__name__}({self.default})\"\n\n\nclass Form(Body):  # type: ignore[misc]\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        media_type: str = \"application/x-www-form-urlencoded\",\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        super().__init__(\n            default=default,\n            default_factory=default_factory,\n            annotation=annotation,\n            media_type=media_type,\n            alias=alias,\n            alias_priority=alias_priority,\n            validation_alias=validation_alias,\n            serialization_alias=serialization_alias,\n            title=title,\n            description=description,\n            gt=gt,\n            ge=ge,\n            lt=lt,\n            le=le,\n            min_length=min_length,\n            max_length=max_length,\n            pattern=pattern,\n            regex=regex,\n            discriminator=discriminator,\n            strict=strict,\n            multiple_of=multiple_of,\n            allow_inf_nan=allow_inf_nan,\n            max_digits=max_digits,\n            decimal_places=decimal_places,\n            deprecated=deprecated,\n            example=example,\n            examples=examples,\n            openapi_examples=openapi_examples,\n            include_in_schema=include_in_schema,\n            json_schema_extra=json_schema_extra,\n            **extra,\n        )\n\n\nclass File(Form):  # type: ignore[misc]\n    def __init__(\n        self,\n        default: Any = Undefined,\n        *,\n        default_factory: Callable[[], Any] | None = _Unset,\n        annotation: Any | None = None,\n        media_type: str = \"multipart/form-data\",\n        alias: str | None = None,\n        alias_priority: int | None = _Unset,\n        validation_alias: str | AliasPath | AliasChoices | None = None,\n        serialization_alias: str | None = None,\n        title: str | None = None,\n        description: str | None = None,\n        gt: float | None = None,\n        ge: float | None = None,\n        lt: float | None = None,\n        le: float | None = None,\n        min_length: int | None = None,\n        max_length: int | None = None,\n        pattern: str | None = None,\n        regex: Annotated[\n            str | None,\n            deprecated(\n                \"Deprecated in FastAPI 0.100.0 and Pydantic v2, use `pattern` instead.\"\n            ),\n        ] = None,\n        discriminator: str | None = None,\n        strict: bool | None = _Unset,\n        multiple_of: float | None = _Unset,\n        allow_inf_nan: bool | None = _Unset,\n        max_digits: int | None = _Unset,\n        decimal_places: int | None = _Unset,\n        examples: list[Any] | None = None,\n        example: Annotated[\n            Any | None,\n            deprecated(\n                \"Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, \"\n                \"although still supported. Use examples instead.\"\n            ),\n        ] = _Unset,\n        openapi_examples: dict[str, Example] | None = None,\n        deprecated: deprecated | str | bool | None = None,\n        include_in_schema: bool = True,\n        json_schema_extra: dict[str, Any] | None = None,\n        **extra: Any,\n    ):\n        super().__init__(\n            default=default,\n            default_factory=default_factory,\n            annotation=annotation,\n            media_type=media_type,\n            alias=alias,\n            alias_priority=alias_priority,\n            validation_alias=validation_alias,\n            serialization_alias=serialization_alias,\n            title=title,\n            description=description,\n            gt=gt,\n            ge=ge,\n            lt=lt,\n            le=le,\n            min_length=min_length,\n            max_length=max_length,\n            pattern=pattern,\n            regex=regex,\n            discriminator=discriminator,\n            strict=strict,\n            multiple_of=multiple_of,\n            allow_inf_nan=allow_inf_nan,\n            max_digits=max_digits,\n            decimal_places=decimal_places,\n            deprecated=deprecated,\n            example=example,\n            examples=examples,\n            openapi_examples=openapi_examples,\n            include_in_schema=include_in_schema,\n            json_schema_extra=json_schema_extra,\n            **extra,\n        )\n\n\n@dataclass(frozen=True)\nclass Depends:\n    dependency: Callable[..., Any] | None = None\n    use_cache: bool = True\n    scope: Literal[\"function\", \"request\"] | None = None\n\n\n@dataclass(frozen=True)\nclass Security(Depends):\n    scopes: Sequence[str] | None = None\n"
  },
  {
    "path": "fastapi/py.typed",
    "content": ""
  },
  {
    "path": "fastapi/requests.py",
    "content": "from starlette.requests import HTTPConnection as HTTPConnection  # noqa: F401\nfrom starlette.requests import Request as Request  # noqa: F401\n"
  },
  {
    "path": "fastapi/responses.py",
    "content": "import importlib\nfrom typing import Any, Protocol, cast\n\nfrom fastapi.exceptions import FastAPIDeprecationWarning\nfrom fastapi.sse import EventSourceResponse as EventSourceResponse  # noqa\nfrom starlette.responses import FileResponse as FileResponse  # noqa\nfrom starlette.responses import HTMLResponse as HTMLResponse  # noqa\nfrom starlette.responses import JSONResponse as JSONResponse  # noqa\nfrom starlette.responses import PlainTextResponse as PlainTextResponse  # noqa\nfrom starlette.responses import RedirectResponse as RedirectResponse  # noqa\nfrom starlette.responses import Response as Response  # noqa\nfrom starlette.responses import StreamingResponse as StreamingResponse  # noqa\nfrom typing_extensions import deprecated\n\n\nclass _UjsonModule(Protocol):\n    def dumps(self, __obj: Any, *, ensure_ascii: bool = ...) -> str: ...\n\n\nclass _OrjsonModule(Protocol):\n    OPT_NON_STR_KEYS: int\n    OPT_SERIALIZE_NUMPY: int\n\n    def dumps(self, __obj: Any, *, option: int = ...) -> bytes: ...\n\n\ntry:\n    ujson = cast(_UjsonModule, importlib.import_module(\"ujson\"))\nexcept ModuleNotFoundError:  # pragma: nocover\n    ujson = None  # type: ignore[assignment]\n\n\ntry:\n    orjson = cast(_OrjsonModule, importlib.import_module(\"orjson\"))\nexcept ModuleNotFoundError:  # pragma: nocover\n    orjson = None  # type: ignore[assignment]\n\n\n@deprecated(\n    \"UJSONResponse is deprecated, FastAPI now serializes data directly to JSON \"\n    \"bytes via Pydantic when a return type or response model is set, which is \"\n    \"faster and doesn't need a custom response class. Read more in the FastAPI \"\n    \"docs: https://fastapi.tiangolo.com/advanced/custom-response/#orjson-or-response-model \"\n    \"and https://fastapi.tiangolo.com/tutorial/response-model/\",\n    category=FastAPIDeprecationWarning,\n    stacklevel=2,\n)\nclass UJSONResponse(JSONResponse):\n    \"\"\"JSON response using the ujson library to serialize data to JSON.\n\n    **Deprecated**: `UJSONResponse` is deprecated. FastAPI now serializes data\n    directly to JSON bytes via Pydantic when a return type or response model is\n    set, which is faster and doesn't need a custom response class.\n\n    Read more in the\n    [FastAPI docs for Custom Response](https://fastapi.tiangolo.com/advanced/custom-response/#orjson-or-response-model)\n    and the\n    [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).\n\n    **Note**: `ujson` is not included with FastAPI and must be installed\n    separately, e.g. `pip install ujson`.\n    \"\"\"\n\n    def render(self, content: Any) -> bytes:\n        assert ujson is not None, \"ujson must be installed to use UJSONResponse\"\n        return ujson.dumps(content, ensure_ascii=False).encode(\"utf-8\")\n\n\n@deprecated(\n    \"ORJSONResponse is deprecated, FastAPI now serializes data directly to JSON \"\n    \"bytes via Pydantic when a return type or response model is set, which is \"\n    \"faster and doesn't need a custom response class. Read more in the FastAPI \"\n    \"docs: https://fastapi.tiangolo.com/advanced/custom-response/#orjson-or-response-model \"\n    \"and https://fastapi.tiangolo.com/tutorial/response-model/\",\n    category=FastAPIDeprecationWarning,\n    stacklevel=2,\n)\nclass ORJSONResponse(JSONResponse):\n    \"\"\"JSON response using the orjson library to serialize data to JSON.\n\n    **Deprecated**: `ORJSONResponse` is deprecated. FastAPI now serializes data\n    directly to JSON bytes via Pydantic when a return type or response model is\n    set, which is faster and doesn't need a custom response class.\n\n    Read more in the\n    [FastAPI docs for Custom Response](https://fastapi.tiangolo.com/advanced/custom-response/#orjson-or-response-model)\n    and the\n    [FastAPI docs for Response Model](https://fastapi.tiangolo.com/tutorial/response-model/).\n\n    **Note**: `orjson` is not included with FastAPI and must be installed\n    separately, e.g. `pip install orjson`.\n    \"\"\"\n\n    def render(self, content: Any) -> bytes:\n        assert orjson is not None, \"orjson must be installed to use ORJSONResponse\"\n        return orjson.dumps(\n            content, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY\n        )\n"
  },
  {
    "path": "fastapi/security/__init__.py",
    "content": "from .api_key import APIKeyCookie as APIKeyCookie\nfrom .api_key import APIKeyHeader as APIKeyHeader\nfrom .api_key import APIKeyQuery as APIKeyQuery\nfrom .http import HTTPAuthorizationCredentials as HTTPAuthorizationCredentials\nfrom .http import HTTPBasic as HTTPBasic\nfrom .http import HTTPBasicCredentials as HTTPBasicCredentials\nfrom .http import HTTPBearer as HTTPBearer\nfrom .http import HTTPDigest as HTTPDigest\nfrom .oauth2 import OAuth2 as OAuth2\nfrom .oauth2 import OAuth2AuthorizationCodeBearer as OAuth2AuthorizationCodeBearer\nfrom .oauth2 import OAuth2PasswordBearer as OAuth2PasswordBearer\nfrom .oauth2 import OAuth2PasswordRequestForm as OAuth2PasswordRequestForm\nfrom .oauth2 import OAuth2PasswordRequestFormStrict as OAuth2PasswordRequestFormStrict\nfrom .oauth2 import SecurityScopes as SecurityScopes\nfrom .open_id_connect_url import OpenIdConnect as OpenIdConnect\n"
  },
  {
    "path": "fastapi/security/api_key.py",
    "content": "from typing import Annotated\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import APIKey, APIKeyIn\nfrom fastapi.security.base import SecurityBase\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_401_UNAUTHORIZED\n\n\nclass APIKeyBase(SecurityBase):\n    model: APIKey\n\n    def __init__(\n        self,\n        location: APIKeyIn,\n        name: str,\n        description: str | None,\n        scheme_name: str | None,\n        auto_error: bool,\n    ):\n        self.auto_error = auto_error\n\n        self.model: APIKey = APIKey(\n            **{\"in\": location},  # ty: ignore[invalid-argument-type]\n            name=name,\n            description=description,\n        )\n        self.scheme_name = scheme_name or self.__class__.__name__\n\n    def make_not_authenticated_error(self) -> HTTPException:\n        \"\"\"\n        The WWW-Authenticate header is not standardized for API Key authentication but\n        the HTTP specification requires that an error of 401 \"Unauthorized\" must\n        include a WWW-Authenticate header.\n\n        Ref: https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized\n\n        For this, this method sends a custom challenge `APIKey`.\n        \"\"\"\n        return HTTPException(\n            status_code=HTTP_401_UNAUTHORIZED,\n            detail=\"Not authenticated\",\n            headers={\"WWW-Authenticate\": \"APIKey\"},\n        )\n\n    def check_api_key(self, api_key: str | None) -> str | None:\n        if not api_key:\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            return None\n        return api_key\n\n\nclass APIKeyQuery(APIKeyBase):\n    \"\"\"\n    API key authentication using a query parameter.\n\n    This defines the name of the query parameter that should be provided in the request\n    with the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the query parameter automatically and provides it as the\n    dependency result. But it doesn't define how to send that API key to the client.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be a string containing the key value.\n\n    ## Example\n\n    ```python\n    from fastapi import Depends, FastAPI\n    from fastapi.security import APIKeyQuery\n\n    app = FastAPI()\n\n    query_scheme = APIKeyQuery(name=\"api_key\")\n\n\n    @app.get(\"/items/\")\n    async def read_items(api_key: str = Depends(query_scheme)):\n        return {\"api_key\": api_key}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        name: Annotated[\n            str,\n            Doc(\"Query parameter name.\"),\n        ],\n        scheme_name: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the query parameter is not provided, `APIKeyQuery` will\n                automatically cancel the request and send the client an error.\n\n                If `auto_error` is set to `False`, when the query parameter is not\n                available, instead of erroring out, the dependency result will be\n                `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, in a query\n                parameter or in an HTTP Bearer token).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        super().__init__(\n            location=APIKeyIn.query,\n            name=name,\n            scheme_name=scheme_name,\n            description=description,\n            auto_error=auto_error,\n        )\n\n    async def __call__(self, request: Request) -> str | None:\n        api_key = request.query_params.get(self.model.name)\n        return self.check_api_key(api_key)\n\n\nclass APIKeyHeader(APIKeyBase):\n    \"\"\"\n    API key authentication using a header.\n\n    This defines the name of the header that should be provided in the request with\n    the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the header automatically and provides it as the dependency\n    result. But it doesn't define how to send that key to the client.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be a string containing the key value.\n\n    ## Example\n\n    ```python\n    from fastapi import Depends, FastAPI\n    from fastapi.security import APIKeyHeader\n\n    app = FastAPI()\n\n    header_scheme = APIKeyHeader(name=\"x-key\")\n\n\n    @app.get(\"/items/\")\n    async def read_items(key: str = Depends(header_scheme)):\n        return {\"key\": key}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        name: Annotated[str, Doc(\"Header name.\")],\n        scheme_name: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the header is not provided, `APIKeyHeader` will\n                automatically cancel the request and send the client an error.\n\n                If `auto_error` is set to `False`, when the header is not available,\n                instead of erroring out, the dependency result will be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, in a header or\n                in an HTTP Bearer token).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        super().__init__(\n            location=APIKeyIn.header,\n            name=name,\n            scheme_name=scheme_name,\n            description=description,\n            auto_error=auto_error,\n        )\n\n    async def __call__(self, request: Request) -> str | None:\n        api_key = request.headers.get(self.model.name)\n        return self.check_api_key(api_key)\n\n\nclass APIKeyCookie(APIKeyBase):\n    \"\"\"\n    API key authentication using a cookie.\n\n    This defines the name of the cookie that should be provided in the request with\n    the API key and integrates that into the OpenAPI documentation. It extracts\n    the key value sent in the cookie automatically and provides it as the dependency\n    result. But it doesn't define how to set that cookie.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be a string containing the key value.\n\n    ## Example\n\n    ```python\n    from fastapi import Depends, FastAPI\n    from fastapi.security import APIKeyCookie\n\n    app = FastAPI()\n\n    cookie_scheme = APIKeyCookie(name=\"session\")\n\n\n    @app.get(\"/items/\")\n    async def read_items(session: str = Depends(cookie_scheme)):\n        return {\"session\": session}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        name: Annotated[str, Doc(\"Cookie name.\")],\n        scheme_name: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the cookie is not provided, `APIKeyCookie` will\n                automatically cancel the request and send the client an error.\n\n                If `auto_error` is set to `False`, when the cookie is not available,\n                instead of erroring out, the dependency result will be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, in a cookie or\n                in an HTTP Bearer token).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        super().__init__(\n            location=APIKeyIn.cookie,\n            name=name,\n            scheme_name=scheme_name,\n            description=description,\n            auto_error=auto_error,\n        )\n\n    async def __call__(self, request: Request) -> str | None:\n        api_key = request.cookies.get(self.model.name)\n        return self.check_api_key(api_key)\n"
  },
  {
    "path": "fastapi/security/base.py",
    "content": "from fastapi.openapi.models import SecurityBase as SecurityBaseModel\n\n\nclass SecurityBase:\n    model: SecurityBaseModel\n    scheme_name: str\n"
  },
  {
    "path": "fastapi/security/http.py",
    "content": "import binascii\nfrom base64 import b64decode\nfrom typing import Annotated\n\nfrom annotated_doc import Doc\nfrom fastapi.exceptions import HTTPException\nfrom fastapi.openapi.models import HTTPBase as HTTPBaseModel\nfrom fastapi.openapi.models import HTTPBearer as HTTPBearerModel\nfrom fastapi.security.base import SecurityBase\nfrom fastapi.security.utils import get_authorization_scheme_param\nfrom pydantic import BaseModel\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_401_UNAUTHORIZED\n\n\nclass HTTPBasicCredentials(BaseModel):\n    \"\"\"\n    The HTTP Basic credentials given as the result of using `HTTPBasic` in a\n    dependency.\n\n    Read more about it in the\n    [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/).\n    \"\"\"\n\n    username: Annotated[str, Doc(\"The HTTP Basic username.\")]\n    password: Annotated[str, Doc(\"The HTTP Basic password.\")]\n\n\nclass HTTPAuthorizationCredentials(BaseModel):\n    \"\"\"\n    The HTTP authorization credentials in the result of using `HTTPBearer` or\n    `HTTPDigest` in a dependency.\n\n    The HTTP authorization header value is split by the first space.\n\n    The first part is the `scheme`, the second part is the `credentials`.\n\n    For example, in an HTTP Bearer token scheme, the client will send a header\n    like:\n\n    ```\n    Authorization: Bearer deadbeef12346\n    ```\n\n    In this case:\n\n    * `scheme` will have the value `\"Bearer\"`\n    * `credentials` will have the value `\"deadbeef12346\"`\n    \"\"\"\n\n    scheme: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The HTTP authorization scheme extracted from the header value.\n            \"\"\"\n        ),\n    ]\n    credentials: Annotated[\n        str,\n        Doc(\n            \"\"\"\n            The HTTP authorization credentials extracted from the header value.\n            \"\"\"\n        ),\n    ]\n\n\nclass HTTPBase(SecurityBase):\n    model: HTTPBaseModel\n\n    def __init__(\n        self,\n        *,\n        scheme: str,\n        scheme_name: str | None = None,\n        description: str | None = None,\n        auto_error: bool = True,\n    ):\n        self.model = HTTPBaseModel(scheme=scheme, description=description)\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    def make_authenticate_headers(self) -> dict[str, str]:\n        return {\"WWW-Authenticate\": f\"{self.model.scheme.title()}\"}\n\n    def make_not_authenticated_error(self) -> HTTPException:\n        return HTTPException(\n            status_code=HTTP_401_UNAUTHORIZED,\n            detail=\"Not authenticated\",\n            headers=self.make_authenticate_headers(),\n        )\n\n    async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            else:\n                return None\n        return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)\n\n\nclass HTTPBasic(HTTPBase):\n    \"\"\"\n    HTTP Basic authentication.\n\n    Ref: https://datatracker.ietf.org/doc/html/rfc7617\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be an `HTTPBasicCredentials` object containing the\n    `username` and the `password`.\n\n    Read more about it in the\n    [FastAPI docs for HTTP Basic Auth](https://fastapi.tiangolo.com/advanced/security/http-basic-auth/).\n\n    ## Example\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import Depends, FastAPI\n    from fastapi.security import HTTPBasic, HTTPBasicCredentials\n\n    app = FastAPI()\n\n    security = HTTPBasic()\n\n\n    @app.get(\"/users/me\")\n    def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]):\n        return {\"username\": credentials.username, \"password\": credentials.password}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        scheme_name: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        realm: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                HTTP Basic authentication realm.\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the HTTP Basic authentication is not provided (a\n                header), `HTTPBasic` will automatically cancel the request and send the\n                client an error.\n\n                If `auto_error` is set to `False`, when the HTTP Basic authentication\n                is not available, instead of erroring out, the dependency result will\n                be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, in HTTP Basic\n                authentication or in an HTTP Bearer token).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        self.model = HTTPBaseModel(scheme=\"basic\", description=description)\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.realm = realm\n        self.auto_error = auto_error\n\n    def make_authenticate_headers(self) -> dict[str, str]:\n        if self.realm:\n            return {\"WWW-Authenticate\": f'Basic realm=\"{self.realm}\"'}\n        return {\"WWW-Authenticate\": \"Basic\"}\n\n    async def __call__(  # type: ignore\n        self, request: Request\n    ) -> HTTPBasicCredentials | None:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, param = get_authorization_scheme_param(authorization)\n        if not authorization or scheme.lower() != \"basic\":\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            else:\n                return None\n        try:\n            data = b64decode(param).decode(\"ascii\")\n        except (ValueError, UnicodeDecodeError, binascii.Error) as e:\n            raise self.make_not_authenticated_error() from e\n        username, separator, password = data.partition(\":\")\n        if not separator:\n            raise self.make_not_authenticated_error()\n        return HTTPBasicCredentials(username=username, password=password)\n\n\nclass HTTPBearer(HTTPBase):\n    \"\"\"\n    HTTP Bearer token authentication.\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be an `HTTPAuthorizationCredentials` object containing\n    the `scheme` and the `credentials`.\n\n    ## Example\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import Depends, FastAPI\n    from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer\n\n    app = FastAPI()\n\n    security = HTTPBearer()\n\n\n    @app.get(\"/users/me\")\n    def read_current_user(\n        credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]\n    ):\n        return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        bearerFormat: Annotated[str | None, Doc(\"Bearer token format.\")] = None,\n        scheme_name: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the HTTP Bearer token is not provided (in an\n                `Authorization` header), `HTTPBearer` will automatically cancel the\n                request and send the client an error.\n\n                If `auto_error` is set to `False`, when the HTTP Bearer token\n                is not available, instead of erroring out, the dependency result will\n                be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, in an HTTP\n                Bearer token or in a cookie).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        self.model = HTTPBearerModel(bearerFormat=bearerFormat, description=description)\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            else:\n                return None\n        if scheme.lower() != \"bearer\":\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            else:\n                return None\n        return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)\n\n\nclass HTTPDigest(HTTPBase):\n    \"\"\"\n    HTTP Digest authentication.\n\n    **Warning**: this is only a stub to connect the components with OpenAPI in FastAPI,\n    but it doesn't implement the full Digest scheme, you would need to subclass it\n    and implement it in your code.\n\n    Ref: https://datatracker.ietf.org/doc/html/rfc7616\n\n    ## Usage\n\n    Create an instance object and use that object as the dependency in `Depends()`.\n\n    The dependency result will be an `HTTPAuthorizationCredentials` object containing\n    the `scheme` and the `credentials`.\n\n    ## Example\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import Depends, FastAPI\n    from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest\n\n    app = FastAPI()\n\n    security = HTTPDigest()\n\n\n    @app.get(\"/users/me\")\n    def read_current_user(\n        credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]\n    ):\n        return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n    ```\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        scheme_name: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if the HTTP Digest is not provided, `HTTPDigest` will\n                automatically cancel the request and send the client an error.\n\n                If `auto_error` is set to `False`, when the HTTP Digest is not\n                available, instead of erroring out, the dependency result will\n                be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, in HTTP\n                Digest or in a cookie).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        self.model = HTTPBaseModel(scheme=\"digest\", description=description)\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    async def __call__(self, request: Request) -> HTTPAuthorizationCredentials | None:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, credentials = get_authorization_scheme_param(authorization)\n        if not (authorization and scheme and credentials):\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            else:\n                return None\n        if scheme.lower() != \"digest\":\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            else:\n                return None\n        return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)\n"
  },
  {
    "path": "fastapi/security/oauth2.py",
    "content": "from typing import Annotated, Any, cast\n\nfrom annotated_doc import Doc\nfrom fastapi.exceptions import HTTPException\nfrom fastapi.openapi.models import OAuth2 as OAuth2Model\nfrom fastapi.openapi.models import OAuthFlows as OAuthFlowsModel\nfrom fastapi.param_functions import Form\nfrom fastapi.security.base import SecurityBase\nfrom fastapi.security.utils import get_authorization_scheme_param\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_401_UNAUTHORIZED\n\n\nclass OAuth2PasswordRequestForm:\n    \"\"\"\n    This is a dependency class to collect the `username` and `password` as form data\n    for an OAuth2 password flow.\n\n    The OAuth2 specification dictates that for a password flow the data should be\n    collected using form data (instead of JSON) and that it should have the specific\n    fields `username` and `password`.\n\n    All the initialization parameters are extracted from the request.\n\n    Read more about it in the\n    [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n\n    ## Example\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import Depends, FastAPI\n    from fastapi.security import OAuth2PasswordRequestForm\n\n    app = FastAPI()\n\n\n    @app.post(\"/login\")\n    def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):\n        data = {}\n        data[\"scopes\"] = []\n        for scope in form_data.scopes:\n            data[\"scopes\"].append(scope)\n        if form_data.client_id:\n            data[\"client_id\"] = form_data.client_id\n        if form_data.client_secret:\n            data[\"client_secret\"] = form_data.client_secret\n        return data\n    ```\n\n    Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.\n    You could have custom internal logic to separate it by colon characters (`:`) or\n    similar, and get the two parts `items` and `read`. Many applications do that to\n    group and organize permissions, you could do it as well in your application, just\n    know that it is application specific, it's not part of the specification.\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        grant_type: Annotated[\n            str | None,\n            Form(pattern=\"^password$\"),\n            Doc(\n                \"\"\"\n                The OAuth2 spec says it is required and MUST be the fixed string\n                \"password\". Nevertheless, this dependency class is permissive and\n                allows not passing it. If you want to enforce it, use instead the\n                `OAuth2PasswordRequestFormStrict` dependency.\n\n                Read more about it in the\n                [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n                \"\"\"\n            ),\n        ] = None,\n        username: Annotated[\n            str,\n            Form(),\n            Doc(\n                \"\"\"\n                `username` string. The OAuth2 spec requires the exact field name\n                `username`.\n\n                Read more about it in the\n                [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n                \"\"\"\n            ),\n        ],\n        password: Annotated[\n            str,\n            Form(json_schema_extra={\"format\": \"password\"}),\n            Doc(\n                \"\"\"\n                `password` string. The OAuth2 spec requires the exact field name\n                `password`.\n\n                Read more about it in the\n                [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n                \"\"\"\n            ),\n        ],\n        scope: Annotated[\n            str,\n            Form(),\n            Doc(\n                \"\"\"\n                A single string with actually several scopes separated by spaces. Each\n                scope is also a string.\n\n                For example, a single string with:\n\n                ```python\n                \"items:read items:write users:read profile openid\"\n                ````\n\n                would represent the scopes:\n\n                * `items:read`\n                * `items:write`\n                * `users:read`\n                * `profile`\n                * `openid`\n\n                Read more about it in the\n                [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n                \"\"\"\n            ),\n        ] = \"\",\n        client_id: Annotated[\n            str | None,\n            Form(),\n            Doc(\n                \"\"\"\n                If there's a `client_id`, it can be sent as part of the form fields.\n                But the OAuth2 specification recommends sending the `client_id` and\n                `client_secret` (if any) using HTTP Basic auth.\n                \"\"\"\n            ),\n        ] = None,\n        client_secret: Annotated[\n            str | None,\n            Form(json_schema_extra={\"format\": \"password\"}),\n            Doc(\n                \"\"\"\n                If there's a `client_secret` (and a `client_id`), they can be sent\n                as part of the form fields. But the OAuth2 specification recommends\n                sending the `client_id` and `client_secret` (if any) using HTTP Basic\n                auth.\n                \"\"\"\n            ),\n        ] = None,\n    ):\n        self.grant_type = grant_type\n        self.username = username\n        self.password = password\n        self.scopes = scope.split()\n        self.client_id = client_id\n        self.client_secret = client_secret\n\n\nclass OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):\n    \"\"\"\n    This is a dependency class to collect the `username` and `password` as form data\n    for an OAuth2 password flow.\n\n    The OAuth2 specification dictates that for a password flow the data should be\n    collected using form data (instead of JSON) and that it should have the specific\n    fields `username` and `password`.\n\n    All the initialization parameters are extracted from the request.\n\n    The only difference between `OAuth2PasswordRequestFormStrict` and\n    `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the\n    client to send the form field `grant_type` with the value `\"password\"`, which\n    is required in the OAuth2 specification (it seems that for no particular reason),\n    while for `OAuth2PasswordRequestForm` `grant_type` is optional.\n\n    Read more about it in the\n    [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n\n    ## Example\n\n    ```python\n    from typing import Annotated\n\n    from fastapi import Depends, FastAPI\n    from fastapi.security import OAuth2PasswordRequestForm\n\n    app = FastAPI()\n\n\n    @app.post(\"/login\")\n    def login(form_data: Annotated[OAuth2PasswordRequestFormStrict, Depends()]):\n        data = {}\n        data[\"scopes\"] = []\n        for scope in form_data.scopes:\n            data[\"scopes\"].append(scope)\n        if form_data.client_id:\n            data[\"client_id\"] = form_data.client_id\n        if form_data.client_secret:\n            data[\"client_secret\"] = form_data.client_secret\n        return data\n    ```\n\n    Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.\n    You could have custom internal logic to separate it by colon characters (`:`) or\n    similar, and get the two parts `items` and `read`. Many applications do that to\n    group and organize permissions, you could do it as well in your application, just\n    know that it is application specific, it's not part of the specification.\n\n\n    grant_type: the OAuth2 spec says it is required and MUST be the fixed string \"password\".\n        This dependency is strict about it. If you want to be permissive, use instead the\n        OAuth2PasswordRequestForm dependency class.\n    username: username string. The OAuth2 spec requires the exact field name \"username\".\n    password: password string. The OAuth2 spec requires the exact field name \"password\".\n    scope: Optional string. Several scopes (each one a string) separated by spaces. E.g.\n        \"items:read items:write users:read profile openid\"\n    client_id: optional string. OAuth2 recommends sending the client_id and client_secret (if any)\n        using HTTP Basic auth, as: client_id:client_secret\n    client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any)\n        using HTTP Basic auth, as: client_id:client_secret\n    \"\"\"\n\n    def __init__(\n        self,\n        grant_type: Annotated[\n            str,\n            Form(pattern=\"^password$\"),\n            Doc(\n                \"\"\"\n                The OAuth2 spec says it is required and MUST be the fixed string\n                \"password\". This dependency is strict about it. If you want to be\n                permissive, use instead the `OAuth2PasswordRequestForm` dependency\n                class.\n\n                Read more about it in the\n                [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n                \"\"\"\n            ),\n        ],\n        username: Annotated[\n            str,\n            Form(),\n            Doc(\n                \"\"\"\n                `username` string. The OAuth2 spec requires the exact field name\n                `username`.\n\n                Read more about it in the\n                [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n                \"\"\"\n            ),\n        ],\n        password: Annotated[\n            str,\n            Form(),\n            Doc(\n                \"\"\"\n                `password` string. The OAuth2 spec requires the exact field name\n                `password`.\n\n                Read more about it in the\n                [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n                \"\"\"\n            ),\n        ],\n        scope: Annotated[\n            str,\n            Form(),\n            Doc(\n                \"\"\"\n                A single string with actually several scopes separated by spaces. Each\n                scope is also a string.\n\n                For example, a single string with:\n\n                ```python\n                \"items:read items:write users:read profile openid\"\n                ````\n\n                would represent the scopes:\n\n                * `items:read`\n                * `items:write`\n                * `users:read`\n                * `profile`\n                * `openid`\n\n                Read more about it in the\n                [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n                \"\"\"\n            ),\n        ] = \"\",\n        client_id: Annotated[\n            str | None,\n            Form(),\n            Doc(\n                \"\"\"\n                If there's a `client_id`, it can be sent as part of the form fields.\n                But the OAuth2 specification recommends sending the `client_id` and\n                `client_secret` (if any) using HTTP Basic auth.\n                \"\"\"\n            ),\n        ] = None,\n        client_secret: Annotated[\n            str | None,\n            Form(),\n            Doc(\n                \"\"\"\n                If there's a `client_secret` (and a `client_id`), they can be sent\n                as part of the form fields. But the OAuth2 specification recommends\n                sending the `client_id` and `client_secret` (if any) using HTTP Basic\n                auth.\n                \"\"\"\n            ),\n        ] = None,\n    ):\n        super().__init__(\n            grant_type=grant_type,\n            username=username,\n            password=password,\n            scope=scope,\n            client_id=client_id,\n            client_secret=client_secret,\n        )\n\n\nclass OAuth2(SecurityBase):\n    \"\"\"\n    This is the base class for OAuth2 authentication, an instance of it would be used\n    as a dependency. All other OAuth2 classes inherit from it and customize it for\n    each OAuth2 flow.\n\n    You normally would not create a new class inheriting from it but use one of the\n    existing subclasses, and maybe compose them if you want to support multiple flows.\n\n    Read more about it in the\n    [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/).\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        flows: Annotated[\n            OAuthFlowsModel | dict[str, dict[str, Any]],\n            Doc(\n                \"\"\"\n                The dictionary of OAuth2 flows.\n                \"\"\"\n            ),\n        ] = OAuthFlowsModel(),\n        scheme_name: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if no HTTP Authorization header is provided, required for\n                OAuth2 authentication, it will automatically cancel the request and\n                send the client an error.\n\n                If `auto_error` is set to `False`, when the HTTP Authorization header\n                is not available, instead of erroring out, the dependency result will\n                be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, with OAuth2\n                or in a cookie).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        self.model = OAuth2Model(\n            flows=cast(OAuthFlowsModel, flows), description=description\n        )\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    def make_not_authenticated_error(self) -> HTTPException:\n        \"\"\"\n        The OAuth 2 specification doesn't define the challenge that should be used,\n        because a `Bearer` token is not really the only option to authenticate.\n\n        But declaring any other authentication challenge would be application-specific\n        as it's not defined in the specification.\n\n        For practical reasons, this method uses the `Bearer` challenge by default, as\n        it's probably the most common one.\n\n        If you are implementing an OAuth2 authentication scheme other than the provided\n        ones in FastAPI (based on bearer tokens), you might want to override this.\n\n        Ref: https://datatracker.ietf.org/doc/html/rfc6749\n        \"\"\"\n        return HTTPException(\n            status_code=HTTP_401_UNAUTHORIZED,\n            detail=\"Not authenticated\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n\n    async def __call__(self, request: Request) -> str | None:\n        authorization = request.headers.get(\"Authorization\")\n        if not authorization:\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            else:\n                return None\n        return authorization\n\n\nclass OAuth2PasswordBearer(OAuth2):\n    \"\"\"\n    OAuth2 flow for authentication using a bearer token obtained with a password.\n    An instance of it would be used as a dependency.\n\n    Read more about it in the\n    [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n    \"\"\"\n\n    def __init__(\n        self,\n        tokenUrl: Annotated[\n            str,\n            Doc(\n                \"\"\"\n                The URL to obtain the OAuth2 token. This would be the *path operation*\n                that has `OAuth2PasswordRequestForm` as a dependency.\n\n                Read more about it in the\n                [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n                \"\"\"\n            ),\n        ],\n        scheme_name: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        scopes: Annotated[\n            dict[str, str] | None,\n            Doc(\n                \"\"\"\n                The OAuth2 scopes that would be required by the *path operations* that\n                use this dependency.\n\n                Read more about it in the\n                [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if no HTTP Authorization header is provided, required for\n                OAuth2 authentication, it will automatically cancel the request and\n                send the client an error.\n\n                If `auto_error` is set to `False`, when the HTTP Authorization header\n                is not available, instead of erroring out, the dependency result will\n                be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, with OAuth2\n                or in a cookie).\n                \"\"\"\n            ),\n        ] = True,\n        refreshUrl: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                The URL to refresh the token and obtain a new one.\n                \"\"\"\n            ),\n        ] = None,\n    ):\n        if not scopes:\n            scopes = {}\n        flows = OAuthFlowsModel(\n            password=cast(\n                Any,\n                {\n                    \"tokenUrl\": tokenUrl,\n                    \"refreshUrl\": refreshUrl,\n                    \"scopes\": scopes,\n                },\n            )\n        )\n        super().__init__(\n            flows=flows,\n            scheme_name=scheme_name,\n            description=description,\n            auto_error=auto_error,\n        )\n\n    async def __call__(self, request: Request) -> str | None:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, param = get_authorization_scheme_param(authorization)\n        if not authorization or scheme.lower() != \"bearer\":\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            else:\n                return None\n        return param\n\n\nclass OAuth2AuthorizationCodeBearer(OAuth2):\n    \"\"\"\n    OAuth2 flow for authentication using a bearer token obtained with an OAuth2 code\n    flow. An instance of it would be used as a dependency.\n    \"\"\"\n\n    def __init__(\n        self,\n        authorizationUrl: str,\n        tokenUrl: Annotated[\n            str,\n            Doc(\n                \"\"\"\n                The URL to obtain the OAuth2 token.\n                \"\"\"\n            ),\n        ],\n        refreshUrl: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                The URL to refresh the token and obtain a new one.\n                \"\"\"\n            ),\n        ] = None,\n        scheme_name: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        scopes: Annotated[\n            dict[str, str] | None,\n            Doc(\n                \"\"\"\n                The OAuth2 scopes that would be required by the *path operations* that\n                use this dependency.\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if no HTTP Authorization header is provided, required for\n                OAuth2 authentication, it will automatically cancel the request and\n                send the client an error.\n\n                If `auto_error` is set to `False`, when the HTTP Authorization header\n                is not available, instead of erroring out, the dependency result will\n                be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, with OAuth2\n                or in a cookie).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        if not scopes:\n            scopes = {}\n        flows = OAuthFlowsModel(\n            authorizationCode=cast(\n                Any,\n                {\n                    \"authorizationUrl\": authorizationUrl,\n                    \"tokenUrl\": tokenUrl,\n                    \"refreshUrl\": refreshUrl,\n                    \"scopes\": scopes,\n                },\n            )\n        )\n        super().__init__(\n            flows=flows,\n            scheme_name=scheme_name,\n            description=description,\n            auto_error=auto_error,\n        )\n\n    async def __call__(self, request: Request) -> str | None:\n        authorization = request.headers.get(\"Authorization\")\n        scheme, param = get_authorization_scheme_param(authorization)\n        if not authorization or scheme.lower() != \"bearer\":\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            else:\n                return None  # pragma: nocover\n        return param\n\n\nclass SecurityScopes:\n    \"\"\"\n    This is a special class that you can define in a parameter in a dependency to\n    obtain the OAuth2 scopes required by all the dependencies in the same chain.\n\n    This way, multiple dependencies can have different scopes, even when used in the\n    same *path operation*. And with this, you can access all the scopes required in\n    all those dependencies in a single place.\n\n    Read more about it in the\n    [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/).\n    \"\"\"\n\n    def __init__(\n        self,\n        scopes: Annotated[\n            list[str] | None,\n            Doc(\n                \"\"\"\n                This will be filled by FastAPI.\n                \"\"\"\n            ),\n        ] = None,\n    ):\n        self.scopes: Annotated[\n            list[str],\n            Doc(\n                \"\"\"\n                The list of all the scopes required by dependencies.\n                \"\"\"\n            ),\n        ] = scopes or []\n        self.scope_str: Annotated[\n            str,\n            Doc(\n                \"\"\"\n                All the scopes required by all the dependencies in a single string\n                separated by spaces, as defined in the OAuth2 specification.\n                \"\"\"\n            ),\n        ] = \" \".join(self.scopes)\n"
  },
  {
    "path": "fastapi/security/open_id_connect_url.py",
    "content": "from typing import Annotated\n\nfrom annotated_doc import Doc\nfrom fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel\nfrom fastapi.security.base import SecurityBase\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_401_UNAUTHORIZED\n\n\nclass OpenIdConnect(SecurityBase):\n    \"\"\"\n    OpenID Connect authentication class. An instance of it would be used as a\n    dependency.\n\n    **Warning**: this is only a stub to connect the components with OpenAPI in FastAPI,\n    but it doesn't implement the full OpenIdConnect scheme, for example, it doesn't use\n    the OpenIDConnect URL. You would need to subclass it and implement it in your\n    code.\n    \"\"\"\n\n    def __init__(\n        self,\n        *,\n        openIdConnectUrl: Annotated[\n            str,\n            Doc(\n                \"\"\"\n            The OpenID Connect URL.\n            \"\"\"\n            ),\n        ],\n        scheme_name: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme name.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        description: Annotated[\n            str | None,\n            Doc(\n                \"\"\"\n                Security scheme description.\n\n                It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n                \"\"\"\n            ),\n        ] = None,\n        auto_error: Annotated[\n            bool,\n            Doc(\n                \"\"\"\n                By default, if no HTTP Authorization header is provided, required for\n                OpenID Connect authentication, it will automatically cancel the request\n                and send the client an error.\n\n                If `auto_error` is set to `False`, when the HTTP Authorization header\n                is not available, instead of erroring out, the dependency result will\n                be `None`.\n\n                This is useful when you want to have optional authentication.\n\n                It is also useful when you want to have authentication that can be\n                provided in one of multiple optional ways (for example, with OpenID\n                Connect or in a cookie).\n                \"\"\"\n            ),\n        ] = True,\n    ):\n        self.model = OpenIdConnectModel(\n            openIdConnectUrl=openIdConnectUrl, description=description\n        )\n        self.scheme_name = scheme_name or self.__class__.__name__\n        self.auto_error = auto_error\n\n    def make_not_authenticated_error(self) -> HTTPException:\n        return HTTPException(\n            status_code=HTTP_401_UNAUTHORIZED,\n            detail=\"Not authenticated\",\n            headers={\"WWW-Authenticate\": \"Bearer\"},\n        )\n\n    async def __call__(self, request: Request) -> str | None:\n        authorization = request.headers.get(\"Authorization\")\n        if not authorization:\n            if self.auto_error:\n                raise self.make_not_authenticated_error()\n            else:\n                return None\n        return authorization\n"
  },
  {
    "path": "fastapi/security/utils.py",
    "content": "def get_authorization_scheme_param(\n    authorization_header_value: str | None,\n) -> tuple[str, str]:\n    if not authorization_header_value:\n        return \"\", \"\"\n    scheme, _, param = authorization_header_value.partition(\" \")\n    return scheme, param.strip()\n"
  },
  {
    "path": "fastapi/sse.py",
    "content": "from typing import Annotated, Any\n\nfrom annotated_doc import Doc\nfrom pydantic import AfterValidator, BaseModel, Field, model_validator\nfrom starlette.responses import StreamingResponse\n\n# Canonical SSE event schema matching the OpenAPI 3.2 spec\n# (Section 4.14.4 \"Special Considerations for Server-Sent Events\")\n_SSE_EVENT_SCHEMA: dict[str, Any] = {\n    \"type\": \"object\",\n    \"properties\": {\n        \"data\": {\"type\": \"string\"},\n        \"event\": {\"type\": \"string\"},\n        \"id\": {\"type\": \"string\"},\n        \"retry\": {\"type\": \"integer\", \"minimum\": 0},\n    },\n}\n\n\nclass EventSourceResponse(StreamingResponse):\n    \"\"\"Streaming response with `text/event-stream` media type.\n\n    Use as `response_class=EventSourceResponse` on a *path operation* that uses `yield`\n    to enable Server Sent Events (SSE) responses.\n\n    Works with **any HTTP method** (`GET`, `POST`, etc.), which makes it compatible\n    with protocols like MCP that stream SSE over `POST`.\n\n    The actual encoding logic lives in the FastAPI routing layer. This class\n    serves mainly as a marker and sets the correct `Content-Type`.\n    \"\"\"\n\n    media_type = \"text/event-stream\"\n\n\ndef _check_id_no_null(v: str | None) -> str | None:\n    if v is not None and \"\\0\" in v:\n        raise ValueError(\"SSE 'id' must not contain null characters\")\n    return v\n\n\nclass ServerSentEvent(BaseModel):\n    \"\"\"Represents a single Server-Sent Event.\n\n    When `yield`ed from a *path operation function* that uses\n    `response_class=EventSourceResponse`, each `ServerSentEvent` is encoded\n    into the [SSE wire format](https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream)\n    (`text/event-stream`).\n\n    If you yield a plain object (dict, Pydantic model, etc.) instead, it is\n    automatically JSON-encoded and sent as the `data:` field.\n\n    All `data` values **including plain strings** are JSON-serialized.\n\n    For example, `data=\"hello\"` produces `data: \"hello\"` on the wire (with\n    quotes).\n    \"\"\"\n\n    data: Annotated[\n        Any,\n        Doc(\n            \"\"\"\n            The event payload.\n\n            Can be any JSON-serializable value: a Pydantic model, dict, list,\n            string, number, etc. It is **always** serialized to JSON: strings\n            are quoted (`\"hello\"` becomes `data: \"hello\"` on the wire).\n\n            Mutually exclusive with `raw_data`.\n            \"\"\"\n        ),\n    ] = None\n    raw_data: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Raw string to send as the `data:` field **without** JSON encoding.\n\n            Use this when you need to send pre-formatted text, HTML fragments,\n            CSV lines, or any non-JSON payload. The string is placed directly\n            into the `data:` field as-is.\n\n            Mutually exclusive with `data`.\n            \"\"\"\n        ),\n    ] = None\n    event: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Optional event type name.\n\n            Maps to `addEventListener(event, ...)` on the browser. When omitted,\n            the browser dispatches on the generic `message` event.\n            \"\"\"\n        ),\n    ] = None\n    id: Annotated[\n        str | None,\n        AfterValidator(_check_id_no_null),\n        Doc(\n            \"\"\"\n            Optional event ID.\n\n            The browser sends this value back as the `Last-Event-ID` header on\n            automatic reconnection. **Must not contain null (`\\\\0`) characters.**\n            \"\"\"\n        ),\n    ] = None\n    retry: Annotated[\n        int | None,\n        Field(ge=0),\n        Doc(\n            \"\"\"\n            Optional reconnection time in **milliseconds**.\n\n            Tells the browser how long to wait before reconnecting after the\n            connection is lost. Must be a non-negative integer.\n            \"\"\"\n        ),\n    ] = None\n    comment: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Optional comment line(s).\n\n            Comment lines start with `:` in the SSE wire format and are ignored by\n            `EventSource` clients. Useful for keep-alive pings to prevent\n            proxy/load-balancer timeouts.\n            \"\"\"\n        ),\n    ] = None\n\n    @model_validator(mode=\"after\")\n    def _check_data_exclusive(self) -> \"ServerSentEvent\":\n        if self.data is not None and self.raw_data is not None:\n            raise ValueError(\n                \"Cannot set both 'data' and 'raw_data' on the same \"\n                \"ServerSentEvent. Use 'data' for JSON-serialized payloads \"\n                \"or 'raw_data' for pre-formatted strings.\"\n            )\n        return self\n\n\ndef format_sse_event(\n    *,\n    data_str: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Pre-serialized data string to use as the `data:` field.\n            \"\"\"\n        ),\n    ] = None,\n    event: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Optional event type name (`event:` field).\n            \"\"\"\n        ),\n    ] = None,\n    id: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Optional event ID (`id:` field).\n            \"\"\"\n        ),\n    ] = None,\n    retry: Annotated[\n        int | None,\n        Doc(\n            \"\"\"\n            Optional reconnection time in milliseconds (`retry:` field).\n            \"\"\"\n        ),\n    ] = None,\n    comment: Annotated[\n        str | None,\n        Doc(\n            \"\"\"\n            Optional comment line(s) (`:` prefix).\n            \"\"\"\n        ),\n    ] = None,\n) -> bytes:\n    \"\"\"Build SSE wire-format bytes from **pre-serialized** data.\n\n    The result always ends with `\\n\\n` (the event terminator).\n    \"\"\"\n    lines: list[str] = []\n\n    if comment is not None:\n        for line in comment.splitlines():\n            lines.append(f\": {line}\")\n\n    if event is not None:\n        lines.append(f\"event: {event}\")\n\n    if data_str is not None:\n        for line in data_str.splitlines():\n            lines.append(f\"data: {line}\")\n\n    if id is not None:\n        lines.append(f\"id: {id}\")\n\n    if retry is not None:\n        lines.append(f\"retry: {retry}\")\n\n    lines.append(\"\")\n    lines.append(\"\")\n    return \"\\n\".join(lines).encode(\"utf-8\")\n\n\n# Keep-alive comment, per the SSE spec recommendation\nKEEPALIVE_COMMENT = b\": ping\\n\\n\"\n\n# Seconds between keep-alive pings when a generator is idle.\n# Private but importable so tests can monkeypatch it.\n_PING_INTERVAL: float = 15.0\n"
  },
  {
    "path": "fastapi/staticfiles.py",
    "content": "from starlette.staticfiles import StaticFiles as StaticFiles  # noqa\n"
  },
  {
    "path": "fastapi/templating.py",
    "content": "from starlette.templating import Jinja2Templates as Jinja2Templates  # noqa\n"
  },
  {
    "path": "fastapi/testclient.py",
    "content": "from starlette.testclient import TestClient as TestClient  # noqa\n"
  },
  {
    "path": "fastapi/types.py",
    "content": "import types\nfrom collections.abc import Callable\nfrom enum import Enum\nfrom typing import Any, TypeVar, Union\n\nfrom pydantic import BaseModel\nfrom pydantic.main import IncEx as IncEx\n\nDecoratedCallable = TypeVar(\"DecoratedCallable\", bound=Callable[..., Any])\nUnionType = getattr(types, \"UnionType\", Union)\nModelNameMap = dict[type[BaseModel] | type[Enum], str]\nDependencyCacheKey = tuple[Callable[..., Any] | None, tuple[str, ...], str]\n"
  },
  {
    "path": "fastapi/utils.py",
    "content": "import re\nimport warnings\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    Literal,\n)\n\nimport fastapi\nfrom fastapi._compat import (\n    ModelField,\n    PydanticSchemaGenerationError,\n    Undefined,\n    annotation_is_pydantic_v1,\n)\nfrom fastapi.datastructures import DefaultPlaceholder, DefaultType\nfrom fastapi.exceptions import FastAPIDeprecationWarning, PydanticV1NotSupportedError\nfrom pydantic.fields import FieldInfo\n\nfrom ._compat import v2\n\nif TYPE_CHECKING:  # pragma: nocover\n    from .routing import APIRoute\n\n\ndef is_body_allowed_for_status_code(status_code: int | str | None) -> bool:\n    if status_code is None:\n        return True\n    # Ref: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#patterned-fields-1\n    if status_code in {\n        \"default\",\n        \"1XX\",\n        \"2XX\",\n        \"3XX\",\n        \"4XX\",\n        \"5XX\",\n    }:\n        return True\n    current_status_code = int(status_code)\n    return not (current_status_code < 200 or current_status_code in {204, 205, 304})\n\n\ndef get_path_param_names(path: str) -> set[str]:\n    return set(re.findall(\"{(.*?)}\", path))\n\n\n_invalid_args_message = (\n    \"Invalid args for response field! Hint: \"\n    \"check that {type_} is a valid Pydantic field type. \"\n    \"If you are using a return type annotation that is not a valid Pydantic \"\n    \"field (e.g. Union[Response, dict, None]) you can disable generating the \"\n    \"response model from the type annotation with the path operation decorator \"\n    \"parameter response_model=None. Read more: \"\n    \"https://fastapi.tiangolo.com/tutorial/response-model/\"\n)\n\n\ndef create_model_field(\n    name: str,\n    type_: Any,\n    default: Any | None = Undefined,\n    field_info: FieldInfo | None = None,\n    alias: str | None = None,\n    mode: Literal[\"validation\", \"serialization\"] = \"validation\",\n) -> ModelField:\n    if annotation_is_pydantic_v1(type_):\n        raise PydanticV1NotSupportedError(\n            \"pydantic.v1 models are no longer supported by FastAPI.\"\n            f\" Please update the response model {type_!r}.\"\n        )\n    field_info = field_info or FieldInfo(annotation=type_, default=default, alias=alias)\n    try:\n        return v2.ModelField(mode=mode, name=name, field_info=field_info)\n    except PydanticSchemaGenerationError:\n        raise fastapi.exceptions.FastAPIError(\n            _invalid_args_message.format(type_=type_)\n        ) from None\n\n\ndef generate_operation_id_for_path(\n    *, name: str, path: str, method: str\n) -> str:  # pragma: nocover\n    warnings.warn(\n        message=\"fastapi.utils.generate_operation_id_for_path() was deprecated, \"\n        \"it is not used internally, and will be removed soon\",\n        category=FastAPIDeprecationWarning,\n        stacklevel=2,\n    )\n    operation_id = f\"{name}{path}\"\n    operation_id = re.sub(r\"\\W\", \"_\", operation_id)\n    operation_id = f\"{operation_id}_{method.lower()}\"\n    return operation_id\n\n\ndef generate_unique_id(route: \"APIRoute\") -> str:\n    operation_id = f\"{route.name}{route.path_format}\"\n    operation_id = re.sub(r\"\\W\", \"_\", operation_id)\n    assert route.methods\n    operation_id = f\"{operation_id}_{list(route.methods)[0].lower()}\"\n    return operation_id\n\n\ndef deep_dict_update(main_dict: dict[Any, Any], update_dict: dict[Any, Any]) -> None:\n    for key, value in update_dict.items():\n        if (\n            key in main_dict\n            and isinstance(main_dict[key], dict)\n            and isinstance(value, dict)\n        ):\n            deep_dict_update(main_dict[key], value)\n        elif (\n            key in main_dict\n            and isinstance(main_dict[key], list)\n            and isinstance(update_dict[key], list)\n        ):\n            main_dict[key] = main_dict[key] + update_dict[key]\n        else:\n            main_dict[key] = value\n\n\ndef get_value_or_default(\n    first_item: DefaultPlaceholder | DefaultType,\n    *extra_items: DefaultPlaceholder | DefaultType,\n) -> DefaultPlaceholder | DefaultType:\n    \"\"\"\n    Pass items or `DefaultPlaceholder`s by descending priority.\n\n    The first one to _not_ be a `DefaultPlaceholder` will be returned.\n\n    Otherwise, the first item (a `DefaultPlaceholder`) will be returned.\n    \"\"\"\n    items = (first_item,) + extra_items\n    for item in items:\n        if not isinstance(item, DefaultPlaceholder):\n            return item\n    return first_item\n"
  },
  {
    "path": "fastapi/websockets.py",
    "content": "from starlette.websockets import WebSocket as WebSocket  # noqa\nfrom starlette.websockets import WebSocketDisconnect as WebSocketDisconnect  # noqa\nfrom starlette.websockets import WebSocketState as WebSocketState  # noqa\n"
  },
  {
    "path": "fastapi-slim/README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://fastapi.tiangolo.com\"><img src=\"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\" alt=\"FastAPI\"></a>\n</p>\n<p align=\"center\">\n    <em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/fastapi/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\" target=\"_blank\">\n    <img src=\"https://github.com/fastapi/fastapi/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/fastapi\" target=\"_blank\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/fastapi.svg\" alt=\"Coverage\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\" target=\"_blank\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n<a href=\"https://pypi.org/project/fastapi\" target=\"_blank\">\n    <img src=\"https://img.shields.io/pypi/pyversions/fastapi.svg?color=%2334D058\" alt=\"Supported Python versions\">\n</a>\n</p>\n\n---\n\n**Documentation**: <a href=\"https://fastapi.tiangolo.com\" target=\"_blank\">https://fastapi.tiangolo.com</a>\n\n**Source Code**: <a href=\"https://github.com/fastapi/fastapi\" target=\"_blank\">https://github.com/fastapi/fastapi</a>\n\n---\n\nFastAPI is a modern, fast (high-performance), web framework for building APIs with Python based on standard Python type hints.\n\n## `fastapi-slim`\n\n⚠️ Do not install this package. ⚠️\n\nThis package, `fastapi-slim`, does nothing other than depend on `fastapi`.\n\nAll the functionality has been integrated into `fastapi`.\n\nThe only reason this package exists is as a migration path for old projects that used to depend on `fastapi-slim`, so that they can get the latest version of `fastapi`.\n\nYou **should not** install this package.\n\nInstall instead:\n\n```bash\npip install fastapi\n```\n\nThis package is deprecated and will stop receiving any updates and published versions.\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\nrequires = [\"pdm-backend\"]\nbuild-backend = \"pdm.backend\"\n\n[project]\nname = \"fastapi\"\ndynamic = [\"version\"]\ndescription = \"FastAPI framework, high performance, easy to learn, fast to code, ready for production\"\nreadme = \"README.md\"\nlicense = \"MIT\"\nlicense-files = [\"LICENSE\"]\nrequires-python = \">=3.10\"\nauthors = [\n    { name = \"Sebastián Ramírez\", email = \"tiangolo@gmail.com\" },\n]\nclassifiers = [\n    \"Intended Audience :: Information Technology\",\n    \"Intended Audience :: System Administrators\",\n    \"Operating System :: OS Independent\",\n    \"Programming Language :: Python :: 3\",\n    \"Programming Language :: Python\",\n    \"Topic :: Internet\",\n    \"Topic :: Software Development :: Libraries :: Application Frameworks\",\n    \"Topic :: Software Development :: Libraries :: Python Modules\",\n    \"Topic :: Software Development :: Libraries\",\n    \"Topic :: Software Development\",\n    \"Typing :: Typed\",\n    \"Development Status :: 4 - Beta\",\n    \"Environment :: Web Environment\",\n    \"Framework :: AsyncIO\",\n    \"Framework :: FastAPI\",\n    \"Framework :: Pydantic\",\n    \"Framework :: Pydantic :: 2\",\n    \"Intended Audience :: Developers\",\n    \"Programming Language :: Python :: 3 :: Only\",\n    \"Programming Language :: Python :: 3.10\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Programming Language :: Python :: 3.12\",\n    \"Programming Language :: Python :: 3.13\",\n    \"Programming Language :: Python :: 3.14\",\n    \"Topic :: Internet :: WWW/HTTP :: HTTP Servers\",\n    \"Topic :: Internet :: WWW/HTTP\",\n]\ndependencies = [\n    \"starlette>=0.46.0\",\n    \"pydantic>=2.9.0\",\n    \"typing-extensions>=4.8.0\",\n    \"typing-inspection>=0.4.2\",\n    \"annotated-doc>=0.0.2\",\n]\n\n[project.urls]\nHomepage = \"https://github.com/fastapi/fastapi\"\nDocumentation = \"https://fastapi.tiangolo.com/\"\nRepository = \"https://github.com/fastapi/fastapi\"\nIssues = \"https://github.com/fastapi/fastapi/issues\"\nChangelog = \"https://fastapi.tiangolo.com/release-notes/\"\n\n[project.optional-dependencies]\nstandard = [\n    \"fastapi-cli[standard] >=0.0.8\",\n    \"fastar >= 0.9.0\",\n    # For the test client\n    \"httpx >=0.23.0,<1.0.0\",\n    # For templates\n    \"jinja2 >=3.1.5\",\n    # For forms and file uploads\n    \"python-multipart >=0.0.18\",\n    # To validate email fields\n    \"email-validator >=2.0.0\",\n    # Uvicorn with uvloop\n    \"uvicorn[standard] >=0.12.0\",\n    # # Settings management\n    \"pydantic-settings >=2.0.0\",\n    # # Extra Pydantic data types\n    \"pydantic-extra-types >=2.0.0\",\n]\n\nstandard-no-fastapi-cloud-cli = [\n    \"fastapi-cli[standard-no-fastapi-cloud-cli] >=0.0.8\",\n    # For the test client\n    \"httpx >=0.23.0,<1.0.0\",\n    # For templates\n    \"jinja2 >=3.1.5\",\n    # For forms and file uploads\n    \"python-multipart >=0.0.18\",\n    # To validate email fields\n    \"email-validator >=2.0.0\",\n    # Uvicorn with uvloop\n    \"uvicorn[standard] >=0.12.0\",\n    # # Settings management\n    \"pydantic-settings >=2.0.0\",\n    # # Extra Pydantic data types\n    \"pydantic-extra-types >=2.0.0\",\n]\n\nall = [\n    \"fastapi-cli[standard] >=0.0.8\",\n    # # For the test client\n    \"httpx >=0.23.0,<1.0.0\",\n    # For templates\n    \"jinja2 >=3.1.5\",\n    # For forms and file uploads\n    \"python-multipart >=0.0.18\",\n    # For Starlette's SessionMiddleware, not commonly used with FastAPI\n    \"itsdangerous >=1.1.0\",\n    # For Starlette's schema generation, would not be used with FastAPI\n    \"pyyaml >=5.3.1\",\n    # To validate email fields\n    \"email-validator >=2.0.0\",\n    # Uvicorn with uvloop\n    \"uvicorn[standard] >=0.12.0\",\n    # Settings management\n    \"pydantic-settings >=2.0.0\",\n    # Extra Pydantic data types\n    \"pydantic-extra-types >=2.0.0\",\n]\n\n[project.scripts]\nfastapi = \"fastapi.cli:main\"\n\n[dependency-groups]\ndev = [\n    { include-group = \"tests\" },\n    { include-group = \"docs\" },\n    { include-group = \"translations\" },\n    \"playwright >=1.57.0\",\n    \"prek >=0.2.22\",\n    \"zizmor >=1.23.1\",\n]\ndocs = [\n    { include-group = \"docs-tests\" },\n    \"black >=25.1.0\",\n    \"cairosvg >=2.8.2\",\n    # for MkDocs live reload\n    \"click==8.2.1\",\n    \"griffe-typingdoc >=0.3.0\",\n    \"griffe-warnings-deprecated >=1.1.0\",\n    \"jieba >=0.42.1\",\n    \"markdown-include-variants >=0.0.8\",\n    \"mdx-include >=1.4.1,<2.0.0\",\n    \"mkdocs-macros-plugin >=1.5.0\",\n    \"mkdocs-material >=9.7.0\",\n    \"mkdocs-redirects >=1.2.1,<1.3.0\",\n    \"mkdocstrings[python] >=0.30.1\",\n    \"pillow >=11.3.0\",\n    \"python-slugify >=8.0.4\",\n    \"pyyaml >=5.3.1,<7.0.0\",\n    \"typer >=0.21.1\",\n]\ndocs-tests = [\n    \"httpx >=0.23.0,<1.0.0\",\n    \"ruff >=0.14.14\",\n]\ngithub-actions = [\n    \"httpx >=0.27.0,<1.0.0\",\n    \"pydantic >=2.9.0,<3.0.0\",\n    \"pydantic-settings >=2.1.0,<3.0.0\",\n    \"pygithub >=2.3.0,<3.0.0\",\n    \"pyyaml >=5.3.1,<7.0.0\",\n    \"smokeshow >=0.5.0\",\n]\ntests = [\n    { include-group = \"docs-tests\" },\n    \"anyio[trio] >=3.2.1,<5.0.0\",\n    \"coverage[toml] >=7.13,<8.0\",\n    \"dirty-equals >=0.9.0\",\n    \"flask >=3.0.0,<4.0.0\",\n    \"inline-snapshot >=0.21.1\",\n    \"mypy >=1.14.1\",\n    \"pwdlib[argon2] >=0.2.1\",\n    \"pyjwt >=2.9.0\",\n    \"pytest >=9.0.0\",\n    \"pytest-codspeed >=4.2.0\",\n    \"pyyaml >=5.3.1,<7.0.0\",\n    \"sqlmodel >=0.0.31\",\n    \"strawberry-graphql >=0.200.0,<1.0.0\",\n    \"ty>=0.0.25\",\n    \"a2wsgi >=1.9.0,<=2.0.0\",\n    \"pytest-xdist[psutil]>=2.5.0\",\n    \"pytest-cov>=4.0.0\",\n    \"pytest-sugar>=1.0.0\",\n    \"pytest-timeout>=2.4.0\",\n]\ntranslations = [\n    \"gitpython >=3.1.46\",\n    \"pydantic-ai >=0.4.10\",\n    \"pygithub >=2.8.1\",\n]\n\n[tool.pdm]\nversion = { source = \"file\", path = \"fastapi/__init__.py\" }\ndistribution = true\n\n[tool.pdm.build]\nsource-includes = [\n    \"tests/\",\n    \"docs_src/\",\n    \"scripts/\",\n    # For a test\n    \"docs/en/docs/img/favicon.png\",\n]\n\n[tool.mypy]\nplugins = [\"pydantic.mypy\"]\nstrict = true\n\n[[tool.mypy.overrides]]\nmodule = \"fastapi.concurrency\"\nwarn_unused_ignores = false\nignore_missing_imports = true\n\n[[tool.mypy.overrides]]\nmodule = \"fastapi.tests.*\"\nignore_missing_imports = true\ncheck_untyped_defs = true\n\n[[tool.mypy.overrides]]\nmodule = \"docs_src.*\"\ndisallow_incomplete_defs = false\ndisallow_untyped_defs = false\ndisallow_untyped_calls = false\n\n[tool.pytest]\nminversion = \"9.0\"\naddopts = [\n  \"--strict-config\",\n  \"--strict-markers\",\n  \"--ignore=docs_src\",\n]\nstrict_xfail = true\nfilterwarnings = [\n    \"error\",\n]\ntimeout = \"20\"\n\n[tool.coverage.run]\nparallel = true\ndata_file = \"coverage/.coverage\"\nsource = [\n    \"docs_src\",\n    \"tests\",\n    \"fastapi\"\n]\nrelative_files = true\ncontext = '${CONTEXT}'\nomit = [\n    \"tests/benchmarks/*\",\n    \"docs_src/response_model/tutorial003_04_py39.py\",\n    \"docs_src/response_model/tutorial003_04_py310.py\",\n    \"docs_src/dependencies/tutorial013_an_py310.py\",  # temporary code example?\n    \"docs_src/dependencies/tutorial014_an_py310.py\",  # temporary code example?\n    # Pydantic v1 migration, no longer tested\n    \"docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py\",\n    \"docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py\",\n    \"docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py\",\n    \"docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py\",\n]\n\n[tool.coverage.report]\nshow_missing = true\nsort = \"-Cover\"\n\n[tool.coverage.html]\nshow_contexts = true\n\n[tool.ruff.lint]\nselect = [\n    \"E\",  # pycodestyle errors\n    \"W\",  # pycodestyle warnings\n    \"F\",  # pyflakes\n    \"I\",  # isort\n    \"B\",  # flake8-bugbear\n    \"C4\",  # flake8-comprehensions\n    \"UP\",  # pyupgrade\n]\nignore = [\n    \"E501\",  # line too long, handled by black\n    \"B008\",  # do not perform function calls in argument defaults\n    \"C901\",  # too complex\n]\n\n[tool.ruff.lint.per-file-ignores]\n\"__init__.py\" = [\"F401\"]\n\"docs_src/custom_request_and_route/tutorial002_an_py310.py\" = [\"B904\"]\n\"docs_src/custom_request_and_route/tutorial002_an_py39.py\" = [\"B904\"]\n\"docs_src/custom_request_and_route/tutorial002_py310.py\" = [\"B904\"]\n\"docs_src/custom_request_and_route/tutorial002_py39.py\" = [\"B904\"]\n\"docs_src/custom_response/tutorial007_py310.py\" = [\"B007\"]\n\"docs_src/custom_response/tutorial007_py39.py\" = [\"B007\"]\n\"docs_src/dataclasses/tutorial003_py39.py\" = [\"I001\"]\n\"docs_src/dependencies/tutorial007_py310.py\" = [\"F821\"]\n\"docs_src/dependencies/tutorial007_py39.py\" = [\"F821\"]\n\"docs_src/dependencies/tutorial008_an_py310.py\" = [\"F821\"]\n\"docs_src/dependencies/tutorial008_an_py39.py\" = [\"F821\"]\n\"docs_src/dependencies/tutorial008_py310.py\" = [\"F821\"]\n\"docs_src/dependencies/tutorial008_py39.py\" = [\"F821\"]\n\"docs_src/dependencies/tutorial008b_an_py310.py\" = [\"B904\"]\n\"docs_src/dependencies/tutorial008b_an_py39.py\" = [\"B904\"]\n\"docs_src/dependencies/tutorial008b_py310.py\" = [\"B904\"]\n\"docs_src/dependencies/tutorial008b_py39.py\" = [\"B904\"]\n\"docs_src/dependencies/tutorial009_py310.py\" = [\"F821\"]\n\"docs_src/dependencies/tutorial009_py39.py\" = [\"F821\"]\n\"docs_src/dependencies/tutorial010_py310.py\" = [\"F821\"]\n\"docs_src/dependencies/tutorial010_py39.py\" = [\"F821\"]\n\"docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py\" = [\"B904\"]\n\"docs_src/path_operation_advanced_configuration/tutorial007_py310.py\" = [\"B904\"]\n\"docs_src/path_operation_advanced_configuration/tutorial007_py39.py\" = [\"B904\"]\n\"docs_src/query_params_str_validations/tutorial012_an_py310.py\" = [\"B006\"]\n\"docs_src/query_params_str_validations/tutorial012_an_py39.py\" = [\"B006\"]\n\"docs_src/query_params_str_validations/tutorial013_an_py310.py\" = [\"B006\"]\n\"docs_src/query_params_str_validations/tutorial013_an_py39.py\" = [\"B006\"]\n\"docs_src/security/tutorial004_an_py310.py\" = [\"B904\"]\n\"docs_src/security/tutorial004_an_py39.py\" = [\"B904\"]\n\"docs_src/security/tutorial004_py310.py\" = [\"B904\"]\n\"docs_src/security/tutorial004_py39.py\" = [\"B904\"]\n\"docs_src/security/tutorial005_an_py310.py\" = [\"B904\"]\n\"docs_src/security/tutorial005_an_py39.py\" = [\"B904\"]\n\"docs_src/security/tutorial005_py310.py\" = [\"B904\"]\n\"docs_src/security/tutorial005_py39.py\" = [\"B904\"]\n\"docs_src/json_base64_bytes/tutorial001_py310.py\" = [\"UP012\"]\n\"docs_src/stream_json_lines/tutorial001_py310.py\" = [\"UP028\"]\n\"docs_src/stream_data/tutorial001_py310.py\" = [\"UP028\"]\n\"docs_src/stream_data/tutorial002_py310.py\" = [\"UP028\"]\n\"docs_src/server_sent_events/tutorial001_py310.py\" = [\"UP028\"]\n\n[tool.ruff.lint.isort]\nknown-third-party = [\"fastapi\", \"pydantic\", \"starlette\"]\n\n[tool.ruff.lint.pyupgrade]\n# Preserve types, even if a file imports `from __future__ import annotations`.\nkeep-runtime-typing = true\n\n[tool.inline-snapshot]\n# default-flags=[\"fix\"]\n# default-flags=[\"create\"]\n\n[tool.typos.files]\nextend-exclude = [\n    \"coverage/\",\n    \"dist/\",\n    \"docs/de/\",\n    \"docs/en/data/\",\n    \"docs/en/docs/img/\",\n    \"docs/en/docs/release-notes.md\",\n    \"docs/es/\",\n    \"docs/fr/\",\n    \"docs/ja/\",\n    \"docs/ko/\",\n    \"docs/language_names.yml\",\n    \"docs/pt/\",\n    \"docs/ru/\",\n    \"docs/tr/\",\n    \"docs/uk/\",\n    \"docs/zh/\",\n    \"docs/zh-hant/\",\n    \"htmlcov/\",\n    \"scripts/general-llm-prompt.md\",\n    \"scripts/tests/test_translation_fixer/test_complex_doc/\",\n    \"site/\",\n    \"site_build/\",\n    \"uv.lock\",\n]\n\n[tool.typos.default.extend-identifiers]\nalls = \"alls\"\n\n[tool.typos.default.extend-words]\nba = \"ba\"\nfo = \"fo\"\nhavin = \"havin\"\nInes = \"Ines\"\nser = \"ser\"\n\n[tool.ty.terminal]\nerror-on-warning = true\n"
  },
  {
    "path": "scripts/add_latest_release_date.py",
    "content": "\"\"\"Check release-notes.md and add today's date to the latest release header if missing.\"\"\"\n\nimport re\nimport sys\nfrom datetime import date\n\nRELEASE_NOTES_FILE = \"docs/en/docs/release-notes.md\"\nRELEASE_HEADER_PATTERN = re.compile(r\"^## (\\d+\\.\\d+\\.\\d+)\\s*(\\(.*\\))?\\s*$\")\n\n\ndef main() -> None:\n    with open(RELEASE_NOTES_FILE) as f:\n        lines = f.readlines()\n\n    for i, line in enumerate(lines):\n        match = RELEASE_HEADER_PATTERN.match(line)\n        if not match:\n            continue\n\n        version = match.group(1)\n        date_part = match.group(2)\n\n        if date_part:\n            print(f\"Latest release {version} already has a date: {date_part}\")\n            sys.exit(0)\n\n        today = date.today().isoformat()\n        lines[i] = f\"## {version} ({today})\\n\"\n        print(f\"Added date: {version} ({today})\")\n\n        with open(RELEASE_NOTES_FILE, \"w\") as f:\n            f.writelines(lines)\n        sys.exit(0)\n\n    print(\"No release header found\")\n    sys.exit(1)\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/contributors.py",
    "content": "import logging\nimport secrets\nimport subprocess\nfrom collections import Counter\nfrom datetime import datetime\nfrom pathlib import Path\nfrom typing import Any\n\nimport httpx\nimport yaml\nfrom github import Github\nfrom pydantic import BaseModel, SecretStr\nfrom pydantic_settings import BaseSettings\n\ngithub_graphql_url = \"https://api.github.com/graphql\"\n\n\nprs_query = \"\"\"\nquery Q($after: String) {\n  repository(name: \"fastapi\", owner: \"fastapi\") {\n    pullRequests(first: 100, after: $after) {\n      edges {\n        cursor\n        node {\n          number\n          labels(first: 100) {\n            nodes {\n              name\n            }\n          }\n          author {\n            login\n            avatarUrl\n            url\n          }\n          title\n          createdAt\n          lastEditedAt\n          updatedAt\n          state\n          reviews(first:100) {\n            nodes {\n              author {\n                login\n                avatarUrl\n                url\n              }\n              state\n            }\n          }\n        }\n      }\n    }\n  }\n}\n\"\"\"\n\n\nclass Author(BaseModel):\n    login: str\n    avatarUrl: str\n    url: str\n\n\nclass LabelNode(BaseModel):\n    name: str\n\n\nclass Labels(BaseModel):\n    nodes: list[LabelNode]\n\n\nclass ReviewNode(BaseModel):\n    author: Author | None = None\n    state: str\n\n\nclass Reviews(BaseModel):\n    nodes: list[ReviewNode]\n\n\nclass PullRequestNode(BaseModel):\n    number: int\n    labels: Labels\n    author: Author | None = None\n    title: str\n    createdAt: datetime\n    lastEditedAt: datetime | None = None\n    updatedAt: datetime | None = None\n    state: str\n    reviews: Reviews\n\n\nclass PullRequestEdge(BaseModel):\n    cursor: str\n    node: PullRequestNode\n\n\nclass PullRequests(BaseModel):\n    edges: list[PullRequestEdge]\n\n\nclass PRsRepository(BaseModel):\n    pullRequests: PullRequests\n\n\nclass PRsResponseData(BaseModel):\n    repository: PRsRepository\n\n\nclass PRsResponse(BaseModel):\n    data: PRsResponseData\n\n\nclass Settings(BaseSettings):\n    github_token: SecretStr\n    github_repository: str\n    httpx_timeout: int = 30\n\n\ndef get_graphql_response(\n    *,\n    settings: Settings,\n    query: str,\n    after: str | None = None,\n) -> dict[str, Any]:\n    headers = {\"Authorization\": f\"token {settings.github_token.get_secret_value()}\"}\n    variables = {\"after\": after}\n    response = httpx.post(\n        github_graphql_url,\n        headers=headers,\n        timeout=settings.httpx_timeout,\n        json={\"query\": query, \"variables\": variables, \"operationName\": \"Q\"},\n    )\n    if response.status_code != 200:\n        logging.error(f\"Response was not 200, after: {after}\")\n        logging.error(response.text)\n        raise RuntimeError(response.text)\n    data = response.json()\n    if \"errors\" in data:\n        logging.error(f\"Errors in response, after: {after}\")\n        logging.error(data[\"errors\"])\n        logging.error(response.text)\n        raise RuntimeError(response.text)\n    return data\n\n\ndef get_graphql_pr_edges(\n    *, settings: Settings, after: str | None = None\n) -> list[PullRequestEdge]:\n    data = get_graphql_response(settings=settings, query=prs_query, after=after)\n    graphql_response = PRsResponse.model_validate(data)\n    return graphql_response.data.repository.pullRequests.edges\n\n\ndef get_pr_nodes(settings: Settings) -> list[PullRequestNode]:\n    pr_nodes: list[PullRequestNode] = []\n    pr_edges = get_graphql_pr_edges(settings=settings)\n\n    while pr_edges:\n        for edge in pr_edges:\n            pr_nodes.append(edge.node)\n        last_edge = pr_edges[-1]\n        pr_edges = get_graphql_pr_edges(settings=settings, after=last_edge.cursor)\n    return pr_nodes\n\n\nclass ContributorsResults(BaseModel):\n    contributors: Counter[str]\n    translation_reviewers: Counter[str]\n    translators: Counter[str]\n    authors: dict[str, Author]\n\n\ndef get_contributors(pr_nodes: list[PullRequestNode]) -> ContributorsResults:\n    contributors = Counter[str]()\n    translation_reviewers = Counter[str]()\n    translators = Counter[str]()\n    authors: dict[str, Author] = {}\n\n    for pr in pr_nodes:\n        if pr.author:\n            authors[pr.author.login] = pr.author\n        is_lang = False\n        for label in pr.labels.nodes:\n            if label.name == \"lang-all\":\n                is_lang = True\n                break\n        for review in pr.reviews.nodes:\n            if review.author:\n                authors[review.author.login] = review.author\n                if is_lang:\n                    translation_reviewers[review.author.login] += 1\n        if pr.state == \"MERGED\" and pr.author:\n            if is_lang:\n                translators[pr.author.login] += 1\n            else:\n                contributors[pr.author.login] += 1\n    return ContributorsResults(\n        contributors=contributors,\n        translation_reviewers=translation_reviewers,\n        translators=translators,\n        authors=authors,\n    )\n\n\ndef get_users_to_write(\n    *,\n    counter: Counter[str],\n    authors: dict[str, Author],\n    min_count: int = 2,\n) -> dict[str, Any]:\n    users: dict[str, Any] = {}\n    for user, count in counter.most_common():\n        if count >= min_count:\n            author = authors[user]\n            users[user] = {\n                \"login\": user,\n                \"count\": count,\n                \"avatarUrl\": author.avatarUrl,\n                \"url\": author.url,\n            }\n    return users\n\n\ndef update_content(*, content_path: Path, new_content: Any) -> bool:\n    old_content = content_path.read_text(encoding=\"utf-8\")\n\n    new_content = yaml.dump(new_content, sort_keys=False, width=200, allow_unicode=True)\n    if old_content == new_content:\n        logging.info(f\"The content hasn't changed for {content_path}\")\n        return False\n    content_path.write_text(new_content, encoding=\"utf-8\")\n    logging.info(f\"Updated {content_path}\")\n    return True\n\n\ndef main() -> None:\n    logging.basicConfig(level=logging.INFO)\n    settings = Settings()\n    logging.info(f\"Using config: {settings.model_dump_json()}\")\n    g = Github(settings.github_token.get_secret_value())\n    repo = g.get_repo(settings.github_repository)\n\n    pr_nodes = get_pr_nodes(settings=settings)\n    contributors_results = get_contributors(pr_nodes=pr_nodes)\n    authors = contributors_results.authors\n\n    top_contributors = get_users_to_write(\n        counter=contributors_results.contributors,\n        authors=authors,\n    )\n\n    top_translators = get_users_to_write(\n        counter=contributors_results.translators,\n        authors=authors,\n    )\n    top_translations_reviewers = get_users_to_write(\n        counter=contributors_results.translation_reviewers,\n        authors=authors,\n    )\n\n    # For local development\n    # contributors_path = Path(\"../docs/en/data/contributors.yml\")\n    contributors_path = Path(\"./docs/en/data/contributors.yml\")\n    # translators_path = Path(\"../docs/en/data/translators.yml\")\n    translators_path = Path(\"./docs/en/data/translators.yml\")\n    # translation_reviewers_path = Path(\"../docs/en/data/translation_reviewers.yml\")\n    translation_reviewers_path = Path(\"./docs/en/data/translation_reviewers.yml\")\n\n    updated = [\n        update_content(content_path=contributors_path, new_content=top_contributors),\n        update_content(content_path=translators_path, new_content=top_translators),\n        update_content(\n            content_path=translation_reviewers_path,\n            new_content=top_translations_reviewers,\n        ),\n    ]\n\n    if not any(updated):\n        logging.info(\"The data hasn't changed, finishing.\")\n        return\n\n    logging.info(\"Setting up GitHub Actions git user\")\n    subprocess.run([\"git\", \"config\", \"user.name\", \"github-actions[bot]\"], check=True)\n    subprocess.run(\n        [\"git\", \"config\", \"user.email\", \"github-actions[bot]@users.noreply.github.com\"],\n        check=True,\n    )\n    branch_name = f\"fastapi-people-contributors-{secrets.token_hex(4)}\"\n    logging.info(f\"Creating a new branch {branch_name}\")\n    subprocess.run([\"git\", \"checkout\", \"-b\", branch_name], check=True)\n    logging.info(\"Adding updated file\")\n    subprocess.run(\n        [\n            \"git\",\n            \"add\",\n            str(contributors_path),\n            str(translators_path),\n            str(translation_reviewers_path),\n        ],\n        check=True,\n    )\n    logging.info(\"Committing updated file\")\n    message = \"👥 Update FastAPI People - Contributors and Translators\"\n    subprocess.run([\"git\", \"commit\", \"-m\", message], check=True)\n    logging.info(\"Pushing branch\")\n    subprocess.run([\"git\", \"push\", \"origin\", branch_name], check=True)\n    logging.info(\"Creating PR\")\n    pr = repo.create_pull(title=message, body=message, base=\"master\", head=branch_name)\n    logging.info(f\"Created PR: {pr.number}\")\n    logging.info(\"Finished\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/coverage.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\nset -x\n\ncoverage combine\ncoverage report\ncoverage html\n"
  },
  {
    "path": "scripts/deploy_docs_status.py",
    "content": "import logging\nimport re\nfrom typing import Literal\n\nfrom github import Auth, Github\nfrom pydantic import BaseModel, SecretStr\nfrom pydantic_settings import BaseSettings\n\n\nclass Settings(BaseSettings):\n    github_repository: str\n    github_token: SecretStr\n    deploy_url: str | None = None\n    commit_sha: str\n    run_id: int\n    state: Literal[\"pending\", \"success\", \"error\"] = \"pending\"\n\n\nclass LinkData(BaseModel):\n    previous_link: str\n    preview_link: str\n    en_link: str | None = None\n\n\ndef main() -> None:\n    logging.basicConfig(level=logging.INFO)\n    settings = Settings()\n\n    logging.info(f\"Using config: {settings.model_dump_json()}\")\n    g = Github(auth=Auth.Token(settings.github_token.get_secret_value()))\n    repo = g.get_repo(settings.github_repository)\n    use_pr = next(\n        (pr for pr in repo.get_pulls() if pr.head.sha == settings.commit_sha), None\n    )\n    if not use_pr:\n        logging.error(f\"No PR found for hash: {settings.commit_sha}\")\n        return\n    commits = list(use_pr.get_commits())\n    current_commit = [c for c in commits if c.sha == settings.commit_sha][0]\n    run_url = f\"https://github.com/{settings.github_repository}/actions/runs/{settings.run_id}\"\n    if settings.state == \"pending\":\n        current_commit.create_status(\n            state=\"pending\",\n            description=\"Deploying Docs\",\n            context=\"deploy-docs\",\n            target_url=run_url,\n        )\n        logging.info(\"No deploy URL available yet\")\n        return\n    if settings.state == \"error\":\n        current_commit.create_status(\n            state=\"error\",\n            description=\"Error Deploying Docs\",\n            context=\"deploy-docs\",\n            target_url=run_url,\n        )\n        logging.info(\"Error deploying docs\")\n        return\n    assert settings.state == \"success\"\n    if not settings.deploy_url:\n        current_commit.create_status(\n            state=\"success\",\n            description=\"No Docs Changes\",\n            context=\"deploy-docs\",\n            target_url=run_url,\n        )\n        logging.info(\"No docs changes found\")\n        return\n    assert settings.deploy_url\n    current_commit.create_status(\n        state=\"success\",\n        description=\"Docs Deployed\",\n        context=\"deploy-docs\",\n        target_url=run_url,\n    )\n\n    files = list(use_pr.get_files())\n    docs_files = [f for f in files if f.filename.startswith(\"docs/\")]\n\n    deploy_url = settings.deploy_url.rstrip(\"/\")\n    lang_links: dict[str, list[LinkData]] = {}\n    for f in docs_files:\n        match = re.match(r\"docs/([^/]+)/docs/(.*)\", f.filename)\n        if not match:\n            continue\n        lang = match.group(1)\n        path = match.group(2)\n        if path.endswith(\"index.md\"):\n            path = path.replace(\"index.md\", \"\")\n        else:\n            path = path.replace(\".md\", \"/\")\n        en_path = path\n        if lang == \"en\":\n            use_path = en_path\n        else:\n            use_path = f\"{lang}/{path}\"\n        link = LinkData(\n            previous_link=f\"https://fastapi.tiangolo.com/{use_path}\",\n            preview_link=f\"{deploy_url}/{use_path}\",\n        )\n        if lang != \"en\":\n            link.en_link = f\"https://fastapi.tiangolo.com/{en_path}\"\n        lang_links.setdefault(lang, []).append(link)\n\n    links: list[LinkData] = []\n    en_links = lang_links.get(\"en\", [])\n    en_links.sort(key=lambda x: x.preview_link)\n    links.extend(en_links)\n\n    langs = list(lang_links.keys())\n    langs.sort()\n    for lang in langs:\n        if lang == \"en\":\n            continue\n        current_lang_links = lang_links[lang]\n        current_lang_links.sort(key=lambda x: x.preview_link)\n        links.extend(current_lang_links)\n\n    header = \"## 📝 Docs preview\"\n    message = header\n    message += f\"\\n\\nLast commit {settings.commit_sha} at: {deploy_url}\"\n\n    if links:\n        message += \"\\n\\n### Modified Pages\\n\\n\"\n        for link in links:\n            message += f\"* {link.preview_link}\"\n            message += f\" - ([before]({link.previous_link}))\"\n            if link.en_link:\n                message += f\" - ([English]({link.en_link}))\"\n            message += \"\\n\"\n\n    print(message)\n    issue = use_pr.as_issue()\n    comments = list(issue.get_comments())\n    for comment in comments:\n        if (\n            comment.body.startswith(header)\n            and comment.user.login == \"github-actions[bot]\"\n        ):\n            comment.edit(message)\n            break\n    else:\n        issue.create_comment(message)\n\n    logging.info(\"Finished\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/doc_parsing_utils.py",
    "content": "import re\nfrom typing import TypedDict\n\nCODE_INCLUDE_RE = re.compile(r\"^\\{\\*\\s*(\\S+)\\s*(.*)\\*\\}$\")\nCODE_INCLUDE_PLACEHOLDER = \"<CODE_INCLUDE>\"\n\nHEADER_WITH_PERMALINK_RE = re.compile(r\"^(#{1,6}) (.+?)(\\s*\\{\\s*#.*\\s*\\})?\\s*$\")\nHEADER_LINE_RE = re.compile(r\"^(#{1,6}) (.+?)(?:\\s*\\{\\s*(#.*)\\s*\\})?\\s*$\")\n\nTIANGOLO_COM = \"https://fastapi.tiangolo.com\"\nASSETS_URL_PREFIXES = (\"/img/\", \"/css/\", \"/js/\")\n\nMARKDOWN_LINK_RE = re.compile(\n    r\"(?<!\\\\)(?<!\\!)\"  # not an image ![...] and not escaped \\[...]\n    r\"\\[(?P<text>.*?)\\]\"  # link text (non-greedy)\n    r\"\\(\"\n    r\"(?P<url>[^)\\s]+)\"  # url (no spaces and `)`)\n    r'(?:\\s+[\"\\'](?P<title>.*?)[\"\\'])?'  # optional title in \"\" or ''\n    r\"\\)\"\n    r\"(?:\\{(?P<attrs>[^}]*)\\})?\"  # optional attributes in {}\n)\n\nHTML_LINK_RE = re.compile(r\"<a\\s+[^>]*>.*?</a>\")\nHTML_LINK_TEXT_RE = re.compile(r\"<a\\b([^>]*)>(.*?)</a>\")\nHTML_LINK_OPEN_TAG_RE = re.compile(r\"<a\\b([^>]*)>\")\nHTML_ATTR_RE = re.compile(r'(\\w+)\\s*=\\s*([\\'\"])(.*?)\\2')\n\nCODE_BLOCK_LANG_RE = re.compile(r\"^`{3,4}([\\w-]*)\", re.MULTILINE)\n\nSLASHES_COMMENT_RE = re.compile(\n    r\"^(?P<code>.*?)(?P<comment>(?:(?<= )// .*)|(?:^// .*))?$\"\n)\n\nHASH_COMMENT_RE = re.compile(r\"^(?P<code>.*?)(?P<comment>(?:(?<= )# .*)|(?:^# .*))?$\")\n\n\nclass CodeIncludeInfo(TypedDict):\n    line_no: int\n    line: str\n\n\nclass HeaderPermalinkInfo(TypedDict):\n    line_no: int\n    hashes: str\n    title: str\n    permalink: str\n\n\nclass MarkdownLinkInfo(TypedDict):\n    line_no: int\n    url: str\n    text: str\n    title: str | None\n    attributes: str | None\n    full_match: str\n\n\nclass HTMLLinkAttribute(TypedDict):\n    name: str\n    quote: str\n    value: str\n\n\nclass HtmlLinkInfo(TypedDict):\n    line_no: int\n    full_tag: str\n    attributes: list[HTMLLinkAttribute]\n    text: str\n\n\nclass MultilineCodeBlockInfo(TypedDict):\n    lang: str\n    start_line_no: int\n    content: list[str]\n\n\n# Code includes\n# --------------------------------------------------------------------------------------\n\n\ndef extract_code_includes(lines: list[str]) -> list[CodeIncludeInfo]:\n    \"\"\"\n    Extract lines that contain code includes.\n\n    Return list of CodeIncludeInfo, where each dict contains:\n    - `line_no` - line number (1-based)\n    - `line` - text of the line\n    \"\"\"\n\n    includes: list[CodeIncludeInfo] = []\n    for line_no, line in enumerate(lines, start=1):\n        if CODE_INCLUDE_RE.match(line):\n            includes.append(CodeIncludeInfo(line_no=line_no, line=line))\n    return includes\n\n\ndef replace_code_includes_with_placeholders(text: list[str]) -> list[str]:\n    \"\"\"\n    Replace code includes with placeholders.\n    \"\"\"\n\n    modified_text = text.copy()\n    includes = extract_code_includes(text)\n    for include in includes:\n        modified_text[include[\"line_no\"] - 1] = CODE_INCLUDE_PLACEHOLDER\n    return modified_text\n\n\ndef replace_placeholders_with_code_includes(\n    text: list[str], original_includes: list[CodeIncludeInfo]\n) -> list[str]:\n    \"\"\"\n    Replace code includes placeholders with actual code includes from the original (English) document.\n    Fail if the number of placeholders does not match the number of original includes.\n    \"\"\"\n\n    code_include_lines = [\n        line_no\n        for line_no, line in enumerate(text)\n        if line.strip() == CODE_INCLUDE_PLACEHOLDER\n    ]\n\n    if len(code_include_lines) != len(original_includes):\n        raise ValueError(\n            \"Number of code include placeholders does not match the number of code includes \"\n            \"in the original document \"\n            f\"({len(code_include_lines)} vs {len(original_includes)})\"\n        )\n\n    modified_text = text.copy()\n    for i, line_no in enumerate(code_include_lines):\n        modified_text[line_no] = original_includes[i][\"line\"]\n\n    return modified_text\n\n\n# Header permalinks\n# --------------------------------------------------------------------------------------\n\n\ndef extract_header_permalinks(lines: list[str]) -> list[HeaderPermalinkInfo]:\n    \"\"\"\n    Extract list of header permalinks from the given lines.\n\n    Return list of HeaderPermalinkInfo, where each dict contains:\n    - `line_no` - line number (1-based)\n    - `hashes` - string of hashes representing header level (e.g., \"###\")\n    - `permalink` - permalink string (e.g., \"{#permalink}\")\n    \"\"\"\n\n    headers: list[HeaderPermalinkInfo] = []\n    in_code_block3 = False\n    in_code_block4 = False\n\n    for line_no, line in enumerate(lines, start=1):\n        if not (in_code_block3 or in_code_block4):\n            if line.startswith(\"```\"):\n                count = len(line) - len(line.lstrip(\"`\"))\n                if count == 3:\n                    in_code_block3 = True\n                    continue\n                elif count >= 4:\n                    in_code_block4 = True\n                    continue\n\n            header_match = HEADER_WITH_PERMALINK_RE.match(line)\n            if header_match:\n                hashes, title, permalink = header_match.groups()\n                headers.append(\n                    HeaderPermalinkInfo(\n                        hashes=hashes, line_no=line_no, permalink=permalink, title=title\n                    )\n                )\n\n        elif in_code_block3:\n            if line.startswith(\"```\"):\n                count = len(line) - len(line.lstrip(\"`\"))\n                if count == 3:\n                    in_code_block3 = False\n                    continue\n\n        elif in_code_block4:\n            if line.startswith(\"````\"):\n                count = len(line) - len(line.lstrip(\"`\"))\n                if count >= 4:\n                    in_code_block4 = False\n                    continue\n\n    return headers\n\n\ndef remove_header_permalinks(lines: list[str]) -> list[str]:\n    \"\"\"\n    Remove permalinks from headers in the given lines.\n    \"\"\"\n\n    modified_lines: list[str] = []\n    for line in lines:\n        header_match = HEADER_WITH_PERMALINK_RE.match(line)\n        if header_match:\n            hashes, title, _permalink = header_match.groups()\n            modified_line = f\"{hashes} {title}\"\n            modified_lines.append(modified_line)\n        else:\n            modified_lines.append(line)\n    return modified_lines\n\n\ndef replace_header_permalinks(\n    text: list[str],\n    header_permalinks: list[HeaderPermalinkInfo],\n    original_header_permalinks: list[HeaderPermalinkInfo],\n) -> list[str]:\n    \"\"\"\n    Replace permalinks in the given text with the permalinks from the original document.\n\n    Fail if the number or level of headers does not match the original.\n    \"\"\"\n\n    modified_text: list[str] = text.copy()\n\n    if len(header_permalinks) != len(original_header_permalinks):\n        raise ValueError(\n            \"Number of headers with permalinks does not match the number in the \"\n            \"original document \"\n            f\"({len(header_permalinks)} vs {len(original_header_permalinks)})\"\n        )\n\n    for header_no in range(len(header_permalinks)):\n        header_info = header_permalinks[header_no]\n        original_header_info = original_header_permalinks[header_no]\n\n        if header_info[\"hashes\"] != original_header_info[\"hashes\"]:\n            raise ValueError(\n                \"Header levels do not match between document and original document\"\n                f\" (found {header_info['hashes']}, expected {original_header_info['hashes']})\"\n                f\" for header №{header_no + 1} in line {header_info['line_no']}\"\n            )\n        line_no = header_info[\"line_no\"] - 1\n        hashes = header_info[\"hashes\"]\n        title = header_info[\"title\"]\n        permalink = original_header_info[\"permalink\"]\n        modified_text[line_no] = f\"{hashes} {title}{permalink}\"\n\n    return modified_text\n\n\n# Markdown links\n# --------------------------------------------------------------------------------------\n\n\ndef extract_markdown_links(lines: list[str]) -> list[MarkdownLinkInfo]:\n    \"\"\"\n    Extract all markdown links from the given lines.\n\n    Return list of MarkdownLinkInfo, where each dict contains:\n    - `line_no` - line number (1-based)\n    - `url` - link URL\n    - `text` - link text\n    - `title` - link title (if any)\n    \"\"\"\n\n    links: list[MarkdownLinkInfo] = []\n    for line_no, line in enumerate(lines, start=1):\n        for m in MARKDOWN_LINK_RE.finditer(line):\n            links.append(\n                MarkdownLinkInfo(\n                    line_no=line_no,\n                    url=m.group(\"url\"),\n                    text=m.group(\"text\"),\n                    title=m.group(\"title\"),\n                    attributes=m.group(\"attrs\"),\n                    full_match=m.group(0),\n                )\n            )\n    return links\n\n\ndef _add_lang_code_to_url(url: str, lang_code: str) -> str:\n    if url.startswith(TIANGOLO_COM):\n        rel_url = url[len(TIANGOLO_COM) :]\n        if not rel_url.startswith(ASSETS_URL_PREFIXES):\n            url = url.replace(TIANGOLO_COM, f\"{TIANGOLO_COM}/{lang_code}\")\n    return url\n\n\ndef _construct_markdown_link(\n    url: str,\n    text: str,\n    title: str | None,\n    attributes: str | None,\n    lang_code: str,\n) -> str:\n    \"\"\"\n    Construct a markdown link, adjusting the URL for the given language code if needed.\n    \"\"\"\n    url = _add_lang_code_to_url(url, lang_code)\n\n    if title:\n        link = f'[{text}]({url} \"{title}\")'\n    else:\n        link = f\"[{text}]({url})\"\n\n    if attributes:\n        link += f\"{{{attributes}}}\"\n\n    return link\n\n\ndef replace_markdown_links(\n    text: list[str],\n    links: list[MarkdownLinkInfo],\n    original_links: list[MarkdownLinkInfo],\n    lang_code: str,\n) -> list[str]:\n    \"\"\"\n    Replace markdown links in the given text with the original links.\n\n    Fail if the number of links does not match the original.\n    \"\"\"\n\n    if len(links) != len(original_links):\n        raise ValueError(\n            \"Number of markdown links does not match the number in the \"\n            \"original document \"\n            f\"({len(links)} vs {len(original_links)})\"\n        )\n\n    modified_text = text.copy()\n    for i, link_info in enumerate(links):\n        link_text = link_info[\"text\"]\n        link_title = link_info[\"title\"]\n        original_link_info = original_links[i]\n\n        # Replace\n        replacement_link = _construct_markdown_link(\n            url=original_link_info[\"url\"],\n            text=link_text,\n            title=link_title,\n            attributes=original_link_info[\"attributes\"],\n            lang_code=lang_code,\n        )\n        line_no = link_info[\"line_no\"] - 1\n        modified_line = modified_text[line_no]\n        modified_line = modified_line.replace(\n            link_info[\"full_match\"], replacement_link, 1\n        )\n        modified_text[line_no] = modified_line\n\n    return modified_text\n\n\n# HTML links\n# --------------------------------------------------------------------------------------\n\n\ndef extract_html_links(lines: list[str]) -> list[HtmlLinkInfo]:\n    \"\"\"\n    Extract all HTML links from the given lines.\n\n    Return list of HtmlLinkInfo, where each dict contains:\n    - `line_no` - line number (1-based)\n    - `full_tag` - full HTML link tag\n    - `attributes` - list of HTMLLinkAttribute (name, quote, value)\n    - `text` - link text\n    \"\"\"\n\n    links = []\n    for line_no, line in enumerate(lines, start=1):\n        for html_link in HTML_LINK_RE.finditer(line):\n            link_str = html_link.group(0)\n\n            link_text_match = HTML_LINK_TEXT_RE.match(link_str)\n            assert link_text_match is not None\n            link_text = link_text_match.group(2)\n            assert isinstance(link_text, str)\n\n            link_open_tag_match = HTML_LINK_OPEN_TAG_RE.match(link_str)\n            assert link_open_tag_match is not None\n            link_open_tag = link_open_tag_match.group(1)\n            assert isinstance(link_open_tag, str)\n\n            attributes: list[HTMLLinkAttribute] = []\n            for attr_name, attr_quote, attr_value in re.findall(\n                HTML_ATTR_RE, link_open_tag\n            ):\n                assert isinstance(attr_name, str)\n                assert isinstance(attr_quote, str)\n                assert isinstance(attr_value, str)\n                attributes.append(\n                    HTMLLinkAttribute(\n                        name=attr_name, quote=attr_quote, value=attr_value\n                    )\n                )\n            links.append(\n                HtmlLinkInfo(\n                    line_no=line_no,\n                    full_tag=link_str,\n                    attributes=attributes,\n                    text=link_text,\n                )\n            )\n    return links\n\n\ndef _construct_html_link(\n    link_text: str,\n    attributes: list[HTMLLinkAttribute],\n    lang_code: str,\n) -> str:\n    \"\"\"\n    Reconstruct HTML link, adjusting the URL for the given language code if needed.\n    \"\"\"\n\n    attributes_upd: list[HTMLLinkAttribute] = []\n    for attribute in attributes:\n        if attribute[\"name\"] == \"href\":\n            original_url = attribute[\"value\"]\n            url = _add_lang_code_to_url(original_url, lang_code)\n            attributes_upd.append(\n                HTMLLinkAttribute(name=\"href\", quote=attribute[\"quote\"], value=url)\n            )\n        else:\n            attributes_upd.append(attribute)\n\n    attrs_str = \" \".join(\n        f\"{attribute['name']}={attribute['quote']}{attribute['value']}{attribute['quote']}\"\n        for attribute in attributes_upd\n    )\n    return f\"<a {attrs_str}>{link_text}</a>\"\n\n\ndef replace_html_links(\n    text: list[str],\n    links: list[HtmlLinkInfo],\n    original_links: list[HtmlLinkInfo],\n    lang_code: str,\n) -> list[str]:\n    \"\"\"\n    Replace HTML links in the given text with the links from the original document.\n\n    Adjust URLs for the given language code.\n    Fail if the number of links does not match the original.\n    \"\"\"\n\n    if len(links) != len(original_links):\n        raise ValueError(\n            \"Number of HTML links does not match the number in the \"\n            \"original document \"\n            f\"({len(links)} vs {len(original_links)})\"\n        )\n\n    modified_text = text.copy()\n    for link_index, link in enumerate(links):\n        original_link_info = original_links[link_index]\n\n        # Replace in the document text\n        replacement_link = _construct_html_link(\n            link_text=link[\"text\"],\n            attributes=original_link_info[\"attributes\"],\n            lang_code=lang_code,\n        )\n        line_no = link[\"line_no\"] - 1\n        modified_text[line_no] = modified_text[line_no].replace(\n            link[\"full_tag\"], replacement_link, 1\n        )\n\n    return modified_text\n\n\n# Multiline code blocks\n# --------------------------------------------------------------------------------------\n\n\ndef get_code_block_lang(line: str) -> str:\n    match = CODE_BLOCK_LANG_RE.match(line)\n    if match:\n        return match.group(1)\n    return \"\"\n\n\ndef extract_multiline_code_blocks(text: list[str]) -> list[MultilineCodeBlockInfo]:\n    blocks: list[MultilineCodeBlockInfo] = []\n\n    in_code_block3 = False\n    in_code_block4 = False\n    current_block_lang = \"\"\n    current_block_start_line = -1\n    current_block_lines = []\n\n    for line_no, line in enumerate(text, start=1):\n        stripped = line.lstrip()\n\n        # --- Detect opening fence ---\n        if not (in_code_block3 or in_code_block4):\n            if stripped.startswith(\"```\"):\n                current_block_start_line = line_no\n                count = len(stripped) - len(stripped.lstrip(\"`\"))\n                if count == 3:\n                    in_code_block3 = True\n                    current_block_lang = get_code_block_lang(stripped)\n                    current_block_lines = [line]\n                    continue\n                elif count >= 4:\n                    in_code_block4 = True\n                    current_block_lang = get_code_block_lang(stripped)\n                    current_block_lines = [line]\n                    continue\n\n        # --- Detect closing fence ---\n        elif in_code_block3:\n            if stripped.startswith(\"```\"):\n                count = len(stripped) - len(stripped.lstrip(\"`\"))\n                if count == 3:\n                    current_block_lines.append(line)\n                    blocks.append(\n                        MultilineCodeBlockInfo(\n                            lang=current_block_lang,\n                            start_line_no=current_block_start_line,\n                            content=current_block_lines,\n                        )\n                    )\n                    in_code_block3 = False\n                    current_block_lang = \"\"\n                    current_block_start_line = -1\n                    current_block_lines = []\n                    continue\n            current_block_lines.append(line)\n\n        elif in_code_block4:\n            if stripped.startswith(\"````\"):\n                count = len(stripped) - len(stripped.lstrip(\"`\"))\n                if count >= 4:\n                    current_block_lines.append(line)\n                    blocks.append(\n                        MultilineCodeBlockInfo(\n                            lang=current_block_lang,\n                            start_line_no=current_block_start_line,\n                            content=current_block_lines,\n                        )\n                    )\n                    in_code_block4 = False\n                    current_block_lang = \"\"\n                    current_block_start_line = -1\n                    current_block_lines = []\n                    continue\n            current_block_lines.append(line)\n\n    return blocks\n\n\ndef _split_hash_comment(line: str) -> tuple[str, str | None]:\n    match = HASH_COMMENT_RE.match(line)\n    if match:\n        code = match.group(\"code\").rstrip()\n        comment = match.group(\"comment\")\n        return code, comment\n    return line.rstrip(), None\n\n\ndef _split_slashes_comment(line: str) -> tuple[str, str | None]:\n    match = SLASHES_COMMENT_RE.match(line)\n    if match:\n        code = match.group(\"code\").rstrip()\n        comment = match.group(\"comment\")\n        return code, comment\n    return line, None\n\n\ndef replace_multiline_code_block(\n    block_a: MultilineCodeBlockInfo, block_b: MultilineCodeBlockInfo\n) -> list[str]:\n    \"\"\"\n    Replace multiline code block `a` with block `b` leaving comments intact.\n\n    Syntax of comments depends on the language of the code block.\n    Raises ValueError if the blocks are not compatible (different languages or different number of lines).\n    \"\"\"\n\n    start_line = block_a[\"start_line_no\"]\n    end_line_no = start_line + len(block_a[\"content\"]) - 1\n\n    if block_a[\"lang\"] != block_b[\"lang\"]:\n        raise ValueError(\n            f\"Code block (lines {start_line}-{end_line_no}) \"\n            \"has different language than the original block \"\n            f\"('{block_a['lang']}' vs '{block_b['lang']}')\"\n        )\n    if len(block_a[\"content\"]) != len(block_b[\"content\"]):\n        raise ValueError(\n            f\"Code block (lines {start_line}-{end_line_no}) \"\n            \"has different number of lines than the original block \"\n            f\"({len(block_a['content'])} vs {len(block_b['content'])})\"\n        )\n\n    block_language = block_a[\"lang\"].lower()\n    if block_language in {\"mermaid\"}:\n        if block_a != block_b:\n            print(\n                f\"Skipping mermaid code block replacement (lines {start_line}-{end_line_no}). \"\n                \"This should be checked manually.\"\n            )\n        return block_a[\"content\"].copy()  # We don't handle mermaid code blocks for now\n\n    code_block: list[str] = []\n    for line_a, line_b in zip(block_a[\"content\"], block_b[\"content\"], strict=False):\n        line_a_comment: str | None = None\n        line_b_comment: str | None = None\n\n        # Handle comments based on language\n        if block_language in {\n            \"python\",\n            \"py\",\n            \"sh\",\n            \"bash\",\n            \"dockerfile\",\n            \"requirements\",\n            \"gitignore\",\n            \"toml\",\n            \"yaml\",\n            \"yml\",\n            \"hash-style-comments\",\n        }:\n            _line_a_code, line_a_comment = _split_hash_comment(line_a)\n            _line_b_code, line_b_comment = _split_hash_comment(line_b)\n            res_line = line_b\n            if line_b_comment:\n                res_line = res_line.replace(line_b_comment, line_a_comment, 1)\n            code_block.append(res_line)\n        elif block_language in {\"console\", \"json\", \"slash-style-comments\"}:\n            _line_a_code, line_a_comment = _split_slashes_comment(line_a)\n            _line_b_code, line_b_comment = _split_slashes_comment(line_b)\n            res_line = line_b\n            if line_b_comment:\n                res_line = res_line.replace(line_b_comment, line_a_comment, 1)\n            code_block.append(res_line)\n        else:\n            code_block.append(line_b)\n\n    return code_block\n\n\ndef replace_multiline_code_blocks_in_text(\n    text: list[str],\n    code_blocks: list[MultilineCodeBlockInfo],\n    original_code_blocks: list[MultilineCodeBlockInfo],\n) -> list[str]:\n    \"\"\"\n    Update each code block in `text` with the corresponding code block from\n    `original_code_blocks` with comments taken from `code_blocks`.\n\n    Raises ValueError if the number, language, or shape of code blocks do not match.\n    \"\"\"\n\n    if len(code_blocks) != len(original_code_blocks):\n        raise ValueError(\n            \"Number of code blocks does not match the number in the original document \"\n            f\"({len(code_blocks)} vs {len(original_code_blocks)})\"\n        )\n\n    modified_text = text.copy()\n    for block, original_block in zip(code_blocks, original_code_blocks, strict=True):\n        updated_content = replace_multiline_code_block(block, original_block)\n\n        start_line_index = block[\"start_line_no\"] - 1\n        for i, updated_line in enumerate(updated_content):\n            modified_text[start_line_index + i] = updated_line\n\n    return modified_text\n\n\n# All checks\n# --------------------------------------------------------------------------------------\n\n\ndef check_translation(\n    doc_lines: list[str],\n    en_doc_lines: list[str],\n    lang_code: str,\n    auto_fix: bool,\n    path: str,\n) -> list[str]:\n    # Fix code includes\n    en_code_includes = extract_code_includes(en_doc_lines)\n    doc_lines_with_placeholders = replace_code_includes_with_placeholders(doc_lines)\n    fixed_doc_lines = replace_placeholders_with_code_includes(\n        doc_lines_with_placeholders, en_code_includes\n    )\n    if auto_fix and (fixed_doc_lines != doc_lines):\n        print(f\"Fixing code includes in: {path}\")\n        doc_lines = fixed_doc_lines\n\n    # Fix permalinks\n    en_permalinks = extract_header_permalinks(en_doc_lines)\n    doc_permalinks = extract_header_permalinks(doc_lines)\n    fixed_doc_lines = replace_header_permalinks(\n        doc_lines, doc_permalinks, en_permalinks\n    )\n    if auto_fix and (fixed_doc_lines != doc_lines):\n        print(f\"Fixing header permalinks in: {path}\")\n        doc_lines = fixed_doc_lines\n\n    # Fix markdown links\n    en_markdown_links = extract_markdown_links(en_doc_lines)\n    doc_markdown_links = extract_markdown_links(doc_lines)\n    fixed_doc_lines = replace_markdown_links(\n        doc_lines, doc_markdown_links, en_markdown_links, lang_code\n    )\n    if auto_fix and (fixed_doc_lines != doc_lines):\n        print(f\"Fixing markdown links in: {path}\")\n        doc_lines = fixed_doc_lines\n\n    # Fix HTML links\n    en_html_links = extract_html_links(en_doc_lines)\n    doc_html_links = extract_html_links(doc_lines)\n    fixed_doc_lines = replace_html_links(\n        doc_lines, doc_html_links, en_html_links, lang_code\n    )\n    if auto_fix and (fixed_doc_lines != doc_lines):\n        print(f\"Fixing HTML links in: {path}\")\n        doc_lines = fixed_doc_lines\n\n    # Fix multiline code blocks\n    en_code_blocks = extract_multiline_code_blocks(en_doc_lines)\n    doc_code_blocks = extract_multiline_code_blocks(doc_lines)\n    fixed_doc_lines = replace_multiline_code_blocks_in_text(\n        doc_lines, doc_code_blocks, en_code_blocks\n    )\n    if auto_fix and (fixed_doc_lines != doc_lines):\n        print(f\"Fixing multiline code blocks in: {path}\")\n        doc_lines = fixed_doc_lines\n\n    return doc_lines\n"
  },
  {
    "path": "scripts/docs.py",
    "content": "import json\nimport logging\nimport os\nimport re\nimport shutil\nimport subprocess\nfrom html.parser import HTMLParser\nfrom http.server import HTTPServer, SimpleHTTPRequestHandler\nfrom multiprocessing import Pool\nfrom pathlib import Path\nfrom typing import Any\n\nimport mkdocs.utils\nimport typer\nimport yaml\nfrom jinja2 import Template\nfrom ruff.__main__ import find_ruff_bin\nfrom slugify import slugify as py_slugify\n\nlogging.basicConfig(level=logging.INFO)\n\nSUPPORTED_LANGS = {\n    \"de\",\n    \"en\",\n    \"es\",\n    \"fr\",\n    \"ja\",\n    \"ko\",\n    \"pt\",\n    \"ru\",\n    \"tr\",\n    \"uk\",\n    \"zh\",\n    \"zh-hant\",\n}\n\n\napp = typer.Typer()\n\nmkdocs_name = \"mkdocs.yml\"\n\nmissing_translation_snippet = \"\"\"\n{!../../docs/missing-translation.md!}\n\"\"\"\n\nnon_translated_sections = (\n    f\"reference{os.sep}\",\n    \"release-notes.md\",\n    \"fastapi-people.md\",\n    \"external-links.md\",\n    \"newsletter.md\",\n    \"management-tasks.md\",\n    \"management.md\",\n    \"contributing.md\",\n)\n\ndocs_path = Path(\"docs\")\nen_docs_path = Path(\"docs/en\")\nen_config_path: Path = en_docs_path / mkdocs_name\nsite_path = Path(\"site\").absolute()\nbuild_site_path = Path(\"site_build\").absolute()\n\nheader_pattern = re.compile(r\"^(#{1,6}) (.+?)(?:\\s*\\{\\s*(#.*)\\s*\\})?\\s*$\")\nheader_with_permalink_pattern = re.compile(r\"^(#{1,6}) (.+?)(\\s*\\{\\s*#.*\\s*\\})\\s*$\")\ncode_block3_pattern = re.compile(r\"^\\s*```\")\ncode_block4_pattern = re.compile(r\"^\\s*````\")\n\n\n# Pattern to match markdown links: [text](url) → text\nmd_link_pattern = re.compile(r\"\\[([^\\]]+)\\]\\([^)]+\\)\")\n\n\ndef strip_markdown_links(text: str) -> str:\n    \"\"\"Replace markdown links with just their visible text.\"\"\"\n    return md_link_pattern.sub(r\"\\1\", text)\n\n\nclass VisibleTextExtractor(HTMLParser):\n    \"\"\"Extract visible text from a string with HTML tags.\"\"\"\n\n    def __init__(self):\n        super().__init__()\n        self.text_parts = []\n\n    def handle_data(self, data):\n        self.text_parts.append(data)\n\n    def extract_visible_text(self, html: str) -> str:\n        self.reset()\n        self.text_parts = []\n        self.feed(html)\n        return \"\".join(self.text_parts).strip()\n\n\ndef slugify(text: str) -> str:\n    return py_slugify(\n        text,\n        replacements=[\n            (\"`\", \"\"),  # `dict`s -> dicts\n            (\"'s\", \"s\"),  # it's -> its\n            (\"'t\", \"t\"),  # don't -> dont\n            (\"**\", \"\"),  # **FastAPI**s -> FastAPIs\n        ],\n    )\n\n\ndef get_en_config() -> dict[str, Any]:\n    return mkdocs.utils.yaml_load(en_config_path.read_text(encoding=\"utf-8\"))\n\n\ndef get_lang_paths() -> list[Path]:\n    return sorted(docs_path.iterdir())\n\n\ndef lang_callback(lang: str | None) -> str | None:\n    if lang is None:\n        return None\n    lang = lang.lower()\n    return lang\n\n\ndef complete_existing_lang(incomplete: str):\n    lang_path: Path\n    for lang_path in get_lang_paths():\n        if lang_path.is_dir() and lang_path.name.startswith(incomplete):\n            yield lang_path.name\n\n\n@app.callback()\ndef callback() -> None:\n    # For MacOS with Cairo\n    os.environ[\"DYLD_FALLBACK_LIBRARY_PATH\"] = \"/opt/homebrew/lib\"\n\n\n@app.command()\ndef new_lang(lang: str = typer.Argument(..., callback=lang_callback)):\n    \"\"\"\n    Generate a new docs translation directory for the language LANG.\n    \"\"\"\n    new_path: Path = Path(\"docs\") / lang\n    if new_path.exists():\n        typer.echo(f\"The language was already created: {lang}\")\n        raise typer.Abort()\n    new_path.mkdir()\n    new_config_path: Path = Path(new_path) / mkdocs_name\n    new_config_path.write_text(\"INHERIT: ../en/mkdocs.yml\\n\", encoding=\"utf-8\")\n    new_llm_prompt_path: Path = new_path / \"llm-prompt.md\"\n    new_llm_prompt_path.write_text(\"\", encoding=\"utf-8\")\n    print(f\"Successfully initialized: {new_path}\")\n    update_languages()\n\n\n@app.command()\ndef build_lang(\n    lang: str = typer.Argument(\n        ..., callback=lang_callback, autocompletion=complete_existing_lang\n    ),\n) -> None:\n    \"\"\"\n    Build the docs for a language.\n    \"\"\"\n    lang_path: Path = Path(\"docs\") / lang\n    if not lang_path.is_dir():\n        typer.echo(f\"The language translation doesn't seem to exist yet: {lang}\")\n        raise typer.Abort()\n    typer.echo(f\"Building docs for: {lang}\")\n    build_site_dist_path = build_site_path / lang\n    if lang == \"en\":\n        dist_path = site_path\n        # Don't remove en dist_path as it might already contain other languages.\n        # When running build_all(), that function already removes site_path.\n        # All this is only relevant locally, on GitHub Actions all this is done through\n        # artifacts and multiple workflows, so it doesn't matter if directories are\n        # removed or not.\n    else:\n        dist_path = site_path / lang\n        shutil.rmtree(dist_path, ignore_errors=True)\n    current_dir = os.getcwd()\n    os.chdir(lang_path)\n    shutil.rmtree(build_site_dist_path, ignore_errors=True)\n    subprocess.run([\"mkdocs\", \"build\", \"--site-dir\", build_site_dist_path], check=True)\n    shutil.copytree(build_site_dist_path, dist_path, dirs_exist_ok=True)\n    os.chdir(current_dir)\n    typer.secho(f\"Successfully built docs for: {lang}\", color=typer.colors.GREEN)\n\n\nindex_sponsors_template = \"\"\"\n### Keystone Sponsor\n\n{% for sponsor in sponsors.keystone -%}\n<a href=\"{{ sponsor.url }}\" target=\"_blank\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\"></a>\n{% endfor %}\n### Gold Sponsors\n\n{% for sponsor in sponsors.gold -%}\n<a href=\"{{ sponsor.url }}\" target=\"_blank\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\"></a>\n{% endfor %}\n### Silver Sponsors\n\n{% for sponsor in sponsors.silver -%}\n<a href=\"{{ sponsor.url }}\" target=\"_blank\" title=\"{{ sponsor.title }}\"><img src=\"{{ sponsor.img }}\"></a>\n{% endfor %}\n\n\"\"\"\n\n\ndef remove_header_permalinks(content: str):\n    lines: list[str] = []\n    for line in content.split(\"\\n\"):\n        match = header_with_permalink_pattern.match(line)\n        if match:\n            hashes, title, *_ = match.groups()\n            line = f\"{hashes} {title}\"\n        lines.append(line)\n    return \"\\n\".join(lines)\n\n\ndef generate_readme_content() -> str:\n    en_index = en_docs_path / \"docs\" / \"index.md\"\n    content = en_index.read_text(\"utf-8\")\n    content = remove_header_permalinks(content)  # remove permalinks from headers\n    match_pre = re.search(r\"</style>\\n\\n\", content)\n    match_start = re.search(r\"<!-- sponsors -->\", content)\n    match_end = re.search(r\"<!-- /sponsors -->\", content)\n    sponsors_data_path = en_docs_path / \"data\" / \"sponsors.yml\"\n    sponsors = mkdocs.utils.yaml_load(sponsors_data_path.read_text(encoding=\"utf-8\"))\n    if not (match_start and match_end):\n        raise RuntimeError(\"Couldn't auto-generate sponsors section\")\n    if not match_pre:\n        raise RuntimeError(\"Couldn't find pre section (<style>) in index.md\")\n    frontmatter_end = match_pre.end()\n    pre_end = match_start.end()\n    post_start = match_end.start()\n    template = Template(index_sponsors_template)\n    message = template.render(sponsors=sponsors)\n    pre_content = content[frontmatter_end:pre_end]\n    post_content = content[post_start:]\n    new_content = pre_content + message + post_content\n    # Remove content between <!-- only-mkdocs --> and <!-- /only-mkdocs -->\n    new_content = re.sub(\n        r\"<!-- only-mkdocs -->.*?<!-- /only-mkdocs -->\",\n        \"\",\n        new_content,\n        flags=re.DOTALL,\n    )\n    return new_content\n\n\n@app.command()\ndef generate_readme() -> None:\n    \"\"\"\n    Generate README.md content from main index.md\n    \"\"\"\n    readme_path = Path(\"README.md\")\n    old_content = readme_path.read_text(\"utf-8\")\n    new_content = generate_readme_content()\n    if new_content != old_content:\n        print(\"README.md outdated from the latest index.md\")\n        print(\"Updating README.md\")\n        readme_path.write_text(new_content, encoding=\"utf-8\")\n        raise typer.Exit(1)\n    print(\"README.md is up to date ✅\")\n\n\n@app.command()\ndef build_all() -> None:\n    \"\"\"\n    Build mkdocs site for en, and then build each language inside, end result is located\n    at directory ./site/ with each language inside.\n    \"\"\"\n    update_languages()\n    shutil.rmtree(site_path, ignore_errors=True)\n    langs = [\n        lang.name\n        for lang in get_lang_paths()\n        if (lang.is_dir() and lang.name in SUPPORTED_LANGS)\n    ]\n    cpu_count = os.cpu_count() or 1\n    process_pool_size = cpu_count * 4\n    typer.echo(f\"Using process pool size: {process_pool_size}\")\n    with Pool(process_pool_size) as p:\n        p.map(build_lang, langs)\n\n\n@app.command()\ndef update_languages() -> None:\n    \"\"\"\n    Update the mkdocs.yml file Languages section including all the available languages.\n    \"\"\"\n    old_config = get_en_config()\n    updated_config = get_updated_config_content()\n    if old_config != updated_config:\n        print(\"docs/en/mkdocs.yml outdated\")\n        print(\"Updating docs/en/mkdocs.yml\")\n        en_config_path.write_text(\n            yaml.dump(updated_config, sort_keys=False, width=200, allow_unicode=True),\n            encoding=\"utf-8\",\n        )\n        raise typer.Exit(1)\n    print(\"docs/en/mkdocs.yml is up to date ✅\")\n\n\n@app.command()\ndef serve() -> None:\n    \"\"\"\n    A quick server to preview a built site with translations.\n\n    For development, prefer the command live (or just mkdocs serve).\n\n    This is here only to preview a site with translations already built.\n\n    Make sure you run the build-all command first.\n    \"\"\"\n    typer.echo(\"Warning: this is a very simple server.\")\n    typer.echo(\"For development, use the command live instead.\")\n    typer.echo(\"This is here only to preview a site with translations already built.\")\n    typer.echo(\"Make sure you run the build-all command first.\")\n    os.chdir(\"site\")\n    server_address = (\"\", 8008)\n    server = HTTPServer(server_address, SimpleHTTPRequestHandler)\n    typer.echo(\"Serving at: http://127.0.0.1:8008\")\n    server.serve_forever()\n\n\n@app.command()\ndef live(\n    lang: str = typer.Argument(\n        None, callback=lang_callback, autocompletion=complete_existing_lang\n    ),\n    dirty: bool = False,\n) -> None:\n    \"\"\"\n    Serve with livereload a docs site for a specific language.\n\n    This only shows the actual translated files, not the placeholders created with\n    build-all.\n\n    Takes an optional LANG argument with the name of the language to serve, by default\n    en.\n    \"\"\"\n    # Enable line numbers during local development to make it easier to highlight\n    if lang is None:\n        lang = \"en\"\n    lang_path: Path = docs_path / lang\n    # Enable line numbers during local development to make it easier to highlight\n    args = [\"mkdocs\", \"serve\", \"--dev-addr\", \"127.0.0.1:8008\"]\n    if dirty:\n        args.append(\"--dirty\")\n    subprocess.run(\n        args, env={**os.environ, \"LINENUMS\": \"true\"}, cwd=lang_path, check=True\n    )\n\n\ndef get_updated_config_content() -> dict[str, Any]:\n    config = get_en_config()\n    languages = [{\"en\": \"/\"}]\n    new_alternate: list[dict[str, str]] = []\n    # Language names sourced from https://quickref.me/iso-639-1\n    # Contributors may wish to update or change these, e.g. to fix capitalization.\n    language_names_path = Path(__file__).parent / \"../docs/language_names.yml\"\n    local_language_names: dict[str, str] = mkdocs.utils.yaml_load(\n        language_names_path.read_text(encoding=\"utf-8\")\n    )\n    for lang_path in get_lang_paths():\n        if lang_path.name in {\"en\", \"em\"} or not lang_path.is_dir():\n            continue\n        if lang_path.name not in SUPPORTED_LANGS:\n            # Skip languages that are not yet ready\n            continue\n        code = lang_path.name\n        languages.append({code: f\"/{code}/\"})\n    for lang_dict in languages:\n        code = list(lang_dict.keys())[0]\n        url = lang_dict[code]\n        if code not in local_language_names:\n            print(\n                f\"Missing language name for: {code}, \"\n                \"update it in docs/language_names.yml\"\n            )\n            raise typer.Abort()\n        use_name = f\"{code} - {local_language_names[code]}\"\n        new_alternate.append({\"link\": url, \"name\": use_name})\n    config[\"extra\"][\"alternate\"] = new_alternate\n    return config\n\n\n@app.command()\ndef ensure_non_translated() -> None:\n    \"\"\"\n    Ensure there are no files in the non translatable pages.\n    \"\"\"\n    print(\"Ensuring no non translated pages\")\n    lang_paths = get_lang_paths()\n    error_paths = []\n    for lang in lang_paths:\n        if lang.name == \"en\":\n            continue\n        for non_translatable in non_translated_sections:\n            non_translatable_path = lang / \"docs\" / non_translatable\n            if non_translatable_path.exists():\n                error_paths.append(non_translatable_path)\n    if error_paths:\n        print(\"Non-translated pages found, removing them:\")\n        for error_path in error_paths:\n            print(error_path)\n            if error_path.is_file():\n                error_path.unlink()\n            else:\n                shutil.rmtree(error_path)\n        raise typer.Exit(1)\n    print(\"No non-translated pages found ✅\")\n\n\n@app.command()\ndef langs_json():\n    langs = []\n    for lang_path in get_lang_paths():\n        if lang_path.is_dir() and lang_path.name in SUPPORTED_LANGS:\n            langs.append(lang_path.name)\n    print(json.dumps(langs))\n\n\n@app.command()\ndef generate_docs_src_versions_for_file(file_path: Path) -> None:\n    target_versions = [\"py39\", \"py310\"]\n    full_path_str = str(file_path)\n    for target_version in target_versions:\n        if f\"_{target_version}\" in full_path_str:\n            logging.info(\n                f\"Skipping {file_path}, already a version file for {target_version}\"\n            )\n            return\n    base_content = file_path.read_text(encoding=\"utf-8\")\n    previous_content = {base_content}\n    for target_version in target_versions:\n        version_result = subprocess.run(\n            [\n                find_ruff_bin(),\n                \"check\",\n                \"--target-version\",\n                target_version,\n                \"--fix\",\n                \"--unsafe-fixes\",\n                \"-\",\n            ],\n            input=base_content.encode(\"utf-8\"),\n            capture_output=True,\n        )\n        content_target = version_result.stdout.decode(\"utf-8\")\n        format_result = subprocess.run(\n            [find_ruff_bin(), \"format\", \"-\"],\n            input=content_target.encode(\"utf-8\"),\n            capture_output=True,\n        )\n        content_format = format_result.stdout.decode(\"utf-8\")\n        if content_format in previous_content:\n            continue\n        previous_content.add(content_format)\n        # Determine where the version label should go: in the parent directory\n        # name or in the file name, matching the source structure.\n        label_in_parent = False\n        for v in target_versions:\n            if f\"_{v}\" in file_path.parent.name:\n                label_in_parent = True\n                break\n        if label_in_parent:\n            parent_name = file_path.parent.name\n            for v in target_versions:\n                parent_name = parent_name.replace(f\"_{v}\", \"\")\n            new_parent = file_path.parent.parent / f\"{parent_name}_{target_version}\"\n            new_parent.mkdir(parents=True, exist_ok=True)\n            version_file = new_parent / file_path.name\n        else:\n            base_name = file_path.stem\n            for v in target_versions:\n                if base_name.endswith(f\"_{v}\"):\n                    base_name = base_name[: -len(f\"_{v}\")]\n                    break\n            version_file = file_path.with_name(f\"{base_name}_{target_version}.py\")\n        logging.info(f\"Writing to {version_file}\")\n        version_file.write_text(content_format, encoding=\"utf-8\")\n\n\n@app.command()\ndef generate_docs_src_versions() -> None:\n    \"\"\"\n    Generate Python version-specific files for all .py files in docs_src.\n    \"\"\"\n    docs_src_path = Path(\"docs_src\")\n    for py_file in sorted(docs_src_path.rglob(\"*.py\")):\n        generate_docs_src_versions_for_file(py_file)\n\n\n@app.command()\ndef copy_py39_to_py310() -> None:\n    \"\"\"\n    For each docs_src file/directory with a _py39 label that has no _py310\n    counterpart, copy it with the _py310 label.\n    \"\"\"\n    docs_src_path = Path(\"docs_src\")\n    # Handle directory-level labels (e.g. app_b_an_py39/)\n    for dir_path in sorted(docs_src_path.rglob(\"*_py39\")):\n        if not dir_path.is_dir():\n            continue\n        py310_dir = dir_path.parent / dir_path.name.replace(\"_py39\", \"_py310\")\n        if py310_dir.exists():\n            continue\n        logging.info(f\"Copying directory {dir_path} -> {py310_dir}\")\n        shutil.copytree(dir_path, py310_dir)\n    # Handle file-level labels (e.g. tutorial001_py39.py)\n    for file_path in sorted(docs_src_path.rglob(\"*_py39.py\")):\n        if not file_path.is_file():\n            continue\n        # Skip files inside _py39 directories (already handled above)\n        if \"_py39\" in file_path.parent.name:\n            continue\n        py310_file = file_path.with_name(\n            file_path.name.replace(\"_py39.py\", \"_py310.py\")\n        )\n        if py310_file.exists():\n            continue\n        logging.info(f\"Copying file {file_path} -> {py310_file}\")\n        shutil.copy2(file_path, py310_file)\n\n\n@app.command()\ndef update_docs_includes_py39_to_py310() -> None:\n    \"\"\"\n    Update .md files in docs/en/ to replace _py39 includes with _py310 versions.\n\n    For each include line referencing a _py39 file or directory in docs_src, replace\n    the _py39 label with _py310.\n    \"\"\"\n    include_pattern = re.compile(r\"\\{[^}]*docs_src/[^}]*_py39[^}]*\\.py[^}]*\\}\")\n    count = 0\n    for md_file in sorted(en_docs_path.rglob(\"*.md\")):\n        content = md_file.read_text(encoding=\"utf-8\")\n        if \"_py39\" not in content:\n            continue\n        new_content = include_pattern.sub(\n            lambda m: m.group(0).replace(\"_py39\", \"_py310\"), content\n        )\n        if new_content != content:\n            md_file.write_text(new_content, encoding=\"utf-8\")\n            count += 1\n            logging.info(f\"Updated includes in {md_file}\")\n    print(f\"Updated {count} file(s) ✅\")\n\n\n@app.command()\ndef remove_unused_docs_src() -> None:\n    \"\"\"\n    Delete .py files in docs_src that are not included in any .md file under docs/.\n    \"\"\"\n    docs_src_path = Path(\"docs_src\")\n    # Collect all docs .md content referencing docs_src\n    all_docs_content = \"\"\n    for md_file in docs_path.rglob(\"*.md\"):\n        all_docs_content += md_file.read_text(encoding=\"utf-8\")\n    # Build a set of directory-based package roots (e.g. docs_src/bigger_applications/app_py39)\n    # where at least one file is referenced in docs. All files in these directories\n    # should be kept since they may be internally imported by the referenced files.\n    used_package_dirs: set[Path] = set()\n    for py_file in docs_src_path.rglob(\"*.py\"):\n        if py_file.name == \"__init__.py\":\n            continue\n        rel_path = str(py_file)\n        if rel_path in all_docs_content:\n            # Walk up from the file's parent to find the package root\n            # (a subdirectory under docs_src/<topic>/)\n            parts = py_file.relative_to(docs_src_path).parts\n            if len(parts) > 2:\n                # File is inside a sub-package like docs_src/topic/app_xxx/...\n                package_root = docs_src_path / parts[0] / parts[1]\n                used_package_dirs.add(package_root)\n    removed = 0\n    for py_file in sorted(docs_src_path.rglob(\"*.py\")):\n        if py_file.name == \"__init__.py\":\n            continue\n        # Build the relative path as it appears in includes (e.g. docs_src/first_steps/tutorial001.py)\n        rel_path = str(py_file)\n        if rel_path in all_docs_content:\n            continue\n        # If this file is inside a directory-based package where any sibling is\n        # referenced, keep it (it's likely imported internally).\n        parts = py_file.relative_to(docs_src_path).parts\n        if len(parts) > 2:\n            package_root = docs_src_path / parts[0] / parts[1]\n            if package_root in used_package_dirs:\n                continue\n        # Check if the _an counterpart (or non-_an counterpart) is referenced.\n        # If either variant is included, keep both.\n        # Handle both file-level _an (tutorial001_an.py) and directory-level _an\n        # (app_an/main.py)\n        counterpart_found = False\n        full_path_str = str(py_file)\n        if \"_an\" in py_file.stem:\n            # This is an _an file, check if the non-_an version is referenced\n            counterpart = full_path_str.replace(\n                f\"/{py_file.stem}\", f\"/{py_file.stem.replace('_an', '', 1)}\"\n            )\n            if counterpart in all_docs_content:\n                counterpart_found = True\n        else:\n            # This is a non-_an file, check if there's an _an version referenced\n            # Insert _an before any version suffix or at the end of the stem\n            stem = py_file.stem\n            for suffix in (\"_py39\", \"_py310\"):\n                if suffix in stem:\n                    an_stem = stem.replace(suffix, f\"_an{suffix}\", 1)\n                    break\n            else:\n                an_stem = f\"{stem}_an\"\n            counterpart = full_path_str.replace(f\"/{stem}.\", f\"/{an_stem}.\")\n            if counterpart in all_docs_content:\n                counterpart_found = True\n        # Also check directory-level _an counterparts\n        if not counterpart_found:\n            parent_name = py_file.parent.name\n            if \"_an\" in parent_name:\n                counterpart_parent = parent_name.replace(\"_an\", \"\", 1)\n                counterpart_dir = str(py_file).replace(\n                    f\"/{parent_name}/\", f\"/{counterpart_parent}/\"\n                )\n                if counterpart_dir in all_docs_content:\n                    counterpart_found = True\n            else:\n                # Try inserting _an into parent directory name\n                for suffix in (\"_py39\", \"_py310\"):\n                    if suffix in parent_name:\n                        an_parent = parent_name.replace(suffix, f\"_an{suffix}\", 1)\n                        break\n                else:\n                    an_parent = f\"{parent_name}_an\"\n                counterpart_dir = str(py_file).replace(\n                    f\"/{parent_name}/\", f\"/{an_parent}/\"\n                )\n                if counterpart_dir in all_docs_content:\n                    counterpart_found = True\n        if counterpart_found:\n            continue\n        logging.info(f\"Removing unused file: {py_file}\")\n        py_file.unlink()\n        removed += 1\n    # Clean up directories that are empty or only contain __init__.py / __pycache__\n    for dir_path in sorted(docs_src_path.rglob(\"*\"), reverse=True):\n        if not dir_path.is_dir():\n            continue\n        remaining = [\n            f\n            for f in dir_path.iterdir()\n            if f.name != \"__pycache__\" and f.name != \"__init__.py\"\n        ]\n        if not remaining:\n            logging.info(f\"Removing empty/init-only directory: {dir_path}\")\n            shutil.rmtree(dir_path)\n    print(f\"Removed {removed} unused file(s) ✅\")\n\n\n@app.command()\ndef add_permalinks_page(path: Path, update_existing: bool = False):\n    \"\"\"\n    Add or update header permalinks in specific page of En docs.\n    \"\"\"\n\n    if not path.is_relative_to(en_docs_path / \"docs\"):\n        raise RuntimeError(f\"Path must be inside {en_docs_path}\")\n    rel_path = path.relative_to(en_docs_path / \"docs\")\n\n    # Skip excluded sections\n    if str(rel_path).startswith(non_translated_sections):\n        return\n\n    visible_text_extractor = VisibleTextExtractor()\n    updated_lines = []\n    in_code_block3 = False\n    in_code_block4 = False\n    permalinks = set()\n\n    with path.open(\"r\", encoding=\"utf-8\") as f:\n        lines = f.readlines()\n\n    for line in lines:\n        # Handle codeblocks start and end\n        if not (in_code_block3 or in_code_block4):\n            if code_block4_pattern.match(line):\n                in_code_block4 = True\n            elif code_block3_pattern.match(line):\n                in_code_block3 = True\n        else:\n            if in_code_block4 and code_block4_pattern.match(line):\n                in_code_block4 = False\n            elif in_code_block3 and code_block3_pattern.match(line):\n                in_code_block3 = False\n\n        # Process Headers only outside codeblocks\n        if not (in_code_block3 or in_code_block4):\n            match = header_pattern.match(line)\n            if match:\n                hashes, title, _permalink = match.groups()\n                if (not _permalink) or update_existing:\n                    slug = slugify(\n                        visible_text_extractor.extract_visible_text(\n                            strip_markdown_links(title)\n                        )\n                    )\n                    if slug in permalinks:\n                        # If the slug is already used, append a number to make it unique\n                        count = 1\n                        original_slug = slug\n                        while slug in permalinks:\n                            slug = f\"{original_slug}_{count}\"\n                            count += 1\n                    permalinks.add(slug)\n\n                    line = f\"{hashes} {title} {{ #{slug} }}\\n\"\n\n        updated_lines.append(line)\n\n    with path.open(\"w\", encoding=\"utf-8\") as f:\n        f.writelines(updated_lines)\n\n\n@app.command()\ndef add_permalinks_pages(pages: list[Path], update_existing: bool = False) -> None:\n    \"\"\"\n    Add or update header permalinks in specific pages of En docs.\n    \"\"\"\n    for md_file in pages:\n        add_permalinks_page(md_file, update_existing=update_existing)\n\n\n@app.command()\ndef add_permalinks(update_existing: bool = False) -> None:\n    \"\"\"\n    Add or update header permalinks in all pages of En docs.\n    \"\"\"\n    for md_file in en_docs_path.rglob(\"*.md\"):\n        add_permalinks_page(md_file, update_existing=update_existing)\n\n\nif __name__ == \"__main__\":\n    app()\n"
  },
  {
    "path": "scripts/format.sh",
    "content": "#!/usr/bin/env bash\nset -x\n\nruff check fastapi tests docs_src scripts --fix\nruff format fastapi tests docs_src scripts\n"
  },
  {
    "path": "scripts/general-llm-prompt.md",
    "content": "### Your task\n\nTranslate an English original content to a target language.\n\nThe original content is written in Markdown, write the translation in Markdown as well.\n\nThe original content will be surrounded by triple percentage signs (%%%). Do not include the triple percentage signs in the translation.\n\n[placeholder_for_additional_instructions]\n\n### Technical terms in English\n\nFor technical terms in English that don't have a common translation term, use the original term in English.\n\n### Content of code snippets\n\nDo not translate the content of code snippets, keep the original in English. For example, `list`, `dict`, keep them as is.\n\n### Content of code blocks\n\nDo not translate the content of code blocks, except for comments in the language which the code block uses.\n\nExamples:\n\nSource (English) - The code block is a bash code example with one comment:\n\n```bash\n# Print greeting\necho \"Hello, World!\"\n```\n\nResult (German):\n\n```bash\n# Gruß ausgeben\necho \"Hello, World!\"\n```\n\nSource (English) - The code block is a console example containing HTML tags. No comments, so nothing to change here:\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\nResult (German):\n\n```console\n$ <font color=\"#4E9A06\">fastapi</font> run <u style=\"text-decoration-style:solid\">main.py</u>\n<span style=\"background-color:#009485\"><font color=\"#D3D7CF\"> FastAPI </font></span>  Starting server\n        Searching for package file structure\n```\n\nSource (English) - The code block is a console example containing 5 comments:\n\n\n```console\n// Go to the home directory\n$ cd\n// Create a directory for all your code projects\n$ mkdir code\n// Enter into that code directory\n$ cd code\n// Create a directory for this project\n$ mkdir awesome-project\n// Enter into that project directory\n$ cd awesome-project\n```\n\nResult (German):\n\n```console\n// Gehe zum Home-Verzeichnis\n$ cd\n// Erstelle ein Verzeichnis für alle Ihre Code-Projekte\n$ mkdir code\n// Gehe in dieses Code-Verzeichnis\n$ cd code\n// Erstelle ein Verzeichnis für dieses Projekt\n$ mkdir awesome-project\n// Gehe in dieses Projektverzeichnis\n$ cd awesome-project\n```\n\nIf there is an existing translation and its Mermaid diagram is in sync with the Mermaid diagram in the English source, except a few translated words, then use the Mermaid diagram of the existing translation. The human editor of the translation translated these words in the Mermaid diagram. Keep these translations, do not revert them back to the English source.\n\nExample:\n\nSource (English):\n\n```mermaid\nflowchart LR\n    subgraph global[global env]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone project]\n        stone(philosophers-stone) -->|requires| harry-1\n    end\n```\n\nExisting translation (German) - has three translations:\n\n```mermaid\nflowchart LR\n    subgraph global[globale Umgebung]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone-Projekt]\n        stone(philosophers-stone) -->|benötigt| harry-1\n    end\n```\n\nResult (German) - you change nothing:\n\n```mermaid\nflowchart LR\n    subgraph global[globale Umgebung]\n        harry-1[harry v1]\n    end\n    subgraph stone-project[philosophers-stone-Projekt]\n        stone(philosophers-stone) -->|benötigt| harry-1\n    end\n```\n\n### Special blocks\n\nThere are special blocks of notes, tips and others that look like:\n\n/// note\nHere goes a note\n///\n\nTo translate it, keep the same line and add the translation after a vertical bar.\n\nFor example, if you were translating to Spanish, you would write:\n\n/// note | Nota\n\nSome examples in Spanish:\n\nSource (English):\n\n/// tip\n\nResult (Spanish):\n\n/// tip | Consejo\n\nSource (English):\n\n/// details | Preview\n\nResult (Spanish):\n\n/// details | Vista previa\n\n### Tab blocks\n\nThere are special blocks surrounded by four slashes (////). They mark text, which will be rendered as part of a tab in the final document. The scheme is:\n\n//// tab | {tab title}\n{tab content, may span many lines}\n////\n\nKeep everything before the vertical bar (|) as is, including the vertical bar. Translate the tab title. Translate the tab content, applying the rules you know. Keep the four block closing slashes as is.\n\nExamples:\n\nSource (English):\n\n//// tab | Python 3.8+ non-Annotated\nHello\n////\n\nResult (German):\n\n//// tab | Python 3.8+ nicht annotiert\nHallo\n////\n\nSource (English) - Here there is nothing to translate in the tab title:\n\n//// tab | Linux, macOS, Windows Bash\nHello again\n////\n\nResult (German):\n\n//// tab | Linux, macOS, Windows Bash\nHallo wieder\n////\n\n### Headings\n\nEvery Markdown heading in the English text (all levels) ends with a part inside curly brackets. This part denotes the hash of this heading, which is used in links to this heading. In translations, translate the heading, but do not translate this hash part, so that links do not break.\n\nExamples of how to translate a heading:\n\nSource (English):\n\n```\n## Alternative API docs { #alternative-api-docs }\n```\n\nResult (Spanish):\n\n```\n## Documentación de la API alternativa { #alternative-api-docs }\n```\n\nSource (English):\n\n```\n### Example { #example }\n```\n\nResult (German):\n\n```\n### Beispiel { #example }\n```\n\n### Links\n\nUse the following rules for links (apply both to Markdown-style links ([text](url)) and to HTML-style <a href=\"url\">text</a> tags):\n\n- The order of links should match the order of links in the English source. Do not change the order of links. Rephrase the sentence if necessary.\n\n- For relative URLs, only translate the link text. Do not translate the URL or its parts.\n\nExample:\n\nSource (English):\n\n```\n[One of the fastest Python frameworks available](#performance)\n```\n\nResult (German):\n\n```\n[Eines der schnellsten verfügbaren Python-Frameworks](#performance)\n```\n\n- For absolute URLs which DO NOT start EXACTLY with https://fastapi.tiangolo.com, only translate the link text and leave the URL unchanged.\n\nExample:\n\nSource (English):\n\n```\n<a href=\"https://sqlmodel.tiangolo.com/\" class=\"external-link\" target=\"_blank\">SQLModel docs</a>\n```\n\nResult (German):\n\n```\n<a href=\"https://sqlmodel.tiangolo.com/\" class=\"external-link\" target=\"_blank\">SQLModel-Dokumentation</a>\n```\n\n- For absolute URLs which DO start EXACTLY with https://fastapi.tiangolo.com, only translate the link text and change the URL by adding the language code (https://fastapi.tiangolo.com/{language_code}[rest part of the url]).\n\nExample:\n\nSource (English):\n\n```\n<a href=\"https://fastapi.tiangolo.com/tutorial/path-params/#documentation\" class=\"external-link\" target=\"_blank\">Documentation</a>\n```\n\nResult (Spanish):\n\n```\n<a href=\"https://fastapi.tiangolo.com/es/tutorial/path-params/#documentation\" class=\"external-link\" target=\"_blank\">Documentación</a>\n```\n\n- Do not add language codes for URLs that point to static assets (e.g., images, CSS, JavaScript).\n\nExample:\n\nSource (English):\n\n```\n<a href=\"https://fastapi.tiangolo.com/img/something.jpg\" class=\"external-link\" target=\"_blank\">Something</a>\n```\n\nResult (Spanish):\n\n```\n<a href=\"https://fastapi.tiangolo.com/img/something.jpg\" class=\"external-link\" target=\"_blank\">Algo</a>\n```\n\n- For internal links, only translate link text.\n\nExample:\n\nSource (English):\n\n```\n[Create Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}\n```\n\nResult (German):\n\n```\n[Pull Requests erzeugen](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}\n```\n\n- Do not translate anchor fragments in links (the part after `#`), as they must remain the same to work correctly.\n\n- If an existing translation has a link with an anchor fragment different to the anchor fragment in the English source, then this is an error. Fix this by using the anchor fragment of the English source.\n\nExample:\n\nSource (English):\n\n```\n[Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}\n```\n\nExisting wrong translation (German) - notice the wrongly translated anchor fragment:\n\n```\n[Body - Mehrere Parameter: Einfache Werte im Body](body-multiple-params.md#einzelne-werte-im-body){.internal-link target=_blank}.\n```\n\nResult (German) - you fix the anchor fragment:\n\n```\n[Body - Mehrere Parameter: Einfache Werte im Body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.\n```\n\n- Do not add anchor fragments at will, even if this makes sense. If the English source has no anchor, don't add one.\n\nExample:\n\nSource (English):\n\n```\nCreate a [virtual environment](../virtual-environments.md){.internal-link target=_blank}\n```\n\nWrong translation in German - Anchor added to the URL.\n\n```\nErstelle eine [virtuelle Umgebung](../virtual-environments.md#create-a-virtual-environment){.internal-link target=_blank}\n```\n\nGood translation (German) - URL stays like in the English source.\n\n```\nErstelle eine [Virtuelle Umgebung](../virtual-environments.md){.internal-link target=_blank}\n```\n\n**Important**: Always match the link syntax used in the English source document. If the English source uses Markdown-style links (`[text](url)`), the translation must also use Markdown-style links. If the English source uses HTML-style links (`<a href=\"url\">text</a>`), the translation must also use HTML-style links. The link format in the translation must always mirror the link format in the English source.\n\n### HTML abbr elements\n\nTranslate HTML abbr elements (`<abbr title=\"description\">text</abbr>`) as follows:\n\n- The text inside abbr tag may be surrounded by further HTML or Markdown markup or quotes, for example <code>text</code> or `text` or \"text\". Preserve markup and only translate visible text inside the abbr element.\n\n- If the description (the text inside the title attribute) contains the full phrase for this abbreviation, then append a dash (-) to the full phrase, followed by the translation of the full phrase.\n\nConversion scheme:\n\nSource (English):\n\n```\n<abbr title=\"{full phrase}\">{abbreviation}</abbr>\n```\n\nResult:\n\n```\n<abbr title=\"{full phrase} - {translation of full phrase}\">{abbreviation}</abbr>\n```\n\nExamples:\n\nSource (English):\n\n```\n<abbr title=\"Internet of Things\">IoT</abbr>\n<abbr title=\"Central Processing Unit\">CPU</abbr>\n<abbr title=\"too long; didn't read\"><strong>TL;DR:</strong></abbr>\n```\n\nResult (German):\n\n```\n<abbr title=\"Internet of Things - Internet der Dinge\">IoT</abbr>\n<abbr title=\"Central Processing Unit - Zentrale Verarbeitungseinheit\">CPU</abbr>\n<abbr title=\"too long; didn't read - zu lang; hab's nicht gelesen\"><strong>TL;DR:</strong></abbr>\n```\n\n- If the language to which you translate mostly uses the letters of the ASCII char set (for example Spanish, French, German, but not Russian, Chinese) and if the translation of the full phrase is identical to, or starts with the same letters as the original full phrase, then only give the translation of the full phrase.\n\nConversion scheme:\n\nSource (English):\n\n```\n<abbr title=\"{full phrase}\">{abbreviation}</abbr>\n```\n\nResult:\n\n```\n<abbr title=\"{translation of full phrase}\">{abbreviation}</abbr>\n```\n\nExamples:\n\nSource (English):\n\n```\n<abbr title=\"JSON Web Tokens\">JWT</abbr>\n<abbr title=\"Enumeration\">Enum</abbr>\n<abbr title=\"Asynchronous Server Gateway Interface\">ASGI</abbr>\n```\n\nResult (German):\n\n```\n<abbr title=\"JSON Web Tokens\">JWT</abbr>\n<abbr title=\"Enumeration\">Enum</abbr>\n<abbr title=\"Asynchrones Server-Gateway-Interface\">ASGI</abbr>\n```\n\n- If the title of abbr element contains a full phrase for that abbreviation, and other information, separated by a colon (`:`), then append a dash (`-`) and the translation of the full phrase to the original full phrase and translate the other information.\n\nConversion scheme:\n\nSource (English):\n\n```\n<abbr title=\"{full phrase}: {other information}\">{abbreviation}</abbr>\n```\n\nResult:\n\n```\n<abbr title=\"{full phrase} - {translation of full phrase}: {translation of other information}\">{abbreviation}</abbr>\n```\n\nExamples:\n\nSource (English):\n\n```\n<abbr title=\"Input/Output: disk reading or writing, network communication.\">I/O</abbr>\n<abbr title=\"Content Delivery Network: service, that provides static files.\">CDN</abbr>\n<abbr title=\"Integrated Development Environment: similar to a code editor\">IDE</abbr>\n```\n\nResult (German):\n\n```\n<abbr title=\"Input/Output - Eingabe/Ausgabe: Lesen oder Schreiben auf der Festplatte, Netzwerkkommunikation.\">I/O</abbr>\n<abbr title=\"Content Delivery Network - Inhalte auslieferndes Netzwerk: Dienst, der statische Dateien bereitstellt.\">CDN</abbr>\n<abbr title=\"Integrated Development Environment - Integrierte Entwicklungsumgebung: Ähnlich einem Code-Editor\">IDE</abbr>\n```\n\n- You can leave the original full phrase away, if the translated full phrase is identical or starts with the same letters as the original full phrase.\n\nConversion scheme:\n\nSource (English):\n\n```\n<abbr title=\"{full phrase}: {information}\">{abbreviation}</abbr>\n```\n\nResult:\n\n```\n<abbr title=\"{translation of full phrase}: {translation of information}\">{abbreviation}</abbr>\n```\n\nExample:\n\nSource (English):\n\n```\n<abbr title=\"Object Relational Mapper: a fancy term for a library where some classes represent SQL tables and instances represent rows in those tables\">ORM</abbr>\n```\n\nResult (German):\n\n```\n<abbr title=\"Objektrelationaler Mapper: Ein Fachbegriff für eine Bibliothek, in der einige Klassen SQL-Tabellen und Instanzen Zeilen in diesen Tabellen darstellen\">ORM</abbr>\n```\n\n- If there is an existing translation, and it has ADDITIONAL abbr elements in a sentence, and these additional abbr elements do not exist in the related sentence in the English text, then KEEP those additional abbr elements in the translation. Do not remove them. Except when you remove the whole sentence from the translation, because the whole sentence was removed from the English text, then also remove the abbr element. The reasoning for this rule is, that such additional abbr elements are manually added by the human editor of the translation, in order to translate or explain an English word to the human readers of the translation. These additional abbr elements would not make sense in the English text, but they do make sense in the translation. So keep them in the translation, even though they are not part of the English text. This rule only applies to abbr elements.\n\n- Apply above rules also when there is an existing translation! Make sure that all title attributes in abbr elements get properly translated or updated, using the schemes given above. However, leave the ADDITIONAL abbr's described above alone. Do not change their formatting or content.\n\n### HTML dfn elements\n\nFor HTML dfn elements (`<dfn>text</dfn>`), translate the text inside the dfn element and the title attribute. Do not include the original English text in the title attribute.\n\nExamples:\n\nSource (English):\n\n```\n<dfn title=\"also known as: endpoints, routes\">path</dfn>\n<dfn title=\"a program that checks for code errors\">linter</dfn>\n```\n\nResult (German):\n\n```\n<dfn title=\"auch bekannt als: Endpunkte, Routen\">Pfad</dfn>\n<dfn title=\"Programm das auf Fehler im Code prüft\">Linter</dfn>\n```\n"
  },
  {
    "path": "scripts/label_approved.py",
    "content": "import logging\nfrom typing import Literal\n\nfrom github import Github\nfrom github.PullRequestReview import PullRequestReview\nfrom pydantic import BaseModel, SecretStr\nfrom pydantic_settings import BaseSettings\n\n\nclass LabelSettings(BaseModel):\n    await_label: str | None = None\n    number: int\n\n\ndefault_config = {\"approved-2\": LabelSettings(await_label=\"awaiting-review\", number=2)}\n\n\nclass Settings(BaseSettings):\n    github_repository: str\n    token: SecretStr\n    debug: bool | None = False\n    config: dict[str, LabelSettings] | Literal[\"\"] = default_config\n\n\nsettings = Settings()\nif settings.debug:\n    logging.basicConfig(level=logging.DEBUG)\nelse:\n    logging.basicConfig(level=logging.INFO)\nlogging.debug(f\"Using config: {settings.model_dump_json()}\")\ng = Github(settings.token.get_secret_value())\nrepo = g.get_repo(settings.github_repository)\nfor pr in repo.get_pulls(state=\"open\"):\n    logging.info(f\"Checking PR: #{pr.number}\")\n    pr_labels = list(pr.get_labels())\n    pr_label_by_name = {label.name: label for label in pr_labels}\n    reviews = list(pr.get_reviews())\n    review_by_user: dict[str, PullRequestReview] = {}\n    for review in reviews:\n        if review.user.login in review_by_user:\n            stored_review = review_by_user[review.user.login]\n            if review.submitted_at >= stored_review.submitted_at:\n                review_by_user[review.user.login] = review\n        else:\n            review_by_user[review.user.login] = review\n    approved_reviews = [\n        review for review in review_by_user.values() if review.state == \"APPROVED\"\n    ]\n    config = settings.config or default_config\n    for approved_label, conf in config.items():\n        logging.debug(f\"Processing config: {conf.model_dump_json()}\")\n        if conf.await_label is None or (conf.await_label in pr_label_by_name):\n            logging.debug(f\"Processable PR: {pr.number}\")\n            if len(approved_reviews) >= conf.number:\n                logging.info(f\"Adding label to PR: {pr.number}\")\n                pr.add_to_labels(approved_label)\n                if conf.await_label:\n                    logging.info(f\"Removing label from PR: {pr.number}\")\n                    pr.remove_from_labels(conf.await_label)\nlogging.info(\"Finished\")\n"
  },
  {
    "path": "scripts/lint.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\nset -x\n\nmypy fastapi\nty check fastapi\nruff check fastapi tests docs_src scripts\nruff format fastapi tests --check\n"
  },
  {
    "path": "scripts/mkdocs_hooks.py",
    "content": "from functools import lru_cache\nfrom pathlib import Path\nfrom typing import Any\n\nimport material\nfrom mkdocs.config.defaults import MkDocsConfig\nfrom mkdocs.structure.files import File, Files\nfrom mkdocs.structure.nav import Link, Navigation, Section\nfrom mkdocs.structure.pages import Page\n\nnon_translated_sections = [\n    \"reference/\",\n    \"release-notes.md\",\n    \"fastapi-people.md\",\n    \"external-links.md\",\n    \"newsletter.md\",\n    \"management-tasks.md\",\n    \"management.md\",\n]\n\n\n@lru_cache\ndef get_missing_translation_content(docs_dir: str) -> str:\n    docs_dir_path = Path(docs_dir)\n    missing_translation_path = docs_dir_path.parent.parent / \"missing-translation.md\"\n    return missing_translation_path.read_text(encoding=\"utf-8\")\n\n\n@lru_cache\ndef get_translation_banner_content(docs_dir: str) -> str:\n    docs_dir_path = Path(docs_dir)\n    translation_banner_path = docs_dir_path / \"translation-banner.md\"\n    if not translation_banner_path.is_file():\n        translation_banner_path = (\n            docs_dir_path.parent.parent / \"en\" / \"docs\" / \"translation-banner.md\"\n        )\n    return translation_banner_path.read_text(encoding=\"utf-8\")\n\n\n@lru_cache\ndef get_mkdocs_material_langs() -> list[str]:\n    material_path = Path(material.__file__).parent\n    material_langs_path = material_path / \"templates\" / \"partials\" / \"languages\"\n    langs = [file.stem for file in material_langs_path.glob(\"*.html\")]\n    return langs\n\n\nclass EnFile(File):\n    pass\n\n\ndef on_config(config: MkDocsConfig, **kwargs: Any) -> MkDocsConfig:\n    available_langs = get_mkdocs_material_langs()\n    dir_path = Path(config.docs_dir)\n    lang = dir_path.parent.name\n    if lang in available_langs:\n        config.theme[\"language\"] = lang\n    if not (config.site_url or \"\").endswith(f\"{lang}/\") and lang != \"en\":\n        config.site_url = f\"{config.site_url}{lang}/\"\n    return config\n\n\ndef resolve_file(*, item: str, files: Files, config: MkDocsConfig) -> None:\n    item_path = Path(config.docs_dir) / item\n    if not item_path.is_file():\n        en_src_dir = (Path(config.docs_dir) / \"../../en/docs\").resolve()\n        potential_path = en_src_dir / item\n        if potential_path.is_file():\n            files.append(\n                EnFile(\n                    path=item,\n                    src_dir=str(en_src_dir),\n                    dest_dir=config.site_dir,\n                    use_directory_urls=config.use_directory_urls,\n                )\n            )\n\n\ndef resolve_files(*, items: list[Any], files: Files, config: MkDocsConfig) -> None:\n    for item in items:\n        if isinstance(item, str):\n            resolve_file(item=item, files=files, config=config)\n        elif isinstance(item, dict):\n            assert len(item) == 1\n            values = list(item.values())\n            if not values:\n                continue\n            if isinstance(values[0], str):\n                resolve_file(item=values[0], files=files, config=config)\n            elif isinstance(values[0], list):\n                resolve_files(items=values[0], files=files, config=config)\n            else:\n                raise ValueError(f\"Unexpected value: {values}\")\n\n\ndef on_files(files: Files, *, config: MkDocsConfig) -> Files:\n    resolve_files(items=config.nav or [], files=files, config=config)\n    if \"logo\" in config.theme:\n        resolve_file(item=config.theme[\"logo\"], files=files, config=config)\n    if \"favicon\" in config.theme:\n        resolve_file(item=config.theme[\"favicon\"], files=files, config=config)\n    resolve_files(items=config.extra_css, files=files, config=config)\n    resolve_files(items=config.extra_javascript, files=files, config=config)\n    return files\n\n\ndef generate_renamed_section_items(\n    items: list[Page | Section | Link], *, config: MkDocsConfig\n) -> list[Page | Section | Link]:\n    new_items: list[Page | Section | Link] = []\n    for item in items:\n        if isinstance(item, Section):\n            new_title = item.title\n            new_children = generate_renamed_section_items(item.children, config=config)\n            first_child = new_children[0]\n            if isinstance(first_child, Page):\n                if first_child.file.src_path.endswith(\"index.md\"):\n                    # Read the source so that the title is parsed and available\n                    first_child.read_source(config=config)\n                    new_title = first_child.title or new_title\n            # Creating a new section makes it render it collapsed by default\n            # no idea why, so, let's just modify the existing one\n            # new_section = Section(title=new_title, children=new_children)\n            item.title = new_title.split(\"{ #\")[0]\n            item.children = new_children\n            new_items.append(item)\n        else:\n            new_items.append(item)\n    return new_items\n\n\ndef on_nav(\n    nav: Navigation, *, config: MkDocsConfig, files: Files, **kwargs: Any\n) -> Navigation:\n    new_items = generate_renamed_section_items(nav.items, config=config)\n    return Navigation(items=new_items, pages=nav.pages)\n\n\ndef on_pre_page(page: Page, *, config: MkDocsConfig, files: Files) -> Page:\n    return page\n\n\ndef on_page_markdown(\n    markdown: str, *, page: Page, config: MkDocsConfig, files: Files\n) -> str:\n    # Set metadata[\"social\"][\"cards_layout_options\"][\"title\"] to clean title (without\n    # permalink)\n    title = page.title\n    clean_title = title.split(\"{ #\")[0]\n    if clean_title:\n        page.meta.setdefault(\"social\", {})\n        page.meta[\"social\"].setdefault(\"cards_layout_options\", {})\n        page.meta[\"social\"][\"cards_layout_options\"][\"title\"] = clean_title\n\n    if isinstance(page.file, EnFile):\n        for excluded_section in non_translated_sections:\n            if page.file.src_path.startswith(excluded_section):\n                return markdown\n        missing_translation_content = get_missing_translation_content(config.docs_dir)\n        header = \"\"\n        body = markdown\n        if markdown.startswith(\"#\"):\n            header, _, body = markdown.partition(\"\\n\\n\")\n        return f\"{header}\\n\\n{missing_translation_content}\\n\\n{body}\"\n\n    docs_dir_path = Path(config.docs_dir)\n    en_docs_dir_path = docs_dir_path.parent.parent / \"en/docs\"\n\n    if docs_dir_path == en_docs_dir_path:\n        return markdown\n\n    # For translated pages add translation banner\n    translation_banner_content = get_translation_banner_content(config.docs_dir)\n    en_url = \"https://fastapi.tiangolo.com/\" + page.url.lstrip(\"/\")\n    translation_banner_content = translation_banner_content.replace(\n        \"ENGLISH_VERSION_URL\", en_url\n    )\n    header = \"\"\n    body = markdown\n    if markdown.startswith(\"#\"):\n        header, _, body = markdown.partition(\"\\n\\n\")\n    return f\"{header}\\n\\n{translation_banner_content}\\n\\n{body}\"\n"
  },
  {
    "path": "scripts/notify_translations.py",
    "content": "import logging\nimport random\nimport sys\nimport time\nfrom pathlib import Path\nfrom typing import Any, cast\n\nimport httpx\nfrom github import Github\nfrom pydantic import BaseModel, SecretStr\nfrom pydantic_settings import BaseSettings\n\nawaiting_label = \"awaiting-review\"\nlang_all_label = \"lang-all\"\napproved_label = \"approved-1\"\n\n\ngithub_graphql_url = \"https://api.github.com/graphql\"\nquestions_translations_category_id = \"DIC_kwDOCZduT84CT5P9\"\n\nall_discussions_query = \"\"\"\nquery Q($category_id: ID) {\n  repository(name: \"fastapi\", owner: \"fastapi\") {\n    discussions(categoryId: $category_id, first: 100) {\n      nodes {\n        title\n        id\n        number\n        labels(first: 10) {\n          edges {\n            node {\n              id\n              name\n            }\n          }\n        }\n      }\n    }\n  }\n}\n\"\"\"\n\ntranslation_discussion_query = \"\"\"\nquery Q($after: String, $discussion_number: Int!) {\n  repository(name: \"fastapi\", owner: \"fastapi\") {\n    discussion(number: $discussion_number) {\n      comments(first: 100, after: $after) {\n        edges {\n          cursor\n          node {\n            id\n            url\n            body\n          }\n        }\n      }\n    }\n  }\n}\n\"\"\"\n\nadd_comment_mutation = \"\"\"\nmutation Q($discussion_id: ID!, $body: String!) {\n  addDiscussionComment(input: {discussionId: $discussion_id, body: $body}) {\n    comment {\n      id\n      url\n      body\n    }\n  }\n}\n\"\"\"\n\nupdate_comment_mutation = \"\"\"\nmutation Q($comment_id: ID!, $body: String!) {\n  updateDiscussionComment(input: {commentId: $comment_id, body: $body}) {\n    comment {\n      id\n      url\n      body\n    }\n  }\n}\n\"\"\"\n\n\nclass Comment(BaseModel):\n    id: str\n    url: str\n    body: str\n\n\nclass UpdateDiscussionComment(BaseModel):\n    comment: Comment\n\n\nclass UpdateCommentData(BaseModel):\n    updateDiscussionComment: UpdateDiscussionComment\n\n\nclass UpdateCommentResponse(BaseModel):\n    data: UpdateCommentData\n\n\nclass AddDiscussionComment(BaseModel):\n    comment: Comment\n\n\nclass AddCommentData(BaseModel):\n    addDiscussionComment: AddDiscussionComment\n\n\nclass AddCommentResponse(BaseModel):\n    data: AddCommentData\n\n\nclass CommentsEdge(BaseModel):\n    node: Comment\n    cursor: str\n\n\nclass Comments(BaseModel):\n    edges: list[CommentsEdge]\n\n\nclass CommentsDiscussion(BaseModel):\n    comments: Comments\n\n\nclass CommentsRepository(BaseModel):\n    discussion: CommentsDiscussion\n\n\nclass CommentsData(BaseModel):\n    repository: CommentsRepository\n\n\nclass CommentsResponse(BaseModel):\n    data: CommentsData\n\n\nclass AllDiscussionsLabelNode(BaseModel):\n    id: str\n    name: str\n\n\nclass AllDiscussionsLabelsEdge(BaseModel):\n    node: AllDiscussionsLabelNode\n\n\nclass AllDiscussionsDiscussionLabels(BaseModel):\n    edges: list[AllDiscussionsLabelsEdge]\n\n\nclass AllDiscussionsDiscussionNode(BaseModel):\n    title: str\n    id: str\n    number: int\n    labels: AllDiscussionsDiscussionLabels\n\n\nclass AllDiscussionsDiscussions(BaseModel):\n    nodes: list[AllDiscussionsDiscussionNode]\n\n\nclass AllDiscussionsRepository(BaseModel):\n    discussions: AllDiscussionsDiscussions\n\n\nclass AllDiscussionsData(BaseModel):\n    repository: AllDiscussionsRepository\n\n\nclass AllDiscussionsResponse(BaseModel):\n    data: AllDiscussionsData\n\n\nclass Settings(BaseSettings):\n    model_config = {\"env_ignore_empty\": True}\n\n    github_repository: str\n    github_token: SecretStr\n    github_event_path: Path\n    github_event_name: str | None = None\n    httpx_timeout: int = 30\n    debug: bool | None = False\n    number: int | None = None\n\n\nclass PartialGitHubEventIssue(BaseModel):\n    number: int | None = None\n\n\nclass PartialGitHubEvent(BaseModel):\n    pull_request: PartialGitHubEventIssue | None = None\n\n\ndef get_graphql_response(\n    *,\n    settings: Settings,\n    query: str,\n    after: str | None = None,\n    category_id: str | None = None,\n    discussion_number: int | None = None,\n    discussion_id: str | None = None,\n    comment_id: str | None = None,\n    body: str | None = None,\n) -> dict[str, Any]:\n    headers = {\"Authorization\": f\"token {settings.github_token.get_secret_value()}\"}\n    variables = {\n        \"after\": after,\n        \"category_id\": category_id,\n        \"discussion_number\": discussion_number,\n        \"discussion_id\": discussion_id,\n        \"comment_id\": comment_id,\n        \"body\": body,\n    }\n    response = httpx.post(\n        github_graphql_url,\n        headers=headers,\n        timeout=settings.httpx_timeout,\n        json={\"query\": query, \"variables\": variables, \"operationName\": \"Q\"},\n    )\n    if response.status_code != 200:\n        logging.error(\n            f\"Response was not 200, after: {after}, category_id: {category_id}\"\n        )\n        logging.error(response.text)\n        raise RuntimeError(response.text)\n    data = response.json()\n    if \"errors\" in data:\n        logging.error(f\"Errors in response, after: {after}, category_id: {category_id}\")\n        logging.error(data[\"errors\"])\n        logging.error(response.text)\n        raise RuntimeError(response.text)\n    return cast(dict[str, Any], data)\n\n\ndef get_graphql_translation_discussions(\n    *, settings: Settings\n) -> list[AllDiscussionsDiscussionNode]:\n    data = get_graphql_response(\n        settings=settings,\n        query=all_discussions_query,\n        category_id=questions_translations_category_id,\n    )\n    graphql_response = AllDiscussionsResponse.model_validate(data)\n    return graphql_response.data.repository.discussions.nodes\n\n\ndef get_graphql_translation_discussion_comments_edges(\n    *, settings: Settings, discussion_number: int, after: str | None = None\n) -> list[CommentsEdge]:\n    data = get_graphql_response(\n        settings=settings,\n        query=translation_discussion_query,\n        discussion_number=discussion_number,\n        after=after,\n    )\n    graphql_response = CommentsResponse.model_validate(data)\n    return graphql_response.data.repository.discussion.comments.edges\n\n\ndef get_graphql_translation_discussion_comments(\n    *, settings: Settings, discussion_number: int\n) -> list[Comment]:\n    comment_nodes: list[Comment] = []\n    discussion_edges = get_graphql_translation_discussion_comments_edges(\n        settings=settings, discussion_number=discussion_number\n    )\n\n    while discussion_edges:\n        for discussion_edge in discussion_edges:\n            comment_nodes.append(discussion_edge.node)\n        last_edge = discussion_edges[-1]\n        discussion_edges = get_graphql_translation_discussion_comments_edges(\n            settings=settings,\n            discussion_number=discussion_number,\n            after=last_edge.cursor,\n        )\n    return comment_nodes\n\n\ndef create_comment(*, settings: Settings, discussion_id: str, body: str) -> Comment:\n    data = get_graphql_response(\n        settings=settings,\n        query=add_comment_mutation,\n        discussion_id=discussion_id,\n        body=body,\n    )\n    response = AddCommentResponse.model_validate(data)\n    return response.data.addDiscussionComment.comment\n\n\ndef update_comment(*, settings: Settings, comment_id: str, body: str) -> Comment:\n    data = get_graphql_response(\n        settings=settings,\n        query=update_comment_mutation,\n        comment_id=comment_id,\n        body=body,\n    )\n    response = UpdateCommentResponse.model_validate(data)\n    return response.data.updateDiscussionComment.comment\n\n\ndef main() -> None:\n    settings = Settings()\n    if settings.debug:\n        logging.basicConfig(level=logging.DEBUG)\n    else:\n        logging.basicConfig(level=logging.INFO)\n    logging.debug(f\"Using config: {settings.model_dump_json()}\")\n    g = Github(settings.github_token.get_secret_value())\n    repo = g.get_repo(settings.github_repository)\n    if not settings.github_event_path.is_file():\n        raise RuntimeError(\n            f\"No github event file available at: {settings.github_event_path}\"\n        )\n    contents = settings.github_event_path.read_text(\"utf-8\")\n    github_event = PartialGitHubEvent.model_validate_json(contents)\n    logging.info(f\"Using GitHub event: {github_event}\")\n    number = (\n        github_event.pull_request and github_event.pull_request.number\n    ) or settings.number\n    if number is None:\n        raise RuntimeError(\"No PR number available\")\n\n    # Avoid race conditions with multiple labels\n    sleep_time = random.random() * 10  # random number between 0 and 10 seconds\n    logging.info(\n        f\"Sleeping for {sleep_time} seconds to avoid \"\n        \"race conditions and multiple comments\"\n    )\n    time.sleep(sleep_time)\n\n    # Get PR\n    logging.debug(f\"Processing PR: #{number}\")\n    pr = repo.get_pull(number)\n    label_strs = {label.name for label in pr.get_labels()}\n    langs = []\n    for label in label_strs:\n        if label.startswith(\"lang-\") and not label == lang_all_label:\n            langs.append(label[5:])\n    logging.info(f\"PR #{pr.number} has labels: {label_strs}\")\n    if not langs or lang_all_label not in label_strs:\n        logging.info(f\"PR #{pr.number} doesn't seem to be a translation PR, skipping\")\n        sys.exit(0)\n\n    # Generate translation map, lang ID to discussion\n    discussions = get_graphql_translation_discussions(settings=settings)\n    lang_to_discussion_map: dict[str, AllDiscussionsDiscussionNode] = {}\n    for discussion in discussions:\n        for edge in discussion.labels.edges:\n            label = edge.node.name\n            if label.startswith(\"lang-\") and not label == lang_all_label:\n                lang = label[5:]\n                lang_to_discussion_map[lang] = discussion\n    logging.debug(f\"Using translations map: {lang_to_discussion_map}\")\n\n    # Messages to create or check\n    new_translation_message = f\"Good news everyone! 😉 There's a new translation PR to be reviewed: #{pr.number} by @{pr.user.login}. 🎉 This requires 2 approvals from native speakers to be merged. 🤓\"\n    done_translation_message = f\"~There's a new translation PR to be reviewed: #{pr.number} by @{pr.user.login}~ Good job! This is done. 🍰☕\"\n\n    # Normally only one language, but still\n    for lang in langs:\n        if lang not in lang_to_discussion_map:\n            log_message = f\"Could not find discussion for language: {lang}\"\n            logging.error(log_message)\n            raise RuntimeError(log_message)\n        discussion = lang_to_discussion_map[lang]\n        logging.info(\n            f\"Found a translation discussion for language: {lang} in discussion: #{discussion.number}\"\n        )\n\n        already_notified_comment: Comment | None = None\n        already_done_comment: Comment | None = None\n\n        logging.info(\n            f\"Checking current comments in discussion: #{discussion.number} to see if already notified about this PR: #{pr.number}\"\n        )\n        comments = get_graphql_translation_discussion_comments(\n            settings=settings, discussion_number=discussion.number\n        )\n        for comment in comments:\n            if new_translation_message in comment.body:\n                already_notified_comment = comment\n            elif done_translation_message in comment.body:\n                already_done_comment = comment\n        logging.info(\n            f\"Already notified comment: {already_notified_comment}, already done comment: {already_done_comment}\"\n        )\n\n        if pr.state == \"open\" and awaiting_label in label_strs:\n            logging.info(\n                f\"This PR seems to be a language translation and awaiting reviews: #{pr.number}\"\n            )\n            if already_notified_comment:\n                logging.info(\n                    f\"This PR #{pr.number} was already notified in comment: {already_notified_comment.url}\"\n                )\n            else:\n                logging.info(\n                    f\"Writing notification comment about PR #{pr.number} in Discussion: #{discussion.number}\"\n                )\n                comment = create_comment(\n                    settings=settings,\n                    discussion_id=discussion.id,\n                    body=new_translation_message,\n                )\n                logging.info(f\"Notified in comment: {comment.url}\")\n        elif pr.state == \"closed\" or approved_label in label_strs:\n            logging.info(f\"Already approved or closed PR #{pr.number}\")\n            if already_done_comment:\n                logging.info(\n                    f\"This PR #{pr.number} was already marked as done in comment: {already_done_comment.url}\"\n                )\n            elif already_notified_comment:\n                updated_comment = update_comment(\n                    settings=settings,\n                    comment_id=already_notified_comment.id,\n                    body=done_translation_message,\n                )\n                logging.info(f\"Marked as done in comment: {updated_comment.url}\")\n        else:\n            logging.info(\n                f\"There doesn't seem to be anything to be done about PR #{pr.number}\"\n            )\n    logging.info(\"Finished\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/people.py",
    "content": "import logging\nimport secrets\nimport subprocess\nimport time\nfrom collections import Counter\nfrom collections.abc import Container\nfrom datetime import datetime, timedelta, timezone\nfrom math import ceil\nfrom pathlib import Path\nfrom typing import Annotated, Any\n\nimport httpx\nimport yaml\nfrom github import Github\nfrom pydantic import BaseModel, BeforeValidator, SecretStr\nfrom pydantic_settings import BaseSettings\n\ngithub_graphql_url = \"https://api.github.com/graphql\"\nquestions_category_id = \"DIC_kwDOCZduT84B6E2a\"\n\n\nPOINTS_PER_MINUTE_LIMIT = 84  # 5000 points per hour\n\nMINIMIZED_COMMENTS_REASONS_TO_EXCLUDE = {\"abuse\", \"off-topic\", \"duplicate\", \"spam\"}\n\n\nclass RateLimiter:\n    def __init__(self) -> None:\n        self.last_query_cost: int = 1\n        self.remaining_points: int = 5000\n        self.reset_at: datetime = datetime.fromtimestamp(0, timezone.utc)\n        self.last_request_start_time: datetime = datetime.fromtimestamp(0, timezone.utc)\n        self.speed_multiplier: float = 1.0\n\n    def __enter__(self) -> \"RateLimiter\":\n        now = datetime.now(tz=timezone.utc)\n\n        # Handle primary rate limits\n        primary_limit_wait_time = 0.0\n        if self.remaining_points <= self.last_query_cost:\n            primary_limit_wait_time = (self.reset_at - now).total_seconds() + 2\n            logging.warning(\n                f\"Approaching GitHub API rate limit, remaining points: {self.remaining_points}, \"\n                f\"reset time in {primary_limit_wait_time} seconds\"\n            )\n\n        # Handle secondary rate limits\n        secondary_limit_wait_time = 0.0\n        points_per_minute = POINTS_PER_MINUTE_LIMIT * self.speed_multiplier\n        interval = 60 / (points_per_minute / self.last_query_cost)\n        time_since_last_request = (now - self.last_request_start_time).total_seconds()\n        if time_since_last_request < interval:\n            secondary_limit_wait_time = interval - time_since_last_request\n\n        final_wait_time = ceil(max(primary_limit_wait_time, secondary_limit_wait_time))\n        logging.info(f\"Sleeping for {final_wait_time} seconds to respect rate limit\")\n        time.sleep(max(final_wait_time, 1))\n\n        self.last_request_start_time = datetime.now(tz=timezone.utc)\n        return self\n\n    def __exit__(self, exc_type, exc_val, exc_tb) -> None:\n        pass\n\n    def update_request_info(self, cost: int, remaining: int, reset_at: str) -> None:\n        self.last_query_cost = cost\n        self.remaining_points = remaining\n        self.reset_at = datetime.fromisoformat(reset_at.replace(\"Z\", \"+00:00\"))\n\n\nrate_limiter = RateLimiter()\n\n\ndiscussions_query = \"\"\"\nquery Q($after: String, $category_id: ID) {\n  repository(name: \"fastapi\", owner: \"fastapi\") {\n    discussions(first: 30, after: $after, categoryId: $category_id) {\n      edges {\n        cursor\n        node {\n          number\n          author {\n            login\n            avatarUrl\n            url\n          }\n          createdAt\n          comments(first: 50) {\n            totalCount\n            nodes {\n              createdAt\n              author {\n                login\n                avatarUrl\n                url\n              }\n              isAnswer\n              replies(first: 10) {\n                totalCount\n                nodes {\n                  createdAt\n                  author {\n                    login\n                    avatarUrl\n                    url\n                  }\n                  minimizedReason\n                }\n              }\n              minimizedReason\n            }\n          }\n        }\n      }\n    }\n  }\n  rateLimit {\n    cost\n    remaining\n    resetAt\n  }\n}\n\"\"\"\n\nLowerStr = Annotated[\n    str, BeforeValidator(lambda v: v.lower() if isinstance(v, str) else v)\n]\n\n\nclass Author(BaseModel):\n    login: str\n    avatarUrl: str | None = None\n    url: str | None = None\n\n\nclass CommentsNode(BaseModel):\n    createdAt: datetime\n    author: Author | None = None\n    minimizedReason: LowerStr | None = None\n\n\nclass Replies(BaseModel):\n    totalCount: int\n    nodes: list[CommentsNode]\n\n\nclass DiscussionsCommentsNode(CommentsNode):\n    minimizedReason: LowerStr | None = None\n    replies: Replies\n\n\nclass DiscussionsComments(BaseModel):\n    totalCount: int\n    nodes: list[DiscussionsCommentsNode]\n\n\nclass DiscussionsNode(BaseModel):\n    number: int\n    author: Author | None = None\n    title: str | None = None\n    createdAt: datetime\n    comments: DiscussionsComments\n\n\nclass DiscussionsEdge(BaseModel):\n    cursor: str\n    node: DiscussionsNode\n\n\nclass Discussions(BaseModel):\n    edges: list[DiscussionsEdge]\n\n\nclass DiscussionsRepository(BaseModel):\n    discussions: Discussions\n\n\nclass DiscussionsResponseData(BaseModel):\n    repository: DiscussionsRepository\n\n\nclass DiscussionsResponse(BaseModel):\n    data: DiscussionsResponseData\n\n\nclass Settings(BaseSettings):\n    github_token: SecretStr\n    github_repository: str\n    httpx_timeout: int = 30\n    speed_multiplier: float = 1.0\n\n\ndef get_graphql_response(\n    *,\n    settings: Settings,\n    query: str,\n    after: str | None = None,\n    category_id: str | None = None,\n) -> dict[str, Any]:\n    headers = {\"Authorization\": f\"token {settings.github_token.get_secret_value()}\"}\n    variables = {\"after\": after, \"category_id\": category_id}\n    response = httpx.post(\n        github_graphql_url,\n        headers=headers,\n        timeout=settings.httpx_timeout,\n        json={\"query\": query, \"variables\": variables, \"operationName\": \"Q\"},\n    )\n    if response.status_code != 200:\n        logging.error(\n            f\"Response was not 200, after: {after}, category_id: {category_id}\"\n        )\n        logging.error(response.text)\n        raise RuntimeError(response.text)\n    data = response.json()\n    if \"errors\" in data:\n        logging.error(f\"Errors in response, after: {after}, category_id: {category_id}\")\n        logging.error(data[\"errors\"])\n        logging.error(response.text)\n        raise RuntimeError(response.text)\n    return data\n\n\ndef get_graphql_question_discussion_edges(\n    *,\n    settings: Settings,\n    after: str | None = None,\n) -> list[DiscussionsEdge]:\n    with rate_limiter:\n        data = get_graphql_response(\n            settings=settings,\n            query=discussions_query,\n            after=after,\n            category_id=questions_category_id,\n        )\n\n    rate_limiter.update_request_info(\n        cost=data[\"data\"][\"rateLimit\"][\"cost\"],\n        remaining=data[\"data\"][\"rateLimit\"][\"remaining\"],\n        reset_at=data[\"data\"][\"rateLimit\"][\"resetAt\"],\n    )\n    graphql_response = DiscussionsResponse.model_validate(data)\n    return graphql_response.data.repository.discussions.edges\n\n\nclass DiscussionExpertsResults(BaseModel):\n    commenters: Counter[str]\n    last_month_commenters: Counter[str]\n    three_months_commenters: Counter[str]\n    six_months_commenters: Counter[str]\n    one_year_commenters: Counter[str]\n    authors: dict[str, Author]\n\n\ndef get_discussion_nodes(settings: Settings) -> list[DiscussionsNode]:\n    discussion_nodes: list[DiscussionsNode] = []\n    discussion_edges = get_graphql_question_discussion_edges(settings=settings)\n\n    while discussion_edges:\n        for discussion_edge in discussion_edges:\n            discussion_nodes.append(discussion_edge.node)\n        last_edge = discussion_edges[-1]\n        discussion_edges = get_graphql_question_discussion_edges(\n            settings=settings, after=last_edge.cursor\n        )\n    return discussion_nodes\n\n\ndef get_discussions_experts(\n    discussion_nodes: list[DiscussionsNode],\n) -> DiscussionExpertsResults:\n    commenters = Counter[str]()\n    last_month_commenters = Counter[str]()\n    three_months_commenters = Counter[str]()\n    six_months_commenters = Counter[str]()\n    one_year_commenters = Counter[str]()\n    authors: dict[str, Author] = {}\n\n    now = datetime.now(tz=timezone.utc)\n    one_month_ago = now - timedelta(days=30)\n    three_months_ago = now - timedelta(days=90)\n    six_months_ago = now - timedelta(days=180)\n    one_year_ago = now - timedelta(days=365)\n\n    for discussion in discussion_nodes:\n        discussion_author_name = None\n        if discussion.author:\n            authors[discussion.author.login] = discussion.author\n            discussion_author_name = discussion.author.login\n        discussion_commentors: dict[str, datetime] = {}\n        for comment in discussion.comments.nodes:\n            if (\n                comment.minimizedReason not in MINIMIZED_COMMENTS_REASONS_TO_EXCLUDE\n                and comment.author\n            ):\n                authors[comment.author.login] = comment.author\n                if comment.author.login != discussion_author_name:\n                    author_time = discussion_commentors.get(\n                        comment.author.login, comment.createdAt\n                    )\n                    discussion_commentors[comment.author.login] = max(\n                        author_time, comment.createdAt\n                    )\n            for reply in comment.replies.nodes:\n                if (\n                    reply.minimizedReason not in MINIMIZED_COMMENTS_REASONS_TO_EXCLUDE\n                    and reply.author\n                ):\n                    authors[reply.author.login] = reply.author\n                    if reply.author.login != discussion_author_name:\n                        author_time = discussion_commentors.get(\n                            reply.author.login, reply.createdAt\n                        )\n                        discussion_commentors[reply.author.login] = max(\n                            author_time, reply.createdAt\n                        )\n        for author_name, author_time in discussion_commentors.items():\n            commenters[author_name] += 1\n            if author_time > one_month_ago:\n                last_month_commenters[author_name] += 1\n            if author_time > three_months_ago:\n                three_months_commenters[author_name] += 1\n            if author_time > six_months_ago:\n                six_months_commenters[author_name] += 1\n            if author_time > one_year_ago:\n                one_year_commenters[author_name] += 1\n    discussion_experts_results = DiscussionExpertsResults(\n        authors=authors,\n        commenters=commenters,\n        last_month_commenters=last_month_commenters,\n        three_months_commenters=three_months_commenters,\n        six_months_commenters=six_months_commenters,\n        one_year_commenters=one_year_commenters,\n    )\n    return discussion_experts_results\n\n\ndef get_top_users(\n    *,\n    counter: Counter[str],\n    authors: dict[str, Author],\n    skip_users: Container[str],\n    min_count: int = 2,\n) -> list[dict[str, Any]]:\n    users: list[dict[str, Any]] = []\n    for commenter, count in counter.most_common(50):\n        if commenter in skip_users:\n            continue\n        if count >= min_count:\n            author = authors[commenter]\n            users.append(\n                {\n                    \"login\": commenter,\n                    \"count\": count,\n                    \"avatarUrl\": author.avatarUrl,\n                    \"url\": author.url,\n                }\n            )\n    return users\n\n\ndef get_users_to_write(\n    *,\n    counter: Counter[str],\n    authors: dict[str, Author],\n    min_count: int = 2,\n) -> list[dict[str, Any]]:\n    users: dict[str, Any] = {}\n    users_list: list[dict[str, Any]] = []\n    for user, count in counter.most_common(60):\n        if count >= min_count:\n            author = authors[user]\n            user_data = {\n                \"login\": user,\n                \"count\": count,\n                \"avatarUrl\": author.avatarUrl,\n                \"url\": author.url,\n            }\n            users[user] = user_data\n            users_list.append(user_data)\n    return users_list\n\n\ndef update_content(*, content_path: Path, new_content: Any) -> bool:\n    old_content = content_path.read_text(encoding=\"utf-8\")\n\n    new_content = yaml.dump(new_content, sort_keys=False, width=200, allow_unicode=True)\n    if old_content == new_content:\n        logging.info(f\"The content hasn't changed for {content_path}\")\n        return False\n    content_path.write_text(new_content, encoding=\"utf-8\")\n    logging.info(f\"Updated {content_path}\")\n    return True\n\n\ndef main() -> None:\n    logging.basicConfig(level=logging.INFO)\n    settings = Settings()\n    logging.info(f\"Using config: {settings.model_dump_json()}\")\n    rate_limiter.speed_multiplier = settings.speed_multiplier\n    g = Github(settings.github_token.get_secret_value())\n    repo = g.get_repo(settings.github_repository)\n\n    discussion_nodes = get_discussion_nodes(settings=settings)\n    experts_results = get_discussions_experts(discussion_nodes=discussion_nodes)\n\n    authors = experts_results.authors\n    maintainers_logins = {\"tiangolo\"}\n    maintainers = []\n    for login in maintainers_logins:\n        user = authors[login]\n        maintainers.append(\n            {\n                \"login\": login,\n                \"answers\": experts_results.commenters[login],\n                \"avatarUrl\": user.avatarUrl,\n                \"url\": user.url,\n            }\n        )\n\n    experts = get_users_to_write(\n        counter=experts_results.commenters,\n        authors=authors,\n    )\n    last_month_experts = get_users_to_write(\n        counter=experts_results.last_month_commenters,\n        authors=authors,\n    )\n    three_months_experts = get_users_to_write(\n        counter=experts_results.three_months_commenters,\n        authors=authors,\n    )\n    six_months_experts = get_users_to_write(\n        counter=experts_results.six_months_commenters,\n        authors=authors,\n    )\n    one_year_experts = get_users_to_write(\n        counter=experts_results.one_year_commenters,\n        authors=authors,\n    )\n\n    people = {\n        \"maintainers\": maintainers,\n        \"experts\": experts,\n        \"last_month_experts\": last_month_experts,\n        \"three_months_experts\": three_months_experts,\n        \"six_months_experts\": six_months_experts,\n        \"one_year_experts\": one_year_experts,\n    }\n\n    # For local development\n    # people_path = Path(\"../docs/en/data/people.yml\")\n    people_path = Path(\"./docs/en/data/people.yml\")\n\n    updated = update_content(content_path=people_path, new_content=people)\n\n    if not updated:\n        logging.info(\"The data hasn't changed, finishing.\")\n        return\n\n    logging.info(\"Setting up GitHub Actions git user\")\n    subprocess.run([\"git\", \"config\", \"user.name\", \"github-actions[bot]\"], check=True)\n    subprocess.run(\n        [\"git\", \"config\", \"user.email\", \"github-actions[bot]@users.noreply.github.com\"],\n        check=True,\n    )\n    branch_name = f\"fastapi-people-experts-{secrets.token_hex(4)}\"\n    logging.info(f\"Creating a new branch {branch_name}\")\n    subprocess.run([\"git\", \"checkout\", \"-b\", branch_name], check=True)\n    logging.info(\"Adding updated file\")\n    subprocess.run([\"git\", \"add\", str(people_path)], check=True)\n    logging.info(\"Committing updated file\")\n    message = \"👥 Update FastAPI People - Experts\"\n    subprocess.run([\"git\", \"commit\", \"-m\", message], check=True)\n    logging.info(\"Pushing branch\")\n    subprocess.run([\"git\", \"push\", \"origin\", branch_name], check=True)\n    logging.info(\"Creating PR\")\n    pr = repo.create_pull(title=message, body=message, base=\"master\", head=branch_name)\n    logging.info(f\"Created PR: {pr.number}\")\n    logging.info(\"Finished\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/playwright/cookie_param_models/image01.py",
    "content": "import subprocess\nimport time\n\nimport httpx\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    browser = playwright.chromium.launch(headless=False)\n    context = browser.new_context()\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_role(\"link\", name=\"/items/\").click()\n    # Manually add the screenshot\n    page.screenshot(path=\"docs/en/docs/img/tutorial/cookie-param-models/image01.png\")\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"fastapi\", \"run\", \"docs_src/cookie_param_models/tutorial001.py\"]\n)\ntry:\n    for _ in range(3):\n        try:\n            response = httpx.get(\"http://localhost:8000/docs\")\n        except httpx.ConnectError:\n            time.sleep(1)\n            break\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/header_param_models/image01.py",
    "content": "import subprocess\nimport time\n\nimport httpx\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_role(\"button\", name=\"GET /items/ Read Items\").click()\n    page.get_by_role(\"button\", name=\"Try it out\").click()\n    # Manually add the screenshot\n    page.screenshot(path=\"docs/en/docs/img/tutorial/header-param-models/image01.png\")\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"fastapi\", \"run\", \"docs_src/header_param_models/tutorial001.py\"]\n)\ntry:\n    for _ in range(3):\n        try:\n            response = httpx.get(\"http://localhost:8000/docs\")\n        except httpx.ConnectError:\n            time.sleep(1)\n            break\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/json_base64_bytes/image01.py",
    "content": "import subprocess\nimport time\n\nimport httpx\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_role(\"button\", name=\"POST /data Post Data\").click()\n    # Manually add the screenshot\n    page.screenshot(path=\"docs/en/docs/img/tutorial/json-base64-bytes/image01.png\")\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"fastapi\", \"run\", \"docs_src/json_base64_bytes/tutorial001_py310.py\"]\n)\ntry:\n    for _ in range(3):\n        try:\n            response = httpx.get(\"http://localhost:8000/docs\")\n        except httpx.ConnectError:\n            time.sleep(1)\n            break\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/query_param_models/image01.py",
    "content": "import subprocess\nimport time\n\nimport httpx\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    browser = playwright.chromium.launch(headless=False)\n    context = browser.new_context()\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_role(\"button\", name=\"GET /items/ Read Items\").click()\n    page.get_by_role(\"button\", name=\"Try it out\").click()\n    page.get_by_role(\"heading\", name=\"Servers\").click()\n    # Manually add the screenshot\n    page.screenshot(path=\"docs/en/docs/img/tutorial/query-param-models/image01.png\")\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"fastapi\", \"run\", \"docs_src/query_param_models/tutorial001.py\"]\n)\ntry:\n    for _ in range(3):\n        try:\n            response = httpx.get(\"http://localhost:8000/docs\")\n        except httpx.ConnectError:\n            time.sleep(1)\n            break\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/request_form_models/image01.py",
    "content": "import subprocess\nimport time\n\nimport httpx\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_role(\"button\", name=\"POST /login/ Login\").click()\n    page.get_by_role(\"button\", name=\"Try it out\").click()\n    # Manually add the screenshot\n    page.screenshot(path=\"docs/en/docs/img/tutorial/request-form-models/image01.png\")\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"fastapi\", \"run\", \"docs_src/request_form_models/tutorial001.py\"]\n)\ntry:\n    for _ in range(3):\n        try:\n            response = httpx.get(\"http://localhost:8000/docs\")\n        except httpx.ConnectError:\n            time.sleep(1)\n            break\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/separate_openapi_schemas/image01.py",
    "content": "import subprocess\n\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_text(\"POST/items/Create Item\").click()\n    page.get_by_role(\"tab\", name=\"Schema\").first.click()\n    # Manually add the screenshot\n    page.screenshot(\n        path=\"docs/en/docs/img/tutorial/separate-openapi-schemas/image01.png\"\n    )\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"uvicorn\", \"docs_src.separate_openapi_schemas.tutorial001:app\"]\n)\ntry:\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/separate_openapi_schemas/image02.py",
    "content": "import subprocess\n\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_text(\"GET/items/Read Items\").click()\n    page.get_by_role(\"button\", name=\"Try it out\").click()\n    page.get_by_role(\"button\", name=\"Execute\").click()\n    # Manually add the screenshot\n    page.screenshot(\n        path=\"docs/en/docs/img/tutorial/separate-openapi-schemas/image02.png\"\n    )\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"uvicorn\", \"docs_src.separate_openapi_schemas.tutorial001:app\"]\n)\ntry:\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/separate_openapi_schemas/image03.py",
    "content": "import subprocess\n\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_text(\"GET/items/Read Items\").click()\n    page.get_by_role(\"tab\", name=\"Schema\").click()\n    page.get_by_label(\"Schema\").get_by_role(\"button\", name=\"Expand all\").click()\n    # Manually add the screenshot\n    page.screenshot(\n        path=\"docs/en/docs/img/tutorial/separate-openapi-schemas/image03.png\"\n    )\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"uvicorn\", \"docs_src.separate_openapi_schemas.tutorial001:app\"]\n)\ntry:\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/separate_openapi_schemas/image04.py",
    "content": "import subprocess\n\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_role(\"button\", name=\"Item-Input\").click()\n    page.get_by_role(\"button\", name=\"Item-Output\").click()\n    page.set_viewport_size({\"width\": 960, \"height\": 820})\n    # Manually add the screenshot\n    page.screenshot(\n        path=\"docs/en/docs/img/tutorial/separate-openapi-schemas/image04.png\"\n    )\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"uvicorn\", \"docs_src.separate_openapi_schemas.tutorial001:app\"]\n)\ntry:\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/separate_openapi_schemas/image05.py",
    "content": "import subprocess\n\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_role(\"button\", name=\"Item\", exact=True).click()\n    page.set_viewport_size({\"width\": 960, \"height\": 700})\n    # Manually add the screenshot\n    page.screenshot(\n        path=\"docs/en/docs/img/tutorial/separate-openapi-schemas/image05.png\"\n    )\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"uvicorn\", \"docs_src.separate_openapi_schemas.tutorial002:app\"]\n)\ntry:\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/sql_databases/image01.py",
    "content": "import subprocess\nimport time\n\nimport httpx\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_label(\"post /heroes/\").click()\n    # Manually add the screenshot\n    page.screenshot(path=\"docs/en/docs/img/tutorial/sql-databases/image01.png\")\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"fastapi\", \"run\", \"docs_src/sql_databases/tutorial001.py\"],\n)\ntry:\n    for _ in range(3):\n        try:\n            response = httpx.get(\"http://localhost:8000/docs\")\n        except httpx.ConnectError:\n            time.sleep(1)\n            break\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/playwright/sql_databases/image02.py",
    "content": "import subprocess\nimport time\n\nimport httpx\nfrom playwright.sync_api import Playwright, sync_playwright\n\n\n# Run playwright codegen to generate the code below, copy paste the sections in run()\ndef run(playwright: Playwright) -> None:\n    browser = playwright.chromium.launch(headless=False)\n    # Update the viewport manually\n    context = browser.new_context(viewport={\"width\": 960, \"height\": 1080})\n    page = context.new_page()\n    page.goto(\"http://localhost:8000/docs\")\n    page.get_by_label(\"post /heroes/\").click()\n    # Manually add the screenshot\n    page.screenshot(path=\"docs/en/docs/img/tutorial/sql-databases/image02.png\")\n\n    # ---------------------\n    context.close()\n    browser.close()\n\n\nprocess = subprocess.Popen(\n    [\"fastapi\", \"run\", \"docs_src/sql_databases/tutorial002.py\"],\n)\ntry:\n    for _ in range(3):\n        try:\n            response = httpx.get(\"http://localhost:8000/docs\")\n        except httpx.ConnectError:\n            time.sleep(1)\n            break\n    with sync_playwright() as playwright:\n        run(playwright)\nfinally:\n    process.terminate()\n"
  },
  {
    "path": "scripts/sponsors.py",
    "content": "import logging\nimport secrets\nimport subprocess\nfrom collections import defaultdict\nfrom pathlib import Path\nfrom typing import Any\n\nimport httpx\nimport yaml\nfrom github import Github\nfrom pydantic import BaseModel, SecretStr\nfrom pydantic_settings import BaseSettings\n\ngithub_graphql_url = \"https://api.github.com/graphql\"\n\n\nsponsors_query = \"\"\"\nquery Q($after: String) {\n  user(login: \"tiangolo\") {\n    sponsorshipsAsMaintainer(first: 100, after: $after) {\n      edges {\n        cursor\n        node {\n          sponsorEntity {\n            ... on Organization {\n              login\n              avatarUrl\n              url\n            }\n            ... on User {\n              login\n              avatarUrl\n              url\n            }\n          }\n          tier {\n            name\n            monthlyPriceInDollars\n          }\n        }\n      }\n    }\n  }\n}\n\"\"\"\n\n\nclass SponsorEntity(BaseModel):\n    login: str\n    avatarUrl: str\n    url: str\n\n\nclass Tier(BaseModel):\n    name: str\n    monthlyPriceInDollars: float\n\n\nclass SponsorshipAsMaintainerNode(BaseModel):\n    sponsorEntity: SponsorEntity\n    tier: Tier\n\n\nclass SponsorshipAsMaintainerEdge(BaseModel):\n    cursor: str\n    node: SponsorshipAsMaintainerNode\n\n\nclass SponsorshipAsMaintainer(BaseModel):\n    edges: list[SponsorshipAsMaintainerEdge]\n\n\nclass SponsorsUser(BaseModel):\n    sponsorshipsAsMaintainer: SponsorshipAsMaintainer\n\n\nclass SponsorsResponseData(BaseModel):\n    user: SponsorsUser\n\n\nclass SponsorsResponse(BaseModel):\n    data: SponsorsResponseData\n\n\nclass Settings(BaseSettings):\n    sponsors_token: SecretStr\n    pr_token: SecretStr\n    github_repository: str\n    httpx_timeout: int = 30\n\n\ndef get_graphql_response(\n    *,\n    settings: Settings,\n    query: str,\n    after: str | None = None,\n) -> dict[str, Any]:\n    headers = {\"Authorization\": f\"token {settings.sponsors_token.get_secret_value()}\"}\n    variables = {\"after\": after}\n    response = httpx.post(\n        github_graphql_url,\n        headers=headers,\n        timeout=settings.httpx_timeout,\n        json={\"query\": query, \"variables\": variables, \"operationName\": \"Q\"},\n    )\n    if response.status_code != 200:\n        logging.error(f\"Response was not 200, after: {after}\")\n        logging.error(response.text)\n        raise RuntimeError(response.text)\n    data = response.json()\n    if \"errors\" in data:\n        logging.error(f\"Errors in response, after: {after}\")\n        logging.error(data[\"errors\"])\n        logging.error(response.text)\n        raise RuntimeError(response.text)\n    return data\n\n\ndef get_graphql_sponsor_edges(\n    *, settings: Settings, after: str | None = None\n) -> list[SponsorshipAsMaintainerEdge]:\n    data = get_graphql_response(settings=settings, query=sponsors_query, after=after)\n    graphql_response = SponsorsResponse.model_validate(data)\n    return graphql_response.data.user.sponsorshipsAsMaintainer.edges\n\n\ndef get_individual_sponsors(\n    settings: Settings,\n) -> defaultdict[float, dict[str, SponsorEntity]]:\n    nodes: list[SponsorshipAsMaintainerNode] = []\n    edges = get_graphql_sponsor_edges(settings=settings)\n\n    while edges:\n        for edge in edges:\n            nodes.append(edge.node)\n        last_edge = edges[-1]\n        edges = get_graphql_sponsor_edges(settings=settings, after=last_edge.cursor)\n\n    tiers: defaultdict[float, dict[str, SponsorEntity]] = defaultdict(dict)\n    for node in nodes:\n        tiers[node.tier.monthlyPriceInDollars][node.sponsorEntity.login] = (\n            node.sponsorEntity\n        )\n    return tiers\n\n\ndef update_content(*, content_path: Path, new_content: Any) -> bool:\n    old_content = content_path.read_text(encoding=\"utf-8\")\n\n    new_content = yaml.dump(new_content, sort_keys=False, width=200, allow_unicode=True)\n    if old_content == new_content:\n        logging.info(f\"The content hasn't changed for {content_path}\")\n        return False\n    content_path.write_text(new_content, encoding=\"utf-8\")\n    logging.info(f\"Updated {content_path}\")\n    return True\n\n\ndef main() -> None:\n    logging.basicConfig(level=logging.INFO)\n    settings = Settings()\n    logging.info(f\"Using config: {settings.model_dump_json()}\")\n    g = Github(settings.pr_token.get_secret_value())\n    repo = g.get_repo(settings.github_repository)\n\n    tiers = get_individual_sponsors(settings=settings)\n    keys = list(tiers.keys())\n    keys.sort(reverse=True)\n    sponsors = []\n    for key in keys:\n        sponsor_group = []\n        for login, sponsor in tiers[key].items():\n            sponsor_group.append(\n                {\"login\": login, \"avatarUrl\": sponsor.avatarUrl, \"url\": sponsor.url}\n            )\n        sponsors.append(sponsor_group)\n    github_sponsors = {\n        \"sponsors\": sponsors,\n    }\n\n    # For local development\n    # github_sponsors_path = Path(\"../docs/en/data/github_sponsors.yml\")\n    github_sponsors_path = Path(\"./docs/en/data/github_sponsors.yml\")\n    updated = update_content(\n        content_path=github_sponsors_path, new_content=github_sponsors\n    )\n\n    if not updated:\n        logging.info(\"The data hasn't changed, finishing.\")\n        return\n\n    logging.info(\"Setting up GitHub Actions git user\")\n    subprocess.run([\"git\", \"config\", \"user.name\", \"github-actions[bot]\"], check=True)\n    subprocess.run(\n        [\"git\", \"config\", \"user.email\", \"github-actions[bot]@users.noreply.github.com\"],\n        check=True,\n    )\n    branch_name = f\"fastapi-people-sponsors-{secrets.token_hex(4)}\"\n    logging.info(f\"Creating a new branch {branch_name}\")\n    subprocess.run([\"git\", \"checkout\", \"-b\", branch_name], check=True)\n    logging.info(\"Adding updated file\")\n    subprocess.run(\n        [\n            \"git\",\n            \"add\",\n            str(github_sponsors_path),\n        ],\n        check=True,\n    )\n    logging.info(\"Committing updated file\")\n    message = \"👥 Update FastAPI People - Sponsors\"\n    subprocess.run([\"git\", \"commit\", \"-m\", message], check=True)\n    logging.info(\"Pushing branch\")\n    subprocess.run([\"git\", \"push\", \"origin\", branch_name], check=True)\n    logging.info(\"Creating PR\")\n    pr = repo.create_pull(title=message, body=message, base=\"master\", head=branch_name)\n    logging.info(f\"Created PR: {pr.number}\")\n    logging.info(\"Finished\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/test-cov-html.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\nset -x\n\nbash scripts/test-cov.sh --cov-report=term-missing --cov-report=html ${@}\n"
  },
  {
    "path": "scripts/test-cov.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\nset -x\n\nbash scripts/test.sh --cov --cov-context=test ${@}\n"
  },
  {
    "path": "scripts/test.sh",
    "content": "#!/usr/bin/env bash\n\nset -e\nset -x\n\nexport PYTHONPATH=./docs_src\npytest -n auto --dist loadgroup  tests scripts/tests/ ${@}\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/conftest.py",
    "content": "import shutil\nimport sys\nfrom pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nskip_on_windows = pytest.mark.skipif(\n    sys.platform == \"win32\", reason=\"Skipping on Windows\"\n)\n\n\nTHIS_DIR = Path(__file__).parent.resolve()\n\n\ndef pytest_collection_modifyitems(config, items: list[pytest.Item]) -> None:\n    if sys.platform != \"win32\":\n        return\n\n    for item in items:\n        item_path = Path(item.fspath).resolve()\n        if item_path.is_relative_to(THIS_DIR):\n            item.add_marker(skip_on_windows)\n\n\n@pytest.fixture(name=\"runner\")\ndef get_runner():\n    runner = CliRunner()\n    with runner.isolated_filesystem():\n        yield runner\n\n\n@pytest.fixture(name=\"root_dir\")\ndef prepare_paths(runner):\n    docs_dir = Path(\"docs\")\n    en_docs_dir = docs_dir / \"en\" / \"docs\"\n    lang_docs_dir = docs_dir / \"lang\" / \"docs\"\n    en_docs_dir.mkdir(parents=True, exist_ok=True)\n    lang_docs_dir.mkdir(parents=True, exist_ok=True)\n    yield Path.cwd()\n\n\n@pytest.fixture\ndef copy_test_files(root_dir: Path, request: pytest.FixtureRequest):\n    en_file_path = Path(request.param[0])\n    translation_file_path = Path(request.param[1])\n    shutil.copy(str(en_file_path), str(root_dir / \"docs\" / \"en\" / \"docs\" / \"doc.md\"))\n    shutil.copy(\n        str(translation_file_path), str(root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\")\n    )\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/data/en_doc.md",
    "content": "# Code blocks { #code-blocks }\n\nSome text\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    # Comment with indentation\n    print(\"Hello, world!\")  # Print greeting\n```\n\nSome more text\n\n```toml\n# This is a sample TOML code block\ntitle = \"TOML Example\"  # Title of the document\n```\n\nAnd more text\n\n```console\n// Use the command \"live\" and pass the language code as a CLI argument\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\nAnd even more text\n\n```json\n{\n    // This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" // Greeting\n}\n```\n\nMermaid diagram\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/data/translated_doc_lines_number_gt.md",
    "content": "# Code blocks { #code-blocks }\n\nSome text\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    # Comment with indentation\n    print(\"Hello, world!\")  # Print greeting\n```\n\nSome more text\n\n```toml\n# Extra line\n# This is a sample TOML code block\ntitle = \"TOML Example\"  # Title of the document\n```\n\nAnd more text\n\n```console\n// Use the command \"live\" and pass the language code as a CLI argument\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\nAnd even more text\n\n```json\n{\n    // This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" // Greeting\n}\n```\n\nДиаграма Mermaid\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/data/translated_doc_lines_number_lt.md",
    "content": "# Code blocks { #code-blocks }\n\nSome text\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    # Comment with indentation\n    print(\"Hello, world!\")  # Print greeting\n```\n\nSome more text\n\nThe following block is missing first line:\n\n```toml\ntitle = \"TOML Example\"  # Title of the document\n```\n\nAnd more text\n\n```console\n// Use the command \"live\" and pass the language code as a CLI argument\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\nAnd even more text\n\n```json\n{\n    // This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" // Greeting\n}\n```\n\nДиаграма Mermaid\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/data/translated_doc_mermaid_not_translated.md",
    "content": "# Code blocks { #code-blocks }\n\nSome text\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    # Comment with indentation\n    print(\"Hello, world!\")  # Print greeting\n```\n\nSome more text\n\n```toml\n# This is a sample TOML code block\ntitle = \"TOML Example\"  # Title of the document\n```\n\nAnd more text\n\n```console\n// Use the command \"live\" and pass the language code as a CLI argument\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\nAnd even more text\n\n```json\n{\n    // This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" // Greeting\n}\n```\n\nДиаграма Mermaid\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/data/translated_doc_mermaid_translated.md",
    "content": "# Code blocks { #code-blocks }\n\nSome text\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    # Comment with indentation\n    print(\"Hello, world!\")  # Print greeting\n```\n\nSome more text\n\n```toml\n# This is a sample TOML code block\ntitle = \"TOML Example\"  # Title of the document\n```\n\nAnd more text\n\n```console\n// Use the command \"live\" and pass the language code as a CLI argument\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\nAnd even more text\n\n```json\n{\n    // This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" // Greeting\n}\n```\n\nДиаграма Mermaid\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|требует| harry-1[harry v1]\n```\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/data/translated_doc_number_gt.md",
    "content": "# Code blocks { #code-blocks }\n\nSome text\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    # Comment with indentation\n    print(\"Hello, world!\")  # Print greeting\n```\n\nSome more text\n\n```toml\n# This is a sample TOML code block\ntitle = \"TOML Example\"  # Title of the document\n```\n\nExtra code block\n\n```\n$ cd my_project\n```\n\nAnd more text\n\n```console\n// Use the command \"live\" and pass the language code as a CLI argument\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\nAnd even more text\n\n```json\n{\n    // This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" // Greeting\n}\n```\n\nДиаграма Mermaid\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/data/translated_doc_number_lt.md",
    "content": "# Code blocks { #code-blocks }\n\nSome text\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    # Comment with indentation\n    print(\"Hello, world!\")  # Print greeting\n```\n\nSome more text\n\nMissing code block...\n\nAnd more text\n\n```console\n// Use the command \"live\" and pass the language code as a CLI argument\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\nAnd even more text\n\n```json\n{\n    // This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" // Greeting\n}\n```\n\nДиаграма Mermaid\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/data/translated_doc_wrong_lang_code.md",
    "content": "# Code blocks { #code-blocks }\n\nSome text\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    # Comment with indentation\n    print(\"Hello, world!\")  # Print greeting\n```\n\nSome more text\n\nThe following block has wrong language code (should be TOML):\n\n```yaml\n# This is a sample TOML code block\ntitle = \"TOML Example\"  # Title of the document\n```\n\nAnd more text\n\n```console\n// Use the command \"live\" and pass the language code as a CLI argument\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\nAnd even more text\n\n```json\n{\n    // This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" // Greeting\n}\n```\n\nДиаграма Mermaid\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/data/translated_doc_wrong_lang_code_2.md",
    "content": "# Code blocks { #code-blocks }\n\nSome text\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    # Comment with indentation\n    print(\"Hello, world!\")  # Print greeting\n```\n\nSome more text\n\nThe following block has wrong language code (should be TOML):\n\n```\n# This is a sample TOML code block\ntitle = \"TOML Example\"  # Title of the document\n```\n\nAnd more text\n\n```console\n// Use the command \"live\" and pass the language code as a CLI argument\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\nAnd even more text\n\n```json\n{\n    // This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" // Greeting\n}\n```\n\nДиаграма Mermaid\n\n```mermaid\nflowchart LR\n    stone(philosophers-stone) -->|requires| harry-1[harry v1]\n```\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/test_code_blocks_lines_number_mismatch.py",
    "content": "from pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nfrom scripts.translation_fixer import cli\n\ndata_path = Path(\n    \"scripts/tests/test_translation_fixer/test_code_blocks/data\"\n).absolute()\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_lines_number_gt.md\")],\n    indirect=True,\n)\ndef test_gt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_lines_number_gt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Code block (lines 14-18) has different number of lines than the original block (5 vs 4)\"\n    ) in result.output\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_lines_number_lt.md\")],\n    indirect=True,\n)\ndef test_lt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    # assert result.exit_code == 1, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_lines_number_lt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Code block (lines 16-18) has different number of lines than the original block (3 vs 4)\"\n    ) in result.output\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/test_code_blocks_mermaid.py",
    "content": "from pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nfrom scripts.translation_fixer import cli\n\ndata_path = Path(\n    \"scripts/tests/test_translation_fixer/test_code_blocks/data\"\n).absolute()\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_mermaid_translated.md\")],\n    indirect=True,\n)\ndef test_translated(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 0, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(\n        f\"{data_path}/translated_doc_mermaid_translated.md\"\n    ).read_text(\"utf-8\")\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert (\n        \"Skipping mermaid code block replacement (lines 41-44). This should be checked manually.\"\n    ) in result.output\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [\n        (\n            f\"{data_path}/en_doc.md\",\n            f\"{data_path}/translated_doc_mermaid_not_translated.md\",\n        )\n    ],\n    indirect=True,\n)\ndef test_not_translated(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 0, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(\n        f\"{data_path}/translated_doc_mermaid_not_translated.md\"\n    ).read_text(\"utf-8\")\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert (\"Skipping mermaid code block replacement\") not in result.output\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/test_code_blocks_number_mismatch.py",
    "content": "from pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nfrom scripts.translation_fixer import cli\n\ndata_path = Path(\n    \"scripts/tests/test_translation_fixer/test_code_blocks/data\"\n).absolute()\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_number_gt.md\")],\n    indirect=True,\n)\ndef test_gt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_number_gt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Number of code blocks does not match the number \"\n        \"in the original document (6 vs 5)\"\n    ) in result.output\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_number_lt.md\")],\n    indirect=True,\n)\ndef test_lt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    # assert result.exit_code == 1, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_number_lt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Number of code blocks does not match the number \"\n        \"in the original document (4 vs 5)\"\n    ) in result.output\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_blocks/test_code_blocks_wrong_lang_code.py",
    "content": "from pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nfrom scripts.translation_fixer import cli\n\ndata_path = Path(\n    \"scripts/tests/test_translation_fixer/test_code_blocks/data\"\n).absolute()\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_wrong_lang_code.md\")],\n    indirect=True,\n)\ndef test_wrong_lang_code_1(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_wrong_lang_code.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Code block (lines 16-19) has different language than the original block ('yaml' vs 'toml')\"\n    ) in result.output\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_wrong_lang_code_2.md\")],\n    indirect=True,\n)\ndef test_wrong_lang_code_2(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(\n        f\"{data_path}/translated_doc_wrong_lang_code_2.md\"\n    ).read_text(\"utf-8\")\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Code block (lines 16-19) has different language than the original block ('' vs 'toml')\"\n    ) in result.output\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_includes/data/en_doc.md",
    "content": "# Header\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\nSome text\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nSome more text\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nAnd even more text\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_includes/data/translated_doc_number_gt.md",
    "content": "# Header\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\nSome text\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nSome more text\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\nAnd even more text\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_includes/data/translated_doc_number_lt.md",
    "content": "# Header\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\nSome text\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\nSome more text\n\n...\n\nAnd even more text\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_code_includes/test_number_mismatch.py",
    "content": "from pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nfrom scripts.translation_fixer import cli\n\ndata_path = Path(\n    \"scripts/tests/test_translation_fixer/test_code_includes/data\"\n).absolute()\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_number_gt.md\")],\n    indirect=True,\n)\ndef test_gt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_number_gt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Number of code include placeholders does not match the number of code includes \"\n        \"in the original document (4 vs 3)\"\n    ) in result.output\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_number_lt.md\")],\n    indirect=True,\n)\ndef test_lt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_number_lt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Number of code include placeholders does not match the number of code includes \"\n        \"in the original document (2 vs 3)\"\n    ) in result.output\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_complex_doc/data/en_doc.md",
    "content": "# Test translation fixer tool { #test-translation-fixer }\n\n## Code blocks with and without comments { #code-blocks-with-and-without-comments }\n\nThis is a test page for the translation fixer tool.\n\n### Code blocks with comments { #code-blocks-with-comments }\n\nThe following code blocks include comments in different styles.\nFixer tool should fix content, but preserve comments correctly.\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    # Comment with indentation\n    print(\"Hello, world!\")  # Print greeting\n```\n\n```toml\n# This is a sample TOML code block\ntitle = \"TOML Example\"  # Title of the document\n```\n\n```console\n// Use the command \"live\" and pass the language code as a CLI argument\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\n```json\n{\n    // This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" // Greeting\n}\n```\n\n\n### Code blocks with comments where language uses different comment styles { #code-blocks-with-different-comment-styles }\n\nThe following code blocks include comments in different styles based on the language.\nFixer tool will not preserve comments in these blocks.\n\n```json\n{\n    # This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" # Print greeting\n}\n```\n\n```console\n# This is a sample console code block\n$ echo \"Hello, world!\"  # Print greeting\n```\n\n```toml\n// This is a sample TOML code block\ntitle = \"TOML Example\"  // Title of the document\n```\n\n\n### Code blocks with comments with unsupported languages or without language specified { #code-blocks-with-unsupported-languages }\n\nThe following code blocks use unsupported languages for comment preservation.\nFixer tool will not preserve comments in these blocks.\n\n```javascript\n// This is a sample JavaScript code block\nconsole.log(\"Hello, world!\"); // Print greeting\n```\n\n```\n# This is a sample console code block\n$ echo \"Hello, world!\"  # Print greeting\n```\n\n```\n// This is a sample console code block\n$ echo \"Hello, world!\"  // Print greeting\n```\n\n\n### Code blocks with comments that don't follow pattern { #code-blocks-with-comments-without-pattern }\n\nFixer tool expects comments that follow specific pattern:\n\n- For hash-style comments: comment starts with `# ` (hash following by whitespace) in the beginning of the string or after a whitespace.\n- For slash-style comments: comment starts with `// ` (two slashes following by whitespace) in the beginning of the string or after a whitespace.\n\nIf comment doesn't follow this pattern, fixer tool will not preserve it.\n\n```python\n#Function declaration\ndef hello_world():# Print greeting\n    print(\"Hello, world!\")  #Print greeting without space after hash\n```\n\n```console\n//Function declaration\ndef hello_world():// Print greeting\n    print(\"Hello, world!\")  //Print greeting without space after slashes\n```\n\n## Code blocks with quadruple backticks { #code-blocks-with-quadruple-backticks }\n\nThe following code block uses quadruple backticks.\n\n````python\n# Hello world function\ndef hello_world():\n    print(\"Hello, world!\")  # Print greeting\n````\n\n### Backticks number mismatch is fixable { #backticks-number-mismatch-is-fixable }\n\nThe following code block has triple backticks in the original document, but quadruple backticks in the translated document.\nIt will be fixed by the fixer tool (will convert to triple backticks).\n\n```Python\n# Some Python code\n```\n\n### Triple backticks inside quadruple backticks { #triple-backticks-inside-quadruple-backticks }\n\nComments inside nested code block will NOT be preserved.\n\n````\nHere is a code block with quadruple backticks that contains triple backticks inside:\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    print(\"Hello, world!\")  # Print greeting\n```\n\n````\n\n# Code includes { #code-includes }\n\n## Simple code includes { #simple-code-includes }\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\n{* ../../docs_src/python_types/tutorial002_py310.py *}\n\n\n## Code includes with highlighting { #code-includes-with-highlighting }\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[10] *}\n\n\n## Code includes with line ranges { #code-includes-with-line-ranges }\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] *}\n\n\n## Code includes with line ranges and highlighting { #code-includes-with-line-ranges-and-highlighting }\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\n{* ../../docs_src/dependencies/tutorial015_an_py310.py ln[10:15] hl[12:14] *}\n\n\n## Code includes qith title { #code-includes-with-title }\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\n## Code includes with unknown attributes { #code-includes-with-unknown-attributes }\n\n{* ../../docs_src/python_types/tutorial001_py310.py unknown[123] *}\n\n## Some more code includes to test fixing { #some-more-code-includes-to-test-fixing }\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\n\n\n# Links { #links }\n\n## Markdown-style links { #markdown-style-links }\n\nThis is a [Markdown link](https://example.com) to an external site.\n\nThis is a link with attributes: [**FastAPI** Project Generators](project-generation.md){.internal-link target=_blank}\n\nThis is a link to the main FastAPI site: [FastAPI](https://fastapi.tiangolo.com) - tool should add language code to the URL.\n\nThis is a link to one of the pages on FastAPI site: [How to](https://fastapi.tiangolo.com/how-to/) - tool should add language code to the URL.\n\nLink to test wrong attribute: [**FastAPI** Project Generators](project-generation.md){.internal-link} - tool should fix the attribute.\n\nLink with a title: [Example](https://example.com \"Example site\") - URL will be fixed, title preserved.\n\n### Markdown link to static assets { #markdown-link-to-static-assets }\n\nThese are links to static assets:\n\n* [FastAPI Logo](https://fastapi.tiangolo.com/img/fastapi-logo.png)\n* [FastAPI CSS](https://fastapi.tiangolo.com/css/fastapi.css)\n* [FastAPI JS](https://fastapi.tiangolo.com/js/fastapi.js)\n\nTool should NOT add language code to their URLs.\n\n## HTML-style links { #html-style-links }\n\nThis is an <a href=\"https://example.com\" target=\"_blank\" class=\"external-link\">HTML link</a> to an external site.\n\nThis is an <a href=\"https://fastapi.tiangolo.com\">link to the main FastAPI site</a> - tool should add language code to the URL.\n\nThis is an <a href=\"https://fastapi.tiangolo.com/how-to/\">link to one of the pages on FastAPI site</a> - tool should add language code to the URL.\n\nLink to test wrong attribute: <a href=\"project-generation.md\" class=\"internal-link\">**FastAPI** Project Generators</a> - tool should fix the attribute.\n\n### HTML links to static assets { #html-links-to-static-assets }\n\nThese are links to static assets:\n\n* <a href=\"https://fastapi.tiangolo.com/img/fastapi-logo.png\">FastAPI Logo</a>\n* <a href=\"https://fastapi.tiangolo.com/css/fastapi.css\">FastAPI CSS</a>\n* <a href=\"https://fastapi.tiangolo.com/js/fastapi.js\">FastAPI JS</a>\n\nTool should NOT add language code to their URLs.\n\n# Header (with HTML link to <a href=\"https://tiangolo.com\">tiangolo.com</a>) { #header-with-html-link-to-tiangolo-com }\n\n#Not a header\n\n```Python\n# Also not a header\n```\n\nSome text\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_complex_doc/data/translated_doc.md",
    "content": "# Тестовый инструмент исправления переводов { #test-translation-fixer }\n\n## Блоки кода с комментариями и без комментариев { #code-blocks-with-and-without-comments }\n\nЭто тестовая страница для инструмента исправления переводов.\n\n### Блоки кода с комментариями { #code-blocks-with-comments }\n\nСледующие блоки кода содержат комментарии в разных стилях.\nИнструмент исправления должен исправлять содержимое, но корректно сохранять комментарии.\n\n```python\n# Это пример блока кода на Python\ndef hello_world():\n    # Комментарий с отступом\n    print(\"Hello, world!\")  # Печать приветствия\n```\n\n```toml\n# Это пример блока кода на TOML\ntitle = \"TOML Example\"  # Заголовок документа\n```\n\n```console\n// Используйте команду \"live\" и передайте код языка в качестве аргумента CLI\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\n```json\n{\n    // Это пример блока кода на JSON\n    \"greeting\": \"Hello, world!\" // Печать приветствия\n}\n```\n\n\n### Блоки кода с комментариями, где язык использует другие стили комментариев { #code-blocks-with-different-comment-styles }\n\nСледующие блоки кода содержат комментарии в разных стилях в зависимости от языка.\nИнструмент исправления не будет сохранять комментарии в этих блоках.\n\n```json\n{\n    # Это пример блока кода на JSON\n    \"greeting\": \"Hello, world!\" # Печать приветствия\n}\n```\n\n```console\n# Это пример блока кода консоли\n$ echo \"Hello, world!\"  # Печать приветствия\n```\n\n```toml\n// Это пример блока кода на TOML\ntitle = \"TOML Example\"  // Заголовок документа\n```\n\n### Блоки кода с комментариями на неподдерживаемых языках или без указания языка { #code-blocks-with-unsupported-languages }\n\nСледующие блоки кода используют неподдерживаемые языки для сохранения комментариев.\nИнструмент исправления не будет сохранять комментарии в этих блоках.\n\n```javascript\n// Это пример блока кода на JavaScript\nconsole.log(\"Hello, world!\"); // Печать приветствия\n```\n\n```\n# Это пример блока кода консоли\n$ echo \"Hello, world!\"  # Печать приветствия\n```\n\n```\n// Это пример блока кода консоли\n$ echo \"Hello, world!\"  // Печать приветствия\n```\n\n### Блоки кода с комментариями, которые не соответствуют шаблону { #code-blocks-with-comments-without-pattern }\n\nИнструмент исправления ожидает комментарии, которые соответствуют определённому шаблону:\n\n- Для комментариев в стиле с решёткой: комментарий начинается с `# ` (решётка, затем пробел) в начале строки или после пробела.\n- Для комментариев в стиле со слешами: комментарий начинается с `// ` (два слеша, затем пробел) в начале строки или после пробела.\n\nЕсли комментарий не соответствует этому шаблону, инструмент исправления не будет его сохранять.\n\n```python\n#Объявление функции\ndef hello_world():# Печать приветствия\n    print(\"Hello, world!\")  #Печать приветствия без пробела после решётки\n```\n\n```console\n//Объявление функции\ndef hello_world():// Печать приветствия\n    print(\"Hello, world!\")  //Печать приветствия без пробела после слешей\n```\n\n## Блок кода с четырёхкратными обратными кавычками { #code-blocks-with-quadruple-backticks }\n\nСледующий блок кода содержит четырёхкратные обратные кавычки.\n\n````python\n# Функция приветствия\ndef hello_world():\n    print(\"Hello, world\")  # Печать приветствия\n````\n\n### Несоответствие обратных кавычек фиксится { #backticks-number-mismatch-is-fixable }\n\nСледующий блок кода имеет тройные обратные кавычки в оригинальном документе, но четырёхкратные обратные кавычки в переведённом документе.\nЭто будет исправлено инструментом исправления (будет преобразовано в тройные обратные кавычки).\n\n````Python\n# Немного кода на Python\n````\n\n### Блок кода в тройных обратных кавычка внутри блока кода в четырёхкратных обратных кавычках { #triple-backticks-inside-quadruple-backticks }\n\nКомментарии внутри вложенного блока кода в тройных обратных кавычках НЕ БУДУТ сохранены.\n\n````\nHere is a code block with quadruple backticks that contains triple backticks inside:\n\n```python\n# Этот комментарий НЕ будет сохранён\ndef hello_world():\n    print(\"Hello, world\")  # Как и этот комментарий\n```\n\n````\n\n# Включения кода { #code-includes }\n\n## Простые включения кода { #simple-code-includes }\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\n{* ../../docs_src/python_types/tutorial002_py310.py *}\n\n\n## Включения кода с подсветкой { #code-includes-with-highlighting }\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[10] *}\n\n\n## Включения кода с диапазонами строк { #code-includes-with-line-ranges }\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] *}\n\n\n## Включения кода с диапазонами строк и подсветкой { #code-includes-with-line-ranges-and-highlighting }\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\n{* ../../docs_src/dependencies/tutorial015_an_py310.py ln[10:15] hl[12:14] *}\n\n\n## Включения кода с заголовком { #code-includes-with-title }\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\n## Включения кода с неизвестными атрибутами { #code-includes-with-unknown-attributes }\n\n{* ../../docs_src/python_types/tutorial001_py310.py unknown[123] *}\n\n## Ещё включения кода для тестирования исправления { #some-more-code-includes-to-test-fixing }\n\n{*    ../../docs_src/dependencies/tutorial013_an_py310.py     ln[19 : 21]    *}\n\n{* ../../docs_src/bigger_applications/app_an_py310/wrong.py hl[3] title[\"app/internal/admin.py\"] *}\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[1:30] hl[1:10] *}\n\n# Ссылки { #links }\n\n## Ссылки в стиле Markdown { #markdown-style-links }\n\nЭто [Markdown-ссылка](https://example.com) на внешний сайт.\n\nЭто ссылка с атрибутами: [**FastAPI** генераторы проектов](project-generation.md){.internal-link target=_blank}\n\nЭто ссылка на основной сайт FastAPI: [FastAPI](https://fastapi.tiangolo.com) — инструмент должен добавить код языка в URL.\n\nЭто ссылка на одну из страниц на сайте FastAPI: [How to](https://fastapi.tiangolo.com/how-to) — инструмент должен добавить код языка в URL.\n\nСсылка для тестирования неправильного атрибута: [**FastAPI** генераторы проектов](project-generation.md){.external-link} - инструмент должен исправить атрибут.\n\nСсылка с заголовком: [Пример](http://example.com/ \"Сайт для примера\") - URL будет исправлен инструментом, заголовок сохранится.\n\n### Markdown ссылки на статические ресурсы { #markdown-link-to-static-assets }\n\nЭто ссылки на статические ресурсы:\n\n* [FastAPI Logo](https://fastapi.tiangolo.com/img/fastapi-logo.png)\n* [FastAPI CSS](https://fastapi.tiangolo.com/css/fastapi.css)\n* [FastAPI JS](https://fastapi.tiangolo.com/js/fastapi.js)\n\nИнструмент НЕ должен добавлять код языка в их URL.\n\n## Ссылки в стиле HTML { #html-style-links }\n\nЭто <a href=\"https://example.com\" target=\"_blank\" class=\"external-link\">HTML-ссылка</a> на внешний сайт.\n\nЭто <a href=\"https://fastapi.tiangolo.com\">ссылка на основной сайт FastAPI</a> — инструмент должен добавить код языка в URL.\n\nЭто <a href=\"https://fastapi.tiangolo.com/how-to/\">ссылка на одну из страниц на сайте FastAPI</a> — инструмент должен добавить код языка в URL.\n\nСсылка для тестирования неправильного атрибута: <a href=\"project-generation.md\" class=\"external-link\">**FastAPI** генераторы проектов</a> - инструмент должен исправить атрибут.\n\n### HTML ссылки на статические ресурсы { #html-links-to-static-assets }\n\nЭто ссылки на статические ресурсы:\n\n* <a href=\"https://fastapi.tiangolo.com/img/fastapi-logo.png\">FastAPI Logo</a>\n* <a href=\"https://fastapi.tiangolo.com/css/fastapi.css\">FastAPI CSS</a>\n* <a href=\"https://fastapi.tiangolo.com/js/fastapi.js\">FastAPI JS</a>\n\nИнструмент НЕ должен добавлять код языка в их URL.\n\n# Заголовок (с HTML ссылкой на <a href=\"https://tiangolo.com\">tiangolo.com</a>) { #header-5 }\n\n#Не заголовок\n\n```Python\n# Также не заголовок\n```\n\nНемного текста\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_complex_doc/data/translated_doc_expected.md",
    "content": "# Тестовый инструмент исправления переводов { #test-translation-fixer }\n\n## Блоки кода с комментариями и без комментариев { #code-blocks-with-and-without-comments }\n\nЭто тестовая страница для инструмента исправления переводов.\n\n### Блоки кода с комментариями { #code-blocks-with-comments }\n\nСледующие блоки кода содержат комментарии в разных стилях.\nИнструмент исправления должен исправлять содержимое, но корректно сохранять комментарии.\n\n```python\n# Это пример блока кода на Python\ndef hello_world():\n    # Комментарий с отступом\n    print(\"Hello, world!\")  # Печать приветствия\n```\n\n```toml\n# Это пример блока кода на TOML\ntitle = \"TOML Example\"  # Заголовок документа\n```\n\n```console\n// Используйте команду \"live\" и передайте код языка в качестве аргумента CLI\n$ python ./scripts/docs.py live es\n\n<span style=\"color: green;\">[INFO]</span> Serving on http://127.0.0.1:8008\n<span style=\"color: green;\">[INFO]</span> Start watching changes\n<span style=\"color: green;\">[INFO]</span> Start detecting changes\n```\n\n```json\n{\n    // Это пример блока кода на JSON\n    \"greeting\": \"Hello, world!\" // Печать приветствия\n}\n```\n\n\n### Блоки кода с комментариями, где язык использует другие стили комментариев { #code-blocks-with-different-comment-styles }\n\nСледующие блоки кода содержат комментарии в разных стилях в зависимости от языка.\nИнструмент исправления не будет сохранять комментарии в этих блоках.\n\n```json\n{\n    # This is a sample JSON code block\n    \"greeting\": \"Hello, world!\" # Print greeting\n}\n```\n\n```console\n# This is a sample console code block\n$ echo \"Hello, world!\"  # Print greeting\n```\n\n```toml\n// This is a sample TOML code block\ntitle = \"TOML Example\"  // Title of the document\n```\n\n### Блоки кода с комментариями на неподдерживаемых языках или без указания языка { #code-blocks-with-unsupported-languages }\n\nСледующие блоки кода используют неподдерживаемые языки для сохранения комментариев.\nИнструмент исправления не будет сохранять комментарии в этих блоках.\n\n```javascript\n// This is a sample JavaScript code block\nconsole.log(\"Hello, world!\"); // Print greeting\n```\n\n```\n# This is a sample console code block\n$ echo \"Hello, world!\"  # Print greeting\n```\n\n```\n// This is a sample console code block\n$ echo \"Hello, world!\"  // Print greeting\n```\n\n### Блоки кода с комментариями, которые не соответствуют шаблону { #code-blocks-with-comments-without-pattern }\n\nИнструмент исправления ожидает комментарии, которые соответствуют определённому шаблону:\n\n- Для комментариев в стиле с решёткой: комментарий начинается с `# ` (решётка, затем пробел) в начале строки или после пробела.\n- Для комментариев в стиле со слешами: комментарий начинается с `// ` (два слеша, затем пробел) в начале строки или после пробела.\n\nЕсли комментарий не соответствует этому шаблону, инструмент исправления не будет его сохранять.\n\n```python\n#Function declaration\ndef hello_world():# Print greeting\n    print(\"Hello, world!\")  #Print greeting without space after hash\n```\n\n```console\n//Function declaration\ndef hello_world():// Print greeting\n    print(\"Hello, world!\")  //Print greeting without space after slashes\n```\n\n## Блок кода с четырёхкратными обратными кавычками { #code-blocks-with-quadruple-backticks }\n\nСледующий блок кода содержит четырёхкратные обратные кавычки.\n\n````python\n# Функция приветствия\ndef hello_world():\n    print(\"Hello, world!\")  # Печать приветствия\n````\n\n### Несоответствие обратных кавычек фиксится { #backticks-number-mismatch-is-fixable }\n\nСледующий блок кода имеет тройные обратные кавычки в оригинальном документе, но четырёхкратные обратные кавычки в переведённом документе.\nЭто будет исправлено инструментом исправления (будет преобразовано в тройные обратные кавычки).\n\n```Python\n# Немного кода на Python\n```\n\n### Блок кода в тройных обратных кавычка внутри блока кода в четырёхкратных обратных кавычках { #triple-backticks-inside-quadruple-backticks }\n\nКомментарии внутри вложенного блока кода в тройных обратных кавычках НЕ БУДУТ сохранены.\n\n````\nHere is a code block with quadruple backticks that contains triple backticks inside:\n\n```python\n# This is a sample Python code block\ndef hello_world():\n    print(\"Hello, world!\")  # Print greeting\n```\n\n````\n\n# Включения кода { #code-includes }\n\n## Простые включения кода { #simple-code-includes }\n\n{* ../../docs_src/python_types/tutorial001_py310.py *}\n\n{* ../../docs_src/python_types/tutorial002_py310.py *}\n\n\n## Включения кода с подсветкой { #code-includes-with-highlighting }\n\n{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *}\n\n{* ../../docs_src/python_types/tutorial006_py310.py hl[10] *}\n\n\n## Включения кода с диапазонами строк { #code-includes-with-line-ranges }\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] *}\n\n\n## Включения кода с диапазонами строк и подсветкой { #code-includes-with-line-ranges-and-highlighting }\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\n{* ../../docs_src/dependencies/tutorial015_an_py310.py ln[10:15] hl[12:14] *}\n\n\n## Включения кода с заголовком { #code-includes-with-title }\n\n{* ../../docs_src/bigger_applications/app_an_py310/routers/users.py hl[1,3] title[\"app/routers/users.py\"] *}\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\n## Включения кода с неизвестными атрибутами { #code-includes-with-unknown-attributes }\n\n{* ../../docs_src/python_types/tutorial001_py310.py unknown[123] *}\n\n## Ещё включения кода для тестирования исправления { #some-more-code-includes-to-test-fixing }\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[19:21] *}\n\n{* ../../docs_src/bigger_applications/app_an_py310/internal/admin.py hl[3] title[\"app/internal/admin.py\"] *}\n\n{* ../../docs_src/dependencies/tutorial013_an_py310.py ln[30:38] hl[31:33] *}\n\n# Ссылки { #links }\n\n## Ссылки в стиле Markdown { #markdown-style-links }\n\nЭто [Markdown-ссылка](https://example.com) на внешний сайт.\n\nЭто ссылка с атрибутами: [**FastAPI** генераторы проектов](project-generation.md){.internal-link target=_blank}\n\nЭто ссылка на основной сайт FastAPI: [FastAPI](https://fastapi.tiangolo.com/lang) — инструмент должен добавить код языка в URL.\n\nЭто ссылка на одну из страниц на сайте FastAPI: [How to](https://fastapi.tiangolo.com/lang/how-to/) — инструмент должен добавить код языка в URL.\n\nСсылка для тестирования неправильного атрибута: [**FastAPI** генераторы проектов](project-generation.md){.internal-link} - инструмент должен исправить атрибут.\n\nСсылка с заголовком: [Пример](https://example.com \"Сайт для примера\") - URL будет исправлен инструментом, заголовок сохранится.\n\n### Markdown ссылки на статические ресурсы { #markdown-link-to-static-assets }\n\nЭто ссылки на статические ресурсы:\n\n* [FastAPI Logo](https://fastapi.tiangolo.com/img/fastapi-logo.png)\n* [FastAPI CSS](https://fastapi.tiangolo.com/css/fastapi.css)\n* [FastAPI JS](https://fastapi.tiangolo.com/js/fastapi.js)\n\nИнструмент НЕ должен добавлять код языка в их URL.\n\n## Ссылки в стиле HTML { #html-style-links }\n\nЭто <a href=\"https://example.com\" target=\"_blank\" class=\"external-link\">HTML-ссылка</a> на внешний сайт.\n\nЭто <a href=\"https://fastapi.tiangolo.com/lang\">ссылка на основной сайт FastAPI</a> — инструмент должен добавить код языка в URL.\n\nЭто <a href=\"https://fastapi.tiangolo.com/lang/how-to/\">ссылка на одну из страниц на сайте FastAPI</a> — инструмент должен добавить код языка в URL.\n\nСсылка для тестирования неправильного атрибута: <a href=\"project-generation.md\" class=\"internal-link\">**FastAPI** генераторы проектов</a> - инструмент должен исправить атрибут.\n\n### HTML ссылки на статические ресурсы { #html-links-to-static-assets }\n\nЭто ссылки на статические ресурсы:\n\n* <a href=\"https://fastapi.tiangolo.com/img/fastapi-logo.png\">FastAPI Logo</a>\n* <a href=\"https://fastapi.tiangolo.com/css/fastapi.css\">FastAPI CSS</a>\n* <a href=\"https://fastapi.tiangolo.com/js/fastapi.js\">FastAPI JS</a>\n\nИнструмент НЕ должен добавлять код языка в их URL.\n\n# Заголовок (с HTML ссылкой на <a href=\"https://tiangolo.com\">tiangolo.com</a>) { #header-with-html-link-to-tiangolo-com }\n\n#Не заголовок\n\n```Python\n# Также не заголовок\n```\n\nНемного текста\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_complex_doc/test_compex_doc.py",
    "content": "from pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nfrom scripts.translation_fixer import cli\n\ndata_path = Path(\n    \"scripts/tests/test_translation_fixer/test_complex_doc/data\"\n).absolute()\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc.md\")],\n    indirect=True,\n)\ndef test_fix(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 0, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = (data_path / \"translated_doc_expected.md\").read_text(\"utf-8\")\n    assert fixed_content == expected_content\n\n    assert \"Fixing multiline code blocks in\" in result.output\n    assert \"Fixing markdown links in\" in result.output\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_header_permalinks/data/en_doc.md",
    "content": "# Header 1 { #header-1 }\n\nSome text\n\n## Header 2 { #header-2 }\n\nSome more text\n\n### Header 3 { #header-3 }\n\nEven more text\n\n# Header 4 { #header-4 }\n\nA bit more text\n\n#Not a header\n\nFinal portion of text\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_header_permalinks/data/translated_doc_level_mismatch_1.md",
    "content": "# Header 1 { #header-1 }\n\nSome text\n\n# Header 2 { #header-2 }\n\nSome more text\n\n### Header 3 { #header-3 }\n\nEven more text\n\n# Header 4 { #header-4 }\n\nA bit more text\n\n#Not a header\n\nFinal portion of text\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_header_permalinks/data/translated_doc_level_mismatch_2.md",
    "content": "# Header 1 { #header-1 }\n\nSome text\n\n## Header 2 { #header-2 }\n\nSome more text\n\n### Header 3 { #header-3 }\n\nEven more text\n\n## Header 4 { #header-4 }\n\nA bit more text\n\n#Not a header\n\nFinal portion of text\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_header_permalinks/data/translated_doc_number_gt.md",
    "content": "# Header 1 { #header-1 }\n\nSome text\n\n## Header 2 { #header-2 }\n\nSome more text\n\n### Header 3 { #header-3 }\n\nEven more text\n\n# Header 4 { #header-4 }\n\nA bit more text\n\n# Extra header\n\nFinal portion of text\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_header_permalinks/data/translated_doc_number_lt.md",
    "content": "# Header 1 { #header-1 }\n\nSome text\n\n## Header 2 { #header-2 }\n\nSome more text\n\n### Header 3 { #header-3 }\n\nEven more text\n\nHeader 4 is missing\n\nA bit more text\n\n#Not a header\n\nFinal portion of text\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_header_permalinks/test_header_level_mismatch.py",
    "content": "from pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nfrom scripts.translation_fixer import cli\n\ndata_path = Path(\n    \"scripts/tests/test_translation_fixer/test_header_permalinks/data\"\n).absolute()\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_level_mismatch_1.md\")],\n    indirect=True,\n)\ndef test_level_mismatch_1(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(\n        f\"{data_path}/translated_doc_level_mismatch_1.md\"\n    ).read_text(\"utf-8\")\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Header levels do not match between document and original document\"\n        \" (found #, expected ##) for header №2 in line 5\"\n    ) in result.output\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_level_mismatch_2.md\")],\n    indirect=True,\n)\ndef test_level_mismatch_2(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(\n        f\"{data_path}/translated_doc_level_mismatch_2.md\"\n    ).read_text(\"utf-8\")\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Header levels do not match between document and original document\"\n        \" (found ##, expected #) for header №4 in line 13\"\n    ) in result.output\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_header_permalinks/test_header_number_mismatch.py",
    "content": "from pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nfrom scripts.translation_fixer import cli\n\ndata_path = Path(\n    \"scripts/tests/test_translation_fixer/test_header_permalinks/data\"\n).absolute()\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_number_gt.md\")],\n    indirect=True,\n)\ndef test_gt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_number_gt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Number of headers with permalinks does not match the number \"\n        \"in the original document (5 vs 4)\"\n    ) in result.output\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_number_lt.md\")],\n    indirect=True,\n)\ndef test_lt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_number_lt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Number of headers with permalinks does not match the number \"\n        \"in the original document (3 vs 4)\"\n    ) in result.output\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_html_links/data/en_doc.md",
    "content": "# Header 1 { #header-1 }\n\nSome text with a link to <a href=\"https://fastapi.tiangolo.com\">FastAPI</a>.\n\n## Header 2 { #header-2 }\n\nTwo links here: <a href=\"https://fastapi.tiangolo.com/how-to/\">How to</a> and <a href=\"project-generation.md\" class=\"internal-link\" target=\"_blank\">Project Generators</a>.\n\n### Header 3 { #header-3 }\n\nAnother link: <a href=\"project-generation.md\" class=\"internal-link\" target=\"_blank\" title=\"Link title\">**FastAPI** Project Generators</a> with title.\n\n# Header 4 { #header-4 }\n\nLink to anchor: <a href=\"#header-2\">Header 2</a>\n\n# Header with <a href=\"http://example.com\">link</a> { #header-with-link }\n\nSome text\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_html_links/data/translated_doc_number_gt.md",
    "content": "# Заголовок 1 { #header-1 }\n\nНемного текста со ссылкой на <a href=\"https://fastapi.tiangolo.com\">FastAPI</a>.\n\n## Заголовок 2 { #header-2 }\n\nДве ссылки здесь: <a href=\"https://fastapi.tiangolo.com/how-to/\">How to</a> и <a href=\"project-generation.md\" class=\"internal-link\" target=\"_blank\">Project Generators</a>.\n\n### Заголовок 3 { #header-3 }\n\nЕщё ссылка: <a href=\"project-generation.md\" class=\"internal-link\" target=\"_blank\" title=\"Тайтл\">**FastAPI** Генераторы Проектов</a> с тайтлом.\n\nИ ещё одна <a href=\"https://github.com\">экстра ссылка</a>.\n\n# Заголовок 4 { #header-4 }\n\nСсылка на якорь: <a href=\"#header-2\">Заголовок 2</a>\n\n# Заголовок со <a href=\"http://example.com\">ссылкой</a> { #header-with-link }\n\nНемного текста\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_html_links/data/translated_doc_number_lt.md",
    "content": "# Заголовок 1 { #header-1 }\n\nНемного текста со ссылкой на <a href=\"https://fastapi.tiangolo.com\">FastAPI</a>.\n\n## Заголовок 2 { #header-2 }\n\nДве ссылки здесь: <a href=\"https://fastapi.tiangolo.com/how-to/\">How to</a> и <a href=\"project-generation.md\" class=\"internal-link\" target=\"_blank\">Project Generators</a>.\n\n### Заголовок 3 { #header-3 }\n\nЕщё ссылка: <a href=\"project-generation.md\" class=\"internal-link\" target=\"_blank\" title=\"Тайтл\">**FastAPI** Генераторы Проектов</a> с тайтлом.\n\n# Заголовок 4 { #header-4 }\n\nСсылка на якорь: <a href=\"#header-2\">Заголовок 2</a>\n\n# Заголовок с потерянной ссылкой { #header-with-link }\n\nНемного текста\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_html_links/test_html_links_number_mismatch.py",
    "content": "from pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nfrom scripts.translation_fixer import cli\n\ndata_path = Path(\"scripts/tests/test_translation_fixer/test_html_links/data\").absolute()\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_number_gt.md\")],\n    indirect=True,\n)\ndef test_gt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_number_gt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Number of HTML links does not match the number \"\n        \"in the original document (7 vs 6)\"\n    ) in result.output\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_number_lt.md\")],\n    indirect=True,\n)\ndef test_lt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    # assert result.exit_code == 1, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_number_lt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Number of HTML links does not match the number \"\n        \"in the original document (5 vs 6)\"\n    ) in result.output\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_markdown_links/data/en_doc.md",
    "content": "# Header 1 { #header-1 }\n\nSome text with a link to [FastAPI](https://fastapi.tiangolo.com).\n\n## Header 2 { #header-2 }\n\nTwo links here: [How to](https://fastapi.tiangolo.com/how-to/) and [Project Generators](project-generation.md){.internal-link target=_blank}.\n\n### Header 3 { #header-3 }\n\nAnother link: [**FastAPI** Project Generators](project-generation.md \"Link title\"){.internal-link target=_blank} with title.\n\n# Header 4 { #header-4 }\n\nLink to anchor: [Header 2](#header-2)\n\n# Header with [link](http://example.com) { #header-with-link }\n\nSome text\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_markdown_links/data/translated_doc.md",
    "content": "# Заголовок 1 { #header-1 }\n\nНемного текста со ссылкой на [FastAPI](https://fastapi.tiangolo.com).\n\n## Заголовок 2 { #header-2 }\n\nДве ссылки здесь: [How to](https://fastapi.tiangolo.com/how-to/) и [Project Generators](project-generation.md){.internal-link target=_blank}.\n\n### Заголовок 3 { #header-3 }\n\nЕщё ссылка: [**FastAPI** Генераторы Проектов](project-generation.md \"Тайтл\"){.internal-link target=_blank} с тайтлом.\n\n# Заголовок 4 { #header-4 }\n\nСсылка на якорь: [Заголовок 2](#header-2)\n\n# Заголовок со [ссылкой](http://example.com) { #header-with-link }\n\nНемного текста\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_markdown_links/data/translated_doc_number_gt.md",
    "content": "# Заголовок 1 { #header-1 }\n\nНемного текста со ссылкой на [FastAPI](https://fastapi.tiangolo.com).\n\n## Заголовок 2 { #header-2 }\n\nДве ссылки здесь: [How to](https://fastapi.tiangolo.com/how-to/) и [Project Generators](project-generation.md){.internal-link target=_blank}.\n\n### Заголовок 3 { #header-3 }\n\nЕщё ссылка: [**FastAPI** Генераторы Проектов](project-generation.md \"Тайтл\"){.internal-link target=_blank} с тайтлом.\n\nИ ещё одна [экстра ссылка](https://github.com).\n\n# Заголовок 4 { #header-4 }\n\nСсылка на якорь: [Заголовок 2](#header-2)\n\n# Заголовок со [ссылкой](http://example.com) { #header-with-link }\n\nНемного текста\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_markdown_links/data/translated_doc_number_lt.md",
    "content": "# Заголовок 1 { #header-1 }\n\nНемного текста со ссылкой на [FastAPI](https://fastapi.tiangolo.com).\n\n## Заголовок 2 { #header-2 }\n\nДве ссылки здесь: [How to](https://fastapi.tiangolo.com/how-to/) и [Project Generators](project-generation.md){.internal-link target=_blank}.\n\n### Заголовок 3 { #header-3 }\n\nЕщё ссылка: [**FastAPI** Генераторы Проектов](project-generation.md \"Тайтл\"){.internal-link target=_blank} с тайтлом.\n\n# Заголовок 4 { #header-4 }\n\nСсылка на якорь: [Заголовок 2](#header-2)\n\n# Заголовок с потерянной ссылкой { #header-with-link }\n\nНемного текста\n"
  },
  {
    "path": "scripts/tests/test_translation_fixer/test_markdown_links/test_mkd_links_number_mismatch.py",
    "content": "from pathlib import Path\n\nimport pytest\nfrom typer.testing import CliRunner\n\nfrom scripts.translation_fixer import cli\n\ndata_path = Path(\n    \"scripts/tests/test_translation_fixer/test_markdown_links/data\"\n).absolute()\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_number_gt.md\")],\n    indirect=True,\n)\ndef test_gt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    assert result.exit_code == 1, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_number_gt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Number of markdown links does not match the number \"\n        \"in the original document (7 vs 6)\"\n    ) in result.output\n\n\n@pytest.mark.parametrize(\n    \"copy_test_files\",\n    [(f\"{data_path}/en_doc.md\", f\"{data_path}/translated_doc_number_lt.md\")],\n    indirect=True,\n)\ndef test_lt(runner: CliRunner, root_dir: Path, copy_test_files):\n    result = runner.invoke(\n        cli,\n        [\"fix-pages\", \"docs/lang/docs/doc.md\"],\n    )\n    # assert result.exit_code == 1, result.output\n\n    fixed_content = (root_dir / \"docs\" / \"lang\" / \"docs\" / \"doc.md\").read_text(\"utf-8\")\n    expected_content = Path(f\"{data_path}/translated_doc_number_lt.md\").read_text(\n        \"utf-8\"\n    )\n\n    assert fixed_content == expected_content  # Translated doc remains unchanged\n    assert \"Error processing docs/lang/docs/doc.md\" in result.output\n    assert (\n        \"Number of markdown links does not match the number \"\n        \"in the original document (5 vs 6)\"\n    ) in result.output\n"
  },
  {
    "path": "scripts/topic_repos.py",
    "content": "import logging\nimport secrets\nimport subprocess\nfrom pathlib import Path\n\nimport yaml\nfrom github import Github\nfrom pydantic import BaseModel, SecretStr\nfrom pydantic_settings import BaseSettings\n\n\nclass Settings(BaseSettings):\n    github_repository: str\n    github_token: SecretStr\n\n\nclass Repo(BaseModel):\n    name: str\n    html_url: str\n    stars: int\n    owner_login: str\n    owner_html_url: str\n\n\ndef main() -> None:\n    logging.basicConfig(level=logging.INFO)\n    settings = Settings()\n\n    logging.info(f\"Using config: {settings.model_dump_json()}\")\n    g = Github(settings.github_token.get_secret_value(), per_page=100)\n    r = g.get_repo(settings.github_repository)\n    repos = g.search_repositories(query=\"topic:fastapi\")\n    repos_list = list(repos)\n    final_repos: list[Repo] = []\n    for repo in repos_list[:100]:\n        if repo.full_name == settings.github_repository:\n            continue\n        final_repos.append(\n            Repo(\n                name=repo.name,\n                html_url=repo.html_url,\n                stars=repo.stargazers_count,\n                owner_login=repo.owner.login,\n                owner_html_url=repo.owner.html_url,\n            )\n        )\n    data = [repo.model_dump() for repo in final_repos]\n\n    # Local development\n    # repos_path = Path(\"../docs/en/data/topic_repos.yml\")\n    repos_path = Path(\"./docs/en/data/topic_repos.yml\")\n    repos_old_content = repos_path.read_text(encoding=\"utf-8\")\n    new_repos_content = yaml.dump(data, sort_keys=False, width=200, allow_unicode=True)\n    if repos_old_content == new_repos_content:\n        logging.info(\"The data hasn't changed. Finishing.\")\n        return\n    repos_path.write_text(new_repos_content, encoding=\"utf-8\")\n    logging.info(\"Setting up GitHub Actions git user\")\n    subprocess.run([\"git\", \"config\", \"user.name\", \"github-actions[bot]\"], check=True)\n    subprocess.run(\n        [\"git\", \"config\", \"user.email\", \"github-actions[bot]@users.noreply.github.com\"],\n        check=True,\n    )\n    branch_name = f\"fastapi-topic-repos-{secrets.token_hex(4)}\"\n    logging.info(f\"Creating a new branch {branch_name}\")\n    subprocess.run([\"git\", \"checkout\", \"-b\", branch_name], check=True)\n    logging.info(\"Adding updated file\")\n    subprocess.run([\"git\", \"add\", str(repos_path)], check=True)\n    logging.info(\"Committing updated file\")\n    message = \"👥 Update FastAPI GitHub topic repositories\"\n    subprocess.run([\"git\", \"commit\", \"-m\", message], check=True)\n    logging.info(\"Pushing branch\")\n    subprocess.run([\"git\", \"push\", \"origin\", branch_name], check=True)\n    logging.info(\"Creating PR\")\n    pr = r.create_pull(title=message, body=message, base=\"master\", head=branch_name)\n    logging.info(f\"Created PR: {pr.number}\")\n    logging.info(\"Finished\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/translate.py",
    "content": "import json\nimport secrets\nimport subprocess\nfrom collections.abc import Iterable\nfrom functools import lru_cache\nfrom os import sep as pathsep\nfrom pathlib import Path\nfrom typing import Annotated\n\nimport git\nimport typer\nimport yaml\nfrom doc_parsing_utils import check_translation\nfrom github import Github\nfrom pydantic_ai import Agent\nfrom rich import print\n\nnon_translated_sections = (\n    f\"reference{pathsep}\",\n    \"release-notes.md\",\n    \"fastapi-people.md\",\n    \"external-links.md\",\n    \"newsletter.md\",\n    \"management-tasks.md\",\n    \"management.md\",\n    \"contributing.md\",\n)\n\ngeneral_prompt_path = Path(__file__).absolute().parent / \"general-llm-prompt.md\"\ngeneral_prompt = general_prompt_path.read_text(encoding=\"utf-8\")\n\napp = typer.Typer()\n\n\n@lru_cache\ndef get_langs() -> dict[str, str]:\n    return yaml.safe_load(Path(\"docs/language_names.yml\").read_text(encoding=\"utf-8\"))\n\n\ndef generate_lang_path(*, lang: str, path: Path) -> Path:\n    en_docs_path = Path(\"docs/en/docs\")\n    assert str(path).startswith(str(en_docs_path)), (\n        f\"Path must be inside {en_docs_path}\"\n    )\n    lang_docs_path = Path(f\"docs/{lang}/docs\")\n    out_path = Path(str(path).replace(str(en_docs_path), str(lang_docs_path)))\n    return out_path\n\n\ndef generate_en_path(*, lang: str, path: Path) -> Path:\n    en_docs_path = Path(\"docs/en/docs\")\n    assert not str(path).startswith(str(en_docs_path)), (\n        f\"Path must not be inside {en_docs_path}\"\n    )\n    lang_docs_path = Path(f\"docs/{lang}/docs\")\n    out_path = Path(str(path).replace(str(lang_docs_path), str(en_docs_path)))\n    return out_path\n\n\ndef get_prompt(\n    lang_prompt_content: str,\n    old_translation: str | None,\n    language: str,\n    language_name: str,\n    original_content: str,\n    additional_instructions: str,\n) -> str:\n    general_prompt_with_additional_instructions = general_prompt.replace(\n        \"[placeholder_for_additional_instructions]\", additional_instructions\n    )\n    prompt_segments = [\n        general_prompt_with_additional_instructions,\n        lang_prompt_content,\n    ]\n    if old_translation:\n        prompt_segments.extend(\n            [\n                \"There is an existing previous translation for the original English content, that may be outdated.\",\n                \"Update the translation only where necessary:\",\n                \"- If the original English content has added parts, also add these parts to the translation.\",\n                \"- If the original English content has removed parts, also remove them from the translation, unless you were instructed earlier to not do that in specific cases.\",\n                \"- If parts of the original English content have changed, also change those parts in the translation.\",\n                \"- If the previous translation violates current instructions, update it.\",\n                \"- Otherwise, preserve the original translation LINE-BY-LINE, AS-IS.\",\n                \"Do not:\",\n                \"- rephrase or rewrite correct lines just to improve the style.\",\n                \"- add or remove line breaks, unless the original English content changed.\",\n                \"- change formatting or whitespace unless absolutely required.\",\n                \"Only change what must be changed. The goal is to minimize diffs for easier human review.\",\n                \"UNLESS you were instructed earlier to behave different, there MUST NOT be whole sentences or partial sentences in the updated translation, which are not in the original English content, and there MUST NOT be whole sentences or partial sentences in the original English content, which are not in the updated translation. Remember: the updated translation shall be IN SYNC with the original English content.\",\n                \"Previous translation:\",\n                f\"%%%\\n{old_translation}%%%\",\n            ]\n        )\n    prompt_segments.extend(\n        [\n            f\"Translate to {language} ({language_name}).\",\n            \"Original content:\",\n            f\"%%%\\n{original_content}%%%\",\n        ]\n    )\n    return \"\\n\\n\".join(prompt_segments)\n\n\n@app.command()\ndef translate_page(\n    *,\n    language: Annotated[str, typer.Option(envvar=\"LANGUAGE\")],\n    en_path: Annotated[Path, typer.Option(envvar=\"EN_PATH\")],\n) -> None:\n    assert language != \"en\", (\n        \"`en` is the source language, choose another language as translation target\"\n    )\n    langs = get_langs()\n    language_name = langs[language]\n    lang_path = Path(f\"docs/{language}\")\n    lang_path.mkdir(exist_ok=True)\n    lang_prompt_path = lang_path / \"llm-prompt.md\"\n    assert lang_prompt_path.exists(), f\"Prompt file not found: {lang_prompt_path}\"\n    lang_prompt_content = lang_prompt_path.read_text(encoding=\"utf-8\")\n\n    en_docs_path = Path(\"docs/en/docs\")\n    assert str(en_path).startswith(str(en_docs_path)), (\n        f\"Path must be inside {en_docs_path}\"\n    )\n    out_path = generate_lang_path(lang=language, path=en_path)\n    out_path.parent.mkdir(parents=True, exist_ok=True)\n    original_content = en_path.read_text(encoding=\"utf-8\")\n    old_translation: str | None = None\n    if out_path.exists():\n        print(f\"Found existing translation: {out_path}\")\n        old_translation = out_path.read_text(encoding=\"utf-8\")\n    print(f\"Translating {en_path} to {language} ({language_name})\")\n    agent = Agent(\"openai:gpt-5\")\n\n    MAX_ATTEMPTS = 3\n    additional_instructions = \"\"\n    for attempt_no in range(1, MAX_ATTEMPTS + 1):\n        print(f\"Running agent for {out_path} (attempt {attempt_no}/{MAX_ATTEMPTS})\")\n        prompt = get_prompt(\n            lang_prompt_content=lang_prompt_content,\n            old_translation=old_translation,\n            language=language,\n            language_name=language_name,\n            original_content=original_content,\n            additional_instructions=additional_instructions,\n        )\n        result = agent.run_sync(\n            prompt.replace(\n                \"[placeholder_for_additional_instructions]\", additional_instructions\n            )\n        )\n        out_content = f\"{result.output.strip()}\\n\"\n        try:\n            check_translation(\n                doc_lines=out_content.splitlines(),\n                en_doc_lines=original_content.splitlines(),\n                lang_code=language,\n                auto_fix=False,\n                path=str(out_path),\n            )\n            break  # Exit loop if no errors\n        except ValueError as e:\n            print(\n                f\"Translation check failed on attempt {attempt_no}/{MAX_ATTEMPTS}: {e}\"\n            )\n            additional_instructions = (\n                f\"Current translation fails validation checks ({str(e)}). \"\n                \"Please, pay special attention to it.\"\n            )\n            old_translation = out_content\n            continue  # Retry if not reached max attempts\n    else:  # Max retry attempts reached\n        print(f\"Translation failed for {out_path} after {MAX_ATTEMPTS} attempts\")\n\n    print(f\"Saving translation to {out_path}\")\n    out_path.write_text(out_content, encoding=\"utf-8\", newline=\"\\n\")\n\n\ndef iter_all_en_paths() -> Iterable[Path]:\n    \"\"\"\n    Iterate on the markdown files to translate in order of priority.\n    \"\"\"\n    first_dirs = [\n        Path(\"docs/en/docs/learn\"),\n        Path(\"docs/en/docs/tutorial\"),\n        Path(\"docs/en/docs/advanced\"),\n        Path(\"docs/en/docs/about\"),\n        Path(\"docs/en/docs/how-to\"),\n    ]\n    first_parent = Path(\"docs/en/docs\")\n    yield from first_parent.glob(\"*.md\")\n    for dir_path in first_dirs:\n        yield from dir_path.rglob(\"*.md\")\n    first_dirs_str = tuple(str(d) for d in first_dirs)\n    for path in Path(\"docs/en/docs\").rglob(\"*.md\"):\n        if str(path).startswith(first_dirs_str):\n            continue\n        if path.parent == first_parent:\n            continue\n        yield path\n\n\ndef iter_en_paths_to_translate() -> Iterable[Path]:\n    en_docs_root = Path(\"docs/en/docs/\")\n    for path in iter_all_en_paths():\n        relpath = path.relative_to(en_docs_root)\n        if not str(relpath).startswith(non_translated_sections):\n            yield path\n\n\n@app.command()\ndef translate_lang(language: Annotated[str, typer.Option(envvar=\"LANGUAGE\")]) -> None:\n    paths_to_process = list(iter_en_paths_to_translate())\n    print(\"Original paths:\")\n    for p in paths_to_process:\n        print(f\"  - {p}\")\n    print(f\"Total original paths: {len(paths_to_process)}\")\n    missing_paths: list[Path] = []\n    skipped_paths: list[Path] = []\n    for p in paths_to_process:\n        lang_path = generate_lang_path(lang=language, path=p)\n        if lang_path.exists():\n            skipped_paths.append(p)\n            continue\n        missing_paths.append(p)\n    print(\"Paths to skip:\")\n    for p in skipped_paths:\n        print(f\"  - {p}\")\n    print(f\"Total paths to skip: {len(skipped_paths)}\")\n    print(\"Paths to process:\")\n    for p in missing_paths:\n        print(f\"  - {p}\")\n    print(f\"Total paths to process: {len(missing_paths)}\")\n    for p in missing_paths:\n        print(f\"Translating: {p}\")\n        translate_page(language=\"es\", en_path=p)\n        print(f\"Done translating: {p}\")\n\n\ndef get_llm_translatable() -> list[str]:\n    translatable_langs = []\n    langs = get_langs()\n    for lang in langs:\n        if lang == \"en\":\n            continue\n        lang_prompt_path = Path(f\"docs/{lang}/llm-prompt.md\")\n        if lang_prompt_path.exists():\n            translatable_langs.append(lang)\n    return translatable_langs\n\n\n@app.command()\ndef list_llm_translatable() -> list[str]:\n    translatable_langs = get_llm_translatable()\n    print(\"LLM translatable languages:\", translatable_langs)\n    return translatable_langs\n\n\n@app.command()\ndef llm_translatable_json(\n    language: Annotated[str | None, typer.Option(envvar=\"LANGUAGE\")] = None,\n) -> None:\n    translatable_langs = get_llm_translatable()\n    if language:\n        if language in translatable_langs:\n            print(json.dumps([language]))\n            return\n        else:\n            raise typer.Exit(code=1)\n    print(json.dumps(translatable_langs))\n\n\n@app.command()\ndef commands_json(\n    command: Annotated[str | None, typer.Option(envvar=\"COMMAND\")] = None,\n) -> None:\n    available_commands = [\n        \"translate-page\",\n        \"translate-lang\",\n        \"update-outdated\",\n        \"add-missing\",\n        \"update-and-add\",\n        \"remove-removable\",\n    ]\n    default_commands = [\n        \"remove-removable\",\n        \"update-outdated\",\n        \"add-missing\",\n    ]\n    if command:\n        if command in available_commands:\n            print(json.dumps([command]))\n            return\n        else:\n            raise typer.Exit(code=1)\n    print(json.dumps(default_commands))\n\n\n@app.command()\ndef list_removable(language: str) -> list[Path]:\n    removable_paths: list[Path] = []\n    lang_paths = Path(f\"docs/{language}\").rglob(\"*.md\")\n    for path in lang_paths:\n        en_path = generate_en_path(lang=language, path=path)\n        if not en_path.exists():\n            removable_paths.append(path)\n    print(removable_paths)\n    return removable_paths\n\n\n@app.command()\ndef list_all_removable() -> list[Path]:\n    all_removable_paths: list[Path] = []\n    langs = get_langs()\n    for lang in langs:\n        if lang == \"en\":\n            continue\n        removable_paths = list_removable(lang)\n        all_removable_paths.extend(removable_paths)\n    print(all_removable_paths)\n    return all_removable_paths\n\n\n@app.command()\ndef remove_removable(language: Annotated[str, typer.Option(envvar=\"LANGUAGE\")]) -> None:\n    removable_paths = list_removable(language)\n    for path in removable_paths:\n        path.unlink()\n        print(f\"Removed: {path}\")\n    print(\"Done removing all removable paths\")\n\n\n@app.command()\ndef remove_all_removable() -> None:\n    all_removable = list_all_removable()\n    for removable_path in all_removable:\n        removable_path.unlink()\n        print(f\"Removed: {removable_path}\")\n    print(\"Done removing all removable paths\")\n\n\n@app.command()\ndef list_missing(language: str) -> list[Path]:\n    missing_paths: list[Path] = []\n    en_lang_paths = list(iter_en_paths_to_translate())\n    for path in en_lang_paths:\n        lang_path = generate_lang_path(lang=language, path=path)\n        if not lang_path.exists():\n            missing_paths.append(path)\n    print(missing_paths)\n    return missing_paths\n\n\n@app.command()\ndef list_outdated(language: str) -> list[Path]:\n    dir_path = Path(__file__).absolute().parent.parent\n    repo = git.Repo(dir_path)\n\n    outdated_paths: list[Path] = []\n    en_lang_paths = list(iter_en_paths_to_translate())\n    for path in en_lang_paths:\n        lang_path = generate_lang_path(lang=language, path=path)\n        if not lang_path.exists():\n            continue\n        en_commit_datetime = list(repo.iter_commits(paths=path, max_count=1))[\n            0\n        ].committed_datetime\n        lang_commit_datetime = list(repo.iter_commits(paths=lang_path, max_count=1))[\n            0\n        ].committed_datetime\n        if lang_commit_datetime < en_commit_datetime:\n            outdated_paths.append(path)\n    print(outdated_paths)\n    return outdated_paths\n\n\n@app.command()\ndef update_outdated(\n    language: Annotated[str, typer.Option(envvar=\"LANGUAGE\")],\n    max: Annotated[int, typer.Option(envvar=\"MAX\")] = 10,\n) -> None:\n    outdated_paths = list_outdated(language)\n    for path in outdated_paths[:max]:\n        print(f\"Updating lang: {language} path: {path}\")\n        translate_page(language=language, en_path=path)\n        print(f\"Done updating: {path}\")\n    print(\"Done updating all outdated paths\")\n\n\n@app.command()\ndef add_missing(\n    language: Annotated[str, typer.Option(envvar=\"LANGUAGE\")],\n    max: Annotated[int, typer.Option(envvar=\"MAX\")] = 10,\n) -> None:\n    missing_paths = list_missing(language)\n    for path in missing_paths[:max]:\n        print(f\"Adding lang: {language} path: {path}\")\n        translate_page(language=language, en_path=path)\n        print(f\"Done adding: {path}\")\n    print(\"Done adding all missing paths\")\n\n\n@app.command()\ndef update_and_add(\n    language: Annotated[str, typer.Option(envvar=\"LANGUAGE\")],\n    max: Annotated[int, typer.Option(envvar=\"MAX\")] = 10,\n) -> None:\n    print(f\"Updating outdated translations for {language}\")\n    update_outdated(language=language, max=max)\n    print(f\"Adding missing translations for {language}\")\n    add_missing(language=language, max=max)\n    print(f\"Done updating and adding for {language}\")\n\n\n@app.command()\ndef make_pr(\n    *,\n    language: Annotated[str | None, typer.Option(envvar=\"LANGUAGE\")] = None,\n    command: Annotated[str | None, typer.Option(envvar=\"COMMAND\")] = None,\n    github_token: Annotated[str, typer.Option(envvar=\"GITHUB_TOKEN\")],\n    github_repository: Annotated[str, typer.Option(envvar=\"GITHUB_REPOSITORY\")],\n    commit_in_place: Annotated[\n        bool, typer.Option(envvar=\"COMMIT_IN_PLACE\", show_default=True)\n    ] = False,\n) -> None:\n    print(\"Setting up GitHub Actions git user\")\n    repo = git.Repo(Path(__file__).absolute().parent.parent)\n    if not repo.is_dirty(untracked_files=True):\n        print(\"Repository is clean, no changes to commit\")\n        return\n    subprocess.run([\"git\", \"config\", \"user.name\", \"github-actions[bot]\"], check=True)\n    subprocess.run(\n        [\"git\", \"config\", \"user.email\", \"github-actions[bot]@users.noreply.github.com\"],\n        check=True,\n    )\n    current_branch = repo.active_branch.name\n    if current_branch == \"master\" and commit_in_place:\n        print(\"Can't commit directly to master\")\n        raise typer.Exit(code=1)\n\n    if not commit_in_place:\n        branch_name = \"translate\"\n        if language:\n            branch_name += f\"-{language}\"\n        if command:\n            branch_name += f\"-{command}\"\n        branch_name += f\"-{secrets.token_hex(4)}\"\n        print(f\"Creating a new branch {branch_name}\")\n        subprocess.run([\"git\", \"checkout\", \"-b\", branch_name], check=True)\n    else:\n        branch_name = current_branch\n        print(f\"Committing in place on branch {branch_name}\")\n    print(\"Adding updated files\")\n    git_path = Path(\"docs\")\n    subprocess.run([\"git\", \"add\", str(git_path)], check=True)\n    print(\"Committing updated file\")\n    message = \"🌐 Update translations\"\n    if language:\n        message += f\" for {language}\"\n    if command:\n        message += f\" ({command})\"\n    subprocess.run([\"git\", \"commit\", \"-m\", message], check=True)\n    print(\"Pushing branch\")\n    subprocess.run([\"git\", \"push\", \"origin\", branch_name], check=True)\n    if not commit_in_place:\n        print(\"Creating PR\")\n        g = Github(github_token)\n        gh_repo = g.get_repo(github_repository)\n        body = (\n            message\n            + \"\\n\\nThis PR was created automatically using LLMs.\"\n            + f\"\\n\\nIt uses the prompt file https://github.com/fastapi/fastapi/blob/master/docs/{language}/llm-prompt.md.\"\n            + \"\\n\\nIn most cases, it's better to make PRs updating that file so that the LLM can do a better job generating the translations than suggesting changes in this PR.\"\n        )\n        pr = gh_repo.create_pull(\n            title=message, body=body, base=\"master\", head=branch_name\n        )\n        print(f\"Created PR: {pr.number}\")\n    print(\"Finished\")\n\n\nif __name__ == \"__main__\":\n    app()\n"
  },
  {
    "path": "scripts/translation_fixer.py",
    "content": "import os\nfrom collections.abc import Iterable\nfrom pathlib import Path\nfrom typing import Annotated\n\nimport typer\n\nfrom scripts.doc_parsing_utils import check_translation\n\nnon_translated_sections = (\n    f\"reference{os.sep}\",\n    \"release-notes.md\",\n    \"fastapi-people.md\",\n    \"external-links.md\",\n    \"newsletter.md\",\n    \"management-tasks.md\",\n    \"management.md\",\n    \"contributing.md\",\n)\n\n\ncli = typer.Typer()\n\n\n@cli.callback()\ndef callback():\n    pass\n\n\ndef iter_all_lang_paths(lang_path_root: Path) -> Iterable[Path]:\n    \"\"\"\n    Iterate on the markdown files to translate in order of priority.\n    \"\"\"\n\n    first_dirs = [\n        lang_path_root / \"learn\",\n        lang_path_root / \"tutorial\",\n        lang_path_root / \"advanced\",\n        lang_path_root / \"about\",\n        lang_path_root / \"how-to\",\n    ]\n    first_parent = lang_path_root\n    yield from first_parent.glob(\"*.md\")\n    for dir_path in first_dirs:\n        yield from dir_path.rglob(\"*.md\")\n    first_dirs_str = tuple(str(d) for d in first_dirs)\n    for path in lang_path_root.rglob(\"*.md\"):\n        if str(path).startswith(first_dirs_str):\n            continue\n        if path.parent == first_parent:\n            continue\n        yield path\n\n\ndef get_all_paths(lang: str):\n    res: list[str] = []\n    lang_docs_root = Path(\"docs\") / lang / \"docs\"\n    for path in iter_all_lang_paths(lang_docs_root):\n        relpath = path.relative_to(lang_docs_root)\n        if not str(relpath).startswith(non_translated_sections):\n            res.append(str(relpath))\n    return res\n\n\ndef process_one_page(path: Path) -> bool:\n    \"\"\"\n    Fix one translated document by comparing it to the English version.\n\n    Returns True if processed successfully, False otherwise.\n    \"\"\"\n\n    try:\n        lang_code = path.parts[1]\n        if lang_code == \"en\":\n            print(f\"Skipping English document: {path}\")\n            return True\n\n        en_doc_path = Path(\"docs\") / \"en\" / Path(*path.parts[2:])\n\n        doc_lines = path.read_text(encoding=\"utf-8\").splitlines()\n        en_doc_lines = en_doc_path.read_text(encoding=\"utf-8\").splitlines()\n\n        doc_lines = check_translation(\n            doc_lines=doc_lines,\n            en_doc_lines=en_doc_lines,\n            lang_code=lang_code,\n            auto_fix=True,\n            path=str(path),\n        )\n\n        # Write back the fixed document\n        doc_lines.append(\"\")  # Ensure file ends with a newline\n        path.write_text(\"\\n\".join(doc_lines), encoding=\"utf-8\")\n\n    except ValueError as e:\n        print(f\"Error processing {path}: {e}\")\n        return False\n    return True\n\n\n@cli.command()\ndef fix_all(ctx: typer.Context, language: str):\n    docs = get_all_paths(language)\n\n    all_good = True\n    for page in docs:\n        doc_path = Path(\"docs\") / language / \"docs\" / page\n        res = process_one_page(doc_path)\n        all_good = all_good and res\n\n    if not all_good:\n        raise typer.Exit(code=1)\n\n\n@cli.command()\ndef fix_pages(\n    doc_paths: Annotated[\n        list[Path],\n        typer.Argument(help=\"List of paths to documents.\"),\n    ],\n):\n    all_good = True\n    for path in doc_paths:\n        res = process_one_page(path)\n        all_good = all_good and res\n\n    if not all_good:\n        raise typer.Exit(code=1)\n\n\nif __name__ == \"__main__\":\n    cli()\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/benchmarks/__init__.py",
    "content": ""
  },
  {
    "path": "tests/benchmarks/test_general_performance.py",
    "content": "import json\nimport sys\nfrom collections.abc import Iterator\nfrom typing import Annotated, Any\n\nimport pytest\nfrom fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\nif \"--codspeed\" not in sys.argv:\n    pytest.skip(\n        \"Benchmark tests are skipped by default; run with --codspeed.\",\n        allow_module_level=True,\n    )\n\nLARGE_ITEMS: list[dict[str, Any]] = [\n    {\n        \"id\": i,\n        \"name\": f\"item-{i}\",\n        \"values\": list(range(25)),\n        \"meta\": {\n            \"active\": True,\n            \"group\": i % 10,\n            \"tag\": f\"t{i % 5}\",\n        },\n    }\n    for i in range(300)\n]\n\nLARGE_METADATA: dict[str, Any] = {\n    \"source\": \"benchmark\",\n    \"version\": 1,\n    \"flags\": {\"a\": True, \"b\": False, \"c\": True},\n    \"notes\": [\"x\" * 50, \"y\" * 50, \"z\" * 50],\n}\n\nLARGE_PAYLOAD: dict[str, Any] = {\"items\": LARGE_ITEMS, \"metadata\": LARGE_METADATA}\n\n\ndef dep_a():\n    return 40\n\n\ndef dep_b(a: Annotated[int, Depends(dep_a)]):\n    return a + 2\n\n\nclass ItemIn(BaseModel):\n    name: str\n    value: int\n\n\nclass ItemOut(BaseModel):\n    name: str\n    value: int\n    dep: int\n\n\nclass LargeIn(BaseModel):\n    items: list[dict[str, Any]]\n    metadata: dict[str, Any]\n\n\nclass LargeOut(BaseModel):\n    items: list[dict[str, Any]]\n    metadata: dict[str, Any]\n\n\napp = FastAPI()\n\n\n@app.post(\"/sync/validated\", response_model=ItemOut)\ndef sync_validated(item: ItemIn, dep: Annotated[int, Depends(dep_b)]):\n    return ItemOut(name=item.name, value=item.value, dep=dep)\n\n\n@app.get(\"/sync/dict-no-response-model\")\ndef sync_dict_no_response_model():\n    return {\"name\": \"foo\", \"value\": 123}\n\n\n@app.get(\"/sync/dict-with-response-model\", response_model=ItemOut)\ndef sync_dict_with_response_model(\n    dep: Annotated[int, Depends(dep_b)],\n):\n    return {\"name\": \"foo\", \"value\": 123, \"dep\": dep}\n\n\n@app.get(\"/sync/model-no-response-model\")\ndef sync_model_no_response_model(dep: Annotated[int, Depends(dep_b)]):\n    return ItemOut(name=\"foo\", value=123, dep=dep)\n\n\n@app.get(\"/sync/model-with-response-model\", response_model=ItemOut)\ndef sync_model_with_response_model(dep: Annotated[int, Depends(dep_b)]):\n    return ItemOut(name=\"foo\", value=123, dep=dep)\n\n\n@app.post(\"/async/validated\", response_model=ItemOut)\nasync def async_validated(\n    item: ItemIn,\n    dep: Annotated[int, Depends(dep_b)],\n):\n    return ItemOut(name=item.name, value=item.value, dep=dep)\n\n\n@app.post(\"/sync/large-receive\")\ndef sync_large_receive(payload: LargeIn):\n    return {\"received\": len(payload.items)}\n\n\n@app.post(\"/async/large-receive\")\nasync def async_large_receive(payload: LargeIn):\n    return {\"received\": len(payload.items)}\n\n\n@app.get(\"/sync/large-dict-no-response-model\")\ndef sync_large_dict_no_response_model():\n    return LARGE_PAYLOAD\n\n\n@app.get(\"/sync/large-dict-with-response-model\", response_model=LargeOut)\ndef sync_large_dict_with_response_model():\n    return LARGE_PAYLOAD\n\n\n@app.get(\"/sync/large-model-no-response-model\")\ndef sync_large_model_no_response_model():\n    return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA)\n\n\n@app.get(\"/sync/large-model-with-response-model\", response_model=LargeOut)\ndef sync_large_model_with_response_model():\n    return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA)\n\n\n@app.get(\"/async/large-dict-no-response-model\")\nasync def async_large_dict_no_response_model():\n    return LARGE_PAYLOAD\n\n\n@app.get(\"/async/large-dict-with-response-model\", response_model=LargeOut)\nasync def async_large_dict_with_response_model():\n    return LARGE_PAYLOAD\n\n\n@app.get(\"/async/large-model-no-response-model\")\nasync def async_large_model_no_response_model():\n    return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA)\n\n\n@app.get(\"/async/large-model-with-response-model\", response_model=LargeOut)\nasync def async_large_model_with_response_model():\n    return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA)\n\n\n@app.get(\"/async/dict-no-response-model\")\nasync def async_dict_no_response_model():\n    return {\"name\": \"foo\", \"value\": 123}\n\n\n@app.get(\"/async/dict-with-response-model\", response_model=ItemOut)\nasync def async_dict_with_response_model(\n    dep: Annotated[int, Depends(dep_b)],\n):\n    return {\"name\": \"foo\", \"value\": 123, \"dep\": dep}\n\n\n@app.get(\"/async/model-no-response-model\")\nasync def async_model_no_response_model(\n    dep: Annotated[int, Depends(dep_b)],\n):\n    return ItemOut(name=\"foo\", value=123, dep=dep)\n\n\n@app.get(\"/async/model-with-response-model\", response_model=ItemOut)\nasync def async_model_with_response_model(\n    dep: Annotated[int, Depends(dep_b)],\n):\n    return ItemOut(name=\"foo\", value=123, dep=dep)\n\n\n@pytest.fixture(scope=\"module\")\ndef client() -> Iterator[TestClient]:\n    with TestClient(app) as client:\n        yield client\n\n\ndef _bench_get(benchmark, client: TestClient, path: str) -> tuple[int, bytes]:\n    warmup = client.get(path)\n    assert warmup.status_code == 200\n\n    def do_request() -> tuple[int, bytes]:\n        response = client.get(path)\n        return response.status_code, response.content\n\n    return benchmark(do_request)\n\n\ndef _bench_post_json(\n    benchmark, client: TestClient, path: str, json: dict[str, Any]\n) -> tuple[int, bytes]:\n    warmup = client.post(path, json=json)\n    assert warmup.status_code == 200\n\n    def do_request() -> tuple[int, bytes]:\n        response = client.post(path, json=json)\n        return response.status_code, response.content\n\n    return benchmark(do_request)\n\n\ndef test_sync_receiving_validated_pydantic_model(benchmark, client: TestClient) -> None:\n    status_code, body = _bench_post_json(\n        benchmark,\n        client,\n        \"/sync/validated\",\n        json={\"name\": \"foo\", \"value\": 123},\n    )\n    assert status_code == 200\n    assert body == b'{\"name\":\"foo\",\"value\":123,\"dep\":42}'\n\n\ndef test_sync_return_dict_without_response_model(benchmark, client: TestClient) -> None:\n    status_code, body = _bench_get(benchmark, client, \"/sync/dict-no-response-model\")\n    assert status_code == 200\n    assert body == b'{\"name\":\"foo\",\"value\":123}'\n\n\ndef test_sync_return_dict_with_response_model(benchmark, client: TestClient) -> None:\n    status_code, body = _bench_get(benchmark, client, \"/sync/dict-with-response-model\")\n    assert status_code == 200\n    assert body == b'{\"name\":\"foo\",\"value\":123,\"dep\":42}'\n\n\ndef test_sync_return_model_without_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(benchmark, client, \"/sync/model-no-response-model\")\n    assert status_code == 200\n    assert body == b'{\"name\":\"foo\",\"value\":123,\"dep\":42}'\n\n\ndef test_sync_return_model_with_response_model(benchmark, client: TestClient) -> None:\n    status_code, body = _bench_get(benchmark, client, \"/sync/model-with-response-model\")\n    assert status_code == 200\n    assert body == b'{\"name\":\"foo\",\"value\":123,\"dep\":42}'\n\n\ndef test_async_receiving_validated_pydantic_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_post_json(\n        benchmark, client, \"/async/validated\", json={\"name\": \"foo\", \"value\": 123}\n    )\n    assert status_code == 200\n    assert body == b'{\"name\":\"foo\",\"value\":123,\"dep\":42}'\n\n\ndef test_async_return_dict_without_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(benchmark, client, \"/async/dict-no-response-model\")\n    assert status_code == 200\n    assert body == b'{\"name\":\"foo\",\"value\":123}'\n\n\ndef test_async_return_dict_with_response_model(benchmark, client: TestClient) -> None:\n    status_code, body = _bench_get(benchmark, client, \"/async/dict-with-response-model\")\n    assert status_code == 200\n    assert body == b'{\"name\":\"foo\",\"value\":123,\"dep\":42}'\n\n\ndef test_async_return_model_without_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(benchmark, client, \"/async/model-no-response-model\")\n    assert status_code == 200\n    assert body == b'{\"name\":\"foo\",\"value\":123,\"dep\":42}'\n\n\ndef test_async_return_model_with_response_model(benchmark, client: TestClient) -> None:\n    status_code, body = _bench_get(\n        benchmark, client, \"/async/model-with-response-model\"\n    )\n    assert status_code == 200\n    assert body == b'{\"name\":\"foo\",\"value\":123,\"dep\":42}'\n\n\ndef test_sync_receiving_large_payload(benchmark, client: TestClient) -> None:\n    status_code, body = _bench_post_json(\n        benchmark,\n        client,\n        \"/sync/large-receive\",\n        json=LARGE_PAYLOAD,\n    )\n    assert status_code == 200\n    assert body == b'{\"received\":300}'\n\n\ndef test_async_receiving_large_payload(benchmark, client: TestClient) -> None:\n    status_code, body = _bench_post_json(\n        benchmark,\n        client,\n        \"/async/large-receive\",\n        json=LARGE_PAYLOAD,\n    )\n    assert status_code == 200\n    assert body == b'{\"received\":300}'\n\n\ndef _expected_large_payload_json_bytes() -> bytes:\n    return json.dumps(\n        LARGE_PAYLOAD,\n        ensure_ascii=False,\n        allow_nan=False,\n        separators=(\",\", \":\"),\n    ).encode(\"utf-8\")\n\n\ndef test_sync_return_large_dict_without_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(\n        benchmark, client, \"/sync/large-dict-no-response-model\"\n    )\n    assert status_code == 200\n    assert body == _expected_large_payload_json_bytes()\n\n\ndef test_sync_return_large_dict_with_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(\n        benchmark, client, \"/sync/large-dict-with-response-model\"\n    )\n    assert status_code == 200\n    assert body == _expected_large_payload_json_bytes()\n\n\ndef test_sync_return_large_model_without_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(\n        benchmark, client, \"/sync/large-model-no-response-model\"\n    )\n    assert status_code == 200\n    assert body == _expected_large_payload_json_bytes()\n\n\ndef test_sync_return_large_model_with_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(\n        benchmark, client, \"/sync/large-model-with-response-model\"\n    )\n    assert status_code == 200\n    assert body == _expected_large_payload_json_bytes()\n\n\ndef test_async_return_large_dict_without_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(\n        benchmark, client, \"/async/large-dict-no-response-model\"\n    )\n    assert status_code == 200\n    assert body == _expected_large_payload_json_bytes()\n\n\ndef test_async_return_large_dict_with_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(\n        benchmark, client, \"/async/large-dict-with-response-model\"\n    )\n    assert status_code == 200\n    assert body == _expected_large_payload_json_bytes()\n\n\ndef test_async_return_large_model_without_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(\n        benchmark, client, \"/async/large-model-no-response-model\"\n    )\n    assert status_code == 200\n    assert body == _expected_large_payload_json_bytes()\n\n\ndef test_async_return_large_model_with_response_model(\n    benchmark, client: TestClient\n) -> None:\n    status_code, body = _bench_get(\n        benchmark, client, \"/async/large-model-with-response-model\"\n    )\n    assert status_code == 200\n    assert body == _expected_large_payload_json_bytes()\n"
  },
  {
    "path": "tests/forward_reference_type.py",
    "content": "from pydantic import BaseModel\n\n\ndef forwardref_method(input: \"ForwardRefModel\") -> \"ForwardRefModel\":\n    return ForwardRefModel(x=input.x + 1)\n\n\nclass ForwardRefModel(BaseModel):\n    x: int = 0\n"
  },
  {
    "path": "tests/main.py",
    "content": "import http\n\nfrom fastapi import FastAPI, Path, Query\n\nexternal_docs = {\n    \"description\": \"External API documentation.\",\n    \"url\": \"https://docs.example.com/api-general\",\n}\n\napp = FastAPI(openapi_external_docs=external_docs)\n\n\n@app.api_route(\"/api_route\")\ndef non_operation():\n    return {\"message\": \"Hello World\"}\n\n\ndef non_decorated_route():\n    return {\"message\": \"Hello World\"}\n\n\napp.add_api_route(\"/non_decorated_route\", non_decorated_route)\n\n\n@app.get(\"/text\")\ndef get_text():\n    return \"Hello World\"\n\n\n@app.get(\"/path/{item_id}\")\ndef get_id(item_id):\n    return item_id\n\n\n@app.get(\"/path/str/{item_id}\")\ndef get_str_id(item_id: str):\n    return item_id\n\n\n@app.get(\"/path/int/{item_id}\")\ndef get_int_id(item_id: int):\n    return item_id\n\n\n@app.get(\"/path/float/{item_id}\")\ndef get_float_id(item_id: float):\n    return item_id\n\n\n@app.get(\"/path/bool/{item_id}\")\ndef get_bool_id(item_id: bool):\n    return item_id\n\n\n@app.get(\"/path/param/{item_id}\")\ndef get_path_param_id(item_id: str | None = Path()):\n    return item_id\n\n\n@app.get(\"/path/param-minlength/{item_id}\")\ndef get_path_param_min_length(item_id: str = Path(min_length=3)):\n    return item_id\n\n\n@app.get(\"/path/param-maxlength/{item_id}\")\ndef get_path_param_max_length(item_id: str = Path(max_length=3)):\n    return item_id\n\n\n@app.get(\"/path/param-min_maxlength/{item_id}\")\ndef get_path_param_min_max_length(item_id: str = Path(max_length=3, min_length=2)):\n    return item_id\n\n\n@app.get(\"/path/param-gt/{item_id}\")\ndef get_path_param_gt(item_id: float = Path(gt=3)):\n    return item_id\n\n\n@app.get(\"/path/param-gt0/{item_id}\")\ndef get_path_param_gt0(item_id: float = Path(gt=0)):\n    return item_id\n\n\n@app.get(\"/path/param-ge/{item_id}\")\ndef get_path_param_ge(item_id: float = Path(ge=3)):\n    return item_id\n\n\n@app.get(\"/path/param-lt/{item_id}\")\ndef get_path_param_lt(item_id: float = Path(lt=3)):\n    return item_id\n\n\n@app.get(\"/path/param-lt0/{item_id}\")\ndef get_path_param_lt0(item_id: float = Path(lt=0)):\n    return item_id\n\n\n@app.get(\"/path/param-le/{item_id}\")\ndef get_path_param_le(item_id: float = Path(le=3)):\n    return item_id\n\n\n@app.get(\"/path/param-lt-gt/{item_id}\")\ndef get_path_param_lt_gt(item_id: float = Path(lt=3, gt=1)):\n    return item_id\n\n\n@app.get(\"/path/param-le-ge/{item_id}\")\ndef get_path_param_le_ge(item_id: float = Path(le=3, ge=1)):\n    return item_id\n\n\n@app.get(\"/path/param-lt-int/{item_id}\")\ndef get_path_param_lt_int(item_id: int = Path(lt=3)):\n    return item_id\n\n\n@app.get(\"/path/param-gt-int/{item_id}\")\ndef get_path_param_gt_int(item_id: int = Path(gt=3)):\n    return item_id\n\n\n@app.get(\"/path/param-le-int/{item_id}\")\ndef get_path_param_le_int(item_id: int = Path(le=3)):\n    return item_id\n\n\n@app.get(\"/path/param-ge-int/{item_id}\")\ndef get_path_param_ge_int(item_id: int = Path(ge=3)):\n    return item_id\n\n\n@app.get(\"/path/param-lt-gt-int/{item_id}\")\ndef get_path_param_lt_gt_int(item_id: int = Path(lt=3, gt=1)):\n    return item_id\n\n\n@app.get(\"/path/param-le-ge-int/{item_id}\")\ndef get_path_param_le_ge_int(item_id: int = Path(le=3, ge=1)):\n    return item_id\n\n\n@app.get(\"/query\")\ndef get_query(query):\n    return f\"foo bar {query}\"\n\n\n@app.get(\"/query/optional\")\ndef get_query_optional(query=None):\n    if query is None:\n        return \"foo bar\"\n    return f\"foo bar {query}\"\n\n\n@app.get(\"/query/int\")\ndef get_query_type(query: int):\n    return f\"foo bar {query}\"\n\n\n@app.get(\"/query/int/optional\")\ndef get_query_type_optional(query: int | None = None):\n    if query is None:\n        return \"foo bar\"\n    return f\"foo bar {query}\"\n\n\n@app.get(\"/query/int/default\")\ndef get_query_type_int_default(query: int = 10):\n    return f\"foo bar {query}\"\n\n\n@app.get(\"/query/param\")\ndef get_query_param(query=Query(default=None)):\n    if query is None:\n        return \"foo bar\"\n    return f\"foo bar {query}\"\n\n\n@app.get(\"/query/param-required\")\ndef get_query_param_required(query=Query()):\n    return f\"foo bar {query}\"\n\n\n@app.get(\"/query/param-required/int\")\ndef get_query_param_required_type(query: int = Query()):\n    return f\"foo bar {query}\"\n\n\n@app.get(\"/enum-status-code\", status_code=http.HTTPStatus.CREATED)\ndef get_enum_status_code():\n    return \"foo bar\"\n\n\n@app.get(\"/query/frozenset\")\ndef get_query_type_frozenset(query: frozenset[int] = Query(...)):\n    return \",\".join(map(str, sorted(query)))\n\n\n@app.get(\"/query/list\")\ndef get_query_list(device_ids: list[int] = Query()) -> list[int]:\n    return device_ids\n\n\n@app.get(\"/query/list-default\")\ndef get_query_list_default(device_ids: list[int] = Query(default=[])) -> list[int]:\n    return device_ids\n"
  },
  {
    "path": "tests/test_additional_properties.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Items(BaseModel):\n    items: dict[str, int]\n\n\n@app.post(\"/foo\")\ndef foo(items: Items):\n    return items.items\n\n\nclient = TestClient(app)\n\n\ndef test_additional_properties_post():\n    response = client.post(\"/foo\", json={\"items\": {\"foo\": 1, \"bar\": 2}})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"foo\": 1, \"bar\": 2}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/foo\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Foo\",\n                        \"operationId\": \"foo_foo_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Items\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Items\": {\n                        \"title\": \"Items\",\n                        \"required\": [\"items\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"items\": {\n                                \"title\": \"Items\",\n                                \"type\": \"object\",\n                                \"additionalProperties\": {\"type\": \"integer\"},\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_additional_properties_bool.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, ConfigDict\n\n\nclass FooBaseModel(BaseModel):\n    model_config = ConfigDict(extra=\"forbid\")\n\n\nclass Foo(FooBaseModel):\n    pass\n\n\napp = FastAPI()\n\n\n@app.post(\"/\")\nasync def post(\n    foo: Foo | None = None,\n):\n    return foo\n\n\nclient = TestClient(app)\n\n\ndef test_call_invalid():\n    response = client.post(\"/\", json={\"foo\": {\"bar\": \"baz\"}})\n    assert response.status_code == 422\n\n\ndef test_call_valid():\n    response = client.post(\"/\", json={})\n    assert response.status_code == 200\n    assert response.json() == {}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"post\": {\n                        \"summary\": \"Post\",\n                        \"operationId\": \"post__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"anyOf\": [\n                                            {\"$ref\": \"#/components/schemas/Foo\"},\n                                            {\"type\": \"null\"},\n                                        ],\n                                        \"title\": \"Foo\",\n                                    }\n                                }\n                            }\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Foo\": {\n                        \"properties\": {},\n                        \"additionalProperties\": False,\n                        \"type\": \"object\",\n                        \"title\": \"Foo\",\n                    },\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_additional_response_extra.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nrouter = APIRouter()\n\nsub_router = APIRouter()\n\napp = FastAPI()\n\n\n@sub_router.get(\"/\")\ndef read_item():\n    return {\"id\": \"foo\"}\n\n\nrouter.include_router(sub_router, prefix=\"/items\")\n\napp.include_router(router)\n\nclient = TestClient(app)\n\n\ndef test_path_operation():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"id\": \"foo\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__get\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_additional_responses_bad.py",
    "content": "import pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.get(\"/a\", responses={\"hello\": {\"description\": \"Not a valid additional response\"}})\nasync def a():\n    pass  # pragma: no cover\n\n\nopenapi_schema = {\n    \"openapi\": \"3.1.0\",\n    \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n    \"paths\": {\n        \"/a\": {\n            \"get\": {\n                \"responses\": {\n                    # this is how one would imagine the openapi schema to be\n                    # but since the key is not valid, openapi.utils.get_openapi will raise ValueError\n                    \"hello\": {\"description\": \"Not a valid additional response\"},\n                    \"200\": {\n                        \"description\": \"Successful Response\",\n                        \"content\": {\"application/json\": {\"schema\": {}}},\n                    },\n                },\n                \"summary\": \"A\",\n                \"operationId\": \"a_a_get\",\n            }\n        }\n    },\n}\n\nclient = TestClient(app)\n\n\ndef test_openapi_schema():\n    with pytest.raises(ValueError):\n        client.get(\"/openapi.json\")\n"
  },
  {
    "path": "tests/test_additional_responses_custom_model_in_callback.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, HttpUrl\nfrom starlette.responses import JSONResponse\n\n\nclass CustomModel(BaseModel):\n    a: int\n\n\napp = FastAPI()\n\ncallback_router = APIRouter(default_response_class=JSONResponse)\n\n\n@callback_router.get(\n    \"{$callback_url}/callback/\", responses={400: {\"model\": CustomModel}}\n)\ndef callback_route():\n    pass  # pragma: no cover\n\n\n@app.post(\"/\", callbacks=callback_router.routes)\ndef main_route(callback_url: HttpUrl):\n    pass  # pragma: no cover\n\n\nclient = TestClient(app)\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"post\": {\n                        \"summary\": \"Main Route\",\n                        \"operationId\": \"main_route__post\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Callback Url\",\n                                    \"maxLength\": 2083,\n                                    \"minLength\": 1,\n                                    \"type\": \"string\",\n                                    \"format\": \"uri\",\n                                },\n                                \"name\": \"callback_url\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"callbacks\": {\n                            \"callback_route\": {\n                                \"{$callback_url}/callback/\": {\n                                    \"get\": {\n                                        \"summary\": \"Callback Route\",\n                                        \"operationId\": \"callback_route__callback_url__callback__get\",\n                                        \"responses\": {\n                                            \"400\": {\n                                                \"content\": {\n                                                    \"application/json\": {\n                                                        \"schema\": {\n                                                            \"$ref\": \"#/components/schemas/CustomModel\"\n                                                        }\n                                                    }\n                                                },\n                                                \"description\": \"Bad Request\",\n                                            },\n                                            \"200\": {\n                                                \"description\": \"Successful Response\",\n                                                \"content\": {\n                                                    \"application/json\": {\"schema\": {}}\n                                                },\n                                            },\n                                        },\n                                    }\n                                }\n                            }\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"CustomModel\": {\n                        \"title\": \"CustomModel\",\n                        \"required\": [\"a\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"a\": {\"title\": \"A\", \"type\": \"integer\"}},\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_additional_responses_custom_validationerror.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass JsonApiResponse(JSONResponse):\n    media_type = \"application/vnd.api+json\"\n\n\nclass Error(BaseModel):\n    status: str\n    title: str\n\n\nclass JsonApiError(BaseModel):\n    errors: list[Error]\n\n\n@app.get(\n    \"/a/{id}\",\n    response_class=JsonApiResponse,\n    responses={422: {\"description\": \"Error\", \"model\": JsonApiError}},\n)\nasync def a(id):\n    pass  # pragma: no cover\n\n\nclient = TestClient(app)\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/a/{id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"422\": {\n                                \"description\": \"Error\",\n                                \"content\": {\n                                    \"application/vnd.api+json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/JsonApiError\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/vnd.api+json\": {\"schema\": {}}},\n                            },\n                        },\n                        \"summary\": \"A\",\n                        \"operationId\": \"a_a__id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Id\"},\n                                \"name\": \"id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Error\": {\n                        \"title\": \"Error\",\n                        \"required\": [\"status\", \"title\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"status\": {\"title\": \"Status\", \"type\": \"string\"},\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                        },\n                    },\n                    \"JsonApiError\": {\n                        \"title\": \"JsonApiError\",\n                        \"required\": [\"errors\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"errors\": {\n                                \"title\": \"Errors\",\n                                \"type\": \"array\",\n                                \"items\": {\"$ref\": \"#/components/schemas/Error\"},\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_additional_responses_default_validationerror.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\n@app.get(\"/a/{id}\")\nasync def a(id):\n    pass  # pragma: no cover\n\n\nclient = TestClient(app)\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/a/{id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                        },\n                        \"summary\": \"A\",\n                        \"operationId\": \"a_a__id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Id\"},\n                                \"name\": \"id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_additional_responses_response_class.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass JsonApiResponse(JSONResponse):\n    media_type = \"application/vnd.api+json\"\n\n\nclass Error(BaseModel):\n    status: str\n    title: str\n\n\nclass JsonApiError(BaseModel):\n    errors: list[Error]\n\n\n@app.get(\n    \"/a\",\n    response_class=JsonApiResponse,\n    responses={500: {\"description\": \"Error\", \"model\": JsonApiError}},\n)\nasync def a():\n    pass  # pragma: no cover\n\n\n@app.get(\"/b\", responses={500: {\"description\": \"Error\", \"model\": Error}})\nasync def b():\n    pass  # pragma: no cover\n\n\nclient = TestClient(app)\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/a\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"500\": {\n                                \"description\": \"Error\",\n                                \"content\": {\n                                    \"application/vnd.api+json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/JsonApiError\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/vnd.api+json\": {\"schema\": {}}},\n                            },\n                        },\n                        \"summary\": \"A\",\n                        \"operationId\": \"a_a_get\",\n                    }\n                },\n                \"/b\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"500\": {\n                                \"description\": \"Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Error\"}\n                                    }\n                                },\n                            },\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                        },\n                        \"summary\": \"B\",\n                        \"operationId\": \"b_b_get\",\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Error\": {\n                        \"title\": \"Error\",\n                        \"required\": [\"status\", \"title\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"status\": {\"title\": \"Status\", \"type\": \"string\"},\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                        },\n                    },\n                    \"JsonApiError\": {\n                        \"title\": \"JsonApiError\",\n                        \"required\": [\"errors\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"errors\": {\n                                \"title\": \"Errors\",\n                                \"type\": \"array\",\n                                \"items\": {\"$ref\": \"#/components/schemas/Error\"},\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_additional_responses_router.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\n\nclass ResponseModel(BaseModel):\n    message: str\n\n\napp = FastAPI()\nrouter = APIRouter()\n\n\n@router.get(\"/a\", responses={501: {\"description\": \"Error 1\"}})\nasync def a():\n    return \"a\"\n\n\n@router.get(\n    \"/b\",\n    responses={\n        502: {\"description\": \"Error 2\"},\n        \"4XX\": {\"description\": \"Error with range, upper\"},\n    },\n)\nasync def b():\n    return \"b\"\n\n\n@router.get(\n    \"/c\",\n    responses={\n        \"400\": {\"description\": \"Error with str\"},\n        \"5xx\": {\"description\": \"Error with range, lower\"},\n        \"default\": {\"description\": \"A default response\"},\n    },\n)\nasync def c():\n    return \"c\"\n\n\n@router.get(\n    \"/d\",\n    responses={\n        \"400\": {\"description\": \"Error with str\"},\n        \"5XX\": {\"model\": ResponseModel},\n        \"default\": {\"model\": ResponseModel},\n    },\n)\nasync def d():\n    return \"d\"\n\n\napp.include_router(router)\n\n\nclient = TestClient(app)\n\n\ndef test_a():\n    response = client.get(\"/a\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"a\"\n\n\ndef test_b():\n    response = client.get(\"/b\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"b\"\n\n\ndef test_c():\n    response = client.get(\"/c\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"c\"\n\n\ndef test_d():\n    response = client.get(\"/d\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"d\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/a\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"501\": {\"description\": \"Error 1\"},\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                        },\n                        \"summary\": \"A\",\n                        \"operationId\": \"a_a_get\",\n                    }\n                },\n                \"/b\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"502\": {\"description\": \"Error 2\"},\n                            \"4XX\": {\"description\": \"Error with range, upper\"},\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                        },\n                        \"summary\": \"B\",\n                        \"operationId\": \"b_b_get\",\n                    }\n                },\n                \"/c\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"400\": {\"description\": \"Error with str\"},\n                            \"5XX\": {\"description\": \"Error with range, lower\"},\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"default\": {\"description\": \"A default response\"},\n                        },\n                        \"summary\": \"C\",\n                        \"operationId\": \"c_c_get\",\n                    }\n                },\n                \"/d\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"400\": {\"description\": \"Error with str\"},\n                            \"5XX\": {\n                                \"description\": \"Server Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ResponseModel\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"default\": {\n                                \"description\": \"Default Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ResponseModel\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"D\",\n                        \"operationId\": \"d_d_get\",\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ResponseModel\": {\n                        \"title\": \"ResponseModel\",\n                        \"required\": [\"message\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"message\": {\"title\": \"Message\", \"type\": \"string\"}\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_additional_responses_union_duplicate_anyof.py",
    "content": "\"\"\"\nRegression test: Ensure app-level responses with Union models and content/examples\ndon't accumulate duplicate $ref entries in anyOf arrays.\nSee https://github.com/fastapi/fastapi/pull/14463\n\"\"\"\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\n\nclass ModelA(BaseModel):\n    a: str\n\n\nclass ModelB(BaseModel):\n    b: str\n\n\napp = FastAPI(\n    responses={\n        500: {\n            \"model\": ModelA | ModelB,\n            \"content\": {\"application/json\": {\"examples\": {\"Case A\": {\"value\": \"a\"}}}},\n        }\n    }\n)\n\n\n@app.get(\"/route1\")\nasync def route1():\n    pass  # pragma: no cover\n\n\n@app.get(\"/route2\")\nasync def route2():\n    pass  # pragma: no cover\n\n\nclient = TestClient(app)\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/route1\": {\n                    \"get\": {\n                        \"summary\": \"Route1\",\n                        \"operationId\": \"route1_route1_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"500\": {\n                                \"description\": \"Internal Server Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"anyOf\": [\n                                                {\"$ref\": \"#/components/schemas/ModelA\"},\n                                                {\"$ref\": \"#/components/schemas/ModelB\"},\n                                            ],\n                                            \"title\": \"Response 500 Route1 Route1 Get\",\n                                        },\n                                        \"examples\": {\"Case A\": {\"value\": \"a\"}},\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/route2\": {\n                    \"get\": {\n                        \"summary\": \"Route2\",\n                        \"operationId\": \"route2_route2_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"500\": {\n                                \"description\": \"Internal Server Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"anyOf\": [\n                                                {\"$ref\": \"#/components/schemas/ModelA\"},\n                                                {\"$ref\": \"#/components/schemas/ModelB\"},\n                                            ],\n                                            \"title\": \"Response 500 Route2 Route2 Get\",\n                                        },\n                                        \"examples\": {\"Case A\": {\"value\": \"a\"}},\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ModelA\": {\n                        \"properties\": {\"a\": {\"type\": \"string\", \"title\": \"A\"}},\n                        \"type\": \"object\",\n                        \"required\": [\"a\"],\n                        \"title\": \"ModelA\",\n                    },\n                    \"ModelB\": {\n                        \"properties\": {\"b\": {\"type\": \"string\", \"title\": \"B\"}},\n                        \"type\": \"object\",\n                        \"required\": [\"b\"],\n                        \"title\": \"ModelB\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_allow_inf_nan_in_enforcing.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import Body, FastAPI, Query\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.post(\"/\")\nasync def get(\n    x: Annotated[float, Query(allow_inf_nan=True)] = 0,\n    y: Annotated[float, Query(allow_inf_nan=False)] = 0,\n    z: Annotated[float, Query()] = 0,\n    b: Annotated[float, Body(allow_inf_nan=False)] = 0,\n) -> str:\n    return \"OK\"\n\n\nclient = TestClient(app)\n\n\n@pytest.mark.parametrize(\n    \"value,code\",\n    [\n        (\"-1\", 200),\n        (\"inf\", 200),\n        (\"-inf\", 200),\n        (\"nan\", 200),\n        (\"0\", 200),\n        (\"342\", 200),\n    ],\n)\ndef test_allow_inf_nan_param_true(value: str, code: int):\n    response = client.post(f\"/?x={value}\")\n    assert response.status_code == code, response.text\n\n\n@pytest.mark.parametrize(\n    \"value,code\",\n    [\n        (\"-1\", 200),\n        (\"inf\", 422),\n        (\"-inf\", 422),\n        (\"nan\", 422),\n        (\"0\", 200),\n        (\"342\", 200),\n    ],\n)\ndef test_allow_inf_nan_param_false(value: str, code: int):\n    response = client.post(f\"/?y={value}\")\n    assert response.status_code == code, response.text\n\n\n@pytest.mark.parametrize(\n    \"value,code\",\n    [\n        (\"-1\", 200),\n        (\"inf\", 200),\n        (\"-inf\", 200),\n        (\"nan\", 200),\n        (\"0\", 200),\n        (\"342\", 200),\n    ],\n)\ndef test_allow_inf_nan_param_default(value: str, code: int):\n    response = client.post(f\"/?z={value}\")\n    assert response.status_code == code, response.text\n\n\n@pytest.mark.parametrize(\n    \"value,code\",\n    [\n        (\"-1\", 200),\n        (\"inf\", 422),\n        (\"-inf\", 422),\n        (\"nan\", 422),\n        (\"0\", 200),\n        (\"342\", 200),\n    ],\n)\ndef test_allow_inf_nan_body(value: str, code: int):\n    response = client.post(\"/\", json=value)\n    assert response.status_code == code, response.text\n"
  },
  {
    "path": "tests/test_ambiguous_params.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import Depends, FastAPI, Path\nfrom fastapi.param_functions import Query\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\ndef test_no_annotated_defaults():\n    with pytest.raises(\n        AssertionError, match=\"Path parameters cannot have a default value\"\n    ):\n\n        @app.get(\"/items/{item_id}/\")\n        async def get_item(item_id: Annotated[int, Path(default=1)]):\n            pass  # pragma: nocover\n\n    with pytest.raises(\n        AssertionError,\n        match=(\n            \"`Query` default value cannot be set in `Annotated` for 'item_id'. Set the\"\n            \" default value with `=` instead.\"\n        ),\n    ):\n\n        @app.get(\"/\")\n        async def get(item_id: Annotated[int, Query(default=1)]):\n            pass  # pragma: nocover\n\n\ndef test_multiple_annotations():\n    async def dep():\n        pass  # pragma: nocover\n\n    @app.get(\"/multi-query\")\n    async def get(foo: Annotated[int, Query(gt=2), Query(lt=10)]):\n        return foo\n\n    with pytest.raises(\n        AssertionError,\n        match=(\n            \"Cannot specify `Depends` in `Annotated` and default value\"\n            \" together for 'foo'\"\n        ),\n    ):\n\n        @app.get(\"/\")\n        async def get2(foo: Annotated[int, Depends(dep)] = Depends(dep)):\n            pass  # pragma: nocover\n\n    with pytest.raises(\n        AssertionError,\n        match=(\n            \"Cannot specify a FastAPI annotation in `Annotated` and `Depends` as a\"\n            \" default value together for 'foo'\"\n        ),\n    ):\n\n        @app.get(\"/\")\n        async def get3(foo: Annotated[int, Query(min_length=1)] = Depends(dep)):\n            pass  # pragma: nocover\n\n    client = TestClient(app)\n    response = client.get(\"/multi-query\", params={\"foo\": \"5\"})\n    assert response.status_code == 200\n    assert response.json() == 5\n\n    response = client.get(\"/multi-query\", params={\"foo\": \"123\"})\n    assert response.status_code == 422\n\n    response = client.get(\"/multi-query\", params={\"foo\": \"1\"})\n    assert response.status_code == 422\n"
  },
  {
    "path": "tests/test_annotated.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import APIRouter, FastAPI, Query\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\n@app.get(\"/default\")\nasync def default(foo: Annotated[str, Query()] = \"foo\"):\n    return {\"foo\": foo}\n\n\n@app.get(\"/required\")\nasync def required(foo: Annotated[str, Query(min_length=1)]):\n    return {\"foo\": foo}\n\n\n@app.get(\"/multiple\")\nasync def multiple(foo: Annotated[str, object(), Query(min_length=1)]):\n    return {\"foo\": foo}\n\n\n@app.get(\"/unrelated\")\nasync def unrelated(foo: Annotated[str, object()]):\n    return {\"foo\": foo}\n\n\nclient = TestClient(app)\n\nfoo_is_missing = {\n    \"detail\": [\n        {\n            \"loc\": [\"query\", \"foo\"],\n            \"msg\": \"Field required\",\n            \"type\": \"missing\",\n            \"input\": None,\n        }\n    ]\n}\nfoo_is_short = {\n    \"detail\": [\n        {\n            \"ctx\": {\"min_length\": 1},\n            \"loc\": [\"query\", \"foo\"],\n            \"msg\": \"String should have at least 1 character\",\n            \"type\": \"string_too_short\",\n            \"input\": \"\",\n        }\n    ]\n}\n\n\n@pytest.mark.parametrize(\n    \"path,expected_status,expected_response\",\n    [\n        (\"/default\", 200, {\"foo\": \"foo\"}),\n        (\"/default?foo=bar\", 200, {\"foo\": \"bar\"}),\n        (\"/required?foo=bar\", 200, {\"foo\": \"bar\"}),\n        (\"/required\", 422, foo_is_missing),\n        (\"/required?foo=\", 422, foo_is_short),\n        (\"/multiple?foo=bar\", 200, {\"foo\": \"bar\"}),\n        (\"/multiple\", 422, foo_is_missing),\n        (\"/multiple?foo=\", 422, foo_is_short),\n        (\"/unrelated?foo=bar\", 200, {\"foo\": \"bar\"}),\n        (\"/unrelated\", 422, foo_is_missing),\n    ],\n)\ndef test_get(path, expected_status, expected_response):\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_multiple_path():\n    app = FastAPI()\n\n    @app.get(\"/test1\")\n    @app.get(\"/test2\")\n    async def test(var: Annotated[str, Query()] = \"bar\"):\n        return {\"foo\": var}\n\n    client = TestClient(app)\n    response = client.get(\"/test1\")\n    assert response.status_code == 200\n    assert response.json() == {\"foo\": \"bar\"}\n\n    response = client.get(\"/test1\", params={\"var\": \"baz\"})\n    assert response.status_code == 200\n    assert response.json() == {\"foo\": \"baz\"}\n\n    response = client.get(\"/test2\")\n    assert response.status_code == 200\n    assert response.json() == {\"foo\": \"bar\"}\n\n    response = client.get(\"/test2\", params={\"var\": \"baz\"})\n    assert response.status_code == 200\n    assert response.json() == {\"foo\": \"baz\"}\n\n\ndef test_nested_router():\n    app = FastAPI()\n\n    router = APIRouter(prefix=\"/nested\")\n\n    @router.get(\"/test\")\n    async def test(var: Annotated[str, Query()] = \"bar\"):\n        return {\"foo\": var}\n\n    app.include_router(router)\n\n    client = TestClient(app)\n\n    response = client.get(\"/nested/test\")\n    assert response.status_code == 200\n    assert response.json() == {\"foo\": \"bar\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/default\": {\n                    \"get\": {\n                        \"summary\": \"Default\",\n                        \"operationId\": \"default_default_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Foo\",\n                                    \"type\": \"string\",\n                                    \"default\": \"foo\",\n                                },\n                                \"name\": \"foo\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/required\": {\n                    \"get\": {\n                        \"summary\": \"Required\",\n                        \"operationId\": \"required_required_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Foo\",\n                                    \"minLength\": 1,\n                                    \"type\": \"string\",\n                                },\n                                \"name\": \"foo\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/multiple\": {\n                    \"get\": {\n                        \"summary\": \"Multiple\",\n                        \"operationId\": \"multiple_multiple_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Foo\",\n                                    \"minLength\": 1,\n                                    \"type\": \"string\",\n                                },\n                                \"name\": \"foo\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/unrelated\": {\n                    \"get\": {\n                        \"summary\": \"Unrelated\",\n                        \"operationId\": \"unrelated_unrelated_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Foo\", \"type\": \"string\"},\n                                \"name\": \"foo\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_application.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom .main import app\n\nclient = TestClient(app)\n\n\n@pytest.mark.parametrize(\n    \"path,expected_status,expected_response\",\n    [\n        (\"/api_route\", 200, {\"message\": \"Hello World\"}),\n        (\"/non_decorated_route\", 200, {\"message\": \"Hello World\"}),\n        (\"/nonexistent\", 404, {\"detail\": \"Not Found\"}),\n    ],\n)\ndef test_get_path(path, expected_status, expected_response):\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_swagger_ui():\n    response = client.get(\"/docs\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"text/html; charset=utf-8\"\n    assert \"swagger-ui-dist\" in response.text\n    assert (\n        \"oauth2RedirectUrl: window.location.origin + '/docs/oauth2-redirect'\"\n        in response.text\n    )\n\n\ndef test_swagger_ui_oauth2_redirect():\n    response = client.get(\"/docs/oauth2-redirect\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"text/html; charset=utf-8\"\n    assert \"window.opener.swaggerUIRedirectOauth2\" in response.text\n\n\ndef test_redoc():\n    response = client.get(\"/redoc\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"text/html; charset=utf-8\"\n    assert \"redoc@2\" in response.text\n\n\ndef test_enum_status_code_response():\n    response = client.get(\"/enum-status-code\")\n    assert response.status_code == 201, response.text\n    assert response.json() == \"foo bar\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"externalDocs\": {\n                \"description\": \"External API documentation.\",\n                \"url\": \"https://docs.example.com/api-general\",\n            },\n            \"paths\": {\n                \"/api_route\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Non Operation\",\n                        \"operationId\": \"non_operation_api_route_get\",\n                    }\n                },\n                \"/non_decorated_route\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Non Decorated Route\",\n                        \"operationId\": \"non_decorated_route_non_decorated_route_get\",\n                    }\n                },\n                \"/text\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Get Text\",\n                        \"operationId\": \"get_text_text_get\",\n                    }\n                },\n                \"/path/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Id\",\n                        \"operationId\": \"get_id_path__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/str/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Str Id\",\n                        \"operationId\": \"get_str_id_path_str__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/int/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Int Id\",\n                        \"operationId\": \"get_int_id_path_int__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"integer\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/float/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Float Id\",\n                        \"operationId\": \"get_float_id_path_float__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"number\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/bool/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Bool Id\",\n                        \"operationId\": \"get_bool_id_path_bool__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"boolean\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Id\",\n                        \"operationId\": \"get_path_param_id_path_param__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Item Id\",\n                                },\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-minlength/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Min Length\",\n                        \"operationId\": \"get_path_param_min_length_path_param_minlength__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"minLength\": 3,\n                                    \"type\": \"string\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-maxlength/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Max Length\",\n                        \"operationId\": \"get_path_param_max_length_path_param_maxlength__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"maxLength\": 3,\n                                    \"type\": \"string\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-min_maxlength/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Min Max Length\",\n                        \"operationId\": \"get_path_param_min_max_length_path_param_min_maxlength__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"maxLength\": 3,\n                                    \"minLength\": 2,\n                                    \"type\": \"string\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-gt/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Gt\",\n                        \"operationId\": \"get_path_param_gt_path_param_gt__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"exclusiveMinimum\": 3.0,\n                                    \"type\": \"number\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-gt0/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Gt0\",\n                        \"operationId\": \"get_path_param_gt0_path_param_gt0__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"exclusiveMinimum\": 0.0,\n                                    \"type\": \"number\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-ge/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Ge\",\n                        \"operationId\": \"get_path_param_ge_path_param_ge__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"minimum\": 3.0,\n                                    \"type\": \"number\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-lt/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Lt\",\n                        \"operationId\": \"get_path_param_lt_path_param_lt__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"exclusiveMaximum\": 3.0,\n                                    \"type\": \"number\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-lt0/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Lt0\",\n                        \"operationId\": \"get_path_param_lt0_path_param_lt0__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"exclusiveMaximum\": 0.0,\n                                    \"type\": \"number\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-le/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Le\",\n                        \"operationId\": \"get_path_param_le_path_param_le__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"maximum\": 3.0,\n                                    \"type\": \"number\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-lt-gt/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Lt Gt\",\n                        \"operationId\": \"get_path_param_lt_gt_path_param_lt_gt__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"exclusiveMaximum\": 3.0,\n                                    \"exclusiveMinimum\": 1.0,\n                                    \"type\": \"number\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-le-ge/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Le Ge\",\n                        \"operationId\": \"get_path_param_le_ge_path_param_le_ge__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"maximum\": 3.0,\n                                    \"minimum\": 1.0,\n                                    \"type\": \"number\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-lt-int/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Lt Int\",\n                        \"operationId\": \"get_path_param_lt_int_path_param_lt_int__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"exclusiveMaximum\": 3.0,\n                                    \"type\": \"integer\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-gt-int/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Gt Int\",\n                        \"operationId\": \"get_path_param_gt_int_path_param_gt_int__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"exclusiveMinimum\": 3.0,\n                                    \"type\": \"integer\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-le-int/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Le Int\",\n                        \"operationId\": \"get_path_param_le_int_path_param_le_int__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"maximum\": 3.0,\n                                    \"type\": \"integer\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-ge-int/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Ge Int\",\n                        \"operationId\": \"get_path_param_ge_int_path_param_ge_int__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"minimum\": 3.0,\n                                    \"type\": \"integer\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-lt-gt-int/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Lt Gt Int\",\n                        \"operationId\": \"get_path_param_lt_gt_int_path_param_lt_gt_int__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"exclusiveMaximum\": 3.0,\n                                    \"exclusiveMinimum\": 1.0,\n                                    \"type\": \"integer\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/path/param-le-ge-int/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Path Param Le Ge Int\",\n                        \"operationId\": \"get_path_param_le_ge_int_path_param_le_ge_int__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"maximum\": 3.0,\n                                    \"minimum\": 1.0,\n                                    \"type\": \"integer\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/query\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Query\",\n                        \"operationId\": \"get_query_query_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Query\"},\n                                \"name\": \"query\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                },\n                \"/query/optional\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Query Optional\",\n                        \"operationId\": \"get_query_optional_query_optional_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\"title\": \"Query\"},\n                                \"name\": \"query\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                },\n                \"/query/int\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Query Type\",\n                        \"operationId\": \"get_query_type_query_int_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Query\", \"type\": \"integer\"},\n                                \"name\": \"query\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                },\n                \"/query/int/optional\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Query Type Optional\",\n                        \"operationId\": \"get_query_type_optional_query_int_optional_get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"query\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Query\",\n                                },\n                            }\n                        ],\n                    }\n                },\n                \"/query/int/default\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Query Type Int Default\",\n                        \"operationId\": \"get_query_type_int_default_query_int_default_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Query\",\n                                    \"type\": \"integer\",\n                                    \"default\": 10,\n                                },\n                                \"name\": \"query\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                },\n                \"/query/param\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Query Param\",\n                        \"operationId\": \"get_query_param_query_param_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\"title\": \"Query\"},\n                                \"name\": \"query\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                },\n                \"/query/param-required\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Query Param Required\",\n                        \"operationId\": \"get_query_param_required_query_param_required_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Query\"},\n                                \"name\": \"query\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                },\n                \"/query/param-required/int\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Query Param Required Type\",\n                        \"operationId\": \"get_query_param_required_type_query_param_required_int_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Query\", \"type\": \"integer\"},\n                                \"name\": \"query\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                },\n                \"/enum-status-code\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"201\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                        },\n                        \"summary\": \"Get Enum Status Code\",\n                        \"operationId\": \"get_enum_status_code_enum_status_code_get\",\n                    }\n                },\n                \"/query/frozenset\": {\n                    \"get\": {\n                        \"summary\": \"Get Query Type Frozenset\",\n                        \"operationId\": \"get_query_type_frozenset_query_frozenset_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Query\",\n                                    \"uniqueItems\": True,\n                                    \"type\": \"array\",\n                                    \"items\": {\"type\": \"integer\"},\n                                },\n                                \"name\": \"query\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/query/list\": {\n                    \"get\": {\n                        \"summary\": \"Get Query List\",\n                        \"operationId\": \"get_query_list_query_list_get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"device_ids\",\n                                \"in\": \"query\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\"type\": \"integer\"},\n                                    \"title\": \"Device Ids\",\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"type\": \"array\",\n                                            \"items\": {\"type\": \"integer\"},\n                                            \"title\": \"Response Get Query List Query List Get\",\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/query/list-default\": {\n                    \"get\": {\n                        \"summary\": \"Get Query List Default\",\n                        \"operationId\": \"get_query_list_default_query_list_default_get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"device_ids\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\"type\": \"integer\"},\n                                    \"default\": [],\n                                    \"title\": \"Device Ids\",\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"type\": \"array\",\n                                            \"items\": {\"type\": \"integer\"},\n                                            \"title\": \"Response Get Query List Default Query List Default Get\",\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_arbitrary_types.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(name=\"client\")\ndef get_client():\n    from pydantic import (\n        BaseModel,\n        ConfigDict,\n        PlainSerializer,\n        TypeAdapter,\n        WithJsonSchema,\n    )\n\n    class FakeNumpyArray:\n        def __init__(self):\n            self.data = [1.0, 2.0, 3.0]\n\n    FakeNumpyArrayPydantic = Annotated[\n        FakeNumpyArray,\n        WithJsonSchema(TypeAdapter(list[float]).json_schema()),\n        PlainSerializer(lambda v: v.data),\n    ]\n\n    class MyModel(BaseModel):\n        model_config = ConfigDict(arbitrary_types_allowed=True)\n        custom_field: FakeNumpyArrayPydantic\n\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def test() -> MyModel:\n        return MyModel(custom_field=FakeNumpyArray())\n\n    client = TestClient(app)\n    return client\n\n\ndef test_get(client: TestClient):\n    response = client.get(\"/\")\n    assert response.json() == {\"custom_field\": [1.0, 2.0, 3.0]}\n\n\ndef test_typeadapter():\n    # This test is only to confirm that Pydantic alone is working as expected\n    from pydantic import (\n        BaseModel,\n        ConfigDict,\n        PlainSerializer,\n        TypeAdapter,\n        WithJsonSchema,\n    )\n\n    class FakeNumpyArray:\n        def __init__(self):\n            self.data = [1.0, 2.0, 3.0]\n\n    FakeNumpyArrayPydantic = Annotated[\n        FakeNumpyArray,\n        WithJsonSchema(TypeAdapter(list[float]).json_schema()),\n        PlainSerializer(lambda v: v.data),\n    ]\n\n    class MyModel(BaseModel):\n        model_config = ConfigDict(arbitrary_types_allowed=True)\n        custom_field: FakeNumpyArrayPydantic\n\n    ta = TypeAdapter(MyModel)\n    assert ta.dump_python(MyModel(custom_field=FakeNumpyArray())) == {\n        \"custom_field\": [1.0, 2.0, 3.0]\n    }\n    assert ta.json_schema() == snapshot(\n        {\n            \"properties\": {\n                \"custom_field\": {\n                    \"items\": {\"type\": \"number\"},\n                    \"title\": \"Custom Field\",\n                    \"type\": \"array\",\n                }\n            },\n            \"required\": [\"custom_field\"],\n            \"title\": \"MyModel\",\n            \"type\": \"object\",\n        }\n    )\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Test\",\n                        \"operationId\": \"test__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/MyModel\"\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"MyModel\": {\n                        \"properties\": {\n                            \"custom_field\": {\n                                \"items\": {\"type\": \"number\"},\n                                \"type\": \"array\",\n                                \"title\": \"Custom Field\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"custom_field\"],\n                        \"title\": \"MyModel\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_callable_endpoint.py",
    "content": "from functools import partial\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\n\ndef main(some_arg, q: str | None = None):\n    return {\"some_arg\": some_arg, \"q\": q}\n\n\nendpoint = partial(main, \"foo\")\n\napp = FastAPI()\n\napp.get(\"/\")(endpoint)\n\n\nclient = TestClient(app)\n\n\ndef test_partial():\n    response = client.get(\"/?q=bar\")\n    data = response.json()\n    assert data == {\"some_arg\": \"foo\", \"q\": \"bar\"}\n"
  },
  {
    "path": "tests/test_compat.py",
    "content": "from fastapi import FastAPI, UploadFile\nfrom fastapi._compat import (\n    Undefined,\n    is_uploadfile_sequence_annotation,\n)\nfrom fastapi._compat.shared import is_bytes_sequence_annotation\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, ConfigDict\nfrom pydantic.fields import FieldInfo\n\n\ndef test_model_field_default_required():\n    from fastapi._compat import v2\n\n    # For coverage\n    field_info = FieldInfo(annotation=str)\n    field = v2.ModelField(name=\"foo\", field_info=field_info)\n    assert field.default is Undefined\n\n\ndef test_complex():\n    app = FastAPI()\n\n    @app.post(\"/\")\n    def foo(foo: str | list[int]):\n        return foo\n\n    client = TestClient(app)\n\n    response = client.post(\"/\", json=\"bar\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"bar\"\n\n    response2 = client.post(\"/\", json=[1, 2])\n    assert response2.status_code == 200, response2.text\n    assert response2.json() == [1, 2]\n\n\ndef test_propagates_pydantic2_model_config():\n    app = FastAPI()\n\n    class Missing:\n        def __bool__(self):\n            return False\n\n    class EmbeddedModel(BaseModel):\n        model_config = ConfigDict(arbitrary_types_allowed=True)\n        value: str | Missing = Missing()\n\n    class Model(BaseModel):\n        model_config = ConfigDict(\n            arbitrary_types_allowed=True,\n        )\n        value: str | Missing = Missing()\n        embedded_model: EmbeddedModel = EmbeddedModel()\n\n    @app.post(\"/\")\n    def foo(req: Model) -> dict[str, str | None]:\n        return {\n            \"value\": req.value or None,\n            \"embedded_value\": req.embedded_model.value or None,\n        }\n\n    client = TestClient(app)\n\n    response = client.post(\"/\", json={})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"value\": None,\n        \"embedded_value\": None,\n    }\n\n    response2 = client.post(\n        \"/\", json={\"value\": \"foo\", \"embedded_model\": {\"value\": \"bar\"}}\n    )\n    assert response2.status_code == 200, response2.text\n    assert response2.json() == {\n        \"value\": \"foo\",\n        \"embedded_value\": \"bar\",\n    }\n\n\ndef test_is_bytes_sequence_annotation_union():\n    # For coverage\n    # TODO: in theory this would allow declaring types that could be lists of bytes\n    # to be read from files and other types, but I'm not even sure it's a good idea\n    # to support it as a first class \"feature\"\n    assert is_bytes_sequence_annotation(list[str] | list[bytes])\n\n\ndef test_is_uploadfile_sequence_annotation():\n    # For coverage\n    # TODO: in theory this would allow declaring types that could be lists of UploadFile\n    # and other types, but I'm not even sure it's a good idea to support it as a first\n    # class \"feature\"\n    assert is_uploadfile_sequence_annotation(list[str] | list[UploadFile])\n\n\ndef test_serialize_sequence_value_with_optional_list():\n    \"\"\"Test that serialize_sequence_value handles optional lists correctly.\"\"\"\n    from fastapi._compat import v2\n\n    field_info = FieldInfo(annotation=list[str] | None)\n    field = v2.ModelField(name=\"items\", field_info=field_info)\n    result = v2.serialize_sequence_value(field=field, value=[\"a\", \"b\", \"c\"])\n    assert result == [\"a\", \"b\", \"c\"]\n    assert isinstance(result, list)\n\n\ndef test_serialize_sequence_value_with_optional_list_pipe_union():\n    \"\"\"Test that serialize_sequence_value handles optional lists correctly (with new syntax).\"\"\"\n    from fastapi._compat import v2\n\n    field_info = FieldInfo(annotation=list[str] | None)\n    field = v2.ModelField(name=\"items\", field_info=field_info)\n    result = v2.serialize_sequence_value(field=field, value=[\"a\", \"b\", \"c\"])\n    assert result == [\"a\", \"b\", \"c\"]\n    assert isinstance(result, list)\n\n\ndef test_serialize_sequence_value_with_none_first_in_union():\n    \"\"\"Test that serialize_sequence_value handles Union[None, List[...]] correctly.\"\"\"\n    from typing import Union\n\n    from fastapi._compat import v2\n\n    # Use Union[None, list[str]] to ensure None comes first in the union args\n    field_info = FieldInfo(annotation=Union[None, list[str]])  # noqa: UP007\n    field = v2.ModelField(name=\"items\", field_info=field_info)\n    result = v2.serialize_sequence_value(field=field, value=[\"x\", \"y\"])\n    assert result == [\"x\", \"y\"]\n    assert isinstance(result, list)\n"
  },
  {
    "path": "tests/test_computed_fields.py",
    "content": "import pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(request):\n    separate_input_output_schemas = request.param\n    app = FastAPI(separate_input_output_schemas=separate_input_output_schemas)\n\n    from pydantic import BaseModel, computed_field\n\n    class Rectangle(BaseModel):\n        width: int\n        length: int\n\n        @computed_field\n        @property\n        def area(self) -> int:\n            return self.width * self.length\n\n    @app.get(\"/\")\n    def read_root() -> Rectangle:\n        return Rectangle(width=3, length=4)\n\n    @app.get(\"/responses\", responses={200: {\"model\": Rectangle}})\n    def read_responses() -> Rectangle:\n        return Rectangle(width=3, length=4)\n\n    client = TestClient(app)\n    return client\n\n\n@pytest.mark.parametrize(\"client\", [True, False], indirect=True)\n@pytest.mark.parametrize(\"path\", [\"/\", \"/responses\"])\ndef test_get(client: TestClient, path: str):\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"width\": 3, \"length\": 4, \"area\": 12}\n\n\n@pytest.mark.parametrize(\"client\", [True, False], indirect=True)\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Read Root\",\n                        \"operationId\": \"read_root__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Rectangle\"\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/responses\": {\n                    \"get\": {\n                        \"summary\": \"Read Responses\",\n                        \"operationId\": \"read_responses_responses_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Rectangle\"\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Rectangle\": {\n                        \"properties\": {\n                            \"width\": {\"type\": \"integer\", \"title\": \"Width\"},\n                            \"length\": {\"type\": \"integer\", \"title\": \"Length\"},\n                            \"area\": {\n                                \"type\": \"integer\",\n                                \"title\": \"Area\",\n                                \"readOnly\": True,\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"width\", \"length\", \"area\"],\n                        \"title\": \"Rectangle\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_custom_middleware_exception.py",
    "content": "from pathlib import Path\n\nfrom fastapi import APIRouter, FastAPI, File, UploadFile\nfrom fastapi.exceptions import HTTPException\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\nrouter = APIRouter()\n\n\nclass ContentSizeLimitMiddleware:\n    \"\"\"Content size limiting middleware for ASGI applications\n    Args:\n      app (ASGI application): ASGI application\n      max_content_size (optional): the maximum content size allowed in bytes, None for no limit\n    \"\"\"\n\n    def __init__(self, app: APIRouter, max_content_size: int | None = None):\n        self.app = app\n        self.max_content_size = max_content_size\n\n    def receive_wrapper(self, receive):\n        received = 0\n\n        async def inner():\n            nonlocal received\n            message = await receive()\n            if message[\"type\"] != \"http.request\":\n                return message  # pragma: no cover\n\n            body_len = len(message.get(\"body\", b\"\"))\n            received += body_len\n            if received > self.max_content_size:\n                raise HTTPException(\n                    422,\n                    detail={\n                        \"name\": \"ContentSizeLimitExceeded\",\n                        \"code\": 999,\n                        \"message\": \"File limit exceeded\",\n                    },\n                )\n            return message\n\n        return inner\n\n    async def __call__(self, scope, receive, send):\n        if scope[\"type\"] != \"http\" or self.max_content_size is None:\n            await self.app(scope, receive, send)\n            return\n\n        wrapper = self.receive_wrapper(receive)\n        await self.app(scope, wrapper, send)\n\n\n@router.post(\"/middleware\")\ndef run_middleware(file: UploadFile = File(..., description=\"Big File\")):\n    return {\"message\": \"OK\"}\n\n\napp.include_router(router)\napp.add_middleware(ContentSizeLimitMiddleware, max_content_size=2**8)\n\n\nclient = TestClient(app)\n\n\ndef test_custom_middleware_exception(tmp_path: Path):\n    default_pydantic_max_size = 2**16\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"x\" * (default_pydantic_max_size + 1))\n\n    with client:\n        with open(path, \"rb\") as file:\n            response = client.post(\"/middleware\", files={\"file\": file})\n        assert response.status_code == 422, response.text\n        assert response.json() == {\n            \"detail\": {\n                \"name\": \"ContentSizeLimitExceeded\",\n                \"code\": 999,\n                \"message\": \"File limit exceeded\",\n            }\n        }\n\n\ndef test_custom_middleware_exception_not_raised(tmp_path: Path):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n\n    with client:\n        with open(path, \"rb\") as file:\n            response = client.post(\"/middleware\", files={\"file\": file})\n        assert response.status_code == 200, response.text\n        assert response.json() == {\"message\": \"OK\"}\n"
  },
  {
    "path": "tests/test_custom_route_class.py",
    "content": "import pytest\nfrom fastapi import APIRouter, FastAPI\nfrom fastapi.routing import APIRoute\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom starlette.routing import Route\n\napp = FastAPI()\n\n\nclass APIRouteA(APIRoute):\n    x_type = \"A\"\n\n\nclass APIRouteB(APIRoute):\n    x_type = \"B\"\n\n\nclass APIRouteC(APIRoute):\n    x_type = \"C\"\n\n\nrouter_a = APIRouter(route_class=APIRouteA)\nrouter_b = APIRouter(route_class=APIRouteB)\nrouter_c = APIRouter(route_class=APIRouteC)\n\n\n@router_a.get(\"/\")\ndef get_a():\n    return {\"msg\": \"A\"}\n\n\n@router_b.get(\"/\")\ndef get_b():\n    return {\"msg\": \"B\"}\n\n\n@router_c.get(\"/\")\ndef get_c():\n    return {\"msg\": \"C\"}\n\n\nrouter_b.include_router(router=router_c, prefix=\"/c\")\nrouter_a.include_router(router=router_b, prefix=\"/b\")\napp.include_router(router=router_a, prefix=\"/a\")\n\n\nclient = TestClient(app)\n\n\n@pytest.mark.parametrize(\n    \"path,expected_status,expected_response\",\n    [\n        (\"/a\", 200, {\"msg\": \"A\"}),\n        (\"/a/b\", 200, {\"msg\": \"B\"}),\n        (\"/a/b/c\", 200, {\"msg\": \"C\"}),\n    ],\n)\ndef test_get_path(path, expected_status, expected_response):\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_route_classes():\n    routes = {}\n    for r in app.router.routes:\n        assert isinstance(r, Route)\n        routes[r.path] = r\n    assert getattr(routes[\"/a/\"], \"x_type\") == \"A\"  # noqa: B009\n    assert getattr(routes[\"/a/b/\"], \"x_type\") == \"B\"  # noqa: B009\n    assert getattr(routes[\"/a/b/c/\"], \"x_type\") == \"C\"  # noqa: B009\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/a/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Get A\",\n                        \"operationId\": \"get_a_a__get\",\n                    }\n                },\n                \"/a/b/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Get B\",\n                        \"operationId\": \"get_b_a_b__get\",\n                    }\n                },\n                \"/a/b/c/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Get C\",\n                        \"operationId\": \"get_c_a_b_c__get\",\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_custom_schema_fields.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, WithJsonSchema\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n\n    description: Annotated[str | None, WithJsonSchema({\"type\": [\"string\", \"null\"]})] = (\n        None\n    )\n\n    model_config = {\n        \"json_schema_extra\": {\n            \"x-something-internal\": {\"level\": 4},\n        }\n    }\n\n\n@app.get(\"/foo\", response_model=Item)\ndef foo():\n    return {\"name\": \"Foo item\"}\n\n\nclient = TestClient(app)\n\n\nitem_schema = {\n    \"title\": \"Item\",\n    \"required\": [\"name\"],\n    \"type\": \"object\",\n    \"x-something-internal\": {\n        \"level\": 4,\n    },\n    \"properties\": {\n        \"name\": {\n            \"title\": \"Name\",\n            \"type\": \"string\",\n        },\n        \"description\": {\n            \"title\": \"Description\",\n            \"type\": [\"string\", \"null\"],\n        },\n    },\n}\n\n\ndef test_custom_response_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json()[\"components\"][\"schemas\"][\"Item\"] == item_schema\n\n\ndef test_response():\n    # For coverage\n    response = client.get(\"/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo item\", \"description\": None}\n"
  },
  {
    "path": "tests/test_custom_swagger_ui_redirect.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\nswagger_ui_oauth2_redirect_url = \"/docs/redirect\"\n\napp = FastAPI(swagger_ui_oauth2_redirect_url=swagger_ui_oauth2_redirect_url)\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return {\"id\": \"foo\"}\n\n\nclient = TestClient(app)\n\n\ndef test_swagger_ui():\n    response = client.get(\"/docs\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"text/html; charset=utf-8\"\n    assert \"swagger-ui-dist\" in response.text\n    print(client.base_url)\n    assert (\n        f\"oauth2RedirectUrl: window.location.origin + '{swagger_ui_oauth2_redirect_url}'\"\n        in response.text\n    )\n\n\ndef test_swagger_ui_oauth2_redirect():\n    response = client.get(swagger_ui_oauth2_redirect_url)\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"text/html; charset=utf-8\"\n    assert \"window.opener.swaggerUIRedirectOauth2\" in response.text\n\n\ndef test_response():\n    response = client.get(\"/items/\")\n    assert response.json() == {\"id\": \"foo\"}\n"
  },
  {
    "path": "tests/test_datastructures.py",
    "content": "import io\nfrom pathlib import Path\n\nimport pytest\nfrom fastapi import FastAPI, UploadFile\nfrom fastapi.datastructures import Default\nfrom fastapi.testclient import TestClient\n\n\ndef test_upload_file_invalid_pydantic_v2():\n    with pytest.raises(ValueError):\n        UploadFile._validate(\"not a Starlette UploadFile\", {})\n\n\ndef test_default_placeholder_equals():\n    placeholder_1 = Default(\"a\")\n    placeholder_2 = Default(\"a\")\n    assert placeholder_1 == placeholder_2\n    assert placeholder_1.value == placeholder_2.value\n\n\ndef test_default_placeholder_bool():\n    placeholder_a = Default(\"a\")\n    placeholder_b = Default(\"\")\n    assert placeholder_a\n    assert not placeholder_b\n\n\ndef test_upload_file_is_closed(tmp_path: Path):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n    app = FastAPI()\n\n    testing_file_store: list[UploadFile] = []\n\n    @app.post(\"/uploadfile/\")\n    def create_upload_file(file: UploadFile):\n        testing_file_store.append(file)\n        return {\"filename\": file.filename}\n\n    client = TestClient(app)\n    with path.open(\"rb\") as file:\n        response = client.post(\"/uploadfile/\", files={\"file\": file})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"filename\": \"test.txt\"}\n\n    assert testing_file_store\n    assert testing_file_store[0].file.closed\n\n\n# For UploadFile coverage, segments copied from Starlette tests\n\n\n@pytest.mark.anyio\nasync def test_upload_file():\n    stream = io.BytesIO(b\"data\")\n    file = UploadFile(filename=\"file\", file=stream, size=4)\n    assert await file.read() == b\"data\"\n    assert file.size == 4\n    await file.write(b\" and more data!\")\n    assert await file.read() == b\"\"\n    assert file.size == 19\n    await file.seek(0)\n    assert await file.read() == b\"data and more data!\"\n    await file.close()\n"
  },
  {
    "path": "tests/test_datetime_custom_encoder.py",
    "content": "from datetime import datetime, timezone\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\n\ndef test_pydanticv2():\n    from pydantic import field_serializer\n\n    class ModelWithDatetimeField(BaseModel):\n        dt_field: datetime\n\n        @field_serializer(\"dt_field\")\n        def serialize_datetime(self, dt_field: datetime):\n            return dt_field.replace(microsecond=0, tzinfo=timezone.utc).isoformat()\n\n    app = FastAPI()\n    model = ModelWithDatetimeField(dt_field=datetime(2019, 1, 1, 8))\n\n    @app.get(\"/model\", response_model=ModelWithDatetimeField)\n    def get_model():\n        return model\n\n    client = TestClient(app)\n    with client:\n        response = client.get(\"/model\")\n    assert response.json() == {\"dt_field\": \"2019-01-01T08:00:00+00:00\"}\n"
  },
  {
    "path": "tests/test_default_response_class.py",
    "content": "from typing import Any\n\nfrom fastapi import APIRouter, FastAPI\nfrom fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse\nfrom fastapi.testclient import TestClient\n\nfrom tests.utils import needs_orjson\n\n\nclass ORJSONResponse(JSONResponse):\n    media_type = \"application/x-orjson\"\n\n    def render(self, content: Any) -> bytes:\n        import orjson\n\n        return orjson.dumps(content)\n\n\nclass OverrideResponse(JSONResponse):\n    media_type = \"application/x-override\"\n\n\napp = FastAPI(default_response_class=ORJSONResponse)\nrouter_a = APIRouter()\nrouter_a_a = APIRouter()\nrouter_a_b_override = APIRouter()  # Overrides default class\nrouter_b_override = APIRouter()  # Overrides default class\nrouter_b_a = APIRouter()\nrouter_b_a_c_override = APIRouter()  # Overrides default class again\n\n\n@app.get(\"/\")\ndef get_root():\n    return {\"msg\": \"Hello World\"}\n\n\n@app.get(\"/override\", response_class=PlainTextResponse)\ndef get_path_override():\n    return \"Hello World\"\n\n\n@router_a.get(\"/\")\ndef get_a():\n    return {\"msg\": \"Hello A\"}\n\n\n@router_a.get(\"/override\", response_class=PlainTextResponse)\ndef get_a_path_override():\n    return \"Hello A\"\n\n\n@router_a_a.get(\"/\")\ndef get_a_a():\n    return {\"msg\": \"Hello A A\"}\n\n\n@router_a_a.get(\"/override\", response_class=PlainTextResponse)\ndef get_a_a_path_override():\n    return \"Hello A A\"\n\n\n@router_a_b_override.get(\"/\")\ndef get_a_b():\n    return \"Hello A B\"\n\n\n@router_a_b_override.get(\"/override\", response_class=HTMLResponse)\ndef get_a_b_path_override():\n    return \"Hello A B\"\n\n\n@router_b_override.get(\"/\")\ndef get_b():\n    return \"Hello B\"\n\n\n@router_b_override.get(\"/override\", response_class=HTMLResponse)\ndef get_b_path_override():\n    return \"Hello B\"\n\n\n@router_b_a.get(\"/\")\ndef get_b_a():\n    return \"Hello B A\"\n\n\n@router_b_a.get(\"/override\", response_class=HTMLResponse)\ndef get_b_a_path_override():\n    return \"Hello B A\"\n\n\n@router_b_a_c_override.get(\"/\")\ndef get_b_a_c():\n    return \"Hello B A C\"\n\n\n@router_b_a_c_override.get(\"/override\", response_class=OverrideResponse)\ndef get_b_a_c_path_override():\n    return {\"msg\": \"Hello B A C\"}\n\n\nrouter_b_a.include_router(\n    router_b_a_c_override, prefix=\"/c\", default_response_class=HTMLResponse\n)\nrouter_b_override.include_router(router_b_a, prefix=\"/a\")\nrouter_a.include_router(router_a_a, prefix=\"/a\")\nrouter_a.include_router(\n    router_a_b_override, prefix=\"/b\", default_response_class=PlainTextResponse\n)\napp.include_router(router_a, prefix=\"/a\")\napp.include_router(\n    router_b_override, prefix=\"/b\", default_response_class=PlainTextResponse\n)\n\n\nclient = TestClient(app)\n\norjson_type = \"application/x-orjson\"\ntext_type = \"text/plain; charset=utf-8\"\nhtml_type = \"text/html; charset=utf-8\"\noverride_type = \"application/x-override\"\n\n\n@needs_orjson\ndef test_app():\n    with client:\n        response = client.get(\"/\")\n    assert response.json() == {\"msg\": \"Hello World\"}\n    assert response.headers[\"content-type\"] == orjson_type\n\n\ndef test_app_override():\n    with client:\n        response = client.get(\"/override\")\n    assert response.content == b\"Hello World\"\n    assert response.headers[\"content-type\"] == text_type\n\n\n@needs_orjson\ndef test_router_a():\n    with client:\n        response = client.get(\"/a\")\n    assert response.json() == {\"msg\": \"Hello A\"}\n    assert response.headers[\"content-type\"] == orjson_type\n\n\ndef test_router_a_override():\n    with client:\n        response = client.get(\"/a/override\")\n    assert response.content == b\"Hello A\"\n    assert response.headers[\"content-type\"] == text_type\n\n\n@needs_orjson\ndef test_router_a_a():\n    with client:\n        response = client.get(\"/a/a\")\n    assert response.json() == {\"msg\": \"Hello A A\"}\n    assert response.headers[\"content-type\"] == orjson_type\n\n\ndef test_router_a_a_override():\n    with client:\n        response = client.get(\"/a/a/override\")\n    assert response.content == b\"Hello A A\"\n    assert response.headers[\"content-type\"] == text_type\n\n\ndef test_router_a_b():\n    with client:\n        response = client.get(\"/a/b\")\n    assert response.content == b\"Hello A B\"\n    assert response.headers[\"content-type\"] == text_type\n\n\ndef test_router_a_b_override():\n    with client:\n        response = client.get(\"/a/b/override\")\n    assert response.content == b\"Hello A B\"\n    assert response.headers[\"content-type\"] == html_type\n\n\ndef test_router_b():\n    with client:\n        response = client.get(\"/b\")\n    assert response.content == b\"Hello B\"\n    assert response.headers[\"content-type\"] == text_type\n\n\ndef test_router_b_override():\n    with client:\n        response = client.get(\"/b/override\")\n    assert response.content == b\"Hello B\"\n    assert response.headers[\"content-type\"] == html_type\n\n\ndef test_router_b_a():\n    with client:\n        response = client.get(\"/b/a\")\n    assert response.content == b\"Hello B A\"\n    assert response.headers[\"content-type\"] == text_type\n\n\ndef test_router_b_a_override():\n    with client:\n        response = client.get(\"/b/a/override\")\n    assert response.content == b\"Hello B A\"\n    assert response.headers[\"content-type\"] == html_type\n\n\ndef test_router_b_a_c():\n    with client:\n        response = client.get(\"/b/a/c\")\n    assert response.content == b\"Hello B A C\"\n    assert response.headers[\"content-type\"] == html_type\n\n\ndef test_router_b_a_c_override():\n    with client:\n        response = client.get(\"/b/a/c/override\")\n    assert response.json() == {\"msg\": \"Hello B A C\"}\n    assert response.headers[\"content-type\"] == override_type\n"
  },
  {
    "path": "tests/test_default_response_class_router.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse\nfrom fastapi.testclient import TestClient\n\n\nclass OverrideResponse(JSONResponse):\n    media_type = \"application/x-override\"\n\n\napp = FastAPI()\nrouter_a = APIRouter()\nrouter_a_a = APIRouter()\nrouter_a_b_override = APIRouter()  # Overrides default class\nrouter_b_override = APIRouter()  # Overrides default class\nrouter_b_a = APIRouter()\nrouter_b_a_c_override = APIRouter()  # Overrides default class again\n\n\n@app.get(\"/\")\ndef get_root():\n    return {\"msg\": \"Hello World\"}\n\n\n@app.get(\"/override\", response_class=PlainTextResponse)\ndef get_path_override():\n    return \"Hello World\"\n\n\n@router_a.get(\"/\")\ndef get_a():\n    return {\"msg\": \"Hello A\"}\n\n\n@router_a.get(\"/override\", response_class=PlainTextResponse)\ndef get_a_path_override():\n    return \"Hello A\"\n\n\n@router_a_a.get(\"/\")\ndef get_a_a():\n    return {\"msg\": \"Hello A A\"}\n\n\n@router_a_a.get(\"/override\", response_class=PlainTextResponse)\ndef get_a_a_path_override():\n    return \"Hello A A\"\n\n\n@router_a_b_override.get(\"/\")\ndef get_a_b():\n    return \"Hello A B\"\n\n\n@router_a_b_override.get(\"/override\", response_class=HTMLResponse)\ndef get_a_b_path_override():\n    return \"Hello A B\"\n\n\n@router_b_override.get(\"/\")\ndef get_b():\n    return \"Hello B\"\n\n\n@router_b_override.get(\"/override\", response_class=HTMLResponse)\ndef get_b_path_override():\n    return \"Hello B\"\n\n\n@router_b_a.get(\"/\")\ndef get_b_a():\n    return \"Hello B A\"\n\n\n@router_b_a.get(\"/override\", response_class=HTMLResponse)\ndef get_b_a_path_override():\n    return \"Hello B A\"\n\n\n@router_b_a_c_override.get(\"/\")\ndef get_b_a_c():\n    return \"Hello B A C\"\n\n\n@router_b_a_c_override.get(\"/override\", response_class=OverrideResponse)\ndef get_b_a_c_path_override():\n    return {\"msg\": \"Hello B A C\"}\n\n\nrouter_b_a.include_router(\n    router_b_a_c_override, prefix=\"/c\", default_response_class=HTMLResponse\n)\nrouter_b_override.include_router(router_b_a, prefix=\"/a\")\nrouter_a.include_router(router_a_a, prefix=\"/a\")\nrouter_a.include_router(\n    router_a_b_override, prefix=\"/b\", default_response_class=PlainTextResponse\n)\napp.include_router(router_a, prefix=\"/a\")\napp.include_router(\n    router_b_override, prefix=\"/b\", default_response_class=PlainTextResponse\n)\n\n\nclient = TestClient(app)\n\njson_type = \"application/json\"\ntext_type = \"text/plain; charset=utf-8\"\nhtml_type = \"text/html; charset=utf-8\"\noverride_type = \"application/x-override\"\n\n\ndef test_app():\n    with client:\n        response = client.get(\"/\")\n    assert response.json() == {\"msg\": \"Hello World\"}\n    assert response.headers[\"content-type\"] == json_type\n\n\ndef test_app_override():\n    with client:\n        response = client.get(\"/override\")\n    assert response.content == b\"Hello World\"\n    assert response.headers[\"content-type\"] == text_type\n\n\ndef test_router_a():\n    with client:\n        response = client.get(\"/a\")\n    assert response.json() == {\"msg\": \"Hello A\"}\n    assert response.headers[\"content-type\"] == json_type\n\n\ndef test_router_a_override():\n    with client:\n        response = client.get(\"/a/override\")\n    assert response.content == b\"Hello A\"\n    assert response.headers[\"content-type\"] == text_type\n\n\ndef test_router_a_a():\n    with client:\n        response = client.get(\"/a/a\")\n    assert response.json() == {\"msg\": \"Hello A A\"}\n    assert response.headers[\"content-type\"] == json_type\n\n\ndef test_router_a_a_override():\n    with client:\n        response = client.get(\"/a/a/override\")\n    assert response.content == b\"Hello A A\"\n    assert response.headers[\"content-type\"] == text_type\n\n\ndef test_router_a_b():\n    with client:\n        response = client.get(\"/a/b\")\n    assert response.content == b\"Hello A B\"\n    assert response.headers[\"content-type\"] == text_type\n\n\ndef test_router_a_b_override():\n    with client:\n        response = client.get(\"/a/b/override\")\n    assert response.content == b\"Hello A B\"\n    assert response.headers[\"content-type\"] == html_type\n\n\ndef test_router_b():\n    with client:\n        response = client.get(\"/b\")\n    assert response.content == b\"Hello B\"\n    assert response.headers[\"content-type\"] == text_type\n\n\ndef test_router_b_override():\n    with client:\n        response = client.get(\"/b/override\")\n    assert response.content == b\"Hello B\"\n    assert response.headers[\"content-type\"] == html_type\n\n\ndef test_router_b_a():\n    with client:\n        response = client.get(\"/b/a\")\n    assert response.content == b\"Hello B A\"\n    assert response.headers[\"content-type\"] == text_type\n\n\ndef test_router_b_a_override():\n    with client:\n        response = client.get(\"/b/a/override\")\n    assert response.content == b\"Hello B A\"\n    assert response.headers[\"content-type\"] == html_type\n\n\ndef test_router_b_a_c():\n    with client:\n        response = client.get(\"/b/a/c\")\n    assert response.content == b\"Hello B A C\"\n    assert response.headers[\"content-type\"] == html_type\n\n\ndef test_router_b_a_c_override():\n    with client:\n        response = client.get(\"/b/a/c/override\")\n    assert response.json() == {\"msg\": \"Hello B A C\"}\n    assert response.headers[\"content-type\"] == override_type\n"
  },
  {
    "path": "tests/test_dependencies_utils.py",
    "content": "from fastapi.dependencies.utils import get_typed_annotation\n\n\ndef test_get_typed_annotation():\n    # For coverage\n    annotation = \"None\"\n    typed_annotation = get_typed_annotation(annotation, globals())\n    assert typed_annotation is None\n"
  },
  {
    "path": "tests/test_dependency_after_yield_raise.py",
    "content": "from typing import Annotated, Any\n\nimport pytest\nfrom fastapi import Depends, FastAPI, HTTPException\nfrom fastapi.testclient import TestClient\n\n\nclass CustomError(Exception):\n    pass\n\n\ndef catching_dep() -> Any:\n    try:\n        yield \"s\"\n    except CustomError as err:\n        raise HTTPException(status_code=418, detail=\"Session error\") from err\n\n\ndef broken_dep() -> Any:\n    yield \"s\"\n    raise ValueError(\"Broken after yield\")\n\n\napp = FastAPI()\n\n\n@app.get(\"/catching\")\ndef catching(d: Annotated[str, Depends(catching_dep)]) -> Any:\n    raise CustomError(\"Simulated error during streaming\")\n\n\n@app.get(\"/broken\")\ndef broken(d: Annotated[str, Depends(broken_dep)]) -> Any:\n    return {\"message\": \"all good?\"}\n\n\nclient = TestClient(app)\n\n\ndef test_catching():\n    response = client.get(\"/catching\")\n    assert response.status_code == 418\n    assert response.json() == {\"detail\": \"Session error\"}\n\n\ndef test_broken_raise():\n    with pytest.raises(ValueError, match=\"Broken after yield\"):\n        client.get(\"/broken\")\n\n\ndef test_broken_no_raise():\n    \"\"\"\n    When a dependency with yield raises after the yield (not in an except), the\n    response is already \"successfully\" sent back to the client, but there's still\n    an error in the server afterwards, an exception is raised and captured or shown\n    in the server logs.\n    \"\"\"\n    with TestClient(app, raise_server_exceptions=False) as client:\n        response = client.get(\"/broken\")\n        assert response.status_code == 200\n        assert response.json() == {\"message\": \"all good?\"}\n\n\ndef test_broken_return_finishes():\n    client = TestClient(app, raise_server_exceptions=False)\n    response = client.get(\"/broken\")\n    assert response.status_code == 200\n    assert response.json() == {\"message\": \"all good?\"}\n"
  },
  {
    "path": "tests/test_dependency_after_yield_streaming.py",
    "content": "from collections.abc import Generator\nfrom contextlib import contextmanager\nfrom typing import Annotated, Any\n\nimport pytest\nfrom fastapi import Depends, FastAPI\nfrom fastapi.responses import StreamingResponse\nfrom fastapi.testclient import TestClient\n\n\nclass Session:\n    def __init__(self) -> None:\n        self.data = [\"foo\", \"bar\", \"baz\"]\n        self.open = True\n\n    def __iter__(self) -> Generator[str, None, None]:\n        for item in self.data:\n            if self.open:\n                yield item\n            else:\n                raise ValueError(\"Session closed\")\n\n\n@contextmanager\ndef acquire_session() -> Generator[Session, None, None]:\n    session = Session()\n    try:\n        yield session\n    finally:\n        session.open = False\n\n\ndef dep_session() -> Any:\n    with acquire_session() as s:\n        yield s\n\n\ndef broken_dep_session() -> Any:\n    with acquire_session() as s:\n        s.open = False\n        yield s\n\n\nSessionDep = Annotated[Session, Depends(dep_session)]\nBrokenSessionDep = Annotated[Session, Depends(broken_dep_session)]\n\napp = FastAPI()\n\n\n@app.get(\"/data\")\ndef get_data(session: SessionDep) -> Any:\n    data = list(session)\n    return data\n\n\n@app.get(\"/stream-simple\")\ndef get_stream_simple(session: SessionDep) -> Any:\n    def iter_data():\n        yield from [\"x\", \"y\", \"z\"]\n\n    return StreamingResponse(iter_data())\n\n\n@app.get(\"/stream-session\")\ndef get_stream_session(session: SessionDep) -> Any:\n    def iter_data():\n        yield from session\n\n    return StreamingResponse(iter_data())\n\n\n@app.get(\"/broken-session-data\")\ndef get_broken_session_data(session: BrokenSessionDep) -> Any:\n    return list(session)\n\n\n@app.get(\"/broken-session-stream\")\ndef get_broken_session_stream(session: BrokenSessionDep) -> Any:\n    def iter_data():\n        yield from session\n\n    return StreamingResponse(iter_data())\n\n\nclient = TestClient(app)\n\n\ndef test_regular_no_stream():\n    response = client.get(\"/data\")\n    assert response.json() == [\"foo\", \"bar\", \"baz\"]\n\n\ndef test_stream_simple():\n    response = client.get(\"/stream-simple\")\n    assert response.text == \"xyz\"\n\n\ndef test_stream_session():\n    response = client.get(\"/stream-session\")\n    assert response.text == \"foobarbaz\"\n\n\ndef test_broken_session_data():\n    with pytest.raises(ValueError, match=\"Session closed\"):\n        client.get(\"/broken-session-data\")\n\n\ndef test_broken_session_data_no_raise():\n    client = TestClient(app, raise_server_exceptions=False)\n    response = client.get(\"/broken-session-data\")\n    assert response.status_code == 500\n    assert response.text == \"Internal Server Error\"\n\n\ndef test_broken_session_stream_raise():\n    # Can raise ValueError on Pydantic v2 and ExceptionGroup on Pydantic v1\n    with pytest.raises((ValueError, Exception)):\n        client.get(\"/broken-session-stream\")\n\n\ndef test_broken_session_stream_no_raise():\n    \"\"\"\n    When a dependency with yield raises after the streaming response already started\n    the 200 status code is already sent, but there's still an error in the server\n    afterwards, an exception is raised and captured or shown in the server logs.\n    \"\"\"\n    with TestClient(app, raise_server_exceptions=False) as client:\n        response = client.get(\"/broken-session-stream\")\n        assert response.status_code == 200\n        assert response.text == \"\"\n"
  },
  {
    "path": "tests/test_dependency_after_yield_websockets.py",
    "content": "from collections.abc import Generator\nfrom contextlib import contextmanager\nfrom typing import Annotated, Any\n\nimport pytest\nfrom fastapi import Depends, FastAPI, WebSocket\nfrom fastapi.testclient import TestClient\n\n\nclass Session:\n    def __init__(self) -> None:\n        self.data = [\"foo\", \"bar\", \"baz\"]\n        self.open = True\n\n    def __iter__(self) -> Generator[str, None, None]:\n        for item in self.data:\n            if self.open:\n                yield item\n            else:\n                raise ValueError(\"Session closed\")\n\n\n@contextmanager\ndef acquire_session() -> Generator[Session, None, None]:\n    session = Session()\n    try:\n        yield session\n    finally:\n        session.open = False\n\n\ndef dep_session() -> Any:\n    with acquire_session() as s:\n        yield s\n\n\ndef broken_dep_session() -> Any:\n    with acquire_session() as s:\n        s.open = False\n        yield s\n\n\nSessionDep = Annotated[Session, Depends(dep_session)]\nBrokenSessionDep = Annotated[Session, Depends(broken_dep_session)]\n\napp = FastAPI()\n\n\n@app.websocket(\"/ws\")\nasync def websocket_endpoint(websocket: WebSocket, session: SessionDep):\n    await websocket.accept()\n    for item in session:\n        await websocket.send_text(f\"{item}\")\n\n\n@app.websocket(\"/ws-broken\")\nasync def websocket_endpoint_broken(websocket: WebSocket, session: BrokenSessionDep):\n    await websocket.accept()\n    for item in session:\n        await websocket.send_text(f\"{item}\")  # pragma no cover\n\n\nclient = TestClient(app)\n\n\ndef test_websocket_dependency_after_yield():\n    with client.websocket_connect(\"/ws\") as websocket:\n        data = websocket.receive_text()\n        assert data == \"foo\"\n        data = websocket.receive_text()\n        assert data == \"bar\"\n        data = websocket.receive_text()\n        assert data == \"baz\"\n\n\ndef test_websocket_dependency_after_yield_broken():\n    with pytest.raises(ValueError, match=\"Session closed\"):\n        with client.websocket_connect(\"/ws-broken\"):\n            pass  # pragma no cover\n"
  },
  {
    "path": "tests/test_dependency_cache.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\ncounter_holder = {\"counter\": 0}\n\n\nasync def dep_counter():\n    counter_holder[\"counter\"] += 1\n    return counter_holder[\"counter\"]\n\n\nasync def super_dep(count: int = Depends(dep_counter)):\n    return count\n\n\n@app.get(\"/counter/\")\nasync def get_counter(count: int = Depends(dep_counter)):\n    return {\"counter\": count}\n\n\n@app.get(\"/sub-counter/\")\nasync def get_sub_counter(\n    subcount: int = Depends(super_dep), count: int = Depends(dep_counter)\n):\n    return {\"counter\": count, \"subcounter\": subcount}\n\n\n@app.get(\"/sub-counter-no-cache/\")\nasync def get_sub_counter_no_cache(\n    subcount: int = Depends(super_dep),\n    count: int = Depends(dep_counter, use_cache=False),\n):\n    return {\"counter\": count, \"subcounter\": subcount}\n\n\n@app.get(\"/scope-counter\")\nasync def get_scope_counter(\n    count: int = Security(dep_counter),\n    scope_count_1: int = Security(dep_counter, scopes=[\"scope\"]),\n    scope_count_2: int = Security(dep_counter, scopes=[\"scope\"]),\n):\n    return {\n        \"counter\": count,\n        \"scope_counter_1\": scope_count_1,\n        \"scope_counter_2\": scope_count_2,\n    }\n\n\nclient = TestClient(app)\n\n\ndef test_normal_counter():\n    counter_holder[\"counter\"] = 0\n    response = client.get(\"/counter/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"counter\": 1}\n    response = client.get(\"/counter/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"counter\": 2}\n\n\ndef test_sub_counter():\n    counter_holder[\"counter\"] = 0\n    response = client.get(\"/sub-counter/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"counter\": 1, \"subcounter\": 1}\n    response = client.get(\"/sub-counter/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"counter\": 2, \"subcounter\": 2}\n\n\ndef test_sub_counter_no_cache():\n    counter_holder[\"counter\"] = 0\n    response = client.get(\"/sub-counter-no-cache/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"counter\": 2, \"subcounter\": 1}\n    response = client.get(\"/sub-counter-no-cache/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"counter\": 4, \"subcounter\": 3}\n\n\ndef test_security_cache():\n    counter_holder[\"counter\"] = 0\n    response = client.get(\"/scope-counter/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"counter\": 1, \"scope_counter_1\": 2, \"scope_counter_2\": 2}\n    response = client.get(\"/scope-counter/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"counter\": 3, \"scope_counter_1\": 4, \"scope_counter_2\": 4}\n"
  },
  {
    "path": "tests/test_dependency_class.py",
    "content": "from collections.abc import AsyncGenerator, Generator\n\nimport pytest\nfrom fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\nclass CallableDependency:\n    def __call__(self, value: str) -> str:\n        return value\n\n\nclass CallableGenDependency:\n    def __call__(self, value: str) -> Generator[str, None, None]:\n        yield value\n\n\nclass AsyncCallableDependency:\n    async def __call__(self, value: str) -> str:\n        return value\n\n\nclass AsyncCallableGenDependency:\n    async def __call__(self, value: str) -> AsyncGenerator[str, None]:\n        yield value\n\n\nclass MethodsDependency:\n    def synchronous(self, value: str) -> str:\n        return value\n\n    async def asynchronous(self, value: str) -> str:\n        return value\n\n    def synchronous_gen(self, value: str) -> Generator[str, None, None]:\n        yield value\n\n    async def asynchronous_gen(self, value: str) -> AsyncGenerator[str, None]:\n        yield value\n\n\ncallable_dependency = CallableDependency()\ncallable_gen_dependency = CallableGenDependency()\nasync_callable_dependency = AsyncCallableDependency()\nasync_callable_gen_dependency = AsyncCallableGenDependency()\nmethods_dependency = MethodsDependency()\n\n\n@app.get(\"/callable-dependency-class\")\nasync def get_callable_dependency_class(\n    value: str, instance: CallableDependency = Depends()\n):\n    return instance(value)\n\n\n@app.get(\"/callable-gen-dependency-class\")\nasync def get_callable_gen_dependency_class(\n    value: str, instance: CallableGenDependency = Depends()\n):\n    return next(instance(value))\n\n\n@app.get(\"/async-callable-dependency-class\")\nasync def get_async_callable_dependency_class(\n    value: str, instance: AsyncCallableDependency = Depends()\n):\n    return await instance(value)\n\n\n@app.get(\"/async-callable-gen-dependency-class\")\nasync def get_async_callable_gen_dependency_class(\n    value: str, instance: AsyncCallableGenDependency = Depends()\n):\n    return await instance(value).__anext__()\n\n\n@app.get(\"/callable-dependency\")\nasync def get_callable_dependency(value: str = Depends(callable_dependency)):\n    return value\n\n\n@app.get(\"/callable-gen-dependency\")\nasync def get_callable_gen_dependency(value: str = Depends(callable_gen_dependency)):\n    return value\n\n\n@app.get(\"/async-callable-dependency\")\nasync def get_async_callable_dependency(\n    value: str = Depends(async_callable_dependency),\n):\n    return value\n\n\n@app.get(\"/async-callable-gen-dependency\")\nasync def get_async_callable_gen_dependency(\n    value: str = Depends(async_callable_gen_dependency),\n):\n    return value\n\n\n@app.get(\"/synchronous-method-dependency\")\nasync def get_synchronous_method_dependency(\n    value: str = Depends(methods_dependency.synchronous),\n):\n    return value\n\n\n@app.get(\"/synchronous-method-gen-dependency\")\nasync def get_synchronous_method_gen_dependency(\n    value: str = Depends(methods_dependency.synchronous_gen),\n):\n    return value\n\n\n@app.get(\"/asynchronous-method-dependency\")\nasync def get_asynchronous_method_dependency(\n    value: str = Depends(methods_dependency.asynchronous),\n):\n    return value\n\n\n@app.get(\"/asynchronous-method-gen-dependency\")\nasync def get_asynchronous_method_gen_dependency(\n    value: str = Depends(methods_dependency.asynchronous_gen),\n):\n    return value\n\n\nclient = TestClient(app)\n\n\n@pytest.mark.parametrize(\n    \"route,value\",\n    [\n        (\"/callable-dependency\", \"callable-dependency\"),\n        (\"/callable-gen-dependency\", \"callable-gen-dependency\"),\n        (\"/async-callable-dependency\", \"async-callable-dependency\"),\n        (\"/async-callable-gen-dependency\", \"async-callable-gen-dependency\"),\n        (\"/synchronous-method-dependency\", \"synchronous-method-dependency\"),\n        (\"/synchronous-method-gen-dependency\", \"synchronous-method-gen-dependency\"),\n        (\"/asynchronous-method-dependency\", \"asynchronous-method-dependency\"),\n        (\"/asynchronous-method-gen-dependency\", \"asynchronous-method-gen-dependency\"),\n        (\"/callable-dependency-class\", \"callable-dependency-class\"),\n        (\"/callable-gen-dependency-class\", \"callable-gen-dependency-class\"),\n        (\"/async-callable-dependency-class\", \"async-callable-dependency-class\"),\n        (\"/async-callable-gen-dependency-class\", \"async-callable-gen-dependency-class\"),\n    ],\n)\ndef test_class_dependency(route, value):\n    response = client.get(route, params={\"value\": value})\n    assert response.status_code == 200, response.text\n    assert response.json() == value\n"
  },
  {
    "path": "tests/test_dependency_contextmanager.py",
    "content": "import json\n\nimport pytest\nfrom fastapi import BackgroundTasks, Depends, FastAPI\nfrom fastapi.responses import StreamingResponse\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\nstate = {\n    \"/async\": \"asyncgen not started\",\n    \"/sync\": \"generator not started\",\n    \"/async_raise\": \"asyncgen raise not started\",\n    \"/sync_raise\": \"generator raise not started\",\n    \"context_a\": \"not started a\",\n    \"context_b\": \"not started b\",\n    \"bg\": \"not set\",\n    \"sync_bg\": \"not set\",\n}\n\nerrors = []\n\n\nasync def get_state():\n    return state\n\n\nclass AsyncDependencyError(Exception):\n    pass\n\n\nclass SyncDependencyError(Exception):\n    pass\n\n\nclass OtherDependencyError(Exception):\n    pass\n\n\nasync def asyncgen_state(state: dict[str, str] = Depends(get_state)):\n    state[\"/async\"] = \"asyncgen started\"\n    yield state[\"/async\"]\n    state[\"/async\"] = \"asyncgen completed\"\n\n\ndef generator_state(state: dict[str, str] = Depends(get_state)):\n    state[\"/sync\"] = \"generator started\"\n    yield state[\"/sync\"]\n    state[\"/sync\"] = \"generator completed\"\n\n\nasync def asyncgen_state_try(state: dict[str, str] = Depends(get_state)):\n    state[\"/async_raise\"] = \"asyncgen raise started\"\n    try:\n        yield state[\"/async_raise\"]\n    except AsyncDependencyError:\n        errors.append(\"/async_raise\")\n        raise\n    finally:\n        state[\"/async_raise\"] = \"asyncgen raise finalized\"\n\n\ndef generator_state_try(state: dict[str, str] = Depends(get_state)):\n    state[\"/sync_raise\"] = \"generator raise started\"\n    try:\n        yield state[\"/sync_raise\"]\n    except SyncDependencyError:\n        errors.append(\"/sync_raise\")\n        raise\n    finally:\n        state[\"/sync_raise\"] = \"generator raise finalized\"\n\n\nasync def context_a(state: dict = Depends(get_state)):\n    state[\"context_a\"] = \"started a\"\n    try:\n        yield state\n    finally:\n        state[\"context_a\"] = \"finished a\"\n\n\nasync def context_b(state: dict = Depends(context_a)):\n    state[\"context_b\"] = \"started b\"\n    try:\n        yield state\n    finally:\n        state[\"context_b\"] = f\"finished b with a: {state['context_a']}\"\n\n\n@app.get(\"/async\")\nasync def get_async(state: str = Depends(asyncgen_state)):\n    return state\n\n\n@app.get(\"/sync\")\nasync def get_sync(state: str = Depends(generator_state)):\n    return state\n\n\n@app.get(\"/async_raise\")\nasync def get_async_raise(state: str = Depends(asyncgen_state_try)):\n    assert state == \"asyncgen raise started\"\n    raise AsyncDependencyError()\n\n\n@app.get(\"/sync_raise\")\nasync def get_sync_raise(state: str = Depends(generator_state_try)):\n    assert state == \"generator raise started\"\n    raise SyncDependencyError()\n\n\n@app.get(\"/async_raise_other\")\nasync def get_async_raise_other(state: str = Depends(asyncgen_state_try)):\n    assert state == \"asyncgen raise started\"\n    raise OtherDependencyError()\n\n\n@app.get(\"/sync_raise_other\")\nasync def get_sync_raise_other(state: str = Depends(generator_state_try)):\n    assert state == \"generator raise started\"\n    raise OtherDependencyError()\n\n\n@app.get(\"/context_b\")\nasync def get_context_b(state: dict = Depends(context_b)):\n    return state\n\n\n@app.get(\"/context_b_raise\")\nasync def get_context_b_raise(state: dict = Depends(context_b)):\n    assert state[\"context_b\"] == \"started b\"\n    assert state[\"context_a\"] == \"started a\"\n    raise OtherDependencyError()\n\n\n@app.get(\"/context_b_bg\")\nasync def get_context_b_bg(tasks: BackgroundTasks, state: dict = Depends(context_b)):\n    async def bg(state: dict):\n        state[\"bg\"] = f\"bg set - b: {state['context_b']} - a: {state['context_a']}\"\n\n    tasks.add_task(bg, state)\n    return state\n\n\n# Sync versions\n\n\n@app.get(\"/sync_async\")\ndef get_sync_async(state: str = Depends(asyncgen_state)):\n    return state\n\n\n@app.get(\"/sync_sync\")\ndef get_sync_sync(state: str = Depends(generator_state)):\n    return state\n\n\n@app.get(\"/sync_async_raise\")\ndef get_sync_async_raise(state: str = Depends(asyncgen_state_try)):\n    assert state == \"asyncgen raise started\"\n    raise AsyncDependencyError()\n\n\n@app.get(\"/sync_sync_raise\")\ndef get_sync_sync_raise(state: str = Depends(generator_state_try)):\n    assert state == \"generator raise started\"\n    raise SyncDependencyError()\n\n\n@app.get(\"/sync_async_raise_other\")\ndef get_sync_async_raise_other(state: str = Depends(asyncgen_state_try)):\n    assert state == \"asyncgen raise started\"\n    raise OtherDependencyError()\n\n\n@app.get(\"/sync_sync_raise_other\")\ndef get_sync_sync_raise_other(state: str = Depends(generator_state_try)):\n    assert state == \"generator raise started\"\n    raise OtherDependencyError()\n\n\n@app.get(\"/sync_context_b\")\ndef get_sync_context_b(state: dict = Depends(context_b)):\n    return state\n\n\n@app.get(\"/sync_context_b_raise\")\ndef get_sync_context_b_raise(state: dict = Depends(context_b)):\n    assert state[\"context_b\"] == \"started b\"\n    assert state[\"context_a\"] == \"started a\"\n    raise OtherDependencyError()\n\n\n@app.get(\"/sync_context_b_bg\")\nasync def get_sync_context_b_bg(\n    tasks: BackgroundTasks, state: dict = Depends(context_b)\n):\n    async def bg(state: dict):\n        state[\"sync_bg\"] = (\n            f\"sync_bg set - b: {state['context_b']} - a: {state['context_a']}\"\n        )\n\n    tasks.add_task(bg, state)\n    return state\n\n\n@app.middleware(\"http\")\nasync def middleware(request, call_next):\n    response: StreamingResponse = await call_next(request)\n    response.headers[\"x-state\"] = json.dumps(state.copy())\n    return response\n\n\nclient = TestClient(app)\n\n\ndef test_async_state():\n    assert state[\"/async\"] == \"asyncgen not started\"\n    response = client.get(\"/async\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"asyncgen started\"\n    assert state[\"/async\"] == \"asyncgen completed\"\n\n\ndef test_sync_state():\n    assert state[\"/sync\"] == \"generator not started\"\n    response = client.get(\"/sync\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"generator started\"\n    assert state[\"/sync\"] == \"generator completed\"\n\n\ndef test_async_raise_other():\n    assert state[\"/async_raise\"] == \"asyncgen raise not started\"\n    with pytest.raises(OtherDependencyError):\n        client.get(\"/async_raise_other\")\n    assert state[\"/async_raise\"] == \"asyncgen raise finalized\"\n    assert \"/async_raise\" not in errors\n\n\ndef test_sync_raise_other():\n    assert state[\"/sync_raise\"] == \"generator raise not started\"\n    with pytest.raises(OtherDependencyError):\n        client.get(\"/sync_raise_other\")\n    assert state[\"/sync_raise\"] == \"generator raise finalized\"\n    assert \"/sync_raise\" not in errors\n\n\ndef test_async_raise_raises():\n    with pytest.raises(AsyncDependencyError):\n        client.get(\"/async_raise\")\n    assert state[\"/async_raise\"] == \"asyncgen raise finalized\"\n    assert \"/async_raise\" in errors\n    errors.clear()\n\n\ndef test_async_raise_server_error():\n    client = TestClient(app, raise_server_exceptions=False)\n    response = client.get(\"/async_raise\")\n    assert response.status_code == 500, response.text\n    assert state[\"/async_raise\"] == \"asyncgen raise finalized\"\n    assert \"/async_raise\" in errors\n    errors.clear()\n\n\ndef test_context_b():\n    response = client.get(\"/context_b\")\n    data = response.json()\n    assert data[\"context_b\"] == \"started b\"\n    assert data[\"context_a\"] == \"started a\"\n    assert state[\"context_b\"] == \"finished b with a: started a\"\n    assert state[\"context_a\"] == \"finished a\"\n\n\ndef test_context_b_raise():\n    with pytest.raises(OtherDependencyError):\n        client.get(\"/context_b_raise\")\n    assert state[\"context_b\"] == \"finished b with a: started a\"\n    assert state[\"context_a\"] == \"finished a\"\n\n\ndef test_background_tasks():\n    response = client.get(\"/context_b_bg\")\n    data = response.json()\n    assert data[\"context_b\"] == \"started b\"\n    assert data[\"context_a\"] == \"started a\"\n    assert data[\"bg\"] == \"not set\"\n    middleware_state = json.loads(response.headers[\"x-state\"])\n    assert middleware_state[\"context_b\"] == \"started b\"\n    assert middleware_state[\"context_a\"] == \"started a\"\n    assert middleware_state[\"bg\"] == \"not set\"\n    assert state[\"context_b\"] == \"finished b with a: started a\"\n    assert state[\"context_a\"] == \"finished a\"\n    assert state[\"bg\"] == \"bg set - b: started b - a: started a\"\n\n\ndef test_sync_raise_raises():\n    with pytest.raises(SyncDependencyError):\n        client.get(\"/sync_raise\")\n    assert state[\"/sync_raise\"] == \"generator raise finalized\"\n    assert \"/sync_raise\" in errors\n    errors.clear()\n\n\ndef test_sync_raise_server_error():\n    client = TestClient(app, raise_server_exceptions=False)\n    response = client.get(\"/sync_raise\")\n    assert response.status_code == 500, response.text\n    assert state[\"/sync_raise\"] == \"generator raise finalized\"\n    assert \"/sync_raise\" in errors\n    errors.clear()\n\n\ndef test_sync_async_state():\n    response = client.get(\"/sync_async\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"asyncgen started\"\n    assert state[\"/async\"] == \"asyncgen completed\"\n\n\ndef test_sync_sync_state():\n    response = client.get(\"/sync_sync\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"generator started\"\n    assert state[\"/sync\"] == \"generator completed\"\n\n\ndef test_sync_async_raise_other():\n    with pytest.raises(OtherDependencyError):\n        client.get(\"/sync_async_raise_other\")\n    assert state[\"/async_raise\"] == \"asyncgen raise finalized\"\n    assert \"/async_raise\" not in errors\n\n\ndef test_sync_sync_raise_other():\n    with pytest.raises(OtherDependencyError):\n        client.get(\"/sync_sync_raise_other\")\n    assert state[\"/sync_raise\"] == \"generator raise finalized\"\n    assert \"/sync_raise\" not in errors\n\n\ndef test_sync_async_raise_raises():\n    with pytest.raises(AsyncDependencyError):\n        client.get(\"/sync_async_raise\")\n    assert state[\"/async_raise\"] == \"asyncgen raise finalized\"\n    assert \"/async_raise\" in errors\n    errors.clear()\n\n\ndef test_sync_async_raise_server_error():\n    client = TestClient(app, raise_server_exceptions=False)\n    response = client.get(\"/sync_async_raise\")\n    assert response.status_code == 500, response.text\n    assert state[\"/async_raise\"] == \"asyncgen raise finalized\"\n    assert \"/async_raise\" in errors\n    errors.clear()\n\n\ndef test_sync_sync_raise_raises():\n    with pytest.raises(SyncDependencyError):\n        client.get(\"/sync_sync_raise\")\n    assert state[\"/sync_raise\"] == \"generator raise finalized\"\n    assert \"/sync_raise\" in errors\n    errors.clear()\n\n\ndef test_sync_sync_raise_server_error():\n    client = TestClient(app, raise_server_exceptions=False)\n    response = client.get(\"/sync_sync_raise\")\n    assert response.status_code == 500, response.text\n    assert state[\"/sync_raise\"] == \"generator raise finalized\"\n    assert \"/sync_raise\" in errors\n    errors.clear()\n\n\ndef test_sync_context_b():\n    response = client.get(\"/sync_context_b\")\n    data = response.json()\n    assert data[\"context_b\"] == \"started b\"\n    assert data[\"context_a\"] == \"started a\"\n    assert state[\"context_b\"] == \"finished b with a: started a\"\n    assert state[\"context_a\"] == \"finished a\"\n\n\ndef test_sync_context_b_raise():\n    with pytest.raises(OtherDependencyError):\n        client.get(\"/sync_context_b_raise\")\n    assert state[\"context_b\"] == \"finished b with a: started a\"\n    assert state[\"context_a\"] == \"finished a\"\n\n\ndef test_sync_background_tasks():\n    response = client.get(\"/sync_context_b_bg\")\n    data = response.json()\n    assert data[\"context_b\"] == \"started b\"\n    assert data[\"context_a\"] == \"started a\"\n    assert data[\"sync_bg\"] == \"not set\"\n    assert state[\"context_b\"] == \"finished b with a: started a\"\n    assert state[\"context_a\"] == \"finished a\"\n    assert state[\"sync_bg\"] == \"sync_bg set - b: started b - a: started a\"\n"
  },
  {
    "path": "tests/test_dependency_contextvars.py",
    "content": "from collections.abc import Awaitable, Callable\nfrom contextvars import ContextVar\nfrom typing import Any\n\nfrom fastapi import Depends, FastAPI, Request, Response\nfrom fastapi.testclient import TestClient\n\nlegacy_request_state_context_var: ContextVar[dict[str, Any] | None] = ContextVar(\n    \"legacy_request_state_context_var\", default=None\n)\n\napp = FastAPI()\n\n\nasync def set_up_request_state_dependency():\n    request_state = {\"user\": \"deadpond\"}\n    contextvar_token = legacy_request_state_context_var.set(request_state)\n    yield request_state\n    legacy_request_state_context_var.reset(contextvar_token)\n\n\n@app.middleware(\"http\")\nasync def custom_middleware(\n    request: Request, call_next: Callable[[Request], Awaitable[Response]]\n):\n    response = await call_next(request)\n    response.headers[\"custom\"] = \"foo\"\n    return response\n\n\n@app.get(\"/user\", dependencies=[Depends(set_up_request_state_dependency)])\ndef get_user():\n    request_state = legacy_request_state_context_var.get()\n    assert request_state\n    return request_state[\"user\"]\n\n\nclient = TestClient(app)\n\n\ndef test_dependency_contextvars():\n    \"\"\"\n    Check that custom middlewares don't affect the contextvar context for dependencies.\n\n    The code before yield and the code after yield should be run in the same contextvar\n    context, so that request_state_context_var.reset(contextvar_token).\n\n    If they are run in a different context, that raises an error.\n    \"\"\"\n    response = client.get(\"/user\")\n    assert response.json() == \"deadpond\"\n    assert response.headers[\"custom\"] == \"foo\"\n"
  },
  {
    "path": "tests/test_dependency_duplicates.py",
    "content": "from fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\nclient = TestClient(app)\n\n\nclass Item(BaseModel):\n    data: str\n\n\ndef duplicate_dependency(item: Item):\n    return item\n\n\ndef dependency(item2: Item):\n    return item2\n\n\ndef sub_duplicate_dependency(\n    item: Item, sub_item: Item = Depends(duplicate_dependency)\n):\n    return [item, sub_item]\n\n\n@app.post(\"/with-duplicates\")\nasync def with_duplicates(item: Item, item2: Item = Depends(duplicate_dependency)):\n    return [item, item2]\n\n\n@app.post(\"/no-duplicates\")\nasync def no_duplicates(item: Item, item2: Item = Depends(dependency)):\n    return [item, item2]\n\n\n@app.post(\"/with-duplicates-sub\")\nasync def no_duplicates_sub(\n    item: Item, sub_items: list[Item] = Depends(sub_duplicate_dependency)\n):\n    return [item, sub_items]\n\n\ndef test_no_duplicates_invalid():\n    response = client.post(\"/no-duplicates\", json={\"item\": {\"data\": \"myitem\"}})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"item2\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_no_duplicates():\n    response = client.post(\n        \"/no-duplicates\",\n        json={\"item\": {\"data\": \"myitem\"}, \"item2\": {\"data\": \"myitem2\"}},\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"data\": \"myitem\"}, {\"data\": \"myitem2\"}]\n\n\ndef test_duplicates():\n    response = client.post(\"/with-duplicates\", json={\"data\": \"myitem\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"data\": \"myitem\"}, {\"data\": \"myitem\"}]\n\n\ndef test_sub_duplicates():\n    response = client.post(\"/with-duplicates-sub\", json={\"data\": \"myitem\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"data\": \"myitem\"},\n        [{\"data\": \"myitem\"}, {\"data\": \"myitem\"}],\n    ]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/with-duplicates\": {\n                    \"post\": {\n                        \"summary\": \"With Duplicates\",\n                        \"operationId\": \"with_duplicates_with_duplicates_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/no-duplicates\": {\n                    \"post\": {\n                        \"summary\": \"No Duplicates\",\n                        \"operationId\": \"no_duplicates_no_duplicates_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_no_duplicates_no_duplicates_post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/with-duplicates-sub\": {\n                    \"post\": {\n                        \"summary\": \"No Duplicates Sub\",\n                        \"operationId\": \"no_duplicates_sub_with_duplicates_sub_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_no_duplicates_no_duplicates_post\": {\n                        \"title\": \"Body_no_duplicates_no_duplicates_post\",\n                        \"required\": [\"item\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"data\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"data\": {\"title\": \"Data\", \"type\": \"string\"}},\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_dependency_overrides.py",
    "content": "import pytest\nfrom fastapi import APIRouter, Depends, FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\nrouter = APIRouter()\n\n\nasync def common_parameters(q: str, skip: int = 0, limit: int = 100):\n    return {\"q\": q, \"skip\": skip, \"limit\": limit}\n\n\n@app.get(\"/main-depends/\")\nasync def main_depends(commons: dict = Depends(common_parameters)):\n    return {\"in\": \"main-depends\", \"params\": commons}\n\n\n@app.get(\"/decorator-depends/\", dependencies=[Depends(common_parameters)])\nasync def decorator_depends():\n    return {\"in\": \"decorator-depends\"}\n\n\n@router.get(\"/router-depends/\")\nasync def router_depends(commons: dict = Depends(common_parameters)):\n    return {\"in\": \"router-depends\", \"params\": commons}\n\n\n@router.get(\"/router-decorator-depends/\", dependencies=[Depends(common_parameters)])\nasync def router_decorator_depends():\n    return {\"in\": \"router-decorator-depends\"}\n\n\napp.include_router(router)\n\nclient = TestClient(app)\n\n\nasync def overrider_dependency_simple(q: str | None = None):\n    return {\"q\": q, \"skip\": 5, \"limit\": 10}\n\n\nasync def overrider_sub_dependency(k: str):\n    return {\"k\": k}\n\n\nasync def overrider_dependency_with_sub(msg: dict = Depends(overrider_sub_dependency)):\n    return msg\n\n\ndef test_main_depends():\n    response = client.get(\"/main-depends/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_main_depends_q_foo():\n    response = client.get(\"/main-depends/?q=foo\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"in\": \"main-depends\",\n        \"params\": {\"q\": \"foo\", \"skip\": 0, \"limit\": 100},\n    }\n\n\ndef test_main_depends_q_foo_skip_100_limit_200():\n    response = client.get(\"/main-depends/?q=foo&skip=100&limit=200\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"in\": \"main-depends\",\n        \"params\": {\"q\": \"foo\", \"skip\": 100, \"limit\": 200},\n    }\n\n\ndef test_decorator_depends():\n    response = client.get(\"/decorator-depends/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_decorator_depends_q_foo():\n    response = client.get(\"/decorator-depends/?q=foo\")\n    assert response.status_code == 200\n    assert response.json() == {\"in\": \"decorator-depends\"}\n\n\ndef test_decorator_depends_q_foo_skip_100_limit_200():\n    response = client.get(\"/decorator-depends/?q=foo&skip=100&limit=200\")\n    assert response.status_code == 200\n    assert response.json() == {\"in\": \"decorator-depends\"}\n\n\ndef test_router_depends():\n    response = client.get(\"/router-depends/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_router_depends_q_foo():\n    response = client.get(\"/router-depends/?q=foo\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"in\": \"router-depends\",\n        \"params\": {\"q\": \"foo\", \"skip\": 0, \"limit\": 100},\n    }\n\n\ndef test_router_depends_q_foo_skip_100_limit_200():\n    response = client.get(\"/router-depends/?q=foo&skip=100&limit=200\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"in\": \"router-depends\",\n        \"params\": {\"q\": \"foo\", \"skip\": 100, \"limit\": 200},\n    }\n\n\ndef test_router_decorator_depends():\n    response = client.get(\"/router-decorator-depends/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_router_decorator_depends_q_foo():\n    response = client.get(\"/router-decorator-depends/?q=foo\")\n    assert response.status_code == 200\n    assert response.json() == {\"in\": \"router-decorator-depends\"}\n\n\ndef test_router_decorator_depends_q_foo_skip_100_limit_200():\n    response = client.get(\"/router-decorator-depends/?q=foo&skip=100&limit=200\")\n    assert response.status_code == 200\n    assert response.json() == {\"in\": \"router-decorator-depends\"}\n\n\n@pytest.mark.parametrize(\n    \"url,status_code,expected\",\n    [\n        (\n            \"/main-depends/\",\n            200,\n            {\"in\": \"main-depends\", \"params\": {\"q\": None, \"skip\": 5, \"limit\": 10}},\n        ),\n        (\n            \"/main-depends/?q=foo\",\n            200,\n            {\"in\": \"main-depends\", \"params\": {\"q\": \"foo\", \"skip\": 5, \"limit\": 10}},\n        ),\n        (\n            \"/main-depends/?q=foo&skip=100&limit=200\",\n            200,\n            {\"in\": \"main-depends\", \"params\": {\"q\": \"foo\", \"skip\": 5, \"limit\": 10}},\n        ),\n        (\"/decorator-depends/\", 200, {\"in\": \"decorator-depends\"}),\n        (\n            \"/router-depends/\",\n            200,\n            {\"in\": \"router-depends\", \"params\": {\"q\": None, \"skip\": 5, \"limit\": 10}},\n        ),\n        (\n            \"/router-depends/?q=foo\",\n            200,\n            {\"in\": \"router-depends\", \"params\": {\"q\": \"foo\", \"skip\": 5, \"limit\": 10}},\n        ),\n        (\n            \"/router-depends/?q=foo&skip=100&limit=200\",\n            200,\n            {\"in\": \"router-depends\", \"params\": {\"q\": \"foo\", \"skip\": 5, \"limit\": 10}},\n        ),\n        (\"/router-decorator-depends/\", 200, {\"in\": \"router-decorator-depends\"}),\n    ],\n)\ndef test_override_simple(url, status_code, expected):\n    app.dependency_overrides[common_parameters] = overrider_dependency_simple\n    response = client.get(url)\n    assert response.status_code == status_code\n    assert response.json() == expected\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_main_depends():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/main-depends/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"k\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub__main_depends_q_foo():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/main-depends/?q=foo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"k\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_main_depends_k_bar():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/main-depends/?k=bar\")\n    assert response.status_code == 200\n    assert response.json() == {\"in\": \"main-depends\", \"params\": {\"k\": \"bar\"}}\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_decorator_depends():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/decorator-depends/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"k\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_decorator_depends_q_foo():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/decorator-depends/?q=foo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"k\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_decorator_depends_k_bar():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/decorator-depends/?k=bar\")\n    assert response.status_code == 200\n    assert response.json() == {\"in\": \"decorator-depends\"}\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_router_depends():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/router-depends/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"k\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_router_depends_q_foo():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/router-depends/?q=foo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"k\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_router_depends_k_bar():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/router-depends/?k=bar\")\n    assert response.status_code == 200\n    assert response.json() == {\"in\": \"router-depends\", \"params\": {\"k\": \"bar\"}}\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_router_decorator_depends():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/router-decorator-depends/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"k\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_router_decorator_depends_q_foo():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/router-decorator-depends/?q=foo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"k\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n    app.dependency_overrides = {}\n\n\ndef test_override_with_sub_router_decorator_depends_k_bar():\n    app.dependency_overrides[common_parameters] = overrider_dependency_with_sub\n    response = client.get(\"/router-decorator-depends/?k=bar\")\n    assert response.status_code == 200\n    assert response.json() == {\"in\": \"router-decorator-depends\"}\n    app.dependency_overrides = {}\n"
  },
  {
    "path": "tests/test_dependency_paramless.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, HTTPException, Security\nfrom fastapi.security import (\n    OAuth2PasswordBearer,\n    SecurityScopes,\n)\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"token\")\n\n\ndef process_auth(\n    credentials: Annotated[str | None, Security(oauth2_scheme)],\n    security_scopes: SecurityScopes,\n):\n    # This is an incorrect way of using it, this is not checking if the scopes are\n    # provided by the token, only if the endpoint is requesting them, but the test\n    # here is just to check if FastAPI is indeed registering and passing the scopes\n    # correctly when using Security with parameterless dependencies.\n    if \"a\" not in security_scopes.scopes or \"b\" not in security_scopes.scopes:\n        raise HTTPException(detail=\"a or b not in scopes\", status_code=401)\n    return {\"token\": credentials, \"scopes\": security_scopes.scopes}\n\n\n@app.get(\"/get-credentials\")\ndef get_credentials(\n    credentials: Annotated[dict, Security(process_auth, scopes=[\"a\", \"b\"])],\n):\n    return credentials\n\n\n@app.get(\n    \"/parameterless-with-scopes\",\n    dependencies=[Security(process_auth, scopes=[\"a\", \"b\"])],\n)\ndef get_parameterless_with_scopes():\n    return {\"status\": \"ok\"}\n\n\n@app.get(\n    \"/parameterless-without-scopes\",\n    dependencies=[Security(process_auth)],\n)\ndef get_parameterless_without_scopes():\n    return {\"status\": \"ok\"}\n\n\nclient = TestClient(app)\n\n\ndef test_get_credentials():\n    response = client.get(\"/get-credentials\", headers={\"authorization\": \"Bearer token\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"token\": \"token\", \"scopes\": [\"a\", \"b\"]}\n\n\ndef test_parameterless_with_scopes():\n    response = client.get(\n        \"/parameterless-with-scopes\", headers={\"authorization\": \"Bearer token\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"status\": \"ok\"}\n\n\ndef test_parameterless_without_scopes():\n    response = client.get(\n        \"/parameterless-without-scopes\", headers={\"authorization\": \"Bearer token\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"a or b not in scopes\"}\n\n\ndef test_call_get_parameterless_without_scopes_for_coverage():\n    assert get_parameterless_without_scopes() == {\"status\": \"ok\"}\n"
  },
  {
    "path": "tests/test_dependency_partial.py",
    "content": "from collections.abc import AsyncGenerator, Generator\nfrom functools import partial\nfrom typing import Annotated\n\nimport pytest\nfrom fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\ndef function_dependency(value: str) -> str:\n    return value\n\n\nasync def async_function_dependency(value: str) -> str:\n    return value\n\n\ndef gen_dependency(value: str) -> Generator[str, None, None]:\n    yield value\n\n\nasync def async_gen_dependency(value: str) -> AsyncGenerator[str, None]:\n    yield value\n\n\nclass CallableDependency:\n    def __call__(self, value: str) -> str:\n        return value\n\n\nclass CallableGenDependency:\n    def __call__(self, value: str) -> Generator[str, None, None]:\n        yield value\n\n\nclass AsyncCallableDependency:\n    async def __call__(self, value: str) -> str:\n        return value\n\n\nclass AsyncCallableGenDependency:\n    async def __call__(self, value: str) -> AsyncGenerator[str, None]:\n        yield value\n\n\nclass MethodsDependency:\n    def synchronous(self, value: str) -> str:\n        return value\n\n    async def asynchronous(self, value: str) -> str:\n        return value\n\n    def synchronous_gen(self, value: str) -> Generator[str, None, None]:\n        yield value\n\n    async def asynchronous_gen(self, value: str) -> AsyncGenerator[str, None]:\n        yield value\n\n\ncallable_dependency = CallableDependency()\ncallable_gen_dependency = CallableGenDependency()\nasync_callable_dependency = AsyncCallableDependency()\nasync_callable_gen_dependency = AsyncCallableGenDependency()\nmethods_dependency = MethodsDependency()\n\n\n@app.get(\"/partial-function-dependency\")\nasync def get_partial_function_dependency(\n    value: Annotated[\n        str, Depends(partial(function_dependency, \"partial-function-dependency\"))\n    ],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-async-function-dependency\")\nasync def get_partial_async_function_dependency(\n    value: Annotated[\n        str,\n        Depends(\n            partial(async_function_dependency, \"partial-async-function-dependency\")\n        ),\n    ],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-gen-dependency\")\nasync def get_partial_gen_dependency(\n    value: Annotated[str, Depends(partial(gen_dependency, \"partial-gen-dependency\"))],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-async-gen-dependency\")\nasync def get_partial_async_gen_dependency(\n    value: Annotated[\n        str, Depends(partial(async_gen_dependency, \"partial-async-gen-dependency\"))\n    ],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-callable-dependency\")\nasync def get_partial_callable_dependency(\n    value: Annotated[\n        str, Depends(partial(callable_dependency, \"partial-callable-dependency\"))\n    ],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-callable-gen-dependency\")\nasync def get_partial_callable_gen_dependency(\n    value: Annotated[\n        str,\n        Depends(partial(callable_gen_dependency, \"partial-callable-gen-dependency\")),\n    ],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-async-callable-dependency\")\nasync def get_partial_async_callable_dependency(\n    value: Annotated[\n        str,\n        Depends(\n            partial(async_callable_dependency, \"partial-async-callable-dependency\")\n        ),\n    ],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-async-callable-gen-dependency\")\nasync def get_partial_async_callable_gen_dependency(\n    value: Annotated[\n        str,\n        Depends(\n            partial(\n                async_callable_gen_dependency, \"partial-async-callable-gen-dependency\"\n            )\n        ),\n    ],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-synchronous-method-dependency\")\nasync def get_partial_synchronous_method_dependency(\n    value: Annotated[\n        str,\n        Depends(\n            partial(\n                methods_dependency.synchronous, \"partial-synchronous-method-dependency\"\n            )\n        ),\n    ],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-synchronous-method-gen-dependency\")\nasync def get_partial_synchronous_method_gen_dependency(\n    value: Annotated[\n        str,\n        Depends(\n            partial(\n                methods_dependency.synchronous_gen,\n                \"partial-synchronous-method-gen-dependency\",\n            )\n        ),\n    ],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-asynchronous-method-dependency\")\nasync def get_partial_asynchronous_method_dependency(\n    value: Annotated[\n        str,\n        Depends(\n            partial(\n                methods_dependency.asynchronous,\n                \"partial-asynchronous-method-dependency\",\n            )\n        ),\n    ],\n) -> str:\n    return value\n\n\n@app.get(\"/partial-asynchronous-method-gen-dependency\")\nasync def get_partial_asynchronous_method_gen_dependency(\n    value: Annotated[\n        str,\n        Depends(\n            partial(\n                methods_dependency.asynchronous_gen,\n                \"partial-asynchronous-method-gen-dependency\",\n            )\n        ),\n    ],\n) -> str:\n    return value\n\n\nclient = TestClient(app)\n\n\n@pytest.mark.parametrize(\n    \"route,value\",\n    [\n        (\"/partial-function-dependency\", \"partial-function-dependency\"),\n        (\n            \"/partial-async-function-dependency\",\n            \"partial-async-function-dependency\",\n        ),\n        (\"/partial-gen-dependency\", \"partial-gen-dependency\"),\n        (\"/partial-async-gen-dependency\", \"partial-async-gen-dependency\"),\n        (\"/partial-callable-dependency\", \"partial-callable-dependency\"),\n        (\"/partial-callable-gen-dependency\", \"partial-callable-gen-dependency\"),\n        (\"/partial-async-callable-dependency\", \"partial-async-callable-dependency\"),\n        (\n            \"/partial-async-callable-gen-dependency\",\n            \"partial-async-callable-gen-dependency\",\n        ),\n        (\n            \"/partial-synchronous-method-dependency\",\n            \"partial-synchronous-method-dependency\",\n        ),\n        (\n            \"/partial-synchronous-method-gen-dependency\",\n            \"partial-synchronous-method-gen-dependency\",\n        ),\n        (\n            \"/partial-asynchronous-method-dependency\",\n            \"partial-asynchronous-method-dependency\",\n        ),\n        (\n            \"/partial-asynchronous-method-gen-dependency\",\n            \"partial-asynchronous-method-gen-dependency\",\n        ),\n    ],\n)\ndef test_dependency_types_with_partial(route: str, value: str) -> None:\n    response = client.get(route)\n    assert response.status_code == 200, response.text\n    assert response.json() == value\n"
  },
  {
    "path": "tests/test_dependency_pep695.py",
    "content": "from typing import Annotated\n\nfrom fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\nfrom typing_extensions import TypeAliasType\n\n\nasync def some_value() -> int:\n    return 123\n\n\nDependedValue = TypeAliasType(\n    \"DependedValue\", Annotated[int, Depends(some_value)], type_params=()\n)\n\n\ndef test_pep695_type_dependencies():\n    app = FastAPI()\n\n    @app.get(\"/\")\n    async def get_with_dep(value: DependedValue) -> str:  # noqa\n        return f\"value: {value}\"\n\n    client = TestClient(app)\n    response = client.get(\"/\")\n    assert response.status_code == 200\n    assert response.text == '\"value: 123\"'\n"
  },
  {
    "path": "tests/test_dependency_security_overrides.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security import SecurityScopes\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\ndef get_user(required_scopes: SecurityScopes):\n    return \"john\", required_scopes.scopes\n\n\ndef get_user_override(required_scopes: SecurityScopes):\n    return \"alice\", required_scopes.scopes\n\n\ndef get_data():\n    return [1, 2, 3]\n\n\ndef get_data_override():\n    return [3, 4, 5]\n\n\n@app.get(\"/user\")\ndef read_user(\n    user_data: tuple[str, list[str]] = Security(get_user, scopes=[\"foo\", \"bar\"]),\n    data: list[int] = Depends(get_data),\n):\n    return {\"user\": user_data[0], \"scopes\": user_data[1], \"data\": data}\n\n\nclient = TestClient(app)\n\n\ndef test_normal():\n    response = client.get(\"/user\")\n    assert response.json() == {\n        \"user\": \"john\",\n        \"scopes\": [\"foo\", \"bar\"],\n        \"data\": [1, 2, 3],\n    }\n\n\ndef test_override_data():\n    app.dependency_overrides[get_data] = get_data_override\n    response = client.get(\"/user\")\n    assert response.json() == {\n        \"user\": \"john\",\n        \"scopes\": [\"foo\", \"bar\"],\n        \"data\": [3, 4, 5],\n    }\n    app.dependency_overrides = {}\n\n\ndef test_override_security():\n    app.dependency_overrides[get_user] = get_user_override\n    response = client.get(\"/user\")\n    assert response.json() == {\n        \"user\": \"alice\",\n        \"scopes\": [\"foo\", \"bar\"],\n        \"data\": [1, 2, 3],\n    }\n    app.dependency_overrides = {}\n"
  },
  {
    "path": "tests/test_dependency_wrapped.py",
    "content": "import inspect\nimport sys\nfrom collections.abc import AsyncGenerator, Generator\nfrom functools import wraps\n\nimport pytest\nfrom fastapi import Depends, FastAPI\nfrom fastapi.concurrency import iterate_in_threadpool, run_in_threadpool\nfrom fastapi.testclient import TestClient\n\nif sys.version_info >= (3, 13):  # pragma: no cover\n    from inspect import iscoroutinefunction\nelse:  # pragma: no cover\n    from asyncio import iscoroutinefunction\n\n\ndef noop_wrap(func):\n    @wraps(func)\n    def wrapper(*args, **kwargs):\n        return func(*args, **kwargs)\n\n    return wrapper\n\n\ndef noop_wrap_async(func):\n    if inspect.isgeneratorfunction(func):\n\n        @wraps(func)\n        async def gen_wrapper(*args, **kwargs):\n            async for item in iterate_in_threadpool(func(*args, **kwargs)):\n                yield item\n\n        return gen_wrapper\n\n    elif inspect.isasyncgenfunction(func):\n\n        @wraps(func)\n        async def async_gen_wrapper(*args, **kwargs):\n            async for item in func(*args, **kwargs):\n                yield item\n\n        return async_gen_wrapper\n\n    @wraps(func)\n    async def wrapper(*args, **kwargs):\n        if inspect.isroutine(func) and iscoroutinefunction(func):\n            return await func(*args, **kwargs)\n        if inspect.isclass(func):\n            return await run_in_threadpool(func, *args, **kwargs)\n        dunder_call = getattr(func, \"__call__\", None)  # noqa: B004\n        if iscoroutinefunction(dunder_call):\n            return await dunder_call(*args, **kwargs)\n        return await run_in_threadpool(func, *args, **kwargs)\n\n    return wrapper\n\n\nclass ClassInstanceDep:\n    def __call__(self):\n        return True\n\n\nclass_instance_dep = ClassInstanceDep()\nwrapped_class_instance_dep = noop_wrap(class_instance_dep)\nwrapped_class_instance_dep_async_wrapper = noop_wrap_async(class_instance_dep)\n\n\nclass ClassInstanceGenDep:\n    def __call__(self):\n        yield True\n\n\nclass_instance_gen_dep = ClassInstanceGenDep()\nwrapped_class_instance_gen_dep = noop_wrap(class_instance_gen_dep)\n\n\nclass ClassInstanceWrappedDep:\n    @noop_wrap\n    def __call__(self):\n        return True\n\n\nclass_instance_wrapped_dep = ClassInstanceWrappedDep()\n\n\nclass ClassInstanceWrappedAsyncDep:\n    @noop_wrap_async\n    def __call__(self):\n        return True\n\n\nclass_instance_wrapped_async_dep = ClassInstanceWrappedAsyncDep()\n\n\nclass ClassInstanceWrappedGenDep:\n    @noop_wrap\n    def __call__(self):\n        yield True\n\n\nclass_instance_wrapped_gen_dep = ClassInstanceWrappedGenDep()\n\n\nclass ClassInstanceWrappedAsyncGenDep:\n    @noop_wrap_async\n    def __call__(self):\n        yield True\n\n\nclass_instance_wrapped_async_gen_dep = ClassInstanceWrappedAsyncGenDep()\n\n\nclass ClassDep:\n    def __init__(self):\n        self.value = True\n\n\nwrapped_class_dep = noop_wrap(ClassDep)\nwrapped_class_dep_async_wrapper = noop_wrap_async(ClassDep)\n\n\nclass ClassInstanceAsyncDep:\n    async def __call__(self):\n        return True\n\n\nclass_instance_async_dep = ClassInstanceAsyncDep()\nwrapped_class_instance_async_dep = noop_wrap(class_instance_async_dep)\nwrapped_class_instance_async_dep_async_wrapper = noop_wrap_async(\n    class_instance_async_dep\n)\n\n\nclass ClassInstanceAsyncGenDep:\n    async def __call__(self):\n        yield True\n\n\nclass_instance_async_gen_dep = ClassInstanceAsyncGenDep()\nwrapped_class_instance_async_gen_dep = noop_wrap(class_instance_async_gen_dep)\n\n\nclass ClassInstanceAsyncWrappedDep:\n    @noop_wrap\n    async def __call__(self):\n        return True\n\n\nclass_instance_async_wrapped_dep = ClassInstanceAsyncWrappedDep()\n\n\nclass ClassInstanceAsyncWrappedAsyncDep:\n    @noop_wrap_async\n    async def __call__(self):\n        return True\n\n\nclass_instance_async_wrapped_async_dep = ClassInstanceAsyncWrappedAsyncDep()\n\n\nclass ClassInstanceAsyncWrappedGenDep:\n    @noop_wrap\n    async def __call__(self):\n        yield True\n\n\nclass_instance_async_wrapped_gen_dep = ClassInstanceAsyncWrappedGenDep()\n\n\nclass ClassInstanceAsyncWrappedGenAsyncDep:\n    @noop_wrap_async\n    async def __call__(self):\n        yield True\n\n\nclass_instance_async_wrapped_gen_async_dep = ClassInstanceAsyncWrappedGenAsyncDep()\n\napp = FastAPI()\n\n# Sync wrapper\n\n\n@noop_wrap\ndef wrapped_dependency() -> bool:\n    return True\n\n\n@noop_wrap\ndef wrapped_gen_dependency() -> Generator[bool, None, None]:\n    yield True\n\n\n@noop_wrap\nasync def async_wrapped_dependency() -> bool:\n    return True\n\n\n@noop_wrap\nasync def async_wrapped_gen_dependency() -> AsyncGenerator[bool, None]:\n    yield True\n\n\n@app.get(\"/wrapped-dependency/\")\nasync def get_wrapped_dependency(value: bool = Depends(wrapped_dependency)):\n    return value\n\n\n@app.get(\"/wrapped-gen-dependency/\")\nasync def get_wrapped_gen_dependency(value: bool = Depends(wrapped_gen_dependency)):\n    return value\n\n\n@app.get(\"/async-wrapped-dependency/\")\nasync def get_async_wrapped_dependency(value: bool = Depends(async_wrapped_dependency)):\n    return value\n\n\n@app.get(\"/async-wrapped-gen-dependency/\")\nasync def get_async_wrapped_gen_dependency(\n    value: bool = Depends(async_wrapped_gen_dependency),\n):\n    return value\n\n\n@app.get(\"/wrapped-class-instance-dependency/\")\nasync def get_wrapped_class_instance_dependency(\n    value: bool = Depends(wrapped_class_instance_dep),\n):\n    return value\n\n\n@app.get(\"/wrapped-class-instance-async-dependency/\")\nasync def get_wrapped_class_instance_async_dependency(\n    value: bool = Depends(wrapped_class_instance_async_dep),\n):\n    return value\n\n\n@app.get(\"/wrapped-class-instance-gen-dependency/\")\nasync def get_wrapped_class_instance_gen_dependency(\n    value: bool = Depends(wrapped_class_instance_gen_dep),\n):\n    return value\n\n\n@app.get(\"/wrapped-class-instance-async-gen-dependency/\")\nasync def get_wrapped_class_instance_async_gen_dependency(\n    value: bool = Depends(wrapped_class_instance_async_gen_dep),\n):\n    return value\n\n\n@app.get(\"/class-instance-wrapped-dependency/\")\nasync def get_class_instance_wrapped_dependency(\n    value: bool = Depends(class_instance_wrapped_dep),\n):\n    return value\n\n\n@app.get(\"/class-instance-wrapped-async-dependency/\")\nasync def get_class_instance_wrapped_async_dependency(\n    value: bool = Depends(class_instance_wrapped_async_dep),\n):\n    return value\n\n\n@app.get(\"/class-instance-async-wrapped-dependency/\")\nasync def get_class_instance_async_wrapped_dependency(\n    value: bool = Depends(class_instance_async_wrapped_dep),\n):\n    return value\n\n\n@app.get(\"/class-instance-async-wrapped-async-dependency/\")\nasync def get_class_instance_async_wrapped_async_dependency(\n    value: bool = Depends(class_instance_async_wrapped_async_dep),\n):\n    return value\n\n\n@app.get(\"/class-instance-wrapped-gen-dependency/\")\nasync def get_class_instance_wrapped_gen_dependency(\n    value: bool = Depends(class_instance_wrapped_gen_dep),\n):\n    return value\n\n\n@app.get(\"/class-instance-wrapped-async-gen-dependency/\")\nasync def get_class_instance_wrapped_async_gen_dependency(\n    value: bool = Depends(class_instance_wrapped_async_gen_dep),\n):\n    return value\n\n\n@app.get(\"/class-instance-async-wrapped-gen-dependency/\")\nasync def get_class_instance_async_wrapped_gen_dependency(\n    value: bool = Depends(class_instance_async_wrapped_gen_dep),\n):\n    return value\n\n\n@app.get(\"/class-instance-async-wrapped-gen-async-dependency/\")\nasync def get_class_instance_async_wrapped_gen_async_dependency(\n    value: bool = Depends(class_instance_async_wrapped_gen_async_dep),\n):\n    return value\n\n\n@app.get(\"/wrapped-class-dependency/\")\nasync def get_wrapped_class_dependency(value: ClassDep = Depends(wrapped_class_dep)):\n    return value.value\n\n\n@app.get(\"/wrapped-endpoint/\")\n@noop_wrap\ndef get_wrapped_endpoint():\n    return True\n\n\n@app.get(\"/async-wrapped-endpoint/\")\n@noop_wrap\nasync def get_async_wrapped_endpoint():\n    return True\n\n\n# Async wrapper\n\n\n@noop_wrap_async\ndef wrapped_dependency_async_wrapper() -> bool:\n    return True\n\n\n@noop_wrap_async\ndef wrapped_gen_dependency_async_wrapper() -> Generator[bool, None, None]:\n    yield True\n\n\n@noop_wrap_async\nasync def async_wrapped_dependency_async_wrapper() -> bool:\n    return True\n\n\n@noop_wrap_async\nasync def async_wrapped_gen_dependency_async_wrapper() -> AsyncGenerator[bool, None]:\n    yield True\n\n\n@app.get(\"/wrapped-dependency-async-wrapper/\")\nasync def get_wrapped_dependency_async_wrapper(\n    value: bool = Depends(wrapped_dependency_async_wrapper),\n):\n    return value\n\n\n@app.get(\"/wrapped-gen-dependency-async-wrapper/\")\nasync def get_wrapped_gen_dependency_async_wrapper(\n    value: bool = Depends(wrapped_gen_dependency_async_wrapper),\n):\n    return value\n\n\n@app.get(\"/async-wrapped-dependency-async-wrapper/\")\nasync def get_async_wrapped_dependency_async_wrapper(\n    value: bool = Depends(async_wrapped_dependency_async_wrapper),\n):\n    return value\n\n\n@app.get(\"/async-wrapped-gen-dependency-async-wrapper/\")\nasync def get_async_wrapped_gen_dependency_async_wrapper(\n    value: bool = Depends(async_wrapped_gen_dependency_async_wrapper),\n):\n    return value\n\n\n@app.get(\"/wrapped-class-instance-dependency-async-wrapper/\")\nasync def get_wrapped_class_instance_dependency_async_wrapper(\n    value: bool = Depends(wrapped_class_instance_dep_async_wrapper),\n):\n    return value\n\n\n@app.get(\"/wrapped-class-instance-async-dependency-async-wrapper/\")\nasync def get_wrapped_class_instance_async_dependency_async_wrapper(\n    value: bool = Depends(wrapped_class_instance_async_dep_async_wrapper),\n):\n    return value\n\n\n@app.get(\"/wrapped-class-dependency-async-wrapper/\")\nasync def get_wrapped_class_dependency_async_wrapper(\n    value: ClassDep = Depends(wrapped_class_dep_async_wrapper),\n):\n    return value.value\n\n\n@app.get(\"/wrapped-endpoint-async-wrapper/\")\n@noop_wrap_async\ndef get_wrapped_endpoint_async_wrapper():\n    return True\n\n\n@app.get(\"/async-wrapped-endpoint-async-wrapper/\")\n@noop_wrap_async\nasync def get_async_wrapped_endpoint_async_wrapper():\n    return True\n\n\nclient = TestClient(app)\n\n\n@pytest.mark.parametrize(\n    \"route\",\n    [\n        \"/wrapped-dependency/\",\n        \"/wrapped-gen-dependency/\",\n        \"/async-wrapped-dependency/\",\n        \"/async-wrapped-gen-dependency/\",\n        \"/wrapped-class-instance-dependency/\",\n        \"/wrapped-class-instance-async-dependency/\",\n        \"/wrapped-class-instance-gen-dependency/\",\n        \"/wrapped-class-instance-async-gen-dependency/\",\n        \"/class-instance-wrapped-dependency/\",\n        \"/class-instance-wrapped-async-dependency/\",\n        \"/class-instance-async-wrapped-dependency/\",\n        \"/class-instance-async-wrapped-async-dependency/\",\n        \"/class-instance-wrapped-gen-dependency/\",\n        \"/class-instance-wrapped-async-gen-dependency/\",\n        \"/class-instance-async-wrapped-gen-dependency/\",\n        \"/class-instance-async-wrapped-gen-async-dependency/\",\n        \"/wrapped-class-dependency/\",\n        \"/wrapped-endpoint/\",\n        \"/async-wrapped-endpoint/\",\n        \"/wrapped-dependency-async-wrapper/\",\n        \"/wrapped-gen-dependency-async-wrapper/\",\n        \"/async-wrapped-dependency-async-wrapper/\",\n        \"/async-wrapped-gen-dependency-async-wrapper/\",\n        \"/wrapped-class-instance-dependency-async-wrapper/\",\n        \"/wrapped-class-instance-async-dependency-async-wrapper/\",\n        \"/wrapped-class-dependency-async-wrapper/\",\n        \"/wrapped-endpoint-async-wrapper/\",\n        \"/async-wrapped-endpoint-async-wrapper/\",\n    ],\n)\ndef test_class_dependency(route):\n    response = client.get(route)\n    assert response.status_code == 200, response.text\n    assert response.json() is True\n"
  },
  {
    "path": "tests/test_dependency_yield_except_httpexception.py",
    "content": "import pytest\nfrom fastapi import Body, Depends, FastAPI, HTTPException\nfrom fastapi.testclient import TestClient\n\ninitial_fake_database = {\"rick\": \"Rick Sanchez\"}\n\nfake_database = initial_fake_database.copy()\n\ninitial_state = {\"except\": False, \"finally\": False}\n\nstate = initial_state.copy()\n\napp = FastAPI()\n\n\nasync def get_database():\n    temp_database = fake_database.copy()\n    try:\n        yield temp_database\n        fake_database.update(temp_database)\n    except HTTPException:\n        state[\"except\"] = True\n        raise\n    finally:\n        state[\"finally\"] = True\n\n\n@app.put(\"/invalid-user/{user_id}\")\ndef put_invalid_user(\n    user_id: str, name: str = Body(), db: dict = Depends(get_database)\n):\n    db[user_id] = name\n    raise HTTPException(status_code=400, detail=\"Invalid user\")\n\n\n@app.put(\"/user/{user_id}\")\ndef put_user(user_id: str, name: str = Body(), db: dict = Depends(get_database)):\n    db[user_id] = name\n    return {\"message\": \"OK\"}\n\n\n@pytest.fixture(autouse=True)\ndef reset_state_and_db():\n    global fake_database\n    global state\n    fake_database = initial_fake_database.copy()\n    state = initial_state.copy()\n\n\nclient = TestClient(app)\n\n\ndef test_dependency_gets_exception():\n    assert state[\"except\"] is False\n    assert state[\"finally\"] is False\n    response = client.put(\"/invalid-user/rick\", json=\"Morty\")\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"Invalid user\"}\n    assert state[\"except\"] is True\n    assert state[\"finally\"] is True\n    assert fake_database[\"rick\"] == \"Rick Sanchez\"\n\n\ndef test_dependency_no_exception():\n    assert state[\"except\"] is False\n    assert state[\"finally\"] is False\n    response = client.put(\"/user/rick\", json=\"Morty\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"OK\"}\n    assert state[\"except\"] is False\n    assert state[\"finally\"] is True\n    assert fake_database[\"rick\"] == \"Morty\"\n"
  },
  {
    "path": "tests/test_dependency_yield_scope.py",
    "content": "import json\nfrom typing import Annotated, Any\n\nimport pytest\nfrom fastapi import APIRouter, Depends, FastAPI, HTTPException\nfrom fastapi.exceptions import FastAPIError\nfrom fastapi.responses import StreamingResponse\nfrom fastapi.testclient import TestClient\n\n\nclass Session:\n    def __init__(self) -> None:\n        self.open = True\n\n\ndef dep_session() -> Any:\n    s = Session()\n    yield s\n    s.open = False\n\n\ndef raise_after_yield() -> Any:\n    yield\n    raise HTTPException(status_code=503, detail=\"Exception after yield\")\n\n\nSessionFuncDep = Annotated[Session, Depends(dep_session, scope=\"function\")]\nSessionRequestDep = Annotated[Session, Depends(dep_session, scope=\"request\")]\nSessionDefaultDep = Annotated[Session, Depends(dep_session)]\n\n\nclass NamedSession:\n    def __init__(self, name: str = \"default\") -> None:\n        self.name = name\n        self.open = True\n\n\ndef get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep) -> Any:\n    assert session is session_b\n    named_session = NamedSession(name=\"named\")\n    yield named_session, session_b\n    named_session.open = False\n\n\nNamedSessionsDep = Annotated[tuple[NamedSession, Session], Depends(get_named_session)]\n\n\ndef get_named_func_session(session: SessionFuncDep) -> Any:\n    named_session = NamedSession(name=\"named\")\n    yield named_session, session\n    named_session.open = False\n\n\ndef get_named_regular_func_session(session: SessionFuncDep) -> Any:\n    named_session = NamedSession(name=\"named\")\n    return named_session, session\n\n\nBrokenSessionsDep = Annotated[\n    tuple[NamedSession, Session], Depends(get_named_func_session)\n]\nNamedSessionsFuncDep = Annotated[\n    tuple[NamedSession, Session], Depends(get_named_func_session, scope=\"function\")\n]\n\nRegularSessionsDep = Annotated[\n    tuple[NamedSession, Session], Depends(get_named_regular_func_session)\n]\n\napp = FastAPI()\nrouter = APIRouter()\n\n\n@router.get(\"/\")\ndef get_index():\n    return {\"status\": \"ok\"}\n\n\n@app.get(\"/function-scope\")\ndef function_scope(session: SessionFuncDep) -> Any:\n    def iter_data():\n        yield json.dumps({\"is_open\": session.open})\n\n    return StreamingResponse(iter_data())\n\n\n@app.get(\"/request-scope\")\ndef request_scope(session: SessionRequestDep) -> Any:\n    def iter_data():\n        yield json.dumps({\"is_open\": session.open})\n\n    return StreamingResponse(iter_data())\n\n\n@app.get(\"/two-scopes\")\ndef get_stream_session(\n    function_session: SessionFuncDep, request_session: SessionRequestDep\n) -> Any:\n    def iter_data():\n        yield json.dumps(\n            {\"func_is_open\": function_session.open, \"req_is_open\": request_session.open}\n        )\n\n    return StreamingResponse(iter_data())\n\n\n@app.get(\"/sub\")\ndef get_sub(sessions: NamedSessionsDep) -> Any:\n    def iter_data():\n        yield json.dumps(\n            {\"named_session_open\": sessions[0].open, \"session_open\": sessions[1].open}\n        )\n\n    return StreamingResponse(iter_data())\n\n\n@app.get(\"/named-function-scope\")\ndef get_named_function_scope(sessions: NamedSessionsFuncDep) -> Any:\n    def iter_data():\n        yield json.dumps(\n            {\"named_session_open\": sessions[0].open, \"session_open\": sessions[1].open}\n        )\n\n    return StreamingResponse(iter_data())\n\n\n@app.get(\"/regular-function-scope\")\ndef get_regular_function_scope(sessions: RegularSessionsDep) -> Any:\n    def iter_data():\n        yield json.dumps(\n            {\"named_session_open\": sessions[0].open, \"session_open\": sessions[1].open}\n        )\n\n    return StreamingResponse(iter_data())\n\n\napp.include_router(\n    prefix=\"/router-scope-function\",\n    router=router,\n    dependencies=[Depends(raise_after_yield, scope=\"function\")],\n)\n\napp.include_router(\n    prefix=\"/router-scope-request\",\n    router=router,\n    dependencies=[Depends(raise_after_yield, scope=\"request\")],\n)\n\nclient = TestClient(app)\n\n\ndef test_function_scope() -> None:\n    response = client.get(\"/function-scope\")\n    assert response.status_code == 200\n    data = response.json()\n    assert data[\"is_open\"] is False\n\n\ndef test_request_scope() -> None:\n    response = client.get(\"/request-scope\")\n    assert response.status_code == 200\n    data = response.json()\n    assert data[\"is_open\"] is True\n\n\ndef test_two_scopes() -> None:\n    response = client.get(\"/two-scopes\")\n    assert response.status_code == 200\n    data = response.json()\n    assert data[\"func_is_open\"] is False\n    assert data[\"req_is_open\"] is True\n\n\ndef test_sub() -> None:\n    response = client.get(\"/sub\")\n    assert response.status_code == 200\n    data = response.json()\n    assert data[\"named_session_open\"] is True\n    assert data[\"session_open\"] is True\n\n\ndef test_broken_scope() -> None:\n    with pytest.raises(\n        FastAPIError,\n        match='The dependency \"get_named_func_session\" has a scope of \"request\", it cannot depend on dependencies with scope \"function\"',\n    ):\n\n        @app.get(\"/broken-scope\")\n        def get_broken(sessions: BrokenSessionsDep) -> Any:  # pragma: no cover\n            pass\n\n\ndef test_named_function_scope() -> None:\n    response = client.get(\"/named-function-scope\")\n    assert response.status_code == 200\n    data = response.json()\n    assert data[\"named_session_open\"] is False\n    assert data[\"session_open\"] is False\n\n\ndef test_regular_function_scope() -> None:\n    response = client.get(\"/regular-function-scope\")\n    assert response.status_code == 200\n    data = response.json()\n    assert data[\"named_session_open\"] is True\n    assert data[\"session_open\"] is False\n\n\ndef test_router_level_dep_scope_function() -> None:\n    response = client.get(\"/router-scope-function/\")\n    assert response.status_code == 503\n    assert response.json() == {\"detail\": \"Exception after yield\"}\n\n\ndef test_router_level_dep_scope_request() -> None:\n    with TestClient(app, raise_server_exceptions=False) as client:\n        response = client.get(\"/router-scope-request/\")\n        assert response.status_code == 200\n        assert response.json() == {\"status\": \"ok\"}\n\n\ndef test_app_level_dep_scope_function() -> None:\n    app = FastAPI(dependencies=[Depends(raise_after_yield, scope=\"function\")])\n\n    @app.get(\"/app-scope-function\")\n    def get_app_scope_function():\n        return {\"status\": \"ok\"}\n\n    with TestClient(app) as client:\n        response = client.get(\"/app-scope-function\")\n        assert response.status_code == 503\n        assert response.json() == {\"detail\": \"Exception after yield\"}\n\n\ndef test_app_level_dep_scope_request() -> None:\n    app = FastAPI(dependencies=[Depends(raise_after_yield, scope=\"request\")])\n\n    @app.get(\"/app-scope-request\")\n    def get_app_scope_request():\n        return {\"status\": \"ok\"}\n\n    with TestClient(app, raise_server_exceptions=False) as client:\n        response = client.get(\"/app-scope-request\")\n        assert response.status_code == 200\n        assert response.json() == {\"status\": \"ok\"}\n"
  },
  {
    "path": "tests/test_dependency_yield_scope_websockets.py",
    "content": "from contextvars import ContextVar\nfrom typing import Annotated, Any\n\nimport pytest\nfrom fastapi import Depends, FastAPI, WebSocket\nfrom fastapi.exceptions import FastAPIError\nfrom fastapi.testclient import TestClient\n\nglobal_context: ContextVar[dict[str, Any]] = ContextVar(\"global_context\", default={})  # noqa: B039\n\n\nclass Session:\n    def __init__(self) -> None:\n        self.open = True\n\n\nasync def dep_session() -> Any:\n    s = Session()\n    yield s\n    s.open = False\n    global_state = global_context.get()\n    global_state[\"session_closed\"] = True\n\n\nSessionFuncDep = Annotated[Session, Depends(dep_session, scope=\"function\")]\nSessionRequestDep = Annotated[Session, Depends(dep_session, scope=\"request\")]\nSessionDefaultDep = Annotated[Session, Depends(dep_session)]\n\n\nclass NamedSession:\n    def __init__(self, name: str = \"default\") -> None:\n        self.name = name\n        self.open = True\n\n\ndef get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep) -> Any:\n    assert session is session_b\n    named_session = NamedSession(name=\"named\")\n    yield named_session, session_b\n    named_session.open = False\n    global_state = global_context.get()\n    global_state[\"named_session_closed\"] = True\n\n\nNamedSessionsDep = Annotated[tuple[NamedSession, Session], Depends(get_named_session)]\n\n\ndef get_named_func_session(session: SessionFuncDep) -> Any:\n    named_session = NamedSession(name=\"named\")\n    yield named_session, session\n    named_session.open = False\n    global_state = global_context.get()\n    global_state[\"named_func_session_closed\"] = True\n\n\ndef get_named_regular_func_session(session: SessionFuncDep) -> Any:\n    named_session = NamedSession(name=\"named\")\n    return named_session, session\n\n\nBrokenSessionsDep = Annotated[\n    tuple[NamedSession, Session], Depends(get_named_func_session)\n]\nNamedSessionsFuncDep = Annotated[\n    tuple[NamedSession, Session], Depends(get_named_func_session, scope=\"function\")\n]\n\nRegularSessionsDep = Annotated[\n    tuple[NamedSession, Session], Depends(get_named_regular_func_session)\n]\n\napp = FastAPI()\n\n\n@app.websocket(\"/function-scope\")\nasync def function_scope(websocket: WebSocket, session: SessionFuncDep) -> Any:\n    await websocket.accept()\n    await websocket.send_json({\"is_open\": session.open})\n\n\n@app.websocket(\"/request-scope\")\nasync def request_scope(websocket: WebSocket, session: SessionRequestDep) -> Any:\n    await websocket.accept()\n    await websocket.send_json({\"is_open\": session.open})\n\n\n@app.websocket(\"/two-scopes\")\nasync def get_stream_session(\n    websocket: WebSocket,\n    function_session: SessionFuncDep,\n    request_session: SessionRequestDep,\n) -> Any:\n    await websocket.accept()\n    await websocket.send_json(\n        {\"func_is_open\": function_session.open, \"req_is_open\": request_session.open}\n    )\n\n\n@app.websocket(\"/sub\")\nasync def get_sub(websocket: WebSocket, sessions: NamedSessionsDep) -> Any:\n    await websocket.accept()\n    await websocket.send_json(\n        {\"named_session_open\": sessions[0].open, \"session_open\": sessions[1].open}\n    )\n\n\n@app.websocket(\"/named-function-scope\")\nasync def get_named_function_scope(\n    websocket: WebSocket, sessions: NamedSessionsFuncDep\n) -> Any:\n    await websocket.accept()\n    await websocket.send_json(\n        {\"named_session_open\": sessions[0].open, \"session_open\": sessions[1].open}\n    )\n\n\n@app.websocket(\"/regular-function-scope\")\nasync def get_regular_function_scope(\n    websocket: WebSocket, sessions: RegularSessionsDep\n) -> Any:\n    await websocket.accept()\n    await websocket.send_json(\n        {\"named_session_open\": sessions[0].open, \"session_open\": sessions[1].open}\n    )\n\n\nclient = TestClient(app)\n\n\ndef test_function_scope() -> None:\n    global_context.set({})\n    global_state = global_context.get()\n    with client.websocket_connect(\"/function-scope\") as websocket:\n        data = websocket.receive_json()\n    assert data[\"is_open\"] is True\n    assert global_state[\"session_closed\"] is True\n\n\ndef test_request_scope() -> None:\n    global_context.set({})\n    global_state = global_context.get()\n    with client.websocket_connect(\"/request-scope\") as websocket:\n        data = websocket.receive_json()\n    assert data[\"is_open\"] is True\n    assert global_state[\"session_closed\"] is True\n\n\ndef test_two_scopes() -> None:\n    global_context.set({})\n    global_state = global_context.get()\n    with client.websocket_connect(\"/two-scopes\") as websocket:\n        data = websocket.receive_json()\n    assert data[\"func_is_open\"] is True\n    assert data[\"req_is_open\"] is True\n    assert global_state[\"session_closed\"] is True\n\n\ndef test_sub() -> None:\n    global_context.set({})\n    global_state = global_context.get()\n    with client.websocket_connect(\"/sub\") as websocket:\n        data = websocket.receive_json()\n    assert data[\"named_session_open\"] is True\n    assert data[\"session_open\"] is True\n    assert global_state[\"session_closed\"] is True\n    assert global_state[\"named_session_closed\"] is True\n\n\ndef test_broken_scope() -> None:\n    with pytest.raises(\n        FastAPIError,\n        match='The dependency \"get_named_func_session\" has a scope of \"request\", it cannot depend on dependencies with scope \"function\"',\n    ):\n\n        @app.websocket(\"/broken-scope\")\n        async def get_broken(\n            websocket: WebSocket, sessions: BrokenSessionsDep\n        ) -> Any:  # pragma: no cover\n            pass\n\n\ndef test_named_function_scope() -> None:\n    global_context.set({})\n    global_state = global_context.get()\n    with client.websocket_connect(\"/named-function-scope\") as websocket:\n        data = websocket.receive_json()\n    assert data[\"named_session_open\"] is True\n    assert data[\"session_open\"] is True\n    assert global_state[\"session_closed\"] is True\n    assert global_state[\"named_func_session_closed\"] is True\n\n\ndef test_regular_function_scope() -> None:\n    global_context.set({})\n    global_state = global_context.get()\n    with client.websocket_connect(\"/regular-function-scope\") as websocket:\n        data = websocket.receive_json()\n    assert data[\"named_session_open\"] is True\n    assert data[\"session_open\"] is True\n    assert global_state[\"session_closed\"] is True\n"
  },
  {
    "path": "tests/test_depends_hashable.py",
    "content": "# This is more or less a workaround to make Depends and Security hashable\n# as other tools that use them depend on that\n# Ref: https://github.com/fastapi/fastapi/pull/14320\n\nfrom fastapi import Depends, Security\n\n\ndef dep():\n    pass\n\n\ndef test_depends_hashable():\n    dep()  # just for coverage\n    d1 = Depends(dep)\n    d2 = Depends(dep)\n    d3 = Depends(dep, scope=\"function\")\n    d4 = Depends(dep, scope=\"function\")\n\n    s1 = Security(dep)\n    s2 = Security(dep)\n\n    assert hash(d1) == hash(d2)\n    assert hash(s1) == hash(s2)\n    assert hash(d1) != hash(d3)\n    assert hash(d3) == hash(d4)\n"
  },
  {
    "path": "tests/test_deprecated_openapi_prefix.py",
    "content": "from fastapi import FastAPI, Request\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI(openapi_prefix=\"/api/v1\")\n\n\n@app.get(\"/app\")\ndef read_main(request: Request):\n    return {\"message\": \"Hello World\", \"root_path\": request.scope.get(\"root_path\")}\n\n\nclient = TestClient(app)\n\n\ndef test_main():\n    response = client.get(\"/app\")\n    assert response.status_code == 200\n    assert response.json() == {\"message\": \"Hello World\", \"root_path\": \"/api/v1\"}\n\n\ndef test_openapi():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/app\": {\n                    \"get\": {\n                        \"summary\": \"Read Main\",\n                        \"operationId\": \"read_main_app_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n            \"servers\": [{\"url\": \"/api/v1\"}],\n        }\n    )\n"
  },
  {
    "path": "tests/test_deprecated_responses.py",
    "content": "import warnings\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.exceptions import FastAPIDeprecationWarning\nfrom fastapi.responses import ORJSONResponse, UJSONResponse\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\nfrom tests.utils import needs_orjson, needs_ujson\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\n# ORJSON\n\n\ndef _make_orjson_app() -> FastAPI:\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", FastAPIDeprecationWarning)\n        app = FastAPI(default_response_class=ORJSONResponse)\n\n    @app.get(\"/items\")\n    def get_items() -> Item:\n        return Item(name=\"widget\", price=9.99)\n\n    return app\n\n\n@needs_orjson\ndef test_orjson_response_returns_correct_data():\n    app = _make_orjson_app()\n    client = TestClient(app)\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", FastAPIDeprecationWarning)\n        response = client.get(\"/items\")\n    assert response.status_code == 200\n    assert response.json() == {\"name\": \"widget\", \"price\": 9.99}\n\n\n@needs_orjson\ndef test_orjson_response_emits_deprecation_warning():\n    with pytest.warns(FastAPIDeprecationWarning, match=\"ORJSONResponse is deprecated\"):\n        ORJSONResponse(content={\"hello\": \"world\"})\n\n\n# UJSON\n\n\ndef _make_ujson_app() -> FastAPI:\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", FastAPIDeprecationWarning)\n        app = FastAPI(default_response_class=UJSONResponse)\n\n    @app.get(\"/items\")\n    def get_items() -> Item:\n        return Item(name=\"widget\", price=9.99)\n\n    return app\n\n\n@needs_ujson\ndef test_ujson_response_returns_correct_data():\n    app = _make_ujson_app()\n    client = TestClient(app)\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", FastAPIDeprecationWarning)\n        response = client.get(\"/items\")\n    assert response.status_code == 200\n    assert response.json() == {\"name\": \"widget\", \"price\": 9.99}\n\n\n@needs_ujson\ndef test_ujson_response_emits_deprecation_warning():\n    with pytest.warns(FastAPIDeprecationWarning, match=\"UJSONResponse is deprecated\"):\n        UJSONResponse(content={\"hello\": \"world\"})\n"
  },
  {
    "path": "tests/test_dump_json_fast_path.py",
    "content": "from unittest.mock import patch\n\nfrom fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\napp = FastAPI()\n\n\n@app.get(\"/default\")\ndef get_default() -> Item:\n    return Item(name=\"widget\", price=9.99)\n\n\n@app.get(\"/explicit\", response_class=JSONResponse)\ndef get_explicit() -> Item:\n    return Item(name=\"widget\", price=9.99)\n\n\nclient = TestClient(app)\n\n\ndef test_default_response_class_skips_json_dumps():\n    \"\"\"When no response_class is set, the fast path serializes directly to\n    JSON bytes via Pydantic's dump_json and never calls json.dumps.\"\"\"\n    with patch(\n        \"starlette.responses.json.dumps\", wraps=__import__(\"json\").dumps\n    ) as mock_dumps:\n        response = client.get(\"/default\")\n    assert response.status_code == 200\n    assert response.json() == {\"name\": \"widget\", \"price\": 9.99}\n    mock_dumps.assert_not_called()\n\n\ndef test_explicit_response_class_uses_json_dumps():\n    \"\"\"When response_class is explicitly set to JSONResponse, the normal path\n    is used and json.dumps is called via JSONResponse.render().\"\"\"\n    with patch(\n        \"starlette.responses.json.dumps\", wraps=__import__(\"json\").dumps\n    ) as mock_dumps:\n        response = client.get(\"/explicit\")\n    assert response.status_code == 200\n    assert response.json() == {\"name\": \"widget\", \"price\": 9.99}\n    mock_dumps.assert_called_once()\n"
  },
  {
    "path": "tests/test_duplicate_models_openapi.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Model(BaseModel):\n    pass\n\n\nclass Model2(BaseModel):\n    a: Model\n\n\nclass Model3(BaseModel):\n    c: Model\n    d: Model2\n\n\n@app.get(\"/\", response_model=Model3)\ndef f():\n    return {\"c\": {}, \"d\": {\"a\": {}}}\n\n\nclient = TestClient(app)\n\n\ndef test_get_api_route():\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"c\": {}, \"d\": {\"a\": {}}}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"F\",\n                        \"operationId\": \"f__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Model3\"\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Model\": {\"title\": \"Model\", \"type\": \"object\", \"properties\": {}},\n                    \"Model2\": {\n                        \"title\": \"Model2\",\n                        \"required\": [\"a\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"a\": {\"$ref\": \"#/components/schemas/Model\"}},\n                    },\n                    \"Model3\": {\n                        \"title\": \"Model3\",\n                        \"required\": [\"c\", \"d\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"c\": {\"$ref\": \"#/components/schemas/Model\"},\n                            \"d\": {\"$ref\": \"#/components/schemas/Model2\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_empty_router.py",
    "content": "import pytest\nfrom fastapi import APIRouter, FastAPI\nfrom fastapi.exceptions import FastAPIError\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\nrouter = APIRouter()\n\n\n@router.get(\"\")\ndef get_empty():\n    return [\"OK\"]\n\n\napp.include_router(router, prefix=\"/prefix\")\n\n\nclient = TestClient(app)\n\n\ndef test_use_empty():\n    with client:\n        response = client.get(\"/prefix\")\n        assert response.status_code == 200, response.text\n        assert response.json() == [\"OK\"]\n\n        response = client.get(\"/prefix/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == [\"OK\"]\n\n\ndef test_include_empty():\n    # if both include and router.path are empty - it should raise exception\n    with pytest.raises(FastAPIError):\n        app.include_router(router)\n"
  },
  {
    "path": "tests/test_enforce_once_required_parameter.py",
    "content": "from fastapi import Depends, FastAPI, Query\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\ndef _get_client_key(client_id: str = Query(...)) -> str:\n    return f\"{client_id}_key\"\n\n\ndef _get_client_tag(client_id: str | None = Query(None)) -> str | None:\n    if client_id is None:\n        return None\n    return f\"{client_id}_tag\"\n\n\n@app.get(\"/foo\")\ndef foo_handler(\n    client_key: str = Depends(_get_client_key),\n    client_tag: str | None = Depends(_get_client_tag),\n):\n    return {\"client_id\": client_key, \"client_tag\": client_tag}\n\n\nclient = TestClient(app)\n\n\ndef test_get_invalid():\n    response = client.get(\"/foo\")\n    assert response.status_code == 422\n\n\ndef test_get_valid():\n    response = client.get(\"/foo\", params={\"client_id\": \"bar\"})\n    assert response.status_code == 200\n    assert response.json() == {\"client_id\": \"bar_key\", \"client_tag\": \"bar_tag\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            }\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                }\n            },\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/foo\": {\n                    \"get\": {\n                        \"operationId\": \"foo_handler_foo_get\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"query\",\n                                \"name\": \"client_id\",\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Client Id\", \"type\": \"string\"},\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Foo Handler\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_exception_handlers.py",
    "content": "import pytest\nfrom fastapi import Depends, FastAPI, HTTPException\nfrom fastapi.exceptions import RequestValidationError\nfrom fastapi.testclient import TestClient\nfrom starlette.responses import JSONResponse\n\n\ndef http_exception_handler(request, exception):\n    return JSONResponse({\"exception\": \"http-exception\"})\n\n\ndef request_validation_exception_handler(request, exception):\n    return JSONResponse({\"exception\": \"request-validation\"})\n\n\ndef server_error_exception_handler(request, exception):\n    return JSONResponse(status_code=500, content={\"exception\": \"server-error\"})\n\n\napp = FastAPI(\n    exception_handlers={\n        HTTPException: http_exception_handler,\n        RequestValidationError: request_validation_exception_handler,\n        Exception: server_error_exception_handler,\n    }\n)\n\nclient = TestClient(app)\n\n\ndef raise_value_error():\n    raise ValueError()\n\n\ndef dependency_with_yield():\n    yield raise_value_error()\n\n\n@app.get(\"/dependency-with-yield\", dependencies=[Depends(dependency_with_yield)])\ndef with_yield(): ...\n\n\n@app.get(\"/http-exception\")\ndef route_with_http_exception():\n    raise HTTPException(status_code=400)\n\n\n@app.get(\"/request-validation/{param}/\")\ndef route_with_request_validation_exception(param: int):\n    pass  # pragma: no cover\n\n\n@app.get(\"/server-error\")\ndef route_with_server_error():\n    raise RuntimeError(\"Oops!\")\n\n\ndef test_override_http_exception():\n    response = client.get(\"/http-exception\")\n    assert response.status_code == 200\n    assert response.json() == {\"exception\": \"http-exception\"}\n\n\ndef test_override_request_validation_exception():\n    response = client.get(\"/request-validation/invalid\")\n    assert response.status_code == 200\n    assert response.json() == {\"exception\": \"request-validation\"}\n\n\ndef test_override_server_error_exception_raises():\n    with pytest.raises(RuntimeError):\n        client.get(\"/server-error\")\n\n\ndef test_override_server_error_exception_response():\n    client = TestClient(app, raise_server_exceptions=False)\n    response = client.get(\"/server-error\")\n    assert response.status_code == 500\n    assert response.json() == {\"exception\": \"server-error\"}\n\n\ndef test_traceback_for_dependency_with_yield():\n    client = TestClient(app, raise_server_exceptions=True)\n    with pytest.raises(ValueError) as exc_info:\n        client.get(\"/dependency-with-yield\")\n    last_frame = exc_info.traceback[-1]\n    assert str(last_frame.path) == __file__\n    assert last_frame.lineno == raise_value_error.__code__.co_firstlineno\n"
  },
  {
    "path": "tests/test_extra_routes.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float | None = None\n\n\n@app.api_route(\"/items/{item_id}\", methods=[\"GET\"])\ndef get_items(item_id: str):\n    return {\"item_id\": item_id}\n\n\ndef get_not_decorated(item_id: str):\n    return {\"item_id\": item_id}\n\n\napp.add_api_route(\"/items-not-decorated/{item_id}\", get_not_decorated)\n\n\n@app.delete(\"/items/{item_id}\")\ndef delete_item(item_id: str, item: Item):\n    return {\"item_id\": item_id, \"item\": item}\n\n\n@app.head(\"/items/{item_id}\")\ndef head_item(item_id: str):\n    return JSONResponse(None, headers={\"x-fastapi-item-id\": item_id})\n\n\n@app.options(\"/items/{item_id}\")\ndef options_item(item_id: str):\n    return JSONResponse(None, headers={\"x-fastapi-item-id\": item_id})\n\n\n@app.patch(\"/items/{item_id}\")\ndef patch_item(item_id: str, item: Item):\n    return {\"item_id\": item_id, \"item\": item}\n\n\n@app.trace(\"/items/{item_id}\")\ndef trace_item(item_id: str):\n    return JSONResponse(None, media_type=\"message/http\")\n\n\nclient = TestClient(app)\n\n\ndef test_get_api_route():\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": \"foo\"}\n\n\ndef test_get_api_route_not_decorated():\n    response = client.get(\"/items-not-decorated/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": \"foo\"}\n\n\ndef test_delete():\n    response = client.request(\"DELETE\", \"/items/foo\", json={\"name\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": \"foo\", \"item\": {\"name\": \"Foo\", \"price\": None}}\n\n\ndef test_head():\n    response = client.head(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"x-fastapi-item-id\"] == \"foo\"\n\n\ndef test_options():\n    response = client.options(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"x-fastapi-item-id\"] == \"foo\"\n\n\ndef test_patch():\n    response = client.patch(\"/items/foo\", json={\"name\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": \"foo\", \"item\": {\"name\": \"Foo\", \"price\": None}}\n\n\ndef test_trace():\n    response = client.request(\"trace\", \"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"message/http\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Items\",\n                        \"operationId\": \"get_items_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    },\n                    \"delete\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Delete Item\",\n                        \"operationId\": \"delete_item_items__item_id__delete\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    },\n                    \"options\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Options Item\",\n                        \"operationId\": \"options_item_items__item_id__options\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    },\n                    \"head\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Head Item\",\n                        \"operationId\": \"head_item_items__item_id__head\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    },\n                    \"patch\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Patch Item\",\n                        \"operationId\": \"patch_item_items__item_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    },\n                    \"trace\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Trace Item\",\n                        \"operationId\": \"trace_item_items__item_id__trace\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    },\n                },\n                \"/items-not-decorated/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Get Not Decorated\",\n                        \"operationId\": \"get_not_decorated_items_not_decorated__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_fastapi_cli.py",
    "content": "import os\nimport subprocess\nimport sys\nfrom unittest.mock import patch\n\nimport fastapi.cli\nimport pytest\n\n\ndef test_fastapi_cli():\n    result = subprocess.run(\n        [\n            sys.executable,\n            \"-m\",\n            \"coverage\",\n            \"run\",\n            \"-m\",\n            \"fastapi\",\n            \"dev\",\n            \"non_existent_file.py\",\n        ],\n        capture_output=True,\n        encoding=\"utf-8\",\n        env={**os.environ, \"PYTHONIOENCODING\": \"utf-8\"},\n    )\n    assert result.returncode == 1, result.stdout\n    assert \"Path does not exist non_existent_file.py\" in result.stdout\n\n\ndef test_fastapi_cli_not_installed():\n    with patch.object(fastapi.cli, \"cli_main\", None):\n        with pytest.raises(RuntimeError) as exc_info:\n            fastapi.cli.main()\n        assert \"To use the fastapi command, please install\" in str(exc_info.value)\n"
  },
  {
    "path": "tests/test_file_and_form_order_issue_9116.py",
    "content": "\"\"\"\nRegression test, Error 422 if Form is declared before File\nSee https://github.com/tiangolo/fastapi/discussions/9116\n\"\"\"\n\nfrom pathlib import Path\nfrom typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, File, Form\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.post(\"/file_before_form\")\ndef file_before_form(\n    file: bytes = File(),\n    city: str = Form(),\n):\n    return {\"file_content\": file, \"city\": city}\n\n\n@app.post(\"/file_after_form\")\ndef file_after_form(\n    city: str = Form(),\n    file: bytes = File(),\n):\n    return {\"file_content\": file, \"city\": city}\n\n\n@app.post(\"/file_list_before_form\")\ndef file_list_before_form(\n    files: Annotated[list[bytes], File()],\n    city: Annotated[str, Form()],\n):\n    return {\"file_contents\": files, \"city\": city}\n\n\n@app.post(\"/file_list_after_form\")\ndef file_list_after_form(\n    city: Annotated[str, Form()],\n    files: Annotated[list[bytes], File()],\n):\n    return {\"file_contents\": files, \"city\": city}\n\n\nclient = TestClient(app)\n\n\n@pytest.fixture\ndef tmp_file_1(tmp_path: Path) -> Path:\n    f = tmp_path / \"example1.txt\"\n    f.write_text(\"foo\")\n    return f\n\n\n@pytest.fixture\ndef tmp_file_2(tmp_path: Path) -> Path:\n    f = tmp_path / \"example2.txt\"\n    f.write_text(\"bar\")\n    return f\n\n\n@pytest.mark.parametrize(\"endpoint_path\", (\"/file_before_form\", \"/file_after_form\"))\ndef test_file_form_order(endpoint_path: str, tmp_file_1: Path):\n    response = client.post(\n        url=endpoint_path,\n        data={\"city\": \"Thimphou\"},\n        files={\"file\": (tmp_file_1.name, tmp_file_1.read_bytes())},\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_content\": \"foo\", \"city\": \"Thimphou\"}\n\n\n@pytest.mark.parametrize(\n    \"endpoint_path\", (\"/file_list_before_form\", \"/file_list_after_form\")\n)\ndef test_file_list_form_order(endpoint_path: str, tmp_file_1: Path, tmp_file_2: Path):\n    response = client.post(\n        url=endpoint_path,\n        data={\"city\": \"Thimphou\"},\n        files=(\n            (\"files\", (tmp_file_1.name, tmp_file_1.read_bytes())),\n            (\"files\", (tmp_file_2.name, tmp_file_2.read_bytes())),\n        ),\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_contents\": [\"foo\", \"bar\"], \"city\": \"Thimphou\"}\n"
  },
  {
    "path": "tests/test_filter_pydantic_sub_model_pv2.py",
    "content": "import pytest\nfrom dirty_equals import HasRepr\nfrom fastapi import Depends, FastAPI\nfrom fastapi.exceptions import ResponseValidationError\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(name=\"client\")\ndef get_client():\n    from pydantic import BaseModel, ValidationInfo, field_validator\n\n    app = FastAPI()\n\n    class ModelB(BaseModel):\n        username: str\n\n    class ModelC(ModelB):\n        password: str\n\n    class ModelA(BaseModel):\n        name: str\n        description: str | None = None\n        foo: ModelB\n        tags: dict[str, str] = {}\n\n        @field_validator(\"name\")\n        def lower_username(cls, name: str, info: ValidationInfo):\n            if not name.endswith(\"A\"):\n                raise ValueError(\"name must end in A\")\n            return name\n\n    async def get_model_c() -> ModelC:\n        return ModelC(username=\"test-user\", password=\"test-password\")\n\n    @app.get(\"/model/{name}\", response_model=ModelA)\n    async def get_model_a(name: str, model_c=Depends(get_model_c)):\n        return {\n            \"name\": name,\n            \"description\": \"model-a-desc\",\n            \"foo\": model_c,\n            \"tags\": {\"key1\": \"value1\", \"key2\": \"value2\"},\n        }\n\n    client = TestClient(app)\n    return client\n\n\ndef test_filter_sub_model(client: TestClient):\n    response = client.get(\"/model/modelA\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"modelA\",\n        \"description\": \"model-a-desc\",\n        \"foo\": {\"username\": \"test-user\"},\n        \"tags\": {\"key1\": \"value1\", \"key2\": \"value2\"},\n    }\n\n\ndef test_validator_is_cloned(client: TestClient):\n    with pytest.raises(ResponseValidationError) as err:\n        client.get(\"/model/modelX\")\n    assert err.value.errors() == [\n        {\n            \"type\": \"value_error\",\n            \"loc\": (\"response\", \"name\"),\n            \"msg\": \"Value error, name must end in A\",\n            \"input\": \"modelX\",\n            \"ctx\": {\"error\": HasRepr(\"ValueError('name must end in A')\")},\n        }\n    ]\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/model/{name}\": {\n                    \"get\": {\n                        \"summary\": \"Get Model A\",\n                        \"operationId\": \"get_model_a_model__name__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Name\", \"type\": \"string\"},\n                                \"name\": \"name\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ModelA\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ModelA\": {\n                        \"title\": \"ModelA\",\n                        \"required\": [\"name\", \"foo\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"foo\": {\"$ref\": \"#/components/schemas/ModelB\"},\n                            \"tags\": {\n                                \"additionalProperties\": {\"type\": \"string\"},\n                                \"type\": \"object\",\n                                \"title\": \"Tags\",\n                                \"default\": {},\n                            },\n                        },\n                    },\n                    \"ModelB\": {\n                        \"title\": \"ModelB\",\n                        \"required\": [\"username\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"}\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_form_default.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, File, Form\nfrom starlette.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.post(\"/urlencoded\")\nasync def post_url_encoded(age: Annotated[int | None, Form()] = None):\n    return age\n\n\n@app.post(\"/multipart\")\nasync def post_multi_part(\n    age: Annotated[int | None, Form()] = None,\n    file: Annotated[bytes | None, File()] = None,\n):\n    return {\"file\": file, \"age\": age}\n\n\nclient = TestClient(app)\n\n\ndef test_form_default_url_encoded():\n    response = client.post(\"/urlencoded\", data={\"age\": \"\"})\n    assert response.status_code == 200\n    assert response.text == \"null\"\n\n\ndef test_form_default_multi_part():\n    response = client.post(\"/multipart\", data={\"age\": \"\"})\n    assert response.status_code == 200\n    assert response.json() == {\"file\": None, \"age\": None}\n"
  },
  {
    "path": "tests/test_forms_from_non_typing_sequences.py",
    "content": "from fastapi import FastAPI, Form\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.post(\"/form/python-list\")\ndef post_form_param_list(items: list = Form()):\n    return items\n\n\n@app.post(\"/form/python-set\")\ndef post_form_param_set(items: set = Form()):\n    return items\n\n\n@app.post(\"/form/python-tuple\")\ndef post_form_param_tuple(items: tuple = Form()):\n    return items\n\n\nclient = TestClient(app)\n\n\ndef test_python_list_param_as_form():\n    response = client.post(\n        \"/form/python-list\", data={\"items\": [\"first\", \"second\", \"third\"]}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"first\", \"second\", \"third\"]\n\n\ndef test_python_set_param_as_form():\n    response = client.post(\n        \"/form/python-set\", data={\"items\": [\"first\", \"second\", \"third\"]}\n    )\n    assert response.status_code == 200, response.text\n    assert set(response.json()) == {\"first\", \"second\", \"third\"}\n\n\ndef test_python_tuple_param_as_form():\n    response = client.post(\n        \"/form/python-tuple\", data={\"items\": [\"first\", \"second\", \"third\"]}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"first\", \"second\", \"third\"]\n"
  },
  {
    "path": "tests/test_forms_single_model.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Form\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n\nclass FormModel(BaseModel):\n    username: str\n    lastname: str\n    age: int | None = None\n    tags: list[str] = [\"foo\", \"bar\"]\n    alias_with: str = Field(alias=\"with\", default=\"nothing\")\n\n\nclass FormModelExtraAllow(BaseModel):\n    param: str\n\n    model_config = {\"extra\": \"allow\"}\n\n\n@app.post(\"/form/\")\ndef post_form(user: Annotated[FormModel, Form()]):\n    return user\n\n\n@app.post(\"/form-extra-allow/\")\ndef post_form_extra_allow(params: Annotated[FormModelExtraAllow, Form()]):\n    return params\n\n\nclient = TestClient(app)\n\n\ndef test_send_all_data():\n    response = client.post(\n        \"/form/\",\n        data={\n            \"username\": \"Rick\",\n            \"lastname\": \"Sanchez\",\n            \"age\": \"70\",\n            \"tags\": [\"plumbus\", \"citadel\"],\n            \"with\": \"something\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"username\": \"Rick\",\n        \"lastname\": \"Sanchez\",\n        \"age\": 70,\n        \"tags\": [\"plumbus\", \"citadel\"],\n        \"with\": \"something\",\n    }\n\n\ndef test_defaults():\n    response = client.post(\"/form/\", data={\"username\": \"Rick\", \"lastname\": \"Sanchez\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"username\": \"Rick\",\n        \"lastname\": \"Sanchez\",\n        \"age\": None,\n        \"tags\": [\"foo\", \"bar\"],\n        \"with\": \"nothing\",\n    }\n\n\ndef test_invalid_data():\n    response = client.post(\n        \"/form/\",\n        data={\n            \"username\": \"Rick\",\n            \"lastname\": \"Sanchez\",\n            \"age\": \"seventy\",\n            \"tags\": [\"plumbus\", \"citadel\"],\n        },\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"body\", \"age\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"seventy\",\n            }\n        ]\n    }\n\n\ndef test_no_data():\n    response = client.post(\"/form/\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": {\"tags\": [\"foo\", \"bar\"], \"with\": \"nothing\"},\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"lastname\"],\n                \"msg\": \"Field required\",\n                \"input\": {\"tags\": [\"foo\", \"bar\"], \"with\": \"nothing\"},\n            },\n        ]\n    }\n\n\ndef test_extra_param_single():\n    response = client.post(\n        \"/form-extra-allow/\",\n        data={\n            \"param\": \"123\",\n            \"extra_param\": \"456\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"param\": \"123\",\n        \"extra_param\": \"456\",\n    }\n\n\ndef test_extra_param_list():\n    response = client.post(\n        \"/form-extra-allow/\",\n        data={\n            \"param\": \"123\",\n            \"extra_params\": [\"456\", \"789\"],\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"param\": \"123\",\n        \"extra_params\": [\"456\", \"789\"],\n    }\n"
  },
  {
    "path": "tests/test_forms_single_param.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Form\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\n@app.post(\"/form/\")\ndef post_form(username: Annotated[str, Form()]):\n    return username\n\n\nclient = TestClient(app)\n\n\ndef test_single_form_field():\n    response = client.post(\"/form/\", data={\"username\": \"Rick\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == \"Rick\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/form/\": {\n                    \"post\": {\n                        \"summary\": \"Post Form\",\n                        \"operationId\": \"post_form_form__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_post_form_form__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_post_form_form__post\": {\n                        \"properties\": {\n                            \"username\": {\"type\": \"string\", \"title\": \"Username\"}\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"username\"],\n                        \"title\": \"Body_post_form_form__post\",\n                    },\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_generate_unique_id_function.py",
    "content": "import warnings\n\nfrom fastapi import APIRouter, FastAPI\nfrom fastapi.routing import APIRoute\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\n\ndef custom_generate_unique_id(route: APIRoute):\n    return f\"foo_{route.name}\"\n\n\ndef custom_generate_unique_id2(route: APIRoute):\n    return f\"bar_{route.name}\"\n\n\ndef custom_generate_unique_id3(route: APIRoute):\n    return f\"baz_{route.name}\"\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\nclass Message(BaseModel):\n    title: str\n    description: str\n\n\ndef test_top_level_generate_unique_id():\n    app = FastAPI(generate_unique_id_function=custom_generate_unique_id)\n    router = APIRouter()\n\n    @app.post(\"/\", response_model=list[Item], responses={404: {\"model\": list[Message]}})\n    def post_root(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    @router.post(\n        \"/router\", response_model=list[Item], responses={404: {\"model\": list[Message]}}\n    )\n    def post_router(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    app.include_router(router)\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"post\": {\n                        \"summary\": \"Post Root\",\n                        \"operationId\": \"foo_post_root\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_foo_post_root\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Foo Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Foo Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/router\": {\n                    \"post\": {\n                        \"summary\": \"Post Router\",\n                        \"operationId\": \"foo_post_router\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_foo_post_router\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Foo Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Foo Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_foo_post_root\": {\n                        \"title\": \"Body_foo_post_root\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"Body_foo_post_router\": {\n                        \"title\": \"Body_foo_post_router\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"Message\": {\n                        \"title\": \"Message\",\n                        \"required\": [\"title\", \"description\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n\n\ndef test_router_overrides_generate_unique_id():\n    app = FastAPI(generate_unique_id_function=custom_generate_unique_id)\n    router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)\n\n    @app.post(\"/\", response_model=list[Item], responses={404: {\"model\": list[Message]}})\n    def post_root(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    @router.post(\n        \"/router\", response_model=list[Item], responses={404: {\"model\": list[Message]}}\n    )\n    def post_router(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    app.include_router(router)\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"post\": {\n                        \"summary\": \"Post Root\",\n                        \"operationId\": \"foo_post_root\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_foo_post_root\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Foo Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Foo Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/router\": {\n                    \"post\": {\n                        \"summary\": \"Post Router\",\n                        \"operationId\": \"bar_post_router\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_bar_post_router\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Bar Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Bar Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_bar_post_router\": {\n                        \"title\": \"Body_bar_post_router\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"Body_foo_post_root\": {\n                        \"title\": \"Body_foo_post_root\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"Message\": {\n                        \"title\": \"Message\",\n                        \"required\": [\"title\", \"description\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n\n\ndef test_router_include_overrides_generate_unique_id():\n    app = FastAPI(generate_unique_id_function=custom_generate_unique_id)\n    router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)\n\n    @app.post(\"/\", response_model=list[Item], responses={404: {\"model\": list[Message]}})\n    def post_root(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    @router.post(\n        \"/router\", response_model=list[Item], responses={404: {\"model\": list[Message]}}\n    )\n    def post_router(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    app.include_router(router, generate_unique_id_function=custom_generate_unique_id3)\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"post\": {\n                        \"summary\": \"Post Root\",\n                        \"operationId\": \"foo_post_root\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_foo_post_root\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Foo Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Foo Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/router\": {\n                    \"post\": {\n                        \"summary\": \"Post Router\",\n                        \"operationId\": \"bar_post_router\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_bar_post_router\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Bar Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Bar Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_bar_post_router\": {\n                        \"title\": \"Body_bar_post_router\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"Body_foo_post_root\": {\n                        \"title\": \"Body_foo_post_root\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"Message\": {\n                        \"title\": \"Message\",\n                        \"required\": [\"title\", \"description\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n\n\ndef test_subrouter_top_level_include_overrides_generate_unique_id():\n    app = FastAPI(generate_unique_id_function=custom_generate_unique_id)\n    router = APIRouter()\n    sub_router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)\n\n    @app.post(\"/\", response_model=list[Item], responses={404: {\"model\": list[Message]}})\n    def post_root(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    @router.post(\n        \"/router\", response_model=list[Item], responses={404: {\"model\": list[Message]}}\n    )\n    def post_router(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    @sub_router.post(\n        \"/subrouter\",\n        response_model=list[Item],\n        responses={404: {\"model\": list[Message]}},\n    )\n    def post_subrouter(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    router.include_router(sub_router)\n    app.include_router(router, generate_unique_id_function=custom_generate_unique_id3)\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"post\": {\n                        \"summary\": \"Post Root\",\n                        \"operationId\": \"foo_post_root\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_foo_post_root\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Foo Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Foo Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/router\": {\n                    \"post\": {\n                        \"summary\": \"Post Router\",\n                        \"operationId\": \"baz_post_router\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_baz_post_router\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Baz Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Baz Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/subrouter\": {\n                    \"post\": {\n                        \"summary\": \"Post Subrouter\",\n                        \"operationId\": \"bar_post_subrouter\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_bar_post_subrouter\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Bar Post Subrouter\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Bar Post Subrouter\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_bar_post_subrouter\": {\n                        \"title\": \"Body_bar_post_subrouter\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"Body_baz_post_router\": {\n                        \"title\": \"Body_baz_post_router\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"Body_foo_post_root\": {\n                        \"title\": \"Body_foo_post_root\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"Message\": {\n                        \"title\": \"Message\",\n                        \"required\": [\"title\", \"description\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n\n\ndef test_router_path_operation_overrides_generate_unique_id():\n    app = FastAPI(generate_unique_id_function=custom_generate_unique_id)\n    router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)\n\n    @app.post(\"/\", response_model=list[Item], responses={404: {\"model\": list[Message]}})\n    def post_root(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    @router.post(\n        \"/router\",\n        response_model=list[Item],\n        responses={404: {\"model\": list[Message]}},\n        generate_unique_id_function=custom_generate_unique_id3,\n    )\n    def post_router(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    app.include_router(router)\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"post\": {\n                        \"summary\": \"Post Root\",\n                        \"operationId\": \"foo_post_root\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_foo_post_root\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Foo Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Foo Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/router\": {\n                    \"post\": {\n                        \"summary\": \"Post Router\",\n                        \"operationId\": \"baz_post_router\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_baz_post_router\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Baz Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Baz Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_baz_post_router\": {\n                        \"title\": \"Body_baz_post_router\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"Body_foo_post_root\": {\n                        \"title\": \"Body_foo_post_root\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"Message\": {\n                        \"title\": \"Message\",\n                        \"required\": [\"title\", \"description\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n\n\ndef test_app_path_operation_overrides_generate_unique_id():\n    app = FastAPI(generate_unique_id_function=custom_generate_unique_id)\n    router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)\n\n    @app.post(\n        \"/\",\n        response_model=list[Item],\n        responses={404: {\"model\": list[Message]}},\n        generate_unique_id_function=custom_generate_unique_id3,\n    )\n    def post_root(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    @router.post(\n        \"/router\",\n        response_model=list[Item],\n        responses={404: {\"model\": list[Message]}},\n    )\n    def post_router(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    app.include_router(router)\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"post\": {\n                        \"summary\": \"Post Root\",\n                        \"operationId\": \"baz_post_root\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_baz_post_root\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Baz Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Baz Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/router\": {\n                    \"post\": {\n                        \"summary\": \"Post Router\",\n                        \"operationId\": \"bar_post_router\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_bar_post_router\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Bar Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Bar Post Router\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_bar_post_router\": {\n                        \"title\": \"Body_bar_post_router\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"Body_baz_post_root\": {\n                        \"title\": \"Body_baz_post_root\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"Message\": {\n                        \"title\": \"Message\",\n                        \"required\": [\"title\", \"description\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n\n\ndef test_callback_override_generate_unique_id():\n    app = FastAPI(generate_unique_id_function=custom_generate_unique_id)\n    callback_router = APIRouter(generate_unique_id_function=custom_generate_unique_id2)\n\n    @callback_router.post(\n        \"/post-callback\",\n        response_model=list[Item],\n        responses={404: {\"model\": list[Message]}},\n        generate_unique_id_function=custom_generate_unique_id3,\n    )\n    def post_callback(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    @app.post(\n        \"/\",\n        response_model=list[Item],\n        responses={404: {\"model\": list[Message]}},\n        generate_unique_id_function=custom_generate_unique_id3,\n        callbacks=callback_router.routes,\n    )\n    def post_root(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    @app.post(\n        \"/tocallback\",\n        response_model=list[Item],\n        responses={404: {\"model\": list[Message]}},\n    )\n    def post_with_callback(item1: Item, item2: Item):\n        return item1, item2  # pragma: nocover\n\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"post\": {\n                        \"summary\": \"Post Root\",\n                        \"operationId\": \"baz_post_root\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_baz_post_root\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Baz Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Baz Post Root\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"callbacks\": {\n                            \"post_callback\": {\n                                \"/post-callback\": {\n                                    \"post\": {\n                                        \"summary\": \"Post Callback\",\n                                        \"operationId\": \"baz_post_callback\",\n                                        \"requestBody\": {\n                                            \"content\": {\n                                                \"application/json\": {\n                                                    \"schema\": {\n                                                        \"$ref\": \"#/components/schemas/Body_baz_post_callback\"\n                                                    }\n                                                }\n                                            },\n                                            \"required\": True,\n                                        },\n                                        \"responses\": {\n                                            \"200\": {\n                                                \"description\": \"Successful Response\",\n                                                \"content\": {\n                                                    \"application/json\": {\n                                                        \"schema\": {\n                                                            \"title\": \"Response Baz Post Callback\",\n                                                            \"type\": \"array\",\n                                                            \"items\": {\n                                                                \"$ref\": \"#/components/schemas/Item\"\n                                                            },\n                                                        }\n                                                    }\n                                                },\n                                            },\n                                            \"404\": {\n                                                \"description\": \"Not Found\",\n                                                \"content\": {\n                                                    \"application/json\": {\n                                                        \"schema\": {\n                                                            \"title\": \"Response 404 Baz Post Callback\",\n                                                            \"type\": \"array\",\n                                                            \"items\": {\n                                                                \"$ref\": \"#/components/schemas/Message\"\n                                                            },\n                                                        }\n                                                    }\n                                                },\n                                            },\n                                            \"422\": {\n                                                \"description\": \"Validation Error\",\n                                                \"content\": {\n                                                    \"application/json\": {\n                                                        \"schema\": {\n                                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                                        }\n                                                    }\n                                                },\n                                            },\n                                        },\n                                    }\n                                }\n                            }\n                        },\n                    }\n                },\n                \"/tocallback\": {\n                    \"post\": {\n                        \"summary\": \"Post With Callback\",\n                        \"operationId\": \"foo_post_with_callback\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_foo_post_with_callback\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Foo Post With Callback\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 404 Foo Post With Callback\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Message\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_baz_post_callback\": {\n                        \"title\": \"Body_baz_post_callback\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"Body_baz_post_root\": {\n                        \"title\": \"Body_baz_post_root\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"Body_foo_post_with_callback\": {\n                        \"title\": \"Body_foo_post_with_callback\",\n                        \"required\": [\"item1\", \"item2\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item1\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"item2\": {\"$ref\": \"#/components/schemas/Item\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"Message\": {\n                        \"title\": \"Message\",\n                        \"required\": [\"title\", \"description\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n\n\ndef test_warn_duplicate_operation_id():\n    def broken_operation_id(route: APIRoute):\n        return \"foo\"\n\n    app = FastAPI(generate_unique_id_function=broken_operation_id)\n\n    @app.post(\"/\")\n    def post_root(item1: Item):\n        return item1  # pragma: nocover\n\n    @app.post(\"/second\")\n    def post_second(item1: Item):\n        return item1  # pragma: nocover\n\n    @app.post(\"/third\")\n    def post_third(item1: Item):\n        return item1  # pragma: nocover\n\n    client = TestClient(app)\n    with warnings.catch_warnings(record=True) as w:\n        warnings.simplefilter(\"always\")\n        client.get(\"/openapi.json\")\n        assert len(w) >= 2\n        duplicate_warnings = [\n            warning for warning in w if issubclass(warning.category, UserWarning)\n        ]\n        assert len(duplicate_warnings) > 0\n        assert \"Duplicate Operation ID\" in str(duplicate_warnings[0].message)\n"
  },
  {
    "path": "tests/test_generic_parameterless_depends.py",
    "content": "from typing import Annotated, TypeVar\n\nfrom fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nT = TypeVar(\"T\")\n\nDep = Annotated[T, Depends()]\n\n\nclass A:\n    pass\n\n\nclass B:\n    pass\n\n\n@app.get(\"/a\")\nasync def a(dep: Dep[A]):\n    return {\"cls\": dep.__class__.__name__}\n\n\n@app.get(\"/b\")\nasync def b(dep: Dep[B]):\n    return {\"cls\": dep.__class__.__name__}\n\n\nclient = TestClient(app)\n\n\ndef test_generic_parameterless_depends():\n    response = client.get(\"/a\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"cls\": \"A\"}\n\n    response = client.get(\"/b\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"cls\": \"B\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/a\": {\n                    \"get\": {\n                        \"operationId\": \"a_a_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                        \"summary\": \"A\",\n                    }\n                },\n                \"/b\": {\n                    \"get\": {\n                        \"operationId\": \"b_b_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                        \"summary\": \"B\",\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_get_model_definitions_formfeed_escape.py",
    "content": "import pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(name=\"client\")\ndef client_fixture() -> TestClient:\n    from pydantic import BaseModel\n\n    class Address(BaseModel):\n        \"\"\"\n        This is a public description of an Address\n        \\f\n        You can't see this part of the docstring, it's private!\n        \"\"\"\n\n        line_1: str\n        city: str\n        state_province: str\n\n    class Facility(BaseModel):\n        id: str\n        address: Address\n\n    app = FastAPI()\n\n    @app.get(\"/facilities/{facility_id}\")\n    def get_facility(facility_id: str) -> Facility:\n        return Facility(\n            id=facility_id,\n            address=Address(line_1=\"123 Main St\", city=\"Anytown\", state_province=\"CA\"),\n        )\n\n    client = TestClient(app)\n    return client\n\n\ndef test_get(client: TestClient):\n    response = client.get(\"/facilities/42\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"id\": \"42\",\n        \"address\": {\n            \"line_1\": \"123 Main St\",\n            \"city\": \"Anytown\",\n            \"state_province\": \"CA\",\n        },\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    \"\"\"\n    Sanity check to ensure our app's openapi schema renders as we expect\n    \"\"\"\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"components\": {\n                \"schemas\": {\n                    \"Address\": {\n                        # NOTE: the description of this model shows only the public-facing text, before the `\\f` in docstring\n                        \"description\": \"This is a public description of an Address\\n\",\n                        \"properties\": {\n                            \"city\": {\"title\": \"City\", \"type\": \"string\"},\n                            \"line_1\": {\"title\": \"Line 1\", \"type\": \"string\"},\n                            \"state_province\": {\n                                \"title\": \"State Province\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\"line_1\", \"city\", \"state_province\"],\n                        \"title\": \"Address\",\n                        \"type\": \"object\",\n                    },\n                    \"Facility\": {\n                        \"properties\": {\n                            \"address\": {\"$ref\": \"#/components/schemas/Address\"},\n                            \"id\": {\"title\": \"Id\", \"type\": \"string\"},\n                        },\n                        \"required\": [\"id\", \"address\"],\n                        \"title\": \"Facility\",\n                        \"type\": \"object\",\n                    },\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            }\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                }\n            },\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/facilities/{facility_id}\": {\n                    \"get\": {\n                        \"operationId\": \"get_facility_facilities__facility_id__get\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"facility_id\",\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Facility Id\", \"type\": \"string\"},\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Facility\"\n                                        }\n                                    }\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Get Facility\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_get_request_body.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Product(BaseModel):\n    name: str\n    description: str = None  # type: ignore\n    price: float\n\n\n@app.get(\"/product\")\nasync def create_item(product: Product):\n    return product\n\n\nclient = TestClient(app)\n\n\ndef test_get_with_body():\n    body = {\"name\": \"Foo\", \"description\": \"Some description\", \"price\": 5.5}\n    response = client.request(\"GET\", \"/product\", json=body)\n    assert response.json() == body\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/product\": {\n                    \"get\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_product_get\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Product\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Product\": {\n                        \"title\": \"Product\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_http_connection_injection.py",
    "content": "from fastapi import Depends, FastAPI\nfrom fastapi.requests import HTTPConnection\nfrom fastapi.testclient import TestClient\nfrom starlette.websockets import WebSocket\n\napp = FastAPI()\napp.state.value = 42\n\n\nasync def extract_value_from_http_connection(conn: HTTPConnection):\n    return conn.app.state.value\n\n\n@app.get(\"/http\")\nasync def get_value_by_http(value: int = Depends(extract_value_from_http_connection)):\n    return value\n\n\n@app.websocket(\"/ws\")\nasync def get_value_by_ws(\n    websocket: WebSocket, value: int = Depends(extract_value_from_http_connection)\n):\n    await websocket.accept()\n    await websocket.send_json(value)\n    await websocket.close()\n\n\nclient = TestClient(app)\n\n\ndef test_value_extracting_by_http():\n    response = client.get(\"/http\")\n    assert response.status_code == 200\n    assert response.json() == 42\n\n\ndef test_value_extracting_by_ws():\n    with client.websocket_connect(\"/ws\") as websocket:\n        assert websocket.receive_json() == 42\n"
  },
  {
    "path": "tests/test_include_route.py",
    "content": "from fastapi import APIRouter, FastAPI, Request\nfrom fastapi.responses import JSONResponse\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\nrouter = APIRouter()\n\n\n@router.route(\"/items/\")\ndef read_items(request: Request):\n    return JSONResponse({\"hello\": \"world\"})\n\n\napp.include_router(router)\n\nclient = TestClient(app)\n\n\ndef test_sub_router():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"hello\": \"world\"}\n"
  },
  {
    "path": "tests/test_infer_param_optionality.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\nuser_router = APIRouter()\nitem_router = APIRouter()\n\n\n@user_router.get(\"/\")\ndef get_users():\n    return [{\"user_id\": \"u1\"}, {\"user_id\": \"u2\"}]\n\n\n@user_router.get(\"/{user_id}\")\ndef get_user(user_id: str):\n    return {\"user_id\": user_id}\n\n\n@item_router.get(\"/\")\ndef get_items(user_id: str | None = None):\n    if user_id is None:\n        return [{\"item_id\": \"i1\", \"user_id\": \"u1\"}, {\"item_id\": \"i2\", \"user_id\": \"u2\"}]\n    else:\n        return [{\"item_id\": \"i2\", \"user_id\": user_id}]\n\n\n@item_router.get(\"/{item_id}\")\ndef get_item(item_id: str, user_id: str | None = None):\n    if user_id is None:\n        return {\"item_id\": item_id}\n    else:\n        return {\"item_id\": item_id, \"user_id\": user_id}\n\n\napp.include_router(user_router, prefix=\"/users\")\napp.include_router(item_router, prefix=\"/items\")\n\napp.include_router(item_router, prefix=\"/users/{user_id}/items\")\n\n\nclient = TestClient(app)\n\n\ndef test_get_users():\n    \"\"\"Check that /users returns expected data\"\"\"\n    response = client.get(\"/users\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"user_id\": \"u1\"}, {\"user_id\": \"u2\"}]\n\n\ndef test_get_user():\n    \"\"\"Check that /users/{user_id} returns expected data\"\"\"\n    response = client.get(\"/users/abc123\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"user_id\": \"abc123\"}\n\n\ndef test_get_items_1():\n    \"\"\"Check that /items returns expected data\"\"\"\n    response = client.get(\"/items\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"item_id\": \"i1\", \"user_id\": \"u1\"},\n        {\"item_id\": \"i2\", \"user_id\": \"u2\"},\n    ]\n\n\ndef test_get_items_2():\n    \"\"\"Check that /items returns expected data with user_id specified\"\"\"\n    response = client.get(\"/items?user_id=abc123\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item_id\": \"i2\", \"user_id\": \"abc123\"}]\n\n\ndef test_get_item_1():\n    \"\"\"Check that /items/{item_id} returns expected data\"\"\"\n    response = client.get(\"/items/item01\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": \"item01\"}\n\n\ndef test_get_item_2():\n    \"\"\"Check that /items/{item_id} returns expected data with user_id specified\"\"\"\n    response = client.get(\"/items/item01?user_id=abc123\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": \"item01\", \"user_id\": \"abc123\"}\n\n\ndef test_get_users_items():\n    \"\"\"Check that /users/{user_id}/items returns expected data\"\"\"\n    response = client.get(\"/users/abc123/items\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item_id\": \"i2\", \"user_id\": \"abc123\"}]\n\n\ndef test_get_users_item():\n    \"\"\"Check that /users/{user_id}/items returns expected data\"\"\"\n    response = client.get(\"/users/abc123/items/item01\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": \"item01\", \"user_id\": \"abc123\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/\": {\n                    \"get\": {\n                        \"summary\": \"Get Users\",\n                        \"operationId\": \"get_users_users__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/users/{user_id}\": {\n                    \"get\": {\n                        \"summary\": \"Get User\",\n                        \"operationId\": \"get_user_users__user_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"User Id\", \"type\": \"string\"},\n                                \"name\": \"user_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Get Items\",\n                        \"operationId\": \"get_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"name\": \"user_id\",\n                                \"in\": \"query\",\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"User Id\",\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Get Item\",\n                        \"operationId\": \"get_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": False,\n                                \"name\": \"user_id\",\n                                \"in\": \"query\",\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"User Id\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/users/{user_id}/items/\": {\n                    \"get\": {\n                        \"summary\": \"Get Items\",\n                        \"operationId\": \"get_items_users__user_id__items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"name\": \"user_id\",\n                                \"in\": \"path\",\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"User Id\",\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/users/{user_id}/items/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Get Item\",\n                        \"operationId\": \"get_item_users__user_id__items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"name\": \"user_id\",\n                                \"in\": \"path\",\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"User Id\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_inherited_custom_class.py",
    "content": "import uuid\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\n\nclass MyUuid:\n    def __init__(self, uuid_string: str):\n        self.uuid = uuid_string\n\n    def __str__(self):\n        return self.uuid\n\n    @property  # type: ignore\n    def __class__(self):\n        return uuid.UUID\n\n    @property\n    def __dict__(self):\n        \"\"\"Spoof a missing __dict__ by raising TypeError, this is how\n        asyncpg.pgroto.pgproto.UUID behaves\"\"\"\n        raise TypeError(\"vars() argument must have __dict__ attribute\")\n\n\ndef test_pydanticv2():\n    from pydantic import field_serializer\n\n    app = FastAPI()\n\n    @app.get(\"/fast_uuid\")\n    def return_fast_uuid():\n        asyncpg_uuid = MyUuid(\"a10ff360-3b1e-4984-a26f-d3ab460bdb51\")\n        assert isinstance(asyncpg_uuid, uuid.UUID)\n        assert type(asyncpg_uuid) is not uuid.UUID\n        with pytest.raises(TypeError):\n            vars(asyncpg_uuid)\n        return {\"fast_uuid\": asyncpg_uuid}\n\n    class SomeCustomClass(BaseModel):\n        model_config = {\"arbitrary_types_allowed\": True}\n\n        a_uuid: MyUuid\n\n        @field_serializer(\"a_uuid\")\n        def serialize_a_uuid(self, v):\n            return str(v)\n\n    @app.get(\"/get_custom_class\")\n    def return_some_user():\n        # Test that the fix also works for custom pydantic classes\n        return SomeCustomClass(a_uuid=MyUuid(\"b8799909-f914-42de-91bc-95c819218d01\"))\n\n    client = TestClient(app)\n\n    with client:\n        response_simple = client.get(\"/fast_uuid\")\n        response_pydantic = client.get(\"/get_custom_class\")\n\n    assert response_simple.json() == {\n        \"fast_uuid\": \"a10ff360-3b1e-4984-a26f-d3ab460bdb51\"\n    }\n\n    assert response_pydantic.json() == {\n        \"a_uuid\": \"b8799909-f914-42de-91bc-95c819218d01\"\n    }\n"
  },
  {
    "path": "tests/test_invalid_path_param.py",
    "content": "import pytest\nfrom fastapi import FastAPI\nfrom pydantic import BaseModel\n\n\ndef test_invalid_sequence():\n    with pytest.raises(AssertionError):\n        app = FastAPI()\n\n        class Item(BaseModel):\n            title: str\n\n        @app.get(\"/items/{id}\")\n        def read_items(id: list[Item]):\n            pass  # pragma: no cover\n\n\ndef test_invalid_tuple():\n    with pytest.raises(AssertionError):\n        app = FastAPI()\n\n        class Item(BaseModel):\n            title: str\n\n        @app.get(\"/items/{id}\")\n        def read_items(id: tuple[Item, Item]):\n            pass  # pragma: no cover\n\n\ndef test_invalid_dict():\n    with pytest.raises(AssertionError):\n        app = FastAPI()\n\n        class Item(BaseModel):\n            title: str\n\n        @app.get(\"/items/{id}\")\n        def read_items(id: dict[str, Item]):\n            pass  # pragma: no cover\n\n\ndef test_invalid_simple_list():\n    with pytest.raises(AssertionError):\n        app = FastAPI()\n\n        @app.get(\"/items/{id}\")\n        def read_items(id: list):\n            pass  # pragma: no cover\n\n\ndef test_invalid_simple_tuple():\n    with pytest.raises(AssertionError):\n        app = FastAPI()\n\n        @app.get(\"/items/{id}\")\n        def read_items(id: tuple):\n            pass  # pragma: no cover\n\n\ndef test_invalid_simple_set():\n    with pytest.raises(AssertionError):\n        app = FastAPI()\n\n        @app.get(\"/items/{id}\")\n        def read_items(id: set):\n            pass  # pragma: no cover\n\n\ndef test_invalid_simple_dict():\n    with pytest.raises(AssertionError):\n        app = FastAPI()\n\n        @app.get(\"/items/{id}\")\n        def read_items(id: dict):\n            pass  # pragma: no cover\n"
  },
  {
    "path": "tests/test_invalid_sequence_param.py",
    "content": "import pytest\nfrom fastapi import FastAPI, Query\nfrom pydantic import BaseModel\n\n\ndef test_invalid_sequence():\n    with pytest.raises(\n        AssertionError,\n        match=\"Query parameter 'q' must be one of the supported types\",\n    ):\n        app = FastAPI()\n\n        class Item(BaseModel):\n            title: str\n\n        @app.get(\"/items/\")\n        def read_items(q: list[Item] = Query(default=None)):\n            pass  # pragma: no cover\n\n\ndef test_invalid_tuple():\n    with pytest.raises(\n        AssertionError,\n        match=\"Query parameter 'q' must be one of the supported types\",\n    ):\n        app = FastAPI()\n\n        class Item(BaseModel):\n            title: str\n\n        @app.get(\"/items/\")\n        def read_items(q: tuple[Item, Item] = Query(default=None)):\n            pass  # pragma: no cover\n\n\ndef test_invalid_dict():\n    with pytest.raises(\n        AssertionError,\n        match=\"Query parameter 'q' must be one of the supported types\",\n    ):\n        app = FastAPI()\n\n        class Item(BaseModel):\n            title: str\n\n        @app.get(\"/items/\")\n        def read_items(q: dict[str, Item] = Query(default=None)):\n            pass  # pragma: no cover\n\n\ndef test_invalid_simple_dict():\n    with pytest.raises(\n        AssertionError,\n        match=\"Query parameter 'q' must be one of the supported types\",\n    ):\n        app = FastAPI()\n\n        class Item(BaseModel):\n            title: str\n\n        @app.get(\"/items/\")\n        def read_items(q: dict | None = Query(default=None)):\n            pass  # pragma: no cover\n"
  },
  {
    "path": "tests/test_json_type.py",
    "content": "import json\nfrom typing import Annotated\n\nfrom fastapi import Cookie, FastAPI, Form, Header, Query\nfrom fastapi.testclient import TestClient\nfrom pydantic import Json\n\napp = FastAPI()\n\n\n@app.post(\"/form-json-list\")\ndef form_json_list(items: Annotated[Json[list[str]], Form()]) -> list[str]:\n    return items\n\n\n@app.get(\"/query-json-list\")\ndef query_json_list(items: Annotated[Json[list[str]], Query()]) -> list[str]:\n    return items\n\n\n@app.get(\"/header-json-list\")\ndef header_json_list(x_items: Annotated[Json[list[str]], Header()]) -> list[str]:\n    return x_items\n\n\n@app.get(\"/cookie-json-list\")\ndef cookie_json_list(items: Annotated[Json[list[str]], Cookie()]) -> list[str]:\n    return items\n\n\nclient = TestClient(app)\n\n\ndef test_form_json_list():\n    response = client.post(\n        \"/form-json-list\", data={\"items\": json.dumps([\"abc\", \"def\"])}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"abc\", \"def\"]\n\n\ndef test_query_json_list():\n    response = client.get(\n        \"/query-json-list\", params={\"items\": json.dumps([\"abc\", \"def\"])}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"abc\", \"def\"]\n\n\ndef test_header_json_list():\n    response = client.get(\n        \"/header-json-list\", headers={\"x-items\": json.dumps([\"abc\", \"def\"])}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"abc\", \"def\"]\n\n\ndef test_cookie_json_list():\n    client.cookies.set(\"items\", json.dumps([\"abc\", \"def\"]))\n    response = client.get(\"/cookie-json-list\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"abc\", \"def\"]\n    client.cookies.clear()\n"
  },
  {
    "path": "tests/test_jsonable_encoder.py",
    "content": "import warnings\nfrom collections import deque\nfrom dataclasses import dataclass\nfrom datetime import datetime, timezone\nfrom decimal import Decimal\nfrom enum import Enum\nfrom math import isinf, isnan\nfrom pathlib import PurePath, PurePosixPath, PureWindowsPath\nfrom typing import TypedDict\n\nimport pytest\nfrom fastapi._compat import Undefined\nfrom fastapi.encoders import jsonable_encoder\nfrom fastapi.exceptions import PydanticV1NotSupportedError\nfrom pydantic import BaseModel, Field, ValidationError\n\n\nclass Person:\n    def __init__(self, name: str):\n        self.name = name\n\n\nclass Pet:\n    def __init__(self, owner: Person, name: str):\n        self.owner = owner\n        self.name = name\n\n\n@dataclass\nclass Item:\n    name: str\n    count: int\n\n\nclass DictablePerson(Person):\n    def __iter__(self):\n        return ((k, v) for k, v in self.__dict__.items())\n\n\nclass DictablePet(Pet):\n    def __iter__(self):\n        return ((k, v) for k, v in self.__dict__.items())\n\n\nclass Unserializable:\n    def __iter__(self):\n        raise NotImplementedError()\n\n    @property\n    def __dict__(self):\n        raise NotImplementedError()\n\n\nclass RoleEnum(Enum):\n    admin = \"admin\"\n    normal = \"normal\"\n\n\nclass ModelWithConfig(BaseModel):\n    role: RoleEnum | None = None\n\n    model_config = {\"use_enum_values\": True}\n\n\nclass ModelWithAlias(BaseModel):\n    foo: str = Field(alias=\"Foo\")\n\n\nclass ModelWithDefault(BaseModel):\n    foo: str = ...  # type: ignore\n    bar: str = \"bar\"\n    bla: str = \"bla\"\n\n\ndef test_encode_dict():\n    pet = {\"name\": \"Firulais\", \"owner\": {\"name\": \"Foo\"}}\n    assert jsonable_encoder(pet) == {\"name\": \"Firulais\", \"owner\": {\"name\": \"Foo\"}}\n    assert jsonable_encoder(pet, include={\"name\"}) == {\"name\": \"Firulais\"}\n    assert jsonable_encoder(pet, exclude={\"owner\"}) == {\"name\": \"Firulais\"}\n    assert jsonable_encoder(pet, include={}) == {}\n    assert jsonable_encoder(pet, exclude={}) == {\n        \"name\": \"Firulais\",\n        \"owner\": {\"name\": \"Foo\"},\n    }\n\n\ndef test_encode_dict_include_exclude_list():\n    pet = {\"name\": \"Firulais\", \"owner\": {\"name\": \"Foo\"}}\n    assert jsonable_encoder(pet) == {\"name\": \"Firulais\", \"owner\": {\"name\": \"Foo\"}}\n    assert jsonable_encoder(pet, include=[\"name\"]) == {\"name\": \"Firulais\"}\n    assert jsonable_encoder(pet, exclude=[\"owner\"]) == {\"name\": \"Firulais\"}\n    assert jsonable_encoder(pet, include=[]) == {}\n    assert jsonable_encoder(pet, exclude=[]) == {\n        \"name\": \"Firulais\",\n        \"owner\": {\"name\": \"Foo\"},\n    }\n\n\ndef test_encode_class():\n    person = Person(name=\"Foo\")\n    pet = Pet(owner=person, name=\"Firulais\")\n    assert jsonable_encoder(pet) == {\"name\": \"Firulais\", \"owner\": {\"name\": \"Foo\"}}\n    assert jsonable_encoder(pet, include={\"name\"}) == {\"name\": \"Firulais\"}\n    assert jsonable_encoder(pet, exclude={\"owner\"}) == {\"name\": \"Firulais\"}\n    assert jsonable_encoder(pet, include={}) == {}\n    assert jsonable_encoder(pet, exclude={}) == {\n        \"name\": \"Firulais\",\n        \"owner\": {\"name\": \"Foo\"},\n    }\n\n\ndef test_encode_dictable():\n    person = DictablePerson(name=\"Foo\")\n    pet = DictablePet(owner=person, name=\"Firulais\")\n    assert jsonable_encoder(pet) == {\"name\": \"Firulais\", \"owner\": {\"name\": \"Foo\"}}\n    assert jsonable_encoder(pet, include={\"name\"}) == {\"name\": \"Firulais\"}\n    assert jsonable_encoder(pet, exclude={\"owner\"}) == {\"name\": \"Firulais\"}\n    assert jsonable_encoder(pet, include={}) == {}\n    assert jsonable_encoder(pet, exclude={}) == {\n        \"name\": \"Firulais\",\n        \"owner\": {\"name\": \"Foo\"},\n    }\n\n\ndef test_encode_dataclass():\n    item = Item(name=\"foo\", count=100)\n    assert jsonable_encoder(item) == {\"name\": \"foo\", \"count\": 100}\n    assert jsonable_encoder(item, include={\"name\"}) == {\"name\": \"foo\"}\n    assert jsonable_encoder(item, exclude={\"count\"}) == {\"name\": \"foo\"}\n    assert jsonable_encoder(item, include={}) == {}\n    assert jsonable_encoder(item, exclude={}) == {\"name\": \"foo\", \"count\": 100}\n\n\ndef test_encode_unsupported():\n    unserializable = Unserializable()\n    with pytest.raises(ValueError):\n        jsonable_encoder(unserializable)\n\n\ndef test_encode_custom_json_encoders_model_pydanticv2():\n    from pydantic import field_serializer\n\n    class ModelWithCustomEncoder(BaseModel):\n        dt_field: datetime\n\n        @field_serializer(\"dt_field\")\n        def serialize_dt_field(self, dt):\n            return dt.replace(microsecond=0, tzinfo=timezone.utc).isoformat()\n\n    class ModelWithCustomEncoderSubclass(ModelWithCustomEncoder):\n        pass\n\n    model = ModelWithCustomEncoder(dt_field=datetime(2019, 1, 1, 8))\n    assert jsonable_encoder(model) == {\"dt_field\": \"2019-01-01T08:00:00+00:00\"}\n    subclass_model = ModelWithCustomEncoderSubclass(dt_field=datetime(2019, 1, 1, 8))\n    assert jsonable_encoder(subclass_model) == {\"dt_field\": \"2019-01-01T08:00:00+00:00\"}\n\n\ndef test_json_encoder_error_with_pydanticv1():\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", UserWarning)\n        from pydantic import v1\n\n    class ModelV1(v1.BaseModel):\n        name: str\n\n    data = ModelV1(name=\"test\")\n    with pytest.raises(PydanticV1NotSupportedError):\n        jsonable_encoder(data)\n\n\ndef test_encode_model_with_config():\n    model = ModelWithConfig(role=RoleEnum.admin)\n    assert jsonable_encoder(model) == {\"role\": \"admin\"}\n\n\ndef test_encode_model_with_alias_raises():\n    with pytest.raises(ValidationError):\n        ModelWithAlias(foo=\"Bar\")\n\n\ndef test_encode_model_with_alias():\n    model = ModelWithAlias(Foo=\"Bar\")\n    assert jsonable_encoder(model) == {\"Foo\": \"Bar\"}\n\n\ndef test_encode_model_with_default():\n    model = ModelWithDefault(foo=\"foo\", bar=\"bar\")\n    assert jsonable_encoder(model) == {\"foo\": \"foo\", \"bar\": \"bar\", \"bla\": \"bla\"}\n    assert jsonable_encoder(model, exclude_unset=True) == {\"foo\": \"foo\", \"bar\": \"bar\"}\n    assert jsonable_encoder(model, exclude_defaults=True) == {\"foo\": \"foo\"}\n    assert jsonable_encoder(model, exclude_unset=True, exclude_defaults=True) == {\n        \"foo\": \"foo\"\n    }\n    assert jsonable_encoder(model, include={\"foo\"}) == {\"foo\": \"foo\"}\n    assert jsonable_encoder(model, exclude={\"bla\"}) == {\"foo\": \"foo\", \"bar\": \"bar\"}\n    assert jsonable_encoder(model, include={}) == {}\n    assert jsonable_encoder(model, exclude={}) == {\n        \"foo\": \"foo\",\n        \"bar\": \"bar\",\n        \"bla\": \"bla\",\n    }\n\n\ndef test_custom_encoders():\n    class safe_datetime(datetime):\n        pass\n\n    class MyDict(TypedDict):\n        dt_field: safe_datetime\n\n    instance = MyDict(dt_field=safe_datetime.now())\n\n    encoded_instance = jsonable_encoder(\n        instance, custom_encoder={safe_datetime: lambda o: o.strftime(\"%H:%M:%S\")}\n    )\n    assert encoded_instance[\"dt_field\"] == instance[\"dt_field\"].strftime(\"%H:%M:%S\")\n\n    encoded_instance = jsonable_encoder(\n        instance, custom_encoder={datetime: lambda o: o.strftime(\"%H:%M:%S\")}\n    )\n    assert encoded_instance[\"dt_field\"] == instance[\"dt_field\"].strftime(\"%H:%M:%S\")\n\n    encoded_instance2 = jsonable_encoder(instance)\n    assert encoded_instance2[\"dt_field\"] == instance[\"dt_field\"].isoformat()\n\n\ndef test_custom_enum_encoders():\n    def custom_enum_encoder(v: Enum):\n        return v.value.lower()\n\n    class MyEnum(Enum):\n        ENUM_VAL_1 = \"ENUM_VAL_1\"\n\n    instance = MyEnum.ENUM_VAL_1\n\n    encoded_instance = jsonable_encoder(\n        instance, custom_encoder={MyEnum: custom_enum_encoder}\n    )\n    assert encoded_instance == custom_enum_encoder(instance)\n\n\ndef test_encode_model_with_pure_path():\n    class ModelWithPath(BaseModel):\n        path: PurePath\n\n        model_config = {\"arbitrary_types_allowed\": True}\n\n    test_path = PurePath(\"/foo\", \"bar\")\n    obj = ModelWithPath(path=test_path)\n    assert jsonable_encoder(obj) == {\"path\": str(test_path)}\n\n\ndef test_encode_model_with_pure_posix_path():\n    class ModelWithPath(BaseModel):\n        path: PurePosixPath\n\n        model_config = {\"arbitrary_types_allowed\": True}\n\n    obj = ModelWithPath(path=PurePosixPath(\"/foo\", \"bar\"))\n    assert jsonable_encoder(obj) == {\"path\": \"/foo/bar\"}\n\n\ndef test_encode_model_with_pure_windows_path():\n    class ModelWithPath(BaseModel):\n        path: PureWindowsPath\n\n        model_config = {\"arbitrary_types_allowed\": True}\n\n    obj = ModelWithPath(path=PureWindowsPath(\"/foo\", \"bar\"))\n    assert jsonable_encoder(obj) == {\"path\": \"\\\\foo\\\\bar\"}\n\n\ndef test_encode_pure_path():\n    test_path = PurePath(\"/foo\", \"bar\")\n\n    assert jsonable_encoder({\"path\": test_path}) == {\"path\": str(test_path)}\n\n\ndef test_decimal_encoder_float():\n    data = {\"value\": Decimal(1.23)}\n    assert jsonable_encoder(data) == {\"value\": 1.23}\n\n\ndef test_decimal_encoder_int():\n    data = {\"value\": Decimal(2)}\n    assert jsonable_encoder(data) == {\"value\": 2}\n\n\ndef test_decimal_encoder_nan():\n    data = {\"value\": Decimal(\"NaN\")}\n    assert isnan(jsonable_encoder(data)[\"value\"])\n\n\ndef test_decimal_encoder_infinity():\n    data = {\"value\": Decimal(\"Infinity\")}\n    assert isinf(jsonable_encoder(data)[\"value\"])\n    data = {\"value\": Decimal(\"-Infinity\")}\n    assert isinf(jsonable_encoder(data)[\"value\"])\n\n\ndef test_encode_deque_encodes_child_models():\n    class Model(BaseModel):\n        test: str\n\n    dq = deque([Model(test=\"test\")])\n\n    assert jsonable_encoder(dq)[0][\"test\"] == \"test\"\n\n\ndef test_encode_pydantic_undefined():\n    data = {\"value\": Undefined}\n    assert jsonable_encoder(data) == {\"value\": None}\n\n\n@pytest.mark.filterwarnings(\"ignore::DeprecationWarning\")\n@pytest.mark.parametrize(\n    \"module_path\",\n    [\n        pytest.param(\"pydantic.color\"),\n        pytest.param(\"pydantic_extra_types.color\"),\n    ],\n)\ndef test_encode_color(module_path):\n    try:\n        Color = __import__(module_path, fromlist=[\"Color\"]).Color\n    except ImportError:  # pragma: no cover\n        pytest.skip(f\"{module_path} not available\")\n\n    data = {\"color\": Color(\"blue\")}\n    assert jsonable_encoder(data) == {\"color\": \"blue\"}\n"
  },
  {
    "path": "tests/test_list_bytes_file_order_preserved_issue_14811.py",
    "content": "\"\"\"\nRegression test: preserve order when using list[bytes] + File()\nSee https://github.com/fastapi/fastapi/discussions/14811\nFixed in PR: https://github.com/fastapi/fastapi/pull/14884\n\"\"\"\n\nfrom typing import Annotated\n\nimport anyio\nimport pytest\nfrom fastapi import FastAPI, File\nfrom fastapi.testclient import TestClient\nfrom starlette.datastructures import UploadFile as StarletteUploadFile\n\n\ndef test_list_bytes_file_preserves_order(\n    monkeypatch: pytest.MonkeyPatch,\n) -> None:\n    app = FastAPI()\n\n    @app.post(\"/upload\")\n    async def upload(files: Annotated[list[bytes], File()]):\n        # return something that makes order obvious\n        return [b[0] for b in files]\n\n    original_read = StarletteUploadFile.read\n\n    async def patched_read(self: StarletteUploadFile, size: int = -1) -> bytes:\n        # Make the FIRST file slower *deterministically*\n        if self.filename == \"slow.txt\":\n            await anyio.sleep(0.05)\n        return await original_read(self, size)\n\n    monkeypatch.setattr(StarletteUploadFile, \"read\", patched_read)\n\n    client = TestClient(app)\n\n    files = [\n        (\"files\", (\"slow.txt\", b\"A\" * 10, \"text/plain\")),\n        (\"files\", (\"fast.txt\", b\"B\" * 10, \"text/plain\")),\n    ]\n    r = client.post(\"/upload\", files=files)\n    assert r.status_code == 200, r.text\n\n    # Must preserve request order: slow first, fast second\n    assert r.json() == [ord(\"A\"), ord(\"B\")]\n"
  },
  {
    "path": "tests/test_local_docs.py",
    "content": "import inspect\n\nfrom fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html\n\n\ndef test_strings_in_generated_swagger():\n    sig = inspect.signature(get_swagger_ui_html)\n    swagger_js_url = sig.parameters.get(\"swagger_js_url\").default  # type: ignore\n    swagger_css_url = sig.parameters.get(\"swagger_css_url\").default  # type: ignore\n    swagger_favicon_url = sig.parameters.get(\"swagger_favicon_url\").default  # type: ignore\n    html = get_swagger_ui_html(openapi_url=\"/docs\", title=\"title\")\n    body_content = html.body.decode()\n    assert swagger_js_url in body_content\n    assert swagger_css_url in body_content\n    assert swagger_favicon_url in body_content\n\n\ndef test_strings_in_custom_swagger():\n    swagger_js_url = \"swagger_fake_file.js\"\n    swagger_css_url = \"swagger_fake_file.css\"\n    swagger_favicon_url = \"swagger_fake_file.png\"\n    html = get_swagger_ui_html(\n        openapi_url=\"/docs\",\n        title=\"title\",\n        swagger_js_url=swagger_js_url,\n        swagger_css_url=swagger_css_url,\n        swagger_favicon_url=swagger_favicon_url,\n    )\n    body_content = html.body.decode()\n    assert swagger_js_url in body_content\n    assert swagger_css_url in body_content\n    assert swagger_favicon_url in body_content\n\n\ndef test_strings_in_generated_redoc():\n    sig = inspect.signature(get_redoc_html)\n    redoc_js_url = sig.parameters.get(\"redoc_js_url\").default  # type: ignore\n    redoc_favicon_url = sig.parameters.get(\"redoc_favicon_url\").default  # type: ignore\n    html = get_redoc_html(openapi_url=\"/docs\", title=\"title\")\n    body_content = html.body.decode()\n    assert redoc_js_url in body_content\n    assert redoc_favicon_url in body_content\n\n\ndef test_strings_in_custom_redoc():\n    redoc_js_url = \"fake_redoc_file.js\"\n    redoc_favicon_url = \"fake_redoc_file.png\"\n    html = get_redoc_html(\n        openapi_url=\"/docs\",\n        title=\"title\",\n        redoc_js_url=redoc_js_url,\n        redoc_favicon_url=redoc_favicon_url,\n    )\n    body_content = html.body.decode()\n    assert redoc_js_url in body_content\n    assert redoc_favicon_url in body_content\n\n\ndef test_google_fonts_in_generated_redoc():\n    body_with_google_fonts = get_redoc_html(\n        openapi_url=\"/docs\", title=\"title\"\n    ).body.decode()\n    assert \"fonts.googleapis.com\" in body_with_google_fonts\n    body_without_google_fonts = get_redoc_html(\n        openapi_url=\"/docs\", title=\"title\", with_google_fonts=False\n    ).body.decode()\n    assert \"fonts.googleapis.com\" not in body_without_google_fonts\n"
  },
  {
    "path": "tests/test_modules_same_name_body/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_modules_same_name_body/app/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_modules_same_name_body/app/a.py",
    "content": "from fastapi import APIRouter, Body\n\nrouter = APIRouter()\n\n\n@router.post(\"/compute\")\ndef compute(a: int = Body(), b: str = Body()):\n    return {\"a\": a, \"b\": b}\n"
  },
  {
    "path": "tests/test_modules_same_name_body/app/b.py",
    "content": "from fastapi import APIRouter, Body\n\nrouter = APIRouter()\n\n\n@router.post(\"/compute/\")\ndef compute(a: int = Body(), b: str = Body()):\n    return {\"a\": a, \"b\": b}\n"
  },
  {
    "path": "tests/test_modules_same_name_body/app/main.py",
    "content": "from fastapi import FastAPI\n\nfrom . import a, b\n\napp = FastAPI()\n\napp.include_router(a.router, prefix=\"/a\")\napp.include_router(b.router, prefix=\"/b\")\n"
  },
  {
    "path": "tests/test_modules_same_name_body/test_main.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom .app.main import app\n\nclient = TestClient(app)\n\n\n@pytest.mark.parametrize(\n    \"path\", [\"/a/compute\", \"/a/compute/\", \"/b/compute\", \"/b/compute/\"]\n)\ndef test_post(path):\n    data = {\"a\": 2, \"b\": \"foo\"}\n    response = client.post(path, json=data)\n    assert response.status_code == 200, response.text\n    assert data == response.json()\n\n\n@pytest.mark.parametrize(\n    \"path\", [\"/a/compute\", \"/a/compute/\", \"/b/compute\", \"/b/compute/\"]\n)\ndef test_post_invalid(path):\n    data = {\"a\": \"bar\", \"b\": \"foo\"}\n    response = client.post(path, json=data)\n    assert response.status_code == 422, response.text\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/a/compute\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Compute\",\n                        \"operationId\": \"compute_a_compute_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_compute_a_compute_post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n                \"/b/compute/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Compute\",\n                        \"operationId\": \"compute_b_compute__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_compute_b_compute__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_compute_b_compute__post\": {\n                        \"title\": \"Body_compute_b_compute__post\",\n                        \"required\": [\"a\", \"b\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"a\": {\"title\": \"A\", \"type\": \"integer\"},\n                            \"b\": {\"title\": \"B\", \"type\": \"string\"},\n                        },\n                    },\n                    \"Body_compute_a_compute_post\": {\n                        \"title\": \"Body_compute_a_compute_post\",\n                        \"required\": [\"a\", \"b\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"a\": {\"title\": \"A\", \"type\": \"integer\"},\n                            \"b\": {\"title\": \"B\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_multi_body_errors.py",
    "content": "from decimal import Decimal\n\nfrom dirty_equals import IsOneOf\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, condecimal\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    age: condecimal(gt=Decimal(0.0))  # type: ignore\n\n\n@app.post(\"/items/\")\ndef save_item_no_body(item: list[Item]):\n    return {\"item\": item}\n\n\nclient = TestClient(app)\n\n\ndef test_put_correct_body():\n    response = client.post(\"/items/\", json=[{\"name\": \"Foo\", \"age\": 5}])\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"item\": [\n                {\n                    \"name\": \"Foo\",\n                    \"age\": \"5\",\n                }\n            ]\n        }\n    )\n\n\ndef test_jsonable_encoder_requiring_error():\n    response = client.post(\"/items/\", json=[{\"name\": \"Foo\", \"age\": -1.0}])\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"greater_than\",\n                \"loc\": [\"body\", 0, \"age\"],\n                \"msg\": \"Input should be greater than 0\",\n                \"input\": -1.0,\n                \"ctx\": {\"gt\": 0},\n            }\n        ]\n    }\n\n\ndef test_put_incorrect_body_multiple():\n    response = client.post(\"/items/\", json=[{\"age\": \"five\"}, {\"age\": \"six\"}])\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", 0, \"name\"],\n                \"msg\": \"Field required\",\n                \"input\": {\"age\": \"five\"},\n            },\n            {\n                \"type\": \"decimal_parsing\",\n                \"loc\": [\"body\", 0, \"age\"],\n                \"msg\": \"Input should be a valid decimal\",\n                \"input\": \"five\",\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", 1, \"name\"],\n                \"msg\": \"Field required\",\n                \"input\": {\"age\": \"six\"},\n            },\n            {\n                \"type\": \"decimal_parsing\",\n                \"loc\": [\"body\", 1, \"age\"],\n                \"msg\": \"Input should be a valid decimal\",\n                \"input\": \"six\",\n            },\n        ]\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Save Item No Body\",\n                        \"operationId\": \"save_item_no_body_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"title\": \"Item\",\n                                        \"type\": \"array\",\n                                        \"items\": {\"$ref\": \"#/components/schemas/Item\"},\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"age\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"age\": {\n                                \"title\": \"Age\",\n                                \"anyOf\": [\n                                    {\"exclusiveMinimum\": 0.0, \"type\": \"number\"},\n                                    IsOneOf(\n                                        # pydantic < 2.12.0\n                                        {\"type\": \"string\"},\n                                        # pydantic >= 2.12.0\n                                        {\n                                            \"type\": \"string\",\n                                            \"pattern\": r\"^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$\",\n                                        },\n                                    ),\n                                ],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_multi_query_errors.py",
    "content": "from fastapi import FastAPI, Query\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\ndef read_items(q: list[int] = Query(default=None)):\n    return {\"q\": q}\n\n\nclient = TestClient(app)\n\n\ndef test_multi_query():\n    response = client.get(\"/items/?q=5&q=6\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"q\": [5, 6]}\n\n\ndef test_multi_query_incorrect():\n    response = client.get(\"/items/?q=five&q=six\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"query\", \"q\", 0],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"five\",\n            },\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"query\", \"q\", 1],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"six\",\n            },\n        ]\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Q\",\n                                    \"type\": \"array\",\n                                    \"items\": {\"type\": \"integer\"},\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_multipart_installation.py",
    "content": "import warnings\n\nimport pytest\nfrom fastapi import FastAPI, File, Form, UploadFile\nfrom fastapi.dependencies.utils import (\n    multipart_incorrect_install_error,\n    multipart_not_installed_error,\n)\n\n\ndef test_incorrect_multipart_installed_form(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        monkeypatch.delattr(\"multipart.multipart.parse_options_header\", raising=False)\n    with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):\n        app = FastAPI()\n\n        @app.post(\"/\")\n        async def root(username: str = Form()):\n            return username  # pragma: nocover\n\n\ndef test_incorrect_multipart_installed_file_upload(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        monkeypatch.delattr(\"multipart.multipart.parse_options_header\", raising=False)\n    with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):\n        app = FastAPI()\n\n        @app.post(\"/\")\n        async def root(f: UploadFile = File()):\n            return f  # pragma: nocover\n\n\ndef test_incorrect_multipart_installed_file_bytes(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        monkeypatch.delattr(\"multipart.multipart.parse_options_header\", raising=False)\n    with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):\n        app = FastAPI()\n\n        @app.post(\"/\")\n        async def root(f: bytes = File()):\n            return f  # pragma: nocover\n\n\ndef test_incorrect_multipart_installed_multi_form(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        monkeypatch.delattr(\"multipart.multipart.parse_options_header\", raising=False)\n    with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):\n        app = FastAPI()\n\n        @app.post(\"/\")\n        async def root(username: str = Form(), password: str = Form()):\n            return username  # pragma: nocover\n\n\ndef test_incorrect_multipart_installed_form_file(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        monkeypatch.delattr(\"multipart.multipart.parse_options_header\", raising=False)\n    with pytest.raises(RuntimeError, match=multipart_incorrect_install_error):\n        app = FastAPI()\n\n        @app.post(\"/\")\n        async def root(username: str = Form(), f: UploadFile = File()):\n            return username  # pragma: nocover\n\n\ndef test_no_multipart_installed(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        monkeypatch.delattr(\"multipart.__version__\", raising=False)\n        with pytest.raises(RuntimeError, match=multipart_not_installed_error):\n            app = FastAPI()\n\n            @app.post(\"/\")\n            async def root(username: str = Form()):\n                return username  # pragma: nocover\n\n\ndef test_no_multipart_installed_file(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        monkeypatch.delattr(\"multipart.__version__\", raising=False)\n        with pytest.raises(RuntimeError, match=multipart_not_installed_error):\n            app = FastAPI()\n\n            @app.post(\"/\")\n            async def root(f: UploadFile = File()):\n                return f  # pragma: nocover\n\n\ndef test_no_multipart_installed_file_bytes(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        monkeypatch.delattr(\"multipart.__version__\", raising=False)\n        with pytest.raises(RuntimeError, match=multipart_not_installed_error):\n            app = FastAPI()\n\n            @app.post(\"/\")\n            async def root(f: bytes = File()):\n                return f  # pragma: nocover\n\n\ndef test_no_multipart_installed_multi_form(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        monkeypatch.delattr(\"multipart.__version__\", raising=False)\n        with pytest.raises(RuntimeError, match=multipart_not_installed_error):\n            app = FastAPI()\n\n            @app.post(\"/\")\n            async def root(username: str = Form(), password: str = Form()):\n                return username  # pragma: nocover\n\n\ndef test_no_multipart_installed_form_file(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        monkeypatch.delattr(\"multipart.__version__\", raising=False)\n        with pytest.raises(RuntimeError, match=multipart_not_installed_error):\n            app = FastAPI()\n\n            @app.post(\"/\")\n            async def root(username: str = Form(), f: UploadFile = File()):\n                return username  # pragma: nocover\n\n\ndef test_old_multipart_installed(monkeypatch):\n    monkeypatch.setattr(\"python_multipart.__version__\", \"0.0.12\")\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        app = FastAPI()\n\n        @app.post(\"/\")\n        async def root(username: str = Form()):\n            return username  # pragma: nocover\n"
  },
  {
    "path": "tests/test_no_schema_split.py",
    "content": "# Test with parts from, and to verify the report in:\n# https://github.com/fastapi/fastapi/discussions/14177\n# Made an issue in:\n# https://github.com/fastapi/fastapi/issues/14247\nfrom enum import Enum\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\n\nclass MessageEventType(str, Enum):\n    alpha = \"alpha\"\n    beta = \"beta\"\n\n\nclass MessageEvent(BaseModel):\n    event_type: MessageEventType = Field(default=MessageEventType.alpha)\n    output: str\n\n\nclass MessageOutput(BaseModel):\n    body: str = \"\"\n    events: list[MessageEvent] = []\n\n\nclass Message(BaseModel):\n    input: str\n    output: MessageOutput\n\n\napp = FastAPI(title=\"Minimal FastAPI App\", version=\"1.0.0\")\n\n\n@app.post(\"/messages\", response_model=Message)\nasync def create_message(input_message: str) -> Message:\n    return Message(\n        input=input_message,\n        output=MessageOutput(body=f\"Processed: {input_message}\"),\n    )\n\n\nclient = TestClient(app)\n\n\ndef test_create_message():\n    response = client.post(\"/messages\", params={\"input_message\": \"Hello\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"input\": \"Hello\",\n        \"output\": {\"body\": \"Processed: Hello\", \"events\": []},\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"Minimal FastAPI App\", \"version\": \"1.0.0\"},\n            \"paths\": {\n                \"/messages\": {\n                    \"post\": {\n                        \"summary\": \"Create Message\",\n                        \"operationId\": \"create_message_messages_post\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"input_message\",\n                                \"in\": \"query\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"string\", \"title\": \"Input Message\"},\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Message\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Message\": {\n                        \"properties\": {\n                            \"input\": {\"type\": \"string\", \"title\": \"Input\"},\n                            \"output\": {\"$ref\": \"#/components/schemas/MessageOutput\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"input\", \"output\"],\n                        \"title\": \"Message\",\n                    },\n                    \"MessageEvent\": {\n                        \"properties\": {\n                            \"event_type\": {\n                                \"$ref\": \"#/components/schemas/MessageEventType\",\n                                \"default\": \"alpha\",\n                            },\n                            \"output\": {\"type\": \"string\", \"title\": \"Output\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"output\"],\n                        \"title\": \"MessageEvent\",\n                    },\n                    \"MessageEventType\": {\n                        \"type\": \"string\",\n                        \"enum\": [\"alpha\", \"beta\"],\n                        \"title\": \"MessageEventType\",\n                    },\n                    \"MessageOutput\": {\n                        \"properties\": {\n                            \"body\": {\"type\": \"string\", \"title\": \"Body\", \"default\": \"\"},\n                            \"events\": {\n                                \"items\": {\"$ref\": \"#/components/schemas/MessageEvent\"},\n                                \"type\": \"array\",\n                                \"title\": \"Events\",\n                                \"default\": [],\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"MessageOutput\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_no_swagger_ui_redirect.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI(swagger_ui_oauth2_redirect_url=None)\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return {\"id\": \"foo\"}\n\n\nclient = TestClient(app)\n\n\ndef test_swagger_ui():\n    response = client.get(\"/docs\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"text/html; charset=utf-8\"\n    assert \"swagger-ui-dist\" in response.text\n    print(client.base_url)\n    assert \"oauth2RedirectUrl\" not in response.text\n\n\ndef test_swagger_ui_no_oauth2_redirect():\n    response = client.get(\"/docs/oauth2-redirect\")\n    assert response.status_code == 404, response.text\n\n\ndef test_response():\n    response = client.get(\"/items/\")\n    assert response.json() == {\"id\": \"foo\"}\n"
  },
  {
    "path": "tests/test_openapi_cache_root_path.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\n\ndef test_root_path_does_not_persist_across_requests():\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def read_root():  # pragma: no cover\n        return {\"ok\": True}\n\n    # Attacker request with a spoofed root_path\n    attacker_client = TestClient(app, root_path=\"/evil-api\")\n    response1 = attacker_client.get(\"/openapi.json\")\n    data1 = response1.json()\n    assert any(s.get(\"url\") == \"/evil-api\" for s in data1.get(\"servers\", []))\n\n    # Subsequent legitimate request with no root_path\n    clean_client = TestClient(app)\n    response2 = clean_client.get(\"/openapi.json\")\n    data2 = response2.json()\n    servers = [s.get(\"url\") for s in data2.get(\"servers\", [])]\n    assert \"/evil-api\" not in servers\n\n\ndef test_multiple_different_root_paths_do_not_accumulate():\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def read_root():  # pragma: no cover\n        return {\"ok\": True}\n\n    for prefix in [\"/path-a\", \"/path-b\", \"/path-c\"]:\n        c = TestClient(app, root_path=prefix)\n        c.get(\"/openapi.json\")\n\n    # A clean request should not have any of them\n    clean_client = TestClient(app)\n    response = clean_client.get(\"/openapi.json\")\n    data = response.json()\n    servers = [s.get(\"url\") for s in data.get(\"servers\", [])]\n    for prefix in [\"/path-a\", \"/path-b\", \"/path-c\"]:\n        assert prefix not in servers, (\n            f\"root_path '{prefix}' leaked into clean request: {servers}\"\n        )\n\n\ndef test_legitimate_root_path_still_appears():\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def read_root():  # pragma: no cover\n        return {\"ok\": True}\n\n    client = TestClient(app, root_path=\"/api/v1\")\n    response = client.get(\"/openapi.json\")\n    data = response.json()\n    servers = [s.get(\"url\") for s in data.get(\"servers\", [])]\n    assert \"/api/v1\" in servers\n\n\ndef test_configured_servers_not_mutated():\n    configured_servers = [{\"url\": \"https://prod.example.com\"}]\n    app = FastAPI(servers=configured_servers)\n\n    @app.get(\"/\")\n    def read_root():  # pragma: no cover\n        return {\"ok\": True}\n\n    # Request with a rogue root_path\n    attacker_client = TestClient(app, root_path=\"/evil\")\n    attacker_client.get(\"/openapi.json\")\n\n    # The original servers list must be untouched\n    assert configured_servers == [{\"url\": \"https://prod.example.com\"}]\n"
  },
  {
    "path": "tests/test_openapi_examples.py",
    "content": "from fastapi import Body, Cookie, FastAPI, Header, Path, Query\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    data: str\n\n\n@app.post(\"/examples/\")\ndef examples(\n    item: Item = Body(\n        examples=[\n            {\"data\": \"Data in Body examples, example1\"},\n        ],\n        openapi_examples={\n            \"Example One\": {\n                \"summary\": \"Example One Summary\",\n                \"description\": \"Example One Description\",\n                \"value\": {\"data\": \"Data in Body examples, example1\"},\n            },\n            \"Example Two\": {\n                \"value\": {\"data\": \"Data in Body examples, example2\"},\n            },\n        },\n    ),\n):\n    return item\n\n\n@app.get(\"/path_examples/{item_id}\")\ndef path_examples(\n    item_id: str = Path(\n        examples=[\n            \"json_schema_item_1\",\n            \"json_schema_item_2\",\n        ],\n        openapi_examples={\n            \"Path One\": {\n                \"summary\": \"Path One Summary\",\n                \"description\": \"Path One Description\",\n                \"value\": \"item_1\",\n            },\n            \"Path Two\": {\n                \"value\": \"item_2\",\n            },\n        },\n    ),\n):\n    return item_id\n\n\n@app.get(\"/query_examples/\")\ndef query_examples(\n    data: str | None = Query(\n        default=None,\n        examples=[\n            \"json_schema_query1\",\n            \"json_schema_query2\",\n        ],\n        openapi_examples={\n            \"Query One\": {\n                \"summary\": \"Query One Summary\",\n                \"description\": \"Query One Description\",\n                \"value\": \"query1\",\n            },\n            \"Query Two\": {\n                \"value\": \"query2\",\n            },\n        },\n    ),\n):\n    return data\n\n\n@app.get(\"/header_examples/\")\ndef header_examples(\n    data: str | None = Header(\n        default=None,\n        examples=[\n            \"json_schema_header1\",\n            \"json_schema_header2\",\n        ],\n        openapi_examples={\n            \"Header One\": {\n                \"summary\": \"Header One Summary\",\n                \"description\": \"Header One Description\",\n                \"value\": \"header1\",\n            },\n            \"Header Two\": {\n                \"value\": \"header2\",\n            },\n        },\n    ),\n):\n    return data\n\n\n@app.get(\"/cookie_examples/\")\ndef cookie_examples(\n    data: str | None = Cookie(\n        default=None,\n        examples=[\"json_schema_cookie1\", \"json_schema_cookie2\"],\n        openapi_examples={\n            \"Cookie One\": {\n                \"summary\": \"Cookie One Summary\",\n                \"description\": \"Cookie One Description\",\n                \"value\": \"cookie1\",\n            },\n            \"Cookie Two\": {\n                \"value\": \"cookie2\",\n            },\n        },\n    ),\n):\n    return data\n\n\nclient = TestClient(app)\n\n\ndef test_call_api():\n    response = client.post(\"/examples/\", json={\"data\": \"example1\"})\n    assert response.status_code == 200, response.text\n\n    response = client.get(\"/path_examples/foo\")\n    assert response.status_code == 200, response.text\n\n    response = client.get(\"/query_examples/\")\n    assert response.status_code == 200, response.text\n\n    response = client.get(\"/header_examples/\")\n    assert response.status_code == 200, response.text\n\n    response = client.get(\"/cookie_examples/\")\n    assert response.status_code == 200, response.text\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/examples/\": {\n                    \"post\": {\n                        \"summary\": \"Examples\",\n                        \"operationId\": \"examples_examples__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                        \"examples\": [\n                                            {\"data\": \"Data in Body examples, example1\"}\n                                        ],\n                                    },\n                                    \"examples\": {\n                                        \"Example One\": {\n                                            \"summary\": \"Example One Summary\",\n                                            \"description\": \"Example One Description\",\n                                            \"value\": {\n                                                \"data\": \"Data in Body examples, example1\"\n                                            },\n                                        },\n                                        \"Example Two\": {\n                                            \"value\": {\n                                                \"data\": \"Data in Body examples, example2\"\n                                            }\n                                        },\n                                    },\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/path_examples/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Path Examples\",\n                        \"operationId\": \"path_examples_path_examples__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"type\": \"string\",\n                                    \"examples\": [\n                                        \"json_schema_item_1\",\n                                        \"json_schema_item_2\",\n                                    ],\n                                    \"title\": \"Item Id\",\n                                },\n                                \"examples\": {\n                                    \"Path One\": {\n                                        \"summary\": \"Path One Summary\",\n                                        \"description\": \"Path One Description\",\n                                        \"value\": \"item_1\",\n                                    },\n                                    \"Path Two\": {\"value\": \"item_2\"},\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/query_examples/\": {\n                    \"get\": {\n                        \"summary\": \"Query Examples\",\n                        \"operationId\": \"query_examples_query_examples__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"data\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"examples\": [\n                                        \"json_schema_query1\",\n                                        \"json_schema_query2\",\n                                    ],\n                                    \"title\": \"Data\",\n                                },\n                                \"examples\": {\n                                    \"Query One\": {\n                                        \"summary\": \"Query One Summary\",\n                                        \"description\": \"Query One Description\",\n                                        \"value\": \"query1\",\n                                    },\n                                    \"Query Two\": {\"value\": \"query2\"},\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/header_examples/\": {\n                    \"get\": {\n                        \"summary\": \"Header Examples\",\n                        \"operationId\": \"header_examples_header_examples__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"data\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"examples\": [\n                                        \"json_schema_header1\",\n                                        \"json_schema_header2\",\n                                    ],\n                                    \"title\": \"Data\",\n                                },\n                                \"examples\": {\n                                    \"Header One\": {\n                                        \"summary\": \"Header One Summary\",\n                                        \"description\": \"Header One Description\",\n                                        \"value\": \"header1\",\n                                    },\n                                    \"Header Two\": {\"value\": \"header2\"},\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/cookie_examples/\": {\n                    \"get\": {\n                        \"summary\": \"Cookie Examples\",\n                        \"operationId\": \"cookie_examples_cookie_examples__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"data\",\n                                \"in\": \"cookie\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"examples\": [\n                                        \"json_schema_cookie1\",\n                                        \"json_schema_cookie2\",\n                                    ],\n                                    \"title\": \"Data\",\n                                },\n                                \"examples\": {\n                                    \"Cookie One\": {\n                                        \"summary\": \"Cookie One Summary\",\n                                        \"description\": \"Cookie One Description\",\n                                        \"value\": \"cookie1\",\n                                    },\n                                    \"Cookie Two\": {\"value\": \"cookie2\"},\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\"data\": {\"type\": \"string\", \"title\": \"Data\"}},\n                        \"type\": \"object\",\n                        \"required\": [\"data\"],\n                        \"title\": \"Item\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_openapi_model_description_trim_on_formfeed.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass MyModel(BaseModel):\n    \"\"\"\n    A model with a form feed character in the title.\n    \\f\n    Text after form feed character.\n    \"\"\"\n\n\n@app.get(\"/foo\")\ndef foo(v: MyModel):  # pragma: no cover\n    pass\n\n\nclient = TestClient(app)\n\n\ndef test_openapi():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    openapi_schema = response.json()\n\n    assert openapi_schema[\"components\"][\"schemas\"][\"MyModel\"][\"description\"] == (\n        \"A model with a form feed character in the title.\\n\"\n    )\n"
  },
  {
    "path": "tests/test_openapi_query_parameter_extension.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\n@app.get(\n    \"/\",\n    openapi_extra={\n        \"parameters\": [\n            {\n                \"required\": False,\n                \"schema\": {\"title\": \"Extra Param 1\"},\n                \"name\": \"extra_param_1\",\n                \"in\": \"query\",\n            },\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"Extra Param 2\"},\n                \"name\": \"extra_param_2\",\n                \"in\": \"query\",\n            },\n        ]\n    },\n)\ndef route_with_extra_query_parameters(standard_query_param: int | None = 50):\n    return {}\n\n\nclient = TestClient(app)\n\n\ndef test_get_route():\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {}\n\n\ndef test_openapi():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Route With Extra Query Parameters\",\n                        \"operationId\": \"route_with_extra_query_parameters__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                    \"default\": 50,\n                                    \"title\": \"Standard Query Param\",\n                                },\n                                \"name\": \"standard_query_param\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\"title\": \"Extra Param 1\"},\n                                \"name\": \"extra_param_1\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Extra Param 2\"},\n                                \"name\": \"extra_param_2\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_openapi_route_extensions.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\n@app.get(\"/\", openapi_extra={\"x-custom-extension\": \"value\"})\ndef route_with_extras():\n    return {}\n\n\nclient = TestClient(app)\n\n\ndef test_get_route():\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                        },\n                        \"summary\": \"Route With Extras\",\n                        \"operationId\": \"route_with_extras__get\",\n                        \"x-custom-extension\": \"value\",\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_openapi_schema_type.py",
    "content": "import pytest\nfrom fastapi.openapi.models import Schema, SchemaType\n\n\n@pytest.mark.parametrize(\n    \"type_value\",\n    [\n        \"array\",\n        [\"string\", \"null\"],\n        None,\n    ],\n)\ndef test_allowed_schema_type(\n    type_value: SchemaType | list[SchemaType] | None,\n) -> None:\n    \"\"\"Test that Schema accepts SchemaType, List[SchemaType] and None for type field.\"\"\"\n    schema = Schema(type=type_value)\n    assert schema.type == type_value\n\n\ndef test_invalid_type_value() -> None:\n    \"\"\"Test that Schema raises ValueError for invalid type values.\"\"\"\n    with pytest.raises(ValueError, match=\"2 validation errors for Schema\"):\n        Schema(type=True)  # type: ignore[arg-type]\n"
  },
  {
    "path": "tests/test_openapi_separate_input_output_schemas.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, computed_field\n\n\nclass SubItem(BaseModel):\n    subname: str\n    sub_description: str | None = None\n    tags: list[str] = []\n    model_config = {\"json_schema_serialization_defaults_required\": True}\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n    sub: SubItem | None = None\n    model_config = {\"json_schema_serialization_defaults_required\": True}\n\n\nclass WithComputedField(BaseModel):\n    name: str\n\n    @computed_field\n    @property\n    def computed_field(self) -> str:\n        return f\"computed {self.name}\"\n\n\ndef get_app_client(separate_input_output_schemas: bool = True) -> TestClient:\n    app = FastAPI(separate_input_output_schemas=separate_input_output_schemas)\n\n    @app.post(\"/items/\", responses={402: {\"model\": Item}})\n    def create_item(item: Item) -> Item:\n        return item\n\n    @app.post(\"/items-list/\")\n    def create_item_list(item: list[Item]):\n        return item\n\n    @app.get(\"/items/\")\n    def read_items() -> list[Item]:\n        return [\n            Item(\n                name=\"Portal Gun\",\n                description=\"Device to travel through the multi-rick-verse\",\n                sub=SubItem(subname=\"subname\"),\n            ),\n            Item(name=\"Plumbus\"),\n        ]\n\n    @app.post(\"/with-computed-field/\")\n    def create_with_computed_field(\n        with_computed_field: WithComputedField,\n    ) -> WithComputedField:\n        return with_computed_field\n\n    client = TestClient(app)\n    return client\n\n\ndef test_create_item():\n    client = get_app_client()\n    client_no = get_app_client(separate_input_output_schemas=False)\n    response = client.post(\"/items/\", json={\"name\": \"Plumbus\"})\n    response2 = client_no.post(\"/items/\", json={\"name\": \"Plumbus\"})\n    assert response.status_code == response2.status_code == 200, response.text\n    assert (\n        response.json()\n        == response2.json()\n        == {\"name\": \"Plumbus\", \"description\": None, \"sub\": None}\n    )\n\n\ndef test_create_item_with_sub():\n    client = get_app_client()\n    client_no = get_app_client(separate_input_output_schemas=False)\n    data = {\n        \"name\": \"Plumbus\",\n        \"sub\": {\"subname\": \"SubPlumbus\", \"sub_description\": \"Sub WTF\"},\n    }\n    response = client.post(\"/items/\", json=data)\n    response2 = client_no.post(\"/items/\", json=data)\n    assert response.status_code == response2.status_code == 200, response.text\n    assert (\n        response.json()\n        == response2.json()\n        == {\n            \"name\": \"Plumbus\",\n            \"description\": None,\n            \"sub\": {\"subname\": \"SubPlumbus\", \"sub_description\": \"Sub WTF\", \"tags\": []},\n        }\n    )\n\n\ndef test_create_item_list():\n    client = get_app_client()\n    client_no = get_app_client(separate_input_output_schemas=False)\n    data = [\n        {\"name\": \"Plumbus\"},\n        {\n            \"name\": \"Portal Gun\",\n            \"description\": \"Device to travel through the multi-rick-verse\",\n        },\n    ]\n    response = client.post(\"/items-list/\", json=data)\n    response2 = client_no.post(\"/items-list/\", json=data)\n    assert response.status_code == response2.status_code == 200, response.text\n    assert (\n        response.json()\n        == response2.json()\n        == [\n            {\"name\": \"Plumbus\", \"description\": None, \"sub\": None},\n            {\n                \"name\": \"Portal Gun\",\n                \"description\": \"Device to travel through the multi-rick-verse\",\n                \"sub\": None,\n            },\n        ]\n    )\n\n\ndef test_read_items():\n    client = get_app_client()\n    client_no = get_app_client(separate_input_output_schemas=False)\n    response = client.get(\"/items/\")\n    response2 = client_no.get(\"/items/\")\n    assert response.status_code == response2.status_code == 200, response.text\n    assert (\n        response.json()\n        == response2.json()\n        == [\n            {\n                \"name\": \"Portal Gun\",\n                \"description\": \"Device to travel through the multi-rick-verse\",\n                \"sub\": {\"subname\": \"subname\", \"sub_description\": None, \"tags\": []},\n            },\n            {\"name\": \"Plumbus\", \"description\": None, \"sub\": None},\n        ]\n    )\n\n\ndef test_with_computed_field():\n    client = get_app_client()\n    client_no = get_app_client(separate_input_output_schemas=False)\n    response = client.post(\"/with-computed-field/\", json={\"name\": \"example\"})\n    response2 = client_no.post(\"/with-computed-field/\", json={\"name\": \"example\"})\n    assert response.status_code == response2.status_code == 200, response.text\n    assert (\n        response.json()\n        == response2.json()\n        == {\n            \"name\": \"example\",\n            \"computed_field\": \"computed example\",\n        }\n    )\n\n\ndef test_openapi_schema():\n    client = get_app_client()\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item-Output\"\n                                            },\n                                            \"type\": \"array\",\n                                            \"title\": \"Response Read Items Items  Get\",\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item-Input\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Item-Output\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"402\": {\n                                \"description\": \"Payment Required\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Item-Output\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/items-list/\": {\n                    \"post\": {\n                        \"summary\": \"Create Item List\",\n                        \"operationId\": \"create_item_list_items_list__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"items\": {\n                                            \"$ref\": \"#/components/schemas/Item-Input\"\n                                        },\n                                        \"type\": \"array\",\n                                        \"title\": \"Item\",\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/with-computed-field/\": {\n                    \"post\": {\n                        \"summary\": \"Create With Computed Field\",\n                        \"operationId\": \"create_with_computed_field_with_computed_field__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/WithComputedField-Input\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/WithComputedField-Output\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Item-Input\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                            },\n                            \"sub\": {\n                                \"anyOf\": [\n                                    {\"$ref\": \"#/components/schemas/SubItem-Input\"},\n                                    {\"type\": \"null\"},\n                                ]\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\"],\n                        \"title\": \"Item\",\n                    },\n                    \"Item-Output\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                            },\n                            \"sub\": {\n                                \"anyOf\": [\n                                    {\"$ref\": \"#/components/schemas/SubItem-Output\"},\n                                    {\"type\": \"null\"},\n                                ]\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"description\", \"sub\"],\n                        \"title\": \"Item\",\n                    },\n                    \"SubItem-Input\": {\n                        \"properties\": {\n                            \"subname\": {\"type\": \"string\", \"title\": \"Subname\"},\n                            \"sub_description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Sub Description\",\n                            },\n                            \"tags\": {\n                                \"items\": {\"type\": \"string\"},\n                                \"type\": \"array\",\n                                \"title\": \"Tags\",\n                                \"default\": [],\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"subname\"],\n                        \"title\": \"SubItem\",\n                    },\n                    \"SubItem-Output\": {\n                        \"properties\": {\n                            \"subname\": {\"type\": \"string\", \"title\": \"Subname\"},\n                            \"sub_description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Sub Description\",\n                            },\n                            \"tags\": {\n                                \"items\": {\"type\": \"string\"},\n                                \"type\": \"array\",\n                                \"title\": \"Tags\",\n                                \"default\": [],\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"subname\", \"sub_description\", \"tags\"],\n                        \"title\": \"SubItem\",\n                    },\n                    \"WithComputedField-Input\": {\n                        \"properties\": {\"name\": {\"type\": \"string\", \"title\": \"Name\"}},\n                        \"type\": \"object\",\n                        \"required\": [\"name\"],\n                        \"title\": \"WithComputedField\",\n                    },\n                    \"WithComputedField-Output\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"computed_field\": {\n                                \"type\": \"string\",\n                                \"title\": \"Computed Field\",\n                                \"readOnly\": True,\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"computed_field\"],\n                        \"title\": \"WithComputedField\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n\n\ndef test_openapi_schema_no_separate():\n    client = get_app_client(separate_input_output_schemas=False)\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                            \"type\": \"array\",\n                                            \"title\": \"Response Read Items Items  Get\",\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"402\": {\n                                \"description\": \"Payment Required\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/items-list/\": {\n                    \"post\": {\n                        \"summary\": \"Create Item List\",\n                        \"operationId\": \"create_item_list_items_list__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"items\": {\"$ref\": \"#/components/schemas/Item\"},\n                                        \"type\": \"array\",\n                                        \"title\": \"Item\",\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/with-computed-field/\": {\n                    \"post\": {\n                        \"summary\": \"Create With Computed Field\",\n                        \"operationId\": \"create_with_computed_field_with_computed_field__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/WithComputedField-Input\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/WithComputedField-Output\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                            },\n                            \"sub\": {\n                                \"anyOf\": [\n                                    {\"$ref\": \"#/components/schemas/SubItem\"},\n                                    {\"type\": \"null\"},\n                                ]\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\"],\n                        \"title\": \"Item\",\n                    },\n                    \"SubItem\": {\n                        \"properties\": {\n                            \"subname\": {\"type\": \"string\", \"title\": \"Subname\"},\n                            \"sub_description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Sub Description\",\n                            },\n                            \"tags\": {\n                                \"items\": {\"type\": \"string\"},\n                                \"type\": \"array\",\n                                \"title\": \"Tags\",\n                                \"default\": [],\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"subname\"],\n                        \"title\": \"SubItem\",\n                    },\n                    \"WithComputedField-Input\": {\n                        \"properties\": {\"name\": {\"type\": \"string\", \"title\": \"Name\"}},\n                        \"type\": \"object\",\n                        \"required\": [\"name\"],\n                        \"title\": \"WithComputedField\",\n                    },\n                    \"WithComputedField-Output\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"computed_field\": {\n                                \"type\": \"string\",\n                                \"title\": \"Computed Field\",\n                                \"readOnly\": True,\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"computed_field\"],\n                        \"title\": \"WithComputedField\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_openapi_servers.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI(\n    servers=[\n        {\"url\": \"/\", \"description\": \"Default, relative server\"},\n        {\n            \"url\": \"http://staging.localhost.tiangolo.com:8000\",\n            \"description\": \"Staging but actually localhost still\",\n        },\n        {\"url\": \"https://prod.example.com\"},\n    ]\n)\n\n\n@app.get(\"/foo\")\ndef foo():\n    return {\"message\": \"Hello World\"}\n\n\nclient = TestClient(app)\n\n\ndef test_app():\n    response = client.get(\"/foo\")\n    assert response.status_code == 200, response.text\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"servers\": [\n                {\"url\": \"/\", \"description\": \"Default, relative server\"},\n                {\n                    \"url\": \"http://staging.localhost.tiangolo.com:8000\",\n                    \"description\": \"Staging but actually localhost still\",\n                },\n                {\"url\": \"https://prod.example.com\"},\n            ],\n            \"paths\": {\n                \"/foo\": {\n                    \"get\": {\n                        \"summary\": \"Foo\",\n                        \"operationId\": \"foo_foo_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_operations_signatures.py",
    "content": "import inspect\n\nfrom fastapi import APIRouter, FastAPI\n\nmethod_names = [\"get\", \"put\", \"post\", \"delete\", \"options\", \"head\", \"patch\", \"trace\"]\n\n\ndef test_signatures_consistency():\n    base_sig = inspect.signature(APIRouter.get)\n    for method_name in method_names:\n        router_method = getattr(APIRouter, method_name)\n        app_method = getattr(FastAPI, method_name)\n        router_sig = inspect.signature(router_method)\n        app_sig = inspect.signature(app_method)\n        param: inspect.Parameter\n        for key, param in base_sig.parameters.items():\n            router_param: inspect.Parameter = router_sig.parameters[key]\n            app_param: inspect.Parameter = app_sig.parameters[key]\n            assert param.annotation == router_param.annotation\n            assert param.annotation == app_param.annotation\n            assert param.default == router_param.default\n            assert param.default == app_param.default\n"
  },
  {
    "path": "tests/test_optional_file_list.py",
    "content": "from fastapi import FastAPI, File\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.post(\"/files\")\nasync def upload_files(files: list[bytes] | None = File(None)):\n    if files is None:\n        return {\"files_count\": 0}\n    return {\"files_count\": len(files), \"sizes\": [len(f) for f in files]}\n\n\ndef test_optional_bytes_list():\n    client = TestClient(app)\n    response = client.post(\n        \"/files\",\n        files=[(\"files\", b\"content1\"), (\"files\", b\"content2\")],\n    )\n    assert response.status_code == 200\n    assert response.json() == {\"files_count\": 2, \"sizes\": [8, 8]}\n\n\ndef test_optional_bytes_list_no_files():\n    client = TestClient(app)\n    response = client.post(\"/files\")\n    assert response.status_code == 200\n    assert response.json() == {\"files_count\": 0}\n"
  },
  {
    "path": "tests/test_orjson_response_class.py",
    "content": "import warnings\n\nimport pytest\n\npytest.importorskip(\"orjson\")\n\nfrom fastapi import FastAPI\nfrom fastapi.exceptions import FastAPIDeprecationWarning\nfrom fastapi.responses import ORJSONResponse\nfrom fastapi.testclient import TestClient\nfrom sqlalchemy.sql.elements import quoted_name\n\nwith warnings.catch_warnings():\n    warnings.simplefilter(\"ignore\", FastAPIDeprecationWarning)\n    app = FastAPI(default_response_class=ORJSONResponse)\n\n\n@app.get(\"/orjson_non_str_keys\")\ndef get_orjson_non_str_keys():\n    key = quoted_name(value=\"msg\", quote=False)\n    return {key: \"Hello World\", 1: 1}\n\n\nclient = TestClient(app)\n\n\ndef test_orjson_non_str_keys():\n    with warnings.catch_warnings():\n        warnings.simplefilter(\"ignore\", FastAPIDeprecationWarning)\n        with client:\n            response = client.get(\"/orjson_non_str_keys\")\n    assert response.json() == {\"msg\": \"Hello World\", \"1\": 1}\n"
  },
  {
    "path": "tests/test_param_class.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.params import Param\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.get(\"/items/\")\ndef read_items(q: str | None = Param(default=None)):  # type: ignore\n    return {\"q\": q}\n\n\nclient = TestClient(app)\n\n\ndef test_default_param_query_none():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"q\": None}\n\n\ndef test_default_param_query():\n    response = client.get(\"/items/?q=foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"q\": \"foo\"}\n"
  },
  {
    "path": "tests/test_param_in_path_and_dependency.py",
    "content": "from fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\nasync def user_exists(user_id: int):\n    return True\n\n\n@app.get(\"/users/{user_id}\", dependencies=[Depends(user_exists)])\nasync def read_users(user_id: int):\n    pass\n\n\nclient = TestClient(app)\n\n\ndef test_read_users():\n    response = client.get(\"/users/42\")\n    assert response.status_code == 200, response.text\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/{user_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Users\",\n                        \"operationId\": \"read_users_users__user_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"User Id\", \"type\": \"integer\"},\n                                \"name\": \"user_id\",\n                                \"in\": \"path\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_param_include_in_schema.py",
    "content": "import pytest\nfrom fastapi import Cookie, FastAPI, Header, Path, Query\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\n@app.get(\"/hidden_cookie\")\nasync def hidden_cookie(\n    hidden_cookie: str | None = Cookie(default=None, include_in_schema=False),\n):\n    return {\"hidden_cookie\": hidden_cookie}\n\n\n@app.get(\"/hidden_header\")\nasync def hidden_header(\n    hidden_header: str | None = Header(default=None, include_in_schema=False),\n):\n    return {\"hidden_header\": hidden_header}\n\n\n@app.get(\"/hidden_path/{hidden_path}\")\nasync def hidden_path(hidden_path: str = Path(include_in_schema=False)):\n    return {\"hidden_path\": hidden_path}\n\n\n@app.get(\"/hidden_query\")\nasync def hidden_query(\n    hidden_query: str | None = Query(default=None, include_in_schema=False),\n):\n    return {\"hidden_query\": hidden_query}\n\n\n@pytest.mark.parametrize(\n    \"path,cookies,expected_status,expected_response\",\n    [\n        (\n            \"/hidden_cookie\",\n            {},\n            200,\n            {\"hidden_cookie\": None},\n        ),\n        (\n            \"/hidden_cookie\",\n            {\"hidden_cookie\": \"somevalue\"},\n            200,\n            {\"hidden_cookie\": \"somevalue\"},\n        ),\n    ],\n)\ndef test_hidden_cookie(path, cookies, expected_status, expected_response):\n    client = TestClient(app, cookies=cookies)\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\n@pytest.mark.parametrize(\n    \"path,headers,expected_status,expected_response\",\n    [\n        (\n            \"/hidden_header\",\n            {},\n            200,\n            {\"hidden_header\": None},\n        ),\n        (\n            \"/hidden_header\",\n            {\"Hidden-Header\": \"somevalue\"},\n            200,\n            {\"hidden_header\": \"somevalue\"},\n        ),\n    ],\n)\ndef test_hidden_header(path, headers, expected_status, expected_response):\n    client = TestClient(app)\n    response = client.get(path, headers=headers)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_hidden_path():\n    client = TestClient(app)\n    response = client.get(\"/hidden_path/hidden_path\")\n    assert response.status_code == 200\n    assert response.json() == {\"hidden_path\": \"hidden_path\"}\n\n\n@pytest.mark.parametrize(\n    \"path,expected_status,expected_response\",\n    [\n        (\n            \"/hidden_query\",\n            200,\n            {\"hidden_query\": None},\n        ),\n        (\n            \"/hidden_query?hidden_query=somevalue\",\n            200,\n            {\"hidden_query\": \"somevalue\"},\n        ),\n    ],\n)\ndef test_hidden_query(path, expected_status, expected_response):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema():\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/hidden_cookie\": {\n                    \"get\": {\n                        \"summary\": \"Hidden Cookie\",\n                        \"operationId\": \"hidden_cookie_hidden_cookie_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/hidden_header\": {\n                    \"get\": {\n                        \"summary\": \"Hidden Header\",\n                        \"operationId\": \"hidden_header_hidden_header_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/hidden_path/{hidden_path}\": {\n                    \"get\": {\n                        \"summary\": \"Hidden Path\",\n                        \"operationId\": \"hidden_path_hidden_path__hidden_path__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/hidden_query\": {\n                    \"get\": {\n                        \"summary\": \"Hidden Query\",\n                        \"operationId\": \"hidden_query_hidden_query_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_params_repr.py",
    "content": "from typing import Any\n\nfrom fastapi.params import Body, Cookie, Header, Param, Path, Query\n\ntest_data: list[Any] = [\"teststr\", None, ..., 1, []]\n\n\ndef get_user():\n    return {}  # pragma: no cover\n\n\ndef test_param_repr_str():\n    assert repr(Param(\"teststr\")) == \"Param(teststr)\"\n\n\ndef test_param_repr_none():\n    assert repr(Param(None)) == \"Param(None)\"\n\n\ndef test_param_repr_ellipsis():\n    assert repr(Param(...)) == \"Param(PydanticUndefined)\"\n\n\ndef test_param_repr_number():\n    assert repr(Param(1)) == \"Param(1)\"\n\n\ndef test_param_repr_list():\n    assert repr(Param([])) == \"Param([])\"\n\n\ndef test_path_repr():\n    assert repr(Path()) == \"Path(PydanticUndefined)\"\n    assert repr(Path(...)) == \"Path(PydanticUndefined)\"\n\n\ndef test_query_repr_str():\n    assert repr(Query(\"teststr\")) == \"Query(teststr)\"\n\n\ndef test_query_repr_none():\n    assert repr(Query(None)) == \"Query(None)\"\n\n\ndef test_query_repr_ellipsis():\n    assert repr(Query(...)) == \"Query(PydanticUndefined)\"\n\n\ndef test_query_repr_number():\n    assert repr(Query(1)) == \"Query(1)\"\n\n\ndef test_query_repr_list():\n    assert repr(Query([])) == \"Query([])\"\n\n\ndef test_header_repr_str():\n    assert repr(Header(\"teststr\")) == \"Header(teststr)\"\n\n\ndef test_header_repr_none():\n    assert repr(Header(None)) == \"Header(None)\"\n\n\ndef test_header_repr_ellipsis():\n    assert repr(Header(...)) == \"Header(PydanticUndefined)\"\n\n\ndef test_header_repr_number():\n    assert repr(Header(1)) == \"Header(1)\"\n\n\ndef test_header_repr_list():\n    assert repr(Header([])) == \"Header([])\"\n\n\ndef test_cookie_repr_str():\n    assert repr(Cookie(\"teststr\")) == \"Cookie(teststr)\"\n\n\ndef test_cookie_repr_none():\n    assert repr(Cookie(None)) == \"Cookie(None)\"\n\n\ndef test_cookie_repr_ellipsis():\n    assert repr(Cookie(...)) == \"Cookie(PydanticUndefined)\"\n\n\ndef test_cookie_repr_number():\n    assert repr(Cookie(1)) == \"Cookie(1)\"\n\n\ndef test_cookie_repr_list():\n    assert repr(Cookie([])) == \"Cookie([])\"\n\n\ndef test_body_repr_str():\n    assert repr(Body(\"teststr\")) == \"Body(teststr)\"\n\n\ndef test_body_repr_none():\n    assert repr(Body(None)) == \"Body(None)\"\n\n\ndef test_body_repr_ellipsis():\n    assert repr(Body(...)) == \"Body(PydanticUndefined)\"\n\n\ndef test_body_repr_number():\n    assert repr(Body(1)) == \"Body(1)\"\n\n\ndef test_body_repr_list():\n    assert repr(Body([])) == \"Body([])\"\n"
  },
  {
    "path": "tests/test_path.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom .main import app\n\nclient = TestClient(app)\n\n\ndef test_text_get():\n    response = client.get(\"/text\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"Hello World\"\n\n\ndef test_nonexistent():\n    response = client.get(\"/nonexistent\")\n    assert response.status_code == 404, response.text\n    assert response.json() == {\"detail\": \"Not Found\"}\n\n\ndef test_path_foobar():\n    response = client.get(\"/path/foobar\")\n    assert response.status_code == 200\n    assert response.json() == \"foobar\"\n\n\ndef test_path_str_foobar():\n    response = client.get(\"/path/str/foobar\")\n    assert response.status_code == 200\n    assert response.json() == \"foobar\"\n\n\ndef test_path_str_42():\n    response = client.get(\"/path/str/42\")\n    assert response.status_code == 200\n    assert response.json() == \"42\"\n\n\ndef test_path_str_True():\n    response = client.get(\"/path/str/True\")\n    assert response.status_code == 200\n    assert response.json() == \"True\"\n\n\ndef test_path_int_foobar():\n    response = client.get(\"/path/int/foobar\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"foobar\",\n            }\n        ]\n    }\n\n\ndef test_path_int_True():\n    response = client.get(\"/path/int/True\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"True\",\n            }\n        ]\n    }\n\n\ndef test_path_int_42():\n    response = client.get(\"/path/int/42\")\n    assert response.status_code == 200\n    assert response.json() == 42\n\n\ndef test_path_int_42_5():\n    response = client.get(\"/path/int/42.5\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"42.5\",\n            }\n        ]\n    }\n\n\ndef test_path_float_foobar():\n    response = client.get(\"/path/float/foobar\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"float_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid number, unable to parse string as a number\",\n                \"input\": \"foobar\",\n            }\n        ]\n    }\n\n\ndef test_path_float_True():\n    response = client.get(\"/path/float/True\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"float_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid number, unable to parse string as a number\",\n                \"input\": \"True\",\n            }\n        ]\n    }\n\n\ndef test_path_float_42():\n    response = client.get(\"/path/float/42\")\n    assert response.status_code == 200\n    assert response.json() == 42\n\n\ndef test_path_float_42_5():\n    response = client.get(\"/path/float/42.5\")\n    assert response.status_code == 200\n    assert response.json() == 42.5\n\n\ndef test_path_bool_foobar():\n    response = client.get(\"/path/bool/foobar\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"bool_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid boolean, unable to interpret input\",\n                \"input\": \"foobar\",\n            }\n        ]\n    }\n\n\ndef test_path_bool_True():\n    response = client.get(\"/path/bool/True\")\n    assert response.status_code == 200\n    assert response.json() is True\n\n\ndef test_path_bool_42():\n    response = client.get(\"/path/bool/42\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"bool_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid boolean, unable to interpret input\",\n                \"input\": \"42\",\n            }\n        ]\n    }\n\n\ndef test_path_bool_42_5():\n    response = client.get(\"/path/bool/42.5\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"bool_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid boolean, unable to interpret input\",\n                \"input\": \"42.5\",\n            }\n        ]\n    }\n\n\ndef test_path_bool_1():\n    response = client.get(\"/path/bool/1\")\n    assert response.status_code == 200\n    assert response.json() is True\n\n\ndef test_path_bool_0():\n    response = client.get(\"/path/bool/0\")\n    assert response.status_code == 200\n    assert response.json() is False\n\n\ndef test_path_bool_true():\n    response = client.get(\"/path/bool/true\")\n    assert response.status_code == 200\n    assert response.json() is True\n\n\ndef test_path_bool_False():\n    response = client.get(\"/path/bool/False\")\n    assert response.status_code == 200\n    assert response.json() is False\n\n\ndef test_path_bool_false():\n    response = client.get(\"/path/bool/false\")\n    assert response.status_code == 200\n    assert response.json() is False\n\n\ndef test_path_param_foo():\n    response = client.get(\"/path/param/foo\")\n    assert response.status_code == 200\n    assert response.json() == \"foo\"\n\n\ndef test_path_param_minlength_foo():\n    response = client.get(\"/path/param-minlength/foo\")\n    assert response.status_code == 200\n    assert response.json() == \"foo\"\n\n\ndef test_path_param_minlength_fo():\n    response = client.get(\"/path/param-minlength/fo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_short\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"String should have at least 3 characters\",\n                \"input\": \"fo\",\n                \"ctx\": {\"min_length\": 3},\n            }\n        ]\n    }\n\n\ndef test_path_param_maxlength_foo():\n    response = client.get(\"/path/param-maxlength/foo\")\n    assert response.status_code == 200\n    assert response.json() == \"foo\"\n\n\ndef test_path_param_maxlength_foobar():\n    response = client.get(\"/path/param-maxlength/foobar\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_long\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"String should have at most 3 characters\",\n                \"input\": \"foobar\",\n                \"ctx\": {\"max_length\": 3},\n            }\n        ]\n    }\n\n\ndef test_path_param_min_maxlength_foo():\n    response = client.get(\"/path/param-min_maxlength/foo\")\n    assert response.status_code == 200\n    assert response.json() == \"foo\"\n\n\ndef test_path_param_min_maxlength_foobar():\n    response = client.get(\"/path/param-min_maxlength/foobar\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_long\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"String should have at most 3 characters\",\n                \"input\": \"foobar\",\n                \"ctx\": {\"max_length\": 3},\n            }\n        ]\n    }\n\n\ndef test_path_param_min_maxlength_f():\n    response = client.get(\"/path/param-min_maxlength/f\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_short\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"String should have at least 2 characters\",\n                \"input\": \"f\",\n                \"ctx\": {\"min_length\": 2},\n            }\n        ]\n    }\n\n\ndef test_path_param_gt_42():\n    response = client.get(\"/path/param-gt/42\")\n    assert response.status_code == 200\n    assert response.json() == 42\n\n\ndef test_path_param_gt_2():\n    response = client.get(\"/path/param-gt/2\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"greater_than\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be greater than 3\",\n                \"input\": \"2\",\n                \"ctx\": {\"gt\": 3.0},\n            }\n        ]\n    }\n\n\ndef test_path_param_gt0_0_05():\n    response = client.get(\"/path/param-gt0/0.05\")\n    assert response.status_code == 200\n    assert response.json() == 0.05\n\n\ndef test_path_param_gt0_0():\n    response = client.get(\"/path/param-gt0/0\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"greater_than\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be greater than 0\",\n                \"input\": \"0\",\n                \"ctx\": {\"gt\": 0.0},\n            }\n        ]\n    }\n\n\ndef test_path_param_ge_42():\n    response = client.get(\"/path/param-ge/42\")\n    assert response.status_code == 200\n    assert response.json() == 42\n\n\ndef test_path_param_ge_3():\n    response = client.get(\"/path/param-ge/3\")\n    assert response.status_code == 200\n    assert response.json() == 3\n\n\ndef test_path_param_ge_2():\n    response = client.get(\"/path/param-ge/2\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"greater_than_equal\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be greater than or equal to 3\",\n                \"input\": \"2\",\n                \"ctx\": {\"ge\": 3.0},\n            }\n        ]\n    }\n\n\ndef test_path_param_lt_42():\n    response = client.get(\"/path/param-lt/42\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"less_than\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be less than 3\",\n                \"input\": \"42\",\n                \"ctx\": {\"lt\": 3.0},\n            }\n        ]\n    }\n\n\ndef test_path_param_lt_2():\n    response = client.get(\"/path/param-lt/2\")\n    assert response.status_code == 200\n    assert response.json() == 2\n\n\ndef test_path_param_lt0__1():\n    response = client.get(\"/path/param-lt0/-1\")\n    assert response.status_code == 200\n    assert response.json() == -1\n\n\ndef test_path_param_lt0_0():\n    response = client.get(\"/path/param-lt0/0\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"less_than\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be less than 0\",\n                \"input\": \"0\",\n                \"ctx\": {\"lt\": 0.0},\n            }\n        ]\n    }\n\n\ndef test_path_param_le_42():\n    response = client.get(\"/path/param-le/42\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"less_than_equal\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be less than or equal to 3\",\n                \"input\": \"42\",\n                \"ctx\": {\"le\": 3.0},\n            }\n        ]\n    }\n\n\ndef test_path_param_le_3():\n    response = client.get(\"/path/param-le/3\")\n    assert response.status_code == 200\n    assert response.json() == 3\n\n\ndef test_path_param_le_2():\n    response = client.get(\"/path/param-le/2\")\n    assert response.status_code == 200\n    assert response.json() == 2\n\n\ndef test_path_param_lt_gt_2():\n    response = client.get(\"/path/param-lt-gt/2\")\n    assert response.status_code == 200\n    assert response.json() == 2\n\n\ndef test_path_param_lt_gt_4():\n    response = client.get(\"/path/param-lt-gt/4\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"less_than\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be less than 3\",\n                \"input\": \"4\",\n                \"ctx\": {\"lt\": 3.0},\n            }\n        ]\n    }\n\n\ndef test_path_param_lt_gt_0():\n    response = client.get(\"/path/param-lt-gt/0\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"greater_than\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be greater than 1\",\n                \"input\": \"0\",\n                \"ctx\": {\"gt\": 1.0},\n            }\n        ]\n    }\n\n\ndef test_path_param_le_ge_2():\n    response = client.get(\"/path/param-le-ge/2\")\n    assert response.status_code == 200\n    assert response.json() == 2\n\n\ndef test_path_param_le_ge_1():\n    response = client.get(\"/path/param-le-ge/1\")\n    assert response.status_code == 200\n\n\ndef test_path_param_le_ge_3():\n    response = client.get(\"/path/param-le-ge/3\")\n    assert response.status_code == 200\n    assert response.json() == 3\n\n\ndef test_path_param_le_ge_4():\n    response = client.get(\"/path/param-le-ge/4\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"less_than_equal\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be less than or equal to 3\",\n                \"input\": \"4\",\n                \"ctx\": {\"le\": 3.0},\n            }\n        ]\n    }\n\n\ndef test_path_param_lt_int_2():\n    response = client.get(\"/path/param-lt-int/2\")\n    assert response.status_code == 200\n    assert response.json() == 2\n\n\ndef test_path_param_lt_int_42():\n    response = client.get(\"/path/param-lt-int/42\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"less_than\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be less than 3\",\n                \"input\": \"42\",\n                \"ctx\": {\"lt\": 3},\n            }\n        ]\n    }\n\n\ndef test_path_param_lt_int_2_7():\n    response = client.get(\"/path/param-lt-int/2.7\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"2.7\",\n            }\n        ]\n    }\n\n\ndef test_path_param_gt_int_42():\n    response = client.get(\"/path/param-gt-int/42\")\n    assert response.status_code == 200\n    assert response.json() == 42\n\n\ndef test_path_param_gt_int_2():\n    response = client.get(\"/path/param-gt-int/2\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"greater_than\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be greater than 3\",\n                \"input\": \"2\",\n                \"ctx\": {\"gt\": 3},\n            }\n        ]\n    }\n\n\ndef test_path_param_gt_int_2_7():\n    response = client.get(\"/path/param-gt-int/2.7\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"2.7\",\n            }\n        ]\n    }\n\n\ndef test_path_param_le_int_42():\n    response = client.get(\"/path/param-le-int/42\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"less_than_equal\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be less than or equal to 3\",\n                \"input\": \"42\",\n                \"ctx\": {\"le\": 3},\n            }\n        ]\n    }\n\n\ndef test_path_param_le_int_3():\n    response = client.get(\"/path/param-le-int/3\")\n    assert response.status_code == 200\n    assert response.json() == 3\n\n\ndef test_path_param_le_int_2():\n    response = client.get(\"/path/param-le-int/2\")\n    assert response.status_code == 200\n    assert response.json() == 2\n\n\ndef test_path_param_le_int_2_7():\n    response = client.get(\"/path/param-le-int/2.7\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"2.7\",\n            }\n        ]\n    }\n\n\ndef test_path_param_ge_int_42():\n    response = client.get(\"/path/param-ge-int/42\")\n    assert response.status_code == 200\n    assert response.json() == 42\n\n\ndef test_path_param_ge_int_3():\n    response = client.get(\"/path/param-ge-int/3\")\n    assert response.status_code == 200\n    assert response.json() == 3\n\n\ndef test_path_param_ge_int_2():\n    response = client.get(\"/path/param-ge-int/2\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"greater_than_equal\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be greater than or equal to 3\",\n                \"input\": \"2\",\n                \"ctx\": {\"ge\": 3},\n            }\n        ]\n    }\n\n\ndef test_path_param_ge_int_2_7():\n    response = client.get(\"/path/param-ge-int/2.7\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"2.7\",\n            }\n        ]\n    }\n\n\ndef test_path_param_lt_gt_int_2():\n    response = client.get(\"/path/param-lt-gt-int/2\")\n    assert response.status_code == 200\n    assert response.json() == 2\n\n\ndef test_path_param_lt_gt_int_4():\n    response = client.get(\"/path/param-lt-gt-int/4\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"less_than\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be less than 3\",\n                \"input\": \"4\",\n                \"ctx\": {\"lt\": 3},\n            }\n        ]\n    }\n\n\ndef test_path_param_lt_gt_int_0():\n    response = client.get(\"/path/param-lt-gt-int/0\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"greater_than\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be greater than 1\",\n                \"input\": \"0\",\n                \"ctx\": {\"gt\": 1},\n            }\n        ]\n    }\n\n\ndef test_path_param_lt_gt_int_2_7():\n    response = client.get(\"/path/param-lt-gt-int/2.7\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"2.7\",\n            }\n        ]\n    }\n\n\ndef test_path_param_le_ge_int_2():\n    response = client.get(\"/path/param-le-ge-int/2\")\n    assert response.status_code == 200\n    assert response.json() == 2\n\n\ndef test_path_param_le_ge_int_1():\n    response = client.get(\"/path/param-le-ge-int/1\")\n    assert response.status_code == 200\n    assert response.json() == 1\n\n\ndef test_path_param_le_ge_int_3():\n    response = client.get(\"/path/param-le-ge-int/3\")\n    assert response.status_code == 200\n    assert response.json() == 3\n\n\ndef test_path_param_le_ge_int_4():\n    response = client.get(\"/path/param-le-ge-int/4\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"less_than_equal\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be less than or equal to 3\",\n                \"input\": \"4\",\n                \"ctx\": {\"le\": 3},\n            }\n        ]\n    }\n\n\ndef test_path_param_le_ge_int_2_7():\n    response = client.get(\"/path/param-le-ge-int/2.7\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"2.7\",\n            }\n        ]\n    }\n"
  },
  {
    "path": "tests/test_put_no_body.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\n@app.put(\"/items/{item_id}\")\ndef save_item_no_body(item_id: str):\n    return {\"item_id\": item_id}\n\n\nclient = TestClient(app)\n\n\ndef test_put_no_body():\n    response = client.put(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": \"foo\"}\n\n\ndef test_put_no_body_with_body():\n    response = client.put(\"/items/foo\", json={\"name\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": \"foo\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Save Item No Body\",\n                        \"operationId\": \"save_item_no_body_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_pydantic_v1_error.py",
    "content": "import sys\nimport warnings\n\nimport pytest\n\nfrom tests.utils import skip_module_if_py_gte_314\n\nif sys.version_info >= (3, 14):\n    skip_module_if_py_gte_314()\n\nfrom fastapi import FastAPI\nfrom fastapi.exceptions import PydanticV1NotSupportedError\n\nwith warnings.catch_warnings():\n    warnings.simplefilter(\"ignore\", UserWarning)\n    from pydantic.v1 import BaseModel\n\n\ndef test_raises_pydantic_v1_model_in_endpoint_param() -> None:\n    class ParamModelV1(BaseModel):\n        name: str\n\n    app = FastAPI()\n\n    with pytest.raises(PydanticV1NotSupportedError):\n\n        @app.post(\"/param\")\n        def endpoint(data: ParamModelV1):  # pragma: no cover\n            return data\n\n\ndef test_raises_pydantic_v1_model_in_return_type() -> None:\n    class ReturnModelV1(BaseModel):\n        name: str\n\n    app = FastAPI()\n\n    with pytest.raises(PydanticV1NotSupportedError):\n\n        @app.get(\"/return\")\n        def endpoint() -> ReturnModelV1:  # pragma: no cover\n            return ReturnModelV1(name=\"test\")\n\n\ndef test_raises_pydantic_v1_model_in_response_model() -> None:\n    class ResponseModelV1(BaseModel):\n        name: str\n\n    app = FastAPI()\n\n    with pytest.raises(PydanticV1NotSupportedError):\n\n        @app.get(\"/response-model\", response_model=ResponseModelV1)\n        def endpoint():  # pragma: no cover\n            return {\"name\": \"test\"}\n\n\ndef test_raises_pydantic_v1_model_in_additional_responses_model() -> None:\n    class ErrorModelV1(BaseModel):\n        detail: str\n\n    app = FastAPI()\n\n    with pytest.raises(PydanticV1NotSupportedError):\n\n        @app.get(\n            \"/responses\", response_model=None, responses={400: {\"model\": ErrorModelV1}}\n        )\n        def endpoint():  # pragma: no cover\n            return {\"ok\": True}\n\n\ndef test_raises_pydantic_v1_model_in_union() -> None:\n    class ModelV1A(BaseModel):\n        name: str\n\n    app = FastAPI()\n\n    with pytest.raises(PydanticV1NotSupportedError):\n\n        @app.post(\"/union\")\n        def endpoint(data: dict | ModelV1A):  # pragma: no cover\n            return data\n\n\ndef test_raises_pydantic_v1_model_in_sequence() -> None:\n    class ModelV1A(BaseModel):\n        name: str\n\n    app = FastAPI()\n\n    with pytest.raises(PydanticV1NotSupportedError):\n\n        @app.post(\"/sequence\")\n        def endpoint(data: list[ModelV1A]):  # pragma: no cover\n            return data\n"
  },
  {
    "path": "tests/test_pydanticv2_dataclasses_uuid_stringified_annotations.py",
    "content": "from __future__ import annotations\n\nimport uuid\nfrom dataclasses import dataclass, field\n\nfrom dirty_equals import IsUUID\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@dataclass\nclass Item:\n    id: uuid.UUID\n    name: str\n    price: float\n    tags: list[str] = field(default_factory=list)\n    description: str | None = None\n    tax: float | None = None\n\n\napp = FastAPI()\n\n\n@app.get(\"/item\", response_model=Item)\nasync def read_item():\n    return {\n        \"id\": uuid.uuid4(),\n        \"name\": \"Island In The Moon\",\n        \"price\": 12.99,\n        \"description\": \"A place to be playin' and havin' fun\",\n        \"tags\": [\"breater\"],\n    }\n\n\nclient = TestClient(app)\n\n\ndef test_annotations():\n    response = client.get(\"/item\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"id\": IsUUID(),\n            \"name\": \"Island In The Moon\",\n            \"price\": 12.99,\n            \"tags\": [\"breater\"],\n            \"description\": \"A place to be playin' and havin' fun\",\n            \"tax\": None,\n        }\n    )\n"
  },
  {
    "path": "tests/test_query.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom .main import app\n\nclient = TestClient(app)\n\n\ndef test_query():\n    response = client.get(\"/query\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_query_query_baz():\n    response = client.get(\"/query?query=baz\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar baz\"\n\n\ndef test_query_not_declared_baz():\n    response = client.get(\"/query?not_declared=baz\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_query_optional():\n    response = client.get(\"/query/optional\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar\"\n\n\ndef test_query_optional_query_baz():\n    response = client.get(\"/query/optional?query=baz\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar baz\"\n\n\ndef test_query_optional_not_declared_baz():\n    response = client.get(\"/query/optional?not_declared=baz\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar\"\n\n\ndef test_query_int():\n    response = client.get(\"/query/int\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_query_int_query_42():\n    response = client.get(\"/query/int?query=42\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar 42\"\n\n\ndef test_query_int_query_42_5():\n    response = client.get(\"/query/int?query=42.5\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"42.5\",\n            }\n        ]\n    }\n\n\ndef test_query_int_query_baz():\n    response = client.get(\"/query/int?query=baz\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"baz\",\n            }\n        ]\n    }\n\n\ndef test_query_int_not_declared_baz():\n    response = client.get(\"/query/int?not_declared=baz\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_query_int_optional():\n    response = client.get(\"/query/int/optional\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar\"\n\n\ndef test_query_int_optional_query_50():\n    response = client.get(\"/query/int/optional?query=50\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar 50\"\n\n\ndef test_query_int_optional_query_foo():\n    response = client.get(\"/query/int/optional?query=foo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"foo\",\n            }\n        ]\n    }\n\n\ndef test_query_int_default():\n    response = client.get(\"/query/int/default\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar 10\"\n\n\ndef test_query_int_default_query_50():\n    response = client.get(\"/query/int/default?query=50\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar 50\"\n\n\ndef test_query_int_default_query_foo():\n    response = client.get(\"/query/int/default?query=foo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"foo\",\n            }\n        ]\n    }\n\n\ndef test_query_param():\n    response = client.get(\"/query/param\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar\"\n\n\ndef test_query_param_query_50():\n    response = client.get(\"/query/param?query=50\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar 50\"\n\n\ndef test_query_param_required():\n    response = client.get(\"/query/param-required\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_query_param_required_query_50():\n    response = client.get(\"/query/param-required?query=50\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar 50\"\n\n\ndef test_query_param_required_int():\n    response = client.get(\"/query/param-required/int\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_query_param_required_int_query_50():\n    response = client.get(\"/query/param-required/int?query=50\")\n    assert response.status_code == 200\n    assert response.json() == \"foo bar 50\"\n\n\ndef test_query_param_required_int_query_foo():\n    response = client.get(\"/query/param-required/int?query=foo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"query\", \"query\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"foo\",\n            }\n        ]\n    }\n\n\ndef test_query_frozenset_query_1_query_1_query_2():\n    response = client.get(\"/query/frozenset/?query=1&query=1&query=2\")\n    assert response.status_code == 200\n    assert response.json() == \"1,2\"\n\n\ndef test_query_list():\n    response = client.get(\"/query/list/?device_ids=1&device_ids=2\")\n    assert response.status_code == 200\n    assert response.json() == [1, 2]\n\n\ndef test_query_list_empty():\n    response = client.get(\"/query/list/\")\n    assert response.status_code == 422\n\n\ndef test_query_list_default():\n    response = client.get(\"/query/list-default/?device_ids=1&device_ids=2\")\n    assert response.status_code == 200\n    assert response.json() == [1, 2]\n\n\ndef test_query_list_default_empty():\n    response = client.get(\"/query/list-default/\")\n    assert response.status_code == 200\n    assert response.json() == []\n"
  },
  {
    "path": "tests/test_query_cookie_header_model_extra_params.py",
    "content": "from fastapi import Cookie, FastAPI, Header, Query\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Model(BaseModel):\n    param: str\n\n    model_config = {\"extra\": \"allow\"}\n\n\n@app.get(\"/query\")\nasync def query_model_with_extra(data: Model = Query()):\n    return data\n\n\n@app.get(\"/header\")\nasync def header_model_with_extra(data: Model = Header()):\n    return data\n\n\n@app.get(\"/cookie\")\nasync def cookies_model_with_extra(data: Model = Cookie()):\n    return data\n\n\ndef test_query_pass_extra_list():\n    client = TestClient(app)\n    resp = client.get(\n        \"/query\",\n        params={\n            \"param\": \"123\",\n            \"param2\": [\"456\", \"789\"],  # Pass a list of values as extra parameter\n        },\n    )\n    assert resp.status_code == 200\n    assert resp.json() == {\n        \"param\": \"123\",\n        \"param2\": [\"456\", \"789\"],\n    }\n\n\ndef test_query_pass_extra_single():\n    client = TestClient(app)\n    resp = client.get(\n        \"/query\",\n        params={\n            \"param\": \"123\",\n            \"param2\": \"456\",\n        },\n    )\n    assert resp.status_code == 200\n    assert resp.json() == {\n        \"param\": \"123\",\n        \"param2\": \"456\",\n    }\n\n\ndef test_header_pass_extra_list():\n    client = TestClient(app)\n\n    resp = client.get(\n        \"/header\",\n        headers=[\n            (\"param\", \"123\"),\n            (\"param2\", \"456\"),  # Pass a list of values as extra parameter\n            (\"param2\", \"789\"),\n        ],\n    )\n    assert resp.status_code == 200\n    resp_json = resp.json()\n    assert \"param2\" in resp_json\n    assert resp_json[\"param2\"] == [\"456\", \"789\"]\n\n\ndef test_header_pass_extra_single():\n    client = TestClient(app)\n\n    resp = client.get(\n        \"/header\",\n        headers=[\n            (\"param\", \"123\"),\n            (\"param2\", \"456\"),\n        ],\n    )\n    assert resp.status_code == 200\n    resp_json = resp.json()\n    assert \"param2\" in resp_json\n    assert resp_json[\"param2\"] == \"456\"\n\n\ndef test_cookie_pass_extra_list():\n    client = TestClient(app)\n    client.cookies = [\n        (\"param\", \"123\"),\n        (\"param2\", \"456\"),  # Pass a list of values as extra parameter\n        (\"param2\", \"789\"),\n    ]\n    resp = client.get(\"/cookie\")\n    assert resp.status_code == 200\n    resp_json = resp.json()\n    assert \"param2\" in resp_json\n    assert resp_json[\"param2\"] == \"789\"  # Cookies only keep the last value\n"
  },
  {
    "path": "tests/test_read_with_orm_mode.py",
    "content": "from typing import Any\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, ConfigDict\n\n\ndef test_read_with_orm_mode() -> None:\n    class PersonBase(BaseModel):\n        name: str\n        lastname: str\n\n    class Person(PersonBase):\n        @property\n        def full_name(self) -> str:\n            return f\"{self.name} {self.lastname}\"\n\n        model_config = ConfigDict(from_attributes=True)\n\n    class PersonCreate(PersonBase):\n        pass\n\n    class PersonRead(PersonBase):\n        full_name: str\n\n        model_config = {\"from_attributes\": True}\n\n    app = FastAPI()\n\n    @app.post(\"/people/\", response_model=PersonRead)\n    def create_person(person: PersonCreate) -> Any:\n        db_person = Person.model_validate(person)\n        return db_person\n\n    client = TestClient(app)\n\n    person_data = {\"name\": \"Dive\", \"lastname\": \"Wilson\"}\n    response = client.post(\"/people/\", json=person_data)\n    data = response.json()\n    assert response.status_code == 200, response.text\n    assert data[\"name\"] == person_data[\"name\"]\n    assert data[\"lastname\"] == person_data[\"lastname\"]\n    assert data[\"full_name\"] == person_data[\"name\"] + \" \" + person_data[\"lastname\"]\n"
  },
  {
    "path": "tests/test_regex_deprecated_body.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, Form\nfrom fastapi.exceptions import FastAPIDeprecationWarning\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom .utils import needs_py310\n\n\ndef get_client():\n    app = FastAPI()\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.post(\"/items/\")\n        async def read_items(\n            q: Annotated[str | None, Form(regex=\"^fixedquery$\")] = None,\n        ):\n            if q:\n                return f\"Hello {q}\"\n            else:\n                return \"Hello World\"\n\n    client = TestClient(app)\n    return client\n\n\n@needs_py310\ndef test_no_query():\n    client = get_client()\n    response = client.post(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == \"Hello World\"\n\n\n@needs_py310\ndef test_q_fixedquery():\n    client = get_client()\n    response = client.post(\"/items/\", data={\"q\": \"fixedquery\"})\n    assert response.status_code == 200\n    assert response.json() == \"Hello fixedquery\"\n\n\n@needs_py310\ndef test_query_nonregexquery():\n    client = get_client()\n    response = client.post(\"/items/\", data={\"q\": \"nonregexquery\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_pattern_mismatch\",\n                \"loc\": [\"body\", \"q\"],\n                \"msg\": \"String should match pattern '^fixedquery$'\",\n                \"input\": \"nonregexquery\",\n                \"ctx\": {\"pattern\": \"^fixedquery$\"},\n            }\n        ]\n    }\n\n\n@needs_py310\ndef test_openapi_schema():\n    client = get_client()\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_read_items_items__post\"\n                                    }\n                                }\n                            }\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_read_items_items__post\": {\n                        \"properties\": {\n                            \"q\": {\n                                \"anyOf\": [\n                                    {\"type\": \"string\", \"pattern\": \"^fixedquery$\"},\n                                    {\"type\": \"null\"},\n                                ],\n                                \"title\": \"Q\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"Body_read_items_items__post\",\n                    },\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_regex_deprecated_params.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, Query\nfrom fastapi.exceptions import FastAPIDeprecationWarning\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom .utils import needs_py310\n\n\ndef get_client():\n    app = FastAPI()\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.get(\"/items/\")\n        async def read_items(\n            q: Annotated[str | None, Query(regex=\"^fixedquery$\")] = None,\n        ):\n            if q:\n                return f\"Hello {q}\"\n            else:\n                return \"Hello World\"\n\n    client = TestClient(app)\n    return client\n\n\n@needs_py310\ndef test_query_params_str_validations_no_query():\n    client = get_client()\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == \"Hello World\"\n\n\n@needs_py310\ndef test_query_params_str_validations_q_fixedquery():\n    client = get_client()\n    response = client.get(\"/items/\", params={\"q\": \"fixedquery\"})\n    assert response.status_code == 200\n    assert response.json() == \"Hello fixedquery\"\n\n\n@needs_py310\ndef test_query_params_str_validations_item_query_nonregexquery():\n    client = get_client()\n    response = client.get(\"/items/\", params={\"q\": \"nonregexquery\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_pattern_mismatch\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"String should match pattern '^fixedquery$'\",\n                \"input\": \"nonregexquery\",\n                \"ctx\": {\"pattern\": \"^fixedquery$\"},\n            }\n        ]\n    }\n\n\n@needs_py310\ndef test_openapi_schema():\n    client = get_client()\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\"type\": \"string\", \"pattern\": \"^fixedquery$\"},\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Q\",\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_repeated_cookie_headers.py",
    "content": "from fastapi import Depends, FastAPI, Response\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\ndef set_cookie(*, response: Response):\n    response.set_cookie(\"cookie-name\", \"cookie-value\")\n    return {}\n\n\ndef set_indirect_cookie(*, dep: str = Depends(set_cookie)):\n    return dep\n\n\n@app.get(\"/directCookie\")\ndef get_direct_cookie(dep: str = Depends(set_cookie)):\n    return {\"dep\": dep}\n\n\n@app.get(\"/indirectCookie\")\ndef get_indirect_cookie(dep: str = Depends(set_indirect_cookie)):\n    return {\"dep\": dep}\n\n\nclient = TestClient(app)\n\n\ndef test_cookie_is_set_once():\n    direct_response = client.get(\"/directCookie\")\n    indirect_response = client.get(\"/indirectCookie\")\n    assert (\n        direct_response.headers[\"set-cookie\"] == indirect_response.headers[\"set-cookie\"]\n    )\n"
  },
  {
    "path": "tests/test_repeated_dependency_schema.py",
    "content": "from fastapi import Depends, FastAPI, Header, status\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\ndef get_header(*, someheader: str = Header()):\n    return someheader\n\n\ndef get_something_else(*, someheader: str = Depends(get_header)):\n    return f\"{someheader}123\"\n\n\n@app.get(\"/\")\ndef get_deps(dep1: str = Depends(get_header), dep2: str = Depends(get_something_else)):\n    return {\"dep1\": dep1, \"dep2\": dep2}\n\n\nclient = TestClient(app)\n\n\ndef test_response():\n    response = client.get(\"/\", headers={\"someheader\": \"hello\"})\n    assert response.status_code == status.HTTP_200_OK\n    assert response.json() == {\"dep1\": \"hello\", \"dep2\": \"hello123\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == status.HTTP_200_OK\n    actual_schema = response.json()\n    assert (\n        len(actual_schema[\"paths\"][\"/\"][\"get\"][\"parameters\"]) == 1\n    )  # primary goal of this test\n    assert actual_schema == snapshot(\n        {\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            }\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                }\n            },\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"operationId\": \"get_deps__get\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"header\",\n                                \"name\": \"someheader\",\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Someheader\", \"type\": \"string\"},\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Get Deps\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_repeated_parameter_alias.py",
    "content": "from fastapi import FastAPI, Path, Query, status\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\n@app.get(\"/{repeated_alias}\")\ndef get_parameters_with_repeated_aliases(\n    path: str = Path(..., alias=\"repeated_alias\"),\n    query: str = Query(..., alias=\"repeated_alias\"),\n):\n    return {\"path\": path, \"query\": query}\n\n\nclient = TestClient(app)\n\n\ndef test_get_parameters():\n    response = client.get(\"/test_path\", params={\"repeated_alias\": \"test_query\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"path\": \"test_path\", \"query\": \"test_query\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == status.HTTP_200_OK\n    assert response.json() == snapshot(\n        {\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            }\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                }\n            },\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/{repeated_alias}\": {\n                    \"get\": {\n                        \"operationId\": \"get_parameters_with_repeated_aliases__repeated_alias__get\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"repeated_alias\",\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Repeated Alias\", \"type\": \"string\"},\n                            },\n                            {\n                                \"in\": \"query\",\n                                \"name\": \"repeated_alias\",\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Repeated Alias\", \"type\": \"string\"},\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Get Parameters With Repeated Aliases\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_request_body_parameters_media_type.py",
    "content": "from fastapi import Body, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\nmedia_type = \"application/vnd.api+json\"\n\n\n# NOTE: These are not valid JSON:API resources\n# but they are fine for testing requestBody with custom media_type\nclass Product(BaseModel):\n    name: str\n    price: float\n\n\nclass Shop(BaseModel):\n    name: str\n\n\n@app.post(\"/products\")\nasync def create_product(data: Product = Body(media_type=media_type, embed=True)):\n    pass  # pragma: no cover\n\n\n@app.post(\"/shops\")\nasync def create_shop(\n    data: Shop = Body(media_type=media_type),\n    included: list[Product] = Body(default=[], media_type=media_type),\n):\n    pass  # pragma: no cover\n\n\nclient = TestClient(app)\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/products\": {\n                    \"post\": {\n                        \"summary\": \"Create Product\",\n                        \"operationId\": \"create_product_products_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/vnd.api+json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_product_products_post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/shops\": {\n                    \"post\": {\n                        \"summary\": \"Create Shop\",\n                        \"operationId\": \"create_shop_shops_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/vnd.api+json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_shop_shops_post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_create_product_products_post\": {\n                        \"title\": \"Body_create_product_products_post\",\n                        \"required\": [\"data\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"data\": {\"$ref\": \"#/components/schemas/Product\"}\n                        },\n                    },\n                    \"Body_create_shop_shops_post\": {\n                        \"title\": \"Body_create_shop_shops_post\",\n                        \"required\": [\"data\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"data\": {\"$ref\": \"#/components/schemas/Shop\"},\n                            \"included\": {\n                                \"title\": \"Included\",\n                                \"type\": \"array\",\n                                \"items\": {\"$ref\": \"#/components/schemas/Product\"},\n                                \"default\": [],\n                            },\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Product\": {\n                        \"title\": \"Product\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"Shop\": {\n                        \"title\": \"Shop\",\n                        \"required\": [\"name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"name\": {\"title\": \"Name\", \"type\": \"string\"}},\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_request_param_model_by_alias.py",
    "content": "from dirty_equals import IsPartialDict\nfrom fastapi import Cookie, FastAPI, Header, Query\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n\nclass Model(BaseModel):\n    param: str = Field(alias=\"param_alias\")\n\n\n@app.get(\"/query\")\nasync def query_model(data: Model = Query()):\n    return {\"param\": data.param}\n\n\n@app.get(\"/header\")\nasync def header_model(data: Model = Header()):\n    return {\"param\": data.param}\n\n\n@app.get(\"/cookie\")\nasync def cookie_model(data: Model = Cookie()):\n    return {\"param\": data.param}\n\n\ndef test_query_model_with_alias():\n    client = TestClient(app)\n    response = client.get(\"/query\", params={\"param_alias\": \"value\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"param\": \"value\"}\n\n\ndef test_header_model_with_alias():\n    client = TestClient(app)\n    response = client.get(\"/header\", headers={\"param_alias\": \"value\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"param\": \"value\"}\n\n\ndef test_cookie_model_with_alias():\n    client = TestClient(app)\n    client.cookies.set(\"param_alias\", \"value\")\n    response = client.get(\"/cookie\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"param\": \"value\"}\n\n\ndef test_query_model_with_alias_by_name():\n    client = TestClient(app)\n    response = client.get(\"/query\", params={\"param\": \"value\"})\n    assert response.status_code == 422, response.text\n    details = response.json()\n    assert details[\"detail\"][0][\"input\"] == {\"param\": \"value\"}\n\n\ndef test_header_model_with_alias_by_name():\n    client = TestClient(app)\n    response = client.get(\"/header\", headers={\"param\": \"value\"})\n    assert response.status_code == 422, response.text\n    details = response.json()\n    assert details[\"detail\"][0][\"input\"] == IsPartialDict({\"param\": \"value\"})\n\n\ndef test_cookie_model_with_alias_by_name():\n    client = TestClient(app)\n    client.cookies.set(\"param\", \"value\")\n    response = client.get(\"/cookie\")\n    assert response.status_code == 422, response.text\n    details = response.json()\n    assert details[\"detail\"][0][\"input\"] == {\"param\": \"value\"}\n"
  },
  {
    "path": "tests/test_request_params/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_request_params/test_body/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_request_params/test_body/test_list.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom dirty_equals import IsOneOf, IsPartialDict\nfrom fastapi import Body, FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/required-list-str\", operation_id=\"required_list_str\")\nasync def read_required_list_str(p: Annotated[list[str], Body(embed=True)]):\n    return {\"p\": p}\n\n\nclass BodyModelRequiredListStr(BaseModel):\n    p: list[str]\n\n\n@app.post(\"/model-required-list-str\", operation_id=\"model_required_list_str\")\ndef read_model_required_list_str(p: BodyModelRequiredListStr):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\n                \"items\": {\"type\": \"string\"},\n                \"title\": \"P\",\n                \"type\": \"array\",\n            },\n        },\n        \"required\": [\"p\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\"json\", [None, {}])\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str_missing(path: str, json: dict | None):\n    client = TestClient(app)\n    response = client.post(path, json=json)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": IsOneOf([\"body\", \"p\"], [\"body\"]),\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/required-list-alias\", operation_id=\"required_list_alias\")\nasync def read_required_list_alias(\n    p: Annotated[list[str], Body(embed=True, alias=\"p_alias\")],\n):\n    return {\"p\": p}\n\n\nclass BodyModelRequiredListAlias(BaseModel):\n    p: list[str] = Field(alias=\"p_alias\")\n\n\n@app.post(\"/model-required-list-alias\", operation_id=\"model_required_list_alias\")\nasync def read_model_required_list_alias(p: BodyModelRequiredListAlias):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias\",\n        \"/model-required-list-alias\",\n    ],\n)\ndef test_required_list_str_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\n                \"items\": {\"type\": \"string\"},\n                \"title\": \"P Alias\",\n                \"type\": \"array\",\n            },\n        },\n        \"required\": [\"p_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\"json\", [None, {}])\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-alias\", \"/model-required-list-alias\"],\n)\ndef test_required_list_alias_missing(path: str, json: dict | None):\n    client = TestClient(app)\n    response = client.post(path, json=json)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": IsOneOf([\"body\", \"p_alias\"], [\"body\"]),\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-alias\", \"/model-required-list-alias\"],\n)\ndef test_required_list_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": [\"hello\", \"world\"]}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-alias\", \"/model-required-list-alias\"],\n)\ndef test_required_list_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\n    \"/required-list-validation-alias\", operation_id=\"required_list_validation_alias\"\n)\ndef read_required_list_validation_alias(\n    p: Annotated[list[str], Body(embed=True, validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass BodyModelRequiredListValidationAlias(BaseModel):\n    p: list[str] = Field(validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-required-list-validation-alias\",\n    operation_id=\"model_required_list_validation_alias\",\n)\nasync def read_model_required_list_validation_alias(\n    p: BodyModelRequiredListValidationAlias,\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-validation-alias\", \"/model-required-list-validation-alias\"],\n)\ndef test_required_list_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"items\": {\"type\": \"string\"},\n                \"title\": \"P Val Alias\",\n                \"type\": \"array\",\n            },\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\"json\", [None, {}])\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-validation-alias\",\n        \"/model-required-list-validation-alias\",\n    ],\n)\ndef test_required_list_validation_alias_missing(path: str, json: dict | None):\n    client = TestClient(app)\n    response = client.post(path, json=json)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": IsOneOf([\"body\"], [\"body\", \"p_val_alias\"]),\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-validation-alias\",\n        \"/model-required-list-validation-alias\",\n    ],\n)\ndef test_required_list_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, IsPartialDict({\"p\": [\"hello\", \"world\"]})),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-validation-alias\",\n        \"/model-required-list-validation-alias\",\n    ],\n)\ndef test_required_list_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_val_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/required-list-alias-and-validation-alias\",\n    operation_id=\"required_list_alias_and_validation_alias\",\n)\ndef read_required_list_alias_and_validation_alias(\n    p: Annotated[\n        list[str], Body(embed=True, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ],\n):\n    return {\"p\": p}\n\n\nclass BodyModelRequiredListAliasAndValidationAlias(BaseModel):\n    p: list[str] = Field(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-required-list-alias-and-validation-alias\",\n    operation_id=\"model_required_list_alias_and_validation_alias\",\n)\ndef read_model_required_list_alias_and_validation_alias(\n    p: BodyModelRequiredListAliasAndValidationAlias,\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"items\": {\"type\": \"string\"},\n                \"title\": \"P Val Alias\",\n                \"type\": \"array\",\n            },\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\"json\", [None, {}])\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_missing(path: str, json):\n    client = TestClient(app)\n    response = client.post(path, json=json)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": IsOneOf([\"body\"], [\"body\", \"p_val_alias\"]),\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": [\"hello\", \"world\"]}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p_alias\": [\"hello\", \"world\"]}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_val_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n"
  },
  {
    "path": "tests/test_request_params/test_body/test_optional_list.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import Body, FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/optional-list-str\", operation_id=\"optional_list_str\")\nasync def read_optional_list_str(\n    p: Annotated[list[str] | None, Body(embed=True)] = None,\n):\n    return {\"p\": p}\n\n\nclass BodyModelOptionalListStr(BaseModel):\n    p: list[str] | None = None\n\n\n@app.post(\"/model-optional-list-str\", operation_id=\"model_optional_list_str\")\nasync def read_model_optional_list_str(p: BodyModelOptionalListStr):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\n                \"anyOf\": [\n                    {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\ndef test_optional_list_str_missing():\n    client = TestClient(app)\n    response = client.post(\"/optional-list-str\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\ndef test_model_optional_list_str_missing():\n    client = TestClient(app)\n    response = client.post(\"/model-optional-list-str\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\"body\"],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str_missing_empty_dict(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/optional-list-alias\", operation_id=\"optional_list_alias\")\nasync def read_optional_list_alias(\n    p: Annotated[list[str] | None, Body(embed=True, alias=\"p_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass BodyModelOptionalListAlias(BaseModel):\n    p: list[str] | None = Field(None, alias=\"p_alias\")\n\n\n@app.post(\"/model-optional-list-alias\", operation_id=\"model_optional_list_alias\")\nasync def read_model_optional_list_alias(p: BodyModelOptionalListAlias):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias\",\n        \"/model-optional-list-alias\",\n    ],\n)\ndef test_optional_list_str_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\n                \"anyOf\": [\n                    {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\ndef test_optional_list_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/optional-list-alias\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\ndef test_model_optional_list_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/model-optional-list-alias\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\"body\"],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_alias_missing_empty_dict(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\n    \"/optional-list-validation-alias\", operation_id=\"optional_list_validation_alias\"\n)\ndef read_optional_list_validation_alias(\n    p: Annotated[\n        list[str] | None, Body(embed=True, validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"p\": p}\n\n\nclass BodyModelOptionalListValidationAlias(BaseModel):\n    p: list[str] | None = Field(None, validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-optional-list-validation-alias\",\n    operation_id=\"model_optional_list_validation_alias\",\n)\ndef read_model_optional_list_validation_alias(\n    p: BodyModelOptionalListValidationAlias,\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [\n                    {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Val Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\ndef test_optional_list_validation_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/optional-list-validation-alias\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\ndef test_model_optional_list_validation_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/model-optional-list-validation-alias\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\"body\"],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_missing_empty_dict(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-validation-alias\",\n        \"/model-optional-list-validation-alias\",\n    ],\n)\ndef test_optional_list_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-validation-alias\",\n        \"/model-optional-list-validation-alias\",\n    ],\n)\ndef test_optional_list_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_val_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/optional-list-alias-and-validation-alias\",\n    operation_id=\"optional_list_alias_and_validation_alias\",\n)\ndef read_optional_list_alias_and_validation_alias(\n    p: Annotated[\n        list[str] | None,\n        Body(embed=True, alias=\"p_alias\", validation_alias=\"p_val_alias\"),\n    ] = None,\n):\n    return {\"p\": p}\n\n\nclass BodyModelOptionalListAliasAndValidationAlias(BaseModel):\n    p: list[str] | None = Field(None, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-optional-list-alias-and-validation-alias\",\n    operation_id=\"model_optional_list_alias_and_validation_alias\",\n)\ndef read_model_optional_list_alias_and_validation_alias(\n    p: BodyModelOptionalListAliasAndValidationAlias,\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [\n                    {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Val Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\ndef test_optional_list_alias_and_validation_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/optional-list-alias-and-validation-alias\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\ndef test_model_optional_list_alias_and_validation_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/model-optional-list-alias-and-validation-alias\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\"body\"],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_missing_empty_dict(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_val_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"p\": [\n            \"hello\",\n            \"world\",\n        ]\n    }\n"
  },
  {
    "path": "tests/test_request_params/test_body/test_optional_str.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import Body, FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/optional-str\", operation_id=\"optional_str\")\nasync def read_optional_str(p: Annotated[str | None, Body(embed=True)] = None):\n    return {\"p\": p}\n\n\nclass BodyModelOptionalStr(BaseModel):\n    p: str | None = None\n\n\n@app.post(\"/model-optional-str\", operation_id=\"model_optional_str\")\nasync def read_model_optional_str(p: BodyModelOptionalStr):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\n                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                \"title\": \"P\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\ndef test_optional_str_missing():\n    client = TestClient(app)\n    response = client.post(\"/optional-str\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\ndef test_model_optional_str_missing():\n    client = TestClient(app)\n    response = client.post(\"/model-optional-str\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\"body\"],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str_missing_empty_dict(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/optional-alias\", operation_id=\"optional_alias\")\nasync def read_optional_alias(\n    p: Annotated[str | None, Body(embed=True, alias=\"p_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass BodyModelOptionalAlias(BaseModel):\n    p: str | None = Field(None, alias=\"p_alias\")\n\n\n@app.post(\"/model-optional-alias\", operation_id=\"model_optional_alias\")\nasync def read_model_optional_alias(p: BodyModelOptionalAlias):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias\",\n        \"/model-optional-alias\",\n    ],\n)\ndef test_optional_str_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\n                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                \"title\": \"P Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\ndef test_optional_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/optional-alias\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\ndef test_model_optional_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/model-optional-alias\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\"body\"],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_model_optional_alias_missing_empty_dict(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\"/optional-validation-alias\", operation_id=\"optional_validation_alias\")\ndef read_optional_validation_alias(\n    p: Annotated[str | None, Body(embed=True, validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass BodyModelOptionalValidationAlias(BaseModel):\n    p: str | None = Field(None, validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-optional-validation-alias\", operation_id=\"model_optional_validation_alias\"\n)\ndef read_model_optional_validation_alias(\n    p: BodyModelOptionalValidationAlias,\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-validation-alias\", \"/model-optional-validation-alias\"],\n)\ndef test_optional_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                \"title\": \"P Val Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\ndef test_optional_validation_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/optional-validation-alias\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\ndef test_model_optional_validation_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/model-optional-validation-alias\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\"body\"],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-validation-alias\", \"/model-optional-validation-alias\"],\n)\ndef test_model_optional_validation_alias_missing_empty_dict(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-validation-alias\",\n        \"/model-optional-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-validation-alias\",\n        \"/model-optional-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/optional-alias-and-validation-alias\",\n    operation_id=\"optional_alias_and_validation_alias\",\n)\ndef read_optional_alias_and_validation_alias(\n    p: Annotated[\n        str | None, Body(embed=True, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"p\": p}\n\n\nclass BodyModelOptionalAliasAndValidationAlias(BaseModel):\n    p: str | None = Field(None, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-optional-alias-and-validation-alias\",\n    operation_id=\"model_optional_alias_and_validation_alias\",\n)\ndef read_model_optional_alias_and_validation_alias(\n    p: BodyModelOptionalAliasAndValidationAlias,\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                \"title\": \"P Val Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\ndef test_optional_alias_and_validation_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/optional-alias-and-validation-alias\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\ndef test_model_optional_alias_and_validation_alias_missing():\n    client = TestClient(app)\n    response = client.post(\"/model-optional-alias-and-validation-alias\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\"body\"],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_model_optional_alias_and_validation_alias_missing_empty_dict(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_request_params/test_body/test_required_str.py",
    "content": "from typing import Annotated, Any\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi import Body, FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/required-str\", operation_id=\"required_str\")\nasync def read_required_str(p: Annotated[str, Body(embed=True)]):\n    return {\"p\": p}\n\n\nclass BodyModelRequiredStr(BaseModel):\n    p: str\n\n\n@app.post(\"/model-required-str\", operation_id=\"model_required_str\")\nasync def read_model_required_str(p: BodyModelRequiredStr):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\"title\": \"P\", \"type\": \"string\"},\n        },\n        \"required\": [\"p\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\"json\", [None, {}])\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str_missing(path: str, json: dict[str, Any] | None):\n    client = TestClient(app)\n    response = client.post(path, json=json)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": IsOneOf([\"body\"], [\"body\", \"p\"]),\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/required-alias\", operation_id=\"required_alias\")\nasync def read_required_alias(\n    p: Annotated[str, Body(embed=True, alias=\"p_alias\")],\n):\n    return {\"p\": p}\n\n\nclass BodyModelRequiredAlias(BaseModel):\n    p: str = Field(alias=\"p_alias\")\n\n\n@app.post(\"/model-required-alias\", operation_id=\"model_required_alias\")\nasync def read_model_required_alias(p: BodyModelRequiredAlias):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias\",\n        \"/model-required-alias\",\n    ],\n)\ndef test_required_str_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\"title\": \"P Alias\", \"type\": \"string\"},\n        },\n        \"required\": [\"p_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\"json\", [None, {}])\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_alias_missing(path: str, json: dict[str, Any] | None):\n    client = TestClient(app)\n    response = client.post(path, json=json)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": IsOneOf([\"body\", \"p_alias\"], [\"body\"]),\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": \"hello\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": \"hello\"}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_alias\": \"hello\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\"/required-validation-alias\", operation_id=\"required_validation_alias\")\ndef read_required_validation_alias(\n    p: Annotated[str, Body(embed=True, validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass BodyModelRequiredValidationAlias(BaseModel):\n    p: str = Field(validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-required-validation-alias\", operation_id=\"model_required_validation_alias\"\n)\ndef read_model_required_validation_alias(\n    p: BodyModelRequiredValidationAlias,\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-validation-alias\", \"/model-required-validation-alias\"],\n)\ndef test_required_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\"title\": \"P Val Alias\", \"type\": \"string\"},\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\"json\", [None, {}])\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_missing(path: str, json: dict[str, Any] | None):\n    client = TestClient(app)\n    response = client.post(path, json=json)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": IsOneOf([\"body\", \"p_val_alias\"], [\"body\"]),\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": \"hello\"})\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": \"hello\"}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/required-alias-and-validation-alias\",\n    operation_id=\"required_alias_and_validation_alias\",\n)\ndef read_required_alias_and_validation_alias(\n    p: Annotated[\n        str, Body(embed=True, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ],\n):\n    return {\"p\": p}\n\n\nclass BodyModelRequiredAliasAndValidationAlias(BaseModel):\n    p: str = Field(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-required-alias-and-validation-alias\",\n    operation_id=\"model_required_alias_and_validation_alias\",\n)\ndef read_model_required_alias_and_validation_alias(\n    p: BodyModelRequiredAliasAndValidationAlias,\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\"title\": \"P Val Alias\", \"type\": \"string\"},\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\"json\", [None, {}])\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_missing(\n    path: str, json: dict[str, Any] | None\n):\n    client = TestClient(app)\n    response = client.post(path, json=json)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": IsOneOf([\"body\"], [\"body\", \"p_val_alias\"]),\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p\": \"hello\"})\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": \"hello\"}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_alias\": \"hello\"})\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p_alias\": \"hello\"}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, json={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_request_params/test_body/utils.py",
    "content": "from typing import Any\n\n\ndef get_body_model_name(openapi: dict[str, Any], path: str) -> str:\n    body = openapi[\"paths\"][path][\"post\"][\"requestBody\"]\n    body_schema = body[\"content\"][\"application/json\"][\"schema\"]\n    return body_schema.get(\"$ref\", \"\").split(\"/\")[-1]\n"
  },
  {
    "path": "tests/test_request_params/test_cookie/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_request_params/test_cookie/test_list.py",
    "content": "# Currently, there is no way to pass multiple cookies with the same name.\n# The only way to pass multiple values for cookie params is to serialize them using\n# a comma as a delimiter, but this is not currently supported by Starlette.\n"
  },
  {
    "path": "tests/test_request_params/test_cookie/test_optional_list.py",
    "content": "# Currently, there is no way to pass multiple cookies with the same name.\n# The only way to pass multiple values for cookie params is to serialize them using\n# a comma as a delimiter, but this is not currently supported by Starlette.\n"
  },
  {
    "path": "tests/test_request_params/test_cookie/test_optional_str.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import Cookie, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.get(\"/optional-str\")\nasync def read_optional_str(p: Annotated[str | None, Cookie()] = None):\n    return {\"p\": p}\n\n\nclass CookieModelOptionalStr(BaseModel):\n    p: str | None = None\n\n\n@app.get(\"/model-optional-str\")\nasync def read_model_optional_str(p: Annotated[CookieModelOptionalStr, Cookie()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P\",\n                },\n                \"name\": \"p\",\n                \"in\": \"cookie\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.get(\"/optional-alias\")\nasync def read_optional_alias(\n    p: Annotated[str | None, Cookie(alias=\"p_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass CookieModelOptionalAlias(BaseModel):\n    p: str | None = Field(None, alias=\"p_alias\")\n\n\n@app.get(\"/model-optional-alias\")\nasync def read_model_optional_alias(p: Annotated[CookieModelOptionalAlias, Cookie()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_str_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P Alias\",\n                },\n                \"name\": \"p_alias\",\n                \"in\": \"cookie\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_by_name(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias\",\n        \"/model-optional-alias\",\n    ],\n)\ndef test_optional_alias_by_alias(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p_alias\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.get(\"/optional-validation-alias\")\ndef read_optional_validation_alias(\n    p: Annotated[str | None, Cookie(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass CookieModelOptionalValidationAlias(BaseModel):\n    p: str | None = Field(None, validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-optional-validation-alias\")\ndef read_model_optional_validation_alias(\n    p: Annotated[CookieModelOptionalValidationAlias, Cookie()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-validation-alias\", \"/model-optional-validation-alias\"],\n)\ndef test_optional_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P Val Alias\",\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"cookie\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-validation-alias\", \"/model-optional-validation-alias\"],\n)\ndef test_optional_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-validation-alias\",\n        \"/model-optional-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-validation-alias\",\n        \"/model-optional-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p_val_alias\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.get(\"/optional-alias-and-validation-alias\")\ndef read_optional_alias_and_validation_alias(\n    p: Annotated[\n        str | None, Cookie(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"p\": p}\n\n\nclass CookieModelOptionalAliasAndValidationAlias(BaseModel):\n    p: str | None = Field(None, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-optional-alias-and-validation-alias\")\ndef read_model_optional_alias_and_validation_alias(\n    p: Annotated[CookieModelOptionalAliasAndValidationAlias, Cookie()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P Val Alias\",\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"cookie\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p_alias\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p_val_alias\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_request_params/test_cookie/test_required_str.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi import Cookie, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.get(\"/required-str\")\nasync def read_required_str(p: Annotated[str, Cookie()]):\n    return {\"p\": p}\n\n\nclass CookieModelRequiredStr(BaseModel):\n    p: str\n\n\n@app.get(\"/model-required-str\")\nasync def read_model_required_str(p: Annotated[CookieModelRequiredStr, Cookie()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P\", \"type\": \"string\"},\n                \"name\": \"p\",\n                \"in\": \"cookie\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"cookie\", \"p\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.get(\"/required-alias\")\nasync def read_required_alias(p: Annotated[str, Cookie(alias=\"p_alias\")]):\n    return {\"p\": p}\n\n\nclass CookieModelRequiredAlias(BaseModel):\n    p: str = Field(alias=\"p_alias\")\n\n\n@app.get(\"/model-required-alias\")\nasync def read_model_required_alias(p: Annotated[CookieModelRequiredAlias, Cookie()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_str_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P Alias\", \"type\": \"string\"},\n                \"name\": \"p_alias\",\n                \"in\": \"cookie\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"cookie\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias\",\n        \"/model-required-alias\",\n    ],\n)\ndef test_required_alias_by_name(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"cookie\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    {\"p\": \"hello\"},\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias\",\n        \"/model-required-alias\",\n    ],\n)\ndef test_required_alias_by_alias(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p_alias\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.get(\"/required-validation-alias\")\ndef read_required_validation_alias(\n    p: Annotated[str, Cookie(validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass CookieModelRequiredValidationAlias(BaseModel):\n    p: str = Field(validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-required-validation-alias\")\ndef read_model_required_validation_alias(\n    p: Annotated[CookieModelRequiredValidationAlias, Cookie()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-validation-alias\", \"/model-required-validation-alias\"],\n)\ndef test_required_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P Val Alias\", \"type\": \"string\"},\n                \"name\": \"p_val_alias\",\n                \"in\": \"cookie\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"cookie\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"cookie\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": \"hello\"}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p_val_alias\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.get(\"/required-alias-and-validation-alias\")\ndef read_required_alias_and_validation_alias(\n    p: Annotated[str, Cookie(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass CookieModelRequiredAliasAndValidationAlias(BaseModel):\n    p: str = Field(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-required-alias-and-validation-alias\")\ndef read_model_required_alias_and_validation_alias(\n    p: Annotated[CookieModelRequiredAliasAndValidationAlias, Cookie()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P Val Alias\", \"type\": \"string\"},\n                \"name\": \"p_val_alias\",\n                \"in\": \"cookie\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"cookie\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"cookie\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    {\"p\": \"hello\"},\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p_alias\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"cookie\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    {\"p_alias\": \"hello\"},\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    client.cookies.set(\"p_val_alias\", \"hello\")\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_request_params/test_file/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_request_params/test_file/test_list.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, File, UploadFile\nfrom fastapi.testclient import TestClient\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/list-bytes\", operation_id=\"list_bytes\")\nasync def read_list_bytes(p: Annotated[list[bytes], File()]):\n    return {\"file_size\": [len(file) for file in p]}\n\n\n@app.post(\"/list-uploadfile\", operation_id=\"list_uploadfile\")\nasync def read_list_uploadfile(p: Annotated[list[UploadFile], File()]):\n    return {\"file_size\": [file.size for file in p]}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes\",\n        \"/list-uploadfile\",\n    ],\n)\ndef test_list_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\n                \"type\": \"array\",\n                \"items\": {\n                    \"type\": \"string\",\n                    \"contentMediaType\": \"application/octet-stream\",\n                },\n                \"title\": \"P\",\n            },\n        },\n        \"required\": [\"p\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes\",\n        \"/list-uploadfile\",\n    ],\n)\ndef test_list_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes\",\n        \"/list-uploadfile\",\n    ],\n)\ndef test_list(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\"), (\"p\", b\"world\")])\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": [5, 5]}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/list-bytes-alias\", operation_id=\"list_bytes_alias\")\nasync def read_list_bytes_alias(p: Annotated[list[bytes], File(alias=\"p_alias\")]):\n    return {\"file_size\": [len(file) for file in p]}\n\n\n@app.post(\"/list-uploadfile-alias\", operation_id=\"list_uploadfile_alias\")\nasync def read_list_uploadfile_alias(\n    p: Annotated[list[UploadFile], File(alias=\"p_alias\")],\n):\n    return {\"file_size\": [file.size for file in p]}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-alias\",\n        \"/list-uploadfile-alias\",\n    ],\n)\ndef test_list_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\n                \"type\": \"array\",\n                \"items\": {\n                    \"type\": \"string\",\n                    \"contentMediaType\": \"application/octet-stream\",\n                },\n                \"title\": \"P Alias\",\n            },\n        },\n        \"required\": [\"p_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-alias\",\n        \"/list-uploadfile-alias\",\n    ],\n)\ndef test_list_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-alias\",\n        \"/list-uploadfile-alias\",\n    ],\n)\ndef test_list_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\"), (\"p\", b\"world\")])\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-alias\",\n        \"/list-uploadfile-alias\",\n    ],\n)\ndef test_list_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_alias\", b\"hello\"), (\"p_alias\", b\"world\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": [5, 5]}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\"/list-bytes-validation-alias\", operation_id=\"list_bytes_validation_alias\")\ndef read_list_bytes_validation_alias(\n    p: Annotated[list[bytes], File(validation_alias=\"p_val_alias\")],\n):\n    return {\"file_size\": [len(file) for file in p]}\n\n\n@app.post(\n    \"/list-uploadfile-validation-alias\",\n    operation_id=\"list_uploadfile_validation_alias\",\n)\ndef read_list_uploadfile_validation_alias(\n    p: Annotated[list[UploadFile], File(validation_alias=\"p_val_alias\")],\n):\n    return {\"file_size\": [file.size for file in p]}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-validation-alias\",\n        \"/list-uploadfile-validation-alias\",\n    ],\n)\ndef test_list_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"type\": \"array\",\n                \"items\": {\n                    \"type\": \"string\",\n                    \"contentMediaType\": \"application/octet-stream\",\n                },\n                \"title\": \"P Val Alias\",\n            },\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-validation-alias\",\n        \"/list-uploadfile-validation-alias\",\n    ],\n)\ndef test_list_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-validation-alias\",\n        \"/list-uploadfile-validation-alias\",\n    ],\n)\ndef test_list_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\"), (\"p\", b\"world\")])\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-validation-alias\",\n        \"/list-uploadfile-validation-alias\",\n    ],\n)\ndef test_list_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(\n        path, files=[(\"p_val_alias\", b\"hello\"), (\"p_val_alias\", b\"world\")]\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": [5, 5]}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/list-bytes-alias-and-validation-alias\",\n    operation_id=\"list_bytes_alias_and_validation_alias\",\n)\ndef read_list_bytes_alias_and_validation_alias(\n    p: Annotated[list[bytes], File(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"file_size\": [len(file) for file in p]}\n\n\n@app.post(\n    \"/list-uploadfile-alias-and-validation-alias\",\n    operation_id=\"list_uploadfile_alias_and_validation_alias\",\n)\ndef read_list_uploadfile_alias_and_validation_alias(\n    p: Annotated[\n        list[UploadFile], File(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ],\n):\n    return {\"file_size\": [file.size for file in p]}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-alias-and-validation-alias\",\n        \"/list-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_list_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"type\": \"array\",\n                \"items\": {\n                    \"type\": \"string\",\n                    \"contentMediaType\": \"application/octet-stream\",\n                },\n                \"title\": \"P Val Alias\",\n            },\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-alias-and-validation-alias\",\n        \"/list-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_list_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-alias-and-validation-alias\",\n        \"/list-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_list_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", \"hello\"), (\"p\", \"world\")])\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-alias-and-validation-alias\",\n        \"/list-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_list_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_alias\", b\"hello\"), (\"p_alias\", b\"world\")])\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/list-bytes-alias-and-validation-alias\",\n        \"/list-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_list_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(\n        path, files=[(\"p_val_alias\", b\"hello\"), (\"p_val_alias\", b\"world\")]\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": [5, 5]}\n"
  },
  {
    "path": "tests/test_request_params/test_file/test_optional.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, File, UploadFile\nfrom fastapi.testclient import TestClient\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/optional-bytes\", operation_id=\"optional_bytes\")\nasync def read_optional_bytes(p: Annotated[bytes | None, File()] = None):\n    return {\"file_size\": len(p) if p else None}\n\n\n@app.post(\"/optional-uploadfile\", operation_id=\"optional_uploadfile\")\nasync def read_optional_uploadfile(p: Annotated[UploadFile | None, File()] = None):\n    return {\"file_size\": p.size if p else None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes\",\n        \"/optional-uploadfile\",\n    ],\n)\ndef test_optional_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\n                \"anyOf\": [\n                    {\"type\": \"string\", \"contentMediaType\": \"application/octet-stream\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P\",\n            }\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes\",\n        \"/optional-uploadfile\",\n    ],\n)\ndef test_optional_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes\",\n        \"/optional-uploadfile\",\n    ],\n)\ndef test_optional(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\")])\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": 5}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/optional-bytes-alias\", operation_id=\"optional_bytes_alias\")\nasync def read_optional_bytes_alias(\n    p: Annotated[bytes | None, File(alias=\"p_alias\")] = None,\n):\n    return {\"file_size\": len(p) if p else None}\n\n\n@app.post(\"/optional-uploadfile-alias\", operation_id=\"optional_uploadfile_alias\")\nasync def read_optional_uploadfile_alias(\n    p: Annotated[UploadFile | None, File(alias=\"p_alias\")] = None,\n):\n    return {\"file_size\": p.size if p else None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-alias\",\n        \"/optional-uploadfile-alias\",\n    ],\n)\ndef test_optional_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\n                \"anyOf\": [\n                    {\"type\": \"string\", \"contentMediaType\": \"application/octet-stream\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Alias\",\n            }\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-alias\",\n        \"/optional-uploadfile-alias\",\n    ],\n)\ndef test_optional_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-alias\",\n        \"/optional-uploadfile-alias\",\n    ],\n)\ndef test_optional_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\")])\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-alias\",\n        \"/optional-uploadfile-alias\",\n    ],\n)\ndef test_optional_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_alias\", b\"hello\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": 5}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\n    \"/optional-bytes-validation-alias\", operation_id=\"optional_bytes_validation_alias\"\n)\ndef read_optional_bytes_validation_alias(\n    p: Annotated[bytes | None, File(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"file_size\": len(p) if p else None}\n\n\n@app.post(\n    \"/optional-uploadfile-validation-alias\",\n    operation_id=\"optional_uploadfile_validation_alias\",\n)\ndef read_optional_uploadfile_validation_alias(\n    p: Annotated[UploadFile | None, File(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"file_size\": p.size if p else None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-validation-alias\",\n        \"/optional-uploadfile-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [\n                    {\"type\": \"string\", \"contentMediaType\": \"application/octet-stream\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Val Alias\",\n            }\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-validation-alias\",\n        \"/optional-uploadfile-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-validation-alias\",\n        \"/optional-uploadfile-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-validation-alias\",\n        \"/optional-uploadfile-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_val_alias\", b\"hello\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": 5}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/optional-bytes-alias-and-validation-alias\",\n    operation_id=\"optional_bytes_alias_and_validation_alias\",\n)\ndef read_optional_bytes_alias_and_validation_alias(\n    p: Annotated[\n        bytes | None, File(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"file_size\": len(p) if p else None}\n\n\n@app.post(\n    \"/optional-uploadfile-alias-and-validation-alias\",\n    operation_id=\"optional_uploadfile_alias_and_validation_alias\",\n)\ndef read_optional_uploadfile_alias_and_validation_alias(\n    p: Annotated[\n        UploadFile | None, File(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"file_size\": p.size if p else None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-alias-and-validation-alias\",\n        \"/optional-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [\n                    {\"type\": \"string\", \"contentMediaType\": \"application/octet-stream\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Val Alias\",\n            }\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-alias-and-validation-alias\",\n        \"/optional-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-alias-and-validation-alias\",\n        \"/optional-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-alias-and-validation-alias\",\n        \"/optional-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_alias\", b\"hello\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-bytes-alias-and-validation-alias\",\n        \"/optional-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_val_alias\", b\"hello\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": 5}\n"
  },
  {
    "path": "tests/test_request_params/test_file/test_optional_list.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, File, UploadFile\nfrom fastapi.testclient import TestClient\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/optional-list-bytes\")\nasync def read_optional_list_bytes(p: Annotated[list[bytes] | None, File()] = None):\n    return {\"file_size\": [len(file) for file in p] if p else None}\n\n\n@app.post(\"/optional-list-uploadfile\")\nasync def read_optional_list_uploadfile(\n    p: Annotated[list[UploadFile] | None, File()] = None,\n):\n    return {\"file_size\": [file.size for file in p] if p else None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes\",\n        \"/optional-list-uploadfile\",\n    ],\n)\ndef test_optional_list_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\n                \"anyOf\": [\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\",\n                            \"contentMediaType\": \"application/octet-stream\",\n                        },\n                    },\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P\",\n            }\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes\",\n        \"/optional-list-uploadfile\",\n    ],\n)\ndef test_optional_list_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes\",\n        \"/optional-list-uploadfile\",\n    ],\n)\ndef test_optional_list(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\"), (\"p\", b\"world\")])\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": [5, 5]}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/optional-list-bytes-alias\")\nasync def read_optional_list_bytes_alias(\n    p: Annotated[list[bytes] | None, File(alias=\"p_alias\")] = None,\n):\n    return {\"file_size\": [len(file) for file in p] if p else None}\n\n\n@app.post(\"/optional-list-uploadfile-alias\")\nasync def read_optional_list_uploadfile_alias(\n    p: Annotated[list[UploadFile] | None, File(alias=\"p_alias\")] = None,\n):\n    return {\"file_size\": [file.size for file in p] if p else None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-alias\",\n        \"/optional-list-uploadfile-alias\",\n    ],\n)\ndef test_optional_list_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\n                \"anyOf\": [\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\",\n                            \"contentMediaType\": \"application/octet-stream\",\n                        },\n                    },\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Alias\",\n            }\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-alias\",\n        \"/optional-list-uploadfile-alias\",\n    ],\n)\ndef test_optional_list_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-alias\",\n        \"/optional-list-uploadfile-alias\",\n    ],\n)\ndef test_optional_list_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\"), (\"p\", b\"world\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-alias\",\n        \"/optional-list-uploadfile-alias\",\n    ],\n)\ndef test_optional_list_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_alias\", b\"hello\"), (\"p_alias\", b\"world\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": [5, 5]}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\"/optional-list-bytes-validation-alias\")\ndef read_optional_list_bytes_validation_alias(\n    p: Annotated[list[bytes] | None, File(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"file_size\": [len(file) for file in p] if p else None}\n\n\n@app.post(\"/optional-list-uploadfile-validation-alias\")\ndef read_optional_list_uploadfile_validation_alias(\n    p: Annotated[list[UploadFile] | None, File(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"file_size\": [file.size for file in p] if p else None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-validation-alias\",\n        \"/optional-list-uploadfile-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\",\n                            \"contentMediaType\": \"application/octet-stream\",\n                        },\n                    },\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Val Alias\",\n            }\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-validation-alias\",\n        \"/optional-list-uploadfile-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-validation-alias\",\n        \"/optional-list-uploadfile-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\"), (\"p\", b\"world\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-validation-alias\",\n        \"/optional-list-uploadfile-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(\n        path, files=[(\"p_val_alias\", b\"hello\"), (\"p_val_alias\", b\"world\")]\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": [5, 5]}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\"/optional-list-bytes-alias-and-validation-alias\")\ndef read_optional_list_bytes_alias_and_validation_alias(\n    p: Annotated[\n        list[bytes] | None, File(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"file_size\": [len(file) for file in p] if p else None}\n\n\n@app.post(\"/optional-list-uploadfile-alias-and-validation-alias\")\ndef read_optional_list_uploadfile_alias_and_validation_alias(\n    p: Annotated[\n        list[UploadFile] | None,\n        File(alias=\"p_alias\", validation_alias=\"p_val_alias\"),\n    ] = None,\n):\n    return {\"file_size\": [file.size for file in p] if p else None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-alias-and-validation-alias\",\n        \"/optional-list-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [\n                    {\n                        \"type\": \"array\",\n                        \"items\": {\n                            \"type\": \"string\",\n                            \"contentMediaType\": \"application/octet-stream\",\n                        },\n                    },\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Val Alias\",\n            }\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-alias-and-validation-alias\",\n        \"/optional-list-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-alias-and-validation-alias\",\n        \"/optional-list-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-alias-and-validation-alias\",\n        \"/optional-list-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_alias\", b\"hello\"), (\"p_alias\", b\"world\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-bytes-alias-and-validation-alias\",\n        \"/optional-list-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(\n        path, files=[(\"p_val_alias\", b\"hello\"), (\"p_val_alias\", b\"world\")]\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": [5, 5]}\n"
  },
  {
    "path": "tests/test_request_params/test_file/test_required.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, File, UploadFile\nfrom fastapi.testclient import TestClient\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/required-bytes\", operation_id=\"required_bytes\")\nasync def read_required_bytes(p: Annotated[bytes, File()]):\n    return {\"file_size\": len(p)}\n\n\n@app.post(\"/required-uploadfile\", operation_id=\"required_uploadfile\")\nasync def read_required_uploadfile(p: Annotated[UploadFile, File()]):\n    return {\"file_size\": p.size}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes\",\n        \"/required-uploadfile\",\n    ],\n)\ndef test_required_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\n                \"title\": \"P\",\n                \"type\": \"string\",\n                \"contentMediaType\": \"application/octet-stream\",\n            },\n        },\n        \"required\": [\"p\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes\",\n        \"/required-uploadfile\",\n    ],\n)\ndef test_required_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes\",\n        \"/required-uploadfile\",\n    ],\n)\ndef test_required(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\")])\n    assert response.status_code == 200\n    assert response.json() == {\"file_size\": 5}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/required-bytes-alias\", operation_id=\"required_bytes_alias\")\nasync def read_required_bytes_alias(p: Annotated[bytes, File(alias=\"p_alias\")]):\n    return {\"file_size\": len(p)}\n\n\n@app.post(\"/required-uploadfile-alias\", operation_id=\"required_uploadfile_alias\")\nasync def read_required_uploadfile_alias(\n    p: Annotated[UploadFile, File(alias=\"p_alias\")],\n):\n    return {\"file_size\": p.size}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-alias\",\n        \"/required-uploadfile-alias\",\n    ],\n)\ndef test_required_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\n                \"title\": \"P Alias\",\n                \"type\": \"string\",\n                \"contentMediaType\": \"application/octet-stream\",\n            },\n        },\n        \"required\": [\"p_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-alias\",\n        \"/required-uploadfile-alias\",\n    ],\n)\ndef test_required_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-alias\",\n        \"/required-uploadfile-alias\",\n    ],\n)\ndef test_required_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\")])\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-alias\",\n        \"/required-uploadfile-alias\",\n    ],\n)\ndef test_required_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_alias\", b\"hello\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": 5}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\n    \"/required-bytes-validation-alias\", operation_id=\"required_bytes_validation_alias\"\n)\ndef read_required_bytes_validation_alias(\n    p: Annotated[bytes, File(validation_alias=\"p_val_alias\")],\n):\n    return {\"file_size\": len(p)}\n\n\n@app.post(\n    \"/required-uploadfile-validation-alias\",\n    operation_id=\"required_uploadfile_validation_alias\",\n)\ndef read_required_uploadfile_validation_alias(\n    p: Annotated[UploadFile, File(validation_alias=\"p_val_alias\")],\n):\n    return {\"file_size\": p.size}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-validation-alias\",\n        \"/required-uploadfile-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"title\": \"P Val Alias\",\n                \"type\": \"string\",\n                \"contentMediaType\": \"application/octet-stream\",\n            },\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-validation-alias\",\n        \"/required-uploadfile-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-validation-alias\",\n        \"/required-uploadfile-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p\", b\"hello\")])\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-validation-alias\",\n        \"/required-uploadfile-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_val_alias\", b\"hello\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": 5}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/required-bytes-alias-and-validation-alias\",\n    operation_id=\"required_bytes_alias_and_validation_alias\",\n)\ndef read_required_bytes_alias_and_validation_alias(\n    p: Annotated[bytes, File(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"file_size\": len(p)}\n\n\n@app.post(\n    \"/required-uploadfile-alias-and-validation-alias\",\n    operation_id=\"required_uploadfile_alias_and_validation_alias\",\n)\ndef read_required_uploadfile_alias_and_validation_alias(\n    p: Annotated[UploadFile, File(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"file_size\": p.size}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-alias-and-validation-alias\",\n        \"/required-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"title\": \"P Val Alias\",\n                \"type\": \"string\",\n                \"contentMediaType\": \"application/octet-stream\",\n            },\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-alias-and-validation-alias\",\n        \"/required-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-alias-and-validation-alias\",\n        \"/required-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, files={\"p\": \"hello\"})\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-alias-and-validation-alias\",\n        \"/required-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_alias\", b\"hello\")])\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-bytes-alias-and-validation-alias\",\n        \"/required-uploadfile-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, files=[(\"p_val_alias\", b\"hello\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": 5}\n"
  },
  {
    "path": "tests/test_request_params/test_file/utils.py",
    "content": "from typing import Any\n\n\ndef get_body_model_name(openapi: dict[str, Any], path: str) -> str:\n    body = openapi[\"paths\"][path][\"post\"][\"requestBody\"]\n    body_schema = body[\"content\"][\"multipart/form-data\"][\"schema\"]\n    return body_schema.get(\"$ref\", \"\").split(\"/\")[-1]\n"
  },
  {
    "path": "tests/test_request_params/test_form/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_request_params/test_form/test_list.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom dirty_equals import IsOneOf, IsPartialDict\nfrom fastapi import FastAPI, Form\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/required-list-str\", operation_id=\"required_list_str\")\nasync def read_required_list_str(p: Annotated[list[str], Form()]):\n    return {\"p\": p}\n\n\nclass FormModelRequiredListStr(BaseModel):\n    p: list[str]\n\n\n@app.post(\"/model-required-list-str\", operation_id=\"model_required_list_str\")\ndef read_model_required_list_str(p: Annotated[FormModelRequiredListStr, Form()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\n                \"items\": {\"type\": \"string\"},\n                \"title\": \"P\",\n                \"type\": \"array\",\n            },\n        },\n        \"required\": [\"p\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/required-list-alias\", operation_id=\"required_list_alias\")\nasync def read_required_list_alias(p: Annotated[list[str], Form(alias=\"p_alias\")]):\n    return {\"p\": p}\n\n\nclass FormModelRequiredListAlias(BaseModel):\n    p: list[str] = Field(alias=\"p_alias\")\n\n\n@app.post(\"/model-required-list-alias\", operation_id=\"model_required_list_alias\")\nasync def read_model_required_list_alias(\n    p: Annotated[FormModelRequiredListAlias, Form()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias\",\n        \"/model-required-list-alias\",\n    ],\n)\ndef test_required_list_str_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\n                \"items\": {\"type\": \"string\"},\n                \"title\": \"P Alias\",\n                \"type\": \"array\",\n            },\n        },\n        \"required\": [\"p_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-alias\", \"/model-required-list-alias\"],\n)\ndef test_required_list_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias\",\n        \"/model-required-list-alias\",\n    ],\n)\ndef test_required_list_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": [\"hello\", \"world\"]}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-alias\", \"/model-required-list-alias\"],\n)\ndef test_required_list_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\n    \"/required-list-validation-alias\", operation_id=\"required_list_validation_alias\"\n)\ndef read_required_list_validation_alias(\n    p: Annotated[list[str], Form(validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass FormModelRequiredListValidationAlias(BaseModel):\n    p: list[str] = Field(validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-required-list-validation-alias\",\n    operation_id=\"model_required_list_validation_alias\",\n)\nasync def read_model_required_list_validation_alias(\n    p: Annotated[FormModelRequiredListValidationAlias, Form()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-validation-alias\", \"/model-required-list-validation-alias\"],\n)\ndef test_required_list_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"items\": {\"type\": \"string\"},\n                \"title\": \"P Val Alias\",\n                \"type\": \"array\",\n            },\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-validation-alias\",\n        \"/model-required-list-validation-alias\",\n    ],\n)\ndef test_required_list_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-validation-alias\",\n        \"/model-required-list-validation-alias\",\n    ],\n)\ndef test_required_list_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, IsPartialDict({\"p\": [\"hello\", \"world\"]})),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-validation-alias\", \"/model-required-list-validation-alias\"],\n)\ndef test_required_list_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_val_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/required-list-alias-and-validation-alias\",\n    operation_id=\"required_list_alias_and_validation_alias\",\n)\ndef read_required_list_alias_and_validation_alias(\n    p: Annotated[list[str], Form(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass FormModelRequiredListAliasAndValidationAlias(BaseModel):\n    p: list[str] = Field(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-required-list-alias-and-validation-alias\",\n    operation_id=\"model_required_list_alias_and_validation_alias\",\n)\ndef read_model_required_list_alias_and_validation_alias(\n    p: Annotated[FormModelRequiredListAliasAndValidationAlias, Form()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"items\": {\"type\": \"string\"},\n                \"title\": \"P Val Alias\",\n                \"type\": \"array\",\n            },\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    {\"p\": [\"hello\", \"world\"]},\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p_alias\": [\"hello\", \"world\"]}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_val_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n"
  },
  {
    "path": "tests/test_request_params/test_form/test_optional_list.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, Form\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/optional-list-str\", operation_id=\"optional_list_str\")\nasync def read_optional_list_str(\n    p: Annotated[list[str] | None, Form()] = None,\n):\n    return {\"p\": p}\n\n\nclass FormModelOptionalListStr(BaseModel):\n    p: list[str] | None = None\n\n\n@app.post(\"/model-optional-list-str\", operation_id=\"model_optional_list_str\")\nasync def read_model_optional_list_str(p: Annotated[FormModelOptionalListStr, Form()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\n                \"anyOf\": [\n                    {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/optional-list-alias\", operation_id=\"optional_list_alias\")\nasync def read_optional_list_alias(\n    p: Annotated[list[str] | None, Form(alias=\"p_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass FormModelOptionalListAlias(BaseModel):\n    p: list[str] | None = Field(None, alias=\"p_alias\")\n\n\n@app.post(\"/model-optional-list-alias\", operation_id=\"model_optional_list_alias\")\nasync def read_model_optional_list_alias(\n    p: Annotated[FormModelOptionalListAlias, Form()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias\",\n        \"/model-optional-list-alias\",\n    ],\n)\ndef test_optional_list_str_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\n                \"anyOf\": [\n                    {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\n    \"/optional-list-validation-alias\", operation_id=\"optional_list_validation_alias\"\n)\ndef read_optional_list_validation_alias(\n    p: Annotated[list[str] | None, Form(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass FormModelOptionalListValidationAlias(BaseModel):\n    p: list[str] | None = Field(None, validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-optional-list-validation-alias\",\n    operation_id=\"model_optional_list_validation_alias\",\n)\ndef read_model_optional_list_validation_alias(\n    p: Annotated[FormModelOptionalListValidationAlias, Form()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [\n                    {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Val Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-validation-alias\",\n        \"/model-optional-list-validation-alias\",\n    ],\n)\ndef test_optional_list_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_val_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/optional-list-alias-and-validation-alias\",\n    operation_id=\"optional_list_alias_and_validation_alias\",\n)\ndef read_optional_list_alias_and_validation_alias(\n    p: Annotated[\n        list[str] | None, Form(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"p\": p}\n\n\nclass FormModelOptionalListAliasAndValidationAlias(BaseModel):\n    p: list[str] | None = Field(None, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-optional-list-alias-and-validation-alias\",\n    operation_id=\"model_optional_list_alias_and_validation_alias\",\n)\ndef read_model_optional_list_alias_and_validation_alias(\n    p: Annotated[FormModelOptionalListAliasAndValidationAlias, Form()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [\n                    {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                    {\"type\": \"null\"},\n                ],\n                \"title\": \"P Val Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_val_alias\": [\"hello\", \"world\"]})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"p\": [\n            \"hello\",\n            \"world\",\n        ]\n    }\n"
  },
  {
    "path": "tests/test_request_params/test_form/test_optional_str.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, Form\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/optional-str\", operation_id=\"optional_str\")\nasync def read_optional_str(p: Annotated[str | None, Form()] = None):\n    return {\"p\": p}\n\n\nclass FormModelOptionalStr(BaseModel):\n    p: str | None = None\n\n\n@app.post(\"/model-optional-str\", operation_id=\"model_optional_str\")\nasync def read_model_optional_str(p: Annotated[FormModelOptionalStr, Form()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\n                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                \"title\": \"P\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/optional-alias\", operation_id=\"optional_alias\")\nasync def read_optional_alias(\n    p: Annotated[str | None, Form(alias=\"p_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass FormModelOptionalAlias(BaseModel):\n    p: str | None = Field(None, alias=\"p_alias\")\n\n\n@app.post(\"/model-optional-alias\", operation_id=\"model_optional_alias\")\nasync def read_model_optional_alias(p: Annotated[FormModelOptionalAlias, Form()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias\",\n        \"/model-optional-alias\",\n    ],\n)\ndef test_optional_str_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\n                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                \"title\": \"P Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\"/optional-validation-alias\", operation_id=\"optional_validation_alias\")\ndef read_optional_validation_alias(\n    p: Annotated[str | None, Form(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass FormModelOptionalValidationAlias(BaseModel):\n    p: str | None = Field(None, validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-optional-validation-alias\", operation_id=\"model_optional_validation_alias\"\n)\ndef read_model_optional_validation_alias(\n    p: Annotated[FormModelOptionalValidationAlias, Form()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-validation-alias\", \"/model-optional-validation-alias\"],\n)\ndef test_optional_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                \"title\": \"P Val Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-validation-alias\", \"/model-optional-validation-alias\"],\n)\ndef test_optional_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-validation-alias\",\n        \"/model-optional-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-validation-alias\",\n        \"/model-optional-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/optional-alias-and-validation-alias\",\n    operation_id=\"optional_alias_and_validation_alias\",\n)\ndef read_optional_alias_and_validation_alias(\n    p: Annotated[\n        str | None, Form(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"p\": p}\n\n\nclass FormModelOptionalAliasAndValidationAlias(BaseModel):\n    p: str | None = Field(None, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-optional-alias-and-validation-alias\",\n    operation_id=\"model_optional_alias_and_validation_alias\",\n)\ndef read_model_optional_alias_and_validation_alias(\n    p: Annotated[FormModelOptionalAliasAndValidationAlias, Form()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\n                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                \"title\": \"P Val Alias\",\n            },\n        },\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_request_params/test_form/test_required_str.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi import FastAPI, Form\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\nfrom .utils import get_body_model_name\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.post(\"/required-str\", operation_id=\"required_str\")\nasync def read_required_str(p: Annotated[str, Form()]):\n    return {\"p\": p}\n\n\nclass FormModelRequiredStr(BaseModel):\n    p: str\n\n\n@app.post(\"/model-required-str\", operation_id=\"model_required_str\")\nasync def read_model_required_str(p: Annotated[FormModelRequiredStr, Form()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p\": {\"title\": \"P\", \"type\": \"string\"},\n        },\n        \"required\": [\"p\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.post(\"/required-alias\", operation_id=\"required_alias\")\nasync def read_required_alias(p: Annotated[str, Form(alias=\"p_alias\")]):\n    return {\"p\": p}\n\n\nclass FormModelRequiredAlias(BaseModel):\n    p: str = Field(alias=\"p_alias\")\n\n\n@app.post(\"/model-required-alias\", operation_id=\"model_required_alias\")\nasync def read_model_required_alias(p: Annotated[FormModelRequiredAlias, Form()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias\",\n        \"/model-required-alias\",\n    ],\n)\ndef test_required_str_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_alias\": {\"title\": \"P Alias\", \"type\": \"string\"},\n        },\n        \"required\": [\"p_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": \"hello\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": \"hello\"}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_alias\": \"hello\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.post(\"/required-validation-alias\", operation_id=\"required_validation_alias\")\ndef read_required_validation_alias(\n    p: Annotated[str, Form(validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass FormModelRequiredValidationAlias(BaseModel):\n    p: str = Field(validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-required-validation-alias\", operation_id=\"model_required_validation_alias\"\n)\ndef read_model_required_validation_alias(\n    p: Annotated[FormModelRequiredValidationAlias, Form()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-validation-alias\", \"/model-required-validation-alias\"],\n)\ndef test_required_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\"title\": \"P Val Alias\", \"type\": \"string\"},\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": \"hello\"})\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": \"hello\"}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.post(\n    \"/required-alias-and-validation-alias\",\n    operation_id=\"required_alias_and_validation_alias\",\n)\ndef read_required_alias_and_validation_alias(\n    p: Annotated[str, Form(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass FormModelRequiredAliasAndValidationAlias(BaseModel):\n    p: str = Field(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.post(\n    \"/model-required-alias-and-validation-alias\",\n    operation_id=\"model_required_alias_and_validation_alias\",\n)\ndef read_model_required_alias_and_validation_alias(\n    p: Annotated[FormModelRequiredAliasAndValidationAlias, Form()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_schema(path: str):\n    openapi = app.openapi()\n    body_model_name = get_body_model_name(openapi, path)\n\n    assert app.openapi()[\"components\"][\"schemas\"][body_model_name] == {\n        \"properties\": {\n            \"p_val_alias\": {\"title\": \"P Val Alias\", \"type\": \"string\"},\n        },\n        \"required\": [\"p_val_alias\"],\n        \"title\": body_model_name,\n        \"type\": \"object\",\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.post(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p\": \"hello\"})\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"body\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": \"hello\"}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_alias\": \"hello\"})\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p_alias\": \"hello\"}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.post(path, data={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_request_params/test_form/utils.py",
    "content": "from typing import Any\n\n\ndef get_body_model_name(openapi: dict[str, Any], path: str) -> str:\n    body = openapi[\"paths\"][path][\"post\"][\"requestBody\"]\n    body_schema = body[\"content\"][\"application/x-www-form-urlencoded\"][\"schema\"]\n    return body_schema.get(\"$ref\", \"\").split(\"/\")[-1]\n"
  },
  {
    "path": "tests/test_request_params/test_header/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_request_params/test_header/test_list.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom dirty_equals import AnyThing, IsOneOf, IsPartialDict\nfrom fastapi import FastAPI, Header\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.get(\"/required-list-str\")\nasync def read_required_list_str(p: Annotated[list[str], Header()]):\n    return {\"p\": p}\n\n\nclass HeaderModelRequiredListStr(BaseModel):\n    p: list[str]\n\n\n@app.get(\"/model-required-list-str\")\ndef read_model_required_list_str(p: Annotated[HeaderModelRequiredListStr, Header()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\n                    \"title\": \"P\",\n                    \"type\": \"array\",\n                    \"items\": {\"type\": \"string\"},\n                },\n                \"name\": \"p\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"p\"],\n                \"msg\": \"Field required\",\n                \"input\": AnyThing,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p\", \"hello\"), (\"p\", \"world\")])\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.get(\"/required-list-alias\")\nasync def read_required_list_alias(p: Annotated[list[str], Header(alias=\"p_alias\")]):\n    return {\"p\": p}\n\n\nclass HeaderModelRequiredListAlias(BaseModel):\n    p: list[str] = Field(alias=\"p_alias\")\n\n\n@app.get(\"/model-required-list-alias\")\nasync def read_model_required_list_alias(\n    p: Annotated[HeaderModelRequiredListAlias, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-alias\", \"/model-required-list-alias\"],\n)\ndef test_required_list_str_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\n                    \"title\": \"P Alias\",\n                    \"type\": \"array\",\n                    \"items\": {\"type\": \"string\"},\n                },\n                \"name\": \"p_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-alias\", \"/model-required-list-alias\"],\n)\ndef test_required_list_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": AnyThing,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias\",\n        \"/model-required-list-alias\",\n    ],\n)\ndef test_required_list_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p\", \"hello\"), (\"p\", \"world\")])\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, IsPartialDict({\"p\": [\"hello\", \"world\"]})),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias\",\n        \"/model-required-list-alias\",\n    ],\n)\ndef test_required_list_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p_alias\", \"hello\"), (\"p_alias\", \"world\")])\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.get(\"/required-list-validation-alias\")\ndef read_required_list_validation_alias(\n    p: Annotated[list[str], Header(validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass HeaderModelRequiredListValidationAlias(BaseModel):\n    p: list[str] = Field(validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-required-list-validation-alias\")\nasync def read_model_required_list_validation_alias(\n    p: Annotated[HeaderModelRequiredListValidationAlias, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-validation-alias\", \"/model-required-list-validation-alias\"],\n)\ndef test_required_list_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\n                    \"title\": \"P Val Alias\",\n                    \"type\": \"array\",\n                    \"items\": {\"type\": \"string\"},\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-validation-alias\",\n        \"/model-required-list-validation-alias\",\n    ],\n)\ndef test_required_list_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"header\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": AnyThing,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-validation-alias\",\n        \"/model-required-list-validation-alias\",\n    ],\n)\ndef test_required_list_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p\", \"hello\"), (\"p\", \"world\")])\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, IsPartialDict({\"p\": [\"hello\", \"world\"]})),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-validation-alias\", \"/model-required-list-validation-alias\"],\n)\ndef test_required_list_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(\n        path, headers=[(\"p_val_alias\", \"hello\"), (\"p_val_alias\", \"world\")]\n    )\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.get(\"/required-list-alias-and-validation-alias\")\ndef read_required_list_alias_and_validation_alias(\n    p: Annotated[list[str], Header(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass HeaderModelRequiredListAliasAndValidationAlias(BaseModel):\n    p: list[str] = Field(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-required-list-alias-and-validation-alias\")\ndef read_model_required_list_alias_and_validation_alias(\n    p: Annotated[HeaderModelRequiredListAliasAndValidationAlias, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\n                    \"title\": \"P Val Alias\",\n                    \"type\": \"array\",\n                    \"items\": {\"type\": \"string\"},\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"header\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": AnyThing,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p\", \"hello\"), (\"p\", \"world\")])\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"header\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    IsPartialDict({\"p\": [\"hello\", \"world\"]}),\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p_alias\", \"hello\"), (\"p_alias\", \"world\")])\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    IsPartialDict({\"p_alias\": [\"hello\", \"world\"]}),\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(\n        path, headers=[(\"p_val_alias\", \"hello\"), (\"p_val_alias\", \"world\")]\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n"
  },
  {
    "path": "tests/test_request_params/test_header/test_optional_list.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, Header\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.get(\"/optional-list-str\")\nasync def read_optional_list_str(\n    p: Annotated[list[str] | None, Header()] = None,\n):\n    return {\"p\": p}\n\n\nclass HeaderModelOptionalListStr(BaseModel):\n    p: list[str] | None = None\n\n\n@app.get(\"/model-optional-list-str\")\nasync def read_model_optional_list_str(\n    p: Annotated[HeaderModelOptionalListStr, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [\n                        {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                        {\"type\": \"null\"},\n                    ],\n                    \"title\": \"P\",\n                },\n                \"name\": \"p\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p\", \"hello\"), (\"p\", \"world\")])\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.get(\"/optional-list-alias\")\nasync def read_optional_list_alias(\n    p: Annotated[list[str] | None, Header(alias=\"p_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass HeaderModelOptionalListAlias(BaseModel):\n    p: list[str] | None = Field(None, alias=\"p_alias\")\n\n\n@app.get(\"/model-optional-list-alias\")\nasync def read_model_optional_list_alias(\n    p: Annotated[HeaderModelOptionalListAlias, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_str_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [\n                        {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                        {\"type\": \"null\"},\n                    ],\n                    \"title\": \"P Alias\",\n                },\n                \"name\": \"p_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p\", \"hello\"), (\"p\", \"world\")])\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias\",\n        \"/model-optional-list-alias\",\n    ],\n)\ndef test_optional_list_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p_alias\", \"hello\"), (\"p_alias\", \"world\")])\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.get(\"/optional-list-validation-alias\")\ndef read_optional_list_validation_alias(\n    p: Annotated[list[str] | None, Header(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass HeaderModelOptionalListValidationAlias(BaseModel):\n    p: list[str] | None = Field(None, validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-optional-list-validation-alias\")\ndef read_model_optional_list_validation_alias(\n    p: Annotated[HeaderModelOptionalListValidationAlias, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [\n                        {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                        {\"type\": \"null\"},\n                    ],\n                    \"title\": \"P Val Alias\",\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-validation-alias\",\n        \"/model-optional-list-validation-alias\",\n    ],\n)\ndef test_optional_list_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p\", \"hello\"), (\"p\", \"world\")])\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(\n        path, headers=[(\"p_val_alias\", \"hello\"), (\"p_val_alias\", \"world\")]\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.get(\"/optional-list-alias-and-validation-alias\")\ndef read_optional_list_alias_and_validation_alias(\n    p: Annotated[\n        list[str] | None, Header(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"p\": p}\n\n\nclass HeaderModelOptionalListAliasAndValidationAlias(BaseModel):\n    p: list[str] | None = Field(None, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-optional-list-alias-and-validation-alias\")\ndef read_model_optional_list_alias_and_validation_alias(\n    p: Annotated[HeaderModelOptionalListAliasAndValidationAlias, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [\n                        {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                        {\"type\": \"null\"},\n                    ],\n                    \"title\": \"P Val Alias\",\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p\", \"hello\"), (\"p\", \"world\")])\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers=[(\"p_alias\", \"hello\"), (\"p_alias\", \"world\")])\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(\n        path, headers=[(\"p_val_alias\", \"hello\"), (\"p_val_alias\", \"world\")]\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"p\": [\n            \"hello\",\n            \"world\",\n        ]\n    }\n"
  },
  {
    "path": "tests/test_request_params/test_header/test_optional_str.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, Header\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.get(\"/optional-str\")\nasync def read_optional_str(p: Annotated[str | None, Header()] = None):\n    return {\"p\": p}\n\n\nclass HeaderModelOptionalStr(BaseModel):\n    p: str | None = None\n\n\n@app.get(\"/model-optional-str\")\nasync def read_model_optional_str(p: Annotated[HeaderModelOptionalStr, Header()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P\",\n                },\n                \"name\": \"p\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.get(\"/optional-alias\")\nasync def read_optional_alias(\n    p: Annotated[str | None, Header(alias=\"p_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass HeaderModelOptionalAlias(BaseModel):\n    p: str | None = Field(None, alias=\"p_alias\")\n\n\n@app.get(\"/model-optional-alias\")\nasync def read_model_optional_alias(p: Annotated[HeaderModelOptionalAlias, Header()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_str_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P Alias\",\n                },\n                \"name\": \"p_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias\",\n        \"/model-optional-alias\",\n    ],\n)\ndef test_optional_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.get(\"/optional-validation-alias\")\ndef read_optional_validation_alias(\n    p: Annotated[str | None, Header(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass HeaderModelOptionalValidationAlias(BaseModel):\n    p: str | None = Field(None, validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-optional-validation-alias\")\ndef read_model_optional_validation_alias(\n    p: Annotated[HeaderModelOptionalValidationAlias, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-validation-alias\", \"/model-optional-validation-alias\"],\n)\ndef test_optional_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P Val Alias\",\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-validation-alias\", \"/model-optional-validation-alias\"],\n)\ndef test_optional_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-validation-alias\",\n        \"/model-optional-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-validation-alias\",\n        \"/model-optional-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.get(\"/optional-alias-and-validation-alias\")\ndef read_optional_alias_and_validation_alias(\n    p: Annotated[\n        str | None, Header(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"p\": p}\n\n\nclass HeaderModelOptionalAliasAndValidationAlias(BaseModel):\n    p: str | None = Field(None, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-optional-alias-and-validation-alias\")\ndef read_model_optional_alias_and_validation_alias(\n    p: Annotated[HeaderModelOptionalAliasAndValidationAlias, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P Val Alias\",\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_request_params/test_header/test_required_str.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom dirty_equals import AnyThing, IsOneOf, IsPartialDict\nfrom fastapi import FastAPI, Header\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.get(\"/required-str\")\nasync def read_required_str(p: Annotated[str, Header()]):\n    return {\"p\": p}\n\n\nclass HeaderModelRequiredStr(BaseModel):\n    p: str\n\n\n@app.get(\"/model-required-str\")\nasync def read_model_required_str(p: Annotated[HeaderModelRequiredStr, Header()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P\", \"type\": \"string\"},\n                \"name\": \"p\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"p\"],\n                \"msg\": \"Field required\",\n                \"input\": AnyThing,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p\": \"hello\"})\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.get(\"/required-alias\")\nasync def read_required_alias(p: Annotated[str, Header(alias=\"p_alias\")]):\n    return {\"p\": p}\n\n\nclass HeaderModelRequiredAlias(BaseModel):\n    p: str = Field(alias=\"p_alias\")\n\n\n@app.get(\"/model-required-alias\")\nasync def read_model_required_alias(p: Annotated[HeaderModelRequiredAlias, Header()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_str_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P Alias\", \"type\": \"string\"},\n                \"name\": \"p_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": AnyThing,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias\",\n        \"/model-required-alias\",\n    ],\n)\ndef test_required_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p\": \"hello\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, IsPartialDict({\"p\": \"hello\"})),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias\",\n        \"/model-required-alias\",\n    ],\n)\ndef test_required_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p_alias\": \"hello\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.get(\"/required-validation-alias\")\ndef read_required_validation_alias(\n    p: Annotated[str, Header(validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass HeaderModelRequiredValidationAlias(BaseModel):\n    p: str = Field(validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-required-validation-alias\")\ndef read_model_required_validation_alias(\n    p: Annotated[HeaderModelRequiredValidationAlias, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-validation-alias\", \"/model-required-validation-alias\"],\n)\ndef test_required_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P Val Alias\", \"type\": \"string\"},\n                \"name\": \"p_val_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"header\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": AnyThing,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p\": \"hello\"})\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, IsPartialDict({\"p\": \"hello\"})),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.get(\"/required-alias-and-validation-alias\")\ndef read_required_alias_and_validation_alias(\n    p: Annotated[str, Header(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass HeaderModelRequiredAliasAndValidationAlias(BaseModel):\n    p: str = Field(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-required-alias-and-validation-alias\")\ndef read_model_required_alias_and_validation_alias(\n    p: Annotated[HeaderModelRequiredAliasAndValidationAlias, Header()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P Val Alias\", \"type\": \"string\"},\n                \"name\": \"p_val_alias\",\n                \"in\": \"header\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"header\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": AnyThing,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p\": \"hello\"})\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"header\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    IsPartialDict({\"p\": \"hello\"}),\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p_alias\": \"hello\"})\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    IsPartialDict({\"p_alias\": \"hello\"}),\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(path, headers={\"p_val_alias\": \"hello\"})\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_request_params/test_path/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_request_params/test_path/test_list.py",
    "content": "# FastAPI doesn't currently support non-scalar Path parameters\n"
  },
  {
    "path": "tests/test_request_params/test_path/test_optional_list.py",
    "content": "# Optional Path parameters are not supported\n"
  },
  {
    "path": "tests/test_request_params/test_path/test_optional_str.py",
    "content": "# Optional Path parameters are not supported\n"
  },
  {
    "path": "tests/test_request_params/test_path/test_required_str.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, Path\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import Is, snapshot\n\napp = FastAPI()\n\n\n@app.get(\"/required-str/{p}\")\nasync def read_required_str(p: Annotated[str, Path()]):\n    return {\"p\": p}\n\n\n@app.get(\"/required-alias/{p_alias}\")\nasync def read_required_alias(p: Annotated[str, Path(alias=\"p_alias\")]):\n    return {\"p\": p}\n\n\n@app.get(\"/required-validation-alias/{p_val_alias}\")\ndef read_required_validation_alias(\n    p: Annotated[str, Path(validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\n@app.get(\"/required-alias-and-validation-alias/{p_val_alias}\")\ndef read_required_alias_and_validation_alias(\n    p: Annotated[str, Path(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\n@pytest.mark.parametrize(\n    (\"path\", \"expected_name\", \"expected_title\"),\n    [\n        pytest.param(\"/required-str/{p}\", \"p\", \"P\", id=\"required-str\"),\n        pytest.param(\n            \"/required-alias/{p_alias}\", \"p_alias\", \"P Alias\", id=\"required-alias\"\n        ),\n        pytest.param(\n            \"/required-validation-alias/{p_val_alias}\",\n            \"p_val_alias\",\n            \"P Val Alias\",\n            id=\"required-validation-alias\",\n        ),\n        pytest.param(\n            \"/required-alias-and-validation-alias/{p_val_alias}\",\n            \"p_val_alias\",\n            \"P Val Alias\",\n            id=\"required-alias-and-validation-alias\",\n        ),\n    ],\n)\ndef test_schema(path: str, expected_name: str, expected_title: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": Is(expected_title), \"type\": \"string\"},\n                \"name\": Is(expected_name),\n                \"in\": \"path\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        pytest.param(\"/required-str\", id=\"required-str\"),\n        pytest.param(\"/required-alias\", id=\"required-alias\"),\n        pytest.param(\n            \"/required-validation-alias\",\n            id=\"required-validation-alias\",\n        ),\n        pytest.param(\n            \"/required-alias-and-validation-alias\",\n            id=\"required-alias-and-validation-alias\",\n        ),\n    ],\n)\ndef test_success(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}/hello\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_request_params/test_query/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_request_params/test_query/test_list.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi import FastAPI, Query\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.get(\"/required-list-str\")\nasync def read_required_list_str(p: Annotated[list[str], Query()]):\n    return {\"p\": p}\n\n\nclass QueryModelRequiredListStr(BaseModel):\n    p: list[str]\n\n\n@app.get(\"/model-required-list-str\")\ndef read_model_required_list_str(p: Annotated[QueryModelRequiredListStr, Query()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\n                    \"title\": \"P\",\n                    \"type\": \"array\",\n                    \"items\": {\"type\": \"string\"},\n                },\n                \"name\": \"p\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"p\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-str\", \"/model-required-list-str\"],\n)\ndef test_required_list_str(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello&p=world\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.get(\"/required-list-alias\")\nasync def read_required_list_alias(p: Annotated[list[str], Query(alias=\"p_alias\")]):\n    return {\"p\": p}\n\n\nclass QueryModelRequiredListAlias(BaseModel):\n    p: list[str] = Field(alias=\"p_alias\")\n\n\n@app.get(\"/model-required-list-alias\")\nasync def read_model_required_list_alias(\n    p: Annotated[QueryModelRequiredListAlias, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-alias\", \"/model-required-list-alias\"],\n)\ndef test_required_list_str_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\n                    \"title\": \"P Alias\",\n                    \"type\": \"array\",\n                    \"items\": {\"type\": \"string\"},\n                },\n                \"name\": \"p_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-alias\", \"/model-required-list-alias\"],\n)\ndef test_required_list_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias\",\n        \"/model-required-list-alias\",\n    ],\n)\ndef test_required_list_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello&p=world\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": [\"hello\", \"world\"]}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias\",\n        \"/model-required-list-alias\",\n    ],\n)\ndef test_required_list_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_alias=hello&p_alias=world\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.get(\"/required-list-validation-alias\")\ndef read_required_list_validation_alias(\n    p: Annotated[list[str], Query(validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass QueryModelRequiredListValidationAlias(BaseModel):\n    p: list[str] = Field(validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-required-list-validation-alias\")\nasync def read_model_required_list_validation_alias(\n    p: Annotated[QueryModelRequiredListValidationAlias, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-validation-alias\", \"/model-required-list-validation-alias\"],\n)\ndef test_required_list_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\n                    \"title\": \"P Val Alias\",\n                    \"type\": \"array\",\n                    \"items\": {\"type\": \"string\"},\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-validation-alias\",\n        \"/model-required-list-validation-alias\",\n    ],\n)\ndef test_required_list_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"query\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-validation-alias\",\n        \"/model-required-list-validation-alias\",\n    ],\n)\ndef test_required_list_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello&p=world\")\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": [\"hello\", \"world\"]}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-list-validation-alias\", \"/model-required-list-validation-alias\"],\n)\ndef test_required_list_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_val_alias=hello&p_val_alias=world\")\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.get(\"/required-list-alias-and-validation-alias\")\ndef read_required_list_alias_and_validation_alias(\n    p: Annotated[list[str], Query(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass QueryModelRequiredListAliasAndValidationAlias(BaseModel):\n    p: list[str] = Field(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-required-list-alias-and-validation-alias\")\ndef read_model_required_list_alias_and_validation_alias(\n    p: Annotated[QueryModelRequiredListAliasAndValidationAlias, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\n                    \"title\": \"P Val Alias\",\n                    \"type\": \"array\",\n                    \"items\": {\"type\": \"string\"},\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"query\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello&p=world\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"query\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    {\n                        \"p\": [\n                            \"hello\",\n                            \"world\",\n                        ]\n                    },\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_alias=hello&p_alias=world\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    {\"p_alias\": [\"hello\", \"world\"]},\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-list-alias-and-validation-alias\",\n        \"/model-required-list-alias-and-validation-alias\",\n    ],\n)\ndef test_required_list_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_val_alias=hello&p_val_alias=world\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n"
  },
  {
    "path": "tests/test_request_params/test_query/test_optional_list.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, Query\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.get(\"/optional-list-str\")\nasync def read_optional_list_str(\n    p: Annotated[list[str] | None, Query()] = None,\n):\n    return {\"p\": p}\n\n\nclass QueryModelOptionalListStr(BaseModel):\n    p: list[str] | None = None\n\n\n@app.get(\"/model-optional-list-str\")\nasync def read_model_optional_list_str(\n    p: Annotated[QueryModelOptionalListStr, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [\n                        {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                        {\"type\": \"null\"},\n                    ],\n                    \"title\": \"P\",\n                },\n                \"name\": \"p\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-str\", \"/model-optional-list-str\"],\n)\ndef test_optional_list_str(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello&p=world\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.get(\"/optional-list-alias\")\nasync def read_optional_list_alias(\n    p: Annotated[list[str] | None, Query(alias=\"p_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass QueryModelOptionalListAlias(BaseModel):\n    p: list[str] | None = Field(None, alias=\"p_alias\")\n\n\n@app.get(\"/model-optional-list-alias\")\nasync def read_model_optional_list_alias(\n    p: Annotated[QueryModelOptionalListAlias, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_str_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [\n                        {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                        {\"type\": \"null\"},\n                    ],\n                    \"title\": \"P Alias\",\n                },\n                \"name\": \"p_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-alias\", \"/model-optional-list-alias\"],\n)\ndef test_optional_list_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello&p=world\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias\",\n        \"/model-optional-list-alias\",\n    ],\n)\ndef test_optional_list_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_alias=hello&p_alias=world\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.get(\"/optional-list-validation-alias\")\ndef read_optional_list_validation_alias(\n    p: Annotated[list[str] | None, Query(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass QueryModelOptionalListValidationAlias(BaseModel):\n    p: list[str] | None = Field(None, validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-optional-list-validation-alias\")\ndef read_model_optional_list_validation_alias(\n    p: Annotated[QueryModelOptionalListValidationAlias, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [\n                        {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                        {\"type\": \"null\"},\n                    ],\n                    \"title\": \"P Val Alias\",\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-validation-alias\",\n        \"/model-optional-list-validation-alias\",\n    ],\n)\ndef test_optional_list_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello&p=world\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-list-validation-alias\", \"/model-optional-list-validation-alias\"],\n)\ndef test_optional_list_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_val_alias=hello&p_val_alias=world\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": [\"hello\", \"world\"]}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.get(\"/optional-list-alias-and-validation-alias\")\ndef read_optional_list_alias_and_validation_alias(\n    p: Annotated[\n        list[str] | None, Query(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"p\": p}\n\n\nclass QueryModelOptionalListAliasAndValidationAlias(BaseModel):\n    p: list[str] | None = Field(None, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-optional-list-alias-and-validation-alias\")\ndef read_model_optional_list_alias_and_validation_alias(\n    p: Annotated[QueryModelOptionalListAliasAndValidationAlias, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [\n                        {\"items\": {\"type\": \"string\"}, \"type\": \"array\"},\n                        {\"type\": \"null\"},\n                    ],\n                    \"title\": \"P Val Alias\",\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello&p=world\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_alias=hello&p_alias=world\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-list-alias-and-validation-alias\",\n        \"/model-optional-list-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_list_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_val_alias=hello&p_val_alias=world\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"p\": [\n            \"hello\",\n            \"world\",\n        ]\n    }\n"
  },
  {
    "path": "tests/test_request_params/test_query/test_optional_str.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI, Query\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.get(\"/optional-str\")\nasync def read_optional_str(p: str | None = None):\n    return {\"p\": p}\n\n\nclass QueryModelOptionalStr(BaseModel):\n    p: str | None = None\n\n\n@app.get(\"/model-optional-str\")\nasync def read_model_optional_str(p: Annotated[QueryModelOptionalStr, Query()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P\",\n                },\n                \"name\": \"p\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-str\", \"/model-optional-str\"],\n)\ndef test_optional_str(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.get(\"/optional-alias\")\nasync def read_optional_alias(\n    p: Annotated[str | None, Query(alias=\"p_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass QueryModelOptionalAlias(BaseModel):\n    p: str | None = Field(None, alias=\"p_alias\")\n\n\n@app.get(\"/model-optional-alias\")\nasync def read_model_optional_alias(p: Annotated[QueryModelOptionalAlias, Query()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_str_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P Alias\",\n                },\n                \"name\": \"p_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-alias\", \"/model-optional-alias\"],\n)\ndef test_optional_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias\",\n        \"/model-optional-alias\",\n    ],\n)\ndef test_optional_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_alias=hello\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.get(\"/optional-validation-alias\")\ndef read_optional_validation_alias(\n    p: Annotated[str | None, Query(validation_alias=\"p_val_alias\")] = None,\n):\n    return {\"p\": p}\n\n\nclass QueryModelOptionalValidationAlias(BaseModel):\n    p: str | None = Field(None, validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-optional-validation-alias\")\ndef read_model_optional_validation_alias(\n    p: Annotated[QueryModelOptionalValidationAlias, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-validation-alias\", \"/model-optional-validation-alias\"],\n)\ndef test_optional_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P Val Alias\",\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/optional-validation-alias\", \"/model-optional-validation-alias\"],\n)\ndef test_optional_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-validation-alias\",\n        \"/model-optional-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-validation-alias\",\n        \"/model-optional-validation-alias\",\n    ],\n)\ndef test_optional_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_val_alias=hello\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.get(\"/optional-alias-and-validation-alias\")\ndef read_optional_alias_and_validation_alias(\n    p: Annotated[\n        str | None, Query(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n    ] = None,\n):\n    return {\"p\": p}\n\n\nclass QueryModelOptionalAliasAndValidationAlias(BaseModel):\n    p: str | None = Field(None, alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-optional-alias-and-validation-alias\")\ndef read_model_optional_alias_and_validation_alias(\n    p: Annotated[QueryModelOptionalAliasAndValidationAlias, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": False,\n                \"schema\": {\n                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                    \"title\": \"P Val Alias\",\n                },\n                \"name\": \"p_val_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_alias=hello\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": None}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/optional-alias-and-validation-alias\",\n        \"/model-optional-alias-and-validation-alias\",\n    ],\n)\ndef test_optional_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_val_alias=hello\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_request_params/test_query/test_required_str.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi import FastAPI, Query\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n# =====================================================================================\n# Without aliases\n\n\n@app.get(\"/required-str\")\nasync def read_required_str(p: str):\n    return {\"p\": p}\n\n\nclass QueryModelRequiredStr(BaseModel):\n    p: str\n\n\n@app.get(\"/model-required-str\")\nasync def read_model_required_str(p: Annotated[QueryModelRequiredStr, Query()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P\", \"type\": \"string\"},\n                \"name\": \"p\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"p\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-str\", \"/model-required-str\"],\n)\ndef test_required_str(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello\")\n    assert response.status_code == 200\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias\n\n\n@app.get(\"/required-alias\")\nasync def read_required_alias(p: Annotated[str, Query(alias=\"p_alias\")]):\n    return {\"p\": p}\n\n\nclass QueryModelRequiredAlias(BaseModel):\n    p: str = Field(alias=\"p_alias\")\n\n\n@app.get(\"/model-required-alias\")\nasync def read_model_required_alias(p: Annotated[QueryModelRequiredAlias, Query()]):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_str_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P Alias\", \"type\": \"string\"},\n                \"name\": \"p_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-alias\", \"/model-required-alias\"],\n)\ndef test_required_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias\",\n        \"/model-required-alias\",\n    ],\n)\ndef test_required_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"p_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    {\"p\": \"hello\"},\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias\",\n        \"/model-required-alias\",\n    ],\n)\ndef test_required_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_alias=hello\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Validation alias\n\n\n@app.get(\"/required-validation-alias\")\ndef read_required_validation_alias(\n    p: Annotated[str, Query(validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass QueryModelRequiredValidationAlias(BaseModel):\n    p: str = Field(validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-required-validation-alias\")\ndef read_model_required_validation_alias(\n    p: Annotated[QueryModelRequiredValidationAlias, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\"/required-validation-alias\", \"/model-required-validation-alias\"],\n)\ndef test_required_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P Val Alias\", \"type\": \"string\"},\n                \"name\": \"p_val_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"query\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello\")\n    assert response.status_code == 422, response.text\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {\"p\": \"hello\"}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-validation-alias\",\n        \"/model-required-validation-alias\",\n    ],\n)\ndef test_required_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_val_alias=hello\")\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": \"hello\"}\n\n\n# =====================================================================================\n# Alias and validation alias\n\n\n@app.get(\"/required-alias-and-validation-alias\")\ndef read_required_alias_and_validation_alias(\n    p: Annotated[str, Query(alias=\"p_alias\", validation_alias=\"p_val_alias\")],\n):\n    return {\"p\": p}\n\n\nclass QueryModelRequiredAliasAndValidationAlias(BaseModel):\n    p: str = Field(alias=\"p_alias\", validation_alias=\"p_val_alias\")\n\n\n@app.get(\"/model-required-alias-and-validation-alias\")\ndef read_model_required_alias_and_validation_alias(\n    p: Annotated[QueryModelRequiredAliasAndValidationAlias, Query()],\n):\n    return {\"p\": p.p}\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_schema(path: str):\n    assert app.openapi()[\"paths\"][path][\"get\"][\"parameters\"] == snapshot(\n        [\n            {\n                \"required\": True,\n                \"schema\": {\"title\": \"P Val Alias\", \"type\": \"string\"},\n                \"name\": \"p_val_alias\",\n                \"in\": \"query\",\n            }\n        ]\n    )\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_missing(path: str):\n    client = TestClient(app)\n    response = client.get(path)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"query\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(None, {}),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_name(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p=hello\")\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\n                    \"query\",\n                    \"p_val_alias\",\n                ],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    {\"p\": \"hello\"},\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_alias=hello\")\n    assert response.status_code == 422\n\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"p_val_alias\"],\n                \"msg\": \"Field required\",\n                \"input\": IsOneOf(\n                    None,\n                    {\"p_alias\": \"hello\"},\n                ),\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/required-alias-and-validation-alias\",\n        \"/model-required-alias-and-validation-alias\",\n    ],\n)\ndef test_required_alias_and_validation_alias_by_validation_alias(path: str):\n    client = TestClient(app)\n    response = client.get(f\"{path}?p_val_alias=hello\")\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\"p\": \"hello\"}\n"
  },
  {
    "path": "tests/test_required_noneable.py",
    "content": "from fastapi import Body, FastAPI, Query\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.get(\"/query\")\ndef read_query(q: str | None):\n    return q\n\n\n@app.get(\"/explicit-query\")\ndef read_explicit_query(q: str | None = Query()):\n    return q\n\n\n@app.post(\"/body-embed\")\ndef send_body_embed(b: str | None = Body(embed=True)):\n    return b\n\n\nclient = TestClient(app)\n\n\ndef test_required_nonable_query_invalid():\n    response = client.get(\"/query\")\n    assert response.status_code == 422\n\n\ndef test_required_noneable_query_value():\n    response = client.get(\"/query\", params={\"q\": \"foo\"})\n    assert response.status_code == 200\n    assert response.json() == \"foo\"\n\n\ndef test_required_nonable_explicit_query_invalid():\n    response = client.get(\"/explicit-query\")\n    assert response.status_code == 422\n\n\ndef test_required_nonable_explicit_query_value():\n    response = client.get(\"/explicit-query\", params={\"q\": \"foo\"})\n    assert response.status_code == 200\n    assert response.json() == \"foo\"\n\n\ndef test_required_nonable_body_embed_no_content():\n    response = client.post(\"/body-embed\")\n    assert response.status_code == 422\n\n\ndef test_required_nonable_body_embed_invalid():\n    response = client.post(\"/body-embed\", json={\"invalid\": \"invalid\"})\n    assert response.status_code == 422\n\n\ndef test_required_noneable_body_embed_value():\n    response = client.post(\"/body-embed\", json={\"b\": \"foo\"})\n    assert response.status_code == 200\n    assert response.json() == \"foo\"\n"
  },
  {
    "path": "tests/test_response_by_alias.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, ConfigDict, Field\n\napp = FastAPI()\n\n\nclass Model(BaseModel):\n    name: str = Field(alias=\"alias\")\n\n\nclass ModelNoAlias(BaseModel):\n    name: str\n\n    model_config = ConfigDict(\n        json_schema_extra={\n            \"description\": (\n                \"response_model_by_alias=False is basically a quick hack, to support \"\n                \"proper OpenAPI use another model with the correct field names\"\n            )\n        }\n    )\n\n\n@app.get(\"/dict\", response_model=Model, response_model_by_alias=False)\ndef read_dict():\n    return {\"alias\": \"Foo\"}\n\n\n@app.get(\"/model\", response_model=Model, response_model_by_alias=False)\ndef read_model():\n    return Model(alias=\"Foo\")\n\n\n@app.get(\"/list\", response_model=list[Model], response_model_by_alias=False)\ndef read_list():\n    return [{\"alias\": \"Foo\"}, {\"alias\": \"Bar\"}]\n\n\n@app.get(\"/by-alias/dict\", response_model=Model)\ndef by_alias_dict():\n    return {\"alias\": \"Foo\"}\n\n\n@app.get(\"/by-alias/model\", response_model=Model)\ndef by_alias_model():\n    return Model(alias=\"Foo\")\n\n\n@app.get(\"/by-alias/list\", response_model=list[Model])\ndef by_alias_list():\n    return [{\"alias\": \"Foo\"}, {\"alias\": \"Bar\"}]\n\n\n@app.get(\"/no-alias/dict\", response_model=ModelNoAlias)\ndef no_alias_dict():\n    return {\"name\": \"Foo\"}\n\n\n@app.get(\"/no-alias/model\", response_model=ModelNoAlias)\ndef no_alias_model():\n    return ModelNoAlias(name=\"Foo\")\n\n\n@app.get(\"/no-alias/list\", response_model=list[ModelNoAlias])\ndef no_alias_list():\n    return [{\"name\": \"Foo\"}, {\"name\": \"Bar\"}]\n\n\nclient = TestClient(app)\n\n\ndef test_read_dict():\n    response = client.get(\"/dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\"}\n\n\ndef test_read_model():\n    response = client.get(\"/model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\"}\n\n\ndef test_read_list():\n    response = client.get(\"/list\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"name\": \"Foo\"},\n        {\"name\": \"Bar\"},\n    ]\n\n\ndef test_read_dict_by_alias():\n    response = client.get(\"/by-alias/dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"alias\": \"Foo\"}\n\n\ndef test_read_model_by_alias():\n    response = client.get(\"/by-alias/model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"alias\": \"Foo\"}\n\n\ndef test_read_list_by_alias():\n    response = client.get(\"/by-alias/list\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"alias\": \"Foo\"},\n        {\"alias\": \"Bar\"},\n    ]\n\n\ndef test_read_dict_no_alias():\n    response = client.get(\"/no-alias/dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\"}\n\n\ndef test_read_model_no_alias():\n    response = client.get(\"/no-alias/model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\"}\n\n\ndef test_read_list_no_alias():\n    response = client.get(\"/no-alias/list\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"name\": \"Foo\"},\n        {\"name\": \"Bar\"},\n    ]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/dict\": {\n                    \"get\": {\n                        \"summary\": \"Read Dict\",\n                        \"operationId\": \"read_dict_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Model\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/model\": {\n                    \"get\": {\n                        \"summary\": \"Read Model\",\n                        \"operationId\": \"read_model_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Model\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/list\": {\n                    \"get\": {\n                        \"summary\": \"Read List\",\n                        \"operationId\": \"read_list_list_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read List List Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Model\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/by-alias/dict\": {\n                    \"get\": {\n                        \"summary\": \"By Alias Dict\",\n                        \"operationId\": \"by_alias_dict_by_alias_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Model\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/by-alias/model\": {\n                    \"get\": {\n                        \"summary\": \"By Alias Model\",\n                        \"operationId\": \"by_alias_model_by_alias_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Model\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/by-alias/list\": {\n                    \"get\": {\n                        \"summary\": \"By Alias List\",\n                        \"operationId\": \"by_alias_list_by_alias_list_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response By Alias List By Alias List Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Model\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no-alias/dict\": {\n                    \"get\": {\n                        \"summary\": \"No Alias Dict\",\n                        \"operationId\": \"no_alias_dict_no_alias_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ModelNoAlias\"\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no-alias/model\": {\n                    \"get\": {\n                        \"summary\": \"No Alias Model\",\n                        \"operationId\": \"no_alias_model_no_alias_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ModelNoAlias\"\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no-alias/list\": {\n                    \"get\": {\n                        \"summary\": \"No Alias List\",\n                        \"operationId\": \"no_alias_list_no_alias_list_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response No Alias List No Alias List Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/ModelNoAlias\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Model\": {\n                        \"title\": \"Model\",\n                        \"required\": [\"alias\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"alias\": {\"title\": \"Alias\", \"type\": \"string\"}},\n                    },\n                    \"ModelNoAlias\": {\n                        \"title\": \"ModelNoAlias\",\n                        \"required\": [\"name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"name\": {\"title\": \"Name\", \"type\": \"string\"}},\n                        \"description\": \"response_model_by_alias=False is basically a quick hack, to support proper OpenAPI use another model with the correct field names\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_response_change_status_code.py",
    "content": "from fastapi import Depends, FastAPI, Response\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\nasync def response_status_setter(response: Response):\n    response.status_code = 201\n\n\nasync def parent_dep(result=Depends(response_status_setter)):\n    return result\n\n\n@app.get(\"/\", dependencies=[Depends(parent_dep)])\nasync def get_main():\n    return {\"msg\": \"Hello World\"}\n\n\nclient = TestClient(app)\n\n\ndef test_dependency_set_status_code():\n    response = client.get(\"/\")\n    assert response.status_code == 201, response.text\n    assert response.json() == {\"msg\": \"Hello World\"}\n"
  },
  {
    "path": "tests/test_response_class_no_mediatype.py",
    "content": "from fastapi import FastAPI, Response\nfrom fastapi.responses import JSONResponse\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass JsonApiResponse(JSONResponse):\n    media_type = \"application/vnd.api+json\"\n\n\nclass Error(BaseModel):\n    status: str\n    title: str\n\n\nclass JsonApiError(BaseModel):\n    errors: list[Error]\n\n\n@app.get(\n    \"/a\",\n    response_class=Response,\n    responses={500: {\"description\": \"Error\", \"model\": JsonApiError}},\n)\nasync def a():\n    pass  # pragma: no cover\n\n\n@app.get(\"/b\", responses={500: {\"description\": \"Error\", \"model\": Error}})\nasync def b():\n    pass  # pragma: no cover\n\n\nclient = TestClient(app)\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/a\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"500\": {\n                                \"description\": \"Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/JsonApiError\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"200\": {\"description\": \"Successful Response\"},\n                        },\n                        \"summary\": \"A\",\n                        \"operationId\": \"a_a_get\",\n                    }\n                },\n                \"/b\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"500\": {\n                                \"description\": \"Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Error\"}\n                                    }\n                                },\n                            },\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                        },\n                        \"summary\": \"B\",\n                        \"operationId\": \"b_b_get\",\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Error\": {\n                        \"title\": \"Error\",\n                        \"required\": [\"status\", \"title\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"status\": {\"title\": \"Status\", \"type\": \"string\"},\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                        },\n                    },\n                    \"JsonApiError\": {\n                        \"title\": \"JsonApiError\",\n                        \"required\": [\"errors\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"errors\": {\n                                \"title\": \"Errors\",\n                                \"type\": \"array\",\n                                \"items\": {\"$ref\": \"#/components/schemas/Error\"},\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_response_code_no_body.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.responses import JSONResponse\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass JsonApiResponse(JSONResponse):\n    media_type = \"application/vnd.api+json\"\n\n\nclass Error(BaseModel):\n    status: str\n    title: str\n\n\nclass JsonApiError(BaseModel):\n    errors: list[Error]\n\n\n@app.get(\n    \"/a\",\n    status_code=204,\n    response_class=JsonApiResponse,\n    responses={500: {\"description\": \"Error\", \"model\": JsonApiError}},\n)\nasync def a():\n    pass\n\n\n@app.get(\"/b\", responses={204: {\"description\": \"No Content\"}})\nasync def b():\n    pass  # pragma: no cover\n\n\nclient = TestClient(app)\n\n\ndef test_get_response():\n    response = client.get(\"/a\")\n    assert response.status_code == 204, response.text\n    assert \"content-length\" not in response.headers\n    assert response.content == b\"\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/a\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"500\": {\n                                \"description\": \"Error\",\n                                \"content\": {\n                                    \"application/vnd.api+json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/JsonApiError\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"204\": {\"description\": \"Successful Response\"},\n                        },\n                        \"summary\": \"A\",\n                        \"operationId\": \"a_a_get\",\n                    }\n                },\n                \"/b\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"204\": {\"description\": \"No Content\"},\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                        },\n                        \"summary\": \"B\",\n                        \"operationId\": \"b_b_get\",\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Error\": {\n                        \"title\": \"Error\",\n                        \"required\": [\"status\", \"title\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"status\": {\"title\": \"Status\", \"type\": \"string\"},\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                        },\n                    },\n                    \"JsonApiError\": {\n                        \"title\": \"JsonApiError\",\n                        \"required\": [\"errors\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"errors\": {\n                                \"title\": \"Errors\",\n                                \"type\": \"array\",\n                                \"items\": {\"$ref\": \"#/components/schemas/Error\"},\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_response_dependency.py",
    "content": "\"\"\"Test using special types (Response, Request, BackgroundTasks) as dependency annotations.\n\nThese tests verify that special FastAPI types can be used with Depends() annotations\nand that the dependency injection system properly handles them.\n\"\"\"\n\nfrom typing import Annotated\n\nfrom fastapi import BackgroundTasks, Depends, FastAPI, Request, Response\nfrom fastapi.responses import JSONResponse\nfrom fastapi.testclient import TestClient\n\n\ndef test_response_with_depends_annotated():\n    \"\"\"Response type hint should work with Annotated[Response, Depends(...)].\"\"\"\n    app = FastAPI()\n\n    def modify_response(response: Response) -> Response:\n        response.headers[\"X-Custom\"] = \"modified\"\n        return response\n\n    @app.get(\"/\")\n    def endpoint(response: Annotated[Response, Depends(modify_response)]):\n        return {\"status\": \"ok\"}\n\n    client = TestClient(app)\n    resp = client.get(\"/\")\n\n    assert resp.status_code == 200\n    assert resp.json() == {\"status\": \"ok\"}\n    assert resp.headers.get(\"X-Custom\") == \"modified\"\n\n\ndef test_response_with_depends_default():\n    \"\"\"Response type hint should work with Response = Depends(...).\"\"\"\n    app = FastAPI()\n\n    def modify_response(response: Response) -> Response:\n        response.headers[\"X-Custom\"] = \"modified\"\n        return response\n\n    @app.get(\"/\")\n    def endpoint(response: Response = Depends(modify_response)):\n        return {\"status\": \"ok\"}\n\n    client = TestClient(app)\n    resp = client.get(\"/\")\n\n    assert resp.status_code == 200\n    assert resp.json() == {\"status\": \"ok\"}\n    assert resp.headers.get(\"X-Custom\") == \"modified\"\n\n\ndef test_response_without_depends():\n    \"\"\"Regular Response injection should still work.\"\"\"\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def endpoint(response: Response):\n        response.headers[\"X-Direct\"] = \"set\"\n        return {\"status\": \"ok\"}\n\n    client = TestClient(app)\n    resp = client.get(\"/\")\n\n    assert resp.status_code == 200\n    assert resp.json() == {\"status\": \"ok\"}\n    assert resp.headers.get(\"X-Direct\") == \"set\"\n\n\ndef test_response_dependency_chain():\n    \"\"\"Response dependency should work in a chain of dependencies.\"\"\"\n    app = FastAPI()\n\n    def first_modifier(response: Response) -> Response:\n        response.headers[\"X-First\"] = \"1\"\n        return response\n\n    def second_modifier(\n        response: Annotated[Response, Depends(first_modifier)],\n    ) -> Response:\n        response.headers[\"X-Second\"] = \"2\"\n        return response\n\n    @app.get(\"/\")\n    def endpoint(response: Annotated[Response, Depends(second_modifier)]):\n        return {\"status\": \"ok\"}\n\n    client = TestClient(app)\n    resp = client.get(\"/\")\n\n    assert resp.status_code == 200\n    assert resp.headers.get(\"X-First\") == \"1\"\n    assert resp.headers.get(\"X-Second\") == \"2\"\n\n\ndef test_response_dependency_returns_different_response_instance():\n    \"\"\"Dependency that returns a different Response instance should work.\n\n    When a dependency returns a new Response object (e.g., JSONResponse) instead\n    of modifying the injected one, the returned response should be used and any\n    modifications to it in the endpoint should be preserved.\n    \"\"\"\n    app = FastAPI()\n\n    def default_response() -> Response:\n        response = JSONResponse(content={\"status\": \"ok\"})\n        response.headers[\"X-Custom\"] = \"initial\"\n        return response\n\n    @app.get(\"/\")\n    def endpoint(response: Annotated[Response, Depends(default_response)]):\n        response.headers[\"X-Custom\"] = \"modified\"\n        return response\n\n    client = TestClient(app)\n    resp = client.get(\"/\")\n\n    assert resp.status_code == 200\n    assert resp.json() == {\"status\": \"ok\"}\n    assert resp.headers.get(\"X-Custom\") == \"modified\"\n\n\n# Tests for Request type hint with Depends\ndef test_request_with_depends_annotated():\n    \"\"\"Request type hint should work in dependency chain.\"\"\"\n    app = FastAPI()\n\n    def extract_request_info(request: Request) -> dict:\n        return {\n            \"path\": request.url.path,\n            \"user_agent\": request.headers.get(\"user-agent\", \"unknown\"),\n        }\n\n    @app.get(\"/\")\n    def endpoint(\n        info: Annotated[dict, Depends(extract_request_info)],\n    ):\n        return info\n\n    client = TestClient(app)\n    resp = client.get(\"/\", headers={\"user-agent\": \"test-agent\"})\n\n    assert resp.status_code == 200\n    assert resp.json() == {\"path\": \"/\", \"user_agent\": \"test-agent\"}\n\n\n# Tests for BackgroundTasks type hint with Depends\ndef test_background_tasks_with_depends_annotated():\n    \"\"\"BackgroundTasks type hint should work with Annotated[BackgroundTasks, Depends(...)].\"\"\"\n    app = FastAPI()\n    task_results = []\n\n    def background_task(message: str):\n        task_results.append(message)\n\n    def add_background_task(background_tasks: BackgroundTasks) -> BackgroundTasks:\n        background_tasks.add_task(background_task, \"from dependency\")\n        return background_tasks\n\n    @app.get(\"/\")\n    def endpoint(\n        background_tasks: Annotated[BackgroundTasks, Depends(add_background_task)],\n    ):\n        background_tasks.add_task(background_task, \"from endpoint\")\n        return {\"status\": \"ok\"}\n\n    client = TestClient(app)\n    resp = client.get(\"/\")\n\n    assert resp.status_code == 200\n    assert \"from dependency\" in task_results\n    assert \"from endpoint\" in task_results\n"
  },
  {
    "path": "tests/test_response_model_as_return_annotation.py",
    "content": "import pytest\nfrom fastapi import FastAPI\nfrom fastapi.exceptions import FastAPIError, ResponseValidationError\nfrom fastapi.responses import JSONResponse, Response\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\n\nclass BaseUser(BaseModel):\n    name: str\n\n\nclass User(BaseUser):\n    surname: str\n\n\nclass DBUser(User):\n    password_hash: str\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\napp = FastAPI()\n\n\n@app.get(\"/no_response_model-no_annotation-return_model\")\ndef no_response_model_no_annotation_return_model():\n    return User(name=\"John\", surname=\"Doe\")\n\n\n@app.get(\"/no_response_model-no_annotation-return_dict\")\ndef no_response_model_no_annotation_return_dict():\n    return {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\n@app.get(\"/response_model-no_annotation-return_same_model\", response_model=User)\ndef response_model_no_annotation_return_same_model():\n    return User(name=\"John\", surname=\"Doe\")\n\n\n@app.get(\"/response_model-no_annotation-return_exact_dict\", response_model=User)\ndef response_model_no_annotation_return_exact_dict():\n    return {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\n@app.get(\"/response_model-no_annotation-return_invalid_dict\", response_model=User)\ndef response_model_no_annotation_return_invalid_dict():\n    return {\"name\": \"John\"}\n\n\n@app.get(\"/response_model-no_annotation-return_invalid_model\", response_model=User)\ndef response_model_no_annotation_return_invalid_model():\n    return Item(name=\"Foo\", price=42.0)\n\n\n@app.get(\n    \"/response_model-no_annotation-return_dict_with_extra_data\", response_model=User\n)\ndef response_model_no_annotation_return_dict_with_extra_data():\n    return {\"name\": \"John\", \"surname\": \"Doe\", \"password_hash\": \"secret\"}\n\n\n@app.get(\n    \"/response_model-no_annotation-return_submodel_with_extra_data\", response_model=User\n)\ndef response_model_no_annotation_return_submodel_with_extra_data():\n    return DBUser(name=\"John\", surname=\"Doe\", password_hash=\"secret\")\n\n\n@app.get(\"/no_response_model-annotation-return_same_model\")\ndef no_response_model_annotation_return_same_model() -> User:\n    return User(name=\"John\", surname=\"Doe\")\n\n\n@app.get(\"/no_response_model-annotation-return_exact_dict\")\ndef no_response_model_annotation_return_exact_dict() -> User:\n    return {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\n@app.get(\"/no_response_model-annotation-return_invalid_dict\")\ndef no_response_model_annotation_return_invalid_dict() -> User:\n    return {\"name\": \"John\"}\n\n\n@app.get(\"/no_response_model-annotation-return_invalid_model\")\ndef no_response_model_annotation_return_invalid_model() -> User:\n    return Item(name=\"Foo\", price=42.0)\n\n\n@app.get(\"/no_response_model-annotation-return_dict_with_extra_data\")\ndef no_response_model_annotation_return_dict_with_extra_data() -> User:\n    return {\"name\": \"John\", \"surname\": \"Doe\", \"password_hash\": \"secret\"}\n\n\n@app.get(\"/no_response_model-annotation-return_submodel_with_extra_data\")\ndef no_response_model_annotation_return_submodel_with_extra_data() -> User:\n    return DBUser(name=\"John\", surname=\"Doe\", password_hash=\"secret\")\n\n\n@app.get(\"/response_model_none-annotation-return_same_model\", response_model=None)\ndef response_model_none_annotation_return_same_model() -> User:\n    return User(name=\"John\", surname=\"Doe\")\n\n\n@app.get(\"/response_model_none-annotation-return_exact_dict\", response_model=None)\ndef response_model_none_annotation_return_exact_dict() -> User:\n    return {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\n@app.get(\"/response_model_none-annotation-return_invalid_dict\", response_model=None)\ndef response_model_none_annotation_return_invalid_dict() -> User:\n    return {\"name\": \"John\"}\n\n\n@app.get(\"/response_model_none-annotation-return_invalid_model\", response_model=None)\ndef response_model_none_annotation_return_invalid_model() -> User:\n    return Item(name=\"Foo\", price=42.0)\n\n\n@app.get(\n    \"/response_model_none-annotation-return_dict_with_extra_data\", response_model=None\n)\ndef response_model_none_annotation_return_dict_with_extra_data() -> User:\n    return {\"name\": \"John\", \"surname\": \"Doe\", \"password_hash\": \"secret\"}\n\n\n@app.get(\n    \"/response_model_none-annotation-return_submodel_with_extra_data\",\n    response_model=None,\n)\ndef response_model_none_annotation_return_submodel_with_extra_data() -> User:\n    return DBUser(name=\"John\", surname=\"Doe\", password_hash=\"secret\")\n\n\n@app.get(\n    \"/response_model_model1-annotation_model2-return_same_model\", response_model=User\n)\ndef response_model_model1_annotation_model2_return_same_model() -> Item:\n    return User(name=\"John\", surname=\"Doe\")\n\n\n@app.get(\n    \"/response_model_model1-annotation_model2-return_exact_dict\", response_model=User\n)\ndef response_model_model1_annotation_model2_return_exact_dict() -> Item:\n    return {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\n@app.get(\n    \"/response_model_model1-annotation_model2-return_invalid_dict\", response_model=User\n)\ndef response_model_model1_annotation_model2_return_invalid_dict() -> Item:\n    return {\"name\": \"John\"}\n\n\n@app.get(\n    \"/response_model_model1-annotation_model2-return_invalid_model\", response_model=User\n)\ndef response_model_model1_annotation_model2_return_invalid_model() -> Item:\n    return Item(name=\"Foo\", price=42.0)\n\n\n@app.get(\n    \"/response_model_model1-annotation_model2-return_dict_with_extra_data\",\n    response_model=User,\n)\ndef response_model_model1_annotation_model2_return_dict_with_extra_data() -> Item:\n    return {\"name\": \"John\", \"surname\": \"Doe\", \"password_hash\": \"secret\"}\n\n\n@app.get(\n    \"/response_model_model1-annotation_model2-return_submodel_with_extra_data\",\n    response_model=User,\n)\ndef response_model_model1_annotation_model2_return_submodel_with_extra_data() -> Item:\n    return DBUser(name=\"John\", surname=\"Doe\", password_hash=\"secret\")\n\n\n@app.get(\n    \"/response_model_filtering_model-annotation_submodel-return_submodel\",\n    response_model=User,\n)\ndef response_model_filtering_model_annotation_submodel_return_submodel() -> DBUser:\n    return DBUser(name=\"John\", surname=\"Doe\", password_hash=\"secret\")\n\n\n@app.get(\"/response_model_list_of_model-no_annotation\", response_model=list[User])\ndef response_model_list_of_model_no_annotation():\n    return [\n        DBUser(name=\"John\", surname=\"Doe\", password_hash=\"secret\"),\n        DBUser(name=\"Jane\", surname=\"Does\", password_hash=\"secret2\"),\n    ]\n\n\n@app.get(\"/no_response_model-annotation_list_of_model\")\ndef no_response_model_annotation_list_of_model() -> list[User]:\n    return [\n        DBUser(name=\"John\", surname=\"Doe\", password_hash=\"secret\"),\n        DBUser(name=\"Jane\", surname=\"Does\", password_hash=\"secret2\"),\n    ]\n\n\n@app.get(\"/no_response_model-annotation_forward_ref_list_of_model\")\ndef no_response_model_annotation_forward_ref_list_of_model() -> \"list[User]\":\n    return [\n        DBUser(name=\"John\", surname=\"Doe\", password_hash=\"secret\"),\n        DBUser(name=\"Jane\", surname=\"Does\", password_hash=\"secret2\"),\n    ]\n\n\n@app.get(\n    \"/response_model_union-no_annotation-return_model1\",\n    response_model=User | Item,\n)\ndef response_model_union_no_annotation_return_model1():\n    return DBUser(name=\"John\", surname=\"Doe\", password_hash=\"secret\")\n\n\n@app.get(\n    \"/response_model_union-no_annotation-return_model2\",\n    response_model=User | Item,\n)\ndef response_model_union_no_annotation_return_model2():\n    return Item(name=\"Foo\", price=42.0)\n\n\n@app.get(\"/no_response_model-annotation_union-return_model1\")\ndef no_response_model_annotation_union_return_model1() -> User | Item:\n    return DBUser(name=\"John\", surname=\"Doe\", password_hash=\"secret\")\n\n\n@app.get(\"/no_response_model-annotation_union-return_model2\")\ndef no_response_model_annotation_union_return_model2() -> User | Item:\n    return Item(name=\"Foo\", price=42.0)\n\n\n@app.get(\"/no_response_model-annotation_response_class\")\ndef no_response_model_annotation_response_class() -> Response:\n    return Response(content=\"Foo\")\n\n\n@app.get(\"/no_response_model-annotation_json_response_class\")\ndef no_response_model_annotation_json_response_class() -> JSONResponse:\n    return JSONResponse(content={\"foo\": \"bar\"})\n\n\nclient = TestClient(app)\n\n\ndef test_no_response_model_no_annotation_return_model():\n    response = client.get(\"/no_response_model-no_annotation-return_model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_no_response_model_no_annotation_return_dict():\n    response = client.get(\"/no_response_model-no_annotation-return_dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_no_annotation_return_same_model():\n    response = client.get(\"/response_model-no_annotation-return_same_model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_no_annotation_return_exact_dict():\n    response = client.get(\"/response_model-no_annotation-return_exact_dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_no_annotation_return_invalid_dict():\n    with pytest.raises(ResponseValidationError) as excinfo:\n        client.get(\"/response_model-no_annotation-return_invalid_dict\")\n    assert \"missing\" in str(excinfo.value)\n\n\ndef test_response_model_no_annotation_return_invalid_model():\n    with pytest.raises(ResponseValidationError) as excinfo:\n        client.get(\"/response_model-no_annotation-return_invalid_model\")\n    assert \"missing\" in str(excinfo.value)\n\n\ndef test_response_model_no_annotation_return_dict_with_extra_data():\n    response = client.get(\"/response_model-no_annotation-return_dict_with_extra_data\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_no_annotation_return_submodel_with_extra_data():\n    response = client.get(\n        \"/response_model-no_annotation-return_submodel_with_extra_data\"\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_no_response_model_annotation_return_same_model():\n    response = client.get(\"/no_response_model-annotation-return_same_model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_no_response_model_annotation_return_exact_dict():\n    response = client.get(\"/no_response_model-annotation-return_exact_dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_no_response_model_annotation_return_invalid_dict():\n    with pytest.raises(ResponseValidationError) as excinfo:\n        client.get(\"/no_response_model-annotation-return_invalid_dict\")\n    assert \"missing\" in str(excinfo.value)\n\n\ndef test_no_response_model_annotation_return_invalid_model():\n    with pytest.raises(ResponseValidationError) as excinfo:\n        client.get(\"/no_response_model-annotation-return_invalid_model\")\n    assert \"missing\" in str(excinfo.value)\n\n\ndef test_no_response_model_annotation_return_dict_with_extra_data():\n    response = client.get(\"/no_response_model-annotation-return_dict_with_extra_data\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_no_response_model_annotation_return_submodel_with_extra_data():\n    response = client.get(\n        \"/no_response_model-annotation-return_submodel_with_extra_data\"\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_none_annotation_return_same_model():\n    response = client.get(\"/response_model_none-annotation-return_same_model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_none_annotation_return_exact_dict():\n    response = client.get(\"/response_model_none-annotation-return_exact_dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_none_annotation_return_invalid_dict():\n    response = client.get(\"/response_model_none-annotation-return_invalid_dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\"}\n\n\ndef test_response_model_none_annotation_return_invalid_model():\n    response = client.get(\"/response_model_none-annotation-return_invalid_model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\", \"price\": 42.0}\n\n\ndef test_response_model_none_annotation_return_dict_with_extra_data():\n    response = client.get(\"/response_model_none-annotation-return_dict_with_extra_data\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"John\",\n        \"surname\": \"Doe\",\n        \"password_hash\": \"secret\",\n    }\n\n\ndef test_response_model_none_annotation_return_submodel_with_extra_data():\n    response = client.get(\n        \"/response_model_none-annotation-return_submodel_with_extra_data\"\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"John\",\n        \"surname\": \"Doe\",\n        \"password_hash\": \"secret\",\n    }\n\n\ndef test_response_model_model1_annotation_model2_return_same_model():\n    response = client.get(\"/response_model_model1-annotation_model2-return_same_model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_model1_annotation_model2_return_exact_dict():\n    response = client.get(\"/response_model_model1-annotation_model2-return_exact_dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_model1_annotation_model2_return_invalid_dict():\n    with pytest.raises(ResponseValidationError) as excinfo:\n        client.get(\"/response_model_model1-annotation_model2-return_invalid_dict\")\n    assert \"missing\" in str(excinfo.value)\n\n\ndef test_response_model_model1_annotation_model2_return_invalid_model():\n    with pytest.raises(ResponseValidationError) as excinfo:\n        client.get(\"/response_model_model1-annotation_model2-return_invalid_model\")\n    assert \"missing\" in str(excinfo.value)\n\n\ndef test_response_model_model1_annotation_model2_return_dict_with_extra_data():\n    response = client.get(\n        \"/response_model_model1-annotation_model2-return_dict_with_extra_data\"\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_model1_annotation_model2_return_submodel_with_extra_data():\n    response = client.get(\n        \"/response_model_model1-annotation_model2-return_submodel_with_extra_data\"\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_filtering_model_annotation_submodel_return_submodel():\n    response = client.get(\n        \"/response_model_filtering_model-annotation_submodel-return_submodel\"\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_list_of_model_no_annotation():\n    response = client.get(\"/response_model_list_of_model-no_annotation\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"name\": \"John\", \"surname\": \"Doe\"},\n        {\"name\": \"Jane\", \"surname\": \"Does\"},\n    ]\n\n\ndef test_no_response_model_annotation_list_of_model():\n    response = client.get(\"/no_response_model-annotation_list_of_model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"name\": \"John\", \"surname\": \"Doe\"},\n        {\"name\": \"Jane\", \"surname\": \"Does\"},\n    ]\n\n\ndef test_no_response_model_annotation_forward_ref_list_of_model():\n    response = client.get(\"/no_response_model-annotation_forward_ref_list_of_model\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"name\": \"John\", \"surname\": \"Doe\"},\n        {\"name\": \"Jane\", \"surname\": \"Does\"},\n    ]\n\n\ndef test_response_model_union_no_annotation_return_model1():\n    response = client.get(\"/response_model_union-no_annotation-return_model1\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_response_model_union_no_annotation_return_model2():\n    response = client.get(\"/response_model_union-no_annotation-return_model2\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\", \"price\": 42.0}\n\n\ndef test_no_response_model_annotation_union_return_model1():\n    response = client.get(\"/no_response_model-annotation_union-return_model1\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"John\", \"surname\": \"Doe\"}\n\n\ndef test_no_response_model_annotation_union_return_model2():\n    response = client.get(\"/no_response_model-annotation_union-return_model2\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\", \"price\": 42.0}\n\n\ndef test_no_response_model_annotation_return_class():\n    response = client.get(\"/no_response_model-annotation_response_class\")\n    assert response.status_code == 200, response.text\n    assert response.text == \"Foo\"\n\n\ndef test_no_response_model_annotation_json_response_class():\n    response = client.get(\"/no_response_model-annotation_json_response_class\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"foo\": \"bar\"}\n\n\ndef test_invalid_response_model_field():\n    app = FastAPI()\n    with pytest.raises(FastAPIError) as e:\n\n        @app.get(\"/\")\n        def read_root() -> Response | None:\n            return Response(content=\"Foo\")  # pragma: no cover\n\n    assert \"valid Pydantic field type\" in e.value.args[0]\n    assert \"parameter response_model=None\" in e.value.args[0]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/no_response_model-no_annotation-return_model\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model No Annotation Return Model\",\n                        \"operationId\": \"no_response_model_no_annotation_return_model_no_response_model_no_annotation_return_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-no_annotation-return_dict\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model No Annotation Return Dict\",\n                        \"operationId\": \"no_response_model_no_annotation_return_dict_no_response_model_no_annotation_return_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/response_model-no_annotation-return_same_model\": {\n                    \"get\": {\n                        \"summary\": \"Response Model No Annotation Return Same Model\",\n                        \"operationId\": \"response_model_no_annotation_return_same_model_response_model_no_annotation_return_same_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model-no_annotation-return_exact_dict\": {\n                    \"get\": {\n                        \"summary\": \"Response Model No Annotation Return Exact Dict\",\n                        \"operationId\": \"response_model_no_annotation_return_exact_dict_response_model_no_annotation_return_exact_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model-no_annotation-return_invalid_dict\": {\n                    \"get\": {\n                        \"summary\": \"Response Model No Annotation Return Invalid Dict\",\n                        \"operationId\": \"response_model_no_annotation_return_invalid_dict_response_model_no_annotation_return_invalid_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model-no_annotation-return_invalid_model\": {\n                    \"get\": {\n                        \"summary\": \"Response Model No Annotation Return Invalid Model\",\n                        \"operationId\": \"response_model_no_annotation_return_invalid_model_response_model_no_annotation_return_invalid_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model-no_annotation-return_dict_with_extra_data\": {\n                    \"get\": {\n                        \"summary\": \"Response Model No Annotation Return Dict With Extra Data\",\n                        \"operationId\": \"response_model_no_annotation_return_dict_with_extra_data_response_model_no_annotation_return_dict_with_extra_data_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model-no_annotation-return_submodel_with_extra_data\": {\n                    \"get\": {\n                        \"summary\": \"Response Model No Annotation Return Submodel With Extra Data\",\n                        \"operationId\": \"response_model_no_annotation_return_submodel_with_extra_data_response_model_no_annotation_return_submodel_with_extra_data_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation-return_same_model\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Return Same Model\",\n                        \"operationId\": \"no_response_model_annotation_return_same_model_no_response_model_annotation_return_same_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation-return_exact_dict\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Return Exact Dict\",\n                        \"operationId\": \"no_response_model_annotation_return_exact_dict_no_response_model_annotation_return_exact_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation-return_invalid_dict\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Return Invalid Dict\",\n                        \"operationId\": \"no_response_model_annotation_return_invalid_dict_no_response_model_annotation_return_invalid_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation-return_invalid_model\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Return Invalid Model\",\n                        \"operationId\": \"no_response_model_annotation_return_invalid_model_no_response_model_annotation_return_invalid_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation-return_dict_with_extra_data\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Return Dict With Extra Data\",\n                        \"operationId\": \"no_response_model_annotation_return_dict_with_extra_data_no_response_model_annotation_return_dict_with_extra_data_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation-return_submodel_with_extra_data\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Return Submodel With Extra Data\",\n                        \"operationId\": \"no_response_model_annotation_return_submodel_with_extra_data_no_response_model_annotation_return_submodel_with_extra_data_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model_none-annotation-return_same_model\": {\n                    \"get\": {\n                        \"summary\": \"Response Model None Annotation Return Same Model\",\n                        \"operationId\": \"response_model_none_annotation_return_same_model_response_model_none_annotation_return_same_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/response_model_none-annotation-return_exact_dict\": {\n                    \"get\": {\n                        \"summary\": \"Response Model None Annotation Return Exact Dict\",\n                        \"operationId\": \"response_model_none_annotation_return_exact_dict_response_model_none_annotation_return_exact_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/response_model_none-annotation-return_invalid_dict\": {\n                    \"get\": {\n                        \"summary\": \"Response Model None Annotation Return Invalid Dict\",\n                        \"operationId\": \"response_model_none_annotation_return_invalid_dict_response_model_none_annotation_return_invalid_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/response_model_none-annotation-return_invalid_model\": {\n                    \"get\": {\n                        \"summary\": \"Response Model None Annotation Return Invalid Model\",\n                        \"operationId\": \"response_model_none_annotation_return_invalid_model_response_model_none_annotation_return_invalid_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/response_model_none-annotation-return_dict_with_extra_data\": {\n                    \"get\": {\n                        \"summary\": \"Response Model None Annotation Return Dict With Extra Data\",\n                        \"operationId\": \"response_model_none_annotation_return_dict_with_extra_data_response_model_none_annotation_return_dict_with_extra_data_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/response_model_none-annotation-return_submodel_with_extra_data\": {\n                    \"get\": {\n                        \"summary\": \"Response Model None Annotation Return Submodel With Extra Data\",\n                        \"operationId\": \"response_model_none_annotation_return_submodel_with_extra_data_response_model_none_annotation_return_submodel_with_extra_data_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/response_model_model1-annotation_model2-return_same_model\": {\n                    \"get\": {\n                        \"summary\": \"Response Model Model1 Annotation Model2 Return Same Model\",\n                        \"operationId\": \"response_model_model1_annotation_model2_return_same_model_response_model_model1_annotation_model2_return_same_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model_model1-annotation_model2-return_exact_dict\": {\n                    \"get\": {\n                        \"summary\": \"Response Model Model1 Annotation Model2 Return Exact Dict\",\n                        \"operationId\": \"response_model_model1_annotation_model2_return_exact_dict_response_model_model1_annotation_model2_return_exact_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model_model1-annotation_model2-return_invalid_dict\": {\n                    \"get\": {\n                        \"summary\": \"Response Model Model1 Annotation Model2 Return Invalid Dict\",\n                        \"operationId\": \"response_model_model1_annotation_model2_return_invalid_dict_response_model_model1_annotation_model2_return_invalid_dict_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model_model1-annotation_model2-return_invalid_model\": {\n                    \"get\": {\n                        \"summary\": \"Response Model Model1 Annotation Model2 Return Invalid Model\",\n                        \"operationId\": \"response_model_model1_annotation_model2_return_invalid_model_response_model_model1_annotation_model2_return_invalid_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model_model1-annotation_model2-return_dict_with_extra_data\": {\n                    \"get\": {\n                        \"summary\": \"Response Model Model1 Annotation Model2 Return Dict With Extra Data\",\n                        \"operationId\": \"response_model_model1_annotation_model2_return_dict_with_extra_data_response_model_model1_annotation_model2_return_dict_with_extra_data_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model_model1-annotation_model2-return_submodel_with_extra_data\": {\n                    \"get\": {\n                        \"summary\": \"Response Model Model1 Annotation Model2 Return Submodel With Extra Data\",\n                        \"operationId\": \"response_model_model1_annotation_model2_return_submodel_with_extra_data_response_model_model1_annotation_model2_return_submodel_with_extra_data_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model_filtering_model-annotation_submodel-return_submodel\": {\n                    \"get\": {\n                        \"summary\": \"Response Model Filtering Model Annotation Submodel Return Submodel\",\n                        \"operationId\": \"response_model_filtering_model_annotation_submodel_return_submodel_response_model_filtering_model_annotation_submodel_return_submodel_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model_list_of_model-no_annotation\": {\n                    \"get\": {\n                        \"summary\": \"Response Model List Of Model No Annotation\",\n                        \"operationId\": \"response_model_list_of_model_no_annotation_response_model_list_of_model_no_annotation_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Response Model List Of Model No Annotation Response Model List Of Model No Annotation Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/User\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation_list_of_model\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation List Of Model\",\n                        \"operationId\": \"no_response_model_annotation_list_of_model_no_response_model_annotation_list_of_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response No Response Model Annotation List Of Model No Response Model Annotation List Of Model Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/User\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation_forward_ref_list_of_model\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Forward Ref List Of Model\",\n                        \"operationId\": \"no_response_model_annotation_forward_ref_list_of_model_no_response_model_annotation_forward_ref_list_of_model_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response No Response Model Annotation Forward Ref List Of Model No Response Model Annotation Forward Ref List Of Model Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/User\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model_union-no_annotation-return_model1\": {\n                    \"get\": {\n                        \"summary\": \"Response Model Union No Annotation Return Model1\",\n                        \"operationId\": \"response_model_union_no_annotation_return_model1_response_model_union_no_annotation_return_model1_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Response Model Union No Annotation Return Model1 Response Model Union No Annotation Return Model1 Get\",\n                                            \"anyOf\": [\n                                                {\"$ref\": \"#/components/schemas/User\"},\n                                                {\"$ref\": \"#/components/schemas/Item\"},\n                                            ],\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/response_model_union-no_annotation-return_model2\": {\n                    \"get\": {\n                        \"summary\": \"Response Model Union No Annotation Return Model2\",\n                        \"operationId\": \"response_model_union_no_annotation_return_model2_response_model_union_no_annotation_return_model2_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Response Model Union No Annotation Return Model2 Response Model Union No Annotation Return Model2 Get\",\n                                            \"anyOf\": [\n                                                {\"$ref\": \"#/components/schemas/User\"},\n                                                {\"$ref\": \"#/components/schemas/Item\"},\n                                            ],\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation_union-return_model1\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Union Return Model1\",\n                        \"operationId\": \"no_response_model_annotation_union_return_model1_no_response_model_annotation_union_return_model1_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response No Response Model Annotation Union Return Model1 No Response Model Annotation Union Return Model1 Get\",\n                                            \"anyOf\": [\n                                                {\"$ref\": \"#/components/schemas/User\"},\n                                                {\"$ref\": \"#/components/schemas/Item\"},\n                                            ],\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation_union-return_model2\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Union Return Model2\",\n                        \"operationId\": \"no_response_model_annotation_union_return_model2_no_response_model_annotation_union_return_model2_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response No Response Model Annotation Union Return Model2 No Response Model Annotation Union Return Model2 Get\",\n                                            \"anyOf\": [\n                                                {\"$ref\": \"#/components/schemas/User\"},\n                                                {\"$ref\": \"#/components/schemas/Item\"},\n                                            ],\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation_response_class\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Response Class\",\n                        \"operationId\": \"no_response_model_annotation_response_class_no_response_model_annotation_response_class_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/no_response_model-annotation_json_response_class\": {\n                    \"get\": {\n                        \"summary\": \"No Response Model Annotation Json Response Class\",\n                        \"operationId\": \"no_response_model_annotation_json_response_class_no_response_model_annotation_json_response_class_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"User\": {\n                        \"title\": \"User\",\n                        \"required\": [\"name\", \"surname\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"surname\": {\"title\": \"Surname\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_response_model_data_filter.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass UserBase(BaseModel):\n    email: str\n\n\nclass UserCreate(UserBase):\n    password: str\n\n\nclass UserDB(UserBase):\n    hashed_password: str\n\n\nclass PetDB(BaseModel):\n    name: str\n    owner: UserDB\n\n\nclass PetOut(BaseModel):\n    name: str\n    owner: UserBase\n\n\n@app.post(\"/users/\", response_model=UserBase)\nasync def create_user(user: UserCreate):\n    return user\n\n\n@app.get(\"/pets/{pet_id}\", response_model=PetOut)\nasync def read_pet(pet_id: int):\n    user = UserDB(\n        email=\"johndoe@example.com\",\n        hashed_password=\"secrethashed\",\n    )\n    pet = PetDB(name=\"Nibbler\", owner=user)\n    return pet\n\n\n@app.get(\"/pets/\", response_model=list[PetOut])\nasync def read_pets():\n    user = UserDB(\n        email=\"johndoe@example.com\",\n        hashed_password=\"secrethashed\",\n    )\n    pet1 = PetDB(name=\"Nibbler\", owner=user)\n    pet2 = PetDB(name=\"Zoidberg\", owner=user)\n    return [pet1, pet2]\n\n\nclient = TestClient(app)\n\n\ndef test_filter_top_level_model():\n    response = client.post(\n        \"/users\", json={\"email\": \"johndoe@example.com\", \"password\": \"secret\"}\n    )\n    assert response.json() == {\"email\": \"johndoe@example.com\"}\n\n\ndef test_filter_second_level_model():\n    response = client.get(\"/pets/1\")\n    assert response.json() == {\n        \"name\": \"Nibbler\",\n        \"owner\": {\"email\": \"johndoe@example.com\"},\n    }\n\n\ndef test_list_of_models():\n    response = client.get(\"/pets/\")\n    assert response.json() == [\n        {\"name\": \"Nibbler\", \"owner\": {\"email\": \"johndoe@example.com\"}},\n        {\"name\": \"Zoidberg\", \"owner\": {\"email\": \"johndoe@example.com\"}},\n    ]\n"
  },
  {
    "path": "tests/test_response_model_data_filter_no_inheritance.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass UserCreate(BaseModel):\n    email: str\n    password: str\n\n\nclass UserDB(BaseModel):\n    email: str\n    hashed_password: str\n\n\nclass User(BaseModel):\n    email: str\n\n\nclass PetDB(BaseModel):\n    name: str\n    owner: UserDB\n\n\nclass PetOut(BaseModel):\n    name: str\n    owner: User\n\n\n@app.post(\"/users/\", response_model=User)\nasync def create_user(user: UserCreate):\n    return user\n\n\n@app.get(\"/pets/{pet_id}\", response_model=PetOut)\nasync def read_pet(pet_id: int):\n    user = UserDB(\n        email=\"johndoe@example.com\",\n        hashed_password=\"secrethashed\",\n    )\n    pet = PetDB(name=\"Nibbler\", owner=user)\n    return pet\n\n\n@app.get(\"/pets/\", response_model=list[PetOut])\nasync def read_pets():\n    user = UserDB(\n        email=\"johndoe@example.com\",\n        hashed_password=\"secrethashed\",\n    )\n    pet1 = PetDB(name=\"Nibbler\", owner=user)\n    pet2 = PetDB(name=\"Zoidberg\", owner=user)\n    return [pet1, pet2]\n\n\nclient = TestClient(app)\n\n\ndef test_filter_top_level_model():\n    response = client.post(\n        \"/users\", json={\"email\": \"johndoe@example.com\", \"password\": \"secret\"}\n    )\n    assert response.json() == {\"email\": \"johndoe@example.com\"}\n\n\ndef test_filter_second_level_model():\n    response = client.get(\"/pets/1\")\n    assert response.json() == {\n        \"name\": \"Nibbler\",\n        \"owner\": {\"email\": \"johndoe@example.com\"},\n    }\n\n\ndef test_list_of_models():\n    response = client.get(\"/pets/\")\n    assert response.json() == [\n        {\"name\": \"Nibbler\", \"owner\": {\"email\": \"johndoe@example.com\"}},\n        {\"name\": \"Zoidberg\", \"owner\": {\"email\": \"johndoe@example.com\"}},\n    ]\n"
  },
  {
    "path": "tests/test_response_model_default_factory.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel, Field\n\napp = FastAPI()\n\n\nclass ResponseModel(BaseModel):\n    code: int = 200\n    message: str = Field(default_factory=lambda: \"Successful operation.\")\n\n\n@app.get(\n    \"/response_model_has_default_factory_return_dict\",\n    response_model=ResponseModel,\n)\nasync def response_model_has_default_factory_return_dict():\n    return {\"code\": 200}\n\n\n@app.get(\n    \"/response_model_has_default_factory_return_model\",\n    response_model=ResponseModel,\n)\nasync def response_model_has_default_factory_return_model():\n    return ResponseModel()\n\n\nclient = TestClient(app)\n\n\ndef test_response_model_has_default_factory_return_dict():\n    response = client.get(\"/response_model_has_default_factory_return_dict\")\n\n    assert response.status_code == 200, response.text\n\n    assert response.json()[\"code\"] == 200\n    assert response.json()[\"message\"] == \"Successful operation.\"\n\n\ndef test_response_model_has_default_factory_return_model():\n    response = client.get(\"/response_model_has_default_factory_return_model\")\n\n    assert response.status_code == 200, response.text\n\n    assert response.json()[\"code\"] == 200\n    assert response.json()[\"message\"] == \"Successful operation.\"\n"
  },
  {
    "path": "tests/test_response_model_include_exclude.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\n\nclass Model1(BaseModel):\n    foo: str\n    bar: str\n\n\nclass Model2(BaseModel):\n    ref: Model1\n    baz: str\n\n\nclass Model3(BaseModel):\n    name: str\n    age: int\n    ref2: Model2\n\n\napp = FastAPI()\n\n\n@app.get(\n    \"/simple_include\",\n    response_model=Model2,\n    response_model_include={\"baz\": ..., \"ref\": {\"foo\"}},\n)\ndef simple_include():\n    return Model2(\n        ref=Model1(foo=\"simple_include model foo\", bar=\"simple_include model bar\"),\n        baz=\"simple_include model2 baz\",\n    )\n\n\n@app.get(\n    \"/simple_include_dict\",\n    response_model=Model2,\n    response_model_include={\"baz\": ..., \"ref\": {\"foo\"}},\n)\ndef simple_include_dict():\n    return {\n        \"ref\": {\n            \"foo\": \"simple_include_dict model foo\",\n            \"bar\": \"simple_include_dict model bar\",\n        },\n        \"baz\": \"simple_include_dict model2 baz\",\n    }\n\n\n@app.get(\n    \"/simple_exclude\",\n    response_model=Model2,\n    response_model_exclude={\"ref\": {\"bar\"}},\n)\ndef simple_exclude():\n    return Model2(\n        ref=Model1(foo=\"simple_exclude model foo\", bar=\"simple_exclude model bar\"),\n        baz=\"simple_exclude model2 baz\",\n    )\n\n\n@app.get(\n    \"/simple_exclude_dict\",\n    response_model=Model2,\n    response_model_exclude={\"ref\": {\"bar\"}},\n)\ndef simple_exclude_dict():\n    return {\n        \"ref\": {\n            \"foo\": \"simple_exclude_dict model foo\",\n            \"bar\": \"simple_exclude_dict model bar\",\n        },\n        \"baz\": \"simple_exclude_dict model2 baz\",\n    }\n\n\n@app.get(\n    \"/mixed\",\n    response_model=Model3,\n    response_model_include={\"ref2\", \"name\"},\n    response_model_exclude={\"ref2\": {\"baz\"}},\n)\ndef mixed():\n    return Model3(\n        name=\"mixed model3 name\",\n        age=3,\n        ref2=Model2(\n            ref=Model1(foo=\"mixed model foo\", bar=\"mixed model bar\"),\n            baz=\"mixed model2 baz\",\n        ),\n    )\n\n\n@app.get(\n    \"/mixed_dict\",\n    response_model=Model3,\n    response_model_include={\"ref2\", \"name\"},\n    response_model_exclude={\"ref2\": {\"baz\"}},\n)\ndef mixed_dict():\n    return {\n        \"name\": \"mixed_dict model3 name\",\n        \"age\": 3,\n        \"ref2\": {\n            \"ref\": {\"foo\": \"mixed_dict model foo\", \"bar\": \"mixed_dict model bar\"},\n            \"baz\": \"mixed_dict model2 baz\",\n        },\n    }\n\n\nclient = TestClient(app)\n\n\ndef test_nested_include_simple():\n    response = client.get(\"/simple_include\")\n\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\n        \"baz\": \"simple_include model2 baz\",\n        \"ref\": {\"foo\": \"simple_include model foo\"},\n    }\n\n\ndef test_nested_include_simple_dict():\n    response = client.get(\"/simple_include_dict\")\n\n    assert response.status_code == 200, response.text\n\n    assert response.json() == {\n        \"baz\": \"simple_include_dict model2 baz\",\n        \"ref\": {\"foo\": \"simple_include_dict model foo\"},\n    }\n\n\ndef test_nested_exclude_simple():\n    response = client.get(\"/simple_exclude\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"baz\": \"simple_exclude model2 baz\",\n        \"ref\": {\"foo\": \"simple_exclude model foo\"},\n    }\n\n\ndef test_nested_exclude_simple_dict():\n    response = client.get(\"/simple_exclude_dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"baz\": \"simple_exclude_dict model2 baz\",\n        \"ref\": {\"foo\": \"simple_exclude_dict model foo\"},\n    }\n\n\ndef test_nested_include_mixed():\n    response = client.get(\"/mixed\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"mixed model3 name\",\n        \"ref2\": {\n            \"ref\": {\"foo\": \"mixed model foo\", \"bar\": \"mixed model bar\"},\n        },\n    }\n\n\ndef test_nested_include_mixed_dict():\n    response = client.get(\"/mixed_dict\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"mixed_dict model3 name\",\n        \"ref2\": {\n            \"ref\": {\"foo\": \"mixed_dict model foo\", \"bar\": \"mixed_dict model bar\"},\n        },\n    }\n"
  },
  {
    "path": "tests/test_response_model_invalid.py",
    "content": "import pytest\nfrom fastapi import FastAPI\nfrom fastapi.exceptions import FastAPIError\n\n\nclass NonPydanticModel:\n    pass\n\n\ndef test_invalid_response_model_raises():\n    with pytest.raises(FastAPIError):\n        app = FastAPI()\n\n        @app.get(\"/\", response_model=NonPydanticModel)\n        def read_root():\n            pass  # pragma: nocover\n\n\ndef test_invalid_response_model_sub_type_raises():\n    with pytest.raises(FastAPIError):\n        app = FastAPI()\n\n        @app.get(\"/\", response_model=list[NonPydanticModel])\n        def read_root():\n            pass  # pragma: nocover\n\n\ndef test_invalid_response_model_in_responses_raises():\n    with pytest.raises(FastAPIError):\n        app = FastAPI()\n\n        @app.get(\"/\", responses={\"500\": {\"model\": NonPydanticModel}})\n        def read_root():\n            pass  # pragma: nocover\n\n\ndef test_invalid_response_model_sub_type_in_responses_raises():\n    with pytest.raises(FastAPIError):\n        app = FastAPI()\n\n        @app.get(\"/\", responses={\"500\": {\"model\": list[NonPydanticModel]}})\n        def read_root():\n            pass  # pragma: nocover\n"
  },
  {
    "path": "tests/test_response_model_sub_types.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\n\nclass Model(BaseModel):\n    name: str\n\n\napp = FastAPI()\n\n\n@app.get(\"/valid1\", responses={\"500\": {\"model\": int}})\ndef valid1():\n    pass\n\n\n@app.get(\"/valid2\", responses={\"500\": {\"model\": list[int]}})\ndef valid2():\n    pass\n\n\n@app.get(\"/valid3\", responses={\"500\": {\"model\": Model}})\ndef valid3():\n    pass\n\n\n@app.get(\"/valid4\", responses={\"500\": {\"model\": list[Model]}})\ndef valid4():\n    pass\n\n\nclient = TestClient(app)\n\n\ndef test_path_operations():\n    response = client.get(\"/valid1\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/valid2\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/valid3\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/valid4\")\n    assert response.status_code == 200, response.text\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/valid1\": {\n                    \"get\": {\n                        \"summary\": \"Valid1\",\n                        \"operationId\": \"valid1_valid1_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"500\": {\n                                \"description\": \"Internal Server Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 500 Valid1 Valid1 Get\",\n                                            \"type\": \"integer\",\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/valid2\": {\n                    \"get\": {\n                        \"summary\": \"Valid2\",\n                        \"operationId\": \"valid2_valid2_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"500\": {\n                                \"description\": \"Internal Server Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 500 Valid2 Valid2 Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\"type\": \"integer\"},\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/valid3\": {\n                    \"get\": {\n                        \"summary\": \"Valid3\",\n                        \"operationId\": \"valid3_valid3_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"500\": {\n                                \"description\": \"Internal Server Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Model\"}\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/valid4\": {\n                    \"get\": {\n                        \"summary\": \"Valid4\",\n                        \"operationId\": \"valid4_valid4_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"500\": {\n                                \"description\": \"Internal Server Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response 500 Valid4 Valid4 Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Model\"\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Model\": {\n                        \"title\": \"Model\",\n                        \"required\": [\"name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"name\": {\"title\": \"Name\", \"type\": \"string\"}},\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_response_set_response_code_empty.py",
    "content": "from typing import Any\n\nfrom fastapi import FastAPI, Response\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\n\n@app.delete(\n    \"/{id}\",\n    status_code=204,\n    response_model=None,\n)\nasync def delete_deployment(\n    id: int,\n    response: Response,\n) -> Any:\n    response.status_code = 400\n    return {\"msg\": \"Status overwritten\", \"id\": id}\n\n\nclient = TestClient(app)\n\n\ndef test_dependency_set_status_code():\n    response = client.delete(\"/1\")\n    assert response.status_code == 400 and response.content\n    assert response.json() == {\"msg\": \"Status overwritten\", \"id\": 1}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/{id}\": {\n                    \"delete\": {\n                        \"summary\": \"Delete Deployment\",\n                        \"operationId\": \"delete_deployment__id__delete\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Id\", \"type\": \"integer\"},\n                                \"name\": \"id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"204\": {\"description\": \"Successful Response\"},\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_return_none_stringified_annotations.py",
    "content": "import http\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\n\ndef test_no_content():\n    app = FastAPI()\n\n    @app.get(\"/no-content\", status_code=http.HTTPStatus.NO_CONTENT)\n    def return_no_content() -> \"None\":\n        return\n\n    client = TestClient(app)\n    response = client.get(\"/no-content\")\n    assert response.status_code == http.HTTPStatus.NO_CONTENT, response.text\n    assert not response.content\n"
  },
  {
    "path": "tests/test_route_scope.py",
    "content": "import pytest\nfrom fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect\nfrom fastapi.routing import APIRoute, APIWebSocketRoute\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.get(\"/users/{user_id}\")\nasync def get_user(user_id: str, request: Request):\n    route: APIRoute = request.scope[\"route\"]\n    return {\"user_id\": user_id, \"path\": route.path}\n\n\n@app.websocket(\"/items/{item_id}\")\nasync def websocket_item(item_id: str, websocket: WebSocket):\n    route: APIWebSocketRoute = websocket.scope[\"route\"]\n    await websocket.accept()\n    await websocket.send_json({\"item_id\": item_id, \"path\": route.path})\n\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/users/rick\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"user_id\": \"rick\", \"path\": \"/users/{user_id}\"}\n\n\ndef test_invalid_method_doesnt_match():\n    response = client.post(\"/users/rick\")\n    assert response.status_code == 405, response.text\n\n\ndef test_invalid_path_doesnt_match():\n    response = client.post(\"/usersx/rick\")\n    assert response.status_code == 404, response.text\n\n\ndef test_websocket():\n    with client.websocket_connect(\"/items/portal-gun\") as websocket:\n        data = websocket.receive_json()\n        assert data == {\"item_id\": \"portal-gun\", \"path\": \"/items/{item_id}\"}\n\n\ndef test_websocket_invalid_path_doesnt_match():\n    with pytest.raises(WebSocketDisconnect):\n        with client.websocket_connect(\"/itemsx/portal-gun\"):\n            pass  # pragma: no cover\n"
  },
  {
    "path": "tests/test_router_circular_import.py",
    "content": "import pytest\nfrom fastapi import APIRouter\n\n\ndef test_router_circular_import():\n    router = APIRouter()\n\n    with pytest.raises(\n        AssertionError,\n        match=\"Cannot include the same APIRouter instance into itself. Did you mean to include a different router?\",\n    ):\n        router.include_router(router)\n"
  },
  {
    "path": "tests/test_router_events.py",
    "content": "from collections.abc import AsyncGenerator\nfrom contextlib import asynccontextmanager\n\nimport pytest\nfrom fastapi import APIRouter, FastAPI, Request\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\n\nclass State(BaseModel):\n    app_startup: bool = False\n    app_shutdown: bool = False\n    router_startup: bool = False\n    router_shutdown: bool = False\n    sub_router_startup: bool = False\n    sub_router_shutdown: bool = False\n\n\n@pytest.fixture\ndef state() -> State:\n    return State()\n\n\n@pytest.mark.filterwarnings(\n    r\"ignore:\\s*on_event is deprecated, use lifespan event handlers instead.*:DeprecationWarning\"\n)\ndef test_router_events(state: State) -> None:\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def main() -> dict[str, str]:\n        return {\"message\": \"Hello World\"}\n\n    @app.on_event(\"startup\")\n    def app_startup() -> None:\n        state.app_startup = True\n\n    @app.on_event(\"shutdown\")\n    def app_shutdown() -> None:\n        state.app_shutdown = True\n\n    router = APIRouter()\n\n    @router.on_event(\"startup\")\n    def router_startup() -> None:\n        state.router_startup = True\n\n    @router.on_event(\"shutdown\")\n    def router_shutdown() -> None:\n        state.router_shutdown = True\n\n    sub_router = APIRouter()\n\n    @sub_router.on_event(\"startup\")\n    def sub_router_startup() -> None:\n        state.sub_router_startup = True\n\n    @sub_router.on_event(\"shutdown\")\n    def sub_router_shutdown() -> None:\n        state.sub_router_shutdown = True\n\n    router.include_router(sub_router)\n    app.include_router(router)\n\n    assert state.app_startup is False\n    assert state.router_startup is False\n    assert state.sub_router_startup is False\n    assert state.app_shutdown is False\n    assert state.router_shutdown is False\n    assert state.sub_router_shutdown is False\n    with TestClient(app) as client:\n        assert state.app_startup is True\n        assert state.router_startup is True\n        assert state.sub_router_startup is True\n        assert state.app_shutdown is False\n        assert state.router_shutdown is False\n        assert state.sub_router_shutdown is False\n        response = client.get(\"/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\"message\": \"Hello World\"}\n    assert state.app_startup is True\n    assert state.router_startup is True\n    assert state.sub_router_startup is True\n    assert state.app_shutdown is True\n    assert state.router_shutdown is True\n    assert state.sub_router_shutdown is True\n\n\ndef test_app_lifespan_state(state: State) -> None:\n    @asynccontextmanager\n    async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:\n        state.app_startup = True\n        yield\n        state.app_shutdown = True\n\n    app = FastAPI(lifespan=lifespan)\n\n    @app.get(\"/\")\n    def main() -> dict[str, str]:\n        return {\"message\": \"Hello World\"}\n\n    assert state.app_startup is False\n    assert state.app_shutdown is False\n    with TestClient(app) as client:\n        assert state.app_startup is True\n        assert state.app_shutdown is False\n        response = client.get(\"/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\"message\": \"Hello World\"}\n    assert state.app_startup is True\n    assert state.app_shutdown is True\n\n\ndef test_router_nested_lifespan_state(state: State) -> None:\n    @asynccontextmanager\n    async def lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]:\n        state.app_startup = True\n        yield {\"app\": True}\n        state.app_shutdown = True\n\n    @asynccontextmanager\n    async def router_lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]:\n        state.router_startup = True\n        yield {\"router\": True}\n        state.router_shutdown = True\n\n    @asynccontextmanager\n    async def subrouter_lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]:\n        state.sub_router_startup = True\n        yield {\"sub_router\": True}\n        state.sub_router_shutdown = True\n\n    sub_router = APIRouter(lifespan=subrouter_lifespan)\n\n    router = APIRouter(lifespan=router_lifespan)\n    router.include_router(sub_router)\n\n    app = FastAPI(lifespan=lifespan)\n    app.include_router(router)\n\n    @app.get(\"/\")\n    def main(request: Request) -> dict[str, str]:\n        assert request.state.app\n        assert request.state.router\n        assert request.state.sub_router\n        return {\"message\": \"Hello World\"}\n\n    assert state.app_startup is False\n    assert state.router_startup is False\n    assert state.sub_router_startup is False\n    assert state.app_shutdown is False\n    assert state.router_shutdown is False\n    assert state.sub_router_shutdown is False\n\n    with TestClient(app) as client:\n        assert state.app_startup is True\n        assert state.router_startup is True\n        assert state.sub_router_startup is True\n        assert state.app_shutdown is False\n        assert state.router_shutdown is False\n        assert state.sub_router_shutdown is False\n        response = client.get(\"/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\"message\": \"Hello World\"}\n\n    assert state.app_startup is True\n    assert state.router_startup is True\n    assert state.sub_router_startup is True\n    assert state.app_shutdown is True\n    assert state.router_shutdown is True\n    assert state.sub_router_shutdown is True\n\n\ndef test_router_nested_lifespan_state_overriding_by_parent() -> None:\n    @asynccontextmanager\n    async def lifespan(\n        app: FastAPI,\n    ) -> AsyncGenerator[dict[str, str | bool], None]:\n        yield {\n            \"app_specific\": True,\n            \"overridden\": \"app\",\n        }\n\n    @asynccontextmanager\n    async def router_lifespan(\n        app: FastAPI,\n    ) -> AsyncGenerator[dict[str, str | bool], None]:\n        yield {\n            \"router_specific\": True,\n            \"overridden\": \"router\",  # should override parent\n        }\n\n    router = APIRouter(lifespan=router_lifespan)\n    app = FastAPI(lifespan=lifespan)\n    app.include_router(router)\n\n    with TestClient(app) as client:\n        assert client.app_state == {\n            \"app_specific\": True,\n            \"router_specific\": True,\n            \"overridden\": \"app\",\n        }\n\n\ndef test_merged_no_return_lifespans_return_none() -> None:\n    @asynccontextmanager\n    async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:\n        yield\n\n    @asynccontextmanager\n    async def router_lifespan(app: FastAPI) -> AsyncGenerator[None, None]:\n        yield\n\n    router = APIRouter(lifespan=router_lifespan)\n    app = FastAPI(lifespan=lifespan)\n    app.include_router(router)\n\n    with TestClient(app) as client:\n        assert not client.app_state\n\n\ndef test_merged_mixed_state_lifespans() -> None:\n    @asynccontextmanager\n    async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:\n        yield\n\n    @asynccontextmanager\n    async def router_lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]:\n        yield {\"router\": True}\n\n    @asynccontextmanager\n    async def sub_router_lifespan(app: FastAPI) -> AsyncGenerator[None, None]:\n        yield\n\n    sub_router = APIRouter(lifespan=sub_router_lifespan)\n    router = APIRouter(lifespan=router_lifespan)\n    app = FastAPI(lifespan=lifespan)\n    router.include_router(sub_router)\n    app.include_router(router)\n\n    with TestClient(app) as client:\n        assert client.app_state == {\"router\": True}\n\n\n@pytest.mark.filterwarnings(\n    r\"ignore:\\s*on_event is deprecated, use lifespan event handlers instead.*:DeprecationWarning\"\n)\ndef test_router_async_shutdown_handler(state: State) -> None:\n    \"\"\"Test that async on_shutdown event handlers are called correctly, for coverage.\"\"\"\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def main() -> dict[str, str]:\n        return {\"message\": \"Hello World\"}\n\n    @app.on_event(\"shutdown\")\n    async def app_shutdown() -> None:\n        state.app_shutdown = True\n\n    assert state.app_shutdown is False\n    with TestClient(app) as client:\n        assert state.app_shutdown is False\n        response = client.get(\"/\")\n        assert response.status_code == 200, response.text\n    assert state.app_shutdown is True\n\n\ndef test_router_sync_generator_lifespan(state: State) -> None:\n    \"\"\"Test that a sync generator lifespan works via _wrap_gen_lifespan_context.\"\"\"\n    from collections.abc import Generator\n\n    def lifespan(app: FastAPI) -> Generator[None, None, None]:\n        state.app_startup = True\n        yield\n        state.app_shutdown = True\n\n    app = FastAPI(lifespan=lifespan)  # type: ignore[arg-type]\n\n    @app.get(\"/\")\n    def main() -> dict[str, str]:\n        return {\"message\": \"Hello World\"}\n\n    assert state.app_startup is False\n    assert state.app_shutdown is False\n    with TestClient(app) as client:\n        assert state.app_startup is True\n        assert state.app_shutdown is False\n        response = client.get(\"/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\"message\": \"Hello World\"}\n    assert state.app_startup is True\n    assert state.app_shutdown is True\n\n\ndef test_router_async_generator_lifespan(state: State) -> None:\n    \"\"\"Test that an async generator lifespan (not wrapped) works.\"\"\"\n\n    async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:\n        state.app_startup = True\n        yield\n        state.app_shutdown = True\n\n    app = FastAPI(lifespan=lifespan)  # type: ignore[arg-type]\n\n    @app.get(\"/\")\n    def main() -> dict[str, str]:\n        return {\"message\": \"Hello World\"}\n\n    assert state.app_startup is False\n    assert state.app_shutdown is False\n    with TestClient(app) as client:\n        assert state.app_startup is True\n        assert state.app_shutdown is False\n        response = client.get(\"/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\"message\": \"Hello World\"}\n    assert state.app_startup is True\n    assert state.app_shutdown is True\n\n\ndef test_startup_shutdown_handlers_as_parameters(state: State) -> None:\n    \"\"\"Test that startup/shutdown handlers passed as parameters to FastAPI are called correctly.\"\"\"\n\n    def app_startup() -> None:\n        state.app_startup = True\n\n    def app_shutdown() -> None:\n        state.app_shutdown = True\n\n    app = FastAPI(on_startup=[app_startup], on_shutdown=[app_shutdown])\n\n    @app.get(\"/\")\n    def main() -> dict[str, str]:\n        return {\"message\": \"Hello World\"}\n\n    def router_startup() -> None:\n        state.router_startup = True\n\n    def router_shutdown() -> None:\n        state.router_shutdown = True\n\n    router = APIRouter(on_startup=[router_startup], on_shutdown=[router_shutdown])\n\n    def sub_router_startup() -> None:\n        state.sub_router_startup = True\n\n    def sub_router_shutdown() -> None:\n        state.sub_router_shutdown = True\n\n    sub_router = APIRouter(\n        on_startup=[sub_router_startup], on_shutdown=[sub_router_shutdown]\n    )\n\n    router.include_router(sub_router)\n    app.include_router(router)\n\n    assert state.app_startup is False\n    assert state.router_startup is False\n    assert state.sub_router_startup is False\n    assert state.app_shutdown is False\n    assert state.router_shutdown is False\n    assert state.sub_router_shutdown is False\n    with TestClient(app) as client:\n        assert state.app_startup is True\n        assert state.router_startup is True\n        assert state.sub_router_startup is True\n        assert state.app_shutdown is False\n        assert state.router_shutdown is False\n        assert state.sub_router_shutdown is False\n        response = client.get(\"/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\"message\": \"Hello World\"}\n    assert state.app_startup is True\n    assert state.router_startup is True\n    assert state.sub_router_startup is True\n    assert state.app_shutdown is True\n    assert state.router_shutdown is True\n    assert state.sub_router_shutdown is True\n"
  },
  {
    "path": "tests/test_router_prefix_with_template.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\nrouter = APIRouter()\n\n\n@router.get(\"/users/{id}\")\ndef read_user(segment: str, id: str):\n    return {\"segment\": segment, \"id\": id}\n\n\napp.include_router(router, prefix=\"/{segment}\")\n\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/seg/users/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"segment\": \"seg\", \"id\": \"foo\"}\n"
  },
  {
    "path": "tests/test_router_redirect_slashes.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom fastapi.testclient import TestClient\n\n\ndef test_redirect_slashes_enabled():\n    app = FastAPI()\n    router = APIRouter()\n\n    @router.get(\"/hello/\")\n    def hello_page() -> str:\n        return \"Hello, World!\"\n\n    app.include_router(router)\n\n    client = TestClient(app)\n\n    response = client.get(\"/hello/\", follow_redirects=False)\n    assert response.status_code == 200\n\n    response = client.get(\"/hello\", follow_redirects=False)\n    assert response.status_code == 307\n\n\ndef test_redirect_slashes_disabled():\n    app = FastAPI(redirect_slashes=False)\n    router = APIRouter()\n\n    @router.get(\"/hello/\")\n    def hello_page() -> str:\n        return \"Hello, World!\"\n\n    app.include_router(router)\n\n    client = TestClient(app)\n\n    response = client.get(\"/hello/\", follow_redirects=False)\n    assert response.status_code == 200\n\n    response = client.get(\"/hello\", follow_redirects=False)\n    assert response.status_code == 404\n"
  },
  {
    "path": "tests/test_schema_compat_pydantic_v2.py",
    "content": "import pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(name=\"client\")\ndef get_client():\n    from enum import Enum\n\n    app = FastAPI()\n\n    class PlatformRole(str, Enum):\n        admin = \"admin\"\n        user = \"user\"\n\n    class OtherRole(str, Enum): ...\n\n    class User(BaseModel):\n        username: str\n        role: PlatformRole | OtherRole\n\n    @app.get(\"/users\")\n    async def get_user() -> User:\n        return {\"username\": \"alice\", \"role\": \"admin\"}\n\n    client = TestClient(app)\n    return client\n\n\n@needs_py310\ndef test_get(client: TestClient):\n    response = client.get(\"/users\")\n    assert response.json() == {\"username\": \"alice\", \"role\": \"admin\"}\n\n\n@needs_py310\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users\": {\n                    \"get\": {\n                        \"summary\": \"Get User\",\n                        \"operationId\": \"get_user_users_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": IsOneOf(\n                    # Pydantic >= 2.11: no top-level OtherRole\n                    {\n                        \"PlatformRole\": {\n                            \"type\": \"string\",\n                            \"enum\": [\"admin\", \"user\"],\n                            \"title\": \"PlatformRole\",\n                        },\n                        \"User\": {\n                            \"properties\": {\n                                \"username\": {\"type\": \"string\", \"title\": \"Username\"},\n                                \"role\": {\n                                    \"anyOf\": [\n                                        {\"$ref\": \"#/components/schemas/PlatformRole\"},\n                                        {\"enum\": [], \"title\": \"OtherRole\"},\n                                    ],\n                                    \"title\": \"Role\",\n                                },\n                            },\n                            \"type\": \"object\",\n                            \"required\": [\"username\", \"role\"],\n                            \"title\": \"User\",\n                        },\n                    },\n                    # Pydantic < 2.11: adds a top-level OtherRole schema\n                    {\n                        \"OtherRole\": {\n                            \"enum\": [],\n                            \"title\": \"OtherRole\",\n                        },\n                        \"PlatformRole\": {\n                            \"type\": \"string\",\n                            \"enum\": [\"admin\", \"user\"],\n                            \"title\": \"PlatformRole\",\n                        },\n                        \"User\": {\n                            \"properties\": {\n                                \"username\": {\"type\": \"string\", \"title\": \"Username\"},\n                                \"role\": {\n                                    \"anyOf\": [\n                                        {\"$ref\": \"#/components/schemas/PlatformRole\"},\n                                        {\"enum\": [], \"title\": \"OtherRole\"},\n                                    ],\n                                    \"title\": \"Role\",\n                                },\n                            },\n                            \"type\": \"object\",\n                            \"required\": [\"username\", \"role\"],\n                            \"title\": \"User\",\n                        },\n                    },\n                )\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_schema_extra_examples.py",
    "content": "import pytest\nfrom fastapi import Body, Cookie, FastAPI, Header, Path, Query\nfrom fastapi.exceptions import FastAPIDeprecationWarning\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, ConfigDict\n\n\ndef create_app():\n    app = FastAPI()\n\n    class Item(BaseModel):\n        data: str\n\n        model_config = ConfigDict(\n            json_schema_extra={\"example\": {\"data\": \"Data in schema_extra\"}}\n        )\n\n    @app.post(\"/schema_extra/\")\n    def schema_extra(item: Item):\n        return item\n\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.post(\"/example/\")\n        def example(item: Item = Body(example={\"data\": \"Data in Body example\"})):\n            return item\n\n    @app.post(\"/examples/\")\n    def examples(\n        item: Item = Body(\n            examples=[\n                {\"data\": \"Data in Body examples, example1\"},\n                {\"data\": \"Data in Body examples, example2\"},\n            ],\n        ),\n    ):\n        return item\n\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.post(\"/example_examples/\")\n        def example_examples(\n            item: Item = Body(\n                example={\"data\": \"Overridden example\"},\n                examples=[\n                    {\"data\": \"examples example_examples 1\"},\n                    {\"data\": \"examples example_examples 2\"},\n                ],\n            ),\n        ):\n            return item\n\n    # TODO: enable these tests once/if Form(embed=False) is supported\n    # TODO: In that case, define if File() should support example/examples too\n    # @app.post(\"/form_example\")\n    # def form_example(firstname: str = Form(example=\"John\")):\n    #     return firstname\n\n    # @app.post(\"/form_examples\")\n    # def form_examples(\n    #     lastname: str = Form(\n    #         ...,\n    #         examples={\n    #             \"example1\": {\"summary\": \"last name summary\", \"value\": \"Doe\"},\n    #             \"example2\": {\"value\": \"Doesn't\"},\n    #         },\n    #     ),\n    # ):\n    #     return lastname\n\n    # @app.post(\"/form_example_examples\")\n    # def form_example_examples(\n    #     lastname: str = Form(\n    #         ...,\n    #         example=\"Doe overridden\",\n    #         examples={\n    #             \"example1\": {\"summary\": \"last name summary\", \"value\": \"Doe\"},\n    #             \"example2\": {\"value\": \"Doesn't\"},\n    #         },\n    #     ),\n    # ):\n    #     return lastname\n\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.get(\"/path_example/{item_id}\")\n        def path_example(\n            item_id: str = Path(\n                example=\"item_1\",\n            ),\n        ):\n            return item_id\n\n    @app.get(\"/path_examples/{item_id}\")\n    def path_examples(\n        item_id: str = Path(\n            examples=[\"item_1\", \"item_2\"],\n        ),\n    ):\n        return item_id\n\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.get(\"/path_example_examples/{item_id}\")\n        def path_example_examples(\n            item_id: str = Path(\n                example=\"item_overridden\",\n                examples=[\"item_1\", \"item_2\"],\n            ),\n        ):\n            return item_id\n\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.get(\"/query_example/\")\n        def query_example(\n            data: str | None = Query(\n                default=None,\n                example=\"query1\",\n            ),\n        ):\n            return data\n\n    @app.get(\"/query_examples/\")\n    def query_examples(\n        data: str | None = Query(\n            default=None,\n            examples=[\"query1\", \"query2\"],\n        ),\n    ):\n        return data\n\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.get(\"/query_example_examples/\")\n        def query_example_examples(\n            data: str | None = Query(\n                default=None,\n                example=\"query_overridden\",\n                examples=[\"query1\", \"query2\"],\n            ),\n        ):\n            return data\n\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.get(\"/header_example/\")\n        def header_example(\n            data: str | None = Header(\n                default=None,\n                example=\"header1\",\n            ),\n        ):\n            return data\n\n    @app.get(\"/header_examples/\")\n    def header_examples(\n        data: str | None = Header(\n            default=None,\n            examples=[\n                \"header1\",\n                \"header2\",\n            ],\n        ),\n    ):\n        return data\n\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.get(\"/header_example_examples/\")\n        def header_example_examples(\n            data: str | None = Header(\n                default=None,\n                example=\"header_overridden\",\n                examples=[\"header1\", \"header2\"],\n            ),\n        ):\n            return data\n\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.get(\"/cookie_example/\")\n        def cookie_example(\n            data: str | None = Cookie(\n                default=None,\n                example=\"cookie1\",\n            ),\n        ):\n            return data\n\n    @app.get(\"/cookie_examples/\")\n    def cookie_examples(\n        data: str | None = Cookie(\n            default=None,\n            examples=[\"cookie1\", \"cookie2\"],\n        ),\n    ):\n        return data\n\n    with pytest.warns(FastAPIDeprecationWarning):\n\n        @app.get(\"/cookie_example_examples/\")\n        def cookie_example_examples(\n            data: str | None = Cookie(\n                default=None,\n                example=\"cookie_overridden\",\n                examples=[\"cookie1\", \"cookie2\"],\n            ),\n        ):\n            return data\n\n    return app\n\n\ndef test_call_api():\n    app = create_app()\n    client = TestClient(app)\n    response = client.post(\"/schema_extra/\", json={\"data\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    response = client.post(\"/example/\", json={\"data\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    response = client.post(\"/examples/\", json={\"data\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    response = client.post(\"/example_examples/\", json={\"data\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    response = client.get(\"/path_example/foo\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/path_examples/foo\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/path_example_examples/foo\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/query_example/\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/query_examples/\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/query_example_examples/\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/header_example/\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/header_examples/\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/header_example_examples/\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/cookie_example/\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/cookie_examples/\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/cookie_example_examples/\")\n    assert response.status_code == 200, response.text\n\n\ndef test_openapi_schema():\n    \"\"\"\n    Test that example overrides work:\n\n    * pydantic model schema_extra is included\n    * Body(example={}) overrides schema_extra in pydantic model\n    * Body(examples{}) overrides Body(example={}) and schema_extra in pydantic model\n    \"\"\"\n    app = create_app()\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/schema_extra/\": {\n                    \"post\": {\n                        \"summary\": \"Schema Extra\",\n                        \"operationId\": \"schema_extra_schema_extra__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/example/\": {\n                    \"post\": {\n                        \"summary\": \"Example\",\n                        \"operationId\": \"example_example__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"},\n                                    \"example\": {\"data\": \"Data in Body example\"},\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/examples/\": {\n                    \"post\": {\n                        \"summary\": \"Examples\",\n                        \"operationId\": \"examples_examples__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                        \"examples\": [\n                                            {\"data\": \"Data in Body examples, example1\"},\n                                            {\"data\": \"Data in Body examples, example2\"},\n                                        ],\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/example_examples/\": {\n                    \"post\": {\n                        \"summary\": \"Example Examples\",\n                        \"operationId\": \"example_examples_example_examples__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                        \"examples\": [\n                                            {\"data\": \"examples example_examples 1\"},\n                                            {\"data\": \"examples example_examples 2\"},\n                                        ],\n                                    },\n                                    \"example\": {\"data\": \"Overridden example\"},\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/path_example/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Path Example\",\n                        \"operationId\": \"path_example_path_example__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"example\": \"item_1\",\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/path_examples/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Path Examples\",\n                        \"operationId\": \"path_examples_path_examples__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"string\",\n                                    \"examples\": [\"item_1\", \"item_2\"],\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/path_example_examples/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Path Example Examples\",\n                        \"operationId\": \"path_example_examples_path_example_examples__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"string\",\n                                    \"examples\": [\"item_1\", \"item_2\"],\n                                },\n                                \"example\": \"item_overridden\",\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/query_example/\": {\n                    \"get\": {\n                        \"summary\": \"Query Example\",\n                        \"operationId\": \"query_example_query_example__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Data\",\n                                },\n                                \"example\": \"query1\",\n                                \"name\": \"data\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/query_examples/\": {\n                    \"get\": {\n                        \"summary\": \"Query Examples\",\n                        \"operationId\": \"query_examples_query_examples__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Data\",\n                                    \"examples\": [\"query1\", \"query2\"],\n                                },\n                                \"name\": \"data\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/query_example_examples/\": {\n                    \"get\": {\n                        \"summary\": \"Query Example Examples\",\n                        \"operationId\": \"query_example_examples_query_example_examples__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Data\",\n                                    \"examples\": [\"query1\", \"query2\"],\n                                },\n                                \"example\": \"query_overridden\",\n                                \"name\": \"data\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/header_example/\": {\n                    \"get\": {\n                        \"summary\": \"Header Example\",\n                        \"operationId\": \"header_example_header_example__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Data\",\n                                },\n                                \"example\": \"header1\",\n                                \"name\": \"data\",\n                                \"in\": \"header\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/header_examples/\": {\n                    \"get\": {\n                        \"summary\": \"Header Examples\",\n                        \"operationId\": \"header_examples_header_examples__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Data\",\n                                    \"examples\": [\"header1\", \"header2\"],\n                                },\n                                \"name\": \"data\",\n                                \"in\": \"header\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/header_example_examples/\": {\n                    \"get\": {\n                        \"summary\": \"Header Example Examples\",\n                        \"operationId\": \"header_example_examples_header_example_examples__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Data\",\n                                    \"examples\": [\"header1\", \"header2\"],\n                                },\n                                \"example\": \"header_overridden\",\n                                \"name\": \"data\",\n                                \"in\": \"header\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/cookie_example/\": {\n                    \"get\": {\n                        \"summary\": \"Cookie Example\",\n                        \"operationId\": \"cookie_example_cookie_example__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Data\",\n                                },\n                                \"example\": \"cookie1\",\n                                \"name\": \"data\",\n                                \"in\": \"cookie\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/cookie_examples/\": {\n                    \"get\": {\n                        \"summary\": \"Cookie Examples\",\n                        \"operationId\": \"cookie_examples_cookie_examples__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Data\",\n                                    \"examples\": [\"cookie1\", \"cookie2\"],\n                                },\n                                \"name\": \"data\",\n                                \"in\": \"cookie\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/cookie_example_examples/\": {\n                    \"get\": {\n                        \"summary\": \"Cookie Example Examples\",\n                        \"operationId\": \"cookie_example_examples_cookie_example_examples__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Data\",\n                                    \"examples\": [\"cookie1\", \"cookie2\"],\n                                },\n                                \"example\": \"cookie_overridden\",\n                                \"name\": \"data\",\n                                \"in\": \"cookie\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"data\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"data\": {\"title\": \"Data\", \"type\": \"string\"}},\n                        \"example\": {\"data\": \"Data in schema_extra\"},\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_schema_ref_pydantic_v2.py",
    "content": "from typing import Any\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, ConfigDict, Field\n\n\n@pytest.fixture(name=\"client\")\ndef get_client():\n    app = FastAPI()\n\n    class ModelWithRef(BaseModel):\n        ref: str = Field(validation_alias=\"$ref\", serialization_alias=\"$ref\")\n        model_config = ConfigDict(validate_by_alias=True, serialize_by_alias=True)\n\n    @app.get(\"/\", response_model=ModelWithRef)\n    async def read_root() -> Any:\n        return {\"$ref\": \"some-ref\"}\n\n    client = TestClient(app)\n    return client\n\n\ndef test_get(client: TestClient):\n    response = client.get(\"/\")\n    assert response.json() == {\"$ref\": \"some-ref\"}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Read Root\",\n                        \"operationId\": \"read_root__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ModelWithRef\"\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ModelWithRef\": {\n                        \"properties\": {\"$ref\": {\"type\": \"string\", \"title\": \"$Ref\"}},\n                        \"type\": \"object\",\n                        \"required\": [\"$ref\"],\n                        \"title\": \"ModelWithRef\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_api_key_cookie.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security import APIKeyCookie\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\napi_key = APIKeyCookie(name=\"key\")\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str = Security(api_key)):\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User = Depends(get_current_user)):\n    return current_user\n\n\ndef test_security_api_key():\n    client = TestClient(app, cookies={\"key\": \"secret\"})\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"secret\"}\n\n\ndef test_security_api_key_no_key():\n    client = TestClient(app)\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"APIKey\"\n\n\ndef test_openapi_schema():\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"APIKeyCookie\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"APIKeyCookie\": {\"type\": \"apiKey\", \"name\": \"key\", \"in\": \"cookie\"}\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_api_key_cookie_description.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security import APIKeyCookie\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\napi_key = APIKeyCookie(name=\"key\", description=\"An API Cookie Key\")\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str = Security(api_key)):\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User = Depends(get_current_user)):\n    return current_user\n\n\ndef test_security_api_key():\n    client = TestClient(app, cookies={\"key\": \"secret\"})\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"secret\"}\n\n\ndef test_security_api_key_no_key():\n    client = TestClient(app)\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"APIKey\"\n\n\ndef test_openapi_schema():\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"APIKeyCookie\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"APIKeyCookie\": {\n                        \"type\": \"apiKey\",\n                        \"name\": \"key\",\n                        \"in\": \"cookie\",\n                        \"description\": \"An API Cookie Key\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_api_key_cookie_optional.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security import APIKeyCookie\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\napi_key = APIKeyCookie(name=\"key\", auto_error=False)\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str | None = Security(api_key)):\n    if oauth_header is None:\n        return None\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User = Depends(get_current_user)):\n    if current_user is None:\n        return {\"msg\": \"Create an account first\"}\n    else:\n        return current_user\n\n\ndef test_security_api_key():\n    client = TestClient(app, cookies={\"key\": \"secret\"})\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"secret\"}\n\n\ndef test_security_api_key_no_key():\n    client = TestClient(app)\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_openapi_schema():\n    client = TestClient(app)\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"APIKeyCookie\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"APIKeyCookie\": {\"type\": \"apiKey\", \"name\": \"key\", \"in\": \"cookie\"}\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_api_key_header.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security import APIKeyHeader\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\napi_key = APIKeyHeader(name=\"key\")\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str = Security(api_key)):\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User = Depends(get_current_user)):\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_api_key():\n    response = client.get(\"/users/me\", headers={\"key\": \"secret\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"secret\"}\n\n\ndef test_security_api_key_no_key():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"APIKey\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"APIKeyHeader\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"APIKeyHeader\": {\"type\": \"apiKey\", \"name\": \"key\", \"in\": \"header\"}\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_api_key_header_description.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security import APIKeyHeader\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\napi_key = APIKeyHeader(name=\"key\", description=\"An API Key Header\")\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str = Security(api_key)):\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User = Depends(get_current_user)):\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_api_key():\n    response = client.get(\"/users/me\", headers={\"key\": \"secret\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"secret\"}\n\n\ndef test_security_api_key_no_key():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"APIKey\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"APIKeyHeader\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"APIKeyHeader\": {\n                        \"type\": \"apiKey\",\n                        \"name\": \"key\",\n                        \"in\": \"header\",\n                        \"description\": \"An API Key Header\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_api_key_header_optional.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security import APIKeyHeader\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\napi_key = APIKeyHeader(name=\"key\", auto_error=False)\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str | None = Security(api_key)):\n    if oauth_header is None:\n        return None\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User | None = Depends(get_current_user)):\n    if current_user is None:\n        return {\"msg\": \"Create an account first\"}\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_api_key():\n    response = client.get(\"/users/me\", headers={\"key\": \"secret\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"secret\"}\n\n\ndef test_security_api_key_no_key():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"APIKeyHeader\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"APIKeyHeader\": {\"type\": \"apiKey\", \"name\": \"key\", \"in\": \"header\"}\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_api_key_query.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security import APIKeyQuery\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\napi_key = APIKeyQuery(name=\"key\")\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str = Security(api_key)):\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User = Depends(get_current_user)):\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_api_key():\n    response = client.get(\"/users/me?key=secret\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"secret\"}\n\n\ndef test_security_api_key_no_key():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"APIKey\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"APIKeyQuery\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"APIKeyQuery\": {\"type\": \"apiKey\", \"name\": \"key\", \"in\": \"query\"}\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_api_key_query_description.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security import APIKeyQuery\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\napi_key = APIKeyQuery(name=\"key\", description=\"API Key Query\")\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str = Security(api_key)):\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User = Depends(get_current_user)):\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_api_key():\n    response = client.get(\"/users/me?key=secret\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"secret\"}\n\n\ndef test_security_api_key_no_key():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"APIKey\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"APIKeyQuery\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"APIKeyQuery\": {\n                        \"type\": \"apiKey\",\n                        \"name\": \"key\",\n                        \"in\": \"query\",\n                        \"description\": \"API Key Query\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_api_key_query_optional.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security import APIKeyQuery\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\napi_key = APIKeyQuery(name=\"key\", auto_error=False)\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str | None = Security(api_key)):\n    if oauth_header is None:\n        return None\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User | None = Depends(get_current_user)):\n    if current_user is None:\n        return {\"msg\": \"Create an account first\"}\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_api_key():\n    response = client.get(\"/users/me?key=secret\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"secret\"}\n\n\ndef test_security_api_key_no_key():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"APIKeyQuery\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"APIKeyQuery\": {\"type\": \"apiKey\", \"name\": \"key\", \"in\": \"query\"}\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_base.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security.http import HTTPAuthorizationCredentials, HTTPBase\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPBase(scheme=\"Other\")\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: HTTPAuthorizationCredentials = Security(security)):\n    return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_base():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Other foobar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"scheme\": \"Other\", \"credentials\": \"foobar\"}\n\n\ndef test_security_http_base_with_whitespaces():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Other  foobar \"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"scheme\": \"Other\", \"credentials\": \"foobar\"}\n\n\ndef test_security_http_base_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Other\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBase\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPBase\": {\"type\": \"http\", \"scheme\": \"Other\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_base_description.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security.http import HTTPAuthorizationCredentials, HTTPBase\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPBase(scheme=\"Other\", description=\"Other Security Scheme\")\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: HTTPAuthorizationCredentials = Security(security)):\n    return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_base():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Other foobar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"scheme\": \"Other\", \"credentials\": \"foobar\"}\n\n\ndef test_security_http_base_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Other\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBase\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"HTTPBase\": {\n                        \"type\": \"http\",\n                        \"scheme\": \"Other\",\n                        \"description\": \"Other Security Scheme\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_base_optional.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security.http import HTTPAuthorizationCredentials, HTTPBase\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPBase(scheme=\"Other\", auto_error=False)\n\n\n@app.get(\"/users/me\")\ndef read_current_user(\n    credentials: HTTPAuthorizationCredentials | None = Security(security),\n):\n    if credentials is None:\n        return {\"msg\": \"Create an account first\"}\n    return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_base():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Other foobar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"scheme\": \"Other\", \"credentials\": \"foobar\"}\n\n\ndef test_security_http_base_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBase\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPBase\": {\"type\": \"http\", \"scheme\": \"Other\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_basic_optional.py",
    "content": "from base64 import b64encode\n\nfrom fastapi import FastAPI, Security\nfrom fastapi.security import HTTPBasic, HTTPBasicCredentials\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPBasic(auto_error=False)\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: HTTPBasicCredentials | None = Security(security)):\n    if credentials is None:\n        return {\"msg\": \"Create an account first\"}\n    return {\"username\": credentials.username, \"password\": credentials.password}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_basic():\n    response = client.get(\"/users/me\", auth=(\"john\", \"secret\"))\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"john\", \"password\": \"secret\"}\n\n\ndef test_security_http_basic_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_security_http_basic_invalid_credentials():\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Basic notabase64token\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == \"Basic\"\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_security_http_basic_non_basic_credentials():\n    payload = b64encode(b\"johnsecret\").decode(\"ascii\")\n    auth_header = f\"Basic {payload}\"\n    response = client.get(\"/users/me\", headers={\"Authorization\": auth_header})\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == \"Basic\"\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBasic\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPBasic\": {\"type\": \"http\", \"scheme\": \"basic\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_basic_realm.py",
    "content": "from base64 import b64encode\n\nfrom fastapi import FastAPI, Security\nfrom fastapi.security import HTTPBasic, HTTPBasicCredentials\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPBasic(realm=\"simple\")\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: HTTPBasicCredentials = Security(security)):\n    return {\"username\": credentials.username, \"password\": credentials.password}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_basic():\n    response = client.get(\"/users/me\", auth=(\"john\", \"secret\"))\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"john\", \"password\": \"secret\"}\n\n\ndef test_security_http_basic_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == 'Basic realm=\"simple\"'\n\n\ndef test_security_http_basic_invalid_credentials():\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Basic notabase64token\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == 'Basic realm=\"simple\"'\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_security_http_basic_non_basic_credentials():\n    payload = b64encode(b\"johnsecret\").decode(\"ascii\")\n    auth_header = f\"Basic {payload}\"\n    response = client.get(\"/users/me\", headers={\"Authorization\": auth_header})\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == 'Basic realm=\"simple\"'\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBasic\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPBasic\": {\"type\": \"http\", \"scheme\": \"basic\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_basic_realm_description.py",
    "content": "from base64 import b64encode\n\nfrom fastapi import FastAPI, Security\nfrom fastapi.security import HTTPBasic, HTTPBasicCredentials\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPBasic(realm=\"simple\", description=\"HTTPBasic scheme\")\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: HTTPBasicCredentials = Security(security)):\n    return {\"username\": credentials.username, \"password\": credentials.password}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_basic():\n    response = client.get(\"/users/me\", auth=(\"john\", \"secret\"))\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"john\", \"password\": \"secret\"}\n\n\ndef test_security_http_basic_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == 'Basic realm=\"simple\"'\n\n\ndef test_security_http_basic_invalid_credentials():\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Basic notabase64token\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == 'Basic realm=\"simple\"'\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_security_http_basic_non_basic_credentials():\n    payload = b64encode(b\"johnsecret\").decode(\"ascii\")\n    auth_header = f\"Basic {payload}\"\n    response = client.get(\"/users/me\", headers={\"Authorization\": auth_header})\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == 'Basic realm=\"simple\"'\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBasic\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"HTTPBasic\": {\n                        \"type\": \"http\",\n                        \"scheme\": \"basic\",\n                        \"description\": \"HTTPBasic scheme\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_bearer.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security import HTTPAuthorizationCredentials, HTTPBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPBearer()\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: HTTPAuthorizationCredentials = Security(security)):\n    return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_bearer():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer foobar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"scheme\": \"Bearer\", \"credentials\": \"foobar\"}\n\n\ndef test_security_http_bearer_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_security_http_bearer_incorrect_scheme_credentials():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Basic notreally\"})\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPBearer\": {\"type\": \"http\", \"scheme\": \"bearer\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_bearer_description.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security import HTTPAuthorizationCredentials, HTTPBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPBearer(description=\"HTTP Bearer token scheme\")\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: HTTPAuthorizationCredentials = Security(security)):\n    return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_bearer():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer foobar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"scheme\": \"Bearer\", \"credentials\": \"foobar\"}\n\n\ndef test_security_http_bearer_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_security_http_bearer_incorrect_scheme_credentials():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Basic notreally\"})\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"HTTPBearer\": {\n                        \"type\": \"http\",\n                        \"scheme\": \"bearer\",\n                        \"description\": \"HTTP Bearer token scheme\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_bearer_optional.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security import HTTPAuthorizationCredentials, HTTPBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPBearer(auto_error=False)\n\n\n@app.get(\"/users/me\")\ndef read_current_user(\n    credentials: HTTPAuthorizationCredentials | None = Security(security),\n):\n    if credentials is None:\n        return {\"msg\": \"Create an account first\"}\n    return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_bearer():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer foobar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"scheme\": \"Bearer\", \"credentials\": \"foobar\"}\n\n\ndef test_security_http_bearer_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_security_http_bearer_incorrect_scheme_credentials():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Basic notreally\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPBearer\": {\"type\": \"http\", \"scheme\": \"bearer\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_digest.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security import HTTPAuthorizationCredentials, HTTPDigest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPDigest()\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: HTTPAuthorizationCredentials = Security(security)):\n    return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_digest():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Digest foobar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"scheme\": \"Digest\", \"credentials\": \"foobar\"}\n\n\ndef test_security_http_digest_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Digest\"\n\n\ndef test_security_http_digest_incorrect_scheme_credentials():\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Other invalidauthorization\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Digest\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPDigest\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPDigest\": {\"type\": \"http\", \"scheme\": \"digest\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_digest_description.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security import HTTPAuthorizationCredentials, HTTPDigest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPDigest(description=\"HTTPDigest scheme\")\n\n\n@app.get(\"/users/me\")\ndef read_current_user(credentials: HTTPAuthorizationCredentials = Security(security)):\n    return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_digest():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Digest foobar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"scheme\": \"Digest\", \"credentials\": \"foobar\"}\n\n\ndef test_security_http_digest_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Digest\"\n\n\ndef test_security_http_digest_incorrect_scheme_credentials():\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Other invalidauthorization\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Digest\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPDigest\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"HTTPDigest\": {\n                        \"type\": \"http\",\n                        \"scheme\": \"digest\",\n                        \"description\": \"HTTPDigest scheme\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_http_digest_optional.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security import HTTPAuthorizationCredentials, HTTPDigest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nsecurity = HTTPDigest(auto_error=False)\n\n\n@app.get(\"/users/me\")\ndef read_current_user(\n    credentials: HTTPAuthorizationCredentials | None = Security(security),\n):\n    if credentials is None:\n        return {\"msg\": \"Create an account first\"}\n    return {\"scheme\": credentials.scheme, \"credentials\": credentials.credentials}\n\n\nclient = TestClient(app)\n\n\ndef test_security_http_digest():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Digest foobar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"scheme\": \"Digest\", \"credentials\": \"foobar\"}\n\n\ndef test_security_http_digest_no_credentials():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_security_http_digest_incorrect_scheme_credentials():\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Other invalidauthorization\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPDigest\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPDigest\": {\"type\": \"http\", \"scheme\": \"digest\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_oauth2.py",
    "content": "import pytest\nfrom fastapi import Depends, FastAPI, Security\nfrom fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\nreusable_oauth2 = OAuth2(\n    flows={\n        \"password\": {\n            \"tokenUrl\": \"token\",\n            \"scopes\": {\"read:users\": \"Read the users\", \"write:users\": \"Create users\"},\n        }\n    }\n)\n\n\nclass User(BaseModel):\n    username: str\n\n\n# Here we use string annotations to test them\ndef get_current_user(oauth_header: \"str\" = Security(reusable_oauth2)):\n    user = User(username=oauth_header)\n    return user\n\n\n@app.post(\"/login\")\n# Here we use string annotations to test them\ndef login(form_data: \"OAuth2PasswordRequestFormStrict\" = Depends()):\n    return form_data\n\n\n@app.get(\"/users/me\")\n# Here we use string annotations to test them\ndef read_current_user(current_user: \"User\" = Depends(get_current_user)):\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_oauth2():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Bearer footokenbar\"}\n\n\ndef test_security_oauth2_password_other_header():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Other footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Other footokenbar\"}\n\n\ndef test_security_oauth2_password_bearer_no_header():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_strict_login_no_data():\n    response = client.post(\"/login\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"grant_type\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_strict_login_no_grant_type():\n    response = client.post(\"/login\", data={\"username\": \"johndoe\", \"password\": \"secret\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"grant_type\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    argnames=[\"grant_type\"],\n    argvalues=[\n        pytest.param(\"incorrect\", id=\"incorrect value\"),\n        pytest.param(\"passwordblah\", id=\"password with suffix\"),\n        pytest.param(\"blahpassword\", id=\"password with prefix\"),\n    ],\n)\ndef test_strict_login_incorrect_grant_type(grant_type: str):\n    response = client.post(\n        \"/login\",\n        data={\"username\": \"johndoe\", \"password\": \"secret\", \"grant_type\": grant_type},\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_pattern_mismatch\",\n                \"loc\": [\"body\", \"grant_type\"],\n                \"msg\": \"String should match pattern '^password$'\",\n                \"input\": grant_type,\n                \"ctx\": {\"pattern\": \"^password$\"},\n            }\n        ]\n    }\n\n\ndef test_strict_login_correct_grant_type():\n    response = client.post(\n        \"/login\",\n        data={\"username\": \"johndoe\", \"password\": \"secret\", \"grant_type\": \"password\"},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"grant_type\": \"password\",\n        \"username\": \"johndoe\",\n        \"password\": \"secret\",\n        \"scopes\": [],\n        \"client_id\": None,\n        \"client_secret\": None,\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/login\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Login\",\n                        \"operationId\": \"login_login_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_login_login_post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"OAuth2\": []}],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_login_login_post\": {\n                        \"title\": \"Body_login_login_post\",\n                        \"required\": [\"grant_type\", \"username\", \"password\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"grant_type\": {\n                                \"title\": \"Grant Type\",\n                                \"pattern\": \"^password$\",\n                                \"type\": \"string\",\n                            },\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"password\": {\"title\": \"Password\", \"type\": \"string\"},\n                            \"scope\": {\n                                \"title\": \"Scope\",\n                                \"type\": \"string\",\n                                \"default\": \"\",\n                            },\n                            \"client_id\": {\n                                \"title\": \"Client Id\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"client_secret\": {\n                                \"title\": \"Client Secret\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                },\n                \"securitySchemes\": {\n                    \"OAuth2\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\n                            \"password\": {\n                                \"scopes\": {\n                                    \"read:users\": \"Read the users\",\n                                    \"write:users\": \"Create users\",\n                                },\n                                \"tokenUrl\": \"token\",\n                            }\n                        },\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_oauth2_authorization_code_bearer.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security import OAuth2AuthorizationCodeBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\noauth2_scheme = OAuth2AuthorizationCodeBearer(\n    authorizationUrl=\"authorize\", tokenUrl=\"token\", auto_error=True\n)\n\n\n@app.get(\"/items/\")\nasync def read_items(token: str | None = Security(oauth2_scheme)):\n    return {\"token\": token}\n\n\nclient = TestClient(app)\n\n\ndef test_no_token():\n    response = client.get(\"/items\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_incorrect_token():\n    response = client.get(\"/items\", headers={\"Authorization\": \"Non-existent testtoken\"})\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_token():\n    response = client.get(\"/items\", headers={\"Authorization\": \"Bearer testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"token\": \"testtoken\"}\n\n\ndef test_token_with_whitespaces():\n    response = client.get(\"/items\", headers={\"Authorization\": \"Bearer  testtoken \"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"token\": \"testtoken\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"security\": [{\"OAuth2AuthorizationCodeBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OAuth2AuthorizationCodeBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\n                            \"authorizationCode\": {\n                                \"authorizationUrl\": \"authorize\",\n                                \"tokenUrl\": \"token\",\n                                \"scopes\": {},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_oauth2_authorization_code_bearer_description.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security import OAuth2AuthorizationCodeBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\noauth2_scheme = OAuth2AuthorizationCodeBearer(\n    authorizationUrl=\"authorize\",\n    tokenUrl=\"token\",\n    description=\"OAuth2 Code Bearer\",\n    auto_error=True,\n)\n\n\n@app.get(\"/items/\")\nasync def read_items(token: str | None = Security(oauth2_scheme)):\n    return {\"token\": token}\n\n\nclient = TestClient(app)\n\n\ndef test_no_token():\n    response = client.get(\"/items\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_incorrect_token():\n    response = client.get(\"/items\", headers={\"Authorization\": \"Non-existent testtoken\"})\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_token():\n    response = client.get(\"/items\", headers={\"Authorization\": \"Bearer testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"token\": \"testtoken\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"security\": [{\"OAuth2AuthorizationCodeBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OAuth2AuthorizationCodeBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\n                            \"authorizationCode\": {\n                                \"authorizationUrl\": \"authorize\",\n                                \"tokenUrl\": \"token\",\n                                \"scopes\": {},\n                            }\n                        },\n                        \"description\": \"OAuth2 Code Bearer\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py",
    "content": "# Ref: https://github.com/fastapi/fastapi/issues/14454\n\nfrom typing import Annotated\n\nfrom fastapi import APIRouter, Depends, FastAPI, Security\nfrom fastapi.security import OAuth2AuthorizationCodeBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\noauth2_scheme = OAuth2AuthorizationCodeBearer(\n    authorizationUrl=\"authorize\",\n    tokenUrl=\"token\",\n    auto_error=True,\n    scopes={\"read\": \"Read access\", \"write\": \"Write access\"},\n)\n\n\nasync def get_token(token: Annotated[str, Depends(oauth2_scheme)]) -> str:\n    return token\n\n\napp = FastAPI(dependencies=[Depends(get_token)])\n\n\n@app.get(\"/\")\nasync def root():\n    return {\"message\": \"Hello World\"}\n\n\n@app.get(\n    \"/with-oauth2-scheme\",\n    dependencies=[Security(oauth2_scheme, scopes=[\"read\", \"write\"])],\n)\nasync def read_with_oauth2_scheme():\n    return {\"message\": \"Admin Access\"}\n\n\n@app.get(\n    \"/with-get-token\", dependencies=[Security(get_token, scopes=[\"read\", \"write\"])]\n)\nasync def read_with_get_token():\n    return {\"message\": \"Admin Access\"}\n\n\nrouter = APIRouter(dependencies=[Security(oauth2_scheme, scopes=[\"read\"])])\n\n\n@router.get(\"/items/\")\nasync def read_items(token: str | None = Depends(oauth2_scheme)):\n    return {\"token\": token}\n\n\n@router.post(\"/items/\")\nasync def create_item(\n    token: str | None = Security(oauth2_scheme, scopes=[\"read\", \"write\"]),\n):\n    return {\"token\": token}\n\n\napp.include_router(router)\n\nclient = TestClient(app)\n\n\ndef test_root():\n    response = client.get(\"/\", headers={\"Authorization\": \"Bearer testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello World\"}\n\n\ndef test_read_with_oauth2_scheme():\n    response = client.get(\n        \"/with-oauth2-scheme\", headers={\"Authorization\": \"Bearer testtoken\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Admin Access\"}\n\n\ndef test_read_with_get_token():\n    response = client.get(\n        \"/with-get-token\", headers={\"Authorization\": \"Bearer testtoken\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Admin Access\"}\n\n\ndef test_read_token():\n    response = client.get(\"/items/\", headers={\"Authorization\": \"Bearer testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"token\": \"testtoken\"}\n\n\ndef test_create_token():\n    response = client.post(\"/items/\", headers={\"Authorization\": \"Bearer testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"token\": \"testtoken\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Root\",\n                        \"operationId\": \"root__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"security\": [{\"OAuth2AuthorizationCodeBearer\": []}],\n                    }\n                },\n                \"/with-oauth2-scheme\": {\n                    \"get\": {\n                        \"summary\": \"Read With Oauth2 Scheme\",\n                        \"operationId\": \"read_with_oauth2_scheme_with_oauth2_scheme_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"security\": [\n                            {\"OAuth2AuthorizationCodeBearer\": [\"read\", \"write\"]}\n                        ],\n                    }\n                },\n                \"/with-get-token\": {\n                    \"get\": {\n                        \"summary\": \"Read With Get Token\",\n                        \"operationId\": \"read_with_get_token_with_get_token_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"security\": [\n                            {\"OAuth2AuthorizationCodeBearer\": [\"read\", \"write\"]}\n                        ],\n                    }\n                },\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"security\": [\n                            {\"OAuth2AuthorizationCodeBearer\": [\"read\"]},\n                        ],\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"security\": [\n                            {\"OAuth2AuthorizationCodeBearer\": [\"read\", \"write\"]},\n                        ],\n                    },\n                },\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OAuth2AuthorizationCodeBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\n                            \"authorizationCode\": {\n                                \"scopes\": {\n                                    \"read\": \"Read access\",\n                                    \"write\": \"Write access\",\n                                },\n                                \"authorizationUrl\": \"authorize\",\n                                \"tokenUrl\": \"token\",\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_oauth2_authorization_code_bearer_scopes_openapi_simple.py",
    "content": "# Ref: https://github.com/fastapi/fastapi/issues/14454\n\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI, Security\nfrom fastapi.security import OAuth2AuthorizationCodeBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\noauth2_scheme = OAuth2AuthorizationCodeBearer(\n    authorizationUrl=\"api/oauth/authorize\",\n    tokenUrl=\"/api/oauth/token\",\n    scopes={\"read\": \"Read access\", \"write\": \"Write access\"},\n)\n\n\nasync def get_token(token: Annotated[str, Depends(oauth2_scheme)]) -> str:\n    return token\n\n\napp = FastAPI(dependencies=[Depends(get_token)])\n\n\n@app.get(\"/admin\", dependencies=[Security(get_token, scopes=[\"read\", \"write\"])])\nasync def read_admin():\n    return {\"message\": \"Admin Access\"}\n\n\nclient = TestClient(app)\n\n\ndef test_read_admin():\n    response = client.get(\"/admin\", headers={\"Authorization\": \"Bearer faketoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Admin Access\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/admin\": {\n                    \"get\": {\n                        \"summary\": \"Read Admin\",\n                        \"operationId\": \"read_admin_admin_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"security\": [\n                            {\"OAuth2AuthorizationCodeBearer\": [\"read\", \"write\"]}\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OAuth2AuthorizationCodeBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\n                            \"authorizationCode\": {\n                                \"scopes\": {\n                                    \"read\": \"Read access\",\n                                    \"write\": \"Write access\",\n                                },\n                                \"authorizationUrl\": \"api/oauth/authorize\",\n                                \"tokenUrl\": \"/api/oauth/token\",\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_oauth2_optional.py",
    "content": "import pytest\nfrom fastapi import Depends, FastAPI, Security\nfrom fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\nreusable_oauth2 = OAuth2(\n    flows={\n        \"password\": {\n            \"tokenUrl\": \"token\",\n            \"scopes\": {\"read:users\": \"Read the users\", \"write:users\": \"Create users\"},\n        }\n    },\n    auto_error=False,\n)\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str | None = Security(reusable_oauth2)):\n    if oauth_header is None:\n        return None\n    user = User(username=oauth_header)\n    return user\n\n\n@app.post(\"/login\")\ndef login(form_data: OAuth2PasswordRequestFormStrict = Depends()):\n    return form_data\n\n\n@app.get(\"/users/me\")\ndef read_users_me(current_user: User | None = Depends(get_current_user)):\n    if current_user is None:\n        return {\"msg\": \"Create an account first\"}\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_oauth2():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Bearer footokenbar\"}\n\n\ndef test_security_oauth2_password_other_header():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Other footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Other footokenbar\"}\n\n\ndef test_security_oauth2_password_bearer_no_header():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_strict_login_no_data():\n    response = client.post(\"/login\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"grant_type\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_strict_login_no_grant_type():\n    response = client.post(\"/login\", data={\"username\": \"johndoe\", \"password\": \"secret\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"grant_type\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    argnames=[\"grant_type\"],\n    argvalues=[\n        pytest.param(\"incorrect\", id=\"incorrect value\"),\n        pytest.param(\"passwordblah\", id=\"password with suffix\"),\n        pytest.param(\"blahpassword\", id=\"password with prefix\"),\n    ],\n)\ndef test_strict_login_incorrect_grant_type(grant_type: str):\n    response = client.post(\n        \"/login\",\n        data={\"username\": \"johndoe\", \"password\": \"secret\", \"grant_type\": grant_type},\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_pattern_mismatch\",\n                \"loc\": [\"body\", \"grant_type\"],\n                \"msg\": \"String should match pattern '^password$'\",\n                \"input\": grant_type,\n                \"ctx\": {\"pattern\": \"^password$\"},\n            }\n        ]\n    }\n\n\ndef test_strict_login_correct_data():\n    response = client.post(\n        \"/login\",\n        data={\"username\": \"johndoe\", \"password\": \"secret\", \"grant_type\": \"password\"},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"grant_type\": \"password\",\n        \"username\": \"johndoe\",\n        \"password\": \"secret\",\n        \"scopes\": [],\n        \"client_id\": None,\n        \"client_secret\": None,\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/login\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Login\",\n                        \"operationId\": \"login_login_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_login_login_post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Users Me\",\n                        \"operationId\": \"read_users_me_users_me_get\",\n                        \"security\": [{\"OAuth2\": []}],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_login_login_post\": {\n                        \"title\": \"Body_login_login_post\",\n                        \"required\": [\"grant_type\", \"username\", \"password\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"grant_type\": {\n                                \"title\": \"Grant Type\",\n                                \"pattern\": \"^password$\",\n                                \"type\": \"string\",\n                            },\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"password\": {\"title\": \"Password\", \"type\": \"string\"},\n                            \"scope\": {\n                                \"title\": \"Scope\",\n                                \"type\": \"string\",\n                                \"default\": \"\",\n                            },\n                            \"client_id\": {\n                                \"title\": \"Client Id\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"client_secret\": {\n                                \"title\": \"Client Secret\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                },\n                \"securitySchemes\": {\n                    \"OAuth2\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\n                            \"password\": {\n                                \"scopes\": {\n                                    \"read:users\": \"Read the users\",\n                                    \"write:users\": \"Create users\",\n                                },\n                                \"tokenUrl\": \"token\",\n                            }\n                        },\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_oauth2_optional_description.py",
    "content": "import pytest\nfrom fastapi import Depends, FastAPI, Security\nfrom fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\nreusable_oauth2 = OAuth2(\n    flows={\n        \"password\": {\n            \"tokenUrl\": \"token\",\n            \"scopes\": {\"read:users\": \"Read the users\", \"write:users\": \"Create users\"},\n        }\n    },\n    description=\"OAuth2 security scheme\",\n    auto_error=False,\n)\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str | None = Security(reusable_oauth2)):\n    if oauth_header is None:\n        return None\n    user = User(username=oauth_header)\n    return user\n\n\n@app.post(\"/login\")\ndef login(form_data: OAuth2PasswordRequestFormStrict = Depends()):\n    return form_data\n\n\n@app.get(\"/users/me\")\ndef read_users_me(current_user: User | None = Depends(get_current_user)):\n    if current_user is None:\n        return {\"msg\": \"Create an account first\"}\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_oauth2():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Bearer footokenbar\"}\n\n\ndef test_security_oauth2_password_other_header():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Other footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Other footokenbar\"}\n\n\ndef test_security_oauth2_password_bearer_no_header():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_strict_login_None():\n    response = client.post(\"/login\", data=None)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"grant_type\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_strict_login_no_grant_type():\n    response = client.post(\"/login\", data={\"username\": \"johndoe\", \"password\": \"secret\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"grant_type\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\n@pytest.mark.parametrize(\n    argnames=[\"grant_type\"],\n    argvalues=[\n        pytest.param(\"incorrect\", id=\"incorrect value\"),\n        pytest.param(\"passwordblah\", id=\"password with suffix\"),\n        pytest.param(\"blahpassword\", id=\"password with prefix\"),\n    ],\n)\ndef test_strict_login_incorrect_grant_type(grant_type: str):\n    response = client.post(\n        \"/login\",\n        data={\"username\": \"johndoe\", \"password\": \"secret\", \"grant_type\": grant_type},\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_pattern_mismatch\",\n                \"loc\": [\"body\", \"grant_type\"],\n                \"msg\": \"String should match pattern '^password$'\",\n                \"input\": grant_type,\n                \"ctx\": {\"pattern\": \"^password$\"},\n            }\n        ]\n    }\n\n\ndef test_strict_login_correct_correct_grant_type():\n    response = client.post(\n        \"/login\",\n        data={\"username\": \"johndoe\", \"password\": \"secret\", \"grant_type\": \"password\"},\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"grant_type\": \"password\",\n        \"username\": \"johndoe\",\n        \"password\": \"secret\",\n        \"scopes\": [],\n        \"client_id\": None,\n        \"client_secret\": None,\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/login\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Login\",\n                        \"operationId\": \"login_login_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_login_login_post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Users Me\",\n                        \"operationId\": \"read_users_me_users_me_get\",\n                        \"security\": [{\"OAuth2\": []}],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_login_login_post\": {\n                        \"title\": \"Body_login_login_post\",\n                        \"required\": [\"grant_type\", \"username\", \"password\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"grant_type\": {\n                                \"title\": \"Grant Type\",\n                                \"pattern\": \"^password$\",\n                                \"type\": \"string\",\n                            },\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"password\": {\"title\": \"Password\", \"type\": \"string\"},\n                            \"scope\": {\n                                \"title\": \"Scope\",\n                                \"type\": \"string\",\n                                \"default\": \"\",\n                            },\n                            \"client_id\": {\n                                \"title\": \"Client Id\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"client_secret\": {\n                                \"title\": \"Client Secret\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                },\n                \"securitySchemes\": {\n                    \"OAuth2\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\n                            \"password\": {\n                                \"scopes\": {\n                                    \"read:users\": \"Read the users\",\n                                    \"write:users\": \"Create users\",\n                                },\n                                \"tokenUrl\": \"token\",\n                            }\n                        },\n                        \"description\": \"OAuth2 security scheme\",\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_oauth2_password_bearer_optional.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security import OAuth2PasswordBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\noauth2_scheme = OAuth2PasswordBearer(tokenUrl=\"/token\", auto_error=False)\n\n\n@app.get(\"/items/\")\nasync def read_items(token: str | None = Security(oauth2_scheme)):\n    if token is None:\n        return {\"msg\": \"Create an account first\"}\n    return {\"token\": token}\n\n\nclient = TestClient(app)\n\n\ndef test_no_token():\n    response = client.get(\"/items\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_token():\n    response = client.get(\"/items\", headers={\"Authorization\": \"Bearer testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"token\": \"testtoken\"}\n\n\ndef test_incorrect_token():\n    response = client.get(\"/items\", headers={\"Authorization\": \"Notexistent testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"security\": [{\"OAuth2PasswordBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OAuth2PasswordBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\"password\": {\"scopes\": {}, \"tokenUrl\": \"/token\"}},\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_oauth2_password_bearer_optional_description.py",
    "content": "from fastapi import FastAPI, Security\nfrom fastapi.security import OAuth2PasswordBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\noauth2_scheme = OAuth2PasswordBearer(\n    tokenUrl=\"/token\",\n    description=\"OAuth2PasswordBearer security scheme\",\n    auto_error=False,\n)\n\n\n@app.get(\"/items/\")\nasync def read_items(token: str | None = Security(oauth2_scheme)):\n    if token is None:\n        return {\"msg\": \"Create an account first\"}\n    return {\"token\": token}\n\n\nclient = TestClient(app)\n\n\ndef test_no_token():\n    response = client.get(\"/items\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_token():\n    response = client.get(\"/items\", headers={\"Authorization\": \"Bearer testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"token\": \"testtoken\"}\n\n\ndef test_incorrect_token():\n    response = client.get(\"/items\", headers={\"Authorization\": \"Notexistent testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"security\": [{\"OAuth2PasswordBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OAuth2PasswordBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\"password\": {\"scopes\": {}, \"tokenUrl\": \"/token\"}},\n                        \"description\": \"OAuth2PasswordBearer security scheme\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_openid_connect.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security.open_id_connect_url import OpenIdConnect\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\noid = OpenIdConnect(openIdConnectUrl=\"/openid\")\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str = Security(oid)):\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User = Depends(get_current_user)):\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_oauth2():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Bearer footokenbar\"}\n\n\ndef test_security_oauth2_password_other_header():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Other footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Other footokenbar\"}\n\n\ndef test_security_oauth2_password_bearer_no_header():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"OpenIdConnect\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OpenIdConnect\": {\n                        \"type\": \"openIdConnect\",\n                        \"openIdConnectUrl\": \"/openid\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_openid_connect_description.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security.open_id_connect_url import OpenIdConnect\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\noid = OpenIdConnect(\n    openIdConnectUrl=\"/openid\", description=\"OpenIdConnect security scheme\"\n)\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str = Security(oid)):\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User = Depends(get_current_user)):\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_oauth2():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Bearer footokenbar\"}\n\n\ndef test_security_oauth2_password_other_header():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Other footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Other footokenbar\"}\n\n\ndef test_security_oauth2_password_bearer_no_header():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"OpenIdConnect\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OpenIdConnect\": {\n                        \"type\": \"openIdConnect\",\n                        \"openIdConnectUrl\": \"/openid\",\n                        \"description\": \"OpenIdConnect security scheme\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_openid_connect_optional.py",
    "content": "from fastapi import Depends, FastAPI, Security\nfrom fastapi.security.open_id_connect_url import OpenIdConnect\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\noid = OpenIdConnect(openIdConnectUrl=\"/openid\", auto_error=False)\n\n\nclass User(BaseModel):\n    username: str\n\n\ndef get_current_user(oauth_header: str | None = Security(oid)):\n    if oauth_header is None:\n        return None\n    user = User(username=oauth_header)\n    return user\n\n\n@app.get(\"/users/me\")\ndef read_current_user(current_user: User | None = Depends(get_current_user)):\n    if current_user is None:\n        return {\"msg\": \"Create an account first\"}\n    return current_user\n\n\nclient = TestClient(app)\n\n\ndef test_security_oauth2():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Bearer footokenbar\"}\n\n\ndef test_security_oauth2_password_other_header():\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Other footokenbar\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"Other footokenbar\"}\n\n\ndef test_security_oauth2_password_bearer_no_header():\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Create an account first\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"OpenIdConnect\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OpenIdConnect\": {\n                        \"type\": \"openIdConnect\",\n                        \"openIdConnectUrl\": \"/openid\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_security_scopes.py",
    "content": "from typing import Annotated\n\nimport pytest\nfrom fastapi import Depends, FastAPI, Security\nfrom fastapi.testclient import TestClient\n\n\n@pytest.fixture(name=\"call_counter\")\ndef call_counter_fixture():\n    return {\"count\": 0}\n\n\n@pytest.fixture(name=\"app\")\ndef app_fixture(call_counter: dict[str, int]):\n    def get_db():\n        call_counter[\"count\"] += 1\n        return f\"db_{call_counter['count']}\"\n\n    def get_user(db: Annotated[str, Depends(get_db)]):\n        return \"user\"\n\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def endpoint(\n        db: Annotated[str, Depends(get_db)],\n        user: Annotated[str, Security(get_user, scopes=[\"read\"])],\n    ):\n        return {\"db\": db}\n\n    return app\n\n\n@pytest.fixture(name=\"client\")\ndef client_fixture(app: FastAPI):\n    return TestClient(app)\n\n\ndef test_security_scopes_dependency_called_once(\n    client: TestClient, call_counter: dict[str, int]\n):\n    response = client.get(\"/\")\n\n    assert response.status_code == 200\n    assert call_counter[\"count\"] == 1\n"
  },
  {
    "path": "tests/test_security_scopes_dont_propagate.py",
    "content": "# Ref: https://github.com/tiangolo/fastapi/issues/5623\n\nfrom typing import Annotated, Any\n\nfrom fastapi import FastAPI, Security\nfrom fastapi.security import SecurityScopes\nfrom fastapi.testclient import TestClient\n\n\nasync def security1(scopes: SecurityScopes):\n    return scopes.scopes\n\n\nasync def security2(scopes: SecurityScopes):\n    return scopes.scopes\n\n\nasync def dep3(\n    dep1: Annotated[list[str], Security(security1, scopes=[\"scope1\"])],\n    dep2: Annotated[list[str], Security(security2, scopes=[\"scope2\"])],\n):\n    return {\"dep1\": dep1, \"dep2\": dep2}\n\n\napp = FastAPI()\n\n\n@app.get(\"/scopes\")\ndef get_scopes(\n    dep3: Annotated[dict[str, Any], Security(dep3, scopes=[\"scope3\"])],\n):\n    return dep3\n\n\nclient = TestClient(app)\n\n\ndef test_security_scopes_dont_propagate():\n    response = client.get(\"/scopes\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"dep1\": [\"scope3\", \"scope1\"],\n        \"dep2\": [\"scope3\", \"scope2\"],\n    }\n"
  },
  {
    "path": "tests/test_security_scopes_sub_dependency.py",
    "content": "# Ref: https://github.com/fastapi/fastapi/discussions/6024#discussioncomment-8541913\n\n\nfrom typing import Annotated\n\nimport pytest\nfrom fastapi import Depends, FastAPI, Security\nfrom fastapi.security import SecurityScopes\nfrom fastapi.testclient import TestClient\n\n\n@pytest.fixture(name=\"call_counts\")\ndef call_counts_fixture():\n    return {\n        \"get_db_session\": 0,\n        \"get_current_user\": 0,\n        \"get_user_me\": 0,\n        \"get_user_items\": 0,\n    }\n\n\n@pytest.fixture(name=\"app\")\ndef app_fixture(call_counts: dict[str, int]):\n    def get_db_session():\n        call_counts[\"get_db_session\"] += 1\n        return f\"db_session_{call_counts['get_db_session']}\"\n\n    def get_current_user(\n        security_scopes: SecurityScopes,\n        db_session: Annotated[str, Depends(get_db_session)],\n    ):\n        call_counts[\"get_current_user\"] += 1\n        return {\n            \"user\": f\"user_{call_counts['get_current_user']}\",\n            \"scopes\": security_scopes.scopes,\n            \"db_session\": db_session,\n        }\n\n    def get_user_me(\n        current_user: Annotated[dict, Security(get_current_user, scopes=[\"me\"])],\n    ):\n        call_counts[\"get_user_me\"] += 1\n        return {\n            \"user_me\": f\"user_me_{call_counts['get_user_me']}\",\n            \"current_user\": current_user,\n        }\n\n    def get_user_items(\n        user_me: Annotated[dict, Depends(get_user_me)],\n    ):\n        call_counts[\"get_user_items\"] += 1\n        return {\n            \"user_items\": f\"user_items_{call_counts['get_user_items']}\",\n            \"user_me\": user_me,\n        }\n\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def path_operation(\n        user_me: Annotated[dict, Depends(get_user_me)],\n        user_items: Annotated[dict, Security(get_user_items, scopes=[\"items\"])],\n    ):\n        return {\n            \"user_me\": user_me,\n            \"user_items\": user_items,\n        }\n\n    return app\n\n\n@pytest.fixture(name=\"client\")\ndef client_fixture(app: FastAPI):\n    return TestClient(app)\n\n\ndef test_security_scopes_sub_dependency_caching(\n    client: TestClient, call_counts: dict[str, int]\n):\n    response = client.get(\"/\")\n\n    assert response.status_code == 200\n    assert call_counts[\"get_db_session\"] == 1\n    assert call_counts[\"get_current_user\"] == 2\n    assert call_counts[\"get_user_me\"] == 2\n    assert call_counts[\"get_user_items\"] == 1\n    assert response.json() == {\n        \"user_me\": {\n            \"user_me\": \"user_me_1\",\n            \"current_user\": {\n                \"user\": \"user_1\",\n                \"scopes\": [\"me\"],\n                \"db_session\": \"db_session_1\",\n            },\n        },\n        \"user_items\": {\n            \"user_items\": \"user_items_1\",\n            \"user_me\": {\n                \"user_me\": \"user_me_2\",\n                \"current_user\": {\n                    \"user\": \"user_2\",\n                    \"scopes\": [\"items\", \"me\"],\n                    \"db_session\": \"db_session_1\",\n                },\n            },\n        },\n    }\n"
  },
  {
    "path": "tests/test_serialize_response.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float | None = None\n    owner_ids: list[int] | None = None\n\n\n@app.get(\"/items/valid\", response_model=Item)\ndef get_valid():\n    return {\"name\": \"valid\", \"price\": 1.0}\n\n\n@app.get(\"/items/coerce\", response_model=Item)\ndef get_coerce():\n    return {\"name\": \"coerce\", \"price\": \"1.0\"}\n\n\n@app.get(\"/items/validlist\", response_model=list[Item])\ndef get_validlist():\n    return [\n        {\"name\": \"foo\"},\n        {\"name\": \"bar\", \"price\": 1.0},\n        {\"name\": \"baz\", \"price\": 2.0, \"owner_ids\": [1, 2, 3]},\n    ]\n\n\nclient = TestClient(app)\n\n\ndef test_valid():\n    response = client.get(\"/items/valid\")\n    response.raise_for_status()\n    assert response.json() == {\"name\": \"valid\", \"price\": 1.0, \"owner_ids\": None}\n\n\ndef test_coerce():\n    response = client.get(\"/items/coerce\")\n    response.raise_for_status()\n    assert response.json() == {\"name\": \"coerce\", \"price\": 1.0, \"owner_ids\": None}\n\n\ndef test_validlist():\n    response = client.get(\"/items/validlist\")\n    response.raise_for_status()\n    assert response.json() == [\n        {\"name\": \"foo\", \"price\": None, \"owner_ids\": None},\n        {\"name\": \"bar\", \"price\": 1.0, \"owner_ids\": None},\n        {\"name\": \"baz\", \"price\": 2.0, \"owner_ids\": [1, 2, 3]},\n    ]\n"
  },
  {
    "path": "tests/test_serialize_response_dataclass.py",
    "content": "from dataclasses import dataclass\nfrom datetime import datetime\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@dataclass\nclass Item:\n    name: str\n    date: datetime\n    price: float | None = None\n    owner_ids: list[int] | None = None\n\n\n@app.get(\"/items/valid\", response_model=Item)\ndef get_valid():\n    return {\"name\": \"valid\", \"date\": datetime(2021, 7, 26), \"price\": 1.0}\n\n\n@app.get(\"/items/object\", response_model=Item)\ndef get_object():\n    return Item(\n        name=\"object\", date=datetime(2021, 7, 26), price=1.0, owner_ids=[1, 2, 3]\n    )\n\n\n@app.get(\"/items/coerce\", response_model=Item)\ndef get_coerce():\n    return {\"name\": \"coerce\", \"date\": datetime(2021, 7, 26).isoformat(), \"price\": \"1.0\"}\n\n\n@app.get(\"/items/validlist\", response_model=list[Item])\ndef get_validlist():\n    return [\n        {\"name\": \"foo\", \"date\": datetime(2021, 7, 26)},\n        {\"name\": \"bar\", \"date\": datetime(2021, 7, 26), \"price\": 1.0},\n        {\n            \"name\": \"baz\",\n            \"date\": datetime(2021, 7, 26),\n            \"price\": 2.0,\n            \"owner_ids\": [1, 2, 3],\n        },\n    ]\n\n\n@app.get(\"/items/objectlist\", response_model=list[Item])\ndef get_objectlist():\n    return [\n        Item(name=\"foo\", date=datetime(2021, 7, 26)),\n        Item(name=\"bar\", date=datetime(2021, 7, 26), price=1.0),\n        Item(name=\"baz\", date=datetime(2021, 7, 26), price=2.0, owner_ids=[1, 2, 3]),\n    ]\n\n\n@app.get(\"/items/no-response-model/object\")\ndef get_no_response_model_object():\n    return Item(\n        name=\"object\", date=datetime(2021, 7, 26), price=1.0, owner_ids=[1, 2, 3]\n    )\n\n\n@app.get(\"/items/no-response-model/objectlist\")\ndef get_no_response_model_objectlist():\n    return [\n        Item(name=\"foo\", date=datetime(2021, 7, 26)),\n        Item(name=\"bar\", date=datetime(2021, 7, 26), price=1.0),\n        Item(name=\"baz\", date=datetime(2021, 7, 26), price=2.0, owner_ids=[1, 2, 3]),\n    ]\n\n\nclient = TestClient(app)\n\n\ndef test_valid():\n    response = client.get(\"/items/valid\")\n    response.raise_for_status()\n    assert response.json() == {\n        \"name\": \"valid\",\n        \"date\": datetime(2021, 7, 26).isoformat(),\n        \"price\": 1.0,\n        \"owner_ids\": None,\n    }\n\n\ndef test_object():\n    response = client.get(\"/items/object\")\n    response.raise_for_status()\n    assert response.json() == {\n        \"name\": \"object\",\n        \"date\": datetime(2021, 7, 26).isoformat(),\n        \"price\": 1.0,\n        \"owner_ids\": [1, 2, 3],\n    }\n\n\ndef test_coerce():\n    response = client.get(\"/items/coerce\")\n    response.raise_for_status()\n    assert response.json() == {\n        \"name\": \"coerce\",\n        \"date\": datetime(2021, 7, 26).isoformat(),\n        \"price\": 1.0,\n        \"owner_ids\": None,\n    }\n\n\ndef test_validlist():\n    response = client.get(\"/items/validlist\")\n    response.raise_for_status()\n    assert response.json() == [\n        {\n            \"name\": \"foo\",\n            \"date\": datetime(2021, 7, 26).isoformat(),\n            \"price\": None,\n            \"owner_ids\": None,\n        },\n        {\n            \"name\": \"bar\",\n            \"date\": datetime(2021, 7, 26).isoformat(),\n            \"price\": 1.0,\n            \"owner_ids\": None,\n        },\n        {\n            \"name\": \"baz\",\n            \"date\": datetime(2021, 7, 26).isoformat(),\n            \"price\": 2.0,\n            \"owner_ids\": [1, 2, 3],\n        },\n    ]\n\n\ndef test_objectlist():\n    response = client.get(\"/items/objectlist\")\n    response.raise_for_status()\n    assert response.json() == [\n        {\n            \"name\": \"foo\",\n            \"date\": datetime(2021, 7, 26).isoformat(),\n            \"price\": None,\n            \"owner_ids\": None,\n        },\n        {\n            \"name\": \"bar\",\n            \"date\": datetime(2021, 7, 26).isoformat(),\n            \"price\": 1.0,\n            \"owner_ids\": None,\n        },\n        {\n            \"name\": \"baz\",\n            \"date\": datetime(2021, 7, 26).isoformat(),\n            \"price\": 2.0,\n            \"owner_ids\": [1, 2, 3],\n        },\n    ]\n\n\ndef test_no_response_model_object():\n    response = client.get(\"/items/no-response-model/object\")\n    response.raise_for_status()\n    assert response.json() == {\n        \"name\": \"object\",\n        \"date\": datetime(2021, 7, 26).isoformat(),\n        \"price\": 1.0,\n        \"owner_ids\": [1, 2, 3],\n    }\n\n\ndef test_no_response_model_objectlist():\n    response = client.get(\"/items/no-response-model/objectlist\")\n    response.raise_for_status()\n    assert response.json() == [\n        {\n            \"name\": \"foo\",\n            \"date\": datetime(2021, 7, 26).isoformat(),\n            \"price\": None,\n            \"owner_ids\": None,\n        },\n        {\n            \"name\": \"bar\",\n            \"date\": datetime(2021, 7, 26).isoformat(),\n            \"price\": 1.0,\n            \"owner_ids\": None,\n        },\n        {\n            \"name\": \"baz\",\n            \"date\": datetime(2021, 7, 26).isoformat(),\n            \"price\": 2.0,\n            \"owner_ids\": [1, 2, 3],\n        },\n    ]\n"
  },
  {
    "path": "tests/test_serialize_response_model.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel, Field\nfrom starlette.testclient import TestClient\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str = Field(alias=\"aliased_name\")\n    price: float | None = None\n    owner_ids: list[int] | None = None\n\n\n@app.get(\"/items/valid\", response_model=Item)\ndef get_valid():\n    return Item(aliased_name=\"valid\", price=1.0)\n\n\n@app.get(\"/items/coerce\", response_model=Item)\ndef get_coerce():\n    return Item(aliased_name=\"coerce\", price=\"1.0\")\n\n\n@app.get(\"/items/validlist\", response_model=list[Item])\ndef get_validlist():\n    return [\n        Item(aliased_name=\"foo\"),\n        Item(aliased_name=\"bar\", price=1.0),\n        Item(aliased_name=\"baz\", price=2.0, owner_ids=[1, 2, 3]),\n    ]\n\n\n@app.get(\"/items/validdict\", response_model=dict[str, Item])\ndef get_validdict():\n    return {\n        \"k1\": Item(aliased_name=\"foo\"),\n        \"k2\": Item(aliased_name=\"bar\", price=1.0),\n        \"k3\": Item(aliased_name=\"baz\", price=2.0, owner_ids=[1, 2, 3]),\n    }\n\n\n@app.get(\n    \"/items/valid-exclude-unset\", response_model=Item, response_model_exclude_unset=True\n)\ndef get_valid_exclude_unset():\n    return Item(aliased_name=\"valid\", price=1.0)\n\n\n@app.get(\n    \"/items/coerce-exclude-unset\",\n    response_model=Item,\n    response_model_exclude_unset=True,\n)\ndef get_coerce_exclude_unset():\n    return Item(aliased_name=\"coerce\", price=\"1.0\")\n\n\n@app.get(\n    \"/items/validlist-exclude-unset\",\n    response_model=list[Item],\n    response_model_exclude_unset=True,\n)\ndef get_validlist_exclude_unset():\n    return [\n        Item(aliased_name=\"foo\"),\n        Item(aliased_name=\"bar\", price=1.0),\n        Item(aliased_name=\"baz\", price=2.0, owner_ids=[1, 2, 3]),\n    ]\n\n\n@app.get(\n    \"/items/validdict-exclude-unset\",\n    response_model=dict[str, Item],\n    response_model_exclude_unset=True,\n)\ndef get_validdict_exclude_unset():\n    return {\n        \"k1\": Item(aliased_name=\"foo\"),\n        \"k2\": Item(aliased_name=\"bar\", price=1.0),\n        \"k3\": Item(aliased_name=\"baz\", price=2.0, owner_ids=[1, 2, 3]),\n    }\n\n\nclient = TestClient(app)\n\n\ndef test_valid():\n    response = client.get(\"/items/valid\")\n    response.raise_for_status()\n    assert response.json() == {\"aliased_name\": \"valid\", \"price\": 1.0, \"owner_ids\": None}\n\n\ndef test_coerce():\n    response = client.get(\"/items/coerce\")\n    response.raise_for_status()\n    assert response.json() == {\n        \"aliased_name\": \"coerce\",\n        \"price\": 1.0,\n        \"owner_ids\": None,\n    }\n\n\ndef test_validlist():\n    response = client.get(\"/items/validlist\")\n    response.raise_for_status()\n    assert response.json() == [\n        {\"aliased_name\": \"foo\", \"price\": None, \"owner_ids\": None},\n        {\"aliased_name\": \"bar\", \"price\": 1.0, \"owner_ids\": None},\n        {\"aliased_name\": \"baz\", \"price\": 2.0, \"owner_ids\": [1, 2, 3]},\n    ]\n\n\ndef test_validdict():\n    response = client.get(\"/items/validdict\")\n    response.raise_for_status()\n    assert response.json() == {\n        \"k1\": {\"aliased_name\": \"foo\", \"price\": None, \"owner_ids\": None},\n        \"k2\": {\"aliased_name\": \"bar\", \"price\": 1.0, \"owner_ids\": None},\n        \"k3\": {\"aliased_name\": \"baz\", \"price\": 2.0, \"owner_ids\": [1, 2, 3]},\n    }\n\n\ndef test_valid_exclude_unset():\n    response = client.get(\"/items/valid-exclude-unset\")\n    response.raise_for_status()\n    assert response.json() == {\"aliased_name\": \"valid\", \"price\": 1.0}\n\n\ndef test_coerce_exclude_unset():\n    response = client.get(\"/items/coerce-exclude-unset\")\n    response.raise_for_status()\n    assert response.json() == {\"aliased_name\": \"coerce\", \"price\": 1.0}\n\n\ndef test_validlist_exclude_unset():\n    response = client.get(\"/items/validlist-exclude-unset\")\n    response.raise_for_status()\n    assert response.json() == [\n        {\"aliased_name\": \"foo\"},\n        {\"aliased_name\": \"bar\", \"price\": 1.0},\n        {\"aliased_name\": \"baz\", \"price\": 2.0, \"owner_ids\": [1, 2, 3]},\n    ]\n\n\ndef test_validdict_exclude_unset():\n    response = client.get(\"/items/validdict-exclude-unset\")\n    response.raise_for_status()\n    assert response.json() == {\n        \"k1\": {\"aliased_name\": \"foo\"},\n        \"k2\": {\"aliased_name\": \"bar\", \"price\": 1.0},\n        \"k3\": {\"aliased_name\": \"baz\", \"price\": 2.0, \"owner_ids\": [1, 2, 3]},\n    }\n"
  },
  {
    "path": "tests/test_skip_defaults.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass SubModel(BaseModel):\n    a: str | None = \"foo\"\n\n\nclass Model(BaseModel):\n    x: int | None = None\n    sub: SubModel\n\n\nclass ModelSubclass(Model):\n    y: int\n    z: int = 0\n    w: int | None = None\n\n\nclass ModelDefaults(BaseModel):\n    w: str | None = None\n    x: str | None = None\n    y: str = \"y\"\n    z: str = \"z\"\n\n\n@app.get(\"/\", response_model=Model, response_model_exclude_unset=True)\ndef get_root() -> ModelSubclass:\n    return ModelSubclass(sub={}, y=1, z=0)\n\n\n@app.get(\n    \"/exclude_unset\", response_model=ModelDefaults, response_model_exclude_unset=True\n)\ndef get_exclude_unset() -> ModelDefaults:\n    return ModelDefaults(x=None, y=\"y\")\n\n\n@app.get(\n    \"/exclude_defaults\",\n    response_model=ModelDefaults,\n    response_model_exclude_defaults=True,\n)\ndef get_exclude_defaults() -> ModelDefaults:\n    return ModelDefaults(x=None, y=\"y\")\n\n\n@app.get(\n    \"/exclude_none\", response_model=ModelDefaults, response_model_exclude_none=True\n)\ndef get_exclude_none() -> ModelDefaults:\n    return ModelDefaults(x=None, y=\"y\")\n\n\n@app.get(\n    \"/exclude_unset_none\",\n    response_model=ModelDefaults,\n    response_model_exclude_unset=True,\n    response_model_exclude_none=True,\n)\ndef get_exclude_unset_none() -> ModelDefaults:\n    return ModelDefaults(x=None, y=\"y\")\n\n\nclient = TestClient(app)\n\n\ndef test_return_defaults():\n    response = client.get(\"/\")\n    assert response.json() == {\"sub\": {}}\n\n\ndef test_return_exclude_unset():\n    response = client.get(\"/exclude_unset\")\n    assert response.json() == {\"x\": None, \"y\": \"y\"}\n\n\ndef test_return_exclude_defaults():\n    response = client.get(\"/exclude_defaults\")\n    assert response.json() == {}\n\n\ndef test_return_exclude_none():\n    response = client.get(\"/exclude_none\")\n    assert response.json() == {\"y\": \"y\", \"z\": \"z\"}\n\n\ndef test_return_exclude_unset_none():\n    response = client.get(\"/exclude_unset_none\")\n    assert response.json() == {\"y\": \"y\"}\n"
  },
  {
    "path": "tests/test_sse.py",
    "content": "import asyncio\nimport time\nfrom collections.abc import AsyncIterable, Iterable\n\nimport fastapi.routing\nimport pytest\nfrom fastapi import APIRouter, FastAPI\nfrom fastapi.responses import EventSourceResponse\nfrom fastapi.sse import ServerSentEvent\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    description: str | None = None\n\n\nitems = [\n    Item(name=\"Plumbus\", description=\"A multi-purpose household device.\"),\n    Item(name=\"Portal Gun\", description=\"A portal opening device.\"),\n    Item(name=\"Meeseeks Box\", description=\"A box that summons a Meeseeks.\"),\n]\n\n\napp = FastAPI()\n\n\n@app.get(\"/items/stream\", response_class=EventSourceResponse)\nasync def sse_items() -> AsyncIterable[Item]:\n    for item in items:\n        yield item\n\n\n@app.get(\"/items/stream-sync\", response_class=EventSourceResponse)\ndef sse_items_sync() -> Iterable[Item]:\n    yield from items\n\n\n@app.get(\"/items/stream-no-annotation\", response_class=EventSourceResponse)\nasync def sse_items_no_annotation():\n    for item in items:\n        yield item\n\n\n@app.get(\"/items/stream-sync-no-annotation\", response_class=EventSourceResponse)\ndef sse_items_sync_no_annotation():\n    yield from items\n\n\n@app.get(\"/items/stream-dict\", response_class=EventSourceResponse)\nasync def sse_items_dict():\n    for item in items:\n        yield {\"name\": item.name, \"description\": item.description}\n\n\n@app.get(\"/items/stream-sse-event\", response_class=EventSourceResponse)\nasync def sse_items_event():\n    yield ServerSentEvent(data=\"hello\", event=\"greeting\", id=\"1\")\n    yield ServerSentEvent(data={\"key\": \"value\"}, event=\"json-data\", id=\"2\")\n    yield ServerSentEvent(comment=\"just a comment\")\n    yield ServerSentEvent(data=\"retry-test\", retry=5000)\n\n\n@app.get(\"/items/stream-mixed\", response_class=EventSourceResponse)\nasync def sse_items_mixed() -> AsyncIterable[Item]:\n    yield items[0]\n    yield ServerSentEvent(data=\"custom-event\", event=\"special\")\n    yield items[1]\n\n\n@app.get(\"/items/stream-string\", response_class=EventSourceResponse)\nasync def sse_items_string():\n    yield ServerSentEvent(data=\"plain text data\")\n\n\n@app.post(\"/items/stream-post\", response_class=EventSourceResponse)\nasync def sse_items_post() -> AsyncIterable[Item]:\n    for item in items:\n        yield item\n\n\n@app.get(\"/items/stream-raw\", response_class=EventSourceResponse)\nasync def sse_items_raw():\n    yield ServerSentEvent(raw_data=\"plain text without quotes\")\n    yield ServerSentEvent(raw_data=\"<div>html fragment</div>\", event=\"html\")\n    yield ServerSentEvent(raw_data=\"cpu,87.3,1709145600\", event=\"csv\")\n\n\nrouter = APIRouter()\n\n\n@router.get(\"/events\", response_class=EventSourceResponse)\nasync def stream_events():\n    yield {\"msg\": \"hello\"}\n    yield {\"msg\": \"world\"}\n\n\napp.include_router(router, prefix=\"/api\")\n\n\n@pytest.fixture(name=\"client\")\ndef client_fixture():\n    with TestClient(app) as c:\n        yield c\n\n\ndef test_async_generator_with_model(client: TestClient):\n    response = client.get(\"/items/stream\")\n    assert response.status_code == 200\n    assert response.headers[\"content-type\"] == \"text/event-stream; charset=utf-8\"\n    assert response.headers[\"cache-control\"] == \"no-cache\"\n    assert response.headers[\"x-accel-buffering\"] == \"no\"\n\n    lines = response.text.strip().split(\"\\n\")\n    data_lines = [line for line in lines if line.startswith(\"data: \")]\n    assert len(data_lines) == 3\n    assert '\"name\":\"Plumbus\"' in data_lines[0] or '\"name\": \"Plumbus\"' in data_lines[0]\n    assert (\n        '\"name\":\"Portal Gun\"' in data_lines[1]\n        or '\"name\": \"Portal Gun\"' in data_lines[1]\n    )\n    assert (\n        '\"name\":\"Meeseeks Box\"' in data_lines[2]\n        or '\"name\": \"Meeseeks Box\"' in data_lines[2]\n    )\n\n\ndef test_sync_generator_with_model(client: TestClient):\n    response = client.get(\"/items/stream-sync\")\n    assert response.status_code == 200\n    assert response.headers[\"content-type\"] == \"text/event-stream; charset=utf-8\"\n\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 3\n\n\ndef test_async_generator_no_annotation(client: TestClient):\n    response = client.get(\"/items/stream-no-annotation\")\n    assert response.status_code == 200\n    assert response.headers[\"content-type\"] == \"text/event-stream; charset=utf-8\"\n\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 3\n\n\ndef test_sync_generator_no_annotation(client: TestClient):\n    response = client.get(\"/items/stream-sync-no-annotation\")\n    assert response.status_code == 200\n    assert response.headers[\"content-type\"] == \"text/event-stream; charset=utf-8\"\n\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 3\n\n\ndef test_dict_items(client: TestClient):\n    response = client.get(\"/items/stream-dict\")\n    assert response.status_code == 200\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 3\n    assert '\"name\"' in data_lines[0]\n\n\ndef test_post_method_sse(client: TestClient):\n    \"\"\"SSE should work with POST (needed for MCP compatibility).\"\"\"\n    response = client.post(\"/items/stream-post\")\n    assert response.status_code == 200\n    assert response.headers[\"content-type\"] == \"text/event-stream; charset=utf-8\"\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 3\n\n\ndef test_sse_events_with_fields(client: TestClient):\n    response = client.get(\"/items/stream-sse-event\")\n    assert response.status_code == 200\n    text = response.text\n\n    assert \"event: greeting\\n\" in text\n    assert 'data: \"hello\"\\n' in text\n    assert \"id: 1\\n\" in text\n\n    assert \"event: json-data\\n\" in text\n    assert \"id: 2\\n\" in text\n    assert 'data: {\"key\": \"value\"}\\n' in text\n\n    assert \": just a comment\\n\" in text\n\n    assert \"retry: 5000\\n\" in text\n    assert 'data: \"retry-test\"\\n' in text\n\n\ndef test_mixed_plain_and_sse_events(client: TestClient):\n    response = client.get(\"/items/stream-mixed\")\n    assert response.status_code == 200\n    text = response.text\n\n    assert \"event: special\\n\" in text\n    assert 'data: \"custom-event\"\\n' in text\n    assert '\"name\"' in text\n\n\ndef test_string_data_json_encoded(client: TestClient):\n    \"\"\"Strings are always JSON-encoded (quoted).\"\"\"\n    response = client.get(\"/items/stream-string\")\n    assert response.status_code == 200\n    assert 'data: \"plain text data\"\\n' in response.text\n\n\ndef test_server_sent_event_null_id_rejected():\n    with pytest.raises(ValueError, match=\"null\"):\n        ServerSentEvent(data=\"test\", id=\"has\\0null\")\n\n\ndef test_server_sent_event_negative_retry_rejected():\n    with pytest.raises(ValueError):\n        ServerSentEvent(data=\"test\", retry=-1)\n\n\ndef test_server_sent_event_float_retry_rejected():\n    with pytest.raises(ValueError):\n        ServerSentEvent(data=\"test\", retry=1.5)  # type: ignore[arg-type]\n\n\ndef test_raw_data_sent_without_json_encoding(client: TestClient):\n    \"\"\"raw_data is sent as-is, not JSON-encoded.\"\"\"\n    response = client.get(\"/items/stream-raw\")\n    assert response.status_code == 200\n    text = response.text\n\n    # raw_data should appear without JSON quotes\n    assert \"data: plain text without quotes\\n\" in text\n    # Not JSON-quoted\n    assert 'data: \"plain text without quotes\"' not in text\n\n    assert \"event: html\\n\" in text\n    assert \"data: <div>html fragment</div>\\n\" in text\n\n    assert \"event: csv\\n\" in text\n    assert \"data: cpu,87.3,1709145600\\n\" in text\n\n\ndef test_data_and_raw_data_mutually_exclusive():\n    \"\"\"Cannot set both data and raw_data.\"\"\"\n    with pytest.raises(ValueError, match=\"Cannot set both\"):\n        ServerSentEvent(data=\"json\", raw_data=\"raw\")\n\n\ndef test_sse_on_router_included_in_app(client: TestClient):\n    response = client.get(\"/api/events\")\n    assert response.status_code == 200\n    assert response.headers[\"content-type\"] == \"text/event-stream; charset=utf-8\"\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 2\n\n\n# Keepalive ping tests\n\n\nkeepalive_app = FastAPI()\n\n\n@keepalive_app.get(\"/slow-async\", response_class=EventSourceResponse)\nasync def slow_async_stream():\n    yield {\"n\": 1}\n    # Sleep longer than the (monkeypatched) ping interval so a keepalive\n    # comment is emitted before the next item.\n    await asyncio.sleep(0.3)\n    yield {\"n\": 2}\n\n\n@keepalive_app.get(\"/slow-sync\", response_class=EventSourceResponse)\ndef slow_sync_stream():\n    yield {\"n\": 1}\n    time.sleep(0.3)\n    yield {\"n\": 2}\n\n\ndef test_keepalive_ping_async(monkeypatch: pytest.MonkeyPatch):\n    monkeypatch.setattr(fastapi.routing, \"_PING_INTERVAL\", 0.05)\n    with TestClient(keepalive_app) as c:\n        response = c.get(\"/slow-async\")\n    assert response.status_code == 200\n    text = response.text\n    # The keepalive comment \": ping\" should appear between the two data events\n    assert \": ping\\n\" in text\n    data_lines = [line for line in text.split(\"\\n\") if line.startswith(\"data: \")]\n    assert len(data_lines) == 2\n\n\ndef test_keepalive_ping_sync(monkeypatch: pytest.MonkeyPatch):\n    monkeypatch.setattr(fastapi.routing, \"_PING_INTERVAL\", 0.05)\n    with TestClient(keepalive_app) as c:\n        response = c.get(\"/slow-sync\")\n    assert response.status_code == 200\n    text = response.text\n    assert \": ping\\n\" in text\n    data_lines = [line for line in text.split(\"\\n\") if line.startswith(\"data: \")]\n    assert len(data_lines) == 2\n\n\ndef test_no_keepalive_when_fast(client: TestClient):\n    \"\"\"No keepalive comment when items arrive quickly.\"\"\"\n    response = client.get(\"/items/stream\")\n    assert response.status_code == 200\n    # KEEPALIVE_COMMENT is \": ping\\n\\n\".\n    assert \": ping\\n\" not in response.text\n"
  },
  {
    "path": "tests/test_starlette_exception.py",
    "content": "from fastapi import FastAPI, HTTPException\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom starlette.exceptions import HTTPException as StarletteHTTPException\n\napp = FastAPI()\n\nitems = {\"foo\": \"The Foo Wrestlers\"}\n\n\n@app.get(\"/items/{item_id}\")\nasync def read_item(item_id: str):\n    if item_id not in items:\n        raise HTTPException(\n            status_code=404,\n            detail=\"Item not found\",\n            headers={\"X-Error\": \"Some custom header\"},\n        )\n    return {\"item\": items[item_id]}\n\n\n@app.get(\"/http-no-body-statuscode-exception\")\nasync def no_body_status_code_exception():\n    raise HTTPException(status_code=204)\n\n\n@app.get(\"/http-no-body-statuscode-with-detail-exception\")\nasync def no_body_status_code_with_detail_exception():\n    raise HTTPException(status_code=204, detail=\"I should just disappear!\")\n\n\n@app.get(\"/starlette-items/{item_id}\")\nasync def read_starlette_item(item_id: str):\n    if item_id not in items:\n        raise StarletteHTTPException(status_code=404, detail=\"Item not found\")\n    return {\"item\": items[item_id]}\n\n\nclient = TestClient(app)\n\n\ndef test_get_item():\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item\": \"The Foo Wrestlers\"}\n\n\ndef test_get_item_not_found():\n    response = client.get(\"/items/bar\")\n    assert response.status_code == 404, response.text\n    assert response.headers.get(\"x-error\") == \"Some custom header\"\n    assert response.json() == {\"detail\": \"Item not found\"}\n\n\ndef test_get_starlette_item():\n    response = client.get(\"/starlette-items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item\": \"The Foo Wrestlers\"}\n\n\ndef test_get_starlette_item_not_found():\n    response = client.get(\"/starlette-items/bar\")\n    assert response.status_code == 404, response.text\n    assert response.headers.get(\"x-error\") is None\n    assert response.json() == {\"detail\": \"Item not found\"}\n\n\ndef test_no_body_status_code_exception_handlers():\n    response = client.get(\"/http-no-body-statuscode-exception\")\n    assert response.status_code == 204\n    assert not response.content\n\n\ndef test_no_body_status_code_with_detail_exception_handlers():\n    response = client.get(\"/http-no-body-statuscode-with-detail-exception\")\n    assert response.status_code == 204\n    assert not response.content\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/http-no-body-statuscode-exception\": {\n                    \"get\": {\n                        \"operationId\": \"no_body_status_code_exception_http_no_body_statuscode_exception_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                        \"summary\": \"No Body Status Code Exception\",\n                    }\n                },\n                \"/http-no-body-statuscode-with-detail-exception\": {\n                    \"get\": {\n                        \"operationId\": \"no_body_status_code_with_detail_exception_http_no_body_statuscode_with_detail_exception_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                        \"summary\": \"No Body Status Code With Detail Exception\",\n                    }\n                },\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/starlette-items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Starlette Item\",\n                        \"operationId\": \"read_starlette_item_starlette_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_starlette_urlconvertors.py",
    "content": "from fastapi import FastAPI, Path, Query\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\n\n@app.get(\"/int/{param:int}\")\ndef int_convertor(param: int = Path()):\n    return {\"int\": param}\n\n\n@app.get(\"/float/{param:float}\")\ndef float_convertor(param: float = Path()):\n    return {\"float\": param}\n\n\n@app.get(\"/path/{param:path}\")\ndef path_convertor(param: str = Path()):\n    return {\"path\": param}\n\n\n@app.get(\"/query/\")\ndef query_convertor(param: str = Query()):\n    return {\"query\": param}\n\n\nclient = TestClient(app)\n\n\ndef test_route_converters_int():\n    # Test integer conversion\n    response = client.get(\"/int/5\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"int\": 5}\n    assert app.url_path_for(\"int_convertor\", param=5) == \"/int/5\"  # type: ignore\n\n\ndef test_route_converters_float():\n    # Test float conversion\n    response = client.get(\"/float/25.5\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"float\": 25.5}\n    assert app.url_path_for(\"float_convertor\", param=25.5) == \"/float/25.5\"  # type: ignore\n\n\ndef test_route_converters_path():\n    # Test path conversion\n    response = client.get(\"/path/some/example\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"path\": \"some/example\"}\n\n\ndef test_route_converters_query():\n    # Test query conversion\n    response = client.get(\"/query\", params={\"param\": \"Qué tal!\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"query\": \"Qué tal!\"}\n\n\ndef test_url_path_for_path_convertor():\n    assert (\n        app.url_path_for(\"path_convertor\", param=\"some/example\") == \"/path/some/example\"\n    )\n"
  },
  {
    "path": "tests/test_stream_bare_type.py",
    "content": "import json\nfrom typing import AsyncIterable, Iterable  # noqa: UP035 to test coverage\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n\n\napp = FastAPI()\n\n\n@app.get(\"/items/stream-bare-async\")\nasync def stream_bare_async() -> AsyncIterable:\n    yield {\"name\": \"foo\"}\n\n\n@app.get(\"/items/stream-bare-sync\")\ndef stream_bare_sync() -> Iterable:\n    yield {\"name\": \"bar\"}\n\n\nclient = TestClient(app)\n\n\ndef test_stream_bare_async_iterable():\n    response = client.get(\"/items/stream-bare-async\")\n    assert response.status_code == 200\n    assert response.headers[\"content-type\"] == \"application/jsonl\"\n    lines = [json.loads(line) for line in response.text.strip().splitlines()]\n    assert lines == [{\"name\": \"foo\"}]\n\n\ndef test_stream_bare_sync_iterable():\n    response = client.get(\"/items/stream-bare-sync\")\n    assert response.status_code == 200\n    assert response.headers[\"content-type\"] == \"application/jsonl\"\n    lines = [json.loads(line) for line in response.text.strip().splitlines()]\n    assert lines == [{\"name\": \"bar\"}]\n"
  },
  {
    "path": "tests/test_stream_cancellation.py",
    "content": "\"\"\"\nTest that async streaming endpoints can be cancelled without hanging.\n\nRef: https://github.com/fastapi/fastapi/issues/14680\n\"\"\"\n\nfrom collections.abc import AsyncIterable\n\nimport anyio\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.responses import StreamingResponse\n\npytestmark = [\n    pytest.mark.anyio,\n    pytest.mark.filterwarnings(\"ignore::pytest.PytestUnraisableExceptionWarning\"),\n]\n\n\napp = FastAPI()\n\n\n@app.get(\"/stream-raw\", response_class=StreamingResponse)\nasync def stream_raw() -> AsyncIterable[str]:\n    \"\"\"Async generator with no internal await - would hang without checkpoint.\"\"\"\n    i = 0\n    while True:\n        yield f\"item {i}\\n\"\n        i += 1\n\n\n@app.get(\"/stream-jsonl\")\nasync def stream_jsonl() -> AsyncIterable[int]:\n    \"\"\"JSONL async generator with no internal await.\"\"\"\n    i = 0\n    while True:\n        yield i\n        i += 1\n\n\nasync def _run_asgi_and_cancel(app: FastAPI, path: str, timeout: float) -> bool:\n    \"\"\"Call the ASGI app for *path* and cancel after *timeout* seconds.\n\n    Returns `True` if the cancellation was delivered (i.e. it did not hang).\n    \"\"\"\n    chunks: list[bytes] = []\n\n    async def receive():  # type: ignore[no-untyped-def]\n        # Simulate a client that never disconnects, rely on cancellation\n        await anyio.sleep(float(\"inf\"))\n        return {\"type\": \"http.disconnect\"}  # pragma: no cover\n\n    async def send(message: dict) -> None:  # type: ignore[type-arg]\n        if message[\"type\"] == \"http.response.body\":\n            chunks.append(message.get(\"body\", b\"\"))\n\n    scope = {\n        \"type\": \"http\",\n        \"asgi\": {\"version\": \"3.0\", \"spec_version\": \"2.0\"},\n        \"http_version\": \"1.1\",\n        \"method\": \"GET\",\n        \"path\": path,\n        \"query_string\": b\"\",\n        \"root_path\": \"\",\n        \"headers\": [],\n        \"server\": (\"test\", 80),\n    }\n\n    with anyio.move_on_after(timeout) as cancel_scope:\n        await app(scope, receive, send)  # type: ignore[arg-type]\n\n    # If we got here within the timeout the generator was cancellable.\n    # cancel_scope.cancelled_caught is True when move_on_after fired.\n    return cancel_scope.cancelled_caught or len(chunks) > 0\n\n\nasync def test_raw_stream_cancellation() -> None:\n    \"\"\"Raw streaming endpoint should be cancellable within a reasonable time.\"\"\"\n    cancelled = await _run_asgi_and_cancel(app, \"/stream-raw\", timeout=3.0)\n    # The key assertion: we reached this line at all (didn't hang).\n    # cancelled will be True because the infinite generator was interrupted.\n    assert cancelled\n\n\nasync def test_jsonl_stream_cancellation() -> None:\n    \"\"\"JSONL streaming endpoint should be cancellable within a reasonable time.\"\"\"\n    cancelled = await _run_asgi_and_cancel(app, \"/stream-jsonl\", timeout=3.0)\n    assert cancelled\n"
  },
  {
    "path": "tests/test_stream_json_validation_error.py",
    "content": "from collections.abc import AsyncIterable, Iterable\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.exceptions import ResponseValidationError\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    name: str\n    price: float\n\n\napp = FastAPI()\n\n\n@app.get(\"/items/stream-invalid\")\nasync def stream_items_invalid() -> AsyncIterable[Item]:\n    yield {\"name\": \"valid\", \"price\": 1.0}\n    yield {\"name\": \"invalid\", \"price\": \"not-a-number\"}\n\n\n@app.get(\"/items/stream-invalid-sync\")\ndef stream_items_invalid_sync() -> Iterable[Item]:\n    yield {\"name\": \"valid\", \"price\": 1.0}\n    yield {\"name\": \"invalid\", \"price\": \"not-a-number\"}\n\n\nclient = TestClient(app)\n\n\ndef test_stream_json_validation_error_async():\n    with pytest.raises(ResponseValidationError):\n        client.get(\"/items/stream-invalid\")\n\n\ndef test_stream_json_validation_error_sync():\n    with pytest.raises(ResponseValidationError):\n        client.get(\"/items/stream-invalid-sync\")\n"
  },
  {
    "path": "tests/test_strict_content_type_app_level.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\napp_default = FastAPI()\n\n\n@app_default.post(\"/items/\")\nasync def app_default_post(data: dict):\n    return data\n\n\napp_lax = FastAPI(strict_content_type=False)\n\n\n@app_lax.post(\"/items/\")\nasync def app_lax_post(data: dict):\n    return data\n\n\nclient_default = TestClient(app_default)\nclient_lax = TestClient(app_lax)\n\n\ndef test_default_strict_rejects_no_content_type():\n    response = client_default.post(\"/items/\", content='{\"key\": \"value\"}')\n    assert response.status_code == 422\n\n\ndef test_default_strict_accepts_json_content_type():\n    response = client_default.post(\"/items/\", json={\"key\": \"value\"})\n    assert response.status_code == 200\n    assert response.json() == {\"key\": \"value\"}\n\n\ndef test_lax_accepts_no_content_type():\n    response = client_lax.post(\"/items/\", content='{\"key\": \"value\"}')\n    assert response.status_code == 200\n    assert response.json() == {\"key\": \"value\"}\n\n\ndef test_lax_accepts_json_content_type():\n    response = client_lax.post(\"/items/\", json={\"key\": \"value\"})\n    assert response.status_code == 200\n    assert response.json() == {\"key\": \"value\"}\n"
  },
  {
    "path": "tests/test_strict_content_type_nested.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom fastapi.testclient import TestClient\n\n# Lax app with nested routers, inner overrides to strict\n\napp_nested = FastAPI(strict_content_type=False)  # lax app\nouter_router = APIRouter(prefix=\"/outer\")  # inherits lax from app\ninner_strict = APIRouter(prefix=\"/strict\", strict_content_type=True)\ninner_default = APIRouter(prefix=\"/default\")\n\n\n@inner_strict.post(\"/items/\")\nasync def inner_strict_post(data: dict):\n    return data\n\n\n@inner_default.post(\"/items/\")\nasync def inner_default_post(data: dict):\n    return data\n\n\nouter_router.include_router(inner_strict)\nouter_router.include_router(inner_default)\napp_nested.include_router(outer_router)\n\nclient_nested = TestClient(app_nested)\n\n\ndef test_strict_inner_on_lax_app_rejects_no_content_type():\n    response = client_nested.post(\"/outer/strict/items/\", content='{\"key\": \"value\"}')\n    assert response.status_code == 422\n\n\ndef test_default_inner_inherits_lax_from_app():\n    response = client_nested.post(\"/outer/default/items/\", content='{\"key\": \"value\"}')\n    assert response.status_code == 200\n    assert response.json() == {\"key\": \"value\"}\n\n\ndef test_strict_inner_accepts_json_content_type():\n    response = client_nested.post(\"/outer/strict/items/\", json={\"key\": \"value\"})\n    assert response.status_code == 200\n\n\ndef test_default_inner_accepts_json_content_type():\n    response = client_nested.post(\"/outer/default/items/\", json={\"key\": \"value\"})\n    assert response.status_code == 200\n\n\n# Strict app -> lax outer router -> strict inner router\n\napp_mixed = FastAPI(strict_content_type=True)\nmixed_outer = APIRouter(prefix=\"/outer\", strict_content_type=False)\nmixed_inner = APIRouter(prefix=\"/inner\", strict_content_type=True)\n\n\n@mixed_outer.post(\"/items/\")\nasync def mixed_outer_post(data: dict):\n    return data\n\n\n@mixed_inner.post(\"/items/\")\nasync def mixed_inner_post(data: dict):\n    return data\n\n\nmixed_outer.include_router(mixed_inner)\napp_mixed.include_router(mixed_outer)\n\nclient_mixed = TestClient(app_mixed)\n\n\ndef test_lax_outer_on_strict_app_accepts_no_content_type():\n    response = client_mixed.post(\"/outer/items/\", content='{\"key\": \"value\"}')\n    assert response.status_code == 200\n    assert response.json() == {\"key\": \"value\"}\n\n\ndef test_strict_inner_on_lax_outer_rejects_no_content_type():\n    response = client_mixed.post(\"/outer/inner/items/\", content='{\"key\": \"value\"}')\n    assert response.status_code == 422\n\n\ndef test_lax_outer_accepts_json_content_type():\n    response = client_mixed.post(\"/outer/items/\", json={\"key\": \"value\"})\n    assert response.status_code == 200\n\n\ndef test_strict_inner_on_lax_outer_accepts_json_content_type():\n    response = client_mixed.post(\"/outer/inner/items/\", json={\"key\": \"value\"})\n    assert response.status_code == 200\n"
  },
  {
    "path": "tests/test_strict_content_type_router_level.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom fastapi.testclient import TestClient\n\napp = FastAPI()\n\nrouter_lax = APIRouter(prefix=\"/lax\", strict_content_type=False)\nrouter_strict = APIRouter(prefix=\"/strict\", strict_content_type=True)\nrouter_default = APIRouter(prefix=\"/default\")\n\n\n@router_lax.post(\"/items/\")\nasync def router_lax_post(data: dict):\n    return data\n\n\n@router_strict.post(\"/items/\")\nasync def router_strict_post(data: dict):\n    return data\n\n\n@router_default.post(\"/items/\")\nasync def router_default_post(data: dict):\n    return data\n\n\napp.include_router(router_lax)\napp.include_router(router_strict)\napp.include_router(router_default)\n\nclient = TestClient(app)\n\n\ndef test_lax_router_on_strict_app_accepts_no_content_type():\n    response = client.post(\"/lax/items/\", content='{\"key\": \"value\"}')\n    assert response.status_code == 200\n    assert response.json() == {\"key\": \"value\"}\n\n\ndef test_strict_router_on_strict_app_rejects_no_content_type():\n    response = client.post(\"/strict/items/\", content='{\"key\": \"value\"}')\n    assert response.status_code == 422\n\n\ndef test_default_router_inherits_strict_from_app():\n    response = client.post(\"/default/items/\", content='{\"key\": \"value\"}')\n    assert response.status_code == 422\n\n\ndef test_lax_router_accepts_json_content_type():\n    response = client.post(\"/lax/items/\", json={\"key\": \"value\"})\n    assert response.status_code == 200\n\n\ndef test_strict_router_accepts_json_content_type():\n    response = client.post(\"/strict/items/\", json={\"key\": \"value\"})\n    assert response.status_code == 200\n\n\ndef test_default_router_accepts_json_content_type():\n    response = client.post(\"/default/items/\", json={\"key\": \"value\"})\n    assert response.status_code == 200\n"
  },
  {
    "path": "tests/test_stringified_annotation_dependency.py",
    "content": "from __future__ import annotations\n\nfrom typing import TYPE_CHECKING, Annotated\n\nimport pytest\nfrom fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nif TYPE_CHECKING:  # pragma: no cover\n    from collections.abc import AsyncGenerator\n\n\nclass DummyClient:\n    async def get_people(self) -> list:\n        return [\"John Doe\", \"Jane Doe\"]\n\n    async def close(self) -> None:\n        pass\n\n\nasync def get_client() -> AsyncGenerator[DummyClient, None]:\n    client = DummyClient()\n    yield client\n    await client.close()\n\n\nClient = Annotated[DummyClient, Depends(get_client)]\n\n\n@pytest.fixture(name=\"client\")\ndef client_fixture() -> TestClient:\n    app = FastAPI()\n\n    @app.get(\"/\")\n    async def get_people(client: Client) -> list:\n        return await client.get_people()\n\n    client = TestClient(app)\n    return client\n\n\ndef test_get(client: TestClient):\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"John Doe\", \"Jane Doe\"]\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Get People\",\n                        \"operationId\": \"get_people__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"items\": {},\n                                            \"type\": \"array\",\n                                            \"title\": \"Response Get People  Get\",\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_stringified_annotation_dependency_py314.py",
    "content": "from typing import TYPE_CHECKING, Annotated\n\nfrom fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\n\nfrom .utils import needs_py314\n\nif TYPE_CHECKING:  # pragma: no cover\n\n    class DummyUser: ...\n\n\n@needs_py314\ndef test_stringified_annotation():\n    # python3.14: Use forward reference without \"from __future__ import annotations\"\n    async def get_current_user() -> DummyUser | None:\n        return None\n\n    app = FastAPI()\n\n    client = TestClient(app)\n\n    @app.get(\"/\")\n    async def get(\n        current_user: Annotated[DummyUser | None, Depends(get_current_user)],\n    ) -> str:\n        return \"hello world\"\n\n    response = client.get(\"/\")\n    assert response.status_code == 200\n"
  },
  {
    "path": "tests/test_stringified_annotations_simple.py",
    "content": "from __future__ import annotations\n\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI, Request\nfrom fastapi.testclient import TestClient\n\nfrom .utils import needs_py310\n\n\nclass Dep:\n    def __call__(self, request: Request):\n        return \"test\"\n\n\n@needs_py310\ndef test_stringified_annotations():\n    app = FastAPI()\n\n    client = TestClient(app)\n\n    @app.get(\"/test/\")\n    def call(test: Annotated[str, Depends(Dep())]):\n        return {\"test\": test}\n\n    response = client.get(\"/test\")\n    assert response.status_code == 200\n"
  },
  {
    "path": "tests/test_sub_callbacks.py",
    "content": "from fastapi import APIRouter, FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, HttpUrl\n\napp = FastAPI()\n\n\nclass Invoice(BaseModel):\n    id: str\n    title: str | None = None\n    customer: str\n    total: float\n\n\nclass InvoiceEvent(BaseModel):\n    description: str\n    paid: bool\n\n\nclass InvoiceEventReceived(BaseModel):\n    ok: bool\n\n\ninvoices_callback_router = APIRouter()\n\n\n@invoices_callback_router.post(\n    \"{$callback_url}/invoices/{$request.body.id}\", response_model=InvoiceEventReceived\n)\ndef invoice_notification(body: InvoiceEvent):\n    pass  # pragma: nocover\n\n\nclass Event(BaseModel):\n    name: str\n    total: float\n\n\nevents_callback_router = APIRouter()\n\n\n@events_callback_router.get(\"{$callback_url}/events/{$request.body.title}\")\ndef event_callback(event: Event):\n    pass  # pragma: nocover\n\n\nsubrouter = APIRouter()\n\n\n@subrouter.post(\"/invoices/\", callbacks=invoices_callback_router.routes)\ndef create_invoice(invoice: Invoice, callback_url: HttpUrl | None = None):\n    \"\"\"\n    Create an invoice.\n\n    This will (let's imagine) let the API user (some external developer) create an\n    invoice.\n\n    And this path operation will:\n\n    * Send the invoice to the client.\n    * Collect the money from the client.\n    * Send a notification back to the API user (the external developer), as a callback.\n        * At this point is that the API will somehow send a POST request to the\n            external API with the notification of the invoice event\n            (e.g. \"payment successful\").\n    \"\"\"\n    # Send the invoice, collect the money, send the notification (the callback)\n    return {\"msg\": \"Invoice received\"}\n\n\napp.include_router(subrouter, callbacks=events_callback_router.routes)\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.post(\n        \"/invoices/\", json={\"id\": \"fooinvoice\", \"customer\": \"John\", \"total\": 5.3}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Invoice received\"}\n\n\ndef test_openapi_schema():\n    with client:\n        response = client.get(\"/openapi.json\")\n        assert response.json() == snapshot(\n            {\n                \"openapi\": \"3.1.0\",\n                \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n                \"paths\": {\n                    \"/invoices/\": {\n                        \"post\": {\n                            \"summary\": \"Create Invoice\",\n                            \"description\": 'Create an invoice.\\n\\nThis will (let\\'s imagine) let the API user (some external developer) create an\\ninvoice.\\n\\nAnd this path operation will:\\n\\n* Send the invoice to the client.\\n* Collect the money from the client.\\n* Send a notification back to the API user (the external developer), as a callback.\\n    * At this point is that the API will somehow send a POST request to the\\n        external API with the notification of the invoice event\\n        (e.g. \"payment successful\").',\n                            \"operationId\": \"create_invoice_invoices__post\",\n                            \"parameters\": [\n                                {\n                                    \"required\": False,\n                                    \"schema\": {\n                                        \"title\": \"Callback Url\",\n                                        \"anyOf\": [\n                                            {\n                                                \"type\": \"string\",\n                                                \"format\": \"uri\",\n                                                \"minLength\": 1,\n                                                \"maxLength\": 2083,\n                                            },\n                                            {\"type\": \"null\"},\n                                        ],\n                                    },\n                                    \"name\": \"callback_url\",\n                                    \"in\": \"query\",\n                                }\n                            ],\n                            \"requestBody\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Invoice\"\n                                        }\n                                    }\n                                },\n                                \"required\": True,\n                            },\n                            \"responses\": {\n                                \"200\": {\n                                    \"description\": \"Successful Response\",\n                                    \"content\": {\"application/json\": {\"schema\": {}}},\n                                },\n                                \"422\": {\n                                    \"description\": \"Validation Error\",\n                                    \"content\": {\n                                        \"application/json\": {\n                                            \"schema\": {\n                                                \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                            }\n                                        }\n                                    },\n                                },\n                            },\n                            \"callbacks\": {\n                                \"event_callback\": {\n                                    \"{$callback_url}/events/{$request.body.title}\": {\n                                        \"get\": {\n                                            \"summary\": \"Event Callback\",\n                                            \"operationId\": \"event_callback__callback_url__events___request_body_title__get\",\n                                            \"requestBody\": {\n                                                \"required\": True,\n                                                \"content\": {\n                                                    \"application/json\": {\n                                                        \"schema\": {\n                                                            \"$ref\": \"#/components/schemas/Event\"\n                                                        }\n                                                    }\n                                                },\n                                            },\n                                            \"responses\": {\n                                                \"200\": {\n                                                    \"description\": \"Successful Response\",\n                                                    \"content\": {\n                                                        \"application/json\": {\n                                                            \"schema\": {}\n                                                        }\n                                                    },\n                                                },\n                                                \"422\": {\n                                                    \"description\": \"Validation Error\",\n                                                    \"content\": {\n                                                        \"application/json\": {\n                                                            \"schema\": {\n                                                                \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                                            }\n                                                        }\n                                                    },\n                                                },\n                                            },\n                                        }\n                                    }\n                                },\n                                \"invoice_notification\": {\n                                    \"{$callback_url}/invoices/{$request.body.id}\": {\n                                        \"post\": {\n                                            \"summary\": \"Invoice Notification\",\n                                            \"operationId\": \"invoice_notification__callback_url__invoices___request_body_id__post\",\n                                            \"requestBody\": {\n                                                \"required\": True,\n                                                \"content\": {\n                                                    \"application/json\": {\n                                                        \"schema\": {\n                                                            \"$ref\": \"#/components/schemas/InvoiceEvent\"\n                                                        }\n                                                    }\n                                                },\n                                            },\n                                            \"responses\": {\n                                                \"200\": {\n                                                    \"description\": \"Successful Response\",\n                                                    \"content\": {\n                                                        \"application/json\": {\n                                                            \"schema\": {\n                                                                \"$ref\": \"#/components/schemas/InvoiceEventReceived\"\n                                                            }\n                                                        }\n                                                    },\n                                                },\n                                                \"422\": {\n                                                    \"description\": \"Validation Error\",\n                                                    \"content\": {\n                                                        \"application/json\": {\n                                                            \"schema\": {\n                                                                \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                                            }\n                                                        }\n                                                    },\n                                                },\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                        }\n                    }\n                },\n                \"components\": {\n                    \"schemas\": {\n                        \"Event\": {\n                            \"title\": \"Event\",\n                            \"required\": [\"name\", \"total\"],\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                                \"total\": {\"title\": \"Total\", \"type\": \"number\"},\n                            },\n                        },\n                        \"HTTPValidationError\": {\n                            \"title\": \"HTTPValidationError\",\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"detail\": {\n                                    \"title\": \"Detail\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"$ref\": \"#/components/schemas/ValidationError\"\n                                    },\n                                }\n                            },\n                        },\n                        \"Invoice\": {\n                            \"title\": \"Invoice\",\n                            \"required\": [\"id\", \"customer\", \"total\"],\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"id\": {\"title\": \"Id\", \"type\": \"string\"},\n                                \"title\": {\n                                    \"title\": \"Title\",\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                },\n                                \"customer\": {\"title\": \"Customer\", \"type\": \"string\"},\n                                \"total\": {\"title\": \"Total\", \"type\": \"number\"},\n                            },\n                        },\n                        \"InvoiceEvent\": {\n                            \"title\": \"InvoiceEvent\",\n                            \"required\": [\"description\", \"paid\"],\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"description\": {\n                                    \"title\": \"Description\",\n                                    \"type\": \"string\",\n                                },\n                                \"paid\": {\"title\": \"Paid\", \"type\": \"boolean\"},\n                            },\n                        },\n                        \"InvoiceEventReceived\": {\n                            \"title\": \"InvoiceEventReceived\",\n                            \"required\": [\"ok\"],\n                            \"type\": \"object\",\n                            \"properties\": {\"ok\": {\"title\": \"Ok\", \"type\": \"boolean\"}},\n                        },\n                        \"ValidationError\": {\n                            \"title\": \"ValidationError\",\n                            \"required\": [\"loc\", \"msg\", \"type\"],\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                        },\n                    }\n                },\n            }\n        )\n"
  },
  {
    "path": "tests/test_swagger_ui_escape.py",
    "content": "from fastapi.openapi.docs import get_swagger_ui_html\n\n\ndef test_init_oauth_html_chars_are_escaped():\n    xss_payload = \"Evil</script><script>alert(1)</script>\"\n    html = get_swagger_ui_html(\n        openapi_url=\"/openapi.json\",\n        title=\"Test\",\n        init_oauth={\"appName\": xss_payload},\n    )\n    body = html.body.decode()\n\n    assert \"</script><script>\" not in body\n    assert \"\\\\u003c/script\\\\u003e\\\\u003cscript\\\\u003e\" in body\n\n\ndef test_swagger_ui_parameters_html_chars_are_escaped():\n    html = get_swagger_ui_html(\n        openapi_url=\"/openapi.json\",\n        title=\"Test\",\n        swagger_ui_parameters={\"customKey\": \"<img src=x onerror=alert(1)>\"},\n    )\n    body = html.body.decode()\n    assert \"<img src=x onerror=alert(1)>\" not in body\n    assert \"\\\\u003cimg\" in body\n\n\ndef test_normal_init_oauth_still_works():\n    html = get_swagger_ui_html(\n        openapi_url=\"/openapi.json\",\n        title=\"Test\",\n        init_oauth={\"clientId\": \"my-client\", \"appName\": \"My App\"},\n    )\n    body = html.body.decode()\n    assert '\"clientId\": \"my-client\"' in body\n    assert '\"appName\": \"My App\"' in body\n    assert \"ui.initOAuth\" in body\n"
  },
  {
    "path": "tests/test_swagger_ui_init_oauth.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\nswagger_ui_init_oauth = {\"clientId\": \"the-foo-clients\", \"appName\": \"The Predendapp\"}\n\napp = FastAPI(swagger_ui_init_oauth=swagger_ui_init_oauth)\n\n\n@app.get(\"/items/\")\nasync def read_items():\n    return {\"id\": \"foo\"}\n\n\nclient = TestClient(app)\n\n\ndef test_swagger_ui():\n    response = client.get(\"/docs\")\n    assert response.status_code == 200, response.text\n    print(response.text)\n    assert \"ui.initOAuth\" in response.text\n    assert '\"appName\": \"The Predendapp\"' in response.text\n    assert '\"clientId\": \"the-foo-clients\"' in response.text\n\n\ndef test_response():\n    response = client.get(\"/items/\")\n    assert response.json() == {\"id\": \"foo\"}\n"
  },
  {
    "path": "tests/test_top_level_security_scheme_in_openapi.py",
    "content": "# Test security scheme at the top level, including OpenAPI\n# Ref: https://github.com/fastapi/fastapi/discussions/14263\n# Ref: https://github.com/fastapi/fastapi/issues/14271\nfrom fastapi import Depends, FastAPI\nfrom fastapi.security import HTTPBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\napp = FastAPI()\n\nbearer_scheme = HTTPBearer()\n\n\n@app.get(\"/\", dependencies=[Depends(bearer_scheme)])\nasync def get_root():\n    return {\"message\": \"Hello, World!\"}\n\n\nclient = TestClient(app)\n\n\ndef test_get_root():\n    response = client.get(\"/\", headers={\"Authorization\": \"Bearer token\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello, World!\"}\n\n\ndef test_get_root_no_token():\n    response = client.get(\"/\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Get Root\",\n                        \"operationId\": \"get_root__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"security\": [{\"HTTPBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPBearer\": {\"type\": \"http\", \"scheme\": \"bearer\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tuples.py",
    "content": "from fastapi import FastAPI, Form\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass ItemGroup(BaseModel):\n    items: list[tuple[str, str]]\n\n\nclass Coordinate(BaseModel):\n    x: float\n    y: float\n\n\n@app.post(\"/model-with-tuple/\")\ndef post_model_with_tuple(item_group: ItemGroup):\n    return item_group\n\n\n@app.post(\"/tuple-of-models/\")\ndef post_tuple_of_models(square: tuple[Coordinate, Coordinate]):\n    return square\n\n\n@app.post(\"/tuple-form/\")\ndef hello(values: tuple[int, int] = Form()):\n    return values\n\n\nclient = TestClient(app)\n\n\ndef test_model_with_tuple_valid():\n    data = {\"items\": [[\"foo\", \"bar\"], [\"baz\", \"whatelse\"]]}\n    response = client.post(\"/model-with-tuple/\", json=data)\n    assert response.status_code == 200, response.text\n    assert response.json() == data\n\n\ndef test_model_with_tuple_invalid():\n    data = {\"items\": [[\"foo\", \"bar\"], [\"baz\", \"whatelse\", \"too\", \"much\"]]}\n    response = client.post(\"/model-with-tuple/\", json=data)\n    assert response.status_code == 422, response.text\n\n    data = {\"items\": [[\"foo\", \"bar\"], [\"baz\"]]}\n    response = client.post(\"/model-with-tuple/\", json=data)\n    assert response.status_code == 422, response.text\n\n\ndef test_tuple_with_model_valid():\n    data = [{\"x\": 1, \"y\": 2}, {\"x\": 3, \"y\": 4}]\n    response = client.post(\"/tuple-of-models/\", json=data)\n    assert response.status_code == 200, response.text\n    assert response.json() == data\n\n\ndef test_tuple_with_model_invalid():\n    data = [{\"x\": 1, \"y\": 2}, {\"x\": 3, \"y\": 4}, {\"x\": 5, \"y\": 6}]\n    response = client.post(\"/tuple-of-models/\", json=data)\n    assert response.status_code == 422, response.text\n\n    data = [{\"x\": 1, \"y\": 2}]\n    response = client.post(\"/tuple-of-models/\", json=data)\n    assert response.status_code == 422, response.text\n\n\ndef test_tuple_form_valid():\n    response = client.post(\"/tuple-form/\", data={\"values\": (\"1\", \"2\")})\n    assert response.status_code == 200, response.text\n    assert response.json() == [1, 2]\n\n\ndef test_tuple_form_invalid():\n    response = client.post(\"/tuple-form/\", data={\"values\": (\"1\", \"2\", \"3\")})\n    assert response.status_code == 422, response.text\n\n    response = client.post(\"/tuple-form/\", data={\"values\": (\"1\")})\n    assert response.status_code == 422, response.text\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/model-with-tuple/\": {\n                    \"post\": {\n                        \"summary\": \"Post Model With Tuple\",\n                        \"operationId\": \"post_model_with_tuple_model_with_tuple__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/ItemGroup\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/tuple-of-models/\": {\n                    \"post\": {\n                        \"summary\": \"Post Tuple Of Models\",\n                        \"operationId\": \"post_tuple_of_models_tuple_of_models__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"title\": \"Square\",\n                                        \"maxItems\": 2,\n                                        \"minItems\": 2,\n                                        \"type\": \"array\",\n                                        \"prefixItems\": [\n                                            {\"$ref\": \"#/components/schemas/Coordinate\"},\n                                            {\"$ref\": \"#/components/schemas/Coordinate\"},\n                                        ],\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/tuple-form/\": {\n                    \"post\": {\n                        \"summary\": \"Hello\",\n                        \"operationId\": \"hello_tuple_form__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_hello_tuple_form__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_hello_tuple_form__post\": {\n                        \"title\": \"Body_hello_tuple_form__post\",\n                        \"required\": [\"values\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"values\": {\n                                \"title\": \"Values\",\n                                \"maxItems\": 2,\n                                \"minItems\": 2,\n                                \"type\": \"array\",\n                                \"prefixItems\": [\n                                    {\"type\": \"integer\"},\n                                    {\"type\": \"integer\"},\n                                ],\n                            }\n                        },\n                    },\n                    \"Coordinate\": {\n                        \"title\": \"Coordinate\",\n                        \"required\": [\"x\", \"y\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"x\": {\"title\": \"X\", \"type\": \"number\"},\n                            \"y\": {\"title\": \"Y\", \"type\": \"number\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ItemGroup\": {\n                        \"title\": \"ItemGroup\",\n                        \"required\": [\"items\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"items\": {\n                                \"title\": \"Items\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"maxItems\": 2,\n                                    \"minItems\": 2,\n                                    \"type\": \"array\",\n                                    \"prefixItems\": [\n                                        {\"type\": \"string\"},\n                                        {\"type\": \"string\"},\n                                    ],\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_additional_responses/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_additional_responses/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.additional_responses.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_path_operation():\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"id\": \"foo\", \"value\": \"there goes my hero\"}\n\n\ndef test_path_operation_not_found():\n    response = client.get(\"/items/bar\")\n    assert response.status_code == 404, response.text\n    assert response.json() == {\"message\": \"Item not found\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"404\": {\n                                \"description\": \"Not Found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Message\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"id\", \"value\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"id\": {\"title\": \"Id\", \"type\": \"string\"},\n                            \"value\": {\"title\": \"Value\", \"type\": \"string\"},\n                        },\n                    },\n                    \"Message\": {\n                        \"title\": \"Message\",\n                        \"required\": [\"message\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"message\": {\"title\": \"Message\", \"type\": \"string\"}\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_additional_responses/test_tutorial002.py",
    "content": "import importlib\nimport os\nimport shutil\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310, workdir_lock\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.additional_responses.{request.param}\")\n\n    client = TestClient(mod.app)\n    client.headers.clear()\n    return client\n\n\ndef test_path_operation(client: TestClient):\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"id\": \"foo\", \"value\": \"there goes my hero\"}\n\n\n@workdir_lock\ndef test_path_operation_img(client: TestClient):\n    shutil.copy(\"./docs/en/docs/img/favicon.png\", \"./image.png\")\n    response = client.get(\"/items/foo?img=1\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"Content-Type\"] == \"image/png\"\n    assert len(response.content)\n    os.remove(\"./image.png\")\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Return the JSON item or an image.\",\n                                \"content\": {\n                                    \"image/png\": {},\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    },\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"boolean\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Img\",\n                                },\n                                \"name\": \"img\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"id\", \"value\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"id\": {\"title\": \"Id\", \"type\": \"string\"},\n                            \"value\": {\"title\": \"Value\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_additional_responses/test_tutorial003.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.additional_responses.tutorial003_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_path_operation():\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"id\": \"foo\", \"value\": \"there goes my hero\"}\n\n\ndef test_path_operation_not_found():\n    response = client.get(\"/items/bar\")\n    assert response.status_code == 404, response.text\n    assert response.json() == {\"message\": \"Item not found\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"404\": {\n                                \"description\": \"The item was not found\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Message\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"200\": {\n                                \"description\": \"Item requested by ID\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"},\n                                        \"example\": {\n                                            \"id\": \"bar\",\n                                            \"value\": \"The bar tenders\",\n                                        },\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"id\", \"value\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"id\": {\"title\": \"Id\", \"type\": \"string\"},\n                            \"value\": {\"title\": \"Value\", \"type\": \"string\"},\n                        },\n                    },\n                    \"Message\": {\n                        \"title\": \"Message\",\n                        \"required\": [\"message\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"message\": {\"title\": \"Message\", \"type\": \"string\"}\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_additional_responses/test_tutorial004.py",
    "content": "import importlib\nimport os\nimport shutil\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310, workdir_lock\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.additional_responses.{request.param}\")\n\n    client = TestClient(mod.app)\n    client.headers.clear()\n    return client\n\n\ndef test_path_operation(client: TestClient):\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"id\": \"foo\", \"value\": \"there goes my hero\"}\n\n\n@workdir_lock\ndef test_path_operation_img(client: TestClient):\n    shutil.copy(\"./docs/en/docs/img/favicon.png\", \"./image.png\")\n    response = client.get(\"/items/foo?img=1\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"Content-Type\"] == \"image/png\"\n    assert len(response.content)\n    os.remove(\"./image.png\")\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"404\": {\"description\": \"Item not found\"},\n                            \"302\": {\"description\": \"The item was moved\"},\n                            \"403\": {\"description\": \"Not enough privileges\"},\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"image/png\": {},\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    },\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"boolean\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Img\",\n                                },\n                                \"name\": \"img\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"id\", \"value\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"id\": {\"title\": \"Id\", \"type\": \"string\"},\n                            \"value\": {\"title\": \"Value\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_additional_status_codes/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_additional_status_codes/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.additional_status_codes.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_update(client: TestClient):\n    response = client.put(\"/items/foo\", json={\"name\": \"Wrestlers\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Wrestlers\", \"size\": None}\n\n\ndef test_create(client: TestClient):\n    response = client.put(\"/items/red\", json={\"name\": \"Chillies\"})\n    assert response.status_code == 201, response.text\n    assert response.json() == {\"name\": \"Chillies\", \"size\": None}\n"
  },
  {
    "path": "tests/test_tutorial/test_advanced_middleware/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_advanced_middleware/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.advanced_middleware.tutorial001_py310 import app\n\n\ndef test_middleware():\n    client = TestClient(app, base_url=\"https://testserver\")\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n\n    client = TestClient(app)\n    response = client.get(\"/\", follow_redirects=False)\n    assert response.status_code == 307, response.text\n    assert response.headers[\"location\"] == \"https://testserver/\"\n"
  },
  {
    "path": "tests/test_tutorial/test_advanced_middleware/test_tutorial002.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.advanced_middleware.tutorial002_py310 import app\n\n\ndef test_middleware():\n    client = TestClient(app, base_url=\"http://example.com\")\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    client = TestClient(app, base_url=\"http://subdomain.example.com\")\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    client = TestClient(app, base_url=\"http://invalidhost\")\n    response = client.get(\"/\")\n    assert response.status_code == 400, response.text\n"
  },
  {
    "path": "tests/test_tutorial/test_advanced_middleware/test_tutorial003.py",
    "content": "from fastapi.responses import PlainTextResponse\nfrom fastapi.testclient import TestClient\n\nfrom docs_src.advanced_middleware.tutorial003_py310 import app\n\n\n@app.get(\"/large\")\nasync def large():\n    return PlainTextResponse(\"x\" * 4000, status_code=200)\n\n\nclient = TestClient(app)\n\n\ndef test_middleware():\n    response = client.get(\"/large\", headers={\"accept-encoding\": \"gzip\"})\n    assert response.status_code == 200, response.text\n    assert response.text == \"x\" * 4000\n    assert response.headers[\"Content-Encoding\"] == \"gzip\"\n    assert int(response.headers[\"Content-Length\"]) < 4000\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n"
  },
  {
    "path": "tests/test_tutorial/test_async_tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_async_tests/test_main_a.py",
    "content": "import pytest\n\nfrom docs_src.async_tests.app_a_py310.test_main import test_root\n\n\n@pytest.mark.anyio\nasync def test_async_testing():\n    await test_root()\n"
  },
  {
    "path": "tests/test_tutorial/test_authentication_error_status_code/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial001_an_py310\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.authentication_error_status_code.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_me(client: TestClient):\n    response = client.get(\"/me\", headers={\"Authorization\": \"Bearer secrettoken\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"message\": \"You are authenticated\",\n        \"token\": \"secrettoken\",\n    }\n\n\ndef test_get_me_no_credentials(client: TestClient):\n    response = client.get(\"/me\")\n    assert response.status_code == 403\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/me\": {\n                    \"get\": {\n                        \"summary\": \"Read Me\",\n                        \"operationId\": \"read_me_me_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"security\": [{\"HTTPBearer403\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"HTTPBearer403\": {\"type\": \"http\", \"scheme\": \"bearer\"}\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_background_tasks/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_background_tasks/test_tutorial001.py",
    "content": "import os\nfrom pathlib import Path\n\nfrom fastapi.testclient import TestClient\n\nfrom docs_src.background_tasks.tutorial001_py310 import app\nfrom tests.utils import workdir_lock\n\nclient = TestClient(app)\n\n\n@workdir_lock\ndef test():\n    log = Path(\"log.txt\")\n    if log.is_file():\n        os.remove(log)  # pragma: no cover\n    response = client.post(\"/send-notification/foo@example.com\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Notification sent in the background\"}\n    with open(\"./log.txt\") as f:\n        assert \"notification for foo@example.com: some notification\" in f.read()\n"
  },
  {
    "path": "tests/test_tutorial/test_background_tasks/test_tutorial002.py",
    "content": "import importlib\nimport os\nfrom pathlib import Path\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom tests.utils import needs_py310, workdir_lock\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.background_tasks.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@workdir_lock\ndef test(client: TestClient):\n    log = Path(\"log.txt\")\n    if log.is_file():\n        os.remove(log)  # pragma: no cover\n    response = client.post(\"/send-notification/foo@example.com?q=some-query\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Message sent\"}\n    with open(\"./log.txt\") as f:\n        assert \"found query: some-query\\nmessage to foo@example.com\" in f.read()\n"
  },
  {
    "path": "tests/test_tutorial/test_behind_a_proxy/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.behind_a_proxy.tutorial001_py310 import app\n\nclient = TestClient(app, root_path=\"/api/v1\")\n\n\ndef test_main():\n    response = client.get(\"/app\")\n    assert response.status_code == 200\n    assert response.json() == {\"message\": \"Hello World\", \"root_path\": \"/api/v1\"}\n\n\ndef test_openapi():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/app\": {\n                    \"get\": {\n                        \"summary\": \"Read Main\",\n                        \"operationId\": \"read_main_app_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n            \"servers\": [{\"url\": \"/api/v1\"}],\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.behind_a_proxy.tutorial001_01_py310 import app\n\nclient = TestClient(\n    app,\n    base_url=\"https://example.com\",\n    follow_redirects=False,\n)\n\n\ndef test_redirect() -> None:\n    response = client.get(\"/items\")\n    assert response.status_code == 307\n    assert response.headers[\"location\"] == \"https://example.com/items/\"\n\n\ndef test_no_redirect() -> None:\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == [\"plumbus\", \"portal gun\"]\n"
  },
  {
    "path": "tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.behind_a_proxy.tutorial002_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_main():\n    response = client.get(\"/app\")\n    assert response.status_code == 200\n    assert response.json() == {\"message\": \"Hello World\", \"root_path\": \"/api/v1\"}\n\n\ndef test_openapi():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/app\": {\n                    \"get\": {\n                        \"summary\": \"Read Main\",\n                        \"operationId\": \"read_main_app_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n            \"servers\": [{\"url\": \"/api/v1\"}],\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.behind_a_proxy.tutorial003_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_main():\n    response = client.get(\"/app\")\n    assert response.status_code == 200\n    assert response.json() == {\"message\": \"Hello World\", \"root_path\": \"/api/v1\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"servers\": [\n                {\"url\": \"/api/v1\"},\n                {\n                    \"url\": \"https://stag.example.com\",\n                    \"description\": \"Staging environment\",\n                },\n                {\n                    \"url\": \"https://prod.example.com\",\n                    \"description\": \"Production environment\",\n                },\n            ],\n            \"paths\": {\n                \"/app\": {\n                    \"get\": {\n                        \"summary\": \"Read Main\",\n                        \"operationId\": \"read_main_app_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.behind_a_proxy.tutorial004_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_main():\n    response = client.get(\"/app\")\n    assert response.status_code == 200\n    assert response.json() == {\"message\": \"Hello World\", \"root_path\": \"/api/v1\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"servers\": [\n                {\n                    \"url\": \"https://stag.example.com\",\n                    \"description\": \"Staging environment\",\n                },\n                {\n                    \"url\": \"https://prod.example.com\",\n                    \"description\": \"Production environment\",\n                },\n            ],\n            \"paths\": {\n                \"/app\": {\n                    \"get\": {\n                        \"summary\": \"Read Main\",\n                        \"operationId\": \"read_main_app_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_bigger_applications/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_bigger_applications/test_main.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"app_an_py310.main\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.bigger_applications.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_users_token_jessica(client: TestClient):\n    response = client.get(\"/users?token=jessica\")\n    assert response.status_code == 200\n    assert response.json() == [{\"username\": \"Rick\"}, {\"username\": \"Morty\"}]\n\n\ndef test_users_with_no_token(client: TestClient):\n    response = client.get(\"/users\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_users_foo_token_jessica(client: TestClient):\n    response = client.get(\"/users/foo?token=jessica\")\n    assert response.status_code == 200\n    assert response.json() == {\"username\": \"foo\"}\n\n\ndef test_users_foo_with_no_token(client: TestClient):\n    response = client.get(\"/users/foo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_users_me_token_jessica(client: TestClient):\n    response = client.get(\"/users/me?token=jessica\")\n    assert response.status_code == 200\n    assert response.json() == {\"username\": \"fakecurrentuser\"}\n\n\ndef test_users_me_with_no_token(client: TestClient):\n    response = client.get(\"/users/me\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_users_token_monica_with_no_jessica(client: TestClient):\n    response = client.get(\"/users?token=monica\")\n    assert response.status_code == 400\n    assert response.json() == {\"detail\": \"No Jessica token provided\"}\n\n\ndef test_items_token_jessica(client: TestClient):\n    response = client.get(\n        \"/items?token=jessica\", headers={\"X-Token\": \"fake-super-secret-token\"}\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"plumbus\": {\"name\": \"Plumbus\"},\n        \"gun\": {\"name\": \"Portal Gun\"},\n    }\n\n\ndef test_items_with_no_token_jessica(client: TestClient):\n    response = client.get(\"/items\", headers={\"X-Token\": \"fake-super-secret-token\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_items_plumbus_token_jessica(client: TestClient):\n    response = client.get(\n        \"/items/plumbus?token=jessica\", headers={\"X-Token\": \"fake-super-secret-token\"}\n    )\n    assert response.status_code == 200\n    assert response.json() == {\"name\": \"Plumbus\", \"item_id\": \"plumbus\"}\n\n\ndef test_items_bar_token_jessica(client: TestClient):\n    response = client.get(\n        \"/items/bar?token=jessica\", headers={\"X-Token\": \"fake-super-secret-token\"}\n    )\n    assert response.status_code == 404\n    assert response.json() == {\"detail\": \"Item not found\"}\n\n\ndef test_items_plumbus_with_no_token(client: TestClient):\n    response = client.get(\n        \"/items/plumbus\", headers={\"X-Token\": \"fake-super-secret-token\"}\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_items_with_invalid_token(client: TestClient):\n    response = client.get(\"/items?token=jessica\", headers={\"X-Token\": \"invalid\"})\n    assert response.status_code == 400\n    assert response.json() == {\"detail\": \"X-Token header invalid\"}\n\n\ndef test_items_bar_with_invalid_token(client: TestClient):\n    response = client.get(\"/items/bar?token=jessica\", headers={\"X-Token\": \"invalid\"})\n    assert response.status_code == 400\n    assert response.json() == {\"detail\": \"X-Token header invalid\"}\n\n\ndef test_items_with_missing_x_token_header(client: TestClient):\n    response = client.get(\"/items?token=jessica\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"x-token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_items_plumbus_with_missing_x_token_header(client: TestClient):\n    response = client.get(\"/items/plumbus?token=jessica\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"x-token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_root_token_jessica(client: TestClient):\n    response = client.get(\"/?token=jessica\")\n    assert response.status_code == 200\n    assert response.json() == {\"message\": \"Hello Bigger Applications!\"}\n\n\ndef test_root_with_no_token(client: TestClient):\n    response = client.get(\"/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_put_no_header(client: TestClient):\n    response = client.put(\"/items/foo\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"x-token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_put_invalid_header(client: TestClient):\n    response = client.put(\"/items/foo\", headers={\"X-Token\": \"invalid\"})\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"X-Token header invalid\"}\n\n\ndef test_put(client: TestClient):\n    response = client.put(\n        \"/items/plumbus?token=jessica\", headers={\"X-Token\": \"fake-super-secret-token\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": \"plumbus\", \"name\": \"The great Plumbus\"}\n\n\ndef test_put_forbidden(client: TestClient):\n    response = client.put(\n        \"/items/bar?token=jessica\", headers={\"X-Token\": \"fake-super-secret-token\"}\n    )\n    assert response.status_code == 403, response.text\n    assert response.json() == {\"detail\": \"You can only update the item: plumbus\"}\n\n\ndef test_admin(client: TestClient):\n    response = client.post(\n        \"/admin/?token=jessica\", headers={\"X-Token\": \"fake-super-secret-token\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Admin getting schwifty\"}\n\n\ndef test_admin_invalid_header(client: TestClient):\n    response = client.post(\"/admin/\", headers={\"X-Token\": \"invalid\"})\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"X-Token header invalid\"}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/\": {\n                    \"get\": {\n                        \"tags\": [\"users\"],\n                        \"summary\": \"Read Users\",\n                        \"operationId\": \"read_users_users__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Token\", \"type\": \"string\"},\n                                \"name\": \"token\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/users/me\": {\n                    \"get\": {\n                        \"tags\": [\"users\"],\n                        \"summary\": \"Read User Me\",\n                        \"operationId\": \"read_user_me_users_me_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Token\", \"type\": \"string\"},\n                                \"name\": \"token\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/users/{username}\": {\n                    \"get\": {\n                        \"tags\": [\"users\"],\n                        \"summary\": \"Read User\",\n                        \"operationId\": \"read_user_users__username__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Username\", \"type\": \"string\"},\n                                \"name\": \"username\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Token\", \"type\": \"string\"},\n                                \"name\": \"token\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/items/\": {\n                    \"get\": {\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Token\", \"type\": \"string\"},\n                                \"name\": \"token\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"X-Token\", \"type\": \"string\"},\n                                \"name\": \"x-token\",\n                                \"in\": \"header\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"404\": {\"description\": \"Not found\"},\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Token\", \"type\": \"string\"},\n                                \"name\": \"token\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"X-Token\", \"type\": \"string\"},\n                                \"name\": \"x-token\",\n                                \"in\": \"header\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"404\": {\"description\": \"Not found\"},\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"put\": {\n                        \"tags\": [\"items\", \"custom\"],\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Token\", \"type\": \"string\"},\n                                \"name\": \"token\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"X-Token\", \"type\": \"string\"},\n                                \"name\": \"x-token\",\n                                \"in\": \"header\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"404\": {\"description\": \"Not found\"},\n                            \"403\": {\"description\": \"Operation forbidden\"},\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/admin/\": {\n                    \"post\": {\n                        \"tags\": [\"admin\"],\n                        \"summary\": \"Update Admin\",\n                        \"operationId\": \"update_admin_admin__post\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Token\", \"type\": \"string\"},\n                                \"name\": \"token\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"X-Token\", \"type\": \"string\"},\n                                \"name\": \"x-token\",\n                                \"in\": \"header\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"418\": {\"description\": \"I'm a teapot\"},\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Root\",\n                        \"operationId\": \"root__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Token\", \"type\": \"string\"},\n                                \"name\": \"token\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_body/test_tutorial001.py",
    "content": "import importlib\nfrom unittest.mock import patch\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_body_float(client: TestClient):\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"price\": 50.5})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"price\": 50.5,\n        \"description\": None,\n        \"tax\": None,\n    }\n\n\ndef test_post_with_str_float(client: TestClient):\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"price\": \"50.5\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"price\": 50.5,\n        \"description\": None,\n        \"tax\": None,\n    }\n\n\ndef test_post_with_str_float_description(client: TestClient):\n    response = client.post(\n        \"/items/\", json={\"name\": \"Foo\", \"price\": \"50.5\", \"description\": \"Some Foo\"}\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"price\": 50.5,\n        \"description\": \"Some Foo\",\n        \"tax\": None,\n    }\n\n\ndef test_post_with_str_float_description_tax(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        json={\"name\": \"Foo\", \"price\": \"50.5\", \"description\": \"Some Foo\", \"tax\": 0.3},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"price\": 50.5,\n        \"description\": \"Some Foo\",\n        \"tax\": 0.3,\n    }\n\n\ndef test_post_with_only_name(client: TestClient):\n    response = client.post(\"/items/\", json={\"name\": \"Foo\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"price\"],\n                \"msg\": \"Field required\",\n                \"input\": {\"name\": \"Foo\"},\n            }\n        ]\n    }\n\n\ndef test_post_with_only_name_price(client: TestClient):\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"price\": \"twenty\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"float_parsing\",\n                \"loc\": [\"body\", \"price\"],\n                \"msg\": \"Input should be a valid number, unable to parse string as a number\",\n                \"input\": \"twenty\",\n            }\n        ]\n    }\n\n\ndef test_post_with_no_data(client: TestClient):\n    response = client.post(\"/items/\", json={})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"name\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"price\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n        ]\n    }\n\n\ndef test_post_with_none(client: TestClient):\n    response = client.post(\"/items/\", json=None)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_post_broken_body(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        headers={\"content-type\": \"application/json\"},\n        content=\"{some broken json}\",\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"json_invalid\",\n                \"loc\": [\"body\", 1],\n                \"msg\": \"JSON decode error\",\n                \"input\": {},\n                \"ctx\": {\"error\": \"Expecting property name enclosed in double quotes\"},\n            }\n        ]\n    }\n\n\ndef test_post_form_for_json(client: TestClient):\n    response = client.post(\"/items/\", data={\"name\": \"Foo\", \"price\": 50.5})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"model_attributes_type\",\n                \"loc\": [\"body\"],\n                \"msg\": \"Input should be a valid dictionary or object to extract fields from\",\n                \"input\": \"name=Foo&price=50.5\",\n            }\n        ]\n    }\n\n\ndef test_explicit_content_type(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        content='{\"name\": \"Foo\", \"price\": 50.5}',\n        headers={\"Content-Type\": \"application/json\"},\n    )\n    assert response.status_code == 200, response.text\n\n\ndef test_geo_json(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        content='{\"name\": \"Foo\", \"price\": 50.5}',\n        headers={\"Content-Type\": \"application/geo+json\"},\n    )\n    assert response.status_code == 200, response.text\n\n\ndef test_no_content_type_json(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        content='{\"name\": \"Foo\", \"price\": 50.5}',\n    )\n    assert response.status_code == 422, response.text\n\n\ndef test_wrong_headers(client: TestClient):\n    data = '{\"name\": \"Foo\", \"price\": 50.5}'\n    response = client.post(\n        \"/items/\", content=data, headers={\"Content-Type\": \"text/plain\"}\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"model_attributes_type\",\n                \"loc\": [\"body\"],\n                \"msg\": \"Input should be a valid dictionary or object to extract fields from\",\n                \"input\": '{\"name\": \"Foo\", \"price\": 50.5}',\n            }\n        ]\n    }\n\n    response = client.post(\n        \"/items/\", content=data, headers={\"Content-Type\": \"application/geo+json-seq\"}\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"model_attributes_type\",\n                \"loc\": [\"body\"],\n                \"msg\": \"Input should be a valid dictionary or object to extract fields from\",\n                \"input\": '{\"name\": \"Foo\", \"price\": 50.5}',\n            }\n        ]\n    }\n\n    response = client.post(\n        \"/items/\", content=data, headers={\"Content-Type\": \"application/not-really-json\"}\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"model_attributes_type\",\n                \"loc\": [\"body\"],\n                \"msg\": \"Input should be a valid dictionary or object to extract fields from\",\n                \"input\": '{\"name\": \"Foo\", \"price\": 50.5}',\n            }\n        ]\n    }\n\n\ndef test_other_exceptions(client: TestClient):\n    with patch(\"json.loads\", side_effect=Exception):\n        response = client.post(\"/items/\", json={\"test\": \"test2\"})\n        assert response.status_code == 400, response.text\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\"price\", [\"50.5\", 50.5])\ndef test_post_with_tax(client: TestClient, price: str | float):\n    response = client.post(\n        \"/items/\",\n        json={\"name\": \"Foo\", \"price\": price, \"description\": \"Some Foo\", \"tax\": 0.3},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"price\": 50.5,\n        \"description\": \"Some Foo\",\n        \"tax\": 0.3,\n        \"price_with_tax\": 50.8,\n    }\n\n\n@pytest.mark.parametrize(\"price\", [\"50.5\", 50.5])\ndef test_post_without_tax(client: TestClient, price: str | float):\n    response = client.post(\n        \"/items/\", json={\"name\": \"Foo\", \"price\": price, \"description\": \"Some Foo\"}\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"price\": 50.5,\n        \"description\": \"Some Foo\",\n        \"tax\": None,\n    }\n\n\ndef test_post_with_no_data(client: TestClient):\n    response = client.post(\"/items/\", json={})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"name\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"price\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_put_all(client: TestClient):\n    response = client.put(\n        \"/items/123\",\n        json={\"name\": \"Foo\", \"price\": 50.1, \"description\": \"Some Foo\", \"tax\": 0.3},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 123,\n        \"name\": \"Foo\",\n        \"price\": 50.1,\n        \"description\": \"Some Foo\",\n        \"tax\": 0.3,\n    }\n\n\ndef test_put_only_required(client: TestClient):\n    response = client.put(\n        \"/items/123\",\n        json={\"name\": \"Foo\", \"price\": 50.1},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 123,\n        \"name\": \"Foo\",\n        \"price\": 50.1,\n        \"description\": None,\n        \"tax\": None,\n    }\n\n\ndef test_put_with_no_data(client: TestClient):\n    response = client.put(\"/items/123\", json={})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"name\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"price\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"integer\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_put_all(client: TestClient):\n    response = client.put(\n        \"/items/123\",\n        json={\"name\": \"Foo\", \"price\": 50.1, \"description\": \"Some Foo\", \"tax\": 0.3},\n        params={\"q\": \"somequery\"},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 123,\n        \"name\": \"Foo\",\n        \"price\": 50.1,\n        \"description\": \"Some Foo\",\n        \"tax\": 0.3,\n        \"q\": \"somequery\",\n    }\n\n\ndef test_put_only_required(client: TestClient):\n    response = client.put(\n        \"/items/123\",\n        json={\"name\": \"Foo\", \"price\": 50.1},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 123,\n        \"name\": \"Foo\",\n        \"price\": 50.1,\n        \"description\": None,\n        \"tax\": None,\n    }\n\n\ndef test_put_with_no_data(client: TestClient):\n    response = client.put(\"/items/123\", json={})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"name\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"price\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"integer\",\n                                },\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_fields/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_body_fields/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_fields.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_items_5(client: TestClient):\n    response = client.put(\"/items/5\", json={\"item\": {\"name\": \"Foo\", \"price\": 3.0}})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 5,\n        \"item\": {\"name\": \"Foo\", \"price\": 3.0, \"description\": None, \"tax\": None},\n    }\n\n\ndef test_items_6(client: TestClient):\n    response = client.put(\n        \"/items/6\",\n        json={\n            \"item\": {\n                \"name\": \"Bar\",\n                \"price\": 0.2,\n                \"description\": \"Some bar\",\n                \"tax\": \"5.4\",\n            }\n        },\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 6,\n        \"item\": {\n            \"name\": \"Bar\",\n            \"price\": 0.2,\n            \"description\": \"Some bar\",\n            \"tax\": 5.4,\n        },\n    }\n\n\ndef test_invalid_price(client: TestClient):\n    response = client.put(\"/items/5\", json={\"item\": {\"name\": \"Foo\", \"price\": -3.0}})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"greater_than\",\n                \"loc\": [\"body\", \"item\", \"price\"],\n                \"msg\": \"Input should be greater than 0\",\n                \"input\": -3.0,\n                \"ctx\": {\"gt\": 0.0},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"integer\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_update_item_items__item_id__put\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\n                                \"title\": \"The description of the item\",\n                                \"anyOf\": [\n                                    {\"maxLength\": 300, \"type\": \"string\"},\n                                    {\"type\": \"null\"},\n                                ],\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"exclusiveMinimum\": 0.0,\n                                \"type\": \"number\",\n                                \"description\": \"The price must be greater than zero\",\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"Body_update_item_items__item_id__put\": {\n                        \"title\": \"Body_update_item_items__item_id__put\",\n                        \"required\": [\"item\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"item\": {\"$ref\": \"#/components/schemas/Item\"}},\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_multiple_params/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_body_multiple_params/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_multiple_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body_q_bar_content(client: TestClient):\n    response = client.put(\"/items/5?q=bar\", json={\"name\": \"Foo\", \"price\": 50.5})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 5,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"price\": 50.5,\n            \"description\": None,\n            \"tax\": None,\n        },\n        \"q\": \"bar\",\n    }\n\n\ndef test_post_no_body_q_bar(client: TestClient):\n    response = client.put(\"/items/5?q=bar\", json=None)\n    assert response.status_code == 200\n    assert response.json() == {\"item_id\": 5, \"q\": \"bar\"}\n\n\ndef test_post_no_body(client: TestClient):\n    response = client.put(\"/items/5\", json=None)\n    assert response.status_code == 200\n    assert response.json() == {\"item_id\": 5}\n\n\ndef test_post_id_foo(client: TestClient):\n    response = client.put(\"/items/foo\", json=None)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"foo\",\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"The ID of the item to get\",\n                                    \"maximum\": 1000.0,\n                                    \"minimum\": 0.0,\n                                    \"type\": \"integer\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"anyOf\": [\n                                            {\"$ref\": \"#/components/schemas/Item\"},\n                                            {\"type\": \"null\"},\n                                        ],\n                                        \"title\": \"Item\",\n                                    }\n                                }\n                            }\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_multiple_params/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_multiple_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_all(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"item\": {\n                \"name\": \"Foo\",\n                \"price\": 50.5,\n                \"description\": \"Some Foo\",\n                \"tax\": 0.1,\n            },\n            \"user\": {\"username\": \"johndoe\", \"full_name\": \"John Doe\"},\n        },\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 5,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"price\": 50.5,\n            \"description\": \"Some Foo\",\n            \"tax\": 0.1,\n        },\n        \"user\": {\"username\": \"johndoe\", \"full_name\": \"John Doe\"},\n    }\n\n\ndef test_post_required(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"item\": {\"name\": \"Foo\", \"price\": 50.5},\n            \"user\": {\"username\": \"johndoe\"},\n        },\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 5,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"price\": 50.5,\n            \"description\": None,\n            \"tax\": None,\n        },\n        \"user\": {\"username\": \"johndoe\", \"full_name\": None},\n    }\n\n\ndef test_post_no_body(client: TestClient):\n    response = client.put(\"/items/5\", json=None)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\n                    \"body\",\n                    \"item\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"input\": None,\n                \"loc\": [\n                    \"body\",\n                    \"user\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\ndef test_post_no_item(client: TestClient):\n    response = client.put(\"/items/5\", json={\"user\": {\"username\": \"johndoe\"}})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\n                    \"body\",\n                    \"item\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\ndef test_post_no_user(client: TestClient):\n    response = client.put(\"/items/5\", json={\"item\": {\"name\": \"Foo\", \"price\": 50.5}})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\n                    \"body\",\n                    \"user\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\ndef test_post_missing_required_field_in_item(client: TestClient):\n    response = client.put(\n        \"/items/5\", json={\"item\": {\"name\": \"Foo\"}, \"user\": {\"username\": \"johndoe\"}}\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": {\"name\": \"Foo\"},\n                \"loc\": [\n                    \"body\",\n                    \"item\",\n                    \"price\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\ndef test_post_missing_required_field_in_user(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"item\": {\"name\": \"Foo\", \"price\": 50.5},\n            \"user\": {\"full_name\": \"John Doe\"},\n        },\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": {\"full_name\": \"John Doe\"},\n                \"loc\": [\n                    \"body\",\n                    \"user\",\n                    \"username\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\ndef test_post_id_foo(client: TestClient):\n    response = client.put(\n        \"/items/foo\",\n        json={\n            \"item\": {\"name\": \"Foo\", \"price\": 50.5},\n            \"user\": {\"username\": \"johndoe\"},\n        },\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"foo\",\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"info\": {\n                \"title\": \"FastAPI\",\n                \"version\": \"0.1.0\",\n            },\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"integer\",\n                                },\n                            },\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_update_item_items__item_id__put\",\n                                    },\n                                },\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_update_item_items__item_id__put\": {\n                        \"properties\": {\n                            \"item\": {\n                                \"$ref\": \"#/components/schemas/Item\",\n                            },\n                            \"user\": {\n                                \"$ref\": \"#/components/schemas/User\",\n                            },\n                        },\n                        \"required\": [\n                            \"item\",\n                            \"user\",\n                        ],\n                        \"title\": \"Body_update_item_items__item_id__put\",\n                        \"type\": \"object\",\n                    },\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"User\": {\n                        \"properties\": {\n                            \"username\": {\n                                \"title\": \"Username\",\n                                \"type\": \"string\",\n                            },\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                        \"required\": [\n                            \"username\",\n                        ],\n                        \"title\": \"User\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_multiple_params/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n        pytest.param(\"tutorial003_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_multiple_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body_valid(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"importance\": 2,\n            \"item\": {\"name\": \"Foo\", \"price\": 50.5},\n            \"user\": {\"username\": \"Dave\"},\n        },\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 5,\n        \"importance\": 2,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"price\": 50.5,\n            \"description\": None,\n            \"tax\": None,\n        },\n        \"user\": {\"username\": \"Dave\", \"full_name\": None},\n    }\n\n\ndef test_post_body_no_data(client: TestClient):\n    response = client.put(\"/items/5\", json=None)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"item\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"user\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"importance\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_post_body_empty_list(client: TestClient):\n    response = client.put(\"/items/5\", json=[])\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"item\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"user\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"importance\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"integer\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_update_item_items__item_id__put\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"User\": {\n                        \"title\": \"User\",\n                        \"required\": [\"username\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"Body_update_item_items__item_id__put\": {\n                        \"title\": \"Body_update_item_items__item_id__put\",\n                        \"required\": [\"item\", \"user\", \"importance\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"user\": {\"$ref\": \"#/components/schemas/User\"},\n                            \"importance\": {\"title\": \"Importance\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_multiple_params/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n        pytest.param(\"tutorial004_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_multiple_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_put_all(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"importance\": 2,\n            \"item\": {\"name\": \"Foo\", \"price\": 50.5},\n            \"user\": {\"username\": \"Dave\"},\n        },\n        params={\"q\": \"somequery\"},\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 5,\n        \"importance\": 2,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"price\": 50.5,\n            \"description\": None,\n            \"tax\": None,\n        },\n        \"user\": {\"username\": \"Dave\", \"full_name\": None},\n        \"q\": \"somequery\",\n    }\n\n\ndef test_put_only_required(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"importance\": 2,\n            \"item\": {\"name\": \"Foo\", \"price\": 50.5},\n            \"user\": {\"username\": \"Dave\"},\n        },\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 5,\n        \"importance\": 2,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"price\": 50.5,\n            \"description\": None,\n            \"tax\": None,\n        },\n        \"user\": {\"username\": \"Dave\", \"full_name\": None},\n    }\n\n\ndef test_put_missing_body(client: TestClient):\n    response = client.put(\"/items/5\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\n                    \"body\",\n                    \"item\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"input\": None,\n                \"loc\": [\n                    \"body\",\n                    \"user\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"input\": None,\n                \"loc\": [\n                    \"body\",\n                    \"importance\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\ndef test_put_empty_body(client: TestClient):\n    response = client.put(\"/items/5\", json={})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"item\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"user\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"importance\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_put_invalid_importance(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"importance\": 0,\n            \"item\": {\"name\": \"Foo\", \"price\": 50.5},\n            \"user\": {\"username\": \"Dave\"},\n        },\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"importance\"],\n                \"msg\": \"Input should be greater than 0\",\n                \"type\": \"greater_than\",\n                \"input\": 0,\n                \"ctx\": {\"gt\": 0},\n            },\n        ],\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"integer\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_update_item_items__item_id__put\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"User\": {\n                        \"title\": \"User\",\n                        \"required\": [\"username\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"Body_update_item_items__item_id__put\": {\n                        \"title\": \"Body_update_item_items__item_id__put\",\n                        \"required\": [\"item\", \"user\", \"importance\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"item\": {\"$ref\": \"#/components/schemas/Item\"},\n                            \"user\": {\"$ref\": \"#/components/schemas/User\"},\n                            \"importance\": {\n                                \"title\": \"Importance\",\n                                \"type\": \"integer\",\n                                \"exclusiveMinimum\": 0.0,\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_multiple_params/test_tutorial005.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n        pytest.param(\"tutorial005_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_multiple_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_all(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"item\": {\n                \"name\": \"Foo\",\n                \"price\": 50.5,\n                \"description\": \"Some Foo\",\n                \"tax\": 0.1,\n            },\n        },\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 5,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"price\": 50.5,\n            \"description\": \"Some Foo\",\n            \"tax\": 0.1,\n        },\n    }\n\n\ndef test_post_required(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"item\": {\"name\": \"Foo\", \"price\": 50.5},\n        },\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": 5,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"price\": 50.5,\n            \"description\": None,\n            \"tax\": None,\n        },\n    }\n\n\ndef test_post_no_body(client: TestClient):\n    response = client.put(\"/items/5\", json=None)\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\n                    \"body\",\n                    \"item\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\ndef test_post_like_not_embedded(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"name\": \"Foo\",\n            \"price\": 50.5,\n        },\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": None,\n                \"loc\": [\n                    \"body\",\n                    \"item\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\ndef test_post_missing_required_field_in_item(client: TestClient):\n    response = client.put(\n        \"/items/5\", json={\"item\": {\"name\": \"Foo\"}, \"user\": {\"username\": \"johndoe\"}}\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": {\"name\": \"Foo\"},\n                \"loc\": [\n                    \"body\",\n                    \"item\",\n                    \"price\",\n                ],\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ],\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"info\": {\n                \"title\": \"FastAPI\",\n                \"version\": \"0.1.0\",\n            },\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"integer\",\n                                },\n                            },\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_update_item_items__item_id__put\",\n                                    },\n                                },\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_update_item_items__item_id__put\": {\n                        \"properties\": {\n                            \"item\": {\n                                \"$ref\": \"#/components/schemas/Item\",\n                            },\n                        },\n                        \"required\": [\"item\"],\n                        \"title\": \"Body_update_item_items__item_id__put\",\n                        \"type\": \"object\",\n                    },\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_nested_models/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_body_nested_models/test_tutorial001_tutorial002_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom dirty_equals import IsList\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import Is, snapshot\n\nfrom ...utils import needs_py310\n\nUNTYPED_LIST_SCHEMA = {\"type\": \"array\", \"items\": {}}\n\nLIST_OF_STR_SCHEMA = {\"type\": \"array\", \"items\": {\"type\": \"string\"}}\n\nSET_OF_STR_SCHEMA = {\"type\": \"array\", \"items\": {\"type\": \"string\"}, \"uniqueItems\": True}\n\n\n@pytest.fixture(\n    name=\"mod_name\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_mod_name(request: pytest.FixtureRequest):\n    return request.param\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(mod_name: str):\n    mod = importlib.import_module(f\"docs_src.body_nested_models.{mod_name}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_put_all(client: TestClient, mod_name: str):\n    if mod_name.startswith(\"tutorial003\"):\n        tags_expected = IsList(\"foo\", \"bar\", check_order=False)\n    else:\n        tags_expected = [\"foo\", \"bar\", \"foo\"]\n\n    response = client.put(\n        \"/items/123\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n            \"tags\": [\"foo\", \"bar\", \"foo\"],\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"item_id\": 123,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n            \"tags\": tags_expected,\n        },\n    }\n\n\ndef test_put_only_required(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\"name\": \"Foo\", \"price\": 35.4},\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"item_id\": 5,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"description\": None,\n            \"price\": 35.4,\n            \"tax\": None,\n            \"tags\": [],\n        },\n    }\n\n\ndef test_put_empty_body(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={},\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"name\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"price\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_put_missing_required(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\"description\": \"A very nice Item\"},\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"name\"],\n                \"input\": {\"description\": \"A very nice Item\"},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"price\"],\n                \"input\": {\"description\": \"A very nice Item\"},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient, mod_name: str):\n    tags_schema = {\"default\": [], \"title\": \"Tags\"}\n    if mod_name.startswith(\"tutorial001\"):\n        tags_schema.update(UNTYPED_LIST_SCHEMA)\n    elif mod_name.startswith(\"tutorial002\"):\n        tags_schema.update(LIST_OF_STR_SCHEMA)\n    elif mod_name.startswith(\"tutorial003\"):\n        tags_schema.update(SET_OF_STR_SCHEMA)\n\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"integer\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"type\": \"number\",\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                            \"tags\": Is(tags_schema),\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_nested_models/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom dirty_equals import IsList\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_nested_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_put_all(client: TestClient):\n    response = client.put(\n        \"/items/123\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n            \"tags\": [\"foo\", \"bar\", \"foo\"],\n            \"image\": {\"url\": \"http://example.com/image.png\", \"name\": \"example image\"},\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"item_id\": 123,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n            \"tags\": IsList(\"foo\", \"bar\", check_order=False),\n            \"image\": {\"url\": \"http://example.com/image.png\", \"name\": \"example image\"},\n        },\n    }\n\n\ndef test_put_only_required(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\"name\": \"Foo\", \"price\": 35.4},\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"item_id\": 5,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"description\": None,\n            \"price\": 35.4,\n            \"tax\": None,\n            \"tags\": [],\n            \"image\": None,\n        },\n    }\n\n\ndef test_put_empty_body(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={},\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"name\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"price\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_put_missing_required_in_item(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\"description\": \"A very nice Item\"},\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"name\"],\n                \"input\": {\"description\": \"A very nice Item\"},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"price\"],\n                \"input\": {\"description\": \"A very nice Item\"},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_put_missing_required_in_image(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"name\": \"Foo\",\n            \"price\": 35.4,\n            \"image\": {\"url\": \"http://example.com/image.png\"},\n        },\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"image\", \"name\"],\n                \"input\": {\"url\": \"http://example.com/image.png\"},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"integer\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Image\": {\n                        \"properties\": {\n                            \"url\": {\n                                \"title\": \"Url\",\n                                \"type\": \"string\",\n                            },\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\"url\", \"name\"],\n                        \"title\": \"Image\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"type\": \"number\",\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"default\": [],\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                                \"uniqueItems\": True,\n                            },\n                            \"image\": {\n                                \"anyOf\": [\n                                    {\"$ref\": \"#/components/schemas/Image\"},\n                                    {\"type\": \"null\"},\n                                ],\n                            },\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_nested_models/test_tutorial005.py",
    "content": "import importlib\n\nimport pytest\nfrom dirty_equals import IsList\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_nested_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_put_all(client: TestClient):\n    response = client.put(\n        \"/items/123\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n            \"tags\": [\"foo\", \"bar\", \"foo\"],\n            \"image\": {\"url\": \"http://example.com/image.png\", \"name\": \"example image\"},\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"item_id\": 123,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n            \"tags\": IsList(\"foo\", \"bar\", check_order=False),\n            \"image\": {\"url\": \"http://example.com/image.png\", \"name\": \"example image\"},\n        },\n    }\n\n\ndef test_put_only_required(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\"name\": \"Foo\", \"price\": 35.4},\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"item_id\": 5,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"description\": None,\n            \"price\": 35.4,\n            \"tax\": None,\n            \"tags\": [],\n            \"image\": None,\n        },\n    }\n\n\ndef test_put_empty_body(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={},\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"name\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"price\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_put_missing_required_in_item(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\"description\": \"A very nice Item\"},\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"name\"],\n                \"input\": {\"description\": \"A very nice Item\"},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"price\"],\n                \"input\": {\"description\": \"A very nice Item\"},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_put_missing_required_in_image(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"name\": \"Foo\",\n            \"price\": 35.4,\n            \"image\": {\"url\": \"http://example.com/image.png\"},\n        },\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"image\", \"name\"],\n                \"input\": {\"url\": \"http://example.com/image.png\"},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_put_wrong_url(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"name\": \"Foo\",\n            \"price\": 35.4,\n            \"image\": {\"url\": \"not a valid url\", \"name\": \"example image\"},\n        },\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"image\", \"url\"],\n                \"input\": \"not a valid url\",\n                \"msg\": \"Input should be a valid URL, relative URL without a base\",\n                \"type\": \"url_parsing\",\n                \"ctx\": {\"error\": \"relative URL without a base\"},\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"integer\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Image\": {\n                        \"properties\": {\n                            \"url\": {\n                                \"title\": \"Url\",\n                                \"type\": \"string\",\n                                \"format\": \"uri\",\n                                \"maxLength\": 2083,\n                                \"minLength\": 1,\n                            },\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\"url\", \"name\"],\n                        \"title\": \"Image\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"type\": \"number\",\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"default\": [],\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                                \"uniqueItems\": True,\n                            },\n                            \"image\": {\n                                \"anyOf\": [\n                                    {\"$ref\": \"#/components/schemas/Image\"},\n                                    {\"type\": \"null\"},\n                                ],\n                            },\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_nested_models/test_tutorial006.py",
    "content": "import importlib\n\nimport pytest\nfrom dirty_equals import IsList\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial006_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_nested_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_put_all(client: TestClient):\n    response = client.put(\n        \"/items/123\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n            \"tags\": [\"foo\", \"bar\", \"foo\"],\n            \"images\": [\n                {\"url\": \"http://example.com/image.png\", \"name\": \"example image\"}\n            ],\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"item_id\": 123,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n            \"tags\": IsList(\"foo\", \"bar\", check_order=False),\n            \"images\": [\n                {\"url\": \"http://example.com/image.png\", \"name\": \"example image\"}\n            ],\n        },\n    }\n\n\ndef test_put_only_required(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\"name\": \"Foo\", \"price\": 35.4},\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"item_id\": 5,\n        \"item\": {\n            \"name\": \"Foo\",\n            \"description\": None,\n            \"price\": 35.4,\n            \"tax\": None,\n            \"tags\": [],\n            \"images\": None,\n        },\n    }\n\n\ndef test_put_empty_body(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={},\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"name\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"price\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_put_images_not_list(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"name\": \"Foo\",\n            \"price\": 35.4,\n            \"images\": {\"url\": \"http://example.com/image.png\", \"name\": \"example image\"},\n        },\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"images\"],\n                \"input\": {\n                    \"url\": \"http://example.com/image.png\",\n                    \"name\": \"example image\",\n                },\n                \"msg\": \"Input should be a valid list\",\n                \"type\": \"list_type\",\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"integer\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Image\": {\n                        \"properties\": {\n                            \"url\": {\n                                \"title\": \"Url\",\n                                \"type\": \"string\",\n                                \"format\": \"uri\",\n                                \"maxLength\": 2083,\n                                \"minLength\": 1,\n                            },\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\"url\", \"name\"],\n                        \"title\": \"Image\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"type\": \"number\",\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"default\": [],\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                                \"uniqueItems\": True,\n                            },\n                            \"images\": {\n                                \"anyOf\": [\n                                    {\n                                        \"items\": {\n                                            \"$ref\": \"#/components/schemas/Image\",\n                                        },\n                                        \"type\": \"array\",\n                                    },\n                                    {\n                                        \"type\": \"null\",\n                                    },\n                                ],\n                                \"title\": \"Images\",\n                            },\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_nested_models/test_tutorial007.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial007_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_nested_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_all(client: TestClient):\n    data = {\n        \"name\": \"Special Offer\",\n        \"description\": \"This is a special offer\",\n        \"price\": 38.6,\n        \"items\": [\n            {\n                \"name\": \"Foo\",\n                \"description\": \"A very nice Item\",\n                \"price\": 35.4,\n                \"tax\": 3.2,\n                \"tags\": [\"foo\"],\n                \"images\": [\n                    {\n                        \"url\": \"http://example.com/image.png\",\n                        \"name\": \"example image\",\n                    }\n                ],\n            }\n        ],\n    }\n\n    response = client.post(\n        \"/offers/\",\n        json=data,\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == data\n\n\ndef test_put_only_required(client: TestClient):\n    response = client.post(\n        \"/offers/\",\n        json={\n            \"name\": \"Special Offer\",\n            \"price\": 38.6,\n            \"items\": [\n                {\n                    \"name\": \"Foo\",\n                    \"price\": 35.4,\n                    \"images\": [\n                        {\n                            \"url\": \"http://example.com/image.png\",\n                            \"name\": \"example image\",\n                        }\n                    ],\n                }\n            ],\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Special Offer\",\n        \"description\": None,\n        \"price\": 38.6,\n        \"items\": [\n            {\n                \"name\": \"Foo\",\n                \"description\": None,\n                \"price\": 35.4,\n                \"tax\": None,\n                \"tags\": [],\n                \"images\": [\n                    {\n                        \"url\": \"http://example.com/image.png\",\n                        \"name\": \"example image\",\n                    }\n                ],\n            }\n        ],\n    }\n\n\ndef test_put_empty_body(client: TestClient):\n    response = client.post(\n        \"/offers/\",\n        json={},\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"name\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"price\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"items\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_put_missing_required_in_items(client: TestClient):\n    response = client.post(\n        \"/offers/\",\n        json={\n            \"name\": \"Special Offer\",\n            \"price\": 38.6,\n            \"items\": [{}],\n        },\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"items\", 0, \"name\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"items\", 0, \"price\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_put_missing_required_in_images(client: TestClient):\n    response = client.post(\n        \"/offers/\",\n        json={\n            \"name\": \"Special Offer\",\n            \"price\": 38.6,\n            \"items\": [\n                {\"name\": \"Foo\", \"price\": 35.4, \"images\": [{}]},\n            ],\n        },\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"items\", 0, \"images\", 0, \"url\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n            {\n                \"loc\": [\"body\", \"items\", 0, \"images\", 0, \"name\"],\n                \"input\": {},\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/offers/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create Offer\",\n                        \"operationId\": \"create_offer_offers__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Offer\",\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Image\": {\n                        \"properties\": {\n                            \"url\": {\n                                \"title\": \"Url\",\n                                \"type\": \"string\",\n                                \"format\": \"uri\",\n                                \"maxLength\": 2083,\n                                \"minLength\": 1,\n                            },\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\"url\", \"name\"],\n                        \"title\": \"Image\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"type\": \"number\",\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"default\": [],\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                                \"uniqueItems\": True,\n                            },\n                            \"images\": {\n                                \"anyOf\": [\n                                    {\n                                        \"items\": {\n                                            \"$ref\": \"#/components/schemas/Image\",\n                                        },\n                                        \"type\": \"array\",\n                                    },\n                                    {\n                                        \"type\": \"null\",\n                                    },\n                                ],\n                                \"title\": \"Images\",\n                            },\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"Offer\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"type\": \"number\",\n                            },\n                            \"items\": {\n                                \"title\": \"Items\",\n                                \"type\": \"array\",\n                                \"items\": {\"$ref\": \"#/components/schemas/Item\"},\n                            },\n                        },\n                        \"required\": [\"name\", \"price\", \"items\"],\n                        \"title\": \"Offer\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_nested_models/test_tutorial008.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial008_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_nested_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body(client: TestClient):\n    data = [\n        {\"url\": \"http://example.com/\", \"name\": \"Example\"},\n        {\"url\": \"http://fastapi.tiangolo.com/\", \"name\": \"FastAPI\"},\n    ]\n    response = client.post(\"/images/multiple\", json=data)\n    assert response.status_code == 200, response.text\n    assert response.json() == data\n\n\ndef test_post_invalid_list_item(client: TestClient):\n    data = [{\"url\": \"not a valid url\", \"name\": \"Example\"}]\n    response = client.post(\"/images/multiple\", json=data)\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", 0, \"url\"],\n                \"input\": \"not a valid url\",\n                \"msg\": \"Input should be a valid URL, relative URL without a base\",\n                \"type\": \"url_parsing\",\n                \"ctx\": {\"error\": \"relative URL without a base\"},\n            },\n        ]\n    }\n\n\ndef test_post_not_a_list(client: TestClient):\n    data = {\"url\": \"http://example.com/\", \"name\": \"Example\"}\n    response = client.post(\"/images/multiple\", json=data)\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\"],\n                \"input\": {\n                    \"name\": \"Example\",\n                    \"url\": \"http://example.com/\",\n                },\n                \"msg\": \"Input should be a valid list\",\n                \"type\": \"list_type\",\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/images/multiple/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create Multiple Images\",\n                        \"operationId\": \"create_multiple_images_images_multiple__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"title\": \"Images\",\n                                        \"type\": \"array\",\n                                        \"items\": {\"$ref\": \"#/components/schemas/Image\"},\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Image\": {\n                        \"properties\": {\n                            \"url\": {\n                                \"title\": \"Url\",\n                                \"type\": \"string\",\n                                \"format\": \"uri\",\n                                \"maxLength\": 2083,\n                                \"minLength\": 1,\n                            },\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\"url\", \"name\"],\n                        \"title\": \"Image\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_nested_models/test_tutorial009.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial009_py310\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_nested_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body(client: TestClient):\n    data = {\"2\": 2.2, \"3\": 3.3}\n    response = client.post(\"/index-weights/\", json=data)\n    assert response.status_code == 200, response.text\n    assert response.json() == data\n\n\ndef test_post_invalid_body(client: TestClient):\n    data = {\"foo\": 2.2, \"3\": 3.3}\n    response = client.post(\"/index-weights/\", json=data)\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"body\", \"foo\", \"[key]\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"foo\",\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/index-weights/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create Index Weights\",\n                        \"operationId\": \"create_index_weights_index_weights__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"title\": \"Weights\",\n                                        \"type\": \"object\",\n                                        \"additionalProperties\": {\"type\": \"number\"},\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_updates/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_body_updates/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_updates.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get(client: TestClient):\n    response = client.get(\"/items/baz\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Baz\",\n        \"description\": None,\n        \"price\": 50.2,\n        \"tax\": 10.5,\n        \"tags\": [],\n    }\n\n\ndef test_put(client: TestClient):\n    response = client.put(\n        \"/items/bar\", json={\"name\": \"Barz\", \"price\": 3, \"description\": None}\n    )\n    assert response.json() == {\n        \"name\": \"Barz\",\n        \"description\": None,\n        \"price\": 3,\n        \"tax\": 10.5,\n        \"tags\": [],\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    },\n                    \"put\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    },\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"type\": \"object\",\n                        \"title\": \"Item\",\n                        \"properties\": {\n                            \"name\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Name\",\n                            },\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                            },\n                            \"price\": {\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                                \"title\": \"Price\",\n                            },\n                            \"tax\": {\"title\": \"Tax\", \"type\": \"number\", \"default\": 10.5},\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                                \"default\": [],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_body_updates/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.body_updates.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get(client: TestClient):\n    response = client.get(\"/items/baz\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Baz\",\n        \"description\": None,\n        \"price\": 50.2,\n        \"tax\": 10.5,\n        \"tags\": [],\n    }\n\n\ndef test_patch_all(client: TestClient):\n    response = client.patch(\n        \"/items/foo\",\n        json={\n            \"name\": \"Fooz\",\n            \"description\": \"Item description\",\n            \"price\": 3,\n            \"tax\": 10.5,\n            \"tags\": [\"tag1\", \"tag2\"],\n        },\n    )\n    assert response.json() == {\n        \"name\": \"Fooz\",\n        \"description\": \"Item description\",\n        \"price\": 3,\n        \"tax\": 10.5,\n        \"tags\": [\"tag1\", \"tag2\"],\n    }\n\n\ndef test_patch_name(client: TestClient):\n    response = client.patch(\n        \"/items/bar\",\n        json={\"name\": \"Barz\"},\n    )\n    assert response.json() == {\n        \"name\": \"Barz\",\n        \"description\": \"The bartenders\",\n        \"price\": 62,\n        \"tax\": 20.2,\n        \"tags\": [],\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    },\n                    \"patch\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    },\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"type\": \"object\",\n                        \"title\": \"Item\",\n                        \"properties\": {\n                            \"name\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Name\",\n                            },\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                            },\n                            \"price\": {\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                                \"title\": \"Price\",\n                            },\n                            \"tax\": {\"title\": \"Tax\", \"type\": \"number\", \"default\": 10.5},\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                                \"default\": [],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_conditional_openapi/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_conditional_openapi/test_tutorial001.py",
    "content": "import importlib\n\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\ndef get_client() -> TestClient:\n    from docs_src.conditional_openapi import tutorial001_py310\n\n    importlib.reload(tutorial001_py310)\n\n    client = TestClient(tutorial001_py310.app)\n    return client\n\n\ndef test_disable_openapi(monkeypatch):\n    monkeypatch.setenv(\"OPENAPI_URL\", \"\")\n    # Load the client after setting the env var\n    client = get_client()\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 404, response.text\n    response = client.get(\"/docs\")\n    assert response.status_code == 404, response.text\n    response = client.get(\"/redoc\")\n    assert response.status_code == 404, response.text\n\n\ndef test_root():\n    client = get_client()\n    response = client.get(\"/\")\n    assert response.status_code == 200\n    assert response.json() == {\"message\": \"Hello World\"}\n\n\ndef test_default_openapi():\n    client = get_client()\n    response = client.get(\"/docs\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/redoc\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/openapi.json\")\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Root\",\n                        \"operationId\": \"root__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_configure_swagger_ui/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.configure_swagger_ui.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_swagger_ui():\n    response = client.get(\"/docs\")\n    assert response.status_code == 200, response.text\n    assert '\"syntaxHighlight\": false' in response.text, (\n        \"syntaxHighlight should be included and converted to JSON\"\n    )\n    assert '\"dom_id\": \"#swagger-ui\"' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert \"presets: [\" in response.text, \"default configs should be preserved\"\n    assert \"SwaggerUIBundle.presets.apis,\" in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert \"SwaggerUIBundle.SwaggerUIStandalonePreset\" in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"layout\": \"BaseLayout\",' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"deepLinking\": true,' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"showExtensions\": true,' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"showCommonExtensions\": true,' in response.text, (\n        \"default configs should be preserved\"\n    )\n\n\ndef test_get_users():\n    response = client.get(\"/users/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello foo\"}\n"
  },
  {
    "path": "tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.configure_swagger_ui.tutorial002_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_swagger_ui():\n    response = client.get(\"/docs\")\n    assert response.status_code == 200, response.text\n    assert '\"syntaxHighlight\": false' not in response.text, (\n        \"not used parameters should not be included\"\n    )\n    assert '\"syntaxHighlight\": {\"theme\": \"obsidian\"}' in response.text, (\n        \"parameters with middle dots should be included in a JSON compatible way\"\n    )\n    assert '\"dom_id\": \"#swagger-ui\"' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert \"presets: [\" in response.text, \"default configs should be preserved\"\n    assert \"SwaggerUIBundle.presets.apis,\" in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert \"SwaggerUIBundle.SwaggerUIStandalonePreset\" in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"layout\": \"BaseLayout\",' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"deepLinking\": true,' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"showExtensions\": true,' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"showCommonExtensions\": true,' in response.text, (\n        \"default configs should be preserved\"\n    )\n\n\ndef test_get_users():\n    response = client.get(\"/users/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello foo\"}\n"
  },
  {
    "path": "tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.configure_swagger_ui.tutorial003_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_swagger_ui():\n    response = client.get(\"/docs\")\n    assert response.status_code == 200, response.text\n    assert '\"deepLinking\": false,' in response.text, (\n        \"overridden configs should be preserved\"\n    )\n    assert '\"deepLinking\": true' not in response.text, (\n        \"overridden configs should not include the old value\"\n    )\n    assert '\"syntaxHighlight\": false' not in response.text, (\n        \"not used parameters should not be included\"\n    )\n    assert '\"dom_id\": \"#swagger-ui\"' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert \"presets: [\" in response.text, \"default configs should be preserved\"\n    assert \"SwaggerUIBundle.presets.apis,\" in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert \"SwaggerUIBundle.SwaggerUIStandalonePreset\" in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"layout\": \"BaseLayout\",' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"showExtensions\": true,' in response.text, (\n        \"default configs should be preserved\"\n    )\n    assert '\"showCommonExtensions\": true,' in response.text, (\n        \"default configs should be preserved\"\n    )\n\n\ndef test_get_users():\n    response = client.get(\"/users/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello foo\"}\n"
  },
  {
    "path": "tests/test_tutorial/test_cookie_param_models/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_cookie_param_models/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.cookie_param_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_cookie_param_model(client: TestClient):\n    with client as c:\n        c.cookies.set(\"session_id\", \"123\")\n        c.cookies.set(\"fatebook_tracker\", \"456\")\n        c.cookies.set(\"googall_tracker\", \"789\")\n        response = c.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"session_id\": \"123\",\n        \"fatebook_tracker\": \"456\",\n        \"googall_tracker\": \"789\",\n    }\n\n\ndef test_cookie_param_model_defaults(client: TestClient):\n    with client as c:\n        c.cookies.set(\"session_id\", \"123\")\n        response = c.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"session_id\": \"123\",\n        \"fatebook_tracker\": None,\n        \"googall_tracker\": None,\n    }\n\n\ndef test_cookie_param_model_invalid(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 422\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"missing\",\n                    \"loc\": [\"cookie\", \"session_id\"],\n                    \"msg\": \"Field required\",\n                    \"input\": {},\n                }\n            ]\n        }\n    )\n\n\ndef test_cookie_param_model_extra(client: TestClient):\n    with client as c:\n        c.cookies.set(\"session_id\", \"123\")\n        c.cookies.set(\"extra\", \"track-me-here-too\")\n        response = c.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\"session_id\": \"123\", \"fatebook_tracker\": None, \"googall_tracker\": None}\n    )\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"session_id\",\n                                \"in\": \"cookie\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"string\", \"title\": \"Session Id\"},\n                            },\n                            {\n                                \"name\": \"fatebook_tracker\",\n                                \"in\": \"cookie\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Fatebook Tracker\",\n                                },\n                            },\n                            {\n                                \"name\": \"googall_tracker\",\n                                \"in\": \"cookie\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Googall Tracker\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_cookie_param_models/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=[needs_py310]),\n        pytest.param(\"tutorial002_an_py310\", marks=[needs_py310]),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.cookie_param_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_cookie_param_model(client: TestClient):\n    with client as c:\n        c.cookies.set(\"session_id\", \"123\")\n        c.cookies.set(\"fatebook_tracker\", \"456\")\n        c.cookies.set(\"googall_tracker\", \"789\")\n        response = c.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"session_id\": \"123\",\n        \"fatebook_tracker\": \"456\",\n        \"googall_tracker\": \"789\",\n    }\n\n\ndef test_cookie_param_model_defaults(client: TestClient):\n    with client as c:\n        c.cookies.set(\"session_id\", \"123\")\n        response = c.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"session_id\": \"123\",\n        \"fatebook_tracker\": None,\n        \"googall_tracker\": None,\n    }\n\n\ndef test_cookie_param_model_invalid(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"cookie\", \"session_id\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            }\n        ]\n    }\n\n\ndef test_cookie_param_model_extra(client: TestClient):\n    with client as c:\n        c.cookies.set(\"session_id\", \"123\")\n        c.cookies.set(\"extra\", \"track-me-here-too\")\n        response = c.get(\"/items/\")\n    assert response.status_code == 422\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"extra_forbidden\",\n                    \"loc\": [\"cookie\", \"extra\"],\n                    \"msg\": \"Extra inputs are not permitted\",\n                    \"input\": \"track-me-here-too\",\n                }\n            ]\n        }\n    )\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"session_id\",\n                                \"in\": \"cookie\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"string\", \"title\": \"Session Id\"},\n                            },\n                            {\n                                \"name\": \"fatebook_tracker\",\n                                \"in\": \"cookie\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\"type\": \"string\"},\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Fatebook Tracker\",\n                                },\n                            },\n                            {\n                                \"name\": \"googall_tracker\",\n                                \"in\": \"cookie\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Googall Tracker\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_cookie_params/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_cookie_params/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_mod(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.cookie_params.{request.param}\")\n\n    return mod\n\n\n@pytest.mark.parametrize(\n    \"path,cookies,expected_status,expected_response\",\n    [\n        (\"/items\", None, 200, {\"ads_id\": None}),\n        (\"/items\", {\"ads_id\": \"ads_track\"}, 200, {\"ads_id\": \"ads_track\"}),\n        (\n            \"/items\",\n            {\"ads_id\": \"ads_track\", \"session\": \"cookiesession\"},\n            200,\n            {\"ads_id\": \"ads_track\"},\n        ),\n        (\"/items\", {\"session\": \"cookiesession\"}, 200, {\"ads_id\": None}),\n    ],\n)\ndef test(path, cookies, expected_status, expected_response, mod: ModuleType):\n    client = TestClient(mod.app, cookies=cookies)\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Ads Id\",\n                                },\n                                \"name\": \"ads_id\",\n                                \"in\": \"cookie\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_cors/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_cors/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.cors.tutorial001_py310 import app\n\n\ndef test_cors():\n    client = TestClient(app)\n    # Test pre-flight response\n    headers = {\n        \"Origin\": \"https://localhost.tiangolo.com\",\n        \"Access-Control-Request-Method\": \"GET\",\n        \"Access-Control-Request-Headers\": \"X-Example\",\n    }\n    response = client.options(\"/\", headers=headers)\n    assert response.status_code == 200, response.text\n    assert response.text == \"OK\"\n    assert (\n        response.headers[\"access-control-allow-origin\"]\n        == \"https://localhost.tiangolo.com\"\n    )\n    assert response.headers[\"access-control-allow-headers\"] == \"X-Example\"\n\n    # Test standard response\n    headers = {\"Origin\": \"https://localhost.tiangolo.com\"}\n    response = client.get(\"/\", headers=headers)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello World\"}\n    assert (\n        response.headers[\"access-control-allow-origin\"]\n        == \"https://localhost.tiangolo.com\"\n    )\n\n    # Test non-CORS response\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello World\"}\n    assert \"access-control-allow-origin\" not in response.headers\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_docs_ui/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py",
    "content": "import os\nfrom pathlib import Path\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom tests.utils import workdir_lock\n\n\n@pytest.fixture(scope=\"module\")\ndef client():\n    static_dir: Path = Path(os.getcwd()) / \"static\"\n    print(static_dir)\n    static_dir.mkdir(exist_ok=True)\n    from docs_src.custom_docs_ui.tutorial001_py310 import app\n\n    with TestClient(app) as client:\n        yield client\n    static_dir.rmdir()\n\n\n@workdir_lock\ndef test_swagger_ui_html(client: TestClient):\n    response = client.get(\"/docs\")\n    assert response.status_code == 200, response.text\n    assert \"https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js\" in response.text\n    assert \"https://unpkg.com/swagger-ui-dist@5/swagger-ui.css\" in response.text\n\n\n@workdir_lock\ndef test_swagger_ui_oauth2_redirect_html(client: TestClient):\n    response = client.get(\"/docs/oauth2-redirect\")\n    assert response.status_code == 200, response.text\n    assert \"window.opener.swaggerUIRedirectOauth2\" in response.text\n\n\n@workdir_lock\ndef test_redoc_html(client: TestClient):\n    response = client.get(\"/redoc\")\n    assert response.status_code == 200, response.text\n    assert \"https://unpkg.com/redoc@2/bundles/redoc.standalone.js\" in response.text\n\n\n@workdir_lock\ndef test_api(client: TestClient):\n    response = client.get(\"/users/john\")\n    assert response.status_code == 200, response.text\n    assert response.json()[\"message\"] == \"Hello john\"\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py",
    "content": "import os\nfrom pathlib import Path\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom tests.utils import workdir_lock\n\n\n@pytest.fixture(scope=\"module\")\ndef client():\n    static_dir: Path = Path(os.getcwd()) / \"static\"\n    print(static_dir)\n    static_dir.mkdir(exist_ok=True)\n    from docs_src.custom_docs_ui.tutorial002_py310 import app\n\n    with TestClient(app) as client:\n        yield client\n    static_dir.rmdir()\n\n\n@workdir_lock\ndef test_swagger_ui_html(client: TestClient):\n    response = client.get(\"/docs\")\n    assert response.status_code == 200, response.text\n    assert \"/static/swagger-ui-bundle.js\" in response.text\n    assert \"/static/swagger-ui.css\" in response.text\n\n\n@workdir_lock\ndef test_swagger_ui_oauth2_redirect_html(client: TestClient):\n    response = client.get(\"/docs/oauth2-redirect\")\n    assert response.status_code == 200, response.text\n    assert \"window.opener.swaggerUIRedirectOauth2\" in response.text\n\n\n@workdir_lock\ndef test_redoc_html(client: TestClient):\n    response = client.get(\"/redoc\")\n    assert response.status_code == 200, response.text\n    assert \"/static/redoc.standalone.js\" in response.text\n\n\n@workdir_lock\ndef test_api(client: TestClient):\n    response = client.get(\"/users/john\")\n    assert response.status_code == 200, response.text\n    assert response.json()[\"message\"] == \"Hello john\"\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_request_and_route/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py",
    "content": "import gzip\nimport importlib\nimport json\n\nimport pytest\nfrom fastapi import Request\nfrom fastapi.testclient import TestClient\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.custom_request_and_route.{request.param}\")\n\n    @mod.app.get(\"/check-class\")\n    async def check_gzip_request(request: Request):\n        return {\"request_class\": type(request).__name__}\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\"compress\", [True, False])\ndef test_gzip_request(client: TestClient, compress):\n    n = 1000\n    headers = {}\n    body = [1] * n\n    data = json.dumps(body).encode()\n    if compress:\n        data = gzip.compress(data)\n        headers[\"Content-Encoding\"] = \"gzip\"\n    headers[\"Content-Type\"] = \"application/json\"\n    response = client.post(\"/sum\", content=data, headers=headers)\n    assert response.json() == {\"sum\": n}\n\n\ndef test_request_class(client: TestClient):\n    response = client.get(\"/check-class\")\n    assert response.json() == {\"request_class\": \"GzipRequest\"}\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom dirty_equals import IsOneOf\nfrom fastapi.testclient import TestClient\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.custom_request_and_route.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_endpoint_works(client: TestClient):\n    response = client.post(\"/\", json=[1, 2, 3])\n    assert response.json() == 6\n\n\ndef test_exception_handler_body_access(client: TestClient):\n    response = client.post(\"/\", json={\"numbers\": [1, 2, 3]})\n    assert response.json() == {\n        \"detail\": {\n            \"errors\": [\n                {\n                    \"type\": \"list_type\",\n                    \"loc\": [\"body\"],\n                    \"msg\": \"Input should be a valid list\",\n                    \"input\": {\"numbers\": [1, 2, 3]},\n                }\n            ],\n            # httpx 0.28.0 switches to compact JSON https://github.com/encode/httpx/issues/3363\n            \"body\": IsOneOf('{\"numbers\": [1, 2, 3]}', '{\"numbers\":[1,2,3]}'),\n        }\n    }\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.custom_request_and_route.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get(client: TestClient):\n    response = client.get(\"/\")\n    assert response.json() == {\"message\": \"Not timed\"}\n    assert \"X-Response-Time\" not in response.headers\n\n\ndef test_get_timed(client: TestClient):\n    response = client.get(\"/timed\")\n    assert response.json() == {\"message\": \"It's the time of my life\"}\n    assert \"X-Response-Time\" in response.headers\n    assert float(response.headers[\"X-Response-Time\"]) >= 0\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\npytest.importorskip(\"orjson\")\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.custom_response.{request.param}\")\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.filterwarnings(\"ignore::fastapi.exceptions.FastAPIDeprecationWarning\")\ndef test_get_custom_response(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item_id\": \"Foo\"}]\n\n\n@pytest.mark.filterwarnings(\"ignore::fastapi.exceptions.FastAPIDeprecationWarning\")\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial001b.py",
    "content": "import warnings\n\nimport pytest\nfrom fastapi.exceptions import FastAPIDeprecationWarning\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nwith warnings.catch_warnings():\n    warnings.simplefilter(\"ignore\", FastAPIDeprecationWarning)\n    from docs_src.custom_response.tutorial001b_py310 import app\n\nclient = TestClient(app)\n\npytest.importorskip(\"orjson\")\n\n\n@pytest.mark.filterwarnings(\"ignore::fastapi.exceptions.FastAPIDeprecationWarning\")\ndef test_get_custom_response():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item_id\": \"Foo\"}]\n\n\n@pytest.mark.filterwarnings(\"ignore::fastapi.exceptions.FastAPIDeprecationWarning\")\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial002_tutorial003_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import Is, snapshot\n\n\n@pytest.fixture(\n    name=\"mod_name\",\n    params=[\n        pytest.param(\"tutorial002_py310\"),\n        pytest.param(\"tutorial003_py310\"),\n        pytest.param(\"tutorial004_py310\"),\n    ],\n)\ndef get_mod_name(request: pytest.FixtureRequest) -> str:\n    return request.param\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(mod_name: str) -> TestClient:\n    mod = importlib.import_module(f\"docs_src.custom_response.{mod_name}\")\n    return TestClient(mod.app)\n\n\nhtml_contents = \"\"\"\n    <html>\n        <head>\n            <title>Some HTML in here</title>\n        </head>\n        <body>\n            <h1>Look ma! HTML!</h1>\n        </body>\n    </html>\n    \"\"\"\n\n\ndef test_get_custom_response(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.text == html_contents\n\n\ndef test_openapi_schema(client: TestClient, mod_name: str):\n    if mod_name.startswith(\"tutorial003\"):\n        response_content = {\"application/json\": {\"schema\": {}}}\n    else:\n        response_content = {\"text/html\": {\"schema\": {\"type\": \"string\"}}}\n\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": Is(response_content),\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial005.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.custom_response.tutorial005_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    assert response.text == \"Hello World\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Main\",\n                        \"operationId\": \"main__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"text/plain\": {\"schema\": {\"type\": \"string\"}}\n                                },\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial006.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.custom_response.tutorial006_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/typer\", follow_redirects=False)\n    assert response.status_code == 307, response.text\n    assert response.headers[\"location\"] == \"https://typer.tiangolo.com\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/typer\": {\n                    \"get\": {\n                        \"summary\": \"Redirect Typer\",\n                        \"operationId\": \"redirect_typer_typer_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial006b.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.custom_response.tutorial006b_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_redirect_response_class():\n    response = client.get(\"/fastapi\", follow_redirects=False)\n    assert response.status_code == 307\n    assert response.headers[\"location\"] == \"https://fastapi.tiangolo.com\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/fastapi\": {\n                    \"get\": {\n                        \"summary\": \"Redirect Fastapi\",\n                        \"operationId\": \"redirect_fastapi_fastapi_get\",\n                        \"responses\": {\"307\": {\"description\": \"Successful Response\"}},\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial006c.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.custom_response.tutorial006c_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_redirect_status_code():\n    response = client.get(\"/pydantic\", follow_redirects=False)\n    assert response.status_code == 302\n    assert response.headers[\"location\"] == \"https://docs.pydantic.dev/\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/pydantic\": {\n                    \"get\": {\n                        \"summary\": \"Redirect Pydantic\",\n                        \"operationId\": \"redirect_pydantic_pydantic_get\",\n                        \"responses\": {\"302\": {\"description\": \"Successful Response\"}},\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial007.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.custom_response.tutorial007_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get():\n    fake_content = b\"some fake video bytes\"\n    response = client.get(\"/\")\n    assert response.content == fake_content * 10\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial008.py",
    "content": "from pathlib import Path\n\nfrom fastapi.testclient import TestClient\n\nfrom docs_src.custom_response import tutorial008_py310\nfrom docs_src.custom_response.tutorial008_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get(tmp_path: Path):\n    file_path: Path = tmp_path / \"large-video-file.mp4\"\n    tutorial008_py310.some_file_path = str(file_path)\n    test_content = b\"Fake video bytes\"\n    file_path.write_bytes(test_content)\n    response = client.get(\"/\")\n    assert response.content == test_content\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial009.py",
    "content": "from pathlib import Path\n\nfrom fastapi.testclient import TestClient\n\nfrom docs_src.custom_response import tutorial009_py310\nfrom docs_src.custom_response.tutorial009_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get(tmp_path: Path):\n    file_path: Path = tmp_path / \"large-video-file.mp4\"\n    tutorial009_py310.some_file_path = str(file_path)\n    test_content = b\"Fake video bytes\"\n    file_path.write_bytes(test_content)\n    response = client.get(\"/\")\n    assert response.content == test_content\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial009b.py",
    "content": "from pathlib import Path\n\nfrom fastapi.testclient import TestClient\n\nfrom docs_src.custom_response import tutorial009b_py310\nfrom docs_src.custom_response.tutorial009b_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get(tmp_path: Path):\n    file_path: Path = tmp_path / \"large-video-file.mp4\"\n    tutorial009b_py310.some_file_path = str(file_path)\n    test_content = b\"Fake video bytes\"\n    file_path.write_bytes(test_content)\n    response = client.get(\"/\")\n    assert response.content == test_content\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial009c.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\n\npytest.importorskip(\"orjson\")\n\nfrom docs_src.custom_response.tutorial009c_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/\")\n    assert response.content == b'{\\n  \"message\": \"Hello World\"\\n}'\n"
  },
  {
    "path": "tests/test_tutorial/test_custom_response/test_tutorial010.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial010_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.custom_response.{request.param}\")\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_custom_response(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.text == snapshot(\"<h1>Items</h1><p>This is a list of items.</p>\")\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"text/html\": {\"schema\": {\"type\": \"string\"}}\n                                },\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_dataclasses/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_dataclasses/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dataclasses_.{request.param}\")\n\n    client = TestClient(mod.app)\n    client.headers.clear()\n    return client\n\n\ndef test_post_item(client: TestClient):\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"price\": 3})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"price\": 3,\n        \"description\": None,\n        \"tax\": None,\n    }\n\n\ndef test_post_invalid_item(client: TestClient):\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"price\": \"invalid price\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"float_parsing\",\n                \"loc\": [\"body\", \"price\"],\n                \"msg\": \"Input should be a valid number, unable to parse string as a number\",\n                \"input\": \"invalid price\",\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_dataclasses/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dataclasses_.{request.param}\")\n\n    client = TestClient(mod.app)\n    client.headers.clear()\n    return client\n\n\ndef test_get_item(client: TestClient):\n    response = client.get(\"/items/next\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"name\": \"Island In The Moon\",\n        \"price\": 12.99,\n        \"description\": \"A place to be playin' and havin' fun\",\n        \"tags\": [\"breater\"],\n        \"tax\": None,\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/next\": {\n                    \"get\": {\n                        \"summary\": \"Read Next Item\",\n                        \"operationId\": \"read_next_item_items_next_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            }\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                            },\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_dataclasses/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dataclasses_.{request.param}\")\n\n    client = TestClient(mod.app)\n    client.headers.clear()\n    return client\n\n\ndef test_post_authors_item(client: TestClient):\n    response = client.post(\n        \"/authors/foo/items/\",\n        json=[{\"name\": \"Bar\"}, {\"name\": \"Baz\", \"description\": \"Drop the Baz\"}],\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"name\": \"foo\",\n        \"items\": [\n            {\"name\": \"Bar\", \"description\": None},\n            {\"name\": \"Baz\", \"description\": \"Drop the Baz\"},\n        ],\n    }\n\n\ndef test_get_authors(client: TestClient):\n    response = client.get(\"/authors/\")\n    assert response.status_code == 200\n    assert response.json() == [\n        {\n            \"name\": \"Breaters\",\n            \"items\": [\n                {\n                    \"name\": \"Island In The Moon\",\n                    \"description\": \"A place to be playin' and havin' fun\",\n                },\n                {\"name\": \"Holy Buddies\", \"description\": None},\n            ],\n        },\n        {\n            \"name\": \"System of an Up\",\n            \"items\": [\n                {\n                    \"name\": \"Salt\",\n                    \"description\": \"The kombucha mushroom people's favorite\",\n                },\n                {\"name\": \"Pad Thai\", \"description\": None},\n                {\n                    \"name\": \"Lonely Night\",\n                    \"description\": \"The mostests lonliest nightiest of allest\",\n                },\n            ],\n        },\n    ]\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/authors/{author_id}/items/\": {\n                    \"post\": {\n                        \"summary\": \"Create Author Items\",\n                        \"operationId\": \"create_author_items_authors__author_id__items__post\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Author Id\", \"type\": \"string\"},\n                                \"name\": \"author_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"title\": \"Items\",\n                                        \"type\": \"array\",\n                                        \"items\": {\"$ref\": \"#/components/schemas/Item\"},\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/Author\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/authors/\": {\n                    \"get\": {\n                        \"summary\": \"Get Authors\",\n                        \"operationId\": \"get_authors_authors__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Get Authors Authors  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Author\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Author\": {\n                        \"title\": \"Author\",\n                        \"required\": [\"name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"items\": {\n                                \"title\": \"Items\",\n                                \"type\": \"array\",\n                                \"items\": {\"$ref\": \"#/components/schemas/Item\"},\n                            },\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_debugging/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_debugging/test_tutorial001.py",
    "content": "import importlib\nimport runpy\nimport sys\nimport unittest\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nMOD_NAME = \"docs_src.debugging.tutorial001_py310\"\n\n\n@pytest.fixture(name=\"client\")\ndef get_client():\n    mod = importlib.import_module(MOD_NAME)\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_uvicorn_run_is_not_called_on_import():\n    if sys.modules.get(MOD_NAME):\n        del sys.modules[MOD_NAME]  # pragma: no cover\n    with unittest.mock.patch(\"uvicorn.run\") as uvicorn_run_mock:\n        importlib.import_module(MOD_NAME)\n    uvicorn_run_mock.assert_not_called()\n\n\ndef test_get_root(client: TestClient):\n    response = client.get(\"/\")\n    assert response.status_code == 200\n    assert response.json() == {\"hello world\": \"ba\"}\n\n\ndef test_uvicorn_run_called_when_run_as_main():  # Just for coverage\n    if sys.modules.get(MOD_NAME):\n        del sys.modules[MOD_NAME]\n    with unittest.mock.patch(\"uvicorn.run\") as uvicorn_run_mock:\n        runpy.run_module(MOD_NAME, run_name=\"__main__\")\n\n    uvicorn_run_mock.assert_called_once_with(\n        unittest.mock.ANY, host=\"0.0.0.0\", port=8000\n    )\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Root\",\n                        \"operationId\": \"root__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial001_tutorial001_02.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_02_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dependencies.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"path,expected_status,expected_response\",\n    [\n        (\"/items\", 200, {\"q\": None, \"skip\": 0, \"limit\": 100}),\n        (\"/items?q=foo\", 200, {\"q\": \"foo\", \"skip\": 0, \"limit\": 100}),\n        (\"/items?q=foo&skip=5\", 200, {\"q\": \"foo\", \"skip\": 5, \"limit\": 100}),\n        (\"/items?q=foo&skip=5&limit=30\", 200, {\"q\": \"foo\", \"skip\": 5, \"limit\": 30}),\n        (\"/users\", 200, {\"q\": None, \"skip\": 0, \"limit\": 100}),\n    ],\n)\ndef test_get(path, expected_status, expected_response, client: TestClient):\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Skip\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"skip\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                    }\n                },\n                \"/users/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Users\",\n                        \"operationId\": \"read_users_users__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Skip\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"skip\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial002_tutorial003_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_an_py310\", marks=needs_py310),\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n        pytest.param(\"tutorial003_an_py310\", marks=needs_py310),\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n        pytest.param(\"tutorial004_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dependencies.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"path,expected_status,expected_response\",\n    [\n        (\n            \"/items\",\n            200,\n            {\n                \"items\": [\n                    {\"item_name\": \"Foo\"},\n                    {\"item_name\": \"Bar\"},\n                    {\"item_name\": \"Baz\"},\n                ]\n            },\n        ),\n        (\n            \"/items?q=foo\",\n            200,\n            {\n                \"items\": [\n                    {\"item_name\": \"Foo\"},\n                    {\"item_name\": \"Bar\"},\n                    {\"item_name\": \"Baz\"},\n                ],\n                \"q\": \"foo\",\n            },\n        ),\n        (\n            \"/items?q=foo&skip=1\",\n            200,\n            {\"items\": [{\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}], \"q\": \"foo\"},\n        ),\n        (\n            \"/items?q=bar&limit=2\",\n            200,\n            {\"items\": [{\"item_name\": \"Foo\"}, {\"item_name\": \"Bar\"}], \"q\": \"bar\"},\n        ),\n        (\n            \"/items?q=bar&skip=1&limit=1\",\n            200,\n            {\"items\": [{\"item_name\": \"Bar\"}], \"q\": \"bar\"},\n        ),\n        (\n            \"/items?limit=1&q=bar&skip=1\",\n            200,\n            {\"items\": [{\"item_name\": \"Bar\"}], \"q\": \"bar\"},\n        ),\n    ],\n)\ndef test_get(path, expected_status, expected_response, client: TestClient):\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Skip\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"skip\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"type\": \"integer\",\n                                    \"default\": 100,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial005.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n        pytest.param(\"tutorial005_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dependencies.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"path,cookie,expected_status,expected_response\",\n    [\n        (\n            \"/items\",\n            \"from_cookie\",\n            200,\n            {\"q_or_cookie\": \"from_cookie\"},\n        ),\n        (\n            \"/items?q=foo\",\n            \"from_cookie\",\n            200,\n            {\"q_or_cookie\": \"foo\"},\n        ),\n        (\n            \"/items\",\n            None,\n            200,\n            {\"q_or_cookie\": None},\n        ),\n    ],\n)\ndef test_get(path, cookie, expected_status, expected_response, client: TestClient):\n    if cookie is not None:\n        client.cookies.set(\"last_query\", cookie)\n    else:\n        client.cookies.clear()\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Query\",\n                        \"operationId\": \"read_query_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Last Query\",\n                                },\n                                \"name\": \"last_query\",\n                                \"in\": \"cookie\",\n                            },\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial006.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial006_py310\"),\n        pytest.param(\"tutorial006_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dependencies.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_no_headers(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"x-token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"x-key\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_get_invalid_one_header(client: TestClient):\n    response = client.get(\"/items/\", headers={\"X-Token\": \"invalid\"})\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"X-Token header invalid\"}\n\n\ndef test_get_invalid_second_header(client: TestClient):\n    response = client.get(\n        \"/items/\", headers={\"X-Token\": \"fake-super-secret-token\", \"X-Key\": \"invalid\"}\n    )\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"X-Key header invalid\"}\n\n\ndef test_get_valid_headers(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        headers={\n            \"X-Token\": \"fake-super-secret-token\",\n            \"X-Key\": \"fake-super-secret-key\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item\": \"Foo\"}, {\"item\": \"Bar\"}]\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"X-Token\", \"type\": \"string\"},\n                                \"name\": \"x-token\",\n                                \"in\": \"header\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"X-Key\", \"type\": \"string\"},\n                                \"name\": \"x-key\",\n                                \"in\": \"header\",\n                            },\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial007.py",
    "content": "import asyncio\nfrom contextlib import asynccontextmanager\nfrom unittest.mock import Mock, patch\n\nfrom docs_src.dependencies.tutorial007_py310 import get_db\n\n\ndef test_get_db():  # Just for coverage\n    async def test_async_gen():\n        cm = asynccontextmanager(get_db)\n        async with cm() as db_session:\n            return db_session\n\n    dbsession_moock = Mock()\n\n    with patch(\n        \"docs_src.dependencies.tutorial007_py310.DBSession\",\n        return_value=dbsession_moock,\n        create=True,\n    ):\n        value = asyncio.run(test_async_gen())\n\n    assert value is dbsession_moock\n    dbsession_moock.close.assert_called_once()\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial008.py",
    "content": "import importlib\nimport sys\nfrom types import ModuleType\nfrom typing import Annotated, Any\nfrom unittest.mock import Mock, patch\n\nimport pytest\nfrom fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        \"tutorial008_py310\",\n        pytest.param(\n            \"tutorial008_an_py310\",\n            marks=pytest.mark.xfail(\n                sys.version_info < (3, 14),\n                reason=\"Fails with `NameError: name 'DepA' is not defined`\",\n            ),\n        ),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest):\n    mod_name = f\"docs_src.dependencies.{request.param}\"\n    mod = importlib.import_module(mod_name)\n    return mod\n\n\ndef test_get_db(module: ModuleType):\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def read_root(c: Annotated[Any, Depends(module.dependency_c)]):\n        return {\"c\": str(c)}\n\n    client = TestClient(app)\n\n    a_mock = Mock()\n    b_mock = Mock()\n    c_mock = Mock()\n\n    with (\n        patch(\n            f\"{module.__name__}.generate_dep_a\",\n            return_value=a_mock,\n            create=True,\n        ),\n        patch(\n            f\"{module.__name__}.generate_dep_b\",\n            return_value=b_mock,\n            create=True,\n        ),\n        patch(\n            f\"{module.__name__}.generate_dep_c\",\n            return_value=c_mock,\n            create=True,\n        ),\n    ):\n        response = client.get(\"/\")\n\n    assert response.status_code == 200\n    assert response.json() == {\"c\": str(c_mock)}\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial008b.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial008b_py310\"),\n        pytest.param(\"tutorial008b_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dependencies.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_no_item(client: TestClient):\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 404, response.text\n    assert response.json() == {\"detail\": \"Item not found\"}\n\n\ndef test_owner_error(client: TestClient):\n    response = client.get(\"/items/plumbus\")\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"Owner error: Rick\"}\n\n\ndef test_get_item(client: TestClient):\n    response = client.get(\"/items/portal-gun\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"description\": \"Gun to create portals\", \"owner\": \"Rick\"}\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial008c.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom fastapi.exceptions import FastAPIError\nfrom fastapi.testclient import TestClient\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial008c_py310\"),\n        pytest.param(\"tutorial008c_an_py310\"),\n    ],\n)\ndef get_mod(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dependencies.{request.param}\")\n\n    return mod\n\n\ndef test_get_no_item(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 404, response.text\n    assert response.json() == {\"detail\": \"Item not found, there's only a plumbus here\"}\n\n\ndef test_get(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/items/plumbus\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"plumbus\"\n\n\ndef test_fastapi_error(mod: ModuleType):\n    client = TestClient(mod.app)\n    with pytest.raises(FastAPIError) as exc_info:\n        client.get(\"/items/portal-gun\")\n    assert \"raising an exception and a dependency with yield\" in exc_info.value.args[0]\n\n\ndef test_internal_server_error(mod: ModuleType):\n    client = TestClient(mod.app, raise_server_exceptions=False)\n    response = client.get(\"/items/portal-gun\")\n    assert response.status_code == 500, response.text\n    assert response.text == \"Internal Server Error\"\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial008d.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial008d_py310\"),\n        pytest.param(\"tutorial008d_an_py310\"),\n    ],\n)\ndef get_mod(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dependencies.{request.param}\")\n\n    return mod\n\n\ndef test_get_no_item(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 404, response.text\n    assert response.json() == {\"detail\": \"Item not found, there's only a plumbus here\"}\n\n\ndef test_get(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/items/plumbus\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"plumbus\"\n\n\ndef test_internal_error(mod: ModuleType):\n    client = TestClient(mod.app)\n    with pytest.raises(mod.InternalError) as exc_info:\n        client.get(\"/items/portal-gun\")\n    assert (\n        exc_info.value.args[0] == \"The portal gun is too dangerous to be owned by Rick\"\n    )\n\n\ndef test_internal_server_error(mod: ModuleType):\n    client = TestClient(mod.app, raise_server_exceptions=False)\n    response = client.get(\"/items/portal-gun\")\n    assert response.status_code == 500, response.text\n    assert response.text == \"Internal Server Error\"\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial008e.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial008e_py310\"),\n        pytest.param(\"tutorial008e_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dependencies.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_users_me(client: TestClient):\n    response = client.get(\"/users/me\")\n    assert response.status_code == 200, response.text\n    assert response.json() == \"Rick\"\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial010.py",
    "content": "from typing import Annotated, Any\nfrom unittest.mock import Mock, patch\n\nfrom fastapi import Depends, FastAPI\nfrom fastapi.testclient import TestClient\n\nfrom docs_src.dependencies.tutorial010_py310 import get_db\n\n\ndef test_get_db():\n    app = FastAPI()\n\n    @app.get(\"/\")\n    def read_root(c: Annotated[Any, Depends(get_db)]):\n        return {\"c\": str(c)}\n\n    client = TestClient(app)\n\n    dbsession_mock = Mock()\n\n    with patch(\n        \"docs_src.dependencies.tutorial010_py310.DBSession\",\n        return_value=dbsession_mock,\n        create=True,\n    ):\n        response = client.get(\"/\")\n\n    assert response.status_code == 200\n    assert response.json() == {\"c\": str(dbsession_mock)}\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial011.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial011_py310\",\n        pytest.param(\"tutorial011_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dependencies.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"path,expected_status,expected_response\",\n    [\n        (\n            \"/query-checker/\",\n            200,\n            {\"fixed_content_in_query\": False},\n        ),\n        (\n            \"/query-checker/?q=qwerty\",\n            200,\n            {\"fixed_content_in_query\": False},\n        ),\n        (\n            \"/query-checker/?q=foobar\",\n            200,\n            {\"fixed_content_in_query\": True},\n        ),\n    ],\n)\ndef test_get(path, expected_status, expected_response, client: TestClient):\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/query-checker/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Query Check\",\n                        \"operationId\": \"read_query_check_query_checker__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"string\",\n                                    \"default\": \"\",\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_dependencies/test_tutorial012.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial012_py310\"),\n        pytest.param(\"tutorial012_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.dependencies.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_no_headers_items(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"x-token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"x-key\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_get_no_headers_users(client: TestClient):\n    response = client.get(\"/users/\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"x-token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"header\", \"x-key\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_get_invalid_one_header_items(client: TestClient):\n    response = client.get(\"/items/\", headers={\"X-Token\": \"invalid\"})\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"X-Token header invalid\"}\n\n\ndef test_get_invalid_one_users(client: TestClient):\n    response = client.get(\"/users/\", headers={\"X-Token\": \"invalid\"})\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"X-Token header invalid\"}\n\n\ndef test_get_invalid_second_header_items(client: TestClient):\n    response = client.get(\n        \"/items/\", headers={\"X-Token\": \"fake-super-secret-token\", \"X-Key\": \"invalid\"}\n    )\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"X-Key header invalid\"}\n\n\ndef test_get_invalid_second_header_users(client: TestClient):\n    response = client.get(\n        \"/users/\", headers={\"X-Token\": \"fake-super-secret-token\", \"X-Key\": \"invalid\"}\n    )\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"X-Key header invalid\"}\n\n\ndef test_get_valid_headers_items(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        headers={\n            \"X-Token\": \"fake-super-secret-token\",\n            \"X-Key\": \"fake-super-secret-key\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item\": \"Portal Gun\"}, {\"item\": \"Plumbus\"}]\n\n\ndef test_get_valid_headers_users(client: TestClient):\n    response = client.get(\n        \"/users/\",\n        headers={\n            \"X-Token\": \"fake-super-secret-token\",\n            \"X-Key\": \"fake-super-secret-key\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"username\": \"Rick\"}, {\"username\": \"Morty\"}]\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"X-Token\", \"type\": \"string\"},\n                                \"name\": \"x-token\",\n                                \"in\": \"header\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"X-Key\", \"type\": \"string\"},\n                                \"name\": \"x-key\",\n                                \"in\": \"header\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/users/\": {\n                    \"get\": {\n                        \"summary\": \"Read Users\",\n                        \"operationId\": \"read_users_users__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"X-Token\", \"type\": \"string\"},\n                                \"name\": \"x-token\",\n                                \"in\": \"header\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"X-Key\", \"type\": \"string\"},\n                                \"name\": \"x-key\",\n                                \"in\": \"header\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_encoder/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_encoder/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest):\n    module = importlib.import_module(f\"docs_src.encoder.{request.param}\")\n    return module\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(mod: ModuleType):\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_put(client: TestClient, mod: ModuleType):\n    fake_db = mod.fake_db\n\n    response = client.put(\n        \"/items/123\",\n        json={\n            \"title\": \"Foo\",\n            \"timestamp\": \"2023-01-01T12:00:00\",\n            \"description\": \"An optional description\",\n        },\n    )\n    assert response.status_code == 200\n    assert \"123\" in fake_db\n    assert fake_db[\"123\"] == {\n        \"title\": \"Foo\",\n        \"timestamp\": \"2023-01-01T12:00:00\",\n        \"description\": \"An optional description\",\n    }\n\n\ndef test_put_invalid_data(client: TestClient, mod: ModuleType):\n    fake_db = mod.fake_db\n\n    response = client.put(\n        \"/items/345\",\n        json={\n            \"title\": \"Foo\",\n            \"timestamp\": \"not a date\",\n        },\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"body\", \"timestamp\"],\n                \"msg\": \"Input should be a valid datetime or date, invalid character in year\",\n                \"type\": \"datetime_from_date_parsing\",\n                \"input\": \"not a date\",\n                \"ctx\": {\"error\": \"invalid character in year\"},\n            }\n        ]\n    }\n    assert \"345\" not in fake_db\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{id}\": {\n                    \"put\": {\n                        \"operationId\": \"update_item_items__id__put\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Id\",\n                                    \"type\": \"string\",\n                                },\n                            },\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                    },\n                                },\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"description\": {\n                                \"anyOf\": [\n                                    {\n                                        \"type\": \"string\",\n                                    },\n                                    {\n                                        \"type\": \"null\",\n                                    },\n                                ],\n                                \"title\": \"Description\",\n                            },\n                            \"timestamp\": {\n                                \"format\": \"date-time\",\n                                \"title\": \"Timestamp\",\n                                \"type\": \"string\",\n                            },\n                            \"title\": {\n                                \"title\": \"Title\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"title\",\n                            \"timestamp\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_events/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_events/test_tutorial001.py",
    "content": "import pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(name=\"app\", scope=\"module\")\ndef get_app():\n    with pytest.warns(DeprecationWarning):\n        from docs_src.events.tutorial001_py310 import app\n    yield app\n\n\ndef test_events(app: FastAPI):\n    with TestClient(app) as client:\n        response = client.get(\"/items/foo\")\n        assert response.status_code == 200, response.text\n        assert response.json() == {\"name\": \"Fighters\"}\n\n\ndef test_openapi_schema(app: FastAPI):\n    with TestClient(app) as client:\n        response = client.get(\"/openapi.json\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            {\n                \"openapi\": \"3.1.0\",\n                \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n                \"paths\": {\n                    \"/items/{item_id}\": {\n                        \"get\": {\n                            \"responses\": {\n                                \"200\": {\n                                    \"description\": \"Successful Response\",\n                                    \"content\": {\"application/json\": {\"schema\": {}}},\n                                },\n                                \"422\": {\n                                    \"description\": \"Validation Error\",\n                                    \"content\": {\n                                        \"application/json\": {\n                                            \"schema\": {\n                                                \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                            }\n                                        }\n                                    },\n                                },\n                            },\n                            \"summary\": \"Read Items\",\n                            \"operationId\": \"read_items_items__item_id__get\",\n                            \"parameters\": [\n                                {\n                                    \"required\": True,\n                                    \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                    \"name\": \"item_id\",\n                                    \"in\": \"path\",\n                                }\n                            ],\n                        }\n                    }\n                },\n                \"components\": {\n                    \"schemas\": {\n                        \"ValidationError\": {\n                            \"title\": \"ValidationError\",\n                            \"required\": [\"loc\", \"msg\", \"type\"],\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                        },\n                        \"HTTPValidationError\": {\n                            \"title\": \"HTTPValidationError\",\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"detail\": {\n                                    \"title\": \"Detail\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"$ref\": \"#/components/schemas/ValidationError\"\n                                    },\n                                }\n                            },\n                        },\n                    }\n                },\n            }\n        )\n"
  },
  {
    "path": "tests/test_tutorial/test_events/test_tutorial002.py",
    "content": "import pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import workdir_lock\n\n\n@pytest.fixture(name=\"app\", scope=\"module\")\ndef get_app():\n    with pytest.warns(DeprecationWarning):\n        from docs_src.events.tutorial002_py310 import app\n    yield app\n\n\n@workdir_lock\ndef test_events(app: FastAPI):\n    with TestClient(app) as client:\n        response = client.get(\"/items/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == [{\"name\": \"Foo\"}]\n    with open(\"log.txt\") as log:\n        assert \"Application shutdown\" in log.read()\n\n\n@workdir_lock\ndef test_openapi_schema(app: FastAPI):\n    with TestClient(app) as client:\n        response = client.get(\"/openapi.json\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            {\n                \"openapi\": \"3.1.0\",\n                \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n                \"paths\": {\n                    \"/items/\": {\n                        \"get\": {\n                            \"responses\": {\n                                \"200\": {\n                                    \"description\": \"Successful Response\",\n                                    \"content\": {\"application/json\": {\"schema\": {}}},\n                                }\n                            },\n                            \"summary\": \"Read Items\",\n                            \"operationId\": \"read_items_items__get\",\n                        }\n                    }\n                },\n            }\n        )\n"
  },
  {
    "path": "tests/test_tutorial/test_events/test_tutorial003.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.events.tutorial003_py310 import (\n    app,\n    fake_answer_to_everything_ml_model,\n    ml_models,\n)\n\n\ndef test_events():\n    assert not ml_models, \"ml_models should be empty\"\n    with TestClient(app) as client:\n        assert ml_models[\"answer_to_everything\"] == fake_answer_to_everything_ml_model\n        response = client.get(\"/predict\", params={\"x\": 2})\n        assert response.status_code == 200, response.text\n        assert response.json() == {\"result\": 84.0}\n    assert not ml_models, \"ml_models should be empty\"\n\n\ndef test_openapi_schema():\n    with TestClient(app) as client:\n        response = client.get(\"/openapi.json\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            {\n                \"openapi\": \"3.1.0\",\n                \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n                \"paths\": {\n                    \"/predict\": {\n                        \"get\": {\n                            \"summary\": \"Predict\",\n                            \"operationId\": \"predict_predict_get\",\n                            \"parameters\": [\n                                {\n                                    \"required\": True,\n                                    \"schema\": {\"title\": \"X\", \"type\": \"number\"},\n                                    \"name\": \"x\",\n                                    \"in\": \"query\",\n                                }\n                            ],\n                            \"responses\": {\n                                \"200\": {\n                                    \"description\": \"Successful Response\",\n                                    \"content\": {\"application/json\": {\"schema\": {}}},\n                                },\n                                \"422\": {\n                                    \"description\": \"Validation Error\",\n                                    \"content\": {\n                                        \"application/json\": {\n                                            \"schema\": {\n                                                \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                            }\n                                        }\n                                    },\n                                },\n                            },\n                        }\n                    }\n                },\n                \"components\": {\n                    \"schemas\": {\n                        \"HTTPValidationError\": {\n                            \"title\": \"HTTPValidationError\",\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"detail\": {\n                                    \"title\": \"Detail\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"$ref\": \"#/components/schemas/ValidationError\"\n                                    },\n                                }\n                            },\n                        },\n                        \"ValidationError\": {\n                            \"title\": \"ValidationError\",\n                            \"required\": [\"loc\", \"msg\", \"type\"],\n                            \"type\": \"object\",\n                            \"properties\": {\n                                \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                                \"input\": {\"title\": \"Input\"},\n                                \"loc\": {\n                                    \"title\": \"Location\",\n                                    \"type\": \"array\",\n                                    \"items\": {\n                                        \"anyOf\": [\n                                            {\"type\": \"string\"},\n                                            {\"type\": \"integer\"},\n                                        ]\n                                    },\n                                },\n                                \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                                \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            },\n                        },\n                    }\n                },\n            }\n        )\n"
  },
  {
    "path": "tests/test_tutorial/test_extending_openapi/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_extending_openapi/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.extending_openapi.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"name\": \"Foo\"}]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\n                \"title\": \"Custom title\",\n                \"summary\": \"This is a very custom OpenAPI schema\",\n                \"description\": \"Here's a longer description of the custom **OpenAPI** schema\",\n                \"version\": \"2.5.0\",\n                \"x-logo\": {\n                    \"url\": \"https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png\"\n                },\n            },\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                    }\n                }\n            },\n        }\n    )\n    openapi_schema = response.json()\n    # Request again to test the custom cache\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == openapi_schema\n"
  },
  {
    "path": "tests/test_tutorial/test_extra_data_types/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_extra_data_types/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.extra_data_types.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_extra_types(client: TestClient):\n    item_id = \"ff97dd87-a4a5-4a12-b412-cde99f33e00e\"\n    data = {\n        \"start_datetime\": \"2018-12-22T14:00:00+00:00\",\n        \"end_datetime\": \"2018-12-24T15:00:00+00:00\",\n        \"repeat_at\": \"15:30:00\",\n        \"process_after\": 300,\n    }\n    expected_response = data.copy()\n    expected_response.update(\n        {\n            \"start_process\": \"2018-12-22T14:05:00+00:00\",\n            \"duration\": 176_100,\n            \"item_id\": item_id,\n        }\n    )\n    response = client.put(f\"/items/{item_id}\", json=data)\n    assert response.status_code == 200, response.text\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"string\",\n                                    \"format\": \"uuid\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"required\": True,\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_read_items_items__item_id__put\"\n                                    }\n                                }\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_read_items_items__item_id__put\": {\n                        \"title\": \"Body_read_items_items__item_id__put\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"start_datetime\": {\n                                \"title\": \"Start Datetime\",\n                                \"type\": \"string\",\n                                \"format\": \"date-time\",\n                            },\n                            \"end_datetime\": {\n                                \"title\": \"End Datetime\",\n                                \"type\": \"string\",\n                                \"format\": \"date-time\",\n                            },\n                            \"repeat_at\": {\n                                \"title\": \"Repeat At\",\n                                \"anyOf\": [\n                                    {\"type\": \"string\", \"format\": \"time\"},\n                                    {\"type\": \"null\"},\n                                ],\n                            },\n                            \"process_after\": {\n                                \"title\": \"Process After\",\n                                \"type\": \"string\",\n                                \"format\": \"duration\",\n                            },\n                        },\n                        \"required\": [\"start_datetime\", \"end_datetime\", \"process_after\"],\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_extra_models/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_extra_models/test_tutorial001_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom dirty_equals import IsList\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.extra_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post(client: TestClient):\n    response = client.post(\n        \"/user/\",\n        json={\n            \"username\": \"johndoe\",\n            \"password\": \"secret\",\n            \"email\": \"johndoe@example.com\",\n            \"full_name\": \"John Doe\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"username\": \"johndoe\",\n        \"email\": \"johndoe@example.com\",\n        \"full_name\": \"John Doe\",\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/user/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/UserOut\",\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create User\",\n                        \"operationId\": \"create_user_user__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/UserIn\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"UserIn\": {\n                        \"title\": \"UserIn\",\n                        \"required\": IsList(\n                            \"username\", \"password\", \"email\", check_order=False\n                        ),\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"password\": {\"title\": \"Password\", \"type\": \"string\"},\n                            \"email\": {\n                                \"title\": \"Email\",\n                                \"type\": \"string\",\n                                \"format\": \"email\",\n                            },\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"UserOut\": {\n                        \"title\": \"UserOut\",\n                        \"required\": [\"username\", \"email\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"email\": {\n                                \"title\": \"Email\",\n                                \"type\": \"string\",\n                                \"format\": \"email\",\n                            },\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_extra_models/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.extra_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_car(client: TestClient):\n    response = client.get(\"/items/item1\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"description\": \"All my friends drive a low rider\",\n        \"type\": \"car\",\n    }\n\n\ndef test_get_plane(client: TestClient):\n    response = client.get(\"/items/item2\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"description\": \"Music is my aeroplane, it's my aeroplane\",\n        \"type\": \"plane\",\n        \"size\": 5,\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Item Items  Item Id  Get\",\n                                            \"anyOf\": [\n                                                {\n                                                    \"$ref\": \"#/components/schemas/PlaneItem\"\n                                                },\n                                                {\n                                                    \"$ref\": \"#/components/schemas/CarItem\"\n                                                },\n                                            ],\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"PlaneItem\": {\n                        \"title\": \"PlaneItem\",\n                        \"required\": [\"description\", \"size\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                            \"type\": {\n                                \"title\": \"Type\",\n                                \"type\": \"string\",\n                                \"default\": \"plane\",\n                            },\n                            \"size\": {\"title\": \"Size\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"CarItem\": {\n                        \"title\": \"CarItem\",\n                        \"required\": [\"description\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                            \"type\": {\n                                \"title\": \"Type\",\n                                \"type\": \"string\",\n                                \"default\": \"car\",\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_extra_models/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.extra_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_items(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"name\": \"Foo\", \"description\": \"There comes my hero\"},\n        {\"name\": \"Red\", \"description\": \"It's my aeroplane\"},\n    ]\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Items Items  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"description\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_extra_models/test_tutorial005.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial005_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.extra_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_items(client: TestClient):\n    response = client.get(\"/keyword-weights/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"foo\": 2.3, \"bar\": 3.4}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/keyword-weights/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Read Keyword Weights Keyword Weights  Get\",\n                                            \"type\": \"object\",\n                                            \"additionalProperties\": {\"type\": \"number\"},\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                        \"summary\": \"Read Keyword Weights\",\n                        \"operationId\": \"read_keyword_weights_keyword_weights__get\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_first_steps/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_first_steps/test_tutorial001_tutorial002_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial001_py310\",\n        \"tutorial003_py310\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.first_steps.{request.param}\")\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"path,expected_status,expected_response\",\n    [\n        (\"/\", 200, {\"message\": \"Hello World\"}),\n        (\"/nonexistent\", 404, {\"detail\": \"Not Found\"}),\n    ],\n)\ndef test_get_path(client: TestClient, path, expected_status, expected_response):\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Root\",\n                        \"operationId\": \"root__get\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_generate_clients/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_generate_clients/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.generate_clients.{request.param}\")\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_items(client: TestClient):\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"price\": 5})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"item received\"}\n\n\ndef test_get_items(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"name\": \"Plumbus\", \"price\": 3},\n        {\"name\": \"Portal Gun\", \"price\": 9001},\n    ]\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Get Items\",\n                        \"operationId\": \"get_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Get Items Items  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ResponseMessage\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"ResponseMessage\": {\n                        \"title\": \"ResponseMessage\",\n                        \"required\": [\"message\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"message\": {\"title\": \"Message\", \"type\": \"string\"}\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_generate_clients/test_tutorial002.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.generate_clients.tutorial002_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_post_items():\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"price\": 5})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Item received\"}\n\n\ndef test_post_users():\n    response = client.post(\n        \"/users/\", json={\"username\": \"Foo\", \"email\": \"foo@example.com\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"User received\"}\n\n\ndef test_get_items():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"name\": \"Plumbus\", \"price\": 3},\n        {\"name\": \"Portal Gun\", \"price\": 9001},\n    ]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Get Items\",\n                        \"operationId\": \"get_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Get Items Items  Get\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ResponseMessage\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/users/\": {\n                    \"post\": {\n                        \"tags\": [\"users\"],\n                        \"summary\": \"Create User\",\n                        \"operationId\": \"create_user_users__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ResponseMessage\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"ResponseMessage\": {\n                        \"title\": \"ResponseMessage\",\n                        \"required\": [\"message\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"message\": {\"title\": \"Message\", \"type\": \"string\"}\n                        },\n                    },\n                    \"User\": {\n                        \"title\": \"User\",\n                        \"required\": [\"username\", \"email\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"email\": {\"title\": \"Email\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_generate_clients/test_tutorial003.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.generate_clients.tutorial003_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_post_items():\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"price\": 5})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Item received\"}\n\n\ndef test_post_users():\n    response = client.post(\n        \"/users/\", json={\"username\": \"Foo\", \"email\": \"foo@example.com\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"User received\"}\n\n\ndef test_get_items():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\"name\": \"Plumbus\", \"price\": 3},\n        {\"name\": \"Portal Gun\", \"price\": 9001},\n    ]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Get Items\",\n                        \"operationId\": \"items-get_items\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"title\": \"Response Items-Get Items\",\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"items-create_item\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ResponseMessage\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/users/\": {\n                    \"post\": {\n                        \"tags\": [\"users\"],\n                        \"summary\": \"Create User\",\n                        \"operationId\": \"users-create_user\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ResponseMessage\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                        },\n                    },\n                    \"ResponseMessage\": {\n                        \"title\": \"ResponseMessage\",\n                        \"required\": [\"message\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"message\": {\"title\": \"Message\", \"type\": \"string\"}\n                        },\n                    },\n                    \"User\": {\n                        \"title\": \"User\",\n                        \"required\": [\"username\", \"email\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"email\": {\"title\": \"Email\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_generate_clients/test_tutorial004.py",
    "content": "import importlib\nimport json\nimport pathlib\nfrom unittest.mock import patch\n\nfrom inline_snapshot import snapshot\n\nfrom docs_src.generate_clients import tutorial003_py310\n\n\ndef test_remove_tags(tmp_path: pathlib.Path):\n    tmp_file = tmp_path / \"openapi.json\"\n    openapi_json = tutorial003_py310.app.openapi()\n    tmp_file.write_text(json.dumps(openapi_json))\n\n    with patch(\"pathlib.Path\", return_value=tmp_file):\n        importlib.import_module(\"docs_src.generate_clients.tutorial004_py310\")\n\n    modified_openapi = json.loads(tmp_file.read_text())\n    assert modified_openapi == snapshot(\n        {\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"type\": \"number\",\n                            },\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ResponseMessage\": {\n                        \"properties\": {\n                            \"message\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"message\",\n                        ],\n                        \"title\": \"ResponseMessage\",\n                        \"type\": \"object\",\n                    },\n                    \"User\": {\n                        \"properties\": {\n                            \"email\": {\n                                \"title\": \"Email\",\n                                \"type\": \"string\",\n                            },\n                            \"username\": {\n                                \"title\": \"Username\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"username\",\n                            \"email\",\n                        ],\n                        \"title\": \"User\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n            \"info\": {\n                \"title\": \"FastAPI\",\n                \"version\": \"0.1.0\",\n            },\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"operationId\": \"get_items\",\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\",\n                                            },\n                                            \"title\": \"Response Items-Get Items\",\n                                            \"type\": \"array\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                        },\n                        \"summary\": \"Get Items\",\n                        \"tags\": [\n                            \"items\",\n                        ],\n                    },\n                    \"post\": {\n                        \"operationId\": \"create_item\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                    },\n                                },\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ResponseMessage\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Create Item\",\n                        \"tags\": [\n                            \"items\",\n                        ],\n                    },\n                },\n                \"/users/\": {\n                    \"post\": {\n                        \"operationId\": \"create_user\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/User\",\n                                    },\n                                },\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/ResponseMessage\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Create User\",\n                        \"tags\": [\n                            \"users\",\n                        ],\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_graphql/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_graphql/test_tutorial001.py",
    "content": "import warnings\n\nimport pytest\nfrom inline_snapshot import snapshot\nfrom starlette.testclient import TestClient\n\nwarnings.filterwarnings(\n    \"ignore\",\n    message=r\"The 'lia' package has been renamed to 'cross_web'\\..*\",\n    category=DeprecationWarning,\n)\n\nfrom docs_src.graphql_.tutorial001_py310 import app  # noqa: E402\n\n\n@pytest.fixture(name=\"client\")\ndef get_client() -> TestClient:\n    return TestClient(app)\n\n\ndef test_query(client: TestClient):\n    response = client.post(\"/graphql\", json={\"query\": \"{ user { name, age } }\"})\n    assert response.status_code == 200\n    assert response.json() == {\"data\": {\"user\": {\"name\": \"Patrick\", \"age\": 100}}}\n\n\ndef test_openapi(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"info\": {\n                \"title\": \"FastAPI\",\n                \"version\": \"0.1.0\",\n            },\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/graphql\": {\n                    \"get\": {\n                        \"operationId\": \"handle_http_get_graphql_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"The GraphiQL integrated development environment.\",\n                            },\n                            \"404\": {\n                                \"description\": \"Not found if GraphiQL or query via GET are not enabled.\",\n                            },\n                        },\n                        \"summary\": \"Handle Http Get\",\n                    },\n                    \"post\": {\n                        \"operationId\": \"handle_http_post_graphql_post\",\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                        },\n                        \"summary\": \"Handle Http Post\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_handling_errors/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_handling_errors/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.handling_errors.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get_item():\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item\": \"The Foo Wrestlers\"}\n\n\ndef test_get_item_not_found():\n    response = client.get(\"/items/bar\")\n    assert response.status_code == 404, response.text\n    assert response.headers.get(\"x-error\") is None\n    assert response.json() == {\"detail\": \"Item not found\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_handling_errors/test_tutorial002.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.handling_errors.tutorial002_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get_item_header():\n    response = client.get(\"/items-header/foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item\": \"The Foo Wrestlers\"}\n\n\ndef test_get_item_not_found_header():\n    response = client.get(\"/items-header/bar\")\n    assert response.status_code == 404, response.text\n    assert response.headers.get(\"x-error\") == \"There goes my error\"\n    assert response.json() == {\"detail\": \"Item not found\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items-header/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item Header\",\n                        \"operationId\": \"read_item_header_items_header__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_handling_errors/test_tutorial003.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.handling_errors.tutorial003_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/unicorns/shinny\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"unicorn_name\": \"shinny\"}\n\n\ndef test_get_exception():\n    response = client.get(\"/unicorns/yolo\")\n    assert response.status_code == 418, response.text\n    assert response.json() == {\n        \"message\": \"Oops! yolo did something. There goes a rainbow...\"\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/unicorns/{name}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Unicorn\",\n                        \"operationId\": \"read_unicorn_unicorns__name__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Name\", \"type\": \"string\"},\n                                \"name\": \"name\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_handling_errors/test_tutorial004.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.handling_errors.tutorial004_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get_validation_error():\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 400, response.text\n    assert \"Validation errors:\" in response.text\n    assert \"Field: ('path', 'item_id')\" in response.text\n\n\ndef test_get_http_error():\n    response = client.get(\"/items/3\")\n    assert response.status_code == 418, response.text\n    assert response.content == b\"Nope! I don't like 3.\"\n\n\ndef test_get():\n    response = client.get(\"/items/2\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": 2}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"integer\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_handling_errors/test_tutorial005.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.handling_errors.tutorial005_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_post_validation_error():\n    response = client.post(\"/items/\", json={\"title\": \"towel\", \"size\": \"XL\"})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"body\", \"size\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"XL\",\n            }\n        ],\n        \"body\": {\"title\": \"towel\", \"size\": \"XL\"},\n    }\n\n\ndef test_post():\n    data = {\"title\": \"towel\", \"size\": 5}\n    response = client.post(\"/items/\", json=data)\n    assert response.status_code == 200, response.text\n    assert response.json() == data\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"title\", \"size\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                            \"size\": {\"title\": \"Size\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_handling_errors/test_tutorial006.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.handling_errors.tutorial006_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get_validation_error():\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"foo\",\n            }\n        ]\n    }\n\n\ndef test_get_http_error():\n    response = client.get(\"/items/3\")\n    assert response.status_code == 418, response.text\n    assert response.json() == {\"detail\": \"Nope! I don't like 3.\"}\n\n\ndef test_get():\n    response = client.get(\"/items/2\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": 2}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"integer\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_header_param_models/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_header_param_models/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.header_param_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_header_param_model(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        headers=[\n            (\"save-data\", \"true\"),\n            (\"if-modified-since\", \"yesterday\"),\n            (\"traceparent\", \"123\"),\n            (\"x-tag\", \"one\"),\n            (\"x-tag\", \"two\"),\n        ],\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"host\": \"testserver\",\n        \"save_data\": True,\n        \"if_modified_since\": \"yesterday\",\n        \"traceparent\": \"123\",\n        \"x_tag\": [\"one\", \"two\"],\n    }\n\n\ndef test_header_param_model_defaults(client: TestClient):\n    response = client.get(\"/items/\", headers=[(\"save-data\", \"true\")])\n    assert response.status_code == 200\n    assert response.json() == {\n        \"host\": \"testserver\",\n        \"save_data\": True,\n        \"if_modified_since\": None,\n        \"traceparent\": None,\n        \"x_tag\": [],\n    }\n\n\ndef test_header_param_model_invalid(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 422\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"missing\",\n                    \"loc\": [\"header\", \"save_data\"],\n                    \"msg\": \"Field required\",\n                    \"input\": {\n                        \"x_tag\": [],\n                        \"host\": \"testserver\",\n                        \"accept\": \"*/*\",\n                        \"accept-encoding\": \"gzip, deflate\",\n                        \"connection\": \"keep-alive\",\n                        \"user-agent\": \"testclient\",\n                    },\n                }\n            ]\n        }\n    )\n\n\ndef test_header_param_model_extra(client: TestClient):\n    response = client.get(\n        \"/items/\", headers=[(\"save-data\", \"true\"), (\"tool\", \"plumbus\")]\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"host\": \"testserver\",\n            \"save_data\": True,\n            \"if_modified_since\": None,\n            \"traceparent\": None,\n            \"x_tag\": [],\n        }\n    )\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"host\",\n                                \"in\": \"header\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"string\", \"title\": \"Host\"},\n                            },\n                            {\n                                \"name\": \"save-data\",\n                                \"in\": \"header\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"boolean\", \"title\": \"Save Data\"},\n                            },\n                            {\n                                \"name\": \"if-modified-since\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"If Modified Since\",\n                                },\n                            },\n                            {\n                                \"name\": \"traceparent\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Traceparent\",\n                                },\n                            },\n                            {\n                                \"name\": \"x-tag\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\"type\": \"string\"},\n                                    \"default\": [],\n                                    \"title\": \"X Tag\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_header_param_models/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=[needs_py310]),\n        pytest.param(\"tutorial002_an_py310\", marks=[needs_py310]),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.header_param_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    client.headers.clear()\n    return client\n\n\ndef test_header_param_model(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        headers=[\n            (\"save-data\", \"true\"),\n            (\"if-modified-since\", \"yesterday\"),\n            (\"traceparent\", \"123\"),\n            (\"x-tag\", \"one\"),\n            (\"x-tag\", \"two\"),\n        ],\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"host\": \"testserver\",\n        \"save_data\": True,\n        \"if_modified_since\": \"yesterday\",\n        \"traceparent\": \"123\",\n        \"x_tag\": [\"one\", \"two\"],\n    }\n\n\ndef test_header_param_model_defaults(client: TestClient):\n    response = client.get(\"/items/\", headers=[(\"save-data\", \"true\")])\n    assert response.status_code == 200\n    assert response.json() == {\n        \"host\": \"testserver\",\n        \"save_data\": True,\n        \"if_modified_since\": None,\n        \"traceparent\": None,\n        \"x_tag\": [],\n    }\n\n\ndef test_header_param_model_invalid(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 422\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"missing\",\n                    \"loc\": [\"header\", \"save_data\"],\n                    \"msg\": \"Field required\",\n                    \"input\": {\"x_tag\": [], \"host\": \"testserver\"},\n                }\n            ]\n        }\n    )\n\n\ndef test_header_param_model_extra(client: TestClient):\n    response = client.get(\n        \"/items/\", headers=[(\"save-data\", \"true\"), (\"tool\", \"plumbus\")]\n    )\n    assert response.status_code == 422, response.text\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"extra_forbidden\",\n                    \"loc\": [\"header\", \"tool\"],\n                    \"msg\": \"Extra inputs are not permitted\",\n                    \"input\": \"plumbus\",\n                }\n            ]\n        }\n    )\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"host\",\n                                \"in\": \"header\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"string\", \"title\": \"Host\"},\n                            },\n                            {\n                                \"name\": \"save-data\",\n                                \"in\": \"header\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"boolean\", \"title\": \"Save Data\"},\n                            },\n                            {\n                                \"name\": \"if-modified-since\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"If Modified Since\",\n                                },\n                            },\n                            {\n                                \"name\": \"traceparent\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Traceparent\",\n                                },\n                            },\n                            {\n                                \"name\": \"x-tag\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\"type\": \"string\"},\n                                    \"default\": [],\n                                    \"title\": \"X Tag\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_header_param_models/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n        pytest.param(\"tutorial003_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.header_param_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_header_param_model(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        headers=[\n            (\"save_data\", \"true\"),\n            (\"if_modified_since\", \"yesterday\"),\n            (\"traceparent\", \"123\"),\n            (\"x_tag\", \"one\"),\n            (\"x_tag\", \"two\"),\n        ],\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"host\": \"testserver\",\n        \"save_data\": True,\n        \"if_modified_since\": \"yesterday\",\n        \"traceparent\": \"123\",\n        \"x_tag\": [\"one\", \"two\"],\n    }\n\n\ndef test_header_param_model_no_underscore(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        headers=[\n            (\"save-data\", \"true\"),\n            (\"if-modified-since\", \"yesterday\"),\n            (\"traceparent\", \"123\"),\n            (\"x-tag\", \"one\"),\n            (\"x-tag\", \"two\"),\n        ],\n    )\n    assert response.status_code == 422\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"missing\",\n                    \"loc\": [\"header\", \"save_data\"],\n                    \"msg\": \"Field required\",\n                    \"input\": {\n                        \"host\": \"testserver\",\n                        \"traceparent\": \"123\",\n                        \"x_tag\": [],\n                        \"accept\": \"*/*\",\n                        \"accept-encoding\": \"gzip, deflate\",\n                        \"connection\": \"keep-alive\",\n                        \"user-agent\": \"testclient\",\n                        \"save-data\": \"true\",\n                        \"if-modified-since\": \"yesterday\",\n                        \"x-tag\": [\"one\", \"two\"],\n                    },\n                }\n            ]\n        }\n    )\n\n\ndef test_header_param_model_defaults(client: TestClient):\n    response = client.get(\"/items/\", headers=[(\"save_data\", \"true\")])\n    assert response.status_code == 200\n    assert response.json() == {\n        \"host\": \"testserver\",\n        \"save_data\": True,\n        \"if_modified_since\": None,\n        \"traceparent\": None,\n        \"x_tag\": [],\n    }\n\n\ndef test_header_param_model_invalid(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 422\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"missing\",\n                    \"loc\": [\"header\", \"save_data\"],\n                    \"msg\": \"Field required\",\n                    \"input\": {\n                        \"x_tag\": [],\n                        \"host\": \"testserver\",\n                        \"accept\": \"*/*\",\n                        \"accept-encoding\": \"gzip, deflate\",\n                        \"connection\": \"keep-alive\",\n                        \"user-agent\": \"testclient\",\n                    },\n                }\n            ]\n        }\n    )\n\n\ndef test_header_param_model_extra(client: TestClient):\n    response = client.get(\n        \"/items/\", headers=[(\"save_data\", \"true\"), (\"tool\", \"plumbus\")]\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"host\": \"testserver\",\n            \"save_data\": True,\n            \"if_modified_since\": None,\n            \"traceparent\": None,\n            \"x_tag\": [],\n        }\n    )\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"host\",\n                                \"in\": \"header\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"string\", \"title\": \"Host\"},\n                            },\n                            {\n                                \"name\": \"save_data\",\n                                \"in\": \"header\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"boolean\", \"title\": \"Save Data\"},\n                            },\n                            {\n                                \"name\": \"if_modified_since\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"If Modified Since\",\n                                },\n                            },\n                            {\n                                \"name\": \"traceparent\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Traceparent\",\n                                },\n                            },\n                            {\n                                \"name\": \"x_tag\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\"type\": \"string\"},\n                                    \"default\": [],\n                                    \"title\": \"X Tag\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_header_params/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_header_params/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.header_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"path,headers,expected_status,expected_response\",\n    [\n        (\"/items\", None, 200, {\"User-Agent\": \"testclient\"}),\n        (\"/items\", {\"X-Header\": \"notvalid\"}, 200, {\"User-Agent\": \"testclient\"}),\n        (\"/items\", {\"User-Agent\": \"FastAPI test\"}, 200, {\"User-Agent\": \"FastAPI test\"}),\n    ],\n)\ndef test(path, headers, expected_status, expected_response, client: TestClient):\n    response = client.get(path, headers=headers)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"User-Agent\",\n                                },\n                                \"name\": \"user-agent\",\n                                \"in\": \"header\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_header_params/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.header_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"path,headers,expected_status,expected_response\",\n    [\n        (\"/items\", None, 200, {\"strange_header\": None}),\n        (\"/items\", {\"X-Header\": \"notvalid\"}, 200, {\"strange_header\": None}),\n        (\n            \"/items\",\n            {\"strange_header\": \"FastAPI test\"},\n            200,\n            {\"strange_header\": \"FastAPI test\"},\n        ),\n        (\n            \"/items\",\n            {\"strange-header\": \"Not really underscore\"},\n            200,\n            {\"strange_header\": None},\n        ),\n    ],\n)\ndef test(path, headers, expected_status, expected_response, client: TestClient):\n    response = client.get(path, headers=headers)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Strange Header\",\n                                },\n                                \"name\": \"strange_header\",\n                                \"in\": \"header\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_header_params/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n        pytest.param(\"tutorial003_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.header_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"path,headers,expected_status,expected_response\",\n    [\n        (\"/items\", None, 200, {\"X-Token values\": None}),\n        (\"/items\", {\"x-token\": \"foo\"}, 200, {\"X-Token values\": [\"foo\"]}),\n        (\n            \"/items\",\n            [(\"x-token\", \"foo\"), (\"x-token\", \"bar\")],\n            200,\n            {\"X-Token values\": [\"foo\", \"bar\"]},\n        ),\n    ],\n)\ndef test(path, headers, expected_status, expected_response, client: TestClient):\n    response = client.get(path, headers=headers)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"X-Token\",\n                                    \"anyOf\": [\n                                        {\"type\": \"array\", \"items\": {\"type\": \"string\"}},\n                                        {\"type\": \"null\"},\n                                    ],\n                                },\n                                \"name\": \"x-token\",\n                                \"in\": \"header\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_json_base64_bytes/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_json_base64_bytes/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[pytest.param(\"tutorial001_py310\", marks=needs_py310)],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.json_base64_bytes.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_data(client: TestClient):\n    response = client.post(\n        \"/data\",\n        json={\n            \"description\": \"A file\",\n            \"data\": \"SGVsbG8sIFdvcmxkIQ==\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"description\": \"A file\", \"content\": \"Hello, World!\"}\n\n\ndef test_get_data(client: TestClient):\n    response = client.get(\"/data\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"description\": \"A plumbus\", \"data\": \"aGVsbG8=\"}\n\n\ndef test_post_data_in_out(client: TestClient):\n    response = client.post(\n        \"/data-in-out\",\n        json={\n            \"description\": \"A plumbus\",\n            \"data\": \"SGVsbG8sIFdvcmxkIQ==\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"description\": \"A plumbus\",\n        \"data\": \"SGVsbG8sIFdvcmxkIQ==\",\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/data\": {\n                    \"get\": {\n                        \"summary\": \"Get Data\",\n                        \"operationId\": \"get_data_data_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/DataOutput\"\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Post Data\",\n                        \"operationId\": \"post_data_data_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/DataInput\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/data-in-out\": {\n                    \"post\": {\n                        \"summary\": \"Post Data In Out\",\n                        \"operationId\": \"post_data_in_out_data_in_out_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/DataInputOutput\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/DataInputOutput\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"DataInput\": {\n                        \"properties\": {\n                            \"description\": {\"type\": \"string\", \"title\": \"Description\"},\n                            \"data\": {\n                                \"type\": \"string\",\n                                \"contentEncoding\": \"base64\",\n                                \"contentMediaType\": \"application/octet-stream\",\n                                \"title\": \"Data\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"description\", \"data\"],\n                        \"title\": \"DataInput\",\n                    },\n                    \"DataInputOutput\": {\n                        \"properties\": {\n                            \"description\": {\"type\": \"string\", \"title\": \"Description\"},\n                            \"data\": {\n                                \"type\": \"string\",\n                                \"contentEncoding\": \"base64\",\n                                \"contentMediaType\": \"application/octet-stream\",\n                                \"title\": \"Data\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"description\", \"data\"],\n                        \"title\": \"DataInputOutput\",\n                    },\n                    \"DataOutput\": {\n                        \"properties\": {\n                            \"description\": {\"type\": \"string\", \"title\": \"Description\"},\n                            \"data\": {\n                                \"type\": \"string\",\n                                \"contentEncoding\": \"base64\",\n                                \"contentMediaType\": \"application/octet-stream\",\n                                \"title\": \"Data\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"description\", \"data\"],\n                        \"title\": \"DataOutput\",\n                    },\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_metadata/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_metadata/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.metadata.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_items():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"name\": \"Katana\"}]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\n                \"title\": \"ChimichangApp\",\n                \"summary\": \"Deadpool's favorite app. Nuff said.\",\n                \"description\": \"\\nChimichangApp API helps you do awesome stuff. 🚀\\n\\n## Items\\n\\nYou can **read items**.\\n\\n## Users\\n\\nYou will be able to:\\n\\n* **Create users** (_not implemented_).\\n* **Read users** (_not implemented_).\\n\",\n                \"termsOfService\": \"http://example.com/terms/\",\n                \"contact\": {\n                    \"name\": \"Deadpoolio the Amazing\",\n                    \"url\": \"http://x-force.example.com/contact/\",\n                    \"email\": \"dp@x-force.example.com\",\n                },\n                \"license\": {\n                    \"name\": \"Apache 2.0\",\n                    \"url\": \"https://www.apache.org/licenses/LICENSE-2.0.html\",\n                },\n                \"version\": \"0.0.1\",\n            },\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_metadata/test_tutorial001_1.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.metadata.tutorial001_1_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_items():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"name\": \"Katana\"}]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\n                \"title\": \"ChimichangApp\",\n                \"summary\": \"Deadpool's favorite app. Nuff said.\",\n                \"description\": \"\\nChimichangApp API helps you do awesome stuff. 🚀\\n\\n## Items\\n\\nYou can **read items**.\\n\\n## Users\\n\\nYou will be able to:\\n\\n* **Create users** (_not implemented_).\\n* **Read users** (_not implemented_).\\n\",\n                \"termsOfService\": \"http://example.com/terms/\",\n                \"contact\": {\n                    \"name\": \"Deadpoolio the Amazing\",\n                    \"url\": \"http://x-force.example.com/contact/\",\n                    \"email\": \"dp@x-force.example.com\",\n                },\n                \"license\": {\n                    \"name\": \"Apache 2.0\",\n                    \"identifier\": \"Apache-2.0\",\n                },\n                \"version\": \"0.0.1\",\n            },\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_metadata/test_tutorial002.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.metadata.tutorial002_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_items():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"name\": \"Foo\"}]\n\n\ndef test_get_openapi_json_default_url():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 404, response.text\n\n\ndef test_openapi_schema():\n    response = client.get(\"/api/v1/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\n                \"title\": \"FastAPI\",\n                \"version\": \"0.1.0\",\n            },\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_metadata/test_tutorial003.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.metadata.tutorial003_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_items():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"name\": \"Foo\"}]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\n                \"title\": \"FastAPI\",\n                \"version\": \"0.1.0\",\n            },\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n\n\ndef test_swagger_ui_default_url():\n    response = client.get(\"/docs\")\n    assert response.status_code == 404, response.text\n\n\ndef test_swagger_ui_custom_url():\n    response = client.get(\"/documentation\")\n    assert response.status_code == 200, response.text\n    assert \"<title>FastAPI - Swagger UI</title>\" in response.text\n\n\ndef test_redoc_ui_default_url():\n    response = client.get(\"/redoc\")\n    assert response.status_code == 404, response.text\n"
  },
  {
    "path": "tests/test_tutorial/test_metadata/test_tutorial004.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.metadata.tutorial004_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_path_operations():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    response = client.get(\"/users/\")\n    assert response.status_code == 200, response.text\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/\": {\n                    \"get\": {\n                        \"tags\": [\"users\"],\n                        \"summary\": \"Get Users\",\n                        \"operationId\": \"get_users_users__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/items/\": {\n                    \"get\": {\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Get Items\",\n                        \"operationId\": \"get_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n            },\n            \"tags\": [\n                {\n                    \"name\": \"users\",\n                    \"description\": \"Operations with users. The **login** logic is also here.\",\n                },\n                {\n                    \"name\": \"items\",\n                    \"description\": \"Manage items. So _fancy_ they have their own docs.\",\n                    \"externalDocs\": {\n                        \"description\": \"Items external docs\",\n                        \"url\": \"https://fastapi.tiangolo.com/\",\n                    },\n                },\n            ],\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_middleware/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_middleware/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.middleware.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_response_headers():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert \"X-Process-Time\" in response.headers\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\n                \"title\": \"FastAPI\",\n                \"version\": \"0.1.0\",\n            },\n            \"paths\": {},\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_openapi_callbacks/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_mod(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.openapi_callbacks.{request.param}\")\n    return mod\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(mod: ModuleType):\n    client = TestClient(mod.app)\n    client.headers.clear()\n    return client\n\n\ndef test_get(client: TestClient):\n    response = client.post(\n        \"/invoices/\", json={\"id\": \"fooinvoice\", \"customer\": \"John\", \"total\": 5.3}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"msg\": \"Invoice received\"}\n\n\ndef test_dummy_callback(mod: ModuleType):\n    # Just for coverage\n    mod.invoice_notification({})\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/invoices/\": {\n                    \"post\": {\n                        \"summary\": \"Create Invoice\",\n                        \"description\": 'Create an invoice.\\n\\nThis will (let\\'s imagine) let the API user (some external developer) create an\\ninvoice.\\n\\nAnd this path operation will:\\n\\n* Send the invoice to the client.\\n* Collect the money from the client.\\n* Send a notification back to the API user (the external developer), as a callback.\\n    * At this point is that the API will somehow send a POST request to the\\n        external API with the notification of the invoice event\\n        (e.g. \"payment successful\").',\n                        \"operationId\": \"create_invoice_invoices__post\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                            \"format\": \"uri\",\n                                            \"minLength\": 1,\n                                            \"maxLength\": 2083,\n                                        },\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Callback Url\",\n                                },\n                                \"name\": \"callback_url\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Invoice\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"callbacks\": {\n                            \"invoice_notification\": {\n                                \"{$callback_url}/invoices/{$request.body.id}\": {\n                                    \"post\": {\n                                        \"summary\": \"Invoice Notification\",\n                                        \"operationId\": \"invoice_notification__callback_url__invoices___request_body_id__post\",\n                                        \"requestBody\": {\n                                            \"required\": True,\n                                            \"content\": {\n                                                \"application/json\": {\n                                                    \"schema\": {\n                                                        \"$ref\": \"#/components/schemas/InvoiceEvent\"\n                                                    }\n                                                }\n                                            },\n                                        },\n                                        \"responses\": {\n                                            \"200\": {\n                                                \"description\": \"Successful Response\",\n                                                \"content\": {\n                                                    \"application/json\": {\n                                                        \"schema\": {\n                                                            \"$ref\": \"#/components/schemas/InvoiceEventReceived\"\n                                                        }\n                                                    }\n                                                },\n                                            },\n                                            \"422\": {\n                                                \"description\": \"Validation Error\",\n                                                \"content\": {\n                                                    \"application/json\": {\n                                                        \"schema\": {\n                                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                                        }\n                                                    }\n                                                },\n                                            },\n                                        },\n                                    }\n                                }\n                            }\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Invoice\": {\n                        \"title\": \"Invoice\",\n                        \"required\": [\"id\", \"customer\", \"total\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"id\": {\"title\": \"Id\", \"type\": \"string\"},\n                            \"title\": {\n                                \"title\": \"Title\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"customer\": {\"title\": \"Customer\", \"type\": \"string\"},\n                            \"total\": {\"title\": \"Total\", \"type\": \"number\"},\n                        },\n                    },\n                    \"InvoiceEvent\": {\n                        \"title\": \"InvoiceEvent\",\n                        \"required\": [\"description\", \"paid\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"description\": {\"title\": \"Description\", \"type\": \"string\"},\n                            \"paid\": {\"title\": \"Paid\", \"type\": \"boolean\"},\n                        },\n                    },\n                    \"InvoiceEventReceived\": {\n                        \"title\": \"InvoiceEventReceived\",\n                        \"required\": [\"ok\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"ok\": {\"title\": \"Ok\", \"type\": \"boolean\"}},\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_openapi_webhooks/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.openapi_webhooks.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/users/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"Rick\", \"Morty\"]\n\n\ndef test_dummy_webhook():\n    # Just for coverage\n    app.webhooks.routes[0].endpoint({})\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/\": {\n                    \"get\": {\n                        \"summary\": \"Read Users\",\n                        \"operationId\": \"read_users_users__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n            \"webhooks\": {\n                \"new-subscription\": {\n                    \"post\": {\n                        \"summary\": \"New Subscription\",\n                        \"description\": \"When a new user subscribes to your service we'll send you a POST request with this\\ndata to the URL that you register for the event `new-subscription` in the dashboard.\",\n                        \"operationId\": \"new_subscriptionnew_subscription_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Subscription\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Subscription\": {\n                        \"properties\": {\n                            \"username\": {\"type\": \"string\", \"title\": \"Username\"},\n                            \"monthly_fee\": {\"type\": \"number\", \"title\": \"Monthly Fee\"},\n                            \"start_date\": {\n                                \"type\": \"string\",\n                                \"format\": \"date-time\",\n                                \"title\": \"Start Date\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"username\", \"monthly_fee\", \"start_date\"],\n                        \"title\": \"Subscription\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_advanced_configurations/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_operation_advanced_configuration.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item_id\": \"Foo\"}]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"some_specific_id_you_define\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_operation_advanced_configuration.tutorial002_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item_id\": \"Foo\"}]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_operation_advanced_configuration.tutorial003_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item_id\": \"Foo\"}]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {},\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.path_operation_advanced_configuration.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    client.headers.clear()\n    return client\n\n\ndef test_query_params_str_validations(client: TestClient):\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"price\": 42})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"price\": 42,\n        \"description\": None,\n        \"tax\": None,\n        \"tags\": [],\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create an item\",\n                        \"description\": \"Create an item with all the information:\\n\\n- **name**: each item must have a name\\n- **description**: a long description\\n- **price**: required\\n- **tax**: if the item doesn't have tax, you can omit this\\n- **tags**: a set of unique tag strings for this item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"uniqueItems\": True,\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                                \"default\": [],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_operation_advanced_configuration.tutorial005_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"x-aperture-labs-portal\": \"blue\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_operation_advanced_configuration.tutorial006_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_post():\n    response = client.post(\"/items/\", content=b\"this is actually not validated\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"size\": 30,\n        \"content\": {\n            \"name\": \"Maaaagic\",\n            \"price\": 42,\n            \"description\": \"Just kiddin', no magic here. ✨\",\n        },\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"required\": [\"name\", \"price\"],\n                                        \"type\": \"object\",\n                                        \"properties\": {\n                                            \"name\": {\"type\": \"string\"},\n                                            \"price\": {\"type\": \"number\"},\n                                            \"description\": {\"type\": \"string\"},\n                                        },\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial007_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.path_operation_advanced_configuration.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post(client: TestClient):\n    yaml_data = \"\"\"\n        name: Deadpoolio\n        tags:\n        - x-force\n        - x-men\n        - x-avengers\n        \"\"\"\n    response = client.post(\"/items/\", content=yaml_data)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Deadpoolio\",\n        \"tags\": [\"x-force\", \"x-men\", \"x-avengers\"],\n    }\n\n\ndef test_post_broken_yaml(client: TestClient):\n    yaml_data = \"\"\"\n        name: Deadpoolio\n        tags:\n        x - x-force\n        x - x-men\n        x - x-avengers\n        \"\"\"\n    response = client.post(\"/items/\", content=yaml_data)\n    assert response.status_code == 422, response.text\n    assert response.json() == {\"detail\": \"Invalid YAML\"}\n\n\ndef test_post_invalid(client: TestClient):\n    yaml_data = \"\"\"\n        name: Deadpoolio\n        tags:\n        - x-force\n        - x-men\n        - x-avengers\n        - sneaky: object\n        \"\"\"\n    response = client.post(\"/items/\", content=yaml_data)\n    assert response.status_code == 422, response.text\n    # insert_assert(response.json())\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_type\",\n                \"loc\": [\"tags\", 3],\n                \"msg\": \"Input should be a valid string\",\n                \"input\": {\"sneaky\": \"object\"},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-yaml\": {\n                                    \"schema\": {\n                                        \"title\": \"Item\",\n                                        \"required\": [\"name\", \"tags\"],\n                                        \"type\": \"object\",\n                                        \"properties\": {\n                                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                                            \"tags\": {\n                                                \"title\": \"Tags\",\n                                                \"type\": \"array\",\n                                                \"items\": {\"type\": \"string\"},\n                                            },\n                                        },\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_configurations/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_path_operation_configurations/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom dirty_equals import IsList\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest) -> TestClient:\n    mod = importlib.import_module(\n        f\"docs_src.path_operation_configuration.{request.param}\"\n    )\n    return TestClient(mod.app)\n\n\ndef test_post_items(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"Item description\",\n            \"price\": 42.0,\n            \"tax\": 3.2,\n            \"tags\": [\"bar\", \"baz\"],\n        },\n    )\n    assert response.status_code == 201, response.text\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"description\": \"Item description\",\n        \"price\": 42.0,\n        \"tax\": 3.2,\n        \"tags\": IsList(\"bar\", \"baz\", check_order=False),\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"201\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"description\": {\n                                \"anyOf\": [\n                                    {\n                                        \"type\": \"string\",\n                                    },\n                                    {\n                                        \"type\": \"null\",\n                                    },\n                                ],\n                                \"title\": \"Description\",\n                            },\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"type\": \"number\",\n                            },\n                            \"tags\": {\n                                \"default\": [],\n                                \"items\": {\n                                    \"type\": \"string\",\n                                },\n                                \"title\": \"Tags\",\n                                \"type\": \"array\",\n                                \"uniqueItems\": True,\n                            },\n                            \"tax\": {\n                                \"anyOf\": [\n                                    {\n                                        \"type\": \"number\",\n                                    },\n                                    {\n                                        \"type\": \"null\",\n                                    },\n                                ],\n                                \"title\": \"Tax\",\n                            },\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_configurations/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom dirty_equals import IsList\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest) -> TestClient:\n    mod = importlib.import_module(\n        f\"docs_src.path_operation_configuration.{request.param}\"\n    )\n    return TestClient(mod.app)\n\n\ndef test_post_items(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"Item description\",\n            \"price\": 42.0,\n            \"tax\": 3.2,\n            \"tags\": [\"bar\", \"baz\"],\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"description\": \"Item description\",\n        \"price\": 42.0,\n        \"tax\": 3.2,\n        \"tags\": IsList(\"bar\", \"baz\", check_order=False),\n    }\n\n\ndef test_get_items(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"name\": \"Foo\", \"price\": 42}]\n\n\ndef test_get_users(client: TestClient):\n    response = client.get(\"/users/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"username\": \"johndoe\"}]\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/users/\": {\n                    \"get\": {\n                        \"tags\": [\"users\"],\n                        \"summary\": \"Read Users\",\n                        \"operationId\": \"read_users_users__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"description\": {\n                                \"anyOf\": [\n                                    {\n                                        \"type\": \"string\",\n                                    },\n                                    {\n                                        \"type\": \"null\",\n                                    },\n                                ],\n                                \"title\": \"Description\",\n                            },\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"type\": \"number\",\n                            },\n                            \"tags\": {\n                                \"default\": [],\n                                \"items\": {\n                                    \"type\": \"string\",\n                                },\n                                \"title\": \"Tags\",\n                                \"type\": \"array\",\n                                \"uniqueItems\": True,\n                            },\n                            \"tax\": {\n                                \"anyOf\": [\n                                    {\n                                        \"type\": \"number\",\n                                    },\n                                    {\n                                        \"type\": \"null\",\n                                    },\n                                ],\n                                \"title\": \"Tax\",\n                            },\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_operation_configuration.tutorial002b_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get_items():\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"Portal gun\", \"Plumbus\"]\n\n\ndef test_get_users():\n    response = client.get(\"/users/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"Rick\", \"Morty\"]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Get Items\",\n                        \"operationId\": \"get_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n                \"/users/\": {\n                    \"get\": {\n                        \"tags\": [\"users\"],\n                        \"summary\": \"Read Users\",\n                        \"operationId\": \"read_users_users__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_configurations/test_tutorial003_tutorial004.py",
    "content": "import importlib\nfrom textwrap import dedent\n\nimport pytest\nfrom dirty_equals import IsList\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import Is, snapshot\n\nfrom ...utils import needs_py310\n\nDESCRIPTIONS = {\n    \"tutorial003\": \"Create an item with all the information, name, description, price, tax and a set of unique tags\",\n    \"tutorial004\": dedent(\"\"\"\n        Create an item with all the information:\n\n        - **name**: each item must have a name\n        - **description**: a long description\n        - **price**: required\n        - **tax**: if the item doesn't have tax, you can omit this\n        - **tags**: a set of unique tag strings for this item\n    \"\"\").strip(),\n}\n\n\n@pytest.fixture(\n    name=\"mod_name\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_mod_name(request: pytest.FixtureRequest) -> str:\n    return request.param\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(mod_name: str) -> TestClient:\n    mod = importlib.import_module(f\"docs_src.path_operation_configuration.{mod_name}\")\n    return TestClient(mod.app)\n\n\ndef test_post_items(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"Item description\",\n            \"price\": 42.0,\n            \"tax\": 3.2,\n            \"tags\": [\"bar\", \"baz\"],\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"description\": \"Item description\",\n        \"price\": 42.0,\n        \"tax\": 3.2,\n        \"tags\": IsList(\"bar\", \"baz\", check_order=False),\n    }\n\n\ndef test_openapi_schema(client: TestClient, mod_name: str):\n    mod_name = mod_name[:11]\n\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"summary\": \"Create an item\",\n                        \"description\": Is(DESCRIPTIONS[mod_name]),\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"description\": {\n                                \"anyOf\": [\n                                    {\n                                        \"type\": \"string\",\n                                    },\n                                    {\n                                        \"type\": \"null\",\n                                    },\n                                ],\n                                \"title\": \"Description\",\n                            },\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"type\": \"string\",\n                            },\n                            \"price\": {\n                                \"title\": \"Price\",\n                                \"type\": \"number\",\n                            },\n                            \"tags\": {\n                                \"default\": [],\n                                \"items\": {\n                                    \"type\": \"string\",\n                                },\n                                \"title\": \"Tags\",\n                                \"type\": \"array\",\n                                \"uniqueItems\": True,\n                            },\n                            \"tax\": {\n                                \"anyOf\": [\n                                    {\n                                        \"type\": \"number\",\n                                    },\n                                    {\n                                        \"type\": \"null\",\n                                    },\n                                ],\n                                \"title\": \"Tax\",\n                            },\n                        },\n                        \"required\": [\n                            \"name\",\n                            \"price\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.path_operation_configuration.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations(client: TestClient):\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"price\": 42})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Foo\",\n        \"price\": 42,\n        \"description\": None,\n        \"tax\": None,\n        \"tags\": [],\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"The created item\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create an item\",\n                        \"description\": \"Create an item with all the information:\\n\\n- **name**: each item must have a name\\n- **description**: a long description\\n- **price**: required\\n- **tax**: if the item doesn't have tax, you can omit this\\n- **tags**: a set of unique tag strings for this item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"uniqueItems\": True,\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                                \"default\": [],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_operation_configuration.tutorial006_py310 import app\n\nclient = TestClient(app)\n\n\n@pytest.mark.parametrize(\n    \"path,expected_status,expected_response\",\n    [\n        (\"/items/\", 200, [{\"name\": \"Foo\", \"price\": 42}]),\n        (\"/users/\", 200, [{\"username\": \"johndoe\"}]),\n        (\"/elements/\", 200, [{\"item_id\": \"Foo\"}]),\n    ],\n)\ndef test_query_params_str_validations(path, expected_status, expected_response):\n    response = client.get(path)\n    assert response.status_code == expected_status\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                    }\n                },\n                \"/users/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"tags\": [\"users\"],\n                        \"summary\": \"Read Users\",\n                        \"operationId\": \"read_users_users__get\",\n                    }\n                },\n                \"/elements/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"tags\": [\"items\"],\n                        \"summary\": \"Read Elements\",\n                        \"operationId\": \"read_elements_elements__get\",\n                        \"deprecated\": True,\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_path_params/test_tutorial001.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_params.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\n@pytest.mark.parametrize(\n    (\"item_id\", \"expected_response\"),\n    [\n        (1, {\"item_id\": \"1\"}),\n        (\"alice\", {\"item_id\": \"alice\"}),\n    ],\n)\ndef test_get_items(item_id, expected_response):\n    response = client.get(f\"/items/{item_id}\")\n    assert response.status_code == 200, response.text\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params/test_tutorial002.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_params.tutorial002_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get_items():\n    response = client.get(\"/items/1\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item_id\": 1}\n\n\ndef test_get_items_invalid_id():\n    response = client.get(\"/items/item1\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"input\": \"item1\",\n                \"loc\": [\"path\", \"item_id\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"type\": \"int_parsing\",\n            }\n        ]\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"integer\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params/test_tutorial003.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_params.tutorial003_py310 import app\n\nclient = TestClient(app)\n\n\n@pytest.mark.parametrize(\n    (\"user_id\", \"expected_response\"),\n    [\n        (\"me\", {\"user_id\": \"the current user\"}),\n        (\"alice\", {\"user_id\": \"alice\"}),\n    ],\n)\ndef test_get_users(user_id: str, expected_response: dict):\n    response = client.get(f\"/users/{user_id}\")\n    assert response.status_code == 200, response.text\n    assert response.json() == expected_response\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"operationId\": \"read_user_me_users_me_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                        },\n                        \"summary\": \"Read User Me\",\n                    },\n                },\n                \"/users/{user_id}\": {\n                    \"get\": {\n                        \"operationId\": \"read_user_users__user_id__get\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"user_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"User Id\",\n                                    \"type\": \"string\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Read User\",\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params/test_tutorial003b.py",
    "content": "import asyncio\n\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_params.tutorial003b_py310 import app, read_users2\n\nclient = TestClient(app)\n\n\ndef test_get_users():\n    response = client.get(\"/users\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\"Rick\", \"Morty\"]\n\n\ndef test_read_users2():  # Just for coverage\n    assert asyncio.run(read_users2()) == [\"Bean\", \"Elfo\"]\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users\": {\n                    \"get\": {\n                        \"operationId\": \"read_users2_users_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                        },\n                        \"summary\": \"Read Users2\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params/test_tutorial004.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_params.tutorial004_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_file_path():\n    response = client.get(\"/files/home/johndoe/myfile.txt\")\n    print(response.content)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_path\": \"home/johndoe/myfile.txt\"}\n\n\ndef test_root_file_path():\n    response = client.get(\"/files//home/johndoe/myfile.txt\")\n    print(response.content)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_path\": \"/home/johndoe/myfile.txt\"}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/files/{file_path}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read File\",\n                        \"operationId\": \"read_file_files__file_path__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"File Path\", \"type\": \"string\"},\n                                \"name\": \"file_path\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params/test_tutorial005.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.path_params.tutorial005_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get_enums_alexnet():\n    response = client.get(\"/models/alexnet\")\n    assert response.status_code == 200\n    assert response.json() == {\"model_name\": \"alexnet\", \"message\": \"Deep Learning FTW!\"}\n\n\ndef test_get_enums_lenet():\n    response = client.get(\"/models/lenet\")\n    assert response.status_code == 200\n    assert response.json() == {\"model_name\": \"lenet\", \"message\": \"LeCNN all the images\"}\n\n\ndef test_get_enums_resnet():\n    response = client.get(\"/models/resnet\")\n    assert response.status_code == 200\n    assert response.json() == {\"model_name\": \"resnet\", \"message\": \"Have some residuals\"}\n\n\ndef test_get_enums_invalid():\n    response = client.get(\"/models/foo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"enum\",\n                \"loc\": [\"path\", \"model_name\"],\n                \"msg\": \"Input should be 'alexnet', 'resnet' or 'lenet'\",\n                \"input\": \"foo\",\n                \"ctx\": {\"expected\": \"'alexnet', 'resnet' or 'lenet'\"},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/models/{model_name}\": {\n                    \"get\": {\n                        \"summary\": \"Get Model\",\n                        \"operationId\": \"get_model_models__model_name__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"$ref\": \"#/components/schemas/ModelName\"},\n                                \"name\": \"model_name\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ModelName\": {\n                        \"title\": \"ModelName\",\n                        \"enum\": [\"alexnet\", \"resnet\", \"lenet\"],\n                        \"type\": \"string\",\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params_numeric_validations/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_path_params_numeric_validations/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest) -> TestClient:\n    mod = importlib.import_module(\n        f\"docs_src.path_params_numeric_validations.{request.param}\"\n    )\n    return TestClient(mod.app)\n\n\n@pytest.mark.parametrize(\n    \"path,expected_response\",\n    [\n        (\"/items/42\", {\"item_id\": 42}),\n        (\"/items/123?item-query=somequery\", {\"item_id\": 123, \"q\": \"somequery\"}),\n    ],\n)\ndef test_read_items(client: TestClient, path, expected_response):\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == expected_response\n\n\ndef test_read_items_invalid_item_id(client: TestClient):\n    response = client.get(\"/items/invalid_id\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"path\", \"item_id\"],\n                \"input\": \"invalid_id\",\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"type\": \"int_parsing\",\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"The ID of the item to get\",\n                                    \"type\": \"integer\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"null\",\n                                        },\n                                    ],\n                                    \"title\": \"Item-Query\",\n                                },\n                                \"name\": \"item-query\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params_numeric_validations/test_tutorial002_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\"),\n        pytest.param(\"tutorial002_an_py310\"),\n        pytest.param(\"tutorial003_py310\"),\n        pytest.param(\"tutorial003_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest) -> TestClient:\n    mod = importlib.import_module(\n        f\"docs_src.path_params_numeric_validations.{request.param}\"\n    )\n    return TestClient(mod.app)\n\n\n@pytest.mark.parametrize(\n    \"path,expected_response\",\n    [\n        (\"/items/42?q=\", {\"item_id\": 42}),\n        (\"/items/123?q=somequery\", {\"item_id\": 123, \"q\": \"somequery\"}),\n    ],\n)\ndef test_read_items(client: TestClient, path, expected_response):\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == expected_response\n\n\ndef test_read_items_invalid_item_id(client: TestClient):\n    response = client.get(\"/items/invalid_id?q=somequery\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"path\", \"item_id\"],\n                \"input\": \"invalid_id\",\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"type\": \"int_parsing\",\n            }\n        ]\n    }\n\n\ndef test_read_items_missing_q(client: TestClient):\n    response = client.get(\"/items/42\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"query\", \"q\"],\n                \"input\": None,\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"The ID of the item to get\",\n                                    \"type\": \"integer\",\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"type\": \"string\",\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params_numeric_validations/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\"),\n        pytest.param(\"tutorial004_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest) -> TestClient:\n    mod = importlib.import_module(\n        f\"docs_src.path_params_numeric_validations.{request.param}\"\n    )\n    return TestClient(mod.app)\n\n\n@pytest.mark.parametrize(\n    \"path,expected_response\",\n    [\n        (\"/items/42?q=\", {\"item_id\": 42}),\n        (\"/items/1?q=somequery\", {\"item_id\": 1, \"q\": \"somequery\"}),\n    ],\n)\ndef test_read_items(client: TestClient, path, expected_response):\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == expected_response\n\n\ndef test_read_items_non_int_item_id(client: TestClient):\n    response = client.get(\"/items/invalid_id?q=somequery\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"path\", \"item_id\"],\n                \"input\": \"invalid_id\",\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"type\": \"int_parsing\",\n            }\n        ]\n    }\n\n\ndef test_read_items_item_id_less_than_one(client: TestClient):\n    response = client.get(\"/items/0?q=somequery\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"path\", \"item_id\"],\n                \"input\": \"0\",\n                \"msg\": \"Input should be greater than or equal to 1\",\n                \"type\": \"greater_than_equal\",\n                \"ctx\": {\"ge\": 1},\n            }\n        ]\n    }\n\n\ndef test_read_items_missing_q(client: TestClient):\n    response = client.get(\"/items/42\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"query\", \"q\"],\n                \"input\": None,\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"The ID of the item to get\",\n                                    \"type\": \"integer\",\n                                    \"minimum\": 1,\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"type\": \"string\",\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params_numeric_validations/test_tutorial005.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial005_py310\"),\n        pytest.param(\"tutorial005_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest) -> TestClient:\n    mod = importlib.import_module(\n        f\"docs_src.path_params_numeric_validations.{request.param}\"\n    )\n    return TestClient(mod.app)\n\n\n@pytest.mark.parametrize(\n    \"path,expected_response\",\n    [\n        (\"/items/1?q=\", {\"item_id\": 1}),\n        (\"/items/1000?q=somequery\", {\"item_id\": 1000, \"q\": \"somequery\"}),\n    ],\n)\ndef test_read_items(client: TestClient, path, expected_response):\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == expected_response\n\n\ndef test_read_items_non_int_item_id(client: TestClient):\n    response = client.get(\"/items/invalid_id?q=somequery\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"path\", \"item_id\"],\n                \"input\": \"invalid_id\",\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"type\": \"int_parsing\",\n            }\n        ]\n    }\n\n\ndef test_read_items_item_id_less_than_one(client: TestClient):\n    response = client.get(\"/items/0?q=somequery\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"path\", \"item_id\"],\n                \"input\": \"0\",\n                \"msg\": \"Input should be greater than 0\",\n                \"type\": \"greater_than\",\n                \"ctx\": {\"gt\": 0},\n            }\n        ]\n    }\n\n\ndef test_read_items_item_id_greater_than_one_thousand(client: TestClient):\n    response = client.get(\"/items/1001?q=somequery\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"path\", \"item_id\"],\n                \"input\": \"1001\",\n                \"msg\": \"Input should be less than or equal to 1000\",\n                \"type\": \"less_than_equal\",\n                \"ctx\": {\"le\": 1000},\n            }\n        ]\n    }\n\n\ndef test_read_items_missing_q(client: TestClient):\n    response = client.get(\"/items/42\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"query\", \"q\"],\n                \"input\": None,\n                \"msg\": \"Field required\",\n                \"type\": \"missing\",\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"The ID of the item to get\",\n                                    \"type\": \"integer\",\n                                    \"exclusiveMinimum\": 0,\n                                    \"maximum\": 1000,\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"type\": \"string\",\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_path_params_numeric_validations/test_tutorial006.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial006_py310\"),\n        pytest.param(\"tutorial006_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest) -> TestClient:\n    mod = importlib.import_module(\n        f\"docs_src.path_params_numeric_validations.{request.param}\"\n    )\n    return TestClient(mod.app)\n\n\n@pytest.mark.parametrize(\n    \"path,expected_response\",\n    [\n        (\n            \"/items/0?q=&size=0.1\",\n            {\"item_id\": 0, \"size\": 0.1},\n        ),\n        (\n            \"/items/1000?q=somequery&size=10.4\",\n            {\"item_id\": 1000, \"q\": \"somequery\", \"size\": 10.4},\n        ),\n    ],\n)\ndef test_read_items(client: TestClient, path, expected_response):\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.json() == expected_response\n\n\ndef test_read_items_item_id_less_than_zero(client: TestClient):\n    response = client.get(\"/items/-1?q=somequery&size=5\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"path\", \"item_id\"],\n                \"input\": \"-1\",\n                \"msg\": \"Input should be greater than or equal to 0\",\n                \"type\": \"greater_than_equal\",\n                \"ctx\": {\"ge\": 0},\n            }\n        ]\n    }\n\n\ndef test_read_items_item_id_greater_than_one_thousand(client: TestClient):\n    response = client.get(\"/items/1001?q=somequery&size=5\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"path\", \"item_id\"],\n                \"input\": \"1001\",\n                \"msg\": \"Input should be less than or equal to 1000\",\n                \"type\": \"less_than_equal\",\n                \"ctx\": {\"le\": 1000},\n            }\n        ]\n    }\n\n\ndef test_read_items_size_too_small(client: TestClient):\n    response = client.get(\"/items/1?q=somequery&size=0.0\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"query\", \"size\"],\n                \"input\": \"0.0\",\n                \"msg\": \"Input should be greater than 0\",\n                \"type\": \"greater_than\",\n                \"ctx\": {\"gt\": 0.0},\n            }\n        ]\n    }\n\n\ndef test_read_items_size_too_large(client: TestClient):\n    response = client.get(\"/items/1?q=somequery&size=10.5\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"loc\": [\"query\", \"size\"],\n                \"input\": \"10.5\",\n                \"msg\": \"Input should be less than 10.5\",\n                \"type\": \"less_than\",\n                \"ctx\": {\"lt\": 10.5},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"The ID of the item to get\",\n                                    \"type\": \"integer\",\n                                    \"minimum\": 0,\n                                    \"maximum\": 1000,\n                                },\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"type\": \"string\",\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"in\": \"query\",\n                                \"name\": \"size\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"exclusiveMaximum\": 10.5,\n                                    \"exclusiveMinimum\": 0,\n                                    \"title\": \"Size\",\n                                    \"type\": \"number\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial001_tutorial002.py",
    "content": "import runpy\nfrom unittest.mock import patch\n\nimport pytest\n\n\n@pytest.mark.parametrize(\n    \"module_name\",\n    [\n        \"tutorial001_py310\",\n        \"tutorial002_py310\",\n    ],\n)\ndef test_run_module(module_name: str):\n    with patch(\"builtins.print\") as mock_print:\n        runpy.run_module(f\"docs_src.python_types.{module_name}\", run_name=\"__main__\")\n\n    mock_print.assert_called_with(\"John Doe\")\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial003.py",
    "content": "import pytest\n\nfrom docs_src.python_types.tutorial003_py310 import get_name_with_age\n\n\ndef test_get_name_with_age_pass_int():\n    with pytest.raises(TypeError):\n        get_name_with_age(\"John\", 30)\n\n\ndef test_get_name_with_age_pass_str():\n    assert get_name_with_age(\"John\", \"30\") == \"John is this old: 30\"\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial004.py",
    "content": "from docs_src.python_types.tutorial004_py310 import get_name_with_age\n\n\ndef test_get_name_with_age_pass_int():\n    assert get_name_with_age(\"John\", 30) == \"John is this old: 30\"\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial005.py",
    "content": "from docs_src.python_types.tutorial005_py310 import get_items\n\n\ndef test_get_items():\n    res = get_items(\n        \"item_a\",\n        \"item_b\",\n        \"item_c\",\n        \"item_d\",\n        \"item_e\",\n    )\n    assert res == (\"item_a\", \"item_b\", \"item_c\", \"item_d\", \"item_e\")\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial006.py",
    "content": "from unittest.mock import patch\n\nfrom docs_src.python_types.tutorial006_py310 import process_items\n\n\ndef test_process_items():\n    with patch(\"builtins.print\") as mock_print:\n        process_items([\"item_a\", \"item_b\", \"item_c\"])\n\n    assert mock_print.call_count == 3\n    call_args = [arg.args for arg in mock_print.call_args_list]\n    assert call_args == [\n        (\"item_a\",),\n        (\"item_b\",),\n        (\"item_c\",),\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial007.py",
    "content": "from docs_src.python_types.tutorial007_py310 import process_items\n\n\ndef test_process_items():\n    items_t = (1, 2, \"foo\")\n    items_s = {b\"a\", b\"b\", b\"c\"}\n\n    assert process_items(items_t, items_s) == (items_t, items_s)\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial008.py",
    "content": "from unittest.mock import patch\n\nfrom docs_src.python_types.tutorial008_py310 import process_items\n\n\ndef test_process_items():\n    with patch(\"builtins.print\") as mock_print:\n        process_items({\"a\": 1.0, \"b\": 2.5})\n\n    assert mock_print.call_count == 4\n    call_args = [arg.args for arg in mock_print.call_args_list]\n    assert call_args == [\n        (\"a\",),\n        (1.0,),\n        (\"b\",),\n        (2.5,),\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial008b.py",
    "content": "import importlib\nfrom types import ModuleType\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial008b_py310\"),\n        pytest.param(\"tutorial008b_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.python_types.{request.param}\")\n    return mod\n\n\ndef test_process_items(module: ModuleType):\n    with patch(\"builtins.print\") as mock_print:\n        module.process_item(\"a\")\n\n    assert mock_print.call_count == 1\n    mock_print.assert_called_with(\"a\")\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial009_tutorial009b.py",
    "content": "import importlib\nfrom types import ModuleType\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"module\",\n    params=[\n        pytest.param(\"tutorial009_py310\"),\n        pytest.param(\"tutorial009_py310\", marks=needs_py310),\n    ],\n)\ndef get_module(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.python_types.{request.param}\")\n    return mod\n\n\ndef test_say_hi(module: ModuleType):\n    with patch(\"builtins.print\") as mock_print:\n        module.say_hi(\"FastAPI\")\n        module.say_hi()\n\n    assert mock_print.call_count == 2\n    call_args = [arg.args for arg in mock_print.call_args_list]\n    assert call_args == [\n        (\"Hey FastAPI!\",),\n        (\"Hello World\",),\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial010.py",
    "content": "from docs_src.python_types.tutorial010_py310 import Person, get_person_name\n\n\ndef test_get_person_name():\n    assert get_person_name(Person(\"John Doe\")) == \"John Doe\"\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial011.py",
    "content": "import runpy\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom ...utils import needs_py310\n\n\n@pytest.mark.parametrize(\n    \"module_name\",\n    [\n        pytest.param(\"tutorial011_py310\", marks=needs_py310),\n    ],\n)\ndef test_run_module(module_name: str):\n    with patch(\"builtins.print\") as mock_print:\n        runpy.run_module(f\"docs_src.python_types.{module_name}\", run_name=\"__main__\")\n\n    assert mock_print.call_count == 2\n    call_args = [str(arg.args[0]) for arg in mock_print.call_args_list]\n    assert call_args == [\n        \"id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]\",\n        \"123\",\n    ]\n"
  },
  {
    "path": "tests/test_tutorial/test_python_types/test_tutorial013.py",
    "content": "from docs_src.python_types.tutorial013_py310 import say_hello\n\n\ndef test_say_hello():\n    assert say_hello(\"FastAPI\") == \"Hello FastAPI\"\n"
  },
  {
    "path": "tests/test_tutorial/test_query_param_models/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_query_param_models/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.query_param_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_param_model(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        params={\n            \"limit\": 10,\n            \"offset\": 5,\n            \"order_by\": \"updated_at\",\n            \"tags\": [\"tag1\", \"tag2\"],\n        },\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"limit\": 10,\n        \"offset\": 5,\n        \"order_by\": \"updated_at\",\n        \"tags\": [\"tag1\", \"tag2\"],\n    }\n\n\ndef test_query_param_model_defaults(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"limit\": 100,\n        \"offset\": 0,\n        \"order_by\": \"created_at\",\n        \"tags\": [],\n    }\n\n\ndef test_query_param_model_invalid(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        params={\n            \"limit\": 150,\n            \"offset\": -1,\n            \"order_by\": \"invalid\",\n        },\n    )\n    assert response.status_code == 422\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"less_than_equal\",\n                    \"loc\": [\"query\", \"limit\"],\n                    \"msg\": \"Input should be less than or equal to 100\",\n                    \"input\": \"150\",\n                    \"ctx\": {\"le\": 100},\n                },\n                {\n                    \"type\": \"greater_than_equal\",\n                    \"loc\": [\"query\", \"offset\"],\n                    \"msg\": \"Input should be greater than or equal to 0\",\n                    \"input\": \"-1\",\n                    \"ctx\": {\"ge\": 0},\n                },\n                {\n                    \"type\": \"literal_error\",\n                    \"loc\": [\"query\", \"order_by\"],\n                    \"msg\": \"Input should be 'created_at' or 'updated_at'\",\n                    \"input\": \"invalid\",\n                    \"ctx\": {\"expected\": \"'created_at' or 'updated_at'\"},\n                },\n            ]\n        }\n    )\n\n\ndef test_query_param_model_extra(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        params={\n            \"limit\": 10,\n            \"offset\": 5,\n            \"order_by\": \"updated_at\",\n            \"tags\": [\"tag1\", \"tag2\"],\n            \"tool\": \"plumbus\",\n        },\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"limit\": 10,\n        \"offset\": 5,\n        \"order_by\": \"updated_at\",\n        \"tags\": [\"tag1\", \"tag2\"],\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"integer\",\n                                    \"maximum\": 100,\n                                    \"exclusiveMinimum\": 0,\n                                    \"default\": 100,\n                                    \"title\": \"Limit\",\n                                },\n                            },\n                            {\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"integer\",\n                                    \"minimum\": 0,\n                                    \"default\": 0,\n                                    \"title\": \"Offset\",\n                                },\n                            },\n                            {\n                                \"name\": \"order_by\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"enum\": [\"created_at\", \"updated_at\"],\n                                    \"type\": \"string\",\n                                    \"default\": \"created_at\",\n                                    \"title\": \"Order By\",\n                                },\n                            },\n                            {\n                                \"name\": \"tags\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\"type\": \"string\"},\n                                    \"default\": [],\n                                    \"title\": \"Tags\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_param_models/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=[needs_py310]),\n        pytest.param(\"tutorial002_an_py310\", marks=[needs_py310]),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.query_param_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_param_model(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        params={\n            \"limit\": 10,\n            \"offset\": 5,\n            \"order_by\": \"updated_at\",\n            \"tags\": [\"tag1\", \"tag2\"],\n        },\n    )\n    assert response.status_code == 200\n    assert response.json() == {\n        \"limit\": 10,\n        \"offset\": 5,\n        \"order_by\": \"updated_at\",\n        \"tags\": [\"tag1\", \"tag2\"],\n    }\n\n\ndef test_query_param_model_defaults(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"limit\": 100,\n        \"offset\": 0,\n        \"order_by\": \"created_at\",\n        \"tags\": [],\n    }\n\n\ndef test_query_param_model_invalid(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        params={\n            \"limit\": 150,\n            \"offset\": -1,\n            \"order_by\": \"invalid\",\n        },\n    )\n    assert response.status_code == 422\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"less_than_equal\",\n                    \"loc\": [\"query\", \"limit\"],\n                    \"msg\": \"Input should be less than or equal to 100\",\n                    \"input\": \"150\",\n                    \"ctx\": {\"le\": 100},\n                },\n                {\n                    \"type\": \"greater_than_equal\",\n                    \"loc\": [\"query\", \"offset\"],\n                    \"msg\": \"Input should be greater than or equal to 0\",\n                    \"input\": \"-1\",\n                    \"ctx\": {\"ge\": 0},\n                },\n                {\n                    \"type\": \"literal_error\",\n                    \"loc\": [\"query\", \"order_by\"],\n                    \"msg\": \"Input should be 'created_at' or 'updated_at'\",\n                    \"input\": \"invalid\",\n                    \"ctx\": {\"expected\": \"'created_at' or 'updated_at'\"},\n                },\n            ]\n        }\n    )\n\n\ndef test_query_param_model_extra(client: TestClient):\n    response = client.get(\n        \"/items/\",\n        params={\n            \"limit\": 10,\n            \"offset\": 5,\n            \"order_by\": \"updated_at\",\n            \"tags\": [\"tag1\", \"tag2\"],\n            \"tool\": \"plumbus\",\n        },\n    )\n    assert response.status_code == 422\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"extra_forbidden\",\n                    \"loc\": [\"query\", \"tool\"],\n                    \"msg\": \"Extra inputs are not permitted\",\n                    \"input\": \"plumbus\",\n                }\n            ]\n        }\n    )\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"integer\",\n                                    \"maximum\": 100,\n                                    \"exclusiveMinimum\": 0,\n                                    \"default\": 100,\n                                    \"title\": \"Limit\",\n                                },\n                            },\n                            {\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"integer\",\n                                    \"minimum\": 0,\n                                    \"default\": 0,\n                                    \"title\": \"Offset\",\n                                },\n                            },\n                            {\n                                \"name\": \"order_by\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"enum\": [\"created_at\", \"updated_at\"],\n                                    \"type\": \"string\",\n                                    \"default\": \"created_at\",\n                                    \"title\": \"Order By\",\n                                },\n                            },\n                            {\n                                \"name\": \"tags\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"array\",\n                                    \"items\": {\"type\": \"string\"},\n                                    \"default\": [],\n                                    \"title\": \"Tags\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_query_params/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.query_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    (\"path\", \"expected_json\"),\n    [\n        (\n            \"/items/\",\n            [{\"item_name\": \"Foo\"}, {\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}],\n        ),\n        (\n            \"/items/?skip=1\",\n            [{\"item_name\": \"Bar\"}, {\"item_name\": \"Baz\"}],\n        ),\n        (\n            \"/items/?skip=1&limit=1\",\n            [{\"item_name\": \"Bar\"}],\n        ),\n    ],\n)\ndef test_read_user_item(client: TestClient, path, expected_json):\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == expected_json\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Skip\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"skip\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Limit\",\n                                    \"type\": \"integer\",\n                                    \"default\": 10,\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.query_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    (\"path\", \"expected_json\"),\n    [\n        (\n            \"/items/foo\",\n            {\"item_id\": \"foo\"},\n        ),\n        (\n            \"/items/bar?q=somequery\",\n            {\"item_id\": \"bar\", \"q\": \"somequery\"},\n        ),\n    ],\n)\ndef test_read_user_item(client: TestClient, path, expected_json):\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == expected_json\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Q\",\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"null\",\n                                        },\n                                    ],\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.query_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    (\"path\", \"expected_json\"),\n    [\n        (\n            \"/items/foo\",\n            {\n                \"item_id\": \"foo\",\n                \"description\": \"This is an amazing item that has a long description\",\n            },\n        ),\n        (\n            \"/items/bar?q=somequery\",\n            {\n                \"item_id\": \"bar\",\n                \"q\": \"somequery\",\n                \"description\": \"This is an amazing item that has a long description\",\n            },\n        ),\n        (\n            \"/items/baz?short=true\",\n            {\"item_id\": \"baz\"},\n        ),\n    ],\n)\ndef test_read_user_item(client: TestClient, path, expected_json):\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == expected_json\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Q\",\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"null\",\n                                        },\n                                    ],\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Short\",\n                                    \"type\": \"boolean\",\n                                    \"default\": False,\n                                },\n                                \"name\": \"short\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.query_params.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    (\"path\", \"expected_json\"),\n    [\n        (\n            \"/users/123/items/foo\",\n            {\n                \"item_id\": \"foo\",\n                \"owner_id\": 123,\n                \"description\": \"This is an amazing item that has a long description\",\n            },\n        ),\n        (\n            \"/users/1/items/bar?q=somequery\",\n            {\n                \"item_id\": \"bar\",\n                \"owner_id\": 1,\n                \"q\": \"somequery\",\n                \"description\": \"This is an amazing item that has a long description\",\n            },\n        ),\n        (\n            \"/users/42/items/baz?short=true\",\n            {\"item_id\": \"baz\", \"owner_id\": 42},\n        ),\n    ],\n)\ndef test_read_user_item(client: TestClient, path, expected_json):\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.json() == expected_json\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/{user_id}/items/{item_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read User Item\",\n                        \"operationId\": \"read_user_item_users__user_id__items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"User Id\", \"type\": \"integer\"},\n                                \"name\": \"user_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Q\",\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"null\",\n                                        },\n                                    ],\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Short\",\n                                    \"type\": \"boolean\",\n                                    \"default\": False,\n                                },\n                                \"name\": \"short\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params/test_tutorial005.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.query_params.tutorial005_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_foo_needy_very():\n    response = client.get(\"/items/foo?needy=very\")\n    assert response.status_code == 200\n    assert response.json() == {\"item_id\": \"foo\", \"needy\": \"very\"}\n\n\ndef test_foo_no_needy():\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"needy\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read User Item\",\n                        \"operationId\": \"read_user_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Needy\", \"type\": \"string\"},\n                                \"name\": \"needy\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params/test_tutorial006.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial006_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.query_params.{request.param}\")\n\n    c = TestClient(mod.app)\n    return c\n\n\ndef test_foo_needy_very(client: TestClient):\n    response = client.get(\"/items/foo?needy=very\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"item_id\": \"foo\",\n        \"needy\": \"very\",\n        \"skip\": 0,\n        \"limit\": None,\n    }\n\n\ndef test_foo_no_needy(client: TestClient):\n    response = client.get(\"/items/foo?skip=a&limit=b\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"needy\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"query\", \"skip\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"a\",\n            },\n            {\n                \"type\": \"int_parsing\",\n                \"loc\": [\"query\", \"limit\"],\n                \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n                \"input\": \"b\",\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read User Item\",\n                        \"operationId\": \"read_user_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            },\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Needy\", \"type\": \"string\"},\n                                \"name\": \"needy\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Skip\",\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                },\n                                \"name\": \"skip\",\n                                \"in\": \"query\",\n                            },\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Limit\",\n                                },\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                            },\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_q_empty_str(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"\"})\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_q_query(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"query\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"query\",\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\"type\": \"string\"},\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_q_empty_str(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"\"})\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_q_query(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"query\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"query\",\n    }\n\n\ndef test_query_params_str_validations_q_too_long(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"q\" * 51})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_long\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"String should have at most 50 characters\",\n                \"input\": \"q\" * 51,\n                \"ctx\": {\"max_length\": 50},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                            \"maxLength\": 50,\n                                        },\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n        pytest.param(\"tutorial003_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_q_query(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"query\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"query\",\n    }\n\n\ndef test_query_params_str_validations_q_too_short(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"qu\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_short\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"String should have at least 3 characters\",\n                \"input\": \"qu\",\n                \"ctx\": {\"min_length\": 3},\n            }\n        ]\n    }\n\n\ndef test_query_params_str_validations_q_too_long(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"q\" * 51})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_long\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"String should have at most 50 characters\",\n                \"input\": \"q\" * 51,\n                \"ctx\": {\"max_length\": 50},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                            \"minLength\": 3,\n                                            \"maxLength\": 50,\n                                        },\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n        pytest.param(\"tutorial004_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_q_fixedquery(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fixedquery\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"fixedquery\",\n    }\n\n\ndef test_query_params_str_validations_q_nonregexquery(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"nonregexquery\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_pattern_mismatch\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"String should match pattern '^fixedquery$'\",\n                \"input\": \"nonregexquery\",\n                \"ctx\": {\"pattern\": \"^fixedquery$\"},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                            \"minLength\": 3,\n                                            \"maxLength\": 50,\n                                            \"pattern\": \"^fixedquery$\",\n                                        },\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial005.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial005_py310\"),\n        pytest.param(\"tutorial005_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"fixedquery\",\n    }\n\n\ndef test_query_params_str_validations_q_query(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"query\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"query\",\n    }\n\n\ndef test_query_params_str_validations_q_short(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fa\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_short\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"String should have at least 3 characters\",\n                \"input\": \"fa\",\n                \"ctx\": {\"min_length\": 3},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"string\",\n                                    \"default\": \"fixedquery\",\n                                    \"minLength\": 3,\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial006.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial006_py310\"),\n        pytest.param(\"tutorial006_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_query_params_str_validations_q_fixedquery(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fixedquery\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"fixedquery\",\n    }\n\n\ndef test_query_params_str_validations_q_fixedquery_too_short(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fa\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_short\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"String should have at least 3 characters\",\n                \"input\": \"fa\",\n                \"ctx\": {\"min_length\": 3},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"type\": \"string\",\n                                    \"minLength\": 3,\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial006c.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial006c_py310\", marks=needs_py310),\n        pytest.param(\"tutorial006c_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.xfail(\n    reason=\"Code example is not valid. See https://github.com/fastapi/fastapi/issues/12419\"\n)\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {  # pragma: no cover\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n    }\n\n\n@pytest.mark.xfail(\n    reason=\"Code example is not valid. See https://github.com/fastapi/fastapi/issues/12419\"\n)\ndef test_query_params_str_validations_empty_str(client: TestClient):\n    response = client.get(\"/items/?q=\")\n    assert response.status_code == 200\n    assert response.json() == {  # pragma: no cover\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n    }\n\n\ndef test_query_params_str_validations_q_query(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"query\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"query\",\n    }\n\n\ndef test_query_params_str_validations_q_short(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fa\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_short\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"String should have at least 3 characters\",\n                \"input\": \"fa\",\n                \"ctx\": {\"min_length\": 3},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\"type\": \"string\", \"minLength\": 3},\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial007.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial007_py310\", marks=needs_py310),\n        pytest.param(\"tutorial007_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_q_fixedquery(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fixedquery\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"fixedquery\",\n    }\n\n\ndef test_query_params_str_validations_q_fixedquery_too_short(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fa\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_short\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"String should have at least 3 characters\",\n                \"input\": \"fa\",\n                \"ctx\": {\"min_length\": 3},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                            \"minLength\": 3,\n                                        },\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Query string\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial008.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial008_py310\", marks=needs_py310),\n        pytest.param(\"tutorial008_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_q_fixedquery(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fixedquery\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"fixedquery\",\n    }\n\n\ndef test_query_params_str_validations_q_fixedquery_too_short(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fa\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_too_short\",\n                \"loc\": [\"query\", \"q\"],\n                \"msg\": \"String should have at least 3 characters\",\n                \"input\": \"fa\",\n                \"ctx\": {\"min_length\": 3},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"description\": \"Query string for the items to search in the database that have a good match\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                            \"minLength\": 3,\n                                        },\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Query string\",\n                                    \"description\": \"Query string for the items to search in the database that have a good match\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial009.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial009_py310\", marks=needs_py310),\n        pytest.param(\"tutorial009_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_item_query_fixedquery(client: TestClient):\n    response = client.get(\"/items/\", params={\"item-query\": \"fixedquery\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"fixedquery\",\n    }\n\n\ndef test_query_params_str_validations_q_fixedquery(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fixedquery\"})\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\"type\": \"string\"},\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Item-Query\",\n                                },\n                                \"required\": False,\n                                \"name\": \"item-query\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi._compat import PYDANTIC_VERSION_MINOR_TUPLE\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import Is, snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial010_py310\", marks=needs_py310),\n        pytest.param(\"tutorial010_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_query_params_str_validations_no_query(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_item_query_fixedquery(client: TestClient):\n    response = client.get(\"/items/\", params={\"item-query\": \"fixedquery\"})\n    assert response.status_code == 200\n    assert response.json() == {\n        \"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}],\n        \"q\": \"fixedquery\",\n    }\n\n\ndef test_query_params_str_validations_q_fixedquery(client: TestClient):\n    response = client.get(\"/items/\", params={\"q\": \"fixedquery\"})\n    assert response.status_code == 200\n    assert response.json() == {\"items\": [{\"item_id\": \"Foo\"}, {\"item_id\": \"Bar\"}]}\n\n\ndef test_query_params_str_validations_item_query_nonregexquery(client: TestClient):\n    response = client.get(\"/items/\", params={\"item-query\": \"nonregexquery\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"string_pattern_mismatch\",\n                \"loc\": [\"query\", \"item-query\"],\n                \"msg\": \"String should match pattern '^fixedquery$'\",\n                \"input\": \"nonregexquery\",\n                \"ctx\": {\"pattern\": \"^fixedquery$\"},\n            }\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n\n    parameters_schema = {\n        \"anyOf\": [\n            {\n                \"type\": \"string\",\n                \"minLength\": 3,\n                \"maxLength\": 50,\n                \"pattern\": \"^fixedquery$\",\n            },\n            {\"type\": \"null\"},\n        ],\n        \"title\": \"Query string\",\n        \"description\": \"Query string for the items to search in the database that have a good match\",\n        # See https://github.com/pydantic/pydantic/blob/80353c29a824c55dea4667b328ba8f329879ac9f/tests/test_fastapi.sh#L25-L34.\n        **({\"deprecated\": True} if PYDANTIC_VERSION_MINOR_TUPLE >= (2, 10) else {}),\n    }\n\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"description\": \"Query string for the items to search in the database that have a good match\",\n                                \"required\": False,\n                                \"deprecated\": True,\n                                \"schema\": Is(parameters_schema),\n                                \"name\": \"item-query\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial011_py310\", marks=needs_py310),\n        pytest.param(\"tutorial011_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_multi_query_values(client: TestClient):\n    url = \"/items/?q=foo&q=bar\"\n    response = client.get(url)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"q\": [\"foo\", \"bar\"]}\n\n\ndef test_query_no_values(client: TestClient):\n    url = \"/items/\"\n    response = client.get(url)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"q\": None}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [\n                                        {\"type\": \"array\", \"items\": {\"type\": \"string\"}},\n                                        {\"type\": \"null\"},\n                                    ],\n                                    \"title\": \"Q\",\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial012_py310\"),\n        pytest.param(\"tutorial012_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_default_query_values(client: TestClient):\n    url = \"/items/\"\n    response = client.get(url)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"q\": [\"foo\", \"bar\"]}\n\n\ndef test_multi_query_values(client: TestClient):\n    url = \"/items/?q=baz&q=foobar\"\n    response = client.get(url)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"q\": [\"baz\", \"foobar\"]}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Q\",\n                                    \"type\": \"array\",\n                                    \"items\": {\"type\": \"string\"},\n                                    \"default\": [\"foo\", \"bar\"],\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial013_py310\",\n        \"tutorial013_an_py310\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_multi_query_values(client: TestClient):\n    url = \"/items/?q=foo&q=bar\"\n    response = client.get(url)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"q\": [\"foo\", \"bar\"]}\n\n\ndef test_query_no_values(client: TestClient):\n    url = \"/items/\"\n    response = client.get(url)\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"q\": []}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Q\",\n                                    \"type\": \"array\",\n                                    \"items\": {},\n                                    \"default\": [],\n                                },\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial014_py310\", marks=needs_py310),\n        pytest.param(\"tutorial014_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_hidden_query(client: TestClient):\n    response = client.get(\"/items?hidden_query=somevalue\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"hidden_query\": \"somevalue\"}\n\n\ndef test_no_hidden_query(client: TestClient):\n    response = client.get(\"/items\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"hidden_query\": \"Not found\"}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py",
    "content": "import importlib\n\nimport pytest\nfrom dirty_equals import IsStr\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial015_an_py310\", marks=[needs_py310]),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(\n        f\"docs_src.query_params_str_validations.{request.param}\"\n    )\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_random_item(client: TestClient):\n    response = client.get(\"/items\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"id\": IsStr(), \"name\": IsStr()}\n\n\ndef test_get_item(client: TestClient):\n    response = client.get(\"/items?id=isbn-9781529046137\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"id\": \"isbn-9781529046137\",\n        \"name\": \"The Hitchhiker's Guide to the Galaxy\",\n    }\n\n\ndef test_get_item_does_not_exist(client: TestClient):\n    response = client.get(\"/items?id=isbn-nope\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"id\": \"isbn-nope\", \"name\": None}\n\n\ndef test_get_invalid_item(client: TestClient):\n    response = client.get(\"/items?id=wtf-yes\")\n    assert response.status_code == 422, response.text\n    assert response.json() == snapshot(\n        {\n            \"detail\": [\n                {\n                    \"type\": \"value_error\",\n                    \"loc\": [\"query\", \"id\"],\n                    \"msg\": 'Value error, Invalid ID format, it must start with \"isbn-\" or \"imdb-\"',\n                    \"input\": \"wtf-yes\",\n                    \"ctx\": {\"error\": {}},\n                }\n            ]\n        }\n    )\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"id\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Id\",\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_request_files/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_request_files/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial001_py310\",\n        \"tutorial001_an_py310\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.request_files.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_form_no_body(client: TestClient):\n    response = client.post(\"/files/\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"file\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_post_body_json(client: TestClient):\n    response = client.post(\"/files/\", json={\"file\": \"Foo\"})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"file\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_post_file(tmp_path, client: TestClient):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n\n    with path.open(\"rb\") as file:\n        response = client.post(\"/files/\", files={\"file\": file})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": 14}\n\n\ndef test_post_large_file(tmp_path, client: TestClient):\n    default_pydantic_max_size = 2**16\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"x\" * (default_pydantic_max_size + 1))\n\n    with path.open(\"rb\") as file:\n        response = client.post(\"/files/\", files={\"file\": file})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": default_pydantic_max_size + 1}\n\n\ndef test_post_upload_file(tmp_path, client: TestClient):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n\n    with path.open(\"rb\") as file:\n        response = client.post(\"/uploadfile/\", files={\"file\": file})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"filename\": \"test.txt\"}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/files/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create File\",\n                        \"operationId\": \"create_file_files__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_file_files__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n                \"/uploadfile/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create Upload File\",\n                        \"operationId\": \"create_upload_file_uploadfile__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_upload_file_uploadfile__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_create_upload_file_uploadfile__post\": {\n                        \"title\": \"Body_create_upload_file_uploadfile__post\",\n                        \"required\": [\"file\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"file\": {\n                                \"title\": \"File\",\n                                \"contentMediaType\": \"application/octet-stream\",\n                                \"type\": \"string\",\n                            }\n                        },\n                    },\n                    \"Body_create_file_files__post\": {\n                        \"title\": \"Body_create_file_files__post\",\n                        \"required\": [\"file\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"file\": {\n                                \"title\": \"File\",\n                                \"type\": \"string\",\n                                \"contentMediaType\": \"application/octet-stream\",\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_request_files/test_tutorial001_02.py",
    "content": "import importlib\nfrom pathlib import Path\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_02_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_02_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.request_files.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_form_no_body(client: TestClient):\n    response = client.post(\"/files/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"No file sent\"}\n\n\ndef test_post_uploadfile_no_body(client: TestClient):\n    response = client.post(\"/uploadfile/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"No upload file sent\"}\n\n\ndef test_post_file(tmp_path: Path, client: TestClient):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n\n    with path.open(\"rb\") as file:\n        response = client.post(\"/files/\", files={\"file\": file})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": 14}\n\n\ndef test_post_upload_file(tmp_path: Path, client: TestClient):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n\n    with path.open(\"rb\") as file:\n        response = client.post(\"/uploadfile/\", files={\"file\": file})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"filename\": \"test.txt\"}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/files/\": {\n                    \"post\": {\n                        \"summary\": \"Create File\",\n                        \"operationId\": \"create_file_files__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_file_files__post\"\n                                    }\n                                }\n                            }\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/uploadfile/\": {\n                    \"post\": {\n                        \"summary\": \"Create Upload File\",\n                        \"operationId\": \"create_upload_file_uploadfile__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_upload_file_uploadfile__post\"\n                                    }\n                                }\n                            }\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_create_file_files__post\": {\n                        \"title\": \"Body_create_file_files__post\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"file\": {\n                                \"title\": \"File\",\n                                \"anyOf\": [\n                                    {\n                                        \"type\": \"string\",\n                                        \"contentMediaType\": \"application/octet-stream\",\n                                    },\n                                    {\"type\": \"null\"},\n                                ],\n                            }\n                        },\n                    },\n                    \"Body_create_upload_file_uploadfile__post\": {\n                        \"title\": \"Body_create_upload_file_uploadfile__post\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"file\": {\n                                \"title\": \"File\",\n                                \"anyOf\": [\n                                    {\n                                        \"type\": \"string\",\n                                        \"contentMediaType\": \"application/octet-stream\",\n                                    },\n                                    {\"type\": \"null\"},\n                                ],\n                            }\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_request_files/test_tutorial001_03.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial001_03_py310\",\n        \"tutorial001_03_an_py310\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.request_files.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_file(tmp_path, client: TestClient):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n\n    with path.open(\"rb\") as file:\n        response = client.post(\"/files/\", files={\"file\": file})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_size\": 14}\n\n\ndef test_post_upload_file(tmp_path, client: TestClient):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n\n    with path.open(\"rb\") as file:\n        response = client.post(\"/uploadfile/\", files={\"file\": file})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"filename\": \"test.txt\"}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/files/\": {\n                    \"post\": {\n                        \"summary\": \"Create File\",\n                        \"operationId\": \"create_file_files__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_file_files__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/uploadfile/\": {\n                    \"post\": {\n                        \"summary\": \"Create Upload File\",\n                        \"operationId\": \"create_upload_file_uploadfile__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_upload_file_uploadfile__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_create_file_files__post\": {\n                        \"title\": \"Body_create_file_files__post\",\n                        \"required\": [\"file\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"file\": {\n                                \"title\": \"File\",\n                                \"type\": \"string\",\n                                \"description\": \"A file read as bytes\",\n                                \"contentMediaType\": \"application/octet-stream\",\n                            }\n                        },\n                    },\n                    \"Body_create_upload_file_uploadfile__post\": {\n                        \"title\": \"Body_create_upload_file_uploadfile__post\",\n                        \"required\": [\"file\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"file\": {\n                                \"title\": \"File\",\n                                \"contentMediaType\": \"application/octet-stream\",\n                                \"type\": \"string\",\n                                \"description\": \"A file read as UploadFile\",\n                            }\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_request_files/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"app\",\n    params=[\n        \"tutorial002_py310\",\n        \"tutorial002_an_py310\",\n    ],\n)\ndef get_app(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.request_files.{request.param}\")\n\n    return mod.app\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(app: FastAPI):\n    client = TestClient(app)\n    return client\n\n\ndef test_post_form_no_body(client: TestClient):\n    response = client.post(\"/files/\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"files\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_post_body_json(client: TestClient):\n    response = client.post(\"/files/\", json={\"file\": \"Foo\"})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"files\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_post_files(tmp_path, app: FastAPI):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n    path2 = tmp_path / \"test2.txt\"\n    path2.write_bytes(b\"<file content2>\")\n\n    client = TestClient(app)\n    with path.open(\"rb\") as file, path2.open(\"rb\") as file2:\n        response = client.post(\n            \"/files/\",\n            files=(\n                (\"files\", (\"test.txt\", file)),\n                (\"files\", (\"test2.txt\", file2)),\n            ),\n        )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_sizes\": [14, 15]}\n\n\ndef test_post_upload_file(tmp_path, app: FastAPI):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n    path2 = tmp_path / \"test2.txt\"\n    path2.write_bytes(b\"<file content2>\")\n\n    client = TestClient(app)\n    with path.open(\"rb\") as file, path2.open(\"rb\") as file2:\n        response = client.post(\n            \"/uploadfiles/\",\n            files=(\n                (\"files\", (\"test.txt\", file)),\n                (\"files\", (\"test2.txt\", file2)),\n            ),\n        )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"filenames\": [\"test.txt\", \"test2.txt\"]}\n\n\ndef test_get_root(app: FastAPI):\n    client = TestClient(app)\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    assert b\"<form\" in response.content\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/files/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create Files\",\n                        \"operationId\": \"create_files_files__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_files_files__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n                \"/uploadfiles/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create Upload Files\",\n                        \"operationId\": \"create_upload_files_uploadfiles__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_upload_files_uploadfiles__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n                \"/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Main\",\n                        \"operationId\": \"main__get\",\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_create_upload_files_uploadfiles__post\": {\n                        \"title\": \"Body_create_upload_files_uploadfiles__post\",\n                        \"required\": [\"files\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"files\": {\n                                \"title\": \"Files\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"type\": \"string\",\n                                    \"contentMediaType\": \"application/octet-stream\",\n                                },\n                            }\n                        },\n                    },\n                    \"Body_create_files_files__post\": {\n                        \"title\": \"Body_create_files_files__post\",\n                        \"required\": [\"files\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"files\": {\n                                \"title\": \"Files\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"type\": \"string\",\n                                    \"contentMediaType\": \"application/octet-stream\",\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_request_files/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"app\",\n    params=[\n        \"tutorial003_py310\",\n        \"tutorial003_an_py310\",\n    ],\n)\ndef get_app(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.request_files.{request.param}\")\n\n    return mod.app\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(app: FastAPI):\n    client = TestClient(app)\n    return client\n\n\ndef test_post_files(tmp_path, app: FastAPI):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n    path2 = tmp_path / \"test2.txt\"\n    path2.write_bytes(b\"<file content2>\")\n\n    client = TestClient(app)\n    with path.open(\"rb\") as file, path2.open(\"rb\") as file2:\n        response = client.post(\n            \"/files/\",\n            files=(\n                (\"files\", (\"test.txt\", file)),\n                (\"files\", (\"test2.txt\", file2)),\n            ),\n        )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"file_sizes\": [14, 15]}\n\n\ndef test_post_upload_file(tmp_path, app: FastAPI):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n    path2 = tmp_path / \"test2.txt\"\n    path2.write_bytes(b\"<file content2>\")\n\n    client = TestClient(app)\n    with path.open(\"rb\") as file, path2.open(\"rb\") as file2:\n        response = client.post(\n            \"/uploadfiles/\",\n            files=(\n                (\"files\", (\"test.txt\", file)),\n                (\"files\", (\"test2.txt\", file2)),\n            ),\n        )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"filenames\": [\"test.txt\", \"test2.txt\"]}\n\n\ndef test_get_root(app: FastAPI):\n    client = TestClient(app)\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    assert b\"<form\" in response.content\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/files/\": {\n                    \"post\": {\n                        \"summary\": \"Create Files\",\n                        \"operationId\": \"create_files_files__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_files_files__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/uploadfiles/\": {\n                    \"post\": {\n                        \"summary\": \"Create Upload Files\",\n                        \"operationId\": \"create_upload_files_uploadfiles__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_upload_files_uploadfiles__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/\": {\n                    \"get\": {\n                        \"summary\": \"Main\",\n                        \"operationId\": \"main__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_create_files_files__post\": {\n                        \"title\": \"Body_create_files_files__post\",\n                        \"required\": [\"files\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"files\": {\n                                \"title\": \"Files\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"type\": \"string\",\n                                    \"contentMediaType\": \"application/octet-stream\",\n                                },\n                                \"description\": \"Multiple files as bytes\",\n                            }\n                        },\n                    },\n                    \"Body_create_upload_files_uploadfiles__post\": {\n                        \"title\": \"Body_create_upload_files_uploadfiles__post\",\n                        \"required\": [\"files\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"files\": {\n                                \"title\": \"Files\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"type\": \"string\",\n                                    \"contentMediaType\": \"application/octet-stream\",\n                                },\n                                \"description\": \"Multiple files as UploadFile\",\n                            }\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_request_form_models/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_request_form_models/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial001_py310\",\n        \"tutorial001_an_py310\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.request_form_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body_form(client: TestClient):\n    response = client.post(\"/login/\", data={\"username\": \"Foo\", \"password\": \"secret\"})\n    assert response.status_code == 200\n    assert response.json() == {\"username\": \"Foo\", \"password\": \"secret\"}\n\n\ndef test_post_body_form_no_password(client: TestClient):\n    response = client.post(\"/login/\", data={\"username\": \"Foo\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": {\"username\": \"Foo\"},\n            }\n        ]\n    }\n\n\ndef test_post_body_form_no_username(client: TestClient):\n    response = client.post(\"/login/\", data={\"password\": \"secret\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": {\"password\": \"secret\"},\n            }\n        ]\n    }\n\n\ndef test_post_body_form_no_data(client: TestClient):\n    response = client.post(\"/login/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n        ]\n    }\n\n\ndef test_post_body_json(client: TestClient):\n    response = client.post(\"/login/\", json={\"username\": \"Foo\", \"password\": \"secret\"})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/login/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Login\",\n                        \"operationId\": \"login_login__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/FormData\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"FormData\": {\n                        \"properties\": {\n                            \"username\": {\"type\": \"string\", \"title\": \"Username\"},\n                            \"password\": {\"type\": \"string\", \"title\": \"Password\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"username\", \"password\"],\n                        \"title\": \"FormData\",\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_request_form_models/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial002_py310\",\n        \"tutorial002_an_py310\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.request_form_models.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body_form(client: TestClient):\n    response = client.post(\"/login/\", data={\"username\": \"Foo\", \"password\": \"secret\"})\n    assert response.status_code == 200\n    assert response.json() == {\"username\": \"Foo\", \"password\": \"secret\"}\n\n\ndef test_post_body_extra_form(client: TestClient):\n    response = client.post(\n        \"/login/\", data={\"username\": \"Foo\", \"password\": \"secret\", \"extra\": \"extra\"}\n    )\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"extra_forbidden\",\n                \"loc\": [\"body\", \"extra\"],\n                \"msg\": \"Extra inputs are not permitted\",\n                \"input\": \"extra\",\n            }\n        ]\n    }\n\n\ndef test_post_body_form_no_password(client: TestClient):\n    response = client.post(\"/login/\", data={\"username\": \"Foo\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": {\"username\": \"Foo\"},\n            }\n        ]\n    }\n\n\ndef test_post_body_form_no_username(client: TestClient):\n    response = client.post(\"/login/\", data={\"password\": \"secret\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": {\"password\": \"secret\"},\n            }\n        ]\n    }\n\n\ndef test_post_body_form_no_data(client: TestClient):\n    response = client.post(\"/login/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n        ]\n    }\n\n\ndef test_post_body_json(client: TestClient):\n    response = client.post(\"/login/\", json={\"username\": \"Foo\", \"password\": \"secret\"})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": {},\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/login/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Login\",\n                        \"operationId\": \"login_login__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/FormData\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"FormData\": {\n                        \"properties\": {\n                            \"username\": {\"type\": \"string\", \"title\": \"Username\"},\n                            \"password\": {\"type\": \"string\", \"title\": \"Password\"},\n                        },\n                        \"additionalProperties\": False,\n                        \"type\": \"object\",\n                        \"required\": [\"username\", \"password\"],\n                        \"title\": \"FormData\",\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_request_forms/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_request_forms/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial001_py310\",\n        \"tutorial001_an_py310\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.request_forms.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body_form(client: TestClient):\n    response = client.post(\"/login/\", data={\"username\": \"Foo\", \"password\": \"secret\"})\n    assert response.status_code == 200\n    assert response.json() == {\"username\": \"Foo\"}\n\n\ndef test_post_body_form_no_password(client: TestClient):\n    response = client.post(\"/login/\", data={\"username\": \"Foo\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_post_body_form_no_username(client: TestClient):\n    response = client.post(\"/login/\", data={\"password\": \"secret\"})\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            }\n        ]\n    }\n\n\ndef test_post_body_form_no_data(client: TestClient):\n    response = client.post(\"/login/\")\n    assert response.status_code == 422\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_post_body_json(client: TestClient):\n    response = client.post(\"/login/\", json={\"username\": \"Foo\", \"password\": \"secret\"})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"username\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"password\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/login/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Login\",\n                        \"operationId\": \"login_login__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_login_login__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_login_login__post\": {\n                        \"title\": \"Body_login_login__post\",\n                        \"required\": [\"username\", \"password\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"password\": {\"title\": \"Password\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_request_forms_and_files/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"app\",\n    params=[\n        \"tutorial001_py310\",\n        \"tutorial001_an_py310\",\n    ],\n)\ndef get_app(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.request_forms_and_files.{request.param}\")\n\n    return mod.app\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(app: FastAPI):\n    client = TestClient(app)\n    return client\n\n\ndef test_post_form_no_body(client: TestClient):\n    response = client.post(\"/files/\")\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"file\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"fileb\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_post_form_no_file(client: TestClient):\n    response = client.post(\"/files/\", data={\"token\": \"foo\"})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"file\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"fileb\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_post_body_json(client: TestClient):\n    response = client.post(\"/files/\", json={\"file\": \"Foo\", \"token\": \"Bar\"})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"file\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"fileb\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_post_file_no_token(tmp_path, app: FastAPI):\n    path = tmp_path / \"test.txt\"\n    path.write_bytes(b\"<file content>\")\n\n    client = TestClient(app)\n    with path.open(\"rb\") as file:\n        response = client.post(\"/files/\", files={\"file\": file})\n    assert response.status_code == 422, response.text\n    assert response.json() == {\n        \"detail\": [\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"fileb\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n            {\n                \"type\": \"missing\",\n                \"loc\": [\"body\", \"token\"],\n                \"msg\": \"Field required\",\n                \"input\": None,\n            },\n        ]\n    }\n\n\ndef test_post_files_and_token(tmp_path, app: FastAPI):\n    patha = tmp_path / \"test.txt\"\n    pathb = tmp_path / \"testb.txt\"\n    patha.write_text(\"<file content>\")\n    pathb.write_text(\"<file b content>\")\n\n    client = TestClient(app)\n    with patha.open(\"rb\") as filea, pathb.open(\"rb\") as fileb:\n        response = client.post(\n            \"/files/\",\n            data={\"token\": \"foo\"},\n            files={\"file\": filea, \"fileb\": (\"testb.txt\", fileb, \"text/plain\")},\n        )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"file_size\": 14,\n        \"token\": \"foo\",\n        \"fileb_content_type\": \"text/plain\",\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/files/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create File\",\n                        \"operationId\": \"create_file_files__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"multipart/form-data\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_create_file_files__post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_create_file_files__post\": {\n                        \"title\": \"Body_create_file_files__post\",\n                        \"required\": [\"file\", \"fileb\", \"token\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"file\": {\n                                \"title\": \"File\",\n                                \"type\": \"string\",\n                                \"contentMediaType\": \"application/octet-stream\",\n                            },\n                            \"fileb\": {\n                                \"title\": \"Fileb\",\n                                \"contentMediaType\": \"application/octet-stream\",\n                                \"type\": \"string\",\n                            },\n                            \"token\": {\"title\": \"Token\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_change_status_code/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_response_change_status_code/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.response_change_status_code.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_path_operation():\n    response = client.put(\"/get-or-create-task/foo\")\n    print(response.content)\n    assert response.status_code == 200, response.text\n    assert response.json() == \"Listen to the Bar Fighters\"\n    response = client.put(\"/get-or-create-task/bar\")\n    assert response.status_code == 201, response.text\n    assert response.json() == \"This didn't exist before\"\n"
  },
  {
    "path": "tests/test_tutorial/test_response_cookies/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_response_cookies/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.response_cookies.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_path_operation():\n    response = client.post(\"/cookie/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Come to the dark side, we have cookies\"}\n    assert response.cookies[\"fakesession\"] == \"fake-cookie-session-value\"\n"
  },
  {
    "path": "tests/test_tutorial/test_response_cookies/test_tutorial002.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.response_cookies.tutorial002_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_path_operation():\n    response = client.post(\"/cookie-and-object/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Come to the dark side, we have cookies\"}\n    assert response.cookies[\"fakesession\"] == \"fake-cookie-session-value\"\n"
  },
  {
    "path": "tests/test_tutorial/test_response_directly/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_response_directly/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_directly.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_path_operation(client: TestClient):\n    response = client.put(\n        \"/items/1\",\n        json={\n            \"title\": \"Foo\",\n            \"timestamp\": \"2023-01-01T12:00:00\",\n            \"description\": \"A test item\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"description\": \"A test item\",\n        \"timestamp\": \"2023-01-01T12:00:00\",\n        \"title\": \"Foo\",\n    }\n\n\ndef test_openapi_schema_pv2(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"info\": {\n                \"title\": \"FastAPI\",\n                \"version\": \"0.1.0\",\n            },\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/items/{id}\": {\n                    \"put\": {\n                        \"operationId\": \"update_item_items__id__put\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"id\",\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Id\", \"type\": \"string\"},\n                            },\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                    },\n                                },\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\"schema\": {}},\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Update Item\",\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"description\": {\n                                \"anyOf\": [\n                                    {\"type\": \"string\"},\n                                    {\"type\": \"null\"},\n                                ],\n                                \"title\": \"Description\",\n                            },\n                            \"timestamp\": {\n                                \"format\": \"date-time\",\n                                \"title\": \"Timestamp\",\n                                \"type\": \"string\",\n                            },\n                            \"title\": {\"title\": \"Title\", \"type\": \"string\"},\n                        },\n                        \"required\": [\n                            \"title\",\n                            \"timestamp\",\n                        ],\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\"type\": \"string\"},\n                                        {\"type\": \"integer\"},\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_directly/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_directly.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_path_operation(client: TestClient):\n    expected_content = \"\"\"<?xml version=\"1.0\"?>\n    <shampoo>\n    <Header>\n        Apply shampoo here.\n    </Header>\n    <Body>\n        You'll have to use soap here.\n    </Body>\n    </shampoo>\n    \"\"\"\n\n    response = client.get(\"/legacy/\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"application/xml\"\n    assert response.text == expected_content\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"info\": {\n                \"title\": \"FastAPI\",\n                \"version\": \"0.1.0\",\n            },\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/legacy/\": {\n                    \"get\": {\n                        \"operationId\": \"get_legacy_data_legacy__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                        },\n                        \"summary\": \"Get Legacy Data\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_headers/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_response_headers/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.response_headers.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_path_operation():\n    response = client.get(\"/headers/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello World\"}\n    assert response.headers[\"X-Cat-Dog\"] == \"alone in the world\"\n    assert response.headers[\"Content-Language\"] == \"en-US\"\n"
  },
  {
    "path": "tests/test_tutorial/test_response_headers/test_tutorial002.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.response_headers.tutorial002_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_path_operation():\n    response = client.get(\"/headers-and-object/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello World\"}\n    assert response.headers[\"X-Cat-Dog\"] == \"alone in the world\"\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial001_tutorial001_01.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_01_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_model.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_read_items(client: TestClient):\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\n            \"name\": \"Portal Gun\",\n            \"description\": None,\n            \"price\": 42.0,\n            \"tags\": [],\n            \"tax\": None,\n        },\n        {\n            \"name\": \"Plumbus\",\n            \"description\": None,\n            \"price\": 32.0,\n            \"tags\": [],\n            \"tax\": None,\n        },\n    ]\n\n\ndef test_create_item(client: TestClient):\n    item_data = {\n        \"name\": \"Test Item\",\n        \"description\": \"A test item\",\n        \"price\": 10.5,\n        \"tax\": 1.5,\n        \"tags\": [\"test\", \"item\"],\n    }\n    response = client.post(\"/items/\", json=item_data)\n    assert response.status_code == 200, response.text\n    assert response.json() == item_data\n\n\ndef test_create_item_only_required(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        json={\n            \"name\": \"Test Item\",\n            \"price\": 10.5,\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Test Item\",\n        \"price\": 10.5,\n        \"description\": None,\n        \"tax\": None,\n        \"tags\": [],\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                            \"title\": \"Response Read Items Items  Get\",\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                    },\n                    \"post\": {\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                    },\n                                },\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"},\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                    },\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                                \"default\": [],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_model.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_user(client: TestClient):\n    user_data = {\n        \"username\": \"foo\",\n        \"password\": \"fighter\",\n        \"email\": \"foo@example.com\",\n        \"full_name\": \"Grave Dohl\",\n    }\n    response = client.post(\n        \"/user/\",\n        json=user_data,\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == user_data\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/user/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/UserIn\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create User\",\n                        \"operationId\": \"create_user_user__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/UserIn\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"UserIn\": {\n                        \"title\": \"UserIn\",\n                        \"required\": [\"username\", \"password\", \"email\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"password\": {\"title\": \"Password\", \"type\": \"string\"},\n                            \"email\": {\n                                \"title\": \"Email\",\n                                \"type\": \"string\",\n                                \"format\": \"email\",\n                            },\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_model.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_user(client: TestClient):\n    response = client.post(\n        \"/user/\",\n        json={\n            \"username\": \"foo\",\n            \"password\": \"fighter\",\n            \"email\": \"foo@example.com\",\n            \"full_name\": \"Grave Dohl\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"username\": \"foo\",\n        \"email\": \"foo@example.com\",\n        \"full_name\": \"Grave Dohl\",\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/user/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/UserOut\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Create User\",\n                        \"operationId\": \"create_user_user__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/UserIn\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"UserOut\": {\n                        \"title\": \"UserOut\",\n                        \"required\": [\"username\", \"email\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"email\": {\n                                \"title\": \"Email\",\n                                \"type\": \"string\",\n                                \"format\": \"email\",\n                            },\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"UserIn\": {\n                        \"title\": \"UserIn\",\n                        \"required\": [\"username\", \"password\", \"email\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"password\": {\"title\": \"Password\", \"type\": \"string\"},\n                            \"email\": {\n                                \"title\": \"Email\",\n                                \"type\": \"string\",\n                                \"format\": \"email\",\n                            },\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial003_01.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_01_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_model.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_user(client: TestClient):\n    response = client.post(\n        \"/user/\",\n        json={\n            \"username\": \"foo\",\n            \"password\": \"fighter\",\n            \"email\": \"foo@example.com\",\n            \"full_name\": \"Grave Dohl\",\n        },\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"username\": \"foo\",\n        \"email\": \"foo@example.com\",\n        \"full_name\": \"Grave Dohl\",\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/user/\": {\n                    \"post\": {\n                        \"summary\": \"Create User\",\n                        \"operationId\": \"create_user_user__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/UserIn\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/BaseUser\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"BaseUser\": {\n                        \"title\": \"BaseUser\",\n                        \"required\": [\"username\", \"email\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"email\": {\n                                \"title\": \"Email\",\n                                \"type\": \"string\",\n                                \"format\": \"email\",\n                            },\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"UserIn\": {\n                        \"title\": \"UserIn\",\n                        \"required\": [\"username\", \"email\", \"password\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"email\": {\n                                \"title\": \"Email\",\n                                \"type\": \"string\",\n                                \"format\": \"email\",\n                            },\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"password\": {\"title\": \"Password\", \"type\": \"string\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial003_02.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.response_model.tutorial003_02_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get_portal():\n    response = client.get(\"/portal\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Here's your interdimensional portal.\"}\n\n\ndef test_get_redirect():\n    response = client.get(\"/portal\", params={\"teleport\": True}, follow_redirects=False)\n    assert response.status_code == 307, response.text\n    assert response.headers[\"location\"] == \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/portal\": {\n                    \"get\": {\n                        \"summary\": \"Get Portal\",\n                        \"operationId\": \"get_portal_portal_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Teleport\",\n                                    \"type\": \"boolean\",\n                                    \"default\": False,\n                                },\n                                \"name\": \"teleport\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial003_03.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.response_model.tutorial003_03_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_get_portal():\n    response = client.get(\"/teleport\", follow_redirects=False)\n    assert response.status_code == 307, response.text\n    assert response.headers[\"location\"] == \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\"\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/teleport\": {\n                    \"get\": {\n                        \"summary\": \"Get Teleport\",\n                        \"operationId\": \"get_teleport_teleport_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial003_04.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.exceptions import FastAPIError\n\nfrom ...utils import needs_py310\n\n\n@pytest.mark.parametrize(\n    \"module_name\",\n    [\n        pytest.param(\"tutorial003_04_py310\", marks=needs_py310),\n    ],\n)\ndef test_invalid_response_model(module_name: str) -> None:\n    with pytest.raises(FastAPIError):\n        importlib.import_module(f\"docs_src.response_model.{module_name}\")\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial003_05.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_05_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_model.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_get_portal(client: TestClient):\n    response = client.get(\"/portal\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Here's your interdimensional portal.\"}\n\n\ndef test_get_redirect(client: TestClient):\n    response = client.get(\"/portal\", params={\"teleport\": True}, follow_redirects=False)\n    assert response.status_code == 307, response.text\n    assert response.headers[\"location\"] == \"https://www.youtube.com/watch?v=dQw4w9WgXcQ\"\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/portal\": {\n                    \"get\": {\n                        \"summary\": \"Get Portal\",\n                        \"operationId\": \"get_portal_portal_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": False,\n                                \"schema\": {\n                                    \"title\": \"Teleport\",\n                                    \"type\": \"boolean\",\n                                    \"default\": False,\n                                },\n                                \"name\": \"teleport\",\n                                \"in\": \"query\",\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_model.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"url,data\",\n    [\n        (\"/items/foo\", {\"name\": \"Foo\", \"price\": 50.2}),\n        (\n            \"/items/bar\",\n            {\"name\": \"Bar\", \"description\": \"The bartenders\", \"price\": 62, \"tax\": 20.2},\n        ),\n        (\n            \"/items/baz\",\n            {\n                \"name\": \"Baz\",\n                \"description\": None,\n                \"price\": 50.2,\n                \"tax\": 10.5,\n                \"tags\": [],\n            },\n        ),\n    ],\n)\ndef test_get(url, data, client: TestClient):\n    response = client.get(url)\n    assert response.status_code == 200, response.text\n    assert response.json() == data\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item\",\n                        \"operationId\": \"read_item_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"tax\": {\"title\": \"Tax\", \"type\": \"number\", \"default\": 10.5},\n                            \"tags\": {\n                                \"title\": \"Tags\",\n                                \"type\": \"array\",\n                                \"items\": {\"type\": \"string\"},\n                                \"default\": [],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial005.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_model.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_read_item_name(client: TestClient):\n    response = client.get(\"/items/bar/name\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Bar\", \"description\": \"The Bar fighters\"}\n\n\ndef test_read_item_public_data(client: TestClient):\n    response = client.get(\"/items/bar/public\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Bar\",\n        \"description\": \"The Bar fighters\",\n        \"price\": 62,\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}/name\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item Name\",\n                        \"operationId\": \"read_item_name_items__item_id__name_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/items/{item_id}/public\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item Public Data\",\n                        \"operationId\": \"read_item_public_data_items__item_id__public_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"tax\": {\"title\": \"Tax\", \"type\": \"number\", \"default\": 10.5},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_model/test_tutorial006.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial006_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_model.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_read_item_name(client: TestClient):\n    response = client.get(\"/items/bar/name\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Bar\", \"description\": \"The Bar fighters\"}\n\n\ndef test_read_item_public_data(client: TestClient):\n    response = client.get(\"/items/bar/public\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"Bar\",\n        \"description\": \"The Bar fighters\",\n        \"price\": 62,\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}/name\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item Name\",\n                        \"operationId\": \"read_item_name_items__item_id__name_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n                \"/items/{item_id}/public\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Read Item Public Data\",\n                        \"operationId\": \"read_item_public_data_items__item_id__public_get\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"string\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"tax\": {\"title\": \"Tax\", \"type\": \"number\", \"default\": 10.5},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_response_status_code/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_response_status_code/test_tutorial001_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\"),\n        pytest.param(\"tutorial002_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.response_status_code.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_create_item(client: TestClient):\n    response = client.post(\"/items/\", params={\"name\": \"Test Item\"})\n    assert response.status_code == 201, response.text\n    assert response.json() == {\"name\": \"Test Item\"}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"parameters\": [\n                            {\n                                \"name\": \"name\",\n                                \"in\": \"query\",\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Name\", \"type\": \"string\"},\n                            }\n                        ],\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"responses\": {\n                            \"201\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_schema_extra_example/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_schema_extra_example/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.schema_extra_example.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body_example(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n        },\n    )\n    assert response.status_code == 200\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"integer\", \"title\": \"Item Id\"},\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"required\": True,\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                            },\n                            \"price\": {\"type\": \"number\", \"title\": \"Price\"},\n                            \"tax\": {\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                                \"title\": \"Tax\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"price\"],\n                        \"title\": \"Item\",\n                        \"examples\": [\n                            {\n                                \"description\": \"A very nice Item\",\n                                \"name\": \"Foo\",\n                                \"price\": 35.4,\n                                \"tax\": 3.2,\n                            }\n                        ],\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_schema_extra_example/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.schema_extra_example.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body_example(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n        },\n    )\n    assert response.status_code == 200\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"integer\", \"title\": \"Item Id\"},\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"required\": True,\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"type\": \"string\",\n                                \"title\": \"Name\",\n                                \"examples\": [\"Foo\"],\n                            },\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                                \"examples\": [\"A very nice Item\"],\n                            },\n                            \"price\": {\n                                \"type\": \"number\",\n                                \"title\": \"Price\",\n                                \"examples\": [35.4],\n                            },\n                            \"tax\": {\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                                \"title\": \"Tax\",\n                                \"examples\": [3.2],\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"price\"],\n                        \"title\": \"Item\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_schema_extra_example/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n        pytest.param(\"tutorial003_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.schema_extra_example.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body_example(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n        },\n    )\n    assert response.status_code == 200\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"integer\", \"title\": \"Item Id\"},\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"required\": True,\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                        \"examples\": [\n                                            {\n                                                \"description\": \"A very nice Item\",\n                                                \"name\": \"Foo\",\n                                                \"price\": 35.4,\n                                                \"tax\": 3.2,\n                                            }\n                                        ],\n                                    },\n                                }\n                            },\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                            },\n                            \"price\": {\"type\": \"number\", \"title\": \"Price\"},\n                            \"tax\": {\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                                \"title\": \"Tax\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"price\"],\n                        \"title\": \"Item\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_schema_extra_example/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n        pytest.param(\"tutorial004_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.schema_extra_example.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body_example(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n        },\n    )\n    assert response.status_code == 200\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"integer\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Item\",\n                                        \"examples\": [\n                                            {\n                                                \"name\": \"Foo\",\n                                                \"description\": \"A very nice Item\",\n                                                \"price\": 35.4,\n                                                \"tax\": 3.2,\n                                            },\n                                            {\"name\": \"Bar\", \"price\": \"35.4\"},\n                                            {\n                                                \"name\": \"Baz\",\n                                                \"price\": \"thirty five point four\",\n                                            },\n                                        ],\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_schema_extra_example/test_tutorial005.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n        pytest.param(\"tutorial005_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.schema_extra_example.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_post_body_example(client: TestClient):\n    response = client.put(\n        \"/items/5\",\n        json={\n            \"name\": \"Foo\",\n            \"description\": \"A very nice Item\",\n            \"price\": 35.4,\n            \"tax\": 3.2,\n        },\n    )\n    assert response.status_code == 200\n\n\ndef test_openapi_schema(client: TestClient) -> None:\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"put\": {\n                        \"summary\": \"Update Item\",\n                        \"operationId\": \"update_item_items__item_id__put\",\n                        \"parameters\": [\n                            {\n                                \"required\": True,\n                                \"schema\": {\"title\": \"Item Id\", \"type\": \"integer\"},\n                                \"name\": \"item_id\",\n                                \"in\": \"path\",\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"},\n                                    \"examples\": {\n                                        \"normal\": {\n                                            \"summary\": \"A normal example\",\n                                            \"description\": \"A **normal** item works correctly.\",\n                                            \"value\": {\n                                                \"name\": \"Foo\",\n                                                \"description\": \"A very nice Item\",\n                                                \"price\": 35.4,\n                                                \"tax\": 3.2,\n                                            },\n                                        },\n                                        \"converted\": {\n                                            \"summary\": \"An example with converted data\",\n                                            \"description\": \"FastAPI can convert price `strings` to actual `numbers` automatically\",\n                                            \"value\": {\"name\": \"Bar\", \"price\": \"35.4\"},\n                                        },\n                                        \"invalid\": {\n                                            \"summary\": \"Invalid data is rejected with an error\",\n                                            \"value\": {\n                                                \"name\": \"Baz\",\n                                                \"price\": \"thirty five point four\",\n                                            },\n                                        },\n                                    },\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"required\": [\"name\", \"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\"title\": \"Name\", \"type\": \"string\"},\n                            \"description\": {\n                                \"title\": \"Description\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"price\": {\"title\": \"Price\", \"type\": \"number\"},\n                            \"tax\": {\n                                \"title\": \"Tax\",\n                                \"anyOf\": [{\"type\": \"number\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_security/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_security/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\"),\n        pytest.param(\"tutorial001_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.security.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_no_token(client: TestClient):\n    response = client.get(\"/items\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_token(client: TestClient):\n    response = client.get(\"/items\", headers={\"Authorization\": \"Bearer testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"token\": \"testtoken\"}\n\n\ndef test_incorrect_token(client: TestClient):\n    response = client.get(\"/items\", headers={\"Authorization\": \"Notexistent testtoken\"})\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"security\": [{\"OAuth2PasswordBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OAuth2PasswordBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\"password\": {\"scopes\": {}, \"tokenUrl\": \"token\"}},\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_security/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.security.{request.param}\")\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_no_token(client: TestClient):\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_token(client: TestClient):\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer testtoken\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"username\": \"testtokenfakedecoded\",\n        \"email\": \"john@example.com\",\n        \"full_name\": \"John Doe\",\n        \"disabled\": None,\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Users Me\",\n                        \"operationId\": \"read_users_me_users_me_get\",\n                        \"security\": [{\"OAuth2PasswordBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\n                    \"OAuth2PasswordBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\"password\": {\"scopes\": {}, \"tokenUrl\": \"token\"}},\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_security/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\", marks=needs_py310),\n        pytest.param(\"tutorial003_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.security.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_login(client: TestClient):\n    response = client.post(\"/token\", data={\"username\": \"johndoe\", \"password\": \"secret\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"access_token\": \"johndoe\", \"token_type\": \"bearer\"}\n\n\ndef test_login_incorrect_password(client: TestClient):\n    response = client.post(\n        \"/token\", data={\"username\": \"johndoe\", \"password\": \"incorrect\"}\n    )\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"Incorrect username or password\"}\n\n\ndef test_login_incorrect_username(client: TestClient):\n    response = client.post(\"/token\", data={\"username\": \"foo\", \"password\": \"secret\"})\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"Incorrect username or password\"}\n\n\ndef test_no_token(client: TestClient):\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_token(client: TestClient):\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer johndoe\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"username\": \"johndoe\",\n        \"full_name\": \"John Doe\",\n        \"email\": \"johndoe@example.com\",\n        \"hashed_password\": \"fakehashedsecret\",\n        \"disabled\": False,\n    }\n\n\ndef test_incorrect_token(client: TestClient):\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer nonexistent\"})\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_incorrect_token_type(client: TestClient):\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Notexistent testtoken\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_inactive_user(client: TestClient):\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer alice\"})\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"Inactive user\"}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/token\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Login\",\n                        \"operationId\": \"login_token_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_login_token_post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Users Me\",\n                        \"operationId\": \"read_users_me_users_me_get\",\n                        \"security\": [{\"OAuth2PasswordBearer\": []}],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Body_login_token_post\": {\n                        \"title\": \"Body_login_token_post\",\n                        \"required\": [\"username\", \"password\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"grant_type\": {\n                                \"title\": \"Grant Type\",\n                                \"anyOf\": [\n                                    {\"pattern\": \"^password$\", \"type\": \"string\"},\n                                    {\"type\": \"null\"},\n                                ],\n                            },\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"password\": {\n                                \"title\": \"Password\",\n                                \"type\": \"string\",\n                                \"format\": \"password\",\n                            },\n                            \"scope\": {\n                                \"title\": \"Scope\",\n                                \"type\": \"string\",\n                                \"default\": \"\",\n                            },\n                            \"client_id\": {\n                                \"title\": \"Client Id\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"client_secret\": {\n                                \"title\": \"Client Secret\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"format\": \"password\",\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                },\n                \"securitySchemes\": {\n                    \"OAuth2PasswordBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\"password\": {\"scopes\": {}, \"tokenUrl\": \"token\"}},\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_security/test_tutorial004.py",
    "content": "import importlib\nfrom types import ModuleType\nfrom unittest.mock import patch\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial004_py310\", marks=needs_py310),\n        pytest.param(\"tutorial004_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_mod(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.security.{request.param}\")\n\n    return mod\n\n\ndef get_access_token(*, username=\"johndoe\", password=\"secret\", client: TestClient):\n    data = {\"username\": username, \"password\": password}\n    response = client.post(\"/token\", data=data)\n    content = response.json()\n    access_token = content.get(\"access_token\")\n    return access_token\n\n\ndef test_login(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.post(\"/token\", data={\"username\": \"johndoe\", \"password\": \"secret\"})\n    assert response.status_code == 200, response.text\n    content = response.json()\n    assert \"access_token\" in content\n    assert content[\"token_type\"] == \"bearer\"\n\n\ndef test_login_incorrect_password(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.post(\n        \"/token\", data={\"username\": \"johndoe\", \"password\": \"incorrect\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Incorrect username or password\"}\n\n\ndef test_login_incorrect_username(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.post(\"/token\", data={\"username\": \"foo\", \"password\": \"secret\"})\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Incorrect username or password\"}\n\n\ndef test_no_token(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_token(mod: ModuleType):\n    client = TestClient(mod.app)\n    access_token = get_access_token(client=client)\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": f\"Bearer {access_token}\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"username\": \"johndoe\",\n        \"full_name\": \"John Doe\",\n        \"email\": \"johndoe@example.com\",\n        \"disabled\": False,\n    }\n\n\ndef test_incorrect_token(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer nonexistent\"})\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Could not validate credentials\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_incorrect_token_type(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Notexistent testtoken\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_verify_password(mod: ModuleType):\n    assert mod.verify_password(\n        \"secret\", mod.fake_users_db[\"johndoe\"][\"hashed_password\"]\n    )\n\n\ndef test_get_password_hash(mod: ModuleType):\n    assert mod.get_password_hash(\"johndoe\")\n\n\ndef test_create_access_token(mod: ModuleType):\n    access_token = mod.create_access_token(data={\"data\": \"foo\"})\n    assert access_token\n\n\ndef test_token_no_sub(mod: ModuleType):\n    client = TestClient(mod.app)\n\n    response = client.get(\n        \"/users/me\",\n        headers={\n            \"Authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiZm9vIn0.9ynBhuYb4e6aW3oJr_K_TBgwcMTDpRToQIE25L57rOE\"\n        },\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Could not validate credentials\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_token_no_username(mod: ModuleType):\n    client = TestClient(mod.app)\n\n    response = client.get(\n        \"/users/me\",\n        headers={\n            \"Authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb28ifQ.NnExK_dlNAYyzACrXtXDrcWOgGY2JuPbI4eDaHdfK5Y\"\n        },\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Could not validate credentials\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_token_nonexistent_user(mod: ModuleType):\n    client = TestClient(mod.app)\n\n    response = client.get(\n        \"/users/me\",\n        headers={\n            \"Authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VybmFtZTpib2IifQ.HcfCW67Uda-0gz54ZWTqmtgJnZeNem0Q757eTa9EZuw\"\n        },\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Could not validate credentials\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_token_inactive_user(mod: ModuleType):\n    client = TestClient(mod.app)\n    alice_user_data = {\n        \"username\": \"alice\",\n        \"full_name\": \"Alice Wonderson\",\n        \"email\": \"alice@example.com\",\n        \"hashed_password\": mod.get_password_hash(\"secretalice\"),\n        \"disabled\": True,\n    }\n    with patch.dict(f\"{mod.__name__}.fake_users_db\", {\"alice\": alice_user_data}):\n        access_token = get_access_token(\n            username=\"alice\", password=\"secretalice\", client=client\n        )\n        response = client.get(\n            \"/users/me\", headers={\"Authorization\": f\"Bearer {access_token}\"}\n        )\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"Inactive user\"}\n\n\ndef test_read_items(mod: ModuleType):\n    client = TestClient(mod.app)\n    access_token = get_access_token(client=client)\n    response = client.get(\n        \"/users/me/items/\", headers={\"Authorization\": f\"Bearer {access_token}\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item_id\": \"Foo\", \"owner\": \"johndoe\"}]\n\n\ndef test_openapi_schema(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/token\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Token\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Login For Access Token\",\n                        \"operationId\": \"login_for_access_token_token_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_login_for_access_token_token_post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n                \"/users/me/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                        \"summary\": \"Read Users Me\",\n                        \"operationId\": \"read_users_me_users_me__get\",\n                        \"security\": [{\"OAuth2PasswordBearer\": []}],\n                    }\n                },\n                \"/users/me/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Own Items\",\n                        \"operationId\": \"read_own_items_users_me_items__get\",\n                        \"security\": [{\"OAuth2PasswordBearer\": []}],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"User\": {\n                        \"title\": \"User\",\n                        \"required\": [\"username\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"email\": {\n                                \"title\": \"Email\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"disabled\": {\n                                \"title\": \"Disabled\",\n                                \"anyOf\": [{\"type\": \"boolean\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"Token\": {\n                        \"title\": \"Token\",\n                        \"required\": [\"access_token\", \"token_type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"access_token\": {\"title\": \"Access Token\", \"type\": \"string\"},\n                            \"token_type\": {\"title\": \"Token Type\", \"type\": \"string\"},\n                        },\n                    },\n                    \"Body_login_for_access_token_token_post\": {\n                        \"title\": \"Body_login_for_access_token_token_post\",\n                        \"required\": [\"username\", \"password\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"grant_type\": {\n                                \"title\": \"Grant Type\",\n                                \"anyOf\": [\n                                    {\"pattern\": \"^password$\", \"type\": \"string\"},\n                                    {\"type\": \"null\"},\n                                ],\n                            },\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"password\": {\n                                \"title\": \"Password\",\n                                \"type\": \"string\",\n                                \"format\": \"password\",\n                            },\n                            \"scope\": {\n                                \"title\": \"Scope\",\n                                \"type\": \"string\",\n                                \"default\": \"\",\n                            },\n                            \"client_id\": {\n                                \"title\": \"Client Id\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"client_secret\": {\n                                \"title\": \"Client Secret\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"format\": \"password\",\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                },\n                \"securitySchemes\": {\n                    \"OAuth2PasswordBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\n                            \"password\": {\n                                \"scopes\": {},\n                                \"tokenUrl\": \"token\",\n                            }\n                        },\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_security/test_tutorial005.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial005_py310\", marks=needs_py310),\n        pytest.param(\"tutorial005_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_mod(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.security.{request.param}\")\n\n    return mod\n\n\ndef get_access_token(\n    *, username=\"johndoe\", password=\"secret\", scope=None, client: TestClient\n):\n    data = {\"username\": username, \"password\": password}\n    if scope:\n        data[\"scope\"] = scope\n    response = client.post(\"/token\", data=data)\n    content = response.json()\n    access_token = content.get(\"access_token\")\n    return access_token\n\n\ndef test_login(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.post(\"/token\", data={\"username\": \"johndoe\", \"password\": \"secret\"})\n    assert response.status_code == 200, response.text\n    content = response.json()\n    assert \"access_token\" in content\n    assert content[\"token_type\"] == \"bearer\"\n\n\ndef test_login_incorrect_password(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.post(\n        \"/token\", data={\"username\": \"johndoe\", \"password\": \"incorrect\"}\n    )\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"Incorrect username or password\"}\n\n\ndef test_login_incorrect_username(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.post(\"/token\", data={\"username\": \"foo\", \"password\": \"secret\"})\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"Incorrect username or password\"}\n\n\ndef test_no_token(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/users/me\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_token(mod: ModuleType):\n    client = TestClient(mod.app)\n    access_token = get_access_token(scope=\"me\", client=client)\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": f\"Bearer {access_token}\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"username\": \"johndoe\",\n        \"full_name\": \"John Doe\",\n        \"email\": \"johndoe@example.com\",\n        \"disabled\": False,\n    }\n\n\ndef test_incorrect_token(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/users/me\", headers={\"Authorization\": \"Bearer nonexistent\"})\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Could not validate credentials\"}\n    assert response.headers[\"WWW-Authenticate\"] == 'Bearer scope=\"me\"'\n\n\ndef test_incorrect_token_type(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Notexistent testtoken\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_verify_password(mod: ModuleType):\n    assert mod.verify_password(\n        \"secret\", mod.fake_users_db[\"johndoe\"][\"hashed_password\"]\n    )\n\n\ndef test_get_password_hash(mod: ModuleType):\n    assert mod.get_password_hash(\"secretalice\")\n\n\ndef test_create_access_token(mod: ModuleType):\n    access_token = mod.create_access_token(data={\"data\": \"foo\"})\n    assert access_token\n\n\ndef test_token_no_sub(mod: ModuleType):\n    client = TestClient(mod.app)\n\n    response = client.get(\n        \"/users/me\",\n        headers={\n            \"Authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiZm9vIn0.9ynBhuYb4e6aW3oJr_K_TBgwcMTDpRToQIE25L57rOE\"\n        },\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Could not validate credentials\"}\n    assert response.headers[\"WWW-Authenticate\"] == 'Bearer scope=\"me\"'\n\n\ndef test_token_no_username(mod: ModuleType):\n    client = TestClient(mod.app)\n\n    response = client.get(\n        \"/users/me\",\n        headers={\n            \"Authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb28ifQ.NnExK_dlNAYyzACrXtXDrcWOgGY2JuPbI4eDaHdfK5Y\"\n        },\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Could not validate credentials\"}\n    assert response.headers[\"WWW-Authenticate\"] == 'Bearer scope=\"me\"'\n\n\ndef test_token_no_scope(mod: ModuleType):\n    client = TestClient(mod.app)\n\n    access_token = get_access_token(client=client)\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": f\"Bearer {access_token}\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not enough permissions\"}\n    assert response.headers[\"WWW-Authenticate\"] == 'Bearer scope=\"me\"'\n\n\ndef test_token_nonexistent_user(mod: ModuleType):\n    client = TestClient(mod.app)\n\n    response = client.get(\n        \"/users/me\",\n        headers={\n            \"Authorization\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VybmFtZTpib2IifQ.HcfCW67Uda-0gz54ZWTqmtgJnZeNem0Q757eTa9EZuw\"\n        },\n    )\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Could not validate credentials\"}\n    assert response.headers[\"WWW-Authenticate\"] == 'Bearer scope=\"me\"'\n\n\ndef test_token_inactive_user(mod: ModuleType):\n    client = TestClient(mod.app)\n\n    access_token = get_access_token(\n        username=\"alice\", password=\"secretalice\", scope=\"me\", client=client\n    )\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": f\"Bearer {access_token}\"}\n    )\n    assert response.status_code == 400, response.text\n    assert response.json() == {\"detail\": \"Inactive user\"}\n\n\ndef test_read_items(mod: ModuleType):\n    client = TestClient(mod.app)\n    access_token = get_access_token(scope=\"me items\", client=client)\n    response = client.get(\n        \"/users/me/items/\", headers={\"Authorization\": f\"Bearer {access_token}\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == [{\"item_id\": \"Foo\", \"owner\": \"johndoe\"}]\n\n\ndef test_read_system_status(mod: ModuleType):\n    client = TestClient(mod.app)\n    access_token = get_access_token(client=client)\n    response = client.get(\n        \"/status/\", headers={\"Authorization\": f\"Bearer {access_token}\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"status\": \"ok\"}\n\n\ndef test_read_system_status_no_token(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/status/\")\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Bearer\"\n\n\ndef test_openapi_schema(mod: ModuleType):\n    client = TestClient(mod.app)\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/token\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Token\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Login For Access Token\",\n                        \"operationId\": \"login_for_access_token_token_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Body_login_for_access_token_token_post\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                },\n                \"/users/me/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/User\"}\n                                    }\n                                },\n                            }\n                        },\n                        \"summary\": \"Read Users Me\",\n                        \"operationId\": \"read_users_me_users_me__get\",\n                        \"security\": [{\"OAuth2PasswordBearer\": [\"me\"]}],\n                    }\n                },\n                \"/users/me/items/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Own Items\",\n                        \"operationId\": \"read_own_items_users_me_items__get\",\n                        \"security\": [{\"OAuth2PasswordBearer\": [\"items\", \"me\"]}],\n                    }\n                },\n                \"/status/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read System Status\",\n                        \"operationId\": \"read_system_status_status__get\",\n                        \"security\": [{\"OAuth2PasswordBearer\": []}],\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"User\": {\n                        \"title\": \"User\",\n                        \"required\": [\"username\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"email\": {\n                                \"title\": \"Email\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"full_name\": {\n                                \"title\": \"Full Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"disabled\": {\n                                \"title\": \"Disabled\",\n                                \"anyOf\": [{\"type\": \"boolean\"}, {\"type\": \"null\"}],\n                            },\n                        },\n                    },\n                    \"Token\": {\n                        \"title\": \"Token\",\n                        \"required\": [\"access_token\", \"token_type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"access_token\": {\"title\": \"Access Token\", \"type\": \"string\"},\n                            \"token_type\": {\"title\": \"Token Type\", \"type\": \"string\"},\n                        },\n                    },\n                    \"Body_login_for_access_token_token_post\": {\n                        \"title\": \"Body_login_for_access_token_token_post\",\n                        \"required\": [\"username\", \"password\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"grant_type\": {\n                                \"title\": \"Grant Type\",\n                                \"anyOf\": [\n                                    {\"pattern\": \"^password$\", \"type\": \"string\"},\n                                    {\"type\": \"null\"},\n                                ],\n                            },\n                            \"username\": {\"title\": \"Username\", \"type\": \"string\"},\n                            \"password\": {\n                                \"title\": \"Password\",\n                                \"type\": \"string\",\n                                \"format\": \"password\",\n                            },\n                            \"scope\": {\n                                \"title\": \"Scope\",\n                                \"type\": \"string\",\n                                \"default\": \"\",\n                            },\n                            \"client_id\": {\n                                \"title\": \"Client Id\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"client_secret\": {\n                                \"title\": \"Client Secret\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"format\": \"password\",\n                            },\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                },\n                \"securitySchemes\": {\n                    \"OAuth2PasswordBearer\": {\n                        \"type\": \"oauth2\",\n                        \"flows\": {\n                            \"password\": {\n                                \"scopes\": {\n                                    \"me\": \"Read information about the current user.\",\n                                    \"items\": \"Read items.\",\n                                },\n                                \"tokenUrl\": \"token\",\n                            }\n                        },\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_security/test_tutorial006.py",
    "content": "import importlib\nfrom base64 import b64encode\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial006_py310\"),\n        pytest.param(\"tutorial006_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.security.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_security_http_basic(client: TestClient):\n    response = client.get(\"/users/me\", auth=(\"john\", \"secret\"))\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"john\", \"password\": \"secret\"}\n\n\ndef test_security_http_basic_no_credentials(client: TestClient):\n    response = client.get(\"/users/me\")\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == \"Basic\"\n\n\ndef test_security_http_basic_invalid_credentials(client: TestClient):\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Basic notabase64token\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == \"Basic\"\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_security_http_basic_non_basic_credentials(client: TestClient):\n    payload = b64encode(b\"johnsecret\").decode(\"ascii\")\n    auth_header = f\"Basic {payload}\"\n    response = client.get(\"/users/me\", headers={\"Authorization\": auth_header})\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == \"Basic\"\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBasic\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPBasic\": {\"type\": \"http\", \"scheme\": \"basic\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_security/test_tutorial007.py",
    "content": "import importlib\nfrom base64 import b64encode\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial007_py310\"),\n        pytest.param(\"tutorial007_an_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.security.{request.param}\")\n    return TestClient(mod.app)\n\n\ndef test_security_http_basic(client: TestClient):\n    response = client.get(\"/users/me\", auth=(\"stanleyjobson\", \"swordfish\"))\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"username\": \"stanleyjobson\"}\n\n\ndef test_security_http_basic_no_credentials(client: TestClient):\n    response = client.get(\"/users/me\")\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == \"Basic\"\n\n\ndef test_security_http_basic_invalid_credentials(client: TestClient):\n    response = client.get(\n        \"/users/me\", headers={\"Authorization\": \"Basic notabase64token\"}\n    )\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == \"Basic\"\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_security_http_basic_non_basic_credentials(client: TestClient):\n    payload = b64encode(b\"johnsecret\").decode(\"ascii\")\n    auth_header = f\"Basic {payload}\"\n    response = client.get(\"/users/me\", headers={\"Authorization\": auth_header})\n    assert response.status_code == 401, response.text\n    assert response.headers[\"WWW-Authenticate\"] == \"Basic\"\n    assert response.json() == {\"detail\": \"Not authenticated\"}\n\n\ndef test_security_http_basic_invalid_username(client: TestClient):\n    response = client.get(\"/users/me\", auth=(\"alice\", \"swordfish\"))\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Incorrect username or password\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Basic\"\n\n\ndef test_security_http_basic_invalid_password(client: TestClient):\n    response = client.get(\"/users/me\", auth=(\"stanleyjobson\", \"wrongpassword\"))\n    assert response.status_code == 401, response.text\n    assert response.json() == {\"detail\": \"Incorrect username or password\"}\n    assert response.headers[\"WWW-Authenticate\"] == \"Basic\"\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/users/me\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Current User\",\n                        \"operationId\": \"read_current_user_users_me_get\",\n                        \"security\": [{\"HTTPBasic\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"securitySchemes\": {\"HTTPBasic\": {\"type\": \"http\", \"scheme\": \"basic\"}}\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_separate_openapi_schemas/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest) -> TestClient:\n    mod = importlib.import_module(f\"docs_src.separate_openapi_schemas.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_create_item(client: TestClient) -> None:\n    response = client.post(\"/items/\", json={\"name\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\", \"description\": None}\n\n\ndef test_read_items(client: TestClient) -> None:\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\n            \"name\": \"Portal Gun\",\n            \"description\": \"Device to travel through the multi-rick-verse\",\n        },\n        {\"name\": \"Plumbus\", \"description\": None},\n    ]\n\n\ndef test_openapi_schema(client: TestClient) -> None:\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                            \"type\": \"array\",\n                                            \"title\": \"Response Read Items Items  Get\",\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\"],\n                        \"title\": \"Item\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest) -> TestClient:\n    mod = importlib.import_module(f\"docs_src.separate_openapi_schemas.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_create_item(client: TestClient) -> None:\n    response = client.post(\"/items/\", json={\"name\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\", \"description\": None}\n\n\ndef test_read_items(client: TestClient) -> None:\n    response = client.get(\"/items/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == [\n        {\n            \"name\": \"Portal Gun\",\n            \"description\": \"Device to travel through the multi-rick-verse\",\n        },\n        {\"name\": \"Plumbus\", \"description\": None},\n    ]\n\n\ndef test_openapi_schema(client: TestClient) -> None:\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"get\": {\n                        \"summary\": \"Read Items\",\n                        \"operationId\": \"read_items_items__get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Item\"\n                                            },\n                                            \"type\": \"array\",\n                                            \"title\": \"Response Read Items Items  Get\",\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    },\n                    \"post\": {\n                        \"summary\": \"Create Item\",\n                        \"operationId\": \"create_item_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Item\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"description\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Description\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\"],\n                        \"title\": \"Item\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_server_sent_events/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_server_sent_events/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.server_sent_events.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/items/stream\",\n        \"/items/stream-no-async\",\n        \"/items/stream-no-annotation\",\n        \"/items/stream-no-async-no-annotation\",\n    ],\n)\ndef test_stream_items(client: TestClient, path: str):\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"text/event-stream; charset=utf-8\"\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 3\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/stream\": {\n                    \"get\": {\n                        \"summary\": \"Sse Items\",\n                        \"operationId\": \"sse_items_items_stream_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"text/event-stream\": {\n                                        \"itemSchema\": {\n                                            \"type\": \"object\",\n                                            \"properties\": {\n                                                \"data\": {\n                                                    \"type\": \"string\",\n                                                    \"contentMediaType\": \"application/json\",\n                                                    \"contentSchema\": {\n                                                        \"$ref\": \"#/components/schemas/Item\"\n                                                    },\n                                                },\n                                                \"event\": {\"type\": \"string\"},\n                                                \"id\": {\"type\": \"string\"},\n                                                \"retry\": {\n                                                    \"type\": \"integer\",\n                                                    \"minimum\": 0,\n                                                },\n                                            },\n                                            \"required\": [\"data\"],\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/items/stream-no-async\": {\n                    \"get\": {\n                        \"summary\": \"Sse Items No Async\",\n                        \"operationId\": \"sse_items_no_async_items_stream_no_async_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"text/event-stream\": {\n                                        \"itemSchema\": {\n                                            \"type\": \"object\",\n                                            \"properties\": {\n                                                \"data\": {\n                                                    \"type\": \"string\",\n                                                    \"contentMediaType\": \"application/json\",\n                                                    \"contentSchema\": {\n                                                        \"$ref\": \"#/components/schemas/Item\"\n                                                    },\n                                                },\n                                                \"event\": {\"type\": \"string\"},\n                                                \"id\": {\"type\": \"string\"},\n                                                \"retry\": {\n                                                    \"type\": \"integer\",\n                                                    \"minimum\": 0,\n                                                },\n                                            },\n                                            \"required\": [\"data\"],\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/items/stream-no-annotation\": {\n                    \"get\": {\n                        \"summary\": \"Sse Items No Annotation\",\n                        \"operationId\": \"sse_items_no_annotation_items_stream_no_annotation_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"text/event-stream\": {\n                                        \"itemSchema\": {\n                                            \"type\": \"object\",\n                                            \"properties\": {\n                                                \"data\": {\"type\": \"string\"},\n                                                \"event\": {\"type\": \"string\"},\n                                                \"id\": {\"type\": \"string\"},\n                                                \"retry\": {\n                                                    \"type\": \"integer\",\n                                                    \"minimum\": 0,\n                                                },\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/items/stream-no-async-no-annotation\": {\n                    \"get\": {\n                        \"summary\": \"Sse Items No Async No Annotation\",\n                        \"operationId\": \"sse_items_no_async_no_annotation_items_stream_no_async_no_annotation_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"text/event-stream\": {\n                                        \"itemSchema\": {\n                                            \"type\": \"object\",\n                                            \"properties\": {\n                                                \"data\": {\"type\": \"string\"},\n                                                \"event\": {\"type\": \"string\"},\n                                                \"id\": {\"type\": \"string\"},\n                                                \"retry\": {\n                                                    \"type\": \"integer\",\n                                                    \"minimum\": 0,\n                                                },\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"description\": {\n                                \"anyOf\": [\n                                    {\"type\": \"string\"},\n                                    {\"type\": \"null\"},\n                                ],\n                                \"title\": \"Description\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"description\"],\n                        \"title\": \"Item\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_server_sent_events/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.server_sent_events.{request.param}\")\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_stream_items(client: TestClient):\n    response = client.get(\"/items/stream\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"text/event-stream; charset=utf-8\"\n\n    lines = response.text.strip().split(\"\\n\")\n\n    # First event is a comment-only event\n    assert lines[0] == \": stream of item updates\"\n\n    # Remaining lines contain event:, data:, id:, retry: fields\n    event_lines = [line for line in lines if line.startswith(\"event: \")]\n    assert len(event_lines) == 3\n    assert all(line == \"event: item_update\" for line in event_lines)\n\n    data_lines = [line for line in lines if line.startswith(\"data: \")]\n    assert len(data_lines) == 3\n\n    id_lines = [line for line in lines if line.startswith(\"id: \")]\n    assert id_lines == [\"id: 1\", \"id: 2\", \"id: 3\"]\n\n    retry_lines = [line for line in lines if line.startswith(\"retry: \")]\n    assert len(retry_lines) == 3\n    assert all(line == \"retry: 5000\" for line in retry_lines)\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/stream\": {\n                    \"get\": {\n                        \"summary\": \"Stream Items\",\n                        \"operationId\": \"stream_items_items_stream_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"text/event-stream\": {\n                                        \"itemSchema\": {\n                                            \"type\": \"object\",\n                                            \"properties\": {\n                                                \"data\": {\"type\": \"string\"},\n                                                \"event\": {\"type\": \"string\"},\n                                                \"id\": {\"type\": \"string\"},\n                                                \"retry\": {\n                                                    \"type\": \"integer\",\n                                                    \"minimum\": 0,\n                                                },\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_server_sent_events/test_tutorial003.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial003_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.server_sent_events.{request.param}\")\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_stream_logs(client: TestClient):\n    response = client.get(\"/logs/stream\")\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"text/event-stream; charset=utf-8\"\n\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 3\n\n    # raw_data is sent without JSON encoding (no quotes around the string)\n    assert data_lines[0] == \"data: 2025-01-01 INFO  Application started\"\n    assert data_lines[1] == \"data: 2025-01-01 DEBUG Connected to database\"\n    assert data_lines[2] == \"data: 2025-01-01 WARN  High memory usage detected\"\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/logs/stream\": {\n                    \"get\": {\n                        \"summary\": \"Stream Logs\",\n                        \"operationId\": \"stream_logs_logs_stream_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"text/event-stream\": {\n                                        \"itemSchema\": {\n                                            \"type\": \"object\",\n                                            \"properties\": {\n                                                \"data\": {\"type\": \"string\"},\n                                                \"event\": {\"type\": \"string\"},\n                                                \"id\": {\"type\": \"string\"},\n                                                \"retry\": {\n                                                    \"type\": \"integer\",\n                                                    \"minimum\": 0,\n                                                },\n                                            },\n                                        }\n                                    }\n                                },\n                            }\n                        },\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_server_sent_events/test_tutorial004.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial004_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.server_sent_events.{request.param}\")\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_stream_all_items(client: TestClient):\n    response = client.get(\"/items/stream\")\n    assert response.status_code == 200, response.text\n\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 3\n\n    id_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"id: \")\n    ]\n    assert id_lines == [\"id: 0\", \"id: 1\", \"id: 2\"]\n\n\ndef test_resume_from_last_event_id(client: TestClient):\n    response = client.get(\n        \"/items/stream\",\n        headers={\"last-event-id\": \"0\"},\n    )\n    assert response.status_code == 200, response.text\n\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 2\n\n    id_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"id: \")\n    ]\n    assert id_lines == [\"id: 1\", \"id: 2\"]\n\n\ndef test_resume_from_last_item(client: TestClient):\n    response = client.get(\n        \"/items/stream\",\n        headers={\"last-event-id\": \"1\"},\n    )\n    assert response.status_code == 200, response.text\n\n    data_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"data: \")\n    ]\n    assert len(data_lines) == 1\n\n    id_lines = [\n        line for line in response.text.strip().split(\"\\n\") if line.startswith(\"id: \")\n    ]\n    assert id_lines == [\"id: 2\"]\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/stream\": {\n                    \"get\": {\n                        \"summary\": \"Stream Items\",\n                        \"operationId\": \"stream_items_items_stream_get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"last-event-id\",\n                                \"in\": \"header\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                    \"title\": \"Last-Event-Id\",\n                                },\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"text/event-stream\": {\n                                        \"itemSchema\": {\n                                            \"type\": \"object\",\n                                            \"properties\": {\n                                                \"data\": {\"type\": \"string\"},\n                                                \"event\": {\"type\": \"string\"},\n                                                \"id\": {\"type\": \"string\"},\n                                                \"retry\": {\n                                                    \"type\": \"integer\",\n                                                    \"minimum\": 0,\n                                                },\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"type\": \"object\", \"title\": \"Context\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_server_sent_events/test_tutorial005.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial005_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.server_sent_events.{request.param}\")\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_stream_chat(client: TestClient):\n    response = client.post(\n        \"/chat/stream\",\n        json={\"text\": \"hello world\"},\n    )\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"text/event-stream; charset=utf-8\"\n\n    lines = response.text.strip().split(\"\\n\")\n\n    event_lines = [line for line in lines if line.startswith(\"event: \")]\n    assert event_lines == [\n        \"event: token\",\n        \"event: token\",\n        \"event: done\",\n    ]\n\n    data_lines = [line for line in lines if line.startswith(\"data: \")]\n    assert data_lines == [\n        'data: \"hello\"',\n        'data: \"world\"',\n        \"data: [DONE]\",\n    ]\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/chat/stream\": {\n                    \"post\": {\n                        \"summary\": \"Stream Chat\",\n                        \"operationId\": \"stream_chat_chat_stream_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Prompt\"}\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"text/event-stream\": {\n                                        \"itemSchema\": {\n                                            \"type\": \"object\",\n                                            \"properties\": {\n                                                \"data\": {\"type\": \"string\"},\n                                                \"event\": {\"type\": \"string\"},\n                                                \"id\": {\"type\": \"string\"},\n                                                \"retry\": {\n                                                    \"type\": \"integer\",\n                                                    \"minimum\": 0,\n                                                },\n                                            },\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Prompt\": {\n                        \"properties\": {\"text\": {\"type\": \"string\", \"title\": \"Text\"}},\n                        \"type\": \"object\",\n                        \"required\": [\"text\"],\n                        \"title\": \"Prompt\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"type\": \"object\", \"title\": \"Context\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_settings/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_settings/test_app01.py",
    "content": "import importlib\nimport sys\n\nimport pytest\nfrom dirty_equals import IsAnyStr\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import ValidationError\nfrom pytest import MonkeyPatch\n\n\n@pytest.fixture(\n    name=\"mod_name\",\n    params=[\n        pytest.param(\"app01_py310\"),\n    ],\n)\ndef get_mod_name(request: pytest.FixtureRequest):\n    return f\"docs_src.settings.{request.param}.main\"\n\n\n@pytest.fixture(name=\"client\")\ndef get_test_client(mod_name: str, monkeypatch: MonkeyPatch) -> TestClient:\n    if mod_name in sys.modules:\n        del sys.modules[mod_name]  # pragma: no cover\n    monkeypatch.setenv(\"ADMIN_EMAIL\", \"admin@example.com\")\n    main_mod = importlib.import_module(mod_name)\n    return TestClient(main_mod.app)\n\n\ndef test_settings_validation_error(mod_name: str, monkeypatch: MonkeyPatch):\n    monkeypatch.delenv(\"ADMIN_EMAIL\", raising=False)\n    if mod_name in sys.modules:\n        del sys.modules[mod_name]  # pragma: no cover\n\n    with pytest.raises(ValidationError) as exc_info:\n        importlib.import_module(mod_name)\n    assert exc_info.value.errors() == [\n        {\n            \"loc\": (\"admin_email\",),\n            \"msg\": \"Field required\",\n            \"type\": \"missing\",\n            \"input\": {},\n            \"url\": IsAnyStr,\n        }\n    ]\n\n\ndef test_app(client: TestClient):\n    response = client.get(\"/info\")\n    data = response.json()\n    assert data == {\n        \"app_name\": \"Awesome API\",\n        \"admin_email\": \"admin@example.com\",\n        \"items_per_user\": 50,\n    }\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/info\": {\n                    \"get\": {\n                        \"operationId\": \"info_info_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Info\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_settings/test_app02.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom pytest import MonkeyPatch\n\n\n@pytest.fixture(\n    name=\"mod_path\",\n    params=[\n        pytest.param(\"app02_py310\"),\n        pytest.param(\"app02_an_py310\"),\n    ],\n)\ndef get_mod_path(request: pytest.FixtureRequest):\n    mod_path = f\"docs_src.settings.{request.param}\"\n    return mod_path\n\n\n@pytest.fixture(name=\"main_mod\")\ndef get_main_mod(mod_path: str) -> ModuleType:\n    main_mod = importlib.import_module(f\"{mod_path}.main\")\n    return main_mod\n\n\n@pytest.fixture(name=\"test_main_mod\")\ndef get_test_main_mod(mod_path: str) -> ModuleType:\n    test_main_mod = importlib.import_module(f\"{mod_path}.test_main\")\n    return test_main_mod\n\n\ndef test_settings(main_mod: ModuleType, monkeypatch: MonkeyPatch):\n    monkeypatch.setenv(\"ADMIN_EMAIL\", \"admin@example.com\")\n    settings = main_mod.get_settings()\n    assert settings.app_name == \"Awesome API\"\n    assert settings.items_per_user == 50\n\n\ndef test_override_settings(test_main_mod: ModuleType):\n    test_main_mod.test_app()\n"
  },
  {
    "path": "tests/test_tutorial/test_settings/test_app03.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom pytest import MonkeyPatch\n\n\n@pytest.fixture(\n    name=\"mod_path\",\n    params=[\n        pytest.param(\"app03_py310\"),\n        pytest.param(\"app03_an_py310\"),\n    ],\n)\ndef get_mod_path(request: pytest.FixtureRequest):\n    mod_path = f\"docs_src.settings.{request.param}\"\n    return mod_path\n\n\n@pytest.fixture(name=\"main_mod\")\ndef get_main_mod(mod_path: str) -> ModuleType:\n    main_mod = importlib.import_module(f\"{mod_path}.main\")\n    return main_mod\n\n\ndef test_settings(main_mod: ModuleType, monkeypatch: MonkeyPatch):\n    monkeypatch.setenv(\"ADMIN_EMAIL\", \"admin@example.com\")\n    settings = main_mod.get_settings()\n    assert settings.app_name == \"Awesome API\"\n    assert settings.admin_email == \"admin@example.com\"\n    assert settings.items_per_user == 50\n\n\ndef test_endpoint(main_mod: ModuleType, monkeypatch: MonkeyPatch):\n    monkeypatch.setenv(\"ADMIN_EMAIL\", \"admin@example.com\")\n    client = TestClient(main_mod.app)\n    response = client.get(\"/info\")\n    assert response.status_code == 200\n    assert response.json() == {\n        \"app_name\": \"Awesome API\",\n        \"admin_email\": \"admin@example.com\",\n        \"items_per_user\": 50,\n    }\n"
  },
  {
    "path": "tests/test_tutorial/test_settings/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom pytest import MonkeyPatch\n\n\n@pytest.fixture(name=\"app\", params=[pytest.param(\"tutorial001_py310\")])\ndef get_app(request: pytest.FixtureRequest, monkeypatch: MonkeyPatch):\n    monkeypatch.setenv(\"ADMIN_EMAIL\", \"admin@example.com\")\n    mod = importlib.import_module(f\"docs_src.settings.{request.param}\")\n    return mod.app\n\n\ndef test_settings(app):\n    client = TestClient(app)\n    response = client.get(\"/info\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"app_name\": \"Awesome API\",\n        \"admin_email\": \"admin@example.com\",\n        \"items_per_user\": 50,\n    }\n"
  },
  {
    "path": "tests/test_tutorial/test_sql_databases/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_sql_databases/test_tutorial001.py",
    "content": "import importlib\nimport warnings\n\nimport pytest\nfrom dirty_equals import IsInt\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom sqlalchemy import StaticPool\nfrom sqlmodel import SQLModel, create_engine\nfrom sqlmodel.main import default_registry\n\nfrom tests.utils import needs_py310\n\n\ndef clear_sqlmodel():\n    # Clear the tables in the metadata for the default base model\n    SQLModel.metadata.clear()\n    # Clear the Models associated with the registry, to avoid warnings\n    default_registry.dispose()\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    clear_sqlmodel()\n    # TODO: remove when updating SQL tutorial to use new lifespan API\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        mod = importlib.import_module(f\"docs_src.sql_databases.{request.param}\")\n        clear_sqlmodel()\n        importlib.reload(mod)\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args={\"check_same_thread\": False}, poolclass=StaticPool\n    )\n\n    with TestClient(mod.app) as c:\n        yield c\n    # Clean up connection explicitly to avoid resource warning\n    mod.engine.dispose()\n\n\ndef test_crud_app(client: TestClient):\n    # TODO: this warns that SQLModel.from_orm is deprecated in Pydantic v1, refactor\n    # this if using obj.model_validate becomes independent of Pydantic v2\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        # No heroes before creating\n        response = client.get(\"heroes/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == []\n\n        # Create a hero\n        response = client.post(\n            \"/heroes/\",\n            json={\n                \"id\": 999,\n                \"name\": \"Dead Pond\",\n                \"age\": 30,\n                \"secret_name\": \"Dive Wilson\",\n            },\n        )\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            {\"age\": 30, \"secret_name\": \"Dive Wilson\", \"id\": 999, \"name\": \"Dead Pond\"}\n        )\n\n        # Read a hero\n        hero_id = response.json()[\"id\"]\n        response = client.get(f\"/heroes/{hero_id}\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            {\"name\": \"Dead Pond\", \"age\": 30, \"id\": 999, \"secret_name\": \"Dive Wilson\"}\n        )\n\n        # Read all heroes\n        # Create more heroes first\n        response = client.post(\n            \"/heroes/\",\n            json={\"name\": \"Spider-Boy\", \"age\": 18, \"secret_name\": \"Pedro Parqueador\"},\n        )\n        assert response.status_code == 200, response.text\n        response = client.post(\n            \"/heroes/\", json={\"name\": \"Rusty-Man\", \"secret_name\": \"Tommy Sharp\"}\n        )\n        assert response.status_code == 200, response.text\n\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            [\n                {\n                    \"name\": \"Dead Pond\",\n                    \"age\": 30,\n                    \"id\": IsInt(),\n                    \"secret_name\": \"Dive Wilson\",\n                },\n                {\n                    \"name\": \"Spider-Boy\",\n                    \"age\": 18,\n                    \"id\": IsInt(),\n                    \"secret_name\": \"Pedro Parqueador\",\n                },\n                {\n                    \"name\": \"Rusty-Man\",\n                    \"age\": None,\n                    \"id\": IsInt(),\n                    \"secret_name\": \"Tommy Sharp\",\n                },\n            ]\n        )\n\n        response = client.get(\"/heroes/?offset=1&limit=1\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            [\n                {\n                    \"name\": \"Spider-Boy\",\n                    \"age\": 18,\n                    \"id\": IsInt(),\n                    \"secret_name\": \"Pedro Parqueador\",\n                }\n            ]\n        )\n\n        # Delete a hero\n        response = client.delete(f\"/heroes/{hero_id}\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot({\"ok\": True})\n\n        response = client.get(f\"/heroes/{hero_id}\")\n        assert response.status_code == 404, response.text\n\n        response = client.delete(f\"/heroes/{hero_id}\")\n        assert response.status_code == 404, response.text\n        assert response.json() == snapshot({\"detail\": \"Hero not found\"})\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"required\": True,\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\"$ref\": \"#/components/schemas/Hero\"}\n                                }\n                            },\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Hero\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                    \"title\": \"Offset\",\n                                },\n                            },\n                            {\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"integer\",\n                                    \"maximum\": 100,\n                                    \"default\": 100,\n                                    \"title\": \"Limit\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/Hero\"\n                                            },\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/heroes/{hero_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Hero\",\n                        \"operationId\": \"read_hero_heroes__hero_id__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"integer\", \"title\": \"Hero Id\"},\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\"$ref\": \"#/components/schemas/Hero\"}\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"delete\": {\n                        \"summary\": \"Delete Hero\",\n                        \"operationId\": \"delete_hero_heroes__hero_id__delete\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"integer\", \"title\": \"Hero Id\"},\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Hero\": {\n                        \"properties\": {\n                            \"id\": {\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                \"title\": \"Id\",\n                            },\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"age\": {\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                \"title\": \"Age\",\n                            },\n                            \"secret_name\": {\"type\": \"string\", \"title\": \"Secret Name\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"title\": \"Hero\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_sql_databases/test_tutorial002.py",
    "content": "import importlib\nimport warnings\n\nimport pytest\nfrom dirty_equals import IsInt\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import Is, snapshot\nfrom sqlalchemy import StaticPool\nfrom sqlmodel import SQLModel, create_engine\nfrom sqlmodel.main import default_registry\n\nfrom tests.utils import needs_py310\n\n\ndef clear_sqlmodel():\n    # Clear the tables in the metadata for the default base model\n    SQLModel.metadata.clear()\n    # Clear the Models associated with the registry, to avoid warnings\n    default_registry.dispose()\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    clear_sqlmodel()\n    # TODO: remove when updating SQL tutorial to use new lifespan API\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        mod = importlib.import_module(f\"docs_src.sql_databases.{request.param}\")\n        clear_sqlmodel()\n        importlib.reload(mod)\n    mod.sqlite_url = \"sqlite://\"\n    mod.engine = create_engine(\n        mod.sqlite_url, connect_args={\"check_same_thread\": False}, poolclass=StaticPool\n    )\n\n    with TestClient(mod.app) as c:\n        yield c\n    # Clean up connection explicitly to avoid resource warning\n    mod.engine.dispose()\n\n\ndef test_crud_app(client: TestClient):\n    # TODO: this warns that SQLModel.from_orm is deprecated in Pydantic v1, refactor\n    # this if using obj.model_validate becomes independent of Pydantic v2\n    with warnings.catch_warnings(record=True):\n        warnings.simplefilter(\"always\")\n        # No heroes before creating\n        response = client.get(\"heroes/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == []\n\n        # Create a hero\n        response = client.post(\n            \"/heroes/\",\n            json={\n                \"id\": 9000,\n                \"name\": \"Dead Pond\",\n                \"age\": 30,\n                \"secret_name\": \"Dive Wilson\",\n            },\n        )\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            {\"age\": 30, \"id\": IsInt(), \"name\": \"Dead Pond\"}\n        )\n        assert response.json()[\"id\"] != 9000, (\n            \"The ID should be generated by the database\"\n        )\n\n        # Read a hero\n        hero_id = response.json()[\"id\"]\n        response = client.get(f\"/heroes/{hero_id}\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            {\"name\": \"Dead Pond\", \"age\": 30, \"id\": IsInt()}\n        )\n\n        # Read all heroes\n        # Create more heroes first\n        response = client.post(\n            \"/heroes/\",\n            json={\"name\": \"Spider-Boy\", \"age\": 18, \"secret_name\": \"Pedro Parqueador\"},\n        )\n        assert response.status_code == 200, response.text\n        response = client.post(\n            \"/heroes/\", json={\"name\": \"Rusty-Man\", \"secret_name\": \"Tommy Sharp\"}\n        )\n        assert response.status_code == 200, response.text\n\n        response = client.get(\"/heroes/\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            [\n                {\"name\": \"Dead Pond\", \"age\": 30, \"id\": IsInt()},\n                {\"name\": \"Spider-Boy\", \"age\": 18, \"id\": IsInt()},\n                {\"name\": \"Rusty-Man\", \"age\": None, \"id\": IsInt()},\n            ]\n        )\n\n        response = client.get(\"/heroes/?offset=1&limit=1\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            [{\"name\": \"Spider-Boy\", \"age\": 18, \"id\": IsInt()}]\n        )\n\n        # Update a hero\n        response = client.patch(\n            f\"/heroes/{hero_id}\", json={\"name\": \"Dog Pond\", \"age\": None}\n        )\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            {\"name\": \"Dog Pond\", \"age\": None, \"id\": Is(hero_id)}\n        )\n\n        # Get updated hero\n        response = client.get(f\"/heroes/{hero_id}\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot(\n            {\"name\": \"Dog Pond\", \"age\": None, \"id\": Is(hero_id)}\n        )\n\n        # Delete a hero\n        response = client.delete(f\"/heroes/{hero_id}\")\n        assert response.status_code == 200, response.text\n        assert response.json() == snapshot({\"ok\": True})\n\n        # The hero is no longer found\n        response = client.get(f\"/heroes/{hero_id}\")\n        assert response.status_code == 404, response.text\n\n        # Delete a hero that does not exist\n        response = client.delete(f\"/heroes/{hero_id}\")\n        assert response.status_code == 404, response.text\n        assert response.json() == snapshot({\"detail\": \"Hero not found\"})\n\n        # Update a hero that does not exist\n        response = client.patch(f\"/heroes/{hero_id}\", json={\"name\": \"Dog Pond\"})\n        assert response.status_code == 404, response.text\n        assert response.json() == snapshot({\"detail\": \"Hero not found\"})\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/heroes/\": {\n                    \"post\": {\n                        \"summary\": \"Create Hero\",\n                        \"operationId\": \"create_hero_heroes__post\",\n                        \"requestBody\": {\n                            \"required\": True,\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroCreate\"\n                                    }\n                                }\n                            },\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"get\": {\n                        \"summary\": \"Read Heroes\",\n                        \"operationId\": \"read_heroes_heroes__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"offset\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"integer\",\n                                    \"default\": 0,\n                                    \"title\": \"Offset\",\n                                },\n                            },\n                            {\n                                \"name\": \"limit\",\n                                \"in\": \"query\",\n                                \"required\": False,\n                                \"schema\": {\n                                    \"type\": \"integer\",\n                                    \"maximum\": 100,\n                                    \"default\": 100,\n                                    \"title\": \"Limit\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"type\": \"array\",\n                                            \"items\": {\n                                                \"$ref\": \"#/components/schemas/HeroPublic\"\n                                            },\n                                            \"title\": \"Response Read Heroes Heroes  Get\",\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n                \"/heroes/{hero_id}\": {\n                    \"get\": {\n                        \"summary\": \"Read Hero\",\n                        \"operationId\": \"read_hero_heroes__hero_id__get\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"integer\", \"title\": \"Hero Id\"},\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"patch\": {\n                        \"summary\": \"Update Hero\",\n                        \"operationId\": \"update_hero_heroes__hero_id__patch\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"integer\", \"title\": \"Hero Id\"},\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"required\": True,\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/HeroUpdate\"\n                                    }\n                                }\n                            },\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HeroPublic\"\n                                        }\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                    \"delete\": {\n                        \"summary\": \"Delete Hero\",\n                        \"operationId\": \"delete_hero_heroes__hero_id__delete\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"hero_id\",\n                                \"in\": \"path\",\n                                \"required\": True,\n                                \"schema\": {\"type\": \"integer\", \"title\": \"Hero Id\"},\n                            }\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"HeroCreate\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"age\": {\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                \"title\": \"Age\",\n                            },\n                            \"secret_name\": {\"type\": \"string\", \"title\": \"Secret Name\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"secret_name\"],\n                        \"title\": \"HeroCreate\",\n                    },\n                    \"HeroPublic\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"age\": {\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                \"title\": \"Age\",\n                            },\n                            \"id\": {\"type\": \"integer\", \"title\": \"Id\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"id\"],\n                        \"title\": \"HeroPublic\",\n                    },\n                    \"HeroUpdate\": {\n                        \"properties\": {\n                            \"name\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Name\",\n                            },\n                            \"age\": {\n                                \"anyOf\": [{\"type\": \"integer\"}, {\"type\": \"null\"}],\n                                \"title\": \"Age\",\n                            },\n                            \"secret_name\": {\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                                \"title\": \"Secret Name\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HeroUpdate\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_static_files/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_static_files/test_tutorial001.py",
    "content": "import os\nfrom pathlib import Path\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom tests.utils import workdir_lock\n\n\n@pytest.fixture(scope=\"module\")\ndef client():\n    static_dir: Path = Path(os.getcwd()) / \"static\"\n    static_dir.mkdir(exist_ok=True)\n    sample_file = static_dir / \"sample.txt\"\n    sample_file.write_text(\"This is a sample static file.\")\n    from docs_src.static_files.tutorial001_py310 import app\n\n    with TestClient(app) as client:\n        yield client\n    sample_file.unlink()\n    static_dir.rmdir()\n\n\n@workdir_lock\ndef test_static_files(client: TestClient):\n    response = client.get(\"/static/sample.txt\")\n    assert response.status_code == 200, response.text\n    assert response.text == \"This is a sample static file.\"\n\n\n@workdir_lock\ndef test_static_files_not_found(client: TestClient):\n    response = client.get(\"/static/non_existent_file.txt\")\n    assert response.status_code == 404, response.text\n\n\n@workdir_lock\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {},\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_stream_data/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_stream_data/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.stream_data.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\nexpected_text = (\n    \"\"\n    \"Rick: (stumbles in drunkenly, and turns on the lights)\"\n    \" Morty! You gotta come on. You got--... you gotta come with me.\"\n    \"Morty: (rubs his eyes) What, Rick? What's going on?\"\n    \"Rick: I got a surprise for you, Morty.\"\n    \"Morty: It's the middle of the night. What are you talking about?\"\n    \"Rick: (spills alcohol on Morty's bed) Come on, I got a surprise for you.\"\n    \" (drags Morty by the ankle) Come on, hurry up.\"\n    \" (pulls Morty out of his bed and into the hall)\"\n    \"Morty: Ow! Ow! You're tugging me too hard!\"\n    \"Rick: We gotta go, gotta get outta here, come on.\"\n    \" Got a surprise for you Morty.\"\n)\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/story/stream\",\n        \"/story/stream-no-async\",\n        \"/story/stream-no-annotation\",\n        \"/story/stream-no-async-no-annotation\",\n        \"/story/stream-bytes\",\n        \"/story/stream-no-async-bytes\",\n        \"/story/stream-no-annotation-bytes\",\n        \"/story/stream-no-async-no-annotation-bytes\",\n    ],\n)\ndef test_stream_story(client: TestClient, path: str):\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.text == expected_text\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/story/stream\": {\n                    \"get\": {\n                        \"summary\": \"Stream Story\",\n                        \"operationId\": \"stream_story_story_stream_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                    }\n                },\n                \"/story/stream-no-async\": {\n                    \"get\": {\n                        \"summary\": \"Stream Story No Async\",\n                        \"operationId\": \"stream_story_no_async_story_stream_no_async_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                    }\n                },\n                \"/story/stream-no-annotation\": {\n                    \"get\": {\n                        \"summary\": \"Stream Story No Annotation\",\n                        \"operationId\": \"stream_story_no_annotation_story_stream_no_annotation_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                    }\n                },\n                \"/story/stream-no-async-no-annotation\": {\n                    \"get\": {\n                        \"summary\": \"Stream Story No Async No Annotation\",\n                        \"operationId\": \"stream_story_no_async_no_annotation_story_stream_no_async_no_annotation_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                    }\n                },\n                \"/story/stream-bytes\": {\n                    \"get\": {\n                        \"summary\": \"Stream Story Bytes\",\n                        \"operationId\": \"stream_story_bytes_story_stream_bytes_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                    }\n                },\n                \"/story/stream-no-async-bytes\": {\n                    \"get\": {\n                        \"summary\": \"Stream Story No Async Bytes\",\n                        \"operationId\": \"stream_story_no_async_bytes_story_stream_no_async_bytes_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                    }\n                },\n                \"/story/stream-no-annotation-bytes\": {\n                    \"get\": {\n                        \"summary\": \"Stream Story No Annotation Bytes\",\n                        \"operationId\": \"stream_story_no_annotation_bytes_story_stream_no_annotation_bytes_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                    }\n                },\n                \"/story/stream-no-async-no-annotation-bytes\": {\n                    \"get\": {\n                        \"summary\": \"Stream Story No Async No Annotation Bytes\",\n                        \"operationId\": \"stream_story_no_async_no_annotation_bytes_story_stream_no_async_no_annotation_bytes_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                            }\n                        },\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_stream_data/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial002_py310\"),\n    ],\n)\ndef get_mod(request: pytest.FixtureRequest):\n    return importlib.import_module(f\"docs_src.stream_data.{request.param}\")\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(mod):\n    client = TestClient(mod.app)\n    return client\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/image/stream\",\n        \"/image/stream-no-async\",\n        \"/image/stream-no-async-yield-from\",\n        \"/image/stream-no-annotation\",\n        \"/image/stream-no-async-no-annotation\",\n    ],\n)\ndef test_stream_image(mod, client: TestClient, path: str):\n    response = client.get(path)\n    assert response.status_code == 200\n    assert response.headers[\"content-type\"] == \"image/png\"\n    assert response.content == mod.binary_image\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/image/stream\": {\n                    \"get\": {\n                        \"summary\": \"Stream Image\",\n                        \"operationId\": \"stream_image_image_stream_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"image/png\": {\"schema\": {\"type\": \"string\"}}\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/image/stream-no-async\": {\n                    \"get\": {\n                        \"summary\": \"Stream Image No Async\",\n                        \"operationId\": \"stream_image_no_async_image_stream_no_async_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"image/png\": {\"schema\": {\"type\": \"string\"}}\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/image/stream-no-async-yield-from\": {\n                    \"get\": {\n                        \"summary\": \"Stream Image No Async Yield From\",\n                        \"operationId\": \"stream_image_no_async_yield_from_image_stream_no_async_yield_from_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"image/png\": {\"schema\": {\"type\": \"string\"}}\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/image/stream-no-annotation\": {\n                    \"get\": {\n                        \"summary\": \"Stream Image No Annotation\",\n                        \"operationId\": \"stream_image_no_annotation_image_stream_no_annotation_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"image/png\": {\"schema\": {\"type\": \"string\"}}\n                                },\n                            }\n                        },\n                    }\n                },\n                \"/image/stream-no-async-no-annotation\": {\n                    \"get\": {\n                        \"summary\": \"Stream Image No Async No Annotation\",\n                        \"operationId\": \"stream_image_no_async_no_annotation_image_stream_no_async_no_annotation_get\",\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"image/png\": {\"schema\": {\"type\": \"string\"}}\n                                },\n                            }\n                        },\n                    }\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_stream_json_lines/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_stream_json_lines/test_tutorial001.py",
    "content": "import importlib\nimport json\n\nimport pytest\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        pytest.param(\"tutorial001_py310\"),\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.stream_json_lines.{request.param}\")\n\n    client = TestClient(mod.app)\n    return client\n\n\nexpected_items = [\n    {\"name\": \"Plumbus\", \"description\": \"A multi-purpose household device.\"},\n    {\"name\": \"Portal Gun\", \"description\": \"A portal opening device.\"},\n    {\"name\": \"Meeseeks Box\", \"description\": \"A box that summons a Meeseeks.\"},\n]\n\n\n@pytest.mark.parametrize(\n    \"path\",\n    [\n        \"/items/stream\",\n        \"/items/stream-no-async\",\n        \"/items/stream-no-annotation\",\n        \"/items/stream-no-async-no-annotation\",\n    ],\n)\ndef test_stream_items(client: TestClient, path: str):\n    response = client.get(path)\n    assert response.status_code == 200, response.text\n    assert response.headers[\"content-type\"] == \"application/jsonl\"\n    lines = [json.loads(line) for line in response.text.strip().splitlines()]\n    assert lines == expected_items\n\n\ndef test_openapi_schema(client: TestClient):\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/stream\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/jsonl\": {\n                                        \"itemSchema\": {\n                                            \"$ref\": \"#/components/schemas/Item\"\n                                        },\n                                    }\n                                },\n                            }\n                        },\n                        \"summary\": \"Stream Items\",\n                        \"operationId\": \"stream_items_items_stream_get\",\n                    }\n                },\n                \"/items/stream-no-async\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/jsonl\": {\n                                        \"itemSchema\": {\n                                            \"$ref\": \"#/components/schemas/Item\"\n                                        },\n                                    }\n                                },\n                            }\n                        },\n                        \"summary\": \"Stream Items No Async\",\n                        \"operationId\": \"stream_items_no_async_items_stream_no_async_get\",\n                    }\n                },\n                \"/items/stream-no-annotation\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/jsonl\": {\n                                        \"itemSchema\": {},\n                                    }\n                                },\n                            }\n                        },\n                        \"summary\": \"Stream Items No Annotation\",\n                        \"operationId\": \"stream_items_no_annotation_items_stream_no_annotation_get\",\n                    }\n                },\n                \"/items/stream-no-async-no-annotation\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/jsonl\": {\n                                        \"itemSchema\": {},\n                                    }\n                                },\n                            }\n                        },\n                        \"summary\": \"Stream Items No Async No Annotation\",\n                        \"operationId\": \"stream_items_no_async_no_annotation_items_stream_no_async_no_annotation_get\",\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"description\": {\n                                \"anyOf\": [\n                                    {\"type\": \"string\"},\n                                    {\"type\": \"null\"},\n                                ],\n                                \"title\": \"Description\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"description\"],\n                        \"title\": \"Item\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_strict_content_type/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_strict_content_type/test_tutorial001.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\n\n@pytest.fixture(\n    name=\"client\",\n    params=[\n        \"tutorial001_py310\",\n    ],\n)\ndef get_client(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.strict_content_type.{request.param}\")\n    client = TestClient(mod.app)\n    return client\n\n\ndef test_lax_post_without_content_type_is_parsed_as_json(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        content='{\"name\": \"Foo\", \"price\": 50.5}',\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\", \"price\": 50.5}\n\n\ndef test_lax_post_with_json_content_type(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        json={\"name\": \"Foo\", \"price\": 50.5},\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"name\": \"Foo\", \"price\": 50.5}\n\n\ndef test_lax_post_with_text_plain_is_still_rejected(client: TestClient):\n    response = client.post(\n        \"/items/\",\n        content='{\"name\": \"Foo\", \"price\": 50.5}',\n        headers={\"Content-Type\": \"text/plain\"},\n    )\n    assert response.status_code == 422, response.text\n"
  },
  {
    "path": "tests/test_tutorial/test_sub_applications/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_sub_applications/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.sub_applications.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_main():\n    response = client.get(\"/app\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello World from main app\"}\n\n\ndef test_sub():\n    response = client.get(\"/subapi/sub\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello World from sub API\"}\n\n\ndef test_openapi_schema_main():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/app\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Main\",\n                        \"operationId\": \"read_main_app_get\",\n                    }\n                }\n            },\n        }\n    )\n\n\ndef test_openapi_schema_sub():\n    response = client.get(\"/subapi/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/sub\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Sub\",\n                        \"operationId\": \"read_sub_sub_get\",\n                    }\n                }\n            },\n            \"servers\": [{\"url\": \"/subapi\"}],\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_templates/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_templates/test_tutorial001.py",
    "content": "import os\nimport shutil\n\nfrom fastapi.testclient import TestClient\n\nfrom tests.utils import workdir_lock\n\n\n@workdir_lock\ndef test_main():\n    if os.path.isdir(\"./static\"):  # pragma: nocover\n        shutil.rmtree(\"./static\")\n    if os.path.isdir(\"./templates\"):  # pragma: nocover\n        shutil.rmtree(\"./templates\")\n    shutil.copytree(\"./docs_src/templates/templates/\", \"./templates\")\n    shutil.copytree(\"./docs_src/templates/static/\", \"./static\")\n    from docs_src.templates.tutorial001_py310 import app\n\n    client = TestClient(app)\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 200, response.text\n    assert (\n        b'<h1><a href=\"http://testserver/items/foo\">Item ID: foo</a></h1>'\n        in response.content\n    )\n    response = client.get(\"/static/styles.css\")\n    assert response.status_code == 200, response.text\n    assert b\"color: green;\" in response.content\n    shutil.rmtree(\"./templates\")\n    shutil.rmtree(\"./static\")\n"
  },
  {
    "path": "tests/test_tutorial/test_testing/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_testing/test_main_a.py",
    "content": "from inline_snapshot import snapshot\n\nfrom docs_src.app_testing.app_a_py310.test_main import client, test_read_main\n\n\ndef test_main():\n    test_read_main()\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Main\",\n                        \"operationId\": \"read_main__get\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_testing/test_main_b.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"test_module\",\n    params=[\n        pytest.param(\"app_b_py310.test_main\", marks=needs_py310),\n        pytest.param(\"app_b_an_py310.test_main\", marks=needs_py310),\n    ],\n)\ndef get_test_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod: ModuleType = importlib.import_module(f\"docs_src.app_testing.{request.param}\")\n    return mod\n\n\ndef test_app(test_module: ModuleType):\n    test_main = test_module\n    test_main.test_create_existing_item()\n    test_main.test_create_item()\n    test_main.test_create_item_bad_token()\n    test_main.test_read_nonexistent_item()\n    test_main.test_read_item()\n    test_main.test_read_item_bad_token()\n"
  },
  {
    "path": "tests/test_tutorial/test_testing/test_tutorial001.py",
    "content": "from inline_snapshot import snapshot\n\nfrom docs_src.app_testing.tutorial001_py310 import client, test_read_main\n\n\ndef test_main():\n    test_read_main()\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/\": {\n                    \"get\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            }\n                        },\n                        \"summary\": \"Read Main\",\n                        \"operationId\": \"read_main__get\",\n                    }\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_testing/test_tutorial002.py",
    "content": "from docs_src.app_testing.tutorial002_py310 import test_read_main, test_websocket\n\n\ndef test_main():\n    test_read_main()\n\n\ndef test_ws():\n    test_websocket()\n"
  },
  {
    "path": "tests/test_tutorial/test_testing/test_tutorial003.py",
    "content": "import pytest\n\n\ndef test_main():\n    with pytest.warns(DeprecationWarning):\n        from docs_src.app_testing.tutorial003_py310 import test_read_items\n    test_read_items()\n"
  },
  {
    "path": "tests/test_tutorial/test_testing/test_tutorial004.py",
    "content": "from docs_src.app_testing.tutorial004_py310 import test_read_items\n\n\ndef test_main():\n    test_read_items()\n"
  },
  {
    "path": "tests/test_tutorial/test_testing_dependencies/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_testing_dependencies/test_tutorial001.py",
    "content": "import importlib\nfrom types import ModuleType\n\nimport pytest\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"test_module\",\n    params=[\n        pytest.param(\"tutorial001_py310\", marks=needs_py310),\n        pytest.param(\"tutorial001_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_test_module(request: pytest.FixtureRequest) -> ModuleType:\n    mod: ModuleType = importlib.import_module(\n        f\"docs_src.dependency_testing.{request.param}\"\n    )\n    return mod\n\n\ndef test_override_in_items_run(test_module: ModuleType):\n    test_override_in_items = test_module.test_override_in_items\n\n    test_override_in_items()\n\n\ndef test_override_in_items_with_q_run(test_module: ModuleType):\n    test_override_in_items_with_q = test_module.test_override_in_items_with_q\n\n    test_override_in_items_with_q()\n\n\ndef test_override_in_items_with_params_run(test_module: ModuleType):\n    test_override_in_items_with_params = test_module.test_override_in_items_with_params\n\n    test_override_in_items_with_params()\n\n\ndef test_override_in_users(test_module: ModuleType):\n    client = test_module.client\n    response = client.get(\"/users/\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"message\": \"Hello Users!\",\n        \"params\": {\"q\": None, \"skip\": 5, \"limit\": 10},\n    }\n\n\ndef test_override_in_users_with_q(test_module: ModuleType):\n    client = test_module.client\n    response = client.get(\"/users/?q=foo\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"message\": \"Hello Users!\",\n        \"params\": {\"q\": \"foo\", \"skip\": 5, \"limit\": 10},\n    }\n\n\ndef test_override_in_users_with_params(test_module: ModuleType):\n    client = test_module.client\n    response = client.get(\"/users/?q=foo&skip=100&limit=200\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"message\": \"Hello Users!\",\n        \"params\": {\"q\": \"foo\", \"skip\": 5, \"limit\": 10},\n    }\n\n\ndef test_normal_app(test_module: ModuleType):\n    app = test_module.app\n    client = test_module.client\n    app.dependency_overrides = None\n    response = client.get(\"/items/?q=foo&skip=100&limit=200\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"message\": \"Hello Items!\",\n        \"params\": {\"q\": \"foo\", \"skip\": 100, \"limit\": 200},\n    }\n"
  },
  {
    "path": "tests/test_tutorial/test_using_request_directly/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_using_request_directly/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\n\nfrom docs_src.using_request_directly.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_path_operation():\n    response = client.get(\"/items/foo\")\n    assert response.status_code == 200\n    assert response.json() == {\"client_host\": \"testclient\", \"item_id\": \"foo\"}\n\n\ndef test_openapi():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200\n    assert response.json() == snapshot(\n        {\n            \"info\": {\n                \"title\": \"FastAPI\",\n                \"version\": \"0.1.0\",\n            },\n            \"openapi\": \"3.1.0\",\n            \"paths\": {\n                \"/items/{item_id}\": {\n                    \"get\": {\n                        \"operationId\": \"read_root_items__item_id__get\",\n                        \"parameters\": [\n                            {\n                                \"in\": \"path\",\n                                \"name\": \"item_id\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"title\": \"Item Id\",\n                                    \"type\": \"string\",\n                                },\n                            },\n                        ],\n                        \"responses\": {\n                            \"200\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {},\n                                    },\n                                },\n                                \"description\": \"Successful Response\",\n                            },\n                            \"422\": {\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\",\n                                        },\n                                    },\n                                },\n                                \"description\": \"Validation Error\",\n                            },\n                        },\n                        \"summary\": \"Read Root\",\n                    },\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\",\n                                },\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                            },\n                        },\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [\n                                        {\n                                            \"type\": \"string\",\n                                        },\n                                        {\n                                            \"type\": \"integer\",\n                                        },\n                                    ],\n                                },\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                            },\n                            \"msg\": {\n                                \"title\": \"Message\",\n                                \"type\": \"string\",\n                            },\n                            \"type\": {\n                                \"title\": \"Error Type\",\n                                \"type\": \"string\",\n                            },\n                        },\n                        \"required\": [\n                            \"loc\",\n                            \"msg\",\n                            \"type\",\n                        ],\n                        \"title\": \"ValidationError\",\n                        \"type\": \"object\",\n                    },\n                },\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_tutorial/test_websockets/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_websockets/test_tutorial001.py",
    "content": "import pytest\nfrom fastapi.testclient import TestClient\nfrom fastapi.websockets import WebSocketDisconnect\n\nfrom docs_src.websockets_.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_main():\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    assert b\"<!DOCTYPE html>\" in response.content\n\n\ndef test_websocket():\n    with pytest.raises(WebSocketDisconnect):\n        with client.websocket_connect(\"/ws\") as websocket:\n            message = \"Message one\"\n            websocket.send_text(message)\n            data = websocket.receive_text()\n            assert data == f\"Message text was: {message}\"\n            message = \"Message two\"\n            websocket.send_text(message)\n            data = websocket.receive_text()\n            assert data == f\"Message text was: {message}\"\n"
  },
  {
    "path": "tests/test_tutorial/test_websockets/test_tutorial002.py",
    "content": "import importlib\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom fastapi.websockets import WebSocketDisconnect\n\nfrom ...utils import needs_py310\n\n\n@pytest.fixture(\n    name=\"app\",\n    params=[\n        pytest.param(\"tutorial002_py310\", marks=needs_py310),\n        pytest.param(\"tutorial002_an_py310\", marks=needs_py310),\n    ],\n)\ndef get_app(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.websockets_.{request.param}\")\n\n    return mod.app\n\n\ndef test_main(app: FastAPI):\n    client = TestClient(app)\n    response = client.get(\"/\")\n    assert response.status_code == 200, response.text\n    assert b\"<!DOCTYPE html>\" in response.content\n\n\ndef test_websocket_with_cookie(app: FastAPI):\n    client = TestClient(app, cookies={\"session\": \"fakesession\"})\n    with pytest.raises(WebSocketDisconnect):\n        with client.websocket_connect(\"/items/foo/ws\") as websocket:\n            message = \"Message one\"\n            websocket.send_text(message)\n            data = websocket.receive_text()\n            assert data == \"Session cookie or query token value is: fakesession\"\n            data = websocket.receive_text()\n            assert data == f\"Message text was: {message}, for item ID: foo\"\n            message = \"Message two\"\n            websocket.send_text(message)\n            data = websocket.receive_text()\n            assert data == \"Session cookie or query token value is: fakesession\"\n            data = websocket.receive_text()\n            assert data == f\"Message text was: {message}, for item ID: foo\"\n\n\ndef test_websocket_with_header(app: FastAPI):\n    client = TestClient(app)\n    with pytest.raises(WebSocketDisconnect):\n        with client.websocket_connect(\"/items/bar/ws?token=some-token\") as websocket:\n            message = \"Message one\"\n            websocket.send_text(message)\n            data = websocket.receive_text()\n            assert data == \"Session cookie or query token value is: some-token\"\n            data = websocket.receive_text()\n            assert data == f\"Message text was: {message}, for item ID: bar\"\n            message = \"Message two\"\n            websocket.send_text(message)\n            data = websocket.receive_text()\n            assert data == \"Session cookie or query token value is: some-token\"\n            data = websocket.receive_text()\n            assert data == f\"Message text was: {message}, for item ID: bar\"\n\n\ndef test_websocket_with_header_and_query(app: FastAPI):\n    client = TestClient(app)\n    with pytest.raises(WebSocketDisconnect):\n        with client.websocket_connect(\"/items/2/ws?q=3&token=some-token\") as websocket:\n            message = \"Message one\"\n            websocket.send_text(message)\n            data = websocket.receive_text()\n            assert data == \"Session cookie or query token value is: some-token\"\n            data = websocket.receive_text()\n            assert data == \"Query parameter q is: 3\"\n            data = websocket.receive_text()\n            assert data == f\"Message text was: {message}, for item ID: 2\"\n            message = \"Message two\"\n            websocket.send_text(message)\n            data = websocket.receive_text()\n            assert data == \"Session cookie or query token value is: some-token\"\n            data = websocket.receive_text()\n            assert data == \"Query parameter q is: 3\"\n            data = websocket.receive_text()\n            assert data == f\"Message text was: {message}, for item ID: 2\"\n\n\ndef test_websocket_no_credentials(app: FastAPI):\n    client = TestClient(app)\n    with pytest.raises(WebSocketDisconnect):\n        with client.websocket_connect(\"/items/foo/ws\"):\n            pytest.fail(\n                \"did not raise WebSocketDisconnect on __enter__\"\n            )  # pragma: no cover\n\n\ndef test_websocket_invalid_data(app: FastAPI):\n    client = TestClient(app)\n    with pytest.raises(WebSocketDisconnect):\n        with client.websocket_connect(\"/items/foo/ws?q=bar&token=some-token\"):\n            pytest.fail(\n                \"did not raise WebSocketDisconnect on __enter__\"\n            )  # pragma: no cover\n"
  },
  {
    "path": "tests/test_tutorial/test_websockets/test_tutorial003.py",
    "content": "import importlib\nimport time\nfrom types import ModuleType\n\nimport pytest\nfrom fastapi.testclient import TestClient\n\n\n@pytest.fixture(\n    name=\"mod\",\n    params=[\n        pytest.param(\"tutorial003_py310\"),\n    ],\n)\ndef get_mod(request: pytest.FixtureRequest):\n    mod = importlib.import_module(f\"docs_src.websockets_.{request.param}\")\n\n    return mod\n\n\n@pytest.fixture(name=\"html\")\ndef get_html(mod: ModuleType):\n    return mod.html\n\n\n@pytest.fixture(name=\"client\")\ndef get_client(mod: ModuleType):\n    client = TestClient(mod.app)\n\n    return client\n\n\ndef test_get(client: TestClient, html: str):\n    response = client.get(\"/\")\n    assert response.text == html\n\n\ndef test_websocket_handle_disconnection(client: TestClient):\n    with (\n        client.websocket_connect(\"/ws/1234\") as connection,\n        client.websocket_connect(\"/ws/5678\") as connection_two,\n    ):\n        connection.send_text(\"Hello from 1234\")\n        data1 = connection.receive_text()\n        assert data1 == \"You wrote: Hello from 1234\"\n        time.sleep(0.01)  # Give server time to process broadcast\n        data2 = connection_two.receive_text()\n        client1_says = \"Client #1234 says: Hello from 1234\"\n        assert data2 == client1_says\n        data1 = connection.receive_text()\n        assert data1 == client1_says\n        connection_two.close()\n        time.sleep(0.01)  # Give server time to process broadcast\n        data1 = connection.receive_text()\n        assert data1 == \"Client #5678 left the chat\"\n"
  },
  {
    "path": "tests/test_tutorial/test_wsgi/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_tutorial/test_wsgi/test_tutorial001.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom docs_src.wsgi.tutorial001_py310 import app\n\nclient = TestClient(app)\n\n\ndef test_flask():\n    response = client.get(\"/v1/\")\n    assert response.status_code == 200, response.text\n    assert response.text == \"Hello, World from Flask!\"\n\n\ndef test_app():\n    response = client.get(\"/v2\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"message\": \"Hello World\"}\n"
  },
  {
    "path": "tests/test_typing_python39.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\nfrom .utils import needs_py310\n\n\n@needs_py310\ndef test_typing():\n    types = {\n        list[int]: [1, 2, 3],\n        dict[str, list[int]]: {\"a\": [1, 2, 3], \"b\": [4, 5, 6]},\n        set[int]: [1, 2, 3],  # `set` is converted to `list`\n        tuple[int, ...]: [1, 2, 3],  # `tuple` is converted to `list`\n    }\n    for test_type, expect in types.items():\n        app = FastAPI()\n\n        @app.post(\"/\", response_model=test_type)\n        def post_endpoint(input: test_type):\n            return input\n\n        res = TestClient(app).post(\"/\", json=expect)\n        assert res.status_code == 200, res.json()\n        assert res.json() == expect\n"
  },
  {
    "path": "tests/test_union_body.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str | None = None\n\n\nclass OtherItem(BaseModel):\n    price: int\n\n\n@app.post(\"/items/\")\ndef save_union_body(item: OtherItem | Item):\n    return {\"item\": item}\n\n\nclient = TestClient(app)\n\n\ndef test_post_other_item():\n    response = client.post(\"/items/\", json={\"price\": 100})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item\": {\"price\": 100}}\n\n\ndef test_post_item():\n    response = client.post(\"/items/\", json={\"name\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item\": {\"name\": \"Foo\"}}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Save Union Body\",\n                        \"operationId\": \"save_union_body_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"title\": \"Item\",\n                                        \"anyOf\": [\n                                            {\"$ref\": \"#/components/schemas/OtherItem\"},\n                                            {\"$ref\": \"#/components/schemas/Item\"},\n                                        ],\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"OtherItem\": {\n                        \"title\": \"OtherItem\",\n                        \"required\": [\"price\"],\n                        \"type\": \"object\",\n                        \"properties\": {\"price\": {\"title\": \"Price\", \"type\": \"integer\"}},\n                    },\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            }\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_union_body_discriminator.py",
    "content": "from typing import Annotated, Any, Literal\n\nfrom dirty_equals import IsOneOf\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel, Field\n\n\ndef test_discriminator_pydantic_v2() -> None:\n    from pydantic import Tag\n\n    app = FastAPI()\n\n    class FirstItem(BaseModel):\n        value: Literal[\"first\"]\n        price: int\n\n    class OtherItem(BaseModel):\n        value: Literal[\"other\"]\n        price: float\n\n    Item = Annotated[\n        Annotated[FirstItem, Tag(\"first\")] | Annotated[OtherItem, Tag(\"other\")],\n        Field(discriminator=\"value\"),\n    ]\n\n    @app.post(\"/items/\")\n    def save_union_body_discriminator(\n        item: Item, q: Annotated[str, Field(description=\"Query string\")]\n    ) -> dict[str, Any]:\n        return {\"item\": item}\n\n    client = TestClient(app)\n    response = client.post(\"/items/?q=first\", json={\"value\": \"first\", \"price\": 100})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item\": {\"value\": \"first\", \"price\": 100}}\n\n    response = client.post(\"/items/?q=other\", json={\"value\": \"other\", \"price\": 100.5})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item\": {\"value\": \"other\", \"price\": 100.5}}\n\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"summary\": \"Save Union Body Discriminator\",\n                        \"operationId\": \"save_union_body_discriminator_items__post\",\n                        \"parameters\": [\n                            {\n                                \"name\": \"q\",\n                                \"in\": \"query\",\n                                \"required\": True,\n                                \"schema\": {\n                                    \"type\": \"string\",\n                                    \"description\": \"Query string\",\n                                    \"title\": \"Q\",\n                                },\n                            }\n                        ],\n                        \"requestBody\": {\n                            \"required\": True,\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"oneOf\": [\n                                            {\"$ref\": \"#/components/schemas/FirstItem\"},\n                                            {\"$ref\": \"#/components/schemas/OtherItem\"},\n                                        ],\n                                        \"discriminator\": {\n                                            \"propertyName\": \"value\",\n                                            \"mapping\": {\n                                                \"first\": \"#/components/schemas/FirstItem\",\n                                                \"other\": \"#/components/schemas/OtherItem\",\n                                            },\n                                        },\n                                        \"title\": \"Item\",\n                                    }\n                                }\n                            },\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": IsOneOf(\n                                            # Pydantic < 2.11: no additionalProperties\n                                            {\n                                                \"type\": \"object\",\n                                                \"title\": \"Response Save Union Body Discriminator Items  Post\",\n                                            },\n                                            # Pydantic >= 2.11: has additionalProperties\n                                            {\n                                                \"type\": \"object\",\n                                                \"additionalProperties\": True,\n                                                \"title\": \"Response Save Union Body Discriminator Items  Post\",\n                                            },\n                                        )\n                                    }\n                                },\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"FirstItem\": {\n                        \"properties\": {\n                            \"value\": IsOneOf(\n                                # Pydantic >= 2.10: const only\n                                {\n                                    \"type\": \"string\",\n                                    \"const\": \"first\",\n                                    \"title\": \"Value\",\n                                },\n                                # Pydantic 2.9: const + enum\n                                {\n                                    \"type\": \"string\",\n                                    \"const\": \"first\",\n                                    \"enum\": [\"first\"],\n                                    \"title\": \"Value\",\n                                },\n                            ),\n                            \"price\": {\"type\": \"integer\", \"title\": \"Price\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"value\", \"price\"],\n                        \"title\": \"FirstItem\",\n                    },\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"OtherItem\": {\n                        \"properties\": {\n                            \"value\": IsOneOf(\n                                # Pydantic >= 2.10.0: const only\n                                {\n                                    \"type\": \"string\",\n                                    \"const\": \"other\",\n                                    \"title\": \"Value\",\n                                },\n                                # Pydantic 2.9.x: const + enum\n                                {\n                                    \"type\": \"string\",\n                                    \"const\": \"other\",\n                                    \"enum\": [\"other\"],\n                                    \"title\": \"Value\",\n                                },\n                            ),\n                            \"price\": {\"type\": \"number\", \"title\": \"Price\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"value\", \"price\"],\n                        \"title\": \"OtherItem\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_union_body_discriminator_annotated.py",
    "content": "# Ref: https://github.com/fastapi/fastapi/discussions/14495\n\nfrom typing import Annotated\n\nimport pytest\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\n\n@pytest.fixture(name=\"client\")\ndef client_fixture() -> TestClient:\n    from fastapi import Body\n    from pydantic import Discriminator, Tag\n\n    class Cat(BaseModel):\n        pet_type: str = \"cat\"\n        meows: int\n\n    class Dog(BaseModel):\n        pet_type: str = \"dog\"\n        barks: float\n\n    def get_pet_type(v):\n        assert isinstance(v, dict)\n        return v.get(\"pet_type\", \"\")\n\n    Pet = Annotated[\n        Annotated[Cat, Tag(\"cat\")] | Annotated[Dog, Tag(\"dog\")],\n        Discriminator(get_pet_type),\n    ]\n\n    app = FastAPI()\n\n    @app.post(\"/pet/assignment\")\n    async def create_pet_assignment(pet: Pet = Body()):\n        return pet\n\n    @app.post(\"/pet/annotated\")\n    async def create_pet_annotated(pet: Annotated[Pet, Body()]):\n        return pet\n\n    client = TestClient(app)\n    return client\n\n\ndef test_union_body_discriminator_assignment(client: TestClient) -> None:\n    response = client.post(\"/pet/assignment\", json={\"pet_type\": \"cat\", \"meows\": 5})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"pet_type\": \"cat\", \"meows\": 5}\n\n\ndef test_union_body_discriminator_annotated(client: TestClient) -> None:\n    response = client.post(\"/pet/annotated\", json={\"pet_type\": \"dog\", \"barks\": 3.5})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"pet_type\": \"dog\", \"barks\": 3.5}\n\n\ndef test_openapi_schema(client: TestClient) -> None:\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/pet/assignment\": {\n                    \"post\": {\n                        \"summary\": \"Create Pet Assignment\",\n                        \"operationId\": \"create_pet_assignment_pet_assignment_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"anyOf\": [\n                                            {\"$ref\": \"#/components/schemas/Cat\"},\n                                            {\"$ref\": \"#/components/schemas/Dog\"},\n                                        ],\n                                        \"title\": \"Pet\",\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n                \"/pet/annotated\": {\n                    \"post\": {\n                        \"summary\": \"Create Pet Annotated\",\n                        \"operationId\": \"create_pet_annotated_pet_annotated_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"oneOf\": [\n                                            {\"$ref\": \"#/components/schemas/Cat\"},\n                                            {\"$ref\": \"#/components/schemas/Dog\"},\n                                        ],\n                                        \"title\": \"Pet\",\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                },\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Cat\": {\n                        \"properties\": {\n                            \"pet_type\": {\n                                \"type\": \"string\",\n                                \"title\": \"Pet Type\",\n                                \"default\": \"cat\",\n                            },\n                            \"meows\": {\"type\": \"integer\", \"title\": \"Meows\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"meows\"],\n                        \"title\": \"Cat\",\n                    },\n                    \"Dog\": {\n                        \"properties\": {\n                            \"pet_type\": {\n                                \"type\": \"string\",\n                                \"title\": \"Pet Type\",\n                                \"default\": \"dog\",\n                            },\n                            \"barks\": {\"type\": \"number\", \"title\": \"Barks\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"barks\"],\n                        \"title\": \"Dog\",\n                    },\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_union_forms.py",
    "content": "from typing import Annotated\n\nfrom fastapi import FastAPI, Form\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass UserForm(BaseModel):\n    name: str\n    email: str\n\n\nclass CompanyForm(BaseModel):\n    company_name: str\n    industry: str\n\n\n@app.post(\"/form-union/\")\ndef post_union_form(data: Annotated[UserForm | CompanyForm, Form()]):\n    return {\"received\": data}\n\n\nclient = TestClient(app)\n\n\ndef test_post_user_form():\n    response = client.post(\n        \"/form-union/\", data={\"name\": \"John Doe\", \"email\": \"john@example.com\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"received\": {\"name\": \"John Doe\", \"email\": \"john@example.com\"}\n    }\n\n\ndef test_post_company_form():\n    response = client.post(\n        \"/form-union/\", data={\"company_name\": \"Tech Corp\", \"industry\": \"Technology\"}\n    )\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"received\": {\"company_name\": \"Tech Corp\", \"industry\": \"Technology\"}\n    }\n\n\ndef test_invalid_form_data():\n    response = client.post(\n        \"/form-union/\",\n        data={\"name\": \"John\", \"company_name\": \"Tech Corp\"},\n    )\n    assert response.status_code == 422, response.text\n\n\ndef test_empty_form():\n    response = client.post(\"/form-union/\")\n    assert response.status_code == 422, response.text\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/form-union/\": {\n                    \"post\": {\n                        \"summary\": \"Post Union Form\",\n                        \"operationId\": \"post_union_form_form_union__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/x-www-form-urlencoded\": {\n                                    \"schema\": {\n                                        \"anyOf\": [\n                                            {\"$ref\": \"#/components/schemas/UserForm\"},\n                                            {\n                                                \"$ref\": \"#/components/schemas/CompanyForm\"\n                                            },\n                                        ],\n                                        \"title\": \"Data\",\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"CompanyForm\": {\n                        \"properties\": {\n                            \"company_name\": {\"type\": \"string\", \"title\": \"Company Name\"},\n                            \"industry\": {\"type\": \"string\", \"title\": \"Industry\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"company_name\", \"industry\"],\n                        \"title\": \"CompanyForm\",\n                    },\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"UserForm\": {\n                        \"properties\": {\n                            \"name\": {\"type\": \"string\", \"title\": \"Name\"},\n                            \"email\": {\"type\": \"string\", \"title\": \"Email\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"name\", \"email\"],\n                        \"title\": \"UserForm\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_union_inherited_body.py",
    "content": "from fastapi import FastAPI\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str | None = None\n\n\nclass ExtendedItem(Item):\n    age: int\n\n\n@app.post(\"/items/\")\ndef save_union_different_body(item: ExtendedItem | Item):\n    return {\"item\": item}\n\n\nclient = TestClient(app)\n\n\ndef test_post_extended_item():\n    response = client.post(\"/items/\", json={\"name\": \"Foo\", \"age\": 5})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item\": {\"name\": \"Foo\", \"age\": 5}}\n\n\ndef test_post_item():\n    response = client.post(\"/items/\", json={\"name\": \"Foo\"})\n    assert response.status_code == 200, response.text\n    assert response.json() == {\"item\": {\"name\": \"Foo\"}}\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {\n                \"/items/\": {\n                    \"post\": {\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"summary\": \"Save Union Different Body\",\n                        \"operationId\": \"save_union_different_body_items__post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"title\": \"Item\",\n                                        \"anyOf\": [\n                                            {\n                                                \"$ref\": \"#/components/schemas/ExtendedItem\"\n                                            },\n                                            {\"$ref\": \"#/components/schemas/Item\"},\n                                        ],\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"Item\": {\n                        \"title\": \"Item\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            }\n                        },\n                    },\n                    \"ExtendedItem\": {\n                        \"title\": \"ExtendedItem\",\n                        \"required\": [\"age\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"name\": {\n                                \"title\": \"Name\",\n                                \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"null\"}],\n                            },\n                            \"age\": {\"title\": \"Age\", \"type\": \"integer\"},\n                        },\n                    },\n                    \"ValidationError\": {\n                        \"title\": \"ValidationError\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"loc\": {\n                                \"title\": \"Location\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                            },\n                            \"msg\": {\"title\": \"Message\", \"type\": \"string\"},\n                            \"type\": {\"title\": \"Error Type\", \"type\": \"string\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                        },\n                    },\n                    \"HTTPValidationError\": {\n                        \"title\": \"HTTPValidationError\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"detail\": {\n                                \"title\": \"Detail\",\n                                \"type\": \"array\",\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                            }\n                        },\n                    },\n                }\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_validate_response.py",
    "content": "import pytest\nfrom fastapi import FastAPI\nfrom fastapi.exceptions import ResponseValidationError\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass Item(BaseModel):\n    name: str\n    price: float | None = None\n    owner_ids: list[int] | None = None\n\n\n@app.get(\"/items/invalid\", response_model=Item)\ndef get_invalid():\n    return {\"name\": \"invalid\", \"price\": \"foo\"}\n\n\n@app.get(\"/items/invalidnone\", response_model=Item)\ndef get_invalid_none():\n    return None\n\n\n@app.get(\"/items/validnone\", response_model=Item | None)\ndef get_valid_none(send_none: bool = False):\n    if send_none:\n        return None\n    else:\n        return {\"name\": \"invalid\", \"price\": 3.2}\n\n\n@app.get(\"/items/innerinvalid\", response_model=Item)\ndef get_innerinvalid():\n    return {\"name\": \"double invalid\", \"price\": \"foo\", \"owner_ids\": [\"foo\", \"bar\"]}\n\n\n@app.get(\"/items/invalidlist\", response_model=list[Item])\ndef get_invalidlist():\n    return [\n        {\"name\": \"foo\"},\n        {\"name\": \"bar\", \"price\": \"bar\"},\n        {\"name\": \"baz\", \"price\": \"baz\"},\n    ]\n\n\nclient = TestClient(app)\n\n\ndef test_invalid():\n    with pytest.raises(ResponseValidationError):\n        client.get(\"/items/invalid\")\n\n\ndef test_invalid_none():\n    with pytest.raises(ResponseValidationError):\n        client.get(\"/items/invalidnone\")\n\n\ndef test_valid_none_data():\n    response = client.get(\"/items/validnone\")\n    data = response.json()\n    assert response.status_code == 200\n    assert data == {\"name\": \"invalid\", \"price\": 3.2, \"owner_ids\": None}\n\n\ndef test_valid_none_none():\n    response = client.get(\"/items/validnone\", params={\"send_none\": \"true\"})\n    data = response.json()\n    assert response.status_code == 200\n    assert data is None\n\n\ndef test_double_invalid():\n    with pytest.raises(ResponseValidationError):\n        client.get(\"/items/innerinvalid\")\n\n\ndef test_invalid_list():\n    with pytest.raises(ResponseValidationError):\n        client.get(\"/items/invalidlist\")\n"
  },
  {
    "path": "tests/test_validate_response_dataclass.py",
    "content": "import pytest\nfrom fastapi import FastAPI\nfrom fastapi.exceptions import ResponseValidationError\nfrom fastapi.testclient import TestClient\nfrom pydantic.dataclasses import dataclass\n\napp = FastAPI()\n\n\n@dataclass\nclass Item:\n    name: str\n    price: float | None = None\n    owner_ids: list[int] | None = None\n\n\n@app.get(\"/items/invalid\", response_model=Item)\ndef get_invalid():\n    return {\"name\": \"invalid\", \"price\": \"foo\"}\n\n\n@app.get(\"/items/innerinvalid\", response_model=Item)\ndef get_innerinvalid():\n    return {\"name\": \"double invalid\", \"price\": \"foo\", \"owner_ids\": [\"foo\", \"bar\"]}\n\n\n@app.get(\"/items/invalidlist\", response_model=list[Item])\ndef get_invalidlist():\n    return [\n        {\"name\": \"foo\"},\n        {\"name\": \"bar\", \"price\": \"bar\"},\n        {\"name\": \"baz\", \"price\": \"baz\"},\n    ]\n\n\nclient = TestClient(app)\n\n\ndef test_invalid():\n    with pytest.raises(ResponseValidationError):\n        client.get(\"/items/invalid\")\n\n\ndef test_double_invalid():\n    with pytest.raises(ResponseValidationError):\n        client.get(\"/items/innerinvalid\")\n\n\ndef test_invalid_list():\n    with pytest.raises(ResponseValidationError):\n        client.get(\"/items/invalidlist\")\n"
  },
  {
    "path": "tests/test_validate_response_recursive/__init__.py",
    "content": ""
  },
  {
    "path": "tests/test_validate_response_recursive/app.py",
    "content": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\nclass RecursiveItem(BaseModel):\n    sub_items: list[\"RecursiveItem\"] = []\n    name: str\n\n\nclass RecursiveSubitemInSubmodel(BaseModel):\n    sub_items2: list[\"RecursiveItemViaSubmodel\"] = []\n    name: str\n\n\nclass RecursiveItemViaSubmodel(BaseModel):\n    sub_items1: list[RecursiveSubitemInSubmodel] = []\n    name: str\n\n\nRecursiveItem.model_rebuild()\nRecursiveSubitemInSubmodel.model_rebuild()\nRecursiveItemViaSubmodel.model_rebuild()\n\n\n@app.get(\"/items/recursive\", response_model=RecursiveItem)\ndef get_recursive():\n    return {\"name\": \"item\", \"sub_items\": [{\"name\": \"subitem\", \"sub_items\": []}]}\n\n\n@app.get(\"/items/recursive-submodel\", response_model=RecursiveItemViaSubmodel)\ndef get_recursive_submodel():\n    return {\n        \"name\": \"item\",\n        \"sub_items1\": [\n            {\n                \"name\": \"subitem\",\n                \"sub_items2\": [\n                    {\n                        \"name\": \"subsubitem\",\n                        \"sub_items1\": [{\"name\": \"subsubsubitem\", \"sub_items2\": []}],\n                    }\n                ],\n            }\n        ],\n    }\n"
  },
  {
    "path": "tests/test_validate_response_recursive/test_validate_response_recursive.py",
    "content": "from fastapi.testclient import TestClient\n\nfrom .app import app\n\n\ndef test_recursive():\n    client = TestClient(app)\n    response = client.get(\"/items/recursive\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"sub_items\": [{\"name\": \"subitem\", \"sub_items\": []}],\n        \"name\": \"item\",\n    }\n\n    response = client.get(\"/items/recursive-submodel\")\n    assert response.status_code == 200, response.text\n    assert response.json() == {\n        \"name\": \"item\",\n        \"sub_items1\": [\n            {\n                \"name\": \"subitem\",\n                \"sub_items2\": [\n                    {\n                        \"name\": \"subsubitem\",\n                        \"sub_items1\": [{\"name\": \"subsubsubitem\", \"sub_items2\": []}],\n                    }\n                ],\n            }\n        ],\n    }\n"
  },
  {
    "path": "tests/test_validation_error_context.py",
    "content": "from fastapi import FastAPI, Request, WebSocket\nfrom fastapi.exceptions import (\n    RequestValidationError,\n    ResponseValidationError,\n    WebSocketRequestValidationError,\n)\nfrom fastapi.testclient import TestClient\nfrom pydantic import BaseModel\n\n\nclass Item(BaseModel):\n    id: int\n    name: str\n\n\nclass ExceptionCapture:\n    def __init__(self):\n        self.exception = None\n\n    def capture(self, exc):\n        self.exception = exc\n        return exc\n\n\napp = FastAPI()\nsub_app = FastAPI()\ncaptured_exception = ExceptionCapture()\n\napp.mount(path=\"/sub\", app=sub_app)\n\n\n@app.exception_handler(RequestValidationError)\n@sub_app.exception_handler(RequestValidationError)\nasync def request_validation_handler(request: Request, exc: RequestValidationError):\n    captured_exception.capture(exc)\n    raise exc\n\n\n@app.exception_handler(ResponseValidationError)\n@sub_app.exception_handler(ResponseValidationError)\nasync def response_validation_handler(_: Request, exc: ResponseValidationError):\n    captured_exception.capture(exc)\n    raise exc\n\n\n@app.exception_handler(WebSocketRequestValidationError)\n@sub_app.exception_handler(WebSocketRequestValidationError)\nasync def websocket_validation_handler(\n    websocket: WebSocket, exc: WebSocketRequestValidationError\n):\n    captured_exception.capture(exc)\n    raise exc\n\n\n@app.get(\"/users/{user_id}\")\ndef get_user(user_id: int):\n    return {\"user_id\": user_id}  # pragma: no cover\n\n\n@app.get(\"/items/\", response_model=Item)\ndef get_item():\n    return {\"name\": \"Widget\"}\n\n\n@sub_app.get(\"/items/\", response_model=Item)\ndef get_sub_item():\n    return {\"name\": \"Widget\"}  # pragma: no cover\n\n\n@app.websocket(\"/ws/{item_id}\")\nasync def websocket_endpoint(websocket: WebSocket, item_id: int):\n    await websocket.accept()  # pragma: no cover\n    await websocket.send_text(f\"Item: {item_id}\")  # pragma: no cover\n    await websocket.close()  # pragma: no cover\n\n\n@sub_app.websocket(\"/ws/{item_id}\")\nasync def subapp_websocket_endpoint(websocket: WebSocket, item_id: int):\n    await websocket.accept()  # pragma: no cover\n    await websocket.send_text(f\"Item: {item_id}\")  # pragma: no cover\n    await websocket.close()  # pragma: no cover\n\n\nclient = TestClient(app)\n\n\ndef test_request_validation_error_includes_endpoint_context():\n    captured_exception.exception = None\n    try:\n        client.get(\"/users/invalid\")\n    except Exception:\n        pass\n\n    assert captured_exception.exception is not None\n    error_str = str(captured_exception.exception)\n    assert \"get_user\" in error_str\n    assert \"/users/\" in error_str\n\n\ndef test_response_validation_error_includes_endpoint_context():\n    captured_exception.exception = None\n    try:\n        client.get(\"/items/\")\n    except Exception:\n        pass\n\n    assert captured_exception.exception is not None\n    error_str = str(captured_exception.exception)\n    assert \"get_item\" in error_str\n    assert \"/items/\" in error_str\n\n\ndef test_websocket_validation_error_includes_endpoint_context():\n    captured_exception.exception = None\n    try:\n        with client.websocket_connect(\"/ws/invalid\"):\n            pass  # pragma: no cover\n    except Exception:\n        pass\n\n    assert captured_exception.exception is not None\n    error_str = str(captured_exception.exception)\n    assert \"websocket_endpoint\" in error_str\n    assert \"/ws/\" in error_str\n\n\ndef test_subapp_request_validation_error_includes_endpoint_context():\n    captured_exception.exception = None\n    try:\n        client.get(\"/sub/items/\")\n    except Exception:\n        pass\n\n    assert captured_exception.exception is not None\n    error_str = str(captured_exception.exception)\n    assert \"get_sub_item\" in error_str\n    assert \"/sub/items/\" in error_str\n\n\ndef test_subapp_websocket_validation_error_includes_endpoint_context():\n    captured_exception.exception = None\n    try:\n        with client.websocket_connect(\"/sub/ws/invalid\"):\n            pass  # pragma: no cover\n    except Exception:\n        pass\n\n    assert captured_exception.exception is not None\n    error_str = str(captured_exception.exception)\n    assert \"subapp_websocket_endpoint\" in error_str\n    assert \"/sub/ws/\" in error_str\n\n\ndef test_validation_error_with_only_path():\n    errors = [{\"type\": \"missing\", \"loc\": (\"body\", \"name\"), \"msg\": \"Field required\"}]\n    exc = RequestValidationError(errors, endpoint_ctx={\"path\": \"GET /api/test\"})\n    error_str = str(exc)\n    assert \"Endpoint: GET /api/test\" in error_str\n    assert 'File \"' not in error_str\n\n\ndef test_validation_error_with_no_context():\n    errors = [{\"type\": \"missing\", \"loc\": (\"body\", \"name\"), \"msg\": \"Field required\"}]\n    exc = RequestValidationError(errors, endpoint_ctx={})\n    error_str = str(exc)\n    assert \"1 validation error:\" in error_str\n    assert \"Endpoint\" not in error_str\n    assert 'File \"' not in error_str\n"
  },
  {
    "path": "tests/test_webhooks_security.py",
    "content": "from datetime import datetime\nfrom typing import Annotated\n\nfrom fastapi import FastAPI, Security\nfrom fastapi.security import HTTPBearer\nfrom fastapi.testclient import TestClient\nfrom inline_snapshot import snapshot\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\nbearer_scheme = HTTPBearer()\n\n\nclass Subscription(BaseModel):\n    username: str\n    monthly_fee: float\n    start_date: datetime\n\n\n@app.webhooks.post(\"new-subscription\")\ndef new_subscription(\n    body: Subscription, token: Annotated[str, Security(bearer_scheme)]\n):\n    \"\"\"\n    When a new user subscribes to your service we'll send you a POST request with this\n    data to the URL that you register for the event `new-subscription` in the dashboard.\n    \"\"\"\n\n\nclient = TestClient(app)\n\n\ndef test_dummy_webhook():\n    # Just for coverage\n    new_subscription(body={}, token=\"Bearer 123\")\n\n\ndef test_openapi_schema():\n    response = client.get(\"/openapi.json\")\n    assert response.status_code == 200, response.text\n    assert response.json() == snapshot(\n        {\n            \"openapi\": \"3.1.0\",\n            \"info\": {\"title\": \"FastAPI\", \"version\": \"0.1.0\"},\n            \"paths\": {},\n            \"webhooks\": {\n                \"new-subscription\": {\n                    \"post\": {\n                        \"summary\": \"New Subscription\",\n                        \"description\": \"When a new user subscribes to your service we'll send you a POST request with this\\ndata to the URL that you register for the event `new-subscription` in the dashboard.\",\n                        \"operationId\": \"new_subscriptionnew_subscription_post\",\n                        \"requestBody\": {\n                            \"content\": {\n                                \"application/json\": {\n                                    \"schema\": {\n                                        \"$ref\": \"#/components/schemas/Subscription\"\n                                    }\n                                }\n                            },\n                            \"required\": True,\n                        },\n                        \"responses\": {\n                            \"200\": {\n                                \"description\": \"Successful Response\",\n                                \"content\": {\"application/json\": {\"schema\": {}}},\n                            },\n                            \"422\": {\n                                \"description\": \"Validation Error\",\n                                \"content\": {\n                                    \"application/json\": {\n                                        \"schema\": {\n                                            \"$ref\": \"#/components/schemas/HTTPValidationError\"\n                                        }\n                                    }\n                                },\n                            },\n                        },\n                        \"security\": [{\"HTTPBearer\": []}],\n                    }\n                }\n            },\n            \"components\": {\n                \"schemas\": {\n                    \"HTTPValidationError\": {\n                        \"properties\": {\n                            \"detail\": {\n                                \"items\": {\n                                    \"$ref\": \"#/components/schemas/ValidationError\"\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Detail\",\n                            }\n                        },\n                        \"type\": \"object\",\n                        \"title\": \"HTTPValidationError\",\n                    },\n                    \"Subscription\": {\n                        \"properties\": {\n                            \"username\": {\"type\": \"string\", \"title\": \"Username\"},\n                            \"monthly_fee\": {\"type\": \"number\", \"title\": \"Monthly Fee\"},\n                            \"start_date\": {\n                                \"type\": \"string\",\n                                \"format\": \"date-time\",\n                                \"title\": \"Start Date\",\n                            },\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"username\", \"monthly_fee\", \"start_date\"],\n                        \"title\": \"Subscription\",\n                    },\n                    \"ValidationError\": {\n                        \"properties\": {\n                            \"ctx\": {\"title\": \"Context\", \"type\": \"object\"},\n                            \"input\": {\"title\": \"Input\"},\n                            \"loc\": {\n                                \"items\": {\n                                    \"anyOf\": [{\"type\": \"string\"}, {\"type\": \"integer\"}]\n                                },\n                                \"type\": \"array\",\n                                \"title\": \"Location\",\n                            },\n                            \"msg\": {\"type\": \"string\", \"title\": \"Message\"},\n                            \"type\": {\"type\": \"string\", \"title\": \"Error Type\"},\n                        },\n                        \"type\": \"object\",\n                        \"required\": [\"loc\", \"msg\", \"type\"],\n                        \"title\": \"ValidationError\",\n                    },\n                },\n                \"securitySchemes\": {\"HTTPBearer\": {\"type\": \"http\", \"scheme\": \"bearer\"}},\n            },\n        }\n    )\n"
  },
  {
    "path": "tests/test_wrapped_method_forward_reference.py",
    "content": "import functools\n\nfrom fastapi import FastAPI\nfrom fastapi.testclient import TestClient\n\nfrom .forward_reference_type import forwardref_method\n\n\ndef passthrough(f):\n    @functools.wraps(f)\n    def method(*args, **kwargs):\n        return f(*args, **kwargs)\n\n    return method\n\n\ndef test_wrapped_method_type_inference():\n    \"\"\"\n    Regression test ensuring that when a method imported from another module\n    is decorated with something that sets the __wrapped__ attribute (functools.wraps),\n    then the types are still processed correctly, including dereferencing of forward\n    references.\n    \"\"\"\n    app = FastAPI()\n    client = TestClient(app)\n    app.post(\"/endpoint\")(passthrough(forwardref_method))\n    app.post(\"/endpoint2\")(passthrough(passthrough(forwardref_method)))\n    with client:\n        response = client.post(\"/endpoint\", json={\"input\": {\"x\": 0}})\n        response2 = client.post(\"/endpoint2\", json={\"input\": {\"x\": 0}})\n    assert response.json() == response2.json() == {\"x\": 1}\n"
  },
  {
    "path": "tests/test_ws_dependencies.py",
    "content": "import json\nfrom typing import Annotated\n\nfrom fastapi import APIRouter, Depends, FastAPI, WebSocket\nfrom fastapi.testclient import TestClient\n\n\ndef dependency_list() -> list[str]:\n    return []\n\n\nDepList = Annotated[list[str], Depends(dependency_list)]\n\n\ndef create_dependency(name: str):\n    def fun(deps: DepList):\n        deps.append(name)\n\n    return Depends(fun)\n\n\nrouter = APIRouter(dependencies=[create_dependency(\"router\")])\nprefix_router = APIRouter(dependencies=[create_dependency(\"prefix_router\")])\napp = FastAPI(dependencies=[create_dependency(\"app\")])\n\n\n@app.websocket(\"/\", dependencies=[create_dependency(\"index\")])\nasync def index(websocket: WebSocket, deps: DepList):\n    await websocket.accept()\n    await websocket.send_text(json.dumps(deps))\n    await websocket.close()\n\n\n@router.websocket(\"/router\", dependencies=[create_dependency(\"routerindex\")])\nasync def routerindex(websocket: WebSocket, deps: DepList):\n    await websocket.accept()\n    await websocket.send_text(json.dumps(deps))\n    await websocket.close()\n\n\n@prefix_router.websocket(\"/\", dependencies=[create_dependency(\"routerprefixindex\")])\nasync def routerprefixindex(websocket: WebSocket, deps: DepList):\n    await websocket.accept()\n    await websocket.send_text(json.dumps(deps))\n    await websocket.close()\n\n\napp.include_router(router, dependencies=[create_dependency(\"router2\")])\napp.include_router(\n    prefix_router, prefix=\"/prefix\", dependencies=[create_dependency(\"prefix_router2\")]\n)\n\n\ndef test_index():\n    client = TestClient(app)\n    with client.websocket_connect(\"/\") as websocket:\n        data = json.loads(websocket.receive_text())\n        assert data == [\"app\", \"index\"]\n\n\ndef test_routerindex():\n    client = TestClient(app)\n    with client.websocket_connect(\"/router\") as websocket:\n        data = json.loads(websocket.receive_text())\n        assert data == [\"app\", \"router2\", \"router\", \"routerindex\"]\n\n\ndef test_routerprefixindex():\n    client = TestClient(app)\n    with client.websocket_connect(\"/prefix/\") as websocket:\n        data = json.loads(websocket.receive_text())\n        assert data == [\"app\", \"prefix_router2\", \"prefix_router\", \"routerprefixindex\"]\n"
  },
  {
    "path": "tests/test_ws_router.py",
    "content": "import functools\n\nimport pytest\nfrom fastapi import (\n    APIRouter,\n    Depends,\n    FastAPI,\n    Header,\n    WebSocket,\n    WebSocketDisconnect,\n    status,\n)\nfrom fastapi.middleware import Middleware\nfrom fastapi.testclient import TestClient\n\nrouter = APIRouter()\nprefix_router = APIRouter()\nnative_prefix_route = APIRouter(prefix=\"/native\")\napp = FastAPI()\n\n\n@app.websocket_route(\"/\")\nasync def index(websocket: WebSocket):\n    await websocket.accept()\n    await websocket.send_text(\"Hello, world!\")\n    await websocket.close()\n\n\n@router.websocket_route(\"/router\")\nasync def routerindex(websocket: WebSocket):\n    await websocket.accept()\n    await websocket.send_text(\"Hello, router!\")\n    await websocket.close()\n\n\n@prefix_router.websocket_route(\"/\")\nasync def routerprefixindex(websocket: WebSocket):\n    await websocket.accept()\n    await websocket.send_text(\"Hello, router with prefix!\")\n    await websocket.close()\n\n\n@router.websocket(\"/router2\")\nasync def routerindex2(websocket: WebSocket):\n    await websocket.accept()\n    await websocket.send_text(\"Hello, router!\")\n    await websocket.close()\n\n\n@router.websocket(\"/router/{pathparam:path}\")\nasync def routerindexparams(websocket: WebSocket, pathparam: str, queryparam: str):\n    await websocket.accept()\n    await websocket.send_text(pathparam)\n    await websocket.send_text(queryparam)\n    await websocket.close()\n\n\nasync def ws_dependency():\n    return \"Socket Dependency\"\n\n\n@router.websocket(\"/router-ws-depends/\")\nasync def router_ws_decorator_depends(\n    websocket: WebSocket, data=Depends(ws_dependency)\n):\n    await websocket.accept()\n    await websocket.send_text(data)\n    await websocket.close()\n\n\n@native_prefix_route.websocket(\"/\")\nasync def router_native_prefix_ws(websocket: WebSocket):\n    await websocket.accept()\n    await websocket.send_text(\"Hello, router with native prefix!\")\n    await websocket.close()\n\n\nasync def ws_dependency_err():\n    raise NotImplementedError()\n\n\n@router.websocket(\"/depends-err/\")\nasync def router_ws_depends_err(websocket: WebSocket, data=Depends(ws_dependency_err)):\n    pass  # pragma: no cover\n\n\nasync def ws_dependency_validate(x_missing: str = Header()):\n    pass  # pragma: no cover\n\n\n@router.websocket(\"/depends-validate/\")\nasync def router_ws_depends_validate(\n    websocket: WebSocket, data=Depends(ws_dependency_validate)\n):\n    pass  # pragma: no cover\n\n\nclass CustomError(Exception):\n    pass\n\n\n@router.websocket(\"/custom_error/\")\nasync def router_ws_custom_error(websocket: WebSocket):\n    raise CustomError()\n\n\ndef make_app(app=None, **kwargs):\n    app = app or FastAPI(**kwargs)\n    app.include_router(router)\n    app.include_router(prefix_router, prefix=\"/prefix\")\n    app.include_router(native_prefix_route)\n    return app\n\n\napp = make_app(app)\n\n\ndef test_app():\n    client = TestClient(app)\n    with client.websocket_connect(\"/\") as websocket:\n        data = websocket.receive_text()\n        assert data == \"Hello, world!\"\n\n\ndef test_router():\n    client = TestClient(app)\n    with client.websocket_connect(\"/router\") as websocket:\n        data = websocket.receive_text()\n        assert data == \"Hello, router!\"\n\n\ndef test_prefix_router():\n    client = TestClient(app)\n    with client.websocket_connect(\"/prefix/\") as websocket:\n        data = websocket.receive_text()\n        assert data == \"Hello, router with prefix!\"\n\n\ndef test_native_prefix_router():\n    client = TestClient(app)\n    with client.websocket_connect(\"/native/\") as websocket:\n        data = websocket.receive_text()\n        assert data == \"Hello, router with native prefix!\"\n\n\ndef test_router2():\n    client = TestClient(app)\n    with client.websocket_connect(\"/router2\") as websocket:\n        data = websocket.receive_text()\n        assert data == \"Hello, router!\"\n\n\ndef test_router_ws_depends():\n    client = TestClient(app)\n    with client.websocket_connect(\"/router-ws-depends/\") as websocket:\n        assert websocket.receive_text() == \"Socket Dependency\"\n\n\ndef test_router_ws_depends_with_override():\n    client = TestClient(app)\n    app.dependency_overrides[ws_dependency] = lambda: \"Override\"  # noqa: E731\n    with client.websocket_connect(\"/router-ws-depends/\") as websocket:\n        assert websocket.receive_text() == \"Override\"\n\n\ndef test_router_with_params():\n    client = TestClient(app)\n    with client.websocket_connect(\n        \"/router/path/to/file?queryparam=a_query_param\"\n    ) as websocket:\n        data = websocket.receive_text()\n        assert data == \"path/to/file\"\n        data = websocket.receive_text()\n        assert data == \"a_query_param\"\n\n\ndef test_wrong_uri():\n    \"\"\"\n    Verify that a websocket connection to a non-existent endpoint returns in a shutdown\n    \"\"\"\n    client = TestClient(app)\n    with pytest.raises(WebSocketDisconnect) as e:\n        with client.websocket_connect(\"/no-router/\"):\n            pass  # pragma: no cover\n    assert e.value.code == status.WS_1000_NORMAL_CLOSURE\n\n\ndef websocket_middleware(middleware_func):\n    \"\"\"\n    Helper to create a Starlette pure websocket middleware\n    \"\"\"\n\n    def middleware_constructor(app):\n        @functools.wraps(app)\n        async def wrapped_app(scope, receive, send):\n            if scope[\"type\"] != \"websocket\":\n                return await app(scope, receive, send)  # pragma: no cover\n\n            async def call_next():\n                return await app(scope, receive, send)\n\n            websocket = WebSocket(scope, receive=receive, send=send)\n            return await middleware_func(websocket, call_next)\n\n        return wrapped_app\n\n    return middleware_constructor\n\n\ndef test_depend_validation():\n    \"\"\"\n    Verify that a validation in a dependency invokes the correct exception handler\n    \"\"\"\n    caught = []\n\n    @websocket_middleware\n    async def catcher(websocket, call_next):\n        try:\n            return await call_next()\n        except Exception as e:  # pragma: no cover\n            caught.append(e)\n            raise\n\n    myapp = make_app(middleware=[Middleware(catcher)])\n\n    client = TestClient(myapp)\n    with pytest.raises(WebSocketDisconnect) as e:\n        with client.websocket_connect(\"/depends-validate/\"):\n            pass  # pragma: no cover\n    # the validation error does produce a close message\n    assert e.value.code == status.WS_1008_POLICY_VIOLATION\n    # and no error is leaked\n    assert caught == []\n\n\ndef test_depend_err_middleware():\n    \"\"\"\n    Verify that it is possible to write custom WebSocket middleware to catch errors\n    \"\"\"\n\n    @websocket_middleware\n    async def errorhandler(websocket: WebSocket, call_next):\n        try:\n            return await call_next()\n        except Exception as e:\n            await websocket.close(code=status.WS_1006_ABNORMAL_CLOSURE, reason=repr(e))\n\n    myapp = make_app(middleware=[Middleware(errorhandler)])\n    client = TestClient(myapp)\n    with pytest.raises(WebSocketDisconnect) as e:\n        with client.websocket_connect(\"/depends-err/\"):\n            pass  # pragma: no cover\n    assert e.value.code == status.WS_1006_ABNORMAL_CLOSURE\n    assert \"NotImplementedError\" in e.value.reason\n\n\ndef test_depend_err_handler():\n    \"\"\"\n    Verify that it is possible to write custom WebSocket middleware to catch errors\n    \"\"\"\n\n    async def custom_handler(websocket: WebSocket, exc: CustomError) -> None:\n        await websocket.close(1002, \"foo\")\n\n    myapp = make_app(exception_handlers={CustomError: custom_handler})\n    client = TestClient(myapp)\n    with pytest.raises(WebSocketDisconnect) as e:\n        with client.websocket_connect(\"/custom_error/\"):\n            pass  # pragma: no cover\n    assert e.value.code == 1002\n    assert \"foo\" in e.value.reason\n"
  },
  {
    "path": "tests/utils.py",
    "content": "import importlib\nimport sys\n\nimport pytest\n\nneeds_py310 = pytest.mark.skipif(\n    sys.version_info < (3, 10), reason=\"requires python3.10+\"\n)\nneeds_py314 = pytest.mark.skipif(\n    sys.version_info < (3, 14), reason=\"requires python3.14+\"\n)\n\nneeds_orjson = pytest.mark.skipif(\n    importlib.util.find_spec(\"orjson\") is None,\n    reason=\"requires orjson\",\n)\n\nneeds_ujson = pytest.mark.skipif(\n    importlib.util.find_spec(\"ujson\") is None,\n    reason=\"requires ujson\",\n)\n\nworkdir_lock = pytest.mark.xdist_group(\"workdir_lock\")\n\n\ndef skip_module_if_py_gte_314():\n    \"\"\"Skip entire module on Python 3.14+ at import time.\"\"\"\n    if sys.version_info >= (3, 14):\n        pytest.skip(\"requires python3.13-\", allow_module_level=True)\n"
  }
]